diff --git a/.devcontainer/add_kitware_archive.sh b/.devcontainer/add_kitware_archive.sh deleted file mode 100755 index aff0b6c8d0f..00000000000 --- a/.devcontainer/add_kitware_archive.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/bin/sh -# ----------------------------------------------------------------------------- -# This script is from: https://apt.kitware.com/kitware-archive.sh -# -# It installs key and repo for the kitware CMAKE-archive. -# -# Author: Bernhard Bablok -# -# ----------------------------------------------------------------------------- - -set -eu - -help() { - echo "Usage: $0 [--release ] [--rc]" > /dev/stderr -} - -doing= -rc= -release= -help= -for opt in "$@" -do - case "${doing}" in - release) - release="${opt}" - doing= - ;; - "") - case "${opt}" in - --rc) - rc=1 - ;; - --release) - doing=release - ;; - --help) - help=1 - ;; - esac - ;; - esac -done - -if [ -n "${doing}" ] -then - echo "--${doing} option given no argument." > /dev/stderr - echo > /dev/stderr - help - exit 1 -fi - -if [ -n "${help}" ] -then - help - exit -fi - -if [ -z "${release}" ] -then - unset UBUNTU_CODENAME - . /etc/os-release - - if [ -z "${UBUNTU_CODENAME+x}" ] - then - echo "This is not an Ubuntu system. Aborting." > /dev/stderr - exit 1 - fi - - release="${UBUNTU_CODENAME}" -fi - -case "${release}" in -noble|jammy|focal) - packages= - keyring_packages="ca-certificates gpg wget" - ;; -*) - echo "Only Ubuntu Noble (24.04), Jammy (22.04), and Focal (20.04) are supported. Aborting." > /dev/stderr - exit 1 - ;; -esac - -get_keyring= -if [ ! -f /usr/share/doc/kitware-archive-keyring/copyright ] -then - packages="${packages} ${keyring_packages}" - get_keyring=1 -fi - -# Start the real work -set -x - -apt-get update -# shellcheck disable=SC2086 -apt-get install -y ${packages} - -test -n "${get_keyring}" && (wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - > /usr/share/keyrings/kitware-archive-keyring.gpg) - -echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ ${release} main" > /etc/apt/sources.list.d/kitware.list -if [ -n "${rc}" ] -then - echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ ${release}-rc main" >> /etc/apt/sources.list.d/kitware.list -fi - -apt-get update -test -n "${get_keyring}" && rm /usr/share/keyrings/kitware-archive-keyring.gpg -apt-get install -y kitware-archive-keyring diff --git a/.devcontainer/common_tools.sh b/.devcontainer/common_tools.sh index d94977b01cc..1231b8e4f4b 100755 --- a/.devcontainer/common_tools.sh +++ b/.devcontainer/common_tools.sh @@ -9,16 +9,18 @@ # ----------------------------------------------------------------------------- REPO_ROOT="/workspaces/circuitpython" +CMAKE_VERSION="3.31.12" echo -e "[common_tools.sh] starting install" cd "$REPO_ROOT" # --- repositories and tools ------------------------------------------------ -echo -e "[common_tools.sh] adding kitware-archive (for current CMAKE)" -sudo .devcontainer/add_kitware_archive.sh -echo -e "[common_tools.sh] installing current version of CMAKE" -sudo apt-get -y install cmake +echo -e "[common_tools.sh] installing CMAKE $CMAKE_VERSION" +wget -q https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-$(arch).sh +chmod +x cmake-$CMAKE_VERSION-linux-$(arch).sh +sudo ./cmake-$CMAKE_VERSION-linux-$(arch).sh --prefix=/usr/local --skip-license +rm cmake-$CMAKE_VERSION-linux-$(arch).sh echo -e "[common_tools.sh] adding pybricks/ppa" sudo add-apt-repository -y ppa:pybricks/ppa diff --git a/.devcontainer/cortex-m-toolchain.sh b/.devcontainer/cortex-m-toolchain.sh index 10896abd08c..56be006544f 100755 --- a/.devcontainer/cortex-m-toolchain.sh +++ b/.devcontainer/cortex-m-toolchain.sh @@ -14,10 +14,10 @@ echo -e "[cortex-m-toolchain.sh] downloading and installing gcc-arm-non-eabi too cd /workspaces wget -qO gcc-arm-none-eabi.tar.xz \ - https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi.tar.xz + https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi.tar.xz tar -xJf gcc-arm-none-eabi.tar.xz -ln -s arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi gcc-arm-none-eabi +ln -s arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi gcc-arm-none-eabi rm -f gcc-arm-none-eabi.tar.xz echo -e "[cortex-m-toolchain.sh] update PATH in environment" diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 195e1e06eea..97b5e558f40 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,3 +1,6 @@ +# all: Apply code formatting to new paths. +48c7daaa3d7068c127c5bc395ffa72029ab9bba1 + # all: Prune trailing whitespace. dda9b9c6da5d3c31fa8769e581a753e95a270803 diff --git a/.gitattributes b/.gitattributes index 38bba729fc1..890c9cead6c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13,12 +13,14 @@ # CIRCUITPY-CHANGE: add some more binary types. # These are binary so should never be modified by git. *.a binary +*.FLM binary *.ico binary *.png binary *.jpg binary *.dxf binary *.mpy binary *.der binary +*.bin binary *.deb binary *.zip binary *.pdf binary @@ -27,4 +29,5 @@ # These should also not be modified by git. tests/basics/string_cr_conversion.py -text tests/basics/string_crlf_conversion.py -text +tests/micropython/test_normalize_newlines.py.exp -text # CIRCUITPY-CHANGE: remove non-CircuitPython tests diff --git a/.github/actions/deps/external/action.yml b/.github/actions/deps/external/action.yml index 10aace1134e..326bc8275c1 100644 --- a/.github/actions/deps/external/action.yml +++ b/.github/actions/deps/external/action.yml @@ -26,20 +26,14 @@ runs: inputs.port != 'zephyr-cp' uses: carlosperate/arm-none-eabi-gcc-action@v1 with: - # When changing this update what Windows grabs too! - release: '14.2.Rel1' + release: '15.2.Rel1' # espressif - - name: Get espressif toolchain - if: inputs.port == 'espressif' - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - shell: bash - name: Install IDF tools if: inputs.port == 'espressif' run: | $IDF_PATH/install.sh + $IDF_PATH/tools/idf_tools.py install ninja rm -rf $IDF_TOOLS_PATH/dist shell: bash - name: Set environment @@ -56,6 +50,16 @@ runs: uses: ./.github/actions/deps/python with: action: ${{ inputs.action }} + - name: Set ESP-IDF constraints path + if: inputs.port == 'espressif' + run: python3 -u tools/ci_set_idf_constraint.py + shell: bash + - name: Install python dependencies - run: pip install -r requirements-dev.txt + run: | + if [ -n "${IDF_CONSTRAINT_FILE:-}" ] && [ -f "$IDF_CONSTRAINT_FILE" ]; then + pip install -c "$IDF_CONSTRAINT_FILE" -r requirements-dev.txt + else + pip install -r requirements-dev.txt + fi shell: bash diff --git a/.github/actions/deps/ports/action.yml b/.github/actions/deps/ports/action.yml index 6f91ea62cec..cd3b4c80fe2 100644 --- a/.github/actions/deps/ports/action.yml +++ b/.github/actions/deps/ports/action.yml @@ -30,3 +30,5 @@ runs: - name: Set up Zephyr if: inputs.port == 'zephyr-cp' uses: ./.github/actions/deps/ports/zephyr-cp + with: + sdl: ${{ startsWith(inputs.board, 'native_') }} diff --git a/.github/actions/deps/ports/broadcom/action.yml b/.github/actions/deps/ports/broadcom/action.yml index 9ad0e361bda..8ee85e35138 100644 --- a/.github/actions/deps/ports/broadcom/action.yml +++ b/.github/actions/deps/ports/broadcom/action.yml @@ -5,8 +5,8 @@ runs: steps: - name: Get broadcom toolchain run: | - wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/arm-gnu-toolchain-14.2.rel1-x86_64-aarch64-none-elf.tar.xz - sudo tar -C /usr --strip-components=1 -xaf arm-gnu-toolchain-14.2.rel1-x86_64-aarch64-none-elf.tar.xz + wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/arm-gnu-toolchain-15.2.rel1-x86_64-aarch64-none-elf.tar.xz + sudo tar -C /usr --strip-components=1 -xaf arm-gnu-toolchain-15.2.rel1-x86_64-aarch64-none-elf.tar.xz sudo apt-get update sudo apt-get install -y mtools shell: bash @@ -16,7 +16,7 @@ runs: tar -xaf dosfstools-4.2.tar.gz cd dosfstools-4.2 ./configure - make -j4 + make -j$(nproc) cd src echo >> $GITHUB_PATH $(pwd) shell: bash diff --git a/.github/actions/deps/ports/espressif/action.yml b/.github/actions/deps/ports/espressif/action.yml index 25965eb7ef0..a25c96d190e 100644 --- a/.github/actions/deps/ports/espressif/action.yml +++ b/.github/actions/deps/ports/espressif/action.yml @@ -19,7 +19,7 @@ runs: shell: bash - name: Cache IDF submodules - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | .git/modules/ports/espressif/esp-idf @@ -27,10 +27,10 @@ runs: key: submodules-idf-${{ steps.idf-commit.outputs.commit }} - name: Cache IDF tools - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.IDF_TOOLS_PATH }} - key: ${{ runner.os }}-${{ env.pythonLocation }}-tools-idf-${{ steps.idf-commit.outputs.commit }} + key: ${{ runner.os }}-${{ env.pythonLocation }}-tools-idf-${{ steps.idf-commit.outputs.commit }}-20260911 - name: Initialize IDF submodules run: git submodule update --init --depth=1 --recursive $IDF_PATH diff --git a/.github/actions/deps/ports/zephyr-cp/action.yml b/.github/actions/deps/ports/zephyr-cp/action.yml index cfa1177598e..bd0af847773 100644 --- a/.github/actions/deps/ports/zephyr-cp/action.yml +++ b/.github/actions/deps/ports/zephyr-cp/action.yml @@ -1,8 +1,32 @@ name: Fetch Zephyr port deps +inputs: + sdl: + description: 'Install the 32-bit SDL2 packages native_sim needs' + required: false + default: 'false' + runs: using: composite steps: + - name: Get Linux build dependencies + if: runner.os == 'Linux' + run: | + echo "--- cpu model ---" + grep "model name" /proc/cpuinfo | head -1 + sudo apt-get update + sudo apt-get install -y libusb-1.0-0-dev libudev-dev pkg-config mtools + shell: bash + - name: Get SDL2 for native_sim + if: runner.os == 'Linux' && inputs.sdl == 'true' + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + # We have to hold python3 so the following install works. See https://github.com/actions/runner-images/issues/13803 + sudo apt-mark hold python3 + sudo apt-get install -y libsdl2-dev:i386 libsdl2-image-dev:i386 + echo "PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" >> $GITHUB_ENV + shell: bash - name: Setup Zephyr project uses: zephyrproject-rtos/action-zephyr-setup@v1 with: @@ -13,3 +37,6 @@ runs: run: west zephyr-export shell: bash working-directory: ports/zephyr-cp + - name: Install Zephyr protobuf dependency + run: pip install protobuf==6.33.5 + shell: bash diff --git a/.github/actions/deps/python/action.yml b/.github/actions/deps/python/action.yml index da59b87b17a..bc8b578c147 100644 --- a/.github/actions/deps/python/action.yml +++ b/.github/actions/deps/python/action.yml @@ -16,7 +16,7 @@ runs: - name: Cache python dependencies id: cache-python-deps if: inputs.action == 'cache' - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .cp_tools key: ${{ runner.os }}-${{ env.pythonLocation }}-tools-cp-${{ hashFiles('requirements-dev.txt') }} @@ -24,7 +24,7 @@ runs: - name: Restore python dependencies id: restore-python-deps if: inputs.action == 'restore' - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: .cp_tools key: ${{ runner.os }}-${{ env.pythonLocation }}-tools-cp-${{ hashFiles('requirements-dev.txt') }} diff --git a/.github/actions/deps/submodules/action.yml b/.github/actions/deps/submodules/action.yml index eed83af41f4..65a303f71c5 100644 --- a/.github/actions/deps/submodules/action.yml +++ b/.github/actions/deps/submodules/action.yml @@ -12,6 +12,12 @@ inputs: default: '["extmod/ulab", "lib/", "tools/"]' type: string + port: + description: 'Also cache the submodules of this port, in their own entry' + required: false + default: '' + type: string + action: description: 'The cache action to use' required: false @@ -48,7 +54,7 @@ runs: - name: Cache submodules if: ${{ inputs.action == 'cache' }} - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ".git/modules/\n${{ join(fromJSON(steps.create-submodule-status.outputs.submodules), '\n') }}" key: submodules-common-${{ hashFiles('submodule_status') }} @@ -56,14 +62,33 @@ runs: - name: Restore submodules if: ${{ inputs.action == 'restore' }} - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: ".git/modules/\n${{ join(fromJSON(steps.create-submodule-status.outputs.submodules), '\n') }}" key: submodules-common-${{ hashFiles('submodule_status') }} enableCrossOsArchive: true + - name: Port submodule status + id: port-submodule-status + # The ports whose board jobs clone the most over the network: 29 CMSIS and HAL + # repositories on stm, the sdk and lwip on raspberrypi and mimxrt10xx. espressif + # and zephyr-cp fetch theirs in their own way; the rest have little to gain. + if: ${{ contains(fromJSON('["stm", "raspberrypi", "mimxrt10xx"]'), inputs.port) }} + run: | + git submodule status ports/${{ inputs.port }} > port_submodule_status + echo $(cut -d ' ' -f 2 port_submodule_status) | echo "submodules=[\"$(sed "s/ /\", \"/g")\"]" >> $GITHUB_OUTPUT + shell: bash + + - name: Cache port submodules + if: ${{ steps.port-submodule-status.outcome == 'success' }} + uses: actions/cache@v5 + with: + path: ".git/modules/ports/${{ inputs.port }}\n${{ join(fromJSON(steps.port-submodule-status.outputs.submodules), '\n') }}" + key: submodules-${{ inputs.port }}-${{ hashFiles('port_submodule_status') }} + enableCrossOsArchive: true + - name: Remove submodule status - run: rm submodule_status + run: rm -f submodule_status port_submodule_status shell: bash - name: CircuitPython dependencies diff --git a/.github/actions/mpy_cross/action.yml b/.github/actions/mpy_cross/action.yml index 8839f790915..1eda5855353 100644 --- a/.github/actions/mpy_cross/action.yml +++ b/.github/actions/mpy_cross/action.yml @@ -16,7 +16,7 @@ runs: id: download-mpy-cross if: inputs.download == 'true' continue-on-error: true - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: mpy-cross path: mpy-cross/build @@ -28,7 +28,7 @@ runs: - name: Build mpy-cross if: inputs.download == 'false' || steps.download-mpy-cross.outcome == 'failure' - run: make -C mpy-cross -j4 + run: make -C mpy-cross -j$(nproc) shell: bash env: CP_VERSION: ${{ inputs.cp-version }} @@ -36,7 +36,7 @@ runs: - name: Upload mpy-cross if: inputs.download == 'false' || steps.download-mpy-cross.outcome == 'failure' continue-on-error: true - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: mpy-cross path: mpy-cross/build/mpy-cross diff --git a/.github/workflows/build-board-custom.yml b/.github/workflows/build-board-custom.yml index bf18d7d7259..caeb16cfddf 100644 --- a/.github/workflows/build-board-custom.yml +++ b/.github/workflows/build-board-custom.yml @@ -70,7 +70,7 @@ jobs: run: | > custom-build && git add custom-build - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Board to port @@ -121,10 +121,10 @@ jobs: BOARD: ${{ inputs.board }} FLAGS: ${{ inputs.flags }} DEBUG: ${{ inputs.debug && '1' || '0' }} - run: make -j4 $FLAGS BOARD="$BOARD" DEBUG=$DEBUG TRANSLATION="$TRANSLATION" + run: make -j$(nproc) $FLAGS BOARD="$BOARD" DEBUG=$DEBUG TRANSLATION="$TRANSLATION" working-directory: ports/${{ steps.board-to-port.outputs.port }} - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ inputs.board }}-${{ inputs.language }}-${{ inputs.version }}${{ inputs.flags != '' && '-custom' || '' }}${{ inputs.debug && '-debug' || '' }} path: ports/${{ steps.board-to-port.outputs.port }}/build-${{ inputs.board }}/firmware.* diff --git a/.github/workflows/build-boards.yml b/.github/workflows/build-boards.yml index 7e5156d4011..bf1734a19c2 100644 --- a/.github/workflows/build-boards.yml +++ b/.github/workflows/build-boards.yml @@ -24,12 +24,12 @@ jobs: env: CP_VERSION: ${{ inputs.cp-version }} strategy: - fail-fast: false + fail-fast: ${{ github.event_name == 'merge_group' }} matrix: board: ${{ fromJSON(inputs.boards) }} steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false @@ -37,9 +37,9 @@ jobs: persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: 3.x + python-version: ${{ inputs.port == 'zephyr-cp' && '3.13' || '3.x' }} - name: Set up port id: set-up-port @@ -51,6 +51,8 @@ jobs: - name: Set up submodules id: set-up-submodules uses: ./.github/actions/deps/submodules + with: + port: ${{ inputs.port }} - name: Set up external uses: ./.github/actions/deps/external @@ -87,7 +89,7 @@ jobs: HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.board }} path: bin/${{ matrix.board }} diff --git a/.github/workflows/build-mpy-cross.yml b/.github/workflows/build-mpy-cross.yml index 831ad308227..dedf9154b8d 100644 --- a/.github/workflows/build-mpy-cross.yml +++ b/.github/workflows/build-mpy-cross.yml @@ -16,7 +16,7 @@ jobs: build: runs-on: ubuntu-24.04 strategy: - fail-fast: false + fail-fast: ${{ github.event_name == 'merge_group' }} matrix: mpy-cross: ["static", "static-aarch64", "static-mingw", "static-raspbian"] env: @@ -28,14 +28,14 @@ jobs: OS_static-raspbian: linux-raspbian steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules @@ -55,7 +55,7 @@ jobs: sudo apt-get install -y mingw-w64 - name: Build mpy-cross.${{ matrix.mpy-cross }} - run: make -C mpy-cross -j4 -f Makefile.${{ matrix.mpy-cross }} + run: make -C mpy-cross -j$(nproc) -f Makefile.${{ matrix.mpy-cross }} - name: Set output env: @@ -66,7 +66,7 @@ jobs: echo >> $GITHUB_ENV "OS=$OS" - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: mpy-cross.${{ env.EX }} path: mpy-cross/build-${{ matrix.mpy-cross }}/mpy-cross.${{ env.EX }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f837d793bd..e250c8debd7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,12 +6,17 @@ name: Build CI on: push: + branches: + - main + - '*.x' pull_request: + merge_group: + types: [checks_requested] release: types: [published] concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref || github.run_id }} cancel-in-progress: true jobs: @@ -19,8 +24,8 @@ jobs: runs-on: ubuntu-24.04 outputs: docs: ${{ steps.set-matrix.outputs.docs }} + zephyr-tests: ${{ steps.set-matrix.outputs.zephyr-tests }} ports: ${{ steps.set-matrix.outputs.ports }} - windows: ${{ steps.set-matrix.outputs.windows }} cp-version: ${{ steps.set-up-submodules.outputs.version }} steps: - name: Dump GitHub context @@ -28,14 +33,14 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Duplicate USB VID/PID check @@ -66,15 +71,15 @@ jobs: GITHUB_TOKEN: ${{ github.token }} EXCLUDE_COMMIT: ${{ github.event.pull_request.head.sha }} - name: Set head sha (pull) - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' || github.event_name == 'merge_group' env: - HEAD_SHA: ${{ github.event.pull_request.head.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} run: echo "HEAD_SHA=$HEAD_SHA" >> $GITHUB_ENV - name: Set base sha (pull) - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' || github.event_name == 'merge_group' run: git cat-file -e $SHA && echo "BASE_SHA=$SHA" >> $GITHUB_ENV || true env: - SHA: ${{ steps.get-last-commit-with-checks.outputs.commit_sha || github.event.pull_request.base.sha }} + SHA: ${{ steps.get-last-commit-with-checks.outputs.commit_sha || github.event.pull_request.base.sha || github.event.merge_group.base_sha }} - name: Set head sha (push) if: github.event_name == 'push' env: @@ -98,6 +103,13 @@ jobs: with: cp-version: ${{ needs.scheduler.outputs.cp-version }} + zephyr-tests: + needs: scheduler + if: needs.scheduler.outputs.zephyr-tests == 'True' + uses: ./.github/workflows/run-zephyr-tests.yml + with: + cp-version: ${{ needs.scheduler.outputs.cp-version }} + mpy-cross: needs: scheduler if: needs.scheduler.outputs.ports != '{}' @@ -107,21 +119,21 @@ jobs: cp-version: ${{ needs.scheduler.outputs.cp-version }} mpy-cross-mac: - runs-on: macos-13 + runs-on: macos-latest needs: scheduler if: needs.scheduler.outputs.ports != '{}' env: CP_VERSION: ${{ needs.scheduler.outputs.cp-version }} steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules @@ -131,33 +143,18 @@ jobs: gcc --version python3 --version msgfmt --version - - name: Build mpy-cross - run: make -C mpy-cross -j4 - - uses: actions/upload-artifact@v4 - with: - name: mpy-cross-macos-x64 - path: mpy-cross/build/mpy-cross - name: Build mpy-cross (arm64) - run: make -C mpy-cross -j4 -f Makefile.m1 V=2 - - uses: actions/upload-artifact@v4 + run: make -C mpy-cross -j$(sysctl -n hw.ncpu) -f Makefile.m1 V=2 + - uses: actions/upload-artifact@v7 with: name: mpy-cross-macos-arm64 path: mpy-cross/build-arm64/mpy-cross-arm64 - - name: Make universal binary - run: lipo -create -output mpy-cross-macos-universal mpy-cross/build/mpy-cross mpy-cross/build-arm64/mpy-cross-arm64 - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: mpy-cross-macos-universal - path: mpy-cross-macos-universal - name: Upload to S3 if: >- (github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository_owner == 'adafruit') || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested')) run: | - [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross-macos-universal s3://adafruit-circuit-python/bin/mpy-cross/macos/mpy-cross-macos-"${CP_VERSION}"-universal --no-progress --region us-east-1 [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/build-arm64/mpy-cross-arm64 s3://adafruit-circuit-python/bin/mpy-cross/macos/mpy-cross-macos-"${CP_VERSION}"-arm64 --no-progress --region us-east-1 - [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/build/mpy-cross s3://adafruit-circuit-python/bin/mpy-cross/macos/mpy-cross-macos-"${CP_VERSION}"-x64 --no-progress --region us-east-1 env: AWS_PAGER: '' AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -171,14 +168,14 @@ jobs: CP_VERSION: ${{ needs.scheduler.outputs.cp-version }} steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules @@ -191,21 +188,21 @@ jobs: sudo apt-get install -y latexmk librsvg2-bin texlive-fonts-recommended texlive-latex-recommended texlive-latex-extra pip install -r requirements-doc.txt - name: Build and Validate Stubs - run: make check-stubs -j4 - - uses: actions/upload-artifact@v4 + run: make check-stubs -j$(nproc) + - uses: actions/upload-artifact@v7 with: name: stubs path: circuitpython-stubs/dist/* - name: Test Documentation Build (HTML) run: sphinx-build -E -W -b html -D version="$CP_VERSION" -D release="$CP_VERSION" . _build/html - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: docs-html path: _build/html - name: Test Documentation Build (LaTeX/PDF) run: | make latexpdf - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: docs-latexpdf path: _build/latex @@ -226,118 +223,33 @@ jobs: [ -z "$TWINE_USERNAME" ] || echo "Uploading dev release to PyPi" [ -z "$TWINE_USERNAME" ] || twine upload circuitpython-stubs/dist/* - windows: - runs-on: windows-2022 - needs: scheduler - if: needs.scheduler.outputs.windows == 'True' - env: - CP_VERSION: ${{ needs.scheduler.outputs.cp-version }} - defaults: - run: - # We define a custom shell script here, although `msys2.cmd` does neither exist nor is it available in the PATH yet - shell: msys2 {0} - steps: - # We want to change the configuration of the git command that actions/checkout will be using - # (since it is not possible to set autocrlf through the action yet, see actions/checkout#226). - - run: git config --global core.autocrlf input - shell: bash - - name: Check python coding (cmd) - run: python -c "import sys, locale; print(sys.getdefaultencoding(), locale.getpreferredencoding(False))" - shell: cmd - # We use a JS Action, which calls the system terminal or other custom terminals directly, if required - - uses: msys2/setup-msys2@v2 - with: - install: base-devel git wget unzip gcc python-pip - # The goal of this was to test how things worked when the default file encoding (locale.getpreferedencoding()) - # was not UTF-8. However, msys2 python does use utf-8 as the preferred file encoding, and using actions/setup-python - # python3.8 gave a broken build, so we're not really testing what we wanted to test. - # However, commandline length limits are being tested so that does some good. - - name: Check python coding (msys2) - run: | - locale -v - which python; python --version - python -c "import sys, locale; print(sys.getdefaultencoding(), locale.getpreferredencoding(False))" - which python3; python3 --version - python3 -c "import sys, locale; print(sys.getdefaultencoding(), locale.getpreferredencoding(False))" - - name: Install dependencies - run: | - wget --no-verbose -O gcc-arm.zip https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-mingw-w64-i686-arm-none-eabi.zip - unzip -q -d /tmp/arm-gnu-toolchain gcc-arm.zip - tar -C /tmp/arm-gnu-toolchain -cf - . | tar -C /usr/local -xf - - # We could use a venv instead, but that requires entering the venv on each run step - # that runs in its own shell. There are some actions that help with that, but not for msys2 - # that I can find. (dhalbert) - pip install --break-system-packages wheel - # requirements-dev.txt doesn't install on windows. (with msys2 python) - # instead, pick a subset for what we want to do - pip install --break-system-packages cascadetoml jinja2 typer click intelhex - # check that installed packages work....? - which python; python --version; python -c "import cascadetoml" - which python3; python3 --version; python3 -c "import cascadetoml" - - name: Set up repository - uses: actions/checkout@v4 - with: - submodules: false - show-progress: false - fetch-depth: 1 - persist-credentials: false - - name: Set up submodules - uses: ./.github/actions/deps/submodules - - name: build mpy-cross - run: make -j4 -C mpy-cross - - name: build rp2040 - run: make -j4 -C ports/raspberrypi BOARD=adafruit_feather_rp2040 TRANSLATION=de_DE - - name: build samd21 - run: make -j4 -C ports/atmel-samd BOARD=feather_m0_express TRANSLATION=zh_Latn_pinyin - - name: build samd51 - run: make -j4 -C ports/atmel-samd BOARD=feather_m4_express TRANSLATION=es - - name: build nordic - run: make -j4 -C ports/nordic BOARD=feather_nrf52840_express TRANSLATION=fr - - name: build stm - run: make -j4 -C ports/stm BOARD=feather_stm32f405_express TRANSLATION=pt_BR - # I gave up trying to do esp builds on windows when I saw - # ERROR: Platform MINGW64_NT-10.0-17763-x86_64 appears to be unsupported - # https://github.com/espressif/esp-idf/issues/7062 - - windows-zephyr: - strategy: - matrix: - os: [windows-2022, windows-2025] - runs-on: ${{ matrix.os }} - needs: scheduler - if: needs.scheduler.outputs.windows == 'True' - env: - CP_VERSION: ${{ needs.scheduler.outputs.cp-version }} - steps: - - name: Set up repository - uses: actions/checkout@v4 - with: - submodules: false - show-progress: false - fetch-depth: 1 - persist-credentials: false - - uses: actions/setup-python@v5 - with: - python-version: '3.13' - - name: Set up Zephyr - uses: ./.github/actions/deps/ports/zephyr-cp - - name: Set up submodules - uses: ./.github/actions/deps/submodules - - name: build mpy-cross - run: make -j4 -C mpy-cross - - name: build ek_ra8d1 - run: make -j4 -C ports/zephyr-cp BOARD=renesas_ek_ra8d1 - ports: needs: [scheduler, mpy-cross, tests] if: needs.scheduler.outputs.ports != '{}' uses: ./.github/workflows/build-boards.yml secrets: inherit strategy: - fail-fast: false + fail-fast: ${{ github.event_name == 'merge_group' }} + max-parallel: 55 matrix: port: ${{ fromJSON(needs.scheduler.outputs.ports).ports }} with: boards: ${{ toJSON(fromJSON(needs.scheduler.outputs.ports)[matrix.port]) }} cp-version: ${{ needs.scheduler.outputs.cp-version }} - port: ${{ matrix.port }} + port: ${{ fromJSON(needs.scheduler.outputs.ports).split_ports[matrix.port] || matrix.port }} + + build-ci: + # Final gate for ruleset checks: always runs so the required check is + # reported, and fails if any job (or matrix leg) failed or was cancelled. + needs: [tests, zephyr-tests, mpy-cross, mpy-cross-mac, docs, ports] + if: ${{ always() }} + runs-on: ubuntu-24.04 + steps: + - name: Check build results + run: | + echo "Job results: ${{ toJSON(needs.*.result) }}" + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]] || [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + echo "One or more jobs failed or were cancelled" + exit 1 + fi + echo "All build jobs succeeded" diff --git a/.github/workflows/bundle_cron.yml b/.github/workflows/bundle_cron.yml index 606707d4102..eefffaaa5b9 100644 --- a/.github/workflows/bundle_cron.yml +++ b/.github/workflows/bundle_cron.yml @@ -29,18 +29,18 @@ jobs: if: startswith(github.repository, 'adafruit/') steps: - name: Set up Python 3.12 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.12 - name: Load contributor cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: key: "contributor-cache" path: "contributors.json" - name: Versions run: | python3 --version - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: repository: 'adafruit/adabot' submodules: true diff --git a/.github/workflows/create-website-pr.yml b/.github/workflows/create-website-pr.yml index 32c1792fa6c..559a41e67e7 100644 --- a/.github/workflows/create-website-pr.yml +++ b/.github/workflows/create-website-pr.yml @@ -17,14 +17,14 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules diff --git a/.github/workflows/learn_cron.yml b/.github/workflows/learn_cron.yml index 6100e6637c2..135089bfd5e 100644 --- a/.github/workflows/learn_cron.yml +++ b/.github/workflows/learn_cron.yml @@ -26,7 +26,7 @@ jobs: # default branches). if: ${{ (github.repository_owner == 'adafruit') }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: repository: ${{ github.repository_owner }}/Adafruit_Learning_System_Guides token: ${{ secrets.ADABOT_GITHUB_ACCESS_TOKEN }} diff --git a/.github/workflows/notify-on-issue-label.yml b/.github/workflows/notify-on-issue-label.yml index 2b229156811..2465851e35b 100644 --- a/.github/workflows/notify-on-issue-label.yml +++ b/.github/workflows/notify-on-issue-label.yml @@ -10,7 +10,7 @@ jobs: permissions: issues: write steps: - - uses: tekktrik/issue-labeled-ping@v2 + - uses: tekktrik/issue-labeled-ping@v3 with: github-token: ${{ secrets.GITHUB_TOKEN }} user: v923z diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 778270dc08c..46961aca41f 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -6,10 +6,14 @@ name: pre-commit on: push: + branches-ignore: + - 'gh-readonly-queue/**' pull_request: + merge_group: + types: [checks_requested] concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref || github.run_id }} cancel-in-progress: true jobs: @@ -17,14 +21,14 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules @@ -42,7 +46,7 @@ jobs: run: git diff > ~/pre-commit.patch - name: Upload patch if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: patch path: ~/pre-commit.patch diff --git a/.github/workflows/reports_cron.yml b/.github/workflows/reports_cron.yml index b4e9a43024e..476ead95d25 100644 --- a/.github/workflows/reports_cron.yml +++ b/.github/workflows/reports_cron.yml @@ -38,13 +38,13 @@ jobs: BIGQUERY_CLIENT_EMAIL: ${{ secrets.BIGQUERY_CLIENT_EMAIL }} steps: - name: Set up Python 3.11 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.11 - name: Versions run: | python3 --version - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: repository: 'adafruit/adabot' submodules: true diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 80bfc72bd98..db4f5b0e316 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -11,7 +11,7 @@ jobs: run: runs-on: ubuntu-24.04 strategy: - fail-fast: false + fail-fast: ${{ github.event_name == 'merge_group' }} matrix: test: [all, mpy, native, native_mpy] env: @@ -23,46 +23,45 @@ jobs: TEST_native: --emit native TEST_native_mpy: --via-mpy --emit native -d basics float micropython steps: - - name: Set up repository - uses: actions/checkout@v4 - with: - submodules: false - show-progress: false - fetch-depth: 1 - - name: Set up python - uses: actions/setup-python@v5 - with: - python-version: 3.12 - - name: Set up submodules - uses: ./.github/actions/deps/submodules - with: - target: tests - - name: Set up external - if: matrix.test == 'all' - uses: ./.github/actions/deps/external - - name: Set up mpy-cross - uses: ./.github/actions/mpy_cross - with: - cp-version: ${{ inputs.cp-version }} - - name: Build unix port - run: make -C ports/unix VARIANT=coverage -j4 - - name: Run tests - run: ./run-tests.py -j4 ${{ env[format('TEST_{0}', matrix.test)] }} - working-directory: tests - - name: Print failure info - run: ./run-tests.py -j4 --print-failures - if: failure() - working-directory: tests - # Not working after MicroPython v1.23 merge. - # - name: Build native modules - # if: matrix.test == 'all' - # run: | - # make -C examples/natmod/features1 - # make -C examples/natmod/features2 - # make -C examples/natmod/heapq - # make -C examples/natmod/random - # make -C examples/natmod/re - # - name: Test native modules - # if: matrix.test == 'all' - # run: ./run-natmodtests.py extmod/{heapq*,random*,re*}.py - # working-directory: tests + - name: Set up repository + uses: actions/checkout@v6 + with: + submodules: false + show-progress: false + fetch-depth: 1 + - name: Set up python + uses: actions/setup-python@v6 + with: + python-version: 3.12 + - name: Set up submodules + uses: ./.github/actions/deps/submodules + with: + target: tests + - name: Set up external + if: matrix.test == 'all' + uses: ./.github/actions/deps/external + - name: Set up mpy-cross + uses: ./.github/actions/mpy_cross + with: + cp-version: ${{ inputs.cp-version }} + - name: Build unix port + run: make -C ports/unix VARIANT=coverage -j$(nproc) + - name: Run tests + run: ./run-tests.py -j$(nproc) ${{ env[format('TEST_{0}', matrix.test)] }} + working-directory: tests + - name: Print failure info + run: ./run-tests.py -j$(nproc) --print-failures + if: failure() + working-directory: tests + - name: Build native modules + if: matrix.test == 'all' + run: | + make -C examples/natmod/features1 + make -C examples/natmod/features2 + make -C examples/natmod/heapq + make -C examples/natmod/random + make -C examples/natmod/re + - name: Test native modules + if: matrix.test == 'all' + run: ./run-natmodtests.py extmod/{heapq*,random*,re*}.py + working-directory: tests diff --git a/.github/workflows/run-zephyr-tests.yml b/.github/workflows/run-zephyr-tests.yml new file mode 100644 index 00000000000..7d20aca059b --- /dev/null +++ b/.github/workflows/run-zephyr-tests.yml @@ -0,0 +1,58 @@ +name: Run Zephyr tests + +on: + workflow_call: + inputs: + cp-version: + required: true + type: string + +jobs: + zephyr: + runs-on: ubuntu-24.04 + name: ${{ matrix.shard }} + strategy: + fail-fast: ${{ github.event_name == 'merge_group' }} + # One job per board family, so the bsim suites, which take the longest, run + # side by side instead of after each other. + matrix: + include: + - shard: native_sim + boards: native_native_sim native_native_sim_asan + pytest_args: tests/ --ignore=tests/bsim -n $(nproc) --dist loadfile + - shard: nrf5340bsim + boards: native_nrf5340bsim + pytest_args: tests/bsim -k native_nrf5340bsim -n $(nproc) --dist loadfile + - shard: nrf54lm20bsim + boards: native_nrf54lm20bsim + pytest_args: tests/bsim -k native_nrf54lm20bsim -n $(nproc) --dist loadfile + env: + CP_VERSION: ${{ inputs.cp-version }} + steps: + - name: Set up repository + uses: actions/checkout@v6 + with: + submodules: false + show-progress: false + fetch-depth: 1 + - name: Set up python + uses: actions/setup-python@v6 + with: + python-version: 3.13 + - name: Set up Zephyr + uses: ./.github/actions/deps/ports/zephyr-cp + with: + sdl: true + - name: Set up submodules + id: set-up-submodules + uses: ./.github/actions/deps/submodules + with: + target: zephyr-cp + - name: Set up external + uses: ./.github/actions/deps/external + - name: Build bsim + if: contains(matrix.shard, 'bsim') + run: make -j $(nproc) everything + working-directory: ports/zephyr-cp/tools/bsim + - name: Run Zephyr tests + run: make -C ports/zephyr-cp -j$(nproc) test TEST_BOARDS="${{ matrix.boards }}" PYTEST_ARGS="${{ matrix.pytest_args }}" diff --git a/.gitignore b/.gitignore index f996911d8d7..659801277f3 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ circuitpython-stubs/ test-stubs/ build-*/ docs/genrst/ +.mpy_ld_cache-*/ # Test failure outputs and intermediate artifacts ###################### @@ -55,6 +56,9 @@ __pycache__/ ###################### GNUmakefile user.props +user_pre_mpconfigport.mk +user_post_mpconfigport.mk +user_post_circuitpy_defns.mk # Sphinx output ############### @@ -107,3 +111,10 @@ TAGS # windsurf rules .windsurfrules + +# git-review-web outputs +.review + +# Zephyr trace files +**/channel0_0 +**/*.perfetto-trace diff --git a/.gitmodules b/.gitmodules index b89769942af..0dee3eb5cd4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -143,7 +143,7 @@ [submodule "ports/espressif/esp-idf"] path = ports/espressif/esp-idf url = https://github.com/adafruit/esp-idf.git - branch = circuitpython-v5.4.1 + branch = circuitpython-v5.5.1 [submodule "ports/espressif/esp-protocols"] path = ports/espressif/esp-protocols url = https://github.com/adafruit/esp-protocols.git @@ -316,7 +316,7 @@ branch = circuitpython9 [submodule "lib/mbedtls"] path = lib/mbedtls - url = https://github.com/ARMmbed/mbedtls.git + url = https://github.com/Mbed-TLS/mbedtls.git [submodule "frozen/Adafruit_CircuitPython_UC8151D"] path = frozen/Adafruit_CircuitPython_UC8151D url = https://github.com/adafruit/Adafruit_CircuitPython_UC8151D @@ -415,3 +415,18 @@ [submodule "ports/espressif/microros-lib"] path = ports/espressif/microros-lib url = https://github.com/hierophect/microros-lib.git +[submodule "frozen/Adafruit_CircuitPython_OPT4048"] + path = frozen/Adafruit_CircuitPython_OPT4048 + url = https://github.com/adafruit/Adafruit_CircuitPython_OPT4048.git +[submodule "frozen/CircuitPython_edupico2_paj7620"] + path = frozen/CircuitPython_edupico2_paj7620 + url = https://github.com/CytronTechnologies/CircuitPython_edupico2_paj7620.git +[submodule "frozen/Adafruit_CircuitPython_BLE_File_Transfer"] + path = frozen/Adafruit_CircuitPython_BLE_File_Transfer + url = https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer.git +[submodule "frozen/Adafruit_CircuitPython_CS42L42"] + path = frozen/Adafruit_CircuitPython_CS42L42 + url = https://github.com/adafruit/Adafruit_CircuitPython_CS42L42.git +[submodule "frozen/Adafruit_CircuitPython_TAS2505"] + path = frozen/Adafruit_CircuitPython_TAS2505 + url = https://github.com/adafruit/Adafruit_CircuitPython_TAS2505.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f7e7956498d..c39faf99f00 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: check-yaml - id: end-of-file-fixer @@ -28,7 +28,7 @@ repos: lib/mbedtls_errors/generate_errors.diff ) - repo: https://github.com/codespell-project/codespell - rev: v2.2.4 + rev: v2.4.1 hooks: - id: codespell args: [-w] @@ -55,7 +55,7 @@ repos: language: python - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.9.4 + rev: v0.15.7 hooks: # Run the linter. - id: ruff @@ -63,6 +63,6 @@ repos: # Run the formatter. - id: ruff-format - repo: https://github.com/tox-dev/pyproject-fmt - rev: "v2.5.0" + rev: "v2.21.0" hooks: - id: pyproject-fmt diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..e7d2fdbbe8c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,4 @@ +- Capture CircuitPython output by finding the matching device in `/dev/serial/by-id` +- You can mount the CIRCUITPY drive by doing `udisksctl mount -b /dev/disk/by-label/CIRCUITPY` and access it via `/run/media//CIRCUITPY`. +- `circup` is a command line tool to install libraries and examples to CIRCUITPY. +- When connecting to serial devices on Linux use /dev/serial/by-id. These will be more stable than /dev/ttyACM*. diff --git a/BUILDING.md b/BUILDING.md index 34cd544d736..6778965bed0 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -64,6 +64,52 @@ If you aren't sure what boards exist, have a peek in the boards subdirectory of If you have a fast computer with many cores, consider adding `-j` to your build flags, such as `-j17` on a 6-core 12-thread machine. +## Configuration + +Ports and boards are preconfigured, thus make knows how to build a specific +board. Power users can change the configuration of a specific board or port, +either by passing compile-time options to make, or by creating appropriate +make include files. + +The configuration system is hierarchical. A higher level will typically only +set an option that a lower level hasn't configured: + +* board configuration: `mpconfigport.mk` +* pre-port user configuration: `user_pre_mpconfigport.mk` +* port configuration: `mpconfigport.mk` +* post-port user configuration: `user_post_mpconfigport.mk` +* global configuration: `py/circuitpython_mpconfig.mk` + +The board configuration is within the board-directory, e.g. +`ports/raspberrypi/boards/raspberry_pi_pico/`, the port configuration is +in the port-directory, e.g. `ports/raspberrypi/`. + +Editing these configuration files is the way to go if you want to change +the default behavior and ultimately create a pull-request. Otherwise, +changes should go into one of the user configuration files. + +User specific configurations are optional and should be maintained out of +tree. Passing `-I directory` tells make where to search for the additional +configuration files. E.g. to speed up boots by removing the wait-time for +the save-mode button press, you would: + +* create a directory: `mkdir -p ~/my_cp_config` +* create the config file: `echo 'CIRCUITPY_SKIP_SAFE_MODE_WAIT=0' > ~/my_cp_config/user_pre_mpconfigport.mk` +* run make with: `make -I ~/my_cp_config BOARD=raspberry_pi_pico` + +Besides the `user*mpconfigport.mk` files, there is another optional file +named `user_post_circuitpy_defns.mk`. This file is included at the end +and can be used to tweak compiler-definitions that are not covered by +one of the compile time options `CIRCUITPY_*`. + +Example: to create a build for the Pico2-W with an integrated saves-partition, +you would create a `user_post_circuitpy_defns.mk` with the following content: + + $(info ===> processing user_post_circuitpy_defns.mk) + ifeq (${BOARD},raspberry_pi_pico2_w) + CFLAGS += -DCIRCUITPY_SAVES_PARTITION_SIZE=1048576 + endif + ## Testing If you are working on changes to the core language, you might find it useful to run the test suite. diff --git a/LICENSE b/LICENSE index 90d19f757b2..2b332548d80 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2025 Damien P. George +Copyright (c) 2013-2026 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 diff --git a/LICENSE_MicroPython b/LICENSE_MicroPython index 469ae192739..1fad9b4134e 100644 --- a/LICENSE_MicroPython +++ b/LICENSE_MicroPython @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2024 Damien P. George +Copyright (c) 2013-2025 Damien P. George Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index c2aebc61f1c..3fc38581f9b 100644 --- a/Makefile +++ b/Makefile @@ -237,7 +237,7 @@ pseudoxml: all-source: TRANSLATE_CHECK_SUBMODULES=if ! [ -f extmod/ulab/README.md ]; then $(PYTHON) tools/ci_fetch_deps.py translate; fi -TRANSLATE_COMMAND=find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -x locale/synthetic.pot -f- -L C -s --add-location=file --keyword=MP_ERROR_TEXT -o - | sed -e '/"POT-Creation-Date: /d' +TRANSLATE_COMMAND=find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -x locale/synthetic.pot -f- -L C --sort-by-file --add-location=file --keyword=MP_ERROR_TEXT -o - | sed -e '/"POT-Creation-Date: /d' locale/circuitpython.pot: all-source $(TRANSLATE_CHECK_SUBMODULES) $(TRANSLATE_COMMAND) > $@ @@ -255,7 +255,7 @@ translate: locale/circuitpython.pot # needed we preserve a rule to do it. .PHONY: msgmerge msgmerge: - for po in $(shell ls locale/*.po); do msgmerge -U $$po -s --no-fuzzy-matching --add-location=file locale/circuitpython.pot; done + for po in $(shell ls locale/*.po); do msgmerge -U $$po --sort-by-file --no-fuzzy-matching --add-location=file locale/circuitpython.pot; done merge-translate: git merge HEAD 1>&2 2> /dev/null; test $$? -eq 128 @@ -375,5 +375,6 @@ coverage-fresh: make -j -C ports/unix VARIANT=coverage .PHONY: run-tests +# If TESTS="abc.py def.py" is specified as an arg, run only those tests. Otherwise, run all tests. run-tests: - cd tests; MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py + cd tests; MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py $(TESTS) diff --git a/README.rst b/README.rst index 80aa1b2aee2..89c7d9229d8 100644 --- a/README.rst +++ b/README.rst @@ -226,7 +226,7 @@ Ports Ports include the code unique to a microcontroller line. -The following ports are available: ``atmel-samd``, ``cxd56``, ``espressif``, ``litex``, ``mimxrt10xx``, ``nordic``, ``raspberrypi``, ``renode``, ``silabs`` (``efr32``), ``stm``, ``unix``. +The following ports are available: ``atmel-samd``, ``cxd56``, ``espressif``, ``litex``, ``mimxrt10xx``, ``nordic``, ``raspberrypi``, ``renode``, ``silabs`` (``efr32``), ``stm``, ``unix``, and ``zephyr-cp``. However, not all ports are fully functional. Some have limited functionality and known serious bugs. For details, refer to the **Port status** section in the `latest release `__ notes. diff --git a/conf.py b/conf.py index 34436c09020..d62931a7848 100644 --- a/conf.py +++ b/conf.py @@ -192,7 +192,13 @@ def autoapi_prepare_jinja_env(jinja_env): # Port READMEs in various formats "ports/*/README*", ] -exclude_patterns = ["docs/autoapi/templates/**", "docs/README.md"] +exclude_patterns = [ + "docs/autoapi/templates/**", + "docs/README.md", + "AGENTS.md", + "**/AGENTS.md", + "docs/library/weakref.rst", +] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -325,6 +331,7 @@ def autoapi_prepare_jinja_env(jinja_env): \hbadness=99999 \hfuzz=20pt \usepackage{pdflscape} +\DeclareUnicodeCharacter{FFFD}{?} """, } diff --git a/data/nvm.toml b/data/nvm.toml index 8bca037b052..a2a0c03c221 160000 --- a/data/nvm.toml +++ b/data/nvm.toml @@ -1 +1 @@ -Subproject commit 8bca037b052a4a4dc46a56a25a1b802652ee3f47 +Subproject commit a2a0c03c221a9bc37992147b5d4ad785a6e467fe diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index fac7eb9f5fd..005dd0aeb03 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -29,10 +29,6 @@ #include "shared-bindings/_bleio/ScanEntry.h" #include "shared-bindings/time/__init__.h" -#if CIRCUITPY_OS_GETENV -#include "shared-bindings/os/__init__.h" -#endif - #define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) #define SEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000000) / (RESOLUTION)) #define UNITS_TO_SEC(TIME, RESOLUTION) (((TIME)*(RESOLUTION)) / 1000000) @@ -247,9 +243,6 @@ static void check_enabled(bleio_adapter_obj_t *adapter) { // return true; // } -// Includes trailing null. -char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0, 0}; - static void _adapter_set_name(bleio_adapter_obj_t *self, mp_obj_str_t *name_obj) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(name_obj, &bufinfo, MP_BUFFER_READ); @@ -259,29 +252,9 @@ static void _adapter_set_name(bleio_adapter_obj_t *self, mp_obj_str_t *name_obj) // Get various values and limits set by the adapter. // Set event mask. static void bleio_adapter_hci_init(bleio_adapter_obj_t *self) { - mp_int_t name_len = 0; + self->name = NULL; - #if CIRCUITPY_OS_GETENV - mp_obj_t name = common_hal_os_getenv("CIRCUITPY_BLE_NAME", mp_const_none); - if (name != mp_const_none) { - mp_arg_validate_type_string(name, MP_QSTR_CIRCUITPY_BLE_NAME); - self->name = name; - } - #endif - - if (!self->name) { - name_len = sizeof(default_ble_name) - 1; - bt_addr_t addr; - hci_check_error(hci_read_bd_addr(&addr)); - - default_ble_name[name_len - 4] = nibble_to_hex_lower[addr.val[1] >> 4 & 0xf]; - default_ble_name[name_len - 3] = nibble_to_hex_lower[addr.val[1] & 0xf]; - default_ble_name[name_len - 2] = nibble_to_hex_lower[addr.val[0] >> 4 & 0xf]; - default_ble_name[name_len - 1] = nibble_to_hex_lower[addr.val[0] & 0xf]; - // default_ble_name[name_len] will be zero. - self->name = mp_obj_new_str(default_ble_name, (uint8_t)name_len); - } - _adapter_set_name(self, self->name); + bleio_adapter_reset_name(self); // Get version information. if (hci_read_local_version(&self->hci_version, &self->hci_revision, &self->lmp_version, @@ -394,18 +367,14 @@ bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *s bt_addr_t addr; hci_check_error(hci_read_bd_addr(&addr)); - bleio_address_obj_t *address = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - - common_hal_bleio_address_construct(address, addr.val, BT_ADDR_LE_PUBLIC); - return address; + // The cached address is refreshed on every call. + common_hal_bleio_address_construct(&self->address, addr.val, BT_ADDR_LE_PUBLIC); + self->address.base.type = &bleio_address_type; + return &self->address; } bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { - mp_buffer_info_t bufinfo; - if (!mp_get_buffer(address->bytes, &bufinfo, MP_BUFFER_READ)) { - return false; - } - return hci_le_set_random_address(bufinfo.buf) == HCI_OK; + return hci_le_set_random_address(address->bytes) == HCI_OK; } mp_obj_str_t *common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) { @@ -660,11 +629,8 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, // Copy peer address, if supplied. if (directed_to) { - mp_buffer_info_t bufinfo; - if (mp_get_buffer(directed_to->bytes, &bufinfo, MP_BUFFER_READ)) { - peer_addr.type = directed_to->type; - memcpy(&peer_addr.a.val, bufinfo.buf, sizeof(peer_addr.a.val)); - } + peer_addr.type = directed_to->type; + memcpy(&peer_addr.a.val, directed_to->bytes, sizeof(peer_addr.a.val)); } bool extended = @@ -950,7 +916,6 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { } connection->connection_obj = mp_const_none; } - } void bleio_adapter_background(bleio_adapter_obj_t *adapter) { diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index fda1c11d6cb..c018c676171 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -11,6 +11,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" @@ -65,6 +66,10 @@ typedef struct _bleio_adapter_obj_t { // the service they belong to. This vets that. uint16_t last_added_service_handle; uint16_t last_added_characteristic_handle; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; } bleio_adapter_obj_t; uint16_t bleio_adapter_add_attribute(bleio_adapter_obj_t *adapter, mp_obj_t *attribute); diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index a33b8ff4784..49b66d38e72 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -180,7 +180,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, } const uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); - common_hal_bleio_check_connected(conn_handle); + bleio_check_connected(conn_handle); uint16_t cccd_value = (notify ? CCCD_NOTIFY : 0) | diff --git a/devices/ble_hci/common-hal/_bleio/Connection.c b/devices/ble_hci/common-hal/_bleio/Connection.c index 30ed0af575c..028b68796b5 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.c +++ b/devices/ble_hci/common-hal/_bleio/Connection.c @@ -323,6 +323,18 @@ bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) { return self->connection->conn_handle != BLE_CONN_HANDLE_INVALID; } +bool common_hal_bleio_connection_get_authenticated(bleio_connection_obj_t *self) { + return false; +} + +mp_obj_t common_hal_bleio_connection_get_numeric_comparison(bleio_connection_obj_t *self) { + return mp_const_none; +} + +void common_hal_bleio_connection_confirm_pairing(bleio_connection_obj_t *self, bool accept) { + mp_raise_NotImplementedError(NULL); +} + void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) { hci_disconnect(self->conn_handle); } diff --git a/devices/ble_hci/common-hal/_bleio/Connection.h b/devices/ble_hci/common-hal/_bleio/Connection.h index 04edb104ddc..02a000501bf 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.h +++ b/devices/ble_hci/common-hal/_bleio/Connection.h @@ -61,6 +61,7 @@ typedef struct { uint8_t disconnect_reason; } bleio_connection_obj_t; +void bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/devices/ble_hci/common-hal/_bleio/PacketBuffer.c b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c index 771a1509f39..f29f4dd88a7 100644 --- a/devices/ble_hci/common-hal/_bleio/PacketBuffer.c +++ b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c @@ -245,6 +245,8 @@ void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { if (!common_hal_bleio_packet_buffer_deinited(self)) { bleio_characteristic_clear_observer(self->characteristic); ringbuf_deinit(&self->ringbuf); + // Mark as deinited, so common_hal_bleio_packet_buffer_deinited() reports it. + self->characteristic = NULL; } } diff --git a/devices/ble_hci/common-hal/_bleio/PacketBuffer.h b/devices/ble_hci/common-hal/_bleio/PacketBuffer.h index 563f365d21b..4e001339fe3 100644 --- a/devices/ble_hci/common-hal/_bleio/PacketBuffer.h +++ b/devices/ble_hci/common-hal/_bleio/PacketBuffer.h @@ -28,4 +28,7 @@ typedef struct { bool packet_queued; } bleio_packet_buffer_obj_t; +// Unused, but needed for _common_hal_bleio_packet_buffer_construct() +typedef void *ble_event_handler_t; + void bleio_packet_buffer_update(bleio_packet_buffer_obj_t *self, mp_buffer_info_t *bufinfo); diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index 6376f6f10c8..29078944aaa 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -30,7 +30,7 @@ bool vm_used_ble; // switch (sec_status) { // case BLE_GAP_SEC_STATUS_UNSPECIFIED: -// mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored.")); +// mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. The pairing request on the other device may have been declined or ignored.")); // return; // default: // mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unknown security error: 0x%04x"), sec_status); @@ -38,6 +38,13 @@ bool vm_used_ble; // } void common_hal_bleio_init(void) { + // Called on every import of _bleio. This is the only initialization HCI gets: + // unlike other ports, nothing runs at board startup, because HCI is unusable + // until user code supplies an adapter (UART, etc.) anyway. + // Create a UUID object for all CCCD's. + cccd_uuid.base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(&cccd_uuid, BLE_UUID_CCCD, NULL); + bleio_hci_reset(); } void bleio_user_reset(void) { @@ -47,10 +54,6 @@ void bleio_user_reset(void) { // Turn off BLE on a reset or reload. void bleio_reset(void) { - // Create a UUID object for all CCCD's. - cccd_uuid.base.type = &bleio_uuid_type; - common_hal_bleio_uuid_construct(&cccd_uuid, BLE_UUID_CCCD, NULL); - bleio_hci_reset(); if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { @@ -84,7 +87,7 @@ bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void) { return &common_hal_bleio_adapter_obj; } -void common_hal_bleio_check_connected(uint16_t conn_handle) { +void bleio_check_connected(uint16_t conn_handle) { if (conn_handle == BLE_CONN_HANDLE_INVALID) { mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected")); } diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index 930b4793161..7e4a43aee97 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -136,6 +136,8 @@ static void send_error(uint16_t conn_handle, uint8_t opcode, uint16_t handle, ui .code = BT_ATT_OP_ERROR_RSP, }, { .request = opcode, + .handle = handle, + .error = code, }}; hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(rsp), (uint8_t *)&rsp); diff --git a/docs/environment.rst b/docs/environment.rst index b97820b3caf..6ba541ba34c 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -1,72 +1,91 @@ Environment Variables ===================== -CircuitPython 8.0.0 introduces support for environment variables. Environment -variables are commonly used to store "secrets" such as Wi-Fi passwords and API -keys. This method *does not* make them secure. It only separates them from the -code. +CircuitPython provides support for environment variables. These values +can be examined by user code, and are also used as settings by CircuitPython during startup. -CircuitPython uses a file called ``settings.toml`` at the drive root (no -folder) as the environment. User code can access the values from the file -using `os.getenv()`. It is recommended to save any values used repeatedly in a -variable because `os.getenv()` will parse the ``settings.toml`` file contents -on every access. +CircuitPython looks for a file called ``settings.toml`` at the **CIRCUITPY** drive root +to find the values of environment variables, +The file format is a subset of the `TOML config file language `__. -CircuitPython only supports a subset of the full toml specification, see below -for more details. The subset is very "Python-like", which is a key reason we -selected the format. +User code can access the values from the file using either `os.getenv()` or `supervisor.get_setting()` +The value returned by `os.getenv()` is always a string, but `supervisor.get_setting()` +will parse a value into a Python object: a string, an integer, a float, or a boolean. -Due to technical limitations it probably also accepts some files that are -not valid TOML files; bugs of this nature are subject to change (i.e., be -fixed) without the usual deprecation period for incompatible changes. +Both `os.getenv()` and `supervisor.get_setting()` +read and parse the ``settings.toml`` file on every access. +It will save time to copy any values you use repeatedly into variables. -File format example: +Environment variables are sometimes used to store "secrets" such as Wi-Fi passwords and API +keys. The ``settings.toml`` file *does not* make the secrets secure. It only separates them from the +code. -.. code-block:: +CircuitPython supports only a subset of the full TOML specification; see below for more details. +The subset is very "Python-like", which is a key reason the format was selected. +To make the code simpler, the implementation accepts some files that are +not valid TOML, but do not depend on this. - str_key="Hello world" # with trailing comment - int_key = 7 - unicode_key="œuvre" - unicode_key2="\\u0153uvre" # same as above - unicode_key3="\\U00000153uvre" # same as above - escape_codes="supported, including \\r\\n\\"\\\\" - # comment - [subtable] - subvalue="cannot retrieve this using getenv" +The full TOML specification provides for tables labeled with table names in brackets, like +``[table_name]``. +CircuitPython does not support this and ignores any explicit inline TOML tables. +Here is an example ``settings.toml`` file. +Entries consist of a key and value, separated by an ``=`` sign. +Upper and lower case may both be used in the key name. -Details of the toml language subset +.. code-block:: + + # Comment. + CIRCUITPY_WIFI_PASSWORD = "mypassword" + GREETING="Hello world" # trailing comments are ok + REPEAT_COUNT = 7 # an integer + CIRCUITPY_SDCARD_USB = false # a boolean + delay = 0.75 # a float + FRENCH="œuvre" # unicode can be used + FRENCH2="\u0153uvre" # same unicode string, using a 16-bit escape code + FRENCH3="\U00000153uvre" # same unicode string, using a 32-bit escape code + STRING_WITH_ESCAPE_CODES="supported, including \r \n \" \\" + +Details of the TOML language subset ----------------------------------- -* The content is required to be in UTF-8 encoding -* The supported data types are string and integer -* Only basic strings are supported, not triple-quoted strings -* Only integers supported by strtol. (no 0o, no 0b, no underscores 1_000, 011 - is 9, not 11) -* Only bare keys are supported +* The content must be in UTF-8 encoding +* The supported data types are strings, integers, floats, and booleans. +* Whitespace is allowed. +* Only basic strings are supported, not triple-quoted strings. +* Only integers supported by ``strtol()`` can be parsed: + no ``0o``, no ``0b``, no underscores ``1_000``, ``011`` is 9, not 11. +* Only bare keys are supported. * Duplicate keys are not diagnosed. -* Comments are supported -* Only values from the "root table" can be retrieved -* due to technical limitations, the content of multi-line - strings can erroneously be parsed as a value. +* Comments are allowed. +* Only values from the "root table" can be retrieved. + CircuitPython behavior ---------------------- -CircuitPython will also read the environment to configure its behavior. Some keys are read at -startup once and others are read on reload (ctrl-D in the REPL). If a reload doesn't change things, -then try a reset (a power cycle or pressing the reset button). Other keys are ignored by CircuitPython. -Here are the keys it uses: +On startup, CircuitPython looks for for certain key/value pairs to use as configuration values. +Some values are read only once, after a hard reset, and others are read on each reload (ctrl-D in the REPL). +If you edit ``settings.toml`` and a reload doesn't read your changes, +then try a hard reset (a power cycle or pressing the reset button). +You can also include any other key/value pairs in the file for use with your own code. -Core CircuitPython keys -^^^^^^^^^^^^^^^^^^^^^^^ +Keys that affect CircuitPython behavior +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +CIRCUITPY_BLE_NAME (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If supplied, sets the BLE name the board advertises as, including for the BLE workflow. +Otherwise, defaults to ``CIRCUITPYxxxx``, where ``xxxx`` varies per board. + +CIRCUITPY_BLE_WORKFLOW (boolean) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If ``false``, disable the BLE workflow. Defaults to ``true``. If ``false``, +changing ``supervisor.runtime.ble_workflow`` has no effect. -CIRCUITPY_BLE_NAME -~~~~~~~~~~~~~~~~~~ -Default BLE name the board advertises as, including for the BLE workflow. -CIRCUITPY_HEAP_START_SIZE -~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_HEAP_START_SIZE (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the initial size of the python heap, allocated from the outer heap. Must be a multiple of 4. The default is currently 8192. The python heap will grow by doubling and redoubling this initial size until it cannot fit in the outer heap. @@ -74,37 +93,60 @@ Larger values will reserve more RAM for python use and prevent the supervisor an from large allocations of their own. Smaller values will likely grow sooner than large start sizes. -CIRCUITPY_PYSTACK_SIZE -~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_PYSTACK_SIZE (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the size of the python stack. Must be a multiple of 4. The default value is currently 1536. Increasing the stack reduces the size of the heap available to python code. Used to avoid "Pystack exhausted" errors when the code can't be reworked to avoid it. -CIRCUITPY_WEB_API_PASSWORD -~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_WEB_API_PASSWORD (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Password required to make modifications to the board from the Web Workflow. - -CIRCUITPY_WEB_API_PORT -~~~~~~~~~~~~~~~~~~~~~~ -TCP port number used for the web HTTP API. Defaults to 80 when omitted. - -CIRCUITPY_WEB_INSTANCE_NAME -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Name the board advertises as for the WEB workflow. Defaults to human readable board name if omitted. - -CIRCUITPY_WIFI_PASSWORD -~~~~~~~~~~~~~~~~~~~~~~~ -Wi-Fi password used to auto connect to CIRCUITPY_WIFI_SSID. - -CIRCUITPY_WIFI_SSID -~~~~~~~~~~~~~~~~~~~ -Wi-Fi SSID to auto-connect to even if user code is not running. - -Additional board specific keys +If the password is not specified, the Web Workflow is not enabled. + +CIRCUITPY_WEB_API_PORT (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +TCP port number used for the Web Workflow HTTP API. Defaults to 80 when omitted. + +CIRCUITPY_WEB_INSTANCE_NAME (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Human-friendly name the board advertises over mDNS for the Web Workflow. +Defaults to the human-readable board name if omitted. +This is not the hostname. + +CIRCUITPY_WIFI_SSID (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +CIRCUITPY_WIFI_PASSWORD (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If these values are supplied, connects automatically to a local WiFi network +with the specified SSID and password before ``boot.py`` and/or ``code.py`` are run. + +CIRCUITPY_WIFI_HOSTNAME (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If supplied, sets the initial ``wifi.radio.hostname`` to the given value. +Otherwise, the default value is ``cpy--``, +with some shortening for length if necessary. +If the supplied value is an invalid hostname or is too long, it is ignored. + +CIRCUITPY_SDCARD_USB (boolean) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Present a mounted SD card as a USB MSC device. If the board has default pins for an SD card socket, +the card is mounted automatically on startup. +Only one card can be presented. +Defaults to ``true``, except on the Adafruit Memento board, where it defaults to ``false`` +for now to avoid a bug. +SD card presentation can slow down board startup, +so set this to ``false`` if you don't need this feature. + + +Additional board-specific keys ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -CIRCUITPY_DISPLAY_WIDTH (Sunton, MaTouch) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_DISPLAY_WIDTH (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(Sunton, MaTouch boards) + Selects the correct screen resolution (1024x600 or 800x640) for the particular board variant. If the CIRCUITPY_DISPLAY_WIDTH parameter is set to a value of 1024 the display is initialized during power up at 1024x600 otherwise the display will be initialized at a resolution @@ -114,8 +156,8 @@ of 800x480. `Sunton ESP32-2432S028 `_ `Sunton ESP32-2432S024C `_ -CIRCUITPY_DISPLAY_ROTATION -~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_DISPLAY_ROTATION (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Selects the correct screen rotation (0, 90, 180 or 270) for the particular board variant. If the CIRCUITPY_DISPLAY_ROTATION parameter is set the display will be initialized during power up with the selected rotation, otherwise the display will be initialized with @@ -126,8 +168,8 @@ a rotation of 0. Attempting to initialize the screen with a rotation other than `Adafruit Feather RP2350 `_ `Adafruit Metro RP2350 `_ -CIRCUITPY_DISPLAY_FREQUENCY -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_DISPLAY_FREQUENCY (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Allows the entry of a display frequency used during the "dotclock" framebuffer construction. If a valid frequency is not defined the board will initialize the framebuffer with a frequency of 12500000hz (12.5Mhz). The value should be entered as an integer in hertz @@ -137,8 +179,8 @@ display frequency. `Sunton ESP32-8048S050 `_ -CIRCUITPY_PICODVI_ENABLE -~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_PICODVI_ENABLE (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Whether to configure the display at board initialization time, one of the following: .. code-block:: @@ -154,8 +196,16 @@ until it is released by ``displayio.release_displays()``. It does not appear at `Adafruit Feather RP2350 `_ `Adafruit Metro RP2350 `_ -CIRCUITPY_DISPLAY_WIDTH, CIRCUITPY_DISPLAY_HEIGHT, and CIRCUITPY_DISPLAY_COLOR_DEPTH (RP2350 boards with DVI or HSTX connector) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_DISPLAY_WIDTH (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +CIRCUITPY_DISPLAY_HEIGHT (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +CIRCUITPY_DISPLAY_COLOR_DEPTH (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(RP2350 boards with DVI or HSTX connector) + Selects the desired resolution and color depth. Supported resolutions are: @@ -181,23 +231,30 @@ Example: Configure the display to 640x480 black and white (1 bit per pixel): `Adafruit Feather RP2350 `_ `Adafruit Metro RP2350 `_ -CIRCUITPY_TERMINAL_SCALE -~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_SAFEMODE_DELAY (float) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Wait for the specified amount of time, in seconds, for the user to press the reset button +to initiate safe mode after a hard reset. +The status LED blinks during this time. +If not specified, use the default delay, which is one second. + +CIRCUITPY_TERMINAL_SCALE (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Allows the entry of a display scaling factor used during the terminalio console construction. The entered scaling factor only affects the terminalio console and has no impact on the UART, Web Workflow, BLE Workflow, etc consoles. -This feature is not enabled on boards that the CIRCUITPY_OS_GETENV (os CIRCUIPTY_FULL_BUILD) +This feature is not enabled on boards that the CIRCUITPY_SETTINGS_TOML (or CIRCUITPY_FULL_BUILD) flag has been set to 0. Currently this is primarily boards with limited flash including some of the Atmel_samd boards based on the SAMD21/M0 microprocessor. -CIRCUITPY_TERMINAL_FONT -~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_TERMINAL_FONT (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Specifies a custom font file path to use for the terminalio console instead of the default ``/fonts/terminal.lvfontbin``. This allows users to create and use custom fonts for the CircuitPython console. -This feature requires both CIRCUITPY_OS_GETENV and CIRCUITPY_LVFONTIO to be enabled. +This feature requires both CIRCUITPY_SETTINGS_TOML and CIRCUITPY_LVFONTIO to be enabled. Example: diff --git a/docs/library/builtins.rst b/docs/library/builtins.rst index 148c1513f3d..c8e05d895e5 100644 --- a/docs/library/builtins.rst +++ b/docs/library/builtins.rst @@ -37,6 +37,35 @@ Functions and types |see_cpython| `python:bytes`. + .. method:: bytes.decode(encoding='utf-8', errors='strict') + + Decode the bytes object to a string using the specified *encoding*. + + MicroPython supports the following encodings: + + - ``'utf-8'`` or ``'utf8'`` - UTF-8 encoding (default) + - ``'ascii'`` - ASCII encoding (subset of UTF-8) + + The *errors* parameter controls how decoding errors are handled: + + - ``'strict'`` - Raise a ``UnicodeError`` on invalid UTF-8 (default) + - ``'ignore'`` - Skip invalid bytes (requires ``MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS``) + - ``'replace'`` - Replace invalid bytes with U+FFFD '�' (requires ``MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS``) + + .. note:: + Error handler support depends on build configuration. On constrained + systems, only ``'strict'`` mode may be available. + + Example:: + + >>> b'\xc2\xa9 2024'.decode('utf-8') # © symbol + '© 2024' + >>> b'hello\xffworld'.decode('utf-8', 'ignore') # Skip invalid bytes + 'helloworld' + + Raises ``LookupError`` if the encoding is not supported, or + ``UnicodeError`` if the data contains invalid UTF-8 and ``errors='strict'``. + .. function:: callable() .. function:: chr() @@ -152,6 +181,35 @@ Functions and types .. class:: str() + .. method:: str.encode(encoding='utf-8') + + Encode the string to bytes using the specified *encoding*. + + MicroPython supports the following encodings: + + - ``'utf-8'`` or ``'utf8'`` - UTF-8 encoding (default) + - ``'ascii'`` - ASCII encoding (subset of UTF-8) + + Example:: + + >>> '© 2024'.encode('utf-8') # Copyright symbol + b'\xc2\xa9 2024' + + Raises ``LookupError`` if the encoding is not supported. + + .. method:: str.center(width) + + Return a centered string of length *width*. Padding is done using spaces. + + When Unicode support is enabled (``MICROPY_PY_BUILTINS_STR_UNICODE``), this + method counts Unicode characters rather than bytes, ensuring proper alignment + for multi-byte UTF-8 characters. + + Example:: + + >>> 'café'.center(10) # é is 2 bytes in UTF-8 + ' café ' + .. function:: sum() .. function:: super() diff --git a/docs/library/collections.rst b/docs/library/collections.rst index b006a97dcaf..c3ec763d20e 100644 --- a/docs/library/collections.rst +++ b/docs/library/collections.rst @@ -109,3 +109,19 @@ Classes a 2 w 5 b 3 + + .. method:: OrderedDict.popitem() + + Remove and return a (key, value) pair from the dictionary. + Pairs are returned in LIFO order. + + .. admonition:: Difference to CPython + :class: attention + + ``OrderedDict.popitem()`` does not support the ``last=False`` argument and + will always remove and return the last item if present. + + A workaround for this is to use ``pop()`` to remove the first item:: + + first_key = next(iter(d)) + d.pop(first_key) diff --git a/docs/library/gc.rst b/docs/library/gc.rst index d1625c0d8f3..7e946469f63 100644 --- a/docs/library/gc.rst +++ b/docs/library/gc.rst @@ -2,7 +2,8 @@ ========================================== .. module:: gc - :synopsis: control the garbage collector + :synopsis: control the garbage collector which automatically frees + :ref:`heap memory ` |see_cpython_module| :mod:`python:gc`. @@ -18,6 +19,10 @@ Functions Disable automatic garbage collection. Heap memory can still be allocated, and garbage collection can still be initiated manually using :meth:`gc.collect`. +.. function:: isenabled() + + Returns True if automatic garbage collection is enabled, and False otherwise. + .. function:: collect() Run a garbage collection. @@ -64,3 +69,40 @@ Functions This function is a MicroPython extension. CPython has a similar function - ``set_threshold()``, but due to different GC implementations, its signature and semantics are different. + + Examples + ^^^^^^^^ + + To trigger a garbage collection each time 32768 bytes of RAM have been allocated in total:: + + gc.threshold(32768) + + To restore the default behaviour, only triggering garbage collection when out of memory:: + + gc.threshold(-1) + +Example +------- + +.. code-block:: bash + + >>> import gc + >>> gc.mem_free() # Gets number of bytes free in memory + 8192 + >>> gc.mem_alloc() # Gets number of bytes allocated in memory + 1024 + >>> foo = bytearray(1000) # Create a big array of data + >>> gc.mem_free() # Show that there's less memory available + 7168 + >>> gc.mem_alloc() # Show that there's more memory used + 2048 + >>> del foo # Delete the object + >>> gc.mem_free() # Show that collection hasn't run yet + 7168 + >>> gc.mem_alloc() # That memory is still allocated + 2048 + >>> gc.collect() # Manually run the collection + >>> gc.mem_free() # Now we have reclaimed that memory + 8192 + >>> gc.mem_alloc() # That memory is no longer allocated + 1024 diff --git a/docs/library/index.rst b/docs/library/index.rst index 4e763e8a27e..d5f0b240f1b 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -34,6 +34,7 @@ These libraries are not currently enabled in any CircuitPython build, but may be platform.rst re.rst select.rst + string.templatelib.rst sys.rst Omitted ``string`` functions diff --git a/docs/library/io.rst b/docs/library/io.rst index ad1fb03c777..8ebb2e8c63f 100644 --- a/docs/library/io.rst +++ b/docs/library/io.rst @@ -71,8 +71,9 @@ buffered, they aren't in MicroPython. (Indeed, that's one of the cases for which we may introduce buffering support.) Note that for efficiency, MicroPython doesn't provide abstract base -classes corresponding to the hierarchy above, and it's not possible -to implement, or subclass, a stream class in pure Python. +classes corresponding to the hierarchy above. However, the +:class:`IOBase` class can be subclassed to implement custom stream +objects in pure Python. Functions --------- @@ -95,6 +96,68 @@ Classes This is type of a file open in text mode, e.g. using ``open(name, "rt")``. You should not instantiate this class directly. +.. class:: IOBase() + + Base class for implementing custom stream objects in Python. Subclasses + can override ``readinto``, ``write``, and ``ioctl`` to create objects + that work with ``print()``, ``json.dump()``, ``select.poll()``, + ``open()`` via a user filesystem, and other stream consumers. + + .. admonition:: Difference to CPython + :class: attention + + In CPython, ``io.IOBase`` has a much larger API surface. MicroPython's + ``IOBase`` is minimal: the C stream infrastructure provides standard + methods like ``read()``, ``readline()``, ``seek()``, ``close()``, and + ``flush()`` automatically. Subclasses only need to implement the + methods below. + + Subclasses implement some or all of the following methods. The C stream + layer calls these internally when user code calls standard stream + functions. + + .. method:: IOBase.readinto(buf) + + Read data into *buf* (a ``bytearray`` sized by the caller). Return the + number of bytes read, 0 at EOF, or ``None`` if no data is available on + a non-blocking stream. Return a negative errno value (e.g. ``-errno.EIO`` + or ``-1``) to signal an error. + + .. method:: IOBase.write(buf) + + Write *buf* (a ``bytearray``) to the stream. Return the number of + bytes written, or ``None`` if a non-blocking stream cannot accept data. + Return a negative errno value to signal an error. + + .. method:: IOBase.ioctl(op, arg) + + Control the stream and query its properties. The operation to perform + is given by *op* which is one of the following integers: + + - 1 -- flush write buffers (*arg* is unused) + - 3 -- poll for readiness; *arg* is a bitmask of events to check, + return a bitmask of ready events. Poll flags: + + * ``0x0001`` -- data available for reading + * ``0x0004`` -- stream ready for writing + * ``0x0008`` -- error condition + * ``0x0010`` -- hang up (e.g. connection closed) + * ``0x0020`` -- invalid request + + - 4 -- close the stream (*arg* is unused) + - 11 -- return the preferred read buffer size, or 0 (*arg* is unused) + + As a minimum ``ioctl(4, ...)`` should be handled to support stream + closure. Implement ``ioctl(3, ...)`` if the stream will be used with + ``select.poll()`` or ``asyncio``. + + Other operations exist for advanced use cases (2 = seek, 5 = timeout, + 10 = fileno); see ``py/stream.h`` for the full list. + + Must always return an integer. Return 0 for success, or ``-1`` for + unsupported operations. (Returning 0 for an unhandled operation tells + the C layer the operation was processed successfully, which may cause + incorrect behaviour.) .. class:: StringIO([string]) .. class:: BytesIO([string]) @@ -129,3 +192,77 @@ Classes :class: attention These constructors are a MicroPython extension. + +IOBase Examples +--------------- + +A minimal write-only stream that collects output into a buffer:: + + import io + + class MyOutput(io.IOBase): + def __init__(self): + self.data = bytearray() + + def write(self, buf): + self.data.extend(buf) + return len(buf) + + def ioctl(self, op, arg): + if op == 4: # close + return 0 + return -1 + + s = MyOutput() + print("hello", file=s) + print(s.data) # bytearray(b'hello\n') + +A readable stream that can be used with ``select.poll()``:: + + import io, select + from micropython import const + + _MP_STREAM_POLL = const(3) + _MP_STREAM_POLL_RD = const(0x0001) + _MP_STREAM_CLOSE = const(4) + + class RingBuffer(io.IOBase): + def __init__(self, size): + self._buf = bytearray(size) + self._size = size + self._wpos = 0 + self._rpos = 0 + + def _available(self): + return (self._wpos - self._rpos) % self._size + + def put(self, data): + for b in data: + self._buf[self._wpos % self._size] = b + self._wpos = (self._wpos + 1) % self._size + + def readinto(self, buf): + n = min(len(buf), self._available()) + for i in range(n): + buf[i] = self._buf[self._rpos % self._size] + self._rpos = (self._rpos + 1) % self._size + return n + + def ioctl(self, op, arg): + if op == _MP_STREAM_POLL: + if arg & _MP_STREAM_POLL_RD and self._available() > 0: + return _MP_STREAM_POLL_RD + return 0 + if op == _MP_STREAM_CLOSE: + return 0 + return -1 + + rb = RingBuffer(64) + rb.put(b"test data") + + poller = select.poll() + poller.register(rb, select.POLLIN) + for obj, flags in poller.poll(0): + buf = bytearray(16) + n = obj.readinto(buf) + print(buf[:n]) # bytearray(b'test data') diff --git a/docs/library/platform.rst b/docs/library/platform.rst index c091477d84c..c19ef0f5df5 100644 --- a/docs/library/platform.rst +++ b/docs/library/platform.rst @@ -36,3 +36,11 @@ Functions Returns a tuple of strings *(lib, version)*, where *lib* is the name of the libc that MicroPython is linked to, and *version* the corresponding version of this libc. + +.. function:: processor() + + Returns a string with a detailed name of the processor, if one is available. + If no name for the processor is known, it will return an empty string + instead. + + This is currently available only on RISC-V targets (both 32 and 64 bits). diff --git a/docs/library/re.rst b/docs/library/re.rst index 19b15d2d2c2..47f623c5600 100644 --- a/docs/library/re.rst +++ b/docs/library/re.rst @@ -54,6 +54,10 @@ Supported operators and special sequences are: Grouping. Each group is capturing (a substring it captures can be accessed with `match.group()` method). +``(?:...)`` + Non-capturing grouping. Each group is matched using the same rules as + regular grouping, but will not be part of the match object. + ``\d`` Matches digit. Equivalent to ``[0-9]``. @@ -87,7 +91,6 @@ Supported operators and special sequences are: * counted repetitions (``{m,n}``) * named groups (``(?P...)``) -* non-capturing groups (``(?:...)``) * more advanced assertions (``\b``, ``\B``) * special character escapes like ``\r``, ``\n`` - use Python's own escaping instead @@ -154,8 +157,8 @@ Regex objects Compiled regular expression. Instances of this class are created using `re.compile()`. -.. method:: regex.match(string) - regex.search(string) +.. method:: regex.match(string, [pos, [endpos]]) + regex.search(string, [pos, [endpos]]) regex.sub(replace, string, count=0, flags=0, /) Similar to the module-level functions :meth:`match`, :meth:`search` @@ -163,6 +166,16 @@ Compiled regular expression. Instances of this class are created using Using methods is (much) more efficient if the same regex is applied to multiple strings. + The optional second parameter *pos* gives an index in the string where the + search is to start; it defaults to ``0``. This is not completely equivalent + to slicing the string; the ``'^'`` pattern character matches at the real + beginning of the string and at positions just after a newline, but not + necessarily at the index where the search is to start. + + The optional parameter *endpos* limits how far the string will be searched; + it will be as if the string is *endpos* characters long, so only the + characters from *pos* to ``endpos - 1`` will be searched for a match. + .. method:: regex.split(string, max_split=-1, /) Split a *string* using regex. If *max_split* is given, it specifies diff --git a/docs/library/select.rst b/docs/library/select.rst index 08bbe08df2c..dcf1aa781b6 100644 --- a/docs/library/select.rst +++ b/docs/library/select.rst @@ -76,6 +76,9 @@ Methods In case of timeout, an empty list is returned. + Calling ``poll.poll`` is guaranteed to call pending callback functions + before entering the polling loop. + .. admonition:: Difference to CPython :class: attention @@ -93,6 +96,9 @@ Methods won't be processed until new mask is set with `poll.modify()`. This behaviour is useful for asynchronous I/O schedulers. + Calling ``poll.ipoll`` is guaranteed to call pending callback functions + before entering the polling loop. + .. admonition:: Difference to CPython :class: attention diff --git a/docs/library/string.templatelib.rst b/docs/library/string.templatelib.rst new file mode 100644 index 00000000000..4d10bdf124f --- /dev/null +++ b/docs/library/string.templatelib.rst @@ -0,0 +1,225 @@ +:mod:`string.templatelib` -- Template String Support +==================================================== + +.. module:: string.templatelib + :synopsis: PEP 750 template string support + +This module provides support for template strings (t-strings) as defined in +`PEP 750 `_. Template strings are created +using the ``t`` prefix and provide access to both the literal string parts and +interpolated values before they are combined. + +Classes +------- + +.. class:: Template(*args) + + Represents a template string. Template objects are typically created by + t-string syntax (``t"..."``) but can also be constructed directly using + the constructor. + + .. attribute:: strings + + A tuple of string literals that appear between interpolations. + + .. attribute:: interpolations + + A tuple of :class:`Interpolation` objects representing the interpolated + expressions. + + .. attribute:: values + + A read-only property that returns a tuple containing the ``value`` + attribute from each interpolation in the template. + + .. method:: __iter__() + + Iterate over the template contents, yielding string parts and + :class:`Interpolation` objects in the order they appear. Empty strings + are omitted. + + .. method:: __add__(other) + + Concatenate two templates. Returns a new :class:`Template` combining + the strings and interpolations from both templates. + + :raises TypeError: if *other* is not a :class:`Template` + + Template concatenation with ``str`` is prohibited to avoid ambiguity + about whether the string should be treated as a literal or interpolation:: + + t1 = t"Hello " + t2 = t"World" + result = t1 + t2 # Valid + + # TypeError: cannot concatenate str to Template + result = t1 + "World" + +.. class:: Interpolation(value, expression='', conversion=None, format_spec='') + + Represents an interpolated expression within a template string. All + arguments can be passed as keyword arguments. + + .. attribute:: value + + The evaluated value of the interpolated expression. + + .. attribute:: expression + + The string representation of the expression as it appeared in the + template string. + + .. attribute:: conversion + + The conversion specifier (``'s'`` or ``'r'``) if present, otherwise ``None``. + Note that MicroPython does not support the ``'a'`` conversion. + + .. attribute:: format_spec + + The format specification string if present, otherwise an empty string. + +Template String Syntax +---------------------- + +Template strings use the same syntax as f-strings but with a ``t`` prefix:: + + name = "World" + template = t"Hello {name}!" + + # Access template components + print(template.strings) # ('Hello ', '!') + print(template.values) # ('World',) + print(template.interpolations[0].expression) # 'name' + +Conversion Specifiers +~~~~~~~~~~~~~~~~~~~~~ + +Template strings store conversion specifiers as metadata. Unlike f-strings, +the conversion is not applied automatically:: + + value = "test" + t = t"{value!r}" + # t.interpolations[0].value == "test" (not repr(value)) + # t.interpolations[0].conversion == "r" + +Processing code must explicitly apply conversions when needed. + +Format Specifications +~~~~~~~~~~~~~~~~~~~~~ + +Format specifications are stored as metadata in the ``Interpolation`` object. +Unlike f-strings, formatting is not applied automatically:: + + pi = 3.14159 + t = t"{pi:.2f}" + # t.interpolations[0].value == 3.14159 (not formatted) + # t.interpolations[0].format_spec == ".2f" + +Per PEP 750, processing code is not required to use format specifications, but +when present they should be respected and match f-string behavior where possible. + +Debug Format +~~~~~~~~~~~~ + +The debug format ``{expr=}`` is supported:: + + x = 42 + t = t"{x=}" + # t.strings == ("x=", "") + # t.interpolations[0].expression == "x" + # t.interpolations[0].conversion == "r" + +.. admonition:: Important + :class: attention + + As per PEP 750, unlike f-strings, template strings do not automatically + apply conversions or format specifications. This is by design to allow + processing code to control how these are handled. Processing code must + explicitly handle these attributes. + + MicroPython does not provide the ``format()`` built-in function. Use + string formatting methods like ``str.format()`` instead. + +Example Usage +------------- + +Basic processing without format support:: + + def simple_process(template): + """Simple template processing""" + parts = [] + for item in template: + if isinstance(item, str): + parts.append(item) + else: + parts.append(str(item.value)) + return "".join(parts) + +Processing template with format support:: + + from string.templatelib import Template, Interpolation + + def convert(value, conversion): + """Apply conversion specifier to value""" + if conversion == "r": + return repr(value) + elif conversion == "s": + return str(value) + return value + + def process_template(template): + """Process template with conversion and format support""" + result = [] + for part in template: + if isinstance(part, str): + result.append(part) + else: # Interpolation + value = convert(part.value, part.conversion) + if part.format_spec: + # Apply format specification using str.format + value = ("{:" + part.format_spec + "}").format(value) + else: + value = str(value) + result.append(value) + return "".join(result) + + pi = 3.14159 + name = "Alice" + t = t"{name!r}: {pi:.2f}" + print(process_template(t)) + # Output: "'Alice': 3.14" + + # Other format specifications work too + value = 42 + print(process_template(t"{value:>10}")) # " 42" + print(process_template(t"{value:04d}")) # "0042" + +HTML escaping example:: + + def html_escape(value): + """Escape HTML special characters""" + if not isinstance(value, str): + value = str(value) + return value.replace("&", "&").replace("<", "<").replace(">", ">") + + def safe_html(template): + """Convert template to HTML-safe string""" + result = [] + for part in template: + if isinstance(part, str): + result.append(part) + else: + result.append(html_escape(part.value)) + return "".join(result) + + user_input = "" + t = t"User said: {user_input}" + print(safe_html(t)) + # Output: "User said: <script>alert('xss')</script>" + +See Also +-------- + +* `PEP 750 `_ - Template Strings specification +* :ref:`python:formatstrings` - Format string syntax +* `Formatted string literals `_ - f-strings in Python diff --git a/docs/library/sys.rst b/docs/library/sys.rst index 8def36a2b07..c9c687df359 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -12,17 +12,9 @@ Functions .. function:: exit(retval=0, /) Terminate current program with a given exit code. Underlyingly, this - function raise as `SystemExit` exception. If an argument is given, its + function raises a `SystemExit` exception. If an argument is given, its value given as an argument to `SystemExit`. -.. function:: print_exception(exc, file=sys.stdout, /) - - This function is deprecated and will be removed starting in - CircuitPython 10.x, `traceback.print_exception()` should be used instead. - - Print exception with a traceback to a file-like object *file* (or - `sys.stdout` by default). - .. admonition:: Difference to CPython :class: attention @@ -52,6 +44,8 @@ Constants * *version* - tuple (major, minor, micro), e.g. (1, 7, 0) * *_machine* - string describing the underlying machine * *_mpy* - supported mpy file-format version (optional attribute) + * *_build* - string that can help identify the configuration that + MicroPython was built with This object is the recommended way to distinguish CircuitPython from other Python implementations (note that it still may not exist in the very @@ -116,15 +110,15 @@ Constants .. data:: stderr - Standard error ``stream``. + Standard error `stream`. .. data:: stdin - Standard input ``stream``. + Standard input `stream`. .. data:: stdout - Standard output ``stream``. + Standard output `stream`. .. data:: version diff --git a/docs/library/weakref.rst b/docs/library/weakref.rst new file mode 100644 index 00000000000..ffebc91277b --- /dev/null +++ b/docs/library/weakref.rst @@ -0,0 +1,78 @@ +:mod:`weakref` -- Python object lifetime management +=================================================== + +.. module:: weakref + :synopsis: Create weak references to Python objects + +|see_cpython_module| :mod:`python:weakref`. + +This module allows creation of weak references to Python objects. A weak reference +is a non-traceable reference to a heap-allocated Python object, so the garbage +collector can still reclaim the object even though the weak reference refers to it. + +Python callbacks can be registered to be called when an object is reclaimed by the +garbage collector. This provides a safe way to clean up when objects are no longer +needed. + +**Availability:** the weakref module requires ``MICROPY_PY_WEAKREF`` to be enabled +at compile time. It is enabled on the unix coverage variant and the webassembly +pyscript variant. + +ref objects +----------- + +A ref object is the simplest way to make a weak reference. + +.. class:: ref(object [, callback], /) + + Return a weak reference to the given *object*. + + If *callback* is given and is not ``None`` then, when *object* is reclaimed + by the garbage collector and if the weak reference object is still alive, the + *callback* will be called. The *callback* will be passed the weak reference + object as its single argument. + +.. method:: ref.__call__() + + Calling the weak reference object will return its referenced object if that + object is still alive. Otherwise ``None`` will be returned. + +finalize objects +---------------- + +A finalize object is an extended version of a ref object that is more convenient to +use, and allows more control over the callback. + +.. class:: finalize(object, callback, /, *args, **kwargs) + + Return a weak reference to the given *object*. In contrast to *weakref.ref* + objects, finalize objects are held onto internally and will not be collected until + *object* is collected. + + A finalize object starts off alive. It transitions to the dead state when the + finalize object is called, either explicitly or when *object* is collected. It also + transitions to dead if the `finalize.detach()` method is called. + + When *object* is reclaimed by the garbage collector (or the finalize object is + explicitly called by user code) and the finalize object is still in the alive state, + the *callback* will be called. The *callback* will be passed arguments as: + ``callback(*args, **kwargs)``. + +.. method:: finalize.__call__() + + If the finalize object is alive then it transitions to the dead state and returns + the value of ``callback(*args, **kwargs)``. Otherwise ``None`` will be returned. + +.. method:: finalize.alive + + Read-only boolean attribute that indicates if the finalizer is in the alive state. + +.. method:: finalize.peek() + + If the finalize object is alive then return ``(object, callback, args, kwargs)``. + Otherwise return ``None``. + +.. method:: finalize.detach() + + If the finalize object is alive then it transitions to the dead state and returns + ``(object, callback, args, kwargs)``. Otherwise ``None`` will be returned. diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index 9e9330de4cc..391dc307d23 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -186,6 +186,13 @@ Glossary Most MicroPython boards make a REPL available over a UART, and this is typically accessible on a host PC via USB. + small integer + MicroPython optimises the internal representation of integers such that + "small" values do not take up space on the heap, and calculations with + them do not require heap allocation. On most 32-bit ports, this + corresponds to values in the interval ``-2**30 <= x < 2**30``, but this + should be considered an implementation detail and not relied upon. + stream Also known as a "file-like object". A Python object which provides sequential read-write access to the underlying data. A stream object diff --git a/docs/rstjinja.py b/docs/rstjinja.py index e7d8a312f1f..ab940dc7134 100644 --- a/docs/rstjinja.py +++ b/docs/rstjinja.py @@ -5,7 +5,7 @@ def render_with_jinja(docname, source): - if re.search("^\s*.. jinja$", source[0], re.M): + if re.search(r"^\s*.. jinja$", source[0], re.M): return True return False @@ -38,3 +38,7 @@ def rstjinja(app, docname, source): def setup(app): app.connect("source-read", rstjinja) + return { + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/docs/shared_bindings_matrix.py b/docs/shared_bindings_matrix.py index b4fe4ff7e24..2f9eb796788 100644 --- a/docs/shared_bindings_matrix.py +++ b/docs/shared_bindings_matrix.py @@ -84,8 +84,9 @@ "keypad.Keys": "CIRCUITPY_KEYPAD_KEYS", "keypad.ShiftRegisterKeys": "CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS", "keypad_demux.DemuxKeyMatrix": "CIRCUITPY_KEYPAD_DEMUX", - "os.getenv": "CIRCUITPY_OS_GETENV", + "os.getenv": "CIRCUITPY_SETTINGS_TOML", "select": "MICROPY_PY_SELECT_SELECT", + "supervisor.get_setting": "CIRCUITPY_SETTINGS_TOML", "sys": "CIRCUITPY_SYS", "terminalio": "CIRCUITPY_DISPLAYIO", "usb": "CIRCUITPY_PYUSB", @@ -199,6 +200,8 @@ def get_settings_from_makefile(port_dir, board_name): contents = subprocess.run( [ "make", + # Don't let make run in parallel; it can mix up the output from the various "print-" targets. + "-j1", "-C", port_dir, "-f", diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index 7fad2aac181..d505ff09ef0 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -7,22 +7,22 @@ variety of errors that can happen, what they mean and how to fix them. File system issues ------------------ -If your host computer starts complaining that your ``CIRCUITPY`` drive is corrupted +If your host computer starts complaining that your **CIRCUITPY** drive is corrupted or files cannot be overwritten or deleted, then you will have to erase it completely. -When CircuitPython restarts it will create a fresh empty ``CIRCUITPY`` filesystem. +When CircuitPython restarts it will create a fresh empty **CIRCUITPY** filesystem. -Corruption often happens on Windows when the ``CIRCUITPY`` disk is not safely ejected +Corruption often happens on Windows when the **CIRCUITPY** disk is not safely ejected before being reset by the button or being disconnected from USB. This can also happen on Linux and Mac OSX but it's less likely. -.. caution:: To erase and re-create ``CIRCUITPY`` (for example, to correct a corrupted filesystem), +.. caution:: To erase and re-create **CIRCUITPY** (for example, to correct a corrupted filesystem), follow one of the procedures below. It's important to note that **any files stored on the** - ``CIRCUITPY`` **drive will be erased. Back up your code if possible before continuing!** + **CIRCUITPY** **drive will be erased. Back up your code if possible before continuing!** REPL Erase Method ^^^^^^^^^^^^^^^^^ This is the recommended method of erasing your board. If you are having trouble accessing the -``CIRCUITPY`` drive or the REPL, consider first putting your board into +**CIRCUITPY** drive or the REPL, consider first putting your board into `safe mode `_. **To erase any board if you have access to the REPL:** @@ -30,7 +30,7 @@ This is the recommended method of erasing your board. If you are having trouble #. Connect to the CircuitPython REPL using a terminal program. #. Type ``import storage`` into the REPL. #. Then, type ``storage.erase_filesystem()`` into the REPL. -#. The ``CIRCUITPY`` drive will be erased and the board will restart with an empty ``CIRCUITPY`` drive. +#. The **CIRCUITPY** drive will be erased and the board will restart with an empty **CIRCUITPY** drive. Erase File Method ^^^^^^^^^^^^^^^^^ diff --git a/docs/workflows.md b/docs/workflows.md index 84d7530e2fe..ad676d5678e 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -4,11 +4,11 @@ Workflows are the process used to 1) manipulate files on the CircuitPython devic with the serial connection to CircuitPython. The serial connection is usually used to access the REPL. -Starting with CircuitPython 3.x we moved to a USB-only workflow. Prior to that, we used the serial -connection alone to do the whole workflow. In CircuitPython 7.x, a BLE workflow was added with the -advantage of working with mobile devices. CircuitPython 8.x added a web workflow that works over the -local network (usually Wi-Fi) and a web browser. Other clients can also use the Web REST API. Boards -should clearly document which workflows are supported. +CircuitPython started with a USB mass storage device workflow for filesystem operations. +CircuitPython 7.x added a BLE workflow with the advantage of working with mobile devices. +CircuitPython 8.x added a web workflow that works over the +local network (usually Wi-Fi) and a web browser. +Other clients can also use the Web REST API. Boards should clearly document which workflows are supported. Code for workflows lives in `supervisor/shared`. @@ -21,7 +21,7 @@ device has been plugged into a host. ### Mass Storage CircuitPython exposes a standard mass storage (MSC) interface to enable file manipulation over a -standard interface. (This is how USB drives work.) This interface works underneath the file system at +standard interface. The board appears as a USB drive. This interface works underneath the file system at the block level so using it excludes other types of workflows from manipulating the file system at the same time. @@ -29,55 +29,68 @@ CircuitPython 10.x adds multiple Logical Units (LUNs) to the mass storage interf multiple drives to be accessed and ejected independently. #### CIRCUITPY drive -The CIRCUITPY drive is the main drive that CircuitPython uses. It is writable by the host by default +The CIRCUITPY drive is the main drive that CircuitPython presents. It is writable by the host by default and read-only to CircuitPython. `storage.remount()` can be used to remount the drive to CircuitPython as read-write. #### CPSAVES drive -The board may also expose a CPSAVES drive. (This is based on the ``CIRCUITPY_SAVES_PARTITION_SIZE`` -setting in ``mpconfigboard.h``.) It is a portion of the main flash that is writable by CircuitPython -by default. It is read-only to the host. `storage.remount()` can be used to remount the drive to the -host as read-write. +The board may also expose a CPSAVES drive. (This is based on the `CIRCUITPY_SAVES_PARTITION_SIZE` +setting in `mpconfigboard.h`.) It is a portion of the main flash that is writable by CircuitPython +by default. The CPSAVES drive becomes visible to the attached host computer after a few seconds. +By default it is read-only to the host, but `storage.remount()` can be used to remount the drive +as read-write to the host #### SD card drive -A few boards have SD card automounting. (This is based on the ``DEFAULT_SD`` settings in -``mpconfigboard.h``.) The card is writable from CircuitPython by default and read-only to the host. +A few boards auomatically mount an SD card, if present, to the `/sd` mount point. +Boards that do this have `DEFAULT_SD` settings in`mpconfigboard.h` which allow detecting the +presence of an SD card, and fixed pin settings for the SD card socket. +The mounted SD card is writable from CircuitPython by default and read-only to the host. `storage.remount()` can be used to remount the drive to the host as read-write. -On most other boards, except for ``atmel-samd`` boards, an SD card mounted in user code -at ``/sd`` will become visible after a few seconds on the attached host computer, as an -additional drive besides CIRCUITPY and (if present) CPSAVES. It will present with the volume -label on the SD card. Depending on the host operating system settings, the drive may or may not be -auto-mounted on the host. Host writes to drives mounted by user code will not trigger a reload. +If `CIRCUITPY_SDCARD_USB` in settings.toml is `true` (the default), +an SD card mounted in user code at `/sd` will become visible on the attached host computer +after a few seconds, as an additional drive besides CIRCUITPY and (if present) CPSAVES. +It will present with the volume label on the SD card. +Depending on the host operating system settings, the drive may or may not be +auto-mounted on the host. +Host writes to drives mounted by user code will not trigger a reload. ### CDC serial -CircuitPython exposes one CDC USB interface for CircuitPython serial. This is a standard serial -USB interface. +CircuitPython exposes a standard serial CDC USB interface for the CircuitPython REPL. +Setting the CDC's baudrate 1200 and disconnecting will reboot the board into a bootloader. +This technique was first used by Arduino boards and the Arduino IDE to trigger a reset into bootloader. -TODO: Document how it designates itself from the user CDC. +A second CDC interface is optionally available for binary data transfer (see `usb_cdc`). -Setting baudrate 1200 and disconnecting will reboot into a bootloader. (Used by Arduino to trigger -a reset into bootloader.) ## BLE -The BLE workflow is enabled for Nordic boards. By default, to prevent malicious access, it is disabled. -To connect to the BLE workflow, press the reset button while the status led blinks blue quickly -after the safe mode blinks. The board will restart and broadcast the file transfer service UUID -(`0xfebb`) along with the board's [Creation IDs](https://github.com/creationid/creators). This -public broadcast is done at a lower transmit level so the devices must be closer. On connection, the -device will need to pair and bond. Once bonded, the device will broadcast whenever disconnected -using a rotating key rather than a static one. Non-bonded devices won't be able to resolve it. After -connection, the central device can discover two default services. One for file transfer and one for -CircuitPython specifically that includes serial characteristics. +The BLE workflow provides file transfer and REPL access over BLE. +It can be controlled by setting `CIRCUITPY_BLE_WORKFLOW` to be `true` or `false`. +in `settings.toml`. The default is `true`. + +To prevent malicious access, even if `CIRCUITPY_BLE_WORKFLOW=true`, +the user must initiate a bonded connection with the host. +To bond, press the reset button when the status led blinks blue quickly after reset, +after the safe mode blinks. +The board will restart and advertise the file transfer service UUID (`0xfebb`) +along with the board's [Creation ID](https://github.com/creationid/creators). +This public advertisement is done at a lower transmit level so the devices must be closer. +On connection, the device will need to pair and bond. +Once bonded, the device will advertise whenever disconnected, +using a rotating key rather than a static one. +Non-bonded devices won't be able to resolve it. + +After connection, will discover two default services: one is for file transfer and +the other provides version information and a serial connection to the CircuitPython REPL. To change the default BLE advertising name without (or before) running user code, the desired name -can be put in the `settings.toml` file. The key is `CIRCUITPY_BLE_NAME`. It's limited to approximately -30 characters depending on the port's settings and will be truncated if longer. +can be put in the `settings.toml` using the `CIRCUITPY_BLE_NAME` key. The name is limited to approximately +30 characters, depending on the port, and will be truncated if longer. ### File Transfer API -CircuitPython uses [an open File Transfer API](https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer) +The file transfer service provides [an open File Transfer API](https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer) to enable file system access. ### CircuitPython Service @@ -87,22 +100,22 @@ replaced by the four specific digits below. The service itself is `0001`. #### TX - `0002` / RX - `0003` -These characteristic work just like the Nordic Uart Service (NUS) but have different UUIDs to prevent -conflicts with user created NUS services. +The TX and RX characteristics for the CircuitPython service work just like the Nordic Uart Service (NUS) +but have different UUIDs to prevent conflicts with user-created NUS services. #### Version - `0100` -Read-only characteristic that returns the UTF-8 encoded version string. +The Version characteristic is read-only and returns the UTF-8 encoded version string. ## Web If the keys `CIRCUITPY_WIFI_SSID` and `CIRCUITPY_WIFI_PASSWORD` are set in `settings.toml`, CircuitPython will automatically connect to the given Wi-Fi network on boot and upon reload. -If `CIRCUITPY_WEB_API_PASSWORD` is set, MDNS and the http server for the web workflow will also start. +If `CIRCUITPY_WEB_API_PASSWORD` is set, MDNS and the HTTP server for the web workflow will also start. -The webserver is on port 80 unless overridden by `CIRCUITPY_WEB_API_PORT`. It also enables MDNS. +The webserver is on port 80 unless overridden by `CIRCUITPY_WEB_API_PORT`. It also enables mDNS. The name of the board as advertised to the network can be overridden by `CIRCUITPY_WEB_INSTANCE_NAME`. -Here is an example `/settings.toml`: +Here is an example `settings.toml`: ```bash # To auto-connect to Wi-Fi @@ -249,7 +262,7 @@ curl -v -u :passw0rd -X PUT -L --location-trusted http://circuitpython.local/fs/ ``` ##### Move -Moves the directory at the given path to ``X-Destination``. Also known as rename. +Moves the directory at the given path to `X-Destination`. Also known as rename. The custom `X-Destination` header stores the destination path of the directory. @@ -335,7 +348,7 @@ curl -v -u :passw0rd -L --location-trusted http://circuitpython.local/fs/lib/hel ##### Move -Moves the file at the given path to the ``X-Destination``. Also known as rename. +Moves the file at the given path to the `X-Destination`. Also known as rename. The custom `X-Destination` header stores the destination path of the file. diff --git a/examples/natmod/.gitignore b/examples/natmod/.gitignore new file mode 100644 index 00000000000..4815d20f06b --- /dev/null +++ b/examples/natmod/.gitignore @@ -0,0 +1 @@ +*.mpy diff --git a/examples/natmod/README.md b/examples/natmod/README.md new file mode 100644 index 00000000000..ca6b887d034 --- /dev/null +++ b/examples/natmod/README.md @@ -0,0 +1,74 @@ +# Dynamic Native Modules + +Dynamic Native Modules are .mpy files that contain native machine code from a +language other than Python. For more info see [the +documentation](https://docs.micropython.org/en/latest/develop/natmod.html). + +This should not be confused with [User C +Modules](https://docs.micropython.org/en/latest/develop/cmodules.html) which are +a mechanism to add additional out-of-tree modules into the firmware build. + +## Examples + +This directory contains several examples of writing dynamic native modules, in +two main categories: + +1. Feature examples. + + * `features0` - A module containing a single "factorial" function which + demonstrates working with integers. + + * `features1` - A module that demonstrates some common tasks: + - defining simple functions exposed to Python + - defining local, helper C functions + - defining constant integers and strings exposed to Python + - getting and creating integer objects + - creating Python lists + - raising exceptions + - allocating memory + - BSS and constant data (rodata) + - relocated pointers in rodata + + * `features2` - This is a hybrid module containing both Python and C code, + and additionally the C code is spread over multiple files. It also + demonstrates using floating point (only when the target supports + hardware floating point). + + * `features3` - A module that shows how to use types, constant objects, + and creating dictionary instances. + + * `features4` - A module that demonstrates how to define a class. + +2. Dynamic version of existing built-ins. + + This provides a way to add missing functionality to firmware that doesn't + include certain built-in modules. See the `heapq`, `random`, `re`, + `deflate`, `btree`, and `framebuf` directories. + + So for example, if your firmware was compiled with `MICROPY_PY_FRAMEBUF` + disabled (e.g. to save flash space), then it would not include the + `framebuf` module. The `framebuf` native module provides a way to add the + `framebuf` module dynamically. + + The way these work is they define a dynamic native module which + `#include`'s the original module and then does the necessary + initialisation of the module's globals dict. + +## Build instructions + +To compile an example, you need to have the same toolchain available as +required for your target port. e.g. `arm-none-eabi-gcc` for any ARM Cortex M +target. See the port instructions for details. + +You also need to have the `pyelftools` Python package available, either via +your system package manager or installed from PyPI in a virtual environment +with `pip`. + +Each example provides a Makefile. You should specify the `ARCH` argument to +make (one of x86, x64, armv6m, armv7m, xtensa, xtensawin, rv32imc): + +``` +$ cd features0 +$ make ARCH=armv7m +$ mpremote cp features0.mpy : +``` diff --git a/examples/natmod/btree/Makefile b/examples/natmod/btree/Makefile new file mode 100644 index 00000000000..040fa770396 --- /dev/null +++ b/examples/natmod/btree/Makefile @@ -0,0 +1,62 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in btree so it can coexist) +MOD_BASE = btree +MOD = $(MOD_BASE)_$(ARCH) + +# Source files (.c or .py) +SRC = btree_c.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx +BERKELEY_DB_CONFIG_FILE ?= \"extmod/berkeley-db/berkeley_db_config_port.h\" +CFLAGS += -I$(BTREE_DIR)/include +CFLAGS += -DBERKELEY_DB_CONFIG_FILE=$(BERKELEY_DB_CONFIG_FILE) +CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter +CFLAGS += -Wno-deprecated-non-prototype + +SRC += $(addprefix $(realpath $(BTREE_DIR))/,\ + btree/bt_close.c \ + btree/bt_conv.c \ + btree/bt_delete.c \ + btree/bt_get.c \ + btree/bt_open.c \ + btree/bt_overflow.c \ + btree/bt_page.c \ + btree/bt_put.c \ + btree/bt_search.c \ + btree/bt_seq.c \ + btree/bt_split.c \ + btree/bt_utils.c \ + mpool/mpool.c \ + ) + +ifeq ($(ARCH),xtensa) +MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld +endif + +# Use our own errno implementation if Picolibc is used +CFLAGS += -D__PICOLIBC_ERRNO_FUNCTION=__errno + +ifeq ($(ARCH),armv6m) +# Link with libgcc.a for division helper functions +LINK_RUNTIME = 1 +endif + +# Strip the architecture name from the internal filename. +MPY_LD_FLAGS = "--source-name=$(MOD_BASE).mpy" + +ifeq ($(ARCH),armv7m) +ifeq ($(findstring clang,$(shell $(CC) --version)),clang) +# Link with libclang_rt.builtins.a for memset/memcpy. +LINK_RUNTIME = 1 +endif +endif + +include $(MPY_DIR)/py/dynruntime.mk + +# btree needs gnu99 defined +CFLAGS += -std=gnu99 diff --git a/examples/natmod/btree/btree_c.c b/examples/natmod/btree/btree_c.c new file mode 100644 index 00000000000..c26dbcc8478 --- /dev/null +++ b/examples/natmod/btree/btree_c.c @@ -0,0 +1,158 @@ +#define MICROPY_PY_BTREE (1) + +#include "py/dynruntime.h" + +#include + +void *malloc(size_t n) { + void *ptr = m_malloc(n); + return ptr; +} +void *realloc(void *ptr, size_t n) { + mp_printf(&mp_plat_print, "UNDEF %d\n", __LINE__); + return NULL; +} +void *calloc(size_t n, size_t m) { + void *ptr = m_malloc(n * m); + // memory already cleared by conservative GC + return ptr; +} + +void free(void *ptr) { + m_free(ptr); +} + +void abort_(void) { + nlr_raise(mp_obj_new_exception(mp_load_global(MP_QSTR_RuntimeError))); +} + +int puts(const char *s) { + return mp_printf(&mp_plat_print, "%s\n", s); +} + +int native_errno; +#if defined(__linux__) +int *__errno_location(void) +#else +int *__errno(void) +#endif +{ + return &native_errno; +} + +ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) { + mp_obj_base_t *o = stream; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); + mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) { + mp_obj_base_t *o = stream; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); + mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) { + const mp_obj_base_t *o = stream; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); + struct mp_stream_seek_t seek_s; + seek_s.offset = offset; + seek_s.whence = whence; + mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &native_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return seek_s.offset; +} + +int mp_stream_posix_fsync(void *stream) { + mp_obj_base_t *o = stream; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); + mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_FLUSH, 0, &native_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return res; +} + +mp_obj_full_type_t btree_type; +mp_getiter_iternext_custom_t btree_getiter_iternext; + +#include "extmod/modbtree.c" + +mp_map_elem_t btree_locals_dict_table[8]; +static MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table); + +static mp_obj_t btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // The allowed_args array must have its qstr's populated at runtime. + enum { ARG_flags, ARG_cachesize, ARG_pagesize, ARG_minkeypage }; + mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + allowed_args[0].qst = MP_QSTR_flags; + allowed_args[1].qst = MP_QSTR_cachesize; + allowed_args[2].qst = MP_QSTR_pagesize; + allowed_args[3].qst = MP_QSTR_minkeypage; + + // Make sure we got a stream object + mp_get_stream_raise(pos_args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + + 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); + + BTREEINFO openinfo = {0}; + openinfo.flags = args[ARG_flags].u_int; + openinfo.cachesize = args[ARG_cachesize].u_int; + openinfo.psize = args[ARG_pagesize].u_int; + openinfo.minkeypage = args[ARG_minkeypage].u_int; + DB *db = __bt_open(MP_OBJ_TO_PTR(pos_args[0]), &btree_stream_fvtable, &openinfo, 0); + if (db == NULL) { + mp_raise_OSError(native_errno); + } + + return MP_OBJ_FROM_PTR(btree_new(db, pos_args[0])); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(btree_open_obj, 1, btree_open); + +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 + + btree_getiter_iternext.getiter = btree_getiter; + btree_getiter_iternext.iternext = btree_iternext; + + btree_type.base.type = (void *)&mp_fun_table.type_type; + btree_type.flags = MP_TYPE_FLAG_ITER_IS_CUSTOM; + btree_type.name = MP_QSTR_btree; + MP_OBJ_TYPE_SET_SLOT(&btree_type, print, btree_print, 0); + MP_OBJ_TYPE_SET_SLOT(&btree_type, iter, &btree_getiter_iternext, 1); + MP_OBJ_TYPE_SET_SLOT(&btree_type, binary_op, btree_binary_op, 2); + MP_OBJ_TYPE_SET_SLOT(&btree_type, subscr, btree_subscr, 3); + btree_locals_dict_table[0] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&btree_close_obj) }; + btree_locals_dict_table[1] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_flush), MP_OBJ_FROM_PTR(&btree_flush_obj) }; + btree_locals_dict_table[2] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_get), MP_OBJ_FROM_PTR(&btree_get_obj) }; + btree_locals_dict_table[3] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_put), MP_OBJ_FROM_PTR(&btree_put_obj) }; + btree_locals_dict_table[4] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_seq), MP_OBJ_FROM_PTR(&btree_seq_obj) }; + btree_locals_dict_table[5] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_keys), MP_OBJ_FROM_PTR(&btree_keys_obj) }; + btree_locals_dict_table[6] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_values), MP_OBJ_FROM_PTR(&btree_values_obj) }; + btree_locals_dict_table[7] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_items), MP_OBJ_FROM_PTR(&btree_items_obj) }; + MP_OBJ_TYPE_SET_SLOT(&btree_type, locals_dict, (void *)&btree_locals_dict, 4); + + mp_store_global(MP_QSTR_open, MP_OBJ_FROM_PTR(&btree_open_obj)); + mp_store_global(MP_QSTR_INCL, MP_OBJ_NEW_SMALL_INT(FLAG_END_KEY_INCL)); + mp_store_global(MP_QSTR_DESC, MP_OBJ_NEW_SMALL_INT(FLAG_DESC)); + + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/deflate/Makefile b/examples/natmod/deflate/Makefile new file mode 100644 index 00000000000..aa0951e88ef --- /dev/null +++ b/examples/natmod/deflate/Makefile @@ -0,0 +1,35 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in uzlib so it can coexist) +MOD_BASE = deflate +MOD = $(MOD_BASE)_$(ARCH) + +# Source files (.c or .py) +SRC = deflate.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) +ARCH ?= x64 + +ifeq ($(ARCH),armv7m) +ifeq ($(findstring clang,$(shell $(CC) --version)),clang) +# Link with libclang_rt.a for memset +LINK_RUNTIME = 1 +endif +endif + +ifeq ($(ARCH),armv6m) +# Link with libgcc.a or libclang_rt.a for division helper functions +LINK_RUNTIME = 1 +endif + +ifeq ($(ARCH),xtensa) +# Link with libm.a and libgcc.a from the toolchain +LINK_RUNTIME = 1 +MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld +endif + +# Strip the architecture name from the internal filename. +MPY_LD_FLAGS = "--source-name=$(MOD_BASE).mpy" + +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 00000000000..3c470aca9f0 --- /dev/null +++ b/examples/natmod/deflate/deflate.c @@ -0,0 +1,61 @@ +#define MICROPY_PY_DEFLATE (1) +#define MICROPY_PY_DEFLATE_COMPRESS (1) + +#include "py/dynruntime.h" + +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/features0/Makefile b/examples/natmod/features0/Makefile new file mode 100644 index 00000000000..9bc4bbf23b8 --- /dev/null +++ b/examples/natmod/features0/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features0 + +# Source files (.c or .py) +SRC = features0.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features0/features0.c b/examples/natmod/features0/features0.c new file mode 100644 index 00000000000..c3d31afb79c --- /dev/null +++ b/examples/natmod/features0/features0.c @@ -0,0 +1,40 @@ +/* This example demonstrates the following features in a native module: + - defining a simple function exposed to Python + - defining a local, helper C function + - getting and creating integer objects +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// Helper function to compute factorial +static mp_int_t factorial_helper(mp_int_t x) { + if (x == 0) { + return 1; + } + return x * factorial_helper(x - 1); +} + +// This is the function which will be called from Python, as factorial(x) +static mp_obj_t factorial(mp_obj_t x_obj) { + // Extract the integer from the MicroPython input object + mp_int_t x = mp_obj_get_int(x_obj); + // Calculate the factorial + mp_int_t result = factorial_helper(x); + // Convert the result to a MicroPython integer object and return it + return mp_obj_new_int(result); +} +// Define a Python reference to the function above +static MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Make the function available in the module's namespace + mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features1/Makefile b/examples/natmod/features1/Makefile new file mode 100644 index 00000000000..49040511020 --- /dev/null +++ b/examples/natmod/features1/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features1 + +# Source files (.c or .py) +SRC = features1.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features1/features1.c b/examples/natmod/features1/features1.c new file mode 100644 index 00000000000..92b96dbb183 --- /dev/null +++ b/examples/natmod/features1/features1.c @@ -0,0 +1,106 @@ +/* This example demonstrates the following features in a native module: + - defining simple functions exposed to Python + - defining local, helper C functions + - defining constant integers and strings exposed to Python + - getting and creating integer objects + - creating Python lists + - raising exceptions + - allocating memory + - BSS and constant data (rodata) + - relocated pointers in rodata +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// BSS (zero) data +uint16_t data16[4]; + +// Constant data (rodata) +const uint8_t table8[] = { 0, 1, 1, 2, 3, 5, 8, 13 }; +const uint16_t table16[] = { 0x1000, 0x2000 }; + +// Constant data pointing to BSS/constant data +uint16_t *const table_ptr16a[] = { &data16[0], &data16[1], &data16[2], &data16[3] }; +const uint16_t *const table_ptr16b[] = { &table16[0], &table16[1] }; + +// A simple function that adds its 2 arguments (must be integers) +static mp_obj_t add(mp_obj_t x_in, mp_obj_t y_in) { + mp_int_t x = mp_obj_get_int(x_in); + mp_int_t y = mp_obj_get_int(y_in); + return mp_obj_new_int(x + y); +} +static MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add); + +// A local helper function (not exposed to Python) +static mp_int_t fibonacci_helper(mp_int_t x) { + if (x < MP_ARRAY_SIZE(table8)) { + return table8[x]; + } else { + return fibonacci_helper(x - 1) + fibonacci_helper(x - 2); + } +} + +// A function which computes Fibonacci numbers +static mp_obj_t fibonacci(mp_obj_t x_in) { + mp_int_t x = mp_obj_get_int(x_in); + if (x < 0) { + mp_raise_ValueError(MP_ERROR_TEXT("can't compute negative Fibonacci number")); + } + return mp_obj_new_int(fibonacci_helper(x)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci); + +// A function that accesses the BSS data +static mp_obj_t access(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // Create a list holding all items from data16 + mp_obj_list_t *lst = MP_OBJ_TO_PTR(mp_obj_new_list(MP_ARRAY_SIZE(data16), NULL)); + for (int i = 0; i < MP_ARRAY_SIZE(data16); ++i) { + lst->items[i] = mp_obj_new_int(data16[i]); + } + return MP_OBJ_FROM_PTR(lst); + } else if (n_args == 1) { + // Get one item from data16 + mp_int_t idx = mp_obj_get_int(args[0]) & 3; + return mp_obj_new_int(data16[idx]); + } else { + // Set one item in data16 (via table_ptr16a) + mp_int_t idx = mp_obj_get_int(args[0]) & 3; + *table_ptr16a[idx] = mp_obj_get_int(args[1]); + return mp_const_none; + } +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(access_obj, 0, 2, access); + +// A function that allocates memory and creates a bytearray +static mp_obj_t make_array(void) { + uint16_t *ptr = m_new(uint16_t, MP_ARRAY_SIZE(table_ptr16b)); + for (int i = 0; i < MP_ARRAY_SIZE(table_ptr16b); ++i) { + ptr[i] = *table_ptr16b[i]; + } + return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) * MP_ARRAY_SIZE(table_ptr16b), ptr); +} +static MP_DEFINE_CONST_FUN_OBJ_0(make_array_obj, make_array); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // 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 + mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj)); + mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj)); + mp_store_global(MP_QSTR_access, MP_OBJ_FROM_PTR(&access_obj)); + mp_store_global(MP_QSTR_make_array, MP_OBJ_FROM_PTR(&make_array_obj)); + + // Add some constants to the module's namespace + mp_store_global(MP_QSTR_VAL, MP_OBJ_NEW_SMALL_INT(42)); + mp_store_global(MP_QSTR_MSG, MP_OBJ_NEW_QSTR(MP_QSTR_HELLO_MICROPYTHON)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features2/Makefile b/examples/natmod/features2/Makefile new file mode 100644 index 00000000000..2129974048f --- /dev/null +++ b/examples/natmod/features2/Makefile @@ -0,0 +1,24 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features2 + +# Source files (.c or .py) +SRC = main.c prod.c test.py + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +ifeq ($(findstring clang,$(shell $(CC) --version)),clang) +ifeq ($(ARCH),$(filter $(ARCH),armv6m armv7m rv32imc)) +# Link with both libc.a and libclang_rt.builtins.a +LINK_CLANG_LIBC = 1 +endif +endif + +# Link with libm.a and libgcc.a from the toolchain +LINK_RUNTIME = 1 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features2/main.c b/examples/natmod/features2/main.c new file mode 100644 index 00000000000..5ce8e7b0130 --- /dev/null +++ b/examples/natmod/features2/main.c @@ -0,0 +1,94 @@ +/* This example demonstrates the following features in a native module: + - using floats + - calling math functions from libm.a + - defining additional code in Python (see test.py) + - have extra C code in a separate file (see prod.c) +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// Include the header for auxiliary C code for this module +#include "prod.h" + +// Include standard library header +#include + +// Automatically detect if this module should include double-precision code. +// If double precision is supported by the target architecture then it can +// be used in native module regardless of what float setting the target +// MicroPython runtime uses (being none, float or double). +#if defined(__i386__) || defined(__x86_64__) || (defined(__ARM_FP) && (__ARM_FP & 8)) +#define USE_DOUBLE 1 +#else +#define USE_DOUBLE 0 +#endif + +// A function that uses the default float type configured for the current target +// This default can be overridden by specifying MICROPY_FLOAT_IMPL at the make level +static mp_obj_t add(mp_obj_t x, mp_obj_t y) { + return mp_obj_new_float(mp_obj_get_float(x) + mp_obj_get_float(y)); +} +static MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add); + +// A function that explicitly uses single precision floats +static mp_obj_t add_f(mp_obj_t x, mp_obj_t y) { + return mp_obj_new_float_from_f(mp_obj_get_float_to_f(x) + mp_obj_get_float_to_f(y)); +} +static MP_DEFINE_CONST_FUN_OBJ_2(add_f_obj, add_f); + +#if USE_DOUBLE +// A function that explicitly uses double precision floats +static mp_obj_t add_d(mp_obj_t x, mp_obj_t y) { + return mp_obj_new_float_from_d(mp_obj_get_float_to_d(x) + mp_obj_get_float_to_d(y)); +} +static MP_DEFINE_CONST_FUN_OBJ_2(add_d_obj, add_d); +#endif + +// A function that uses libm +static mp_obj_t call_round(mp_obj_t x) { + return mp_obj_new_float_from_f(roundf(mp_obj_get_float_to_f(x))); +} +static MP_DEFINE_CONST_FUN_OBJ_1(round_obj, call_round); + +// A function that computes the product of floats in an array. +// This function uses the most general C argument interface, which is more difficult +// to use but has access to the globals dict of the module via self->globals. +static mp_obj_t productf(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // Check number of arguments is valid + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // Extract buffer pointer and verify typecode + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_RW); + if (bufinfo.typecode != 'f') { + mp_raise_ValueError(MP_ERROR_TEXT("expecting float array")); + } + + // Compute product, store result back in first element of array + float *ptr = bufinfo.buf; + float prod = prod_array(bufinfo.len / sizeof(*ptr), ptr); + ptr[0] = prod; + + return mp_const_none; +} + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Make the functions available in the module's namespace + mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj)); + mp_store_global(MP_QSTR_add_f, MP_OBJ_FROM_PTR(&add_f_obj)); + #if USE_DOUBLE + mp_store_global(MP_QSTR_add_d, MP_OBJ_FROM_PTR(&add_d_obj)); + #endif + mp_store_global(MP_QSTR_round, MP_OBJ_FROM_PTR(&round_obj)); + + // The productf function uses the most general C argument interface + mp_store_global(MP_QSTR_productf, MP_DYNRUNTIME_MAKE_FUNCTION(productf)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features2/prod.c b/examples/natmod/features2/prod.c new file mode 100644 index 00000000000..7791dcad1d2 --- /dev/null +++ b/examples/natmod/features2/prod.c @@ -0,0 +1,9 @@ +#include "prod.h" + +float prod_array(int n, float *ar) { + float ans = 1; + for (int i = 0; i < n; ++i) { + ans *= ar[i]; + } + return ans; +} diff --git a/examples/natmod/features2/prod.h b/examples/natmod/features2/prod.h new file mode 100644 index 00000000000..f27dd8d0330 --- /dev/null +++ b/examples/natmod/features2/prod.h @@ -0,0 +1 @@ +float prod_array(int n, float *ar); diff --git a/examples/natmod/features2/test.py b/examples/natmod/features2/test.py new file mode 100644 index 00000000000..af79b9692c2 --- /dev/null +++ b/examples/natmod/features2/test.py @@ -0,0 +1,31 @@ +# This Python code will be merged with the C code in main.c + +# ruff: noqa: F821 - this file is evaluated with C-defined names in scope + +import array + + +def isclose(a, b): + return abs(a - b) < 1e-3 + + +def test(): + tests = [ + isclose(add(0.1, 0.2), 0.3), + isclose(add_f(0.1, 0.2), 0.3), + ] + + ar = array.array("f", [1, 2, 3.5]) + productf(ar) + tests.append(isclose(ar[0], 7)) + + if "add_d" in globals(): + tests.append(isclose(add_d(0.1, 0.2), 0.3)) + + print(tests) + + if not all(tests): + raise SystemExit(1) + + +test() diff --git a/examples/natmod/features3/Makefile b/examples/natmod/features3/Makefile new file mode 100644 index 00000000000..3573f41caca --- /dev/null +++ b/examples/natmod/features3/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features3 + +# Source files (.c or .py) +SRC = features3.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features3/features3.c b/examples/natmod/features3/features3.c new file mode 100644 index 00000000000..1d3bc51e609 --- /dev/null +++ b/examples/natmod/features3/features3.c @@ -0,0 +1,60 @@ +/* This example demonstrates the following features in a native module: + - using types + - using constant objects + - creating dictionaries +*/ + +// Include the header file to get access to the MicroPython API. +#include "py/dynruntime.h" + +// A function that returns a tuple of object types. +static mp_obj_t get_types(void) { + return mp_obj_new_tuple(9, ((mp_obj_t []) { + MP_OBJ_FROM_PTR(&mp_type_type), + MP_OBJ_FROM_PTR(&mp_type_NoneType), + MP_OBJ_FROM_PTR(&mp_type_bool), + MP_OBJ_FROM_PTR(&mp_type_int), + MP_OBJ_FROM_PTR(&mp_type_str), + MP_OBJ_FROM_PTR(&mp_type_bytes), + MP_OBJ_FROM_PTR(&mp_type_tuple), + MP_OBJ_FROM_PTR(&mp_type_list), + MP_OBJ_FROM_PTR(&mp_type_dict), + })); +} +static MP_DEFINE_CONST_FUN_OBJ_0(get_types_obj, get_types); + +// A function that returns a tuple of constant objects. +static mp_obj_t get_const_objects(void) { + return mp_obj_new_tuple(5, ((mp_obj_t []) { + mp_const_none, + mp_const_false, + mp_const_true, + mp_const_empty_bytes, + mp_const_empty_tuple, + })); +} +static MP_DEFINE_CONST_FUN_OBJ_0(get_const_objects_obj, get_const_objects); + +// A function that creates a dictionary from the given arguments. +static mp_obj_t make_dict(size_t n_args, const mp_obj_t *args) { + mp_obj_t dict = mp_obj_new_dict(n_args / 2); + for (; n_args >= 2; n_args -= 2, args += 2) { + mp_obj_dict_store(dict, args[0], args[1]); + } + return dict; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(make_dict_obj, 0, MP_OBJ_FUN_ARGS_MAX, make_dict); + +// This is the entry point and is called when the module is imported. +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things. + MP_DYNRUNTIME_INIT_ENTRY + + // Make the functions available in the module's namespace. + mp_store_global(MP_QSTR_make_dict, MP_OBJ_FROM_PTR(&make_dict_obj)); + mp_store_global(MP_QSTR_get_types, MP_OBJ_FROM_PTR(&get_types_obj)); + mp_store_global(MP_QSTR_get_const_objects, MP_OBJ_FROM_PTR(&get_const_objects_obj)); + + // This must be last, it restores the globals dict. + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features4/Makefile b/examples/natmod/features4/Makefile new file mode 100644 index 00000000000..34fc3a7ef7b --- /dev/null +++ b/examples/natmod/features4/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features4 + +# Source files (.c or .py) +SRC = features4.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features4/features4.c b/examples/natmod/features4/features4.c new file mode 100644 index 00000000000..c4d82a1f700 --- /dev/null +++ b/examples/natmod/features4/features4.c @@ -0,0 +1,89 @@ +/* + This example extends on features0 but demonstrates how to define a class, + and a custom exception. + + The Factorial class constructor takes an integer, and then the calculate + method can be called to get the factorial. + + >>> import features4 + >>> f = features4.Factorial(4) + >>> f.calculate() + 24 + + If the argument to the Factorial class constructor is less than zero, a + FactorialError is raised. +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// This is type(Factorial) +mp_obj_full_type_t mp_type_factorial; + +// This is the internal state of a Factorial instance. +typedef struct { + mp_obj_base_t base; + mp_int_t n; +} mp_obj_factorial_t; + +mp_obj_full_type_t mp_type_FactorialError; + +// Essentially Factorial.__new__ (but also kind of __init__). +// Takes a single argument (the number to find the factorial of) +static mp_obj_t factorial_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + mp_obj_factorial_t *o = mp_obj_malloc(mp_obj_factorial_t, type); + o->n = mp_obj_get_int(args_in[0]); + + if (o->n < 0) { + mp_raise_msg((mp_obj_type_t *)&mp_type_FactorialError, "argument must be zero or above"); + } + + return MP_OBJ_FROM_PTR(o); +} + +static mp_int_t factorial_helper(mp_int_t x) { + if (x == 0) { + return 1; + } + return x * factorial_helper(x - 1); +} + +// Implements Factorial.calculate() +static mp_obj_t factorial_calculate(mp_obj_t self_in) { + mp_obj_factorial_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(factorial_helper(self->n)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(factorial_calculate_obj, factorial_calculate); + +// Locals dict for the Factorial type (will have a single method, calculate, +// added in mpy_init). +mp_map_elem_t factorial_locals_dict_table[1]; +static MP_DEFINE_CONST_DICT(factorial_locals_dict, factorial_locals_dict_table); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Initialise the type. + mp_type_factorial.base.type = (void *)&mp_type_type; + mp_type_factorial.flags = MP_TYPE_FLAG_NONE; + mp_type_factorial.name = MP_QSTR_Factorial; + MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, make_new, factorial_make_new, 0); + factorial_locals_dict_table[0] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_calculate), MP_OBJ_FROM_PTR(&factorial_calculate_obj) }; + MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, locals_dict, (void *)&factorial_locals_dict, 1); + + // Make the Factorial type available on the module. + mp_store_global(MP_QSTR_Factorial, MP_OBJ_FROM_PTR(&mp_type_factorial)); + + // Initialise the exception type. + mp_obj_exception_init(&mp_type_FactorialError, MP_QSTR_FactorialError, &mp_type_Exception); + + // Make the FactorialError type available on the module. + mp_store_global(MP_QSTR_FactorialError, MP_OBJ_FROM_PTR(&mp_type_FactorialError)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/framebuf/Makefile b/examples/natmod/framebuf/Makefile new file mode 100644 index 00000000000..86a201d23bd --- /dev/null +++ b/examples/natmod/framebuf/Makefile @@ -0,0 +1,33 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in framebuf so it can coexist) +MOD_BASE = framebuf +MOD = $(MOD_BASE)_$(ARCH) + +# Source files (.c or .py) +SRC = framebuf.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) +ARCH ?= x64 + +ifeq ($(ARCH),armv7m) +ifeq ($(findstring clang,$(shell $(CC) --version)),clang) +# Link with libclang_rt.a for memset +LINK_RUNTIME = 1 +endif +endif + +ifeq ($(ARCH),armv6m) +# Link with libgcc.a for division helper functions +LINK_RUNTIME = 1 +endif + +ifeq ($(ARCH),xtensa) +MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld +endif + +# Strip the architecture name from the internal filename. +MPY_LD_FLAGS = "--source-name=$(MOD_BASE).mpy" + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/framebuf/framebuf.c b/examples/natmod/framebuf/framebuf.c new file mode 100644 index 00000000000..6e672439fe9 --- /dev/null +++ b/examples/natmod/framebuf/framebuf.c @@ -0,0 +1,45 @@ +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_FRAMEBUF (1) + +#include "py/dynruntime.h" + +mp_obj_full_type_t mp_type_framebuf; + +#include "extmod/modframebuf.c" + +mp_map_elem_t framebuf_locals_dict_table[12]; +static MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_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 + + mp_type_framebuf.base.type = (void *)&mp_type_type; + mp_type_framebuf.name = MP_QSTR_FrameBuffer; + MP_OBJ_TYPE_SET_SLOT(&mp_type_framebuf, make_new, framebuf_make_new, 0); + MP_OBJ_TYPE_SET_SLOT(&mp_type_framebuf, buffer, framebuf_get_buffer, 1); + framebuf_locals_dict_table[0] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_fill), MP_OBJ_FROM_PTR(&framebuf_fill_obj) }; + framebuf_locals_dict_table[1] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_fill_rect), MP_OBJ_FROM_PTR(&framebuf_fill_rect_obj) }; + framebuf_locals_dict_table[2] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_pixel), MP_OBJ_FROM_PTR(&framebuf_pixel_obj) }; + framebuf_locals_dict_table[3] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_hline), MP_OBJ_FROM_PTR(&framebuf_hline_obj) }; + framebuf_locals_dict_table[4] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_vline), MP_OBJ_FROM_PTR(&framebuf_vline_obj) }; + framebuf_locals_dict_table[5] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_rect), MP_OBJ_FROM_PTR(&framebuf_rect_obj) }; + framebuf_locals_dict_table[6] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_line), MP_OBJ_FROM_PTR(&framebuf_line_obj) }; + framebuf_locals_dict_table[7] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_ellipse), MP_OBJ_FROM_PTR(&framebuf_ellipse_obj) }; + framebuf_locals_dict_table[8] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_poly), MP_OBJ_FROM_PTR(&framebuf_poly_obj) }; + framebuf_locals_dict_table[9] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_blit), MP_OBJ_FROM_PTR(&framebuf_blit_obj) }; + framebuf_locals_dict_table[10] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_scroll), MP_OBJ_FROM_PTR(&framebuf_scroll_obj) }; + framebuf_locals_dict_table[11] = (mp_map_elem_t) { MP_OBJ_NEW_QSTR(MP_QSTR_text), MP_OBJ_FROM_PTR(&framebuf_text_obj) }; + MP_OBJ_TYPE_SET_SLOT(&mp_type_framebuf, locals_dict, (void *)&framebuf_locals_dict, 2); + + mp_store_global(MP_QSTR_FrameBuffer, MP_OBJ_FROM_PTR(&mp_type_framebuf)); + mp_store_global(MP_QSTR_MVLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB)); + mp_store_global(MP_QSTR_MONO_VLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB)); + mp_store_global(MP_QSTR_RGB565, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565)); + mp_store_global(MP_QSTR_GS2_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS2_HMSB)); + mp_store_global(MP_QSTR_GS4_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB)); + mp_store_global(MP_QSTR_GS8, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS8)); + mp_store_global(MP_QSTR_MONO_HLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHLSB)); + mp_store_global(MP_QSTR_MONO_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHMSB)); + + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/heapq/Makefile b/examples/natmod/heapq/Makefile new file mode 100644 index 00000000000..7068b55dfd0 --- /dev/null +++ b/examples/natmod/heapq/Makefile @@ -0,0 +1,17 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in heapq so it can coexist) +MOD_BASE = heapq +MOD = $(MOD_BASE)_$(ARCH) + +# Source files (.c or .py) +SRC = heapq.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Strip the architecture name from the internal filename. +MPY_LD_FLAGS = "--source-name=$(MOD_BASE).mpy" + +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 00000000000..ed19652a66b --- /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 00000000000..ae0970604b3 --- /dev/null +++ b/examples/natmod/random/Makefile @@ -0,0 +1,17 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in random so it can coexist) +MOD_BASE = random +MOD = $(MOD_BASE)_$(ARCH) + +# Source files (.c or .py) +SRC = random.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Strip the architecture name from the internal filename. +MPY_LD_FLAGS = "--source-name=$(MOD_BASE).mpy" + +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 00000000000..d73b53e2e7d --- /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 00000000000..2596437546d --- /dev/null +++ b/examples/natmod/re/Makefile @@ -0,0 +1,29 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in re so it can coexist) +MOD_BASE = re +MOD = $(MOD_BASE)_$(ARCH) + +# Source files (.c or .py) +SRC = re.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +ifeq ($(ARCH),armv7m) +ifeq ($(findstring clang,$(shell $(CC) --version)),clang) +# Link with libclang_rt.a for memmove +LINK_RUNTIME = 1 +endif +endif + +ifeq ($(ARCH),armv6m) +# Link with libgcc.a for division helper functions +LINK_RUNTIME = 1 +endif + +# Strip the architecture name from the internal filename. +MPY_LD_FLAGS = "--source-name=$(MOD_BASE).mpy" + +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 00000000000..6c5c65842d6 --- /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 + +#if defined __has_builtin +#if __has_builtin(__builtin_alloca) +#define alloca __builtin_alloca +#endif +#endif + +#if !defined(alloca) +#if defined(_PICOLIBC__) && !defined(HAVE_BUILTIN_ALLOCA) +#define alloca(n) m_malloc(n) +#else +#include +#endif +#endif + +#include "py/dynruntime.h" + +#define STACK_LIMIT (2048) + +const char *stack_top; + +void mp_cstack_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")); + } +} + +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/extmod/extmod.mk b/extmod/extmod.mk index daa6f267342..5b2772e4e2a 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -162,7 +162,7 @@ endif ifeq ($(MICROPY_VFS_LFS2),1) CFLAGS_EXTMOD += -DMICROPY_VFS_LFS2=1 -CFLAGS_THIRDPARTY += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT +CFLAGS_THIRDPARTY += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT -DLFS2_DEFINES=extmod/littlefs-include/lfs2_defines.h SRC_THIRDPARTY_C += $(addprefix $(LITTLEFS_DIR)/,\ lfs2.c \ lfs2_util.c \ @@ -461,7 +461,7 @@ ESP_HOSTED_SRC_C = $(addprefix $(ESP_HOSTED_DIR)/,\ ) ifeq ($(MICROPY_PY_BLUETOOTH),1) -ESP_HOSTED_SRC_C += $(ESP_HOSTED_DIR)/esp_hosted_bthci.c +ESP_HOSTED_SRC_C += $(ESP_HOSTED_DIR)/esp_hosted_bthci_uart.c endif # Include the protobuf-c support functions diff --git a/extmod/lwip-include/arch/cc.h b/extmod/lwip-include/arch/cc.h deleted file mode 100644 index 400dc6ec75d..00000000000 --- a/extmod/lwip-include/arch/cc.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H -#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H - -#include - -// Generate lwip's internal types from stdint - -typedef uint8_t u8_t; -typedef int8_t s8_t; -typedef uint16_t u16_t; -typedef int16_t s16_t; -typedef uint32_t u32_t; -typedef int32_t s32_t; - -typedef u32_t mem_ptr_t; - -#define U16_F "hu" -#define S16_F "hd" -#define X16_F "hx" -#define U32_F "u" -#define S32_F "d" -#define X32_F "x" - -#define X8_F "02x" -#define SZT_F "u" - -#define BYTE_ORDER LITTLE_ENDIAN - -#define LWIP_CHKSUM_ALGORITHM 2 - -#include -#define LWIP_PLATFORM_DIAG(x) -#define LWIP_PLATFORM_ASSERT(x) { assert(1); } - -//#define PACK_STRUCT_FIELD(x) x __attribute__((packed)) -#define PACK_STRUCT_FIELD(x) x -#define PACK_STRUCT_STRUCT __attribute__((packed)) -#define PACK_STRUCT_BEGIN -#define PACK_STRUCT_END - -#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H diff --git a/extmod/lwip-include/arch/perf.h b/extmod/lwip-include/arch/perf.h deleted file mode 100644 index d310fc339f1..00000000000 --- a/extmod/lwip-include/arch/perf.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H -#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H - -#define PERF_START /* null definition */ -#define PERF_STOP(x) /* null definition */ - -#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H diff --git a/extmod/lwip-include/lwipopts.h b/extmod/lwip-include/lwipopts.h deleted file mode 100644 index 584decfe85f..00000000000 --- a/extmod/lwip-include/lwipopts.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H -#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H - -#include -#include -#include - -// We're running without an OS for this port. We don't provide any services except light protection. -#define NO_SYS 1 - -#define SYS_LIGHTWEIGHT_PROT 1 -#include -typedef uint32_t sys_prot_t; - -#define TCP_LISTEN_BACKLOG 1 - -// We'll put these into a proper ifdef once somebody implements an ethernet driver -#define LWIP_ARP 0 -#define LWIP_ETHERNET 0 - -#define LWIP_DNS 1 - -#define LWIP_NETCONN 0 -#define LWIP_SOCKET 0 - -// CIRCUITPY-CHANGE: #if instead of #ifdef -#if MICROPY_PY_LWIP_SLIP -#define LWIP_HAVE_SLIPIF 1 -#endif - -// For now, we can simply define this as a macro for the timer code. But this function isn't -// universal and other ports will need to do something else. It may be necessary to move -// things like this into a port-provided header file. -#define sys_now mp_hal_ticks_ms - -#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H diff --git a/extmod/lwip-include/lwipopts_common.h b/extmod/lwip-include/lwipopts_common.h deleted file mode 100644 index 3e423090949..00000000000 --- a/extmod/lwip-include/lwipopts_common.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2025 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef MICROPY_INCLUDED_LWIPOPTS_COMMON_H -#define MICROPY_INCLUDED_LWIPOPTS_COMMON_H - -#include "py/mpconfig.h" - -// This sys-arch protection is not needed. -// Ports either protect lwIP code with flags, or run it at PendSV priority. -#define SYS_ARCH_DECL_PROTECT(lev) do { } while (0) -#define SYS_ARCH_PROTECT(lev) do { } while (0) -#define SYS_ARCH_UNPROTECT(lev) do { } while (0) - -#define NO_SYS 1 -#define SYS_LIGHTWEIGHT_PROT 1 -#define MEM_ALIGNMENT 4 - -#define LWIP_CHKSUM_ALGORITHM 3 -#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 - -#define LWIP_ARP 1 -#define LWIP_ETHERNET 1 -#define LWIP_RAW 1 -#define LWIP_NETCONN 0 -#define LWIP_SOCKET 0 -#define LWIP_STATS 0 -#define LWIP_NETIF_HOSTNAME 1 - -#define LWIP_DHCP 1 -#define LWIP_DHCP_CHECK_LINK_UP 1 -#define LWIP_DHCP_DOES_ACD_CHECK 0 // to speed DHCP up -#define LWIP_DNS 1 -#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1 -#define LWIP_MDNS_RESPONDER 1 -#define LWIP_IGMP 1 - -#if MICROPY_PY_LWIP_PPP -#define PPP_SUPPORT 1 -#define PAP_SUPPORT 1 -#define CHAP_SUPPORT 1 -#endif - -#define LWIP_NUM_NETIF_CLIENT_DATA LWIP_MDNS_RESPONDER -#define MEMP_NUM_UDP_PCB (4 + LWIP_MDNS_RESPONDER) - -// The mDNS responder requires 5 timers per IP version plus 2 others. Not having enough silently breaks it. -#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + (LWIP_MDNS_RESPONDER * (2 + (5 * (LWIP_IPV4 + LWIP_IPV6))))) - -#define SO_REUSE 1 -#define TCP_LISTEN_BACKLOG 1 - -// TCP memory settings. -// Default lwIP settings takes 15800 bytes; TCP d/l: 380k/s local, 7.2k/s remote; TCP u/l is very slow. -#ifndef MEM_SIZE - -#if 0 -// lwIP takes 19159 bytes; TCP d/l and u/l are around 320k/s on local network. -#define MEM_SIZE (5000) -#define TCP_WND (4 * TCP_MSS) -#define TCP_SND_BUF (4 * TCP_MSS) -#endif - -#if 1 -// lwIP takes 26700 bytes; TCP dl/ul are around 750/600 k/s on local network. -#define MEM_SIZE (8000) -#define TCP_MSS (800) -#define TCP_WND (8 * TCP_MSS) -#define TCP_SND_BUF (8 * TCP_MSS) -#define MEMP_NUM_TCP_SEG (32) -#endif - -#if 0 -// lwIP takes 45600 bytes; TCP dl/ul are around 1200/1000 k/s on local network. -#define MEM_SIZE (16000) -#define TCP_MSS (1460) -#define TCP_WND (8 * TCP_MSS) -#define TCP_SND_BUF (8 * TCP_MSS) -#define MEMP_NUM_TCP_SEG (32) -#endif - -#endif // MEM_SIZE - -// Needed for PPP. -#define sys_jiffies sys_now - -typedef uint32_t sys_prot_t; - -#endif // MICROPY_INCLUDED_LWIPOPTS_COMMON_H diff --git a/extmod/modjson.c b/extmod/modjson.c index 67da36f0ccf..77f4a336aa8 100644 --- a/extmod/modjson.c +++ b/extmod/modjson.c @@ -227,7 +227,8 @@ static mp_obj_t _mod_json_load(mp_obj_t stream_obj, bool return_first_json) { for (;;) { cont: if (S_END(s)) { - break; + // Input finished abruptly in the middle of a composite entity. + goto fail; } mp_obj_t next = MP_OBJ_NULL; bool enter = false; diff --git a/extmod/modos.c b/extmod/modos.c index 69fdc3fac0a..c330162e102 100644 --- a/extmod/modos.c +++ b/extmod/modos.c @@ -145,6 +145,21 @@ static mp_obj_t mp_os_dupterm_notify(mp_obj_t obj_in) { static MP_DEFINE_CONST_FUN_OBJ_1(mp_os_dupterm_notify_obj, mp_os_dupterm_notify); #endif +#if MICROPY_PY_OS_URANDOM +// This wraps the port-specific mp_hal_get_random(), which is usually defined in mphalport.c. +static mp_obj_t mp_os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + if (n < 0) { + mp_raise_ValueError(NULL); + } + vstr_t vstr; + vstr_init_len(&vstr, n); + mp_hal_get_random(n, (uint8_t *)vstr.buf); + return mp_obj_new_bytes_from_vstr(&vstr); +} +static MP_DEFINE_CONST_FUN_OBJ_1(mp_os_urandom_obj, mp_os_urandom); +#endif + static const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_os) }, diff --git a/extmod/modplatform.c b/extmod/modplatform.c index c6d4d31b97e..e1f5476c3b3 100644 --- a/extmod/modplatform.c +++ b/extmod/modplatform.c @@ -61,11 +61,49 @@ static mp_obj_t platform_libc_ver(size_t n_args, const mp_obj_t *pos_args, mp_ma } static MP_DEFINE_CONST_FUN_OBJ_KW(platform_libc_ver_obj, 0, platform_libc_ver); +#ifdef __riscv +static mp_obj_t platform_processor(void) { + #if (__riscv_xlen <= 64) && !defined(__linux__) + uintptr_t misa_csr = 0; + + // Load the MISA CSR directly. + __asm volatile ( + "csrr %0, misa \n" + : "+r" (misa_csr) + : + : + ); + + char processor_buffer[31] = { // "RV32"/"RV64" + up to 26 chars. + #if (__riscv_xlen < 64) + "RV32" + #else + "RV64" + #endif + }; + mp_uint_t offset = 4; + for (mp_uint_t bit = 0; bit < 26; bit++) { + if (misa_csr & (1U << bit)) { + processor_buffer[offset++] = 'A' + bit; + } + } + + return mp_obj_new_str(processor_buffer, offset); + #else + return MP_OBJ_NEW_QSTR(MP_QSTR_); + #endif +} +static MP_DEFINE_CONST_FUN_OBJ_0(platform_processor_obj, platform_processor); +#endif + 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) }, + #ifdef __riscv + { MP_ROM_QSTR(MP_QSTR_processor), MP_ROM_PTR(&platform_processor_obj) }, + #endif }; static MP_DEFINE_CONST_DICT(modplatform_globals, modplatform_globals_table); diff --git a/extmod/modplatform.h b/extmod/modplatform.h index a155f071cba..2417a007b3a 100644 --- a/extmod/modplatform.h +++ b/extmod/modplatform.h @@ -53,6 +53,8 @@ #else #define MICROPY_PLATFORM_ARCH "riscv" #endif +#elif defined(__loongarch__) && defined(__loongarch64) +#define MICROPY_PLATFORM_ARCH "loongarch64" #else #define MICROPY_PLATFORM_ARCH "" #endif @@ -103,6 +105,9 @@ #elif defined(__ANDROID__) #define MICROPY_PLATFORM_LIBC_LIB "bionic" #define MICROPY_PLATFORM_LIBC_VER MP_STRINGIFY(__ANDROID_API__) +#elif defined(__FreeBSD__) +#define MICROPY_PLATFORM_LIBC_LIB "libc" +#define MICROPY_PLATFORM_LIBC_VER "" #else #define MICROPY_PLATFORM_LIBC_LIB "" #define MICROPY_PLATFORM_LIBC_VER "" @@ -112,6 +117,8 @@ #define MICROPY_PLATFORM_SYSTEM "Android" #elif defined(__linux) #define MICROPY_PLATFORM_SYSTEM "Linux" +#elif defined(__FreeBSD__) +#define MICROPY_PLATFORM_SYSTEM "FreeBSD" #elif defined(__unix__) #define MICROPY_PLATFORM_SYSTEM "Unix" #elif defined(__CYGWIN__) diff --git a/extmod/modre.c b/extmod/modre.c index ba2927eb4a8..36fff1d1dc6 100644 --- a/extmod/modre.c +++ b/extmod/modre.c @@ -196,10 +196,11 @@ static void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t // Note: this function can't be named re_exec because it may clash with system headers, eg on FreeBSD static mp_obj_t re_exec_helper(bool is_anchored, uint n_args, const mp_obj_t *args) { - (void)n_args; mp_obj_re_t *self; + bool was_compiled = false; if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) { self = MP_OBJ_TO_PTR(args[0]); + was_compiled = true; } else { self = MP_OBJ_TO_PTR(mod_re_compile(1, args)); } @@ -207,37 +208,28 @@ static mp_obj_t re_exec_helper(bool is_anchored, uint n_args, const mp_obj_t *ar size_t len; subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len); subj.end = subj.begin + len; - // CIRCUITPY-CHANGE - #if MICROPY_PY_RE_MATCH_SPAN_START_END && !(defined(MICROPY_ENABLE_DYNRUNTIME) && MICROPY_ENABLE_DYNRUNTIME) - - if (n_args > 2) { - const mp_obj_type_t *self_type = mp_obj_get_type(args[1]); - mp_int_t str_len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(args[1])); - const byte *begin = (const byte *)subj.begin; - int pos = mp_obj_get_int(args[2]); - if (pos >= str_len) { - return mp_const_none; - } - if (pos < 0) { - pos = 0; + if (was_compiled && n_args > 2) { + // Arg #2 is starting-pos + mp_int_t startpos = mp_obj_get_int(args[2]); + if (startpos > (mp_int_t)len) { + startpos = len; + } else if (startpos < 0) { + startpos = 0; } - const byte *pos_ptr = str_index_to_ptr(self_type, begin, len, MP_OBJ_NEW_SMALL_INT(pos), true); - - const byte *endpos_ptr = (const byte *)subj.end; + subj.begin += startpos; if (n_args > 3) { - int endpos = mp_obj_get_int(args[3]); - if (endpos <= pos) { - return mp_const_none; + // Arg #3 is ending-pos + mp_int_t endpos = mp_obj_get_int(args[3]); + if (endpos > (mp_int_t)len) { + endpos = len; + } else if (endpos < startpos) { + endpos = startpos; } - // Will cap to length - endpos_ptr = str_index_to_ptr(self_type, begin, len, args[3], true); + subj.end = subj.begin_line + endpos; } - - subj.begin = (const char *)pos_ptr; - subj.end = (const char *)endpos_ptr; } - #endif + int caps_num = (self->re.sub + 1) * 2; mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, caps, 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 @@ -458,6 +450,9 @@ static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { const char *re_str = mp_obj_str_get_str(args[0]); int size = re1_5_sizecode(re_str); if (size == -1) { + #if MICROPY_ERROR_REPORTING >= MICROPY_ERROR_REPORTING_NORMAL + mp_raise_ValueError(MP_ERROR_TEXT("regex too complex")); + #endif goto error; } mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, re.insts, char, size, (mp_obj_type_t *)&re_type); @@ -470,6 +465,7 @@ static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { int error = re1_5_compilecode(&o->re, re_str); if (error != 0) { error: + // CIRCUITPY-CHANGE: capitalized mp_raise_ValueError(MP_ERROR_TEXT("Error in regex")); } #if MICROPY_PY_RE_DEBUG diff --git a/extmod/modselect.c b/extmod/modselect.c index c4edee6a56b..72566e024f0 100644 --- a/extmod/modselect.c +++ b/extmod/modselect.c @@ -344,6 +344,8 @@ static mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size mp_uint_t start_ticks = mp_hal_ticks_ms(); bool has_timeout = timeout != (mp_uint_t)-1; + mp_handle_pending(true); + #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS for (;;) { diff --git a/extmod/modtime.c b/extmod/modtime.c index deb4bb4c9ac..ee898828a4a 100644 --- a/extmod/modtime.c +++ b/extmod/modtime.c @@ -53,26 +53,26 @@ // - 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; if (n_args == 0 || args[0] == mp_const_none) { // Get current date and time. - return mp_time_localtime_get(); + mp_time_localtime_get(&tm); } else { // Convert given seconds to tuple. - mp_int_t seconds = mp_obj_get_int(args[0]); - timeutils_struct_time_t tm; + mp_timestamp_t seconds = timeutils_obj_get_timestamp(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_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); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_time_localtime_obj, 0, 1, time_localtime); @@ -90,7 +90,7 @@ static mp_obj_t time_mktime(mp_obj_t tuple) { mp_raise_TypeError(MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9")); } - return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), + return timeutils_obj_from_timestamp(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]))); } diff --git a/extmod/vfs.c b/extmod/vfs.c index 0cf93c3966c..2379e19fa0b 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -101,7 +101,7 @@ mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out) { return MP_STATE_VM(vfs_cur); } -// Version of mp_vfs_lookup_path that takes and returns uPy string objects. +// Version of mp_vfs_lookup_path that takes and returns MicroPython string objects. static mp_vfs_mount_t *lookup_path(mp_obj_t path_in, mp_obj_t *path_out) { const char *path = mp_obj_str_get_str(path_in); const char *p_out; @@ -178,7 +178,9 @@ static mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) { mp_vfs_blockdev_init(&blockdev, bdev_obj); uint8_t buf[44]; for (size_t block_num = 0; block_num <= 1; ++block_num) { - mp_vfs_blockdev_read_ext(&blockdev, block_num, 8, sizeof(buf), buf); + if (mp_vfs_blockdev_read_ext(&blockdev, block_num, 8, sizeof(buf), buf) != 0) { + continue; + } #if MICROPY_VFS_LFS1 if (memcmp(&buf[32], "littlefs", 8) == 0) { // LFS1 diff --git a/extmod/vfs.h b/extmod/vfs.h index 699232e56cd..8c452751f32 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -41,7 +41,9 @@ #define MP_S_IFREG (0x8000) // these are the values for mp_vfs_blockdev_t.flags +#if MICROPY_VFS_BLOCKDEV_NATIVE #define MP_BLOCKDEV_FLAG_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func +#endif #define MP_BLOCKDEV_FLAG_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount #define MP_BLOCKDEV_FLAG_HAVE_IOCTL (0x0004) // new protocol with ioctl #define MP_BLOCKDEV_FLAG_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it @@ -64,11 +66,20 @@ #define MP_BLOCKDEV_IOCTL_BLOCK_ERASE (6) // Constants for vfs.rom_ioctl() function. +// The 4-arg form of WRITE_PREPARE is only available if GET_MIN_PREPARE returns >0. #define MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS (1) // rom_ioctl(1) #define MP_VFS_ROM_IOCTL_GET_SEGMENT (2) // rom_ioctl(2, ) -#define MP_VFS_ROM_IOCTL_WRITE_PREPARE (3) // rom_ioctl(3, , ) +#define MP_VFS_ROM_IOCTL_WRITE_PREPARE (3) // rom_ioctl(3, , ) or rom_ioctl(3, , , ) #define MP_VFS_ROM_IOCTL_WRITE (4) // rom_ioctl(4, , , ) #define MP_VFS_ROM_IOCTL_WRITE_COMPLETE (5) // rom_ioctl(5, ) +#define MP_VFS_ROM_IOCTL_GET_MIN_PREPARE (6) // rom_ioctl(6, ) + +#if MICROPY_VFS_BLOCKDEV_NATIVE +// Function signatures used when MP_BLOCKDEV_FLAG_NATIVE is set. +// Should return 0 for success, or a negative errno code for failure. +typedef int (*mp_vfs_blockdev_native_readblocks)(uint8_t *, uint32_t, uint32_t); +typedef int (*mp_vfs_blockdev_native_writeblocks)(const uint8_t *, uint32_t, uint32_t); +#endif // At the moment the VFS protocol just has import_stat, but could be extended to other methods typedef struct _mp_vfs_proto_t { diff --git a/extmod/vfs_blockdev.c b/extmod/vfs_blockdev.c index f1187b9bbf2..db6fc28e2ec 100644 --- a/extmod/vfs_blockdev.c +++ b/extmod/vfs_blockdev.c @@ -38,6 +38,10 @@ #include "shared-bindings/sdioio/SDCard.h" #endif +#if CIRCUITPY_EMMCIO +#include "shared-bindings/emmcio/EMMC.h" +#endif + #if MICROPY_VFS @@ -63,7 +67,35 @@ void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) { #endif #if CIRCUITPY_SDIOIO if (mp_obj_get_type(bdev) == &sdioio_SDCard_type) { - // TODO: Enable native blockdev for SDIO too. + self->flags |= MP_BLOCKDEV_FLAG_NATIVE | MP_BLOCKDEV_FLAG_HAVE_IOCTL; + self->readblocks[0] = mp_const_none; + self->readblocks[1] = bdev; + self->readblocks[2] = (mp_obj_t)sdioio_sdcard_readblocks; // native version + self->writeblocks[0] = mp_const_none; + self->writeblocks[1] = bdev; + self->writeblocks[2] = (mp_obj_t)sdioio_sdcard_writeblocks; // native version + self->u.ioctl[0] = mp_const_none; + self->u.ioctl[1] = bdev; + self->u.ioctl[2] = (mp_obj_t)sdioio_sdcard_ioctl; // native version + } + #endif + + #if CIRCUITPY_EMMCIO + if (mp_obj_get_type(bdev) == &emmcio_emmc_type) { + self->flags |= MP_BLOCKDEV_FLAG_NATIVE | MP_BLOCKDEV_FLAG_HAVE_IOCTL; + self->readblocks[0] = mp_const_none; + self->readblocks[1] = bdev; + self->readblocks[2] = (mp_obj_t)emmcio_emmc_readblocks_native; + if (emmcio_emmc_is_write_enabled(bdev)) { + self->writeblocks[0] = mp_const_none; + self->writeblocks[1] = bdev; + self->writeblocks[2] = (mp_obj_t)emmcio_emmc_writeblocks_native; + } else { + self->writeblocks[0] = MP_OBJ_NULL; + } + self->u.ioctl[0] = mp_const_none; + self->u.ioctl[1] = bdev; + self->u.ioctl[2] = (mp_obj_t)emmcio_emmc_ioctl_native; } #endif if (self->u.ioctl[0] != MP_OBJ_NULL) { @@ -79,7 +111,11 @@ void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) { // Helper function to minimise code size of read/write functions // note the n_args argument is moved to the end for further code size reduction (args keep same position in caller and callee). static int mp_vfs_blockdev_call_rw(mp_obj_t *args, size_t block_num, size_t block_off, size_t len, void *buf, size_t n_args) { + #if MICROPY_PY_BUILTINS_MEMORYVIEW + mp_obj_array_t ar = {{&mp_type_memoryview}, 'B' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW, 0, len, buf}; + #else mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, len, buf}; + #endif args[2] = MP_OBJ_NEW_SMALL_INT(block_num); args[3] = MP_OBJ_FROM_PTR(&ar); args[4] = MP_OBJ_NEW_SMALL_INT(block_off); // ignored for n_args == 2 @@ -88,31 +124,26 @@ static int mp_vfs_blockdev_call_rw(mp_obj_t *args, size_t block_num, size_t bloc if (ret == mp_const_none) { return 0; } else { - // Some block devices return a bool indicating success, so - // convert those to an errno integer code. - if (ret == mp_const_true) { - return 0; - } else if (ret == mp_const_false) { - return -MP_EIO; - } // Block device functions are expected to return 0 on success // and negative integer on errors. Check for positive integer // results as some callers (i.e. littlefs) will produce corrupt // results from these. - int i = MP_OBJ_SMALL_INT_VALUE(ret); + int i = mp_obj_get_int(ret); return i > 0 ? (-MP_EINVAL) : i; } } int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf) { + #if MICROPY_VFS_BLOCKDEV_NATIVE if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) { // CIRCUITPY-CHANGE: Pass the blockdev object into native readblocks so // it has the corresponding state. mp_uint_t (*f)(mp_obj_t self, uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->readblocks[2]; return f(self->readblocks[1], buf, block_num, num_blocks); - } else { - return mp_vfs_blockdev_call_rw(self->readblocks, block_num, 0, num_blocks * self->block_size, buf, 2); } + #endif + + return mp_vfs_blockdev_call_rw(self->readblocks, block_num, 0, num_blocks * self->block_size, buf, 2); } int mp_vfs_blockdev_read_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, uint8_t *buf) { @@ -125,14 +156,16 @@ int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_ return -MP_EROFS; } + #if MICROPY_VFS_BLOCKDEV_NATIVE if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) { - // CIRCUITPY-CHANGE: Pass the blockdev object into native readblocks so + // CIRCUITPY-CHANGE: Pass the blockdev object into native writeblocks so // it has the corresponding state. mp_uint_t (*f)(mp_obj_t self, const uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->writeblocks[2]; return f(self->writeblocks[1], buf, block_num, num_blocks); - } else { - return mp_vfs_blockdev_call_rw(self->writeblocks, block_num, 0, num_blocks * self->block_size, (void *)buf, 2); } + #endif + + return mp_vfs_blockdev_call_rw(self->writeblocks, block_num, 0, num_blocks * self->block_size, (void *)buf, 2); } int mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, const uint8_t *buf) { @@ -146,6 +179,7 @@ int mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg) { if (self->flags & MP_BLOCKDEV_FLAG_HAVE_IOCTL) { // CIRCUITPY-CHANGE: Support native IOCTL so it can run outside of the VM. + #if MICROPY_VFS_BLOCKDEV_NATIVE if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) { size_t out_value; bool (*f)(mp_obj_t self, uint32_t, uint32_t, size_t *) = (void *)(uintptr_t)self->u.ioctl[2]; @@ -155,6 +189,7 @@ mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t } return MP_OBJ_NEW_SMALL_INT(out_value); } + #endif // New protocol with ioctl self->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(cmd); self->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(arg); diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 6267452cd32..95ed79eb18b 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -58,7 +58,7 @@ // CIRCUITPY-CHANGE // Factoring this common call saves about 90 bytes. -static NORETURN void mp_raise_OSError_fresult(FRESULT res) { +static MP_NORETURN void mp_raise_OSError_fresult(FRESULT res) { mp_raise_OSError(fresult_to_errno_table[res]); } diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 2a3021ee9a8..aee6318cacf 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -102,15 +102,15 @@ static mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)(uintptr_t)arg; switch (s->whence) { - case 0: // SEEK_SET + case MP_SEEK_SET: f_lseek(&self->fp, s->offset); break; - case 1: // SEEK_CUR + case MP_SEEK_CUR: f_lseek(&self->fp, f_tell(&self->fp) + s->offset); break; - case 2: // SEEK_END + case MP_SEEK_END: f_lseek(&self->fp, f_size(&self->fp) + s->offset); break; } diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c index 4b10ca3aa59..bbdd21cfb91 100644 --- a/extmod/vfs_lfsx.c +++ b/extmod/vfs_lfsx.c @@ -104,6 +104,12 @@ static void MP_VFS_LFSx(init_config)(MP_OBJ_VFS_LFSx * self, mp_obj_t bdev, size config->read_buffer = m_new(uint8_t, config->cache_size); config->prog_buffer = m_new(uint8_t, config->cache_size); config->lookahead_buffer = m_new(uint8_t, config->lookahead_size); + #ifdef LFS2_MULTIVERSION + // This can be set to override the on-disk lfs version. + // eg. for compat with lfs2 < v2.6 add the following to make: + // CFLAGS += '-DLFS2_MULTIVERSION=0x00020000' + config->disk_version = LFS2_MULTIVERSION; + #endif #endif } @@ -300,7 +306,7 @@ static mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) { struct LFSx_API (info) info; int ret = LFSx_API(stat)(&self->lfs, path, &info); if (ret < 0 || info.type != LFSx_MACRO(_TYPE_DIR)) { - mp_raise_OSError(-MP_ENOENT); + mp_raise_OSError(MP_ENOENT); } } @@ -378,7 +384,7 @@ static mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) { mp_raise_OSError(-ret); } - mp_uint_t mtime = 0; + mp_timestamp_t mtime = 0; #if LFS_BUILD_VERSION == 2 uint8_t mtime_buf[8]; lfs2_ssize_t sz = lfs2_getattr(&self->lfs, path, LFS_ATTR_MTIME, &mtime_buf, sizeof(mtime_buf)); @@ -400,9 +406,9 @@ static mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) { t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size - t->items[7] = mp_obj_new_int_from_uint(mtime); // st_atime - t->items[8] = mp_obj_new_int_from_uint(mtime); // st_mtime - t->items[9] = mp_obj_new_int_from_uint(mtime); // st_ctime + t->items[7] = timeutils_obj_from_timestamp(mtime); // st_atime + t->items[8] = timeutils_obj_from_timestamp(mtime); // st_mtime + t->items[9] = timeutils_obj_from_timestamp(mtime); // st_ctime return MP_OBJ_FROM_PTR(t); } diff --git a/extmod/vfs_lfsx_file.c b/extmod/vfs_lfsx_file.c index ab5cce50088..a0e572d80cb 100644 --- a/extmod/vfs_lfsx_file.c +++ b/extmod/vfs_lfsx_file.c @@ -90,9 +90,9 @@ mp_obj_t MP_VFS_LFSx(file_open)(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mod } #if LFS_BUILD_VERSION == 1 - MP_OBJ_VFS_LFSx_FILE *o = mp_obj_malloc_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, uint8_t, self->lfs.cfg->prog_size, type); + MP_OBJ_VFS_LFSx_FILE *o = mp_obj_malloc_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, file_buffer, uint8_t, self->lfs.cfg->prog_size, type); #else - MP_OBJ_VFS_LFSx_FILE *o = mp_obj_malloc_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, uint8_t, self->lfs.cfg->cache_size, type); + MP_OBJ_VFS_LFSx_FILE *o = mp_obj_malloc_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, file_buffer, uint8_t, self->lfs.cfg->cache_size, type); #endif o->vfs = self; #if !MICROPY_GC_CONSERVATIVE_CLEAR @@ -152,11 +152,8 @@ static mp_uint_t MP_VFS_LFSx(file_write)(mp_obj_t self_in, const void *buf, mp_u static mp_uint_t MP_VFS_LFSx(file_ioctl)(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in); - if (request != MP_STREAM_CLOSE) { - MP_VFS_LFSx(check_open)(self); - } - if (request == MP_STREAM_SEEK) { + MP_VFS_LFSx(check_open)(self); struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)(uintptr_t)arg; int res = LFSx_API(file_seek)(&self->vfs->lfs, &self->file, s->offset, s->whence); if (res < 0) { @@ -171,6 +168,7 @@ static mp_uint_t MP_VFS_LFSx(file_ioctl)(mp_obj_t self_in, mp_uint_t request, ui s->offset = res; return 0; } else if (request == MP_STREAM_FLUSH) { + MP_VFS_LFSx(check_open)(self); int res = LFSx_API(file_sync)(&self->vfs->lfs, &self->file); if (res < 0) { *errcode = -res; diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c index bd9a6d84062..90030db1965 100644 --- a/extmod/vfs_posix.c +++ b/extmod/vfs_posix.c @@ -137,7 +137,7 @@ static mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, siz vstr_add_char(&vfs->root, '/'); } vfs->root_len = vfs->root.len; - vfs->readonly = false; + vfs->readonly = !MICROPY_VFS_POSIX_WRITABLE; return MP_OBJ_FROM_PTR(vfs); } @@ -160,10 +160,21 @@ static mp_obj_t vfs_posix_umount(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount); +static inline bool vfs_posix_is_readonly(mp_obj_vfs_posix_t *self) { + return !MICROPY_VFS_POSIX_WRITABLE || self->readonly; +} + +static void vfs_posix_require_writable(mp_obj_t self_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + if (vfs_posix_is_readonly(self)) { + mp_raise_OSError(MP_EROFS); + } +} + static mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) { mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); const char *mode = mp_obj_str_get_str(mode_in); - if (self->readonly + if (vfs_posix_is_readonly(self) && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) { mp_raise_OSError(MP_EROFS); } @@ -303,6 +314,7 @@ typedef struct _mp_obj_listdir_t { } mp_obj_listdir_t; static mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { + vfs_posix_require_writable(self_in); mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); const char *path = vfs_posix_get_path_str(self, path_in); MP_THREAD_GIL_EXIT(); @@ -320,17 +332,23 @@ static mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir); static mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) { + vfs_posix_require_writable(self_in); return vfs_posix_fun1_helper(self_in, path_in, unlink); } static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove); static mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) { + vfs_posix_require_writable(self_in); mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); const char *old_path = vfs_posix_get_path_str(self, old_path_in); + size_t old_path_len = strlen(old_path) + 1; + char *old_path_copy = m_new(char, old_path_len); + memcpy(old_path_copy, old_path, old_path_len); const char *new_path = vfs_posix_get_path_str(self, new_path_in); MP_THREAD_GIL_EXIT(); - int ret = rename(old_path, new_path); + int ret = rename(old_path_copy, new_path); MP_THREAD_GIL_ENTER(); + m_del(char, old_path_copy, old_path_len); if (ret != 0) { mp_raise_OSError(errno); } @@ -339,6 +357,7 @@ static mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_ static MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename); static mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) { + vfs_posix_require_writable(self_in); return vfs_posix_fun1_helper(self_in, path_in, rmdir); } static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir); diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 501550cb502..5fe330d7fcf 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -146,12 +146,9 @@ static mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t static mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); - if (request != MP_STREAM_CLOSE) { - check_fd_is_open(o); - } - switch (request) { case MP_STREAM_FLUSH: { + check_fd_is_open(o); int ret; // fsync(stdin/stdout/stderr) may fail with EINVAL (or ENOTSUP on macos or EBADF // on windows), because the OS doesn't buffer these except for instance when they @@ -190,6 +187,7 @@ static mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ return 0; } case MP_STREAM_SEEK: { + check_fd_is_open(o); struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg; MP_THREAD_GIL_EXIT(); off_t off = lseek(o->fd, s->offset, s->whence); @@ -210,12 +208,14 @@ static mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ o->fd = -1; return 0; case MP_STREAM_GET_FILENO: + check_fd_is_open(o); return o->fd; #if MICROPY_PY_SELECT && !MICROPY_PY_SELECT_POSIX_OPTIMISATIONS case MP_STREAM_POLL: { #ifdef _WIN32 mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32")); #else + check_fd_is_open(o); mp_uint_t ret = 0; uint8_t pollevents = 0; if (arg & MP_STREAM_POLL_RD) { diff --git a/extmod/vfs_reader.c b/extmod/vfs_reader.c index de5c4e03d3c..139ecafb35b 100644 --- a/extmod/vfs_reader.c +++ b/extmod/vfs_reader.c @@ -56,6 +56,7 @@ static mp_uint_t mp_reader_vfs_readbyte(void *data) { return MP_READER_EOF; } else { int errcode; + mp_event_handle_nowait(); reader->buflen = mp_stream_rw(reader->file, reader->buf, reader->bufsize, &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); if (errcode != 0) { // TODO handle errors properly @@ -83,7 +84,7 @@ void mp_reader_new_file(mp_reader_t *reader, qstr filename) { }; mp_obj_t file = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map); - const mp_stream_p_t *stream_p = mp_get_stream(file); + const mp_stream_p_t *stream_p = mp_get_stream_raise(file, MP_STREAM_OP_READ); int errcode = 0; #if MICROPY_VFS_ROM diff --git a/extmod/vfs_rom_file.c b/extmod/vfs_rom_file.c index 57aca8c5dc7..6d7c47111f5 100644 --- a/extmod/vfs_rom_file.c +++ b/extmod/vfs_rom_file.c @@ -110,11 +110,11 @@ static mp_uint_t vfs_rom_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t switch (request) { case MP_STREAM_SEEK: { struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg; - if (s->whence == 0) { // SEEK_SET + if (s->whence == MP_SEEK_SET) { self->file_offset = (size_t)s->offset; - } else if (s->whence == 1) { // SEEK_CUR + } else if (s->whence == MP_SEEK_CUR) { self->file_offset += s->offset; - } else { // SEEK_END + } else { // MP_SEEK_END self->file_offset = self->file_size + s->offset; } if (self->file_offset > self->file_size) { diff --git a/frozen/Adafruit_CircuitPython_AHTx0 b/frozen/Adafruit_CircuitPython_AHTx0 index ff95dd5f3d0..3dd249f5695 160000 --- a/frozen/Adafruit_CircuitPython_AHTx0 +++ b/frozen/Adafruit_CircuitPython_AHTx0 @@ -1 +1 @@ -Subproject commit ff95dd5f3d0186c5cdc8bd8cb34ac22ac2e2225d +Subproject commit 3dd249f56957d1927dee6e6e31742039c6699cef diff --git a/frozen/Adafruit_CircuitPython_APDS9960 b/frozen/Adafruit_CircuitPython_APDS9960 index 00127a75d22..75a7b1abef0 160000 --- a/frozen/Adafruit_CircuitPython_APDS9960 +++ b/frozen/Adafruit_CircuitPython_APDS9960 @@ -1 +1 @@ -Subproject commit 00127a75d22f035096ea9317ad57c74c6a9b4232 +Subproject commit 75a7b1abef02342a7cdead30271ce168243bf1fa diff --git a/frozen/Adafruit_CircuitPython_BLE b/frozen/Adafruit_CircuitPython_BLE index 1acb303cc7f..82ada04a0f4 160000 --- a/frozen/Adafruit_CircuitPython_BLE +++ b/frozen/Adafruit_CircuitPython_BLE @@ -1 +1 @@ -Subproject commit 1acb303cc7f63a752c9fb87655d2ec478e564be2 +Subproject commit 82ada04a0f4019de00d103256621f73b80151a0d diff --git a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center index 476082b43c9..7c081325944 160000 --- a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center +++ b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center @@ -1 +1 @@ -Subproject commit 476082b43c9e5971da20a320a05546a8285d4891 +Subproject commit 7c08132594453a021812f45e86a2972d6945672e diff --git a/frozen/Adafruit_CircuitPython_BLE_File_Transfer b/frozen/Adafruit_CircuitPython_BLE_File_Transfer new file mode 160000 index 00000000000..14c0870bc91 --- /dev/null +++ b/frozen/Adafruit_CircuitPython_BLE_File_Transfer @@ -0,0 +1 @@ +Subproject commit 14c0870bc915aba90cf6e8a4002adeb563bc95fe diff --git a/frozen/Adafruit_CircuitPython_Bitmap_Font b/frozen/Adafruit_CircuitPython_Bitmap_Font index 5ca3f55f2e3..94bec4ba5ee 160000 --- a/frozen/Adafruit_CircuitPython_Bitmap_Font +++ b/frozen/Adafruit_CircuitPython_Bitmap_Font @@ -1 +1 @@ -Subproject commit 5ca3f55f2e39302c787ca93f95276e8269024038 +Subproject commit 94bec4ba5ee9bbc1f9a72281e3085ab10b5efd3a diff --git a/frozen/Adafruit_CircuitPython_BusDevice b/frozen/Adafruit_CircuitPython_BusDevice index afe91665e43..686728c7b11 160000 --- a/frozen/Adafruit_CircuitPython_BusDevice +++ b/frozen/Adafruit_CircuitPython_BusDevice @@ -1 +1 @@ -Subproject commit afe91665e438947bd3d88ba4a0f937ec58ff1035 +Subproject commit 686728c7b11eb0b7ffb62691b68ccead413e7cc5 diff --git a/frozen/Adafruit_CircuitPython_CS42L42 b/frozen/Adafruit_CircuitPython_CS42L42 new file mode 160000 index 00000000000..d254bbaf680 --- /dev/null +++ b/frozen/Adafruit_CircuitPython_CS42L42 @@ -0,0 +1 @@ +Subproject commit d254bbaf680c835896165ad2a28bd0216fa0ab42 diff --git a/frozen/Adafruit_CircuitPython_CircuitPlayground b/frozen/Adafruit_CircuitPython_CircuitPlayground index d093fed4059..852e7206e5e 160000 --- a/frozen/Adafruit_CircuitPython_CircuitPlayground +++ b/frozen/Adafruit_CircuitPython_CircuitPlayground @@ -1 +1 @@ -Subproject commit d093fed40590af312e44b1efa8d88ecaef9aaed4 +Subproject commit 852e7206e5ed26ec3929a25bc8331b0951fee20e diff --git a/frozen/Adafruit_CircuitPython_ConnectionManager b/frozen/Adafruit_CircuitPython_ConnectionManager index 95f39faaa64..69542345f3d 160000 --- a/frozen/Adafruit_CircuitPython_ConnectionManager +++ b/frozen/Adafruit_CircuitPython_ConnectionManager @@ -1 +1 @@ -Subproject commit 95f39faaa647b4215f615603368a453742423a09 +Subproject commit 69542345f3dc6f9060eb5d78d5dcd4e636bf66b9 diff --git a/frozen/Adafruit_CircuitPython_Crickit b/frozen/Adafruit_CircuitPython_Crickit index efeb183228f..aa213ba6f89 160000 --- a/frozen/Adafruit_CircuitPython_Crickit +++ b/frozen/Adafruit_CircuitPython_Crickit @@ -1 +1 @@ -Subproject commit efeb183228ff9640aec5938f9c2305766579dc25 +Subproject commit aa213ba6f897cdeb45ce4e961f44f862e3832c03 diff --git a/frozen/Adafruit_CircuitPython_DRV2605 b/frozen/Adafruit_CircuitPython_DRV2605 index f120d562221..2b8443ff94a 160000 --- a/frozen/Adafruit_CircuitPython_DRV2605 +++ b/frozen/Adafruit_CircuitPython_DRV2605 @@ -1 +1 @@ -Subproject commit f120d56222166af85b33e8e9c70eff6aec2e4828 +Subproject commit 2b8443ff94a179a027efd9f62d905c398f4f7b43 diff --git a/frozen/Adafruit_CircuitPython_DS3231 b/frozen/Adafruit_CircuitPython_DS3231 index a5d94eee49d..5dc331cd999 160000 --- a/frozen/Adafruit_CircuitPython_DS3231 +++ b/frozen/Adafruit_CircuitPython_DS3231 @@ -1 +1 @@ -Subproject commit a5d94eee49d324bad474847749c3d481a1f7c908 +Subproject commit 5dc331cd99930dd209c63f77256764c2b41016f2 diff --git a/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 b/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 index 4b382e8986d..45520b642df 160000 --- a/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 +++ b/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 @@ -1 +1 @@ -Subproject commit 4b382e8986db36eaef558fec67be543205f268b2 +Subproject commit 45520b642df77b1718befb24e5e6853b1172792f diff --git a/frozen/Adafruit_CircuitPython_Display_Shapes b/frozen/Adafruit_CircuitPython_Display_Shapes index e8867231041..7f0466c1d3a 160000 --- a/frozen/Adafruit_CircuitPython_Display_Shapes +++ b/frozen/Adafruit_CircuitPython_Display_Shapes @@ -1 +1 @@ -Subproject commit e8867231041837735ef2769a6dc793887d1979ca +Subproject commit 7f0466c1d3ac344bb8ef282d09c5eb8c1a521d72 diff --git a/frozen/Adafruit_CircuitPython_Display_Text b/frozen/Adafruit_CircuitPython_Display_Text index 7d1f187aac8..6761a7f0a3c 160000 --- a/frozen/Adafruit_CircuitPython_Display_Text +++ b/frozen/Adafruit_CircuitPython_Display_Text @@ -1 +1 @@ -Subproject commit 7d1f187aac8e899e791324cc78633bf4f32c984b +Subproject commit 6761a7f0a3ce7549c9887caee2c85bceef739d00 diff --git a/frozen/Adafruit_CircuitPython_DotStar b/frozen/Adafruit_CircuitPython_DotStar index 4b0ba649e5a..d08e231d5f9 160000 --- a/frozen/Adafruit_CircuitPython_DotStar +++ b/frozen/Adafruit_CircuitPython_DotStar @@ -1 +1 @@ -Subproject commit 4b0ba649e5abdebead5b9a47a6c695d67c2c25fa +Subproject commit d08e231d5f95566a09f2a0c08cb647703882262d diff --git a/frozen/Adafruit_CircuitPython_ESP32SPI b/frozen/Adafruit_CircuitPython_ESP32SPI index 063b90c8706..64f4695cc44 160000 --- a/frozen/Adafruit_CircuitPython_ESP32SPI +++ b/frozen/Adafruit_CircuitPython_ESP32SPI @@ -1 +1 @@ -Subproject commit 063b90c8706ddef97cc4abf9cb78e0cc09ff3c6c +Subproject commit 64f4695cc4457df0718e1a6460082381359c3562 diff --git a/frozen/Adafruit_CircuitPython_FakeRequests b/frozen/Adafruit_CircuitPython_FakeRequests index 020121e90c6..130a3d7fcfb 160000 --- a/frozen/Adafruit_CircuitPython_FakeRequests +++ b/frozen/Adafruit_CircuitPython_FakeRequests @@ -1 +1 @@ -Subproject commit 020121e90c6306147f91b8079b75f3d14ff86138 +Subproject commit 130a3d7fcfbba67bb86232f22ca08ba862873947 diff --git a/frozen/Adafruit_CircuitPython_FocalTouch b/frozen/Adafruit_CircuitPython_FocalTouch index 2fb86313db3..2070d7853cd 160000 --- a/frozen/Adafruit_CircuitPython_FocalTouch +++ b/frozen/Adafruit_CircuitPython_FocalTouch @@ -1 +1 @@ -Subproject commit 2fb86313db3408e57b1fbfbc56359ccb4f16f38b +Subproject commit 2070d7853cd1fe81381e02f4bc0af1bb145cb69e diff --git a/frozen/Adafruit_CircuitPython_HID b/frozen/Adafruit_CircuitPython_HID index d06b8b812ca..693baa60eb6 160000 --- a/frozen/Adafruit_CircuitPython_HID +++ b/frozen/Adafruit_CircuitPython_HID @@ -1 +1 @@ -Subproject commit d06b8b812caef3ae2eebb662f4e57ca306ce3219 +Subproject commit 693baa60eb684bb53379d98c6a036f56b8010666 diff --git a/frozen/Adafruit_CircuitPython_HTTPServer b/frozen/Adafruit_CircuitPython_HTTPServer index c43147a016f..c1d964fe7bf 160000 --- a/frozen/Adafruit_CircuitPython_HTTPServer +++ b/frozen/Adafruit_CircuitPython_HTTPServer @@ -1 +1 @@ -Subproject commit c43147a016ffd13c57a0923730bc6a83afefb4ad +Subproject commit c1d964fe7bf8734f7a858e798583d0f1304ae1c1 diff --git a/frozen/Adafruit_CircuitPython_IRRemote b/frozen/Adafruit_CircuitPython_IRRemote index b92d6930421..bb14c81e07a 160000 --- a/frozen/Adafruit_CircuitPython_IRRemote +++ b/frozen/Adafruit_CircuitPython_IRRemote @@ -1 +1 @@ -Subproject commit b92d69304212ee57a5f008317fcc4ebaf75ddebb +Subproject commit bb14c81e07aa798b36a53923059b5ab8a914915b diff --git a/frozen/Adafruit_CircuitPython_IS31FL3731 b/frozen/Adafruit_CircuitPython_IS31FL3731 index a0d701892d8..3becc08e451 160000 --- a/frozen/Adafruit_CircuitPython_IS31FL3731 +++ b/frozen/Adafruit_CircuitPython_IS31FL3731 @@ -1 +1 @@ -Subproject commit a0d701892d8bef096d80f1117bee718cecb380ff +Subproject commit 3becc08e451eeb2b6678a3d17547f5b0922e4660 diff --git a/frozen/Adafruit_CircuitPython_ImageLoad b/frozen/Adafruit_CircuitPython_ImageLoad index 135b0e4478b..11855997455 160000 --- a/frozen/Adafruit_CircuitPython_ImageLoad +++ b/frozen/Adafruit_CircuitPython_ImageLoad @@ -1 +1 @@ -Subproject commit 135b0e4478b34e1271e6bd87fa6d8efa0bef64b5 +Subproject commit 11855997455465bc93670e2a3f92e73bc9f7caee diff --git a/frozen/Adafruit_CircuitPython_LC709203F b/frozen/Adafruit_CircuitPython_LC709203F index b007bcae07b..bcbb0cfead8 160000 --- a/frozen/Adafruit_CircuitPython_LC709203F +++ b/frozen/Adafruit_CircuitPython_LC709203F @@ -1 +1 @@ -Subproject commit b007bcae07b346fd28aaee770dcabc9dde698c67 +Subproject commit bcbb0cfead8650a61357a167bc47058f05fba159 diff --git a/frozen/Adafruit_CircuitPython_LED_Animation b/frozen/Adafruit_CircuitPython_LED_Animation index 8af05705962..38a3c7844b4 160000 --- a/frozen/Adafruit_CircuitPython_LED_Animation +++ b/frozen/Adafruit_CircuitPython_LED_Animation @@ -1 +1 @@ -Subproject commit 8af05705962e8bb7d2f8003e6a70916a9a51b863 +Subproject commit 38a3c7844b4c59235fac46ee01e20caf872dad43 diff --git a/frozen/Adafruit_CircuitPython_LIS3DH b/frozen/Adafruit_CircuitPython_LIS3DH index 640b18ec1bf..cd40b482a09 160000 --- a/frozen/Adafruit_CircuitPython_LIS3DH +++ b/frozen/Adafruit_CircuitPython_LIS3DH @@ -1 +1 @@ -Subproject commit 640b18ec1bfd71e0a70f7ff3b8784043cd2d2671 +Subproject commit cd40b482a098a62ecce1b4c62a1f1930be984e16 diff --git a/frozen/Adafruit_CircuitPython_LSM6DS b/frozen/Adafruit_CircuitPython_LSM6DS index 2f50836f4bf..cdfc14a687a 160000 --- a/frozen/Adafruit_CircuitPython_LSM6DS +++ b/frozen/Adafruit_CircuitPython_LSM6DS @@ -1 +1 @@ -Subproject commit 2f50836f4bf0d9e48e4b8e046ba4d4167ad6dbdc +Subproject commit cdfc14a687a138aa0f2c6abab061bfc1bfafa561 diff --git a/frozen/Adafruit_CircuitPython_MIDI b/frozen/Adafruit_CircuitPython_MIDI index c4e693c2d49..6f5d6812474 160000 --- a/frozen/Adafruit_CircuitPython_MIDI +++ b/frozen/Adafruit_CircuitPython_MIDI @@ -1 +1 @@ -Subproject commit c4e693c2d4904d885cf842efc25687ccaccbabfa +Subproject commit 6f5d6812474a0460e9418278ea7da1e2269d2c0d diff --git a/frozen/Adafruit_CircuitPython_MPU6050 b/frozen/Adafruit_CircuitPython_MPU6050 index 05a0c3b7227..d30ee1fa5f4 160000 --- a/frozen/Adafruit_CircuitPython_MPU6050 +++ b/frozen/Adafruit_CircuitPython_MPU6050 @@ -1 +1 @@ -Subproject commit 05a0c3b72279db9fa2431308a77e6ab7ba040c8a +Subproject commit d30ee1fa5f49b62b4df382ea5310a77fa39d6bd9 diff --git a/frozen/Adafruit_CircuitPython_Motor b/frozen/Adafruit_CircuitPython_Motor index 89facc69a40..dc0c88c1d7c 160000 --- a/frozen/Adafruit_CircuitPython_Motor +++ b/frozen/Adafruit_CircuitPython_Motor @@ -1 +1 @@ -Subproject commit 89facc69a405ae83702ce566414adc39d46068f1 +Subproject commit dc0c88c1d7ca386a434d17c65a1e5efa5fc31a5f diff --git a/frozen/Adafruit_CircuitPython_NeoPixel b/frozen/Adafruit_CircuitPython_NeoPixel index 0ba2f2122a5..aa82c0724cc 160000 --- a/frozen/Adafruit_CircuitPython_NeoPixel +++ b/frozen/Adafruit_CircuitPython_NeoPixel @@ -1 +1 @@ -Subproject commit 0ba2f2122a54a71b1bc3576f87b1ba7dfc9db11e +Subproject commit aa82c0724ccb68fbd94605c9f4f09b19c5d2919d diff --git a/frozen/Adafruit_CircuitPython_OPT4048 b/frozen/Adafruit_CircuitPython_OPT4048 new file mode 160000 index 00000000000..97e63d8cd24 --- /dev/null +++ b/frozen/Adafruit_CircuitPython_OPT4048 @@ -0,0 +1 @@ +Subproject commit 97e63d8cd2425248c0aee323c3d8a6422404eaa5 diff --git a/frozen/Adafruit_CircuitPython_PCF8563 b/frozen/Adafruit_CircuitPython_PCF8563 index 74bb72d1c60..c4ca8d355b7 160000 --- a/frozen/Adafruit_CircuitPython_PCF8563 +++ b/frozen/Adafruit_CircuitPython_PCF8563 @@ -1 +1 @@ -Subproject commit 74bb72d1c607e44cf0d5349c466acd34863c11b4 +Subproject commit c4ca8d355b79179b44716544577925442a801bc0 diff --git a/frozen/Adafruit_CircuitPython_Pixel_Framebuf b/frozen/Adafruit_CircuitPython_Pixel_Framebuf index 1db789cf994..ffd3e8a6926 160000 --- a/frozen/Adafruit_CircuitPython_Pixel_Framebuf +++ b/frozen/Adafruit_CircuitPython_Pixel_Framebuf @@ -1 +1 @@ -Subproject commit 1db789cf99429e27d740279000788edc794d9d0d +Subproject commit ffd3e8a692676d076a2fa3f725e3a8ea63441139 diff --git a/frozen/Adafruit_CircuitPython_PortalBase b/frozen/Adafruit_CircuitPython_PortalBase index d26e2324de4..fc4aeea36ae 160000 --- a/frozen/Adafruit_CircuitPython_PortalBase +++ b/frozen/Adafruit_CircuitPython_PortalBase @@ -1 +1 @@ -Subproject commit d26e2324de496761e0aa72abc30ba07cdce8814b +Subproject commit fc4aeea36ae462463eb1317b66e0f772c439b28a diff --git a/frozen/Adafruit_CircuitPython_ProgressBar b/frozen/Adafruit_CircuitPython_ProgressBar index 6ba9d9d991a..e720f6ff61a 160000 --- a/frozen/Adafruit_CircuitPython_ProgressBar +++ b/frozen/Adafruit_CircuitPython_ProgressBar @@ -1 +1 @@ -Subproject commit 6ba9d9d991ada6c0cea6a32bd64595cfd37e06b2 +Subproject commit e720f6ff61aa41485a5611d8df3f7fa25fe8fb79 diff --git a/frozen/Adafruit_CircuitPython_RFM69 b/frozen/Adafruit_CircuitPython_RFM69 index 07be137bf5b..2f8a38c3cae 160000 --- a/frozen/Adafruit_CircuitPython_RFM69 +++ b/frozen/Adafruit_CircuitPython_RFM69 @@ -1 +1 @@ -Subproject commit 07be137bf5bda7a0469225c9cbb09b9a0aa08791 +Subproject commit 2f8a38c3cae772aa73216499dd40fde695878566 diff --git a/frozen/Adafruit_CircuitPython_RFM9x b/frozen/Adafruit_CircuitPython_RFM9x index 609aafb018b..b2a843ddff2 160000 --- a/frozen/Adafruit_CircuitPython_RFM9x +++ b/frozen/Adafruit_CircuitPython_RFM9x @@ -1 +1 @@ -Subproject commit 609aafb018b1cf5b7f60f2a7c961b827dce7468e +Subproject commit b2a843ddff22cec5a2b6ee79ba0c52e17cbf9dd2 diff --git a/frozen/Adafruit_CircuitPython_Register b/frozen/Adafruit_CircuitPython_Register index 96d0a4774f5..6ebae944c97 160000 --- a/frozen/Adafruit_CircuitPython_Register +++ b/frozen/Adafruit_CircuitPython_Register @@ -1 +1 @@ -Subproject commit 96d0a4774f5525b926c131618e436b8e5c218a2f +Subproject commit 6ebae944c97ff8f9394ceb2c634a32aef903e5c4 diff --git a/frozen/Adafruit_CircuitPython_Requests b/frozen/Adafruit_CircuitPython_Requests index 5e646b244cf..82a656aa807 160000 --- a/frozen/Adafruit_CircuitPython_Requests +++ b/frozen/Adafruit_CircuitPython_Requests @@ -1 +1 @@ -Subproject commit 5e646b244cf36f879f15aaf77a270e4c7e6e8336 +Subproject commit 82a656aa80797ae8c526b69061b9e75728d377c9 diff --git a/frozen/Adafruit_CircuitPython_SD b/frozen/Adafruit_CircuitPython_SD index ee4d73293c8..e85d264ad6e 160000 --- a/frozen/Adafruit_CircuitPython_SD +++ b/frozen/Adafruit_CircuitPython_SD @@ -1 +1 @@ -Subproject commit ee4d73293c8d059cd0c8bcf46758e62f5393cbee +Subproject commit e85d264ad6eaa286333fd3dbbf7a95b9ea7f0af3 diff --git a/frozen/Adafruit_CircuitPython_SHT4x b/frozen/Adafruit_CircuitPython_SHT4x index 26a0a407d43..c29695027b1 160000 --- a/frozen/Adafruit_CircuitPython_SHT4x +++ b/frozen/Adafruit_CircuitPython_SHT4x @@ -1 +1 @@ -Subproject commit 26a0a407d43bd6208deffdf577e214d899855c0e +Subproject commit c29695027b1d5f5140b570f31c91ace373f45843 diff --git a/frozen/Adafruit_CircuitPython_SSD1306 b/frozen/Adafruit_CircuitPython_SSD1306 index d75b4d593cd..f8fa41a320f 160000 --- a/frozen/Adafruit_CircuitPython_SSD1306 +++ b/frozen/Adafruit_CircuitPython_SSD1306 @@ -1 +1 @@ -Subproject commit d75b4d593cd184cbea5e237f5212cd9122d46263 +Subproject commit f8fa41a320f0bb29be6f37d340e69eba16b7a311 diff --git a/frozen/Adafruit_CircuitPython_SSD1680 b/frozen/Adafruit_CircuitPython_SSD1680 index d6aa01c4f8f..d3eb6f27c0d 160000 --- a/frozen/Adafruit_CircuitPython_SSD1680 +++ b/frozen/Adafruit_CircuitPython_SSD1680 @@ -1 +1 @@ -Subproject commit d6aa01c4f8fa1004430bfcdd4db2219183425693 +Subproject commit d3eb6f27c0d89e7e8a08bdaf0c6a6e40f7fc512c diff --git a/frozen/Adafruit_CircuitPython_ST7789 b/frozen/Adafruit_CircuitPython_ST7789 index 0f7269267c0..24a0feec2b2 160000 --- a/frozen/Adafruit_CircuitPython_ST7789 +++ b/frozen/Adafruit_CircuitPython_ST7789 @@ -1 +1 @@ -Subproject commit 0f7269267c0d17ada34926333bbda4021e5d7cb3 +Subproject commit 24a0feec2b24517c9f606f5063b6b48db4ce370e diff --git a/frozen/Adafruit_CircuitPython_SimpleIO b/frozen/Adafruit_CircuitPython_SimpleIO index d5278d246bc..5762bd0ec13 160000 --- a/frozen/Adafruit_CircuitPython_SimpleIO +++ b/frozen/Adafruit_CircuitPython_SimpleIO @@ -1 +1 @@ -Subproject commit d5278d246bcf658ef5d44e7658c956fac29bd9e1 +Subproject commit 5762bd0ec1309f9ef489633ed8bcc17d1bc7f560 diff --git a/frozen/Adafruit_CircuitPython_SimpleMath b/frozen/Adafruit_CircuitPython_SimpleMath index 33f82828598..3653b67541b 160000 --- a/frozen/Adafruit_CircuitPython_SimpleMath +++ b/frozen/Adafruit_CircuitPython_SimpleMath @@ -1 +1 @@ -Subproject commit 33f82828598a3a10c73dfa50601fef4beac40be8 +Subproject commit 3653b67541b7dbf0fbaaa65628c25cc6900dea87 diff --git a/frozen/Adafruit_CircuitPython_TAS2505 b/frozen/Adafruit_CircuitPython_TAS2505 new file mode 160000 index 00000000000..8363a155b5e --- /dev/null +++ b/frozen/Adafruit_CircuitPython_TAS2505 @@ -0,0 +1 @@ +Subproject commit 8363a155b5e03f13b0c796b350e086ed4e9edc75 diff --git a/frozen/Adafruit_CircuitPython_Thermistor b/frozen/Adafruit_CircuitPython_Thermistor index 2b45967cc52..86b15255613 160000 --- a/frozen/Adafruit_CircuitPython_Thermistor +++ b/frozen/Adafruit_CircuitPython_Thermistor @@ -1 +1 @@ -Subproject commit 2b45967cc5283e71b7826f6a158d8c8556dde287 +Subproject commit 86b152556138624979cad2df3210cadc38b5b344 diff --git a/frozen/Adafruit_CircuitPython_Ticks b/frozen/Adafruit_CircuitPython_Ticks index 6e159f899b0..0b27bc3dad3 160000 --- a/frozen/Adafruit_CircuitPython_Ticks +++ b/frozen/Adafruit_CircuitPython_Ticks @@ -1 +1 @@ -Subproject commit 6e159f899b017e920a6058a6b16735af8a6e852e +Subproject commit 0b27bc3dad368b2cd6f18cb4faba3fcb41d54477 diff --git a/frozen/Adafruit_CircuitPython_UC8151D b/frozen/Adafruit_CircuitPython_UC8151D index 4ebf9c28543..9a37fc43eeb 160000 --- a/frozen/Adafruit_CircuitPython_UC8151D +++ b/frozen/Adafruit_CircuitPython_UC8151D @@ -1 +1 @@ -Subproject commit 4ebf9c2854376a06766a6ae4732a4537a766fb75 +Subproject commit 9a37fc43eeb277f698614e8d657c4104a75a44aa diff --git a/frozen/Adafruit_CircuitPython_Wave b/frozen/Adafruit_CircuitPython_Wave index 6fba948b024..b2dd41fa0e3 160000 --- a/frozen/Adafruit_CircuitPython_Wave +++ b/frozen/Adafruit_CircuitPython_Wave @@ -1 +1 @@ -Subproject commit 6fba948b024ec210b3cf1f1b068b3eebc82fe8d4 +Subproject commit b2dd41fa0e3757c187a4693147eb7d83a84b5119 diff --git a/frozen/Adafruit_CircuitPython_Wiznet5k b/frozen/Adafruit_CircuitPython_Wiznet5k index 736241c7a22..f01275e34ad 160000 --- a/frozen/Adafruit_CircuitPython_Wiznet5k +++ b/frozen/Adafruit_CircuitPython_Wiznet5k @@ -1 +1 @@ -Subproject commit 736241c7a22f86dcf8ff73a77c4536cedfdc4cdd +Subproject commit f01275e34ad2e5f7ddd9d074e963a8359011a297 diff --git a/frozen/Adafruit_CircuitPython_asyncio b/frozen/Adafruit_CircuitPython_asyncio index 24818f817f5..705ae0cbda8 160000 --- a/frozen/Adafruit_CircuitPython_asyncio +++ b/frozen/Adafruit_CircuitPython_asyncio @@ -1 +1 @@ -Subproject commit 24818f817f5118f59aa696a04776049c179c0f4f +Subproject commit 705ae0cbda87c4bb4d82fb81aa8fb718b5a4b385 diff --git a/frozen/Adafruit_CircuitPython_framebuf b/frozen/Adafruit_CircuitPython_framebuf index 0fedf2f308e..6f6c89891de 160000 --- a/frozen/Adafruit_CircuitPython_framebuf +++ b/frozen/Adafruit_CircuitPython_framebuf @@ -1 +1 @@ -Subproject commit 0fedf2f308ed6b3e8261661e4810e613f33d7171 +Subproject commit 6f6c89891de7d96c43028c4fdff5765763dffe16 diff --git a/frozen/Adafruit_CircuitPython_seesaw b/frozen/Adafruit_CircuitPython_seesaw index 94c541f4531..13ba8ba2a2c 160000 --- a/frozen/Adafruit_CircuitPython_seesaw +++ b/frozen/Adafruit_CircuitPython_seesaw @@ -1 +1 @@ -Subproject commit 94c541f45313dc7eb98a4cd1a6c3af39f001cc49 +Subproject commit 13ba8ba2a2cecb9df5a41390f991ce6c0cd76e14 diff --git a/frozen/CircuitPython_edupico2_paj7620 b/frozen/CircuitPython_edupico2_paj7620 new file mode 160000 index 00000000000..16a4d784724 --- /dev/null +++ b/frozen/CircuitPython_edupico2_paj7620 @@ -0,0 +1 @@ +Subproject commit 16a4d784724992862cffd594aeed8c627ecc18b3 diff --git a/frozen/circuitpython-stage b/frozen/circuitpython-stage index ccac175f5e9..7b71363acb6 160000 --- a/frozen/circuitpython-stage +++ b/frozen/circuitpython-stage @@ -1 +1 @@ -Subproject commit ccac175f5e9c8392d436058d4364a8ca5e58abc7 +Subproject commit 7b71363acb67cb1b254b12607f35280cfb4ad6c1 diff --git a/lib/AnimatedGIF/gif.c b/lib/AnimatedGIF/gif.c index 0822b608c18..316fc1ab749 100644 --- a/lib/AnimatedGIF/gif.c +++ b/lib/AnimatedGIF/gif.c @@ -23,7 +23,7 @@ // #include "AnimatedGIF_circuitpy.h" -#ifdef HAL_ESP32_HAL_H_ +#ifndef memcpy_P #define memcpy_P memcpy #endif diff --git a/lib/berkeley-db-1.xx b/lib/berkeley-db-1.xx index 85373b548f1..0f3bb6947c2 160000 --- a/lib/berkeley-db-1.xx +++ b/lib/berkeley-db-1.xx @@ -1 +1 @@ -Subproject commit 85373b548f1fb0119a463582570b44189dfb09ae +Subproject commit 0f3bb6947c2f57233916dccd7bb425d7bf86e5a6 diff --git a/lib/libm_dbl/libm.h b/lib/libm_dbl/libm.h index cbae6916625..fa49ad1cddd 100644 --- a/lib/libm_dbl/libm.h +++ b/lib/libm_dbl/libm.h @@ -89,7 +89,9 @@ do { \ (d) = __u.f; \ } while (0) +#if !defined(DBL_EPSILON) #define DBL_EPSILON 2.22044604925031308085e-16 +#endif int __rem_pio2(double, double*); int __rem_pio2_large(double*, double*, int, int, int); diff --git a/lib/libm_dbl/rint.c b/lib/libm_dbl/rint.c index fbba390e7d7..b85dec8f246 100644 --- a/lib/libm_dbl/rint.c +++ b/lib/libm_dbl/rint.c @@ -2,7 +2,7 @@ #include #include -#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 || FLT_EVAL_METHOD==16 #define EPS DBL_EPSILON #elif FLT_EVAL_METHOD==2 #define EPS LDBL_EPSILON diff --git a/lib/littlefs/lfs2.c b/lib/littlefs/lfs2.c index 613213669c8..8c65397384b 100644 --- a/lib/littlefs/lfs2.c +++ b/lib/littlefs/lfs2.c @@ -93,6 +93,7 @@ static int lfs2_bd_read(lfs2_t *lfs2, // bypass cache? diff = lfs2_aligndown(diff, lfs2->cfg->read_size); int err = lfs2->cfg->read(lfs2->cfg, block, off, data, diff); + LFS2_ASSERT(err <= 0); if (err) { return err; } @@ -257,7 +258,7 @@ static int lfs2_bd_prog(lfs2_t *lfs2, continue; } - // pcache must have been flushed, either by programming and + // pcache must have been flushed, either by programming an // entire block or manually flushing the pcache LFS2_ASSERT(pcache->block == LFS2_BLOCK_NULL); @@ -282,6 +283,21 @@ static int lfs2_bd_erase(lfs2_t *lfs2, lfs2_block_t block) { /// Small type-level utilities /// + +// some operations on paths +static inline lfs2_size_t lfs2_path_namelen(const char *path) { + return (lfs2_size_t)strcspn(path, "/"); +} + +static inline bool lfs2_path_islast(const char *path) { + lfs2_size_t namelen = lfs2_path_namelen(path); + return path[namelen + strspn(path + namelen, "/")] == '\0'; +} + +static inline bool lfs2_path_isdir(const char *path) { + return path[lfs2_path_namelen(path)] != '\0'; +} + // operations on block pairs static inline void lfs2_pair_swap(lfs2_block_t pair[2]) { lfs2_block_t t = pair[0]; @@ -389,18 +405,15 @@ struct lfs2_diskoff { // operations on global state static inline void lfs2_gstate_xor(lfs2_gstate_t *a, const lfs2_gstate_t *b) { - for (int i = 0; i < 3; i++) { - ((uint32_t*)a)[i] ^= ((const uint32_t*)b)[i]; - } + a->tag ^= b->tag; + a->pair[0] ^= b->pair[0]; + a->pair[1] ^= b->pair[1]; } static inline bool lfs2_gstate_iszero(const lfs2_gstate_t *a) { - for (int i = 0; i < 3; i++) { - if (((uint32_t*)a)[i] != 0) { - return false; - } - } - return true; + return a->tag == 0 + && a->pair[0] == 0 + && a->pair[1] == 0; } #ifndef LFS2_READONLY @@ -550,9 +563,9 @@ static int lfs2_dir_compact(lfs2_t *lfs2, lfs2_mdir_t *source, uint16_t begin, uint16_t end); static lfs2_ssize_t lfs2_file_flushedwrite(lfs2_t *lfs2, lfs2_file_t *file, const void *buffer, lfs2_size_t size); -static lfs2_ssize_t lfs2_file_rawwrite(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_ssize_t lfs2_file_write_(lfs2_t *lfs2, lfs2_file_t *file, const void *buffer, lfs2_size_t size); -static int lfs2_file_rawsync(lfs2_t *lfs2, lfs2_file_t *file); +static int lfs2_file_sync_(lfs2_t *lfs2, lfs2_file_t *file); static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file); static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file); @@ -574,65 +587,72 @@ static int lfs21_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); #endif -static int lfs2_dir_rawrewind(lfs2_t *lfs2, lfs2_dir_t *dir); +static int lfs2_dir_rewind_(lfs2_t *lfs2, lfs2_dir_t *dir); static lfs2_ssize_t lfs2_file_flushedread(lfs2_t *lfs2, lfs2_file_t *file, void *buffer, lfs2_size_t size); -static lfs2_ssize_t lfs2_file_rawread(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_ssize_t lfs2_file_read_(lfs2_t *lfs2, lfs2_file_t *file, void *buffer, lfs2_size_t size); -static int lfs2_file_rawclose(lfs2_t *lfs2, lfs2_file_t *file); -static lfs2_soff_t lfs2_file_rawsize(lfs2_t *lfs2, lfs2_file_t *file); +static int lfs2_file_close_(lfs2_t *lfs2, lfs2_file_t *file); +static lfs2_soff_t lfs2_file_size_(lfs2_t *lfs2, lfs2_file_t *file); -static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2); -static int lfs2_fs_rawtraverse(lfs2_t *lfs2, +static lfs2_ssize_t lfs2_fs_size_(lfs2_t *lfs2); +static int lfs2_fs_traverse_(lfs2_t *lfs2, int (*cb)(void *data, lfs2_block_t block), void *data, bool includeorphans); static int lfs2_deinit(lfs2_t *lfs2); -static int lfs2_rawunmount(lfs2_t *lfs2); +static int lfs2_unmount_(lfs2_t *lfs2); /// Block allocator /// + +// allocations should call this when all allocated blocks are committed to +// the filesystem +// +// after a checkpoint, the block allocator may realloc any untracked blocks +static void lfs2_alloc_ckpoint(lfs2_t *lfs2) { + lfs2->lookahead.ckpoint = lfs2->block_count; +} + +// drop the lookahead buffer, this is done during mounting and failed +// traversals in order to avoid invalid lookahead state +static void lfs2_alloc_drop(lfs2_t *lfs2) { + lfs2->lookahead.size = 0; + lfs2->lookahead.next = 0; + lfs2_alloc_ckpoint(lfs2); +} + #ifndef LFS2_READONLY static int lfs2_alloc_lookahead(void *p, lfs2_block_t block) { lfs2_t *lfs2 = (lfs2_t*)p; - lfs2_block_t off = ((block - lfs2->free.off) + lfs2_block_t off = ((block - lfs2->lookahead.start) + lfs2->block_count) % lfs2->block_count; - if (off < lfs2->free.size) { - lfs2->free.buffer[off / 32] |= 1U << (off % 32); + if (off < lfs2->lookahead.size) { + lfs2->lookahead.buffer[off / 8] |= 1U << (off % 8); } return 0; } #endif -// indicate allocated blocks have been committed into the filesystem, this -// is to prevent blocks from being garbage collected in the middle of a -// commit operation -static void lfs2_alloc_ack(lfs2_t *lfs2) { - lfs2->free.ack = lfs2->block_count; -} - -// drop the lookahead buffer, this is done during mounting and failed -// traversals in order to avoid invalid lookahead state -static void lfs2_alloc_drop(lfs2_t *lfs2) { - lfs2->free.size = 0; - lfs2->free.i = 0; - lfs2_alloc_ack(lfs2); -} - #ifndef LFS2_READONLY -static int lfs2_fs_rawgc(lfs2_t *lfs2) { - // Move free offset at the first unused block (lfs2->free.i) - // lfs2->free.i is equal lfs2->free.size when all blocks are used - lfs2->free.off = (lfs2->free.off + lfs2->free.i) % lfs2->block_count; - lfs2->free.size = lfs2_min(8*lfs2->cfg->lookahead_size, lfs2->free.ack); - lfs2->free.i = 0; +static int lfs2_alloc_scan(lfs2_t *lfs2) { + // move lookahead buffer to the first unused block + // + // note we limit the lookahead buffer to at most the amount of blocks + // checkpointed, this prevents the math in lfs2_alloc from underflowing + lfs2->lookahead.start = (lfs2->lookahead.start + lfs2->lookahead.next) + % lfs2->block_count; + lfs2->lookahead.next = 0; + lfs2->lookahead.size = lfs2_min( + 8*lfs2->cfg->lookahead_size, + lfs2->lookahead.ckpoint); // find mask of free blocks from tree - memset(lfs2->free.buffer, 0, lfs2->cfg->lookahead_size); - int err = lfs2_fs_rawtraverse(lfs2, lfs2_alloc_lookahead, lfs2, true); + memset(lfs2->lookahead.buffer, 0, lfs2->cfg->lookahead_size); + int err = lfs2_fs_traverse_(lfs2, lfs2_alloc_lookahead, lfs2, true); if (err) { lfs2_alloc_drop(lfs2); return err; @@ -645,36 +665,49 @@ static int lfs2_fs_rawgc(lfs2_t *lfs2) { #ifndef LFS2_READONLY static int lfs2_alloc(lfs2_t *lfs2, lfs2_block_t *block) { while (true) { - while (lfs2->free.i != lfs2->free.size) { - lfs2_block_t off = lfs2->free.i; - lfs2->free.i += 1; - lfs2->free.ack -= 1; - - if (!(lfs2->free.buffer[off / 32] & (1U << (off % 32)))) { + // scan our lookahead buffer for free blocks + while (lfs2->lookahead.next < lfs2->lookahead.size) { + if (!(lfs2->lookahead.buffer[lfs2->lookahead.next / 8] + & (1U << (lfs2->lookahead.next % 8)))) { // found a free block - *block = (lfs2->free.off + off) % lfs2->block_count; - - // eagerly find next off so an alloc ack can - // discredit old lookahead blocks - while (lfs2->free.i != lfs2->free.size && - (lfs2->free.buffer[lfs2->free.i / 32] - & (1U << (lfs2->free.i % 32)))) { - lfs2->free.i += 1; - lfs2->free.ack -= 1; + *block = (lfs2->lookahead.start + lfs2->lookahead.next) + % lfs2->block_count; + + // eagerly find next free block to maximize how many blocks + // lfs2_alloc_ckpoint makes available for scanning + while (true) { + lfs2->lookahead.next += 1; + lfs2->lookahead.ckpoint -= 1; + + if (lfs2->lookahead.next >= lfs2->lookahead.size + || !(lfs2->lookahead.buffer[lfs2->lookahead.next / 8] + & (1U << (lfs2->lookahead.next % 8)))) { + return 0; + } } - - return 0; } + + lfs2->lookahead.next += 1; + lfs2->lookahead.ckpoint -= 1; } - // check if we have looked at all blocks since last ack - if (lfs2->free.ack == 0) { - LFS2_ERROR("No more free space %"PRIu32, - lfs2->free.i + lfs2->free.off); + // In order to keep our block allocator from spinning forever when our + // filesystem is full, we mark points where there are no in-flight + // allocations with a checkpoint before starting a set of allocations. + // + // If we've looked at all blocks since the last checkpoint, we report + // the filesystem as out of storage. + // + if (lfs2->lookahead.ckpoint <= 0) { + LFS2_ERROR("No more free space 0x%"PRIx32, + (lfs2->lookahead.start + lfs2->lookahead.next) + % lfs2->block_count); return LFS2_ERR_NOSPC; } - int err = lfs2_fs_rawgc(lfs2); + // No blocks in our lookahead buffer, we need to scan the filesystem for + // unused blocks in the next lookahead window. + int err = lfs2_alloc_scan(lfs2); if(err) { return err; } @@ -690,11 +723,14 @@ static lfs2_stag_t lfs2_dir_getslice(lfs2_t *lfs2, const lfs2_mdir_t *dir, lfs2_tag_t ntag = dir->etag; lfs2_stag_t gdiff = 0; + // synthetic moves if (lfs2_gstate_hasmovehere(&lfs2->gdisk, dir->pair) && - lfs2_tag_id(gmask) != 0 && - lfs2_tag_id(lfs2->gdisk.tag) <= lfs2_tag_id(gtag)) { - // synthetic moves - gdiff -= LFS2_MKTAG(0, 1, 0); + lfs2_tag_id(gmask) != 0) { + if (lfs2_tag_id(lfs2->gdisk.tag) == lfs2_tag_id(gtag)) { + return LFS2_ERR_NOENT; + } else if (lfs2_tag_id(lfs2->gdisk.tag) < lfs2_tag_id(gtag)) { + gdiff -= LFS2_MKTAG(0, 1, 0); + } } // iterate over dir block backwards (for faster lookups) @@ -704,6 +740,7 @@ static lfs2_stag_t lfs2_dir_getslice(lfs2_t *lfs2, const lfs2_mdir_t *dir, int err = lfs2_bd_read(lfs2, NULL, &lfs2->rcache, sizeof(ntag), dir->pair[0], off, &ntag, sizeof(ntag)); + LFS2_ASSERT(err <= 0); if (err) { return err; } @@ -732,6 +769,7 @@ static lfs2_stag_t lfs2_dir_getslice(lfs2_t *lfs2, const lfs2_mdir_t *dir, err = lfs2_bd_read(lfs2, NULL, &lfs2->rcache, diff, dir->pair[0], off+sizeof(tag)+goff, gbuffer, diff); + LFS2_ASSERT(err <= 0); if (err) { return err; } @@ -793,9 +831,6 @@ static int lfs2_dir_getread(lfs2_t *lfs2, const lfs2_mdir_t *dir, size -= diff; continue; } - - // rcache takes priority - diff = lfs2_min(diff, rcache->off-off); } // load to cache, first condition can no longer fail @@ -1247,6 +1282,7 @@ static lfs2_stag_t lfs2_dir_fetchmatch(lfs2_t *lfs2, if (err == LFS2_ERR_CORRUPT) { break; } + return err; } lfs2_fcrc_fromle32(&fcrc); @@ -1255,6 +1291,7 @@ static lfs2_stag_t lfs2_dir_fetchmatch(lfs2_t *lfs2, // found a match for our fetcher? if ((fmask & tag) == (fmask & ftag)) { + LFS2_ASSERT(cb != NULL); int res = cb(data, tag, &(struct lfs2_diskoff){ dir->pair[0], off+sizeof(tag)}); if (res < 0) { @@ -1438,44 +1475,60 @@ static int lfs2_dir_find_match(void *data, return LFS2_CMP_EQ; } +// lfs2_dir_find tries to set path and id even if file is not found +// +// returns: +// - 0 if file is found +// - LFS2_ERR_NOENT if file or parent is not found +// - LFS2_ERR_NOTDIR if parent is not a dir static lfs2_stag_t lfs2_dir_find(lfs2_t *lfs2, lfs2_mdir_t *dir, const char **path, uint16_t *id) { // we reduce path to a single name if we can find it const char *name = *path; - if (id) { - *id = 0x3ff; - } // default to root dir lfs2_stag_t tag = LFS2_MKTAG(LFS2_TYPE_DIR, 0x3ff, 0); dir->tail[0] = lfs2->root[0]; dir->tail[1] = lfs2->root[1]; + // empty paths are not allowed + if (*name == '\0') { + return LFS2_ERR_INVAL; + } + while (true) { nextname: - // skip slashes - name += strspn(name, "/"); - lfs2_size_t namelen = strcspn(name, "/"); + // skip slashes if we're a directory + if (lfs2_tag_type3(tag) == LFS2_TYPE_DIR) { + name += strspn(name, "/"); + } + lfs2_size_t namelen = (lfs2_size_t)strcspn(name, "/"); - // skip '.' and root '..' - if ((namelen == 1 && memcmp(name, ".", 1) == 0) || - (namelen == 2 && memcmp(name, "..", 2) == 0)) { + // skip '.' + if (namelen == 1 && memcmp(name, ".", 1) == 0) { name += namelen; goto nextname; } + // error on unmatched '..', trying to go above root? + if (namelen == 2 && memcmp(name, "..", 2) == 0) { + return LFS2_ERR_INVAL; + } + // skip if matched by '..' in name const char *suffix = name + namelen; lfs2_size_t sufflen; int depth = 1; while (true) { suffix += strspn(suffix, "/"); - sufflen = strcspn(suffix, "/"); + sufflen = (lfs2_size_t)strcspn(suffix, "/"); if (sufflen == 0) { break; } - if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { + if (sufflen == 1 && memcmp(suffix, ".", 1) == 0) { + // noop + } else if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { depth -= 1; if (depth == 0) { name = suffix + sufflen; @@ -1489,14 +1542,14 @@ static lfs2_stag_t lfs2_dir_find(lfs2_t *lfs2, lfs2_mdir_t *dir, } // found path - if (name[0] == '\0') { + if (*name == '\0') { return tag; } // update what we've found so far *path = name; - // only continue if we hit a directory + // only continue if we're a directory if (lfs2_tag_type3(tag) != LFS2_TYPE_DIR) { return LFS2_ERR_NOTDIR; } @@ -1516,8 +1569,7 @@ static lfs2_stag_t lfs2_dir_find(lfs2_t *lfs2, lfs2_mdir_t *dir, tag = lfs2_dir_fetchmatch(lfs2, dir, dir->tail, LFS2_MKTAG(0x780, 0, 0), LFS2_MKTAG(LFS2_TYPE_NAME, 0, namelen), - // are we last name? - (strchr(name, '/') == NULL) ? id : NULL, + id, lfs2_dir_find_match, &(struct lfs2_dir_find_match){ lfs2, name, namelen}); if (tag < 0) { @@ -1710,7 +1762,7 @@ static int lfs2_dir_commitcrc(lfs2_t *lfs2, struct lfs2_commit *commit) { commit->off = noff; // perturb valid bit? - commit->ptag = ntag ^ ((0x80UL & ~eperturb) << 24); + commit->ptag = ntag ^ ((lfs2_tag_t)(0x80 & ~eperturb) << 24); // reset crc for next commit commit->crc = 0xffffffff; @@ -2105,13 +2157,14 @@ static int lfs2_dir_splittingcompact(lfs2_t *lfs2, lfs2_mdir_t *dir, // And we cap at half a block to avoid degenerate cases with // nearly-full metadata blocks. // + lfs2_size_t metadata_max = (lfs2->cfg->metadata_max) + ? lfs2->cfg->metadata_max + : lfs2->cfg->block_size; if (end - split < 0xff && size <= lfs2_min( - lfs2->cfg->block_size - 40, + metadata_max - 40, lfs2_alignup( - (lfs2->cfg->metadata_max - ? lfs2->cfg->metadata_max - : lfs2->cfg->block_size)/2, + metadata_max/2, lfs2->cfg->prog_size))) { break; } @@ -2146,14 +2199,16 @@ static int lfs2_dir_splittingcompact(lfs2_t *lfs2, lfs2_mdir_t *dir, && lfs2_pair_cmp(dir->pair, (const lfs2_block_t[2]){0, 1}) == 0) { // oh no! we're writing too much to the superblock, // should we expand? - lfs2_ssize_t size = lfs2_fs_rawsize(lfs2); + lfs2_ssize_t size = lfs2_fs_size_(lfs2); if (size < 0) { return size; } - // do we have extra space? littlefs can't reclaim this space - // by itself, so expand cautiously - if ((lfs2_size_t)size < lfs2->block_count/2) { + // littlefs cannot reclaim expanded superblocks, so expand cautiously + // + // if our filesystem is more than ~88% full, don't expand, this is + // somewhat arbitrary + if (lfs2->block_count - size > lfs2->block_count/8) { LFS2_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev); int err = lfs2_dir_split(lfs2, dir, attrs, attrcount, source, begin, end); @@ -2166,7 +2221,8 @@ static int lfs2_dir_splittingcompact(lfs2_t *lfs2, lfs2_mdir_t *dir, // we can do, we'll error later if we've become frozen LFS2_WARN("Unable to expand superblock"); } else { - end = begin; + // duplicate the superblock entry into the new superblock + end = 1; } } } @@ -2213,7 +2269,7 @@ static int lfs2_dir_relocatingcommit(lfs2_t *lfs2, lfs2_mdir_t *dir, } } - if (dir->erased) { + if (dir->erased && dir->count < 0xff) { // try to commit struct lfs2_commit commit = { .block = dir->pair[0], @@ -2312,7 +2368,8 @@ fixmlist:; if (d->m.pair != pair) { for (int i = 0; i < attrcount; i++) { if (lfs2_tag_type3(attrs[i].tag) == LFS2_TYPE_DELETE && - d->id == lfs2_tag_id(attrs[i].tag)) { + d->id == lfs2_tag_id(attrs[i].tag) && + d->type != LFS2_TYPE_DIR) { d->m.pair[0] = LFS2_BLOCK_NULL; d->m.pair[1] = LFS2_BLOCK_NULL; } else if (lfs2_tag_type3(attrs[i].tag) == LFS2_TYPE_DELETE && @@ -2333,7 +2390,9 @@ fixmlist:; while (d->id >= d->m.count && d->m.split) { // we split and id is on tail now - d->id -= d->m.count; + if (lfs2_pair_cmp(d->m.tail, lfs2->root) != 0) { + d->id -= d->m.count; + } int err = lfs2_dir_fetch(lfs2, &d->m, d->m.tail); if (err) { return err; @@ -2499,7 +2558,7 @@ static int lfs2_dir_orphaningcommit(lfs2_t *lfs2, lfs2_mdir_t *dir, if (err != LFS2_ERR_NOENT) { if (lfs2_gstate_hasorphans(&lfs2->gstate)) { // next step, clean up orphans - err = lfs2_fs_preporphans(lfs2, -hasparent); + err = lfs2_fs_preporphans(lfs2, -(int8_t)hasparent); if (err) { return err; } @@ -2564,7 +2623,7 @@ static int lfs2_dir_commit(lfs2_t *lfs2, lfs2_mdir_t *dir, /// Top level directory operations /// #ifndef LFS2_READONLY -static int lfs2_rawmkdir(lfs2_t *lfs2, const char *path) { +static int lfs2_mkdir_(lfs2_t *lfs2, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs2_fs_forceconsistency(lfs2); if (err) { @@ -2575,18 +2634,18 @@ static int lfs2_rawmkdir(lfs2_t *lfs2, const char *path) { cwd.next = lfs2->mlist; uint16_t id; err = lfs2_dir_find(lfs2, &cwd.m, &path, &id); - if (!(err == LFS2_ERR_NOENT && id != 0x3ff)) { + if (!(err == LFS2_ERR_NOENT && lfs2_path_islast(path))) { return (err < 0) ? err : LFS2_ERR_EXIST; } // check that name fits - lfs2_size_t nlen = strlen(path); + lfs2_size_t nlen = lfs2_path_namelen(path); if (nlen > lfs2->name_max) { return LFS2_ERR_NAMETOOLONG; } // build up new directory - lfs2_alloc_ack(lfs2); + lfs2_alloc_ckpoint(lfs2); lfs2_mdir_t dir; err = lfs2_dir_alloc(lfs2, &dir); if (err) { @@ -2660,7 +2719,7 @@ static int lfs2_rawmkdir(lfs2_t *lfs2, const char *path) { } #endif -static int lfs2_dir_rawopen(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { +static int lfs2_dir_open_(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { lfs2_stag_t tag = lfs2_dir_find(lfs2, &dir->m, &path, NULL); if (tag < 0) { return tag; @@ -2704,14 +2763,14 @@ static int lfs2_dir_rawopen(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { return 0; } -static int lfs2_dir_rawclose(lfs2_t *lfs2, lfs2_dir_t *dir) { +static int lfs2_dir_close_(lfs2_t *lfs2, lfs2_dir_t *dir) { // remove from list of mdirs lfs2_mlist_remove(lfs2, (struct lfs2_mlist *)dir); return 0; } -static int lfs2_dir_rawread(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { +static int lfs2_dir_read_(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { memset(info, 0, sizeof(*info)); // special offset for '.' and '..' @@ -2756,9 +2815,9 @@ static int lfs2_dir_rawread(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *inf return true; } -static int lfs2_dir_rawseek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { +static int lfs2_dir_seek_(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { // simply walk from head dir - int err = lfs2_dir_rawrewind(lfs2, dir); + int err = lfs2_dir_rewind_(lfs2, dir); if (err) { return err; } @@ -2793,12 +2852,12 @@ static int lfs2_dir_rawseek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { return 0; } -static lfs2_soff_t lfs2_dir_rawtell(lfs2_t *lfs2, lfs2_dir_t *dir) { +static lfs2_soff_t lfs2_dir_tell_(lfs2_t *lfs2, lfs2_dir_t *dir) { (void)lfs2; return dir->pos; } -static int lfs2_dir_rawrewind(lfs2_t *lfs2, lfs2_dir_t *dir) { +static int lfs2_dir_rewind_(lfs2_t *lfs2, lfs2_dir_t *dir) { // reload the head dir int err = lfs2_dir_fetch(lfs2, &dir->m, dir->head); if (err) { @@ -3004,7 +3063,7 @@ static int lfs2_ctz_traverse(lfs2_t *lfs2, /// Top level file operations /// -static int lfs2_file_rawopencfg(lfs2_t *lfs2, lfs2_file_t *file, +static int lfs2_file_opencfg_(lfs2_t *lfs2, lfs2_file_t *file, const char *path, int flags, const struct lfs2_file_config *cfg) { #ifndef LFS2_READONLY @@ -3029,7 +3088,7 @@ static int lfs2_file_rawopencfg(lfs2_t *lfs2, lfs2_file_t *file, // allocate entry for file if it doesn't exist lfs2_stag_t tag = lfs2_dir_find(lfs2, &file->m, &path, &file->id); - if (tag < 0 && !(tag == LFS2_ERR_NOENT && file->id != 0x3ff)) { + if (tag < 0 && !(tag == LFS2_ERR_NOENT && lfs2_path_islast(path))) { err = tag; goto cleanup; } @@ -3049,8 +3108,14 @@ static int lfs2_file_rawopencfg(lfs2_t *lfs2, lfs2_file_t *file, goto cleanup; } + // don't allow trailing slashes + if (lfs2_path_isdir(path)) { + err = LFS2_ERR_NOTDIR; + goto cleanup; + } + // check that name fits - lfs2_size_t nlen = strlen(path); + lfs2_size_t nlen = lfs2_path_namelen(path); if (nlen > lfs2->name_max) { err = LFS2_ERR_NAMETOOLONG; goto cleanup; @@ -3166,24 +3231,26 @@ static int lfs2_file_rawopencfg(lfs2_t *lfs2, lfs2_file_t *file, #ifndef LFS2_READONLY file->flags |= LFS2_F_ERRED; #endif - lfs2_file_rawclose(lfs2, file); + lfs2_file_close_(lfs2, file); return err; } #ifndef LFS2_NO_MALLOC -static int lfs2_file_rawopen(lfs2_t *lfs2, lfs2_file_t *file, +static int lfs2_file_open_(lfs2_t *lfs2, lfs2_file_t *file, const char *path, int flags) { static const struct lfs2_file_config defaults = {0}; - int err = lfs2_file_rawopencfg(lfs2, file, path, flags, &defaults); + int err = lfs2_file_opencfg_(lfs2, file, path, flags, &defaults); return err; } #endif -static int lfs2_file_rawclose(lfs2_t *lfs2, lfs2_file_t *file) { -#ifndef LFS2_READONLY - int err = lfs2_file_rawsync(lfs2, file); -#else +static int lfs2_file_close_(lfs2_t *lfs2, lfs2_file_t *file) { int err = 0; +#ifndef LFS2_READONLY + // it's not safe to do anything if our file errored + if (!(file->flags & LFS2_F_ERRED)) { + err = lfs2_file_sync_(lfs2, file); + } #endif // remove from list of mdirs @@ -3272,7 +3339,7 @@ static int lfs2_file_relocate(lfs2_t *lfs2, lfs2_file_t *file) { #ifndef LFS2_READONLY static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file) { file->off = file->pos; - lfs2_alloc_ack(lfs2); + lfs2_alloc_ckpoint(lfs2); int err = lfs2_file_relocate(lfs2, file); if (err) { return err; @@ -3364,21 +3431,24 @@ static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file) { } #ifndef LFS2_READONLY -static int lfs2_file_rawsync(lfs2_t *lfs2, lfs2_file_t *file) { - if (file->flags & LFS2_F_ERRED) { - // it's not safe to do anything if our file errored - return 0; - } - +static int lfs2_file_sync_(lfs2_t *lfs2, lfs2_file_t *file) { int err = lfs2_file_flush(lfs2, file); if (err) { file->flags |= LFS2_F_ERRED; return err; } - if ((file->flags & LFS2_F_DIRTY) && !lfs2_pair_isnull(file->m.pair)) { + // before we commit metadata, we need sync the disk to make sure + // data writes don't complete after metadata writes + if (!(file->flags & LFS2_F_INLINE)) { + err = lfs2_bd_sync(lfs2, &lfs2->pcache, &lfs2->rcache, false); + if (err) { + return err; + } + } + // update dir entry uint16_t type; const void *buffer; @@ -3412,6 +3482,17 @@ static int lfs2_file_rawsync(lfs2_t *lfs2, lfs2_file_t *file) { file->flags &= ~LFS2_F_DIRTY; } + // mark any other file handles as dirty + desync + for (lfs2_file_t *f = (lfs2_file_t*)lfs2->mlist; f; f = f->next) { + if (file != f + && f->type == LFS2_TYPE_REG + && lfs2_pair_cmp(f->m.pair, file->m.pair) == 0 + && f->id == file->id) { + f->flags |= LFS2_F_DUSTY; + } + } + + file->flags &= ~LFS2_F_ERRED & ~LFS2_F_DUSTY; return 0; } #endif @@ -3477,7 +3558,7 @@ static lfs2_ssize_t lfs2_file_flushedread(lfs2_t *lfs2, lfs2_file_t *file, return size; } -static lfs2_ssize_t lfs2_file_rawread(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_ssize_t lfs2_file_read_(lfs2_t *lfs2, lfs2_file_t *file, void *buffer, lfs2_size_t size) { LFS2_ASSERT((file->flags & LFS2_O_RDONLY) == LFS2_O_RDONLY); @@ -3502,11 +3583,7 @@ static lfs2_ssize_t lfs2_file_flushedwrite(lfs2_t *lfs2, lfs2_file_t *file, lfs2_size_t nsize = size; if ((file->flags & LFS2_F_INLINE) && - lfs2_max(file->pos+nsize, file->ctz.size) > - lfs2_min(0x3fe, lfs2_min( - lfs2->cfg->cache_size, - (lfs2->cfg->metadata_max ? - lfs2->cfg->metadata_max : lfs2->cfg->block_size) / 8))) { + lfs2_max(file->pos+nsize, file->ctz.size) > lfs2->inline_max) { // inline file doesn't fit anymore int err = lfs2_file_outline(lfs2, file); if (err) { @@ -3535,7 +3612,7 @@ static lfs2_ssize_t lfs2_file_flushedwrite(lfs2_t *lfs2, lfs2_file_t *file, } // extend file with new blocks - lfs2_alloc_ack(lfs2); + lfs2_alloc_ckpoint(lfs2); int err = lfs2_ctz_extend(lfs2, &file->cache, &lfs2->rcache, file->block, file->pos, &file->block, &file->off); @@ -3578,13 +3655,13 @@ static lfs2_ssize_t lfs2_file_flushedwrite(lfs2_t *lfs2, lfs2_file_t *file, data += diff; nsize -= diff; - lfs2_alloc_ack(lfs2); + lfs2_alloc_ckpoint(lfs2); } return size; } -static lfs2_ssize_t lfs2_file_rawwrite(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_ssize_t lfs2_file_write_(lfs2_t *lfs2, lfs2_file_t *file, const void *buffer, lfs2_size_t size) { LFS2_ASSERT((file->flags & LFS2_O_WRONLY) == LFS2_O_WRONLY); @@ -3623,30 +3700,24 @@ static lfs2_ssize_t lfs2_file_rawwrite(lfs2_t *lfs2, lfs2_file_t *file, return nsize; } - file->flags &= ~LFS2_F_ERRED; + file->flags &= ~LFS2_F_ERRED & ~LFS2_F_DUSTY; return nsize; } #endif -static lfs2_soff_t lfs2_file_rawseek(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_soff_t lfs2_file_seek_(lfs2_t *lfs2, lfs2_file_t *file, lfs2_soff_t off, int whence) { // find new pos + // + // fortunately for us, littlefs is limited to 31-bit file sizes, so we + // don't have to worry too much about integer overflow lfs2_off_t npos = file->pos; if (whence == LFS2_SEEK_SET) { npos = off; } else if (whence == LFS2_SEEK_CUR) { - if ((lfs2_soff_t)file->pos + off < 0) { - return LFS2_ERR_INVAL; - } else { - npos = file->pos + off; - } + npos = file->pos + (lfs2_off_t)off; } else if (whence == LFS2_SEEK_END) { - lfs2_soff_t res = lfs2_file_rawsize(lfs2, file) + off; - if (res < 0) { - return LFS2_ERR_INVAL; - } else { - npos = res; - } + npos = (lfs2_off_t)lfs2_file_size_(lfs2, file) + (lfs2_off_t)off; } if (npos > lfs2->file_max) { @@ -3661,13 +3732,8 @@ static lfs2_soff_t lfs2_file_rawseek(lfs2_t *lfs2, lfs2_file_t *file, // if we're only reading and our new offset is still in the file's cache // we can avoid flushing and needing to reread the data - if ( -#ifndef LFS2_READONLY - !(file->flags & LFS2_F_WRITING) -#else - true -#endif - ) { + if ((file->flags & LFS2_F_READING) + && file->off != lfs2->cfg->block_size) { int oindex = lfs2_ctz_index(lfs2, &(lfs2_off_t){file->pos}); lfs2_off_t noff = npos; int nindex = lfs2_ctz_index(lfs2, &noff); @@ -3692,7 +3758,7 @@ static lfs2_soff_t lfs2_file_rawseek(lfs2_t *lfs2, lfs2_file_t *file, } #ifndef LFS2_READONLY -static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { +static int lfs2_file_truncate_(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { LFS2_ASSERT((file->flags & LFS2_O_WRONLY) == LFS2_O_WRONLY); if (size > LFS2_FILE_MAX) { @@ -3700,15 +3766,12 @@ static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t siz } lfs2_off_t pos = file->pos; - lfs2_off_t oldsize = lfs2_file_rawsize(lfs2, file); + lfs2_off_t oldsize = lfs2_file_size_(lfs2, file); if (size < oldsize) { // revert to inline file? - if (size <= lfs2_min(0x3fe, lfs2_min( - lfs2->cfg->cache_size, - (lfs2->cfg->metadata_max ? - lfs2->cfg->metadata_max : lfs2->cfg->block_size) / 8))) { + if (size <= lfs2->inline_max) { // flush+seek to head - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, 0, LFS2_SEEK_SET); + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, 0, LFS2_SEEK_SET); if (res < 0) { return (int)res; } @@ -3753,14 +3816,14 @@ static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t siz } } else if (size > oldsize) { // flush+seek if not already at end - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, 0, LFS2_SEEK_END); + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, 0, LFS2_SEEK_END); if (res < 0) { return (int)res; } // fill with zeros while (file->pos < size) { - res = lfs2_file_rawwrite(lfs2, file, &(uint8_t){0}, 1); + res = lfs2_file_write_(lfs2, file, &(uint8_t){0}, 1); if (res < 0) { return (int)res; } @@ -3768,7 +3831,7 @@ static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t siz } // restore pos - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, pos, LFS2_SEEK_SET); + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, pos, LFS2_SEEK_SET); if (res < 0) { return (int)res; } @@ -3777,13 +3840,13 @@ static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t siz } #endif -static lfs2_soff_t lfs2_file_rawtell(lfs2_t *lfs2, lfs2_file_t *file) { +static lfs2_soff_t lfs2_file_tell_(lfs2_t *lfs2, lfs2_file_t *file) { (void)lfs2; return file->pos; } -static int lfs2_file_rawrewind(lfs2_t *lfs2, lfs2_file_t *file) { - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, 0, LFS2_SEEK_SET); +static int lfs2_file_rewind_(lfs2_t *lfs2, lfs2_file_t *file) { + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, 0, LFS2_SEEK_SET); if (res < 0) { return (int)res; } @@ -3791,7 +3854,7 @@ static int lfs2_file_rawrewind(lfs2_t *lfs2, lfs2_file_t *file) { return 0; } -static lfs2_soff_t lfs2_file_rawsize(lfs2_t *lfs2, lfs2_file_t *file) { +static lfs2_soff_t lfs2_file_size_(lfs2_t *lfs2, lfs2_file_t *file) { (void)lfs2; #ifndef LFS2_READONLY @@ -3805,18 +3868,24 @@ static lfs2_soff_t lfs2_file_rawsize(lfs2_t *lfs2, lfs2_file_t *file) { /// General fs operations /// -static int lfs2_rawstat(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { +static int lfs2_stat_(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { lfs2_mdir_t cwd; lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); if (tag < 0) { return (int)tag; } + // only allow trailing slashes on dirs + if (strchr(path, '/') != NULL + && lfs2_tag_type3(tag) != LFS2_TYPE_DIR) { + return LFS2_ERR_NOTDIR; + } + return lfs2_dir_getinfo(lfs2, &cwd, lfs2_tag_id(tag), info); } #ifndef LFS2_READONLY -static int lfs2_rawremove(lfs2_t *lfs2, const char *path) { +static int lfs2_remove_(lfs2_t *lfs2, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs2_fs_forceconsistency(lfs2); if (err) { @@ -3872,7 +3941,9 @@ static int lfs2_rawremove(lfs2_t *lfs2, const char *path) { } lfs2->mlist = dir.next; - if (lfs2_tag_type3(tag) == LFS2_TYPE_DIR) { + if (lfs2_gstate_hasorphans(&lfs2->gstate)) { + LFS2_ASSERT(lfs2_tag_type3(tag) == LFS2_TYPE_DIR); + // fix orphan err = lfs2_fs_preporphans(lfs2, -1); if (err) { @@ -3895,7 +3966,7 @@ static int lfs2_rawremove(lfs2_t *lfs2, const char *path) { #endif #ifndef LFS2_READONLY -static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { +static int lfs2_rename_(lfs2_t *lfs2, const char *oldpath, const char *newpath) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs2_fs_forceconsistency(lfs2); if (err) { @@ -3914,7 +3985,7 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath uint16_t newid; lfs2_stag_t prevtag = lfs2_dir_find(lfs2, &newcwd, &newpath, &newid); if ((prevtag < 0 || lfs2_tag_id(prevtag) == 0x3ff) && - !(prevtag == LFS2_ERR_NOENT && newid != 0x3ff)) { + !(prevtag == LFS2_ERR_NOENT && lfs2_path_islast(newpath))) { return (prevtag < 0) ? (int)prevtag : LFS2_ERR_INVAL; } @@ -3925,8 +3996,14 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath struct lfs2_mlist prevdir; prevdir.next = lfs2->mlist; if (prevtag == LFS2_ERR_NOENT) { + // if we're a file, don't allow trailing slashes + if (lfs2_path_isdir(newpath) + && lfs2_tag_type3(oldtag) != LFS2_TYPE_DIR) { + return LFS2_ERR_NOTDIR; + } + // check that name fits - lfs2_size_t nlen = strlen(newpath); + lfs2_size_t nlen = lfs2_path_namelen(newpath); if (nlen > lfs2->name_max) { return LFS2_ERR_NAMETOOLONG; } @@ -3938,7 +4015,9 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath newoldid += 1; } } else if (lfs2_tag_type3(prevtag) != lfs2_tag_type3(oldtag)) { - return LFS2_ERR_ISDIR; + return (lfs2_tag_type3(prevtag) == LFS2_TYPE_DIR) + ? LFS2_ERR_ISDIR + : LFS2_ERR_NOTDIR; } else if (samepair && newid == newoldid) { // we're renaming to ourselves?? return 0; @@ -3984,7 +4063,8 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath {LFS2_MKTAG_IF(prevtag != LFS2_ERR_NOENT, LFS2_TYPE_DELETE, newid, 0), NULL}, {LFS2_MKTAG(LFS2_TYPE_CREATE, newid, 0), NULL}, - {LFS2_MKTAG(lfs2_tag_type3(oldtag), newid, strlen(newpath)), newpath}, + {LFS2_MKTAG(lfs2_tag_type3(oldtag), + newid, lfs2_path_namelen(newpath)), newpath}, {LFS2_MKTAG(LFS2_FROM_MOVE, newid, lfs2_tag_id(oldtag)), &oldcwd}, {LFS2_MKTAG_IF(samepair, LFS2_TYPE_DELETE, newoldid, 0), NULL})); @@ -4007,8 +4087,10 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath } lfs2->mlist = prevdir.next; - if (prevtag != LFS2_ERR_NOENT - && lfs2_tag_type3(prevtag) == LFS2_TYPE_DIR) { + if (lfs2_gstate_hasorphans(&lfs2->gstate)) { + LFS2_ASSERT(prevtag != LFS2_ERR_NOENT + && lfs2_tag_type3(prevtag) == LFS2_TYPE_DIR); + // fix orphan err = lfs2_fs_preporphans(lfs2, -1); if (err) { @@ -4030,7 +4112,7 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath } #endif -static lfs2_ssize_t lfs2_rawgetattr(lfs2_t *lfs2, const char *path, +static lfs2_ssize_t lfs2_getattr_(lfs2_t *lfs2, const char *path, uint8_t type, void *buffer, lfs2_size_t size) { lfs2_mdir_t cwd; lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); @@ -4088,7 +4170,7 @@ static int lfs2_commitattr(lfs2_t *lfs2, const char *path, #endif #ifndef LFS2_READONLY -static int lfs2_rawsetattr(lfs2_t *lfs2, const char *path, +static int lfs2_setattr_(lfs2_t *lfs2, const char *path, uint8_t type, const void *buffer, lfs2_size_t size) { if (size > lfs2->attr_max) { return LFS2_ERR_NOSPC; @@ -4099,13 +4181,28 @@ static int lfs2_rawsetattr(lfs2_t *lfs2, const char *path, #endif #ifndef LFS2_READONLY -static int lfs2_rawremoveattr(lfs2_t *lfs2, const char *path, uint8_t type) { +static int lfs2_removeattr_(lfs2_t *lfs2, const char *path, uint8_t type) { return lfs2_commitattr(lfs2, path, type, NULL, 0x3ff); } #endif /// Filesystem operations /// + +// compile time checks, see lfs2.h for why these limits exist +#if LFS2_NAME_MAX > 1022 +#error "Invalid LFS2_NAME_MAX, must be <= 1022" +#endif + +#if LFS2_FILE_MAX > 2147483647 +#error "Invalid LFS2_FILE_MAX, must be <= 2147483647" +#endif + +#if LFS2_ATTR_MAX > 1022 +#error "Invalid LFS2_ATTR_MAX, must be <= 1022" +#endif + +// common filesystem initialization static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { lfs2->cfg = cfg; lfs2->block_count = cfg->block_count; // May be 0 @@ -4126,6 +4223,14 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { // which littlefs currently does not support LFS2_ASSERT((bool)0x80000000); + // check that the required io functions are provided + LFS2_ASSERT(lfs2->cfg->read != NULL); +#ifndef LFS2_READONLY + LFS2_ASSERT(lfs2->cfg->prog != NULL); + LFS2_ASSERT(lfs2->cfg->erase != NULL); + LFS2_ASSERT(lfs2->cfg->sync != NULL); +#endif + // validate that the lfs2-cfg sizes were initiated properly before // performing any arithmetic logics with them LFS2_ASSERT(lfs2->cfg->read_size != 0); @@ -4153,6 +4258,23 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { // wear-leveling. LFS2_ASSERT(lfs2->cfg->block_cycles != 0); + // check that compact_thresh makes sense + // + // metadata can't be compacted below block_size/2, and metadata can't + // exceed a block_size + LFS2_ASSERT(lfs2->cfg->compact_thresh == 0 + || lfs2->cfg->compact_thresh >= lfs2->cfg->block_size/2); + LFS2_ASSERT(lfs2->cfg->compact_thresh == (lfs2_size_t)-1 + || lfs2->cfg->compact_thresh <= lfs2->cfg->block_size); + + // check that metadata_max is a multiple of read_size and prog_size, + // and a factor of the block_size + LFS2_ASSERT(!lfs2->cfg->metadata_max + || lfs2->cfg->metadata_max % lfs2->cfg->read_size == 0); + LFS2_ASSERT(!lfs2->cfg->metadata_max + || lfs2->cfg->metadata_max % lfs2->cfg->prog_size == 0); + LFS2_ASSERT(!lfs2->cfg->metadata_max + || lfs2->cfg->block_size % lfs2->cfg->metadata_max == 0); // setup read cache if (lfs2->cfg->read_buffer) { @@ -4180,15 +4302,14 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { lfs2_cache_zero(lfs2, &lfs2->rcache); lfs2_cache_zero(lfs2, &lfs2->pcache); - // setup lookahead, must be multiple of 64-bits, 32-bit aligned + // setup lookahead buffer, note mount finishes initializing this after + // we establish a decent pseudo-random seed LFS2_ASSERT(lfs2->cfg->lookahead_size > 0); - LFS2_ASSERT(lfs2->cfg->lookahead_size % 8 == 0 && - (uintptr_t)lfs2->cfg->lookahead_buffer % 4 == 0); if (lfs2->cfg->lookahead_buffer) { - lfs2->free.buffer = lfs2->cfg->lookahead_buffer; + lfs2->lookahead.buffer = lfs2->cfg->lookahead_buffer; } else { - lfs2->free.buffer = lfs2_malloc(lfs2->cfg->lookahead_size); - if (!lfs2->free.buffer) { + lfs2->lookahead.buffer = lfs2_malloc(lfs2->cfg->lookahead_size); + if (!lfs2->lookahead.buffer) { err = LFS2_ERR_NOMEM; goto cleanup; } @@ -4215,6 +4336,27 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { LFS2_ASSERT(lfs2->cfg->metadata_max <= lfs2->cfg->block_size); + LFS2_ASSERT(lfs2->cfg->inline_max == (lfs2_size_t)-1 + || lfs2->cfg->inline_max <= lfs2->cfg->cache_size); + LFS2_ASSERT(lfs2->cfg->inline_max == (lfs2_size_t)-1 + || lfs2->cfg->inline_max <= lfs2->attr_max); + LFS2_ASSERT(lfs2->cfg->inline_max == (lfs2_size_t)-1 + || lfs2->cfg->inline_max <= ((lfs2->cfg->metadata_max) + ? lfs2->cfg->metadata_max + : lfs2->cfg->block_size)/8); + lfs2->inline_max = lfs2->cfg->inline_max; + if (lfs2->inline_max == (lfs2_size_t)-1) { + lfs2->inline_max = 0; + } else if (lfs2->inline_max == 0) { + lfs2->inline_max = lfs2_min( + lfs2->cfg->cache_size, + lfs2_min( + lfs2->attr_max, + ((lfs2->cfg->metadata_max) + ? lfs2->cfg->metadata_max + : lfs2->cfg->block_size)/8)); + } + // setup default state lfs2->root[0] = LFS2_BLOCK_NULL; lfs2->root[1] = LFS2_BLOCK_NULL; @@ -4245,7 +4387,7 @@ static int lfs2_deinit(lfs2_t *lfs2) { } if (!lfs2->cfg->lookahead_buffer) { - lfs2_free(lfs2->free.buffer); + lfs2_free(lfs2->lookahead.buffer); } return 0; @@ -4254,7 +4396,7 @@ static int lfs2_deinit(lfs2_t *lfs2) { #ifndef LFS2_READONLY -static int lfs2_rawformat(lfs2_t *lfs2, const struct lfs2_config *cfg) { +static int lfs2_format_(lfs2_t *lfs2, const struct lfs2_config *cfg) { int err = 0; { err = lfs2_init(lfs2, cfg); @@ -4265,12 +4407,12 @@ static int lfs2_rawformat(lfs2_t *lfs2, const struct lfs2_config *cfg) { LFS2_ASSERT(cfg->block_count != 0); // create free lookahead - memset(lfs2->free.buffer, 0, lfs2->cfg->lookahead_size); - lfs2->free.off = 0; - lfs2->free.size = lfs2_min(8*lfs2->cfg->lookahead_size, + memset(lfs2->lookahead.buffer, 0, lfs2->cfg->lookahead_size); + lfs2->lookahead.start = 0; + lfs2->lookahead.size = lfs2_min(8*lfs2->cfg->lookahead_size, lfs2->block_count); - lfs2->free.i = 0; - lfs2_alloc_ack(lfs2); + lfs2->lookahead.next = 0; + lfs2_alloc_ckpoint(lfs2); // create root dir lfs2_mdir_t root; @@ -4321,7 +4463,31 @@ static int lfs2_rawformat(lfs2_t *lfs2, const struct lfs2_config *cfg) { } #endif -static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { +struct lfs2_tortoise_t { + lfs2_block_t pair[2]; + lfs2_size_t i; + lfs2_size_t period; +}; + +static int lfs2_tortoise_detectcycles( + const lfs2_mdir_t *dir, struct lfs2_tortoise_t *tortoise) { + // detect cycles with Brent's algorithm + if (lfs2_pair_issync(dir->tail, tortoise->pair)) { + LFS2_WARN("Cycle detected in tail list"); + return LFS2_ERR_CORRUPT; + } + if (tortoise->i == tortoise->period) { + tortoise->pair[0] = dir->tail[0]; + tortoise->pair[1] = dir->tail[1]; + tortoise->i = 0; + tortoise->period *= 2; + } + tortoise->i += 1; + + return LFS2_ERR_OK; +} + +static int lfs2_mount_(lfs2_t *lfs2, const struct lfs2_config *cfg) { int err = lfs2_init(lfs2, cfg); if (err) { return err; @@ -4329,23 +4495,16 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { // scan directory blocks for superblock and any global updates lfs2_mdir_t dir = {.tail = {0, 1}}; - lfs2_block_t tortoise[2] = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}; - lfs2_size_t tortoise_i = 1; - lfs2_size_t tortoise_period = 1; + struct lfs2_tortoise_t tortoise = { + .pair = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}, + .i = 1, + .period = 1, + }; while (!lfs2_pair_isnull(dir.tail)) { - // detect cycles with Brent's algorithm - if (lfs2_pair_issync(dir.tail, tortoise)) { - LFS2_WARN("Cycle detected in tail list"); - err = LFS2_ERR_CORRUPT; + err = lfs2_tortoise_detectcycles(&dir, &tortoise); + if (err < 0) { goto cleanup; } - if (tortoise_i == tortoise_period) { - tortoise[0] = dir.tail[0]; - tortoise[1] = dir.tail[1]; - tortoise_i = 0; - tortoise_period *= 2; - } - tortoise_i += 1; // fetch next block in tail list lfs2_stag_t tag = lfs2_dir_fetchmatch(lfs2, &dir, dir.tail, @@ -4394,6 +4553,7 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { // found older minor version? set an in-device only bit in the // gstate so we know we need to rewrite the superblock before // the first write + bool needssuperblock = false; if (minor_version < lfs2_fs_disk_version_minor(lfs2)) { LFS2_DEBUG("Found older minor version " "v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16, @@ -4401,10 +4561,11 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { minor_version, lfs2_fs_disk_version_major(lfs2), lfs2_fs_disk_version_minor(lfs2)); - // note this bit is reserved on disk, so fetching more gstate - // will not interfere here - lfs2_fs_prepsuperblock(lfs2, true); + needssuperblock = true; } + // note this bit is reserved on disk, so fetching more gstate + // will not interfere here + lfs2_fs_prepsuperblock(lfs2, needssuperblock); // check superblock configuration if (superblock.name_max) { @@ -4438,6 +4599,9 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { } lfs2->attr_max = superblock.attr_max; + + // we also need to update inline_max in case attr_max changed + lfs2->inline_max = lfs2_min(lfs2->inline_max, lfs2->attr_max); } // this is where we get the block_count from disk if block_count=0 @@ -4478,23 +4642,23 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { // setup free lookahead, to distribute allocations uniformly across // boots, we start the allocator at a random location - lfs2->free.off = lfs2->seed % lfs2->block_count; + lfs2->lookahead.start = lfs2->seed % lfs2->block_count; lfs2_alloc_drop(lfs2); return 0; cleanup: - lfs2_rawunmount(lfs2); + lfs2_unmount_(lfs2); return err; } -static int lfs2_rawunmount(lfs2_t *lfs2) { +static int lfs2_unmount_(lfs2_t *lfs2) { return lfs2_deinit(lfs2); } /// Filesystem filesystem operations /// -static int lfs2_fs_rawstat(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) { +static int lfs2_fs_stat_(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) { // if the superblock is up-to-date, we must be on the most recent // minor version of littlefs if (!lfs2_gstate_needssuperblock(&lfs2->gstate)) { @@ -4534,7 +4698,7 @@ static int lfs2_fs_rawstat(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) { return 0; } -int lfs2_fs_rawtraverse(lfs2_t *lfs2, +int lfs2_fs_traverse_(lfs2_t *lfs2, int (*cb)(void *data, lfs2_block_t block), void *data, bool includeorphans) { // iterate over metadata pairs @@ -4553,22 +4717,17 @@ int lfs2_fs_rawtraverse(lfs2_t *lfs2, } #endif - lfs2_block_t tortoise[2] = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}; - lfs2_size_t tortoise_i = 1; - lfs2_size_t tortoise_period = 1; + struct lfs2_tortoise_t tortoise = { + .pair = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}, + .i = 1, + .period = 1, + }; + int err = LFS2_ERR_OK; while (!lfs2_pair_isnull(dir.tail)) { - // detect cycles with Brent's algorithm - if (lfs2_pair_issync(dir.tail, tortoise)) { - LFS2_WARN("Cycle detected in tail list"); + err = lfs2_tortoise_detectcycles(&dir, &tortoise); + if (err < 0) { return LFS2_ERR_CORRUPT; } - if (tortoise_i == tortoise_period) { - tortoise[0] = dir.tail[0]; - tortoise[1] = dir.tail[1]; - tortoise_i = 0; - tortoise_period *= 2; - } - tortoise_i += 1; for (int i = 0; i < 2; i++) { int err = cb(data, dir.tail[i]); @@ -4620,7 +4779,8 @@ int lfs2_fs_rawtraverse(lfs2_t *lfs2, continue; } - if ((f->flags & LFS2_F_DIRTY) && !(f->flags & LFS2_F_INLINE)) { + if (((f->flags & LFS2_F_DIRTY) || (f->flags & LFS2_F_DUSTY)) + && !(f->flags & LFS2_F_INLINE)) { int err = lfs2_ctz_traverse(lfs2, &f->cache, &lfs2->rcache, f->ctz.head, f->ctz.size, cb, data); if (err) { @@ -4647,22 +4807,17 @@ static int lfs2_fs_pred(lfs2_t *lfs2, // iterate over all directory directory entries pdir->tail[0] = 0; pdir->tail[1] = 1; - lfs2_block_t tortoise[2] = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}; - lfs2_size_t tortoise_i = 1; - lfs2_size_t tortoise_period = 1; + struct lfs2_tortoise_t tortoise = { + .pair = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}, + .i = 1, + .period = 1, + }; + int err = LFS2_ERR_OK; while (!lfs2_pair_isnull(pdir->tail)) { - // detect cycles with Brent's algorithm - if (lfs2_pair_issync(pdir->tail, tortoise)) { - LFS2_WARN("Cycle detected in tail list"); + err = lfs2_tortoise_detectcycles(pdir, &tortoise); + if (err < 0) { return LFS2_ERR_CORRUPT; } - if (tortoise_i == tortoise_period) { - tortoise[0] = pdir->tail[0]; - tortoise[1] = pdir->tail[1]; - tortoise_i = 0; - tortoise_period *= 2; - } - tortoise_i += 1; if (lfs2_pair_cmp(pdir->tail, pair) == 0) { return 0; @@ -4712,22 +4867,17 @@ static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t pair[2], // use fetchmatch with callback to find pairs parent->tail[0] = 0; parent->tail[1] = 1; - lfs2_block_t tortoise[2] = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}; - lfs2_size_t tortoise_i = 1; - lfs2_size_t tortoise_period = 1; + struct lfs2_tortoise_t tortoise = { + .pair = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}, + .i = 1, + .period = 1, + }; + int err = LFS2_ERR_OK; while (!lfs2_pair_isnull(parent->tail)) { - // detect cycles with Brent's algorithm - if (lfs2_pair_issync(parent->tail, tortoise)) { - LFS2_WARN("Cycle detected in tail list"); - return LFS2_ERR_CORRUPT; - } - if (tortoise_i == tortoise_period) { - tortoise[0] = parent->tail[0]; - tortoise[1] = parent->tail[1]; - tortoise_i = 0; - tortoise_period *= 2; + err = lfs2_tortoise_detectcycles(parent, &tortoise); + if (err < 0) { + return err; } - tortoise_i += 1; lfs2_stag_t tag = lfs2_dir_fetchmatch(lfs2, parent, parent->tail, LFS2_MKTAG(0x7ff, 0, 0x3ff), @@ -4999,7 +5149,7 @@ static int lfs2_fs_forceconsistency(lfs2_t *lfs2) { #endif #ifndef LFS2_READONLY -static int lfs2_fs_rawmkconsistent(lfs2_t *lfs2) { +static int lfs2_fs_mkconsistent_(lfs2_t *lfs2) { // lfs2_fs_forceconsistency does most of the work here int err = lfs2_fs_forceconsistency(lfs2); if (err) { @@ -5035,9 +5185,9 @@ static int lfs2_fs_size_count(void *p, lfs2_block_t block) { return 0; } -static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2) { +static lfs2_ssize_t lfs2_fs_size_(lfs2_t *lfs2) { lfs2_size_t size = 0; - int err = lfs2_fs_rawtraverse(lfs2, lfs2_fs_size_count, &size, false); + int err = lfs2_fs_traverse_(lfs2, lfs2_fs_size_count, &size, false); if (err) { return err; } @@ -5045,41 +5195,118 @@ static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2) { return size; } +// explicit garbage collection #ifndef LFS2_READONLY -static int lfs2_fs_rawgrow(lfs2_t *lfs2, lfs2_size_t block_count) { - // shrinking is not supported - LFS2_ASSERT(block_count >= lfs2->block_count); +static int lfs2_fs_gc_(lfs2_t *lfs2) { + // force consistency, even if we're not necessarily going to write, + // because this function is supposed to take care of janitorial work + // isn't it? + int err = lfs2_fs_forceconsistency(lfs2); + if (err) { + return err; + } + + // try to compact metadata pairs, note we can't really accomplish + // anything if compact_thresh doesn't at least leave a prog_size + // available + if (lfs2->cfg->compact_thresh + < lfs2->cfg->block_size - lfs2->cfg->prog_size) { + // iterate over all mdirs + lfs2_mdir_t mdir = {.tail = {0, 1}}; + while (!lfs2_pair_isnull(mdir.tail)) { + err = lfs2_dir_fetch(lfs2, &mdir, mdir.tail); + if (err) { + return err; + } - if (block_count > lfs2->block_count) { - lfs2->block_count = block_count; + // not erased? exceeds our compaction threshold? + if (!mdir.erased || ((lfs2->cfg->compact_thresh == 0) + ? mdir.off > lfs2->cfg->block_size - lfs2->cfg->block_size/8 + : mdir.off > lfs2->cfg->compact_thresh)) { + // the easiest way to trigger a compaction is to mark + // the mdir as unerased and add an empty commit + mdir.erased = false; + err = lfs2_dir_commit(lfs2, &mdir, NULL, 0); + if (err) { + return err; + } + } + } + } - // fetch the root - lfs2_mdir_t root; - int err = lfs2_dir_fetch(lfs2, &root, lfs2->root); + // try to populate the lookahead buffer, unless it's already full + if (lfs2->lookahead.size < lfs2_min( + 8 * lfs2->cfg->lookahead_size, + lfs2->block_count)) { + err = lfs2_alloc_scan(lfs2); if (err) { return err; } + } - // update the superblock - lfs2_superblock_t superblock; - lfs2_stag_t tag = lfs2_dir_get(lfs2, &root, LFS2_MKTAG(0x7ff, 0x3ff, 0), - LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)), - &superblock); - if (tag < 0) { - return tag; - } - lfs2_superblock_fromle32(&superblock); + return 0; +} +#endif - superblock.block_count = lfs2->block_count; +#ifndef LFS2_READONLY +#ifdef LFS2_SHRINKNONRELOCATING +static int lfs2_shrink_checkblock(void *data, lfs2_block_t block) { + lfs2_size_t threshold = *((lfs2_size_t*)data); + if (block >= threshold) { + return LFS2_ERR_NOTEMPTY; + } + return 0; +} +#endif - lfs2_superblock_tole32(&superblock); - err = lfs2_dir_commit(lfs2, &root, LFS2_MKATTRS( - {tag, &superblock})); +static int lfs2_fs_grow_(lfs2_t *lfs2, lfs2_size_t block_count) { + int err; + + if (block_count == lfs2->block_count) { + return 0; + } + + +#ifndef LFS2_SHRINKNONRELOCATING + // shrinking is not supported + LFS2_ASSERT(block_count >= lfs2->block_count); +#endif +#ifdef LFS2_SHRINKNONRELOCATING + if (block_count < lfs2->block_count) { + err = lfs2_fs_traverse_(lfs2, lfs2_shrink_checkblock, &block_count, true); if (err) { return err; } } +#endif + + lfs2->block_count = block_count; + + // fetch the root + lfs2_mdir_t root; + err = lfs2_dir_fetch(lfs2, &root, lfs2->root); + if (err) { + return err; + } + // update the superblock + lfs2_superblock_t superblock; + lfs2_stag_t tag = lfs2_dir_get(lfs2, &root, LFS2_MKTAG(0x7ff, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock); + if (tag < 0) { + return tag; + } + lfs2_superblock_fromle32(&superblock); + + superblock.block_count = lfs2->block_count; + + lfs2_superblock_tole32(&superblock); + err = lfs2_dir_commit(lfs2, &root, LFS2_MKATTRS( + {tag, &superblock})); + if (err) { + return err; + } return 0; } #endif @@ -5451,10 +5678,10 @@ static int lfs21_mount(lfs2_t *lfs2, struct lfs21 *lfs21, lfs2->lfs21->root[1] = LFS2_BLOCK_NULL; // setup free lookahead - lfs2->free.off = 0; - lfs2->free.size = 0; - lfs2->free.i = 0; - lfs2_alloc_ack(lfs2); + lfs2->lookahead.start = 0; + lfs2->lookahead.size = 0; + lfs2->lookahead.next = 0; + lfs2_alloc_ckpoint(lfs2); // load superblock lfs21_dir_t dir; @@ -5505,7 +5732,7 @@ static int lfs21_unmount(lfs2_t *lfs2) { } /// v1 migration /// -static int lfs2_rawmigrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { +static int lfs2_migrate_(lfs2_t *lfs2, const struct lfs2_config *cfg) { struct lfs21 lfs21; // Indeterminate filesystem size not allowed for migration. @@ -5759,7 +5986,7 @@ int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *cfg) { ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".block_cycles=%"PRId32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " ".name_max=%"PRIu32", .file_max=%"PRIu32", " @@ -5772,7 +5999,7 @@ int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *cfg) { cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, cfg->name_max, cfg->file_max, cfg->attr_max); - err = lfs2_rawformat(lfs2, cfg); + err = lfs2_format_(lfs2, cfg); LFS2_TRACE("lfs2_format -> %d", err); LFS2_UNLOCK(cfg); @@ -5789,7 +6016,7 @@ int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *cfg) { ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".block_cycles=%"PRId32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " ".name_max=%"PRIu32", .file_max=%"PRIu32", " @@ -5802,7 +6029,7 @@ int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *cfg) { cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, cfg->name_max, cfg->file_max, cfg->attr_max); - err = lfs2_rawmount(lfs2, cfg); + err = lfs2_mount_(lfs2, cfg); LFS2_TRACE("lfs2_mount -> %d", err); LFS2_UNLOCK(cfg); @@ -5816,7 +6043,7 @@ int lfs2_unmount(lfs2_t *lfs2) { } LFS2_TRACE("lfs2_unmount(%p)", (void*)lfs2); - err = lfs2_rawunmount(lfs2); + err = lfs2_unmount_(lfs2); LFS2_TRACE("lfs2_unmount -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5831,7 +6058,7 @@ int lfs2_remove(lfs2_t *lfs2, const char *path) { } LFS2_TRACE("lfs2_remove(%p, \"%s\")", (void*)lfs2, path); - err = lfs2_rawremove(lfs2, path); + err = lfs2_remove_(lfs2, path); LFS2_TRACE("lfs2_remove -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5847,7 +6074,7 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { } LFS2_TRACE("lfs2_rename(%p, \"%s\", \"%s\")", (void*)lfs2, oldpath, newpath); - err = lfs2_rawrename(lfs2, oldpath, newpath); + err = lfs2_rename_(lfs2, oldpath, newpath); LFS2_TRACE("lfs2_rename -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5862,7 +6089,7 @@ int lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { } LFS2_TRACE("lfs2_stat(%p, \"%s\", %p)", (void*)lfs2, path, (void*)info); - err = lfs2_rawstat(lfs2, path, info); + err = lfs2_stat_(lfs2, path, info); LFS2_TRACE("lfs2_stat -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5878,7 +6105,7 @@ lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, LFS2_TRACE("lfs2_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", (void*)lfs2, path, type, buffer, size); - lfs2_ssize_t res = lfs2_rawgetattr(lfs2, path, type, buffer, size); + lfs2_ssize_t res = lfs2_getattr_(lfs2, path, type, buffer, size); LFS2_TRACE("lfs2_getattr -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -5895,7 +6122,7 @@ int lfs2_setattr(lfs2_t *lfs2, const char *path, LFS2_TRACE("lfs2_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", (void*)lfs2, path, type, buffer, size); - err = lfs2_rawsetattr(lfs2, path, type, buffer, size); + err = lfs2_setattr_(lfs2, path, type, buffer, size); LFS2_TRACE("lfs2_setattr -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5911,7 +6138,7 @@ int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type) { } LFS2_TRACE("lfs2_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs2, path, type); - err = lfs2_rawremoveattr(lfs2, path, type); + err = lfs2_removeattr_(lfs2, path, type); LFS2_TRACE("lfs2_removeattr -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5926,10 +6153,10 @@ int lfs2_file_open(lfs2_t *lfs2, lfs2_file_t *file, const char *path, int flags) return err; } LFS2_TRACE("lfs2_file_open(%p, %p, \"%s\", %x)", - (void*)lfs2, (void*)file, path, flags); + (void*)lfs2, (void*)file, path, (unsigned)flags); LFS2_ASSERT(!lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawopen(lfs2, file, path, flags); + err = lfs2_file_open_(lfs2, file, path, flags); LFS2_TRACE("lfs2_file_open -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5946,11 +6173,11 @@ int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, } LFS2_TRACE("lfs2_file_opencfg(%p, %p, \"%s\", %x, %p {" ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", - (void*)lfs2, (void*)file, path, flags, + (void*)lfs2, (void*)file, path, (unsigned)flags, (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); LFS2_ASSERT(!lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawopencfg(lfs2, file, path, flags, cfg); + err = lfs2_file_opencfg_(lfs2, file, path, flags, cfg); LFS2_TRACE("lfs2_file_opencfg -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5965,7 +6192,7 @@ int lfs2_file_close(lfs2_t *lfs2, lfs2_file_t *file) { LFS2_TRACE("lfs2_file_close(%p, %p)", (void*)lfs2, (void*)file); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawclose(lfs2, file); + err = lfs2_file_close_(lfs2, file); LFS2_TRACE("lfs2_file_close -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5981,7 +6208,7 @@ int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file) { LFS2_TRACE("lfs2_file_sync(%p, %p)", (void*)lfs2, (void*)file); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawsync(lfs2, file); + err = lfs2_file_sync_(lfs2, file); LFS2_TRACE("lfs2_file_sync -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5999,7 +6226,7 @@ lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, (void*)lfs2, (void*)file, buffer, size); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_ssize_t res = lfs2_file_rawread(lfs2, file, buffer, size); + lfs2_ssize_t res = lfs2_file_read_(lfs2, file, buffer, size); LFS2_TRACE("lfs2_file_read -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6017,7 +6244,7 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, (void*)lfs2, (void*)file, buffer, size); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_ssize_t res = lfs2_file_rawwrite(lfs2, file, buffer, size); + lfs2_ssize_t res = lfs2_file_write_(lfs2, file, buffer, size); LFS2_TRACE("lfs2_file_write -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6035,7 +6262,7 @@ lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, (void*)lfs2, (void*)file, off, whence); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, off, whence); + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, off, whence); LFS2_TRACE("lfs2_file_seek -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6052,7 +6279,7 @@ int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { (void*)lfs2, (void*)file, size); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawtruncate(lfs2, file, size); + err = lfs2_file_truncate_(lfs2, file, size); LFS2_TRACE("lfs2_file_truncate -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6068,7 +6295,7 @@ lfs2_soff_t lfs2_file_tell(lfs2_t *lfs2, lfs2_file_t *file) { LFS2_TRACE("lfs2_file_tell(%p, %p)", (void*)lfs2, (void*)file); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_soff_t res = lfs2_file_rawtell(lfs2, file); + lfs2_soff_t res = lfs2_file_tell_(lfs2, file); LFS2_TRACE("lfs2_file_tell -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6082,7 +6309,7 @@ int lfs2_file_rewind(lfs2_t *lfs2, lfs2_file_t *file) { } LFS2_TRACE("lfs2_file_rewind(%p, %p)", (void*)lfs2, (void*)file); - err = lfs2_file_rawrewind(lfs2, file); + err = lfs2_file_rewind_(lfs2, file); LFS2_TRACE("lfs2_file_rewind -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6097,9 +6324,9 @@ lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file) { LFS2_TRACE("lfs2_file_size(%p, %p)", (void*)lfs2, (void*)file); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_soff_t res = lfs2_file_rawsize(lfs2, file); + lfs2_soff_t res = lfs2_file_size_(lfs2, file); - LFS2_TRACE("lfs2_file_size -> %"PRId32, res); + LFS2_TRACE("lfs2_file_size -> %"PRIu32, res); LFS2_UNLOCK(lfs2->cfg); return res; } @@ -6112,7 +6339,7 @@ int lfs2_mkdir(lfs2_t *lfs2, const char *path) { } LFS2_TRACE("lfs2_mkdir(%p, \"%s\")", (void*)lfs2, path); - err = lfs2_rawmkdir(lfs2, path); + err = lfs2_mkdir_(lfs2, path); LFS2_TRACE("lfs2_mkdir -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6128,7 +6355,7 @@ int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { LFS2_TRACE("lfs2_dir_open(%p, %p, \"%s\")", (void*)lfs2, (void*)dir, path); LFS2_ASSERT(!lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)dir)); - err = lfs2_dir_rawopen(lfs2, dir, path); + err = lfs2_dir_open_(lfs2, dir, path); LFS2_TRACE("lfs2_dir_open -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6142,7 +6369,7 @@ int lfs2_dir_close(lfs2_t *lfs2, lfs2_dir_t *dir) { } LFS2_TRACE("lfs2_dir_close(%p, %p)", (void*)lfs2, (void*)dir); - err = lfs2_dir_rawclose(lfs2, dir); + err = lfs2_dir_close_(lfs2, dir); LFS2_TRACE("lfs2_dir_close -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6157,7 +6384,7 @@ int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { LFS2_TRACE("lfs2_dir_read(%p, %p, %p)", (void*)lfs2, (void*)dir, (void*)info); - err = lfs2_dir_rawread(lfs2, dir, info); + err = lfs2_dir_read_(lfs2, dir, info); LFS2_TRACE("lfs2_dir_read -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6172,7 +6399,7 @@ int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { LFS2_TRACE("lfs2_dir_seek(%p, %p, %"PRIu32")", (void*)lfs2, (void*)dir, off); - err = lfs2_dir_rawseek(lfs2, dir, off); + err = lfs2_dir_seek_(lfs2, dir, off); LFS2_TRACE("lfs2_dir_seek -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6186,7 +6413,7 @@ lfs2_soff_t lfs2_dir_tell(lfs2_t *lfs2, lfs2_dir_t *dir) { } LFS2_TRACE("lfs2_dir_tell(%p, %p)", (void*)lfs2, (void*)dir); - lfs2_soff_t res = lfs2_dir_rawtell(lfs2, dir); + lfs2_soff_t res = lfs2_dir_tell_(lfs2, dir); LFS2_TRACE("lfs2_dir_tell -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6200,7 +6427,7 @@ int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir) { } LFS2_TRACE("lfs2_dir_rewind(%p, %p)", (void*)lfs2, (void*)dir); - err = lfs2_dir_rawrewind(lfs2, dir); + err = lfs2_dir_rewind_(lfs2, dir); LFS2_TRACE("lfs2_dir_rewind -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6214,7 +6441,7 @@ int lfs2_fs_stat(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) { } LFS2_TRACE("lfs2_fs_stat(%p, %p)", (void*)lfs2, (void*)fsinfo); - err = lfs2_fs_rawstat(lfs2, fsinfo); + err = lfs2_fs_stat_(lfs2, fsinfo); LFS2_TRACE("lfs2_fs_stat -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6228,7 +6455,7 @@ lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2) { } LFS2_TRACE("lfs2_fs_size(%p)", (void*)lfs2); - lfs2_ssize_t res = lfs2_fs_rawsize(lfs2); + lfs2_ssize_t res = lfs2_fs_size_(lfs2); LFS2_TRACE("lfs2_fs_size -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6243,7 +6470,7 @@ int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void *, lfs2_block_t), void *data) LFS2_TRACE("lfs2_fs_traverse(%p, %p, %p)", (void*)lfs2, (void*)(uintptr_t)cb, data); - err = lfs2_fs_rawtraverse(lfs2, cb, data, true); + err = lfs2_fs_traverse_(lfs2, cb, data, true); LFS2_TRACE("lfs2_fs_traverse -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6251,32 +6478,32 @@ int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void *, lfs2_block_t), void *data) } #ifndef LFS2_READONLY -int lfs2_fs_gc(lfs2_t *lfs2) { +int lfs2_fs_mkconsistent(lfs2_t *lfs2) { int err = LFS2_LOCK(lfs2->cfg); if (err) { return err; } - LFS2_TRACE("lfs2_fs_gc(%p)", (void*)lfs2); + LFS2_TRACE("lfs2_fs_mkconsistent(%p)", (void*)lfs2); - err = lfs2_fs_rawgc(lfs2); + err = lfs2_fs_mkconsistent_(lfs2); - LFS2_TRACE("lfs2_fs_gc -> %d", err); + LFS2_TRACE("lfs2_fs_mkconsistent -> %d", err); LFS2_UNLOCK(lfs2->cfg); return err; } #endif #ifndef LFS2_READONLY -int lfs2_fs_mkconsistent(lfs2_t *lfs2) { +int lfs2_fs_gc(lfs2_t *lfs2) { int err = LFS2_LOCK(lfs2->cfg); if (err) { return err; } - LFS2_TRACE("lfs2_fs_mkconsistent(%p)", (void*)lfs2); + LFS2_TRACE("lfs2_fs_gc(%p)", (void*)lfs2); - err = lfs2_fs_rawmkconsistent(lfs2); + err = lfs2_fs_gc_(lfs2); - LFS2_TRACE("lfs2_fs_mkconsistent -> %d", err); + LFS2_TRACE("lfs2_fs_gc -> %d", err); LFS2_UNLOCK(lfs2->cfg); return err; } @@ -6290,7 +6517,7 @@ int lfs2_fs_grow(lfs2_t *lfs2, lfs2_size_t block_count) { } LFS2_TRACE("lfs2_fs_grow(%p, %"PRIu32")", (void*)lfs2, block_count); - err = lfs2_fs_rawgrow(lfs2, block_count); + err = lfs2_fs_grow_(lfs2, block_count); LFS2_TRACE("lfs2_fs_grow -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6308,7 +6535,7 @@ int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".block_cycles=%"PRId32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " ".name_max=%"PRIu32", .file_max=%"PRIu32", " @@ -6321,7 +6548,7 @@ int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, cfg->name_max, cfg->file_max, cfg->attr_max); - err = lfs2_rawmigrate(lfs2, cfg); + err = lfs2_migrate_(lfs2, cfg); LFS2_TRACE("lfs2_migrate -> %d", err); LFS2_UNLOCK(cfg); diff --git a/lib/littlefs/lfs2.h b/lib/littlefs/lfs2.h index 559ccebac92..53f2a1569ee 100644 --- a/lib/littlefs/lfs2.h +++ b/lib/littlefs/lfs2.h @@ -21,7 +21,7 @@ extern "C" // Software library version // Major (top-nibble), incremented on backwards incompatible changes // Minor (bottom-nibble), incremented on feature additions -#define LFS2_VERSION 0x00020008 +#define LFS2_VERSION 0x0002000b #define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16)) #define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0)) @@ -52,16 +52,15 @@ typedef uint32_t lfs2_block_t; #endif // Maximum size of a file in bytes, may be redefined to limit to support other -// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the -// functions lfs2_file_seek, lfs2_file_size, and lfs2_file_tell will return -// incorrect values due to using signed integers. Stored in superblock and -// must be respected by other littlefs drivers. +// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be +// respected by other littlefs drivers. #ifndef LFS2_FILE_MAX #define LFS2_FILE_MAX 2147483647 #endif // Maximum size of custom attributes in bytes, may be redefined, but there is -// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022. +// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022. Stored +// in superblock and must be respected by other littlefs drivers. #ifndef LFS2_ATTR_MAX #define LFS2_ATTR_MAX 1022 #endif @@ -136,14 +135,15 @@ enum lfs2_open_flags { // internally used flags #ifndef LFS2_READONLY - LFS2_F_DIRTY = 0x010000, // File does not match storage - LFS2_F_WRITING = 0x020000, // File has been written since last flush + LFS2_F_DIRTY = 0x00010000, // File does not match storage due to write + LFS2_F_DUSTY = 0x00020000, // File does not match storage due to desync + LFS2_F_WRITING = 0x00040000, // File has been written since last flush #endif - LFS2_F_READING = 0x040000, // File has been read since last flush + LFS2_F_READING = 0x00080000, // File has been read since last flush #ifndef LFS2_READONLY - LFS2_F_ERRED = 0x080000, // An error occurred during write + LFS2_F_ERRED = 0x00100000, // An error occurred during write #endif - LFS2_F_INLINE = 0x100000, // Currently inlined in directory entry + LFS2_F_INLINE = 0x01000000, // Currently inlined in directory entry }; // File seek flags @@ -205,7 +205,8 @@ struct lfs2_config { // program sizes. lfs2_size_t block_size; - // Number of erasable blocks on the device. + // Number of erasable blocks on the device. Defaults to block_count stored + // on disk when zero. lfs2_size_t block_count; // Number of erase cycles before littlefs evicts metadata logs and moves @@ -226,9 +227,20 @@ struct lfs2_config { // Size of the lookahead buffer in bytes. A larger lookahead buffer // increases the number of blocks found during an allocation pass. The // lookahead buffer is stored as a compact bitmap, so each byte of RAM - // can track 8 blocks. Must be a multiple of 8. + // can track 8 blocks. lfs2_size_t lookahead_size; + // Threshold for metadata compaction during lfs2_fs_gc in bytes. Metadata + // pairs that exceed this threshold will be compacted during lfs2_fs_gc. + // Defaults to ~88% block_size when zero, though the default may change + // in the future. + // + // Note this only affects lfs2_fs_gc. Normal compactions still only occur + // when full. + // + // Set to -1 to disable metadata compaction during lfs2_fs_gc. + lfs2_size_t compact_thresh; + // Optional statically allocated read buffer. Must be cache_size. // By default lfs2_malloc is used to allocate this buffer. void *read_buffer; @@ -237,25 +249,24 @@ struct lfs2_config { // By default lfs2_malloc is used to allocate this buffer. void *prog_buffer; - // Optional statically allocated lookahead buffer. Must be lookahead_size - // and aligned to a 32-bit boundary. By default lfs2_malloc is used to - // allocate this buffer. + // Optional statically allocated lookahead buffer. Must be lookahead_size. + // By default lfs2_malloc is used to allocate this buffer. void *lookahead_buffer; // Optional upper limit on length of file names in bytes. No downside for // larger names except the size of the info struct which is controlled by - // the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX when zero. Stored in - // superblock and must be respected by other littlefs drivers. + // the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX or name_max stored on + // disk when zero. lfs2_size_t name_max; // Optional upper limit on files in bytes. No downside for larger files - // but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX when zero. Stored - // in superblock and must be respected by other littlefs drivers. + // but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX or file_max stored + // on disk when zero. lfs2_size_t file_max; // Optional upper limit on custom attributes in bytes. No downside for // larger attributes size but must be <= LFS2_ATTR_MAX. Defaults to - // LFS2_ATTR_MAX when zero. + // LFS2_ATTR_MAX or attr_max stored on disk when zero. lfs2_size_t attr_max; // Optional upper limit on total space given to metadata pairs in bytes. On @@ -264,6 +275,15 @@ struct lfs2_config { // Defaults to block_size when zero. lfs2_size_t metadata_max; + // Optional upper limit on inlined files in bytes. Inlined files live in + // metadata and decrease storage requirements, but may be limited to + // improve metadata-related performance. Must be <= cache_size, <= + // attr_max, and <= block_size/8. Defaults to the largest possible + // inline_max when zero. + // + // Set to -1 to disable inlined files. + lfs2_size_t inline_max; + #ifdef LFS2_MULTIVERSION // On-disk version to use when writing in the form of 16-bit major version // + 16-bit minor version. This limiting metadata to what is supported by @@ -430,19 +450,20 @@ typedef struct lfs2 { lfs2_gstate_t gdisk; lfs2_gstate_t gdelta; - struct lfs2_free { - lfs2_block_t off; + struct lfs2_lookahead { + lfs2_block_t start; lfs2_block_t size; - lfs2_block_t i; - lfs2_block_t ack; - uint32_t *buffer; - } free; + lfs2_block_t next; + lfs2_block_t ckpoint; + uint8_t *buffer; + } lookahead; const struct lfs2_config *cfg; lfs2_size_t block_count; lfs2_size_t name_max; lfs2_size_t file_max; lfs2_size_t attr_max; + lfs2_size_t inline_max; #ifdef LFS2_MIGRATE struct lfs21 *lfs21; @@ -712,18 +733,6 @@ lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2); // Returns a negative error code on failure. int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); -// Attempt to proactively find free blocks -// -// Calling this function is not required, but may allowing the offloading of -// the expensive block allocation scan to a less time-critical code path. -// -// Note: littlefs currently does not persist any found free blocks to disk. -// This may change in the future. -// -// Returns a negative error code on failure. Finding no free blocks is -// not an error. -int lfs2_fs_gc(lfs2_t *lfs2); - #ifndef LFS2_READONLY // Attempt to make the filesystem consistent and ready for writing // @@ -736,11 +745,33 @@ int lfs2_fs_gc(lfs2_t *lfs2); int lfs2_fs_mkconsistent(lfs2_t *lfs2); #endif +#ifndef LFS2_READONLY +// Attempt any janitorial work +// +// This currently: +// 1. Calls mkconsistent if not already consistent +// 2. Compacts metadata > compact_thresh +// 3. Populates the block allocator +// +// Though additional janitorial work may be added in the future. +// +// Calling this function is not required, but may allow the offloading of +// expensive janitorial work to a less time-critical code path. +// +// Returns a negative error code on failure. Accomplishing nothing is not +// an error. +int lfs2_fs_gc(lfs2_t *lfs2); +#endif + #ifndef LFS2_READONLY // Grows the filesystem to a new size, updating the superblock with the new // block count. // -// Note: This is irreversible. +// If LFS2_SHRINKNONRELOCATING is defined, this function will also accept +// block_counts smaller than the current configuration, after checking +// that none of the blocks that are being removed are in use. +// Note that littlefs's pseudorandom block allocation means that +// this is very unlikely to work in the general case. // // Returns a negative error code on failure. int lfs2_fs_grow(lfs2_t *lfs2, lfs2_size_t block_count); diff --git a/lib/littlefs/lfs2_util.c b/lib/littlefs/lfs2_util.c index c9850e78869..4fe7e5340ce 100644 --- a/lib/littlefs/lfs2_util.c +++ b/lib/littlefs/lfs2_util.c @@ -11,6 +11,8 @@ #ifndef LFS2_CONFIG +// If user provides their own CRC impl we don't need this +#ifndef LFS2_CRC // Software CRC implementation with small lookup table uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) { static const uint32_t rtable[16] = { @@ -29,6 +31,7 @@ uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) { return crc; } +#endif #endif diff --git a/lib/littlefs/lfs2_util.h b/lib/littlefs/lfs2_util.h index dd2cbcc106d..12c82a630b0 100644 --- a/lib/littlefs/lfs2_util.h +++ b/lib/littlefs/lfs2_util.h @@ -8,6 +8,9 @@ #ifndef LFS2_UTIL_H #define LFS2_UTIL_H +#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x) +#define LFS2_STRINGIZE2(x) #x + // Users can override lfs2_util.h with their own configuration by defining // LFS2_CONFIG as a header file to include (-DLFS2_CONFIG=lfs2_config.h). // @@ -15,11 +18,26 @@ // provided by the config file. To start, I would suggest copying lfs2_util.h // and modifying as needed. #ifdef LFS2_CONFIG -#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x) -#define LFS2_STRINGIZE2(x) #x #include LFS2_STRINGIZE(LFS2_CONFIG) #else +// Alternatively, users can provide a header file which defines +// macros and other things consumed by littlefs. +// +// For example, provide my_defines.h, which contains +// something like: +// +// #include +// extern void *my_malloc(size_t sz); +// #define LFS2_MALLOC(sz) my_malloc(sz) +// +// And build littlefs with the header by defining LFS2_DEFINES. +// (-DLFS2_DEFINES=my_defines.h) + +#ifdef LFS2_DEFINES +#include LFS2_STRINGIZE(LFS2_DEFINES) +#endif + // System includes #include #include @@ -177,10 +195,10 @@ static inline uint32_t lfs2_fromle32(uint32_t a) { (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) return __builtin_bswap32(a); #else - return (((uint8_t*)&a)[0] << 0) | - (((uint8_t*)&a)[1] << 8) | - (((uint8_t*)&a)[2] << 16) | - (((uint8_t*)&a)[3] << 24); + return ((uint32_t)((uint8_t*)&a)[0] << 0) | + ((uint32_t)((uint8_t*)&a)[1] << 8) | + ((uint32_t)((uint8_t*)&a)[2] << 16) | + ((uint32_t)((uint8_t*)&a)[3] << 24); #endif } @@ -200,10 +218,10 @@ static inline uint32_t lfs2_frombe32(uint32_t a) { (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) return a; #else - return (((uint8_t*)&a)[0] << 24) | - (((uint8_t*)&a)[1] << 16) | - (((uint8_t*)&a)[2] << 8) | - (((uint8_t*)&a)[3] << 0); + return ((uint32_t)((uint8_t*)&a)[0] << 24) | + ((uint32_t)((uint8_t*)&a)[1] << 16) | + ((uint32_t)((uint8_t*)&a)[2] << 8) | + ((uint32_t)((uint8_t*)&a)[3] << 0); #endif } @@ -212,12 +230,22 @@ static inline uint32_t lfs2_tobe32(uint32_t a) { } // Calculate CRC-32 with polynomial = 0x04c11db7 +#ifdef LFS2_CRC +static inline uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) { + return LFS2_CRC(crc, buffer, size); +} +#else uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size); +#endif // Allocate memory, only used if buffers are not provided to littlefs -// Note, memory must be 64-bit aligned +// +// littlefs current has no alignment requirements, as it only allocates +// byte-level buffers. static inline void *lfs2_malloc(size_t size) { -#ifndef LFS2_NO_MALLOC +#if defined(LFS2_MALLOC) + return LFS2_MALLOC(size); +#elif !defined(LFS2_NO_MALLOC) return malloc(size); #else (void)size; @@ -227,7 +255,9 @@ static inline void *lfs2_malloc(size_t size) { // Deallocate memory, only used if buffers are not provided to littlefs static inline void lfs2_free(void *p) { -#ifndef LFS2_NO_MALLOC +#if defined(LFS2_FREE) + LFS2_FREE(p); +#elif !defined(LFS2_NO_MALLOC) free(p); #else (void)p; diff --git a/lib/mbedtls b/lib/mbedtls index 981743de6fc..ece41aa84d7 160000 --- a/lib/mbedtls +++ b/lib/mbedtls @@ -1 +1 @@ -Subproject commit 981743de6fcdbe672e482b6fd724d31d0a0d2476 +Subproject commit ece41aa84d7879d7e55c59e955a5884b541f7f3b diff --git a/lib/mbedtls_config/crt_bundle.c b/lib/mbedtls_config/crt_bundle.c index 9c546a26883..01bb497f655 100644 --- a/lib/mbedtls_config/crt_bundle.c +++ b/lib/mbedtls_config/crt_bundle.c @@ -56,10 +56,6 @@ static crt_bundle_t s_crt_bundle; static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len); -#if MBEDTLS_VERSION_MAJOR < 3 -#define MBEDTLS_PRIVATE(x) x -#endif - static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len) { int ret = 0; mbedtls_x509_crt parent; @@ -74,13 +70,6 @@ static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_b } - // Fast check to avoid expensive computations when not necessary - if (!mbedtls_pk_can_do(&parent.pk, child->MBEDTLS_PRIVATE(sig_pk))) { - LOGE(TAG, "Simple compare failed"); - ret = -1; - goto cleanup; - } - md_info = mbedtls_md_info_from_type(child->MBEDTLS_PRIVATE(sig_md)); if ((ret = mbedtls_md(md_info, child->tbs.p, child->tbs.len, hash)) != 0) { LOGE(TAG, "Internal mbedTLS error %X", ret); @@ -88,10 +77,9 @@ static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_b } if ((ret = mbedtls_pk_verify_ext( - child->MBEDTLS_PRIVATE(sig_pk), child->MBEDTLS_PRIVATE(sig_opts), &parent.pk, + child->MBEDTLS_PRIVATE(sig_pk), &parent.pk, child->MBEDTLS_PRIVATE(sig_md), hash, mbedtls_md_get_size(md_info), child->MBEDTLS_PRIVATE(sig).p, child->MBEDTLS_PRIVATE(sig).len)) != 0) { - LOGE(TAG, "PK verify failed with error %X", ret); goto cleanup; } diff --git a/lib/mbedtls_config/hashlib_psa_port.c b/lib/mbedtls_config/hashlib_psa_port.c new file mode 100644 index 00000000000..88a3b96adba --- /dev/null +++ b/lib/mbedtls_config/hashlib_psa_port.c @@ -0,0 +1,32 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Platform glue for ports that build the PSA crypto core for hashlib but not for ssl. +// The ssl equivalent is mbedtls_port.c; the two are mutually exclusive, because +// CIRCUITPY_HASHLIB_MBEDTLS_ONLY means hashlib without ssl. + +#include + +#if CIRCUITPY_HASHLIB_MBEDTLS_ONLY + +#include "psa/crypto.h" + +#include "shared-bindings/os/__init__.h" + +// Required by MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. psa_crypto_init() initializes the RNG +// subsystem even in a build that only ever hashes, so this has to exist. +psa_status_t mbedtls_psa_external_get_random( + mbedtls_psa_external_random_context_t *context, + uint8_t *output, size_t output_size, size_t *output_length) { + (void)context; + if (!common_hal_os_urandom(output, output_size)) { + return PSA_ERROR_INSUFFICIENT_ENTROPY; + } + *output_length = output_size; + return PSA_SUCCESS; +} + +#endif diff --git a/lib/mbedtls_config/mbedtls_config.h b/lib/mbedtls_config/mbedtls_config.h index 7943994e157..062ad11ff17 100644 --- a/lib/mbedtls_config/mbedtls_config.h +++ b/lib/mbedtls_config/mbedtls_config.h @@ -1,130 +1,102 @@ -/* - * 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_MBEDTLS_CONFIG_H -#define MICROPY_INCLUDED_MBEDTLS_CONFIG_H - -// If you want to debug MBEDTLS uncomment the following and -// Pass 3 to mbedtls_debug_set_threshold in socket_new +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018-2019 Damien P. George +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// mbedtls TLS and X.509 configuration, selected with MBEDTLS_CONFIG_FILE. +// +// As of mbedtls 4.0 this file covers only TLS and X.509. Everything cryptographic -- +// algorithms, key types, the platform hooks and the RNG -- is configured in +// tf_psa_crypto_config.h next to this file, and selected with +// TF_PSA_CRYPTO_CONFIG_FILE. + +#pragma once + +// If you want to debug mbedtls, uncomment the following. SSLSocket.c raises the debug +// threshold to 4 when it is set. // #define MBEDTLS_DEBUG_C -// 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_ECP_NIST_OPTIM -#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED -#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED -#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_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 +// Protocol versions + +// TLS 1.0 and 1.1 were removed in mbedtls 3.0, and were obsolete long before that. +// +// TLS 1.3 is available in 4.x but is turned off, to match espressif +// It also cost 25648 bytes on Pico W, which has only ~50 KB of firmware +// space left. Enabling it here would also require enabling +// MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED, and PSA_WANT_ALG_HKDF* in +// tf_psa_crypto_config.h for the 1.3 key schedule. #define MBEDTLS_SSL_PROTO_TLS1_2 + +// DTLS is deliberately off: common_hal_ssl_sslcontext_wrap_socket() rejects anything +// that is not SOCKETPOOL_SOCK_STREAM, so it could never be reached. + +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C + +// Key exchanges. Without at least one of these there are no TLS 1.2 ciphersuites at +// all, the ClientHello offers nothing, and the server answers with a fatal +// handshake_failure alert. These two are what espressif enables +// (CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_{RSA,ECDSA}) and cover the public web. The PSK +// and ECJPAKE exchanges that 4.x also still offers are not reachable from the ssl +// module, and the static-RSA and DHE exchanges the mbedtls 2.28 config enabled are +// gone from 4.x upstream. +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +// Extensions + #define MBEDTLS_SSL_SERVER_NAME_INDICATION +#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +// Buffers -// Use a smaller output buffer to reduce size of SSL context +// Accept a full-size record inbound, since we do not control what the peer sends, +// but use a smaller outbound buffer to reduce the SSL context size. #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_BASE64_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_GCM_C -#define MBEDTLS_MD_C -#define MBEDTLS_MD5_C -#define MBEDTLS_OID_C -#define MBEDTLS_PKCS5_C -#define MBEDTLS_PEM_PARSE_C -#define MBEDTLS_PK_C -#define MBEDTLS_PK_HAVE_ECC_KEYS -#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_PROTO_DTLS -#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 +// X.509 + #define MBEDTLS_X509_USE_C -#define MBEDTLS_HAVE_TIME -#define MBEDTLS_DHM_C // needed by DHE_PSK -#undef MBEDTLS_HAVE_TIME_DATE - -// 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 - -// Time hook -#include -time_t rp2_rtctime_seconds(time_t *timer); -#define MBEDTLS_PLATFORM_TIME_MACRO rp2_rtctime_seconds - -#include "mbedtls/check_config.h" - -#endif /* MICROPY_INCLUDED_MBEDTLS_CONFIG_H */ +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +// MBEDTLS_HAVE_TIME_DATE is deliberately left off, so certificate notBefore/notAfter +// are not checked (see the BADCERT_EXPIRED/BADCERT_FUTURE tests in x509_crt.c, which +// are compiled out without it). CircuitPython does not know the wall clock time unless +// the program sets it explicitly, which often does not happen; with an unset clock, +// checking the dates would reject valid certificates rather than catch expired ones. +// espressif does not set CONFIG_MBEDTLS_HAVE_TIME_DATE either. +// +// Nothing else we enable consumes time -- no session tickets, no context +// serialization, no DTLS, no TLS 1.3 -- so MBEDTLS_HAVE_TIME is off as well, and +// mbedtls_port.c needs neither a wall clock nor mbedtls_ms_time(). + +// Error strings + +// SSLSocket.c keys off MBEDTLS_ERROR_C to decide whether to put a message on the +// OSError it raises. mbedtls's own error.c is not built; lib/mbedtls_errors supplies +// a smaller mbedtls_strerror() instead. +#define MBEDTLS_ERROR_C + +// Sanity checks +// +// mbedtls's own mbedtls_check_config.h only validates the prerequisites of options +// that are enabled, so it says nothing when a whole category is missing. This is where +// TF_PSA_CRYPTO_CONFIG_FILE replacing psa/crypto_config.h rather than overlaying it +// bites: every default we rely on has to be restated here, and forgetting one produces +// a build that compiles and links but cannot complete a handshake. +#if !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +#error "No MBEDTLS_KEY_EXCHANGE_* enabled: ciphersuite_definitions[] would be empty, " \ + "so the ClientHello would offer nothing and every TLS 1.2 handshake would fail." +#endif diff --git a/lib/mbedtls_config/mbedtls_port.c b/lib/mbedtls_config/mbedtls_port.c index b7e8ceae5de..cc29145e803 100644 --- a/lib/mbedtls_config/mbedtls_port.c +++ b/lib/mbedtls_config/mbedtls_port.c @@ -1,53 +1,29 @@ -/* - * 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 +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018-2019 Damien P. George +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries + +#include "py/mpconfig.h" #if CIRCUITPY_SSL_MBEDTLS -#include "py/runtime.h" -#include "mbedtls_config.h" -#include "mbedtls/entropy_poll.h" +#include "psa/crypto.h" -#include "shared/timeutils/timeutils.h" #include "shared-bindings/os/__init__.h" -#include "shared-bindings/time/__init__.h" - -extern uint8_t rosc_random_u8(size_t cycles); - -int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) { - *olen = len; - common_hal_os_urandom(data, len); - return 0; -} -time_t rp2_rtctime_seconds(time_t *timer) { - mp_obj_t datetime = mp_load_attr(MP_STATE_VM(rtc_time_source), MP_QSTR_datetime); - timeutils_struct_time_t tm; - struct_time_to_tm(datetime, &tm); - return timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); +// The RNG behind MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. mbedtls asks for randomness through +// this instead of seeding its own entropy accumulator and CTR-DRBG, so the port's TRNG +// is the only source. `context` is unused; mbedtls initializes it to 0 and we keep no +// state of our own. +psa_status_t mbedtls_psa_external_get_random( + mbedtls_psa_external_random_context_t *context, + uint8_t *output, size_t output_size, size_t *output_length) { + (void)context; + if (!common_hal_os_urandom(output, output_size)) { + return PSA_ERROR_INSUFFICIENT_ENTROPY; + } + *output_length = output_size; + return PSA_SUCCESS; } #endif diff --git a/lib/mbedtls_config/tf_psa_crypto_config.h b/lib/mbedtls_config/tf_psa_crypto_config.h new file mode 100644 index 00000000000..72e69ba5f63 --- /dev/null +++ b/lib/mbedtls_config/tf_psa_crypto_config.h @@ -0,0 +1,133 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018-2019 Damien P. George +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// TF-PSA-Crypto configuration, selected with TF_PSA_CRYPTO_CONFIG_FILE. +// +// mbedtls 4.0 split its configuration in two: MBEDTLS_CONFIG_FILE now covers only +// TLS and X.509 (see mbedtls_config.h next to this file), and everything +// cryptographic moved here. Algorithms and key types are requested with PSA_WANT_* +// rather than the old MBEDTLS__C module switches; the builtin implementations +// they need are derived from those by tf-psa-crypto's own config_adjust headers. + +#pragma once + +// Platform integration /////////////////////////////////////////////////////// + +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_DEPRECATED_REMOVED + +// Memory allocation hooks, so mbedtls allocations are tracked like the rest of the +// VM's. +#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 + +// Randomness ///////////////////////////////////////////////////////////////// + +// Take randomness straight from the port's TRNG rather than seeding mbedtls's own +// entropy accumulator and CTR-DRBG. mbedtls 4.x dropped MBEDTLS_ENTROPY_HARDWARE_ALT, +// which is how this was wired before, and going direct also keeps entropy.c and +// ctr_drbg.c out of the build. mbedtls_psa_external_get_random() is in +// mbedtls_port.c. +#define MBEDTLS_PSA_CRYPTO_C +#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + +// Size/speed tradeoffs /////////////////////////////////////////////////////// + +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_SHA256_SMALLER +#define MBEDTLS_ECP_NIST_OPTIM + +// Hashes ///////////////////////////////////////////////////////////////////// + +// SHA-1 is still needed to parse certificates that sign with it, and is what +// hashlib exposes as "sha1". +#define PSA_WANT_ALG_SHA_1 +#define PSA_WANT_ALG_SHA_224 +#define PSA_WANT_ALG_SHA_256 +#define PSA_WANT_ALG_SHA_384 +#define PSA_WANT_ALG_SHA_512 +#define PSA_WANT_ALG_HMAC +#define PSA_WANT_KEY_TYPE_HMAC + +// Key derivation ///////////////////////////////////////////////////////////// + +// The TLS 1.2 key schedule. HKDF is deliberately absent: it is the TLS 1.3 key +// schedule, and mbedtls_config.h enables TLS 1.2 only. +#define PSA_WANT_ALG_TLS12_PRF +#define PSA_WANT_ALG_TLS12_PSK_TO_MS +#define PSA_WANT_KEY_TYPE_DERIVE +#define PSA_WANT_KEY_TYPE_RAW_DATA + +// Bulk ciphers /////////////////////////////////////////////////////////////// + +#define PSA_WANT_KEY_TYPE_AES +#define PSA_WANT_ALG_GCM +#define PSA_WANT_ALG_CCM +#define PSA_WANT_ALG_CBC_NO_PADDING +#define PSA_WANT_ALG_CBC_PKCS7 +#define PSA_WANT_ALG_ECB_NO_PADDING + +// RP2 has no AES accelerator, so ChaCha20-Poly1305 is 40-70% faster than AES-GCM here, +// measured over HTTPS on Pico W and Pico 2 W. mbedtls offers it ahead of AES-GCM, and +// real-world CDNs do negotiate it. Costs about 6 kB. espressif leaves it off, since +// ESP32 has AES hardware. +#define PSA_WANT_KEY_TYPE_CHACHA20 +#define PSA_WANT_ALG_CHACHA20_POLY1305 + +// Public key ///////////////////////////////////////////////////////////////// + +#define PSA_WANT_ALG_RSA_PKCS1V15_CRYPT +#define PSA_WANT_ALG_RSA_PKCS1V15_SIGN +#define PSA_WANT_ALG_RSA_PSS +#define PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY +#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC +#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT + +#define PSA_WANT_ALG_ECDH +#define PSA_WANT_ALG_ECDSA +#define PSA_WANT_ALG_DETERMINISTIC_ECDSA +#define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT +// An ECDHE handshake generates an ephemeral key pair, sends its public part, then +// runs the key agreement, so it needs GENERATE, EXPORT and DERIVE as well as the two +// above. Without them psa_generate_key() fails and the TLS 1.2 client reports +// MBEDTLS_ERR_SSL_HW_ACCEL_FAILED -- a legacy name that in 4.x just means a PSA call +// failed. See ssl_tls12_client.c. +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE + +// P-256 and P-384 cover essentially every public CA. Curve25519 is here for x25519 +// ECDHE, which servers commonly prefer (RFC 8422). Deliberately absent: +// - P-521: no public CA issues from it, and it cost 5792 bytes on Pico W. +// - Brainpool and secp256k1: unused on the public web. espressif enables secp256k1 +// only because ESP-IDF defaults it on. +// The 192- and 224-bit curves the mbedtls 2.28 config enabled are gone from 4.x +// upstream; there is no PSA_WANT_ECC_SECP_R1_192/_224 to select. +#define PSA_WANT_ECC_SECP_R1_256 +#define PSA_WANT_ECC_SECP_R1_384 +#define PSA_WANT_ECC_MONTGOMERY_255 + +// Key and certificate parsing //////////////////////////////////////////////// + +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_WRITE_C +#define MBEDTLS_MD_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_PKCS5_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C diff --git a/lib/mbedtls_config/tf_psa_crypto_config_hashlib.h b/lib/mbedtls_config/tf_psa_crypto_config_hashlib.h new file mode 100644 index 00000000000..0dbf9b13542 --- /dev/null +++ b/lib/mbedtls_config/tf_psa_crypto_config_hashlib.h @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018-2019 Damien P. George +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// TF-PSA-Crypto configuration for ports that want hashlib but not ssl, selected with +// TF_PSA_CRYPTO_CONFIG_FILE when CIRCUITPY_HASHLIB_MBEDTLS_ONLY is set. +// +// Only the crypto config is needed here: nothing on this path includes +// mbedtls/build_info.h, so no TLS/X.509 configuration is required. +// +// The PSA core is enabled so that hashlib can use the same psa_hash_*() interface on +// every port. It also means PSA_WANT_* behaves as documented: tf-psa-crypto/build_info.h +// only derives the builtin implementations from PSA_WANT_* when MBEDTLS_PSA_CRYPTO_C is +// set, so without it PSA_WANT_ALG_SHA_256 would silently select nothing. + +#pragma once + +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_DEPRECATED_REMOVED + +#undef MBEDTLS_HAVE_TIME +#undef MBEDTLS_HAVE_TIME_DATE + +// The digests hashlib exposes. +#define PSA_WANT_ALG_SHA_1 +#define PSA_WANT_ALG_SHA_256 + +// psa_crypto_init() initializes the RNG subsystem even in a build that only hashes, so +// a random generator has to be available. Take it straight from the port TRNG, which +// keeps entropy.c and ctr_drbg.c out of the build; see hashlib_psa_port.c. +#define MBEDTLS_PSA_CRYPTO_C +#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + +#define MBEDTLS_SHA256_SMALLER + +// 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 diff --git a/lib/mbedtls_errors/do-mp.sh b/lib/mbedtls_errors/do-mp.sh index 5c6b9711794..3713b0087a7 100755 --- a/lib/mbedtls_errors/do-mp.sh +++ b/lib/mbedtls_errors/do-mp.sh @@ -1,4 +1,15 @@ #! /bin/bash -e # Generate mp_mbedtls_errors.c for inclusion in ports that use $MPY/lib/mbedtls +# +# As of mbedtls 4.0 the error #defines live in two trees: TLS and X.509 in +# mbedtls/include/mbedtls, and the legacy crypto modules in tf-psa-crypto, so +# generate_errors.pl now takes the crypto include directory as well. patch -o mp_generate_errors.pl ../mbedtls/scripts/generate_errors.pl -#if defined(MBEDTLS_AES_C) -#include "mbedtls/aes.h" +#if defined(MBEDTLS_NET_C) +#include "mbedtls/net_sockets.h" #endif -#if defined(MBEDTLS_ARC4_C) -#include "mbedtls/arc4.h" +#if defined(MBEDTLS_PKCS7_C) +#include "mbedtls/pkcs7.h" #endif -#if defined(MBEDTLS_ARIA_C) -#include "mbedtls/aria.h" +#if defined(MBEDTLS_SSL_TLS_C) +#include "mbedtls/ssl.h" #endif -#if defined(MBEDTLS_ASN1_PARSE_C) -#include "mbedtls/asn1.h" +#if defined(MBEDTLS_X509_USE_C) || \ + defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" #endif -#if defined(MBEDTLS_BASE64_C) -#include "mbedtls/base64.h" +#if defined(MBEDTLS_AES_C) +#include "mbedtls/private/aes.h" #endif -#if defined(MBEDTLS_BIGNUM_C) -#include "mbedtls/bignum.h" +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/private/aria.h" #endif -#if defined(MBEDTLS_BLOWFISH_C) -#include "mbedtls/blowfish.h" +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/private/bignum.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" +#include "mbedtls/private/camellia.h" #endif #if defined(MBEDTLS_CHACHAPOLY_C) -#include "mbedtls/chachapoly.h" +#include "mbedtls/private/chachapoly.h" #endif #if defined(MBEDTLS_CIPHER_C) -#include "mbedtls/cipher.h" -#endif - -#if defined(MBEDTLS_CMAC_C) -#include "mbedtls/cmac.h" +#include "mbedtls/private/cipher.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" +#include "mbedtls/private/ctr_drbg.h" #endif #if defined(MBEDTLS_ECP_C) -#include "mbedtls/ecp.h" +#include "mbedtls/private/ecp.h" #endif #if defined(MBEDTLS_ENTROPY_C) -#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 - -#if defined(MBEDTLS_HKDF_C) -#include "mbedtls/hkdf.h" +#include "mbedtls/private/entropy.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) -#if defined(MBEDTLS_PADLOCK_FILE) -#include MBEDTLS_PADLOCK_FILE -#else -#include "mbedtls/padlock.h" -#endif -#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" +#include "mbedtls/private/hmac_drbg.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" +#include "mbedtls/private/pkcs5.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" +#include "mbedtls/private/rsa.h" #endif @@ -231,197 +112,44 @@ struct ssl_errs { // 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" }, -#if defined(MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED), "CIPHER_HW_ACCEL_FAILED" }, -#endif -#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" }, -#if defined(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED), "ECP_HW_ACCEL_FAILED" }, -#endif - { -(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" }, -#if defined(MBEDTLS_ERR_MD_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_MD_HW_ACCEL_FAILED), "MD_HW_ACCEL_FAILED" }, -#endif -#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" }, -#if defined(MBEDTLS_ERR_PK_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_PK_HW_ACCEL_FAILED), "PK_HW_ACCEL_FAILED" }, -#endif -#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" }, -#if defined(MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION) - { -(MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION), "RSA_UNSUPPORTED_OPERATION" }, -#endif -#if defined(MBEDTLS_ERR_RSA_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_RSA_HW_ACCEL_FAILED), "RSA_HW_ACCEL_FAILED" }, -#endif -#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_PKCS7_C) + { -(MBEDTLS_ERR_PKCS7_INVALID_FORMAT), "PKCS7_INVALID_FORMAT" }, + { -(MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE), "PKCS7_FEATURE_UNAVAILABLE" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_VERSION), "PKCS7_INVALID_VERSION" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO), "PKCS7_INVALID_CONTENT_INFO" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_ALG), "PKCS7_INVALID_ALG" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_CERT), "PKCS7_INVALID_CERT" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_SIGNATURE), "PKCS7_INVALID_SIGNATURE" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO), "PKCS7_INVALID_SIGNER_INFO" }, + { -(MBEDTLS_ERR_PKCS7_CERT_DATE_INVALID), "PKCS7_CERT_DATE_INVALID" }, +#endif /* MBEDTLS_PKCS7_C */ #if defined(MBEDTLS_SSL_TLS_C) + { -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS), "SSL_CRYPTO_IN_PROGRESS" }, { -(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" }, -#if defined(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER) - { -(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER), "SSL_UNKNOWN_CIPHER" }, -#endif -#if defined(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN) - { -(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN), "SSL_NO_CIPHER_CHOSEN" }, -#endif + { -(MBEDTLS_ERR_SSL_DECODE_ERROR), "SSL_DECODE_ERROR" }, { -(MBEDTLS_ERR_SSL_NO_RNG), "SSL_NO_RNG" }, { -(MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE), "SSL_NO_CLIENT_CERTIFICATE" }, -#if defined(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE) - { -(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE), "SSL_CERTIFICATE_TOO_LARGE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED) - { -(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED), "SSL_CERTIFICATE_REQUIRED" }, -#endif + { -(MBEDTLS_ERR_SSL_UNSUPPORTED_EXTENSION), "SSL_UNSUPPORTED_EXTENSION" }, + { -(MBEDTLS_ERR_SSL_NO_APPLICATION_PROTOCOL), "SSL_NO_APPLICATION_PROTOCOL" }, { -(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" }, -#if defined(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED) - { -(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED), "SSL_PEER_VERIFY_FAILED" }, -#endif + { -(MBEDTLS_ERR_SSL_UNRECOGNIZED_NAME), "SSL_UNRECOGNIZED_NAME" }, { -(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY), "SSL_PEER_CLOSE_NOTIFY" }, -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO) - { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO), "SSL_BAD_HS_CLIENT_HELLO" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO) - { -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO), "SSL_BAD_HS_SERVER_HELLO" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE) - { -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE), "SSL_BAD_HS_CERTIFICATE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST) - { -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST), "SSL_BAD_HS_CERTIFICATE_REQUEST" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE) - { -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE), "SSL_BAD_HS_SERVER_KEY_EXCHANGE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE) - { -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE), "SSL_BAD_HS_SERVER_HELLO_DONE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) - { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE), "SSL_BAD_HS_CLIENT_KEY_EXCHANGE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP) - { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP), "SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS) - { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS), "SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY) - { -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY), "SSL_BAD_HS_CERTIFICATE_VERIFY" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC) - { -(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC), "SSL_BAD_HS_CHANGE_CIPHER_SPEC" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_FINISHED) - { -(MBEDTLS_ERR_SSL_BAD_HS_FINISHED), "SSL_BAD_HS_FINISHED" }, -#endif - { -(MBEDTLS_ERR_SSL_ALLOC_FAILED), "SSL_ALLOC_FAILED" }, + { -(MBEDTLS_ERR_SSL_BAD_CERTIFICATE), "SSL_BAD_CERTIFICATE" }, + { -(MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET), "SSL_RECEIVED_NEW_SESSION_TICKET" }, + { -(MBEDTLS_ERR_SSL_CANNOT_READ_EARLY_DATA), "SSL_CANNOT_READ_EARLY_DATA" }, + { -(MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA), "SSL_RECEIVED_EARLY_DATA" }, + { -(MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA), "SSL_CANNOT_WRITE_EARLY_DATA" }, + { -(MBEDTLS_ERR_SSL_CACHE_ENTRY_NOT_FOUND), "SSL_CACHE_ENTRY_NOT_FOUND" }, { -(MBEDTLS_ERR_SSL_HW_ACCEL_FAILED), "SSL_HW_ACCEL_FAILED" }, { -(MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH), "SSL_HW_ACCEL_FALLTHROUGH" }, -#if defined(MBEDTLS_ERR_SSL_COMPRESSION_FAILED) - { -(MBEDTLS_ERR_SSL_COMPRESSION_FAILED), "SSL_COMPRESSION_FAILED" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) - { -(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION), "SSL_BAD_HS_PROTOCOL_VERSION" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET) - { -(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET), "SSL_BAD_HS_NEW_SESSION_TICKET" }, -#endif + { -(MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION), "SSL_BAD_PROTOCOL_VERSION" }, + { -(MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE), "SSL_HANDSHAKE_FAILURE" }, { -(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" }, @@ -429,29 +157,24 @@ static const struct ssl_errs mbedtls_high_level_error_tab[] = { { -(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" }, -#if defined(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) - { -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE), "SSL_NO_USABLE_CIPHERSUITE" }, -#endif { -(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" }, -#if defined(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH) - { -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH), "SSL_INVALID_VERIFY_HASH" }, -#endif + { -(MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER), "SSL_ILLEGAL_PARAMETER" }, { -(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" }, + { -(MBEDTLS_ERR_SSL_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME), "SSL_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME" }, #endif /* MBEDTLS_SSL_TLS_C */ -#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_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" }, @@ -468,11 +191,34 @@ static const struct ssl_errs mbedtls_high_level_error_tab[] = { { -(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 */ +#endif /* MBEDTLS_X509_USE_C || + MBEDTLS_X509_CREATE_C */ + +#if defined(MBEDTLS_CIPHER_C) + { -(MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE), "CIPHER_FEATURE_UNAVAILABLE" }, + { -(MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED), "CIPHER_FULL_BLOCK_EXPECTED" }, + { -(MBEDTLS_ERR_CIPHER_INVALID_CONTEXT), "CIPHER_INVALID_CONTEXT" }, +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_ECP_C) + { -(MBEDTLS_ERR_ECP_INVALID_KEY), "ECP_INVALID_KEY" }, +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_PKCS5_C) + { -(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_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_RNG_FAILED), "RSA_RNG_FAILED" }, +#endif /* MBEDTLS_RSA_C */ // END generated code }; @@ -480,98 +226,46 @@ static const struct ssl_errs mbedtls_low_level_error_tab[] = { // Low level error codes // // BEGIN generated code +#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_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_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" }, -#if defined(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE) - { -(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE), "AES_FEATURE_UNAVAILABLE" }, -#endif -#if defined(MBEDTLS_ERR_AES_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_AES_HW_ACCEL_FAILED), "AES_HW_ACCEL_FAILED" }, -#endif #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" }, -#if defined(MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE) - { -(MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE), "ARIA_FEATURE_UNAVAILABLE" }, -#endif -#if defined(MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED), "ARIA_HW_ACCEL_FAILED" }, -#endif #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" }, -#if defined(MBEDTLS_ERR_CCM_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_CCM_HW_ACCEL_FAILED), "CCM_HW_ACCEL_FAILED" }, -#endif -#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" }, -#if defined(MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED), "CHACHA20_HW_ACCEL_FAILED" }, -#endif -#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) -#if defined(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED), "CMAC_HW_ACCEL_FAILED" }, -#endif -#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" }, @@ -579,128 +273,19 @@ static const struct ssl_errs mbedtls_low_level_error_tab[] = { { -(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_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" }, -#if defined(MBEDTLS_ERR_GCM_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_GCM_HW_ACCEL_FAILED), "GCM_HW_ACCEL_FAILED" }, -#endif - { -(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) -#if defined(MBEDTLS_ERR_MD5_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_MD5_HW_ACCEL_FAILED), "MD5_HW_ACCEL_FAILED" }, -#endif -#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) -#if defined(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED), "SHA1_HW_ACCEL_FAILED" }, -#endif - { -(MBEDTLS_ERR_SHA1_BAD_INPUT_DATA), "SHA1_BAD_INPUT_DATA" }, -#endif /* MBEDTLS_SHA1_C */ - -#if defined(MBEDTLS_SHA256_C) -#if defined(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED), "SHA256_HW_ACCEL_FAILED" }, -#endif - { -(MBEDTLS_ERR_SHA256_BAD_INPUT_DATA), "SHA256_BAD_INPUT_DATA" }, -#endif /* MBEDTLS_SHA256_C */ - -#if defined(MBEDTLS_SHA512_C) -#if defined(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED), "SHA512_HW_ACCEL_FAILED" }, -#endif - { -(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 }; diff --git a/lib/micropython-lib b/lib/micropython-lib index 5b496e944ec..ee4bb8ff139 160000 --- a/lib/micropython-lib +++ b/lib/micropython-lib @@ -1 +1 @@ -Subproject commit 5b496e944ec045177afa1620920a168410b7f60b +Subproject commit ee4bb8ff139e24c42b739935fbd8ec7c4d061e02 diff --git a/lib/protomatter b/lib/protomatter index 0bd9873153a..425b6c7f887 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit 0bd9873153ab0a91d6737c392622159a4515a2e5 +Subproject commit 425b6c7f887cca5d24d768d8c80c74ba7eb88dc6 diff --git a/lib/re1.5/compilecode.c b/lib/re1.5/compilecode.c index 63ae1e02b8d..77a0b8ff2a6 100644 --- a/lib/re1.5/compilecode.c +++ b/lib/re1.5/compilecode.c @@ -50,6 +50,8 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) int term = PC; int alt_label = 0; + re1_5_stack_chk(); + for (; *re && *re != ')'; re++) { switch (*re) { case '\\': diff --git a/lib/tinyusb b/lib/tinyusb index 5fb3c09963b..5453ed09f19 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 5fb3c09963bca362e535788e289d4b3518da5973 +Subproject commit 5453ed09f19af010b6a361562d967cfa30aaadc6 diff --git a/locale/ID.po b/locale/ID.po index ee7b8dfc4a3..ca862a97147 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -6,15 +6,15 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-06-30 16:01+0000\n" -"Last-Translator: MAE \n" +"PO-Revision-Date: 2026-02-13 15:09+0000\n" +"Last-Translator: Arif Budiman \n" "Language-Team: LANGUAGE \n" "Language: ID\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.13-dev\n" +"X-Generator: Weblate 5.16-dev\n" #: main.c msgid "" @@ -116,7 +116,7 @@ msgstr "%q gagal: %d" #: shared-module/audiodelays/MultiTapDelay.c msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" +msgstr "%q dalam %q harus bertipe %q atau %q, bukan %q" #: py/argcheck.c shared-module/audiofilters/Filter.c msgid "%q in %q must be of type %q, not %q" @@ -289,7 +289,7 @@ msgstr "%q, %q, dan %q semuanya harus memiliki panjang yang sama" #: py/objint.c shared-bindings/_bleio/Connection.c #: shared-bindings/storage/__init__.c msgid "%q=%q" -msgstr "" +msgstr "%q=%q" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "%q[%u] shifts in more bits than pin count" @@ -566,7 +566,7 @@ msgstr "Sudah disebarkan." #: ports/atmel-samd/common-hal/canio/Listener.c msgid "Already have all-matches listener" -msgstr "" +msgstr "Sudah memiliki listener semua-kecocokan" #: ports/espressif/common-hal/_bleio/__init__.c msgid "Already in progress" @@ -610,7 +610,7 @@ msgstr "Nilai array harus berupa byte tunggal." #: ports/atmel-samd/common-hal/spitarget/SPITarget.c msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" +msgstr "Transfer SPI async sedang berlangsung pada bus ini, terus menunggu." #: shared-module/memorymonitor/AllocationAlarm.c #, c-format @@ -624,7 +624,7 @@ msgstr "Konversi audio belum diimplementasikan" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c msgid "Audio source error" -msgstr "" +msgstr "Kesalahan sumber audio" #: shared-bindings/wifi/Radio.c msgid "AuthMode.OPEN is not used with password" @@ -767,7 +767,7 @@ msgstr "" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Can't construct AudioOut because continuous channel already open" -msgstr "" +msgstr "Tidak dapat membuat AudioOut karena kanal berkelanjutan sudah terbuka" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c @@ -817,7 +817,7 @@ msgstr "Tidak dapat merekam ke file" #: shared-module/storage/__init__.c msgid "Cannot remount path when visible via USB." -msgstr "" +msgstr "Tidak dapat me-remount jalur ketika terlihat melalui USB." #: shared-bindings/digitalio/DigitalInOut.c msgid "Cannot set value when direction is input." @@ -834,7 +834,7 @@ msgstr "Tidak dapat membuat subkelas dari irisan" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" +msgstr "Tidak dapat menggunakan GPIO0..15 bersamaan dengan GPIO32..47" #: ports/nordic/common-hal/alarm/pin/PinAlarm.c msgid "Cannot wake on pin edge, only level" @@ -873,7 +873,7 @@ msgstr "Tipe array koordinat memiliki ukuran yang berbeda" #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" -msgstr "" +msgstr "Tidak dapat mempublikasikan ke topik ROS" #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" @@ -890,7 +890,7 @@ msgstr "Tidak dapat mengalokasikan dekoder" #: ports/espressif/common-hal/rclcpy/__init__.c #, c-format msgid "Critical ROS failure during soft reboot, reset required: %d" -msgstr "" +msgstr "Kegagalan ROS kritis selama soft reboot, reset diperlukan: %d" #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" @@ -1009,28 +1009,30 @@ msgstr "Gagal memperoleh mutex, err 0x%04x" #: ports/raspberrypi/common-hal/mdns/Server.c msgid "Failed to add service TXT record" -msgstr "" +msgstr "Gagal menambahkan record TXT layanan" #: shared-bindings/mdns/Server.c msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" +"Gagal menambahkan record TXT layanan; ditemukan non-string atau bytes dalam " +"txt_records" #: shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" -msgstr "" +msgstr "Gagal mengalokasikan buffer %q" #: ports/espressif/common-hal/wifi/__init__.c msgid "Failed to allocate Wifi memory" -msgstr "" +msgstr "Gagal mengalokasikan memori Wifi" #: ports/espressif/common-hal/wifi/ScannedNetworks.c msgid "Failed to allocate wifi scan memory" -msgstr "" +msgstr "Gagal mengalokasikan memori pemindaian wifi" #: ports/stm/common-hal/audiopwmio/PWMAudioOut.c msgid "Failed to buffer the sample" -msgstr "" +msgstr "Gagal membuffer sampel" #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c @@ -1043,23 +1045,23 @@ msgstr "Gagal terhubung: habis waktu" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: invalid arg" -msgstr "" +msgstr "Gagal membuat kanal berkelanjutan: argumen tidak valid" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: invalid state" -msgstr "" +msgstr "Gagal membuat kanal berkelanjutan: status tidak valid" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: no mem" -msgstr "" +msgstr "Gagal membuat kanal berkelanjutan: tidak ada memori" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: not found" -msgstr "" +msgstr "Gagal membuat kanal berkelanjutan: tidak ditemukan" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to enable continuous" -msgstr "" +msgstr "Gagal mengaktifkan berkelanjutan" #: shared-module/audiomp3/MP3Decoder.c msgid "Failed to parse MP3 file" @@ -1067,7 +1069,7 @@ msgstr "Gagal mengurai file MP3" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to register continuous events callback" -msgstr "" +msgstr "Gagal mendaftarkan callback event berkelanjutan" #: ports/nordic/sd_mutex.c #, c-format @@ -1076,11 +1078,11 @@ msgstr "Gagal melepaskan mutex, err 0x%04x" #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" -msgstr "" +msgstr "Gagal menetapkan hostname" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to start async audio" -msgstr "" +msgstr "Gagal memulai audio async" #: supervisor/shared/safe_mode.c msgid "Failed to write internal flash." @@ -1093,43 +1095,44 @@ msgstr "File sudah ada" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c #: shared-module/os/getenv.c msgid "File not found" -msgstr "" +msgstr "File tidak ditemukan" #: ports/atmel-samd/common-hal/canio/Listener.c #: ports/espressif/common-hal/canio/Listener.c #: ports/mimxrt10xx/common-hal/canio/Listener.c #: ports/stm/common-hal/canio/Listener.c msgid "Filters too complex" -msgstr "" +msgstr "Filter terlalu kompleks" #: ports/espressif/common-hal/dualbank/__init__.c msgid "Firmware is duplicate" -msgstr "" +msgstr "Firmware adalah duplikat" #: ports/espressif/common-hal/dualbank/__init__.c msgid "Firmware is invalid" -msgstr "" +msgstr "Firmware tidak valid" #: ports/espressif/common-hal/dualbank/__init__.c msgid "Firmware is too big" -msgstr "" +msgstr "Firmware terlalu besar" #: shared-bindings/bitmaptools/__init__.c msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "" +msgstr "Untuk colorspace L8, bitmap input harus memiliki 8 bit per piksel" #: shared-bindings/bitmaptools/__init__.c msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "" +msgstr "Untuk colorspace RGB, bitmap input harus memiliki 16 bit per piksel" #: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c msgid "Format not supported" -msgstr "" +msgstr "Format tidak didukung" #: ports/mimxrt10xx/common-hal/microcontroller/Processor.c msgid "" "Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" +"Frekuensi harus 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 atau 1008 Mhz" #: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c #: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c @@ -1138,11 +1141,11 @@ msgstr "Fungsinya membutuhkan kunci" #: ports/cxd56/common-hal/gnss/GNSS.c msgid "GNSS init" -msgstr "" +msgstr "Inisialisasi GNSS" #: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" -msgstr "" +msgstr "Kegagalan Umum" #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c @@ -1152,7 +1155,7 @@ msgstr "Grup sudah digunakan" #: supervisor/shared/safe_mode.c msgid "Hard fault: memory access or instruction error." -msgstr "" +msgstr "Hard fault: kesalahan akses memori atau instruksi." #: ports/mimxrt10xx/common-hal/busio/SPI.c #: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c @@ -1163,7 +1166,7 @@ msgstr "Perangkat keras sedang digunakan, coba pin alternatif" #: supervisor/shared/safe_mode.c msgid "Heap allocation when VM not running." -msgstr "" +msgstr "Alokasi heap ketika VM tidak berjalan." #: extmod/vfs_posix_file.c py/objstringio.c msgid "I/O operation on closed file" @@ -1171,16 +1174,16 @@ msgstr "operasi I/O pada file tertutup" #: ports/stm/common-hal/busio/I2C.c msgid "I2C init error" -msgstr "" +msgstr "Kesalahan inisialisasi I2C" #: ports/raspberrypi/common-hal/busio/I2C.c #: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c msgid "I2C peripheral in use" -msgstr "" +msgstr "Periferal I2C sedang digunakan" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "In-buffer elements must be <= 4 bytes long" -msgstr "" +msgstr "Elemen in-buffer harus <= 4 byte panjangnya" #: shared-bindings/_pew/PewPew.c msgid "Incorrect buffer size" @@ -1188,24 +1191,25 @@ msgstr "Ukuran penyangga salah" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Init program size invalid" -msgstr "" +msgstr "Ukuran program inisialisasi tidak valid" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "" +msgstr "Arah pin set awal berkonflik dengan arah pin out awal" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Initial set pin state conflicts with initial out pin state" -msgstr "" +msgstr "Status pin set awal berkonflik dengan status pin out awal" #: shared-bindings/bitops/__init__.c #, c-format msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" +"Panjang buffer input (%d) harus merupakan kelipatan dari jumlah strand (%d)" #: ports/atmel-samd/common-hal/pulseio/PulseIn.c msgid "Input taking too long" -msgstr "" +msgstr "Input memakan waktu terlalu lama" #: py/moderrno.c msgid "Input/output error" @@ -1223,20 +1227,20 @@ msgstr "Enkripsi tidak cukup" #: shared-module/jpegio/JpegDecoder.c msgid "Insufficient memory pool for the image" -msgstr "" +msgstr "Pool memori tidak mencukupi untuk gambar" #: shared-module/jpegio/JpegDecoder.c msgid "Insufficient stream input buffer" -msgstr "" +msgstr "Buffer input stream tidak mencukupi" #: ports/espressif/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Interface must be started" -msgstr "" +msgstr "Interface harus dimulai" #: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c msgid "Internal audio buffer too small" -msgstr "" +msgstr "Buffer audio internal terlalu kecil" #: ports/stm/common-hal/busio/UART.c msgid "Internal define error" @@ -1244,7 +1248,7 @@ msgstr "Kesalahan definisi internal" #: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c msgid "Internal error" -msgstr "" +msgstr "Kesalahan internal" #: shared-module/rgbmatrix/RGBMatrix.c #, c-format @@ -1262,19 +1266,19 @@ msgstr "Kesalahan internal #%d" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-bindings/pwmio/PWMOut.c msgid "Internal resource(s) in use" -msgstr "" +msgstr "Sumber daya internal sedang digunakan" #: supervisor/shared/safe_mode.c msgid "Internal watchdog timer expired." -msgstr "" +msgstr "Timer watchdog internal kedaluwarsa." #: supervisor/shared/safe_mode.c msgid "Interrupt error." -msgstr "" +msgstr "Kesalahan interrupt." #: shared-module/jpegio/JpegDecoder.c msgid "Interrupted by output function" -msgstr "" +msgstr "Diinterupsi oleh fungsi output" #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c @@ -1290,12 +1294,12 @@ msgstr "" #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c msgid "Invalid %q" -msgstr "" +msgstr "%q tidak valid" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" -msgstr "" +msgstr "%q dan %q tidak valid" #: ports/atmel-samd/common-hal/microcontroller/Pin.c #: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c @@ -1311,19 +1315,19 @@ msgstr "Nilai Unit ADC tidak valid" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid BLE parameter" -msgstr "" +msgstr "Parameter BLE tidak valid" #: shared-bindings/wifi/Radio.c msgid "Invalid BSSID" -msgstr "" +msgstr "BSSID tidak valid" #: shared-bindings/wifi/Radio.c msgid "Invalid MAC address" -msgstr "" +msgstr "Alamat MAC tidak valid" #: ports/espressif/common-hal/rclcpy/__init__.c msgid "Invalid ROS domain ID" -msgstr "" +msgstr "ID domain ROS tidak valid" #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" @@ -1336,16 +1340,16 @@ msgstr "Bit per nilai tidak valid" #: shared-module/os/getenv.c #, c-format msgid "Invalid byte %.*s" -msgstr "" +msgstr "Byte tidak valid %.*s" #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" -msgstr "" +msgstr "data_pins[%d] tidak valid" #: shared-module/msgpack/__init__.c msgid "Invalid format" -msgstr "" +msgstr "Format tidak valid" #: shared-module/audiocore/WaveFile.c msgid "Invalid format chunk size" @@ -1353,29 +1357,29 @@ msgstr "Ukuran potongan format tidak valid" #: shared-bindings/wifi/Radio.c msgid "Invalid hex password" -msgstr "" +msgstr "Password hex tidak valid" #: ports/espressif/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Invalid multicast MAC address" -msgstr "" +msgstr "Alamat MAC multicast tidak valid" #: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" -msgstr "" +msgstr "Ukuran tidak valid" #: shared-module/ssl/SSLSocket.c msgid "Invalid socket for TLS" -msgstr "" +msgstr "Socket tidak valid untuk TLS" #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" -msgstr "" +msgstr "Status tidak valid" #: shared-module/os/getenv.c msgid "Invalid unicode escape" -msgstr "" +msgstr "Escape unicode tidak valid" #: shared-bindings/aesio/aes.c msgid "Key must be 16, 24, or 32 bytes long" @@ -1383,11 +1387,11 @@ msgstr "Panjang kunci harus 16, 24, atau 32 byte" #: shared-module/os/getenv.c msgid "Key not found" -msgstr "" +msgstr "Kunci tidak ditemukan" #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" -msgstr "" +msgstr "Pemetaan LED harus sesuai dengan ukuran display" #: py/compile.c msgid "LHS of keyword arg must be an id" @@ -1395,74 +1399,75 @@ msgstr "LHS dari keyword arg harus menjadi sebuah id" #: shared-module/displayio/Group.c msgid "Layer already in a group" -msgstr "" +msgstr "Layer sudah ada dalam grup" #: shared-module/displayio/Group.c msgid "Layer must be a Group or TileGrid subclass" -msgstr "" +msgstr "Layer harus merupakan subclass Group atau TileGrid" #: shared-bindings/audiocore/RawSample.c msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" +"Panjang %q harus merupakan kelipatan genap dari channel_count * type_size" #: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" -msgstr "" +msgstr "Alamat MAC tidak valid" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/espressif/common-hal/_bleio/Descriptor.c msgid "MITM security not supported" -msgstr "" +msgstr "Keamanan MITM tidak didukung" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "MMC/SDIO Clock Error %x" -msgstr "" +msgstr "Kesalahan Clock MMC/SDIO %x" #: shared-bindings/is31fl3741/IS31FL3741.c msgid "Mapping must be a tuple" -msgstr "" +msgstr "Mapping harus berupa tuple" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched data size" -msgstr "" +msgstr "Ukuran data tidak cocok" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched swap flag" -msgstr "" +msgstr "Flag swap tidak cocok" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "" +msgstr "first_in_pin tidak ada. %q[%u] membaca pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "" +msgstr "first_in_pin tidak ada. %q[%u] melakukan shift in dari pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "" +msgstr "first_in_pin tidak ada. %q[%u] menunggu berdasarkan pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "" +msgstr "first_out_pin tidak ada. %q[%u] melakukan shift out ke pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "" +msgstr "first_out_pin tidak ada. %q[%u] menulis pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "" +msgstr "first_set_pin tidak ada. %q[%u] menetapkan pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "" +msgstr "jmp_pin tidak ada. %q[%u] melompat pada pin" #: shared-module/storage/__init__.c msgid "Mount point directory missing" -msgstr "" +msgstr "Direktori titik mount tidak ada" #: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c #: shared-bindings/displayio/Group.c @@ -1471,7 +1476,7 @@ msgstr "Harus berupa subclass %q." #: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c msgid "Must provide 5/6/5 RGB pins" -msgstr "" +msgstr "Harus menyediakan pin RGB 5/6/5" #: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" @@ -1484,23 +1489,23 @@ msgstr "Harus menggunakan kelipatan 6 pin rgb, bukan %d" #: supervisor/shared/safe_mode.c msgid "NLR jump failed. Likely memory corruption." -msgstr "" +msgstr "Lompatan NLR gagal. Kemungkinan korupsi memori." #: ports/espressif/common-hal/nvm/ByteArray.c msgid "NVS Error" -msgstr "" +msgstr "Kesalahan NVS" #: shared-bindings/socketpool/SocketPool.c msgid "Name or service not known" -msgstr "" +msgstr "Nama atau layanan tidak diketahui" #: shared-bindings/displayio/TileGrid.c msgid "New bitmap must be same size as old bitmap" -msgstr "" +msgstr "Bitmap baru harus berukuran sama dengan bitmap lama" #: ports/espressif/common-hal/_bleio/__init__.c msgid "Nimble out of memory" -msgstr "" +msgstr "Nimble kehabisan memori" #: ports/atmel-samd/common-hal/busio/UART.c #: ports/espressif/common-hal/busio/SPI.c @@ -1535,26 +1540,26 @@ msgstr "tidak ada channel DMA ditemukan" #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c msgid "No DMA pacing timer found" -msgstr "" +msgstr "Tidak ditemukan timer pacing DMA" #: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c #, c-format msgid "No I2C device at address: 0x%x" -msgstr "" +msgstr "Tidak ada perangkat I2C pada alamat: 0x%x" #: supervisor/shared/web_workflow/web_workflow.c msgid "No IP" -msgstr "" +msgstr "Tidak ada IP" #: ports/atmel-samd/common-hal/microcontroller/__init__.c #: ports/cxd56/common-hal/microcontroller/__init__.c #: ports/mimxrt10xx/common-hal/microcontroller/__init__.c msgid "No bootloader present" -msgstr "" +msgstr "Tidak ada bootloader" #: shared-module/usb/core/Device.c msgid "No configuration set" -msgstr "" +msgstr "Tidak ada konfigurasi yang ditetapkan" #: shared-bindings/_bleio/PacketBuffer.c msgid "No connection: length cannot be determined" @@ -1576,11 +1581,11 @@ msgstr "Tidak ada perangkat keras acak yang tersedia" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "No in in program" -msgstr "" +msgstr "Tidak ada in dalam program" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "No in or out in program" -msgstr "" +msgstr "Tidak ada in atau out dalam program" #: py/objint.c shared-bindings/time/__init__.c msgid "No long integer support" @@ -1588,18 +1593,18 @@ msgstr "Tidak ada dukungan bilangan bulat yang panjang" #: shared-bindings/wifi/Radio.c msgid "No network with that ssid" -msgstr "" +msgstr "Tidak ada jaringan dengan ssid tersebut" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "No out in program" -msgstr "" +msgstr "Tidak ada out dalam program" #: ports/atmel-samd/common-hal/busio/I2C.c #: ports/espressif/common-hal/busio/I2C.c #: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c #: ports/raspberrypi/common-hal/busio/I2C.c msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "" +msgstr "Tidak ditemukan pull up pada SDA atau SCL; periksa pengkabelan Anda" #: shared-module/touchio/TouchIn.c msgid "No pulldown on pin; 1Mohm recommended" @@ -1607,7 +1612,7 @@ msgstr "Tidak ada pull-down pada pin; 1Mohm direkomendasikan" #: shared-module/touchio/TouchIn.c msgid "No pullup on pin; 1Mohm recommended" -msgstr "" +msgstr "Tidak ada pullup pada pin; 1Mohm direkomendasikan" #: py/moderrno.c msgid "No space left on device" @@ -1615,7 +1620,7 @@ msgstr "Tidak ada ruang yang tersisa di perangkat" #: py/moderrno.c msgid "No such device" -msgstr "" +msgstr "Perangkat tidak ada" #: py/moderrno.c msgid "No such file/directory" @@ -1627,15 +1632,15 @@ msgstr "Penghitung waktu tidak tersedia" #: shared-module/usb/core/Device.c msgid "No usb host port initialized" -msgstr "" +msgstr "Tidak ada port host usb yang diinisialisasi" #: ports/nordic/common-hal/_bleio/__init__.c msgid "Nordic system firmware out of memory" -msgstr "" +msgstr "Firmware sistem Nordic kehabisan memori" #: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c msgid "Not a valid IP string" -msgstr "" +msgstr "Bukan string IP yang valid" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c @@ -1656,7 +1661,7 @@ msgstr "" #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format msgid "Number of data_pins must be %d or %d, not %d" -msgstr "" +msgstr "Jumlah data_pins harus %d atau %d, bukan %d" #: shared-bindings/util.c msgid "" @@ -1670,17 +1675,17 @@ msgstr "Parity ganjil tidak didukung" #: supervisor/shared/bluetooth/bluetooth.c msgid "Off" -msgstr "" +msgstr "Mati" #: supervisor/shared/bluetooth/bluetooth.c msgid "Ok" -msgstr "" +msgstr "Ok" #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c #, c-format msgid "Only 8 or 16 bit mono with %dx oversampling supported." -msgstr "" +msgstr "Hanya mono 8 atau 16 bit dengan oversampling %dx yang didukung." #: ports/espressif/common-hal/wifi/__init__.c #: ports/raspberrypi/common-hal/wifi/__init__.c @@ -1701,51 +1706,51 @@ msgstr "" #: shared-bindings/_bleio/Adapter.c msgid "Only connectable advertisements can be directed" -msgstr "" +msgstr "Hanya advertisement yang dapat terhubung yang dapat diarahkan" #: ports/stm/common-hal/alarm/pin/PinAlarm.c msgid "Only edge detection is available on this hardware" -msgstr "" +msgstr "Hanya deteksi tepi yang tersedia pada perangkat keras ini" #: shared-bindings/ipaddress/__init__.c msgid "Only int or string supported for ip" -msgstr "" +msgstr "Hanya int atau string yang didukung untuk ip" #: ports/espressif/common-hal/alarm/touch/TouchAlarm.c msgid "Only one %q can be set in deep sleep." -msgstr "" +msgstr "Hanya satu %q yang dapat ditetapkan dalam deep sleep." #: ports/espressif/common-hal/espulp/ULPAlarm.c msgid "Only one %q can be set." -msgstr "" +msgstr "Hanya satu %q yang dapat ditetapkan." #: ports/espressif/common-hal/i2ctarget/I2CTarget.c #: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c msgid "Only one address is allowed" -msgstr "" +msgstr "Hanya satu alamat yang diperbolehkan" #: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c #: ports/nordic/common-hal/alarm/time/TimeAlarm.c #: ports/stm/common-hal/alarm/time/TimeAlarm.c msgid "Only one alarm.time alarm can be set" -msgstr "" +msgstr "Hanya satu alarm alarm.time yang dapat ditetapkan" #: ports/espressif/common-hal/alarm/time/TimeAlarm.c #: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c msgid "Only one alarm.time alarm can be set." -msgstr "" +msgstr "Hanya satu alarm alarm.time yang dapat ditetapkan." #: shared-module/displayio/ColorConverter.c msgid "Only one color can be transparent at a time" -msgstr "" +msgstr "Hanya satu warna yang dapat transparan pada satu waktu" #: py/moderrno.c msgid "Operation not permitted" -msgstr "" +msgstr "Operasi tidak diizinkan" #: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" -msgstr "" +msgstr "Operasi atau fitur tidak didukung" #: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" @@ -1753,7 +1758,7 @@ msgstr "Waktu habis" #: ports/raspberrypi/common-hal/mdns/Server.c msgid "Out of MDNS service slots" -msgstr "" +msgstr "Kehabisan slot layanan MDNS" #: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" @@ -1767,27 +1772,27 @@ msgstr "Kehabisan socket" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Out-buffer elements must be <= 4 bytes long" -msgstr "" +msgstr "Elemen out-buffer harus <= 4 byte panjangnya" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "PWM restart" -msgstr "" +msgstr "Restart PWM" #: ports/raspberrypi/common-hal/countio/Counter.c msgid "PWM slice already in use" -msgstr "" +msgstr "Slice PWM sudah digunakan" #: ports/raspberrypi/common-hal/countio/Counter.c msgid "PWM slice channel A already in use" -msgstr "" +msgstr "Channel A slice PWM sudah digunakan" #: shared-bindings/spitarget/SPITarget.c msgid "Packet buffers for an SPI transfer must have the same length." -msgstr "" +msgstr "Buffer paket untuk transfer SPI harus memiliki panjang yang sama." #: shared-module/jpegio/JpegDecoder.c msgid "Parameter error" -msgstr "" +msgstr "Kesalahan parameter" #: ports/espressif/common-hal/audiobusio/__init__.c msgid "Peripheral in use" @@ -1799,7 +1804,7 @@ msgstr "Izin ditolak" #: ports/stm/common-hal/alarm/pin/PinAlarm.c msgid "Pin cannot wake from Deep Sleep" -msgstr "" +msgstr "Pin tidak dapat membangunkan dari Deep Sleep" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Pin count too large" @@ -1843,7 +1848,7 @@ msgstr "Pin harus berbagi potongan PWM" #: shared-module/usb/core/Device.c msgid "Pipe error" -msgstr "" +msgstr "Kesalahan pipe" #: py/builtinhelp.c msgid "Plus any modules on the filesystem\n" @@ -1869,7 +1874,7 @@ msgstr "" #: main.c msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "" +msgstr "Berpura-pura deep sleep sampai alarm, CTRL-C atau penulisan file.\n" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" @@ -1889,7 +1894,7 @@ msgstr "Program terlalu lama" #: shared-bindings/rclcpy/Publisher.c msgid "Publishers can only be created from a parent node" -msgstr "" +msgstr "Publisher hanya dapat dibuat dari node induk" #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." @@ -1913,23 +1918,23 @@ msgstr "Kesalahan Init RNG" #: ports/espressif/common-hal/rclcpy/__init__.c msgid "ROS failed to initialize. Is agent connected?" -msgstr "" +msgstr "ROS gagal diinisialisasi. Apakah agen terhubung?" #: ports/espressif/common-hal/rclcpy/__init__.c msgid "ROS internal setup failure" -msgstr "" +msgstr "Kegagalan pengaturan internal ROS" #: ports/espressif/common-hal/rclcpy/__init__.c msgid "ROS memory allocator failure" -msgstr "" +msgstr "Kegagalan alokator memori ROS" #: ports/espressif/common-hal/rclcpy/Node.c msgid "ROS node failed to initialize" -msgstr "" +msgstr "Node ROS gagal diinisialisasi" #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "ROS topic failed to initialize" -msgstr "" +msgstr "Topik ROS gagal diinisialisasi" #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c @@ -2003,18 +2008,18 @@ msgstr "Kartu SD Format CSD tidak didukung" #: ports/cxd56/common-hal/sdioio/SDCard.c msgid "SDCard init" -msgstr "" +msgstr "Inisialisasi SDCard" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "SDIO GetCardInfo Error %d" -msgstr "" +msgstr "Kesalahan GetCardInfo SDIO %d" #: ports/espressif/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "SDIO Init Error %x" -msgstr "" +msgstr "Kesalahan Init SDIO %x" #: ports/espressif/common-hal/busio/SPI.c msgid "SPI configuration failed" @@ -2022,7 +2027,7 @@ msgstr "Konfigurasi SPI gagal" #: ports/stm/common-hal/busio/SPI.c msgid "SPI init error" -msgstr "" +msgstr "Kesalahan inisialisasi SPI" #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" @@ -2030,7 +2035,7 @@ msgstr "Periferal SPI sedang digunakan" #: ports/stm/common-hal/busio/SPI.c msgid "SPI re-init" -msgstr "" +msgstr "Inisialisasi ulang SPI" #: shared-bindings/is31fl3741/FrameBuffer.c msgid "Scale dimensions must divide by 3" @@ -2146,7 +2151,7 @@ msgstr "Lebar ubin harus persis membagi lebar bitmap" #: shared-module/tilepalettemapper/TilePaletteMapper.c msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +msgstr "TilePaletteMapper hanya dapat diikat ke TileGrid sekali" #: shared-bindings/alarm/time/TimeAlarm.c msgid "Time is in the past." @@ -2197,12 +2202,12 @@ msgstr "Traceback (bagian terakhir dari panggilan terkini):\n" #: ports/stm/common-hal/busio/UART.c msgid "UART de-init" -msgstr "" +msgstr "De-inisialisasi UART" #: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c #: ports/stm/common-hal/busio/UART.c msgid "UART init" -msgstr "" +msgstr "Inisialisasi UART" #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" @@ -2210,11 +2215,11 @@ msgstr "Periferal UART sedang digunakan" #: ports/stm/common-hal/busio/UART.c msgid "UART re-init" -msgstr "" +msgstr "Inisialisasi ulang UART" #: ports/stm/common-hal/busio/UART.c msgid "UART write" -msgstr "" +msgstr "Penulisan UART" #: main.c msgid "UID:" @@ -2222,7 +2227,7 @@ msgstr "UID:" #: shared-module/usb_hid/Device.c msgid "USB busy" -msgstr "" +msgstr "USB sibuk" #: supervisor/shared/safe_mode.c msgid "USB devices need more endpoints than are available." @@ -2234,7 +2239,7 @@ msgstr "Perangkat USB menggunakan terlalu banyak nama antarmuka." #: shared-module/usb_hid/Device.c msgid "USB error" -msgstr "" +msgstr "Kesalahan USB" #: shared-bindings/_bleio/UUID.c msgid "UUID integer value must be 0-0xffff" @@ -2283,7 +2288,7 @@ msgstr "Tidak dapat membaca data palet warna" #: ports/mimxrt10xx/common-hal/canio/CAN.c msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" +msgstr "Tidak dapat mengirim Pesan CAN: semua buffer pesan Tx sibuk" #: ports/espressif/common-hal/mdns/Server.c #: ports/raspberrypi/common-hal/mdns/Server.c @@ -2373,7 +2378,7 @@ msgstr "" #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" -msgstr "" +msgstr "Colorspace tidak didukung" #: shared-module/displayio/bus_core.c msgid "Unsupported display bus type" @@ -2439,17 +2444,17 @@ msgstr "" #: supervisor/shared/web_workflow/web_workflow.c msgid "Wi-Fi: " -msgstr "" +msgstr "Wi-Fi: " #: ports/espressif/common-hal/wifi/Radio.c #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "WiFi tidak diaktifkan" #: main.c msgid "Woken up by alarm.\n" -msgstr "" +msgstr "Dibangunkan oleh alarm.\n" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c @@ -2528,7 +2533,7 @@ msgstr "__init __() harus mengembalikan None" #: py/objtype.c #, c-format msgid "__init__() should return None, not '%s'" -msgstr "" +msgstr "__init__() harus mengembalikan None, bukan '%s'" #: py/objobject.c msgid "__new__ arg must be a user-type" @@ -2544,7 +2549,7 @@ msgstr "alamatnya kosong" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "already playing" -msgstr "" +msgstr "sudah diputar" #: py/compile.c msgid "annotation must be an identifier" @@ -2568,15 +2573,15 @@ msgstr "Argumen argsort harus berupa ndarray" #: extmod/ulab/code/numpy/numerical.c msgid "argsort is not implemented for flattened arrays" -msgstr "" +msgstr "argsort tidak diimplementasikan untuk array yang diratakan" #: extmod/ulab/code/numpy/random/random.c msgid "argument must be None, an integer or a tuple of integers" -msgstr "" +msgstr "argumen harus None, integer atau tuple integer" #: py/compile.c msgid "argument name reused" -msgstr "" +msgstr "nama argumen digunakan kembali" #: py/argcheck.c shared-bindings/_stage/__init__.c #: shared-bindings/digitalio/DigitalInOut.c @@ -2589,15 +2594,15 @@ msgstr "argumen harus berupa ndarrays" #: extmod/ulab/code/ndarray.c msgid "array and index length must be equal" -msgstr "" +msgstr "panjang array dan indeks harus sama" #: extmod/ulab/code/numpy/io/io.c msgid "array has too many dimensions" -msgstr "" +msgstr "array memiliki terlalu banyak dimensi" #: extmod/ulab/code/ndarray.c msgid "array is too big" -msgstr "" +msgstr "array terlalu besar" #: py/objarray.c shared-bindings/alarm/SleepMemory.c #: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c @@ -2606,15 +2611,15 @@ msgstr "diperlukan array/byte di sisi kanan" #: py/asmxtensa.c msgid "asm overflow" -msgstr "" +msgstr "asm overflow" #: py/compile.c msgid "async for/with outside async function" -msgstr "" +msgstr "async for/with di luar fungsi async" #: extmod/ulab/code/numpy/numerical.c msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "" +msgstr "percobaan untuk mendapatkan (arg)min/(arg)max dari urutan kosong" #: extmod/ulab/code/numpy/numerical.c msgid "attempt to get argmin/argmax of an empty sequence" @@ -2622,27 +2627,27 @@ msgstr "berusaha mendapatkan argmin/argmax dari urutan kosong" #: py/objstr.c msgid "attributes not supported" -msgstr "" +msgstr "atribut tidak didukung" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "audio format not supported" -msgstr "" +msgstr "format audio tidak didukung" #: extmod/ulab/code/ulab_tools.c msgid "axis is out of bounds" -msgstr "" +msgstr "axis berada di luar batas" #: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c msgid "axis must be None, or an integer" -msgstr "" +msgstr "axis harus None, atau integer" #: extmod/ulab/code/numpy/numerical.c msgid "axis too long" -msgstr "" +msgstr "axis terlalu panjang" #: shared-bindings/bitmaptools/__init__.c msgid "background value out of range of target" -msgstr "" +msgstr "nilai latar belakang di luar jangkauan target" #: py/builtinevex.c msgid "bad compile mode" @@ -2654,7 +2659,7 @@ msgstr "specifier salah konversi" #: py/objstr.c msgid "bad format string" -msgstr "" +msgstr "string format salah" #: py/binary.c py/objarray.c msgid "bad typecode" @@ -2662,27 +2667,27 @@ msgstr "typecode buruk" #: py/emitnative.c msgid "binary op %q not implemented" -msgstr "" +msgstr "operasi biner %q tidak diimplementasikan" #: ports/espressif/common-hal/audiobusio/PDMIn.c msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" +msgstr "bit_depth harus 8, 16, 24, atau 32." #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" -msgstr "" +msgstr "ukuran dan kedalaman bitmap harus cocok" #: shared-bindings/bitmaptools/__init__.c msgid "bitmap sizes must match" -msgstr "" +msgstr "ukuran bitmap harus cocok" #: extmod/modrandom.c msgid "bits must be 32 or less" -msgstr "" +msgstr "bit harus 32 atau kurang" #: shared-bindings/audiofreeverb/Freeverb.c msgid "bits_per_sample must be 16" -msgstr "" +msgstr "bits_per_sample harus 16" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c #: shared-bindings/audiodelays/MultiTapDelay.c @@ -2691,19 +2696,19 @@ msgstr "" #: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c #: shared-bindings/audiomixer/Mixer.c msgid "bits_per_sample must be 8 or 16" -msgstr "" +msgstr "bits_per_sample harus 8 atau 16" #: py/emitinlinethumb.c msgid "branch not in range" -msgstr "" +msgstr "branch tidak dalam jangkauan" #: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c msgid "buffer is smaller than requested size" -msgstr "" +msgstr "buffer lebih kecil dari ukuran yang diminta" #: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c msgid "buffer size must be a multiple of element size" -msgstr "" +msgstr "ukuran buffer harus kelipatan dari ukuran elemen" #: shared-module/struct/__init__.c msgid "buffer size must match format" @@ -2711,27 +2716,27 @@ msgstr "ukuran buffer harus sesuai dengan format" #: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c msgid "buffer slices must be of equal length" -msgstr "" +msgstr "potongan buffer harus memiliki panjang yang sama" #: py/modstruct.c shared-module/struct/__init__.c msgid "buffer too small" -msgstr "" +msgstr "buffer terlalu kecil" #: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c msgid "buffer too small for requested bytes" -msgstr "" +msgstr "buffer terlalu kecil untuk byte yang diminta" #: py/emitbc.c msgid "bytecode overflow" -msgstr "" +msgstr "bytecode overflow" #: py/objarray.c msgid "bytes length not a multiple of item size" -msgstr "" +msgstr "panjang bytes bukan kelipatan dari ukuran item" #: py/objstr.c msgid "bytes value out of range" -msgstr "" +msgstr "nilai bytes di luar jangkauan" #: ports/atmel-samd/bindings/samd/Clock.c msgid "calibration is out of range" @@ -2744,7 +2749,7 @@ msgstr "kalibrasi adalah read only" #: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c #: shared-module/vectorio/Rectangle.c msgid "can only have one parent" -msgstr "" +msgstr "hanya dapat memiliki satu induk" #: py/emitinlinethumb.c msgid "can only have up to 4 parameters to Thumb assembly" @@ -2752,15 +2757,15 @@ msgstr "hanya mampu memiliki hingga 4 parameter untuk Thumb assembly" #: py/emitinlinextensa.c msgid "can only have up to 4 parameters to Xtensa assembly" -msgstr "" +msgstr "hanya dapat memiliki hingga 4 parameter untuk assembly Xtensa" #: extmod/ulab/code/ndarray.c msgid "can only specify one unknown dimension" -msgstr "" +msgstr "hanya dapat menentukan satu dimensi yang tidak diketahui" #: py/objtype.c msgid "can't add special method to already-subclassed class" -msgstr "" +msgstr "tidak dapat menambahkan metode khusus ke kelas yang sudah di-subclass" #: py/compile.c msgid "can't assign to expression" @@ -2768,50 +2773,50 @@ msgstr "tidak dapat menetapkan ke ekspresi" #: extmod/modasyncio.c msgid "can't cancel self" -msgstr "" +msgstr "tidak dapat membatalkan diri sendiri" #: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c msgid "can't convert %q to %q" -msgstr "" +msgstr "tidak dapat mengonversi %q ke %q" #: py/obj.c #, c-format msgid "can't convert %s to complex" -msgstr "" +msgstr "tidak dapat mengonversi %s ke complex" #: py/obj.c #, c-format msgid "can't convert %s to float" -msgstr "" +msgstr "tidak dapat mengonversi %s ke float" #: py/objint.c py/runtime.c #, c-format msgid "can't convert %s to int" -msgstr "" +msgstr "tidak dapat mengonversi %s ke int" #: py/objstr.c msgid "can't convert '%q' object to %q implicitly" -msgstr "" +msgstr "tidak dapat mengonversi objek '%q' ke %q secara implisit" #: extmod/ulab/code/numpy/vector.c msgid "can't convert complex to float" -msgstr "" +msgstr "tidak dapat mengonversi complex ke float" #: py/obj.c msgid "can't convert to complex" -msgstr "" +msgstr "tidak dapat mengonversi ke complex" #: py/obj.c msgid "can't convert to float" -msgstr "" +msgstr "tidak dapat mengonversi ke float" #: py/runtime.c msgid "can't convert to int" -msgstr "" +msgstr "tidak dapat mengonversi ke int" #: py/objstr.c msgid "can't convert to str implicitly" -msgstr "" +msgstr "tidak dapat mengonversi ke str secara implisit" #: py/compile.c msgid "can't declare nonlocal in outer code" @@ -2823,93 +2828,95 @@ msgstr "tidak bisa menghapus ekspresi" #: py/emitnative.c msgid "can't do binary op between '%q' and '%q'" -msgstr "" +msgstr "tidak dapat melakukan operasi biner antara '%q' dan '%q'" #: py/emitnative.c msgid "can't do unary op of '%q'" -msgstr "" +msgstr "tidak dapat melakukan operasi unary dari '%q'" #: py/emitnative.c msgid "can't implicitly convert '%q' to 'bool'" -msgstr "" +msgstr "tidak dapat mengonversi '%q' ke 'bool' secara implisit" #: py/runtime.c msgid "can't import name %q" -msgstr "" +msgstr "tidak dapat mengimpor nama %q" #: py/emitnative.c msgid "can't load from '%q'" -msgstr "" +msgstr "tidak dapat memuat dari '%q'" #: py/emitnative.c msgid "can't load with '%q' index" -msgstr "" +msgstr "tidak dapat memuat dengan indeks '%q'" #: py/builtinimport.c msgid "can't perform relative import" -msgstr "" +msgstr "tidak dapat melakukan impor relatif" #: py/objgenerator.c msgid "can't send non-None value to a just-started generator" -msgstr "" +msgstr "tidak dapat mengirim nilai non-None ke generator yang baru dimulai" #: shared-module/sdcardio/SDCard.c msgid "can't set 512 block size" -msgstr "" +msgstr "tidak dapat mengatur ukuran blok 512" #: py/objexcept.c py/objnamedtuple.c msgid "can't set attribute" -msgstr "" +msgstr "tidak dapat mengatur atribut" #: py/runtime.c msgid "can't set attribute '%q'" -msgstr "" +msgstr "tidak dapat mengatur atribut '%q'" #: py/emitnative.c msgid "can't store '%q'" -msgstr "" +msgstr "tidak dapat menyimpan '%q'" #: py/emitnative.c msgid "can't store to '%q'" -msgstr "" +msgstr "tidak dapat menyimpan ke '%q'" #: py/emitnative.c msgid "can't store with '%q' index" -msgstr "" +msgstr "tidak dapat menyimpan dengan indeks '%q'" #: py/objstr.c msgid "" "can't switch from automatic field numbering to manual field specification" msgstr "" +"tidak dapat beralih dari penomoran field otomatis ke spesifikasi field manual" #: py/objstr.c msgid "" "can't switch from manual field specification to automatic field numbering" msgstr "" +"tidak dapat beralih dari spesifikasi field manual ke penomoran field otomatis" #: py/objcomplex.c msgid "can't truncate-divide a complex number" -msgstr "" +msgstr "tidak dapat truncate-divide bilangan complex" #: extmod/modasyncio.c msgid "can't wait" -msgstr "" +msgstr "tidak dapat menunggu" #: extmod/ulab/code/ndarray.c msgid "cannot assign new shape" -msgstr "" +msgstr "tidak dapat menetapkan bentuk baru" #: extmod/ulab/code/ndarray_operators.c msgid "cannot cast output with casting rule" -msgstr "" +msgstr "tidak dapat melakukan cast output dengan aturan casting" #: extmod/ulab/code/ndarray.c msgid "cannot convert complex to dtype" -msgstr "" +msgstr "tidak dapat mengonversi complex ke dtype" #: extmod/ulab/code/ndarray.c msgid "cannot convert complex type" -msgstr "" +msgstr "tidak dapat mengonversi tipe complex" #: py/objtype.c msgid "cannot create '%q' instances" @@ -2917,71 +2924,71 @@ msgstr "" #: py/objtype.c msgid "cannot create instance" -msgstr "" +msgstr "tidak dapat membuat instance" #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" -msgstr "" +msgstr "tidak dapat menghapus elemen array" #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" -msgstr "" +msgstr "tidak dapat membentuk ulang array" #: py/emitnative.c msgid "casting" -msgstr "" +msgstr "casting" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "channel re-init" -msgstr "" +msgstr "inisialisasi ulang channel" #: shared-bindings/_stage/Text.c msgid "chars buffer too small" -msgstr "" +msgstr "buffer chars terlalu kecil" #: py/modbuiltins.c msgid "chr() arg not in range(0x110000)" -msgstr "" +msgstr "argumen chr() tidak dalam rentang(0x110000)" #: py/modbuiltins.c msgid "chr() arg not in range(256)" -msgstr "" +msgstr "argumen chr() tidak dalam rentang(256)" #: shared-bindings/bitmaptools/__init__.c msgid "clip point must be (x,y) tuple" -msgstr "" +msgstr "clip point harus berupa tuple (x,y)" #: shared-bindings/msgpack/ExtType.c msgid "code outside range 0~127" -msgstr "" +msgstr "kode di luar rentang 0~127" #: shared-bindings/displayio/Palette.c msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" -msgstr "" +msgstr "buffer warna harus 3 byte (RGB) atau 4 byte (RGB + pad byte)" #: shared-bindings/displayio/Palette.c msgid "color buffer must be a buffer, tuple, list, or int" -msgstr "" +msgstr "buffer warna harus berupa buffer, tuple, list, atau int" #: shared-bindings/displayio/Palette.c msgid "color buffer must be a bytearray or array of type 'b' or 'B'" -msgstr "" +msgstr "buffer warna harus berupa bytearray atau array bertipe 'b' atau 'B'" #: shared-bindings/displayio/Palette.c msgid "color must be between 0x000000 and 0xffffff" -msgstr "" +msgstr "warna harus antara 0x000000 dan 0xffffff" #: py/emitnative.c msgid "comparison of int and uint" -msgstr "" +msgstr "perbandingan int dan uint" #: py/objcomplex.c msgid "complex divide by zero" -msgstr "" +msgstr "pembagian complex dengan nol" #: py/objfloat.c py/parsenum.c msgid "complex values not supported" -msgstr "" +msgstr "nilai complex tidak didukung" #: extmod/modzlib.c msgid "compression header" @@ -2989,56 +2996,56 @@ msgstr "kompresi header" #: py/emitnative.c msgid "conversion to object" -msgstr "" +msgstr "konversi ke objek" #: extmod/ulab/code/numpy/filter.c msgid "convolve arguments must be linear arrays" -msgstr "" +msgstr "argumen convolve harus berupa array linear" #: extmod/ulab/code/numpy/filter.c msgid "convolve arguments must be ndarrays" -msgstr "" +msgstr "argumen convolve harus berupa ndarray" #: extmod/ulab/code/numpy/filter.c msgid "convolve arguments must not be empty" -msgstr "" +msgstr "argumen convolve tidak boleh kosong" #: extmod/ulab/code/numpy/io/io.c msgid "corrupted file" -msgstr "" +msgstr "file rusak" #: extmod/ulab/code/numpy/poly.c msgid "could not invert Vandermonde matrix" -msgstr "" +msgstr "tidak dapat membalik matriks Vandermonde" #: shared-module/sdcardio/SDCard.c msgid "couldn't determine SD card version" -msgstr "" +msgstr "tidak dapat menentukan versi kartu SD" #: extmod/ulab/code/numpy/numerical.c msgid "cross is defined for 1D arrays of length 3" -msgstr "" +msgstr "cross didefinisikan untuk array 1D dengan panjang 3" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "data must be iterable" -msgstr "" +msgstr "data harus dapat diiterasi" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "data must be of equal length" -msgstr "" +msgstr "data harus memiliki panjang yang sama" #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "data pin #%d in use" -msgstr "" +msgstr "pin data #%d sedang digunakan" #: extmod/ulab/code/ndarray.c msgid "data type not understood" -msgstr "" +msgstr "tipe data tidak dipahami" #: py/parsenum.c msgid "decimal numbers not supported" -msgstr "" +msgstr "angka desimal tidak didukung" #: py/compile.c msgid "default 'except' must be last" @@ -3046,60 +3053,62 @@ msgstr "'except' standar harus terakhir" #: shared-bindings/msgpack/__init__.c msgid "default is not a function" -msgstr "" +msgstr "default bukan fungsi" #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" +"buffer tujuan harus berupa bytearray atau array bertipe 'B' untuk bit_depth " +"= 8" #: shared-bindings/audiobusio/PDMIn.c msgid "destination buffer must be an array of type 'H' for bit_depth = 16" -msgstr "" +msgstr "buffer tujuan harus berupa array bertipe 'H' untuk bit_depth = 16" #: py/objdict.c msgid "dict update sequence has wrong length" -msgstr "" +msgstr "urutan pembaruan dict memiliki panjang yang salah" #: extmod/ulab/code/numpy/numerical.c msgid "diff argument must be an ndarray" -msgstr "" +msgstr "argumen diff harus berupa ndarray" #: extmod/ulab/code/numpy/numerical.c msgid "differentiation order out of range" -msgstr "" +msgstr "urutan diferensiasi di luar jangkauan" #: extmod/ulab/code/numpy/transform.c msgid "dimensions do not match" -msgstr "" +msgstr "dimensi tidak cocok" #: py/emitnative.c msgid "div/mod not implemented for uint" -msgstr "" +msgstr "div/mod tidak diimplementasikan untuk uint" #: extmod/ulab/code/numpy/create.c msgid "divide by zero" -msgstr "" +msgstr "pembagian dengan nol" #: py/runtime.c msgid "division by zero" -msgstr "" +msgstr "pembagian dengan nol" #: extmod/ulab/code/numpy/vector.c msgid "dtype must be float, or complex" -msgstr "" +msgstr "dtype harus float, atau complex" #: extmod/ulab/code/ndarray_operators.c msgid "dtype of int32 is not supported" -msgstr "" +msgstr "dtype int32 tidak didukung" #: py/objdeque.c msgid "empty" -msgstr "" +msgstr "kosong" #: extmod/ulab/code/numpy/io/io.c msgid "empty file" -msgstr "" +msgstr "file kosong" #: extmod/modasyncio.c extmod/modheapq.c msgid "empty heap" @@ -3107,19 +3116,19 @@ msgstr "heap kosong" #: py/objstr.c msgid "empty separator" -msgstr "" +msgstr "pemisah kosong" #: shared-bindings/random/__init__.c msgid "empty sequence" -msgstr "" +msgstr "urutan kosong" #: py/objstr.c msgid "end of format while looking for conversion specifier" -msgstr "" +msgstr "akhir format saat mencari spesifier konversi" #: shared-bindings/alarm/time/TimeAlarm.c msgid "epoch_time not supported on this board" -msgstr "" +msgstr "epoch_time tidak didukung pada board ini" #: ports/nordic/common-hal/busio/UART.c #, c-format @@ -3128,19 +3137,19 @@ msgstr "error = 0x%08lX" #: py/runtime.c msgid "exceptions must derive from BaseException" -msgstr "" +msgstr "exception harus diturunkan dari BaseException" #: py/objstr.c msgid "expected ':' after format specifier" -msgstr "" +msgstr "mengharapkan ':' setelah spesifier format" #: py/obj.c msgid "expected tuple/list" -msgstr "" +msgstr "mengharapkan tuple/list" #: py/modthread.c msgid "expecting a dict for keyword args" -msgstr "" +msgstr "mengharapkan dict untuk argumen keyword" #: py/compile.c msgid "expecting an assembler instruction" @@ -3156,7 +3165,7 @@ msgstr "key:value diharapkan untuk dict" #: shared-bindings/msgpack/__init__.c msgid "ext_hook is not a function" -msgstr "" +msgstr "ext_hook bukan fungsi" #: py/argcheck.c msgid "extra keyword arguments given" @@ -3170,11 +3179,11 @@ msgstr "argumen posisi ekstra telah diberikan" #: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c #: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c msgid "file must be a file opened in byte mode" -msgstr "" +msgstr "file harus berupa file yang dibuka dalam mode byte" #: shared-bindings/traceback/__init__.c msgid "file write is not available" -msgstr "" +msgstr "penulisan file tidak tersedia" #: shared-bindings/storage/__init__.c msgid "filesystem must provide mount method" @@ -3182,63 +3191,63 @@ msgstr "" #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" -msgstr "" +msgstr "argumen pertama harus dapat dipanggil" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "first argument must be a function" -msgstr "" +msgstr "argumen pertama harus berupa fungsi" #: extmod/ulab/code/numpy/create.c msgid "first argument must be a tuple of ndarrays" -msgstr "" +msgstr "argumen pertama harus berupa tuple ndarray" #: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c msgid "first argument must be an ndarray" -msgstr "" +msgstr "argumen pertama harus berupa ndarray" #: py/objtype.c msgid "first argument to super() must be type" -msgstr "" +msgstr "argumen pertama untuk super() harus bertipe type" #: extmod/ulab/code/scipy/linalg/linalg.c msgid "first two arguments must be ndarrays" -msgstr "" +msgstr "dua argumen pertama harus berupa ndarray" #: extmod/ulab/code/ndarray.c msgid "flattening order must be either 'C', or 'F'" -msgstr "" +msgstr "urutan perataan harus 'C', atau 'F'" #: extmod/ulab/code/numpy/numerical.c msgid "flip argument must be an ndarray" -msgstr "" +msgstr "argumen flip harus berupa ndarray" #: py/objint.c msgid "float too big" -msgstr "" +msgstr "float terlalu besar" #: py/nativeglue.c msgid "float unsupported" -msgstr "" +msgstr "float tidak didukung" #: shared-bindings/_stage/Text.c msgid "font must be 2048 bytes long" -msgstr "" +msgstr "font harus sepanjang 2048 byte" #: extmod/moddeflate.c msgid "format" -msgstr "" +msgstr "format" #: py/objstr.c msgid "format needs a dict" -msgstr "" +msgstr "format memerlukan dict" #: py/objdeque.c msgid "full" -msgstr "" +msgstr "penuh" #: py/argcheck.c msgid "function doesn't take keyword arguments" -msgstr "" +msgstr "fungsi tidak menerima argumen keyword" #: py/argcheck.c #, c-format @@ -3251,15 +3260,15 @@ msgstr "fungsi mendapatkan nilai ganda untuk argumen '%q'" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "function has the same sign at the ends of interval" -msgstr "" +msgstr "fungsi memiliki tanda yang sama pada ujung interval" #: extmod/ulab/code/ndarray.c msgid "function is defined for ndarrays only" -msgstr "" +msgstr "fungsi didefinisikan hanya untuk ndarray" #: extmod/ulab/code/numpy/carray/carray.c msgid "function is implemented for ndarrays only" -msgstr "" +msgstr "fungsi diimplementasikan hanya untuk ndarray" #: py/argcheck.c #, c-format @@ -3287,23 +3296,23 @@ msgstr "fungsi mengambil posisi argumen %d tapi %d yang diberikan" #: py/objgenerator.c msgid "generator already executing" -msgstr "" +msgstr "generator sudah berjalan" #: py/objgenerator.c msgid "generator ignored GeneratorExit" -msgstr "" +msgstr "generator mengabaikan GeneratorExit" #: py/objgenerator.c py/runtime.c msgid "generator raised StopIteration" -msgstr "" +msgstr "generator memunculkan StopIteration" #: shared-bindings/_stage/Layer.c msgid "graphic must be 2048 bytes long" -msgstr "" +msgstr "grafik harus sepanjang 2048 byte" #: extmod/modhashlib.c msgid "hash is final" -msgstr "" +msgstr "hash bersifat final" #: extmod/modheapq.c msgid "heap must be a list" @@ -3319,23 +3328,23 @@ msgstr "identifier didefinisi ulang sebagai nonlocal" #: py/compile.c msgid "import * not at module level" -msgstr "" +msgstr "import * tidak pada tingkat modul" #: py/persistentcode.c msgid "incompatible .mpy arch" -msgstr "" +msgstr "arsitektur .mpy tidak kompatibel" #: py/persistentcode.c msgid "incompatible .mpy file" -msgstr "" +msgstr "file .mpy tidak kompatibel" #: py/objstr.c msgid "incomplete format" -msgstr "" +msgstr "format tidak lengkap" #: py/objstr.c msgid "incomplete format key" -msgstr "" +msgstr "kunci format tidak lengkap" #: extmod/modbinascii.c msgid "incorrect padding" @@ -3343,11 +3352,11 @@ msgstr "lapisan (padding) tidak benar" #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c msgid "index is out of bounds" -msgstr "" +msgstr "indeks berada di luar batas" #: shared-bindings/_pixelmap/PixelMap.c msgid "index must be tuple or int" -msgstr "" +msgstr "indeks harus berupa tuple atau int" #: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c #: ports/espressif/common-hal/pulseio/PulseIn.c @@ -3357,19 +3366,19 @@ msgstr "index keluar dari jangkauan" #: py/obj.c msgid "indices must be integers" -msgstr "" +msgstr "indeks harus berupa integer" #: extmod/ulab/code/ndarray.c msgid "indices must be integers, slices, or Boolean lists" -msgstr "" +msgstr "indeks harus berupa integer, slice, atau list Boolean" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "initial values must be iterable" -msgstr "" +msgstr "nilai awal harus dapat diiterasi" #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c msgid "initial_value length is wrong" -msgstr "" +msgstr "panjang initial_value salah" #: py/compile.c msgid "inline assembler must be a function" @@ -3377,98 +3386,98 @@ msgstr "inline assembler harus sebuah fungsi" #: extmod/ulab/code/numpy/vector.c msgid "input and output dimensions differ" -msgstr "" +msgstr "dimensi input dan output berbeda" #: extmod/ulab/code/numpy/vector.c msgid "input and output shapes differ" -msgstr "" +msgstr "bentuk input dan output berbeda" #: extmod/ulab/code/numpy/create.c msgid "input argument must be an integer, a tuple, or a list" -msgstr "" +msgstr "argumen input harus berupa integer, tuple, atau list" #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "input array length must be power of 2" -msgstr "" +msgstr "panjang array input harus pangkat 2" #: extmod/ulab/code/numpy/create.c msgid "input arrays are not compatible" -msgstr "" +msgstr "array input tidak kompatibel" #: extmod/ulab/code/numpy/poly.c msgid "input data must be an iterable" -msgstr "" +msgstr "data input harus dapat diiterasi" #: extmod/ulab/code/numpy/vector.c msgid "input dtype must be float or complex" -msgstr "" +msgstr "dtype input harus float atau complex" #: extmod/ulab/code/numpy/poly.c msgid "input is not iterable" -msgstr "" +msgstr "input tidak dapat diiterasi" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "input matrix is asymmetric" -msgstr "" +msgstr "matriks input asimetris" #: extmod/ulab/code/numpy/linalg/linalg.c #: extmod/ulab/code/scipy/linalg/linalg.c msgid "input matrix is singular" -msgstr "" +msgstr "matriks input singular" #: extmod/ulab/code/numpy/create.c msgid "input must be 1- or 2-d" -msgstr "" +msgstr "input harus 1- atau 2-d" #: extmod/ulab/code/numpy/carray/carray.c msgid "input must be a 1D ndarray" -msgstr "" +msgstr "input harus berupa ndarray 1D" #: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c msgid "input must be a dense ndarray" -msgstr "" +msgstr "input harus berupa ndarray padat" #: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c msgid "input must be an ndarray" -msgstr "" +msgstr "input harus berupa ndarray" #: extmod/ulab/code/numpy/carray/carray.c msgid "input must be an ndarray, or a scalar" -msgstr "" +msgstr "input harus berupa ndarray, atau skalar" #: extmod/ulab/code/scipy/signal/signal.c msgid "input must be one-dimensional" -msgstr "" +msgstr "input harus satu dimensi" #: extmod/ulab/code/ulab_tools.c msgid "input must be square matrix" -msgstr "" +msgstr "input harus berupa matriks persegi" #: extmod/ulab/code/numpy/numerical.c msgid "input must be tuple, list, range, or ndarray" -msgstr "" +msgstr "input harus berupa tuple, list, range, atau ndarray" #: extmod/ulab/code/numpy/poly.c msgid "input vectors must be of equal length" -msgstr "" +msgstr "vektor input harus memiliki panjang yang sama" #: extmod/ulab/code/numpy/approx.c msgid "interp is defined for 1D iterables of equal length" -msgstr "" +msgstr "interp didefinisikan untuk iterable 1D dengan panjang yang sama" #: shared-bindings/_bleio/Adapter.c #, c-format msgid "interval must be in range %s-%s" -msgstr "" +msgstr "interval harus dalam rentang %s-%s" #: py/compile.c msgid "invalid arch" -msgstr "" +msgstr "arsitektur tidak valid" #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" -msgstr "" +msgstr "bits_per_pixel %d tidak valid, harus 1, 2, 4, 8, 16, 24, atau 32" #: shared-module/ssl/SSLSocket.c msgid "invalid cert" @@ -3477,24 +3486,24 @@ msgstr "cert tidak valid" #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" -msgstr "" +msgstr "element size %d tidak valid untuk bits_per_pixel %d\n" #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element_size %d, must be, 1, 2, or 4" -msgstr "" +msgstr "element_size %d tidak valid, harus 1, 2, atau 4" #: shared-bindings/traceback/__init__.c msgid "invalid exception" -msgstr "" +msgstr "exception tidak valid" #: py/objstr.c msgid "invalid format specifier" -msgstr "" +msgstr "spesifier format tidak valid" #: shared-bindings/wifi/Radio.c msgid "invalid hostname" -msgstr "" +msgstr "hostname tidak valid" #: shared-module/ssl/SSLSocket.c msgid "invalid key" @@ -3506,11 +3515,11 @@ msgstr "micropython decorator tidak valid" #: ports/espressif/common-hal/espcamera/Camera.c msgid "invalid setting" -msgstr "" +msgstr "pengaturan tidak valid" #: shared-bindings/random/__init__.c msgid "invalid step" -msgstr "" +msgstr "step tidak valid" #: py/compile.c py/parse.c msgid "invalid syntax" @@ -3518,40 +3527,42 @@ msgstr "syntax tidak valid" #: py/parsenum.c msgid "invalid syntax for integer" -msgstr "" +msgstr "sintaks tidak valid untuk integer" #: py/parsenum.c #, c-format msgid "invalid syntax for integer with base %d" -msgstr "" +msgstr "sintaks tidak valid untuk integer dengan basis %d" #: py/parsenum.c msgid "invalid syntax for number" -msgstr "" +msgstr "sintaks tidak valid untuk angka" #: py/objtype.c msgid "issubclass() arg 1 must be a class" -msgstr "" +msgstr "argumen 1 issubclass() harus berupa class" #: py/objtype.c msgid "issubclass() arg 2 must be a class or a tuple of classes" -msgstr "" +msgstr "argumen 2 issubclass() harus berupa class atau tuple class" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "iterations did not converge" -msgstr "" +msgstr "iterasi tidak konvergen" #: py/objstr.c msgid "join expects a list of str/bytes objects consistent with self object" -msgstr "" +msgstr "join mengharapkan list objek str/bytes yang konsisten dengan objek self" #: py/argcheck.c msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" +"argumen keyword tidak diimplementasikan - gunakan argumen normal sebagai " +"gantinya" #: py/emitinlinethumb.c py/emitinlinextensa.c msgid "label '%q' not defined" -msgstr "" +msgstr "label '%q' tidak didefinisikan" #: py/compile.c msgid "label redefined" @@ -3559,101 +3570,101 @@ msgstr "label didefinis ulang" #: py/objarray.c msgid "lhs and rhs should be compatible" -msgstr "" +msgstr "lhs dan rhs harus kompatibel" #: py/emitnative.c msgid "local '%q' has type '%q' but source is '%q'" -msgstr "" +msgstr "lokal '%q' memiliki tipe '%q' tetapi sumber adalah '%q'" #: py/emitnative.c msgid "local '%q' used before type known" -msgstr "" +msgstr "lokal '%q' digunakan sebelum tipe diketahui" #: py/vm.c msgid "local variable referenced before assignment" -msgstr "" +msgstr "variabel lokal direferensikan sebelum penetapan" #: ports/espressif/common-hal/canio/CAN.c msgid "loopback + silent mode not supported by peripheral" -msgstr "" +msgstr "mode loopback + silent tidak didukung oleh periferal" #: ports/espressif/common-hal/mdns/Server.c #: ports/raspberrypi/common-hal/mdns/Server.c msgid "mDNS already initialized" -msgstr "" +msgstr "mDNS sudah diinisialisasi" #: ports/espressif/common-hal/mdns/Server.c #: ports/raspberrypi/common-hal/mdns/Server.c msgid "mDNS only works with built-in WiFi" -msgstr "" +msgstr "mDNS hanya bekerja dengan WiFi bawaan" #: py/parse.c msgid "malformed f-string" -msgstr "" +msgstr "f-string salah bentuk" #: shared-bindings/_stage/Layer.c msgid "map buffer too small" -msgstr "" +msgstr "buffer peta terlalu kecil" #: py/modmath.c shared-bindings/math/__init__.c msgid "math domain error" -msgstr "" +msgstr "kesalahan domain matematika" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "matrix is not positive definite" -msgstr "" +msgstr "matriks tidak definit positif" #: ports/espressif/common-hal/_bleio/Descriptor.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c #, c-format msgid "max_length must be 0-%d when fixed_length is %s" -msgstr "" +msgstr "max_length harus 0-%d ketika fixed_length adalah %s" #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c msgid "maximum number of dimensions is " -msgstr "" +msgstr "jumlah maksimum dimensi adalah " #: py/runtime.c msgid "maximum recursion depth exceeded" -msgstr "" +msgstr "kedalaman rekursi maksimum terlampaui" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "maxiter must be > 0" -msgstr "" +msgstr "maxiter harus > 0" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "maxiter should be > 0" -msgstr "" +msgstr "maxiter harus > 0" #: extmod/ulab/code/numpy/numerical.c msgid "median argument must be an ndarray" -msgstr "" +msgstr "argumen median harus berupa ndarray" #: py/runtime.c #, c-format msgid "memory allocation failed, allocating %u bytes" -msgstr "" +msgstr "alokasi memori gagal, mengalokasikan %u byte" #: py/runtime.c msgid "memory allocation failed, heap is locked" -msgstr "" +msgstr "alokasi memori gagal, heap terkunci" #: py/objarray.c msgid "memoryview offset too large" -msgstr "" +msgstr "offset memoryview terlalu besar" #: py/objarray.c msgid "memoryview: length is not a multiple of itemsize" -msgstr "" +msgstr "memoryview: panjang bukan kelipatan dari itemsize" #: extmod/modtime.c msgid "mktime needs a tuple of length 8 or 9" -msgstr "" +msgstr "mktime memerlukan tuple dengan panjang 8 atau 9" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "mode must be complete, or reduced" -msgstr "" +msgstr "mode harus complete, atau reduced" #: py/builtinimport.c msgid "module not found" @@ -3661,11 +3672,11 @@ msgstr "modul tidak ditemukan" #: ports/espressif/common-hal/wifi/Monitor.c msgid "monitor init failed" -msgstr "" +msgstr "inisialisasi monitor gagal" #: extmod/ulab/code/numpy/poly.c msgid "more degrees of freedom than data points" -msgstr "" +msgstr "lebih banyak derajat kebebasan daripada titik data" #: py/compile.c msgid "multiple *x in assignment" @@ -3673,76 +3684,76 @@ msgstr "perkalian *x dalam assignment" #: py/objtype.c msgid "multiple bases have instance lay-out conflict" -msgstr "" +msgstr "beberapa basis memiliki konflik tata letak instance" #: py/objtype.c msgid "multiple inheritance not supported" -msgstr "" +msgstr "pewarisan berganda tidak didukung" #: py/emitnative.c msgid "must raise an object" -msgstr "" +msgstr "harus memunculkan objek" #: py/modbuiltins.c msgid "must use keyword argument for key function" -msgstr "" +msgstr "harus menggunakan argumen keyword untuk fungsi kunci" #: py/runtime.c msgid "name '%q' isn't defined" -msgstr "" +msgstr "nama '%q' tidak didefinisikan" #: py/runtime.c msgid "name not defined" -msgstr "" +msgstr "nama tidak didefinisikan" #: py/qstr.c msgid "name too long" -msgstr "" +msgstr "nama terlalu panjang" #: py/persistentcode.c msgid "native code in .mpy unsupported" -msgstr "" +msgstr "kode native dalam .mpy tidak didukung" #: py/asmthumb.c msgid "native method too big" -msgstr "" +msgstr "metode native terlalu besar" #: py/emitnative.c msgid "native yield" -msgstr "" +msgstr "yield native" #: extmod/ulab/code/ndarray.c msgid "ndarray length overflows" -msgstr "" +msgstr "panjang ndarray meluap" #: py/runtime.c #, c-format msgid "need more than %d values to unpack" -msgstr "" +msgstr "memerlukan lebih dari %d nilai untuk membongkar" #: py/modmath.c msgid "negative factorial" -msgstr "" +msgstr "faktorial negatif" #: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative power with no float support" -msgstr "" +msgstr "pangkat negatif tanpa dukungan float" #: py/objint_mpz.c py/runtime.c msgid "negative shift count" -msgstr "" +msgstr "jumlah shift negatif" #: shared-bindings/_pixelmap/PixelMap.c msgid "nested index must be int" -msgstr "" +msgstr "indeks bersarang harus int" #: shared-module/sdcardio/SDCard.c msgid "no SD card" -msgstr "" +msgstr "tidak ada kartu SD" #: py/vm.c msgid "no active exception to reraise" -msgstr "" +msgstr "tidak ada exception aktif untuk dimunculkan kembali" #: py/compile.c msgid "no binding for nonlocal found" @@ -3750,11 +3761,11 @@ msgstr "tidak ada ikatan/bind pada temuan nonlocal" #: shared-module/msgpack/__init__.c msgid "no default packer" -msgstr "" +msgstr "tidak ada packer default" #: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c msgid "no default seed" -msgstr "" +msgstr "tidak ada seed default" #: py/builtinimport.c msgid "no module named '%q'" @@ -3762,16 +3773,16 @@ msgstr "tidak ada modul yang bernama '%q'" #: shared-module/sdcardio/SDCard.c msgid "no response from SD card" -msgstr "" +msgstr "tidak ada respons dari kartu SD" #: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c msgid "no such attribute" -msgstr "" +msgstr "atribut tidak ada" #: ports/espressif/common-hal/_bleio/Connection.c #: ports/nordic/common-hal/_bleio/Connection.c msgid "non-UUID found in service_uuids_whitelist" -msgstr "" +msgstr "non-UUID ditemukan dalam service_uuids_whitelist" #: py/compile.c msgid "non-default argument follows default argument" @@ -3783,19 +3794,19 @@ msgstr "digit non-hex ditemukan" #: ports/nordic/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" -msgstr "" +msgstr "timeout non-nol harus > 0.01" #: shared-bindings/_bleio/Adapter.c msgid "non-zero timeout must be >= interval" -msgstr "" +msgstr "timeout non-nol harus >= interval" #: shared-bindings/_bleio/UUID.c msgid "not a 128-bit UUID" -msgstr "" +msgstr "bukan UUID 128-bit" #: py/parse.c msgid "not a constant" -msgstr "" +msgstr "bukan konstanta" #: py/objstr.c msgid "not all arguments converted during string formatting" @@ -3807,65 +3818,65 @@ msgstr "" #: extmod/ulab/code/numpy/carray/carray_tools.c msgid "not implemented for complex dtype" -msgstr "" +msgstr "tidak diimplementasikan untuk dtype complex" #: extmod/ulab/code/numpy/bitwise.c msgid "not supported for input types" -msgstr "" +msgstr "tidak didukung untuk tipe input" #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" -msgstr "" +msgstr "jumlah titik harus setidaknya 2" #: py/builtinhelp.c msgid "object " -msgstr "" +msgstr "objek " #: py/obj.c #, c-format msgid "object '%s' isn't a tuple or list" -msgstr "" +msgstr "objek '%s' bukan tuple atau list" #: py/obj.c msgid "object doesn't support item assignment" -msgstr "" +msgstr "objek tidak mendukung penetapan item" #: py/obj.c msgid "object doesn't support item deletion" -msgstr "" +msgstr "objek tidak mendukung penghapusan item" #: py/obj.c msgid "object has no len" -msgstr "" +msgstr "objek tidak memiliki len" #: py/obj.c msgid "object isn't subscriptable" -msgstr "" +msgstr "objek tidak dapat disubskripsikan" #: py/runtime.c msgid "object not an iterator" -msgstr "" +msgstr "objek bukan iterator" #: py/objtype.c py/runtime.c msgid "object not callable" -msgstr "" +msgstr "objek tidak dapat dipanggil" #: py/sequence.c shared-bindings/displayio/Group.c msgid "object not in sequence" -msgstr "" +msgstr "objek tidak dalam urutan" #: py/runtime.c msgid "object not iterable" -msgstr "" +msgstr "objek tidak dapat diiterasi" #: py/obj.c #, c-format msgid "object of type '%s' has no len()" -msgstr "" +msgstr "objek bertipe '%s' tidak memiliki len()" #: py/obj.c msgid "object with buffer protocol required" -msgstr "" +msgstr "objek dengan protokol buffer diperlukan" #: py/objstr.c msgid "odd-length string" @@ -3873,146 +3884,146 @@ msgstr "panjang data string memiliki keganjilan (odd-length)" #: supervisor/shared/web_workflow/web_workflow.c msgid "off" -msgstr "" +msgstr "mati" #: extmod/ulab/code/utils/utils.c msgid "offset is too large" -msgstr "" +msgstr "offset terlalu besar" #: shared-bindings/dualbank/__init__.c msgid "offset must be >= 0" -msgstr "" +msgstr "offset harus >= 0" #: extmod/ulab/code/numpy/create.c msgid "offset must be non-negative and no greater than buffer length" -msgstr "" +msgstr "offset harus non-negatif dan tidak lebih besar dari panjang buffer" #: ports/nordic/common-hal/audiobusio/PDMIn.c #: ports/stm/common-hal/audiobusio/PDMIn.c msgid "only bit_depth=16 is supported" -msgstr "" +msgstr "hanya bit_depth=16 yang didukung" #: ports/stm/common-hal/audiobusio/PDMIn.c msgid "only mono is supported" -msgstr "" +msgstr "hanya mono yang didukung" #: extmod/ulab/code/numpy/create.c msgid "only ndarrays can be concatenated" -msgstr "" +msgstr "hanya ndarray yang dapat digabungkan" #: ports/stm/common-hal/audiobusio/PDMIn.c msgid "only oversample=64 is supported" -msgstr "" +msgstr "hanya oversample=64 yang didukung" #: ports/nordic/common-hal/audiobusio/PDMIn.c #: ports/stm/common-hal/audiobusio/PDMIn.c msgid "only sample_rate=16000 is supported" -msgstr "" +msgstr "hanya sample_rate=16000 yang didukung" #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" -msgstr "" +msgstr "hanya slice dengan step=1 (alias None) yang didukung" #: py/vm.c msgid "opcode" -msgstr "" +msgstr "opcode" #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c #: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c msgid "operands could not be broadcast together" -msgstr "" +msgstr "operan tidak dapat di-broadcast bersama" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "operation is defined for 2D arrays only" -msgstr "" +msgstr "operasi didefinisikan hanya untuk array 2D" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "operation is defined for ndarrays only" -msgstr "" +msgstr "operasi didefinisikan hanya untuk ndarray" #: extmod/ulab/code/ndarray.c msgid "operation is implemented for 1D Boolean arrays only" -msgstr "" +msgstr "operasi diimplementasikan hanya untuk array Boolean 1D" #: extmod/ulab/code/numpy/numerical.c msgid "operation is not implemented on ndarrays" -msgstr "" +msgstr "operasi tidak diimplementasikan pada ndarray" #: extmod/ulab/code/ndarray.c msgid "operation is not supported for given type" -msgstr "" +msgstr "operasi tidak didukung untuk tipe yang diberikan" #: extmod/ulab/code/ndarray_operators.c msgid "operation not supported for the input types" -msgstr "" +msgstr "operasi tidak didukung untuk tipe input" #: py/modbuiltins.c msgid "ord expects a character" -msgstr "" +msgstr "ord mengharapkan karakter" #: py/modbuiltins.c #, c-format msgid "ord() expected a character, but string of length %d found" -msgstr "" +msgstr "ord() mengharapkan karakter, tetapi string dengan panjang %d ditemukan" #: extmod/ulab/code/utils/utils.c msgid "out array is too small" -msgstr "" +msgstr "array out terlalu kecil" #: extmod/ulab/code/numpy/random/random.c msgid "out has wrong type" -msgstr "" +msgstr "out memiliki tipe yang salah" #: extmod/ulab/code/numpy/vector.c msgid "out keyword is not supported for complex dtype" -msgstr "" +msgstr "keyword out tidak didukung untuk dtype complex" #: extmod/ulab/code/numpy/vector.c msgid "out keyword is not supported for function" -msgstr "" +msgstr "keyword out tidak didukung untuk fungsi" #: extmod/ulab/code/utils/utils.c msgid "out must be a float dense array" -msgstr "" +msgstr "out harus berupa array padat float" #: extmod/ulab/code/numpy/vector.c msgid "out must be an ndarray" -msgstr "" +msgstr "out harus berupa ndarray" #: extmod/ulab/code/numpy/vector.c msgid "out must be of float dtype" -msgstr "" +msgstr "out harus bertipe dtype float" #: shared-bindings/bitmaptools/__init__.c msgid "out of range of target" -msgstr "" +msgstr "di luar jangkauan target" #: extmod/ulab/code/numpy/random/random.c msgid "output array has wrong type" -msgstr "" +msgstr "array output memiliki tipe yang salah" #: extmod/ulab/code/numpy/random/random.c msgid "output array must be contiguous" -msgstr "" +msgstr "array output harus berdekatan" #: py/objint_mpz.c msgid "overflow converting long int to machine word" -msgstr "" +msgstr "overflow saat mengonversi long int ke machine word" #: py/modstruct.c #, c-format msgid "pack expected %d items for packing (got %d)" -msgstr "" +msgstr "pack mengharapkan %d item untuk packing (mendapat %d)" #: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c msgid "palette must be 32 bytes long" -msgstr "" +msgstr "palet harus sepanjang 32 byte" #: py/emitinlinextensa.c msgid "parameters must be registers in sequence a2 to a5" -msgstr "" +msgstr "parameter harus berupa register dalam urutan a2 hingga a5" #: py/emitinlinethumb.c msgid "parameters must be registers in sequence r0 to r3" @@ -4020,7 +4031,7 @@ msgstr "parameter harus menjadi register dalam urutan r0 sampai r3" #: extmod/vfs_posix_file.c msgid "poll on file not available on win32" -msgstr "" +msgstr "poll pada file tidak tersedia di win32" #: ports/espressif/common-hal/pulseio/PulseIn.c msgid "pop from an empty PulseIn" @@ -4033,31 +4044,31 @@ msgstr "Muncul dari PulseIn yang kosong" #: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c #: shared-bindings/ps2io/Ps2.c msgid "pop from empty %q" -msgstr "" +msgstr "pop dari %q kosong" #: shared-bindings/socketpool/Socket.c msgid "port must be >= 0" -msgstr "" +msgstr "port harus >= 0" #: py/compile.c msgid "positional arg after **" -msgstr "" +msgstr "argumen posisional setelah **" #: py/compile.c msgid "positional arg after keyword arg" -msgstr "" +msgstr "argumen posisional setelah argumen keyword" #: py/objint_mpz.c msgid "pow() 3rd argument cannot be 0" -msgstr "" +msgstr "argumen ketiga pow() tidak boleh 0" #: py/objint_mpz.c msgid "pow() with 3 arguments requires integers" -msgstr "" +msgstr "pow() dengan 3 argumen memerlukan integer" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "pull masks conflict with direction masks" -msgstr "" +msgstr "mask pull berkonflik dengan mask arah" #: py/parse.c msgid "raw f-strings are not supported" @@ -4065,7 +4076,7 @@ msgstr "" #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "real and imaginary parts must be of equal length" -msgstr "" +msgstr "bagian real dan imajiner harus memiliki panjang yang sama" #: py/builtinimport.c msgid "relative import" @@ -4074,11 +4085,11 @@ msgstr "impor relatif" #: py/obj.c #, c-format msgid "requested length %d but object has length %d" -msgstr "" +msgstr "panjang yang diminta %d tetapi objek memiliki panjang %d" #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" -msgstr "" +msgstr "hasil tidak dapat di-cast ke tipe yang ditentukan" #: py/compile.c msgid "return annotation must be an identifier" @@ -4086,29 +4097,29 @@ msgstr "anotasi return harus sebuah identifier" #: py/emitnative.c msgid "return expected '%q' but got '%q'" -msgstr "" +msgstr "return mengharapkan '%q' tetapi mendapat '%q'" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format msgid "rgb_pins[%d] duplicates another pin assignment" -msgstr "" +msgstr "rgb_pins[%d] menduplikasi penetapan pin lain" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format msgid "rgb_pins[%d] is not on the same port as clock" -msgstr "" +msgstr "rgb_pins[%d] tidak pada port yang sama dengan clock" #: extmod/ulab/code/numpy/numerical.c msgid "roll argument must be an ndarray" -msgstr "" +msgstr "argumen roll harus berupa ndarray" #: py/objstr.c msgid "rsplit(None,n)" -msgstr "" +msgstr "rsplit(None,n)" #: shared-bindings/audiofreeverb/Freeverb.c msgid "samples_signed must be true" -msgstr "" +msgstr "samples_signed harus true" #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -4117,7 +4128,7 @@ msgstr "nilai sampling keluar dari jangkauan" #: py/modmicropython.c msgid "schedule queue full" -msgstr "" +msgstr "antrian jadwal penuh" #: py/builtinimport.c msgid "script compilation not supported" @@ -4125,43 +4136,43 @@ msgstr "kompilasi script tidak didukung" #: py/nativeglue.c msgid "set unsupported" -msgstr "" +msgstr "set tidak didukung" #: extmod/ulab/code/numpy/random/random.c msgid "shape must be None, and integer or a tuple of integers" -msgstr "" +msgstr "shape harus None, dan integer atau tuple integer" #: extmod/ulab/code/ndarray.c msgid "shape must be integer or tuple of integers" -msgstr "" +msgstr "shape harus integer atau tuple integer" #: shared-module/msgpack/__init__.c msgid "short read" -msgstr "" +msgstr "pembacaan pendek" #: py/objstr.c msgid "sign not allowed in string format specifier" -msgstr "" +msgstr "tanda tidak diperbolehkan dalam spesifier format string" #: py/objstr.c msgid "sign not allowed with integer format specifier 'c'" -msgstr "" +msgstr "tanda tidak diperbolehkan dengan spesifier format integer 'c'" #: extmod/ulab/code/ulab_tools.c msgid "size is defined for ndarrays only" -msgstr "" +msgstr "size didefinisikan hanya untuk ndarray" #: extmod/ulab/code/numpy/random/random.c msgid "size must match out.shape when used together" -msgstr "" +msgstr "size harus cocok dengan out.shape ketika digunakan bersama" #: py/nativeglue.c msgid "slice unsupported" -msgstr "" +msgstr "slice tidak didukung" #: py/objint.c py/sequence.c msgid "small int overflow" -msgstr "" +msgstr "overflow int kecil" #: main.c msgid "soft reboot\n" @@ -4169,39 +4180,39 @@ msgstr "memulai ulang software(soft reboot)\n" #: extmod/ulab/code/numpy/numerical.c msgid "sort argument must be an ndarray" -msgstr "" +msgstr "argumen sort harus berupa ndarray" #: extmod/ulab/code/scipy/signal/signal.c msgid "sos array must be of shape (n_section, 6)" -msgstr "" +msgstr "array sos harus berbentuk (n_section, 6)" #: extmod/ulab/code/scipy/signal/signal.c msgid "sos[:, 3] should be all ones" -msgstr "" +msgstr "sos[:, 3] harus semuanya satu" #: extmod/ulab/code/scipy/signal/signal.c msgid "sosfilt requires iterable arguments" -msgstr "" +msgstr "sosfilt memerlukan argumen yang dapat diiterasi" #: shared-bindings/bitmaptools/__init__.c msgid "source palette too large" -msgstr "" +msgstr "palet sumber terlalu besar" #: shared-bindings/bitmaptools/__init__.c msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "" +msgstr "source_bitmap harus memiliki value_count 2 atau 65536" #: shared-bindings/bitmaptools/__init__.c msgid "source_bitmap must have value_count of 65536" -msgstr "" +msgstr "source_bitmap harus memiliki value_count 65536" #: shared-bindings/bitmaptools/__init__.c msgid "source_bitmap must have value_count of 8" -msgstr "" +msgstr "source_bitmap harus memiliki value_count 8" #: extmod/modre.c msgid "splitting with sub-captures" -msgstr "" +msgstr "pemisahan dengan sub-capture" #: py/objstr.c msgid "start/end indices" @@ -4209,28 +4220,28 @@ msgstr "" #: shared-bindings/random/__init__.c msgid "stop not reachable from start" -msgstr "" +msgstr "stop tidak dapat dijangkau dari start" #: py/stream.c shared-bindings/getpass/__init__.c msgid "stream operation not supported" -msgstr "" +msgstr "operasi stream tidak didukung" #: py/objarray.c py/objstr.c msgid "string argument without an encoding" -msgstr "" +msgstr "argumen string tanpa encoding" #: py/objstrunicode.c msgid "string index out of range" -msgstr "" +msgstr "indeks string di luar jangkauan" #: py/objstrunicode.c #, c-format msgid "string indices must be integers, not %s" -msgstr "" +msgstr "indeks string harus integer, bukan %s" #: py/objarray.c py/objstr.c msgid "substring not found" -msgstr "" +msgstr "substring tidak ditemukan" #: py/compile.c msgid "super() can't find self" @@ -4242,87 +4253,87 @@ msgstr "sintaksis error pada JSON" #: extmod/modtime.c msgid "ticks interval overflow" -msgstr "" +msgstr "overflow interval tick" #: ports/nordic/common-hal/watchdog/WatchDogTimer.c msgid "timeout duration exceeded the maximum supported value" -msgstr "" +msgstr "durasi timeout melebihi nilai maksimum yang didukung" #: ports/nordic/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" -msgstr "" +msgstr "timeout harus < 655.35 detik" #: ports/raspberrypi/common-hal/floppyio/__init__.c msgid "timeout waiting for flux" -msgstr "" +msgstr "timeout menunggu flux" #: ports/raspberrypi/common-hal/floppyio/__init__.c #: shared-module/floppyio/__init__.c msgid "timeout waiting for index pulse" -msgstr "" +msgstr "timeout menunggu pulsa indeks" #: shared-module/sdcardio/SDCard.c msgid "timeout waiting for v1 card" -msgstr "" +msgstr "timeout menunggu kartu v1" #: shared-module/sdcardio/SDCard.c msgid "timeout waiting for v2 card" -msgstr "" +msgstr "timeout menunggu kartu v2" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "timer re-init" -msgstr "" +msgstr "inisialisasi ulang timer" #: shared-bindings/time/__init__.c msgid "timestamp out of range for platform time_t" -msgstr "" +msgstr "timestamp di luar jangkauan untuk time_t platform" #: extmod/ulab/code/ndarray.c msgid "tobytes can be invoked for dense arrays only" -msgstr "" +msgstr "tobytes hanya dapat dipanggil untuk array padat" #: py/compile.c msgid "too many args" -msgstr "" +msgstr "terlalu banyak argumen" #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c msgid "too many dimensions" -msgstr "" +msgstr "terlalu banyak dimensi" #: extmod/ulab/code/ndarray.c msgid "too many indices" -msgstr "" +msgstr "terlalu banyak indeks" #: py/asmthumb.c msgid "too many locals for native method" -msgstr "" +msgstr "terlalu banyak lokal untuk metode native" #: py/runtime.c #, c-format msgid "too many values to unpack (expected %d)" -msgstr "" +msgstr "terlalu banyak nilai untuk dibongkar (diharapkan %d)" #: extmod/ulab/code/numpy/approx.c msgid "trapz is defined for 1D arrays of equal length" -msgstr "" +msgstr "trapz didefinisikan untuk array 1D dengan panjang yang sama" #: extmod/ulab/code/numpy/approx.c msgid "trapz is defined for 1D iterables" -msgstr "" +msgstr "trapz didefinisikan untuk iterable 1D" #: py/obj.c msgid "tuple/list has wrong length" -msgstr "" +msgstr "tuple/list memiliki panjang yang salah" #: ports/espressif/common-hal/canio/CAN.c #, c-format msgid "twai_driver_install returned esp-idf error #%d" -msgstr "" +msgstr "twai_driver_install mengembalikan kesalahan esp-idf #%d" #: ports/espressif/common-hal/canio/CAN.c #, c-format msgid "twai_start returned esp-idf error #%d" -msgstr "" +msgstr "twai_start mengembalikan kesalahan esp-idf #%d" #: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c msgid "tx and rx cannot both be None" @@ -4330,27 +4341,27 @@ msgstr "tx dan rx keduanya tidak boleh kosong" #: py/objtype.c msgid "type '%q' isn't an acceptable base type" -msgstr "" +msgstr "tipe '%q' bukan tipe basis yang dapat diterima" #: py/objtype.c msgid "type isn't an acceptable base type" -msgstr "" +msgstr "tipe bukan tipe basis yang dapat diterima" #: py/runtime.c msgid "type object '%q' has no attribute '%q'" -msgstr "" +msgstr "objek tipe '%q' tidak memiliki atribut '%q'" #: py/objtype.c msgid "type takes 1 or 3 arguments" -msgstr "" +msgstr "type memerlukan 1 atau 3 argumen" #: py/objint_longlong.c msgid "ulonglong too large" -msgstr "" +msgstr "ulonglong terlalu besar" #: py/parse.c msgid "unexpected indent" -msgstr "" +msgstr "indentasi tak terduga" #: py/bc.c msgid "unexpected keyword argument" @@ -4363,20 +4374,20 @@ msgstr "keyword argumen '%q' tidak diharapkan" #: py/lexer.c msgid "unicode name escapes" -msgstr "" +msgstr "escape nama unicode" #: py/parse.c msgid "unindent doesn't match any outer indent level" -msgstr "" +msgstr "unindent tidak cocok dengan tingkat indentasi luar mana pun" #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" -msgstr "" +msgstr "spesifier konversi tidak dikenal %c" #: py/objstr.c msgid "unknown format code '%c' for object of type '%q'" -msgstr "" +msgstr "kode format tidak dikenal '%c' untuk objek bertipe '%q'" #: py/compile.c msgid "unknown type" @@ -4384,100 +4395,102 @@ msgstr "tipe tidak diketahui" #: py/compile.c msgid "unknown type '%q'" -msgstr "" +msgstr "tipe tidak dikenal '%q'" #: py/objstr.c #, c-format msgid "unmatched '%c' in format" -msgstr "" +msgstr "'%c' tidak cocok dalam format" #: py/objtype.c py/runtime.c msgid "unreadable attribute" -msgstr "" +msgstr "atribut tidak dapat dibaca" #: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c #: shared-bindings/tilepalettemapper/TilePaletteMapper.c #: shared-bindings/vectorio/VectorShape.c msgid "unsupported %q type" -msgstr "" +msgstr "tipe %q tidak didukung" #: py/emitinlinethumb.c #, c-format msgid "unsupported Thumb instruction '%s' with %d arguments" -msgstr "" +msgstr "instruksi Thumb tidak didukung '%s' dengan %d argumen" #: py/emitinlinextensa.c #, c-format msgid "unsupported Xtensa instruction '%s' with %d arguments" -msgstr "" +msgstr "instruksi Xtensa tidak didukung '%s' dengan %d argumen" #: shared-module/bitmapfilter/__init__.c msgid "unsupported bitmap depth" -msgstr "" +msgstr "kedalaman bitmap tidak didukung" #: shared-module/gifio/GifWriter.c msgid "unsupported colorspace for GifWriter" -msgstr "" +msgstr "colorspace tidak didukung untuk GifWriter" #: shared-bindings/bitmaptools/__init__.c msgid "unsupported colorspace for dither" -msgstr "" +msgstr "colorspace tidak didukung untuk dither" #: py/objstr.c #, c-format msgid "unsupported format character '%c' (0x%x) at index %d" -msgstr "" +msgstr "karakter format tidak didukung '%c' (0x%x) pada indeks %d" #: py/runtime.c msgid "unsupported type for %q: '%s'" -msgstr "" +msgstr "tipe tidak didukung untuk %q: '%s'" #: py/runtime.c msgid "unsupported type for operator" -msgstr "" +msgstr "tipe tidak didukung untuk operator" #: py/runtime.c msgid "unsupported types for %q: '%q', '%q'" -msgstr "" +msgstr "tipe tidak didukung untuk %q: '%q', '%q'" #: extmod/ulab/code/numpy/io/io.c msgid "usecols is too high" -msgstr "" +msgstr "usecols terlalu tinggi" #: extmod/ulab/code/numpy/io/io.c msgid "usecols keyword must be specified" -msgstr "" +msgstr "keyword usecols harus ditentukan" #: py/objint.c #, c-format msgid "value must fit in %d byte(s)" -msgstr "" +msgstr "nilai harus muat dalam %d byte" #: shared-bindings/bitmaptools/__init__.c msgid "value out of range of target" -msgstr "" +msgstr "nilai di luar jangkauan target" #: extmod/moddeflate.c msgid "wbits" -msgstr "" +msgstr "wbit" #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " "or 25)" msgstr "" +"weights harus berupa urutan dengan jumlah persegi ganjil elemen (biasanya 9 " +"atau 25)" #: shared-bindings/bitmapfilter/__init__.c msgid "weights must be an object of type %q, %q, %q, or %q, not %q " -msgstr "" +msgstr "weights harus berupa objek bertipe %q, %q, %q, atau %q, bukan %q " #: shared-bindings/is31fl3741/FrameBuffer.c msgid "width must be greater than zero" -msgstr "" +msgstr "lebar harus lebih besar dari nol" #: ports/raspberrypi/common-hal/wifi/Monitor.c msgid "wifi.Monitor not available" -msgstr "" +msgstr "wifi.Monitor tidak tersedia" #: shared-bindings/_bleio/Adapter.c msgid "window must be <= interval" @@ -4493,11 +4506,11 @@ msgstr "sumbu yang ditentukan salah" #: extmod/ulab/code/numpy/io/io.c msgid "wrong dtype" -msgstr "" +msgstr "dtype salah" #: extmod/ulab/code/numpy/transform.c msgid "wrong index type" -msgstr "" +msgstr "tipe indeks salah" #: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c #: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c @@ -4507,11 +4520,11 @@ msgstr "tipe input salah" #: extmod/ulab/code/numpy/transform.c msgid "wrong length of condition array" -msgstr "" +msgstr "panjang array kondisi salah" #: extmod/ulab/code/numpy/transform.c msgid "wrong length of index array" -msgstr "" +msgstr "panjang array indeks salah" #: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c msgid "wrong number of arguments" diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 1e167c30353..564d483b467 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -16,877 +16,988 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -#: py/obj.c -msgid " File \"%q\"" +#: extmod/moddeflate.c +msgid "format" msgstr "" -#: py/obj.c -msgid " File \"%q\", line %d" +#: extmod/moddeflate.c +msgid "wbits" msgstr "" -#: py/builtinhelp.c -msgid " is of type %q\n" +#: extmod/modhashlib.c +msgid "hash is final" msgstr "" -#: main.c -msgid " not found.\n" +#: extmod/modheapq.c +msgid "heap must be a list" msgstr "" -#: main.c -msgid " output:\n" +#: extmod/modjson.c +msgid "syntax error in JSON" msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modrandom.c +msgid "bits must be 32 or less" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" +#: extmod/modre.c +msgid "splitting with sub-captures" msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" +#: extmod/modre.c +msgid "regex too complex" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modre.c +msgid "Error in regex" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -msgid "%q failure: %d" +#: extmod/modzlib.c +msgid "compression header" msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c -msgid "%q in use" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" msgstr "" -#: py/objstr.c -msgid "%q index out of range" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c -msgid "%q init failed" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" msgstr "" -#: py/runtime.c -msgid "%q moved from %q to %q" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" msgstr "" -#: py/argcheck.c -msgid "%q must be %d" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" msgstr "" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " msgstr "" -#: py/argcheck.c -msgid "%q must be >= %d" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" msgstr "" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" msgstr "" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" msgstr "" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c -msgid "%q out of range" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" msgstr "" -#: py/objmodule.c -msgid "%q renamed %q" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" msgstr "" -#: py/proto.c -msgid "'%q' object does not support '%q'" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" msgstr "" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" msgstr "" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" msgstr "" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" msgstr "" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" msgstr "" -#: py/compile.c -msgid "'await' outside function" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" msgstr "" -#: py/compile.c -msgid "'break'/'continue' outside loop" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" msgstr "" -#: py/compile.c -msgid "'data' requires at least 2 arguments" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" msgstr "" -#: py/compile.c -msgid "'data' requires integer arguments" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" msgstr "" -#: py/compile.c -msgid "'label' requires 1 argument" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" msgstr "" -#: py/emitnative.c -msgid "'not' not implemented" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" msgstr "" -#: py/compile.c -msgid "'return' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" msgstr "" -#: py/compile.c -msgid "'yield from' inside async function" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" msgstr "" -#: py/compile.c -msgid "'yield' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" msgstr "" -#: py/compile.c -msgid "* arg after **" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" msgstr "" -#: py/compile.c -msgid "*x must be assignment target" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" msgstr "" -#: py/obj.c -msgid ", in %q\n" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" msgstr "" -#: py/objcomplex.c -msgid "0.0 to a complex power" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" msgstr "" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" msgstr "" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" msgstr "" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" msgstr "" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" msgstr "" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" msgstr "" -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" msgstr "" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" msgstr "" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" msgstr "" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" msgstr "" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" msgstr "" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Audio source error" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" msgstr "" -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" msgstr "" -#: main.c -msgid "Auto-reload is off.\n" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" msgstr "" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" msgstr "" -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Bit clock and word select must be sequential GPIO pins" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" msgstr "" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" +#: main.c +msgid "Done" msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" +#: main.c +msgid " output:\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" msgstr "" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" +#: main.c +msgid "Auto-reload is off.\n" msgstr "" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" +#: main.c +msgid "Running in safe mode! Not running saved code.\n" msgstr "" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" +#: main.c +msgid " not found.\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Cannot record to a file" +#: main.c +msgid "" +"\n" +"Code done running.\n" msgstr "" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: main.c +msgid "Woken up by alarm.\n" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Cannot set value when direction is input." +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" msgstr "" -#: py/objslice.c -msgid "Cannot subclass slice" +#: main.c +msgid "UID:" +msgstr "" + +#: main.c +msgid "soft reboot\n" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c +msgid "%q init failed" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "" + +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "" + +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "" + +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" +msgstr "" + +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "" + +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "" + +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" msgstr "" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c #: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" +msgid "Unknown reason." +msgstr "" + +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" +msgstr "" + +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Clock unit in use" msgstr "" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "" + +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "" + +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "" + +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" +msgstr "" + +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +msgid "Invalid data_pins[%d]" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Device Init Error" +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" msgstr "" #: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c @@ -894,876 +1005,930 @@ msgstr "" msgid "Data 0 pin must be byte aligned" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Destination capacity is smaller than destination_length." +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/socketpool/SocketPool.c +msgid "%q failure: %d" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/audiocore/WaveFile.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/floppyio/__init__.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" msgstr "" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display rotation must be in 90 degree increments" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" msgstr "" -#: main.c -msgid "Done" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Drive mode not used when direction is input." +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" msgstr "" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -msgid "ESP-IDF memory allocation failed" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" msgstr "" -#: extmod/modre.c -msgid "Error in regex" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" msgstr "" -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." msgstr "" -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." msgstr "" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." msgstr "" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." msgstr "" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" msgstr "" #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" +msgid "Already advertising." msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" +msgid "Extended advertisements with scan response not supported." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Service.c +msgid "Too many %q" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" +#: ports/espressif/common-hal/_bleio/Connection.c +msgid "No pairing in progress" msgstr "" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" msgstr "" -#: py/moderrno.c -msgid "File exists" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" msgstr "" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c -msgid "File not found" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" +#: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Already in progress" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" msgstr "" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." msgstr "" -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." msgstr "" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" msgstr "" -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" msgstr "" -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c shared-bindings/emmcio/EMMC.c +msgid "Peripheral in use" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" msgstr "" -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" msgstr "" -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" msgstr "" -#: py/moderrno.c -msgid "Input/output error" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" msgstr "" -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c -msgid "Internal error" +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c #: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "" - -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" +msgid "Must provide 5/6/5 RGB pins" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" msgstr "" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "Invalid format" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" msgstr "" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c +#: shared-bindings/picogame/__init__.c +msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" +msgid "Received response was invalid" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" msgstr "" -#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" +msgid "Version was invalid" msgstr "" -#: shared-module/os/getenv.c -msgid "Invalid unicode escape" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" msgstr "" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" msgstr "" -#: py/compile.c -msgid "LHS of keyword arg must be an id" +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "MMC/SDIO Clock Error %x" +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" msgstr "" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" msgstr "" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" msgstr "" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" msgstr "" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" msgstr "" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c -msgid "No %q pin" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "No DAC on chip" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA channel found" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Only IPv4 addresses supported" msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +#: shared-bindings/emmcio/EMMC.c +msgid "Hardware in use, try alternative pins" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" msgstr "" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" +#: ports/nordic/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "Numeric comparison pairing" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "" +"Unspecified issue. The pairing request on the other device may have been " +"declined or ignored." msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#, c-format +msgid "Unknown security error: 0x%04x" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" msgstr "" -#: py/moderrno.c -msgid "No space left on device" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" msgstr "" -#: py/moderrno.c -msgid "No such device" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: py/moderrno.c -msgid "No such file/directory" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c -msgid "Not playing" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/nordic/sd_mutex.c #, c-format -msgid "Number of data_pins must be %d or %d, not %d" -msgstr "" - -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +msgid "Failed to acquire mutex, err 0x%04x" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/__init__.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" msgstr "" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" msgstr "" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" msgstr "" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: py/moderrno.c -msgid "Operation not permitted" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation timed out" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" +#: ports/raspberrypi/common-hal/busio/SPI.c shared-bindings/emmcio/EMMC.c +msgid "SPI peripheral in use" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" msgstr "" #: ports/raspberrypi/common-hal/countio/Counter.c @@ -1774,89 +1939,109 @@ msgstr "" msgid "PWM slice channel A already in use" msgstr "" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: ports/espressif/common-hal/audiobusio/__init__.c -msgid "Peripheral in use" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: py/moderrno.c -msgid "Permission denied" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" msgstr "" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" msgstr "" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" msgstr "" #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c msgid "Pins must be sequential GPIO pins" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" msgstr "" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" msgstr "" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" msgstr "" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" msgstr "" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -1867,1464 +2052,1434 @@ msgstr "" msgid "Program does OUT without loading OSR" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" msgstr "" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Pull not used when direction is output." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" msgstr "" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" msgstr "" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" msgstr "" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" msgstr "" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" msgstr "" -#: shared-module/audiocore/__init__.c -msgid "The sample's %q does not match" +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" msgstr "" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" +#: py/argcheck.c shared-bindings/wifi/Radio.c +msgid "'%q' argument required" msgstr "" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c +msgid "argument num/types mismatch" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" +#: py/argcheck.c +msgid "%q must be %d" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" +#: py/argcheck.c +msgid "%q must be >= %d" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample." +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" +#: py/argcheck.c +msgid "%q length must be %d-%d" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" +#: py/argcheck.c +msgid "%q length must be >= %d" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many displays" +#: py/argcheck.c +msgid "%q length must be <= %d" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" msgstr "" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" +#: py/argcheck.c shared-module/audiofilters/__init__.c +msgid "%q in %q must be of type %q, not %q" msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: main.c -msgid "UID:" +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB busy" +#: py/binary.c +msgid "integer out of range" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" +#: py/builtinhelp.c +msgid "object " msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" +#: py/builtinhelp.c +msgid " is of type %q\n" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +#: py/builtinhelp.c +#, c-format +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Unable to allocate buffers for signed conversion" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -msgid "Unable to create lock" +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: py/parse.c -msgid "Unable to init parser" +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" +#: py/compile.c +msgid "invalid arch" msgstr "" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." +#: py/compile.c +msgid "can't delete expression" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" +#: py/compile.c +msgid "'break'/'continue' outside loop" msgstr "" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." +#: py/compile.c +msgid "'return' outside function" msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" +#: py/compile.c +msgid "*x must be assignment target" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" +#: py/compile.c +msgid "* arg after **" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" +#: py/compile.c +msgid "* arg after kwarg" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +#: py/compile.c +msgid "too many args" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: py/compile.c +msgid "LHS of keyword arg must be an id" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: py/compile.c +msgid "'yield' outside function" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: py/compile.c +msgid "'yield from' inside async function" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" +#: py/compile.c +msgid "'await' outside function" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: py/compile.c +msgid "argument name reused" msgstr "" -#: py/builtinhelp.c -#, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" +#: py/compile.c +msgid "inline assembler must be a function" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " +#: py/compile.c +msgid "unknown type" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: main.c -msgid "Woken up by alarm.\n" +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: py/compile.c +msgid "'label' requires 1 argument" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." +#: py/compile.c +msgid "label redefined" msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." +#: py/compile.c +msgid "'align' requires 1 argument" msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." +#: py/compile.c +msgid "'data' requires at least 2 arguments" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: py/compile.c +msgid "'data' requires integer arguments" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: py/emitbc.c +msgid "bytecode overflow" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" +#: py/emitinlinerv32.c +msgid "opcode '%q': registers must be different" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/emitinlinerv32.c +msgid "opcode '%q': malformed register list" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/emitinlinerv32.c +msgid "opcode '%q': invalid stack adjustment" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: wrong register(s)" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" -#: py/compile.c -msgid "annotation must be an identifier" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" msgstr "" -#: py/compile.c -msgid "argument name reused" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" msgstr "" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" +#: py/emitinlinethumb.c +msgid "branch not in range" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: py/compile.c -msgid "async for/with outside async function" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/emitnative.c +msgid "conversion to object" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/emitnative.c +msgid "local '%q' used before type known" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" +#: py/emitnative.c +msgid "can't load from '%q'" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" +#: py/emitnative.c +msgid "can't load with '%q' index" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/emitnative.c +msgid "can't store to '%q'" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/emitnative.c +msgid "can't store with '%q' index" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" #: py/emitnative.c -msgid "binary op %q not implemented" +msgid "'not' not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." +#: py/emitnative.c +msgid "can't do unary op of '%q'" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/emitnative.c +msgid "div/mod not implemented for uint" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/emitnative.c +msgid "comparison of int and uint" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" +#: py/emitnative.c +msgid "casting" msgstr "" -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/emitnative.c +msgid "native raise" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/emitnative.c +msgid "must raise an object" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/modbuiltins.c py/objstr.c +msgid "char not in range(0x110000)" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: py/emitbc.c -msgid "bytecode overflow" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: py/objarray.c -msgid "bytes length not a multiple of item size" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: py/objstr.c -msgid "bytes value out of range" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/moderrno.c +msgid "Operation not permitted" msgstr "" -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +#: py/moderrno.c +msgid "No such file/directory" msgstr "" -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +#: py/moderrno.c +msgid "Input/output error" msgstr "" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" +#: py/moderrno.c +msgid "Permission denied" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" +#: py/moderrno.c +msgid "File exists" msgstr "" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" +#: py/moderrno.c +msgid "No such device" msgstr "" -#: py/compile.c -msgid "can't assign to expression" +#: py/moderrno.c +msgid "No space left on device" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to complex" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to float" +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: py/objint.c py/runtime.c +#: py/modstruct.c #, c-format -msgid "can't convert %s to int" -msgstr "" - -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: py/obj.c -msgid "can't convert to complex" +#: py/modweakref.c +msgid "not a heap object" msgstr "" -#: py/obj.c -msgid "can't convert to float" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: py/runtime.c -msgid "can't convert to int" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +#: py/obj.c +msgid " File \"%q\", line %d" msgstr "" -#: py/emitnative.c -msgid "can't do unary op of '%q'" +#: py/obj.c +msgid " File \"%q\"" msgstr "" -#: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +#: py/obj.c +msgid ", in %q\n" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: py/emitnative.c -msgid "can't load from '%q'" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: py/emitnative.c -msgid "can't load with '%q' index" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: py/emitnative.c -msgid "can't store '%q'" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: py/emitnative.c -msgid "can't store to '%q'" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: py/emitnative.c -msgid "can't store with '%q' index" +#: py/obj.c +msgid "%q indices must be integers, not %s" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/obj.c +msgid "object has no len" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" msgstr "" -#: py/objtype.c -msgid "cannot create instance" +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: py/emitnative.c -msgid "casting" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/objcomplex.c +msgid "0.0 to a complex power" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/objdeque.c +msgid "full" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/objdeque.c +msgid "empty" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" +#: py/objdict.c +msgid "dict update sequence has wrong length" msgstr "" -#: py/objcomplex.c -msgid "complex divide by zero" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" #: py/objfloat.c py/parsenum.c msgid "complex values not supported" msgstr "" -#: extmod/modzlib.c -msgid "compression header" -msgstr "" - -#: py/emitnative.c -msgid "conversion to object" -msgstr "" - -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/objint.c +msgid "float too big" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/objint_impl.h #, c-format -msgid "data pin #%d in use" +msgid "value would overflow a %d byte buffer" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" +#: py/objint_impl.h +msgid "can't convert negative int to unsigned" msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: py/objdict.c -msgid "dict update sequence has wrong length" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" msgstr "" -#: py/emitnative.c -msgid "div/mod not implemented for uint" +#: py/objslice.c +msgid "Cannot subclass slice" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "divide by zero" +#: py/objstr.c +msgid "unknown encoding: %q" msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/objstr.c +msgid "bytes value out of range" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/objstr.c +msgid "empty separator" msgstr "" -#: py/objdeque.c -msgid "empty" +#: py/objstr.c +msgid "rsplit(None,n)" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" msgstr "" #: py/objstr.c -msgid "empty separator" +msgid "bad conversion specifier" msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" #: py/objstr.c -msgid "end of format while looking for conversion specifier" +#, c-format +msgid "unknown conversion specifier %c" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/objstr.c +msgid "expected ':' after format specifier" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objstr.c +msgid "%q index out of range" msgstr "" #: py/objstr.c -msgid "expected ':' after format specifier" +msgid "attributes not supported" msgstr "" -#: py/obj.c -msgid "expected tuple/list" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" -#: py/modthread.c -msgid "expecting a dict for keyword args" +#: py/objstr.c +msgid "invalid format specifier" msgstr "" -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objstr.c +msgid "incomplete format key" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objstr.c +msgid "incomplete format" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objtemplate.c +msgid "expected str or Interpolation" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." msgstr "" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: extmod/moddeflate.c -msgid "format" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: py/objstr.c -msgid "format needs a dict" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: py/objstr.c -msgid "format string didn't convert all arguments" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: py/objstr.c -msgid "format string needs more arguments" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objdeque.c -msgid "full" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" +msgstr "" + +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" +#: py/parse.c +msgid "not a constant" msgstr "" -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" +#: py/parse.c +msgid "Unable to init parser" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" +#: py/parsenum.c +msgid "invalid syntax for integer" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/parsenum.c +msgid "invalid syntax for number" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" #: py/persistentcode.c @@ -3332,1225 +3487,1245 @@ msgid "incompatible .mpy arch" msgstr "" #: py/persistentcode.c -msgid "incompatible .mpy file" -msgstr "" - -#: py/objstr.c -msgid "incomplete format" +msgid "function must be bytecode" msgstr "" -#: py/objstr.c -msgid "incomplete format key" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/qstr.c +msgid "name too long" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/runtime.c +msgid "'%q' object isn't iterable" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" +#: py/runtime.c +msgid "'%q' object isn't an iterator" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/runtime.c +msgid "can't convert to int" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/vm.c +msgid "local variable referenced before assignment" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/vm.c +msgid "opcode" msgstr "" #: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" +msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" msgstr "" -#: shared-bindings/bitmaptools/__init__.c +#: shared-bindings/_bleio/Adapter.c #, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgid "interval must be in range %s-%s" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for integer" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" +#: shared-bindings/_bleio/__init__.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: py/compile.c -msgid "label redefined" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" msgstr "" -#: py/vm.c -msgid "local variable referenced before assignment" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: py/parse.c -msgid "malformed f-string" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" msgstr "" -#: py/runtime.c -msgid "maximum recursion depth exceeded" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." msgstr "" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c +#: shared-bindings/audiodelays/GranularPitchShift.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: py/builtinimport.c -msgid "module not found" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: py/compile.c -msgid "multiple *x in assignment" +#: shared-bindings/audioio/AudioOut.c shared-bindings/emmcio/EMMC.c +msgid "%q and %q must be different" msgstr "" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: py/objtype.c -msgid "multiple inheritance not supported" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/emitnative.c -msgid "must raise an object" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" msgstr "" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" -#: py/qstr.c -msgid "name too long" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: py/asmthumb.c -msgid "native method too big" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/modmath.c -msgid "negative factorial" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" msgstr "" -#: py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: py/builtinimport.c -msgid "no module named '%q'" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." msgstr "" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: py/builtinhelp.c -msgid "object " +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" -#: py/obj.c -msgid "object doesn't support item assignment" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: py/obj.c -msgid "object with buffer protocol required" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" #: shared-bindings/dualbank/__init__.c msgid "offset must be >= 0" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/emmcio/EMMC.c shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: py/vm.c -msgid "opcode" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: py/modstruct.c +#: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "pack expected %d items for packing (got %d)" +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" msgstr "" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" msgstr "" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" msgstr "" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: py/compile.c -msgid "positional arg after **" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" msgstr "" -#: py/objstr.c -msgid "rsplit(None,n)" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/wifi/Radio.c +msgid "Supply either %q or %q, not both" msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" msgstr "" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" msgstr "" -#: py/nativeglue.c -msgid "set unsupported" +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "short read" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" msgstr "" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" msgstr "" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" msgstr "" -#: main.c -msgid "soft reboot\n" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: py/objstrunicode.c +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c #, c-format -msgid "string indices must be integers, not %s" +msgid "Unable to find I2C Display at %x" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" msgstr "" -#: py/compile.c -msgid "too many args" +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" msgstr "" -#: py/runtime.c +#: shared-module/rgbmatrix/RGBMatrix.c #, c-format -msgid "too many values to unpack (expected %d)" -msgstr "" - -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +msgid "Internal error #%d" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" msgstr "" -#: py/parse.c -msgid "unexpected indent" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" msgstr "" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" msgstr "" -#: py/compile.c -msgid "unknown type" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" msgstr "" -#: py/compile.c -msgid "unknown type '%q'" +#: shared-module/usb/core/Device.c +msgid "Pipe error" msgstr "" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" +#: shared-module/usb/core/Device.c +msgid "No configuration set" msgstr "" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" msgstr "" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: extmod/moddeflate.c -msgid "wbits" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." msgstr "" -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" -#: py/runtime.c -msgid "wrong number of values to unpack" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" msgstr "" diff --git a/locale/cs.po b/locale/cs.po index fa1cb2d40b7..ca29ce63563 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -16,1089 +16,960 @@ msgstr "" "Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -"\n" -"Běh programu byl dokončen.\n" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" -msgstr "" -"\n" -"Kód byl zastaven kvůli automatickému načtení. K načtení dojde brzy.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" +msgstr "nelze zrušit sám sebe" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" +msgstr "nelze čekat" + +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -"\n" -"Prosím, založte issue s vaším programem na github.com/adafruit/circuitpython/" -"issues." -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -"\n" -"Stiskněte reset pro ukončení nouzového režimu.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/moddeflate.c +msgid "format" msgstr "" -"\n" -"Jste v bezpečnostním režimu z důvodu:\n" -#: py/obj.c -msgid " File \"%q\"" -msgstr " Soubor \"%q\"" +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " Soubor \"%q\", řádek %d" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "hash je konečný" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " je typu %q\n" +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "" -#: main.c -msgid " not found.\n" -msgstr " nenalezen\n" +#: extmod/modjson.c +msgid "syntax error in JSON" +msgstr "" -#: main.c -msgid " output:\n" -msgstr " výstup:\n" +#: extmod/modrandom.c +msgid "bits must be 32 or less" +msgstr "počet bitů nesmí přesáhnout 32" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" -msgstr "%d adresní pin, %d rgb pin a %d dlaždice indikuje výšku %d, ne %d" +#: extmod/modre.c +msgid "splitting with sub-captures" +msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q a %q obsahují duplicitní piny" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q a %q musí být rozdílné" +#: extmod/modre.c +msgid "Error in regex" +msgstr "Chyba v regulárním výrazu" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q obsahuje duplicitní piny" - -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -msgid "%q failure: %d" -msgstr "%q: selhání %d" - -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/modzlib.c +msgid "compression header" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "%q v %q musí být typu %q, ne %q" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" +msgstr "datový typ nebyl rozpoznán" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q se právě používá" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "pole je příliš velké" -#: py/objstr.c -msgid "%q index out of range" -msgstr "Index %q je mimo rozsah" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "délka ndarray přetekla" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "Indexy %q musí být celá čísla, nikoli %s" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "nelze převést typ complex" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c -msgid "%q init failed" -msgstr "Inicializace %q selhala" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "příliš mnoho dimenzí" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q je %q" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "%q je pouze u této desky pouze pro čtení" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "Délka %q musí být %d" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "%q délka musí být %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "Pole a index musí mít stejnou délku" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "Délka %q musí být <= %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "nelze převést complex na dtype" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "Délka %q musí být >= %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "operace je immplementována pouze pro 1D boolean pole" -#: py/runtime.c -msgid "%q moved from %q to %q" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" msgstr "" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q musí být %d" - -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q musí být %d-%d" - -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q musí být 1, pokud %q je True" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "nelze smazat prvky pole" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "%q musí být <= %d" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" -msgstr "%q musí být <= %u" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "" -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "%q musí být >= %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" +msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q musí být bytearray nebo pole typu 'H' nebo 'B'" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" +msgstr "tvar musí být integer nebo tuple integerů" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q musí být bytearray nebo pole typu 'h', 'H', 'b', nebo 'B'" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "maximální počet dimenzí je " -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" -msgstr "%q musí být pole typu 'H V" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "nelze změnit rozměry pole" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" -msgstr "%q musí být pole typu 'h'" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." -msgstr "" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "nelze přiřadit nový tvar" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "%q musí být typu %q nebo %q, ne %q" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "funkce je definována pouze pro ndarraye" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q musí být typu %q, ne %q" - -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q musí být mocnina 2" - -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "%q je mimo hranice" - -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "%q je mimo rozsah" - -#: py/objmodule.c -msgid "%q renamed %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "%q krok nemůže být nula" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q() vyžaduje %d pozičních argumentů, ale pouze %d jich bylo zadáno" +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q, a %q musí mít všechny shodnou délku" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" +msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "není podporováno pro vstupní typy" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" -msgstr "%q[%u] posouvá dovnitř o více bitů než je počet pinů" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "funkce je implementována jen pro ndarraye" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" -msgstr "%q[%u] posouvá ven o více bitů než je počet pinů" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "vstup musí být ndarray nebo scalar" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "%q[%u] používá extra pin" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" +msgstr "vstup musí být 1D ndarray" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" -msgstr "%q[%u] čeká na vstup mimo rozsah" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "není implementováno pro komplexní dtype" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "%s chyba 0x%x" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" +msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "Je vyžadován argument '%q'" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "vstupní argument musí být integer, tuple nebo list" -#: py/proto.c -msgid "'%q' object does not support '%q'" -msgstr "Objekt '%q' nepodporuje '%q'" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" +msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "Objekt '%q' není iterátor" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" +msgstr "dělení nulou" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "Objekt '%q' není iterovatelný" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' očekává label" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "první argument musí být tuple nebo ndarray" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' očekává registr" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "pouze ndarraye mohou být spojeny" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' očekává speciální registr" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' očekává registr FPU" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "vstupní pole nejsou kompatibilní" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s' očekává adresu ve formátu [a, b]" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "vstup musí být 1- nebo 2-d" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' očekává integer (celé číslo)" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s' očekává nanejvýš r%d" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' očekává {r0, r1, ...}" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "velikost bufferu musí být násobkem velikosti elementu" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' integer %d není v rozsahu %d..%d" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "buffer je menší než požadovaná velikost" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' integer 0x%x nepatří do masky 0x%x" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "FFT lze použít pouze pro ndarrays" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "'%s' objekt nepodporuje přiřazení položky" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "FFT je implementován pouze pro lineární pole" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "'%s' objekt nepodporuje smazání položky" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "'%s' objekt nemá žádný atribut '%q'" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "'%s' objekt není vložitelný" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "Specifikátor zarovnání '=' není ve formátovacím řetězci povolen" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' a 'O' nejsou podporované typy formátů" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "'align' vyžaduje 1 argument" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "poškozený soubor" -#: py/compile.c -msgid "'await' outside function" -msgstr "'await' je volán mimo funkci" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "špatný dtype" -#: py/compile.c -msgid "'break'/'continue' outside loop" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" msgstr "" -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "'data' vyžaduje nejméně 2 argumenty" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "prázdný soubor" -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "'data' vyžaduje celočíselné argumenty" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "'label' vyžaduje 1 argument" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "pole má příliš mnoho dimenzí" -#: py/emitnative.c -msgid "'not' not implemented" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" msgstr "" -#: py/compile.c -msgid "'return' outside function" -msgstr "'return' je volán mimo funkci" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "" -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "'yield from' volán uvnitř funkce async" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" -#: py/compile.c -msgid "'yield' outside function" -msgstr "'yield' je volán mimo funkci" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "" -#: py/compile.c -msgid "* arg after **" -msgstr "* arg po **" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "operace je definována pouze pro ndarray pole" -#: py/compile.c -msgid "*x must be assignment target" -msgstr "∗x musí být cíl přiřazení" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "operace je definována pouze pro 2D pole" -#: py/obj.c -msgid ", in %q\n" -msgstr ", v% q\n" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" msgstr "" -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "0.0 na komplexní mocninu" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" +msgstr "pokus o získání (arg)min/(arg)max z prázdné sekvence" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "pow() nepodporuje 3 argumenty" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "osa musí být None nebo integer" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "AP nemohl být spuštěn" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "Adresa musí být %d bajtů dlouhá" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "Adresní rozsah není povolen" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" -msgstr "Adresní rozsah se překlápí přes maximální možnou adresu" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "Všechny CAN periferie jsou používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "argsort není implementován pro zploštěná pole" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "Všechny I2C periferie jsou používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" +msgstr "osa je příliš dlouhá" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "Všechny RX FIFO jsou používány" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "Všechny SPI periferie jsou používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" +msgstr "" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "Všechny UART periferie jsou používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" +msgstr "" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "Všechny kanály jsou používány" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "Všechny DMA kanály jsou používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" +msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "Všechny kanály událostí jsou již používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "Všechny stavové automaty jsou používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "" -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "Všechny časovače pro tento pin jsou používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "Všechny časovače jsou používány" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "Již propagujeme." +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "Již existuje posluchač pro všechny zprávy" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "Již běží" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "vstup není iterovatelný" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "Již skenuje wifi sítě" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "Došlo k chybě při načítání '%s'\n" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "Jiný PWMAudioOut je již aktivní" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" +msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "Další odesílání je již aktivní" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "Pole musí obsahovat poloviční slova (typ „H“)" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "Hodnoty pole by měly být jednoduché bajty." - -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" msgstr "" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "Pokus o alokování %d bloků" - -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "Konverze audia není implementována" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Audio source error" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "AuthMode.OPEN nepoužívá heslo" - -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "Autentizace selhala" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "" -#: main.c -msgid "Auto-reload is off.\n" -msgstr "Automatické načtení je vypnuto.\n" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "špatný typ indexu" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" msgstr "" -"Automatické opětovné načtení je zapnuto. Jednoduše uložte soubory přes USB a " -"spusťte je, nebo vypněte REPL.\n" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "Baudrate není podporován periférií" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "dimenze nesouhlasí" -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "Pod minimální obnovovací frekvencí" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" +msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Bit clock and word select must be sequential GPIO pins" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "Velikost bitmapy a počet bitů na hodnotu se musí shodovat" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "dimenze vstupu a výstupu se liší" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "Bootovací zařízení musí být první (rozhraní #0)." +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "vstupní a výstupní tvar je růzmý" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "RX a TX jsou vyžadovány pro kontrolu toku" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "Jas není nastavitelný" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" +msgstr "" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Vyrovnávací paměť + offset je příliš malý %d %d %d" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" +msgstr "dtype musí být float nebo complex" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "Prvky bufferu musí být 4 bajty dlouhé nebo méně" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "nelze převést complex na float" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "Buffer není bytearray." +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "vstupní dtype musí být float nebo complex" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "Délka vyrovnávací paměti %d je příliš velká. Musí být menší než %d" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "První argument musí být zavolatelný" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "Buffer je příliš krátký o %d bajtů" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "první dva argumenty musí být ndarray" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "Buffer příliš malý" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "vstup musí být hustý ndarray" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Sběrnicový pin %d je již používán" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "první argument musí být funkce" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Buffer musí být dlouhý 16 bajtů." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "Bloky CBC musí být násobky 16 bajtů" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "maxiter by měl být > 0" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "Disk CIRCUITPY nelze nalézt nebo vytvořit." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "maxiter musí být > 0" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC nebo kontrolní součet byl neplatný" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "data musí být iterovatelná" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "Volání super().__init__() před přístupem k nativnímu objektu." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "výchozí hodnoty musí být iterovatelné" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" -msgstr "Inizializace kamery" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "data musí mít stejnou délku" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "Alarm z IO RTC je možné generovat pouze z hlubokého spánku." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "vstup musí být jednorozměrný" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" msgstr "" -"Lze nastavit alarm na jednom pinu ve stavu low při hlubokém spánku, ostatní " -"musí být ve stavu high." -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" msgstr "" -"Lze nastavit alarm na maximálně dvou pinech ve stavu low při hlubokém spánku." -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "Nelze nastavit CCCD na místní charakteristiku" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" +msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "Nelze změnit USB zařízení" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "Není možné vytvořit nový adaptér; použití _bleio.adapter;" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "osa je mimo rozsah" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "Nelze odstranit hodnoty" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "Nelze získat ve výstupním režimu" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" +msgstr "" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "Nelze získat teplotu (°C)" +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" +msgstr "vstup musí být ndarray" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "Nelze aktivovat pull rezistor na pinu, který je pouze pro vstup." +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" +msgstr "offset je příliš velký" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Cannot record to a file" -msgstr "Nelze nahrávat do souboru" +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" +msgstr "výstupní pole je příliš malé" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." -msgstr "" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" +msgstr "Filesystém pouze pro čtení" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Cannot set value when direction is input." -msgstr "Nelze nastavit hodnotu, když směr je vstup." +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "I/O operace nad zavřeným souborem" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "Nelze určit RTS nebo CTS v režimu RS485" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" +msgstr "" -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "Nelze použít řez podtřídy" +#: main.c +msgid "Done" +msgstr "Hotovo" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" +#: main.c +msgid " output:\n" +msgstr " výstup:\n" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" -msgstr "Nelze probudit hranou na pinu, pouze úrovní" +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" +msgstr "" +"Automatické opětovné načtení je zapnuto. Jednoduše uložte soubory přes USB a " +"spusťte je, nebo vypněte REPL.\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." -msgstr "Nelze probudit hranou na pinu. Pouze úrovní." +#: main.c +msgid "Auto-reload is off.\n" +msgstr "Automatické načtení je vypnuto.\n" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "CharacteristicBuffer psaní není poskytováno" +#: main.c +msgid "Running in safe mode! Not running saved code.\n" +msgstr "Běh v nouzovém režimu! Uložený kód není zpracováván.\n" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "Jádro kódu CircuitPython tvrdě havarovalo. Jejda!\n" +#: main.c +msgid " not found.\n" +msgstr " nenalezen\n" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "Jednotka hodin je používána" +#: main.c +msgid "WARNING: Your code filename has two extensions\n" +msgstr "UPOZORNĚNÍ: Název souboru vašeho kódu má dvě koncovky\n" -#: shared-bindings/_bleio/Connection.c +#: main.c msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" -"Připojení bylo odpojeno a nelze jej dále používat. Vytvořte nové připojení." - -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" -msgstr "Pole souřadnic mají různé délky" +"\n" +"Kód byl zastaven kvůli automatickému načtení. K načtení dojde brzy.\n" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" +#: main.c +msgid "" +"\n" +"Code done running.\n" msgstr "" +"\n" +"Běh programu byl dokončen.\n" -#: shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" -msgstr "" +#: main.c +msgid "Woken up by alarm.\n" +msgstr "Probuzen alarmem.\n" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" +"Zmáčkněte jakoukoli klávesu pro spuštění REPLu. Použijte CTRL-D pro opětovné " +"načtení.\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "Není možné nastavit adresu" - -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "Nelze začít přerušení, RX je zaneprázdněn" +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +msgstr "Předstírám hluboký spánek do alarmu, CTRL-C nebo zápisu souboru.\n" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "Dekodér nelze přiřadit" +#: main.c +msgid "UID:" +msgstr "UID:" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: main.c +msgid "soft reboot\n" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" -msgstr "Chyba inicializace kanálu DAC" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c +msgid "%q init failed" +msgstr "Inicializace %q selhala" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Device Init Error" -msgstr "Chyba inicializace zařízení DAC" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC se již používá" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "%q je mimo rozsah" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "Datový pin 0 musí být zarovnán na bajty" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" +msgstr "Chybný stav" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "Data nejsou podporována s cíleným oznamováním" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "Data jsou příliš velká pro propagovaný paket" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -"Piny pro hluboký spánek musí používat náběžnou hranu s pulldown rezistorem" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "Cílová kapacita je menší než destination_length." +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "RX a TX jsou vyžadovány pro kontrolu toku" -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "Chyba alokace %q bufferu" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "Zařízení je používáno" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "Displej musí mít 16bitový barevný prostor." +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "Všechny UART periferie jsou používány" -#: shared-bindings/busdisplay/BusDisplay.c +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display rotation must be in 90 degree increments" -msgstr "Otočení displeje musí být po 90 stupních" - -#: main.c -msgid "Done" -msgstr "Hotovo" +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "Špatný %s" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Drive mode not used when direction is input." +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "Při zpracování uvedené výjimky nastala další výjimka:" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB operuje najednou pouze 16 bajtů" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "Interní audio buffer je příliš malý" -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -msgid "ESP-IDF memory allocation failed" -msgstr "ESP-IDF alokace paměti selhala" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "" -#: extmod/modre.c -msgid "Error in regex" -msgstr "Chyba v regulárním výrazu" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "Chyba v safemode.py." +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "Při spuštění jsi stiskl obě tlačítka." -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" -msgstr "Očekáván typ %q" +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "Všechny časovače jsou používány" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "FFT lze použít pouze pro ndarrays" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "FFT je implementován pouze pro lineární pole" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." +msgstr "Neznámý důvod." -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "Nepodařilo se odeslat příkaz." +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" +msgstr "Lze nastavit pouze jeden alarm typu alarm.time" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "Nepodařilo se získat mutex, err 0x%04x" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" +msgstr "Žádný DAC na čipu" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" msgstr "" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" -msgstr "Chyba alokace %q bufferu" - -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" -msgstr "Chyba alokace paměti WiFi" - -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" -msgstr "Nepodařilo se alokovat paměť pro wifi scan" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" -msgstr "Nepodařilo se nabufferovat sample" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "Připojení se nezdařilo: interní chyba" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "Jednotka hodin je používána" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "Nepodařilo se připojit: časový limit" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" +msgstr "Žádné volné GCLK" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" -msgstr "" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" +msgstr "V samplu je příliš mnoho kanálů" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" -msgstr "" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" +msgstr "Nebyl nalezen žádný kanál DMA" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "Soubor MP3 se nepodařilo analyzovat" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC se již používá" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "Nepodařilo se uvolnit mutex, err 0x%04x" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" +msgstr "Pravý kanál nepodporován" -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "Všechny kanály událostí jsou již používány" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" -msgstr "" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "SDA nebo SCL zřejmě nemá pull up; zkontroluj zapojení" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" -msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q musí být mocnina 2" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." -msgstr "Nepodařilo se zapsat do interní paměti." +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "Žádný %q pin" -#: py/moderrno.c -msgid "File exists" -msgstr "soubor existuje" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "Všechny RX FIFO jsou používány" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c -msgid "File not found" -msgstr "Soubor nenalezen" +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "Již existuje posluchač pro všechny zprávy" #: ports/atmel-samd/common-hal/canio/Listener.c #: ports/espressif/common-hal/canio/Listener.c @@ -1107,116 +978,305 @@ msgstr "Soubor nenalezen" msgid "Filters too complex" msgstr "Filtry jsou příliš komplexní" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "Firmware je duplicitní" +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "Nelze získat ve výstupním režimu" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "Firmware není validní" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" +msgstr "Chybný data_pin[%d]" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "Firmware je příliš velký" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" +msgstr "datový pin #%d je používán" -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "Pro barevný prostor L8 musí mít vstupní bitmapa 8 bitů na pixel" +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" +msgstr "Neplatný pin %q" -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "Pro barevný prostor RGB musí mít vstupní bitmapa 16 bitů na pixel" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "Formát není podporován" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "Datový pin 0 musí být zarovnán na bajty" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "Sběrnicový pin %d je již používán" + +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" +msgstr "pop z prázdného %q" + +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" +msgstr "Vstup trval příliš dlouho" + +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "Další odesílání je již aktivní" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/socketpool/SocketPool.c +msgid "%q failure: %d" +msgstr "%q: selhání %d" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/audiocore/WaveFile.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/floppyio/__init__.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" msgstr "" -"Frekvence musí být 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 nebo 1008 " -"Mhz" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "Funkce vyžaduje zámek" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." +msgstr "" + +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" +msgstr "Inicializace UART" + +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "Inizializace kamery" + +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "Velikost není podporována" + +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "Buffer příliš malý" + +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "Formát není podporován" #: ports/cxd56/common-hal/gnss/GNSS.c msgid "GNSS init" msgstr "Inicializace GNSS" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" -msgstr "Základní chyba" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" +msgstr "Inicializace SD karty" -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "Skupina již byla použita" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "Již běží" -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "Fatální chyba: přístup k paměti nebo chyba instrukce." +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q je %q" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "Hardware je používán, zkuste alternativní piny" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "Při spuštění jsi stiskl tlačítko SW38." -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." -msgstr "Alokace heapu při neběžícím VM." +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "I/O operace nad zavřeným souborem" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." +msgstr "Při spuštění jsi stiskl tlačítko na pinu GPIO0." -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "Chyba inicializace I2C" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "Při spuštění jsi stiskl tlačítko Rec." -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "Periférie I2C je používána" +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "Při spuštění jsi stiskl tlačítko VOLUME." -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "Elementy v bufferu musí být <= 4 bajty" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "Při spuštění jsi stiskl středové tlačítko." -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "Nesprávná velikost vyrovnávací paměti" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." +msgstr "Při spuštění jsi stiskl tlačítko A." -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "Velikost init programu není správná" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "Při spuštění jsi stiskl tlačítko DOWN." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." +msgstr "Scan již probíhá. Lze zastavit pomocí stop_scan." + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "Připojení se nezdařilo: interní chyba" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "Data jsou příliš velká pro propagovaný paket" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "Již propagujeme." + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." msgstr "" -#: shared-bindings/bitops/__init__.c +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "Data nejsou podporována s cíleným oznamováním" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c #, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgstr "Časový limit je příliš dlouhý: maximální limit je %d vteřin" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" -msgstr "Vstup trval příliš dlouho" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" -#: py/moderrno.c -msgid "Input/output error" -msgstr "Chyba vstupu/výstupu" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Service.c +msgid "Too many %q" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" +msgstr "Žádné CCCD pro tuto charakteristiku" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "Nelze nastavit CCCD na místní charakteristiku" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" +msgstr "Nepřipojený" + +#: ports/espressif/common-hal/_bleio/Connection.c +msgid "No pairing in progress" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" +msgstr "" + +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" +msgstr "Velikost dat k zápisu je větší než %q" + +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" +msgstr "Chybný BLE parametr" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Already in progress" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" +msgstr "Neznámá chyba firmwaru na %s:%d: %d" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" +msgstr "Neznámá chyba firmwaru: %d" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c @@ -1228,1222 +1288,1163 @@ msgstr "Nedostatečná autentizace" msgid "Insufficient encryption" msgstr "Nedostatečné šifrování" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" -msgstr "" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "Neznámá chyba BLE na %s:%d: %d" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" -msgstr "" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" +msgstr "Neznámá chyba BLE: %d" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "Rozhraní musí být nastartováno" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "Nelze probudit hranou na pinu. Pouze úrovní." -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "Interní audio buffer je příliš malý" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "Nelze aktivovat pull rezistor na pinu, který je pouze pro vstup." -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." msgstr "" +"Lze nastavit alarm na maximálně dvou pinech ve stavu low při hlubokém spánku." -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c -msgid "Internal error" -msgstr "Interní chyba" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." +msgstr "" +"Lze nastavit alarm na jednom pinu ve stavu low při hlubokém spánku, ostatní " +"musí být ve stavu high." -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" -msgstr "Vnitřní chyba #%d" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "Alarm z IO RTC je možné generovat pouze z hlubokého spánku." -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" -msgstr "" +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." +msgstr "Může být nastaven pouze jeden alarm typu alarm.time." -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "Interní watchdog timer expiroval." +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." +msgstr "Pouze jeden %q lze nastavit v hlubokém spánku." -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "Chyba přerušení." +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "%q musí být pole typu 'H V" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c shared-bindings/emmcio/EMMC.c +msgid "Peripheral in use" +msgstr "Periférie je používána" + +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" -msgstr "Špatný %s" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" +msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "Neplatný pin %q" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" +msgstr "" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "Neplatná hodnota jednotky ADC" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "Chybný BLE parametr" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "Chybné BSSID" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "Chybná MAC adresa" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" +msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "Neplatný argument" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "Špatný byte %.*s" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "Všechny I2C periferie jsou používány" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" -msgstr "Chybný data_pin[%d]" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" +msgstr "Není možné vytvořit zámek" -#: shared-module/msgpack/__init__.c -msgid "Invalid format" -msgstr "Špatný formát" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" +msgstr "Konfigurace SPI selhala" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "Neplatná velikost bloku" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "Všechny SPI periferie jsou používány" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" -msgstr "Špatné heslo v hex" +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "ESP-IDF alokace paměti selhala" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "Chybná multicastová MAC adresa" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "Nelze určit RTS nebo CTS v režimu RS485" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "Chybná velikost" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" +msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "Chybný soket pro TLS" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "Baudrate není podporován periférií" -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" -msgstr "Chybný stav" +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "Všechny CAN periferie jsou používány" -#: shared-module/os/getenv.c -msgid "Invalid unicode escape" -msgstr "Neplatná unicode escape sekvence" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "Klíč musí být dlouhý 16, 24 nebo 32 bajtů" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" +msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "Klíč nenalezen" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" +msgstr "" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "Mapování LED musí korespondovat s velikostí displeje" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" +msgstr "Je třeba poskytnout 5/6/5 RGB piny" -#: py/compile.c -msgid "LHS of keyword arg must be an id" -msgstr "" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" +msgstr "Firmware je duplicitní" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "Vrstva již v groupě je" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "Firmware není validní" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "Vrstva musí být Group nebo TileGrid" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "Firmware je příliš velký" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" +msgstr "neplatné nastavení" + #: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "MAC adresa byla chybná" +msgid "Generic Failure" +msgstr "Základní chyba" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" +msgstr "Došla paměť" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "MMC/SDIO Clock Error %x" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "Neplatný argument" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "Chybná velikost" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" +msgstr "Požadovaný zdroj nebyl nalezen" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" -msgstr "Nekorespondující velikost dat" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c +#: shared-bindings/picogame/__init__.c +msgid "Operation or feature not supported" +msgstr "Operace nebo funkce není podporována" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" -msgstr "Nekorespondující swap flag" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" +msgstr "Časový limit operace vypršel" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "Chybí first_in_pin. %q[%u] čte z pinu(ů)" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" +msgstr "Přijatá odpověď nebyla validní" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "Chybí first_in_pin. %q[%u] posunuje z pinu(ů)" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC nebo kontrolní součet byl neplatný" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "Chybí first_in_pin. %q[%u] čeká na základě pinu" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" +msgstr "Verze byla neplatná" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "Chybí first_out_pin. %q[%u] posunuje do pinu(ů)" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" +msgstr "MAC adresa byla chybná" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "Chybí first_out_pin. %q[%u] zapisuje do pinu(ů)" +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" +msgstr "%s chyba 0x%x" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "Chybí first_set_pin. %q[%u] nastavuje pin(y)" +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" +msgstr "Program je příliš dlouhý" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "Chybí jmp_pin. %q[%u] skáče na pin" +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q se právě používá" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" -msgstr "" +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." +msgstr "Lze nastavit pouze jeden %q ." -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." -msgstr "Musí být podtřída %q." +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" +msgstr "Je povolena pouze jedna adresa" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" -msgstr "Je třeba poskytnout 5/6/5 RGB piny" +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" +msgstr "Neznámý chybový kód %d" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" -msgstr "Musí poskytnout pin MISO nebo MOSI" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" +msgstr "mDNS pracuje pouze s vestavěnou WiFi" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" -msgstr "Je nutné použít několik kolíků 6 rgb, nikoli %d" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" +msgstr "mDNS je již inicializováno" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." -msgstr "NLR skok selhal. Pravděpodobně poškozením paměti." +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" +msgstr "Nepodařilo se začít mDNS dotaz" + +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "Adresní rozsah není povolen" #: ports/espressif/common-hal/nvm/ByteArray.c msgid "NVS Error" msgstr "Chyba NVS" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" -msgstr "Jméno nebo služba není známa" - -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" -msgstr "Nová bitmapa musí mít stejnou velikost jako původní bitmapa" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "Žádný %q pin" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "Žádné CCCD pro tuto charakteristiku" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "Interní chyba" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "No DAC on chip" -msgstr "Žádný DAC na čipu" +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA channel found" -msgstr "Nebyl nalezen žádný kanál DMA" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#: ports/espressif/common-hal/rclcpy/__init__.c #, c-format -msgid "No I2C device at address: 0x%x" -msgstr "Žádné I2C zařízení na adrese: 0x%x" +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "Není IP" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" -msgstr "Konfigurace není nastavena" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" -msgstr "Žádné připojení: nelze určit délku" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" -msgstr "Žádná výchozí sběrnice %q" +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" -msgstr "Žádné volné GCLK" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" +msgstr "" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" +msgstr "Došly sockety" + +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" +msgstr "SocketPool je možné použít pouze s wifi.radio" + +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "%q musí být <= %u" + +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" -msgstr "V programu není vstup" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "Rozhraní musí být nastartováno" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" -msgstr "V programu není vstup nebo výstup" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "Chybná multicastová MAC adresa" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" -msgstr "Není podpora long integer" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "Již skenuje wifi sítě" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "Žádná síť s takovým SSID" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" -msgstr "V programu není výstup" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" +msgstr "Nepodařilo se alokovat paměť pro wifi scan" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "SDA nebo SCL zřejmě nemá pull up; zkontroluj zapojení" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" +msgstr "Chyba alokace paměti WiFi" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" -msgstr "Žádný pulldown na pinu; doporučeno 1Mohm" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Only IPv4 addresses supported" +msgstr "Pouze IPv4 adresy podporovány" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" +msgstr "Musí poskytnout pin MISO nebo MOSI" + +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +#: shared-bindings/emmcio/EMMC.c +msgid "Hardware in use, try alternative pins" +msgstr "Hardware je používán, zkuste alternativní piny" + +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" +msgstr "" + +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" +"Frekvence musí být 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 nebo 1008 " +"Mhz" -#: py/moderrno.c -msgid "No space left on device" -msgstr "Na zařízení nezůstal žádný prostor" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." +msgstr "Při spuštění jsi stiskl tlačítko doleva." -#: py/moderrno.c -msgid "No such device" -msgstr "Žádné takové zařízení" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" +msgstr "timeout musí být < 655.35 s" -#: py/moderrno.c -msgid "No such file/directory" -msgstr "Žádný takový soubor / adresář" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" +msgstr "nenulový timeout musí být > 0.01" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" -msgstr "Není k dispozici žádný časovač" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "Nepodařilo se připojit: časový limit" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" -msgstr "Žádný USB host port není inicializován" +#: ports/nordic/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "Numeric comparison pairing" +msgstr "" + +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" +msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c msgid "Nordic system firmware out of memory" msgstr "Nordic system firmware - nedostatek paměti" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" -msgstr "Nevalidní IP string" - -#: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" -msgstr "Nepřipojený" - -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c -msgid "Not playing" -msgstr "Nehraje" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" +#, c-format +msgid "Unknown system firmware error: %04x" +msgstr "Neznámá chyba firmwaru: %04x" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/nordic/common-hal/_bleio/__init__.c #, c-format -msgid "Number of data_pins must be %d or %d, not %d" +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: shared-bindings/util.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +"Unspecified issue. The pairing request on the other device may have been " +"declined or ignored." msgstr "" -"Objekt byl deinicializován a nelze jej dále používat. Vytvořte nový objekt." -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" -msgstr "" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#, c-format +msgid "Unknown security error: 0x%04x" +msgstr "Neznámá bezpečnostní chyba: 0x%04x" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" -msgstr "Vypnuto" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" +msgstr "Nelze probudit hranou na pinu, pouze úrovní" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" -msgstr "Ok" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "Zařízení je používáno" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" -msgstr "Pouze IPv4 adresy podporovány" - -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" -msgstr "Pouze IPv4 sokety podporovány" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" -#: shared-module/displayio/OnDiskBitmap.c +#: ports/nordic/common-hal/busio/UART.c #, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +msgid "error = 0x%08lX" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" -msgstr "Na tomto hardware je dostupná pouze detekce hrany" - -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" -msgstr "Pro IP je podporován pouze int nebo string" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "Všechny kanály jsou používány" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." -msgstr "Pouze jeden %q lze nastavit v hlubokém spánku." +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "Nelze získat teplotu (°C)" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." -msgstr "Lze nastavit pouze jeden %q ." +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" +msgstr "timeout překročil maximální podporovanou hodnotu" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" -msgstr "Je povolena pouze jedna adresa" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" +msgstr "" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" -msgstr "Lze nastavit pouze jeden alarm typu alarm.time" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +msgstr "WatchDogTimer nelze deaktivovat v režimu RESET" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." -msgstr "Může být nastaven pouze jeden alarm typu alarm.time." +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "Nepodařilo se získat mutex, err 0x%04x" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" -msgstr "Pouze jedna barva může být nastavena jako transparentní" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "Nepodařilo se uvolnit mutex, err 0x%04x" -#: py/moderrno.c -msgid "Operation not permitted" -msgstr "Operace není povolena" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "Konverze audia není implementována" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" -msgstr "Operace nebo funkce není podporována" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/__init__.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q musí být typu %q nebo %q, ne %q" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation timed out" -msgstr "Časový limit operace vypršel" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" +msgstr "Velikost programu je nesprávná" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" -msgstr "Došly mDNS sloty" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "Velikost init programu není správná" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" -msgstr "Došla paměť" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "Prvky bufferu musí být 4 bajty dlouhé nebo méně" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" -msgstr "Došly sockety" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" +msgstr "Nekorespondující velikost dat" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" -msgstr "Restart PWM" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" -msgstr "PWM kanál je již využíván" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" -msgstr "PWM kanál A je již využíván" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "Elementy v bufferu musí být <= 4 bajty" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." -msgstr "" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "Funkce vyžaduje zámek" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: ports/espressif/common-hal/audiobusio/__init__.c -msgid "Peripheral in use" -msgstr "Periférie je používána" - -#: py/moderrno.c -msgid "Permission denied" -msgstr "Přístup odepřen" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" -msgstr "Z Deep Sleep nelze probudit pinem" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" -msgstr "Počet pinů je příliš velký" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" -msgstr "Přerušení od pinu je již používáno" - -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" -msgstr "Pin je pouze vstupní" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" -msgstr "Pin musí být na PWM kanálu B" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" +msgstr "Touch alarmy nejsou dostupné" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "Plus všechny moduly na filesystému\n" - -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" -msgstr "Polygon potřebuje nejméně 3 body" - -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." -msgstr "Pokles napájení. Zkontroluj, zda je k dispozici dostatečné napájení." - -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" -"Zmáčkněte jakoukoli klávesu pro spuštění REPLu. Použijte CTRL-D pro opětovné " -"načtení.\n" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "Předstírám hluboký spánek do alarmu, CTRL-C nebo zápisu souboru.\n" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" -msgstr "Program provedl IN bez načtení ISR" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" -msgstr "Program provedl OUT bez načtení OSR" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" -msgstr "Velikost programu je nesprávná" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "Periférie I2C je používána" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" -msgstr "Program je příliš dlouhý" +#: ports/raspberrypi/common-hal/busio/SPI.c shared-bindings/emmcio/EMMC.c +msgid "SPI peripheral in use" +msgstr "SPI periferie je používána" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" -msgstr "" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" +msgstr "UART periférie je používána" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Pull not used when direction is output." -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "Pin musí být na PWM kanálu B" #: ports/raspberrypi/common-hal/countio/Counter.c msgid "RISE_AND_FALL not available on this chip" msgstr "RISE_AND_FALL není na tomto čipu k dispozici" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" -msgstr "" - -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" +msgstr "PWM kanál je již využíván" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" +msgstr "PWM kanál A je již využíván" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" -msgstr "" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "Všechny stavové automaty jsou používány" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" -msgstr "RTC není na této desce podporován" - -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" -msgstr "Chyba generování náhodných čísel" - -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" -msgstr "Pouze pro čtení" - -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" -msgstr "Filesystém pouze pro čtení" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" -msgstr "Přijatá odpověď nebyla validní" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" +msgstr "Došly mDNS sloty" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" -msgstr "Opětovné připojování" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" +msgstr "Nelze přistupovat k nezarovnanému IO registru" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" -msgstr "Pokus o obnovení příliš brzo" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" +msgstr "Není možné zapisovat do paměti jen pro čtení" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" -msgstr "RemoteTransmissionRequests je limitován na 8 bajtů" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "Všechny časovače pro tento pin jsou používány" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" -msgstr "Požadovaný režim AES je nepodporovaný" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q musí být typu %q, ne %q" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" -msgstr "Požadovaný zdroj nebyl nalezen" +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" +msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" -msgstr "Pravý kanál nepodporován" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" +msgstr "Počet pinů je příliš velký" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" +msgstr "Chybí jmp_pin. %q[%u] skáče na pin" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" -msgstr "Běh v nouzovém režimu! Uložený kód není zpracováván.\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "%q[%u] používá extra pin" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" -msgstr "CSD formát SD karty není podporován" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" +msgstr "Chybí first_in_pin. %q[%u] čeká na základě pinu" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" -msgstr "Inicializace SD karty" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" +msgstr "%q[%u] čeká na vstup mimo rozsah" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" -msgstr "SDIO GetCardInfo chyba %d" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +msgstr "Chybí first_in_pin. %q[%u] posunuje z pinu(ů)" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" +msgstr "%q[%u] posouvá dovnitř o více bitů než je počet pinů" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" -msgstr "Konfigurace SPI selhala" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "Chybí first_out_pin. %q[%u] posunuje do pinu(ů)" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" -msgstr "Chyba inicializace SPI" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "%q[%u] posouvá ven o více bitů než je počet pinů" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "Chybí first_set_pin. %q[%u] nastavuje pin(y)" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" -msgstr "SPI periferie je používána" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "Chybí first_out_pin. %q[%u] zapisuje do pinu(ů)" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" -msgstr "Opětovná inicializace SPI" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" +msgstr "Chybí first_in_pin. %q[%u] čte z pinu(ů)" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" +msgstr "Program provedl IN bez načtení ISR" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." -msgstr "Scan již probíhá. Lze zastavit pomocí stop_scan." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" +msgstr "Program provedl OUT bez načtení OSR" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" msgstr "" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" -msgstr "Velikost není podporována" - -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" +msgstr "V programu není výstup" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" -msgstr "SocketPool je možné použít pouze s wifi.radio" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" +msgstr "V programu není vstup" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" -msgstr "Zdrojové a cílové buffery musí být stejné délky" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" +msgstr "V programu není vstup nebo výstup" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" -msgstr "Specifikuj přesně jeden z data0 nebo data_pins" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" +msgstr "Nekorespondující swap flag" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" -msgstr "Musíš definovat monotonic_time nebo epoch_time" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" +msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" -msgstr "Parametr \"system\" musí být gnss.SatelliteSystem" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" +msgstr "Pouze IPv4 sokety podporovány" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" -msgstr "Čas pro čtení teploty vypršel" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "Všechny DMA kanály jsou používány" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." -msgstr "Modul `microcontroller` byl použit pro spuštění do nouzového režimu." +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" +msgstr "wifi.Monitor není dostupný" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" -msgstr "Výše uvedená výjimka byla přímá příčina následující výjimky:" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q je pouze u této desky pouze pro čtení" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" -msgstr "Počet prvků rgb_pin musí být 6, 12, 18, 24, nebo 30" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "AP nemohl být spuštěn" -#: shared-module/audiocore/__init__.c -msgid "The sample's %q does not match" -msgstr "" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" +msgstr "Na tomto hardware je dostupná pouze detekce hrany" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." -msgstr "Fatální chyby firmware třetí strany." +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" +msgstr "Přerušení od pinu je již používáno" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." -msgstr "Tento mikrokontrolér nepodporuje kontinuální snímání." +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" +msgstr "Z Deep Sleep nelze probudit pinem" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" +"Piny pro hluboký spánek musí používat náběžnou hranu s pulldown rezistorem" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "Neplatná hodnota jednotky ADC" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "Chyba inicializace zařízení DAC" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "Chyba inicializace kanálu DAC" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" +msgstr "je podporováno pouze mono" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." -msgstr "Čas je v minulosti." +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" +msgstr "je podporován pouze oversampling 64" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "Jiný PWMAudioOut je již aktivní" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c #, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "Časový limit je příliš dlouhý: maximální limit je %d vteřin" +msgid "Buffer length %d too big. It must be less than %d" +msgstr "Délka vyrovnávací paměti %d je příliš velká. Musí být menší než %d" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" -msgstr "" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" +msgstr "Nepodařilo se nabufferovat sample" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" -msgstr "V samplu je příliš mnoho kanálů" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "Chyba inicializace I2C" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample." -msgstr "" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" +msgstr "Chyba inicializace SPI" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" -msgstr "" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" +msgstr "Opětovná inicializace SPI" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" msgstr "" -"Příliš mnoho sběrnic displaye; nezapomněl si na displayio.release_displays()?" - -#: shared-module/displayio/__init__.c -msgid "Too many displays" -msgstr "Příliš mnoho displejů" - -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" -msgstr "Velikost dat k zápisu je větší než %q" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" -msgstr "Touch alarmy nejsou dostupné" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "Nelze začít přerušení, RX je zaneprázdněn" -#: py/obj.c -msgid "Traceback (most recent call last):\n" -msgstr "" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" +msgstr "Zápis na UART" #: ports/stm/common-hal/busio/UART.c msgid "UART de-init" msgstr "De-inicializace UART" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c #: ports/stm/common-hal/busio/UART.c -msgid "UART init" -msgstr "Inicializace UART" +msgid "UART re-init" +msgstr "Opětovná inicializace UART" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" +msgstr "Čas pro čtení teploty vypršel" + +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" +msgstr "Časový limit čtení napětí vypršel" + +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" +msgstr "" + +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" +msgstr "Chyba generování náhodných čísel" + +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" -msgstr "UART periférie je používána" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" +msgstr "opětovný init timeru" + +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" +msgstr "opětovná inicializace kanálu" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" -msgstr "Opětovná inicializace UART" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" +msgstr "Restart PWM" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" +msgstr "SDIO GetCardInfo chyba %d" + +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" -msgstr "Zápis na UART" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "Jas není nastavitelný" -#: main.c -msgid "UID:" -msgstr "UID:" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q musí být %d-%d" -#: shared-module/usb_hid/Device.c -msgid "USB busy" -msgstr "USB zaneprázdněno" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "Skupina již byla použita" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." -msgstr "USB zařízení potřebují více endpointů než je k dispozici." +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." -msgstr "USB zařízení používají příliš mnoho názvů rozhraní." +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" -#: shared-module/usb_hid/Device.c +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c msgid "USB error" msgstr "Chyba USB" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "UUID integer musí být 0-0xffff" - -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" -msgstr "UUID řetězec neodpovídá 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" - -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" -msgstr "Hodnota UUID není str, int ani byte buffer" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" +msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" -msgstr "Nelze přistupovat k nezarovnanému IO registru" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "Pod minimální obnovovací frekvencí" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Unable to allocate buffers for signed conversion" +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -msgid "Unable to create lock" -msgstr "Není možné vytvořit zámek" - -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c +#: py/argcheck.c #, c-format -msgid "Unable to find I2C Display at %x" -msgstr "I2C display nenalezen na %x" +msgid "function missing %d required positional arguments" +msgstr "funkci chybí %d povinné poziční argumenty" -#: py/parse.c -msgid "Unable to init parser" +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" -msgstr "Nelze číst data palety barev" +#: py/argcheck.c shared-bindings/wifi/Radio.c +msgid "'%q' argument required" +msgstr "Je vyžadován argument '%q'" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" -msgstr "Nepodařilo se začít mDNS dotaz" - -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." -msgstr "Není možné zapisovat do nvm." - -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" -msgstr "Není možné zapisovat do paměti jen pro čtení" - -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." -msgstr "Nelze zapsat do sleep_memory." +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" +msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" -msgstr "Neznámá chyba BLE na %s:%d: %d" +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c +msgid "argument num/types mismatch" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" -msgstr "Neznámá chyba BLE: %d" +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" +msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" -msgstr "Neznámý chybový kód %d" +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q musí být %d" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" -msgstr "Neznámé selhání %d" +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "%q musí být >= %d" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" -msgstr "" +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "%q musí být <= %d" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." -msgstr "Neznámý důvod." +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "%q délka musí být %d-%d" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" -msgstr "Neznámá bezpečnostní chyba: 0x%04x" +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "Délka %q musí být >= %d" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" -msgstr "Neznámá chyba firmwaru na %s:%d: %d" +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "Délka %q musí být <= %d" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" -msgstr "Neznámá chyba firmwaru: %04x" +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "Délka %q musí být %d" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" -msgstr "Neznámá chyba firmwaru: %d" +#: py/argcheck.c shared-module/audiofilters/__init__.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q v %q musí být typu %q, ne %q" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" -msgstr "Nepodporovaný barevný prostor" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" -msgstr "Nepodporovaná sběrnice dispalye" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q() vyžaduje %d pozičních argumentů, ale pouze %d jich bylo zadáno" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" -msgstr "Nepodporovaný hash algoritmus" +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" +msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" -msgstr "" +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" +msgstr "funkci chybí požadovaný argument na pozici #%d" + +#: py/bc.c +msgid "function missing required keyword argument '%q'" +msgstr "funkci chybí argument specifikovaný klíčovým slovem" + +#: py/bc.c +msgid "function missing keyword-only argument" +msgstr "funkci chybí argument pouze pro klíčové slovo" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: py/binary.c +msgid "integer out of range" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" -msgstr "Verze byla neplatná" +#: py/builtinevex.c +msgid "bad compile mode" +msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" -msgstr "Časový limit čtení napětí vypršel" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" +msgstr "Plus všechny moduly na filesystému\n" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" -msgstr "UPOZORNĚNÍ: Název souboru vašeho kódu má dvě koncovky\n" +#: py/builtinhelp.c +msgid "object " +msgstr "objekt " -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" -msgstr "WatchDogTimer nelze deaktivovat v režimu RESET" +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " je typu %q\n" #: py/builtinhelp.c #, c-format @@ -2460,1679 +2461,1763 @@ msgstr "" "\n" "Seznam vestavěných modulů můžete vypsat pomocí `help(\"modules\")`.\n" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: main.c -msgid "Woken up by alarm.\n" -msgstr "Probuzen alarmem.\n" +#: py/builtinimport.c +msgid "can't perform relative import" +msgstr "nelze provést relativní import" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." -msgstr "Při spuštění jsi stiskl obě tlačítka." +#: py/builtinimport.c +msgid "no module named '%q'" +msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." -msgstr "Při spuštění jsi stiskl tlačítko A." +#: py/builtinimport.c +msgid "relative import" +msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." -msgstr "Při spuštění jsi stiskl tlačítko DOWN." +#: py/compile.c +msgid "can't assign to expression" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" -msgstr "Při spuštění jsi stiskl tlačítko BOOT" +#: py/compile.c +msgid "multiple *x in assignment" +msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." -msgstr "Při spuštění jsi stiskl tlačítko na pinu GPIO0." +#: py/compile.c +msgid "invalid micropython decorator" +msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." -msgstr "Při spuštění jsi stiskl tlačítko Rec." +#: py/compile.c +msgid "invalid arch" +msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." -msgstr "Při spuštění jsi stiskl tlačítko SW38." +#: py/compile.c +msgid "can't delete expression" +msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." -msgstr "Při spuštění jsi stiskl tlačítko VOLUME." +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." -msgstr "Při spuštění jsi stiskl středové tlačítko." +#: py/compile.c +msgid "'return' outside function" +msgstr "'return' je volán mimo funkci" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." -msgstr "Při spuštění jsi stiskl tlačítko doleva." +#: py/compile.c +msgid "import * not at module level" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." -msgstr "Při spuštění jsi stiskl tlačítko reset." +#: py/compile.c +msgid "identifier redefined as global" +msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" -msgstr "[zkráceno kvůli délce]" +#: py/compile.c +msgid "no binding for nonlocal found" +msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/compile.c +msgid "*x must be assignment target" +msgstr "∗x musí být cíl přiřazení" + +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/compile.c +msgid "* arg after **" +msgstr "* arg po **" + +#: py/compile.c +msgid "* arg after kwarg" msgstr "" #: py/compile.c -msgid "annotation must be an identifier" -msgstr "anotace musí být identifikátor" +msgid "too many args" +msgstr "příliš mnoho argumentů" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/compile.c +msgid "LHS of keyword arg must be an id" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" -msgstr "argsort není implementován pro zploštěná pole" +#: py/compile.c +msgid "expecting key:value for dict" +msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/compile.c +msgid "expecting just a value for set" msgstr "" #: py/compile.c -msgid "argument name reused" -msgstr "jméno argumentu znovupoužito" +msgid "'yield' outside function" +msgstr "'yield' je volán mimo funkci" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" -msgstr "" +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "'yield from' volán uvnitř funkce async" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" -msgstr "" +#: py/compile.c +msgid "'await' outside function" +msgstr "'await' je volán mimo funkci" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" -msgstr "Pole a index musí mít stejnou délku" +#: py/compile.c +msgid "unknown type '%q'" +msgstr "neznámý typ '%q'" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" -msgstr "pole má příliš mnoho dimenzí" +#: py/compile.c +msgid "annotation must be an identifier" +msgstr "anotace musí být identifikátor" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" -msgstr "pole je příliš velké" +#: py/compile.c +msgid "argument name reused" +msgstr "jméno argumentu znovupoužito" + +#: py/compile.c +msgid "inline assembler must be a function" +msgstr "" + +#: py/compile.c +msgid "unknown type" +msgstr "neznámý typ" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "přetečení v asm" - #: py/compile.c -msgid "async for/with outside async function" +msgid "expecting an assembler instruction" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "pokus o získání (arg)min/(arg)max z prázdné sekvence" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "'label' vyžaduje 1 argument" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/compile.c +msgid "label redefined" msgstr "" -#: py/objstr.c -msgid "attributes not supported" -msgstr "" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "'align' vyžaduje 1 argument" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" -msgstr "" +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "'data' vyžaduje nejméně 2 argumenty" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" -msgstr "osa je mimo rozsah" +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "'data' vyžaduje celočíselné argumenty" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" -msgstr "osa musí být None nebo integer" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" -msgstr "osa je příliš dlouhá" +#: py/emitbc.c +msgid "bytecode overflow" +msgstr "přetečení bytecode" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: py/emitnative.c -msgid "binary op %q not implemented" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" -msgstr "velikosti bitmapy musí odpovídat" +#: py/emitinlinerv32.c +msgid "opcode '%q': registers must be different" +msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" -msgstr "počet bitů nesmí přesáhnout 32" +#: py/emitinlinerv32.c +msgid "opcode '%q': malformed register list" +msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/emitinlinerv32.c +msgid "opcode '%q': invalid stack adjustment" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: wrong register(s)" +msgstr "" + +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" #: py/emitinlinethumb.c -msgid "branch not in range" +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" -msgstr "buffer je menší než požadovaná velikost" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" +msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" -msgstr "velikost bufferu musí být násobkem velikosti elementu" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s' očekává nanejvýš r%d" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "'%s' očekává registr" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "'%s' očekává speciální registr" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "'%s' očekává registr FPU" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" -msgstr "buffer je příliš malý pro počet požadovaných bajtů" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' očekává {r0, r1, ...}" -#: py/emitbc.c -msgid "bytecode overflow" -msgstr "přetečení bytecode" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "'%s' očekává integer (celé číslo)" -#: py/objarray.c -msgid "bytes length not a multiple of item size" -msgstr "Počet bajtů není násobkem velikosti prvku" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' integer 0x%x nepatří do masky 0x%x" -#: py/objstr.c -msgid "bytes value out of range" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s' očekává adresu ve formátu [a, b]" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' očekává label" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" -msgstr "může mít pouze jednoho rodiče" - -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" #: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +msgid "branch not in range" msgstr "" #: py/emitinlinextensa.c msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" -msgstr "" - -#: py/objtype.c -msgid "can't add special method to already-subclassed class" -msgstr "" - -#: py/compile.c -msgid "can't assign to expression" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" -msgstr "nelze zrušit sám sebe" - -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" -msgstr "není možné převést %q na %q" - -#: py/obj.c +#: py/emitinlinextensa.c #, c-format -msgid "can't convert %s to complex" -msgstr "nelze převést %s na complex" +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' integer %d není v rozsahu %d..%d" -#: py/obj.c +#: py/emitinlinextensa.c #, c-format -msgid "can't convert %s to float" -msgstr "nelze převést %s na float" +msgid "%d is not a multiple of %d" +msgstr "" -#: py/objint.c py/runtime.c +#: py/emitinlinextensa.c #, c-format -msgid "can't convert %s to int" +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" +#: py/emitnative.c +msgid "conversion to object" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" -msgstr "nelze převést complex na float" - -#: py/obj.c -msgid "can't convert to complex" -msgstr "nelze převést na complex" - -#: py/obj.c -msgid "can't convert to float" -msgstr "nelze převést na float" - -#: py/runtime.c -msgid "can't convert to int" -msgstr "nelze převést na int" +#: py/emitnative.c +msgid "local '%q' used before type known" +msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/emitnative.c +msgid "can't load from '%q'" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/emitnative.c +msgid "can't load with '%q' index" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" #: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +msgid "can't store to '%q'" msgstr "" #: py/emitnative.c -msgid "can't do unary op of '%q'" +msgid "can't store with '%q' index" msgstr "" #: py/emitnative.c msgid "can't implicitly convert '%q' to 'bool'" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/emitnative.c +msgid "'not' not implemented" msgstr "" #: py/emitnative.c -msgid "can't load from '%q'" +msgid "can't do unary op of '%q'" msgstr "" #: py/emitnative.c -msgid "can't load with '%q' index" -msgstr "" +msgid "div/mod not implemented for uint" +msgstr "div/mod nejsou implementované pro uint" -#: py/builtinimport.c -msgid "can't perform relative import" -msgstr "nelze provést relativní import" +#: py/emitnative.c +msgid "comparison of int and uint" +msgstr "porovnání int a uint" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" -msgstr "nelze nastavit velikost bloku 512" - -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" -msgstr "nelze nastavit atribut '%q'" +#: py/emitnative.c +msgid "casting" +msgstr "" #: py/emitnative.c -msgid "can't store '%q'" +msgid "return expected '%q' but got '%q'" msgstr "" #: py/emitnative.c -msgid "can't store to '%q'" +msgid "native raise" msgstr "" #: py/emitnative.c -msgid "can't store with '%q' index" +msgid "must raise an object" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/modbuiltins.c py/objstr.c +msgid "char not in range(0x110000)" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" -msgstr "nelze čekat" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" +msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" -msgstr "nelze přiřadit nový tvar" +#: py/modbuiltins.c +msgid "arg is an empty sequence" +msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" -msgstr "nelze převést complex na dtype" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" +msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" -msgstr "nelze převést typ complex" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "pow() nepodporuje 3 argumenty" -#: py/objtype.c -msgid "cannot create instance" +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" -msgstr "nelze smazat prvky pole" +#: py/moderrno.c +msgid "Operation not permitted" +msgstr "Operace není povolena" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" -msgstr "nelze změnit rozměry pole" +#: py/moderrno.c +msgid "No such file/directory" +msgstr "Žádný takový soubor / adresář" -#: py/emitnative.c -msgid "casting" -msgstr "" +#: py/moderrno.c +msgid "Input/output error" +msgstr "Chyba vstupu/výstupu" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" -msgstr "opětovná inicializace kanálu" +#: py/moderrno.c +msgid "Permission denied" +msgstr "Přístup odepřen" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" -msgstr "" +#: py/moderrno.c +msgid "File exists" +msgstr "soubor existuje" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" -msgstr "" +#: py/moderrno.c +msgid "No such device" +msgstr "Žádné takové zařízení" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" -msgstr "" +#: py/moderrno.c +msgid "No space left on device" +msgstr "Na zařízení nezůstal žádný prostor" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" -msgstr "kód mimo rozsah 0~127" +#: py/modmath.c +msgid "negative factorial" +msgstr "záporný faktoriál" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" -msgstr "porovnání int a uint" +#: py/modweakref.c +msgid "not a heap object" +msgstr "" -#: py/objcomplex.c -msgid "complex divide by zero" +#: py/nativeglue.c +msgid "set unsupported" +msgstr "set neoodporován" + +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/nativeglue.c +msgid "float unsupported" +msgstr "float není podporován" + +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" +msgstr "není možné převést %q na %q" + +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" +msgstr "Při zpracování uvedené výjimky nastala další výjimka:" + +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" +msgstr "Výše uvedená výjimka byla přímá příčina následující výjimky:" + +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " Soubor \"%q\", řádek %d" + +#: py/obj.c +msgid " File \"%q\"" +msgstr " Soubor \"%q\"" + +#: py/obj.c +msgid ", in %q\n" +msgstr ", v% q\n" + +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/obj.c +msgid "can't convert to float" +msgstr "nelze převést na float" + +#: py/obj.c +#, c-format +msgid "can't convert %s to float" +msgstr "nelze převést %s na float" + +#: py/obj.c +msgid "can't convert to complex" +msgstr "nelze převést na complex" + +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" +msgstr "nelze převést %s na complex" + +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: py/emitnative.c -msgid "conversion to object" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" +msgstr "objekt '%s' není tuple or nebo list" + +#: py/obj.c +msgid "tuple/list has wrong length" +msgstr "tuple/list má špatnou délku" + +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "Indexy %q musí být celá čísla, nikoli %s" + +#: py/obj.c +msgid "object has no len" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" +msgstr "objekt typu '%s' nemá len()" + +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" -msgstr "poškozený soubor" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "'%s' objekt nepodporuje smazání položky" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" -msgstr "nelze zjistit verzi SD karty" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "'%s' objekt není vložitelný" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" -msgstr "data musí být iterovatelná" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" -msgstr "data musí mít stejnou délku" - -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/obj.c #, c-format -msgid "data pin #%d in use" -msgstr "datový pin #%d je používán" - -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" -msgstr "datový typ nebyl rozpoznán" +msgid "'%s' object doesn't support item assignment" +msgstr "'%s' objekt nepodporuje přiřazení položky" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" -msgstr "" +#: py/objarray.c +msgid "bytes length not a multiple of item size" +msgstr "Počet bajtů není násobkem velikosti prvku" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" -msgstr "" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" +msgstr "memoryview: délka není násobkem velikosti položky" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: py/objdict.c -msgid "dict update sequence has wrong length" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" -msgstr "dimenze nesouhlasí" - -#: py/emitnative.c -msgid "div/mod not implemented for uint" -msgstr "div/mod nejsou implementované pro uint" +#: py/objarray.c +msgid "memoryview offset too large" +msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "divide by zero" -msgstr "dělení nulou" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" +msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" -msgstr "dtype musí být float nebo complex" +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "0.0 na komplexní mocninu" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/objdeque.c +msgid "full" msgstr "" #: py/objdeque.c msgid "empty" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" -msgstr "prázdný soubor" +#: py/objdict.c +msgid "dict update sequence has wrong length" +msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: py/objstr.c -msgid "empty separator" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: py/objstr.c -msgid "end of format while looking for conversion specifier" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" -msgstr "epoch_time není podporován na této desce" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" +msgstr "generátor způsobil StopIteration" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: py/objstr.c -msgid "expected ':' after format specifier" +#: py/objint.c +msgid "float too big" msgstr "" -#: py/obj.c -msgid "expected tuple/list" -msgstr "" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" +msgstr "Není podpora long integer" -#: py/modthread.c -msgid "expecting a dict for keyword args" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "%q=%q" + +#: py/objint_impl.h +#, c-format +msgid "value would overflow a %d byte buffer" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objint_impl.h +msgid "can't convert negative int to unsigned" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" -msgstr "zápis do souboru není dostupný" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" +msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" -msgstr "První argument musí být zavolatelný" +#: py/objobject.c +msgid "arg must be user-type" +msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" -msgstr "první argument musí být funkce" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "%q krok nemůže být nula" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" -msgstr "první argument musí být tuple nebo ndarray" +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "Nelze použít řez podtřídy" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objstr.c +msgid "unknown encoding: %q" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objstr.c +msgid "bytes value out of range" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" -msgstr "první dva argumenty musí být ndarray" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" +msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objstr.c +msgid "empty separator" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objstr.c +msgid "rsplit(None,n)" +msgstr "rsplit(None,n)" + +#: py/objstr.c +msgid "bad format string" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" +msgstr "neshoduje se '%c' ve formátu" + +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: py/nativeglue.c -msgid "float unsupported" -msgstr "float není podporován" - -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" -#: extmod/moddeflate.c -msgid "format" +#: py/objstr.c +#, c-format +msgid "unknown conversion specifier %c" msgstr "" #: py/objstr.c -msgid "format needs a dict" +msgid "expected ':' after format specifier" msgstr "" #: py/objstr.c -msgid "format string didn't convert all arguments" +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" #: py/objstr.c -msgid "format string needs more arguments" +msgid "%q index out of range" +msgstr "Index %q je mimo rozsah" + +#: py/objstr.c +msgid "attributes not supported" msgstr "" -#: py/objdeque.c -msgid "full" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objstr.c +msgid "invalid format specifier" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" -msgstr "funkce je definována pouze pro ndarraye" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "Specifikátor zarovnání '=' není ve formátovacím řetězci povolen" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" -msgstr "funkce je implementována jen pro ndarraye" +#: py/objstr.c +msgid "format needs a dict" +msgstr "" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" -msgstr "funkci chybí %d povinné poziční argumenty" +#: py/objstr.c +msgid "incomplete format key" +msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" -msgstr "funkci chybí argument pouze pro klíčové slovo" +#: py/objstr.c +msgid "incomplete format" +msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" -msgstr "funkci chybí argument specifikovaný klíčovým slovem" +#: py/objstr.c +msgid "format string needs more arguments" +msgstr "" -#: py/bc.c +#: py/objstr.c #, c-format -msgid "function missing required positional argument #%d" -msgstr "funkci chybí požadovaný argument na pozici #%d" +msgid "%%c needs int or char" +msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c +#: py/objstr.c #, c-format -msgid "function takes %d positional arguments but %d were given" +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" -msgstr "generátor způsobil StopIteration" - -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" -msgstr "hash je konečný" - -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/objtemplate.c +msgid "expected str or Interpolation" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy arch" -msgstr "nekopmatibilní architektura .mpy" - -#: py/persistentcode.c -msgid "incompatible .mpy file" -msgstr "nekompatibilní .mpy soubor" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "Volání super().__init__() před přístupem k nativnímu objektu." -#: py/objstr.c -msgid "incomplete format" +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: py/objstr.c -msgid "incomplete format key" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" -msgstr "index musí být tuple nebo int" - -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" -msgstr "výchozí hodnoty musí být iterovatelné" - -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "délka initial_value je chybná" - -#: py/compile.c -msgid "inline assembler must be a function" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" -msgstr "dimenze vstupu a výstupu se liší" - -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" -msgstr "vstupní a výstupní tvar je růzmý" - -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" -msgstr "vstupní argument musí být integer, tuple nebo list" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" -msgstr "vstupní pole nejsou kompatibilní" - -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" -msgstr "vstupní dtype musí být float nebo complex" - -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" -msgstr "vstup není iterovatelný" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" +msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" -msgstr "vstup musí být 1- nebo 2-d" +#: py/objtype.c +msgid "first argument to super() must be type" +msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" -msgstr "vstup musí být 1D ndarray" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" +msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" -msgstr "vstup musí být hustý ndarray" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" +msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" -msgstr "vstup musí být ndarray" +#: py/parse.c +msgid "not a constant" +msgstr "není konstanta" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" -msgstr "vstup musí být ndarray nebo scalar" +#: py/parse.c +msgid "Unable to init parser" +msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" -msgstr "vstup musí být jednorozměrný" +#: py/parse.c +msgid "unexpected indent" +msgstr "neočekávané odsazení" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/parsenum.c +msgid "invalid syntax for integer" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" +#: py/parsenum.c +msgid "invalid syntax for number" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" -msgstr "chybné bits_per_pixel %d, musí být 1, 2, 4, 8, 16, 24, or 32" +#: py/persistentcode.c +msgid "incompatible .mpy file" +msgstr "nekompatibilní .mpy soubor" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" -msgstr "špatný certifikár" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" -msgstr "chybná element_size %d, musí být 1, 2, nebo 4" +#: py/persistentcode.c +msgid "incompatible .mpy arch" +msgstr "nekopmatibilní architektura .mpy" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" -msgstr "špatná výjimka" +#: py/persistentcode.c +msgid "function must be bytecode" +msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "Objekt '%q' nepodporuje '%q'" + +#: py/qstr.c +msgid "name too long" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" -msgstr "špatný hostname" +#: py/runtime.c +msgid "name not defined" +msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" -msgstr "špatný klíč" +#: py/runtime.c +msgid "name '%q' isn't defined" +msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" -msgstr "neplatné nastavení" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" +msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for integer" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: py/parsenum.c +#: py/runtime.c #, c-format -msgid "invalid syntax for integer with base %d" +msgid "too many values to unpack (expected %d)" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "'%s' objekt nemá žádný atribut '%q'" + +#: py/runtime.c +msgid "can't set attribute '%q'" +msgstr "nelze nastavit atribut '%q'" + +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "Objekt '%q' není iterovatelný" + +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "Objekt '%q' není iterátor" + +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" -#: py/compile.c -msgid "label redefined" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: py/runtime.c +msgid "can't convert to int" +msgstr "nelze převést na int" + +#: py/runtime.c +msgid "division by zero" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" +msgstr "" + +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" #: py/vm.c msgid "local variable referenced before assignment" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" -msgstr "mDNS je již inicializováno" +#: py/vm.c +msgid "opcode" +msgstr "opcode" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" -msgstr "mDNS pracuje pouze s vestavěnou WiFi" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "Není možné vytvořit nový adaptér; použití _bleio.adapter;" -#: py/parse.c -msgid "malformed f-string" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "Není možné nastavit adresu" + +#: shared-bindings/_bleio/Adapter.c +#, c-format +msgid "interval must be in range %s-%s" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" +msgstr "nenulový timeout musí být >= interval" + +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " -msgstr "maximální počet dimenzí je " +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "CharacteristicBuffer psaní není poskytováno" -#: py/runtime.c -msgid "maximum recursion depth exceeded" +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." msgstr "" +"Připojení bylo odpojeno a nelze jej dále používat. Vytvořte nové připojení." -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" -msgstr "maxiter musí být > 0" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" +msgstr "Buffer je příliš krátký o %d bajtů" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" -msgstr "maxiter by měl být > 0" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" +msgstr "Žádné připojení: nelze určit délku" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" -msgstr "" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +msgstr "UUID řetězec neodpovídá 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" -msgstr "" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" +msgstr "Hodnota UUID není str, int ani byte buffer" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" -msgstr "" +#: shared-bindings/_bleio/__init__.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" +msgstr "Pouze pro čtení" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" -msgstr "memoryview: délka není násobkem velikosti položky" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "Nesprávná velikost vyrovnávací paměti" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" -msgstr "" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" +msgstr "index musí být tuple nebo int" -#: py/builtinimport.c -msgid "module not found" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" msgstr "" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" -msgstr "" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" +msgstr "Pin je pouze vstupní" -#: py/compile.c -msgid "multiple *x in assignment" +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "Klíč musí být dlouhý 16, 24 nebo 32 bajtů" -#: py/objtype.c -msgid "multiple inheritance not supported" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" +msgstr "Požadovaný režim AES je nepodporovaný" -#: py/emitnative.c -msgid "must raise an object" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" +msgstr "Zdrojové a cílové buffery musí být stejné délky" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB operuje najednou pouze 16 bajtů" -#: py/runtime.c -msgid "name '%q' isn't defined" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "Bloky CBC musí být násobky 16 bajtů" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: py/qstr.c -msgid "name too long" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "Hodnoty pole by měly být jednoduché bajty." -#: py/persistentcode.c -msgid "native code in .mpy unsupported" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." +msgstr "Nelze zapsat do sleep_memory." -#: py/asmthumb.c -msgid "native method too big" -msgstr "" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" +msgstr "Očekáván typ %q" -#: py/emitnative.c -msgid "native yield" -msgstr "" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" +msgstr "RTC není na této desce podporován" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" -msgstr "délka ndarray přetekla" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" +msgstr "Musíš definovat monotonic_time nebo epoch_time" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" -msgstr "" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" +msgstr "epoch_time není podporován na této desce" -#: py/modmath.c -msgid "negative factorial" -msgstr "záporný faktoriál" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." +msgstr "Čas je v minulosti." -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" -msgstr "" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q musí být bytearray nebo pole typu 'H' nebo 'B'" -#: py/objint_mpz.c py/runtime.c -msgid "negative shift count" -msgstr "" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" +msgstr "Nehraje" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "není vložena SD karta" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "Nelze nahrávat do souboru" -#: py/vm.c -msgid "no active exception to reraise" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "Cílová kapacita je menší než destination_length." -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" -msgstr "" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q musí být bytearray nebo pole typu 'h', 'H', 'b', nebo 'B'" -#: py/builtinimport.c -msgid "no module named '%q'" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" -msgstr "žádná odpověď z SD karty" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" +msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c +#: shared-bindings/audiodelays/GranularPitchShift.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" -msgstr "nenulový timeout musí být > 0.01" +#: shared-bindings/audioio/AudioOut.c shared-bindings/emmcio/EMMC.c +msgid "%q and %q must be different" +msgstr "%q a %q musí být rozdílné" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" -msgstr "nenulový timeout musí být >= interval" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" +msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/parse.c -msgid "not a constant" -msgstr "není konstanta" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" +msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" -msgstr "není implementováno pro komplexní dtype" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" +msgstr "zdrojová paleta je příliš velká" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" -msgstr "není podporováno pro vstupní typy" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "Velikost bitmapy a počet bitů na hodnotu se musí shodovat" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +msgstr "Pro barevný prostor L8 musí mít vstupní bitmapa 8 bitů na pixel" -#: py/builtinhelp.c -msgid "object " -msgstr "objekt " +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +msgstr "Pro barevný prostor RGB musí mít vstupní bitmapa 16 bitů na pixel" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" -msgstr "objekt '%s' není tuple or nebo list" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" +msgstr "Nepodporovaný barevný prostor" -#: py/obj.c -msgid "object doesn't support item assignment" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "Pole souřadnic mají různé délky" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" +msgstr "chybná element_size %d, musí být 1, 2, nebo 4" + +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/obj.c +#: shared-bindings/bitmaptools/__init__.c #, c-format -msgid "object of type '%s' has no len()" -msgstr "objekt typu '%s' nemá len()" +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgstr "chybné bits_per_pixel %d, musí být 1, 2, 4, 8, 16, 24, or 32" -#: py/obj.c -msgid "object with buffer protocol required" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" +msgstr "velikosti bitmapy musí odpovídat" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" -msgstr "vypnuto" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" +msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" -msgstr "offset je příliš velký" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" +msgstr "" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" -msgstr "offset musí být >= 0" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" +msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" -msgstr "je podporováno pouze mono" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" +msgstr "Žádná výchozí sběrnice %q" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" -msgstr "pouze ndarraye mohou být spojeny" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "Otočení displeje musí být po 90 stupních" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" -msgstr "je podporován pouze oversampling 64" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q musí být 1, pokud %q je True" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "Displej musí mít 16bitový barevný prostor." -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: py/vm.c -msgid "opcode" -msgstr "opcode" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." +msgstr "Musí být podtřída %q." -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" -msgstr "" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" +msgstr "RemoteTransmissionRequests je limitován na 8 bajtů" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "Nelze nastavit hodnotu, když směr je vstup." -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" -msgstr "operace je definována pouze pro 2D pole" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" -msgstr "operace je definována pouze pro ndarray pole" - -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" -msgstr "operace je immplementována pouze pro 1D boolean pole" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "Nelze odstranit hodnoty" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" -msgstr "výstupní pole je příliš malé" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" +msgstr "nepodporovaný typ% q" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" -msgstr "" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" +msgstr "Nová bitmapa musí mít stejnou velikost jako původní bitmapa" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" -msgstr "" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" +msgstr "offset musí být >= 0" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/emmcio/EMMC.c shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" -msgstr "" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "Pokus o obnovení příliš brzo" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" -msgstr "" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "Buffer není bytearray." -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" +msgstr "Parametr \"system\" musí být gnss.SatelliteSystem" + +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" +msgstr "Nepodporovaný hash algoritmus" + +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" +msgstr "Nevalidní IP string" + +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" +msgstr "Adresa musí být %d bajtů dlouhá" + +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "Pro IP je podporován pouze int nebo string" + +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" -msgstr "" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" +msgstr "Adresní rozsah se překlápí přes maximální možnou adresu" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q obsahuje duplicitní piny" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" -msgstr "pop z prázdného %q" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q a %q obsahují duplicitní piny" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" -msgstr "port musí být >= 0" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" +msgstr "kód mimo rozsah 0~127" -#: py/compile.c -msgid "positional arg after **" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" -msgstr "" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." +msgstr "Není možné zapisovat do nvm." -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" -msgstr "" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" +msgstr "Specifikuj přesně jeden z data0 nebo data_pins" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "Špatný formát" + +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." +msgstr "Nepodařilo se odeslat příkaz." + +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "Pole musí obsahovat poloviční slova (typ „H“)" + +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +msgstr "Počet prvků rgb_pin musí být 6, 12, 18, 24, nebo 30" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -4142,447 +4227,563 @@ msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" -msgstr "" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" +msgstr "Je nutné použít několik kolíků 6 rgb, nikoli %d" -#: py/objstr.c -msgid "rsplit(None,n)" -msgstr "rsplit(None,n)" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +msgstr "%d adresní pin, %d rgb pin a %d dlaždice indikuje výšku %d, ne %d" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" -msgstr "" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" +msgstr "port musí být >= 0" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" -msgstr "" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" +msgstr "buffer je příliš malý pro počet požadovaných bajtů" -#: py/modmicropython.c -msgid "schedule queue full" -msgstr "" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" +msgstr "Jméno nebo služba není známa" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: py/nativeglue.c -msgid "set unsupported" -msgstr "set neoodporován" - -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" -msgstr "tvar musí být integer nebo tuple integerů" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "Nelze změnit USB zařízení" -#: shared-module/msgpack/__init__.c -msgid "short read" -msgstr "" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" +msgstr "Soubor nenalezen" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" +msgstr "zápis do souboru není dostupný" + +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" +msgstr "špatná výjimka" + +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q, a %q musí mít všechny shodnou délku" + +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" +"Objekt byl deinicializován a nelze jej dále používat. Vytvořte nový objekt." -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" msgstr "" -#: main.c -msgid "soft reboot\n" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" +msgstr "Špatné heslo v hex" + +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" +msgstr "špatný hostname" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "Chybná MAC adresa" + +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "AuthMode.OPEN nepoužívá heslo" + +#: shared-bindings/wifi/Radio.c +msgid "Supply either %q or %q, not both" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "Chybné BSSID" + +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "Autentizace selhala" + +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" +msgstr "Žádná síť s takovým SSID" + +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" +msgstr "Neznámé selhání %d" + +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" +msgstr "Žádné I2C zařízení na adrese: 0x%x" + +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "Neplatná velikost bloku" + +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" -msgstr "zdrojová paleta je příliš velká" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "Dekodér nelze přiřadit" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "Soubor MP3 se nepodařilo analyzovat" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" -msgstr "" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" +msgstr "Pouze jedna barva může být nastavena jako transparentní" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" -msgstr "" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "Vrstva již v groupě je" -#: py/objstrunicode.c -msgid "string index out of range" -msgstr "" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "Vrstva musí být Group nebo TileGrid" -#: py/objstrunicode.c +#: shared-module/displayio/OnDiskBitmap.c #, c-format -msgid "string indices must be integers, not %s" +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" +msgstr "Nelze číst data palety barev" + +#: shared-module/displayio/__init__.c +msgid "Too many displays" +msgstr "Příliš mnoho displejů" + +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" +"Příliš mnoho sběrnic displaye; nezapomněl si na displayio.release_displays()?" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" +msgstr "Nepodporovaná sběrnice dispalye" + +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" +msgstr "I2C display nenalezen na %x" + +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" -msgstr "timeout překročil maximální podporovanou hodnotu" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." +msgstr "Tento mikrokontrolér nepodporuje kontinuální snímání." -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" -msgstr "timeout musí být < 655.35 s" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "Mapování LED musí korespondovat s velikostí displeje" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" -msgstr "opětovný init timeru" - -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" msgstr "" -#: py/compile.c -msgid "too many args" -msgstr "příliš mnoho argumentů" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" -msgstr "příliš mnoho dimenzí" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" +msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: py/runtime.c +#: shared-module/memorymonitor/AllocationAlarm.c #, c-format -msgid "too many values to unpack (expected %d)" +msgid "Attempt to allocate %d blocks" +msgstr "Pokus o alokování %d bloků" + +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" -msgstr "tuple/list má špatnou délku" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" +msgstr "Není k dispozici žádný časovač" -#: ports/espressif/common-hal/canio/CAN.c +#: shared-module/rgbmatrix/RGBMatrix.c #, c-format -msgid "twai_driver_install returned esp-idf error #%d" -msgstr "" +msgid "Internal error #%d" +msgstr "Vnitřní chyba #%d" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" +msgstr "není vložena SD karta" + +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" +msgstr "nelze zjistit verzi SD karty" + +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" +msgstr "žádná odpověď z SD karty" + +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" +msgstr "CSD formát SD karty není podporován" + +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" +msgstr "nelze nastavit velikost bloku 512" + +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "Chybný soket pro TLS" + +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" +msgstr "špatný klíč" + +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" +msgstr "špatný certifikár" + +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' a 'O' nejsou podporované typy formátů" + +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "%q musí být pole typu 'h'" + +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/parse.c -msgid "unexpected indent" -msgstr "neočekávané odsazení" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" +msgstr "Žádný pulldown na pinu; doporučeno 1Mohm" -#: py/bc.c -msgid "unexpected keyword argument" -msgstr "" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" +msgstr "Žádný USB host port není inicializován" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" +#: shared-module/usb/core/Device.c +msgid "Pipe error" msgstr "" -#: py/lexer.c -msgid "unicode name escapes" -msgstr "" +#: shared-module/usb/core/Device.c +msgid "No configuration set" +msgstr "Konfigurace není nastavena" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" -msgstr "" +#: shared-module/usb_hid/Device.c +msgid "USB busy" +msgstr "USB zaneprázdněno" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" +msgstr "může mít pouze jednoho rodiče" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" -msgstr "" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" +msgstr "Polygon potřebuje nejméně 3 body" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" +msgstr "Opětovné připojování" -#: py/compile.c -msgid "unknown type" -msgstr "neznámý typ" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" +msgstr "Ok" -#: py/compile.c -msgid "unknown type '%q'" -msgstr "neznámý typ '%q'" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" +msgstr "Vypnuto" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" -msgstr "neshoduje se '%c' ve formátu" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "[zkráceno kvůli délce]" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" +"\n" +"Jste v bezpečnostním režimu z důvodu:\n" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" -msgstr "nepodporovaný typ% q" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." +msgstr "Pokles napájení. Zkontroluj, zda je k dispozici dostatečné napájení." -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" +msgstr "Při spuštění jsi stiskl tlačítko BOOT" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." +msgstr "Při spuštění jsi stiskl tlačítko reset." -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "Disk CIRCUITPY nelze nalézt nebo vytvořit." -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." +msgstr "Modul `microcontroller` byl použit pro spuštění do nouzového režimu." -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "Chyba v safemode.py." -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." +msgstr "USB zařízení potřebují více endpointů než je k dispozici." -#: py/runtime.c -msgid "unsupported type for operator" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." +msgstr "USB zařízení používají příliš mnoho názvů rozhraní." -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "Bootovací zařízení musí být první (rozhraní #0)." -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "Interní watchdog timer expiroval." -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "Jádro kódu CircuitPython tvrdě havarovalo. Jejda!\n" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." +msgstr "Alokace heapu při neběžícím VM." -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." +msgstr "Nepodařilo se zapsat do interní paměti." -#: extmod/moddeflate.c -msgid "wbits" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." +msgstr "Fatální chyba: přístup k paměti nebo chyba instrukce." -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." +msgstr "Chyba přerušení." -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." +msgstr "NLR skok selhal. Pravděpodobně poškozením paměti." -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" -msgstr "wifi.Monitor není dostupný" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." +msgstr "Fatální chyby firmware třetí strany." -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" +"\n" +"Prosím, založte issue s vaším programem na github.com/adafruit/circuitpython/" +"issues." -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" +"\n" +"Stiskněte reset pro ukončení nouzového režimu.\n" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" -msgstr "" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "Došlo k chybě při načítání '%s'\n" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" -msgstr "špatný dtype" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" +msgstr "Neplatná unicode escape sekvence" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" -msgstr "špatný typ indexu" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" -msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" +msgstr "vypnuto" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" -msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "Není IP" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" -msgstr "" +#~ msgid "%q out of bounds" +#~ msgstr "%q je mimo hranice" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" -msgstr "" +#~ msgid "asm overflow" +#~ msgstr "přetečení v asm" -#: py/runtime.c -msgid "wrong number of values to unpack" -msgstr "" +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Vyrovnávací paměť + offset je příliš malý %d %d %d" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" -msgstr "" +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Buffer musí být dlouhý 16 bajtů." -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" -msgstr "" +#~ msgid "UUID integer value must be 0-0xffff" +#~ msgstr "UUID integer musí být 0-0xffff" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" -msgstr "" +#~ msgid "initial_value length is wrong" +#~ msgstr "délka initial_value je chybná" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" -msgstr "" +#, c-format +#~ msgid "Invalid byte %.*s" +#~ msgstr "Špatný byte %.*s" + +#~ msgid "Key not found" +#~ msgstr "Klíč nenalezen" #, c-format #~ msgid "%%c requires int or char" @@ -4876,8 +5077,8 @@ msgstr "" #~ msgstr "IV musí být dlouhé %d bajtů" #~ msgid "" -#~ "Incompatible .mpy file. Please update all .mpy files. See http://adafru." -#~ "it/mpy-update for more info." +#~ "Incompatible .mpy file. Please update all .mpy files. See http://" +#~ "adafru.it/mpy-update for more info." #~ msgstr "" #~ "Nekompatibilní soubor .mpy. Aktualizujte prosím všechny soubory .mpy. " #~ "Další informace naleznete na adrese http://adafru.it/mpy-update." diff --git a/locale/el.po b/locale/el.po index 91624ceb086..16b979aea44 100644 --- a/locale/el.po +++ b/locale/el.po @@ -18,1722 +18,1530 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -"\n" -"Η εκτέλεση του κώδικα ολοκληρώθηκε.\n" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -"\n" -"Ο κώδικας σταμάτησε λόγω της αυτόματης επαναφόρτωσης. Η επαναφόρτωση θα " -"γίνει σύντομα.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -"\n" -"Παρακαλώ δημιουργήστε ένα πρόβλημα με το πρόγραμμά σας στο github.com/" -"adafruit/circuitpython/issues." -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -"\n" -"Πατήστε reset για να βγείτε από την ασφαλή λειτουργία.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -"\n" -"Είσαστε τε ασφαλή λειτουργία διότι:\n" - -#: py/obj.c -msgid " File \"%q\"" -msgstr " Αρχείο \"%q\"" - -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " Αρχείο \"%q\", γραμμή %d" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " είναι τύπου %q\n" +#: extmod/moddeflate.c +msgid "format" +msgstr "" -#: main.c -msgid " not found.\n" -msgstr " δεν βρέθηκε.\n" +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" -#: main.c -msgid " output:\n" -msgstr " έξοδος:\n" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modheapq.c +msgid "heap must be a list" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modjson.c +msgid "syntax error in JSON" msgstr "" -"%d pin διεύθυνσης, %d rgb ping και %d πλακίδια αναδεικνύουν ύψος %d, όχι %d" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q και %q περιέχουν διπλότυπα pins" +#: extmod/modrandom.c +msgid "bits must be 32 or less" +msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q και %q πρεπει να είναι διαφορετικά" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modre.c +msgid "splitting with sub-captures" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modre.c +msgid "regex too complex" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q περιέχει διπλότυπα pins" +#: extmod/modre.c +msgid "Error in regex" +msgstr "Σφάλμα σε regex" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -msgid "%q failure: %d" -msgstr "%q αποτυχία: %d" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" +msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "%q στο %q πρέπει να είναι τύπου %q, όχι %q" +#: extmod/modzlib.c +msgid "compression header" +msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q είναι σε χρήση" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" +msgstr "" -#: py/objstr.c -msgid "%q index out of range" -msgstr "%q δείκτης εκτός εμβέλειας" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "%q δείκτες πρέπει να είναι ακέραιοι, όχι %s" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c -msgid "%q init failed" -msgstr "%q εκκίνηση απέτυχε" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q είναι %q" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "%q είναι μόνο για ανάγνωση για αυτήν την πλακέτα" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "%q μήκος πρέπει να είναι %d" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "%q μήκος πρέπει να είναι %d-%d" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "%q μήκος πρέπει να είναι <= %d" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "%q μήκος πρέπει να είναι >= %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "%q μετακινήθηκε από το %q στο %q" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q πρέπει να είναι %d" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q πρέπει να είναι %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q πρέπει να είναι 1 όταν %q είναι True" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "%q πρέπει να είναι <= %d" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" -msgstr "%q πρέπει να είναι <= %u" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" +msgstr "" -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "%q πρέπει να είναι >= %d" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" +msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q πρέπει να είναι bytearray ή array τύπου 'H' ή 'B'" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q πρέπει να είναι bytearray ή array τύπου 'h', 'H', 'b', ή 'B'" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" -msgstr "%q πρέπει να είναι υποκλάση του %q" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" -msgstr "%q πρέπει να είναι πίνακας τύπου 'H'" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" -msgstr "%q πρέπει να είναι λίστα τύπου 'h'" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "%q πρέπει να είναι τύπου %q ή %q, όχι %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" +msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q πρέπει να είναι τύπου %q, όχι %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q πρέπει να είναι δύναμη του 2" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" +msgstr "" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "%q εκτός ορίων" +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "%q εκτός εμβέλειας" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" +msgstr "" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "%q μεταονομάστηκε σε %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" +msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "%q βήμα δεν μπορεί να είναι μηδέν" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q() παίρνει %d ορίσματα θέσεως αλλά %d δόθηκαν" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q, και %q πρέπει να είναι όλα του ιδίου μήκους" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" -msgstr "%q[%u] μετατοπίζει σε περισσότερα bits από αριθμό pin" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" -msgstr "%q[%u] μετατοπίζει από περισσότερα bits από αριθμό pin" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "%q[%u] χρησιμοποιεί παραπάνω pin" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "%s σφάλμα 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "'%q' όρισμα απαιτείται" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "" -#: py/proto.c -msgid "'%q' object does not support '%q'" -msgstr "'%q' αντικείμενο δεν υποστηρίζει '%q'" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "'%q' αντικείμενο δεν είναι επαναλήπτης" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "'%q' αντικείμενο δεν είναι επαναληπτικό" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' περιμένει μια ετικέτα" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' περιμένει έναν καταχωρητή" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' περιμένει έναν ειδικό καταχωρητή" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' περιμένει έναν FPU καταχωρητή" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s' περιμένει μια διεύθυνση της μορφής [a, b]" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' περιμένει έναν ακέραιο" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s' περιμένει το πολύ r%d" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' περιμένει {r0, r1, ...}" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' ακέραιος %d δεν είναι μέσα στο επιτρεπτό εύρος %d..%d" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' ακέραιος 0x%x δεν χωράει στην μάσκα 0x%x" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "'%s' αντικείμενο δεν υποστηρίζει ορισμό πράγματος" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "'%s' αντικείμενο δεν υποστηρίζει διαγραφή πράγματος" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "'%s' αντικείμενο δεν έχει γνώρισμα '%q'" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "'%s' αντικείμενο δεν είναι subscriptable" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "Ευθυγράμμιση του '=' δεν επιτρέπεται εντός προσδιοριστή string format" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' και 'O' δεν είναι υποστηριζόμενοι τύποι format" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "'align' απαιτεί τουλάχιστον ένα όρισμα" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "" -#: py/compile.c -msgid "'await' outside function" -msgstr "'await' εκτός συνάρτησης" - -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "'break'/'continue' εκτός επανάληψης" - -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "'data' απαιτεί τουλάχιστον 2 παραμέτρους" - -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "'data' απαιτεί ακέραιες παραμέτρους" - -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "'label' απαιτεί ένα όρισμα" - -#: py/emitnative.c -msgid "'not' not implemented" -msgstr "" - -#: py/compile.c -msgid "'return' outside function" -msgstr "'return' εκτός συνάρτησης" - -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "'yield from' εκτός ασύνχρονης συνάρτησης" - -#: py/compile.c -msgid "'yield' outside function" -msgstr "'yield' εκτός συνάρτησης" - -#: py/compile.c -msgid "* arg after **" -msgstr "* όρισμα μετά **" - -#: py/compile.c -msgid "*x must be assignment target" -msgstr "*x πρέπει να είναι στόχος ανάθεσης" - -#: py/obj.c -msgid ", in %q\n" -msgstr ", στο %q\n" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" -msgstr ".show(x) αφαιρέθηκε. Χρησιμοποιήστε το .root_group = x" - -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "0.0 σε μία σύνθετη δύναμη" - -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "pow() με 3 παραμέτρους δεν υποστηρίζεται" - -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "AP δεν μπόρεσε να εκκινηθεί" - -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "Η διεύθυνση πρέπει να είναι %d bytes μεγάλη" - -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "Εμβέλεια διευθύνσεων δεν επιτρέπεται" - -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "Όλα τα περιφεριακά CAN είναι σε χρήση" - -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "Όλα τα I2C περιφεριακά ειναι σε χρήση" - -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "Όλα τα RX FIFOs είναι σε χρήση" - -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "Όλα τα SPI περιφεριακά είναι σε χρήση" - -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "Όλα τα UART περιφεριακά ειναι σε χρήση" - -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "Όλα τα κανάλια είναι σε χρήση" - -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "Όλα τα κανάλια dma είναι σε χρήση" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "Όλα τα κανάλια συμβάντων είναι σε χρήση" - -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "Όλες οι μηχανές κατάστασης είναι σε χρήση" - -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" -msgstr "Όλα τα κανάλια συμβάντων συγχρονισμού είναι σε χρήση" - -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "Όλοι οι χρονιστές για αυτό το pin χρησιμοποιούνται ήδη" - -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "Όλοι οι χρονιστές βρίσκονται σε χρήση" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "Ήδη διαφημίζουμε." - -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "Ύπάρχει ήδη all-matches ακροατής" - -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" -msgstr "" - -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "Τρέχει ήδη" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "Ήδη γίνεται σάρωση για δίκτυα wifi" - -#: shared-module/os/getenv.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "Παρουσιάστηκε σφάλμα κατά την ανάκτηση '%s':\n" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "Και άλλο PWMAudioOut είναι σε χρήση" - -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "Άλλη αποστολή είναι ήδη ενεργή" - -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "H παράταξη πρέπει να περιέχει halfwords (τύπου 'H')" - -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "Η τιμές της παράταξη πρέπει να είναι μονά bytes." - -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" - -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "Προσπάθεια να δεσμευτούν %d blocks" - -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "Η μετατροπή ήχου δεν υποστηρίζεται" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Audio source error" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "AuthMode.OPEN δεν μπορεί να χρησιμοποιηθεί με κωδικό" - -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "Αποτυχία αυθεντικοποίησης" - -#: main.c -msgid "Auto-reload is off.\n" -msgstr "Η αυτόματη επαναφόρτωση είναι απενεργοποιημένη.\n" - -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" -msgstr "" -"Η αυτόματη επαναφόρτωση είναι ενεργή. Αποθηκεύστε αρχεία μέσω USB για να " -"τρέξετε ή ανοίξτε το REPL για απενεργοποίηση.\n" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "Baudrate δεν υποστηρίζεται από την περιφεριακή συσκευή" - -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "Χαμηλότερο από το ελάχιστο frame rate" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "Ρολόι bit και ορισμού λέξης πρέπει να είναι διαδοχικά GPIO pins" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "Το μέγεθος του bitmap και τα bits ανα τιμή πρέπει να ταιριάζουν" - -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "Η συσκευή εκκίνησης πρέπει να επιλεχθεί πρώτα (διεπαφή #0)." - -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "Και RX και TX απαιτούνται για έλεγχο flow" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "H φωτεινότητα δεν μπορεί να προσαρμοστεί" - -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Buffer + offset είναι πολύ μικρά %d %d %d" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "Στοιχεία του buffer πρέπει να είναι το πολύ 4 bytes" - -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "Το buffer δεν είναι ένα bytearray." - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "Το μήκος buffer %d είναι πολύ μεγάλο. Πρέπει ν α είναι λιγότερο απο %d" - -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "Buffer πολύ μικρό κατα %d bytes" - -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "Buffer πολύ μικρός" - -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Bus pin %d είναι ήδη σε χρήση" - -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Byte buffer πρέπει να είναι 16 bytes." - -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "CBC blocks πρέπει να είναι πολλαπλάσια του 16 bytes" - -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "Ο CIRCUITPY δίσκος δεν μπόρεσε να βρεθεί ή να δημιουργηθεί." - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC ή checksum ήταν άκυρο" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "Κλήση super().__init__() πρίν την πρόσβαση του τοπικού αντικειμένου." +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" -msgstr "Εκκίνηση κάμερας" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "Μόνο IO alarm ή RTC επιτρέπονται από βαθύ ύπνο." +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" msgstr "" -"Μόνο ένα alarm από low pin ενώ τα άλλα alarm θα είναι απο high σε βαθύ ύπνο." -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." -msgstr "Μπορεί να γίνει alarm μόνο σε δύο low pins σε βαθύ ύπνο." +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "Δεν μπορεί να οριστεί CCCD σε τοπικό Characteristic" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "Δεν μπορούν να αλλάξουν οι USB συσκευές τώρα" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" msgstr "" -"Δεν μπορεί να δημιουργηθεί νέο Adapter; χρησιμοποιείστε _bleio.adapter;" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "Δεν μπορούν να διαγραφούν οι τιμές" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "Δεν γίνεται να διαβαστεί το pull όσο είναι σε output mode" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "Δεν μπορεί να διαβαστεί η θερμοκρασία" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" msgstr "" -"Δεν μπορούμε να έχουμε απαντήσεις scan για εκτεταμένες, συνδεόμενες " -"διαφημήσεις." -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "Δεν γίνεται pull σε pin μόνο για εισόδο." +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Cannot record to a file" -msgstr "Δεν μπορεί να γίνει καταγραφή σε αρχείο" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" +msgstr "" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Cannot set value when direction is input." -msgstr "Δεν μπορεί να οριστεί τιμή οταν η κατεύθυνση είναι input." +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "Δεν μπορεί να οριστεί RTS ή CTS σε RS485 mode" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" +msgstr "" -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "Δεν γίνεται υποκατηγορία ενός slice" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" -msgstr "Δεν γίνεται αφύπνηση σε pin edge, αλλά μόνο σε level" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." -msgstr "Δεν μπορεί να γίνει αφύπνηση σε pin edge. Μόνο level." +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "Δεν υποστηρίζονται εγγραφές στο CharacteristicBuffer" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "Ο πυρήνας της CircuitPython κατέρευσε. Οουπς!\n" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "Μονάδα ρολογιού ήδη σε χρήση" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" msgstr "" -"Έχει γίνει αποσύνδεση και αυτή η συνδεση δεν μπορεί να χρησιμοποιηθεί. " -"Δημιουργήστε μια νέα σύνδεση." -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "Δεν μπόρεσε να ρυθμιστεί η διεύθυνση" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "Δεν μπόρεσε να εκκινηθεί το interrupt, RX κατειλημμένο" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "Δεν μπόρεσε να δεσμευτεί decoder" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" -msgstr "Σφάλμα εκκίνησης καναλιού DAC" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Device Init Error" -msgstr "Σφάλμα εκκίνησης συσκευής DAC" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC είναι ήδη σε χρήση" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" +msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "Το Data 0 pin πρέπει να είναι byte aligned" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "Δεν υποστηρίζονται δεδομένα με κατευθυνόμενη διαφήμιση" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "Τα δεδομένα είναι πολύ μεγάλα για πακέτο διαφημίσεων" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "Τα pins βαθύ ύπνου πρέπει να χρησιμοποιούν rising edge με pulldown" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Destination capacity is smaller than destination_length." +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" msgstr "" -"Το μέγεθος προορισμού πρέπει να είναι μικρότερο από το destination_length." -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" msgstr "" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "Συσκευή σε χρήση" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#, fuzzy -msgid "Display must have a 16 bit colorspace." -msgstr "Η οθόνη πρέπει να έχει 16 bit χρωματική ευκρίνεια." +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display rotation must be in 90 degree increments" -msgstr "Η περιστροφή της οθόνη πρέπει να γίνεται σε βήματα 90 μοιρών" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "" -#: main.c -msgid "Done" -msgstr "Ολοκληρώθηκε" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" +msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Drive mode not used when direction is input." -msgstr "Ο τρόπος οδήγησης δεν χρησιμοποιείται όταν η κατεύθυνση είναι είσοδος." +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" msgstr "" -"Κατά την αντιμετώπιση της παραπάνω εξαίρεσης, ακόμα μία εξαίρεση συνέβη:" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB δουλεύει μόνο σε 16 bytes κάθε φορά" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -msgid "ESP-IDF memory allocation failed" -msgstr "ESP-IDF δέσμευση μνήμης απέτυχε" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" +msgstr "" -#: extmod/modre.c -msgid "Error in regex" -msgstr "Σφάλμα σε regex" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "Σφάλμα στο safemode.py." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "" -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" msgstr "" -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" msgstr "" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" msgstr "" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" msgstr "" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" +#: main.c +msgid "Done" +msgstr "Ολοκληρώθηκε" + +#: main.c +msgid " output:\n" +msgstr " έξοδος:\n" + +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" msgstr "" +"Η αυτόματη επαναφόρτωση είναι ενεργή. Αποθηκεύστε αρχεία μέσω USB για να " +"τρέξετε ή ανοίξτε το REPL για απενεργοποίηση.\n" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" +#: main.c +msgid "Auto-reload is off.\n" +msgstr "Η αυτόματη επαναφόρτωση είναι απενεργοποιημένη.\n" + +#: main.c +msgid "Running in safe mode! Not running saved code.\n" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" +#: main.c +msgid " not found.\n" +msgstr " δεν βρέθηκε.\n" + +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" +"\n" +"Ο κώδικας σταμάτησε λόγω της αυτόματης επαναφόρτωσης. Η επαναφόρτωση θα " +"γίνει σύντομα.\n" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" +#: main.c +msgid "" +"\n" +"Code done running.\n" msgstr "" +"\n" +"Η εκτέλεση του κώδικα ολοκληρώθηκε.\n" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." +#: main.c +msgid "Woken up by alarm.\n" msgstr "" -#: py/moderrno.c -msgid "File exists" +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" +"Πατήστε οποιοδήποτε πλήκτρο για να μπείτε στο REPL. Πατήστε CTRL-D για " +"επαναφόρτωση.\n" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c -msgid "File not found" +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +msgstr "Προσποίηση βαθύ ύπνου μεχρι γεγονότος, CTRL-C ή εγγραφή αρχείου.\n" + +#: main.c +msgid "UID:" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" +#: main.c +msgid "soft reboot\n" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c +msgid "%q init failed" +msgstr "%q εκκίνηση απέτυχε" + +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "%q εκτός εμβέλειας" + +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "Και RX και TX απαιτούνται για έλεγχο flow" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" msgstr "" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "Όλα τα UART περιφεριακά ειναι σε χρήση" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "Όλα τα κανάλια συμβάντων συγχρονισμού είναι σε χρήση" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" msgstr "" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" msgstr "" -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." msgstr "" -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "" +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "Όλοι οι χρονιστές βρίσκονται σε χρήση" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" msgstr "" -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" msgstr "" -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" -msgstr "" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "Μονάδα ρολογιού ήδη σε χρήση" -#: py/moderrno.c -msgid "Input/output error" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC είναι ήδη σε χρήση" -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c -msgid "Internal error" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "Όλα τα κανάλια συμβάντων είναι σε χρήση" -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" -msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q πρέπει να είναι δύναμη του 2" -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "Όλα τα RX FIFOs είναι σε χρήση" + +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "Ύπάρχει ήδη all-matches ακροατής" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "Δεν γίνεται να διαβαστεί το pull όσο είναι σε output mode" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" msgstr "" #: ports/atmel-samd/common-hal/microcontroller/Pin.c #: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c #: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/microcontroller/Pin.c msgid "Invalid %q pin" msgstr "" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "Το Data 0 pin πρέπει να είναι byte aligned" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "Bus pin %d είναι ήδη σε χρήση" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "" +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "Άλλη αποστολή είναι ήδη ενεργή" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" -msgstr "" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/socketpool/SocketPool.c +msgid "%q failure: %d" +msgstr "%q αποτυχία: %d" -#: shared-module/os/getenv.c +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/audiocore/WaveFile.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/floppyio/__init__.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format -msgid "Invalid byte %.*s" +msgid "Buffer must be a multiple of %d bytes" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" -#: shared-module/msgpack/__init__.c -msgid "Invalid format" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" msgstr "" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "Εκκίνηση κάμερας" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "Buffer πολύ μικρός" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" msgstr "" -#: shared-module/os/getenv.c -msgid "Invalid unicode escape" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "Τρέχει ήδη" + +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q είναι %q" + +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." msgstr "" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." msgstr "" -#: py/compile.c -msgid "LHS of keyword arg must be an id" +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "MMC/SDIO Clock Error %x" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" msgstr "" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "Τα δεδομένα είναι πολύ μεγάλα για πακέτο διαφημίσεων" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "Ήδη διαφημίζουμε." + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." msgstr "" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "Δεν υποστηρίζονται δεδομένα με κατευθυνόμενη διαφήμιση" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Service.c +msgid "Too many %q" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "Δεν μπορεί να οριστεί CCCD σε τοπικό Characteristic" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +#: ports/espressif/common-hal/_bleio/Connection.c +msgid "No pairing in progress" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" msgstr "" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" msgstr "" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" +#: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Already in progress" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c +#: ports/espressif/common-hal/_bleio/__init__.c #, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" +msgid "Unknown system firmware error at %s:%d: %d" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" msgstr "" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" msgstr "" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#, c-format +msgid "Unknown BLE error: %d" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "Δεν μπορεί να γίνει αφύπνηση σε pin edge. Μόνο level." -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "Δεν γίνεται pull σε pin μόνο για εισόδο." -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "No DAC on chip" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." +msgstr "Μπορεί να γίνει alarm μόνο σε δύο low pins σε βαθύ ύπνο." + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." msgstr "" +"Μόνο ένα alarm από low pin ενώ τα άλλα alarm θα είναι απο high σε βαθύ ύπνο." -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA channel found" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "Μόνο IO alarm ή RTC επιτρέπονται από βαθύ ύπνο." + +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "%q πρέπει να είναι πίνακας τύπου 'H'" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c shared-bindings/emmcio/EMMC.c +msgid "Peripheral in use" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" msgstr "" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" msgstr "" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -#: ports/atmel-samd/common-hal/busio/I2C.c #: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "Όλα τα I2C περιφεριακά ειναι σε χρήση" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" msgstr "" -#: py/moderrno.c -msgid "No space left on device" -msgstr "" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "Όλα τα SPI περιφεριακά είναι σε χρήση" -#: py/moderrno.c -msgid "No such device" +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "ESP-IDF δέσμευση μνήμης απέτυχε" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "Δεν μπορεί να οριστεί RTS ή CTS σε RS485 mode" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" msgstr "" -#: py/moderrno.c -msgid "No such file/directory" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "Baudrate δεν υποστηρίζεται από την περιφεριακή συσκευή" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "Όλα τα περιφεριακά CAN είναι σε χρήση" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" msgstr "" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c -msgid "Not playing" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#, c-format -msgid "Number of data_pins must be %d or %d, not %d" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" msgstr "" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c +#: shared-bindings/picogame/__init__.c +msgid "Operation or feature not supported" msgstr "" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC ή checksum ήταν άκυρο" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" msgstr "" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" +msgstr "%s σφάλμα 0x%x" + +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" msgstr "" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q είναι σε χρήση" + #: ports/espressif/common-hal/espulp/ULPAlarm.c msgid "Only one %q can be set." msgstr "" @@ -1743,2846 +1551,3229 @@ msgstr "" msgid "Only one address is allowed" msgstr "" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" -msgstr "" - -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" msgstr "" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: py/moderrno.c -msgid "Operation not permitted" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation timed out" -msgstr "" +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "Εμβέλεια διευθύνσεων δεν επιτρέπεται" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" msgstr "" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" -#: ports/espressif/common-hal/audiobusio/__init__.c -msgid "Peripheral in use" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" msgstr "" -#: py/moderrno.c -msgid "Permission denied" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" msgstr "" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" msgstr "" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" -msgstr "" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "%q πρέπει να είναι <= %u" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" msgstr "" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "Ήδη γίνεται σάρωση για δίκτυα wifi" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" msgstr "" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Only IPv4 addresses supported" msgstr "" -"Πατήστε οποιοδήποτε πλήκτρο για να μπείτε στο REPL. Πατήστε CTRL-D για " -"επαναφόρτωση.\n" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "Προσποίηση βαθύ ύπνου μεχρι γεγονότος, CTRL-C ή εγγραφή αρχείου.\n" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +#: shared-bindings/emmcio/EMMC.c +msgid "Hardware in use, try alternative pins" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Pull not used when direction is output." +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" +#: ports/nordic/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "Numeric comparison pairing" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "" +"Unspecified issue. The pairing request on the other device may have been " +"declined or ignored." msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#, c-format +msgid "Unknown security error: 0x%04x" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" +msgstr "Δεν γίνεται αφύπνηση σε pin edge, αλλά μόνο σε level" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "Συσκευή σε χρήση" + +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "Όλα τα κανάλια είναι σε χρήση" + +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "Δεν μπορεί να διαβαστεί η θερμοκρασία" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" msgstr "" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "Η μετατροπή ήχου δεν υποστηρίζεται" + +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/__init__.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q πρέπει να είναι τύπου %q ή %q, όχι %q" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "Στοιχεία του buffer πρέπει να είναι το πολύ 4 bytes" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" msgstr "" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "Ρολόι bit και ορισμού λέξης πρέπει να είναι διαδοχικά GPIO pins" + +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." +#: ports/raspberrypi/common-hal/busio/SPI.c shared-bindings/emmcio/EMMC.c +msgid "SPI peripheral in use" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" msgstr "" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "Όλες οι μηχανές κατάστασης είναι σε χρήση" + +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" msgstr "" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" -msgstr "" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "Όλοι οι χρονιστές για αυτό το pin χρησιμοποιούνται ήδη" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" -msgstr "" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q πρέπει να είναι τύπου %q, όχι %q" -#: shared-module/audiocore/__init__.c -msgid "The sample's %q does not match" +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" msgstr "" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" msgstr "" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "%q[%u] χρησιμοποιεί παραπάνω pin" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" msgstr "" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" msgstr "" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" +msgstr "%q[%u] μετατοπίζει σε περισσότερα bits από αριθμό pin" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "%q[%u] μετατοπίζει από περισσότερα bits από αριθμό pin" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many displays" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" msgstr "" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" msgstr "" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" -msgstr "" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "Όλα τα κανάλια dma είναι σε χρήση" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: main.c -msgid "UID:" -msgstr "" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q είναι μόνο για ανάγνωση για αυτήν την πλακέτα" -#: shared-module/usb_hid/Device.c -msgid "USB busy" -msgstr "" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "AP δεν μπόρεσε να εκκινηθεί" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" +msgstr "Τα pins βαθύ ύπνου πρέπει να χρησιμοποιούν rising edge με pulldown" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "Σφάλμα εκκίνησης συσκευής DAC" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "Σφάλμα εκκίνησης καναλιού DAC" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Unable to allocate buffers for signed conversion" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -msgid "Unable to create lock" -msgstr "" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "Και άλλο PWMAudioOut είναι σε χρήση" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c #, c-format -msgid "Unable to find I2C Display at %x" -msgstr "" +msgid "Buffer length %d too big. It must be less than %d" +msgstr "Το μήκος buffer %d είναι πολύ μεγάλο. Πρέπει ν α είναι λιγότερο απο %d" -#: py/parse.c -msgid "Unable to init parser" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" msgstr "" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" -msgstr "" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "Δεν μπόρεσε να εκκινηθεί το interrupt, RX κατειλημμένο" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "Unknown system firmware error: %d" +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" +msgstr ".show(x) αφαιρέθηκε. Χρησιμοποιήστε το .root_group = x" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "H φωτεινότητα δεν μπορεί να προσαρμοστεί" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q πρέπει να είναι %d-%d" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "Χαμηλότερο από το ελάχιστο frame rate" + +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" msgstr "" -#: py/builtinhelp.c +#: py/argcheck.c #, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" +msgid "function expected at most %d arguments, got %d" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " +#: py/argcheck.c shared-bindings/wifi/Radio.c +msgid "'%q' argument required" +msgstr "'%q' όρισμα απαιτείται" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: main.c -msgid "Woken up by alarm.\n" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c +msgid "argument num/types mismatch" msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q πρέπει να είναι %d" + +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "%q πρέπει να είναι >= %d" + +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "%q πρέπει να είναι <= %d" + +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "%q μήκος πρέπει να είναι %d-%d" + +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "%q μήκος πρέπει να είναι >= %d" + +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "%q μήκος πρέπει να είναι <= %d" + +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "%q μήκος πρέπει να είναι %d" + +#: py/argcheck.c shared-module/audiofilters/__init__.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q στο %q πρέπει να είναι τύπου %q, όχι %q" + +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q() παίρνει %d ορίσματα θέσεως αλλά %d δόθηκαν" + +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." +#: py/binary.c py/objarray.c +msgid "bad typecode" +msgstr "" + +#: py/binary.c +msgid "integer out of range" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/builtinhelp.c +msgid "object " msgstr "" -#: py/objtype.c +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " είναι τύπου %q\n" + +#: py/builtinhelp.c #, c-format -msgid "__init__() should return None, not '%s'" +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: py/compile.c -msgid "annotation must be an identifier" +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/compile.c +msgid "invalid arch" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/compile.c +msgid "can't delete expression" msgstr "" #: py/compile.c -msgid "argument name reused" -msgstr "" +msgid "'break'/'continue' outside loop" +msgstr "'break'/'continue' εκτός επανάληψης" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" -msgstr "" +#: py/compile.c +msgid "'return' outside function" +msgstr "'return' εκτός συνάρτησης" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" #: py/compile.c msgid "async for/with outside async function" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "" +#: py/compile.c +msgid "*x must be assignment target" +msgstr "*x πρέπει να είναι στόχος ανάθεσης" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/compile.c +msgid "* arg after **" +msgstr "* όρισμα μετά **" + +#: py/compile.c +msgid "* arg after kwarg" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/compile.c +msgid "too many args" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/compile.c +msgid "LHS of keyword arg must be an id" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/compile.c +msgid "'yield' outside function" +msgstr "'yield' εκτός συνάρτησης" + +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "'yield from' εκτός ασύνχρονης συνάρτησης" + +#: py/compile.c +msgid "'await' outside function" +msgstr "'await' εκτός συνάρτησης" + +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: py/emitnative.c -msgid "binary op %q not implemented" +#: py/compile.c +msgid "argument name reused" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." +#: py/compile.c +msgid "inline assembler must be a function" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/compile.c +msgid "unknown type" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "'label' απαιτεί ένα όρισμα" + +#: py/compile.c +msgid "label redefined" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "'align' απαιτεί τουλάχιστον ένα όρισμα" + +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "'data' απαιτεί τουλάχιστον 2 παραμέτρους" + +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "'data' απαιτεί ακέραιες παραμέτρους" + +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/emitbc.c +msgid "bytecode overflow" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: py/emitbc.c -msgid "bytecode overflow" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: py/objarray.c -msgid "bytes length not a multiple of item size" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: py/objstr.c -msgid "bytes value out of range" +#: py/emitinlinerv32.c +msgid "opcode '%q': registers must be different" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" +#: py/emitinlinerv32.c +msgid "opcode '%q': malformed register list" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/emitinlinerv32.c +msgid "opcode '%q': invalid stack adjustment" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: wrong register(s)" msgstr "" #: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +msgid "invalid RV32 instruction '%q'" msgstr "" #: py/emitinlinethumb.c msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s' περιμένει το πολύ r%d" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "'%s' περιμένει έναν καταχωρητή" -#: py/compile.c -msgid "can't assign to expression" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "'%s' περιμένει έναν ειδικό καταχωρητή" -#: extmod/modasyncio.c -msgid "can't cancel self" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "'%s' περιμένει έναν FPU καταχωρητή" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' περιμένει {r0, r1, ...}" -#: py/obj.c +#: py/emitinlinethumb.c py/emitinlinextensa.c #, c-format -msgid "can't convert %s to complex" -msgstr "" +msgid "'%s' expects an integer" +msgstr "'%s' περιμένει έναν ακέραιο" -#: py/obj.c +#: py/emitinlinethumb.c #, c-format -msgid "can't convert %s to float" -msgstr "" +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' ακέραιος 0x%x δεν χωράει στην μάσκα 0x%x" -#: py/objint.c py/runtime.c +#: py/emitinlinethumb.c #, c-format -msgid "can't convert %s to int" -msgstr "" +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s' περιμένει μια διεύθυνση της μορφής [a, b]" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' περιμένει μια ετικέτα" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: py/obj.c -msgid "can't convert to complex" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" -#: py/obj.c -msgid "can't convert to float" +#: py/emitinlinethumb.c +msgid "branch not in range" msgstr "" -#: py/runtime.c -msgid "can't convert to int" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' ακέραιος %d δεν είναι μέσα στο επιτρεπτό εύρος %d..%d" + +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/emitnative.c +msgid "conversion to object" msgstr "" #: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +msgid "local '%q' used before type known" msgstr "" #: py/emitnative.c -msgid "can't do unary op of '%q'" +msgid "can't load from '%q'" msgstr "" #: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +msgid "can't load with '%q' index" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" #: py/emitnative.c -msgid "can't load from '%q'" +msgid "can't store '%q'" msgstr "" #: py/emitnative.c -msgid "can't load with '%q' index" +msgid "can't store to '%q'" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" +#: py/emitnative.c +msgid "can't store with '%q' index" msgstr "" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/emitnative.c +msgid "'not' not implemented" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/emitnative.c +msgid "can't do unary op of '%q'" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/emitnative.c +msgid "div/mod not implemented for uint" msgstr "" #: py/emitnative.c -msgid "can't store '%q'" +msgid "comparison of int and uint" msgstr "" #: py/emitnative.c -msgid "can't store to '%q'" +msgid "binary op %q not implemented" msgstr "" #: py/emitnative.c -msgid "can't store with '%q' index" +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/emitnative.c +msgid "casting" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/emitnative.c +msgid "native raise" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/emitnative.c +msgid "must raise an object" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/modbuiltins.c py/objstr.c +msgid "char not in range(0x110000)" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: py/objtype.c -msgid "cannot create instance" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: py/emitnative.c -msgid "casting" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "pow() με 3 παραμέτρους δεν υποστηρίζεται" + +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/moderrno.c +msgid "Operation not permitted" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/moderrno.c +msgid "No such file/directory" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" +#: py/moderrno.c +msgid "Input/output error" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" +#: py/moderrno.c +msgid "Permission denied" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/moderrno.c +msgid "File exists" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/moderrno.c +msgid "No such device" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/moderrno.c +msgid "No space left on device" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: py/objcomplex.c -msgid "complex divide by zero" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/modweakref.c +msgid "not a heap object" msgstr "" -#: py/emitnative.c -msgid "conversion to object" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" msgstr "" +"Κατά την αντιμετώπιση της παραπάνω εξαίρεσης, ακόμα μία εξαίρεση συνέβη:" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " Αρχείο \"%q\", γραμμή %d" + +#: py/obj.c +msgid " File \"%q\"" +msgstr " Αρχείο \"%q\"" + +#: py/obj.c +msgid ", in %q\n" +msgstr ", στο %q\n" + +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/obj.c #, c-format -msgid "data pin #%d in use" +msgid "can't convert %s to complex" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" -msgstr "" +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "%q δείκτες πρέπει να είναι ακέραιοι, όχι %s" -#: py/objdict.c -msgid "dict update sequence has wrong length" +#: py/obj.c +msgid "object has no len" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "'%s' αντικείμενο δεν υποστηρίζει διαγραφή πράγματος" + +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: py/emitnative.c -msgid "div/mod not implemented for uint" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "'%s' αντικείμενο δεν είναι subscriptable" + +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "divide by zero" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "'%s' αντικείμενο δεν υποστηρίζει ορισμό πράγματος" + +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: py/objdeque.c -msgid "empty" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: py/objstr.c -msgid "empty separator" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: py/objstr.c -msgid "end of format while looking for conversion specifier" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "0.0 σε μία σύνθετη δύναμη" + +#: py/objdeque.c +msgid "full" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objdeque.c +msgid "empty" msgstr "" -#: py/objstr.c -msgid "expected ':' after format specifier" +#: py/objdict.c +msgid "dict update sequence has wrong length" msgstr "" -#: py/obj.c -msgid "expected tuple/list" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: py/modthread.c -msgid "expecting a dict for keyword args" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objint.c +msgid "float too big" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" +#: py/objint.c shared-bindings/_bleio/Connection.c #: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" +msgid "%q=%q" +msgstr "%q=%q" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/objint_impl.h +#, c-format +msgid "value would overflow a %d byte buffer" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/objint_impl.h +msgid "can't convert negative int to unsigned" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "%q βήμα δεν μπορεί να είναι μηδέν" -#: extmod/moddeflate.c -msgid "format" +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "Δεν γίνεται υποκατηγορία ενός slice" + +#: py/objstr.c +msgid "unknown encoding: %q" msgstr "" #: py/objstr.c -msgid "format needs a dict" +msgid "bytes value out of range" msgstr "" #: py/objstr.c -msgid "format string didn't convert all arguments" +msgid "join expects a list of str/bytes objects consistent with self object" msgstr "" #: py/objstr.c -msgid "format string needs more arguments" +msgid "empty separator" msgstr "" -#: py/objdeque.c -msgid "full" +#: py/objstr.c +msgid "rsplit(None,n)" msgstr "" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: py/argcheck.c +#: py/objstr.c #, c-format -msgid "function expected at most %d arguments, got %d" +msgid "unmatched '%c' in format" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" +#: py/objstr.c +#, c-format +msgid "unknown conversion specifier %c" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objstr.c +msgid "expected ':' after format specifier" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" -msgstr "" +#: py/objstr.c +msgid "%q index out of range" +msgstr "%q δείκτης εκτός εμβέλειας" -#: py/bc.c -msgid "function missing required keyword argument '%q'" +#: py/objstr.c +msgid "attributes not supported" msgstr "" -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" +#: py/objstr.c +msgid "invalid format specifier" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "Ευθυγράμμιση του '=' δεν επιτρέπεται εντός προσδιοριστή string format" + +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/objstr.c +msgid "incomplete format key" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/objstr.c +msgid "incomplete format" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy arch" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy file" +#: py/objstr.c +msgid "non-hex digit" msgstr "" #: py/objstr.c -msgid "incomplete format" +msgid "can't convert to str implicitly" msgstr "" #: py/objstr.c -msgid "incomplete format key" +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/objtemplate.c +msgid "expected str or Interpolation" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "Κλήση super().__init__() πρίν την πρόσβαση του τοπικού αντικειμένου." + +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/parse.c +msgid "not a constant" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/parse.c +msgid "Unable to init parser" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/parsenum.c +msgid "invalid syntax for integer" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/parsenum.c +msgid "invalid syntax for number" +msgstr "" + +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: py/persistentcode.c +msgid "incompatible .mpy arch" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +#: py/persistentcode.c +msgid "function must be bytecode" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" -msgstr "" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "'%q' αντικείμενο δεν υποστηρίζει '%q'" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +#: py/qstr.c +msgid "name too long" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for integer" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "'%s' αντικείμενο δεν έχει γνώρισμα '%q'" + +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "'%q' αντικείμενο δεν είναι επαναληπτικό" + +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "'%q' αντικείμενο δεν είναι επαναλήπτης" + +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: py/runtime.c +msgid "can't convert to int" msgstr "" -#: py/compile.c -msgid "label redefined" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" #: py/vm.c msgid "local variable referenced before assignment" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" +#: py/vm.c +msgid "opcode" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" +"Δεν μπορεί να δημιουργηθεί νέο Adapter; χρησιμοποιείστε _bleio.adapter;" -#: py/parse.c -msgid "malformed f-string" -msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "Δεν μπόρεσε να ρυθμιστεί η διεύθυνση" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" +#: shared-bindings/_bleio/Adapter.c +#, c-format +msgid "interval must be in range %s-%s" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." msgstr "" +"Δεν μπορούμε να έχουμε απαντήσεις scan για εκτεταμένες, συνδεόμενες " +"διαφημήσεις." -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: py/runtime.c -msgid "maximum recursion depth exceeded" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "Δεν υποστηρίζονται εγγραφές στο CharacteristicBuffer" + +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." msgstr "" +"Έχει γίνει αποσύνδεση και αυτή η συνδεση δεν μπορεί να χρησιμοποιηθεί. " +"Δημιουργήστε μια νέα σύνδεση." -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" +msgstr "Buffer πολύ μικρό κατα %d bytes" + +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" +#: shared-bindings/_bleio/__init__.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" msgstr "" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" -#: py/builtinimport.c -msgid "module not found" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" msgstr "" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" msgstr "" -#: py/compile.c -msgid "multiple *x in assignment" +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: py/objtype.c -msgid "multiple inheritance not supported" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: py/emitnative.c -msgid "must raise an object" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB δουλεύει μόνο σε 16 bytes κάθε φορά" -#: py/runtime.c -msgid "name '%q' isn't defined" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "CBC blocks πρέπει να είναι πολλαπλάσια του 16 bytes" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: py/qstr.c -msgid "name too long" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "Η τιμές της παράταξη πρέπει να είναι μονά bytes." -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: py/asmthumb.c -msgid "native method too big" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" msgstr "" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: py/modmath.c -msgid "negative factorial" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" -msgstr "" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q πρέπει να είναι bytearray ή array τύπου 'H' ή 'B'" -#: py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "Δεν μπορεί να γίνει καταγραφή σε αρχείο" -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." msgstr "" +"Το μέγεθος προορισμού πρέπει να είναι μικρότερο από το destination_length." -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q πρέπει να είναι bytearray ή array τύπου 'h', 'H', 'b', ή 'B'" + +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: py/builtinimport.c -msgid "no module named '%q'" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c +#: shared-bindings/audiodelays/GranularPitchShift.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/audioio/AudioOut.c shared-bindings/emmcio/EMMC.c +msgid "%q and %q must be different" +msgstr "%q και %q πρεπει να είναι διαφορετικά" + +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" msgstr "" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "Το μέγεθος του bitmap και τα bits ανα τιμή πρέπει να ταιριάζουν" + +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: py/builtinhelp.c -msgid "object " +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: py/obj.c -msgid "object doesn't support item assignment" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: py/obj.c -msgid "object with buffer protocol required" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "Η περιστροφή της οθόνη πρέπει να γίνεται σε βήματα 90 μοιρών" + +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q πρέπει να είναι 1 όταν %q είναι True" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#, fuzzy +msgid "Display must have a 16 bit colorspace." +msgstr "Η οθόνη πρέπει να έχει 16 bit χρωματική ευκρίνεια." + +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "Δεν μπορεί να οριστεί τιμή οταν η κατεύθυνση είναι input." -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "Ο τρόπος οδήγησης δεν χρησιμοποιείται όταν η κατεύθυνση είναι είσοδος." -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: py/vm.c -msgid "opcode" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" -msgstr "" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "Δεν μπορούν να διαγραφούν οι τιμές" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/emmcio/EMMC.c shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "Το buffer δεν είναι ένα bytearray." + +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" +msgstr "Η διεύθυνση πρέπει να είναι %d bytes μεγάλη" + +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" msgstr "" -#: py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" msgstr "" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q περιέχει διπλότυπα pins" + +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q και %q περιέχουν διπλότυπα pins" + +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" msgstr "" -#: py/compile.c -msgid "positional arg after **" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "H παράταξη πρέπει να περιέχει halfwords (τύπου 'H')" + +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: py/obj.c +#: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "requested length %d but object has length %d" +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +msgstr "" +"%d pin διεύθυνσης, %d rgb ping και %d πλακίδια αναδεικνύουν ύψος %d, όχι %d" + +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" msgstr "" -#: py/objstr.c -msgid "rsplit(None,n)" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "Δεν μπορούν να αλλάξουν οι USB συσκευές τώρα" + +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" msgstr "" -#: py/nativeglue.c -msgid "set unsupported" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "short read" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q, και %q πρέπει να είναι όλα του ιδίου μήκους" + +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "%q πρέπει να είναι υποκλάση του %q" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" msgstr "" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "AuthMode.OPEN δεν μπορεί να χρησιμοποιηθεί με κωδικό" + +#: shared-bindings/wifi/Radio.c +msgid "Supply either %q or %q, not both" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" msgstr "" -#: main.c -msgid "soft reboot\n" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "Αποτυχία αυθεντικοποίησης" + +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "Δεν μπόρεσε να δεσμευτεί decoder" + +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" msgstr "" -#: py/objstrunicode.c -#, c-format -msgid "string indices must be integers, not %s" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: py/compile.c -msgid "too many args" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" msgstr "" -#: py/runtime.c -#, c-format -msgid "too many values to unpack (expected %d)" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c +#: shared-module/memorymonitor/AllocationAlarm.c #, c-format -msgid "twai_driver_install returned esp-idf error #%d" +msgid "Attempt to allocate %d blocks" +msgstr "Προσπάθεια να δεσμευτούν %d blocks" + +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Internal error #%d" msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: py/parse.c -msgid "unexpected indent" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" msgstr "" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" msgstr "" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/compile.c -msgid "unknown type" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/compile.c -msgid "unknown type '%q'" -msgstr "" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' και 'O' δεν είναι υποστηριζόμενοι τύποι format" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "%q πρέπει να είναι λίστα τύπου 'h'" + +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" +#: shared-module/usb/core/Device.c +msgid "Pipe error" msgstr "" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" +#: shared-module/usb/core/Device.c +msgid "No configuration set" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" msgstr "" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" +"\n" +"Είσαστε τε ασφαλή λειτουργία διότι:\n" -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." msgstr "" -#: extmod/moddeflate.c -msgid "wbits" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "Ο CIRCUITPY δίσκος δεν μπόρεσε να βρεθεί ή να δημιουργηθεί." + +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "Σφάλμα στο safemode.py." + +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "Η συσκευή εκκίνησης πρέπει να επιλεχθεί πρώτα (διεπαφή #0)." + +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "Ο πυρήνας της CircuitPython κατέρευσε. Οουπς!\n" + +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." msgstr "" -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: py/runtime.c -msgid "wrong number of values to unpack" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" +"\n" +"Παρακαλώ δημιουργήστε ένα πρόβλημα με το πρόγραμμά σας στο github.com/" +"adafruit/circuitpython/issues." -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" +"\n" +"Πατήστε reset για να βγείτε από την ασφαλή λειτουργία.\n" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "Παρουσιάστηκε σφάλμα κατά την ανάκτηση '%s':\n" + +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" msgstr "" +#~ msgid "%q out of bounds" +#~ msgstr "%q εκτός ορίων" + +#~ msgid "%q renamed %q" +#~ msgstr "%q μεταονομάστηκε σε %q" + +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Buffer + offset είναι πολύ μικρά %d %d %d" + +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Byte buffer πρέπει να είναι 16 bytes." + +#~ msgid "%q moved from %q to %q" +#~ msgstr "%q μετακινήθηκε από το %q στο %q" + #, c-format #~ msgid "%%c requires int or char" #~ msgstr "%%c απαιτεί ακέραιο ή χαρακτήρα" diff --git a/locale/en_GB.po b/locale/en_GB.po index 8d640a3c680..29380c91c80 100644 --- a/locale/en_GB.po +++ b/locale/en_GB.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-06-15 23:04+0000\n" +"PO-Revision-Date: 2026-04-30 11:09+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: none\n" "Language: en_GB\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.12-dev\n" +"X-Generator: Weblate 5.17.1\n" #: main.c msgid "" @@ -527,7 +527,7 @@ msgstr "All channels in use" #: ports/raspberrypi/common-hal/usb_host/Port.c msgid "All dma channels in use" -msgstr "All DMA channels in use" +msgstr "All dma channels in use" #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "All event channels in use" diff --git a/locale/es.po b/locale/es.po index 85a03408b75..87589c2c28b 100644 --- a/locale/es.po +++ b/locale/es.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-08-03 08:01+0000\n" -"Last-Translator: MAE \n" +"PO-Revision-Date: 2026-05-06 18:11+0000\n" +"Last-Translator: Francisco Serrador \n" "Language-Team: \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.13-dev\n" +"X-Generator: Weblate 5.17.1\n" #: main.c msgid "" @@ -614,7 +614,6 @@ msgid "Array values should be single bytes." msgstr "Valores del array deben ser bytes individuales." #: ports/atmel-samd/common-hal/spitarget/SPITarget.c -#, fuzzy msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" "Transferencia SPI asíncrona en curso en este canal, manténgase esperando." @@ -1064,9 +1063,8 @@ msgid "Failed to create continuous channels: not found" msgstr "Error al crear canales continuos: no encontrado" #: ports/espressif/common-hal/audioio/AudioOut.c -#, fuzzy msgid "Failed to enable continuous" -msgstr "Fallo habilitando continous" +msgstr "Ha fallado al habilitar continuo" #: shared-module/audiomp3/MP3Decoder.c msgid "Failed to parse MP3 file" @@ -1912,9 +1910,8 @@ msgid "Program too long" msgstr "El programa es demasiado grande" #: shared-bindings/rclcpy/Publisher.c -#, fuzzy msgid "Publishers can only be created from a parent node" -msgstr "Publicadores solo pueden ser creados desde un nodo padre" +msgstr "Las publicadores solo pueden ser creadas desde un nodo antecesor" #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." @@ -2170,9 +2167,8 @@ msgid "Tile width must exactly divide bitmap width" msgstr "Ancho del Tile debe dividir exactamente el ancho de mapa de bits" #: shared-module/tilepalettemapper/TilePaletteMapper.c -#, fuzzy msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "Tilepalettemapper sólo puede vincularse una vez a un TileGrid" +msgstr "TilePaletteMapper solo puede vincularse una vez a un TileGrid" #: shared-bindings/alarm/time/TimeAlarm.c msgid "Time is in the past." diff --git a/locale/hi.po b/locale/hi.po index 1ab48338eba..d0fd102bae7 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -18,1754 +18,1919 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -#: py/obj.c -msgid " File \"%q\"" +#: extmod/moddeflate.c +msgid "format" msgstr "" -#: py/obj.c -msgid " File \"%q\", line %d" +#: extmod/moddeflate.c +msgid "wbits" msgstr "" -#: py/builtinhelp.c -msgid " is of type %q\n" +#: extmod/modhashlib.c +msgid "hash is final" msgstr "" -#: main.c -msgid " not found.\n" +#: extmod/modheapq.c +msgid "heap must be a list" msgstr "" -#: main.c -msgid " output:\n" +#: extmod/modjson.c +msgid "syntax error in JSON" msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modrandom.c +msgid "bits must be 32 or less" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" +#: extmod/modre.c +msgid "splitting with sub-captures" msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" +#: extmod/modre.c +msgid "regex too complex" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modre.c +msgid "Error in regex" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -msgid "%q failure: %d" +#: extmod/modzlib.c +msgid "compression header" msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c -msgid "%q in use" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" msgstr "" -#: py/objstr.c -msgid "%q index out of range" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c -msgid "%q init failed" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" msgstr "" -#: py/runtime.c -msgid "%q moved from %q to %q" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" msgstr "" -#: py/argcheck.c -msgid "%q must be %d" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" msgstr "" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " msgstr "" -#: py/argcheck.c -msgid "%q must be >= %d" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" msgstr "" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" msgstr "" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" msgstr "" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c -msgid "%q out of range" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" msgstr "" -#: py/objmodule.c -msgid "%q renamed %q" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" msgstr "" -#: py/proto.c -msgid "'%q' object does not support '%q'" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" msgstr "" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" msgstr "" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" msgstr "" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" msgstr "" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" msgstr "" -#: py/compile.c -msgid "'await' outside function" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" msgstr "" -#: py/compile.c -msgid "'break'/'continue' outside loop" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" msgstr "" -#: py/compile.c -msgid "'data' requires at least 2 arguments" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" msgstr "" -#: py/compile.c -msgid "'data' requires integer arguments" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" msgstr "" -#: py/compile.c -msgid "'label' requires 1 argument" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" msgstr "" -#: py/emitnative.c -msgid "'not' not implemented" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" msgstr "" -#: py/compile.c -msgid "'return' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" msgstr "" -#: py/compile.c -msgid "'yield from' inside async function" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" msgstr "" -#: py/compile.c -msgid "'yield' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" msgstr "" -#: py/compile.c -msgid "* arg after **" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" msgstr "" -#: py/compile.c -msgid "*x must be assignment target" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" msgstr "" -#: py/obj.c -msgid ", in %q\n" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" msgstr "" -#: py/objcomplex.c -msgid "0.0 to a complex power" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" msgstr "" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" msgstr "" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" msgstr "" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" msgstr "" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" msgstr "" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" msgstr "" -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" msgstr "" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" msgstr "" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" msgstr "" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" msgstr "" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" msgstr "" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Audio source error" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" msgstr "" -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" msgstr "" -#: main.c -msgid "Auto-reload is off.\n" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" msgstr "" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" msgstr "" -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Bit clock and word select must be sequential GPIO pins" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" msgstr "" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" +#: main.c +msgid "Done" msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" +#: main.c +msgid " output:\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" msgstr "" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" +#: main.c +msgid "Auto-reload is off.\n" msgstr "" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" +#: main.c +msgid "Running in safe mode! Not running saved code.\n" msgstr "" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" +#: main.c +msgid " not found.\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Cannot record to a file" +#: main.c +msgid "" +"\n" +"Code done running.\n" msgstr "" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: main.c +msgid "Woken up by alarm.\n" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Cannot set value when direction is input." +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" msgstr "" -#: py/objslice.c -msgid "Cannot subclass slice" +#: main.c +msgid "UID:" +msgstr "UID:" + +#: main.c +msgid "soft reboot\n" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c +msgid "%q init failed" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" msgstr "" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Device Init Error" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" msgstr "" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "" + +#: ports/atmel-samd/common-hal/_pew/PewPew.c #: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Destination capacity is smaller than destination_length." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" msgstr "" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display rotation must be in 90 degree increments" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" msgstr "" -#: main.c -msgid "Done" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Drive mode not used when direction is input." +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "" + +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" +msgstr "" + +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" msgstr "" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c #: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -msgid "ESP-IDF memory allocation failed" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" msgstr "" -#: extmod/modre.c -msgid "Error in regex" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" msgstr "" -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" +msgstr "" + +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" msgstr "" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "" + +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c #: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." +msgid "pop from empty %q" msgstr "" -#: ports/nordic/sd_mutex.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" +msgstr "" + +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/socketpool/SocketPool.c +msgid "%q failure: %d" +msgstr "" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/audiocore/WaveFile.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/floppyio/__init__.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format -msgid "Failed to acquire mutex, err 0x%04x" +msgid "Buffer must be a multiple of %d bytes" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" msgstr "" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" msgstr "" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "" + +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" msgstr "" -#: ports/nordic/sd_mutex.c +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c #, c-format -msgid "Failed to release mutex, err 0x%04x" +msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Service.c +msgid "Too many %q" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" msgstr "" -#: py/moderrno.c -msgid "File exists" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" msgstr "" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c -msgid "File not found" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" +#: ports/espressif/common-hal/_bleio/Connection.c +msgid "No pairing in progress" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" msgstr "" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Already in progress" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" msgstr "" -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." msgstr "" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." msgstr "" -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." msgstr "" -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." msgstr "" -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" msgstr "" -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c shared-bindings/emmcio/EMMC.c +msgid "Peripheral in use" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" msgstr "" -#: py/moderrno.c -msgid "Input/output error" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" msgstr "" -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c -msgid "Internal error" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" msgstr "" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" msgstr "" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "Invalid format" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" msgstr "" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" msgstr "" -#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" +#: ports/raspberrypi/common-hal/picogame/Display.c +#: shared-bindings/picogame/__init__.c +msgid "Operation or feature not supported" msgstr "" -#: shared-module/os/getenv.c -msgid "Invalid unicode escape" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" msgstr "" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" msgstr "" -#: py/compile.c -msgid "LHS of keyword arg must be an id" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c #, c-format -msgid "MMC/SDIO Clock Error %x" +msgid "Unknown error code %d" msgstr "" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" msgstr "" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" +msgid "SDIO Init Error 0x%02x" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" msgstr "" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" msgstr "" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c -msgid "No %q pin" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" msgstr "" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "No DAC on chip" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA channel found" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Only IPv4 addresses supported" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +#: shared-bindings/emmcio/EMMC.c +msgid "Hardware in use, try alternative pins" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" msgstr "" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" +#: ports/nordic/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "Numeric comparison pairing" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" msgstr "" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "" +"Unspecified issue. The pairing request on the other device may have been " +"declined or ignored." msgstr "" -#: py/moderrno.c -msgid "No space left on device" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#, c-format +msgid "Unknown security error: 0x%04x" msgstr "" -#: py/moderrno.c -msgid "No such device" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" msgstr "" -#: py/moderrno.c -msgid "No such file/directory" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" msgstr "" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c -msgid "Not playing" +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#, c-format -msgid "Number of data_pins must be %d or %d, not %d" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" msgstr "" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/__init__.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" msgstr "" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" msgstr "" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" msgstr "" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" msgstr "" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: py/moderrno.c -msgid "Operation not permitted" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation timed out" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" +#: ports/raspberrypi/common-hal/busio/SPI.c shared-bindings/emmcio/EMMC.c +msgid "SPI peripheral in use" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" msgstr "" #: ports/raspberrypi/common-hal/countio/Counter.c @@ -1776,89 +1941,109 @@ msgstr "" msgid "PWM slice channel A already in use" msgstr "" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: ports/espressif/common-hal/audiobusio/__init__.c -msgid "Peripheral in use" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: py/moderrno.c -msgid "Permission denied" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" msgstr "" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" msgstr "" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" msgstr "" #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c msgid "Pins must be sequential GPIO pins" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" msgstr "" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" msgstr "" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" msgstr "" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" msgstr "" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -1869,1464 +2054,1434 @@ msgstr "" msgid "Program does OUT without loading OSR" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" msgstr "" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Pull not used when direction is output." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" msgstr "" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" msgstr "" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" msgstr "" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: shared-module/audiocore/__init__.c -msgid "The sample's %q does not match" +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" msgstr "" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" msgstr "" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." +#: py/argcheck.c shared-bindings/wifi/Radio.c +msgid "'%q' argument required" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c +msgid "argument num/types mismatch" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" +#: py/argcheck.c +msgid "%q must be %d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" +#: py/argcheck.c +msgid "%q must be >= %d" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample." +#: py/argcheck.c +msgid "%q length must be %d-%d" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" +#: py/argcheck.c +msgid "%q length must be >= %d" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" +#: py/argcheck.c +msgid "%q length must be <= %d" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many displays" +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" +#: py/argcheck.c shared-module/audiofilters/__init__.c +msgid "%q in %q must be of type %q, not %q" msgstr "" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: main.c -msgid "UID:" -msgstr "UID:" - -#: shared-module/usb_hid/Device.c -msgid "USB busy" +#: py/binary.c +msgid "integer out of range" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" +#: py/builtinhelp.c +msgid "object " msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" +#: py/builtinhelp.c +msgid " is of type %q\n" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +#: py/builtinhelp.c +#, c-format +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Unable to allocate buffers for signed conversion" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -msgid "Unable to create lock" +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: py/parse.c -msgid "Unable to init parser" +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" +#: py/compile.c +msgid "invalid arch" msgstr "" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." +#: py/compile.c +msgid "can't delete expression" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" +#: py/compile.c +msgid "'break'/'continue' outside loop" msgstr "" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." +#: py/compile.c +msgid "'return' outside function" msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" +#: py/compile.c +msgid "*x must be assignment target" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" +#: py/compile.c +msgid "* arg after **" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" +#: py/compile.c +msgid "* arg after kwarg" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +#: py/compile.c +msgid "too many args" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: py/compile.c +msgid "LHS of keyword arg must be an id" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: py/compile.c +msgid "'yield' outside function" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: py/compile.c +msgid "'yield from' inside async function" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" +#: py/compile.c +msgid "'await' outside function" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: py/compile.c +msgid "argument name reused" msgstr "" -#: py/builtinhelp.c -#, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" +#: py/compile.c +msgid "inline assembler must be a function" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " +#: py/compile.c +msgid "unknown type" +msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: main.c -msgid "Woken up by alarm.\n" +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: py/compile.c +msgid "'label' requires 1 argument" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." +#: py/compile.c +msgid "label redefined" msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." +#: py/compile.c +msgid "'align' requires 1 argument" msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." +#: py/compile.c +msgid "'data' requires at least 2 arguments" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: py/compile.c +msgid "'data' requires integer arguments" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: py/emitbc.c +msgid "bytecode overflow" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" +#: py/emitinlinerv32.c +msgid "opcode '%q': registers must be different" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/emitinlinerv32.c +msgid "opcode '%q': malformed register list" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/emitinlinerv32.c +msgid "opcode '%q': invalid stack adjustment" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: wrong register(s)" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" -#: py/compile.c -msgid "annotation must be an identifier" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" msgstr "" -#: py/compile.c -msgid "argument name reused" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" msgstr "" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" +#: py/emitinlinethumb.c +msgid "branch not in range" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: py/compile.c -msgid "async for/with outside async function" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/emitnative.c +msgid "conversion to object" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/emitnative.c +msgid "local '%q' used before type known" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" +#: py/emitnative.c +msgid "can't load from '%q'" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" +#: py/emitnative.c +msgid "can't load with '%q' index" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/emitnative.c +msgid "can't store to '%q'" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/emitnative.c +msgid "can't store with '%q' index" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" #: py/emitnative.c -msgid "binary op %q not implemented" +msgid "'not' not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." +#: py/emitnative.c +msgid "can't do unary op of '%q'" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/emitnative.c +msgid "div/mod not implemented for uint" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/emitnative.c +msgid "comparison of int and uint" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" +#: py/emitnative.c +msgid "casting" msgstr "" -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/emitnative.c +msgid "native raise" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/emitnative.c +msgid "must raise an object" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/modbuiltins.c py/objstr.c +msgid "char not in range(0x110000)" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: py/emitbc.c -msgid "bytecode overflow" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: py/objarray.c -msgid "bytes length not a multiple of item size" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: py/objstr.c -msgid "bytes value out of range" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/moderrno.c +msgid "Operation not permitted" msgstr "" -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +#: py/moderrno.c +msgid "No such file/directory" msgstr "" -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +#: py/moderrno.c +msgid "Input/output error" msgstr "" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" +#: py/moderrno.c +msgid "Permission denied" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" +#: py/moderrno.c +msgid "File exists" msgstr "" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" +#: py/moderrno.c +msgid "No such device" msgstr "" -#: py/compile.c -msgid "can't assign to expression" +#: py/moderrno.c +msgid "No space left on device" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to complex" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to float" +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: py/objint.c py/runtime.c +#: py/modstruct.c #, c-format -msgid "can't convert %s to int" -msgstr "" - -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: py/obj.c -msgid "can't convert to complex" +#: py/modweakref.c +msgid "not a heap object" msgstr "" -#: py/obj.c -msgid "can't convert to float" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: py/runtime.c -msgid "can't convert to int" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +#: py/obj.c +msgid " File \"%q\", line %d" msgstr "" -#: py/emitnative.c -msgid "can't do unary op of '%q'" +#: py/obj.c +msgid " File \"%q\"" msgstr "" -#: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +#: py/obj.c +msgid ", in %q\n" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: py/emitnative.c -msgid "can't load from '%q'" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: py/emitnative.c -msgid "can't load with '%q' index" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: py/emitnative.c -msgid "can't store '%q'" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: py/emitnative.c -msgid "can't store to '%q'" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: py/emitnative.c -msgid "can't store with '%q' index" +#: py/obj.c +msgid "%q indices must be integers, not %s" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/obj.c +msgid "object has no len" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" msgstr "" -#: py/objtype.c -msgid "cannot create instance" +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: py/emitnative.c -msgid "casting" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/objcomplex.c +msgid "0.0 to a complex power" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/objdeque.c +msgid "full" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/objdeque.c +msgid "empty" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" +#: py/objdict.c +msgid "dict update sequence has wrong length" msgstr "" -#: py/objcomplex.c -msgid "complex divide by zero" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" #: py/objfloat.c py/parsenum.c msgid "complex values not supported" msgstr "" -#: extmod/modzlib.c -msgid "compression header" -msgstr "" - -#: py/emitnative.c -msgid "conversion to object" -msgstr "" - -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/objint.c +msgid "float too big" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/objint_impl.h #, c-format -msgid "data pin #%d in use" +msgid "value would overflow a %d byte buffer" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" +#: py/objint_impl.h +msgid "can't convert negative int to unsigned" msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: py/objdict.c -msgid "dict update sequence has wrong length" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" msgstr "" -#: py/emitnative.c -msgid "div/mod not implemented for uint" +#: py/objslice.c +msgid "Cannot subclass slice" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "divide by zero" +#: py/objstr.c +msgid "unknown encoding: %q" msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/objstr.c +msgid "bytes value out of range" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/objstr.c +msgid "empty separator" msgstr "" -#: py/objdeque.c -msgid "empty" +#: py/objstr.c +msgid "rsplit(None,n)" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" msgstr "" #: py/objstr.c -msgid "empty separator" +msgid "bad conversion specifier" msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" #: py/objstr.c -msgid "end of format while looking for conversion specifier" +#, c-format +msgid "unknown conversion specifier %c" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/objstr.c +msgid "expected ':' after format specifier" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objstr.c +msgid "%q index out of range" msgstr "" #: py/objstr.c -msgid "expected ':' after format specifier" +msgid "attributes not supported" msgstr "" -#: py/obj.c -msgid "expected tuple/list" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" -#: py/modthread.c -msgid "expecting a dict for keyword args" +#: py/objstr.c +msgid "invalid format specifier" msgstr "" -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objstr.c +msgid "incomplete format key" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objstr.c +msgid "incomplete format" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objtemplate.c +msgid "expected str or Interpolation" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." msgstr "" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: extmod/moddeflate.c -msgid "format" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: py/objstr.c -msgid "format needs a dict" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: py/objstr.c -msgid "format string didn't convert all arguments" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: py/objstr.c -msgid "format string needs more arguments" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objdeque.c -msgid "full" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" msgstr "" -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" +#: py/parse.c +msgid "not a constant" +msgstr "" + +#: py/parse.c +msgid "Unable to init parser" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" +#: py/parsenum.c +msgid "invalid syntax for integer" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/parsenum.c +msgid "invalid syntax for number" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" #: py/persistentcode.c @@ -3334,1225 +3489,1245 @@ msgid "incompatible .mpy arch" msgstr "" #: py/persistentcode.c -msgid "incompatible .mpy file" -msgstr "" - -#: py/objstr.c -msgid "incomplete format" +msgid "function must be bytecode" msgstr "" -#: py/objstr.c -msgid "incomplete format key" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/qstr.c +msgid "name too long" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/runtime.c +msgid "'%q' object isn't iterable" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" +#: py/runtime.c +msgid "'%q' object isn't an iterator" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/runtime.c +msgid "can't convert to int" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/vm.c +msgid "local variable referenced before assignment" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/vm.c +msgid "opcode" msgstr "" #: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" +msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" msgstr "" -#: shared-bindings/bitmaptools/__init__.c +#: shared-bindings/_bleio/Adapter.c #, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgid "interval must be in range %s-%s" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for integer" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" +#: shared-bindings/_bleio/__init__.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: py/compile.c -msgid "label redefined" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" msgstr "" -#: py/vm.c -msgid "local variable referenced before assignment" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: py/parse.c -msgid "malformed f-string" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" msgstr "" -#: py/runtime.c -msgid "maximum recursion depth exceeded" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." msgstr "" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c +#: shared-bindings/audiodelays/GranularPitchShift.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: py/builtinimport.c -msgid "module not found" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: py/compile.c -msgid "multiple *x in assignment" +#: shared-bindings/audioio/AudioOut.c shared-bindings/emmcio/EMMC.c +msgid "%q and %q must be different" msgstr "" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: py/objtype.c -msgid "multiple inheritance not supported" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/emitnative.c -msgid "must raise an object" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" msgstr "" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" -#: py/qstr.c -msgid "name too long" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: py/asmthumb.c -msgid "native method too big" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/modmath.c -msgid "negative factorial" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" msgstr "" -#: py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: py/builtinimport.c -msgid "no module named '%q'" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" msgstr "" - -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." msgstr "" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: py/builtinhelp.c -msgid "object " +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" -#: py/obj.c -msgid "object doesn't support item assignment" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: py/obj.c -msgid "object with buffer protocol required" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" #: shared-bindings/dualbank/__init__.c msgid "offset must be >= 0" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/emmcio/EMMC.c shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: py/vm.c -msgid "opcode" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: py/modstruct.c +#: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "pack expected %d items for packing (got %d)" -msgstr "" - -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" msgstr "" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" msgstr "" -#: py/compile.c -msgid "positional arg after **" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" msgstr "" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" msgstr "" -#: py/objstr.c -msgid "rsplit(None,n)" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" +#: shared-bindings/wifi/Radio.c +msgid "Supply either %q or %q, not both" msgstr "" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" msgstr "" -#: py/nativeglue.c -msgid "set unsupported" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "short read" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" msgstr "" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" msgstr "" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" msgstr "" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" msgstr "" -#: main.c -msgid "soft reboot\n" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: py/objstrunicode.c -#, c-format -msgid "string indices must be integers, not %s" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: py/compile.c -msgid "too many args" +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: py/runtime.c -#, c-format -msgid "too many values to unpack (expected %d)" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Internal error #%d" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" msgstr "" -#: py/parse.c -msgid "unexpected indent" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" msgstr "" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" msgstr "" -#: py/compile.c -msgid "unknown type" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" msgstr "" -#: py/compile.c -msgid "unknown type '%q'" +#: shared-module/usb/core/Device.c +msgid "Pipe error" msgstr "" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" +#: shared-module/usb/core/Device.c +msgid "No configuration set" msgstr "" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" msgstr "" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: extmod/moddeflate.c -msgid "wbits" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." msgstr "" -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" -#: py/runtime.c -msgid "wrong number of values to unpack" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" -msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 35bfed4de08..0dffaaac216 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -17,1122 +17,963 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -"\n" -"코드 실행 완료.\n" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -"\n" -"자동 업로드에 의해 코드가 중지되었습니다. 곧 다시 로드됩니다.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -"\n" -"github.com/adafruit/circuitpython/issues 에\n" -"프로그램 오류를 제출하세요." -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -"\n" -"재설정을 눌러 안전 모드를 종료합니다.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -"\n" -"안전 모드에 있는 이유는 다음과 같습니다:\n" -#: py/obj.c -msgid " File \"%q\"" -msgstr " 파일 \"%q\"" +#: extmod/moddeflate.c +msgid "format" +msgstr "" -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " 파일 \"%q\", 라인 %d" +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " %q 유형입니다\n" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "" -#: main.c -msgid " not found.\n" -msgstr " 찾을 수 없습니다.\n" +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "" -#: main.c -msgid " output:\n" -msgstr " 산출:\n" +#: extmod/modjson.c +msgid "syntax error in JSON" +msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modrandom.c +msgid "bits must be 32 or less" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" msgstr "" -"%d 주소 핀들, %d rgb 핀들과 %d 타일 들은 높이가 %d임을 나타낸다, %d가 아니라" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q 및 %q에 중복된 핀이 포함" +#: extmod/modre.c +msgid "splitting with sub-captures" +msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q와 %q는 달라야 합니다" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modre.c +msgid "Error in regex" +msgstr "Regex에 오류가 있습니다." + +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q에 중복된 핀이 포함" +#: extmod/modzlib.c +msgid "compression header" +msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -msgid "%q failure: %d" -msgstr "%q 실패: %d" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" +msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "%q의 %q는 %q가 아니라 %q 유형이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q 사용 중입니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "" -#: py/objstr.c -msgid "%q index out of range" -msgstr "%q 인덱스 범위를 벗어났습니다" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "%q 인덱스는 %s 가 아닌 정수 여야합니다" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c -msgid "%q init failed" -msgstr "%q 초기화 실패" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q는 %q입니다" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "%q는 이 보드에 대한 읽기 전용입니다" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "%q 길이는 %d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "%q 길이는 %d - %d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "%q 길이는 <= %d>여야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "%q 길이는 >= %d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "" -#: py/runtime.c -#, fuzzy -msgid "%q moved from %q to %q" -msgstr "%q가 %q에서 %q로 이동했습니다" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q는 %d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q는 %d-%d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q가 참일 때 %q는 1이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" +msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -#, fuzzy -msgid "%q must be <= %d" -msgstr "%q 는 <= %d 여야 합니다" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -#, fuzzy -msgid "%q must be <= %u" -msgstr "%q 는 <= %u 여야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "" -#: py/argcheck.c -#, fuzzy -msgid "%q must be >= %d" -msgstr "%q 는 >= %d 여야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q는 'H' 또는 'B' 타입의 바이트 배열 또는 배열이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q는 h, H, b 또는 B 유형의 바이트 배열 또는 배열이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" -msgstr "%q는 %q의 하위 클래스여야 합니다" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" +msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -#, fuzzy -msgid "%q must be array of type 'H'" -msgstr "%q는 'H' 유형의 배열이어야 합니다" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" +msgstr "" -#: shared-module/synthio/__init__.c -#, fuzzy -msgid "%q must be array of type 'h'" -msgstr "%q는 'h' 유형의 배열이어야 합니다" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "%q는 %q가 아닌 %q 또는 %q 유형이어야 합니다" +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" +msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q는 %q가 아니라 %q 유형이어야 합니다" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" +msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q는 2의 거듭제곱이어야 합니다" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "" -#: shared-bindings/wifi/Monitor.c -#, fuzzy -msgid "%q out of bounds" -msgstr "%q가 경계를 벗어남" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c -#, fuzzy -msgid "%q out of range" -msgstr "%q가 범위를 벗어남" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "%q가 %q로 이름이 변경되었습니다" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" +msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -#, fuzzy -msgid "%q step cannot be zero" -msgstr "%q 단계는 0일 수 없습니다" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" msgstr "" -#: py/bc.c py/objnamedtuple.c -#, fuzzy -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q()는 %d 위치 인수를 사용하지만 %d이(가) 주어졌습니다" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q 및 %q의 길이는 모두 같아야 합니다" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" +msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "%q[%u] shifts in more bits than pin count" -msgstr "%q[%u]가 핀 수보다 더 많은 비트로 이동했습니다" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "%q[%u] shifts out more bits than pin count" -msgstr "%q[%u]이(가) 핀 수보다 많은 비트를 전송합니다" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "%q[%u]에서 추가 핀 사용" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" -msgstr "%q[%u]이(가) 카운트 외부의 입력을 대기합니다" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, fuzzy, c-format -msgid "%s error 0x%x" -msgstr "%s 오류 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "'%q' 인수가 필요합니다" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "" -#: py/proto.c -msgid "'%q' object does not support '%q'" -msgstr "'%q' 개체가 '%q'를 지원하지 않습니다" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "'%q' 개체가 iterator가 아닙니다" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "'%q' 개체를 사용할 수 없습니다" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "FFT는 ndarrays에 대해서만 정의됩니다" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' 에는 라벨이 필요합니다" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "FFT는 선형 배열에 대해서만 구현됩니다" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' 에는 레지스터가 필요합니다" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' 에는 특별한 레지스터가 필요합니다" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' 에는 FPU레지스터가 필요합니다" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" -#: py/emitinlinethumb.c -#, fuzzy, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s' 에는 [a, b] 형식의 주소가 필요합니다" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' 는 정수 여야합니다" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" -#: py/emitinlinethumb.c -#, fuzzy, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s'는 최대 r%d를 필요로 합니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' {r0, r1, ...}은 을 기대합니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "" -#: py/emitinlinextensa.c -#, fuzzy, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' 정수 %d가 %d..%d 범위 내에 있지 않습니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "" -#: py/emitinlinethumb.c -#, fuzzy, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' 정수 0x%x 이 마스크 0x%x에 맞지 않습니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "" -#: py/obj.c -#, fuzzy, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "'%s' 개체가 항목 할당을 지원하지 않습니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" -#: py/obj.c -#, fuzzy, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "'%s' 개체가 항목 삭제를 지원하지 않습니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "" -#: py/runtime.c -#, fuzzy -msgid "'%s' object has no attribute '%q'" -msgstr "'%s' 개체에 '%q' 특성이 없습니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "'%s' 개체를 subscriptable 할 수 없습니다" - -#: py/objstr.c -#, fuzzy -msgid "'=' alignment not allowed in string format specifier" -msgstr "'=' 문자열 형식 지정자에서 정렬이 허용되지 않습니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' 및 'O'는 지원되지 않는 형식 유형입니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "'align' 에는 1 개의 독립변수가 필요합니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "" -#: py/compile.c -msgid "'await' outside function" -msgstr "'await' 는 펑크션 외부에 있습니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "" -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "'break'/'continue' 외부 루프" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "" -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "'data' 에는 >=2 개의 독립변수가 필요합니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "" -#: py/compile.c -#, fuzzy -msgid "'data' requires integer arguments" -msgstr "'data' 에는 정수 인수가 필요합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "'label' 에는 1 개의 독립변수가 필요합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" +msgstr "" -#: py/emitnative.c -msgid "'not' not implemented" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" msgstr "" -#: py/compile.c -msgid "'return' outside function" -msgstr "'return' 는 함수 외부에 존재합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "" -#: py/compile.c -#, fuzzy -msgid "'yield from' inside async function" -msgstr "비동기 함수 내 'yield from'" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "" -#: py/compile.c -msgid "'yield' outside function" -msgstr "'yield' 는 함수 외부에 존재합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "" -#: py/compile.c -#, fuzzy -msgid "* arg after **" -msgstr "* 인수 뒤에 **" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" -#: py/compile.c -#, fuzzy -msgid "*x must be assignment target" -msgstr "*x는 할당 대상이어야 합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "" -#: py/obj.c -msgid ", in %q\n" -msgstr ", 에서 %q\n" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#, fuzzy -msgid ".show(x) removed. Use .root_group = x" -msgstr ".show(x)가 제거되었습니다. .root_group = x를 사용합니다" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "" -#: py/objcomplex.c -msgid "0.0 to a complex power" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" msgstr "" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "pow() 는 3개의 인수를 지원하지 않습니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "AP를 시작할 수 없습니다" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "주소 길이는 %d 바이트 여야합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" +msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "주소 범위가 허용되지 않습니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, fuzzy -msgid "All CAN peripherals are in use" -msgstr "모든 CAN 주변 기기가 사용 중입니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "사용 중인 모든 I2C주변 기기" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -#, fuzzy -msgid "All RX FIFOs in use" -msgstr "모든 RX FIFOs가 사용 중입니다" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "사용중인 모든 SPI주변 기기" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "사용중인 모든 UART주변 기기" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "모든 채널이 사용중입니다" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" +msgstr "" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "모든 dma채널이 사용 중입니다" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#, fuzzy -msgid "All event channels in use" -msgstr "모든 이벤트 채널이 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#, fuzzy -msgid "All state machines in use" -msgstr "모든 상태 머신이 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "" -#: ports/atmel-samd/audio_dma.c -#, fuzzy -msgid "All sync event channels in use" -msgstr "모든 동기화 이벤트 채널이 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" +msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "핀의 모든 타이머가 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "모든 타이머가 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, fuzzy -msgid "Already advertising." -msgstr "이미 광고 중입니다." +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#, fuzzy -msgid "Already have all-matches listener" -msgstr "이미 모든 일치 리스너가 있습니다" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "이미 실행 중입니다" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -#, fuzzy -msgid "Already scanning for wifi networks" -msgstr "이미 wifi 네트워크를 찾고 있습니다" - -#: shared-module/os/getenv.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "%s'을(를) 검색하는 동안 오류가 발생했습니다:\n" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, fuzzy -msgid "Another PWMAudioOut is already active" -msgstr "다른 PWMaudioOut이 이미 활성화되어 있습니다" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "다른 전송이 이미 활성화되었습니다" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" +msgstr "" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "배열은 하프워드(유형 'H')가 포함되어야 합니다" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -#, fuzzy -msgid "Array values should be single bytes." -msgstr "배열 값은 1바이트 여야합니다." +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" msgstr "" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "%d 블록 할당 시도" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "오디오 변환이 구현되지 않음" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Audio source error" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "AuthMode.OPEN은 암호와 함께 사용되지 않습니다" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" +msgstr "" -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "인증 실패" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" +msgstr "" -#: main.c -msgid "Auto-reload is off.\n" -msgstr "자동 재 장전이 꺼져 있습니다\n" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" msgstr "" -"자동 새로 고침이 켜져 있습니다. USB를 통해 파일을 저장하여 실행하십시오. 비활" -"성화하려면 REPL을 입력하십시오.\n" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "주변 기기에서 전송 속도가 지원되지 않습니다" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "" -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "최소 프레임 속도 미만" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" +msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "비트 클럭 및 워드 선택은 순차적 GPIO 핀이어야 합니다" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "비트맵 크기와 값 당 비트가 일치해야 합니다" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "부팅 장치는 첫 번째(인터페이스 #0)여야 합니다." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "플로우 제어에 RX와 TX가 모두 필요합니다" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "밝기를 조절할 수 없습니다" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Buffer + offset이 너무 작습니다 %d %d %d" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "버퍼 요소는 4바이트 이하여야 합니다" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "버퍼는 바이트 배열이 아닙니다." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "버퍼 길이 %d가 너무 큽니다. 그것은 %d보다 작아야 합니다" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "버퍼가 %d 바이트로 너무 짧습니다" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "버퍼가 너무 작습니다" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Bus 핀 %d은 이미 사용 중입니다" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" +msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "잘못된 크기의 버퍼. 16 바이트 여야합니다." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "CBC 블록은 16 바이트의 배수여야 합니다" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "CIRCUITPY 드라이브를 찾거나 만들 수 없습니다." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC 또는 checksum이 잘못되었습니다" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "네이티브 개체에 액세스하기 전에 super().__init__()를 호출하십시오." +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#, fuzzy -msgid "Camera init" -msgstr "카메라 초기화" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "로컬 특성에 CCCD를 설정할 수 없습니다" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" +msgstr "읽기 전용 파일 시스템" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "현재 USB 디바이스를 변경할 수 없습니다" +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "닫힌 파일에서 I/O 작업" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "_bleio.adapter를 사용해서; 새로운 Adapter를 만들 수 없습니다;" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" +msgstr "" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "값을 삭제할 수 없습니다" +#: main.c +msgid "Done" +msgstr "완료" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "출력 모드에서는 끌어올 수 없습니다" +#: main.c +msgid " output:\n" +msgstr " 산출:\n" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "온도 데이터를 수신 할 수 없습니다" +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" +msgstr "" +"자동 새로 고침이 켜져 있습니다. USB를 통해 파일을 저장하여 실행하십시오. 비활" +"성화하려면 REPL을 입력하십시오.\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." -msgstr "확장되고 연결 가능한 광고에 대한 검색 응답을 가질 수 없습니다." +#: main.c +msgid "Auto-reload is off.\n" +msgstr "자동 재 장전이 꺼져 있습니다\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "입력 전용 핀을 끌어올 수 없습니다." +#: main.c +msgid "Running in safe mode! Not running saved code.\n" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Cannot record to a file" -msgstr "파일에 녹음 할 수 없습니다" +#: main.c +msgid " not found.\n" +msgstr " 찾을 수 없습니다.\n" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Cannot set value when direction is input." -msgstr "방향이 입력되면 값을 설정할 수 없습니다." - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "RS485 모드에서는 RTS 또는 CTS를 지정할 수 없습니다" +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" +msgstr "" +"\n" +"자동 업로드에 의해 코드가 중지되었습니다. 곧 다시 로드됩니다.\n" -#: py/objslice.c -msgid "Cannot subclass slice" +#: main.c +msgid "" +"\n" +"Code done running.\n" msgstr "" +"\n" +"코드 실행 완료.\n" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: main.c +msgid "Woken up by alarm.\n" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -#, fuzzy -msgid "Cannot wake on pin edge, only level" -msgstr "핀의 에지에서 깨울 수 없고, 레벨에서만 깨울 수 있습니다" +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +msgstr "아무 키나 눌러 REPL을 입력한다. 다시 로드할땐 CTRL-D를 사용한다.\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -#, fuzzy -msgid "Cannot wake on pin edge. Only level." -msgstr "핀의 에지에서는 깨울 수 없습니다. 레벨에서만 깨울 수 있습니다." +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +msgstr "알람, CTRL-C 또는 파일을 작성하기 전까지 딥 슬립을 하는 척합니다\n" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "CharacteristicBuffer 쓰기는 제공되지 않습니다" +#: main.c +msgid "UID:" +msgstr "UID:" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "CircuitPython 핵심 코드가 심하게 충돌했습니다. 앗!\n" +#: main.c +msgid "soft reboot\n" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "시계 장치가 사용 중입니다" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c +msgid "%q init failed" +msgstr "%q 초기화 실패" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." -msgstr "연결이 끊어져 더 이상 사용할 수 없습니다. 새로운 연결을 만드십시오." +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" -msgstr "좌표 배열의 길이가 다릅니다" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +#, fuzzy +msgid "%q out of range" +msgstr "%q가 범위를 벗어남" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" -msgstr "좌표 배열 유형은 크기가 다릅니다" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" +msgstr "잘못된 상태" -#: shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "주소를 설정할 수 없습니다" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "플로우 제어에 RX와 TX가 모두 필요합니다" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "인터럽트를 시작할 수 없습니다, RX가 사용 중입니다" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "%q 버퍼 할당에 실패했습니다" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "디코더를 할당할 수 없습니다" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" -msgstr "DAC 채널 초기화 오류" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "사용중인 모든 UART주변 기기" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Device Init Error" -msgstr "DAC 장치 초기화 오류" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "잘못된 %q" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC가 현재 사용 중입니다" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "데이터 0 핀은 바이트 정렬되어야 합니다" +#: ports/atmel-samd/audio_dma.c +#, fuzzy +msgid "All sync event channels in use" +msgstr "모든 동기화 이벤트 채널이 사용 중입니다" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" -msgstr "데이터 형식 오류(손상된 데이터일 수 있습니다)" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "내부 오디오 버퍼가 너무 작습니다" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "직접 광고에서는 데이터가 지원되지 않습니다" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "광고 (브로드 캐스트) 패킷에 대한 데이터가 너무 큽니다" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" +msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#, fuzzy -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "딥 슬립 핀은 풀다운이 있는 상승 에지를 사용해야 합니다" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "대상 용량이 destination_length보다 작습니다." - -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" -msgstr "장치 오류 또는 입력 스트림의 잘못된 종료" - -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "사용 중인 장치" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "디스플레이는 16 비트 색 공간을 가져야 합니다." - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display rotation must be in 90 degree increments" -msgstr "디스플레이 회전은 90도씩 증가해야 합니다" - -#: main.c -msgid "Done" -msgstr "완료" - -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Drive mode not used when direction is input." -msgstr "방향을 입력할 때 드라이브 모드는 사용되지 않습니다." - -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "위 예외를 처리하는 동안, 또 다른 예외가 발생하였습니다:" - -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB는 한 번에 16 바이트에서만 작동합니다" - -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -msgid "ESP-IDF memory allocation failed" -msgstr "ESP-IDF 메모리 할당에 실패하였습니다" +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "모든 타이머가 사용 중입니다" -#: extmod/modre.c -msgid "Error in regex" -msgstr "Regex에 오류가 있습니다." +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" +msgstr "" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c #: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "safemode.py에 오류가 있습니다." - -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" -msgstr "%q 유형이 필요합니다" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, fuzzy -msgid "Extended advertisements with scan response not supported." -msgstr "검색 응답이 있는 확장 광고는 지원되지 않습니다." - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "FFT는 ndarrays에 대해서만 정의됩니다" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "FFT는 선형 배열에 대해서만 구현됩니다" - -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "명령을 보내는 것에 실패했습니다." - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "뮤텍스 획득에 실패했습니다, 오류 0x%04x" - -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" -msgstr "서비스 TXT 레코드를 추가하는 것에 실패했습니다" - -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" +msgid "Unknown reason." msgstr "" -"서비스 TXT 레코드를 추가하는 것에 실패했습니다; txt_records에서 비문자열 또" -"는 바이트가 발견되었습니다" - -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" -msgstr "%q 버퍼 할당에 실패했습니다" - -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" -msgstr "Wifi 메모리 할당에 실패했습니다" - -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" -msgstr "wifi 검색 메모리 할당에 실패했습니다" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" -msgstr "샘플 버퍼링에 실패했습니다" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "연결에 실패했습니다: 내부 오류" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" +msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "연결에 실패했습니다: 시간 초과" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" +msgstr "칩에 DAC가 없습니다" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" -msgstr "" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "시계 장치가 사용 중입니다" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" -msgstr "" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" +msgstr "무료 GCLKs가 없습니다" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "MP3 파일 분석에 실패했습니다" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" +msgstr "DMA 채널을 찾을 수 없습니다" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: ports/nordic/sd_mutex.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c #, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "뮤텍스 해제에 실패했습니다, 오류 0x%04x" +msgid "Only 8 or 16 bit mono with %dx oversampling supported." +msgstr "%dx 오버샘플링이 포함된 8 또는 16 비트 모노만 지원됩니다." -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC가 현재 사용 중입니다" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" msgstr "" -#: supervisor/shared/safe_mode.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c #, fuzzy -msgid "Failed to write internal flash." -msgstr "내부 플래시를 쓰는 것에 실패했습니다." +msgid "All event channels in use" +msgstr "모든 이벤트 채널이 사용 중입니다" -#: py/moderrno.c -msgid "File exists" -msgstr "파일이 있습니다" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "SDA 또는 SCL에서 풀업을 찾을 수 없습니다; 케이블 연결을 확인하십시오" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c -msgid "File not found" -msgstr "파일을 찾을 수 없습니다" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q는 2의 거듭제곱이어야 합니다" + +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "%q 핀이 없습니다" + +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +#, fuzzy +msgid "All RX FIFOs in use" +msgstr "모든 RX FIFOs가 사용 중입니다" + +#: ports/atmel-samd/common-hal/canio/Listener.c +#, fuzzy +msgid "Already have all-matches listener" +msgstr "이미 모든 일치 리스너가 있습니다" #: ports/atmel-samd/common-hal/canio/Listener.c #: ports/espressif/common-hal/canio/Listener.c @@ -1141,636 +982,575 @@ msgstr "파일을 찾을 수 없습니다" msgid "Filters too complex" msgstr "필터가 너무 복잡합니다" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "펌웨어가 중복되었습니다" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "펌웨어가 잘못되었습니다" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "펌웨어가 너무 큽니다" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "L8 색상 공간의 경우, 입력 비트맵은 픽셀 당 8 비트를 가져야 합니다" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "RGB 색상 공간의 경우, 입력 비트맵은 픽셀 당 16 비트를 가져야 합니다" +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "출력 모드에서는 끌어올 수 없습니다" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "지원되지 않는 형식입니다" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" +msgstr "잘못된 data_pins[%d]" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" msgstr "" -"주파수는 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 또는 1008 Mhz 여야 " -"합니다" - -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "이 함수에는 잠금이 필요합니다" - -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "GNSS 초기화" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" -msgstr "일반 오류" -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "이미 사용된 그룹" - -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "치명적인 실수: 메모리 액세스 또는 명령 오류." - -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "하드웨어가 사용 중입니다, 대체 핀을 사용해보십시오" - -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." -msgstr "VM이 작동하지 않을 때 힙이 할당됩니다." - -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "닫힌 파일에서 I/O 작업" - -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "I2C 초기화 오류" - -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "I2C 주변 기기가 사용 중입니다" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "버퍼 내 요소 길이는 <= 4여야 합니다" - -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "잘못된 버퍼 크기" +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" +msgstr "잘못된 %q 핀" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "초기화 프로그램의 크기가 잘못되었습니다" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "초기 설정한 핀의 방향이 초기 바깥쪽 핀의 방향과 충돌합니다" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "데이터 0 핀은 바이트 정렬되어야 합니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" -msgstr "초기 설정한 핀의 상태가 초기 바깥쪽 핀의 상태와 충돌합니다" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "Bus 핀 %d은 이미 사용 중입니다" -#: shared-bindings/bitops/__init__.c -#, fuzzy, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "입력 버퍼 길이 (%d) 는 스트랜드 수 (%d)의 배수여야 한다" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" +msgstr "" #: ports/atmel-samd/common-hal/pulseio/PulseIn.c msgid "Input taking too long" msgstr "입력이 너무 오래 걸린다" -#: py/moderrno.c -msgid "Input/output error" -msgstr "입력/출력 오류" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" -msgstr "불충분한 인증" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" -msgstr "불충분한 암호화" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" -msgstr "이미지에 대한 메모리 풀이 부족합니다" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" -msgstr "불충분한 스트림 입력 버퍼" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "인터페이스를 시작해야 합니다" - -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "내부 오디오 버퍼가 너무 작습니다" - -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" -msgstr "내부 정의 오류" +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "다른 전송이 이미 활성화되었습니다" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c -msgid "Internal error" -msgstr "내부 오류" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/socketpool/SocketPool.c +msgid "%q failure: %d" +msgstr "%q 실패: %d" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/audiocore/WaveFile.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/floppyio/__init__.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format -msgid "Internal error #%d" -msgstr "내부 오류 #%d" - -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" +msgid "Buffer must be a multiple of %d bytes" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "내부 감시 타이머가 만료되었습니다." - -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "인터럽트 오류." - -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" -msgstr "출력 함수로 인해 종료되었다" - -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" -msgstr "잘못된 %q" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." +msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "잘못된 %q 핀" +#: ports/cxd56/common-hal/camera/Camera.c +#, fuzzy +msgid "Camera init" +msgstr "카메라 초기화" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "잘못된 ADC 단위 값" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "잘못된 BLE 파라미터" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "버퍼가 너무 작습니다" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "잘못된 BSSID" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "지원되지 않는 형식입니다" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "잘못된 MAC 주소" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" +msgstr "GNSS 초기화" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "잘못된 인수" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "이미 실행 중입니다" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" -msgstr "값 당 잘못된 비트" +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q는 %q입니다" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "잘못된 바이트 %.*s" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" -msgstr "잘못된 data_pins[%d]" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "" -#: shared-module/msgpack/__init__.c -msgid "Invalid format" -msgstr "잘못된 형식" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." +msgstr "" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "형식 청크 크기가 잘못되었습니다" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" -msgstr "잘못된 16진수 패스워드" +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "잘못된 멀티캐스트 MAC 주소" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "잘못된 크기" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." +msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "TLS에 대한 잘못된 소켓" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" -msgstr "잘못된 상태" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" +msgstr "" -#: shared-module/os/getenv.c -msgid "Invalid unicode escape" -msgstr "잘못된 유니코드 이스케이프" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "키는 16, 24, 또는 32 바이트 길이여야 합니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "연결에 실패했습니다: 내부 오류" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "키를 찾을 수 없습니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "광고 (브로드 캐스트) 패킷에 대한 데이터가 너무 큽니다" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "LED 매핑은 디스플레이 크기와 일치해야 합니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, fuzzy +msgid "Already advertising." +msgstr "이미 광고 중입니다." -#: py/compile.c -msgid "LHS of keyword arg must be an id" -msgstr "키워드 인수의 LHS 는 id 여야 합니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, fuzzy +msgid "Extended advertisements with scan response not supported." +msgstr "검색 응답이 있는 확장 광고는 지원되지 않습니다." -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "레이어가 이미 그룹에 있습니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "직접 광고에서는 데이터가 지원되지 않습니다" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "레이어는 그룹 또는 TileGrid 하위 클래스 여야 합니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "MAC 주소는 잘못되었습니다" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" #: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +#: ports/espressif/common-hal/_bleio/Service.c +msgid "Too many %q" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" +msgstr "이 특성에 대한 CCCD가 없습니다" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "로컬 특성에 CCCD를 설정할 수 없습니다" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" +msgstr "연결되지 않았습니다" + +#: ports/espressif/common-hal/_bleio/Connection.c +msgid "No pairing in progress" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c #, c-format -msgid "MMC/SDIO Clock Error %x" +msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" -msgstr "매핑은 투플이어야 합니다" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" +msgstr "" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" -msgstr "일치하지 않는 데이터 크기" +#: ports/espressif/common-hal/_bleio/__init__.c +#, fuzzy +msgid "Nimble out of memory" +msgstr "빠른 메모리 부족" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" -msgstr "일치하지 않는 스왑 플래그" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" +msgstr "잘못된 BLE 파라미터" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Already in progress" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "first_in_pin이 누락되어 있습니다. %q[%u]이 pin(s)을 읽습니다" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "first_in_pin이 누락되었습니다. %q[%u]는 pin(s)에서 이동합니다" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" +msgstr "불충분한 인증" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "first_in_pin이 누락되었습니다. %q[%u]는 핀에 따라 대기 중입니다" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" +msgstr "불충분한 암호화" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "first_out_pin이 누락되었습니다. %q[%u]는 pin(s)으로 이동합니다" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "first_out_pin이 누락되었습니다. %q[%u]는 pin(s)에 씁니다" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c #, fuzzy -msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "first_set_pin이 누락되었습니다. %q[%u]는 pin(s)을 설정합니다" +msgid "Cannot wake on pin edge. Only level." +msgstr "핀의 에지에서는 깨울 수 없습니다. 레벨에서만 깨울 수 있습니다." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "jmp_pin이 누락되었습니다. %q[%u] 핀으로 점프합니다" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "입력 전용 핀을 끌어올 수 없습니다." -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." -msgstr "%q의 하위클래스여야 합니다." - -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" -msgstr "5/6/5 RGB 핀을 제공해야 합니다" - -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" -msgstr "MISO 또는 MOSI 핀을 제공해야 합니다" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." +msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" -msgstr "%d이 아닌, 6 rgb 핀을 여러 개 사용해야 합니다" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." -msgstr "NLR 는 점프에 실패했습니다. 아마도 메모리 손상일 것입니다." +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." +msgstr "" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" -msgstr "NVS 오류" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." +msgstr "딥 슬립에서는 하나의 %q만 설정할 수 있습니다." -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" -msgstr "이름 또는 서비스를 알 수 없습니다" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +#, fuzzy +msgid "%q must be array of type 'H'" +msgstr "%q는 'H' 유형의 배열이어야 합니다" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" -msgstr "새로운 비트맵은 원본 비트맵과 크기가 같아야 합니다" +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c shared-bindings/emmcio/EMMC.c #, fuzzy -msgid "Nimble out of memory" -msgstr "빠른 메모리 부족" +msgid "Peripheral in use" +msgstr "주변 기기가 사용 중입니다" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "%q 핀이 없습니다" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "이 특성에 대한 CCCD가 없습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" +msgstr "" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "No DAC on chip" -msgstr "칩에 DAC가 없습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA channel found" -msgstr "DMA 채널을 찾을 수 없습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" +msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" -msgstr "DMA 간격 타이머를 찾을 수 없습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" +msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" -msgstr "주소에 I2C 장치가 없습니다: 0x%x" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" +msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "IP가 없습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" +msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" msgstr "" -#: shared-module/usb/core/Device.c -#, fuzzy -msgid "No configuration set" -msgstr "구성이 설정되어 있지 않습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" +msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" -msgstr "연결이 없습니다: 길이를 결정할 수 없습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" -msgstr "기본 버스 %q가 없습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" -msgstr "무료 GCLKs가 없습니다" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "사용 중인 모든 I2C주변 기기" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" -msgstr "임의의 하드웨어를 사용할 수 없습니다" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "No in in program" -msgstr "프로그램에 입력이 없습니다" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "No in or out in program" -msgstr "프로그램에 입력 또는 출력이 없습니다" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "사용중인 모든 SPI주변 기기" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" -msgstr "긴 정수 지원이 없습니다" +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "ESP-IDF 메모리 할당에 실패하였습니다" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "이 ssid를 사용하는 네트워크가 없습니다" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "RS485 모드에서는 RTS 또는 CTS를 지정할 수 없습니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" -msgstr "프로그램에 출력이 없습니다" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" +msgstr "RS485 모드가 아닐 때 RS485 반전이 지정됩니다" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "SDA 또는 SCL에서 풀업을 찾을 수 없습니다; 케이블 연결을 확인하십시오" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "주변 기기에서 전송 속도가 지원되지 않습니다" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" -msgstr "핀에 풀다운이 없습니다; 1Mohm를 권장합니다" +#: ports/espressif/common-hal/canio/CAN.c +#, fuzzy +msgid "All CAN peripherals are in use" +msgstr "모든 CAN 주변 기기가 사용 중입니다" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" msgstr "" -#: py/moderrno.c -msgid "No space left on device" -msgstr "장치에 남은 공간이 없습니다" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" +msgstr "" -#: py/moderrno.c -msgid "No such device" -msgstr "해당 장치가 없습니다" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" +msgstr "" -#: py/moderrno.c -msgid "No such file/directory" -msgstr "해당 파일/디렉토리가 없습니다" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" +msgstr "5/6/5 RGB 핀을 제공해야 합니다" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" -msgstr "사용 가능한 타이머가 없습니다" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" +msgstr "펌웨어가 중복되었습니다" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" -msgstr "usb 호스트 포트가 초기화되지 않았습니다" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "펌웨어가 잘못되었습니다" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" -msgstr "Nordic 시스템 펌웨어에 메모리가 부족합니다" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "펌웨어가 너무 큽니다" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" -msgstr "유효한 IP 문자열이 아닙니다" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" -msgstr "연결되지 않았습니다" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" +msgstr "" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c -msgid "Not playing" -msgstr "재생되지 않았습니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" +msgstr "일반 오류" -#: shared-module/jpegio/JpegDecoder.c +#: ports/espressif/common-hal/espidf/__init__.c #, fuzzy -msgid "Not supported JPEG standard" -msgstr "지원되지 않는 JPEG 표준" - -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#, c-format -msgid "Number of data_pins must be %d or %d, not %d" -msgstr "" +msgid "Out of memory" +msgstr "메모리 부족" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." -msgstr "" -"개체가 초기화 해제되어 더 이사 사용될 수 없습니다. 새로운 개체를 만드십시오." +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "잘못된 인수" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" -msgstr "홀수 패리티는 지원되지 않습니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "잘못된 크기" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" -msgstr "꺼짐 (연결 끊김)" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" +msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" -msgstr "켜짐 (연결됨)" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c +#: shared-bindings/picogame/__init__.c +msgid "Operation or feature not supported" +msgstr "작업 또는 기능이 지원되지 않습니다" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." -msgstr "%dx 오버샘플링이 포함된 8 또는 16 비트 모노만 지원됩니다." +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#, fuzzy +msgid "Operation timed out" +msgstr "작업 시간 초과되었습니다" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" -msgstr "IPv4 주소만 지원됩니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" +msgstr "수신된 응답이 잘못되었습니다" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" -msgstr "IPv4 소켓만 지원됩니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC 또는 checksum이 잘못되었습니다" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" -msgstr "윈도우 형식, 비압축 BMP만 지원됩니다: 지정된 헤더 크기는 %d 입니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, fuzzy -msgid "Only connectable advertisements can be directed" -msgstr "연결 가능한 광고만 지시할 수 있습니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" +msgstr "MAC 주소는 잘못되었습니다" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" -msgstr "이 하드웨어에서는 에지 감지만 가능합니다" +#: ports/espressif/common-hal/espidf/__init__.c +#, fuzzy, c-format +msgid "%s error 0x%x" +msgstr "%s 오류 0x%x" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" -msgstr "ip에는 정수 또는 문자열만 지원됩니다" +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" +msgstr "프로그램이 너무 깁니다" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." -msgstr "딥 슬립에서는 하나의 %q만 설정할 수 있습니다." +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q 사용 중입니다" #: ports/espressif/common-hal/espulp/ULPAlarm.c msgid "Only one %q can be set." @@ -1782,44 +1562,100 @@ msgstr "하나의 %q만 설정할 수 있습니다." msgid "Only one address is allowed" msgstr "오직 하나의 주소만 허용됩니다" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" msgstr "" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: shared-module/displayio/ColorConverter.c -#, fuzzy -msgid "Only one color can be transparent at a time" -msgstr "한 번에 한 가지 색상만 투명할 수 있습니다" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" +msgstr "" -#: py/moderrno.c -#, fuzzy -msgid "Operation not permitted" -msgstr "작업이 허용되지 않습니다" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" -msgstr "작업 또는 기능이 지원되지 않습니다" +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "주소 범위가 허용되지 않습니다" -#: ports/espressif/common-hal/espidf/__init__.c -#, fuzzy -msgid "Operation timed out" -msgstr "작업 시간 초과되었습니다" +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" +msgstr "NVS 오류" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" -msgstr "MDNS 서비스 슬롯 부족" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" +msgstr "" + +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "내부 오류" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, fuzzy -msgid "Out of memory" -msgstr "메모리 부족" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" +msgstr "" #: ports/espressif/common-hal/socketpool/Socket.c #: ports/raspberrypi/common-hal/socketpool/Socket.c @@ -1827,1082 +1663,1206 @@ msgstr "메모리 부족" msgid "Out of sockets" msgstr "소켓 부족" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" -msgstr "출력 버퍼 요소의 길이는 <= 4 바이트 여야 합니다" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" +msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c #, fuzzy -msgid "PWM restart" -msgstr "PWM 재시작" +msgid "%q must be <= %u" +msgstr "%q 는 <= %u 여야 합니다" -#: ports/raspberrypi/common-hal/countio/Counter.c -#, fuzzy -msgid "PWM slice already in use" -msgstr "PWM slice가 이미 사용 중입니다" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" +msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -#, fuzzy -msgid "PWM slice channel A already in use" -msgstr "PWM slice channel A가 이미 사용 중입니다" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "인터페이스를 시작해야 합니다" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "잘못된 멀티캐스트 MAC 주소" -#: shared-module/jpegio/JpegDecoder.c +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c #, fuzzy -msgid "Parameter error" -msgstr "파라미터 오류" +msgid "Already scanning for wifi networks" +msgstr "이미 wifi 네트워크를 찾고 있습니다" -#: ports/espressif/common-hal/audiobusio/__init__.c -#, fuzzy -msgid "Peripheral in use" -msgstr "주변 기기가 사용 중입니다" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" +msgstr "" -#: py/moderrno.c -msgid "Permission denied" -msgstr "권한이 거부 되었습니다" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" +msgstr "wifi 검색 메모리 할당에 실패했습니다" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" -msgstr "핀은 딥 슬립에서 깨어날 수 없습니다" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" +msgstr "Wifi 메모리 할당에 실패했습니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "Pin count too large" -msgstr "핀 수 너무 큼" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Only IPv4 addresses supported" +msgstr "IPv4 주소만 지원됩니다" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" -msgstr "핀 인터럽트는 이미 사용 중입니다" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" +msgstr "MISO 또는 MOSI 핀을 제공해야 합니다" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" -msgstr "핀은 입력 전용입니다" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +#: shared-bindings/emmcio/EMMC.c +msgid "Hardware in use, try alternative pins" +msgstr "하드웨어가 사용 중입니다, 대체 핀을 사용해보십시오" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" -msgstr "핀은 PWM 채널 B에 있어야 합니다" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" +msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" +"주파수는 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 또는 1008 Mhz 여야 " +"합니다" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" -msgstr "핀은 순차적이어야 합니다" - -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" -msgstr "핀은 순차적인 GPIO 핀이어야 합니다" - -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" -msgstr "파이프 오류" - -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "게다가 파일 시스템의 모든 모듈\n" - -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" -msgstr "다각형은 최소 3개의 점이 필요합니다" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." -msgstr "전력이 내려갔습니다. 충분한 전력을 제공할 수 있는지 확인하십시오." +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, fuzzy -msgid "Prefix buffer must be on the heap" -msgstr "앞의 버퍼는 힙에 있어야 합니다" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "연결에 실패했습니다: 시간 초과" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" -msgstr "아무 키나 눌러 REPL을 입력한다. 다시 로드할땐 CTRL-D를 사용한다.\n" +#: ports/nordic/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "Numeric comparison pairing" +msgstr "" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "알람, CTRL-C 또는 파일을 작성하기 전까지 딥 슬립을 하는 척합니다\n" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" -msgstr "프로그램이 ISR을 로드하지 않고 IN을 실행했습니다" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" +msgstr "Nordic 시스템 펌웨어에 메모리가 부족합니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" -msgstr "프로그램이 OSR을 로드하지 않고 OUT을 실행했습니다" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" +msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" -msgstr "프로그램 크기가 잘못되었습니다" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" +msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" -msgstr "프로그램이 너무 깁니다" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "" +"Unspecified issue. The pairing request on the other device may have been " +"declined or ignored." +msgstr "" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#, c-format +msgid "Unknown security error: 0x%04x" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c #, fuzzy -msgid "Pull not used when direction is output." -msgstr "방향이 출력 될 때 풀은 사용되지 않습니다" +msgid "Cannot wake on pin edge, only level" +msgstr "핀의 에지에서 깨울 수 없고, 레벨에서만 깨울 수 있습니다" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" -msgstr "이 칩에서는 RISE_AND_FALL을 사용할 수 없습니다" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "사용 중인 장치" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" -msgstr "RNG DeInit 오류" - -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" -msgstr "RNG 초기화 오류" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" +msgstr "홀수 패리티는 지원되지 않습니다" + +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "모든 채널이 사용중입니다" + +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "온도 데이터를 수신 할 수 없습니다" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" -msgstr "RS485 모드가 아닐 때 RS485 반전이 지정됩니다" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "뮤텍스 획득에 실패했습니다, 오류 0x%04x" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" -msgstr "이 보드에서는 PTC가 지원되지 않습니다" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "뮤텍스 해제에 실패했습니다, 오류 0x%04x" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" -msgstr "난수 생성 오류" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "오디오 변환이 구현되지 않음" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" -msgstr "읽기 전용" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/__init__.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q는 %q가 아닌 %q 또는 %q 유형이어야 합니다" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" -msgstr "읽기 전용 파일 시스템" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" +msgstr "프로그램 크기가 잘못되었습니다" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" -msgstr "수신된 응답이 잘못되었습니다" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "초기화 프로그램의 크기가 잘못되었습니다" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" -msgstr "다시 연결하는 중입니다" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "버퍼 요소는 4바이트 이하여야 합니다" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" -msgstr "너무 빨리 새로고침하였습니다" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" +msgstr "일치하지 않는 데이터 크기" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" +msgstr "출력 버퍼 요소의 길이는 <= 4 바이트 여야 합니다" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "버퍼 내 요소 길이는 <= 4여야 합니다" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" -msgstr "" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "이 함수에는 잠금이 필요합니다" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" -msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "비트 클럭 및 워드 선택은 순차적 GPIO 핀이어야 합니다" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" -msgstr "" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" +msgstr "DMA 간격 타이머를 찾을 수 없습니다" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" -msgstr "" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "I2C 주변 기기가 사용 중입니다" -#: ports/raspberrypi/common-hal/busio/SPI.c +#: ports/raspberrypi/common-hal/busio/SPI.c shared-bindings/emmcio/EMMC.c msgid "SPI peripheral in use" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "핀은 PWM 채널 B에 있어야 합니다" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" +msgstr "이 칩에서는 RISE_AND_FALL을 사용할 수 없습니다" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +#, fuzzy +msgid "PWM slice already in use" +msgstr "PWM slice가 이미 사용 중입니다" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +#, fuzzy +msgid "PWM slice channel A already in use" +msgstr "PWM slice channel A가 이미 사용 중입니다" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" -msgstr "" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#, fuzzy +msgid "All state machines in use" +msgstr "모든 상태 머신이 사용 중입니다" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" -msgstr "" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" +msgstr "핀은 순차적이어야 합니다" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" -msgstr "" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" +msgstr "서비스 TXT 레코드를 추가하는 것에 실패했습니다" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." -msgstr "" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" +msgstr "MDNS 서비스 슬롯 부족" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" -msgstr "" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "핀의 모든 타이머가 사용 중입니다" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." -msgstr "" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q는 %q가 아니라 %q 유형이어야 합니다" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" -msgstr "" +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" +msgstr "핀은 순차적인 GPIO 핀이어야 합니다" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "Pin count too large" +msgstr "핀 수 너무 큼" -#: shared-module/audiocore/__init__.c -msgid "The sample's %q does not match" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "Missing jmp_pin. %q[%u] jumps on pin" +msgstr "jmp_pin이 누락되었습니다. %q[%u] 핀으로 점프합니다" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "%q[%u]에서 추가 핀 사용" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" +msgstr "first_in_pin이 누락되었습니다. %q[%u]는 핀에 따라 대기 중입니다" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" +msgstr "%q[%u]이(가) 카운트 외부의 입력을 대기합니다" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +msgstr "first_in_pin이 누락되었습니다. %q[%u]는 pin(s)에서 이동합니다" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "%q[%u] shifts in more bits than pin count" +msgstr "%q[%u]가 핀 수보다 더 많은 비트로 이동했습니다" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "first_out_pin이 누락되었습니다. %q[%u]는 pin(s)으로 이동합니다" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "%q[%u] shifts out more bits than pin count" +msgstr "%q[%u]이(가) 핀 수보다 많은 비트를 전송합니다" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "first_set_pin이 누락되었습니다. %q[%u]는 pin(s)을 설정합니다" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "first_out_pin이 누락되었습니다. %q[%u]는 pin(s)에 씁니다" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "Missing first_in_pin. %q[%u] reads pin(s)" +msgstr "first_in_pin이 누락되어 있습니다. %q[%u]이 pin(s)을 읽습니다" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" +msgstr "프로그램이 ISR을 로드하지 않고 IN을 실행했습니다" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" +msgstr "프로그램이 OSR을 로드하지 않고 OUT을 실행했습니다" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" +msgstr "초기 설정한 핀의 상태가 초기 바깥쪽 핀의 상태와 충돌합니다" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" +msgstr "초기 설정한 핀의 방향이 초기 바깥쪽 핀의 방향과 충돌합니다" -#: shared-module/displayio/__init__.c -msgid "Too many displays" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" +msgstr "프로그램에 출력이 없습니다" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "No in in program" +msgstr "프로그램에 입력이 없습니다" -#: py/obj.c -msgid "Traceback (most recent call last):\n" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "No in or out in program" +msgstr "프로그램에 입력 또는 출력이 없습니다" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" +msgstr "일치하지 않는 스왑 플래그" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" -msgstr "" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" +msgstr "IPv4 소켓만 지원됩니다" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" -msgstr "" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "모든 dma채널이 사용 중입니다" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" -msgstr "" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q는 이 보드에 대한 읽기 전용입니다" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" -msgstr "" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "AP를 시작할 수 없습니다" -#: main.c -msgid "UID:" -msgstr "UID:" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" +msgstr "이 하드웨어에서는 에지 감지만 가능합니다" -#: shared-module/usb_hid/Device.c -msgid "USB busy" -msgstr "" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" +msgstr "핀 인터럽트는 이미 사용 중입니다" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." -msgstr "" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" +msgstr "핀은 딥 슬립에서 깨어날 수 없습니다" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." -msgstr "" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#, fuzzy +msgid "Deep sleep pins must use a rising edge with pulldown" +msgstr "딥 슬립 핀은 풀다운이 있는 상승 에지를 사용해야 합니다" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "잘못된 ADC 단위 값" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "DAC 장치 초기화 오류" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" -msgstr "UUID문자열이 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'형식이 아닙니다" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "DAC 채널 초기화 오류" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -"UUID값이 문자열(str), 정수(int) 또는 바이트버퍼가(byte buffer) 아닙니다" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Unable to allocate buffers for signed conversion" -msgstr "" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, fuzzy +msgid "Another PWMAudioOut is already active" +msgstr "다른 PWMaudioOut이 이미 활성화되어 있습니다" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." -msgstr "" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "버퍼 길이 %d가 너무 큽니다. 그것은 %d보다 작아야 합니다" -#: ports/espressif/common-hal/busio/I2C.c -msgid "Unable to create lock" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" +msgstr "샘플 버퍼링에 실패했습니다" + +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "I2C 초기화 오류" + +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" -#: py/parse.c -msgid "Unable to init parser" -msgstr "파서를 초기화(init) 할 수 없습니다" +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" +msgstr "내부 정의 오류" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" -msgstr "" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "인터럽트를 시작할 수 없습니다, RX가 사용 중입니다" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" msgstr "" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" -msgstr "" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" +msgstr "RNG 초기화 오류" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" -msgstr "" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" +msgstr "난수 생성 오류" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" +msgstr "RNG DeInit 오류" + +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: shared-bindings/wifi/Radio.c +#: ports/stm/common-hal/pwmio/PWMOut.c +#, fuzzy +msgid "PWM restart" +msgstr "PWM 재시작" + +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "Unknown failure %d" +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "Unknown gatt error: 0x%04x" +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#, fuzzy +msgid ".show(x) removed. Use .root_group = x" +msgstr ".show(x)가 제거되었습니다. .root_group = x를 사용합니다" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "밝기를 조절할 수 없습니다" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q는 %d-%d이어야 합니다" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "이미 사용된 그룹" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" -msgstr "" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "최소 프레임 속도 미만" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" -msgstr "" +#: py/argcheck.c shared-bindings/wifi/Radio.c +msgid "'%q' argument required" +msgstr "'%q' 인수가 필요합니다" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: py/builtinhelp.c -#, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c +msgid "argument num/types mismatch" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" -msgstr "" +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q는 %d이어야 합니다" -#: main.c -msgid "Woken up by alarm.\n" -msgstr "" +#: py/argcheck.c +#, fuzzy +msgid "%q must be >= %d" +msgstr "%q 는 >= %d 여야 합니다" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" -msgstr "" +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +#, fuzzy +msgid "%q must be <= %d" +msgstr "%q 는 <= %d 여야 합니다" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." -msgstr "" +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "%q 길이는 %d - %d이어야 합니다" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." -msgstr "" +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "%q 길이는 >= %d이어야 합니다" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "%q 길이는 <= %d>여야 합니다" + +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "%q 길이는 %d이어야 합니다" + +#: py/argcheck.c shared-module/audiofilters/__init__.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q의 %q는 %q가 아니라 %q 유형이어야 합니다" + +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: py/bc.c py/objnamedtuple.c +#, fuzzy +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q()는 %d 위치 인수를 사용하지만 %d이(가) 주어졌습니다" + +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: py/binary.c +msgid "integer out of range" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" +msgstr "게다가 파일 시스템의 모든 모듈\n" + +#: py/builtinhelp.c +msgid "object " msgstr "" -#: py/objtype.c +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " %q 유형입니다\n" + +#: py/builtinhelp.c #, c-format -msgid "__init__() should return None, not '%s'" +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: py/compile.c -msgid "annotation must be an identifier" +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/compile.c +msgid "invalid arch" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/compile.c +msgid "can't delete expression" msgstr "" #: py/compile.c -msgid "argument name reused" -msgstr "" +msgid "'break'/'continue' outside loop" +msgstr "'break'/'continue' 외부 루프" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" -msgstr "" +#: py/compile.c +msgid "'return' outside function" +msgstr "'return' 는 함수 외부에 존재합니다" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" #: py/compile.c msgid "async for/with outside async function" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "" +#: py/compile.c +#, fuzzy +msgid "*x must be assignment target" +msgstr "*x는 할당 대상이어야 합니다" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: py/objstr.c -msgid "attributes not supported" -msgstr "" +#: py/compile.c +#, fuzzy +msgid "* arg after **" +msgstr "* 인수 뒤에 **" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/compile.c +msgid "* arg after kwarg" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/compile.c +msgid "too many args" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" -msgstr "" +#: py/compile.c +msgid "LHS of keyword arg must be an id" +msgstr "키워드 인수의 LHS 는 id 여야 합니다" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/compile.c py/parse.c +msgid "invalid syntax" +msgstr "구문(syntax)가 유효하지 않습니다" + +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/compile.c +msgid "'yield' outside function" +msgstr "'yield' 는 함수 외부에 존재합니다" + +#: py/compile.c +#, fuzzy +msgid "'yield from' inside async function" +msgstr "비동기 함수 내 'yield from'" + +#: py/compile.c +msgid "'await' outside function" +msgstr "'await' 는 펑크션 외부에 있습니다" + +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: py/emitnative.c -msgid "binary op %q not implemented" +#: py/compile.c +msgid "argument name reused" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." +#: py/compile.c +msgid "inline assembler must be a function" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/compile.c +msgid "unknown type" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "'label' 에는 1 개의 독립변수가 필요합니다" + +#: py/compile.c +msgid "label redefined" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" -msgstr "bits_per_sample은 8 또는 16이어야합니다" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "'align' 에는 1 개의 독립변수가 필요합니다" -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "'data' 에는 >=2 개의 독립변수가 필요합니다" + +#: py/compile.c +#, fuzzy +msgid "'data' requires integer arguments" +msgstr "'data' 에는 정수 인수가 필요합니다" + +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/emitbc.c +msgid "bytecode overflow" +msgstr "" + +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: py/emitbc.c -msgid "bytecode overflow" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: py/objarray.c -msgid "bytes length not a multiple of item size" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: py/objstr.c -msgid "bytes value out of range" +#: py/emitinlinerv32.c +msgid "opcode '%q': registers must be different" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" +#: py/emitinlinerv32.c +msgid "opcode '%q': malformed register list" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/emitinlinerv32.c +msgid "opcode '%q': invalid stack adjustment" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: wrong register(s)" msgstr "" #: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +msgid "invalid RV32 instruction '%q'" msgstr "" #: py/emitinlinethumb.c msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" +#: py/emitinlinethumb.c +#, fuzzy, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s'는 최대 r%d를 필요로 합니다" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "'%s' 에는 레지스터가 필요합니다" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "'%s' 에는 특별한 레지스터가 필요합니다" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "'%s' 에는 FPU레지스터가 필요합니다" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' {r0, r1, ...}은 을 기대합니다" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "'%s' 는 정수 여야합니다" + +#: py/emitinlinethumb.c +#, fuzzy, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' 정수 0x%x 이 마스크 0x%x에 맞지 않습니다" + +#: py/emitinlinethumb.c +#, fuzzy, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s' 에는 [a, b] 형식의 주소가 필요합니다" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' 에는 라벨이 필요합니다" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" -#: py/compile.c -msgid "can't assign to expression" +#: py/emitinlinethumb.c +msgid "branch not in range" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: py/obj.c +#: py/emitinlinextensa.c #, fuzzy, c-format -msgid "can't convert %s to complex" -msgstr "%s 를 복합어로 변환할 수 없습니다" +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' 정수 %d가 %d..%d 범위 내에 있지 않습니다" -#: py/obj.c +#: py/emitinlinextensa.c #, c-format -msgid "can't convert %s to float" +msgid "%d is not a multiple of %d" msgstr "" -#: py/objint.c py/runtime.c +#: py/emitinlinextensa.c #, c-format -msgid "can't convert %s to int" +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" +#: py/emitnative.c +msgid "conversion to object" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" +#: py/emitnative.c +msgid "local '%q' used before type known" msgstr "" -#: py/obj.c -msgid "can't convert to complex" +#: py/emitnative.c +msgid "can't load from '%q'" msgstr "" -#: py/obj.c -msgid "can't convert to float" +#: py/emitnative.c +msgid "can't load with '%q' index" msgstr "" -#: py/runtime.c -msgid "can't convert to int" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/emitnative.c +msgid "can't store to '%q'" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/emitnative.c +msgid "can't store with '%q' index" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" #: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +msgid "'not' not implemented" msgstr "" #: py/emitnative.c @@ -2910,1728 +2870,1969 @@ msgid "can't do unary op of '%q'" msgstr "" #: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +msgid "div/mod not implemented for uint" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/emitnative.c +msgid "comparison of int and uint" msgstr "" #: py/emitnative.c -msgid "can't load from '%q'" +msgid "binary op %q not implemented" msgstr "" #: py/emitnative.c -msgid "can't load with '%q' index" +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" +#: py/emitnative.c +msgid "casting" msgstr "" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/emitnative.c +msgid "native raise" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/emitnative.c +msgid "must raise an object" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: py/emitnative.c -msgid "can't store '%q'" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: py/emitnative.c -msgid "can't store to '%q'" +#: py/modbuiltins.c py/objstr.c +msgid "char not in range(0x110000)" msgstr "" -#: py/emitnative.c -msgid "can't store with '%q' index" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "pow() 는 3개의 인수를 지원하지 않습니다" + +#: py/modbuiltins.c +msgid "must use keyword argument for key function" +msgstr "" + +#: py/moderrno.c +#, fuzzy +msgid "Operation not permitted" +msgstr "작업이 허용되지 않습니다" + +#: py/moderrno.c +msgid "No such file/directory" +msgstr "해당 파일/디렉토리가 없습니다" + +#: py/moderrno.c +msgid "Input/output error" +msgstr "입력/출력 오류" + +#: py/moderrno.c +msgid "Permission denied" +msgstr "권한이 거부 되었습니다" + +#: py/moderrno.c +msgid "File exists" +msgstr "파일이 있습니다" + +#: py/moderrno.c +msgid "No such device" +msgstr "해당 장치가 없습니다" + +#: py/moderrno.c +msgid "No space left on device" +msgstr "장치에 남은 공간이 없습니다" + +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" +#: py/modthread.c +msgid "expecting a dict for keyword args" +msgstr "사전(dict)이 예상되었습니다" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/modweakref.c +msgid "not a heap object" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: py/emitnative.c -msgid "casting" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" -msgstr "" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" +msgstr "위 예외를 처리하는 동안, 또 다른 예외가 발생하였습니다:" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" -msgstr "" +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " 파일 \"%q\", 라인 %d" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/obj.c +msgid " File \"%q\"" +msgstr " 파일 \"%q\"" + +#: py/obj.c +msgid ", in %q\n" +msgstr ", 에서 %q\n" + +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/obj.c +#, fuzzy, c-format +msgid "can't convert %s to complex" +msgstr "%s 를 복합어로 변환할 수 없습니다" + +#: py/obj.c +msgid "expected tuple/list" +msgstr "튜플(tuple) 또는 리스트(list)이 예상되었습니다" + +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: py/objcomplex.c -msgid "complex divide by zero" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "%q 인덱스는 %s 가 아닌 정수 여야합니다" + +#: py/obj.c +msgid "object has no len" msgstr "" -#: py/emitnative.c -msgid "conversion to object" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/obj.c +#, fuzzy, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "'%s' 개체가 항목 삭제를 지원하지 않습니다" + +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "'%s' 개체를 subscriptable 할 수 없습니다" + +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" +#: py/obj.c +#, fuzzy, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "'%s' 개체가 항목 할당을 지원하지 않습니다" + +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "data pin #%d in use" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/objcomplex.c +msgid "0.0 to a complex power" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +#: py/objdeque.c +msgid "full" +msgstr "완전한(full)" + +#: py/objdeque.c +msgid "empty" msgstr "" #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: py/emitnative.c -msgid "div/mod not implemented for uint" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "divide by zero" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: py/objdeque.c -msgid "empty" -msgstr "" +#: py/objint.c +msgid "float too big" +msgstr "float이 너무 큽니다" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" -msgstr "" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" +msgstr "긴 정수 지원이 없습니다" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: py/objstr.c -msgid "empty separator" -msgstr "" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "%q=%q" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objint_impl.h +#, c-format +msgid "value would overflow a %d byte buffer" msgstr "" -#: py/objstr.c -msgid "end of format while looking for conversion specifier" +#: py/objint_impl.h +msgid "can't convert negative int to unsigned" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: py/objstr.c -msgid "expected ':' after format specifier" -msgstr "':'이 예상되었습니다" - -#: py/obj.c -msgid "expected tuple/list" -msgstr "튜플(tuple) 또는 리스트(list)이 예상되었습니다" - -#: py/modthread.c -msgid "expecting a dict for keyword args" -msgstr "사전(dict)이 예상되었습니다" - -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" -msgstr "" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +#, fuzzy +msgid "%q step cannot be zero" +msgstr "%q 단계는 0일 수 없습니다" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objslice.c +msgid "Cannot subclass slice" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/objstr.c +msgid "unknown encoding: %q" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" +#: py/objstr.c +msgid "bytes value out of range" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/objstr.c +msgid "empty separator" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/objstr.c +msgid "rsplit(None,n)" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objstr.c +#, c-format +msgid "unknown conversion specifier %c" msgstr "" -#: py/objint.c -msgid "float too big" -msgstr "float이 너무 큽니다" +#: py/objstr.c +msgid "expected ':' after format specifier" +msgstr "':'이 예상되었습니다" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" +#: py/objstr.c +msgid "%q index out of range" +msgstr "%q 인덱스 범위를 벗어났습니다" + +#: py/objstr.c +msgid "attributes not supported" msgstr "" -#: extmod/moddeflate.c -msgid "format" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" #: py/objstr.c -msgid "format needs a dict" +msgid "invalid format specifier" +msgstr "형식 지정자(format specifier)가 유효하지 않습니다" + +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" #: py/objstr.c -msgid "format string didn't convert all arguments" +msgid "sign not allowed with integer format specifier 'c'" msgstr "" #: py/objstr.c -msgid "format string needs more arguments" +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: py/objdeque.c -msgid "full" -msgstr "완전한(full)" +#: py/objstr.c +#, fuzzy +msgid "'=' alignment not allowed in string format specifier" +msgstr "'=' 문자열 형식 지정자에서 정렬이 허용되지 않습니다" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" +#: py/objstr.c +msgid "incomplete format key" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objstr.c +msgid "incomplete format" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c +#: py/objstrunicode.c #, c-format -msgid "function takes %d positional arguments but %d were given" +msgid "string indices must be integers, not %s" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/objtemplate.c +msgid "expected str or Interpolation" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" -msgstr "" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "네이티브 개체에 액세스하기 전에 super().__init__()를 호출하십시오." -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy arch" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy file" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: py/objstr.c -msgid "incomplete format" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: py/objstr.c -msgid "incomplete format key" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/parse.c +msgid "not a constant" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" +#: py/parse.c +msgid "Unable to init parser" +msgstr "파서를 초기화(init) 할 수 없습니다" + +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/parsenum.c +msgid "invalid syntax for integer" +msgstr "구문(syntax)가 정수가 유효하지 않습니다" + +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" +msgstr "구문(syntax)가 정수가 유효하지 않습니다" + +#: py/parsenum.c +msgid "invalid syntax for number" +msgstr "숫자에 대한 구문(syntax)가 유효하지 않습니다" + +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/persistentcode.c +msgid "incompatible .mpy arch" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/persistentcode.c +msgid "function must be bytecode" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "'%q' 개체가 '%q'를 지원하지 않습니다" + +#: py/qstr.c +msgid "name too long" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/runtime.c +#, fuzzy +msgid "'%s' object has no attribute '%q'" +msgstr "'%s' 개체에 '%q' 특성이 없습니다" + +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "'%q' 개체를 사용할 수 없습니다" + +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "'%q' 개체가 iterator가 아닙니다" + +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" -msgstr "cert가 유효하지 않습니다" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" +msgstr "" -#: shared-bindings/bitmaptools/__init__.c +#: py/runtime.c #, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: py/runtime.c +msgid "can't convert to int" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" -msgstr "형식 지정자(format specifier)가 유효하지 않습니다" +#: py/runtime.c +msgid "maximum recursion depth exceeded" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" -msgstr "키가 유효하지 않습니다" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" +msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: py/vm.c +msgid "local variable referenced before assignment" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" -msgstr "단계(step)가 유효하지 않습니다" +#: py/vm.c +msgid "opcode" +msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" -msgstr "구문(syntax)가 유효하지 않습니다" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "_bleio.adapter를 사용해서; 새로운 Adapter를 만들 수 없습니다;" -#: py/parsenum.c -msgid "invalid syntax for integer" -msgstr "구문(syntax)가 정수가 유효하지 않습니다" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "주소를 설정할 수 없습니다" -#: py/parsenum.c +#: shared-bindings/_bleio/Adapter.c #, c-format -msgid "invalid syntax for integer with base %d" -msgstr "구문(syntax)가 정수가 유효하지 않습니다" - -#: py/parsenum.c -msgid "invalid syntax for number" -msgstr "숫자에 대한 구문(syntax)가 유효하지 않습니다" - -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +msgid "interval must be in range %s-%s" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" -msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." +msgstr "확장되고 연결 가능한 광고에 대한 검색 응답을 가질 수 없습니다." -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" -msgstr "" +#: shared-bindings/_bleio/Adapter.c +#, fuzzy +msgid "Only connectable advertisements can be directed" +msgstr "연결 가능한 광고만 지시할 수 있습니다" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" -msgstr "" +#: shared-bindings/_bleio/Adapter.c +#, fuzzy +msgid "Prefix buffer must be on the heap" +msgstr "앞의 버퍼는 힙에 있어야 합니다" + +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "CharacteristicBuffer 쓰기는 제공되지 않습니다" -#: py/compile.c -msgid "label redefined" -msgstr "" +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." +msgstr "연결이 끊어져 더 이상 사용할 수 없습니다. 새로운 연결을 만드십시오." -#: py/objarray.c -msgid "lhs and rhs should be compatible" -msgstr "" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" +msgstr "버퍼가 %d 바이트로 너무 짧습니다" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" -msgstr "" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" +msgstr "연결이 없습니다: 길이를 결정할 수 없습니다" -#: py/emitnative.c -msgid "local '%q' used before type known" -msgstr "" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +msgstr "UUID문자열이 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'형식이 아닙니다" -#: py/vm.c -msgid "local variable referenced before assignment" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" +"UUID값이 문자열(str), 정수(int) 또는 바이트버퍼가(byte buffer) 아닙니다" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" -msgstr "" +#: shared-bindings/_bleio/__init__.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" +msgstr "읽기 전용" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "잘못된 버퍼 크기" + +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: py/parse.c -msgid "malformed f-string" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" #: shared-bindings/_stage/Layer.c msgid "map buffer too small" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" -msgstr "" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" +msgstr "핀은 입력 전용입니다" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c #, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "키는 16, 24, 또는 32 바이트 길이여야 합니다" -#: py/runtime.c -msgid "maximum recursion depth exceeded" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB는 한 번에 16 바이트에서만 작동합니다" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "CBC 블록은 16 바이트의 배수여야 합니다" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +#, fuzzy +msgid "Array values should be single bytes." +msgstr "배열 값은 1바이트 여야합니다." -#: py/objarray.c -msgid "memoryview offset too large" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" -msgstr "" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" +msgstr "%q 유형이 필요합니다" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" -msgstr "" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" +msgstr "이 보드에서는 PTC가 지원되지 않습니다" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: py/builtinimport.c -msgid "module not found" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" -msgstr "" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q는 'H' 또는 'B' 타입의 바이트 배열 또는 배열이어야 합니다" -#: py/compile.c -msgid "multiple *x in assignment" -msgstr "" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" +msgstr "재생되지 않았습니다" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: py/objtype.c -msgid "multiple inheritance not supported" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "파일에 녹음 할 수 없습니다" -#: py/emitnative.c -msgid "must raise an object" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "대상 용량이 destination_length보다 작습니다." -#: py/modbuiltins.c -msgid "must use keyword argument for key function" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/runtime.c -msgid "name not defined" -msgstr "" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q는 h, H, b 또는 B 유형의 바이트 배열 또는 배열이어야 합니다" -#: py/qstr.c -msgid "name too long" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c +#: shared-bindings/audiodelays/GranularPitchShift.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" +msgstr "bits_per_sample은 8 또는 16이어야합니다" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: py/runtime.c +#: shared-bindings/audioi2sin/I2SIn.c #, c-format -msgid "need more than %d values to unpack" +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: py/modmath.c -msgid "negative factorial" +#: shared-bindings/audioio/AudioOut.c shared-bindings/emmcio/EMMC.c +msgid "%q and %q must be different" +msgstr "%q와 %q는 달라야 합니다" + +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "비트맵 크기와 값 당 비트가 일치해야 합니다" + +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +msgstr "L8 색상 공간의 경우, 입력 비트맵은 픽셀 당 8 비트를 가져야 합니다" + +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +msgstr "RGB 색상 공간의 경우, 입력 비트맵은 픽셀 당 16 비트를 가져야 합니다" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/builtinimport.c -msgid "no module named '%q'" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" +msgstr "좌표 배열 유형은 크기가 다릅니다" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "좌표 배열의 길이가 다릅니다" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" -msgstr "" +#: shared-bindings/bitops/__init__.c +#, fuzzy, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgstr "입력 버퍼 길이 (%d) 는 스트랜드 수 (%d)의 배수여야 한다" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" -msgstr "" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" +msgstr "기본 버스 %q가 없습니다" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "디스플레이 회전은 90도씩 증가해야 합니다" -#: py/builtinhelp.c -msgid "object " -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q가 참일 때 %q는 1이어야 합니다" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "디스플레이는 16 비트 색 공간을 가져야 합니다." -#: py/obj.c -msgid "object doesn't support item assignment" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: py/obj.c -msgid "object doesn't support item deletion" -msgstr "" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." +msgstr "%q의 하위클래스여야 합니다." -#: py/obj.c -msgid "object has no len" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "방향이 입력되면 값을 설정할 수 없습니다." -#: py/runtime.c -msgid "object not an iterator" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "방향을 입력할 때 드라이브 모드는 사용되지 않습니다." -#: py/objtype.c py/runtime.c -msgid "object not callable" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +#, fuzzy +msgid "Pull not used when direction is output." +msgstr "방향이 출력 될 때 풀은 사용되지 않습니다" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: py/obj.c -msgid "object with buffer protocol required" -msgstr "" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "값을 삭제할 수 없습니다" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" -msgstr "" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" +msgstr "새로운 비트맵은 원본 비트맵과 크기가 같아야 합니다" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" -#: py/vm.c -msgid "opcode" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/emmcio/EMMC.c shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" -msgstr "" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "너무 빨리 새로고침하였습니다" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" -msgstr "" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "버퍼는 바이트 배열이 아닙니다." -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" -msgstr "" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" +msgstr "유효한 IP 문자열이 아닙니다" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" -msgstr "" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" +msgstr "주소 길이는 %d 바이트 여야합니다" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" -msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "ip에는 정수 또는 문자열만 지원됩니다" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" -msgstr "" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" +msgstr "매핑은 투플이어야 합니다" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" +"서비스 TXT 레코드를 추가하는 것에 실패했습니다; txt_records에서 비문자열 또" +"는 바이트가 발견되었습니다" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q에 중복된 핀이 포함" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q 및 %q에 중복된 핀이 포함" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" -msgstr "" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" +msgstr "임의의 하드웨어를 사용할 수 없습니다" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" -msgstr "" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "잘못된 형식" -#: py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." +msgstr "명령을 보내는 것에 실패했습니다." + +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "배열은 하프워드(유형 'H')가 포함되어야 합니다" + +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" +#: shared-bindings/random/__init__.c +msgid "invalid step" +msgstr "단계(step)가 유효하지 않습니다" + +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" msgstr "" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" +msgstr "%d이 아닌, 6 rgb 핀을 여러 개 사용해야 합니다" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +"%d 주소 핀들, %d rgb 핀들과 %d 타일 들은 높이가 %d임을 나타낸다, %d가 아니라" #: shared-bindings/socketpool/Socket.c msgid "port must be >= 0" msgstr "" -#: py/compile.c -msgid "positional arg after **" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" -msgstr "" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" +msgstr "이름 또는 서비스를 알 수 없습니다" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" -msgstr "" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "현재 USB 디바이스를 변경할 수 없습니다" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" -msgstr "" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" +msgstr "파일을 찾을 수 없습니다" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" -msgstr "" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q 및 %q의 길이는 모두 같아야 합니다" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" +"개체가 초기화 해제되어 더 이사 사용될 수 없습니다. 새로운 개체를 만드십시오." -#: py/objstr.c -msgid "rsplit(None,n)" -msgstr "" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "%q는 %q의 하위 클래스여야 합니다" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" +msgstr "잘못된 16진수 패스워드" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "잘못된 MAC 주소" -#: py/builtinimport.c -msgid "script compilation not supported" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "AuthMode.OPEN은 암호와 함께 사용되지 않습니다" -#: py/nativeglue.c -msgid "set unsupported" +#: shared-bindings/wifi/Radio.c +msgid "Supply either %q or %q, not both" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "잘못된 BSSID" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" -msgstr "" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "인증 실패" -#: shared-module/msgpack/__init__.c -msgid "short read" +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" +msgstr "이 ssid를 사용하는 네트워크가 없습니다" + +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: py/objstr.c -msgid "sign not allowed in string format specifier" -msgstr "" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" +msgstr "주소에 I2C 장치가 없습니다: 0x%x" + +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "형식 청크 크기가 잘못되었습니다" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" msgstr "" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" -msgstr "" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "디코더를 할당할 수 없습니다" -#: main.c -msgid "soft reboot\n" -msgstr "" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "MP3 파일 분석에 실패했습니다" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" -msgstr "" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" +msgstr "값 당 잘못된 비트" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" -msgstr "" +#: shared-module/displayio/ColorConverter.c +#, fuzzy +msgid "Only one color can be transparent at a time" +msgstr "한 번에 한 가지 색상만 투명할 수 있습니다" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "레이어가 이미 그룹에 있습니다" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" -msgstr "" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "레이어는 그룹 또는 TileGrid 하위 클래스 여야 합니다" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" +msgstr "윈도우 형식, 비압축 BMP만 지원됩니다: 지정된 헤더 크기는 %d 입니다" + +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: py/objstrunicode.c +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c #, c-format -msgid "string indices must be integers, not %s" +msgid "Unable to find I2C Display at %x" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" -msgstr "" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "LED 매핑은 디스플레이 크기와 일치해야 합니다" -#: extmod/modtime.c -msgid "ticks interval overflow" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" +msgstr "출력 함수로 인해 종료되었다" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" +msgstr "장치 오류 또는 입력 스트림의 잘못된 종료" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" +msgstr "이미지에 대한 메모리 풀이 부족합니다" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" +msgstr "불충분한 스트림 입력 버퍼" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +#, fuzzy +msgid "Parameter error" +msgstr "파라미터 오류" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" +msgstr "데이터 형식 오류(손상된 데이터일 수 있습니다)" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" -msgstr "" +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" +msgstr "%d 블록 할당 시도" -#: py/compile.c -msgid "too many args" +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" -msgstr "" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" +msgstr "사용 가능한 타이머가 없습니다" -#: py/runtime.c +#: shared-module/rgbmatrix/RGBMatrix.c #, c-format -msgid "too many values to unpack (expected %d)" +msgid "Internal error #%d" +msgstr "내부 오류 #%d" + +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "TLS에 대한 잘못된 소켓" + +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" +msgstr "키가 유효하지 않습니다" + +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" +msgstr "cert가 유효하지 않습니다" + +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' 및 'O'는 지원되지 않는 형식 유형입니다" + +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/synthio/__init__.c +#, fuzzy +msgid "%q must be array of type 'h'" +msgstr "%q는 'h' 유형의 배열이어야 합니다" + +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/parse.c -msgid "unexpected indent" -msgstr "" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" +msgstr "핀에 풀다운이 없습니다; 1Mohm를 권장합니다" -#: py/bc.c -msgid "unexpected keyword argument" -msgstr "" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" +msgstr "usb 호스트 포트가 초기화되지 않았습니다" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" -msgstr "" +#: shared-module/usb/core/Device.c +msgid "Pipe error" +msgstr "파이프 오류" -#: py/lexer.c -msgid "unicode name escapes" -msgstr "" +#: shared-module/usb/core/Device.c +#, fuzzy +msgid "No configuration set" +msgstr "구성이 설정되어 있지 않습니다" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" -msgstr "" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" +msgstr "다각형은 최소 3개의 점이 필요합니다" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" +msgstr "다시 연결하는 중입니다" -#: py/compile.c -msgid "unknown type" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" +msgstr "켜짐 (연결됨)" -#: py/compile.c -msgid "unknown type '%q'" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" +msgstr "꺼짐 (연결 끊김)" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" +"\n" +"안전 모드에 있는 이유는 다음과 같습니다:\n" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." +msgstr "전력이 내려갔습니다. 충분한 전력을 제공할 수 있는지 확인하십시오." -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "CIRCUITPY 드라이브를 찾거나 만들 수 없습니다." -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "safemode.py에 오류가 있습니다." -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "부팅 장치는 첫 번째(인터페이스 #0)여야 합니다." -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "내부 감시 타이머가 만료되었습니다." -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "CircuitPython 핵심 코드가 심하게 충돌했습니다. 앗!\n" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." +msgstr "VM이 작동하지 않을 때 힙이 할당됩니다." -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" -msgstr "" +#: supervisor/shared/safe_mode.c +#, fuzzy +msgid "Failed to write internal flash." +msgstr "내부 플래시를 쓰는 것에 실패했습니다." -#: extmod/moddeflate.c -msgid "wbits" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." +msgstr "치명적인 실수: 메모리 액세스 또는 명령 오류." -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." +msgstr "인터럽트 오류." -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." +msgstr "NLR 는 점프에 실패했습니다. 아마도 메모리 손상일 것입니다." -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" +"\n" +"github.com/adafruit/circuitpython/issues 에\n" +"프로그램 오류를 제출하세요." -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" +"\n" +"재설정을 눌러 안전 모드를 종료합니다.\n" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" -msgstr "" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "%s'을(를) 검색하는 동안 오류가 발생했습니다:\n" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" -msgstr "" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" +msgstr "잘못된 유니코드 이스케이프" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " msgstr "" -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" -msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "IP가 없습니다" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" -msgstr "" +#, fuzzy +#~ msgid "%q out of bounds" +#~ msgstr "%q가 경계를 벗어남" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" -msgstr "" +#~ msgid "%q renamed %q" +#~ msgstr "%q가 %q로 이름이 변경되었습니다" -#: py/runtime.c -msgid "wrong number of values to unpack" -msgstr "" +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Buffer + offset이 너무 작습니다 %d %d %d" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" -msgstr "" +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "잘못된 크기의 버퍼. 16 바이트 여야합니다." -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" -msgstr "" +#, c-format +#~ msgid "Invalid byte %.*s" +#~ msgstr "잘못된 바이트 %.*s" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" -msgstr "" +#~ msgid "Key not found" +#~ msgstr "키를 찾을 수 없습니다" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" -msgstr "" +#, fuzzy +#~ msgid "Not supported JPEG standard" +#~ msgstr "지원되지 않는 JPEG 표준" + +#, fuzzy +#~ msgid "%q moved from %q to %q" +#~ msgstr "%q가 %q에서 %q로 이동했습니다" #, c-format #~ msgid "%%c requires int or char" diff --git a/locale/ru.po b/locale/ru.po index af7c8bca194..0473a941613 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -18,1226 +18,1272 @@ msgstr "" "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" -msgstr "" -"\n" -"Программа закончила выполнение.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" +msgstr "пустая куча" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" -msgstr "" -"\n" -"Программа остановлена автоматической перезагрузкой. Скоро перезагрузка.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" +msgstr "Не могу отменить себя" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." -msgstr "" -"\n" -"Пожалуйста подайте вопрос с вашей программой на github.com/adafruit/" -"circuitpython/issues." +#: extmod/modasyncio.c +msgid "can't wait" +msgstr "не может ждать" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" -msgstr "" -"\n" -"Нажмите на сброс чтобы выйти из безопасного режима.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" +msgstr "Требуется байтоподобный объект" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" +msgstr "Неправильная набивка" + +#: extmod/moddeflate.c +msgid "format" +msgstr "формат" + +#: extmod/moddeflate.c +msgid "wbits" msgstr "" -"\n" -"Вы в безопасном режиме потому что:\n" -#: py/obj.c -msgid " File \"%q\"" -msgstr " Файл \"%q\"" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "хэш является окончательным" -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " Файл \"%q\", строка %d" +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "куча должна быть списком" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " имеет тип %q\n" +#: extmod/modjson.c +msgid "syntax error in JSON" +msgstr "синтаксис ошибка в JSON" -#: main.c -msgid " not found.\n" -msgstr " не найден.\n" +#: extmod/modrandom.c +msgid "bits must be 32 or less" +msgstr "биты должны быть 32 или менее" -#: main.c -msgid " output:\n" -msgstr " вывод:\n" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" +msgstr "Нет начального числа по умолчанию" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" -msgstr "" +#: extmod/modre.c +msgid "splitting with sub-captures" +msgstr "разделение с помощью подзахватов" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modre.c +msgid "regex too complex" msgstr "" -"Адресные контакты %d, контакты rgb %d и плитки %d обозначают высоту %d, а не " -"%d" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q и %q содержат пины дупликаты" +#: extmod/modre.c +msgid "Error in regex" +msgstr "Ошибка в регулярном выражении" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q и %q должны быть разными" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" +msgstr "mktime нужен кортеж длины 8 или 9" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" -msgstr "%q и %q должны иметь общую единицу тактового генератора" +#: extmod/modtime.c +msgid "ticks interval overflow" +msgstr "переполнение интервала тиков" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" -msgstr "%q не может быть изменен после установки режима на %q" +#: extmod/modzlib.c +msgid "compression header" +msgstr "Заголовок сжатия" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q содержит пины дупликаты" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" +msgstr "Тип данных не понят" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -msgid "%q failure: %d" -msgstr "%q сбой: %d" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "массив слишком велик" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "Переполнение длины массива ndarray" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "%q в %q должно быть типа %q, а не %q" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "Не удается преобразовать сложный тип" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q используется" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "Слишком много измерений" -#: py/objstr.c -msgid "%q index out of range" -msgstr "Индекс %q вне диапазона" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "индекс выходит из границ" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "Индексы %q должны быть целыми числами, а не %s" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "индексы должны быть целыми числами, срезами или логическими списками" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c -msgid "%q init failed" -msgstr "Инициализация %q не удалась" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "Операнды не могут транслироваться вместе" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q является %q" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "Длина массива и индекса должна быть равна" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "%q читается только для этой доски" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "не может превратить комплекс в dtype" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "Длинна %q должна быть %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "операция реализована только для 1D логических массивов" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "Длинна %q должна быть %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "Слишком много индексов" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "Длинна %q должна быть <= %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "Не удается удалить элементы массива" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "Длинна %q должна быть >= %d" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "порядок сглаживания должен быть либо 'C', либо 'F'" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "%q переместился из %q в %q" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "Тобайты могут быть вызваны только для плотных массивов" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q должно быть %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" +msgstr "Операция не поддерживается для данного типа" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q должно быть %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" +msgstr "фигура должна быть целым числом или кортежом целых чисел" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q должен быть равен 1, если %q имеет значение True" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "Максимальное количество измерений составляет " -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "%q должно быть <= %d" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "Можно указать только одно неизвестное измерение" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" -msgstr "%q должно быть <= %u" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "Не удается изменить форму массива" -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "%q должно быть >= %d" - -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q должен быть массивом байтов или массивом типа «H» или «B»" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "Не удается назначить новую фигуру" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q должен быть массивом байтов или массивом типа «h», «H», «b» или «B»" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "Функция определяется только для массивов ndarrays" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" -msgstr "%q должен быть подклассом %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" +msgstr "операция не поддерживается для типов ввода" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" -msgstr "%q должен быть массивом типа 'H \"" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" +msgstr "dtype int32 не поддерживается" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" -msgstr "%q должен быть массивом типа 'h \"" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "Не удается привести выходные данные с помощью правила приведения" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." -msgstr "%q должно быть кратно 8." +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" +msgstr "Результаты не могут быть приведены к указанному типу" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "%q должно быть типа%q или%q, а не%q" +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" +msgstr "interp определен для 1D-итераций одинаковой длины" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" -msgstr "%q должен иметь тип %q, %q или %q, а не %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" +msgstr "ловушка определена для одномерных 1D итераций" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q должно быть типа %q, а не %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" +msgstr "ловушка определена для одномерных 1D массивов одинаковой длины" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q должен быть во 2-й степени" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "Не поддерживается для типов ввода" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "%q за пределом" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "Функция реализована только для массивов ndarrays" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "%q вне диапазона" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "Ввод должен быть массивом ndarray или скаляр" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "%q переименован %q" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" +msgstr "Ввод должен быть 1D массивом ndarray" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "Шаг %q не может быть нулём" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "не реализовано для сложного типа d" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" -msgstr "%q слишком долго" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" +msgstr "Неправильный тип ввода" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q() принимает %d позиционных аргументов, но было передано %d" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "Входной аргумент должен быть целым числом, кортежом или списком" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" -msgstr "%q() без %q()" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" +msgstr "неправильное количество аргументов" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q, и %q должны быть одной длинны" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" +msgstr "Делим на ноль" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" +msgstr "arange: не удается вычислить длину" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" -msgstr "%q [%u] смещается в большем количестве чем количество пинов" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "Первый аргумент должен быть кортежом массива ndarrays" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" -msgstr "%q[%u] смещает больше битов чем количество выводов" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "только массивы ndarrays могут быть объединены" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "%q[%u] использует дополнительный контакт" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "Указана неправильная ось" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" -msgstr "%q [%u] ожидает ввода за пределами графа" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "Входные массивы несовместимы" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "%s ошибка 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "Вход должен быть 1- или 2-D" -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "Требуется аргумент '%q'" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "Количество баллов должно быть не менее 2" -#: py/proto.c -msgid "'%q' object does not support '%q'" -msgstr "Объект '%q' не поддерживает '%q'" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "Смещение должно быть неотрицательным и не превышать длину буфера" -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "Объект '%q' не является итератором" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "Размер буфера должен быть кратен размеру элемента" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" -msgstr "" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "Размер буфера меньше запрошенного" -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "Объект '%q' не является итерируемым" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "FFT определено только для массивов ndarrays" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' ожидает метку" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "FFT реализовано только для линейных массивов" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' ожидает регистр" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "Длина входного массива должна быть равна степени 2" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' ожидает специальный регистр" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "реальные и воображаемые части должны быть одинаковой длины" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' ожидает регистр FPU" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "переплетение аргументов должно быть массивами ndarrays" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s' ожидает адрес в формате [a, b]" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "Аргументы свертки должны быть линейными массивами" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' ожидает целое число" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "аргументы свертки не должны быть пустыми" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s' ожидает не более r%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "Поврежденный файл" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' ожидает {r0, r1, ...}" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "Неправильный тип" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' целое число %d не находится в пределах диапазона %d..%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "Ключевое слово usecols должно быть указано" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' целое число 0x%x не помещается в маску 0x%x" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "пустой файл" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "Объект '%s' не поддерживает присвоение элементов" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "Usecols слишком высок" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "Объект '%s' не поддерживает удаление элементов" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "Массив имеет слишком много измерений" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "Объект '%s' не имеет атрибута '%q'" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "Входная матрица асимметрична" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "Объект '%s' не может быть подписан" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "матрица не является положительно определенной" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "Выравнивание '=' недопустимо в спецификаторе формата строки" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "итерации не сходятся" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' и 'O' не являются поддерживаемыми типами форматов" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "Входная матрица является сингулярной" -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "«выравнивание» требует 1 аргумента" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "операция определена только для массивов ndarrays" -#: py/compile.c -msgid "'await' outside function" -msgstr "«ожидание» внешняя функция" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "операция определена только для 2D-массивов" -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "'прервать'/'продолжить' вне цикла" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "Режим должен быть завершенным или уменьшенным" -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "«данные» требуют как минимум 2 аргумента" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" +"Попытка получить аргумент минимальный/аргумент максимальный пустой " +"последовательности" -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "«данные» требуют целочисленных аргументов" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" +msgstr "" +"Попытка получить (аргумент)минимальный/(аргумент)максимальный пустой " +"последовательности" -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "«метка» требует 1 аргумент" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "ось должна быть None или целым числом" -#: py/emitnative.c -msgid "'not' not implemented" -msgstr "'не' не реализовано" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "операция не реализована на массивах ndarrays" -#: py/compile.c -msgid "'return' outside function" -msgstr "«возврат» внешняя функция" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "Ввод должен быть кортеж, список, диапазон или массивом ndarray" -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "«выход из» внутри асинхронной функции" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "аргумент сортировки должен быть массивом ndarray" -#: py/compile.c -msgid "'yield' outside function" -msgstr "внешняя функция \"выход\"" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "аргумент сортировки должен быть аргументом массива ndarray" -#: py/compile.c -msgid "* arg after **" -msgstr "* аргумент после **" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "сортировка arg не реализована для сглаженных массивов" -#: py/compile.c -msgid "*x must be assignment target" -msgstr "*x должно быть целью назначения" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" +msgstr "Слишком длинная ось" -#: py/obj.c -msgid ", in %q\n" -msgstr ", в %q\n" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "Аргументы должны быть массивами ndarrays" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" -msgstr ". Показать(x) удален. Используйте . корневую_группу = x" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" +msgstr "крест определяется для 1D массивов длины 3" -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "0.0 в комплексную степень" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" +msgstr "аргумент DIFF должен быть массивом ndarray" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "Pow() с 3 аргументами не поддерживается" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "индекс вне диапазона" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "AP не может быть запущен" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" +msgstr "Порядок дифференциации вне диапазона" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "Адрес должен быть длиной %d байт" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "Флип -аргумент должен быть массивом ndarray" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "Диапазон адресов не разрешен" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "Неправильный индекс оси" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" -msgstr "Обертывание диапазона адресов" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "Средний аргумент должен быть массивом ndarray" -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "Все периферийные устройства CAN уже используются" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "аргумент roll должен быть массивом ndarray" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "Все периферийные устройства I2C уже используются" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "Входные данные должны быть итерируемыми" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "Все RX FIFO уже используются" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "Больше степеней свободы чем точек данных" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "Все периферийные устройства SPI уже используются" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "Входные векторы должны быть одинаковой длины" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "Все периферийные устройства UART уже используются" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" +msgstr "не удалось инвертировать матрицу Вандермонда" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "Все каналы уже используются" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "Ввод не является итерируемым" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "Все используемые каналы dma" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "аргумент должен быть None, целым числом или кортежем целых чисел" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "Все каналы событий уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "форма должна быть None, целым числом или кортежем целых чисел" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "Все машины состояний уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" +msgstr "out имеет неправильный тип" -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" -msgstr "Все каналы событий синхронизации уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "Выходной массив имеет неправильный тип" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "Все таймеры для этого пина уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "Размер должен соответствовать out.shape при совместном использовании" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "Все таймеры уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "выходной массив должен быть непрерывным" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "Уже реклама." +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" +msgstr "неправильная длина массива состояния" -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "Уже есть универсальный слушатель" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "Первым аргументом должен быть массивом ndarray" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" -msgstr "Уже в процессе" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "Неправильный тип индекса" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "Уже запущен" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" +msgstr "неправильная длина массива индексов" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "Поиск сетей wifi уже происходит" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "Размеры не совпадают" -#: shared-module/os/getenv.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "Произошла ошибка при получении '%s':\n" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" +msgstr "out должен быть массивом ndarray" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "Другой аудиовыход PWM уже активен" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" +msgstr "Выход должен быть поплавкового типа" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "Другая передача уже активна" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "Входные и выходные размеры различаются" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "Массив должен содержать полуслова (тип 'H')" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "Входные и выходные формы различаются" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "Значения массива должны быть однобайтовыми." +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "ключевое слово не поддерживается для функции" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" +msgstr "Ключевое слово out не поддерживается для сложного типа d" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "Попытка выделения %d блоков" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" +msgstr "Тип d должен быть плавающим или сложным" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "Преобразование звука не реализовано" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "Не может преобразовать сложный в плавающий" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Audio source error" -msgstr "" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "Входной тип dtype должен быть плавающим или сложным" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "Режим авторизации.OPEN не используется с паролем" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "Первый аргумент должен быть вызываемым" -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "Ошибка аутентификации" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" +msgstr "неверный тип вывода" -#: main.c -msgid "Auto-reload is off.\n" -msgstr "Автоматическая перезагрузка отключена.\n" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "Первые два аргумента должны быть массивами ndarrays" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" -msgstr "" -"Автоматическая перезагрузка включена. Просто сохрани файл по USB или зайди в " -"REPL чтобы отключить.\n" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "Ввод должен быть плотным массивом ndarray" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "Скорость передачи данных не поддерживается периферийным устройством" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "первый аргумент должен быть функцией" -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "Ниже минимальной частоты кадров" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" +msgstr "функция имеет один и тот же знак в конце интервала" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "Несколько часов и слов должны быть последовательными GPIO пинами" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "макситер должен быть > 0" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "" -"Размер растрового изображения и число битов на значение должны совпадать" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "maxiter должен быть > 0" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "Загрузочное устройство должно быть первым (интерфейс #0)." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "Данные должны быть итерируемыми" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "Для управления потоком требуется как RX так и TX" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "Начальные значения должны быть итерируемыми" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "Яркость не регулируется" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "Данные должны быть одинаковой длины" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Буфер + сдвиг слишком малы %d %d %d" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" +msgstr "sosфильтр требует повторяющихся аргументов" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "Элементы буфера должны иметь длину не более 4 байт" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "Входные данные должны быть одномерными" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "Буфер не является байтовым массивом." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "зи, должно быть, массивом ndarray" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "Размер буфера %d слишком большой. Он должен быть меньше чем %d" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" +msgstr "zi должен иметь форму (n_section, 2)" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" -msgstr "Буфер должен быть кратен %d байт" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" +msgstr "zi должно быть типа float" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "Буфер слишком короткий на %d байт" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" +msgstr "Массив sos должен иметь форму (n_section, 6)" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "Слишком маленький буфер" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "sos[:, 3] должны быть все единицы" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Вывод шины %d уже используется" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "Ось выходит за пределы" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Буфер байтов должен быть размером 16 байтам." +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "размер определен только для массива ndarrays" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "Блоки CBC должны быть кратны 16 байтам" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" +msgstr "Входные данные должны быть квадратной матрицей" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "Диск CIRCUTPY не удалось найти или создать." +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" +msgstr "Ввод должен быть массивом ndarray" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC или контрольная сумма неправильная" +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" +msgstr "Out должен быть плотным массивом с плавающей запятой" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "Вызовите super().__init__() перед доступом к собственному объекту." +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" +msgstr "Смещение слишком большое" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" -msgstr "Иницализация камеры" +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" +msgstr "Наш массив слишком мал" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "Возможен только сигнал тревоги по RTC IO из глубокого сна." +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" +msgstr "Файловая система только для чтения" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." -msgstr "" -"Может сигнализировать только по одному низкому контакту в то время как " -"другие сигнализируют о высоком уровне после глубокого сна." +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "Операция ввода-вывода на закрытом файле" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." -msgstr "" -"Из глубокого сна может сигнализировать только по двум низким контактам." +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" +msgstr "Опрос в файле недоступен в Win32" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" -msgstr "" +#: main.c +msgid "Done" +msgstr "Выполнено" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "Невозможно установить CCCD для локальной характеристики" +#: main.c +msgid " output:\n" +msgstr " вывод:\n" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "Невозможно изменить USB устройство сейчас" +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" +msgstr "" +"Автоматическая перезагрузка включена. Просто сохрани файл по USB или зайди в " +"REPL чтобы отключить.\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "Невозможно создать новый Adapter; используйте _bleio.adapter;" +#: main.c +msgid "Auto-reload is off.\n" +msgstr "Автоматическая перезагрузка отключена.\n" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "Невозможно удалить значения" +#: main.c +msgid "Running in safe mode! Not running saved code.\n" +msgstr "Работает в безопасном режиме! Сохраненный код не выполняется.\n" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "Невозможно получить pull в режиме вывода" +#: main.c +msgid " not found.\n" +msgstr " не найден.\n" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "Невозможно получить температуру" +#: main.c +msgid "WARNING: Your code filename has two extensions\n" +msgstr "ВНИМАНИЕ: Имя файла кода имеет два расширения\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" -"Не может быть ответов на сканирование для расширенных подключаемых рекламных " -"объявлений." +"\n" +"Программа остановлена автоматической перезагрузкой. Скоро перезагрузка.\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "Невозможно вытащить контакт только для ввода." +#: main.c +msgid "" +"\n" +"Code done running.\n" +msgstr "" +"\n" +"Программа закончила выполнение.\n" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Cannot record to a file" -msgstr "Невозможно записать в файл" +#: main.c +msgid "Woken up by alarm.\n" +msgstr "Проснулся по тревоге.\n" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" +"Нажмите любую клавишу чтобы зайти в REPL. Используйте CTRL-D для " +"перезагрузки.\n" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Cannot set value when direction is input." -msgstr "Невозможно установить значение при вводе направления." +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +msgstr "" +"Притворяюсь глубоким сном до сигнала тревоги, CTRL-C или записи файла.\n" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "Невозможно указать RTS или CTS в режиме RS485" +#: main.c +msgid "UID:" +msgstr "UID:" -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "Невозможно создать подкласс среза" +#: main.c +msgid "soft reboot\n" +msgstr "Мягкая перезагрузка\n" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "Невозможно использовать GPIO0..15 вместе с GPIO32..47" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c +msgid "%q init failed" +msgstr "Инициализация %q не удалась" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" msgstr "" -"Невозможно проснуться по изменению логического уровня, только по уровню" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." -msgstr "Невозможно проснуться по спаду росту на пине. Только по уровню." +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "%q вне диапазона" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "ХарактеристикаЗапись в буфер не предусмотрена" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" +msgstr "Неверное состояние" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "Основной код CircuitPython сильно разбился. Упс!\n" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "Источник тактирования уже используется" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -"Соединение было отключено и больше не может использоваться. Создайте новое " -"соединение." -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" -msgstr "Координатные массивы имеют разные длины" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "Для управления потоком требуется как RX так и TX" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" -msgstr "Типы массивов координат имеют разные размеры" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "Не удалось выделить буфер %q" -#: shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "Не удалось задать адрес" - -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "Не удалось запустить прерывание, RX занят" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "Все периферийные устройства UART уже используются" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "Не удалось выделить место для декодера" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "Недопустимый %q" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" -msgstr "Ошибка инициализации канала DAC" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "Все каналы событий синхронизации уже используются" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Device Init Error" -msgstr "Ошибка инициализации устройства DAC" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "Внутренний звуковой буфер слишком мал" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC уже используется" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "Калибровка доступна только для чтения" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "Пин data 0 должен быть байтово выровнен" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" +msgstr "Калибровка выходит за пределы допустимого диапазона" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" -msgstr "Ошибка формата данных (возможно, данные повреждены)" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "Вы нажали обе кнопки при запуске." -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "Данные не поддерживаются направленным объявлением" +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "Все таймеры уже используются" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "Данные слишком велики для пакета объявления" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" +msgstr "Используемые внутренние ресурсы" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "" -"Выводы глубокого сна должны использовать сигнал по возрастанию с подтяжкой к " -"земле" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." +msgstr "Причина неизвестна." -#: shared-bindings/audiobusio/PDMIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "Емкость места назначения меньше длины места назначения." +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" +msgstr "Можно установить только один будильник" -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" -msgstr "Ошибка устройства или неправильное завершение входного потока" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" +msgstr "DAC отсутствует на чипе" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "Устройство используется" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" +msgstr "%q и %q должны иметь общую единицу тактового генератора" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "Дисплей должен иметь 16 битное цветовое пространство." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" +msgstr "Сериализатор используется" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display rotation must be in 90 degree increments" -msgstr "Поворот дисплея должен осуществляться с шагом 90 градусов" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "Источник тактирования уже используется" -#: main.c -msgid "Done" -msgstr "Выполнено" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" +msgstr "Свободные GCLK отсутствуют" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Drive mode not used when direction is input." -msgstr "Режим движения не используется при вводе направления." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" +msgstr "Слишком много каналов в выборке" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "" -"При обращении с вышеуказанным исключением произошло еще одно исключение:" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" +msgstr "Канал DMA не найден" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB работает только с 16 байтами за раз" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" +msgstr "Не удается выделить буферы для подписанного преобразования" -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -msgid "ESP-IDF memory allocation failed" -msgstr "Ошибка выделения памяти ESP-IDF" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." +msgstr "Поддерживается только 8 или 16-битное моно с передискретизацией %dx." -#: extmod/modre.c -msgid "Error in regex" -msgstr "Ошибка в регулярном выражении" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" +msgstr "Частота дискретизации выходит за пределы допустимого диапазона" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "Ошибка в сейфе. py." +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC уже используется" -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" -msgstr "Ожидаемый вид %q" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" +msgstr "Правый канал не поддерживается" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." -msgstr "Расширенные объявления с ответом сканирования не поддерживаются." +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "Все каналы событий уже используются" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "FFT определено только для массивов ndarrays" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "На SDA или SCL не обнаружено подтягивания; проверь свою проводку" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "FFT реализовано только для линейных массивов" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q должен быть во 2-й степени" -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "Не удалось отправить команду." +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "Нет пина %q" -#: ports/nordic/sd_mutex.c +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "Все RX FIFO уже используются" + +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "Уже есть универсальный слушатель" + +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" +msgstr "Фильтры слишком сложные" + +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "Невозможно получить pull в режиме вывода" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "Не удалось получить mutex, ошибка 0x%04x" +msgid "Invalid data_pins[%d]" +msgstr "Неверный data_pins[%d]" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" -msgstr "Не удалось добавить служебную запись TXT" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" +msgstr "data-пин #%d уже используется" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" -msgstr "" -"Не удалось добавить служебную TXT-запись; в txt_records обнаружена нестрока " -"или байт" +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" +msgstr "Недопустимый пин %q" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" -msgstr "Не удалось выделить буфер %q" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "Отсутствует загрузчик" -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" -msgstr "Не удалось выделить память Wifi" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "Пин data 0 должен быть байтово выровнен" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" -msgstr "Не удалось выделить память для сканирования wifi" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "Вывод шины %d уже используется" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" -msgstr "Не удалось выполнить буферизацию образца" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" +msgstr "Всплывающее окно из пустого %q" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "Не удалось подключиться: внутренняя ошибка" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" +msgstr "Ввод занимает слишком много времени" + +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "Другая передача уже активна" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/socketpool/SocketPool.c +msgid "%q failure: %d" +msgstr "%q сбой: %d" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "Не удалось подключиться: таймаут" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/audiocore/WaveFile.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/floppyio/__init__.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" +msgstr "Буфер должен быть кратен %d байт" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" -msgstr "" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" +msgstr "Инициализация UART" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "Иницализация камеры" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "Размер не поддерживается" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "Слишком маленький буфер" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "Не удалось распарсить файл MP3" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "Формат не поддерживается" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" -msgstr "" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" +msgstr "Инициализация GNSS" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "Не удалось освободить mutex, ошибка 0x%04x" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" +msgstr "Инициализация SD-карты" -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" -msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "Уже запущен" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" -msgstr "" +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q является %q" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" -msgstr "" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "Вы нажали кнопку SW38 при запуске." -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." -msgstr "Не удалось записать внутреннюю флэш-память." +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "При запуске вы нажали кнопку BOOT." -#: py/moderrno.c -msgid "File exists" -msgstr "Файл существует" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." +msgstr "Вы нажали кнопку GPIO0 при запуске." -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c -msgid "File not found" -msgstr "Файл не найден" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "Вы нажали кнопку «Запись» при запуске." -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" -msgstr "Фильтры слишком сложные" +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "Вы нажали кнопку ГРОМКОСТЬ при запуске." -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "Прошивка дублируется" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "Вы нажали центральную кнопку при запуске." -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "Недопустимая прошивка" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." +msgstr "Вы нажали кнопку A при запуске." + +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "Вы нажали кнопку ВНИЗ при запуске." +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "Прошивка слишком большая" +msgid "Update failed" +msgstr "Обновление не удалось" -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "" -"Для цветового пространства L8 входное растровое изображение должно иметь 8 " -"бит на пиксель" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." +msgstr "Сканирование уже выполняется. Остановитесь на stop_scan." -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "" -"Для цветовых пространств RGB входное растровое изображение должно иметь 16 " -"бит на пиксель" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "Не удалось подключиться: внутренняя ошибка" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "Формат не поддерживается" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "Данные слишком велики для пакета объявления" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" -msgstr "" -"Частота должна быть 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 или 1008 " -"МГц" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "Уже реклама." -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "Функция требует блокировки" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." +msgstr "Расширенные объявления с ответом сканирования не поддерживаются." -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "Инициализация GNSS" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "Данные не поддерживаются направленным объявлением" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" -msgstr "Общий сбой" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgstr "Таймаут слишком длинный: максимальная длина таймаута %d секунд" -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "Группа уже используется" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "Длина значения! = требуемая фиксированная длина" -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "Жесткая ошибка: доступ к памяти или ошибка инструкции." +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "Длина значения > максимальная_длина" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "Оборудование используется, попробуйте использовать другие пины" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Service.c +msgid "Too many %q" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." -msgstr "Выделение кучи, когда виртуальная машина не запущена." +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" +msgstr "Для этой характеристики нет CCCD" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "Операция ввода-вывода на закрытом файле" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "Невозможно установить CCCD для локальной характеристики" -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "Ошибка инициализации I2C" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" +msgstr "Не подключено" -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "Периферийное устройство I2C уже используется" +#: ports/espressif/common-hal/_bleio/Connection.c +msgid "No pairing in progress" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" +msgstr "не-UUID найден в сервисе_uuids_белый список" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "Элементы буфера должны быть длиной <= 4 байта" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "максимальная_длина должна быть 0-%d когда фиксированная длина %s" -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "Неправильный размер буфера" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" +msgstr "Запись не поддерживается в Характеристика" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "Неверный размер программы инициализации" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" +msgstr "Общее количество данных для записи превышает %q" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "" -"Исходное установленное направление штифта конфликтует с исходным " -"направлением вывода" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" +msgstr "Изображение памяти" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" -msgstr "" -"Исходное установленное состояние контакта конфликтует с исходным состоянием " -"выхода" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" +msgstr "Недопустимый параметр BLE" -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "Длина входного буфера (%d) должна быть кратна количеству цепочек (%d)" +#: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Already in progress" +msgstr "Уже в процессе" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" -msgstr "Ввод занимает слишком много времени" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" +msgstr "Неизвестная системная ошибка прошивки на %s:%d: %d" -#: py/moderrno.c -msgid "Input/output error" -msgstr "Ошибка ввода/вывода" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" +msgstr "Неизвестная ошибка прошивки системы: %d" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c @@ -1249,569 +1295,667 @@ msgstr "Неполная аутентификация" msgid "Insufficient encryption" msgstr "Недостаточное шифрование" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" -msgstr "Недостаточный объем памяти для изображения" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "Неизвестная ошибка BLE в %s:%d: %d" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" -msgstr "Недостаточный буфер ввода потока" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" +msgstr "Неизвестная ошибка BLE: %d" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "Интерфейс должен быть запущен" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "Невозможно проснуться по спаду росту на пине. Только по уровню." -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "Внутренний звуковой буфер слишком мал" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "Невозможно вытащить контакт только для ввода." -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" -msgstr "Внутренняя ошибка определения" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." +msgstr "" +"Из глубокого сна может сигнализировать только по двум низким контактам." -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c -msgid "Internal error" -msgstr "Внутренняя ошибка" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." +msgstr "" +"Может сигнализировать только по одному низкому контакту в то время как " +"другие сигнализируют о высоком уровне после глубокого сна." -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" -msgstr "Внутренняя ошибка #%d" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "Возможен только сигнал тревоги по RTC IO из глубокого сна." -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" -msgstr "Используемые внутренние ресурсы" +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." +msgstr "Можно установить только один будильник alarm.time." -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "Внутренний сторожевой таймер истек." +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." +msgstr "Только один %q может быть переведен в режим глубокого сна." -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "Прерванная ошибка." +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "%q должен быть массивом типа 'H \"" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" -msgstr "Прерывается функцией выхода" +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" -msgstr "Недопустимый %q" +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c shared-bindings/emmcio/EMMC.c +msgid "Peripheral in use" +msgstr "Периферийные устройства в использовании" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" -msgstr "Недопустимые %q и %q" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "Недопустимый пин %q" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" +msgstr "" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "Недопустимое значение единицы ADC" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "Недопустимый параметр BLE" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "Неверный BSSID" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "Неверный MAC-адрес" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" +msgstr "" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "Все периферийные устройства I2C уже используются" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" +msgstr "Не удается создать блокировку" + +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" +msgstr "Сбой конфигурации SPI" + +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "Все периферийные устройства SPI уже используются" + +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "Ошибка выделения памяти ESP-IDF" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "Невозможно указать RTS или CTS в режиме RS485" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" +msgstr "Инверсия RS485 указана, когда она не находится в режиме RS485" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" -msgstr "" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "Скорость передачи данных не поддерживается периферийным устройством" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "Недопустимый аргумент" +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "Все периферийные устройства CAN уже используются" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" -msgstr "Недопустимое бит-на-значение" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" +msgstr "" +"Замыкание на себя + бесшумный режим, не поддерживаемый периферийными " +"устройствами" -#: shared-module/os/getenv.c +#: ports/espressif/common-hal/canio/CAN.c #, c-format -msgid "Invalid byte %.*s" -msgstr "Неверный байт %.*s" +msgid "twai_driver_install returned esp-idf error #%d" +msgstr "twai_driver_install вернул ошибку esp-idf #%d" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: ports/espressif/common-hal/canio/CAN.c #, c-format -msgid "Invalid data_pins[%d]" -msgstr "Неверный data_pins[%d]" +msgid "twai_start returned esp-idf error #%d" +msgstr "twai_start вернул ошибку esp-idf #%d" -#: shared-module/msgpack/__init__.c -msgid "Invalid format" -msgstr "Недопустимый формат" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" +msgstr "Должен иметь 5/6/5 контактов RGB" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "Неверный размер блока формата" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" +msgstr "Прошивка дублируется" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" -msgstr "Неверный шестнадцатеричный пароль" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "Недопустимая прошивка" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "Неверный MAC-адрес многоадресной рассылки" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "Прошивка слишком большая" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "Неверный размер" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" +msgstr "нет такого атрибута" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "Неверный сокет для TLS" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" +msgstr "Недопустимый параметр" -#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" -msgstr "Неверное состояние" +msgid "Generic Failure" +msgstr "Общий сбой" -#: shared-module/os/getenv.c -msgid "Invalid unicode escape" -msgstr "Недопустимое экранирование Юникода" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" +msgstr "Не хватает памяти" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "Ключ должен быть длинной 16, 24 или 32 байта" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "Недопустимый аргумент" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "Ключ не найден" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "Неверный размер" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "Светодиодные сопоставления должны соответствовать размеру дисплея" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" +msgstr "Запрошенный ресурс не найден" -#: py/compile.c -msgid "LHS of keyword arg must be an id" -msgstr "LHS ключевого слова arg должен быть идентификатором(id)" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c +#: shared-bindings/picogame/__init__.c +msgid "Operation or feature not supported" +msgstr "Операция или функция, не поддерживаемые" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "Слой уже в группе (Group)" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" +msgstr "Истекло время ожидания операции" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "Слой должен быть группой (Group) или субклассом TileGrid" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" +msgstr "Полученный ответ недействителен" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" -msgstr "Длина %q должна быть четной, кратной количеству каналов * размер_типа" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC или контрольная сумма неправильная" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" +msgstr "Версия была недействительной" #: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "MAC адрес был недействительным" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" -msgstr "Защита от MITM не поддерживается" - -#: ports/stm/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format -msgid "MMC/SDIO Clock Error %x" -msgstr "" - -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" -msgstr "Сопоставление должно быть кортежом" - -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" -msgstr "Размер данных различается" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" -msgstr "Несоответствующий флаг подкачки" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "Отсутствует first_in_pin. %q[%u] читает выводы" +msgid "%s error 0x%x" +msgstr "%s ошибка 0x%x" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "Отсутствует first_in_pin. %q[%u] смещается от контакта (контактов)" +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" +msgstr "Слишком длинная программа" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "Отсутствует first_in_pin. Инструкция %d ожидает на основе пина" +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q используется" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "Отсутствует first_out_pin. %q[%u] переключается на контакты" +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." +msgstr "Можно установить только один %q." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "Отсутствует first_out_pin. %q[%u] записывает выводы" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" +msgstr "Разрешен только один адрес" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "Отсутствует first_set_pin. %q[%u] устанавливает контакты" +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" +msgstr "Неизвестный код ошибки %d" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "Не хватает jmp_pin.%q [%u] прыгает на пин" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" +msgstr "mDNS работает только со встроенным WiFi" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" -msgstr "Отсутствует каталог точки монтирования" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" +msgstr "mDNS уже инициализирован" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." -msgstr "Должен быть субклассом %q." +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" +msgstr "Не удается запустить запрос mDNS" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" -msgstr "Должен иметь 5/6/5 контактов RGB" +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "Диапазон адресов не разрешен" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" -msgstr "Пин MISO или MOSI должен быть предоставлен" +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" +msgstr "Ошибка NVS" -#: shared-bindings/rgbmatrix/RGBMatrix.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c #, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" -msgstr "Количество используемых rgb-пинов должно быть кратно 6, а не %d" +msgid "Number of data_pins must be %d or %d, not %d" +msgstr "Количество выводов_данных должно быть %d или %d, а не %d" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." -msgstr "Прыжок NLR не удался. Вероятно повреждение памяти." +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" +msgstr "вытолкнуть из пустого импульсного входа" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" -msgstr "Ошибка NVS" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" -msgstr "Имя или услуга не известны" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "Внутренняя ошибка" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -"Новое растровое изображение должно быть того же размера, что и старое " -"растровое изображение" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" -msgstr "Изображение памяти" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "Нет пина %q" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "Для этой характеристики нет CCCD" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "No DAC on chip" -msgstr "DAC отсутствует на чипе" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA channel found" -msgstr "Канал DMA не найден" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" -msgstr "Таймер стимуляции DMA не найден" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "No I2C device at address: 0x%x" -msgstr "Нет устройства I2C по адресу: %x" +msgid "SDIO Init Error 0x%02x" +msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "Нет IP" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" +msgstr "Неподдерживаемый тип сокета" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" -msgstr "Отсутствует загрузчик" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" +msgstr "Вне розеток" -#: shared-module/usb/core/Device.c -msgid "No configuration set" -msgstr "Нет конфигураций" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" +msgstr "SocketPool можно использовать только с wifi.radio" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" -msgstr "Нет соединения: длина не может быть определена" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "%q должно быть <= %u" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" -msgstr "Нет шины %q по умолчанию" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" +msgstr "Сбой инициализации монитора" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" -msgstr "Свободные GCLK отсутствуют" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "Интерфейс должен быть запущен" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" -msgstr "Отсутствует аппаратный генератор случайных чисел" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "Неверный MAC-адрес многоадресной рассылки" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" -msgstr "Нет в программе" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "Поиск сетей wifi уже происходит" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" -msgstr "В программе отсутствует ввод или вывод" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" +msgstr "" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" -msgstr "Нет поддержки длинных целых чисел (long integer)" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" +msgstr "Не удалось выделить память для сканирования wifi" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "Нет сети с этим ssid" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" +msgstr "Не удалось выделить память Wifi" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" -msgstr "В программе отсутствует вывод" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Only IPv4 addresses supported" +msgstr "Поддерживаются только адреса IPv4" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "На SDA или SCL не обнаружено подтягивания; проверь свою проводку" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" +msgstr "Пин MISO или MOSI должен быть предоставлен" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" -msgstr "Отсутствует подтяжка к земле на пине; Рекомендуется 1 Мегаом" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +#: shared-bindings/emmcio/EMMC.c +msgid "Hardware in use, try alternative pins" +msgstr "Оборудование используется, попробуйте использовать другие пины" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: py/moderrno.c -msgid "No space left on device" -msgstr "На устройстве не осталось свободного места" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +msgstr "" +"Частота должна быть 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 или 1008 " +"МГц" -#: py/moderrno.c -msgid "No such device" -msgstr "Нет такого устройства" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." +msgstr "Вы нажали левую кнопку при запуске." -#: py/moderrno.c -msgid "No such file/directory" -msgstr "Файл/директория не существует" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" +msgstr "таймаут должен быть < 655.35 сек" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" -msgstr "Нет доступного таймера" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" +msgstr "Ненулевое время ожидания должно быть > 0,01" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" -msgstr "Порт USB-хоста не инициализирован" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "Не удалось подключиться: таймаут" + +#: ports/nordic/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "Numeric comparison pairing" +msgstr "" + +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" +msgstr "Неожиданный тип nrfx uuid" #: ports/nordic/common-hal/_bleio/__init__.c msgid "Nordic system firmware out of memory" msgstr "Скандинавская система прошивки из памяти" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" -msgstr "Недействительная строка IP" - -#: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" -msgstr "Не подключено" +#, c-format +msgid "Unknown system firmware error: %04x" +msgstr "Неизвестная системная ошибка прошивки: %04x" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c -msgid "Not playing" -msgstr "Не воспроизводится (Not playing)" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" +msgstr "Неизвестная ошибка gatt: 0x%04x" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "Не поддерживается Стандарт JPEG" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "" +"Unspecified issue. The pairing request on the other device may have been " +"declined or ignored." +msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c #, c-format -msgid "Number of data_pins must be %d or %d, not %d" -msgstr "Количество выводов_данных должно быть %d или %d, а не %d" +msgid "Unknown security error: 0x%04x" +msgstr "Неизвестная ошибка безопасности: 0x%04x" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" msgstr "" -"Объект был деинициализирован и больше не может быть использован. Создайте " -"новый объект." +"Невозможно проснуться по изменению логического уровня, только по уровню" + +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "Устройство используется" + +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "только образец_рейт=16000 поддерживается" + +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "поддерживается только бит_глубина=16" + +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" +msgstr "ошибка = 0x%08lX" #: ports/nordic/common-hal/busio/UART.c msgid "Odd parity is not supported" msgstr "Нечетная четность не поддерживается" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" -msgstr "Выключено" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "Все каналы уже используются" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" -msgstr "Да" +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "Невозможно получить температуру" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." -msgstr "Поддерживается только 8 или 16-битное моно с передискретизацией %dx." +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" +msgstr "" +"Продолжительность таймаута превысила максимальное поддерживаемое значение" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" -msgstr "Поддерживаются только адреса IPv4" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" +msgstr "%q не может быть изменен после установки режима на %q" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" -msgstr "Поддерживаются только сокеты IPv4" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +msgstr "" +"Сторожевой таймер не может быть деинициализирован, если установлен режим " +"RESET" -#: shared-module/displayio/OnDiskBitmap.c +#: ports/nordic/sd_mutex.c #, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" -msgstr "" -"Поддерживается только формат Windows, несжатый BMP: заданный размер " -"заголовка - %d" +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "Не удалось получить mutex, ошибка 0x%04x" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" -msgstr "Только подключаемые объявления могут быть направлены" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "Не удалось освободить mutex, ошибка 0x%04x" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" -msgstr "На этом аппаратном обеспечении доступно только обнаружение края" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "Преобразование звука не реализовано" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" -msgstr "Для IP поддерживаются только int или строка" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/__init__.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q должно быть типа%q или%q, а не%q" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." -msgstr "Только один %q может быть переведен в режим глубокого сна." +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" +msgstr "Недопустимый размер программы" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." -msgstr "Можно установить только один %q." +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "Неверный размер программы инициализации" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" -msgstr "Разрешен только один адрес" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "Элементы буфера должны иметь длину не более 4 байт" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" -msgstr "Можно установить только один будильник" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" +msgstr "Размер данных различается" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." -msgstr "Можно установить только один будильник alarm.time." +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" +msgstr "Элементы вне буфера должны иметь длину <= 4 байта" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" -msgstr "Только один цвет может быть прозрачным одновременно" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "Элементы буфера должны быть длиной <= 4 байта" -#: py/moderrno.c -msgid "Operation not permitted" -msgstr "Операция не разрешена" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "Функция требует блокировки" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" -msgstr "Операция или функция, не поддерживаемые" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "Буферные фрагменты должны быть одинаковой длины" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation timed out" -msgstr "Истекло время ожидания операции" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" +msgstr "Сенсорные сигналы недоступны" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" -msgstr "Отсутствуют сервисные слоты MDNS" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "Невозможно использовать GPIO0..15 вместе с GPIO32..47" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" -msgstr "Не хватает памяти" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "Несколько часов и слов должны быть последовательными GPIO пинами" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" -msgstr "Вне розеток" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." +msgstr "Слишком много каналов в выборке." -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" -msgstr "Элементы вне буфера должны иметь длину <= 4 байта" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" +msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" -msgstr "PWM перезагрузка" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" +msgstr "Пины должны иметь общий срез PWM" + +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" +msgstr "Таймер стимуляции DMA не найден" + +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "Периферийное устройство I2C уже используется" + +#: ports/raspberrypi/common-hal/busio/SPI.c shared-bindings/emmcio/EMMC.c +msgid "SPI peripheral in use" +msgstr "Используемое периферийное устройство SPI" + +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" +msgstr "Используемое периферийное устройство UART" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "Пин должен быть на канале ШИМ B" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" +msgstr "RISE_AND_FALL недоступен на этом чипе" #: ports/raspberrypi/common-hal/countio/Counter.c msgid "PWM slice already in use" @@ -1821,96 +1965,110 @@ msgstr "PWM уже используется" msgid "PWM slice channel A already in use" msgstr "PWM канал среза A уже используется" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." -msgstr "" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "Все машины состояний уже используются" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" -msgstr "Ошибка параметра" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" +msgstr "таймаут ожидания потока" -#: ports/espressif/common-hal/audiobusio/__init__.c -msgid "Peripheral in use" -msgstr "Периферийные устройства в использовании" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" +msgstr "таймаут ожидания индексного импульса" -#: py/moderrno.c -msgid "Permission denied" -msgstr "Отказано в разрешении" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" +msgstr "Пины должны быть последовательными" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" -msgstr "Пин не может вывести из глубокого сна" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" +msgstr "Недопустимые %q и %q" + +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" +msgstr "Не удалось добавить служебную запись TXT" + +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" +msgstr "Отсутствуют сервисные слоты MDNS" + +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" +msgstr "Невозможно получить доступ к невыровненному регистру ввода-вывода" + +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" +msgstr "Невозможно записать в постоянную память" + +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "Все таймеры для этого пина уже используются" + +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q должно быть типа %q, а не %q" + +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" +msgstr "Пины должны быть последовательными выводами GPIO" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Pin count too large" msgstr "Слишком большое количество пинов" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" -msgstr "Прерывание пина уже используется" - -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" -msgstr "Пин является только входом" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" -msgstr "Пин должен быть на канале ШИМ B" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" -msgstr "" -"Распиновка использует %d байт на элемент, что превышает идеальное %d байт. " -"Если этого нельзя избежать, передайте конструктору allow_inefficient=True" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" +msgstr "Не хватает jmp_pin.%q [%u] прыгает на пин" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" -msgstr "Пины должны быть последовательными" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "%q[%u] использует дополнительный контакт" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" -msgstr "Пины должны быть последовательными выводами GPIO" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" +msgstr "Отсутствует first_in_pin. Инструкция %d ожидает на основе пина" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" -msgstr "Пины должны иметь общий срез PWM" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" +msgstr "%q [%u] ожидает ввода за пределами графа" -#: shared-module/usb/core/Device.c -msgid "Pipe error" -msgstr "Ошибка трубопровода" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +msgstr "Отсутствует first_in_pin. %q[%u] смещается от контакта (контактов)" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "Плюс любые модули в файловой системе\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" +msgstr "%q [%u] смещается в большем количестве чем количество пинов" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" -msgstr "Полигону необходимо как минимум 3 точки" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "Отсутствует first_out_pin. %q[%u] переключается на контакты" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." -msgstr "" -"Мощность просела. Убедитесь, что вы обеспечиваете достаточную мощность." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "%q[%u] смещает больше битов чем количество выводов" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" -msgstr "Буфер префикса должен находиться в куче" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "Отсутствует first_set_pin. %q[%u] устанавливает контакты" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" -msgstr "" -"Нажмите любую клавишу чтобы зайти в REPL. Используйте CTRL-D для " -"перезагрузки.\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "Отсутствует first_out_pin. %q[%u] записывает выводы" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "" -"Притворяюсь глубоким сном до сигнала тревоги, CTRL-C или записи файла.\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" +msgstr "Отсутствует first_in_pin. %q[%u] читает выводы" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" @@ -1920,2735 +2078,2833 @@ msgstr "Программа выполняет IN без загрузки ISR" msgid "Program does OUT without loading OSR" msgstr "Программа выполняет ВЫХОД без загрузки OSR" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" -msgstr "Недопустимый размер программы" - -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" -msgstr "Слишком длинная программа" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" +msgstr "" +"Исходное установленное состояние контакта конфликтует с исходным состоянием " +"выхода" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" msgstr "" +"Исходное установленное направление штифта конфликтует с исходным " +"направлением вывода" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Pull not used when direction is output." -msgstr "Тяга не используется, когда выводится направление." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" +msgstr "Маски вытягивания конфликтуют с масками направления" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" -msgstr "RISE_AND_FALL недоступен на этом чипе" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" +msgstr "В программе отсутствует вывод" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" -msgstr "RLE-сжатый BMP не поддерживается" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" +msgstr "Нет в программе" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" -msgstr "Ошибка деинициализации генератора случайных чисел" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" +msgstr "В программе отсутствует ввод или вывод" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" -msgstr "Ошибка инициализации RNG" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" +msgstr "Несоответствующий флаг подкачки" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" -msgstr "" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" +msgstr "Поддерживаются только сокеты IPv4" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" -msgstr "" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "Все используемые каналы dma" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" +msgstr "Wi-Fi. Монитор недоступен" + +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q читается только для этой доски" + +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "AP не может быть запущен" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" +msgstr "На этом аппаратном обеспечении доступно только обнаружение края" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" +msgstr "Прерывание пина уже используется" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" +msgstr "Пин не может вывести из глубокого сна" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" +"Выводы глубокого сна должны использовать сигнал по возрастанию с подтяжкой к " +"земле" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "Недопустимое значение единицы ADC" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" -msgstr "Инверсия RS485 указана, когда она не находится в режиме RS485" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "Ошибка инициализации устройства DAC" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" -msgstr "RTC не поддерживается на этой плате" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "Ошибка инициализации канала DAC" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" -msgstr "Ошибка генерации случайных чисел" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" +msgstr "Поддерживается только моно" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" -msgstr "Только для чтения" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" +msgstr "поддерживается только выборка = 64" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" -msgstr "Файловая система только для чтения" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "Другой аудиовыход PWM уже активен" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" -msgstr "Полученный ответ недействителен" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "Размер буфера %d слишком большой. Он должен быть меньше чем %d" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" +msgstr "Не удалось выполнить буферизацию образца" + +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "Ошибка инициализации I2C" + +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" +msgstr "Ошибка инициализации SPI" + +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" +msgstr "Повторная инициализация SPI" + +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" +msgstr "Внутренняя ошибка определения" + +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "Не удалось запустить прерывание, RX занят" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" -msgstr "Повторное соединение" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" +msgstr "Запись UART" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" -msgstr "Слишком раннее обновление" +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" +msgstr "Деинициализация UART" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" -msgstr "Запросы на удаленную передачу ограничены 8 байтами" +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" +msgstr "Повторная инициализация UART" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" -msgstr "Запрошенный режим AES не поддерживается" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" +msgstr "Истекло время ожидания считывания температуры" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" -msgstr "Запрошенный ресурс не найден" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" +msgstr "Истекло время ожидания считывания напряжения" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" -msgstr "Правый канал не поддерживается" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" +msgstr "Ошибка инициализации RNG" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" -msgstr "Правильный формат, но не поддерживается" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" +msgstr "Ошибка генерации случайных чисел" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" -msgstr "Работает в безопасном режиме! Сохраненный код не выполняется.\n" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" +msgstr "Ошибка деинициализации генератора случайных чисел" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" -msgstr "Формат CSD SD-карты не поддерживается" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" +msgstr "Повторное инициализация таймера" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" -msgstr "Инициализация SD-карты" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" +msgstr "Реинициализация канала" + +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" +msgstr "PWM перезагрузка" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "SDIO GetCardInfo Error %d" -msgstr "Ошибка получения информации о карте SDIO %d" +msgid "MMC/SDIO Clock Error %x" +msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "SDIO Init Error %x" -msgstr "Ошибка инициализации SDIO %x" - -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" -msgstr "Сбой конфигурации SPI" - -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" -msgstr "Ошибка инициализации SPI" - -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" -msgstr "" +msgid "SDIO GetCardInfo Error %d" +msgstr "Ошибка получения информации о карте SDIO %d" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" -msgstr "Используемое периферийное устройство SPI" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" +msgstr ". Показать(x) удален. Используйте . корневую_группу = x" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" -msgstr "Повторная инициализация SPI" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "Яркость не регулируется" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" -msgstr "Размеры шкалы необходимо разделить на 3" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." -msgstr "Сканирование уже выполняется. Остановитесь на stop_scan." - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" -msgstr "Сериализатор используется" - -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" -msgstr "Контекст на стороне сервера не может иметь имя хоста" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q должно быть %d-%d" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" -msgstr "Размер не поддерживается" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "Группа уже используется" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." -msgstr "Нарежьте и оцените разную длину." +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" -msgstr "Фрагменты не поддерживаются" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c #: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" -msgstr "SocketPool можно использовать только с wifi.radio" +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" -msgstr "Исходный и конечный буферы должны иметь одинаковую длину" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "Ошибка USB" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" -msgstr "Укажите точно один из data0 или data_pins" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." -msgstr "Переполнение стека. Увеличьте размер стека." +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "Ниже минимальной частоты кадров" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" -msgstr "Поставьте один из monotonic_time или epoch_time" +#: py/argcheck.c +msgid "function doesn't take keyword arguments" +msgstr "функция не принимает аргументы ключевых слов" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" -msgstr "Системная запись должна быть gnss. Спутниковая система" +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" +msgstr "функция принимает %d позиционные аргументы, но %d были заданы" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" -msgstr "Истекло время ожидания считывания температуры" +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" +msgstr "Функция отсутствует %d обязательные позиционные аргументы" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." -msgstr "" -"Модуль «микроконтроллер» использовался для загрузки в безопасном режиме." +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" +msgstr "функция, ожидаемая в большинстве %d аргументов, получила %d" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" -msgstr "" -"Вышеупомянутое исключение было непосредственной причиной следующего " -"исключения:" +#: py/argcheck.c shared-bindings/wifi/Radio.c +msgid "'%q' argument required" +msgstr "Требуется аргумент '%q'" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" -msgstr "Длина rgb_pins должна быть 6, 12, 18, 24 или 30" +#: py/argcheck.c +msgid "extra positional arguments given" +msgstr "Приведены дополнительные позиционные аргументы" -#: shared-module/audiocore/__init__.c -msgid "The sample's %q does not match" -msgstr "%q образца не совпадает" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" +msgstr "неожиданный аргумент ключевого слова '%q'" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." -msgstr "Неустранимая ошибка прошивки стороннего производителя." +#: py/argcheck.c +msgid "extra keyword arguments given" +msgstr "Приведены дополнительные аргументы ключевых слов" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." -msgstr "Этот микроконтроллер не поддерживает непрерывный захват." +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c +msgid "argument num/types mismatch" +msgstr "Аргумент Несоответствие числа/типов" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -"Этот микроконтроллер поддерживает только data0=, а не data_pins=, поскольку " -"для него требуются смежные выводы." +"Аргумент(ы) ключевого слова не реализован - используйте вместо него обычные " +"аргументы" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" -msgstr "Высота плитки должна точно делить высоту растрового изображения" +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q должно быть %d" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" -msgstr "Выход индекса плитки за пределы" +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "%q должно быть >= %d" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" -msgstr "Ширина плитки должна точно делить ширину растрового изображения" +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "%q должно быть <= %d" + +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "Длинна %q должна быть %d-%d" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "Длинна %q должна быть >= %d" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." -msgstr "Время в прошлом." +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "Длинна %q должна быть <= %d" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "Таймаут слишком длинный: максимальная длина таймаута %d секунд" +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "Длинна %q должна быть %d" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" -msgstr "" +#: py/argcheck.c shared-module/audiofilters/__init__.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q в %q должно быть типа %q, а не %q" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" -msgstr "Слишком много каналов в выборке" +#: py/asmthumb.c +msgid "too many locals for native method" +msgstr "Слишком много местных жителей для нативного метода" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample." -msgstr "Слишком много каналов в выборке." +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" -msgstr "Слишком много дескрипторов" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" -msgstr "Слишком много шин дисплея; забыл displayio.release_displays()?" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q() принимает %d позиционных аргументов, но было передано %d" -#: shared-module/displayio/__init__.c -msgid "Too many displays" -msgstr "Слишком много дисплеев" +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" +msgstr "функция имеет несколько значений для аргументации%q \"" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" -msgstr "Общее количество данных для записи превышает %q" +#: py/bc.c +msgid "unexpected keyword argument" +msgstr "Неожиданный аргумент ключевого слова" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" -msgstr "Сенсорные сигналы недоступны" +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" +msgstr "В функции отсутствует обязательный позиционный аргумент #%d" -#: py/obj.c -msgid "Traceback (most recent call last):\n" -msgstr "Трассировка (последний вызов):\n" +#: py/bc.c +msgid "function missing required keyword argument '%q'" +msgstr "В функции отсутствует обязательный аргумент ключевого слова '%q'" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" -msgstr "Деинициализация UART" +#: py/bc.c +msgid "function missing keyword-only argument" +msgstr "функция отсутствует аргумент только по ключевому слову" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" -msgstr "Инициализация UART" +#: py/binary.c py/objarray.c +msgid "bad typecode" +msgstr "Неверный шрифт" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: py/binary.c +msgid "integer out of range" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" -msgstr "Используемое периферийное устройство UART" +#: py/builtinevex.c +msgid "bad compile mode" +msgstr "Неверный режим компиляции" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" -msgstr "Повторная инициализация UART" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" +msgstr "Плюс любые модули в файловой системе\n" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" -msgstr "" +#: py/builtinhelp.c +msgid "object " +msgstr "объект " -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " имеет тип %q\n" + +#: py/builtinhelp.c +#, c-format +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" +"Добро пожаловать в Adafruit CircuitPython %s! \n" +"\n" +"Посетите circuitpython.org для получения дополнительной информации. \n" +"\n" +"Чтобы получить список встроенных модулей, введите 'help(\"modules\")'.\n" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" -msgstr "Запись UART" +#: py/builtinimport.c +msgid "script compilation not supported" +msgstr "Компиляция скриптов не поддерживается" -#: main.c -msgid "UID:" -msgstr "UID:" +#: py/builtinimport.c +msgid "can't perform relative import" +msgstr "Не удается выполнить относительный импорт" -#: shared-module/usb_hid/Device.c -msgid "USB busy" -msgstr "USB занят" +#: py/builtinimport.c +msgid "module not found" +msgstr "модуль не найден" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." -msgstr "USB-устройствам требуется больше конечных точек, чем доступно." +#: py/builtinimport.c +msgid "no module named '%q'" +msgstr "Нет модуля с именем '%Q'" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." -msgstr "USB-устройства указывают слишком много имен интерфейсов." +#: py/builtinimport.c +msgid "relative import" +msgstr "Относительный импорт" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "Ошибка USB" +#: py/compile.c +msgid "can't assign to expression" +msgstr "Не удается назначить выражение" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "Целое значение UUID должно быть равно 0-0xffff" +#: py/compile.c +msgid "multiple *x in assignment" +msgstr "Несколько *x в назначении" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" -msgstr "UUID строка не 'xxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxxx \"" +#: py/compile.c +msgid "non-default argument follows default argument" +msgstr "" +"Аргумент отличный от аргумента по умолчанию следует за аргументом по " +"умолчанию" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" -msgstr "Значение UUID не является строковым, целым или байтовым буфером" +#: py/compile.c +msgid "invalid micropython decorator" +msgstr "неверный декоратор микропитона" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" -msgstr "Невозможно получить доступ к невыровненному регистру ввода-вывода" +#: py/compile.c +msgid "invalid arch" +msgstr "недействительная арка" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Unable to allocate buffers for signed conversion" -msgstr "Не удается выделить буферы для подписанного преобразования" +#: py/compile.c +msgid "can't delete expression" +msgstr "Не удается удалить выражение" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." -msgstr "Невозможно выделить место в куче." +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "'прервать'/'продолжить' вне цикла" -#: ports/espressif/common-hal/busio/I2C.c -msgid "Unable to create lock" -msgstr "Не удается создать блокировку" +#: py/compile.c +msgid "'return' outside function" +msgstr "«возврат» внешняя функция" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" -msgstr "Не удается найти дисплей I2C в %x" +#: py/compile.c +msgid "import * not at module level" +msgstr "Импорт * не на уровне модуля" -#: py/parse.c -msgid "Unable to init parser" -msgstr "Не удается инициировать синтаксический анализатор" +#: py/compile.c +msgid "identifier redefined as global" +msgstr "идентификатор переопределен как глобальный" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" -msgstr "Не удается прочитать данные цветовой палитры" +#: py/compile.c +msgid "no binding for nonlocal found" +msgstr "Привязка для нелокальных не найдена" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" +#: py/compile.c +msgid "identifier redefined as nonlocal" +msgstr "идентификатор переопределен как нелокальный" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" -msgstr "Не удается запустить запрос mDNS" +#: py/compile.c +msgid "can't declare nonlocal in outer code" +msgstr "не может объявить нелокальный во внешнем коде" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." -msgstr "Невозможно выполнить запись в nvm." +#: py/compile.c +msgid "default 'except' must be last" +msgstr "по умолчанию \"за исключением\" должно быть последним" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" -msgstr "Невозможно записать в постоянную память" +#: py/compile.c +msgid "async for/with outside async function" +msgstr "async для/вместе с внешней async-функцией" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." -msgstr "Невозможно записать в Sleep_memory." +#: py/compile.c +msgid "*x must be assignment target" +msgstr "*x должно быть целью назначения" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" -msgstr "Неожиданный тип nrfx uuid" +#: py/compile.c +msgid "super() can't find self" +msgstr "super() не может найти себя" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" -msgstr "Неизвестная ошибка BLE в %s:%d: %d" +#: py/compile.c +msgid "* arg after **" +msgstr "* аргумент после **" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" -msgstr "Неизвестная ошибка BLE: %d" +#: py/compile.c +msgid "* arg after kwarg" +msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" -msgstr "Неизвестный код ошибки %d" +#: py/compile.c +msgid "too many args" +msgstr "слишком много аргументов" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" -msgstr "Неизвестный сбой %d" +#: py/compile.c +msgid "LHS of keyword arg must be an id" +msgstr "LHS ключевого слова arg должен быть идентификатором(id)" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" -msgstr "Неизвестная ошибка gatt: 0x%04x" +#: py/compile.c +msgid "positional arg after **" +msgstr "позиционный аргумент после **" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." -msgstr "Причина неизвестна." +#: py/compile.c +msgid "positional arg after keyword arg" +msgstr "позиционный аргумент после ключевого слова аргумента" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" -msgstr "Неизвестная ошибка безопасности: 0x%04x" +#: py/compile.c py/parse.c +msgid "invalid syntax" +msgstr "недействительный синтаксис" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" -msgstr "Неизвестная системная ошибка прошивки на %s:%d: %d" +#: py/compile.c +msgid "expecting key:value for dict" +msgstr "ожидание ключа: значение для дикта" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" -msgstr "Неизвестная системная ошибка прошивки: %04x" +#: py/compile.c +msgid "expecting just a value for set" +msgstr "ожидание только значения для набора" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" -msgstr "Неизвестная ошибка прошивки системы: %d" +#: py/compile.c +msgid "'yield' outside function" +msgstr "внешняя функция \"выход\"" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." -msgstr "" -"Непревзойденное количество элементов на RHS (ожидалось %d, получено %d)." +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "«выход из» внутри асинхронной функции" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." -msgstr "" -"Неуказанная проблема. Возможно, запрос на сопряжение на другом устройстве " -"был отклонен или проигнорирован." +#: py/compile.c +msgid "'await' outside function" +msgstr "«ожидание» внешняя функция" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" -msgstr "Неподдерживаемое цветовое пространство" +#: py/compile.c +msgid "unknown type '%q'" +msgstr "Неизвестный тип '%q'" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" -msgstr "Неподдерживаемый тип шины дисплея" +#: py/compile.c +msgid "annotation must be an identifier" +msgstr "Аннотация должна быть идентификатором" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" -msgstr "Неподдерживаемый алгоритм хеширования" +#: py/compile.c +msgid "argument name reused" +msgstr "Повторное использование имени аргумента" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" -msgstr "Неподдерживаемый тип сокета" +#: py/compile.c +msgid "inline assembler must be a function" +msgstr "Встроенный ассемблер должен быть функцией" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" -msgstr "Обновление не удалось" +#: py/compile.c +msgid "unknown type" +msgstr "Неизвестный тип" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" -msgstr "Длина значения! = требуемая фиксированная длина" +#: py/compile.c +msgid "return annotation must be an identifier" +msgstr "Возвращаемая аннотация должна быть идентификатором" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" -msgstr "Длина значения > максимальная_длина" +#: py/compile.c +msgid "expecting an assembler instruction" +msgstr "Ожидание инструкции ассемблера" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" -msgstr "Версия была недействительной" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "«метка» требует 1 аргумент" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" -msgstr "Истекло время ожидания считывания напряжения" +#: py/compile.c +msgid "label redefined" +msgstr "Метка переопределена" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" -msgstr "ВНИМАНИЕ: Имя файла кода имеет два расширения\n" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "«выравнивание» требует 1 аргумента" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" -msgstr "" -"Сторожевой таймер не может быть деинициализирован, если установлен режим " -"RESET" +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "«данные» требуют как минимум 2 аргумента" -#: py/builtinhelp.c -#, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "«данные» требуют целочисленных аргументов" + +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -"Добро пожаловать в Adafruit CircuitPython %s! \n" -"\n" -"Посетите circuitpython.org для получения дополнительной информации. \n" -"\n" -"Чтобы получить список встроенных модулей, введите 'help(\"modules\")'.\n" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " +#: py/emitbc.c +msgid "bytecode overflow" +msgstr "Переполнение байт-кода" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: main.c -msgid "Woken up by alarm.\n" -msgstr "Проснулся по тревоге.\n" - -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" -msgstr "Запись не поддерживается в Характеристика" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" +msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." -msgstr "Вы нажали обе кнопки при запуске." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" +msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." -msgstr "Вы нажали кнопку A при запуске." +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" +msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." -msgstr "Вы нажали кнопку ВНИЗ при запуске." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" -msgstr "Вы нажали кнопку BOOT при запуске" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" +msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." -msgstr "При запуске вы нажали кнопку BOOT." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" +msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." -msgstr "Вы нажали кнопку GPIO0 при запуске." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" +msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." -msgstr "Вы нажали кнопку «Запись» при запуске." +#: py/emitinlinerv32.c +msgid "opcode '%q': registers must be different" +msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." -msgstr "Вы нажали кнопку SW38 при запуске." +#: py/emitinlinerv32.c +msgid "opcode '%q': malformed register list" +msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." -msgstr "Вы нажали кнопку ГРОМКОСТЬ при запуске." +#: py/emitinlinerv32.c +msgid "opcode '%q': invalid stack adjustment" +msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." -msgstr "Вы нажали центральную кнопку при запуске." +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: wrong register(s)" +msgstr "" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." -msgstr "Вы нажали левую кнопку при запуске." +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." -msgstr "Вы нажали кнопку сброса во время загрузки." +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" +msgstr "может иметь только до 4 параметров для сборки большого пальца" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" -msgstr "[отрезается по длине]" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" +msgstr "Параметры должны быть регистрами в последовательности от r0 до r3" -#: py/objtype.c -msgid "__init__() should return None" -msgstr "__init__() должен возвращать значение None" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s' ожидает не более r%d" -#: py/objtype.c +#: py/emitinlinethumb.c py/emitinlinextensa.c #, c-format -msgid "__init__() should return None, not '%s'" -msgstr "__init__() должна возвращать Нет, а не \"%s\"" +msgid "'%s' expects a register" +msgstr "'%s' ожидает регистр" -#: py/objobject.c -msgid "__new__ arg must be a user-type" -msgstr "__new__ arg должен быть пользовательского типа" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "'%s' ожидает специальный регистр" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" -msgstr "Требуется байтоподобный объект" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "'%s' ожидает регистр FPU" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" -msgstr "адреса пусты" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' ожидает {r0, r1, ...}" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "'%s' ожидает целое число" -#: py/compile.c -msgid "annotation must be an identifier" -msgstr "Аннотация должна быть идентификатором" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' целое число 0x%x не помещается в маску 0x%x" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" -msgstr "arange: не удается вычислить длину" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s' ожидает адрес в формате [a, b]" -#: py/modbuiltins.c -msgid "arg is an empty sequence" -msgstr "arg - пустая последовательность" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' ожидает метку" -#: py/objobject.c -msgid "arg must be user-type" -msgstr "arg должен быть пользовательского типа" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" +msgstr "Метка '%q' не определена" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" -msgstr "аргумент сортировки должен быть аргументом массива ndarray" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" +msgstr "неподдерживаемая инструкция Thumb '%s' с аргументами %d" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" -msgstr "сортировка arg не реализована для сглаженных массивов" +#: py/emitinlinethumb.c +msgid "branch not in range" +msgstr "Ветвь не в пределах досягаемости" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" -msgstr "аргумент должен быть None, целым числом или кортежем целых чисел" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" +msgstr "может иметь только до 4 параметров для сборки Xtensa" -#: py/compile.c -msgid "argument name reused" -msgstr "Повторное использование имени аргумента" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" +msgstr "Параметры должны быть регистрами в последовательности от a2 до a5" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" -msgstr "Аргумент Несоответствие числа/типов" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' целое число %d не находится в пределах диапазона %d..%d" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" -msgstr "Аргументы должны быть массивами ndarrays" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" -msgstr "Длина массива и индекса должна быть равна" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" +msgstr "неподдерживаемая инструкция Xtensa '%s' с аргументами %d" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" -msgstr "Массив имеет слишком много измерений" +#: py/emitnative.c +msgid "conversion to object" +msgstr "Преобразование в объект" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" -msgstr "массив слишком велик" +#: py/emitnative.c +msgid "local '%q' used before type known" +msgstr "местный '%q' используется перед типом" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" -msgstr "массив/байты, необходимые справа" +#: py/emitnative.c +msgid "can't load from '%q'" +msgstr "Не удается загрузить из '%q'" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "Переполнение ASM" +#: py/emitnative.c +msgid "can't load with '%q' index" +msgstr "Не удается загрузить с индексом '%q'" -#: py/compile.c -msgid "async for/with outside async function" -msgstr "async для/вместе с внешней async-функцией" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" +msgstr "Локальный '%q' имеет тип '%q', но источник '%q'" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "" -"Попытка получить (аргумент)минимальный/(аргумент)максимальный пустой " -"последовательности" +#: py/emitnative.c +msgid "can't store '%q'" +msgstr "Не удается сохранить '%q'" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" -msgstr "" -"Попытка получить аргумент минимальный/аргумент максимальный пустой " -"последовательности" +#: py/emitnative.c +msgid "can't store to '%q'" +msgstr "невозможно сохранить в «%q»" -#: py/objstr.c -msgid "attributes not supported" -msgstr "Атрибуты не поддерживаются" +#: py/emitnative.c +msgid "can't store with '%q' index" +msgstr "не может хранить с индексом%q" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" -msgstr "" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" +msgstr "не может неявно преобразовать '%q' в 'bool'" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" -msgstr "Ось выходит за пределы" +#: py/emitnative.c +msgid "'not' not implemented" +msgstr "'не' не реализовано" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" -msgstr "ось должна быть None или целым числом" +#: py/emitnative.c +msgid "can't do unary op of '%q'" +msgstr "Невозможно выполнить унарную операцию '%q'" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" -msgstr "Слишком длинная ось" +#: py/emitnative.c +msgid "div/mod not implemented for uint" +msgstr "div/mod не реализован для uint" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" -msgstr "Фоновое значение вне диапазона цели" +#: py/emitnative.c +msgid "comparison of int and uint" +msgstr "сравнение int и uint" -#: py/builtinevex.c -msgid "bad compile mode" -msgstr "Неверный режим компиляции" +#: py/emitnative.c +msgid "binary op %q not implemented" +msgstr "двоичная операция %q не реализована" -#: py/objstr.c -msgid "bad conversion specifier" -msgstr "Неверный спецификатор преобразования" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" +msgstr "Не могу выполнить двоичную операцию между '%q' и '%q'" -#: py/objstr.c -msgid "bad format string" -msgstr "Строка неверного формата" +#: py/emitnative.c +msgid "casting" +msgstr "кастинг" -#: py/binary.c py/objarray.c -msgid "bad typecode" -msgstr "Неверный шрифт" +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" +msgstr "Возврат ожидался '%q', но получил '%q'" #: py/emitnative.c -msgid "binary op %q not implemented" -msgstr "двоичная операция %q не реализована" - -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "Глубина_бита должна быть равна 8, 16, 24 или 32." +msgid "native raise" +msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" -msgstr "Размер и глубина растрового изображения должны совпадать" +#: py/emitnative.c +msgid "must raise an object" +msgstr "должен поднять объект" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" -msgstr "Размеры растровых изображений должны совпадать" +#: py/emitnative.c +msgid "native yield" +msgstr "родной урожай" -#: extmod/modrandom.c -msgid "bits must be 32 or less" -msgstr "биты должны быть 32 или менее" +#: py/lexer.c +msgid "unicode name escapes" +msgstr "Экранирование имен в Юникоде" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/modbuiltins.c py/objstr.c +msgid "char not in range(0x110000)" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" -msgstr "bits_per_sample должно быть 8 или 16" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" +msgstr "chr() аргумент вне диапазона (256)" -#: py/emitinlinethumb.c -msgid "branch not in range" -msgstr "Ветвь не в пределах досягаемости" +#: py/modbuiltins.c +msgid "arg is an empty sequence" +msgstr "arg - пустая последовательность" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" -msgstr "Размер буфера меньше запрошенного" +#: py/modbuiltins.c +msgid "ord expects a character" +msgstr "Орд ожидает персонажа" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" -msgstr "Размер буфера должен быть кратен размеру элемента" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" +msgstr "ord() ожидал символ, но строка длины %d найдена" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" -msgstr "Размер буфера должен соответствовать формату" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "Pow() с 3 аргументами не поддерживается" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "Буферные фрагменты должны быть одинаковой длины" +#: py/modbuiltins.c +msgid "must use keyword argument for key function" +msgstr "Необходимо использовать аргумент ключевого слова для ключевой функции" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" -msgstr "буфер слишком мал" +#: py/moderrno.c +msgid "Operation not permitted" +msgstr "Операция не разрешена" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" -msgstr "Слишком маленький буфер для запрашиваемых байтов" +#: py/moderrno.c +msgid "No such file/directory" +msgstr "Файл/директория не существует" -#: py/emitbc.c -msgid "bytecode overflow" -msgstr "Переполнение байт-кода" +#: py/moderrno.c +msgid "Input/output error" +msgstr "Ошибка ввода/вывода" -#: py/objarray.c -msgid "bytes length not a multiple of item size" -msgstr "длина байтов, не кратная размеру элемента" +#: py/moderrno.c +msgid "Permission denied" +msgstr "Отказано в разрешении" -#: py/objstr.c -msgid "bytes value out of range" -msgstr "Значение байтов вне диапазона" +#: py/moderrno.c +msgid "File exists" +msgstr "Файл существует" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" -msgstr "Калибровка выходит за пределы допустимого диапазона" +#: py/moderrno.c +msgid "No such device" +msgstr "Нет такого устройства" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" -msgstr "Калибровка доступна только для чтения" +#: py/moderrno.c +msgid "No space left on device" +msgstr "На устройстве не осталось свободного места" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" -msgstr "может иметь только одного родителя" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" +msgstr "Ошибка математической области" -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" -msgstr "" +#: py/modmath.c +msgid "negative factorial" +msgstr "отрицательный факториал" -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" -msgstr "может иметь только до 4 параметров для сборки большого пальца" +#: py/modmicropython.c +msgid "schedule queue full" +msgstr "Расписание Очередь заполнена" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" -msgstr "может иметь только до 4 параметров для сборки Xtensa" +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c +msgid "buffer too small" +msgstr "буфер слишком мал" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" -msgstr "Можно указать только одно неизвестное измерение" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" +msgstr "Упаковка ожидаемых %d товаров для упаковки (получил %d)" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" +#: py/modthread.c +msgid "expecting a dict for keyword args" +msgstr "ожидание определения аргументов ключевых слов" + +#: py/modweakref.c +msgid "not a heap object" msgstr "" -"Не удается добавить специальный метод к уже имеющемуся подклассу классу" -#: py/compile.c -msgid "can't assign to expression" -msgstr "Не удается назначить выражение" +#: py/nativeglue.c +msgid "set unsupported" +msgstr "Установить не поддерживается" -#: extmod/modasyncio.c -msgid "can't cancel self" -msgstr "Не могу отменить себя" +#: py/nativeglue.c +msgid "slice unsupported" +msgstr "Фрагмент не поддерживается" + +#: py/nativeglue.c +msgid "float unsupported" +msgstr "Плавающий без поддержки" #: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c msgid "can't convert %q to %q" msgstr "Не удается преобразовать %q в %q" #: py/obj.c -#, c-format -msgid "can't convert %s to complex" -msgstr "не может преобразовать %s в сложный" +msgid "During handling of the above exception, another exception occurred:" +msgstr "" +"При обращении с вышеуказанным исключением произошло еще одно исключение:" #: py/obj.c -#, c-format -msgid "can't convert %s to float" -msgstr "не могу преобразовать %s в число с плавающей запятой" +msgid "The above exception was the direct cause of the following exception:" +msgstr "" +"Вышеупомянутое исключение было непосредственной причиной следующего " +"исключения:" -#: py/objint.c py/runtime.c -#, c-format -msgid "can't convert %s to int" -msgstr "Невозможно преобразовать %s в int" +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " Файл \"%q\", строка %d" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" -msgstr "не может конвертировать «%q» в% q косвенно" +#: py/obj.c +msgid " File \"%q\"" +msgstr " Файл \"%q\"" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" -msgstr "Не может преобразовать сложный в плавающий" +#: py/obj.c +msgid ", in %q\n" +msgstr ", в %q\n" #: py/obj.c -msgid "can't convert to complex" -msgstr "не может быть преобразован в сложный" +msgid "Traceback (most recent call last):\n" +msgstr "Трассировка (последний вызов):\n" #: py/obj.c msgid "can't convert to float" msgstr "Не удается преобразовать в float" -#: py/runtime.c -msgid "can't convert to int" -msgstr "Не удается преобразовать в int" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" +msgstr "не могу преобразовать %s в число с плавающей запятой" -#: py/objstr.c -msgid "can't convert to str implicitly" -msgstr "не может превратиться в полосу неявно" +#: py/obj.c +msgid "can't convert to complex" +msgstr "не может быть преобразован в сложный" -#: py/objtype.c -msgid "can't create '%q' instances" -msgstr "" +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" +msgstr "не может преобразовать %s в сложный" -#: py/compile.c -msgid "can't declare nonlocal in outer code" -msgstr "не может объявить нелокальный во внешнем коде" +#: py/obj.c +msgid "expected tuple/list" +msgstr "Ожидаемый кортеж/список" -#: py/compile.c -msgid "can't delete expression" -msgstr "Не удается удалить выражение" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" +msgstr "Объект \"%s\" не является кортежом или списком" -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" -msgstr "Не могу выполнить двоичную операцию между '%q' и '%q'" +#: py/obj.c +msgid "tuple/list has wrong length" +msgstr "Кортеж/список имеет неправильную длину" + +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" +msgstr "запрашиваемая длина %d, но объект имеет длину %d" + +#: py/obj.c +msgid "indices must be integers" +msgstr "индексы должны быть целыми числами" + +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "Индексы %q должны быть целыми числами, а не %s" + +#: py/obj.c +msgid "object has no len" +msgstr "Объект не имеет объектива" + +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" +msgstr "объект типа «%s» не имеет len()" -#: py/emitnative.c -msgid "can't do unary op of '%q'" -msgstr "Невозможно выполнить унарную операцию '%q'" +#: py/obj.c +msgid "object doesn't support item deletion" +msgstr "Объект не поддерживает удаление элементов" -#: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" -msgstr "не может неявно преобразовать '%q' в 'bool'" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "Объект '%s' не поддерживает удаление элементов" -#: py/runtime.c -msgid "can't import name %q" -msgstr "Невозможно импортировать имя %q" +#: py/obj.c +msgid "object isn't subscriptable" +msgstr "Объект не имеет индекса" -#: py/emitnative.c -msgid "can't load from '%q'" -msgstr "Не удается загрузить из '%q'" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "Объект '%s' не может быть подписан" -#: py/emitnative.c -msgid "can't load with '%q' index" -msgstr "Не удается загрузить с индексом '%q'" +#: py/obj.c +msgid "object doesn't support item assignment" +msgstr "Объект не поддерживает назначение элементов" -#: py/builtinimport.c -msgid "can't perform relative import" -msgstr "Не удается выполнить относительный импорт" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "Объект '%s' не поддерживает присвоение элементов" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" -msgstr "" -"не может отправить значение, отличное от None, только что запущенному " -"генератору" +#: py/obj.c +msgid "object with buffer protocol required" +msgstr "Объект с обязательным буферным протоколом" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" -msgstr "Не удается установить размер блока 512" +#: py/objarray.c +msgid "bytes length not a multiple of item size" +msgstr "длина байтов, не кратная размеру элемента" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" -msgstr "Не удается установить атрибут" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" +msgstr "строковый аргумент без кодировки" -#: py/runtime.c -msgid "can't set attribute '%q'" -msgstr "Не удается установить атрибут '%q'" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" +msgstr "вид памяти: длина не является множеством элементов" -#: py/emitnative.c -msgid "can't store '%q'" -msgstr "Не удается сохранить '%q'" +#: py/objarray.c py/objstr.c +msgid "substring not found" +msgstr "Подстрока не найдена" -#: py/emitnative.c -msgid "can't store to '%q'" -msgstr "невозможно сохранить в «%q»" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" +msgstr "поддерживаются только срезы с шагом = 1 (так как нет)" -#: py/emitnative.c -msgid "can't store with '%q' index" -msgstr "не может хранить с индексом%q" +#: py/objarray.c +msgid "lhs and rhs should be compatible" +msgstr "lhs и rhs должны быть совместимыми" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" -msgstr "" -"Не удается переключиться с автоматической нумерации полей на ручную " -"спецификацию полей" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" +msgstr "массив/байты, необходимые справа" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" -msgstr "не может переключаться с ручного поля на автоматическую нумерацию поля" +#: py/objarray.c +msgid "memoryview offset too large" +msgstr "Слишком большое смещение просмотра памяти" #: py/objcomplex.c msgid "can't truncate-divide a complex number" msgstr "нельзя усекать и делить комплексное число" -#: extmod/modasyncio.c -msgid "can't wait" -msgstr "не может ждать" +#: py/objcomplex.c +msgid "complex divide by zero" +msgstr "комплексное деление на ноль" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" -msgstr "Не удается назначить новую фигуру" +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "0.0 в комплексную степень" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" -msgstr "Не удается привести выходные данные с помощью правила приведения" +#: py/objdeque.c +msgid "full" +msgstr "полный" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" -msgstr "не может превратить комплекс в dtype" +#: py/objdeque.c +msgid "empty" +msgstr "пусто" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" -msgstr "Не удается преобразовать сложный тип" +#: py/objdict.c +msgid "dict update sequence has wrong length" +msgstr "последовательность обновления дикта имеет неправильную длину" -#: py/objtype.c -msgid "cannot create instance" -msgstr "Не удается создать экземпляр" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" +msgstr "Не удается установить атрибут" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" -msgstr "Не удается удалить элементы массива" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" +msgstr "Комплексные значения не поддерживаются" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" -msgstr "Не удается изменить форму массива" +#: py/objgenerator.c +msgid "generator already executing" +msgstr "генератор уже работает" -#: py/emitnative.c -msgid "casting" -msgstr "кастинг" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" +msgstr "" +"не может отправить значение, отличное от None, только что запущенному " +"генератору" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" -msgstr "Реинициализация канала" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" +msgstr "генератор поднят Остановить итерацию" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" -msgstr "Слишком маленький буфер символов" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" +msgstr "генератор проигнорировал Выход" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" -msgstr "chr() аргумент вне диапазона (0x110000)" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" +msgstr "Невозможно преобразовать %s в int" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" -msgstr "chr() аргумент вне диапазона (256)" +#: py/objint.c +msgid "float too big" +msgstr "Поплавок слишком большой" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" -msgstr "Точка клипа должна быть кортежом (x,y)" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" +msgstr "Нет поддержки длинных целых чисел (long integer)" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" -msgstr "код вне диапазона 0~127" +#: py/objint.c py/sequence.c +msgid "small int overflow" +msgstr "Маленькое переполнение int" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "%q=%q" + +#: py/objint_impl.h +#, c-format +msgid "value would overflow a %d byte buffer" msgstr "" -"Цветовой буфер должен иметь размер 3 байта (RGB) или 4 байта (RGB + байт " -"заполнения)" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" -msgstr "Цветовой буфер должен быть буфером, кортежом, списком или целым числом" +#: py/objint_impl.h +msgid "can't convert negative int to unsigned" +msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -"цветовой буфер должен быть байтом массива или массивом типа \"b\" или \"B\"" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" -msgstr "Цвет должен быть от 0x000000 до 0xffffff" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" +msgstr "Количество отрицательных сдвигов" -#: py/emitnative.c -msgid "comparison of int and uint" -msgstr "сравнение int и uint" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" +msgstr "Отрицательная мощность без поплавковой опоры" -#: py/objcomplex.c -msgid "complex divide by zero" -msgstr "комплексное деление на ноль" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" +msgstr "переполнение преобразование длинного целого в машинное слово" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" -msgstr "Комплексные значения не поддерживаются" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" +msgstr "pow() с 3 аргументами требует целых чисел" -#: extmod/modzlib.c -msgid "compression header" -msgstr "Заголовок сжатия" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" +msgstr "3-й аргумент pow() не может быть равен 0" -#: py/emitnative.c -msgid "conversion to object" -msgstr "Преобразование в объект" +#: py/objobject.c +msgid "__new__ arg must be a user-type" +msgstr "__new__ arg должен быть пользовательского типа" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" -msgstr "Аргументы свертки должны быть линейными массивами" +#: py/objobject.c +msgid "arg must be user-type" +msgstr "arg должен быть пользовательского типа" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" -msgstr "переплетение аргументов должно быть массивами ndarrays" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "Шаг %q не может быть нулём" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" -msgstr "аргументы свертки не должны быть пустыми" +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "Невозможно создать подкласс среза" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" -msgstr "Поврежденный файл" +#: py/objstr.c +msgid "unknown encoding: %q" +msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" -msgstr "не удалось инвертировать матрицу Вандермонда" +#: py/objstr.c +msgid "bytes value out of range" +msgstr "Значение байтов вне диапазона" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" -msgstr "Не удалось определить версию SD карты" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" +msgstr "" +"присоединяйтесь к ожидающему список стр/байт объектов, совместимых с " +"самообъектом" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" -msgstr "крест определяется для 1D массивов длины 3" +#: py/objstr.c +msgid "empty separator" +msgstr "пустой сепаратор" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" -msgstr "Данные должны быть итерируемыми" +#: py/objstr.c +msgid "rsplit(None,n)" +msgstr "rsplit(Нет;n)" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" -msgstr "Данные должны быть одинаковой длины" +#: py/objstr.c +msgid "bad format string" +msgstr "Строка неверного формата" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/objstr.c #, c-format -msgid "data pin #%d in use" -msgstr "data-пин #%d уже используется" +msgid "unmatched '%c' in format" +msgstr "Несовпадающий '%c' в формате" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" -msgstr "Тип данных не понят" +#: py/objstr.c +msgid "bad conversion specifier" +msgstr "Неверный спецификатор преобразования" -#: py/parsenum.c -msgid "decimal numbers not supported" -msgstr "Десятичные числа не поддерживаются" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" +msgstr "конец формата при поиске спецификатора преобразования" -#: py/compile.c -msgid "default 'except' must be last" -msgstr "по умолчанию \"за исключением\" должно быть последним" +#: py/objstr.c +#, c-format +msgid "unknown conversion specifier %c" +msgstr "Неизвестный спецификатор преобразования %c" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" -msgstr "По умолчанию не является функцией" +#: py/objstr.c +msgid "expected ':' after format specifier" +msgstr "Ожидаемый ':' после спецификатора формата" -#: shared-bindings/audiobusio/PDMIn.c +#: py/objstr.c msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" -msgstr "" -"буфер назначения должен быть байтоммассива или массивом типа \"B\" для " -"бит_глубины = 8" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +"can't switch from automatic field numbering to manual field specification" msgstr "" -"буфер назначения должен быть массивом типа «H» для битовой_глубины = 16" - -#: py/objdict.c -msgid "dict update sequence has wrong length" -msgstr "последовательность обновления дикта имеет неправильную длину" +"Не удается переключиться с автоматической нумерации полей на ручную " +"спецификацию полей" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" -msgstr "аргумент DIFF должен быть массивом ndarray" +#: py/objstr.c +msgid "%q index out of range" +msgstr "Индекс %q вне диапазона" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" -msgstr "Порядок дифференциации вне диапазона" +#: py/objstr.c +msgid "attributes not supported" +msgstr "Атрибуты не поддерживаются" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" -msgstr "Размеры не совпадают" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" +msgstr "не может переключаться с ручного поля на автоматическую нумерацию поля" -#: py/emitnative.c -msgid "div/mod not implemented for uint" -msgstr "div/mod не реализован для uint" +#: py/objstr.c +msgid "invalid format specifier" +msgstr "Недопустимый спецификатор формата" -#: extmod/ulab/code/numpy/create.c -msgid "divide by zero" -msgstr "Делим на ноль" +#: py/objstr.c +msgid "sign not allowed in string format specifier" +msgstr "Знак не разрешен в спецификаторе строкового формата" -#: py/runtime.c -msgid "division by zero" -msgstr "Деление на ноль" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" +msgstr "Знак не разрешен со спецификатором целочисленного формата 'c'" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" -msgstr "Тип d должен быть плавающим или сложным" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" +msgstr "Неизвестный код формата '%c' для объекта типа '%q'" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" -msgstr "dtype int32 не поддерживается" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "Выравнивание '=' недопустимо в спецификаторе формата строки" -#: py/objdeque.c -msgid "empty" -msgstr "пусто" +#: py/objstr.c +msgid "format needs a dict" +msgstr "Формат требует диктата" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" -msgstr "пустой файл" +#: py/objstr.c +msgid "incomplete format key" +msgstr "Неполный ключ форматирования" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" -msgstr "пустая куча" +#: py/objstr.c +msgid "incomplete format" +msgstr "Неполный формат" #: py/objstr.c -msgid "empty separator" -msgstr "пустой сепаратор" +msgid "format string needs more arguments" +msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" -msgstr "пустая последовательность" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" +msgstr "" #: py/objstr.c -msgid "end of format while looking for conversion specifier" -msgstr "конец формата при поиске спецификатора преобразования" +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" +msgstr "Неподдерживаемый символ формата '%c' (0x%x) при индексе %d" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" -msgstr "epoch_time не поддерживается на этой плате" +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" -msgstr "ошибка = 0x%08lX" +#: py/objstr.c +msgid "non-hex digit" +msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" -msgstr "исключения должны быть производными от базового исключения" +#: py/objstr.c +msgid "can't convert to str implicitly" +msgstr "не может превратиться в полосу неявно" #: py/objstr.c -msgid "expected ':' after format specifier" -msgstr "Ожидаемый ':' после спецификатора формата" +msgid "can't convert '%q' object to %q implicitly" +msgstr "не может конвертировать «%q» в% q косвенно" -#: py/obj.c -msgid "expected tuple/list" -msgstr "Ожидаемый кортеж/список" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" +msgstr "Индексы строк должны быть целыми числами, а не %s" -#: py/modthread.c -msgid "expecting a dict for keyword args" -msgstr "ожидание определения аргументов ключевых слов" +#: py/objstrunicode.c +msgid "string index out of range" +msgstr "индекс строки выходит за пределы диапазона" -#: py/compile.c -msgid "expecting an assembler instruction" -msgstr "Ожидание инструкции ассемблера" +#: py/objtemplate.c +msgid "expected str or Interpolation" +msgstr "" -#: py/compile.c -msgid "expecting just a value for set" -msgstr "ожидание только значения для набора" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "Вызовите super().__init__() перед доступом к собственному объекту." -#: py/compile.c -msgid "expecting key:value for dict" -msgstr "ожидание ключа: значение для дикта" +#: py/objtype.c +msgid "__init__() should return None" +msgstr "__init__() должен возвращать значение None" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" -msgstr "ext_hook не является функцией" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" +msgstr "__init__() должна возвращать Нет, а не \"%s\"" -#: py/argcheck.c -msgid "extra keyword arguments given" -msgstr "Приведены дополнительные аргументы ключевых слов" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" +msgstr "Нечитаемый атрибут" -#: py/argcheck.c -msgid "extra positional arguments given" -msgstr "Приведены дополнительные позиционные аргументы" +#: py/objtype.c py/runtime.c +msgid "object not callable" +msgstr "Объект не вызывается" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" -msgstr "Файл должен быть файлом, открытым в байтовом режиме" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" +msgstr "" + +#: py/objtype.c +msgid "type takes 1 or 3 arguments" +msgstr "тип занимает 1 или 3 аргумента" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" -msgstr "Запись файлов недоступна" +#: py/objtype.c +msgid "can't create instance" +msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "Файловая система должна предусматривать метод монтирования" +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" -msgstr "Первый аргумент должен быть вызываемым" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" +msgstr "" +"Не удается добавить специальный метод к уже имеющемуся подклассу классу" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" -msgstr "первый аргумент должен быть функцией" +#: py/objtype.c +msgid "type isn't an acceptable base type" +msgstr "Тип не является приемлемым базовым типом" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" -msgstr "Первый аргумент должен быть кортежом массива ndarrays" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" +msgstr "Тип '%Q' не является допустимым базовым типом" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" -msgstr "Первым аргументом должен быть массивом ndarray" +#: py/objtype.c +msgid "multiple inheritance not supported" +msgstr "Множественное наследование не поддерживается" + +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" +msgstr "Несколько баз имеют конфликт расположения экземпляров" #: py/objtype.c msgid "first argument to super() must be type" msgstr "первый аргумент супер() должен быть типом" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" -msgstr "Первые два аргумента должны быть массивами ndarrays" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" +msgstr "issubclass() arg 2 должен быть классом или кортежом классов" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" -msgstr "порядок сглаживания должен быть либо 'C', либо 'F'" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" +msgstr "issubclass() arg 1 должен быть классом" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" -msgstr "Флип -аргумент должен быть массивом ndarray" +#: py/parse.c +msgid "not a constant" +msgstr "не константа" -#: py/objint.c -msgid "float too big" -msgstr "Поплавок слишком большой" +#: py/parse.c +msgid "Unable to init parser" +msgstr "Не удается инициировать синтаксический анализатор" -#: py/nativeglue.c -msgid "float unsupported" -msgstr "Плавающий без поддержки" +#: py/parse.c +msgid "unexpected indent" +msgstr "Неожиданный отступ" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "Длина шрифта должна составлять 2048 байт" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" +msgstr "Отступ не совпадает ни с одним уровнем внешнего отступа" -#: extmod/moddeflate.c -msgid "format" -msgstr "формат" +#: py/parse.c +msgid "malformed f-string" +msgstr "Неправильно сформированная F-строка" -#: py/objstr.c -msgid "format needs a dict" -msgstr "Формат требует диктата" +#: py/parsenum.c +msgid "invalid syntax for integer" +msgstr "недействительный синтаксис для целых чисел" -#: py/objstr.c -msgid "format string didn't convert all arguments" -msgstr "" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" +msgstr "недействительный синтаксис для целых чисел с основанием %d" -#: py/objstr.c -msgid "format string needs more arguments" -msgstr "" +#: py/parsenum.c +msgid "invalid syntax for number" +msgstr "недействительный синтаксис для номера" -#: py/objdeque.c -msgid "full" -msgstr "полный" +#: py/parsenum.c +msgid "decimal numbers not supported" +msgstr "Десятичные числа не поддерживаются" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" -msgstr "функция не принимает аргументы ключевых слов" +#: py/persistentcode.c +msgid "incompatible .mpy file" +msgstr "несовместимый файл .mpy" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" -msgstr "функция, ожидаемая в большинстве %d аргументов, получила %d" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" -msgstr "функция имеет несколько значений для аргументации%q \"" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" +msgstr "Нативный код в .mpy не поддерживается" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" -msgstr "функция имеет один и тот же знак в конце интервала" +#: py/persistentcode.c +msgid "incompatible .mpy arch" +msgstr "несовместимые .mpy арка" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" -msgstr "Функция определяется только для массивов ndarrays" +#: py/persistentcode.c +msgid "function must be bytecode" +msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" -msgstr "Функция реализована только для массивов ndarrays" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "Объект '%q' не поддерживает '%q'" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" -msgstr "Функция отсутствует %d обязательные позиционные аргументы" +#: py/qstr.c +msgid "name too long" +msgstr "слишком длинное имя" -#: py/bc.c -msgid "function missing keyword-only argument" -msgstr "функция отсутствует аргумент только по ключевому слову" +#: py/runtime.c +msgid "name not defined" +msgstr "Имя не определено" -#: py/bc.c -msgid "function missing required keyword argument '%q'" -msgstr "В функции отсутствует обязательный аргумент ключевого слова '%q'" +#: py/runtime.c +msgid "name '%q' isn't defined" +msgstr "Имя '%q' не определено" -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" -msgstr "В функции отсутствует обязательный позиционный аргумент #%d" +#: py/runtime.c +msgid "unsupported type for operator" +msgstr "Неподдерживаемый тип для оператора" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" -msgstr "функция принимает %d позиционные аргументы, но %d были заданы" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" +msgstr "неподдерживаемый тип для %q: '%s'" -#: py/objgenerator.c -msgid "generator already executing" -msgstr "генератор уже работает" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" +msgstr "Неподдерживаемые типы для %q: '%q', '%q'" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" -msgstr "генератор проигнорировал Выход" +#: py/runtime.c +msgid "wrong number of values to unpack" +msgstr "Неправильное количество значений для распаковки" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" -msgstr "генератор поднят Остановить итерацию" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" +msgstr "Для распаковки требуется более значений %d" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "Длина рисунка должна составлять 2048 байт" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" +msgstr "Слишком много значений для распаковки (ожидаемый %d)" -#: extmod/modhashlib.c -msgid "hash is final" -msgstr "хэш является окончательным" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" +msgstr "тип объекта '%q' не имеет атрибута '%q \"" -#: extmod/modheapq.c -msgid "heap must be a list" -msgstr "куча должна быть списком" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" -#: py/compile.c -msgid "identifier redefined as global" -msgstr "идентификатор переопределен как глобальный" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "Объект '%s' не имеет атрибута '%q'" -#: py/compile.c -msgid "identifier redefined as nonlocal" -msgstr "идентификатор переопределен как нелокальный" +#: py/runtime.c +msgid "can't set attribute '%q'" +msgstr "Не удается установить атрибут '%q'" -#: py/compile.c -msgid "import * not at module level" -msgstr "Импорт * не на уровне модуля" +#: py/runtime.c +msgid "object not iterable" +msgstr "Объект не итерируемый" -#: py/persistentcode.c -msgid "incompatible .mpy arch" -msgstr "несовместимые .mpy арка" +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "Объект '%q' не является итерируемым" -#: py/persistentcode.c -msgid "incompatible .mpy file" -msgstr "несовместимый файл .mpy" +#: py/runtime.c +msgid "object not an iterator" +msgstr "объект не итератор" -#: py/objstr.c -msgid "incomplete format" -msgstr "Неполный формат" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "Объект '%q' не является итератором" -#: py/objstr.c -msgid "incomplete format key" -msgstr "Неполный ключ форматирования" +#: py/runtime.c +msgid "exceptions must derive from BaseException" +msgstr "исключения должны быть производными от базового исключения" + +#: py/runtime.c +msgid "can't import name %q" +msgstr "Невозможно импортировать имя %q" -#: extmod/modbinascii.c -msgid "incorrect padding" -msgstr "Неправильная набивка" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" +msgstr "Не удалось выделить память, куча заблокирована" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" -msgstr "индекс выходит из границ" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" +msgstr "Сбой выделения памяти, выделение %u байт" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" -msgstr "Индекс должен быть кортежом или целым кортежом" +#: py/runtime.c +msgid "can't convert to int" +msgstr "Не удается преобразовать в int" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" -msgstr "индекс вне диапазона" +#: py/runtime.c +msgid "division by zero" +msgstr "Деление на ноль" -#: py/obj.c -msgid "indices must be integers" -msgstr "индексы должны быть целыми числами" +#: py/runtime.c +msgid "maximum recursion depth exceeded" +msgstr "Превышена максимальная глубина рекурсии" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" -msgstr "индексы должны быть целыми числами, срезами или логическими списками" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" +msgstr "объект не в последовательности" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" -msgstr "Начальные значения должны быть итерируемыми" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" +msgstr "Потоковая операция не поддерживается" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "длина первоначального_значения ошибочна" +#: py/vm.c +msgid "local variable referenced before assignment" +msgstr "локальная переменная, на которую ссылается перед присвоением" -#: py/compile.c -msgid "inline assembler must be a function" -msgstr "Встроенный ассемблер должен быть функцией" +#: py/vm.c +msgid "no active exception to reraise" +msgstr "Нет активного исключения для повторного создания" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" -msgstr "Входные и выходные размеры различаются" +#: py/vm.c +msgid "opcode" +msgstr "код операции" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" -msgstr "Входные и выходные формы различаются" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "Невозможно создать новый Adapter; используйте _bleio.adapter;" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" -msgstr "Входной аргумент должен быть целым числом, кортежом или списком" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "Не удалось задать адрес" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" -msgstr "Длина входного массива должна быть равна степени 2" +#: shared-bindings/_bleio/Adapter.c +#, c-format +msgid "interval must be in range %s-%s" +msgstr "Интервал должен находиться в диапазоне %s-%s" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" -msgstr "Входные массивы несовместимы" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." +msgstr "" +"Не может быть ответов на сканирование для расширенных подключаемых рекламных " +"объявлений." -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" -msgstr "Входные данные должны быть итерируемыми" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" +msgstr "Только подключаемые объявления могут быть направлены" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" -msgstr "Входной тип dtype должен быть плавающим или сложным" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" +msgstr "Ненулевое время ожидания должно быть >= интервал" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" -msgstr "Ввод не является итерируемым" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" +msgstr "окно должно быть <= интервал" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" -msgstr "Входная матрица асимметрична" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" +msgstr "Буфер префикса должен находиться в куче" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" -msgstr "Входная матрица является сингулярной" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "ХарактеристикаЗапись в буфер не предусмотрена" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" -msgstr "Вход должен быть 1- или 2-D" +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." +msgstr "" +"Соединение было отключено и больше не может использоваться. Создайте новое " +"соединение." -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" -msgstr "Ввод должен быть 1D массивом ndarray" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" +msgstr "Буфер слишком короткий на %d байт" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" -msgstr "Ввод должен быть плотным массивом ndarray" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" +msgstr "Нет соединения: длина не может быть определена" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" -msgstr "Ввод должен быть массивом ndarray" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +msgstr "UUID строка не 'xxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxxx \"" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" -msgstr "Ввод должен быть массивом ndarray или скаляр" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" +msgstr "Значение UUID не является строковым, целым или байтовым буфером" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" -msgstr "Входные данные должны быть одномерными" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" +msgstr "не 128-битный UUID" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" -msgstr "Входные данные должны быть квадратной матрицей" +#: shared-bindings/_bleio/__init__.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" +msgstr "Только для чтения" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" -msgstr "Ввод должен быть кортеж, список, диапазон или массивом ndarray" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "Неправильный размер буфера" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" -msgstr "Входные векторы должны быть одинаковой длины" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" +msgstr "вложенный индекс должен быть int" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" -msgstr "interp определен для 1D-итераций одинаковой длины" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" +msgstr "Индекс должен быть кортежом или целым кортежом" -#: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" -msgstr "Интервал должен находиться в диапазоне %s-%s" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" +msgstr "Слишком маленький буфер карты" -#: py/compile.c -msgid "invalid arch" -msgstr "недействительная арка" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" +msgstr "Слишком маленький буфер символов" -#: shared-bindings/bitmaptools/__init__.c +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" +msgstr "Пин является только входом" + +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c #, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" -msgstr "неверный бит_на_пиксель %d, должно быть 1, 2, 4, 8, 16, 24 или 32" +msgid "Unmatched number of items on RHS (expected %d, got %d)." +msgstr "" +"Непревзойденное количество элементов на RHS (ожидалось %d, получено %d)." -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" -msgstr "Неверный сертификат" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "Ключ должен быть длинной 16, 24 или 32 байта" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" -msgstr "недопустимый размер элемента %d для битов на_пиксель %d\n" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" +msgstr "Запрошенный режим AES не поддерживается" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" -msgstr "аннулированный элемент_размер %d, должен быть, 1, 2 или 4" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" +msgstr "Исходный и конечный буферы должны иметь одинаковую длину" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" -msgstr "Недопустимое исключение" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB работает только с 16 байтами за раз" -#: py/objstr.c -msgid "invalid format specifier" -msgstr "Недопустимый спецификатор формата" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "Блоки CBC должны быть кратны 16 байтам" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" -msgstr "Недопустимое имя хоста" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." +msgstr "Нарежьте и оцените разную длину." -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" -msgstr "Неверный ключ" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "Значения массива должны быть однобайтовыми." -#: py/compile.c -msgid "invalid micropython decorator" -msgstr "неверный декоратор микропитона" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." +msgstr "Невозможно записать в Sleep_memory." -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" -msgstr "Недопустимый параметр" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" +msgstr "Ожидаемый вид %q" -#: shared-bindings/random/__init__.c -msgid "invalid step" -msgstr "недействительный шаг" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" +msgstr "RTC не поддерживается на этой плате" -#: py/compile.c py/parse.c -msgid "invalid syntax" -msgstr "недействительный синтаксис" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" +msgstr "Поставьте один из monotonic_time или epoch_time" -#: py/parsenum.c -msgid "invalid syntax for integer" -msgstr "недействительный синтаксис для целых чисел" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" +msgstr "epoch_time не поддерживается на этой плате" -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" -msgstr "недействительный синтаксис для целых чисел с основанием %d" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." +msgstr "Время в прошлом." -#: py/parsenum.c -msgid "invalid syntax for number" -msgstr "недействительный синтаксис для номера" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q должен быть массивом байтов или массивом типа «H» или «B»" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" -msgstr "issubclass() arg 1 должен быть классом" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" +msgstr "Не воспроизводится (Not playing)" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" -msgstr "issubclass() arg 2 должен быть классом или кортежом классов" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." +msgstr "%q должно быть кратно 8." -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" -msgstr "итерации не сходятся" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "Невозможно записать в файл" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" -msgstr "" -"присоединяйтесь к ожидающему список стр/байт объектов, совместимых с " -"самообъектом" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "Емкость места назначения меньше длины места назначения." -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -"Аргумент(ы) ключевого слова не реализован - используйте вместо него обычные " -"аргументы" +"буфер назначения должен быть массивом типа «H» для битовой_глубины = 16" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" -msgstr "Метка '%q' не определена" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +msgstr "" +"буфер назначения должен быть байтоммассива или массивом типа \"B\" для " +"бит_глубины = 8" -#: py/compile.c -msgid "label redefined" -msgstr "Метка переопределена" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q должен быть массивом байтов или массивом типа «h», «H», «b» или «B»" -#: py/objarray.c -msgid "lhs and rhs should be compatible" -msgstr "lhs и rhs должны быть совместимыми" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" +msgstr "Длина %q должна быть четной, кратной количеству каналов * размер_типа" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" -msgstr "Локальный '%q' имеет тип '%q', но источник '%q'" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" +msgstr "Файл должен быть файлом, открытым в байтовом режиме" -#: py/emitnative.c -msgid "local '%q' used before type known" -msgstr "местный '%q' используется перед типом" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c +#: shared-bindings/audiodelays/GranularPitchShift.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" +msgstr "bits_per_sample должно быть 8 или 16" -#: py/vm.c -msgid "local variable referenced before assignment" -msgstr "локальная переменная, на которую ссылается перед присвоением" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" +msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -"Замыкание на себя + бесшумный режим, не поддерживаемый периферийными " -"устройствами" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" -msgstr "mDNS уже инициализирован" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" -msgstr "mDNS работает только со встроенным WiFi" +#: shared-bindings/audioio/AudioOut.c shared-bindings/emmcio/EMMC.c +msgid "%q and %q must be different" +msgstr "%q и %q должны быть разными" -#: py/parse.c -msgid "malformed f-string" -msgstr "Неправильно сформированная F-строка" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" +msgstr "" +"Весом должна быть последовательность с нечетным квадратным числом элементов " +"(обычно 9 или 25)" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" -msgstr "Слишком маленький буфер карты" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +msgstr "Веса должны быть объектом типа %q, %q, %q или %q, а не %q " -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" -msgstr "Ошибка математической области" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" +msgstr "Точка клипа должна быть кортежом (x,y)" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" -msgstr "матрица не является положительно определенной" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" +msgstr "Исходная палитра слишком велика" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" -msgstr "максимальная_длина должна быть 0-%d когда фиксированная длина %s" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "" +"Размер растрового изображения и число битов на значение должны совпадать" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " -msgstr "Максимальное количество измерений составляет " +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +msgstr "" +"Для цветового пространства L8 входное растровое изображение должно иметь 8 " +"бит на пиксель" -#: py/runtime.c -msgid "maximum recursion depth exceeded" -msgstr "Превышена максимальная глубина рекурсии" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +msgstr "" +"Для цветовых пространств RGB входное растровое изображение должно иметь 16 " +"бит на пиксель" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" -msgstr "maxiter должен быть > 0" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" +msgstr "Неподдерживаемое цветовое пространство" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" -msgstr "макситер должен быть > 0" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" -msgstr "Средний аргумент должен быть массивом ndarray" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" -msgstr "Сбой выделения памяти, выделение %u байт" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" +msgstr "вне досягаемости цели" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" -msgstr "Не удалось выделить память, куча заблокирована" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" +msgstr "Величина выходящая за пределы диапазона цели" -#: py/objarray.c -msgid "memoryview offset too large" -msgstr "Слишком большое смещение просмотра памяти" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" +msgstr "Фоновое значение вне диапазона цели" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" -msgstr "вид памяти: длина не является множеством элементов" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" +msgstr "Типы массивов координат имеют разные размеры" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" -msgstr "mktime нужен кортеж длины 8 или 9" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "Координатные массивы имеют разные длины" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" -msgstr "Режим должен быть завершенным или уменьшенным" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" +msgstr "аннулированный элемент_размер %d, должен быть, 1, 2 или 4" -#: py/builtinimport.c -msgid "module not found" -msgstr "модуль не найден" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" +msgstr "недопустимый размер элемента %d для битов на_пиксель %d\n" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" -msgstr "Сбой инициализации монитора" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgstr "неверный бит_на_пиксель %d, должно быть 1, 2, 4, 8, 16, 24 или 32" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" -msgstr "Больше степеней свободы чем точек данных" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" +msgstr "Размеры растровых изображений должны совпадать" -#: py/compile.c -msgid "multiple *x in assignment" -msgstr "Несколько *x в назначении" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" +msgstr "source_bitmap должен иметь значение_счет 2 или 65536" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" -msgstr "Несколько баз имеют конфликт расположения экземпляров" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" +msgstr "source_bitmap должен иметь значение_счет 65536" -#: py/objtype.c -msgid "multiple inheritance not supported" -msgstr "Множественное наследование не поддерживается" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" +msgstr "source_bitmap должен иметь значение_счет 8" -#: py/emitnative.c -msgid "must raise an object" -msgstr "должен поднять объект" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" +msgstr "Неподдерживаемое цветовое пространство для дизеринга" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" -msgstr "Необходимо использовать аргумент ключевого слова для ключевой функции" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgstr "Длина входного буфера (%d) должна быть кратна количеству цепочек (%d)" -#: py/runtime.c -msgid "name '%q' isn't defined" -msgstr "Имя '%q' не определено" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" +msgstr "Нет шины %q по умолчанию" -#: py/runtime.c -msgid "name not defined" -msgstr "Имя не определено" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "Поворот дисплея должен осуществляться с шагом 90 градусов" -#: py/qstr.c -msgid "name too long" -msgstr "слишком длинное имя" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q должен быть равен 1, если %q имеет значение True" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" -msgstr "Нативный код в .mpy не поддерживается" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "Дисплей должен иметь 16 битное цветовое пространство." -#: py/asmthumb.c -msgid "native method too big" -msgstr "родной метод слишком большой" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" +msgstr "tx и rx не могут быть одновременно None" -#: py/emitnative.c -msgid "native yield" -msgstr "родной урожай" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." +msgstr "Должен быть субклассом %q." -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" -msgstr "Переполнение длины массива ndarray" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" +msgstr "Запросы на удаленную передачу ограничены 8 байтами" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" -msgstr "Для распаковки требуется более значений %d" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "Невозможно установить значение при вводе направления." -#: py/modmath.c -msgid "negative factorial" -msgstr "отрицательный факториал" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "Режим движения не используется при вводе направления." -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" -msgstr "Отрицательная мощность без поплавковой опоры" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." +msgstr "Тяга не используется, когда выводится направление." -#: py/objint_mpz.c py/runtime.c -msgid "negative shift count" -msgstr "Количество отрицательных сдвигов" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" -msgstr "вложенный индекс должен быть int" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "нет SD карты" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" -#: py/vm.c -msgid "no active exception to reraise" -msgstr "Нет активного исключения для повторного создания" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "Невозможно удалить значения" -#: py/compile.c -msgid "no binding for nonlocal found" -msgstr "Привязка для нелокальных не найдена" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" +msgstr "Фрагменты не поддерживаются" -#: shared-module/msgpack/__init__.c -msgid "no default packer" -msgstr "Нет упаковщика по умолчанию" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +msgstr "" +"цветовой буфер должен быть байтом массива или массивом типа \"b\" или \"B\"" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" -msgstr "Нет начального числа по умолчанию" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +msgstr "" +"Цветовой буфер должен иметь размер 3 байта (RGB) или 4 байта (RGB + байт " +"заполнения)" -#: py/builtinimport.c -msgid "no module named '%q'" -msgstr "Нет модуля с именем '%Q'" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" +msgstr "Цвет должен быть от 0x000000 до 0xffffff" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" -msgstr "нет ответа с SD карты" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" +msgstr "Цветовой буфер должен быть буфером, кортежом, списком или целым числом" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" -msgstr "нет такого атрибута" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" +msgstr "Неподдерживаемый тип %Q" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" -msgstr "не-UUID найден в сервисе_uuids_белый список" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" +msgstr "Ширина плитки должна точно делить ширину растрового изображения" -#: py/compile.c -msgid "non-default argument follows default argument" -msgstr "" -"Аргумент отличный от аргумента по умолчанию следует за аргументом по " -"умолчанию" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" +msgstr "Высота плитки должна точно делить высоту растрового изображения" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" msgstr "" +"Новое растровое изображение должно быть того же размера, что и старое " +"растровое изображение" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" -msgstr "Ненулевое время ожидания должно быть > 0,01" - -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" -msgstr "Ненулевое время ожидания должно быть >= интервал" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" +msgstr "Выход индекса плитки за пределы" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" -msgstr "не 128-битный UUID" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" +msgstr "Смещение должно быть >= 0" -#: py/parse.c -msgid "not a constant" -msgstr "не константа" +#: shared-bindings/emmcio/EMMC.c shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" -msgstr "не реализовано для сложного типа d" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "Слишком раннее обновление" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" -msgstr "Не поддерживается для типов ввода" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "Буфер не является байтовым массивом." -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" -msgstr "Количество баллов должно быть не менее 2" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" +msgstr "Системная запись должна быть gnss. Спутниковая система" -#: py/builtinhelp.c -msgid "object " -msgstr "объект " +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" +msgstr "Неподдерживаемый алгоритм хеширования" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" -msgstr "Объект \"%s\" не является кортежом или списком" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" -#: py/obj.c -msgid "object doesn't support item assignment" -msgstr "Объект не поддерживает назначение элементов" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" +msgstr "адреса пусты" -#: py/obj.c -msgid "object doesn't support item deletion" -msgstr "Объект не поддерживает удаление элементов" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" +msgstr "Недействительная строка IP" -#: py/obj.c -msgid "object has no len" -msgstr "Объект не имеет объектива" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" +msgstr "Адрес должен быть длиной %d байт" -#: py/obj.c -msgid "object isn't subscriptable" -msgstr "Объект не имеет индекса" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "Для IP поддерживаются только int или строка" -#: py/runtime.c -msgid "object not an iterator" -msgstr "объект не итератор" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" +msgstr "ширина должна быть больше нуля" -#: py/objtype.c py/runtime.c -msgid "object not callable" -msgstr "Объект не вызывается" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" +msgstr "Размеры шкалы необходимо разделить на 3" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" -msgstr "объект не в последовательности" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" +msgstr "Сопоставление должно быть кортежом" -#: py/runtime.c -msgid "object not iterable" -msgstr "Объект не итерируемый" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" +msgstr "%q должен иметь тип %q, %q или %q, а не %q" -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" -msgstr "объект типа «%s» не имеет len()" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" +msgstr "" +"Не удалось добавить служебную TXT-запись; в txt_records обнаружена нестрока " +"или байт" -#: py/obj.c -msgid "object with buffer protocol required" -msgstr "Объект с обязательным буферным протоколом" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" +msgstr "Обертывание диапазона адресов" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" -msgstr "выключить" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q содержит пины дупликаты" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" -msgstr "Смещение слишком большое" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q и %q содержат пины дупликаты" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" -msgstr "Смещение должно быть >= 0" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" +msgstr "код вне диапазона 0~127" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" -msgstr "Смещение должно быть неотрицательным и не превышать длину буфера" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" +msgstr "По умолчанию не является функцией" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" -msgstr "поддерживается только бит_глубина=16" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" +msgstr "ext_hook не является функцией" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" -msgstr "Поддерживается только моно" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." +msgstr "Невозможно выполнить запись в nvm." -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" -msgstr "только массивы ndarrays могут быть объединены" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" +msgstr "Отсутствует аппаратный генератор случайных чисел" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" -msgstr "поддерживается только выборка = 64" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" +msgstr "Укажите точно один из data0 или data_pins" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" -msgstr "только образец_рейт=16000 поддерживается" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "Недопустимый формат" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" -msgstr "поддерживаются только срезы с шагом = 1 (так как нет)" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." +msgstr "Не удалось отправить команду." -#: py/vm.c -msgid "opcode" -msgstr "код операции" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "Массив должен содержать полуслова (тип 'H')" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" -msgstr "" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" +msgstr "Остановка недоступна с начального запуска" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" -msgstr "" +#: shared-bindings/random/__init__.c +msgid "invalid step" +msgstr "недействительный шаг" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" -msgstr "" +#: shared-bindings/random/__init__.c +msgid "empty sequence" +msgstr "пустая последовательность" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +msgstr "Длина rgb_pins должна быть 6, 12, 18, 24 или 30" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" +msgstr "rgb_pins[%d] не находится на том же порту что и часы" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" +msgstr "rgb_pins[%d] дублирует другое назначение пинов" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" +"Распиновка использует %d байт на элемент, что превышает идеальное %d байт. " +"Если этого нельзя избежать, передайте конструктору allow_inefficient=True" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" -msgstr "Операнды не могут транслироваться вместе" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" +msgstr "Количество используемых rgb-пинов должно быть кратно 6, а не %d" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" -msgstr "операция определена только для 2D-массивов" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +msgstr "" +"Адресные контакты %d, контакты rgb %d и плитки %d обозначают высоту %d, а не " +"%d" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" -msgstr "операция определена только для массивов ndarrays" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" +msgstr "порт должен быть >= 0" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" -msgstr "операция реализована только для 1D логических массивов" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" +msgstr "Слишком маленький буфер для запрашиваемых байтов" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" -msgstr "операция не реализована на массивах ndarrays" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" +msgstr "Имя или услуга не известны" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" -msgstr "Операция не поддерживается для данного типа" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." +msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" -msgstr "операция не поддерживается для типов ввода" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" +msgstr "Контекст на стороне сервера не может иметь имя хоста" -#: py/modbuiltins.c -msgid "ord expects a character" -msgstr "Орд ожидает персонажа" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "Невозможно изменить USB устройство сейчас" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" -msgstr "ord() ожидал символ, но строка длины %d найдена" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" +msgstr "Файл не найден" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" -msgstr "Наш массив слишком мал" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" +msgstr "" +"Временная метка выходит за пределы допустимого диапазона для платформы time_t" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" -msgstr "out имеет неправильный тип" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" +msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" -msgstr "Ключевое слово out не поддерживается для сложного типа d" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" +msgstr "Запись файлов недоступна" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" -msgstr "ключевое слово не поддерживается для функции" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" +msgstr "Недопустимое исключение" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" -msgstr "Out должен быть плотным массивом с плавающей запятой" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" -msgstr "out должен быть массивом ndarray" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" -msgstr "Выход должен быть поплавкового типа" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q, и %q должны быть одной длинны" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" -msgstr "вне досягаемости цели" +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." +msgstr "" +"Объект был деинициализирован и больше не может быть использован. Создайте " +"новый объект." -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" -msgstr "Выходной массив имеет неправильный тип" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "%q должен быть подклассом %q" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" -msgstr "выходной массив должен быть непрерывным" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" +msgstr "Неверный шестнадцатеричный пароль" -#: py/objint_mpz.c -msgid "overflow converting long int to machine word" -msgstr "переполнение преобразование длинного целого в машинное слово" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" +msgstr "Недопустимое имя хоста" -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" -msgstr "Упаковка ожидаемых %d товаров для упаковки (получил %d)" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "Неверный MAC-адрес" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "Длина палитры должна составлять 32 байта" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "Режим авторизации.OPEN не используется с паролем" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/wifi/Radio.c +msgid "Supply either %q or %q, not both" msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" -msgstr "Параметры должны быть регистрами в последовательности от a2 до a5" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "Неверный BSSID" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" -msgstr "Параметры должны быть регистрами в последовательности от r0 до r3" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "Ошибка аутентификации" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" -msgstr "Опрос в файле недоступен в Win32" +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" +msgstr "Нет сети с этим ssid" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" -msgstr "вытолкнуть из пустого импульсного входа" +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" +msgstr "Неизвестный сбой %d" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" -msgstr "Всплывающее окно из пустого %q" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" +msgstr "Нет устройства I2C по адресу: %x" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" -msgstr "порт должен быть >= 0" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "Неверный размер блока формата" -#: py/compile.c -msgid "positional arg after **" -msgstr "позиционный аргумент после **" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" +msgstr "%q образца не совпадает" -#: py/compile.c -msgid "positional arg after keyword arg" -msgstr "позиционный аргумент после ключевого слова аргумента" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" +msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" -msgstr "3-й аргумент pow() не может быть равен 0" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" +msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" -msgstr "pow() с 3 аргументами требует целых чисел" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" -msgstr "Маски вытягивания конфликтуют с масками направления" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "Не удалось выделить место для декодера" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" -msgstr "реальные и воображаемые части должны быть одинаковой длины" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "Не удалось распарсить файл MP3" -#: py/builtinimport.c -msgid "relative import" -msgstr "Относительный импорт" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" +msgstr "%q слишком долго" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" -msgstr "запрашиваемая длина %d, но объект имеет длину %d" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" +msgstr "Размер и глубина растрового изображения должны совпадать" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" -msgstr "Результаты не могут быть приведены к указанному типу" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" +msgstr "неподдерживаемая глубина растрового изображения" -#: py/compile.c -msgid "return annotation must be an identifier" -msgstr "Возвращаемая аннотация должна быть идентификатором" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" +msgstr "Недопустимое бит-на-значение" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" -msgstr "Возврат ожидался '%q', но получил '%q'" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" +msgstr "Только один цвет может быть прозрачным одновременно" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" -msgstr "rgb_pins[%d] дублирует другое назначение пинов" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "Слой уже в группе (Group)" -#: shared-bindings/rgbmatrix/RGBMatrix.c +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "Слой должен быть группой (Group) или субклассом TileGrid" + +#: shared-module/displayio/OnDiskBitmap.c #, c-format -msgid "rgb_pins[%d] is not on the same port as clock" -msgstr "rgb_pins[%d] не находится на том же порту что и часы" +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" +msgstr "" +"Поддерживается только формат Windows, несжатый BMP: заданный размер " +"заголовка - %d" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" -msgstr "аргумент roll должен быть массивом ndarray" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" +msgstr "RLE-сжатый BMP не поддерживается" -#: py/objstr.c -msgid "rsplit(None,n)" -msgstr "rsplit(Нет;n)" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" +msgstr "Не удается прочитать данные цветовой палитры" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" -msgstr "" +#: shared-module/displayio/__init__.c +msgid "Too many displays" +msgstr "Слишком много дисплеев" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" -msgstr "Частота дискретизации выходит за пределы допустимого диапазона" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" +msgstr "Слишком много шин дисплея; забыл displayio.release_displays()?" -#: py/modmicropython.c -msgid "schedule queue full" -msgstr "Расписание Очередь заполнена" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" +msgstr "Неподдерживаемый тип шины дисплея" -#: py/builtinimport.c -msgid "script compilation not supported" -msgstr "Компиляция скриптов не поддерживается" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" +msgstr "неподдерживаемое цветовое пространство для GifWriter" -#: py/nativeglue.c -msgid "set unsupported" -msgstr "Установить не поддерживается" +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" +msgstr "Не удается найти дисплей I2C в %x" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" -msgstr "форма должна быть None, целым числом или кортежем целых чисел" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" -msgstr "фигура должна быть целым числом или кортежом целых чисел" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." +msgstr "Этот микроконтроллер не поддерживает непрерывный захват." -#: shared-module/msgpack/__init__.c -msgid "short read" -msgstr "короткое чтение" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "Светодиодные сопоставления должны соответствовать размеру дисплея" -#: py/objstr.c -msgid "sign not allowed in string format specifier" -msgstr "Знак не разрешен в спецификаторе строкового формата" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" +msgstr "Прерывается функцией выхода" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" -msgstr "Знак не разрешен со спецификатором целочисленного формата 'c'" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" +msgstr "Ошибка устройства или неправильное завершение входного потока" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" -msgstr "размер определен только для массива ndarrays" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" +msgstr "Недостаточный объем памяти для изображения" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" -msgstr "Размер должен соответствовать out.shape при совместном использовании" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" +msgstr "Недостаточный буфер ввода потока" -#: py/nativeglue.c -msgid "slice unsupported" -msgstr "Фрагмент не поддерживается" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" +msgstr "Ошибка параметра" -#: py/objint.c py/sequence.c -msgid "small int overflow" -msgstr "Маленькое переполнение int" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" +msgstr "Ошибка формата данных (возможно, данные повреждены)" -#: main.c -msgid "soft reboot\n" -msgstr "Мягкая перезагрузка\n" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" +msgstr "Правильный формат, но не поддерживается" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" -msgstr "аргумент сортировки должен быть массивом ndarray" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" -msgstr "Массив sos должен иметь форму (n_section, 6)" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" +msgstr "%q() без %q()" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" -msgstr "sos[:, 3] должны быть все единицы" +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" +msgstr "Попытка выделения %d блоков" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" -msgstr "sosфильтр требует повторяющихся аргументов" +#: shared-module/msgpack/__init__.c +msgid "short read" +msgstr "короткое чтение" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" -msgstr "Исходная палитра слишком велика" +#: shared-module/msgpack/__init__.c +msgid "no default packer" +msgstr "Нет упаковщика по умолчанию" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "source_bitmap должен иметь значение_счет 2 или 65536" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." +msgstr "" +"Этот микроконтроллер поддерживает только data0=, а не data_pins=, поскольку " +"для него требуются смежные выводы." -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" -msgstr "source_bitmap должен иметь значение_счет 65536" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" +msgstr "Нет доступного таймера" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" -msgstr "source_bitmap должен иметь значение_счет 8" +#: shared-module/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Internal error #%d" +msgstr "Внутренняя ошибка #%d" -#: extmod/modre.c -msgid "splitting with sub-captures" -msgstr "разделение с помощью подзахватов" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" +msgstr "Таймаут в ожидании карты v1" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" -msgstr "Остановка недоступна с начального запуска" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" +msgstr "Таймаут ожидания карты v2" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" -msgstr "Потоковая операция не поддерживается" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" +msgstr "нет SD карты" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" -msgstr "строковый аргумент без кодировки" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" +msgstr "Не удалось определить версию SD карты" -#: py/objstrunicode.c -msgid "string index out of range" -msgstr "индекс строки выходит за пределы диапазона" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" +msgstr "нет ответа с SD карты" -#: py/objstrunicode.c -#, c-format -msgid "string indices must be integers, not %s" -msgstr "Индексы строк должны быть целыми числами, а не %s" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" +msgstr "Формат CSD SD-карты не поддерживается" -#: py/objarray.c py/objstr.c -msgid "substring not found" -msgstr "Подстрока не найдена" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" +msgstr "Не удается установить размер блока 512" -#: py/compile.c -msgid "super() can't find self" -msgstr "super() не может найти себя" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "Неверный сокет для TLS" -#: extmod/modjson.c -msgid "syntax error in JSON" -msgstr "синтаксис ошибка в JSON" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" +msgstr "Неверный ключ" -#: extmod/modtime.c -msgid "ticks interval overflow" -msgstr "переполнение интервала тиков" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" +msgstr "Неверный сертификат" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" +msgstr "Отсутствует каталог точки монтирования" + +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -"Продолжительность таймаута превысила максимальное поддерживаемое значение" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" -msgstr "таймаут должен быть < 655.35 сек" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' и 'O' не являются поддерживаемыми типами форматов" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" -msgstr "таймаут ожидания потока" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" +msgstr "Размер буфера должен соответствовать формату" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" -msgstr "таймаут ожидания индексного импульса" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "%q должен быть массивом типа 'h \"" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" -msgstr "Таймаут в ожидании карты v1" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" +msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" -msgstr "Таймаут ожидания карты v2" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" +msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" -msgstr "Повторное инициализация таймера" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" +msgstr "Отсутствует подтяжка к земле на пине; Рекомендуется 1 Мегаом" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" -msgstr "" -"Временная метка выходит за пределы допустимого диапазона для платформы time_t" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" +msgstr "Порт USB-хоста не инициализирован" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" -msgstr "Тобайты могут быть вызваны только для плотных массивов" +#: shared-module/usb/core/Device.c +msgid "Pipe error" +msgstr "Ошибка трубопровода" -#: py/compile.c -msgid "too many args" -msgstr "слишком много аргументов" +#: shared-module/usb/core/Device.c +msgid "No configuration set" +msgstr "Нет конфигураций" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" -msgstr "Слишком много измерений" +#: shared-module/usb_hid/Device.c +msgid "USB busy" +msgstr "USB занят" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" -msgstr "Слишком много индексов" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" +msgstr "может иметь только одного родителя" -#: py/asmthumb.c -msgid "too many locals for native method" -msgstr "Слишком много местных жителей для нативного метода" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" +msgstr "Полигону необходимо как минимум 3 точки" -#: py/runtime.c -#, c-format -msgid "too many values to unpack (expected %d)" -msgstr "Слишком много значений для распаковки (ожидаемый %d)" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" +msgstr "Повторное соединение" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" -msgstr "ловушка определена для одномерных 1D массивов одинаковой длины" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" +msgstr "Да" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" -msgstr "ловушка определена для одномерных 1D итераций" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" +msgstr "Выключено" -#: py/obj.c -msgid "tuple/list has wrong length" -msgstr "Кортеж/список имеет неправильную длину" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "[отрезается по длине]" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" -msgstr "twai_driver_install вернул ошибку esp-idf #%d" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" +msgstr "" +"\n" +"Вы в безопасном режиме потому что:\n" + +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." +msgstr "" +"Мощность просела. Убедитесь, что вы обеспечиваете достаточную мощность." -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" -msgstr "twai_start вернул ошибку esp-idf #%d" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" +msgstr "Вы нажали кнопку BOOT при запуске" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" -msgstr "tx и rx не могут быть одновременно None" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." +msgstr "Вы нажали кнопку сброса во время загрузки." -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" -msgstr "Тип '%Q' не является допустимым базовым типом" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "Диск CIRCUTPY не удалось найти или создать." -#: py/objtype.c -msgid "type isn't an acceptable base type" -msgstr "Тип не является приемлемым базовым типом" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." +msgstr "" +"Модуль «микроконтроллер» использовался для загрузки в безопасном режиме." -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" -msgstr "тип объекта '%q' не имеет атрибута '%q \"" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "Ошибка в сейфе. py." -#: py/objtype.c -msgid "type takes 1 or 3 arguments" -msgstr "тип занимает 1 или 3 аргумента" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." +msgstr "Переполнение стека. Увеличьте размер стека." -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "голова длинная слишком большая" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." +msgstr "USB-устройствам требуется больше конечных точек, чем доступно." -#: py/parse.c -msgid "unexpected indent" -msgstr "Неожиданный отступ" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." +msgstr "USB-устройства указывают слишком много имен интерфейсов." -#: py/bc.c -msgid "unexpected keyword argument" -msgstr "Неожиданный аргумент ключевого слова" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "Загрузочное устройство должно быть первым (интерфейс #0)." -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" -msgstr "неожиданный аргумент ключевого слова '%q'" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "Внутренний сторожевой таймер истек." -#: py/lexer.c -msgid "unicode name escapes" -msgstr "Экранирование имен в Юникоде" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "Основной код CircuitPython сильно разбился. Упс!\n" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" -msgstr "Отступ не совпадает ни с одним уровнем внешнего отступа" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." +msgstr "Выделение кучи, когда виртуальная машина не запущена." -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." +msgstr "Не удалось записать внутреннюю флэш-память." -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" -msgstr "Неизвестный спецификатор преобразования %c" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." +msgstr "Жесткая ошибка: доступ к памяти или ошибка инструкции." -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" -msgstr "Неизвестный код формата '%c' для объекта типа '%q'" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." +msgstr "Прерванная ошибка." -#: py/compile.c -msgid "unknown type" -msgstr "Неизвестный тип" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." +msgstr "Прыжок NLR не удался. Вероятно повреждение памяти." -#: py/compile.c -msgid "unknown type '%q'" -msgstr "Неизвестный тип '%q'" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." +msgstr "Невозможно выделить место в куче." -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" -msgstr "Несовпадающий '%c' в формате" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." +msgstr "Неустранимая ошибка прошивки стороннего производителя." -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" -msgstr "Нечитаемый атрибут" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." +msgstr "" +"\n" +"Пожалуйста подайте вопрос с вашей программой на github.com/adafruit/" +"circuitpython/issues." -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" -msgstr "Неподдерживаемый тип %Q" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" +msgstr "" +"\n" +"Нажмите на сброс чтобы выйти из безопасного режима.\n" -#: py/emitinlinethumb.c +#: supervisor/shared/settings.c #, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" -msgstr "неподдерживаемая инструкция Thumb '%s' с аргументами %d" +msgid "An error occurred while retrieving '%s':\n" +msgstr "Произошла ошибка при получении '%s':\n" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" -msgstr "неподдерживаемая инструкция Xtensa '%s' с аргументами %d" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" +msgstr "Недопустимое экранирование Юникода" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" -msgstr "неподдерживаемая глубина растрового изображения" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" -msgstr "неподдерживаемое цветовое пространство для GifWriter" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" +msgstr "выключить" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" -msgstr "Неподдерживаемое цветовое пространство для дизеринга" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "Нет IP" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" -msgstr "Неподдерживаемый символ формата '%c' (0x%x) при индексе %d" +#~ msgid "MITM security not supported" +#~ msgstr "Защита от MITM не поддерживается" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" -msgstr "неподдерживаемый тип для %q: '%s'" +#~ msgid "%q out of bounds" +#~ msgstr "%q за пределом" -#: py/runtime.c -msgid "unsupported type for operator" -msgstr "Неподдерживаемый тип для оператора" +#~ msgid "chr() arg not in range(0x110000)" +#~ msgstr "chr() аргумент вне диапазона (0x110000)" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" -msgstr "Неподдерживаемые типы для %q: '%q', '%q'" +#, c-format +#~ msgid "value must fit in %d byte(s)" +#~ msgstr "Значение должно совпадать с байтами %d" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" -msgstr "Usecols слишком высок" +#~ msgid "Too many descriptors" +#~ msgstr "Слишком много дескрипторов" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" -msgstr "Ключевое слово usecols должно быть указано" +#~ msgid "" +#~ "Unspecified issue. Can be that the pairing prompt on the other device was " +#~ "declined or ignored." +#~ msgstr "" +#~ "Неуказанная проблема. Возможно, запрос на сопряжение на другом устройстве " +#~ "был отклонен или проигнорирован." -#: py/objint.c #, c-format -msgid "value must fit in %d byte(s)" -msgstr "Значение должно совпадать с байтами %d" - -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" -msgstr "Величина выходящая за пределы диапазона цели" - -#: extmod/moddeflate.c -msgid "wbits" -msgstr "" +#~ msgid "SDIO Init Error %x" +#~ msgstr "Ошибка инициализации SDIO %x" -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" -msgstr "" -"Весом должна быть последовательность с нечетным квадратным числом элементов " -"(обычно 9 или 25)" +#~ msgid "bit_depth must be 8, 16, 24, or 32." +#~ msgstr "Глубина_бита должна быть равна 8, 16, 24 или 32." -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " -msgstr "Веса должны быть объектом типа %q, %q, %q или %q, а не %q " +#~ msgid "%q renamed %q" +#~ msgstr "%q переименован %q" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" -msgstr "ширина должна быть больше нуля" +#~ msgid "asm overflow" +#~ msgstr "Переполнение ASM" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" -msgstr "Wi-Fi. Монитор недоступен" +#~ msgid "cannot create instance" +#~ msgstr "Не удается создать экземпляр" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" -msgstr "окно должно быть <= интервал" +#~ msgid "native method too big" +#~ msgstr "родной метод слишком большой" -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" -msgstr "Неправильный индекс оси" +#~ msgid "ulonglong too large" +#~ msgstr "голова длинная слишком большая" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" -msgstr "Указана неправильная ось" +#~ msgid "font must be 2048 bytes long" +#~ msgstr "Длина шрифта должна составлять 2048 байт" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" -msgstr "Неправильный тип" +#~ msgid "graphic must be 2048 bytes long" +#~ msgstr "Длина рисунка должна составлять 2048 байт" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" -msgstr "Неправильный тип индекса" +#~ msgid "palette must be 32 bytes long" +#~ msgstr "Длина палитры должна составлять 32 байта" -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" -msgstr "Неправильный тип ввода" +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Буфер + сдвиг слишком малы %d %d %d" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" -msgstr "неправильная длина массива состояния" +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Буфер байтов должен быть размером 16 байтам." -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" -msgstr "неправильная длина массива индексов" +#~ msgid "UUID integer value must be 0-0xffff" +#~ msgstr "Целое значение UUID должно быть равно 0-0xffff" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" -msgstr "неправильное количество аргументов" +#~ msgid "initial_value length is wrong" +#~ msgstr "длина первоначального_значения ошибочна" -#: py/runtime.c -msgid "wrong number of values to unpack" -msgstr "Неправильное количество значений для распаковки" +#, c-format +#~ msgid "Invalid byte %.*s" +#~ msgstr "Неверный байт %.*s" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" -msgstr "неверный тип вывода" +#~ msgid "Key not found" +#~ msgstr "Ключ не найден" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" -msgstr "зи, должно быть, массивом ndarray" +#~ msgid "Not supported JPEG standard" +#~ msgstr "Не поддерживается Стандарт JPEG" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" -msgstr "zi должно быть типа float" +#~ msgid "%q moved from %q to %q" +#~ msgstr "%q переместился из %q в %q" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" -msgstr "zi должен иметь форму (n_section, 2)" +#~ msgid "filesystem must provide mount method" +#~ msgstr "Файловая система должна предусматривать метод монтирования" #~ msgid "start/end indices" #~ msgstr "Начальные/конечные индексы" @@ -5149,8 +5405,8 @@ msgstr "zi должен иметь форму (n_section, 2)" #~ msgstr "IV должен быть длиной %d байт" #~ msgid "" -#~ "Incompatible .mpy file. Please update all .mpy files. See http://adafru." -#~ "it/mpy-update for more info." +#~ "Incompatible .mpy file. Please update all .mpy files. See http://" +#~ "adafru.it/mpy-update for more info." #~ msgstr "" #~ "Несовместимый файл .mpy. Пожалуйста, обновите все файлы .mpy. См. http://" #~ "adafru.it/mpy-update для получения дополнительной информации." diff --git a/locale/tr.po b/locale/tr.po index 758137eae21..9040e3e57ca 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -7,1096 +7,972 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-06-30 16:02+0000\n" -"Last-Translator: MAE \n" +"PO-Revision-Date: 2026-07-08 15:01+0000\n" +"Last-Translator: H B \n" "Language-Team: none\n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.13-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -"\n" -"Program çalıştırıldı.\n" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -"\n" -"Program otomatik yeniden yükleme tarafından durduruldu. Birazdan tekrar " -"yüklenecek.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -"\n" -"Lütfen programınızla ilgili bir sorunu github.com/adafruit/circuitpython/" -"issues adresinden bildirin." -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -"\n" -"Güvenli moddasın çünkü:\n" - -#: py/obj.c -msgid " File \"%q\"" -msgstr " \"%q\" dosyası" -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " \"%q\" dosyası, %d numaralı satır" +#: extmod/moddeflate.c +msgid "format" +msgstr "" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " nesnesi, %q tipindedir\n" +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" -#: main.c -msgid " not found.\n" -msgstr " bulunamadı.\n" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "" -#: main.c -msgid " output:\n" -msgstr " çıktı:\n" +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modjson.c +msgid "syntax error in JSON" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modrandom.c +msgid "bits must be 32 or less" msgstr "" -"%d adres pinleri, %d RGB pinleri ve %d döşemeleri %d'nin yüksekliği " -"gösterir, %d'nin değil" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q ve %q yinelenen pinler içeriyor" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" +msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q ve %q farklı olmalılar" +#: extmod/modre.c +msgid "splitting with sub-captures" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modre.c +msgid "regex too complex" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" -msgstr "Mod %q olarak ayarlandıktan sonra %q değiştirilemez" +#: extmod/modre.c +msgid "Error in regex" +msgstr "regex'te hata" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q yinelenen pinler içeriyor" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" +msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -msgid "%q failure: %d" -msgstr "%q hata: %d" +#: extmod/modtime.c +msgid "ticks interval overflow" +msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/modzlib.c +msgid "compression header" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q kullanımda" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "" -#: py/objstr.c -msgid "%q index out of range" -msgstr "%q indeksi aralık dışında" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "%q indeksleri integer olmalı, %s değil" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c -msgid "%q init failed" -msgstr "%q init başarısız oldu" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q %q dir" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "%q boyutu %d olmalıdır" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "%q boyutları %d-%d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "%q boyutu <= %d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "%q boyutu >= %d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "" -#: py/runtime.c -msgid "%q moved from %q to %q" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" msgstr "" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q, %d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q, %d-%d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q 1 olmalı, %q True olduğu zaman" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "%q <= %d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" +msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" msgstr "" -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "%q >= %d olmalıdır" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q 'H' ya da 'B' tipi bir bytearray ya da array olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q 'h', 'H', 'b' ya da 'B' tipi bir bytearray ya da array olmalı" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" msgstr "" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q, 2'nin kuvveti olmalıdır" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" +msgstr "" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "%q sınırların dışında" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "%q aralık dışında" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "" -#: py/objmodule.c -msgid "%q renamed %q" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "%q sıfır olamaz" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" -msgstr "%q çok uzun" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" +msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q(), %d konumsal argümanını alır ancak %d verildi" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q ve %q aynı uzunlukta olmalıdır" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "%s hatası 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "'%q' argümanı gerekli" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "" -#: py/proto.c -msgid "'%q' object does not support '%q'" -msgstr "'%q' nesnesi '%q' öğesini desteklemiyor" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "'%q' nesnesi bir iteratör değildir" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "'%q' nesnesi iterable değildir" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' bir etiket bekliyor" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' bir yazmaç bekliyor" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "FFT sadece ndarrays'te tanımlandı" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' özel bir yazmaç bekliyor" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "FFT yalnızca doğrusal diziler için uygulanır" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' bir FPU yazmacı bekliyor" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s', [a, b] biçiminde bir adres bekliyor" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' bir integer bekliyor" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s' en fazla r%d bekler" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' {r0, r1, ...} bekliyor" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' integer %d, %d..%d aralığında değil" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' integer 0x%x, 0x%x maskesine uymuyor" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "'%s' nesnesi, öğe atamasını desteklemiyor" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "'%s' nesnesi, öğe silmeyi desteklemiyor" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "'%s' nesnesinin '%q' özelliği yok" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "'%s' nesnesi subscriptable özelliğe sahip değil" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "'=' hizalamasına string biçiminde izin verilmez" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' ve 'O' desteklenen biçim türlerinden değildir" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "'align' 1 argümana ihtiyaç duyar" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" -#: py/compile.c -msgid "'await' outside function" -msgstr "fonksiyon dışında 'await'" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "" -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "Döngü dışında 'break'/'continue'" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "" -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "'data' en az 2 argümana ihtiyaç duyar" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "" -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "'data' integer tipinde argümanlara ihtiyaç duyar" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "" -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "'label' 1 argümana ihtiyaç duyar" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" -#: py/emitnative.c -msgid "'not' not implemented" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" msgstr "" -#: py/compile.c -msgid "'return' outside function" -msgstr "fonksiyon dışında 'return'" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "" -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "asenkron fonksiyon içinde 'yield from'" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "" -#: py/compile.c -msgid "'yield' outside function" -msgstr "fonksiyon dışında 'yield'" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "" -#: py/compile.c -msgid "* arg after **" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" msgstr "" -#: py/compile.c -msgid "*x must be assignment target" -msgstr "*x atama hedefi olmalıdır" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" -#: py/obj.c -msgid ", in %q\n" -msgstr ", içinde %q\n" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" msgstr "" -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "0.0'dan bir karmaşık güce" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "3-argümanlı pow() desteklenmemektedir" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "Adres %d byte uzunluğunda olmalıdır" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" msgstr "" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "Tüm CAN çevre birimleri kullanımda" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "Tüm I2C çevre birimleri kullanımda" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "Tüm RX FIFO'ları kullanımda" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "Tüm SPI çevre birimleri kullanımda" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "Tüm UART çevre birimleri kullanımda" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "Tüm kanallar kullanımda" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "Tüm olay kanalları kullanımda" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "Tüm durum makineleri kullanımda" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "" -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" -msgstr "Tüm asenkron olay kanalları kullanımda" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "Bu pin için tüm zamanlayıcılar kullanımda" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" +msgstr "" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "Tüm zamanlayıcılar kullanımda" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "Halihazırda duyuruluyor." +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "Tüm eşleşmelerle eşleşen dinleyiciniz var" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "Halihazırda çalışıyor" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "Halihazırda wifi ağları için tarama yapılıyor" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "Başka bir PWMAudioOut zaten aktif durumda" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "Başka bir gönderme zaten aktif" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" +msgstr "" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "Dizi yarımsözcüklere sahip olmalıdır (tip 'H')" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" +msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "Dizi değerleri tekil bytelar olmalıdır." +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" msgstr "" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "%d bloğun ayrılması girişimi" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "Ses dönüşümü implemente edilmedi" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Audio source error" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "AuthMode.OPEN bir şifre ile kullanılmadı" - -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "Kimlik doğrulama hatası" - -#: main.c -msgid "Auto-reload is off.\n" -msgstr "Otomatik yeniden yükleme devre dışı.\n" - -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" msgstr "" -"Otomatik yeniden yükleme aktif. Dosyaları çalıştırmak için USB aracılığı ile " -"kaydedin ya da deaktif etmek için REPL moda girin.\n" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "Baudhızı, çevre birimi tarafından desteklenmiyor" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "" -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "Minimum kare hızından altında" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Bit clock and word select must be sequential GPIO pins" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "Bitmap boyutu ve bit başına değer uyuşmalı" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "Hem RX hem de TX akış kontrolü için gerekli" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "Parlaklık ayarlanabilir değil" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Buffer + offset çok küçük %d %d %d" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" +msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "Buffer elementleri 4 bit olmak zorunda" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "Buffer bir bytearray değil." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "Mevcut arabellek boyutu %d çok büyük. En fazla %d kadar olmalı" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "Buffer bitten %d daha az" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Veriyolu pini %d kullanımda" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Bit buffer'ı 16bit olmalı." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "CBC blokları 16 baytın katları şeklinde olmalı" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "CIRCUITPY sürücüsü bulunamadı veya oluşturulamadı." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC yada checksum geçersiz" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" +msgstr "" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "Yerel nesneye erişmeden önce super().__init__() fonksiyonunu çağırın." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "Sadece alarm RTC IO'yu uyandırabilir." +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "USB aygıtları şu an değiştirilemez" +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "yeni Adaptör oluşturulamadı; _bleio.adapter kullanın;" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" +msgstr "" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "Değerler silinemez" +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "Kapalı dosyada I/O işlemi" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "Çıkış modundayken çekme alınamıyor" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" +msgstr "" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "Isı okunamadı" +#: main.c +msgid "Done" +msgstr "Tamamlandı" -#: shared-bindings/_bleio/Adapter.c -#, fuzzy -msgid "Cannot have scan responses for extended, connectable advertisements." -msgstr "Genişletilmiş, bağlanabilir reklamlar için tarama yanıtları yapılamaz." +#: main.c +msgid " output:\n" +msgstr " çıktı:\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" msgstr "" +"Otomatik yeniden yükleme aktif. Dosyaları çalıştırmak için USB aracılığı ile " +"kaydedin ya da deaktif etmek için REPL moda girin.\n" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Cannot record to a file" -msgstr "Dosyaya kayıt yapılamıyor" +#: main.c +msgid "Auto-reload is off.\n" +msgstr "Otomatik yeniden yükleme devre dışı.\n" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: main.c +msgid "Running in safe mode! Not running saved code.\n" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Cannot set value when direction is input." -msgstr "Yön, giriş olduğunda değer ayarlanamıyor." - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "RS485 modunda RTS veya CTS belirtilemez" - -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "" +#: main.c +msgid " not found.\n" +msgstr " bulunamadı.\n" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" +"\n" +"Program otomatik yeniden yükleme tarafından durduruldu. Birazdan tekrar " +"yüklenecek.\n" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "CharacteristicBuffer yazılmı sağlanmadı" - -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "CircuitPython kor kodu patladı. Haydaaa!\n" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "Saat ünitesi kullanımda" - -#: shared-bindings/_bleio/Connection.c +#: main.c msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." -msgstr "Bağlantı koparıldı ve tekrar kullanılamaz. Yeni bir bağlantı kurun." - -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" +"\n" +"Code done running.\n" msgstr "" +"\n" +"Program çalıştırıldı.\n" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" +#: main.c +msgid "Woken up by alarm.\n" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" +"REPL moda girmek için herhangi bir tuşa basınız. Programı yeniden yüklemek " +"için CTRL+D tuş kombinasyonunu kullanabilirsiniz.\n" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" msgstr "" +"Alarma, CTRL-C'ye veya dosya yazana kadar derin uyku moduna geçiliyor.\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "Adres ayarlanamadı" - -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "Kesinti başlatılamadı, RX kullanımda" - -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "" +#: main.c +msgid "UID:" +msgstr "UID:" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: main.c +msgid "soft reboot\n" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" -msgstr "" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c +msgid "%q init failed" +msgstr "%q init başarısız oldu" -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Device Init Error" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC zaten kullanımda" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "%q aralık dışında" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "Data 0 pini bite hizalı olmalı" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" +msgstr "Geçersiz durum" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "Hem RX hem de TX akış kontrolü için gerekli" -#: shared-bindings/audiobusio/PDMIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "Hedef kapasitesi, hedef_uzunluğundan daha küçük." +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "Cihaz kullanımda" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "Ekran 16 bitlik bir renk uzayına sahip olmalıdır." +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "Tüm UART çevre birimleri kullanımda" -#: shared-bindings/busdisplay/BusDisplay.c +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display rotation must be in 90 degree increments" -msgstr "Ekran dönüşü 90 derecelik artışlarla olmalıdır" +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "Geçersiz %q" -#: main.c -msgid "Done" -msgstr "Tamamlandı" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Drive mode not used when direction is input." -msgstr "Yön, giriş olduğunda sürüş modu kullanılmaz." +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "Tüm asenkron olay kanalları kullanımda" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "Yukarıdaki hatanın işlenmesi sırasında başka bir hata oluştu:" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "Dahili ses arabelleği çok küçük" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB aynı anda yalnızca 16 baytla çalışır" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -msgid "ESP-IDF memory allocation failed" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" msgstr "" -#: extmod/modre.c -msgid "Error in regex" -msgstr "regex'te hata" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "" + +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "Tüm zamanlayıcılar kullanımda" + +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" +msgstr "" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c #: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." +msgid "Unknown reason." msgstr "" -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "FFT sadece ndarrays'te tanımlandı" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" +msgstr "%q ve %q bir saat birimi paylaşmalıdır" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "FFT yalnızca doğrusal diziler için uygulanır" - -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "Komut gönderilemedi." - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "Muteks alınamadı, err 0x%04x" - -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" -msgstr "" - -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" -msgstr "" - -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" -msgstr "" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "Saat ünitesi kullanımda" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "Bağlantı kurulamadı: internal error" - -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "Bağlantı kurulamadı: timeout" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "MP3 dosyası ayrıştırılamadı" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC zaten kullanımda" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "Muteks serbest bırakılamadı, err 0x%04x" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "Tüm olay kanalları kullanımda" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" -msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q, 2'nin kuvveti olmalıdır" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." -msgstr "Dahili flaş yazılamadı." +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "%q pini yok" -#: py/moderrno.c -msgid "File exists" -msgstr "Dosya var" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "Tüm RX FIFO'ları kullanımda" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c -msgid "File not found" -msgstr "" +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "Tüm eşleşmelerle eşleşen dinleyiciniz var" #: ports/atmel-samd/common-hal/canio/Listener.c #: ports/espressif/common-hal/canio/Listener.c @@ -1105,672 +981,673 @@ msgstr "" msgid "Filters too complex" msgstr "Filtreler çok karmaşık" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "Yazılım geçersiz" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "Yazılım çok büyük" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "" -"L8 renk uzayı için, giriş bitmap'i piksel başına 8 bayta sahip olmalıdır" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "" -"RGB renk uzayı için, giriş bitmap'i piksel başına 16 bayta sahip olmalıdır" +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "Çıkış modundayken çekme alınamıyor" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "Format desteklenmiyor" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" +msgstr "Geçersiz veri_pini [%d]" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" msgstr "" -"Frekans 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 ya da 1008 Mhz " -"olmalıdır" - -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "Fonksiyon kilit gerektirir" -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "GNSS init" +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" +msgstr "Geersi %q pin" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "Grup zaten kullanılıyor" - -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "Data 0 pini bite hizalı olmalı" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "Donanım kullanımda, alternatif pinleri deneyin" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "Veriyolu pini %d kullanımda" -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" msgstr "" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "Kapalı dosyada I/O işlemi" - -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "I2C init hatası" - -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "I2C çevre cihazı kullanımda" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "Buffer öğeleri <=4 bayt uzunluğunda olmalı" - -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "Yanlış buffer size" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "Init program boyutu geçersiz" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "İlk pin yönü, ilk çıkış pin yönüyle çakışıyor" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" -msgstr "İlk pinin durumu, ilk çıkış pininin durumu ile çakışıyor" - -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "Giriş buffer uzunluğu (%d) strand sayımının (%d) katı olmalıdır" - #: ports/atmel-samd/common-hal/pulseio/PulseIn.c msgid "Input taking too long" msgstr "Giriş çok uzun sürüyor" -#: py/moderrno.c -msgid "Input/output error" -msgstr "Giriş/çıkış hatası" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" -msgstr "Yetersiz kimlik doğrulama" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" -msgstr "Yetersiz şifreleme" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" -msgstr "" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "Arayüz başlatılmalıdır" - -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "Dahili ses arabelleği çok küçük" - -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" -msgstr "Dahili tanımlama hatası" +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "Başka bir gönderme zaten aktif" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c -msgid "Internal error" -msgstr "Dahili hata" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/socketpool/SocketPool.c +msgid "%q failure: %d" +msgstr "%q hata: %d" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/audiocore/WaveFile.c +#: shared-bindings/emmcio/EMMC.c shared-bindings/floppyio/__init__.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format -msgid "Internal error #%d" -msgstr "Dahili hata #%d" - -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "Dahili bekçi zamanlayıcısının süresi doldu." +msgid "Buffer must be a multiple of %d bytes" +msgstr "Tampon, %d baytların katı olmalıdır" -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +"Bu veri yolunda asenkron SPI transferi devam ediyor, beklemeye devam edin." -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" -msgstr "Geçersiz %q" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "Kamerayı başlat" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "Geersi %q pin" - -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "Geçersiz ADC Ünite değeri" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "Geçersiz BLE parametresi" - -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "Geçersiz BSSID" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "Tampon çok küçük" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "Geçersiz MAC adresi" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "Format desteklenmiyor" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" +msgstr "GNSS init" + +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "Geçersiz argüman" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "Halihazırda çalışıyor" -#: shared-module/displayio/Bitmap.c -#, fuzzy -msgid "Invalid bits per value" -msgstr "Geçersiz bit başına değer" +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q %q dir" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" -msgstr "Geçersiz veri_pini [%d]" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "" -#: shared-module/msgpack/__init__.c -msgid "Invalid format" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." msgstr "" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "Geçersiz biçim yığın boyutu" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "Geçersiz multicast MAC adresi" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "Geçersiz boyut" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." +msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "TLS için geçersiz soket" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" -msgstr "Geçersiz durum" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" +msgstr "" -#: shared-module/os/getenv.c -msgid "Invalid unicode escape" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "Anahtar 16, 24 veya 32 bayt uzunluğunda olmalıdır" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "Bağlantı kurulamadı: internal error" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "Veri, reklam paketi için çok büyük" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "LED eşlemeleri ekran boyutuyla eşleşmelidir" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "Halihazırda duyuruluyor." -#: py/compile.c -msgid "LHS of keyword arg must be an id" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "Katman zaten bir grupta" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "Veri, hedefli reklamcılıkla desteklenmemektedir" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "Katman, bir Grup ya da TileGrid alt sınıfı olmalıdır" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "MAC adresi geçersiz" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" #: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +#: ports/espressif/common-hal/_bleio/Service.c +msgid "Too many %q" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "MMC/SDIO Clock Error %x" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" msgstr "" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" -msgstr "Map tuple olmalıdır" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "Yerel Karakteristikte CCCD ayarlanamaz" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" +#: ports/espressif/common-hal/_bleio/Connection.c +msgid "No pairing in progress" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" +msgstr "Geçersiz BLE parametresi" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Already in progress" +msgstr "Zaten işlemde" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" +msgstr "Yetersiz kimlik doğrulama" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" +msgstr "Yetersiz şifreleme" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" msgstr "" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "Sadece giriş olan pinde pull ayarlanamaz." + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." +msgstr "Derin uykudan uyanırken yalnızca iki düşük pinde alarm tetiklenebilir." + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." +msgstr "" +"Derin uykudan uyanırken, diğerleri yüksek seviyede alarm verecek şekilde " +"ayarlanmışken sadece tek bir düşük pinde alarm tetiklenebilir." + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "Sadece alarm RTC IO'yu uyandırabilir." + +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." msgstr "" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" -msgstr "" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "%q, 'H' dizisi türünde olmalıdır" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" -msgstr "" +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "%q 8, 16, 24 veya 32 olmalıdır" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c shared-bindings/emmcio/EMMC.c +msgid "Peripheral in use" msgstr "" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" -msgstr "NVS hatası" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "%q 8 veya 16 olmalıdır" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "%q pini yok" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" msgstr "" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "No DAC on chip" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA channel found" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "IP yok" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "AudioOut oluşturulamıyor çünkü kesintisiz kanal zaten açık" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" -msgstr "" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "Tüm I2C çevre birimleri kullanımda" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" -msgstr "" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "Tüm SPI çevre birimleri kullanımda" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" -msgstr "" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "RS485 modunda RTS veya CTS belirtilemez" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" msgstr "" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" -msgstr "" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "Baudhızı, çevre birimi tarafından desteklenmiyor" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "" +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "Tüm CAN çevre birimleri kullanımda" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" msgstr "" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" msgstr "" -#: py/moderrno.c -msgid "No space left on device" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" msgstr "" -#: py/moderrno.c -msgid "No such device" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "Yazılım geçersiz" + +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "Yazılım çok büyük" + +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: py/moderrno.c -msgid "No such file/directory" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "Geçersiz argüman" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "Geçersiz boyut" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c +#: shared-bindings/picogame/__init__.c +msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" msgstr "" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c -msgid "Not playing" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC yada checksum geçersiz" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" +msgstr "MAC adresi geçersiz" + +#: ports/espressif/common-hal/espidf/__init__.c #, c-format -msgid "Number of data_pins must be %d or %d, not %d" -msgstr "" +msgid "%s error 0x%x" +msgstr "%s hatası 0x%x" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" -msgstr "" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q kullanımda" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c #, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." +msgid "Unknown error code %d" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" -msgstr "" +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" +msgstr "NVS hatası" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." -msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "DMA yetenekli tampon tahsis edilemedi" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "Dahili hata" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" msgstr "" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "ROS konusuna yayımlanamadı" + +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" +"Yazılımsal yeniden başlatma sırasında kritik ROS hatası, sıfırlama " +"gerekiyor: %d" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" msgstr "" -#: py/moderrno.c -msgid "Operation not permitted" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation timed out" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" msgstr "" #: ports/espressif/common-hal/socketpool/Socket.c @@ -1779,672 +1656,801 @@ msgstr "" msgid "Out of sockets" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" -msgstr "" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "%q, %u değerinden küçük veya eşit olmalıdır" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "Arayüz başlatılmalıdır" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "Geçersiz multicast MAC adresi" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "Halihazırda wifi ağları için tarama yapılıyor" -#: ports/espressif/common-hal/audiobusio/__init__.c -msgid "Peripheral in use" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: py/moderrno.c -msgid "Permission denied" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Only IPv4 addresses supported" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" msgstr "" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" -msgstr "" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +#: shared-bindings/emmcio/EMMC.c +msgid "Hardware in use, try alternative pins" +msgstr "Donanım kullanımda, alternatif pinleri deneyin" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" +"Frekans 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 ya da 1008 Mhz " +"olmalıdır" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" -msgstr "" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "Bağlantı kurulamadı: timeout" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" +#: ports/nordic/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "Numeric comparison pairing" msgstr "" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" msgstr "" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -"REPL moda girmek için herhangi bir tuşa basınız. Programı yeniden yüklemek " -"için CTRL+D tuş kombinasyonunu kullanabilirsiniz.\n" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +msgid "" +"Unspecified issue. The pairing request on the other device may have been " +"declined or ignored." msgstr "" -"Alarma, CTRL-C'ye veya dosya yazana kadar derin uyku moduna geçiliyor.\n" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" +#: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#, c-format +msgid "Unknown security error: 0x%04x" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" -msgstr "" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" +msgstr "Pin kenarı ile uyandırılamaz, yalnızca seviye ile uyanabilir" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" -msgstr "" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "Cihaz kullanımda" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -msgid "Pull not used when direction is output." +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" -msgstr "" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "Tüm kanallar kullanımda" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" -msgstr "" +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "Isı okunamadı" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" -msgstr "" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" +msgstr "Mod %q olarak ayarlandıktan sonra %q değiştirilemez" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" -msgstr "" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "Muteks alınamadı, err 0x%04x" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" -msgstr "" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "Muteks serbest bırakılamadı, err 0x%04x" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" -msgstr "" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "Ses dönüşümü implemente edilmedi" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/__init__.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q; %q veya %q tipi olmalıdır, %q değil" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "Init program boyutu geçersiz" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "Buffer elementleri 4 bit olmak zorunda" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" msgstr "" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "Buffer öğeleri <=4 bayt uzunluğunda olmalı" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" -msgstr "" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "Fonksiyon kilit gerektirir" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" -msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "GPIO0..15, GPIO32..47 ile birlikte kullanılamaz" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" -msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "Bit saati ve kelime seçimi ardışık GPIO pinleri olmalı" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" +msgstr "Ses kaynağı hatası" + +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "%q 16,24 veya 32 olmalıdır" + +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "I2C çevre cihazı kullanımda" + +#: ports/raspberrypi/common-hal/busio/SPI.c shared-bindings/emmcio/EMMC.c +msgid "SPI peripheral in use" msgstr "" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "Tüm durum makineleri kullanımda" + +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" msgstr "" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "Bu pin için tüm zamanlayıcılar kullanımda" + +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q; %q tipi olmalıdır, %q değil" + +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" msgstr "" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" msgstr "" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" msgstr "" -#: shared-module/audiocore/__init__.c -msgid "The sample's %q does not match" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" msgstr "" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" msgstr "" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" +msgstr "İlk pinin durumu, ilk çıkış pininin durumu ile çakışıyor" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" +msgstr "İlk pin yönü, ilk çıkış pin yönüyle çakışıyor" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" msgstr "" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c #, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample." -msgstr "" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "Kullanımdaki tüm dma kanalları" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" -msgstr "" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q bu kart için salt okunur" -#: shared-module/displayio/__init__.c -msgid "Too many displays" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" msgstr "" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" +"Derin uyku pinleri, aşağı çekme direnci ile yükselen kenar kullanmalıdır" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "Geçersiz ADC Ünite değeri" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "DAC cihazı başlatma hatası" + +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "DAC kanalı başlatma hatası" + +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "Başka bir PWMAudioOut zaten aktif durumda" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "Mevcut arabellek boyutu %d çok büyük. En fazla %d kadar olmalı" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "I2C init hatası" + +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" #: ports/stm/common-hal/busio/UART.c -msgid "UART write" -msgstr "" +msgid "Internal define error" +msgstr "Dahili tanımlama hatası" -#: main.c -msgid "UID:" -msgstr "UID:" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "Kesinti başlatılamadı, RX kullanımda" -#: shared-module/usb_hid/Device.c -msgid "USB busy" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Unable to allocate buffers for signed conversion" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -msgid "Unable to create lock" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" msgstr "" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "Unable to find I2C Display at %x" +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: py/parse.c -msgid "Unable to init parser" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" msgstr "" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "Parlaklık ayarlanabilir değil" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q, %d-%d olmalıdır" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "Grup zaten kullanılıyor" + +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "Minimum kare hızından altında" + +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c #, c-format -msgid "Unknown error code %d" +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: shared-bindings/wifi/Radio.c +#: py/argcheck.c #, c-format -msgid "Unknown failure %d" +msgid "function missing %d required positional arguments" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c +#: py/argcheck.c #, c-format -msgid "Unknown gatt error: 0x%04x" +msgid "function expected at most %d arguments, got %d" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." +#: py/argcheck.c shared-bindings/wifi/Radio.c +msgid "'%q' argument required" +msgstr "'%q' argümanı gerekli" + +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c +msgid "argument num/types mismatch" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q, %d olmalıdır" + +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "%q >= %d olmalıdır" + +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "%q <= %d olmalıdır" + +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "%q boyutları %d-%d olmalıdır" + +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "%q boyutu >= %d olmalıdır" + +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "%q boyutu <= %d olmalıdır" + +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "%q boyutu %d olmalıdır" + +#: py/argcheck.c shared-module/audiofilters/__init__.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q'nün içindeki %q, %q tipi olmalıdır, %q değil" + +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q(), %d konumsal argümanını alır ancak %d verildi" + +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" +#: py/binary.c +msgid "integer out of range" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: py/builtinhelp.c +msgid "object " msgstr "" +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " nesnesi, %q tipindedir\n" + #: py/builtinhelp.c #, c-format msgid "" @@ -2455,908 +2461,879 @@ msgid "" "To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" -msgstr "" - -#: main.c -msgid "Woken up by alarm.\n" -msgstr "" - -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" -msgstr "" - -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." -msgstr "" - -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." +#: py/compile.c +msgid "invalid arch" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: py/compile.c +msgid "can't delete expression" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" -msgstr "" +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "Döngü dışında 'break'/'continue'" -#: py/objtype.c -msgid "__init__() should return None" -msgstr "" +#: py/compile.c +msgid "'return' outside function" +msgstr "fonksiyon dışında 'return'" -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" #: py/compile.c -msgid "annotation must be an identifier" +msgid "default 'except' must be last" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" -msgstr "" +#: py/compile.c +msgid "*x must be assignment target" +msgstr "*x atama hedefi olmalıdır" -#: py/objobject.c -msgid "arg must be user-type" +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/compile.c +msgid "* arg after **" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/compile.c +msgid "* arg after kwarg" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/compile.c +msgid "too many args" msgstr "" #: py/compile.c -msgid "argument name reused" +msgid "LHS of keyword arg must be an id" msgstr "" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" -msgstr "" +#: py/compile.c +msgid "'yield' outside function" +msgstr "fonksiyon dışında 'yield'" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "asenkron fonksiyon içinde 'yield from'" #: py/compile.c -msgid "async for/with outside async function" -msgstr "" +msgid "'await' outside function" +msgstr "fonksiyon dışında 'await'" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/compile.c +msgid "argument name reused" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/compile.c +msgid "inline assembler must be a function" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/compile.c +msgid "unknown type" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" -msgstr "" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "'label' 1 argümana ihtiyaç duyar" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/compile.c +msgid "label redefined" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" -msgstr "" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "'align' 1 argümana ihtiyaç duyar" -#: py/objstr.c -msgid "bad format string" -msgstr "" +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "'data' en az 2 argümana ihtiyaç duyar" -#: py/binary.c py/objarray.c -msgid "bad typecode" -msgstr "" +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "'data' integer tipinde argümanlara ihtiyaç duyar" -#: py/emitnative.c -msgid "binary op %q not implemented" +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." +#: py/emitbc.c +msgid "bytecode overflow" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/emitinlinerv32.c +msgid "opcode '%q': registers must be different" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/emitinlinerv32.c +msgid "opcode '%q': malformed register list" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/emitinlinerv32.c +msgid "opcode '%q': invalid stack adjustment" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: wrong register(s)" msgstr "" -#: py/emitbc.c -msgid "bytecode overflow" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" -#: py/objarray.c -msgid "bytes length not a multiple of item size" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: py/objstr.c -msgid "bytes value out of range" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s' en fazla r%d bekler" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "'%s' bir yazmaç bekliyor" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "'%s' özel bir yazmaç bekliyor" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "'%s' bir FPU yazmacı bekliyor" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' {r0, r1, ...} bekliyor" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "'%s' bir integer bekliyor" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' integer 0x%x, 0x%x maskesine uymuyor" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s', [a, b] biçiminde bir adres bekliyor" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' bir etiket bekliyor" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" #: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +msgid "branch not in range" msgstr "" #: py/emitinlinextensa.c msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" -msgstr "" - -#: py/objtype.c -msgid "can't add special method to already-subclassed class" -msgstr "" - -#: py/compile.c -msgid "can't assign to expression" -msgstr "" - -#: extmod/modasyncio.c -msgid "can't cancel self" -msgstr "" - -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: py/obj.c +#: py/emitinlinextensa.c #, c-format -msgid "can't convert %s to complex" -msgstr "" +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' integer %d, %d..%d aralığında değil" -#: py/obj.c +#: py/emitinlinextensa.c #, c-format -msgid "can't convert %s to float" -msgstr "" +msgid "%d is not a multiple of %d" +msgstr "%d %d'nin katı değil" -#: py/objint.c py/runtime.c +#: py/emitinlinextensa.c #, c-format -msgid "can't convert %s to int" -msgstr "" - -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" -msgstr "" - -#: py/obj.c -msgid "can't convert to complex" +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: py/obj.c -msgid "can't convert to float" +#: py/emitnative.c +msgid "conversion to object" msgstr "" -#: py/runtime.c -msgid "can't convert to int" +#: py/emitnative.c +msgid "local '%q' used before type known" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/emitnative.c +msgid "can't load from '%q'" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/emitnative.c +msgid "can't load with '%q' index" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" #: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +msgid "can't store to '%q'" msgstr "" #: py/emitnative.c -msgid "can't do unary op of '%q'" +msgid "can't store with '%q' index" msgstr "" #: py/emitnative.c msgid "can't implicitly convert '%q' to 'bool'" msgstr "" -#: py/runtime.c -msgid "can't import name %q" -msgstr "" - #: py/emitnative.c -msgid "can't load from '%q'" +msgid "'not' not implemented" msgstr "" #: py/emitnative.c -msgid "can't load with '%q' index" +msgid "can't do unary op of '%q'" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" +#: py/emitnative.c +msgid "div/mod not implemented for uint" msgstr "" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/emitnative.c +msgid "comparison of int and uint" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/emitnative.c +msgid "casting" msgstr "" #: py/emitnative.c -msgid "can't store '%q'" +msgid "return expected '%q' but got '%q'" msgstr "" #: py/emitnative.c -msgid "can't store to '%q'" +msgid "native raise" msgstr "" #: py/emitnative.c -msgid "can't store with '%q' index" +msgid "must raise an object" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/modbuiltins.c py/objstr.c +msgid "char not in range(0x110000)" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" -msgstr "" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "3-argümanlı pow() desteklenmemektedir" -#: py/objtype.c -msgid "cannot create instance" +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/moderrno.c +msgid "Operation not permitted" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/moderrno.c +msgid "No such file/directory" msgstr "" -#: py/emitnative.c -msgid "casting" -msgstr "" +#: py/moderrno.c +msgid "Input/output error" +msgstr "Giriş/çıkış hatası" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/moderrno.c +msgid "Permission denied" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" -msgstr "" +#: py/moderrno.c +msgid "File exists" +msgstr "Dosya var" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" +#: py/moderrno.c +msgid "No such device" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" +#: py/moderrno.c +msgid "No space left on device" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" +#: py/modweakref.c +msgid "not a heap object" msgstr "" -#: py/objcomplex.c -msgid "complex divide by zero" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: py/emitnative.c -msgid "conversion to object" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" -msgstr "" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" +msgstr "Yukarıdaki hatanın işlenmesi sırasında başka bir hata oluştu:" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" -msgstr "" +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " \"%q\" dosyası, %d numaralı satır" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" -msgstr "" +#: py/obj.c +msgid " File \"%q\"" +msgstr " \"%q\" dosyası" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" -msgstr "" +#: py/obj.c +msgid ", in %q\n" +msgstr ", içinde %q\n" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/obj.c #, c-format -msgid "data pin #%d in use" +msgid "can't convert %s to complex" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" -msgstr "" +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "%q indeksleri integer olmalı, %s değil" -#: py/objdict.c -msgid "dict update sequence has wrong length" +#: py/obj.c +msgid "object has no len" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" -msgstr "" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "'%s' nesnesi, öğe silmeyi desteklemiyor" -#: py/emitnative.c -msgid "div/mod not implemented for uint" +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "divide by zero" -msgstr "" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "'%s' nesnesi subscriptable özelliğe sahip değil" -#: py/runtime.c -msgid "division by zero" +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" -msgstr "" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "'%s' nesnesi, öğe atamasını desteklemiyor" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: py/objdeque.c -msgid "empty" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: py/objstr.c -msgid "empty separator" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: py/objstr.c -msgid "end of format while looking for conversion specifier" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" -#: py/objstr.c -msgid "expected ':' after format specifier" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: py/obj.c -msgid "expected tuple/list" -msgstr "" +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "0.0'dan bir karmaşık güce" -#: py/modthread.c -msgid "expecting a dict for keyword args" +#: py/objdeque.c +msgid "full" msgstr "" -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objdeque.c +msgid "empty" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objdict.c +msgid "dict update sequence has wrong length" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/objint.c +msgid "float too big" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" -msgstr "" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "%q=%q" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objint_impl.h +#, c-format +msgid "value would overflow a %d byte buffer" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" +#: py/objint_impl.h +msgid "can't convert negative int to unsigned" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: extmod/moddeflate.c -msgid "format" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: py/objstr.c -msgid "format needs a dict" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: py/objstr.c -msgid "format string didn't convert all arguments" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: py/objstr.c -msgid "format string needs more arguments" -msgstr "" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "%q sıfır olamaz" -#: py/objdeque.c -msgid "full" -msgstr "" +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "Alt sınıf kesilemez" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objstr.c +msgid "unknown encoding: %q" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" +#: py/objstr.c +msgid "bytes value out of range" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objstr.c +msgid "empty separator" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" -msgstr "" +#: py/objstr.c +msgid "rsplit(None,n)" +msgstr "rsplit(None,n)" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: py/argcheck.c +#: py/objstr.c #, c-format -msgid "function missing %d required positional arguments" +msgid "unmatched '%c' in format" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" -#: py/bc.c +#: py/objstr.c #, c-format -msgid "function missing required positional argument #%d" +msgid "unknown conversion specifier %c" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" +#: py/objstr.c +msgid "expected ':' after format specifier" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" -msgstr "" +#: py/objstr.c +msgid "%q index out of range" +msgstr "%q indeksi aralık dışında" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" +#: py/objstr.c +msgid "attributes not supported" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/objstr.c +msgid "invalid format specifier" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: py/compile.c -msgid "import * not at module level" -msgstr "" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "'=' hizalamasına string biçiminde izin verilmez" -#: py/persistentcode.c -msgid "incompatible .mpy arch" +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy file" +#: py/objstr.c +msgid "incomplete format key" msgstr "" #: py/objstr.c @@ -3364,775 +3341,880 @@ msgid "incomplete format" msgstr "" #: py/objstr.c -msgid "incomplete format key" +msgid "format string needs more arguments" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" +msgstr "%%c int ya da char gerektirir" + +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" +#: py/objtemplate.c +msgid "expected str or Interpolation" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "Yerel nesneye erişmeden önce super().__init__() fonksiyonunu çağırın." + +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/parse.c +msgid "not a constant" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/parse.c +msgid "Unable to init parser" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: shared-bindings/_bleio/Adapter.c +#: py/parsenum.c +msgid "invalid syntax for integer" +msgstr "" + +#: py/parsenum.c #, c-format -msgid "interval must be in range %s-%s" +msgid "invalid syntax for integer with base %d" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: py/parsenum.c +msgid "invalid syntax for number" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: py/persistentcode.c +msgid "incompatible .mpy arch" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: py/persistentcode.c +msgid "function must be bytecode" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "'%q' nesnesi '%q' öğesini desteklemiyor" + +#: py/qstr.c +msgid "name too long" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for integer" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: py/parsenum.c +#: py/runtime.c #, c-format -msgid "invalid syntax for integer with base %d" +msgid "need more than %d values to unpack" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" -msgstr "" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "'%s' nesnesinin '%q' özelliği yok" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "'%q' nesnesi iterable değildir" + +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: py/compile.c -msgid "label redefined" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "'%q' nesnesi bir iteratör değildir" + +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: py/vm.c -msgid "local variable referenced before assignment" +#: py/runtime.c +msgid "can't convert to int" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: py/parse.c -msgid "malformed f-string" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" +#: py/vm.c +msgid "local variable referenced before assignment" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" +#: py/vm.c +msgid "opcode" msgstr "" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "yeni Adaptör oluşturulamadı; _bleio.adapter kullanın;" + +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "Adres ayarlanamadı" + +#: shared-bindings/_bleio/Adapter.c #, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +msgid "interval must be in range %s-%s" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " -msgstr "" +#: shared-bindings/_bleio/Adapter.c +#, fuzzy +msgid "Cannot have scan responses for extended, connectable advertisements." +msgstr "Genişletilmiş, bağlanabilir reklamlar için tarama yanıtları yapılamaz." -#: py/runtime.c -msgid "maximum recursion depth exceeded" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: py/runtime.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "CharacteristicBuffer yazılmı sağlanmadı" + +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." +msgstr "Bağlantı koparıldı ve tekrar kullanılamaz. Yeni bir bağlantı kurun." + +#: shared-bindings/_bleio/PacketBuffer.c #, c-format -msgid "memory allocation failed, allocating %u bytes" -msgstr "" +msgid "Buffer too short by %d bytes" +msgstr "Buffer bitten %d daha az" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" +#: shared-bindings/_bleio/__init__.c shared-bindings/emmcio/EMMC.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" msgstr "" -#: py/builtinimport.c -msgid "module not found" -msgstr "" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "Yanlış buffer size" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" -#: py/compile.c -msgid "multiple *x in assignment" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" msgstr "" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: py/objtype.c -msgid "multiple inheritance not supported" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" msgstr "" -#: py/emitnative.c -msgid "must raise an object" +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "Anahtar 16, 24 veya 32 bayt uzunluğunda olmalıdır" -#: py/runtime.c -msgid "name '%q' isn't defined" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: py/qstr.c -msgid "name too long" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB aynı anda yalnızca 16 baytla çalışır" + +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "CBC blokları 16 baytın katları şeklinde olmalı" + +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "Dizi değerleri tekil bytelar olmalıdır." -#: py/asmthumb.c -msgid "native method too big" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" msgstr "" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: py/modmath.c -msgid "negative factorial" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: py/objint_mpz.c py/runtime.c -msgid "negative shift count" -msgstr "" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q 'H' ya da 'B' tipi bir bytearray ya da array olmalıdır" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." +msgstr "%q 8'in katı olmalıdır." -#: py/vm.c -msgid "no active exception to reraise" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "Dosyaya kayıt yapılamıyor" -#: py/compile.c -msgid "no binding for nonlocal found" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "Hedef kapasitesi, hedef_uzunluğundan daha küçük." -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/builtinimport.c -msgid "no module named '%q'" -msgstr "" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q 'h', 'H', 'b' ya da 'B' tipi bir bytearray ya da array olmalı" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c +#: shared-bindings/audiodelays/GranularPitchShift.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" -msgstr "" +#: shared-bindings/audioio/AudioOut.c shared-bindings/emmcio/EMMC.c +msgid "%q and %q must be different" +msgstr "%q ve %q farklı olmalılar" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "Bitmap boyutu ve bit başına değer uyuşmalı" -#: py/builtinhelp.c -msgid "object " +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" +"L8 renk uzayı için, giriş bitmap'i piksel başına 8 bayta sahip olmalıdır" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" msgstr "" +"RGB renk uzayı için, giriş bitmap'i piksel başına 16 bayta sahip olmalıdır" -#: py/obj.c -msgid "object doesn't support item assignment" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" +msgstr "Kordinat dizilerinin türlerifarklı boyutlara sahip" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "Kordinat dizilerinin uzunlukları farklı" + +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: py/obj.c +#: shared-bindings/bitmaptools/__init__.c #, c-format -msgid "object of type '%s' has no len()" +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/obj.c -msgid "object with buffer protocol required" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgstr "Giriş buffer uzunluğu (%d) strand sayımının (%d) katı olmalıdır" + +#: shared-bindings/board/__init__.c +msgid "No default %q bus" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "Ekran dönüşü 90 derecelik artışlarla olmalıdır" + +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q 1 olmalı, %q True olduğu zaman" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "Ekran 16 bitlik bir renk uzayına sahip olmalıdır." + +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "Yön, giriş olduğunda değer ayarlanamıyor." + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "Yön, giriş olduğunda sürüş modu kullanılmaz." + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: py/vm.c -msgid "opcode" -msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "%q nesnesinde '%q' metodu eksik" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" -msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "%q nesnesinde '%q' niteliği eksik" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" -msgstr "" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "Değerler silinemez" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/emmcio/EMMC.c shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" -msgstr "" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "Buffer bir bytearray değil." -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" -msgstr "" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" +msgstr "Adres %d byte uzunluğunda olmalıdır" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" -msgstr "" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" +msgstr "Map tuple olmalıdır" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" +msgstr "%q; %q, %q veya %q tipi olmalıdır, %q değil" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" -msgstr "" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" +msgstr "Adres aralığı başa döner" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q yinelenen pinler içeriyor" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q ve %q yinelenen pinler içeriyor" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: py/compile.c -msgid "positional arg after **" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" -msgstr "" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." +msgstr "Komut gönderilemedi." -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" -msgstr "" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "Dizi yarımsözcüklere sahip olmalıdır (tip 'H')" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -4140,445 +4222,556 @@ msgstr "" msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" msgstr "" -#: py/objstr.c -msgid "rsplit(None,n)" -msgstr "rsplit(None,n)" - -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +"%d adres pinleri, %d RGB pinleri ve %d döşemeleri %d'nin yüksekliği " +"gösterir, %d'nin değil" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" msgstr "" -#: py/nativeglue.c -msgid "set unsupported" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: shared-module/msgpack/__init__.c -msgid "short read" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: py/objstr.c -msgid "sign not allowed in string format specifier" -msgstr "" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "USB aygıtları şu an değiştirilemez" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" msgstr "" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: main.c -msgid "soft reboot\n" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "Mikrofon veya hoparlörden en az biri etkinleştirilmiş olmalı" + +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q ve %q aynı uzunlukta olmalıdır" + +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "%q, %q'nün alt türü olmalıdır" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "Geçersiz MAC adresi" + +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "AuthMode.OPEN bir şifre ile kullanılmadı" + +#: shared-bindings/wifi/Radio.c +msgid "Supply either %q or %q, not both" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "Geçersiz BSSID" + +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "Kimlik doğrulama hatası" + +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "Geçersiz biçim yığın boyutu" + +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" +msgstr "%q'nün içindeki %q, %q veya %q tipi olmalıdır, %q değil" + +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "Deşifre edici tahsis edilemedi" + +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "MP3 dosyası ayrıştırılamadı" + +#: shared-module/bitbangio/I2C.c +msgid "%q too long" +msgstr "%q çok uzun" + +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/displayio/Bitmap.c +#, fuzzy +msgid "Invalid bits per value" +msgstr "Geçersiz bit başına değer" + +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" msgstr "" -#: py/objstrunicode.c +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "Katman zaten bir grupta" + +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "Katman, bir Grup ya da TileGrid alt sınıfı olmalıdır" + +#: shared-module/displayio/OnDiskBitmap.c #, c-format -msgid "string indices must be integers, not %s" +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" -msgstr "" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "Kart IOExpander'ı devreden çıkarılamıyor" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "LED eşlemeleri ekran boyutuyla eşleşmelidir" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" msgstr "" -#: py/compile.c -msgid "too many args" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" +msgstr "Veri formatı hatası (bozuk veri olabilir)" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: py/runtime.c +#: shared-module/memorymonitor/AllocationAlarm.c #, c-format -msgid "too many values to unpack (expected %d)" -msgstr "" +msgid "Attempt to allocate %d blocks" +msgstr "%d bloğun ayrılması girişimi" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c +#: shared-module/rgbmatrix/RGBMatrix.c #, c-format -msgid "twai_start returned esp-idf error #%d" +msgid "Internal error #%d" +msgstr "Dahili hata #%d" + +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: py/parse.c -msgid "unexpected indent" -msgstr "" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "TLS için geçersiz soket" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" msgstr "" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" -msgstr "" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." +msgstr "USB üzerinden görünür durumdayken yol yeniden bağlanamaz." -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' ve 'O' desteklenen biçim türlerinden değildir" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" -msgstr "" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "%q, 'h' dizisi türünde olmalıdır" -#: py/compile.c -msgid "unknown type" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/compile.c -msgid "unknown type '%q'" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" msgstr "" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" +#: shared-module/usb/core/Device.c +msgid "Pipe error" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: shared-module/usb/core/Device.c +msgid "No configuration set" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" msgstr "" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" +"\n" +"Güvenli moddasın çünkü:\n" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "CIRCUITPY sürücüsü bulunamadı veya oluşturulamadı." -#: extmod/moddeflate.c -msgid "wbits" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "Önyükleme cihazı birinci olmalı (arayüz #0)." -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "Dahili bekçi zamanlayıcısının süresi doldu." -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "CircuitPython kor kodu patladı. Haydaaa!\n" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." +msgstr "Dahili flaş yazılamadı." -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." msgstr "" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: py/runtime.c -msgid "wrong number of values to unpack" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" +"\n" +"Lütfen programınızla ilgili bir sorunu github.com/adafruit/circuitpython/" +"issues adresinden bildirin." -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" +"\n" +"Güvenli moddan çıkmak için reset'e basın\n" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "'%s' alınırken hata yaşandı:\n" + +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "IP yok" + +#~ msgid "%q out of bounds" +#~ msgstr "%q sınırların dışında" + +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Buffer + offset çok küçük %d %d %d" + +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Bit buffer'ı 16bit olmalı." + #, c-format #~ msgid "%%c requires int or char" #~ msgstr "%%c int veya char tipine ihtiyaç duyar" @@ -4818,8 +5011,8 @@ msgstr "" #~ msgstr "IV %d bayt uzunluğunda olmalı" #~ msgid "" -#~ "Incompatible .mpy file. Please update all .mpy files. See http://adafru." -#~ "it/mpy-update for more info." +#~ "Incompatible .mpy file. Please update all .mpy files. See http://" +#~ "adafru.it/mpy-update for more info." #~ msgstr "" #~ "Uyumsuz .mpy dosyası. Lütfen tüm .mpy dosyalarını güncelleyin. Daha fazla " #~ "bilgi için http://adafru.it/mpy-update ." diff --git a/main.c b/main.c index 91687ff2f8b..8b1ebd4b9fe 100644 --- a/main.c +++ b/main.c @@ -21,6 +21,7 @@ #include "py/stackctrl.h" #include "shared/readline/readline.h" +#include "shared/runtime/gchelper.h" #include "shared/runtime/pyexec.h" #include "background.h" @@ -30,7 +31,6 @@ #include "supervisor/cpu.h" #include "supervisor/filesystem.h" #include "supervisor/port.h" -#include "supervisor/shared/cpu_regs.h" #include "supervisor/shared/reload.h" #include "supervisor/shared/safe_mode.h" #include "supervisor/shared/serial.h" @@ -43,6 +43,7 @@ #include "supervisor/shared/external_flash/external_flash.h" #include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/supervisor/__init__.h" #include "shared-bindings/supervisor/Runtime.h" @@ -83,6 +84,10 @@ #include "shared-module/keypad/__init__.h" #endif +#if CIRCUITPY_AUDIOFILEWRITER +#include "shared-module/audiofilewriter/AudioFileWriter.h" +#endif + #if CIRCUITPY_MEMORYMONITOR #include "shared-module/memorymonitor/__init__.h" #endif @@ -112,35 +117,30 @@ uint8_t value_out = 0; #endif -#if MICROPY_ENABLE_PYSTACK && CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif -static void reset_devices(void) { - #if CIRCUITPY_BLEIO_HCI - bleio_reset(); - #endif -} - static uint8_t *_heap; static uint8_t *_pystack; +static volatile bool _vm_is_running = false; static const char line_clear[] = "\x1b[2K\x1b[0G"; #if MICROPY_ENABLE_PYSTACK || MICROPY_ENABLE_GC static uint8_t *_allocate_memory(safe_mode_t safe_mode, const char *env_key, size_t default_size, size_t *final_size) { *final_size = default_size; - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML if (safe_mode == SAFE_MODE_NONE) { mp_int_t size; - if (common_hal_os_getenv_int(env_key, &size) == GETENV_OK && size > 0) { + if (settings_get_int(env_key, &size) == SETTINGS_OK && size > 0) { *final_size = size; } } #endif uint8_t *ptr = port_malloc(*final_size, false); - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML if (ptr == NULL) { // Fallback to the build size. ptr = port_malloc(default_size, false); @@ -207,28 +207,33 @@ static void start_mp(safe_mode_t safe_mode) { // Always return to root common_hal_os_chdir("/"); + + _vm_is_running = true; } static void stop_mp(void) { + _vm_is_running = false; #if MICROPY_VFS // Unmount all heap allocated vfs mounts. mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); - do { - if (gc_ptr_on_heap(vfs)) { - // mp_vfs_umount will splice out an unmounted vfs from the vfs_mount_table linked list. - mp_vfs_umount(vfs->obj); - // Start over at the beginning of the list since the first entry may have been removed. - vfs = MP_STATE_VM(vfs_mount_table); - continue; - } - vfs = vfs->next; - } while (vfs != NULL); + if (vfs != NULL) { + do { + if (gc_ptr_on_heap(vfs)) { + // mp_vfs_umount will splice out an unmounted vfs from the vfs_mount_table linked list. + mp_vfs_umount(vfs->obj); + // Start over at the beginning of the list since the first entry may have been removed. + vfs = MP_STATE_VM(vfs_mount_table); + continue; + } + vfs = vfs->next; + } while (vfs != NULL); - // The last vfs is CIRCUITPY and the root directory. - vfs = MP_STATE_VM(vfs_mount_table); - while (vfs->next != NULL) { - vfs = vfs->next; + // The last vfs is CIRCUITPY and the root directory. + vfs = MP_STATE_VM(vfs_mount_table); + while (vfs->next != NULL) { + vfs = vfs->next; + } } MP_STATE_VM(vfs_cur) = vfs; #endif @@ -244,6 +249,7 @@ static void stop_mp(void) { qstr_reset(); gc_deinit(); + port_gc_deinit(); port_free(_heap); _heap = NULL; @@ -262,9 +268,10 @@ void supervisor_execution_status(void) { mp_obj_exception_t *exception = MP_OBJ_TO_PTR(_exec_result.exception); if (_current_executing_filename != NULL) { serial_write(_current_executing_filename); - } else if ((_exec_result.return_code & PYEXEC_EXCEPTION) != 0 && - _exec_result.exception_line > 0 && - exception != NULL) { + } else if ( + (_exec_result.return_code == PYEXEC_UNHANDLED_EXCEPTION) && + (_exec_result.exception_line > 0) && + exception != NULL) { mp_printf(&mp_plat_print, "%d@%s %q", _exec_result.exception_line, _exec_result.exception_filename, exception->base.type->name); } else { serial_write_compressed(MP_ERROR_TEXT("Done")); @@ -330,6 +337,9 @@ static void count_strn(void *data, const char *str, size_t len) { } static void cleanup_after_vm(mp_obj_t exception) { + // Do any port cleanup needed before anything else, including releasing board buses. + reset_port_early(); + // Get the traceback of any exception from this run off the heap. // MP_OBJ_SENTINEL means "this run does not contribute to traceback storage, don't touch it" // MP_OBJ_NULL (=0) means "this run completed successfully, clear any stored traceback" @@ -360,9 +370,6 @@ static void cleanup_after_vm(mp_obj_t exception) { } } - // Reset port-independent devices, like CIRCUITPY_BLEIO_HCI. - reset_devices(); - #if CIRCUITPY_ATEXIT atexit_reset(); #endif @@ -376,7 +383,7 @@ static void cleanup_after_vm(mp_obj_t exception) { memorymonitor_reset(); #endif - // Disable user related BLE state that uses the micropython heap. + // Disable user related BLE state that uses the VM heap. Leave BLE workflow running if it's in use. #if CIRCUITPY_BLEIO bleio_user_reset(); #endif @@ -389,6 +396,10 @@ static void cleanup_after_vm(mp_obj_t exception) { keypad_reset(); #endif + #if CIRCUITPY_AUDIOFILEWRITER + audiofilewriter_reset(); + #endif + // Close user-initiated sockets. #if CIRCUITPY_SOCKETPOOL socketpool_user_reset(); @@ -409,8 +420,13 @@ static void cleanup_after_vm(mp_obj_t exception) { // Free the heap last because other modules may reference heap memory and need to shut down. filesystem_flush(); + + // Runs finalisers while shutting down the heap. stop_mp(); + // Don't reset pins until finalisers have run. + reset_all_pins(); + // Let the workflows know we've reset in case they want to restart. supervisor_workflow_reset(); } @@ -429,17 +445,6 @@ static void print_code_py_status_message(safe_mode_t safe_mode) { } static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *simulate_reset) { - bool serial_connected_at_start = serial_connected(); - bool printed_safe_mode_message = false; - #if CIRCUITPY_AUTORELOAD_DELAY_MS > 0 - if (serial_connected_at_start) { - serial_write("\r\n"); - print_code_py_status_message(safe_mode); - print_safe_mode_message(safe_mode); - printed_safe_mode_message = true; - } - #endif - bool skip_repl = false; bool skip_wait = false; bool found_main = false; @@ -513,6 +518,7 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s // Finished executing python code. Cleanup includes filesystem flush and a board reset. + _vm_is_running = false; cleanup_after_vm(_exec_result.exception); _exec_result.exception = NULL; @@ -572,7 +578,7 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s blink_count = 0; } else #endif - if (_exec_result.return_code != PYEXEC_EXCEPTION) { + if (_exec_result.return_code != PYEXEC_UNHANDLED_EXCEPTION) { if (safe_mode == SAFE_MODE_NONE) { color = ALL_DONE; blink_count = ALL_DONE_BLINKS; @@ -638,20 +644,18 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s // If messages haven't been printed yet, print them if (!printed_press_any_key && serial_connected() && !autoreload_pending()) { - if (!serial_connected_at_start) { - print_code_py_status_message(safe_mode); - } - - if (!printed_safe_mode_message) { - print_safe_mode_message(safe_mode); - printed_safe_mode_message = true; - } + print_code_py_status_message(safe_mode); + print_safe_mode_message(safe_mode); serial_write("\r\n"); serial_write_compressed(MP_ERROR_TEXT("Press any key to enter the REPL. Use CTRL-D to reload.\n")); + if (safe_mode != SAFE_MODE_NONE) { + // Reset the port again in safe mode. It doesn't usually do much but + // the Zephyr native_sim tests use it for tracking test completion. + reset_port(); + } printed_press_any_key = true; } if (!serial_connected()) { - serial_connected_at_start = false; printed_press_any_key = false; } @@ -659,7 +663,7 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s #if CIRCUITPY_ALARM if (_exec_result.return_code & PYEXEC_DEEP_SLEEP) { const bool awoke_from_true_deep_sleep = - common_hal_mcu_processor_get_reset_reason() == RESET_REASON_DEEP_SLEEP_ALARM; + common_hal_mcu_processor_get_reset_reason() == MCU_RESET_REASON_DEEP_SLEEP_ALARM; if (fake_sleeping) { // This waits until a pretend deep sleep alarm occurs. They are set @@ -769,8 +773,10 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s // Done waiting, start the board back up. - // We delay resetting BLE until after the wait in case we're transferring - // more files over. + // Resetting BLE is delayed until here, after the wait, in case files were being + // transferred over the BLE workflow during the wait. The reset restarts the BLE + // stack, dropping the workflow connection, only if user code created GATT + // services; otherwise it is a no-op and the connection continues. #if CIRCUITPY_BLEIO bleio_reset(); #endif @@ -794,6 +800,12 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s #if CIRCUITPY_DISPLAYIO common_hal_displayio_auto_primary_display(); #endif + // Undo any preserve_dios. + #if CIRCUITPY_ALARM_PRESERVE_DIOS + common_hal_alarm_clear_pin_preservations(); + #endif + // Reset pins, as if there was a hard reset. + reset_all_pins(); // Pretend that the next run is the first run, as if we were reset. *simulate_reset = true; } @@ -980,8 +992,9 @@ static int run_repl(safe_mode_t safe_mode) { #endif cleanup_after_vm(MP_OBJ_SENTINEL); - // Also reset bleio. The above call omits it in case workflows should continue. In this case, - // we're switching straight to another VM so we want to reset. + // Also reset bleio, which cleanup_after_vm() above omits so workflows can + // continue between VMs. As in run_code_py(), this restarts the BLE stack only if + // user code created GATT services. #if CIRCUITPY_BLEIO bleio_reset(); #endif @@ -1007,8 +1020,12 @@ int __attribute__((used)) main(void) { // initialise the cpu and peripherals set_safe_mode(port_init()); + // All ports need pins reset, after never-reset pins are marked in port_init(); + reset_all_pins(); + port_heap_init(); + // Turn on RX and TX LEDs if we have them. init_rxtx_leds(); @@ -1023,18 +1040,12 @@ int __attribute__((used)) main(void) { serial_early_init(); mp_hal_stdout_tx_str(line_clear); - // Wait briefly to give a reset window where we'll enter safe mode after the reset. - if (get_safe_mode() == SAFE_MODE_NONE) { - set_safe_mode(wait_for_safe_mode_reset()); - } - stack_init(); #if CIRCUITPY_STATUS_BAR supervisor_status_bar_init(); #endif - #if !INTERNAL_FLASH_FILESYSTEM // Set up anything that might need to get done before we try to use SPI flash // This is needed for some boards where flash relies on GPIO setup to work @@ -1051,6 +1062,13 @@ int __attribute__((used)) main(void) { set_safe_mode(SAFE_MODE_NO_CIRCUITPY); } + // Wait briefly to give a reset window where we'll enter safe mode after the reset. + // Do this after mounting the filesystem because settings.toml can contain + // CIRCUITPY_SAFE_MODE_DELAY to change the default delay. + if (get_safe_mode() == SAFE_MODE_NONE) { + set_safe_mode(wait_for_safe_mode_reset()); + } + #if CIRCUITPY_BLEIO // Early init so that a reset press can cause BLE public advertising. Need the filesystem to // read settings.toml. @@ -1068,8 +1086,6 @@ int __attribute__((used)) main(void) { // Reset everything and prep MicroPython to run boot.py. reset_port(); - // Port-independent devices, like CIRCUITPY_BLEIO_HCI. - reset_devices(); reset_board(); // displays init after filesystem, since they could share the flash SPI @@ -1132,7 +1148,7 @@ int __attribute__((used)) main(void) { } else { skip_repl = false; } - } else if (exit_code != 0) { + } else if (exit_code != PYEXEC_NORMAL_EXIT) { break; } @@ -1148,13 +1164,7 @@ int __attribute__((used)) main(void) { void gc_collect(void) { gc_collect_start(); - // Load register values onto the stack. They get collected below with the rest of the stack. - size_t regs[SAVED_REGISTER_COUNT]; - mp_uint_t sp = cpu_get_regs_and_sp(regs); - - // This naively collects all object references from an approximate stack - // range. - gc_collect_root((void **)sp, ((mp_uint_t)port_stack_get_top() - sp) / sizeof(mp_uint_t)); + gc_helper_collect_regs_and_stack(); // This collects root pointers from the VFS mount table. Some of them may // have lost their references in the VM even though they are mounted. @@ -1195,14 +1205,18 @@ size_t gc_get_max_new_split(void) { return port_heap_get_largest_free_size(); } -void NORETURN nlr_jump_fail(void *val) { +void MP_NORETURN nlr_jump_fail(void *val) { reset_into_safe_mode(SAFE_MODE_NLR_JUMP_FAIL); while (true) { } } +bool vm_is_running(void) { + return _vm_is_running; +} + #ifndef NDEBUG -static void NORETURN __fatal_error(const char *msg) { +static void MP_NORETURN __fatal_error(const char *msg) { #if CIRCUITPY_DEBUG == 0 reset_into_safe_mode(SAFE_MODE_HARD_FAULT); #endif diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 989aec68bb5..7d829e79e68 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include #include #include #include @@ -34,16 +35,25 @@ #include "py/persistentcode.h" #include "py/runtime.h" #include "py/gc.h" -#include "py/stackctrl.h" +#include "py/parsenumbase.h" #include "genhdr/mpversion.h" #ifdef _WIN32 // CIRCUITPY-CHANGE #include "fmode.h" #endif +#if MICROPY_EMIT_NATIVE && MICROPY_EMIT_RV32 +#include "py/asmrv32.h" + +static asm_rv32_backend_options_t rv32_options = { 0 }; +#endif + // Command line options, with their defaults static uint emit_opt = MP_EMIT_OPT_NONE; -mp_uint_t mp_verbose_flag = 0; + +#if MICROPY_ENABLE_SOURCE_LINE +static bool include_source_lines = true; +#endif // Heap size of GC heap (if enabled) // Make it larger on a 64 bit machine, because pointers are larger. @@ -82,13 +92,20 @@ static int compile_and_save(const char *file, const char *output_file, const cha source_name = qstr_from_str(source_file); } - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); mp_compiled_module_t cm; cm.context = m_new_obj(mp_module_context_t); + cm.arch_flags = 0; + #if MICROPY_EMIT_NATIVE && MICROPY_EMIT_RV32 + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_RV32IMC && mp_dynamic_compiler.backend_options != NULL) { + cm.arch_flags = ((asm_rv32_backend_options_t *)mp_dynamic_compiler.backend_options)->allowed_extensions; + } + #endif + mp_compile_to_raw_code(&parse_tree, source_name, false, &cm); if ((output_file != NULL && strcmp(output_file, "-") == 0) || @@ -131,7 +148,10 @@ static int usage(char **argv) { "Target specific options:\n" "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" "-march= : set architecture for native emitter;\n" - " x86, x64, armv6, armv6m, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin, rv32imc, debug\n" + " x86, x64, armv6, armv6m, armv7m, armv7em, armv7emsp,\n" + " armv7emdp, xtensa, xtensawin, rv32imc, rv64imc, host, debug\n" + "-march-flags= : set architecture-specific flags (can be either a dec/hex/bin value or a comma-separated flags string)\n" + " supported flags for rv32imc: zba, zcmp\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -148,6 +168,12 @@ static int usage(char **argv) { " heapsize= -- set the heap size for the GC (default %ld)\n" , heap_size); impl_opts_cnt++; + #if MICROPY_ENABLE_SOURCE_LINE + printf( + " source-lines -- include source line numbers (default)\n" + " no-source-lines -- exclude source line numbers\n"); + impl_opts_cnt += 2; + #endif if (impl_opts_cnt == 0) { printf(" (none)\n"); @@ -172,6 +198,14 @@ static void pre_process_options(int argc, char **argv) { } else if (strcmp(argv[a + 1], "emit=viper") == 0) { emit_opt = MP_EMIT_OPT_VIPER; #endif + #if MICROPY_ENABLE_SOURCE_LINE + } else if (strcmp(argv[a + 1], "source-lines") == 0) { + // Allow excluding source lines for debug builds. + include_source_lines = true; + } else if (strcmp(argv[a + 1], "no-source-lines") == 0) { + // Allow excluding source lines for debug builds. + include_source_lines = false; + #endif } else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) { char *end; heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, &end, 0); @@ -212,9 +246,57 @@ static char *backslash_to_forwardslash(char *path) { return path; } -MP_NOINLINE int main_(int argc, char **argv) { - mp_stack_set_limit(40000 * (sizeof(void *) / 4)); +// This will need to be reworked in case mpy-cross needs to set more bits than +// what `unsigned long` can fit. +static bool parse_integer(const char *value, unsigned long *integer) { + assert(value && "Attempting to parse a NULL string"); + assert(integer && "Attempting to store into a NULL integer buffer"); + + size_t value_length = strlen(value); + int base = 0; + size_t skip = mp_parse_num_base(value, value_length, &base); + // These can trip strtoul up. + if (base < 2 || value_length == skip || value[skip] == '+') { + return false; + } + errno = 0; + char *end = NULL; + *integer = strtoul(value + skip, &end, base); + if (end != (value + value_length) || errno != 0) { + return false; + } + return true; +} +#if MICROPY_EMIT_NATIVE && MICROPY_EMIT_RV32 +static bool parse_rv32_flags_string(const char *source, unsigned long *flags) { + assert(source && "Flag arguments string is NULL."); + assert(flags && "Collected flags pointer is NULL."); + + const char *current = source; + const char *end = source + strlen(source); + unsigned long collected_flags = 0; + while (current < end) { + const char *separator = strchr(current, ','); + if (separator == NULL) { + separator = end; + } + ptrdiff_t length = separator - current; + if (length == (sizeof("zba") - 1) && memcmp(current, "zba", length) == 0) { + collected_flags |= RV32_EXT_ZBA; + } else if (length == (sizeof("zcmp") - 1) && memcmp(current, "zcmp", length) == 0) { + collected_flags |= RV32_EXT_ZCMP; + } else { + return false; + } + current = separator + 1; + } + *flags = collected_flags; + return collected_flags != 0; +} +#endif + +MP_NOINLINE int main_(int argc, char **argv) { pre_process_options(argc, argv); char *heap = malloc(heap_size); @@ -237,11 +319,16 @@ MP_NOINLINE int main_(int argc, char **argv) { // 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; + mp_dynamic_compiler.backend_options = NULL; + #if MICROPY_ENABLE_SOURCE_LINE + mp_dynamic_compiler.include_source_lines = include_source_lines; + #endif const char *input_file = NULL; const char *output_file = NULL; const char *source_file = NULL; bool option_parsing_active = true; + const char *arch_flags = NULL; // parse main options for (int a = 1; a < argc; a++) { @@ -254,7 +341,7 @@ MP_NOINLINE int main_(int argc, char **argv) { "; mpy-cross emitting mpy v" MP_STRINGIFY(MPY_VERSION) "." MP_STRINGIFY(MPY_SUB_VERSION) "\n"); return 0; } else if (strcmp(argv[a], "-v") == 0) { - mp_verbose_flag++; + // This verbose option doesn't currently do anything. } else if (strncmp(argv[a], "-O", 2) == 0) { if (unichar_isdigit(argv[a][2])) { MP_STATE_VM(mp_optimise_value) = argv[a][2] & 0xf; @@ -318,6 +405,9 @@ MP_NOINLINE int main_(int argc, char **argv) { } else if (strcmp(arch, "rv32imc") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_RV32IMC; mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_RV32I; + } else if (strcmp(arch, "rv64imc") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_RV64IMC; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_RV64I; } else if (strcmp(arch, "debug") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_DEBUG; mp_dynamic_compiler.nlr_buf_num_regs = 0; @@ -331,6 +421,9 @@ MP_NOINLINE int main_(int argc, char **argv) { #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; + #elif defined(__riscv) && (__riscv_xlen == 64) + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_RV64IMC; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_RV64I; #else mp_printf(&mp_stderr_print, "unable to determine host architecture for -march=host\n"); exit(1); @@ -338,6 +431,8 @@ MP_NOINLINE int main_(int argc, char **argv) { } else { return usage(argv); } + } else if (strncmp(argv[a], "-march-flags=", sizeof("-march-flags=") - 1) == 0) { + arch_flags = argv[a] + sizeof("-march-flags=") - 1; } else if (strcmp(argv[a], "--") == 0) { option_parsing_active = false; } else { @@ -352,6 +447,35 @@ MP_NOINLINE int main_(int argc, char **argv) { } } + if (arch_flags && mp_dynamic_compiler.native_arch != MP_NATIVE_ARCH_NONE) { + bool processed = false; + #if MICROPY_EMIT_NATIVE && MICROPY_EMIT_RV32 + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_RV32IMC) { + mp_dynamic_compiler.backend_options = (void *)&rv32_options; + unsigned long raw_flags = 0; + if (parse_integer(arch_flags, &raw_flags) || parse_rv32_flags_string(arch_flags, &raw_flags)) { + if ((raw_flags & ~((unsigned long)RV32_EXT_ALL)) == 0) { + rv32_options.allowed_extensions = (uint8_t)raw_flags; + processed = true; + } + } + } + #endif + if (!processed) { + mp_printf(&mp_stderr_print, "unrecognised arch flags\n"); + exit(1); + } + } + + #if MICROPY_EMIT_NATIVE + if ((MP_STATE_VM(default_emit_opt) == MP_EMIT_OPT_NATIVE_PYTHON + || MP_STATE_VM(default_emit_opt) == MP_EMIT_OPT_VIPER) + && mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_NONE) { + mp_printf(&mp_stderr_print, "arch not specified\n"); + exit(1); + } + #endif + if (input_file == NULL) { mp_printf(&mp_stderr_print, "no input file\n"); exit(1); @@ -359,19 +483,13 @@ MP_NOINLINE int main_(int argc, char **argv) { int ret = compile_and_save(input_file, output_file, source_file); - #if MICROPY_PY_MICROPYTHON_MEM_INFO - if (mp_verbose_flag) { - mp_micropython_mem_info(0, NULL); - } - #endif - mp_deinit(); return ret & 0xff; } int main(int argc, char **argv) { - mp_stack_ctrl_init(); + mp_cstack_init_with_sp_here(40000 * (sizeof(void *) / 4)); return main_(argc, argv); } diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index edbd9f87c05..3f8e54d878b 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -32,6 +32,7 @@ #define MICROPY_ALLOC_PATH_MAX (PATH_MAX) #define MICROPY_PERSISTENT_CODE_LOAD (0) +#define MICROPY_PERSISTENT_CODE_LOAD_NATIVE (0) #define MICROPY_PERSISTENT_CODE_SAVE (1) #ifndef MICROPY_PERSISTENT_CODE_SAVE_FILE @@ -59,6 +60,7 @@ #define MICROPY_COMP_CONST_FOLDING (1) #define MICROPY_COMP_MODULE_CONST (1) #define MICROPY_COMP_CONST (1) +#define MICROPY_COMP_CONST_FLOAT (1) #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) #define MICROPY_COMP_RETURN_IF_EXPR (1) @@ -83,18 +85,24 @@ #define MICROPY_USE_INTERNAL_PRINTF (0) #define MICROPY_PY_FSTRINGS (1) +#define MICROPY_PY_TSTRINGS (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) -#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) +// Fall back to setjmp() implementation for discovery of GC pointers in registers +// if running on intel-based macOS, or on architectures for which there is no +// specialised GC pointer discovery mechanism. +#if (defined(__APPLE__) && defined(__MACH__) && (defined(__i386__) || defined(__x86_64__))) || \ + (!(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || \ + defined(__thumb2__) || defined(__thumb__) || defined(__arm__))) +#define MICROPY_GCREGS_SETJMP (1) #endif -#define MICROPY_PY___FILE__ (0) +#define MICROPY_MODULE___FILE__ (0) #define MICROPY_PY_ARRAY (0) #define MICROPY_PY_ATTRTUPLE (0) #define MICROPY_PY_COLLECTIONS (0) -#define MICROPY_PY_MATH (0) +#define MICROPY_PY_MATH (MICROPY_COMP_CONST_FLOAT) +#define MICROPY_PY_MATH_CONSTANTS (MICROPY_COMP_CONST_FLOAT) #define MICROPY_PY_CMATH (0) #define MICROPY_PY_GC (0) #define MICROPY_PY_IO (0) @@ -102,23 +110,6 @@ // 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 -#elif defined(__MINGW32__) && defined(_WIN64) -#include -typedef __int64 mp_int_t; -typedef unsigned __int64 mp_uint_t; -#elif defined(_MSC_VER) && defined(_WIN64) -typedef __int64 mp_int_t; -typedef unsigned __int64 mp_uint_t; -#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; @@ -143,7 +134,7 @@ typedef long mp_off_t; #ifdef _MSC_VER #define MP_ENDIANNESS_LITTLE (1) -#define NORETURN __declspec(noreturn) +#define MP_NORETURN __declspec(noreturn) #define MP_NOINLINE __declspec(noinline) #define MP_ALWAYSINLINE __forceinline #define MP_LIKELY(x) (x) diff --git a/mpy-cross/mpy_cross/__init__.py b/mpy-cross/mpy_cross/__init__.py index 91cd6f99335..6d7002a3b89 100644 --- a/mpy-cross/mpy_cross/__init__.py +++ b/mpy-cross/mpy_cross/__init__.py @@ -25,7 +25,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from __future__ import print_function import os import re import stat @@ -44,6 +43,7 @@ "NATIVE_ARCH_XTENSA": "xtensa", "NATIVE_ARCH_XTENSAWIN": "xtensawin", "NATIVE_ARCH_RV32IMC": "rv32imc", + "NATIVE_ARCH_RV64IMC": "rv64imc", } globals().update(NATIVE_ARCHS) diff --git a/mpy-cross/mpy_cross/__main__.py b/mpy-cross/mpy_cross/__main__.py index 2b6b81c3333..fe78a9e077e 100644 --- a/mpy-cross/mpy_cross/__main__.py +++ b/mpy-cross/mpy_cross/__main__.py @@ -25,7 +25,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from __future__ import print_function import argparse import sys diff --git a/ports/analog/Makefile b/ports/analog/Makefile index 0ae276985f7..c81280e11ab 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -154,8 +154,10 @@ LINKERFILE = linking/$(MCU_VARIANT_LOWER)_cktpy.ld LDFLAGS += -nostartfiles -specs=nano.specs endif -SRC_S_UPPER = supervisor/shared/cpu_regs.S SRC_S += $(STARTUPFILE) +SRC_S += shared/runtime/gchelper_thumb2.s + +SRC_C += shared/runtime/gchelper_native.c # Needed to compile some MAX32 headers CFLAGS += -D$(MCU_VARIANT_UPPER) \ @@ -252,7 +254,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) # List of sources for qstr extraction @@ -298,7 +299,7 @@ $(BUILD)/firmware.elf: $(OBJ) $(STEPECHO) "LINK $@" $(Q)echo $^ > $(BUILD)/firmware.objs $(Q)$(CC) -o $@ $(LDFLAGS) @$(BUILD)/firmware.objs -Wl,--print-memory-usage -Wl,--start-group $(LIBS) -Wl,--end-group - $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $(LINKERFILE) $(BUILD) + $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $@.map $(BUILD) $(BUILD)/firmware.hex: $(BUILD)/firmware.elf $(STEPECHO) "Create $@" diff --git a/ports/analog/boards/apard32690/mpconfigboard.mk b/ports/analog/boards/apard32690/mpconfigboard.mk index 7cc54ccfc6d..0e62f25f3f8 100644 --- a/ports/analog/boards/apard32690/mpconfigboard.mk +++ b/ports/analog/boards/apard32690/mpconfigboard.mk @@ -19,7 +19,6 @@ USB_VID=0x0456 USB_PID=0x003C USB_MANUFACTURER="Analog Devices, Inc." USB_PRODUCT="MAX32690 APARD" -USB_HIGHSPEED=1 # NOTE: MAX32 devices do not support IN/OUT pairs on the same EP USB_NUM_ENDPOINT_PAIRS=12 diff --git a/ports/analog/boards/max32690evkit/mpconfigboard.mk b/ports/analog/boards/max32690evkit/mpconfigboard.mk index 61413216d81..a97bc9ddacd 100644 --- a/ports/analog/boards/max32690evkit/mpconfigboard.mk +++ b/ports/analog/boards/max32690evkit/mpconfigboard.mk @@ -19,7 +19,6 @@ USB_VID=0x0456 USB_PID=0x003D USB_MANUFACTURER="Analog Devices, Inc." USB_PRODUCT="MAX32690 EvKit" -USB_HIGHSPEED=1 # NOTE: MAX32 devices do not support IN/OUT pairs on the same EP USB_NUM_ENDPOINT_PAIRS=12 diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 336c04fe039..7ebe721b3f4 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -187,7 +187,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } // Write data to the device selected by address -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { int ret; @@ -202,14 +202,14 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, }; ret = MXC_I2C_MasterTransaction(&wr_req); if (ret) { - return MP_EIO; + return -MP_EIO; } return 0; } // Read into buffer from the device selected by address -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { @@ -226,14 +226,14 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, ret = MXC_I2C_MasterTransaction(&rd_req); if (ret) { // Return I/O error - return MP_EIO; + return -MP_EIO; } return 0; } // Write the bytes from out_data to the device selected by address -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { @@ -249,7 +249,7 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, }; ret = MXC_I2C_MasterTransaction(&wr_rd_req); if (ret) { - return MP_EIO; + return -MP_EIO; } return 0; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index b4a519c37a7..bdbe6da9d94 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -42,7 +42,6 @@ typedef enum { SPI_FREE = 0, SPI_BUSY, - SPI_NEVER_RESET, } spi_status_t; // Set each bit to indicate an active SPI @@ -61,6 +60,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Check for NULL Pointer assert(self); + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + // Assign SPI ID based on pins int spi_id = pinsToSpi(mosi, miso, sck); if (spi_id == -1) { @@ -118,8 +120,6 @@ void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { common_hal_never_reset_pin(self->miso); common_hal_never_reset_pin(self->sck); common_hal_never_reset_pin(self->nss); - - spi_status[self->spi_id] = SPI_NEVER_RESET; } // Check SPI status, deinited or not @@ -127,6 +127,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->sck == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->sck = NULL; +} + // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { @@ -138,8 +142,9 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { self->mosi = NULL; self->miso = NULL; - self->sck = NULL; self->nss = NULL; + + common_hal_busio_spi_mark_deinit(self); } // Configures the SPI bus. The SPI object must be locked. @@ -152,7 +157,6 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, mxc_spi_clkmode_t clk_mode; int ret; - self->baudrate = baudrate; self->polarity = polarity; self->phase = phase; self->bits = bits; @@ -180,6 +184,29 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_baudrate); return false; } + + // MXC_SPI_SetFrequency() floors the clock divisor, so the actual rate can be + // HIGHER than requested. Treat baudrate as a ceiling: if the hardware + // overshoots, bisect downward on the requested target for the highest rate + // that does not exceed baudrate. MXC_SPI_GetFrequency() reports the actual + // configured rate, so we don't depend on the divisor internals. + uint32_t actual = MXC_SPI_GetFrequency(self->spi_regs); + if (actual > baudrate) { + uint32_t lo = 1; // f(lo) <= baudrate + uint32_t hi = baudrate; // f(hi) > baudrate (just measured) + while (hi - lo > 1) { + uint32_t mid = lo + (hi - lo) / 2; + MXC_SPI_SetFrequency(self->spi_regs, mid); + if (MXC_SPI_GetFrequency(self->spi_regs) <= baudrate) { + lo = mid; + } else { + hi = mid; + } + } + MXC_SPI_SetFrequency(self->spi_regs, lo); + actual = MXC_SPI_GetFrequency(self->spi_regs); + } + self->baudrate = actual; ret = MXC_SPI_SetDataSize(self->spi_regs, bits); if (ret == E_BAD_PARAM) { mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_bits); diff --git a/ports/analog/common-hal/microcontroller/Processor.c b/ports/analog/common-hal/microcontroller/Processor.c index 87d8047ff2c..3695ecdf671 100644 --- a/ports/analog/common-hal/microcontroller/Processor.c +++ b/ports/analog/common-hal/microcontroller/Processor.c @@ -42,5 +42,5 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { #if CIRCUITPY_ALARM // TODO: (low prior.) add reset reason in alarm / deepsleep cases (should require alarm peripheral API in "peripherals") #endif - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/analog/linking/max32690_cktpy.ld b/ports/analog/linking/max32690_cktpy.ld index 9b32121a135..e802a8f9612 100644 --- a/ports/analog/linking/max32690_cktpy.ld +++ b/ports/analog/linking/max32690_cktpy.ld @@ -41,6 +41,12 @@ SECTIONS { .text : { . = ALIGN(4); + __property_getter_start = .; + *(.property_getter) + __property_getter_end = .; + __property_getset_start = .; + *(.property_getset) + __property_getset_end = .; _text = .; /* ISR Vector beginning of .text */ @@ -183,4 +189,9 @@ SECTIONS { /* Check if data + heap + stack exceeds RAM limit */ ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack") + + ASSERT((__property_getter_end - __property_getter_start) % 8 == 0, + "the .property_getter section must hold whole 8-byte objects") + ASSERT((__property_getset_end - __property_getset_start) % 12 == 0, + "the .property_getset section must hold whole 12-byte objects") } diff --git a/ports/analog/mpconfigport.h b/ports/analog/mpconfigport.h index c4b3ee031ca..3296661fca7 100644 --- a/ports/analog/mpconfigport.h +++ b/ports/analog/mpconfigport.h @@ -12,6 +12,8 @@ // 24KiB stack #define CIRCUITPY_DEFAULT_STACK_SIZE 0x6000 +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + // Also includes mpconfigboard.h #include "py/circuitpy_mpconfig.h" diff --git a/ports/analog/mpconfigport.mk b/ports/analog/mpconfigport.mk index f1cd0bb2901..63521a27467 100644 --- a/ports/analog/mpconfigport.mk +++ b/ports/analog/mpconfigport.mk @@ -6,6 +6,9 @@ # # SPDX-License-Identifier: MIT +# Properties get a dedicated linker section here, so they can drop the unused slots. +CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 1 + CHIP_FAMILY ?= max32 # Necessary to build CircuitPython diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index 40e8e1d6050..e95deaba2a8 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -67,7 +67,7 @@ static uint32_t subsec, sec = 0; static uint32_t tick_flag = 0; // defined by cmsis core files -extern void NVIC_SystemReset(void) NORETURN; +extern void NVIC_SystemReset(void) MP_NORETURN; volatile uint32_t system_ticks = 0; @@ -126,7 +126,7 @@ safe_mode_t port_init(void) { ; // enable TRNG (true random number generator) - #ifdef CIRCUITPY_RANDOM + #if CIRCUITPY_RANDOM MXC_TRNG_Init(); #endif @@ -166,7 +166,6 @@ void reset_cpu(void) { // Reset MCU state void reset_port(void) { - reset_all_pins(); } // Reset to the bootloader diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 9582eff212d..ad4e65b6ddb 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -169,7 +169,7 @@ LIBS += -lm endif ifeq ($(CHIP_FAMILY), samd21) -LDFLAGS += -mthumb -mcpu=cortex-m0plus -Lasf/thirdparty/CMSIS/Lib/GCC/ +LDFLAGS += -mthumb -mcpu=cortex-m0plus -Lasf/thirdparty/CMSIS/Lib/GCC/ # codespell:ignore thirdparty BOOTLOADER_SIZE := 0x2000 else ifeq ($(CHIP_FAMILY), samd51) LDFLAGS += -mthumb -mcpu=cortex-m4 @@ -284,6 +284,7 @@ SRC_C += \ lib/tinyusb/src/portable/microchip/samd/dcd_samd.c \ mphalport.c \ reset.c \ + shared/runtime/gchelper_native.c \ timer_handler.c \ $(SRC_PERIPHERALS) \ @@ -308,7 +309,11 @@ ifeq ($(CIRCUITPY_AUDIOBUSIO),1) SRC_C += peripherals/samd/i2s.c peripherals/samd/$(PERIPHERALS_CHIP_FAMILY)/i2s.c endif -SRC_S_UPPER = supervisor/shared/cpu_regs.S +ifeq ($(CHIP_FAMILY), samd21) +SRC_S += shared/runtime/gchelper_thumb1.s +else +SRC_S += shared/runtime/gchelper_thumb2.s +endif OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_ASF:.c=.o)) @@ -317,7 +322,7 @@ ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) QSTR_GLOBAL_REQUIREMENTS += $(HEADER_BUILD)/sdiodata.h @@ -343,7 +348,7 @@ $(BUILD)/firmware.elf: $(OBJ) $(GENERATED_LD_FILE) $(STEPECHO) "LINK $@" $(Q)echo $(OBJ) > $(BUILD)/firmware.objs $(Q)$(CC) -o $@ $(LDFLAGS) @$(BUILD)/firmware.objs -Wl,--print-memory-usage -Wl,--start-group $(LIBS) -Wl,--end-group - $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $(GENERATED_LD_FILE) $(BUILD) + $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $@.map $(BUILD) endif $(BUILD)/firmware.bin: $(BUILD)/firmware.elf diff --git a/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h index 5979d1ee997..157db0d3f7f 100644 --- a/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h +++ b/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h @@ -431,7 +431,7 @@ // <0x2=>8x arithmetic // <0x3=>8x fractional // <0x3=>3x -// How many over-sampling bits used when samling data state +// How many over-sampling bits used when sampling data state // usart_arch_sampr #ifndef CONF_SERCOM_2_USART_SAMPR #define CONF_SERCOM_2_USART_SAMPR 0x0 diff --git a/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h index e05560e6358..6dd21277b78 100644 --- a/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h +++ b/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h @@ -431,7 +431,7 @@ // <0x2=>8x arithmetic // <0x3=>8x fractional // <0x3=>3x -// How many over-sampling bits used when samling data state +// How many over-sampling bits used when sampling data state // usart_arch_sampr #ifndef CONF_SERCOM_2_USART_SAMPR #define CONF_SERCOM_2_USART_SAMPR 0x0 diff --git a/ports/atmel-samd/asf4_conf/same51/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/same51/hpl_sercom_config.h index e05560e6358..6dd21277b78 100644 --- a/ports/atmel-samd/asf4_conf/same51/hpl_sercom_config.h +++ b/ports/atmel-samd/asf4_conf/same51/hpl_sercom_config.h @@ -431,7 +431,7 @@ // <0x2=>8x arithmetic // <0x3=>8x fractional // <0x3=>3x -// How many over-sampling bits used when samling data state +// How many over-sampling bits used when sampling data state // usart_arch_sampr #ifndef CONF_SERCOM_2_USART_SAMPR #define CONF_SERCOM_2_USART_SAMPR 0x0 diff --git a/ports/atmel-samd/asf4_conf/same54/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/same54/hpl_sercom_config.h index e05560e6358..6dd21277b78 100644 --- a/ports/atmel-samd/asf4_conf/same54/hpl_sercom_config.h +++ b/ports/atmel-samd/asf4_conf/same54/hpl_sercom_config.h @@ -431,7 +431,7 @@ // <0x2=>8x arithmetic // <0x3=>8x fractional // <0x3=>3x -// How many over-sampling bits used when samling data state +// How many over-sampling bits used when sampling data state // usart_arch_sampr #ifndef CONF_SERCOM_2_USART_SAMPR #define CONF_SERCOM_2_USART_SAMPR 0x0 diff --git a/ports/atmel-samd/background.c b/ports/atmel-samd/background.c index 2410f0fddb7..3d25bd340b1 100644 --- a/ports/atmel-samd/background.c +++ b/ports/atmel-samd/background.c @@ -14,7 +14,7 @@ #include "supervisor/shared/stack.h" #include "supervisor/port.h" -#ifdef CIRCUITPY_DISPLAYIO +#if CIRCUITPY_DISPLAYIO #include "shared-module/displayio/__init__.h" #endif diff --git a/ports/atmel-samd/boards/adafruit_pixel_trinkey_m0/mpconfigboard.mk b/ports/atmel-samd/boards/adafruit_pixel_trinkey_m0/mpconfigboard.mk index 32db497b010..24df3a1fbe1 100644 --- a/ports/atmel-samd/boards/adafruit_pixel_trinkey_m0/mpconfigboard.mk +++ b/ports/atmel-samd/boards/adafruit_pixel_trinkey_m0/mpconfigboard.mk @@ -19,6 +19,7 @@ CIRCUITPY_PWMIO = 1 CIRCUITPY_ROTARYIO = 0 CIRCUITPY_RTC = 0 CIRCUITPY_TOUCHIO = 0 +CIRCUITPY_USB_MIDI = 0 CIRCUITPY_PIXELBUF = 1 diff --git a/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.mk b/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.mk index 5c1cab422cb..32793c20d2f 100755 --- a/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.mk @@ -13,6 +13,7 @@ LONGINT_IMPL = MPZ CIRCUITPY_I2CTARGET = 0 CIRCUITPY_PS2IO = 1 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_SPITARGET = 0 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_TILEPALETTEMAPPER = 0 diff --git a/ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk b/ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk index 2ad140094b3..14744513bbc 100644 --- a/ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk @@ -12,6 +12,7 @@ LONGINT_IMPL = MPZ CIRCUITPY_I2CTARGET = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_SPITARGET = 0 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_TILEPALETTEMAPPER = 0 diff --git a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk index ee414b6e214..206716c6879 100644 --- a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk @@ -19,6 +19,7 @@ CIRCUITPY_I2CTARGET = 0 CIRCUITPY_JPEGIO = 0 CIRCUITPY_PS2IO = 0 CIRCUITPY_SYNTHIO = 0 +CIRCUITPY_VECTORIO = 0 CIRCUITPY_LTO_PARTITION = one diff --git a/ports/atmel-samd/boards/hallowing_m0_express/board.c b/ports/atmel-samd/boards/hallowing_m0_express/board.c index 637129a0e9d..fd5ad548512 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m0_express/board.c @@ -54,9 +54,9 @@ void board_init(void) { common_hal_busio_spi_never_reset(spi); common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA28, // Command or data - &pin_PA01, // Chip select - &pin_PA27, // Reset + MP_OBJ_FROM_PTR(&pin_PA28), // Command or data + MP_OBJ_FROM_PTR(&pin_PA01), // Chip select + MP_OBJ_FROM_PTR(&pin_PA27), // Reset 12000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/hallowing_m4_express/board.c b/ports/atmel-samd/boards/hallowing_m4_express/board.c index bfef5fbcd75..c7217b70b0a 100644 --- a/ports/atmel-samd/boards/hallowing_m4_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m4_express/board.c @@ -35,9 +35,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PB31, // TFT_DC Command or data - &pin_PA27, // TFT_CS Chip select - &pin_PB30, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PB31), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PA27), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PB30), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/hallowing_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/hallowing_m4_express/mpconfigboard.mk index 76c60b44646..0ab7e10c4e1 100644 --- a/ports/atmel-samd/boards/hallowing_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/hallowing_m4_express/mpconfigboard.mk @@ -16,6 +16,7 @@ CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_I2CDISPLAYBUS = 0 CIRCUITPY_I2CTARGET = 0 +CIRCUITPY_LOAD_NATIVE = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_PARALLELDISPLAYBUS = 0 CIRCUITPY_RGBMATRIX = 0 diff --git a/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk b/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk index ebe9403c34d..b20242a4361 100644 --- a/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk +++ b/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk @@ -18,11 +18,13 @@ CIRCUITPY_AUDIOMIXER = 0 CIRCUITPY_AUDIOMP3 = 0 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_DISPLAYIO = 0 +CIRCUITPY_ERRNO = 0 CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_PIXELMAP = 0 CIRCUITPY_GETPASS = 0 CIRCUITPY_KEYPAD = 0 +CIRCUITPY_LOAD_NATIVE = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_PIXELBUF = 0 CIRCUITPY_PS2IO = 0 diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython/board.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/board.c new file mode 100644 index 00000000000..b44a1ae51e0 --- /dev/null +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2017 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.h b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.h new file mode 100644 index 00000000000..4416d8517d2 --- /dev/null +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.h @@ -0,0 +1,33 @@ + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Microchip Curiosity CircuitPython" +#define MICROPY_HW_MCU_NAME "same51j20" +#define CIRCUITPY_MCU_FAMILY samd51 + +#define MICROPY_HW_LED_STATUS (&pin_PB23) +#define MICROPY_HW_NEOPIXEL (&pin_PB22) + +#define BOARD_HAS_CRYSTAL 1 + +// USB is always used internally so skip the pin objects for it. +#define IGNORE_PIN_PA24 1 +#define IGNORE_PIN_PA25 1 + +#define DEFAULT_I2C_BUS_SCL (&pin_PB30) +#define DEFAULT_I2C_BUS_SDA (&pin_PB31) + +#define CIRCUITPY_BOARD_SPI (3) +// These correspond to the CIRCUITPY_BOARD_BUS_SINGLETON definitions in pins.c +#define CIRCUITPY_BOARD_SPI_PIN { \ + {.clock = &pin_PB03, .mosi = &pin_PB02, .miso = &pin_PB00}, /*board.SPI()*/ \ + {.clock = &pin_PA05, .mosi = &pin_PA04, .miso = NULL}, /*board.LCD_SPI()*/ \ + {.clock = &pin_PA17, .mosi = &pin_PA16, .miso = &pin_PA18}, /*board.SD_SPI()*/ \ +} + +#define DEFAULT_CAN_BUS_TX (&pin_PB12) +#define DEFAULT_CAN_BUS_RX (&pin_PB13) +#define DEFAULT_CAN_BUS_STDBY (&pin_PB17) + +#define DEFAULT_UART_BUS_RX (&pin_PA23) +#define DEFAULT_UART_BUS_TX (&pin_PA22) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.mk b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.mk new file mode 100644 index 00000000000..985eb4c6a44 --- /dev/null +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x04D8 +USB_PID = 0xE52B +USB_PRODUCT = "Microchip Curiosity CircuitPython" +USB_MANUFACTURER = "Microchip Technology Inc" + +CHIP_VARIANT = SAME51J20A +CHIP_FAMILY = same51 + +QSPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICES = "SST26VF016B,SST26VF032B,SST26VF064B" +LONGINT_IMPL = MPZ + +CIRCUITPY__EVE = 1 +CIRCUITPY_CANIO = 1 diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c new file mode 100644 index 00000000000..49c7f7565e2 --- /dev/null +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c @@ -0,0 +1,91 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2017 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +// The singleton for board.SPI() is already defined. +// board.LCD_SPI() +CIRCUITPY_BOARD_BUS_SINGLETON(lcd_spi, spi, 1) +// board.SD_SPI() +CIRCUITPY_BOARD_BUS_SINGLETON(sd_spi, spi, 2) + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PA21) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA27) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PB14) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PB15) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PB16) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PB23) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PB22) }, + + { MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_PTR(&pin_PA03) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PB04) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB05) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB06) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PB07) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB09) }, + + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pin_PA02) }, + + { MP_ROM_QSTR(MP_QSTR_CAP1), MP_ROM_PTR(&pin_PB09) }, + + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_LCD_BL), MP_ROM_PTR(&pin_PA06) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB30) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB31) }, + + { MP_ROM_QSTR(MP_QSTR_BLE_TX), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_BLE_RX), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_BLE_CLR), MP_ROM_PTR(&pin_PA14) }, + + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_PA18) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_PA17) }, + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_PA19) }, + + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PB00) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB00) }, + { MP_ROM_QSTR(MP_QSTR_IMU_INT), MP_ROM_PTR(&pin_PB00) }, + + { MP_ROM_QSTR(MP_QSTR_CS), MP_ROM_PTR(&pin_PB01) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PB01) }, + { MP_ROM_QSTR(MP_QSTR_IMU_ADDR), MP_ROM_PTR(&pin_PB01) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB02) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PB02) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB03) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PB03) }, + + { MP_ROM_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_PA22) }, + { MP_ROM_QSTR(MP_QSTR_DEBUG_RX), MP_ROM_PTR(&pin_PA23) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STDBY), MP_ROM_PTR(&pin_PB17) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SPI), MP_ROM_PTR(&board_lcd_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_SD_SPI), MP_ROM_PTR(&board_sd_spi_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/atmel-samd/boards/monster_m4sk/board.c b/ports/atmel-samd/boards/monster_m4sk/board.c index 1d4fd69b7f7..1c143ad9270 100644 --- a/ports/atmel-samd/boards/monster_m4sk/board.c +++ b/ports/atmel-samd/boards/monster_m4sk/board.c @@ -35,9 +35,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA07, // TFT_DC Command or data - &pin_PA06, // TFT_CS Chip select - &pin_PA04, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PA07), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PA06), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA04), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/openbook_m4/board.c b/ports/atmel-samd/boards/openbook_m4/board.c index fb75cac3a4e..ebabfb84e9b 100644 --- a/ports/atmel-samd/boards/openbook_m4/board.c +++ b/ports/atmel-samd/boards/openbook_m4/board.c @@ -44,9 +44,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PB05, // EPD_DC Command or data - &pin_PB07, // EPD_CS Chip select - &pin_PA00, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_PB05), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_PB07), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA00), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk b/ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk index 2701fd249f9..aae02a95325 100644 --- a/ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk @@ -14,6 +14,7 @@ CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_I2CTARGET = 0 CIRCUITPY_JPEGIO = 0 CIRCUITPY_KEYPAD = 1 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_TERMINALIO_VT100 = 0 CIRCUITPY_TILEPALETTEMAPPER = 0 diff --git a/ports/atmel-samd/boards/pewpew_lcd/board.c b/ports/atmel-samd/boards/pewpew_lcd/board.c index 6a10132e11d..d60efd39bf7 100644 --- a/ports/atmel-samd/boards/pewpew_lcd/board.c +++ b/ports/atmel-samd/boards/pewpew_lcd/board.c @@ -54,9 +54,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA19, // TFT_DC Command or data - &pin_PA17, // TFT_CS Chip select - &pin_PA18, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PA19), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PA17), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA18), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/pewpew_m4/board.c b/ports/atmel-samd/boards/pewpew_m4/board.c index 2007d755c69..ac67b82a3dc 100644 --- a/ports/atmel-samd/boards/pewpew_m4/board.c +++ b/ports/atmel-samd/boards/pewpew_m4/board.c @@ -83,9 +83,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA16, // TFT_DC Command or data - &pin_PA11, // TFT_CS Chip select - &pin_PA17, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PA16), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PA11), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA17), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk index 0f239fae93a..9874cc51667 100644 --- a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk @@ -39,6 +39,7 @@ CIRCUITPY_BUSDEVICE = 0 CIRCUITPY_BITMAPFILTER = 0 CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_GIFIO = 0 +CIRCUITPY_LOAD_NATIVE = 0 CIRCUITPY_WATCHDOG = 0 CIRCUITPY_AUDIOIO = 1 diff --git a/ports/atmel-samd/boards/pybadge/board.c b/ports/atmel-samd/boards/pybadge/board.c index 545918374e2..e938e96e19e 100644 --- a/ports/atmel-samd/boards/pybadge/board.c +++ b/ports/atmel-samd/boards/pybadge/board.c @@ -56,9 +56,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PB05, // TFT_DC Command or data - &pin_PB07, // TFT_CS Chip select - &pin_PA00, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PB05), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PB07), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA00), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/pybadge/mpconfigboard.mk b/ports/atmel-samd/boards/pybadge/mpconfigboard.mk index 70571b6c77d..86ce2d47e8c 100644 --- a/ports/atmel-samd/boards/pybadge/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pybadge/mpconfigboard.mk @@ -14,6 +14,7 @@ CIRCUITPY_AESIO = 0 CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_GIFIO = 0 +CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_I2CDISPLAYBUS = 0 CIRCUITPY_JPEGIO = 0 CIRCUITPY_KEYPAD = 1 diff --git a/ports/atmel-samd/boards/pygamer/board.c b/ports/atmel-samd/boards/pygamer/board.c index 53275ac686a..fcf6aff0e65 100644 --- a/ports/atmel-samd/boards/pygamer/board.c +++ b/ports/atmel-samd/boards/pygamer/board.c @@ -57,9 +57,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PB05, // TFT_DC Command or data - &pin_PB12, // TFT_CS Chip select - &pin_PA00, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PB05), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PB12), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA00), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/pygamer/mpconfigboard.mk b/ports/atmel-samd/boards/pygamer/mpconfigboard.mk index 19fa4f19b9d..0c6f16f8b63 100644 --- a/ports/atmel-samd/boards/pygamer/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pygamer/mpconfigboard.mk @@ -12,6 +12,7 @@ LONGINT_IMPL = MPZ CIRCUITPY_AESIO = 0 CIRCUITPY_FLOPPYIO = 0 +CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_GIFIO = 0 CIRCUITPY_I2CDISPLAYBUS = 0 diff --git a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c index d3d1ae3a956..1ee80c98786 100644 --- a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c +++ b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c @@ -52,9 +52,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PC06, // TFT_DC Command or data - &pin_PB21, // TFT_CS Chip select - &pin_PC07, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PC06), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PB21), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PC07), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/silicognition-m4-shim/mpconfigboard.mk b/ports/atmel-samd/boards/silicognition-m4-shim/mpconfigboard.mk index 99c447b7a9d..a8b0677e759 100644 --- a/ports/atmel-samd/boards/silicognition-m4-shim/mpconfigboard.mk +++ b/ports/atmel-samd/boards/silicognition-m4-shim/mpconfigboard.mk @@ -12,6 +12,7 @@ LONGINT_IMPL = MPZ CIRCUITPY_I2CTARGET = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_SPITARGET = 0 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_TILEPALETTEMAPPER = 0 diff --git a/ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk b/ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk index 3ce42ed3a7e..be53ef81119 100644 --- a/ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk +++ b/ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk @@ -16,3 +16,4 @@ CIRCUITPY_SYNTHIO = 0 CIRCUITPY_JPEGIO = 0 CIRCUITPY_TERMINALIO_VT100 = 0 CIRCUITPY_TILEPALETTEMAPPER = 0 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/atmel-samd/boards/ugame10/board.c b/ports/atmel-samd/boards/ugame10/board.c index bbf3839c516..34f769e358f 100644 --- a/ports/atmel-samd/boards/ugame10/board.c +++ b/ports/atmel-samd/boards/ugame10/board.c @@ -53,9 +53,9 @@ void board_init(void) { busio_spi_obj_t *spi = common_hal_board_create_spi(0); common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA09, // Command or data - &pin_PA08, // Chip select - NULL, // Reset + MP_OBJ_FROM_PTR(&pin_PA09), // Command or data + MP_OBJ_FROM_PTR(&pin_PA08), // Chip select + mp_const_none, // Reset 24000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/common-hal/alarm/__init__.c b/ports/atmel-samd/common-hal/alarm/__init__.c index 483aa1a9679..153647f4e89 100644 --- a/ports/atmel-samd/common-hal/alarm/__init__.c +++ b/ports/atmel-samd/common-hal/alarm/__init__.c @@ -127,13 +127,10 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj } void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { - if (n_dios > 0) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); - } _setup_sleep_alarms(true, n_alarms, alarms); } -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_time_timealarm_prepare_for_deep_sleep(); // port_disable_tick(); // TODO: Required for SAMD? diff --git a/ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c b/ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c index 3c1fbb5ba7b..de98b7ec85a 100644 --- a/ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c +++ b/ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c @@ -7,6 +7,6 @@ #include "shared-bindings/alarm/touch/TouchAlarm.h" #include "shared-bindings/microcontroller/__init__.h" -NORETURN void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin) { +MP_NORETURN void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_TouchAlarm); } diff --git a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c index 178db2f07d0..e12fe731000 100644 --- a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c +++ b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c @@ -77,7 +77,11 @@ void i2sout_reset(void) { // Caller validates that pins are free. void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); + } if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } @@ -211,6 +215,9 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, if (common_hal_audiobusio_i2sout_get_playing(self)) { common_hal_audiobusio_i2sout_stop(self); } + + audiosample_check(sample); + #ifdef SAMD21 if ((I2S->CTRLA.vec.CKEN & (1 << self->clock_unit)) == 1) { mp_raise_RuntimeError(MP_ERROR_TEXT("Clock unit in use")); diff --git a/ports/atmel-samd/common-hal/audioio/AudioOut.c b/ports/atmel-samd/common-hal/audioio/AudioOut.c index f7af5e292a7..9bff11fa6b4 100644 --- a/ports/atmel-samd/common-hal/audioio/AudioOut.c +++ b/ports/atmel-samd/common-hal/audioio/AudioOut.c @@ -331,6 +331,9 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, if (common_hal_audioio_audioout_get_playing(self)) { common_hal_audioio_audioout_stop(self); } + + audiosample_check(sample); + audio_dma_result result = AUDIO_DMA_OK; uint32_t sample_rate = audiosample_get_sample_rate(sample); #ifdef SAMD21 diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index da108709fea..d9da050dabe 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -176,7 +176,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { uint16_t attempts = ATTEMPTS; @@ -197,17 +197,17 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, if (status == I2C_OK) { return 0; } else if (status == I2C_ERR_BAD_ADDRESS) { - return MP_ENODEV; + return -MP_ENODEV; } - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { uint16_t attempts = ATTEMPTS; @@ -228,14 +228,14 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, if (status == ERR_NONE) { return 0; } else if (status == I2C_ERR_BAD_ADDRESS) { - return MP_ENODEV; + return -MP_ENODEV; } - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index 5dd7bedebc3..19fd81e425d 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -53,7 +53,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } // Ensure the object starts in its deinit state. - self->clock_pin = NO_PIN; + common_hal_busio_spi_mark_deinit(self); // Special case for SAMR21 boards. (feather_radiofruit_zigbee) #if defined(PIN_PC19F_SERCOM4_PAD0) @@ -184,6 +184,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock_pin == NO_PIN; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock_pin = NO_PIN; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -195,7 +199,9 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { reset_pin_number(self->clock_pin); reset_pin_number(self->MOSI_pin); reset_pin_number(self->MISO_pin); - self->clock_pin = NO_PIN; + + // This smashes self->clock_pin, so don't do it before resetting the pin above. + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/atmel-samd/common-hal/microcontroller/Processor.c b/ports/atmel-samd/common-hal/microcontroller/Processor.c index 95ecde815e6..235229ab34c 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Processor.c +++ b/ports/atmel-samd/common-hal/microcontroller/Processor.c @@ -328,5 +328,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/atmel-samd/common-hal/sdioio/SDCard.c b/ports/atmel-samd/common-hal/sdioio/SDCard.c index 8ff1a391bb2..e38a664ed48 100644 --- a/ports/atmel-samd/common-hal/sdioio/SDCard.c +++ b/ports/atmel-samd/common-hal/sdioio/SDCard.c @@ -9,6 +9,7 @@ #include "py/runtime.h" #include "common-hal/microcontroller/Pin.h" +#include "extmod/vfs.h" #include "shared-bindings/sdioio/SDCard.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/__init__.h" @@ -170,43 +171,85 @@ static void debug_print_state(sdioio_sdcard_obj_t *self, const char *what, sd_mm #endif } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { - check_for_deinit(self); - check_whole_block(bufinfo); +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); self->state_programming = true; - sd_mmc_err_t r = sd_mmc_init_write_blocks(0, start_block, bufinfo->len / 512); + sd_mmc_err_t r = sd_mmc_init_write_blocks(0, start_block, num_blocks); if (r != SD_MMC_OK) { debug_print_state(self, "sd_mmc_init_write_blocks", r); - return -EIO; + return -MP_EIO; } - r = sd_mmc_start_write_blocks(bufinfo->buf, bufinfo->len / 512); + r = sd_mmc_start_write_blocks(buf, num_blocks); if (r != SD_MMC_OK) { debug_print_state(self, "sd_mmc_start_write_blocks", r); - return -EIO; + return -MP_EIO; } - // debug_print_state(self, "after writeblocks OK"); return 0; } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { check_for_deinit(self); check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); - sd_mmc_err_t r = sd_mmc_init_read_blocks(0, start_block, bufinfo->len / 512); + sd_mmc_err_t r = sd_mmc_init_read_blocks(0, start_block, num_blocks); if (r != SD_MMC_OK) { debug_print_state(self, "sd_mmc_init_read_blocks", r); - return -EIO; + return -MP_EIO; } - r = sd_mmc_start_read_blocks(bufinfo->buf, bufinfo->len / 512); + r = sd_mmc_start_read_blocks(buf, num_blocks); if (r != SD_MMC_OK) { debug_print_state(self, "sd_mmc_start_read_blocks", r); - return -EIO; + return -MP_EIO; } sd_mmc_wait_end_of_write_blocks(0); return 0; } +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } +} + bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { check_for_deinit(self); return true; diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h index e953ea0fc50..d6d21c35817 100644 --- a/ports/atmel-samd/mpconfigport.h +++ b/ports/atmel-samd/mpconfigport.h @@ -11,9 +11,6 @@ // Definitions that control circuitpy_mpconfig.h: -// On SAMD, presenting the SD card as a second LUN causes USB disconnect. This needs to be fixed eventually. -#define CIRCUITPY_SDCARD_USB (0) - //////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef SAMD21 @@ -69,6 +66,8 @@ #define CIRCUITPY_MCU_FAMILY samd51 #ifdef SAMD51 #define MICROPY_PY_SYS_PLATFORM "MicroChip SAMD51" +#elif defined(SAME51) +#define MICROPY_PY_SYS_PLATFORM "MicroChip SAME51" #elif defined(SAME54) #define MICROPY_PY_SYS_PLATFORM "MicroChip SAME54" #endif diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index 861ef374646..7da0436c719 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -14,6 +14,8 @@ CIRCUITPY_LTO = 1 CIRCUITPY_KEYPAD_DEMUX ?= 0 CIRCUITPY_LVFONTIO ?= 0 +CIRCUITPY_DIGITALINOUT_PROTOCOL = 0 + ###################################################################### # Put samd21-only choices here. @@ -46,10 +48,10 @@ CIRCUITPY_I2CTARGET ?= 0 CIRCUITPY_JSON ?= 0 CIRCUITPY_KEYPAD ?= 0 CIRCUITPY_MSGPACK ?= 0 -CIRCUITPY_OS_GETENV ?= 0 CIRCUITPY_PIXELMAP ?= 0 CIRCUITPY_RE ?= 0 CIRCUITPY_SDCARDIO ?= 0 +CIRCUITPY_SETTINGS_TOML ?= 0 CIRCUITPY_SPITARGET ?= 0 CIRCUITPY_SYNTHIO ?= 0 CIRCUITPY_TOUCHIO_USE_NATIVE ?= 1 @@ -93,11 +95,11 @@ endif # samd21 ###################################################################### ###################################################################### -# Put samd51-only choices here. +# Put samx5x-only choices here. -ifeq ($(CHIP_FAMILY),samd51) +ifneq ($(filter $(CHIP_FAMILY),samd51 same51 same54),) -# No native touchio on SAMD51. +# No native touchio on SAMx5x. CIRCUITPY_TOUCHIO_USE_NATIVE = 0 ifeq ($(CIRCUITPY_FULL_BUILD),0) @@ -119,6 +121,7 @@ CIRCUITPY_ALARM ?= 1 CIRCUITPY_BITMAPFILTER ?= 0 CIRCUITPY_FLOPPYIO ?= $(CIRCUITPY_FULL_BUILD) CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD) +CIRCUITPY_LOAD_NATIVE ?= 1 CIRCUITPY_MAX3421E ?= $(HAS_1MB_FLASH) CIRCUITPY_PS2IO ?= 1 CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FRAMEBUFFERIO) @@ -133,32 +136,7 @@ ifeq ($(CHIP_VARIANT),SAMD51G19A) CIRCUITPY_AUDIOBUSIO = 0 endif -endif # samd51 -###################################################################### - -###################################################################### -# Put same51-only choices here. - -ifeq ($(CHIP_FAMILY),same51) - -# No native touchio on SAME51. -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 - -ifeq ($(CIRCUITPY_FULL_BUILD),0) -CIRCUITPY_LTO_PARTITION ?= one -endif - -# The ?='s allow overriding in mpconfigboard.mk. - -CIRCUITPY_ALARM ?= 1 -CIRCUITPY_PS2IO ?= 1 -CIRCUITPY_SAMD ?= 1 -CIRCUITPY_FLOPPYIO ?= $(CIRCUITPY_FULL_BUILD) -CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD) -CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FRAMEBUFFERIO) -CIRCUITPY_ULAB_OPTIMIZE_SIZE ?= 1 - -endif # same51 +endif # samx5x ###################################################################### CIRCUITPY_BUILD_EXTENSIONS ?= uf2 diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index 863e615ff98..e98b6b79976 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit 863e615ff98c3a8aa904e87a157553559c933b81 +Subproject commit e98b6b799768d21d8f8e2d0a071f19cf7d80467d diff --git a/ports/atmel-samd/reset.c b/ports/atmel-samd/reset.c index 9cacd4ab951..816e23e3251 100644 --- a/ports/atmel-samd/reset.c +++ b/ports/atmel-samd/reset.c @@ -9,7 +9,7 @@ #include "reset.h" #include "supervisor/filesystem.h" -void NVIC_SystemReset(void) NORETURN; +void NVIC_SystemReset(void) MP_NORETURN; void reset(void) { filesystem_flush(); diff --git a/ports/atmel-samd/reset.h b/ports/atmel-samd/reset.h index c74d25fa01e..248d43779fd 100644 --- a/ports/atmel-samd/reset.h +++ b/ports/atmel-samd/reset.h @@ -16,6 +16,6 @@ extern uint32_t _bootloader_dbl_tap; -void reset_to_bootloader(void) NORETURN; -void reset(void) NORETURN; +void reset_to_bootloader(void) MP_NORETURN; +void reset(void) MP_NORETURN; bool bootloader_available(void); diff --git a/ports/atmel-samd/sd_mmc/sd_mmc.c b/ports/atmel-samd/sd_mmc/sd_mmc.c index 60b4d9f8985..6724e88f42a 100644 --- a/ports/atmel-samd/sd_mmc/sd_mmc.c +++ b/ports/atmel-samd/sd_mmc/sd_mmc.c @@ -160,9 +160,9 @@ static struct sd_mmc_card sd_mmc_cards[CONF_SD_MMC_MEM_CNT]; /** HAL driver instance */ static void *sd_mmc_hal; -/** Index of current slot configurated */ +/** Index of current slot configured */ static uint8_t sd_mmc_slot_sel; -/** Pointer on current slot configurated */ +/** Pointer on current slot configured */ static struct sd_mmc_card *sd_mmc_card; /** Number of block to read or write on the current transfer */ static uint16_t sd_mmc_nb_block_to_tranfer = 0; @@ -238,7 +238,7 @@ static bool mmc_mci_op_cond(void) { uint32_t retry, resp; /* - * Timeout 1s = 400KHz / ((6+6)*8) cylces = 4200 retry + * Timeout 1s = 400KHz / ((6+6)*8) cycles = 4200 retry * 6 = cmd byte size * 6 = response byte size */ @@ -277,7 +277,7 @@ static bool sd_mci_op_cond(uint8_t v2) { uint32_t arg, retry, resp; /* - * Timeout 1s = 400KHz / ((6+6+6+6)*8) cylces = 2100 retry + * Timeout 1s = 400KHz / ((6+6+6+6)*8) cycles = 2100 retry * 6 = cmd byte size * 6 = response byte size * 6 = cmd byte size @@ -339,7 +339,7 @@ static bool sdio_op_cond(void) { /* * Wait card ready - * Timeout 1s = 400KHz / ((6+4)*8) cylces = 5000 retry + * Timeout 1s = 400KHz / ((6+4)*8) cycles = 5000 retry * 6 = cmd byte size * 4(SPI) 6(MCI) = response byte size */ @@ -1292,13 +1292,13 @@ static bool sd_mmc_mci_install_mmc(void) { void sd_mmc_init(void *hal, sd_mmc_detect_t *card_detects, sd_mmc_detect_t *wp_detects) { /* GPIO will be used to detect card and write protect. - * The related clocks and pinmux must be configurated in good + * The related clocks and pinmux must be configured in good * condition. */ for (uint8_t slot = 0; slot < CONF_SD_MMC_MEM_CNT; slot++) { sd_mmc_cards[slot].state = SD_MMC_CARD_STATE_NO_CARD; } - sd_mmc_slot_sel = 0xFF; /* No slot configurated */ + sd_mmc_slot_sel = 0xFF; /* No slot configured */ sd_mmc_hal = hal; _cd = card_detects; _wp = wp_detects; diff --git a/ports/atmel-samd/sd_mmc/sd_mmc.h b/ports/atmel-samd/sd_mmc/sd_mmc.h index cdc98e7108e..7b70a631164 100644 --- a/ports/atmel-samd/sd_mmc/sd_mmc.h +++ b/ports/atmel-samd/sd_mmc/sd_mmc.h @@ -113,7 +113,7 @@ typedef struct sd_mmc_detect { uint16_t val; /**< Detection value */ } sd_mmc_detect_t; -/** This SD MMC stack uses the maximum block size autorized (512 bytes) */ +/** This SD MMC stack uses the maximum block size authorized (512 bytes) */ #define SD_MMC_BLOCK_SIZE 512 /** diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 03c2c2543a7..288446cf62e 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -339,6 +339,7 @@ safe_mode_t port_init(void) { init_shared_dma(); // Reset everything into a known state before board_init. + // Pins are reset in main() after this routine returns. reset_port(); #ifdef SAMD21 @@ -411,8 +412,6 @@ void reset_port(void) { reset_ticks(); } - reset_all_pins(); - // Output clocks for debugging. // not supported by SAMD51G; uncomment for SAMD51J or update for 51G // #ifdef SAM_D5X_E5X @@ -686,7 +685,7 @@ void port_idle_until_interrupt(void) { /** * \brief Default interrupt handler for unused IRQs. */ -__attribute__((used)) NORETURN void HardFault_Handler(void) { +__attribute__((used)) MP_NORETURN void HardFault_Handler(void) { #ifdef ENABLE_MICRO_TRACE_BUFFER // Turn off the micro trace buffer so we don't fill it up in the infinite // loop below. diff --git a/ports/broadcom/Makefile b/ports/broadcom/Makefile index f60ebbf045e..dda93c6fd7c 100644 --- a/ports/broadcom/Makefile +++ b/ports/broadcom/Makefile @@ -59,6 +59,8 @@ SRC_C += bindings/videocore/__init__.c \ SRC_S = peripherals/broadcom/boot$(SUFFIX).s +SRC_C += shared/runtime/gchelper_generic.c + OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) diff --git a/ports/broadcom/common-hal/busio/I2C.c b/ports/broadcom/common-hal/busio/I2C.c index 6a77cec08af..7c1eafe281d 100644 --- a/ports/broadcom/common-hal/busio/I2C.c +++ b/ports/broadcom/common-hal/busio/I2C.c @@ -137,7 +137,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { // Discussion of I2C implementation is here: https://github.com/raspberrypi/linux/issues/254 -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { COMPLETE_MEMORY_READS; self->peripheral->S_b.DONE = true; @@ -182,7 +182,7 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, while (self->peripheral->S_b.ERR == 1) { RUN_BACKGROUND_TASKS; } - return MP_ENODEV; + return -MP_ENODEV; } if (loop_len < len) { @@ -192,19 +192,19 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, return 0; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { COMPLETE_MEMORY_READS; self->peripheral->A_b.ADDR = addr; if (self->finish_write) { self->finish_write = false; if (self->peripheral->S_b.ERR == 1) { - return MP_ENODEV; + return -MP_ENODEV; } self->peripheral->FIFO_b.DATA = self->last_write_data; } else { @@ -236,15 +236,15 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, while (self->peripheral->S_b.ERR == 1) { RUN_BACKGROUND_TASKS; } - return MP_ENODEV; + return -MP_ENODEV; } return 0; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/broadcom/common-hal/busio/SPI.c b/ports/broadcom/common-hal/busio/SPI.c index 2396a9b921e..9e4834e86f3 100644 --- a/ports/broadcom/common-hal/busio/SPI.c +++ b/ports/broadcom/common-hal/busio/SPI.c @@ -30,31 +30,8 @@ static SPI0_Type *spi[NUM_SPI] = {SPI0, NULL, NULL}; static SPI1_Type *aux_spi[NUM_SPI] = {NULL, SPI1, SPI2}; #endif -static bool never_reset_spi[NUM_SPI]; static bool spi_in_use[NUM_SPI]; -void reset_spi(void) { - for (size_t i = 0; i < NUM_SPI; i++) { - if (never_reset_spi[i]) { - continue; - } - - if (i == 1 || i == 2) { - if (i == 1) { - AUX->ENABLES_b.SPI_1 = false; - } else { - AUX->ENABLES_b.SPI_2 = false; - } - aux_spi[i]->CNTL0 = 0; - } else { - // Set CS back to default. All 0 except read enable. - spi[i]->CS = SPI0_CS_REN_Msk; - } - - spi_in_use[i] = false; - } -} - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { @@ -67,6 +44,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError(MP_ERROR_TEXT("Half duplex SPI is not implemented")); } + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + // BCM_VERSION != 2711 have 3 SPI but as listed in peripherals/gen/pins.c two are on // index 0, once one index 0 SPI is found the other will throw an invalid_pins error. for (size_t i = 0; i < NUM_SPI; i++) { @@ -118,8 +98,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[self->index] = true; - common_hal_never_reset_pin(self->clock); common_hal_never_reset_pin(self->MOSI); common_hal_never_reset_pin(self->MISO); @@ -129,16 +107,19 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } - never_reset_spi[self->index] = false; common_hal_reset_pin(self->clock); common_hal_reset_pin(self->MOSI); common_hal_reset_pin(self->MISO); - self->clock = NULL; + spi_in_use[self->index] = false; if (self->index == 1 || @@ -149,7 +130,12 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } else if (self->index == 2) { AUX->ENABLES_b.SPI_2 = false; } + } else { + // Set CS back to default. All 0 except read enable. + spi[self->index]->CS = SPI0_CS_REN_Msk; } + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/broadcom/common-hal/busio/SPI.h b/ports/broadcom/common-hal/busio/SPI.h index aec91263677..3d52b6b0a44 100644 --- a/ports/broadcom/common-hal/busio/SPI.h +++ b/ports/broadcom/common-hal/busio/SPI.h @@ -23,5 +23,3 @@ typedef struct { uint8_t bits; uint8_t index; } busio_spi_obj_t; - -void reset_spi(void); diff --git a/ports/broadcom/common-hal/microcontroller/Processor.c b/ports/broadcom/common-hal/microcontroller/Processor.c index 4956604f9b6..94eafe6c3d1 100644 --- a/ports/broadcom/common-hal/microcontroller/Processor.c +++ b/ports/broadcom/common-hal/microcontroller/Processor.c @@ -31,5 +31,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/broadcom/common-hal/sdioio/SDCard.c b/ports/broadcom/common-hal/sdioio/SDCard.c index f87d40cd8dc..2c9e6a2bb58 100644 --- a/ports/broadcom/common-hal/sdioio/SDCard.c +++ b/ports/broadcom/common-hal/sdioio/SDCard.c @@ -11,6 +11,7 @@ #include "py/runtime.h" #include "common-hal/microcontroller/Pin.h" +#include "extmod/vfs.h" #include "shared-bindings/sdioio/SDCard.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/__init__.h" @@ -304,44 +305,95 @@ static void check_whole_block(mp_buffer_info_t *bufinfo) { } } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +// Native function for VFS blockdev layer +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!self->init) { - return -EIO; + return -MP_EIO; } - check_whole_block(bufinfo); self->state_programming = true; COMPLETE_MEMORY_READS; - sdmmc_err_t error = sdmmc_write_sectors(&self->card_info, bufinfo->buf, - start_block, bufinfo->len / 512); + sdmmc_err_t error = sdmmc_write_sectors(&self->card_info, buf, + start_block, num_blocks); COMPLETE_MEMORY_READS; if (error != SDMMC_OK) { mp_printf(&mp_plat_print, "write sectors result %d\n", error); - return -EIO; + return -MP_EIO; } return 0; } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (!self->init) { - return -EIO; + return -MP_EIO; } check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!self->init) { + return -MP_EIO; + } COMPLETE_MEMORY_READS; - sdmmc_err_t error = sdmmc_read_sectors(&self->card_info, bufinfo->buf, - start_block, bufinfo->len / 512); + sdmmc_err_t error = sdmmc_read_sectors(&self->card_info, buf, + start_block, num_blocks); COMPLETE_MEMORY_READS; if (error != SDMMC_OK) { - mp_printf(&mp_plat_print, "read sectors result %d when reading block %d for %d\n", error, start_block, bufinfo->len / 512); - return -EIO; + mp_printf(&mp_plat_print, "read sectors result %d when reading block %d for %d\n", error, start_block, num_blocks); + return -MP_EIO; } return 0; } +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + if (!self->init) { + return -MP_EIO; + } + check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } +} + bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { if (!self->init) { return false; diff --git a/ports/broadcom/mpconfigport.h b/ports/broadcom/mpconfigport.h index 8b749ca0310..73fae8295de 100644 --- a/ports/broadcom/mpconfigport.h +++ b/ports/broadcom/mpconfigport.h @@ -26,6 +26,8 @@ #define MICROPY_FATFS_EXFAT (1) #define MICROPY_FATFS_MKFS_FAT32 (1) +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + //////////////////////////////////////////////////////////////////////////////////////////////////// // This also includes mpconfigboard.h. diff --git a/ports/broadcom/mpconfigport.mk b/ports/broadcom/mpconfigport.mk index d906b5d2aa4..844794b107a 100644 --- a/ports/broadcom/mpconfigport.mk +++ b/ports/broadcom/mpconfigport.mk @@ -22,7 +22,6 @@ CIRCUITPY_VIDEOCORE = 1 INTERNAL_FLASH_FILESYSTEM = 1 USB_NUM_ENDPOINT_PAIRS = 8 -USB_HIGHSPEED = 1 CIRCUITPY_BUILD_EXTENSIONS ?= disk.img.zip,kernel8.img diff --git a/ports/broadcom/supervisor/port.c b/ports/broadcom/supervisor/port.c index 83dd50f1b8b..a0f0be30dd7 100644 --- a/ports/broadcom/supervisor/port.c +++ b/ports/broadcom/supervisor/port.c @@ -67,7 +67,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO reset_i2c(); - reset_spi(); reset_uart(); #endif @@ -85,8 +84,6 @@ void reset_port(void) { #if CIRCUITPY_AUDIOCORE audio_dma_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/cxd56/Makefile b/ports/cxd56/Makefile index fdf3646c80d..88c39210220 100644 --- a/ports/cxd56/Makefile +++ b/ports/cxd56/Makefile @@ -74,7 +74,7 @@ CFLAGS += \ -fdata-sections \ -Wall \ -OPTIMIZATION_FLAGS ?= -O2 -fno-inline-functions +OPTIMIZATION_FLAGS ?= -O2 # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk CFLAGS += $(OPTIMIZATION_FLAGS) @@ -110,7 +110,9 @@ LDFLAGS = \ CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_CXD56 -DCFG_TUD_MIDI_RX_BUFSIZE=512 -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD_MIDI_TX_BUFSIZE=512 -DCFG_TUD_CDC_TX_BUFSIZE=1024 -DCFG_TUD_MSC_BUFSIZE=512 $(CFLAGS_MOD) -SRC_S_UPPER = supervisor/shared/cpu_regs.S +SRC_S = shared/runtime/gchelper_thumb2.s + +SRC_C += shared/runtime/gchelper_native.c SRC_C += \ background.c \ @@ -120,7 +122,7 @@ SRC_C += \ lib/tinyusb/src/portable/sony/cxd56/dcd_cxd56.c \ OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) diff --git a/ports/cxd56/common-hal/busio/I2C.c b/ports/cxd56/common-hal/busio/I2C.c index fb33c242a03..8e846b2402d 100644 --- a/ports/cxd56/common-hal/busio/I2C.c +++ b/ports/cxd56/common-hal/busio/I2C.c @@ -91,7 +91,7 @@ bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { return I2C_TRANSFER(self->i2c_dev, &msg, 1) < 0 ? false : true; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, const uint8_t *data, size_t len, bool stop) { +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, const uint8_t *data, size_t len, bool stop) { struct i2c_msg_s msg; msg.frequency = self->frequency; @@ -102,12 +102,12 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addre return -I2C_TRANSFER(self->i2c_dev, &msg, 1); } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *data, size_t len) { struct i2c_msg_s msg; msg.frequency = self->frequency; @@ -118,9 +118,9 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8 return -I2C_TRANSFER(self->i2c_dev, &msg, 1); } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/cxd56/common-hal/busio/SPI.c b/ports/cxd56/common-hal/busio/SPI.c index 8eedb624201..595b868f348 100644 --- a/ports/cxd56/common-hal/busio/SPI.c +++ b/ports/cxd56/common-hal/busio/SPI.c @@ -54,7 +54,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { return; } - self->spi_dev = NULL; + common_hal_busio_spi_mark_deinit(self); reset_pin_number(self->clock_pin->number); reset_pin_number(self->mosi_pin->number); @@ -65,11 +65,34 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->spi_dev == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->spi_dev = NULL; +} + bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { uint8_t mode; - self->frequency = baudrate; - SPI_SETFREQUENCY(self->spi_dev, baudrate); + // SPI_SETFREQUENCY() picks the nearest available frequency and returns it, + // which can be HIGHER than requested (it overshoots at low frequencies). + // Treat baudrate as a ceiling: if the driver overshoots, bisect downward on + // the requested target for the highest available frequency that does not + // exceed baudrate. The driver returns the actual frequency each call, so we + // don't depend on its divisor internals. + uint32_t actual = SPI_SETFREQUENCY(self->spi_dev, baudrate); + if (actual > baudrate) { + uint32_t lo = 1; // f(lo) <= baudrate + uint32_t hi = baudrate; // f(hi) > baudrate (just measured) + while (hi - lo > 1) { + uint32_t mid = lo + (hi - lo) / 2; + if (SPI_SETFREQUENCY(self->spi_dev, mid) <= baudrate) { + lo = mid; + } else { + hi = mid; + } + } + actual = SPI_SETFREQUENCY(self->spi_dev, lo); + } + self->frequency = actual; if (polarity == 0) { if (phase == 0) { diff --git a/ports/cxd56/common-hal/microcontroller/Processor.c b/ports/cxd56/common-hal/microcontroller/Processor.c index 6b9d20afa04..a3e2a44a3e4 100644 --- a/ports/cxd56/common-hal/microcontroller/Processor.c +++ b/ports/cxd56/common-hal/microcontroller/Processor.c @@ -30,5 +30,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/cxd56/common-hal/microcontroller/__init__.c b/ports/cxd56/common-hal/microcontroller/__init__.c index fa872f2807b..f7ac0c174ae 100644 --- a/ports/cxd56/common-hal/microcontroller/__init__.c +++ b/ports/cxd56/common-hal/microcontroller/__init__.c @@ -61,6 +61,8 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { void common_hal_mcu_reset(void) { filesystem_flush(); boardctl(BOARDIOC_RESET, 0); + // boardctl is noreturn in this case. + __builtin_unreachable(); } static const mp_rom_map_elem_t mcu_pin_globals_table[] = { diff --git a/ports/cxd56/common-hal/os/__init__.c b/ports/cxd56/common-hal/os/__init__.c index e1024108b07..902228f1db0 100644 --- a/ports/cxd56/common-hal/os/__init__.c +++ b/ports/cxd56/common-hal/os/__init__.c @@ -10,17 +10,7 @@ #include "py/objstr.h" #include "py/objtuple.h" +// No HW TRNG. bool common_hal_os_urandom(uint8_t *buffer, mp_uint_t length) { - uint32_t i = 0; - - while (i < length) { - uint32_t new_random = rand(); - for (int j = 0; j < 4 && i < length; j++) { - buffer[i] = new_random & 0xff; - i++; - new_random >>= 8; - } - } - - return true; + return false; } diff --git a/ports/cxd56/common-hal/sdioio/SDCard.c b/ports/cxd56/common-hal/sdioio/SDCard.c index aa1d1371770..227011a8871 100644 --- a/ports/cxd56/common-hal/sdioio/SDCard.c +++ b/ports/cxd56/common-hal/sdioio/SDCard.c @@ -8,6 +8,7 @@ #include #include +#include "extmod/vfs.h" #include "py/mperrno.h" #include "py/runtime.h" @@ -95,22 +96,73 @@ static void check_whole_block(mp_buffer_info_t *bufinfo) { } } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +// Native function for VFS blockdev layer +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + int result = self->inode->u.i_bops->read(self->inode, buf, start_block, num_blocks); + if (result < 0) { + return -MP_EIO; + } + return 0; +} + +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (common_hal_sdioio_sdcard_deinited(self)) { raise_deinited_error(); } check_whole_block(bufinfo); - return self->inode->u.i_bops->read(self->inode, bufinfo->buf, start_block, bufinfo->len / 512); + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +// Native function for VFS blockdev layer +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + int result = self->inode->u.i_bops->write(self->inode, buf, start_block, num_blocks); + if (result < 0) { + return -MP_EIO; + } + return 0; +} + +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (common_hal_sdioio_sdcard_deinited(self)) { raise_deinited_error(); } check_whole_block(bufinfo); - return self->inode->u.i_bops->write(self->inode, bufinfo->buf, start_block, bufinfo->len / 512); + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } } void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self) { diff --git a/ports/cxd56/mkspk/clefia.c b/ports/cxd56/mkspk/clefia.c index e946ee5348a..d36f638fa0b 100644 --- a/ports/cxd56/mkspk/clefia.c +++ b/ports/cxd56/mkspk/clefia.c @@ -466,16 +466,16 @@ int clefiakeyset(unsigned char *rk, const unsigned char *skey) { void clefiaencrypt(unsigned char *ct, const unsigned char *pt, const unsigned char *rk, const int r) { - unsigned char rin[16]; + unsigned char r_in[16]; unsigned char rout[16]; - bytecpy(rin, pt, 16); + bytecpy(r_in, pt, 16); - bytexor(rin + 4, rin + 4, rk + 0, 4); /* initial key whitening */ - bytexor(rin + 12, rin + 12, rk + 4, 4); + bytexor(r_in + 4, r_in + 4, rk + 0, 4); /* initial key whitening */ + bytexor(r_in + 12, r_in + 12, rk + 4, 4); rk += 8; - clefiagfn4(rout, rin, rk, r); /* GFN_{4,r} */ + clefiagfn4(rout, r_in, rk, r); /* GFN_{4,r} */ bytecpy(ct, rout, 16); bytexor(ct + 4, ct + 4, rk + r * 8 + 0, 4); /* final key whitening */ diff --git a/ports/cxd56/mpconfigport.h b/ports/cxd56/mpconfigport.h index f0a57248beb..ec606a76547 100644 --- a/ports/cxd56/mpconfigport.h +++ b/ports/cxd56/mpconfigport.h @@ -23,6 +23,8 @@ #define USB_MSC_EP_NUM_OUT (5) #define USB_MSC_EP_NUM_IN (4) +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + #include "py/circuitpy_mpconfig.h" #define MICROPY_BYTES_PER_GC_BLOCK (32) diff --git a/ports/cxd56/mpconfigport.mk b/ports/cxd56/mpconfigport.mk index cb54233a07e..ebfaa91f251 100644 --- a/ports/cxd56/mpconfigport.mk +++ b/ports/cxd56/mpconfigport.mk @@ -1,5 +1,3 @@ -USB_HIGHSPEED = 1 - # Number of USB endpoint pairs. USB_NUM_ENDPOINT_PAIRS = 6 diff --git a/ports/cxd56/supervisor/port.c b/ports/cxd56/supervisor/port.c index 75abcbf6d93..3dc54df96fb 100644 --- a/ports/cxd56/supervisor/port.c +++ b/ports/cxd56/supervisor/port.c @@ -66,8 +66,6 @@ void reset_port(void) { #if CIRCUITPY_RTC rtc_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/espressif/CMakeLists.txt b/ports/espressif/CMakeLists.txt index 387a18dac09..e612e4f31de 100644 --- a/ports/espressif/CMakeLists.txt +++ b/ports/espressif/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.16) set(ENV{IDF_PATH} ${CMAKE_SOURCE_DIR}/esp-idf) # The component list here determines what options we get in menuconfig and what the ninja file can build. -set(COMPONENTS bt driver esp_driver_dac esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_i2s esp_driver_ledc esp_driver_pcnt esp_driver_rmt esp_driver_spi esp_driver_tsens esp_driver_uart esp-tls esp_adc_cal esp_event esp_netif esp_psram esp_wifi esptool_py freertos log lwip main mbedtls mdns soc ulp usb wpa_supplicant esp-camera esp_lcd vfs esp_vfs_console sdmmc) +set(COMPONENTS bt driver esp_driver_dac esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_i2s esp_driver_ledc esp_driver_pcnt esp_driver_rmt esp_driver_sdmmc esp_driver_spi esp_driver_touch_sens esp_driver_tsens esp_driver_uart esp-tls esp_adc esp_event esp_netif esp_psram esp_security esp_wifi esptool_py freertos log lwip main mbedtls mdns pthread soc ulp wpa_supplicant esp_lcd vfs esp_stdio sdmmc esp-camera) set(EXTRA_COMPONENT_DIRS "esp-protocols/components/mdns" "esp-camera") include($ENV{IDF_PATH}/tools/cmake/project.cmake) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index a063101991f..881bfbf45e6 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -8,6 +8,8 @@ include ../../py/circuitpy_mkenv.mk ifeq ($(IDF_TARGET),esp32s3) BT_IDF_TARGET = esp32c3 +else ifeq ($(IDF_TARGET),esp32c61) +BT_IDF_TARGET = esp32c6 else BT_IDF_TARGET = $(IDF_TARGET) endif @@ -45,39 +47,43 @@ INC += \ -isystem esp-idf/components/bt/host/nimble/nimble/porting/nimble/include \ -isystem esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/include \ -isystem esp-idf/components/bt/host/nimble/port/include \ - -isystem esp-idf/components/driver/touch_sensor/include \ - -isystem esp-idf/components/driver/touch_sensor/$(IDF_TARGET)/include \ + -isystem esp-idf/components/bt/porting/include \ + -isystem esp-idf/components/bt/porting/npl/freertos/include \ + -isystem esp-idf/components/bt/porting/transport/include \ + -isystem esp-idf/components/esp_driver_touch_sens/include \ -isystem esp-idf/components/driver/twai/include \ + -isystem esp-idf/components/driver/i2c/include \ -isystem esp-idf/components/efuse/include \ -isystem esp-idf/components/efuse/$(IDF_TARGET)/include \ - -isystem esp-idf/components/$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_adc/include \ -isystem esp-idf/components/esp_adc/$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_app_format/include \ -isystem esp-idf/components/esp_bootloader_format/include \ -isystem esp-idf/components/esp_common/include \ - -isystem esp-idf/components/esp_driver_deprecated \ -isystem esp-idf/components/esp_driver_dac/include \ -isystem esp-idf/components/esp_driver_gpio/include \ -isystem esp-idf/components/esp_driver_gptimer/include \ -isystem esp-idf/components/esp_driver_i2c/include \ -isystem esp-idf/components/esp_driver_i2s/include \ - -isystem esp-idf/components/esp_driver_$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_driver_ledc/include \ + -isystem esp-idf/components/esp_driver_parlio/include \ -isystem esp-idf/components/esp_driver_pcnt/include \ -isystem esp-idf/components/esp_driver_rmt/include \ -isystem esp-idf/components/esp_driver_sdio/include \ -isystem esp-idf/components/esp_driver_sdmmc/include \ + -isystem esp-idf/components/esp_driver_sdmmc/legacy/include \ + -isystem esp-idf/components/esp_driver_dma/include \ -isystem esp-idf/components/esp_driver_spi/include \ -isystem esp-idf/components/esp_driver_tsens/include \ -isystem esp-idf/components/esp_driver_uart/include \ -isystem esp-idf/components/esp_event/include \ - -isystem esp-idf/components/esp_hw_support/dma/include \ -isystem esp-idf/components/esp_hw_support/include \ -isystem esp-idf/components/esp_hw_support/include/soc \ -isystem esp-idf/components/esp_hw_support/port/$(IDF_TARGET)/private_include \ + -isystem esp-idf/components/esp_hw_support/etm/include \ -isystem esp-idf/components/esp_mm/include \ -isystem esp-idf/components/esp_netif/include \ + -isystem esp-idf/components/esp_blockdev/include \ -isystem esp-idf/components/esp_partition/include \ -isystem esp-idf/components/esp_pm/include \ -isystem esp-idf/components/esp_psram/include \ @@ -102,6 +108,38 @@ INC += \ -isystem esp-idf/components/hal/include \ -isystem esp-idf/components/hal/$(IDF_TARGET)/include \ -isystem esp-idf/components/hal/platform_port/include \ + -isystem esp-idf/components/esp_hal_gpio/include \ + -isystem esp-idf/components/esp_hal_gpio/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_timg/include \ + -isystem esp-idf/components/esp_hal_ana_conv/include \ + -isystem esp-idf/components/esp_hal_touch_sens/include \ + -isystem esp-idf/components/esp_hal_uart/include \ + -isystem esp-idf/components/esp_hal_gpspi/include \ + -isystem esp-idf/components/esp_hal_i2c/include \ + -isystem esp-idf/components/esp_hal_i2s/include \ + -isystem esp-idf/components/esp_hal_i2s/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_ledc/include \ + -isystem esp-idf/components/esp_hal_pcnt/include \ + -isystem esp-idf/components/esp_hal_rmt/include \ + -isystem esp-idf/components/esp_hal_rmt/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_twai/include \ + -isystem esp-idf/components/esp_hal_twai/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_timg/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_gpspi/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_dma/include \ + -isystem esp-idf/components/esp_hal_dma/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_lcd/include \ + -isystem esp-idf/components/esp_hal_lcd/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_sd/include \ + -isystem esp-idf/components/esp_hal_sd/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_usb/include \ + -isystem esp-idf/components/esp_hal_usb/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_parlio/include \ + -isystem esp-idf/components/esp_hal_pmu/include \ + -isystem esp-idf/components/esp_hal_pmu/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_wdt/include \ + -isystem esp-idf/components/esp_hal_wdt/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_security/include \ -isystem esp-idf/components/heap/include \ -isystem esp-idf/components/log/include \ -isystem esp-idf/components/lwip/include \ @@ -111,20 +149,20 @@ INC += \ -isystem esp-idf/components/lwip/port/freertos/include \ -isystem esp-idf/components/mbedtls/esp_crt_bundle/include \ -isystem esp-idf/components/mbedtls/mbedtls/include \ + -isystem esp-idf/components/mbedtls/mbedtls/tf-psa-crypto/include \ + -isystem esp-idf/components/mbedtls/mbedtls/tf-psa-crypto/drivers/builtin/include \ -isystem esp-idf/components/mbedtls/port/include \ - -isystem esp-idf/components/newlib/platform_include \ + -isystem esp-idf/components/mbedtls/port/psa_driver/include \ + -isystem esp-idf/components/esp_libc/platform_include \ -isystem esp-idf/components/nvs_flash/include \ - -isystem esp-idf/components/sdio/include \ -isystem esp-idf/components/sdmmc/include \ -isystem esp-idf/components/soc/include \ -isystem esp-idf/components/soc/$(IDF_TARGET)/include \ -isystem esp-idf/components/soc/$(IDF_TARGET)/register \ -isystem esp-idf/components/spi_flash/include \ - -isystem esp-idf/components/usb/include \ -isystem esp-idf/components/ulp/ulp_fsm/include \ -isystem esp-idf/components/ulp/ulp_riscv/include \ -isystem esp-idf/components/ulp/ulp_common/include \ - -isystem esp-idf/components/ulp/ulp_common/include/$(IDF_TARGET) \ -isystem esp-idf/components/$(IDF_TARGET_ARCH)/include \ -isystem esp-idf/components/$(IDF_TARGET_ARCH)/$(IDF_TARGET)/include \ -isystem esp-protocols/components/mdns/include @@ -133,6 +171,7 @@ CFLAGS += \ -DHAVE_CONFIG_H \ -DESP_PLATFORM=1 \ -DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\" \ + -DMBEDTLS_DECLARE_PRIVATE_IDENTIFIERS \ -DMBEDTLS_PADLOCK_FILE=\"ports/espressif/esp-idf/components/mbedtls/mbedtls/library/padlock.h\" \ -DUNITY_INCLUDE_CONFIG_H -DWITH_POSIX \ -DMP3DEC_GENERIC @@ -149,6 +188,8 @@ CFLAGS += -DSTACK_CANARY_VALUE=0xa5a5a5a5 REGISTRATION_FUNCTIONS = \ -u ld_include_highint_hdl \ -u __cxx_fatal_exception \ + -u __cxx_init_dummy \ + -u __cxa_guard_dummy \ -u esp_app_desc \ -u esp_timer_init_include_func \ -u uart_vfs_include_dev_init \ @@ -156,13 +197,66 @@ REGISTRATION_FUNCTIONS = \ -u __ubsan_include \ -u esp_system_include_startup_funcs \ -u esp_efuse_startup_include_func \ - -u newlib_include_heap_impl \ - -u newlib_include_syscalls_impl \ - -u newlib_include_pthread_impl \ - -u newlib_include_assert_impl \ - -u newlib_include_init_funcs \ + -u esp_libc_include_heap_impl \ + -u esp_libc_include_reent_syscalls_impl \ + -u esp_libc_include_syscalls_impl \ + -u esp_libc_include_pthread_impl \ + -u esp_libc_include_assert_impl \ + -u esp_libc_include_getentropy_impl \ + -u esp_libc_include_init_funcs \ + -u esp_libc_init_funcs \ -u include_esp_phy_override \ - -u vfs_include_syscalls_impl + -u vfs_include_syscalls_impl \ + -u esp_vfs_include_nullfs_register \ + -u usb_serial_jtag_vfs_include_dev_init \ + -u usb_serial_jtag_connection_monitor_include \ + -u esp_flash_spi_init_include_func \ + -u pthread_include_pthread_impl \ + -u pthread_include_pthread_cond_var_impl \ + -u pthread_include_pthread_local_storage_impl \ + -u pthread_include_pthread_rwlock_impl \ + -u pthread_include_pthread_semaphore_impl \ + -u esp_security_init_include_impl \ + -u mbedtls_psa_crypto_init_include_impl + +# RISC-V picolibc ships optimized memcpy/memset/etc. that need forcing +# (gated by CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS in IDF's esp_libc CMake). +ifeq ($(IDF_TARGET_ARCH),riscv) +REGISTRATION_FUNCTIONS += \ + -u esp_libc_include_memcpy_impl \ + -u esp_libc_include_memmove_impl \ + -u esp_libc_include_memcmp_impl \ + -u esp_libc_include_memset_impl \ + -u esp_libc_include_strcpy_impl \ + -u esp_libc_include_strncpy_impl \ + -u esp_libc_include_strcmp_impl \ + -u esp_libc_include_strncmp_impl +endif + +# Chips with PAU + TOP power-down (SOC_PAU_SUPPORTED && SOC_PM_SUPPORT_TOP_PD): +# C5, C6, C61, H2, H21, H4, P4. These pull in sleep_gpio + system-peripheral +# retention, and the SW-driven RISC-V CPU register save/restore path. +ifneq ($(filter $(IDF_TARGET),esp32c5 esp32c6 esp32c61 esp32h2 esp32h21 esp32h4 esp32p4),) +REGISTRATION_FUNCTIONS += \ + -u esp_sleep_gpio_include \ + -u sleep_system_peripheral_dummy \ + -u rv_core_critical_regs_save \ + -u rv_core_critical_regs_restore +endif + +# RISC-V chips with a hardware FPU (H4, P4) need FPU register save/restore +# alongside the CPU retention path. +ifneq ($(filter $(IDF_TARGET),esp32h4 esp32p4),) +REGISTRATION_FUNCTIONS += \ + -u rv_core_fpu_save \ + -u rv_core_fpu_restore +endif + +ifneq ($(CIRCUITPY_WIFI),0) +ifeq ($(filter $(IDF_TARGET),esp32s2 esp32p4),) +REGISTRATION_FUNCTIONS += -u esp_coex_init_include_func +endif +endif #Debugging/Optimization @@ -191,51 +285,66 @@ endif # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk CFLAGS += $(OPTIMIZATION_FLAGS) -CFLAGS += $(INC) -Werror -Wall -std=gnu11 -Wl,--gc-sections $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition +# Default ROM symbol maps; per-chip blocks below may override. +IDF_TARGET_ROM_LD ?= $(IDF_TARGET).rom.ld +# Floating-point/libgcc ROM map. IDF picks between libgcc and rvfp based on +# CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB (rvfp xor libgcc, never both). Default +# to libgcc; targets that ship the rvfp variant in ROM (P4 in particular) +# override this. +IDF_TARGET_ROM_FLOAT_LD ?= $(IDF_TARGET).rom.libgcc.ld -# Most current ESPs have nano versions of newlib in ROM so we use them. -ifneq ($(IDF_TARGET),esp32c6) - CFLAGS += --specs=nano.specs - LDFLAGS += -T$(IDF_TARGET).rom.newlib-nano.ld -else - LDFLAGS += -T$(IDF_TARGET).rom.newlib-normal.ld -endif +CFLAGS += $(INC) -Werror -Wall -std=gnu11 -Wl,--gc-sections $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition -Wno-error=cpp -Wno-cpp + +# ESP-IDF v6.0 uses picolibc instead of newlib. +CFLAGS += --specs=picolibc.specs ifeq ($(IDF_TARGET_ARCH),xtensa) # Remove the last two flags once TinyUSB is updated with the `#include ` instead of # `#include "xtensa/xtensa_api.h"`. - CFLAGS += -mlongcalls -isystem esp-idf/components/xtensa/deprecated_include/ -Wno-error=cpp + CFLAGS += -mlongcalls -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero + CFLAGS += -isystem esp-idf/components/xtensa/deprecated_include/ +ifeq ($(IDF_TARGET),esp32) + CFLAGS += -Wno-frame-address +endif + CFLAGS += -DMICROPY_GCREGS_SETJMP=1 # Wrap longjmp with a patched version that protects register window update with a critical section LDFLAGS += -Wl,--wrap=longjmp + + SRC_C += shared/runtime/gchelper_generic.c else ifeq ($(IDF_TARGET_ARCH),riscv) ifeq ($(IDF_TARGET),esp32p4) - CFLAGS += -march=rv32imafc_zicsr_zifencei_xesppie -mabi=ilp32f + CFLAGS += -march=rv32imafc_zicsr_zifencei_zaamo_zalrsc -mabi=ilp32f + else ifeq ($(IDF_TARGET),$(filter $(IDF_TARGET),esp32c2 esp32c3)) + CFLAGS += -march=rv32imc_zicsr_zifencei else - CFLAGS += -march=rv32imac_zicsr_zifencei + CFLAGS += -march=rv32imac_zicsr_zifencei_zaamo_zalrsc endif LDFLAGS += \ -Lesp-idf/components/riscv/ld \ -Trom.api.ld + + SRC_C += shared/runtime/gchelper_native.c + SRC_S = shared/runtime/gchelper_rv32i.s endif -$(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align -LDFLAGS += $(CFLAGS) -Wl,-nostdlib -Wl,-Map=$@.map -Wl,-cref -Wl,--undefined=uxTopUsedPriority +LDFLAGS += $(CFLAGS) -nostartfiles -Wl,-nostdlib -Wl,-Map=$@.map -Wl,-cref -Wl,--undefined=uxTopUsedPriority LDFLAGS += \ -L$(BUILD)/esp-idf/esp-idf/esp_system/ld \ -Lesp-idf/components/esp_rom/$(IDF_TARGET)/ld \ -Lesp-idf/components/soc/$(IDF_TARGET)/ld \ + -Lesp-idf/components/esp_hal_wdt/$(IDF_TARGET) \ -Tmemory.ld \ -Tsections.ld \ -T$(IDF_TARGET).peripherals.ld \ - -T$(IDF_TARGET).rom.ld \ + -T$(IDF_TARGET_ROM_LD) \ -T$(IDF_TARGET).rom.api.ld \ - -T$(IDF_TARGET).rom.libgcc.ld \ + -T$(IDF_TARGET_ROM_FLOAT_LD) \ -Wl,-Bstatic \ -Wl,--no-warn-mismatch \ -Wl,--build-id=none \ @@ -243,93 +352,224 @@ LDFLAGS += \ ifeq ($(IDF_TARGET),esp32) LDFLAGS += \ - -Tesp32.rom.newlib-data.ld \ - -Tesp32.rom.newlib-funcs.ld \ - -Tesp32.rom.spiflash_legacy.ld + -Tesp32.rom.libc-funcs.ld + +CFLAGS += -isystem esp-idf/components/esp_driver_touch_sens/hw_ver1/include CHIP_COMPONENTS = \ - esp_driver_dac + esp_driver_dac \ + esp_driver_touch_sens \ + esp_hal_i2s \ + esp_hal_lcd \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_touch_sens \ + esp_hal_twai else ifeq ($(IDF_TARGET),esp32c2) LDFLAGS += \ -Tesp32c2.rom.ble.ld \ -Tesp32c2.rom.heap.ld \ - -Tesp32c2.rom.newlib.ld \ + -Tesp32c2.rom.libc.ld \ -Tesp32c2.rom.version.ld \ -Tesp32c2.rom.systimer.ld \ - -Tesp32c2.rom.wdt.ld + -Trom.wdt.ld CFLAGS += -DSOC_XTAL_FREQ_MHZ=CONFIG_XTAL_FREQ CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_hal_dma \ + esp_hal_pmu else ifeq ($(IDF_TARGET),esp32c3) +# esp32c2 has none of: esp_hal_i2s esp_hal_lcd esp_hal_pcnt esp_hal_touch_sens esp_hal_twai LDFLAGS += \ - -Tesp32c3.rom.newlib.ld \ + -Tesp32c3.rom.libc.ld \ -Tesp32c3.rom.version.ld \ -Tesp32c3.rom.eco3_bt_funcs.ld \ -Tesp32c3.rom.eco3.ld \ -Tesp32c3.rom.bt_funcs.ld CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_twai \ + esp_hal_usb + +else ifeq ($(IDF_TARGET),esp32c5) +LDFLAGS += \ + -Tesp32c5.rom.phy.ld \ + -Tesp32c5.rom.pp.ld \ + -Tesp32c5.rom.net80211.ld \ + -Tesp32c5.rom.libc.ld \ + -Tesp32c5.rom.version.ld \ + -Tesp32c5.rom.coexist.ld \ + -Tesp32c5.rom.heap.ld \ + -Tesp32c5.rom.systimer.ld \ + -Trom.wdt.ld + +CHIP_COMPONENTS = \ + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_twai \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32c6) LDFLAGS += \ -Tesp32c6.rom.phy.ld \ -Tesp32c6.rom.pp.ld \ -Tesp32c6.rom.net80211.ld \ - -Tesp32c6.rom.newlib.ld \ + -Tesp32c6.rom.libc.ld \ -Tesp32c6.rom.coexist.ld \ -Tesp32c6.rom.heap.ld \ -Tesp32c6.rom.systimer.ld \ - -Tesp32c6.rom.wdt.ld + -Trom.wdt.ld CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_twai \ + esp_hal_usb + +else ifeq ($(IDF_TARGET),esp32c61) +LDFLAGS += \ + -Tesp32c61.rom.phy.ld \ + -Tesp32c61.rom.pp.ld \ + -Tesp32c61.rom.net80211.ld \ + -Tesp32c61.rom.libc.ld \ + -Tesp32c61.rom.version.ld \ + -Tesp32c61.rom.coexist.ld \ + -Tesp32c61.rom.heap.ld \ + -Tesp32c61.rom.systimer.ld \ + -Trom.wdt.ld + + +CHIP_COMPONENTS = \ + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pmu \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32p4) +CIRCUITPY_ESP32P4_REV ?= 1 +CFLAGS += \ + -isystem esp-idf/components/soc/esp32p4/register/hw_ver$(CIRCUITPY_ESP32P4_REV) \ + -isystem esp-idf/components/esp_hw_support/ldo/include \ + -isystem esp-idf/components/esp_driver_touch_sens/hw_ver3/include + +ifeq ($(CIRCUITPY_ESP32P4_REV),3) +IDF_TARGET_ROM_LD = esp32p4.rom.eco5.ld +IDF_TARGET_ROM_FLOAT_LD = esp32p4.rom.eco5.rvfp.ld LDFLAGS += \ - -Tesp32p4.rom.newlib.ld \ -Tesp32p4.rom.systimer.ld \ - -Tesp32p4.rom.wdt.ld + -Tesp32p4.rom.eco5.libc.ld \ + -Tesp32p4.rom.version.ld \ + -Trom.wdt.ld +else +IDF_TARGET_ROM_FLOAT_LD = esp32p4.rom.rvfp.ld +LDFLAGS += \ + -Tesp32p4.rom.libc.ld \ + -Tesp32p4.rom.systimer.ld \ + -Tesp32p4.rom.version.ld \ + -Trom.wdt.ld +endif CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_touch_sens \ + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_lcd \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_touch_sens \ + esp_hal_twai \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32h2) LDFLAGS += \ -Tesp32h2.rom.heap.ld \ - -Tesp32h2.rom.newlib.ld \ + -Tesp32h2.rom.libc.ld \ -Tesp32h2.rom.systimer.ld \ - -Tesp32h2.rom.wdt.ld + -Trom.wdt.ld CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_twai \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32s2) +CFLAGS += -isystem esp-idf/components/esp_driver_touch_sens/hw_ver2/include + LDFLAGS += \ - -Tesp32s2.rom.newlib-data.ld \ - -Tesp32s2.rom.newlib-funcs.ld \ + -Tesp32s2.rom.libc-funcs.ld \ -Tesp32s2.rom.spiflash_legacy.ld CHIP_COMPONENTS = \ esp_driver_dac \ - esp_driver_tsens + esp_driver_touch_sens \ + esp_driver_tsens \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_lcd \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_touch_sens \ + esp_hal_twai \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32s3) +CFLAGS += -isystem esp-idf/components/esp_driver_touch_sens/hw_ver2/include + LDFLAGS += \ - -Tesp32s3.rom.newlib.ld \ + -Tesp32s3.rom.libc.ld \ -Tesp32s3.rom.version.ld \ -Tesp32s3.rom.systimer.ld \ - -Tesp32s3.rom.wdt.ld \ - -Tesp32s3.rom.bt_funcs.ld + -Tesp32s3.rom.bt_funcs.ld \ + -Trom.wdt.ld CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_touch_sens \ + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_lcd \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_touch_sens \ + esp_hal_twai \ + esp_hal_usb endif @@ -348,8 +588,12 @@ else ifeq ($(IDF_TARGET),esp32c2) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C2 else ifeq ($(IDF_TARGET),esp32c3) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C3 +else ifeq ($(IDF_TARGET),esp32c5) +CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C5 else ifeq ($(IDF_TARGET),esp32c6) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C6 +else ifeq ($(IDF_TARGET),esp32c61) +CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C61 else ifeq ($(IDF_TARGET),esp32p4) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32P4 else ifeq ($(IDF_TARGET),esp32h2) @@ -420,6 +664,10 @@ ifneq ($(CIRCUITPY_AUDIOBUSIO),0) CHIP_COMPONENTS += esp_driver_i2s endif +ifneq ($(CIRCUITPY_AUDIOI2SIN),0) +CHIP_COMPONENTS += esp_driver_i2s +endif + ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) SRC_C += common-hal/_bleio/ble_events.c endif @@ -431,6 +679,13 @@ CFLAGS += \ -isystem esp-idf/components/esp_lcd/rgb/include endif +ifneq ($(CIRCUITPY_MIPIDSI),0) +CFLAGS += \ + -isystem esp-idf/components/esp_lcd/include \ + -isystem esp-idf/components/esp_lcd/interface \ + -isystem esp-idf/components/esp_lcd/dsi/include +endif + ifneq ($(CIRCUITPY_ESPCAMERA),0) SRC_CAMERA := \ $(wildcard common-hal/espcamera/*.c) \ @@ -539,8 +794,6 @@ FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) endif -SRC_S_UPPER = supervisor/shared/cpu_regs.S - OBJ += $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) @@ -548,7 +801,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os $(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os @@ -615,20 +868,29 @@ ifeq ($(ENABLE_JTAG), 1) CFLAGS += -DENABLE_JTAG=1 endif -SDKCONFIGS := esp-idf-config/sdkconfig.defaults;$(DEBUG_SDKCONFIG);$(FLASH_SIZE_SDKCONFIG);$(FLASH_MODE_SDKCONFIG);$(FLASH_SPEED_SDKCONFIG);$(PSRAM_SDKCONFIG);$(PSRAM_SIZE_SDKCONFIG);$(PSRAM_MODE_SDKCONFIG);$(PSRAM_SPEED_SDKCONFIG);$(TARGET_SDKCONFIG);boards/$(BOARD)/sdkconfig ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) - SDKCONFIGS := esp-idf-config/sdkconfig-ble.defaults;$(SDKCONFIGS) + BLE_SDKCONFIG := ;esp-idf-config/sdkconfig-ble.defaults +endif + +# Loaded native code executes from RAM, which memory protection forbids. +ifneq (,$(filter 1,$(CIRCUITPY_ENABLE_MPY_NATIVE) $(CIRCUITPY_LOAD_NATIVE))) + NATIVE_SDKCONFIG := ;esp-idf-config/sdkconfig-native.defaults endif + +SDKCONFIGS := esp-idf-config/sdkconfig.defaults;$(DEBUG_SDKCONFIG);$(FLASH_SIZE_SDKCONFIG);$(FLASH_MODE_SDKCONFIG);$(FLASH_SPEED_SDKCONFIG);$(PSRAM_SDKCONFIG);$(PSRAM_SIZE_SDKCONFIG);$(PSRAM_MODE_SDKCONFIG);$(PSRAM_SPEED_SDKCONFIG);$(BLE_SDKCONFIG)$(NATIVE_SDKCONFIG);$(TARGET_SDKCONFIG);boards/$(BOARD)/sdkconfig + # create the config headers .PHONY: do-sdkconfig do-sdkconfig: $(BUILD)/esp-idf/config/sdkconfig.h QSTR_GLOBAL_REQUIREMENTS += $(BUILD)/esp-idf/config/sdkconfig.h $(BUILD)/esp-idf/config/sdkconfig.h: boards/$(BOARD)/sdkconfig boards/$(BOARD)/mpconfigboard.mk CMakeLists.txt | $(BUILD)/esp-idf - $(STEPECHO) "LINK $@" - $(Q)env IDF_PATH=$(IDF_PATH) cmake -S . -B $(BUILD)/esp-idf -DSDKCONFIG=$(BUILD)/esp-idf/sdkconfig -DSDKCONFIG_DEFAULTS="$(SDKCONFIGS)" -DCMAKE_TOOLCHAIN_FILE=$(IDF_PATH)/tools/cmake/toolchain-$(IDF_TARGET).cmake -DIDF_TARGET=$(IDF_TARGET) -GNinja + $(STEPECHO) "Create $@" + $(Q)env IDF_PATH=$(IDF_PATH) IDF_COMPONENT_MANAGER=0 cmake -S . -B $(BUILD)/esp-idf -DSDKCONFIG=$(BUILD)/esp-idf/sdkconfig -DSDKCONFIG_DEFAULTS="$(SDKCONFIGS)" -DCMAKE_TOOLCHAIN_FILE=$(IDF_PATH)/tools/cmake/toolchain-$(IDF_TARGET).cmake -DIDF_TARGET=$(IDF_TARGET) -GNinja $(Q)$(PYTHON) tools/check-sdkconfig.py \ CIRCUITPY_DUALBANK=$(CIRCUITPY_DUALBANK) \ CIRCUITPY_STORAGE_EXTEND=$(CIRCUITPY_STORAGE_EXTEND) \ + CIRCUITPY_ENABLE_MPY_NATIVE=$(CIRCUITPY_ENABLE_MPY_NATIVE) \ + CIRCUITPY_LOAD_NATIVE=$(CIRCUITPY_LOAD_NATIVE) \ $@ # build a lib @@ -662,7 +924,8 @@ ifneq ($(IDF_TARGET),esp32p4) BINARY_BLOBS = esp-idf/components/esp_phy/lib/$(IDF_TARGET)/libphy.a endif ifneq ($(CIRCUITPY_WIFI),0) - BINARY_BLOBS += esp-idf/components/esp_coex/lib/$(IDF_TARGET)/libcoexist.a $(addprefix esp-idf/components/esp_wifi/lib/$(IDF_TARGET)/, $(BINARY_WIFI_BLOBS)) + BINARY_BLOBS += $(addprefix esp-idf/components/esp_wifi/lib/$(IDF_TARGET)/, $(BINARY_WIFI_BLOBS)) + BINARY_BLOBS += esp-idf/components/esp_coex/lib/$(IDF_TARGET)/libcoexist.a ifneq ($(IDF_TARGET),esp32c2) BINARY_BLOBS += $(addprefix esp-idf/components/esp_wifi/lib/$(IDF_TARGET)/, libmesh.a libwapi.a) endif @@ -672,7 +935,7 @@ ifeq ($(IDF_TARGET),esp32) BINARY_BLOBS += esp-idf/components/esp_phy/lib/$(IDF_TARGET)/librtc.a endif -ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log newlib nvs_flash pthread soc spi_flash vfs esp_vfs_console +ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_dma esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_gdbstub esp_hal_ana_conv esp_hal_clock esp_hal_gpio esp_hal_gpspi esp_hal_i2c esp_hal_ledc esp_hal_mspi esp_hal_security esp_hal_timg esp_hal_uart esp_hal_wdt esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log esp_libc nvs_flash nvs_sec_provider pthread soc spi_flash vfs esp_stdio ifneq ($(CIRCUITPY_WIFI),0) ESP_IDF_COMPONENTS_LINK += esp_coex esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy endif @@ -681,7 +944,9 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) BLE_IMPL_esp32s3 := esp32c3 BLE_IMPL_esp32c2 := libble BLE_IMPL_esp32c3 := esp32c3 + BLE_IMPL_esp32c5 := libble BLE_IMPL_esp32c6 := libble + BLE_IMPL_esp32c61 := libble BLE_IMPL_esp32h2 := libble BLE_IMPL = $(BLE_IMPL_$(IDF_TARGET)) @@ -700,8 +965,8 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) ifeq ($(BLE_IMPL),libble) BINARY_BLOBS += esp-idf/components/esp_phy/lib/$(IDF_TARGET)/libbtbb.a - ifeq ($(IDF_TARGET),esp32c6) - BINARY_BLOBS += esp-idf/components/bt/controller/lib_$(IDF_TARGET)/$(IDF_TARGET)-bt-lib/$(IDF_TARGET)/libble_app.a + ifeq ($(BT_IDF_TARGET),esp32c6) + BINARY_BLOBS += esp-idf/components/bt/controller/lib_$(BT_IDF_TARGET)/$(BT_IDF_TARGET)-bt-lib/$(IDF_TARGET)/libble_app.a else BINARY_BLOBS += esp-idf/components/bt/controller/lib_$(IDF_TARGET)/$(IDF_TARGET)-bt-lib/libble_app.a endif @@ -719,20 +984,27 @@ endif ifneq ($(CIRCUITPY_DOTCLOCKFRAMEBUFFER),0) ESP_IDF_COMPONENTS_LINK += esp_lcd endif +ifneq ($(CIRCUITPY_MIPIDSI),0) + ESP_IDF_COMPONENTS_LINK += esp_lcd +endif ifneq ($(CIRCUITPY_PARALLELDISPLAYBUS),0) ESP_IDF_COMPONENTS_LINK += esp_lcd endif -ifneq ($(CIRCUITPY_USB_DEVICE),0) - ESP_IDF_COMPONENTS_LINK += usb +ifneq ($(CIRCUITPY_QSPIBUS),0) + ESP_IDF_COMPONENTS_LINK += esp_lcd endif ifneq ($(CIRCUITPY_SDIOIO),0) - ESP_IDF_COMPONENTS_LINK += sdmmc esp_driver_sdmmc + ESP_IDF_COMPONENTS_LINK += sdmmc esp_driver_sdmmc esp_driver_sd_intf esp_hal_sd endif ESP_IDF_COMPONENTS_EXPANDED = $(foreach component, $(ESP_IDF_COMPONENTS_LINK), $(BUILD)/esp-idf/esp-idf/$(component)/lib$(component).a) MBEDTLS_COMPONENTS_LINK = crypto tls x509 MBEDTLS_COMPONENTS_LINK_EXPANDED = $(foreach component, $(MBEDTLS_COMPONENTS_LINK), $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/library/libmbed$(component).a) +MBEDTLS_COMPONENTS_LINK_EXPANDED += $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/library/libtfpsacrypto.a +MBEDTLS_COMPONENTS_LINK_EXPANDED += $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/tf-psa-crypto/drivers/builtin/libmbed-builtin.a +MBEDTLS_COMPONENTS_LINK_EXPANDED += $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/tf-psa-crypto/drivers/everest/libeverest.a +MBEDTLS_COMPONENTS_LINK_EXPANDED += $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/tf-psa-crypto/drivers/p256-m/libp256m.a ifeq ($(IDF_TARGET_ARCH),xtensa) BINARY_BLOBS += esp-idf/components/xtensa/$(IDF_TARGET)/libxt_hal.a @@ -767,8 +1039,12 @@ else ifeq ($(IDF_TARGET),esp32c2) BOOTLOADER_OFFSET = 0x0 else ifeq ($(IDF_TARGET),esp32c3) BOOTLOADER_OFFSET = 0x0 +else ifeq ($(IDF_TARGET),esp32c5) +BOOTLOADER_OFFSET = 0x2000 else ifeq ($(IDF_TARGET),esp32c6) BOOTLOADER_OFFSET = 0x0 +else ifeq ($(IDF_TARGET),esp32c61) +BOOTLOADER_OFFSET = 0x0 else ifeq ($(IDF_TARGET),esp32p4) BOOTLOADER_OFFSET = 0x2000 else ifeq ($(IDF_TARGET),esp32s3) @@ -782,7 +1058,7 @@ endif IDF_CMAKE_TARGETS = \ bootloader/bootloader.bin \ - esp-idf/esp_system/__ldgen_output_sections.ld \ + __ldgen_output_sections.ld \ $(foreach component, $(ESP_IDF_COMPONENTS_LINK), esp-idf/$(component)/lib$(component).a) PARTITION_TABLE_OFFSET = 0x8000 @@ -807,9 +1083,9 @@ else ESPTOOLPY_FLASHFREQ = $(CIRCUITPY_ESP_FLASH_FREQ) endif -FLASH_FLAGS = --flash_mode $(ESPTOOLPY_FLASHMODE) --flash_freq $(ESPTOOLPY_FLASHFREQ) --flash_size $(CIRCUITPY_ESP_FLASH_SIZE) +FLASH_FLAGS = --flash-mode $(ESPTOOLPY_FLASHMODE) --flash-freq $(ESPTOOLPY_FLASHFREQ) --flash-size $(CIRCUITPY_ESP_FLASH_SIZE) -ESPTOOL_FLAGS ?= --before=default_reset --after=no_reset --baud 921600 +ESPTOOL_FLAGS ?= --before=default-reset --after=no-reset --baud 921600 ifeq ($(UF2_BOOTLOADER),1) all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 @@ -829,7 +1105,7 @@ $(BUILD)/firmware.elf: $(OBJ) | esp-idf-stamp $(IDF_CMAKE_TARGETS) $(BUILD)/circuitpython-firmware.bin: $(BUILD)/firmware.elf | tools/build_memory_info.py $(STEPECHO) "Create $@" - $(Q)esptool.py --chip $(IDF_TARGET) elf2image $(FLASH_FLAGS) --elf-sha256-offset 0xb0 -o $@ $^ + $(Q)esptool --chip $(IDF_TARGET) elf2image $(FLASH_FLAGS) --elf-sha256-offset 0xb0 -o $@ $^ $(Q)$(PYTHON) tools/build_memory_info.py $< $(BUILD)/esp-idf/sdkconfig $@ $(BUILD) ifeq ($(VALID_BOARD),) @@ -848,10 +1124,10 @@ $(BUILD)/firmware.uf2: $(BUILD)/circuitpython-firmware.bin $(Q)$(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID_$(IDF_TARGET)) -b 0x0000 -c -o $@ $^ flash: $(BUILD)/firmware.bin - esptool.py --chip $(IDF_TARGET) -p $(PORT) $(ESPTOOL_FLAGS) write_flash $(FLASH_FLAGS) 0x0000 $^ + esptool --chip $(IDF_TARGET) -p $(PORT) $(ESPTOOL_FLAGS) write-flash $(FLASH_FLAGS) 0x0000 $^ flash-circuitpython-only: $(BUILD)/circuitpython-firmware.bin - esptool.py --chip $(IDF_TARGET) -p $(PORT) $(ESPTOOL_FLAGS) write_flash $(FLASH_FLAGS) $(FIRMWARE_OFFSET) $^ + esptool --chip $(IDF_TARGET) -p $(PORT) $(ESPTOOL_FLAGS) write-flash $(FLASH_FLAGS) $(FIRMWARE_OFFSET) $^ monitor: $(BUILD)/firmware.elf cp $< build/circuitpython.elf diff --git a/ports/espressif/README.rst b/ports/espressif/README.rst index fe5542aafe4..5af91591f7e 100644 --- a/ports/espressif/README.rst +++ b/ports/espressif/README.rst @@ -41,7 +41,7 @@ Connecting to the ESP32-C3 **USB Connection:** -On ESP32-C3 REV3 chips, a USB Serial/JTAG Controller is available. Note: This USB connection cannot be used for a ``CIRCUITPY`` drive. +On ESP32-C3 REV3 chips, a USB Serial/JTAG Controller is available. Note: This USB connection cannot be used for a **CIRCUITPY** drive. Depending on the board you have, the USB port may or may not be connected to native USB. diff --git a/ports/espressif/background.c b/ports/espressif/background.c index 61615c01615..b1b81ac2c83 100644 --- a/ports/espressif/background.c +++ b/ports/espressif/background.c @@ -13,8 +13,8 @@ #include "freertos/task.h" void port_background_tick(void) { - // Zero delay in case FreeRTOS wants to switch to something else. - vTaskDelay(0); + // Yield with zero delay in case FreeRTOS wants to switch to something else. + port_task_yield(); } void port_background_task(void) { diff --git a/ports/espressif/bindings/espcamera/Camera.c b/ports/espressif/bindings/espcamera/Camera.c index ed6b542a02f..9a74824a053 100644 --- a/ports/espressif/bindings/espcamera/Camera.c +++ b/ports/espressif/bindings/espcamera/Camera.c @@ -179,7 +179,7 @@ static void check_for_deinit(espcamera_camera_obj_t *self) { static mp_obj_t espcamera_camera_frame_available_get(const mp_obj_t self_in) { espcamera_camera_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - return mp_obj_new_bool(esp_camera_fb_available()); + return mp_obj_new_bool(common_hal_espcamera_camera_available(self)); } static MP_DEFINE_CONST_FUN_OBJ_1(espcamera_camera_frame_available_get_obj, espcamera_camera_frame_available_get); @@ -261,7 +261,7 @@ static mp_obj_t espcamera_camera_reconfigure(mp_uint_t n_args, const mp_obj_t *p args[ARG_grab_mode].u_obj != MP_ROM_NONE ? validate_grab_mode(args[ARG_grab_mode].u_obj, MP_QSTR_grab_mode) : common_hal_espcamera_camera_get_grab_mode(self); - bool framebuffer_count = + mp_int_t framebuffer_count = args[ARG_framebuffer_count].u_obj != MP_ROM_NONE ? mp_obj_get_int(args[ARG_framebuffer_count].u_obj) : common_hal_espcamera_camera_get_framebuffer_count(self); diff --git a/ports/espressif/bindings/espidf/__init__.c b/ports/espressif/bindings/espidf/__init__.c index 012ed7d9f9a..897da0eb571 100644 --- a/ports/espressif/bindings/espidf/__init__.c +++ b/ports/espressif/bindings/espidf/__init__.c @@ -106,7 +106,7 @@ MP_DEFINE_CONST_OBJ_TYPE( //| ... //| //| -NORETURN void mp_raise_espidf_MemoryError(void) { +MP_NORETURN void mp_raise_espidf_MemoryError(void) { nlr_raise(mp_obj_new_exception(&mp_type_espidf_MemoryError)); } diff --git a/ports/espressif/bindings/espidf/__init__.h b/ports/espressif/bindings/espidf/__init__.h index 7c112abf736..92d2e0c2769 100644 --- a/ports/espressif/bindings/espidf/__init__.h +++ b/ports/espressif/bindings/espidf/__init__.h @@ -15,9 +15,9 @@ extern const mp_obj_type_t mp_type_espidf_IDFError; extern const mp_obj_type_t mp_type_espidf_MemoryError; -NORETURN void mp_raise_espidf_MemoryError(void); +MP_NORETURN void mp_raise_espidf_MemoryError(void); -void raise_esp_error(esp_err_t err) NORETURN; +void raise_esp_error(esp_err_t err) MP_NORETURN; #define CHECK_ESP_RESULT(x) do { int res = (x); if (res != ESP_OK) raise_esp_error(res); } while (0) size_t common_hal_espidf_get_total_psram(void); diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 01cc06e3be4..345d51b6dff 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -40,6 +40,8 @@ static void espnow_check_for_deinit(espnow_obj_t *self) { //| :param int buffer_size: The size of the internal ring buffer. Default: 526 bytes. //| :param int phy_rate: The ESP-NOW physical layer rate. Default: 1 Mbps. //| `wifi_phy_rate_t `_ +//| +//| **Limitations:** Currently, setting ``phy_rate`` does nothing. The rate is always 1 Mbps. //| """ //| ... //| @@ -231,6 +233,8 @@ MP_PROPERTY_GETTER(espnow_buffer_size_obj, //| phy_rate: int //| """The ESP-NOW physical layer rate. //| `wifi_phy_rate_t `_ +//| +//| **Limitations:** Currently, setting ``phy_rate`` does nothing. The rate is always 1 Mbps. //| """ //| static mp_obj_t espnow_get_phy_rate(const mp_obj_t self_in) { diff --git a/ports/espressif/boards/adafruit_esp32s3_camera/board.c b/ports/espressif/boards/adafruit_esp32s3_camera/board.c index e0c357f04c8..d8b0832d3d0 100644 --- a/ports/espressif/boards/adafruit_esp32s3_camera/board.c +++ b/ports/espressif/boards/adafruit_esp32s3_camera/board.c @@ -37,9 +37,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO40, // TFT_DC Command or data - &pin_GPIO39, // TFT_CS Chip select - &pin_GPIO38, // TFT_RESET Reset + MP_OBJ_FROM_PTR(&pin_GPIO40), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO39), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO38), // TFT_RESET Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.h b/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.h index 25d08535dd6..771a3275fb4 100644 --- a/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.h @@ -20,3 +20,7 @@ #define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) #define DOUBLE_TAP_PIN (&pin_GPIO42) + +// Turn off presenting SD card to USB by default. Changes settings.toml default for this setting. +// Workaround for https://github.com/adafruit/circuitpython/issues/11109. +#define CIRCUITPY_SDCARD_USB (false) diff --git a/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.mk b/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.mk index d1b6d503125..62b6d3612b3 100644 --- a/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.mk @@ -16,6 +16,7 @@ CIRCUITPY_ESP_PSRAM_FREQ = 80m CIRCUITPY_ESPCAMERA = 1 CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 CIRCUITPY_CANIO = 0 CIRCUITPY_DUALBANK = 0 CIRCUITPY_FRAMEBUFFERIO = 0 diff --git a/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/board.c b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/board.c index e554be121db..1fe3fd62800 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/board.c +++ b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO40, // DC - &pin_GPIO42, // CS - &pin_GPIO41, // RST + MP_OBJ_FROM_PTR(&pin_GPIO40), // DC + MP_OBJ_FROM_PTR(&pin_GPIO42), // CS + MP_OBJ_FROM_PTR(&pin_GPIO41), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/adafruit_feather_esp32s2_tft/board.c b/ports/espressif/boards/adafruit_feather_esp32s2_tft/board.c index 1ebb357aed5..22af4caa652 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s2_tft/board.c +++ b/ports/espressif/boards/adafruit_feather_esp32s2_tft/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO39, // DC - &pin_GPIO7, // CS - &pin_GPIO40, // RST + MP_OBJ_FROM_PTR(&pin_GPIO39), // DC + MP_OBJ_FROM_PTR(&pin_GPIO7), // CS + MP_OBJ_FROM_PTR(&pin_GPIO40), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/board.c b/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/board.c index e554be121db..1fe3fd62800 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/board.c +++ b/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO40, // DC - &pin_GPIO42, // CS - &pin_GPIO41, // RST + MP_OBJ_FROM_PTR(&pin_GPIO40), // DC + MP_OBJ_FROM_PTR(&pin_GPIO42), // CS + MP_OBJ_FROM_PTR(&pin_GPIO41), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_tft/board.c b/ports/espressif/boards/adafruit_feather_esp32s3_tft/board.c index e3569d864e7..587c742a64f 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_tft/board.c +++ b/ports/espressif/boards/adafruit_feather_esp32s3_tft/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO39, // DC - &pin_GPIO7, // CS - &pin_GPIO40, // RST + MP_OBJ_FROM_PTR(&pin_GPIO39), // DC + MP_OBJ_FROM_PTR(&pin_GPIO7), // CS + MP_OBJ_FROM_PTR(&pin_GPIO40), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/adafruit_funhouse/board.c b/ports/espressif/boards/adafruit_funhouse/board.c index 061a6abf0d8..83499f5a492 100644 --- a/ports/espressif/boards/adafruit_funhouse/board.c +++ b/ports/espressif/boards/adafruit_funhouse/board.c @@ -37,9 +37,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO39, // TFT_DC Command or data - &pin_GPIO40, // TFT_CS Chip select - &pin_GPIO41, // TFT_RESET Reset + MP_OBJ_FROM_PTR(&pin_GPIO39), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO40), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO41), // TFT_RESET Reset 5000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index d37233b7f24..61659755be2 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -7,9 +7,11 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/fourwire/FourWire.h" #include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-module/displayio/__init__.h" #include "supervisor/shared/board.h" @@ -127,6 +129,52 @@ const uint8_t ssd1680_display_start_sequence[] = { 0x22, 0x00, 0x01, 0xc7 // display update mode }; +// FPC-7519rev.b panels (User ID byte 0x44 or 0xca) need colstart=8 and tuned VCOM + LUT. +// LUT: Good Display reference (GxEPD2_4G / GDEM029T94) with VS rows reversed (L0↔L3, L1↔L2). +// Reason: CircuitPython maps luma 0→L0 and luma 255→L3. On this panel VSH1(0x40) drives WHITE and +// VSL(0x20) drives BLACK, so L0 must carry the black-driving waveform and L3 the white-driving +// waveform — opposite from GxEPD2_4G's Arduino convention (where index 0 = white constant). +// VS=0x48 = VSH1/GND/VSL/GND alternating for DC balance. +// VCOM=0x24 empirically tuned for FPC-7519rev.b contrast. Both 0x44 and 0xca share this sequence. +const uint8_t ssd1680_fpc7519_display_start_sequence[] = { + 0x12, DELAY, 0x00, 0x14, // soft reset and wait 20ms + 0x11, 0x00, 0x01, 0x03, // Ram data entry mode + 0x3c, 0x00, 0x01, 0x03, // border color + 0x2c, 0x00, 0x01, 0x24, // Set vcom voltage (0x24 tuned for FPC-7519rev.b contrast) + 0x03, 0x00, 0x01, 0x17, // Set gate voltage + 0x04, 0x00, 0x03, 0x41, 0xae, 0x32, // Set source voltage + 0x4e, 0x00, 0x01, 0x01, // ram x count + 0x4f, 0x00, 0x02, 0x00, 0x00, // ram y count + 0x01, 0x00, 0x03, 0x27, 0x01, 0x00, // set display size + 0x32, 0x00, 0x99, // Update waveforms (153 bytes follow) + // VS rows: only L0↔L3 are swapped relative to GxEPD2_4G; L1 and L2 stay in place. + // Reason: CircuitPython luma maps 0→L0, 64-127→L2, 128-191→L1, 255→L3. + // GxEPD2 uses L0=white-driver, L3=black-driver (opposite of CircuitPython for extremes). + // GxEPD2 L1=lighter-gray, L2=darker-gray; CircuitPython L1=mid-bright, L2=mid-dark — same ordering. + // So: swap only L0↔L3 (polarity); L1 and L2 keep their GxEPD2 positions (gradient preserved). + // 0x48 = VSH1/GND/VSL/GND alternating — better DC balance than 0x60 (VSH1/VSL/GND/GND) + 0x20, 0x48, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L0 (darkest/black) ← GxEPD2 L3 + 0x08, 0x48, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L1 (mid-light) ← GxEPD2 L1 (luma 128-191 → lighter) + 0x02, 0x48, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L2 (mid-dark) ← GxEPD2 L2 (luma 64-127 → darker) + 0x40, 0x48, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L3 (lightest/white) ← GxEPD2 L0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L4 VCOM + // Timing groups — Good Display reference timing + 0x0A, 0x19, 0x00, 0x03, 0x08, 0x00, 0x00, // Group0: 10+25 / 3+8 frames activation + 0x14, 0x01, 0x00, 0x14, 0x01, 0x00, 0x03, // Group1: 20+1 / 20+1 frames, RP=3 repeats + 0x0A, 0x03, 0x00, 0x08, 0x19, 0x00, 0x00, // Group2: 10+3 / 8+25 frames (mirror of G0) + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // Group3: 1 frame settle + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group4 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group5 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group6 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group8 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group9 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group11 + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, // XON + 0x22, 0x00, 0x01, 0xc7 // display update mode +}; + const uint8_t ssd1680_display_stop_sequence[] = { 0x10, DELAY, 0x01, 0x01, 0x64 }; @@ -135,10 +183,28 @@ const uint8_t ssd1680_display_refresh_sequence[] = { 0x20, 0x00, 0x00 }; -static bool detect_ssd1680(void) { - // Bitbang 4-wire SPI with a bidirectional data line to read register 0x71. - // On the IL0373 it will return 0x13 or similar. On the SSD1680 it is - // unsupported and will be 0xff. + +typedef enum { + DISPLAY_IL0373, + DISPLAY_SSD1680_COLSTART_0, + DISPLAY_SSD1680_COLSTART_8, // FPC-7519rev.b (User ID 0x44 or 0xca) +} display_type_t; + +static display_type_t detect_display_type(void) { + // Bitbang 4-wire SPI with a bidirectional data line to read the first byte of register 0x2e, + // which is the 10-byte USER ID. + // NOTE: the SSD1680 drives its response back on the MOSI/DATA line (GPIO35) in half-duplex + // mode, NOT on the separate MISO line (GPIO37). Read with GPIO35 switched to input. + // On the IL0373 it will return 0xff because it's not a valid register. + // With SSD1680, we have seen two types: + // 1. The first batch of displays, labeled "FPC-A005 20.06.15 TRX", which needs colstart=0. + // These have 10 bytes of zeros in the User ID. + // 2. Later panels, labeled "FPC-7519rev.b", which need colstart=8 and a tuned LUT/VCOM. + // Two controller variants exist within this panel generation: + // User ID [0x44, 0x0, 0x4, 0x0, 0x25, 0x0, 0x1, 0x78, 0x2b, 0xe] + // User ID [0xca, 0xfe, 0x0, 0x16, 0x80, 0x0, 0x75, 0x1, 0x0, 0x98] + // Both carry the same ribbon label and show the same display characteristics. + // So let's distinguish just by the first byte. digitalio_digitalinout_obj_t data; digitalio_digitalinout_obj_t clock; digitalio_digitalinout_obj_t chip_select; @@ -160,10 +226,16 @@ static bool detect_ssd1680(void) { common_hal_digitalio_digitalinout_switch_to_output(&chip_select, false, DRIVE_MODE_PUSH_PULL); common_hal_digitalio_digitalinout_switch_to_output(&data_command, false, DRIVE_MODE_PUSH_PULL); common_hal_digitalio_digitalinout_switch_to_output(&data, false, DRIVE_MODE_PUSH_PULL); - common_hal_digitalio_digitalinout_switch_to_output(&reset, true, DRIVE_MODE_PUSH_PULL); common_hal_digitalio_digitalinout_switch_to_output(&clock, false, DRIVE_MODE_PUSH_PULL); - uint8_t status_read = 0x71; + // Pulse RESET low to wake SSD1680 from deep sleep (entered via stop_sequence on prior run). + // SSD1680 ignores all SPI commands while in deep sleep; only a hardware reset exits it. + common_hal_digitalio_digitalinout_switch_to_output(&reset, false, DRIVE_MODE_PUSH_PULL); + common_hal_mcu_delay_us(200); + common_hal_digitalio_digitalinout_set_value(&reset, true); + common_hal_mcu_delay_us(10000); // 10ms for controller to come out of reset + + uint8_t status_read = 0x2e; // SSD1680 User ID register. Not a valid register on IL0373. for (int i = 0; i < 8; i++) { common_hal_digitalio_digitalinout_set_value(&data, (status_read & (1 << (7 - i))) != 0); common_hal_digitalio_digitalinout_set_value(&clock, true); @@ -192,11 +264,21 @@ static bool detect_ssd1680(void) { common_hal_digitalio_digitalinout_deinit(&chip_select); common_hal_digitalio_digitalinout_deinit(&data_command); common_hal_digitalio_digitalinout_deinit(&reset); - return status == 0xff; + + switch (status) { + case 0xff: + return DISPLAY_IL0373; + case 0x00: + return DISPLAY_SSD1680_COLSTART_0; + default: // unknown SSD1680 variant — assume newer panel needs colstart=8 + case 0x44: + case 0xca: + return DISPLAY_SSD1680_COLSTART_8; + } } void board_init(void) { - bool is_ssd1680 = detect_ssd1680(); + display_type_t display_type = detect_display_type(); fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; busio_spi_obj_t *spi = &bus->inline_bus; @@ -206,9 +288,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO7, // EPD_DC Command or data - &pin_GPIO8, // EPD_CS Chip select - &pin_GPIO6, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO7), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO8), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO6), // EPD_RST Reset 4000000, // Baudrate 0, // Polarity 0); // Phase @@ -216,11 +298,38 @@ void board_init(void) { epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - if (is_ssd1680) { + if (display_type == DISPLAY_IL0373) { + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = il0373_display_start_sequence; + args.start_sequence_len = sizeof(il0373_display_start_sequence); + args.stop_sequence = il0373_display_stop_sequence; + args.stop_sequence_len = sizeof(il0373_display_stop_sequence); + args.width = 296; + args.height = 128; + args.ram_width = 160; + args.ram_height = 296; + args.rotation = 270; + args.write_black_ram_command = 0x10; + args.write_color_ram_command = 0x13; + args.refresh_sequence = il0373_display_refresh_sequence; + args.refresh_sequence_len = sizeof(il0373_display_refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO5; + args.seconds_per_frame = 5.0; + args.grayscale = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); + } else { epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; args.bus = bus; - args.start_sequence = ssd1680_display_start_sequence; - args.start_sequence_len = sizeof(ssd1680_display_start_sequence); + if (display_type == DISPLAY_SSD1680_COLSTART_8) { + args.colstart = 8; + args.start_sequence = ssd1680_fpc7519_display_start_sequence; + args.start_sequence_len = sizeof(ssd1680_fpc7519_display_start_sequence); + } else { + args.start_sequence = ssd1680_display_start_sequence; + args.start_sequence_len = sizeof(ssd1680_display_start_sequence); + } args.stop_sequence = ssd1680_display_stop_sequence; args.stop_sequence_len = sizeof(ssd1680_display_stop_sequence); args.width = 296; @@ -244,27 +353,6 @@ void board_init(void) { args.two_byte_sequence_length = true; args.address_little_endian = true; common_hal_epaperdisplay_epaperdisplay_construct(display, &args); - } else { - epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; - args.bus = bus; - args.start_sequence = il0373_display_start_sequence; - args.start_sequence_len = sizeof(il0373_display_start_sequence); - args.stop_sequence = il0373_display_stop_sequence; - args.stop_sequence_len = sizeof(il0373_display_stop_sequence); - args.width = 296; - args.height = 128; - args.ram_width = 160; - args.ram_height = 296; - args.rotation = 270; - args.write_black_ram_command = 0x10; - args.write_color_ram_command = 0x13; - args.refresh_sequence = il0373_display_refresh_sequence; - args.refresh_sequence_len = sizeof(il0373_display_refresh_sequence); - args.refresh_time = 1.0; - args.busy_pin = &pin_GPIO5; - args.seconds_per_frame = 5.0; - args.grayscale = true; - common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } } diff --git a/ports/espressif/boards/adafruit_p4gpio/board.c b/ports/espressif/boards/adafruit_p4gpio/board.c new file mode 100644 index 00000000000..8287c3ea247 --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.h b/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.h new file mode 100644 index 00000000000..294896c5c34 --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Adafruit P4 GPIO" +#define MICROPY_HW_MCU_NAME "ESP32P4" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO52) + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO35) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO54) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO53) + +// Use the second USB device (numbered 0 and 1) -- HS PHY routed to J1. +#define CIRCUITPY_USB_DEVICE_INSTANCE 1 +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + +// FS USB on GPIO24/25 routed to J2. +#define CIRCUITPY_USB_HOST_INSTANCE 0 diff --git a/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.mk b/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.mk new file mode 100644 index 00000000000..dc1560b2bb5 --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x239A +USB_PID = 0x8174 +USB_PRODUCT = "Adafruit P4 GPIO" +USB_MANUFACTURER = "Adafruit" + +IDF_TARGET = esp32p4 + +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 32MB +CIRCUITPY_ESP_PSRAM_MODE = hpi +CIRCUITPY_ESP_PSRAM_FREQ = 200m diff --git a/ports/espressif/boards/adafruit_p4gpio/pins.c b/ports/espressif/boards/adafruit_p4gpio/pins.c new file mode 100644 index 00000000000..77ed1f89513 --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/pins.c @@ -0,0 +1,85 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Header J8 (B1) + { MP_ROM_QSTR(MP_QSTR_B1_0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_B1_1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_B1_2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_B1_3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_B1_4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_B1_5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_B1_6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_B1_7), MP_ROM_PTR(&pin_GPIO7) }, + + // Header J7 (B2) + { MP_ROM_QSTR(MP_QSTR_B2_0), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_B2_1), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_B2_2), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_B2_3), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_B2_4), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_B2_5), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_B2_6), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_B2_7), MP_ROM_PTR(&pin_GPIO15) }, + + // Header J6 (B3) + { MP_ROM_QSTR(MP_QSTR_B3_0), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_B3_1), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_B3_2), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_B3_3), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_B3_4), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_B3_5), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_B3_6), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_B3_7), MP_ROM_PTR(&pin_GPIO23) }, + + // Header J3 (T3) + { MP_ROM_QSTR(MP_QSTR_T3_0), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_T3_1), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_T3_2), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_T3_3), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_T3_4), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_T3_5), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_T3_6), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_T3_7), MP_ROM_PTR(&pin_GPIO26) }, + + // Header J4 (T2) + { MP_ROM_QSTR(MP_QSTR_T2_0), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_T2_1), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_T2_2), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_T2_3), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_T2_4), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_T2_5), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_T2_6), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_T2_7), MP_ROM_PTR(&pin_GPIO34) }, + + // Header J5 (T1) + { MP_ROM_QSTR(MP_QSTR_T1_0), MP_ROM_PTR(&pin_GPIO51) }, + { MP_ROM_QSTR(MP_QSTR_T1_1), MP_ROM_PTR(&pin_GPIO50) }, + { MP_ROM_QSTR(MP_QSTR_T1_2), MP_ROM_PTR(&pin_GPIO49) }, + { MP_ROM_QSTR(MP_QSTR_T1_3), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_T1_4), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_T1_5), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_T1_6), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_T1_7), MP_ROM_PTR(&pin_GPIO44) }, + + // Boot button (also exposed on J9/J10 pin 2) + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO35) }, + + // NeoPixel + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO52) }, + + // StemmaQT / Qwiic I2C (J11) + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO54) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/adafruit_p4gpio/sdkconfig b/ports/espressif/boards/adafruit_p4gpio/sdkconfig new file mode 100644 index 00000000000..681e52bf82c --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/sdkconfig @@ -0,0 +1,70 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Bootloader config +# +# +# Log +# +# +# Format +# +# CONFIG_BOOTLOADER_LOG_COLORS is not set +# end of Format + +# end of Log + +# default: +CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ=90 +# +# Serial Flash Configurations +# +# CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT is not set +# end of Serial Flash Configurations + +# end of Bootloader config + +# +# Component config +# +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +# end of Bluetooth + +# +# Hardware Settings +# +# +# Chip revision +# +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESP32P4_REV_MIN_100=y +# default: +CONFIG_ESP32P4_REV_MIN_FULL=100 +# default: +CONFIG_ESP_REV_MIN_FULL=100 +# default: +CONFIG_ESP32P4_REV_MAX_FULL=199 +# default: +CONFIG_ESP_REV_MAX_FULL=199 +# end of Chip revision + +# end of Hardware Settings + +# +# ESP System Settings +# +# default: +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_360=y +# default: +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_400 is not set +# default: +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=360 +# end of ESP System Settings + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/adafruit_qtpy_esp32_pico/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32_pico/mpconfigboard.h index 799a53c5c78..a0bc2b9f374 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32_pico/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_qtpy_esp32_pico/mpconfigboard.h @@ -26,3 +26,6 @@ // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h index c59dbfc81c9..a0c73d0bcdf 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h @@ -25,3 +25,6 @@ #define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO5, .rx = &pin_GPIO16}} #define DOUBLE_TAP_PIN (&pin_GPIO10) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/adafruit_qtpy_esp32s3_4mbflash_2mbpsram/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32s3_4mbflash_2mbpsram/mpconfigboard.h index ad97ab057fb..9760bbfeb44 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32s3_4mbflash_2mbpsram/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_qtpy_esp32s3_4mbflash_2mbpsram/mpconfigboard.h @@ -25,3 +25,6 @@ #define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO5, .rx = &pin_GPIO16}} #define DOUBLE_TAP_PIN (&pin_GPIO10) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h index fcdefda3b40..6073bd47d0e 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h @@ -25,3 +25,6 @@ #define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO5, .rx = &pin_GPIO16}} #define DOUBLE_TAP_PIN (&pin_GPIO10) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/adafruit_sparkle_motion/pins.c b/ports/espressif/boards/adafruit_sparkle_motion/pins.c index d78c1e1c4c7..f22cb50608d 100644 --- a/ports/espressif/boards/adafruit_sparkle_motion/pins.c +++ b/ports/espressif/boards/adafruit_sparkle_motion/pins.c @@ -46,6 +46,10 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SIG4), MP_ROM_PTR(&pin_GPIO23) }, { MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_D26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_D33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk index 9ca2eee1577..e51bdc7d8cc 100644 --- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk +++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk @@ -9,6 +9,12 @@ CIRCUITPY_ESP_FLASH_SIZE = 2MB CIRCUITPY_DUALBANK = 0 +CIRCUITPY_AESIO = 0 +CIRCUITPY_CANIO = 0 +CIRCUITPY_GETPASS = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 +CIRCUITPY_PS2IO = 0 +CIRCUITPY_ZLIB = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig index e9628662160..79713bb57e8 100644 --- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig +++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig @@ -9,6 +9,30 @@ # # end of LWIP +# +# Wireless Coexistence +# +# CONFIG_ESP_COEX_SW_COEXIST_ENABLE is not set +# end of Wireless Coexistence + +# +# LibC +# +# CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS is not set +# end of LibC + +# +# mbedTLS +# +# +# Certificate Bundle +# +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y +# end of Certificate Bundle +# +# end of mbedTLS + # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h b/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h index 8f20dc5bfe2..31dba37970c 100644 --- a/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h +++ b/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h @@ -22,3 +22,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define MICROPY_HW_NEOPIXEL (&pin_GPIO40) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.h b/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.h index 44171d1dc4d..65832e3cc9c 100644 --- a/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.h +++ b/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.h @@ -25,3 +25,6 @@ // For entering safe mode, use BOOT button #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/circuitart_zero_s3/mpconfigboard.h b/ports/espressif/boards/circuitart_zero_s3/mpconfigboard.h index 973e6118393..973e2f5bac2 100644 --- a/ports/espressif/boards/circuitart_zero_s3/mpconfigboard.h +++ b/ports/espressif/boards/circuitart_zero_s3/mpconfigboard.h @@ -32,3 +32,6 @@ #define DEFAULT_TFT_CS (&pin_GPIO39) #define DEFAULT_TFT_DC (&pin_GPIO5) #define DEFAULT_TFT_RST (&pin_GPIO40) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/deshipu_ugame_s3/board.c b/ports/espressif/boards/deshipu_ugame_s3/board.c new file mode 100644 index 00000000000..dc09786e74c --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/board.c @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 "supervisor/board.h" +#include "mpconfigboard.h" + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + +#include "esp_log.h" +#include "esp_err.h" + +fourwire_fourwire_obj_t board_display_obj; + +#define DELAY 0x80 + +uint8_t display_init_sequence[] = { + 0x01, 0 | DELAY, 0x80, // Software reset then delay 0x80 (128ms) + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + 0xc0, 1, 0x23, // Power control VRH[5:0] + 0xc1, 1, 0x10, // Power control SAP[2:0];BT[3:0] + 0xc5, 2, 0x3e, 0x28, // VCM control + 0xc7, 1, 0x86, // VCM control2 + 0x37, 1, 0x00, // Vertical scroll zero + 0x3a, 1, 0x55, // COLMOD: Pixel Format Set + 0xb1, 2, 0x00, 0x18, // Frame Rate Control (In Normal Mode/Full Colors) + 0xb6, 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + 0x26, 1, 0x01, // Gamma curve selected + 0xe0, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma + 0xe1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma + 0x11, 0 | DELAY, 0x78, // Exit Sleep then delay 0x78 (120ms) + 0x29, 0 | DELAY, 0x78, // Display on then delay 0x78 (120ms) + 0x36, 1, 0x38, +}; + + +void board_init(void) { + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO12, &pin_GPIO11, NULL, false); + common_hal_busio_spi_never_reset(spi); + + bus->base.type = &fourwire_fourwire_type; + common_hal_fourwire_fourwire_construct(bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO10), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO13), // TFT_RESET Reset + 48000000L, // Baudrate + 0, // Polarity + 0); // Phase + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 320, // Width (after rotation) + 240, // Height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // Color depth + false, // Grayscale + false, // Pixels in a byte share a row. Only used for depth < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command + MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO21, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 20, // native_frames_per_second + true, // backlight_on_high + false, // not SH1107 + 50000); // backlight pwm frequency +} + +void board_deinit(void) { +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h new file mode 100644 index 00000000000..da7c3b4e8a4 --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h @@ -0,0 +1,28 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Scott Shawcroft for Adafruit Industries + * + * 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 "uGame S3" +#define MICROPY_HW_MCU_NAME "ESP32S3" diff --git a/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk new file mode 100644 index 00000000000..36a0ce040c5 --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk @@ -0,0 +1,27 @@ +USB_VID = 0x1209 +USB_PID = 0xD187 +USB_PRODUCT = "uGameS3" +USB_MANUFACTURER = "deshipu" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +CIRCUITPY_STAGE = 1 +CIRCUITPY_KEYPAD = 1 + +CIRCUITPY_CANIO = 0 +CIRCUITPY_DUALBANK = 0 +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_FRAMEBUFFERIO = 0 +CIRCUITPY_PARALLELDISPLAYBUS = 0 +CIRCUITPY_RGBMATRIX = 0 +CIRCUITPY_ROTARYIO = 0 + +FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/ugame_s3 diff --git a/ports/espressif/boards/deshipu_ugame_s3/pins.c b/ports/espressif/boards/deshipu_ugame_s3/pins.c new file mode 100644 index 00000000000..54bd5dcdb4f --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/pins.c @@ -0,0 +1,43 @@ +#include "py/objtuple.h" +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_P1), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_P2), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_P3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_P4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_P5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_P6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_P7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_LEFT), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_UP), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_DOWN), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_O), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_Z), MP_ROM_PTR(&pin_GPIO47) }, + + { MP_ROM_QSTR(MP_QSTR_LIGHT), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_GPIO8) }, + + + { MP_ROM_QSTR(MP_QSTR_AUDIO_BCLK), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_LRCLK), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_DATA), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_GAIN), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/deshipu_ugame_s3/sdkconfig b/ports/espressif/boards/deshipu_ugame_s3/sdkconfig new file mode 100644 index 00000000000..1bddb7a89fb --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/sdkconfig @@ -0,0 +1,22 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="espressif-esp32s3" +# end of LWIP + +# +# Camera configuration +# +# CONFIG_OV7725_SUPPORT is not set +# CONFIG_OV3660_SUPPORT is not set +# end of Camera configuration + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/elecrow_crowpanel_3.5/board.c b/ports/espressif/boards/elecrow_crowpanel_3.5/board.c index 3adfb512e3f..f52f23a9ae8 100755 --- a/ports/espressif/boards/elecrow_crowpanel_3.5/board.c +++ b/ports/espressif/boards/elecrow_crowpanel_3.5/board.c @@ -54,9 +54,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO2, // TFT_DC Command or data - &pin_GPIO15, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS Chip select + mp_const_none, // TFT_RST Reset 20000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c b/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c index 04f5f92f85b..c292ea113aa 100644 --- a/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c +++ b/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c @@ -56,9 +56,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO46, // EPD_DC Command or data - &pin_GPIO45, // EPD_CS Chip select - &pin_GPIO47, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO46), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO45), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO47), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/board.c b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.h b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.h new file mode 100644 index 00000000000..ca05bf78b6a --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "ESP32-C5-DevKitC-1-N8R8" +#define MICROPY_HW_MCU_NAME "ESP32C5" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO27) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO12) +#define DEFAULT_UART_BUS_TX (&pin_GPIO11) diff --git a/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.mk new file mode 100644 index 00000000000..0da008596e3 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.mk @@ -0,0 +1,12 @@ +CIRCUITPY_CREATOR_ID = 0x000C303A +CIRCUITPY_CREATION_ID = 0x00C50001 + +IDF_TARGET = esp32c5 + +CIRCUITPY_ESP_FLASH_MODE = dio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 40m diff --git a/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/pins.c b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/pins.c new file mode 100644 index 00000000000..dc4a478a592 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/pins.c @@ -0,0 +1,40 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_IO28), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/sdkconfig b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/board.c b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.h b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.h new file mode 100644 index 00000000000..d901bfb37ba --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.h @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "ESP32-C61-DevKitC-1-N8R2" +#define MICROPY_HW_MCU_NAME "ESP32C61" + +#define DEFAULT_UART_BUS_RX (&pin_GPIO10) +#define DEFAULT_UART_BUS_TX (&pin_GPIO11) diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.mk new file mode 100644 index 00000000000..1092a874a68 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.mk @@ -0,0 +1,13 @@ +CIRCUITPY_CREATOR_ID = 0x000C303A +CIRCUITPY_CREATION_ID = 0x00C61001 + +IDF_TARGET = esp32c61 +IDF_TARGET_ARCH = riscv + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 2MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/pins.c b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/pins.c new file mode 100644 index 00000000000..901e5216657 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/pins.c @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_IO28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_IO29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/sdkconfig b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h b/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h index 646fb62e562..89a103e6196 100644 --- a/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h +++ b/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -16,5 +16,11 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO38) #define DEFAULT_UART_BUS_TX (&pin_GPIO37) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO8) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO7) + // Use the second USB device (numbered 0 and 1) #define CIRCUITPY_USB_DEVICE_INSTANCE 1 +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + +#define CIRCUITPY_USB_HOST_INSTANCE 0 diff --git a/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c b/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c index 3bb64f434d0..165ce711b73 100644 --- a/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c +++ b/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -9,47 +9,82 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS - { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, - { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, - { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, - { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, - { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + // Header Block J1 + { MP_ROM_QSTR(MP_QSTR_I2C_SDA), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_I2C_SCL), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, - { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, - { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, - { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, - { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, - { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, - { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, - { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, - { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, - { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, - { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, - { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, - { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, - { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, - { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO37) }, { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO38) }, { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, - { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, - { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, - { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, - { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, - { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, - { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, - { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_C6_WAKEUP), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + + { MP_ROM_QSTR(MP_QSTR_IO32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + + { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_C6_EN), MP_ROM_PTR(&pin_GPIO54) }, + { MP_ROM_QSTR(MP_QSTR_IO54), MP_ROM_PTR(&pin_GPIO54) }, + + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + + { MP_ROM_QSTR(MP_QSTR_PA_CTRL), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_IO53), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, - { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, - { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + + // I2S + { MP_ROM_QSTR(MP_QSTR_I2S_DSDIN), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_I2S_ASDOUT), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCLK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_ROM_PTR(&pin_GPIO13) }, + + // Ethernet + { MP_ROM_QSTR(MP_QSTR_RMII_RXDV), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_RMII_RXD0), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_RMII_RXD1), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_MDC), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXD0), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXD1), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXEN), MP_ROM_PTR(&pin_GPIO49) }, + { MP_ROM_QSTR(MP_QSTR_RMII_CLK), MP_ROM_PTR(&pin_GPIO50) }, + { MP_ROM_QSTR(MP_QSTR_PHY_RSTN), MP_ROM_PTR(&pin_GPIO51) }, + { MP_ROM_QSTR(MP_QSTR_MDIO), MP_ROM_PTR(&pin_GPIO52) }, - { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, - { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + // SD Card + { MP_ROM_QSTR(MP_QSTR_SD_DATA0), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA1), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA2), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA3), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_SD_PWRN), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32p4_function_ev/sdkconfig b/ports/espressif/boards/espressif_esp32p4_function_ev/sdkconfig index e69de29bb2d..3bce8cc0c13 100644 --- a/ports/espressif/boards/espressif_esp32p4_function_ev/sdkconfig +++ b/ports/espressif/boards/espressif_esp32p4_function_ev/sdkconfig @@ -0,0 +1,2 @@ +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESP32P4_REV_MIN_100=y diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/board.c b/ports/espressif/boards/espressif_esp32p4x_function_ev/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.h b/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.h new file mode 100644 index 00000000000..d0b44fdff58 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "ESP32-P4X-Function-EV" +#define MICROPY_HW_MCU_NAME "ESP32P4" + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO38) +#define DEFAULT_UART_BUS_TX (&pin_GPIO37) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO8) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO7) + +// Use the second USB device (numbered 0 and 1) +#define CIRCUITPY_USB_DEVICE_INSTANCE 1 +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + +#define CIRCUITPY_USB_HOST_INSTANCE 0 diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.mk new file mode 100644 index 00000000000..bad638a0018 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.mk @@ -0,0 +1,16 @@ +USB_VID = 0x303A +USB_PID = 0x7014 +USB_PRODUCT = "ESP32-P4X-Function-EV" +USB_MANUFACTURER = "Espressif" + +IDF_TARGET = esp32p4 + +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 32MB +CIRCUITPY_ESP_PSRAM_MODE = hpi +CIRCUITPY_ESP_PSRAM_FREQ = 200m + +CIRCUITPY_ESP32P4_REV = 3 diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/pins.c b/ports/espressif/boards/espressif_esp32p4x_function_ev/pins.c new file mode 100644 index 00000000000..165ce711b73 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/pins.c @@ -0,0 +1,90 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Header Block J1 + { MP_ROM_QSTR(MP_QSTR_I2C_SDA), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_I2C_SCL), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_C6_WAKEUP), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + + { MP_ROM_QSTR(MP_QSTR_IO32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + + { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_C6_EN), MP_ROM_PTR(&pin_GPIO54) }, + { MP_ROM_QSTR(MP_QSTR_IO54), MP_ROM_PTR(&pin_GPIO54) }, + + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + + { MP_ROM_QSTR(MP_QSTR_PA_CTRL), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_IO53), MP_ROM_PTR(&pin_GPIO53) }, + + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + + // I2S + { MP_ROM_QSTR(MP_QSTR_I2S_DSDIN), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_I2S_ASDOUT), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCLK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_ROM_PTR(&pin_GPIO13) }, + + // Ethernet + { MP_ROM_QSTR(MP_QSTR_RMII_RXDV), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_RMII_RXD0), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_RMII_RXD1), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_MDC), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXD0), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXD1), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXEN), MP_ROM_PTR(&pin_GPIO49) }, + { MP_ROM_QSTR(MP_QSTR_RMII_CLK), MP_ROM_PTR(&pin_GPIO50) }, + { MP_ROM_QSTR(MP_QSTR_PHY_RSTN), MP_ROM_PTR(&pin_GPIO51) }, + { MP_ROM_QSTR(MP_QSTR_MDIO), MP_ROM_PTR(&pin_GPIO52) }, + + // SD Card + { MP_ROM_QSTR(MP_QSTR_SD_DATA0), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA1), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA2), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA3), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_SD_PWRN), MP_ROM_PTR(&pin_GPIO45) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/sdkconfig b/ports/espressif/boards/espressif_esp32p4x_function_ev/sdkconfig new file mode 100644 index 00000000000..a062a5b5c48 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/sdkconfig @@ -0,0 +1,68 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Bootloader config +# +# +# Log +# +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +# CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set +# default: +CONFIG_BOOTLOADER_LOG_LEVEL=2 +# +# Format +# +# CONFIG_BOOTLOADER_LOG_COLORS is not set +# end of Format + +# end of Log + +# end of Bootloader config + +# +# Component config +# +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +# end of Bluetooth + +# +# Hardware Settings +# +# +# Chip revision +# +# CONFIG_ESP32P4_REV_MIN_300 is not set +CONFIG_ESP32P4_REV_MIN_301=y +# default: +CONFIG_ESP32P4_REV_MIN_FULL=301 +# default: +CONFIG_ESP_REV_MIN_FULL=301 +# end of Chip revision + +# default: +CONFIG_P4_REV3_MSPI_CRASH_AFTER_POWER_UP_WORKAROUND=y +# default: +CONFIG_P4_REV3_MSPI_WORKAROUND_SIZE=0x100 +# end of Hardware Settings + +# +# ESP-STDIO +# +# CONFIG_ESP_CONSOLE_UART_DEFAULT is not set +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y +# default: +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y +# default: +CONFIG_ESP_CONSOLE_UART_NUM=-1 +# default: +CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=6 +# end of ESP-STDIO + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/espressif_esp32s3_box/board.c b/ports/espressif/boards/espressif_esp32s3_box/board.c index 54edb47bac3..a27411fd79c 100644 --- a/ports/espressif/boards/espressif_esp32s3_box/board.c +++ b/ports/espressif/boards/espressif_esp32s3_box/board.c @@ -31,9 +31,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO48, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO48), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/espressif_esp32s3_box_lite/board.c b/ports/espressif/boards/espressif_esp32s3_box_lite/board.c index e675c0f915b..48a49e03bc3 100644 --- a/ports/espressif/boards/espressif_esp32s3_box_lite/board.c +++ b/ports/espressif/boards/espressif_esp32s3_box_lite/board.c @@ -32,9 +32,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO48, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO48), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/board.c b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.h new file mode 100644 index 00000000000..9df0ebcdb40 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "ESP32-S3-DevKitC-1-N32R16" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO38) + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +#define AUTORESET_DELAY_MS 500 diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.mk new file mode 100644 index 00000000000..15fcf8697fc --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x7003 +USB_PRODUCT = "ESP32-S3-DevKitC-1-N32R16" +USB_MANUFACTURER = "Espressif" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_SIZE = 32MB +CIRCUITPY_ESP_FLASH_MODE = opi +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 16MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/pins.c b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/pins.c new file mode 100644 index 00000000000..e77a3813e94 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/pins.c @@ -0,0 +1,55 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO38) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/sdkconfig b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk index 336b9f4dd89..b6ae3cf73b4 100644 --- a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk @@ -13,4 +13,4 @@ CIRCUITPY_ESP_PSRAM_SIZE = 2MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 80m -CIRCUITPY_RCLCPY = 1 +CIRCUITPY_RCLCPY = 0 diff --git a/ports/espressif/boards/espressif_esp32s3_eye/board.c b/ports/espressif/boards/espressif_esp32s3_eye/board.c index c48c9428cf4..43445b034e4 100644 --- a/ports/espressif/boards/espressif_esp32s3_eye/board.c +++ b/ports/espressif/boards/espressif_esp32s3_eye/board.c @@ -56,9 +56,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO43, // DC - &pin_GPIO44, // CS - NULL, // no reset pin + MP_OBJ_FROM_PTR(&pin_GPIO43), // DC + MP_OBJ_FROM_PTR(&pin_GPIO44), // CS + mp_const_none, // no reset pin 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c index 94d08bb56c8..96513a14741 100644 --- a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c +++ b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c @@ -7,6 +7,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" #include "shared-bindings/microcontroller/Pin.h" +#include "driver/gpio.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/fourwire/FourWire.h" @@ -59,9 +60,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO8, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO8), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/hardkernel_odroid_go/board.c b/ports/espressif/boards/hardkernel_odroid_go/board.c index 647fcd740eb..0c2fe8a87c3 100644 --- a/ports/espressif/boards/hardkernel_odroid_go/board.c +++ b/ports/espressif/boards/hardkernel_odroid_go/board.c @@ -6,6 +6,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/fourwire/FourWire.h" #include "shared-module/displayio/__init__.h" @@ -51,9 +52,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO21, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO21), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + mp_const_none, // TFT_RST Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/heltec_vision_master_e290/board.c b/ports/espressif/boards/heltec_vision_master_e290/board.c index 9749f5c7048..5a102c7119b 100644 --- a/ports/espressif/boards/heltec_vision_master_e290/board.c +++ b/ports/espressif/boards/heltec_vision_master_e290/board.c @@ -54,9 +54,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // EPD_DC Command or data - &pin_GPIO3, // EPD_CS Chip select - &pin_GPIO5, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO3), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO5), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/heltec_wireless_paper/board.c b/ports/espressif/boards/heltec_wireless_paper/board.c index c796a9be884..38f6472e085 100644 --- a/ports/espressif/boards/heltec_wireless_paper/board.c +++ b/ports/espressif/boards/heltec_wireless_paper/board.c @@ -94,9 +94,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO5, // EPD_DC Command or data - &pin_GPIO4, // EPD_CS Chip select - &pin_GPIO6, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO5), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO4), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO6), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/hexky_s2/board.c b/ports/espressif/boards/hexky_s2/board.c index c1e1801fed6..41f97796be4 100644 --- a/ports/espressif/boards/hexky_s2/board.c +++ b/ports/espressif/boards/hexky_s2/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO34, // DC - &pin_GPIO33, // CS - &pin_GPIO41, // RST + MP_OBJ_FROM_PTR(&pin_GPIO34), // DC + MP_OBJ_FROM_PTR(&pin_GPIO33), // CS + MP_OBJ_FROM_PTR(&pin_GPIO41), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/hiibot_iots2/board.c b/ports/espressif/boards/hiibot_iots2/board.c index e9941cbc368..e3af7b45835 100644 --- a/ports/espressif/boards/hiibot_iots2/board.c +++ b/ports/espressif/boards/hiibot_iots2/board.c @@ -62,9 +62,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO35, // DC - &pin_GPIO36, // CS - NULL, // NO RST ? + MP_OBJ_FROM_PTR(&pin_GPIO35), // DC + MP_OBJ_FROM_PTR(&pin_GPIO36), // CS + mp_const_none, // NO RST ? 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/board.c b/ports/espressif/boards/ikea_alpstuga_esp32_s3/board.c new file mode 100644 index 00000000000..6d735a9b031 --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/board.c @@ -0,0 +1,12 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "driver/gpio.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.h b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.h new file mode 100644 index 00000000000..9a826047351 --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Ikea Alpstuga Drop-In ESP32S3 4MB Flash 2MB PSRAM" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO33) + +#define MICROPY_HW_LED_STATUS (&pin_GPIO9) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO4) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO3) + +#define DOUBLE_TAP_PIN (&pin_GPIO34) diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk new file mode 100644 index 00000000000..fbfb0f1ed3f --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x239A +USB_PID = 0x8178 +USB_PRODUCT = "Ikea Alpstuga Drop-In ESP32S3 4MB Flash 2MB PSRAM" +USB_MANUFACTURER = "Adafruit" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_SIZE = 4MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 2MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/pins.c b/ports/espressif/boards/ikea_alpstuga_esp32_s3/pins.c new file mode 100644 index 00000000000..20991f032bd --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/pins.c @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_1), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_2), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_3), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO33) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/sdkconfig b/ports/espressif/boards/ikea_alpstuga_esp32_s3/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/lilygo_tdeck/board.c b/ports/espressif/boards/lilygo_tdeck/board.c index 91a2f6d2ad7..45b889760a1 100644 --- a/ports/espressif/boards/lilygo_tdeck/board.c +++ b/ports/espressif/boards/lilygo_tdeck/board.c @@ -32,9 +32,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO11, // TFT_DC Command or data - &pin_GPIO12, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO11), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO12), // TFT_CS Chip select + mp_const_none, // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/lilygo_tdisplay_s3/board.c b/ports/espressif/boards/lilygo_tdisplay_s3/board.c index fe62edf1ed8..a02dab7173d 100644 --- a/ports/espressif/boards/lilygo_tdisplay_s3/board.c +++ b/ports/espressif/boards/lilygo_tdisplay_s3/board.c @@ -6,6 +6,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" #include "shared-module/displayio/mipi_constants.h" diff --git a/ports/espressif/boards/lilygo_tdisplay_s3_pro/board.c b/ports/espressif/boards/lilygo_tdisplay_s3_pro/board.c index ede20df200f..0782e2161ca 100644 --- a/ports/espressif/boards/lilygo_tdisplay_s3_pro/board.c +++ b/ports/espressif/boards/lilygo_tdisplay_s3_pro/board.c @@ -34,9 +34,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO9, // TFT_DC Command or data - &pin_GPIO39, // TFT_CS Chip select - &pin_GPIO47, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO39), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO47), // TFT_RST Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/lilygo_tdongle_s3/board.c b/ports/espressif/boards/lilygo_tdongle_s3/board.c index 8907dc7fe98..47fef9ee214 100644 --- a/ports/espressif/boards/lilygo_tdongle_s3/board.c +++ b/ports/espressif/boards/lilygo_tdongle_s3/board.c @@ -60,9 +60,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO2, // DC - &pin_GPIO4, // CS - &pin_GPIO1, // RST + MP_OBJ_FROM_PTR(&pin_GPIO2), // DC + MP_OBJ_FROM_PTR(&pin_GPIO4), // CS + MP_OBJ_FROM_PTR(&pin_GPIO1), // RST 10000000, // baudrate 0, // polarity 0 // phase @@ -97,7 +97,7 @@ static void display_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true, // backlight_on_high + false, // backlight_on_high false, // SH1107_addressing 50000 // backlight pwm frequency ); diff --git a/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h b/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h index fe5525ef056..a987bac317b 100644 --- a/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h +++ b/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h @@ -11,5 +11,11 @@ #define MICROPY_HW_BOARD_NAME "LILYGO T-Dongle S3" #define MICROPY_HW_MCU_NAME "ESP32S3" -#define DEFAULT_UART_BUS_RX (&pin_GPIO44) -#define DEFAULT_UART_BUS_TX (&pin_GPIO43) +#define MICROPY_HW_APA102_MOSI (&pin_GPIO40) +#define MICROPY_HW_APA102_SCK (&pin_GPIO39) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO44) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/lilygo_tembed_esp32s3/board.c b/ports/espressif/boards/lilygo_tembed_esp32s3/board.c index 698e6980ece..46e2ecf863c 100644 --- a/ports/espressif/boards/lilygo_tembed_esp32s3/board.c +++ b/ports/espressif/boards/lilygo_tembed_esp32s3/board.c @@ -32,9 +32,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO13, // TFT_DC Command or data - &pin_GPIO10, // TFT_CS Chip select - &pin_GPIO9, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO13), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO10), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/lilygo_tqt_pro_nopsram/board.c b/ports/espressif/boards/lilygo_tqt_pro_nopsram/board.c index c7e711aee66..fe72222a22c 100644 --- a/ports/espressif/boards/lilygo_tqt_pro_nopsram/board.c +++ b/ports/espressif/boards/lilygo_tqt_pro_nopsram/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO6, // DC - &pin_GPIO5, // CS - &pin_GPIO1, // RST + MP_OBJ_FROM_PTR(&pin_GPIO6), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO1), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_tqt_pro_psram/board.c b/ports/espressif/boards/lilygo_tqt_pro_psram/board.c index c7e711aee66..fe72222a22c 100644 --- a/ports/espressif/boards/lilygo_tqt_pro_psram/board.c +++ b/ports/espressif/boards/lilygo_tqt_pro_psram/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO6, // DC - &pin_GPIO5, // CS - &pin_GPIO1, // RST + MP_OBJ_FROM_PTR(&pin_GPIO6), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO1), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.h b/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.h index 247e58d916d..382f6e3f598 100644 --- a/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.h +++ b/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.h @@ -16,3 +16,6 @@ #define CIRCUITPY_CONSOLE_UART_RX DEFAULT_UART_BUS_RX #define CIRCUITPY_CONSOLE_UART_TX DEFAULT_UART_BUS_TX + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/board.c b/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/board.c index 2b77e24b91e..6fcfb5c19a4 100644 --- a/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/board.c +++ b/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/board.c @@ -62,9 +62,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO37, // DC - &pin_GPIO34, // CS - &pin_GPIO38, // RST + MP_OBJ_FROM_PTR(&pin_GPIO37), // DC + MP_OBJ_FROM_PTR(&pin_GPIO34), // CS + MP_OBJ_FROM_PTR(&pin_GPIO38), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_16m/board.c b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_16m/board.c index 97574398ca2..8ed5462a2d3 100644 --- a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_16m/board.c +++ b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_16m/board.c @@ -42,9 +42,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO16, // DC - &pin_GPIO5, // CS - &pin_GPIO23, // RST + MP_OBJ_FROM_PTR(&pin_GPIO16), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO23), // RST 24000000, // baudrate (default from the driver) // 40000000, 0, // polarity diff --git a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/board.c b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/board.c index 2d3cb64d455..a90cc5eb66a 100644 --- a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/board.c +++ b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/board.c @@ -41,9 +41,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO16, // DC - &pin_GPIO5, // CS - &pin_GPIO23, // RST + MP_OBJ_FROM_PTR(&pin_GPIO16), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO23), // RST 24000000, // baudrate (default from the driver) // 40000000, 0, // polarity diff --git a/ports/espressif/boards/lilygo_twatch_2020_v3/board.c b/ports/espressif/boards/lilygo_twatch_2020_v3/board.c index 266515c2338..5ea85ec00c6 100644 --- a/ports/espressif/boards/lilygo_twatch_2020_v3/board.c +++ b/ports/espressif/boards/lilygo_twatch_2020_v3/board.c @@ -46,9 +46,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO5, // CS - NULL, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + mp_const_none, // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_twatch_s3/board.c b/ports/espressif/boards/lilygo_twatch_s3/board.c index 51f5933d177..a9fd3db46e7 100644 --- a/ports/espressif/boards/lilygo_twatch_s3/board.c +++ b/ports/espressif/boards/lilygo_twatch_s3/board.c @@ -108,9 +108,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO38, // DC - &pin_GPIO12, // CS - NULL, // RST + MP_OBJ_FROM_PTR(&pin_GPIO38), // DC + MP_OBJ_FROM_PTR(&pin_GPIO12), // CS + mp_const_none, // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lolin_c3_pico/mpconfigboard.h b/ports/espressif/boards/lolin_c3_pico/mpconfigboard.h index 24800307223..6ee4cd4cf95 100644 --- a/ports/espressif/boards/lolin_c3_pico/mpconfigboard.h +++ b/ports/espressif/boards/lolin_c3_pico/mpconfigboard.h @@ -26,3 +26,6 @@ #define CIRCUITPY_BOARD_UART (1) #define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO21, .rx = &pin_GPIO20}} + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/lolin_s3_mini_pro/board.c b/ports/espressif/boards/lolin_s3_mini_pro/board.c index cd5a083dbdb..39e645bc7b5 100644 --- a/ports/espressif/boards/lolin_s3_mini_pro/board.c +++ b/ports/espressif/boards/lolin_s3_mini_pro/board.c @@ -39,9 +39,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO36, // DC - &pin_GPIO35, // CS - &pin_GPIO34, // RST + MP_OBJ_FROM_PTR(&pin_GPIO36), // DC + MP_OBJ_FROM_PTR(&pin_GPIO35), // CS + MP_OBJ_FROM_PTR(&pin_GPIO34), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lolin_s3_mini_pro/mpconfigboard.h b/ports/espressif/boards/lolin_s3_mini_pro/mpconfigboard.h index 2fe5f4205da..bdbea2d18cb 100644 --- a/ports/espressif/boards/lolin_s3_mini_pro/mpconfigboard.h +++ b/ports/espressif/boards/lolin_s3_mini_pro/mpconfigboard.h @@ -22,3 +22,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/m5stack_atoms3/board.c b/ports/espressif/boards/m5stack_atoms3/board.c index df620976b61..3dbd8a1a2b8 100644 --- a/ports/espressif/boards/m5stack_atoms3/board.c +++ b/ports/espressif/boards/m5stack_atoms3/board.c @@ -39,9 +39,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO33, // DC - &pin_GPIO15, // CS - &pin_GPIO34, // RST + MP_OBJ_FROM_PTR(&pin_GPIO33), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO34), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cardputer/board.c b/ports/espressif/boards/m5stack_cardputer/board.c index 6fdc2f8ea5c..00630cd36d2 100644 --- a/ports/espressif/boards/m5stack_cardputer/board.c +++ b/ports/espressif/boards/m5stack_cardputer/board.c @@ -50,9 +50,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO34, // DC - &pin_GPIO37, // CS - &pin_GPIO33, // RST + MP_OBJ_FROM_PTR(&pin_GPIO34), // DC + MP_OBJ_FROM_PTR(&pin_GPIO37), // CS + MP_OBJ_FROM_PTR(&pin_GPIO33), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cardputer_ros/board.c b/ports/espressif/boards/m5stack_cardputer_ros/board.c index 6fdc2f8ea5c..00630cd36d2 100644 --- a/ports/espressif/boards/m5stack_cardputer_ros/board.c +++ b/ports/espressif/boards/m5stack_cardputer_ros/board.c @@ -50,9 +50,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO34, // DC - &pin_GPIO37, // CS - &pin_GPIO33, // RST + MP_OBJ_FROM_PTR(&pin_GPIO34), // DC + MP_OBJ_FROM_PTR(&pin_GPIO37), // CS + MP_OBJ_FROM_PTR(&pin_GPIO33), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk index ede48c2f015..98d2ad502dd 100644 --- a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk @@ -9,7 +9,7 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 8MB -CIRCUITPY_RCLCPY = 1 +CIRCUITPY_RCLCPY = 0 # Very few pins. CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/m5stack_core2/board.c b/ports/espressif/boards/m5stack_core2/board.c index 9d5c2bd650a..2e13c06c44f 100644 --- a/ports/espressif/boards/m5stack_core2/board.c +++ b/ports/espressif/boards/m5stack_core2/board.c @@ -318,9 +318,9 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO15, // DC - &pin_GPIO5, // CS - NULL, // RST + MP_OBJ_FROM_PTR(&pin_GPIO15), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + mp_const_none, // RST 32000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_core_basic/board.c b/ports/espressif/boards/m5stack_core_basic/board.c index 4ae128817a1..5a18d33e527 100644 --- a/ports/espressif/boards/m5stack_core_basic/board.c +++ b/ports/espressif/boards/m5stack_core_basic/board.c @@ -42,9 +42,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO14, // CS - &pin_GPIO33, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO14), // CS + MP_OBJ_FROM_PTR(&pin_GPIO33), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_core_fire/board.c b/ports/espressif/boards/m5stack_core_fire/board.c index 4ae128817a1..5a18d33e527 100644 --- a/ports/espressif/boards/m5stack_core_fire/board.c +++ b/ports/espressif/boards/m5stack_core_fire/board.c @@ -42,9 +42,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO14, // CS - &pin_GPIO33, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO14), // CS + MP_OBJ_FROM_PTR(&pin_GPIO33), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cores3/board.c b/ports/espressif/boards/m5stack_cores3/board.c index f49d6349997..e4e178ee3c9 100644 --- a/ports/espressif/boards/m5stack_cores3/board.c +++ b/ports/espressif/boards/m5stack_cores3/board.c @@ -38,16 +38,18 @@ uint8_t display_init_sequence[] = { }; static bool display_init(void) { - busio_spi_obj_t *spi = common_hal_board_create_spi(0); fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO37, NULL, false); + common_hal_busio_spi_never_reset(spi); bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO35, // DC - &pin_GPIO3, // CS - NULL, // RST + MP_OBJ_FROM_PTR(&pin_GPIO35), // DC + MP_OBJ_FROM_PTR(&pin_GPIO3), // CS + mp_const_none, // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cores3/mpconfigboard.h b/ports/espressif/boards/m5stack_cores3/mpconfigboard.h index 9af6ccf2fb4..0e5e136e3ea 100644 --- a/ports/espressif/boards/m5stack_cores3/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_cores3/mpconfigboard.h @@ -15,9 +15,5 @@ #define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO11, .sda = &pin_GPIO12}, \ {.scl = &pin_GPIO1, .sda = &pin_GPIO2}} -#define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) -#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO37) -#define DEFAULT_SPI_BUS_MISO (&pin_GPIO35) - #define DEFAULT_UART_BUS_RX (&pin_GPIO18) #define DEFAULT_UART_BUS_TX (&pin_GPIO17) diff --git a/ports/espressif/boards/m5stack_cores3/pins.c b/ports/espressif/boards/m5stack_cores3/pins.c index 8b40d9e8484..11357d79a72 100644 --- a/ports/espressif/boards/m5stack_cores3/pins.c +++ b/ports/espressif/boards/m5stack_cores3/pins.c @@ -29,10 +29,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS // M5 Bus (except I2S) - { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO37) }, - { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO35) }, - { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, - + // The SPI bus MISO is also used for the TFT D/C signal, so it is not available for general use + // therefore the SPI bus is not listed on the M5 Bus { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_D44), MP_ROM_PTR(&pin_GPIO44) }, @@ -99,6 +97,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_CAMERA_XCLK), MP_ROM_PTR(&pin_GPIO2) }, // Display + { MP_ROM_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_GPIO36) }, { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO35) }, @@ -109,7 +109,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_PORTA_I2C), MP_ROM_PTR(&board_porta_i2c_obj) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)} diff --git a/ports/espressif/boards/m5stack_cores3_se/board.c b/ports/espressif/boards/m5stack_cores3_se/board.c new file mode 100644 index 00000000000..cb0ed4aea06 --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/board.c @@ -0,0 +1,226 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" +#include "common-hal/microcontroller/Pin.h" + + +#define DELAY 0x80 +#define AXP2101_I2C_ADDRESS 0x34 +#define AW9523B_I2C_ADDRESS 0x58 + +uint8_t display_init_sequence[] = { + 0x01, DELAY, 0x80, // Software reset then delay 0x80 (128ms) + 0xC8, 0x03, 0xFF, 0x93, 0x42, // Turn on the external command + 0xC0, 0x02, 0x12, 0x12, // Power Control 1 + 0xC1, 0x01, 0x03, // Power Control 2 + 0xC5, 0x01, 0xF2, // VCOM Control 1 + 0xB0, 0x01, 0xE0, // RGB Interface SYNC Mode + 0xF6, 0x03, 0x01, 0x00, 0x00, // Interface control + 0XE0, 0x0F, 0x00, 0x0C, 0x11, 0x04, 0x11, 0x08, 0x37, 0x89, 0x4C, 0x06, 0x0C, 0x0A, 0x2E, 0x34, 0x0F, // Positive Gamma Correction + 0xE1, 0x0F, 0x00, 0x0B, 0x11, 0x05, 0x13, 0x09, 0x33, 0x67, 0x48, 0x07, 0x0E, 0x0B, 0x2E, 0x33, 0x0F, // Negative Gamma Correction + 0xB6, 0x04, 0x08, 0x82, 0x1D, 0x04, // Display Function Control + 0x3A, 0x01, 0x55, // COLMOD: Pixel Format Set 16 bit + 0x21, 0x00, // Display inversion ON + 0x36, 0x01, 0x08, // Memory Access Control: RGB order + 0x11, DELAY, 0x78, // Exit Sleep then delay 0x78 (120ms) + 0x29, DELAY, 0x78, // Display on then delay 0x78 (120ms) +}; + +static bool display_init(void) { + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO37, NULL, false); + common_hal_busio_spi_never_reset(spi); + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO35), // DC + MP_OBJ_FROM_PTR(&pin_GPIO3), // CS + mp_const_none, // RST + 40000000, // baudrate + 0, // polarity + 0 // phase + ); + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 320, // width (after rotation) + 240, // height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + NULL, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 61, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); + + return true; +} + +static bool axp2101_init(busio_i2c_obj_t *i2c) { + int rc; + uint8_t write_buf[2]; + + // 0x90 = 0b1011_0011 // LDOS ON/OFF control 0 + // Compared to CoreS3: ALDO2 (bit 2) and ALDO3 (bit 3) disabled (no ES7210/camera) + write_buf[0] = 0x90; + write_buf[1] = 0b10110011; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x92, 0x0D // ALDO1 set to 1.8v for AW88298 + write_buf[0] = 0x92; + write_buf[1] = 0x0D; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x95, 0x1C // ALDO4 set to 3.3v for TF card slot + write_buf[0] = 0x95; + write_buf[1] = 0x1C; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x99, 0x18 // DLDO1 set to 2.9v for TFT backlight + write_buf[0] = 0x99; + write_buf[1] = 0x18; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x27, 0x00 // PowerKey Hold=1sec / PowerOff=4sec + write_buf[0] = 0x27; + write_buf[1] = 0x00; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x69, 0x11 // CHGLED setting + write_buf[0] = 0x69; + write_buf[1] = 0x11; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x10, 0x30 // PMU common config + write_buf[0] = 0x10; + write_buf[1] = 0x30; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + return true; +} + +static bool aw9523b_init(busio_i2c_obj_t *i2c) { + int rc; + uint8_t write_buf[2]; + + // 0x02 = 0b0000_0111 // AW_RST, BUD_OUT_EN, TOUCH_RST + write_buf[0] = 0x02; + write_buf[1] = 0b00000111; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x03 = 0b1000_0011 // BOOST_EN, CAM_RST, LCD_RST + write_buf[0] = 0x03; + write_buf[1] = 0b10000011; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x04 = 0b0001_1000 // Set TF_SW, ES_INT as input + write_buf[0] = 0x04; + write_buf[1] = 0b00011000; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x05 = 0b0000_1100 // Set AW_INT, TOUCH_INT as input + write_buf[0] = 0x05; + write_buf[1] = 0b00001100; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x11 = 0b0001_0000 // Set P0 outputs in push pull mode + write_buf[0] = 0x11; + write_buf[1] = 0b00010000; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + return true; +} + +void board_init(void) { + // Deselect SD card on shared SPI bus before display init (see #10536) + config_pin_as_output_with_level(GPIO_NUM_4, true); + + busio_i2c_obj_t *internal_i2c = common_hal_board_create_i2c(0); + + if (!axp2101_init(internal_i2c)) { + mp_printf(&mp_plat_print, "could not initialize AXP2101"); + return; + } + + if (!aw9523b_init(internal_i2c)) { + mp_printf(&mp_plat_print, "could not initialize AW9523B"); + return; + } + + if (!display_init()) { + mp_printf(&mp_plat_print, "could not initialize the display"); + return; + } +} diff --git a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h new file mode 100644 index 00000000000..edfcbb3c91b --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "M5Stack CoreS3 SE" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO5) + +#define CIRCUITPY_BOARD_I2C (2) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO11, .sda = &pin_GPIO12}, \ + {.scl = &pin_GPIO1, .sda = &pin_GPIO2}} + +#define DEFAULT_UART_BUS_RX (&pin_GPIO18) +#define DEFAULT_UART_BUS_TX (&pin_GPIO17) diff --git a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk new file mode 100644 index 00000000000..2413c43cebe --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk @@ -0,0 +1,27 @@ +USB_VID = 0x303A +USB_PID = 0x8348 + +USB_PRODUCT = "M5Stack CoreS3 SE" +USB_MANUFACTURER = "M5Stack" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +CIRCUITPY_PARALLELDISPLAYBUS = 0 + +OPTIMIZATION_FLAGS = -Os + +# Include these Python libraries in firmware. +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ConnectionManager +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Shapes +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Text +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_FakeRequests +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Requests diff --git a/ports/espressif/boards/m5stack_cores3_se/pins.c b/ports/espressif/boards/m5stack_cores3_se/pins.c new file mode 100644 index 00000000000..f003b74e122 --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/pins.c @@ -0,0 +1,86 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +CIRCUITPY_BOARD_BUS_SINGLETON(porta_i2c, i2c, 1) + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // M5 Bus (except I2S) + // The SPI bus MISO is also used for the TFT D/C signal, so it is not available for general use + // therefore the SPI bus is not listed on the M5 Bus + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_D44), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_PORTC_RX), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_A18), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_PORTA_SDA), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_PORTB_IN), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_PORTB_OUT), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_D43), MP_ROM_PTR(&pin_GPIO43) }, + + { MP_ROM_QSTR(MP_QSTR_PORTC_TX), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_A17), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_PORTA_SCL), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_IR), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO7) }, + + // I2S + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DATA_OUT), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DATA_IN), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MASTER_CLOCK), MP_ROM_PTR(&pin_GPIO0) }, + + // Display + { MP_ROM_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO35) }, + + // Misc + { MP_ROM_QSTR(MP_QSTR_I2C_INTERRUPT), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SDCARD_CS), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_I2C), MP_ROM_PTR(&board_porta_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)} +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/m5stack_cores3_se/sdkconfig b/ports/espressif/boards/m5stack_cores3_se/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/m5stack_dial/board.c b/ports/espressif/boards/m5stack_dial/board.c index 4e7cf4b0240..6214255612b 100644 --- a/ports/espressif/boards/m5stack_dial/board.c +++ b/ports/espressif/boards/m5stack_dial/board.c @@ -49,9 +49,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO4, // DC - &pin_GPIO7, // CS - &pin_GPIO8, // RST + MP_OBJ_FROM_PTR(&pin_GPIO4), // DC + MP_OBJ_FROM_PTR(&pin_GPIO7), // CS + MP_OBJ_FROM_PTR(&pin_GPIO8), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_dinmeter/board.c b/ports/espressif/boards/m5stack_dinmeter/board.c index cd49318fd1c..37fafa994dc 100644 --- a/ports/espressif/boards/m5stack_dinmeter/board.c +++ b/ports/espressif/boards/m5stack_dinmeter/board.c @@ -51,9 +51,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO4, // DC - &pin_GPIO7, // CS - &pin_GPIO8, // RST + MP_OBJ_FROM_PTR(&pin_GPIO4), // DC + MP_OBJ_FROM_PTR(&pin_GPIO7), // CS + MP_OBJ_FROM_PTR(&pin_GPIO8), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_stick_c/board.c b/ports/espressif/boards/m5stack_stick_c/board.c index 641d2d1db7e..491ddead860 100644 --- a/ports/espressif/boards/m5stack_stick_c/board.c +++ b/ports/espressif/boards/m5stack_stick_c/board.c @@ -154,9 +154,9 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO23, // DC - &pin_GPIO5, // CS - &pin_GPIO18, // RST + MP_OBJ_FROM_PTR(&pin_GPIO23), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO18), // RST 10000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_stick_c_plus/board.c b/ports/espressif/boards/m5stack_stick_c_plus/board.c index eec6a208260..8902521db8e 100644 --- a/ports/espressif/boards/m5stack_stick_c_plus/board.c +++ b/ports/espressif/boards/m5stack_stick_c_plus/board.c @@ -154,9 +154,9 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO23, // DC - &pin_GPIO5, // CS - &pin_GPIO18, // RST + MP_OBJ_FROM_PTR(&pin_GPIO23), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO18), // RST 10000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_stick_c_plus2/board.c b/ports/espressif/boards/m5stack_stick_c_plus2/board.c index a50e38df09e..d84faa1888d 100644 --- a/ports/espressif/boards/m5stack_stick_c_plus2/board.c +++ b/ports/espressif/boards/m5stack_stick_c_plus2/board.c @@ -50,9 +50,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO14, // DC - &pin_GPIO5, // CS - &pin_GPIO12, // RST + MP_OBJ_FROM_PTR(&pin_GPIO14), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // RST 10000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_tab5/board.c b/ports/espressif/boards/m5stack_tab5/board.c new file mode 100644 index 00000000000..7c7c768d5c1 --- /dev/null +++ b/ports/espressif/boards/m5stack_tab5/board.c @@ -0,0 +1,379 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/mipidsi/Bus.h" +#include "shared-bindings/mipidsi/Display.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/framebufferio/__init__.h" +#include "shared-module/framebufferio/FramebufferDisplay.h" +#include "ports/espressif/common-hal/microcontroller/Pin.h" + +// Statically allocate the MIPI DSI bus (only one DSI bus on ESP32-P4) +static mipidsi_bus_obj_t board_mipidsi_bus; + +// ILI9881C initialization sequence +static const uint8_t ili9881c_init_sequence[] = { + 0xff, 0x03, 0x98, 0x81, 0x00, + 0x01, 0x80, 0x78, // software reset + // CMD_Page 1 + 0xff, 0x03, 0x98, 0x81, 0x01, + 0xb7, 0x01, 0x03, // set 2 lane + // CMD Page 0 + 0xff, 0x03, 0x98, 0x81, 0x00, + 0x11, 0x80, 0x0a, // out of sleep + 0x36, 0x01, 0x00, // madctl + 0x3a, 0x01, 0x55, // colmod + // CMD_Page 3 + 0xff, 0x03, 0x98, 0x81, 0x03, + 0x01, 0x01, 0x00, + 0x02, 0x01, 0x00, + 0x03, 0x01, 0x73, + 0x04, 0x01, 0x00, + 0x05, 0x01, 0x00, + 0x06, 0x01, 0x08, + 0x07, 0x01, 0x00, + 0x08, 0x01, 0x00, + 0x09, 0x01, 0x1b, + 0x0a, 0x01, 0x01, + 0x0b, 0x01, 0x01, + 0x0c, 0x01, 0x0d, + 0x0d, 0x01, 0x01, + 0x0e, 0x01, 0x01, + 0x0f, 0x01, 0x26, + 0x10, 0x01, 0x26, + 0x11, 0x01, 0x00, + 0x12, 0x01, 0x00, + 0x13, 0x01, 0x02, + 0x14, 0x01, 0x00, + 0x15, 0x01, 0x00, + 0x16, 0x01, 0x00, + 0x17, 0x01, 0x00, + 0x18, 0x01, 0x00, + 0x19, 0x01, 0x00, + 0x1a, 0x01, 0x00, + 0x1b, 0x01, 0x00, + 0x1c, 0x01, 0x00, + 0x1d, 0x01, 0x00, + 0x1e, 0x01, 0x40, + 0x1f, 0x01, 0x00, + 0x20, 0x01, 0x06, + 0x21, 0x01, 0x01, + 0x22, 0x01, 0x00, + 0x23, 0x01, 0x00, + 0x24, 0x01, 0x00, + 0x25, 0x01, 0x00, + 0x26, 0x01, 0x00, + 0x27, 0x01, 0x00, + 0x28, 0x01, 0x33, + 0x29, 0x01, 0x03, + 0x2a, 0x01, 0x00, + 0x2b, 0x01, 0x00, + 0x2c, 0x01, 0x00, + 0x2d, 0x01, 0x00, + 0x2e, 0x01, 0x00, + 0x2f, 0x01, 0x00, + 0x30, 0x01, 0x00, + 0x31, 0x01, 0x00, + 0x32, 0x01, 0x00, + 0x33, 0x01, 0x00, + 0x34, 0x01, 0x00, + 0x35, 0x01, 0x00, + 0x36, 0x01, 0x00, + 0x37, 0x01, 0x00, + 0x38, 0x01, 0x00, + 0x39, 0x01, 0x00, + 0x3a, 0x01, 0x00, + 0x3b, 0x01, 0x00, + 0x3c, 0x01, 0x00, + 0x3d, 0x01, 0x00, + 0x3e, 0x01, 0x00, + 0x3f, 0x01, 0x00, + 0x40, 0x01, 0x00, + 0x41, 0x01, 0x00, + 0x42, 0x01, 0x00, + 0x43, 0x01, 0x00, + 0x44, 0x01, 0x00, + 0x50, 0x01, 0x01, + 0x51, 0x01, 0x23, + 0x52, 0x01, 0x45, + 0x53, 0x01, 0x67, + 0x54, 0x01, 0x89, + 0x55, 0x01, 0xab, + 0x56, 0x01, 0x01, + 0x57, 0x01, 0x23, + 0x58, 0x01, 0x45, + 0x59, 0x01, 0x67, + 0x5a, 0x01, 0x89, + 0x5b, 0x01, 0xab, + 0x5c, 0x01, 0xcd, + 0x5d, 0x01, 0xef, + 0x5e, 0x01, 0x11, + 0x5f, 0x01, 0x02, + 0x60, 0x01, 0x00, + 0x61, 0x01, 0x07, + 0x62, 0x01, 0x06, + 0x63, 0x01, 0x0e, + 0x64, 0x01, 0x0f, + 0x65, 0x01, 0x0c, + 0x66, 0x01, 0x0d, + 0x67, 0x01, 0x02, + 0x68, 0x01, 0x02, + 0x69, 0x01, 0x02, + 0x6a, 0x01, 0x02, + 0x6b, 0x01, 0x02, + 0x6c, 0x01, 0x02, + 0x6d, 0x01, 0x02, + 0x6e, 0x01, 0x02, + 0x6f, 0x01, 0x02, + 0x70, 0x01, 0x02, + 0x71, 0x01, 0x02, + 0x72, 0x01, 0x02, + 0x73, 0x01, 0x05, + 0x74, 0x01, 0x01, + 0x75, 0x01, 0x02, + 0x76, 0x01, 0x00, + 0x77, 0x01, 0x07, + 0x78, 0x01, 0x06, + 0x79, 0x01, 0x0e, + 0x7a, 0x01, 0x0f, + 0x7b, 0x01, 0x0c, + 0x7c, 0x01, 0x0d, + 0x7d, 0x01, 0x02, + 0x7e, 0x01, 0x02, + 0x7f, 0x01, 0x02, + 0x80, 0x01, 0x02, + 0x81, 0x01, 0x02, + 0x82, 0x01, 0x02, + 0x83, 0x01, 0x02, + 0x84, 0x01, 0x02, + 0x85, 0x01, 0x02, + 0x86, 0x01, 0x02, + 0x87, 0x01, 0x02, + 0x88, 0x01, 0x02, + 0x89, 0x01, 0x05, + 0x8a, 0x01, 0x01, + // CMD_Page 4 + 0xff, 0x03, 0x98, 0x81, 0x04, + 0x38, 0x01, 0x01, + 0x39, 0x01, 0x00, + 0x6c, 0x01, 0x15, + 0x6e, 0x01, 0x1a, + 0x6f, 0x01, 0x25, + 0x3a, 0x01, 0xa4, + 0x8d, 0x01, 0x20, + 0x87, 0x01, 0xba, + 0x3b, 0x01, 0x98, + // CMD_Page 1 + 0xff, 0x03, 0x98, 0x81, 0x01, + 0x22, 0x01, 0x0a, + 0x31, 0x01, 0x00, + 0x50, 0x01, 0x6b, + 0x51, 0x01, 0x66, + 0x53, 0x01, 0x73, + 0x55, 0x01, 0x8b, + 0x60, 0x01, 0x1b, + 0x61, 0x01, 0x01, + 0x62, 0x01, 0x0c, + 0x63, 0x01, 0x00, + // Gamma P + 0xa0, 0x01, 0x00, + 0xa1, 0x01, 0x15, + 0xa2, 0x01, 0x1f, + 0xa3, 0x01, 0x13, + 0xa4, 0x01, 0x11, + 0xa5, 0x01, 0x21, + 0xa6, 0x01, 0x17, + 0xa7, 0x01, 0x1b, + 0xa8, 0x01, 0x6b, + 0xa9, 0x01, 0x1e, + 0xaa, 0x01, 0x2b, + 0xab, 0x01, 0x5d, + 0xac, 0x01, 0x19, + 0xad, 0x01, 0x14, + 0xae, 0x01, 0x4b, + 0xaf, 0x01, 0x1d, + 0xb0, 0x01, 0x27, + 0xb1, 0x01, 0x49, + 0xb2, 0x01, 0x5d, + 0xb3, 0x01, 0x39, + // Gamma N + 0xc0, 0x01, 0x00, + 0xc1, 0x01, 0x01, + 0xc2, 0x01, 0x0c, + 0xc3, 0x01, 0x11, + 0xc4, 0x01, 0x15, + 0xc5, 0x01, 0x28, + 0xc6, 0x01, 0x1b, + 0xc7, 0x01, 0x1c, + 0xc8, 0x01, 0x62, + 0xc9, 0x01, 0x1c, + 0xca, 0x01, 0x29, + 0xcb, 0x01, 0x60, + 0xcc, 0x01, 0x16, + 0xcd, 0x01, 0x17, + 0xce, 0x01, 0x4a, + 0xcf, 0x01, 0x23, + 0xd0, 0x01, 0x24, + 0xd1, 0x01, 0x4f, + 0xd2, 0x01, 0x5f, + 0xd3, 0x01, 0x39, + // CMD_Page 0 + 0xff, 0x03, 0x98, 0x81, 0x00, + 0x35, 0x00, + 0xfe, 0x00, + 0x29, 0x00, +}; + +// I2C addresses +#define GOODIX_TOUCH_ADDRESS 0x14 +#define ST7123_ADDRESS 0x55 +#define I2C_DEV_ADDR_PI4IOE1 0x43 + +// PI4IOE GPIO expander registers +#define PI4IO_REG_CHIP_RESET 0x01 +#define PI4IO_REG_IO_DIR 0x03 +#define PI4IO_REG_OUT_SET 0x05 +#define PI4IO_REG_OUT_H_IM 0x07 +#define PI4IO_REG_PULL_SEL 0x0D +#define PI4IO_REG_PULL_EN 0x0B + +void board_init(void) { + // Initialize I2C for GPIO expander and display detection + busio_i2c_obj_t *i2c = common_hal_board_create_i2c(0); + + // Initialize PI4IOE GPIO expander to control LCD reset + uint8_t write_buf[2]; + + common_hal_busio_i2c_try_lock(i2c); + + // Chip reset + write_buf[0] = PI4IO_REG_CHIP_RESET; + write_buf[1] = 0xFF; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Set IO direction (bit 7 as output for LCD reset) + write_buf[0] = PI4IO_REG_IO_DIR; + write_buf[1] = 0b01111111; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Set output high-impedance mode + write_buf[0] = PI4IO_REG_OUT_H_IM; + write_buf[1] = 0b00000000; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Set pull select + write_buf[0] = PI4IO_REG_PULL_SEL; + write_buf[1] = 0b01111111; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Enable pull resistors + write_buf[0] = PI4IO_REG_PULL_EN; + write_buf[1] = 0b01111111; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Set output state (including LCD reset) + write_buf[0] = PI4IO_REG_OUT_SET; + write_buf[1] = 0b01110110; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Small delay for reset to take effect + mp_hal_delay_ms(100); + + // Probe I2C bus to detect which display is present + bool has_goodix = common_hal_busio_i2c_probe(i2c, GOODIX_TOUCH_ADDRESS); + bool has_st7123 = common_hal_busio_i2c_probe(i2c, ST7123_ADDRESS); + + common_hal_busio_i2c_unlock(i2c); + + // Configure display parameters based on detected hardware + uint32_t bus_frequency; + uint32_t pixel_clock_frequency; + const uint8_t *init_sequence; + size_t init_sequence_len; + uint32_t hsync_pulse_width, hsync_back_porch, hsync_front_porch; + uint32_t vsync_pulse_width, vsync_back_porch, vsync_front_porch; + + if (has_goodix) { + // ILI9881C display with Goodix touch + bus_frequency = 730000000; + pixel_clock_frequency = 60000000; + init_sequence = ili9881c_init_sequence; + init_sequence_len = sizeof(ili9881c_init_sequence); + hsync_pulse_width = 40; + hsync_back_porch = 140; + hsync_front_porch = 40; + vsync_pulse_width = 4; + vsync_back_porch = 20; + vsync_front_porch = 20; + } else if (has_st7123) { + // ST7123 display + bus_frequency = 965000000; + pixel_clock_frequency = 70000000; + init_sequence = NULL; // ST7123 doesn't use init sequence + init_sequence_len = 0; + hsync_pulse_width = 2; + hsync_back_porch = 40; + hsync_front_porch = 40; + vsync_pulse_width = 2; + vsync_back_porch = 8; + vsync_front_porch = 220; + + // Not tested now + return; + } else { + return; + } + + // Initialize the statically allocated MIPI DSI bus + board_mipidsi_bus.base.type = &mipidsi_bus_type; + common_hal_mipidsi_bus_construct(&board_mipidsi_bus, bus_frequency, 2); // 2 lanes + + // Allocate display bus for the display object + primary_display_bus_t *display_bus_obj = allocate_display_bus_or_raise(); + mipidsi_display_obj_t *display = &display_bus_obj->mipidsi; + display->base.type = &mipidsi_display_type; + + common_hal_mipidsi_display_construct( + display, + &board_mipidsi_bus, // Use statically allocated bus + init_sequence, + init_sequence_len, + 0, // virtual_channel + 720, // width + 1280, // height + 0, // rotation + 16, // color_depth + &pin_GPIO22, // backlight_pin (LCD_BL) + 0.1f, // brightness + 60, // native_frames_per_second + true, // backlight_on_high + hsync_pulse_width, + hsync_back_porch, + hsync_front_porch, + vsync_pulse_width, + vsync_back_porch, + vsync_front_porch, + pixel_clock_frequency + ); + + // Create framebuffer display + framebufferio_framebufferdisplay_obj_t *fb_display = &allocate_display()->framebuffer_display; + fb_display->base.type = &framebufferio_framebufferdisplay_type; + + common_hal_framebufferio_framebufferdisplay_construct( + fb_display, + MP_OBJ_FROM_PTR(display), + 0, // rotation + true // auto_refresh + ); +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/m5stack_tab5/mpconfigboard.h b/ports/espressif/boards/m5stack_tab5/mpconfigboard.h new file mode 100644 index 00000000000..6c748e93ecd --- /dev/null +++ b/ports/espressif/boards/m5stack_tab5/mpconfigboard.h @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "M5Stack Tab5" +#define MICROPY_HW_MCU_NAME "ESP32P4" + +// I2C bus for touch, IMU, RTC, power monitor, and GPIO expanders +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO32, .sda = &pin_GPIO31}} + +// UART +#define DEFAULT_UART_BUS_RX (&pin_GPIO38) +#define DEFAULT_UART_BUS_TX (&pin_GPIO37) + +// SPI on M5-Bus +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO5) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO19) + +// Use the second USB device (numbered 0 and 1) +#define CIRCUITPY_USB_DEVICE_INSTANCE 0 +#define CIRCUITPY_ESP32P4_SWAP_LSFS (1) diff --git a/ports/espressif/boards/m5stack_tab5/mpconfigboard.mk b/ports/espressif/boards/m5stack_tab5/mpconfigboard.mk new file mode 100644 index 00000000000..4871a259e7a --- /dev/null +++ b/ports/espressif/boards/m5stack_tab5/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x832B +USB_PRODUCT = "M5Stack Tab5" +USB_MANUFACTURER = "M5Stack" + +IDF_TARGET = esp32p4 + +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 32MB +CIRCUITPY_ESP_PSRAM_MODE = hpi +CIRCUITPY_ESP_PSRAM_FREQ = 200m diff --git a/ports/espressif/boards/m5stack_tab5/pins.c b/ports/espressif/boards/m5stack_tab5/pins.c new file mode 100644 index 00000000000..c64d8803c02 --- /dev/null +++ b/ports/espressif/boards/m5stack_tab5/pins.c @@ -0,0 +1,132 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // M5-Bus and general GPIO + { MP_ROM_QSTR(MP_QSTR_G2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_G3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_G4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_G6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_G7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_G16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_G17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_G35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_G45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_G47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_G48), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_G51), MP_ROM_PTR(&pin_GPIO51) }, + { MP_ROM_QSTR(MP_QSTR_G52), MP_ROM_PTR(&pin_GPIO52) }, + + // SPI (on M5-Bus) + { MP_ROM_QSTR(MP_QSTR_G5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_G18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_G19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO19) }, + + // UART (on M5-Bus) + { MP_ROM_QSTR(MP_QSTR_G37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_TXD0), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_G38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_RXD0), MP_ROM_PTR(&pin_GPIO38) }, + + // I2C (Touch, IMU, RTC, Power Monitor, GPIO Expanders) + { MP_ROM_QSTR(MP_QSTR_G31), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_G32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO32) }, + + // Touch Panel + { MP_ROM_QSTR(MP_QSTR_G23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_TP_INT), MP_ROM_PTR(&pin_GPIO23) }, + + // LCD + { MP_ROM_QSTR(MP_QSTR_G22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_LCD_BL), MP_ROM_PTR(&pin_GPIO22) }, + + // Audio ES8388/ES7210 + { MP_ROM_QSTR(MP_QSTR_G26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DSDIN), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_G27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCLK), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_G28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_I2S_ASDOUT), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_G29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCK), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_G30), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_ROM_PTR(&pin_GPIO30) }, + + // Camera + { MP_ROM_QSTR(MP_QSTR_G36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_CAM_MCLK), MP_ROM_PTR(&pin_GPIO36) }, + + // microSD Card (SDIO mode) + { MP_ROM_QSTR(MP_QSTR_G39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT0), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_G40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT1), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_G41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT2), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_G42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT3), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_G43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_G44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO44) }, + + // RS485 + { MP_ROM_QSTR(MP_QSTR_G20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_RS485_TX), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_G21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_RS485_RX), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_G34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_RS485_DIR), MP_ROM_PTR(&pin_GPIO34) }, + + // HY2.0-4P PORT.A + { MP_ROM_QSTR(MP_QSTR_G53), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_Y), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_G54), MP_ROM_PTR(&pin_GPIO54) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_W), MP_ROM_PTR(&pin_GPIO54) }, + + // ESP32-C6 SDIO interface + { MP_ROM_QSTR(MP_QSTR_G8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_D3), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_G9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_D2), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_G10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_D1), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_G11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_D0), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_G12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_CK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_G13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_CMD), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_G14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_C6_IO2), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_G15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_C6_RESET), MP_ROM_PTR(&pin_GPIO15) }, + + // I2C and SPI objects + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)} +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/m5stack_tab5/sdkconfig b/ports/espressif/boards/m5stack_tab5/sdkconfig new file mode 100644 index 00000000000..3bce8cc0c13 --- /dev/null +++ b/ports/espressif/boards/m5stack_tab5/sdkconfig @@ -0,0 +1,2 @@ +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESP32P4_REV_MIN_100=y diff --git a/ports/espressif/boards/makerfabs_tft7/board.c b/ports/espressif/boards/makerfabs_tft7/board.c index dd0ffa26528..a994cfef381 100644 --- a/ports/espressif/boards/makerfabs_tft7/board.c +++ b/ports/espressif/boards/makerfabs_tft7/board.c @@ -6,13 +6,14 @@ #include "supervisor/board.h" #include "mpconfigboard.h" + #include "shared-bindings/board/__init__.h" #include "shared-bindings/dotclockframebuffer/DotClockFramebuffer.h" #include "shared-bindings/dotclockframebuffer/__init__.h" #include "shared-bindings/framebufferio/FramebufferDisplay.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" -#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" static const mcu_pin_obj_t *blue_pins[] = { &pin_GPIO8, @@ -40,14 +41,14 @@ static const mcu_pin_obj_t *red_pins[] = { static void display_init(void) { mp_int_t height = 0, width = 0, frequency = 0; - os_getenv_err_t result; + settings_err_t result; - result = common_hal_os_getenv_int("CIRCUITPY_DISPLAY_WIDTH", &width); - if (result == GETENV_OK && width == 800) { + result = settings_get_int("CIRCUITPY_DISPLAY_WIDTH", &width); + if (result == SETTINGS_OK && width == 800) { width = 800; height = 480; frequency = 6500000; - } else if (result == GETENV_OK && width == 1024) { + } else if (result == SETTINGS_OK && width == 1024) { width = 1024; height = 600; frequency = 10000000; diff --git a/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.h b/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.h index ed8dec14f0a..0d17aef1109 100644 --- a/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.h +++ b/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.h @@ -17,3 +17,6 @@ // Default bus pins #define DEFAULT_UART_BUS_TX (&pin_GPIO17) #define DEFAULT_UART_BUS_RX (&pin_GPIO16) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h b/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h index b7b327b23d3..db2d353f998 100644 --- a/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h +++ b/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DEFAULT_UART_BUS_RX (&pin_GPIO44) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/morpheans_morphesp-240/board.c b/ports/espressif/boards/morpheans_morphesp-240/board.c index 5b1c3f82bbb..44266cce6ed 100644 --- a/ports/espressif/boards/morpheans_morphesp-240/board.c +++ b/ports/espressif/boards/morpheans_morphesp-240/board.c @@ -138,9 +138,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO14, // DC - &pin_GPIO10, // CS - &pin_GPIO9, // RST + MP_OBJ_FROM_PTR(&pin_GPIO14), // DC + MP_OBJ_FROM_PTR(&pin_GPIO10), // CS + MP_OBJ_FROM_PTR(&pin_GPIO9), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/board.c b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/board.c new file mode 100755 index 00000000000..e2517f8640a --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/board.c @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "driver/gpio.h" + +void board_init(void) { + reset_board(); +} + +void reset_board(void) { + // Turn on I2C power by default. + gpio_set_direction(14, GPIO_MODE_DEF_OUTPUT); + gpio_set_level(14, true); + + // Turn on SD power by default + gpio_set_direction(3, GPIO_MODE_DEF_OUTPUT); + gpio_set_level(3, true); +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.h b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.h new file mode 100755 index 00000000000..c3181ea9431 --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.h @@ -0,0 +1,36 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "NHB Systems JL401-S3 4MB Flash 2MB PSRAM" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO1) +#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO2) + +// #define MICROPY_HW_LED_STATUS (&pin_GPIO13) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO48) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO47) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO12) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO11) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO13) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO18) +#define DEFAULT_UART_BUS_TX (&pin_GPIO17) + +#define DOUBLE_TAP_PIN (&pin_GPIO38) + +#define DEFAULT_SD_SCK (&pin_GPIO12) +#define DEFAULT_SD_MOSI (&pin_GPIO11) +#define DEFAULT_SD_MISO (&pin_GPIO13) +#define DEFAULT_SD_CS (&pin_GPIO10) +#define DEFAULT_SD_CARD_DETECT (&pin_GPIO9) +#define DEFAULT_SD_CARD_INSERTED true diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.mk b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.mk new file mode 100755 index 00000000000..fdc981fdccc --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x834A +USB_PRODUCT = "NHB Systems JL401-S3 4MB Flash 2MB PSRAM" +USB_MANUFACTURER = "NHB Systems" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_SIZE = 4MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 2MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/pins.c b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/pins.c new file mode 100644 index 00000000000..111659bee61 --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/pins.c @@ -0,0 +1,89 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL_POWER), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_SD_PWR), MP_ROM_PTR(&pin_GPIO3)}, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + + + // { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) }, + // { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_I2C_POWER), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + + // D33 to D36 used for AD7124 SPI + { MP_ROM_QSTR(MP_QSTR_D33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_D34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_D35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_D36), MP_ROM_PTR(&pin_GPIO36) }, + + { MP_ROM_QSTR(MP_QSTR_D37), MP_ROM_PTR(&pin_GPIO37) }, + // { MP_ROM_QSTR(MP_QSTR_D38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_D39), MP_ROM_PTR(&pin_GPIO39) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_D43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_D44), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) } +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/sdkconfig b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/sdkconfig new file mode 100755 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/oxocard_artwork/board.c b/ports/espressif/boards/oxocard_artwork/board.c index a27cdb7003b..5fe8e814558 100644 --- a/ports/espressif/boards/oxocard_artwork/board.c +++ b/ports/espressif/boards/oxocard_artwork/board.c @@ -43,9 +43,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO15, // CS - &pin_GPIO4, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO4), // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/oxocard_connect/board.c b/ports/espressif/boards/oxocard_connect/board.c index 89be45c8226..2c013811474 100644 --- a/ports/espressif/boards/oxocard_connect/board.c +++ b/ports/espressif/boards/oxocard_connect/board.c @@ -44,9 +44,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO15, // CS - &pin_GPIO4, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO4), // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/oxocard_galaxy/board.c b/ports/espressif/boards/oxocard_galaxy/board.c index a27cdb7003b..5fe8e814558 100644 --- a/ports/espressif/boards/oxocard_galaxy/board.c +++ b/ports/espressif/boards/oxocard_galaxy/board.c @@ -43,9 +43,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO15, // CS - &pin_GPIO4, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO4), // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/oxocard_science/board.c b/ports/espressif/boards/oxocard_science/board.c index a27cdb7003b..5fe8e814558 100644 --- a/ports/espressif/boards/oxocard_science/board.c +++ b/ports/espressif/boards/oxocard_science/board.c @@ -43,9 +43,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO15, // CS - &pin_GPIO4, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO4), // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/board.c b/ports/espressif/boards/pcbcupid_glyph_c3/board.c new file mode 100644 index 00000000000..8bc15c17551 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h new file mode 100644 index 00000000000..064559a4dc8 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 PCBCupid +// +// SPDX-License-Identifier: MIT +#pragma once + +#define MICROPY_HW_BOARD_NAME "PCBCupid GLYPH C3" +#define MICROPY_HW_MCU_NAME "ESP32-C3" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO1) + +#define DEFAULT_UART_BUS_TX (&pin_GPIO21) +#define DEFAULT_UART_BUS_RX (&pin_GPIO20) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO10) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO6) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO7) diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.mk b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.mk new file mode 100644 index 00000000000..dea0619ee7e --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.mk @@ -0,0 +1,10 @@ +CIRCUITPY_CREATOR_ID = 0x20241402 +CIRCUITPY_CREATION_ID = 0x00C30001 + +IDF_TARGET = esp32c3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 4MB + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/pins.c b/ports/espressif/boards/pcbcupid_glyph_c3/pins.c new file mode 100644 index 00000000000..2d15da17bd9 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/pins.c @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 PCBCupid +// +// SPDX-License-Identifier: MIT +#include "shared-bindings/board/__init__.h" +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/sdkconfig b/ports/espressif/boards/pcbcupid_glyph_c3/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/board.c b/ports/espressif/boards/pcbcupid_glyph_c6/board.c new file mode 100644 index 00000000000..3c254a05417 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.h b/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.h new file mode 100644 index 00000000000..6c83a0f4ecb --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.h @@ -0,0 +1,18 @@ +#pragma once + +#define MICROPY_HW_BOARD_NAME "Pcbcupid GLYPH C6" +#define MICROPY_HW_MCU_NAME "ESP32-C6" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO14) + +#define DEFAULT_UART_BUS_TX (&pin_GPIO16) +#define DEFAULT_UART_BUS_RX (&pin_GPIO17) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO21) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO22) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO23) + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9) diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.mk b/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.mk new file mode 100644 index 00000000000..8c2e6d74453 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.mk @@ -0,0 +1,10 @@ +CIRCUITPY_CREATOR_ID = 0x20241402 +CIRCUITPY_CREATION_ID = 0x00C60001 + +IDF_TARGET = esp32c6 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 4MB + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/pins.c b/ports/espressif/boards/pcbcupid_glyph_c6/pins.c new file mode 100644 index 00000000000..c2a4db30854 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/pins.c @@ -0,0 +1,56 @@ +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/sdkconfig b/ports/espressif/boards/pcbcupid_glyph_c6/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/board.c b/ports/espressif/boards/pcbcupid_glyph_h2/board.c new file mode 100644 index 00000000000..4e6bc405957 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_h2/board.c @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.h b/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.h new file mode 100644 index 00000000000..0060381696e --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Pcbcupid GLYPH H2" +#define MICROPY_HW_MCU_NAME "ESP32H2" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO0) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO11) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO22) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO25) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO23) +#define DEFAULT_UART_BUS_TX (&pin_GPIO24) diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.mk b/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.mk new file mode 100644 index 00000000000..4acde24d6f6 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.mk @@ -0,0 +1,11 @@ +CIRCUITPY_CREATOR_ID = 0x20241402 +CIRCUITPY_CREATION_ID = 0x00110001 + +IDF_TARGET = esp32h2 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 48m +CIRCUITPY_ESP_FLASH_SIZE = 4MB +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/pins.c b/ports/espressif/boards/pcbcupid_glyph_h2/pins.c new file mode 100644 index 00000000000..550ba4e3101 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_h2/pins.c @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO0) }, + + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO3) }, + + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO23) }, + + + { MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO5) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/tests/feature_check/async_check.py.exp b/ports/espressif/boards/pcbcupid_glyph_h2/sdkconfig similarity index 100% rename from tests/feature_check/async_check.py.exp rename to ports/espressif/boards/pcbcupid_glyph_h2/sdkconfig diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/board.c b/ports/espressif/boards/pcbcupid_glyph_s3/board.c new file mode 100644 index 00000000000..27b058c946f --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_s3/board.c @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +void board_init(void) { +} diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.h b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.h new file mode 100644 index 00000000000..bc17cb65dfc --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "PCBCupid GLYPH S3" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO21) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO35) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO36) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk new file mode 100644 index 00000000000..9228197411f --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk @@ -0,0 +1,10 @@ +USB_VID = 0x303A +USB_PID = 0x8373 +USB_PRODUCT = "GLYPH S3" +USB_MANUFACTURER = "PCBCupid" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/pins.c b/ports/espressif/boards/pcbcupid_glyph_s3/pins.c new file mode 100644 index 00000000000..5b962f2f74d --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_s3/pins.c @@ -0,0 +1,59 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_A10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/tests/feature_check/bytearray.py.exp b/ports/espressif/boards/pcbcupid_glyph_s3/sdkconfig similarity index 100% rename from tests/feature_check/bytearray.py.exp rename to ports/espressif/boards/pcbcupid_glyph_s3/sdkconfig diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/mpconfigboard.h b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/mpconfigboard.h index c05b6a93a10..d7f24b255d6 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/mpconfigboard.h +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/mpconfigboard.h @@ -12,9 +12,9 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) -#define DEFAULT_SPI_BUS_SCK (&pin_GPIO7) -#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO9) -#define DEFAULT_SPI_BUS_MISO (&pin_GPIO8) +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO7) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO9) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO8) -#define DEFAULT_I2C_BUS_SCL (&pin_GPIO6) -#define DEFAULT_I2C_BUS_SDA (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO6) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO5) diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c index aa3a6f7b7f5..fbb6014685c 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c @@ -31,49 +31,92 @@ static const mp_rom_obj_tuple_t camera_data_tuple = { static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS - { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO1) }, - { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO2) }, - { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO5) }, - { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO9) }, - { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO5) }, - { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO6) }, - { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, - { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO9) }, - { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO8) }, - { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SD), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_CAM_VSYNC), MP_ROM_PTR(&pin_GPIO38) }, + + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCK), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_CAM_SCL), MP_ROM_PTR(&pin_GPIO39) }, + + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WS), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_CAM_SDA), MP_ROM_PTR(&pin_GPIO40) }, + + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_MIC_DATA), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_RX_1), MP_ROM_PTR(&pin_GPIO41) }, + + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_MIC_CLK), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_TX_1), MP_ROM_PTR(&pin_GPIO42) }, + + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_CAM_XCLK), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_SCK_1), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_CAM_PCLK), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_MISO_1), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D5), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_MOSI_1), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D6), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_SDCS), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_CAM_DATA), MP_ROM_PTR(&camera_data_tuple) }, { MP_ROM_QSTR(MP_QSTR_CAM_D0), MP_ROM_PTR(&pin_GPIO15) }, { MP_ROM_QSTR(MP_QSTR_CAM_D1), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_CAM_D2), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_CAM_D3), MP_ROM_PTR(&pin_GPIO16) }, { MP_ROM_QSTR(MP_QSTR_CAM_D4), MP_ROM_PTR(&pin_GPIO14) }, - { MP_ROM_QSTR(MP_QSTR_CAM_D5), MP_ROM_PTR(&pin_GPIO12) }, - { MP_ROM_QSTR(MP_QSTR_CAM_D6), MP_ROM_PTR(&pin_GPIO11) }, { MP_ROM_QSTR(MP_QSTR_CAM_D7), MP_ROM_PTR(&pin_GPIO48) }, - { MP_ROM_QSTR(MP_QSTR_CAM_XCLK), MP_ROM_PTR(&pin_GPIO10) }, { MP_ROM_QSTR(MP_QSTR_CAM_HREF), MP_ROM_PTR(&pin_GPIO47) }, - { MP_ROM_QSTR(MP_QSTR_CAM_PCLK), MP_ROM_PTR(&pin_GPIO13) }, - { MP_ROM_QSTR(MP_QSTR_CAM_VSYNC), MP_ROM_PTR(&pin_GPIO38) }, - { MP_ROM_QSTR(MP_QSTR_CAM_SCL), MP_ROM_PTR(&pin_GPIO39) }, - { MP_ROM_QSTR(MP_QSTR_CAM_SDA), MP_ROM_PTR(&pin_GPIO40) }, - { MP_ROM_QSTR(MP_QSTR_MIC_DATA), MP_ROM_PTR(&pin_GPIO41) }, - { MP_ROM_QSTR(MP_QSTR_MIC_CLK), MP_ROM_PTR(&pin_GPIO42) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/sdkconfig b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/sdkconfig index 919f4d9f345..2d98e822542 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/sdkconfig +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/sdkconfig @@ -5,15 +5,13 @@ # Component config # # -# LWIP # -# end of LWIP # Camera configuration # -CONFIG_OV2640_SUPPORT=y # CONFIG_OV7725_SUPPORT is not set -# CONFIG_OV3660_SUPPORT is not set +CONFIG_OV2640_SUPPORT=y # end of Camera configuration + # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/board.c b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/board.c similarity index 100% rename from ports/espressif/boards/sensebox_eye_esp32s3/board.c rename to ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/board.c diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.h b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.h new file mode 100644 index 00000000000..79deafd6125 --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.h @@ -0,0 +1,24 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Bernhard Bablok +// +// SPDX-License-Identifier: MIT + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Seeed Xiao ESP32-S3 Trmnl DIY Kit" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO21) + +// the unpopulated NFC-header also provides UART +#define CIRCUITPY_BOARD_UART (1) +#define CIRCUITPY_BOARD_UART_PIN {{.rx = &pin_GPIO41, .tx = &pin_GPIO42}} + +// SPI0 is used by the display connector +// SPI1 is used by a two secondary flash chips (one unpopulated) +#define CIRCUITPY_BOARD_SPI (2) +#define CIRCUITPY_BOARD_SPI_PIN \ + {{.clock = &pin_GPIO7, .mosi = &pin_GPIO9}, \ + {.clock = &pin_GPIO13, .mosi = &pin_GPIO11, .miso = &pin_GPIO12} \ + } diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.mk b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.mk new file mode 100644 index 00000000000..9a6b15aa76c --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.mk @@ -0,0 +1,32 @@ +USB_VID = 0x2886 +USB_PID = 0x0300 + +USB_PRODUCT = "Seeed Xiao ESP32-S3 Trmnl DIY Kit" +USB_MANUFACTURER = "Seeed Studio" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +CIRCUITPY_FREQUENCYIO = 0 +CIRCUITPY_RAINBOWIO = 0 +CIRCUITPY__EVE = 0 +CIRCUITPY_PS2IO = 0 +CIRCUITPY_CANIO = 0 +CIRCUITPY_MAX3421E = 0 +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_PARALLELDISPLAYBUS = 0 +CIRCUITPY_COUNTIO = 0 +CIRCUITPY_NEOPIXEL_WRITE = 0 +CIRCUITPY_ROTARYIO = 0 + +CIRCUITPY_AUDIOCORE = 0 +CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 +CIRCUITPY_AUDIOI2SIN = 0 diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/pins.c b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/pins.c new file mode 100644 index 00000000000..422f16b787b --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/pins.c @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BAT_ADC), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BTN1), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_BTN2), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_EDP_BUSY), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_BTN3), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_ADC_EN), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_SPI0_CLK), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SPI0_MOSI), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_EDP_DC), MP_ROM_PTR(&pin_GPIO10) }, + + // connected to two additional flash chips (one unpopulated) + { MP_ROM_QSTR(MP_QSTR_SPI1_MOSI), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SPI1_MISO), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_SPI1_CLK), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_EDP_RES), MP_ROM_PTR(&pin_GPIO38) }, + + // connected to two additional flash chips (CS0 unpopulated) + { MP_ROM_QSTR(MP_QSTR_SPI1_CS0), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SPI1_CS1), MP_ROM_PTR(&pin_GPIO40) }, + + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO41) }, + + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO42) }, + + { MP_ROM_QSTR(MP_QSTR_PWR_EN), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SPI0_CS), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/sdkconfig b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/sdkconfig new file mode 100644 index 00000000000..ce6696bf50f --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/sdkconfig @@ -0,0 +1,11 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.h b/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.h index 6f803cd9c96..6918056cf86 100644 --- a/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.h +++ b/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.h @@ -17,3 +17,6 @@ // For entering safe mode, use BOOT button #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/sensebox_mcu_eye_esp32s3/board.c b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/board.c new file mode 100644 index 00000000000..fea7fe2c300 --- /dev/null +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "mpconfigboard.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.h b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.h similarity index 88% rename from ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.h rename to ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.h index 3908c492f1b..300154fe344 100644 --- a/ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.h +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.h @@ -6,7 +6,7 @@ // Micropython setup -#define MICROPY_HW_BOARD_NAME "senseBox-eye ESP32S3" +#define MICROPY_HW_BOARD_NAME "senseBox MCU Eye ESP32S3" #define MICROPY_HW_MCU_NAME "ESP32S3" #define MICROPY_HW_NEOPIXEL (&pin_GPIO45) diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.mk b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.mk similarity index 93% rename from ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.mk rename to ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.mk index 55e822c5dea..be3c65746c8 100644 --- a/ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.mk +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.mk @@ -7,7 +7,7 @@ USB_MANUFACTURER = "senseBox" IDF_TARGET = esp32s3 CIRCUITPY_ESP_FLASH_MODE = qio -CIRCUITPY_ESP_FLASH_SIZE = 8MB +CIRCUITPY_ESP_FLASH_SIZE = 16MB CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_PSRAM_MODE = opi diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/pins.c b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/pins.c similarity index 98% rename from ports/espressif/boards/sensebox_eye_esp32s3/pins.c rename to ports/espressif/boards/sensebox_mcu_eye_esp32s3/pins.c index c218fafa918..71b984f7ff5 100644 --- a/ports/espressif/boards/sensebox_eye_esp32s3/pins.c +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/pins.c @@ -33,7 +33,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) }, { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, - {MP_ROM_QSTR(MP_QSTR_BUTTON_SW), MP_ROM_PTR(&pin_GPIO47) }, + {MP_ROM_QSTR(MP_QSTR_BUTTON_SW), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO1) }, diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/sdkconfig b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/sdkconfig similarity index 100% rename from ports/espressif/boards/sensebox_eye_esp32s3/sdkconfig rename to ports/espressif/boards/sensebox_mcu_eye_esp32s3/sdkconfig diff --git a/ports/espressif/boards/solderparty_esp32p4_stamp_xl/sdkconfig b/ports/espressif/boards/solderparty_esp32p4_stamp_xl/sdkconfig index e69de29bb2d..3bce8cc0c13 100644 --- a/ports/espressif/boards/solderparty_esp32p4_stamp_xl/sdkconfig +++ b/ports/espressif/boards/solderparty_esp32p4_stamp_xl/sdkconfig @@ -0,0 +1,2 @@ +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESP32P4_REV_MIN_100=y diff --git a/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/board.c b/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/board.c index 89bcbf6b8dd..f4288ae45ac 100644 --- a/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/board.c +++ b/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/board.c @@ -42,9 +42,9 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO0, // DC - &pin_GPIO2, // CS - &pin_GPIO5, // RST + MP_OBJ_FROM_PTR(&pin_GPIO0), // DC + MP_OBJ_FROM_PTR(&pin_GPIO2), // CS + MP_OBJ_FROM_PTR(&pin_GPIO5), // RST 10000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/spotpear_esp32c3_lcd_1_69/board.c b/ports/espressif/boards/spotpear_esp32c3_lcd_1_69/board.c index 6299402e8e0..30879e71404 100644 --- a/ports/espressif/boards/spotpear_esp32c3_lcd_1_69/board.c +++ b/ports/espressif/boards/spotpear_esp32c3_lcd_1_69/board.c @@ -39,9 +39,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO2, // DC - &pin_GPIO3, // CS - &pin_GPIO10, // RST + MP_OBJ_FROM_PTR(&pin_GPIO2), // DC + MP_OBJ_FROM_PTR(&pin_GPIO3), // CS + MP_OBJ_FROM_PTR(&pin_GPIO10), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/sqfmi_watchy/board.c b/ports/espressif/boards/sqfmi_watchy/board.c index 297190b53e2..9cea4e98095 100644 --- a/ports/espressif/boards/sqfmi_watchy/board.c +++ b/ports/espressif/boards/sqfmi_watchy/board.c @@ -150,9 +150,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO10, // EPD_DC Command or data - &pin_GPIO5, // EPD_CS Chip select - &pin_GPIO9, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO10), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO9), // EPD_RST Reset 2000000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/espressif/boards/sunton_esp32_2424S012/board.c b/ports/espressif/boards/sunton_esp32_2424S012/board.c index c313ded8637..4e56bee7d8b 100644 --- a/ports/espressif/boards/sunton_esp32_2424S012/board.c +++ b/ports/espressif/boards/sunton_esp32_2424S012/board.c @@ -105,9 +105,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO2, // DC - &pin_GPIO10, // CS - NULL, // RST + MP_OBJ_FROM_PTR(&pin_GPIO2), // DC + MP_OBJ_FROM_PTR(&pin_GPIO10), // CS + mp_const_none, // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/sunton_esp32_2432S024C/board.c b/ports/espressif/boards/sunton_esp32_2432S024C/board.c index 8b4201d88e8..d50f19f9972 100644 --- a/ports/espressif/boards/sunton_esp32_2432S024C/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S024C/board.c @@ -6,13 +6,14 @@ #include "supervisor/board.h" #include "mpconfigboard.h" + +#include "common-hal/microcontroller/Pin.h" +#include "driver/gpio.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" #include "shared-module/displayio/mipi_constants.h" -#include "driver/gpio.h" -#include "common-hal/microcontroller/Pin.h" -#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" uint8_t display_init_sequence[] = { 0x01, 0x80, 0x80, // # Software reset then delay 0x80 (128ms) @@ -50,17 +51,17 @@ static void display_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO2, // TFT_DC Command or data - &pin_GPIO15, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS Chip select + mp_const_none, // TFT_RST Reset 6000000, // Baudrate 0, // Polarity 0); // Phase busdisplay_busdisplay_obj_t *display = &allocate_display()->display; display->base.type = &busdisplay_busdisplay_type; - os_getenv_err_t result = common_hal_os_getenv_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); - if (result != GETENV_OK) { + settings_err_t result = settings_get_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); + if (result != SETTINGS_OK) { rotation = 0; } diff --git a/ports/espressif/boards/sunton_esp32_2432S024C/pins.c b/ports/espressif/boards/sunton_esp32_2432S024C/pins.c index a69f3150e92..6544017cd99 100644 --- a/ports/espressif/boards/sunton_esp32_2432S024C/pins.c +++ b/ports/espressif/boards/sunton_esp32_2432S024C/pins.c @@ -46,7 +46,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO5) }, - // ILI9341 dsplay (spi) + // ILI9341 display (spi) { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_GPIO13) }, { MP_ROM_QSTR(MP_QSTR_LCD_MISO), MP_ROM_PTR(&pin_GPIO12) }, { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_GPIO14) }, diff --git a/ports/espressif/boards/sunton_esp32_2432S028/board.c b/ports/espressif/boards/sunton_esp32_2432S028/board.c index b249c45dd8f..6cd4a080c99 100644 --- a/ports/espressif/boards/sunton_esp32_2432S028/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S028/board.c @@ -6,13 +6,14 @@ #include "supervisor/board.h" #include "mpconfigboard.h" + +#include "common-hal/microcontroller/Pin.h" +#include "driver/gpio.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" #include "shared-module/displayio/mipi_constants.h" -#include "driver/gpio.h" -#include "common-hal/microcontroller/Pin.h" -#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" uint8_t display_init_sequence[] = { 0x01, 0x80, 0x80, // # Software reset then delay 0x80 (128ms) @@ -50,17 +51,17 @@ static void display_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO2, // TFT_DC Command or data - &pin_GPIO15, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS Chip select + mp_const_none, // TFT_RST Reset 6000000, // Baudrate 0, // Polarity 0); // Phase busdisplay_busdisplay_obj_t *display = &allocate_display()->display; display->base.type = &busdisplay_busdisplay_type; - os_getenv_err_t result = common_hal_os_getenv_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); - if (result != GETENV_OK) { + settings_err_t result = settings_get_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); + if (result != SETTINGS_OK) { rotation = 0; } diff --git a/ports/espressif/boards/sunton_esp32_2432S028/pins.c b/ports/espressif/boards/sunton_esp32_2432S028/pins.c index b852ab11e04..7791c1685eb 100644 --- a/ports/espressif/boards/sunton_esp32_2432S028/pins.c +++ b/ports/espressif/boards/sunton_esp32_2432S028/pins.c @@ -45,7 +45,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO5) }, - // ILI9341 dsplay (spi) + // ILI9341 display (spi) { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_GPIO13) }, { MP_ROM_QSTR(MP_QSTR_LCD_MISO), MP_ROM_PTR(&pin_GPIO12) }, { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_GPIO14) }, diff --git a/ports/espressif/boards/sunton_esp32_2432S032C/board.c b/ports/espressif/boards/sunton_esp32_2432S032C/board.c index b2160e0aa4f..db621cfe8c9 100644 --- a/ports/espressif/boards/sunton_esp32_2432S032C/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S032C/board.c @@ -43,9 +43,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO2, // TFT_DC - &pin_GPIO15, // TFT_CS - NULL, // TFT_RST + MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS + mp_const_none, // TFT_RST 26600000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/espressif/boards/sunton_esp32_8048S050/board.c b/ports/espressif/boards/sunton_esp32_8048S050/board.c index e01f857bfd9..b1794529ff0 100644 --- a/ports/espressif/boards/sunton_esp32_8048S050/board.c +++ b/ports/espressif/boards/sunton_esp32_8048S050/board.c @@ -6,13 +6,15 @@ #include "supervisor/board.h" #include "mpconfigboard.h" + +#include "driver/gpio.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/dotclockframebuffer/DotClockFramebuffer.h" #include "shared-bindings/dotclockframebuffer/__init__.h" #include "shared-bindings/framebufferio/FramebufferDisplay.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" -#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" static const mcu_pin_obj_t *blue_pins[] = { &pin_GPIO8, @@ -47,8 +49,8 @@ static void display_init(void) { dotclockframebuffer_framebuffer_obj_t *framebuffer = &allocate_display_bus_or_raise()->dotclock; framebuffer->base.type = &dotclockframebuffer_framebuffer_type; - os_getenv_err_t result = common_hal_os_getenv_int("CIRCUITPY_DISPLAY_FREQUENCY", &frequency); - if (result != GETENV_OK) { + settings_err_t result = settings_get_int("CIRCUITPY_DISPLAY_FREQUENCY", &frequency); + if (result != SETTINGS_OK) { frequency = 12500000; } diff --git a/ports/espressif/boards/sunton_esp32_8048S070/board.c b/ports/espressif/boards/sunton_esp32_8048S070/board.c index ecc9b7c1236..3d6a9c81e6d 100644 --- a/ports/espressif/boards/sunton_esp32_8048S070/board.c +++ b/ports/espressif/boards/sunton_esp32_8048S070/board.c @@ -6,6 +6,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/dotclockframebuffer/DotClockFramebuffer.h" #include "shared-bindings/dotclockframebuffer/__init__.h" diff --git a/ports/espressif/boards/unexpectedmaker_bling/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_bling/mpconfigboard.h index 671f714daea..f9aad2c4ba3 100644 --- a/ports/espressif/boards/unexpectedmaker_bling/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_bling/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_blizzard_s3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_blizzard_s3/mpconfigboard.h index dd677dad7b9..86275b0d784 100644 --- a/ports/espressif/boards/unexpectedmaker_blizzard_s3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_blizzard_s3/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_edges3d/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_edges3d/mpconfigboard.h index 27be4ffd1ce..a9271bc1e00 100644 --- a/ports/espressif/boards/unexpectedmaker_edges3d/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_edges3d/mpconfigboard.h @@ -21,3 +21,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h index d8349cdb58b..1df282a3326 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h index 1dd6b79a9b9..5141c6d7793 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h index 1d6c9035ac6..c2f9197fad8 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h index 53157a1ff11..dc48fe3f40f 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h @@ -28,3 +28,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_feathers3/pins.c b/ports/espressif/boards/unexpectedmaker_feathers3/pins.c index e611348caa0..63153d3d696 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers3/pins.c +++ b/ports/espressif/boards/unexpectedmaker_feathers3/pins.c @@ -128,6 +128,10 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_LDO2), MP_ROM_PTR(&pin_GPIO39) }, { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + // built-in vs uFL antenna switch (LOW=built-in, HIGH=uFL, default=built-in) + { MP_ROM_QSTR(MP_QSTR_ANTENNA_SWITCH), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + // I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, diff --git a/ports/espressif/boards/unexpectedmaker_feathers3_neo/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers3_neo/mpconfigboard.h index 037190d9aa8..18f2513e6af 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers3_neo/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers3_neo/mpconfigboard.h @@ -27,3 +27,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) // #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_nanos3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_nanos3/mpconfigboard.h index 022d6f3373e..f59ce34fb6a 100644 --- a/ports/espressif/boards/unexpectedmaker_nanos3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_nanos3/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_omgs3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_omgs3/mpconfigboard.h index 5fd666524c7..5ec5945cdfe 100644 --- a/ports/espressif/boards/unexpectedmaker_omgs3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_omgs3/mpconfigboard.h @@ -24,3 +24,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h index bec68c88cb1..dfef3399844 100644 --- a/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_rgbtouch_mini/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_rgbtouch_mini/mpconfigboard.h index 2cf95fa9a6d..b0bbcd2d457 100644 --- a/ports/espressif/boards/unexpectedmaker_rgbtouch_mini/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_rgbtouch_mini/mpconfigboard.h @@ -17,3 +17,6 @@ #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9) #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinyc6/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinyc6/mpconfigboard.h index 3e4995437d5..6f7e84c5c75 100644 --- a/ports/espressif/boards/unexpectedmaker_tinyc6/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinyc6/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO17) #define DEFAULT_UART_BUS_TX (&pin_GPIO16) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.h index c03aa8d7fbc..6300506e9e1 100644 --- a/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.h @@ -18,3 +18,6 @@ // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.h index 2ab781f1a2e..6b01e2c2e13 100644 --- a/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.h @@ -18,3 +18,6 @@ // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h index d7c87bfdba2..07c453cb7bc 100644 --- a/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h index 2556e714d67..066dd00386c 100644 --- a/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinywatch_s3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinywatch_s3/mpconfigboard.h index 6f0181c4acb..309c2e2e702 100644 --- a/ports/espressif/boards/unexpectedmaker_tinywatch_s3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinywatch_s3/mpconfigboard.h @@ -21,3 +21,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/vidi_x/board.c b/ports/espressif/boards/vidi_x/board.c index e53dfd82ad9..57e2b896213 100644 --- a/ports/espressif/boards/vidi_x/board.c +++ b/ports/espressif/boards/vidi_x/board.c @@ -6,6 +6,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/fourwire/FourWire.h" #include "shared-module/displayio/__init__.h" @@ -51,9 +52,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO21, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO21), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + mp_const_none, // TFT_RST Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/board.c b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/board.c index 7dd0e0c0fa2..e56c096e403 100644 --- a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/board.c +++ b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/board.c @@ -48,9 +48,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO15, // DC - &pin_GPIO14, // CS - &pin_GPIO21, // RST + MP_OBJ_FROM_PTR(&pin_GPIO15), // DC + MP_OBJ_FROM_PTR(&pin_GPIO14), // CS + MP_OBJ_FROM_PTR(&pin_GPIO21), // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h index 322acaf84b8..d745d366562 100644 --- a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h @@ -31,3 +31,6 @@ // Explanation of how a user got into safe mode #define BOARD_USER_SAFE_MODE_ACTION MP_ERROR_TEXT("You pressed the BOOT button at start up.") + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/board.c b/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/board.c index cb6fb310338..0bf710ec34c 100644 --- a/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/board.c +++ b/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/board.c @@ -61,9 +61,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO18, // DC - &pin_GPIO9, // CS - &pin_GPIO21, // RST + MP_OBJ_FROM_PTR(&pin_GPIO18), // DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // CS + MP_OBJ_FROM_PTR(&pin_GPIO21), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/mpconfigboard.h index c74499cf80a..638eb0390d8 100644 --- a/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/mpconfigboard.h @@ -20,3 +20,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c new file mode 100644 index 00000000000..7b57f48bcdb --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c @@ -0,0 +1,106 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/digitalio/DigitalInOut.h" + +#include "shared-bindings/qspibus/QSPIBus.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" + +// RM690B0 AMOLED initialization sequence. +// Format: command byte, length | 0x80 (if delay), data bytes..., [delay ms] +// Based on vendor recommendations, tested with Waveshare 2.41" AMOLED panel. +// Non-const to match upstream common_hal_busdisplay_busdisplay_construct signature. +static uint8_t display_init_sequence[] = { + // Page select and configuration + 0xFE, 0x01, 0x20, // Enter user command mode + 0x26, 0x01, 0x0A, // Bias setting + 0x24, 0x01, 0x80, // Source output control + 0xFE, 0x01, 0x13, // Page 13 + 0xEB, 0x01, 0x0E, // Vendor command + 0xFE, 0x01, 0x00, // Return to page 0 + // Display configuration + 0x3A, 0x01, 0x55, // COLMOD: 16-bit RGB565 + 0xC2, 0x81, 0x00, 0x0A, // Vendor command + 10ms delay + 0x35, 0x00, // Tearing effect line on (no data) + 0x51, 0x81, 0x00, 0x0A, // Brightness control + 10ms delay + // Power on + 0x11, 0x80, 0x50, // Sleep out + 80ms delay + // Display window (MV=1: CASET→rows, RASET→cols) + 0x2A, 0x04, 0x00, 0x10, 0x01, 0xD1, // CASET: 16..465 (450px + 16 offset) + 0x2B, 0x04, 0x00, 0x00, 0x02, 0x57, // RASET: 0..599 (600px) + // Enable display + 0x29, 0x80, 0x0A, // Display on + 10ms delay + // Memory access: MV=1, ML=1 for landscape + 0x36, 0x81, 0x30, 0x0A, // MADCTL + 10ms delay + // Brightness + 0x51, 0x01, 0xFF, // Set brightness to maximum +}; + +void board_init(void) { + // 0. Enable display power before any bus/display init. + digitalio_digitalinout_obj_t power_pin; + power_pin.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&power_pin, CIRCUITPY_LCD_POWER); + common_hal_digitalio_digitalinout_set_value(&power_pin, true); + common_hal_digitalio_digitalinout_never_reset(&power_pin); + // Allow power rail to settle before reset/init. + mp_hal_delay_ms(200); + + // 1. Allocate and construct QSPI bus + qspibus_qspibus_obj_t *bus = &allocate_display_bus_or_raise()->qspi_bus; + bus->base.type = &qspibus_qspibus_type; + + common_hal_qspibus_qspibus_construct(bus, + CIRCUITPY_LCD_CLK, // clock + CIRCUITPY_LCD_D0, // data0 + CIRCUITPY_LCD_D1, // data1 + CIRCUITPY_LCD_D2, // data2 + CIRCUITPY_LCD_D3, // data3 + CIRCUITPY_LCD_CS, // cs + NULL, // dcx (not used, QSPI uses encoded commands) + CIRCUITPY_LCD_RESET, // reset + 40000000); // 40 MHz + + // 2. Allocate and construct BusDisplay with RM690B0 init sequence. + // Physical panel: 450 cols × 600 rows. + // MADCTL MV=1 swaps row/col → logical 600×450 landscape. + busdisplay_busdisplay_obj_t *display = &allocate_display_or_raise()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct(display, + bus, + 600, // width (logical, after MV=1 swap) + 450, // height (logical, after MV=1 swap) + 0, // colstart + 16, // rowstart (physical row offset) + 0, // rotation + 16, // color_depth (RGB565) + false, // grayscale + false, // pixels_in_byte_share_row + 1, // bytes_per_cell + false, // reverse_pixels_in_byte + false, // reverse_bytes_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set_column_command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set_row_command + MIPI_COMMAND_WRITE_MEMORY_START, // write_ram_command + display_init_sequence, + sizeof(display_init_sequence), + NULL, // backlight_pin (AMOLED — no backlight GPIO) + 0x51, // brightness_command + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000); // backlight_pwm_frequency +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h new file mode 100644 index 00000000000..7a67f925ab1 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Waveshare ESP32-S3-Touch-AMOLED-2.41" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +// I2C bus - Disabled on boot to avoid conflicts. User must manually initialize I2C. +#define CIRCUITPY_BOARD_I2C (0) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO48, .sda = &pin_GPIO47}} + +// Display refresh buffer: 8192 bytes = 2048 uint32_t words on stack. +// ESP32-S3 main task stack is 24KB; verified safe with this board. +#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (8192) + +// AMOLED Display (displayio + qspibus path) - initialized in board_init() +#define CIRCUITPY_BOARD_DISPLAY (1) +#define CIRCUITPY_LCD_CS (&pin_GPIO9) +#define CIRCUITPY_LCD_CLK (&pin_GPIO10) +#define CIRCUITPY_LCD_D0 (&pin_GPIO11) +#define CIRCUITPY_LCD_D1 (&pin_GPIO12) +#define CIRCUITPY_LCD_D2 (&pin_GPIO13) +#define CIRCUITPY_LCD_D3 (&pin_GPIO14) +#define CIRCUITPY_LCD_RESET (&pin_GPIO21) +#define CIRCUITPY_LCD_POWER (&pin_GPIO16) + +// No default SPI bus — SD card uses SDIO, display uses QSPI. +#define CIRCUITPY_BOARD_SPI (0) + +// Default UART bus +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk new file mode 100644 index 00000000000..f901246804c --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk @@ -0,0 +1,35 @@ +# This file is part of the CircuitPython project: https://circuitpython.org +# SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +# SPDX-License-Identifier: MIT + +USB_VID = 0x303A +USB_PID = 0x8278 +USB_MANUFACTURER = "Waveshare" +USB_PRODUCT = "ESP32-S3-Touch-AMOLED-2.41" + +IDF_TARGET = esp32s3 + +# Flash configuration - 16MB QSPI Flash +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +# PSRAM configuration - 8MB Octal PSRAM +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +OPTIMIZATION_FLAGS = -Os + +# QSPI bus for RM690B0 AMOLED display +CIRCUITPY_QSPIBUS = 1 +CIRCUITPY_PARALLELDISPLAYBUS = 0 + +# No camera on this board +CIRCUITPY_ESPCAMERA = 0 + +# Capacitive touch not available; board uses I2C touch controller +CIRCUITPY_TOUCHIO = 0 + +# SD card via SDMMC interface +CIRCUITPY_SDIOIO = 1 diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c new file mode 100644 index 00000000000..8804cace06d --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c @@ -0,0 +1,109 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/mphal.h" +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // ================================================================= + // ONBOARD PERIPHERALS - Functional Names + // ================================================================= + + // Boot/Control/Battery/Display Power + // NOTE: GPIO16 is shared between battery control circuitry and LCD power + // (see CIRCUITPY_QSPIBUS_PANEL_POWER_PIN in mpconfigboard.h). + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_KEY_BAT), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_BAT_CONTROL), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_LCD_POWER), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_BAT_ADC), MP_ROM_PTR(&pin_GPIO17) }, + + // I2C Bus (shared by Touch, RTC, IMU, IO Expander) + // NOTE: board.I2C auto-initialization is disabled (CIRCUITPY_BOARD_I2C=0) + // to avoid boot conflicts. Users must manually create I2C bus: + // i2c = busio.I2C(board.SCL, board.SDA) + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + // Touch Panel (FT6336U on I2C) + // NOTE: TP_INT is routed through the TCA9554 IO expander (EXIO2), + // not a direct ESP32-S3 GPIO — no TOUCH_INT alias is possible here. + { MP_ROM_QSTR(MP_QSTR_TP_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_TP_SCL), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_TP_RESET), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_SCL), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_RST), MP_ROM_PTR(&pin_GPIO3) }, + + // RTC (PCF85063 on I2C) + { MP_ROM_QSTR(MP_QSTR_RTC_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_RTC_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + // IMU (QMI8658 on I2C) + { MP_ROM_QSTR(MP_QSTR_IMU_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IMU_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + // I/O Expander (TCA9554 on I2C) + { MP_ROM_QSTR(MP_QSTR_EXIO_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_EXIO_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + // USB + { MP_ROM_QSTR(MP_QSTR_USB_D_N), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_USB_D_P), MP_ROM_PTR(&pin_GPIO20) }, + + // UART + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + + // QSPI Display (RM690B0) - canonical generic LCD aliases. + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_LCD_CLK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D0), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D1), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D2), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D3), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_LCD_RESET), MP_ROM_PTR(&pin_GPIO21) }, + + // Display Aliases + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_SCK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_D0), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_D1), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_D2), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_D3), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_RST), MP_ROM_PTR(&pin_GPIO21) }, + + // SD Card (SDIO / SDMMC) + { MP_ROM_QSTR(MP_QSTR_SDIO_CLK), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_CMD), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_D0), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_D3), MP_ROM_PTR(&pin_GPIO2) }, + + // ================================================================= + // GENERAL PURPOSE I/O (IOxx - Espressif Convention) + // ================================================================= + // Only pins NOT dedicated to onboard peripherals are exposed here. + // Use functional names above for dedicated pins (e.g., SDA, SD_CS). + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, // BOOT button (available when not holding BOOT) + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, // TP_RESET (available if touch not used) + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, // Available + + // Board display (initialized in board_init) + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig new file mode 100644 index 00000000000..fa60cc4c237 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig @@ -0,0 +1,3 @@ +# +# Configuration file for the Waveshare ESP32-S3 Touch AMOLED 2.41 +# diff --git a/ports/espressif/boards/waveshare_esp32_s3_eth/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_eth/mpconfigboard.h index 037fa18c0be..5630a162798 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_eth/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_eth/mpconfigboard.h @@ -15,3 +15,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_geek/board.c b/ports/espressif/boards/waveshare_esp32_s3_geek/board.c index 414188fb46a..0ce44753264 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_geek/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_geek/board.c @@ -38,9 +38,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // TFT_DC - &pin_GPIO10, // TFT_CS - &pin_GPIO9, // TFT_RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // TFT_DC + MP_OBJ_FROM_PTR(&pin_GPIO10), // TFT_CS + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_RST 50000000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/espressif/boards/waveshare_esp32_s3_geek/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_geek/mpconfigboard.h index 87ac391f5a0..adb5a1c3af7 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_geek/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_geek/mpconfigboard.h @@ -20,3 +20,6 @@ #define CIRCUITPY_BOARD_SPI (2) #define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO12, .mosi = &pin_GPIO11}, \ {.clock = &pin_GPIO36, .mosi = &pin_GPIO35, .miso = &pin_GPIO37}} + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/board.c b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/board.c index 36990c85566..ee47ccb0bc9 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/board.c @@ -105,9 +105,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // DC - &pin_GPIO9, // CS - &pin_GPIO12, // RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/mpconfigboard.h index 1e1acbdd9f8..f19baae3c46 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/mpconfigboard.h @@ -23,3 +23,6 @@ #define CIRCUITPY_CONSOLE_UART_RX DEFAULT_UART_BUS_RX #define CIRCUITPY_CONSOLE_UART_TX DEFAULT_UART_BUS_TX + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/board.c b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/board.c index f3dd38522f7..4ecf87948ad 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/board.c @@ -48,9 +48,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO41, // DC - &pin_GPIO42, // CS - &pin_GPIO39, // RST + MP_OBJ_FROM_PTR(&pin_GPIO41), // DC + MP_OBJ_FROM_PTR(&pin_GPIO42), // CS + MP_OBJ_FROM_PTR(&pin_GPIO39), // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/mpconfigboard.h index 1999b7c9614..47d03fe9554 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/mpconfigboard.h @@ -20,3 +20,6 @@ #define CIRCUITPY_BOARD_SPI (2) #define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO40, .mosi = &pin_GPIO45}, \ {.clock = &pin_GPIO14, .mosi = &pin_GPIO15, .miso = &pin_GPIO16}} + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_matrix/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_matrix/mpconfigboard.h index 63595cb559e..c6c68e8336f 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_matrix/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_matrix/mpconfigboard.h @@ -13,3 +13,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_matrix/pins.c b/ports/espressif/boards/waveshare_esp32_s3_matrix/pins.c index e21f542179c..a107cd61c22 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_matrix/pins.c +++ b/ports/espressif/boards/waveshare_esp32_s3_matrix/pins.c @@ -35,7 +35,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, - { MP_ROM_QSTR(MP_QSTR_I01), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, diff --git a/ports/espressif/boards/waveshare_esp32_s3_pico/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_pico/mpconfigboard.h index 90ef06f2a12..2b95643a41e 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_pico/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_pico/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) #define DEFAULT_SPI_BUS_MOSI (&pin_GPIO35) #define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.h index fb33519370c..1785cc4486a 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.h @@ -17,3 +17,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO19) #define DEFAULT_UART_BUS_TX (&pin_GPIO20) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/board.c b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h new file mode 100644 index 00000000000..590b0fc5c5c --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Waveshare ESP32-S3-Tiny-N8R8" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +// This corrects the color ordering so that the CircuitPython status lights behave as expected +#define MICROPY_HW_NEOPIXEL_ORDER_GRB (1) +#define MICROPY_HW_NEOPIXEL (&pin_GPIO38) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO19) +#define DEFAULT_UART_BUS_TX (&pin_GPIO20) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.mk new file mode 100644 index 00000000000..ebb8317c457 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.mk @@ -0,0 +1,16 @@ +USB_VID = 0x303a +USB_PID = 0x8379 +USB_PRODUCT = "ESP32-S3-Tiny-N8R8" +USB_MANUFACTURER = "Waveshare Electronics" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/pins.c b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/pins.c new file mode 100644 index 00000000000..917ef0506ab --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/pins.c @@ -0,0 +1,61 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_IO34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + + // NEOPIXEL (GRB Color Order) + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO38) }, + + // UART + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + // Any pins can be I2C + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + // Any pins can be SPI + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c new file mode 100644 index 00000000000..1bdd74e77ee --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c @@ -0,0 +1,145 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 natheihei +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + +#define DELAY 0x80 + +// Driver is JD9853 +// 172 X 320 Pixels RGB 18-bit +// Init sequence converted from Arduino example + +uint8_t display_init_sequence[] = { + // Command: 0x11 (SLPOUT: Sleep Out) + // Description: Exits sleep mode. A 120ms delay is added for the power supply and clock circuits to stabilize. + 0x11, 0 | DELAY, 120, + + 0xDF, 2, 0x98, 0x53, + 0xB2, 1, 0x23, + + 0xB7, 4, 0x00, 0x47, 0x00, 0x6F, + 0xBB, 6, 0x1C, 0x1A, 0x55, 0x73, 0x63, 0xF0, + 0xC0, 2, 0x44, 0xA4, + 0xC1, 1, 0x16, + 0xC3, 8, 0x7D, 0x07, 0x14, 0x06, 0xCF, 0x71, 0x72, 0x77, + 0xC4, 12, 0x00, 0x00, 0xA0, 0x79, 0x0B, 0x0A, 0x16, 0x79, 0x0B, 0x0A, 0x16, 0x82, + + 0xC8, 32, 0x3F, 0x32, 0x29, 0x29, 0x27, 0x2B, 0x27, 0x28, 0x28, 0x26, 0x25, 0x17, 0x12, 0x0D, 0x04, 0x00, + 0x3F, 0x32, 0x29, 0x29, 0x27, 0x2B, 0x27, 0x28, 0x28, 0x26, 0x25, 0x17, 0x12, 0x0D, 0x04, 0x00, + + 0xD0, 5, 0x04, 0x06, 0x6B, 0x0F, 0x00, + 0xD7, 2, 0x00, 0x30, + 0xE6, 1, 0x14, + 0xDE, 1, 0x01, + + 0xB7, 5, 0x03, 0x13, 0xEF, 0x35, 0x35, + 0xC1, 3, 0x14, 0x15, 0xC0, + 0xC2, 2, 0x06, 0x3A, + 0xC4, 2, 0x72, 0x12, + 0xBE, 1, 0x00, + 0xDE, 1, 0x02, + + 0xE5, 3, 0x00, 0x02, 0x00, + 0xE5, 3, 0x01, 0x02, 0x00, + + 0xDE, 1, 0x00, + + // Command: 0x35 (TEON: Tearing Effect Line ON) + // Description: Turns on the Tearing Effect output signal. + 0x35, 1, 0x00, + + // Command: 0x3A (COLMOD: Pixel Format Set) + // Description: Sets the pixel format for the MCU interface. + 0x3A, 1, 0x05, + + // Command: 0x2A (CASET: Column Address Set) + // Description: Defines the accessible column range in frame memory. + 0x2A, 4, 0x00, 0x22, 0x00, 0xCD, + + // Command: 0x2B (PASET: Page Address Set) + // Description: Defines the accessible page (row) range. + 0x2B, 4, 0x00, 0x00, 0x01, 0x3F, + + 0xDE, 1, 0x02, + 0xE5, 3, 0x00, 0x02, 0x00, + 0xDE, 1, 0x00, + + // Command: 0x36 (MADCTL: Memory Access Control) + // Description: Sets the read/write scanning direction of the frame memory. + 0x36, 1, 0x00, + + // Command: 0x21 (INVON: Display Inversion ON) + // 0x21, 0 | DELAY, 10, + + // Command: 0x29 (DISPON: Display ON) + // Description: Turns the display on by enabling output from the frame memory. + 0x29, 0, +}; + +static void display_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO45), // DC + MP_OBJ_FROM_PTR(&pin_GPIO21), // CS + MP_OBJ_FROM_PTR(&pin_GPIO40), // RST + 80000000, // baudrate + 0, // polarity + 0 // phase + ); + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 172, // width (after rotation) + 320, // height (after rotation) + 34, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO46, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} + +void board_init(void) { + // Display + display_init(); +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h new file mode 100644 index 00000000000..7fed8626501 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h @@ -0,0 +1,25 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 natheihei +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Waveshare ESP32-S3 Touch LCD 1.47" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define CIRCUITPY_BOARD_UART (1) +#define CIRCUITPY_BOARD_UART_PIN {{.rx = &pin_GPIO44, .tx = &pin_GPIO43}} + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO41, .sda = &pin_GPIO42}} /* for Touchscreen */ + +#define CIRCUITPY_BOARD_SPI (2) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO38, .mosi = &pin_GPIO39}, /* for LCD display */ \ + {.clock = &pin_GPIO16, .mosi = &pin_GPIO15, .miso = &pin_GPIO17} /* for SD Card */} + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.mk new file mode 100644 index 00000000000..b337b211495 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x8325 +USB_PRODUCT = "ESP32-S3-Touch-LCD-1.47" +USB_MANUFACTURER = "Waveshare Electronics" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/pins.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/pins.c new file mode 100644 index 00000000000..32c7d0dd21d --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/pins.c @@ -0,0 +1,58 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 natheihei +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +CIRCUITPY_BOARD_BUS_SINGLETON(touch_i2c, i2c, 0) +CIRCUITPY_BOARD_BUS_SINGLETON(sd_spi, spi, 1) + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // UART + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + + // GPIO + { MP_ROM_QSTR(MP_QSTR_GPIO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GPIO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GPIO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GPIO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GPIO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GPIO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GPIO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GPIO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GPIO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GPIO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GPIO11), MP_ROM_PTR(&pin_GPIO11) }, + + // I2C (occupied by Touch I2C) + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + // SD Card + { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SD_D0), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SD_D1), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SD_D2), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_SD_D3), MP_ROM_PTR(&pin_GPIO14) }, + // CLK, CMD, D0 is also included in the SPI object as its MISO pin, MOSI pin, and SCK pin respectively + { MP_ROM_QSTR(MP_QSTR_SD_SPI), MP_ROM_PTR(&board_sd_spi_obj) }, + + // AXS5106L Touch + { MP_ROM_QSTR(MP_QSTR_TOUCH_I2C), MP_ROM_PTR(&board_touch_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_RST), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_IRQ), MP_ROM_PTR(&pin_GPIO48) }, + + // JD9853 LCD Display + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, + +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/board.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/board.c index e7a6b86440e..71e2d745623 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/board.c @@ -34,9 +34,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO42, // DC - &pin_GPIO45, // CS - &pin_GPIO0, // RST + MP_OBJ_FROM_PTR(&pin_GPIO42), // DC + MP_OBJ_FROM_PTR(&pin_GPIO45), // CS + MP_OBJ_FROM_PTR(&pin_GPIO0), // RST // 24000000, 40000000, // baudrate 0, // polarity diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/mpconfigboard.h index b4009fdfd7f..d6b66bffafa 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/mpconfigboard.h @@ -17,3 +17,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c new file mode 100755 index 00000000000..49177f48fe7 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c @@ -0,0 +1,77 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + +#define DELAY 0x80 + +// display init sequence according to LilyGO example app +uint8_t display_init_sequence[] = { + 0x01, DELAY, 0x96, // _SWRESET and Delay 150ms + 0x11, DELAY, 0xFF, // _SLPOUT and Delay 500ms + 0x3A, DELAY | 1, 0x55, 0x0A, // _COLMOD and Delay 10ms + 0x21, DELAY, 0x0A, // _INVON Hack and Delay 10ms + 0x13, DELAY, 0x0A, // _NORON and Delay 10ms + 0x36, 0x01, 0x60, // _MADCTL + 0x29, DELAY, 0xFF, // _DISPON and Delay 500ms +}; + +void board_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO41), // DC + MP_OBJ_FROM_PTR(&pin_GPIO42), // CS + MP_OBJ_FROM_PTR(&pin_GPIO39), // RST + 40000000, // baudrate + 0, // polarity + 0 // phase + ); + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 320, // width (after rotation) + 240, // height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO5, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h new file mode 100755 index 00000000000..a04002de73f --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Neradoc +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Waveshare ESP32-S3 Touch LCD 2.8" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO3, .sda = &pin_GPIO1}} + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO40, .mosi = &pin_GPIO45, .miso = &pin_GPIO46}} + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk new file mode 100755 index 00000000000..421a5897600 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x825F +USB_MANUFACTURER = "Waveshare Electronics" +USB_PRODUCT = "ESP32-S3 Touch LCD 2.8" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c new file mode 100755 index 00000000000..0bfb3e940b4 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c @@ -0,0 +1,86 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // LCD (SPI0) + { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MISO), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_LCD_DC), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_LCD_RST), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_LCD_BL), MP_ROM_PTR(&pin_GPIO5) }, // PWM-capable + + // microSD (SPI1) + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO21) }, + + // Touch panel (I2C0) + { MP_ROM_QSTR(MP_QSTR_TP_SCL), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_TP_SDA), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_TP_RST), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_TP_INT), MP_ROM_PTR(&pin_GPIO4) }, + + // IMU (I2C1) + { MP_ROM_QSTR(MP_QSTR_IMU_SCL), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IMU_SDA), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IMU_INT2), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IMU_INT1), MP_ROM_PTR(&pin_GPIO13) }, + + // I2S Audio + { MP_ROM_QSTR(MP_QSTR_I2S_BCK), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DIN), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCK), MP_ROM_PTR(&pin_GPIO38) }, + + // Battery management + { MP_ROM_QSTR(MP_QSTR_BAT_CONTROL), MP_ROM_PTR(&pin_GPIO7) }, // control pin + { MP_ROM_QSTR(MP_QSTR_BAT_PWR), MP_ROM_PTR(&pin_GPIO6) }, // Board name + { MP_ROM_QSTR(MP_QSTR_KEY_BAT), MP_ROM_PTR(&pin_GPIO6) }, // Schematics name + { MP_ROM_QSTR(MP_QSTR_BAT_ADC), MP_ROM_PTR(&pin_GPIO8) }, // VBAT sense (ADC) + + // UART header + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + + // I2C header + { MP_ROM_QSTR(MP_QSTR_I2C_SCL), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_I2C_SDA), MP_ROM_PTR(&pin_GPIO11) }, + + // Boot/User button + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON0), MP_ROM_PTR(&pin_GPIO0) }, + + // Primary bus pins + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO40) }, // Primary SPI (LCD) + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) }, // Primary I2C (TP) + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO1) }, + + // Objects + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, + + // User accessible + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/tests/feature_check/byteorder.py.exp b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/sdkconfig old mode 100644 new mode 100755 similarity index 100% rename from tests/feature_check/byteorder.py.exp rename to ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/sdkconfig diff --git a/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.h index da6b7a8a855..f0a19c0e290 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.h @@ -16,3 +16,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h index 2888af9184a..5875725a00f 100644 --- a/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.h b/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.h index 6a9f0357156..fa0ed02f676 100644 --- a/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.h +++ b/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.h @@ -20,3 +20,6 @@ // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/xteink_x4/board.c b/ports/espressif/boards/xteink_x4/board.c new file mode 100644 index 00000000000..b5b193c65fe --- /dev/null +++ b/ports/espressif/boards/xteink_x4/board.c @@ -0,0 +1,130 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// SPDX-FileCopyrightText: Copyright (c) 2021 skieast/Bruce Segal +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/board.h" + +#define DELAY 0x80 + +// SSD1677 controller driving a GDEQ0426T82 4.26" 800x480 E-Ink display. + +const uint8_t ssd1677_display_start_sequence[] = { + // Software Reset + 0x12, DELAY, 0x00, 0x14, + + // Temperature Sensor Control (use internal sensor) + 0x18, 0x00, 0x01, 0x80, + + // Booster Soft Start + 0x0C, 0x00, 0x05, 0xAE, 0xC7, 0xC3, 0xC0, 0x40, + + // Driver Output Control: 480 gates, GD=0, SM=1, TB=0 = 0x02 + 0x01, 0x00, 0x03, 0xDF, 0x01, 0x02, + + // Data Entry Mode: X increment, Y decrement = 0x01 + 0x11, 0x00, 0x01, 0x01, + + // Border Waveform Control + 0x3C, 0x00, 0x01, 0x01, + + // Set RAM X Address Start/End: 0 to 799 + 0x44, 0x00, 0x04, 0x00, 0x00, 0x1F, 0x03, + + // Set RAM Y Address Start/End: 479 down to 0 + 0x45, 0x00, 0x04, 0xDF, 0x01, 0x00, 0x00, + + // Set RAM X Counter to 0 + 0x4E, 0x00, 0x02, 0x00, 0x00, + + // Set RAM Y Counter to 479 + 0x4F, 0x00, 0x02, 0xDF, 0x01, + + // Auto Write BW RAM (clear to white) + 0x46, DELAY, 0x01, 0xF7, 0xFF, + + // Display Update Control 1: bypass RED + 0x21, 0x00, 0x02, 0x40, 0x00, + + // Display Update Control 2: full refresh with OTP LUT + 0x22, 0x00, 0x01, 0xF7, +}; + +const uint8_t ssd1677_display_stop_sequence[] = { + 0x22, 0x00, 0x01, 0x83, + 0x20, 0x00, 0x00, + 0x10, 0x00, 0x01, 0x01, +}; + +const uint8_t ssd1677_display_refresh_sequence[] = { + 0x20, 0x00, 0x00, +}; + +void board_init(void) { + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO8, &pin_GPIO10, NULL, false); + common_hal_busio_spi_never_reset(spi); + + bus->base.type = &fourwire_fourwire_type; + common_hal_fourwire_fourwire_construct(bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO4), + MP_OBJ_FROM_PTR(&pin_GPIO21), + MP_OBJ_FROM_PTR(&pin_GPIO5), + 40000000, + 0, + 0); + + epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; + display->base.type = &epaperdisplay_epaperdisplay_type; + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = ssd1677_display_start_sequence; + args.start_sequence_len = sizeof(ssd1677_display_start_sequence); + args.stop_sequence = ssd1677_display_stop_sequence; + args.stop_sequence_len = sizeof(ssd1677_display_stop_sequence); + args.width = 800; + args.height = 480; + args.ram_width = 800; + args.ram_height = 480; + args.rotation = 0; + args.write_black_ram_command = 0x24; + args.black_bits_inverted = false; + args.refresh_sequence = ssd1677_display_refresh_sequence; + args.refresh_sequence_len = sizeof(ssd1677_display_refresh_sequence); + args.refresh_time = 1.6; + args.busy_pin = &pin_GPIO6; + args.busy_state = true; + args.seconds_per_frame = 5.0; + args.grayscale = false; + args.two_byte_sequence_length = true; + args.address_little_endian = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); +} + +bool espressif_board_reset_pin_number(gpio_num_t pin_number) { + return false; +} + +void board_deinit(void) { + epaperdisplay_epaperdisplay_obj_t *display = &displays[0].epaper_display; + if (display->base.type == &epaperdisplay_epaperdisplay_type) { + while (common_hal_epaperdisplay_epaperdisplay_get_busy(display)) { + RUN_BACKGROUND_TASKS; + } + } + common_hal_displayio_release_displays(); +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/xteink_x4/mpconfigboard.h b/ports/espressif/boards/xteink_x4/mpconfigboard.h new file mode 100644 index 00000000000..5d4bb372228 --- /dev/null +++ b/ports/espressif/boards/xteink_x4/mpconfigboard.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// SPDX-FileCopyrightText: Copyright (c) 2021 skieast/Bruce Segal +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Board setup +#define MICROPY_HW_BOARD_NAME "Xteink X4" +#define MICROPY_HW_MCU_NAME "ESP32-C3" + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO8, .mosi = &pin_GPIO10, .miso = &pin_GPIO7}} + +// For entering safe mode +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO3) diff --git a/ports/espressif/boards/xteink_x4/mpconfigboard.mk b/ports/espressif/boards/xteink_x4/mpconfigboard.mk new file mode 100644 index 00000000000..8668aad1818 --- /dev/null +++ b/ports/espressif/boards/xteink_x4/mpconfigboard.mk @@ -0,0 +1,29 @@ +CIRCUITPY_CREATOR_ID = 0x0EEE0000 +CIRCUITPY_CREATION_ID = 0x00C30001 + +IDF_TARGET = esp32c3 + +CIRCUITPY_ESP_FLASH_MODE = dio +CIRCUITPY_ESP_FLASH_FREQ = 40m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 + +CIRCUITPY_PARALLELDISPLAYBUS = 0 +CIRCUITPY_RGBMATRIX = 0 +CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOCORE = 0 +CIRCUITPY_AUDIOMIXER = 0 +CIRCUITPY_AUDIOMP3 = 0 +CIRCUITPY_CAMERA = 0 +CIRCUITPY_CANIO = 0 +CIRCUITPY_DOTCLOCKFRAMEBUFFER = 0 +CIRCUITPY_KEYPAD = 0 +CIRCUITPY_ROTARYIO = 0 +CIRCUITPY_USB_HID = 0 +CIRCUITPY_USB_MIDI = 0 +CIRCUITPY_ULAB = 0 +CIRCUITPY_PULSEIO = 0 +CIRCUITPY_PWMIO = 0 +CIRCUITPY_RAINBOWIO = 0 +CIRCUITPY_SYNTHIO = 0 diff --git a/ports/espressif/boards/xteink_x4/pins.c b/ports/espressif/boards/xteink_x4/pins.c new file mode 100644 index 00000000000..6b8232d4cb3 --- /dev/null +++ b/ports/espressif/boards/xteink_x4/pins.c @@ -0,0 +1,52 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// SPDX-FileCopyrightText: Copyright (c) 2021 skieast/Bruce Segal +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_ADC_1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_ADC_2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_EPD_MOSI), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_EPD_SCK), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_EPD_BUSY), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_EPD_RESET), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_EPD_DC), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_EPD_CS), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].epaper_display)}, + +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/xteink_x4/sdkconfig b/ports/espressif/boards/xteink_x4/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/xteink_x4/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/yoto_mini_2024/board.c b/ports/espressif/boards/yoto_mini_2024/board.c new file mode 100644 index 00000000000..fb6a96a957d --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/board.c @@ -0,0 +1,203 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "board.h" + +#include "supervisor/board.h" + +#include "extmod/vfs_fat.h" + +#include "py/mpstate.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/i2cioexpander/IOExpander.h" +#include "shared-bindings/i2cioexpander/IOPin.h" +#include "shared-bindings/sdioio/SDCard.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" + +#include "supervisor/filesystem.h" + +static sdioio_sdcard_obj_t sdmmc; +static mp_vfs_mount_t _sdcard_vfs; +static fs_user_mount_t _sdcard_usermount; +static i2cioexpander_ioexpander_obj_t ioexpander; + +#define DELAY 0x80 + +// This is a GC9306. +uint8_t display_init_sequence[] = { + 0xfe, 0, + 0xef, 0, + + // // sw reset + // 0x01, 0 | DELAY, 150, + // normal display mode on + // 0x13, 0, + // display and color format settings + 0x36, 1, 0x48, // Memory access control. mini does 0x48, not 0, 2, 3, 4 or 6 + 0x3A, 1 | DELAY, 0x55, 10, // COLMOD. mini does 0x06 + 0xa4, 2, 0x44, 0x44, // power control 7 + 0xa5, 2, 0x42, 0x42, + 0xaa, 2, 0x88, 0x88, + 0xae, 1, 0x2b, + 0xe8, 2, 0x22, 0x0b, // frame rate + 0xe3, 2, 0x01, 0x10, + 0xff, 1, 0x61, + 0xac, 1, 0x00, + 0xad, 1, 0x33, + 0xaf, 1, 0x77, + 0xa6, 2, 0x1c, 0x1c, // power control 2 + 0xa7, 2, 0x1c, 0x1c, // power control 3 + 0xa8, 2, 0x10, 0x10, // power control 4 + 0xa9, 2, 0x0d, 0x0d, // power control 5 + 0xf0, 6, 0x02, 0x01, 0x00, 0x00, 0x00, 0x05, // Gamma settings + 0xf1, 6, 0x01, 0x02, 0x00, 0x06, 0x10, 0x0e, + 0xf2, 6, 0x03, 0x11, 0x28, 0x02, 0x00, 0x48, + 0xf3, 6, 0x0c, 0x11, 0x30, 0x00, 0x00, 0x46, + 0xf4, 6, 0x05, 0x1f, 0x1f, 0x36, 0x30, 0x0f, + 0xf5, 6, 0x04, 0x1d, 0x1a, 0x38, 0x3f, 0x0f, // Last gamma setting + 0x35, 1, 0x00, + 0x44, 2, 0x00, 0x0a, // set tear scan line + 0x21, 0, // display inversion on + // sleep out + 0x11, 0 | DELAY, 255, + + // display on + 0x29, 0 | DELAY, 255, +}; + +void board_init(void) { + // Wait for everything to start + mp_hal_delay_ms(300); + + // Initialize the board's peripherals here. + busio_i2c_obj_t *i2c = MP_OBJ_TO_PTR(common_hal_board_create_i2c(0)); + + // Initialize the IOExpander + ioexpander.base.type = &i2cioexpander_ioexpander_type; + common_hal_i2cioexpander_ioexpander_construct( + &ioexpander, + MP_OBJ_FROM_PTR(i2c), + 0x20, // I2C address + 16, // Number of pins + 2, // Output register + 0, // Input register + 6); // Direction register + + board_set(MP_QSTR_IOEXPANDER, MP_OBJ_FROM_PTR(&ioexpander)); + board_set(MP_QSTR_PLUG_STATUS, ioexpander.pins->items[8 + 5]); + board_set(MP_QSTR_CHARGE_STATUS, ioexpander.pins->items[8 + 7]); + board_set(MP_QSTR_POWER_BUTTON, ioexpander.pins->items[8 + 3]); + board_set(MP_QSTR_ENC1_BUTTON, ioexpander.pins->items[5]); + board_set(MP_QSTR_ENC2_BUTTON, ioexpander.pins->items[4]); + board_set(MP_QSTR_HEADPHONE_DETECT, ioexpander.pins->items[8 + 1]); + board_set(MP_QSTR_PACTRL, ioexpander.pins->items[6]); + board_set(MP_QSTR_DISPLAY_CS, ioexpander.pins->items[0]); + board_set(MP_QSTR_DISPLAY_DC, ioexpander.pins->items[1]); + board_set(MP_QSTR_DISPLAY_RESET, ioexpander.pins->items[2]); + + board_set(MP_QSTR_LEVEL_CONVERTER, ioexpander.pins->items[3]); + board_set(MP_QSTR_LEVEL_POWER_ENABLE, ioexpander.pins->items[8 + 4]); + board_set(MP_QSTR_LEVEL_VINHOLD, ioexpander.pins->items[8 + 6]); + + board_set(MP_QSTR_TILT, ioexpander.pins->items[8 + 2]); + + // Only on some variants + board_set(MP_QSTR_RTC_INT, ioexpander.pins->items[7]); + + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[2]), true, DRIVE_MODE_PUSH_PULL); + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[3]), true, DRIVE_MODE_PUSH_PULL); + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[6]), true, DRIVE_MODE_PUSH_PULL); + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[14]), true, DRIVE_MODE_PUSH_PULL); + + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + ioexpander.pins->items[1], // DC + ioexpander.pins->items[0], // CS + ioexpander.pins->items[2], // RST + 25000000, // baudrate + 0, // polarity + 0 // phase + ); + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 240, // width (after rotation) + 240, // height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO26, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); + + digitalinout_result_t sd_enable_res = common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[12]), false, DRIVE_MODE_PUSH_PULL); + if (sd_enable_res != DIGITALINOUT_OK) { + mp_printf(&mp_plat_print, "Failed to initialize IOExpander. Skipping SD card\n"); + return; + } + + sdmmc.base.type = &sdioio_SDCard_type; + const mcu_pin_obj_t *data_pins[4] = {MP_ROM_PTR(&pin_GPIO2), MP_ROM_PTR(&pin_GPIO4), MP_ROM_PTR(&pin_GPIO12), MP_ROM_PTR(&pin_GPIO13)}; + common_hal_sdioio_sdcard_construct(&sdmmc, MP_ROM_PTR(&pin_GPIO14), MP_ROM_PTR(&pin_GPIO15), 4, data_pins, 25 * 1000000); + + fs_user_mount_t *vfs = &_sdcard_usermount; + vfs->base.type = &mp_fat_vfs_type; + vfs->fatfs.drv = vfs; + + // Initialise underlying block device + vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to MP_BLOCKDEV_IOCTL_BLOCK_SIZE + mp_vfs_blockdev_init(&vfs->blockdev, &sdmmc); + + // mount the block device so the VFS methods can be used + FRESULT res = f_mount(&vfs->fatfs); + if (res != FR_OK) { + common_hal_sdioio_sdcard_deinit(&sdmmc); + return; + } + common_hal_sdioio_sdcard_never_reset(&sdmmc); + + filesystem_set_concurrent_write_protection(vfs, true); + filesystem_set_writable_by_usb(vfs, false); + + mp_vfs_mount_t *sdcard_vfs = &_sdcard_vfs; + sdcard_vfs->str = "/sd"; + sdcard_vfs->len = 3; + sdcard_vfs->obj = MP_OBJ_FROM_PTR(&_sdcard_usermount); + sdcard_vfs->next = MP_STATE_VM(vfs_mount_table); + MP_STATE_VM(vfs_mount_table) = sdcard_vfs; +} diff --git a/ports/espressif/boards/yoto_mini_2024/board.h b/ports/espressif/boards/yoto_mini_2024/board.h new file mode 100644 index 00000000000..1e40b62b047 --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/board.h @@ -0,0 +1,3 @@ +#include "py/obj.h" + +extern void board_set(qstr key, mp_obj_t value); diff --git a/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h new file mode 100644 index 00000000000..4fcc2afaae8 --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Yoto Mini 2024" +#define MICROPY_HW_MCU_NAME "ESP32" + +#define CIRCUITPY_MUTABLE_BOARD (1) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO25, .sda = &pin_GPIO21}} +#define CIRCUITPY_BOARD_I2C_SPEED (400000) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO23, .mosi = &pin_GPIO22, .miso = NULL}} + +#define CIRCUITPY_BOARD_UART (1) +#define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO17, .rx = &pin_GPIO16}} + +// UART pins attached to the USB-serial converter chip +#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) +#define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) diff --git a/ports/espressif/boards/yoto_mini_2024/mpconfigboard.mk b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.mk new file mode 100644 index 00000000000..356e7015a04 --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.mk @@ -0,0 +1,14 @@ +CIRCUITPY_CREATOR_ID = 0x40100000 +CIRCUITPY_CREATION_ID = 0x00320002 + +IDF_TARGET = esp32 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 40m + +CIRCUITPY_I2CIOEXPANDER = 1 diff --git a/ports/espressif/boards/yoto_mini_2024/pins.c b/ports/espressif/boards/yoto_mini_2024/pins.c new file mode 100644 index 00000000000..d4ff3b4863f --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/pins.c @@ -0,0 +1,79 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT +// + +#include "board.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static mp_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_MUTABLE_BOARD_DICT_STANDARD_ITEMS + + // External pins are in silkscreen order, from top to bottom, left side, then right side + { MP_ROM_QSTR(MP_QSTR_ENC1A), MP_OBJ_FROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_ENC1B), MP_OBJ_FROM_PTR(&pin_GPIO35) }, + + { MP_ROM_QSTR(MP_QSTR_ENC2A), MP_OBJ_FROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_ENC2B), MP_OBJ_FROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_OBJ_FROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_OBJ_FROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY_SCK), MP_OBJ_FROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_MOSI), MP_OBJ_FROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_NFC_IN), MP_OBJ_FROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_OBJ_FROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_NFC_OUT), MP_OBJ_FROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_OBJ_FROM_PTR(&pin_GPIO33) }, + + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_OBJ_FROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_OBJ_FROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BCLK), MP_OBJ_FROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_OBJ_FROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCLK), MP_OBJ_FROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DOUT), MP_OBJ_FROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER_INT), MP_OBJ_FROM_PTR(&pin_GPIO34) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_OBJ_FROM_PTR(&displays[0].display)}, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_OBJ_FROM_PTR(&board_i2c_obj) }, + + // Filled in by board_init() + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_PLUG_STATUS), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_CHARGE_STATUS), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_POWER_BUTTON), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_ENC1_BUTTON), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_ENC2_BUTTON), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_HEADPHONE_DETECT), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_PACTRL), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_DC), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_RESET), mp_const_none }, + + { MP_ROM_QSTR(MP_QSTR_LEVEL_CONVERTER), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_LEVEL_POWER_ENABLE), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_LEVEL_VINHOLD), mp_const_none }, + + { MP_ROM_QSTR(MP_QSTR_TILT), mp_const_none }, + + // Only on some variants + { MP_ROM_QSTR(MP_QSTR_RTC_INT), mp_const_none }, + +}; +MP_DEFINE_MUTABLE_DICT(board_module_globals, board_module_globals_table); + +void board_set(qstr q, mp_obj_t value) { + mp_obj_t key = MP_OBJ_NEW_QSTR(q); + for (size_t i = 0; i < MP_ARRAY_SIZE(board_module_globals_table); i++) { + if (board_module_globals_table[i].key == key) { + board_module_globals_table[i].value = value; + return; + } + } +} diff --git a/tests/feature_check/complex.py.exp b/ports/espressif/boards/yoto_mini_2024/sdkconfig similarity index 100% rename from tests/feature_check/complex.py.exp rename to ports/espressif/boards/yoto_mini_2024/sdkconfig diff --git a/ports/espressif/boards/yoto_player_v3/board.c b/ports/espressif/boards/yoto_player_v3/board.c new file mode 100644 index 00000000000..fd6ee40b9f3 --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/board.c @@ -0,0 +1,148 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "board.h" + +#include "supervisor/board.h" + +#include "extmod/vfs_fat.h" + +#include "py/mpstate.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/i2cioexpander/IOExpander.h" +#include "shared-bindings/i2cioexpander/IOPin.h" +#include "shared-bindings/sdioio/SDCard.h" + +#include "supervisor/filesystem.h" + +static sdioio_sdcard_obj_t sdmmc; +static mp_vfs_mount_t _sdcard_vfs; +static fs_user_mount_t _sdcard_usermount; +static i2cioexpander_ioexpander_obj_t ioexpander0; // First chip (p0/p1) +static i2cioexpander_ioexpander_obj_t ioexpander1; // Second chip (p2/p3) + +void board_init(void) { + // Wait for everything to start + mp_hal_delay_ms(300); + + // Initialize the board's peripherals here. + busio_i2c_obj_t *i2c = MP_OBJ_TO_PTR(common_hal_board_create_i2c(0)); + + // Initialize the IOExpanders + // V3/V3-E uses two PI4IOE5V6416 chips (16 pins each) + // First chip (0x20): p0 (pins 0-7), p1 (pins 8-15) + ioexpander0.base.type = &i2cioexpander_ioexpander_type; + common_hal_i2cioexpander_ioexpander_construct( + &ioexpander0, + MP_OBJ_FROM_PTR(i2c), + 0x20, // I2C address for first chip + 16, // Number of pins + 2, // Output register + 0, // Input register + 6); // Direction register + + // Second chip (0x21): p2 (pins 0-7), p3 (pins 8-15) + ioexpander1.base.type = &i2cioexpander_ioexpander_type; + common_hal_i2cioexpander_ioexpander_construct( + &ioexpander1, + MP_OBJ_FROM_PTR(i2c), + 0x21, // I2C address for second chip + 16, // Number of pins + 2, // Output register + 0, // Input register + 6); // Direction register + + board_set(MP_QSTR_IOEXPANDER0, MP_OBJ_FROM_PTR(&ioexpander0)); + board_set(MP_QSTR_IOEXPANDER1, MP_OBJ_FROM_PTR(&ioexpander1)); + + // Battery and charging (from first chip - p0/p1) + board_set(MP_QSTR_BATTERY_ALERT, ioexpander0.pins->items[6]); // IOX.0.6 + board_set(MP_QSTR_QI_STATUS, ioexpander0.pins->items[7]); // IOX.0.7 + board_set(MP_QSTR_QI_I2C_INT, ioexpander0.pins->items[0]); // IOX.0.0 + board_set(MP_QSTR_USB_STATUS, ioexpander0.pins->items[8 + 0]); // IOX.1.0 + board_set(MP_QSTR_CHARGE_STATUS, ioexpander0.pins->items[8 + 4]); // IOX.1.4 + + // Buttons (from first chip - p0/p1) + board_set(MP_QSTR_POWER_BUTTON, ioexpander0.pins->items[8 + 3]); // IOX.1.3 + board_set(MP_QSTR_ENC1_BUTTON, ioexpander0.pins->items[5]); // IOX.0.5 + board_set(MP_QSTR_ENC2_BUTTON, ioexpander0.pins->items[4]); // IOX.0.4 + + // Audio (from first chip - p0/p1 and second chip - p2/p3) + board_set(MP_QSTR_HEADPHONE_DETECT, ioexpander0.pins->items[8 + 1]); // IOX.1.1 + board_set(MP_QSTR_PACTRL, ioexpander1.pins->items[4]); // IOX.2.4 + + // Display - V3/V3-E uses ht16d35x with 4 CS lines (from second chip - p2) + board_set(MP_QSTR_DISPLAY_CS0, ioexpander1.pins->items[0]); // IOX.2.0 + board_set(MP_QSTR_DISPLAY_CS1, ioexpander1.pins->items[1]); // IOX.2.1 + board_set(MP_QSTR_DISPLAY_CS2, ioexpander1.pins->items[2]); // IOX.2.2 + board_set(MP_QSTR_DISPLAY_CS3, ioexpander1.pins->items[3]); // IOX.2.3 + + // Power control (from second chip - p2/p3) + board_set(MP_QSTR_LEVEL_CONVERTER, ioexpander1.pins->items[8 + 0]); // IOX.3.0 + board_set(MP_QSTR_LEVEL_POWER_ENABLE, ioexpander1.pins->items[5]); // IOX.2.5 + board_set(MP_QSTR_LEVEL_VINHOLD, ioexpander1.pins->items[8 + 1]); // IOX.3.1 + board_set(MP_QSTR_LEVEL_VOUTEN, ioexpander1.pins->items[8 + 3]); // IOX.3.3 + + // Sensors (from first chip - p0/p1) + board_set(MP_QSTR_TILT, ioexpander0.pins->items[8 + 2]); // IOX.1.2 + board_set(MP_QSTR_RTC_INT, ioexpander0.pins->items[1]); // IOX.0.1 + + // Qi charging control (V3-E, from second chip - p2/p3) + board_set(MP_QSTR_QI_CHARGE_ENABLE, ioexpander1.pins->items[6]); // IOX.2.6 + board_set(MP_QSTR_USB_CHARGE_ENABLE, ioexpander1.pins->items[7]); // IOX.2.7 + board_set(MP_QSTR_QI_ENABLE_5W, ioexpander1.pins->items[8 + 5]); // IOX.3.5 + + // Output pin 3 high. Not clear why. + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander0.pins->items[3]), true, DRIVE_MODE_PUSH_PULL); + + // Initialize output pins + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[0]), true, DRIVE_MODE_PUSH_PULL); // DISPLAY_CS0 (IOX.2.0) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[1]), true, DRIVE_MODE_PUSH_PULL); // DISPLAY_CS1 (IOX.2.1) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[2]), true, DRIVE_MODE_PUSH_PULL); // DISPLAY_CS2 (IOX.2.2) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[3]), true, DRIVE_MODE_PUSH_PULL); // DISPLAY_CS3 (IOX.2.3) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[4]), true, DRIVE_MODE_PUSH_PULL); // PACTRL (IOX.2.4) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[5]), false, DRIVE_MODE_PUSH_PULL); // LEVEL_POWER_ENABLE (IOX.2.5) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[6]), true, DRIVE_MODE_PUSH_PULL); // QI_CHARGE_ENABLE + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[7]), false, DRIVE_MODE_PUSH_PULL); // USB_CHARGE_ENABLE + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[8 + 0]), true, DRIVE_MODE_PUSH_PULL); // LEVEL_CONVERTER (IOX.3.0) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[8 + 1]), true, DRIVE_MODE_PUSH_PULL); // VINHOLD (IOX.3.1) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[8 + 3]), true, DRIVE_MODE_PUSH_PULL); // VOUTEN (IOX.3.3) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[8 + 5]), false, DRIVE_MODE_PUSH_PULL); // QI_ENABLE_5W (IOX.3.5) + + // Initialize SD card + // V3/V3-E uses single-line SD (sd1 mode), not 4-line (sd4 mode) like Mini + sdmmc.base.type = &sdioio_SDCard_type; + const mcu_pin_obj_t *data_pins[1] = {MP_ROM_PTR(&pin_GPIO2)}; + common_hal_sdioio_sdcard_construct(&sdmmc, MP_ROM_PTR(&pin_GPIO14), MP_ROM_PTR(&pin_GPIO15), 1, data_pins, 25 * 1000000); + + fs_user_mount_t *vfs = &_sdcard_usermount; + vfs->base.type = &mp_fat_vfs_type; + vfs->fatfs.drv = vfs; + + // Initialise underlying block device + vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to MP_BLOCKDEV_IOCTL_BLOCK_SIZE + mp_vfs_blockdev_init(&vfs->blockdev, &sdmmc); + + // mount the block device so the VFS methods can be used + FRESULT res = f_mount(&vfs->fatfs); + if (res != FR_OK) { + common_hal_sdioio_sdcard_deinit(&sdmmc); + return; + } + common_hal_sdioio_sdcard_never_reset(&sdmmc); + + filesystem_set_concurrent_write_protection(vfs, true); + filesystem_set_writable_by_usb(vfs, false); + + mp_vfs_mount_t *sdcard_vfs = &_sdcard_vfs; + sdcard_vfs->str = "/sd"; + sdcard_vfs->len = 3; + sdcard_vfs->obj = MP_OBJ_FROM_PTR(&_sdcard_usermount); + sdcard_vfs->next = MP_STATE_VM(vfs_mount_table); + MP_STATE_VM(vfs_mount_table) = sdcard_vfs; +} diff --git a/ports/espressif/boards/yoto_player_v3/board.h b/ports/espressif/boards/yoto_player_v3/board.h new file mode 100644 index 00000000000..1e40b62b047 --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/board.h @@ -0,0 +1,3 @@ +#include "py/obj.h" + +extern void board_set(qstr key, mp_obj_t value); diff --git a/ports/espressif/boards/yoto_player_v3/mpconfigboard.h b/ports/espressif/boards/yoto_player_v3/mpconfigboard.h new file mode 100644 index 00000000000..1660c4881f9 --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/mpconfigboard.h @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Yoto Player V3" +#define MICROPY_HW_MCU_NAME "ESP32" + +#define CIRCUITPY_MUTABLE_BOARD (1) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO25, .sda = &pin_GPIO21}} +#define CIRCUITPY_BOARD_I2C_SPEED (400000) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO23, .mosi = &pin_GPIO22, .miso = &pin_GPIO26}} + +#define CIRCUITPY_BOARD_UART (1) +#define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO17, .rx = &pin_GPIO16}} + +// UART pins attached to the USB-serial converter chip +#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) +#define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) diff --git a/ports/espressif/boards/yoto_player_v3/mpconfigboard.mk b/ports/espressif/boards/yoto_player_v3/mpconfigboard.mk new file mode 100644 index 00000000000..a1b940316c4 --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/mpconfigboard.mk @@ -0,0 +1,14 @@ +CIRCUITPY_CREATOR_ID = 0x40100000 +CIRCUITPY_CREATION_ID = 0x00320001 + +IDF_TARGET = esp32 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 40m + +CIRCUITPY_I2CIOEXPANDER = 1 diff --git a/ports/espressif/boards/yoto_player_v3/pins.c b/ports/espressif/boards/yoto_player_v3/pins.c new file mode 100644 index 00000000000..0862a020fdf --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/pins.c @@ -0,0 +1,104 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT +// + +#include "board.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static mp_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_MUTABLE_BOARD_DICT_STANDARD_ITEMS + + // External pins are in silkscreen order, from top to bottom, left side, then right side + // Encoder 1: V3-E uses GPIO26/13, V3 uses GPIO35/13 + { MP_ROM_QSTR(MP_QSTR_ENC1A), MP_OBJ_FROM_PTR(&pin_GPIO26) }, // V3-E: GPIO26, V3: GPIO35 + { MP_ROM_QSTR(MP_QSTR_ENC1A_V3), MP_OBJ_FROM_PTR(&pin_GPIO35) }, // V3-E: GPIO26, V3: GPIO35 + { MP_ROM_QSTR(MP_QSTR_ENC1B), MP_OBJ_FROM_PTR(&pin_GPIO13) }, + + // Encoder 2: Both V3 and V3-E use GPIO27/4 + { MP_ROM_QSTR(MP_QSTR_ENC2A), MP_OBJ_FROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_ENC2B), MP_OBJ_FROM_PTR(&pin_GPIO4) }, + + // Light sensor (V3/V3-E) + { MP_ROM_QSTR(MP_QSTR_LIGHT_SENSOR), MP_OBJ_FROM_PTR(&pin_GPIO36) }, + + // Temperature sensors (V3/V3-E) + { MP_ROM_QSTR(MP_QSTR_TEMP_SENSOR), MP_OBJ_FROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_QI_RX_TEMP_SENSOR), MP_OBJ_FROM_PTR(&pin_GPIO35) }, // V3-E only + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_OBJ_FROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_OBJ_FROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY_SCK), MP_OBJ_FROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_OBJ_FROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_MOSI), MP_OBJ_FROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_OBJ_FROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_MISO), MP_OBJ_FROM_PTR(&pin_GPIO26) }, // V3/V3-E have MISO + { MP_ROM_QSTR(MP_QSTR_MISO), MP_OBJ_FROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_NFC_IN), MP_OBJ_FROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_OBJ_FROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_NFC_OUT), MP_OBJ_FROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_OBJ_FROM_PTR(&pin_GPIO33) }, + + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_OBJ_FROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_OBJ_FROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BCLK), MP_OBJ_FROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_OBJ_FROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCLK), MP_OBJ_FROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DOUT), MP_OBJ_FROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER_INT), MP_OBJ_FROM_PTR(&pin_GPIO34) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_OBJ_FROM_PTR(&board_i2c_obj) }, + + // Filled in by board_init() + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER0), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER1), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_BATTERY_ALERT), mp_const_none }, // IOX.0.6 + { MP_ROM_QSTR(MP_QSTR_QI_STATUS), mp_const_none }, // IOX.0.7 + { MP_ROM_QSTR(MP_QSTR_USB_STATUS), mp_const_none }, // IOX.1.0 + { MP_ROM_QSTR(MP_QSTR_CHARGE_STATUS), mp_const_none }, // IOX.1.4 + { MP_ROM_QSTR(MP_QSTR_POWER_BUTTON), mp_const_none }, // IOX.1.3 + { MP_ROM_QSTR(MP_QSTR_ENC1_BUTTON), mp_const_none }, // IOX.0.5 + { MP_ROM_QSTR(MP_QSTR_ENC2_BUTTON), mp_const_none }, // IOX.0.4 + { MP_ROM_QSTR(MP_QSTR_HEADPHONE_DETECT), mp_const_none }, // IOX.1.1 + { MP_ROM_QSTR(MP_QSTR_PACTRL), mp_const_none }, // IOX.2.4 + // V3/V3-E use ht16d35x display with 4 CS lines + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS0), mp_const_none }, // IOX.2.0 + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS1), mp_const_none }, // IOX.2.1 + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS2), mp_const_none }, // IOX.2.2 + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS3), mp_const_none }, // IOX.2.3 + + { MP_ROM_QSTR(MP_QSTR_LEVEL_CONVERTER), mp_const_none }, // IOX.3.0 + { MP_ROM_QSTR(MP_QSTR_LEVEL_POWER_ENABLE), mp_const_none }, // IOX.2.5 + { MP_ROM_QSTR(MP_QSTR_LEVEL_VINHOLD), mp_const_none }, // IOX.3.1 + { MP_ROM_QSTR(MP_QSTR_LEVEL_VOUTEN), mp_const_none }, // IOX.3.3 + + { MP_ROM_QSTR(MP_QSTR_TILT), mp_const_none }, // IOX.1.2 + { MP_ROM_QSTR(MP_QSTR_RTC_INT), mp_const_none }, // IOX.0.1 + + // Qi charging pins (V3-E) + { MP_ROM_QSTR(MP_QSTR_QI_CHARGE_ENABLE), mp_const_none }, // IOX.2.6 + { MP_ROM_QSTR(MP_QSTR_QI_ENABLE_5W), mp_const_none }, // IOX.3.5 + { MP_ROM_QSTR(MP_QSTR_QI_I2C_INT), mp_const_none }, // IOX.0.0 + + // USB-C charging pins (V3/V3-E) + { MP_ROM_QSTR(MP_QSTR_USB_CHARGE_ENABLE), mp_const_none }, // IOX.2.7 + +}; +MP_DEFINE_MUTABLE_DICT(board_module_globals, board_module_globals_table); + +void board_set(qstr q, mp_obj_t value) { + mp_obj_t key = MP_OBJ_NEW_QSTR(q); + for (size_t i = 0; i < MP_ARRAY_SIZE(board_module_globals_table); i++) { + if (board_module_globals_table[i].key == key) { + board_module_globals_table[i].value = value; + return; + } + } +} diff --git a/tests/feature_check/const.py.exp b/ports/espressif/boards/yoto_player_v3/sdkconfig similarity index 100% rename from tests/feature_check/const.py.exp rename to ports/espressif/boards/yoto_player_v3/sdkconfig diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index f604e02c200..34122a1048c 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -31,8 +31,9 @@ #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" #include "host/ble_gap.h" +#include "host/ble_gatt.h" +#include "host/ble_sm.h" #include "host/util/util.h" -#include "services/ans/ble_svc_ans.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" @@ -44,10 +45,6 @@ #include "esp_nimble_hci.h" #include "nvs_flash.h" -#if CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" -#endif - // Status variables used while busy-waiting for events. static volatile bool _nimble_sync; static volatile int _connection_status; @@ -61,7 +58,7 @@ static void nimble_host_task(void *param) { static void _on_sync(void) { - int rc = ble_hs_util_ensure_addr(false); + int rc __attribute__((unused)) = ble_hs_util_ensure_addr(false); assert(rc == 0); _nimble_sync = true; @@ -70,7 +67,60 @@ static void _on_sync(void) { // All examples have this. It'd make sense in a header. void ble_store_config_init(void); -char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0, 0, 0, 0}; +// NimBLE sizes its client characteristic configuration (CCCD) pool once, in +// ble_gatts_start(), from the services counted by ble_gatts_count_cfg(). +// But every CircuitPython service is registered afterwards, using +// ble_gatts_add_dynamic_svcs(), which does not do its own counting, +// and does not resize the CCCD pool. +// +// So services added at runtime get no CCCDs of their own added to the pool. +// The CCCDs themselves can allocate on the NimBLE heap if needed, +// but ble_gatts_conn_can_alloc() still tests the CCCD pool size, and NimBLE refuses +// connectable advertising once the pool is empty. This is an oversight in the API. +// NimBLE returns BLE_HS_ENOMEM, which is reported as a MemoryError from +// start_advertising() as soon as the BLE workflow, a user service, and a +// connection together need more CCCDs than the built-in services reserved. +// +// To get around this, we'll make the CCCD pool larger, by calling ble_gatts_count_cfg() +// on a bulky dummy service that is never registered, just to force the pool to a +// good size. Two of the reserved CCCDs cover the BLE workflow's own notifying +// characteristics; the rest are for user services. +#define RESERVED_CCCD_COUNT (18) + +// Never called: the definition below is counted, not registered. NimBLE only +// requires that the callback not be NULL. +static int _reserved_cccd_access_cb(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) { + return BLE_ATT_ERR_UNLIKELY; +} + +// Likewise unused, but must not be NULL. +static const ble_uuid16_t _reserved_cccd_uuid = BLE_UUID16_INIT(0xffff); + +// Reserve CCCDs for the services registered at runtime. NimBLE needs one CCCD +// per subscribable characteristic per connection, plus one for its cache; +// ble_gatts_count_cfg() applies that multiplier itself. +// +// Call this before nimble_port_freertos_init(): ble_gatts_start() sizes the pool +// on the nimble_host task, and counting afterwards is too late. +static void _reserve_cccds(void) { + // ble_gatts_count_cfg() only reads these definitions and keeps no pointers + // into them, so they can live on the stack and then be discarded. + struct ble_gatt_chr_def chr_defs[RESERVED_CCCD_COUNT + 1] = { 0 }; + for (size_t i = 0; i < RESERVED_CCCD_COUNT; i++) { + chr_defs[i].uuid = &_reserved_cccd_uuid.u; + chr_defs[i].access_cb = _reserved_cccd_access_cb; + // Only NOTIFY or INDICATE characteristics get a CCCD. + chr_defs[i].flags = BLE_GATT_CHR_F_NOTIFY; + } + + struct ble_gatt_svc_def svc_defs[2] = { 0 }; + svc_defs[0].type = BLE_GATT_SVC_TYPE_PRIMARY; + svc_defs[0].uuid = &_reserved_cccd_uuid.u; + svc_defs[0].characteristics = chr_defs; + + CHECK_NIMBLE_ERROR(ble_gatts_count_cfg(svc_defs)); +} void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { const bool is_enabled = common_hal_bleio_adapter_get_enabled(self); @@ -96,35 +146,21 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC; ble_hs_cfg.sm_mitm = 0; - ble_hs_cfg.sm_sc = 0; + // LE Secure Connections is always offered. It's negotiated per pairing (a peer + // that only does legacy pairing still works) and is strictly better crypto, so + // there's no downside for existing "Just Works" users. Numeric-comparison pairing + // needs it. IO capability and the MITM requirement stay at the legacy defaults + // above until an attribute is constructed with a *_WITH_MITM permission, which + // raises them - see bleio_adapter_enable_mitm_pairing(). + ble_hs_cfg.sm_sc = 1; /* Stores the IRK */ ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ID; ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ID; ble_svc_gap_init(); ble_svc_gatt_init(); - ble_svc_ans_init(); - - #if CIRCUITPY_OS_GETENV - char ble_name[1 + MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH]; - os_getenv_err_t result = common_hal_os_getenv_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); - if (result == GETENV_OK) { - ble_svc_gap_device_name_set(ble_name); - } else - #endif - { - uint8_t mac[6]; - esp_read_mac(mac, ESP_MAC_BT); - mp_int_t len = sizeof(default_ble_name) - 1; - default_ble_name[len - 6] = nibble_to_hex_lower[mac[3] >> 4 & 0xf]; - default_ble_name[len - 5] = nibble_to_hex_lower[mac[3] & 0xf]; - default_ble_name[len - 4] = nibble_to_hex_lower[mac[4] >> 4 & 0xf]; - default_ble_name[len - 3] = nibble_to_hex_lower[mac[4] & 0xf]; - default_ble_name[len - 2] = nibble_to_hex_lower[mac[5] >> 4 & 0xf]; - default_ble_name[len - 1] = nibble_to_hex_lower[mac[5] & 0xf]; - default_ble_name[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings - ble_svc_gap_device_name_set(default_ble_name); - } + // Grow the CCCD pool so it's not too small. + _reserve_cccds(); // Clear all of the internal connection objects. for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { @@ -150,6 +186,8 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable if (!_nimble_sync) { mp_raise_RuntimeError(MP_ERROR_TEXT("Update failed")); } + + bleio_adapter_reset_name(self); } else { int ret = nimble_port_stop(); while (xTaskGetHandle("nimble_host") != NULL && !mp_hal_is_interrupted()) { @@ -166,6 +204,15 @@ bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { return xTaskGetHandle("nimble_host") != NULL; } +void bleio_adapter_enable_mitm_pairing(void) { + // ble_hs_cfg is a plain global read by the SM code at pairing time, so bumping it + // here (from Characteristic / Descriptor construction, after the adapter is up) takes + // effect for every subsequent pairing. Idempotent and one-way for the lifetime of + // the adapter - a characteristic that needs authentication doesn't stop needing it. + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_YES_NO; + ble_hs_cfg.sm_mitm = 1; +} + bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { uint8_t address_bytes[6]; uint8_t address_type = BLE_ADDR_RANDOM; @@ -175,20 +222,17 @@ bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *s return NULL; } - bleio_address_obj_t *address = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - common_hal_bleio_address_construct(address, address_bytes, BLEIO_ADDRESS_TYPE_RANDOM_STATIC); - return address; + // The cached address is refreshed on every call. + common_hal_bleio_address_construct(&self->address, address_bytes, BLEIO_ADDRESS_TYPE_RANDOM_STATIC); + self->address.base.type = &bleio_address_type; + return &self->address; } bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { if (address->type != BLEIO_ADDRESS_TYPE_RANDOM_STATIC) { return false; } - mp_buffer_info_t bufinfo; - if (!mp_get_buffer(address->bytes, &bufinfo, MP_BUFFER_READ)) { - return false; - } - int result = ble_hs_id_set_rnd(bufinfo.buf); + int result = ble_hs_id_set_rnd(address->bytes); return result == 0; } @@ -318,9 +362,7 @@ void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { static void _convert_address(const bleio_address_obj_t *address, ble_addr_t *nimble_address) { nimble_address->type = address->type; - mp_buffer_info_t address_buf_info; - mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); - memcpy(nimble_address->val, (uint8_t *)address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES); + memcpy(nimble_address->val, address->bytes, NUM_BLEIO_ADDRESS_BYTES); } static int _mtu_reply(uint16_t conn_handle, @@ -339,7 +381,7 @@ static int _mtu_reply(uint16_t conn_handle, return 0; } -static void _new_connection(uint16_t conn_handle) { +static void _new_connection(uint16_t conn_handle, bool user_owned) { // Set the tx_power for the connection higher than the advertisement. esp_ble_tx_power_set(conn_handle, ESP_PWR_LVL_N0); @@ -361,7 +403,9 @@ static void _new_connection(uint16_t conn_handle) { connection->conn_handle = conn_handle; connection->connection_obj = mp_const_none; connection->pair_status = PAIR_NOT_PAIRED; + connection->indicate_outstanding = false; connection->mtu = 0; + connection->user_owned = user_owned; ble_gattc_exchange_mtu(conn_handle, _mtu_reply, connection); @@ -379,12 +423,13 @@ static int _connect_event(struct ble_gap_event *event, void *self_in) { case BLE_GAP_EVENT_CONNECT: if (event->connect.status == 0) { // This triggers an MTU exchange. Its reply will exit the loop waiting for a connection. - _new_connection(event->connect.conn_handle); + // Only user code connects in the central role. + _new_connection(event->connect.conn_handle, true); // Set connections objs back to NULL since we have a new // connection and need a new tuple. self->connection_objs = NULL; } else { - // The loop waiting for the connection to be comnpleted will stop when _connection_status changes. + // The loop waiting for the connection to be completed will stop when _connection_status changes. _connection_status = -event->connect.status; } break; @@ -498,7 +543,8 @@ static int _advertising_event(struct ble_gap_event *event, void *self_in) { #if !MYNEWT_VAL(BLE_EXT_ADV) if (event->connect.status == NIMBLE_OK) { - _new_connection(event->connect.conn_handle); + // The connection belongs to whoever started the advertising it answered. + _new_connection(event->connect.conn_handle, self->user_advertising); // Set connections objs back to NULL since we have a new // connection and need a new tuple. self->connection_objs = NULL; @@ -511,7 +557,8 @@ static int _advertising_event(struct ble_gap_event *event, void *self_in) { case BLE_GAP_EVENT_ADV_COMPLETE: #if MYNEWT_VAL(BLE_EXT_ADV) if (event->adv_complete.reason == NIMBLE_OK) { - _new_connection(event->adv_complete.conn_handle); + // The connection belongs to whoever started the advertising it answered. + _new_connection(event->adv_complete.conn_handle, self->user_advertising); // Set connections objs back to NULL since we have a new // connection and need a new tuple. self->connection_objs = NULL; @@ -561,10 +608,6 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool high_duty_directed = directed_to != NULL && interval <= 3.5 && timeout <= 1; // Really 1.3, but it's an int uint32_t timeout_ms = timeout * 1000; - if (timeout_ms == 0) { - timeout_ms = BLE_HS_FOREVER; - } - #if MYNEWT_VAL(BLE_EXT_ADV) bool extended = advertising_data_len > BLE_ADV_LEGACY_DATA_MAX_LEN || @@ -626,8 +669,12 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, } } + // If timeout_ms is zero, it means advertise forever. This is different than ble_gap_adv_start(). rc = ble_gap_ext_adv_start(0, timeout_ms, 0); + #else + // Extended advertising not enabled. + uint8_t conn_mode = connectable ? BLE_GAP_CONN_MODE_UND : BLE_GAP_CONN_MODE_NON; if (directed_to != NULL) { conn_mode = BLE_GAP_CONN_MODE_DIR; @@ -654,8 +701,10 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, return rc; } } - rc = ble_gap_adv_start(own_addr_type, directed_to != NULL ? &peer: NULL, - timeout_ms, + // If timeout_ms is BLE_HS_FOREVER, it means advertise forever. This is different than ble_gap_ext_adv_start(). + rc = ble_gap_adv_start(own_addr_type, + directed_to != NULL ? &peer: NULL, + timeout_ms == 0 ? BLE_HS_FOREVER : timeout_ms, &adv_params, _advertising_event, self); #endif @@ -733,13 +782,13 @@ void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { } bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { - return ble_gap_adv_active(); + return common_hal_bleio_adapter_get_enabled(self) && ble_gap_adv_active(); } bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; - if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->mtu != 0) { + if (connection->conn_handle != BLEIO_HANDLE_INVALID) { return true; } } @@ -754,7 +803,7 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) { mp_obj_t items[BLEIO_TOTAL_CONNECTION_COUNT]; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; - if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->mtu != 0) { + if (connection->conn_handle != BLEIO_HANDLE_INVALID) { if (connection->connection_obj == mp_const_none) { connection->connection_obj = bleio_connection_new_from_internal(connection); } @@ -817,10 +866,11 @@ void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) { } void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { - common_hal_bleio_adapter_stop_scan(adapter); - if (common_hal_bleio_adapter_get_advertising(adapter)) { - common_hal_bleio_adapter_stop_advertising(adapter); + if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + return; } + common_hal_bleio_adapter_stop_scan(adapter); + common_hal_bleio_adapter_stop_advertising(adapter); adapter->connection_objs = NULL; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { @@ -834,13 +884,13 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { // Wait up to 125 ms (128 ticks) for disconnect to complete. This should be // greater than most connection intervals. - bool any_connected = false; + bool any_connected; uint64_t start_ticks = supervisor_ticks_ms64(); - while (any_connected && supervisor_ticks_ms64() - start_ticks < 128) { + do { any_connected = false; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; any_connected |= connection->conn_handle != BLEIO_HANDLE_INVALID; } - } + } while (any_connected && supervisor_ticks_ms64() - start_ticks < 128); } diff --git a/ports/espressif/common-hal/_bleio/Adapter.h b/ports/espressif/common-hal/_bleio/Adapter.h index 1dbae9946ee..31bd853f2b4 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.h +++ b/ports/espressif/common-hal/_bleio/Adapter.h @@ -11,14 +11,19 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" #include "supervisor/background_callback.h" +#include "sdkconfig.h" + #ifndef BLEIO_TOTAL_CONNECTION_COUNT -#define BLEIO_TOTAL_CONNECTION_COUNT 5 +#define BLEIO_TOTAL_CONNECTION_COUNT CONFIG_BT_NIMBLE_MAX_CONNECTIONS #endif +// Do not allow more connections than NimBLE was configured for. +MP_STATIC_ASSERT(BLEIO_TOTAL_CONNECTION_COUNT <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS); #define BLEIO_HANDLE_INVALID 0xffff @@ -31,7 +36,18 @@ typedef struct { mp_obj_tuple_t *connection_objs; background_callback_t background_callback; bool user_advertising; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; } bleio_adapter_obj_t; void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); void bleio_adapter_reset(bleio_adapter_obj_t *adapter); + +// Raise the SM pairing configuration so an authenticated (MITM-protected) bond can be +// formed: advertise DISPLAY_YESNO IO capability and require MITM. Called from +// Characteristic / Descriptor construction when an attribute is given a *_WITH_MITM +// permission. A no-op-safe idempotent bump; devices with no such attribute keep the +// legacy "Just Works" defaults set in common_hal_bleio_adapter_set_enabled(). +void bleio_adapter_enable_mitm_pairing(void); diff --git a/ports/espressif/common-hal/_bleio/Characteristic.c b/ports/espressif/common-hal/_bleio/Characteristic.c index 805c6d160f3..6ea78629569 100644 --- a/ports/espressif/common-hal/_bleio/Characteristic.c +++ b/ports/espressif/common-hal/_bleio/Characteristic.c @@ -23,6 +23,98 @@ static int characteristic_on_ble_gap_evt(struct ble_gap_event *event, void *param); +// A local characteristic that can notify or indicate registers an event handler +// whose storage is the characteristic object itself. NimBLE's GATT table +// holds a pointer to the object as its access-callback arg. Both stay valid +// because the characteristic's Service is retained while NimBLE knows about +// it, and the Service holds its characteristics; see Service.c. + +// Remember or forget a peer's subscription. NimBLE reports cur_notify and +// cur_indicate both clear when the peer writes zero to the CCCD and when the +// connection ends, so this handles disconnects too. +static void characteristic_set_subscription(bleio_characteristic_obj_t *self, + uint16_t conn_handle, bool notify, bool indicate) { + size_t free_slot = BLEIO_TOTAL_CONNECTION_COUNT; + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (self->subscribers[i].conn_handle == conn_handle) { + if (notify || indicate) { + self->subscribers[i].notify = notify; + self->subscribers[i].indicate = indicate; + } else { + self->subscribers[i].conn_handle = BLEIO_HANDLE_INVALID; + } + return; + } + if (free_slot == BLEIO_TOTAL_CONNECTION_COUNT && + self->subscribers[i].conn_handle == BLEIO_HANDLE_INVALID) { + free_slot = i; + } + } + if ((notify || indicate) && free_slot < BLEIO_TOTAL_CONNECTION_COUNT) { + self->subscribers[free_slot].conn_handle = conn_handle; + self->subscribers[free_slot].notify = notify; + self->subscribers[free_slot].indicate = indicate; + } +} + +// Send one notification or indication. The send may return BLE_HS_ENOMEM, which +// could mean an empty mbuf pool or exhausted controller buffers. +// Both are transient and go away once the radio finishes sending other +// data, so wait them out instead of losing the value. +// NimBLE consumes the mbuf even when the send fails, so we need to build +// a fresh one for each attempt. +// The retry makes progress even from a background callback, +// because the draining is done by the nimble_host task, not by background callbacks. +static void characteristic_notify_indicate(bleio_characteristic_obj_t *self, + uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool indicate) { + while (!mp_hal_is_interrupted()) { + struct os_mbuf *om = ble_hs_mbuf_from_flat(bufinfo->buf, bufinfo->len); + if (om != NULL) { + bleio_connection_internal_t *connection = NULL; + if (indicate) { + // NimBLE allows only one outstanding indication per connection and + // does not check in ble_gatts_indicate_custom(): a second one + // trips BLE_HS_DBG_ASSERT and corrupts the acknowledgment + // bookkeeping, so don't send a second one. + // Wait for the previous acknowledgment. + connection = bleio_conn_handle_to_connection(conn_handle); + if (connection == NULL) { + os_mbuf_free_chain(om); + return; + } + while (connection->indicate_outstanding && + connection->conn_handle == conn_handle && + !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + } + if (connection->conn_handle != conn_handle || mp_hal_is_interrupted()) { + os_mbuf_free_chain(om); + return; + } + // Set before submitting: the acknowledgment can preempt this + // task the moment the indication is on the air. + connection->indicate_outstanding = true; + } + const int rc = indicate + ? ble_gatts_indicate_custom(conn_handle, self->handle, om) + : ble_gatts_notify_custom(conn_handle, self->handle, om); + if (indicate && rc != NIMBLE_OK) { + // Never submitted, so no acknowledgment will clear it. + connection->indicate_outstanding = false; + } + if (rc == NIMBLE_OK) { + return; + } + if (rc != BLE_HS_ENOMEM) { + // Not a transient memory shortage. The peer is gone, or refused. + // These failures are not reported back to Python. + return; + } + } + RUN_BACKGROUND_TASKS; + } +} + void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, @@ -33,6 +125,9 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->handle = BLEIO_HANDLE_INVALID; self->cccd_handle = BLEIO_HANDLE_INVALID; self->sccd_handle = BLEIO_HANDLE_INVALID; + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + self->subscribers[i].conn_handle = BLEIO_HANDLE_INVALID; + } self->props = props; self->read_perm = read_perm; self->write_perm = write_perm; @@ -58,22 +153,37 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, if ((props & CHAR_PROP_WRITE_NO_RESPONSE) != 0) { self->flags |= BLE_GATT_CHR_F_WRITE_NO_RSP; } - if (read_perm == SECURITY_MODE_ENC_WITH_MITM || write_perm == SECURITY_MODE_ENC_WITH_MITM || - read_perm == SECURITY_MODE_SIGNED_WITH_MITM || write_perm == SECURITY_MODE_SIGNED_WITH_MITM) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("MITM security not supported")); - } + // The BLE_GATT_CHR_F_NOTIFY_INDICATE_* flags are set below to require encryption or + // authentication when writing the auto-generated CCCD, if reading the + // characteristic requires it. This matches the nordic port behavior. + // Without the flags, NimBLE registers the CCCD as writable on an unencrypted link, + // so an unpaired central can subscribe and nothing ever requires it to pair. + // + // TODO: This behavior was fixed in NimBLE 1.10.0. ESP-IDF 6.0.1 uses a fork of NimBLE. + // + // NimBLE's GATT layer has no dedicated "LESC" or "signed" characteristic flag: + // ENC_WITH_MITM, LESC_ENC_WITH_MITM and the SIGNED modes all map to the _AUTHEN + // flags, i.e. "require a man-in-the-middle-protected link". A *_WITH_MITM permission + // additionally makes the adapter offer numeric-comparison pairing (below) so such a + // link can actually be established. if (read_perm == SECURITY_MODE_ENC_NO_MITM) { - self->flags |= BLE_GATT_CHR_F_READ_ENC; + self->flags |= BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY_INDICATE_ENC; } - if (read_perm == SECURITY_MODE_SIGNED_NO_MITM) { - self->flags |= BLE_GATT_CHR_F_READ_AUTHEN; + if (read_perm == SECURITY_MODE_ENC_WITH_MITM || read_perm == SECURITY_MODE_LESC_ENC_WITH_MITM || + read_perm == SECURITY_MODE_SIGNED_NO_MITM || read_perm == SECURITY_MODE_SIGNED_WITH_MITM) { + self->flags |= BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY_INDICATE_AUTHEN; } if (write_perm == SECURITY_MODE_ENC_NO_MITM) { self->flags |= BLE_GATT_CHR_F_WRITE_ENC; } - if (write_perm == SECURITY_MODE_SIGNED_NO_MITM) { + if (write_perm == SECURITY_MODE_ENC_WITH_MITM || write_perm == SECURITY_MODE_LESC_ENC_WITH_MITM || + write_perm == SECURITY_MODE_SIGNED_NO_MITM || write_perm == SECURITY_MODE_SIGNED_WITH_MITM) { self->flags |= BLE_GATT_CHR_F_WRITE_AUTHEN; } + if (bleio_attribute_security_mode_requires_mitm(read_perm) || + bleio_attribute_security_mode_requires_mitm(write_perm)) { + bleio_adapter_enable_mitm_pairing(); + } // If max_length is 0, then no storage is allocated. if (max_length > 0) { @@ -92,7 +202,7 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->max_length = max_length; self->fixed_length = fixed_length; - if (initial_value_bufinfo != NULL) { + if (!service->is_remote && initial_value_bufinfo != NULL) { common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo); } @@ -108,6 +218,11 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, ble_event_add_handler_entry(&self->event_handler_entry, characteristic_on_ble_gap_evt, self); } else { common_hal_bleio_service_add_characteristic(self->service, self, initial_value_bufinfo, user_description); + if ((props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) != 0) { + // Remember who subscribes: BLE_GAP_EVENT_SUBSCRIBE is the only report + // of that, and set_value() notifies subscribers and no one else. + ble_event_add_handler_entry(&self->event_handler_entry, characteristic_on_ble_gap_evt, self); + } } } @@ -119,6 +234,12 @@ void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) { if (common_hal_bleio_characteristic_deinited(self)) { return; } + // Take the characteristic off the event list before cleaning up the object. + ble_event_remove_handler(characteristic_on_ble_gap_evt, self); + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + self->subscribers[i].conn_handle = BLEIO_HANDLE_INVALID; + } + if (self->current_value != NULL) { if (gc_ptr_on_heap(self->current_value)) { m_free(self->current_value); @@ -193,7 +314,25 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, self->current_value_len = bufinfo->len; memcpy(self->current_value, bufinfo->buf, self->current_value_len); - ble_gatts_chr_updated(self->handle); + // Notify and indicate subscribers here rather than by using + // ble_gatts_chr_updated(). That function cannot report a failed send, + // so we can't tell whether we succeeded or not. + // + // Unlike ble_gatts_chr_updated(), this does not persist a "changed" + // flag for bonded peers that are currently disconnected, so they are + // not notified on reconnect. This matches the nordic port. + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + const uint16_t conn_handle = self->subscribers[i].conn_handle; + if (conn_handle == BLEIO_HANDLE_INVALID) { + continue; + } + if (self->subscribers[i].notify && (self->props & CHAR_PROP_NOTIFY) != 0) { + characteristic_notify_indicate(self, conn_handle, bufinfo, false); + } + if (self->subscribers[i].indicate && (self->props & CHAR_PROP_INDICATE) != 0) { + characteristic_notify_indicate(self, conn_handle, bufinfo, true); + } + } } } @@ -225,7 +364,26 @@ static int characteristic_on_ble_gap_evt(struct ble_gap_event *event, void *para } break; } + case BLE_GAP_EVENT_NOTIFY_TX: + // For indications only: BLE_HS_EDONE is the peer's acknowledgment + // and BLE_HS_ETIMEOUT is the stack giving up on getting one. Either way, + // the connection's single indication slot is free again. + if (event->notify_tx.indication != 0 && + event->notify_tx.attr_handle == self->handle && + (event->notify_tx.status == BLE_HS_EDONE || + event->notify_tx.status == BLE_HS_ETIMEOUT)) { + bleio_connection_internal_t *connection = + bleio_conn_handle_to_connection(event->notify_tx.conn_handle); + if (connection != NULL) { + connection->indicate_outstanding = false; + } + } + break; case BLE_GAP_EVENT_SUBSCRIBE: + if (event->subscribe.attr_handle == self->handle) { + characteristic_set_subscription(self, event->subscribe.conn_handle, + event->subscribe.cur_notify != 0, event->subscribe.cur_indicate != 0); + } break; default: return 0; @@ -293,7 +451,7 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * bleio_descriptor_obj_t *descriptor) { size_t i = self->descriptor_list->len; if (i >= MAX_DESCRIPTORS) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Too many descriptors")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Too many %q"), MP_QSTR_descriptors); } mp_obj_list_append(MP_OBJ_FROM_PTR(self->descriptor_list), @@ -320,7 +478,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, } const uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); - common_hal_bleio_check_connected(conn_handle); + bleio_check_connected(conn_handle); uint16_t cccd_value = (notify ? 1 << 0 : 0) | diff --git a/ports/espressif/common-hal/_bleio/Characteristic.h b/ports/espressif/common-hal/_bleio/Characteristic.h index 1ae32e9ddd8..e820b47015b 100644 --- a/ports/espressif/common-hal/_bleio/Characteristic.h +++ b/ports/espressif/common-hal/_bleio/Characteristic.h @@ -10,6 +10,7 @@ #include "shared-bindings/_bleio/Attribute.h" #include "common-hal/_bleio/Descriptor.h" #include "shared-module/_bleio/Characteristic.h" +#include "common-hal/_bleio/Adapter.h" #include "common-hal/_bleio/ble_events.h" #include "common-hal/_bleio/Service.h" #include "common-hal/_bleio/UUID.h" @@ -40,6 +41,18 @@ typedef struct _bleio_characteristic_obj { uint16_t user_desc_handle; uint16_t cccd_handle; uint16_t sccd_handle; + // Track currently subscribed peers. NimBLE in the current ESP-IDF offers + // no way to read a peer's CCCD, and notifying without checking would + // send to peers that never asked. NimBLE reports subscriptions with both + // flags clear on CCCD clears and on disconnect, so entries free themselves. + // One subscription per connection at most, hence BLEIO_TOTAL_CONNECTION_COUNT. + // TODO when NimBLE is updated to 1.9.0 or later: ble_gatts_read_cccd() + // reads the CCCD directly, and this table can go away. + struct { + uint16_t conn_handle; + bool notify; + bool indicate; + } subscribers[BLEIO_TOTAL_CONNECTION_COUNT]; ble_event_handler_entry_t event_handler_entry; // The actual structure is managed by the service because it needs to have // an array. diff --git a/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c b/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c index 3c0cbf323f3..2f34666420b 100644 --- a/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c +++ b/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c @@ -16,12 +16,19 @@ #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/CharacteristicBuffer.h" +#include "shared-bindings/microcontroller/__init__.h" #include "supervisor/shared/tick.h" #include "common-hal/_bleio/ble_events.h" +// The ringbuf is filled from the nimble_host task, which preempts the VM task +// at arbitrary points, and ringbuf operations are not atomic, so guard them +// with interrupts disabled. + +// Runs on the nimble_host task. void bleio_characteristic_buffer_extend(bleio_characteristic_buffer_obj_t *self, const uint8_t *data, size_t len) { + common_hal_mcu_disable_interrupts(); if (self->watch_for_interrupt_char) { for (uint16_t i = 0; i < len; i++) { if (data[i] == mp_interrupt_char) { @@ -34,6 +41,7 @@ void bleio_characteristic_buffer_extend(bleio_characteristic_buffer_obj_t *self, } else { ringbuf_put_n(&self->ringbuf, data, len); } + common_hal_mcu_enable_interrupts(); } void _common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, @@ -70,20 +78,23 @@ uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer } } + common_hal_mcu_disable_interrupts(); uint32_t num_bytes_read = ringbuf_get_n(&self->ringbuf, data, len); + common_hal_mcu_enable_interrupts(); return num_bytes_read; } -// NOTE: The nRF port has protection around these operations because the ringbuf -// is filled from an interrupt. On ESP the ringbuf is filled from the BLE host -// task that won't interrupt us. - uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) { - return ringbuf_num_filled(&self->ringbuf); + common_hal_mcu_disable_interrupts(); + uint32_t count = ringbuf_num_filled(&self->ringbuf); + common_hal_mcu_enable_interrupts(); + return count; } void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) { + common_hal_mcu_disable_interrupts(); ringbuf_clear(&self->ringbuf); + common_hal_mcu_enable_interrupts(); } bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 8c88bfe3ec5..ff8a4402001 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -30,7 +30,12 @@ #include "common-hal/_bleio/ble_events.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" + #include "host/ble_att.h" +#include "host/ble_sm.h" +#include "host/ble_store.h" // Uncomment to turn on debug logging just in this file. // #undef CIRCUITPY_VERBOSE_BLE @@ -43,6 +48,7 @@ int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in) case BLE_GAP_EVENT_DISCONNECT: { connection->conn_handle = BLEIO_HANDLE_INVALID; connection->pair_status = PAIR_NOT_PAIRED; + connection->mitm_protected = false; #if CIRCUITPY_VERBOSE_BLE mp_printf(&mp_plat_print, "event->disconnect.reason: 0x%x\n", event->disconnect.reason); @@ -65,7 +71,7 @@ int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in) case BLE_GAP_EVENT_CONN_UPDATE: { struct ble_gap_conn_desc desc; - int rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); + int rc __attribute__((unused)) = ble_gap_conn_find(event->conn_update.conn_handle, &desc); assert(rc == 0); connection->conn_params_updating = false; break; @@ -75,9 +81,53 @@ int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in) ble_gap_conn_find(event->enc_change.conn_handle, &desc); if (desc.sec_state.encrypted) { connection->pair_status = PAIR_PAIRED; + } else if (connection->pair_status == PAIR_WAITING_NUMCMP) { + // Numeric comparison was rejected, or SM otherwise failed. + connection->pair_status = PAIR_NOT_PAIRED; } + // .authenticated is set once the MITM leg (numeric comparison / passkey entry) + // completes; a plain "Just Works" bond leaves it clear. Surfaced as + // Connection.authenticated. + connection->mitm_protected = desc.sec_state.authenticated; break; } + case BLE_GAP_EVENT_PASSKEY_ACTION: { + // The peer started MITM pairing. An attribute was constructed with a + // *_WITH_MITM permission, which made the adapter advertise DISPLAY_YESNO IO + // capability (bleio_adapter_enable_mitm_pairing()), so NimBLE asks us to + // confirm a 6-digit numeric-comparison value. Stash it and enter + // PAIR_WAITING_NUMCMP; Python reads it via Connection.numeric_comparison + // and answers with confirm_pairing(). + if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) { + connection->pairing_numcmp = event->passkey.params.numcmp; + connection->pair_status = PAIR_WAITING_NUMCMP; + } else { + // Passkey entry / OOB: a display + yes/no button can't service these. + // Fail fast instead of letting SM hang until its ~30 s timeout. + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "unsupported passkey action %d; terminating\n", + event->passkey.params.action); + #endif + ble_gap_terminate(event->passkey.conn_handle, BLE_ERR_AUTH_FAIL); + } + break; + } + case BLE_GAP_EVENT_REPEAT_PAIRING: { + // The peer is asking to pair even though we still have a bond with it. + // This means it no longer has its own copy of that bond. Discard our bond + // and tell the BLE stack to carry on pairing. Otherwise NimBLE silently + // ignores the request, and a central that has forgotten this device can + // never pair again without erasing the bonds on the board. The + // nordic port likewise replaces the stored keys when a peer re-pairs. + struct ble_gap_conn_desc desc; + if (ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc) != 0) { + return BLE_GAP_REPEAT_PAIRING_IGNORE; + } + ble_store_util_delete_peer(&desc.peer_id_addr); + // The BLE stack checks that the bond is really gone before retrying, and + // reports this event again if it is not. + return BLE_GAP_REPEAT_PAIRING_RETRY; + } case BLE_GAP_EVENT_MTU: { if (event->mtu.conn_handle != connection->conn_handle) { return 0; @@ -147,6 +197,40 @@ void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bo } } +// LE Secure Connections numeric comparison. Unlike pair(), these don't block: the peer +// (a central) drives the SM procedure; we just observe the pending value and inject the +// yes/no. BLE_GAP_EVENT_PASSKEY_ACTION sets pair_status = PAIR_WAITING_NUMCMP. +mp_obj_t common_hal_bleio_connection_get_numeric_comparison(bleio_connection_obj_t *self) { + if (self->connection == NULL || self->connection->pair_status != PAIR_WAITING_NUMCMP) { + return mp_const_none; + } + return mp_obj_new_int_from_uint(self->connection->pairing_numcmp); +} + +void common_hal_bleio_connection_confirm_pairing(bleio_connection_obj_t *self, bool accept) { + if (self->connection == NULL) { + mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected")); + } + if (self->connection->pair_status != PAIR_WAITING_NUMCMP) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("No pairing in progress")); + } + struct ble_sm_io io = { + .action = BLE_SM_IOACT_NUMCMP, + .numcmp_accept = accept, + }; + CHECK_NIMBLE_ERROR(ble_sm_inject_io(self->connection->conn_handle, &io)); + // SM proceeds from here. On accept, ENC_CHANGE moves us to PAIR_PAIRED; on reject it + // won't, so drop straight back to PAIR_NOT_PAIRED rather than waiting for the peer. + self->connection->pair_status = accept ? PAIR_WAITING : PAIR_NOT_PAIRED; +} + +bool common_hal_bleio_connection_get_authenticated(bleio_connection_obj_t *self) { + if (self->connection == NULL) { + return false; + } + return self->connection->mitm_protected; +} + mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) { while (self->conn_params_updating && !mp_hal_is_interrupted()) { RUN_BACKGROUND_TASKS; @@ -181,44 +265,148 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // Zero when discovery is in process. BLE_HS_EDONE or a BLE_HS_ error code when done. static volatile int _last_discovery_status; -static uint64_t _discovery_start_time; - -// Give 20 seconds for discovery +// Give 20 seconds for each step of discovery: services, characteristics, attributes. #define DISCOVERY_TIMEOUT_MS 20000 -static void _start_discovery_timeout(void) { - _discovery_start_time = common_hal_time_monotonic_ms(); +// Record result of last discovery step: services, characteristics, descriptors. +static void _set_discovery_step_status(int status) { + _last_discovery_status = status; } -static int _wait_for_discovery_step_done(void) { - const uint64_t timeout_time_ms = _discovery_start_time + DISCOVERY_TIMEOUT_MS; - while ((_last_discovery_status == 0) && (common_hal_time_monotonic_ms() < timeout_time_ms)) { - RUN_BACKGROUND_TASKS; - if (mp_hal_is_interrupted()) { - // Return prematurely. Then the interrupt will be raised. - _last_discovery_status = BLE_HS_EDONE; - } +static void _check_discovery_status(int status) { + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "discovery step status: %d\n", status); + #endif + + if (status == BLE_HS_EDONE) { + return; } - return _last_discovery_status; + if (status < BLE_HS_ERR_ATT_BASE) { + CHECK_NIMBLE_ERROR(status); + return; + } + CHECK_BLE_ERROR(status); } -// Record result of last discovery step: services, characteristics, descriptors. -static void _set_discovery_step_status(int status) { - _last_discovery_status = status; +// Raw discovery results are staged here by the NimBLE host-task callbacks. +// Those callbacks run on the "nimble_host" task, NOT the VM task, so they must +// not allocate from the MicroPython heap: an allocation there can trigger a +// gc_collect() that scans the wrong task's stack and frees the VM's live +// objects. Instead the callbacks copy the plain NimBLE result struct into this +// FreeRTOS queue, and the VM task drains it and builds the Python objects. +// +// Discovery is serialized (one discover_remote_services() at a time), so a +// single file-static queue suffices. It must hold one ATT-PDU burst of records: +// within a response PDU the host task invokes the callback repeatedly without +// yielding, so the VM task cannot drain until the next PDU's round-trip. The +// largest burst is a find-information response at the maximum ATT MTU we +// advertise (CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU, 256): about 64 descriptor +// records. The depth is twice that. +// +// The queue is created on first use from the FreeRTOS (IDF) heap, not the GC +// heap, so it needs no GC root and survives soft reloads: a stale procedure's +// sends always land in live memory. It is never deleted. + +// One queue item, sized to the largest record type, so one queue can serve every +// discovery step. +typedef union { + struct ble_gatt_svc svc; + struct ble_gatt_chr chr; + struct ble_gatt_dsc dsc; +} discovery_record_t; + +#define DISCOVERY_QUEUE_DEPTH (128) +static QueueHandle_t _discovery_queue; + +// Create the queue on first use, and empty it before a discovery step. Runs on +// the VM task. xQueueReset() is safe against a stale procedure from a previous +// errored, timed-out, or interrupted discovery that may still be sending +// records on the nimble_host task. +static void _reset_discovery_queue(void) { + if (_discovery_queue == NULL) { + _discovery_queue = xQueueCreate(DISCOVERY_QUEUE_DEPTH, sizeof(discovery_record_t)); + if (_discovery_queue == NULL) { + m_malloc_fail(DISCOVERY_QUEUE_DEPTH * sizeof(discovery_record_t)); + } + } + xQueueReset(_discovery_queue); } static int _discovered_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *svc, void *arg) { - bleio_connection_internal_t *self = (bleio_connection_internal_t *)arg; + if (error->status != 0) { + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_discovered_service_cb error->status: %d, handle: %d\n", + error->status, error->att_handle); + #endif + + // BLE_HS_EDONE or some error has occurred. + _set_discovery_step_status(error->status); + return 0; + } + + // Runs on the nimble_host task: stage the raw result only, never allocate. + discovery_record_t record = { .svc = *svc }; + if (xQueueSend(_discovery_queue, &record, 0) != pdTRUE) { + _set_discovery_step_status(BLE_HS_ENOMEM); + } + return 0; +} + +static int _discovered_characteristic_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, + void *arg) { + if (error->status != 0) { + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_discovered_characteristic_cb error->status: %d, handle: %d\n", + error->status, error->att_handle); + #endif + + // BLE_HS_EDONE or some error has occurred. + _set_discovery_step_status(error->status); + return 0; + } + // Runs on the nimble_host task: stage the raw result only, never allocate. + discovery_record_t record = { .chr = *chr }; + if (xQueueSend(_discovery_queue, &record, 0) != pdTRUE) { + _set_discovery_step_status(BLE_HS_ENOMEM); + } + return 0; +} + +static int _discovered_descriptor_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, + void *arg) { if (error->status != 0) { + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_discovered_descriptor_cb error->status: %d, handle: %d\n", + error->status, error->att_handle); + #endif + // BLE_HS_EDONE or some error has occurred. _set_discovery_step_status(error->status); return 0; } + // Runs on the nimble_host task: stage the raw result only, never allocate. + discovery_record_t record = { .dsc = *dsc }; + if (xQueueSend(_discovery_queue, &record, 0) != pdTRUE) { + _set_discovery_step_status(BLE_HS_ENOMEM); + } + return 0; +} + +// Build a Service object from a staged raw record. Runs on the VM task. +static void _build_service(void *ctx, const void *record) { + bleio_connection_internal_t *self = ctx; + const struct ble_gatt_svc *svc = record; + bleio_service_obj_t *service = mp_obj_malloc(bleio_service_obj_t, &bleio_service_type); // Initialize several fields at once. @@ -236,27 +424,53 @@ static int _discovered_service_cb(uint16_t conn_handle, mp_obj_list_append(MP_OBJ_FROM_PTR(self->remote_service_list), MP_OBJ_FROM_PTR(service)); - return 0; } -static int _discovered_characteristic_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_chr *chr, - void *arg) { - bleio_service_obj_t *service = (bleio_service_obj_t *)arg; - - if (error->status != 0) { - // BLE_HS_EDONE or some error has occurred. - _set_discovery_step_status(error->status); - return 0; +// Drain and build all staged records on the VM task, until the step completes +// and the queue is empty. build() is invoked for each raw record with ctx +// passed through. Returns the discovery step status. +static int _drain_records(void *ctx, + void (*build)(void *ctx, const void *record)) { + const uint64_t timeout_time_ms = common_hal_time_monotonic_ms() + DISCOVERY_TIMEOUT_MS; + discovery_record_t record; + while (true) { + if (xQueueReceive(_discovery_queue, &record, 0) == pdTRUE) { + build(ctx, &record); + continue; + } + // Queue is empty. + if (_last_discovery_status != 0) { + // On EDONE or a NimBLE error, the terminal callback has already + // run, so no more records will arrive: drain any that raced in, + // then stop. On ENOMEM (our own send failure) the procedure may + // still be running, but we are raising anyway; any later + // discovery resets the queue before reuse. + while (xQueueReceive(_discovery_queue, &record, 0) == pdTRUE) { + build(ctx, &record); + } + return _last_discovery_status; + } + if (common_hal_time_monotonic_ms() >= timeout_time_ms) { + return BLE_HS_ETIMEOUT; + } + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + // Return prematurely. Then the interrupt will be raised. + _set_discovery_step_status(BLE_HS_EDONE); + } } +} + +// Build a Characteristic object from a staged raw record. Runs on the VM task. +static void _build_characteristic(void *ctx, const void *record) { + bleio_service_obj_t *service = ctx; + const struct ble_gatt_chr *chr = record; bleio_characteristic_obj_t *characteristic = mp_obj_malloc(bleio_characteristic_obj_t, &bleio_characteristic_type); // Known characteristic UUID. bleio_uuid_obj_t *uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); - uuid->nimble_ble_uuid = chr->uuid; bleio_characteristic_properties_t props = @@ -281,32 +495,17 @@ static int _discovered_characteristic_cb(uint16_t conn_handle, characteristic->def_handle = chr->def_handle; #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "_discovered_characteristic_cb: char handle: %d\n", characteristic->handle); + mp_printf(&mp_plat_print, "_build_characteristic: char handle: %d\n", characteristic->handle); #endif mp_obj_list_append(MP_OBJ_FROM_PTR(service->characteristic_list), MP_OBJ_FROM_PTR(characteristic)); - return 0; } -static int _discovered_descriptor_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - uint16_t chr_val_handle, - const struct ble_gatt_dsc *dsc, - void *arg) { - bleio_characteristic_obj_t *characteristic = (bleio_characteristic_obj_t *)arg; - - if (error->status != 0) { - - #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "_discovered_descriptor_cb error->status: %d, handle: %d\n", - error->status, error->att_handle); - #endif - - // BLE_HS_EDONE or some error has occurred. - _set_discovery_step_status(error->status); - return 0; - } +// Build a Descriptor object from a staged raw record. Runs on the VM task. +static void _build_descriptor(void *ctx, const void *record) { + bleio_characteristic_obj_t *characteristic = ctx; + const struct ble_gatt_dsc *dsc = record; // Remember handles for certain well-known descriptors. switch (dsc->uuid.u16.value) { @@ -337,33 +536,28 @@ static int _discovered_descriptor_cb(uint16_t conn_handle, descriptor->handle = dsc->handle; #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "_discovered_descriptor_cb: char handle: %d, desc handle: %d, uuid type: %d, u16 value: 0x%x\n", + mp_printf(&mp_plat_print, "_build_descriptor: char handle: %d, desc handle: %d, uuid type: %d, u16 value: 0x%x\n", characteristic->handle, descriptor->handle, dsc->uuid.u.type, dsc->uuid.u16.value); #endif mp_obj_list_append(MP_OBJ_FROM_PTR(characteristic->descriptor_list), MP_OBJ_FROM_PTR(descriptor)); - return 0; } static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t service_uuids_whitelist) { // Start over with an empty list. self->remote_service_list = mp_obj_new_list(0, NULL); - // Start timeout in case discovery gets stuck. - _start_discovery_timeout(); - if (service_uuids_whitelist == mp_const_none) { - // Reset discovery status before starting callbacks + // Reset discovery status and staging queue before starting callbacks. _set_discovery_step_status(0); + _reset_discovery_queue(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_svcs(self->conn_handle, _discovered_service_cb, self)); - // Wait for _discovered_service_cb() to be called multiple times until it's done. - int status = _wait_for_discovery_step_done(); - if (status != BLE_HS_EDONE) { - CHECK_BLE_ERROR(status); - } + // Drain staged services and build them on the VM task until done. + int status = _drain_records(self, _build_service); + _check_discovery_status(status); } else { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); @@ -374,27 +568,26 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t } bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); - // Reset discovery status before starting callbacks + // Reset discovery status and staging queue before starting callbacks. _set_discovery_step_status(0); + _reset_discovery_queue(); CHECK_NIMBLE_ERROR(ble_gattc_disc_svc_by_uuid(self->conn_handle, &uuid->nimble_ble_uuid.u, _discovered_service_cb, self)); - // Wait for _discovered_service_cb() to be called multiple times until it's done. - int status = _wait_for_discovery_step_done(); - if (status != BLE_HS_EDONE) { - CHECK_BLE_ERROR(status); - } + // Drain staged services and build them on the VM task until done. + int status = _drain_records(self, _build_service); + _check_discovery_status(status); } } // Now discover characteristics for each discovered service. - for (size_t i = 0; i < self->remote_service_list->len; i++) { bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->remote_service_list->items[i]); - // Reset discovery status before starting callbacks + // Reset discovery status and staging queue before starting callbacks. _set_discovery_step_status(0); + _reset_discovery_queue(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_chrs(self->conn_handle, service->start_handle, @@ -402,11 +595,9 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t _discovered_characteristic_cb, service)); - // Wait for _discovered_characteristic_cb() to be called multiple times until it's done. - int status = _wait_for_discovery_step_done(); - if (status != BLE_HS_EDONE) { - CHECK_BLE_ERROR(status); - } + // Drain staged characteristics and build them on the VM task until done. + int status = _drain_records(service, _build_characteristic); + _check_discovery_status(status); // Got characteristics for this service. Now discover descriptors for each characteristic. size_t char_list_len = service->characteristic_list->len; @@ -423,15 +614,16 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t uint16_t end_handle = next_characteristic == NULL ? service->end_handle - : next_characteristic->handle - 1; + : next_characteristic->def_handle - 1; // Pre-check if there are no descriptors to discover so descriptor discovery doesn't fail if (end_handle <= characteristic->handle) { continue; } - // Reset discovery status before starting callbacks + // Reset discovery status and staging queue before starting callbacks. _set_discovery_step_status(0); + _reset_discovery_queue(); // The descriptor handle inclusive range is [characteristic->handle + 1, end_handle], // but ble_gattc_disc_all_dscs() requires starting with characteristic->handle. @@ -439,11 +631,9 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t end_handle, _discovered_descriptor_cb, characteristic)); - // Wait for _discovered_descriptor_cb to be called multiple times until it's done. - status = _wait_for_discovery_step_done(); - if (status != BLE_HS_EDONE) { - CHECK_BLE_ERROR(status); - } + // Drain staged descriptors and build them on the VM task until done. + status = _drain_records(characteristic, _build_descriptor); + _check_discovery_status(status); } } } diff --git a/ports/espressif/common-hal/_bleio/Connection.h b/ports/espressif/common-hal/_bleio/Connection.h index 326eca02ecd..143cc64d28a 100644 --- a/ports/espressif/common-hal/_bleio/Connection.h +++ b/ports/espressif/common-hal/_bleio/Connection.h @@ -22,6 +22,11 @@ typedef enum { PAIR_NOT_PAIRED, PAIR_WAITING, + // The peer is running LE Secure Connections numeric-comparison pairing and NimBLE is + // waiting for us to confirm the 6-digit value. Python reads it from + // Connection.numeric_comparison and answers with confirm_pairing(). This is a + // peer-driven, non-blocking path; the blocking pair() does not use it. + PAIR_WAITING_NUMCMP, PAIR_PAIRED, } pair_status_t; @@ -31,6 +36,15 @@ typedef enum { typedef struct { uint16_t conn_handle; bool is_central; + // True if user code initiated or accepted this connection: it connected in the + // central role, or a central answered user code's advertising. User-owned + // connections are disconnected when the VM resets; the BLE workflow connection + // is not user-owned and stays up. + bool user_owned; + // An indication we sent from characteristic_notify_indicate() awaits its + // acknowledgment or timeout. NimBLE allows one outstanding indication per + // connection, shared across all characteristics. + volatile bool indicate_outstanding; // Remote services discovered when this peripheral is acting as a client. mp_obj_list_t *remote_service_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must @@ -41,6 +55,13 @@ typedef struct { uint16_t ediv; volatile pair_status_t pair_status; uint8_t sec_status; // Internal security status. + // The 6-digit LE Secure Connections numeric-comparison value stashed by + // BLE_GAP_EVENT_PASSKEY_ACTION. Only valid while pair_status == PAIR_WAITING_NUMCMP. + volatile uint32_t pairing_numcmp; + // True once the link is encrypted AND authenticated against MITM (numeric comparison + // or passkey entry completed). A plain encrypted "Just Works" link leaves this false. + // Surfaced to Python as Connection.authenticated. + volatile bool mitm_protected; mp_obj_t connection_obj; volatile bool conn_params_updating; uint16_t mtu; @@ -64,6 +85,7 @@ void bleio_connection_clear(bleio_connection_internal_t *self); int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in); +void bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/ports/espressif/common-hal/_bleio/Descriptor.c b/ports/espressif/common-hal/_bleio/Descriptor.c index 3f2870740f1..617e862206f 100644 --- a/ports/espressif/common-hal/_bleio/Descriptor.c +++ b/ports/espressif/common-hal/_bleio/Descriptor.c @@ -15,6 +15,8 @@ #include "shared-bindings/_bleio/Service.h" #include "shared-bindings/_bleio/UUID.h" +#include "common-hal/_bleio/Adapter.h" + #include "host/ble_att.h" void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) { @@ -33,22 +35,26 @@ void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_c if (write_perm != SECURITY_MODE_NO_ACCESS) { self->flags |= BLE_ATT_F_WRITE; } - if (read_perm == SECURITY_MODE_ENC_WITH_MITM || write_perm == SECURITY_MODE_ENC_WITH_MITM || - read_perm == SECURITY_MODE_SIGNED_WITH_MITM || write_perm == SECURITY_MODE_SIGNED_WITH_MITM) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("MITM security not supported")); - } + // MITM / LESC-MITM / SIGNED all map to the _AUTHEN flags (require an authenticated + // link); see the matching block in Characteristic.c. if (read_perm == SECURITY_MODE_ENC_NO_MITM) { self->flags |= BLE_ATT_F_READ_ENC; } - if (read_perm == SECURITY_MODE_SIGNED_NO_MITM) { + if (read_perm == SECURITY_MODE_ENC_WITH_MITM || read_perm == SECURITY_MODE_LESC_ENC_WITH_MITM || + read_perm == SECURITY_MODE_SIGNED_NO_MITM || read_perm == SECURITY_MODE_SIGNED_WITH_MITM) { self->flags |= BLE_ATT_F_READ_AUTHEN; } if (write_perm == SECURITY_MODE_ENC_NO_MITM) { self->flags |= BLE_ATT_F_WRITE_ENC; } - if (write_perm == SECURITY_MODE_SIGNED_NO_MITM) { + if (write_perm == SECURITY_MODE_ENC_WITH_MITM || write_perm == SECURITY_MODE_LESC_ENC_WITH_MITM || + write_perm == SECURITY_MODE_SIGNED_NO_MITM || write_perm == SECURITY_MODE_SIGNED_WITH_MITM) { self->flags |= BLE_ATT_F_WRITE_AUTHEN; } + if (bleio_attribute_security_mode_requires_mitm(read_perm) || + bleio_attribute_security_mode_requires_mitm(write_perm)) { + bleio_adapter_enable_mitm_pairing(); + } const mp_int_t max_length_max = BLE_ATT_ATTR_MAX_LEN; if (max_length < 0 || max_length > max_length_max) { diff --git a/ports/espressif/common-hal/_bleio/PacketBuffer.c b/ports/espressif/common-hal/_bleio/PacketBuffer.c index db035157ceb..77f19ad319f 100644 --- a/ports/espressif/common-hal/_bleio/PacketBuffer.c +++ b/ports/espressif/common-hal/_bleio/PacketBuffer.c @@ -15,6 +15,7 @@ #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/PacketBuffer.h" +#include "shared-bindings/microcontroller/__init__.h" #include "supervisor/shared/tick.h" #include "supervisor/shared/bluetooth/serial.h" @@ -23,6 +24,12 @@ #include "host/ble_att.h" +// The ringbuf and the pending outgoing buffers are shared with the nimble_host +// task, which preempts the CircuitPython task at arbitrary points, and ringbuf +// operations are not atomic, so guard the shared accesses with interrupts +// disabled. + +// Runs on the nimble_host task. void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, uint16_t conn_handle, const uint8_t *data, size_t len) { if (self->conn_handle != conn_handle) { return; @@ -34,6 +41,8 @@ void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, uint16_t conn_h return; } + common_hal_mcu_disable_interrupts(); + // Make room for the new value by dropping the oldest packets first. while (ringbuf_num_empty(&self->ringbuf) < len + sizeof(uint16_t)) { uint16_t packet_length; @@ -45,10 +54,18 @@ void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, uint16_t conn_h } ringbuf_put_n(&self->ringbuf, (uint8_t *)&len, sizeof(uint16_t)); ringbuf_put_n(&self->ringbuf, data, len); + + common_hal_mcu_enable_interrupts(); } static int packet_buffer_on_ble_client_evt(struct ble_gap_event *event, void *param); static int queue_next_write(bleio_packet_buffer_obj_t *self); +static void packet_buffer_retry_send(void *data); + +// Interval to wait between send attempts when the outgoing mbuf pool is +// exhausted. The pool drains as fast as the radio sends: a handful of packets +// per connection interval, which is typically tens of milliseconds. +#define RETRY_INTERVAL_MS (10) static int _write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, @@ -61,80 +78,166 @@ static int _write_cb(uint16_t conn_handle, #endif } bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *)arg; + // Whether or not the write succeeded, it is no longer awaiting a response. On + // failure NimBLE already consumed the data, so there is nothing to retry. + self->packet_queued = false; queue_next_write(self); return 0; } +// Try to send the data waiting in the pending buffer, if any. May be called +// from the CircuitPython task or from the nimble_host task, +// which preempts the CircuitPython task. +// BLE_HS_ENOMEM means we are out of mbufs because the radio hasn't drained +// the outgoing queue yet. That is expected, not an error: keep +// the data: the background callback scheduled below and the wait loops in +// write() and flush() will retry sending. +// On other errors drop the data. static int queue_next_write(bleio_packet_buffer_obj_t *self) { - // Queue up the next outgoing buffer. We use two, one that has been passed to the SD for - // transmission (when packet_queued is true) and the other is `pending` and can still be - // modified. By primarily appending to the `pending` buffer we can reduce the protocol overhead - // of the lower level link and ATT layers. - self->packet_queued = false; - if (self->pending_size > 0) { - uint16_t conn_handle = self->conn_handle; - int err_code = NIMBLE_OK; - if (self->client) { - if (self->write_type == CHAR_PROP_WRITE_NO_RESPONSE) { - err_code = ble_gattc_write_no_rsp_flat(conn_handle, - self->characteristic->handle, - self->outgoing[self->pending_index], - self->pending_size); - // We don't set packet_queued because NimBLE will buffer our - // outgoing packets. - } else { - err_code = ble_gattc_write_flat(conn_handle, - self->characteristic->handle, - self->outgoing[self->pending_index], - self->pending_size, - _write_cb, self); - self->pending_index = (self->pending_index + 1) % 2; - self->packet_queued = true; - } + // Remember the current time if a previous send failed. + uint64_t now_ms = 0; + if (self->last_failed_ms != 0) { + now_ms = supervisor_ticks_ms64(); + } + common_hal_mcu_disable_interrupts(); + if (self->send_in_progress || self->packet_queued || + self->pending_size == 0 || + self->conn_handle == BLEIO_HANDLE_INVALID) { + // Succeed if: + // - there is nothing to send + // - a packet is already awaiting its completion event + // - another send call is already in progress (including the + // synchronous BLE_GAP_EVENT_NOTIFY_TX that our own notify and + // indicate calls below raise on this very stack). + common_hal_mcu_enable_interrupts(); + return NIMBLE_OK; + } + if (self->last_failed_ms != 0 && + (now_ms == 0 || now_ms - self->last_failed_ms < RETRY_INTERVAL_MS)) { + // Don't try before retry interval expires: the radio can only go so fast. + // Schedule a retry for later. + common_hal_mcu_enable_interrupts(); + background_callback_add(&self->retry_send_callback, packet_buffer_retry_send, self); + return BLE_HS_ENOMEM; + } + // Claim the pending buffer. While send_in_progress is set, writers wait + // instead of appending to the buffer. Other callers of this function return above, + // so the buffer contents stay stable during the send call even though + // interrupts are enabled again while it runs. + self->send_in_progress = true; + // A client Write with Response or an Indicate gets a completion event (a + // write response or an indicate acknowledgment) that calls back here to + // send whatever accumulates in the meantime. Mark such a packet as in + // flight *before* submitting it: if this task is preempted for long enough, + // the completion can arrive before the code after the send call runs, + // and it must find the flag already set so it can clear it. + bool is_completion_type = self->write_type == CHAR_PROP_WRITE || + self->write_type == CHAR_PROP_INDICATE; + self->packet_queued = is_completion_type; + uint16_t conn_handle = self->conn_handle; + uint16_t attr_handle = self->characteristic->handle; + const uint8_t *data = (const uint8_t *)self->outgoing[0]; + uint16_t data_len = self->pending_size; + common_hal_mcu_enable_interrupts(); + + int err_code; + if (self->client) { + if (self->write_type == CHAR_PROP_WRITE_NO_RESPONSE) { + // Copies the data into an mbuf before returning. No completion + // callback follows; NimBLE buffers the outgoing packet itself. + err_code = ble_gattc_write_no_rsp_flat(conn_handle, attr_handle, + data, data_len); } else { - // Allocate an mbuf because the functions below consume it. - struct os_mbuf *om = ble_hs_mbuf_from_flat(self->outgoing[self->pending_index], self->pending_size); - if (om == NULL) { - // We may not have any more mbufs if BLE busy. It isn't a problem (yet) so we'll - // just skip queueing for now. - return BLE_HS_ENOMEM; - } - size_t pending_size = self->pending_size; - self->pending_size = 0; - if (self->write_type == CHAR_PROP_NOTIFY) { - err_code = ble_gatts_notify_custom(conn_handle, self->characteristic->handle, om); - } else if (self->write_type == CHAR_PROP_INDICATE) { - err_code = ble_gatts_indicate_custom(conn_handle, self->characteristic->handle, om); - self->pending_index = (self->pending_index + 1) % 2; - self->packet_queued = true; - } else { - // Placeholder error. - err_code = BLE_HS_EUNKNOWN; - } - // Undo our queueing if it fails. We need to do it early because we may recurse back - // to here from the above ble_gatts functions. - if (err_code != NIMBLE_OK) { - self->pending_index = (self->pending_index + 1) % 2; - self->packet_queued = false; - self->pending_size = pending_size; - } + // _write_cb will be called only if the write was actually queued. + err_code = ble_gattc_write_flat(conn_handle, attr_handle, + data, data_len, _write_cb, self); } + } else { + // Allocate an mbuf because the functions below consume it, on + // success and on failure. + struct os_mbuf *om = ble_hs_mbuf_from_flat(data, data_len); + if (om == NULL) { + err_code = BLE_HS_ENOMEM; + } else if (self->write_type == CHAR_PROP_NOTIFY) { + // Raises BLE_GAP_EVENT_NOTIFY_TX on this stack before returning, + // on success and on failure. There is no later completion event + // for a notification. + err_code = ble_gatts_notify_custom(conn_handle, attr_handle, om); + } else if (self->write_type == CHAR_PROP_INDICATE) { + // The acknowledgment (or a timeout) will raise + // BLE_GAP_EVENT_NOTIFY_TX later, from the nimble_host task. + err_code = ble_gatts_indicate_custom(conn_handle, attr_handle, om); + } else { + // Placeholder error. + err_code = BLE_HS_EUNKNOWN; + } + } + + uint64_t fail_ms = 0; + if (err_code == BLE_HS_ENOMEM) { + fail_ms = supervisor_ticks_ms64(); + } + common_hal_mcu_disable_interrupts(); + self->send_in_progress = false; + if (self->conn_handle != conn_handle) { + // Disconnected or unsubscribed during the send. The event handler + // already discarded the pending data; make sure nothing looks like a + // send in progress to the new connection, if any. + self->packet_queued = false; + common_hal_mcu_enable_interrupts(); + return err_code; + } + if (err_code == NIMBLE_OK) { + // NimBLE copied the data, so the buffer is immediately reusable, + // even while a write with response or an indicate is still in + // flight: new writes coalesce in it until the completion event. + // Don't touch packet_queued: it was set before the send, and the + // completion event may already have cleared it. self->pending_size = 0; - if (err_code != NIMBLE_OK) { - // On error, simply skip updating the pending buffers so that the next HVC or WRITE - // complete event triggers another attempt. - return err_code; + self->last_failed_ms = 0; + } else { + // Nothing was queued, so no completion event will come. + self->packet_queued = false; + if (err_code == BLE_HS_ENOMEM) { + // Out of mbufs: normal while the radio works through the outgoing + // queue. Keep the data and retry from the background, + // because a failed send gets no completion event to prompt + // another attempt. Re-adding a queued callback does nothing. + self->last_failed_ms = fail_ms; + background_callback_add(&self->retry_send_callback, packet_buffer_retry_send, self); + } else { + // A real error, such as a dropped connection or an ATT failure. + // Drop the data, as before. + self->pending_size = 0; + self->last_failed_ms = 0; } } - return NIMBLE_OK; + common_hal_mcu_enable_interrupts(); + return err_code; } -// This is called from the nimble task. *Not* CircuitPython's. +// Runs as a background callback after a send failed for lack of mbufs. +static void packet_buffer_retry_send(void *data) { + bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *)data; + if (common_hal_bleio_packet_buffer_deinited(self)) { + return; + } + // Reschedules this callback (in queue_next_write()) if still out of mbufs. + queue_next_write(self); +} + +// This is usually called from the nimble task, *not* CircuitPython's. +// BLE_GAP_EVENT_NOTIFY_TX is also raised synchronously, on the task that +// called into NimBLE, by our own sends in queue_next_write(). static int packet_buffer_on_ble_client_evt(struct ble_gap_event *event, void *param) { bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *)param; if (event->type == BLE_GAP_EVENT_DISCONNECT && self->conn_handle == event->disconnect.conn.conn_handle) { self->conn_handle = BLEIO_HANDLE_INVALID; + // Discard the pending state so stale data can't be sent into a + // later connection or subscription. + self->pending_size = 0; + self->packet_queued = false; return false; } if (event->type == BLE_GAP_EVENT_SUBSCRIBE) { @@ -142,16 +245,49 @@ static int packet_buffer_on_ble_client_evt(struct ble_gap_event *event, void *pa self->conn_handle = event->subscribe.conn_handle; } else if (self->conn_handle == event->subscribe.conn_handle && event->subscribe.cur_notify == 0 && event->subscribe.cur_indicate == 0) { self->conn_handle = BLEIO_HANDLE_INVALID; + // Discard the pending state so stale data can't be sent into a + // later subscription. + self->pending_size = 0; + self->packet_queued = false; } return false; } if (event->type == BLE_GAP_EVENT_NOTIFY_TX) { if (self->conn_handle == event->notify_tx.conn_handle && self->characteristic->handle == event->notify_tx.attr_handle) { - if (event->notify_tx.indication == 1 && event->notify_tx.status == 0) { - // The indicate has been queued. + if (event->notify_tx.indication == 1) { + if (event->notify_tx.status == 0) { + // The indicate has been queued. This event is raised + // synchronously inside our own indicate call. + return false; + } + if (event->notify_tx.status == BLE_HS_EDONE || + event->notify_tx.status == BLE_HS_ETIMEOUT) { + // Acknowledged or timed out: the indicate is no longer + // awaiting a response. These statuses come only from the nimble_host + // task later on, never from inside our own send call, so + // clear packet_queued even if a new claim is in progress. + self->packet_queued = false; + if (!self->send_in_progress) { + // Send any data that accumulated in the meantime. + queue_next_write(self); + } + return false; + } + // Any other status is either our own synchronous submission + // failure, handled by the return code in queue_next_write(), + // or a failure that comes with a disconnect, which discards + // the pending state. return false; } - queue_next_write(self); + // A notification transmission was attempted (status 0 on + // success). It was raised synchronously inside a notify call: + // ours, in queue_next_write(), which acts on the result code + // itself (send_in_progress is set), or someone else's on this + // characteristic, which we can use as a prompt to send anything + // that is waiting. + if (!self->send_in_progress) { + queue_next_write(self); + } return false; } } @@ -185,10 +321,13 @@ void _common_hal_bleio_packet_buffer_construct( } self->packet_queued = false; - self->pending_index = 0; + self->send_in_progress = false; self->pending_size = 0; + self->last_failed_ms = 0; self->outgoing[0] = outgoing_buffer1; self->outgoing[1] = outgoing_buffer2; + // Don't touch retry_send_callback: for a statically allocated buffer that + // is being reconstructed, it may still be on the background callback list. if (static_handler_entry != NULL) { ble_event_add_handler_entry((ble_event_handler_entry_t *)static_handler_entry, packet_buffer_on_ble_client_evt, self); @@ -249,6 +388,11 @@ void common_hal_bleio_packet_buffer_construct( outgoing1 = m_malloc_without_collect(max_packet_size); // Only allocate the second buffer if we are doing writes with responses. // Without responses, we just write as quickly as we can. + // + // TODO: this port never reads outgoing[1]. NimBLE copies the data at send + // time, so one buffer can be refilled immediately, unlike the nordic + // SoftDevice which keeps the caller's buffer until TX completes. Kept + // allocated so that reintroducing two-buffer use here is not a bug. if (outgoing == CHAR_PROP_WRITE || outgoing == CHAR_PROP_INDICATE) { outgoing2 = m_malloc_without_collect(max_packet_size); } @@ -264,6 +408,8 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self return 0; } + common_hal_mcu_disable_interrupts(); + // Get packet length, which is in first two bytes of packet. uint16_t packet_length; ringbuf_get_n(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); @@ -282,6 +428,8 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self ret = packet_length; } + common_hal_mcu_enable_interrupts(); + return ret; } @@ -308,38 +456,54 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, c } outgoing_packet_length = MIN(outgoing_packet_length, self->max_packet_size); - if (len + self->pending_size > (size_t)outgoing_packet_length) { - // No room to append len bytes to packet. Wait until we get a free buffer, - // and keep checking that we haven't been disconnected. - while (self->pending_size != 0 && - self->conn_handle != BLEIO_HANDLE_INVALID && - !mp_hal_is_interrupted()) { - RUN_BACKGROUND_TASKS; + size_t num_bytes_written = 0; + + // Append the data to the pending packet, waiting for room if it is full. + // The append must happen with interrupts disabled, with the connection + // still up and with no send call in progress (the nimble_host task can + // start one at any point), so check those conditions inside the critical + // section and retry until they all hold at once. + while (true) { + if (mp_hal_is_interrupted()) { + return -1; } + common_hal_mcu_disable_interrupts(); + if (self->conn_handle == BLEIO_HANDLE_INVALID) { + common_hal_mcu_enable_interrupts(); + return -1; + } + if (!self->send_in_progress && + len + self->pending_size <= (size_t)outgoing_packet_length) { + // Append below, still inside the critical section. + break; + } + common_hal_mcu_enable_interrupts(); + // No room for data yet. Retry the pending packet ourselves: a send that + // failed for lack of mbufs gets no completion event to prompt + // another attempt, and if we were called from a background callback + // (as the BLE workflow does), RUN_BACKGROUND_TASKS below cannot + // re-enter background callbacks to do it for us. + queue_next_write(self); + RUN_BACKGROUND_TASKS; } - if (self->conn_handle == BLEIO_HANDLE_INVALID || - mp_hal_is_interrupted()) { - return -1; - } - - size_t num_bytes_written = 0; - uint32_t *pending = self->outgoing[self->pending_index]; + uint8_t *pending = (uint8_t *)self->outgoing[0]; if (self->pending_size == 0) { memcpy(pending, header, header_len); self->pending_size += header_len; num_bytes_written += header_len; } - memcpy(((uint8_t *)pending) + self->pending_size, data, len); + memcpy(pending + self->pending_size, data, len); self->pending_size += len; num_bytes_written += len; - // If no writes are queued then sneak in this data. - if (!self->packet_queued) { - // This will queue up the packet even if it can't send immediately. - queue_next_write(self); - } + common_hal_mcu_enable_interrupts(); + + // Send now. This is a no-op if a packet is already awaiting its completion + // event; the completion will send the data instead. + queue_next_write(self); + return num_bytes_written; } @@ -423,6 +587,10 @@ void common_hal_bleio_packet_buffer_flush(bleio_packet_buffer_obj_t *self) { self->packet_queued) && self->conn_handle != BLEIO_HANDLE_INVALID && !mp_hal_is_interrupted()) { + // Retry sends that failed for lack of mbufs ourselves: they get no + // completion event, and background callbacks can't run if we were + // called from one (as the BLE workflow does). + queue_next_write(self); RUN_BACKGROUND_TASKS; } } @@ -435,9 +603,15 @@ void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { if (common_hal_bleio_packet_buffer_deinited(self)) { return; } + // Take the packet buffer off the event list before changing anything + // inside the object. + ble_event_remove_handler(packet_buffer_on_ble_client_evt, self); bleio_characteristic_clear_observer(self->characteristic); self->characteristic = NULL; - ble_event_remove_handler(packet_buffer_on_ble_client_evt, self); + // A still-queued retry_send_callback checks deinited(), so it sees the + // NULL characteristic and does nothing. + self->pending_size = 0; + self->packet_queued = false; ringbuf_deinit(&self->ringbuf); } diff --git a/ports/espressif/common-hal/_bleio/PacketBuffer.h b/ports/espressif/common-hal/_bleio/PacketBuffer.h index 0ab084c5b01..b555cf2632f 100644 --- a/ports/espressif/common-hal/_bleio/PacketBuffer.h +++ b/ports/espressif/common-hal/_bleio/PacketBuffer.h @@ -9,24 +9,41 @@ #include "py/ringbuf.h" #include "shared-bindings/_bleio/Characteristic.h" #include "common-hal/_bleio/ble_events.h" +#include "supervisor/background_callback.h" typedef struct { mp_obj_base_t base; bleio_characteristic_obj_t *characteristic; // Ring buffer storing consecutive incoming values. ringbuf_t ringbuf; - // Two outgoing buffers to alternate between. One will be queued for transmission by the SD and - // the other is waiting to be queued and can be extended. + // This is the outgoing packet being assembled. NimBLE copies the data at send + // time, so we only need a single buffer. The second entry exists here but is + // unused: the shared constructors expect two buffers. uint32_t *outgoing[2]; + // Number of bytes waiting in outgoing[0] to be sent. volatile uint16_t pending_size; // We remember the conn_handle so we can do a NOTIFY/INDICATE to a client. // We can find out the conn_handle on a Characteristic write or a CCCD write (but not a read). volatile uint16_t conn_handle; uint16_t max_packet_size; - uint8_t pending_index; uint8_t write_type; bool client; - bool packet_queued; + // True while a client Write with Response or an Indicate is awaiting its + // completion event: a response or acknowledgment from the peer. Not used for + // notifications, whose NOTIFY_TX arrives inside the send call itself. + // Its completion event sends any data that accumulated in the meantime. + volatile bool packet_queued; + // True while a task is inside a send call in queue_next_write(). Writers + // wait instead of appending, and other send attempts (including the + // synchronous BLE_GAP_EVENT_NOTIFY_TX raised inside our own notify and + // indicate calls) return without doing anything. + volatile bool send_in_progress; + // Retries sends that failed for lack of mbufs; they get no completion + // event, so nothing else would try again. + background_callback_t retry_send_callback; + // Time of the last send that failed for lack of mbufs, to pace retries + // while the radio drains the pool. Zero when the last send succeeded. + uint64_t last_failed_ms; } bleio_packet_buffer_obj_t; typedef ble_event_handler_entry_t ble_event_handler_t; diff --git a/ports/espressif/common-hal/_bleio/Service.c b/ports/espressif/common-hal/_bleio/Service.c index 3afbeb2a684..fedfacd307e 100644 --- a/ports/espressif/common-hal/_bleio/Service.c +++ b/ports/espressif/common-hal/_bleio/Service.c @@ -5,8 +5,10 @@ // // SPDX-License-Identifier: MIT +#include "py/gc.h" #include "py/runtime.h" #include "common-hal/_bleio/__init__.h" +#include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Descriptor.h" #include "shared-bindings/_bleio/Service.h" @@ -14,6 +16,51 @@ #include "host/ble_gatt.h" +// NimBLE's GATT table keeps raw pointers into a registered local service and +// everything under it: the chr_defs array lives inside the service object, each +// characteristic and descriptor is an access-callback argument, and every UUID +// is referenced by address. Collecting any of them would leave those dangling, +// so retain a heap Service here for as long as NimBLE knows about it. +// Retaining the service is enough because it holds its characteristics, +// which hold their descriptors. Services in static storage, like the BLE workflow's, +// cannot be collected and are skipped. +static bleio_service_obj_t *_retained_services; + +static void service_retain(bleio_service_obj_t *self) { + if (!gc_ptr_on_heap((void *)self)) { + return; + } + for (bleio_service_obj_t *it = _retained_services; it != NULL; it = it->next_retained) { + if (it == self) { + return; + } + } + self->next_retained = _retained_services; + _retained_services = self; +} + +static void service_release(bleio_service_obj_t *self) { + bleio_service_obj_t **prev = &_retained_services; + for (bleio_service_obj_t *it = *prev; it != NULL; it = it->next_retained) { + if (it == self) { + *prev = it->next_retained; + it->next_retained = NULL; + return; + } + prev = &it->next_retained; + } +} + +void bleio_service_forget_retained(void) { + _retained_services = NULL; +} + +// Mark the retained services. One pointer is enough: the GC traces +// next_retained through the rest of the chain from the head. +void bleio_service_gc_collect(void) { + gc_collect_ptr(_retained_services); +} + uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary, mp_obj_list_t *characteristic_list) { self->handle = 0xFFFF; self->uuid = uuid; @@ -27,6 +74,8 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu self->service_def.includes = NULL; self->service_def.characteristics = self->chr_defs; self->next_svc_type = 0; + self->next_retained = NULL; + self->registered = false; // Don't add the service yet because we don't have any characteristics. return 0; @@ -38,9 +87,21 @@ void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_ob } void common_hal_bleio_service_deinit(bleio_service_obj_t *self) { - // Delete the old version of the service. - if (self->characteristic_list->len > 1) { + // Take the service out of NimBLE's GATT table first, so nothing torn down + // below is still reachable from it. + if (self->registered) { ble_gatts_delete_svc(&self->uuid->nimble_ble_uuid.u); + self->registered = false; + } + // NimBLE no longer refers to this service, so stop retaining it, and deinit + // the characteristics: a local one that can notify or indicate holds an + // event handler that must come off the event list with it. + service_release(self); + if (!self->is_remote) { + for (size_t i = 0; i < self->characteristic_list->len; i++) { + common_hal_bleio_characteristic_deinit( + MP_OBJ_TO_PTR(self->characteristic_list->items[i])); + } } self->service_def.type = 0; } @@ -50,6 +111,7 @@ void bleio_service_from_connection(bleio_service_obj_t *self, mp_obj_t connectio self->uuid = NULL; self->characteristic_list = mp_obj_new_list(0, NULL); self->is_remote = true; + self->registered = false; self->is_secondary = false; self->connection = connection; } @@ -70,13 +132,18 @@ bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { return self->is_secondary; } -// Used by characteristics to update their descriptors. +// Register the service, or register it again after its definition changed: +// NimBLE cannot amend a service that is already in its GATT table, so the old +// version is deleted and the whole service added again. void bleio_service_readd(bleio_service_obj_t *self) { - // Delete the old version of the service. - if (self->characteristic_list->len > 1) { + if (self->registered) { ble_gatts_delete_svc(&self->uuid->nimble_ble_uuid.u); + self->registered = false; } CHECK_NIMBLE_ERROR(ble_gatts_add_dynamic_svcs(&self->service_def)); + self->registered = true; + // NimBLE now refers to this service and everything under it. + service_retain(self); } @@ -84,17 +151,18 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *initial_value_bufinfo, const char *user_description) { + // Don't overflow chr_defs table. + size_t i = self->characteristic_list->len; + if (i >= MAX_CHARACTERISTIC_COUNT) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Too many %q"), MP_QSTR_characteristics); + } + mp_obj_list_append(self->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); if (user_description != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_user_description); } - // Delete the old version of the service. - if (self->characteristic_list->len > 1) { - ble_gatts_delete_svc(&self->uuid->nimble_ble_uuid.u); - } - size_t i = self->characteristic_list->len - 1; self->chr_defs[i].uuid = &characteristic->uuid->nimble_ble_uuid.u; self->chr_defs[i].access_cb = bleio_characteristic_access_cb; self->chr_defs[i].arg = characteristic; @@ -106,5 +174,5 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, self->chr_defs[i + 1].uuid = NULL; characteristic->chr_def = &self->chr_defs[i]; - CHECK_NIMBLE_ERROR(ble_gatts_add_dynamic_svcs(&self->service_def)); + bleio_service_readd(self); } diff --git a/ports/espressif/common-hal/_bleio/Service.h b/ports/espressif/common-hal/_bleio/Service.h index 936627a00ee..d003a96cafa 100644 --- a/ports/espressif/common-hal/_bleio/Service.h +++ b/ports/espressif/common-hal/_bleio/Service.h @@ -21,6 +21,9 @@ typedef struct bleio_service_obj { // True if created during discovery. bool is_remote; bool is_secondary; + // True while NimBLE's GATT table holds this service: it must be deleted + // before the definition is changed or the service is torn down. + bool registered; bleio_uuid_obj_t *uuid; // The connection object is set only when this is a remote service. // A local service doesn't know the connection. @@ -33,7 +36,17 @@ typedef struct bleio_service_obj { // Include a spot for terminating the service def array. uint8_t next_svc_type; struct ble_gatt_chr_def chr_defs[MAX_CHARACTERISTIC_COUNT + 1]; + // Link in the list of services retained while NimBLE's GATT table refers + // to them; see Service.c. NULL when not on that list. + struct bleio_service_obj *next_retained; } bleio_service_obj_t; void bleio_service_from_connection(bleio_service_obj_t *self, mp_obj_t connection); void bleio_service_readd(bleio_service_obj_t *self); + +// Stop retaining every service. Call when the heap they live on is about to go +// away. +void bleio_service_forget_retained(void); + +// Mark the retained services as reachable during a GC pass. +void bleio_service_gc_collect(void); diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index 119fe55921e..f29342f6ec4 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -24,6 +24,8 @@ #include "common-hal/_bleio/__init__.h" #include "common-hal/_bleio/ble_events.h" +#include "services/gatt/ble_svc_gatt.h" + #include "nvs_flash.h" static volatile int _completion_status; @@ -32,11 +34,36 @@ static uint64_t _timeout_start_time; background_callback_t bleio_background_callback; void bleio_user_reset(void) { + if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + return; + } // Stop any user scanning or advertising. common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); + // Disconnect the connections that user code initiated or accepted with its own + // advertising. Keep the BLE workflow connection if present. + // + // Remove each connection's pointers into the VM heap before disconnecting: + // the heap is about to go away, and a disconnect completes asynchronously. + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + connection->connection_obj = mp_const_none; + connection->remote_service_list = NULL; + if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->user_owned) { + common_hal_bleio_connection_disconnect(connection); + } + } + + // Now clear the adapter's remaining heap pointer, since it will be stale + // when the VM stops. + common_hal_bleio_adapter_obj.connection_objs = NULL; + + // Also clean up event handlers that are on the heap. ble_event_remove_heap_handlers(); + // And stop retaining heap services, whose characteristics' handler entries + // the call above just removed. + bleio_service_forget_retained(); // Maybe start advertising the BLE workflow. supervisor_bluetooth_background(); @@ -49,11 +76,31 @@ void bleio_reset(void) { return; } + // The stop/start cycle below clears user-created services from the GATT + // table, and drops every connection, BLE workflow included. So run it + // only when user code created services. All other user BLE state has already + // been torn down individually by bleio_user_reset(). + // + // TODO: ESP-IDF NimBLE can delete individual services (ble_gatts_delete_svc(), + // used in Service.c), so bleio_user_reset() could delete user services one by + // one and never restart the BLE stack at all. For now this port matches + // nordic, whose SoftDevice can only clear services with a full cycle. + if (!bleio_get_user_services_created()) { + return; + } + bleio_clear_user_services_created(); + supervisor_stop_bluetooth(); ble_event_reset(); bleio_adapter_reset(&common_hal_bleio_adapter_obj); common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); supervisor_start_bluetooth(); + + // The stop/start above rebuilt the GATT table, so now any bonded peers' cached + // tables are stale. Signal Service Changed over the whole handle range. + // Without Service Changed, a bonded host trusts its cache indefinitely and can + // look up characteristics at stale handles. + ble_svc_gatt_changed(0x0001, 0xffff); } // The singleton _bleio.Adapter object, bound to _bleio.adapter @@ -84,6 +131,7 @@ void common_hal_bleio_init(void) { void common_hal_bleio_gc_collect(void) { bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); + bleio_service_gc_collect(); } void check_nimble_error(int rc, const char *file, size_t line) { @@ -155,7 +203,7 @@ void check_notify(BaseType_t result) { mp_raise_msg(&mp_type_TimeoutError, NULL); } -void common_hal_bleio_check_connected(uint16_t conn_handle) { +void bleio_check_connected(uint16_t conn_handle) { if (conn_handle == BLEIO_HANDLE_INVALID) { mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected")); } diff --git a/ports/espressif/common-hal/_bleio/ble_events.c b/ports/espressif/common-hal/_bleio/ble_events.c index 5b9eb649c97..5bd3e300a02 100644 --- a/ports/espressif/common-hal/_bleio/ble_events.c +++ b/ports/espressif/common-hal/_bleio/ble_events.c @@ -11,37 +11,50 @@ #include #include +#include "freertos/FreeRTOS.h" + #include "py/gc.h" #include "py/misc.h" #include "py/mpstate.h" #include "py/runtime.h" -#if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE #include "supervisor/shared/bluetooth/serial.h" #endif +// Do event list manipulation in a critical section. +static portMUX_TYPE handler_list_mutex = portMUX_INITIALIZER_UNLOCKED; + void ble_event_reset(void) { // Linked list items will be gc'd. + portENTER_CRITICAL(&handler_list_mutex); MP_STATE_VM(ble_event_handler_entries) = NULL; + portEXIT_CRITICAL(&handler_list_mutex); } void ble_event_remove_heap_handlers(void) { ble_event_handler_entry_t *it = MP_STATE_VM(ble_event_handler_entries); while (it != NULL) { - // If the param is on the heap, then delete the handler. - if (gc_ptr_on_heap(it->param)) { + // Save it->next before removing: the entry may be reused and relinked + // once it is off the list. + ble_event_handler_entry_t *next = it->next; + // Remove the handler if the entry or its param is on the heap, which is + // about to go away. + if (gc_ptr_on_heap(it) || gc_ptr_on_heap(it->param)) { ble_event_remove_handler(it->func, it->param); } - it = it->next; + it = next; } } void ble_event_add_handler_entry(ble_event_handler_entry_t *entry, ble_gap_event_fn *func, void *param) { + portENTER_CRITICAL(&handler_list_mutex); ble_event_handler_entry_t *it = MP_STATE_VM(ble_event_handler_entries); while (it != NULL) { // If event handler and its corresponding param are already on the list, don't add again. if ((it->func == func) && (it->param == param)) { + portEXIT_CRITICAL(&handler_list_mutex); return; } it = it->next; @@ -51,12 +64,17 @@ void ble_event_add_handler_entry(ble_event_handler_entry_t *entry, entry->func = func; MP_STATE_VM(ble_event_handler_entries) = entry; + portEXIT_CRITICAL(&handler_list_mutex); } void ble_event_add_handler(ble_gap_event_fn *func, void *param) { + // Not in a critical section on purpose: this scan only avoids the + // allocation below when the handler is already registered. + // ble_event_add_handler_entry() repeats it in the critical section and is + // the one that decides. The allocation must stay outside, because it can + // collect or raise. ble_event_handler_entry_t *it = MP_STATE_VM(ble_event_handler_entries); while (it != NULL) { - // If event handler and its corresponding param are already on the list, don't add again. if ((it->func == func) && (it->param == param)) { return; } @@ -69,23 +87,27 @@ void ble_event_add_handler(ble_gap_event_fn *func, void *param) { } void ble_event_remove_handler(ble_gap_event_fn *func, void *param) { + portENTER_CRITICAL(&handler_list_mutex); ble_event_handler_entry_t *it = MP_STATE_VM(ble_event_handler_entries); ble_event_handler_entry_t **prev = &MP_STATE_VM(ble_event_handler_entries); while (it != NULL) { if ((it->func == func) && (it->param == param)) { - // Splice out the matching handler. + // Splice out the matching handler. Leave its next pointer alone: + // another walk in progress may already be holding this node as its + // cursor. Clearing next would end that walk here, dropping the + // event for every handler after it. *prev = it->next; - // Clear next of the removed node so it's clearly not in a list. - it->next = NULL; + portEXIT_CRITICAL(&handler_list_mutex); return; } prev = &(it->next); it = it->next; } + portEXIT_CRITICAL(&handler_list_mutex); } int ble_event_run_handlers(struct ble_gap_event *event) { - #if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE ble_serial_disable(); #endif @@ -93,15 +115,23 @@ int ble_event_run_handlers(struct ble_gap_event *event) { mp_printf(&mp_plat_print, "BLE GAP event: 0x%04x\n", event->type); #endif + portENTER_CRITICAL(&handler_list_mutex); ble_event_handler_entry_t *it = MP_STATE_VM(ble_event_handler_entries); + portEXIT_CRITICAL(&handler_list_mutex); bool done = false; while (it != NULL) { - // Capture next before calling the function in case it removes itself from the list. + // Take a consistent snapshot of the node, including next, before + // calling the function: the function may remove itself from the list, + // and so may the VM task while the call runs. + portENTER_CRITICAL(&handler_list_mutex); ble_event_handler_entry_t *next = it->next; - done = it->func(event, it->param) || done; + ble_gap_event_fn *func = it->func; + void *param = it->param; + portEXIT_CRITICAL(&handler_list_mutex); + done = func(event, param) || done; it = next; } - #if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE ble_serial_enable(); #endif return 0; diff --git a/ports/espressif/common-hal/alarm/SleepMemory.c b/ports/espressif/common-hal/alarm/SleepMemory.c index 938772e53ca..301f5108cbf 100644 --- a/ports/espressif/common-hal/alarm/SleepMemory.c +++ b/ports/espressif/common-hal/alarm/SleepMemory.c @@ -15,14 +15,54 @@ // Data storage for singleton instance of SleepMemory. // Might be RTC_SLOW_MEM or RTC_FAST_MEM, depending on setting of CONFIG_ESP32S2_RTCDATA_IN_FAST_MEM. -static RTC_DATA_ATTR uint8_t _sleep_mem[SLEEP_MEMORY_LENGTH]; +#if defined(CONFIG_SOC_RTC_FAST_MEM_SUPPORTED) || defined(CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED) +static RTC_NOINIT_ATTR uint8_t _sleep_mem[SLEEP_MEMORY_LENGTH]; void alarm_sleep_memory_reset(void) { - // ESP-IDF build system takes care of doing esp_sleep_pd_config() or the equivalent with - // the correct settings, depending on which RTC mem we are using. - // https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/system/sleep_modes.html#power-down-of-rtc-peripherals-and-memories + // With RTC_NOINIT_ATTR, the bootloader does not initialize sleep memory. + // Preserve contents on resets where the RTC domain stays powered (software + // reset, watchdog, panic, deep sleep wake). Clear on everything else — + // after power-on, SRAM contents are undefined; after brown-out, the RTC + // domain was reset by hardware (System Reset scope per TRM Figure 6.1-1). + // + // esp_reset_reason() does not change across supervisor reloads, + // so do this check only once per chip reset. + static bool checked_reset_reason = false; + if (checked_reset_reason) { + return; + } + checked_reset_reason = true; + + esp_reset_reason_t reason = esp_reset_reason(); + switch (reason) { + case ESP_RST_SW: // microcontroller.reset() / esp_restart() + case ESP_RST_DEEPSLEEP: // deep sleep wake + case ESP_RST_PANIC: // unhandled exception + case ESP_RST_INT_WDT: // interrupt watchdog + case ESP_RST_TASK_WDT: // task watchdog + case ESP_RST_WDT: // other watchdog + // RTC domain was not reset — sleep memory is intact. + break; + default: + // Power-on, brown-out, unknown, or any other reason where + // RTC SRAM contents may be undefined. Clear to zero. + memset(_sleep_mem, 0, sizeof(_sleep_mem)); + break; + } } +#else + +// Chips without RTC memory can't persist SleepMemory across deep sleep. +static uint8_t _sleep_mem[SLEEP_MEMORY_LENGTH]; + +void alarm_sleep_memory_reset(void) { + // Do nothing for chips without RTC memory. +} + +#endif + + uint32_t common_hal_alarm_sleep_memory_get_length(alarm_sleep_memory_obj_t *self) { return sizeof(_sleep_mem); } diff --git a/ports/espressif/common-hal/alarm/__init__.c b/ports/espressif/common-hal/alarm/__init__.c index 629f976039f..751ef121e5f 100644 --- a/ports/espressif/common-hal/alarm/__init__.c +++ b/ports/espressif/common-hal/alarm/__init__.c @@ -57,68 +57,61 @@ void alarm_reset(void) { esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); } -static esp_sleep_wakeup_cause_t _get_wakeup_cause(bool deep_sleep) { +static uint32_t _get_wakeup_causes(bool deep_sleep) { // First check if the modules remember what last woke up if (alarm_pin_pinalarm_woke_this_cycle()) { - return ESP_SLEEP_WAKEUP_GPIO; + return 1 << ESP_SLEEP_WAKEUP_GPIO; } if (alarm_time_timealarm_woke_this_cycle()) { - return ESP_SLEEP_WAKEUP_TIMER; + return 1 << ESP_SLEEP_WAKEUP_TIMER; } #if CIRCUITPY_ALARM_TOUCH if (alarm_touch_touchalarm_woke_this_cycle()) { - return ESP_SLEEP_WAKEUP_TOUCHPAD; + return 1 << ESP_SLEEP_WAKEUP_TOUCHPAD; } #endif #if CIRCUITPY_ESPULP if (espulp_ulpalarm_woke_this_cycle()) { - return ESP_SLEEP_WAKEUP_ULP; + return 1 << ESP_SLEEP_WAKEUP_ULP; } #endif // If waking from true deep sleep, modules will have lost their state, // so check the deep wakeup cause manually if (deep_sleep) { - return esp_sleep_get_wakeup_cause(); + return esp_sleep_get_wakeup_causes(); } - return ESP_SLEEP_WAKEUP_UNDEFINED; + return 0; } bool common_hal_alarm_woken_from_sleep(void) { - return _get_wakeup_cause(false) != ESP_SLEEP_WAKEUP_UNDEFINED; + return _get_wakeup_causes(false) != 0; } mp_obj_t common_hal_alarm_record_wake_alarm(void) { // If woken from deep sleep, create a copy alarm similar to what would have // been passed in originally. Otherwise, just return none - esp_sleep_wakeup_cause_t cause = _get_wakeup_cause(true); - switch (cause) { - case ESP_SLEEP_WAKEUP_TIMER: { - return alarm_time_timealarm_record_wake_alarm(); - } + uint32_t causes = _get_wakeup_causes(true); - case ESP_SLEEP_WAKEUP_GPIO: - case ESP_SLEEP_WAKEUP_EXT0: - case ESP_SLEEP_WAKEUP_EXT1: { - return alarm_pin_pinalarm_record_wake_alarm(); - } + if (causes & (1 << ESP_SLEEP_WAKEUP_TIMER)) { + return alarm_time_timealarm_record_wake_alarm(); + } - #if CIRCUITPY_ALARM_TOUCH - case ESP_SLEEP_WAKEUP_TOUCHPAD: { - return alarm_touch_touchalarm_record_wake_alarm(); - } - #endif + if (causes & ((1 << ESP_SLEEP_WAKEUP_GPIO) | (1 << ESP_SLEEP_WAKEUP_EXT0) | (1 << ESP_SLEEP_WAKEUP_EXT1))) { + return alarm_pin_pinalarm_record_wake_alarm(); + } - #if CIRCUITPY_ESPULP - case ESP_SLEEP_WAKEUP_ULP: { - return espulp_ulpalarm_record_wake_alarm(); - } - #endif + #if CIRCUITPY_ALARM_TOUCH + if (causes & (1 << ESP_SLEEP_WAKEUP_TOUCHPAD)) { + return alarm_touch_touchalarm_record_wake_alarm(); + } + #endif - case ESP_SLEEP_WAKEUP_UNDEFINED: - default: - // Not a deep sleep reset. - break; + #if CIRCUITPY_ESPULP + if (causes & (1 << ESP_SLEEP_WAKEUP_ULP)) { + return espulp_ulpalarm_record_wake_alarm(); } + #endif + return mp_const_none; } @@ -144,32 +137,22 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj RUN_BACKGROUND_TASKS; // Detect if interrupt was alarm or ctrl-C interrupt. if (common_hal_alarm_woken_from_sleep()) { - esp_sleep_wakeup_cause_t cause = _get_wakeup_cause(false); - switch (cause) { - case ESP_SLEEP_WAKEUP_TIMER: { - wake_alarm = alarm_time_timealarm_find_triggered_alarm(n_alarms, alarms); - break; - } - case ESP_SLEEP_WAKEUP_GPIO: { - wake_alarm = alarm_pin_pinalarm_find_triggered_alarm(n_alarms, alarms); - break; - } - #if CIRCUITPY_ALARM_TOUCH - case ESP_SLEEP_WAKEUP_TOUCHPAD: { - wake_alarm = alarm_touch_touchalarm_find_triggered_alarm(n_alarms, alarms); - break; - } - #endif - #if CIRCUITPY_ESPULP - case ESP_SLEEP_WAKEUP_ULP: { - wake_alarm = espulp_ulpalarm_find_triggered_alarm(n_alarms, alarms); - break; - } - #endif - default: - // Should not reach this, if all light sleep types are covered correctly - break; + uint32_t causes = _get_wakeup_causes(false); + if (causes & (1 << ESP_SLEEP_WAKEUP_TIMER)) { + wake_alarm = alarm_time_timealarm_find_triggered_alarm(n_alarms, alarms); + } else if (causes & (1 << ESP_SLEEP_WAKEUP_GPIO)) { + wake_alarm = alarm_pin_pinalarm_find_triggered_alarm(n_alarms, alarms); + } + #if CIRCUITPY_ALARM_TOUCH + else if (causes & (1 << ESP_SLEEP_WAKEUP_TOUCHPAD)) { + wake_alarm = alarm_touch_touchalarm_find_triggered_alarm(n_alarms, alarms); + } + #endif + #if CIRCUITPY_ESPULP + else if (causes & (1 << ESP_SLEEP_WAKEUP_ULP)) { + wake_alarm = espulp_ulpalarm_find_triggered_alarm(n_alarms, alarms); } + #endif shared_alarm_save_wake_alarm(wake_alarm); break; } @@ -189,7 +172,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala _setup_sleep_alarms(true, n_alarms, alarms); } -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_pin_pinalarm_prepare_for_deep_sleep(); #if CIRCUITPY_ALARM_TOUCH alarm_touch_touchalarm_prepare_for_deep_sleep(); @@ -199,7 +182,7 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) { #endif // We no longer need to remember the pin preservations, since any pin resets are all done. - clear_pin_preservations(); + common_hal_alarm_clear_pin_preservations(); // The ESP-IDF caches the deep sleep settings and applies them before sleep. // We don't need to worry about resetting them in the interim. diff --git a/ports/espressif/common-hal/alarm/pin/PinAlarm.c b/ports/espressif/common-hal/alarm/pin/PinAlarm.c index 8e3e46785f2..3301612356b 100644 --- a/ports/espressif/common-hal/alarm/pin/PinAlarm.c +++ b/ports/espressif/common-hal/alarm/pin/PinAlarm.c @@ -14,10 +14,12 @@ #include "esp_sleep.h" #include "hal/gpio_ll.h" +#include "driver/gpio.h" #include "esp_debug_helpers.h" #ifdef SOC_PM_SUPPORT_EXT0_WAKEUP #include "soc/rtc_cntl_reg.h" +#include "soc/rtc_io_reg.h" #endif #include "driver/rtc_io.h" @@ -100,14 +102,14 @@ mp_obj_t alarm_pin_pinalarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t } mp_obj_t alarm_pin_pinalarm_record_wake_alarm(void) { - esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + uint32_t causes = esp_sleep_get_wakeup_causes(); // Pin status will persist into a fake deep sleep uint64_t pin_status = ((uint64_t)pin_63_32_status) << 32 | pin_31_0_status; size_t pin_number = 64; #ifdef SOC_PM_SUPPORT_EXT0_WAKEUP - if (cause == ESP_SLEEP_WAKEUP_EXT0) { + if (causes & (1 << ESP_SLEEP_WAKEUP_EXT0)) { int rtc_io_pin_number = REG_GET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL); // Look up the GPIO equivalent pin for this RTC GPIO pin. On ESP32, the numbering // is different for RTC_GPIO and regular GPIO, and there's no mapping table. @@ -122,12 +124,12 @@ mp_obj_t alarm_pin_pinalarm_record_wake_alarm(void) { } else { #endif #ifdef SOC_PM_SUPPORT_EXT1_WAKEUP - if (cause == ESP_SLEEP_WAKEUP_EXT1) { + if (causes & (1 << ESP_SLEEP_WAKEUP_EXT1)) { pin_status = esp_sleep_get_ext1_wakeup_status(); } #endif #ifdef SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP - if (cause == ESP_SLEEP_WAKEUP_GPIO) { + if (causes & (1 << ESP_SLEEP_WAKEUP_GPIO)) { pin_status = esp_sleep_get_gpio_wakeup_status(); } #endif @@ -305,11 +307,11 @@ static esp_err_t _setup_deep_sleep(size_t low_count, size_t high_count) { return _setup_ext1(low_count, high_count); } #endif - esp_err_t result = esp_deep_sleep_enable_gpio_wakeup(low_alarms, ESP_GPIO_WAKEUP_GPIO_LOW); + esp_err_t result = esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(low_alarms, ESP_GPIO_WAKEUP_GPIO_LOW); if (result != ESP_OK) { return result; } - result = esp_deep_sleep_enable_gpio_wakeup(high_alarms, ESP_GPIO_WAKEUP_GPIO_HIGH); + result = esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(high_alarms, ESP_GPIO_WAKEUP_GPIO_HIGH); return result; } #else @@ -358,38 +360,40 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob if (gpio_isr_register(gpio_interrupt, NULL, 0, &gpio_interrupt_handle) != ESP_OK) { mp_raise_ValueError(MP_ERROR_TEXT("Can only alarm on RTC IO from deep sleep.")); } - for (size_t i = 0; i < 64; i++) { - uint64_t mask = 1ull << i; + for (gpio_num_t pin = 0; pin < SOC_GPIO_PIN_COUNT; pin++) { + uint64_t mask = 1ULL << pin; bool high = (high_alarms & mask) != 0; bool low = (low_alarms & mask) != 0; bool pull = (pull_pins & mask) != 0; if (!(high || low)) { continue; } - if (rtc_gpio_is_valid_gpio(i)) { + if (rtc_gpio_is_valid_gpio(pin)) { #ifdef SOC_PM_SUPPORT_RTC_PERIPH_PD - rtc_gpio_deinit(i); + rtc_gpio_deinit(pin); #endif } - gpio_int_type_t interrupt_mode = GPIO_INTR_DISABLE; - gpio_pull_mode_t pull_mode = GPIO_FLOATING; + gpio_set_direction(pin, GPIO_MODE_INPUT); + if (pull) { + if (high) { + ESP_ERROR_CHECK(gpio_set_pull_mode(pin, GPIO_PULLDOWN_ONLY)); + } else { + ESP_ERROR_CHECK(gpio_set_pull_mode(pin, GPIO_PULLUP_ONLY)); + } + } else { + ESP_ERROR_CHECK(gpio_set_pull_mode(pin, GPIO_FLOATING)); + } + gpio_int_type_t intr = GPIO_INTR_DISABLE; if (high) { - interrupt_mode = GPIO_INTR_HIGH_LEVEL; - pull_mode = GPIO_PULLDOWN_ONLY; + intr = GPIO_INTR_HIGH_LEVEL; } if (low) { - interrupt_mode = GPIO_INTR_LOW_LEVEL; - pull_mode = GPIO_PULLUP_ONLY; - } - gpio_set_direction(i, GPIO_MODE_DEF_INPUT); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[i], PIN_FUNC_GPIO); - if (pull) { - gpio_set_pull_mode(i, pull_mode); + intr = GPIO_INTR_LOW_LEVEL; } - never_reset_pin_number(i); - // Sets interrupt type and wakeup bits. - gpio_wakeup_enable(i, interrupt_mode); - gpio_intr_enable(i); + never_reset_pin_number(pin); + gpio_wakeup_enable(pin, intr); + gpio_set_intr_type(pin, intr); + gpio_intr_enable(pin); } // Wait for any pulls to settle. mp_hal_delay_ms(50); diff --git a/ports/espressif/common-hal/alarm/touch/TouchAlarm.c b/ports/espressif/common-hal/alarm/touch/TouchAlarm.c index 5791a980d54..93756b3c2ca 100644 --- a/ports/espressif/common-hal/alarm/touch/TouchAlarm.c +++ b/ports/espressif/common-hal/alarm/touch/TouchAlarm.c @@ -17,7 +17,7 @@ static uint16_t touch_channel_mask; static volatile bool woke_up = false; void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin) { - if (pin->touch_channel == TOUCH_PAD_MAX) { + if (pin->touch_channel == NO_TOUCH_CHANNEL) { raise_ValueError_invalid_pin(); } claim_pin(pin); @@ -40,35 +40,28 @@ mp_obj_t alarm_touch_touchalarm_record_wake_alarm(void) { alarm->base.type = &alarm_touch_touchalarm_type; alarm->pin = NULL; - #if defined(CONFIG_IDF_TARGET_ESP32) - touch_pad_t wake_channel; - if (touch_pad_get_wakeup_status(&wake_channel) != ESP_OK) { - return alarm; - } - #else - touch_pad_t wake_channel = touch_pad_get_current_meas_channel(); - if (wake_channel == TOUCH_PAD_MAX) { - return alarm; - } - #endif - // Map the pin number back to a pin object. for (size_t i = 0; i < mcu_pin_globals.map.used; i++) { const mcu_pin_obj_t *pin_obj = MP_OBJ_TO_PTR(mcu_pin_globals.map.table[i].value); - if (pin_obj->touch_channel == wake_channel) { - alarm->pin = mcu_pin_globals.map.table[i].value; - break; + if (pin_obj->touch_channel != NO_TOUCH_CHANNEL) { + if ((touch_channel_mask & (1 << pin_obj->touch_channel)) != 0) { + alarm->pin = mcu_pin_globals.map.table[i].value; + break; + } } } return alarm; } -// This is used to wake the main CircuitPython task. -static void touch_interrupt(void *arg) { - (void)arg; +// This callback is used to wake the main CircuitPython task during light sleep. +static bool touch_active_callback(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx) { + (void)sens_handle; + (void)event; + (void)user_ctx; woke_up = true; port_wake_main_task_from_isr(); + return false; } void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alarms, const mp_obj_t *alarms) { @@ -81,7 +74,7 @@ void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alar mp_raise_ValueError_varg(MP_ERROR_TEXT("Only one %q can be set in deep sleep."), MP_QSTR_TouchAlarm); } touch_alarm = MP_OBJ_TO_PTR(alarms[i]); - touch_channel_mask |= 1 << touch_alarm->pin->number; + touch_channel_mask |= 1 << touch_alarm->pin->touch_channel; // Resetting the pin will set a pull-up, which we don't want. skip_reset_once_pin_number(touch_alarm->pin->number); touch_alarm_set = true; @@ -92,47 +85,76 @@ void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alar return; } - // configure interrupt for pretend to deep sleep - // this will be disabled if we actually deep sleep - - // reset touch peripheral + // Reset touch peripheral and keep it from being reset again peripherals_touch_reset(); peripherals_touch_never_reset(true); - for (uint8_t i = 1; i <= 14; i++) { - if ((touch_channel_mask & 1 << i) != 0) { - touch_pad_t touch_channel = (touch_pad_t)i; - // initialize touchpad - peripherals_touch_init(touch_channel); - - // wait for touch data to reset - mp_hal_delay_ms(10); - - // configure trigger threshold - #if defined(CONFIG_IDF_TARGET_ESP32) - uint16_t touch_value; - // ESP32 touch_pad_read() returns a lower value when a pin is touched, not a higher value - // Typical values on a Feather ESP32 V2 are 600 with a short jumper untouched, - // 70 touched. - touch_pad_read(touch_channel, &touch_value); - touch_pad_set_thresh(touch_channel, touch_value / 2); - #else - uint32_t touch_value; - touch_pad_read_benchmark(touch_channel, &touch_value); - touch_pad_set_thresh(touch_channel, touch_value / 10); // 10% - #endif + // Initialize all touch channels used for alarms + for (uint8_t i = TOUCH_MIN_CHAN_ID; i <= TOUCH_MAX_CHAN_ID; i++) { + if ((touch_channel_mask & (1 << i)) != 0) { + peripherals_touch_init(i); } } - // configure touch interrupt - #if defined(CONFIG_IDF_TARGET_ESP32) - touch_pad_isr_register(touch_interrupt, NULL); - touch_pad_intr_enable(); - #else - touch_pad_timeout_set(true, TOUCH_PAD_THRESHOLD_MAX); - touch_pad_isr_register(touch_interrupt, NULL, TOUCH_PAD_INTR_MASK_ALL); - touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); - #endif + // Wait for touch data to stabilize + mp_hal_delay_ms(10); + + // Now stop scanning and disable so we can reconfigure thresholds + touch_sensor_handle_t controller = peripherals_touch_get_controller(); + touch_sensor_stop_continuous_scanning(controller); + touch_sensor_disable(controller); + + // Configure thresholds based on initial readings + for (uint8_t i = TOUCH_MIN_CHAN_ID; i <= TOUCH_MAX_CHAN_ID; i++) { + if ((touch_channel_mask & (1 << i)) == 0) { + continue; + } + touch_channel_handle_t chan = peripherals_touch_get_handle(i); + + uint32_t benchmark = 0; + #if defined(SOC_TOUCH_SUPPORT_BENCHMARK) && SOC_TOUCH_SUPPORT_BENCHMARK + touch_channel_read_data(chan, TOUCH_CHAN_DATA_TYPE_BENCHMARK, &benchmark); + #else + touch_channel_read_data(chan, TOUCH_CHAN_DATA_TYPE_SMOOTH, &benchmark); + #endif + + #if SOC_TOUCH_SENSOR_VERSION == 1 + touch_channel_config_t chan_cfg = { + .abs_active_thresh = {(uint32_t)(benchmark / 2)}, + .charge_speed = TOUCH_CHARGE_SPEED_7, + .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, + .group = TOUCH_CHAN_TRIG_GROUP_BOTH, + }; + #elif SOC_TOUCH_SENSOR_VERSION == 2 + touch_channel_config_t chan_cfg = { + .active_thresh = {(uint32_t)(benchmark / 10)}, + .charge_speed = TOUCH_CHARGE_SPEED_7, + .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, + }; + #elif SOC_TOUCH_SENSOR_VERSION == 3 + // Values are similar to an ESP-IDF example: 1000, 2500, 5000. + touch_channel_config_t chan_cfg = { + .active_thresh = {(uint32_t)(benchmark / 10), (uint32_t)(benchmark / 4), (uint32_t)(benchmark / 2)}, + }; + #else + #error bad SOC_TOUCH_SENSOR_VERSION + #endif + touch_sensor_reconfig_channel(chan, &chan_cfg); + } + + // Set up filter for proper active/inactive detection + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + touch_sensor_config_filter(controller, &filter_cfg); + + // Register callback for light sleep wakeup + touch_event_callbacks_t callbacks = { + .on_active = touch_active_callback, + }; + touch_sensor_register_callbacks(controller, &callbacks, NULL); + + // Re-enable and start scanning + touch_sensor_enable(controller); + touch_sensor_start_continuous_scanning(controller); } void alarm_touch_touchalarm_prepare_for_deep_sleep(void) { @@ -140,45 +162,43 @@ void alarm_touch_touchalarm_prepare_for_deep_sleep(void) { return; } - touch_pad_t touch_channel = TOUCH_PAD_MAX; - for (uint8_t i = 1; i <= 14; i++) { - if ((touch_channel_mask & 1 << i) != 0) { - touch_channel = (touch_pad_t)i; + touch_sensor_handle_t controller = peripherals_touch_get_controller(); + + // Find the first alarm channel for deep sleep + int deep_slp_chan_id = -1; + for (uint8_t i = TOUCH_MIN_CHAN_ID; i <= TOUCH_MAX_CHAN_ID; i++) { + if ((touch_channel_mask & (1 << i)) != 0) { + deep_slp_chan_id = i; break; } } - // reset touch peripheral - peripherals_touch_never_reset(false); - peripherals_touch_reset(); - - // initialize touchpad - peripherals_touch_init(touch_channel); + if (deep_slp_chan_id < 0) { + return; + } - #if !defined(CONFIG_IDF_TARGET_ESP32) - // configure touchpad for sleep - touch_pad_sleep_channel_enable(touch_channel, true); - touch_pad_sleep_channel_enable_proximity(touch_channel, false); + // Stop scanning and disable to reconfigure for deep sleep + touch_sensor_stop_continuous_scanning(controller); + touch_sensor_disable(controller); + + #if SOC_TOUCH_SUPPORT_SLEEP_WAKEUP + touch_sleep_config_t sleep_cfg = { + .slp_wakeup_lvl = TOUCH_DEEP_SLEEP_WAKEUP, + #if SOC_TOUCH_SENSOR_VERSION == 1 + .deep_slp_sens_cfg = NULL, + #else + .deep_slp_allow_pd = false, + .deep_slp_chan = peripherals_touch_get_handle(deep_slp_chan_id), + .deep_slp_sens_cfg = NULL, + #endif + }; + touch_sensor_config_sleep_wakeup(controller, &sleep_cfg); #endif - // wait for touch data to reset - mp_hal_delay_ms(10); - - // configure trigger threshold - #if defined(CONFIG_IDF_TARGET_ESP32) - uint16_t touch_value; - touch_pad_read(touch_channel, &touch_value); - // ESP32 touch_pad_read() returns a lower value when a pin is touched, not a higher value - // Typical values on a Feather ESP32 V2 are 600 with a short jumper untouched, - // 70 touched. - touch_pad_set_thresh(touch_channel, touch_value / 2); - #else - uint32_t touch_value; - touch_pad_sleep_channel_read_smooth(touch_channel, &touch_value); - touch_pad_sleep_set_threshold(touch_channel, touch_value / 10); // 10% - #endif + // Re-enable for sleep + touch_sensor_enable(controller); + touch_sensor_start_continuous_scanning(controller); - // enable touchpad wakeup esp_sleep_enable_touchpad_wakeup(); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); } diff --git a/ports/espressif/common-hal/analogbufio/BufferedIn.c b/ports/espressif/common-hal/analogbufio/BufferedIn.c index aac7ad28daf..e91c8aafca8 100644 --- a/ports/espressif/common-hal/analogbufio/BufferedIn.c +++ b/ports/espressif/common-hal/analogbufio/BufferedIn.c @@ -23,7 +23,7 @@ #define NUM_SAMPLES_PER_INTERRUPT 256 #define NUM_ADC_CHANNELS 1 #define DMA_BUFFER_SIZE 1024 -#define ATTENUATION ADC_ATTEN_DB_11 +#define ATTENUATION ADC_ATTEN_DB_12 #define ADC_READ_TIMEOUT_MS 2000 #define ADC_PIN_MAX_VALUE 0xfff @@ -33,7 +33,7 @@ #elif defined(CONFIG_IDF_TARGET_ESP32S2) #define ADC_RESULT_BYTE 2 #define ADC_CONV_LIMIT_EN 0 -#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32P4) +#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32C61) #define ADC_RESULT_BYTE 4 #define ADC_CONV_LIMIT_EN 0 #elif defined(CONFIG_IDF_TARGET_ESP32S3) diff --git a/ports/espressif/common-hal/analogio/AnalogIn.c b/ports/espressif/common-hal/analogio/AnalogIn.c index 16340e91ac9..974cba8c5c9 100644 --- a/ports/espressif/common-hal/analogio/AnalogIn.c +++ b/ports/espressif/common-hal/analogio/AnalogIn.c @@ -23,15 +23,19 @@ #define DEFAULT_VREF 1100 #define NO_OF_SAMPLES 2 -#define ATTENUATION ADC_ATTEN_DB_11 +#define ATTENUATION ADC_ATTEN_DB_12 #if defined(CONFIG_IDF_TARGET_ESP32) #define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32C2) #define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32C3) #define DATA_WIDTH ADC_BITWIDTH_12 +#elif defined(CONFIG_IDF_TARGET_ESP32C5) +#define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32C6) #define DATA_WIDTH ADC_BITWIDTH_12 +#elif defined(CONFIG_IDF_TARGET_ESP32C61) +#define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32P4) #define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32S2) @@ -86,10 +90,8 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { adc_cali_scheme_ver_t supported_schemes; adc_cali_check_scheme(&supported_schemes); - #ifndef CONFIG_IDF_TARGET_ESP32P4 adc_cali_scheme_ver_t calibration_scheme = 0; adc_cali_handle_t calibration; - #endif #if defined(ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED adc_cali_curve_fitting_config_t config = { .unit_id = self->pin->adc_index, @@ -137,11 +139,7 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { // This corrects non-linear regions of the ADC range with a LUT, so it's a better reading than raw int voltage; - #ifdef CONFIG_IDF_TARGET_ESP32P4 - voltage = 0; - #else adc_cali_raw_to_voltage(calibration, adc_reading, &voltage); - #endif #if defined(ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED if (calibration_scheme == ADC_CALI_SCHEME_VER_CURVE_FITTING) { diff --git a/ports/espressif/common-hal/analogio/AnalogIn.h b/ports/espressif/common-hal/analogio/AnalogIn.h index 944039bec2a..cd5f1b5d9ef 100644 --- a/ports/espressif/common-hal/analogio/AnalogIn.h +++ b/ports/espressif/common-hal/analogio/AnalogIn.h @@ -8,7 +8,7 @@ #include "common-hal/microcontroller/Pin.h" -#include "components/hal/include/hal/adc_types.h" +#include "hal/adc_types.h" #include "FreeRTOS.h" #include "freertos/semphr.h" #include "py/obj.h" diff --git a/ports/espressif/common-hal/audiobusio/I2SOut.c b/ports/espressif/common-hal/audiobusio/I2SOut.c index adfc081389a..21b4aa829b3 100644 --- a/ports/espressif/common-hal/audiobusio/I2SOut.c +++ b/ports/espressif/common-hal/audiobusio/I2SOut.c @@ -28,7 +28,11 @@ // Caller validates that pins are free. void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); + } port_i2s_allocate_init(&self->i2s, left_justified); i2s_std_config_t i2s_config = { diff --git a/ports/espressif/common-hal/audiobusio/PDMIn.c b/ports/espressif/common-hal/audiobusio/PDMIn.c index c9d28ad7071..7718f096c89 100644 --- a/ports/espressif/common-hal/audiobusio/PDMIn.c +++ b/ports/espressif/common-hal/audiobusio/PDMIn.c @@ -40,7 +40,7 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, && bit_depth != I2S_DATA_BIT_WIDTH_16BIT && bit_depth != I2S_DATA_BIT_WIDTH_24BIT && bit_depth != I2S_DATA_BIT_WIDTH_32BIT) { - mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 8, 16, 24, or 32.")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be 8, 16, 24, or 32"), MP_QSTR_bit_depth); } i2s_chan_config_t chanConfig = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER); diff --git a/ports/espressif/common-hal/audiobusio/__init__.c b/ports/espressif/common-hal/audiobusio/__init__.c index d07a0b521ba..dae711100d3 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.c +++ b/ports/espressif/common-hal/audiobusio/__init__.c @@ -39,25 +39,32 @@ static void i2s_fill_buffer(i2s_t *self) { self->next_buffer_size = 0; return; } - while (!self->stopping && output_buffer_size > 0) { + while (output_buffer_size > 0) { if (self->sample_data == self->sample_end) { + if (self->last_buffer) { + // The final buffer has been fully output; stop now instead of + // fetching another (which for a single-buffer sample would just + // replay it). + self->stopping = true; + break; + } uint32_t sample_buffer_length; audioio_get_buffer_result_t get_buffer_result = audiosample_get_buffer(self->sample, false, 0, &self->sample_data, &sample_buffer_length); self->sample_end = self->sample_data + sample_buffer_length; + if (get_buffer_result == GET_BUFFER_ERROR || sample_buffer_length == 0) { + self->stopping = true; + break; + } if (get_buffer_result == GET_BUFFER_DONE) { if (self->loop) { audiosample_reset_buffer(self->sample, false, 0); } else { - self->stopping = true; - break; + // Output this final buffer before stopping; don't fetch again. + self->last_buffer = true; } } - if (get_buffer_result == GET_BUFFER_ERROR || sample_buffer_length == 0) { - self->stopping = true; - break; - } } size_t sample_bytecount = self->sample_end - self->sample_data; // The framecount is the minimum of space left in the output buffer or left in the incoming sample. @@ -96,6 +103,11 @@ static void i2s_fill_buffer(i2s_t *self) { output_buffer += framecount * CIRCUITPY_OUTPUT_SLOTS; output_buffer_size -= framecount * bytes_per_output_frame; } + // Sample ended mid-buffer (or was empty/errored): silence the rest so the + // DMA doesn't play stale data. + if (output_buffer_size > 0) { + memset(output_buffer, 0, output_buffer_size); + } self->next_buffer = NULL; self->next_buffer_size = 0; } @@ -108,7 +120,7 @@ static void i2s_callback_fun(void *self_in) { static bool i2s_event_interrupt(i2s_chan_handle_t handle, i2s_event_data_t *event, void *self_in) { i2s_t *self = self_in; self->underrun = self->underrun || self->next_buffer != NULL; - self->next_buffer = *(int16_t **)event->data; + self->next_buffer = (int16_t *)event->dma_buf; self->next_buffer_size = event->size; background_callback_add(&self->callback, i2s_callback_fun, self_in); return false; @@ -145,6 +157,7 @@ void port_i2s_deinit(i2s_t *self) { } void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { + audiosample_check(sample); // Pause to disable the I2S channel so we can adjust the clock. port_i2s_pause(self); self->sample = sample; @@ -172,6 +185,7 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { self->playing = true; self->paused = false; self->stopping = false; + self->last_buffer = false; // This will be slow but we can't rewind the underlying sample. So, we will // preload one frame at a time and drop the last sample that can't fit. // We cap ourselves at the max DMA set to prevent a sample drop if starting @@ -179,7 +193,7 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { uint32_t starting_frame; size_t bytes_loaded = 4; size_t preloaded = 0; - while (bytes_loaded > 0 && preloaded < CIRCUITPY_BUFFER_SIZE * CIRCUITPY_BUFFER_COUNT) { + while (bytes_loaded > 0 && preloaded < I2S_DMA_BUFFER_MAX_SIZE * CIRCUITPY_BUFFER_COUNT) { self->next_buffer = &starting_frame; self->next_buffer_size = sizeof(starting_frame); i2s_fill_buffer(self); @@ -209,6 +223,7 @@ void port_i2s_stop(i2s_t *self) { self->sample = NULL; self->playing = false; self->stopping = false; + self->last_buffer = false; } void port_i2s_pause(i2s_t *self) { diff --git a/ports/espressif/common-hal/audiobusio/__init__.h b/ports/espressif/common-hal/audiobusio/__init__.h index 0088cb87d5f..af341460e49 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.h +++ b/ports/espressif/common-hal/audiobusio/__init__.h @@ -19,6 +19,7 @@ typedef struct { bool paused; // True when the I2S channel is configured but disabled. bool playing; // True when the I2S channel is configured. bool stopping; + bool last_buffer; // True once the sample's final buffer has been fetched but not yet fully output. bool samples_signed; int8_t bytes_per_sample; int8_t channel_count; diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c new file mode 100644 index 00000000000..9a85d11f493 --- /dev/null +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -0,0 +1,449 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "bindings/espidf/__init__.h" + +#include "common-hal/audioi2sin/I2SIn.h" +#include "py/runtime.h" +#include "shared-bindings/audioi2sin/I2SIn.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audioi2sin/__init__.h" +#include "supervisor/port.h" + +#include "driver/i2s_std.h" + +#if CIRCUITPY_AUDIOI2SIN + +void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, + const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, + uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, + bool mono, bool left_justified, bool samples_signed, + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); + } + + i2s_data_bit_width_t bit_width = (i2s_data_bit_width_t)bit_depth; + + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); + esp_err_t err = i2s_new_channel(&chan_cfg, NULL, &self->rx_chan); + if (err == ESP_ERR_NOT_FOUND) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Peripheral in use")); + } + CHECK_ESP_RESULT(err); + + // Always configure the bus as stereo. The newer-family I2S peripherals + // (S2/S3/C-series) ignore I2S_SLOT_MODE_MONO on RX and write both slots + // into the DMA buffer regardless, which yields buffers that fill at 2x + // the WS rate and produces half-speed audio. By configuring stereo and + // dropping one slot ourselves in record_to_buffer, behavior is uniform + // across chips. + i2s_std_slot_config_t slot_cfg = left_justified + ? (i2s_std_slot_config_t)I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO) + : (i2s_std_slot_config_t)I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO); + + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate), + .slot_cfg = slot_cfg, + .gpio_cfg = { + .mclk = main_clock != NULL ? main_clock->number : I2S_GPIO_UNUSED, + .bclk = bit_clock->number, + .ws = word_select->number, + .dout = I2S_GPIO_UNUSED, + .din = data->number, + }, + }; + CHECK_ESP_RESULT(i2s_channel_init_std_mode(self->rx_chan, &std_cfg)); + CHECK_ESP_RESULT(i2s_channel_enable(self->rx_chan)); + + self->bit_clock = bit_clock; + self->word_select = word_select; + self->data = data; + self->mclk = main_clock; + self->sample_rate = sample_rate; + self->bit_depth = bit_depth; + self->mono = mono; + self->samples_signed = samples_signed; + + // Populate the audiosample base so I2SIn can stream into the audio pipeline. + // Streaming requires an 8- or 16-bit output depth (reset_buffer enforces it); + // the owned conversion buffer is allocated lazily on first reset_buffer(). + uint8_t channel_count = mono ? 1 : 2; + self->base.sample_rate = sample_rate; + self->base.bits_per_sample = output_bit_depth; + self->base.channel_count = channel_count; + self->base.samples_signed = samples_signed; + self->base.single_buffer = false; + self->base.max_buffer_length = + 2 * AUDIOI2SIN_STREAM_FRAMES * (output_bit_depth / 8) * channel_count; + self->output_buffer = NULL; + self->output_half_bytes = self->base.max_buffer_length / 2; + self->output_index = 0; + + claim_pin(bit_clock); + claim_pin(word_select); + claim_pin(data); + if (main_clock) { + claim_pin(main_clock); + } +} + +bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self) { + return self->data == NULL; +} + +void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self) { + if (common_hal_audioi2sin_i2sin_deinited(self)) { + return; + } + + if (self->rx_chan) { + i2s_channel_disable(self->rx_chan); + i2s_del_channel(self->rx_chan); + self->rx_chan = NULL; + } + + if (self->bit_clock) { + reset_pin_number(self->bit_clock->number); + } + self->bit_clock = NULL; + + if (self->word_select) { + reset_pin_number(self->word_select->number); + } + self->word_select = NULL; + + if (self->data) { + reset_pin_number(self->data->number); + } + self->data = NULL; + + if (self->mclk) { + reset_pin_number(self->mclk->number); + } + self->mclk = NULL; + + if (self->output_buffer != NULL) { + port_free(self->output_buffer); + self->output_buffer = NULL; + } + audiosample_mark_deinit(&self->base); +} + +// Sign-extend a raw I2S sample (in the low `in_depth` bits of `raw`) to a +// canonical int32 value. +static inline int32_t i2sin_normalize_signed(uint32_t raw, uint8_t in_depth) { + if (in_depth == 32) { + return (int32_t)raw; + } + if (in_depth == 24) { + uint32_t sign_bit = 0x800000u; + return (int32_t)((raw ^ sign_bit) - sign_bit); + } + if (in_depth == 16) { + return (int16_t)(raw & 0xffffu); + } + return (int8_t)(raw & 0xffu); +} + +// Read a single sample from the DMA scratch at the given byte offset for the +// configured input bit depth. +static inline uint32_t i2sin_read_raw(const uint8_t *src, uint8_t in_depth) { + if (in_depth == 8) { + return (uint32_t)(*src); + } + if (in_depth == 16) { + uint16_t v; + memcpy(&v, src, sizeof(v)); + return v; + } + uint32_t v; + memcpy(&v, src, sizeof(v)); + return v; +} + +// Normalize `raw` from `in_depth` for this port's wire format, then hand off to +// the shared converter to rescale `in_depth` -> `out_depth` and write it to +// `buffer` at sample index `idx`. The depth conversion + unsigned-WAV flip + +// container store live in `shared_audioi2sin_write_converted` (shared with other +// ports); see that helper for the upscale/downscale semantics. +static inline void i2sin_write_converted(void *buffer, uint32_t idx, + uint32_t raw, uint8_t in_depth, uint8_t out_depth, bool samples_signed) { + int32_t s = i2sin_normalize_signed(raw, in_depth); + shared_audioi2sin_write_converted(buffer, idx, s, in_depth, out_depth, samples_signed); +} + +// I2S delivers signed PCM. When samples_signed is false, XOR each sample with +// the sign bit for its width to convert to unsigned PCM (WAV convention). +static void i2sin_convert_to_unsigned(void *buffer, uint32_t samples, + uint8_t bit_depth, size_t element_size) { + (void)element_size; + uint32_t *p = (uint32_t *)buffer; + + if (bit_depth == 8) { + // 4 samples per word + uint32_t words = samples / 4; + for (uint32_t i = 0; i < words; i++) { + p[i] ^= 0x80808080u; + } + // tail: 0–3 leftover bytes + uint8_t *tail = (uint8_t *)(p + words); + for (uint32_t i = 0; i < (samples & 3u); i++) { + tail[i] ^= 0x80u; + } + } else if (bit_depth == 16) { + // 2 samples per word + uint32_t words = samples / 2; + for (uint32_t i = 0; i < words; i++) { + p[i] ^= 0x80008000u; + } + if (samples & 1u) { + ((uint16_t *)(p + words))[0] ^= 0x8000u; + } + } else { + // 24- or 32-bit: one sample per 32-bit slot + uint32_t mask = (bit_depth == 24) ? 0x00800000u : 0x80000000u; + for (uint32_t i = 0; i < samples; i++) { + p[i] ^= mask; + } + } +} + + +uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, + void *buffer, uint32_t length) { + size_t element_size = self->bit_depth / 8; + // 24-bit samples occupy a 32-bit slot on the I2S bus. + if (self->bit_depth == 24) { + element_size = 4; + } + + if (self->base.bits_per_sample != self->bit_depth) { + // Bit-depth conversion path: always read at input width into scratch, + // convert each sample into the user's buffer at output width. + const uint8_t in_depth = self->bit_depth; + const uint8_t out_depth = self->base.bits_per_sample; + const bool samples_signed = self->samples_signed; + uint8_t scratch[256]; + const size_t in_frame_bytes = 2 * element_size; + const size_t scratch_frames = sizeof(scratch) / in_frame_bytes; + uint32_t produced = 0; + while (produced < length) { + size_t want_frames; + if (self->mono) { + want_frames = length - produced; + } else { + want_frames = (length - produced + 1) / 2; + } + if (want_frames > scratch_frames) { + want_frames = scratch_frames; + } + size_t got_bytes = 0; + esp_err_t err = i2s_channel_read(self->rx_chan, scratch, + want_frames * in_frame_bytes, &got_bytes, portMAX_DELAY); + CHECK_ESP_RESULT(err); + size_t got_frames = got_bytes / in_frame_bytes; + for (size_t i = 0; i < got_frames && produced < length; i++) { + const uint8_t *frame = scratch + i * in_frame_bytes; + uint32_t left_raw = i2sin_read_raw(frame, in_depth); + i2sin_write_converted(buffer, produced++, left_raw, + in_depth, out_depth, samples_signed); + if (!self->mono && produced < length) { + uint32_t right_raw = i2sin_read_raw(frame + element_size, in_depth); + i2sin_write_converted(buffer, produced++, right_raw, + in_depth, out_depth, samples_signed); + } + } + if (got_frames < want_frames) { + break; + } + } + return produced; + } + + uint32_t produced; + if (!self->mono) { + size_t result = 0; + esp_err_t err = i2s_channel_read(self->rx_chan, buffer, length * element_size, + &result, portMAX_DELAY); + CHECK_ESP_RESULT(err); + produced = result / element_size; + } else { + // Mono: bus is configured stereo, so each WS frame yields two slots in + // the DMA buffer. Read in chunks into a scratch and keep only the left + // slot of each frame. + uint8_t scratch[256]; + const size_t frame_bytes = 2 * element_size; + const size_t scratch_frames = sizeof(scratch) / frame_bytes; + uint8_t *out = (uint8_t *)buffer; + produced = 0; + while (produced < length) { + size_t want_frames = length - produced; + if (want_frames > scratch_frames) { + want_frames = scratch_frames; + } + size_t got_bytes = 0; + esp_err_t err = i2s_channel_read(self->rx_chan, scratch, + want_frames * frame_bytes, &got_bytes, portMAX_DELAY); + CHECK_ESP_RESULT(err); + size_t got_frames = got_bytes / frame_bytes; + for (size_t i = 0; i < got_frames; i++) { + memcpy(out + produced * element_size, + scratch + i * frame_bytes, + element_size); + produced++; + } + if (got_frames < want_frames) { + break; + } + } + } + + if (!self->samples_signed && produced > 0) { + i2sin_convert_to_unsigned(buffer, produced, self->bit_depth, element_size); + } + return produced; +} + +uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self) { + return self->bit_depth; +} + +uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self) { + return self->sample_rate; +} + +bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self) { + return self->samples_signed; +} + +// Always false here: this port hands the capture ring to the IDF driver, which +// drops frames internally without telling us. Detecting it would require +// registering an on_recv_q_ovf callback on the channel. +bool common_hal_audioi2sin_i2sin_get_overflow(audioi2sin_i2sin_obj_t *self) { + (void)self; + return false; +} + +// Write `count` silence samples at output depth starting at sample index `idx`. +// For signed PCM silence is 0; for unsigned (WAV) it is mid-scale. +static void i2sin_fill_silence(void *buffer, uint32_t idx, uint32_t count, + uint8_t out_depth, bool samples_signed) { + if (out_depth == 8) { + uint8_t v = samples_signed ? 0 : 0x80u; + memset((uint8_t *)buffer + idx, v, count); + } else { // 16-bit (the only other streamable width) + uint16_t v = samples_signed ? 0 : 0x8000u; + uint16_t *p = (uint16_t *)buffer + idx; + for (uint32_t i = 0; i < count; i++) { + p[i] = v; + } + } +} + +// Non-blocking fill: read whatever frames are immediately available from the I2S +// driver and convert them into `buffer` (output depth, interleaved), padding the +// remainder with silence on underrun. The bus is configured stereo, so each WS +// frame yields two slots; for mono we keep the left slot. `out_depth` is always 8 +// or 16 here (reset_buffer rejects 24/32). Runs in the output backend's refill +// (background callback) context, so i2s_channel_read is called with a 0 ms +// timeout and never blocks. +void common_hal_audioi2sin_i2sin_fill_buffer(audioi2sin_i2sin_obj_t *self, + uint8_t *buffer, uint32_t frames) { + const uint8_t in_depth = self->bit_depth; + const uint8_t out_depth = self->base.bits_per_sample; + const bool samples_signed = self->samples_signed; + const bool stereo = !self->mono; + const uint8_t channel_count = stereo ? 2 : 1; + size_t element_size = (in_depth == 24) ? 4 : (in_depth / 8); + const size_t in_frame_bytes = 2 * element_size; // bus is always stereo + const uint32_t total_samples = frames * channel_count; + + uint8_t scratch[256]; + const size_t scratch_frames = sizeof(scratch) / in_frame_bytes; + + uint32_t produced = 0; + while (produced < total_samples) { + size_t want_frames = (total_samples - produced + channel_count - 1) / channel_count; + if (want_frames > scratch_frames) { + want_frames = scratch_frames; + } + size_t got_bytes = 0; + // 0 ms timeout: return immediately with whatever is buffered. + esp_err_t err = i2s_channel_read(self->rx_chan, scratch, + want_frames * in_frame_bytes, &got_bytes, 0); + if (err != ESP_OK && err != ESP_ERR_TIMEOUT) { + break; + } + size_t got_frames = got_bytes / in_frame_bytes; + if (got_frames == 0) { + break; // underrun: pad with silence below + } + for (size_t i = 0; i < got_frames && produced < total_samples; i++) { + const uint8_t *frame = scratch + i * in_frame_bytes; + uint32_t left_raw = i2sin_read_raw(frame, in_depth); + i2sin_write_converted(buffer, produced++, left_raw, + in_depth, out_depth, samples_signed); + if (stereo && produced < total_samples) { + uint32_t right_raw = i2sin_read_raw(frame + element_size, in_depth); + i2sin_write_converted(buffer, produced++, right_raw, + in_depth, out_depth, samples_signed); + } + } + if (got_frames < want_frames) { + break; + } + } + if (produced < total_samples) { + i2sin_fill_silence(buffer, produced, total_samples - produced, + out_depth, samples_signed); + } +} + +void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, + bool single_channel_output, uint8_t channel) { + (void)single_channel_output; + (void)channel; + // The audio pipeline only carries 8- or 16-bit samples; 24/32-bit modes can + // still record() but cannot stream. + if (self->base.bits_per_sample != 8 && self->base.bits_per_sample != 16) { + mp_raise_ValueError_varg( + MP_ERROR_TEXT("%q must be 8 or 16"), MP_QSTR_output_bit_depth); + } + if (self->output_buffer == NULL) { + self->output_buffer = (uint8_t *)port_malloc(self->base.max_buffer_length, false); + if (self->output_buffer == NULL) { + m_malloc_fail(self->base.max_buffer_length); + } + } + self->output_index = 0; +} + +audioio_get_buffer_result_t common_hal_audioi2sin_i2sin_get_buffer( + audioi2sin_i2sin_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + uint32_t half = self->output_half_bytes; + uint8_t *out = self->output_buffer + half * self->output_index; + self->output_index = 1 - self->output_index; + + uint32_t bytes_per_sample = self->base.bits_per_sample / 8; + uint32_t frames = half / (bytes_per_sample * self->base.channel_count); + common_hal_audioi2sin_i2sin_fill_buffer(self, out, frames); + + if (single_channel_output) { + out += (channel % self->base.channel_count) * bytes_per_sample; + } + *buffer = out; + *buffer_length = half; + // A live mic is an infinite stream; never report DONE or the backend stops. + return GET_BUFFER_MORE_DATA; +} + +#endif // CIRCUITPY_AUDIOI2SIN diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.h b/ports/espressif/common-hal/audioi2sin/I2SIn.h new file mode 100644 index 00000000000..a6fc7224c32 --- /dev/null +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.h @@ -0,0 +1,43 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" + +#include "shared-module/audiocore/__init__.h" + +#include "driver/i2s_std.h" + +#if CIRCUITPY_AUDIOI2SIN + +// Frames handed to the output backend per get_buffer() call; see the matching +// rp2 header for the rationale. +#define AUDIOI2SIN_STREAM_FRAMES (256) + +typedef struct { + // so I2SIn can be used directly as an audiosample source. + audiosample_base_t base; + i2s_chan_handle_t rx_chan; + const mcu_pin_obj_t *bit_clock; + const mcu_pin_obj_t *word_select; + const mcu_pin_obj_t *data; + const mcu_pin_obj_t *mclk; + uint32_t sample_rate; + uint8_t bit_depth; + bool mono; + bool samples_signed; + // Owned double-buffer of converted (output-depth, interleaved) samples, + // allocated lazily on first reset_buffer(). base.max_buffer_length is the + // whole buffer; get_buffer() returns output_half_bytes of it. + uint8_t *output_buffer; + size_t output_half_bytes; + uint8_t output_index; +} audioi2sin_i2sin_obj_t; + +#endif diff --git a/ports/espressif/common-hal/audioi2sin/__init__.c b/ports/espressif/common-hal/audioi2sin/__init__.c new file mode 100644 index 00000000000..584c821b996 --- /dev/null +++ b/ports/espressif/common-hal/audioi2sin/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT diff --git a/ports/espressif/common-hal/audioio/AudioOut.c b/ports/espressif/common-hal/audioio/AudioOut.c index fb8c862ba07..e6aed580e27 100644 --- a/ports/espressif/common-hal/audioio/AudioOut.c +++ b/ports/espressif/common-hal/audioio/AudioOut.c @@ -573,6 +573,8 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, mp_raise_RuntimeError(MP_ERROR_TEXT("already playing")); } + audiosample_check(sample); + size_t samples_size; uint8_t channel_count; bool samples_signed; diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index 98c453ba3c0..30f16276eae 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -9,7 +9,8 @@ #include "py/mphal.h" #include "py/runtime.h" -#include "components/driver/i2c/include/driver/i2c.h" +#include "driver/gpio.h" +#include "soc/soc_caps.h" #include "bindings/espidf/__init__.h" #include "shared-bindings/microcontroller/__init__.h" @@ -88,6 +89,19 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, } CHECK_ESP_RESULT(result); + // Record which port the auto-selected bus landed on. There is no public accessor to map + // a bus handle back to its port, so match the handle against each initialized port. + // Other code (e.g. espcamera) needs the port number to reuse this same bus rather than + // create a second master bus on the same pins. + self->port = -1; + for (i2c_port_num_t port = 0; port < (int)SOC_HP_I2C_NUM; port++) { + i2c_master_bus_handle_t bus_handle; + if (i2c_master_get_bus_handle(port, &bus_handle) == ESP_OK && bus_handle == self->handle) { + self->port = port; + break; + } + } + self->xSemaphore = xSemaphoreCreateMutex(); if (self->xSemaphore == NULL) { i2c_del_master_bus(self->handle); @@ -128,6 +142,12 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { i2c_del_master_bus(self->handle); self->handle = NULL; + // Release the mutex before we delete it. Otherwise FreeRTOS gets unhappy. + xSemaphoreGive(self->xSemaphore); + vSemaphoreDelete(self->xSemaphore); + self->xSemaphore = NULL; + self->has_lock = false; + common_hal_reset_pin(self->sda_pin); common_hal_reset_pin(self->scl_pin); common_hal_busio_i2c_mark_deinit(self); @@ -160,20 +180,23 @@ bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { } void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return; + } xSemaphoreGive(self->xSemaphore); self->has_lock = false; } -static uint8_t convert_esp_err(esp_err_t result) { +static mp_negative_errno_t convert_esp_err(esp_err_t result) { switch (result) { case ESP_OK: return 0; case ESP_FAIL: - return MP_ENODEV; + return -MP_ENODEV; case ESP_ERR_TIMEOUT: - return MP_ETIMEDOUT; + return -MP_ETIMEDOUT; default: - return MP_EIO; + return -MP_EIO; } } @@ -184,7 +207,7 @@ static size_t _transaction_duration_ms(size_t frequency, size_t len) { return (len + 1) / bytes_per_ms + 1000; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = addr, @@ -197,7 +220,7 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const u return convert_esp_err(result); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = addr, @@ -210,7 +233,7 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t return convert_esp_err(result); } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, diff --git a/ports/espressif/common-hal/busio/I2C.h b/ports/espressif/common-hal/busio/I2C.h index 25d9791f252..ef69cba7091 100644 --- a/ports/espressif/common-hal/busio/I2C.h +++ b/ports/espressif/common-hal/busio/I2C.h @@ -8,7 +8,7 @@ #include "common-hal/microcontroller/Pin.h" -#include "components/hal/include/hal/i2c_types.h" +#include "hal/i2c_types.h" #include "FreeRTOS.h" #include "freertos/semphr.h" #include "py/obj.h" @@ -22,6 +22,7 @@ typedef struct { size_t timeout_ms; size_t frequency; i2c_master_bus_handle_t handle; + i2c_port_num_t port; SemaphoreHandle_t xSemaphore; bool has_lock; } busio_i2c_obj_t; diff --git a/ports/espressif/common-hal/busio/SPI.c b/ports/espressif/common-hal/busio/SPI.c index 6439ca41129..b85f8cddd2a 100644 --- a/ports/espressif/common-hal/busio/SPI.c +++ b/ports/espressif/common-hal/busio/SPI.c @@ -16,42 +16,76 @@ #define SPI_MAX_DMA_BITS (SPI_MAX_DMA_LEN * 8) #define MAX_SPI_TRANSACTIONS 10 -static bool spi_never_reset[SOC_SPI_PERIPH_NUM]; static spi_device_handle_t spi_handle[SOC_SPI_PERIPH_NUM]; -static StaticSemaphore_t spi_mutex[SOC_SPI_PERIPH_NUM]; static bool spi_bus_is_free(spi_host_device_t host_id) { return spi_bus_get_attr(host_id) == NULL; } -void spi_reset(void) { - for (spi_host_device_t host_id = SPI2_HOST; host_id < SOC_SPI_PERIPH_NUM; host_id++) { - if (spi_never_reset[host_id]) { - continue; - } - if (!spi_bus_is_free(host_id)) { - spi_bus_remove_device(spi_handle[host_id]); - spi_bus_free(host_id); - } +// Add a throwaway device at the given target clock, ask the driver what +// frequency it would actually produce, then remove it. Returns the actual +// frequency in Hz, or -1 if a device could not be added at that target. +static int spi_probe_actual_freq(busio_spi_obj_t *self, + spi_device_interface_config_t *device_config, int target_hz) { + device_config->clock_speed_hz = target_hz; + spi_device_handle_t handle; + if (spi_bus_add_device(self->host_id, device_config, &handle) != ESP_OK) { + return -1; } + int freq_khz = 0; + spi_device_get_actual_freq(handle, &freq_khz); + spi_bus_remove_device(handle); + return freq_khz * 1000; } static void set_spi_config(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { - // 128 is a 50% duty cycle. - const int closest_clock = spi_get_actual_clock(APB_CLK_FREQ, baudrate, 128); - const spi_device_interface_config_t device_config = { - .clock_speed_hz = closest_clock, + spi_device_interface_config_t device_config = { + .clock_speed_hz = baudrate, .mode = phase | (polarity << 1), .spics_io_num = -1, // No CS pin .queue_size = MAX_SPI_TRANSACTIONS, .pre_cb = NULL }; + + // The ESP-IDF driver rounds clock_speed_hz to the nearest frequency it can + // produce, which may be HIGHER than requested. Treat baudrate as a ceiling: + // probe candidate targets (each time adding a throwaway device, asking the + // driver what it actually produced, and removing it) and keep the highest + // target whose actual frequency does not exceed baudrate. We don't inspect + // divisor internals -- those vary between Espressif chips -- only the + // public add/measure/remove API. + int target = baudrate; + int actual = spi_probe_actual_freq(self, &device_config, target); + if (actual < 0 || actual > (int)baudrate) { + // Bisect for the highest target whose actual frequency is <= baudrate. + // Stop refining once the interval is within 1 kHz, the resolution that + // spi_device_get_actual_freq reports. + int lo = 1; + int hi = baudrate; + while (hi - lo > 1000) { + int mid = lo + (hi - lo) / 2; + int mid_actual = spi_probe_actual_freq(self, &device_config, mid); + if (mid_actual >= 0 && mid_actual <= (int)baudrate) { + lo = mid; + } else { + hi = mid; + } + } + target = lo; + } + + device_config.clock_speed_hz = target; esp_err_t result = spi_bus_add_device(self->host_id, &device_config, &spi_handle[self->host_id]); if (result != ESP_OK) { mp_raise_RuntimeError(MP_ERROR_TEXT("SPI configuration failed")); } - self->baudrate = closest_clock; + + // Report the frequency the driver actually settled on for the real device. + int actual_khz = 0; + spi_device_get_actual_freq(spi_handle[self->host_id], &actual_khz); + self->baudrate = actual_khz * 1000; + self->requested_baudrate = baudrate; self->polarity = polarity; self->phase = phase; self->bits = bits; @@ -61,6 +95,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + const spi_bus_config_t bus_config = { .mosi_io_num = mosi != NULL ? mosi->number : -1, .miso_io_num = miso != NULL ? miso->number : -1, @@ -90,6 +127,12 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, raise_ValueError_invalid_pins(); } + self->mutex = xSemaphoreCreateMutex(); + if (self->mutex == NULL) { + spi_bus_free(self->host_id); + mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to create lock")); + } + set_spi_config(self, 250000, 0, 0, 8); self->MOSI = mosi; @@ -103,12 +146,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, claim_pin(miso); } claim_pin(clock); - - self->mutex = xSemaphoreCreateMutexStatic(&spi_mutex[self->host_id]); } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - spi_never_reset[self->host_id] = true; common_hal_never_reset_pin(self->clock); if (self->MOSI != NULL) { common_hal_never_reset_pin(self->MOSI); @@ -122,6 +162,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -132,11 +176,10 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { RUN_BACKGROUND_TASKS; } - // Mark us as deinit early in case we are used in an interrupt. + // Mark as deinit early in case we are used in an interrupt. common_hal_reset_pin(self->clock); - self->clock = NULL; + common_hal_busio_spi_mark_deinit(self); - spi_never_reset[self->host_id] = false; spi_bus_remove_device(spi_handle[self->host_id]); spi_bus_free(self->host_id); @@ -151,7 +194,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { - if (baudrate == self->baudrate && + if (baudrate == self->requested_baudrate && polarity == self->polarity && phase == self->phase && bits == self->bits) { @@ -162,19 +205,27 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, return true; } -bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { +// Wait as long as needed for the lock. This is used by SD card access from USB. +// Overrides the default busy-wait implementation in shared-bindings/busio/SPI.c +bool common_hal_busio_spi_wait_for_lock(busio_spi_obj_t *self, uint32_t timeout_ms) { if (common_hal_busio_spi_deinited(self)) { return false; } - return xSemaphoreTake(self->mutex, 1) == pdTRUE; + return xSemaphoreTake(self->mutex, pdMS_TO_TICKS(timeout_ms)) == pdTRUE; +} + +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + return common_hal_busio_spi_wait_for_lock(self, 0); } bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { - return self->mutex != NULL && xSemaphoreGetMutexHolder(self->mutex) == xTaskGetCurrentTaskHandle(); + return (self->mutex != NULL) && (xSemaphoreGetMutexHolder(self->mutex) == xTaskGetCurrentTaskHandle()); } void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { - xSemaphoreGive(self->mutex); + if (self->mutex != NULL) { + xSemaphoreGive(self->mutex); + } } bool common_hal_busio_spi_write(busio_spi_obj_t *self, diff --git a/ports/espressif/common-hal/busio/SPI.h b/ports/espressif/common-hal/busio/SPI.h index 820f29333c7..4886ab173ab 100644 --- a/ports/espressif/common-hal/busio/SPI.h +++ b/ports/espressif/common-hal/busio/SPI.h @@ -21,9 +21,8 @@ typedef struct { uint8_t bits; uint8_t phase; uint8_t polarity; - uint32_t baudrate; + uint32_t baudrate; // Actual frequency, reported by the frequency property. + uint32_t requested_baudrate; // Value passed to configure(); used for the cache-hit check. SemaphoreHandle_t mutex; } busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/espressif/common-hal/busio/UART.c b/ports/espressif/common-hal/busio/UART.c index ad5e6fcef1b..01c8321843a 100644 --- a/ports/espressif/common-hal/busio/UART.c +++ b/ports/espressif/common-hal/busio/UART.c @@ -140,7 +140,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, uart_config.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS; } else if (have_rts) { uart_config.flow_ctrl = UART_HW_FLOWCTRL_RTS; - } else if (have_rts) { + } else if (have_cts) { uart_config.flow_ctrl = UART_HW_FLOWCTRL_CTS; } diff --git a/ports/espressif/common-hal/digitalio/DigitalInOut.c b/ports/espressif/common-hal/digitalio/DigitalInOut.c index ed537419405..e4272ba1ff5 100644 --- a/ports/espressif/common-hal/digitalio/DigitalInOut.c +++ b/ports/espressif/common-hal/digitalio/DigitalInOut.c @@ -11,8 +11,11 @@ #include "hal/gpio_hal.h" static bool _pin_is_input(uint8_t pin_number) { - const uint32_t iomux = READ_PERI_REG(GPIO_PIN_MUX_REG[pin_number]); - return (iomux & FUN_IE) != 0; + gpio_io_config_t config; + if (gpio_get_io_config((gpio_num_t)pin_number, &config) != ESP_OK) { + return false; + } + return config.ie; } void digitalio_digitalinout_preserve_for_deep_sleep(size_t n_dios, digitalio_digitalinout_obj_t *preserve_dios[]) { @@ -113,10 +116,12 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode( digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( digitalio_digitalinout_obj_t *self) { - if (GPIO_HAL_GET_HW(GPIO_PORT_0)->pin[self->pin->number].pad_driver == 1) { + gpio_io_config_t config; + if (gpio_get_io_config((gpio_num_t)self->pin->number, &config) != ESP_OK) { + // Should it fail closed or open? return DRIVE_MODE_OPEN_DRAIN; } - return DRIVE_MODE_PUSH_PULL; + return config.od ? DRIVE_MODE_OPEN_DRAIN : DRIVE_MODE_PUSH_PULL; } digitalinout_result_t common_hal_digitalio_digitalinout_set_pull( @@ -134,11 +139,10 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_pull( digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( digitalio_digitalinout_obj_t *self) { - gpio_num_t gpio_num = self->pin->number; - if (REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU)) { - return PULL_UP; - } else if (REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD)) { - return PULL_DOWN; + gpio_io_config_t config; + if (gpio_get_io_config((gpio_num_t)self->pin->number, &config) != ESP_OK) { + // Should it fail closed or open? + return PULL_NONE; } - return PULL_NONE; + return config.pd ? PULL_DOWN : PULL_UP; } diff --git a/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c b/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c index 591c455722e..5df379432a9 100644 --- a/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +++ b/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c @@ -14,7 +14,7 @@ #include "hal/dma_types.h" #include "hal/lcd_hal.h" #include "hal/lcd_ll.h" -#include "soc/lcd_periph.h" +#include "hal/lcd_periph.h" #include "esp_log.h" #define TAG "LCD" @@ -109,8 +109,7 @@ void common_hal_dotclockframebuffer_framebuffer_construct(dotclockframebuffer_fr cfg->timings.flags.pclk_idle_high = pclk_idle_high; cfg->data_width = 16; - cfg->sram_trans_align = 8; - cfg->psram_trans_align = 64; + cfg->dma_burst_size = 64; cfg->hsync_gpio_num = valid_pin(hsync, MP_QSTR_hsync); cfg->vsync_gpio_num = valid_pin(vsync, MP_QSTR_vsync); cfg->de_gpio_num = valid_pin(de, MP_QSTR_de); diff --git a/ports/espressif/common-hal/espcamera/Camera.c b/ports/espressif/common-hal/espcamera/Camera.c index 5b45a26951e..c8f693fa3f1 100644 --- a/ports/espressif/common-hal/espcamera/Camera.c +++ b/ports/espressif/common-hal/espcamera/Camera.c @@ -21,6 +21,11 @@ #error espcamera only works on boards configured with spiram, disable it in mpconfigboard.mk #endif +// The underlying esp-camera driver only handles a singleton camera. +// Track it here so it can be reset, releasing its +// device on the shared I2C bus, before the I2C bus is deinited. +static espcamera_camera_obj_t *live_camera = NULL; + static void i2c_lock(espcamera_camera_obj_t *self) { if (common_hal_busio_i2c_deinited(self->i2c)) { raise_deinited_error(); @@ -86,7 +91,11 @@ void common_hal_espcamera_camera_construct( self->camera_config.pin_reset = reset_pin ? common_hal_mcu_pin_number(reset_pin) : NO_PIN; self->camera_config.pin_xclk = external_clock_pin ? common_hal_mcu_pin_number(external_clock_pin) : NO_PIN; - self->camera_config.sccb_i2c_master_bus_handle = self->i2c->handle; + // Reuse the I2C bus that CircuitPython already created on these pins instead of letting + // esp32-camera create a second master bus on the same pins, which doesn't work. + self->camera_config.pin_sccb_sda = -1; + self->camera_config.pin_sccb_scl = -1; + self->camera_config.sccb_i2c_port = i2c->port; self->camera_config.pin_d7 = data_pins[7]; self->camera_config.pin_d6 = data_pins[6]; @@ -116,6 +125,16 @@ void common_hal_espcamera_camera_construct( i2c_unlock(self); CHECK_ESP_RESULT(result); + + // Only record the camera once esp_camera_init() has succeeded, so a failed + // second construction doesn't overwrite the live singleton. + live_camera = self; +} + +void espcamera_reset(void) { + if (live_camera != NULL) { + common_hal_espcamera_camera_deinit(live_camera); + } } extern void common_hal_espcamera_camera_deinit(espcamera_camera_obj_t *self) { @@ -123,6 +142,14 @@ extern void common_hal_espcamera_camera_deinit(espcamera_camera_obj_t *self) { return; } + // Only tear down the shared esp-camera driver if this object owns it. A + // second, failed construction leaves live_camera pointing at the first + // camera; deiniting that failed object must not destroy the live one. + bool was_live = (live_camera == self); + if (was_live) { + live_camera = NULL; + } + common_hal_pwmio_pwmout_deinit(&self->pwm); // Does nothing if pin is NO_PIN (-1). @@ -139,7 +166,9 @@ extern void common_hal_espcamera_camera_deinit(espcamera_camera_obj_t *self) { reset_pin_number(self->camera_config.pin_d1); reset_pin_number(self->camera_config.pin_d0); - esp_camera_deinit(); + if (was_live) { + esp_camera_deinit(); + } reset_pin_number(self->camera_config.pin_pclk); reset_pin_number(self->camera_config.pin_vsync); @@ -153,7 +182,7 @@ bool common_hal_espcamera_camera_deinited(espcamera_camera_obj_t *self) { } bool common_hal_espcamera_camera_available(espcamera_camera_obj_t *self) { - return esp_camera_fb_available(); + return esp_camera_available_frames(); } camera_fb_t *common_hal_espcamera_camera_take(espcamera_camera_obj_t *self, int timeout_ms) { diff --git a/ports/espressif/common-hal/espcamera/Camera.h b/ports/espressif/common-hal/espcamera/Camera.h index 718fe9a69c4..dd099558aa6 100644 --- a/ports/espressif/common-hal/espcamera/Camera.h +++ b/ports/espressif/common-hal/espcamera/Camera.h @@ -18,3 +18,7 @@ typedef struct espcamera_camera_obj { pwmio_pwmout_obj_t pwm; busio_i2c_obj_t *i2c; } espcamera_obj_t; + +// Deinitialize the active camera, if any, so it releases its device on the +// shared I2C bus. Called from reset_port_early(). +void espcamera_reset(void); diff --git a/ports/espressif/common-hal/espidf/__init__.c b/ports/espressif/common-hal/espidf/__init__.c index 83e30657750..bfb50a04ec7 100644 --- a/ports/espressif/common-hal/espidf/__init__.c +++ b/ports/espressif/common-hal/espidf/__init__.c @@ -27,7 +27,8 @@ static size_t psram_size_usable(void) { #ifdef CONFIG_SPIRAM /* PSRAM chip may be larger than the size we can map into address space */ - #ifdef CONFIG_IDF_TARGET_ESP32P4 + #if defined(CONFIG_IDF_TARGET_ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32C5) + // These targets don't define SOC_EXTRAM_DATA_SIZE. size_t s = esp_psram_get_size(); #else size_t s = MIN(esp_psram_get_size(), SOC_EXTRAM_DATA_SIZE); diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index 79bded96fb4..eb3b57174a3 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -17,6 +17,7 @@ #include "common-hal/espnow/ESPNow.h" +#include "esp_now.h" #include "mphalport.h" #include "esp_now.h" @@ -56,7 +57,7 @@ typedef struct { // 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, esp_now_send_status_t status) { +static void send_cb(const esp_now_send_info_t *tx_info, esp_now_send_status_t status) { espnow_obj_t *self = MP_STATE_PORT(espnow_singleton); if (status == ESP_NOW_SEND_SUCCESS) { self->send_success++; @@ -119,10 +120,20 @@ void common_hal_espnow_init(espnow_obj_t *self) { common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); } - CHECK_ESP_RESULT(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, self->phy_rate)); - CHECK_ESP_RESULT(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, self->phy_rate)); - CHECK_ESP_RESULT(esp_now_init()); + + // esp_now_set_peer_rate_config() is poorly documented, and we haven't figured out + // what the esp_now_rate_config_t settings should be. For now, just ignore phy_rate. + // Note that esp_now_set_peer_rate_config() must be called after esp_now-init(). + // + // esp_now_rate_config_t rate_config = { + // .phymode = WIFI_PHY_MODE_LR, + // .rate = self->phy_rate, + // .ersu = false, + // .dcm = false, + // }; + // CHECK_ESP_RESULT(esp_now_set_peer_rate_config(NULL, &rate_config)); + CHECK_ESP_RESULT(esp_now_register_send_cb(send_cb)); CHECK_ESP_RESULT(esp_now_register_recv_cb(recv_cb)); } diff --git a/ports/espressif/common-hal/i2ctarget/I2CTarget.c b/ports/espressif/common-hal/i2ctarget/I2CTarget.c index 003e7731faa..648f71e6953 100644 --- a/ports/espressif/common-hal/i2ctarget/I2CTarget.c +++ b/ports/espressif/common-hal/i2ctarget/I2CTarget.c @@ -12,6 +12,19 @@ #include "common-hal/i2ctarget/I2CTarget.h" #include "shared-bindings/microcontroller/Pin.h" +static bool i2c_slave_on_receive(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_rx_done_event_data_t *evt_data, void *arg) { + i2ctarget_i2c_target_obj_t *self = (i2ctarget_i2c_target_obj_t *)arg; + for (uint32_t i = 0; i < evt_data->length; i++) { + uint16_t next_head = (self->recv_head + 1) % I2CTARGET_RECV_BUF_SIZE; + if (next_head == self->recv_tail) { + break; // buffer full + } + self->recv_buf[self->recv_head] = evt_data->buffer[i]; + self->recv_head = next_head; + } + return false; +} + void common_hal_i2ctarget_i2c_target_construct(i2ctarget_i2c_target_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint8_t *addresses, unsigned int num_addresses, bool smbus) { @@ -31,32 +44,40 @@ void common_hal_i2ctarget_i2c_target_construct(i2ctarget_i2c_target_obj_t *self, self->sda_pin = sda; self->scl_pin = scl; - self->i2c_num = peripherals_i2c_get_free_num(); - if (self->i2c_num == I2C_NUM_MAX) { - mp_raise_ValueError(MP_ERROR_TEXT("All I2C peripherals are in use")); - } - - const i2c_config_t i2c_conf = { - .mode = I2C_MODE_SLAVE, - .sda_io_num = self->sda_pin->number, - .scl_io_num = self->scl_pin->number, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .slave.addr_10bit_en = 0, - .slave.slave_addr = self->addresses[0], + self->recv_head = 0; + self->recv_tail = 0; + + i2c_slave_config_t slave_config = { + .i2c_port = -1, // auto + .sda_io_num = sda->number, + .scl_io_num = scl->number, + .clk_source = I2C_CLK_SRC_DEFAULT, + .send_buf_depth = 256, + .receive_buf_depth = 256, + .slave_addr = addresses[0], + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .flags = { + .enable_internal_pullup = true, + }, }; - // Initialize I2C. - esp_err_t err = peripherals_i2c_init(self->i2c_num, &i2c_conf); + esp_err_t err = i2c_new_slave_device(&slave_config, &self->handle); if (err != ESP_OK) { - if (err == ESP_FAIL) { + if (err == ESP_ERR_NOT_FOUND) { + mp_raise_ValueError(MP_ERROR_TEXT("All I2C peripherals are in use")); + } else if (err == ESP_FAIL) { mp_raise_OSError(MP_EIO); } else { mp_arg_error_invalid(MP_QSTR_I2CTarget); } } + i2c_slave_event_callbacks_t cbs = { + .on_receive = i2c_slave_on_receive, + }; + i2c_slave_register_event_callbacks(self->handle, &cbs, self); + claim_pin(sda); claim_pin(scl); } @@ -70,7 +91,8 @@ void common_hal_i2ctarget_i2c_target_deinit(i2ctarget_i2c_target_obj_t *self) { return; } - peripherals_i2c_deinit(self->i2c_num); + i2c_del_slave_device(self->handle); + self->handle = NULL; common_hal_reset_pin(self->sda_pin); common_hal_reset_pin(self->scl_pin); @@ -83,24 +105,34 @@ int common_hal_i2ctarget_i2c_target_is_addressed(i2ctarget_i2c_target_obj_t *sel *address = self->addresses[0]; *is_read = true; *is_restart = false; - return 1; + // Check if we have received data + if (self->recv_head != self->recv_tail) { + *is_read = false; + return 1; + } + return 0; } int common_hal_i2ctarget_i2c_target_read_byte(i2ctarget_i2c_target_obj_t *self, uint8_t *data) { - i2c_slave_read_buffer(self->i2c_num, data, 128, 0); + if (self->recv_head == self->recv_tail) { + return 0; // no data available + } + *data = self->recv_buf[self->recv_tail]; + self->recv_tail = (self->recv_tail + 1) % I2CTARGET_RECV_BUF_SIZE; return 1; } int common_hal_i2ctarget_i2c_target_write_byte(i2ctarget_i2c_target_obj_t *self, uint8_t data) { - i2c_reset_tx_fifo(self->i2c_num); - i2c_slave_write_buffer(self->i2c_num, &data, 128, 0); + uint32_t write_len; + esp_err_t err = i2c_slave_write(self->handle, &data, 1, &write_len, 100); + if (err != ESP_OK || write_len == 0) { + return 0; + } return 1; } void common_hal_i2ctarget_i2c_target_ack(i2ctarget_i2c_target_obj_t *self, bool ack) { - } void common_hal_i2ctarget_i2c_target_close(i2ctarget_i2c_target_obj_t *self) { - } diff --git a/ports/espressif/common-hal/i2ctarget/I2CTarget.h b/ports/espressif/common-hal/i2ctarget/I2CTarget.h index 2dcfb581eb3..fc41ac84ebc 100644 --- a/ports/espressif/common-hal/i2ctarget/I2CTarget.h +++ b/ports/espressif/common-hal/i2ctarget/I2CTarget.h @@ -7,14 +7,19 @@ #pragma once #include "py/obj.h" -#include "peripherals/i2c.h" +#include "driver/i2c_slave.h" #include "common-hal/microcontroller/Pin.h" +#define I2CTARGET_RECV_BUF_SIZE 128 + typedef struct { mp_obj_base_t base; - i2c_port_t i2c_num; + i2c_slave_dev_handle_t handle; uint8_t *addresses; uint8_t num_addresses; const mcu_pin_obj_t *scl_pin; const mcu_pin_obj_t *sda_pin; + uint8_t recv_buf[I2CTARGET_RECV_BUF_SIZE]; + volatile uint16_t recv_head; + volatile uint16_t recv_tail; } i2ctarget_i2c_target_obj_t; diff --git a/ports/espressif/common-hal/mdns/RemoteService.c b/ports/espressif/common-hal/mdns/RemoteService.c index 515a3f7bf02..3d80199397e 100644 --- a/ports/espressif/common-hal/mdns/RemoteService.c +++ b/ports/espressif/common-hal/mdns/RemoteService.c @@ -9,56 +9,27 @@ #include "shared-bindings/ipaddress/IPv4Address.h" const char *common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return ""; - } - return self->result->service_type; + return self->service_name; } const char *common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return ""; - } - return self->result->proto; + return self->protocol; } const char *common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return ""; - } - return self->result->instance_name; + return self->instance_name; } const char *common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return ""; - } - return self->result->hostname; + return self->hostname; } mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return 0; - } - return self->result->port; + return self->port; } uint32_t mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self) { - if (self->result == NULL || - self->result->ip_protocol != MDNS_IP_PROTOCOL_V4 || - self->result->addr == NULL) { - return 0; - } - mdns_ip_addr_t *cur = self->result->addr; - while (cur != NULL) { - if (cur->addr.type == ESP_IPADDR_TYPE_V4) { - return cur->addr.u_addr.ip4.addr; - } - - cur = cur->next; - } - - return 0; + return self->ipv4_address; } mp_obj_t common_hal_mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self) { @@ -68,8 +39,3 @@ mp_obj_t common_hal_mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t } return common_hal_ipaddress_new_ipv4address(addr); } - -void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self) { - mdns_query_results_free(self->result); - self->result = NULL; -} diff --git a/ports/espressif/common-hal/mdns/RemoteService.h b/ports/espressif/common-hal/mdns/RemoteService.h index 6fb3000c7d1..89ff69be29d 100644 --- a/ports/espressif/common-hal/mdns/RemoteService.h +++ b/ports/espressif/common-hal/mdns/RemoteService.h @@ -8,7 +8,15 @@ #include "mdns.h" +// The IDF's mdns_result_t lives on the IDF heap and is only valid while mdns +// is inited. Copy what we need into the object instead so that the object's +// lifetime is independent of the mdns.Server's. typedef struct { mp_obj_base_t base; - mdns_result_t *result; + uint32_t ipv4_address; + uint16_t port; + char protocol[5]; // RFC 6763 Section 7.2 - 4 bytes + 1 for NUL + char service_name[17]; // RFC 6763 Section 7.2 - 16 bytes + 1 for NUL + char instance_name[64]; // RFC 6763 Section 7.2 - 63 bytes + 1 for NUL + char hostname[64]; // RFC 6762 Appendix A - 63 bytes for label + 1 for NUL } mdns_remoteservice_obj_t; diff --git a/ports/espressif/common-hal/mdns/Server.c b/ports/espressif/common-hal/mdns/Server.c index e8c34ee0885..7eaa9a442a2 100644 --- a/ports/espressif/common-hal/mdns/Server.c +++ b/ports/espressif/common-hal/mdns/Server.c @@ -6,6 +6,8 @@ #include "shared-bindings/mdns/Server.h" +#include + #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/mdns/RemoteService.h" @@ -18,6 +20,13 @@ // could be created.) static mdns_server_obj_t *_active_object = NULL; +// strlcpy(), but a NULL src yields an empty string instead of undefined +// behavior. The IDF leaves mdns_result_t fields NULL when a query didn't +// resolve them. +static void strlcpy_or_empty(char *dest, const char *src, size_t dest_len) { + strlcpy(dest, src == NULL ? "" : src, dest_len); +} + void mdns_server_construct(mdns_server_obj_t *self, bool workflow) { if (_active_object != NULL) { if (self == _active_object) { @@ -33,9 +42,12 @@ void mdns_server_construct(mdns_server_obj_t *self, bool workflow) { } _active_object = self; + self->instance_name[0] = '\0'; + // Match the netif hostname set when `import wifi` was called. - esp_netif_get_hostname(common_hal_wifi_radio_obj.netif, &self->hostname); - common_hal_mdns_server_set_hostname(self, self->hostname); + const char *netif_hostname; + esp_netif_get_hostname(common_hal_wifi_radio_obj.netif, &netif_hostname); + common_hal_mdns_server_set_hostname(self, netif_hostname); self->inited = true; @@ -95,11 +107,11 @@ void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *ho while (!mdns_hostname_exists(hostname)) { RUN_BACKGROUND_TASKS; } - self->hostname = hostname; + strlcpy_or_empty(self->hostname, hostname, sizeof(self->hostname)); } const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self) { - if (self->instance_name == NULL) { + if (self->instance_name[0] == '\0') { return self->hostname; } return self->instance_name; @@ -107,7 +119,28 @@ const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self) { void common_hal_mdns_server_set_instance_name(mdns_server_obj_t *self, const char *instance_name) { mdns_instance_name_set(instance_name); - self->instance_name = instance_name; + strlcpy_or_empty(self->instance_name, instance_name, sizeof(self->instance_name)); +} + +// Copy everything we expose out of the IDF's result so that the RemoteService +// no longer references IDF-owned memory. The caller is responsible for freeing +// the result itself. +static void copy_data_into_remote_service(mdns_result_t *result, mdns_remoteservice_obj_t *out) { + out->base.type = &mdns_remoteservice_type; + out->port = result->port; + out->ipv4_address = 0; + if (result->ip_protocol == MDNS_IP_PROTOCOL_V4) { + for (mdns_ip_addr_t *cur = result->addr; cur != NULL; cur = cur->next) { + if (cur->addr.type == ESP_IPADDR_TYPE_V4) { + out->ipv4_address = cur->addr.u_addr.ip4.addr; + break; + } + } + } + strlcpy_or_empty(out->protocol, result->proto, sizeof(out->protocol)); + strlcpy_or_empty(out->service_name, result->service_type, sizeof(out->service_name)); + strlcpy_or_empty(out->instance_name, result->instance_name, sizeof(out->instance_name)); + strlcpy_or_empty(out->hostname, result->hostname, sizeof(out->hostname)); } size_t mdns_server_find(mdns_server_obj_t *self, const char *service_type, const char *protocol, @@ -123,23 +156,15 @@ size_t mdns_server_find(mdns_server_obj_t *self, const char *service_type, const } mdns_query_async_delete(search); mdns_result_t *next = results; - // Don't error if we're out of memory. Instead, truncate the tuple. - uint8_t added = 0; + // Truncate if we don't have space for everything the IDF found. + size_t added = 0; while (next != NULL && added < out_len) { - mdns_remoteservice_obj_t *service = &out[added]; - - service->result = next; - service->base.type = &mdns_remoteservice_type; + copy_data_into_remote_service(next, &out[added]); next = next->next; - // Break the linked list so we free each result separately. - service->result->next = NULL; added++; } - if (added < out_len) { - // Free the remaining results from the IDF because we don't have - // enough space in Python. - mdns_query_results_free(next); - } + // We've copied out everything we need, so release the IDF's copy. + mdns_query_results_free(results); return num_results; } @@ -158,36 +183,40 @@ mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *servic // The empty tuple object is shared and stored in flash so return early if // we got it. Without this we'll crash when trying to set len below. if (num_results == 0) { + mdns_query_results_free(results); return MP_OBJ_FROM_PTR(tuple); } mdns_result_t *next = results; // Don't error if we're out of memory. Instead, truncate the tuple. uint8_t added = 0; while (next != NULL) { - mdns_remoteservice_obj_t *service = gc_alloc(sizeof(mdns_remoteservice_obj_t), GC_ALLOC_FLAG_HAS_FINALISER); + mdns_remoteservice_obj_t *service = m_malloc_maybe(sizeof(mdns_remoteservice_obj_t)); if (service == NULL) { if (added == 0) { + mdns_query_results_free(results); m_malloc_fail(sizeof(mdns_remoteservice_obj_t)); } - // Free the remaining results from the IDF because we don't have - // enough space in Python. - mdns_query_results_free(next); break; } - service->result = next; - service->base.type = &mdns_remoteservice_type; + copy_data_into_remote_service(next, service); next = next->next; - // Break the linked list so we free each result separately. - service->result->next = NULL; tuple->items[added] = MP_OBJ_FROM_PTR(service); added++; } tuple->len = added; + // We've copied out everything we need, so release the IDF's copy. + mdns_query_results_free(results); + return MP_OBJ_FROM_PTR(tuple); } void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port, const char *txt_records[], size_t num_txt_records) { + // Reject rather than silently drop them. See the TODO below. + if (num_txt_records > 0) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_txt_records); + } + if (mdns_service_exists(service_type, protocol, NULL)) { mdns_service_port_set(service_type, protocol, port); } else { diff --git a/ports/espressif/common-hal/mdns/Server.h b/ports/espressif/common-hal/mdns/Server.h index f364a539c91..e7bfabb9528 100644 --- a/ports/espressif/common-hal/mdns/Server.h +++ b/ports/espressif/common-hal/mdns/Server.h @@ -10,8 +10,11 @@ typedef struct { mp_obj_base_t base; - const char *hostname; - const char *instance_name; + // Store copies rather than the caller's pointers. The setters are handed + // GC-heap strings, which are recycled when the VM resets while this object + // (and the web workflow's static one) lives on. + char hostname[64]; // RFC 6762 Appendix A - 63 bytes for label + 1 for NUL + char instance_name[64]; // RFC 6763 Section 7.2 - 63 bytes + 1 for NUL // Track if this object owns access to the underlying MDNS service. bool inited; } mdns_server_obj_t; diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index 70912afb545..0c49318f4bc 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -7,6 +7,7 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/alarm/__init__.h" #include "py/mphal.h" @@ -77,6 +78,15 @@ static uint64_t _in_use_pin_mask; #define GPIO_SEL_47 ((uint64_t)PIN_BIT(47)) /*!< Pin 47 selected */ #define GPIO_SEL_48 ((uint64_t)PIN_BIT(48)) /*!< Pin 48 selected */ #endif +#if SOC_GPIO_PIN_COUNT > 49 +#define GPIO_SEL_49 ((uint64_t)PIN_BIT(49)) /*!< Pin 49 selected */ +#define GPIO_SEL_50 ((uint64_t)PIN_BIT(50)) /*!< Pin 50 selected */ +#define GPIO_SEL_51 ((uint64_t)PIN_BIT(51)) /*!< Pin 51 selected */ +#define GPIO_SEL_52 ((uint64_t)PIN_BIT(52)) /*!< Pin 52 selected */ +#define GPIO_SEL_53 ((uint64_t)PIN_BIT(53)) /*!< Pin 53 selected */ +#define GPIO_SEL_54 ((uint64_t)PIN_BIT(54)) /*!< Pin 54 selected */ +#define GPIO_SEL_55 ((uint64_t)PIN_BIT(55)) /*!< Pin 55 selected */ +#endif // Bit mask of all pins that should never EVER be reset. // Typically these are SPI flash and PSRAM control pins, and communication pins. @@ -126,6 +136,32 @@ static const uint64_t pin_mask_reset_forbidden = #endif #endif // ESP32C3 + #if defined(CONFIG_IDF_TARGET_ESP32C5) + // Never ever reset pins used to communicate with SPI flash. + // ports/espressif/esp-idf/components/esp_hal_gpspi/esp32c5/include/soc/spi_pins.h + GPIO_SEL_16 | // MSPI_IOMUX_PIN_NUM_CS0 (flash) + GPIO_SEL_17 | // MSPI_IOMUX_PIN_NUM_MISO + GPIO_SEL_18 | // MSPI_IOMUX_PIN_NUM_WP + GPIO_SEL_19 | // VDD_SPI (powers the in-module flash) + GPIO_SEL_20 | // MSPI_IOMUX_PIN_NUM_HD + GPIO_SEL_21 | // MSPI_IOMUX_PIN_NUM_CLK + GPIO_SEL_22 | // MSPI_IOMUX_PIN_NUM_MOSI + #if CIRCUITPY_ESP_USB_SERIAL_JTAG + // Never ever reset serial/JTAG communication pins. On C5, gpio_ll_func_sel() + // on either clears USB_SERIAL_JTAG.conf0.usb_pad_enable, killing the USB pads. + GPIO_SEL_13 | // USB D- (USB_INT_PHY0_DM_GPIO_NUM) + GPIO_SEL_14 | // USB D+ (USB_INT_PHY0_DP_GPIO_NUM) + #endif + #if defined(CONFIG_SPIRAM) + GPIO_SEL_15 | // MSPI_IOMUX_PIN_NUM_CS1 (PSRAM); keep if PSRAM in use + #endif + #if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) && CONFIG_ESP_CONSOLE_UART_DEFAULT && CONFIG_ESP_CONSOLE_UART_NUM == 0 + // Never reset debug UART/console pins. + GPIO_SEL_11 | + GPIO_SEL_12 | + #endif + #endif // ESP32C5 + #if defined(CONFIG_IDF_TARGET_ESP32C6) // Never ever reset pins used to communicate with SPI flash. GPIO_SEL_24 | // SPICS0 @@ -146,6 +182,29 @@ static const uint64_t pin_mask_reset_forbidden = #endif #endif // ESP32C6 + #if defined(CONFIG_IDF_TARGET_ESP32C61) + // Never ever reset pins used to communicate with SPI flash. + GPIO_SEL_15 | // SPICS0 (flash CS#) + GPIO_SEL_16 | // SPIQ (MISO/SIO1) + GPIO_SEL_17 | // SPIWP (WP#/SIO2) + GPIO_SEL_19 | // SPIHD (HOLD#/SIO3) + GPIO_SEL_20 | // SPICLK (CLK) + GPIO_SEL_21 | // SPID (MOSI/SIO0) + #if CIRCUITPY_ESP_USB_SERIAL_JTAG + // Never ever reset serial/JTAG communication pins. + GPIO_SEL_12 | // USB D- + GPIO_SEL_13 | // USB D+ + #endif + #if defined(CONFIG_SPIRAM) + GPIO_SEL_14 | // SPICS1 (PSRAM CS#); keep if PSRAM in use + #endif + #if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) && CONFIG_ESP_CONSOLE_UART_DEFAULT && CONFIG_ESP_CONSOLE_UART_NUM == 0 + // Never reset debug UART/console pins. + GPIO_SEL_10 | + GPIO_SEL_11 | + #endif + #endif // ESP32C6 + #if defined(CONFIG_IDF_TARGET_ESP32H2) // Never ever reset pins used to communicate with the in-package SPI flash. GPIO_SEL_15 | @@ -172,17 +231,27 @@ static const uint64_t pin_mask_reset_forbidden = #endif // ESP32H2 #if defined(CONFIG_IDF_TARGET_ESP32P4) - // Never ever reset pins used to communicate with the SPI flash. - GPIO_SEL_28 | - GPIO_SEL_29 | - GPIO_SEL_30 | - GPIO_SEL_32 | - GPIO_SEL_33 | - GPIO_SEL_34 | - #if CIRCUITPY_ESP_USB_SERIAL_JTAG + // SPI flash is on dedicated pins. + + // USB is on the FS OTG + #if CIRCUITPY_USB_DEVICE_INSTANCE == 0 + #if CIRCUITPY_ESP32P4_SWAP_LSFS == 1 + // We leave 24 and 25 alone in addition to 26 and 27 when swapped. It doesn't work otherwise. (Not sure why.) + GPIO_SEL_24 | // USB D- + GPIO_SEL_25 | // USB D+ + #endif + GPIO_SEL_26 | // USB D- + GPIO_SEL_27 | // USB D+ + #endif + #if CIRCUITPY_ESP_USB_SERIAL_JTAG || (defined(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) && CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) // Never ever reset serial/JTAG communication pins. - GPIO_SEL_50 | // USB D- - GPIO_SEL_51 | // USB D+ + #if CIRCUITPY_ESP32P4_SWAP_LSFS == 1 + GPIO_SEL_26 | // USB D- + GPIO_SEL_27 | // USB D+ + #else + GPIO_SEL_24 | // USB D- + GPIO_SEL_25 | // USB D+ + #endif #endif #if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) && CONFIG_ESP_CONSOLE_UART_DEFAULT && CONFIG_ESP_CONSOLE_UART_NUM == 0 // Never reset debug UART/console pins. @@ -326,7 +395,7 @@ void preserve_pin_number(gpio_num_t pin_number) { } } -void clear_pin_preservations(void) { +void common_hal_alarm_clear_pin_preservations(void) { _preserved_pin_mask = 0; } @@ -370,9 +439,8 @@ void reset_all_pins(void) { gpio_deep_sleep_hold_dis(); #endif - for (uint8_t i = 0; i < GPIO_PIN_COUNT; i++) { - uint32_t iomux_address = GPIO_PIN_MUX_REG[i]; - if (iomux_address == 0 || + for (gpio_num_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) { + if (!GPIO_IS_VALID_GPIO(i) || _never_reset(i) || _skip_reset_once(i) || _preserved_pin(i)) { diff --git a/ports/espressif/common-hal/microcontroller/Pin.h b/ports/espressif/common-hal/microcontroller/Pin.h index aba7fa68323..7925ac9f8de 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.h +++ b/ports/espressif/common-hal/microcontroller/Pin.h @@ -29,7 +29,6 @@ extern bool pin_number_is_free(gpio_num_t pin_number); extern void never_reset_pin_number(gpio_num_t pin_number); extern void preserve_pin_number(gpio_num_t pin_number); -extern void clear_pin_preservations(void); // Allow the board to reset a pin in a board-specific way. This can be used // for LEDs or enable pins to put them in a state beside the default pull-up. diff --git a/ports/espressif/common-hal/microcontroller/Processor.c b/ports/espressif/common-hal/microcontroller/Processor.c index 8a6a14c0236..26cec5eb467 100644 --- a/ports/espressif/common-hal/microcontroller/Processor.c +++ b/ports/espressif/common-hal/microcontroller/Processor.c @@ -59,12 +59,16 @@ uint32_t common_hal_mcu_processor_get_frequency(void) { // If the requested frequency is not supported by the hardware, return the next lower supported frequency static uint32_t get_valid_cpu_frequency(uint32_t requested_freq_mhz) { - #if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) + #if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) uint32_t valid_cpu_frequencies[] = {20, 40, 80, 160}; #elif defined(CONFIG_IDF_TARGET_ESP32C2) uint32_t valid_cpu_frequencies[] = {20, 40, 80, 120}; #elif defined(CONFIG_IDF_TARGET_ESP32H2) uint32_t valid_cpu_frequencies[] = {32, 48, 64, 96}; + #elif defined(CONFIG_IDF_TARGET_ESP32C5) + // C5's 48 MHz crystal does not divide evenly to 20 or 24 MHz, both of + // which esp_pm_configure() rejects. + uint32_t valid_cpu_frequencies[] = {40, 80, 160, 240}; #else uint32_t valid_cpu_frequencies[] = {20, 40, 80, 160, 240}; #endif @@ -126,6 +130,8 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SYS_0_REG); #elif defined(CONFIG_IDF_TARGET_ESP32C2) uint32_t mac_address_part = REG_READ(EFUSE_RD_BLK2_DATA0_REG); + #elif defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32C5) + uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SYS0_REG); #else uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SPI_SYS_0_REG); #endif @@ -145,6 +151,8 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { mac_address_part = REG_READ(EFUSE_RD_MAC_SYS_1_REG); #elif defined(CONFIG_IDF_TARGET_ESP32C2) mac_address_part = REG_READ(EFUSE_RD_BLK2_DATA1_REG); + #elif defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32C5) + mac_address_part = REG_READ(EFUSE_RD_MAC_SYS1_REG); #else mac_address_part = REG_READ(EFUSE_RD_MAC_SPI_SYS_1_REG); #endif @@ -161,41 +169,41 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { switch (esp_reset_reason()) { case ESP_RST_POWERON: - return RESET_REASON_POWER_ON; + return MCU_RESET_REASON_POWER_ON; case ESP_RST_SW: case ESP_RST_PANIC: - return RESET_REASON_SOFTWARE; + return MCU_RESET_REASON_SOFTWARE; case ESP_RST_INT_WDT: case ESP_RST_TASK_WDT: case ESP_RST_WDT: - return RESET_REASON_WATCHDOG; + return MCU_RESET_REASON_WATCHDOG; case ESP_RST_BROWNOUT: - return RESET_REASON_BROWNOUT; + return MCU_RESET_REASON_BROWNOUT; case ESP_RST_SDIO: case ESP_RST_EXT: - return RESET_REASON_RESET_PIN; - - case ESP_RST_DEEPSLEEP: - switch (esp_sleep_get_wakeup_cause()) { - case ESP_SLEEP_WAKEUP_TIMER: - case ESP_SLEEP_WAKEUP_EXT0: - case ESP_SLEEP_WAKEUP_EXT1: - case ESP_SLEEP_WAKEUP_TOUCHPAD: - case ESP_SLEEP_WAKEUP_ULP: - return RESET_REASON_DEEP_SLEEP_ALARM; - - case ESP_SLEEP_WAKEUP_UNDEFINED: - default: - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_RESET_PIN; + + case ESP_RST_DEEPSLEEP: { + uint32_t wakeup_causes = esp_sleep_get_wakeup_causes(); + uint32_t alarm_causes = + BIT(ESP_SLEEP_WAKEUP_TIMER) | + BIT(ESP_SLEEP_WAKEUP_EXT0) | + BIT(ESP_SLEEP_WAKEUP_EXT1) | + BIT(ESP_SLEEP_WAKEUP_TOUCHPAD) | + BIT(ESP_SLEEP_WAKEUP_ULP); + if (wakeup_causes & alarm_causes) { + return MCU_RESET_REASON_DEEP_SLEEP_ALARM; } + return MCU_RESET_REASON_UNKNOWN; + } case ESP_RST_UNKNOWN: default: - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } } diff --git a/ports/espressif/common-hal/microcontroller/__init__.c b/ports/espressif/common-hal/microcontroller/__init__.c index 918366b8933..2da2d09f22d 100644 --- a/ports/espressif/common-hal/microcontroller/__init__.c +++ b/ports/espressif/common-hal/microcontroller/__init__.c @@ -33,9 +33,15 @@ #elif defined(CONFIG_IDF_TARGET_ESP32C3) #include "soc/rtc_cntl_reg.h" #include "esp32c3/rom/rtc.h" +#elif defined(CONFIG_IDF_TARGET_ESP32C5) +#include "soc/lp_aon_reg.h" +#include "esp32c5/rom/rtc.h" #elif defined(CONFIG_IDF_TARGET_ESP32C6) #include "soc/lp_aon_reg.h" #include "esp32c6/rom/rtc.h" +#elif defined(CONFIG_IDF_TARGET_ESP32C61) +#include "soc/lp_aon_reg.h" +#include "esp32c61/rom/rtc.h" #elif defined(CONFIG_IDF_TARGET_ESP32P4) #include "esp32p4/rom/rtc.h" #elif defined(CONFIG_IDF_TARGET_ESP32S2) @@ -83,7 +89,7 @@ void common_hal_mcu_enable_interrupts(void) { void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { switch (runmode) { case RUNMODE_UF2: - #if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) + #if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) mp_arg_error_invalid(MP_QSTR_run_mode); #else // 0x11F2 is APP_REQUEST_UF2_RESET_HINT & is defined by TinyUF2 @@ -139,7 +145,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { } } -void NORETURN common_hal_mcu_reset(void) { +void MP_NORETURN common_hal_mcu_reset(void) { filesystem_flush(); // TODO: implement as part of flash improvements esp_restart(); } diff --git a/ports/espressif/common-hal/mipidsi/Bus.c b/ports/espressif/common-hal/mipidsi/Bus.c new file mode 100644 index 00000000000..dbb559ea30f --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/Bus.c @@ -0,0 +1,69 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/mipidsi/Bus.h" +#include "bindings/espidf/__init__.h" +#include "py/runtime.h" +#include + +void common_hal_mipidsi_bus_construct(mipidsi_bus_obj_t *self, mp_uint_t frequency, uint8_t num_lanes) { + self->frequency = frequency; + self->num_data_lanes = num_lanes; + self->bus_handle = NULL; + + if (self->use_count > 0) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_mipidsi); + } + + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = 3, + .voltage_mv = 2500, + }; + ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); + + // Create the DSI bus + esp_lcd_dsi_bus_config_t bus_config = { + .bus_id = 0, + .num_data_lanes = num_lanes, + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, + .lane_bit_rate_mbps = frequency / 1000000, // Convert Hz to MHz + }; + + CHECK_ESP_RESULT(esp_lcd_new_dsi_bus(&bus_config, &self->bus_handle)); +} + +void common_hal_mipidsi_bus_deinit(mipidsi_bus_obj_t *self) { + if (self->use_count > 0) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_Bus); + } + if (common_hal_mipidsi_bus_deinited(self)) { + return; + } + + // Delete the DSI bus + if (self->bus_handle != NULL) { + esp_lcd_del_dsi_bus(self->bus_handle); + self->bus_handle = NULL; + } + + self->frequency = 0; + self->num_data_lanes = 0; +} + +bool common_hal_mipidsi_bus_deinited(mipidsi_bus_obj_t *self) { + return self->bus_handle == NULL; +} + +void mipidsi_bus_increment_use_count(mipidsi_bus_obj_t *self) { + self->use_count++; +} +void mipidsi_bus_decrement_use_count(mipidsi_bus_obj_t *self) { + self->use_count--; + if (self->use_count == 0) { + common_hal_mipidsi_bus_deinit(self); + } +} diff --git a/ports/espressif/common-hal/mipidsi/Bus.h b/ports/espressif/common-hal/mipidsi/Bus.h new file mode 100644 index 00000000000..b6257fd7223 --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/Bus.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include + +typedef struct { + mp_obj_base_t base; + mp_uint_t frequency; + esp_lcd_dsi_bus_handle_t bus_handle; + uint8_t num_data_lanes; + uint8_t use_count; // Up to 4 displays +} mipidsi_bus_obj_t; + +void mipidsi_bus_increment_use_count(mipidsi_bus_obj_t *self); +void mipidsi_bus_decrement_use_count(mipidsi_bus_obj_t *self); diff --git a/ports/espressif/common-hal/mipidsi/Display.c b/ports/espressif/common-hal/mipidsi/Display.c new file mode 100644 index 00000000000..dc70f901437 --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/Display.c @@ -0,0 +1,290 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/mipidsi/Display.h" +#include "shared-bindings/mipidsi/Bus.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/time/__init__.h" +#include "bindings/espidf/__init__.h" +#include +#include +#include "py/runtime.h" + +// Cache write-back function (should be from rom/cache.h but it's not always available) +extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size); + +void common_hal_mipidsi_display_construct(mipidsi_display_obj_t *self, + mipidsi_bus_obj_t *bus, + const uint8_t *init_sequence, + size_t init_sequence_len, + mp_uint_t virtual_channel, + mp_uint_t width, + mp_uint_t height, + mp_int_t rotation, + mp_uint_t color_depth, + const mcu_pin_obj_t *backlight_pin, + mp_float_t brightness, + mp_uint_t native_frames_per_second, + bool backlight_on_high, + mp_uint_t hsync_pulse_width, + mp_uint_t hsync_back_porch, + mp_uint_t hsync_front_porch, + mp_uint_t vsync_pulse_width, + mp_uint_t vsync_back_porch, + mp_uint_t vsync_front_porch, + mp_uint_t pixel_clock_frequency) { + self->bus = bus; + self->virtual_channel = virtual_channel; + self->width = width; + self->height = height; + self->rotation = rotation; + self->color_depth = color_depth; + self->native_frames_per_second = native_frames_per_second; + self->backlight_on_high = backlight_on_high; + self->framebuffer = NULL; + self->dbi_io_handle = NULL; + self->dpi_panel_handle = NULL; + + // Create the DBI interface for sending commands + esp_lcd_dbi_io_config_t dbi_config = { + .virtual_channel = virtual_channel, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + }; + + CHECK_ESP_RESULT(esp_lcd_new_panel_io_dbi(bus->bus_handle, &dbi_config, &self->dbi_io_handle)); + + // Determine the pixel format based on color depth + lcd_color_format_t color_format; + if (color_depth == 16) { + color_format = LCD_COLOR_FMT_RGB565; + } else if (color_depth == 24) { + color_format = LCD_COLOR_FMT_RGB888; + } else { + common_hal_mipidsi_display_deinit(self); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_color_depth); + } + + // Create the DPI panel for sending pixel data + esp_lcd_dpi_panel_config_t dpi_config = { + .virtual_channel = virtual_channel, + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, + .dpi_clock_freq_mhz = pixel_clock_frequency / 1000000, + .in_color_format = color_format, + .num_fbs = 1, + .video_timing = { + .h_size = width, + .v_size = height, + .hsync_pulse_width = hsync_pulse_width, + .hsync_back_porch = hsync_back_porch, + .hsync_front_porch = hsync_front_porch, + .vsync_pulse_width = vsync_pulse_width, + .vsync_back_porch = vsync_back_porch, + .vsync_front_porch = vsync_front_porch, + }, + .flags = { + .disable_lp = false, + }, + }; + + esp_err_t ret = esp_lcd_new_panel_dpi(bus->bus_handle, &dpi_config, &self->dpi_panel_handle); + if (ret != ESP_OK) { + common_hal_mipidsi_display_deinit(self); + CHECK_ESP_RESULT(ret); + } + + // Get the framebuffer allocated by the driver + void *fb = NULL; + ret = esp_lcd_dpi_panel_get_frame_buffer(self->dpi_panel_handle, 1, &fb); + if (ret != ESP_OK || fb == NULL) { + common_hal_mipidsi_display_deinit(self); + CHECK_ESP_RESULT(ret); + } + + self->framebuffer = (uint8_t *)fb; + self->framebuffer_size = width * height * (color_depth / 8); + + // Send initialization sequence (format matches busdisplay) + #define DELAY 0x80 + uint32_t i = 0; + while (i < init_sequence_len) { + const uint8_t *cmd = init_sequence + i; + uint8_t data_size = *(cmd + 1); + bool delay = (data_size & DELAY) != 0; + data_size &= ~DELAY; + const uint8_t *data = cmd + 2; + esp_lcd_panel_io_tx_param(self->dbi_io_handle, cmd[0], data, data_size); + + uint16_t delay_length_ms = 0; + if (delay) { + data_size++; + delay_length_ms = *(cmd + 1 + data_size); + if (delay_length_ms == 255) { + delay_length_ms = 500; + } + } + common_hal_time_delay_ms(delay_length_ms); + i += 2 + data_size; + } + + // Initialize the panel after sending init commands + ret = esp_lcd_panel_init(self->dpi_panel_handle); + if (ret != ESP_OK) { + common_hal_mipidsi_display_deinit(self); + CHECK_ESP_RESULT(ret); + } + + // Setup backlight PWM if pin is provided + self->backlight_inout.base.type = &mp_type_NoneType; + if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) { + #if (CIRCUITPY_PWMIO) + pwmout_result_t result = common_hal_pwmio_pwmout_construct(&self->backlight_pwm, backlight_pin, 0, 50000, false); + if (result != PWMOUT_OK) { + self->backlight_inout.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&self->backlight_inout, backlight_pin); + common_hal_never_reset_pin(backlight_pin); + } else { + self->backlight_pwm.base.type = &pwmio_pwmout_type; + common_hal_pwmio_pwmout_never_reset(&self->backlight_pwm); + } + #else + self->backlight_inout.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&self->backlight_inout, backlight_pin); + common_hal_never_reset_pin(backlight_pin); + #endif + + // Set initial brightness + #if (CIRCUITPY_PWMIO) + if (self->backlight_pwm.base.type == &pwmio_pwmout_type) { + common_hal_pwmio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t)(brightness * 0xFFFF)); + } else + #endif + if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + bool on = brightness > 0; + if (!backlight_on_high) { + on = !on; + } + common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, on); + } + } + mipidsi_bus_increment_use_count(self->bus); +} + +void common_hal_mipidsi_display_deinit(mipidsi_display_obj_t *self) { + if (common_hal_mipidsi_display_deinited(self)) { + return; + } + + // Cleanup backlight + #if (CIRCUITPY_PWMIO) + if (self->backlight_pwm.base.type == &pwmio_pwmout_type) { + common_hal_pwmio_pwmout_deinit(&self->backlight_pwm); + } else + #endif + if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_deinit(&self->backlight_inout); + } + + // Delete the DPI panel + if (self->dpi_panel_handle != NULL) { + esp_lcd_panel_del(self->dpi_panel_handle); + self->dpi_panel_handle = NULL; + } + + // Delete the DBI interface + if (self->dbi_io_handle != NULL) { + esp_lcd_panel_io_del(self->dbi_io_handle); + self->dbi_io_handle = NULL; + } + + mipidsi_bus_decrement_use_count(self->bus); + self->bus = NULL; + self->framebuffer = NULL; +} + +bool common_hal_mipidsi_display_deinited(mipidsi_display_obj_t *self) { + return self->dpi_panel_handle == NULL; +} + +void common_hal_mipidsi_display_refresh(mipidsi_display_obj_t *self) { + // Drawing the framebuffer we got from the IDF will flush the cache(s) so + // DMA can see our changes. It won't cause an extra copy. + esp_lcd_panel_draw_bitmap(self->dpi_panel_handle, 0, 0, self->width, self->height, self->framebuffer); + + // The DPI panel will automatically refresh from the framebuffer + // No explicit refresh call is needed as the DSI hardware continuously + // sends data from the framebuffer to the display +} + +mp_float_t common_hal_mipidsi_display_get_brightness(mipidsi_display_obj_t *self) { + return self->current_brightness; +} + +bool common_hal_mipidsi_display_set_brightness(mipidsi_display_obj_t *self, mp_float_t brightness) { + if (!self->backlight_on_high) { + brightness = 1.0 - brightness; + } + bool ok = false; + + // Avoid PWM types and functions when the module isn't enabled + #if (CIRCUITPY_PWMIO) + bool ispwm = (self->backlight_pwm.base.type == &pwmio_pwmout_type) ? true : false; + #else + bool ispwm = false; + #endif + + if (ispwm) { + #if (CIRCUITPY_PWMIO) + common_hal_pwmio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t)(0xffff * brightness)); + ok = true; + #else + ok = false; + #endif + } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); + ok = true; + } + if (ok) { + self->current_brightness = brightness; + } + return ok; +} + +int common_hal_mipidsi_display_get_width(mipidsi_display_obj_t *self) { + return self->width; +} + +int common_hal_mipidsi_display_get_height(mipidsi_display_obj_t *self) { + return self->height; +} + +int common_hal_mipidsi_display_get_row_stride(mipidsi_display_obj_t *self) { + return self->width * (self->color_depth / 8); +} + +int common_hal_mipidsi_display_get_color_depth(mipidsi_display_obj_t *self) { + return self->color_depth; +} + +int common_hal_mipidsi_display_get_native_frames_per_second(mipidsi_display_obj_t *self) { + return self->native_frames_per_second; +} + +bool common_hal_mipidsi_display_get_grayscale(mipidsi_display_obj_t *self) { + return false; +} + +mp_int_t common_hal_mipidsi_display_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + mipidsi_display_obj_t *self = (mipidsi_display_obj_t *)self_in; + + bufinfo->buf = self->framebuffer; + bufinfo->len = self->framebuffer_size; + bufinfo->typecode = 'B'; + + return 0; +} diff --git a/ports/espressif/common-hal/mipidsi/Display.h b/ports/espressif/common-hal/mipidsi/Display.h new file mode 100644 index 00000000000..cbc87e268dc --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/Display.h @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/mipidsi/Bus.h" +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/digitalio/DigitalInOut.h" +#include "common-hal/pwmio/PWMOut.h" +#include +#include + +typedef struct { + mp_obj_base_t base; + mipidsi_bus_obj_t *bus; + mp_uint_t virtual_channel; + mp_uint_t width; + mp_uint_t height; + mp_int_t rotation; + mp_uint_t color_depth; + mp_uint_t native_frames_per_second; + uint8_t *framebuffer; + esp_lcd_panel_io_handle_t dbi_io_handle; + esp_lcd_panel_handle_t dpi_panel_handle; + size_t framebuffer_size; + union { + digitalio_digitalinout_obj_t backlight_inout; + #if CIRCUITPY_PWMIO + pwmio_pwmout_obj_t backlight_pwm; + #endif + }; + bool backlight_on_high; + mp_float_t current_brightness; +} mipidsi_display_obj_t; diff --git a/ports/espressif/common-hal/mipidsi/__init__.c b/ports/espressif/common-hal/mipidsi/__init__.c new file mode 100644 index 00000000000..173f2146e87 --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/mipidsi/__init__.h" diff --git a/ports/espressif/common-hal/mipidsi/__init__.h b/ports/espressif/common-hal/mipidsi/__init__.h new file mode 100644 index 00000000000..972a7c082fd --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/ports/espressif/common-hal/neopixel_write/__init__.c b/ports/espressif/common-hal/neopixel_write/__init__.c index d0d46a31797..cd62220f620 100644 --- a/ports/espressif/common-hal/neopixel_write/__init__.c +++ b/ports/espressif/common-hal/neopixel_write/__init__.c @@ -31,6 +31,8 @@ #include "driver/gpio.h" #include "driver/rmt_tx.h" +#include "hal/rmt_periph.h" +#include "soc/soc_caps.h" // Use closer to WS2812-style timings instead of WS2812B, to accommodate more varieties. #define WS2812_T0H_NS (316) @@ -53,14 +55,13 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, .trans_queue_depth = 1, }; - // Greedily try and grab as much RMT memory as we can. The more we get, the - // smoother the output will be because we'll trigger fewer interrupts. We'll - // give it all back once we're done. + // Greedily allocate as much RMT memory as possible, stepping down by one + // channel's worth each time. More memory means fewer interrupts and smoother output. + // We'll give it all back once we're done. rmt_channel_handle_t channel; esp_err_t result = ESP_ERR_NOT_FOUND; - // If no other channels are in use, we can use all of the RMT RAM including the RX channels. - config.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL * SOC_RMT_CHANNELS_PER_GROUP; - while (result == ESP_ERR_NOT_FOUND && config.mem_block_symbols > 0) { + config.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL * RMT_LL_CHANS_PER_INST; + while (result == ESP_ERR_NOT_FOUND && config.mem_block_symbols >= SOC_RMT_MEM_WORDS_PER_CHANNEL) { result = rmt_new_tx_channel(&config, &channel); config.mem_block_symbols -= SOC_RMT_MEM_WORDS_PER_CHANNEL; } @@ -117,6 +118,7 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, rmt_del_channel(channel); raise_esp_error(result); } + result = ESP_ERR_TIMEOUT; while (result == ESP_ERR_TIMEOUT) { RUN_BACKGROUND_TASKS; diff --git a/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c b/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c index 7721b5e197f..52c4b67bf4e 100644 --- a/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +++ b/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c @@ -18,7 +18,7 @@ #include "common-hal/microcontroller/Pin.h" #include "py/runtime.h" -#include "driver/gpio.h" +#include /* * Current pin limitations for ESP32-S2 ParallelBus: diff --git a/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.h b/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.h index 4724ba7231a..114a1e527a6 100644 --- a/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.h +++ b/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.h @@ -8,7 +8,7 @@ #include "common-hal/digitalio/DigitalInOut.h" -#include "esp-idf/components/esp_lcd/include/esp_lcd_panel_io.h" +#include typedef struct { mp_obj_base_t base; diff --git a/ports/espressif/common-hal/picogame/Display.c b/ports/espressif/common-hal/picogame/Display.c new file mode 100644 index 00000000000..635549e5918 --- /dev/null +++ b/ports/espressif/common-hal/picogame/Display.c @@ -0,0 +1,153 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "common-hal/picogame/Display.h" + +#include + +#include "py/runtime.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/displayio/display_core.h" +#include "shared-bindings/displayio/__init__.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "common-hal/busio/SPI.h" + +#include "driver/spi_master.h" + +// The esp-idf SPI device queue holds MAX_SPI_TRANSACTIONS (10) outstanding +// transactions. We keep up to two strips in flight (current transferring while +// the next is blitted), so each strip may use at most this many DMA chunks and +// still leave room: 2 * 5 <= 10. Strips needing more chunks fall back to a +// blocking send (correct, just no overlap for that strip). +#define PICOGAME_MAX_STRIP_CHUNKS 5 + +void common_hal_picogame_display_construct(picogame_display_obj_t *self, + busdisplay_busdisplay_obj_t *display, bool rgb444) { + self->display = display; + // RGB444 strip packing isn't implemented on this backend yet. Raise rather than silently + // ignore it: a no-op would leave the panel in RGB565 while the caller expects 444 (garbled + // output / wrong byte count). The rpi backend implements it; until this one does, fail loud. + if (rgb444) { + mp_arg_error_invalid(MP_QSTR_rgb444); // not implemented on this port yet + } + self->rgb444 = false; + + // The fast path queues raw DMA on the display's SPI device; only FourWire + // SPI buses expose one. + if (!mp_obj_is_type(display->bus.bus, &fourwire_fourwire_type)) { + mp_arg_error_invalid(MP_QSTR_display); // the fast backend drives a FourWire SPI panel only + } + fourwire_fourwire_obj_t *fw = MP_OBJ_TO_PTR(display->bus.bus); + self->spi = common_hal_busio_spi_get_device_handle(fw->bus); +} + +// Retrieve all outstanding results for *count queued chunks, then zero the count. +static void drain(spi_device_handle_t spi, int *count) { + spi_transaction_t *rtrans; + while (*count > 0) { + spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); + (*count)--; + } +} + +// Queue one strip (nbytes from buf) as up to PICOGAME_MAX_STRIP_CHUNKS DMA +// transactions. Returns the chunk count, or -1 if it would need more chunks. +static int queue_strip(spi_device_handle_t spi, spi_transaction_t *trans, + const uint16_t *buf, size_t nbytes) { + int needed = (int)((nbytes + SPI_MAX_DMA_LEN - 1) / SPI_MAX_DMA_LEN); + if (needed > PICOGAME_MAX_STRIP_CHUNKS) { + return -1; + } + const uint8_t *p = (const uint8_t *)buf; + size_t off = 0; + int n = 0; + while (off < nbytes) { + size_t chunk = nbytes - off; + if (chunk > SPI_MAX_DMA_LEN) { + chunk = SPI_MAX_DMA_LEN; + } + memset(&trans[n], 0, sizeof(spi_transaction_t)); + trans[n].length = chunk * 8; // in bits + trans[n].tx_buffer = p + off; + spi_device_queue_trans(spi, &trans[n], portMAX_DELAY); + off += chunk; + n++; + } + return n; +} + +void common_hal_picogame_display_render(picogame_display_obj_t *self, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buf_a, uint16_t *buf_b, size_t buf_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t background, + int ox, int oy) { + + busdisplay_busdisplay_obj_t *display = self->display; + spi_device_handle_t spi = self->spi; + + // Open the GRAM window (set region, begin transaction, RAMWR). After the + // first DATA send raises DC, DC stays high for the raw queued strips that + // follow, and CS stays low until end_transaction. + int region_w, strip_h; + int cx0 = x0, cy0 = y0, cx1 = x1, cy1 = y1; // strip_begin clamps these to the panel in place + if (!picogame_strip_begin(display, &cx0, &cy0, &cx1, &cy1, buf_pixels, ®ion_w, &strip_h)) { + return; + } + + uint16_t *bufs[2] = { buf_a, buf_b }; + spi_transaction_t trans[2][PICOGAME_MAX_STRIP_CHUNKS]; + int inflight[2] = { 0, 0 }; // chunks queued from bufs[i], awaiting result + + // A StripDraw callback may latch a BaseException (Ctrl-C / auto-reload). Like the portable + // renderer and the RP backend, re-raise it -- but only AFTER the queued transfers drain and + // the bus transaction closes, so hold it here and propagate below. + mp_obj_t pending = MP_OBJ_NULL; + + int cur = 0; + bool first = true; + for (int sy = cy0; sy < cy1; sy += strip_h) { + int sh = picogame_imin(strip_h, cy1 - sy); + size_t nbytes = (size_t)region_w * sh * 2; + uint16_t *buf = bufs[cur]; + + // This buffer must be free before we overwrite it. + drain(spi, &inflight[cur]); + + // Blit this strip. If the OTHER buffer has a strip in flight, its DMA + // transfer overlaps this CPU work -- the whole point of the fast path. + pending = picogame_blit_strip_layers(buf, region_w, sy, sh, cx0, items, kinds, n, + background, ox, oy); + + int nch; + if (first) { + // First DATA send goes through the busdisplay so it raises DC. + display->bus.send(display->bus.bus, DISPLAY_DATA, + CHIP_SELECT_UNTOUCHED, (uint8_t *)buf, nbytes); + first = false; + } else if ((nch = queue_strip(spi, trans[cur], buf, nbytes)) >= 0) { + inflight[cur] = nch; + } else { + // Strip too large to keep two in flight: drain everything and send + // it blocking (DC already high, CS untouched). + drain(spi, &inflight[cur ^ 1]); + display->bus.send(display->bus.bus, DISPLAY_DATA, + CHIP_SELECT_UNTOUCHED, (uint8_t *)buf, nbytes); + } + cur ^= 1; + if (pending != MP_OBJ_NULL) { // callback interrupted: this strip is queued, now stop + flush + break; + } + } + + drain(spi, &inflight[0]); + drain(spi, &inflight[1]); + + displayio_display_bus_end_transaction(&display->bus); + + if (pending != MP_OBJ_NULL) { // bus now closed -> safe to re-raise (Ctrl-C / reload) + nlr_raise(MP_OBJ_TO_PTR(pending)); + } +} diff --git a/ports/espressif/common-hal/picogame/Display.h b/ports/espressif/common-hal/picogame/Display.h new file mode 100644 index 00000000000..b4487e5ee55 --- /dev/null +++ b/ports/espressif/common-hal/picogame/Display.h @@ -0,0 +1,33 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// Fast display backend (espressif): wraps an existing busdisplay and streams +// pixels with the esp-idf SPI master's queued DMA, double-buffered so the CPU +// blits the next strip while the current one transfers. Reuses the busdisplay's +// SPI device, window opcodes and dimensions -- controller/resolution agnostic. + +#pragma once + +#include "py/obj.h" +#include "driver/spi_master.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/picogame/Sprite.h" + +typedef struct { + mp_obj_base_t base; + busdisplay_busdisplay_obj_t *display; + spi_device_handle_t spi; // the busdisplay's SPI device (raw DMA queueing) + bool rgb444; // RGB444 strip packing (not yet implemented on this backend) +} picogame_display_obj_t; + +void common_hal_picogame_display_construct(picogame_display_obj_t *self, + busdisplay_busdisplay_obj_t *display, bool rgb444); + +void common_hal_picogame_display_render(picogame_display_obj_t *self, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buf_a, uint16_t *buf_b, size_t buf_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t background, + int ox, int oy); diff --git a/ports/espressif/common-hal/pulseio/PulseOut.c b/ports/espressif/common-hal/pulseio/PulseOut.c index 68cb64b5e60..8995043b825 100644 --- a/ports/espressif/common-hal/pulseio/PulseOut.c +++ b/ports/espressif/common-hal/pulseio/PulseOut.c @@ -69,7 +69,7 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t *self, uint16_t *pu // Circuitpython allows 16 bit pulse values, while ESP32 only allows 15 bits // Thus, we use entire items for one pulse, rather than switching inside each item for (size_t i = 0; i < length; i++) { - // Setting the RMT duration to 0 has undefined behavior, so avoid that pre-emptively. + // Setting the RMT duration to 0 has undefined behavior, so avoid that preemptively. if (pulses[i] == 0) { continue; } diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c new file mode 100644 index 00000000000..6fb872248e2 --- /dev/null +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -0,0 +1,571 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT + +#include "shared-bindings/qspibus/QSPIBus.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" + +#include "py/gc.h" +#include "py/runtime.h" + +#include "driver/gpio.h" +#include "esp_heap_caps.h" +#include "soc/soc_caps.h" +#include + +#define QSPI_OPCODE_WRITE_CMD (0x02U) +#define QSPI_OPCODE_WRITE_COLOR (0x32U) +#define LCD_CMD_RAMWR (0x2CU) +#define LCD_CMD_RAMWRC (0x3CU) +#define LCD_CMD_DISPOFF (0x28U) +#define LCD_CMD_SLPIN (0x10U) +#define QSPI_DMA_BUFFER_COUNT (2U) +#define QSPI_DMA_BUFFER_SIZE (16U * 1024U) +#define QSPI_COLOR_TIMEOUT_MS (1000U) +static void qspibus_release_dma_buffers(qspibus_qspibus_obj_t *self) { + for (size_t i = 0; i < QSPI_DMA_BUFFER_COUNT; i++) { + if (self->dma_buffer[i] != NULL) { + heap_caps_free(self->dma_buffer[i]); + self->dma_buffer[i] = NULL; + } + } + self->dma_buffer_size = 0; + self->active_buffer = 0; + self->inflight_transfers = 0; + self->transfer_in_progress = false; +} + +static bool qspibus_allocate_dma_buffers(qspibus_qspibus_obj_t *self) { + const size_t candidates[] = { + QSPI_DMA_BUFFER_SIZE, + QSPI_DMA_BUFFER_SIZE / 2, + QSPI_DMA_BUFFER_SIZE / 4, + }; + + for (size_t c = 0; c < MP_ARRAY_SIZE(candidates); c++) { + size_t size = candidates[c]; + bool ok = true; + for (size_t i = 0; i < QSPI_DMA_BUFFER_COUNT; i++) { + self->dma_buffer[i] = heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + if (self->dma_buffer[i] == NULL) { + ok = false; + break; + } + } + if (ok) { + self->dma_buffer_size = size; + self->active_buffer = 0; + self->inflight_transfers = 0; + self->transfer_in_progress = false; + return true; + } + qspibus_release_dma_buffers(self); + } + return false; +} + +// Reset transfer bookkeeping after timeout/error. Drains any stale semaphore +// tokens that late ISR completions may have posted after the timeout expired. +static void qspibus_reset_transfer_state(qspibus_qspibus_obj_t *self) { + self->inflight_transfers = 0; + self->transfer_in_progress = false; + if (self->transfer_done_sem != NULL) { + while (xSemaphoreTake(self->transfer_done_sem, 0) == pdTRUE) { + } + } +} + +static bool qspibus_wait_one_transfer_done(qspibus_qspibus_obj_t *self, TickType_t timeout) { + if (self->inflight_transfers == 0) { + self->transfer_in_progress = false; + return true; + } + + if (xSemaphoreTake(self->transfer_done_sem, timeout) != pdTRUE) { + return false; + } + self->inflight_transfers--; + self->transfer_in_progress = (self->inflight_transfers > 0); + return true; +} + +static bool qspibus_wait_all_transfers_done(qspibus_qspibus_obj_t *self, TickType_t timeout) { + while (self->inflight_transfers > 0) { + if (!qspibus_wait_one_transfer_done(self, timeout)) { + return false; + } + } + return true; +} + +static void qspibus_send_command_bytes( + qspibus_qspibus_obj_t *self, + uint8_t command, + const uint8_t *data, + size_t len) { + + if (!self->bus_initialized) { + raise_deinited_error(); + } + if (self->inflight_transfers >= QSPI_DMA_BUFFER_COUNT) { + if (!qspibus_wait_one_transfer_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg(MP_ERROR_TEXT("Operation timed out")); + } + } + + uint32_t packed_cmd = ((uint32_t)QSPI_OPCODE_WRITE_CMD << 24) | ((uint32_t)command << 8); + esp_err_t err = esp_lcd_panel_io_tx_param(self->io_handle, packed_cmd, data, len); + if (err != ESP_OK) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_QSPI, (int)err); + } +} + +static void qspibus_send_color_bytes( + qspibus_qspibus_obj_t *self, + uint8_t command, + const uint8_t *data, + size_t len) { + + if (!self->bus_initialized) { + raise_deinited_error(); + } + + if (len == 0) { + qspibus_send_command_bytes(self, command, NULL, 0); + return; + } + + // RAMWR must transition to RAMWRC for continued payload chunks. + uint8_t chunk_command = command; + const uint8_t *cursor = data; + size_t remaining = len; + + // Drain stale semaphore tokens that late ISR completions may have + // posted after a previous qspibus_reset_transfer_state(). Without + // this, a stale token could satisfy a future wait, causing the next + // transfer to skip its real DMA-done wait. + if (self->inflight_transfers == 0 && self->transfer_done_sem != NULL) { + while (xSemaphoreTake(self->transfer_done_sem, 0) == pdTRUE) { + } + } + + while (remaining > 0) { + // inflight_transfers is only modified in task context (never from ISR), + // so no atomic/critical section is needed. The ISR only signals the + // counting semaphore; all counter bookkeeping happens task-side. + if (self->inflight_transfers >= QSPI_DMA_BUFFER_COUNT) { + if (!qspibus_wait_one_transfer_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg(MP_ERROR_TEXT("Operation timed out")); + } + } + + size_t chunk = remaining; + if (chunk > self->dma_buffer_size) { + chunk = self->dma_buffer_size; + } + + uint8_t *buffer = self->dma_buffer[self->active_buffer]; + memcpy(buffer, cursor, chunk); + + uint32_t packed_cmd = ((uint32_t)QSPI_OPCODE_WRITE_COLOR << 24) | ((uint32_t)chunk_command << 8); + esp_err_t err = esp_lcd_panel_io_tx_color(self->io_handle, packed_cmd, buffer, chunk); + if (err != ESP_OK) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_QSPI, (int)err); + } + + self->inflight_transfers++; + self->transfer_in_progress = true; + self->active_buffer = (self->active_buffer + 1) % QSPI_DMA_BUFFER_COUNT; + + if (chunk_command == LCD_CMD_RAMWR) { + chunk_command = LCD_CMD_RAMWRC; + } + + cursor += chunk; + remaining -= chunk; + } + + // Let DMA complete asynchronously. The next begin_transaction() will + // wait for all in-flight transfers, allowing fill_area() computation + // to overlap with DMA. The explicit wait is only needed for the + // Python write_data() API path where callers expect the transfer to + // be finished on return. +} + +static bool qspibus_is_color_payload_command(uint8_t command) { + return command == LCD_CMD_RAMWR || command == LCD_CMD_RAMWRC; +} + +static void qspibus_panel_sleep_best_effort(qspibus_qspibus_obj_t *self) { + if (!self->bus_initialized || self->io_handle == NULL) { + return; + } + + if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + } + + // If a command is buffered, flush it first so the panel state machine + // doesn't get a truncated transaction before sleep. + if (self->has_pending_command) { + uint32_t pending = ((uint32_t)QSPI_OPCODE_WRITE_CMD << 24) | ((uint32_t)self->pending_command << 8); + (void)esp_lcd_panel_io_tx_param(self->io_handle, pending, NULL, 0); + self->has_pending_command = false; + } + + uint32_t disp_off = ((uint32_t)QSPI_OPCODE_WRITE_CMD << 24) | ((uint32_t)LCD_CMD_DISPOFF << 8); + (void)esp_lcd_panel_io_tx_param(self->io_handle, disp_off, NULL, 0); + vTaskDelay(pdMS_TO_TICKS(20)); + + uint32_t sleep_in = ((uint32_t)QSPI_OPCODE_WRITE_CMD << 24) | ((uint32_t)LCD_CMD_SLPIN << 8); + (void)esp_lcd_panel_io_tx_param(self->io_handle, sleep_in, NULL, 0); + vTaskDelay(pdMS_TO_TICKS(120)); +} + +static bool IRAM_ATTR qspibus_on_color_trans_done( + esp_lcd_panel_io_handle_t io_handle, + esp_lcd_panel_io_event_data_t *event_data, + void *user_ctx) { + (void)io_handle; + (void)event_data; + + qspibus_qspibus_obj_t *self = (qspibus_qspibus_obj_t *)user_ctx; + if (self->transfer_done_sem == NULL) { + return false; + } + BaseType_t x_higher_priority_task_woken = pdFALSE; + + xSemaphoreGiveFromISR(self->transfer_done_sem, &x_higher_priority_task_woken); + return x_higher_priority_task_woken == pdTRUE; +} + +void common_hal_qspibus_qspibus_construct( + qspibus_qspibus_obj_t *self, + const mcu_pin_obj_t *clock, + const mcu_pin_obj_t *data0, + const mcu_pin_obj_t *data1, + const mcu_pin_obj_t *data2, + const mcu_pin_obj_t *data3, + const mcu_pin_obj_t *cs, + const mcu_pin_obj_t *dcx, + const mcu_pin_obj_t *reset, + uint32_t frequency) { + + self->io_handle = NULL; + self->host_id = SPI2_HOST; + self->clock_pin = clock->number; + self->data0_pin = data0->number; + self->data1_pin = data1->number; + self->data2_pin = data2->number; + self->data3_pin = data3->number; + self->cs_pin = cs->number; + self->dcx_pin = (dcx != NULL) ? dcx->number : -1; + self->reset_pin = (reset != NULL) ? reset->number : -1; + self->frequency = frequency; + self->bus_initialized = false; + self->in_transaction = false; + self->has_pending_command = false; + self->pending_command = 0; + self->transfer_in_progress = false; + self->active_buffer = 0; + self->inflight_transfers = 0; + self->dma_buffer_size = 0; + self->dma_buffer[0] = NULL; + self->dma_buffer[1] = NULL; + self->transfer_done_sem = NULL; + + self->transfer_done_sem = xSemaphoreCreateCounting(QSPI_DMA_BUFFER_COUNT, 0); + if (self->transfer_done_sem == NULL) { + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("ESP-IDF memory allocation failed")); + } + + if (!qspibus_allocate_dma_buffers(self)) { + common_hal_qspibus_qspibus_deinit(self); + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Could not allocate DMA capable buffer")); + } + + const spi_bus_config_t bus_config = { + .sclk_io_num = self->clock_pin, + .mosi_io_num = self->data0_pin, + .miso_io_num = self->data1_pin, + .quadwp_io_num = self->data2_pin, + .quadhd_io_num = self->data3_pin, + .max_transfer_sz = self->dma_buffer_size, + .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_GPIO_PINS, + }; + + esp_err_t err = spi_bus_initialize(self->host_id, &bus_config, SPI_DMA_CH_AUTO); + if (err != ESP_OK) { + common_hal_qspibus_qspibus_deinit(self); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_SPI); + } + + // Mark bus as initialized so deinit knows to call spi_bus_free(). + self->bus_initialized = true; + + const esp_lcd_panel_io_spi_config_t io_config = { + .cs_gpio_num = self->cs_pin, + .dc_gpio_num = -1, + .spi_mode = 0, + .pclk_hz = self->frequency, + .trans_queue_depth = QSPI_DMA_BUFFER_COUNT, + .on_color_trans_done = qspibus_on_color_trans_done, + .user_ctx = self, + .lcd_cmd_bits = 32, + .lcd_param_bits = 8, + .flags = { + .quad_mode = 1, + }, + }; + + err = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)self->host_id, &io_config, &self->io_handle); + if (err != ESP_OK) { + common_hal_qspibus_qspibus_deinit(self); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_QSPI, (int)err); + } + + claim_pin(clock); + claim_pin(data0); + claim_pin(data1); + claim_pin(data2); + claim_pin(data3); + claim_pin(cs); + if (dcx != NULL) { + claim_pin(dcx); + gpio_set_direction((gpio_num_t)self->dcx_pin, GPIO_MODE_OUTPUT); + gpio_set_level((gpio_num_t)self->dcx_pin, 1); + } + + if (reset != NULL) { + claim_pin(reset); + + gpio_set_direction((gpio_num_t)self->reset_pin, GPIO_MODE_OUTPUT); + gpio_set_level((gpio_num_t)self->reset_pin, 0); + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level((gpio_num_t)self->reset_pin, 1); + vTaskDelay(pdMS_TO_TICKS(120)); + } +} + +void common_hal_qspibus_qspibus_deinit(qspibus_qspibus_obj_t *self) { + if (self->bus_initialized) { + qspibus_panel_sleep_best_effort(self); + self->in_transaction = false; + + if (self->io_handle != NULL) { + esp_lcd_panel_io_del(self->io_handle); + self->io_handle = NULL; + } + + spi_bus_free(self->host_id); + self->bus_initialized = false; + } + + if (self->transfer_done_sem != NULL) { + // Set NULL before delete so late ISR callbacks (if any) see NULL and skip. + SemaphoreHandle_t sem = self->transfer_done_sem; + self->transfer_done_sem = NULL; + vSemaphoreDelete(sem); + } + + qspibus_release_dma_buffers(self); + + reset_pin_number(self->clock_pin); + reset_pin_number(self->data0_pin); + reset_pin_number(self->data1_pin); + reset_pin_number(self->data2_pin); + reset_pin_number(self->data3_pin); + reset_pin_number(self->cs_pin); + if (self->dcx_pin >= 0) { + reset_pin_number(self->dcx_pin); + } + if (self->reset_pin >= 0) { + reset_pin_number(self->reset_pin); + } + + self->bus_initialized = false; + self->in_transaction = false; + self->has_pending_command = false; + self->pending_command = 0; + self->transfer_in_progress = false; + self->inflight_transfers = 0; +} + +bool common_hal_qspibus_qspibus_deinited(qspibus_qspibus_obj_t *self) { + return !self->bus_initialized; +} + +void common_hal_qspibus_qspibus_write_command( + qspibus_qspibus_obj_t *self, + uint8_t command) { + if (!self->bus_initialized) { + raise_deinited_error(); + } + if (self->in_transaction) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); + } + + // If caller stages command-only operations repeatedly, flush the previous + // pending command as no-data before replacing it. + if (self->has_pending_command) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + } + + self->pending_command = command; + self->has_pending_command = true; +} + +void common_hal_qspibus_qspibus_write_data( + qspibus_qspibus_obj_t *self, + const uint8_t *data, + size_t len) { + if (!self->bus_initialized) { + raise_deinited_error(); + } + if (self->in_transaction) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); + } + if (len == 0) { + if (self->has_pending_command) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + self->has_pending_command = false; + } + return; + } + if (!self->has_pending_command) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); + } + + if (qspibus_is_color_payload_command(self->pending_command)) { + qspibus_send_color_bytes(self, self->pending_command, data, len); + // Python API: wait for DMA to finish so callers see the transfer as + // complete on return. The internal displayio path skips this wait + // to allow fill_area/DMA overlap. + if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg(MP_ERROR_TEXT("Operation timed out")); + } + } else { + qspibus_send_command_bytes(self, self->pending_command, data, len); + } + self->has_pending_command = false; +} + +bool common_hal_qspibus_qspibus_reset(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + if (!self->bus_initialized || self->reset_pin < 0) { + return false; + } + + gpio_set_level((gpio_num_t)self->reset_pin, 0); + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level((gpio_num_t)self->reset_pin, 1); + vTaskDelay(pdMS_TO_TICKS(120)); + return true; +} + +bool common_hal_qspibus_qspibus_bus_free(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + return self->bus_initialized && !self->in_transaction && !self->transfer_in_progress && !self->has_pending_command; +} + +bool common_hal_qspibus_qspibus_begin_transaction(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + if (!self->bus_initialized || self->in_transaction || self->has_pending_command) { + return false; + } + // Wait for any in-flight DMA to complete before starting a new + // transaction. This replaces the old non-blocking bus_free() check + // and enables fill_area()/DMA overlap: the CPU fills the next + // subrectangle while the previous DMA runs, and this wait only + // blocks when we actually need the bus for the next send. + if (self->transfer_in_progress) { + if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + return false; + } + } + self->in_transaction = true; + return true; +} + +void common_hal_qspibus_qspibus_send( + mp_obj_t obj, + display_byte_type_t data_type, + display_chip_select_behavior_t chip_select, + const uint8_t *data, + uint32_t data_length) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + (void)chip_select; + if (!self->bus_initialized) { + raise_deinited_error(); + } + if (!self->in_transaction) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); + } + + if (data_type == DISPLAY_COMMAND) { + for (uint32_t i = 0; i < data_length; i++) { + if (self->has_pending_command) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + } + self->pending_command = data[i]; + self->has_pending_command = true; + } + return; + } + + if (!self->has_pending_command) { + if (data_length == 0) { + // Zero-length data write after a no-data command is benign. + return; + } + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); + } + + if (data_length == 0) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + self->has_pending_command = false; + return; + } + + if (qspibus_is_color_payload_command(self->pending_command)) { + qspibus_send_color_bytes(self, self->pending_command, data, data_length); + } else { + qspibus_send_command_bytes(self, self->pending_command, data, data_length); + } + self->has_pending_command = false; +} + +void common_hal_qspibus_qspibus_end_transaction(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + if (!self->bus_initialized) { + return; + } + if (self->has_pending_command) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + self->has_pending_command = false; + } + self->in_transaction = false; +} + +void common_hal_qspibus_qspibus_flush(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + if (!self->bus_initialized) { + return; + } + if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + } +} + +void common_hal_qspibus_qspibus_collect_ptrs(mp_obj_t obj) { + (void)obj; +} diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.h b/ports/espressif/common-hal/qspibus/QSPIBus.h new file mode 100644 index 00000000000..eaaa971a79c --- /dev/null +++ b/ports/espressif/common-hal/qspibus/QSPIBus.h @@ -0,0 +1,50 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include + +#include "py/obj.h" + +#include "esp-idf/components/esp_lcd/include/esp_lcd_panel_io.h" +#include "driver/spi_master.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +typedef struct { + mp_obj_base_t base; + + // ESP LCD panel IO handle used for QSPI transactions. + esp_lcd_panel_io_handle_t io_handle; + + // SPI host (SPI2_HOST on ESP32-S3). + spi_host_device_t host_id; + + // Claimed GPIO numbers. + int8_t clock_pin; + int8_t data0_pin; + int8_t data1_pin; + int8_t data2_pin; + int8_t data3_pin; + int8_t cs_pin; + int8_t dcx_pin; // -1 when optional DCX line is not provided. + int8_t reset_pin; // -1 when reset line is not provided. + + uint32_t frequency; + bool bus_initialized; + bool in_transaction; + bool has_pending_command; + uint8_t pending_command; + bool transfer_in_progress; + uint8_t active_buffer; + uint8_t inflight_transfers; + size_t dma_buffer_size; + uint8_t *dma_buffer[2]; + + // Signaled from ISR when panel IO transfer completes. + SemaphoreHandle_t transfer_done_sem; +} qspibus_qspibus_obj_t; diff --git a/ports/espressif/common-hal/qspibus/__init__.c b/ports/espressif/common-hal/qspibus/__init__.c new file mode 100644 index 00000000000..2f763b218cb --- /dev/null +++ b/ports/espressif/common-hal/qspibus/__init__.c @@ -0,0 +1,3 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT diff --git a/ports/espressif/common-hal/qspibus/__init__.h b/ports/espressif/common-hal/qspibus/__init__.h new file mode 100644 index 00000000000..2f763b218cb --- /dev/null +++ b/ports/espressif/common-hal/qspibus/__init__.h @@ -0,0 +1,3 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT diff --git a/ports/espressif/common-hal/sdioio/SDCard.c b/ports/espressif/common-hal/sdioio/SDCard.c index 87ba32f8020..35850f2f8ae 100644 --- a/ports/espressif/common-hal/sdioio/SDCard.c +++ b/ports/espressif/common-hal/sdioio/SDCard.c @@ -10,6 +10,7 @@ #include "driver/sdmmc_host.h" #include "ports/espressif/esp-idf/components/sdmmc/include/sdmmc_cmd.h" +#include "extmod/vfs.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/util.h" #include "shared-bindings/sdioio/SDCard.h" @@ -21,6 +22,7 @@ static const char *TAG = "SDCard.c"; static bool slot_in_use[2]; static bool never_reset_sdio[2] = { false, false }; +static bool host_initialized = false; static void common_hal_sdioio_sdcard_check_for_deinit(sdioio_sdcard_obj_t *self) { if (common_hal_sdioio_sdcard_deinited(self)) { @@ -109,21 +111,22 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, if (!slot_in_use[0] && !slot_in_use[1]) { err = sdmmc_host_init(); if (err != ESP_OK) { - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error %x"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error 0x%02x"), err); } + host_initialized = true; } err = sdmmc_host_init_slot(sd_slot, &slot_config); if (err != ESP_OK) { ESP_LOGW(TAG, "Failed to initialize SDMMC slot: %x", err); - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error %x"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error 0x%02x"), err); } // sdmmc_card_t card; // self->card = malloc(sizeof(sdmmc_card_t)); err = sdmmc_card_init(&host, &self->card); if (err != ESP_OK) { ESP_LOGW(TAG, "Failed to initialize SDMMC card: %x", err); - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error %x"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error 0x%02x"), err); } common_hal_sdioio_sdcard_check_for_deinit(self); @@ -168,32 +171,73 @@ static void check_whole_block(mp_buffer_info_t *bufinfo, int sector_size) { } } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { - common_hal_sdioio_sdcard_check_for_deinit(self); - check_whole_block(bufinfo, self->card.csd.sector_size); - esp_err_t err; - ESP_LOGI(TAG, "in common_hal_sdioio_sdcard_writeblocks"); - // err = sdmmc_io_write_blocks(&self->card, 1, start_block, bufinfo->buf, bufinfo->len); - err = sdmmc_write_sectors(&self->card, bufinfo->buf, start_block, bufinfo->len / self->card.csd.sector_size); +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + ESP_LOGI(TAG, "in sdioio_sdcard_writeblocks"); + esp_err_t err = sdmmc_write_sectors(&self->card, buf, start_block, num_blocks); if (err != ESP_OK) { ESP_LOGW(TAG, "Failed to write blocks with err 0x%X", err); + return -MP_EIO; } return 0; } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { common_hal_sdioio_sdcard_check_for_deinit(self); check_whole_block(bufinfo, self->card.csd.sector_size); - esp_err_t err; - ESP_LOGI(TAG, "in common_hal_sdioio_sdcard_readblocks"); - // err = sdmmc_io_read_blocks(&self->card, 1, start_block, bufinfo->buf, bufinfo->len); - err = sdmmc_read_sectors(&self->card, bufinfo->buf, start_block, bufinfo->len / self->card.csd.sector_size); + + uint32_t num_blocks = bufinfo->len / self->card.csd.sector_size; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + ESP_LOGI(TAG, "in sdioio_sdcard_readblocks"); + esp_err_t err = sdmmc_read_sectors(&self->card, buf, start_block, num_blocks); if (err != ESP_OK) { ESP_LOGW(TAG, "Failed to read blocks with err 0x%X", err); + return -MP_EIO; } return 0; } +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + common_hal_sdioio_sdcard_check_for_deinit(self); + check_whole_block(bufinfo, self->card.csd.sector_size); + + uint32_t num_blocks = bufinfo->len / self->card.csd.sector_size; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } +} + bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { return true; } @@ -210,8 +254,9 @@ void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self) { never_reset_sdio[get_slot_index(self)] = false; slot_in_use[get_slot_index(self)] = false; - if (!slot_in_use[0] && !slot_in_use[1]) { + if (!slot_in_use[0] && !slot_in_use[1] && host_initialized) { sdmmc_host_deinit(); + host_initialized = false; } reset_pin_number(self->command); @@ -251,8 +296,9 @@ void sdioio_reset(void) { slot_in_use[i] = false; } } - if (!slot_in_use[0] && !slot_in_use[1]) { + if (!slot_in_use[0] && !slot_in_use[1] && host_initialized) { sdmmc_host_deinit(); + host_initialized = false; } return; diff --git a/ports/espressif/common-hal/socketpool/SocketPool.c b/ports/espressif/common-hal/socketpool/SocketPool.c index aa7461d3ffe..5d7890af171 100644 --- a/ports/espressif/common-hal/socketpool/SocketPool.c +++ b/ports/espressif/common-hal/socketpool/SocketPool.c @@ -24,18 +24,6 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel // common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking. int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) { - // As of 2022, the version of lwip in esp-idf does not handle the - // trailing-dot syntax of domain names, so emulate it. - // Remove this once https://github.com/espressif/esp-idf/issues/10013 has - // been implemented - if (host) { - size_t strlen_host = strlen(host); - if (strlen_host && host[strlen_host - 1] == '.') { - mp_obj_t nodot = mp_obj_new_str(host, strlen_host - 1); - host = mp_obj_str_get_str(nodot); - } - } - char service_buf[6]; snprintf(service_buf, sizeof(service_buf), "%d", service); diff --git a/ports/espressif/common-hal/wifi/Monitor.c b/ports/espressif/common-hal/wifi/Monitor.c index 635ba7a5a67..f6d0e6e4d8f 100644 --- a/ports/espressif/common-hal/wifi/Monitor.c +++ b/ports/espressif/common-hal/wifi/Monitor.c @@ -9,6 +9,7 @@ #include "py/mpstate.h" #include "py/runtime.h" +#include "bindings/espidf/__init__.h" #include "shared-bindings/wifi/Monitor.h" #include "shared-bindings/wifi/Packet.h" @@ -57,9 +58,26 @@ static void wifi_monitor_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type) { } } +// Tune the radio and return the channel it is on afterwards. Raises +// ValueError for a channel this radio cannot use. Any other failure, for +// example while the station is associated, leaves the radio where it was. +static uint8_t set_channel(uint8_t channel) { + esp_err_t result = esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); + if (result == ESP_ERR_INVALID_ARG) { + mp_arg_error_invalid(MP_QSTR_channel); + } else if (result != ESP_OK) { + wifi_second_chan_t second; + CHECK_ESP_RESULT(esp_wifi_get_channel(&channel, &second)); + } + return channel; +} + void common_hal_wifi_monitor_construct(wifi_monitor_obj_t *self, uint8_t channel, size_t queue) { mp_rom_error_text_t monitor_mode_init_error = MP_ERROR_TEXT("monitor init failed"); + // Before anything needs undoing on failure. + channel = set_channel(channel); + self->queue = xQueueCreate(queue, sizeof(monitor_packet_t)); if (!self->queue) { mp_raise_RuntimeError(monitor_mode_init_error); @@ -74,7 +92,6 @@ void common_hal_wifi_monitor_construct(wifi_monitor_obj_t *self, uint8_t channel if (esp_wifi_set_promiscuous(true) != ESP_OK) { mp_raise_RuntimeError(monitor_mode_init_error); } - esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); self->channel = channel; self->queue_length = queue; @@ -105,8 +122,7 @@ void common_hal_wifi_monitor_deinit(wifi_monitor_obj_t *self) { } void common_hal_wifi_monitor_set_channel(wifi_monitor_obj_t *self, uint8_t channel) { - self->channel = channel; - esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); + self->channel = set_channel(channel); } mp_obj_t common_hal_wifi_monitor_get_channel(wifi_monitor_obj_t *self) { diff --git a/ports/espressif/common-hal/wifi/Network.c b/ports/espressif/common-hal/wifi/Network.c index 5e29cad3193..ac7d963dd08 100644 --- a/ports/espressif/common-hal/wifi/Network.c +++ b/ports/espressif/common-hal/wifi/Network.c @@ -6,6 +6,8 @@ #include +#include "py/objlist.h" + #include "shared-bindings/wifi/Network.h" #include "shared-bindings/wifi/AuthMode.h" diff --git a/ports/espressif/common-hal/wifi/Radio.c b/ports/espressif/common-hal/wifi/Radio.c index dc5311bb8ad..78ce251def4 100644 --- a/ports/espressif/common-hal/wifi/Radio.c +++ b/ports/espressif/common-hal/wifi/Radio.c @@ -13,6 +13,7 @@ #include "common-hal/wifi/__init__.h" #include "shared/runtime/interrupt_char.h" #include "py/gc.h" +#include "py/mphal.h" #include "py/obj.h" #include "py/runtime.h" #include "shared-bindings/ipaddress/IPv4Address.h" @@ -24,6 +25,7 @@ #include "components/esp_netif/include/esp_netif_net_stack.h" #include "components/esp_wifi/include/esp_wifi.h" +#include "soc/soc_caps.h" #include "components/lwip/include/apps/ping/ping_sock.h" #include "lwip/sockets.h" @@ -93,6 +95,11 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { } if (!self->started && enabled) { ESP_ERROR_CHECK(esp_wifi_start()); + #if defined(SOC_WIFI_SUPPORT_5G) && SOC_WIFI_SUPPORT_5G + // Dual-band radios default to 2.4 GHz only. Enable both bands so that + // 5 GHz networks are visible to scans and can be connected to. + ESP_ERROR_CHECK(esp_wifi_set_band_mode(WIFI_BAND_MODE_AUTO)); + #endif self->started = true; common_hal_wifi_radio_set_tx_power(self, CIRCUITPY_WIFI_DEFAULT_TX_POWER); return; @@ -115,7 +122,7 @@ void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *host mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { uint8_t mac[MAC_ADDRESS_LENGTH]; - esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); + esp_wifi_get_mac(WIFI_IF_STA, mac); return mp_obj_new_bytes(mac, MAC_ADDRESS_LENGTH); } @@ -126,7 +133,7 @@ void common_hal_wifi_radio_set_mac_address(wifi_radio_obj_t *self, const uint8_t if ((mac[0] & 0b1) == 0b1) { mp_raise_RuntimeError(MP_ERROR_TEXT("Invalid multicast MAC address")); } - esp_wifi_set_mac(ESP_IF_WIFI_STA, mac); + esp_wifi_set_mac(WIFI_IF_STA, mac); } mp_float_t common_hal_wifi_radio_get_tx_power(wifi_radio_obj_t *self) { @@ -167,7 +174,7 @@ void common_hal_wifi_radio_set_power_management(wifi_radio_obj_t *self, wifi_pow // This is a typical value seen in various examples. config->sta.listen_interval = 3; esp_wifi_set_ps(WIFI_PS_MAX_MODEM); - esp_wifi_set_config(ESP_IF_WIFI_STA, config); + esp_wifi_set_config(WIFI_IF_STA, config); } break; case POWER_MANAGEMENT_NONE: @@ -181,7 +188,7 @@ void common_hal_wifi_radio_set_power_management(wifi_radio_obj_t *self, wifi_pow mp_obj_t common_hal_wifi_radio_get_mac_address_ap(wifi_radio_obj_t *self) { uint8_t mac[MAC_ADDRESS_LENGTH]; - esp_wifi_get_mac(ESP_IF_WIFI_AP, mac); + esp_wifi_get_mac(WIFI_IF_AP, mac); return mp_obj_new_bytes(mac, MAC_ADDRESS_LENGTH); } @@ -192,7 +199,7 @@ void common_hal_wifi_radio_set_mac_address_ap(wifi_radio_obj_t *self, const uint if ((mac[0] & 0b1) == 0b1) { mp_raise_RuntimeError(MP_ERROR_TEXT("Invalid multicast MAC address")); } - esp_wifi_set_mac(ESP_IF_WIFI_AP, mac); + esp_wifi_set_mac(WIFI_IF_AP, mac); } mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self, uint8_t start_channel, uint8_t stop_channel) { @@ -235,6 +242,7 @@ void common_hal_wifi_radio_stop_station(wifi_radio_obj_t *self) { } void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_t ssid_len, uint8_t *password, size_t password_len, uint8_t channel, uint32_t authmode, uint8_t max_connections) { + bool was_ap = self->ap_mode; set_mode_ap(self, true); uint8_t esp_authmode = 0; @@ -268,7 +276,25 @@ void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_ config->ap.max_connection = max_connections; - esp_wifi_set_config(WIFI_IF_AP, config); + esp_err_t result = esp_wifi_set_config(WIFI_IF_AP, config); + if (result != ESP_OK) { + if (!was_ap) { + set_mode_ap(self, false); + } + // The IDF returns ESP_ERR_INVALID_ARG for a channel this radio or its + // country setting cannot use (wifi_ap_config_t.channel). + if (result == ESP_ERR_INVALID_ARG) { + mp_arg_error_invalid(MP_QSTR_channel); + } + raise_esp_error(result); + } + // Wait a few ms for the AP to start. Empirically, this takes < 3ms on ESP32, and < 1ms on other chips. + for (size_t ms = 0; ms < 10; ms++) { + if (common_hal_wifi_radio_get_ap_active(self)) { + break; + } + mp_hal_delay_ms(1); + } } bool common_hal_wifi_radio_get_ap_active(wifi_radio_obj_t *self) { @@ -386,7 +412,7 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t } else { config->sta.scan_method = WIFI_FAST_SCAN; } - esp_wifi_set_config(ESP_IF_WIFI_STA, config); + esp_wifi_set_config(WIFI_IF_STA, config); self->starting_retries = 5; self->retries_left = 5; esp_wifi_connect(); diff --git a/ports/espressif/common-hal/wifi/ScannedNetworks.c b/ports/espressif/common-hal/wifi/ScannedNetworks.c index 02edb9bd036..0a87d3ab342 100644 --- a/ports/espressif/common-hal/wifi/ScannedNetworks.c +++ b/ports/espressif/common-hal/wifi/ScannedNetworks.c @@ -18,6 +18,7 @@ #include "shared-bindings/wifi/ScannedNetworks.h" #include "components/esp_wifi/include/esp_wifi.h" +#include "soc/soc_caps.h" static void wifi_scannednetworks_done(wifi_scannednetworks_obj_t *self) { self->done = true; @@ -111,29 +112,38 @@ mp_obj_t common_hal_wifi_scannednetworks_next(wifi_scannednetworks_obj_t *self) } // We don't do a linear scan so that we look at a variety of spectrum up front. +#if defined(SOC_WIFI_SUPPORT_5G) && SOC_WIFI_SUPPORT_5G +// 2.4 GHz first, then the 5 GHz U-NII bands. DFS channels are omitted: +// they require radar detection before transmitting. +static uint8_t scan_pattern[] = {6, 1, 11, 3, 9, 13, 2, 4, 8, 12, 5, 7, 10, 14, + 36, 40, 44, 48, 149, 153, 157, 161, 165, 0}; +#else static uint8_t scan_pattern[] = {6, 1, 11, 3, 9, 13, 2, 4, 8, 12, 5, 7, 10, 14, 0}; +#endif void wifi_scannednetworks_scan_next_channel(wifi_scannednetworks_obj_t *self) { - // There is no channel 0, so use that as a flag to indicate we've run out of channels to scan. - uint8_t next_channel = 0; - while (self->current_channel_index < sizeof(scan_pattern)) { - next_channel = scan_pattern[self->current_channel_index]; - self->current_channel_index++; - // Scan only channels that are in the specified range. - if (self->start_channel <= next_channel && next_channel <= self->end_channel) { - break; + while (true) { + // There is no channel 0, so use that as a flag to indicate we've run out of channels to scan. + uint8_t next_channel = 0; + while (self->current_channel_index < sizeof(scan_pattern)) { + next_channel = scan_pattern[self->current_channel_index]; + self->current_channel_index++; + // Scan only channels that are in the specified range. + if (self->start_channel <= next_channel && next_channel <= self->end_channel) { + break; + } } - } - wifi_scan_config_t config = { 0 }; - config.channel = next_channel; - if (next_channel == 0) { - wifi_scannednetworks_done(self); - } else { - esp_err_t result = esp_wifi_scan_start(&config, false); - if (result != ESP_OK) { + if (next_channel == 0) { wifi_scannednetworks_done(self); - } else { + return; + } + wifi_scan_config_t config = { 0 }; + config.channel = next_channel; + // The radio rejects channels outside the band it is set to. Skip those + // rather than ending the scan, so the rest of the pattern still runs. + if (esp_wifi_scan_start(&config, false) == ESP_OK) { self->channel_scan_in_progress = true; + return; } } } diff --git a/ports/espressif/common-hal/wifi/__init__.c b/ports/espressif/common-hal/wifi/__init__.c index 1a4c014bfbc..7a9aea3b5e0 100644 --- a/ports/espressif/common-hal/wifi/__init__.c +++ b/ports/espressif/common-hal/wifi/__init__.c @@ -30,6 +30,10 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include "lwip/sockets.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + #if CIRCUITPY_STATUS_BAR #include "supervisor/shared/status_bar.h" #endif @@ -88,7 +92,192 @@ static void event_handler(void *arg, esp_event_base_t event_base, ESP_LOGW(TAG, "disconnected"); wifi_event_sta_disconnected_t *d = (wifi_event_sta_disconnected_t *)event_data; uint8_t reason = d->reason; - ESP_LOGW(TAG, "reason %d 0x%02x", reason, reason); + const char *reason_str = "unknown"; + switch (reason) { + case WIFI_REASON_UNSPECIFIED: + reason_str = "unspecified"; + break; + case WIFI_REASON_AUTH_EXPIRE: + reason_str = "auth expire"; + break; + case WIFI_REASON_AUTH_LEAVE: + reason_str = "auth leave"; + break; + case WIFI_REASON_DISASSOC_DUE_TO_INACTIVITY: + reason_str = "disassoc inactivity"; + break; + case WIFI_REASON_ASSOC_TOOMANY: + reason_str = "assoc toomany"; + break; + case WIFI_REASON_CLASS2_FRAME_FROM_NONAUTH_STA: + reason_str = "class2 from nonauth"; + break; + case WIFI_REASON_CLASS3_FRAME_FROM_NONASSOC_STA: + reason_str = "class3 from nonassoc"; + break; + case WIFI_REASON_ASSOC_LEAVE: + reason_str = "assoc leave"; + break; + case WIFI_REASON_ASSOC_NOT_AUTHED: + reason_str = "assoc not authed"; + break; + case WIFI_REASON_DISASSOC_PWRCAP_BAD: + reason_str = "disassoc pwrcap bad"; + break; + case WIFI_REASON_DISASSOC_SUPCHAN_BAD: + reason_str = "disassoc supchan bad"; + break; + case WIFI_REASON_BSS_TRANSITION_DISASSOC: + reason_str = "bss transition disassoc"; + break; + case WIFI_REASON_IE_INVALID: + reason_str = "ie invalid"; + break; + case WIFI_REASON_MIC_FAILURE: + reason_str = "mic failure"; + break; + case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: + reason_str = "4way handshake timeout"; + break; + case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT: + reason_str = "group key update timeout"; + break; + case WIFI_REASON_IE_IN_4WAY_DIFFERS: + reason_str = "ie in 4way differs"; + break; + case WIFI_REASON_GROUP_CIPHER_INVALID: + reason_str = "group cipher invalid"; + break; + case WIFI_REASON_PAIRWISE_CIPHER_INVALID: + reason_str = "pairwise cipher invalid"; + break; + case WIFI_REASON_AKMP_INVALID: + reason_str = "akmp invalid"; + break; + case WIFI_REASON_UNSUPP_RSN_IE_VERSION: + reason_str = "unsupp rsn ie version"; + break; + case WIFI_REASON_INVALID_RSN_IE_CAP: + reason_str = "invalid rsn ie cap"; + break; + case WIFI_REASON_802_1X_AUTH_FAILED: + reason_str = "802.1x auth failed"; + break; + case WIFI_REASON_CIPHER_SUITE_REJECTED: + reason_str = "cipher suite rejected"; + break; + case WIFI_REASON_TDLS_PEER_UNREACHABLE: + reason_str = "tdls peer unreachable"; + break; + case WIFI_REASON_TDLS_UNSPECIFIED: + reason_str = "tdls unspecified"; + break; + case WIFI_REASON_SSP_REQUESTED_DISASSOC: + reason_str = "ssp requested disassoc"; + break; + case WIFI_REASON_NO_SSP_ROAMING_AGREEMENT: + reason_str = "no ssp roaming agreement"; + break; + case WIFI_REASON_BAD_CIPHER_OR_AKM: + reason_str = "bad cipher or akm"; + break; + case WIFI_REASON_NOT_AUTHORIZED_THIS_LOCATION: + reason_str = "not authorized this location"; + break; + case WIFI_REASON_SERVICE_CHANGE_PERCLUDES_TS: + reason_str = "service change precludes ts"; + break; + case WIFI_REASON_UNSPECIFIED_QOS: + reason_str = "unspecified qos"; + break; + case WIFI_REASON_NOT_ENOUGH_BANDWIDTH: + reason_str = "not enough bandwidth"; + break; + case WIFI_REASON_MISSING_ACKS: + reason_str = "missing acks"; + break; + case WIFI_REASON_EXCEEDED_TXOP: + reason_str = "exceeded txop"; + break; + case WIFI_REASON_STA_LEAVING: + reason_str = "sta leaving"; + break; + case WIFI_REASON_END_BA: + reason_str = "end ba"; + break; + case WIFI_REASON_UNKNOWN_BA: + reason_str = "unknown ba"; + break; + case WIFI_REASON_TIMEOUT: + reason_str = "timeout"; + break; + case WIFI_REASON_PEER_INITIATED: + reason_str = "peer initiated"; + break; + case WIFI_REASON_AP_INITIATED: + reason_str = "ap initiated"; + break; + case WIFI_REASON_INVALID_FT_ACTION_FRAME_COUNT: + reason_str = "invalid ft action frame count"; + break; + case WIFI_REASON_INVALID_PMKID: + reason_str = "invalid pmkid"; + break; + case WIFI_REASON_INVALID_MDE: + reason_str = "invalid mde"; + break; + case WIFI_REASON_INVALID_FTE: + reason_str = "invalid fte"; + break; + case WIFI_REASON_TRANSMISSION_LINK_ESTABLISH_FAILED: + reason_str = "transmission link establish failed"; + break; + case WIFI_REASON_ALTERATIVE_CHANNEL_OCCUPIED: + reason_str = "alternative channel occupied"; + break; + case WIFI_REASON_BEACON_TIMEOUT: + reason_str = "beacon timeout"; + break; + case WIFI_REASON_NO_AP_FOUND: + reason_str = "no ap found"; + break; + case WIFI_REASON_AUTH_FAIL: + reason_str = "auth fail"; + break; + case WIFI_REASON_ASSOC_FAIL: + reason_str = "assoc fail"; + break; + case WIFI_REASON_HANDSHAKE_TIMEOUT: + reason_str = "handshake timeout"; + break; + case WIFI_REASON_CONNECTION_FAIL: + reason_str = "connection fail"; + break; + case WIFI_REASON_AP_TSF_RESET: + reason_str = "ap tsf reset"; + break; + case WIFI_REASON_ROAMING: + reason_str = "roaming"; + break; + case WIFI_REASON_ASSOC_COMEBACK_TIME_TOO_LONG: + reason_str = "assoc comeback time too long"; + break; + case WIFI_REASON_SA_QUERY_TIMEOUT: + reason_str = "sa query timeout"; + break; + case WIFI_REASON_NO_AP_FOUND_W_COMPATIBLE_SECURITY: + reason_str = "no ap found w compatible security"; + break; + case WIFI_REASON_NO_AP_FOUND_IN_AUTHMODE_THRESHOLD: + reason_str = "no ap found in authmode threshold"; + break; + case WIFI_REASON_NO_AP_FOUND_IN_RSSI_THRESHOLD: + reason_str = "no ap found in rssi threshold"; + break; + default: + break; + } + ESP_LOGW(TAG, "reason %d 0x%02x %s", reason, reason, reason_str); if (radio->retries_left > 0 && reason != WIFI_REASON_AUTH_FAIL && reason != WIFI_REASON_NO_AP_FOUND && @@ -104,12 +293,132 @@ static void event_handler(void *arg, esp_event_base_t event_base, break; } - // Cases to handle later. - // case WIFI_EVENT_STA_AUTHMODE_CHANGE: - default: { - ESP_LOGW(TAG, "event %ld 0x%02ld", event_id, event_id); + case WIFI_EVENT_WIFI_READY: + ESP_LOGW(TAG, "wifi ready"); + break; + case WIFI_EVENT_STA_AUTHMODE_CHANGE: + ESP_LOGW(TAG, "sta authmode change"); + break; + case WIFI_EVENT_STA_WPS_ER_SUCCESS: + ESP_LOGW(TAG, "sta wps er success"); + break; + case WIFI_EVENT_STA_WPS_ER_FAILED: + ESP_LOGW(TAG, "sta wps er failed"); + break; + case WIFI_EVENT_STA_WPS_ER_TIMEOUT: + ESP_LOGW(TAG, "sta wps er timeout"); + break; + case WIFI_EVENT_STA_WPS_ER_PIN: + ESP_LOGW(TAG, "sta wps er pin"); + break; + case WIFI_EVENT_STA_WPS_ER_PBC_OVERLAP: + ESP_LOGW(TAG, "sta wps er pbc overlap"); + break; + case WIFI_EVENT_AP_PROBEREQRECVED: + ESP_LOGW(TAG, "ap probereqrecved"); + break; + case WIFI_EVENT_FTM_REPORT: + ESP_LOGW(TAG, "ftm report"); + break; + case WIFI_EVENT_STA_BSS_RSSI_LOW: + ESP_LOGW(TAG, "sta bss rssi low"); + break; + case WIFI_EVENT_ACTION_TX_STATUS: + ESP_LOGW(TAG, "action tx status"); + break; + case WIFI_EVENT_ROC_DONE: + ESP_LOGW(TAG, "roc done"); + break; + case WIFI_EVENT_STA_BEACON_TIMEOUT: + ESP_LOGW(TAG, "sta beacon timeout"); + break; + case WIFI_EVENT_CONNECTIONLESS_MODULE_WAKE_INTERVAL_START: + ESP_LOGW(TAG, "connectionless module wake interval start"); + break; + case WIFI_EVENT_AP_WPS_RG_SUCCESS: + ESP_LOGW(TAG, "ap wps rg success"); + break; + case WIFI_EVENT_AP_WPS_RG_FAILED: + ESP_LOGW(TAG, "ap wps rg failed"); + break; + case WIFI_EVENT_AP_WPS_RG_TIMEOUT: + ESP_LOGW(TAG, "ap wps rg timeout"); + break; + case WIFI_EVENT_AP_WPS_RG_PIN: + ESP_LOGW(TAG, "ap wps rg pin"); + break; + case WIFI_EVENT_AP_WPS_RG_PBC_OVERLAP: + ESP_LOGW(TAG, "ap wps rg pbc overlap"); + break; + case WIFI_EVENT_ITWT_SETUP: + ESP_LOGW(TAG, "itwt setup"); + break; + case WIFI_EVENT_ITWT_TEARDOWN: + ESP_LOGW(TAG, "itwt teardown"); + break; + case WIFI_EVENT_ITWT_PROBE: + ESP_LOGW(TAG, "itwt probe"); + break; + case WIFI_EVENT_ITWT_SUSPEND: + ESP_LOGW(TAG, "itwt suspend"); + break; + case WIFI_EVENT_TWT_WAKEUP: + ESP_LOGW(TAG, "twt wakeup"); + break; + case WIFI_EVENT_BTWT_SETUP: + ESP_LOGW(TAG, "btwt setup"); + break; + case WIFI_EVENT_BTWT_TEARDOWN: + ESP_LOGW(TAG, "btwt teardown"); + break; + case WIFI_EVENT_NAN_SYNC_STARTED: + ESP_LOGW(TAG, "nan sync started"); + break; + case WIFI_EVENT_NAN_SYNC_STOPPED: + ESP_LOGW(TAG, "nan sync stopped"); + break; + case WIFI_EVENT_NAN_SVC_MATCH: + ESP_LOGW(TAG, "nan svc match"); + break; + case WIFI_EVENT_NAN_REPLIED: + ESP_LOGW(TAG, "nan replied"); + break; + case WIFI_EVENT_NAN_RECEIVE: + ESP_LOGW(TAG, "nan receive"); + break; + case WIFI_EVENT_NDP_INDICATION: + ESP_LOGW(TAG, "ndp indication"); + break; + case WIFI_EVENT_NDP_CONFIRM: + ESP_LOGW(TAG, "ndp confirm"); + break; + case WIFI_EVENT_NDP_TERMINATED: + ESP_LOGW(TAG, "ndp terminated"); + break; + case WIFI_EVENT_HOME_CHANNEL_CHANGE: + ESP_LOGW(TAG, "home channel change"); + break; + case WIFI_EVENT_STA_NEIGHBOR_REP: + ESP_LOGW(TAG, "sta neighbor rep"); + break; + case WIFI_EVENT_AP_WRONG_PASSWORD: + ESP_LOGW(TAG, "ap wrong password"); + break; + case WIFI_EVENT_STA_BEACON_OFFSET_UNSTABLE: + ESP_LOGW(TAG, "sta beacon offset unstable"); + break; + case WIFI_EVENT_DPP_URI_READY: + ESP_LOGW(TAG, "dpp uri ready"); + break; + case WIFI_EVENT_DPP_CFG_RECVD: + ESP_LOGW(TAG, "dpp cfg recvd"); + break; + case WIFI_EVENT_DPP_FAILED: + ESP_LOGW(TAG, "dpp failed"); + break; + default: + ESP_LOGW(TAG, "unknown event %ld", event_id); break; - } } } @@ -146,8 +455,8 @@ void common_hal_wifi_init(bool user_initiated) { common_hal_wifi_radio_obj.base.type = &wifi_radio_type; if (!wifi_ever_inited) { - ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(esp_netif_init()); wifi_ever_inited = true; } @@ -175,6 +484,7 @@ void common_hal_wifi_init(bool user_initiated) { &self->handler_instance_got_ip)); wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); + esp_err_t result = esp_wifi_init(&config); #ifdef CONFIG_ESP32_WIFI_NVS_ENABLED // Generally we don't use this because we store ssid and passwords ourselves in the filesystem. esp_err_t err = nvs_flash_init(); @@ -185,8 +495,10 @@ void common_hal_wifi_init(bool user_initiated) { err = nvs_flash_init(); } ESP_ERROR_CHECK(err); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH)); + #else + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); #endif - esp_err_t result = esp_wifi_init(&config); if (result == ESP_ERR_NO_MEM) { if (gc_alloc_possible()) { mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Failed to allocate Wifi memory")); @@ -199,23 +511,36 @@ void common_hal_wifi_init(bool user_initiated) { ESP_LOGE(TAG, "WiFi error code: %x", result); return; } - // Set the default lwip_local_hostname capped at 32 characters. We trim off - // the start of the board name (likely manufacturer) because the end is - // often more unique to the board. - size_t board_len = MIN(32 - ((MAC_ADDRESS_LENGTH * 2) + 6), strlen(CIRCUITPY_BOARD_ID)); - size_t board_trim = strlen(CIRCUITPY_BOARD_ID) - board_len; - // Avoid double _ in the hostname. - if (CIRCUITPY_BOARD_ID[board_trim] == '_') { - board_trim++; + + #if CIRCUITPY_SETTINGS_TOML + char hostname[CONFIG_LWIP_DHCPS_MAX_HOSTNAME_LEN]; + if (settings_get_str("CIRCUITPY_WIFI_HOSTNAME", hostname, sizeof(hostname)) == SETTINGS_OK) { + ESP_ERROR_CHECK(esp_netif_set_hostname(self->netif, hostname)); + } + #else + if (false) { } + #endif + else { + // Set the default lwip_local_hostname capped at 32 characters. We trim off + // the start of the board name (likely manufacturer) because the end is + // often more unique to the board. + size_t board_len = MIN(32 - ((MAC_ADDRESS_LENGTH * 2) + 6), strlen(CIRCUITPY_BOARD_ID)); + size_t board_trim = strlen(CIRCUITPY_BOARD_ID) - board_len; + // Avoid double _ in the hostname. + if (CIRCUITPY_BOARD_ID[board_trim] == '_') { + board_trim++; + } + + char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; + uint8_t mac[MAC_ADDRESS_LENGTH]; + esp_wifi_get_mac(WIFI_IF_STA, mac); + snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; - uint8_t mac[MAC_ADDRESS_LENGTH]; - esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); - snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + const char *default_lwip_local_hostname = cpy_default_hostname; + ESP_ERROR_CHECK(esp_netif_set_hostname(self->netif, default_lwip_local_hostname)); + } - const char *default_lwip_local_hostname = cpy_default_hostname; - ESP_ERROR_CHECK(esp_netif_set_hostname(self->netif, default_lwip_local_hostname)); // set station mode to avoid the default SoftAP common_hal_wifi_radio_start_station(self); // start wifi diff --git a/ports/espressif/esp-camera b/ports/espressif/esp-camera index 243560e9499..303985ab678 160000 --- a/ports/espressif/esp-camera +++ b/ports/espressif/esp-camera @@ -1 +1 @@ -Subproject commit 243560e94997c262565ed537154b0578b8ce2197 +Subproject commit 303985ab678391b78ebe0baff98edcc863f296c2 diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index f50ec8ecdb3..2b900d1222c 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit f50ec8ecdb31f681e6a778f145de95f849c1089d +Subproject commit 2b900d1222cfce5dfa340ed99375af69ec1ee192 diff --git a/ports/espressif/esp-idf-config/sdkconfig-debug.defaults b/ports/espressif/esp-idf-config/sdkconfig-debug.defaults index a9c8e34e547..368ba81bb4a 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-debug.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-debug.defaults @@ -7,6 +7,21 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y # end of Compiler options +# Bootloader config +# +# +# Log +# +# +# Format +# +CONFIG_BOOTLOADER_LOG_COLORS=y +# end of Format + +# end of Log + +# end of Bootloader config + # # Component config # @@ -19,6 +34,17 @@ CONFIG_ESP_CONSOLE_SECONDARY_NONE=y # CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG is not set # end of ESP System Settings +# +# Log +# +# +# Format +# +CONFIG_LOG_COLORS=y +# end of Format + +# end of Log + # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32.defaults index 5789c442a62..1b2698068ed 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32.defaults @@ -62,10 +62,10 @@ CONFIG_ESP_IPC_TASK_STACK_SIZE=1536 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # # SPI Flash driver diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c2.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c2.defaults index 19c73ca5ee5..661b2b52801 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32c2.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c2.defaults @@ -43,10 +43,10 @@ CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # end of Component config diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults index 19c73ca5ee5..661b2b52801 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults @@ -43,10 +43,10 @@ CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # end of Component config diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c5.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c5.defaults new file mode 100644 index 00000000000..eb6f64cbb78 --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c5.defaults @@ -0,0 +1,54 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# Bluetooth +# +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +# +# NimBLE Options +# +CONFIG_BT_NIMBLE_LOG_LEVEL_NONE=y +CONFIG_BT_NIMBLE_NVS_PERSIST=y +# +# Memory Settings +# +CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=20 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=70 +# end of Memory Settings + +CONFIG_BT_NIMBLE_EXT_ADV=y +# end of NimBLE Options + +# end of Bluetooth + +# +# Driver Configurations +# +# +# PCNT Configuration +# +CONFIG_PCNT_CTRL_FUNC_IN_IRAM=y +# end of PCNT Configuration + +# end of Driver Configurations + +# +# Wi-Fi +# +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 +# end of Wi-Fi + +# +# mbedTLS +# +# CONFIG_MBEDTLS_HARDWARE_SHA is not set +# end of mbedTLS + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c6.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c6.defaults index 85dde905f3c..63f42cac952 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32c6.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c6.defaults @@ -49,6 +49,12 @@ CONFIG_ESP_PHY_ENABLE_USB=y CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 # end of Wi-Fi +# +# mbedTLS +# +# CONFIG_MBEDTLS_HARDWARE_SHA is not set +# end of mbedTLS + # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c61.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c61.defaults new file mode 100644 index 00000000000..85dde905f3c --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c61.defaults @@ -0,0 +1,54 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# Bluetooth +# +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +# +# NimBLE Options +# +CONFIG_BT_NIMBLE_LOG_LEVEL_NONE=y +CONFIG_BT_NIMBLE_NVS_PERSIST=y +# +# Memory Settings +# +CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=20 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=70 +# end of Memory Settings + +CONFIG_BT_NIMBLE_EXT_ADV=y +# end of NimBLE Options + +# end of Bluetooth + +# +# Driver Configurations +# +# +# PCNT Configuration +# +CONFIG_PCNT_CTRL_FUNC_IN_IRAM=y +# end of PCNT Configuration + +# end of Driver Configurations + +# +# PHY +# +CONFIG_ESP_PHY_ENABLE_USB=y +# end of PHY + +# +# Wi-Fi +# +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 +# end of Wi-Fi + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults index 5c748bd0e6f..126b49c6fd3 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults @@ -43,10 +43,10 @@ CONFIG_ESP_WIFI_RX_BA_WIN=4 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # # Ultra Low Power (ULP) Co-processor @@ -55,15 +55,9 @@ CONFIG_ULP_COPROC_ENABLED=y CONFIG_ULP_COPROC_TYPE_FSM=y CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only works due to a modification of adafruit/esp-idf # (see adafruit/esp-idf/pull/16) until espressif/esp-idf/issues/12999 is fixed. -CONFIG_ULP_COPROC_RESERVE_MEM=8176 +CONFIG_ULP_COPROC_RESERVE_MEM=8144 # end of Ultra Low Power (ULP) Co-processor -# -# FreeRTOS -# -CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y -# end of FreeRTOS - # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults index fe3c3e0a2da..b48bb58df3f 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults @@ -83,10 +83,10 @@ CONFIG_ESP_WIFI_CACHE_TX_BUFFER_NUM=16 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # # Ultra Low Power (ULP) Co-processor @@ -95,7 +95,7 @@ CONFIG_ULP_COPROC_ENABLED=y CONFIG_ULP_COPROC_TYPE_FSM=y CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only works due to a modification of adafruit/esp-idf # (see adafruit/esp-idf/pull/16) until espressif/esp-idf/issues/12999 is fixed. -CONFIG_ULP_COPROC_RESERVE_MEM=8176 +CONFIG_ULP_COPROC_RESERVE_MEM=8144 # end of Ultra Low Power (ULP) Co-processor # end of Component config diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults index 6a2285a2936..d582a77798c 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults @@ -1,2 +1,4 @@ CONFIG_ESPTOOLPY_FLASHFREQ_120M=y CONFIG_SPI_FLASH_UNDER_HIGH_FREQ=y +CONFIG_SPI_FLASH_HPM_ENA=y +CONFIG_BOOTLOADER_FLASH_DC_AWARE=y diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-2MB-no-ota-no-uf2.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-2MB-no-ota-no-uf2.defaults index 2d0b2ac5eb9..21365b751d1 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-2MB-no-ota-no-uf2.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-2MB-no-ota-no-uf2.defaults @@ -7,7 +7,6 @@ CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set CONFIG_ESPTOOLPY_FLASHSIZE="2MB" -CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y # end of Serial flasher config CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-2MB-no-ota-no-uf2.csv" diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-32MB.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-32MB.defaults index bbdd32afb81..a5a93778864 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-32MB.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-32MB.defaults @@ -8,7 +8,6 @@ # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set CONFIG_ESPTOOLPY_FLASHSIZE_32MB=y CONFIG_ESPTOOLPY_FLASHSIZE="32MB" -CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y # end of Serial flasher config CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-32MB.csv" diff --git a/ports/espressif/esp-idf-config/sdkconfig-native.defaults b/ports/espressif/esp-idf-config/sdkconfig-native.defaults new file mode 100644 index 00000000000..c3eed046a61 --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-native.defaults @@ -0,0 +1,15 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# ESP System Settings +# +# CONFIG_ESP_SYSTEM_MEMPROT is not set +# end of ESP System Settings + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-opt.defaults b/ports/espressif/esp-idf-config/sdkconfig-opt.defaults index 16f5b990386..0da23e81227 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-opt.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-opt.defaults @@ -38,6 +38,24 @@ CONFIG_ESP_CONSOLE_SECONDARY_NONE=y CONFIG_LOG_DEFAULT_LEVEL_NONE=y # end of Log output +# +# Log +# +# +# Log Level +# +# +# Level Settings +# +# CONFIG_LOG_DYNAMIC_LEVEL_CONTROL is not set +CONFIG_LOG_TAG_LEVEL_IMPL_NONE=y +# CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_AND_LINKED_LIST is not set +# end of Level Settings + +# end of Log Level + +# end of Log + # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-psram-16MB.defaults b/ports/espressif/esp-idf-config/sdkconfig-psram-16MB.defaults new file mode 100644 index 00000000000..f3f2fc60bc6 --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-psram-16MB.defaults @@ -0,0 +1,5 @@ +# CONFIG_SPIRAM_TYPE_AUTO is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_TYPE_AUTO=y diff --git a/ports/espressif/esp-idf-config/sdkconfig.defaults b/ports/espressif/esp-idf-config/sdkconfig.defaults index dd766675136..9859e5e94a8 100644 --- a/ports/espressif/esp-idf-config/sdkconfig.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig.defaults @@ -17,9 +17,15 @@ CONFIG_PARTITION_TABLE_CUSTOM=y # GPTimer Configuration # CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y -CONFIG_GPTIMER_ISR_IRAM_SAFE=y +CONFIG_GPTIMER_ISR_CACHE_SAFE=y # end of GPTimer Configuration +# +# Touch Configuration +# +CONFIG_TOUCH_SUPPRESS_DEPRECATE_WARN=y +# end of Touch Configuration + # end of Driver Configurations # @@ -59,9 +65,15 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384 CONFIG_FREERTOS_HZ=1000 # end of Kernel +# +# LibC +# +# end of LibC + # # LWIP # +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096 CONFIG_LWIP_MAX_SOCKETS=8 CONFIG_LWIP_SO_RCVBUF=y # @@ -103,16 +115,12 @@ CONFIG_MBEDTLS_SSL_PROTO_DTLS=y # CONFIG_MBEDTLS_PEM_WRITE_C is not set # end of Certificates -# CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED is not set -# CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED is not set # CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED is not set -# CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED is not set -# CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED is not set # CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED is not set # CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED is not set # CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED is not set # CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM is not set -# CONFIG_MBEDTLS_ERROR_STRINGS is not set +CONFIG_MBEDTLS_ERROR_STRINGS=y # end of mbedTLS # diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 712eb67f1f4..afcf4a9896a 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -27,8 +27,10 @@ // Nearly all boards have this because it is used to enter the ROM bootloader. #ifndef CIRCUITPY_BOOT_BUTTON - #if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) + #if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C61) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9) + #elif defined(CONFIG_IDF_TARGET_ESP32C5) + #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO28) #elif !defined(CONFIG_IDF_TARGET_ESP32) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) #endif @@ -68,3 +70,13 @@ extern portMUX_TYPE background_task_mutex; #ifndef CIRCUITPY_WIFI_DEFAULT_TX_POWER #define CIRCUITPY_WIFI_DEFAULT_TX_POWER (20) #endif + +#ifndef CIRCUITPY_ESP32P4_SWAP_LSFS +#define CIRCUITPY_ESP32P4_SWAP_LSFS (0) +#endif + +#if MICROPY_PERSISTENT_CODE_LOAD_NATIVE +// Loaded native code is copied out of the GC heap into executable RAM. +void *esp_native_code_commit(void *buf, size_t len, void *reloc); +#define MP_PLAT_COMMIT_EXEC(buf, len, reloc) esp_native_code_commit(buf, len, reloc) +#endif diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 42bf3418f96..cce516bcc7e 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -11,12 +11,18 @@ CROSS_COMPILE = riscv32-esp-elf- else ifeq ($(IDF_TARGET),esp32c3) IDF_TARGET_ARCH = riscv CROSS_COMPILE = riscv32-esp-elf- +else ifeq ($(IDF_TARGET),esp32c5) +IDF_TARGET_ARCH = riscv +CROSS_COMPILE = riscv32-esp-elf- else ifeq ($(IDF_TARGET),esp32p4) IDF_TARGET_ARCH = riscv CROSS_COMPILE = riscv32-esp-elf- else ifeq ($(IDF_TARGET),esp32c6) IDF_TARGET_ARCH = riscv CROSS_COMPILE = riscv32-esp-elf- +else ifeq ($(IDF_TARGET),esp32c61) +IDF_TARGET_ARCH = riscv +CROSS_COMPILE = riscv32-esp-elf- else ifeq ($(IDF_TARGET),esp32h2) IDF_TARGET_ARCH = riscv CROSS_COMPILE = riscv32-esp-elf- @@ -54,13 +60,19 @@ CIRCUITPY_HASHLIB_MBEDTLS_ONLY = 0 CIRCUITPY_PORT_SERIAL = 1 +CIRCUITPY_LIB_TLSF = 0 + +CIRCUITPY_LIBC_STRING0 = 0 + # These modules are implemented in ports//common-hal: CIRCUITPY__EVE ?= 1 CIRCUITPY_ALARM ?= 1 -CIRCUITPY_ALARM_TOUCH ?= 0 +CIRCUITPY_ALARM_PRESERVE_DIOS ?= 1 +CIRCUITPY_ALARM_TOUCH ?= 1 CIRCUITPY_ANALOGBUFIO ?= 1 CIRCUITPY_AUDIOBUSIO ?= 1 -CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0 +CIRCUITPY_AUDIOBUSIO_PDMIN ?= 1 +CIRCUITPY_AUDIOI2SIN ?= 1 CIRCUITPY_AUDIOIO ?= 1 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_BLEIO_NATIVE ?= 1 @@ -72,7 +84,7 @@ CIRCUITPY_ESPULP ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 CIRCUITPY_FREQUENCYIO ?= 1 CIRCUITPY_HASHLIB ?= 1 -CIRCUITPY_I2CTARGET ?= 0 +CIRCUITPY_I2CTARGET = 0 CIRCUITPY_MAX3421E ?= 1 CIRCUITPY_MEMORYMAP ?= 1 CIRCUITPY_RCLCPY ?= 0 @@ -84,6 +96,7 @@ CIRCUITPY_ROTARYIO ?= 1 CIRCUITPY_SDIOIO ?= 1 CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY ?= 1 CIRCUITPY_SYNTHIO_MAX_CHANNELS ?= 12 +CIRCUITPY_TOUCHIO ?= 1 CIRCUITPY_TOUCHIO_USE_NATIVE ?= 1 CIRCUITPY_WATCHDOG ?= 1 CIRCUITPY_WIFI ?= 1 @@ -93,12 +106,8 @@ CIRCUITPY_SOCKETPOOL_IPV6 ?= 1 #### esp32 ############################################################ ifeq ($(IDF_TARGET),esp32) # Modules -CIRCUITPY_ALARM_TOUCH = 1 CIRCUITPY_RGBMATRIX = 0 -# SDMMC not supported yet -CIRCUITPY_SDIOIO = 0 - # Has no USB CIRCUITPY_USB_DEVICE = 0 @@ -112,6 +121,10 @@ CIRCUITPY_ESPCAMERA = 0 CIRCUITPY_ESPULP = 0 CIRCUITPY_MEMORYMAP = 0 +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 + # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 @@ -128,6 +141,7 @@ CIRCUITPY_ANALOGBUFIO = 0 # No I2S CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 # No DAC CIRCUITPY_AUDIOIO = 0 @@ -140,8 +154,6 @@ CIRCUITPY_RGBMATRIX = 0 # No SDMMC CIRCUITPY_SDIOIO = 0 -CIRCUITPY_TOUCHIO ?= 1 -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 @@ -156,9 +168,17 @@ CIRCUITPY_MEMORYMAP = 0 # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 + # No DAC CIRCUITPY_AUDIOIO = 0 +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 +CIRCUITPY_AUDIOI2SIN = 0 + # No PCNT peripheral CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_COUNTIO = 0 @@ -167,8 +187,37 @@ CIRCUITPY_ROTARYIO = 0 # No SDMMC CIRCUITPY_SDIOIO = 0 -CIRCUITPY_TOUCHIO ?= 1 +# Features +CIRCUITPY_USB_DEVICE = 0 +CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 + +#### esp32c5 ########################################################## +else ifeq ($(IDF_TARGET),esp32c5) +# Modules +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_ESPULP = 0 +CIRCUITPY_MEMORYMAP = 0 +CIRCUITPY_RGBMATRIX = 0 + +# TWAI-FD generation, needs a new canio backend +CIRCUITPY_CANIO = 0 + +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 CIRCUITPY_TOUCHIO_USE_NATIVE = 0 + +# No DAC +CIRCUITPY_AUDIOIO = 0 + +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 + +# No LCD_CAM peripheral, so no esp_lcd_new_i80_bus() +CIRCUITPY_PARALLELDISPLAYBUS = 0 + +# No SDMMC +CIRCUITPY_SDIOIO = 0 + # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 @@ -181,11 +230,19 @@ CIRCUITPY_ESPULP = 0 CIRCUITPY_MEMORYMAP = 0 CIRCUITPY_RGBMATRIX = 0 +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 + # No DAC CIRCUITPY_AUDIOIO = 0 +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 + # No space for this CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 @@ -193,12 +250,52 @@ CIRCUITPY_PARALLELDISPLAYBUS = 0 # No SDMMC CIRCUITPY_SDIOIO = 0 -CIRCUITPY_TOUCHIO ?= 1 +# Features +CIRCUITPY_USB_DEVICE = 0 +CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 + +#### esp32c6 ########################################################## +else ifeq ($(IDF_TARGET),esp32c61) +# Modules +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_ESPULP = 0 +CIRCUITPY_MEMORYMAP = 0 +CIRCUITPY_RGBMATRIX = 0 + +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 CIRCUITPY_TOUCHIO_USE_NATIVE = 0 + +# No DAC +CIRCUITPY_AUDIOIO = 0 + +# No space for this +CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 + +# No I80 support from the IDF +CIRCUITPY_PARALLELDISPLAYBUS = 0 + +# No SDMMC +CIRCUITPY_SDIOIO = 0 + # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 +# No TWAI on chip +CIRCUITPY_CANIO = 0 + +# No RMT on chip +CIRCUITPY_NEOPIXEL_WRITE = 0 +CIRCUITPY_PULSEIO = 0 +CIRCUITPY_RGBMATRIX = 0 + +# No PCNT on chip +CIRCUITPY_COUNTIO = 0 +CIRCUITPY_ROTARYIO = 0 +CIRCUITPY_FREQUENCYIO = 0 + #### esp32h2 ########################################################## else ifeq ($(IDF_TARGET),esp32h2) # Modules @@ -207,18 +304,22 @@ CIRCUITPY_ESPULP = 0 CIRCUITPY_MEMORYMAP = 0 CIRCUITPY_RGBMATRIX = 0 +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 + # No DAC CIRCUITPY_AUDIOIO = 0 +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 + # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 # No SDMMC CIRCUITPY_SDIOIO = 0 -CIRCUITPY_TOUCHIO ?= 1 -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 - # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 @@ -238,13 +339,9 @@ CIRCUITPY_BLEIO_NATIVE = 0 CIRCUITPY_WIFI = 0 CIRCUITPY_SSL = 0 -CIRCUITPY_TOUCHIO = 1 -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 - # Second stage bootloader doesn't work when the factory partition is empty due to # UF2 missing. UF2_BOOTLOADER = 0 -USB_HIGHSPEED = 1 CIRCUITPY_USB_HID = 0 CIRCUITPY_USB_MIDI = 0 CIRCUITPY_TUSB_MEM_ALIGN = 64 @@ -266,11 +363,17 @@ CIRCUITPY_PARALLELDISPLAYBUS = 0 # Library doesn't support P4 yet it seems CIRCUITPY_ESPCAMERA = 0 +# P4 has MIPI-DSI +CIRCUITPY_MIPIDSI = 1 + #### esp32s2 ########################################################## else ifeq ($(IDF_TARGET),esp32s2) # Modules -CIRCUITPY_ALARM_TOUCH = $(CIRCUITPY_ALARM) CIRCUITPY_AUDIOIO ?= 1 +CIRCUITPY_AUDIOFILEWRITER ?= 1 + +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 # No BLE in hw CIRCUITPY_BLEIO_NATIVE = 0 @@ -284,8 +387,6 @@ CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0 else ifeq ($(IDF_TARGET),esp32s3) # Modules -CIRCUITPY_ALARM_TOUCH = $(CIRCUITPY_ALARM) -CIRCUITPY_AUDIOBUSIO_PDMIN = 1 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0 # No DAC @@ -294,6 +395,12 @@ CIRCUITPY_AUDIOIO = 0 endif #### end chip-specific choices ######################################## +# By default, load native .mpy files. Boards without the flash space turn it off. +CIRCUITPY_LOAD_NATIVE ?= 1 + +# By default, enable dualbank, and it'll be disabled for small flash sizes +CIRCUITPY_DUALBANK ?= 1 + # No room for large modules on 2MB boards # 2MB boards have a single firmware partition, and can't do dualbank. ifeq ($(CIRCUITPY_ESP_FLASH_SIZE),2MB) @@ -326,7 +433,7 @@ CIRCUITPY_JPEGIO ?= $(CIRCUITPY_DISPLAYIO) CIRCUITPY_QRIO ?= $(CIRCUITPY_ESPCAMERA) CIRCUITPY_BLE_FILE_SERVICE ?= $(CIRCUITPY_BLEIO_NATIVE) -CIRCUITPY_SERIAL_BLE ?= $(CIRCUITPY_BLEIO_NATIVE) +CIRCUITPY_BLE_SERIAL_SERVICE ?= $(CIRCUITPY_BLEIO_NATIVE) # Features dependent on other features ifneq ($(CIRCUITPY_USB_DEVICE),0) @@ -347,5 +454,18 @@ endif USB_NUM_ENDPOINT_PAIRS = 7 USB_NUM_IN_ENDPOINTS = 5 +# usb_audio is compiled in on the S3 but claims no endpoints until +# usb_audio.enable() is called from boot.py, so enabling it by default does not +# affect existing boards. Freeing one IN endpoint (usb_hid.disable()) is then the +# only thing a user needs, with no custom build. +ifeq ($(IDF_TARGET),esp32s3) +# It needs the TinyUSB device stack and audiocore, so leave it off for boards +# that turn either off. The S3 has no AUDIOIO and no AUDIOPWMIO, so audiocore +# follows CIRCUITPY_AUDIOBUSIO here. +ifeq ($(filter 0,$(CIRCUITPY_USB_DEVICE) $(CIRCUITPY_AUDIOCORE) $(CIRCUITPY_AUDIOBUSIO)),) +CIRCUITPY_USB_AUDIO ?= 1 +endif +endif + # Usually lots of flash space available CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 1 diff --git a/ports/espressif/peripherals/esp32/pins.c b/ports/espressif/peripherals/esp32/pins.c index e2c45bd06fc..3aa12c9e675 100644 --- a/ports/espressif/peripherals/esp32/pins.c +++ b/ports/espressif/peripherals/esp32/pins.c @@ -6,11 +6,11 @@ #include "peripherals/pins.h" -const mcu_pin_obj_t pin_GPIO0 = PIN(0, ADC_UNIT_2, ADC_CHANNEL_1, TOUCH_PAD_NUM1); +const mcu_pin_obj_t pin_GPIO0 = PIN(0, ADC_UNIT_2, ADC_CHANNEL_1, 1); const mcu_pin_obj_t pin_GPIO1 = PIN(1, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_2, ADC_CHANNEL_2, TOUCH_PAD_NUM2); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_2, ADC_CHANNEL_2, 2); const mcu_pin_obj_t pin_GPIO3 = PIN(3, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_2, ADC_CHANNEL_0, TOUCH_PAD_NUM0); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_2, ADC_CHANNEL_0, 0); const mcu_pin_obj_t pin_GPIO5 = PIN(5, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO6 = PIN(6, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); @@ -18,10 +18,10 @@ const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL) const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_5, TOUCH_PAD_NUM5); -const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_4, TOUCH_PAD_NUM4); -const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_6, TOUCH_PAD_NUM6); -const mcu_pin_obj_t pin_GPIO15 = PIN(15, ADC_UNIT_2, ADC_CHANNEL_3, TOUCH_PAD_NUM3); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_5, 5); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_4, 4); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_6, 6); +const mcu_pin_obj_t pin_GPIO15 = PIN(15, ADC_UNIT_2, ADC_CHANNEL_3, 3); const mcu_pin_obj_t pin_GPIO16 = PIN(16, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO17 = PIN(17, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO18 = PIN(18, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); @@ -34,13 +34,13 @@ const mcu_pin_obj_t pin_GPIO23 = PIN(23, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNE // no GPIO24 const mcu_pin_obj_t pin_GPIO25 = PIN(25, ADC_UNIT_2, ADC_CHANNEL_8, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO26 = PIN(26, ADC_UNIT_2, ADC_CHANNEL_9, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO27 = PIN(27, ADC_UNIT_2, ADC_CHANNEL_7, TOUCH_PAD_NUM7); +const mcu_pin_obj_t pin_GPIO27 = PIN(27, ADC_UNIT_2, ADC_CHANNEL_7, 7); // no GPIO28 // no GPIO29 // no GPIO30 // no GPIO31 -const mcu_pin_obj_t pin_GPIO32 = PIN(32, ADC_UNIT_1, ADC_CHANNEL_4, TOUCH_PAD_NUM9); -const mcu_pin_obj_t pin_GPIO33 = PIN(33, ADC_UNIT_1, ADC_CHANNEL_5, TOUCH_PAD_NUM8); +const mcu_pin_obj_t pin_GPIO32 = PIN(32, ADC_UNIT_1, ADC_CHANNEL_4, 9); +const mcu_pin_obj_t pin_GPIO33 = PIN(33, ADC_UNIT_1, ADC_CHANNEL_5, 8); const mcu_pin_obj_t pin_GPIO34 = PIN(34, ADC_UNIT_1, ADC_CHANNEL_6, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO35 = PIN(35, ADC_UNIT_1, ADC_CHANNEL_7, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO36 = PIN(36, ADC_UNIT_1, ADC_CHANNEL_0, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32c5/pins.c b/ports/espressif/peripherals/esp32c5/pins.c new file mode 100644 index 00000000000..2abf905e18f --- /dev/null +++ b/ports/espressif/peripherals/esp32c5/pins.c @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO15 = PIN(15, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO16 = PIN(16, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO17 = PIN(17, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO18 = PIN(18, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO19 = PIN(19, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO20 = PIN(20, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO21 = PIN(21, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO22 = PIN(22, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO23 = PIN(23, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO24 = PIN(24, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO25 = PIN(25, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO26 = PIN(26, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO27 = PIN(27, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO28 = PIN(28, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32c5/pins.h b/ports/espressif/peripherals/esp32c5/pins.h new file mode 100644 index 00000000000..90c28621791 --- /dev/null +++ b/ports/espressif/peripherals/esp32c5/pins.h @@ -0,0 +1,70 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 Scott Shawcroft for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// DO NOT include this file directly. +// Use shared-bindings/microcontroller/Pin.h instead. +// This ensures that all necessary includes are already included. + +#pragma once + +#define GPIO0_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO0; +#define GPIO1_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO1; +#define GPIO2_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO2; +#define GPIO3_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO3; +#define GPIO4_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO4; +#define GPIO5_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO5; +#define GPIO6_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO6; +#define GPIO7_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO7; +#define GPIO8_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO8; +#define GPIO9_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO9; +#define GPIO10_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO10; +#define GPIO11_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO11; +#define GPIO12_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO12; +#define GPIO13_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO13; +#define GPIO14_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO14; +#define GPIO15_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO15; +#define GPIO16_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO16; +#define GPIO17_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO17; +#define GPIO18_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO18; +#define GPIO19_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO19; +#define GPIO20_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO20; +#define GPIO21_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO21; +#define GPIO22_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO22; +#define GPIO23_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO23; +#define GPIO24_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO24; +#define GPIO25_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO25; +#define GPIO26_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO26; +#define GPIO27_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO27; +#define GPIO28_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO28; diff --git a/ports/espressif/peripherals/esp32c61/pins.c b/ports/espressif/peripherals/esp32c61/pins.c new file mode 100644 index 00000000000..a32e1e8da98 --- /dev/null +++ b/ports/espressif/peripherals/esp32c61/pins.c @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_1, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_2, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_3, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO15 = PIN(15, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO16 = PIN(16, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO17 = PIN(17, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO18 = PIN(18, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO19 = PIN(19, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO20 = PIN(20, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO21 = PIN(21, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO22 = PIN(22, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO23 = PIN(23, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO24 = PIN(24, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO25 = PIN(25, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO26 = PIN(26, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO27 = PIN(27, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO28 = PIN(28, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO29 = PIN(29, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32c61/pins.h b/ports/espressif/peripherals/esp32c61/pins.h new file mode 100644 index 00000000000..908c9fe29f0 --- /dev/null +++ b/ports/espressif/peripherals/esp32c61/pins.h @@ -0,0 +1,72 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 Scott Shawcroft for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// DO NOT include this file directly. +// Use shared-bindings/microcontroller/Pin.h instead. +// This ensures that all necessary includes are already included. + +#pragma once + +#define GPIO0_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO0; +#define GPIO1_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO1; +#define GPIO2_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO2; +#define GPIO3_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO3; +#define GPIO4_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO4; +#define GPIO5_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO5; +#define GPIO6_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO6; +#define GPIO7_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO7; +#define GPIO8_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO8; +#define GPIO9_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO9; +#define GPIO10_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO10; +#define GPIO11_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO11; +#define GPIO12_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO12; +#define GPIO13_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO13; +#define GPIO14_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO14; +#define GPIO15_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO15; +#define GPIO16_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO16; +#define GPIO17_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO17; +#define GPIO18_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO18; +#define GPIO19_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO19; +#define GPIO20_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO20; +#define GPIO21_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO21; +#define GPIO22_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO22; +#define GPIO23_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO23; +#define GPIO24_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO24; +#define GPIO25_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO25; +#define GPIO26_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO26; +#define GPIO27_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO27; +#define GPIO28_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO28; +#define GPIO29_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO29; diff --git a/ports/espressif/peripherals/esp32p4/pins.c b/ports/espressif/peripherals/esp32p4/pins.c index 24e509d40c6..a4e085e6971 100644 --- a/ports/espressif/peripherals/esp32p4/pins.c +++ b/ports/espressif/peripherals/esp32p4/pins.c @@ -8,20 +8,20 @@ const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO1 = PIN(1, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO2 = PIN(2, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM0); -const mcu_pin_obj_t pin_GPIO3 = PIN(3, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM1); -const mcu_pin_obj_t pin_GPIO4 = PIN(4, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM2); -const mcu_pin_obj_t pin_GPIO5 = PIN(5, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM3); -const mcu_pin_obj_t pin_GPIO6 = PIN(6, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM4); -const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM5); -const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM6); -const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM7); -const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM8); -const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM9); -const mcu_pin_obj_t pin_GPIO12 = PIN(12, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM10); -const mcu_pin_obj_t pin_GPIO13 = PIN(13, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM11); -const mcu_pin_obj_t pin_GPIO14 = PIN(14, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM12); -const mcu_pin_obj_t pin_GPIO15 = PIN(15, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM13); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, NO_ADC, NO_ADC_CHANNEL, 0); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, NO_ADC, NO_ADC_CHANNEL, 1); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, NO_ADC, NO_ADC_CHANNEL, 2); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, NO_ADC, NO_ADC_CHANNEL, 3); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, NO_ADC, NO_ADC_CHANNEL, 4); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, 5); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, 6); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, 7); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, 8); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, 9); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, NO_ADC, NO_ADC_CHANNEL, 10); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, NO_ADC, NO_ADC_CHANNEL, 11); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, NO_ADC, NO_ADC_CHANNEL, 12); +const mcu_pin_obj_t pin_GPIO15 = PIN(15, NO_ADC, NO_ADC_CHANNEL, 13); const mcu_pin_obj_t pin_GPIO16 = PIN(16, ADC_UNIT_1, ADC_CHANNEL_0, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO17 = PIN(17, ADC_UNIT_1, ADC_CHANNEL_1, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO18 = PIN(18, ADC_UNIT_1, ADC_CHANNEL_2, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32s2/pins.c b/ports/espressif/peripherals/esp32s2/pins.c index b5e8d483175..cfaecd0ac6d 100644 --- a/ports/espressif/peripherals/esp32s2/pins.c +++ b/ports/espressif/peripherals/esp32s2/pins.c @@ -7,20 +7,20 @@ #include "peripherals/pins.h" const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, TOUCH_PAD_NUM1); -const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, TOUCH_PAD_NUM2); -const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, TOUCH_PAD_NUM3); -const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, TOUCH_PAD_NUM4); -const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, TOUCH_PAD_NUM5); -const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, TOUCH_PAD_NUM6); -const mcu_pin_obj_t pin_GPIO7 = PIN(7, ADC_UNIT_1, ADC_CHANNEL_6, TOUCH_PAD_NUM7); -const mcu_pin_obj_t pin_GPIO8 = PIN(8, ADC_UNIT_1, ADC_CHANNEL_7, TOUCH_PAD_NUM8); -const mcu_pin_obj_t pin_GPIO9 = PIN(9, ADC_UNIT_1, ADC_CHANNEL_8, TOUCH_PAD_NUM9); -const mcu_pin_obj_t pin_GPIO10 = PIN(10, ADC_UNIT_1, ADC_CHANNEL_9, TOUCH_PAD_NUM10); -const mcu_pin_obj_t pin_GPIO11 = PIN(11, ADC_UNIT_2, ADC_CHANNEL_0, TOUCH_PAD_NUM11); -const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_1, TOUCH_PAD_NUM12); -const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_2, TOUCH_PAD_NUM13); -const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_3, TOUCH_PAD_NUM14); +const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, 1); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, 2); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, 3); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, 4); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, 5); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, 6); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, ADC_UNIT_1, ADC_CHANNEL_6, 7); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, ADC_UNIT_1, ADC_CHANNEL_7, 8); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, ADC_UNIT_1, ADC_CHANNEL_8, 9); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, ADC_UNIT_1, ADC_CHANNEL_9, 10); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, ADC_UNIT_2, ADC_CHANNEL_0, 11); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_1, 12); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_2, 13); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_3, 14); const mcu_pin_obj_t pin_GPIO15 = PIN(15, ADC_UNIT_2, ADC_CHANNEL_4, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO16 = PIN(16, ADC_UNIT_2, ADC_CHANNEL_5, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO17 = PIN(17, ADC_UNIT_2, ADC_CHANNEL_6, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32s3/pins.c b/ports/espressif/peripherals/esp32s3/pins.c index c51c4b93575..745cb4a7a67 100644 --- a/ports/espressif/peripherals/esp32s3/pins.c +++ b/ports/espressif/peripherals/esp32s3/pins.c @@ -9,20 +9,20 @@ // NOTE: These numbers do NOT always match the package and module pin number. // These are by solely by GPIO numbers. const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, TOUCH_PAD_NUM1); -const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, TOUCH_PAD_NUM2); -const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, TOUCH_PAD_NUM3); -const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, TOUCH_PAD_NUM4); -const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, TOUCH_PAD_NUM5); -const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, TOUCH_PAD_NUM6); -const mcu_pin_obj_t pin_GPIO7 = PIN(7, ADC_UNIT_1, ADC_CHANNEL_6, TOUCH_PAD_NUM7); -const mcu_pin_obj_t pin_GPIO8 = PIN(8, ADC_UNIT_1, ADC_CHANNEL_7, TOUCH_PAD_NUM8); -const mcu_pin_obj_t pin_GPIO9 = PIN(9, ADC_UNIT_1, ADC_CHANNEL_8, TOUCH_PAD_NUM9); -const mcu_pin_obj_t pin_GPIO10 = PIN(10, ADC_UNIT_1, ADC_CHANNEL_9, TOUCH_PAD_NUM10); -const mcu_pin_obj_t pin_GPIO11 = PIN(11, ADC_UNIT_2, ADC_CHANNEL_0, TOUCH_PAD_NUM11); -const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_1, TOUCH_PAD_NUM12); -const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_2, TOUCH_PAD_NUM13); -const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_3, TOUCH_PAD_NUM14); +const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, 1); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, 2); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, 3); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, 4); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, 5); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, 6); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, ADC_UNIT_1, ADC_CHANNEL_6, 7); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, ADC_UNIT_1, ADC_CHANNEL_7, 8); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, ADC_UNIT_1, ADC_CHANNEL_8, 9); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, ADC_UNIT_1, ADC_CHANNEL_9, 10); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, ADC_UNIT_2, ADC_CHANNEL_0, 11); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_1, 12); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_2, 13); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_3, 14); const mcu_pin_obj_t pin_GPIO15 = PIN(15, ADC_UNIT_2, ADC_CHANNEL_4, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO16 = PIN(16, ADC_UNIT_2, ADC_CHANNEL_5, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO17 = PIN(17, ADC_UNIT_2, ADC_CHANNEL_6, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/pins.h b/ports/espressif/peripherals/pins.h index f89855e308f..ada17075e50 100644 --- a/ports/espressif/peripherals/pins.h +++ b/ports/espressif/peripherals/pins.h @@ -12,16 +12,15 @@ #include "py/obj.h" -#include "components/hal/include/hal/gpio_types.h" -#include "components/hal/include/hal/adc_types.h" -#include "components/hal/include/hal/touch_sensor_types.h" +#include "hal/gpio_types.h" +#include "hal/adc_types.h" typedef struct { mp_obj_base_t base; gpio_num_t number; uint8_t adc_index : 2; uint8_t adc_channel : 6; - touch_pad_t touch_channel; + int8_t touch_channel; } mcu_pin_obj_t; extern const mp_obj_type_t mcu_pin_type; @@ -31,7 +30,7 @@ extern const mp_obj_type_t mcu_pin_type; #define NO_ADC SOC_ADC_PERIPH_NUM #define NO_ADC_CHANNEL SOC_ADC_MAX_CHANNEL_NUM -#define NO_TOUCH_CHANNEL TOUCH_PAD_MAX +#define NO_TOUCH_CHANNEL (-1) // This macro is used to simplify pin definition in peripherals//pins.c #define PIN(p_number, p_adc_index, p_adc_channel, p_touch_channel) \ @@ -50,8 +49,12 @@ extern const mp_obj_type_t mcu_pin_type; #include "esp32c2/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32C3) #include "esp32c3/pins.h" +#elif defined(CONFIG_IDF_TARGET_ESP32C5) +#include "esp32c5/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32C6) #include "esp32c6/pins.h" +#elif defined(CONFIG_IDF_TARGET_ESP32C61) +#include "esp32c61/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32P4) #include "esp32p4/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32H2) diff --git a/ports/espressif/peripherals/touch.c b/ports/espressif/peripherals/touch.c index 71340d94371..fd8436119aa 100644 --- a/ports/espressif/peripherals/touch.c +++ b/ports/espressif/peripherals/touch.c @@ -4,54 +4,146 @@ // // SPDX-License-Identifier: MIT -#include "py/gc.h" #include "peripherals/touch.h" -static bool touch_inited = false; -static bool touch_never_reset = false; +static touch_sensor_handle_t touch_controller = NULL; +static touch_channel_handle_t touch_channels[TOUCH_TOTAL_CHAN_NUM] = {NULL}; +static bool touch_never_reset_flag = false; +static bool touch_enabled = false; +static bool touch_scanning = false; + +static int chan_index(int channel_id) { + return channel_id - TOUCH_MIN_CHAN_ID; +} + +touch_sensor_handle_t peripherals_touch_get_controller(void) { + return touch_controller; +} + +touch_channel_handle_t peripherals_touch_get_handle(int channel_id) { + return touch_channels[chan_index(channel_id)]; +} void peripherals_touch_reset(void) { - if (touch_inited && !touch_never_reset) { - touch_pad_deinit(); - touch_inited = false; + if (touch_controller != NULL && !touch_never_reset_flag) { + if (touch_scanning) { + touch_sensor_stop_continuous_scanning(touch_controller); + touch_scanning = false; + } + if (touch_enabled) { + touch_sensor_disable(touch_controller); + touch_enabled = false; + } + for (unsigned int i = 0; i < TOUCH_TOTAL_CHAN_NUM; i++) { + if (touch_channels[i] != NULL) { + touch_sensor_del_channel(touch_channels[i]); + touch_channels[i] = NULL; + } + } + touch_sensor_del_controller(touch_controller); + touch_controller = NULL; } } void peripherals_touch_never_reset(const bool enable) { - touch_never_reset = enable; + touch_never_reset_flag = enable; } -void peripherals_touch_init(const touch_pad_t touchpad) { - if (!touch_inited) { - touch_pad_init(); - touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); +void peripherals_touch_init(const int channel_id) { + int idx = chan_index(channel_id); + + // Already initialized this channel + if (touch_channels[idx] != NULL) { + return; } - // touch_pad_config() must be done before touch_pad_fsm_start() the first time. - // Otherwise the calibration is wrong and we get maximum raw values if there is - // a trace of any significant length on the pin. - #if defined(CONFIG_IDF_TARGET_ESP32) - touch_pad_config(touchpad, 0); + + // Stop scanning and disable before modifying channels + if (touch_scanning) { + touch_sensor_stop_continuous_scanning(touch_controller); + touch_scanning = false; + } + if (touch_enabled) { + touch_sensor_disable(touch_controller); + touch_enabled = false; + } + + if (touch_controller == NULL) { + #if SOC_TOUCH_SENSOR_VERSION == 1 + touch_sensor_sample_config_t sample_cfg = TOUCH_SENSOR_V1_DEFAULT_SAMPLE_CONFIG(5.0, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_1V7); + #elif SOC_TOUCH_SENSOR_VERSION == 2 + touch_sensor_sample_config_t sample_cfg = TOUCH_SENSOR_V2_DEFAULT_SAMPLE_CONFIG(500, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_2V2); + #elif SOC_TOUCH_SENSOR_VERSION == 3 + touch_sensor_sample_config_t sample_cfg = TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG2(3, 29, 8, 3); + #else + #error bad SOC_TOUCH_SENSOR_VERSION + #endif + touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(1, &sample_cfg); + touch_sensor_new_controller(&sens_cfg, &touch_controller); + } + + #if SOC_TOUCH_SENSOR_VERSION == 1 + touch_channel_config_t chan_cfg = { + .abs_active_thresh = {1000}, + .charge_speed = TOUCH_CHARGE_SPEED_7, + .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, + .group = TOUCH_CHAN_TRIG_GROUP_BOTH, + }; + #elif SOC_TOUCH_SENSOR_VERSION == 2 + touch_channel_config_t chan_cfg = { + .active_thresh = {2000}, + .charge_speed = TOUCH_CHARGE_SPEED_7, + .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, + }; + #elif SOC_TOUCH_SENSOR_VERSION == 3 + // Values are similar to an ESP-IDF example: 1000, 2500, 5000. + touch_channel_config_t chan_cfg = { + .active_thresh = {1000, 2000, 5000}, + }; #else - touch_pad_config(touchpad); - touch_pad_fsm_start(); + #error bad SOC_TOUCH_SENSOR_VERSION #endif - touch_inited = true; + + touch_sensor_new_channel(touch_controller, channel_id, &chan_cfg, &touch_channels[idx]); + + // Enable and start continuous scanning + touch_sensor_enable(touch_controller); + touch_enabled = true; + touch_sensor_start_continuous_scanning(touch_controller); + touch_scanning = true; } -uint16_t peripherals_touch_read(touch_pad_t touchpad) { - #if defined(CONFIG_IDF_TARGET_ESP32) - uint16_t touch_value; - touch_pad_read(touchpad, &touch_value); +uint16_t peripherals_touch_read(int channel_id) { + int idx = chan_index(channel_id); + if (touch_channels[idx] == NULL) { + return 0; + } + + uint32_t touch_value = 0; - // ESP32 touch_pad_read() returns a lower value when a pin is touched instead of a higher value. - // Flip the values around to be consistent with TouchIn assumptions. - return UINT16_MAX - touch_value; - #else - uint32_t touch_value; - touch_pad_read_raw_data(touchpad, &touch_value); + #if SOC_TOUCH_SENSOR_VERSION == 1 + // ESP32 touch reads a lower value when touched. + // Flip the values to be consistent with TouchIn assumptions. + touch_channel_read_data(touch_channels[idx], TOUCH_CHAN_DATA_TYPE_RAW, &touch_value); + if (touch_value > UINT16_MAX) { + return 0; + } + return UINT16_MAX - (uint16_t)touch_value; + + #elif SOC_TOUCH_SENSOR_VERSION == 2 + touch_channel_read_data(touch_channels[idx], TOUCH_CHAN_DATA_TYPE_RAW, &touch_value); if (touch_value > UINT16_MAX) { return UINT16_MAX; } return (uint16_t)touch_value; + + #elif SOC_TOUCH_SENSOR_VERSION == 3 + touch_channel_read_data(touch_channels[idx], TOUCH_CHAN_DATA_TYPE_SMOOTH, &touch_value); + if (touch_value > UINT16_MAX) { + return UINT16_MAX; + } + return (uint16_t)touch_value; + + #else + #error bad SOC_TOUCH_SENSOR_VERSION #endif } diff --git a/ports/espressif/peripherals/touch.h b/ports/espressif/peripherals/touch.h index 6be4f8c2be1..00a96193c88 100644 --- a/ports/espressif/peripherals/touch.h +++ b/ports/espressif/peripherals/touch.h @@ -6,9 +6,11 @@ #pragma once -#include "driver/touch_pad.h" +#include "driver/touch_sens.h" -extern uint16_t peripherals_touch_read(touch_pad_t touchpad); +extern void peripherals_touch_init(const int channel_id); +extern uint16_t peripherals_touch_read(int channel_id); extern void peripherals_touch_reset(void); extern void peripherals_touch_never_reset(const bool enable); -extern void peripherals_touch_init(const touch_pad_t touchpad); +extern touch_sensor_handle_t peripherals_touch_get_controller(void); +extern touch_channel_handle_t peripherals_touch_get_handle(int channel_id); diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 48ae29ab4f9..f0308975a1e 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -15,7 +15,11 @@ #include "supervisor/shared/serial.h" #include "py/mpprint.h" #include "py/runtime.h" +#if MICROPY_PERSISTENT_CODE_LOAD_NATIVE +#include "py/persistentcode.h" +#endif +#include "esp_mac.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -52,7 +56,7 @@ #endif #if CIRCUITPY_ESPCAMERA -#include "esp_camera.h" +#include "common-hal/espcamera/Camera.h" #endif #if CIRCUITPY_RCLCPY @@ -86,6 +90,10 @@ #include "esp_rom_efuse.h" #include "esp_timer.h" +#if MICROPY_PERSISTENT_CODE_LOAD_NATIVE && defined(CONFIG_IDF_TARGET_ESP32S2) +#include "esp_memory_utils.h" +#endif + #ifdef CONFIG_IDF_TARGET_ESP32 #include "hal/efuse_hal.h" #include "esp32/rom/efuse.h" @@ -103,7 +111,7 @@ static esp_timer_handle_t _sleep_timer; TaskHandle_t circuitpython_task = NULL; -extern void esp_restart(void) NORETURN; +extern void esp_restart(void) MP_NORETURN; static void tick_on_cp_core(void *arg) { supervisor_tick(); @@ -216,6 +224,11 @@ static void _never_reset_spi_ram_flash(void) { never_reset_pin_number(bootloader_flash_get_wp_pin()); } #endif // CONFIG_IDF_TARGET_ESP32 + #if defined(CONFIG_IDF_TARGET_ESP32C61) + #if defined(CONFIG_SPIRAM) + common_hal_never_reset_pin(&pin_GPIO14); + #endif + #endif } safe_mode_t port_init(void) { @@ -239,19 +252,19 @@ safe_mode_t port_init(void) { #endif // Send the ROM output out of the UART. This includes early logs. - #if DEBUG + #if DEBUG && (defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) && CONFIG_ESP_CONSOLE_UART_DEFAULT) esp_rom_install_uart_printf(); #endif #define pin_GPIOn(n) pin_GPIO##n #define pin_GPIOn_EXPAND(x) pin_GPIOn(x) - #ifdef CONFIG_CONSOLE_UART_TX_GPIO - common_hal_never_reset_pin(&pin_GPIOn_EXPAND(CONFIG_CONSOLE_UART_TX_GPIO)); + #ifdef CONFIG_ESP_CONSOLE_UART_TX_GPIO + common_hal_never_reset_pin(&pin_GPIOn_EXPAND(CONFIG_ESP_CONSOLE_UART_TX_GPIO)); #endif - #ifdef CONFIG_CONSOLE_UART_RX_GPIO - common_hal_never_reset_pin(&pin_GPIOn_EXPAND(CONFIG_CONSOLE_UART_RX_GPIO)); + #ifdef CONFIG_ESP_CONSOLE_UART_RX_GPIO + common_hal_never_reset_pin(&pin_GPIOn_EXPAND(CONFIG_ESP_CONSOLE_UART_RX_GPIO)); #endif #ifndef ENABLE_JTAG @@ -271,7 +284,7 @@ safe_mode_t port_init(void) { common_hal_never_reset_pin(&pin_GPIO40); common_hal_never_reset_pin(&pin_GPIO41); common_hal_never_reset_pin(&pin_GPIO42); - #elif defined(CONFIG_IDF_TARGET_ESP32P4) + #elif defined(CONFIG_IDF_TARGET_ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32C61) common_hal_never_reset_pin(&pin_GPIO3); common_hal_never_reset_pin(&pin_GPIO4); common_hal_never_reset_pin(&pin_GPIO5); @@ -341,24 +354,77 @@ size_t port_heap_get_largest_free_size(void) { return free_size; } -void reset_port(void) { - // TODO deinit for esp32-camera +#if MICROPY_PERSISTENT_CODE_LOAD_NATIVE +// Loaded native code, kept outside the GC heap until port_gc_deinit(). +typedef struct _native_code_node_t { + struct _native_code_node_t *next; + uint32_t data[]; +} native_code_node_t; + +static native_code_node_t *native_code_head = NULL; + +void port_gc_deinit(void) { + while (native_code_head != NULL) { + native_code_node_t *next = native_code_head->next; + heap_caps_free(native_code_head); + native_code_head = next; + } +} + +// Copy `len` bytes of machine code from `buf` into executable memory and return +// the executable address, applying the relocations in `reloc` (if any) against +// that address first. Raises MemoryError when no executable memory is available. +void *esp_native_code_commit(void *buf, size_t len, void *reloc) { + len = (len + 3) & ~3; + size_t len_node = sizeof(native_code_node_t) + len; + native_code_node_t *node = heap_caps_malloc(len_node, MALLOC_CAP_EXEC); + #if defined(CONFIG_IDF_TARGET_ESP32S2) + // The S2 can hand out MALLOC_CAP_EXEC memory that the CPU cannot fetch from. + if (node != NULL && !esp_ptr_executable(node)) { + heap_caps_free(node); + node = NULL; + } + #endif + if (node == NULL) { + m_malloc_fail(len_node); + } + node->next = native_code_head; + native_code_head = node; + void *p = node->data; + if (reloc) { + mp_native_relocate(reloc, buf, (uintptr_t)p); + } + // Word copy: Xtensa executable RAM is not byte-addressable. + const uint32_t *src = buf; + uint32_t *dst = p; + for (size_t i = 0; i < len / 4; i++) { + dst[i] = src[i]; + } + return p; +} +#endif + +void reset_port_early(void) { + // esp-camera adds an I2C device on the ESP I2C bus, and keeps it there. This + // is unlike busio.I2C, which adds and removes the device on each operation. + // So have the esp-camera API shut down the camera now, before reset_board_buses() tries to delete the I2C bus. + // Unfortunately, there is no I2C driver API to enumerate or delete all the devices. #if CIRCUITPY_ESPCAMERA - esp_camera_deinit(); + espcamera_reset(); #endif +} + +void reset_port(void) { #if CIRCUITPY_SSL ssl_reset(); #endif - reset_all_pins(); - #if CIRCUITPY_ANALOGIO analogout_reset(); #endif #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif @@ -402,8 +468,8 @@ void reset_port(void) { watchdog_reset(); #endif - // Yield so the idle task can run and do any IDF cleanup needed. - port_yield(); + // Yield so the idle task, at priority 0, can run and do any IDF cleanup needed. + port_task_sleep_ms(4); } void reset_to_bootloader(void) { @@ -481,8 +547,13 @@ void port_wake_main_task_from_isr(void) { } } -void port_yield(void) { - vTaskDelay(4); +// Yield to other tasks at the same priority. +void port_task_yield(void) { + vTaskDelay(0); +} + +void port_task_sleep_ms(uint32_t msecs) { + vTaskDelay(pdMS_TO_TICKS(msecs)); } void sleep_timer_cb(void *arg) { @@ -508,7 +579,12 @@ void port_idle_until_interrupt(void) { #if CIRCUITPY_WIFI void port_boot_info(void) { uint8_t mac[6]; - esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); + // This runs before esp_wifi_init(), so esp_wifi_get_mac() fails with + // ESP_ERR_WIFI_NOT_INIT and leaves mac[] untouched. esp_read_mac() reads + // efuse directly and does not need the WiFi driver started. + if (esp_read_mac(mac, ESP_MAC_WIFI_STA) != ESP_OK) { + return; + } mp_printf(&mp_plat_print, "MAC"); for (int i = 0; i < 6; i++) { mp_printf(&mp_plat_print, ":%02X", mac[i]); diff --git a/ports/espressif/supervisor/usb.c b/ports/espressif/supervisor/usb.c index 612abaa808a..7c3b1561a44 100644 --- a/ports/espressif/supervisor/usb.c +++ b/ports/espressif/supervisor/usb.c @@ -2,6 +2,7 @@ // // SPDX-FileCopyrightText: Copyright (c) 2018 hathach for Adafruit Industries // SPDX-FileCopyrightText: Copyright (c) 2019 Lucian Copeland for Adafruit Industries +// SPDX-FileContributor: 2025 Nicolai Electronics // // SPDX-License-Identifier: MIT @@ -20,13 +21,15 @@ #include "driver/gpio.h" #include "esp_private/periph_ctrl.h" -#include "rom/gpio.h" - #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "tusb.h" +#ifdef CONFIG_IDF_TARGET_ESP32P4 +#include "hal/usb_serial_jtag_ll.h" +#endif + #if CIRCUITPY_USB_DEVICE #ifdef CFG_TUSB_DEBUG #define USBD_STACK_SIZE (3 * configMINIMAL_STACK_SIZE) @@ -37,7 +40,7 @@ StackType_t usb_device_stack[USBD_STACK_SIZE]; StaticTask_t usb_device_taskdef; -static usb_phy_handle_t phy_hdl; +static usb_phy_handle_t device_phy_hdl; // USB Device Driver task // This top level thread process all usb events and invoke callbacks @@ -51,34 +54,10 @@ static void usb_device_task(void *param) { tud_task(); tud_cdc_write_flush(); } - vTaskDelay(1); + // Yield with zero delay to switch to any other tasks at same priority. + port_task_yield(); } } - -/** - * Callback invoked when received an "wanted" char. - * @param itf Interface index (for multiple cdc interfaces) - * @param wanted_char The wanted char (set previously) - */ -void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { - (void)itf; // not used - // CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB. - // So, we must notify the other task when a CTRL-C is received. - port_wake_main_task(); - // Workaround for using shared/runtime/interrupt_char.c - // Compare mp_interrupt_char with wanted_char and ignore if not matched - if (mp_interrupt_char == wanted_char) { - tud_cdc_read_flush(); // flush read fifo - mp_sched_keyboard_interrupt(); - } -} - -void tud_cdc_rx_cb(uint8_t itf) { - (void)itf; - // Workaround for "press any key to enter REPL" response being delayed on espressif. - // Wake main task when any key is pressed. - port_wake_main_task(); -} #endif // CIRCUITPY_USB_DEVICE void init_usb_hardware(void) { @@ -86,14 +65,45 @@ void init_usb_hardware(void) { // Configure USB PHY usb_phy_config_t phy_conf = { .controller = USB_PHY_CTRL_OTG, + #if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 1 + .target = USB_PHY_TARGET_UTMI, + #else .target = USB_PHY_TARGET_INT, - + #endif .otg_mode = USB_OTG_MODE_DEVICE, + #if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 0 + .otg_speed = USB_PHY_SPEED_FULL, + #else // https://github.com/hathach/tinyusb/issues/2943#issuecomment-2601888322 // Set speed to undefined (auto-detect) to avoid timing/race issue with S3 with host such as macOS .otg_speed = USB_PHY_SPEED_UNDEFINED, + #endif }; - usb_new_phy(&phy_conf, &phy_hdl); + usb_new_phy(&phy_conf, &device_phy_hdl); + + #if CIRCUITPY_ESP32P4_SWAP_LSFS == 1 + #ifndef CONFIG_IDF_TARGET_ESP32P4 + #error "LSFS swap is only supported on ESP32P4" + #endif + // Switch the USB PHY + const usb_serial_jtag_pull_override_vals_t override_disable_usb = { + .dm_pd = true, .dm_pu = false, .dp_pd = true, .dp_pu = false + }; + const usb_serial_jtag_pull_override_vals_t override_enable_usb = { + .dm_pd = false, .dm_pu = false, .dp_pd = false, .dp_pu = true + }; + + // Drop off the bus by removing the pull-up on USB DP + usb_serial_jtag_ll_phy_enable_pull_override(&override_disable_usb); + + // Select USB mode by swapping and un-swapping the two PHYs + vTaskDelay(pdMS_TO_TICKS(500)); // Wait for disconnect before switching to device + usb_serial_jtag_ll_phy_select(1); + + // Put the device back onto the bus by re-enabling the pull-up on USB DP + usb_serial_jtag_ll_phy_enable_pull_override(&override_enable_usb); + usb_serial_jtag_ll_phy_disable_pull_override(); + #endif // Pin the USB task to the same core as CircuitPython. This way we leave // the other core for networking. @@ -101,7 +111,7 @@ void init_usb_hardware(void) { "usbd", USBD_STACK_SIZE, NULL, - 5, + 1, usb_device_stack, &usb_device_taskdef, xPortGetCoreID()); diff --git a/ports/espressif/tools/build_memory_info.py b/ports/espressif/tools/build_memory_info.py index 9a3c5550138..27ad13b29e6 100644 --- a/ports/espressif/tools/build_memory_info.py +++ b/ports/espressif/tools/build_memory_info.py @@ -56,11 +56,22 @@ ("Internal SRAM 0", (0x4037_C000,), 16 * 1024), ("Internal SRAM 1", (0x3FC8_0000, 0x4038_0000), 384 * 1024), ], + "esp32c5": [ + # Name, Start, Length + ("LP SRAM", (0x5000_0000,), 16 * 1024), + ("HP SRAM", (0x4080_0000,), 384 * 1024), + ], "esp32c6": [ # Name, Start, Length ("LP SRAM", (0x5000_0000,), 16 * 1024), ("HP SRAM", (0x4080_0000,), 512 * 1024), ], + "esp32c61": [ + # Name, Start, Length + ("LP SRAM", (0x5000_0000,), 16 * 1024), + ("HP SRAM", (0x4080_0000,), 320 * 1024), + ("PSRAM", (0x4200_0000,), 2 * 1024 * 1024), + ], "esp32h2": [ # Name, Start, Length ("LP SRAM", (0x5000_0000,), 4 * 1024), diff --git a/ports/espressif/tools/check-sdkconfig.py b/ports/espressif/tools/check-sdkconfig.py index 12254a71d01..f16dc3c871a 100755 --- a/ports/espressif/tools/check-sdkconfig.py +++ b/ports/espressif/tools/check-sdkconfig.py @@ -34,6 +34,17 @@ def validate(sdk_config, circuitpy_config): f"{var} is incompatible with {partition_table=} (no ota_1 partition)" ) + # Native machine code executes from RAM; the PMS/PMP memory protection + # forbids that and makes MALLOC_CAP_EXEC allocations fail. + if ( + circuitpy_config.get("CIRCUITPY_ENABLE_MPY_NATIVE") + or circuitpy_config.get("CIRCUITPY_LOAD_NATIVE") + ) and sdk_config.get("CONFIG_ESP_SYSTEM_MEMPROT"): + raise SystemExit( + "CIRCUITPY_ENABLE_MPY_NATIVE=1 / CIRCUITPY_LOAD_NATIVE=1 require CONFIG_ESP_SYSTEM_MEMPROT=n " + "(see esp-idf-config/sdkconfig-native.defaults)" + ) + # Add more checks here for other things we want to verify. return diff --git a/ports/espressif/tools/decode_backtrace.py b/ports/espressif/tools/decode_backtrace.py index 024e636207e..2001482ffd6 100644 --- a/ports/espressif/tools/decode_backtrace.py +++ b/ports/espressif/tools/decode_backtrace.py @@ -10,22 +10,45 @@ import sys board = sys.argv[1] +# Allow `board-name` or `build-board-name/ as the arg, to allow simple tab completion of boardname. +board = board.replace("build-", "").replace("/", "") print(board) +elfs = [ + f"build-{board}/firmware.elf", + # Add additional ELF files here such as the ROM ELF files from: + # https://github.com/espressif/esp-rom-elfs/releases + # "/home/tannewt/Downloads/esp-rom-elfs-20241011/esp32c6_rev0_rom.elf", +] + while True: + print('"Backtrace:" or "Stack memory:". CTRL-D to finish multiline paste') addresses = input("? ") if addresses.startswith("Backtrace:"): addresses = addresses[len("Backtrace:") :] - if addresses.startswith("Stack memory:"): - addresses = addresses[len("Stack memory:") :] - addresses = addresses.strip().split() - addresses = [address.split(":")[0] for address in addresses] + addresses = addresses.strip().split() + addresses = [address.split(":")[0] for address in addresses] + elif addresses.startswith("Stack memory:"): + addresses = [] + extra_lines = sys.stdin.readlines() + for line in extra_lines: + if not line.strip(): + continue + addresses.extend(line.split(":")[1].strip().split()) for address in addresses: - result = subprocess.run( - ["xtensa-esp32s2-elf-addr2line", "-aipfe", "build-{}/firmware.elf".format(board)] - + [address], - capture_output=True, - ) - stdout = result.stdout.decode("utf-8") - if "?? ??" not in stdout: - print(stdout.strip()) + if address == "0xa5a5a5a5": + # Skip stack fill value. + continue + for elf in elfs: + result = subprocess.run( + ["riscv32-esp-elf-addr2line", "-aipfe", elf, address], + capture_output=True, + ) + stdout = result.stdout.decode("utf-8") + if not stdout: + continue + if "?? ??" not in stdout: + print(stdout.strip()) + break + + print("loop") diff --git a/ports/espressif/tools/update_sdkconfig.py b/ports/espressif/tools/update_sdkconfig.py index 8837d84321b..f262a00e58b 100644 --- a/ports/espressif/tools/update_sdkconfig.py +++ b/ports/espressif/tools/update_sdkconfig.py @@ -5,7 +5,6 @@ import click import copy import kconfiglib -import kconfiglib.core import os OPT_SETTINGS = [ @@ -157,7 +156,7 @@ def sym_default(sym): default=False, help="Updates the sdkconfigs outside of the board directory.", ) -def update(debug, board, update_all): # noqa: C901: too complex +def update(debug, board, update_all): # noqa: C901 too complex """Updates related sdkconfig files based on the build directory version that was likely modified by menuconfig.""" @@ -165,6 +164,8 @@ def update(debug, board, update_all): # noqa: C901: too complex psram_size = "0" uf2_bootloader = None ble_enabled = None + load_native = True # Matches the mpconfigport.mk default. + mpy_native = False for line in board_make.read_text().split("\n"): if "=" not in line or line.startswith("#"): continue @@ -193,6 +194,10 @@ def update(debug, board, update_all): # noqa: C901: too complex uf2_bootloader = not (value == "0") elif key == "CIRCUITPY_BLEIO_NATIVE": ble_enabled = not (value == "0") + elif key == "CIRCUITPY_LOAD_NATIVE": + load_native = not (value == "0") + elif key == "CIRCUITPY_ENABLE_MPY_NATIVE": + mpy_native = value == "1" os.environ["IDF_TARGET"] = target os.environ["COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE"] = ( @@ -203,7 +208,7 @@ def update(debug, board, update_all): # noqa: C901: too complex kconfig_path = pathlib.Path(f"build-{board}/esp-idf/kconfigs.in") kconfig_path = pathlib.Path("esp-idf/Kconfig") - kconfig = kconfiglib.Kconfig(kconfig_path) + kconfig = kconfiglib.Kconfig(str(kconfig_path)) input_config = pathlib.Path(f"build-{board}/esp-idf/sdkconfig") kconfig.load_config(input_config) @@ -240,11 +245,14 @@ def update(debug, board, update_all): # noqa: C901: too complex if ble_enabled: ble_config = pathlib.Path("esp-idf-config/sdkconfig-ble.defaults") sdkconfigs.append(ble_config) + if load_native or mpy_native: + native_config = pathlib.Path("esp-idf-config/sdkconfig-native.defaults") + sdkconfigs.append(native_config) board_config = pathlib.Path(f"boards/{board}/sdkconfig") # Don't include the board file in cp defaults. The board may have custom # overrides. - cp_kconfig_defaults = kconfiglib.Kconfig(kconfig_path) + cp_kconfig_defaults = kconfiglib.Kconfig(str(kconfig_path)) for default_file in sdkconfigs: cp_kconfig_defaults.load_config(default_file, replace=False) @@ -321,7 +329,7 @@ def update(debug, board, update_all): # noqa: C901: too complex if print_debug: print(" " * len(current_group), i, config_string.strip()) - # Some files are `rsource`d into another kconfig with $IDF_TARGET as + # Some files are `rsource`d into another kconfig with $IDF_TARGET as # codespell:ignore rsource # part of the path. kconfiglib doesn't show this as a reference so # we have to look ourselves. target_reference = target in item.name_and_loc @@ -332,7 +340,7 @@ def update(debug, board, update_all): # noqa: C901: too complex shared_keys = {} first = True for path in pathlib.Path(".").glob(loc): - kc = kconfiglib.Kconfig(path) + kc = kconfiglib.Kconfig(str(path)) all_file_syms = set() for sym in kc.unique_defined_syms: all_file_syms.add(sym) @@ -378,6 +386,8 @@ def update(debug, board, update_all): # noqa: C901: too complex all_references.update(rdep.referenced) psram_reference = False for referenced in all_references: + if not referenced.name: + continue if referenced.name.startswith("IDF_TARGET"): target_reference = True if referenced.name in target_symbols: diff --git a/ports/litex/Makefile b/ports/litex/Makefile index 98abe985699..9792ce301a3 100644 --- a/ports/litex/Makefile +++ b/ports/litex/Makefile @@ -32,7 +32,7 @@ ifeq ($(DEBUG), 1) OPTIMIZATION_FLAGS ?= -Og else CFLAGS += -DNDEBUG -ggdb3 - OPTIMIZATION_FLAGS ?= -O2 -fno-inline-functions + OPTIMIZATION_FLAGS ?= -O2 endif # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk @@ -78,8 +78,11 @@ SRC_C += lib/tinyusb/src/portable/valentyusb/eptri/dcd_eptri.c endif SRC_S_UPPER = \ - crt0-vexriscv.S \ - supervisor/shared/cpu_regs.S + crt0-vexriscv.S + +SRC_S = shared/runtime/gchelper_rv32i.s + +SRC_C += shared/runtime/gchelper_native.c $(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align @@ -94,6 +97,7 @@ ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) @@ -114,7 +118,7 @@ else $(BUILD)/firmware.elf: $(OBJ) $(STEPECHO) "LINK $@" $(Q)$(CC) -o $@ $(LDFLAGS) $^ -Wl,--print-memory-usage -Wl,--start-group $(LIBS) -Wl,--end-group - $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $(LD_FILE) $(BUILD) + $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $@.map $(BUILD) endif $(BUILD)/firmware.bin: $(BUILD)/firmware.elf diff --git a/ports/litex/common-hal/microcontroller/Pin.c b/ports/litex/common-hal/microcontroller/Pin.c index dea848f1ec3..bb3636c5b3f 100644 --- a/ports/litex/common-hal/microcontroller/Pin.c +++ b/ports/litex/common-hal/microcontroller/Pin.c @@ -11,6 +11,10 @@ static uint8_t claimed_pins[1]; +void reset_all_pins(void) { + // TODO +} + // Mark pin as free and return it to a quiescent state. void reset_pin_number(uint8_t pin_port, uint8_t pin_number) { if (pin_port == 0x0F) { diff --git a/ports/litex/common-hal/microcontroller/Processor.c b/ports/litex/common-hal/microcontroller/Processor.c index cf80a01d4e6..0d1c29b1ad0 100644 --- a/ports/litex/common-hal/microcontroller/Processor.c +++ b/ports/litex/common-hal/microcontroller/Processor.c @@ -46,5 +46,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/litex/supervisor/port.c b/ports/litex/supervisor/port.c index 98fce16152e..7f9aab7f7ff 100644 --- a/ports/litex/supervisor/port.c +++ b/ports/litex/supervisor/port.c @@ -59,7 +59,6 @@ extern uint32_t _heap_start; extern uint32_t _estack; void reset_port(void) { - // reset_all_pins(); // i2c_reset(); // spi_reset(); // uart_reset(); diff --git a/ports/mimxrt10xx/Makefile b/ports/mimxrt10xx/Makefile index e6928eead61..95fedc70d8e 100644 --- a/ports/mimxrt10xx/Makefile +++ b/ports/mimxrt10xx/Makefile @@ -162,8 +162,11 @@ SRC_C += \ endif SRC_S_UPPER = \ - sdk/devices/$(CHIP_FAMILY)/gcc/startup_$(CHIP_CORE).S \ - supervisor/shared/cpu_regs.S + sdk/devices/$(CHIP_FAMILY)/gcc/startup_$(CHIP_CORE).S + +SRC_S = shared/runtime/gchelper_thumb2.s + +SRC_C += shared/runtime/gchelper_native.c OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_SDK:.c=.o)) @@ -172,7 +175,7 @@ ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S:.S=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) @@ -186,6 +189,7 @@ else $(BUILD)/firmware.elf: $(OBJ) $(LD_FILES) $(STEPECHO) "LINK $@" $(Q)$(CC) -o $@ $(LDFLAGS) $(filter-out %.ld, $^) -Wl,--print-memory-usage -Wl,--start-group $(LIBS) -Wl,--end-group + $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $@.map $(BUILD) endif # -R excludes sections from the output files. diff --git a/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c b/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c index c785f4e090e..b844325a00a 100644 --- a/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c +++ b/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c @@ -53,7 +53,11 @@ static void config_periph_pin(const mcu_periph_obj_t *periph) { // Caller validates that pins are free. void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); + } int instance = -1; const mcu_periph_obj_t *bclk_periph = find_pin_function(mcu_i2s_tx_bclk_list, bit_clock, &instance, MP_QSTR_bit_clock); diff --git a/ports/mimxrt10xx/common-hal/audiobusio/__init__.c b/ports/mimxrt10xx/common-hal/audiobusio/__init__.c index f1030bfcd84..d51ea773acb 100644 --- a/ports/mimxrt10xx/common-hal/audiobusio/__init__.c +++ b/ports/mimxrt10xx/common-hal/audiobusio/__init__.c @@ -372,6 +372,7 @@ static void set_sai_clocking_for_sample_rate(uint32_t sample_rate) { } void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { + audiosample_check(sample); self->sample = sample; self->loop = loop; self->bytes_per_sample = audiosample_get_bits_per_sample(sample) / 8; diff --git a/ports/mimxrt10xx/common-hal/busio/I2C.c b/ports/mimxrt10xx/common-hal/busio/I2C.c index 132b3083212..93c0ab30123 100644 --- a/ports/mimxrt10xx/common-hal/busio/I2C.c +++ b/ports/mimxrt10xx/common-hal/busio/I2C.c @@ -201,7 +201,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { lpi2c_master_transfer_t xfer = { 0 }; @@ -215,15 +215,15 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, return 0; } - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { lpi2c_master_transfer_t xfer = { 0 }; @@ -237,12 +237,12 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, return 0; } - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.c b/ports/mimxrt10xx/common-hal/busio/SPI.c index 732b23d8c9b..90695be4b4e 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.c +++ b/ports/mimxrt10xx/common-hal/busio/SPI.c @@ -26,7 +26,6 @@ // arrays use 0 based numbering: SPI1 is stored at index 0 static bool reserved_spi[MP_ARRAY_SIZE(mcu_spi_banks)]; -static bool never_reset_spi[MP_ARRAY_SIZE(mcu_spi_banks)]; #if IMXRT11XX static const clock_ip_name_t s_lpspiClocks[] = LPSPI_CLOCKS; @@ -53,22 +52,6 @@ static void config_periph_pin(const mcu_periph_obj_t *periph) { | IOMUXC_SW_PAD_CTL_PAD_SRE(0)); } -void spi_reset(void) { - for (uint i = 0; i < MP_ARRAY_SIZE(mcu_spi_banks); i++) { - if (!never_reset_spi[i]) { - reserved_spi[i] = false; - #if IMXRT11XX - // Skip resetting SPIs that aren't clocked. Doing so generates a bus fault. - if ((CCM->LPCG[s_lpspiClocks[i + 1]].STATUS0 & CCM_LPCG_STATUS0_ON_MASK) == ((uint32_t)kCLOCK_Off & CCM_LPCG_STATUS0_ON_MASK)) { - continue; - } - #endif - - LPSPI_Deinit(mcu_spi_banks[i]); - } - } -} - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { @@ -82,6 +65,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); } + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + for (uint i = 0; i < sck_count; i++) { if (mcu_spi_sck_list[i].pin != clock) { continue; @@ -200,7 +186,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[self->clock->bank_idx - 1] = true; common_hal_never_reset_pin(self->clock->pin); if (self->mosi != NULL) { common_hal_never_reset_pin(self->mosi->pin); @@ -214,21 +199,25 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } LPSPI_Deinit(self->spi); reserved_spi[self->clock->bank_idx - 1] = false; - never_reset_spi[self->clock->bank_idx - 1] = false; common_hal_reset_pin(self->clock->pin); common_hal_reset_pin(self->mosi->pin); common_hal_reset_pin(self->miso->pin); - self->clock = NULL; self->mosi = NULL; self->miso = NULL; + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.h b/ports/mimxrt10xx/common-hal/busio/SPI.h index 67801078261..d86489428ec 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.h +++ b/ports/mimxrt10xx/common-hal/busio/SPI.h @@ -21,5 +21,3 @@ typedef struct { const mcu_periph_obj_t *mosi; const mcu_periph_obj_t *miso; } busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/mimxrt10xx/common-hal/microcontroller/Processor.c b/ports/mimxrt10xx/common-hal/microcontroller/Processor.c index 23e854953d6..c7cbd52566b 100644 --- a/ports/mimxrt10xx/common-hal/microcontroller/Processor.c +++ b/ports/mimxrt10xx/common-hal/microcontroller/Processor.c @@ -77,5 +77,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c b/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c index e1507c7fc02..169ce096307 100644 --- a/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +++ b/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c @@ -144,7 +144,7 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self, // We want variable frequency but another class has already claim a fixed frequency. if (variable_frequency) { - return PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE; + return PWMOUT_INTERNAL_RESOURCES_IN_USE; } // Another pin is already using this output. @@ -153,7 +153,7 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self, } if (frequency != _pwm_sm_frequencies[flexpwm_index][submodule]) { - return PWMOUT_INVALID_FREQUENCY_ON_PIN; + return PWMOUT_INTERNAL_RESOURCES_IN_USE; } // Submodule is already running at our target frequency and the output diff --git a/ports/mimxrt10xx/linking/common.ld b/ports/mimxrt10xx/linking/common.ld index 2c6be0dd129..1131f2b6f1f 100644 --- a/ports/mimxrt10xx/linking/common.ld +++ b/ports/mimxrt10xx/linking/common.ld @@ -69,6 +69,12 @@ SECTIONS .text : { . = ALIGN(4); + __property_getter_start = .; + *(.property_getter) + __property_getter_end = .; + __property_getset_start = .; + *(.property_getset) + __property_getset_end = .; *(EXCLUDE_FILE( *fsl_flexspi.o *cd_ci_hs.o @@ -210,4 +216,9 @@ SECTIONS __StackTop = ORIGIN(DTCM) + LENGTH(DTCM); .ARM.attributes 0 : { *(.ARM.attributes) } + + ASSERT((__property_getter_end - __property_getter_start) % 8 == 0, + "the .property_getter section must hold whole 8-byte objects") + ASSERT((__property_getset_end - __property_getset_start) % 12 == 0, + "the .property_getset section must hold whole 12-byte objects") } diff --git a/ports/mimxrt10xx/mpconfigport.h b/ports/mimxrt10xx/mpconfigport.h index 4d5e4e59700..df634dc7328 100644 --- a/ports/mimxrt10xx/mpconfigport.h +++ b/ports/mimxrt10xx/mpconfigport.h @@ -25,6 +25,8 @@ extern uint8_t _ld_default_stack_size; // are aligned to cache lines. #define MICROPY_BYTES_PER_GC_BLOCK (32) +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + #include "py/circuitpy_mpconfig.h" // TODO: diff --git a/ports/mimxrt10xx/mpconfigport.mk b/ports/mimxrt10xx/mpconfigport.mk index 20d802eb354..101568a8432 100644 --- a/ports/mimxrt10xx/mpconfigport.mk +++ b/ports/mimxrt10xx/mpconfigport.mk @@ -1,9 +1,10 @@ +# Properties get a dedicated linker section here, so they can drop the unused slots. +CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 1 + LD_FILE = $(FLASH).ld $(CHIP_FAMILY).ld imxrt10xx.ld INTERNAL_LIBM = 1 -USB_HIGHSPEED = 1 - # Number of USB endpoint pairs. USB_NUM_ENDPOINT_PAIRS = 8 # Align buffers on the cache boundary so we don't inadvertently load them early. diff --git a/ports/mimxrt10xx/reset.h b/ports/mimxrt10xx/reset.h index 04c951221e9..cae838556bc 100644 --- a/ports/mimxrt10xx/reset.h +++ b/ports/mimxrt10xx/reset.h @@ -16,6 +16,6 @@ #define DBL_TAP_MAGIC 0xf01669ef // Randomly selected, adjusted to have first and last bit set #define DBL_TAP_MAGIC_QUICK_BOOT 0xf02669ef -void reset_to_bootloader(void) NORETURN; -void reset(void) NORETURN; +void reset_to_bootloader(void) MP_NORETURN; +void reset(void) MP_NORETURN; bool bootloader_available(void); diff --git a/ports/mimxrt10xx/supervisor/port.c b/ports/mimxrt10xx/supervisor/port.c index d7f7f280d19..62d2569cfde 100644 --- a/ports/mimxrt10xx/supervisor/port.c +++ b/ports/mimxrt10xx/supervisor/port.c @@ -425,10 +425,6 @@ safe_mode_t port_init(void) { } void reset_port(void) { - #if CIRCUITPY_BUSIO - spi_reset(); - #endif - #if CIRCUITPY_AUDIOIO audio_dma_reset(); #endif @@ -450,8 +446,6 @@ void reset_port(void) { #endif // reset_event_system(); - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/nordic/Makefile b/ports/nordic/Makefile index aa614e097ba..2abee97386c 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -6,9 +6,12 @@ include ../../py/circuitpy_mkenv.mk -ifneq ($(SD), ) +# Skip when the make command is not board-specific i.e. fetch-port-submodules. +ifneq ($(VALID_BOARD),) +ifeq ($(CIRCUITPY_BLEIO_NATIVE),1) include bluetooth/bluetooth_common.mk endif +endif CROSS_COMPILE = arm-none-eabi- @@ -36,8 +39,8 @@ ifeq ($(DEBUG), 1) CFLAGS += -ggdb3 OPTIMIZATION_FLAGS = -Og else - OPTIMIZATION_FLAGS ?= -O2 -fno-inline-functions - CFLAGS += -DNDEBUG -ggdb3 + OPTIMIZATION_FLAGS ?= -O2 + CFLAGS += -DNDEBUG endif ifeq ($(NRF_DEBUG_PRINT), 1) @@ -115,11 +118,16 @@ SRC_C += \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).c \ + nrfx/mdk/system_$(MCU_SUB_VARIANT).c \ + +ifeq ($(CIRCUITPY_BLEIO_NATIVE),1) +SRC_C += \ bluetooth/ble_drv.c \ common-hal/_bleio/bonding.c \ - nrfx/mdk/system_$(MCU_SUB_VARIANT).c \ sd_mutex.c \ +endif + SRC_PERIPHERALS := \ peripherals/nrf/cache.c \ peripherals/nrf/clocks.c \ @@ -146,7 +154,9 @@ SRC_C += $(SRC_DCD) $(patsubst %.c,$(BUILD)/%.o,$(SRC_DCD)): CFLAGS += -Wno-missing-prototypes endif # CIRCUITPY_USB_DEVICE -SRC_S_UPPER = supervisor/shared/cpu_regs.S +SRC_S = shared/runtime/gchelper_thumb2.s + +SRC_C += shared/runtime/gchelper_native.c OBJ += $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_NRFX:.c=.o)) @@ -155,7 +165,7 @@ ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) # nrfx uses undefined preprocessor variables quite casually, so we can't do @@ -175,7 +185,13 @@ UF2_FAMILY_ID_nrf52840 = 0xADA52840 UF2_FAMILY_ID_nrf52833 = 0x621E937A +ifeq ($(CIRCUITPY_BLEIO_NATIVE),1) all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 $(BUILD)/firmware.combined.hex +else +# firmware.combined.hex merges in the SoftDevice hex; without one there is +# nothing to combine. +all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 $(BUILD)/firmware.hex +endif ifeq ($(VALID_BOARD),) $(BUILD)/firmware.elf: invalid-board @@ -184,7 +200,7 @@ $(BUILD)/firmware.elf: $(OBJ) $(GENERATED_LD_FILE) $(STEPECHO) "LINK $@" $(Q)echo $(OBJ) > $(BUILD)/firmware.objs $(Q)$(CC) -o $@ $(LDFLAGS) @$(BUILD)/firmware.objs -Wl,--print-memory-usage -Wl,--start-group $(LIBS) -Wl,--end-group - $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $(GENERATED_LD_FILE) $(BUILD) + $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $@.map $(BUILD) endif $(BUILD)/firmware.bin: $(BUILD)/firmware.elf diff --git a/ports/nordic/bluetooth/ble_drv.c b/ports/nordic/bluetooth/ble_drv.c index 35d577f117c..c2122c8845e 100644 --- a/ports/nordic/bluetooth/ble_drv.c +++ b/ports/nordic/bluetooth/ble_drv.c @@ -20,7 +20,7 @@ #include "py/mpstate.h" #include "mpconfigport.h" -#if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE #include "supervisor/shared/bluetooth/serial.h" #endif @@ -141,11 +141,14 @@ void ble_drv_reset(void) { void ble_drv_remove_heap_handlers(void) { ble_drv_evt_handler_entry_t *it = MP_STATE_VM(ble_drv_evt_handler_entries); while (it != NULL) { - // If the param is on the heap, then delete the handler. - if (gc_ptr_on_heap(it->param)) { + // Save it->next before removing, because removing clears it. + ble_drv_evt_handler_entry_t *next = it->next; + // Remove the handler if the entry or its param is on the heap, which is + // about to go away. + if (gc_ptr_on_heap(it) || gc_ptr_on_heap(it->param)) { ble_drv_remove_event_handler(it->func, it->param); } - it = it->next; + it = next; } } @@ -229,7 +232,7 @@ void SD_EVT_IRQHandler(void) { } } - #if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE ble_serial_disable(); #endif while (1) { @@ -270,7 +273,7 @@ void SD_EVT_IRQHandler(void) { } #endif } - #if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE ble_serial_enable(); #endif } diff --git a/ports/nordic/board.h b/ports/nordic/board.h new file mode 100644 index 00000000000..560cafc6da8 --- /dev/null +++ b/ports/nordic/board.h @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Called from port_init() before any peripheral is initialized. +void board_early_init(void); diff --git a/ports/nordic/boards/ADM_B_NRF52840_1/mpconfigboard.mk b/ports/nordic/boards/ADM_B_NRF52840_1/mpconfigboard.mk index f3a2e830dd7..d7cbcecb540 100644 --- a/ports/nordic/boards/ADM_B_NRF52840_1/mpconfigboard.mk +++ b/ports/nordic/boards/ADM_B_NRF52840_1/mpconfigboard.mk @@ -6,3 +6,4 @@ USB_MANUFACTURER = "AtelierDuMaker" MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/nordic/boards/bless_dev_board_multi_sensor/mpconfigboard.mk b/ports/nordic/boards/bless_dev_board_multi_sensor/mpconfigboard.mk index 90b0908505e..ae6f249eb74 100644 --- a/ports/nordic/boards/bless_dev_board_multi_sensor/mpconfigboard.mk +++ b/ports/nordic/boards/bless_dev_board_multi_sensor/mpconfigboard.mk @@ -6,3 +6,6 @@ USB_MANUFACTURER = "Switch Science, Inc." MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 + +CIRCUITPY_LOAD_NATIVE = 0 +CIRCUITPY_MSGPACK = 0 diff --git a/ports/nordic/boards/bluemicro833/mpconfigboard.mk b/ports/nordic/boards/bluemicro833/mpconfigboard.mk index 3fcb7cdbb07..48bd5334f5c 100644 --- a/ports/nordic/boards/bluemicro833/mpconfigboard.mk +++ b/ports/nordic/boards/bluemicro833/mpconfigboard.mk @@ -13,10 +13,12 @@ CIRCUITPY_AUDIOPWMIO = 0 CIRCUITPY_AUDIOMIXER = 0 CIRCUITPY_KEYPAD = 1 CIRCUITPY_KEYPAD_DEMUX = 0 +CIRCUITPY_LOAD_NATIVE = 0 CIRCUITPY_NVM = 0 CIRCUITPY_ONEWIREIO = 0 CIRCUITPY_PIXELBUF = 1 CIRCUITPY_PIXELMAP = 0 +CIRCUITPY_PULSEIO = 0 CIRCUITPY_TOUCHIO = 0 # Features to disable diff --git a/ports/nordic/boards/bluemicro840/mpconfigboard.mk b/ports/nordic/boards/bluemicro840/mpconfigboard.mk index 16d36704a3e..76e84a1c912 100644 --- a/ports/nordic/boards/bluemicro840/mpconfigboard.mk +++ b/ports/nordic/boards/bluemicro840/mpconfigboard.mk @@ -6,3 +6,6 @@ USB_MANUFACTURER = "nrf52.jpconstantineau.com" MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 + +CIRCUITPY_LOAD_NATIVE = 0 +CIRCUITPY_MSGPACK = 0 diff --git a/ports/nordic/boards/clue_nrf52840_express/board.c b/ports/nordic/boards/clue_nrf52840_express/board.c index e2cd8a324ba..0b331b63a96 100644 --- a/ports/nordic/boards/clue_nrf52840_express/board.c +++ b/ports/nordic/boards/clue_nrf52840_express/board.c @@ -34,9 +34,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_P0_13, // TFT_DC Command or data - &pin_P0_12, // TFT_CS Chip select - &pin_P1_03, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_P0_13), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_P0_12), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_P1_03), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/nordic/boards/common.template.ld b/ports/nordic/boards/common.template.ld index dda31e4fdce..3828e3e7f9c 100644 --- a/ports/nordic/boards/common.template.ld +++ b/ports/nordic/boards/common.template.ld @@ -62,6 +62,12 @@ SECTIONS .text : { . = ALIGN(4); + __property_getter_start = .; + *(.property_getter) + __property_getter_end = .; + __property_getset_start = .; + *(.property_getset) + __property_getset_end = .; *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.text))) /* .text sections (code) */ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.text*))) /* .text* sections (code) */ *(.rodata) /* .rodata sections (constants, strings, etc.) */ @@ -155,4 +161,9 @@ SECTIONS */ .ARM.attributes 0 : { *(.ARM.attributes) } + + ASSERT((__property_getter_end - __property_getter_start) % 8 == 0, + "the .property_getter section must hold whole 8-byte objects") + ASSERT((__property_getset_end - __property_getset_start) % 12 == 0, + "the .property_getset section must hold whole 12-byte objects") } diff --git a/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk b/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk index 0e3b1b90489..afbdca62793 100644 --- a/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk +++ b/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk @@ -11,3 +11,6 @@ INTERNAL_FLASH_FILESYSTEM = 1 CIRCUITPY_AUDIOIO = 0 CIRCUITPY_DISPLAYIO = 1 CIRCUITPY_STAGE = 1 +CIRCUITPY_DIGITALINOUT_PROTOCOL = 0 +CIRCUITPY_LOAD_NATIVE = 0 +CIRCUITPY_MSGPACK = 0 diff --git a/ports/nordic/boards/electronut_labs_papyr/mpconfigboard.mk b/ports/nordic/boards/electronut_labs_papyr/mpconfigboard.mk index 569dccc9c4a..0cace0204e3 100644 --- a/ports/nordic/boards/electronut_labs_papyr/mpconfigboard.mk +++ b/ports/nordic/boards/electronut_labs_papyr/mpconfigboard.mk @@ -6,3 +6,4 @@ USB_MANUFACTURER = "Electronut Labs" MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/nordic/boards/espruino_banglejs2/board.c b/ports/nordic/boards/espruino_banglejs2/board.c index 16af0269168..09adb43f8be 100644 --- a/ports/nordic/boards/espruino_banglejs2/board.c +++ b/ports/nordic/boards/espruino_banglejs2/board.c @@ -9,7 +9,6 @@ #include "mpconfigboard.h" #include "shared-bindings/busio/SPI.h" -#include "shared-bindings/fourwire/FourWire.h" #include "shared-bindings/framebufferio/FramebufferDisplay.h" #include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" #include "shared-module/displayio/__init__.h" diff --git a/ports/nordic/boards/hiibot_bluefi/board.c b/ports/nordic/boards/hiibot_bluefi/board.c index 73430d675eb..a05be7a0a63 100644 --- a/ports/nordic/boards/hiibot_bluefi/board.c +++ b/ports/nordic/boards/hiibot_bluefi/board.c @@ -34,9 +34,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_P0_27, // TFT_DC Command or data - &pin_P0_05, // TFT_CS Chip select - NULL, // no TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_P0_27), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_P0_05), // TFT_CS Chip select + mp_const_none, // no TFT_RST Reset // &pin_P1_14, // TFT_RST Reset 60000000, // Baudrate 0, // Polarity diff --git a/ports/nordic/boards/makerdiary_nrf52840_m2_devkit/board.c b/ports/nordic/boards/makerdiary_nrf52840_m2_devkit/board.c index 64199b98009..4f9c051478a 100644 --- a/ports/nordic/boards/makerdiary_nrf52840_m2_devkit/board.c +++ b/ports/nordic/boards/makerdiary_nrf52840_m2_devkit/board.c @@ -35,9 +35,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_P0_08, // TFT_DC Command or data - &pin_P0_06, // TFT_CS Chip select - &pin_P1_09, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_P0_08), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_P0_06), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_P1_09), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/nordic/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.mk b/ports/nordic/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.mk index 1a650d5d4db..35547b75c3f 100644 --- a/ports/nordic/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.mk +++ b/ports/nordic/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.mk @@ -8,3 +8,4 @@ MCU_CHIP = nrf52840 CIRCUITPY_BUILD_EXTENSIONS = hex,uf2 INTERNAL_FLASH_FILESYSTEM = 1 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/nordic/boards/nice_nano/mpconfigboard.mk b/ports/nordic/boards/nice_nano/mpconfigboard.mk index 511a754e69a..5284635cdfc 100644 --- a/ports/nordic/boards/nice_nano/mpconfigboard.mk +++ b/ports/nordic/boards/nice_nano/mpconfigboard.mk @@ -6,3 +6,6 @@ USB_MANUFACTURER = "Nice Keyboards" MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 + +CIRCUITPY_LOAD_NATIVE = 0 +CIRCUITPY_MSGPACK = 0 diff --git a/ports/nordic/boards/ohs2020_badge/board.c b/ports/nordic/boards/ohs2020_badge/board.c index ea716006cb4..d16d99473f0 100644 --- a/ports/nordic/boards/ohs2020_badge/board.c +++ b/ports/nordic/boards/ohs2020_badge/board.c @@ -34,9 +34,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_P0_08, // TFT_DC Command or data - &pin_P0_14, // TFT_CS Chip select - &pin_P0_13, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_P0_08), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_P0_14), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_P0_13), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/nordic/boards/pca10059/mpconfigboard.mk b/ports/nordic/boards/pca10059/mpconfigboard.mk index fe702a50c94..af77ba2345e 100644 --- a/ports/nordic/boards/pca10059/mpconfigboard.mk +++ b/ports/nordic/boards/pca10059/mpconfigboard.mk @@ -8,3 +8,4 @@ MCU_CHIP = nrf52840 CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 INTERNAL_FLASH_FILESYSTEM = 1 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/nordic/boards/pca10100/mpconfigboard.mk b/ports/nordic/boards/pca10100/mpconfigboard.mk index a081a0db479..72053e7cb03 100644 --- a/ports/nordic/boards/pca10100/mpconfigboard.mk +++ b/ports/nordic/boards/pca10100/mpconfigboard.mk @@ -9,3 +9,6 @@ INTERNAL_FLASH_FILESYSTEM = 1 CIRCUITPY_ONEWIREIO = 0 CIRCUITPY_AUDIOMIXER = 0 +CIRCUITPY_RAINBOWIO = 0 +CIRCUITPY_USB_MIDI = 0 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/nordic/boards/pillbug/mpconfigboard.mk b/ports/nordic/boards/pillbug/mpconfigboard.mk index d917ba01578..8d8bab5e29e 100644 --- a/ports/nordic/boards/pillbug/mpconfigboard.mk +++ b/ports/nordic/boards/pillbug/mpconfigboard.mk @@ -6,3 +6,6 @@ USB_MANUFACTURER = "Mechwild" MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 + +CIRCUITPY_LOAD_NATIVE = 0 +CIRCUITPY_MSGPACK = 0 diff --git a/ports/nordic/boards/raytac_mdbt50q-db-40/mpconfigboard.mk b/ports/nordic/boards/raytac_mdbt50q-db-40/mpconfigboard.mk index f49618e776d..3265b888958 100644 --- a/ports/nordic/boards/raytac_mdbt50q-db-40/mpconfigboard.mk +++ b/ports/nordic/boards/raytac_mdbt50q-db-40/mpconfigboard.mk @@ -6,3 +6,4 @@ USB_MANUFACTURER = "Raytac Corporation" MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/nordic/boards/raytac_mdbt50q-rx/mpconfigboard.mk b/ports/nordic/boards/raytac_mdbt50q-rx/mpconfigboard.mk index 08c7266d36b..93ac977e1d8 100644 --- a/ports/nordic/boards/raytac_mdbt50q-rx/mpconfigboard.mk +++ b/ports/nordic/boards/raytac_mdbt50q-rx/mpconfigboard.mk @@ -6,3 +6,4 @@ USB_MANUFACTURER = "Raytac Corporation" MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/nordic/boards/ssci_isp1807_dev_board/mpconfigboard.mk b/ports/nordic/boards/ssci_isp1807_dev_board/mpconfigboard.mk index 34b39d13217..4b0b90e5825 100644 --- a/ports/nordic/boards/ssci_isp1807_dev_board/mpconfigboard.mk +++ b/ports/nordic/boards/ssci_isp1807_dev_board/mpconfigboard.mk @@ -6,3 +6,4 @@ USB_MANUFACTURER = "Switch Science, Inc." MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/nordic/boards/ssci_isp1807_micro_board/mpconfigboard.mk b/ports/nordic/boards/ssci_isp1807_micro_board/mpconfigboard.mk index ae3a750f80f..3041078adf3 100644 --- a/ports/nordic/boards/ssci_isp1807_micro_board/mpconfigboard.mk +++ b/ports/nordic/boards/ssci_isp1807_micro_board/mpconfigboard.mk @@ -6,3 +6,4 @@ USB_MANUFACTURER = "Switch Science, Inc." MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/nordic/boards/supermini_nrf52840/mpconfigboard.mk b/ports/nordic/boards/supermini_nrf52840/mpconfigboard.mk index 699d19b7706..921a140454d 100644 --- a/ports/nordic/boards/supermini_nrf52840/mpconfigboard.mk +++ b/ports/nordic/boards/supermini_nrf52840/mpconfigboard.mk @@ -6,3 +6,6 @@ USB_MANUFACTURER = "ICBbuy" MCU_CHIP = nrf52840 INTERNAL_FLASH_FILESYSTEM = 1 + +CIRCUITPY_LOAD_NATIVE = 0 +CIRCUITPY_MSGPACK = 0 diff --git a/ports/nordic/boards/teenage_engineering_sp1/board.c b/ports/nordic/boards/teenage_engineering_sp1/board.c new file mode 100644 index 00000000000..ad729a5e5fc --- /dev/null +++ b/ports/nordic/boards/teenage_engineering_sp1/board.c @@ -0,0 +1,417 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Early-boot hygiene for the Teenage Engineering SP-1. +// +// Unlike a normal CircuitPython board, this one is entered from a bootloader +// that has already brought hardware up: it starts HFCLK and LFCLK, and leaves +// PWM2, PWM3 and the SAADC enabled. It also starts a watchdog that we cannot +// stop. So the app has to take the machine over from a *running* state rather +// than a reset state, and it has to do so quickly. +// +// The bootloader's watchdog is the reason for the feeds scattered through this +// file: it is running before we are, its configuration is locked, and nothing +// but a reload keeps it from resetting the board. See wdt.h. + +#include "supervisor/board.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/busio/I2C.h" + +#include "background.h" +#include "board.h" +#include "common-hal/microcontroller/Pin.h" +#include "flash_protect.h" +#include "peripherals/nrf/pins.h" +#include "power_off.h" +#include "py/misc.h" +#include "supervisor/shared/safe_mode.h" +#include "shared-module/emmcio/__init__.h" +#include "wdt.h" +#include "nrfx/drivers/include/nrfx_rtc.h" +#include "nrfx/hal/nrf_gpio.h" + +#define PIN_EMMC_RESET (DEFAULT_EMMC_RESET->number) // active low +#define PIN_EMMC_VCCQ_EN (DEFAULT_EMMC_VCCQ->number) // eMMC I/O rail + +// Pins this file drives directly. +#define PIN_OSC_EN NRF_GPIO_PIN_MAP(0, 13) // 3.072 MHz oscillator +#define PIN_TAS_RESET NRF_GPIO_PIN_MAP(0, 9) // TAS2505, active low +#define PIN_CS42_RESET NRF_GPIO_PIN_MAP(0, 15) // CS42L42, active low +#define PIN_BT_RESET NRF_GPIO_PIN_MAP(0, 10) // CYBT-353027-02, active low +#define PIN_CONTROL_RAIL NRF_GPIO_PIN_MAP(1, 10) // feeds faders + ladders +#define PIN_FUNCTION_BUTTON NRF_GPIO_PIN_MAP(0, 27) // active low, only GPIO button +#define PIN_CHARGE_ENABLE NRF_GPIO_PIN_MAP(0, 21) // BQ24232, active low +#define PIN_I2C_SCL NRF_GPIO_PIN_MAP(1, 11) // shared by both codecs +#define PIN_I2C_SDA NRF_GPIO_PIN_MAP(1, 7) + +// Both LED rows, active high. PIN_LED_HEARTBEAT is the first track LED, which +// is also MICROPY_HW_LED_STATUS and BOARD_POWER_OFF_CONFIRM_LED_PIN +#define PIN_LED_HEARTBEAT NRF_GPIO_PIN_MAP(0, 29) +static const uint8_t led_pins[] = { + NRF_GPIO_PIN_MAP(1, 13), NRF_GPIO_PIN_MAP(0, 0), // playback row (side) + NRF_GPIO_PIN_MAP(1, 12), NRF_GPIO_PIN_MAP(0, 1), + PIN_LED_HEARTBEAT, NRF_GPIO_PIN_MAP(0, 26), // track row (front) + NRF_GPIO_PIN_MAP(1, 15), NRF_GPIO_PIN_MAP(1, 14), +}; + +// Whether the boot up blink heartbeat still owns PIN_LED_HEARTBEAT. +static bool heartbeat_lit; + +// The bootloader's watchdog is fed from board_background_task(), so the CPU +// must not stay in WFI for longer than the bootloader will wait. The port owns +// RTC2 and this board builds no SoftDevice (which would own RTC0), so RTC1 is +// free to hand the main loop its turn back on a fixed period. +// +// Waking is the whole job. The feed itself deliberately stays in the main loop, +// so that a wedge there still becomes a reset. +static const nrfx_rtc_t wake_rtc = NRFX_RTC_INSTANCE(1); +#define WAKE_RTC_CHANNEL (0) +// Run the counter straight off the LFCLK, as the port's own RTC does. +#define WAKE_RTC_FREQUENCY_HZ (32768) +// How long the CPU may stay in WFI before the main loop must get another look +// in. +#define WAKE_RTC_PERIOD_TICKS (WAKE_RTC_FREQUENCY_HZ) + +static void arm_wake_rtc(void) { + nrfx_rtc_cc_set(&wake_rtc, WAKE_RTC_CHANNEL, + nrfx_rtc_counter_get(&wake_rtc) + WAKE_RTC_PERIOD_TICKS, true); +} + +static void wake_rtc_handler(nrfx_rtc_int_type_t int_type) { + (void)int_type; + arm_wake_rtc(); +} + +// Bounded wait for a peripheral to acknowledge a STOP. +#define STOP_TIMEOUT_ITERATIONS (20000) + +static void wait_for_event(volatile uint32_t *event) { + for (uint32_t i = 0; i < STOP_TIMEOUT_ITERATIONS && *event == 0; i++) { + __NOP(); + } + *event = 0; + // Read back to flush the write buffer, per the nRF52 errata guidance for + // clearing events. + (void)*event; +} + +static void stop_pwm(NRF_PWM_Type *pwm) { + if (pwm->ENABLE == 0) { + return; + } + pwm->EVENTS_STOPPED = 0; + pwm->TASKS_STOP = 1; + wait_for_event(&pwm->EVENTS_STOPPED); + pwm->INTENCLR = 0xFFFFFFFF; + pwm->ENABLE = 0; +} + +void board_early_init(void) { + // Feed the bootloader's watchdog before anything else. This is the first + // CircuitPython code to run on the board: port_init() calls it before it + // touches a peripheral. + bootloader_wdt_feed(); + + // Lock the bootloader out of NVMC's reach for the rest of this boot. First, + // because from here on every line of CircuitPython that runs is one more + // thing that could get it wrong, and the bootloader is this board's only + // way back in. See flash_protect.h. + board_flash_protect(); + + // A watchdog reset can only mean the main loop stopped, and on this board + // that is worth safe mode with or without a host attached: there is no + // reset pin and no removable battery, so re-running the same wedging + // `code.py` is the one thing that can make the device unrecoverable. + // port_init() asks for safe mode itself when USB is attached; this covers + // the battery case. RESETREAS is still untouched here -- port_init() reads + // and clears it after we return -- and the request is picked up by + // wait_for_safe_mode_reset() later in this same boot, not after a reset. + if ((NRF_POWER->RESETREAS & POWER_RESETREAS_DOG_Msk) != 0 && + (NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk) == 0) { + safe_mode_on_next_reset(SAFE_MODE_WATCHDOG); + } + + // First light boot up status blink. + // + // never lights the bootloader did not jump here, or we died in + // the reset handler / SystemInit + // lights and stays on we are running, but did not reach board_init(): + // suspect the filesystem format or something + // before the workflow starts + // lights, then goes out board_init() reached; USB is next, so from here + // on the absence of a tty is a USB problem + // + nrf_gpio_cfg_output(PIN_LED_HEARTBEAT); + nrf_gpio_pin_set(PIN_LED_HEARTBEAT); + heartbeat_lit = true; + + for (size_t i = 0; i < 8; i++) { + NVIC->ICER[i] = 0xFFFFFFFF; + NVIC->ICPR[i] = 0xFFFFFFFF; + } + __DSB(); + __ISB(); + + // Break any PPI wiring before stopping peripherals, so nothing we stop can + // be restarted by a leftover event->task connection. + NRF_PPI->CHENCLR = 0xFFFFFFFF; + + // The bootloader drives the LEDs with PWM2 and PWM3. PWM0/PWM1 are stopped + // too so that pwmio starts from a known state. + stop_pwm(NRF_PWM0); + stop_pwm(NRF_PWM1); + stop_pwm(NRF_PWM2); + stop_pwm(NRF_PWM3); + + // The bootloader reads the button ladders with the SAADC and leaves it + // enabled, so clear it. + if (NRF_SAADC->ENABLE != 0) { + NRF_SAADC->EVENTS_STOPPED = 0; + NRF_SAADC->TASKS_STOP = 1; + wait_for_event(&NRF_SAADC->EVENTS_STOPPED); + NRF_SAADC->INTENCLR = 0xFFFFFFFF; + NRF_SAADC->EVENTS_END = 0; + NRF_SAADC->EVENTS_STARTED = 0; + NRF_SAADC->EVENTS_CALIBRATEDONE = 0; + NRF_SAADC->ENABLE = 0; + } + + // Last, because the blanket NVIC clear above would undo it: the periodic + // wake-up that keeps the main loop feeding the watchdog. LFCLK is not + // running yet, so the counter starts when port_init() starts it, a few + // instructions from here. + static const nrfx_rtc_config_t wake_rtc_config = { + .prescaler = RTC_FREQ_TO_PRESCALER(WAKE_RTC_FREQUENCY_HZ), + .reliable = 0, + .tick_latency = 0, + .interrupt_priority = 6, + }; + nrfx_rtc_init(&wake_rtc, &wake_rtc_config, wake_rtc_handler); + arm_wake_rtc(); + nrfx_rtc_enable(&wake_rtc); +} + +// Pins that must not float. reset_all_pins() and reset_pin_number() ask the +// board for each pin, so this configuration is re-applied after every reset +// rather than the pin being left in its default (disconnected) state. +// +// None of these are marked never-reset, so Python can still claim them. This +// only makes the resting state between runs a defined, safe one. +static const uint8_t default_low_pins[] = { + // 3.072 MHz oscillator enable. Held low: it draws current straight through + // SYSTEM_OFF, so a floating pin here would drain battery. + PIN_OSC_EN, + + // Codecs and the Bluetooth module held in reset (all active low) so that + // nothing downstream of us starts making noise or driving a shared bus on + // its own. P0.09/P0.10 are the NFC pins; UICR NFCPINS reads with PROTECT + // already cleared on this board, so they are usable as GPIO. + PIN_TAS_RESET, + PIN_CS42_RESET, + PIN_BT_RESET, + + // Rail feeding the faders and both button ladders. Off unless something is + // actually reading them. + PIN_CONTROL_RAIL, + + // BQ24232 charge enable, active low: drive it low so a plugged-in device + // charges. P1.00 (CHARGE_ISET) is deliberately left untouched. It is the + // charge-current programming node (ICHG = 870 AΩ / RISET) and doubles as + // the current monitor. + PIN_CHARGE_ENABLE, +}; + +// Returns false for a pin this board has no opinion about. +static bool apply_pin_default(uint8_t pin_number) { + // Function button: the only GPIO button, active low, and the only wake + // source out of SYSTEM_OFF. Keep it readable at all times, the + // supervisor's power-off gesture depends on it. + if (pin_number == PIN_FUNCTION_BUTTON) { + nrf_gpio_cfg_input(PIN_FUNCTION_BUTTON, NRF_GPIO_PIN_PULLUP); + return true; + } + + // Both LED rows, off. + for (size_t i = 0; i < MP_ARRAY_SIZE(led_pins); i++) { + if (led_pins[i] == pin_number) { + nrf_gpio_cfg_output(pin_number); + nrf_gpio_pin_clear(pin_number); + return true; + } + } + + // eMMC held in reset with its VCCQ rail off. The contents of the chip are + // unaffected; this only keeps the rail from floating. The exception is a + // card the supervisor has automounted: it is a live filesystem between + // runs, so leave its reset and rail exactly as the driver left them. + if (pin_number == PIN_EMMC_RESET || pin_number == PIN_EMMC_VCCQ_EN) { + if (!emmcio_is_automounted()) { + nrf_gpio_cfg_output(pin_number); + nrf_gpio_pin_clear(pin_number); + } + return true; + } + + for (size_t i = 0; i < MP_ARRAY_SIZE(default_low_pins); i++) { + if (default_low_pins[i] == pin_number) { + nrf_gpio_cfg_output(pin_number); + nrf_gpio_pin_clear(pin_number); + return true; + } + } + + return false; +} + +// Put every pin this board has an opinion about into its resting state at once. +static void apply_all_pin_defaults(void) { + apply_pin_default(PIN_FUNCTION_BUTTON); + apply_pin_default(PIN_EMMC_RESET); + apply_pin_default(PIN_EMMC_VCCQ_EN); + for (size_t i = 0; i < MP_ARRAY_SIZE(led_pins); i++) { + apply_pin_default(led_pins[i]); + } + for (size_t i = 0; i < MP_ARRAY_SIZE(default_low_pins); i++) { + apply_pin_default(default_low_pins[i]); + } +} + +bool board_reset_pin_number(uint8_t pin_number) { + // main() calls reset_all_pins() immediately after port_init(), so without + // this the boot up heartbeat blink would last microseconds and show + // nothing. board_init() hands the pin back. + if (heartbeat_lit && pin_number == PIN_LED_HEARTBEAT) { + return true; + } + + return apply_pin_default(pin_number); +} + +// Called once at start up, after the filesystem is mounted and immediately +// before the USB workflow starts. Where we end the heartbeat status blink. +void board_init(void) { + heartbeat_lit = false; + nrf_gpio_pin_clear(PIN_LED_HEARTBEAT); +} + +void board_background_task(void) { + bootloader_wdt_feed(); + + #ifdef BOARD_POWER_OFF_BUTTON_PIN + // Never returns if the hold completes. + power_off_tick(); + #endif +} + +// -- muting the codecs on the way out -------------------------------------- +// +// Dropping the reset lines and the oscillator (apply_all_pin_defaults()) is +// enough to make the board quiet and to save the battery, but it cuts both +// codecs off mid-signal: the CS42L42 loses its clock and the TAS2505's class-D +// driver loses its reset with whatever was on the output still on it. +// +// Bit-banged rather than driven through TWIM. + +#define I2C_FREQUENCY (100000) +#define I2C_TIMEOUT_MS (255) + +static busio_i2c_obj_t codec_i2c; + +// two-byte write +static bool i2c_write2(uint8_t address, uint8_t first, uint8_t second) { + const uint8_t data[2] = { first, second }; + return common_hal_busio_i2c_write(&codec_i2c, address, data, sizeof(data)) == 0; +} + +// Register addresses +#define PAGE_SELECT_REG (0x00) // register 0 selects the page, on both + +#define CS42L42_ADDRESS (0x48) +#define CS_HP_CTL_PAGE (0x20) // CS_HP_CTL = 0x2001, page = high byte +#define CS_HP_CTL_REG (0x01) +#define CS_HP_MUTE (0x0D) + +#define TAS2505_ADDRESS (0x18) +#define TAS_SW_RESET (0x01) // page 0 +#define TAS_DAC_MUTE (0x40) // page 0 +#define TAS_MUTED (0x0C) +#define TAS_SPK_POWER (0x2D) // page 1 + +// Mute the CS42L42, then mute the TAS2505, power its class-D driver down and +// soft-reset it. +static void quiesce_codecs(void) { + bootloader_wdt_feed(); + + #if CIRCUITPY_BOARD_I2C + + busio_i2c_obj_t *shared = common_hal_board_get_i2c(0); + if (shared != NULL) { + common_hal_busio_i2c_unlock(shared); + common_hal_busio_i2c_deinit(shared); + } + #endif + + if (!pin_number_is_free(PIN_I2C_SCL) || !pin_number_is_free(PIN_I2C_SDA)) { + return; + } + + codec_i2c.base.type = &busio_i2c_type; + common_hal_busio_i2c_construct(&codec_i2c, DEFAULT_I2C_BUS_SCL, + DEFAULT_I2C_BUS_SDA, I2C_FREQUENCY, I2C_TIMEOUT_MS); + + if (i2c_write2(CS42L42_ADDRESS, PAGE_SELECT_REG, CS_HP_CTL_PAGE)) { + i2c_write2(CS42L42_ADDRESS, CS_HP_CTL_REG, CS_HP_MUTE); + } + bootloader_wdt_feed(); + + if (i2c_write2(TAS2505_ADDRESS, PAGE_SELECT_REG, 0x00)) { + i2c_write2(TAS2505_ADDRESS, TAS_DAC_MUTE, TAS_MUTED); + bootloader_wdt_feed(); + if (i2c_write2(TAS2505_ADDRESS, PAGE_SELECT_REG, 0x01)) { + i2c_write2(TAS2505_ADDRESS, TAS_SPK_POWER, 0x00); + } + bootloader_wdt_feed(); + // Back to page 0 for the software reset + if (i2c_write2(TAS2505_ADDRESS, PAGE_SELECT_REG, 0x00)) { + i2c_write2(TAS2505_ADDRESS, TAS_SW_RESET, 0x01); + } + } + + common_hal_busio_i2c_deinit(&codec_i2c); + bootloader_wdt_feed(); +} + +void reset_board(void) { + quiesce_codecs(); +} + +// The board half of the power-off sequence +// Runs with the Function button still held, before the wake is armed. +void board_power_off_prepare(void) { + quiesce_codecs(); + + // Codecs into reset, CS42L42 first: it drives the I2S frames, so + // stopping it stops the bus the TAS2505 is listening to. + nrf_gpio_cfg_output(PIN_CS42_RESET); + nrf_gpio_pin_clear(PIN_CS42_RESET); + nrf_gpio_cfg_output(PIN_TAS_RESET); + nrf_gpio_pin_clear(PIN_TAS_RESET); + + // eMMC I/O rail, before the oscillator, so nothing is left half-powered + // against a clock that has stopped. + nrf_gpio_cfg_output(PIN_EMMC_RESET); + nrf_gpio_pin_clear(PIN_EMMC_RESET); + nrf_gpio_cfg_output(PIN_EMMC_VCCQ_EN); + nrf_gpio_pin_clear(PIN_EMMC_VCCQ_EN); + + // 3.072 MHz oscillator + nrf_gpio_cfg_output(PIN_OSC_EN); + nrf_gpio_pin_clear(PIN_OSC_EN); + + // Everything else, LEDs included. + apply_all_pin_defaults(); +} diff --git a/ports/nordic/boards/teenage_engineering_sp1/flash_protect.c b/ports/nordic/boards/teenage_engineering_sp1/flash_protect.c new file mode 100644 index 00000000000..db87935dbb9 --- /dev/null +++ b/ports/nordic/boards/teenage_engineering_sp1/flash_protect.c @@ -0,0 +1,52 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "flash_protect.h" + +#include "py/mpconfig.h" + +#include "nrfx/hal/nrf_acl.h" + +// protect the MBR at 0x0 and the bootloader above it, up to the +// address the bootloader jumps to. +#define PROTECT_START_ADDR (MBR_START_ADDR) +#define PROTECT_SIZE (ISR_START_ADDR - MBR_START_ADDR) + +#if PROTECT_SIZE == 0 +#error The bootloader for this board is not in low flash; nothing for the ACL to protect. +#endif + +#if PROTECT_SIZE > NRF_ACL_REGION_SIZE_MAX +#error The bootloader region is larger than a single ACL region can cover. +#endif + +#if (PROTECT_START_ADDR % FLASH_PAGE_SIZE) != 0 || (PROTECT_SIZE % FLASH_PAGE_SIZE) != 0 +#error ACL regions must start and end on a flash page boundary. +#endif + +void board_flash_protect(void) { + for (uint32_t region = 0; region < ACL_REGIONS_COUNT; region++) { + // A region's registers only take their first write after a reset, so a + // region the bootloader has already configured has to be left alone. + if (nrf_acl_region_size_get(NRF_ACL, region) != 0 || + nrf_acl_region_perm_get(NRF_ACL, region) != 0) { + continue; + } + + // Read stays enabled. The MBR's vector table is read out of this + // region on every interrupt, and the bootloader is executed in place + // out of it on the way back in. + nrf_acl_region_set(NRF_ACL, region, PROTECT_START_ADDR, PROTECT_SIZE, + NRF_ACL_PERM_READ_NO_WRITE); + + // Read back rather than trust the write: an already-claimed region + // would have ignored it. + if (nrf_acl_region_address_get(NRF_ACL, region) == PROTECT_START_ADDR && + nrf_acl_region_size_get(NRF_ACL, region) == PROTECT_SIZE) { + return; + } + } +} diff --git a/ports/nordic/boards/teenage_engineering_sp1/flash_protect.h b/ports/nordic/boards/teenage_engineering_sp1/flash_protect.h new file mode 100644 index 00000000000..4a21bfb2758 --- /dev/null +++ b/ports/nordic/boards/teenage_engineering_sp1/flash_protect.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Hardware write-protection for this board's bootloader. + +void board_flash_protect(void); diff --git a/ports/nordic/boards/teenage_engineering_sp1/mpconfigboard.h b/ports/nordic/boards/teenage_engineering_sp1/mpconfigboard.h new file mode 100644 index 00000000000..2365d724186 --- /dev/null +++ b/ports/nordic/boards/teenage_engineering_sp1/mpconfigboard.h @@ -0,0 +1,81 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "nrfx/hal/nrf_gpio.h" + +#define MICROPY_HW_BOARD_NAME "Teenage Engineering SP-1" +#define MICROPY_HW_MCU_NAME "nRF52840" + +// Flash map. The bootloader owns 0x00000-0x20000 and jumps to 0x20000, so +// the vector table goes there. +// +// There is no bootloader in *high* flash either, so both bootloader sizes are +// zero and BOOTLOADER_START_ADDR collapses onto the bootloader settings page +// at 0xFF000. That page belongs to the bootloader and must never be +// written. +// +// 0x00000-0x20000 bootloader (never touched) +// 0x20000-0x21000 ISR/vector table +// 0x21000-0xBD000 firmware (624 KiB) +// 0xBD000-0xBF000 microcontroller.nvm (8 KiB) +// 0xBF000-0xFF000 CIRCUITPY internal-flash FAT (256 KiB) +// 0xFF000-0x100000 bootloader settings page (RESERVED) +#define ISR_START_ADDR (0x20000) +#define BOOTLOADER_SIZE (0) +#define BOOTLOADER_MBR_SIZE (0) + +// No BLE on this board, so nothing to store for bonding. +#define CIRCUITPY_BLE_CONFIG_SIZE (0) + +// No 32.768 kHz crystal: P0.00 and P0.01 are playback LEDs. Use the RC +// oscillator for LFCLK. +#define BOARD_HAS_32KHZ_XTAL (0) + +// Power off. There is no reset pin, no power switch and no removable battery, +// so SYSTEM_OFF is the only "off" this device has. Waking from off is one +// of only two routes back to the bootloader. P0.27 (Function) is the only +// GPIO button and the only wake source; it is a plain switch to ground. +#define BOARD_POWER_OFF_BUTTON_PIN NRF_GPIO_PIN_MAP(0, 27) + +// The bootloader's DFU magic. The gate at 0x6b2 is 16 bits wide and +// split across both retention registers, +// +// GPREGRET | (GPREGRET2 << 8) == 0x7EB3 +// +// +// This bootloader has no separate UF2/OTA and serial-DFU requests. There is +// one gate, so both magics are the same pair and, reset_to_bootloader() and +// microcontroller.on_next_reset(RunMode.BOOTLOADER) both land in boot mode. +#define BOOTLOADER_DFU_MAGIC (0xB3) +#define BOOTLOADER_DFU_MAGIC2 (0x7E) +#define BOOTLOADER_UF2_MAGIC (0xB3) +#define BOOTLOADER_UF2_MAGIC2 (0x7E) + +// No SD card LUN. There is no card slot on this device. +#define CIRCUITPY_SDCARD_USB (0) + +// The 4 GB eMMC +#define DEFAULT_EMMC_CLOCK (&pin_P0_06) +#define DEFAULT_EMMC_COMMAND (&pin_P0_08) +#define DEFAULT_EMMC_DATA (&pin_P0_07) +#define DEFAULT_EMMC_RESET (&pin_P1_08) +#define DEFAULT_EMMC_VCCQ (&pin_P0_14) + +// TWIM to the CS42L42 (0x48) and TAS2505 (0x18). +#define DEFAULT_I2C_BUS_SCL (&pin_P1_11) +#define DEFAULT_I2C_BUS_SDA (&pin_P1_07) + +// The CDC REPL is normally the only place status is visible. Borrow the first +// track LED for the supervisor status LED so that safe mode is legible on the +// device itself. It is claimed only while the supervisor is showing status and +// is released before user code runs, so board.LED_TRACK1 stays usable. +#define MICROPY_HW_LED_STATUS (&pin_P0_29) + +// Blink that same LED once, ~200 ms, the moment the power-off hold completes. +// The gesture is otherwise silent. +#define BOARD_POWER_OFF_CONFIRM_LED_PIN NRF_GPIO_PIN_MAP(0, 29) diff --git a/ports/nordic/boards/teenage_engineering_sp1/mpconfigboard.mk b/ports/nordic/boards/teenage_engineering_sp1/mpconfigboard.mk new file mode 100644 index 00000000000..5f505494006 --- /dev/null +++ b/ports/nordic/boards/teenage_engineering_sp1/mpconfigboard.mk @@ -0,0 +1,62 @@ +USB_VID = 0x239A +USB_PID = 0x817A +USB_PRODUCT = "SP-1 (CircuitPython)" +USB_MANUFACTURER = "Teenage Engineering" + +MCU_CHIP = nrf52840 + +# SystemInit() burns UICR PSELRESET[0..1] = 18 and resets whenever it finds +# them unprogrammed, which is the case on this board. Opt out of it +$(BUILD)/nrfx/mdk/system_nrf52840.o: CFLAGS += -UCONFIG_GPIO_AS_PINRESET + +# No BLE. A SoftDevice would have to live at 0x1000, which is inside this +# board's bootloader, and the radio has no antenna. +CIRCUITPY_BLEIO_NATIVE = 0 +CIRCUITPY_BLE_FILE_SERVICE = 0 +CIRCUITPY_BLE_SERIAL_SERVICE = 0 + +# CIRCUITPY is in internal flash; there is no external flash chip. +INTERNAL_FLASH_FILESYSTEM = 1 + +# No UF2 bootloader on this device. +CIRCUITPY_BUILD_EXTENSIONS = bin,hex + +# displayio off no display. +CIRCUITPY_DISPLAYIO = 0 +CIRCUITPY_FRAMEBUFFERIO = 0 +CIRCUITPY_RGBMATRIX = 0 +CIRCUITPY_SHARPDISPLAY = 0 +CIRCUITPY_IS31FL3741 = 0 +CIRCUITPY_VECTORIO = 0 + +# The watchdog is started by the bootloader before our first instruction and +# its config registers are locked. +CIRCUITPY_WATCHDOG = 0 + +# alarm's idle paths need a WDT-feed audit before they are safe here. +CIRCUITPY_ALARM = 0 + +# Audio +CIRCUITPY_AUDIOPWMIO = 0 +CIRCUITPY_SYNTHIO = 1 +CIRCUITPY_AUDIOEFFECTS = 1 +CIRCUITPY_AUDIOMP3 = 1 + +# Hold-to-power-off, opted into by BOARD_POWER_OFF_BUTTON_PIN in +# mpconfigboard.h. +SRC_C += boards/$(BOARD)/power_off.c + +# ACL write-protection for the MBR and the bootloader, which this board's +# bootloader does not set up for itself. +SRC_C += boards/$(BOARD)/flash_protect.c + +# The soldered-down eMMC, and the supervisor mount that puts it on /sd and on +# USB as a second drive. +CIRCUITPY_EMMCIO = 1 +CIRCUITPY_EMMC_USB = 1 + +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_CS42L42 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_TAS2505 + +CIRCUITPY_REQUIRE_I2C_PULLUPS = 0 diff --git a/ports/nordic/boards/teenage_engineering_sp1/pins.c b/ports/nordic/boards/teenage_engineering_sp1/pins.c new file mode 100644 index 00000000000..66897f7514d --- /dev/null +++ b/ports/nordic/boards/teenage_engineering_sp1/pins.c @@ -0,0 +1,91 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Pin map from Tim Knapen's reverse-engineering of the Teenage Engineering SP-1 +// https://github.com/timknapen/SP-1-dev/wiki + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Four track faders, in physical left-to-right order. + { MP_ROM_QSTR(MP_QSTR_FADER1), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_FADER2), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_FADER3), MP_ROM_PTR(&pin_P0_04) }, + { MP_ROM_QSTR(MP_QSTR_FADER4), MP_ROM_PTR(&pin_P0_31) }, + + // Two resistor-ladder button rows, read as analog voltages. Both need + // LADDER_POWER driven high to read anything; the faders need it too. + // + // Rungs in ascending voltage: + // LADDER1: TRACK1, TRACK2, TRACK3, TRACK4, PLAY + // LADDER2: ROCKER-, VOL-, ROCKER+, VOL+ + // Both rows are the same resistor network; LADDER2 is LADDER1 with the + // lowest rung unpopulated, so one threshold table serves both. + // + // "ROCKER" is the left-side rocker switch + { MP_ROM_QSTR(MP_QSTR_LADDER1), MP_ROM_PTR(&pin_P0_02) }, + { MP_ROM_QSTR(MP_QSTR_LADDER2), MP_ROM_PTR(&pin_P0_03) }, + { MP_ROM_QSTR(MP_QSTR_LADDER_POWER), MP_ROM_PTR(&pin_P1_10) }, + + // The Function button ("••") is the only GPIO button, active low with a + // pull-up, and the only wake source out of SYSTEM_OFF. + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_P0_27) }, + + // Playback LED row on the side of the device, active high. + { MP_ROM_QSTR(MP_QSTR_LED_PLAY1), MP_ROM_PTR(&pin_P1_13) }, + { MP_ROM_QSTR(MP_QSTR_LED_PLAY2), MP_ROM_PTR(&pin_P0_00) }, + { MP_ROM_QSTR(MP_QSTR_LED_PLAY3), MP_ROM_PTR(&pin_P1_12) }, + { MP_ROM_QSTR(MP_QSTR_LED_PLAY4), MP_ROM_PTR(&pin_P0_01) }, + + // Track LED row above the track buttons, active high. + { MP_ROM_QSTR(MP_QSTR_LED_TRACK1), MP_ROM_PTR(&pin_P0_29) }, + { MP_ROM_QSTR(MP_QSTR_LED_TRACK2), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_LED_TRACK3), MP_ROM_PTR(&pin_P1_15) }, + { MP_ROM_QSTR(MP_QSTR_LED_TRACK4), MP_ROM_PTR(&pin_P1_14) }, + + // I2C to both codecs: CS42L42 headphone amp at 0x48, TAS2505 speaker amp + // at 0x18. + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P1_11) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P1_07) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + // Codec resets, both active low. + { MP_ROM_QSTR(MP_QSTR_TAS_RESET), MP_ROM_PTR(&pin_P0_09) }, + { MP_ROM_QSTR(MP_QSTR_CS42_RESET), MP_ROM_PTR(&pin_P0_15) }, + + // I2S + { MP_ROM_QSTR(MP_QSTR_I2S_DOUT), MP_ROM_PTR(&pin_P1_09) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCLK), MP_ROM_PTR(&pin_P0_11) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_OBJ_FROM_PTR(&pin_P0_11) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BCLK), MP_ROM_PTR(&pin_P0_12) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_OBJ_FROM_PTR(&pin_P0_12) }, + { MP_ROM_QSTR(MP_QSTR_OSC_EN), MP_ROM_PTR(&pin_P0_13) }, + + // 4 GB eMMC + { MP_ROM_QSTR(MP_QSTR_EMMC_CLK), MP_ROM_PTR(&pin_P0_06) }, + { MP_ROM_QSTR(MP_QSTR_EMMC_DAT0), MP_ROM_PTR(&pin_P0_07) }, + { MP_ROM_QSTR(MP_QSTR_EMMC_CMD), MP_ROM_PTR(&pin_P0_08) }, + { MP_ROM_QSTR(MP_QSTR_EMMC_RESET), MP_ROM_PTR(&pin_P1_08) }, + { MP_ROM_QSTR(MP_QSTR_EMMC_VCCQ), MP_ROM_PTR(&pin_P0_14) }, + + // BQ24232 charger. CHARGE_ENABLE and the two status lines are active low. + { MP_ROM_QSTR(MP_QSTR_CHARGE_ISET), MP_ROM_PTR(&pin_P1_00) }, + { MP_ROM_QSTR(MP_QSTR_CHARGE_ENABLE), MP_ROM_PTR(&pin_P0_21) }, + { MP_ROM_QSTR(MP_QSTR_CHARGE_STATUS), MP_ROM_PTR(&pin_P0_22) }, + { MP_ROM_QSTR(MP_QSTR_POWER_GOOD), MP_ROM_PTR(&pin_P0_24) }, + + // Battery sense, AIN4, through a divider. + { MP_ROM_QSTR(MP_QSTR_VBATT), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_P0_28) }, + + // CYBT-353027-02 Bluetooth module reset, active low + { MP_ROM_QSTR(MP_QSTR_BT_RESET), MP_ROM_PTR(&pin_P0_10) }, +}; + +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/nordic/boards/teenage_engineering_sp1/power_off.c b/ports/nordic/boards/teenage_engineering_sp1/power_off.c new file mode 100644 index 00000000000..dd20d4293e4 --- /dev/null +++ b/ports/nordic/boards/teenage_engineering_sp1/power_off.c @@ -0,0 +1,201 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "power_off.h" + +#ifdef BOARD_POWER_OFF_BUTTON_PIN + +#include "py/misc.h" + +#include "supervisor/filesystem.h" +#include "supervisor/flash.h" + +#include "wdt.h" +#include "nrfx/hal/nrf_gpio.h" +#include "nrfx/hal/nrf_power.h" + +#ifndef BOARD_POWER_OFF_HOLD_SECONDS +#define BOARD_POWER_OFF_HOLD_SECONDS (3) +#endif + +// Timings in RTC subticks (32.768 kHz). The counter is 24 bits, so every +// comparison is masked; it wraps every 512s, longer than needed. +#define RTC_COUNTER_MASK (0xFFFFFF) +#define POLL_INTERVAL_SUBTICKS (1024) // ~31 ms +#define POWER_OFF_HOLD_SUBTICKS (BOARD_POWER_OFF_HOLD_SECONDS * 32768) +#define RELEASE_DEBOUNCE_SUBTICKS (1638) // ~50 ms + +// How long the gesture will wait for a filesystem that is being built +#ifndef BOARD_POWER_OFF_FILESYSTEM_GRACE_SECONDS +#define BOARD_POWER_OFF_FILESYSTEM_GRACE_SECONDS (30) +#endif +#define FILESYSTEM_GRACE_SUBTICKS (BOARD_POWER_OFF_FILESYSTEM_GRACE_SECONDS * 32768) + +// The RTC that port.c runs the tick from, read straight out of its counter. +#define POWER_OFF_RTC (NRF_RTC2) + +// Do-nothing default; a board with hardware to quiesce overrides this. +MP_WEAK void board_power_off_prepare(void) { +} + +#ifdef BOARD_POWER_OFF_CONFIRM_LED_PIN + +#ifndef BOARD_POWER_OFF_CONFIRM_LED_MS +#define BOARD_POWER_OFF_CONFIRM_LED_MS (200) +#endif +#define CONFIRM_BLINK_SUBTICKS ((BOARD_POWER_OFF_CONFIRM_LED_MS) * 32768 / 1000) + +// One flash to say the gesture landed. +static void power_off_confirm_blink(void) { + nrf_gpio_cfg_output(BOARD_POWER_OFF_CONFIRM_LED_PIN); + nrf_gpio_pin_set(BOARD_POWER_OFF_CONFIRM_LED_PIN); + // Busy-wait on the same RTC the release loop uses, feeding the watchdog: + // 200 ms is comfortably longer than a bootloader-armed dog's patience. + uint32_t started = POWER_OFF_RTC->COUNTER; + while (((POWER_OFF_RTC->COUNTER - started) & RTC_COUNTER_MASK) < CONFIRM_BLINK_SUBTICKS) { + bootloader_wdt_feed(); + } + nrf_gpio_pin_clear(BOARD_POWER_OFF_CONFIRM_LED_PIN); +} + +#endif // BOARD_POWER_OFF_CONFIRM_LED_PIN + +// Power-off is a sequence, not a register write, and the order matters. +static void power_off(void) { + // 0. Commit the filesystem. Hold-to-power-off is this device's normal + // "off", so the dirty page sitting in the flash cache is typically the + // last thing FAT wrote. + if (filesystem_present()) { + supervisor_flash_flush(); + } + + // 1. Let the board put its own hardware to bed first, while everything is + // still powered and predictable. + board_power_off_prepare(); + + // 1a. Confirm the gesture with one flash, before anything else changes. + // Deliberately after the prepare hook, so it is drawing on a board that + // is already quiesced and the LED it leaves behind is off. + #ifdef BOARD_POWER_OFF_CONFIRM_LED_PIN + power_off_confirm_blink(); + #endif + + // 2. Detach from USB + NRF_USBD->USBPULLUP = 0; + NRF_USBD->ENABLE = 0; + + // 3. Wait for the button to be released, feeding the watchdog meanwhile. + uint32_t released_since = POWER_OFF_RTC->COUNTER; + while (true) { + bootloader_wdt_feed(); + uint32_t now = POWER_OFF_RTC->COUNTER; + if (nrf_gpio_pin_read(BOARD_POWER_OFF_BUTTON_PIN) == 0) { + released_since = now; + } else if (((now - released_since) & RTC_COUNTER_MASK) >= RELEASE_DEBOUNCE_SUBTICKS) { + break; + } + } + + // 4. Clear RESETREAS so the next boot can tell a wake-from-off from a + // watchdog reset. + NRF_POWER->RESETREAS = NRF_POWER->RESETREAS; + + // 5. Arm the wake. Clear any latched DETECT first. + NRF_P0->LATCH = 0xFFFFFFFF; + NRF_P1->LATCH = 0xFFFFFFFF; + nrf_gpio_cfg_sense_input(BOARD_POWER_OFF_BUTTON_PIN, + NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); + + // 6. Off. Note that the spin below deliberately does not feed the + // watchdog. If SYSTEM_OFF does not take a bootloader-armed dog + // bites within seconds and the board comes back up normally. + __DSB(); + NRF_POWER->SYSTEMOFF = 1; + __DSB(); + while (true) { + } +} + +// Reading a pin whose input buffer is disconnected returns 0, which is +// indistinguishable from the button being held. power_off_tick() would see a +// button that is down on the very first poll and never released, so the gesture +// would arm itself off permanently and the board would silently lose its only +// way to power down. +// +// So check the buffer every poll and reconnect it if it +// has gone away. Anything already configured is left exactly as it is. +static void ensure_input_buffer_connected(void) { + uint32_t pin_number = BOARD_POWER_OFF_BUTTON_PIN; + NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&pin_number); + if ((reg->PIN_CNF[pin_number] & GPIO_PIN_CNF_INPUT_Msk) == + (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)) { + // Pull-up, matching the active-low switch-to-ground the header + // documents. Without a pull the line floats and the read is noise. + nrf_gpio_cfg_input(BOARD_POWER_OFF_BUTTON_PIN, NRF_GPIO_PIN_PULLUP); + } +} + +static bool power_off_deferred(uint32_t now) { + static uint32_t absent_since_subticks; + static bool was_absent; + + if (filesystem_present()) { + was_absent = false; + return false; + } + + if (!was_absent) { + was_absent = true; + absent_since_subticks = now; + } + return ((now - absent_since_subticks) & RTC_COUNTER_MASK) < FILESYSTEM_GRACE_SUBTICKS; +} + +void power_off_tick(void) { + uint32_t now = POWER_OFF_RTC->COUNTER; + static uint32_t last_poll_subticks; + if (((now - last_poll_subticks) & RTC_COUNTER_MASK) < POLL_INTERVAL_SUBTICKS) { + return; + } + last_poll_subticks = now; + + if (power_off_deferred(now)) { + return; + } + + ensure_input_buffer_connected(); + + // Reading IN never disturbs the pin, so the gesture still works if user + // code has claimed the button. + bool pressed = nrf_gpio_pin_read(BOARD_POWER_OFF_BUTTON_PIN) == 0; + + // Waking from SYSTEM_OFF happens with the button still held, and the + // bootloader plus start up take far less than the hold time, so a fresh + // boot would otherwise see a hold already in progress and power straight + // back off. Require the button to be seen released once first. + static bool gesture_armed; + static bool was_pressed; + if (!pressed) { + gesture_armed = true; + was_pressed = false; + return; + } + if (!gesture_armed) { + return; + } + + static uint32_t press_started_subticks; + if (!was_pressed) { + was_pressed = true; + press_started_subticks = now; + return; + } + if (((now - press_started_subticks) & RTC_COUNTER_MASK) >= POWER_OFF_HOLD_SUBTICKS) { + power_off(); + } +} + +#endif // BOARD_POWER_OFF_BUTTON_PIN diff --git a/ports/nordic/boards/teenage_engineering_sp1/power_off.h b/ports/nordic/boards/teenage_engineering_sp1/power_off.h new file mode 100644 index 00000000000..d9eef76d611 --- /dev/null +++ b/ports/nordic/boards/teenage_engineering_sp1/power_off.h @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// A supervisor-level power-off gesture, for a board whose only "off" is +// SYSTEM_OFF. +// +// A board opts in by defining BOARD_POWER_OFF_BUTTON_PIN in mpconfigboard.h to +// an active-low, switch-to-ground button that is also the wake source. Holding +// it for BOARD_POWER_OFF_HOLD_SECONDS then powers the board down; pressing it +// again wakes the chip through a reset, which on a board with a bootloader +// means the bootloader runs first. +// +// A board may also define BOARD_POWER_OFF_CONFIRM_LED_PIN to an active-high +// LED, which is flashed once (BOARD_POWER_OFF_CONFIRM_LED_MS, default 200) as +// soon as the hold completes. Without it the gesture is silent, which on a +// screen-less board leaves no way to tell a successful power-off from a hold +// that was a moment too short. +// +// The board does not have to configure that pin. If its input buffer is found +// disconnected the poll reconnects it with a pull-up. A board is still free to +// configure it, and anything already configured is left alone. +// +// The gesture holds off while the supervisor is building the filesystem, so +// that a press during a format cannot leave a half-written FAT behind. The +// press is not lost: it takes effect as soon as the filesystem is mounted. + + +#include "py/mpconfig.h" + +#ifdef BOARD_POWER_OFF_BUTTON_PIN + +// Poll the button and, if it has been held long enough, power off (never +// returns). Called from the board's board_background_task(), i.e. from every +// RUN_BACKGROUND_TASKS. +void power_off_tick(void); + +// Put the board's own hardware into its off state: rails down, resets +// asserted, anything that would drain a battery through SYSTEM_OFF switched +// off. +void board_power_off_prepare(void); + +#endif diff --git a/ports/nordic/boards/teenage_engineering_sp1/wdt.h b/ports/nordic/boards/teenage_engineering_sp1/wdt.h new file mode 100644 index 00000000000..c0107e4e1ca --- /dev/null +++ b/ports/nordic/boards/teenage_engineering_sp1/wdt.h @@ -0,0 +1,40 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Support for the watchdog that this board's bootloader starts, before +// CircuitPython's first instruction, and that cannot be stopped. +// +// This is not the `watchdog` module: that one owns the peripheral and can +// configure it. Here the WDT is already running and its configuration +// registers (CRV, RREN, CONFIG) are locked, so the only thing the application +// can do is reload it. +// +// This is the device's escape hatch. With no reset pin and no way to remove the +// battery, a wedge that stops the main loop has to become a reset, because a +// reset is what runs the bootloader and re-opens the reflashing window. So the +// feed lives in board_background_task(), never in an interrupt handler, and +// mpconfigboard.mk keeps CIRCUITPY_WATCHDOG off so that user code cannot get +// at the peripheral. + +#include + +#include "nrfx.h" + +// Value that a reload request register must be written with, per the nRF52 +// product specification. +#define NRF_WDT_RELOAD_REQUEST_VALUE (0x6E524635UL) + +// Reload the bootloader's watchdog. +// +// Call this from the main loop, never from an interrupt handler. Feeding from +// an ISR would keep a wedged main loop "alive" indefinitely. +static inline void bootloader_wdt_feed(void) { + for (size_t channel = 0; channel < 8; channel++) { + NRF_WDT->RR[channel] = NRF_WDT_RELOAD_REQUEST_VALUE; + } +} diff --git a/ports/nordic/boards/teknikio_bluebird/mpconfigboard.mk b/ports/nordic/boards/teknikio_bluebird/mpconfigboard.mk index 2339a950fed..4a316aea20c 100644 --- a/ports/nordic/boards/teknikio_bluebird/mpconfigboard.mk +++ b/ports/nordic/boards/teknikio_bluebird/mpconfigboard.mk @@ -10,5 +10,6 @@ CIRCUITPY_ANALOGIO = 1 CIRCUITPY_AUDIOCORE = 1 CIRCUITPY_AUDIOPWMIO = 1 CIRCUITPY_DIGITALIO = 1 +CIRCUITPY_LOAD_NATIVE = 0 CIRCUITPY_NEOPIXEL_WRITE = 1 CIRCUITPY_TIME = 1 diff --git a/ports/nordic/common-hal/_bleio/Adapter.c b/ports/nordic/common-hal/_bleio/Adapter.c index 9cf40ae91b3..ea3155e4da7 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.c +++ b/ports/nordic/common-hal/_bleio/Adapter.c @@ -32,11 +32,6 @@ #include "supervisor/usb.h" #endif -#if CIRCUITPY_OS_GETENV -#include "shared-bindings/os/__init__.h" -#include "shared-module/os/__init__.h" -#endif - #define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) #define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) #define BLE_SLAVE_LATENCY 0 @@ -249,6 +244,19 @@ static bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { connection->connection_obj = mp_const_none; connection->pair_status = PAIR_NOT_PAIRED; connection->mtu = 0; + // Only user code connects in the central role, and a peripheral + // connection belongs to whoever started the advertising it answered. + connection->user_owned = connected->role == BLE_GAP_ROLE_CENTRAL || + self->advertising_started_by_user; + // Clear leftover bond state; connection slots are recycled. The + // SoftDevice fills in only the keys the new peer distributes, so a + // stale keyset could mix the previous peer's keys into this peer's + // stored bond, and a stale ediv or pending-save flag could file + // this connection's bond data under the previous peer's key. + connection->ediv = EDIV_INVALID; + connection->do_bond_cccds = false; + connection->do_bond_keys = false; + bonding_clear_keys(&connection->bonding_keys); ble_drv_add_event_handler_entry(&connection->handler_entry, connection_on_ble_evt, connection); self->connection_objs = NULL; @@ -311,31 +319,6 @@ static void get_address(bleio_adapter_obj_t *self, ble_gap_addr_t *address) { check_nrf_error(sd_ble_gap_addr_get(address)); } -char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0, 0}; - -static void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { - // setup the default name - ble_gap_addr_t addr; // local_address - get_address(self, &addr); - mp_int_t len = sizeof(default_ble_name) - 1; - default_ble_name[len - 4] = nibble_to_hex_lower[addr.addr[1] >> 4 & 0xf]; - default_ble_name[len - 3] = nibble_to_hex_lower[addr.addr[1] & 0xf]; - default_ble_name[len - 2] = nibble_to_hex_lower[addr.addr[0] >> 4 & 0xf]; - default_ble_name[len - 1] = nibble_to_hex_lower[addr.addr[0] & 0xf]; - default_ble_name[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings - - #if CIRCUITPY_OS_GETENV - char ble_name[32]; - - os_getenv_err_t result = common_hal_os_getenv_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); - if (result == GETENV_OK) { - common_hal_bleio_adapter_set_name(self, ble_name); - return; - } - #endif - - common_hal_bleio_adapter_set_name(self, (char *)default_ble_name); -} static void bluetooth_adapter_background(void *data) { supervisor_bluetooth_background(); @@ -377,6 +360,9 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable ble_drv_remove_event_handler(connection_on_ble_evt, connection); connection->conn_handle = BLE_CONN_HANDLE_INVALID; } + // The SoftDevice's GATT table is empty after an enable. + bleio_gatts_min_handle = 0xFFFF; + bleio_gatts_max_handle = 0; self->background_callback.fun = bluetooth_adapter_background; self->background_callback.data = self; bleio_adapter_reset_name(self); @@ -409,20 +395,19 @@ bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *s ble_gap_addr_t local_address; get_address(self, &local_address); - bleio_address_obj_t *address = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - - common_hal_bleio_address_construct(address, local_address.addr, local_address.addr_type); - return address; + // Return the address cached on the adapter so this can be called before + // the heap is available (e.g. from bleio_adapter_reset_name). The shared + // common_hal_bleio_address_construct() converts the raw address bytes + // into the Address object. The cached address is refreshed on every call. + common_hal_bleio_address_construct(&self->address, local_address.addr, local_address.addr_type); + self->address.base.type = &bleio_address_type; + return &self->address; } bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { ble_gap_addr_t local_address; - mp_buffer_info_t bufinfo; - if (!mp_get_buffer(address->bytes, &bufinfo, MP_BUFFER_READ)) { - return false; - } local_address.addr_type = address->type; - memcpy(local_address.addr, bufinfo.buf, NUM_BLEIO_ADDRESS_BYTES); + memcpy(local_address.addr, address->bytes, NUM_BLEIO_ADDRESS_BYTES); return sd_ble_gap_addr_set(&local_address) == NRF_SUCCESS; } @@ -611,9 +596,7 @@ static bool connect_on_ble_evt(ble_evt_t *ble_evt, void *info_in) { static void _convert_address(const bleio_address_obj_t *address, ble_gap_addr_t *sd_address) { sd_address->addr_type = address->type; - mp_buffer_info_t address_buf_info; - mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); - memcpy(sd_address->addr, (uint8_t *)address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES); + memcpy(sd_address->addr, address->bytes, NUM_BLEIO_ADDRESS_BYTES); } mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { @@ -740,6 +723,9 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, if (self->current_advertising_data != NULL && self->current_advertising_data == self->advertising_data) { return NRF_ERROR_BUSY; } + // The supervisor calls this internal function directly; user code arrives via + // common_hal_bleio_adapter_start_advertising(), which overrides this to true. + self->advertising_started_by_user = false; // If the current advertising data isn't owned by the adapter then it must be an internal // advertisement that we should stop. @@ -795,7 +781,13 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, // advertising. This prevents a potential race condition where we // fire off a beacon with the same advertising data but a new MAC // address just as we tear down the connection. - .private_addr_cycle_s = timeout + 1, + // + // For unlimited advertising, timeout + 1 would rotate the address + // every second, too fast for a central to resolve it and connect. + // Zero selects the SoftDevice default cycle of 15 minutes + // (BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S). + .private_addr_cycle_s = + timeout == BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED ? 0 : timeout + 1, .p_device_irk = NULL, }; err_code = sd_ble_gap_privacy_set(&privacy); @@ -914,6 +906,7 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool tx_power, directed_to)); self->user_advertising = true; + self->advertising_started_by_user = true; } void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { @@ -999,13 +992,13 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { // Wait up to 125 ms (128 ticks) for disconnect to complete. This should be // greater than most connection intervals. - bool any_connected = false; + bool any_connected; uint64_t start_ticks = supervisor_ticks_ms64(); - while (any_connected && supervisor_ticks_ms64() - start_ticks < 128) { + do { any_connected = false; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; any_connected |= connection->conn_handle != BLE_CONN_HANDLE_INVALID; } - } + } while (any_connected && supervisor_ticks_ms64() - start_ticks < 128); } diff --git a/ports/nordic/common-hal/_bleio/Adapter.h b/ports/nordic/common-hal/_bleio/Adapter.h index 5bc1805d072..6f776261a9c 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.h +++ b/ports/nordic/common-hal/_bleio/Adapter.h @@ -11,6 +11,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" @@ -38,6 +39,15 @@ typedef struct { ble_drv_evt_handler_entry_t advertising_handler_entry; background_callback_t background_callback; bool user_advertising; + // Whether the current (or most recent) advertising was started by user code + // rather than the supervisor. Unlike user_advertising, this is not cleared when + // advertising stops, so the connected-event handler can still read it: the + // advertising event handler runs first and has already stopped the advertising. + bool advertising_started_by_user; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; } bleio_adapter_obj_t; void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); diff --git a/ports/nordic/common-hal/_bleio/Attribute.h b/ports/nordic/common-hal/_bleio/Attribute.h index 5fa6b4d6377..9a58e16bb86 100644 --- a/ports/nordic/common-hal/_bleio/Attribute.h +++ b/ports/nordic/common-hal/_bleio/Attribute.h @@ -6,6 +6,15 @@ #pragma once +#include + +#include "py/obj.h" + #include "shared-module/_bleio/Attribute.h" extern void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode); + +size_t bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); +void bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); +size_t bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); +void bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); diff --git a/ports/nordic/common-hal/_bleio/Characteristic.c b/ports/nordic/common-hal/_bleio/Characteristic.c index 51335be9e59..413c97a3d6e 100644 --- a/ports/nordic/common-hal/_bleio/Characteristic.c +++ b/ports/nordic/common-hal/_bleio/Characteristic.c @@ -138,10 +138,10 @@ size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *sel if (self->handle != BLE_GATT_HANDLE_INVALID) { uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); if (common_hal_bleio_service_get_is_remote(self->service)) { - return common_hal_bleio_gattc_read(self->handle, conn_handle, buf, len); + return bleio_gattc_read(self->handle, conn_handle, buf, len); } else { // conn_handle is ignored for non-system attributes. - return common_hal_bleio_gatts_read(self->handle, conn_handle, buf, len); + return bleio_gatts_read(self->handle, conn_handle, buf, len); } } @@ -159,7 +159,7 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, if (common_hal_bleio_service_get_is_remote(self->service)) { uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); // Last argument is true if write-no-reponse desired. - common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, + bleio_gattc_write(self->handle, conn_handle, bufinfo, (self->props & CHAR_PROP_WRITE_NO_RESPONSE)); } else { // Validate data length for local characteristics only. @@ -172,7 +172,7 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, // Always write the value locally even if no connections are active. // conn_handle is ignored for non-system attributes, so we use BLE_CONN_HANDLE_INVALID. - common_hal_bleio_gatts_write(self->handle, BLE_CONN_HANDLE_INVALID, bufinfo); + bleio_gatts_write(self->handle, BLE_CONN_HANDLE_INVALID, bufinfo); // Check to see if we need to notify or indicate any active connections. for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; @@ -240,6 +240,8 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * }; check_nrf_error(sd_ble_gatts_descriptor_add(self->handle, &desc_attr, &descriptor->handle)); + bleio_gatts_min_handle = MIN(bleio_gatts_min_handle, descriptor->handle); + bleio_gatts_max_handle = MAX(bleio_gatts_max_handle, descriptor->handle); mp_obj_list_append(MP_OBJ_FROM_PTR(self->descriptor_list), MP_OBJ_FROM_PTR(descriptor)); @@ -255,7 +257,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, } const uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); - common_hal_bleio_check_connected(conn_handle); + bleio_check_connected(conn_handle); uint16_t cccd_value = (notify ? BLE_GATT_HVX_NOTIFICATION : 0) | diff --git a/ports/nordic/common-hal/_bleio/Connection.c b/ports/nordic/common-hal/_bleio/Connection.c index f32034582b4..e34aa56c4e2 100644 --- a/ports/nordic/common-hal/_bleio/Connection.c +++ b/ports/nordic/common-hal/_bleio/Connection.c @@ -289,15 +289,23 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { // mode >=1 and/or level >=1 means encryption is set up self->pair_status = PAIR_NOT_PAIRED; } else { - if (bonding_load_cccd_info(self->is_central, self->conn_handle, self->ediv)) { - // Did an sd_ble_gatts_sys_attr_set() with the stored sys_attr values. - // Indicate ATTR table change because we may have reloaded since the peer last - // connected. - sd_ble_gatts_service_changed(self->conn_handle, 0xC, 0xFFFF); - } else { - // No matching bonding found, so use fresh system attributes. + if (!bonding_load_cccd_info(self->is_central, self->conn_handle, self->ediv)) { + // No stored system attributes (CCCD values) found, so use fresh ones. sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); } + if (self->ediv != EDIV_INVALID && bleio_gatts_min_handle <= bleio_gatts_max_handle) { + // The peer reconnected using a stored bond, and the GATT table may + // have changed since it last connected: a reload can add or remove + // user services. Indicate Service Changed so the peer discards its + // cached table. This must not be conditional on the sys-attr load + // above succeeding: a peer that missed the indication would trust a + // stale cache indefinitely, and saved system attributes are the + // less reliable of the two records. The error is ignored if the + // peer hasn't subscribed to indications yet. Both handles must be + // within the application-populated range: the SoftDevice rejects + // 0xFFFF, and also 0xC, which is inside its own GATT service. + (void)sd_ble_gatts_service_changed(self->conn_handle, bleio_gatts_min_handle, bleio_gatts_max_handle); + } self->pair_status = PAIR_PAIRED; } break; @@ -324,6 +332,21 @@ bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { return self->connection->pair_status == PAIR_PAIRED; } +// Authenticated (MITM-protected) pairing - numeric comparison - is implemented on the +// espressif port only. This port can't tell a "Just Works" bond from an authenticated +// one, so report the conservative answer rather than a guarantee it can't make. +bool common_hal_bleio_connection_get_authenticated(bleio_connection_obj_t *self) { + return false; +} + +mp_obj_t common_hal_bleio_connection_get_numeric_comparison(bleio_connection_obj_t *self) { + return mp_const_none; +} + +void common_hal_bleio_connection_confirm_pairing(bleio_connection_obj_t *self, bool accept) { + mp_raise_NotImplementedError(NULL); +} + bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) { if (self->connection == NULL) { return false; diff --git a/ports/nordic/common-hal/_bleio/Connection.h b/ports/nordic/common-hal/_bleio/Connection.h index 110677dc78b..78e2ccd5314 100644 --- a/ports/nordic/common-hal/_bleio/Connection.h +++ b/ports/nordic/common-hal/_bleio/Connection.h @@ -31,6 +31,11 @@ typedef enum { typedef struct { uint16_t conn_handle; bool is_central; + // True if user code initiated or accepted this connection: it connected in the + // central role, or a central answered user code's advertising. User-owned + // connections are disconnected when the VM resets; the BLE workflow connection + // is not user-owned and stays up. + bool user_owned; // Remote services discovered when this peripheral is acting as a client. mp_obj_list_t *remote_service_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must @@ -65,6 +70,7 @@ typedef struct { void bleio_connection_clear(bleio_connection_internal_t *self); bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in); +void bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/ports/nordic/common-hal/_bleio/Descriptor.c b/ports/nordic/common-hal/_bleio/Descriptor.c index 959c8e5c9c0..0d27ca5dc2e 100644 --- a/ports/nordic/common-hal/_bleio/Descriptor.c +++ b/ports/nordic/common-hal/_bleio/Descriptor.c @@ -43,9 +43,9 @@ size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8 if (self->handle != BLE_GATT_HANDLE_INVALID) { uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { - return common_hal_bleio_gattc_read(self->handle, conn_handle, buf, len); + return bleio_gattc_read(self->handle, conn_handle, buf, len); } else { - return common_hal_bleio_gatts_read(self->handle, conn_handle, buf, len); + return bleio_gatts_read(self->handle, conn_handle, buf, len); } } @@ -58,7 +58,7 @@ void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buff uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { // false means WRITE_REQ, not write-no-response - common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, false); + bleio_gattc_write(self->handle, conn_handle, bufinfo, false); } else { // Validate data length for local descriptors only. if (self->fixed_length && bufinfo->len != self->max_length) { @@ -68,7 +68,7 @@ void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buff mp_raise_ValueError(MP_ERROR_TEXT("Value length > max_length")); } - common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); + bleio_gatts_write(self->handle, conn_handle, bufinfo); } } diff --git a/ports/nordic/common-hal/_bleio/PacketBuffer.c b/ports/nordic/common-hal/_bleio/PacketBuffer.c index 6b3e86e3b7a..5be9896b706 100644 --- a/ports/nordic/common-hal/_bleio/PacketBuffer.c +++ b/ports/nordic/common-hal/_bleio/PacketBuffer.c @@ -481,8 +481,14 @@ bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { if (!common_hal_bleio_packet_buffer_deinited(self)) { - ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self); + if (self->client) { + ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self); + } else { + ble_drv_remove_event_handler(packet_buffer_on_ble_server_evt, self); + } ringbuf_deinit(&self->ringbuf); + // Mark as deinited, so common_hal_bleio_packet_buffer_deinited() reports it. + self->characteristic = NULL; } } diff --git a/ports/nordic/common-hal/_bleio/Service.c b/ports/nordic/common-hal/_bleio/Service.c index 1bd75f8a481..c187c54178d 100644 --- a/ports/nordic/common-hal/_bleio/Service.c +++ b/ports/nordic/common-hal/_bleio/Service.c @@ -46,6 +46,8 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu uint32_t result = sd_ble_gatts_service_add(service_type, &nordic_uuid, &self->handle); // Do a service changed indication to all connected peers. if (result == NRF_SUCCESS) { + bleio_gatts_min_handle = MIN(bleio_gatts_min_handle, self->handle); + bleio_gatts_max_handle = MAX(bleio_gatts_max_handle, self->handle); _indicate_service_change(self->handle, self->handle); } @@ -169,6 +171,8 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, _expand_range(char_handles.cccd_handle, &start, &end); _expand_range(char_handles.sccd_handle, &start, &end); _expand_range(char_handles.user_desc_handle, &start, &end); + bleio_gatts_min_handle = MIN(bleio_gatts_min_handle, start); + bleio_gatts_max_handle = MAX(bleio_gatts_max_handle, end); _indicate_service_change(start, end); #if CIRCUITPY_VERBOSE_BLE diff --git a/ports/nordic/common-hal/_bleio/__init__.c b/ports/nordic/common-hal/_bleio/__init__.c index 454937dcd35..554bbf200bc 100644 --- a/ports/nordic/common-hal/_bleio/__init__.c +++ b/ports/nordic/common-hal/_bleio/__init__.c @@ -70,13 +70,16 @@ void check_sec_status(uint8_t sec_status) { switch (sec_status) { case BLE_GAP_SEC_STATUS_UNSPECIFIED: - mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored.")); + mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. The pairing request on the other device may have been declined or ignored.")); return; default: mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unknown security error: 0x%04x"), sec_status); } } +uint16_t bleio_gatts_min_handle = 0xFFFF; +uint16_t bleio_gatts_max_handle; + void common_hal_bleio_init(void) { } @@ -85,6 +88,30 @@ void bleio_user_reset(void) { // Stop any user scanning or advertising. common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); + + // Disconnect the connections that user code initiated or accepted with its + // own advertising. The BLE workflow connection is not user-owned and stays up. + // + // Clear each connection's pointers into the VM heap first: the heap is about + // to go away, and a disconnect completes asynchronously, possibly after it + // has. The disconnect event handler dereferences connection_obj unless it is + // mp_const_none. + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + connection->connection_obj = mp_const_none; + connection->remote_service_list = NULL; + if (connection->conn_handle != BLE_CONN_HANDLE_INVALID && connection->user_owned) { + common_hal_bleio_connection_disconnect(connection); + } + } + + // Clear the adapter's remaining pointers into the VM heap. The full stack + // reset in bleio_reset() used to do this implicitly, but it no longer always + // runs. The adapter struct is a GC root, so a pointer left over from this + // heap would be scanned as a live object in the next VM's heap. + common_hal_bleio_adapter_obj.connection_objs = NULL; + common_hal_bleio_adapter_obj.advertising_data = NULL; + common_hal_bleio_adapter_obj.scan_response_data = NULL; } ble_drv_remove_heap_handlers(); @@ -101,6 +128,16 @@ void bleio_reset(void) { return; } + // The SoftDevice cannot remove individual services from its GATT table: the + // disable/enable cycle below is the only way to clear them, and it drops every + // connection, the BLE workflow's included. So run it only when user code created + // services. All other user BLE state has already been torn down individually by + // bleio_user_reset(). + if (!bleio_get_user_services_created()) { + return; + } + bleio_clear_user_services_created(); + supervisor_stop_bluetooth(); bleio_adapter_reset(&common_hal_bleio_adapter_obj); common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); @@ -112,14 +149,14 @@ void bleio_reset(void) { // It currently only has properties and no state. Inited by bleio_reset bleio_adapter_obj_t common_hal_bleio_adapter_obj; -void common_hal_bleio_check_connected(uint16_t conn_handle) { +void bleio_check_connected(uint16_t conn_handle) { if (conn_handle == BLE_CONN_HANDLE_INVALID) { mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected")); } } // GATTS read of a Characteristic or Descriptor. -size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { +size_t bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { // conn_handle is ignored unless this is a system attribute. // If we're not connected, that's OK, because we can still read and write the local value. @@ -133,7 +170,7 @@ size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_ return gatts_value.len; } -void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { +void bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { // conn_handle is ignored unless this is a system attribute. // If we're not connected, that's OK, because we can still read and write the local value. @@ -188,8 +225,8 @@ static bool _on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { return true; } -size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { - common_hal_bleio_check_connected(conn_handle); +size_t bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { + bleio_check_connected(conn_handle); read_info_t read_info; read_info.buf = buf; @@ -213,15 +250,15 @@ size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_ RUN_BACKGROUND_TASKS; } // Test if we were disconnected while reading - common_hal_bleio_check_connected(read_info.conn_handle); + bleio_check_connected(read_info.conn_handle); ble_drv_remove_event_handler(_on_gattc_read_rsp_evt, &read_info); check_gatt_status(read_info.status); return read_info.final_len; } -void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { - common_hal_bleio_check_connected(conn_handle); +void bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { + bleio_check_connected(conn_handle); ble_gattc_write_params_t write_params = { .write_op = write_no_response ? BLE_GATT_OP_WRITE_CMD: BLE_GATT_OP_WRITE_REQ, diff --git a/ports/nordic/common-hal/_bleio/__init__.h b/ports/nordic/common-hal/_bleio/__init__.h index caf287f9204..eecbc32275f 100644 --- a/ports/nordic/common-hal/_bleio/__init__.h +++ b/ports/nordic/common-hal/_bleio/__init__.h @@ -8,6 +8,12 @@ void bleio_background(void); +// Remember the range of attribute handles the application has populated in the +// SoftDevice's GATT table. Required to call sd_ble_gatts_service_changed() +// with valid arguments: it fails if the args are outside that range. +extern uint16_t bleio_gatts_min_handle; +extern uint16_t bleio_gatts_max_handle; + typedef struct { ble_gap_enc_key_t own_enc; ble_gap_enc_key_t peer_enc; diff --git a/ports/nordic/common-hal/alarm/__init__.c b/ports/nordic/common-hal/alarm/__init__.c index 9753b0321fd..5db3e269994 100644 --- a/ports/nordic/common-hal/alarm/__init__.c +++ b/ports/nordic/common-hal/alarm/__init__.c @@ -232,15 +232,12 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj } void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { - if (n_dios > 0) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); - } _setup_sleep_alarms(true, n_alarms, alarms); } #define PRESCALER_VALUE_IN_DEEP_SLEEP (1024) -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_time_timealarm_prepare_for_deep_sleep(); diff --git a/ports/nordic/common-hal/alarm/pin/PinAlarm.c b/ports/nordic/common-hal/alarm/pin/PinAlarm.c index f43eb1ed251..3359faa74e0 100644 --- a/ports/nordic/common-hal/alarm/pin/PinAlarm.c +++ b/ports/nordic/common-hal/alarm/pin/PinAlarm.c @@ -17,7 +17,9 @@ #include "nrfx.h" #include "nrf_gpio.h" #include "nrfx_gpiote.h" +#ifdef BLUETOOTH_SD #include "nrf_soc.h" +#endif #include #define WPIN_UNUSED 0xFF diff --git a/ports/nordic/common-hal/analogio/AnalogIn.c b/ports/nordic/common-hal/analogio/AnalogIn.c index e48c9dd2e28..1459c67c08c 100644 --- a/ports/nordic/common-hal/analogio/AnalogIn.c +++ b/ports/nordic/common-hal/analogio/AnalogIn.c @@ -23,6 +23,9 @@ void analogin_init(void) { while (nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_CALIBRATEDONE) == 0) { } nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CALIBRATEDONE); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_DONE); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_RESULTDONE); nrf_saadc_disable(NRF_SAADC); } @@ -56,7 +59,8 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { // Something else might have used the ADC in a different way, // so we completely re-initialize it. - nrf_saadc_value_t value = 0; + static volatile nrf_saadc_value_t value __attribute__((aligned(4))); + value = 0; const nrf_saadc_channel_config_t config = { .resistor_p = NRF_SAADC_RESISTOR_DISABLED, @@ -78,7 +82,12 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { nrf_saadc_channel_init(NRF_SAADC, CHANNEL_NO, &config); nrf_saadc_channel_input_set(NRF_SAADC, CHANNEL_NO, self->pin->adc_channel, self->pin->adc_channel); - nrf_saadc_buffer_init(NRF_SAADC, &value, 1); + nrf_saadc_buffer_init(NRF_SAADC, (nrf_saadc_value_t *)&value, 1); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_STARTED); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_DONE); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_RESULTDONE); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_STOPPED); nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START); while (nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_STARTED) == 0) { @@ -100,23 +109,20 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { nrf_saadc_disable(NRF_SAADC); - // Adding the "asm volatile" memory fence here or anywhere after the declaration of `value` - // fixes an issue with gcc13 which causes `value` to always be zero. - // Compiling with gcc10 or gcc12 is fine. - // It can also be fixed by declaring `value` to be static. - // I think I'd like to declare `value` as volatile, but that causes type errors. - asm volatile ("" : : : "memory"); // Disconnect ADC from pin. nrf_saadc_channel_input_set(NRF_SAADC, CHANNEL_NO, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED); + // Read the DMA'd result exactly once. + int32_t result = value; + // value is signed and might be (slightly) < 0, even on single-ended conversions, so force to 0. - if (value < 0) { - value = 0; + if (result < 0) { + result = 0; } // Stretch 14-bit ADC reading to 16-bit range - return (value << 2) | (value >> 12); + return (result << 2) | (result >> 12); } float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) { diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.c b/ports/nordic/common-hal/audiobusio/I2SOut.c index 249b4f9d116..46b9279cbcc 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.c +++ b/ports/nordic/common-hal/audiobusio/I2SOut.c @@ -16,6 +16,8 @@ #include "py/obj.h" #include "py/runtime.h" +#include "nrf_gpio.h" + static audiobusio_i2sout_obj_t *instance; struct { int16_t l, r; @@ -107,23 +109,30 @@ static void i2s_buffer_fill(audiobusio_i2sout_obj_t *self) { while (!self->paused && !self->stopping && bytesleft) { if (self->sample_data == self->sample_end) { + if (self->last_buffer) { + // The final buffer has been fully output; stop now instead of + // fetching another (which for a single-buffer sample would just + // replay it). + self->stopping = true; + break; + } uint32_t sample_buffer_length; audioio_get_buffer_result_t get_buffer_result = audiosample_get_buffer(self->sample, false, 0, &self->sample_data, &sample_buffer_length); self->sample_end = self->sample_data + sample_buffer_length; + if (get_buffer_result == GET_BUFFER_ERROR || sample_buffer_length == 0) { + self->stopping = true; + break; + } if (get_buffer_result == GET_BUFFER_DONE) { if (self->loop) { audiosample_reset_buffer(self->sample, false, 0); } else { - self->stopping = true; - break; + // Output this final buffer before stopping; don't fetch again. + self->last_buffer = true; } } - if (get_buffer_result == GET_BUFFER_ERROR || sample_buffer_length == 0) { - self->stopping = true; - break; - } } uint16_t bytecount = MIN(bytesleft, (size_t)(self->sample_end - self->sample_data)); if (self->samples_signed) { @@ -182,7 +191,8 @@ static void i2s_buffer_fill(audiobusio_i2sout_obj_t *self) { void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool external_clock) { if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } @@ -195,14 +205,23 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, claim_pin(word_select); claim_pin(data); + self->external_clock = external_clock; + NRF_I2S->PSEL.SCK = self->bit_clock_pin_number = bit_clock->number; NRF_I2S->PSEL.LRCK = self->word_select_pin_number = word_select->number; NRF_I2S->PSEL.SDOUT = self->data_pin_number = data->number; - NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master; + if (external_clock) { + nrf_gpio_cfg_input(bit_clock->number, NRF_GPIO_PIN_NOPULL); + nrf_gpio_cfg_input(word_select->number, NRF_GPIO_PIN_NOPULL); + } + + NRF_I2S->CONFIG.MODE = external_clock ? I2S_CONFIG_MODE_MODE_Slave + : I2S_CONFIG_MODE_MODE_Master; NRF_I2S->CONFIG.RXEN = I2S_CONFIG_RXEN_RXEN_Disabled; NRF_I2S->CONFIG.TXEN = I2S_CONFIG_TXEN_TXEN_Enabled; - NRF_I2S->CONFIG.MCKEN = I2S_CONFIG_MCKEN_MCKEN_Enabled; + NRF_I2S->CONFIG.MCKEN = external_clock ? I2S_CONFIG_MCKEN_MCKEN_Disabled + : I2S_CONFIG_MCKEN_MCKEN_Enabled; NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit; NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left; @@ -222,6 +241,10 @@ void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self) { } NRF_I2S->TASKS_STOP = 1; NRF_I2S->ENABLE = I2S_ENABLE_ENABLE_Disabled; + if (self->external_clock) { + nrf_gpio_cfg_default(self->bit_clock_pin_number); + nrf_gpio_cfg_default(self->word_select_pin_number); + } reset_pin_number(self->bit_clock_pin_number); self->bit_clock_pin_number = NO_PIN; reset_pin_number(self->word_select_pin_number); @@ -238,6 +261,8 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, common_hal_audiobusio_i2sout_stop(self); } + audiosample_check(sample); + self->sample = sample; self->loop = loop; uint32_t sample_rate = audiosample_get_sample_rate(sample); @@ -259,7 +284,11 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, ? I2S_CONFIG_CHANNELS_CHANNELS_Left : I2S_CONFIG_CHANNELS_CHANNELS_Stereo; - choose_i2s_clocking(self, sample_rate); + if (self->external_clock) { + self->sample_rate = sample_rate; + } else { + choose_i2s_clocking(self, sample_rate); + } /* Allocate buffers based on a maximum duration * This duration was chosen empirically based on what would * cause os.listdir('') to cause stuttering. It seems like a @@ -280,6 +309,7 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, self->playing = true; self->paused = false; self->stopping = false; + self->last_buffer = false; i2s_buffer_fill(self); NRF_I2S->RXTXD.MAXCNT = self->buffer_length / 4; diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.h b/ports/nordic/common-hal/audiobusio/I2SOut.h index 7cb62ae3d2b..27e077c0649 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.h +++ b/ports/nordic/common-hal/audiobusio/I2SOut.h @@ -28,8 +28,10 @@ typedef struct { uint8_t bytes_per_sample; bool left_justified : 1; + bool external_clock : 1; bool playing : 1; bool stopping : 1; + bool last_buffer : 1; bool paused : 1; bool loop : 1; bool samples_signed : 1; diff --git a/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c b/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c index b48a03e09c6..75df88e4416 100644 --- a/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c @@ -236,6 +236,9 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, if (common_hal_audiopwmio_pwmaudioout_get_playing(self)) { common_hal_audiopwmio_pwmaudioout_stop(self); } + + audiosample_check(sample); + self->sample = sample; self->loop = loop; diff --git a/ports/nordic/common-hal/busio/I2C.c b/ports/nordic/common-hal/busio/I2C.c index 3558fad165b..999737f632b 100644 --- a/ports/nordic/common-hal/busio/I2C.c +++ b/ports/nordic/common-hal/busio/I2C.c @@ -47,18 +47,18 @@ void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { never_reset_pin_number(self->sda_pin_number); } -static uint8_t twi_error_to_mp(const nrfx_err_t err) { +static mp_negative_errno_t twi_error_to_mp(const nrfx_err_t err) { switch (err) { case NRFX_ERROR_DRV_TWI_ERR_ANACK: - return MP_ENODEV; + return -MP_ENODEV; case NRFX_ERROR_BUSY: - return MP_EBUSY; + return -MP_EBUSY; case NRFX_ERROR_INVALID_ADDR: case NRFX_ERROR_DRV_TWI_ERR_DNACK: case NRFX_ERROR_DRV_TWI_ERR_OVERRUN: - return MP_EIO; + return -MP_EIO; case NRFX_ERROR_TIMEOUT: - return MP_ETIMEDOUT; + return -MP_ETIMEDOUT; default: break; } @@ -258,9 +258,9 @@ static nrfx_err_t _twim_xfer_with_timeout(busio_i2c_obj_t *self, nrfx_twim_xfer_ } } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool stopBit) { +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool stopBit) { if (len == 0) { - return common_hal_busio_i2c_probe(self, addr) ? 0 : MP_ENODEV; + return common_hal_busio_i2c_probe(self, addr) ? 0 : -MP_ENODEV; } nrfx_err_t err = NRFX_SUCCESS; @@ -286,11 +286,11 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, return twi_error_to_mp(err); } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { if (len == 0) { return 0; } @@ -317,9 +317,9 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t return twi_error_to_mp(err); } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/nordic/common-hal/busio/SPI.c b/ports/nordic/common-hal/busio/SPI.c index 8af4c5f4e83..5e0f2b242dc 100644 --- a/ports/nordic/common-hal/busio/SPI.c +++ b/ports/nordic/common-hal/busio/SPI.c @@ -14,6 +14,10 @@ #include "nrfx_spim.h" #include "nrf_gpio.h" +#if CIRCUITPY_EMMCIO +#include "common-hal/emmcio/EMMC.h" +#endif + #ifndef NRFX_SPIM3_ENABLED #define NRFX_SPIM3_ENABLED (0) #endif @@ -59,26 +63,13 @@ static const spim_peripheral_t spim_peripherals[] = { #endif }; -static bool never_reset[MP_ARRAY_SIZE(spim_peripherals)]; - // Separate RAM area for SPIM3 transmit buffer to avoid SPIM3 hardware errata. // https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52840_Rev2%2FERR%2FnRF52840%2FRev2%2Flatest%2Fanomaly_840_198.html static uint8_t *spim3_transmit_buffer = (uint8_t *)SPIM3_BUFFER_RAM_START_ADDR; -void spi_reset(void) { - for (size_t i = 0; i < MP_ARRAY_SIZE(spim_peripherals); i++) { - if (never_reset[i]) { - continue; - } - nrfx_spim_uninit(&spim_peripherals[i].spim); - } -} - void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { for (size_t i = 0; i < MP_ARRAY_SIZE(spim_peripherals); i++) { if (self->spim_peripheral == &spim_peripherals[i]) { - never_reset[i] = true; - never_reset_pin_number(self->clock_pin_number); never_reset_pin_number(self->MOSI_pin_number); never_reset_pin_number(self->MISO_pin_number); @@ -125,6 +116,9 @@ static nrf_spim_frequency_t baudrate_to_spim_frequency(const uint32_t baudrate) void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + if (half_duplex) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); } @@ -132,6 +126,11 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * // Find a free instance, with most desirable (highest freq and not shared) allocated first. self->spim_peripheral = NULL; for (size_t i = 0; i < MP_ARRAY_SIZE(spim_peripherals); i++) { + #if CIRCUITPY_EMMCIO + if (spim_peripherals[i].spim.p_reg == NRF_SPIM3 && emmcio_spim3_in_use()) { + continue; + } + #endif if ((spim_peripherals[i].spim.p_reg->ENABLE & SPIM_ENABLE_ENABLE_Msk) == 0) { self->spim_peripheral = &spim_peripherals[i]; break; @@ -178,6 +177,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock_pin_number == NO_PIN; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock_pin_number = NO_PIN; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -188,6 +191,8 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { reset_pin_number(self->clock_pin_number); reset_pin_number(self->MOSI_pin_number); reset_pin_number(self->MISO_pin_number); + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { diff --git a/ports/nordic/common-hal/busio/SPI.h b/ports/nordic/common-hal/busio/SPI.h index 7bfddd9625d..3260c5c27de 100644 --- a/ports/nordic/common-hal/busio/SPI.h +++ b/ports/nordic/common-hal/busio/SPI.h @@ -23,5 +23,3 @@ typedef struct { uint8_t MOSI_pin_number; uint8_t MISO_pin_number; } busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/nordic/common-hal/busio/UART.c b/ports/nordic/common-hal/busio/UART.c index 6939486a5e6..7a4219a9728 100644 --- a/ports/nordic/common-hal/busio/UART.c +++ b/ports/nordic/common-hal/busio/UART.c @@ -182,7 +182,8 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, .interrupt_priority = NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY, .hal_cfg = { .hwfc = hwfc ? NRF_UARTE_HWFC_ENABLED : NRF_UARTE_HWFC_DISABLED, - .parity = (parity == BUSIO_UART_PARITY_NONE) ? NRF_UARTE_PARITY_EXCLUDED : NRF_UARTE_PARITY_INCLUDED + .parity = (parity == BUSIO_UART_PARITY_NONE) ? NRF_UARTE_PARITY_EXCLUDED : NRF_UARTE_PARITY_INCLUDED, + .stop = (stop == 2 ? NRF_UARTE_STOP_TWO : NRF_UARTE_STOP_ONE), } }; diff --git a/ports/nordic/common-hal/emmcio/EMMC.c b/ports/nordic/common-hal/emmcio/EMMC.c new file mode 100644 index 00000000000..703d9bcb6fc --- /dev/null +++ b/ports/nordic/common-hal/emmcio/EMMC.c @@ -0,0 +1,1014 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// ============================================================================ +// eMMC flash driver (1-bit MMC protocol over the nRF52840) +// ============================================================================ +// Two layers: +// +// * COMMAND / control phases (init, CMD17/18 headers, busy polling) are +// bit-banged on GPIO. They are short and timing-insensitive. +// +// * The 512-byte DATA payloads ride SPIM3 + EasyDMA at 16 MHz. eMMC DAT0 at +// default speed is SPI-mode-0 compatible: the host launches data while +// CLK is low, the card samples (and launches) on the rising edge, MSB +// first. The start-bit hunt is bit-banged, then the payload + CRC16 is +// exactly byte-aligned for one RX DMA; on ENABLE=0 the pins fall back to +// their GPIO latches. +// +// INTEGRITY: every block read is verified against the card's CRC16 and the +// caller retries on a mismatch. +// +// ============================================================================ + +#include "common-hal/emmcio/EMMC.h" +#include "common-hal/emmcio/emmc_hw.h" + +#include + +#include "extmod/vfs.h" // MP_BLOCKDEV_IOCTL_* +#include "lib/sdmmc/include/sdmmc_defs.h" // MMC_* command numbers +#include "py/mphal.h" +#include "py/runtime.h" // RUN_BACKGROUND_TASKS +#include "shared-bindings/microcontroller/__init__.h" +#include "common-hal/microcontroller/Pin.h" +#include "peripherals/nrf/nrf52840/pins.h" +#include "shared-module/emmcio/__init__.h" + +#define CMD_SAFE_HALF_US 1u + +// Command-phase half-period: starts slow, switched to 0 (full-speed) after init. +static uint32_t s_cmd_half_us = CMD_SAFE_HALF_US; + +static volatile uint32_t g_emmc_clk_half_us = CMD_SAFE_HALF_US; + + +static bool s_ready; +static uint32_t s_rca; +static uint32_t s_block_count; // from EXT_CSD SEC_COUNT; 0 = not read yet +static uint8_t s_device_type; // from EXT_CSD[196]; 0 = not read yet + +// One 512-byte block + its CRC16, byte-aligned, for the RX DMA. +static uint8_t s_dma_rx[EMMC_BLOCK_SIZE + 2]; + +// ---- bounded-wait helpers -------------------------------------------------- +// The 32768 Hz counter is 24-bit, so every elapsed calculation masks. +#define US_TO_TICKS(us) ((uint32_t)(((uint64_t)(us) * EMMC_TICKS_HZ + 999999u) / 1000000u)) + +static inline uint32_t ticks_since(uint32_t t0) { + return ticks_since_raw(t0); +} + +static inline void half_delay(uint32_t us) { + if (us) { + common_hal_mcu_delay_us(us); + } +} + +static bool s_deadline_armed; +static uint32_t s_deadline_t0; +static uint32_t s_deadline_lim; + +void common_hal_emmcio_emmc_set_deadline(uint32_t timeout_us) { + s_deadline_t0 = EMMC_TICKS(); + s_deadline_lim = US_TO_TICKS(timeout_us); + s_deadline_armed = true; +} + +void common_hal_emmcio_emmc_clear_deadline(void) { + s_deadline_armed = false; +} + +static bool emmc_deadline_expired(void) { + return s_deadline_armed && ticks_since(s_deadline_t0) >= s_deadline_lim; +} + +static inline void emmc_yield(void) { + RUN_BACKGROUND_TASKS; +} + +// Safe clock pulse for command/CRC phases. +static inline void clk_pulse(void) { + CLK_HIGH(); + half_delay(s_cmd_half_us); + CLK_LOW(); + half_delay(s_cmd_half_us); +} + +static void cmd_send_bit(uint8_t bit) { + // caller (send_command) sets CMD_OUT() once. + if (bit) { + CMD_HIGH(); + } else { + CMD_LOW(); + } + clk_pulse(); +} + +// SAMPLE POINT: read the line at the END of the low phase, i.e. before this +// bit's clock pulse, not in the middle of it. That is the one point in the +// cycle where both of the card's timing modes hold valid data. +// +// * backward-compatible timing: the card launches on the FALLING edge and +// holds the bit until the next one, so the whole low phase is valid. +// tOSU(min) = tWL(min) - tODLY, data good from ~8 ns after the edge. +// We read a full low phase later. +// * high-speed timing: the card launches on the RISING edge (tODLY, 13.7 ns +// max, referenced to it) and holds until the next rising edge. +// +static uint8_t cmd_recv_bit(void) { + // caller sets CMD_IN() once before the response read + uint8_t b = (uint8_t)READ_CMD(); + clk_pulse(); + return b; +} + +static uint8_t crc7(const uint8_t *data, uint8_t len) { + uint8_t crc = 0; + for (uint8_t i = 0; i < len; i++) { + uint8_t v = data[i]; + for (int b = 7; b >= 0; b--) { + crc <<= 1; + if (((v >> b) & 1) ^ ((crc >> 7) & 1)) { + crc ^= 0x09; + } + crc &= 0x7F; + } + } + return (crc << 1) | 1; +} + +// Table-driven CRC16-CCITT +static uint16_t s_crc16_tab[256]; +static void crc16_tab_init(void) { + for (uint32_t i = 0; i < 256; i++) { + uint16_t crc = (uint16_t)(i << 8); + for (int b = 0; b < 8; b++) { + crc = (crc & 0x8000) ? (uint16_t)((crc << 1) ^ 0x1021) : (uint16_t)(crc << 1); + } + s_crc16_tab[i] = crc; + } +} + +// The port builds at -Os, so this is an opt-up. crc16 is pure computation, +// the level can only change its speed, never its value. +__attribute__((optimize("O2"))) +static uint16_t crc16(const uint8_t *data, uint32_t len) { + uint16_t crc = 0; + for (uint32_t i = 0; i < len; i++) { + crc = (uint16_t)((crc << 8) ^ s_crc16_tab[(crc >> 8) ^ data[i]]); + } + return crc; +} + +static bool send_command(uint8_t cmd_index, uint32_t arg, uint8_t *r1_out) { + uint8_t frame[6]; + frame[0] = 0x40 | (cmd_index & 0x3F); + frame[1] = (uint8_t)(arg >> 24); + frame[2] = (uint8_t)(arg >> 16); + frame[3] = (uint8_t)(arg >> 8); + frame[4] = (uint8_t)(arg); + frame[5] = crc7(frame, 5); + + // PRE-COMMAND GAP on an UNDRIVEN line + CMD_IN(); + for (int i = 0; i < 24; i++) { + clk_pulse(); + } + CMD_OUT(); + cmd_send_bit(0); + cmd_send_bit(1); + for (int b = 5; b >= 0; b--) { + cmd_send_bit((frame[0] >> b) & 1); + } + for (int i = 1; i <= 4; i++) { + for (int b = 7; b >= 0; b--) { + cmd_send_bit((frame[i] >> b) & 1); + } + } + for (int b = 7; b >= 1; b--) { + cmd_send_bit((frame[5] >> b) & 1); + } + cmd_send_bit(1); + + CMD_IN(); + bool responded = false; + for (int t = 0; t < 200; t++) { + clk_pulse(); + if (!READ_CMD()) { + responded = true; + break; + } + } + if (!responded) { + return false; + } + + if (!r1_out) { + return true; + } + + uint8_t resp[6] = {0}; + for (int i = 0; i < 38; i++) { + uint8_t bit = cmd_recv_bit(); + resp[i / 8] |= (bit << (7 - (i % 8))); + } + memcpy(r1_out, resp, 6); + + // Leave CMD as an INPUT (pulled up) + return true; +} + +// Bit-banged MMC commands intermittently miss the response on the first try +// (settling after the previous command); retry until the card answers. +static bool send_command_retry(uint8_t cmd, uint32_t arg, uint8_t *r1_out, int tries) { + for (int t = 0; t < tries; t++) { + if (emmc_deadline_expired()) { + return false; + } + if (send_command(cmd, arg, r1_out)) { + return true; + } + if (t == 0) { + // First miss = the card still settling after the previous burst: a + // handful of idle clocks is all it needs. + for (int c = 0; c < 16; c++) { + clk_pulse(); + } + } else { + mp_hal_delay_ms(2); + } + } + return false; +} + +// DATA read: per-bit CLK toggle uses the configurable (possibly 0) half-period. +// -O2 opts up from the port's -Os default and is needed: at -Os the GPIO +// and delay helpers stop being inlined and become calls inside the per-bit +// loop, and throw off the timing +__attribute__((optimize("O2"))) +static bool read_data_block(uint8_t *buf) { + const uint32_t hd = g_emmc_clk_half_us; + const uint32_t clk_bit = emmc_pinout.clk_bit; + const uint32_t dat_bit = emmc_pinout.dat_bit; + + DAT0_IN(); + // START-BIT HUNT + { + uint32_t t0 = EMMC_TICKS(); + const uint32_t lim = US_TO_TICKS(80000u); // 80 ms bound + const uint32_t yield_at = US_TO_TICKS(500u); + bool got_start = false; + for (;;) { + // This hunt samples in the HIGH phase and stays there in both + // timing modes + for (int burst = 0; burst < 64 && !got_start; burst++) { + RCLK_HIGH(clk_bit); + half_delay(hd); + EDGE_SETTLE(); + if (!RDAT_GET(dat_bit)) { + got_start = true; // leave with RCLK HIGH (as before) + break; + } + RCLK_LOW(clk_bit); + half_delay(hd); + } + uint32_t el = ticks_since(t0); + if (got_start) { + break; + } + if (el >= lim || emmc_deadline_expired()) { + return false; + } + if (el >= yield_at) { + emmc_yield(); + } + } + } + RCLK_LOW(clk_bit); + half_delay(hd); + + // The start bit was just consumed by the bit-bang hunt above, so the + // remaining 512 data bytes + CRC16 are exactly byte-aligned. + emmc_spim_xfer(NULL, 0, s_dma_rx, sizeof(s_dma_rx)); + memcpy(buf, s_dma_rx, EMMC_BLOCK_SIZE); + uint16_t card_crc = (uint16_t)(((uint16_t)s_dma_rx[EMMC_BLOCK_SIZE] << 8) | + s_dma_rx[EMMC_BLOCK_SIZE + 1]); + RCLK_HIGH(clk_bit); + half_delay(hd); + RCLK_LOW(clk_bit); + half_delay(hd); // end bit + bool crc_ok = crc16(buf, EMMC_BLOCK_SIZE) == card_crc; + DAT0_OUT(); + RDAT_HIGH(dat_bit); + return crc_ok; // a mismatch: caller retries +} + +bool common_hal_emmcio_emmc_read_status(uint8_t *r1_out) { + return send_command_retry(13, s_rca, r1_out, 8); +} + +// Clock out an R2 response and reassemble the CID. R2 framing: start(0) + +// transmission(0) + 6 reserved ones + CID[127:1] + end(1) = 136 bits. +static void drain_r2_cid(uint8_t *cid_out) { + uint8_t bits[136]; + for (int i = 0; i < 136; i++) { + bits[i] = cmd_recv_bit(); + } + memset(cid_out, 0, 16); + for (int i = 0; i < 128; i++) { + // bits[0] start, bits[1] transmission, bits[2..7] six reserved ones, + // bits[8..134] CID[127:1], bits[135] end bit + cid_out[i / 8] |= (uint8_t)(bits[8 + i] << (7 - (i % 8))); + } +} + +#define EMMC_POWER_OFF_MS 50u + +static void emmc_power_cycle(void) { + emmc_spim_deinit(); // SPIM3 must not drive DAT0 either + emmc_pins_init(); + + RST_ASSERT(); + CLK_LOW(); + CMD_LOW(); + DAT0_OUT(); + DAT0_LOW(); + VCCQ_OFF(); + mp_hal_delay_ms(EMMC_POWER_OFF_MS); +} + +static bool emmc_init(emmcio_emmc_obj_t *self) { + s_ready = false; + s_block_count = 0; + s_device_type = 0; + g_emmc_clk_half_us = CMD_SAFE_HALF_US; + s_cmd_half_us = CMD_SAFE_HALF_US; + + self->cmd0_sent = false; + self->cmd1_retries = -1; + self->cmd2_resp = false; + self->cmd3_resp = false; + self->cmd7_resp = false; + self->cmd16_resp = false; + memset(self->cid, 0, sizeof(self->cid)); + self->hs_switch_error = false; + self->hs_active = false; + self->hs_stage = 0; + + emmc_power_cycle(); + + emmc_spim_init(); // hardware-clocked data path, at M16 + crc16_tab_init(); + + CLK_LOW(); + CMD_HIGH(); + DAT0_HIGH(); + + VCCQ_ON(); + mp_hal_delay_ms(10); + + RST_ASSERT(); + mp_hal_delay_ms(1); + RST_RELEASE(); + mp_hal_delay_ms(2); + + CMD_HIGH(); + for (int i = 0; i < 80; i++) { // 74+ clocks before the first command + clk_pulse(); + } + + send_command(0, 0x00000000, NULL); // CMD0 GO_IDLE (no response expected) + self->cmd0_sent = true; + mp_hal_delay_ms(1); + + // CMD1 SEND_OP_COND, arg 0x40FF8000: HCS=1 + uint8_t r3[6] = {0}; + for (int retry = 0; retry < 1000; retry++) { + bool ok = send_command(1, 0x40FF8000, r3); + emmc_yield(); + mp_hal_delay_ms(1); + if (ok && (r3[1] & 0x80)) { // response seen AND busy bit set = ready + self->cmd1_retries = retry; + break; + } + if (emmc_deadline_expired()) { + break; + } + } + if (self->cmd1_retries < 0) { // card never responded ready -> stop + return false; + } + + for (int t = 0; t < 8; t++) { + self->cmd2_resp = send_command(2, 0, NULL); + if (self->cmd2_resp) { + drain_r2_cid(self->cid); + break; + } + mp_hal_delay_ms(2); + } + mp_hal_delay_ms(1); + + uint8_t r6[6] = {0}; + s_rca = 0x0001u << 16; + self->cmd3_resp = send_command_retry(3, s_rca, r6, 8); // SET_RELATIVE_ADDR + mp_hal_delay_ms(1); + + uint8_t r1[6] = {0}; + self->cmd7_resp = send_command_retry(7, s_rca, r1, 8); // SELECT_CARD + mp_hal_delay_ms(1); + self->cmd16_resp = send_command_retry(16, EMMC_BLOCK_SIZE, r1, 8); // SET_BLOCKLEN + mp_hal_delay_ms(1); + + // strict: ready only if the card actually selected AND accepted block length + s_ready = self->cmd7_resp && self->cmd16_resp; + if (s_ready) { + s_cmd_half_us = 0u; // identification done: full-speed commands + g_emmc_clk_half_us = 0u; + } + return s_ready; +} + +uint32_t common_hal_emmcio_emmc_get_block_count(emmcio_emmc_obj_t *self) { + (void)self; + return s_block_count; +} + +// The block-device ioctl +bool common_hal_emmcio_emmc_ioctl(uint32_t op, uint32_t arg, uint32_t *out_value) { + (void)arg; + *out_value = 0; + switch (op) { + case MP_BLOCKDEV_IOCTL_INIT: + // The constructor already did the whole CMD0..CMD16 + EXT_CSD + // walk, or raised. 0 means "initialised"; a card that has since + // been deinited answers with the error the callers check for + // (s_ready), so a mount over a dead object fails at INIT rather + // than at the first read. + *out_value = s_ready ? 0u : 1u; + break; + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: + break; + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = s_block_count; + break; + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = EMMC_BLOCK_SIZE; + break; + default: + return false; + } + return true; +} + +// Power-off: release the bus pins and cut the VCCQ I/O rail. +// The card is gone until the next emmc_init(). +static void emmc_power_down(void) { + s_ready = false; + s_block_count = 0; + emmc_spim_deinit(); + RST_ASSERT(); + emmc_pins_release(); + VCCQ_OFF(); // rail off (pin stays an output) +} + +// CMD8 SEND_EXT_CSD: an ADTC (read) command -- the card responds R1, then +// sends a single 512-byte EXT_CSD data block on DAT0 exactly like CMD17. +// Read-only and safe. buf must be >= EMMC_BLOCK_SIZE. +bool common_hal_emmcio_emmc_read_ext_csd(uint8_t *buf) { + if (!s_ready) { + return false; + } + uint8_t r1[6]; + if (!send_command_retry(8, 0, r1, 8)) { + return false; + } + if (!read_data_block(buf)) { + return false; + } + // SEC_COUNT[215:212], little-endian. 0x00760000 on this part = 7,733,248 + // blocks; the value is the software LBA bound for every later read. + s_block_count = (uint32_t)buf[212] | ((uint32_t)buf[213] << 8) | + ((uint32_t)buf[214] << 16) | ((uint32_t)buf[215] << 24); + // DEVICE_TYPE[196] gates the HS_TIMING switch (bit 1 = 52 MHz supported; + // this part reads 0x57). + s_device_type = buf[196]; + return true; +} + +// ---- R1b / program busy on DAT0 -------------------------------------------- +// Shared by the CMD6 switch (below) and the write path (further down): the +// card pulls DAT0 low while it programs and releases it high when done, and it +// only advances on OUR clock, so the host must keep clocking for the card to +// get anywhere. + +#define EMMC_BUSY_LEADIN_CLOCKS 16 + +static bool dat0_busy_wait(uint32_t timeout_us, bool run_bg) { + DAT0_IN(); // never drive against a busy card + for (int i = 0; i < EMMC_BUSY_LEADIN_CLOCKS; i++) { + clk_pulse(); + } + uint32_t t0 = EMMC_TICKS(); + const uint32_t lim = US_TO_TICKS(timeout_us); + for (;;) { + bool released = false; + for (int i = 0; i < 64 && !released; i++) { + CLK_HIGH(); + half_delay(s_cmd_half_us); + released = READ_DAT0() != 0; + CLK_LOW(); + half_delay(s_cmd_half_us); + } + uint32_t el = ticks_since(t0); + if (released) { + DAT0_OUT(); // back to the read path's resting state + DAT0_HIGH(); + return true; + } + if (el >= lim || emmc_deadline_expired()) { + // DAT0 STAYS AN INPUT on a timeout + return false; + } + if (run_bg) { + emmc_yield(); + } + } +} + +// CMD6 SWITCH argument: access 0b11 (WRITE_BYTE) | index 185 | value 1 | +// cmd_set 0 -> 0x03 B9 01 00. +#define EMMC_SWITCH_HS_TIMING_ARG 0x03B90100u +#define EMMC_EXT_CSD_HS_TIMING 185u +#define EMMC_EXT_CSD_DEVICE_TYPE 196u +#define EMMC_DEVICE_TYPE_HS52 0x02u + +// GENERIC_CMD6_TIME on this part is 0x05 = 50 ms. Ten times that is the bound. +#define EMMC_CMD6_BUSY_US 500000u + +// Poll CMD13 until the card is back in tran and ready for data. This is the +// authoritative "the switch finished" test, and it is also where SWITCH_ERROR +// (status bit 7) shows up if the card rejected the write. +static bool wait_tran_after_switch(emmcio_emmc_obj_t *self, uint32_t timeout_us) { + uint32_t t0 = EMMC_TICKS(); + const uint32_t lim = US_TO_TICKS(timeout_us); + for (;;) { + uint8_t r1[6]; + if (common_hal_emmcio_emmc_read_status(r1)) { + uint32_t status = ((uint32_t)r1[1] << 24) | ((uint32_t)r1[2] << 16) | + ((uint32_t)r1[3] << 8) | (uint32_t)r1[4]; + if (status & (1u << 7)) { // SWITCH_ERROR: the card said no + self->hs_switch_error = true; + return false; + } + if (((status >> 9) & 0xFu) == 4u && ((status >> 8) & 1u)) { + return true; // tran + ready_for_data + } + } + if (ticks_since(t0) >= lim || emmc_deadline_expired()) { + return false; + } + emmc_yield(); + mp_hal_delay_ms(1); + } +} + +static bool emmc_set_high_speed(emmcio_emmc_obj_t *self) { + if (!s_ready) { + return false; + } + // Gate on the card's own capability byte. + if (!(s_device_type & EMMC_DEVICE_TYPE_HS52)) { + return false; + } + self->hs_stage = 1; + + uint8_t r1[6]; + if (!send_command_retry(6, EMMC_SWITCH_HS_TIMING_ARG, r1, 8)) { + return false; + } + self->hs_stage = 2; + // run_bg = true: a CMD6 on a volatile byte has no in-flight card state a + // power-off gesture could damage, so this wait services them as the read + // path does. + if (!dat0_busy_wait(EMMC_CMD6_BUSY_US, true)) { + return false; + } + self->hs_stage = 3; + if (!wait_tran_after_switch(self, EMMC_CMD6_BUSY_US)) { + return false; + } + self->hs_stage = 4; + + + NRF_SPIM3->CONFIG = SPIM_CONFIG_MODE1; + + // Read the byte back AT THE OLD CLOCK. + uint8_t ext_csd[EMMC_BLOCK_SIZE]; + if (!common_hal_emmcio_emmc_read_ext_csd(ext_csd) || + ext_csd[EMMC_EXT_CSD_HS_TIMING] != 1u) { + NRF_SPIM3->CONFIG = SPIM_CONFIG_MODE0; + return false; // still at M16, card still readable + } + self->hs_stage = 5; + + // Now host clock moves. The re-read is a smoke test of the + // faster bus with the integrity layer watching. + NRF_SPIM3->FREQUENCY = SPIM_FREQ_M32; + if (!common_hal_emmcio_emmc_read_ext_csd(ext_csd) || ext_csd[EMMC_EXT_CSD_HS_TIMING] != 1u) { + // Back to the old CLOCK but NOT to the old phase: the card is in + // high-speed timing and stays there until the rail drops, and + // high-speed timing is specified from 0 Hz up. Mode 1 is how we talk + // to it at M16 now. + NRF_SPIM3->FREQUENCY = SPIM_FREQ_M16; + return false; + } + self->hs_active = true; + self->hs_stage = 6; + return true; +} + +bool common_hal_emmcio_emmc_readblocks(uint32_t block_addr, uint8_t *buf, uint32_t count) { + if (!s_ready || count == 0) { + return false; + } + // Reject an out-of-range LBA before any command reaches the card + if (s_block_count != 0 && + (block_addr >= s_block_count || count > s_block_count - block_addr)) { + return false; + } + uint8_t r1[6]; + if (count == 1) { + if (!send_command_retry(17, block_addr, r1, 8)) { + return false; + } + return read_data_block(buf); + } + // RETRY like CMD17 above: at high bus duty the card intermittently misses + // the first command after the previous burst's CMD12 + if (!send_command_retry(18, block_addr, r1, 4)) { + return false; + } + + uint32_t bt0 = EMMC_TICKS(); + const uint32_t blim = US_TO_TICKS(150000u); + for (uint32_t i = 0; i < count; i++) { + if (i && (ticks_since(bt0) >= blim || emmc_deadline_expired())) { + (void)send_command_retry(12, 0, r1, 3); + return false; + } + if (!read_data_block(buf + i * EMMC_BLOCK_SIZE)) { + (void)send_command_retry(12, 0, r1, 3); + return false; + } + } + (void)send_command_retry(12, 0, r1, 3); + return true; +} + +// The card declares MIN_PERF_W_* = 0x00: no minimum write performance +#define EMMC_WR_BUSY_US 500000u +// Same shape as the read side +#define EMMC_WR_BURST_US 250000u + +// -Os states the intent for this bit-bang, but matches the port default and so +// changes nothing today. +__attribute__((optimize("Os"))) +static bool write_data_block(const uint8_t *buf) { + const uint32_t hd = g_emmc_clk_half_us; + const uint32_t clk_bit = emmc_pinout.clk_bit; + const uint32_t dat_bit = emmc_pinout.dat_bit; + + // Write convention: change DAT0 while CLK is LOW, then a full half-period + // of setup before the rising edge where the card latches it. DAT0 is a + // HIGH-DRIVE (H0H1) output. + // + // The frame opens with DAT0 idle-HIGH for a whole byte (the Nwr gap) so + // the card cannot mistake a stray low for an early start bit and misframe + // the token. + DAT0_OUT(); + RDAT_HIGH(dat_bit); + + uint8_t *tx = EMMC_TX_FRAME; // the reserved low-RAM SPIM3 buffer + uint16_t crc = crc16(buf, EMMC_BLOCK_SIZE); + tx[0] = 0xFF; // Nwr idle gap + tx[1] = 0xFE; // 7 idle bits + START 0 + memcpy(&tx[2], buf, EMMC_BLOCK_SIZE); + tx[2 + EMMC_BLOCK_SIZE] = (uint8_t)(crc >> 8); + tx[2 + EMMC_BLOCK_SIZE + 1] = (uint8_t)crc; + RCLK_LOW(clk_bit); + + const uint32_t saved_cfg = NRF_SPIM3->CONFIG; + if (saved_cfg != SPIM_CONFIG_MODE0) { + NRF_SPIM3->CONFIG = SPIM_CONFIG_MODE0; + } + // The TX frame ends exactly at the crc's last bit, no trailing idle + // byte. The card emits its CRC-status token a couple of clocks after the + // end bit. + emmc_spim_xfer(tx, 2u + EMMC_BLOCK_SIZE + 2u, NULL, 0); + if (saved_cfg != SPIM_CONFIG_MODE0) { + NRF_SPIM3->CONFIG = saved_cfg; + } + // END bit: DAT0 is back at its GPIO latch (output HIGH) -- clock it. + half_delay(hd); + EDGE_SETTLE(); + RCLK_HIGH(clk_bit); + half_delay(hd); + RCLK_LOW(clk_bit); + + // CRC-status token: the card drives DAT0 low (start bit), then 3 status + // bits -- 010 accepted, 101 CRC error, 110 write error -- then releases. + DAT0_IN(); + int wr_status = -1; + for (int i = 0; i < 16; i++) { + RCLK_HIGH(clk_bit); + half_delay(hd); + EDGE_SETTLE(); + int start = (int)RDAT_GET(dat_bit); + RCLK_LOW(clk_bit); + half_delay(hd); + if (!start) { + int st = 0; + for (int k = 0; k < 3; k++) { + RCLK_HIGH(clk_bit); + half_delay(hd); + EDGE_SETTLE(); + st = (st << 1) | (int)RDAT_GET(dat_bit); + RCLK_LOW(clk_bit); + half_delay(hd); + } + wr_status = st; + break; + } + } + + // Programming busy on DAT0 + if (!dat0_busy_wait(EMMC_WR_BUSY_US, false)) { + return false; // DAT0 left an INPUT -- see the wait + } + + // ENFORCE the token: 0b010 = accepted. Anything else means the card did + // not take the block. + if (wr_status != 0x2) { + return false; + } + return true; +} + +bool common_hal_emmcio_emmc_writeblocks(uint32_t block_addr, const uint8_t *buf, uint32_t count) { + if (!s_ready || count == 0) { + return false; + } + if (s_block_count != 0 && + (block_addr >= s_block_count || count > s_block_count - block_addr)) { + return false; + } + uint8_t r1[6]; + if (count == 1) { + if (!send_command_retry(24, block_addr, r1, 8)) { + return false; + } + return write_data_block(buf); + } + // Settle-miss retry, exactly as CMD18: at high bus duty the card + // intermittently misses the first command after the previous burst. + if (!send_command_retry(25, block_addr, r1, 4)) { + return false; + } + uint32_t bt0 = EMMC_TICKS(); + const uint32_t blim = US_TO_TICKS(EMMC_WR_BURST_US); + for (uint32_t i = 0; i < count; i++) { + if (i && (ticks_since(bt0) >= blim || emmc_deadline_expired())) { + (void)send_command_retry(12, 0, r1, 3); + return false; + } + if (!write_data_block(buf + i * EMMC_BLOCK_SIZE)) { + (void)send_command_retry(12, 0, r1, 3); + return false; + } + } + (void)send_command_retry(12, 0, r1, 3); + + (void)dat0_busy_wait(EMMC_WR_BUSY_US, false); + return true; +} + +uint32_t common_hal_emmcio_emmc_get_frequency(emmcio_emmc_obj_t *self) { + (void)self; + return NRF_SPIM3->FREQUENCY == SPIM_FREQ_M32 ? 32000000u : 16000000u; +} + +bool common_hal_emmcio_emmc_get_high_speed(emmcio_emmc_obj_t *self) { + return self->hs_active; +} + +const uint8_t *common_hal_emmcio_emmc_get_cid(emmcio_emmc_obj_t *self) { + return self->cid; +} + +static bool s_constructed; + +emmc_pinout_t emmc_pinout; + +static const mcu_pin_obj_t *s_claimed_pins[5]; +static size_t s_claimed_pin_count; + +bool emmcio_spim3_in_use(void) { + return s_constructed; +} + +void emmcio_emmc_release_hardware(void) { + emmc_power_down(); + for (size_t i = 0; i < s_claimed_pin_count; i++) { + reset_pin_number(s_claimed_pins[i]->number); + } + s_claimed_pin_count = 0; + s_constructed = false; +} + +static void emmc_claim_pins(const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *reset, const mcu_pin_obj_t *vccq, + bool never_reset) { + emmc_pinout.clk = clock->number; + emmc_pinout.cmd = command->number; + emmc_pinout.dat0 = data->number; + emmc_pinout.rst = reset != NULL ? reset->number : EMMC_NO_PIN; + emmc_pinout.vccq = vccq != NULL ? vccq->number : EMMC_NO_PIN; + emmc_pinout.clk_bit = 1u << clock->number; + emmc_pinout.dat_bit = 1u << data->number; + emmc_pinout.dat0_cnf = &NRF_P0->PIN_CNF[data->number]; + emmc_pinout.dat0_cnf_in = EMMC_CNF_IN; + emmc_pinout.dat0_cnf_out = EMMC_CNF_OUT_H0H1; + + s_claimed_pin_count = 0; + const mcu_pin_obj_t *pins[] = { clock, command, data, reset, vccq }; + for (size_t i = 0; i < MP_ARRAY_SIZE(pins); i++) { + if (pins[i] == NULL) { + continue; + } + claim_pin(pins[i]); + if (never_reset) { + never_reset_pin_number(pins[i]->number); + } + s_claimed_pins[s_claimed_pin_count++] = pins[i]; + } +} + +static emmcio_construct_result_t emmc_check_pins(const mcu_pin_obj_t *clock, + const mcu_pin_obj_t *command, const mcu_pin_obj_t *data, + const mcu_pin_obj_t *reset, const mcu_pin_obj_t *vccq, int *detail) { + // The data path drives CLK and DAT0 through NRF_P0 directly, so both have + // to be on port 0. CMD, RESET and VCCQ go through the HAL and may be + // anywhere. + if (clock->number >= P0_PIN_NUM) { + *detail = MP_QSTR_clock; + return EMMCIO_ERR_PIN_PORT; + } + if (data->number >= P0_PIN_NUM) { + *detail = MP_QSTR_data; + return EMMCIO_ERR_PIN_PORT; + } + if ((NRF_SPIM3->ENABLE & SPIM_ENABLE_ENABLE_Msk) != 0) { + return EMMCIO_ERR_SPI_IN_USE; + } + const mcu_pin_obj_t *pins[] = { clock, command, data, reset, vccq }; + for (size_t i = 0; i < MP_ARRAY_SIZE(pins); i++) { + if (pins[i] != NULL && !pin_number_is_free(pins[i]->number)) { + return EMMCIO_ERR_PIN_IN_USE; + } + } + return EMMCIO_OK; +} + +#define RETURN_CMD_UNLESS(cmd, done) do { if (!(done)) { return cmd; } } while (0) + +// The MMC command that never answered, so a failure names the step it stopped at. +static int init_failure_command(emmcio_emmc_obj_t *self) { + RETURN_CMD_UNLESS(MMC_GO_IDLE_STATE, self->cmd0_sent); + RETURN_CMD_UNLESS(MMC_SEND_OP_COND, self->cmd1_retries >= 0); // never left busy + RETURN_CMD_UNLESS(MMC_ALL_SEND_CID, self->cmd2_resp); + RETURN_CMD_UNLESS(MMC_SET_RELATIVE_ADDR, self->cmd3_resp); + RETURN_CMD_UNLESS(MMC_SELECT_CARD, self->cmd7_resp); + RETURN_CMD_UNLESS(MMC_SET_BLOCKLEN, self->cmd16_resp); + return MMC_SEND_EXT_CSD; +} + +#undef RETURN_CMD_UNLESS + +// How far the high-speed switch got: hs_stage as documented on the struct, +// except that a CMD13 SWITCH_ERROR (the card rejecting HS_TIMING) reports 7 to +// tell it apart from the card simply never coming back to tran. +static int hs_failure_stage(emmcio_emmc_obj_t *self) { + if (self->hs_stage == 3 && self->hs_switch_error) { + return 7; + } + return self->hs_stage; +} + +static emmcio_construct_result_t emmc_power_up(emmcio_emmc_obj_t *self, bool high_speed, + int *detail) { + s_constructed = true; + + if (!emmc_init(self)) { + *detail = init_failure_command(self); + emmcio_emmc_release_hardware(); + return EMMCIO_ERR_INIT; + } + + uint8_t ext_csd[EMMC_BLOCK_SIZE]; + if (!common_hal_emmcio_emmc_read_ext_csd(ext_csd)) { + emmcio_emmc_release_hardware(); + *detail = 8; + return EMMCIO_ERR_INIT; + } + if (high_speed && !emmc_set_high_speed(self)) { + *detail = hs_failure_stage(self); + emmcio_emmc_release_hardware(); + return EMMCIO_ERR_HIGH_SPEED; + } + return EMMCIO_OK; +} + +emmcio_construct_result_t common_hal_emmcio_emmc_construct(emmcio_emmc_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, const mcu_pin_obj_t *data, + const mcu_pin_obj_t *reset, const mcu_pin_obj_t *vccq, + bool high_speed, bool write_enabled, int *detail) { + *detail = 0; + if (emmcio_is_automounted()) { + return EMMCIO_ERR_USB_OWNED; + } + if (s_constructed) { + return EMMCIO_ERR_IN_USE; + } + emmcio_construct_result_t pin_err = emmc_check_pins(clock, command, data, reset, vccq, detail); + if (pin_err != EMMCIO_OK) { + return pin_err; + } + emmc_claim_pins(clock, command, data, reset, vccq, false); + + emmcio_construct_result_t err = emmc_power_up(self, high_speed, detail); + if (err != EMMCIO_OK) { + return err; + } + + self->deinited = false; + self->write_enabled = write_enabled; + return EMMCIO_OK; +} + +void common_hal_emmcio_emmc_deinit(emmcio_emmc_obj_t *self) { + if (self->deinited) { + return; + } + emmcio_emmc_release_hardware(); + self->deinited = true; +} + +bool common_hal_emmcio_emmc_deinited(emmcio_emmc_obj_t *self) { + return self->deinited; +} + +#if CIRCUITPY_EMMC_USB + +static emmcio_emmc_obj_t s_automount_obj; +static bool s_automounted; + +mp_obj_t emmcio_automount_construct(const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *reset, const mcu_pin_obj_t *vccq, + bool high_speed, bool write_enabled) { + if (s_constructed) { + return MP_OBJ_NULL; + } + int detail; + if (emmc_check_pins(clock, command, data, reset, vccq, &detail) != EMMCIO_OK) { + return MP_OBJ_NULL; + } + emmc_claim_pins(clock, command, data, reset, vccq, true); + s_automount_obj.base.type = &emmcio_emmc_type; + if (emmc_power_up(&s_automount_obj, high_speed, &detail) != EMMCIO_OK) { + return MP_OBJ_NULL; + } + s_automount_obj.deinited = false; + s_automount_obj.write_enabled = write_enabled; + s_automounted = true; + return MP_OBJ_FROM_PTR(&s_automount_obj); +} + +bool emmcio_is_automounted(void) { + return s_automounted; +} + +void emmcio_automount_abandon(void) { + s_automounted = false; + s_automount_obj.deinited = true; + if (s_constructed) { + emmcio_emmc_release_hardware(); + } +} +#endif diff --git a/ports/nordic/common-hal/emmcio/EMMC.h b/ports/nordic/common-hal/emmcio/EMMC.h new file mode 100644 index 00000000000..5bd0d6316c2 --- /dev/null +++ b/ports/nordic/common-hal/emmcio/EMMC.h @@ -0,0 +1,101 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// The nRF52840 eMMC back end: the 1-bit MMC protocol (CLK/CMD/DAT0 plus RST_n +// and a VCCQ rail gate) bit-banged on GPIO, with the 512-byte data payloads +// carried by SPIM3 + EasyDMA. +// +// Only one EMMC object can exist at a time, it owns SPIM3. + +#pragma once + +#include +#include + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/emmcio/EMMC.h" + +typedef struct { + mp_obj_base_t base; + bool deinited; + bool write_enabled; + + + // How far bring-up got, so a failure names the step it stopped at + bool cmd0_sent; + int32_t cmd1_retries; // retries until ready; -1 = never ready + bool cmd2_resp; + bool cmd3_resp; + bool cmd7_resp; + bool cmd16_resp; + uint8_t cid[16]; // CMD2 R2 payload (CID[127:0]) + + // These stay at their zero values unless high_speed was asked for. + bool hs_switch_error; // CMD13 reported SWITCH_ERROR after the CMD6 + bool hs_active; // EXT_CSD[185] verified AND the host clock is at M32 + // How far the switch got, so the failure message names a step + // 0 not attempted, 1 DEVICE_TYPE ok, 2 CMD6 answered, 3 DAT0 released, + // 4 back in tran, 5 EXT_CSD[185] verified, 6 running at M32. + uint8_t hs_stage; +} emmcio_emmc_obj_t; + +// EMMCIO_OK on success. On failure *detail carries the code's extra number, +// which the binding turns into the exception's argument. +emmcio_construct_result_t common_hal_emmcio_emmc_construct(emmcio_emmc_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, const mcu_pin_obj_t *data, + const mcu_pin_obj_t *reset, const mcu_pin_obj_t *vccq, + bool high_speed, bool write_enabled, int *detail); +void common_hal_emmcio_emmc_deinit(emmcio_emmc_obj_t *self); +bool common_hal_emmcio_emmc_deinited(emmcio_emmc_obj_t *self); + +bool common_hal_emmcio_emmc_readblocks(uint32_t block_addr, uint8_t *buf, uint32_t count); + +// CMD24 (count == 1) / CMD25 + CMD12 (count > 1), each block followed by the +// card's CRC-status token and its programming busy. Direct writes only: the +// card's volatile cache is never enabled, so when this returns true the data +// is in NAND and there is nothing to flush. +bool common_hal_emmcio_emmc_writeblocks(uint32_t block_addr, const uint8_t *buf, uint32_t count); + +// Block-device ioctl, taking extmod/vfs.h's MP_BLOCKDEV_IOCTL_* ops. False +// means the op is not implemented. +bool common_hal_emmcio_emmc_ioctl(uint32_t op, uint32_t arg, uint32_t *out_value); + +// CMD8 -> the 512-byte extended CSD. buf must be >= EMMC_BLOCK_SIZE. +bool common_hal_emmcio_emmc_read_ext_csd(uint8_t *buf); + +// CMD13 SEND_STATUS -- the 6-byte R1 response. +bool common_hal_emmcio_emmc_read_status(uint8_t *r1_out); + +uint32_t common_hal_emmcio_emmc_get_block_count(emmcio_emmc_obj_t *self); // 0 until EXT_CSD has been read +uint32_t common_hal_emmcio_emmc_get_frequency(emmcio_emmc_obj_t *self); // the SPIM data-phase clock, Hz +bool common_hal_emmcio_emmc_get_high_speed(emmcio_emmc_obj_t *self); +const uint8_t *common_hal_emmcio_emmc_get_cid(emmcio_emmc_obj_t *self); // 16 bytes, CID[127:0] + +// A wall-clock budget spanning a whole sequence of driver calls, so a card +// that never answers cannot stall a caller. +void common_hal_emmcio_emmc_set_deadline(uint32_t timeout_us); +void common_hal_emmcio_emmc_clear_deadline(void); + + + +// True while a live EMMC object owns SPIM3 +bool emmcio_spim3_in_use(void); + +// Power the card down and give up its pins +void emmcio_emmc_release_hardware(void); + +#if CIRCUITPY_EMMC_USB +// Bring up the supervisor's statically allocated EMMC object. +// Returns MP_OBJ_NULL if the card cannot be brought up. +mp_obj_t emmcio_automount_construct(const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *reset, const mcu_pin_obj_t *vccq, + bool high_speed, bool write_enabled); + +// The automount's undo, safe to call from any of its failure paths. +void emmcio_automount_abandon(void); +#endif diff --git a/ports/nordic/common-hal/emmcio/__init__.c b/ports/nordic/common-hal/emmcio/__init__.c new file mode 100644 index 00000000000..1f2cc314796 --- /dev/null +++ b/ports/nordic/common-hal/emmcio/__init__.c @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "common-hal/emmcio/EMMC.h" +#include "shared-bindings/emmcio/__init__.h" +#include "shared-module/emmcio/__init__.h" + +void emmcio_reset(void) { + // The supervisor's mount outlives the VM, so its card stays up. + if (emmcio_is_automounted()) { + return; + } + if (emmcio_spim3_in_use()) { + emmcio_emmc_release_hardware(); + } +} diff --git a/ports/nordic/common-hal/emmcio/emmc_hw.h b/ports/nordic/common-hal/emmcio/emmc_hw.h new file mode 100644 index 00000000000..6a8f9b1c88c --- /dev/null +++ b/ports/nordic/common-hal/emmcio/emmc_hw.h @@ -0,0 +1,202 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// The hardware the eMMC driver drives: the five pins, the RTC2 tick source +// and the SPIM3 data engine. + + +#pragma once + +#include +#include + +#include "nrf.h" +#include "nrf_gpio.h" + +// CLK and DAT0 must be on port 0: the data path drives them through NRF_P0 +// directly. RST and VCCQ are optional +#define EMMC_NO_PIN 0xFFu + +typedef struct { + uint8_t clk; + uint8_t cmd; + uint8_t dat0; + uint8_t rst; // active low; may be EMMC_NO_PIN + uint8_t vccq; // I/O rail gate; may be EMMC_NO_PIN + uint32_t clk_bit; // port-0 masks, for the data path's direct register use + uint32_t dat_bit; + volatile uint32_t *dat0_cnf; + uint32_t dat0_cnf_in; // input, buffer connected, pull-up + uint32_t dat0_cnf_out; // output, input disconnected, no pull, H0H1 +} emmc_pinout_t; + +#define EMMC_CNF_IN ((GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) | \ + (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | \ + (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | \ + (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | \ + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)) + +#define EMMC_CNF_OUT_H0H1 ((GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | \ + (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) | \ + (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | \ + (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | \ + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)) + +extern emmc_pinout_t emmc_pinout; + +static inline void emmc_opt_pin_write(uint8_t pin, bool high) { + if (pin == EMMC_NO_PIN) { + return; + } + if (high) { + nrf_gpio_pin_set(pin); + } else { + nrf_gpio_pin_clear(pin); + } +} + +static inline void emmc_opt_pin_output(uint8_t pin) { + if (pin != EMMC_NO_PIN) { + nrf_gpio_cfg_output(pin); + } +} + +// SPIM3 clock codes. +#define SPIM_FREQ_M16 0x0A000000u +#define SPIM_FREQ_M32 0x14000000u + +// SPIM3 CONFIG codes +#define SPIM_CONFIG_MODE0 0u // MSB first, CPOL0/CPHA0 +#define SPIM_CONFIG_MODE1 (1u << 1) // MSB first, CPOL0/CPHA1 + +// ---- pin control --------------------------------------------------------- +// The command/init path uses the HAL macros; the data path uses the direct +// port-0 register accesses below +#define CLK_HIGH() nrf_gpio_pin_set(emmc_pinout.clk) +#define CLK_LOW() nrf_gpio_pin_clear(emmc_pinout.clk) +#define CMD_HIGH() nrf_gpio_pin_set(emmc_pinout.cmd) +#define CMD_LOW() nrf_gpio_pin_clear(emmc_pinout.cmd) +#define DAT0_HIGH() nrf_gpio_pin_set(emmc_pinout.dat0) +#define DAT0_LOW() nrf_gpio_pin_clear(emmc_pinout.dat0) +#define DAT0_IN() (*emmc_pinout.dat0_cnf = emmc_pinout.dat0_cnf_in) +// DAT0 as a HIGH-DRIVE output (H0H1) so edges are fast and clean. +#define DAT0_OUT() (*emmc_pinout.dat0_cnf = emmc_pinout.dat0_cnf_out) +#define CMD_IN() nrf_gpio_cfg_input(emmc_pinout.cmd, NRF_GPIO_PIN_PULLUP) +#define CMD_OUT() nrf_gpio_cfg_output(emmc_pinout.cmd) +#define READ_CMD() nrf_gpio_pin_read(emmc_pinout.cmd) +#define READ_DAT0() nrf_gpio_pin_read(emmc_pinout.dat0) + +#define RCLK_HIGH(bit) (NRF_P0->OUTSET = (bit)) +#define RCLK_LOW(bit) (NRF_P0->OUTCLR = (bit)) +#define RDAT_HIGH(bit) (NRF_P0->OUTSET = (bit)) +#define RDAT_GET(bit) ((NRF_P0->IN & (bit)) != 0u) +// A few NOPs of settle after a clock edge for the delay-free (hd==0) path: +// covers the card's data-output valid time without throttling to a busy-wait. +#define EDGE_SETTLE() __asm__ volatile ("nop\nnop\nnop") + +#define RST_ASSERT() emmc_opt_pin_write(emmc_pinout.rst, false) +#define RST_RELEASE() emmc_opt_pin_write(emmc_pinout.rst, true) +#define VCCQ_ON() emmc_opt_pin_write(emmc_pinout.vccq, true) +#define VCCQ_OFF() emmc_opt_pin_write(emmc_pinout.vccq, false) + +static inline void emmc_pins_init(void) { + nrf_gpio_cfg(emmc_pinout.clk, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, + NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE); // high-drive CLK + nrf_gpio_cfg_output(emmc_pinout.cmd); + DAT0_OUT(); // high-drive DAT0 + emmc_opt_pin_output(emmc_pinout.rst); + // VCCQ: standard drive. Do NOT "improve" this to H0H1 without evidence -- + // the rail gate does not need the extra drive and the card came up on it. + emmc_opt_pin_output(emmc_pinout.vccq); +} + +static inline void emmc_pins_release(void) { + nrf_gpio_cfg_default(emmc_pinout.clk); + nrf_gpio_cfg_default(emmc_pinout.cmd); + nrf_gpio_cfg_default(emmc_pinout.dat0); + if (emmc_pinout.rst != EMMC_NO_PIN) { + nrf_gpio_cfg_default(emmc_pinout.rst); + } + // VCCQ stays an output, driven low: the rail must stay off, not float. +} + +// handle nrf52840 errata 198 SPIM3 data corruption +#define EMMC_TX_FRAME ((uint8_t *)SPIM3_BUFFER_RAM_START_ADDR) + +// ---- time ---------------------------------------------------------------- +// Free-running 32768 Hz counter (RTC2, the supervisor's tick source). 24-bit, +// so differences must be masked; it wraps every 512 s. +#define EMMC_TICKS_HZ 32768u +#define EMMC_TICK_MASK 0x00FFFFFFu +#define EMMC_TICKS() (NRF_RTC2->COUNTER) + +static inline uint32_t ticks_since_raw(uint32_t t0) { + return (EMMC_TICKS() - t0) & EMMC_TICK_MASK; +} + +// 20 ms, ~75x the 260 us a full block takes at M16. +#define EMMC_SPIM_TIMEOUT_TICKS ((EMMC_TICKS_HZ * 20u) / 1000u) + +// ---- SPIM3 data engine --------------------------------------------------- +// SPIM3 is the only instance that runs above 8 MHz. M16 = 16 MHz, the fastest +// in-spec step for this card at power-on timing (TRAN_SPEED 0x32 -> 26 MHz cap +// in backwards-compatible mode). The bus is fixed there; the ONE way it moves +// is emmc_set_high_speed(), which first gets the card's own EXT_CSD to read +// back HS_TIMING = 1 (52 MHz limit) and only then steps to M32. +// +// NRF_SPIM3->FREQUENCY and ->CONFIG are read and written directly: the +// peripheral register is the state, and it survives +// ENABLE=0 between transfers. emmc_spim_init() puts both back to M16 / +// mode 0 on every init, so a fresh object always starts at compat speed even +// if the previous one ran high. + +static inline void emmc_spim_init(void) { + NRF_SPIM3->ENABLE = 0; + NRF_SPIM3->PSEL.SCK = emmc_pinout.clk; + NRF_SPIM3->PSEL.MOSI = 0xFFFFFFFFu; // attached per-transfer (write path only) + NRF_SPIM3->PSEL.MISO = 0xFFFFFFFFu; + NRF_SPIM3->PSEL.CSN = 0xFFFFFFFFu; + NRF_SPIM3->FREQUENCY = SPIM_FREQ_M16; + NRF_SPIM3->CONFIG = SPIM_CONFIG_MODE0; // the card comes up in compat timing + NRF_SPIM3->ORC = 0xFF; // idle-high filler +} + +static inline void emmc_spim_deinit(void) { + NRF_SPIM3->ENABLE = 0; + NRF_SPIM3->PSEL.SCK = 0xFFFFFFFFu; + NRF_SPIM3->PSEL.MOSI = 0xFFFFFFFFu; + NRF_SPIM3->PSEL.MISO = 0xFFFFFFFFu; +} + +// One blocking DMA transfer with the wires temporarily owned by SPIM. While +// ENABLED the peripheral drives SCK (+MOSI for TX) / samples MISO; on disable +// the pins fall back to their GPIO latches (CLK low, DAT0 as configured). + +static inline void emmc_spim_xfer(const uint8_t *tx, uint32_t txlen, uint8_t *rx, uint32_t rxlen) { + NRF_SPIM3->PSEL.MOSI = tx ? emmc_pinout.dat0 : 0xFFFFFFFFu; + NRF_SPIM3->PSEL.MISO = rx ? emmc_pinout.dat0 : 0xFFFFFFFFu; + NRF_SPIM3->ENABLE = 7; + NRF_SPIM3->TXD.PTR = (uint32_t)tx; + NRF_SPIM3->TXD.MAXCNT = tx ? txlen : 0; + NRF_SPIM3->RXD.PTR = (uint32_t)rx; + NRF_SPIM3->RXD.MAXCNT = rx ? rxlen : 0; + NRF_SPIM3->EVENTS_END = 0; + NRF_SPIM3->TASKS_START = 1; + { + uint32_t t0 = EMMC_TICKS(); + while (!NRF_SPIM3->EVENTS_END) { + if (ticks_since_raw(t0) >= EMMC_SPIM_TIMEOUT_TICKS) { + NRF_SPIM3->EVENTS_STOPPED = 0; + NRF_SPIM3->TASKS_STOP = 1; + // Let EasyDMA stop writing before the buffer is handed back. + for (uint32_t i = 0; i < 10000u && !NRF_SPIM3->EVENTS_STOPPED; i++) { + } + break; + } + } + } + NRF_SPIM3->ENABLE = 0; +} diff --git a/ports/nordic/common-hal/microcontroller/Pin.c b/ports/nordic/common-hal/microcontroller/Pin.c index 8043d2dfd4d..ea495d32893 100644 --- a/ports/nordic/common-hal/microcontroller/Pin.c +++ b/ports/nordic/common-hal/microcontroller/Pin.c @@ -33,6 +33,10 @@ static void reset_speaker_enable_pin(void) { #endif } +MP_WEAK bool board_reset_pin_number(uint8_t pin_number) { + return false; +} + void reset_all_pins(void) { for (size_t i = 0; i < GPIO_COUNT; i++) { claimed_pins[i] = never_reset_pins[i]; @@ -42,6 +46,10 @@ void reset_all_pins(void) { if ((never_reset_pins[nrf_pin_port(pin)] & (1 << nrf_relative_pin_number(pin))) != 0) { continue; } + // Allow the board to override the reset state of any pin. + if (board_reset_pin_number(pin)) { + continue; + } nrf_gpio_cfg_default(pin); } @@ -64,6 +72,9 @@ void reset_pin_number(uint8_t pin_number) { reset_speaker_enable_pin(); } #endif + + // Allow the board to override the reset state of any pin. + board_reset_pin_number(pin_number); } diff --git a/ports/nordic/common-hal/microcontroller/Pin.h b/ports/nordic/common-hal/microcontroller/Pin.h index e0a7550ec3a..330a8ef1283 100644 --- a/ports/nordic/common-hal/microcontroller/Pin.h +++ b/ports/nordic/common-hal/microcontroller/Pin.h @@ -10,6 +10,11 @@ #include "peripherals/nrf/pins.h" +// If a board needs a different reset state for one or more pins, implement +// board_reset_pin_number so that it sets this state and returns `true` for those +// pin numbers, `false` for others. +bool board_reset_pin_number(uint8_t pin_number); + void reset_all_pins(void); // reset_pin_number takes the pin number instead of the pointer so that objects don't // need to store a full pointer. diff --git a/ports/nordic/common-hal/microcontroller/Processor.c b/ports/nordic/common-hal/microcontroller/Processor.c index c80da222307..fc3f0e7150e 100644 --- a/ports/nordic/common-hal/microcontroller/Processor.c +++ b/ports/nordic/common-hal/microcontroller/Processor.c @@ -109,28 +109,28 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - mcu_reset_reason_t r = RESET_REASON_UNKNOWN; + mcu_reset_reason_t r = MCU_RESET_REASON_UNKNOWN; if (reset_reason_saved == 0) { - r = RESET_REASON_POWER_ON; + r = MCU_RESET_REASON_POWER_ON; } else if (reset_reason_saved & POWER_RESETREAS_RESETPIN_Msk) { - r = RESET_REASON_RESET_PIN; + r = MCU_RESET_REASON_RESET_PIN; } else if (reset_reason_saved & POWER_RESETREAS_DOG_Msk) { - r = RESET_REASON_WATCHDOG; + r = MCU_RESET_REASON_WATCHDOG; } else if (reset_reason_saved & POWER_RESETREAS_SREQ_Msk) { - r = RESET_REASON_SOFTWARE; + r = MCU_RESET_REASON_SOFTWARE; #if CIRCUITPY_ALARM // Our "deep sleep" is still actually light sleep followed by a software // reset. Adding this check here ensures we treat it as-if we're waking // from deep sleep. if (sleepmem_wakeup_event != SLEEPMEM_WAKEUP_BY_NONE) { - r = RESET_REASON_DEEP_SLEEP_ALARM; + r = MCU_RESET_REASON_DEEP_SLEEP_ALARM; } #endif } else if ((reset_reason_saved & POWER_RESETREAS_OFF_Msk) || (reset_reason_saved & POWER_RESETREAS_LPCOMP_Msk) || (reset_reason_saved & POWER_RESETREAS_NFC_Msk) || (reset_reason_saved & POWER_RESETREAS_VBUS_Msk)) { - r = RESET_REASON_DEEP_SLEEP_ALARM; + r = MCU_RESET_REASON_DEEP_SLEEP_ALARM; } return r; } diff --git a/ports/nordic/common-hal/microcontroller/__init__.c b/ports/nordic/common-hal/microcontroller/__init__.c index fbb40afe044..03746d242b8 100644 --- a/ports/nordic/common-hal/microcontroller/__init__.c +++ b/ports/nordic/common-hal/microcontroller/__init__.c @@ -24,7 +24,9 @@ #include "supervisor/port.h" #include "supervisor/shared/safe_mode.h" #include "nrfx_glue.h" +#ifdef BLUETOOTH_SD #include "nrf_nvic.h" +#endif #include "nrf_power.h" // This routine should work even when interrupts are disabled. Used by OneWire @@ -45,7 +47,14 @@ void common_hal_mcu_disable_interrupts(void) { // This only disables interrupts of priority 2 through 7; levels 0, 1, // and 4, are exclusive to softdevice and should never be used, so // this limitation is not important. + #ifdef BLUETOOTH_SD sd_nvic_critical_region_enter(&is_nested_critical_region); + #else + // With no SoftDevice to leave room for, mask everything. Record whether + // interrupts were already masked so the matching exit leaves them so. + is_nested_critical_region = __get_PRIMASK() ? 1 : 0; + __disable_irq(); + #endif } __DMB(); nesting_count++; @@ -61,20 +70,49 @@ void common_hal_mcu_enable_interrupts(void) { return; } __DMB(); + #ifdef BLUETOOTH_SD sd_nvic_critical_region_exit(is_nested_critical_region); + #else + if (!is_nested_critical_region) { + __enable_irq(); + } + #endif } void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { - enum { DFU_MAGIC_UF2_RESET = 0x57 }; uint8_t new_value = 0; if (runmode == RUNMODE_BOOTLOADER || runmode == RUNMODE_UF2) { - new_value = DFU_MAGIC_UF2_RESET; + new_value = BOOTLOADER_UF2_MAGIC; + } + #ifdef BOOTLOADER_UF2_MAGIC2 + // This bootloader's magic is 16 bits wide, split across both retention + // registers, so GPREGRET2 is written as a pair with GPREGRET. + uint8_t new_value2 = 0; + if (runmode == RUNMODE_BOOTLOADER || runmode == RUNMODE_UF2) { + new_value2 = BOOTLOADER_UF2_MAGIC2; } - int err_code = sd_power_gpregret_set(0, DFU_MAGIC_UF2_RESET); + #endif + #ifdef BLUETOOTH_SD + int err_code = sd_power_gpregret_set(0, BOOTLOADER_UF2_MAGIC); + #ifdef BOOTLOADER_UF2_MAGIC2 + if (err_code == NRF_SUCCESS) { + err_code = sd_power_gpregret_set(1, BOOTLOADER_UF2_MAGIC2); + } + #endif if (err_code != NRF_SUCCESS) { // Set it without the soft device if the SD failed. (It may be off.) nrf_power_gpregret_set(NRF_POWER, new_value); + #ifdef BOOTLOADER_UF2_MAGIC2 + nrf_power_gpregret2_set(NRF_POWER, new_value2); + #endif } + #else + // No SoftDevice, so write GPREGRET directly. + nrf_power_gpregret_set(NRF_POWER, new_value); + #ifdef BOOTLOADER_UF2_MAGIC2 + nrf_power_gpregret2_set(NRF_POWER, new_value2); + #endif + #endif if (runmode == RUNMODE_SAFE_MODE) { safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); } diff --git a/ports/nordic/common-hal/neopixel_write/__init__.c b/ports/nordic/common-hal/neopixel_write/__init__.c index 66a1d70e869..e9f3a0fdacc 100644 --- a/ports/nordic/common-hal/neopixel_write/__init__.c +++ b/ports/nordic/common-hal/neopixel_write/__init__.c @@ -125,7 +125,9 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, pixels_pattern = (uint16_t *)stack_pixels; } else { uint8_t sd_en = 0; + #ifdef BLUETOOTH_SD (void)sd_softdevice_is_enabled(&sd_en); + #endif if (pixels_pattern_heap_size < pattern_size) { // Current heap buffer is too small. diff --git a/ports/nordic/common-hal/nvm/ByteArray.c b/ports/nordic/common-hal/nvm/ByteArray.c index c846a61f751..f245207e83c 100644 --- a/ports/nordic/common-hal/nvm/ByteArray.c +++ b/ports/nordic/common-hal/nvm/ByteArray.c @@ -11,6 +11,7 @@ #include #include +#include "background.h" #include "peripherals/nrf/nvm.h" uint32_t common_hal_nvm_bytearray_get_length(const nvm_bytearray_obj_t *self) { @@ -40,6 +41,7 @@ bool common_hal_nvm_bytearray_set_bytes(const nvm_bytearray_obj_t *self, while (len) { uint32_t write_len = MIN(len, FLASH_PAGE_SIZE - offset); + board_background_task(); if (!write_page(page_addr, offset, write_len, values)) { return false; } diff --git a/ports/nordic/common-hal/watchdog/WatchDogTimer.c b/ports/nordic/common-hal/watchdog/WatchDogTimer.c index b20aa0c0629..f3c4cbf10d6 100644 --- a/ports/nordic/common-hal/watchdog/WatchDogTimer.c +++ b/ports/nordic/common-hal/watchdog/WatchDogTimer.c @@ -75,9 +75,6 @@ void common_hal_watchdog_feed(watchdog_watchdogtimer_obj_t *self) { void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self) { if (self->mode == WATCHDOGMODE_RESET) { - if (gc_alloc_possible()) { - mp_raise_RuntimeError(MP_ERROR_TEXT("WatchDogTimer cannot be deinitialized once mode is set to RESET")); - } // Don't change anything because RESET cannot be undone. return; } @@ -164,6 +161,10 @@ void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_w } nrfx_wdt_enable(&wdt); nrfx_wdt_feed(&wdt); + } else if (new_mode == WATCHDOGMODE_NONE && current_mode == WATCHDOGMODE_RESET) { + // raise exception on attempt to set mode back from RESET to None + mp_raise_RuntimeError(MP_ERROR_TEXT("WatchDogTimer cannot be deinitialized once mode is set to RESET")); + } // If we just switched away from RAISE, disable the timmer. diff --git a/ports/nordic/device/nrf52/startup_nrf52840.c b/ports/nordic/device/nrf52/startup_nrf52840.c index 6b81fac2a9c..f602a86e079 100644 --- a/ports/nordic/device/nrf52/startup_nrf52840.c +++ b/ports/nordic/device/nrf52/startup_nrf52840.c @@ -27,8 +27,23 @@ void Default_Handler(void) { } } +extern const func __Vectors[]; + +#ifndef BLUETOOTH_SD +// SCB->VTOR, addressed directly so the startup file need not pull in CMSIS. +#define SCB_VTOR (*(volatile uint32_t *)0xE000ED08UL) +#endif + extern void Reset_Handler(void); void Reset_Handler(void) { + #ifndef BLUETOOTH_SD + // With a SoftDevice, the MBR at 0x0 owns the vector table and forwards + // interrupts to us, so VTOR is already pointing at our table by the time we + // run. + SCB_VTOR = (uint32_t)&__Vectors[0]; + __asm volatile ("dsb 0xF" ::: "memory"); + #endif + uint32_t *p_src = &_sidata; uint32_t *p_dest = &_sdata; diff --git a/ports/nordic/mpconfigport.h b/ports/nordic/mpconfigport.h index 33fcfa371e0..a6995f9b885 100644 --- a/ports/nordic/mpconfigport.h +++ b/ports/nordic/mpconfigport.h @@ -7,10 +7,13 @@ #pragma once +#ifdef BLUETOOTH_SD #include "ble_drv.h" #include "nrf_mbr.h" // for MBR_SIZE #include "nrf_sdm.h" // for SD_FLASH_SIZE +#endif + #include "peripherals/nrf/nvm.h" // for FLASH_PAGE_SIZE #define MICROPY_PY_SYS_STDIO_BUFFER (1) @@ -44,6 +47,17 @@ // Definitions that might be overridden by mpconfigboard.h +#ifndef BLUETOOTH_SD + +#ifndef MBR_SIZE +#define MBR_SIZE (0x1000) +#endif + +#ifndef SD_FLASH_SIZE +#define SD_FLASH_SIZE (0) +#endif +#endif + #ifndef CIRCUITPY_INTERNAL_NVM_SIZE #define CIRCUITPY_INTERNAL_NVM_SIZE (8 * 1024) #endif @@ -81,7 +95,11 @@ #define SD_FLASH_START_ADDR (MBR_START_ADDR + MBR_SIZE) // SD_FLASH_SIZE is from nrf_sdm.h +// A board whose bootloader lives in low flash and jumps to a fixed address +// overrides this in mpconfigboard.h. +#ifndef ISR_START_ADDR #define ISR_START_ADDR (SD_FLASH_START_ADDR + SD_FLASH_SIZE) +#endif #define ISR_SIZE (4 * 1024) // 4kiB // Smallest unit of flash that can be erased. @@ -92,14 +110,37 @@ // Define these regions starting down from the bootloader: // Bootloader values from https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/src/linker/s140_v6.ld +// A board with no bootloader in high flash sets BOOTLOADER_SIZE and +// BOOTLOADER_MBR_SIZE to 0; BOOTLOADER_START_ADDR then collapses onto the +// settings page, which stays the top anchor everything else grows down from. #define BOOTLOADER_START_ADDR (FLASH_SIZE - BOOTLOADER_SIZE - BOOTLOADER_SETTINGS_SIZE - BOOTLOADER_MBR_SIZE) +#ifndef BOOTLOADER_MBR_SIZE #define BOOTLOADER_MBR_SIZE (4 * 1024) // 4kib +#endif #ifndef BOOTLOADER_SIZE #define BOOTLOADER_SIZE (40 * 1024) // 40kiB #endif #define BOOTLOADER_SETTINGS_START_ADDR (FLASH_SIZE - BOOTLOADER_SETTINGS_SIZE) #define BOOTLOADER_SETTINGS_SIZE (4 * 1024) // 4kiB +// Value left in GPREGRET to ask the bootloader to stay in DFU mode after the +// reset that reset_to_bootloader() performs. The default is the Adafruit nRF52 +// bootloader's serial-DFU magic; a board with a different bootloader overrides +// it in mpconfigboard.h. A bootloader whose magic is wider than eight bits also +// defines BOOTLOADER_DFU_MAGIC2, which is written to GPREGRET2. +#ifndef BOOTLOADER_DFU_MAGIC +#define BOOTLOADER_DFU_MAGIC (0x4e) +#endif + +// Value left in GPREGRET by common_hal_mcu_on_next_reset() for RunMode.UF2 and +// RunMode.BOOTLOADER. The default is the Adafruit nRF52 bootloader's UF2/OTA +// magic. A board whose bootloader gates on something else overrides it in +// mpconfigboard.h; if that bootloader has no separate UF2 and serial-DFU +// requests, it sets this to the same value as BOOTLOADER_DFU_MAGIC. +#ifndef BOOTLOADER_UF2_MAGIC +#define BOOTLOADER_UF2_MAGIC (0x57) +#endif + #define CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_START_ADDR (BOOTLOADER_START_ADDR - CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE) #if CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE > 0 && CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_START_ADDR != (BOOTLOADER_START_ADDR - CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE) @@ -159,7 +200,12 @@ // high enough to work and then check the mutation of the value done by sd_ble_enable(). // See common.template.ld. #ifndef SOFTDEVICE_RAM_SIZE +#ifdef BLUETOOTH_SD #define SOFTDEVICE_RAM_SIZE (56 * 1024) +#else + +#define SOFTDEVICE_RAM_SIZE (0) +#endif #endif diff --git a/ports/nordic/mpconfigport.mk b/ports/nordic/mpconfigport.mk index 502e71ae4ae..0288d1329be 100644 --- a/ports/nordic/mpconfigport.mk +++ b/ports/nordic/mpconfigport.mk @@ -1,5 +1,8 @@ # All linking can be done with this common templated linker script, which has # parameters that vary based on chip and/or board. +# Properties get a dedicated linker section here, so they can drop the unused slots. +CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 1 + LD_TEMPLATE_FILE = boards/common.template.ld INTERNAL_LIBM = 1 @@ -9,6 +12,15 @@ CIRCUITPY_BUILD_EXTENSIONS ?= uf2 # Number of USB endpoint pairs. USB_NUM_ENDPOINT_PAIRS = 8 +# The nRF52 USBD implements isochronous transfers only on the fixed, dedicated +# endpoint number 8 (EP_ISO_NUM in TinyUSB's dcd_nrf5x.c); dcd_edpt_open() rejects +# an ISO endpoint on any other number, so a usb_audio mic/speaker placed on a +# sequentially-allocated endpoint would enumerate but never transfer data. Force +# the usb_audio isochronous endpoint onto endpoint 8. (Only read by usb_audio +# code, so it is harmless when CIRCUITPY_USB_AUDIO is off; defined unconditionally +# to stay independent of where that flag gets set in the include order.) +CFLAGS += -DUSB_AUDIO_ISO_EP_NUM=8 + # All nRF ports have longints. LONGINT_IMPL = MPZ @@ -32,6 +44,8 @@ CIRCUITPY_I2CTARGET = 0 CIRCUITPY_RTC ?= 1 +CIRCUITPY_SETTINGS_TOML ?= 1 + # frequencyio not yet implemented CIRCUITPY_FREQUENCYIO = 0 @@ -40,13 +54,12 @@ CIRCUITPY_ROTARYIO_SOFTENCODER = 1 # Sleep and Wakeup CIRCUITPY_ALARM ?= 1 -# Turn on the BLE file service +# Turn on the BLE file and serial services for BLE workflow CIRCUITPY_BLE_FILE_SERVICE ?= 1 - -# Turn on the BLE serial service -CIRCUITPY_SERIAL_BLE ?= 1 +CIRCUITPY_BLE_SERIAL_SERVICE ?= 1 CIRCUITPY_COMPUTED_GOTO_SAVE_SPACE ?= 1 +CIRCUITPY_LOAD_NATIVE ?= 1 # nRF52840-specific @@ -63,6 +76,8 @@ CIRCUITPY_MEMORYMAP ?= 1 CIRCUITPY_RGBMATRIX ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 +CIRCUITPY_HASHLIB ?= 1 + CIRCUITPY_COUNTIO ?= 1 CIRCUITPY_WATCHDOG ?= 1 @@ -81,6 +96,8 @@ ifeq ($(INTERNAL_FLASH_FILESYSTEM),1) OPTIMIZATION_FLAGS ?= -Os CIRCUITPY_LTO = 1 CIRCUITPY_LTO_PARTITION = balanced +else + CIRCUITPY_USB_AUDIO ?= 1 endif else @@ -111,3 +128,8 @@ ifeq ($(INTERNAL_FLASH_FILESYSTEM),1) endif endif endif + +ifneq ($(CIRCUITPY_BLEIO_NATIVE),1) +CIRCUITPY_BLE_FILE_SERVICE = 0 +CIRCUITPY_BLE_SERIAL_SERVICE = 0 +endif diff --git a/ports/nordic/peripherals/nrf/nvm.h b/ports/nordic/peripherals/nrf/nvm.h index aff98094469..10bf92d90cf 100644 --- a/ports/nordic/peripherals/nrf/nvm.h +++ b/ports/nordic/peripherals/nrf/nvm.h @@ -7,9 +7,12 @@ #pragma once +#include +#include + #define FLASH_PAGE_SIZE (4096) -#if BLUETOOTH_SD +#ifdef BLUETOOTH_SD bool sd_flash_page_erase_sync(uint32_t page_number); bool sd_flash_write_sync(uint32_t *dest_words, uint32_t *src_words, uint32_t num_words); #endif diff --git a/ports/nordic/supervisor/internal_flash.c b/ports/nordic/supervisor/internal_flash.c index 88b6a274d06..82a687d1dd8 100644 --- a/ports/nordic/supervisor/internal_flash.c +++ b/ports/nordic/supervisor/internal_flash.c @@ -16,6 +16,7 @@ #include "lib/oofatfs/ff.h" #include "supervisor/shared/safe_mode.h" +#include "background.h" #include "peripherals/nrf/nvm.h" #ifdef BLUETOOTH_SD @@ -54,6 +55,7 @@ void port_internal_flash_flush(void) { // Skip if data is the same if (memcmp(_flash_cache, (void *)_flash_page_addr, FLASH_PAGE_SIZE) != 0) { + board_background_task(); if (!nrf_nvm_safe_flash_page_write(_flash_page_addr, _flash_cache)) { reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL); } diff --git a/ports/nordic/supervisor/port.c b/ports/nordic/supervisor/port.c index ed371c6ad85..6c3897db457 100644 --- a/ports/nordic/supervisor/port.c +++ b/ports/nordic/supervisor/port.c @@ -11,6 +11,8 @@ #include "supervisor/background_callback.h" #include "supervisor/board.h" +#include "board.h" + #include "nrfx/hal/nrf_clock.h" #include "nrfx/hal/nrf_power.h" #include "nrfx/drivers/include/nrfx_gpiote.h" @@ -22,7 +24,13 @@ #include "nrf/power.h" #include "nrf/timers.h" +#ifdef BLUETOOTH_SD #include "nrf_nvic.h" +#endif + +#if CIRCUITPY_EMMCIO +#include "shared-bindings/emmcio/__init__.h" +#endif #include "common-hal/microcontroller/Pin.h" #include "common-hal/alarm/time/TimeAlarm.h" @@ -34,7 +42,6 @@ #include "common-hal/watchdog/WatchDogTimer.h" #include "common-hal/alarm/__init__.h" -#include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/rtc/__init__.h" @@ -52,6 +59,10 @@ extern void qspi_disable(void); #endif +// Do-nothing, not every board needs to provide this function. +MP_WEAK void board_early_init(void) { +} + static void power_warning_handler(void) { reset_into_safe_mode(SAFE_MODE_BROWNOUT); } @@ -131,6 +142,9 @@ void tick_set_prescaler(uint32_t prescaler_val) { } safe_mode_t port_init(void) { + // Before any peripheral is touched + board_early_init(); + nrf_peripherals_clocks_init(); // If GPIO voltage is set wrong in UICR, this will fix it, and @@ -175,10 +189,10 @@ safe_mode_t port_init(void) { // next time we reboot. if (reset_reason_saved & POWER_RESETREAS_DOG_Msk) { NRF_POWER->RESETREAS = POWER_RESETREAS_DOG_Msk; - uint32_t usb_reg = NRF_POWER->USBREGSTATUS; // If USB is connected, then the user might be editing `code.py`, // in which case we should reboot into Safe Mode. + uint32_t usb_reg = NRF_POWER->USBREGSTATUS; if (usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk) { return SAFE_MODE_WATCHDOG; } @@ -189,7 +203,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif @@ -205,6 +218,10 @@ void reset_port(void) { rtc_reset(); #endif + #if CIRCUITPY_EMMCIO + emmcio_reset(); + #endif + timers_reset(); #if CIRCUITPY_WATCHDOG @@ -216,14 +233,15 @@ void reset_port(void) { nrfx_gpiote_uninit(); } nrfx_gpiote_init(NRFX_GPIOTE_CONFIG_IRQ_PRIORITY); - - reset_all_pins(); } void reset_to_bootloader(void) { - enum { DFU_MAGIC_SERIAL = 0x4e }; - - NRF_POWER->GPREGRET = DFU_MAGIC_SERIAL; + NRF_POWER->GPREGRET = BOOTLOADER_DFU_MAGIC; + #ifdef BOOTLOADER_DFU_MAGIC2 + // This bootloader's magic is 16 bits wide, split across both retention + // registers. + NRF_POWER->GPREGRET2 = BOOTLOADER_DFU_MAGIC2; + #endif reset_cpu(); } @@ -326,6 +344,7 @@ void port_idle_until_interrupt(void) { (void)__get_FPSCR(); NVIC_ClearPendingIRQ(FPU_IRQn); } + #ifdef BLUETOOTH_SD uint8_t sd_enabled; sd_softdevice_is_enabled(&sd_enabled); @@ -333,7 +352,10 @@ void port_idle_until_interrupt(void) { if (!background_callback_pending()) { sd_app_evt_wait(); } - } else { + return; + } + #endif + { // Call wait for interrupt ourselves if the SD isn't enabled. // Note that `wfi` should be called with interrupts disabled, // to ensure that the queue is properly drained. The `wfi` diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile old mode 100644 new mode 100755 index b75d5423251..6348dc941f7 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -84,6 +84,33 @@ SRC_CYW43 := SRC_LWIP := endif +ifeq ($(CIRCUITPY_WIZNET), 1) +INC_WIZNET := \ + -isystem common-hal/wiznet \ + +SRC_WIZNET := \ + common-hal/wiznet/wizchip_pio_spi.c \ + +WIZNET_PIOASM = $(BUILD)/pioasm/pioasm/pioasm +.PHONY: pioasmBuild +pioasmBuild: $(WIZNET_PIOASM) + +$(WIZNET_PIOASM): + $(Q)cmake -S pioasm -B $(BUILD)/pioasm + $(MAKE) -C $(BUILD)/pioasm pioasmBuild + +$(BUILD)/wizchip_pio_spi.pio.h: common-hal/wiznet/wizchip_pio_spi.pio $(WIZNET_PIOASM) + $(Q)$(WIZNET_PIOASM) -o c-sdk $< $@ +$(BUILD)/common-hal/wiznet/wizchip_pio_spi.o: $(BUILD)/wizchip_pio_spi.pio.h + +$(BUILD)/genhdr/qstr.i.last: $(BUILD)/wizchip_pio_spi.pio.h + +else +INC_WIZNET := +SRC_WIZNET := + +endif + CHIP_VARIANT_LOWER = $(shell echo $(CHIP_VARIANT) | tr '[:upper:]' '[:lower:]') INC += \ @@ -229,6 +256,10 @@ DISABLE_WARNINGS = -Wno-cast-align CFLAGS += $(INC) -Wtype-limits -Wall -Werror -std=gnu11 -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) -Werror=missing-prototypes -Wold-style-definition PICO_LDFLAGS = --specs=nosys.specs --specs=nano.specs +# The SDK's panic() is flash-resident, but core1 may run with flash access +# disabled by the MPU. Route panics to the RAM-resident __wrap_panic in +# supervisor/port.c, which halts safely on core1 and prints on core0. +PICO_LDFLAGS += -Wl,--wrap=panic # Use toolchain libm if we're not using our own. ifndef INTERNAL_LIBM @@ -396,6 +427,8 @@ OTHER_PICO_FLAGS := \ -Wl,--wrap=__aeabi_uidivmod \ -Wl,--wrap=__aeabi_uldivmod +SRC_S = shared/runtime/gchelper_thumb1.s + ifeq ($(CHIP_VARIANT),RP2040) CFLAGS += \ -march=armv6-m \ @@ -405,8 +438,7 @@ CFLAGS += \ -msoft-float \ -mfloat-abi=soft -CFLAGS += \ - -DPICO_RP2040 +CFLAGS += -DPICO_RP2040=1 -DPICO_RP2350=0 SRC_SDK_CHIP_VARIANT := \ src/rp2_common/hardware_rtc/rtc.c \ @@ -434,12 +466,12 @@ UF2_ID = 0xE48BFF56 DOUBLE_EABI = rp2040 endif ifeq ($(CHIP_VARIANT),RP2350) -CFLAGS += \ - -march=armv8-m.main+fp+dsp \ +AFLAGS = -march=armv8-m.main+fp+dsp \ -mthumb \ - -mabi=aapcs-linux \ -mcpu=cortex-m33 \ -mfloat-abi=softfp +CFLAGS += $(AFLAGS) \ + -mabi=aapcs-linux # ARM Secure family id UF2_ID = 0xe48bff59 @@ -449,7 +481,7 @@ DOUBLE_EABI = dcp INC += \ -isystem sdk/src/rp2_common/hardware_dcp/include/ -CFLAGS += -DPICO_RP2350=1 +CFLAGS += -DPICO_RP2040=0 -DPICO_RP2350=1 SRC_SDK_CHIP_VARIANT := \ src/rp2_common/hardware_powman/powman.c \ @@ -473,6 +505,14 @@ endif endif +SRC_C += shared/runtime/gchelper_native.c + +ifeq ($(CIRCUITPY_PICOGAME),1) +# SIO interpolator fast path for the picogame mode7 inner row (RP2040 + RP2350). +# Portable C remains the fallback on other ports. +SRC_C += common-hal/picogame/interp.c +CFLAGS += -DPICOGAME_HAS_INTERP=1 +endif SRC_SDK := \ src/common/hardware_claim/claim.c \ @@ -531,10 +571,15 @@ $(patsubst %.c,$(BUILD)/%.o,$(SRC_SDK) $(SRC_CYW43)): CFLAGS += -Wno-missing-pro SRC_C += \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ + common-hal/rtc/pico_time.c \ bindings/rp2pio/StateMachine.c \ bindings/rp2pio/__init__.c \ common-hal/rp2pio/StateMachine.c \ common-hal/rp2pio/__init__.c \ + bindings/wiznet/PIO_SPI.c \ + bindings/wiznet/__init__.c \ + common-hal/wiznet/PIO_SPI.c \ + common-hal/wiznet/__init__.c \ audio_dma.c \ background.c \ peripherals/pins.c \ @@ -544,6 +589,7 @@ SRC_C += \ mphalport.c \ $(SRC_CYW43) \ $(SRC_LWIP) \ + $(SRC_WIZNET) \ ifeq ($(CIRCUITPY_USB_HOST), 1) @@ -555,6 +601,12 @@ SRC_C += \ INC += \ -isystem lib/Pico-PIO-USB/src + +# Core1 posts USB events while core0 may hold the TinyUSB queue mutex. The +# contended wait path calls these two flash-resident SDK functions, and core1 +# must not execute from flash. Replace them with RAM-resident implementations +# in common-hal/usb_host/Port.c on USB host builds only. See issue #11116. +PICO_LDFLAGS += -Wl,--wrap=best_effort_wfe_or_timeout -Wl,--wrap=time_us_64 endif ifeq ($(CIRCUITPY_PICODVI),1) @@ -578,90 +630,106 @@ endif endif +ifeq ($(CIRCUITPY_SDIOIO),1) +# Vendored Adafruit SdFat PIO SDIO card driver (C++). The common-hal C sources +# (SDCard.c, __init__.c) are picked up automatically through SRC_COMMON_HAL. +SRC_SDIOIO_CXX := \ + common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp \ + common-hal/sdioio/sdfat_pio/shim.cpp \ + common-hal/sdioio/sdfat_pio/cxx_runtime.cpp \ + +INC += -Icommon-hal/sdioio/sdfat_pio + +# The upstream driver body is guarded by ARDUINO_ARCH_RP2040 and was written +# against the Arduino RP2040 core, so define that macro for it. It is vendored +# third-party code, so don't fail the build on its warnings. +$(BUILD)/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.o: CXXFLAGS += -DARDUINO_ARCH_RP2040 -Wno-error +endif + ifeq ($(CIRCUITPY_SSL),1) -CFLAGS += -isystem $(TOP)/mbedtls/include -SRC_MBEDTLS := $(addprefix lib/mbedtls/library/, \ - aes.c \ - aesni.c \ - arc4.c \ - asn1parse.c \ - asn1write.c \ - base64.c \ - bignum.c \ - blowfish.c \ - camellia.c \ - ccm.c \ - certs.c \ - chacha20.c \ - chachapoly.c \ - cipher.c \ - cipher_wrap.c \ - cmac.c \ - constant_time.c \ - ctr_drbg.c \ - debug.c \ - des.c \ - dhm.c \ - ecdh.c \ - ecdsa.c \ - ecjpake.c \ - ecp.c \ - ecp_curves.c \ - entropy.c \ - entropy_poll.c \ - gcm.c \ - havege.c \ - hmac_drbg.c \ - md2.c \ - md4.c \ - md5.c \ - md.c \ - oid.c \ - padlock.c \ - pem.c \ - pk.c \ - pkcs11.c \ - pkcs12.c \ - pkcs5.c \ - pkparse.c \ - pk_wrap.c \ - pkwrite.c \ - platform.c \ - platform_util.c \ - poly1305.c \ - ripemd160.c \ - rsa.c \ - rsa_internal.c \ - sha1.c \ - sha256.c \ - sha512.c \ - ssl_cache.c \ - ssl_ciphersuites.c \ - ssl_cli.c \ - ssl_cookie.c \ - ssl_msg.c \ - ssl_srv.c \ - ssl_ticket.c \ - ssl_tls.c \ - timing.c \ - x509.c \ - x509_create.c \ - x509_crl.c \ - x509_crt.c \ - x509_csr.c \ - x509write_crt.c \ - x509write_csr.c \ - xtea.c \ - ) +# mbedtls 4.x keeps only TLS and X.509 in library/; crypto lives in the tf-psa-crypto +# submodule, split across core/, drivers/builtin/src/, extras/, platform/ and +# utilities/. +# +# Deliberately excluded: +# - mbedtls_config.c, tf_psa_crypto_config.c: pure config-validation translation +# units that #include generated *_config_check_*.h headers. Skipping them is what +# lets us skip that second code generator. +# - net_sockets.c: CircuitPython drives the socket through socketpool callbacks. +# - pkcs7.c: unused, and MBEDTLS_PKCS7_C is off. +# - psa_its_file.c: filesystem-backed PSA key storage; we have no persistent keys. +# - drivers/{everest,p256-m,pqcp}: alternative curve and ML-DSA implementations. +mbedtls_sources = $(patsubst $(TOP)/%,%,$(filter-out $(2),$(wildcard $(TOP)/$(1)/*.c))) + +SRC_MBEDTLS := \ + $(call mbedtls_sources,lib/mbedtls/library,\ + $(TOP)/lib/mbedtls/library/mbedtls_config.c \ + $(TOP)/lib/mbedtls/library/net_sockets.c \ + $(TOP)/lib/mbedtls/library/pkcs7.c) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/core,\ + $(TOP)/lib/mbedtls/tf-psa-crypto/core/psa_its_file.c \ + $(TOP)/lib/mbedtls/tf-psa-crypto/core/tf_psa_crypto_config.c) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/drivers/builtin/src) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/extras) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/platform) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/utilities) SRC_C += $(SRC_MBEDTLS) lib/mbedtls_config/mbedtls_port.c lib/mbedtls_config/crt_bundle.c +# Public headers of mbedtls and of tf-psa-crypto, then the internal ones. mbedtls 4.x +# still reaches into tf-psa-crypto's internals, so upstream compiles the TLS layer +# with both; see TF_PSA_CRYPTO_LIBRARY_{PUBLIC,PRIVATE}_INCLUDE in +# lib/mbedtls/tf-psa-crypto/scripts/crypto-common.make. CFLAGS += \ -isystem $(TOP)/lib/mbedtls/include \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/include \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/drivers/builtin/include \ + -isystem $(TOP)/lib/mbedtls/library \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/core \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/dispatch \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/drivers/builtin/src \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/extras \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/platform \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/utilities \ -DMBEDTLS_CONFIG_FILE='"$(TOP)/lib/mbedtls_config/mbedtls_config.h"' \ + -DTF_PSA_CRYPTO_CONFIG_FILE='"$(TOP)/lib/mbedtls_config/tf_psa_crypto_config.h"' \ $(BUILD)/x509_crt_bundle.S: $(TOP)/lib/certificates/data/roots-full.pem $(TOP)/tools/gen_crt_bundle.py $(Q)$(PYTHON) $(TOP)/tools/gen_crt_bundle.py -i $< -o $@ --asm OBJ_MBEDTLS := $(BUILD)/x509_crt_bundle.o -$(patsubst %.c,$(BUILD)/%.o,$(SRC_MBEDTLS))): CFLAGS += -Wno-suggest-attribute=format + +# mbedtls 4.x dispatches PSA crypto through a wrapper layer that is generated from +# jinja templates rather than shipped in the repo, so build it. +# It is the same each time, so we could save it, but this makes updating mbedtls easier. +# +# generate_driver_wrappers.py resolves `mbedtls_framework` relative to its own tree, +# which would mean initializing a third nested submodule (tf-psa-crypto/framework). +# Point PYTHONPATH at the top-level framework submodule instead; mbedtls pins both to +# the same commit. +MBEDTLS_GEN := $(BUILD)/tf-psa-crypto +MBEDTLS_WRAPPERS_H := $(MBEDTLS_GEN)/psa_crypto_driver_wrappers.h +MBEDTLS_WRAPPERS_C := $(MBEDTLS_GEN)/psa_crypto_driver_wrappers_no_static.c + +# The script writes both files at once. Naming both as targets of one rule would run +# it twice; see the same workaround in py/py.mk. +$(MBEDTLS_WRAPPERS_C): $(MBEDTLS_WRAPPERS_H) + @true + +$(MBEDTLS_WRAPPERS_H): $(TOP)/lib/mbedtls/tf-psa-crypto/scripts/generate_driver_wrappers.py + $(STEPECHO) "GEN $@" + $(Q)mkdir -p $(MBEDTLS_GEN) + $(Q)PYTHONPATH=$(TOP)/lib/mbedtls/framework/scripts $(PYTHON) $< $(MBEDTLS_GEN) + +OBJ_MBEDTLS += $(MBEDTLS_WRAPPERS_C:.c=.o) +CFLAGS += -I$(MBEDTLS_GEN) + +# psa_crypto.c and friends #include the generated header, so it has to exist before +# any of them compile. +$(patsubst %.c,$(BUILD)/%.o,$(SRC_MBEDTLS)) $(OBJ_MBEDTLS): $(MBEDTLS_WRAPPERS_H) +# Vendored third-party code, so don't hold it to CircuitPython's warning settings. The +# unused-but-set variables are real but harmless: they are in key-exchange paths that +# are compiled out. +$(patsubst %.c,$(BUILD)/%.o,$(SRC_MBEDTLS)) $(OBJ_MBEDTLS): CFLAGS += \ + -Wno-suggest-attribute=format \ + -Wno-unused-but-set-variable else OBJ_MBEDTLS := endif @@ -672,7 +740,6 @@ SRC_S_UPPER = sdk/src/rp2_common/hardware_irq/irq_handler_chain.S \ sdk/src/rp2_common/pico_double/double_aeabi_$(DOUBLE_EABI).S \ sdk/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S \ sdk/src/rp2_common/pico_crt0/crt0.S \ - supervisor/shared/cpu_regs.S \ $(SRC_S_UPPER_CHIP_VARIANT) ifeq ($(CIRCUITPY_PICODVI),1) @@ -682,6 +749,11 @@ endif $(patsubst %.S,$(BUILD)/%.o,$(SRC_S_UPPER)): CFLAGS += -Wno-undef +# py/mkrules.mk derives CXXFLAGS from CFLAGS, which gives the vendored C++ +# translation unit the SDK include paths and defines. Only the C++-specific +# options belong here. +CXXFLAGS += -std=gnu++17 -fno-exceptions -fno-rtti + OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_SDK:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) @@ -694,6 +766,9 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) OBJ += $(BUILD)/boot2_padded_checksummed.o OBJ += $(OBJ_MBEDTLS) +ifeq ($(CIRCUITPY_SDIOIO),1) +OBJ += $(addprefix $(BUILD)/, $(SRC_SDIOIO_CXX:.cpp=.o)) +endif $(BUILD)/%.o: $(BUILD)/%.S $(STEPECHO) "CC $<" @@ -736,6 +811,21 @@ endif LINKER_SCRIPTS += -Wl,-T,link-$(CHIP_VARIANT_LOWER).ld +# Builds where core1 locks flash out via the MPU and may only execute +# RAM-resident code: USB host (PIO-USB frame loop), and picodvi on RP2040 +# (TMDS encode loop). Check the linked ELF from each core1 entry point. +# picodvi's DMA IRQ handler and scanline callback run on core1 but are +# reached only through registered pointers, so they are extra roots. +CORE1_CHECK_ROOTS := +ifeq ($(CIRCUITPY_USB_HOST),1) +CORE1_CHECK_ROOTS += --root core1_main +endif +ifeq ($(CHIP_VARIANT),RP2040) +ifeq ($(CIRCUITPY_PICODVI),1) +CORE1_CHECK_ROOTS += --root core1_main --root dvi_dma1_irq --root core1_scanline_callback +endif +endif + ifeq ($(VALID_BOARD),) $(BUILD)/firmware.elf: invalid-board else @@ -744,6 +834,11 @@ $(BUILD)/firmware.elf: $(OBJ) $(BOARD_LD) link-$(CHIP_VARIANT_LOWER).ld $(Q)echo $(OBJ) > $(BUILD)/firmware.objs $(Q)echo $(PICO_LDFLAGS) > $(BUILD)/firmware.ldflags $(Q)$(CC) -o $@ $(CFLAGS) @$(BUILD)/firmware.ldflags $(LINKER_SCRIPTS) -Wl,--print-memory-usage -Wl,-Map=$@.map -Wl,-cref -Wl,--gc-sections @$(BUILD)/firmware.objs -Wl,-lc + $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $@.map $(BUILD) +ifneq ($(CORE1_CHECK_ROOTS),) + $(STEPECHO) "CHECK core1 flash calls" + $(Q)$(PYTHON) $(TOP)/tools/check_core1_flash_calls.py $@ $(CORE1_CHECK_ROOTS) +endif endif $(BUILD)/firmware.bin: $(BUILD)/firmware.elf diff --git a/ports/raspberrypi/audio_dma.c b/ports/raspberrypi/audio_dma.c index ae3997a128f..8b2f78266e3 100644 --- a/ports/raspberrypi/audio_dma.c +++ b/ports/raspberrypi/audio_dma.c @@ -9,18 +9,23 @@ #include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/WaveFile.h" #include "shared-bindings/microcontroller/__init__.h" -#include "bindings/rp2pio/StateMachine.h" #include "supervisor/background_callback.h" #include "py/mpstate.h" #include "py/runtime.h" #include "hardware/irq.h" -#include "hardware/regs/intctrl.h" // For isr_ macro. #if CIRCUITPY_AUDIOCORE +// audio_dma and rp2pio cooperate on DMA_IRQ_0 using the SDK's shared interrupt +// handlers. We add our handler when we enable our first channel and remove it +// when our last channel is disabled. See the DMA IRQ allocation notes in +// common-hal/microcontroller/__init__.c. +static void audio_dma_enable_irq(uint channel); +static void audio_dma_disable_irq(uint channel); + void audio_dma_reset(void) { for (size_t channel = 0; channel < NUM_DMA_CHANNELS; channel++) { if (MP_STATE_PORT(playing_audio)[channel] == NULL) { @@ -222,6 +227,7 @@ audio_dma_result audio_dma_setup_playback( uint32_t max_buffer_length; audiosample_get_buffer_structure(sample, single_channel_output, &single_buffer, &samples_signed, &max_buffer_length, &dma->sample_spacing); + dma->single_buffer = single_buffer; // Check to see if we have to scale the resolution up. if (dma->sample_resolution <= 8 && dma->output_resolution > 8) { @@ -233,7 +239,7 @@ audio_dma_result audio_dma_setup_playback( max_buffer_length /= dma->sample_spacing; } - #ifdef PICO_RP2350 + #if PICO_RP2350 dma->buffer[0] = (uint8_t *)port_realloc(dma->buffer[0], max_buffer_length, true); #else dma->buffer[0] = (uint8_t *)m_realloc(dma->buffer[0], @@ -249,7 +255,7 @@ audio_dma_result audio_dma_setup_playback( } if (!single_buffer) { - #ifdef PICO_RP2350 + #if PICO_RP2350 dma->buffer[1] = (uint8_t *)port_realloc(dma->buffer[1], max_buffer_length, true); #else dma->buffer[1] = (uint8_t *)m_realloc(dma->buffer[1], @@ -335,12 +341,10 @@ audio_dma_result audio_dma_setup_playback( 1, // transaction count false); // trigger } else { - // Clear any latent interrupts so that we don't immediately disable channels. - dma_hw->ints0 |= (1 << dma->channel[0]) | (1 << dma->channel[1]); // Enable our DMA channels on DMA_IRQ_0 to the CPU. This will wake us up when // we're WFI. - dma_hw->inte0 |= (1 << dma->channel[0]) | (1 << dma->channel[1]); - irq_set_mask_enabled(1 << DMA_IRQ_0, true); + audio_dma_enable_irq(dma->channel[0]); + audio_dma_enable_irq(dma->channel[1]); } dma->playing_in_progress = true; @@ -353,16 +357,11 @@ void audio_dma_stop(audio_dma_t *dma) { dma->paused = true; // Disable our interrupts. - uint32_t channel_mask = 0; if (dma->channel[0] < NUM_DMA_CHANNELS) { - channel_mask |= 1 << dma->channel[0]; + audio_dma_disable_irq(dma->channel[0]); } if (dma->channel[1] < NUM_DMA_CHANNELS) { - channel_mask |= 1 << dma->channel[1]; - } - dma_hw->inte0 &= ~channel_mask; - if (!dma_hw->inte0) { - irq_set_mask_enabled(1 << DMA_IRQ_0, false); + audio_dma_disable_irq(dma->channel[1]); } // Run any remaining audio tasks because we remove ourselves from @@ -460,7 +459,7 @@ void audio_dma_init(audio_dma_t *dma) { } void audio_dma_deinit(audio_dma_t *dma) { - #ifdef PICO_RP2350 + #if PICO_RP2350 port_free(dma->buffer[0]); #else #if MICROPY_MALLOC_USES_ALLOCATED_SIZE @@ -472,7 +471,7 @@ void audio_dma_deinit(audio_dma_t *dma) { dma->buffer[0] = NULL; dma->buffer_length[0] = 0; - #ifdef PICO_RP2350 + #if PICO_RP2350 port_free(dma->buffer[1]); #else #if MICROPY_MALLOC_USES_ALLOCATED_SIZE @@ -489,6 +488,15 @@ bool audio_dma_get_playing(audio_dma_t *dma) { if (dma->channel[0] == NUM_DMA_CHANNELS) { return false; } + // A single-buffer, non-looping sample plays entirely in hardware via DMA + // chaining, with no completion interrupt to stop it. Detect when its DMA + // channel has drained and finish so that playing_in_progress is cleared. + if (dma->single_buffer && !dma->loop && + dma->playing_in_progress && !dma->paused && + !dma_channel_is_busy(dma->channel[0])) { + audio_dma_stop(dma); + return false; + } return dma->playing_in_progress; } @@ -532,34 +540,59 @@ static void dma_callback_fun(void *arg) { } } -void __not_in_flash_func(isr_dma_0)(void) { +// Shared DMA_IRQ_0 handler for audio. It acknowledges and services only audio +// channels, leaving any other channels' interrupts for the other shared +// handlers (e.g. rp2pio) to acknowledge. +static void __not_in_flash_func(audio_dma_irq_handler)(void) { for (size_t i = 0; i < NUM_DMA_CHANNELS; i++) { uint32_t mask = 1 << i; if ((dma_hw->ints0 & mask) == 0) { continue; } + audio_dma_t *dma = MP_STATE_PORT(playing_audio)[i]; + if (dma == NULL) { + // Not one of our channels; leave it for another shared handler. + continue; + } // acknowledge interrupt early. Doing so late means that you could lose an // interrupt if the buffer is very small and the DMA operation // completed by the time callback_add() / dma_complete() returned. This // affected PIO continuous write more than audio. dma_hw->ints0 = mask; - if (MP_STATE_PORT(playing_audio)[i] != NULL) { - audio_dma_t *dma = MP_STATE_PORT(playing_audio)[i]; - // Record all channels whose DMA has completed; they need loading. - dma->channels_to_load_mask |= mask; - // Disable the channel so that we don't play it without filling it. - dma_hw->ch[i].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS; - // This is a noop if the callback is already queued. - background_callback_add(&dma->callback, dma_callback_fun, (void *)dma); - } - if (MP_STATE_PORT(background_pio_read)[i] != NULL) { - rp2pio_statemachine_obj_t *pio = MP_STATE_PORT(background_pio_read)[i]; - rp2pio_statemachine_dma_complete_read(pio, i); - } - if (MP_STATE_PORT(background_pio_write)[i] != NULL) { - rp2pio_statemachine_obj_t *pio = MP_STATE_PORT(background_pio_write)[i]; - rp2pio_statemachine_dma_complete_write(pio, i); - } + // Record all channels whose DMA has completed; they need loading. + dma->channels_to_load_mask |= mask; + // Disable the channel so that we don't play it without filling it. + dma_hw->ch[i].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS; + // This is a noop if the callback is already queued. + background_callback_add(&dma->callback, dma_callback_fun, (void *)dma); + } +} + +// Channels (bitmask) audio currently has enabled on DMA_IRQ_0. Used to decide +// when to add/remove our shared interrupt handler. +static uint32_t audio_dma_irq0_channel_mask = 0; + +static void audio_dma_enable_irq(uint channel) { + // Clear any latent interrupt so that we don't immediately disable the channel. + dma_hw->ints0 = 1u << channel; + if (audio_dma_irq0_channel_mask == 0) { + irq_add_shared_handler(DMA_IRQ_0, audio_dma_irq_handler, + PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); + } + audio_dma_irq0_channel_mask |= 1u << channel; + dma_irqn_set_channel_enabled(0, channel, true); + irq_set_enabled(DMA_IRQ_0, true); +} + +static void audio_dma_disable_irq(uint channel) { + dma_irqn_set_channel_enabled(0, channel, false); + audio_dma_irq0_channel_mask &= ~(1u << channel); + if (audio_dma_irq0_channel_mask == 0) { + irq_remove_handler(DMA_IRQ_0, audio_dma_irq_handler); + } + // Turn off the IRQ line entirely once no one (audio or rp2pio) needs it. + if (dma_hw->inte0 == 0) { + irq_set_enabled(DMA_IRQ_0, false); } } diff --git a/ports/raspberrypi/audio_dma.h b/ports/raspberrypi/audio_dma.h index cd892f5151b..57e47c7444e 100644 --- a/ports/raspberrypi/audio_dma.h +++ b/ports/raspberrypi/audio_dma.h @@ -33,6 +33,7 @@ typedef struct { uint8_t sample_resolution; // in bits audio_dma_result dma_result; bool loop; + bool single_buffer; bool single_channel_output; bool signed_to_unsigned; bool unsigned_to_signed; diff --git a/ports/raspberrypi/bindings/picodvi/Framebuffer.c b/ports/raspberrypi/bindings/picodvi/Framebuffer.c index 9cd66ad7e2a..e80ffea470c 100644 --- a/ports/raspberrypi/bindings/picodvi/Framebuffer.c +++ b/ports/raspberrypi/bindings/picodvi/Framebuffer.c @@ -189,9 +189,27 @@ MP_DEFINE_CONST_FUN_OBJ_1(picodvi_framebuffer_get_color_depth_obj, picodvi_frame MP_PROPERTY_GETTER(picodvi_framebuffer_color_depth_obj, (mp_obj_t)&picodvi_framebuffer_get_color_depth_obj); +//| def wait_for_vblank(self) -> None: +//| """Block until the next frame boundary (vertical blank), then return. Call this right +//| before a full-framebuffer repaint so the repaint starts at the top of scanout and races +//| ahead of the beam, avoiding tearing without a second framebuffer. The repaint must +//| complete faster than one scanout sweep (~16 ms at 60 Hz) to stay ahead of the beam; +//| if it cannot (e.g. a full 640x480 ``displayio`` refresh), use a lower resolution or +//| repaint a smaller area. Bounded by a short timeout, so it is safe even if no DVI +//| signal is active. No-op on the RP2040 PIO-DVI path.""" +//| ... +static mp_obj_t picodvi_framebuffer_wait_for_vblank(mp_obj_t self_in) { + picodvi_framebuffer_obj_t *self = (picodvi_framebuffer_obj_t *)self_in; + check_for_deinit(self); + common_hal_picodvi_framebuffer_wait_for_vblank(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picodvi_framebuffer_wait_for_vblank_obj, picodvi_framebuffer_wait_for_vblank); + static const mp_rom_map_elem_t picodvi_framebuffer_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&picodvi_framebuffer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_wait_for_vblank), MP_ROM_PTR(&picodvi_framebuffer_wait_for_vblank_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&picodvi_framebuffer_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&picodvi_framebuffer_height_obj) }, diff --git a/ports/raspberrypi/bindings/picodvi/Framebuffer.h b/ports/raspberrypi/bindings/picodvi/Framebuffer.h index 7eb7780ee49..d5f59fe84c3 100644 --- a/ports/raspberrypi/bindings/picodvi/Framebuffer.h +++ b/ports/raspberrypi/bindings/picodvi/Framebuffer.h @@ -25,6 +25,7 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self, void common_hal_picodvi_framebuffer_deinit(picodvi_framebuffer_obj_t *self); bool common_hal_picodvi_framebuffer_deinited(picodvi_framebuffer_obj_t *self); void common_hal_picodvi_framebuffer_refresh(picodvi_framebuffer_obj_t *self); +void common_hal_picodvi_framebuffer_wait_for_vblank(picodvi_framebuffer_obj_t *self); int common_hal_picodvi_framebuffer_get_width(picodvi_framebuffer_obj_t *self); int common_hal_picodvi_framebuffer_get_height(picodvi_framebuffer_obj_t *self); int common_hal_picodvi_framebuffer_get_row_stride(picodvi_framebuffer_obj_t *self); diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.h b/ports/raspberrypi/bindings/rp2pio/StateMachine.h index 16f884bcfca..3c775a96449 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.h +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.h @@ -62,6 +62,18 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s bool common_hal_rp2pio_statemachine_stop_background_write(rp2pio_statemachine_obj_t *self); bool common_hal_rp2pio_statemachine_stop_background_read(rp2pio_statemachine_obj_t *self); +// Set the once / loop / loop2 read buffers from raw pointers without going +// through an mp_obj_t wrapper. Pass NULL/0 for unused slots. The caller owns +// the memory; it must remain valid until stop_background_read. +void common_hal_rp2pio_statemachine_set_read_buffers_raw(rp2pio_statemachine_obj_t *self, + void *once, size_t once_len, + void *loop, size_t loop_len, + void *loop2, size_t loop2_len); + +// Returns the DMA channel index used by the current background read, or -1 +// if no background read is active. +int common_hal_rp2pio_statemachine_get_read_dma_channel(rp2pio_statemachine_obj_t *self); + mp_int_t common_hal_rp2pio_statemachine_get_pending_write(rp2pio_statemachine_obj_t *self); mp_int_t common_hal_rp2pio_statemachine_get_pending_read(rp2pio_statemachine_obj_t *self); diff --git a/ports/raspberrypi/bindings/wiznet/PIO_SPI.c b/ports/raspberrypi/bindings/wiznet/PIO_SPI.c new file mode 100755 index 00000000000..1f860fc9979 --- /dev/null +++ b/ports/raspberrypi/bindings/wiznet/PIO_SPI.c @@ -0,0 +1,299 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft +// +// SPDX-License-Identifier: MIT + +// TODO: wiznet.PIO_SPI class. +// This file contains all of the Python API definitions for the +// wiznet.PIO_SPI class. + +#include + +#include "shared-bindings/microcontroller/Pin.h" +#include "bindings/wiznet/PIO_SPI.h" +#include "shared-bindings/util.h" + +#include "shared/runtime/buffer_helper.h" +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/mperrno.h" +#include "py/objproperty.h" +#include "py/runtime.h" + + +// TODO: class WIZNET_PIO_SPI + + +static mp_obj_t wiznet_pio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + #if CIRCUITPY_WIZNET + wiznet_pio_spi_obj_t *self = mp_obj_malloc(wiznet_pio_spi_obj_t, &wiznet_pio_spi_type); + enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_half_duplex, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + 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 mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *mosi = validate_obj_is_free_pin_or_none(args[ARG_MOSI].u_obj, MP_QSTR_mosi); + const mcu_pin_obj_t *miso = validate_obj_is_free_pin_or_none(args[ARG_MISO].u_obj, MP_QSTR_miso); + + if (!miso && !mosi) { + mp_raise_ValueError(MP_ERROR_TEXT("Must provide MISO or MOSI pin")); + } + + common_hal_wiznet_pio_spi_construct(self, clock, mosi, miso, args[ARG_half_duplex].u_bool); + return MP_OBJ_FROM_PTR(self); + #else + mp_raise_NotImplementedError(NULL); + #endif // CIRCUITPY_WIZNET +} + +#if CIRCUITPY_WIZNET + +// TODO: def deinit + +static mp_obj_t wiznet_pio_spi_obj_deinit(mp_obj_t self_in) { + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_wiznet_pio_spi_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_deinit_obj, wiznet_pio_spi_obj_deinit); + +// TODO: def __enter__ + +// TODO: def __exit__ + +static void check_lock(wiznet_pio_spi_obj_t *self) { + asm (""); + if (!common_hal_wiznet_pio_spi_has_lock(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Function requires lock")); + } +} + +static void check_for_deinit(wiznet_pio_spi_obj_t *self) { + if (common_hal_wiznet_pio_spi_deinited(self)) { + raise_deinited_error(); + } +} + +// TODO: def configure + +static mp_obj_t wiznet_pio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + }; + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + check_lock(self); + 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 polarity = (uint8_t)mp_arg_validate_int_range(args[ARG_polarity].u_int, 0, 1, MP_QSTR_polarity); + uint8_t phase = (uint8_t)mp_arg_validate_int_range(args[ARG_phase].u_int, 0, 1, MP_QSTR_phase); + uint8_t bits = (uint8_t)mp_arg_validate_int_range(args[ARG_bits].u_int, 8, 9, MP_QSTR_bits); + + if (!common_hal_wiznet_pio_spi_configure(self, args[ARG_baudrate].u_int, + polarity, phase, bits)) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_configure_obj, 1, wiznet_pio_spi_configure); + +// TODO: def try_lock + +static mp_obj_t wiznet_pio_spi_obj_try_lock(mp_obj_t self_in) { + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_wiznet_pio_spi_try_lock(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_try_lock_obj, wiznet_pio_spi_obj_try_lock); + +// TODO: def unlock + +static mp_obj_t wiznet_pio_spi_obj_unlock(mp_obj_t self_in) { + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_wiznet_pio_spi_unlock(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_unlock_obj, wiznet_pio_spi_obj_unlock); + +// TODO: def write + +static mp_obj_t wiznet_pio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + check_lock(self); + 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_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); + // Compute bounds in terms of elements, not bytes. + int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); + int32_t start = args[ARG_start].u_int; + size_t length = bufinfo.len / stride_in_bytes; + normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + + // Treat start and length in terms of bytes from now on. + start *= stride_in_bytes; + length *= stride_in_bytes; + + if (length == 0) { + return mp_const_none; + } + + bool ok = common_hal_wiznet_pio_spi_write(self, ((uint8_t *)bufinfo.buf) + start, length); + + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_write_obj, 1, wiznet_pio_spi_write); + +// TODO: def readinto + +static mp_obj_t wiznet_pio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_write_value, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + check_lock(self); + 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_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); + // Compute bounds in terms of elements, not bytes. + int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); + int32_t start = args[ARG_start].u_int; + size_t length = bufinfo.len / stride_in_bytes; + normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + + // Treat start and length in terms of bytes from now on. + start *= stride_in_bytes; + length *= stride_in_bytes; + + if (length == 0) { + return mp_const_none; + } + + bool ok = common_hal_wiznet_pio_spi_read(self, ((uint8_t *)bufinfo.buf) + start, length, args[ARG_write_value].u_int); + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_readinto_obj, 1, wiznet_pio_spi_readinto); + + +// TODO: def write_readinto + +static mp_obj_t wiznet_pio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + check_lock(self); + 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_buffer_info_t buf_out_info; + mp_get_buffer_raise(args[ARG_out_buffer].u_obj, &buf_out_info, MP_BUFFER_READ); + int out_stride_in_bytes = mp_binary_get_size('@', buf_out_info.typecode, NULL); + int32_t out_start = args[ARG_out_start].u_int; + size_t out_length = buf_out_info.len / out_stride_in_bytes; + normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length); + + mp_buffer_info_t buf_in_info; + mp_get_buffer_raise(args[ARG_in_buffer].u_obj, &buf_in_info, MP_BUFFER_WRITE); + int in_stride_in_bytes = mp_binary_get_size('@', buf_in_info.typecode, NULL); + int32_t in_start = args[ARG_in_start].u_int; + size_t in_length = buf_in_info.len / in_stride_in_bytes; + normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length); + + // Treat start and length in terms of bytes from now on. + out_start *= out_stride_in_bytes; + out_length *= out_stride_in_bytes; + in_start *= in_stride_in_bytes; + in_length *= in_stride_in_bytes; + + if (out_length != in_length) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer slices must be of equal length")); + } + + if (out_length == 0) { + return mp_const_none; + } + + bool ok = common_hal_wiznet_pio_spi_transfer(self, + ((uint8_t *)buf_out_info.buf) + out_start, + ((uint8_t *)buf_in_info.buf) + in_start, + out_length); + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_write_readinto_obj, 1, wiznet_pio_spi_write_readinto); + +#endif // CIRCUITPY_WIZNET + +static const mp_rom_map_elem_t wiznet_pio_spi_locals_dict_table[] = { + #if CIRCUITPY_WIZNET + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&wiznet_pio_spi_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&wiznet_pio_spi_configure_obj) }, + { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&wiznet_pio_spi_try_lock_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&wiznet_pio_spi_unlock_obj) }, + + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&wiznet_pio_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&wiznet_pio_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&wiznet_pio_spi_write_readinto_obj) }, + + #endif // CIRCUITPY_WIZNET +}; +static MP_DEFINE_CONST_DICT(wiznet_pio_spi_locals_dict, wiznet_pio_spi_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + wiznet_pio_spi_type, + MP_QSTR_PIO_SPI, + MP_TYPE_FLAG_NONE, + make_new, wiznet_pio_spi_make_new, + locals_dict, &wiznet_pio_spi_locals_dict + ); + +wiznet_pio_spi_obj_t *validate_obj_is_wiznet_pio_spi_bus(mp_obj_t obj, qstr arg_name) { + return mp_arg_validate_type(obj, &wiznet_pio_spi_type, arg_name); +} diff --git a/ports/raspberrypi/bindings/wiznet/PIO_SPI.h b/ports/raspberrypi/bindings/wiznet/PIO_SPI.h new file mode 100755 index 00000000000..0289ac0767a --- /dev/null +++ b/ports/raspberrypi/bindings/wiznet/PIO_SPI.h @@ -0,0 +1,40 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/wiznet/PIO_SPI.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t wiznet_pio_spi_type; + +// Construct an underlying SPI object. +extern void common_hal_wiznet_pio_spi_construct(wiznet_pio_spi_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *miso, bool half_duplex); + +extern void common_hal_wiznet_pio_spi_deinit(wiznet_pio_spi_obj_t *self); +extern bool common_hal_wiznet_pio_spi_deinited(wiznet_pio_spi_obj_t *self); + +extern bool common_hal_wiznet_pio_spi_configure(wiznet_pio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits); + +extern bool common_hal_wiznet_pio_spi_try_lock(wiznet_pio_spi_obj_t *self); +extern bool common_hal_wiznet_pio_spi_has_lock(wiznet_pio_spi_obj_t *self); +extern void common_hal_wiznet_pio_spi_unlock(wiznet_pio_spi_obj_t *self); + +// Writes out the given data. +extern bool common_hal_wiznet_pio_spi_write(wiznet_pio_spi_obj_t *self, const uint8_t *data, size_t len); + +// Reads in len bytes while outputting the byte write_value. +extern bool common_hal_wiznet_pio_spi_read(wiznet_pio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value); + +// Reads and write len bytes simultaneously. +extern bool common_hal_wiznet_pio_spi_transfer(wiznet_pio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len); + +extern wiznet_pio_spi_obj_t *validate_obj_is_wiznet_pio_spi_bus(mp_obj_t obj_in, qstr arg_name); diff --git a/ports/raspberrypi/bindings/wiznet/__init__.c b/ports/raspberrypi/bindings/wiznet/__init__.c new file mode 100755 index 00000000000..6ed3c2886cc --- /dev/null +++ b/ports/raspberrypi/bindings/wiznet/__init__.c @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "bindings/wiznet/PIO_SPI.h" + +#include "py/runtime.h" + +static const mp_rom_map_elem_t wiznet_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_wiznet) }, + { MP_ROM_QSTR(MP_QSTR_PIO_SPI), MP_ROM_PTR(&wiznet_pio_spi_type) }, +}; + +static MP_DEFINE_CONST_DICT(wiznet_module_globals, wiznet_module_globals_table); + +const mp_obj_module_t wiznet_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&wiznet_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_wiznet, wiznet_module); diff --git a/ports/zephyr-cp/bindings/zephyr_serial/__init__.h b/ports/raspberrypi/bindings/wiznet/__init__.h old mode 100644 new mode 100755 similarity index 100% rename from ports/zephyr-cp/bindings/zephyr_serial/__init__.h rename to ports/raspberrypi/bindings/wiznet/__init__.h diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.h index 34360169423..4c500366dfc 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.h +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.h @@ -23,3 +23,11 @@ // #define CIRCUITPY_CONSOLE_UART_RX DEFAULT_UART_BUS_RX // #define CIRCUITPY_CONSOLE_UART_TX DEFAULT_UART_BUS_TX + +// Onboard microSD slot on SPI1. +#define DEFAULT_SD_SCK (&pin_GPIO18) +#define DEFAULT_SD_MOSI (&pin_GPIO19) +#define DEFAULT_SD_MISO (&pin_GPIO20) +#define DEFAULT_SD_CS (&pin_GPIO23) +#define DEFAULT_SD_CARD_DETECT (&pin_GPIO16) +#define DEFAULT_SD_CARD_INSERTED true diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.mk index 529853b22f5..cc0880ac544 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.mk @@ -7,3 +7,5 @@ CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ" + +CIRCUITPY_SDIOIO = 1 diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/pins.c b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/pins.c index 78d09407a65..1ab755f0aa1 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/pins.c +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/pins.c @@ -4,8 +4,21 @@ // // SPDX-License-Identifier: MIT +#include "py/objtuple.h" #include "shared-bindings/board/__init__.h" +// Four consecutive data GPIOs for the 4-bit SDIO interface (sdioio.SDCard). +static const mp_rom_obj_tuple_t sdio_data_tuple = { + {&mp_type_tuple}, + 4, + { + MP_ROM_PTR(&pin_GPIO20), + MP_ROM_PTR(&pin_GPIO21), + MP_ROM_PTR(&pin_GPIO22), + MP_ROM_PTR(&pin_GPIO23), + } +}; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -49,18 +62,26 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SD_CARD_DETECT), MP_ROM_PTR(&pin_GPIO16) }, { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_CLOCK), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO19) }, { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_COMMAND), MP_ROM_PTR(&pin_GPIO19) }, { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO20) }, { MP_ROM_QSTR(MP_QSTR_SD_DAT0), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA0), MP_ROM_PTR(&pin_GPIO20) }, { MP_ROM_QSTR(MP_QSTR_SD_DAT1), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA1), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_SD_DAT2), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA2), MP_ROM_PTR(&pin_GPIO22) }, { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO23) }, { MP_ROM_QSTR(MP_QSTR_SD_DAT3), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA3), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA), MP_ROM_PTR(&sdio_data_tuple) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk index 88cce7c4a4c..6ab89398de7 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk @@ -8,3 +8,6 @@ CHIP_PACKAGE = A CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ" + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c b/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c index 5056a4d9c7a..903ed6a9044 100644 --- a/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c +++ b/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c @@ -34,9 +34,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - CIRCUITPY_BOARD_TFT_DC, - CIRCUITPY_BOARD_TFT_CS, - NULL, // TFT_RESET Reset + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_DC), + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_CS), + mp_const_none, // TFT_RESET Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk index 31c4b130d0e..8c46cc0713b 100644 --- a/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk @@ -9,5 +9,10 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" +CIRCUITPY_SDIOIO = 1 + +CIRCUITPY_PICOGAME = 1 +CIRCUITPY_PICOGAME_FRAMEBUFFER = 1 + # CIRCUITPY_DISPLAY_FONT = $(TOP)/tools/fonts/unifont-16.0.02-all.bdf # CIRCUITPY_FONT_EXTRA_CHARACTERS = "🖮🖱️" diff --git a/ports/raspberrypi/boards/adafruit_fruit_jam/pins.c b/ports/raspberrypi/boards/adafruit_fruit_jam/pins.c index 82c4d19eb38..e6d41ae4989 100644 --- a/ports/raspberrypi/boards/adafruit_fruit_jam/pins.c +++ b/ports/raspberrypi/boards/adafruit_fruit_jam/pins.c @@ -4,8 +4,21 @@ // // SPDX-License-Identifier: MIT +#include "py/objtuple.h" #include "shared-bindings/board/__init__.h" +// Four consecutive data GPIOs for the 4-bit SDIO interface (sdioio.SDCard). +static const mp_rom_obj_tuple_t sdio_data_tuple = { + {&mp_type_tuple}, + 4, + { + MP_ROM_PTR(&pin_GPIO36), + MP_ROM_PTR(&pin_GPIO37), + MP_ROM_PTR(&pin_GPIO38), + MP_ROM_PTR(&pin_GPIO39), + } +}; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -91,6 +104,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO39) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA3), MP_ROM_PTR(&pin_GPIO39) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA), MP_ROM_PTR(&sdio_data_tuple) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CARD_DETECT), MP_ROM_PTR(&pin_GPIO33) }, { MP_ROM_QSTR(MP_QSTR_USB_HOST_DATA_PLUS), MP_ROM_PTR(&pin_GPIO1) }, diff --git a/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.mk index 965acff2775..781dfe46ad1 100644 --- a/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" diff --git a/ports/raspberrypi/boards/adafruit_kb2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_kb2040/mpconfigboard.mk index f9e1e2cf157..08c85bb3f46 100644 --- a/ports/raspberrypi/boards/adafruit_kb2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_kb2040/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" diff --git a/ports/raspberrypi/boards/adafruit_macropad_rp2040/board.c b/ports/raspberrypi/boards/adafruit_macropad_rp2040/board.c index 673d9303d6b..ec37b398e22 100644 --- a/ports/raspberrypi/boards/adafruit_macropad_rp2040/board.c +++ b/ports/raspberrypi/boards/adafruit_macropad_rp2040/board.c @@ -29,7 +29,7 @@ uint8_t display_init_sequence[] = { 0xda, 1, 0x12, // com pins 0x81, 1, 0xff, // contrast 255 0xd9, 1, 0x1f, // pre/dis-charge 2DCLKs/2CLKs - 0xdb, 1, 0x20, // VCOM deslect 0.770 + 0xdb, 1, 0x20, // VCOM select 0.770 0x20, 1, 0x20, 0x33, 0, // VPP 9V 0xa6, 0, // not inverted @@ -46,9 +46,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO24, // Command or data - &pin_GPIO22, // Chip select - &pin_GPIO23, // Reset + MP_OBJ_FROM_PTR(&pin_GPIO24), // Command or data + MP_OBJ_FROM_PTR(&pin_GPIO22), // Chip select + MP_OBJ_FROM_PTR(&pin_GPIO23), // Reset 10000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/adafruit_macropad_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_macropad_rp2040/mpconfigboard.mk index 4d708bcf794..ea3d5a80fb9 100644 --- a/ports/raspberrypi/boards/adafruit_macropad_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_macropad_rp2040/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.h index 4242599354c..fdbd18c0e66 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.h +++ b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.h @@ -20,3 +20,11 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO1) #define DEFAULT_UART_BUS_TX (&pin_GPIO0) + +// Onboard microSD slot. +#define DEFAULT_SD_SCK (&pin_GPIO18) +#define DEFAULT_SD_MOSI (&pin_GPIO19) +#define DEFAULT_SD_MISO (&pin_GPIO20) +#define DEFAULT_SD_CS (&pin_GPIO23) +#define DEFAULT_SD_CARD_DETECT (&pin_GPIO15) +#define DEFAULT_SD_CARD_INSERTED true diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk index 20c3042b7a1..8b3ce22c1bc 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk @@ -7,3 +7,5 @@ CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ,W25Q128JV" + +CIRCUITPY_SDIOIO = 1 diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c b/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c index 859e7cacb08..b541aea6f1f 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c +++ b/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c @@ -4,8 +4,21 @@ // // SPDX-License-Identifier: MIT +#include "py/objtuple.h" #include "shared-bindings/board/__init__.h" +// Four consecutive data GPIOs for the 4-bit SDIO interface (sdioio.SDCard). +static const mp_rom_obj_tuple_t sdio_data_tuple = { + {&mp_type_tuple}, + 4, + { + MP_ROM_PTR(&pin_GPIO20), + MP_ROM_PTR(&pin_GPIO21), + MP_ROM_PTR(&pin_GPIO22), + MP_ROM_PTR(&pin_GPIO23), + } +}; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -64,6 +77,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO23) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA3), MP_ROM_PTR(&pin_GPIO23) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA), MP_ROM_PTR(&sdio_data_tuple) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk index e43a8dcf2a3..6d499c367d7 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk @@ -8,3 +8,5 @@ CHIP_PACKAGE = B CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +CIRCUITPY_SDIOIO = 1 diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/pins.c b/ports/raspberrypi/boards/adafruit_metro_rp2350/pins.c index 3fa135b1796..a38c2496dd6 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2350/pins.c +++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/pins.c @@ -4,8 +4,21 @@ // // SPDX-License-Identifier: MIT +#include "py/objtuple.h" #include "shared-bindings/board/__init__.h" +// Four consecutive data GPIOs for the 4-bit SDIO interface (sdioio.SDCard). +static const mp_rom_obj_tuple_t sdio_data_tuple = { + {&mp_type_tuple}, + 4, + { + MP_ROM_PTR(&pin_GPIO36), + MP_ROM_PTR(&pin_GPIO37), + MP_ROM_PTR(&pin_GPIO38), + MP_ROM_PTR(&pin_GPIO39), + } +}; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -85,6 +98,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO39) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA3), MP_ROM_PTR(&pin_GPIO39) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA), MP_ROM_PTR(&sdio_data_tuple) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CARD_DETECT), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_USB_HOST_DATA_PLUS), MP_ROM_PTR(&pin_GPIO32) }, diff --git a/ports/raspberrypi/boards/adafruit_qt2040_trinkey/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_qt2040_trinkey/mpconfigboard.mk index 5f07632b4f6..4252fafba2e 100644 --- a/ports/raspberrypi/boards/adafruit_qt2040_trinkey/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_qt2040_trinkey/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" diff --git a/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.mk index 8258f878336..2b8431454b0 100644 --- a/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" diff --git a/ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c new file mode 100644 index 00000000000..cfa2308f796 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c @@ -0,0 +1,12 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "supervisor/board.h" + +#include "common-hal/picodvi/__init__.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.h new file mode 100644 index 00000000000..958ab01a0b6 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "Adafruit Tinychad RP2350" +#define MICROPY_HW_MCU_NAME "rp2350a" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO17) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO19) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO18) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO10) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO11) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO12) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO1) +#define DEFAULT_UART_BUS_TX (&pin_GPIO0) diff --git a/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk new file mode 100644 index 00000000000..36359c88fe4 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk @@ -0,0 +1,13 @@ +USB_VID = 0x239A +USB_PID = 0x8170 +USB_PRODUCT = "Tinychad RP2350" +USB_MANUFACTURER = "Adafruit" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ" + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/adafruit_tinychad_rp2350/pico-sdk-configboard.h b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/pico-sdk-configboard.h new file mode 100644 index 00000000000..2d9283a9192 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/pico-sdk-configboard.h @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Put board-specific pico-sdk definitions here. This file must exist. + +// Allow extra time for xosc to start. +#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64 diff --git a/ports/raspberrypi/boards/adafruit_tinychad_rp2350/pins.c b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/pins.c new file mode 100644 index 00000000000..0d769fd4d56 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/pins.c @@ -0,0 +1,54 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_CS), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/archi/mpconfigboard.mk b/ports/raspberrypi/boards/archi/mpconfigboard.mk index 1189e6879b9..faf9833da62 100644 --- a/ports/raspberrypi/boards/archi/mpconfigboard.mk +++ b/ports/raspberrypi/boards/archi/mpconfigboard.mk @@ -20,3 +20,5 @@ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_seesaw FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_framebuf FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SimpleIO + +OPTIMIZATION_FLAGS = -O2 diff --git a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c index 35e128627bc..f091c4b05a8 100644 --- a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c +++ b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c @@ -212,9 +212,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO11, // DEFAULT_SPI_BUS_DC, // EPD_DC Command or data - &pin_GPIO13, // DEFAULT_SPI_BUS_CS, // EPD_CS Chip select - &pin_GPIO10, // DEFAULT_SPI_BUS_RESET, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO11), // DEFAULT_SPI_BUS_DC, // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO13), // DEFAULT_SPI_BUS_CS, // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO10), // DEFAULT_SPI_BUS_RESET, // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/mpconfigboard.mk index 14f27c07b99..edb4f3bb3d8 100644 --- a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/mpconfigboard.mk @@ -15,6 +15,9 @@ EXTERNAL_FLASH_DEVICES = "GD25Q64C" CIRCUITPY__EVE = 1 +# The default is -O3. +OPTIMIZATION_FLAGS = -Os + FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_asyncio FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Bitmap_Font FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Shapes diff --git a/ports/raspberrypi/boards/challenger_rp2040_nfc/board.c b/ports/raspberrypi/boards/challenger_rp2040_nfc/board.c new file mode 100644 index 00000000000..52395d4ce04 --- /dev/null +++ b/ports/raspberrypi/boards/challenger_rp2040_nfc/board.c @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Pontus Oldberg, Invector Labs +// SPDX-FileCopyrightText: Copyright (c) 2026 TheFilipcom4607 +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/challenger_rp2040_nfc/mpconfigboard.h b/ports/raspberrypi/boards/challenger_rp2040_nfc/mpconfigboard.h new file mode 100644 index 00000000000..630dcbce721 --- /dev/null +++ b/ports/raspberrypi/boards/challenger_rp2040_nfc/mpconfigboard.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Pontus Oldberg, Invector Labs +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Challenger RP2040 NFC" +#define MICROPY_HW_MCU_NAME "rp2040" + +// The on-board PN7150 sits on GPIO10/11 with no external pull-up +// resistors: iLabs' Arduino core relies on the RP2040's internal +// pull-ups instead (TwoWire::begin() calls gpio_pull_up() on both pins). +#define CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP (1) + +#define MICROPY_HW_LED_STATUS (&pin_GPIO24) +#define MICROPY_HW_NEOPIXEL (&pin_GPIO14) + +#define DEFAULT_UART_BUS_TX (&pin_GPIO16) +#define DEFAULT_UART_BUS_RX (&pin_GPIO17) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO0) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO1) +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO22) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO23) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO20) diff --git a/ports/raspberrypi/boards/challenger_rp2040_nfc/mpconfigboard.mk b/ports/raspberrypi/boards/challenger_rp2040_nfc/mpconfigboard.mk new file mode 100644 index 00000000000..e8618ad660b --- /dev/null +++ b/ports/raspberrypi/boards/challenger_rp2040_nfc/mpconfigboard.mk @@ -0,0 +1,11 @@ +USB_VID = 0x2e8a +USB_PID = 0x1036 +USB_PRODUCT = "Challenger RP2040 NFC" +USB_MANUFACTURER = "Invector Labs" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" + +CIRCUITPY__EVE = 1 diff --git a/ports/raspberrypi/boards/challenger_rp2040_nfc/pico-sdk-configboard.h b/ports/raspberrypi/boards/challenger_rp2040_nfc/pico-sdk-configboard.h new file mode 100644 index 00000000000..718b103cc2a --- /dev/null +++ b/ports/raspberrypi/boards/challenger_rp2040_nfc/pico-sdk-configboard.h @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Pontus Oldberg, Invector Labs +// SPDX-FileCopyrightText: Copyright (c) 2026 TheFilipcom4607 +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/challenger_rp2040_nfc/pins.c b/ports/raspberrypi/boards/challenger_rp2040_nfc/pins.c new file mode 100644 index 00000000000..67f8ecfe731 --- /dev/null +++ b/ports/raspberrypi/boards/challenger_rp2040_nfc/pins.c @@ -0,0 +1,86 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Pontus Oldberg, Invector Labs +// SPDX-FileCopyrightText: Copyright (c) 2026 TheFilipcom4607 +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + + // On board PN7150 NFC controller. Not available on the pin headers. + { MP_ROM_QSTR(MP_QSTR_NFC_IRQ), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_NFC_SDA), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_NFC_SCL), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_NFC_RESET), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_SDI), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_SDO), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, + + // A4 and A5 are digital only on this board. + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/challenger_rp2350_wifi6_ble5/mpconfigboard.mk b/ports/raspberrypi/boards/challenger_rp2350_wifi6_ble5/mpconfigboard.mk index d4f2cdb90d0..7663bcfb19d 100644 --- a/ports/raspberrypi/boards/challenger_rp2350_wifi6_ble5/mpconfigboard.mk +++ b/ports/raspberrypi/boards/challenger_rp2350_wifi6_ble5/mpconfigboard.mk @@ -12,5 +12,9 @@ EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" CIRCUITPY__EVE = 1 CIRCUITPY_ALARM = 0 +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + + FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HID FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register diff --git a/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/board.c b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/board.c new file mode 100644 index 00000000000..e6a868ab212 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/link.ld b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/link.ld new file mode 100644 index 00000000000..e814bead4c5 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/link.ld @@ -0,0 +1 @@ +firmware_size = 1532k; diff --git a/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.h b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.h new file mode 100644 index 00000000000..8eab7e5a525 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Cytron EDU PICO 2" +#define MICROPY_HW_MCU_NAME "rp2350a" + +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (1) +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE (1) + +#define MICROPY_HW_LED_STATUS (&pin_CYW0) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO5, .sda = &pin_GPIO4}} + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO18, .mosi = &pin_GPIO19, .miso = &pin_GPIO16}} diff --git a/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk new file mode 100644 index 00000000000..75d49696a13 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk @@ -0,0 +1,57 @@ +USB_VID = 0x2E8A +USB_PID = 0x107E +USB_PRODUCT = "Cytron EDU PICO 2 for Pico 2W" +USB_MANUFACTURER = "Cytron" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" + +CIRCUITPY_SDCARDIO = 1 + +CIRCUITPY__EVE = 1 + +CIRCUITPY_CYW43 = 1 +CIRCUITPY_SSL = 1 +CIRCUITPY_HASHLIB = 1 +CIRCUITPY_WEB_WORKFLOW = 1 +CIRCUITPY_MDNS = 1 +CIRCUITPY_SOCKETPOOL = 1 +CIRCUITPY_WIFI = 1 + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + +CFLAGS += \ + -DCYW43_PIN_WL_DYNAMIC=0 \ + -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ + -DCYW43_DEFAULT_PIN_WL_REG_ON=23 \ + -DCYW43_DEFAULT_PIN_WL_CLOCK=29 \ + -DCYW43_DEFAULT_PIN_WL_DATA_IN=24 \ + -DCYW43_DEFAULT_PIN_WL_DATA_OUT=24 \ + -DCYW43_DEFAULT_PIN_WL_CS=25 \ + -DCYW43_WL_GPIO_COUNT=3 \ + -DCYW43_WL_GPIO_LED_PIN=0 + -DCYW43_PIO_CLOCK_DIV_INT=3 + +# The default is -O3. +OPTIMIZATION_FLAGS = -Os + +# Include these Python libraries in firmware. +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Text +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Motor +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SimpleIO +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_framebuf +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_OPT4048 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SSD1306 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ImageLoad +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_AHTx0 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HTTPServer +FROZEN_MPY_DIRS += $(TOP)/frozen/CircuitPython_edupico2_paj7620 + +CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' diff --git a/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pico-sdk-configboard.h b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pico-sdk-configboard.h new file mode 100644 index 00000000000..110195b7794 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pins.c b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pins.c new file mode 100644 index 00000000000..83b93e72685 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pins.c @@ -0,0 +1,86 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + + // Motor Controls + { MP_ROM_QSTR(MP_QSTR_M1A), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_M1B), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_M2A), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_M2B), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_LOG_SWITCH), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + + // SPI Pins for SD Card + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_USB_RELAY), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_CYW1) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_CYW0) }, + + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_CYW2) }, + + { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_USB_HOST_DATA_PLUS), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_USB_HOST_DATA_MINUS), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_USB_HOST_POWER), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SD_SPI), MP_ROM_PTR(&board_spi_obj) }, + + + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/cytron_maker_pi_rp2040/pins.c b/ports/raspberrypi/boards/cytron_maker_pi_rp2040/pins.c index 53fae76ac1b..dbfc713930b 100644 --- a/ports/raspberrypi/boards/cytron_maker_pi_rp2040/pins.c +++ b/ports/raspberrypi/boards/cytron_maker_pi_rp2040/pins.c @@ -62,6 +62,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP29_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_VBATT), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, diff --git a/ports/raspberrypi/boards/cytron_motion_2350_pro/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_motion_2350_pro/mpconfigboard.mk index 0ac939ce6a2..9a766f42da7 100644 --- a/ports/raspberrypi/boards/cytron_motion_2350_pro/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_motion_2350_pro/mpconfigboard.mk @@ -11,6 +11,10 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY__EVE = 1 +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + + # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Motor diff --git a/ports/raspberrypi/boards/datanoise_picoadk_v2/mpconfigboard.mk b/ports/raspberrypi/boards/datanoise_picoadk_v2/mpconfigboard.mk index 1b5c6c5d548..42d747537af 100644 --- a/ports/raspberrypi/boards/datanoise_picoadk_v2/mpconfigboard.mk +++ b/ports/raspberrypi/boards/datanoise_picoadk_v2/mpconfigboard.mk @@ -9,5 +9,8 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q32C,W25Q32JVxQ" +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD diff --git a/ports/raspberrypi/boards/hack_club_sprig/board.c b/ports/raspberrypi/boards/hack_club_sprig/board.c index 89b1b3b75b7..94c5a7c5be9 100644 --- a/ports/raspberrypi/boards/hack_club_sprig/board.c +++ b/ports/raspberrypi/boards/hack_club_sprig/board.c @@ -10,7 +10,7 @@ #include "shared-bindings/fourwire/FourWire.h" #include "shared-module/displayio/__init__.h" #include "shared-module/displayio/mipi_constants.h" -#include "supervisor/shared/board.h" +#include "shared-bindings/board/__init__.h" // display init sequence from CircuitPython library https://github.com/adafruit/Adafruit_CircuitPython_ST7735R/blob/dfae353330cf051d1f31db9e4b681c8d70900cc5/adafruit_st7735r.py @@ -57,17 +57,14 @@ uint8_t display_init_sequence[] = { void board_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; - busio_spi_obj_t *spi = &bus->inline_bus; - common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, &pin_GPIO16, false); - common_hal_busio_spi_never_reset(spi); - bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO22, // DC - &pin_GPIO20, // CS - &pin_GPIO26, // RST + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_DC), + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_CS), + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_RESET), 30000000, 0, 0); @@ -92,7 +89,7 @@ void board_init(void) { MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command display_init_sequence, sizeof(display_init_sequence), - &pin_GPIO17, // backlight pin + CIRCUITPY_BOARD_TFT_BACKLIGHT, NO_BRIGHTNESS_COMMAND, 1.0f, // brightness false, // single_byte_bounds @@ -104,4 +101,8 @@ void board_init(void) { 50000); // backlight pwm frequency } +void board_deinit(void) { + common_hal_displayio_release_displays(); +} + // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/hack_club_sprig/mpconfigboard.h b/ports/raspberrypi/boards/hack_club_sprig/mpconfigboard.h index 041aca6d45e..bfc0469a711 100644 --- a/ports/raspberrypi/boards/hack_club_sprig/mpconfigboard.h +++ b/ports/raspberrypi/boards/hack_club_sprig/mpconfigboard.h @@ -10,3 +10,11 @@ #define MICROPY_HW_MCU_NAME "rp2040" #define MICROPY_HW_LED_STATUS (&pin_GPIO4) + +#define CIRCUITPY_BOARD_TFT_DC (&pin_GPIO22) +#define CIRCUITPY_BOARD_TFT_CS (&pin_GPIO20) +#define CIRCUITPY_BOARD_TFT_RESET (&pin_GPIO26) +#define CIRCUITPY_BOARD_TFT_BACKLIGHT (&pin_GPIO17) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO18, .mosi = &pin_GPIO19, .miso = &pin_GPIO16 }} diff --git a/ports/raspberrypi/boards/hack_club_sprig/pins.c b/ports/raspberrypi/boards/hack_club_sprig/pins.c index e5ce1478398..7802ef5466d 100644 --- a/ports/raspberrypi/boards/hack_club_sprig/pins.c +++ b/ports/raspberrypi/boards/hack_club_sprig/pins.c @@ -60,7 +60,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, - // Start Sprig-specific definitions { MP_ROM_QSTR(MP_QSTR_BLUE_LED), MP_ROM_PTR(&pin_GPIO4) }, @@ -79,18 +78,23 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_BUTTON_K), MP_ROM_PTR(&pin_GPIO14) }, { MP_ROM_QSTR(MP_QSTR_BUTTON_L), MP_ROM_PTR(&pin_GPIO15) }, - { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO16) }, - { MP_ROM_QSTR(MP_QSTR_TFT_LITE), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) }, - { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_CARD_CS), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO22) }, - { MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_DC) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_CS) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_RESET) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_BACKLIGHT) }, + { MP_ROM_QSTR(MP_QSTR_TFT_LITE), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_BACKLIGHT) }, + { MP_ROM_QSTR(MP_QSTR_WHITE_LED), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/heiafr_picomo_v2/board.c b/ports/raspberrypi/boards/heiafr_picomo_v2/board.c index 8c60341489f..15324b40ecd 100644 --- a/ports/raspberrypi/boards/heiafr_picomo_v2/board.c +++ b/ports/raspberrypi/boards/heiafr_picomo_v2/board.c @@ -51,9 +51,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO16, // TFT_DC Command or data - &pin_GPIO17, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO16), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // TFT_CS Chip select + mp_const_none, // TFT_RST Reset 62500000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/heiafr_picomo_v3/board.c b/ports/raspberrypi/boards/heiafr_picomo_v3/board.c index 8c60341489f..15324b40ecd 100644 --- a/ports/raspberrypi/boards/heiafr_picomo_v3/board.c +++ b/ports/raspberrypi/boards/heiafr_picomo_v3/board.c @@ -51,9 +51,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO16, // TFT_DC Command or data - &pin_GPIO17, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO16), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // TFT_CS Chip select + mp_const_none, // TFT_RST Reset 62500000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c b/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c index 78cc912130e..2e9ccd45d56 100644 --- a/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c +++ b/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c @@ -63,9 +63,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO1, // DC - &pin_GPIO5, // CS - NULL, // RST (Reset pin tie to 0, do not set here) + MP_OBJ_FROM_PTR(&pin_GPIO1), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + mp_const_none, // RST (Reset pin tie to 0, do not set here) 40000000, // baudrate 1, // polarity 0 // phase diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index e6a868ab212..4fec0cd5b8b 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -5,5 +5,36 @@ // SPDX-License-Identifier: MIT #include "supervisor/board.h" +#include "shared-bindings/mcp4822/MCP4822.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "peripherals/pins.h" +#include "py/runtime.h" +// board.DAC() — factory function that constructs an mcp4822.MCP4822 with +// the MTM Workshop Computer's DAC pins (GP18=SCK, GP19=SDI, GP21=CS). + +static mp_obj_t board_dac_singleton = MP_OBJ_NULL; + +static mp_obj_t board_dac_factory(void) { + if (board_dac_singleton == MP_OBJ_NULL) { + mcp4822_mcp4822_obj_t *dac = mp_obj_malloc_with_finaliser( + mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); + common_hal_mcp4822_mcp4822_construct( + dac, + &pin_GPIO18, // clock (SCK) + &pin_GPIO19, // mosi (SDI) + &pin_GPIO21, // cs + 1); // gain 1x + board_dac_singleton = MP_OBJ_FROM_PTR(dac); + } + return board_dac_singleton; +} +MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); + +void board_deinit(void) { + if (board_dac_singleton != MP_OBJ_NULL) { + common_hal_mcp4822_mcp4822_deinit(MP_OBJ_TO_PTR(board_dac_singleton)); + board_dac_singleton = MP_OBJ_NULL; + } +} // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk index 718c393d168..45c99711d72 100644 --- a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk +++ b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk @@ -11,3 +11,4 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_AUDIOEFFECTS = 1 CIRCUITPY_IMAGECAPTURE = 0 CIRCUITPY_PICODVI = 0 +CIRCUITPY_MCP4822 = 1 diff --git a/ports/raspberrypi/boards/mtm_computer/pins.c b/ports/raspberrypi/boards/mtm_computer/pins.c index 69878182331..ffdf2687702 100644 --- a/ports/raspberrypi/boards/mtm_computer/pins.c +++ b/ports/raspberrypi/boards/mtm_computer/pins.c @@ -6,6 +6,8 @@ #include "shared-bindings/board/__init__.h" +extern const mp_obj_fun_builtin_fixed_t board_dac_obj; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -21,7 +23,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PULSE_2_IN), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_NORM_PROBE), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, @@ -105,6 +106,9 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + // Factory function: dac = board.DAC() returns a configured mcp4822.MCP4822 + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&board_dac_obj) }, + // { MP_ROM_QSTR(MP_QSTR_EEPROM_I2C), MP_ROM_PTR(&board_i2c_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/pajenicko_picopad/board.c b/ports/raspberrypi/boards/pajenicko_picopad/board.c index 0ca13b3ec2e..9edebba57b4 100644 --- a/ports/raspberrypi/boards/pajenicko_picopad/board.c +++ b/ports/raspberrypi/boards/pajenicko_picopad/board.c @@ -51,10 +51,11 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO17, // TFT_DC Command or data - &pin_GPIO21, // TFT_CS Chip select - &pin_GPIO20, // TFT_RST Reset - 60000000, // Baudrate + MP_OBJ_FROM_PTR(&pin_GPIO17), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO21), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO20), // TFT_RST Reset + 62500000, // Baudrate: exactly clk_peri/2 (125MHz/2). Requesting 60MHz makes the + // PL022 divider round DOWN to 31.25MHz - half the display bandwidth. 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk index 764e41d4d91..b5df0e6ecb5 100644 --- a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk @@ -9,11 +9,21 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" +CIRCUITPY_USB_HOST = 0 + CIRCUITPY_KEYPAD = 1 CIRCUITPY_STAGE = 1 +CIRCUITPY_PICOGAME = 1 +CIRCUITPY_PICOGAME_FAST_DISPLAY = 1 +CIRCUITPY_PICOGAME_RGB444 = 1 CIRCUITPY_AUDIOIO = 1 +CIRCUITPY_AUDIOEFFECTS = 0 -CIRCUITPY__EVE = 1 +# Peripherals this board physically lacks: no FT8xx EVE display, no camera for the +# qrio QR *decoder* (QR generation = pure-Python adafruit_miniqr, unaffected), and no +# DVI/HDMI connector. Dropping them frees flash for the picogame engine. +CIRCUITPY__EVE = 0 +CIRCUITPY_QRIO = 0 CIRCUITPY_CYW43 = 1 CIRCUITPY_SSL = 1 @@ -23,7 +33,6 @@ CIRCUITPY_MDNS = 1 CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 -CIRCUITPY_PICODVI = 1 # Pimoroni PicoSystem peripherals are compatible, we can use of existing ugame.py FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/picosystem @@ -41,3 +50,8 @@ CFLAGS += \ # Must be accompanied by a linker script change CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' + +# The rp2 port default is -O3; on this Cortex-M0+ (no SIMD/FPU, 16 KB XIP cache) -O2 plus +# these five loop passes measures within +-1% of -O3 across the picogame render kernels +# while using ~150 KB less flash (gc.o/vm.o stay -O3 via SUPEROPT regardless). +OPTIMIZATION_FLAGS = -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.c b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.c new file mode 100644 index 00000000000..1ce23b26459 --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.c @@ -0,0 +1 @@ +#include "shared-bindings/board/__init__.h" diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.h b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.h new file mode 100644 index 00000000000..75deccbc8ed --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.h @@ -0,0 +1,12 @@ +#ifndef MICROPY_INCLUDED_RASPBERRYPI_BOARDS_PCBCUPID_Glyph_Mini_2040 +#define MICROPY_INCLUDED_RASPBERRYPI_BOARDS_PCBCUPID_Glyph_Mini_2040 + +#define MICROPY_HW_BOARD_NAME "PCBCupid Glyph Mini 2040" +#define MICROPY_HW_MCU_NAME "rp2040" + +#define FLASH_SIZE (8 * 1024 * 1024) +#define CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE (7 * 1024 * 1024) + +#define MICROPY_HW_LED_STATUS (&pin_GPIO16) + +#endif diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.mk b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.mk new file mode 100644 index 00000000000..415aecd6395 --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.mk @@ -0,0 +1,9 @@ +USB_VID = 0x2E8A +USB_PID = 0x1123 +USB_PRODUCT = "Glyph Mini 2040" +USB_MANUFACTURER = "PCBCupid" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pico-sdk-configboard.h b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pico-sdk-configboard.h new file mode 100644 index 00000000000..110195b7794 --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pins.c b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pins.c new file mode 100644 index 00000000000..d2719b1ebea --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pins.c @@ -0,0 +1,37 @@ +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO16) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/board.c b/ports/raspberrypi/boards/pimoroni_badger2040/board.c index 07cc512b9a5..80eddb49e13 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2040/board.c +++ b/ports/raspberrypi/boards/pimoroni_badger2040/board.c @@ -263,9 +263,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO20, // EPD_DC Command or data - &pin_GPIO17, // EPD_CS Chip select - &pin_GPIO21, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO20), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO21), // EPD_RST Reset 1200000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_badger2040w/board.c b/ports/raspberrypi/boards/pimoroni_badger2040w/board.c index b992bcd6a1e..ef5da7ceabc 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2040w/board.c +++ b/ports/raspberrypi/boards/pimoroni_badger2040w/board.c @@ -263,9 +263,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO20, // EPD_DC Command or data - &pin_GPIO17, // EPD_CS Chip select - &pin_GPIO21, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO20), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO21), // EPD_RST Reset 1200000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/badger2350-shared.h b/ports/raspberrypi/boards/pimoroni_badger2350/badger2350-shared.h new file mode 100644 index 00000000000..4cc67efd4df --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/badger2350-shared.h @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/digitalio/DigitalInOut.h" + +extern digitalio_digitalinout_obj_t i2c_power_en_pin_obj; +extern const mp_obj_fun_builtin_fixed_t set_update_speed_obj; +extern const mp_obj_fun_builtin_fixed_t get_reset_state_obj; +extern const mp_obj_fun_builtin_fixed_t on_reset_pressed_obj; diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/board.c b/ports/raspberrypi/boards/pimoroni_badger2350/board.c new file mode 100644 index 00000000000..1da13b80339 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/board.c @@ -0,0 +1,225 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Bob Abeles +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" + +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/board.h" +#include "supervisor/board.h" +#include "badger2350-shared.h" + +#include "hardware/gpio.h" +#include "hardware/structs/iobank0.h" + +digitalio_digitalinout_obj_t i2c_power_en_pin_obj; +static volatile uint32_t reset_button_state = 0; + +// Forward declaration to satisfy -Wmissing-prototypes +static void preinit_button_state(void) __attribute__((constructor(101))); + + +// pin definitions +// Button pin definitions for Badger2350 +#define SW_A_PIN 7 +#define SW_B_PIN 9 +#define SW_C_PIN 10 +#define SW_DOWN_PIN 6 +#define SW_UP_PIN 11 + +static const uint8_t _sw_pin_nrs[] = { + SW_A_PIN, SW_B_PIN, SW_C_PIN, SW_DOWN_PIN, SW_UP_PIN +}; + +// Mask of all front button pins +#define SW_MASK ((1 << SW_A_PIN) | (1 << SW_B_PIN) | (1 << SW_C_PIN) | \ + (1 << SW_DOWN_PIN) | (1 << SW_UP_PIN)) + +// This function runs BEFORE main() via constructor attribute! +// This is the key to fast button state detection. +// Priority 101 = runs very early + +static void preinit_button_state(void) { + // Configure button pins as inputs with pull-downs using direct register access + // This is faster than SDK functions and works before full init + + for (size_t i = 0; i < sizeof(_sw_pin_nrs); i++) { + uint8_t pin_nr = _sw_pin_nrs[i]; + // Set as input + sio_hw->gpio_oe_clr = 1u << pin_nr; + // enable pull-ups + pads_bank0_hw->io[pin_nr] = PADS_BANK0_GPIO0_IE_BITS | + PADS_BANK0_GPIO0_PUE_BITS; + // Set GPIO function + iobank0_hw->io[pin_nr].ctrl = 5; // SIO function + } + + // Small delay for pins to settle (just a few cycles) + for (volatile int i = 0; i < 100; i++) { + __asm volatile ("nop"); + } + + // Capture button states NOW - before anything else runs + reset_button_state = ~sio_hw->gpio_in & SW_MASK; +} + +static mp_obj_t _get_reset_state(void) { + return mp_obj_new_int(reset_button_state); +} +MP_DEFINE_CONST_FUN_OBJ_0(get_reset_state_obj, _get_reset_state); + +static mp_obj_t _on_reset_pressed(mp_obj_t pin_in) { + mcu_pin_obj_t *pin = MP_OBJ_TO_PTR(pin_in); + return mp_obj_new_bool( + (reset_button_state & (1 << pin->number)) != 0); +} +MP_DEFINE_CONST_FUN_OBJ_1(on_reset_pressed_obj, _on_reset_pressed); + +// The display uses an SSD1680 control chip. +uint8_t _start_sequence[] = { + 0x12, 0x80, 0x00, 0x14, // soft reset and wait 20ms + 0x11, 0x00, 0x01, 0x03, // Ram data entry mode + 0x3c, 0x00, 0x01, 0x03, // border color + 0x2c, 0x00, 0x01, 0x28, // Set vcom voltage + 0x03, 0x00, 0x01, 0x17, // Set gate voltage + 0x04, 0x00, 0x03, 0x41, 0xae, 0x32, // Set source voltage + 0x4e, 0x00, 0x01, 0x00, // ram x count + 0x4f, 0x00, 0x02, 0x00, 0x00, // ram y count + 0x01, 0x00, 0x03, 0x07, 0x01, 0x00, // set display size + 0x32, 0x00, 0x99, // Update waveforms + + // offset 44 + 0x40, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L0 + 0xA0, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L1 + 0xA8, 0x65, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L2 + 0xAA, 0x65, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L3 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L4 + + // offset 104 + 0x02, 0x00, 0x00, 0x05, 0x0A, 0x00, 0x03, // Group0 (with default speed==0) + // offset 111 + 0x19, 0x19, 0x00, 0x02, 0x00, 0x00, 0x03, // Group1 (with default speed==0) + // offset 118 + 0x05, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x03, // Group2 (with default speed==0) + + // offset 125 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group3 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group4 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group5 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group6 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group8 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group9 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group11 + 0x44, 0x42, 0x22, 0x22, 0x23, 0x32, 0x00, // Config + 0x00, 0x00, // FR, XON + + 0x22, 0x00, 0x01, 0xc7, // display update mode + +}; + +const uint8_t _stop_sequence[] = { + 0x10, 0x00, 0x01, 0x01 // DSM deep sleep mode 1 +}; + +const uint8_t _refresh_sequence[] = { + 0x20, 0x00, 0x00 // ADUS +}; + +// Change update speed. This changes the repeat-count in the LUTs +// Pimoroni uses: 0 == slow ... 3 == fast +// and calculates the LUT repeat count as 3-speed + +#define SPEED_OFFSET_1 110 +#define SPEED_OFFSET_2 117 +#define SPEED_OFFSET_3 124 + +static mp_obj_t _set_update_speed(mp_obj_t speed_in) { + mp_int_t speed = mp_obj_get_int(speed_in); + uint8_t count = (uint8_t)3 - (uint8_t)(speed & 3); + _start_sequence[SPEED_OFFSET_1] = count; + _start_sequence[SPEED_OFFSET_2] = count; + _start_sequence[SPEED_OFFSET_3] = count; + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_1(set_update_speed_obj, _set_update_speed); + +void board_init(void) { + // Drive the I2C_POWER_EN pin high + i2c_power_en_pin_obj.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct( + &i2c_power_en_pin_obj, &pin_GPIO27); + common_hal_digitalio_digitalinout_switch_to_output( + &i2c_power_en_pin_obj, true, DRIVE_MODE_PUSH_PULL); + common_hal_digitalio_digitalinout_never_reset(&i2c_power_en_pin_obj); + + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, NULL, false); + common_hal_busio_spi_never_reset(spi); + + bus->base.type = &fourwire_fourwire_type; + common_hal_fourwire_fourwire_construct(bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO20), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO21), // EPD_RST Reset + 12000000, // Baudrate + 0, // Polarity + 0); // Phase + + // create and configure display + epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; + display->base.type = &epaperdisplay_epaperdisplay_type; + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = _start_sequence; + args.start_sequence_len = sizeof(_start_sequence); + args.stop_sequence = _stop_sequence; + args.stop_sequence_len = sizeof(_stop_sequence); + args.width = 264; + args.height = 176; + args.ram_width = 250; + args.ram_height = 296; + args.rotation = 270; + args.set_column_window_command = 0x44; + args.set_row_window_command = 0x45; + args.set_current_column_command = 0x4e; + args.set_current_row_command = 0x4f; + args.write_black_ram_command = 0x24; + args.write_color_ram_command = 0x26; + args.color_bits_inverted = true; + args.refresh_sequence = _refresh_sequence; + args.refresh_sequence_len = sizeof(_refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO16; + args.busy_state = true; + args.seconds_per_frame = 3.0; + args.grayscale = true; + args.two_byte_sequence_length = true; + args.address_little_endian = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); +} + +void board_deinit(void) { + epaperdisplay_epaperdisplay_obj_t *display = &displays[0].epaper_display; + if (display->base.type == &epaperdisplay_epaperdisplay_type) { + while (common_hal_epaperdisplay_epaperdisplay_get_busy(display)) { + RUN_BACKGROUND_TASKS; + } + } + common_hal_displayio_release_displays(); +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/link.ld b/ports/raspberrypi/boards/pimoroni_badger2350/link.ld new file mode 100644 index 00000000000..e814bead4c5 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/link.ld @@ -0,0 +1 @@ +firmware_size = 1532k; diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.h new file mode 100644 index 00000000000..6cffd190ad6 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Bernhard Bablok +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "Pimoroni Badger 2350" +#define MICROPY_HW_MCU_NAME "rp2350a" + +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (1) +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE (1) + +#define MICROPY_HW_LED_STATUS (&pin_GPIO0) + +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19) + +#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO8) diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk new file mode 100644 index 00000000000..58f88af2518 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk @@ -0,0 +1,41 @@ +USB_VID = 0x2E8A +USB_PID = 0x1100 +USB_PRODUCT = "Pimoroni Badger 2350" +USB_MANUFACTURER = "Pimoroni" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +CIRCUITPY__EVE = 1 + +CIRCUITPY_CYW43 = 1 +CIRCUITPY_SSL = 1 +CIRCUITPY_HASHLIB = 1 +CIRCUITPY_WEB_WORKFLOW = 1 +CIRCUITPY_MDNS = 1 +CIRCUITPY_SOCKETPOOL = 1 +CIRCUITPY_WIFI = 1 + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + +# PIO clock divider set to 2 (default), consider changing if TM2 gSPI +# becomes unreliable. +CFLAGS += \ + -DCYW43_PIN_WL_DYNAMIC=0 \ + -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ + -DCYW43_DEFAULT_PIN_WL_REG_ON=23 \ + -DCYW43_DEFAULT_PIN_WL_CLOCK=29 \ + -DCYW43_DEFAULT_PIN_WL_DATA_IN=24 \ + -DCYW43_DEFAULT_PIN_WL_DATA_OUT=24 \ + -DCYW43_DEFAULT_PIN_WL_CS=25 \ + -DCYW43_WL_GPIO_COUNT=3 \ + -DCYW43_PIO_CLOCK_DIV_INT=2 \ + -DCYW43_PIO_CLOCK_DIV_FRAC=0 +# Must be accompanied by a linker script change +CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' + +FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/pico-sdk-configboard.h b/ports/raspberrypi/boards/pimoroni_badger2350/pico-sdk-configboard.h new file mode 100644 index 00000000000..42e0612bf8b --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Bob Abeles +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/pins.c b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c new file mode 100644 index 00000000000..1a66961e68f --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c @@ -0,0 +1,135 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Bob Abeles +// +// SPDX-License-Identifier: MIT + +#include "py/objtuple.h" +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "badger2350-shared.h" + + +// LUT manipulation +static const mp_rom_map_elem_t lut_update_table[] = { + { MP_ROM_QSTR(MP_QSTR_SET_UPDATE_SPEED), (mp_obj_t)&set_update_speed_obj }, + { MP_ROM_QSTR(MP_QSTR_SPEED_SLOW), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_SPEED_FAST), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_SPEED_FASTER), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_SPEED_FASTEST), MP_ROM_INT(3) }, +}; +MP_DEFINE_CONST_DICT(lut_update_dict, lut_update_table); + +const mp_obj_module_t display_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&lut_update_dict, +}; + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_display), MP_ROM_PTR(&display_module) }, + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_LED0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_LED1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_LED2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_LED3), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_SW_DOWN), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SW_A), MP_ROM_PTR(&pin_GPIO7) }, + + // GP8 is reserved for PSRAM chip select + + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_SW_B), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_SW_C), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SW_UP), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_RTC_ALARM), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SW_RESET), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SW_INT), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_INKY_BUSY), MP_ROM_PTR(&pin_GPIO16) }, + + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_INKY_CS), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_INKY_DC), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_INKY_RST), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_SW_HOME), MP_ROM_PTR(&pin_GPIO22) }, + + // GP23, GP24, GP25, and GP29 are reserved for RM2 gSPI + + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO26) }, + + // GP27 is the used for I2C power-enable, driven high by board.c + { MP_ROM_QSTR(MP_QSTR_I2C_POWER_EN), MP_ROM_PTR(&i2c_power_en_pin_obj) }, + + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_SENSE_1V1), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + + // Pins accessed though the RM2 module (CYW43439) + // CYW0, CYW1 is unconnected + { MP_ROM_QSTR(MP_QSTR_CHARGE_STAT), MP_ROM_PTR(&pin_CYW2) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].epaper_display)}, + + // button-state on reset + // Use `board.RESET_STATE()` to query the state of all buttons at reset. + // To detect individual key-presses, `board.ON_RESET_PRESSED()` + // is simpler. + { MP_ROM_QSTR(MP_QSTR_RESET_STATE), (mp_obj_t)&get_reset_state_obj }, + + // Use `board.ON_RESET_PRESSED(board.SW_A)` to check if `SW_A` was pressed + // during reset. + { MP_ROM_QSTR(MP_QSTR_ON_RESET_PRESSED), (mp_obj_t)&on_reset_pressed_obj }, + +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/board.c b/ports/raspberrypi/boards/pimoroni_explorer2350/board.c new file mode 100644 index 00000000000..d0c6d9a57ce --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/board.c @@ -0,0 +1,145 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/paralleldisplaybus/ParallelBus.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "hardware/gpio.h" + +// Display pins from Pimoroni Explorer parallel bus: {cs=27, dc=28, wr=30, rd=31, d0=32, bl=26} +#define LCD_BACKLIGHT_PIN 26 +#define LCD_CS_PIN 27 +#define LCD_DC_PIN 28 +#define LCD_WR_PIN 30 +#define LCD_RD_PIN 31 +#define LCD_D0_PIN 32 // Data pins are GPIO32-39 (8 consecutive pins) + +#define DELAY 0x80 + +// ST7789V display init sequence for 320x240 parallel bus +// Based on Pimoroni's pimoroni-pico ST7789 driver configuration +uint8_t display_init_sequence[] = { + // Software reset + 0x01, 0 | DELAY, 150, + // Sleep out + 0x11, 0 | DELAY, 255, + // Tearing effect line on (frame sync) + 0x35, 1, 0x00, + // COLMOD: 16-bit color (5-6-5 RGB) + 0x3A, 1, 0x55, + // Porch control (PORCTRL) + 0xB2, 5, 0x0C, 0x0C, 0x00, 0x33, 0x33, + // Gate control (GCTRL) - VGH=13.26V, VGL=-10.43V + 0xB7, 1, 0x35, + // VCOM setting (VCOMS) + 0xBB, 1, 0x1F, + // LCM control (LCMCTRL) + 0xC0, 1, 0x2C, + // VDV and VRH command enable (VDVVRHEN) + 0xC2, 1, 0x01, + // VRH set (VRHS) + 0xC3, 1, 0x12, + // VDV set (VDVS) + 0xC4, 1, 0x20, + // Frame rate control (FRCTRL2) + 0xC6, 1, 0x0F, + // Power control 1 (PWCTRL1) + 0xD0, 2, 0xA4, 0xA1, + // RAM control (RAMCTRL) - for proper endianness + 0xB0, 2, 0x00, 0xC0, + // Positive gamma correction + 0xE0, 14, 0xD0, 0x08, 0x11, 0x08, 0x0C, 0x15, 0x39, 0x33, 0x50, 0x36, 0x13, 0x14, 0x29, 0x2D, + // Negative gamma correction + 0xE1, 14, 0xD0, 0x08, 0x10, 0x08, 0x06, 0x06, 0x39, 0x44, 0x51, 0x0B, 0x16, 0x14, 0x2F, 0x31, + // Inversion on + 0x21, 0, + // Normal display mode on + 0x13, 0 | DELAY, 10, + // MADCTL: MX=0, MY=1, MV=1, ML=1 (COL_ORDER | SWAP_XY | SCAN_ORDER) = 0x70 + // This configures the 320x240 display in landscape orientation + 0x36, 1, 0x70, + // Display on + 0x29, 0 | DELAY, 100, +}; + +static void display_init(void) { + paralleldisplaybus_parallelbus_obj_t *bus = &allocate_display_bus()->parallel_bus; + bus->base.type = ¶lleldisplaybus_parallelbus_type; + + common_hal_paralleldisplaybus_parallelbus_construct(bus, + &pin_GPIO32, // Data0 (D0) - data pins are sequential GPIO32-39 + &pin_GPIO28, // Command/Data (DC) + &pin_GPIO27, // Chip select (CS) + &pin_GPIO30, // Write (WR) + &pin_GPIO31, // Read (RD) + NULL, // Reset (directly connected to board reset) + 15000000); // Frequency - ST7789 min clock cycle ~66ns = ~15MHz + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct(display, + bus, + 320, // Width + 240, // Height + 0, // column start + 0, // row start + 0, // rotation + 16, // Color depth + false, // grayscale + false, // pixels_in_byte_share_row + 1, // bytes per cell + false, // reverse_pixels_in_byte + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO26, // Backlight pin (BL) + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} + +void board_init(void) { + // Ensure backlight is on before display init + board_reset_pin_number(LCD_BACKLIGHT_PIN); + display_init(); +} + +// Prevent the backlight pin from being reset, keeping display visible across soft resets +bool board_reset_pin_number(uint8_t pin_number) { + if (pin_number == LCD_BACKLIGHT_PIN) { + // Keep backlight on - set high output without glitching + gpio_put(pin_number, 1); + gpio_set_dir(pin_number, GPIO_OUT); + gpio_set_function(pin_number, GPIO_FUNC_SIO); + return true; + } + return false; +} + +void reset_board(void) { + // Keep backlight on during reset + board_reset_pin_number(LCD_BACKLIGHT_PIN); +} + +void board_deinit(void) { + // Backlight will be handled by board_reset_pin_number +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.h new file mode 100644 index 00000000000..dd269aa6b84 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Pimoroni Explorer" +#define MICROPY_HW_MCU_NAME "rp2350b" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO25) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO21, .sda = &pin_GPIO20}} + +#define DEFAULT_UART_BUS_RX (&pin_GPIO1) +#define DEFAULT_UART_BUS_TX (&pin_GPIO0) diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk new file mode 100644 index 00000000000..4409dbf57df --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk @@ -0,0 +1,13 @@ +USB_VID = 0x2E8A +USB_PID = 0x10C0 +USB_PRODUCT = "Explorer" +USB_MANUFACTURER = "Pimoroni" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = B +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +# GPIO12-19 needed for picodvi, but several are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/pico-sdk-configboard.h b/ports/raspberrypi/boards/pimoroni_explorer2350/pico-sdk-configboard.h new file mode 100644 index 00000000000..66b57dfd13d --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/pico-sdk-configboard.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/pins.c b/ports/raspberrypi/boards/pimoroni_explorer2350/pins.c new file mode 100644 index 00000000000..8154a43de00 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/pins.c @@ -0,0 +1,124 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // User GPIOs (accent connector) + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + + // Servo pins + { MP_ROM_QSTR(MP_QSTR_SERVO1), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_SERVO2), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_SERVO3), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SERVO4), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + + // Audio + { MP_ROM_QSTR(MP_QSTR_AUDIO), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_AMP_EN), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + + // Buttons + { MP_ROM_QSTR(MP_QSTR_SW_C), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SW_B), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SW_A), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SW_X), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SW_Y), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SW_Z), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + + // I2C + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + + // User button + { MP_ROM_QSTR(MP_QSTR_SW_USER), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + // LED? + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + + // Display parallel bus pins (ST7789V 320x240) + // Pins from Pimoroni: {cs=27, dc=28, wr=30, rd=31, d0=32, bl=26} + { MP_ROM_QSTR(MP_QSTR_LCD_BL), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_LCD_DC), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_LCD_WR), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_GP30), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_LCD_RD), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_GP31), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D0), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_GP32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D1), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_GP33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D2), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_GP34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D3), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_GP35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D4), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_GP36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D5), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_GP37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D6), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_GP38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D7), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_GP39), MP_ROM_PTR(&pin_GPIO39) }, + + // ADC pins (RP2350B extended GPIOs) + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_ADC0), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_GP40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_ADC1), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_GP41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_ADC2), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_GP42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_ADC3), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_GP43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_ADC4), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_GP44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_ADC5), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_GP45), MP_ROM_PTR(&pin_GPIO45) }, + + // I2C object + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + // Display object + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c index 4bf7518c6a8..58c54334d59 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c @@ -58,9 +58,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO28, // EPD_DC Command or data - &pin_GPIO17, // EPD_CS Chip select - &pin_GPIO27, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO28), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO27), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk index 69b23a72be7..0a56b55a0c1 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk @@ -36,4 +36,3 @@ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register -FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c index 763a91a2555..fc6ca67f3ae 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c @@ -117,9 +117,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO28, // EPD_DC Command or data - &pin_GPIO17, // EPD_CS Chip select - &pin_GPIO27, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO28), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO27), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk index 9218192d083..02cbe3b69b7 100644 --- a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk @@ -19,6 +19,13 @@ CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 CIRCUITPY_PICODVI = 1 +CIRCUITPY_AUDIOEFFECTS = 0 +CIRCUITPY_AUDIOFILEWRITER = 0 +CIRCUITPY_BLEIO_HCI = 0 + +# No room: this board fills FLASH_FIRMWARE. Frees ~9kB. Not the board's I2S +# line-out/HDMI audio, which audiobusio still provides. +CIRCUITPY_USB_AUDIO = 0 CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ diff --git a/ports/raspberrypi/boards/pimoroni_picosystem/board.c b/ports/raspberrypi/boards/pimoroni_picosystem/board.c index 40756b56426..e5956e43ed1 100644 --- a/ports/raspberrypi/boards/pimoroni_picosystem/board.c +++ b/ports/raspberrypi/boards/pimoroni_picosystem/board.c @@ -51,9 +51,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO9, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO4, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_picosystem/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_picosystem/mpconfigboard.mk index 8dca786a5e0..28a3c6a641a 100644 --- a/ports/raspberrypi/boards/pimoroni_picosystem/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_picosystem/mpconfigboard.mk @@ -12,7 +12,13 @@ CIRCUITPY__EVE = 1 CIRCUITPY_KEYPAD = 1 CIRCUITPY_STAGE = 1 +CIRCUITPY_PICOGAME = 1 +CIRCUITPY_PICOGAME_FAST_DISPLAY = 1 CIRCUITPY_AUDIOIO = 1 FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/picosystem + +# The default is -O3. picogame does not fit at -O3; these loop passes keep the render +# kernels within 1% of it. +OPTIMIZATION_FLAGS = -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths diff --git a/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.mk index 56fd7b641de..52dcd3fbe71 100644 --- a/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.mk index 8563f0d0034..cab35965a0f 100644 --- a/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.mk @@ -21,6 +21,9 @@ CIRCUITPY_WIFI = 1 CIRCUITPY_PICODVI = 0 CIRCUITPY_USB_HOST = 0 +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ diff --git a/ports/raspberrypi/boards/pimoroni_tiny2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_tiny2350/mpconfigboard.mk index 9ffdf263003..b94022c1f6d 100644 --- a/ports/raspberrypi/boards/pimoroni_tiny2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_tiny2350/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but several are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/securinghw-xiaomao/board.c b/ports/raspberrypi/boards/securinghw-xiaomao/board.c new file mode 100644 index 00000000000..e6a868ab212 --- /dev/null +++ b/ports/raspberrypi/boards/securinghw-xiaomao/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/securinghw-xiaomao/mpconfigboard.h b/ports/raspberrypi/boards/securinghw-xiaomao/mpconfigboard.h new file mode 100644 index 00000000000..ed69167c774 --- /dev/null +++ b/ports/raspberrypi/boards/securinghw-xiaomao/mpconfigboard.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "SecuringHardware.com Xiaomao" +#define MICROPY_HW_MCU_NAME "rp2040" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO7) +#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO6) + +#define CIRCUITPY_BOARD_UART (2) +#define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO16, .rx = &pin_GPIO17}, \ + {.tx = &pin_GPIO20, .rx = &pin_GPIO21}} diff --git a/ports/raspberrypi/boards/securinghw-xiaomao/mpconfigboard.mk b/ports/raspberrypi/boards/securinghw-xiaomao/mpconfigboard.mk new file mode 100644 index 00000000000..19b8639883a --- /dev/null +++ b/ports/raspberrypi/boards/securinghw-xiaomao/mpconfigboard.mk @@ -0,0 +1,9 @@ +USB_VID = 0x2E8A +USB_PID = 0x1116 +USB_PRODUCT = "Xiaomao" +USB_MANUFACTURER = "SecuringHardwarecom" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" diff --git a/ports/raspberrypi/boards/securinghw-xiaomao/pico-sdk-configboard.h b/ports/raspberrypi/boards/securinghw-xiaomao/pico-sdk-configboard.h new file mode 100644 index 00000000000..110195b7794 --- /dev/null +++ b/ports/raspberrypi/boards/securinghw-xiaomao/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/securinghw-xiaomao/pins.c b/ports/raspberrypi/boards/securinghw-xiaomao/pins.c new file mode 100644 index 00000000000..a6b6cd3ac72 --- /dev/null +++ b/ports/raspberrypi/boards/securinghw-xiaomao/pins.c @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +CIRCUITPY_BOARD_BUS_SINGLETON(uart1, uart, 1) + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_TX1), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_RX1), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_CTS1), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_BTN), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_VBUS_DET), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL_POWER), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART1), MP_ROM_PTR(&board_uart1_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/seeeduino_xiao_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/seeeduino_xiao_rp2350/mpconfigboard.mk index d5f866bd89e..f51d5271215 100644 --- a/ports/raspberrypi/boards/seeeduino_xiao_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/seeeduino_xiao_rp2350/mpconfigboard.mk @@ -8,3 +8,6 @@ CHIP_PACKAGE = A CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "P25Q16H" + +# GPIO12-19 needed for picodvi, but several are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/sparkfun_pro_micro_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/sparkfun_pro_micro_rp2350/mpconfigboard.mk index e5d6e1b8ff8..53cdf72963f 100644 --- a/ports/raspberrypi/boards/sparkfun_pro_micro_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/sparkfun_pro_micro_rp2350/mpconfigboard.mk @@ -8,3 +8,6 @@ CHIP_PACKAGE = A CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/sparkfun_thing_plus_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/sparkfun_thing_plus_rp2350/mpconfigboard.mk index 6e81a229961..81d7f660473 100644 --- a/ports/raspberrypi/boards/sparkfun_thing_plus_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/sparkfun_thing_plus_rp2350/mpconfigboard.mk @@ -23,6 +23,8 @@ CIRCUITPY_MDNS = 1 CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 +# GPIO12-19 needed for picodvi, but GPIO14 is used for a NeoPixel. +CIRCUITPY_PICODVI = 0 CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/board.c b/ports/raspberrypi/boards/studiolab_picoexpander/board.c new file mode 100644 index 00000000000..299f32da04f --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/link.ld b/ports/raspberrypi/boards/studiolab_picoexpander/link.ld new file mode 100644 index 00000000000..e814bead4c5 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/link.ld @@ -0,0 +1 @@ +firmware_size = 1532k; diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h new file mode 100644 index 00000000000..ea475f68222 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "Studiolab Pico Expander" +#define MICROPY_HW_MCU_NAME "rp2350a" + +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (1) +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE (1) + +#define MICROPY_HW_LED_STATUS (&pin_CYW0) +#define MICROPY_HW_NEOPIXEL (&pin_GPIO2) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO5, .sda = &pin_GPIO4}} + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO18, .mosi = &pin_GPIO19, .miso = &pin_GPIO16}} diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk new file mode 100644 index 00000000000..7214b36da28 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk @@ -0,0 +1,38 @@ +USB_VID = 0x1209 +USB_PID = 0xC1C1 +USB_PRODUCT = "StudioLab Pico Expander" +USB_MANUFACTURER = "Raspberry Pi" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" + +CIRCUITPY__EVE = 1 + +CIRCUITPY_CYW43 = 1 +CIRCUITPY_SSL = 1 +CIRCUITPY_HASHLIB = 1 +CIRCUITPY_WEB_WORKFLOW = 1 +CIRCUITPY_MDNS = 1 +CIRCUITPY_SOCKETPOOL = 1 +CIRCUITPY_WIFI = 1 + +# GPIO12-19 needed for picodvi, but GPIO15 is used for a button. +CIRCUITPY_PICODVI = 0 + +CFLAGS += \ + -DCYW43_PIN_WL_DYNAMIC=0 \ + -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ + -DCYW43_DEFAULT_PIN_WL_REG_ON=23 \ + -DCYW43_DEFAULT_PIN_WL_CLOCK=29 \ + -DCYW43_DEFAULT_PIN_WL_DATA_IN=24 \ + -DCYW43_DEFAULT_PIN_WL_DATA_OUT=24 \ + -DCYW43_DEFAULT_PIN_WL_CS=25 \ + -DCYW43_WL_GPIO_COUNT=3 \ + -DCYW43_WL_GPIO_LED_PIN=0 \ + -DCYW43_PIO_CLOCK_DIV_INT=3 + +# Must be accompanied by a linker script change +CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/pico-sdk-configboard.h b/ports/raspberrypi/boards/studiolab_picoexpander/pico-sdk-configboard.h new file mode 100644 index 00000000000..945802d1ab1 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/pins.c b/ports/raspberrypi/boards/studiolab_picoexpander/pins.c new file mode 100644 index 00000000000..6faafbfd177 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/pins.c @@ -0,0 +1,113 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_BTN), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_A26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_A27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_A28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_CYW1) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_CYW0) }, + + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_CYW2) }, + + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/board.c b/ports/raspberrypi/boards/teenage_engineering_ep2350/board.c new file mode 100644 index 00000000000..982ebb6deb1 --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/board.c @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +#include "mpconfigboard.h" +#include "common-hal/microcontroller/Pin.h" +#include "hardware/gpio.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. + +static void assert_power_hold(void) { + // Doing this (rather than gpio_init()) in this specific order ensures no + // glitch if the pin was already configured as a high output. gpio_init() + // temporarily configures the pin as an input, which would release the + // latch and power the board off. + gpio_put(MICROPY_HW_POWER_HOLD_PIN_NUMBER, 1); + gpio_set_dir(MICROPY_HW_POWER_HOLD_PIN_NUMBER, GPIO_OUT); + gpio_set_function(MICROPY_HW_POWER_HOLD_PIN_NUMBER, GPIO_FUNC_SIO); +} + +// Forward declaration to satisfy -Wmissing-prototypes +static void preinit_power_hold(void) __attribute__((constructor(101))); + +// Runs before main(), so the latch is set as early as it can possibly be. +static void preinit_power_hold(void) { + assert_power_hold(); +} + +// The EP-2350 has no power switch: pressing the handle applies power directly, +// and firmware must set the power hold latch on GPIO2 before the handle is +// released or the unit dies. The latch is a true set/reset latch, so a single +// high pulse is enough, but the pin must never be left low. +// +// reset_all_pins() runs this for every pin at startup and again on every soft +// reload, so the latch is re-asserted instead of being reset to an input. The +// pin is deliberately not claimed with never_reset(), so user code can still +// take board.POWER_HOLD and drive it low to power the unit off. +bool board_reset_pin_number(uint8_t pin_number) { + if (pin_number == MICROPY_HW_POWER_HOLD_PIN_NUMBER) { + assert_power_hold(); + return true; + } + return false; +} diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.h b/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.h new file mode 100644 index 00000000000..fc3ad16bdc2 --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "Teenage Engineering ting fx EP-2350" +#define MICROPY_HW_MCU_NAME "rp2350a" + +// Top white LED. Also available as board.LED_WHITE1. +#define MICROPY_HW_LED_STATUS (&pin_GPIO0) + +// GPIO2 is the power hold latch: high keeps the unit powered, low powers it +// off immediately. It is asserted in board_reset_pin_number() so that it +// survives every pin reset. +#define MICROPY_HW_POWER_HOLD_PIN_NUMBER (2) + +// Codec (0x1b) and accelerometer (0x18) share I2C1. External pull-ups. +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO15, .sda = &pin_GPIO14}} diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.mk b/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.mk new file mode 100644 index 00000000000..704edf815e6 --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.mk @@ -0,0 +1,20 @@ +USB_VID = 0x239A +USB_PID = 0x8176 +USB_PRODUCT = "ting fx EP-2350" +USB_MANUFACTURER = "Teenage Engineering" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +# Winbond W25Q16JV, 2MB (16Mbit) on CS0, nothing on CS1. +EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" + +# Only 2MB of flash: firmware gets the default 1020kB and the CIRCUITPY drive +# gets the rest (~1MB). + +# GPIO12-19 are needed for picodvi, but they are all in use here (I2S, I2C, +# LEDs, handle switches) and no pins are broken out. +CIRCUITPY_PICODVI = 0 + +CIRCUITPY__EVE = 1 diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/pico-sdk-configboard.h b/ports/raspberrypi/boards/teenage_engineering_ep2350/pico-sdk-configboard.h new file mode 100644 index 00000000000..f72de7902c9 --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/pico-sdk-configboard.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c new file mode 100644 index 00000000000..ed448aa4def --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c @@ -0,0 +1,118 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // LEDs, one dedicated GPIO each, active high. + // Two columns of four, numbered top (nearest the handle) to bottom. + // Note: GP0 and GP16 share a PWM slice/channel, so the their LEDs + // cannot be PWM-dimmed independently. + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_LED_WHITE1), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_LED_WHITE2), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_LED_WHITE3), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_LED_WHITE4), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_LED_RED1), MP_ROM_PTR(&pin_GPIO16) }, + + { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_LED_RED2), MP_ROM_PTR(&pin_GPIO24) }, + + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_LED_RED3), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_LED_RED4), MP_ROM_PTR(&pin_GPIO17) }, + + // Side buttons. Switches to ground, no external pull-ups: use Pull.UP, + // pressed reads False. + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_TOP), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_MIDDLE), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_BOTTOM), MP_ROM_PTR(&pin_GPIO1) }, + + // Handle: a two-stage switch. HANDLE_IN reads False when the handle is + // fully seated; HANDLE_OUT reads True as soon as the handle is moved. + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_HANDLE_IN), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_HANDLE_OUT), MP_ROM_PTR(&pin_GPIO20) }, + + // Power hold latch. Held high by the board so the unit stays powered once + // the handle is released. Driving it low powers the unit off immediately. + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_POWER_HOLD), MP_ROM_PTR(&pin_GPIO2) }, + + // I2C1: NAU88L21 codec at 0x1b, accelerometer at 0x18. External pull-ups. + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO15) }, + + // I2S to the codec. The codec is the I2S clock source (it drives BCLK and + // LRCLK); the MCU only supplies MCLK. + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DIN), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DOUT), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WS), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_ROM_PTR(&pin_GPIO12) }, + + // Unidentified / unconnected. + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + + // Analog. GP26/GP27 are unconnected. + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + + // Handle position potentiometer: how far the handle has been pressed in. + // Continuous and monotonic over the travel, but it only swings across a + // narrow part of the range, roughly 32370 counts (1.63 V) with the + // handle at rest down to 29850 counts + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_HANDLE_POSITION), MP_ROM_PTR(&pin_GPIO28) }, + + // Volume potentiometer wiper, full scale 0 - 3.3V. + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_VOLUME), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/board.c b/ports/raspberrypi/boards/tinycircuits_thumby/board.c new file mode 100644 index 00000000000..3a306b35f0d --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/board.c @@ -0,0 +1,81 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + + +uint8_t display_init_sequence[] = { + 0xAE, 0, // DISPLAY_OFF + 0x20, 1, 0x00, // Set memory addressing to horizontal mode. + 0x81, 1, 0xcf, // set contrast control + 0xA1, 0, // Column 127 is segment 0 + 0xA6, 0, // Normal display + 0xc8, 0, // Normal display + 0xA8, 1, 0x3f, // Mux ratio is 1/64 + 0xd5, 1, 0x80, // Set divide ratio + 0xd9, 1, 0xf1, // Set pre-charge period + 0xda, 1, 0x12, // Set com configuration + 0xdb, 1, 0x40, // Set vcom configuration + 0x8d, 1, 0x14, // Enable charge pump + 0xAF, 0, // DISPLAY_ON +}; + +void board_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + common_hal_fourwire_fourwire_construct(bus, + spi, + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_OLED_DC), // Command or data + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_OLED_CS), // Chip select + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_OLED_RESET), // Reset + 10000000, // Baudrate + 0, // Polarity + 0); // Phase + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 72, // Width (after rotation) + 40, // Height (after rotation) + 28, // column start + 28, // row start + 0, // rotation + 1, // Color depth + true, // grayscale + false, // pixels in byte share row. only used for depth < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + 0x21, // Set column command + 0x22, // Set row command + 44, // Write memory command + display_init_sequence, + sizeof(display_init_sequence), + NULL, // backlight pin + 0x81, + 1.0f, // brightness + true, // single_byte_bounds + true, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 0); // backlight pwm frequency +} + +void reset_board(void) { +} diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h new file mode 100644 index 00000000000..cec0fc10f55 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "TinyCircuits Thumby" +#define MICROPY_HW_MCU_NAME "rp2040" + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19) + +#define CIRCUITPY_BOARD_OLED_DC (&pin_GPIO17) +#define CIRCUITPY_BOARD_OLED_CS (&pin_GPIO16) +#define CIRCUITPY_BOARD_OLED_RESET (&pin_GPIO20) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk new file mode 100644 index 00000000000..d8140e6cb0a --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk @@ -0,0 +1,18 @@ +USB_VID = 0x1209 +USB_PID = 0x3500 +USB_PRODUCT = "Thumby" +USB_MANUFACTURER = "TinyCircuits" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" + +CIRCUITPY_STAGE = 1 +CIRCUITPY_AUDIOIO = 1 +CIRCUITPY_AUDIOPWMIO = 1 +CIRCUITPY_KEYPAD = 1 + +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_framebuf +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SSD1306 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/pico-sdk-configboard.h b/ports/raspberrypi/boards/tinycircuits_thumby/pico-sdk-configboard.h new file mode 100644 index 00000000000..ce5a7645b4e --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/pico-sdk-configboard.h @@ -0,0 +1,12 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. + +// Allow extra time for xosc to start. +#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64 diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/pins.c b/ports/raspberrypi/boards/tinycircuits_thumby/pins.c new file mode 100644 index 00000000000..0a087bb8db8 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/pins.c @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Link Cable (ASR00074) + { MP_ROM_QSTR(MP_QSTR_EXT_TX), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_EXT), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_EXT_PU), MP_ROM_PTR(&pin_GPIO1) }, + + // 0.42 inch OLED AST1042 + { MP_ROM_QSTR(MP_QSTR_OLED_CS), MP_ROM_PTR(CIRCUITPY_BOARD_OLED_CS) }, + { MP_ROM_QSTR(MP_QSTR_OLED_DC), MP_ROM_PTR(CIRCUITPY_BOARD_OLED_DC) }, + { MP_ROM_QSTR(MP_QSTR_OLED_RESET), MP_ROM_PTR(CIRCUITPY_BOARD_OLED_RESET) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(DEFAULT_SPI_BUS_SCK) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(DEFAULT_SPI_BUS_MOSI) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, + + // Buttons + { MP_ROM_QSTR(MP_QSTR_BUTTON_LEFT), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_UP), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_DOWN), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_1), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_2), MP_ROM_PTR(&pin_GPIO27) }, + + // Mono PWM Speaker + { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_GPIO28) }, + + // Hardware revision ID pins + { MP_OBJ_NEW_QSTR(MP_QSTR_ID3), MP_ROM_PTR(&pin_GPIO12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ID2), MP_ROM_PTR(&pin_GPIO13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ID1), MP_ROM_PTR(&pin_GPIO14) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ID0), MP_ROM_PTR(&pin_GPIO15) }, + + // Power pins + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO26) } +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c b/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c new file mode 100644 index 00000000000..17c512cb2a6 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c @@ -0,0 +1,108 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + + +#define DELAY 0x80 + +// display init sequence according to TinyCircuits-Tiny-Game-Engine +uint8_t display_init_sequence[] = { + 0xFE, 0, // inter register enable 1 + 0xEF, 0, // inter register enable 2 + 0xB0, 1, 0xC0, + 0xB1, 1, 0x80, + 0xB2, 1, 0x2F, + 0xB3, 1, 0x03, + 0xB7, 1, 0x01, + 0xB6, 1, 0x19, + 0xAC, 1, 0xC8, // Complement Principle of RGB 5, 6, 5 + 0xAB, 1, 0x0f, // ? + 0x3A, 1, 0x05, // COLMOD: Pixel Format Set + 0xB4, 1, 0x04, // ? + 0xA8, 1, 0x07, // Frame Rate Set + 0xB8, 1, 0x08, // ? + 0xE7, 1, 0x5A, // VREG_CTL + 0xE8, 1, 0x23, // VGH_SET + 0xE9, 1, 0x47, // VGL_SET + 0xEA, 1, 0x99, // VGH_VGL_CLK + 0xC6, 1, 0x30, // ? + 0xC7, 1, 0x1F, // ? + 0xF0, 14, 0x05, 0x1D, 0x51, 0x2F, 0x85, 0x2A, 0x11, 0x62, 0x00, 0x07, 0x07, 0x0F, 0x08, 0x1F, // SET_GAMMA1 + 0xF1, 14, 0x2E, 0x41, 0x62, 0x56, 0xA5, 0x3A, 0x3f, 0x60, 0x0F, 0x07, 0x0A, 0x18, 0x18, 0x1D, // SET_GAMMA2 + 0x11, 0 | DELAY, 120, + 0x29, 0 | DELAY, 10, // display on +}; + +void board_init(void) { + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct( + spi, + DEFAULT_SPI_BUS_SCK, // CLK + DEFAULT_SPI_BUS_MOSI, // MOSI + NULL, // MISO not connected + false // Not half-duplex + ); + + common_hal_busio_spi_never_reset(spi); + + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_LCD_DC), // DC + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_LCD_CS), // CS + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_LCD_RESET), // RST + 80000000, // baudrate + 0, // polarity + 0 // phase + ); + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 128, // width (after rotation) + 128, // height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + CIRCUITPY_BOARD_LCD_BACKLIGHT, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} + +void reset_board(void) { +} diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h new file mode 100644 index 00000000000..fc76138bb8a --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h @@ -0,0 +1,27 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "TinyCircuits Thumby Color" +#define MICROPY_HW_MCU_NAME "rp2350" + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO9) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO8) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = DEFAULT_I2C_BUS_SCL, .sda = DEFAULT_I2C_BUS_SDA}} + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19) + +#define CIRCUITPY_BOARD_LCD_DC (&pin_GPIO16) +#define CIRCUITPY_BOARD_LCD_CS (&pin_GPIO17) +#define CIRCUITPY_BOARD_LCD_RESET (&pin_GPIO4) +#define CIRCUITPY_BOARD_LCD_BACKLIGHT (&pin_GPIO7) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk new file mode 100644 index 00000000000..6159a39ba55 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk @@ -0,0 +1,18 @@ +USB_VID = 0x1209 +USB_PID = 0x3501 +USB_PRODUCT = "Thumby Color" +USB_MANUFACTURER = "TinyCircuits" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +CIRCUITPY_STAGE = 1 +CIRCUITPY_AUDIOIO = 1 +CIRCUITPY_AUDIOPWMIO = 1 +CIRCUITPY_KEYPAD = 1 + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/pico-sdk-configboard.h b/ports/raspberrypi/boards/tinycircuits_thumby_color/pico-sdk-configboard.h new file mode 100644 index 00000000000..110195b7794 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/pins.c b/ports/raspberrypi/boards/tinycircuits_thumby_color/pins.c new file mode 100644 index 00000000000..d0e63512d7a --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/pins.c @@ -0,0 +1,58 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Buttons + { MP_ROM_QSTR(MP_QSTR_BUTTON_UP), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_LEFT), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_DOWN), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_BUMPER_LEFT), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_BUMPER_RIGHT), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_MENU), MP_ROM_PTR(&pin_GPIO26) }, + + // LED + { MP_ROM_QSTR(MP_QSTR_LED_R), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_LED_G), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_LED_B), MP_ROM_PTR(&pin_GPIO12) }, + + // Rumble + { MP_ROM_QSTR(MP_QSTR_RUMBLE), MP_ROM_PTR(&pin_GPIO5) }, + + // Mono PWM Speaker + { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_SPEAKER_ENABLE), MP_ROM_PTR(&pin_GPIO20) }, + + // 0.85 inch TFT GC9107 + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(CIRCUITPY_BOARD_LCD_CS) }, + { MP_ROM_QSTR(MP_QSTR_LCD_DC), MP_ROM_PTR(CIRCUITPY_BOARD_LCD_DC) }, + { MP_ROM_QSTR(MP_QSTR_LCD_RESET), MP_ROM_PTR(CIRCUITPY_BOARD_LCD_RESET) }, + { MP_ROM_QSTR(MP_QSTR_LCD_BACKLIGHT), MP_ROM_PTR(CIRCUITPY_BOARD_LCD_BACKLIGHT) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(DEFAULT_SPI_BUS_SCK) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(DEFAULT_SPI_BUS_MOSI) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SPI), MP_ROM_PTR(&board_spi_obj) }, + + // RTC I2C + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(DEFAULT_I2C_BUS_SDA) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(DEFAULT_I2C_BUS_SCL) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + // Power pins + { MP_ROM_QSTR(MP_QSTR_CHARGE_STAT), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/ugame22/board.c b/ports/raspberrypi/boards/ugame22/board.c index 6b8152b14ee..ed17a13ebc1 100644 --- a/ports/raspberrypi/boards/ugame22/board.c +++ b/ports/raspberrypi/boards/ugame22/board.c @@ -52,9 +52,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO1, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO1), // TFT_RST Reset 80000000L, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/waveshare_rp2040_geek/board.c b/ports/raspberrypi/boards/waveshare_rp2040_geek/board.c index 71269f0d185..431840fb0c5 100644 --- a/ports/raspberrypi/boards/waveshare_rp2040_geek/board.c +++ b/ports/raspberrypi/boards/waveshare_rp2040_geek/board.c @@ -37,9 +37,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // TFT_DC - &pin_GPIO9, // TFT_CS - &pin_GPIO12, // TFT_RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // TFT_DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // TFT_RST 50000000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/raspberrypi/boards/waveshare_rp2040_lcd_0_96/board.c b/ports/raspberrypi/boards/waveshare_rp2040_lcd_0_96/board.c index f17ca53d724..44d279da43f 100644 --- a/ports/raspberrypi/boards/waveshare_rp2040_lcd_0_96/board.c +++ b/ports/raspberrypi/boards/waveshare_rp2040_lcd_0_96/board.c @@ -60,9 +60,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // DC - &pin_GPIO9, // CS - &pin_GPIO12, // RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/raspberrypi/boards/waveshare_rp2350_geek/board.c b/ports/raspberrypi/boards/waveshare_rp2350_geek/board.c index 71269f0d185..431840fb0c5 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_geek/board.c +++ b/ports/raspberrypi/boards/waveshare_rp2350_geek/board.c @@ -37,9 +37,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // TFT_DC - &pin_GPIO9, // TFT_CS - &pin_GPIO12, // TFT_RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // TFT_DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // TFT_RST 50000000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/raspberrypi/boards/waveshare_rp2350_geek/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_geek/mpconfigboard.mk index 38b69c182c7..e1d89c1fbca 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_geek/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_geek/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but many of the pins are used for other purposes. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_lcd_0_96/board.c b/ports/raspberrypi/boards/waveshare_rp2350_lcd_0_96/board.c index f17ca53d724..44d279da43f 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_lcd_0_96/board.c +++ b/ports/raspberrypi/boards/waveshare_rp2350_lcd_0_96/board.c @@ -60,9 +60,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // DC - &pin_GPIO9, // CS - &pin_GPIO12, // RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/raspberrypi/boards/waveshare_rp2350_lcd_1_28/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_lcd_1_28/mpconfigboard.mk index 8f703c5a932..f04b91f8b0d 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_lcd_1_28/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_lcd_1_28/mpconfigboard.mk @@ -11,6 +11,9 @@ EXTERNAL_FLASH_DEVICES = "P25Q32SH" CIRCUITPY__EVE = 1 +# GPIO12-19 needed for picodvi, but GPIO12 is used for display reset. +CIRCUITPY_PICODVI = 0 + # TODO: Add custom QMI8658 driver # FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython_qmi8658 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_one/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_one/mpconfigboard.mk index 75398b3269b..bde7153c029 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_one/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_one/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but GPIO16 is not broken out and is used for NeoPixel. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_tiny/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_tiny/mpconfigboard.mk index 464c7aff283..79fafbacf5c 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_tiny/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_tiny/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "P25Q32SH" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but GPIO16-19 are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_touch_lcd_1_28/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_touch_lcd_1_28/mpconfigboard.mk index 11e927c7485..0ec6c4ec008 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_touch_lcd_1_28/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_touch_lcd_1_28/mpconfigboard.mk @@ -11,6 +11,9 @@ EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" CIRCUITPY__EVE = 1 +# GPIO12-19 needed for picodvi, but GPIO12 is used for display reset. +CIRCUITPY_PICODVI = 0 + # TODO: Add custom QMI8658 driver # FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython_qmi8658 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_zero/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_zero/mpconfigboard.mk index 444850776a6..7f0a3c71cbb 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_zero/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_zero/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "P25Q32SH" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but GPIO16 is not broken out and is used for NeoPixel. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/board.c b/ports/raspberrypi/boards/weact_studio_rp2350b_core/board.c new file mode 100644 index 00000000000..e6a868ab212 --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h new file mode 100644 index 00000000000..95a81334c73 --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "WeAct Studio RP2350B Core" +#define MICROPY_HW_MCU_NAME "rp2350b" + +#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO0) diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk new file mode 100644 index 00000000000..d86f28280f3 --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk @@ -0,0 +1,12 @@ +USB_VID = 0x1209 +USB_PID = 0xDEC1 +USB_PRODUCT = "RP2350B Core" +USB_MANUFACTURER = "WeAct Studio" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = B +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +CIRCUITPY__EVE = 1 diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/pico-sdk-configboard.h b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pico-sdk-configboard.h new file mode 100644 index 00000000000..66b57dfd13d --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pico-sdk-configboard.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c new file mode 100644 index 00000000000..d6a82becfdd --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c @@ -0,0 +1,91 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, + + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO25) }, + + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_GP30), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_GP31), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_GP32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_GP33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_GP34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_GP35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_GP36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_GP37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_GP38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_GP39), MP_ROM_PTR(&pin_GPIO39) }, + + { MP_ROM_QSTR(MP_QSTR_GP40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO40) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP40_A0), MP_ROM_PTR(&pin_GPIO40) }, + + { MP_ROM_QSTR(MP_QSTR_GP41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO41) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP41_A1), MP_ROM_PTR(&pin_GPIO41) }, + + { MP_ROM_QSTR(MP_QSTR_GP42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO42) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP42_A2), MP_ROM_PTR(&pin_GPIO42) }, + + { MP_ROM_QSTR(MP_QSTR_GP43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO43) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP43_A3), MP_ROM_PTR(&pin_GPIO43) }, + + { MP_ROM_QSTR(MP_QSTR_GP44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO44) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP44_A4), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_GP45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO45) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP45_A5), MP_ROM_PTR(&pin_GPIO45) }, + + { MP_ROM_QSTR(MP_QSTR_GP46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO46) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP46_A6), MP_ROM_PTR(&pin_GPIO46) }, + + { MP_ROM_QSTR(MP_QSTR_GP47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO47) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP47_A7), MP_ROM_PTR(&pin_GPIO47) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/wiznet_w5100s_evb_pico2/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w5100s_evb_pico2/mpconfigboard.mk index 3e3542120e3..d47571e7950 100644 --- a/ports/raspberrypi/boards/wiznet_w5100s_evb_pico2/mpconfigboard.mk +++ b/ports/raspberrypi/boards/wiznet_w5100s_evb_pico2/mpconfigboard.mk @@ -12,5 +12,8 @@ EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 CIRCUITPY_SSL = 1 +# GPIO12-19 needed for picodvi, but GPIO16 is used for Wiznet. +CIRCUITPY_PICODVI = 0 + # The default is -O3. Change to -O2 because the build was overflowing. OPTIMIZATION_FLAGS = -O2 diff --git a/ports/raspberrypi/boards/wiznet_w5500_evb_pico2/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w5500_evb_pico2/mpconfigboard.mk index c10c7aa7eb8..68b621fdf97 100644 --- a/ports/raspberrypi/boards/wiznet_w5500_evb_pico2/mpconfigboard.mk +++ b/ports/raspberrypi/boards/wiznet_w5500_evb_pico2/mpconfigboard.mk @@ -12,5 +12,8 @@ EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 CIRCUITPY_SSL = 1 +# GPIO12-19 needed for picodvi, but GPIO16 is used for Wiznet. +CIRCUITPY_PICODVI = 0 + # The default is -O3. Change to -O2 because the build was overflowing. OPTIMIZATION_FLAGS = -O2 diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/board.c b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/board.c new file mode 100755 index 00000000000..e6a868ab212 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.h b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.h new file mode 100755 index 00000000000..b5ccfb5ffd9 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.h @@ -0,0 +1,30 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "W55RP20-EVB-Pico" +#define MICROPY_HW_MCU_NAME "rp2040" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO19) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO21) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO23) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO22) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO1) +#define DEFAULT_UART_BUS_TX (&pin_GPIO0) + +// Wiznet HW config. +#define MICROPY_HW_WIZNET_PIO_SPI_ID (0) +#define MICROPY_HW_WIZNET_PIO_SPI_BAUDRATE (20 * 1000 * 1000) +#define MICROPY_HW_WIZNET_PIO_SPI_SCK (21) +#define MICROPY_HW_WIZNET_PIO_SPI_MOSI (23) +#define MICROPY_HW_WIZNET_PIO_SPI_MISO (22) +#define MICROPY_HW_WIZNET_PIO_PIN_CS (20) +#define MICROPY_HW_WIZNET_PIO_PIN_RST (25) +// Connecting the INTN pin enables RECV interrupt handling of incoming data. +#define MICROPY_HW_WIZNET_PIN_INTN (24) diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk new file mode 100755 index 00000000000..d43195c0f2a --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk @@ -0,0 +1,16 @@ +USB_VID = 0x2E8A +USB_PID = 0x0005 +USB_PRODUCT = "W55RP20-EVB-Pico" +USB_MANUFACTURER = "WIZnet" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "PY25Q16HB" + +CIRCUITPY_WIZNET = 1 +CIRCUITPY__EVE = 1 +CIRCUITPY_SSL = 1 +CIRCUITPY_USB_HOST = 0 + +OPTIMIZATION_FLAGS = -O2 diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pico-sdk-configboard.h b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pico-sdk-configboard.h new file mode 100755 index 00000000000..110195b7794 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c new file mode 100755 index 00000000000..37ecfd3dfb1 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c @@ -0,0 +1,72 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_CS), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_SCK), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_MISO), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_MOSI), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_INT), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_RST), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + + { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/common-hal/alarm/__init__.c b/ports/raspberrypi/common-hal/alarm/__init__.c index c47ddc31505..39ad8ca1fe6 100644 --- a/ports/raspberrypi/common-hal/alarm/__init__.c +++ b/ports/raspberrypi/common-hal/alarm/__init__.c @@ -191,13 +191,10 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj } void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { - if (n_dios > 0) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); - } _setup_sleep_alarms(true, n_alarms, alarms); } -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { bool timealarm_set = alarm_time_timealarm_is_set(); #if CIRCUITPY_CYW43 diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c index d29f50b06b8..2687af52e2d 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c @@ -167,21 +167,100 @@ const uint16_t i2s_program_left_justified_swap[] = { 0x6201, // 9: out pins, 1 side 0 [2] }; +// External-clock TX. BCLK and WS are inputs driven by something +// else, so the state machine side-sets nothing and waits on the two clocks +// instead. `wait gpio` encodes an absolute pin index, so unlike the internal-clock +// programs above this one cannot be a static table: it is assembled at +// construct time with the pin numbers patched in. +// +// 0: wait 0 gpio W +// 1: wait 1 gpio W ; right channel starts (WS changes on a BCLK fall) +// .wrap_target +// 2: pull noblock ; refills OSR from X on underflow, as the internal-clock program does +// 3: mov x, osr +// 4: set y, 31 +// 5: wait 1 gpio B +// 6: wait 0 gpio B ; drive on the falling edge; receiver latches on rising +// 7: out pins, 1 +// 8: jmp y--, 5 +// .wrap +// +// Left-justified moves the `out` ahead of the two waits, which drives the MSB +// on the same falling edge WS changed on. The first loop iteration's `wait 1` +// otherwise lands on the Philips delay bit, so no pre-roll is needed. +// +// One 32-bit FIFO word covers a whole 16-bit stereo frame; at 24/32 bits the +// frame is two words (right then left). Same layout the internal-clock programs use. +#define I2S_EXT_CLOCK_PROGRAM_LEN (9) +#define I2S_EXT_CLOCK_WRAP_TARGET (2) +#define I2S_EXT_CLOCK_WRAP (8) + +static void build_i2sout_ext_clock_program(uint16_t *prog, uint8_t bclk, uint8_t ws, bool left_justified) { + const uint16_t wait_0_bclk = 0x2000 | bclk; + const uint16_t wait_1_bclk = 0x2080 | bclk; + prog[0] = 0x2000 | ws; // wait 0 gpio W + prog[1] = 0x2080 | ws; // wait 1 gpio W + prog[2] = 0x8080; // pull noblock + prog[3] = 0xa027; // mov x, osr + prog[4] = 0xe05f; // set y, 31 + if (left_justified) { + prog[5] = 0x6001; // out pins, 1 + prog[6] = wait_1_bclk; + prog[7] = wait_0_bclk; + } else { + prog[5] = wait_1_bclk; + prog[6] = wait_0_bclk; + prog[7] = 0x6001; // out pins, 1 + } + prog[8] = 0x0080 | 5; // jmp y--, 5 +} + +// `wait gpio` indices are relative to the PIO's GPIO base, which +// rp2pio_statemachine_construct picks the same way. +static uint8_t i2s_wait_gpio_index(const mcu_pin_obj_t *pin, uint8_t gpio_offset) { + if (pin->number < gpio_offset) { + mp_raise_ValueError(MP_ERROR_TEXT("Cannot use GPIO0..15 together with GPIO32..47")); + } + return pin->number - gpio_offset; +} + void i2sout_reset(void) { } // Caller validates that pins are free. void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool external_clock) { if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } const mcu_pin_obj_t *sideset_pin = NULL; const uint16_t *program = NULL; size_t program_len = 0; - - if (bit_clock->number == word_select->number - 1) { + uint16_t ext_clock_program[I2S_EXT_CLOCK_PROGRAM_LEN]; + pio_pinmask_t wait_gpio_mask = PIO_PINMASK_NONE; + + self->external_clock = external_clock; + + if (external_clock) { + // In external clock mode the clocks are `wait gpio` targets, so they + // need not be sequential GPIOs. + uint8_t gpio_offset = 0; + #if NUM_BANK0_GPIOS > 32 + if (bit_clock->number >= 32 || word_select->number >= 32 || data->number >= 32) { + gpio_offset = 16; + } + #endif + build_i2sout_ext_clock_program(ext_clock_program, + i2s_wait_gpio_index(bit_clock, gpio_offset), + i2s_wait_gpio_index(word_select, gpio_offset), + left_justified); + program = ext_clock_program; + program_len = I2S_EXT_CLOCK_PROGRAM_LEN; + wait_gpio_mask = PIO_PINMASK_OR(PIO_PINMASK_FROM_PIN(bit_clock->number), + PIO_PINMASK_FROM_PIN(word_select->number)); + } else if (bit_clock->number == word_select->number - 1) { sideset_pin = bit_clock; if (left_justified) { @@ -211,23 +290,28 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, common_hal_rp2pio_statemachine_construct( &self->state_machine, program, program_len, - 44100 * 32 * 6, // Clock at 44.1 khz to warm the DAC up. + // Clock at 44.1 khz to warm the DAC up. In external clock mode the SM + // is driven by the waits, not the clock divider, so run it at sysclk. + external_clock ? 0 : 44100 * 32 * 6, NULL, 0, // init NULL, 0, // may_exec data, 1, PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // out pin NULL, 0, // in pins PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // in pulls NULL, 0, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // set pins - sideset_pin, 2, false, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // sideset pins + sideset_pin, sideset_pin == NULL ? 0 : 2, false, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // sideset pins false, // No sideset enable NULL, PULL_NONE, // jump pin - PIO_PINMASK_NONE, // wait gpio pins + wait_gpio_mask, // wait gpio pins + // The clocks are shared through wait_gpio_mask, which _check_gpio_mask_free + // already allows to be shared; the data pin stays exclusively ours. true, // exclusive pin use false, 32, false, // shift out left to start with MSB false, // Wait for txstall false, 32, false, // in settings false, // Not user-interruptible. - 0, -1, // wrap settings + external_clock ? I2S_EXT_CLOCK_WRAP_TARGET : 0, + external_clock ? I2S_EXT_CLOCK_WRAP : -1, // wrap settings PIO_ANY_OFFSET, PIO_FIFO_TYPE_DEFAULT, PIO_MOV_STATUS_DEFAULT, @@ -262,6 +346,8 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, common_hal_audiobusio_i2sout_stop(self); } + audiosample_check(sample); + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); // Make sure we transmit a minimum of 16 bits. // TODO: Maybe we need an intermediate object to upsample instead. This is @@ -278,7 +364,13 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("Too many channels in sample.")); } - common_hal_rp2pio_statemachine_set_frequency(&self->state_machine, clocks_per_bit * frequency); + // An external clock can't be retimed: the sample rate has to match whatever + // the outside world is running WS at, or the pitch is wrong. The restart + // still matters -- it re-execs the program at its offset, so every play() + // re-syncs to WS. + if (!self->external_clock) { + common_hal_rp2pio_statemachine_set_frequency(&self->state_machine, clocks_per_bit * frequency); + } common_hal_rp2pio_statemachine_restart(&self->state_machine); // On the RP2040, output registers are always written with a 32-bit write. diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.h b/ports/raspberrypi/common-hal/audiobusio/I2SOut.h index 2996640dc2d..def66225bf3 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.h +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.h @@ -18,6 +18,7 @@ typedef struct { rp2pio_statemachine_obj_t state_machine; audio_dma_t dma; bool left_justified; + bool external_clock; bool playing; } audiobusio_i2sout_obj_t; diff --git a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c index 327bec8de72..b436469d090 100644 --- a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c +++ b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -43,7 +43,7 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, // Use the state machine to manage pins. common_hal_rp2pio_statemachine_construct(&self->state_machine, pdmin, MP_ARRAY_SIZE(pdmin), - sample_rate * 32 * 2, // Frequency based on sample rate + sample_rate * OVERSAMPLING * 2, // Frequency based on sample rate NULL, 0, NULL, 0, // may_exec NULL, 1, PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // out pin @@ -64,7 +64,8 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, PIO_FIFO_TYPE_DEFAULT, PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine); - if (actual_frequency < MIN_MIC_CLOCK) { + if (actual_frequency < 2 * MIN_MIC_CLOCK) { // 2 PIO samples per audio clock + common_hal_audiobusio_pdmin_deinit(self); mp_raise_ValueError(MP_ERROR_TEXT("sampling rate out of range")); } diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c new file mode 100644 index 00000000000..bb0b0204111 --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -0,0 +1,856 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "shared/runtime/interrupt_char.h" +#include "common-hal/audioi2sin/I2SIn.h" +#include "shared-bindings/audioi2sin/I2SIn.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audioi2sin/__init__.h" +#include "bindings/rp2pio/StateMachine.h" +#include "supervisor/port.h" + +#include "hardware/dma.h" + +#if CIRCUITPY_AUDIOI2SIN + +// 16-bit programs sample a stereo frame of 16+16 = 32 bits and rely on +// auto-push at 32 to deliver one packed (right<<16 | left) word per frame. +// 32-bit programs sample 32 bits per channel and produce two FIFO words per +// frame (right first, then left). Each bit takes 6 PIO clocks (a [2]-delay +// pair). 24-bit recordings reuse the 32-bit programs because most 24-bit +// MEMS mics (SPH0645LM4H, INMP441, ICS-43434) transmit their 24 valid bits +// left-justified inside a 32-bit slot. +// +// `in pins 1` runs on a cycle where side-set drives BCLK high. The attached +// device updates the data line on the BCLK falling edge, so by the rising edge it +// has settled and is safe to sample. Sampling at BCLK low (the previous, +// incorrect arrangement) catches the data mid-transition and the result is +// effectively noise. +#define PIO_CLOCKS_PER_BIT (6) + +// Internal-clock RX, regular pin order (BCLK = WS - 1), Philips alignment. +static const uint16_t i2sin_program[] = { + 0xb842, // 0: nop side 3 + // .wrap_target + 0xf94e, // 1: set y, 14 side 3 [1] + 0xb242, // 2: nop side 2 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xa242, // 5: nop side 0 [2] + 0x4801, // 6: in pins, 1 side 1 + 0xe94e, // 7: set y, 14 side 1 [1] + 0xa242, // 8: nop side 0 [2] + 0x4801, // 9: in pins, 1 side 1 + 0x0988, // 10: jmp y--, 8 side 1 [1] + 0xb242, // 11: nop side 2 [2] + 0x5801, // 12: in pins, 1 side 3 + // .wrap +}; + +// Internal-clock RX, regular pin order, left-justified. +static const uint16_t i2sin_program_left_justified[] = { + 0xa842, // 0: nop side 1 + // .wrap_target + 0xe94e, // 1: set y, 14 side 1 [1] + 0xb242, // 2: nop side 2 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xb242, // 5: nop side 2 [2] + 0x5801, // 6: in pins, 1 side 3 + 0xf94e, // 7: set y, 14 side 3 [1] + 0xa242, // 8: nop side 0 [2] + 0x4801, // 9: in pins, 1 side 1 + 0x0988, // 10: jmp y--, 8 side 1 [1] + 0xa242, // 11: nop side 0 [2] + 0x4801, // 12: in pins, 1 side 1 + // .wrap +}; + +// Internal-clock RX, swapped pin order (BCLK = WS + 1), Philips alignment. +static const uint16_t i2sin_program_swap[] = { + 0xb842, // 0: nop side 3 + // .wrap_target + 0xf94e, // 1: set y, 14 side 3 [1] + 0xaa42, // 2: nop side 1 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xa242, // 5: nop side 0 [2] + 0x5001, // 6: in pins, 1 side 2 + 0xf14e, // 7: set y, 14 side 2 [1] + 0xa242, // 8: nop side 0 [2] + 0x5001, // 9: in pins, 1 side 2 + 0x1188, // 10: jmp y--, 8 side 2 [1] + 0xaa42, // 11: nop side 1 [2] + 0x5801, // 12: in pins, 1 side 3 + // .wrap +}; + +// Internal-clock RX, swapped pin order, left-justified. +static const uint16_t i2sin_program_left_justified_swap[] = { + 0xb042, // 0: nop side 2 + // .wrap_target + 0xf14e, // 1: set y, 14 side 2 [1] + 0xaa42, // 2: nop side 1 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xaa42, // 5: nop side 1 [2] + 0x5801, // 6: in pins, 1 side 3 + 0xf94e, // 7: set y, 14 side 3 [1] + 0xa242, // 8: nop side 0 [2] + 0x5001, // 9: in pins, 1 side 2 + 0x1188, // 10: jmp y--, 8 side 2 [1] + 0xa242, // 11: nop side 0 [2] + 0x5001, // 12: in pins, 1 side 2 + // .wrap +}; + +// 32-bit-per-channel variants: identical to the 16-bit programs above except +// the loop counter is set to 30 (so each `bitloop` runs 31 in's, plus one +// outside the loop = 32 in's per channel). +static const uint16_t i2sin_program_32[] = { + 0xb842, // 0: nop side 3 + // .wrap_target + 0xf95e, // 1: set y, 30 side 3 [1] + 0xb242, // 2: nop side 2 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xa242, // 5: nop side 0 [2] + 0x4801, // 6: in pins, 1 side 1 + 0xe95e, // 7: set y, 30 side 1 [1] + 0xa242, // 8: nop side 0 [2] + 0x4801, // 9: in pins, 1 side 1 + 0x0988, // 10: jmp y--, 8 side 1 [1] + 0xb242, // 11: nop side 2 [2] + 0x5801, // 12: in pins, 1 side 3 + // .wrap +}; + +static const uint16_t i2sin_program_left_justified_32[] = { + 0xa842, // 0: nop side 1 + // .wrap_target + 0xe95e, // 1: set y, 30 side 1 [1] + 0xb242, // 2: nop side 2 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xb242, // 5: nop side 2 [2] + 0x5801, // 6: in pins, 1 side 3 + 0xf95e, // 7: set y, 30 side 3 [1] + 0xa242, // 8: nop side 0 [2] + 0x4801, // 9: in pins, 1 side 1 + 0x0988, // 10: jmp y--, 8 side 1 [1] + 0xa242, // 11: nop side 0 [2] + 0x4801, // 12: in pins, 1 side 1 + // .wrap +}; + +static const uint16_t i2sin_program_swap_32[] = { + 0xb842, // 0: nop side 3 + // .wrap_target + 0xf95e, // 1: set y, 30 side 3 [1] + 0xaa42, // 2: nop side 1 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xa242, // 5: nop side 0 [2] + 0x5001, // 6: in pins, 1 side 2 + 0xf15e, // 7: set y, 30 side 2 [1] + 0xa242, // 8: nop side 0 [2] + 0x5001, // 9: in pins, 1 side 2 + 0x1188, // 10: jmp y--, 8 side 2 [1] + 0xaa42, // 11: nop side 1 [2] + 0x5801, // 12: in pins, 1 side 3 + // .wrap +}; + +static const uint16_t i2sin_program_left_justified_swap_32[] = { + 0xb042, // 0: nop side 2 + // .wrap_target + 0xf15e, // 1: set y, 30 side 2 [1] + 0xaa42, // 2: nop side 1 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xaa42, // 5: nop side 1 [2] + 0x5801, // 6: in pins, 1 side 3 + 0xf95e, // 7: set y, 30 side 3 [1] + 0xa242, // 8: nop side 0 [2] + 0x5001, // 9: in pins, 1 side 2 + 0x1188, // 10: jmp y--, 8 side 2 [1] + 0xa242, // 11: nop side 0 [2] + 0x5001, // 12: in pins, 1 side 2 + // .wrap +}; + +// External-clock RX. BCLK and WS are inputs driven by something +// else -- another I2S object or the codec -- so the state machine side-sets +// nothing and waits on the two clocks instead. `wait gpio` encodes an absolute +// pin index, so unlike the internal-clock programs above this one is assembled at +// construct time with the pin numbers patched in. +// +// 0: wait 0 gpio W ; resync: find a WS rising edge, i.e. the start +// 1: wait 1 gpio W ; of the RIGHT channel (matches word order) +// .wrap_target +// 2: set y, 31 +// 3: wait 0 gpio B ; data changes here +// 4: wait 1 gpio B ; ...and is settled here +// 5: in pins, 1 +// 6: jmp y--, 3 +// .wrap +// +// `set y, 31` + `jmp y--` runs the loop exactly 32 times, so with auto-push at +// 32 and shift-left this pushes one 32-bit word per 32 BCLK, MSB first -- +// identical to what the internal-clock programs produce, so record_to_buffer and +// fill_buffer need no changes. One template covers every bit_depth: at 16 bits +// a 32-BCLK frame is one push (right<<16 | left), at 24/32 a 64-BCLK frame is +// two pushes (right then left). +// +// The WS resync lands on the first data bit, so the program above is +// the `left_justified` alignment: data starts on the WS edge and no instruction +// is spent on a delay bit. The default (Philips) alignment is that program plus +// one more BCLK of skew, the other of the two possible alignments. +// +// Free-running after the initial sync: the external frame must be exactly +// 2 x bits_per_channel BCLKs, the same assumption internal clock mode already bakes +// in. If sync is lost it stays lost. +#define I2SIN_EXT_CLOCK_MAX_PROGRAM_LEN (8) +// The bit loop is the last 5 instructions; everything before it is one-shot sync. +#define I2SIN_EXT_CLOCK_WRAP_TARGET(len) ((int)(len) - 5) + +static size_t build_i2sin_ext_clock_program(uint16_t *prog, uint8_t bclk, uint8_t ws, + bool left_justified) { + const uint16_t wait_0_bclk = 0x2000 | bclk; + const uint16_t wait_1_bclk = 0x2080 | bclk; + size_t len = 0; + prog[len++] = 0x2000 | ws; // wait 0 gpio W + prog[len++] = 0x2080 | ws; // wait 1 gpio W + if (!left_justified) { + prog[len++] = wait_1_bclk; // one more BCLK of skew + } + const size_t bitloop = len + 1; + prog[len++] = 0xe05f; // set y, 31 + prog[len++] = wait_0_bclk; + prog[len++] = wait_1_bclk; + prog[len++] = 0x4001; // in pins, 1 + prog[len++] = 0x0080 | bitloop; // jmp y--, bitloop + return len; +} + +// `wait gpio` indices are relative to the PIO's GPIO base, which +// rp2pio_statemachine_construct picks the same way. +static uint8_t i2s_wait_gpio_index(const mcu_pin_obj_t *pin, uint8_t gpio_offset) { + if (pin->number < gpio_offset) { + mp_raise_ValueError(MP_ERROR_TEXT("Cannot use GPIO0..15 together with GPIO32..47")); + } + return pin->number - gpio_offset; +} + +// Caller validates that pins are free. +void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, + const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, + uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, + bool mono, bool left_justified, bool samples_signed, + bool external_clock) { + + if (main_clock != NULL) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); + } + if (bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be 16, 24, or 32"), MP_QSTR_bit_depth); + } + + // 24- and 32-bit recordings both clock 32 bits per channel; 24-bit MEMS + // mics deliver their data left-justified inside that 32-bit slot. + bool wide = (bit_depth != 16); + uint32_t bits_per_channel = wide ? 32 : 16; + uint32_t pio_clocks_per_frame = bits_per_channel * 2 * PIO_CLOCKS_PER_BIT; + + const mcu_pin_obj_t *sideset_pin = NULL; + const uint16_t *program = NULL; + size_t program_len = 0; + uint16_t ext_clock_program[I2SIN_EXT_CLOCK_MAX_PROGRAM_LEN]; + pio_pinmask_t wait_gpio_mask = PIO_PINMASK_NONE; + + if (external_clock) { + // In external clock mode the clocks are `wait gpio` targets, so they + // need not be sequential GPIOs. + uint8_t gpio_offset = 0; + #if NUM_BANK0_GPIOS > 32 + if (bit_clock->number >= 32 || word_select->number >= 32 || data->number >= 32) { + gpio_offset = 16; + } + #endif + program_len = build_i2sin_ext_clock_program(ext_clock_program, + i2s_wait_gpio_index(bit_clock, gpio_offset), + i2s_wait_gpio_index(word_select, gpio_offset), + left_justified); + program = ext_clock_program; + wait_gpio_mask = PIO_PINMASK_OR(PIO_PINMASK_FROM_PIN(bit_clock->number), + PIO_PINMASK_FROM_PIN(word_select->number)); + } else if (bit_clock->number == word_select->number - 1) { + sideset_pin = bit_clock; + if (left_justified) { + program = wide ? i2sin_program_left_justified_32 : i2sin_program_left_justified; + program_len = wide ? MP_ARRAY_SIZE(i2sin_program_left_justified_32) + : MP_ARRAY_SIZE(i2sin_program_left_justified); + } else { + program = wide ? i2sin_program_32 : i2sin_program; + program_len = wide ? MP_ARRAY_SIZE(i2sin_program_32) + : MP_ARRAY_SIZE(i2sin_program); + } + } else if (bit_clock->number == word_select->number + 1) { + sideset_pin = word_select; + if (left_justified) { + program = wide ? i2sin_program_left_justified_swap_32 : i2sin_program_left_justified_swap; + program_len = wide ? MP_ARRAY_SIZE(i2sin_program_left_justified_swap_32) + : MP_ARRAY_SIZE(i2sin_program_left_justified_swap); + } else { + program = wide ? i2sin_program_swap_32 : i2sin_program_swap; + program_len = wide ? MP_ARRAY_SIZE(i2sin_program_swap_32) + : MP_ARRAY_SIZE(i2sin_program_swap); + } + } else { + mp_raise_ValueError(MP_ERROR_TEXT("Bit clock and word select must be sequential GPIO pins")); + } + + common_hal_rp2pio_statemachine_construct( + &self->state_machine, + program, program_len, + // In external clock mode the SM is driven by the waits, not the clock + // divider, so run it at sysclk. + external_clock ? 0 : sample_rate *pio_clocks_per_frame, + NULL, 0, // init + NULL, 0, // may_exec + NULL, 0, PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // out pin + data, 1, // in pins + PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // in pulls + NULL, 0, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // set pins + sideset_pin, sideset_pin == NULL ? 0 : 2, false, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // sideset pins + false, // No sideset enable + NULL, PULL_NONE, // jump pin + wait_gpio_mask, // wait gpio pins + // The clocks are shared through wait_gpio_mask, which _check_gpio_mask_free + // already allows to be shared; the data pin stays exclusively ours. + true, // exclusive pin use + false, 32, false, // out settings (unused) + false, // Wait for txstall + true, 32, false, // in settings: auto-push at 32 bits, shift left (MSB first) + false, // Not user-interruptible. + external_clock ? I2SIN_EXT_CLOCK_WRAP_TARGET(program_len) : 1, + external_clock ? (int)program_len - 1 : -1, // wrap settings + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, + PIO_MOV_N_DEFAULT); + + // In external clock mode the SM runs at sysclk and the real rate is + // whatever the outside world drives WS at, so `sample_rate` is a + // declaration rather than a measurement. A mismatch shows up as the same + // slow drift the underrun-pad / overflow-drop paths in fill_buffer absorb. + self->sample_rate = external_clock + ? sample_rate + : common_hal_rp2pio_statemachine_get_frequency(&self->state_machine) / pio_clocks_per_frame; + self->bit_depth = bit_depth; + self->mono = mono; + self->samples_signed = samples_signed; + self->left_justified = left_justified; + self->external_clock = external_clock; + self->settled = false; + self->ring = NULL; + self->ring_size = 0; + self->half_size = 0; + self->read_pos = 0; + self->dma_channel = -1; + self->overflow = false; + + // Populate the audiosample base so I2SIn can feed the audio pipeline as a + // streaming source. The output depth must be 8 or 16 to actually stream; we + // still fill base here (so sample_rate/bits_per_sample/etc. read back) and + // raise from reset_buffer if a 24/32-bit instance is played. The owned + // conversion buffer is allocated lazily on first reset_buffer(). + uint8_t channel_count = mono ? 1 : 2; + // Report the *nominal* requested rate (not the PIO-derived self->sample_rate, + // which can be off by a fraction of a Hz). audiosample_must_match requires + // exact equality against the consumer, which is configured for the nominal + // rate; the tiny capture-clock difference shows up as the slow drift that the + // underrun silence-pad / overflow-drop paths in fill_buffer absorb. + self->base.sample_rate = sample_rate; + self->base.bits_per_sample = output_bit_depth; + self->base.channel_count = channel_count; + self->base.samples_signed = samples_signed; + self->base.single_buffer = false; + self->base.max_buffer_length = + 2 * AUDIOI2SIN_STREAM_FRAMES * (output_bit_depth / 8) * channel_count; + self->output_buffer = NULL; + self->output_half_bytes = self->base.max_buffer_length / 2; + self->output_index = 0; + + // Each PIO frame produces 4 bytes in the FIFO regardless of bit depth + // (16-bit auto-pushes one packed stereo word, 24/32-bit pushes two + // separate 32-bit words). One stereo frame is therefore either 4 or + // 8 bytes; size the half-buffer for ~40 ms of audio so a slow consumer + // (SD card flush etc.) can complete without overrunning. + size_t bytes_per_frame = (bit_depth == 16) ? 4 : 8; + size_t target = (size_t)self->sample_rate * bytes_per_frame * 40 / 1000; + size_t half_size = (target > 4096) ? target : 4096; + // Round up to a multiple of 8 so 24/32-bit pair reads never straddle + // the half boundary. + half_size = (half_size + 7u) & ~(size_t)7u; + + self->ring = (uint8_t *)port_malloc(2 * half_size, true); + if (self->ring == NULL) { + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + m_malloc_fail(2 * half_size); + } + self->half_size = half_size; + self->ring_size = 2 * half_size; + + common_hal_rp2pio_statemachine_set_read_buffers_raw(&self->state_machine, + NULL, 0, + self->ring, half_size, + self->ring + half_size, half_size); + if (!common_hal_rp2pio_statemachine_background_read(&self->state_machine, 4, false)) { + port_free(self->ring); + self->ring = NULL; + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + mp_raise_OSError(MP_EIO); + } + self->dma_channel = common_hal_rp2pio_statemachine_get_read_dma_channel(&self->state_machine); +} + +bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self) { + return common_hal_rp2pio_statemachine_deinited(&self->state_machine); +} + +void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self) { + if (common_hal_audioi2sin_i2sin_deinited(self)) { + return; + } + common_hal_rp2pio_statemachine_stop_background_read(&self->state_machine); + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + if (self->ring != NULL) { + port_free(self->ring); + self->ring = NULL; + } + if (self->output_buffer != NULL) { + port_free(self->output_buffer); + self->output_buffer = NULL; + } + self->ring_size = 0; + self->half_size = 0; + self->dma_channel = -1; + audiosample_mark_deinit(&self->base); +} + +uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self) { + return self->bit_depth; +} + +uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self) { + return self->sample_rate; +} + +bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self) { + return self->samples_signed; +} + +// The flag latches when record_to_buffer or fill_buffer finds the DMA more than +// a half-buffer ahead of the read cursor and has to skip forward. Reading clears +// it so a streaming consumer can attribute each report to a known interval. +bool common_hal_audioi2sin_i2sin_get_overflow(audioi2sin_i2sin_obj_t *self) { + bool overflow = self->overflow; + self->overflow = false; + return overflow; +} + +// In 16-bit mode, each PIO frame produces a single 32-bit FIFO word with bits +// 31..16 = right channel and bits 15..0 = left channel (both MSB-first signed +// 16-bit). In 24/32-bit mode each frame produces two FIFO words: right first, +// then left, each MSB-first in the full 32 bits. For mono we keep the left +// channel; for stereo we emit (left, right) pairs. +// +// `output_buffer_length` is the requested number of samples to write (sample +// width = 2 bytes for bit_depth=16, 4 bytes for bit_depth=24 or 32). Returns +// the number actually written. +// Compute the byte offset inside `ring` that the DMA is currently writing +// (one past the last word it finished). Always lies in [0, ring_size). +static size_t i2sin_write_pos(audioi2sin_i2sin_obj_t *self) { + uintptr_t addr = (uintptr_t)dma_channel_hw_addr(self->dma_channel)->write_addr; + uintptr_t base = (uintptr_t)self->ring; + if (addr < base || addr >= base + self->ring_size) { + // The ISR retargets write_addr to the start of the next half right + // after a transfer completes; it should always be in-range, but if + // we observe it mid-update just report "no new data". + return self->read_pos; + } + return (size_t)(addr - base); +} + +// 24-bit non-left-justified data arrives in the low 24 bits of the FIFO word +// with the sign bit at bit 23 and bits 31..24 zero. To make it decode +// correctly as int32 (array typecode "i"), lift the sign bit to bit 31. +static inline uint32_t movesign24(uint32_t val) { + return ((val & 0x800000u) << 8) | (val & 0x7fffffu); +} + +// Sign-extend a raw FIFO sample to a canonical int32 value. `raw` holds the +// sample as delivered by the PIO program for the given input bit depth and +// alignment. The returned int32 represents the same magnitude with the sign +// bit at bit 31. +static inline int32_t i2sin_normalize_signed(uint32_t raw, uint8_t in_depth, + bool left_justified) { + if (in_depth == 32) { + return (int32_t)raw; + } + if (in_depth == 24) { + if (left_justified) { + // value in bits 31..8, sign at 31; arithmetic shift right 8 + return (int32_t)raw >> 8; + } + // value in bits 23..0, sign at 23 + uint32_t sign_bit = 0x800000u; + return (int32_t)((raw ^ sign_bit) - sign_bit); + } + // 16-bit: low 16 bits, sign at 15 + return (int16_t)(raw & 0xffffu); +} + +// Normalize `raw` (input-depth bits, just-read FIFO sample) for this port's wire +// format, then hand off to the shared converter to rescale `in_depth` -> +// `out_depth` and write it to `buffer` at sample index `idx`. The depth +// conversion + unsigned-WAV flip + container store live in +// `shared_audioi2sin_write_converted` (shared with other ports); see that helper +// for the upscale/downscale semantics. +// +// For signed 24-bit output, the int32 slot holds the sign-extended value +// (range -2^23 .. 2^23-1) — unlike the default `output_bit_depth=bit_depth=24` +// path which uses `movesign24`, the converted path returns proper two's +// complement so the result decodes correctly as int32. +static inline void i2sin_write_converted(void *buffer, uint32_t idx, + uint32_t raw, uint8_t in_depth, uint8_t out_depth, + bool samples_signed, bool left_justified) { + int32_t s = i2sin_normalize_signed(raw, in_depth, left_justified); + shared_audioi2sin_write_converted(buffer, idx, s, in_depth, out_depth, samples_signed); +} + +uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, + void *buffer, uint32_t output_buffer_length) { + uint32_t output_count = 0; + const size_t ring_size = self->ring_size; + const size_t half_size = self->half_size; + + // I2S delivers signed PCM. When the caller asked for unsigned samples, + // flip the sign bit per sample (XOR with 0x8000 for 16-bit, 0x800000 for + // 24-bit data in a 32-bit slot, 0x80000000 for 32-bit), matching the WAV + // convention. The default (no-conversion) path applies the flip to the + // raw FIFO word before splitting into channels; the conversion path + // applies the flip per output sample at output bit width. + const bool convert = self->base.bits_per_sample != self->bit_depth; + const uint32_t flip16 = (!convert && !self->samples_signed) ? 0x80008000u : 0u; + const uint32_t flip32 = (!convert && !self->samples_signed) + ? (self->bit_depth == 24 ? 0x800000u : 0x80000000u) + : 0u; + const bool fix_sign24 = !convert + && self->bit_depth == 24 + && self->samples_signed + && !self->left_justified; + const uint8_t in_depth = self->bit_depth; + const uint8_t out_depth = self->base.bits_per_sample; + const bool left_justified = self->left_justified; + const bool samples_signed = self->samples_signed; + + if (self->bit_depth == 16) { + // 16-bit mode auto-pushes one stereo frame per FIFO word. The DMA has + // been streaming since construct time, so the ring already contains + // settled data; drop the first 4 bytes once to discard a single + // pre-record frame (matches the prior synchronous behaviour). + uint16_t *output = convert ? NULL : (uint16_t *)buffer; + while (output_count < output_buffer_length) { + size_t write_pos = i2sin_write_pos(self); + size_t avail = (write_pos + ring_size - self->read_pos) % ring_size; + if (avail > half_size) { + // DMA has filled more than one half ahead of us -- we lost + // data. Snap to just behind the DMA on a 4-byte boundary. + self->overflow = true; + self->read_pos = write_pos & ~(size_t)3u; + avail = 0; + } + if (!self->settled && avail >= 4) { + self->read_pos = (self->read_pos + 4) % ring_size; + avail -= 4; + self->settled = true; + } + if (avail < 4) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + return output_count; + } + continue; + } + while (avail >= 4 && output_count < output_buffer_length) { + uint32_t frame = *(volatile uint32_t *)(self->ring + self->read_pos) ^ flip16; + uint16_t left = (uint16_t)(frame & 0xffff); + uint16_t right = (uint16_t)(frame >> 16); + if (!convert) { + if (self->mono) { + output[output_count++] = left; + } else { + output[output_count++] = left; + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 4) % ring_size; + avail -= 4; + break; + } + output[output_count++] = right; + } + } else { + i2sin_write_converted(buffer, output_count++, left, + in_depth, out_depth, samples_signed, left_justified); + if (!self->mono) { + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 4) % ring_size; + avail -= 4; + break; + } + i2sin_write_converted(buffer, output_count++, right, + in_depth, out_depth, samples_signed, left_justified); + } + } + self->read_pos = (self->read_pos + 4) % ring_size; + avail -= 4; + } + } + } else { + // 24-/32-bit mode emits two FIFO pushes per stereo frame (right then + // left). The state machine was started at instruction 0 by the + // constructor, so the very first push is the right channel and + // alternation is preserved as long as we never touch the program + // counter and always read an even number of words. half_size is a + // multiple of 8, so reading 8-byte pairs stays aligned across the + // ring wrap. + uint32_t *output = convert ? NULL : (uint32_t *)buffer; + while (output_count < output_buffer_length) { + size_t write_pos = i2sin_write_pos(self); + size_t avail = (write_pos + ring_size - self->read_pos) % ring_size; + if (avail > half_size) { + // Overflow: snap to a frame-aligned position one half behind + // the DMA's current half so we resume on the right channel. + self->overflow = true; + size_t cur_half = (write_pos < half_size) ? 0 : half_size; + self->read_pos = (cur_half + half_size) % ring_size; + self->settled = false; + avail = (write_pos + ring_size - self->read_pos) % ring_size; + } + if (!self->settled && avail >= 8) { + self->read_pos = (self->read_pos + 8) % ring_size; + avail -= 8; + self->settled = true; + } + if (avail < 8) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + return output_count; + } + continue; + } + while (avail >= 8 && output_count < output_buffer_length) { + uint32_t right = *(volatile uint32_t *)(self->ring + self->read_pos) ^ flip32; + size_t next_pos = (self->read_pos + 4) % ring_size; + uint32_t left = *(volatile uint32_t *)(self->ring + next_pos) ^ flip32; + if (fix_sign24) { + right = movesign24(right); + left = movesign24(left); + } + if (!convert) { + if (self->mono) { + output[output_count++] = left; + } else { + output[output_count++] = left; + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 8) % ring_size; + avail -= 8; + break; + } + output[output_count++] = right; + } + } else { + i2sin_write_converted(buffer, output_count++, left, + in_depth, out_depth, samples_signed, left_justified); + if (!self->mono) { + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 8) % ring_size; + avail -= 8; + break; + } + i2sin_write_converted(buffer, output_count++, right, + in_depth, out_depth, samples_signed, left_justified); + } + } + self->read_pos = (self->read_pos + 8) % ring_size; + avail -= 8; + } + } + } + + return output_count; +} + +// Write `count` silence samples at output depth starting at sample index `idx`. +// For signed PCM silence is 0; for unsigned (WAV) it is mid-scale. +static void i2sin_fill_silence(void *buffer, uint32_t idx, uint32_t count, + uint8_t out_depth, bool samples_signed) { + if (out_depth == 8) { + uint8_t v = samples_signed ? 0 : 0x80u; + memset((uint8_t *)buffer + idx, v, count); + } else { // 16-bit (the only other streamable width) + uint16_t v = samples_signed ? 0 : 0x8000u; + uint16_t *p = (uint16_t *)buffer + idx; + for (uint32_t i = 0; i < count; i++) { + p[i] = v; + } + } +} + +// Non-blocking fill: convert up to `frames` frames currently available in the +// DMA ring into `buffer` (output depth, interleaved), padding the remainder with +// silence on underrun rather than spinning. Used by get_buffer() from the output +// backend's refill interrupt, so it must never block. `out_depth` is always 8 or +// 16 here (reset_buffer rejects 24/32). Reuses the same per-sample conversion as +// record_to_buffer via i2sin_write_converted. +void common_hal_audioi2sin_i2sin_fill_buffer(audioi2sin_i2sin_obj_t *self, + uint8_t *buffer, uint32_t frames) { + const size_t ring_size = self->ring_size; + const size_t half_size = self->half_size; + const uint8_t in_depth = self->bit_depth; + const uint8_t out_depth = self->base.bits_per_sample; + const bool samples_signed = self->samples_signed; + const bool left_justified = self->left_justified; + const bool stereo = !self->mono; + const uint8_t channel_count = stereo ? 2 : 1; + const size_t frame_bytes = (in_depth == 16) ? 4 : 8; + const uint32_t total_samples = frames * channel_count; + + uint32_t produced = 0; + while (produced < total_samples) { + size_t write_pos = i2sin_write_pos(self); + size_t avail = (write_pos + ring_size - self->read_pos) % ring_size; + if (avail > half_size) { + // The consumer is slower than the mic and the ring is filling up + // (the overflow case record_to_buffer also handles). Drop back to + // just behind the DMA so latency stays bounded; the discarded audio + // shows up as a brief discontinuity, not a hang. + self->overflow = true; + if (in_depth == 16) { + self->read_pos = write_pos & ~(size_t)3u; + } else { + size_t cur_half = (write_pos < half_size) ? 0 : half_size; + self->read_pos = (cur_half + half_size) % ring_size; + self->settled = false; + } + avail = (write_pos + ring_size - self->read_pos) % ring_size; + } + if (!self->settled && avail >= frame_bytes) { + // Drop one frame so playback starts on a settled sample and (for + // 24/32-bit) on the right-channel word the program emits first. + self->read_pos = (self->read_pos + frame_bytes) % ring_size; + avail -= frame_bytes; + self->settled = true; + } + if (avail < frame_bytes) { + break; // underrun: pad the rest with silence below + } + uint32_t left, right; + if (in_depth == 16) { + uint32_t fr = *(volatile uint32_t *)(self->ring + self->read_pos); + left = fr & 0xffffu; + right = fr >> 16; + } else { + right = *(volatile uint32_t *)(self->ring + self->read_pos); + size_t next_pos = (self->read_pos + 4) % ring_size; + left = *(volatile uint32_t *)(self->ring + next_pos); + } + i2sin_write_converted(buffer, produced++, left, + in_depth, out_depth, samples_signed, left_justified); + if (stereo && produced < total_samples) { + i2sin_write_converted(buffer, produced++, right, + in_depth, out_depth, samples_signed, left_justified); + } + self->read_pos = (self->read_pos + frame_bytes) % ring_size; + } + if (produced < total_samples) { + i2sin_fill_silence(buffer, produced, total_samples - produced, + out_depth, samples_signed); + } +} + +void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, + bool single_channel_output, uint8_t channel) { + (void)single_channel_output; + (void)channel; + // The audio pipeline only carries 8- or 16-bit samples. 24/32-bit modes can + // still record() but cannot stream; fail clearly the first time playback is + // set up rather than emitting garbage. + if (self->base.bits_per_sample != 8 && self->base.bits_per_sample != 16) { + mp_raise_ValueError_varg( + MP_ERROR_TEXT("%q must be 8 or 16"), MP_QSTR_output_bit_depth); + } + if (self->output_buffer == NULL) { + // The output backend's DMA reads this buffer directly, so it must be + // DMA-capable like the input ring. + self->output_buffer = (uint8_t *)port_malloc(self->base.max_buffer_length, true); + if (self->output_buffer == NULL) { + m_malloc_fail(self->base.max_buffer_length); + } + } + self->output_index = 0; + // An external-clock SM free-runs a 32-BCLK counter from the WS edge it + // synced to at construct time, so anything that disturbs the frame leaves + // it locked to the wrong half-frame or the wrong bit for good. Re-exec the + // program here so playback always begins from a fresh WS sync. An + // internal-clock SM generates its own clocks and has nothing to sync to, + // so leave it alone. + if (self->external_clock) { + common_hal_rp2pio_statemachine_restart(&self->state_machine); + // restart() clears the shift counters but not the RX FIFO, and the + // words still sitting in it were captured with the old alignment. + pio_sm_clear_fifos(self->state_machine.pio, self->state_machine.state_machine); + } + // Resync to live audio: snap the read cursor just behind the DMA write head + // (frame-aligned) and re-settle so playback begins on fresh samples. + size_t write_pos = i2sin_write_pos(self); + self->read_pos = (self->bit_depth == 16) + ? (write_pos & ~(size_t)3u) + : (write_pos & ~(size_t)7u); + self->settled = false; + self->overflow = false; +} + +audioio_get_buffer_result_t common_hal_audioi2sin_i2sin_get_buffer( + audioi2sin_i2sin_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + uint32_t half = self->output_half_bytes; + uint8_t *out = self->output_buffer + half * self->output_index; + self->output_index = 1 - self->output_index; + + uint32_t bytes_per_sample = self->base.bits_per_sample / 8; + uint32_t frames = half / (bytes_per_sample * self->base.channel_count); + common_hal_audioi2sin_i2sin_fill_buffer(self, out, frames); + + if (single_channel_output) { + out += (channel % self->base.channel_count) * bytes_per_sample; + } + *buffer = out; + *buffer_length = half; + // A live mic is an infinite stream; never report DONE or the backend stops. + return GET_BUFFER_MORE_DATA; +} + +#endif // CIRCUITPY_AUDIOI2SIN diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h new file mode 100644 index 00000000000..594a9fccb02 --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "bindings/rp2pio/StateMachine.h" + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" + +// Number of audio frames a single get_buffer() call hands to the output backend +// (one frame = one mono sample, or an L+R pair in stereo). This sets the pull +// granularity and the silence-pad chunk on underrun. Kept independent of the DMA +// half-buffer so the two can be tuned separately. +#define AUDIOI2SIN_STREAM_FRAMES (256) + +typedef struct { + // so I2SIn can be used directly as an audiosample source. + audiosample_base_t base; + uint32_t sample_rate; + uint8_t bit_depth; + bool mono; + bool samples_signed; + bool left_justified; + bool external_clock; + bool settled; + rp2pio_statemachine_obj_t state_machine; + // Background DMA ring buffer. The state machine alternates DMA writes + // between the two halves so BCLK never stalls between record() calls. + uint8_t *ring; + size_t ring_size; + size_t half_size; + size_t read_pos; + int dma_channel; + bool overflow; + // Owned double-buffer returned to the output backend by get_buffer(), holding + // converted (output-depth, interleaved) samples. Allocated lazily on the first + // reset_buffer() so record()-only use pays no extra RAM. base.max_buffer_length + // is the whole buffer; get_buffer() returns output_half_bytes of it. + uint8_t *output_buffer; + size_t output_half_bytes; + uint8_t output_index; +} audioi2sin_i2sin_obj_t; diff --git a/ports/raspberrypi/common-hal/audioi2sin/README.pio b/ports/raspberrypi/common-hal/audioi2sin/README.pio new file mode 100644 index 00000000000..664c1301a72 --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/README.pio @@ -0,0 +1,14 @@ +.pio files right now are compiled by hand with pico-sdk/tools/pioasm and inserted into I2SIn.c + +i2sin.pio I2S RX, 16 bits/channel, regular pin order, not left_justified +i2sin_left.pio I2S RX, 16 bits/channel, regular pin order, left_justified +i2sin_swap.pio I2S RX, 16 bits/channel, swapped pin order, not left_justified +i2sin_swap_left.pio I2S RX, 16 bits/channel, swapped pin order, left_justified +i2sin_32.pio I2S RX, 32 bits/channel, regular pin order, not left_justified +i2sin_left_32.pio I2S RX, 32 bits/channel, regular pin order, left_justified +i2sin_swap_32.pio I2S RX, 32 bits/channel, swapped pin order, not left_justified +i2sin_swap_left_32.pio I2S RX, 32 bits/channel, swapped pin order, left_justified + +The 32-bit programs are also used for bit_depth=24 because most 24-bit I2S +mics (SPH0645LM4H, INMP441, ICS-43434) place their 24 valid data bits +left-justified inside a 32-bit slot. diff --git a/ports/raspberrypi/common-hal/audioi2sin/__init__.c b/ports/raspberrypi/common-hal/audioi2sin/__init__.c new file mode 100644 index 00000000000..584c821b996 --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio new file mode 100644 index 00000000000..b9d7c9ee28e --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio @@ -0,0 +1,34 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin +.side_set 2 + +; Internal-clock I2S RX. Generates BCLK and LRCLK via side-set and samples the +; data pin. The attached device updates `data` on BCLK falling edge, so this +; program samples on the rising edge: every `in pins 1` runs on a side-set value +; with BCLK=1, and the loop/transition instructions hold BCLK=0 so the +; device has time to settle the next bit. + ; /--- LRCLK + ; |/-- BCLK + ; || + nop side 0b11 +.wrap_target + set y 14 side 0b11 [1] +bitloop1: + nop side 0b10 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b00 [2] + in pins 1 side 0b01 + set y 14 side 0b01 [1] +bitloop0: + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b01 + jmp y-- bitloop0 side 0b01 [1] + nop side 0b10 [2] + in pins 1 side 0b11 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio new file mode 100644 index 00000000000..4d79a179668 --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio @@ -0,0 +1,35 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_32 +.side_set 2 + +; Internal-clock I2S RX, 32 bits per channel (also used for 24-bit mics that +; transmit data left-justified in a 32-bit slot). Generates BCLK and LRCLK +; via side-set and samples the data pin. The attached device updates `data` on +; BCLK falling edge, so this program samples on the rising edge: every `in pins 1` +; runs on a side-set value with BCLK=1, and the preceding nop holds BCLK=0 +; so the device has time to settle the next bit. + ; /--- LRCLK + ; |/-- BCLK + ; || + nop side 0b11 +.wrap_target + set y 30 side 0b11 [1] +bitloop1: + nop side 0b10 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b00 [2] + in pins 1 side 0b01 + set y 30 side 0b01 [1] +bitloop0: + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b01 + jmp y-- bitloop0 side 0b01 [1] + nop side 0b10 [2] + in pins 1 side 0b11 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio new file mode 100644 index 00000000000..a5b8cf15970 --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio @@ -0,0 +1,30 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_left +.side_set 2 + +; Internal-clock I2S RX, left-justified. Mirrors the timing of i2s_left.pio. + ; /--- LRCLK + ; |/-- BCLK + ; || + nop side 0b01 +.wrap_target + set y 14 side 0b01 [1] +bitloop1: + nop side 0b10 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b10 [2] + in pins 1 side 0b11 + set y 14 side 0b11 [1] +bitloop0: + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b01 + jmp y-- bitloop0 side 0b01 [1] + nop side 0b00 [2] + in pins 1 side 0b01 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio new file mode 100644 index 00000000000..c7c18073c0d --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio @@ -0,0 +1,30 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_left_32 +.side_set 2 + +; Internal-clock I2S RX, 32 bits per channel, left-justified. + ; /--- LRCLK + ; |/-- BCLK + ; || + nop side 0b01 +.wrap_target + set y 30 side 0b01 [1] +bitloop1: + nop side 0b10 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b10 [2] + in pins 1 side 0b11 + set y 30 side 0b11 [1] +bitloop0: + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b01 + jmp y-- bitloop0 side 0b01 [1] + nop side 0b00 [2] + in pins 1 side 0b01 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio new file mode 100644 index 00000000000..8ff2e468c0c --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio @@ -0,0 +1,31 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_swap +.side_set 2 + +; Internal-clock I2S RX with the LRCLK and BCLK pin order swapped (BCLK is the +; higher-numbered GPIO). + ; /--- BCLK + ; |/-- LRCLK + ; || + nop side 0b11 +.wrap_target + set y 14 side 0b11 [1] +bitloop1: + nop side 0b01 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b00 [2] + in pins 1 side 0b10 + set y 14 side 0b10 [1] +bitloop0: + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b10 + jmp y-- bitloop0 side 0b10 [1] + nop side 0b01 [2] + in pins 1 side 0b11 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio new file mode 100644 index 00000000000..05d92ab019f --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio @@ -0,0 +1,31 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_swap_32 +.side_set 2 + +; Internal-clock I2S RX, 32 bits per channel, with the LRCLK and BCLK pin order +; swapped (BCLK is the higher-numbered GPIO). + ; /--- BCLK + ; |/-- LRCLK + ; || + nop side 0b11 +.wrap_target + set y 30 side 0b11 [1] +bitloop1: + nop side 0b01 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b00 [2] + in pins 1 side 0b10 + set y 30 side 0b10 [1] +bitloop0: + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b10 + jmp y-- bitloop0 side 0b10 [1] + nop side 0b01 [2] + in pins 1 side 0b11 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio new file mode 100644 index 00000000000..79fb1bd7a6a --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio @@ -0,0 +1,31 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_swap_left +.side_set 2 + +; Internal-clock I2S RX, left-justified, with the LRCLK and BCLK pin order +; swapped (BCLK is the higher-numbered GPIO). + ; /--- BCLK + ; |/-- LRCLK + ; || + nop side 0b10 +.wrap_target + set y 14 side 0b10 [1] +bitloop1: + nop side 0b01 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b01 [2] + in pins 1 side 0b11 + set y 14 side 0b11 [1] +bitloop0: + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b10 + jmp y-- bitloop0 side 0b10 [1] + nop side 0b00 [2] + in pins 1 side 0b10 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio new file mode 100644 index 00000000000..0228fa729dd --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio @@ -0,0 +1,31 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_swap_left_32 +.side_set 2 + +; Internal-clock I2S RX, 32 bits per channel, left-justified, with the LRCLK and +; BCLK pin order swapped (BCLK is the higher-numbered GPIO). + ; /--- BCLK + ; |/-- LRCLK + ; || + nop side 0b10 +.wrap_target + set y 30 side 0b10 [1] +bitloop1: + nop side 0b01 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b01 [2] + in pins 1 side 0b11 + set y 30 side 0b11 [1] +bitloop0: + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b10 + jmp y-- bitloop0 side 0b10 [1] + nop side 0b00 [2] + in pins 1 side 0b10 +.wrap diff --git a/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c b/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c index 6fa5bf02c14..3ab8eb814a1 100644 --- a/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c @@ -160,6 +160,8 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, common_hal_audiopwmio_pwmaudioout_stop(self); } + audiosample_check(sample); + // TODO: Share pacing timers based on frequency. size_t pacing_timer = NUM_DMA_TIMERS; for (size_t i = 0; i < NUM_DMA_TIMERS; i++) { diff --git a/ports/raspberrypi/common-hal/busio/I2C.c b/ports/raspberrypi/common-hal/busio/I2C.c index 0f7e023f0e9..54cebee5193 100644 --- a/ports/raspberrypi/common-hal/busio/I2C.c +++ b/ports/raspberrypi/common-hal/busio/I2C.c @@ -48,7 +48,12 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, mp_arg_validate_int_max(frequency, 1000000, MP_QSTR_frequency); - #if CIRCUITPY_REQUIRE_I2C_PULLUPS + // Don't bother to check for pull-ups when the internal pull-ups are used. + #if CIRCUITPY_REQUIRE_I2C_PULLUPS && !CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP + + // TODO: maybe check the pull-up efficacy with timing scaled by frequency + // as is done in espressif, instead of using a fixed 3us. + // Test that the pins are in a high state. (Hopefully indicating they are pulled up.) gpio_set_function(sda->number, GPIO_FUNC_SIO); gpio_set_function(scl->number, GPIO_FUNC_SIO); @@ -86,7 +91,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // // Do not use the default supplied clock stretching timeout here. // It is too short for some devices. Use the busio timeout instead. - shared_module_bitbangio_i2c_construct(&self->bitbangio_i2c, scl, sda, + shared_module_bitbangio_i2c_construct(&self->bitbangio_i2c, MP_OBJ_FROM_PTR(scl), MP_OBJ_FROM_PTR(sda), frequency, BUS_TIMEOUT_US); self->baudrate = i2c_init(self->peripheral, frequency); @@ -98,6 +103,12 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, gpio_set_function(self->scl_pin, GPIO_FUNC_I2C); gpio_set_function(self->sda_pin, GPIO_FUNC_I2C); + + #if CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP + // Enable the internal pull-ups only once the pins belong to the I2C peripheral. + gpio_pull_up(self->scl_pin); + gpio_pull_up(self->sda_pin); + #endif } bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { @@ -144,7 +155,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { if (len == 0) { // The RP2040 I2C peripheral will not perform 0 byte writes. @@ -174,20 +185,20 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, } switch (result) { case PICO_ERROR_GENERIC: - return MP_ENODEV; + return -MP_ENODEV; case PICO_ERROR_TIMEOUT: - return MP_ETIMEDOUT; + return -MP_ETIMEDOUT; default: - return MP_EIO; + return -MP_EIO; } } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { size_t result = i2c_read_timeout_us(self->peripheral, addr, data, len, false, BUS_TIMEOUT_US); if (result == len) { @@ -195,17 +206,17 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, } switch (result) { case PICO_ERROR_GENERIC: - return MP_ENODEV; + return -MP_ENODEV; case PICO_ERROR_TIMEOUT: - return MP_ETIMEDOUT; + return -MP_ETIMEDOUT; default: - return MP_EIO; + return -MP_EIO; } } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/raspberrypi/common-hal/busio/SPI.c b/ports/raspberrypi/common-hal/busio/SPI.c index 4735d1284f9..aeb06d919ae 100644 --- a/ports/raspberrypi/common-hal/busio/SPI.c +++ b/ports/raspberrypi/common-hal/busio/SPI.c @@ -19,24 +19,14 @@ #define NO_INSTANCE 0xff -static bool never_reset_spi[2]; -static spi_inst_t *spi[2] = {spi0, spi1}; - -void reset_spi(void) { - for (size_t i = 0; i < 2; i++) { - if (never_reset_spi[i]) { - continue; - } - - spi_deinit(spi[i]); - } -} - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { size_t instance_index = NO_INSTANCE; + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + if (half_duplex) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); } @@ -96,8 +86,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[spi_get_index(self->peripheral)] = true; - common_hal_never_reset_pin(self->clock); common_hal_never_reset_pin(self->MOSI); common_hal_never_reset_pin(self->MISO); @@ -107,17 +95,21 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } - never_reset_spi[spi_get_index(self->peripheral)] = false; spi_deinit(self->peripheral); common_hal_reset_pin(self->clock); common_hal_reset_pin(self->MOSI); common_hal_reset_pin(self->MISO); - self->clock = NULL; + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/raspberrypi/common-hal/busio/SPI.h b/ports/raspberrypi/common-hal/busio/SPI.h index 8510eb7693a..3d43c1eff00 100644 --- a/ports/raspberrypi/common-hal/busio/SPI.h +++ b/ports/raspberrypi/common-hal/busio/SPI.h @@ -25,5 +25,3 @@ typedef struct { uint8_t phase; uint8_t bits; } busio_spi_obj_t; - -void reset_spi(void); diff --git a/ports/raspberrypi/common-hal/busio/UART.c b/ports/raspberrypi/common-hal/busio/UART.c index 17fcfa17229..074c78c2f4a 100644 --- a/ports/raspberrypi/common-hal/busio/UART.c +++ b/ports/raspberrypi/common-hal/busio/UART.c @@ -50,7 +50,7 @@ static void pin_check(const uint8_t uart, const mcu_pin_obj_t *pin, const uint8_ if (pins_uart != uart) { raise_ValueError_invalid_pins(); } - #ifdef PICO_RP2350 + #if PICO_RP2350 if ((pin_type == 0 && pin->number % 4 == 2) || (pin_type == 1 && pin->number % 4 == 3)) { return; @@ -67,7 +67,7 @@ static uint8_t pin_init(const uint8_t uart, const mcu_pin_obj_t *pin, const uint } claim_pin(pin); gpio_function_t function = GPIO_FUNC_UART; - #ifdef PICO_RP2350 + #if PICO_RP2350 if ((pin_type == 0 && pin->number % 4 == 2) || (pin_type == 1 && pin->number % 4 == 3)) { function = GPIO_FUNC_UART_AUX; diff --git a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c index d1c92eea998..a40f6e26608 100644 --- a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +++ b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c @@ -85,6 +85,13 @@ void common_hal_i2ctarget_i2c_target_deinit(i2ctarget_i2c_target_obj_t *self) { } int common_hal_i2ctarget_i2c_target_is_addressed(i2ctarget_i2c_target_obj_t *self, uint8_t *address, bool *is_read, bool *is_restart) { + // Interrupt bits must be cleared by software. Clear the STOP and + // RESTART interrupt bits after an I2C transaction finishes. + if (self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { + self->peripheral->hw->clr_stop_det; + self->peripheral->hw->clr_restart_det; + } + if (!((self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) || (self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_RD_REQ_BITS))) { return 0; } @@ -98,12 +105,20 @@ int common_hal_i2ctarget_i2c_target_is_addressed(i2ctarget_i2c_target_obj_t *sel } int common_hal_i2ctarget_i2c_target_read_byte(i2ctarget_i2c_target_obj_t *self, uint8_t *data) { - if (self->peripheral->hw->status & I2C_IC_STATUS_RFNE_BITS) { - *data = (uint8_t)self->peripheral->hw->data_cmd; - return 1; - } else { - return 0; + // Wait for data to arrive or a STOP condition indicating the transfer is over. + // Without this wait, the CPU can drain the FIFO faster than bytes arrive on the + // I2C bus, causing transfers to be split into multiple partial reads. + for (int t = 0; t < 100; t++) { + if (self->peripheral->hw->status & I2C_IC_STATUS_RFNE_BITS) { + *data = (uint8_t)self->peripheral->hw->data_cmd; + return 1; + } + if (self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { + break; + } + mp_hal_delay_us(10); } + return 0; } int common_hal_i2ctarget_i2c_target_write_byte(i2ctarget_i2c_target_obj_t *self, uint8_t data) { diff --git a/ports/raspberrypi/common-hal/mcp4822/MCP4822.c b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c new file mode 100644 index 00000000000..ba4a39b11d8 --- /dev/null +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c @@ -0,0 +1,288 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT +// +// MCP4822 dual-channel 12-bit SPI DAC audio output. +// Uses PIO + DMA for non-blocking audio playback, mirroring audiobusio.I2SOut. + +#include +#include + +#include "mpconfigport.h" + +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "common-hal/mcp4822/MCP4822.h" +#include "shared-bindings/mcp4822/MCP4822.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" +#include "bindings/rp2pio/StateMachine.h" + +// ───────────────────────────────────────────────────────────────────────────── +// PIO program for MCP4822 SPI DAC +// ───────────────────────────────────────────────────────────────────────────── +// +// Pin assignment: +// OUT pin (1) = MOSI — serial data out +// SET pins (N) = MOSI through CS — for CS control & command-bit injection +// SIDE-SET pin (1) = SCK — serial clock +// +// SET PINS bit mapping (bit0=MOSI, ..., bit N=CS): +// 0 = CS low, MOSI low 1 = CS low, MOSI high +// (1 << cs_bit_pos) = CS high, MOSI low +// +// SIDE-SET (1 pin, SCK): side 0 = SCK low, side 1 = SCK high +// +// MCP4822 16-bit command word: +// [15] channel (0=A, 1=B) [14] don't care [13] gain (1=1x, 0=2x) +// [12] output enable (1) [11:0] 12-bit data +// +// DMA feeds unsigned 16-bit audio samples. RP2040 narrow-write replication +// fills both halves of the 32-bit PIO FIFO entry with the same value, +// giving mono→stereo for free. +// +// The PIO pulls 32 bits, then sends two SPI transactions: +// Channel A: cmd nibble, then all 16 sample bits from upper half-word +// Channel B: cmd nibble, then all 16 sample bits from lower half-word +// The MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data), +// so only the top 12 of the 16 sample bits become DAC data. The bottom +// 4 sample bits clock out harmlessly after the DAC has latched. +// This gives correct 16-bit → 12-bit scaling (effectively sample >> 4). +// +// PIO instruction encoding with .side_set 1 (no opt): +// [15:13] opcode [12] side-set [11:8] delay [7:0] operands +// +// Total: 26 instructions, 86 PIO clocks per audio sample. +// ───────────────────────────────────────────────────────────────────────────── + +static const uint16_t mcp4822_pio_program[] = { + // side SCK + // 0: pull noblock side 0 ; Get 32 bits or keep X if FIFO empty + 0x8080, + // 1: mov x, osr side 0 ; Save for pull-noblock fallback + 0xA027, + + // ── Channel A: command nibble 0b0011 (1x gain) ──────────────────────── + // 2: set pins, 0 side 0 ; CS low, MOSI=0 (bit15=0: channel A) + 0xE000, + // 3: nop side 1 ; SCK high — latch bit 15 + 0xB042, + // 4: set pins, 0 side 0 ; MOSI=0 (bit14=0: don't care) + 0xE000, + // 5: nop side 1 ; SCK high + 0xB042, + // 6: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) [patched for 2x] + 0xE001, + // 7: nop side 1 ; SCK high + 0xB042, + // 8: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) + 0xE001, + // 9: nop side 1 ; SCK high + 0xB042, + // 10: set y, 15 side 0 ; Loop counter: 16 sample bits + 0xE04F, + // 11: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopA) + 0x6001, + // 12: jmp y--, 11 side 1 ; SCK high, loop back + 0x108B, + // 13: set pins, 4 side 0 ; CS high — DAC A latches + 0xE004, + + // ── Channel B: command nibble 0b1011 (1x gain) ──────────────────────── + // 14: set pins, 1 side 0 ; CS low, MOSI=1 (bit15=1: channel B) + 0xE001, + // 15: nop side 1 ; SCK high + 0xB042, + // 16: set pins, 0 side 0 ; MOSI=0 (bit14=0) + 0xE000, + // 17: nop side 1 ; SCK high + 0xB042, + // 18: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) [patched for 2x] + 0xE001, + // 19: nop side 1 ; SCK high + 0xB042, + // 20: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) + 0xE001, + // 21: nop side 1 ; SCK high + 0xB042, + // 22: set y, 15 side 0 ; Loop counter: 16 sample bits + 0xE04F, + // 23: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopB) + 0x6001, + // 24: jmp y--, 23 side 1 ; SCK high, loop back + 0x1097, + // 25: set pins, 4 side 0 ; CS high — DAC B latches + 0xE004, +}; + +// Clocks per sample: 2 (pull+mov) + 42 (chanA) + 42 (chanB) = 86 +// Per channel: 8(4 cmd bits × 2 clks) + 1(set y) + 32(16 bits × 2 clks) + 1(cs high) = 42 +#define MCP4822_CLOCKS_PER_SAMPLE 86 + +// MCP4822 gain bit (bit 13) position in the PIO program: +// Instruction 6 = channel A gain bit +// Instruction 18 = channel B gain bit +// 1x gain: set pins, 1 (0xE001) — bit 13 = 1 +// 2x gain: set pins, 0 (0xE000) — bit 13 = 0 +#define MCP4822_PIO_GAIN_INSTR_A 6 +#define MCP4822_PIO_GAIN_INSTR_B 18 +#define MCP4822_PIO_GAIN_1X 0xE001 // set pins, 1 +#define MCP4822_PIO_GAIN_2X 0xE000 // set pins, 0 + +void mcp4822_reset(void) { +} + +// Caller validates that pins are free. +void common_hal_mcp4822_mcp4822_construct(mcp4822_mcp4822_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs, uint8_t gain) { + + // The SET pin group spans from MOSI to CS. + // MOSI must have a lower GPIO number than CS, gap at most 4. + if (cs->number <= mosi->number || (cs->number - mosi->number) > 4) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q and %q"), MP_QSTR_CS, MP_QSTR_MOSI); + } + + uint8_t set_count = cs->number - mosi->number + 1; + + // Build a mutable copy of the PIO program and patch the gain bit + uint16_t program[MP_ARRAY_SIZE(mcp4822_pio_program)]; + memcpy(program, mcp4822_pio_program, sizeof(mcp4822_pio_program)); + uint16_t gain_instr = (gain == 2) ? MCP4822_PIO_GAIN_2X : MCP4822_PIO_GAIN_1X; + program[MCP4822_PIO_GAIN_INSTR_A] = gain_instr; + program[MCP4822_PIO_GAIN_INSTR_B] = gain_instr; + + // Initial SET pin state: CS high (bit at CS position), others low + uint32_t cs_bit_position = cs->number - mosi->number; + pio_pinmask32_t initial_set_state = PIO_PINMASK32_FROM_VALUE(1u << cs_bit_position); + pio_pinmask32_t initial_set_dir = PIO_PINMASK32_FROM_VALUE((1u << set_count) - 1); + + common_hal_rp2pio_statemachine_construct( + &self->state_machine, + program, MP_ARRAY_SIZE(mcp4822_pio_program), + 44100 * MCP4822_CLOCKS_PER_SAMPLE, // Initial frequency; play() adjusts + NULL, 0, // No init program + NULL, 0, // No may_exec + mosi, 1, // OUT: MOSI, 1 pin + PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // OUT state=low, dir=output + NULL, 0, // IN: none + PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // IN pulls: none + mosi, set_count, // SET: MOSI..CS + initial_set_state, initial_set_dir, // SET state (CS high), dir=output + clock, 1, false, // SIDE-SET: SCK, 1 pin, not pindirs + PIO_PINMASK32_NONE, // SIDE-SET state: SCK low + PIO_PINMASK32_FROM_VALUE(0x1), // SIDE-SET dir: output + false, // No sideset enable + NULL, PULL_NONE, // No jump pin + PIO_PINMASK_NONE, // No wait GPIO + true, // Exclusive pin use + false, 32, false, // OUT shift: no autopull, 32-bit, shift left + false, // Don't wait for txstall + false, 32, false, // IN shift (unused) + false, // Not user-interruptible + 0, -1, // Wrap: whole program + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, + PIO_MOV_N_DEFAULT + ); + + self->playing = false; + audio_dma_init(&self->dma); +} + +bool common_hal_mcp4822_mcp4822_deinited(mcp4822_mcp4822_obj_t *self) { + return common_hal_rp2pio_statemachine_deinited(&self->state_machine); +} + +void common_hal_mcp4822_mcp4822_deinit(mcp4822_mcp4822_obj_t *self) { + if (common_hal_mcp4822_mcp4822_deinited(self)) { + return; + } + if (common_hal_mcp4822_mcp4822_get_playing(self)) { + common_hal_mcp4822_mcp4822_stop(self); + } + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + audio_dma_deinit(&self->dma); +} + +void common_hal_mcp4822_mcp4822_play(mcp4822_mcp4822_obj_t *self, + mp_obj_t sample, bool loop) { + + if (common_hal_mcp4822_mcp4822_get_playing(self)) { + common_hal_mcp4822_mcp4822_stop(self); + } + + audiosample_check(sample); + + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); + if (bits_per_sample < 16) { + bits_per_sample = 16; + } + + uint32_t sample_rate = audiosample_get_sample_rate(sample); + uint8_t channel_count = audiosample_get_channel_count(sample); + if (channel_count > 2) { + mp_raise_ValueError(MP_ERROR_TEXT("Too many channels in sample.")); + } + + // PIO clock = sample_rate × clocks_per_sample + common_hal_rp2pio_statemachine_set_frequency( + &self->state_machine, + (uint32_t)sample_rate * MCP4822_CLOCKS_PER_SAMPLE); + common_hal_rp2pio_statemachine_restart(&self->state_machine); + + audio_dma_result result = audio_dma_setup_playback( + &self->dma, + sample, + loop, + false, // single_channel_output + 0, // audio_channel + false, // output_signed = false (unsigned for MCP4822) + bits_per_sample, // output_resolution + (uint32_t)&self->state_machine.pio->txf[self->state_machine.state_machine], + self->state_machine.tx_dreq, + false); // swap_channel + + if (result == AUDIO_DMA_DMA_BUSY) { + common_hal_mcp4822_mcp4822_stop(self); + mp_raise_RuntimeError(MP_ERROR_TEXT("No DMA channel found")); + } else if (result == AUDIO_DMA_MEMORY_ERROR) { + common_hal_mcp4822_mcp4822_stop(self); + mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to allocate buffers for signed conversion")); + } else if (result == AUDIO_DMA_SOURCE_ERROR) { + common_hal_mcp4822_mcp4822_stop(self); + mp_raise_RuntimeError(MP_ERROR_TEXT("Audio source error")); + } + + self->playing = true; +} + +void common_hal_mcp4822_mcp4822_pause(mcp4822_mcp4822_obj_t *self) { + audio_dma_pause(&self->dma); +} + +void common_hal_mcp4822_mcp4822_resume(mcp4822_mcp4822_obj_t *self) { + audio_dma_resume(&self->dma); +} + +bool common_hal_mcp4822_mcp4822_get_paused(mcp4822_mcp4822_obj_t *self) { + return audio_dma_get_paused(&self->dma); +} + +void common_hal_mcp4822_mcp4822_stop(mcp4822_mcp4822_obj_t *self) { + audio_dma_stop(&self->dma); + common_hal_rp2pio_statemachine_stop(&self->state_machine); + self->playing = false; +} + +bool common_hal_mcp4822_mcp4822_get_playing(mcp4822_mcp4822_obj_t *self) { + bool playing = audio_dma_get_playing(&self->dma); + if (!playing && self->playing) { + common_hal_mcp4822_mcp4822_stop(self); + } + return playing; +} diff --git a/ports/raspberrypi/common-hal/mcp4822/MCP4822.h b/ports/raspberrypi/common-hal/mcp4822/MCP4822.h new file mode 100644 index 00000000000..53c8e862b63 --- /dev/null +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/rp2pio/StateMachine.h" + +#include "audio_dma.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + rp2pio_statemachine_obj_t state_machine; + audio_dma_t dma; + bool playing; +} mcp4822_mcp4822_obj_t; + +void mcp4822_reset(void); diff --git a/ports/raspberrypi/common-hal/mcp4822/__init__.c b/ports/raspberrypi/common-hal/mcp4822/__init__.c new file mode 100644 index 00000000000..48981fc88a7 --- /dev/null +++ b/ports/raspberrypi/common-hal/mcp4822/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +// No module-level init needed. diff --git a/ports/raspberrypi/common-hal/mdns/RemoteService.c b/ports/raspberrypi/common-hal/mdns/RemoteService.c index 650e86da9d9..3d80199397e 100644 --- a/ports/raspberrypi/common-hal/mdns/RemoteService.c +++ b/ports/raspberrypi/common-hal/mdns/RemoteService.c @@ -39,6 +39,3 @@ mp_obj_t common_hal_mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t } return common_hal_ipaddress_new_ipv4address(addr); } - -void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self) { -} diff --git a/ports/raspberrypi/common-hal/mdns/Server.c b/ports/raspberrypi/common-hal/mdns/Server.c index ac0c73389b1..059700af61b 100644 --- a/ports/raspberrypi/common-hal/mdns/Server.c +++ b/ports/raspberrypi/common-hal/mdns/Server.c @@ -42,10 +42,23 @@ void mdns_server_construct(mdns_server_obj_t *self, bool workflow) { } self->inited = true; - uint8_t mac[6]; - wifi_radio_get_mac_address(&common_hal_wifi_radio_obj, mac); - snprintf(self->default_hostname, sizeof(self->default_hostname), "cpy-%02x%02x%02x", mac[3], mac[4], mac[5]); - common_hal_mdns_server_set_hostname(self, self->default_hostname); + self->instance_name[0] = '\0'; + self->num_txt_records = 0; + self->txt_storage = NULL; + + // Seed the mDNS hostname from the netif hostname configured via + // CIRCUITPY_WIFI_HOSTNAME. Fall back to the historical MAC-based + // cpy-XXXXXX name when the user hasn't set one, so existing default + // hostnames keep working. + if (common_hal_wifi_radio_obj.hostname[0] != '\0') { + common_hal_mdns_server_set_hostname(self, common_hal_wifi_radio_obj.hostname); + } else { + uint8_t mac[6]; + wifi_radio_get_mac_address(&common_hal_wifi_radio_obj, mac); + char default_hostname[sizeof("cpy-XXXXXX")]; + snprintf(default_hostname, sizeof(default_hostname), "cpy-%02x%02x%02x", mac[3], mac[4], mac[5]); + common_hal_mdns_server_set_hostname(self, default_hostname); + } if (workflow) { // Add a second host entry to respond to "circuitpython.local" queries as well. @@ -91,15 +104,18 @@ void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *ho mdns_resp_add_netif(NETIF_STA, hostname); } - self->hostname = hostname; + strlcpy(self->hostname, hostname, sizeof(self->hostname)); } const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self) { + if (self->instance_name[0] == '\0') { + return self->hostname; + } return self->instance_name; } void common_hal_mdns_server_set_instance_name(mdns_server_obj_t *self, const char *instance_name) { - self->instance_name = instance_name; + strlcpy(self->instance_name, instance_name, sizeof(self->instance_name)); } typedef struct { @@ -288,15 +304,64 @@ static void srv_txt_cb(struct mdns_service *service, void *ptr) { } } +// Take our own copies of the TXT records. lwip only stores srv_txt_cb and this +// object, and calls back at packet-build time, so the caller's strings must +// outlive the call -- and the caller hands us pointers into GC-heap strings. +// +// WARNING: the copies live on the GC heap, which is only safe because TXT +// records can reach us solely through the Python binding, so the VM is +// necessarily running and this object is itself a GC object that dies with the +// same heap. The supervisor's static mdns_server_obj_t never gets TXT records +// (web_workflow.c passes NULL, 0). If supervisor code ever needs to advertise +// TXT records, this must move off the GC heap first -- an inline pool in +// mdns_server_obj_t, or port_malloc -- or the records will dangle after the +// first VM reset. static void assign_txt_records(mdns_server_obj_t *self, const char *txt_records[], size_t num_txt_records) { - size_t allowed_num_txt_records = MDNS_MAX_TXT_RECORDS < num_txt_records ? MDNS_MAX_TXT_RECORDS : num_txt_records; - self->num_txt_records = allowed_num_txt_records; - for (size_t i = 0; i < allowed_num_txt_records; i++) { - self->txt_records[i] = txt_records[i]; + size_t total = 0; + for (size_t i = 0; i < num_txt_records; i++) { + total += strlen(txt_records[i]) + 1; + } + + // Build the replacement before touching self, so that the allocation, and + // any MemoryError it raises, happens outside the lwip lock below. + char *storage = NULL; + const char *records[MDNS_MAX_TXT_RECORDS]; + if (total > 0) { + storage = m_malloc_maybe(total); + if (storage == NULL) { + m_malloc_fail(total); + } + char *next = storage; + for (size_t i = 0; i < num_txt_records; i++) { + size_t size = strlen(txt_records[i]) + 1; + memcpy(next, txt_records[i], size); + records[i] = next; + next += size; + } + } + + // srv_txt_cb reads these from the lwip IRQ, so hold lwip off while they + // change. Otherwise a callback already part way through the old records + // keeps pointers into storage we are about to release. + MICROPY_PY_LWIP_ENTER + char *old_storage = self->txt_storage; + for (size_t i = 0; i < num_txt_records; i++) { + self->txt_records[i] = records[i]; } + self->txt_storage = storage; + self->num_txt_records = num_txt_records; + MICROPY_PY_LWIP_EXIT + + // Nothing can be holding pointers into it now, so release it here rather + // than leaving the GC to do it at an unpredictable time. + m_free(old_storage); } void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port, const char *txt_records[], size_t num_txt_records) { + // Check before touching any state, so a rejected call leaves the existing + // advertisement alone. + mp_arg_validate_length_max(num_txt_records, MDNS_MAX_TXT_RECORDS, MP_QSTR_txt_records); + enum mdns_sd_proto proto = DNSSD_PROTO_UDP; if (strcmp(protocol, "_tcp") == 0) { proto = DNSSD_PROTO_TCP; @@ -316,7 +381,7 @@ void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const cha } assign_txt_records(self, txt_records, num_txt_records); - int8_t slot = mdns_resp_add_service(NETIF_STA, self->instance_name, service_type, proto, port, srv_txt_cb, self); + int8_t slot = mdns_resp_add_service(NETIF_STA, common_hal_mdns_server_get_instance_name(self), service_type, proto, port, srv_txt_cb, self); if (slot < 0) { mp_raise_RuntimeError(MP_ERROR_TEXT("Out of MDNS service slots")); return; diff --git a/ports/raspberrypi/common-hal/mdns/Server.h b/ports/raspberrypi/common-hal/mdns/Server.h index 620e201c897..041add08818 100644 --- a/ports/raspberrypi/common-hal/mdns/Server.h +++ b/ports/raspberrypi/common-hal/mdns/Server.h @@ -14,11 +14,16 @@ typedef struct { mp_obj_base_t base; - const char *hostname; - const char *instance_name; - char default_hostname[sizeof("cpy-XXXXXX")]; + // Store copies rather than the caller's pointers. The setters are handed + // GC-heap strings, which are recycled when the VM resets while this object + // (and the web workflow's static one) lives on. + char hostname[64]; // RFC 6762 Appendix A - 63 bytes for label + 1 for NUL + char instance_name[64]; // RFC 6763 Section 7.2 - 63 bytes + 1 for NUL const char *service_type[MDNS_MAX_SERVICES]; size_t num_txt_records; + // Owned copies of the TXT records, packed NUL-separated into txt_storage, + // which lives on the GC heap. See the warning on assign_txt_records(). + char *txt_storage; const char *txt_records[MDNS_MAX_TXT_RECORDS]; // Track if this object owns access to the underlying MDNS service. bool inited; diff --git a/ports/raspberrypi/common-hal/memorymap/AddressRange.c b/ports/raspberrypi/common-hal/memorymap/AddressRange.c index 0796a3b860b..a5e860cb40c 100644 --- a/ports/raspberrypi/common-hal/memorymap/AddressRange.c +++ b/ports/raspberrypi/common-hal/memorymap/AddressRange.c @@ -14,7 +14,7 @@ #include "hardware/regs/addressmap.h" // RP2 address map ranges, must be arranged in order by ascending start address -#ifdef PICO_RP2040 +#if PICO_RP2040 addressmap_rp2_range_t rp2_ranges[] = { {(uint8_t *)ROM_BASE, 0x00004000, ROM}, // boot ROM {(uint8_t *)XIP_BASE, 0x00100000, XIP}, // XIP normal cache operation @@ -36,7 +36,7 @@ addressmap_rp2_range_t rp2_ranges[] = { {(uint8_t *)PPB_BASE, 0x00004000, IO} // PPB registers }; #endif -#ifdef PICO_RP2350 +#if PICO_RP2350 addressmap_rp2_range_t rp2_ranges[] = { {(uint8_t *)ROM_BASE, 0x00004000, ROM}, // boot ROM {(uint8_t *)XIP_BASE, 0x00100000, XIP}, // XIP normal cache operation diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.c b/ports/raspberrypi/common-hal/microcontroller/Processor.c index a3ea890d9af..fbbef51acb4 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Processor.c +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.c @@ -10,6 +10,7 @@ #include "py/mphal.h" #include "py/runtime.h" #include "common-hal/microcontroller/Processor.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/ResetReason.h" #include "shared-bindings/time/__init__.h" @@ -20,11 +21,16 @@ #include "hardware/vreg.h" #include "hardware/watchdog.h" -#ifdef PICO_RP2040 +#ifdef CIRCUITPY_PSRAM_CHIP_SELECT +#include "hardware/regs/qmi.h" +#include "hardware/structs/qmi.h" +#endif + +#if PICO_RP2040 #include "hardware/regs/vreg_and_chip_reset.h" #include "hardware/structs/vreg_and_chip_reset.h" #endif -#ifdef PICO_RP2350 +#if PICO_RP2350 #include "hardware/regs/powman.h" #include "hardware/structs/powman.h" #endif @@ -50,6 +56,26 @@ uint32_t common_hal_mcu_processor_get_frequency(void) { return clock_get_hz(clk_sys); } +#ifdef CIRCUITPY_PSRAM_CHIP_SELECT +void __no_inline_not_in_flash_func(mcu_processor_update_psram_timing)(uint32_t sys_clk_khz) { + // MAX_SELECT is in units of 64 system clock cycles; PSRAM allows 8 us max CS + // assertion. Use 7.5 us so there is margin at any clk_sys. + uint32_t max_select = (75 * sys_clk_khz) / 640000; + // MIN_DESELECT is in system clock cycles; PSRAM needs 50 ns min CS + // deassertion. Round up so we are never under. + uint32_t min_deselect = (sys_clk_khz + 19999) / 20000; + + qmi_hw->m[1].timing = + QMI_M0_TIMING_PAGEBREAK_VALUE_1024 << QMI_M0_TIMING_PAGEBREAK_LSB | // Break between pages. + 3 << QMI_M0_TIMING_SELECT_HOLD_LSB | // Delay releasing CS for 3 extra system cycles. + 1 << QMI_M0_TIMING_COOLDOWN_LSB | + 1 << QMI_M0_TIMING_RXDELAY_LSB | + max_select << QMI_M0_TIMING_MAX_SELECT_LSB | + min_deselect << QMI_M0_TIMING_MIN_DESELECT_LSB | + 2 << QMI_M0_TIMING_CLKDIV_LSB; +} +#endif + void common_hal_mcu_processor_set_frequency(mcu_processor_obj_t *self, uint32_t frequency) { uint vco, postdiv1, postdiv2; uint32_t freq_khz = frequency / 1000; @@ -68,7 +94,17 @@ void common_hal_mcu_processor_set_frequency(mcu_processor_obj_t *self, uint32_t vreg_set_voltage(voltage); // Wait for a stable voltage common_hal_time_delay_ms(10); + + #ifdef CIRCUITPY_PSRAM_CHIP_SELECT + // Prevent interrupt handlers from accessing PSRAM until its timing matches + // the new system clock. + common_hal_mcu_disable_interrupts(); + #endif set_sys_clock_khz(freq_khz, false); + #ifdef CIRCUITPY_PSRAM_CHIP_SELECT + mcu_processor_update_psram_timing(freq_khz); + common_hal_mcu_enable_interrupts(); + #endif } void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { @@ -78,41 +114,41 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - mcu_reset_reason_t reason = RESET_REASON_UNKNOWN; + mcu_reset_reason_t reason = MCU_RESET_REASON_UNKNOWN; - #ifdef PICO_RP2040 + #if PICO_RP2040 uint32_t chip_reset_reg = vreg_and_chip_reset_hw->chip_reset; if (chip_reset_reg & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) { - reason = RESET_REASON_RESCUE_DEBUG; + reason = MCU_RESET_REASON_RESCUE_DEBUG; } if (chip_reset_reg & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS) { - reason = RESET_REASON_RESET_PIN; + reason = MCU_RESET_REASON_RESET_PIN; } if (chip_reset_reg & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS) { // NOTE: This register is also used for brownout, but there is no way to differentiate between power on and brown out - reason = RESET_REASON_POWER_ON; + reason = MCU_RESET_REASON_POWER_ON; } #endif - #ifdef PICO_RP2350 + #if PICO_RP2350 uint32_t chip_reset_reg = powman_hw->chip_reset; if (chip_reset_reg & POWMAN_CHIP_RESET_HAD_RESCUE_BITS) { - reason = RESET_REASON_RESCUE_DEBUG; + reason = MCU_RESET_REASON_RESCUE_DEBUG; } if (chip_reset_reg & POWMAN_CHIP_RESET_HAD_RUN_LOW_BITS) { - reason = RESET_REASON_RESET_PIN; + reason = MCU_RESET_REASON_RESET_PIN; } if (chip_reset_reg & POWMAN_CHIP_RESET_HAD_BOR_BITS) { - reason = RESET_REASON_BROWNOUT; + reason = MCU_RESET_REASON_BROWNOUT; } if (chip_reset_reg & POWMAN_CHIP_RESET_HAD_POR_BITS) { - reason = RESET_REASON_POWER_ON; + reason = MCU_RESET_REASON_POWER_ON; } #endif @@ -120,12 +156,12 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { // The watchdog is used for software reboots such as resetting after copying a UF2 via the bootloader. if (watchdog_caused_reboot()) { - reason = RESET_REASON_SOFTWARE; + reason = MCU_RESET_REASON_SOFTWARE; } // Actual watchdog usage will set a special value that this function detects. if (watchdog_enable_caused_reboot()) { - reason = RESET_REASON_WATCHDOG; + reason = MCU_RESET_REASON_WATCHDOG; } return reason; diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.h b/ports/raspberrypi/common-hal/microcontroller/Processor.h index df1e1cf2333..9503eaf21f4 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Processor.h +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.h @@ -16,3 +16,7 @@ typedef struct { mp_obj_base_t base; // Stores no state currently. } mcu_processor_obj_t; + +#ifdef CIRCUITPY_PSRAM_CHIP_SELECT +void mcu_processor_update_psram_timing(uint32_t sys_clk_khz); +#endif diff --git a/ports/raspberrypi/common-hal/microcontroller/__init__.c b/ports/raspberrypi/common-hal/microcontroller/__init__.c index e287e551710..3d8bd381f5e 100644 --- a/ports/raspberrypi/common-hal/microcontroller/__init__.c +++ b/ports/raspberrypi/common-hal/microcontroller/__init__.c @@ -25,12 +25,28 @@ #include "hardware/watchdog.h" #include "hardware/irq.h" +// DMA interrupt (DMA_IRQ_n) allocation for this port: +// +// DMA_IRQ_0 Shared. audiocore (audio_dma.c) and rp2pio (StateMachine.c) each +// register a shared handler with irq_add_shared_handler() and +// service only their own DMA channels. Any new code that needs a +// DMA completion interrupt should do the same: add a shared handler +// on DMA_IRQ_0, check dma_hw->ints0, and acknowledge only its own +// channels. Runs at the default IRQ priority and is masked during +// flash writes (see common_hal_mcu_disable_interrupts below). +// DMA_IRQ_1 Exclusive to picodvi (Framebuffer_RP2040.c / Framebuffer_RP2350.c), +// registered with irq_set_exclusive_handler() at the highest +// priority. On RP2350 it is deliberately kept enabled during flash +// writes via BASEPRI (see below) so the display keeps refreshing. +// DMA_IRQ_2 RP2350 only; currently unused / free. +// DMA_IRQ_3 RP2350 only; currently unused / free. + void common_hal_mcu_delay_us(uint32_t delay) { mp_hal_delay_us(delay); } volatile uint32_t nesting_count = 0; -#ifdef PICO_RP2040 +#if PICO_RP2040 void common_hal_mcu_disable_interrupts(void) { // We don't use save_and_disable_interrupts() from the sdk because we don't want to worry about PRIMASK. // This is what we do on the SAMD21 via CMSIS. diff --git a/ports/raspberrypi/common-hal/os/__init__.c b/ports/raspberrypi/common-hal/os/__init__.c index 616bb8d8c79..d2a8da4caef 100644 --- a/ports/raspberrypi/common-hal/os/__init__.c +++ b/ports/raspberrypi/common-hal/os/__init__.c @@ -18,35 +18,159 @@ #include +#ifdef HAS_RP2350_TRNG +#include "hardware/structs/trng.h" +#include "hardware/sync.h" +#endif + // NIST Special Publication 800-90B (draft) recommends several extractors, // including the SHA hash family and states that if the amount of entropy input // is twice the number of bits output from them, that output can be considered -// essentially fully random. If every RANDOM_SAFETY_MARGIN bits from -// `rosc_hw->randombit` have at least 1 bit of entropy, then this criterion is met. +// essentially fully random. +// +// This works by seeding `random_state` with entropy from hardware sources +// (SHA-256 as the conditioning function), then using that state as a counter +// input (SHA-256 as a CSPRNG), re-seeding at least every 256 blocks (8kB). // -// This works by seeding the `random_state` with plenty of random bits (SHA256 -// as entropy harvesting function), then using that state it as a counter input -// (SHA256 as a CSPRNG), re-seeding at least every 256 blocks (8kB). +// On RP2350, entropy comes from both the dedicated TRNG peripheral and the +// ROSC. On RP2040, the ROSC is the only available source. // // In practice, `PractRand` doesn't detect any gross problems with the output // random numbers on samples of 1 to 8 megabytes, no matter the setting of -// RANDOM_SAFETY_MARGIN. (it does detect "unusual" results from time to time, +// ROSC_SAFETY_MARGIN. (it does detect "unusual" results from time to time, // as it will with any RNG) -#define RANDOM_SAFETY_MARGIN (4) + +// Number of ROSC collection rounds on RP2040. Each round feeds +// SHA256_BLOCK_SIZE bytes into the hash; we do 2*N rounds so the +// raw-to-output ratio satisfies 800-90B's 2:1 minimum. +#define ROSC_SAFETY_MARGIN (4) static BYTE random_state[SHA256_BLOCK_SIZE]; + +// Collect `count` bytes from the ROSC, one bit per read. +static void rosc_random_bytes(BYTE *buf, size_t count) { + for (size_t i = 0; i < count; i++) { + buf[i] = rosc_hw->randombit & 1; + for (int k = 0; k < 8; k++) { + buf[i] = (buf[i] << 1) ^ (rosc_hw->randombit & 1); + } + } +} + +#ifdef HAS_RP2350_TRNG + +// TRNG_DEBUG_CONTROL bypass bits: +// +// bit 1 VNC_BYPASS Von Neumann corrector +// bit 2 TRNG_CRNGT_BYPASS Continuous Random Number Generator Test +// bit 3 AUTO_CORRELATE_BYPASS Autocorrelation test +// +// We bypass Von Neumann and autocorrelation but keep CRNGT. +// +// Von Neumann (bypassed): ~4x throughput cost for bias removal. +// Redundant here because SHA-256 conditioning already handles +// biased input -- that's what the 2:1 oversampling ratio is for. +// +// Autocorrelation (bypassed): has a non-trivial false-positive rate +// at high sampling speeds and halts the TRNG until SW reset on +// failure. SHA-256 is not bothered by correlated input. ARM's own +// TZ-TRNG 90B reference configuration also bypasses it (0x0A). +// +// CRNGT (kept): compares consecutive 192-bit EHR outputs. Flags if +// identical -- false-positive rate 2^-192, throughput cost zero. +// This is our early warning for a stuck oscillator or a successful +// injection lock to a fixed state. +#define TRNG_BYPASS_BITS \ + (TRNG_TRNG_DEBUG_CONTROL_VNC_BYPASS_BITS | \ + TRNG_TRNG_DEBUG_CONTROL_AUTO_CORRELATE_BYPASS_BITS) + +// Collect 192 raw bits (6 x 32-bit words) from the TRNG. +// Returns false on CRNGT failure (consecutive identical EHR outputs). +// +// Holds PICO_SPINLOCK_ID_RAND (the SDK's lock for this peripheral) +// with interrupts disabled for the duration of the collection, which +// takes ~192 ROSC cycles (~24us at 8MHz). +static bool trng_collect_192(uint32_t out[6]) { + spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_RAND); + uint32_t save = spin_lock_blocking(lock); + + trng_hw->trng_debug_control = TRNG_BYPASS_BITS; + // One rng_clk cycle between samples. The SDK uses 0 here, but it + // also sets debug_control = -1u (full bypass). The behavior of + // sample_cnt1 = 0 with health tests still active is undocumented, + // so we use 1 to be safe. + trng_hw->sample_cnt1 = 1; + trng_hw->rnd_source_enable = 1; + trng_hw->rng_icr = 0xFFFFFFFF; + + while (trng_hw->trng_busy) { + } + + if (trng_hw->rng_isr & TRNG_RNG_ISR_CRNGT_ERR_BITS) { + // Drain ehr_data so the hardware starts a fresh collection. + // (Reading the last word clears the valid flag.) + for (int i = 0; i < 6; i++) { + (void)trng_hw->ehr_data[i]; + } + trng_hw->rng_icr = TRNG_RNG_ISR_CRNGT_ERR_BITS; + spin_unlock(lock, save); + return false; + } + + for (int i = 0; i < 6; i++) { + out[i] = trng_hw->ehr_data[i]; + } + + // Switch the inverter chain length for the next collection, using + // bits from the sample we just read. Only bits [1:0] matter -- they + // select one of four chain lengths, changing the ROSC frequency. + // This is borrowed from pico_rand's injection-locking countermeasure. + // (The SDK uses its PRNG state here instead of raw output; either + // works since the real defense is SHA-256 conditioning, not this.) + trng_hw->trng_config = out[0]; + + spin_unlock(lock, save); + return true; +} + +#endif // HAS_RP2350_TRNG + static void seed_random_bits(BYTE out[SHA256_BLOCK_SIZE]) { CRYAL_SHA256_CTX context; sha256_init(&context); - for (int i = 0; i < 2 * RANDOM_SAFETY_MARGIN; i++) { - for (int j = 0; j < SHA256_BLOCK_SIZE; j++) { - out[j] = rosc_hw->randombit & 1; - for (int k = 0; k < 8; k++) { - out[j] = (out[j] << 1) ^ (rosc_hw->randombit & 1); + + #ifdef HAS_RP2350_TRNG + // 384 bits from TRNG + 384 bits from ROSC = 768 bits into the hash, + // giving a 3:1 ratio over the 256-bit output (800-90B wants >= 2:1). + // Two independent sources so a failure in one doesn't zero the input. + + // TRNG: 2 x 192 bits. + for (int i = 0; i < 2; i++) { + uint32_t trng_buf[6] = {0}; + for (int attempt = 0; attempt < 3; attempt++) { + if (trng_collect_192(trng_buf)) { + break; } + // CRNGT failure. If all 3 retries fail, trng_buf stays zeroed + // and we rely entirely on the ROSC contribution below. } + sha256_update(&context, (const BYTE *)trng_buf, sizeof(trng_buf)); + } + + // ROSC: 2 x 24 bytes = 384 bits. + for (int i = 0; i < 2; i++) { + BYTE rosc_buf[24]; + rosc_random_bytes(rosc_buf, sizeof(rosc_buf)); + sha256_update(&context, rosc_buf, sizeof(rosc_buf)); + } + #else + // RP2040: ROSC is the only entropy source. + for (int i = 0; i < 2 * ROSC_SAFETY_MARGIN; i++) { + rosc_random_bytes(out, SHA256_BLOCK_SIZE); sha256_update(&context, out, SHA256_BLOCK_SIZE); } + #endif + sha256_final(&context, out); } @@ -61,10 +185,11 @@ static void get_random_bits(BYTE out[SHA256_BLOCK_SIZE]) { } bool common_hal_os_urandom(uint8_t *buffer, mp_uint_t length) { -#define ROSC_POWER_SAVE (1) // assume ROSC is not necessarily active all the time + #define ROSC_POWER_SAVE (1) // assume ROSC is not necessarily active all the time #if ROSC_POWER_SAVE uint32_t old_rosc_ctrl = rosc_hw->ctrl; - rosc_hw->ctrl = (old_rosc_ctrl & ~ROSC_CTRL_ENABLE_BITS) | (ROSC_CTRL_ENABLE_VALUE_ENABLE << 12); + rosc_hw->ctrl = (old_rosc_ctrl & ~ROSC_CTRL_ENABLE_BITS) + | (ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB); #endif while (length) { size_t n = MIN(length, SHA256_BLOCK_SIZE); diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer.h b/ports/raspberrypi/common-hal/picodvi/Framebuffer.h index 50288578590..82c0b189b89 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer.h +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer.h @@ -6,7 +6,7 @@ #pragma once -#ifdef PICO_RP2040 +#if PICO_RP2040 #include "Framebuffer_RP2040.h" #else #include "Framebuffer_RP2350.h" diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c index 788f10d6df6..53ed37cefbe 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -174,32 +174,23 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self, uint8_t slice = pwm_gpio_to_slice_num(self->pin_pair[0]); - pio_program_t program_struct = { - .instructions = NULL, - .length = 2, - .origin = -1 - }; - size_t pio_index = NUM_PIOS; - int free_state_machines[4]; // We may find all four free. We only use the first three. - for (size_t i = 0; i < NUM_PIOS; i++) { - PIO pio = pio_get_instance(i); - uint8_t free_count = 0; - for (size_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { - if (!pio_sm_is_claimed(pio, sm)) { - free_state_machines[free_count] = sm; - free_count++; - } - } - if (free_count >= 3 && pio_can_add_program(pio, &program_struct)) { - pio_index = i; - break; - } - } - + // We need a PIO with room for a 2-instruction program and 3 free state machines. + size_t pio_index = rp2pio_statemachine_find_pio(2, 3); if (pio_index == NUM_PIOS) { mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); } + // Collect the free state machines on the chosen PIO. We only use the first three. + int free_state_machines[4]; // We may find all four free. + uint8_t free_count = 0; + PIO pio = pio_get_instance(pio_index); + for (size_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { + if (!pio_sm_is_claimed(pio, sm)) { + free_state_machines[free_count] = sm; + free_count++; + } + } + self->width = width; self->height = height; @@ -373,6 +364,11 @@ bool common_hal_picodvi_framebuffer_deinited(picodvi_framebuffer_obj_t *self) { void common_hal_picodvi_framebuffer_refresh(picodvi_framebuffer_obj_t *self) { } +void common_hal_picodvi_framebuffer_wait_for_vblank(picodvi_framebuffer_obj_t *self) { + // No frame-boundary counter on the RP2040 PIO-DVI path; vblank sync is a no-op here (the + // tear-free full-repaint path is RP2350/HSTX, e.g. Fruit Jam). Present so the binding links. +} + int common_hal_picodvi_framebuffer_get_width(picodvi_framebuffer_obj_t *self) { return self->width; } diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c index 2dc19558314..8c846ffc440 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c @@ -29,6 +29,7 @@ #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/time/__init__.h" +#include "supervisor/background_callback.h" #include "supervisor/port.h" #include "pico/stdlib.h" @@ -160,6 +161,11 @@ static uint32_t vactive_line720[VACTIVE_LEN] = { picodvi_framebuffer_obj_t *active_picodvi = NULL; +// Incremented once per completed frame by the DMA frame-boundary IRQ, so refresh() can block +// until the next frame starts (vblank sync). A full-framebuffer repaint that begins right after a +// frame boundary then races ahead of scanout, avoiding tearing without a second framebuffer. +static volatile uint32_t framebuffer_frame_count = 0; + static void __not_in_flash_func(dma_irq_handler)(void) { if (active_picodvi == NULL) { return; @@ -171,6 +177,7 @@ static void __not_in_flash_func(dma_irq_handler)(void) { // will trigger the pixel channel). dma_channel_hw_t *ch = &dma_hw->ch[active_picodvi->dma_command_channel]; ch->al3_read_addr_trig = (uintptr_t)active_picodvi->dma_commands; + framebuffer_frame_count++; // frame boundary: scanout has wrapped back to the top } bool common_hal_picodvi_framebuffer_preflight( @@ -625,6 +632,23 @@ bool common_hal_picodvi_framebuffer_deinited(picodvi_framebuffer_obj_t *self) { void common_hal_picodvi_framebuffer_refresh(picodvi_framebuffer_obj_t *self) { } +void common_hal_picodvi_framebuffer_wait_for_vblank(picodvi_framebuffer_obj_t *self) { + // Block until the next frame boundary (vblank). A full-framebuffer repaint issued right after + // this returns starts at the top of scanout and stays ahead of the beam, so it does not tear + // mid-screen. Bounded by a timeout so a stopped or absent DVI signal can never hang the caller. + if (self != active_picodvi) { + return; + } + uint32_t start = framebuffer_frame_count; + uint64_t timeout = common_hal_time_monotonic_ms() + 30; // ~2 frames @ 60 Hz + while (framebuffer_frame_count == start) { + RUN_BACKGROUND_TASKS; // don't starve USB host / other tasks during the ~<16 ms wait + if (common_hal_time_monotonic_ms() >= timeout) { + break; + } + } +} + int common_hal_picodvi_framebuffer_get_width(picodvi_framebuffer_obj_t *self) { return self->width; } diff --git a/ports/raspberrypi/common-hal/picodvi/__init__.c b/ports/raspberrypi/common-hal/picodvi/__init__.c index e8f344852de..c2d4b297b39 100644 --- a/ports/raspberrypi/common-hal/picodvi/__init__.c +++ b/ports/raspberrypi/common-hal/picodvi/__init__.c @@ -10,8 +10,8 @@ #include "shared-bindings/busio/I2C.h" #include "shared-bindings/board/__init__.h" #include "shared-module/displayio/__init__.h" -#include "shared-module/os/__init__.h" #include "supervisor/shared/safe_mode.h" +#include "supervisor/shared/settings.h" #include "py/gc.h" #include "py/runtime.h" #include "supervisor/port_heap.h" @@ -22,7 +22,7 @@ static bool picodvi_autoconstruct_enabled(mp_int_t *default_width, mp_int_t *def buf[0] = 0; // (any failure leaves the content of buf untouched: an empty nul-terminated string - (void)common_hal_os_getenv_str("CIRCUITPY_PICODVI_ENABLE", buf, sizeof(buf)); + (void)settings_get_str("CIRCUITPY_PICODVI_ENABLE", buf, sizeof(buf)); if (!strcasecmp(buf, "never")) { return false; @@ -106,10 +106,10 @@ void picodvi_autoconstruct(void) { mp_int_t color_depth = 8; mp_int_t rotation = 0; - (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_WIDTH", &width); - (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_HEIGHT", &height); - (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_COLOR_DEPTH", &color_depth); - (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); + (void)settings_get_int("CIRCUITPY_DISPLAY_WIDTH", &width); + (void)settings_get_int("CIRCUITPY_DISPLAY_HEIGHT", &height); + (void)settings_get_int("CIRCUITPY_DISPLAY_COLOR_DEPTH", &color_depth); + (void)settings_get_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); if (height == 0) { switch (width) { diff --git a/ports/raspberrypi/common-hal/picogame/Display.c b/ports/raspberrypi/common-hal/picogame/Display.c new file mode 100644 index 00000000000..9c0fcd17011 --- /dev/null +++ b/ports/raspberrypi/common-hal/picogame/Display.c @@ -0,0 +1,165 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "common-hal/picogame/Display.h" + +#include "py/runtime.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/displayio/display_core.h" +#include "shared-bindings/displayio/__init__.h" +#include "shared-bindings/fourwire/FourWire.h" + +#include "hardware/spi.h" +#include "hardware/dma.h" + +// Claimed once and REUSED across every Display construct (incl. across soft resets / each game +// launched via supervisor.set_next_code_file). We claim via the raw pico-sdk, which CircuitPython +// does NOT release on a soft reset -- so claiming per-construct leaked a channel every game until +// "*** PANIC *** No DMA channels available" (and starved board.DISPLAY's own DMA, halving FPS). +// A C static survives a soft reset, so we remember and reuse our one channel; a hard reset frees it. +static int s_picogame_dma_chan = -1; + +void common_hal_picogame_display_construct(picogame_display_obj_t *self, + busdisplay_busdisplay_obj_t *display, bool rgb444) { + self->display = display; + #if CIRCUITPY_PICOGAME_RGB444 + self->rgb444 = rgb444; + #else + if (rgb444) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("Operation or feature not supported")); + } + self->rgb444 = false; + #endif + + // The fast path needs raw SPI access; only FourWire SPI buses are supported. + if (!mp_obj_is_type(display->bus.bus, &fourwire_fourwire_type)) { + mp_raise_TypeError_varg(MP_ERROR_TEXT("%q must be of type %q, not %q"), + MP_QSTR_display, MP_QSTR_FourWire, mp_obj_get_type(display->bus.bus)->name); + } + fourwire_fourwire_obj_t *fw = MP_OBJ_TO_PTR(display->bus.bus); + self->spi = fw->bus->peripheral; + + #if CIRCUITPY_PICOGAME_RGB444 + // Tell the panel which pixel format we'll send (COLMOD). Asserting it here also recovers from + // a previous program that left the panel in the other format (the setting survives soft reset). + picogame_set_pixel_format(display, rgb444); + #endif + + if (s_picogame_dma_chan < 0) { + s_picogame_dma_chan = dma_claim_unused_channel(true); + } + self->dma_chan = s_picogame_dma_chan; + + // Configure the channel ONCE (dreq, 8-bit, read-incr, write addr = SPI data reg). Per-strip we + // then only set the read address + transfer count and trigger -- no per-strip reconfiguration. + dma_channel_config c = dma_channel_get_default_config(self->dma_chan); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, spi_get_dreq((spi_inst_t *)self->spi, true)); + channel_config_set_read_increment(&c, true); + channel_config_set_write_increment(&c, false); + dma_channel_configure(self->dma_chan, &c, + &spi_get_hw((spi_inst_t *)self->spi)->dr, NULL, 0, false); +} + +// Kick off an asynchronous TX-only DMA of `nbytes` from `buf` to the SPI FIFO (channel already +// configured in construct; just point it at `buf`, set the count, and trigger). +static void dma_start(int chan, const uint16_t *buf, size_t nbytes) { + dma_channel_set_read_addr(chan, buf, false); + dma_channel_set_trans_count(chan, nbytes, true); // true = trigger +} + +void common_hal_picogame_display_render(picogame_display_obj_t *self, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buf_a, uint16_t *buf_b, size_t buf_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t background, + int ox, int oy) { + + busdisplay_busdisplay_obj_t *display = self->display; + spi_inst_t *spi = (spi_inst_t *)self->spi; + + // RGB444 packs 2 px into 3 bytes, so each strip row must be an even number of pixels + // (whole bytes). Widen the region to even bounds; the extra <=1 px per side just repaints. + #if CIRCUITPY_PICOGAME_RGB444 + if (self->rgb444) { + x0 &= ~1; + x1 = (x1 + 1) & ~1; + if (x1 > display->core.width) { + x1 = display->core.width; + } + } + #endif + + // Compute geometry + open the GRAM window (set region, begin transaction, + // RAMWR). DC stays high for data after the first DATA send below, so the + // raw-DMA strips that follow need no DC toggling. + int region_w, strip_h; + int cx0 = x0, cy0 = y0, cx1 = x1, cy1 = y1; // strip_begin clamps these to the panel in place + if (!picogame_strip_begin(display, &cx0, &cy0, &cx1, &cy1, buf_pixels, ®ion_w, &strip_h)) { + return; + } + + uint16_t *bufs[2] = { buf_a, buf_b }; + int cur = 0; + bool first = true; + bool dma_inflight = false; + #if CIRCUITPY_PICOGAME_RGB444 + const bool rgb444 = self->rgb444; // hoist: invariant across all strips + #endif + + // A StripDraw callback may latch a BaseException (Ctrl-C / auto-reload). Like the portable + // picogame_render_region, we must re-raise it -- but only AFTER the in-flight DMA finishes and + // the bus transaction closes, so hold it here and propagate below (see the end of the function). + mp_obj_t pending = MP_OBJ_NULL; + + for (int sy = cy0; sy < cy1; sy += strip_h) { + int sh = picogame_imin(strip_h, cy1 - sy); + uint16_t *buf = bufs[cur]; + + // Blit this strip. When a DMA is in flight it transfers the *other* + // buffer, so this CPU work overlaps the SPI transfer. + pending = picogame_blit_strip_layers(buf, region_w, sy, sh, cx0, items, kinds, n, background, ox, oy); + + // RGB444: pack the just-blitted RGB565 strip in place (2 px -> 3 bytes) before sending. + // The pack overlaps the previous strip's DMA (we're transfer-bound), so it's ~free. + #if CIRCUITPY_PICOGAME_RGB444 + size_t nbytes = rgb444 + ? picogame_pack_rgb444(buf, (size_t)region_w * sh) + : (size_t)region_w * sh * 2; + #else + size_t nbytes = (size_t)region_w * sh * 2; + #endif + + if (first) { + // First strip goes through busdisplay: it drives DC high for data, + // which then stays high for the subsequent raw-DMA strips. + display->bus.send(display->bus.bus, DISPLAY_DATA, + CHIP_SELECT_UNTOUCHED, (uint8_t *)buf, nbytes); + first = false; + } else { + if (dma_inflight) { + dma_channel_wait_for_finish_blocking(self->dma_chan); + } + dma_start(self->dma_chan, buf, nbytes); + dma_inflight = true; + } + cur ^= 1; + if (pending != MP_OBJ_NULL) { // callback interrupted: this strip is queued, now stop + flush + break; + } + } + + if (dma_inflight) { + dma_channel_wait_for_finish_blocking(self->dma_chan); + } + while (spi_is_busy(spi)) { + // wait for the last bytes to leave the shift register before releasing CS + } + displayio_display_bus_end_transaction(&display->bus); + + if (pending != MP_OBJ_NULL) { // bus now closed -> safe to re-raise (Ctrl-C / reload) + nlr_raise(MP_OBJ_TO_PTR(pending)); + } +} diff --git a/ports/raspberrypi/common-hal/picogame/Display.h b/ports/raspberrypi/common-hal/picogame/Display.h new file mode 100644 index 00000000000..aaca229260f --- /dev/null +++ b/ports/raspberrypi/common-hal/picogame/Display.h @@ -0,0 +1,33 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// Fast display backend (RP2040): wraps an existing busdisplay and pushes pixels +// with asynchronous, double-buffered DMA so the CPU can blit the next strip +// while the current strip transfers over SPI. Reuses the busdisplay's SPI +// peripheral, window opcodes and dimensions - controller/resolution agnostic. + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/picogame/Sprite.h" + +typedef struct { + mp_obj_base_t base; + busdisplay_busdisplay_obj_t *display; + void *spi; // spi_inst_t* (kept opaque to avoid pico-sdk in this header) + int dma_chan; + bool rgb444; // pack strips to 12-bit RGB444 before sending (~25% less SPI traffic) +} picogame_display_obj_t; + +void common_hal_picogame_display_construct(picogame_display_obj_t *self, + busdisplay_busdisplay_obj_t *display, bool rgb444); + +void common_hal_picogame_display_render(picogame_display_obj_t *self, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buf_a, uint16_t *buf_b, size_t buf_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t background, + int ox, int oy); diff --git a/ports/raspberrypi/common-hal/picogame/interp.c b/ports/raspberrypi/common-hal/picogame/interp.c new file mode 100644 index 00000000000..78cc8581cbb --- /dev/null +++ b/ports/raspberrypi/common-hal/picogame/interp.c @@ -0,0 +1,54 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +// Mode-7 inner row via the SIO INTERPOLATOR (RP2040 + RP2350). The interpolator does the +// whole per-pixel texture walk in hardware: lane0 = (fx >> shx) & (tw-1), lane1 = +// ((fy >> shy) & (th-1)) << log2(tw), POP_FULL = texture_base + lane0 + lane1 = the texel +// ADDRESS, and (ADD_RAW) both accumulators advance by their full-precision steps on the +// same pop. That replaces ~8 shift/mask/mul/add ops per pixel with one SIO read. +// +// Per-CORE hardware: each core has its own interp0, so this stays safe even if rows are +// ever split across cores (each configures its own). The engine claims no SDK +// lane locks: CircuitPython core does not use the interpolators, and the config is +// rewritten per row call anyway. +// +// Fast path constraints (the caller guards): PAL8 texture, no transparency, stride == tw, +// log2(tw)+log2(th) <= 16 (mode7 textures are 64..256 pow2 - always true there). + +#include "py/mpconfig.h" + +#if CIRCUITPY_PICOGAME + +#include +#include "hardware/interp.h" +#include "shared-module/picogame/__init__.h" // the prototype (PICOGAME_HAS_INTERP) + +void picogame_mode7_row_interp(uint16_t *dst, int n, + const uint8_t *tex, const uint16_t *pal, + uint32_t fx, uint32_t fy, int32_t stepx, int32_t stepy, + int shx, int shy, int ltw, int lth) { + interp_config c0 = interp_default_config(); + interp_config_set_shift(&c0, (uint)shx); + interp_config_set_mask(&c0, 0, (uint)(ltw - 1)); + interp_config_set_add_raw(&c0, true); // accumulator advances by the RAW step + interp_set_config(interp0, 0, &c0); + interp_config c1 = interp_default_config(); + interp_config_set_shift(&c1, (uint)(shy - ltw)); + interp_config_set_mask(&c1, (uint)ltw, (uint)(ltw + lth - 1)); + interp_config_set_add_raw(&c1, true); + interp_set_config(interp0, 1, &c1); + interp0->base[0] = (uint32_t)stepx; + interp0->base[1] = (uint32_t)stepy; + interp0->base[2] = (uint32_t)(uintptr_t)tex; + interp0->accum[0] = fx; + interp0->accum[1] = fy; + for (int i = 0; i < n; i++) { + const uint8_t *p = (const uint8_t *)interp0->pop[2]; + dst[i] = pal[*p]; + } +} + +#endif diff --git a/ports/raspberrypi/common-hal/pwmio/PWMOut.c b/ports/raspberrypi/common-hal/pwmio/PWMOut.c index 9ceb5a0185d..2a643974291 100644 --- a/ports/raspberrypi/common-hal/pwmio/PWMOut.c +++ b/ports/raspberrypi/common-hal/pwmio/PWMOut.c @@ -78,7 +78,7 @@ pwmout_result_t pwmout_allocate(uint8_t slice, uint8_t ab_channel, bool variable if (target_slice_frequencies[slice] > 0) { // If we want to change frequency then we can't share. if (variable_frequency) { - return PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE; + return PWMOUT_INTERNAL_RESOURCES_IN_USE; } // If the other user wants a variable frequency then we can't share either. if ((slice_variable_frequency & (1 << slice)) != 0) { @@ -86,7 +86,7 @@ pwmout_result_t pwmout_allocate(uint8_t slice, uint8_t ab_channel, bool variable } // If we're both fixed frequency but we don't match target frequencies then we can't share. if (target_slice_frequencies[slice] != frequency) { - return PWMOUT_INVALID_FREQUENCY_ON_PIN; + return PWMOUT_INTERNAL_RESOURCES_IN_USE; } } diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 71050677f22..2f815cd2ee0 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -68,14 +68,69 @@ static void rp2pio_statemachine_set_pull(pio_pinmask_t pull_pin_up, pio_pinmask_ } } +// audio_dma and rp2pio cooperate on DMA_IRQ_0 using the SDK's shared interrupt +// handlers. We add our handler when we enable our first channel and remove it +// when our last channel is disabled. See the DMA IRQ allocation notes in +// common-hal/microcontroller/__init__.c. + +// Shared DMA_IRQ_0 handler for rp2pio background reads and writes. It +// acknowledges and services only its own channels, leaving any other channels' +// interrupts (e.g. audio) for the other shared handlers to acknowledge. +static void __not_in_flash_func(rp2pio_dma_irq_handler)(void) { + for (size_t i = 0; i < NUM_DMA_CHANNELS; i++) { + uint32_t mask = 1 << i; + if ((dma_hw->ints0 & mask) == 0) { + continue; + } + rp2pio_statemachine_obj_t *read = MP_STATE_PORT(background_pio_read)[i]; + rp2pio_statemachine_obj_t *write = MP_STATE_PORT(background_pio_write)[i]; + if (read == NULL && write == NULL) { + // Not one of our channels; leave it for another shared handler. + continue; + } + // Acknowledge the interrupt early; see the comment in audio_dma.c. + dma_hw->ints0 = mask; + if (read != NULL) { + rp2pio_statemachine_dma_complete_read(read, i); + } + if (write != NULL) { + rp2pio_statemachine_dma_complete_write(write, i); + } + } +} + +// Channels (bitmask) rp2pio currently has enabled on DMA_IRQ_0. Used to decide +// when to add/remove our shared interrupt handler. +static uint32_t rp2pio_dma_irq0_channel_mask = 0; + +static void rp2pio_dma_enable_irq(uint channel) { + // Clear any latent interrupt so that we don't immediately re-trigger. + dma_hw->ints0 = 1u << channel; + if (rp2pio_dma_irq0_channel_mask == 0) { + irq_add_shared_handler(DMA_IRQ_0, rp2pio_dma_irq_handler, + PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); + } + rp2pio_dma_irq0_channel_mask |= 1u << channel; + dma_irqn_set_channel_enabled(0, channel, true); + irq_set_enabled(DMA_IRQ_0, true); +} + +static void rp2pio_dma_disable_irq(uint channel) { + dma_irqn_set_channel_enabled(0, channel, false); + rp2pio_dma_irq0_channel_mask &= ~(1u << channel); + if (rp2pio_dma_irq0_channel_mask == 0) { + irq_remove_handler(DMA_IRQ_0, rp2pio_dma_irq_handler); + } + // Turn off the IRQ line entirely once no one (audio or rp2pio) needs it. + if (dma_hw->inte0 == 0) { + irq_set_enabled(DMA_IRQ_0, false); + } +} + static void rp2pio_statemachine_clear_dma_write(int pio_index, int sm) { if (SM_DMA_ALLOCATED_WRITE(pio_index, sm)) { int channel_write = SM_DMA_GET_CHANNEL_WRITE(pio_index, sm); - uint32_t channel_mask_write = 1u << channel_write; - dma_hw->inte0 &= ~channel_mask_write; - if (!dma_hw->inte0) { - irq_set_mask_enabled(1 << DMA_IRQ_0, false); - } + rp2pio_dma_disable_irq(channel_write); MP_STATE_PORT(background_pio_write)[channel_write] = NULL; dma_channel_abort(channel_write); dma_channel_unclaim(channel_write); @@ -86,11 +141,7 @@ static void rp2pio_statemachine_clear_dma_write(int pio_index, int sm) { static void rp2pio_statemachine_clear_dma_read(int pio_index, int sm) { if (SM_DMA_ALLOCATED_READ(pio_index, sm)) { int channel_read = SM_DMA_GET_CHANNEL_READ(pio_index, sm); - uint32_t channel_mask_read = 1u << channel_read; - dma_hw->inte0 &= ~channel_mask_read; - if (!dma_hw->inte0) { - irq_set_mask_enabled(1 << DMA_IRQ_0, false); - } + rp2pio_dma_disable_irq(channel_read); MP_STATE_PORT(background_pio_read)[channel_read] = NULL; dma_channel_abort(channel_read); dma_channel_unclaim(channel_read); @@ -181,6 +232,24 @@ static pio_pinmask_t _check_pins_free(const mcu_pin_obj_t *first_pin, uint8_t pi return pins_we_use; } +// Same as _check_pins_free but over an explicit GPIO mask, for pins a program +// only waits on. Sharing with another state machine is always allowed for +// these; the caller isn't driving them. +static void _check_gpio_mask_free(pio_pinmask_t mask) { + for (size_t pin_number = 0; pin_number < NUM_BANK0_GPIOS; pin_number++) { + if (!PIO_PINMASK_IS_SET(mask, pin_number)) { + continue; + } + const mcu_pin_obj_t *pin = mcu_get_pin_by_number(pin_number); + if (!pin) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_Pin); + } + if (_pin_reference_count[pin_number] == 0) { + assert_pin_free(pin); + } + } +} + static enum pio_fifo_join compute_fifo_type(int fifo_type_in, bool rx_fifo, bool tx_fifo) { if (fifo_type_in != PIO_FIFO_JOIN_AUTO) { return fifo_type_in; @@ -222,18 +291,60 @@ static bool is_gpio_compatible(PIO pio, uint32_t used_gpio_ranges) { #endif } -static bool use_existing_program(PIO *pio_out, int *sm_out, int *offset_inout, uint32_t program_id, size_t program_len, uint gpio_base, uint gpio_count) { - uint32_t required_gpio_ranges; - if (gpio_count) { - required_gpio_ranges = (1u << (gpio_base >> 4)) | - (1u << ((gpio_base + gpio_count - 1) >> 4)); - } else { - required_gpio_ranges = 0; +static uint32_t required_gpio_ranges(uint gpio_base, uint gpio_count) { + if (!gpio_count) { + return 0; } + return (1u << (gpio_base >> 4)) | + (1u << ((gpio_base + gpio_count - 1) >> 4)); +} +// Look for a PIO that already uses some of the pins we need. The cross-PIO +// overlap check in rp2pio_statemachine_construct fails a construct outright +// when its pins live on another PIO, so a generic claim can hand us a PIO that +// can't work while a usable one sits idle. +static bool use_pio_owning_pins(PIO *pio_out, int *sm_out, int *offset_inout, pio_program_t *program_struct, pio_pinmask_t pins_we_use, uint gpio_base, uint gpio_count) { + if (PIO_PINMASK_VALUE(pins_we_use) == 0) { + return false; + } + uint32_t ranges = required_gpio_ranges(gpio_base, gpio_count); for (size_t i = 0; i < NUM_PIOS; i++) { PIO pio = pio_get_instance(i); - if (!is_gpio_compatible(pio, required_gpio_ranges)) { + if (PIO_PINMASK_VALUE(PIO_PINMASK_AND(_current_pins[i], pins_we_use)) == 0) { + continue; + } + if (!is_gpio_compatible(pio, ranges) || !pio_can_add_program(pio, program_struct)) { + continue; + } + int sm = pio_claim_unused_sm(pio, false); + if (sm < 0) { + continue; + } + *pio_out = pio; + *sm_out = sm; + *offset_inout = pio_add_program(pio, program_struct); + return true; + } + return false; +} + +// FNV-1a over the instruction words. Never returns 0, which _current_program_id +// uses to mean "no program". +static uint32_t program_hash(const uint16_t *program, size_t program_len) { + uint32_t hash = 0x811c9dc5; + for (size_t i = 0; i < program_len; i++) { + hash = (hash ^ (program[i] & 0xff)) * 0x01000193; + hash = (hash ^ (program[i] >> 8)) * 0x01000193; + } + return hash == 0 ? 1 : hash; +} + +static bool use_existing_program(PIO *pio_out, int *sm_out, int *offset_inout, uint32_t program_id, size_t program_len, uint gpio_base, uint gpio_count) { + uint32_t ranges = required_gpio_ranges(gpio_base, gpio_count); + + for (size_t i = 0; i < NUM_PIOS; i++) { + PIO pio = pio_get_instance(i); + if (!is_gpio_compatible(pio, ranges)) { continue; } for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { @@ -275,8 +386,14 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, int fifo_type, int mov_status_type, int mov_status_n ) { - // Create a program id that isn't the pointer so we can store it without storing the original object. - uint32_t program_id = ~((uint32_t)program); + // Create a program id we can store without storing the original object. + // This has to hash the instructions rather than the pointer: programs that + // encode absolute pin numbers (`wait gpio`) are assembled into a caller's + // stack buffer, so two different programs can share an address, and + // use_existing_program() would then hand the second one the first one's + // already-loaded instructions. Hashing the contents also lets identical + // programs from different arrays share a single copy in instruction memory. + uint32_t program_id = program_hash(program, program_len); uint gpio_base = 0, gpio_count = 0; #if NUM_BANK0_GPIOS > 32 @@ -310,7 +427,11 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, int state_machine; bool added = false; - if (!use_existing_program(&pio, &state_machine, &offset, program_id, program_len, gpio_base, gpio_count)) { + if (use_existing_program(&pio, &state_machine, &offset, program_id, program_len, gpio_base, gpio_count)) { + // Program is already loaded and shareable; nothing to add. + } else if (use_pio_owning_pins(&pio, &state_machine, &offset, &program_struct, pins_we_use, gpio_base, gpio_count)) { + added = true; + } else { uint program_offset; bool r = pio_claim_free_sm_and_add_program_for_gpio_range(&program_struct, &pio, (uint *)&state_machine, &program_offset, gpio_base, gpio_count, true); if (!r) { @@ -347,9 +468,20 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, _current_sm_pins[pio_index][state_machine] = pins_we_use; PIO_PINMASK_MERGE(_current_pins[pio_index], pins_we_use); - pio_sm_set_pins_with_mask64(self->pio, state_machine, PIO_PINMASK_VALUE(initial_pin_state), PIO_PINMASK_VALUE(pins_we_use)); - pio_sm_set_pindirs_with_mask64(self->pio, state_machine, PIO_PINMASK_VALUE(initial_pin_direction), PIO_PINMASK_VALUE(pins_we_use)); - rp2pio_statemachine_set_pull(pull_pin_up, pull_pin_down, pins_we_use); + // Only configure the pins no other state machine has claimed yet. A shared + // pin that this state machine doesn't drive (a clock it only waits on, say) + // would otherwise be forced back to input, clobbering its owner's setup. + pio_pinmask_t pins_we_own = PIO_PINMASK_NONE; + for (size_t pin_number = 0; pin_number < NUM_BANK0_GPIOS; pin_number++) { + if (PIO_PINMASK_IS_SET(pins_we_use, pin_number) && _pin_reference_count[pin_number] == 0) { + PIO_PINMASK_SET(pins_we_own, pin_number); + } + } + self->pins_we_own = pins_we_own; + + pio_sm_set_pins_with_mask64(self->pio, state_machine, PIO_PINMASK_VALUE(initial_pin_state), PIO_PINMASK_VALUE(pins_we_own)); + pio_sm_set_pindirs_with_mask64(self->pio, state_machine, PIO_PINMASK_VALUE(initial_pin_direction), PIO_PINMASK_VALUE(pins_we_own)); + rp2pio_statemachine_set_pull(pull_pin_up, pull_pin_down, pins_we_own); self->initial_pin_state = initial_pin_state; self->initial_pin_direction = initial_pin_direction; self->pull_pin_up = pull_pin_up; @@ -632,6 +764,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, common_hal_rp2pio_statemachine_mark_deinit(self); // First, check that all pins are free OR already in use by any PIO if exclusive_pin_use is false. + _check_gpio_mask_free(wait_gpio_mask); pio_pinmask_t pins_we_use = wait_gpio_mask; PIO_PINMASK_MERGE(pins_we_use, _check_pins_free(first_out_pin, out_pin_count, exclusive_pin_use)); PIO_PINMASK_MERGE(pins_we_use, _check_pins_free(first_in_pin, in_pin_count, exclusive_pin_use)); @@ -758,11 +891,10 @@ void common_hal_rp2pio_statemachine_restart(rp2pio_statemachine_obj_t *self) { // the desired offset, so we can just use self->offset. pio_sm_exec(self->pio, self->state_machine, self->offset); pio_sm_restart(self->pio, self->state_machine); - uint8_t pio_index = pio_get_index(self->pio); - pio_pinmask_t pins_we_use = _current_sm_pins[pio_index][self->state_machine]; - pio_sm_set_pins_with_mask64(self->pio, self->state_machine, PIO_PINMASK_VALUE(self->initial_pin_state), PIO_PINMASK_VALUE(pins_we_use)); - pio_sm_set_pindirs_with_mask64(self->pio, self->state_machine, PIO_PINMASK_VALUE(self->initial_pin_direction), PIO_PINMASK_VALUE(pins_we_use)); - rp2pio_statemachine_set_pull(self->pull_pin_up, self->pull_pin_down, pins_we_use); + pio_pinmask_t pins_we_own = self->pins_we_own; + pio_sm_set_pins_with_mask64(self->pio, self->state_machine, PIO_PINMASK_VALUE(self->initial_pin_state), PIO_PINMASK_VALUE(pins_we_own)); + pio_sm_set_pindirs_with_mask64(self->pio, self->state_machine, PIO_PINMASK_VALUE(self->initial_pin_direction), PIO_PINMASK_VALUE(pins_we_own)); + rp2pio_statemachine_set_pull(self->pull_pin_up, self->pull_pin_down, pins_we_own); common_hal_rp2pio_statemachine_run(self, self->init, self->init_len); pio_sm_set_enabled(self->pio, self->state_machine, true); } @@ -811,6 +943,38 @@ void rp2pio_statemachine_never_reset(PIO pio, int sm) { _never_reset[pio_index][sm] = true; } +// Pick a PIO that has room for a program of program_size instructions and at +// least sm_count free state machines; returns its index, or NUM_PIOS if none +// qualifies. This lets an out-of-tree PIO user (e.g. the sdioio SDIO driver, +// which manages its own SDK-level pio_claim_unused_sm / pio_add_program) pick a +// PIO cooperatively rather than blindly seizing pio0/pio1/pio2. Because it uses +// the same SDK claim/instruction bookkeeping that rp2pio itself relies on, a hit +// here means the caller's subsequent claims on the returned PIO will succeed and +// will not collide with an existing rp2pio user. +uint8_t rp2pio_statemachine_find_pio(int program_size, int sm_count) { + pio_program_t test_program = { + .instructions = NULL, + .length = program_size, + .origin = -1, + }; + for (size_t i = 0; i < NUM_PIOS; i++) { + PIO pio = pio_get_instance(i); + if (!pio_can_add_program(pio, &test_program)) { + continue; + } + int free_sms = 0; + for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { + if (!pio_sm_is_claimed(pio, j)) { + free_sms++; + } + } + if (free_sms >= sm_count) { + return i; + } + } + return NUM_PIOS; +} + void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins) { common_hal_rp2pio_statemachine_stop(self); (void)common_hal_rp2pio_statemachine_stop_background_write(self); @@ -1274,12 +1438,8 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t * common_hal_mcu_disable_interrupts(); - // Acknowledge any previous pending interrupt - dma_hw->ints0 |= 1u << channel_write; MP_STATE_PORT(background_pio_write)[channel_write] = self; - dma_hw->inte0 |= 1u << channel_write; - - irq_set_mask_enabled(1 << DMA_IRQ_0, true); + rp2pio_dma_enable_irq(channel_write); dma_start_channel_mask(1u << channel_write); common_hal_mcu_enable_interrupts(); @@ -1438,11 +1598,8 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s false); common_hal_mcu_disable_interrupts(); - // Acknowledge any previous pending interrupt - dma_hw->ints0 |= 1u << channel_read; MP_STATE_PORT(background_pio_read)[channel_read] = self; - dma_hw->inte0 |= 1u << channel_read; - irq_set_mask_enabled(1 << DMA_IRQ_0, true); + rp2pio_dma_enable_irq(channel_read); dma_start_channel_mask((1u << channel_read)); common_hal_mcu_enable_interrupts(); @@ -1482,6 +1639,36 @@ bool common_hal_rp2pio_statemachine_stop_background_read(rp2pio_statemachine_obj return true; } +void common_hal_rp2pio_statemachine_set_read_buffers_raw(rp2pio_statemachine_obj_t *self, + void *once, size_t once_len, + void *loop, size_t loop_len, + void *loop2, size_t loop2_len) { + memset(&self->once_read_buf_info, 0, sizeof(self->once_read_buf_info)); + memset(&self->loop_read_buf_info, 0, sizeof(self->loop_read_buf_info)); + memset(&self->loop2_read_buf_info, 0, sizeof(self->loop2_read_buf_info)); + if (once && once_len) { + self->once_read_buf_info.info.buf = once; + self->once_read_buf_info.info.len = once_len; + } + if (loop && loop_len) { + self->loop_read_buf_info.info.buf = loop; + self->loop_read_buf_info.info.len = loop_len; + } + if (loop2 && loop2_len) { + self->loop2_read_buf_info.info.buf = loop2; + self->loop2_read_buf_info.info.len = loop2_len; + } +} + +int common_hal_rp2pio_statemachine_get_read_dma_channel(rp2pio_statemachine_obj_t *self) { + uint8_t pio_index = pio_get_index(self->pio); + uint8_t sm = self->state_machine; + if (!SM_DMA_ALLOCATED_READ(pio_index, sm)) { + return -1; + } + return SM_DMA_GET_CHANNEL_READ(pio_index, sm); +} + bool common_hal_rp2pio_statemachine_get_reading(rp2pio_statemachine_obj_t *self) { return !self->dma_completed_read; } diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h index c7ef12e1b01..c2007ca1905 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h @@ -12,6 +12,11 @@ #include "common-hal/memorymap/AddressRange.h" #include "hardware/pio.h" +// Shared PIO allocator declarations (rp2pio_statemachine_find_pio, +// rp2pio_statemachine_never_reset, rp2pio_statemachine_reset_ok). Kept in a +// separate, mp-free header so external C++ drivers can include them too. +#include "pio_alloc.h" + // pio_pinmask_t can hold ANY pin masks, so it is used before selection of gpiobase #if NUM_BANK0_GPIOS > 32 typedef struct { uint64_t value; @@ -100,6 +105,7 @@ typedef struct { PIO pio; const uint16_t *init; size_t init_len; + pio_pinmask_t pins_we_own; // Subset of pins that no other state machine had already claimed. pio_pinmask_t initial_pin_state; pio_pinmask_t initial_pin_direction; pio_pinmask_t pull_pin_up; @@ -174,9 +180,4 @@ void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins void rp2pio_statemachine_dma_complete_write(rp2pio_statemachine_obj_t *self, int channel); void rp2pio_statemachine_dma_complete_read(rp2pio_statemachine_obj_t *self, int channel); -void rp2pio_statemachine_reset_ok(PIO pio, int sm); -void rp2pio_statemachine_never_reset(PIO pio, int sm); - -uint8_t rp2pio_statemachine_find_pio(int program_size, int sm_count); - extern const mp_obj_type_t rp2pio_statemachine_type; diff --git a/ports/raspberrypi/common-hal/rp2pio/pio_alloc.h b/ports/raspberrypi/common-hal/rp2pio/pio_alloc.h new file mode 100644 index 00000000000..ceb4e31631a --- /dev/null +++ b/ports/raspberrypi/common-hal/rp2pio/pio_alloc.h @@ -0,0 +1,36 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Shared PIO allocator declarations that let external drivers (including the +// vendored C++ PioSdioCard driver) cooperate with CircuitPython's rp2pio PIO +// allocator instead of seizing whole PIO blocks through the raw SDK. The +// definitions live in common-hal/rp2pio/StateMachine.c. This header +// deliberately does NOT include the MicroPython object headers pulled in by the +// full rp2pio StateMachine.h, so it can be included from C++ translation units. +// The declarations are given C linkage for that reason. + +#pragma once + +#include "hardware/pio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// See common-hal/rp2pio/StateMachine.c. Returns a PIO index (0..NUM_PIOS-1) with +// room for program_size instructions and sm_count free state machines, or +// NUM_PIOS if none qualifies. +uint8_t rp2pio_statemachine_find_pio(int program_size, int sm_count); + +// Mark / unmark a state machine as surviving (or not) a soft reset, so +// rp2pio's reset path keeps its bookkeeping coherent with the SMs a driver +// claims directly. +void rp2pio_statemachine_never_reset(PIO pio, int sm); +void rp2pio_statemachine_reset_ok(PIO pio, int sm); + +#ifdef __cplusplus +} +#endif diff --git a/ports/raspberrypi/common-hal/rtc/pico_time.c b/ports/raspberrypi/common-hal/rtc/pico_time.c new file mode 100644 index 00000000000..c2e3ce9e974 --- /dev/null +++ b/ports/raspberrypi/common-hal/rtc/pico_time.c @@ -0,0 +1,39 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +// The SDK expects the port to provide pico_localtime_r() and pico_mktime(); its +// weak defaults call newlib's localtime_r() and mktime(). CircuitPython has the +// same calendar arithmetic in shared/timeutils, so use that and keep newlib's +// time functions, and what they link in, out of the image. +// +// Newlib would run without a TZ setting here, so both compute UTC. + +#include + +#include "pico/util/datetime.h" +#include "shared/timeutils/timeutils.h" + +struct tm *pico_localtime_r(const time_t *time, struct tm *tm) { + timeutils_struct_time_t t; + timeutils_seconds_since_1970_to_struct_time((timeutils_timestamp_t)*time, &t); + tm->tm_year = t.tm_year - 1900; + tm->tm_mon = t.tm_mon - 1; + tm->tm_mday = t.tm_mday; + tm->tm_hour = t.tm_hour; + tm->tm_min = t.tm_min; + tm->tm_sec = t.tm_sec; + tm->tm_wday = (t.tm_wday + 1) % 7; // timeutils counts from Monday, struct tm from Sunday + tm->tm_yday = t.tm_yday - 1; + tm->tm_isdst = 0; + return tm; +} + +time_t pico_mktime(struct tm *tm) { + time_t t = (time_t)timeutils_mktime_1970(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + pico_localtime_r(&t, tm); // mktime() also normalises the fields it was given + return t; +} diff --git a/ports/raspberrypi/common-hal/sdioio/SDCard.c b/ports/raspberrypi/common-hal/sdioio/SDCard.c new file mode 100644 index 00000000000..04b78dbc4d2 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/SDCard.c @@ -0,0 +1,260 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "common-hal/sdioio/SDCard.h" +#include "common-hal/sdioio/sdfat_pio/shim.h" + +#include "extmod/vfs.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/sdioio/SDCard.h" +#include "shared-bindings/util.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "hardware/platform_defs.h" // NUM_PIOS + +// Live-instance tracking for soft-reset cleanup. The vendored SdFat PIO driver +// claims its PIO block through the raw SDK (pio_claim_unused_sm), whose claim +// bitset lives in static RAM and survives a soft reboot. Because the GC heap is +// wiped without running finalizers, a successfully-constructed card would leak +// its whole PIO block on every Ctrl-D (see sdio_init_troubleshooting.md, +// "Error 43 is a PIO-leak red herring"). We keep a static table of the live +// cards so sdioio_reset() can deinit them (→ pioEnd() → SDK unclaim) before the +// heap is reset. A card is registered only after a fully successful construct +// and removed on deinit; each card consumes a whole PIO, so NUM_PIOS slots is a +// hard upper bound. +static sdioio_sdcard_obj_t *_active_cards[NUM_PIOS]; + +static void register_card(sdioio_sdcard_obj_t *self) { + for (size_t i = 0; i < MP_ARRAY_SIZE(_active_cards); i++) { + if (_active_cards[i] == NULL) { + _active_cards[i] = self; + return; + } + } +} + +static void unregister_card(sdioio_sdcard_obj_t *self) { + for (size_t i = 0; i < MP_ARRAY_SIZE(_active_cards); i++) { + if (_active_cards[i] == self) { + _active_cards[i] = NULL; + return; + } + } +} + +// Maximum SD clock the PIO driver is allowed to be asked for. At a typical +// 150 MHz clk_sys the driver tops out near 37.5 MHz (clkDiv == 1); the cap is +// generous and the achieved rate is reported back through the `frequency` +// property. +#define SDIO_MAX_FREQUENCY (50000000) + +void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, + uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency) { + // The vendored PIO driver only supports 4-bit mode and requires the four + // data lines to be on consecutive GPIOs (DAT0..DAT3). + if (num_data != 4) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Number of data_pins must be %d, not %d"), 4, num_data); + } + for (size_t i = 1; i < num_data; i++) { + if (data[i]->number != data[0]->number + i) { + mp_raise_ValueError(MP_ERROR_TEXT("Data pins must be consecutive")); + } + } + + mp_arg_validate_int_max(frequency, SDIO_MAX_FREQUENCY, MP_QSTR_frequency); + + self->num_data = num_data; + self->clock = clock->number; + self->command = command->number; + for (size_t i = 0; i < num_data; i++) { + self->data[i] = data[i]->number; + } + + claim_pin(clock); + claim_pin(command); + for (size_t i = 0; i < num_data; i++) { + claim_pin(data[i]); + } + + sdfat_pio_card_new(&self->card); + uint32_t actual_frequency = 0; + bool ok = sdfat_pio_card_begin(&self->card, clock->number, command->number, + data[0]->number, frequency, &actual_frequency); + if (!ok) { + // The driver's error code identifies the SD command/phase that failed + // (see SdCardInfo.h SD_CARD_ERROR_* codes). + uint8_t error_code = sdfat_pio_card_error_code(&self->card); + sdfat_pio_card_end(&self->card); + sdfat_pio_card_free(&self->card); + reset_pin_number(self->clock); + reset_pin_number(self->command); + for (size_t i = 0; i < num_data; i++) { + reset_pin_number(self->data[i]); + } + self->command = COMMON_HAL_MCU_NO_PIN; + mp_raise_OSError_msg_varg( + MP_ERROR_TEXT("SDIO Init Error 0x%02x"), error_code); + } + + self->frequency = actual_frequency; + self->capacity = sdfat_pio_card_sector_count(&self->card); + + // Track the live card so sdioio_reset() can release its leaked PIO block on + // the next soft reboot. + register_card(self); +} + +uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t *self) { + return self->capacity; +} + +uint32_t common_hal_sdioio_sdcard_get_frequency(sdioio_sdcard_obj_t *self) { + return self->frequency; +} + +uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t *self) { + return self->num_data; +} + +static void check_for_deinit(sdioio_sdcard_obj_t *self) { + if (common_hal_sdioio_sdcard_deinited(self)) { + raise_deinited_error(); + } +} + +static void check_whole_block(mp_buffer_info_t *bufinfo) { + if (bufinfo->len % 512) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 512); + } +} + +// Native function for the VFS blockdev layer. The PIO driver is synchronous and +// polling, so these block until the transfer completes. +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!sdfat_pio_card_read_sectors(&self->card, start_block, buf, num_blocks)) { + return -MP_EIO; + } + return 0; +} + +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!sdfat_pio_card_write_sectors(&self->card, start_block, buf, num_blocks)) { + return -MP_EIO; + } + return 0; +} + +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer. +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed. + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors. + return true; + + default: + return false; // Unsupported command. + } +} + +bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { + // Only 4-bit mode is supported (see construct); reject a request for any + // other width. Reconfiguring the clock at runtime is not implemented yet, + // so the frequency argument is accepted but ignored. + if (bits != 0 && bits != self->num_data) { + return false; + } + return true; +} + +bool common_hal_sdioio_sdcard_deinited(sdioio_sdcard_obj_t *self) { + return self->command == COMMON_HAL_MCU_NO_PIN; +} + +void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self) { + if (common_hal_sdioio_sdcard_deinited(self)) { + return; + } + + unregister_card(self); + + sdfat_pio_card_end(&self->card); + sdfat_pio_card_free(&self->card); + + reset_pin_number(self->command); + self->command = COMMON_HAL_MCU_NO_PIN; + reset_pin_number(self->clock); + self->clock = COMMON_HAL_MCU_NO_PIN; + for (size_t i = 0; i < self->num_data; i++) { + reset_pin_number(self->data[i]); + self->data[i] = COMMON_HAL_MCU_NO_PIN; + } +} + +void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self) { + if (common_hal_sdioio_sdcard_deinited(self)) { + return; + } + + self->never_reset = true; + + never_reset_pin_number(self->command); + never_reset_pin_number(self->clock); + for (size_t i = 0; i < self->num_data; i++) { + never_reset_pin_number(self->data[i]); + } + + // Also protect the PIO state machines the driver claimed so the rp2pio + // soft-reset path keeps its never-reset bookkeeping coherent with them. + sdfat_pio_card_never_reset(&self->card); +} + +void sdioio_reset(void) { + // Release every live card that isn't protected by never_reset. deinit() + // runs pioEnd(), which unclaims the PIO at the SDK level. + for (size_t i = 0; i < MP_ARRAY_SIZE(_active_cards); i++) { + sdioio_sdcard_obj_t *self = _active_cards[i]; + if (self == NULL || self->never_reset) { + continue; + } + // deinit() calls unregister_card(), clearing this slot. + common_hal_sdioio_sdcard_deinit(self); + } +} diff --git a/ports/raspberrypi/common-hal/sdioio/SDCard.h b/ports/raspberrypi/common-hal/sdioio/SDCard.h new file mode 100644 index 00000000000..a4dca731f73 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/SDCard.h @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/sdioio/sdfat_pio/shim.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // In-place storage for the vendored C++ PioSdioCard instance, constructed + // and torn down through the extern "C" shim in sdfat_pio/. + sdioio_pio_card_storage_t card; + uint32_t frequency; + uint32_t capacity; // Number of 512-byte blocks. + uint8_t num_data; + uint8_t command; + uint8_t clock; + uint8_t data[4]; + bool never_reset; +} sdioio_sdcard_obj_t; + +// Called by the supervisor on soft reset to release any card that is not +// protected with never_reset. +void sdioio_reset(void); diff --git a/ports/raspberrypi/common-hal/sdioio/__init__.c b/ports/raspberrypi/common-hal/sdioio/__init__.c new file mode 100644 index 00000000000..4a92fca8794 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/__init__.c @@ -0,0 +1,8 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// No sdioio module functions. The whole API lives on sdioio.SDCard, which is +// implemented in SDCard.c. diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/DbgLog.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/DbgLog.h new file mode 100644 index 00000000000..8d1ba8db85a --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/DbgLog.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief Classes for Debug messages. + * + * CircuitPython vendored, trimmed copy. The upstream DbgLog.h includes the + * Arduino Printable.h and defines a family of helper print classes (Bin, Hex, + * Num, Dbl, logmsg...). Those are only referenced when debug output is enabled + * (ENABLE_DBG_MSG / USE_DEBUG_MODE), which it is not in this build, so they are + * omitted to keep the Arduino Print dependency out of the firmware. Only the + * no-op DBG_MSG() macro that PioSdioCard.cpp uses on its normal paths remains. + */ +#pragma once + +/** Debug messages are disabled in the CircuitPython build. */ +#define DBG_MSG(...) \ + do { \ + } while (0) diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp new file mode 100644 index 00000000000..f91515ccef2 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp @@ -0,0 +1,1026 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +#ifdef ARDUINO_ARCH_RP2040 +#include + +#include // Required for std::max, std::min +#define DEBUG_FILE "PioSdioCard.cpp" +#include "../SdCardInfo.h" +#include "DbgLog.h" +#include "PioSdioCard.h" +#include "PioSdioCard.pio.h" +// CIRCUITPY-CHANGE: cooperate with CircuitPython's rp2pio PIO allocator +#include "common-hal/rp2pio/pio_alloc.h" +//------------------------------------------------------------------------------ +// USE_DEBUG_MODE 0 - no debug, 1 - print message, 2 - Use scope/analyzer. +#define USE_DEBUG_MODE 0 + +const uint PIO_CLK_DIV_RUN = 1; + +const uint PIN_SDIO_UNDEFINED = 63u; + +const uint DAT_FIFO_DEPTH = 8; +//============================================================================== +// Command definitions. +enum { RSP_R0 = 0, RSP_R1 = 1, RSP_R2 = 2, RSP_R3 = 3, RSP_R6 = 6, RSP_R7 = 7 }; +static const CmdRsp_t CMD0_R0(CMD0, RSP_R0); +static const CmdRsp_t CMD2_R2(CMD2, RSP_R2); +static const CmdRsp_t CMD3_R6(CMD3, RSP_R6); +static const CmdRsp_t CMD6_R1(CMD6, RSP_R1); +static const CmdRsp_t CMD7_R1(CMD7, RSP_R1); +static const CmdRsp_t CMD8_R7(CMD8, RSP_R7); +static const CmdRsp_t CMD9_R2(CMD9, RSP_R2); +static const CmdRsp_t CMD10_R2(CMD10, RSP_R2); +static const CmdRsp_t CMD12_R1(CMD12, RSP_R1); +static const CmdRsp_t CMD13_R1(CMD13, RSP_R1); +static const CmdRsp_t CMD18_R1(CMD18, RSP_R1); +static const CmdRsp_t CMD25_R1(CMD25, RSP_R1); +static const CmdRsp_t CMD32_R1(CMD32, RSP_R1); +static const CmdRsp_t CMD33_R1(CMD33, RSP_R1); +static const CmdRsp_t CMD38_R1(CMD38, RSP_R1); +static const CmdRsp_t CMD55_R1(CMD55, RSP_R1); +static const CmdRsp_t ACMD6_R1(ACMD6, RSP_R1); +static const CmdRsp_t ACMD13_R1(ACMD13, RSP_R1); +static const CmdRsp_t ACMD41_R3(ACMD41, RSP_R3); +static const CmdRsp_t ACMD51_R1(ACMD51, RSP_R1); +//============================================================================== +class Timeout { + public: + explicit Timeout(uint ms) : _usStart(0), _usTimeout(1000 * ms) {} + bool timedOut() { + if (_usStart) { + return (usSinceBoot() - _usStart) > _usTimeout; + } + _usStart = usSinceBoot(); + return false; + } + uint32_t usSinceBoot() { return to_us_since_boot(get_absolute_time()); } + uint32_t _usStart; + uint32_t _usTimeout; +}; +//============================================================================== +#if USE_DEBUG_MODE +//------------------------------------------------------------------------------ +static inline void gpioStatus(uint gpio) { + logmsgln("gpio", gpio, " drive: ", gpio_get_drive_strength(gpio)); + // logmsgln("gpio", gpio, + // " drive: ", static_cast(gpio_get_drive_strength(gpio))); + logmsgln("gpio", gpio, " slew: ", gpio_get_slew_rate(gpio)); + logmsgln("gpio", gpio, " hyst: ", gpio_is_input_hysteresis_enabled(gpio)); + logmsgln("gpio", gpio, " pull: ", gpio_is_pulled_up(gpio)); +} +//------------------------------------------------------------------------------ +static inline void pioRegs(PIO pio) { + logmsgln("ctrl: 0b", Bin(pio->ctrl)); + logmsgln("fstat: 0b", Bin(pio->fstat)); + logmsgln("fdebug: 0b", Bin(pio->fdebug)); + logmsgln("flevel: 0b", Bin(pio->flevel)); + logmsgln("padout: 0b", Bin(pio->dbg_padout)); + logmsgln("padoe: 0b", Bin(pio->dbg_padoe)); + logmsgln("cfginfo: 0x", Hex(pio->dbg_cfginfo)); + logmsgln("sync_bypass: 0b", Bin(pio->input_sync_bypass)); +} +//------------------------------------------------------------------------------ +static inline void pioSmRegs(PIO pio, uint sm) { + logmsgln("sm", sm, " clkdiv: 0x", Hex(pio->sm[sm].clkdiv)); + logmsgln("sm", sm, " execctrl: 0x", Hex(pio->sm[sm].execctrl)); + logmsgln("sm", sm, " shiftctrl: 0x", Hex(pio->sm[sm].shiftctrl)); + logmsgln("sm", sm, " addr: 0x", Hex(pio->sm[sm].addr)); + logmsgln("sm", sm, " pinctrl: 0x", Hex(pio->sm[sm].pinctrl)); +} +//------------------------------------------------------------------------------ +#endif // USE_DEBUG_MODE +#define sdError(code) \ + { \ + setSdErrorCode(code, __LINE__); \ + DBG_MSG(#code); \ + } +#define SDIO_FAIL() DBG_MSG("SDIO_FAIL") +//============================================================================== +// CRC functions. +//------------------------------------------------------------------------------ +// See this library's extras folder. +static const uint8_t crc7_table[256] = { + 0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e, // 00 - 07 + 0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee, // 08 - 0f + 0x32, 0x20, 0x16, 0x04, 0x7a, 0x68, 0x5e, 0x4c, // 10 - 17 + 0xa2, 0xb0, 0x86, 0x94, 0xea, 0xf8, 0xce, 0xdc, // 18 - 1f + 0x64, 0x76, 0x40, 0x52, 0x2c, 0x3e, 0x08, 0x1a, // 20 - 27 + 0xf4, 0xe6, 0xd0, 0xc2, 0xbc, 0xae, 0x98, 0x8a, // 28 - 2f + 0x56, 0x44, 0x72, 0x60, 0x1e, 0x0c, 0x3a, 0x28, // 30 - 37 + 0xc6, 0xd4, 0xe2, 0xf0, 0x8e, 0x9c, 0xaa, 0xb8, // 38 - 3f + 0xc8, 0xda, 0xec, 0xfe, 0x80, 0x92, 0xa4, 0xb6, // 40 - 47 + 0x58, 0x4a, 0x7c, 0x6e, 0x10, 0x02, 0x34, 0x26, // 48 - 4f + 0xfa, 0xe8, 0xde, 0xcc, 0xb2, 0xa0, 0x96, 0x84, // 50 - 57 + 0x6a, 0x78, 0x4e, 0x5c, 0x22, 0x30, 0x06, 0x14, // 58 - 5f + 0xac, 0xbe, 0x88, 0x9a, 0xe4, 0xf6, 0xc0, 0xd2, // 60 - 67 + 0x3c, 0x2e, 0x18, 0x0a, 0x74, 0x66, 0x50, 0x42, // 68 - 6f + 0x9e, 0x8c, 0xba, 0xa8, 0xd6, 0xc4, 0xf2, 0xe0, // 70 - 77 + 0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x70, // 78 - 7f + 0x82, 0x90, 0xa6, 0xb4, 0xca, 0xd8, 0xee, 0xfc, // 80 - 87 + 0x12, 0x00, 0x36, 0x24, 0x5a, 0x48, 0x7e, 0x6c, // 88 - 8f + 0xb0, 0xa2, 0x94, 0x86, 0xf8, 0xea, 0xdc, 0xce, // 90 - 97 + 0x20, 0x32, 0x04, 0x16, 0x68, 0x7a, 0x4c, 0x5e, // 98 - 9f + 0xe6, 0xf4, 0xc2, 0xd0, 0xae, 0xbc, 0x8a, 0x98, // a0 - a7 + 0x76, 0x64, 0x52, 0x40, 0x3e, 0x2c, 0x1a, 0x08, // a8 - af + 0xd4, 0xc6, 0xf0, 0xe2, 0x9c, 0x8e, 0xb8, 0xaa, // b0 - b7 + 0x44, 0x56, 0x60, 0x72, 0x0c, 0x1e, 0x28, 0x3a, // b8 - bf + 0x4a, 0x58, 0x6e, 0x7c, 0x02, 0x10, 0x26, 0x34, // c0 - c7 + 0xda, 0xc8, 0xfe, 0xec, 0x92, 0x80, 0xb6, 0xa4, // c8 - cf + 0x78, 0x6a, 0x5c, 0x4e, 0x30, 0x22, 0x14, 0x06, // d0 - d7 + 0xe8, 0xfa, 0xcc, 0xde, 0xa0, 0xb2, 0x84, 0x96, // d8 - df + 0x2e, 0x3c, 0x0a, 0x18, 0x66, 0x74, 0x42, 0x50, // e0 - e7 + 0xbe, 0xac, 0x9a, 0x88, 0xf6, 0xe4, 0xd2, 0xc0, // e8 - ef + 0x1c, 0x0e, 0x38, 0x2a, 0x54, 0x46, 0x70, 0x62, // f0 - f7 + 0x8c, 0x9e, 0xa8, 0xba, 0xc4, 0xd6, 0xe0, 0xf2 // f8 - ff +}; +//------------------------------------------------------------------------------ +inline static uint8_t CRC7(const uint8_t* data, uint8_t n) { + uint8_t crc = 0; + for (uint8_t i = 0; i < n; i++) { + crc = crc7_table[crc ^ data[i]]; + } + return crc | 1; +} +//------------------------------------------------------------------------------ +// Modified from sdio_crc16_4bit_checksum() in +// https://github.com/ZuluSCSI/ZuluSCSI-firmware +// +static inline __attribute__((always_inline)) uint64_t crc16(uint64_t crc, + uint32_t data_in) { + // Shift out 8 bits for each line + uint32_t data_out = crc >> 32; + crc <<= 32; + + // XOR outgoing data to itself with 4 bit delay + data_out ^= (data_out >> 16); + + // XOR incoming data to outgoing data with 4 bit delay + data_out ^= (data_in >> 16); + + // XOR outgoing and incoming data to accumulator at each tap + uint64_t xorred = data_out ^ data_in; + crc ^= xorred; + crc ^= xorred << (5 * 4); + crc ^= xorred << (12 * 4); + return crc; +} +//------------------------------------------------------------------------------ +//============================================================================== +// add to PioSdioCard class int the future. +// PioSdioCard::PioSdioCard() +// PioSdioCard::~PioSdioCard() +//------------------------------------------------------------------------------ +bool PioSdioCard::cardAcmd(uint32_t rca, CmdRsp_t cmdRsp, uint32_t arg) { + return cardCommand(CMD55_R1, rca) && cardCommand(cmdRsp, arg); +} +//------------------------------------------------------------------------------ +bool PioSdioCard::begin(PioSdioConfig sdioConfig) { + pioEnd(); + Timeout timeout(SD_INIT_TIMEOUT); + uint32_t arg; + m_curState = IDLE_STATE; + m_errorCode = SD_CARD_ERROR_NONE; + m_highCapacity = false; + m_initDone = false; + m_version2 = false; + m_clkPin = sdioConfig.clkPin(); + m_cmdPin = sdioConfig.cmdPin(); + m_dat0Pin = sdioConfig.dat0Pin(); + + // Four PIO cycles per SD CLK cycle. + m_clkDiv = ceil((0.00025 * clock_get_hz(clk_sys)) / SD_MAX_INIT_RATE_KHZ); + +#if USE_DEBUG_MODE == 2 + Serial.println(); + pioRegs(m_pio); + pioSmRegs(m_pio, m_sm0); + pioSmRegs(m_pio, m_sm1); + gpioStatus(m_clkPin); + gpioStatus(m_cmdPin); + while (Serial.read() >= 0) { + } + Serial.println("Logic Analyzer on then type any char"); + while (!Serial.available()) { + } +#endif // USE_DEBUG_MODE + // A few cards still require clocks after power-up. + powerUpClockCycles(); + if (!pioInit()) { + goto fail; + } + pioConfig(m_clkDiv); + if (!cardCommand(CMD0_R0, 0)) { + sdError(SD_CARD_ERROR_CMD0); + goto fail; + } + if (cardCommand(CMD8_R7, 0X1AA)) { + if (m_cardRsp != 0X1AA) { + sdError(SD_CARD_ERROR_CMD8); + goto fail; + } + m_version2 = true; + } else { + m_version2 = false; + m_errorCode = SD_CARD_ERROR_NONE; + } + arg = m_version2 ? 0X40300000 : 0x00300000; + while (true) { + if (!cardAcmd(0, ACMD41_R3, arg)) { + sdError(SD_CARD_ERROR_ACMD41); + goto fail; + } + if (m_cardRsp & 0x80000000) { + break; + } + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_ACMD41); + goto fail; + } + } + m_ocr = m_cardRsp; + if (m_cardRsp & 0x40000000) { + // Is high capacity. + m_highCapacity = true; + } + if (!cardCommand(CMD2_R2, 0)) { + sdError(SD_CARD_ERROR_CMD2); + goto fail; + } + if (!cardCommand(CMD3_R6, 0)) { + sdError(SD_CARD_ERROR_CMD3); + goto fail; + } + m_rca = m_cardRsp & 0xFFFF0000; + if (!cardCommand(CMD9_R2, m_rca, &m_csd)) { + sdError(SD_CARD_ERROR_CMD9); + goto fail; + } + if (!cardCommand(CMD10_R2, m_rca, &m_cid)) { + sdError(SD_CARD_ERROR_CMD10); + goto fail; + } + if (!cardCommand(CMD7_R1, m_rca)) { + sdError(SD_CARD_ERROR_CMD7); + goto fail; + } + + if (!cardAcmd(m_rca, ACMD6_R1, 2)) { + sdError(SD_CARD_ERROR_ACMD6); + goto fail; + } + m_clkDiv = sdioConfig.clkDiv(); + pioConfig(m_clkDiv); + if (!cardAcmd(m_rca, ACMD51_R1, 0)) { + sdError(SD_CARD_ERROR_ACMD51); + goto fail; + } + if (!readData(&m_scr, sizeof(m_scr))) { + DBG_MSG("readData"); + goto fail; + } + if (!cardAcmd(m_rca, ACMD13_R1, 0)) { + sdError(SD_CARD_ERROR_ACMD13); + SDIO_FAIL(); + goto fail; + } + + if (!readData(&m_sds, sizeof(m_sds))) { + SDIO_FAIL(); + goto fail; + } + m_initDone = true; + + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::cardCMD6(uint32_t arg, uint8_t* status) { + if (!cardCommand(CMD6_R1, arg)) { + sdError(SD_CARD_ERROR_CMD6); + goto fail; + } + if (!readData(status, 64)) { + SDIO_FAIL(); + goto fail; + } + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::cardCommand(CmdRsp_t cmd, uint32_t arg, void* rsp) { + uint8_t buf[6]; + uint nRsp = cmd.rsp == RSP_R0 ? 0 : cmd.rsp == RSP_R2 ? 17 : 6; + const io_ro_8* rxFifo = reinterpret_cast(&m_pio->rxf[m_sm0]); + io_wo_8* txFifo = reinterpret_cast(&m_pio->txf[m_sm0]); + pio_sm_set_enabled(m_pio, m_sm1, false); + pio_sm_init(m_pio, m_sm0, m_cmdRspOffset, &m_cmdConfig); + pio_sm_exec(m_pio, m_sm0, pio_encode_set(pio_pindirs, 1)); + *txFifo = 55; + pio_sm_exec(m_pio, m_sm0, pio_encode_out(pio_x, 8)); + *txFifo = nRsp ? 8 * nRsp - 1 : 0; + pio_sm_exec(m_pio, m_sm0, pio_encode_out(pio_y, 8)); + pio_sm_set_enabled(m_pio, m_sm0, true); + uint n = 0; + buf[n++] = (uint8_t)(cmd.idx | 0x40); + buf[n++] = (uint8_t)(arg >> 24U); + buf[n++] = (uint8_t)(arg >> 16U); + buf[n++] = (uint8_t)(arg >> 8U); + buf[n++] = (uint8_t)arg; + buf[n++] = CRC7(buf, 5); + *txFifo = 0XFF; + for (uint i = 0; i < n; i++) { + while (pio_sm_is_tx_fifo_full(m_pio, m_sm0)) { + } + *txFifo = buf[i]; + } + + Timeout timeout(SD_CMD_TIMEOUT); + if (!nRsp) { + uint32_t fdebug_tx_stall = 1u << (PIO_FDEBUG_TXSTALL_LSB + m_sm0); + m_pio->fdebug = fdebug_tx_stall; + while (!(m_pio->fdebug & fdebug_tx_stall)) { + if (timeout.timedOut()) { + goto fail; + } + } + goto done; + } + uint8_t rtn[20]; + + for (uint i = 0; i < nRsp; i++) { + while (pio_sm_is_rx_fifo_empty(m_pio, m_sm0)) { + if (timeout.timedOut()) { + goto fail; + } + } + rtn[i] = *rxFifo; + } + if (cmd.rsp == RSP_R3) { + if (rtn[0] != 0X3F || rtn[5] != 0XFF) { + goto fail; + } + } else { + uint8_t crc; + if (cmd.rsp == RSP_R2) { + crc = CRC7(rtn + 1, nRsp - 2); + } else { + crc = CRC7(rtn, nRsp - 1); + } + if (rtn[nRsp - 1] != crc) { +#if USE_DEBUG_MODE + Serial.printf("CHK: %02X, CRC: %02X\n", rtn[nRsp - 1], crc); + for (uint i = 0; i < nRsp; i++) { + Serial.printf(" %02X", rtn[i]); + } + Serial.println(); +#endif // USE_DEBUG_MODE + sdError(SD_CARD_ERROR_READ_CRC); + goto fail; + } + } + if (nRsp == 6) { + m_cardRsp = (rtn[1] << 24) | (rtn[2] << 16) | (rtn[3] << 8) | rtn[4]; + if (rsp) { + *reinterpret_cast(rsp) = m_cardRsp; + } + } else if (rsp && nRsp == 17) { + memcpy(rsp, rtn + 1, 16); + } + +done: + pio_sm_set_enabled(m_pio, m_sm0, false); + return true; + +fail: +#if USE_DEBUG_MODE + DBG_MSG("CMD", cmd.idx, " failed"); +#endif // USE_DEBUG_MODE + pio_sm_set_enabled(m_pio, m_sm0, false); + return false; +} +//------------------------------------------------------------------------------ +void PioSdioCard::end() { pioEnd(); } +//------------------------------------------------------------------------------ +void PioSdioCard::neverReset() { + if (!m_pio) { + return; + } + if (m_sm0 >= 0) { + rp2pio_statemachine_never_reset(m_pio, m_sm0); + } + if (m_sm1 >= 0) { + rp2pio_statemachine_never_reset(m_pio, m_sm1); + } +} +//------------------------------------------------------------------------------ +bool PioSdioCard::erase(uint32_t firstSector, uint32_t lastSector) { + Timeout timeout(SD_ERASE_TIMEOUT); + if (!syncDevice()) { + SDIO_FAIL(); + goto fail; + } + // check for single sector erase + if (!m_csd.eraseSingleBlock()) { + // erase size mask + uint8_t m = m_csd.eraseSize() - 1; + if ((firstSector & m) != 0 || ((lastSector + 1) & m) != 0) { + // error card can't erase specified area + sdError(SD_CARD_ERROR_ERASE_SINGLE_SECTOR); + goto fail; + } + } + if (!m_highCapacity) { + firstSector <<= 9; + lastSector <<= 9; + } + if (!cardCommand(CMD32_R1, firstSector)) { + sdError(SD_CARD_ERROR_CMD32); + goto fail; + } + if (!cardCommand(CMD33_R1, lastSector)) { + sdError(SD_CARD_ERROR_CMD33); + goto fail; + } + if (!cardCommand(CMD38_R1, 0)) { + sdError(SD_CARD_ERROR_CMD38); + goto fail; + } + while (isBusy()) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_ERASE_TIMEOUT); + goto fail; + } + } + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +uint8_t PioSdioCard::errorCode() const { return m_errorCode; } +//------------------------------------------------------------------------------ +uint32_t PioSdioCard::errorData() const { return m_cardRsp; } +//------------------------------------------------------------------------------ +uint32_t PioSdioCard::errorLine() const { return m_errorLine; } +//------------------------------------------------------------------------------ +bool PioSdioCard::isBusy() { + return gpio_get(m_dat0Pin) ? false : !(status() & CARD_STATUS_READY_FOR_DATA); +} +//------------------------------------------------------------------------------ +void PioSdioCard::pioConfig(float clkDiv) { + m_cmdConfig = + pio_cmd_rsp_program_config(m_cmdRspOffset, m_cmdPin, m_clkPin, clkDiv); + m_rdClkConfig = + pio_rd_clk_program_config(m_rdClkOffset, m_dat0Pin, m_clkPin, clkDiv); + m_rdDataConfig = + pio_rd_data_program_config(m_rdDataOffset, m_dat0Pin, clkDiv); + m_wrDataConfig = + pio_wr_data_program_config(m_wrDataOffset, m_dat0Pin, m_clkPin, clkDiv); + m_wrRespConfig = + pio_wr_resp_program_config(m_wrRespOffset, m_dat0Pin, m_clkPin, clkDiv); +} +//------------------------------------------------------------------------------ +void PioSdioCard::pioEnd() { + if (!m_pio) { + return; + } + // CIRCUITPY-CHANGE: release only the two state machines we claimed (see + // pioInit) rather than every SM on the block, and clear their rp2pio + // never-reset flag so a later reuse of the same SM number by rp2pio is not + // wrongly protected across a soft reset. + if (m_sm0 >= 0) { + pio_sm_set_enabled(m_pio, m_sm0, false); + rp2pio_statemachine_reset_ok(m_pio, m_sm0); + pio_sm_unclaim(m_pio, m_sm0); + m_sm0 = -1; + } + if (m_sm1 >= 0) { + pio_sm_set_enabled(m_pio, m_sm1, false); + rp2pio_statemachine_reset_ok(m_pio, m_sm1); + pio_sm_unclaim(m_pio, m_sm1); + m_sm1 = -1; + } + if (m_cmdRspOffset >= 0) { + pio_remove_program(m_pio, &cmd_rsp_program, m_cmdRspOffset); + m_cmdRspOffset = -1; + } + if (m_rdClkOffset >= 0) { + pio_remove_program(m_pio, &rd_clk_program, m_rdClkOffset); + m_rdClkOffset = -1; + } + if (m_rdDataOffset >= 0) { + pio_remove_program(m_pio, &rd_data_program, m_rdDataOffset); + m_rdDataOffset = -1; + } + if (m_wrDataOffset >= 0) { + pio_remove_program(m_pio, &wr_data_program, m_wrDataOffset); + m_wrDataOffset = -1; + } + if (m_wrRespOffset >= 0) { + pio_remove_program(m_pio, &wr_resp_program, m_wrRespOffset); + m_wrRespOffset = -1; + } + m_pio = nullptr; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::pioInit() { + uint pin[] = {m_clkPin, m_cmdPin, m_dat0Pin, + m_dat0Pin + 1, m_dat0Pin + 2, m_dat0Pin + 3}; + // CIRCUITPY-CHANGE: the PIO's gpio_base (0 or 16). input_sync_bypass bits are + // relative to this base, so it must be subtracted from the raw GPIO numbers + // below (a raw `1 << pin` is UB for pins >= 32, e.g. Fruit Jam's GPIO34-39, + // and silently becomes a no-op on Cortex-M). Declared before the first goto so + // the error paths don't bypass its initialization. + uint gpio_base = 0; + // Declared before the first goto for the same reason as gpio_base. + uint pio_index = 0; + uint16_t pio_instructions[PIO_INSTRUCTION_COUNT]; + pio_program_t pio_program = {.instructions = nullptr, + .length = PIO_INSTRUCTION_COUNT, + .origin = -1, + .pio_version = 0, +#if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 +#endif + }; + // CIRCUITPY-CHANGE: pick a PIO through CircuitPython's rp2pio allocator and + // claim only the two state machines this driver uses, rather than seizing an + // entire PIO block via the raw SDK. This lets sdioio coexist with rp2pio and + // other PIO users. The five programs total total_pio_length (31) instructions, + // so this effectively requires an empty PIO; find_pio enforces that, which in + // turn guarantees the chosen PIO has no other user whose gpio_base the + // pio_set_gpio_base() call below could disturb. + pio_index = rp2pio_statemachine_find_pio(total_pio_length, 2); + if (pio_index >= NUM_PIOS) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_pio = pio_get_instance(pio_index); + m_sm0 = pio_claim_unused_sm(m_pio, false); + m_sm1 = pio_claim_unused_sm(m_pio, false); + if (m_sm0 < 0 || m_sm1 < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } +#if PICO_PIO_USE_GPIO_BASE + if (std::max({m_clkPin, m_cmdPin, m_dat0Pin + 3}) > 31) { + if (std::min({m_clkPin, m_cmdPin, m_dat0Pin}) < 16 || + pio_set_gpio_base(m_pio, 16) != PICO_OK) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + gpio_base = 16; + } else if (pio_set_gpio_base(m_pio, 0) != PICO_OK) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } +#endif // PICO_PIO_USE_GPIO_BASE + rd_data_patch_program(&pio_program, pio_instructions, m_clkPin); + m_rdDataOffset = pio_add_program(m_pio, &pio_program); + if (m_rdDataOffset < 0) { + DBG_MSG("m_rdDataOffset: ", m_rdDataOffset); + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_cmdRspOffset = pio_add_program(m_pio, &cmd_rsp_program); + if (m_cmdRspOffset < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_rdClkOffset = pio_add_program(m_pio, &rd_clk_program); + if (m_rdClkOffset < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_wrDataOffset = pio_add_program(m_pio, &wr_data_program); + if (m_wrDataOffset < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_wrRespOffset = pio_add_program(m_pio, &wr_resp_program); + if (m_wrRespOffset < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + for (uint i = 0; i < 6U; i++) { + gpio_pull_up(pin[i]); + } + gpio_set_drive_strength(m_clkPin, GPIO_DRIVE_STRENGTH_8MA); + gpio_set_slew_rate(m_clkPin, GPIO_SLEW_RATE_FAST); + + for (uint i = 0; i < 6U; i++) { + pio_gpio_init(m_pio, pin[i]); + } + // input_sync_bypass bits are relative to the PIO's gpio_base (0 or 16), so + // subtract it. Using the raw pin numbers here is undefined for pins >= 32 + // (Fruit Jam's SD pins are GPIO34-39) and evaluates to 0 on Cortex-M, leaving + // the input synchronizers in place -- benign at the ~400 kHz init rate but a + // source of CMD/DAT mis-sampling at the 25 MHz run rate. + m_pio->input_sync_bypass |= (1u << (m_clkPin - gpio_base)) | + (1u << (m_cmdPin - gpio_base)) | (0xFu << (m_dat0Pin - gpio_base)); + if (pio_sm_set_consecutive_pindirs(m_pio, m_sm0, m_clkPin, 1, true) != + PICO_OK || + pio_sm_set_consecutive_pindirs(m_pio, m_sm0, m_cmdPin, 1, true) != + PICO_OK || + pio_sm_set_consecutive_pindirs(m_pio, m_sm0, m_dat0Pin, 4, false) != + PICO_OK) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + return true; + +fail: + pioEnd(); + return false; +} +//------------------------------------------------------------------------------ +// A few cards still need at least 74 clocks after power-up. from the spec: +// +// After 1 ms VDD stable time, host provides at least 74 clocks while keeping +// CMD high before issuing the first command. In the case of SPI mode, CS +// shall be held high during 74 clock cycles. +// +// The original April 15, 2001 spec explains the 74 clocks: +// +// The additional 10 clocks (over the 64 clocks after which the card should be +// ready for communication) is provided to eliminate power-up synchronization +// problems. +// +void PioSdioCard::powerUpClockCycles() { + // Two clk_sys per SD clock cycle. + uint32_t nWait = ceil(0.0005 * clock_get_hz(clk_sys) / SD_MAX_INIT_RATE_KHZ); + gpio_init(m_cmdPin); + gpio_set_drive_strength(m_cmdPin, GPIO_DRIVE_STRENGTH_8MA); + gpio_set_dir(m_cmdPin, true); + gpio_put(m_cmdPin, 1); + gpio_init(m_clkPin); + gpio_set_drive_strength(m_clkPin, GPIO_DRIVE_STRENGTH_8MA); + gpio_set_dir(m_clkPin, true); + + // Send 80 SD CLK cycles with CMD high. End with CLK low. + for (uint i = 0; i <= 160; i++) { + gpio_put(m_clkPin, 1 & i); + busy_wait_at_least_cycles(nWait); + } +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readCID(cid_t* cid) { + memcpy(cid, &m_cid, sizeof(cid_t)); + return true; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readCSD(csd_t* csd) { + memcpy(csd, &m_csd, sizeof(csd_t)); + return true; +} +//------------------------------------------------------------------------------ +bool __time_critical_func(PioSdioCard::readData)(void* dst, size_t count) { + uint32_t buf[128]; + uint n32 = count / 4; + uint nr = n32 + 2; + const uint mask = (1ul << m_sm0) | (1ul << m_sm1); + io_wo_8* txFifo = reinterpret_cast(&m_pio->txf[m_sm1]); + pio_sm_init(m_pio, m_sm0, m_rdDataOffset, &m_rdDataConfig); + pio_sm_init(m_pio, m_sm1, m_rdClkOffset, &m_rdClkConfig); + pio_set_sm_mask_enabled(m_pio, mask, true); + + uint nf = nr < DAT_FIFO_DEPTH ? nr : DAT_FIFO_DEPTH; + for (uint it = 0; it < nf; it++) { + *txFifo = 0XFF; + } + io_ro_32* rxFifo = reinterpret_cast(&m_pio->rxf[m_sm0]); + uint32_t* dst32 = (uint)dst & 3 ? buf : reinterpret_cast(dst); + uint64_t crc = 0; + uint64_t chk = 0; + Timeout timeout(SD_READ_TIMEOUT); + uint ir = 0; + if (nf < nr) { + uint nb = nr - nf; + while (true) { + while (pio_sm_get_rx_fifo_level(m_pio, m_sm0) < 4) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_READ_TIMEOUT); + goto fail; + } + } + uint32_t tmp = *rxFifo; + *txFifo = 0XFF; + dst32[ir++] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + tmp = *rxFifo; + *txFifo = 0XFF; + dst32[ir++] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + if (ir == nb) { + break; + } + tmp = *rxFifo; + *txFifo = 0XFF; + dst32[ir++] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + tmp = *rxFifo; + *txFifo = 0XFF; + dst32[ir++] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + } + } + for (; ir < nr; ir++) { + while (pio_sm_is_rx_fifo_empty(m_pio, m_sm0)) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_READ_TIMEOUT); + goto fail; + } + } + uint32_t tmp = *rxFifo; + if (ir < n32) { + dst32[ir] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + } else { + chk <<= 32; + chk |= tmp; + } + } + if (crc != chk) { +#if USE_DEBUG_MODE + Serial.printf("crc: %llX\r\nchk: %llX\r\n", crc, chk); +#endif // USE_DEBUG_MODE + sdError(SD_CARD_ERROR_READ_CRC); + goto fail; + } + pio_set_sm_mask_enabled(m_pio, mask, false); + if (dst32 == buf) { + memcpy(dst, buf, count); + } + return true; + +fail: + pio_set_sm_mask_enabled(m_pio, mask, false); + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readData(uint8_t* dst) { return readData(dst, 512); } +//------------------------------------------------------------------------------ +bool PioSdioCard::readOCR(uint32_t* ocr) { + *ocr = m_ocr; + return true; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readSCR(scr_t* scr) { + memcpy(scr, &m_scr, sizeof(scr_t)); + return true; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readSDS(sds_t* sds) { + memcpy(sds, &m_sds, sizeof(sds_t)); + return true; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readSector(Sector_t sector, uint8_t* dst) { + if (m_curState != READ_STATE || sector != m_curSector) { + if (!syncDevice()) { + SDIO_FAIL(); + goto fail; + } + if (!readStart(sector)) { + sdError(SD_CARD_ERROR_READ_START); + goto fail; + } + m_curSector = sector; + m_curState = READ_STATE; + } + if (!readData(dst, 512)) { + SDIO_FAIL(); + goto fail; + } + m_curSector++; + return true; + +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readSectors(Sector_t sector, uint8_t* dst, size_t ns) { + for (size_t i = 0; i < ns; i++) { + if (!readSector(sector + i, dst + i * 512UL)) { + SDIO_FAIL(); + goto fail; + } + } + return true; + +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readStart(Sector_t sector) { + uint arg = m_highCapacity ? sector : 512 * sector; + if (!cardCommand(CMD18_R1, arg)) { + sdError(SD_CARD_ERROR_CMD18); + goto fail; + } + return true; + +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readStop() { + if (!syncDevice()) { + SDIO_FAIL(); + return false; + } + return true; +} +//------------------------------------------------------------------------------ +uint32_t PioSdioCard::status() { + return cardCommand(CMD13_R1, m_rca) ? m_cardRsp : CARD_STATUS_ERROR; +} +//------------------------------------------------------------------------------ +Sector_t PioSdioCard::sectorCount() { return m_csd.capacity(); } +//------------------------------------------------------------------------------ +bool PioSdioCard::syncDevice() { + if (m_curState != IDLE_STATE) { + Timeout timeout(SD_INIT_TIMEOUT); + while (!gpio_get(m_dat0Pin)) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_CMD12); + goto fail; + } + } + if (!cardCommand(CMD12_R1, 0)) { + sdError(SD_CARD_ERROR_CMD12); + goto fail; + } + while (isBusy()) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_CMD12); + goto fail; + } + } + m_curState = IDLE_STATE; + } + return true; + +fail: + return false; +} +//------------------------------------------------------------------------------ +uint8_t PioSdioCard::type() const { + return !m_initDone ? 0 + : !m_version2 ? SD_CARD_TYPE_SD1 + : !m_highCapacity ? SD_CARD_TYPE_SD2 + : SD_CARD_TYPE_SDHC; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::writeSector(Sector_t sector, const uint8_t* src) { + return writeSectors(sector, src, 1); +} +//------------------------------------------------------------------------------ +bool PioSdioCard::writeSectors(Sector_t sector, const uint8_t* src, size_t ns) { + if (m_curState != WRITE_STATE || m_curSector != sector) { + if (!syncDevice()) { + SDIO_FAIL(); + goto fail; + } + if (!writeStart(sector)) { + sdError(SD_CARD_ERROR_WRITE_START); + goto fail; + } + m_curSector = sector; + m_curState = WRITE_STATE; + } + for (size_t i = 0; i < ns; i++, src += 512) { + if (!writeData(src)) { + sdError(SD_CARD_ERROR_WRITE_DATA); + goto fail; + } + } + m_curSector += ns; + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +bool __time_critical_func(PioSdioCard::writeData)(const uint8_t* src) { + const uint32_t* src32; + uint32_t buf[128]; + if ((uint)src & 3) { + memcpy(buf, src, 512); + src32 = (const uint32_t*)buf; + } else { + src32 = (const uint32_t*)src; + } + uint32_t tmp; + io_wo_32* txFifo = reinterpret_cast(&m_pio->txf[m_sm0]); + io_ro_32* rxFifo = reinterpret_cast(&m_pio->rxf[m_sm1]); + uint8_t rsp; + uint mask = (1ul << m_sm0) | (1ul << m_sm1); + uint64_t crc = 0; + + Timeout timeout(SD_WRITE_TIMEOUT); + while (!gpio_get(m_dat0Pin)) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_WRITE_TIMEOUT); + goto fail; + } + } + pio_sm_init(m_pio, m_sm0, m_wrDataOffset, &m_wrDataConfig); + pio_sm_init(m_pio, m_sm1, m_wrRespOffset, &m_wrRespConfig); + *txFifo = 1048; // 8 + 1024 + 16 + 1 - 1; + pio_sm_exec(m_pio, m_sm0, pio_encode_out(pio_x, 32)); + pio_sm_exec(m_pio, m_sm0, pio_encode_set(pio_pindirs, 0XF)); + *txFifo = 0xFFFFFFF0; + pio_set_sm_mask_enabled(m_pio, mask, true); + for (int i = 0; i < 128;) { + while (pio_sm_get_tx_fifo_level(m_pio, m_sm0) > 4) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_WRITE_FIFO); + goto fail; + } + } + tmp = __builtin_bswap32(src32[i++]); + crc = crc16(crc, tmp); + *txFifo = tmp; + tmp = __builtin_bswap32(src32[i++]); + crc = crc16(crc, tmp); + *txFifo = tmp; + tmp = __builtin_bswap32(src32[i++]); + crc = crc16(crc, tmp); + *txFifo = tmp; + tmp = __builtin_bswap32(src32[i++]); + crc = crc16(crc, tmp); + *txFifo = tmp; + } + while (pio_sm_get_tx_fifo_level(m_pio, m_sm0) > 5) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_WRITE_FIFO); + goto fail; + } + } + *txFifo = static_cast(crc >> 32); + *txFifo = static_cast(crc); + *txFifo = 0xFFFFFFFF; + + while (pio_sm_is_rx_fifo_empty(m_pio, m_sm1)) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_READ_FIFO); + goto fail; + } + } + rsp = *rxFifo; + if ((rsp & 0X1F) != 0b101) { +#if USE_DEBUG_MODE + Serial.printf("wr rsp: %02X\n", rsp); +#endif // USE_DEBUG_MODE + sdError(SD_CARD_ERROR_WRITE_DATA); + goto fail; + } + return true; +fail: + pio_set_sm_mask_enabled(m_pio, mask, false); + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::writeStart(Sector_t sector) { + uint arg = m_highCapacity ? sector : 512 * sector; + if (!cardCommand(CMD25_R1, arg)) { + sdError(SD_CARD_ERROR_CMD25); + goto fail; + } + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::writeStop() { + if (!syncDevice()) { + SDIO_FAIL(); + return false; + } + return true; +} +#endif // ARDUINO_ARCH_RP2040 diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h new file mode 100644 index 00000000000..bc1d39a26fb --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h @@ -0,0 +1,361 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief Classes for PIO SDIO cards. + */ +#pragma once +// CIRCUITPY-CHANGE: Upstream relies on Arduino.h (pulled in via SdFatConfig.h) +// to declare the RP2 SDK PIO types (PIO, pio_sm_config), the `uint` alias used +// by this class's members, and the SDK functions the driver calls (gpio_*, +// clock_get_hz, the pico/time helpers) plus memcpy. This vendored build trims +// that Arduino path, so include those directly here. +#include +#include "hardware/clocks.h" +#include "hardware/gpio.h" +#include "hardware/pio.h" +#include "pico/time.h" +#include "../../common/SysCall.h" +#include "../SdCardInterface.h" +#if defined(ARDUINO_ARCH_RP2040) && defined(PIN_SD_CLK) && \ + defined(PIN_SD_CMD_MOSI) && defined(PIN_SD_DAT0_MISO) && \ + defined(PIN_SD_DAT1) && defined(PIN_SD_DAT2) && defined(PIN_SD_DAT3_CS) +#define HAS_BUILTIN_PIO_SDIO +#endif +class PioSdioConfig; +/** SdioConfig type for PIO SDIO */ +typedef PioSdioConfig SdioConfig; +class PioSdioCard; +/** Sdio type for PIO SDIO */ +typedef PioSdioCard SdioCard; +// ------------------------------------------------------------------------------ +/** + * \class PioSdioConfig + * \brief SDIO card configuration. + */ +class PioSdioConfig { +public: + /** + * PioSdioConfig constructor. + * \param[in] clkPin gpio pin for SDIO CLK. + * \param[in] cmdPin gpio pin for SDIO CMD. + * \param[in] dat0Pin gpio start pin for SDIO DAT[4]. + * \param[in] clkDiv PIO clock divisor. + */ + PioSdioConfig(uint clkPin, uint cmdPin, uint dat0Pin, float clkDiv = 1.0) + : m_clkPin(clkPin), + m_cmdPin(cmdPin), + m_dat0Pin(dat0Pin), + m_clkDiv(clkDiv) { + } + /** \return gpio for SDIO CLK */ + uint clkPin() { + return m_clkPin; + } + /** \return gpio for SDIO CMD */ + uint cmdPin() { + return m_cmdPin; + } + /** \return gpio for SDIO DAT0 */ + uint dat0Pin() { + return m_dat0Pin; + } + /** \return PIO clock divisor */ + float clkDiv() { + return m_clkDiv; + } + +private: + PioSdioConfig() : m_clkPin(63u), m_cmdPin(63u), m_dat0Pin(63u), m_clkDiv(0) { + } + const uint8_t m_clkPin; + const uint8_t m_cmdPin; + const uint8_t m_dat0Pin; + const float m_clkDiv; +}; +// ------------------------------------------------------------------------------ +/** + * \class CmdRsp_t + * \brief SD command/response type. + */ +class CmdRsp_t { +public: + /** + * \param[in] idx_ Command index. + * \param[in] rsp_ Response type. + */ + CmdRsp_t(uint8_t idx_, uint8_t rsp_) : idx(idx_), rsp(rsp_) { + } + uint8_t idx; ///< Command index. + uint8_t rsp; ///< Response type. +}; +// ------------------------------------------------------------------------------ +/** + * \class PioSdioCard + * \brief Raw SDIO access to SD and SDHC flash memory cards. + */ +class PioSdioCard: public SdCardInterface { +public: + PioSdioCard() = default; // cppcheck-suppress uninitMemberVar + /** Initialize the SD card. + * \param[in] config SDIO card configuration. + * \return true for success or false for failure. + */ + bool begin(PioSdioConfig config); + /** CMD6 Switch mode: Check Function Set Function. + * \param[in] arg CMD6 argument. + * \param[out] status return status data. + * + * \return true for success or false for failure. + */ + bool cardCMD6(uint32_t arg, uint8_t *status) final; + /** Disable an SDIO card. + * not implemented. + */ + void end() final; + /** CIRCUITPY-CHANGE: mark this card's PIO state machines as surviving a soft + * reset, keeping rp2pio's never-reset bookkeeping coherent with the SMs this + * driver claims directly. */ + void neverReset(); + + #ifndef DOXYGEN_SHOULD_SKIP_THIS + uint32_t __attribute__((error("use sectorCount()"))) cardSize(); + #endif // DOXYGEN_SHOULD_SKIP_THIS + /** Erase a range of sectors. + * + * \param[in] firstSector The address of the first sector in the range. + * \param[in] lastSector The address of the last sector in the range. + * + * \note This function requests the SD card to do a flash erase for a + * range of sectors. The data on the card after an erase operation is + * either 0 or 1, depends on the card vendor. The card must support + * single sector erase. + * + * \return true for success or false for failure. + */ + bool erase(Sector_t firstSector, Sector_t lastSector) final; + /** + * \return code for the last error. See SdCardInfo.h for a list of error + * codes. + */ + uint8_t errorCode() const final; + /** \return error data for last error. */ + uint32_t errorData() const final; + /** \return error line for last error. Tmp function for debug. */ + uint32_t errorLine() const; + /** + * Check for busy with CMD13. + * + * \return true if busy else false. + */ + bool isBusy() final; + /** \return the SD clock frequency in kHz. */ + uint32_t kHzSdClk(); + /** + * Read a 512 byte sector from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSector(Sector_t sector, uint8_t *dst) final; + /** + * Read multiple 512 byte sectors from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSectors(Sector_t sector, uint8_t *dst, size_t ns) final; + /** + * Read a card's CID register. The CID contains card identification + * information such as Manufacturer ID, Product name, Product serial + * number and Manufacturing date. + * + * \param[out] cid pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCID(cid_t *cid) final; + /** + * Read a card's CSD register. The CSD contains Card-Specific Data that + * provides information regarding access to the card's contents. + * + * \param[out] csd pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCSD(csd_t *csd) final; + /** Read one data sector in a multiple sector read sequence + * + * \param[out] dst Pointer to the location for the data to be read. + * + * \return true for success or false for failure. + */ + bool readData(uint8_t *dst); + /** Read OCR register. + * + * \param[out] ocr Value of OCR register. + * \return true for success or false for failure. + */ + bool readOCR(uint32_t *ocr) final; + /** Read SCR register. + * + * \param[out] scr Value of SCR register. + * \return true for success or false for failure. + */ + bool readSCR(scr_t *scr) final; + /** Return the 64 byte SD Status register. + * \param[out] sds location for 64 status bytes. + * \return true for success or false for failure. + */ + bool readSDS(sds_t *sds) final; + /** Start a read multiple sectors sequence. + * + * \param[in] sector Address of first sector in sequence. + * + * \note This function is used with readData() and readStop() for optimized + * multiple sector reads. + * + * \return true for success or false for failure. + */ + bool readStart(Sector_t sector); + /** End a read multiple sectors sequence. + * + * \return true for success or false for failure. + */ + bool readStop(); + /** \return SDIO card status. */ + uint32_t status() final; + /** + * Determine the size of an SD flash memory card. + * + * \return The number of 512 byte data sectors in the card + * or zero if an error occurs. + */ + Sector_t sectorCount() final; + /** + * Send CMD12 to stop read or write. + * + * \param[in] blocking If true, wait for command complete. + * + * \return true for success or false for failure. + */ + bool stopTransmission(bool blocking); + /** \return success if sync successful. Not for user apps. */ + bool syncDevice() final; + /** Return the card type: SD V1, SD V2 or SDHC + * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. + */ + uint8_t type() const final; + /** + * Writes a 512 byte sector to an SD card. + * + * \param[in] sector Logical sector to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeSector(Sector_t sector, const uint8_t *src) final; + /** + * Write multiple 512 byte sectors to an SD card. + * + * \param[in] sector Logical sector to be written. + * \param[in] ns Number of sectors to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeSectors(Sector_t sector, const uint8_t *src, size_t ns) final; + /** Write one data sector in a multiple sector write sequence. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeData(const uint8_t *src); + /** Start a write multiple sectors sequence. + * + * \param[in] sector Address of first sector in sequence. + * + * \note This function is used with writeData() and writeStop() + * for optimized multiple sector writes. + * + * \return true for success or false for failure. + */ + bool writeStart(Sector_t sector); + + /** End a write multiple sectors sequence. + * + * \return true for success or false for failure. + */ + bool writeStop(); + +private: + // ---------------------------------------------------------------------------- + bool cardAcmd(uint32_t rca, CmdRsp_t cmdRsp, uint32_t arg); + bool cardCommand(CmdRsp_t cmd, uint32_t arg, void *rsp = nullptr); + void pioConfig(float clkDiv); + void pioEnd(); + bool pioInit(); + void powerUpClockCycles(); + bool readData(void *dst, size_t count); + void setSdErrorCode(uint8_t code, uint32_t line) { + m_errorCode = code; + m_errorLine = line; + } + static const uint8_t IDLE_STATE = 0; + static const uint8_t READ_STATE = 1; + static const uint8_t WRITE_STATE = 2; + Sector_t m_curSector = 0; + uint8_t m_curState = IDLE_STATE; + uint m_cardRsp; + uint m_errorCode; + uint m_errorLine; + bool m_highCapacity; + bool m_initDone = false; + uint m_ocr; + bool m_version2; + uint m_rca; + cid_t m_cid; + csd_t m_csd; + scr_t m_scr; + sds_t m_sds; + + float m_clkDiv = 0; + uint m_clkPin = 63u; // PIN_SDIO_UNDEFINED; + uint m_cmdPin = 63u; // PIN_SDIO_UNDEFINED; + uint m_dat0Pin = 63u; // PIN_SDIO_UNDEFINED; + PIO m_pio = nullptr; + int m_sm0 = -1; + int m_sm1 = -1; + int m_cmdRspOffset = -1; + pio_sm_config m_cmdConfig; + int m_rdDataOffset = -1; + pio_sm_config m_rdDataConfig; + int m_rdClkOffset = -1; + pio_sm_config m_rdClkConfig; + int m_wrDataOffset = -1; + pio_sm_config m_wrDataConfig; + int m_wrRespOffset = -1; + pio_sm_config m_wrRespConfig; +}; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.pio.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.pio.h new file mode 100644 index 00000000000..3130fd4edc0 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.pio.h @@ -0,0 +1,331 @@ +/** +* Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +// -------------------------------------------------- // +// This file is autogenerated by pioasm; do not edit! // +// -------------------------------------------------- // + +#pragma once + +#if !PICO_NO_HARDWARE +#include "hardware/pio.h" +#endif + +#define SDIO_IRQ 7 + +// ------- // +// cmd_rsp // +// ------- // + +#define cmd_rsp_wrap_target 0 +#define cmd_rsp_wrap 9 +#define cmd_rsp_pio_version 0 + +static const uint16_t cmd_rsp_program_instructions[] = { + // .wrap_target + 0x7101, // 0: out pins, 1 side 0 [1] + 0x1940, // 1: jmp x--, 0 side 1 [1] + 0x1160, // 2: jmp !y, 0 side 0 [1] + 0xfb80, // 3: set pindirs, 0 side 1 [3] + 0xb342, // 4: nop side 0 [3] + 0xba42, // 5: nop side 1 [2] + 0x00c4, // 6: jmp pin, 4 + 0x4001, // 7: in pins, 1 + 0x9260, // 8: push iffull block side 0 [2] + 0x1987, // 9: jmp y--, 7 side 1 [1] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program cmd_rsp_program = { + .instructions = cmd_rsp_program_instructions, + .length = 10, + .origin = -1, + .pio_version = cmd_rsp_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config cmd_rsp_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + cmd_rsp_wrap_target, offset + cmd_rsp_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} + +static inline pio_sm_config pio_cmd_rsp_program_config(uint offset, uint cmd_pin, uint clk_pin, float clk_div) { + pio_sm_config c = cmd_rsp_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, clk_pin); + sm_config_set_out_pins(&c, cmd_pin, 1); + sm_config_set_in_pins(&c, cmd_pin); + sm_config_set_set_pins(&c, cmd_pin, 1); + sm_config_set_jmp_pin(&c, cmd_pin); + sm_config_set_in_shift(&c, false, false, 8); + sm_config_set_out_shift(&c, false, true, 8); + sm_config_set_clkdiv(&c, clk_div); + return c; +} + +#endif + +// ------ // +// rd_clk // +// ------ // + +#define rd_clk_wrap_target 3 +#define rd_clk_wrap 4 +#define rd_clk_pio_version 0 + +static const uint16_t rd_clk_program_instructions[] = { + 0xb342, // 0: nop side 0 [3] + 0x1bc0, // 1: jmp pin, 0 side 1 [3] + 0xc007, // 2: irq nowait 7 + // .wrap_target + 0x7261, // 3: out null, 1 side 0 [2] + 0xb942, // 4: nop side 1 [1] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program rd_clk_program = { + .instructions = rd_clk_program_instructions, + .length = 5, + .origin = -1, + .pio_version = rd_clk_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config rd_clk_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + rd_clk_wrap_target, offset + rd_clk_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} + +static inline pio_sm_config pio_rd_clk_program_config(uint offset, uint d0_pin, uint clk_pin, float clk_div) { + pio_sm_config c = rd_clk_program_get_default_config(offset); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + sm_config_set_sideset_pins(&c, clk_pin); + sm_config_set_in_pins(&c, d0_pin); + sm_config_set_jmp_pin(&c, d0_pin); + sm_config_set_out_shift(&c, false, true, 8); + sm_config_set_clkdiv(&c, clk_div); + return c; +} + +#endif + +// ------- // +// rd_data // +// ------- // + +#define rd_data_wrap_target 1 +#define rd_data_wrap 3 +#define rd_data_pio_version 0 + +#define rd_data_offset_wait0 1u +#define rd_data_offset_wait1 2u + +static const uint16_t rd_data_program_instructions[] = { + 0x20c7, // 0: wait 1 irq, 7 + // .wrap_target + 0x2000, // 1: wait 0 gpio, 0 + 0x2080, // 2: wait 1 gpio, 0 + 0x4004, // 3: in pins, 4 + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program rd_data_program = { + .instructions = rd_data_program_instructions, + .length = 4, + .origin = -1, + .pio_version = rd_data_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x1 + #endif +}; + +static inline pio_sm_config rd_data_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + rd_data_wrap_target, offset + rd_data_wrap); + return c; +} + +static inline void rd_data_patch_program(pio_program *prog, uint16_t *inst, uint clk_pin) { + *prog = rd_data_program; + prog->instructions = inst; + #if PICO_PIO_VERSION > 0 + prog->used_gpio_ranges = clk_pin < 16 ? 1 : clk_pin < 32 ? 2 : clk_pin < 48 ? 4 : 8; + #endif + memcpy(inst, rd_data_program_instructions, sizeof(rd_data_program_instructions)); + inst[rd_data_offset_wait0] = pio_encode_wait_gpio(0, clk_pin); + inst[rd_data_offset_wait1] = pio_encode_wait_gpio(1, clk_pin); +} +static inline pio_sm_config pio_rd_data_program_config(uint offset, uint data_pin, float clk_div) { + pio_sm_config c = rd_data_program_get_default_config(offset); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + sm_config_set_in_pins(&c, data_pin); + sm_config_set_in_shift(&c, false, true, 32); + sm_config_set_clkdiv(&c, clk_div); + return c; +} + +#endif + +// ------- // +// wr_data // +// ------- // + +#define wr_data_wrap_target 3 +#define wr_data_wrap 3 +#define wr_data_pio_version 0 + +static const uint16_t wr_data_program_instructions[] = { + 0x7104, // 0: out pins, 4 side 0 [1] + 0x1940, // 1: jmp x--, 0 side 1 [1] + 0xc007, // 2: irq nowait 7 + // .wrap_target + 0xa042, // 3: nop + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program wr_data_program = { + .instructions = wr_data_program_instructions, + .length = 4, + .origin = -1, + .pio_version = wr_data_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config wr_data_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + wr_data_wrap_target, offset + wr_data_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} + +static inline pio_sm_config pio_wr_data_program_config(uint offset, uint data_pin, uint clk_pin, float clk_div) { + pio_sm_config c = wr_data_program_get_default_config(offset); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + sm_config_set_sideset_pins(&c, clk_pin); + sm_config_set_out_pins(&c, data_pin, 4); + sm_config_set_set_pins(&c, data_pin, 4); + sm_config_set_out_shift(&c, false, true, 32); + sm_config_set_clkdiv(&c, clk_div); + return c; +} + +#endif + +// ------- // +// wr_resp // +// ------- // + +#define wr_resp_wrap_target 2 +#define wr_resp_wrap 3 +#define wr_resp_pio_version 0 + +static const uint16_t wr_resp_program_instructions[] = { + 0x20c7, // 0: wait 1 irq, 7 + 0xe180, // 1: set pindirs, 0 [1] + // .wrap_target + 0x5c01, // 2: in pins, 1 side 1 [4] + 0x9440, // 3: push iffull noblock side 0 [4] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program wr_resp_program = { + .instructions = wr_resp_program_instructions, + .length = 4, + .origin = -1, + .pio_version = wr_resp_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config wr_resp_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + wr_resp_wrap_target, offset + wr_resp_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} + +static inline pio_sm_config pio_wr_resp_program_config(uint offset, uint data_pin, uint clk_pin, float clk_div) { + pio_sm_config c = wr_resp_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, clk_pin); + sm_config_set_in_pins(&c, data_pin); + sm_config_set_set_pins(&c, data_pin, 4); + sm_config_set_in_shift(&c, false, false, 8); + sm_config_set_clkdiv(&c, clk_div); + return c; +} +static const size_t total_pio_length = + cmd_rsp_program.length + rd_data_program.length + rd_clk_program.length + + wr_data_program.length + wr_resp_program.length; + +#endif + +// -------- // +// fill_pio // +// -------- // + +#define fill_pio_wrap_target 0 +#define fill_pio_wrap 3 +#define fill_pio_pio_version 0 + +static const uint16_t fill_pio_program_instructions[] = { + // .wrap_target + 0x0000, // 0: jmp 0 + 0x0001, // 1: jmp 1 + 0x0002, // 2: jmp 2 + 0x0003, // 3: jmp 3 + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program fill_pio_program = { + .instructions = fill_pio_program_instructions, + .length = 4, + .origin = -1, + .pio_version = fill_pio_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config fill_pio_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + fill_pio_wrap_target, offset + fill_pio_wrap); + return c; +} +#endif diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInfo.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInfo.h new file mode 100644 index 00000000000..c84f9778725 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInfo.h @@ -0,0 +1,530 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief Definitions for SD cards. + */ +#pragma once +#include + +#include "../common/SysCall.h" +// Based on the document: +// +// SD Specifications +// Part 1 +// Physical Layer +// Simplified Specification +// Version 8.00 +// Sep 23, 2020 +// +// https://www.sdcard.org/downloads/pls/ +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ +// SD registers are big endian. +#error bit fields in structures assume little endian processor. +#endif // __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ +// ------------------------------------------------------------------------------ +// SD card errors +// See the SD Specification for command info. +/** Define error codes and brief description. */ +#define SD_ERROR_CODE_LIST \ + SD_CARD_ERROR(NONE, "No error") \ + SD_CARD_ERROR(CMD0, "Card reset failed") \ + SD_CARD_ERROR(CMD2, "SDIO read CID") \ + SD_CARD_ERROR(CMD3, "SDIO publish RCA") \ + SD_CARD_ERROR(CMD6, "Switch card function") \ + SD_CARD_ERROR(CMD7, "SDIO card select") \ + SD_CARD_ERROR(CMD8, "Send and check interface settings") \ + SD_CARD_ERROR(CMD9, "Read CSD data") \ + SD_CARD_ERROR(CMD10, "Read CID data") \ + SD_CARD_ERROR(CMD12, "Stop multiple block transmission") \ + SD_CARD_ERROR(CMD13, "Read card status") \ + SD_CARD_ERROR(CMD17, "Read single block") \ + SD_CARD_ERROR(CMD18, "Read multiple blocks") \ + SD_CARD_ERROR(CMD24, "Write single block") \ + SD_CARD_ERROR(CMD25, "Write multiple blocks") \ + SD_CARD_ERROR(CMD32, "Set first erase block") \ + SD_CARD_ERROR(CMD33, "Set last erase block") \ + SD_CARD_ERROR(CMD38, "Erase selected blocks") \ + SD_CARD_ERROR(CMD58, "Read OCR register") \ + SD_CARD_ERROR(CMD59, "Set CRC mode") \ + SD_CARD_ERROR(ACMD6, "Set SDIO bus width") \ + SD_CARD_ERROR(ACMD13, "Read extended status") \ + SD_CARD_ERROR(ACMD23, "Set pre-erased count") \ + SD_CARD_ERROR(ACMD41, "Activate card initialization") \ + SD_CARD_ERROR(ACMD51, "Read SCR data") \ + SD_CARD_ERROR(READ_TOKEN, "Bad read data token") \ + SD_CARD_ERROR(READ_CRC, "Read CRC error") \ + SD_CARD_ERROR(READ_FIFO, "SDIO fifo read timeout") \ + SD_CARD_ERROR(READ_REG, "Read CID or CSD failed.") \ + SD_CARD_ERROR(READ_START, "Bad readStart argument") \ + SD_CARD_ERROR(READ_TIMEOUT, "Read data timeout") \ + SD_CARD_ERROR(STOP_TRAN, "Multiple block stop failed") \ + SD_CARD_ERROR(TRANSFER_COMPLETE, "SDIO transfer complete") \ + SD_CARD_ERROR(WRITE_DATA, "Write data not accepted") \ + SD_CARD_ERROR(WRITE_FIFO, "SDIO fifo write timeout") \ + SD_CARD_ERROR(WRITE_START, "Bad writeStart argument") \ + SD_CARD_ERROR(WRITE_PROGRAMMING, "Flash programming") \ + SD_CARD_ERROR(WRITE_TIMEOUT, "Write timeout") \ + SD_CARD_ERROR(DMA, "DMA transfer failed") \ + SD_CARD_ERROR(ERASE, "Card did not accept erase commands") \ + SD_CARD_ERROR(ERASE_SINGLE_SECTOR, "Card does not support erase") \ + SD_CARD_ERROR(ERASE_TIMEOUT, "Erase command timeout") \ + SD_CARD_ERROR(INIT_NOT_CALLED, "Card has not been initialized") \ + SD_CARD_ERROR(ADD_PIO_PROGRAM, "Add PIO program") \ + SD_CARD_ERROR(INVALID_CARD_CONFIG, "Invalid card config") \ + SD_CARD_ERROR(FUNCTION_NOT_SUPPORTED, "Unsupported SDIO command") + +enum { +/** Macro for generation of error codes using an enum. */ +#define SD_CARD_ERROR(e, m) SD_CARD_ERROR_##e, + SD_ERROR_CODE_LIST +#undef SD_CARD_ERROR + SD_CARD_ERROR_UNKNOWN +}; +/** Print the enum symbol for an error code. + * \param[in] pr Print stream. + * \param[in] code enum value for error. + */ +void printSdErrorSymbol(print_t *pr, uint8_t code); +/** Print text for an error code. + * \param[in] pr Print stream. + * \param[in] code enum value for error. + */ +void printSdErrorText(print_t *pr, uint8_t code); +// ------------------------------------------------------------------------------ +// card types +/** Standard capacity V1 SD card */ +const uint8_t SD_CARD_TYPE_SD1 = 1; +/** Standard capacity V2 SD card */ +const uint8_t SD_CARD_TYPE_SD2 = 2; +/** High Capacity SD card */ +const uint8_t SD_CARD_TYPE_SDHC = 3; +// ------------------------------------------------------------------------------ +// SD operation timeouts +/** command timeout ms */ +const uint16_t SD_CMD_TIMEOUT = 300; +/** erase timeout ms */ +const uint16_t SD_ERASE_TIMEOUT = 10000; +/** init timeout ms */ +const uint16_t SD_INIT_TIMEOUT = 2000; +/** read timeout ms */ +const uint16_t SD_READ_TIMEOUT = 300; +/** write time out ms */ +const uint16_t SD_WRITE_TIMEOUT = 600; +// ------------------------------------------------------------------------------ +// SD card commands +/** GO_IDLE_STATE - init card in spi mode if CS low */ +const uint8_t CMD0 = 0X00; +/** ALL_SEND_CID - Asks any card to send the CID. */ +const uint8_t CMD2 = 0X02; +/** SEND_RELATIVE_ADDR - Ask the card to publish a new RCA. */ +const uint8_t CMD3 = 0X03; +/** SWITCH_FUNC - Switch Function Command */ +const uint8_t CMD6 = 0X06; +/** SELECT/DESELECT_CARD - toggles between the stand-by and transfer states. */ +const uint8_t CMD7 = 0X07; +/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/ +const uint8_t CMD8 = 0X08; +/** SEND_CSD - read the Card Specific Data (CSD register) */ +const uint8_t CMD9 = 0X09; +/** SEND_CID - read the card identification information (CID register) */ +const uint8_t CMD10 = 0X0A; +/** VOLTAGE_SWITCH -Switch to 1.8V bus signaling level. */ +const uint8_t CMD11 = 0X0B; +/** STOP_TRANSMISSION - end multiple sector read sequence */ +const uint8_t CMD12 = 0X0C; +/** SEND_STATUS - read the card status register */ +const uint8_t CMD13 = 0X0D; +/** READ_SINGLE_SECTOR - read a single data sector from the card */ +const uint8_t CMD17 = 0X11; +/** READ_MULTIPLE_SECTOR - read multiple data sectors from the card */ +const uint8_t CMD18 = 0X12; +/** WRITE_SECTOR - write a single data sector to the card */ +const uint8_t CMD24 = 0X18; +/** WRITE_MULTIPLE_SECTOR - write sectors of data until a STOP_TRANSMISSION */ +const uint8_t CMD25 = 0X19; +/** ERASE_WR_BLK_START - sets the address of the first sector to be erased */ +const uint8_t CMD32 = 0X20; +/** ERASE_WR_BLK_END - sets the address of the last sector of the continuous + range to be erased*/ +const uint8_t CMD33 = 0X21; +/** ERASE - erase all previously selected sectors */ +const uint8_t CMD38 = 0X26; +/** APP_CMD - escape for application specific command */ +const uint8_t CMD55 = 0X37; +/** READ_OCR - read the OCR register of a card */ +const uint8_t CMD58 = 0X3A; +/** CRC_ON_OFF - enable or disable CRC checking */ +const uint8_t CMD59 = 0X3B; +/** SET_BUS_WIDTH - Defines the data bus width for data transfer. */ +const uint8_t ACMD6 = 0X06; +/** SD_STATUS - Send the SD Status. */ +const uint8_t ACMD13 = 0X0D; +/** SET_WR_BLK_ERASE_COUNT - Set the number of write sectors to be + pre-erased before writing */ +const uint8_t ACMD23 = 0X17; +/** SD_SEND_OP_COMD - Sends host capacity support information and + activates the card's initialization process */ +const uint8_t ACMD41 = 0X29; +/** Reads the SD Configuration Register (SCR). */ +const uint8_t ACMD51 = 0X33; +// ============================================================================== +// CARD_STATUS +/** The command's argument was out of the allowed range for this card. */ +const uint32_t CARD_STATUS_OUT_OF_RANGE = 1UL << 31; +/** A misaligned address which did not match the sector length. */ +const uint32_t CARD_STATUS_ADDRESS_ERROR = 1UL << 30; +/** The transferred sector length is not allowed for this card. */ +const uint32_t CARD_STATUS_SECTOR_LEN_ERROR = 1UL << 29; +/** An error in the sequence of erase commands occurred. */ +const uint32_t CARD_STATUS_ERASE_SEQ_ERROR = 1UL << 28; +/** An invalid selection of write-sectors for erase occurred. */ +const uint32_t CARD_STATUS_ERASE_PARAM = 1UL << 27; +/** Set when the host attempts to write to a protected sector. */ +const uint32_t CARD_STATUS_WP_VIOLATION = 1UL << 26; +/** When set, signals that the card is locked by the host. */ +const uint32_t CARD_STATUS_CARD_IS_LOCKED = 1UL << 25; +/** Set when a sequence or password error has been detected. */ +const uint32_t CARD_STATUS_LOCK_UNLOCK_FAILED = 1UL << 24; +/** The CRC check of the previous command failed. */ +const uint32_t CARD_STATUS_COM_CRC_ERROR = 1UL << 23; +/** Command not legal for the card state. */ +const uint32_t CARD_STATUS_ILLEGAL_COMMAND = 1UL << 22; +/** Card internal ECC was applied but failed to correct the data. */ +const uint32_t CARD_STATUS_CARD_ECC_FAILED = 1UL << 21; +/** Internal card controller error */ +const uint32_t CARD_STATUS_CC_ERROR = 1UL << 20; +/** A general or an unknown error occurred during the operation. */ +const uint32_t CARD_STATUS_ERROR = 1UL << 19; +// bits 19, 18, and 17 reserved. +/** Permanent WP set or attempt to change read only values of CSD. */ +const uint32_t CARD_STATUS_CSD_OVERWRITE = 1UL << 16; +/** partial address space was erased due to write protect. */ +const uint32_t CARD_STATUS_WP_ERASE_SKIP = 1UL << 15; +/** The command has been executed without using the internal ECC. */ +const uint32_t CARD_STATUS_CARD_ECC_DISABLED = 1UL << 14; +/** out of erase sequence command was received. */ +const uint32_t CARD_STATUS_ERASE_RESET = 1UL << 13; +/** The state of the card when receiving the command. + * 0 = idle + * 1 = ready + * 2 = ident + * 3 = stby + * 4 = tran + * 5 = data + * 6 = rcv + * 7 = prg + * 8 = dis + * 9-14 = reserved + * 15 = reserved for I/O mode + */ +const uint32_t CARD_STATUS_CURRENT_STATE = 0XF << 9; +/** Shift for current state. */ +const uint32_t CARD_STATUS_CURRENT_STATE_SHIFT = 9; +/** Corresponds to buffer empty signaling on the bus. */ +const uint32_t CARD_STATUS_READY_FOR_DATA = 1UL << 8; +// bit 7 reserved. +/** Extension Functions may set this bit to get host to deal with events. */ +const uint32_t CARD_STATUS_FX_EVENT = 1UL << 6; +/** The card will expect ACMD, or the command has been interpreted as ACMD */ +const uint32_t CARD_STATUS_APP_CMD = 1UL << 5; +// bit 4 reserved. +/** Error in the sequence of the authentication process. */ +const uint32_t CARD_STATUS_AKE_SEQ_ERROR = 1UL << 3; +// bits 2,1, and 0 reserved for manufacturer test mode. +// ============================================================================== +/** status for card in the ready state */ +const uint8_t R1_READY_STATE = 0X00; +/** status for card in the idle state */ +const uint8_t R1_IDLE_STATE = 0X01; +/** status bit for illegal command */ +const uint8_t R1_ILLEGAL_COMMAND = 0X04; +/** start data token for read or write single sector*/ +const uint8_t DATA_START_SECTOR = 0XFE; +/** stop token for write multiple sectors*/ +const uint8_t STOP_TRAN_TOKEN = 0XFD; +/** start data token for write multiple sectors*/ +const uint8_t WRITE_MULTIPLE_TOKEN = 0XFC; +/** mask for data response tokens after a write sector operation */ +const uint8_t DATA_RES_MASK = 0X1F; +/** write data accepted token */ +const uint8_t DATA_RES_ACCEPTED = 0X05; +// ============================================================================== +/** + * \class cid_t + * \brief Card Identification (CID) register. + */ +struct cid_t { + // byte 0 + /** Manufacturer ID */ + uint8_t mid; + // byte 1-2 + /** OEM/Application ID. */ + char oid[2]; + // byte 3-7 + /** Product name. */ + char pnm[5]; + // byte 8 + /** Product revision - n.m two 4-bit nibbles. */ + uint8_t prv; + // byte 9-12 + /** Product serial 32-bit number Big Endian format. */ + uint8_t psn8[4]; + // byte 13-14 + /** Manufacturing date big endian - four nibbles RYYM Reserved Year Month. */ + uint8_t mdt[2]; + // byte 15 + /** CRC7 bits 1-7 checksum, bit 0 always 1 */ + uint8_t crc; + // Extract big endian fields. + /** \return major revision number. */ + int prvN() const { + return prv >> 4; + } + /** \return minor revision number. */ + int prvM() const { + return prv & 0XF; + } + /** \return Manufacturing Year. */ + int mdtYear() const { + return 2000 + ((mdt[0] & 0XF) << 4) + (mdt[1] >> 4); + } + /** \return Manufacturing Month. */ + int mdtMonth() const { + return mdt[1] & 0XF; + } + /** \return Product Serial Number. */ + uint32_t psn() const { + return static_cast < uint32_t > (psn8[0]) << 24 | + static_cast < uint32_t > (psn8[1]) << 16 | + static_cast < uint32_t > (psn8[2]) << 8 | static_cast < uint32_t > (psn8[3]); + } +} __attribute__((packed)); +// ============================================================================== +/** + * \class csd_t + * \brief Union of old and new style CSD register. + */ +struct csd_t { + /** union of all CSD versions */ + uint8_t csd[16]; + // Extract big endian fields. + /** \return Capacity in sectors */ + uint32_t capacity() const { + uint32_t c_size; + uint8_t ver = csd[0] >> 6; + if (ver == 0) { + c_size = static_cast < uint32_t > (csd[6] & 3) << 10; + c_size |= static_cast < uint32_t > (csd[7]) << 2 | csd[8] >> 6; + uint8_t c_size_mult = (csd[9] & 3) << 1 | csd[10] >> 7; + uint8_t read_bl_len = csd[5] & 15; + return (c_size + 1) << (c_size_mult + read_bl_len + 2 - 9); + } else if (ver == 1) { + c_size = static_cast < uint32_t > (csd[7] & 63) << 16; + c_size |= static_cast < uint32_t > (csd[8]) << 8; + c_size |= csd[9]; + return (c_size + 1) << 10; + } else { + return 0; + } + } + /** \return true if erase granularity is single block. */ + bool eraseSingleBlock() const { + return csd[10] & 0X40; + } + /** \return erase size in 512 byte blocks if eraseSingleBlock is false. */ + int eraseSize() const { + return ((csd[10] & 0X3F) << 1 | csd[11] >> 7) + 1; + } + /** \return true if the contents is copied or true if original. */ + bool copy() const { + return csd[14] & 0X40; + } + /** \return true if the entire card is permanently write protected. */ + bool permWriteProtect() const { + return csd[14] & 0X20; + } + /** \return true if the entire card is temporarily write protected. */ + bool tempWriteProtect() const { + return csd[14] & 0X10; + } +}; +// ============================================================================== +/** + * \class scr_t + * \brief SCR register. + */ +struct scr_t { + /** Bytes 0-3 SD Association, bytes 4-7 reserved for manufacturer. */ + uint8_t scr[8]; + /** \return SCR_STRUCTURE field - must be zero.*/ + uint8_t srcStructure() const { + return scr[0] >> 4; + } + /** \return SD_SPEC field 0 - v1.0 or V1.01, 1 - 1.10, 2 - V2.00 or greater */ + uint8_t sdSpec() const { + return scr[0] & 0XF; + } + /** \return false if all zero, true if all one. */ + bool dataAfterErase() const { + return scr[1] & 0X80; + } + /** \return CPRM Security Version. */ + uint8_t sdSecurity() const { + return (scr[1] >> 4) & 0X7; + } + /** \return 0101b. */ + uint8_t sdBusWidths() const { + return scr[1] & 0XF; + } + /** \return true if V3.0 or greater. */ + bool sdSpec3() const { + return scr[2] & 0X80; + } + /** \return if true and sdSpecX is zero V4.xx. */ + bool sdSpec4() const { + return scr[2] & 0X4; + } + /** \return nonzero for version 5 or greater if sdSpec == 2, + sdSpec3 == true. Version is return plus four.*/ + uint8_t sdSpecX() const { + return (scr[2] & 0X3) << 2 | scr[3] >> 6; + } + /** \return bit map for support CMD58/59, CMD48/49, CMD23, and CMD20 */ + uint8_t cmdSupport() const { + return scr[3] & 0XF; + } + /** \return SD spec version */ + int16_t sdSpecVer() const { + if (sdSpec() > 2) { + return -1; + } else if (sdSpec() < 2) { + return sdSpec() ? 110 : 101; + } else if (!sdSpec3()) { + return 200; + } else if (!sdSpec4() && !sdSpecX()) { + return 300; + } + return 400 + 100 * sdSpecX(); + } +}; +// ============================================================================== +/** + * \class sds_t + * \brief SD Status. + */ +// fields are big endian +struct sds_t { + /** byte 0, bit 7-6 width, bit 5 secured mode, bits 4-0 reserved. */ + uint8_t busWidthSecureMode; + /** byte 1 reserved */ + uint8_t reserved1; + /** byte 2-3 zero for SD rd/wr memory card. */ + uint8_t sdCardType[2]; + /** byte 4-7 size of protected area big endian */ + uint8_t sizeOfProtectedArea[4]; + /** byte 8 speed class. */ + uint8_t speed; + /** byte 9 performance move */ + uint8_t performanceMove; + /** byte 10 AU size code. */ + uint8_t auSize; + /** byte 11-12 erase size big endian */ + uint8_t eraseSize[2]; + /** byte 13 erase timeout and erase offset */ + uint8_t eraseTimeoutOffset; + /** byte 14 */ + uint8_t uhsClassAuSize; + /** byte 15 */ + uint8_t videoSpeedClass; + /** byte 16-17 */ + uint8_t vscAuSize[2]; + /** byte 18-21 */ + uint8_t susAddr[3]; + /** byte 21 */ + uint8_t appPerfClass; + /** byte 22 */ + uint8_t perfEnhance; + /** byte 23 */ + uint8_t discardFule; + /** byte 24 */ + uint8_t reservedManufacturer[40]; + + /** \return appClass. */ + int appClass() { + return appPerfClass; + } + /** \return AU size in KB. or zero for error. */ + uint32_t auSizeKB() { + // 0XF mask and uint16_t array helps compiler optimize size on Uno. + uint8_t val = (auSize >> 4) & 0XF; + static const uint16_t au[] = {0, 16, 32, 64, 128, + 256, 512, 1024, 2048, 4096, + 8192, 12288, 16384, 24576, 32768}; + return val < 0XF ? au[val] : 65536UL; + } + /** \return current bus width or -1 for error. */ + uint8_t busWidth() const { + uint8_t w = busWidthSecureMode >> 6; + return w == 2 ? 4 : w == 0 ? 1 : -1; + } + /** \return true is discard operation is supported else true. */ + bool discard() const { + return discardFule & 2; + } + /** \return eraseSize in AUs. */ + uint16_t eraseSizeAU() const { + return static_cast < uint16_t > (eraseSize[0]) << 8 | + static_cast < uint16_t > (eraseSize[1]); + } + /** \return eraseTimeout seconds. */ + uint8_t eraseTimeout() const { + return eraseTimeoutOffset >> 2; + } + /** \return eraseOffset seconds. */ + uint8_t eraseOffset() const { + return eraseTimeoutOffset & 3; + } + /** \return true if full user logical erase is supported else false. */ + bool file() const { + return discardFule & 1; + } + /** \return true for secure mode else false. */ + bool secureMode() const { + return busWidthSecureMode & 0X20; + } + /** \return speed class or -1 for error. */ + int speedClass() const { + return speed < 4 ? 2 * speed : speed == 4 ? 10 : -1; + } + /** \return UHS Speed Grade. */ + int uhsClass() const { + return uhsClassAuSize >> 4; + } + /** \return Video Speed */ + int videoClass() { + return videoSpeedClass; + } +}; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h new file mode 100644 index 00000000000..5d36ae4d043 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h @@ -0,0 +1,118 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief Abstract interface for an SD card. + */ +#pragma once +#include "../common/FsBlockDeviceInterface.h" +#include "SdCardInfo.h" +/** + * \class SdCardInterface + * \brief Abstract interface for an SD card. + */ +class SdCardInterface: public FsBlockDeviceInterface { +public: + /** CMD6 Switch mode: Check Function Set Function. + * \param[in] arg CMD6 argument. + * \param[out] status return status data. + * + * \return true for success or false for failure. + */ + virtual bool cardCMD6(uint32_t arg, uint8_t *status) = 0; + /** Erase a range of sectors. + * + * \param[in] firstSector The address of the first sector in the range. + * \param[in] lastSector The address of the last sector in the range. + * + * \return true for success or false for failure. + */ + virtual bool erase(Sector_t firstSector, Sector_t lastSector) = 0; + /** \return error code. */ + virtual uint8_t errorCode() const = 0; + /** \return error data. */ + virtual uint32_t errorData() const = 0; + /** \return false by default */ + virtual bool hasDedicatedSpi() { + return false; + } + /** \return false by default */ + virtual bool isDedicatedSpi() { + return false; + } + /** \return false by default */ + virtual bool isSpi() { + return false; + } + /** Set SPI sharing state + * \param[in] value desired state. + * \return false by default. + */ + virtual bool setDedicatedSpi(bool value) { + (void)value; + return false; + } + /** + * Read a card's CID register. + * + * \param[out] cid pointer to area for returned data. + * + * \return true for success or false for failure. + */ + virtual bool readCID(cid_t *cid) = 0; + /** + * Read a card's CSD register. + * + * \param[out] csd pointer to area for returned data. + * + * \return true for success or false for failure. + */ + virtual bool readCSD(csd_t *csd) = 0; + /** Read OCR register. + * + * \param[out] ocr Value of OCR register. + * \return true for success or false for failure. + */ + virtual bool readOCR(uint32_t *ocr) = 0; + /** Read SCR register. + * + * \param[out] scr Value of SCR register. + * \return true for success or false for failure. + */ + virtual bool readSCR(scr_t *scr) = 0; + /** Return the 64 byte SD Status register. + * \param[out] sds location for 64 status bytes. + * \return true for success or false for failure. + */ + virtual bool readSDS(sds_t *sds) = 0; + /** \return card status. */ + virtual uint32_t status() { + return 0XFFFFFFFF; + } + /** Return the card type: SD V1, SD V2 or SDHC/SDXC + * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC/SDXC. + */ + virtual uint8_t type() const = 0; +}; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/FsBlockDeviceInterface.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/FsBlockDeviceInterface.h new file mode 100644 index 00000000000..f5f5b0a8b0c --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/FsBlockDeviceInterface.h @@ -0,0 +1,117 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief FsBlockDeviceInterface include file. + */ +#pragma once +#include +#include +/** + * \class FsBlockDeviceInterface + * \brief FsBlockDeviceInterface class. + */ +class FsBlockDeviceInterface { +public: + virtual ~FsBlockDeviceInterface() { + } + + /** end use of device */ + virtual void end() { + } + /** + * Check for FsBlockDevice busy. + * + * \return true if busy else false. + */ + virtual bool isBusy() = 0; + /** + * Read a sector. + * + * \param[in] sector Logical sector to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + virtual bool readSector(Sector_t sector, uint8_t *dst) = 0; + + /** + * Read multiple sectors. + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + virtual bool readSectors(Sector_t sector, uint8_t *dst, size_t ns) = 0; + + /** \return device size in sectors. */ + virtual Sector_t sectorCount() = 0; + + /** End multi-sector transfer and go to idle state. + * \return true for success or false for failure. + */ + virtual bool syncDevice() = 0; + + /** + * Writes a sector. + * + * \param[in] sector Logical sector to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + virtual bool writeSector(Sector_t sector, const uint8_t *src) = 0; + + /** + * Write multiple sectors. + * + * \param[in] sector Logical sector to be written. + * \param[in] ns Number of sectors to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + virtual bool writeSectors(Sector_t sector, const uint8_t *src, size_t ns) = 0; + + // Adafruit SdFat v1 BaseBlockDRiver API for backward-compatible + // maybe removal since v1 is deprecated now + virtual bool syncBlocks() { + return syncDevice(); + } + + virtual bool readBlock(uint32_t block, uint8_t *dst) { + return readSector(block, dst); + } + + virtual bool readBlocks(uint32_t block, uint8_t *dst, size_t nb) { + return readSectors(block, dst, nb); + } + + virtual bool writeBlock(uint32_t block, const uint8_t *src) { + return writeSector(block, src); + } + + virtual bool writeBlocks(uint32_t block, const uint8_t *src, size_t nb) { + return writeSectors(block, src, nb); + } +}; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/SysCall.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/SysCall.h new file mode 100644 index 00000000000..e8735ff2fd6 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/SysCall.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief SysCall class + * + * CircuitPython vendored, trimmed copy. The upstream SysCall.h pulls in + * SdFatConfig.h (and through it Arduino.h / avr/io.h) plus PrintBasic.h. The + * PIO SDIO card driver only needs the Sector_t typedef, nullptr handling, and + * the SD_MAX_INIT_RATE_KHZ tuning constant, so we provide just those here and + * leave the Arduino/Print machinery out of the build. + */ +#pragma once +#include +#include + +#if __cplusplus < 201103 +#warning nullptr defined +/** Define nullptr if not C++11 */ +#define nullptr NULL +#endif // __cplusplus < 201103 +// ------------------------------------------------------------------------------ +/** Type for FsBlockDevice sector */ +typedef uint32_t Sector_t; +// ------------------------------------------------------------------------------ +// SdCardInfo.h declares (but, in this vendored build, never defines) two error +// printing helpers that take a print_t*. Forward declare the type so those +// pointer-only declarations parse without dragging in PrintBasic / Arduino. +class print_t; +// ------------------------------------------------------------------------------ +// Normally supplied by SdFatConfig.h. +#ifndef SD_MAX_INIT_RATE_KHZ +#define SD_MAX_INIT_RATE_KHZ 400 +#endif // SD_MAX_INIT_RATE_KHZ diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/cxx_runtime.cpp b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/cxx_runtime.cpp new file mode 100644 index 00000000000..85a28ed8d95 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/cxx_runtime.cpp @@ -0,0 +1,33 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Minimal freestanding C++ ABI support for the vendored SdFat PIO driver. +// +// CircuitPython links the firmware with gcc and without libstdc++/libsupc++, so +// a few C++ ABI symbols that the driver's class hierarchy makes the compiler +// reference must be provided here: +// * PioSdioCard's vtable contains a deleting destructor slot that names +// `operator delete`, even though we only ever placement-new the object and +// call its destructor explicitly (so it is never actually invoked). +// * The abstract base classes (SdCardInterface / FsBlockDeviceInterface) have +// pure virtuals, so their transient vtables reference `__cxa_pure_virtual`. +// Both are effectively unreachable at run time; they exist only to satisfy the +// linker. + +#include +#include + +extern "C" void __cxa_pure_virtual(void) { + abort(); +} + +void operator delete(void *ptr) noexcept { + free(ptr); +} + +void operator delete(void *ptr, size_t) noexcept { + free(ptr); +} diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp new file mode 100644 index 00000000000..5aeea4c8e94 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp @@ -0,0 +1,80 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// C-callable shim around the vendored C++ PioSdioCard driver. This is the only +// translation unit that includes the C++ class; everything the common-hal C +// code needs is exposed through the extern "C" entry points in shim.h. + +#include + +#include "hardware/clocks.h" + +#include "SdCard/PioSdio/PioSdioCard.h" +#include "shim.h" + +static_assert(sizeof(PioSdioCard) <= SDIOIO_PIO_CARD_STORAGE_SIZE, + "SDIOIO_PIO_CARD_STORAGE_SIZE is too small for PioSdioCard"); +static_assert(alignof(PioSdioCard) <= alignof(sdioio_pio_card_storage_t), + "sdioio_pio_card_storage_t is not aligned enough for PioSdioCard"); + +extern "C" { + +void sdfat_pio_card_new(void *storage) { + new (storage) PioSdioCard(); +} + +void sdfat_pio_card_free(void *storage) { + reinterpret_cast(storage)->~PioSdioCard(); +} + +bool sdfat_pio_card_begin(void *storage, uint32_t clk_pin, uint32_t cmd_pin, + uint32_t dat0_pin, uint32_t frequency, uint32_t *actual_frequency_out) { + PioSdioCard *card = reinterpret_cast(storage); + + // The PIO driver clocks four PIO cycles per SD clock, so the resulting SD + // clock is clk_sys / (4 * clkDiv). Invert that to turn the requested rate + // into a divisor, clamped to the fastest the divisor allows (clkDiv >= 1). + float sys_hz = (float)clock_get_hz(clk_sys); + float clk_div = sys_hz / (4.0f * (float)frequency); + if (clk_div < 1.0f) { + clk_div = 1.0f; + } + + bool ok = card->begin(PioSdioConfig(clk_pin, cmd_pin, dat0_pin, clk_div)); + + if (actual_frequency_out != nullptr) { + *actual_frequency_out = (uint32_t)(sys_hz / (4.0f * clk_div)); + } + return ok; +} + +uint32_t sdfat_pio_card_sector_count(void *storage) { + return reinterpret_cast(storage)->sectorCount(); +} + +bool sdfat_pio_card_read_sectors(void *storage, uint32_t start_sector, + uint8_t *dst, size_t num_sectors) { + return reinterpret_cast(storage)->readSectors(start_sector, dst, num_sectors); +} + +bool sdfat_pio_card_write_sectors(void *storage, uint32_t start_sector, + const uint8_t *src, size_t num_sectors) { + return reinterpret_cast(storage)->writeSectors(start_sector, src, num_sectors); +} + +uint8_t sdfat_pio_card_error_code(void *storage) { + return reinterpret_cast(storage)->errorCode(); +} + +void sdfat_pio_card_end(void *storage) { + reinterpret_cast(storage)->end(); +} + +void sdfat_pio_card_never_reset(void *storage) { + reinterpret_cast(storage)->neverReset(); +} + +} // extern "C" diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h new file mode 100644 index 00000000000..c968ea0f734 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h @@ -0,0 +1,74 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// C-callable shim around the vendored C++ PioSdioCard driver. All use of the +// C++ class is confined to shim.cpp so the common-hal C sources never include +// any C++ headers. + +#pragma once + +#include +#include +#include + +// Size of the opaque storage the C object struct reserves for an in-place +// PioSdioCard instance. shim.cpp static_asserts that the real class fits. The +// real object is well under this (~320 bytes); the slack is intentional so the +// build does not break if the upstream class grows slightly. +#define SDIOIO_PIO_CARD_STORAGE_SIZE 512 + +// Opaque storage for one PioSdioCard, constructed in place by +// sdfat_pio_card_new(). The class's members are at most pointer/word aligned, so +// a pointer member is enough to align the buffer (and matches what the GC heap +// guarantees); shim.cpp static_asserts that this is sufficient. Kept as a plain +// union so the C struct needs no knowledge of the C++ type. +typedef union { + void *for_alignment; + uint8_t bytes[SDIOIO_PIO_CARD_STORAGE_SIZE]; +} sdioio_pio_card_storage_t; + +#ifdef __cplusplus +extern "C" { +#endif + +// Construct a PioSdioCard in place in the given storage buffer. +void sdfat_pio_card_new(void *storage); + +// Run the destructor for the in-place PioSdioCard. +void sdfat_pio_card_free(void *storage); + +// Initialize the card. dat0_pin is the base of four consecutive data GPIOs. +// frequency is the requested SD clock in Hz; the achieved rate is written to +// actual_frequency_out (in Hz) when it is non-NULL. Returns true on success. +bool sdfat_pio_card_begin(void *storage, uint32_t clk_pin, uint32_t cmd_pin, + uint32_t dat0_pin, uint32_t frequency, uint32_t *actual_frequency_out); + +// Number of 512-byte sectors on the card (0 if unknown). +uint32_t sdfat_pio_card_sector_count(void *storage); + +// Read `num_sectors` 512-byte sectors starting at `start_sector` into `dst`. +// Returns true on success. The driver is synchronous/polling, so this blocks. +bool sdfat_pio_card_read_sectors(void *storage, uint32_t start_sector, + uint8_t *dst, size_t num_sectors); + +// Write `num_sectors` 512-byte sectors from `src` starting at `start_sector`. +// Returns true on success. Blocks like the read path. +bool sdfat_pio_card_write_sectors(void *storage, uint32_t start_sector, + const uint8_t *src, size_t num_sectors); + +// Last error code from the driver (see SdCardInfo.h). +uint8_t sdfat_pio_card_error_code(void *storage); + +// Release the card's PIO/state-machine resources. +void sdfat_pio_card_end(void *storage); + +// Mark the card's PIO state machines as surviving a soft reset, so rp2pio's +// reset path leaves them (and their loaded programs) in place. +void sdfat_pio_card_never_reset(void *storage); + +#ifdef __cplusplus +} +#endif diff --git a/ports/raspberrypi/common-hal/socketpool/Socket.c b/ports/raspberrypi/common-hal/socketpool/Socket.c index aeab1498510..357c1162f12 100644 --- a/ports/raspberrypi/common-hal/socketpool/Socket.c +++ b/ports/raspberrypi/common-hal/socketpool/Socket.c @@ -67,8 +67,6 @@ static mp_obj_t socketpool_ip_addr_and_port_to_tuple(const ip_addr_t *addr, int return mp_obj_new_tuple(n, args); } -#define MICROPY_PY_LWIP_SOCK_RAW (1) - #if 0 // print debugging info #define DEBUG_printf DEBUG_printf #else // don't print debugging info @@ -251,7 +249,7 @@ static void _lwip_tcp_err_unaccepted(void *arg, err_t err) { // because it's only ever used by lwIP if tcp_connect is called on the TCP PCB. socketpool_socket_obj_t *socket = (socketpool_socket_obj_t *)pcb->connected; - // Array is not volatile because thiss callback is executed within the lwIP context + // Array is not volatile because this callback is executed within the lwIP context uint8_t alloc = socket->incoming.connection.alloc; struct tcp_pcb **tcp_array = (struct tcp_pcb **)lwip_socket_incoming_array(socket); @@ -1226,6 +1224,20 @@ int common_hal_socketpool_socket_setsockopt(socketpool_socket_obj_t *self, int l bool enable = optlen == sizeof(&zero) && memcmp(value, &zero, optlen); switch (level) { + case SOCKETPOOL_IPPROTO_IP: + switch (optname) { + case SOCKETPOOL_IP_MULTICAST_TTL: + if (self->type != SOCKETPOOL_SOCK_DGRAM) { + return -MP_EOPNOTSUPP; + } + if (self->pcb.udp == NULL || optlen < sizeof(uint8_t)) { + return -MP_EINVAL; + } + udp_set_multicast_ttl(self->pcb.udp, *(const uint8_t *)value); + return 0; + } + break; + case SOCKETPOOL_IPPROTO_TCP: switch (optname) { case SOCKETPOOL_TCP_NODELAY: diff --git a/ports/raspberrypi/common-hal/usb_host/Port.c b/ports/raspberrypi/common-hal/usb_host/Port.c index b8a49725030..f06e9e5d71d 100644 --- a/ports/raspberrypi/common-hal/usb_host/Port.c +++ b/ports/raspberrypi/common-hal/usb_host/Port.c @@ -13,10 +13,10 @@ #include "pico/time.h" #include "hardware/structs/mpu.h" -#ifdef PICO_RP2040 +#if PICO_RP2040 #include "RP2040.h" // (cmsis) #endif -#ifdef PICO_RP2350 +#if PICO_RP2350 #include "RP2350.h" // (cmsis) #endif #include "hardware/dma.h" @@ -34,6 +34,40 @@ usb_host_port_obj_t usb_host_instance; volatile bool _core1_ready = false; +// Core1 posts TinyUSB events while core0 may hold the queue FIFO mutex. The +// contended wait path calls best_effort_wfe_or_timeout() and time_us_64(), +// which normally live in flash, but core1 must not touch flash (see the MPU +// setup in core1_main below). These RAM-resident replacements are linked in +// with --wrap on USB host builds only (see the port Makefile). Issue #11116. +// +uint64_t __wrap_time_us_64(void); +bool __wrap_best_effort_wfe_or_timeout(absolute_time_t timeout_timestamp); + +// The same hi/lo/hi re-read loop as the SDK's timer_time_us_64, to defeat +// rollover between the two 32-bit halves. +uint64_t __not_in_flash_func(__wrap_time_us_64)(void) { + uint32_t hi = timer_hw->timerawh; + uint32_t lo; + do { + lo = timer_hw->timerawl; + uint32_t next_hi = timer_hw->timerawh; + if (hi == next_hi) { + break; + } + hi = next_hi; + } while (true); + return ((uint64_t)hi << 32) | lo; +} + +// Mirrors the SDK's own PICO_TIME_DEFAULT_ALARM_POOL_DISABLED fallback +// (a poll of the clock with no __wfe): "best effort" explicitly permits +// returning early, and every SDK caller re-checks in a loop. Polling honors +// the timeout exactly and avoids dragging the alarm pool machinery into RAM. +bool __not_in_flash_func(__wrap_best_effort_wfe_or_timeout)(absolute_time_t timeout_timestamp) { + tight_loop_contents(); + return __wrap_time_us_64() >= to_us_since_boot(timeout_timestamp); +} + static void __not_in_flash_func(core1_main)(void) { // The MPU is reset before this starts. SysTick->LOAD = (uint32_t)((common_hal_mcu_processor_get_frequency() / 1000) - 1UL); @@ -73,41 +107,19 @@ static void __not_in_flash_func(core1_main)(void) { } } -static uint8_t _sm_free_count(uint8_t pio_index) { - PIO pio = pio_get_instance(pio_index); - uint8_t free_count = 0; - for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { - if (!pio_sm_is_claimed(pio, j)) { - free_count++; - } - } - return free_count; -} - -static bool _has_program_room(uint8_t pio_index, uint8_t program_size) { - PIO pio = pio_get_instance(pio_index); - pio_program_t program_struct = { - .instructions = NULL, - .length = program_size, - .origin = -1 - }; - return pio_can_add_program(pio, &program_struct); -} - // As of 0.6.1, the PIO resource requirement is 1 PIO with 3 state machines & // 32 instructions. Since there are only 32 instructions in a state machine, it should // be impossible to have an allocated state machine but 32 instruction slots available; // go ahead and check for it anyway. // -// Since we check that ALL state machines are available, it's not possible for the GPIO +// Since we require ALL state machines to be available, it's not possible for the GPIO // ranges to mismatch on rp2350b static size_t get_usb_pio(void) { - for (size_t i = 0; i < NUM_PIOS; i++) { - if (_has_program_room(i, 32) && _sm_free_count(i) == NUM_PIO_STATE_MACHINES) { - return i; - } + size_t pio_index = rp2pio_statemachine_find_pio(32, NUM_PIO_STATE_MACHINES); + if (pio_index == NUM_PIOS) { + mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); } - mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); + return pio_index; } diff --git a/ports/raspberrypi/common-hal/wifi/Network.c b/ports/raspberrypi/common-hal/wifi/Network.c index 1cd3effbd0f..dd3e4d0f2f1 100644 --- a/ports/raspberrypi/common-hal/wifi/Network.c +++ b/ports/raspberrypi/common-hal/wifi/Network.c @@ -6,6 +6,8 @@ #include +#include "py/objlist.h" + #include "shared-bindings/wifi/Network.h" #include "shared-bindings/wifi/AuthMode.h" diff --git a/ports/raspberrypi/common-hal/wifi/Radio.c b/ports/raspberrypi/common-hal/wifi/Radio.c index 3c22c3548d1..f7f382cae79 100644 --- a/ports/raspberrypi/common-hal/wifi/Radio.c +++ b/ports/raspberrypi/common-hal/wifi/Radio.c @@ -48,7 +48,7 @@ static inline void nw_put_le32(uint8_t *buf, uint32_t x) { buf[3] = x >> 24; } -NORETURN static void ro_attribute(qstr attr) { +MP_NORETURN static void ro_attribute(qstr attr) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q is read-only for this board"), attr); } @@ -196,6 +196,9 @@ void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_ mp_raise_RuntimeError(MP_ERROR_TEXT("WiFi is not enabled")); } + // The CYW43 is 2.4 GHz only. + mp_arg_validate_int_max(channel, 13, MP_QSTR_channel); + /* TODO: If the AP is stopped once it cannot be restarted. * This means that if if the user does: * diff --git a/ports/raspberrypi/common-hal/wifi/__init__.c b/ports/raspberrypi/common-hal/wifi/__init__.c index 5fbe3fe58d1..84dba581fbf 100644 --- a/ports/raspberrypi/common-hal/wifi/__init__.c +++ b/ports/raspberrypi/common-hal/wifi/__init__.c @@ -15,6 +15,10 @@ #include "py/mpstate.h" #include "py/runtime.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + wifi_radio_obj_t common_hal_wifi_radio_obj; #include "supervisor/port.h" @@ -45,6 +49,15 @@ void common_hal_wifi_init(bool user_initiated) { // set station mode to avoid the default SoftAP common_hal_wifi_radio_start_station(self); + + #if CIRCUITPY_SETTINGS_TOML + // Must be set after station starts. + char hostname[sizeof(self->hostname)]; + if (settings_get_str("CIRCUITPY_WIFI_HOSTNAME", hostname, sizeof(hostname)) == SETTINGS_OK) { + common_hal_wifi_radio_set_hostname(self, hostname); + } + #endif + // start wifi common_hal_wifi_radio_set_enabled(self, true); } diff --git a/ports/raspberrypi/common-hal/wifi/__init__.h b/ports/raspberrypi/common-hal/wifi/__init__.h index 73988e84379..4005c48a3cd 100644 --- a/ports/raspberrypi/common-hal/wifi/__init__.h +++ b/ports/raspberrypi/common-hal/wifi/__init__.h @@ -11,7 +11,7 @@ #include "lwip/ip_addr.h" void wifi_reset(void); -NORETURN void raise_cyw_error(int err); +MP_NORETURN void raise_cyw_error(int err); #define CHECK_CYW_RESULT(x) do { int res = (x); if (res != 0) raise_cyw_error(res); } while (0) void ipaddress_ipaddress_to_lwip(mp_obj_t ip_address, ip_addr_t *lwip_ip_address); diff --git a/ports/raspberrypi/common-hal/wiznet/PIO_SPI.c b/ports/raspberrypi/common-hal/wiznet/PIO_SPI.c new file mode 100755 index 00000000000..30fe8c5d25c --- /dev/null +++ b/ports/raspberrypi/common-hal/wiznet/PIO_SPI.c @@ -0,0 +1,123 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/wiznet/PIO_SPI.h" + +#include "shared/runtime/interrupt_char.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "supervisor/board.h" +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "hardware/dma.h" +#include "hardware/gpio.h" +#include "hardware/pio.h" +#include "hardware/clocks.h" + +#include "wizchip_pio_spi.h" + +#define NO_INSTANCE 0xff + +#ifndef PIO_SPI_PREFERRED_PIO +#define PIO_SPI_PREFERRED_PIO 1 +#endif + +// All wiznet spi operations must start with writing a 3 byte header + +wiznet_pio_spi_config_t wiznet_pio_spi_config; +wiznet_pio_spi_handle_t wiznet_pio_spi_handle = NULL; + +void common_hal_wiznet_pio_spi_construct(wiznet_pio_spi_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *miso, bool half_duplex) { + + if (half_duplex) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); + } + + wiznet_pio_spi_config.data_in_pin = miso->number; + wiznet_pio_spi_config.data_out_pin = mosi->number; + wiznet_pio_spi_config.clock_pin = clock->number; + + if (wiznet_pio_spi_handle != NULL) { + wiznet_pio_spi_close(wiznet_pio_spi_handle); + } + + wiznet_pio_spi_handle = wiznet_pio_spi_open(&wiznet_pio_spi_config); + (*wiznet_pio_spi_handle)->set_active(wiznet_pio_spi_handle); + +} + +bool common_hal_wiznet_pio_spi_deinited(wiznet_pio_spi_obj_t *self) { + return wiznet_pio_spi_config.clock_pin == 0; +} + +void common_hal_wiznet_pio_spi_deinit(wiznet_pio_spi_obj_t *self) { + if (common_hal_wiznet_pio_spi_deinited(self)) { + return; + } + + common_hal_reset_pin(self->clock); + common_hal_reset_pin(self->MOSI); + common_hal_reset_pin(self->MISO); + + wiznet_pio_spi_config.clock_pin = 0; +} + +bool common_hal_wiznet_pio_spi_configure(wiznet_pio_spi_obj_t *self, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { + + uint32_t clock = clock_get_hz(clk_sys); + uint32_t clock_div = clock / baudrate; + + if (clock_div > clock / 4) { + clock_div = clock / 4; + } + + wiznet_pio_spi_config.clock_div_major = clock_div; + wiznet_pio_spi_config.clock_div_minor = 0; + + return true; +} + +bool common_hal_wiznet_pio_spi_try_lock(wiznet_pio_spi_obj_t *self) { + if (common_hal_wiznet_pio_spi_deinited(self)) { + return false; + } + + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + return grabbed_lock; +} + +bool common_hal_wiznet_pio_spi_has_lock(wiznet_pio_spi_obj_t *self) { + return self->has_lock; +} + +void common_hal_wiznet_pio_spi_unlock(wiznet_pio_spi_obj_t *self) { + self->has_lock = false; +} + +bool common_hal_wiznet_pio_spi_write(wiznet_pio_spi_obj_t *self, + const uint8_t *data, size_t len) { + wiznet_pio_spi_write_buffer(data, len); + return true; +} + +bool common_hal_wiznet_pio_spi_read(wiznet_pio_spi_obj_t *self, + uint8_t *data, size_t len, uint8_t write_value) { + wiznet_pio_spi_read_buffer(data, len); + return true; +} + +bool common_hal_wiznet_pio_spi_transfer(wiznet_pio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { + return wiznet_pio_spi_transfer(data_out, len, data_in, len); +} diff --git a/ports/raspberrypi/common-hal/wiznet/PIO_SPI.h b/ports/raspberrypi/common-hal/wiznet/PIO_SPI.h new file mode 100755 index 00000000000..6fcfb452cce --- /dev/null +++ b/ports/raspberrypi/common-hal/wiznet/PIO_SPI.h @@ -0,0 +1,25 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +#include "hardware/spi.h" + +#define SPI_HEADER_LEN 3 + +typedef struct { + mp_obj_base_t base; + bool has_lock; + const mcu_pin_obj_t *clock; + const mcu_pin_obj_t *MOSI; + const mcu_pin_obj_t *MISO; +} wiznet_pio_spi_obj_t; + +void reset_spi(void); diff --git a/ports/zephyr-cp/common-hal/zephyr_i2c/__init__.c b/ports/raspberrypi/common-hal/wiznet/__init__.c old mode 100644 new mode 100755 similarity index 84% rename from ports/zephyr-cp/common-hal/zephyr_i2c/__init__.c rename to ports/raspberrypi/common-hal/wiznet/__init__.c index db93a442f04..b3d5d23882d --- a/ports/zephyr-cp/common-hal/zephyr_i2c/__init__.c +++ b/ports/raspberrypi/common-hal/wiznet/__init__.c @@ -4,4 +4,4 @@ // // SPDX-License-Identifier: MIT -// No zephyr_i2c module functions. +// No wiznet module functions. diff --git a/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.c b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.c new file mode 100755 index 00000000000..eb041527209 --- /dev/null +++ b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "pico/stdlib.h" +#include "pico/error.h" + +#include "hardware/dma.h" +#include "hardware/clocks.h" + +#include "wizchip_pio_spi.h" +#include "wizchip_pio_spi.pio.h" + +#ifndef PIO_SPI_PREFERRED_PIO +#define PIO_SPI_PREFERRED_PIO 1 +#endif + +#define PADS_DRIVE_STRENGTH PADS_BANK0_GPIO0_DRIVE_VALUE_12MA +#define IRQ_SAMPLE_DELAY_NS 100 + +#define WIZNET_PIO_SPI_PROGRAM_NAME wiznet_pio_spi_write_read +#define WIZNET_PIO_SPI_PROGRAM_FUNC __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _program) +#define WIZNET_PIO_SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _program_get_default_config) +#define WIZNET_PIO_SPI_OFFSET_WRITE_BITS __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _offset_write_bits) +#define WIZNET_PIO_SPI_OFFSET_WRITE_END __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _offset_write_end) +#define WIZNET_PIO_SPI_OFFSET_READ_END __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _offset_read_end) + +// All wiznet spi operations must start with writing a 3 byte header +#define WIZNET_PIO_SPI_HEADER_LEN 3 + +#ifndef WIZNET_PICO_PIO_SPI_INSTANCE_COUNT +#define WIZNET_PICO_PIO_SPI_INSTANCE_COUNT 1 +#endif + +typedef struct wiznet_pio_spi_state { + wiznet_pio_spi_funcs_t *funcs; + const wiznet_pio_spi_config_t *spi_config; + pio_hw_t *pio; + uint8_t pio_func_sel; + int8_t pio_offset; + int8_t pio_sm; + int8_t dma_out; + int8_t dma_in; + uint8_t spi_header[WIZNET_PIO_SPI_HEADER_LEN]; + uint8_t spi_header_count; +} wiznet_pio_spi_state_t; +static wiznet_pio_spi_state_t wiznet_pio_spi_state[WIZNET_PICO_PIO_SPI_INSTANCE_COUNT]; +static wiznet_pio_spi_state_t *active_state; + +static wiznet_pio_spi_funcs_t *get_wiznet_pio_spi_impl(void); + +// Initialise our gpios +static void wiznet_pio_spi_gpio_setup(wiznet_pio_spi_state_t *state) { + + // Setup MOSI, MISO and IRQ + gpio_init(state->spi_config->data_out_pin); + gpio_set_dir(state->spi_config->data_out_pin, GPIO_OUT); + gpio_put(state->spi_config->data_out_pin, false); + + gpio_init(state->spi_config->data_in_pin); + gpio_set_dir(state->spi_config->data_in_pin, GPIO_IN); + + // Setup CS + gpio_init(state->spi_config->cs_pin); + gpio_set_dir(state->spi_config->cs_pin, GPIO_OUT); + gpio_put(state->spi_config->cs_pin, true); + + // Setup IRQ + gpio_init(state->spi_config->irq_pin); + gpio_set_dir(state->spi_config->irq_pin, GPIO_IN); + gpio_set_pulls(state->spi_config->irq_pin, false, false); +} + +wiznet_pio_spi_handle_t wiznet_pio_spi_open(const wiznet_pio_spi_config_t *wiznet_pio_spi_config) { + wiznet_pio_spi_state_t *state; + for (size_t i = 0; i < count_of(wiznet_pio_spi_state); i++) { + if (!wiznet_pio_spi_state[i].funcs) { + state = &wiznet_pio_spi_state[i]; + break; + } + } + assert(state); + // if (!state) return NULL; + state->spi_config = wiznet_pio_spi_config; + state->funcs = get_wiznet_pio_spi_impl(); + + wiznet_pio_spi_gpio_setup(state); + + pio_hw_t *pios[2] = {pio0, pio1}; + uint pio_index = PIO_SPI_PREFERRED_PIO; + + if (!pio_can_add_program(pios[pio_index], &WIZNET_PIO_SPI_PROGRAM_FUNC)) { + pio_index ^= 1; + if (!pio_can_add_program(pios[pio_index], &WIZNET_PIO_SPI_PROGRAM_FUNC)) { + return NULL; + } + } + + state->pio = pios[pio_index]; + state->dma_in = -1; + state->dma_out = -1; + + static_assert(GPIO_FUNC_PIO1 == GPIO_FUNC_PIO0 + 1, ""); + state->pio_func_sel = GPIO_FUNC_PIO0 + pio_index; + state->pio_sm = (int8_t)pio_claim_unused_sm(state->pio, false); + if (state->pio_sm < 0) { + wiznet_pio_spi_close(&state->funcs); + return NULL; + } + + state->pio_offset = pio_add_program(state->pio, &WIZNET_PIO_SPI_PROGRAM_FUNC); + + pio_sm_config sm_config = WIZNET_PIO_SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC(state->pio_offset); + + sm_config_set_clkdiv_int_frac(&sm_config, state->spi_config->clock_div_major, state->spi_config->clock_div_minor); + hw_write_masked(&pads_bank0_hw->io[state->spi_config->clock_pin], + (uint)PADS_DRIVE_STRENGTH << PADS_BANK0_GPIO0_DRIVE_LSB, + PADS_BANK0_GPIO0_DRIVE_BITS + ); + hw_write_masked(&pads_bank0_hw->io[state->spi_config->clock_pin], + (uint)1 << PADS_BANK0_GPIO0_SLEWFAST_LSB, + PADS_BANK0_GPIO0_SLEWFAST_BITS + ); + + sm_config_set_out_pins(&sm_config, state->spi_config->data_out_pin, 1); + sm_config_set_in_pins(&sm_config, state->spi_config->data_in_pin); + sm_config_set_set_pins(&sm_config, state->spi_config->data_out_pin, 1); + sm_config_set_sideset(&sm_config, 1, false, false); + sm_config_set_sideset_pins(&sm_config, state->spi_config->clock_pin); + + sm_config_set_in_shift(&sm_config, false, true, 8); + sm_config_set_out_shift(&sm_config, false, true, 8); + hw_set_bits(&state->pio->input_sync_bypass, 1u << state->spi_config->data_in_pin); + pio_sm_set_config(state->pio, state->pio_sm, &sm_config); + pio_sm_set_consecutive_pindirs(state->pio, state->pio_sm, state->spi_config->clock_pin, 1, true); + gpio_set_function(state->spi_config->data_out_pin, state->pio_func_sel); + gpio_set_function(state->spi_config->clock_pin, state->pio_func_sel); + + // Set data pin to pull down and schmitt + gpio_set_pulls(state->spi_config->data_in_pin, false, true); + gpio_set_input_hysteresis_enabled(state->spi_config->data_in_pin, true); + + pio_sm_exec(state->pio, state->pio_sm, pio_encode_set(pio_pins, 1)); + state->dma_out = (int8_t)dma_claim_unused_channel(false); // todo: Should be able to use one dma channel? + state->dma_in = (int8_t)dma_claim_unused_channel(false); + if (state->dma_out < 0 || state->dma_in < 0) { + wiznet_pio_spi_close(&state->funcs); + return NULL; + } + return &state->funcs; +} + +void wiznet_pio_spi_close(wiznet_pio_spi_handle_t handle) { + wiznet_pio_spi_state_t *state = (wiznet_pio_spi_state_t *)handle; + if (state) { + if (state->pio_sm >= 0) { + if (state->pio_offset != -1) { + pio_remove_program(state->pio, &WIZNET_PIO_SPI_PROGRAM_FUNC, state->pio_offset); + } + + pio_sm_unclaim(state->pio, state->pio_sm); + } + if (state->dma_out >= 0) { + dma_channel_unclaim(state->dma_out); + state->dma_out = -1; + } + if (state->dma_in >= 0) { + dma_channel_unclaim(state->dma_in); + state->dma_in = -1; + } + state->funcs = NULL; + } +} + +static void cs_set(wiznet_pio_spi_state_t *state, bool value) { + gpio_put(state->spi_config->cs_pin, value); +} + +static __noinline void ns_delay(uint32_t ns) { + // cycles = ns * clk_sys_hz / 1,000,000,000 + uint32_t cycles = ns * (clock_get_hz(clk_sys) >> 16u) / (1000000000u >> 16u); + busy_wait_at_least_cycles(cycles); +} + +static void wiznet_pio_spi_frame_start(void) { + assert(active_state); + + gpio_set_function(active_state->spi_config->data_out_pin, active_state->pio_func_sel); + gpio_set_function(active_state->spi_config->clock_pin, active_state->pio_func_sel); + gpio_pull_down(active_state->spi_config->clock_pin); + + // Pull CS low + cs_set(active_state, false); +} + +static void wiznet_pio_spi_frame_end(void) { + assert(active_state); + + // from this point a positive edge will cause an IRQ to be pending + cs_set(active_state, true); + + // we need to wait a bit in case the irq line is incorrectly high + #ifdef IRQ_SAMPLE_DELAY_NS + ns_delay(IRQ_SAMPLE_DELAY_NS); + #endif +} + +// send tx then receive rx +// rx can be null if you just want to send, but tx and tx_length must be valid +bool wiznet_pio_spi_transfer(const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length) { + const wiznet_pio_spi_state_t *state = active_state; + if (!state || (tx == NULL)) { + return false; + } + + if (rx != NULL && tx != NULL) { + assert(tx && tx_length && rx_length); + + pio_sm_set_enabled(state->pio, state->pio_sm, false); // disable sm + pio_sm_set_wrap(state->pio, state->pio_sm, state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_BITS, state->pio_offset + WIZNET_PIO_SPI_OFFSET_READ_END - 1); + pio_sm_clear_fifos(state->pio, state->pio_sm); // clear fifos from previous run + pio_sm_set_pindirs_with_mask(state->pio, state->pio_sm, 1u << state->spi_config->data_out_pin, 1u << state->spi_config->data_out_pin); + pio_sm_restart(state->pio, state->pio_sm); + pio_sm_clkdiv_restart(state->pio, state->pio_sm); + pio_sm_put(state->pio, state->pio_sm, tx_length * 8 - 1); // set x + pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_x, 32)); + pio_sm_put(state->pio, state->pio_sm, rx_length - 1); // set y + pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_y, 32)); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_jmp(state->pio_offset)); // setup pc + + dma_channel_abort(state->dma_out); + dma_channel_abort(state->dma_in); + + dma_channel_config out_config = dma_channel_get_default_config(state->dma_out); + channel_config_set_dreq(&out_config, pio_get_dreq(state->pio, state->pio_sm, true)); + channel_config_set_transfer_data_size(&out_config, DMA_SIZE_8); + dma_channel_configure(state->dma_out, &out_config, &state->pio->txf[state->pio_sm], tx, tx_length, true); + + dma_channel_config in_config = dma_channel_get_default_config(state->dma_in); + channel_config_set_dreq(&in_config, pio_get_dreq(state->pio, state->pio_sm, false)); + channel_config_set_write_increment(&in_config, true); + channel_config_set_read_increment(&in_config, false); + channel_config_set_transfer_data_size(&in_config, DMA_SIZE_8); + dma_channel_configure(state->dma_in, &in_config, rx, &state->pio->rxf[state->pio_sm], rx_length, true); + + pio_sm_set_enabled(state->pio, state->pio_sm, true); + __compiler_memory_barrier(); + + dma_channel_wait_for_finish_blocking(state->dma_out); + dma_channel_wait_for_finish_blocking(state->dma_in); + + __compiler_memory_barrier(); + } else if (tx != NULL) { + assert(tx_length); + + pio_sm_set_enabled(state->pio, state->pio_sm, false); + pio_sm_set_wrap(state->pio, state->pio_sm, state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_BITS, state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_END - 1); + pio_sm_clear_fifos(state->pio, state->pio_sm); + pio_sm_restart(state->pio, state->pio_sm); + pio_sm_clkdiv_restart(state->pio, state->pio_sm); + pio_sm_put(state->pio, state->pio_sm, tx_length * 8 - 1); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_x, 32)); + pio_sm_put(state->pio, state->pio_sm, tx_length - 1); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_y, 32)); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_set(pio_pins, 0)); + pio_sm_set_consecutive_pindirs(state->pio, state->pio_sm, state->spi_config->data_out_pin, 1, true); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_jmp(state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_BITS)); + + dma_channel_abort(state->dma_out); + + dma_channel_config out_config = dma_channel_get_default_config(state->dma_out); + channel_config_set_dreq(&out_config, pio_get_dreq(state->pio, state->pio_sm, true)); + + channel_config_set_transfer_data_size(&out_config, DMA_SIZE_8); + dma_channel_configure(state->dma_out, &out_config, &state->pio->txf[state->pio_sm], tx, tx_length, true); + + const uint32_t fDebugTxStall = 1u << (PIO_FDEBUG_TXSTALL_LSB + state->pio_sm); + state->pio->fdebug = fDebugTxStall; + pio_sm_set_enabled(state->pio, state->pio_sm, true); + while (!(state->pio->fdebug & fDebugTxStall)) { + // printf("WIZNET_PIO_SPI: waiting for tx stall\n"); + tight_loop_contents(); // todo timeout + } + uint32_t timeout = 1000000; + if (timeout == 0) { + printf("ERROR: PIO TXSTALL timeout!\n"); + return false; + } + __compiler_memory_barrier(); + pio_sm_set_enabled(state->pio, state->pio_sm, false); + pio_sm_set_consecutive_pindirs(state->pio, state->pio_sm, state->spi_config->data_in_pin, 1, false); + } else if (rx != NULL) { + panic_unsupported(); // shouldn't be used + } + pio_sm_exec(state->pio, state->pio_sm, pio_encode_mov(pio_pins, pio_null)); // for next time we turn output on + + return true; +} + +// To read a byte we must first have been asked to write a 3 byte spi header +static uint8_t wiznet_pio_spi_read_byte(void) { + assert(active_state); + assert(active_state->spi_header_count == WIZNET_PIO_SPI_HEADER_LEN); + uint8_t ret; + if (!wiznet_pio_spi_transfer(active_state->spi_header, active_state->spi_header_count, &ret, 1)) { + panic("spi failed read"); + } + active_state->spi_header_count = 0; + return ret; +} + +// This is not used when the burst functions are provided +static void wiznet_pio_spi_write_byte(uint8_t wb) { + panic_unsupported(); // shouldn't be used +} + +// To read a buffer we must first have been asked to write a 3 byte spi header +void wiznet_pio_spi_read_buffer(uint8_t *pBuf, uint16_t len) { + assert(active_state); + assert(active_state->spi_header_count == WIZNET_PIO_SPI_HEADER_LEN); + if (!wiznet_pio_spi_transfer(active_state->spi_header, active_state->spi_header_count, pBuf, len)) { + panic("spi failed reading buffer"); + } + active_state->spi_header_count = 0; +} + +// If we have been asked to write a spi header already, then write it and the rest of the buffer +// or else if we've been given enough data for just the spi header, save it until the next call +// or we're writing a byte in which case we're given a buffer including the spi header +void wiznet_pio_spi_write_buffer(const uint8_t *pBuf, uint16_t len) { + assert(active_state); + + if (len < WIZNET_PIO_SPI_HEADER_LEN && active_state->spi_header_count != WIZNET_PIO_SPI_HEADER_LEN) { + memcpy(&active_state->spi_header[active_state->spi_header_count], pBuf, len); // expect another call + active_state->spi_header_count++; + } else if (len == WIZNET_PIO_SPI_HEADER_LEN && active_state->spi_header_count == 0) { + memcpy(active_state->spi_header, pBuf, WIZNET_PIO_SPI_HEADER_LEN); // expect another call + active_state->spi_header_count = WIZNET_PIO_SPI_HEADER_LEN; + } else { + if (active_state->spi_header_count == WIZNET_PIO_SPI_HEADER_LEN) { + if (!wiznet_pio_spi_transfer(active_state->spi_header, WIZNET_PIO_SPI_HEADER_LEN, NULL, 0)) { + panic("spi failed writing header"); + } + active_state->spi_header_count = 0; + } + assert(active_state->spi_header_count == 0); + if (!wiznet_pio_spi_transfer(pBuf, len, NULL, 0)) { + panic("spi failed writing buffer"); + } + } +} + +static void wiznet_pio_spi_set_active(wiznet_pio_spi_handle_t handle) { + active_state = (wiznet_pio_spi_state_t *)handle; +} + +static void wiznet_pio_spi_set_inactive(void) { + active_state = NULL; +} + +static void wiznet_pio_spi_reset(wiznet_pio_spi_handle_t handle) { + wiznet_pio_spi_state_t *state = (wiznet_pio_spi_state_t *)handle; + gpio_set_dir(state->spi_config->reset_pin, GPIO_OUT); + gpio_put(state->spi_config->reset_pin, 0); + sleep_ms(100); + gpio_put(state->spi_config->reset_pin, 1); + sleep_ms(100); +} + +static wiznet_pio_spi_funcs_t *get_wiznet_pio_spi_impl(void) { + static wiznet_pio_spi_funcs_t funcs = { + .close = wiznet_pio_spi_close, + .set_active = wiznet_pio_spi_set_active, + .set_inactive = wiznet_pio_spi_set_inactive, + .frame_start = wiznet_pio_spi_frame_start, + .frame_end = wiznet_pio_spi_frame_end, + .read_byte = wiznet_pio_spi_read_byte, + .write_byte = wiznet_pio_spi_write_byte, + .read_buffer = wiznet_pio_spi_read_buffer, + .write_buffer = wiznet_pio_spi_write_buffer, + .reset = wiznet_pio_spi_reset, + }; + return &funcs; +} diff --git a/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.h b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.h new file mode 100755 index 00000000000..841eb48c480 --- /dev/null +++ b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _WIZNET_PIO_SPI_H_ +#define _WIZNET_PIO_SPI_H_ + +typedef struct wiznet_pio_spi_config { + uint8_t data_in_pin; + uint8_t data_out_pin; + uint8_t cs_pin; + uint8_t clock_pin; + uint8_t irq_pin; + uint8_t reset_pin; + uint16_t clock_div_major; + uint8_t clock_div_minor; + uint8_t spi_hw_instance; +} wiznet_pio_spi_config_t; + +typedef struct wiznet_pio_spi_funcs **wiznet_pio_spi_handle_t; + +typedef struct wiznet_pio_spi_funcs { + void (*close)(wiznet_pio_spi_handle_t funcs); + void (*set_active)(wiznet_pio_spi_handle_t funcs); + void (*set_inactive)(void); + void (*frame_start)(void); + void (*frame_end)(void); + uint8_t (*read_byte)(void); + void (*write_byte)(uint8_t tx_data); + void (*read_buffer)(uint8_t *pBuf, uint16_t len); + void (*write_buffer)(const uint8_t *pBuf, uint16_t len); + void (*reset)(wiznet_pio_spi_handle_t funcs); +} wiznet_pio_spi_funcs_t; + +wiznet_pio_spi_handle_t wiznet_pio_spi_open(const wiznet_pio_spi_config_t *pio_spi_config); +void wiznet_pio_spi_close(wiznet_pio_spi_handle_t handle); +bool wiznet_pio_spi_transfer(const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length); +void wiznet_pio_spi_read_buffer(uint8_t *pBuf, uint16_t len); +void wiznet_pio_spi_write_buffer(const uint8_t *pBuf, uint16_t len); + +#endif diff --git a/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.pio b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.pio new file mode 100755 index 00000000000..97a1c5b73d4 --- /dev/null +++ b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.pio @@ -0,0 +1,24 @@ +; +; Copyright (c) 2023 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; + +.program wiznet_pio_spi_write_read +.side_set 1 + +public write_bits: + out pins, 1 side 0 + jmp x-- write_bits side 1 + set pins 0 side 0 +public write_end: +read_byte_delay: + set pindirs 0 side 0 +read_byte: + set x 6 side 1 +read_bits: + in pins, 1 side 0 + jmp x-- read_bits side 1 + in pins, 1 side 0 + jmp y-- read_byte side 0 +public read_end: diff --git a/ports/raspberrypi/lib/Pico-PIO-USB b/ports/raspberrypi/lib/Pico-PIO-USB index 675543bcc9b..a5a2f5ae919 160000 --- a/ports/raspberrypi/lib/Pico-PIO-USB +++ b/ports/raspberrypi/lib/Pico-PIO-USB @@ -1 +1 @@ -Subproject commit 675543bcc9baa8170f868ab7ba316d418dbcf41f +Subproject commit a5a2f5ae91988449ba576ec9d237e806d5cd4416 diff --git a/ports/raspberrypi/link-rp2040.ld b/ports/raspberrypi/link-rp2040.ld index 6e7bd15a7b6..189c3d7c338 100644 --- a/ports/raspberrypi/link-rp2040.ld +++ b/ports/raspberrypi/link-rp2040.ld @@ -82,7 +82,7 @@ SECTIONS *(.property_getset) __property_getset_end = .; - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *interp.o *divider.o *tusb_fifo.o *mem_ops_aeabi.o *usbh.o) .text*) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *interp.o *divider.o *pico_int64_ops_aeabi.o *tusb_fifo.o *mem_ops_aeabi.o *usbh.o) .text*) /* Allow everything in usbh.o except tuh_task_event_ready because we read it from core 1. */ *usbh.o (.text.[_uphc]* .text.tuh_[cmved]* .text.tuh_task_ext*) *(.fini) diff --git a/ports/raspberrypi/link-rp2350.ld b/ports/raspberrypi/link-rp2350.ld index a2cc62909e6..3c339b03fe2 100644 --- a/ports/raspberrypi/link-rp2350.ld +++ b/ports/raspberrypi/link-rp2350.ld @@ -63,7 +63,7 @@ SECTIONS *(.property_getset) __property_getset_end = .; - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *interp.o *divider.o *tusb_fifo.o *mem_ops_aeabi.o *usbh.o *string0.o) .text*) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *interp.o *divider.o *pico_int64_ops_aeabi.o *tusb_fifo.o *mem_ops_aeabi.o *usbh.o *string0.o) .text*) /* Allow everything in usbh.o except tuh_task_event_ready because we read it from core 1. */ *usbh.o (.text.[_uphc]* .text.tuh_[cmved]* .text.tuh_task_ext*) *(.fini) diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index 3eb576de39e..7d47658e729 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -8,11 +8,15 @@ #include "hardware/platform_defs.h" -#ifdef PICO_RP2040 +// CIRCUITPY-CHANGE: CircuitPython supports raw sockets through its own lwip +// integration, independently of MICROPY_PY_LWIP. +#define MICROPY_PY_LWIP_SOCK_RAW (1) + +#if PICO_RP2040 #define MICROPY_PY_SYS_PLATFORM "RP2040" #endif -#ifdef PICO_RP2350 +#if PICO_RP2350 #define MICROPY_PY_SYS_PLATFORM "RP2350" // PSRAM can require more stack space for GC. @@ -36,10 +40,8 @@ #define CIRCUITPY_PROCESSOR_COUNT (2) -// For many RP2 boards BOOTSEL is not connected to a GPIO pin. -#ifndef CIRCUITPY_BOOT_BUTTON +// For RP2 boards we use a custom way to read BOOTSEL #define CIRCUITPY_BOOT_BUTTON_NO_GPIO (1) -#endif #if CIRCUITPY_USB_HOST #define CIRCUITPY_USB_HOST_INSTANCE 1 @@ -48,6 +50,16 @@ // This also includes mpconfigboard.h. #include "py/circuitpy_mpconfig.h" +// Turn on this option to allow the use of the internal pull-up resistors on +// the I2C pins, for boards whose on-board I2C peripherals lack external pull +// up resistors. The internal pull-ups are weak, and using them is only to +// compensate for design decisions that are out of the control of the authors +// of CircuitPython. It is not an endorsement of running without appropriate +// external pull up resistors. +#ifndef CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP +#define CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP (0) +#endif + #if CIRCUITPY_CYW43 #define MICROPY_PY_LWIP_ENTER cyw43_arch_lwip_begin(); #define MICROPY_PY_LWIP_REENTER MICROPY_PY_LWIP_ENTER diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index bbce13d1381..551ab00ab47 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -11,11 +11,16 @@ CIRCUITPY_FLOPPYIO ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_DISPLAYIO) CIRCUITPY_FULL_BUILD ?= 1 CIRCUITPY_AUDIOMP3 ?= 1 +CIRCUITPY_AUDIOSPEED ?= 1 +CIRCUITPY_AUDIOEFFECTS ?= 1 +CIRCUITPY_AUDIOFILEWRITER ?= 1 CIRCUITPY_BITOPS ?= 1 CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 CIRCUITPY_IMAGECAPTURE ?= 1 +CIRCUITPY_LOAD_NATIVE ?= 1 CIRCUITPY_MAX3421E ?= 0 +CIRCUITPY_MCP4822 ?= 0 CIRCUITPY_MEMORYMAP ?= 1 CIRCUITPY_PWMIO ?= 1 CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_DISPLAYIO) @@ -24,6 +29,7 @@ CIRCUITPY_ROTARYIO_SOFTENCODER = 1 CIRCUITPY_SYNTHIO_MAX_CHANNELS = 24 CIRCUITPY_USB_HOST ?= 1 CIRCUITPY_USB_VIDEO ?= 1 +CIRCUITPY_USB_AUDIO ?= 1 # Things that need to be implemented. CIRCUITPY_FREQUENCYIO = 0 @@ -41,6 +47,7 @@ CIRCUITPY_ANALOGBUFIO = 1 # Audio via PWM CIRCUITPY_AUDIOIO = 0 CIRCUITPY_AUDIOBUSIO ?= 1 +CIRCUITPY_AUDIOI2SIN ?= $(CIRCUITPY_AUDIOBUSIO) CIRCUITPY_AUDIOCORE ?= 1 CIRCUITPY_AUDIOPWMIO ?= 1 diff --git a/ports/raspberrypi/supervisor/internal_flash.c b/ports/raspberrypi/supervisor/internal_flash.c index 9d5e13348aa..07b15564c60 100644 --- a/ports/raspberrypi/supervisor/internal_flash.c +++ b/ports/raspberrypi/supervisor/internal_flash.c @@ -23,7 +23,7 @@ #include "supervisor/flash.h" #include "supervisor/usb.h" -#ifdef PICO_RP2350 +#if PICO_RP2350 #include "hardware/structs/qmi.h" #endif #include "hardware/structs/sio.h" diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 66e63248c48..34e9fc159fd 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -4,12 +4,16 @@ // // SPDX-License-Identifier: MIT +#include #include +#include #include #include +#include #include "supervisor/background_callback.h" #include "supervisor/board.h" +#include "supervisor/linker.h" #include "supervisor/port.h" #include "bindings/rp2pio/StateMachine.h" @@ -25,6 +29,7 @@ #if CIRCUITPY_SSL #include "shared-module/ssl/__init__.h" +#include "psa/crypto.h" #endif #if CIRCUITPY_WIFI @@ -34,10 +39,16 @@ #include "common-hal/rtc/RTC.h" #include "common-hal/busio/UART.h" +#if CIRCUITPY_SDIOIO +#include "common-hal/sdioio/SDCard.h" +#endif + #include "supervisor/shared/safe_mode.h" #include "supervisor/shared/stack.h" #include "supervisor/shared/tick.h" +#include "hardware/clocks.h" +#include "hardware/structs/scb.h" #include "hardware/structs/watchdog.h" #include "hardware/gpio.h" #include "hardware/uart.h" @@ -53,7 +64,7 @@ #include "pico/bootrom.h" #include "hardware/watchdog.h" -#ifdef PICO_RP2350 +#if PICO_RP2350 #include "RP2350.h" // CMSIS #endif @@ -72,6 +83,40 @@ critical_section_t background_queue_lock; +// The SDK's panic() lives in flash, but core1 may run with flash access +// disabled by the MPU (usb_host and picodvi lock it out), where a flash call +// hard faults before anything is printed. -Wl,--wrap=panic routes every +// panic here instead: core0 keeps the SDK behavior, core1 halts from RAM. +// Verified by tools/check_core1_flash_calls.py. +void __wrap_panic(const char *fmt, ...) __attribute__((noreturn, format(printf, 1, 2))); +void panic_core0(const char *fmt, va_list args) __attribute__((noreturn, format(printf, 1, 0))); + +// Flash-resident; only ever called from core0 (see __wrap_panic). Mirrors +// the SDK implementation. noinline keeps the flash-calling code out of the +// RAM-resident wrapper below. +__attribute__((noinline)) void panic_core0(const char *fmt, va_list args) { + puts("\n*** PANIC ***\n"); + if (fmt) { + vprintf(fmt, args); + puts(""); + } + _exit(1); +} + +void __not_in_flash_func(__wrap_panic)(const char *fmt, ...) { + if (get_core_num() == 0) { + va_list args; + va_start(args, fmt); + panic_core0(fmt, args); + } + // Flash may be MPU-locked on this core and stdio is core0-only, so the + // message is unprintable here. Halt in RAM: a debugger stops at the + // breakpoint, otherwise spin. + __breakpoint(); + while (1) { + } +} + extern volatile bool mp_msc_enabled; static void _tick_callback(uint alarm_num); @@ -108,6 +153,9 @@ static size_t _psram_size = 0; #include "hardware/structs/xip_ctrl.h" static void __no_inline_not_in_flash_func(setup_psram)(void) { + // Read the system clock before QMI goes into direct mode; clock_get_hz() is + // in flash and XIP is reconfigured below. + uint32_t sys_clk_khz = clock_get_hz(clk_sys) / 1000; gpio_set_function(CIRCUITPY_PSRAM_CHIP_SELECT->number, GPIO_FUNC_XIP_CS1); _psram_size = 0; common_hal_mcu_disable_interrupts(); @@ -193,14 +241,7 @@ static void __no_inline_not_in_flash_func(setup_psram)(void) { // Disable direct csr. qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS); - qmi_hw->m[1].timing = - QMI_M0_TIMING_PAGEBREAK_VALUE_1024 << QMI_M0_TIMING_PAGEBREAK_LSB | // Break between pages. - 3 << QMI_M0_TIMING_SELECT_HOLD_LSB | // Delay releasing CS for 3 extra system cycles. - 1 << QMI_M0_TIMING_COOLDOWN_LSB | - 1 << QMI_M0_TIMING_RXDELAY_LSB | - 16 << QMI_M0_TIMING_MAX_SELECT_LSB | // In units of 64 system clock cycles. PSRAM says 8us max. 8 / 0.00752 / 64 = 16.62 - 7 << QMI_M0_TIMING_MIN_DESELECT_LSB | // In units of system clock cycles. PSRAM says 50ns.50 / 7.52 = 6.64 - 2 << QMI_M0_TIMING_CLKDIV_LSB; + mcu_processor_update_psram_timing(sys_clk_khz); qmi_hw->m[1].rfmt = (QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB | QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_SUFFIX_WIDTH_LSB | @@ -263,17 +304,17 @@ void port_heap_init(void) { } void *port_malloc(size_t size, bool dma_capable) { - if (!dma_capable && _psram_size > 0) { - common_hal_mcu_disable_interrupts(); - void *block = tlsf_malloc(_psram_heap, size); - common_hal_mcu_enable_interrupts(); - if (block) { - return block; - } - } + // Prefer internal RAM for everything: it is much faster than PSRAM + // (data there skips the external bus and the shared XIP cache). PSRAM, when + // present, serves as spillover capacity for allocations that don't need DMA. common_hal_mcu_disable_interrupts(); void *block = tlsf_malloc(_heap, size); common_hal_mcu_enable_interrupts(); + if (block == NULL && !dma_capable && _psram_size > 0) { + common_hal_mcu_disable_interrupts(); + block = tlsf_malloc(_psram_heap, size); + common_hal_mcu_enable_interrupts(); + } return block; } @@ -288,7 +329,11 @@ void port_free(void *ptr) { } void *port_realloc(void *ptr, size_t size, bool dma_capable) { - if (_psram_size > 0 && ((ptr != NULL && ((size_t)ptr) < SRAM_BASE) || (ptr == NULL && !dma_capable))) { + if (ptr == NULL) { + // Fresh allocation: same internal-first policy as port_malloc. + return port_malloc(size, dma_capable); + } + if (_psram_size > 0 && ((size_t)ptr) < SRAM_BASE) { common_hal_mcu_disable_interrupts(); void *block = tlsf_realloc(_psram_heap, ptr, size); common_hal_mcu_enable_interrupts(); @@ -336,10 +381,10 @@ safe_mode_t port_init(void) { // Load from the XIP memory space that doesn't cache. That way we don't // evict anything else. The code we're loading is linked to the RAM address // anyway. - #ifdef PICO_RP2040 + #if PICO_RP2040 size_t nocache = 0x03000000; #endif - #ifdef PICO_RP2350 + #if PICO_RP2350 size_t nocache = 0x04000000; #endif @@ -380,6 +425,16 @@ safe_mode_t port_init(void) { common_hal_rtc_init(); #endif + // Send-event-on-pend, so the WFE in port_idle_until_interrupt wakes on a + // pending interrupt (as WFI did) in addition to waking on SEV — including + // the SEV core 1 sends via port_wake_main_task() when it queues USB host + // work. + #if PICO_RP2040 + scb_hw->scr |= M0PLUS_SCR_SEVONPEND_BITS; + #else + scb_hw->scr |= M33_SCR_SEVONPEND_BITS; + #endif + // For the tick. hardware_alarm_claim(0); hardware_alarm_set_callback(0, _tick_callback); @@ -422,7 +477,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO - reset_spi(); reset_uart(); #endif @@ -434,6 +488,10 @@ void reset_port(void) { reset_rp2pio_statemachine(); #endif + #if CIRCUITPY_SDIOIO + sdioio_reset(); + #endif + #if CIRCUITPY_RTC rtc_reset(); #endif @@ -444,6 +502,14 @@ void reset_port(void) { #if CIRCUITPY_SSL ssl_reset(); + + // For raspberrypi, we must free PSA crypto, because there are GC-heap objects + // in the key slots. We can't put this call in ssl_reset() because that's a + // shared-module implementation. Unlike raspberrypi, espressif ESP-IDF inits PSA + // once at boot and would never re-init it. + // common_hal_ssl_sslcontext_construct() re-inits PSA on demand. + // So for raspberrypi, we must call mbedtls_psa_crypto_free() explicitly. + mbedtls_psa_crypto_free(); #endif #if CIRCUITPY_WATCHDOG @@ -453,8 +519,6 @@ void reset_port(void) { #if CIRCUITPY_WIFI wifi_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { @@ -550,7 +614,7 @@ void port_interrupt_after_ticks(uint32_t ticks) { } void port_idle_until_interrupt(void) { - #ifdef PICO_RP2040 + #if PICO_RP2040 common_hal_mcu_disable_interrupts(); #if CIRCUITPY_USB_HOST if (!background_callback_pending() && !tud_task_event_ready() && !tuh_task_event_ready() && !_woken_up) { @@ -558,7 +622,11 @@ void port_idle_until_interrupt(void) { if (!background_callback_pending() && !tud_task_event_ready() && !_woken_up) { #endif __DSB(); - __WFI(); + // WFE, not WFI: the event register is sticky, so a SEV from core 1 + // (port_wake_main_task, e.g. a USB host event) that lands between the + // checks above and here still terminates the wait. Pending interrupts + // wake it too, via SEVONPEND (set in port_init). + __wfe(); } common_hal_mcu_enable_interrupts(); #else @@ -577,7 +645,8 @@ void port_idle_until_interrupt(void) { if (!background_callback_pending() && !tud_task_event_ready() && !_woken_up) { #endif __DSB(); - __WFI(); + // WFE, not WFI: see the RP2040 branch above. + __wfe(); } // and restore basepri before reenabling interrupts @@ -588,10 +657,24 @@ void port_idle_until_interrupt(void) { #endif } +// Called whenever a background callback is queued, including from core 1 +// (which runs the PIO-USB host and posts its events here). SEV is broadcast +// to both cores and latches in the event register, so it reliably ends the +// WFE in port_idle_until_interrupt even if it arrives before the WFE starts. +// Without this, core 0 sleeps through host events for the remainder of a +// time.sleep(): device removal processing and enumeration stall until the +// next unrelated wakeup. +// PLACE_IN_ITCM: core 1 runs with flash execute-never, so this must live in +// RAM like its background_callback_add_core caller (__sev inlines to a bare +// instruction). +void PLACE_IN_ITCM(port_wake_main_task)(void) { + __sev(); +} + /** * \brief Default interrupt handler for unused IRQs. */ -extern NORETURN void isr_hardfault(void); // provide a prototype to avoid a missing-prototypes diagnostic +extern MP_NORETURN void isr_hardfault(void); // provide a prototype to avoid a missing-prototypes diagnostic __attribute__((used)) void __not_in_flash_func(isr_hardfault)(void) { // Only safe mode from core 0 which is running CircuitPython. Core 1 faulting // should not be fatal to CP. (Fingers crossed.) @@ -603,7 +686,7 @@ __attribute__((used)) void __not_in_flash_func(isr_hardfault)(void) { } } -void port_yield(void) { +void port_task_yield(void) { #if CIRCUITPY_CYW43 cyw43_arch_poll(); #endif @@ -627,7 +710,7 @@ bool __no_inline_not_in_flash_func(port_boot_button_pressed)(void) { // pressed, return is delayed until the button is released and // a delay has passed in order to debounce the button. const uint32_t CS_PIN_INDEX = 1; - #if defined(PICO_RP2040) + #if PICO_RP2040 const uint32_t CS_BIT = 1u << 1; #else const uint32_t CS_BIT = SIO_GPIO_HI_IN_QSPI_CSN_BITS; diff --git a/ports/raspberrypi/supervisor/usb.c b/ports/raspberrypi/supervisor/usb.c index 398f3f448a1..244c5bbce9b 100644 --- a/ports/raspberrypi/supervisor/usb.c +++ b/ports/raspberrypi/supervisor/usb.c @@ -6,14 +6,30 @@ #include "lib/tinyusb/src/device/usbd.h" #include "supervisor/background_callback.h" +#include "supervisor/linker.h" #include "supervisor/usb.h" #include "hardware/irq.h" +#include "hardware/timer.h" #include "pico/platform.h" #include "hardware/regs/intctrl.h" void init_usb_hardware(void) { } +// Override the shared implementation with one that is safe to call from core1. +// TinyUSB's tuh_task_event_ready() calls this, and usb_host polls +// tuh_task_event_ready() from core1's PIO-USB frame loop (see +// common-hal/usb_host/Port.c). tuh_task_event_ready() is deliberately placed in +// RAM by link-rp2*.ld, and everything it calls must be RAM-resident too: on +// RP2350, core1 sets an MPU region that makes flash execute-never, and on +// RP2040 flash may be unavailable while core0 writes to it. time_us_32() is a +// static-inline register read. >>10 yields ~1.024 ms units rather than exact +// milliseconds, which is fine because TinyUSB only uses this API for relative +// delay arithmetic and every use goes through this same function. +uint32_t PLACE_IN_ITCM(tusb_time_millis_api)(void) { + return time_us_32() >> 10; +} + static void _usb_irq_wrapper(void) { usb_irq_handler(0); } diff --git a/ports/renode/Makefile b/ports/renode/Makefile index 92541c03e77..b69d8d251ef 100644 --- a/ports/renode/Makefile +++ b/ports/renode/Makefile @@ -45,7 +45,9 @@ SRC_C += \ background.c \ mphalport.c \ -SRC_S_UPPER = supervisor/shared/cpu_regs.S +SRC_S = shared/runtime/gchelper_thumb1.s + +SRC_C += shared/runtime/gchelper_native.c OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) @@ -54,7 +56,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) $(BUILD)/%.o: $(BUILD)/%.S @@ -87,6 +88,7 @@ $(BUILD)/firmware.elf: $(OBJ) $(BOARD_LD) link.ld $(Q)echo $(OBJ) > $(BUILD)/firmware.objs $(Q)echo $(PICO_LDFLAGS) > $(BUILD)/firmware.ldflags $(Q)$(CC) -o $@ $(CFLAGS) @$(BUILD)/firmware.ldflags $(LINKER_SCRIPTS) -Wl,--print-memory-usage -Wl,-Map=$@.map -Wl,-cref -Wl,--gc-sections @$(BUILD)/firmware.objs -Wl,-lc + $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $@.map $(BUILD) endif $(BUILD)/firmware.bin: $(BUILD)/firmware.elf diff --git a/ports/renode/common-hal/busio/I2C.c b/ports/renode/common-hal/busio/I2C.c index c94f63cb880..41649f180b3 100644 --- a/ports/renode/common-hal/busio/I2C.c +++ b/ports/renode/common-hal/busio/I2C.c @@ -44,19 +44,19 @@ bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return 0; } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - return MP_EIO; + return -MP_EIO; } void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { diff --git a/ports/renode/common-hal/busio/SPI.c b/ports/renode/common-hal/busio/SPI.c index 6f5f6050607..1f66fc5ec4a 100644 --- a/ports/renode/common-hal/busio/SPI.c +++ b/ports/renode/common-hal/busio/SPI.c @@ -21,6 +21,9 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return true; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; diff --git a/ports/renode/common-hal/microcontroller/Processor.c b/ports/renode/common-hal/microcontroller/Processor.c index 3532aa6907a..3a6523338fc 100644 --- a/ports/renode/common-hal/microcontroller/Processor.c +++ b/ports/renode/common-hal/microcontroller/Processor.c @@ -33,5 +33,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_POWER_ON; + return MCU_RESET_REASON_POWER_ON; } diff --git a/ports/renode/supervisor/port.c b/ports/renode/supervisor/port.c index d12ebd2efdd..a40e222d34d 100644 --- a/ports/renode/supervisor/port.c +++ b/ports/renode/supervisor/port.c @@ -210,7 +210,7 @@ __attribute__((used)) void HardFault_Handler(void) { } } -void port_yield(void) { +void port_task_yield(void) { } void port_boot_info(void) { diff --git a/ports/silabs/Makefile b/ports/silabs/Makefile index 58929dd498f..5c0f01e86b1 100644 --- a/ports/silabs/Makefile +++ b/ports/silabs/Makefile @@ -71,7 +71,7 @@ ifeq ($(DEBUG), 1) CFLAGS += -fno-inline -fno-ipa-sra -Og else CFLAGS += -DNDEBUG - OPTIMIZATION_FLAGS ?= -Os -fno-inline-functions + OPTIMIZATION_FLAGS ?= -Os CFLAGS += -g endif @@ -90,7 +90,10 @@ ifneq (,$(wildcard boards/$(BOARD)/sensor.c)) SRC_C += boards/$(BOARD)/sensor.c endif -SRC_S = boards/mp_efr32xg24_gchelper.s +AFLAGS = -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard +SRC_S = shared/runtime/gchelper_thumb1.s + +SRC_C += shared/runtime/gchelper_native.c OBJ += $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) @@ -131,7 +134,8 @@ $(SILABS_BUILD)/$(PROJECTNAME).Makefile: | $(HEADER_BUILD)/mpversion.h $(OUTPUT_DIR)/firmware.out: $(SILABS_BUILD)/pin_functions.h $(SILABS_BUILD)/pins.c $(OBJ) $(OBJS) $(LIB_FILES) $(STEPECHO) 'Linking $(OUTPUT_DIR)/firmware.out' $(Q)echo "$(OBJS) $(OBJ)" > $(OUTPUT_DIR)/linker_objs - $(Q)$(CC) $(LD_FLAGS) @$(OUTPUT_DIR)/linker_objs -Wl,--print-memory-usage $(LIBS) -o $(OUTPUT_DIR)/firmware.out + $(Q)$(CC) $(LD_FLAGS) @$(OUTPUT_DIR)/linker_objs -Wl,--print-memory-usage -Wl,-Map=$(OUTPUT_DIR)/firmware.out.map $(LIBS) -o $(OUTPUT_DIR)/firmware.out + $(Q)$(SIZE) $(OUTPUT_DIR)/firmware.out | $(PYTHON) $(TOP)/tools/build_memory_info.py $(OUTPUT_DIR)/firmware.out.map $(BUILD) $(Q)$(OBJCOPY) $(OUTPUT_DIR)/firmware.out -O binary $(OUTPUT_DIR)/firmware.bin flash: $(OUTPUT_DIR)/firmware.bin diff --git a/ports/silabs/common-hal/_bleio/Adapter.c b/ports/silabs/common-hal/_bleio/Adapter.c index 14b1dac8207..4702555f47d 100644 --- a/ports/silabs/common-hal/_bleio/Adapter.c +++ b/ports/silabs/common-hal/_bleio/Adapter.c @@ -78,31 +78,16 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { const bool is_enabled = common_hal_bleio_adapter_get_enabled(self); - bd_addr get_address; - uint8_t address_type; uint8_t conn_index; bleio_connection_internal_t *connection; - sl_status_t sc = SL_STATUS_FAIL; - uint8_t device_name[DEVICE_NAME_LEN + 1]; - memset(device_name, 0, DEVICE_NAME_LEN); // Don't enable or disable twice if (is_enabled == enabled) { return; } - sc = sl_bt_system_get_identity_address(&get_address, &address_type); - if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Get address fail.")); - } - snprintf((char *)device_name, DEVICE_NAME_LEN + 1, - "CIRCUITPY-%X%X", get_address.addr[1], get_address.addr[0]); - if (enabled) { - sl_bt_gatt_server_write_attribute_value(gattdb_device_name, - 0, - DEVICE_NAME_LEN, - device_name); + bleio_adapter_reset_name(self); // Clear all of the internal connection objects. for (conn_index = 0; conn_index < BLEIO_TOTAL_CONNECTION_COUNT; conn_index++) { @@ -120,17 +105,17 @@ bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *s bd_addr get_address; uint8_t address_type; sl_status_t sc = SL_STATUS_FAIL; - bleio_address_obj_t *address; sc = sl_bt_system_get_identity_address(&get_address, &address_type); if (SL_STATUS_OK != sc) { return NULL; } - address = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - common_hal_bleio_address_construct(address, get_address.addr, + // The cached address is refreshed on every call. + common_hal_bleio_address_construct(&self->address, get_address.addr, BLEIO_ADDRESS_TYPE_RANDOM_STATIC); - return address; + self->address.base.type = &bleio_address_type; + return &self->address; } // Set identity address @@ -138,17 +123,13 @@ bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { sl_status_t sc = SL_STATUS_FAIL; - mp_buffer_info_t bufinfo; bd_addr ble_addr; if (NULL == address) { return false; } - if (!mp_get_buffer(address->bytes, &bufinfo, MP_BUFFER_READ)) { - return false; - } - memcpy(ble_addr.addr, bufinfo.buf, 6); - sl_bt_system_set_identity_address(ble_addr, PUBLIC_ADDRESS); + memcpy(ble_addr.addr, address->bytes, 6); + sc = sl_bt_system_set_identity_address(ble_addr, PUBLIC_ADDRESS); return sc == SL_STATUS_OK; } @@ -172,9 +153,13 @@ mp_obj_str_t *common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) { // Set name of the BLE adapter void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char *name) { + size_t len = strlen(name); + if (len > DEVICE_NAME_LEN) { + len = DEVICE_NAME_LEN; + } sl_bt_gatt_server_write_attribute_value(gattdb_device_name, 0, - DEVICE_NAME_LEN, + len, (const uint8_t *)name); } @@ -453,10 +438,8 @@ bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { // Convert mac address of remote device to connect static void _convert_address(const bleio_address_obj_t *address, bd_addr *sd_address, uint8_t *addr_type) { - mp_buffer_info_t address_buf_info; *addr_type = address->type; - mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); - memcpy(sd_address->addr, (uint8_t *)address_buf_info.buf, 6); + memcpy(sd_address->addr, address->bytes, 6); } // Add new connection into connection list @@ -640,11 +623,11 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { // Wait up to 125 ms (128 ticks) for disconnect to complete. This should be // greater than most connection intervals. start_ticks = supervisor_ticks_ms64(); - while (any_connected && supervisor_ticks_ms64() - start_ticks < 128) { + do { any_connected = false; for (conn_index = 0; conn_index < BLEIO_TOTAL_CONNECTION_COUNT; conn_index++) { connection = &bleio_connections[conn_index]; any_connected |= connection->conn_handle != BLEIO_HANDLE_INVALID; } - } + } while (any_connected && supervisor_ticks_ms64() - start_ticks < 128); } diff --git a/ports/silabs/common-hal/_bleio/Adapter.h b/ports/silabs/common-hal/_bleio/Adapter.h index d7f252df330..561785bab3f 100644 --- a/ports/silabs/common-hal/_bleio/Adapter.h +++ b/ports/silabs/common-hal/_bleio/Adapter.h @@ -29,6 +29,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" #include "supervisor/background_callback.h" @@ -54,6 +55,10 @@ typedef struct { bool user_advertising; bool is_enable; uint8_t advertising_handle; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; } bleio_adapter_obj_t; typedef struct { diff --git a/ports/silabs/common-hal/_bleio/Characteristic.c b/ports/silabs/common-hal/_bleio/Characteristic.c index 37fb792cd4d..9ccc6ad9c36 100644 --- a/ports/silabs/common-hal/_bleio/Characteristic.c +++ b/ports/silabs/common-hal/_bleio/Characteristic.c @@ -249,7 +249,7 @@ size_t common_hal_bleio_characteristic_get_value( return 0; } -// Get max length of charateristic +// Get max length of characteristic size_t common_hal_bleio_characteristic_get_max_length( bleio_characteristic_obj_t *self) { return self->max_length; @@ -373,7 +373,7 @@ void common_hal_bleio_characteristic_add_descriptor( // This indicates the new added descriptor shall be started. sc = sl_bt_gattdb_start_characteristic(gattdb_session, self->handle); if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Start charateristic fail.")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Start characteristic fail.")); return; } @@ -395,7 +395,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, const uint16_t conn_handle = bleio_connection_get_conn_handle( self->service->connection); - common_hal_bleio_check_connected(conn_handle); + bleio_check_connected(conn_handle); notify = 1; indicate = 0; if (notify) { diff --git a/ports/silabs/common-hal/_bleio/Connection.c b/ports/silabs/common-hal/_bleio/Connection.c index 94e556dd0bf..4f5da679931 100644 --- a/ports/silabs/common-hal/_bleio/Connection.c +++ b/ports/silabs/common-hal/_bleio/Connection.c @@ -57,6 +57,21 @@ bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { return self->connection->pair_status == PAIR_PAIRED; } +// Authenticated (MITM-protected) pairing - numeric comparison - is implemented on the +// espressif port only. This port can't tell a "Just Works" bond from an authenticated +// one, so report the conservative answer rather than a guarantee it can't make. +bool common_hal_bleio_connection_get_authenticated(bleio_connection_obj_t *self) { + return false; +} + +mp_obj_t common_hal_bleio_connection_get_numeric_comparison(bleio_connection_obj_t *self) { + return mp_const_none; +} + +void common_hal_bleio_connection_confirm_pairing(bleio_connection_obj_t *self, bool accept) { + mp_raise_NotImplementedError(NULL); +} + // Get connected status bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) { if (self->connection == NULL) { diff --git a/ports/silabs/common-hal/_bleio/Connection.h b/ports/silabs/common-hal/_bleio/Connection.h index 56872024c93..148caecba11 100644 --- a/ports/silabs/common-hal/_bleio/Connection.h +++ b/ports/silabs/common-hal/_bleio/Connection.h @@ -85,6 +85,7 @@ typedef struct void bleio_connection_clear(bleio_connection_internal_t *self); +void bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal( diff --git a/ports/silabs/common-hal/_bleio/PacketBuffer.c b/ports/silabs/common-hal/_bleio/PacketBuffer.c index dec833fe62f..291523e0a6d 100644 --- a/ports/silabs/common-hal/_bleio/PacketBuffer.c +++ b/ports/silabs/common-hal/_bleio/PacketBuffer.c @@ -145,7 +145,7 @@ void _common_hal_bleio_packet_buffer_construct( uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, - ble_event_handler_t static_handler_entry) { + ble_event_handler_t *static_handler_entry) { bleio_characteristic_properties_t temp_prop; self->characteristic = characteristic; @@ -387,6 +387,8 @@ bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { if (!common_hal_bleio_packet_buffer_deinited(self)) { ringbuf_deinit(&self->ringbuf); + // Mark as deinited, so common_hal_bleio_packet_buffer_deinited() reports it. + self->characteristic = NULL; } } diff --git a/ports/silabs/common-hal/_bleio/Service.c b/ports/silabs/common-hal/_bleio/Service.c index abc8ffe74ed..50f0c4593a6 100644 --- a/ports/silabs/common-hal/_bleio/Service.c +++ b/ports/silabs/common-hal/_bleio/Service.c @@ -128,7 +128,7 @@ bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { return self->uuid; } -// Get tuple charateristic of service +// Get tuple characteristic of service mp_obj_tuple_t *common_hal_bleio_service_get_characteristics( bleio_service_obj_t *self) { return mp_obj_new_tuple(self->characteristic_list->len, @@ -210,19 +210,19 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, } if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Add charateristic fail.")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Add characteristic fail.")); } sc = sl_bt_gattdb_start_characteristic(gattdb_session, characteristic->handle); if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Start charateristic fail.")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Start characteristic fail.")); return; } sc = sl_bt_gattdb_commit(gattdb_session); if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Commit charateristic fail.")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Commit characteristic fail.")); return; } mp_obj_list_append(self->characteristic_list, diff --git a/ports/silabs/common-hal/_bleio/__init__.c b/ports/silabs/common-hal/_bleio/__init__.c index c6ae8a0b606..4c5ce1f045d 100644 --- a/ports/silabs/common-hal/_bleio/__init__.c +++ b/ports/silabs/common-hal/_bleio/__init__.c @@ -102,7 +102,7 @@ void check_ble_error(int error_code) { } } -void common_hal_bleio_check_connected(uint16_t conn_handle) { +void bleio_check_connected(uint16_t conn_handle) { if (conn_handle == BLEIO_HANDLE_INVALID) { mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected")); } diff --git a/ports/silabs/common-hal/_bleio/__init__.h b/ports/silabs/common-hal/_bleio/__init__.h index 63eda59d84f..4ecd6456b8b 100644 --- a/ports/silabs/common-hal/_bleio/__init__.h +++ b/ports/silabs/common-hal/_bleio/__init__.h @@ -61,12 +61,6 @@ // Maximum length for variable length Attribute Values. #define BLE_GATTS_VAR_ATTR_LEN_MAX (512) -// Track if the user code modified the BLE state -// to know if we need to undo it on reload. -extern bool vm_used_ble; - -// UUID shared by all CCCD's. -extern bleio_uuid_obj_t cccd_uuid; extern void bleio_reset(); extern osMutexId_t bluetooth_connection_mutex_id; diff --git a/ports/silabs/common-hal/busio/I2C.c b/ports/silabs/common-hal/busio/I2C.c index ae18f561c50..6c2b04d821d 100644 --- a/ports/silabs/common-hal/busio/I2C.c +++ b/ports/silabs/common-hal/busio/I2C.c @@ -145,7 +145,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } // Write data to the device selected by address -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { I2C_TransferSeq_TypeDef seq; @@ -159,13 +159,13 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, ret = I2CSPM_Transfer(self->i2cspm, &seq); if (ret != i2cTransferDone) { - return MP_EIO; + return -MP_EIO; } return 0; } // Read into buffer from the device selected by address -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { @@ -180,13 +180,13 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, ret = I2CSPM_Transfer(self->i2cspm, &seq); if (ret != i2cTransferDone) { - return MP_EIO; + return -MP_EIO; } return 0; } // Write the bytes from out_data to the device selected by address, -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { @@ -204,7 +204,7 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, ret = I2CSPM_Transfer(self->i2cspm, &seq); if (ret != i2cTransferDone) { - return MP_EIO; + return -MP_EIO; } return 0; } diff --git a/ports/silabs/common-hal/busio/SPI.c b/ports/silabs/common-hal/busio/SPI.c index 74cfc69bfb2..fb3b7c4fd20 100644 --- a/ports/silabs/common-hal/busio/SPI.c +++ b/ports/silabs/common-hal/busio/SPI.c @@ -37,16 +37,6 @@ static SPIDRV_HandleData_t spidrv_eusart_handle; static SPIDRV_Init_t spidrv_eusart_init = SPIDRV_MASTER_EUSART1; static bool in_used = false; -static bool never_reset = false; - -// Reset SPI when reload -void spi_reset(void) { - if (!never_reset && in_used) { - SPIDRV_DeInit(&spidrv_eusart_handle); - in_used = false; - } - return; -} // Construct SPI protocol, this function init SPI peripheral void common_hal_busio_spi_construct(busio_spi_obj_t *self, @@ -61,6 +51,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, MP_ERROR_TEXT("Half duplex SPI is not implemented")); } + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + if ((sck != NULL) && (mosi != NULL) && (miso != NULL)) { if (sck->function_list[FN_EUSART1_SCLK] == 1 && miso->function_list[FN_EUSART1_RX] == 1 @@ -108,7 +101,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Never reset SPI when reload void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset = true; common_hal_never_reset_pin(self->mosi); common_hal_never_reset_pin(self->miso); common_hal_never_reset_pin(self->sck); @@ -119,6 +111,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->sck == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->sck = NULL; +} + // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { @@ -132,13 +128,14 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } in_used = false; - self->sck = NULL; self->mosi = NULL; self->miso = NULL; self->handle = NULL; common_hal_reset_pin(self->mosi); common_hal_reset_pin(self->miso); common_hal_reset_pin(self->sck); + + common_hal_busio_spi_mark_deinit(self); } // Configures the SPI bus. The SPI object must be locked. diff --git a/ports/silabs/common-hal/microcontroller/Processor.c b/ports/silabs/common-hal/microcontroller/Processor.c index 226fe4529fb..741a147d1cf 100644 --- a/ports/silabs/common-hal/microcontroller/Processor.c +++ b/ports/silabs/common-hal/microcontroller/Processor.c @@ -62,5 +62,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/silabs/common-hal/microcontroller/__init__.c b/ports/silabs/common-hal/microcontroller/__init__.c index b1472fcf437..7244af6619d 100644 --- a/ports/silabs/common-hal/microcontroller/__init__.c +++ b/ports/silabs/common-hal/microcontroller/__init__.c @@ -60,6 +60,9 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { } } +// CHIP_Reset does not return, but is not declared as such in the SDK. +void __attribute__ ((noreturn)) CHIP_Reset(void); + void common_hal_mcu_reset(void) { filesystem_flush(); // TODO: implement as part of flash improvements CHIP_Reset(); diff --git a/ports/silabs/supervisor/port.c b/ports/silabs/supervisor/port.c index 2409e907dea..85a6e0f92a5 100644 --- a/ports/silabs/supervisor/port.c +++ b/ports/silabs/supervisor/port.c @@ -156,10 +156,7 @@ safe_mode_t port_init(void) { } void reset_port(void) { - reset_all_pins(); - #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif diff --git a/ports/stm/Makefile b/ports/stm/Makefile index 9db283767e0..f7c17ea8d42 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -38,8 +38,7 @@ ifeq ($(DEBUG), 1) CFLAGS += -fno-inline -fno-ipa-sra else CFLAGS += -DNDEBUG - OPTIMIZATION_FLAGS ?= -O2 -fno-inline-functions - CFLAGS += -ggdb3 + OPTIMIZATION_FLAGS ?= -O2 endif # to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk @@ -206,16 +205,19 @@ endif ifneq ($(CIRCUITPY_USB),0) ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32L433xx)) SRC_C += lib/tinyusb/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + SRC_C += lib/tinyusb/src/portable/st/stm32_fsdev/fsdev_common.c else SRC_C += lib/tinyusb/src/portable/synopsys/dwc2/dcd_dwc2.c SRC_C += lib/tinyusb/src/portable/synopsys/dwc2/dwc2_common.c endif endif -SRC_S_UPPER = supervisor/shared/cpu_regs.S SRC_S = \ + shared/runtime/gchelper_thumb1.s \ st_driver/cmsis_device_$(MCU_SERIES_LOWER)/Source/Templates/gcc/startup_$(MCU_VARIANT_LOWER).s +SRC_C += shared/runtime/gchelper_native.c + ifneq ($(FROZEN_MPY_DIR),) FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) @@ -229,7 +231,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os @@ -256,7 +257,7 @@ $(BUILD)/firmware.elf: $(OBJ) $(STEPECHO) "LINK $@" $(Q)echo $^ > $(BUILD)/firmware.objs $(Q)$(CC) -o $@ $(LDFLAGS) @$(BUILD)/firmware.objs -Wl,--print-memory-usage -Wl,--start-group $(LIBS) -Wl,--end-group - $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $(LD_FILE) $(BUILD) + $(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $@.map $(BUILD) endif $(BUILD)/firmware.bin: $(BUILD)/firmware.elf diff --git a/ports/stm/boards/common_default.ld b/ports/stm/boards/common_default.ld index 7c96a42bc56..62a6d63d11c 100644 --- a/ports/stm/boards/common_default.ld +++ b/ports/stm/boards/common_default.ld @@ -35,6 +35,12 @@ SECTIONS .text : { . = ALIGN(4); + __property_getter_start = .; + *(.property_getter) + __property_getter_end = .; + __property_getset_start = .; + *(.property_getset) + __property_getset_end = .; *(.text*) /* .text* sections (code) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ /* *(.glue_7) */ /* glue arm to thumb code */ @@ -95,4 +101,9 @@ SECTIONS .ARM.attributes 0 : { *(.ARM.attributes) } + + ASSERT((__property_getter_end - __property_getter_start) % 8 == 0, + "the .property_getter section must hold whole 8-byte objects") + ASSERT((__property_getset_end - __property_getset_start) % 12 == 0, + "the .property_getset section must hold whole 12-byte objects") } diff --git a/ports/stm/boards/common_nvm.ld b/ports/stm/boards/common_nvm.ld index 1d10db8a314..f2a0456e000 100644 --- a/ports/stm/boards/common_nvm.ld +++ b/ports/stm/boards/common_nvm.ld @@ -45,6 +45,12 @@ SECTIONS .text : { . = ALIGN(4); + __property_getter_start = .; + *(.property_getter) + __property_getter_end = .; + __property_getset_start = .; + *(.property_getset) + __property_getset_end = .; *(.text*) /* .text* sections (code) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ /* *(.glue_7) */ /* glue arm to thumb code */ @@ -105,4 +111,9 @@ SECTIONS .ARM.attributes 0 : { *(.ARM.attributes) } + + ASSERT((__property_getter_end - __property_getter_start) % 8 == 0, + "the .property_getter section must hold whole 8-byte objects") + ASSERT((__property_getset_end - __property_getset_start) % 12 == 0, + "the .property_getset section must hold whole 12-byte objects") } diff --git a/ports/stm/boards/common_tcm.ld b/ports/stm/boards/common_tcm.ld index 6301dbf315b..18c284f965a 100644 --- a/ports/stm/boards/common_tcm.ld +++ b/ports/stm/boards/common_tcm.ld @@ -37,6 +37,12 @@ SECTIONS .text : { . = ALIGN(4); + __property_getter_start = .; + *(.property_getter) + __property_getter_end = .; + __property_getset_start = .; + *(.property_getset) + __property_getset_end = .; *(.text*) /* .text* sections (code) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ /* *(.glue_7) */ /* glue arm to thumb code */ @@ -146,4 +152,9 @@ SECTIONS } >FLASH_FIRMWARE .ARM.attributes 0 : { *(.ARM.attributes) } + + ASSERT((__property_getter_end - __property_getter_start) % 8 == 0, + "the .property_getter section must hold whole 8-byte objects") + ASSERT((__property_getset_end - __property_getset_start) % 12 == 0, + "the .property_getset section must hold whole 12-byte objects") } diff --git a/ports/stm/boards/espruino_pico/README.md b/ports/stm/boards/espruino_pico/README.md index 86df1ad32a3..d930e9aeca3 100644 --- a/ports/stm/boards/espruino_pico/README.md +++ b/ports/stm/boards/espruino_pico/README.md @@ -12,4 +12,4 @@ The Espruino Pico is normally updated via a bootloader activated by the Espruino - Restart the board. -To reinstall Espruino, follow the same steps with the latest Espruino Pico binary from espruino.com/binaries. This will reinstall the usual Espruino bootloader. You must un-short the BOOT0/BTN jumper to re-use the original Espruino Bootloader again. If you used a Pencil mark then you may need to use cleaning fluid and a small brush to totally clear out the graphite. +To reinstall Espruino, follow the same steps with the latest Espruino Pico binary from espruino.com/binaries. This will reinstall the usual Espruino bootloader. You must un-short the BOOT0/BTN jumper to reuse the original Espruino Bootloader again. If you used a Pencil mark then you may need to use cleaning fluid and a small brush to totally clear out the graphite. diff --git a/ports/stm/boards/espruino_wifi/README.MD b/ports/stm/boards/espruino_wifi/README.MD index cc78811f1c7..cebe99bf6d1 100644 --- a/ports/stm/boards/espruino_wifi/README.MD +++ b/ports/stm/boards/espruino_wifi/README.MD @@ -12,4 +12,4 @@ The Espruino Wifi is normally updated via a bootloader activated by the Espruino - Restart the board. -To reinstall Espruino, follow the same steps with the latest Espruino Wifi binary from espruino.com/binaries. This will reinstall the usual Espruino bootloader. You must un-short the BOOT0/BTN jumper to re-use the original Espruino Bootloader again. If you used a Pencil mark then you may need to use cleaning fluid and a small brush to totally clear out the graphite. +To reinstall Espruino, follow the same steps with the latest Espruino Wifi binary from espruino.com/binaries. This will reinstall the usual Espruino bootloader. You must un-short the BOOT0/BTN jumper to reuse the original Espruino Bootloader again. If you used a Pencil mark then you may need to use cleaning fluid and a small brush to totally clear out the graphite. diff --git a/ports/stm/boards/meowbit_v121/board.c b/ports/stm/boards/meowbit_v121/board.c index 181f433a372..c3c745f64a1 100644 --- a/ports/stm/boards/meowbit_v121/board.c +++ b/ports/stm/boards/meowbit_v121/board.c @@ -55,9 +55,9 @@ void board_init(void) { busio_spi_obj_t *internal_spi = &supervisor_flash_spi_bus; common_hal_fourwire_fourwire_construct(bus, internal_spi, - &pin_PA08, // Command or data - &pin_PB12, // Chip select - &pin_PB10, // Reset + MP_OBJ_FROM_PTR(&pin_PA08), // Command or data + MP_OBJ_FROM_PTR(&pin_PB12), // Chip select + MP_OBJ_FROM_PTR(&pin_PB10), // Reset 24000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.mk b/ports/stm/boards/meowbit_v121/mpconfigboard.mk index 3a128fb8343..271c4cd775c 100644 --- a/ports/stm/boards/meowbit_v121/mpconfigboard.mk +++ b/ports/stm/boards/meowbit_v121/mpconfigboard.mk @@ -23,6 +23,7 @@ LD_FILE = boards/STM32F401xe_boot.ld # LD_FILE = boards/STM32F401xe_fs.ld CIRCUITPY_AESIO = 0 +CIRCUITPY_CODEOP = 0 CIRCUITPY_BITMAPFILTER = 0 CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_BLEIO_HCI = 0 @@ -30,6 +31,8 @@ CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_I2CDISPLAYBUS = 0 CIRCUITPY_KEYPAD_DEMUX = 0 +CIRCUITPY_MSGPACK = 0 +CIRCUITPY_PIXELMAP = 0 CIRCUITPY_SHARPDISPLAY = 0 CIRCUITPY_TILEPALETTEMAPPER = 0 CIRCUITPY_ULAB = 0 @@ -37,4 +40,6 @@ CIRCUITPY_ZLIB = 0 CIRCUITPY_STAGE = 1 +CIRCUITPY_DIGITALINOUT_PROTOCOL = 0 + FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/meowbit diff --git a/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.mk b/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.mk index 64be6f4f142..c46a270df65 100644 --- a/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.mk +++ b/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.mk @@ -9,6 +9,7 @@ EXTERNAL_FLASH_DEVICES = GD25Q16C,W25Q16JVxQ,W25Q64FV,W25Q32JVxQ,W25Q64JVxQ LONGINT_IMPL = MPZ INTERNAL_FLASH_FILESYSTEM = 0 +OPTIMIZATION_FLAGS = -Os MCU_SERIES = F4 MCU_VARIANT = STM32F411xE diff --git a/ports/stm/common-hal/alarm/__init__.c b/ports/stm/common-hal/alarm/__init__.c index 3d6c4466882..4cdf01b7f25 100644 --- a/ports/stm/common-hal/alarm/__init__.c +++ b/ports/stm/common-hal/alarm/__init__.c @@ -129,13 +129,10 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj } void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { - if (n_dios > 0) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); - } _setup_sleep_alarms(true, n_alarms, alarms); } -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_set_wakeup_reason(STM_WAKEUP_UNDEF); alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_time_timealarm_prepare_for_deep_sleep(); diff --git a/ports/stm/common-hal/analogio/AnalogOut.h b/ports/stm/common-hal/analogio/AnalogOut.h index 6a8fc2720bf..33c8abc21f8 100644 --- a/ports/stm/common-hal/analogio/AnalogOut.h +++ b/ports/stm/common-hal/analogio/AnalogOut.h @@ -28,3 +28,9 @@ typedef struct { } analogio_analogout_obj_t; void analogout_reset(void); + +// Shared DAC peripheral handle (defined in AnalogOut.c). +// AudioOut reuses this handle for DMA-triggered DAC operation on channel 1. +#if HAS_DAC +extern DAC_HandleTypeDef handle; +#endif diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c new file mode 100644 index 00000000000..e5dd620521c --- /dev/null +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -0,0 +1,782 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// DAC-based audio output for STM32F405 / STM32F407. +// +// Architecture: +// TIM6 (basic timer) generates an update event at the sample rate. +// DAC_CHANNEL_1 (PA04) is configured with DAC_TRIGGER_T6_TRGO so each +// TIM6 update latches the next sample from the DMA FIFO. +// DMA1 Stream5 Channel7 operates in circular mode, feeding 16-bit samples +// from a double-buffer. Stereo additionally drives DAC_CHANNEL_2 (PA05) +// via DMA1 Stream6 Channel7, sharing the same TIM6 trigger. +// The DMA half-complete and complete callbacks queue a background_callback +// to refill the idle half from the audio sample source. +// +// The shared DAC handle (declared in AnalogOut.c) is reused here so both +// modules share state consistently and avoid double-init conflicts. Pin +// claims (common_hal_mcu_pin_claim) act as the inter-module mutex: a second +// AudioOut, or an AnalogOut on the same pin, fails at the claim step. + +#include + +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/mphal.h" + +#include "common-hal/audioio/AudioOut.h" +#include "shared-bindings/audioio/AudioOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" +#include "supervisor/background_callback.h" + +#include STM32_HAL_H + +// Shared DAC handle declared in common-hal/analogio/AnalogOut.h. +// AudioOut reconfigures channel 1 (and 2 for stereo) for DMA-triggered +// operation and restores the no-trigger config on deinit so AnalogOut can +// resume use of the channel afterwards. +#include "common-hal/analogio/AnalogOut.h" + +// Highest sample rate accepted by play(). 1 MHz mirrors atmel-samd's SAMD51 +// limit and is comfortably above any reasonable audio rate; the real hardware +// ceiling is TIM6_CLK / 2 (~42 MHz on F405) but rates that high would just +// underrun the DMA refill path. +#define AUDIOOUT_MAX_SAMPLE_RATE 1000000u + +// TIM6 handle: only one instance ever active, so file-scope is fine. +static TIM_HandleTypeDef tim6_handle; + +// Pointer to the currently active AudioOut object, used by IRQ handlers. +// Pin claims prevent two instances from existing simultaneously, but this +// pointer is also used to early-out IRQs after stop(). +static audioio_audioout_obj_t *active_audioout = NULL; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +// Return the TIM6 input clock frequency in Hz. +// TIM6 sits on APB1. The clock is doubled when the APB1 prescaler != 1 +// (same logic as stm_peripherals_timer_get_source_freq in timers.c but +// applied directly to APB1 since TIM6 is not in mcu_tim_banks[]). +static uint32_t get_tim6_freq(void) { + uint32_t apb1 = HAL_RCC_GetPCLK1Freq(); + uint32_t ppre1 = (RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos; + #if defined(RCC_DCKCFGR_TIMPRE) + uint32_t timpre = RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE; + if (timpre == 0) { + return (ppre1 >= 0b100) ? apb1 * 2 : apb1; + } else { + return (ppre1 > 0b101) ? apb1 * 4 : HAL_RCC_GetHCLKFreq(); + } + #else + return (ppre1 >= 0b100) ? apb1 * 2 : apb1; + #endif +} + +// Gently ramp the given DAC channel output from from_12 to to_12 (both 12-bit, +// 0-4095) to avoid audible clicks. 64 steps × 100 µs/step = ~6.4 ms total; +// shrink the step count and clicks reappear on the F405 output stage. +static void dac_ramp_channel(uint32_t channel, uint32_t from_12, uint32_t to_12) { + if (from_12 == to_12) { + return; + } + int32_t delta = (int32_t)to_12 - (int32_t)from_12; + int32_t step = delta / 64; + if (step == 0) { + step = (delta > 0) ? 1 : -1; + } + int32_t v = (int32_t)from_12; + while (true) { + v += step; + if (step > 0 && v >= (int32_t)to_12) { + v = (int32_t)to_12; + } else if (step < 0 && v <= (int32_t)to_12) { + v = (int32_t)to_12; + } + HAL_DAC_SetValue(&handle, channel, DAC_ALIGN_12B_R, (uint16_t)v); + HAL_DAC_Start(&handle, channel); + mp_hal_delay_us(100); + if (v == (int32_t)to_12) { + break; + } + } +} + +static inline void dac_ramp(uint32_t from_12, uint32_t to_12) { + dac_ramp_channel(DAC_CHANNEL_1, from_12, to_12); +} + +// Convert a buffer of audio samples into 12-bit unsigned DAC values and write +// them into dest[]. Returns the number of DAC samples written; the caller is +// responsible for padding any remaining dest entries with the quiescent value. +// +// NOTE: ports/espressif/common-hal/audioio/AudioOut.c implements the same +// idea with a CONV_MATCH lookup table dispatching to per-format helpers in +// shared-module/audiocore — a more general-purpose pattern. If a future +// refactor lifts a 12-bit DAC variant into shared-module/audiocore, both +// this driver and any other ARM-DAC port could share it. +// +// src - raw sample bytes from audiosample_get_buffer +// src_len - byte length of src +// dest - output array of 12-bit DAC values (uint16_t) +// dest_count - capacity of dest in samples +// bytes_per_sample - 1 or 2 +// samples_signed - true if source samples are signed +// channel_count - 1 (mono) or 2 (stereo) +// channel_offset - 0 for left/mono, 1 for right channel of a stereo stream +static uint32_t convert_to_dac12( + const uint8_t *src, uint32_t src_len, + uint16_t *dest, uint32_t dest_count, + uint8_t bytes_per_sample, bool samples_signed, + uint8_t channel_count, uint8_t channel_offset) { + + // src_stride: bytes between consecutive samples of the same channel + uint32_t src_stride = (uint32_t)bytes_per_sample * channel_count; + // src_offset: byte offset to the desired channel within each frame + uint32_t src_offset = (uint32_t)bytes_per_sample * channel_offset; + uint32_t src_frames = src_len / src_stride; + uint32_t frames = (src_frames < dest_count) ? src_frames : dest_count; + + if (bytes_per_sample == 1) { + for (uint32_t i = 0; i < frames; i++) { + uint8_t u8 = src[i * src_stride + src_offset]; + int32_t s = samples_signed + ? (int32_t)(int8_t)u8 + : (int32_t)u8 - 128; + dest[i] = (uint16_t)((s + 128) & 0xFF) << 4; + } + } else { + for (uint32_t i = 0; i < frames; i++) { + uint16_t u16; + memcpy(&u16, src + i * src_stride + src_offset, 2); + int32_t s = samples_signed + ? (int32_t)(int16_t)u16 + : (int32_t)u16 - 0x8000; + dest[i] = (uint16_t)((s + 0x8000) & 0xFFFF) >> 4; + } + } + return frames; +} + +// Pad [filled, AUDIOOUT_DMA_HALF_SAMPLES) of dest_l (and dest_r if non-NULL) +// with the quiescent value. Used at end-of-stream and on errors so the DAC +// returns smoothly to its resting voltage. +static void pad_quiescent(uint16_t *dest_l, uint16_t *dest_r, + uint32_t filled, uint16_t quiescent_12) { + for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { + dest_l[i] = quiescent_12; + if (dest_r) { + dest_r[i] = quiescent_12; + } + } +} + +// Load one half of the DMA circular buffer from the audio sample source. +// half: 0 = lower half (indices 0..HALF-1), 1 = upper half (HALF..END-1). +// +// Tracks position within the source buffer (src_ptr / src_remaining_len) +// across calls so that large source buffers (e.g. a 1024-sample RawSample) +// are consumed incrementally rather than re-reading from the start each time. +static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { + uint16_t *dest_l = self->dma_buffer + ((uint32_t)half * AUDIOOUT_DMA_HALF_SAMPLES); + uint16_t *dest_r = self->dma_buffer_r + ? self->dma_buffer_r + ((uint32_t)half * AUDIOOUT_DMA_HALF_SAMPLES) + : NULL; + uint16_t quiescent_12 = self->quiescent_value >> 4; + uint32_t src_stride = (uint32_t)self->bytes_per_sample * self->channel_count; + uint32_t filled = 0; + + while (filled < AUDIOOUT_DMA_HALF_SAMPLES) { + // Fetch new source data when the previous buffer is exhausted. + if (self->src_remaining_len == 0) { + // Handle end-of-stream from previous get_buffer call. + if (self->src_done) { + if (self->loop) { + audiosample_reset_buffer(self->sample, + self->channel_count == 1, 0); + self->src_done = false; + } else { + pad_quiescent(dest_l, dest_r, filled, quiescent_12); + self->stopping = true; + return; + } + } + + uint8_t *buf; + uint32_t len; + audioio_get_buffer_result_t result = + audiosample_get_buffer(self->sample, + self->channel_count == 1, 0, &buf, &len); + + if (result == GET_BUFFER_ERROR) { + pad_quiescent(dest_l, dest_r, filled, quiescent_12); + self->stopping = true; + return; + } + + self->src_ptr = buf; + self->src_remaining_len = len; + self->src_done = (result == GET_BUFFER_DONE); + } + + uint32_t written = convert_to_dac12( + self->src_ptr, self->src_remaining_len, + dest_l + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, + self->bytes_per_sample, self->samples_signed, + self->channel_count, 0); + + if (dest_r) { + uint8_t r_offset = (self->channel_count >= 2) ? 1 : 0; + convert_to_dac12( + self->src_ptr, self->src_remaining_len, + dest_r + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, + self->bytes_per_sample, self->samples_signed, + self->channel_count, r_offset); + } + + if (written == 0) { + // src had fewer than src_stride bytes left (e.g. a corrupt WAV + // returned an odd byte count for 16-bit data). Drop the partial + // frame so the next loop iteration calls get_buffer for fresh, + // aligned data — without this the loop spins forever because + // neither filled nor src_remaining_len would advance. + self->src_remaining_len = 0; + continue; + } + + // Advance source position by the amount consumed. + uint32_t bytes_consumed = written * src_stride; + self->src_ptr += bytes_consumed; + self->src_remaining_len -= bytes_consumed; + filled += written; + } +} + +// Background callback: called from the main loop after a DMA half/full event. +static void audioout_fill_callback(void *arg) { + audioio_audioout_obj_t *self = (audioio_audioout_obj_t *)arg; + if (!self || active_audioout != self) { + return; + } + if (self->stopping) { + common_hal_audioio_audioout_stop(self); + return; + } + uint8_t mask; + __disable_irq(); + mask = self->halves_to_fill; + self->halves_to_fill = 0; + __enable_irq(); + if (mask & 0x1) { + load_dma_buffer_half(self, 0); + } + if (mask & 0x2) { + load_dma_buffer_half(self, 1); + } +} + +// --------------------------------------------------------------------------- +// IRQ handlers +// +// DMA1 Stream5/6 are claimed exclusively for DAC use here. If a future port +// change wires another peripheral onto either stream the weak-symbol override +// below will collide silently — add a build-time assertion in that file. +// --------------------------------------------------------------------------- + +void DMA1_Stream5_IRQHandler(void) { + if (active_audioout) { + HAL_DMA_IRQHandler(&active_audioout->dma_handle_l); + } +} + +void DMA1_Stream6_IRQHandler(void) { + if (active_audioout && active_audioout->dma_buffer_r) { + HAL_DMA_IRQHandler(&active_audioout->dma_handle_r); + } +} + +// HAL weak-symbol overrides: called from HAL_DMA_IRQHandler context. +// +// Only the Ch1 (left) callbacks are overridden. The Stream6 IRQ for the +// right channel still calls HAL_DACEx_ConvHalfCpltCallbackCh2 / +// HAL_DACEx_ConvCpltCallbackCh2 (the default empty weak implementations) — +// that is intentional. Both DMA streams are clocked by the same TIM6 trigger +// and started together, so their NDTR counters stay in lock-step. Refilling +// from the left-channel IRQ alone is sufficient and avoids redundant work. + +void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) { + if (active_audioout && !active_audioout->paused) { + active_audioout->halves_to_fill |= 0x1; + background_callback_add(&active_audioout->callback, + audioout_fill_callback, active_audioout); + } +} + +void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac) { + if (active_audioout && !active_audioout->paused) { + active_audioout->halves_to_fill |= 0x2; + background_callback_add(&active_audioout->callback, + audioout_fill_callback, active_audioout); + } +} + +// --------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------- + +void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, + const mcu_pin_obj_t *left_channel, const mcu_pin_obj_t *right_channel, + uint16_t quiescent_value) { + + #if !HAS_DAC + mp_raise_ValueError(MP_ERROR_TEXT("No DAC on chip")); + #else + + // Only PA04 (DAC_CH1) is supported as left channel. + if (left_channel != &pin_PA04) { + raise_ValueError_invalid_pin_name(MP_QSTR_left_channel); + } + + // Right channel must be PA05 (DAC_CH2 / A1) if provided. + if (right_channel != NULL && right_channel != &pin_PA05) { + raise_ValueError_invalid_pin_name(MP_QSTR_right_channel); + } + + // Claim pins first. The pin-claim system is what serialises this driver + // against another AudioOut instance and against AnalogOut on the same + // pins — if either is already using PA04/PA05 the claim raises here, and + // because nothing else is configured yet, no cleanup is needed. + // + // NOTE: ports/atmel-samd/common-hal/audioio/AudioOut.c also claims pins + // first but L242 raises *after* claiming a timer and event channel + // without releasing them on the error path; worth a follow-up there. + common_hal_mcu_pin_claim(left_channel); + if (right_channel != NULL) { + common_hal_mcu_pin_claim(right_channel); + } + + self->left_channel = left_channel; + self->right_channel = right_channel; + self->quiescent_value = quiescent_value; + self->sample = MP_OBJ_NULL; + self->dma_buffer = NULL; + self->dma_buffer_r = NULL; + memset(&self->dma_handle_l, 0, sizeof(self->dma_handle_l)); + memset(&self->dma_handle_r, 0, sizeof(self->dma_handle_r)); + memset(&self->callback, 0, sizeof(self->callback)); + self->stopping = false; + self->paused = false; + self->playing = false; + + // Configure PA04 (and PA05 if stereo) for analog (DAC) mode. + GPIO_InitTypeDef gpio_init = {0}; + gpio_init.Pin = pin_mask(left_channel->number); + gpio_init.Mode = GPIO_MODE_ANALOG; + gpio_init.Pull = GPIO_NOPULL; + HAL_GPIO_Init(pin_port(left_channel->port), &gpio_init); + + if (right_channel != NULL) { + gpio_init.Pin = pin_mask(right_channel->number); + HAL_GPIO_Init(pin_port(right_channel->port), &gpio_init); + } + + // Initialise the shared DAC handle if it hasn't been set up yet + // (i.e. AnalogOut hasn't been used since last reset). __HAL_RCC_DAC_CLK_ENABLE + // is idempotent so calling it unconditionally would be safe too, but + // matching AnalogOut's check keeps the two modules in sync. + if (handle.Instance == NULL || handle.State == HAL_DAC_STATE_RESET) { + __HAL_RCC_DAC_CLK_ENABLE(); + handle.Instance = DAC; + if (HAL_DAC_Init(&handle) != HAL_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("DAC Device Init Error")); + } + } + + // Configure DAC channel 1 with no trigger so the ramp below works + // immediately. play() switches the trigger to TIM6_TRGO. + DAC_ChannelConfTypeDef ch_cfg = {0}; + ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; + ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + if (HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1) != HAL_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("DAC Channel Init Error")); + } + + // Ramp DAC output up to quiescent value to prevent an audible pop. + HAL_DAC_SetValue(&handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0); + HAL_DAC_Start(&handle, DAC_CHANNEL_1); + dac_ramp(0, quiescent_value >> 4); + #endif +} + +bool common_hal_audioio_audioout_deinited(audioio_audioout_obj_t *self) { + return self->left_channel == NULL; +} + +void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t *self) { + if (common_hal_audioio_audioout_deinited(self)) { + return; + } + + common_hal_audioio_audioout_stop(self); + + // Ramp DAC back to zero before disconnecting. + dac_ramp(self->quiescent_value >> 4, 0); + HAL_DAC_Stop(&handle, DAC_CHANNEL_1); + + // Restore channels to no-trigger mode so AnalogOut can use them again. + DAC_ChannelConfTypeDef ch_cfg = {0}; + ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; + ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); + if (self->right_channel != NULL) { + HAL_DAC_Stop(&handle, DAC_CHANNEL_2); + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_2); + reset_pin_number(self->right_channel->port, self->right_channel->number); + self->right_channel = NULL; + } + + // Release the left pin. Let AnalogOut manage DAC clock disable. + reset_pin_number(self->left_channel->port, self->left_channel->number); + self->left_channel = NULL; +} + +void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, + mp_obj_t sample, bool loop) { + // The shared-bindings layer guards every entry point with + // check_for_deinit, so a deinited self can't reach this function. + common_hal_audioio_audioout_stop(self); + + // Extract sample format metadata via the canonical accessors so the + // shared sample-protocol contract is honoured. + audiosample_base_t *base = audiosample_check(sample); + self->bytes_per_sample = audiosample_get_bits_per_sample(base) / 8; + self->samples_signed = base->samples_signed; + self->channel_count = audiosample_get_channel_count(base); + uint32_t sample_rate = audiosample_get_sample_rate(base); + mp_arg_validate_int_min(sample_rate, 1, MP_QSTR_sample_rate); + mp_arg_validate_int_max(sample_rate, AUDIOOUT_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); + + self->sample = sample; + self->loop = loop; + self->stopping = false; + self->paused = false; + self->playing = false; + self->halves_to_fill = 0; + self->src_ptr = NULL; + self->src_remaining_len = 0; + self->src_done = false; + + // Allocate DMA circular buffer(s). m_malloc_without_collect avoids + // triggering a GC cycle while the DAC is mid-configure; m_malloc itself + // raises on failure so no null check is needed. + // + // NOTE: ports/atmel-samd uses plain m_malloc for its audio_dma scratch + // buffers — the same GC-during-fill risk applies and should be migrated + // to m_malloc_without_collect for symmetry with espressif and stm. + self->dma_buffer = (uint16_t *)m_malloc_without_collect( + AUDIOOUT_DMA_BUFFER_SAMPLES * sizeof(uint16_t)); + if (self->right_channel != NULL) { + self->dma_buffer_r = (uint16_t *)m_malloc_without_collect( + AUDIOOUT_DMA_BUFFER_SAMPLES * sizeof(uint16_t)); + } + + // Pre-fill both halves before starting DMA. single_channel_output is + // true when this AudioOut renders only one DAC channel; for stereo + // output we want the audiocore to deliver interleaved frames. + bool single_channel_output = (self->right_channel == NULL); + audiosample_reset_buffer(sample, single_channel_output, 0); + load_dma_buffer_half(self, 0); + load_dma_buffer_half(self, 1); + + // Ramp from quiescent to the first sample so the transition into + // DMA-driven output is glitch-free. The DAC is still in single-mode + // (DAC_TRIGGER_NONE) at this point, set up by construct() / stop(), + // so HAL_DAC_SetValue takes effect immediately. After the ramp the + // pin is sitting at exactly dma_buffer[0], which is also the first + // value the timer-triggered DMA will latch. + uint16_t quiescent_12 = self->quiescent_value >> 4; + dac_ramp_channel(DAC_CHANNEL_1, quiescent_12, self->dma_buffer[0]); + if (self->right_channel != NULL) { + // CH2 was not started in construct(), so it has been outputting + // its reset value (0). Ramp from there. + dac_ramp_channel(DAC_CHANNEL_2, 0, self->dma_buffer_r[0]); + } + + // --- TIM6 setup --- + // TIM6 is a basic timer on APB1. It is not managed by the common timer + // infrastructure (stm_peripherals_find_timer etc.) because it has no GPIO + // pins and is reserved for DAC use (mcu_tim_banks[5] == NULL). + __HAL_RCC_TIM6_CLK_ENABLE(); + + uint32_t tim6_clk = get_tim6_freq(); + // Round to nearest, not truncate, so the realised sample rate is the + // closest TIM6 division to the requested rate. + // NOTE: a sweep audit on atmel-samd (Circuit Playground Express) shows a + // constant -3.4 cent frequency bias across all tones, consistent with a + // truncating period calculation there. The same round-to-nearest fix + // would likely tighten frequency accuracy on that port too. + uint32_t period = (tim6_clk + sample_rate / 2) / sample_rate; + if (period < 2) { + period = 2; + } + period -= 1; + + tim6_handle.Instance = TIM6; + tim6_handle.Init.Prescaler = 0; + tim6_handle.Init.CounterMode = TIM_COUNTERMODE_UP; + tim6_handle.Init.Period = period; + tim6_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + tim6_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&tim6_handle) != HAL_OK) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_TIM6); + } + + // TRGO = Update event → triggers DAC conversion each period. + TIM_MasterConfigTypeDef master_cfg = {0}; + master_cfg.MasterOutputTrigger = TIM_TRGO_UPDATE; + master_cfg.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&tim6_handle, &master_cfg) != HAL_OK) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_TIM6); + } + // NOTE: ports/atmel-samd's audio_dma_setup_playback handles AUDIO_DMA_OK + // and two specific error codes but lets any other non-OK return fall + // through silently — worth tightening there to mirror this raise-on-fail + // pattern. + + // --- DAC channel reconfiguration for DMA-triggered mode --- + // Switch the trigger source to TIM6 *without* disabling the DAC channel. + // HAL_DAC_Stop would disable the channel and momentarily drop the output + // pin to 0 V — audible as a pop between samples. + DAC_ChannelConfTypeDef ch_cfg = {0}; + ch_cfg.DAC_Trigger = DAC_TRIGGER_T6_TRGO; + ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); + if (self->right_channel != NULL) { + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_2); + } + // Reset HAL state from BUSY (set by Start) back to READY so + // HAL_DAC_Start_DMA below doesn't reject the request. + handle.State = HAL_DAC_STATE_READY; + + // --- DMA1 Stream5 Channel7 setup (DAC CH1, left) --- + __HAL_RCC_DMA1_CLK_ENABLE(); + + DMA_HandleTypeDef *hdma = &self->dma_handle_l; + memset(hdma, 0, sizeof(*hdma)); + hdma->Instance = DMA1_Stream5; + hdma->Init.Channel = DMA_CHANNEL_7; + hdma->Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma->Init.PeriphInc = DMA_PINC_DISABLE; + hdma->Init.MemInc = DMA_MINC_ENABLE; + hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + hdma->Init.Mode = DMA_CIRCULAR; + hdma->Init.Priority = DMA_PRIORITY_VERY_HIGH; + hdma->Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(hdma) != HAL_OK) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_DMA); + } + __HAL_LINKDMA(&handle, DMA_Handle1, *hdma); + + HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 6, 0); + NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn); + HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn); + + // --- DMA1 Stream6 Channel7 setup (DAC CH2, right) --- + if (self->right_channel != NULL) { + DMA_HandleTypeDef *hdma_r = &self->dma_handle_r; + memset(hdma_r, 0, sizeof(*hdma_r)); + hdma_r->Instance = DMA1_Stream6; + hdma_r->Init.Channel = DMA_CHANNEL_7; + hdma_r->Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_r->Init.PeriphInc = DMA_PINC_DISABLE; + hdma_r->Init.MemInc = DMA_MINC_ENABLE; + hdma_r->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma_r->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + hdma_r->Init.Mode = DMA_CIRCULAR; + hdma_r->Init.Priority = DMA_PRIORITY_VERY_HIGH; + hdma_r->Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(hdma_r) != HAL_OK) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_DMA); + } + __HAL_LINKDMA(&handle, DMA_Handle2, *hdma_r); + + HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 6, 0); + NVIC_ClearPendingIRQ(DMA1_Stream6_IRQn); + HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn); + } + + // --- Start DMA transfer(s) then timer --- + active_audioout = self; + + if (HAL_DAC_Start_DMA(&handle, DAC_CHANNEL_1, + (uint32_t *)self->dma_buffer, + AUDIOOUT_DMA_BUFFER_SAMPLES, + DAC_ALIGN_12B_R) != HAL_OK) { + active_audioout = NULL; + HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + if (self->right_channel != NULL) { + HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn); + m_free(self->dma_buffer_r); + self->dma_buffer_r = NULL; + } + m_free(self->dma_buffer); + self->dma_buffer = NULL; + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_DAC); + } + + if (self->right_channel != NULL) { + if (HAL_DAC_Start_DMA(&handle, DAC_CHANNEL_2, + (uint32_t *)self->dma_buffer_r, + AUDIOOUT_DMA_BUFFER_SAMPLES, + DAC_ALIGN_12B_R) != HAL_OK) { + active_audioout = NULL; + HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_1); + HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn); + m_free(self->dma_buffer); + self->dma_buffer = NULL; + m_free(self->dma_buffer_r); + self->dma_buffer_r = NULL; + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_DAC); + } + } + + HAL_TIM_Base_Start(&tim6_handle); + self->playing = true; +} + +void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self) { + if (active_audioout != self) { + return; + } + + // Stop the sample clock first so no more DMA requests are generated. + TIM6->CR1 &= ~TIM_CR1_CEN; + + // Switch the DAC channels to no-trigger mode while leaving them enabled. + // This is the key to a click-free stop: HAL_DAC_Stop_DMA / HAL_DAC_Stop + // disable the channel, which briefly pulls the output pin to 0 V before + // the ramp can run. Reconfiguring the trigger only keeps the channel + // enabled; the DAC keeps holding its last DHR value while DMA is aborted. + DAC_ChannelConfTypeDef ch_cfg = {0}; + ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; + ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); + if (self->dma_buffer_r) { + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_2); + } + + // Capture the last DAC output now that no further DMA writes can land. + uint16_t last_l = (uint16_t)(DAC->DOR1 & 0xFFF); + uint16_t last_r = self->dma_buffer_r ? (uint16_t)(DAC->DOR2 & 0xFFF) : 0; + uint16_t quiescent_12 = self->quiescent_value >> 4; + + // Abort DMA without disabling the DAC channels (HAL_DAC_Stop_DMA would). + HAL_DMA_Abort(&self->dma_handle_l); + HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn); + if (self->dma_buffer_r) { + HAL_DMA_Abort(&self->dma_handle_r); + HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn); + NVIC_ClearPendingIRQ(DMA1_Stream6_IRQn); + m_free(self->dma_buffer_r); + self->dma_buffer_r = NULL; + } + + // Free the left DMA buffer. + if (self->dma_buffer) { + m_free(self->dma_buffer); + self->dma_buffer = NULL; + } + + // Ramp left channel from last sample back to quiescent. + dac_ramp_channel(DAC_CHANNEL_1, last_l, quiescent_12); + + // Ramp right channel back to 0 (its reset value) before disabling it, + // so the next play() can ramp cleanly from 0 again. + if (self->right_channel != NULL) { + dac_ramp_channel(DAC_CHANNEL_2, last_r, 0); + HAL_DAC_Stop(&handle, DAC_CHANNEL_2); + } + + self->sample = MP_OBJ_NULL; + self->stopping = false; + self->paused = false; + self->playing = false; + active_audioout = NULL; + + __HAL_RCC_TIM6_CLK_DISABLE(); +} + +bool common_hal_audioio_audioout_get_playing(audioio_audioout_obj_t *self) { + return active_audioout == self && self->playing; +} + +void common_hal_audioio_audioout_pause(audioio_audioout_obj_t *self) { + if (active_audioout != self) { + return; + } + self->paused = true; + // Pause the sample clock; DMA remains armed but no new triggers fire. + TIM6->CR1 &= ~TIM_CR1_CEN; +} + +void common_hal_audioio_audioout_resume(audioio_audioout_obj_t *self) { + if (active_audioout != self || !self->paused) { + return; + } + self->paused = false; + // Restart the sample clock. + TIM6->CR1 |= TIM_CR1_CEN; +} + +bool common_hal_audioio_audioout_get_paused(audioio_audioout_obj_t *self) { + // Match espressif's convention: paused only reports true while a play() + // session is active, so a stale flag from a previous session can never + // leak through. + // + // NOTE: ports/atmel-samd delegates to audio_dma_get_paused() and does + // not gate on a "playing" state — it relies on the DMA hardware staying + // quiescent after stop. Worth aligning to the espressif/stm convention. + return self->playing && self->paused; +} + +// --------------------------------------------------------------------------- +// Reset hook +// --------------------------------------------------------------------------- + +void audioout_reset(void) { + if (active_audioout != NULL) { + // Emergency stop: halt timer and DMA without ramping. + TIM6->CR1 &= ~TIM_CR1_CEN; + HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_1); + HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + if (active_audioout->dma_buffer_r) { + HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_2); + HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn); + m_free(active_audioout->dma_buffer_r); + active_audioout->dma_buffer_r = NULL; + } + if (active_audioout->dma_buffer) { + m_free(active_audioout->dma_buffer); + active_audioout->dma_buffer = NULL; + } + active_audioout->sample = MP_OBJ_NULL; + active_audioout->stopping = false; + active_audioout->paused = false; + active_audioout->playing = false; + // Mark the object deinited and drop both pin references so the next + // construct() starts from a fully clean state. reset_all_pins (run + // elsewhere in reset_port) releases the actual pin claims. + active_audioout->left_channel = NULL; + active_audioout->right_channel = NULL; + active_audioout = NULL; + } + __HAL_RCC_TIM6_CLK_DISABLE(); +} diff --git a/ports/stm/common-hal/audioio/AudioOut.h b/ports/stm/common-hal/audioio/AudioOut.h new file mode 100644 index 00000000000..340118819a9 --- /dev/null +++ b/ports/stm/common-hal/audioio/AudioOut.h @@ -0,0 +1,72 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "common-hal/microcontroller/Pin.h" +#include "supervisor/background_callback.h" +#include STM32_HAL_H + +// Total DMA circular buffer size in 16-bit samples. +// Split into two halves; one half plays while the other is refilled. +// 4096-sample halves at 22050 Hz = ~186 ms per half-buffer interrupt, +// giving the background callback enough headroom to absorb SDIO cluster +// reads, NeoPixel updates, and other main-loop stalls without underrun. +#define AUDIOOUT_DMA_BUFFER_SAMPLES 8192 +#define AUDIOOUT_DMA_HALF_SAMPLES (AUDIOOUT_DMA_BUFFER_SAMPLES / 2) + +typedef struct { + mp_obj_base_t base; + + // Left channel pin (PA04 = DAC_CH1). NULL when deinited. + const mcu_pin_obj_t *left_channel; + // Right channel pin (PA05 = DAC_CH2). NULL when mono. + const mcu_pin_obj_t *right_channel; + + // DMA handles. The DAC handle itself is the shared file-scope handle + // from AnalogOut.c; we link these to it via __HAL_LINKDMA. + DMA_HandleTypeDef dma_handle_l; // DMA1 Stream5 Channel7 (DAC CH1, left) + DMA_HandleTypeDef dma_handle_r; // DMA1 Stream6 Channel7 (DAC CH2, right) + + // Circular DMA buffers: AUDIOOUT_DMA_BUFFER_SAMPLES uint16_t elements each, + // allocated on play() and freed on stop(). + uint16_t *dma_buffer; // left (CH1) + uint16_t *dma_buffer_r; // right (CH2), NULL when mono + + // Current audio sample object being played. + mp_obj_t sample; + bool loop; + bool playing; + + // Set from ISR context to request a clean stop via background callback. + volatile bool stopping; + bool paused; + + // Sample format metadata, populated at play() time. + uint8_t bytes_per_sample; // 1 (8-bit) or 2 (16-bit) + bool samples_signed; + uint8_t channel_count; // 1 = mono, 2 = stereo + uint16_t quiescent_value; // 16-bit resting value (default 0x8000) + + // Background callback queued from DMA ISR, processed in main loop. + background_callback_t callback; + + // Bitmask of DMA halves pending refill: bit0 = lower, bit1 = upper. + // Set from half/full IRQ, drained by the background callback. A bitmask + // (not a scalar) so a back-to-back half+full pair queues both fills even + // if the callback hasn't run yet. + volatile uint8_t halves_to_fill; + + // Source buffer position tracking. Allows consuming large source buffers + // (e.g. RawSample > 256 samples) across multiple DMA half-fills. + const uint8_t *src_ptr; // current read position in source buffer + uint32_t src_remaining_len; // bytes remaining in current source buffer + bool src_done; // GET_BUFFER_DONE received for current buffer +} audioio_audioout_obj_t; + +// Called from reset_port() to stop any active playback on soft-reset. +void audioout_reset(void); diff --git a/ports/zephyr-cp/common-hal/zephyr_serial/__init__.c b/ports/stm/common-hal/audioio/__init__.c similarity index 54% rename from ports/zephyr-cp/common-hal/zephyr_serial/__init__.c rename to ports/stm/common-hal/audioio/__init__.c index 2784446ba15..ebf626832f6 100644 --- a/ports/zephyr-cp/common-hal/zephyr_serial/__init__.c +++ b/ports/stm/common-hal/audioio/__init__.c @@ -1,7 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries LLC // // SPDX-License-Identifier: MIT -// No zephyr_serial module functions. +// No audioio module functions. diff --git a/ports/stm/common-hal/audiopwmio/PWMAudioOut.c b/ports/stm/common-hal/audiopwmio/PWMAudioOut.c index a5cc11965fa..08ab7eb9bc7 100644 --- a/ports/stm/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/stm/common-hal/audiopwmio/PWMAudioOut.c @@ -255,6 +255,9 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, if (active_audio) { mp_raise_RuntimeError(MP_ERROR_TEXT("Another PWMAudioOut is already active")); // TODO } + + audiosample_check(sample); + self->sample = sample; self->loop = loop; diff --git a/ports/stm/common-hal/busio/I2C.c b/ports/stm/common-hal/busio/I2C.c index e6957989cc7..7f7eb990e4d 100644 --- a/ports/stm/common-hal/busio/I2C.c +++ b/ports/stm/common-hal/busio/I2C.c @@ -212,7 +212,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { HAL_StatusTypeDef result; if (!transmit_stop_bit) { @@ -234,19 +234,19 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, result = HAL_I2C_Master_Transmit(&(self->handle), (uint16_t)(addr << 1), (uint8_t *)data, (uint16_t)len, 500); } - return result == HAL_OK ? 0 : MP_EIO; + return result == HAL_OK ? 0 : -MP_EIO; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { if (!self->frame_in_prog) { return HAL_I2C_Master_Receive(&(self->handle), (uint16_t)(addr << 1), data, (uint16_t)len, 500) - == HAL_OK ? 0 : MP_EIO; + == HAL_OK ? 0 : -MP_EIO; } else { HAL_StatusTypeDef result = HAL_I2C_Master_Seq_Receive_IT(&(self->handle), (uint16_t)(addr << 1), (uint8_t *)data, @@ -259,9 +259,9 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, } } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/stm/common-hal/busio/SPI.c b/ports/stm/common-hal/busio/SPI.c index 98696271ca9..24b65fbf54c 100644 --- a/ports/stm/common-hal/busio/SPI.c +++ b/ports/stm/common-hal/busio/SPI.c @@ -19,7 +19,6 @@ #define MAX_SPI 6 static bool reserved_spi[MAX_SPI]; -static bool never_reset_spi[MAX_SPI]; #define ALL_CLOCKS 0xFF static void spi_clock_enable(uint8_t mask); @@ -76,18 +75,6 @@ static uint32_t stm32_baud_to_spi_div(uint32_t baudrate, uint16_t *prescaler, ui return SPI_BAUDRATEPRESCALER_256; } -void spi_reset(void) { - uint16_t never_reset_mask = 0x00; - for (int i = 0; i < MAX_SPI; i++) { - if (!never_reset_spi[i]) { - reserved_spi[i] = false; - } else { - never_reset_mask |= 1 << i; - } - } - spi_clock_disable(ALL_CLOCKS & ~(never_reset_mask)); -} - static const mcu_periph_obj_t *find_pin_function(const mcu_periph_obj_t *table, size_t sz, const mcu_pin_obj_t *pin, int periph_index) { for (size_t i = 0; i < sz; i++, table++) { if (periph_index == table->periph_index && pin == table->pin) { @@ -149,6 +136,10 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *sck, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + // Ensure the object starts in its deinit state before check_pins sets + // self->sck, self->mosi, and self->miso. + common_hal_busio_spi_mark_deinit(self); + int periph_index = check_pins(self, sck, mosi, miso); SPI_TypeDef *SPIx = mcu_spi_banks[periph_index - 1]; @@ -224,7 +215,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[self->sck->periph_index - 1] = true; never_reset_pin_number(self->sck->pin->port, self->sck->pin->number); if (self->mosi != NULL) { never_reset_pin_number(self->mosi->pin->port, self->mosi->pin->number); @@ -238,13 +228,16 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->sck == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->sck = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } spi_clock_disable(1 << (self->sck->periph_index - 1)); reserved_spi[self->sck->periph_index - 1] = false; - never_reset_spi[self->sck->periph_index - 1] = false; reset_pin_number(self->sck->pin->port, self->sck->pin->number); if (self->mosi != NULL) { diff --git a/ports/stm/common-hal/microcontroller/Processor.c b/ports/stm/common-hal/microcontroller/Processor.c index 0781f422ee1..719d29e1d53 100644 --- a/ports/stm/common-hal/microcontroller/Processor.c +++ b/ports/stm/common-hal/microcontroller/Processor.c @@ -127,8 +127,8 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { #if CIRCUITPY_ALARM if (alarm_get_wakeup_cause() != STM_WAKEUP_UNDEF) { - return RESET_REASON_DEEP_SLEEP_ALARM; + return MCU_RESET_REASON_DEEP_SLEEP_ALARM; } #endif - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/stm/common-hal/pwmio/PWMOut.c b/ports/stm/common-hal/pwmio/PWMOut.c index ed3bd67e7ec..fe516065fbd 100644 --- a/ports/stm/common-hal/pwmio/PWMOut.c +++ b/ports/stm/common-hal/pwmio/PWMOut.c @@ -74,12 +74,12 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self, } // If the frequencies are the same it's ok if (tim_frequencies[tim_index] != frequency) { - last_failure = PWMOUT_INVALID_FREQUENCY_ON_PIN; + last_failure = PWMOUT_INTERNAL_RESOURCES_IN_USE; continue; // keep looking } // you can't put a variable frequency on a partially reserved timer if (variable_frequency) { - last_failure = PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE; + last_failure = PWMOUT_INTERNAL_RESOURCES_IN_USE; continue; // keep looking } first_time_setup = false; // skip setting up the timer diff --git a/ports/stm/common-hal/sdioio/SDCard.c b/ports/stm/common-hal/sdioio/SDCard.c index 92e552c2e89..ef708248716 100644 --- a/ports/stm/common-hal/sdioio/SDCard.c +++ b/ports/stm/common-hal/sdioio/SDCard.c @@ -6,6 +6,8 @@ #include #include "shared-bindings/sdioio/SDCard.h" + +#include "extmod/vfs.h" #include "py/mperrno.h" #include "py/runtime.h" @@ -164,7 +166,7 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, HAL_StatusTypeDef r = HAL_SD_Init(&self->handle); if (r != HAL_OK) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("SDIO Init Error %x"), (unsigned int)r); + mp_raise_ValueError_varg(MP_ERROR_TEXT("SDIO Init Error 0x%02x"), (unsigned int)r); } HAL_SD_CardInfoTypeDef info; @@ -239,9 +241,10 @@ static void check_for_deinit(sdioio_sdcard_obj_t *self) { } } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { - check_for_deinit(self); - check_whole_block(bufinfo); +// Native function for VFS blockdev layer +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); self->state_programming = true; common_hal_mcu_disable_interrupts(); @@ -251,17 +254,27 @@ int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t sta #else uint32_t time_out = 1000; #endif - HAL_StatusTypeDef r = HAL_SD_WriteBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, time_out); + HAL_StatusTypeDef r = HAL_SD_WriteBlocks(&self->handle, buf, start_block, num_blocks, time_out); common_hal_mcu_enable_interrupts(); if (r != HAL_OK) { - return -EIO; + return -MP_EIO; } return 0; } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { check_for_deinit(self); check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); common_hal_mcu_disable_interrupts(); #ifdef STM32H750xx @@ -270,14 +283,48 @@ int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t star #else uint32_t time_out = 1000; #endif - HAL_StatusTypeDef r = HAL_SD_ReadBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, time_out); + HAL_StatusTypeDef r = HAL_SD_ReadBlocks(&self->handle, buf, start_block, num_blocks, time_out); common_hal_mcu_enable_interrupts(); if (r != HAL_OK) { - return -EIO; + return -MP_EIO; } return 0; } +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } +} + bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { check_for_deinit(self); return true; diff --git a/ports/stm/mpconfigport.mk b/ports/stm/mpconfigport.mk index 83759fc5d24..b5a2b3bfdc4 100644 --- a/ports/stm/mpconfigport.mk +++ b/ports/stm/mpconfigport.mk @@ -1,8 +1,13 @@ +# Properties get a dedicated linker section here, so they can drop the unused slots. +CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 1 + LONGINT_IMPL ?= MPZ INTERNAL_LIBM ?= 1 ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32F405xx STM32F407xx)) CIRCUITPY_ALARM = 1 + # ?= so a board reusing TIM6 / PA04 for something else can opt out. + CIRCUITPY_AUDIOIO ?= 1 CIRCUITPY_CANIO = 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 CIRCUITPY_SDIOIO ?= 1 @@ -10,13 +15,18 @@ ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32F405xx STM32F407xx)) USB_NUM_ENDPOINT_PAIRS = 4 endif +ifeq ($(INTERNAL_FLASH_FILESYSTEM),1) + OPTIMIZATION_FLAGS ?= -Os +endif + ifeq ($(MCU_VARIANT),STM32F407xx) UF2_FAMILY_ID ?= 0x6d0922fa endif ifeq ($(MCU_SERIES),F4) - # Audio via PWM - CIRCUITPY_AUDIOIO = 0 + CIRCUITPY_LOAD_NATIVE ?= 1 + # Audio via PWM (F405/F407 also supports DAC-based audioio; set above) + CIRCUITPY_AUDIOIO ?= 0 CIRCUITPY_AUDIOCORE ?= 1 CIRCUITPY_AUDIOPWMIO ?= 1 diff --git a/ports/stm/mpconfigport_nanbox.h b/ports/stm/mpconfigport_nanbox.h deleted file mode 100644 index 164850112e0..00000000000 --- a/ports/stm/mpconfigport_nanbox.h +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George -// -// SPDX-License-Identifier: MIT - -#pragma once - -// select nan-boxing object model -#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_D) - -// native emitters don't work with nan-boxing -#define MICROPY_EMIT_X86 (0) -#define MICROPY_EMIT_X64 (0) -#define MICROPY_EMIT_THUMB (0) -#define MICROPY_EMIT_ARM (0) - -#include - -typedef int64_t mp_int_t; -typedef uint64_t mp_uint_t; -#define UINT_FMT "%llu" -#define INT_FMT "%lld" - -#include diff --git a/ports/stm/peripherals/stm32l4/stm32l4r5xx/gpio.c b/ports/stm/peripherals/stm32l4/stm32l4r5xx/gpio.c index 18fe8b760a2..a4adc58e42a 100644 --- a/ports/stm/peripherals/stm32l4/stm32l4r5xx/gpio.c +++ b/ports/stm/peripherals/stm32l4/stm32l4r5xx/gpio.c @@ -17,7 +17,7 @@ void stm32_peripherals_gpio_init(void) { __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); - // These ports are not used on the Swan R5 but may need to be enabeld on other boards + // These ports are not used on the Swan R5 but may need to be enabled on other boards // __HAL_RCC_GPIOH_CLK_ENABLE(); // __HAL_RCC_GPIOI_CLK_ENABLE(); diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index c5a1685a7fd..21da8b2d653 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -32,6 +32,9 @@ #if CIRCUITPY_RTC #include "shared-bindings/rtc/__init__.h" #endif +#if CIRCUITPY_AUDIOIO +#include "common-hal/audioio/AudioOut.h" +#endif #include "peripherals/clocks.h" #include "peripherals/gpio.h" @@ -39,7 +42,7 @@ #include STM32_HAL_H -void NVIC_SystemReset(void) NORETURN; +void NVIC_SystemReset(void) MP_NORETURN; #if (CPY_STM32H7) || (CPY_STM32F7) #if defined(CIRCUITPY_HW_SDRAM_SIZE) @@ -232,7 +235,95 @@ void *port_realloc(void *ptr, size_t size, bool dma_capable) { } #endif +// Pending request for the ST system bootloader. This lives in the saved word, +// RAM that startup does not clear, which is where the other ports keep theirs: +// _bootloader_dbl_tap on atmel-samd, NRF_POWER->GPREGRET on nordic, +// SNVS->LPGPR[3] on mimxrt10xx. The low byte is the attempt count. +#define BOOTLOADER_MAGIC 0xf05a0000 +#define BOOTLOADER_MAGIC_MASK 0xffff0000 +// Magic in the top half, RTC seconds of the last attempt in bits 15:8, attempt +// count in bits 7:0. +#define BOOTLOADER_SECONDS_SHIFT 8 +#define BOOTLOADER_FIELD_MASK 0xff + +// A retry only counts if it follows the previous attempt closely. The ROM fails +// and resets within a second, so anything slower is the part being reset by +// something else while the bootloader was running, and the request is stale. +// Without this, exiting DFU with a software reset lands straight back in DFU. +#define BOOTLOADER_RETRY_WINDOW_S 5 + +// The ROM clocks USB from the HSE but does not know which crystal is fitted, so +// it measures one against the HSI and resets the part when that misses: AN2606 +// Figure 32/33, "HSE detected" -> no -> "Generate System reset". On the 12 MHz +// Feather STM32F405 Express one attempt reached DFU 5 times in 12. +#define BOOTLOADER_MAX_ATTEMPTS 16 + +#if CPY_STM32F4 +// Seconds field of the RTC clock, read straight from the register because the +// HAL handle is not initialised this early. rtc_init() leaves shadow bypass on +// and that setting survives a reset, so the register reads live. Only a read is +// needed, so the backup domain does not have to be unlocked for write. +static uint32_t bootloader_rtc_seconds(void) { + uint32_t tr = RTC->TR; + return ((tr >> 4) & 0x7) * 10 + (tr & 0xF); +} + +// Naked so nothing touches the stack between setting MSP and the branch. +MP_NORETURN static __attribute__((naked)) void branch_to_bootloader(uint32_t bl_addr) { + __asm volatile ( + "ldr r2, [r0, #0]\n" + "msr msp, r2\n" + "ldr r2, [r0, #4]\n" + "bx r2\n" + ); +} + +// Runs before HAL_Init() starts SysTick, so the ROM gets the part close to reset +// state. The ROM sets its own VTOR and runs from 0x1FFF0000, so no SYSCFG remap +// is needed here. +static void check_enter_bootloader(void) { + uint32_t request = port_get_saved_word(); + if ((request & BOOTLOADER_MAGIC_MASK) != BOOTLOADER_MAGIC) { + // Not our word. Safe mode shares it, so leave it alone. + return; + } + + // The ROM signals its HSE-detect failure with a software reset, so SFTRSTF is + // what tells a retry apart from a cold boot, and a power cycle always leaves + // the bootloader. + if (!(RCC->CSR & RCC_CSR_SFTRSTF)) { + port_set_saved_word(0); + return; + } + + uint32_t now = bootloader_rtc_seconds(); + uint32_t then = (request >> BOOTLOADER_SECONDS_SHIFT) & BOOTLOADER_FIELD_MASK; + if ((now + 60 - then) % 60 > BOOTLOADER_RETRY_WINDOW_S) { + port_set_saved_word(0); + return; + } + + uint32_t attempts = request & BOOTLOADER_FIELD_MASK; + if (attempts >= BOOTLOADER_MAX_ATTEMPTS) { + port_set_saved_word(0); + return; + } + port_set_saved_word(BOOTLOADER_MAGIC | + (now << BOOTLOADER_SECONDS_SHIFT) | (attempts + 1)); + // Clearing the flags cancels the request once the ROM succeeds: leaving DFU + // is a jump, not a reset, so SFTRSTF stays clear and the branch above zeroes + // the flag on the way back into the application. + RCC->CSR |= RCC_CSR_RMVF; + + branch_to_bootloader(0x1FFF0000); +} +#endif + safe_mode_t port_init(void) { + #if CPY_STM32F4 + check_enter_bootloader(); + #endif + HAL_Init(); // Turns on SysTick __HAL_RCC_SYSCFG_CLK_ENABLE(); @@ -302,14 +393,11 @@ void SysTick_Handler(void) { } void reset_port(void) { - reset_all_pins(); - #if CIRCUITPY_RTC rtc_reset(); #endif #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif #if CIRCUITPY_SDIOIO @@ -318,47 +406,19 @@ void reset_port(void) { #if CIRCUITPY_ALARM exti_reset(); #endif + #if CIRCUITPY_AUDIOIO + audioout_reset(); + #endif } void reset_to_bootloader(void) { - -/* -From STM AN2606: -Before jumping to bootloader user must: -• Disable all peripheral clocks -• Disable used PLL -• Disable interrupts -• Clear pending interrupts -System memory boot mode can be exited by getting out from bootloader activation -condition and generating hardware reset or using Go command to execute user code -*/ - HAL_RCC_DeInit(); - HAL_DeInit(); - - // Disable all pending interrupts using NVIC - for (uint8_t i = 0; i < MP_ARRAY_SIZE(NVIC->ICER); ++i) { - NVIC->ICER[i] = 0xFFFFFFFF; - } - - // if it is necessary to ensure an interrupt will not be triggered after disabling it in the NVIC, - // add a DSB instruction and then an ISB instruction. (ARM Cortex™-M Programming Guide to - // Memory Barrier Instructions, 4.6 Disabling Interrupts using NVIC) - __DSB(); - __ISB(); - - // Clear all pending interrupts using NVIC - for (uint8_t i = 0; i < MP_ARRAY_SIZE(NVIC->ICPR); ++i) { - NVIC->ICPR[i] = 0xFFFFFFFF; - } - - // information about jump addresses has been taken from STM AN2606. - #if defined(STM32F4) - __set_MSP(*((uint32_t *)0x1FFF0000)); - ((void (*)(void)) * ((uint32_t *)0x1FFF0004))(); - #else - // DFU mode for STM32 variant note implemented. - NVIC_SystemReset(); + #if CPY_STM32F4 + // Record the request and reset, rather than jumping from a running + // application. check_enter_bootloader() jumps on the way back up. + port_set_saved_word(BOOTLOADER_MAGIC | + (bootloader_rtc_seconds() << BOOTLOADER_SECONDS_SHIFT)); #endif + NVIC_SystemReset(); while (true) { asm ("nop;"); diff --git a/ports/unix/Makefile b/ports/unix/Makefile index bb1f6a4740a..62fa4c732e9 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -17,6 +17,10 @@ endif # If the build directory is not given, make it reflect the variant name. BUILD ?= build-$(VARIANT) +ifneq ($(MICROPY_FORCE_32BIT),) +$(warning *** The MICROPY_FORCE_32BIT flag is no longer affecting builds, please update your environment ***) +endif + include ../../py/mkenv.mk -include mpconfigport.mk include $(VARIANT_DIR)/mpconfigvariant.mk @@ -27,6 +31,9 @@ FROZEN_MANIFEST ?= variants/manifest.py # This should be configured by the mpconfigvariant.mk PROG ?= micropython +# For use in test rules below +ABS_PROG = $(abspath $(BUILD)/$(PROG)) + # qstr definitions (must come before including py.mk) QSTR_DEFS += qstrdefsport.h QSTR_GLOBAL_DEPENDENCIES += $(VARIANT_DIR)/mpconfigvariant.h @@ -46,28 +53,38 @@ INC += -I$(BUILD) # compiler settings CWARN = -Wall -Werror -CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) +# CIRCUITPY-CHANGE: add -Wno-missing-field-initializers +CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -Wno-missing-field-initializers +# CIRCUITPY-CHANGE: use gnu11 instead of gnu99 +CFLAGS += $(INC) $(CWARN) -std=gnu11 -DUNIX $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) # Force the use of 64-bits for file sizes in C library functions on 32-bit platforms. # This option has no effect on 64-bit builds. CFLAGS += -D_FILE_OFFSET_BITS=64 +# Force the use of 64-bits for time_t in C library functions on 32-bit platforms. +# This option has no effect on 64-bit builds. +CFLAGS += -D_TIME_BITS=64 + +# Debug info flag is added if either DEBUG=1 or STRIP= is passed to make +# (to produce a debug binary, or a release binary with all symbols, respectively.) +DEBUG_INFO = -ggdb3 + # Debugging/Optimization ifdef DEBUG COPT ?= -Og +CFLAGS += $(DEBUG_INFO) else COPT ?= -Os COPT += -DNDEBUG +ifndef STRIP +CFLAGS += $(DEBUG_INFO) endif +endif # ifdef DEBUG # Remove unused sections. COPT += -fdata-sections -ffunction-sections -# Note: Symbols and debug information will still be stripped from the final binary -# unless "DEBUG=1" or "STRIP=" is passed to make, see README.md for details. -CFLAGS += -g - ifndef DEBUG # _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) @@ -101,11 +118,7 @@ endif # 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) -ifeq ($(MICROPY_FORCE_32BIT),1) -CC = clang -m32 -else CC = clang -endif # Use clang syntax for map file LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip else @@ -117,16 +130,6 @@ LDFLAGS += $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) # Flags to link with pthread library LIBPTHREAD = -lpthread -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 += -I/usr/include/i686-linux-gnu -endif -endif -endif - ifeq ($(MICROPY_USE_READLINE),1) INC += -I$(TOP)/shared/readline CFLAGS += -DMICROPY_USE_READLINE=1 @@ -139,7 +142,11 @@ ifeq ($(MICROPY_PY_SOCKET),1) CFLAGS += -DMICROPY_PY_SOCKET=1 endif ifeq ($(MICROPY_PY_THREAD),1) +ifeq ($(MICROPY_PY_THREAD_GIL),1) +CFLAGS += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=1 +else CFLAGS += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0 +endif LDFLAGS += $(LIBPTHREAD) endif @@ -174,11 +181,7 @@ ifeq ($(MICROPY_STANDALONE),1) GIT_SUBMODULES += lib/libffi DEPLIBS += libffi LIBFFI_CFLAGS := -I$(shell ls -1d $(BUILD)/lib/libffi/include) - ifeq ($(MICROPY_FORCE_32BIT),1) - LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib32/libffi.a - else - LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib/libffi.a - endif +LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib/libffi.a else # Use system version of libffi. LIBFFI_CFLAGS := $(shell pkg-config --cflags libffi) @@ -208,6 +211,8 @@ SRC_C += \ input.c \ alloc.c \ fatfs_port.c \ + shared-module/os/__init__.c \ + supervisor/shared/settings.c \ supervisor/stub/filesystem.c \ supervisor/stub/safe_mode.c \ supervisor/stub/stack.c \ @@ -223,6 +228,7 @@ $(BUILD)/supervisor/shared/translate/translate.o: $(HEADER_BUILD)/qstrdefs.gener SHARED_SRC_C += $(addprefix shared/,\ runtime/gchelper_generic.c \ + runtime/pyexec.c \ timeutils/timeutils.c \ $(SHARED_SRC_C_EXTRA) \ ) @@ -247,12 +253,6 @@ CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs CFLAGS += -DMICROPY_MODULE_FROZEN_STR endif -CXXFLAGS += $(filter-out -Wmissing-prototypes -Wold-style-definition -std=gnu99,$(CFLAGS) $(CXXFLAGS_MOD)) - -ifeq ($(MICROPY_FORCE_32BIT),1) -RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-march=x86' -endif - ifeq ($(CROSS_COMPILE),arm-linux-gnueabi-) # Force disable error text compression when compiling for ARM as the compiler # cannot optimise out the giant strcmp list generated for MP_MATCH_COMPRESSED. @@ -278,7 +278,7 @@ print-failures clean-failures: TEST_ARGS ?= test: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py $(eval DIRNAME=ports/$(notdir $(CURDIR))) - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py $(TEST_ARGS) + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py test_full: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py $(eval DIRNAME=ports/$(notdir $(CURDIR))) diff --git a/ports/unix/README.md b/ports/unix/README.md index b7aa6e3fef7..720be8a047c 100644 --- a/ports/unix/README.md +++ b/ports/unix/README.md @@ -5,9 +5,10 @@ The "unix" port runs in standard Unix-like environments including Linux, BSD, macOS, and Windows Subsystem for Linux. The x86 and x64 architectures are supported (i.e. x86 32- and 64-bit), as well -as ARM and MIPS. Extending the unix port to another architecture requires -writing some assembly code for the exception handling and garbage collection. -Alternatively, a fallback implementation based on setjmp/longjmp can be used. +as ARM, MIPS, RISC-V, and LoongArch. Extending the unix port to another +architecture requires writing some assembly code for the exception handling +and garbage collection. Alternatively, a fallback implementation based on +setjmp/longjmp can be used. Building -------- @@ -18,7 +19,7 @@ To build the unix port locally then you will need: * git command line executable, unless you downloaded a source .tar.xz file from https://micropython.org/download/ -* gcc (or clang for macOS) toolchain +* an appropriate GCC or Clang toolchain for your target (macOS only supports Clang) * GNU Make * Python 3.x @@ -72,6 +73,14 @@ To run the complete testsuite, use: $ make test +There are other make targets to interact with the testsuite: + + $ make test//int # Run all tests matching the pattern "int" + $ make test/ports/unix # Run all tests in ports/unix + $ make test-failures # Re-run only the failed tests + $ make print-failures # print the differences for failed tests + $ make clean-failures # delete the .exp and .out files from failed tests + The Unix port comes with a built-in package manager called `mip`, e.g.: $ ./build-standard/micropython -m mip install hmac @@ -155,3 +164,143 @@ The default compiler optimisation level is -Os, or -Og if `DEBUG=1` is set. Setting the variable `COPT` will explicitly set the optimisation level. For example `make [other arguments] COPT=-O0 DEBUG=1` will build a binary with no optimisations, assertions enabled, and debug symbols. + +### Sanitizers + +Sanitizers are extra runtime checks supported by GCC and Clang. The CI process +supports building with the "undefined behavior" (UBSan) or "address" (ASan) +sanitizers. The script `tools/ci.sh` is the source of truth about how to build +and run in these modes. + +Several classes of checks are disabled via compiler flags: + +* In the undefined behavior sanitizer, checks based on the presence of the + `non_null` attribute are disabled because the code makes technically incorrect + calls like `memset(NULL, 0, 0)`. A future C standard is likely to permit such + calls. +* In the address sanitizer, `detect_stack_use_after_return` is disabled. This + check is intended to make sure locals in a "returned from" stack frame are not + used. However, this mode interferes with various assumptions that + MicroPython's stack checking, NLR, and GC rely on. + +### Notes about x86 (i686) support + +It used to be possible to create an x86 (32-bits) build on a x64 (64-bits) host +by passing `MICROPY_FORCE_32BIT=1` to `make`. That option was retired: x86 +usage has declined quite a bit in the past few years, and MicroPython now +supports at least one more mixed 32/64-bits target architecture for which +enabling `MICROPY_FORCE_32BIT` would make builds fail. + +x86 will be treated as a cross-compilation target from now on. This means you +will need to install a suitable compiler (on Ubuntu you can install either the +`gcc-i686-linux-gnu` and `g++-i686-linux-gnu` packages for GCC, or the `clang` +package for Clang, for example) and pass the appropriate command arguments to +`make` depending on which compiler you chose. + +### Building x86 (i686) code with GCC + +For GCC, you will need to pass the toolchain's command prefix to the +`CROSS_COMPILE` command line variable. + +This change is also extended to native modules, for which you may need to pass +the toolchain's command prefix to the `CROSS` command line variable if your +x86 compiler cannot be invoked with `i686-linux-gnu-gcc`. + +Or, as an example: + +```bash +$ printf "%s %s %s %s\n" $(lsb_release -d | cut -f 2) $(uname -m) +Ubuntu 24.04.4 LTS x86_64 + +$ i686-linux-gnu-gcc --version | head -n 1 +i686-linux-gnu-gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0 + +$ CROSS_COMPILE=i686-linux-gnu- make -C ports/unix +make: Entering directory '/ports/unix' +Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity. +... +LINK build-standard/micropython + text data bss dec hex filename + 723115 36104 2124 761343 b9dff build-standard/micropython +make: Leaving directory '/ports/unix' + +$ file -b ports/unix/build-standard/micropython | cut -d, -f-2 +ELF 32-bit LSB pie executable, Intel 80386 + +# `i686-linux-gnu-` is the default prefix for x86 native modules now, it has +# been explicitly mentioned here in case you want to see how to set it. + +$ make -C examples/natmod/features0 ARCH=x86 CROSS=i686-linux-gnu- +make: Entering directory '/examples/natmod/features0' +GEN build/features0.config.h +CC features0.c +LINK build/features0.o +arch: EM_386 +text size: 192 +bss size: 0 +GOT entries: 4 +GEN features0.mpy +make: Leaving directory '/examples/natmod/features0' + +$ cd examples/natmod/features0 && ../../../ports/unix/build-standard/micropython +MicroPython v1.29.0-preview.490.gb4c58f7ba5.dirty on 2026-07-04; linux [GCC 13.3.0] version +Type "help()" for more information. +>>> import features0 +>>> features0.factorial(10) +3628800 +``` + +### Building x86 (i686) code with Clang + +For Clang, you will need need to pass both the name of the compiler to invoke +as the `CC` command line variable and the extra command line arguments needed +to let Clang know you are building an i686 binary as the `CFLAGS_EXTRA` and +`LDFLAGS_EXTRA` command line variables (usually +`--target=i686-unknown-linux-gnu`). + +For native modules, since linking is not done by the compiler, only the `CC` +and `CFLAGS_EXTRA` arguments are needed. + +Or, as an example: + +```bash +$ printf "%s %s %s %s\n" $(lsb_release -d | cut -f 2) $(uname -m) +Ubuntu 24.04.4 LTS x86_64 + +$ clang --version | head -1 +Ubuntu clang version 18.1.3 (1ubuntu1) + +$ clang -print-targets | grep -i 32-bit.x86 + x86 - 32-bit X86: Pentium-Pro and above + +$ make -C ports/unix CC=clang CFLAGS_EXTRA="--target=i686-unknown-linux-gnu" LDFLAGS_EXTRA='--target=i686-unknown-linux-gnu' +make: Entering directory '/ports/unix' +Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity. +... +LINK build-standard/micropython + text data bss dec hex filename + 836241 34748 2052 873041 d5251 build-standard/micropython +make: Leaving directory '/ports/unix' + +$ file -b ports/unix/build-standard/micropython | cut -d, -f-2 +ELF 32-bit LSB pie executable, Intel 80386 + +$ make -C examples/natmod/features0 ARCH=x86 CC=clang CFLAGS_EXTRA="--target=i686-unknown-linux-gnu" +make: Entering directory '/examples/natmod/features0' +GEN build-x86/features0.config.h +CC features0.c +LINK build-x86/features0.o +arch: EM_386 +text size: 180 +bss size: 0 +GOT entries: 2 +GEN features0.mpy +make: Leaving directory '/examples/natmod/features0' + +$ cd examples/natmod/features0 && ../../../ports/unix/build-standard/micropython +MicroPython v1.29.0-preview.490.gb4c58f7ba5.dirty on 2026-07-04; linux [Clang 18.1.3] version +Type "help()" for more information. +>>> import features0 +>>> features0.factorial(10) +3628800 +``` diff --git a/ports/unix/alloc.c b/ports/unix/alloc.c index 9ab2ca04ebc..7e1b261261e 100644 --- a/ports/unix/alloc.c +++ b/ports/unix/alloc.c @@ -32,7 +32,7 @@ #include "py/mpstate.h" -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE #if defined(__OpenBSD__) || defined(__MACH__) #define MAP_ANONYMOUS MAP_ANON @@ -80,4 +80,4 @@ void mp_unix_free_exec(void *ptr, size_t size) { MP_REGISTER_ROOT_POINTER(void *mmap_region_head); -#endif // MICROPY_EMIT_NATIVE +#endif // MICROPY_ENABLE_NATIVE_CODE diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 7f13f9756f1..8809148652f 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -97,6 +97,7 @@ static const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_write1), MP_ROM_PTR(&mp_stream_write1_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto1), MP_ROM_PTR(&mp_stream_readinto1_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) }, }; @@ -171,19 +172,34 @@ static void pairheap_test(size_t nops, int *ops) { if (mp_pairheap_is_empty(pairheap_lt, heap)) { mp_printf(&mp_plat_print, " -"); } else { - mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]); + mp_printf(&mp_plat_print, " %d", (int)(mp_pairheap_peek(pairheap_lt, heap) - &node[0])); ; } } mp_printf(&mp_plat_print, "\npop all:"); while (!mp_pairheap_is_empty(pairheap_lt, heap)) { - mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]); + mp_printf(&mp_plat_print, " %d", (int)(mp_pairheap_peek(pairheap_lt, heap) - &node[0])); ; heap = mp_pairheap_pop(pairheap_lt, heap); } mp_printf(&mp_plat_print, "\n"); } +// CIRCUITPY-CHANGE: not turned on in CircuitPython +#if MICROPY_SCHEDULER_STATIC_NODES +static mp_sched_node_t mp_coverage_sched_node; +static bool coverage_sched_function_continue; + +static void coverage_sched_function(mp_sched_node_t *node) { + (void)node; + mp_printf(&mp_plat_print, "scheduled function\n"); + if (coverage_sched_function_continue) { + // Re-scheduling node will cause it to run again next time scheduled functions are run + mp_sched_schedule_node(&mp_coverage_sched_node, coverage_sched_function); + } +} +#endif + // function to run extra tests for things that can't be checked by scripts static mp_obj_t extra_coverage(void) { // mp_printf (used by ports that don't have a native printf) @@ -191,10 +207,22 @@ static mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# mp_printf\n"); mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding - mp_printf(&mp_plat_print, "%ld\n", 123); // long - mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex - mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex - mp_printf(&mp_plat_print, "%.2s %.3s '%4.4s' '%5.5q' '%.3q'\n", "abc", "abc", "abc", MP_QSTR_True, MP_QSTR_True); // fixed string precision + mp_printf(&mp_plat_print, "%ld\n", 123l); // long + mp_printf(&mp_plat_print, "%lx\n", 0x123fl); // long hex + mp_printf(&mp_plat_print, "%lX\n", 0x123fl); // capital long hex + if (sizeof(mp_int_t) == 8) { + mp_printf(&mp_plat_print, "%llx\n", LLONG_MAX); // long long hex + mp_printf(&mp_plat_print, "%llX\n", LLONG_MAX); // capital long long hex + mp_printf(&mp_plat_print, "%llu\n", ULLONG_MAX); // unsigned long long + } else { + // fake for platforms without narrower mp_int_t + mp_printf(&mp_plat_print, "7fffffffffffffff\n"); + mp_printf(&mp_plat_print, "7FFFFFFFFFFFFFFF\n"); + mp_printf(&mp_plat_print, "18446744073709551615\n"); + } + mp_printf(&mp_plat_print, "%p\n", (void *)0x789f); // pointer + mp_printf(&mp_plat_print, "%P\n", (void *)0x789f); // pointer uppercase + mp_printf(&mp_plat_print, "%.2s %.3s '%4.4s' '%5.5q' '%.3q'\n", "abc", "abc", "abc", (qstr)MP_QSTR_True, (qstr)MP_QSTR_True); // fixed string precision mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools #ifndef NDEBUG @@ -204,10 +232,36 @@ static mp_obj_t extra_coverage(void) { #endif mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned - mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned - mp_printf(&mp_plat_print, "%X\n", 0x80000000); // should print unsigned - mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier + mp_printf(&mp_plat_print, "%x\n", 0x8000000f); // should print unsigned + mp_printf(&mp_plat_print, "%X\n", 0x8000000f); // should print unsigned + // note: storing the string in a variable is enough to prevent the + // format string checker from checking this format string. Otherwise, + // it would be a compile time diagnostic under the format string + // checker. + const char msg[] = "abc\n%"; + mp_printf(&mp_plat_print, msg); // string ends in middle of format specifier mp_printf(&mp_plat_print, "%%\n"); // literal % character + mp_printf(&mp_plat_print, ".%-3s.\n", "a"); // left adjust + + // Check that all kinds of mp_printf arguments are parsed out + // correctly, by having a char argument before and after each main type + // of value that can be formatted. + mp_printf(&mp_plat_print, "%c%%%c\n", '<', '>'); + mp_printf(&mp_plat_print, "%c%p%c\n", '<', (void *)0xaaaa, '>'); + mp_printf(&mp_plat_print, "%c%b%c\n", '<', true, '>'); + mp_printf(&mp_plat_print, "%c%d%c\n", '<', 0xaaaa, '>'); + mp_printf(&mp_plat_print, "%c%ld%c\n", '<', 0xaaaal, '>'); + mp_printf(&mp_plat_print, "%c" INT_FMT "%c\n", '<', (mp_int_t)0xaaaa, '>'); + mp_printf(&mp_plat_print, "%c%s%c\n", '<', "test", '>'); + mp_printf(&mp_plat_print, "%c%f%c\n", '<', MICROPY_FLOAT_CONST(1000.), '>'); + mp_printf(&mp_plat_print, "%c%q%c\n", '<', (qstr)MP_QSTR_True, '>'); + if (sizeof(mp_int_t) == 8) { + mp_printf(&mp_plat_print, "%c%lld%c\n", '<', LLONG_MAX, '>'); + } else { + mp_printf(&mp_plat_print, "<9223372036854775807>\n"); + } + + } // GC @@ -220,11 +274,33 @@ static mp_obj_t extra_coverage(void) { gc_unlock(); // using gc_realloc to resize to 0, which means free the memory - void *p = gc_alloc(4, false); + void *p = gc_alloc(4, 0); mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false)); // calling gc_nbytes with a non-heap pointer - mp_printf(&mp_plat_print, "%p\n", gc_nbytes(NULL)); + mp_printf(&mp_plat_print, "%d\n", (int)gc_nbytes(NULL)); + + // test gc_info_fast + void *p0 = gc_alloc(4, 0); + void *p1 = gc_alloc(4, 0); + void *p2 = gc_alloc(4, 0); + + // Create a hole + gc_free(p1); + + gc_info_t info_slow; + gc_info_t info_fast; + + gc_info(&info_slow); + gc_info_fast(&info_fast); + + // Free allocs + gc_free(p0); + gc_free(p2); + + // Should be equal + mp_printf(&mp_plat_print, "%d\n", info_slow.used == info_fast.used); + mp_printf(&mp_plat_print, "%d\n", info_slow.free == info_fast.free); } // GC initialisation and allocation stress test, to check the logic behind ALLOC_TABLE_GAP_BYTE @@ -285,13 +361,20 @@ static mp_obj_t extra_coverage(void) { } ptrs[i][j] = j; } - mp_printf(&mp_plat_print, "%d %d\n", i, all_zero); + mp_printf(&mp_plat_print, "%d %d\n", (int)i, (int)all_zero); // hide the pointer from the GC and collect ptrs[i] = FLIP_POINTER(ptrs[i]); gc_collect(); } + // resize one of the blocks + void *before = ptrs[1]; + ptrs[1] = FLIP_POINTER(m_tracked_realloc(FLIP_POINTER(ptrs[1]), 2 * NUM_BYTES)); + void *after = ptrs[1]; + bool location_changed = before != after; + mp_printf(&mp_plat_print, "%d\n", location_changed); + // check the memory blocks have the correct content for (size_t i = 0; i < NUM_PTRS; ++i) { bool correct_contents = true; @@ -301,7 +384,7 @@ static mp_obj_t extra_coverage(void) { break; } } - mp_printf(&mp_plat_print, "%d %d\n", i, correct_contents); + mp_printf(&mp_plat_print, "%d %d\n", (int)i, (int)correct_contents); } // free the memory blocks @@ -310,6 +393,65 @@ static mp_obj_t extra_coverage(void) { } mp_printf(&mp_plat_print, "m_tracked_head = %p\n", MP_STATE_VM(m_tracked_head)); + + // Test realloc with black-box behavioral testing + mp_printf(&mp_plat_print, "# tracked realloc\n"); + + // Test 1: Basic realloc with data preservation + uint8_t *test_ptr = m_tracked_calloc(1, 32); + for (int i = 0; i < 32; i++) { + test_ptr[i] = i; + } + + test_ptr = m_tracked_realloc(test_ptr, 64); // Grow + bool data_preserved = (test_ptr[0] == 0 && test_ptr[31] == 31); + mp_printf(&mp_plat_print, "grow preserves data: %d\n", data_preserved); + + test_ptr = m_tracked_realloc(test_ptr, 16); // Shrink + bool shrink_ok = (test_ptr[0] == 0 && test_ptr[15] == 15); + mp_printf(&mp_plat_print, "shrink preserves data: %d\n", shrink_ok); + + m_tracked_free(test_ptr); + + // Test 2: Multiple allocations + reallocs + GC stability + uint8_t *realloc_ptrs[5]; + for (int i = 0; i < 5; i++) { + realloc_ptrs[i] = m_tracked_calloc(1, 32); + realloc_ptrs[i][0] = 'A' + i; // Mark each + } + + // Realloc some in different positions + realloc_ptrs[0] = m_tracked_realloc(realloc_ptrs[0], 64); // First allocated (tail of list) + realloc_ptrs[2] = m_tracked_realloc(realloc_ptrs[2], 64); // Middle + realloc_ptrs[4] = m_tracked_realloc(realloc_ptrs[4], 64); // Last allocated (head of list) + + // Run GC - if list corrupted, this might crash/fail + gc_collect(); + + // Verify markers intact + bool markers_ok = true; + for (int i = 0; i < 5; i++) { + if (realloc_ptrs[i][0] != 'A' + i) { + markers_ok = false; + break; + } + } + mp_printf(&mp_plat_print, "realloc gc stable: %d\n", markers_ok); + + // Cleanup + for (int i = 0; i < 5; i++) { + m_tracked_free(realloc_ptrs[i]); + } + + // Test 3: Edge cases + uint8_t *null_alloc = m_tracked_realloc(NULL, 32); + null_alloc[0] = 'X'; + mp_printf(&mp_plat_print, "realloc(NULL) ok: %d\n", null_alloc[0] == 'X'); + + void *free_result = m_tracked_realloc(null_alloc, 0); + mp_printf(&mp_plat_print, "realloc(ptr, 0) returns NULL: %d\n", free_result == NULL); + + mp_printf(&mp_plat_print, "m_tracked_head after cleanup: %p\n", MP_STATE_VM(m_tracked_head)); } // vstr @@ -400,7 +542,7 @@ static mp_obj_t extra_coverage(void) { // create a bytearray via mp_obj_new_bytearray mp_buffer_info_t bufinfo; mp_get_buffer_raise(mp_obj_new_bytearray(4, "data"), &bufinfo, MP_BUFFER_RW); - mp_printf(&mp_plat_print, "%.*s\n", bufinfo.len, bufinfo.buf); + mp_printf(&mp_plat_print, "%.*s\n", (int)bufinfo.len, bufinfo.buf); } // mpz @@ -464,6 +606,77 @@ static mp_obj_t extra_coverage(void) { mp_int_t value_signed; mpz_as_int_checked(&mpz, &value_signed); mp_printf(&mp_plat_print, "%d\n", (int)value_signed); + + // hash the zero mpz integer + mpz_set_from_int(&mpz, 0); + mp_printf(&mp_plat_print, "%d\n", (int)mpz_hash(&mpz)); + + // convert the mpz zero integer to int + mp_printf(&mp_plat_print, "%d\n", mpz_as_int_checked(&mpz, &value_signed)); + mp_printf(&mp_plat_print, "%d\n", (int)value_signed); + + // mpz_set_from_float with 0 as argument + mpz_set_from_float(&mpz, 0); + mp_printf(&mp_plat_print, "%f\n", mpz_as_float(&mpz)); + + // convert a large integer value (stored in a mpz) to mp_uint_t and to ll; + mp_obj_t obj_bigint = mp_obj_new_int_from_uint((mp_uint_t)0xdeadbeef); + mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint)); + obj_bigint = mp_obj_new_int_from_ll(0xc0ffee777c0ffeell); + long long value_ll = mp_obj_get_ll(obj_bigint); + mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll); + + // convert a large integer value (stored via a struct object) to uint and to ll + // `deadbeef` global is an uctypes.struct defined by extra_coverage.py + obj_bigint = mp_load_global(MP_QSTR_deadbeef); + mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint)); + value_ll = mp_obj_get_ll(obj_bigint); + mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll); + + // convert a smaller integer value to mp_uint_t and to ll + obj_bigint = mp_obj_new_int_from_uint(0xc0ffee); + mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint)); + value_ll = mp_obj_get_ll(obj_bigint); + mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll); + } + + // list argument helpers + { + mp_printf(&mp_plat_print, "# list argument helpers\n"); + + // Create a list to test with + mp_obj_t list_items[] = { mp_const_none, MP_OBJ_NEW_SMALL_INT(77), mp_obj_new_str_from_cstr("hello") }; + size_t list_len = MP_ARRAY_SIZE(list_items); + mp_obj_t list = mp_obj_new_list(list_len, list_items); + + // mp_obj_list_ensure + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_list_ensure(MP_OBJ_NEW_SMALL_INT(-1), 5); // Not a list + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + + if (nlr_push(&nlr) == 0) { + mp_obj_list_ensure(list, list_len + 2); // List shorter than minimum length + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + + mp_obj_list_t *as_ptr = mp_obj_list_ensure(list, list_len); // Acceptable! + mp_printf(&mp_plat_print, "mp_obj_list_ensure same list? %d\n", MP_OBJ_TO_PTR(list) == as_ptr); + + // mp_obj_list_optional_arg() + as_ptr = mp_obj_list_optional_arg(list, list_len); + mp_printf(&mp_plat_print, "mp_obj_list_optional_arg same list? %d\n", MP_OBJ_TO_PTR(list) == as_ptr); + + as_ptr = mp_obj_list_optional_arg(mp_const_none, list_len); + mp_printf(&mp_plat_print, "mp_obj_list_optional_arg new list len " SIZE_FMT "\n", as_ptr->len); + + as_ptr = mp_obj_list_optional_arg(MP_OBJ_NULL, list_len); + mp_printf(&mp_plat_print, "mp_obj_list_optional_arg new list from NULL len " SIZE_FMT "\n", as_ptr->len); } // runtime utils @@ -481,7 +694,7 @@ static mp_obj_t extra_coverage(void) { mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str_from_cstr("abc"), mp_obj_new_str_from_cstr("abc")); // mp_obj_int_get_checked with mp_obj_int_t that has a value that is a small integer - mp_printf(&mp_plat_print, "%d\n", mp_obj_int_get_checked(mp_obj_int_new_mpz())); + mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_checked(MP_OBJ_FROM_PTR(mp_obj_int_new_mpz()))); // mp_obj_int_get_uint_checked with non-negative small-int mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(MP_OBJ_NEW_SMALL_INT(1))); @@ -506,6 +719,22 @@ static mp_obj_t extra_coverage(void) { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); } + // mp_obj_get_uint from a non-int object (should raise exception) + if (nlr_push(&nlr) == 0) { + mp_obj_get_uint(mp_const_none); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + + // mp_obj_int_get_ll from a non-int object (should raise exception) + if (nlr_push(&nlr) == 0) { + mp_obj_get_ll(mp_const_none); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + // call mp_obj_new_exception_args (it's a part of the public C API and not used in the core) mp_obj_print_exception(&mp_plat_print, mp_obj_new_exception_args(&mp_type_ValueError, 0, NULL)); } @@ -515,39 +744,6 @@ static mp_obj_t extra_coverage(void) { mp_emitter_warning(MP_PASS_CODE_SIZE, "test"); } - // format float - { - mp_printf(&mp_plat_print, "# format float\n"); - - // format with inadequate buffer size - char buf[5]; - mp_format_float(1, buf, sizeof(buf), 'g', 0, '+'); - mp_printf(&mp_plat_print, "%s\n", buf); - - // format with just enough buffer so that precision must be - // set from 0 to 1 twice - char buf2[8]; - mp_format_float(1, buf2, sizeof(buf2), 'g', 0, '+'); - mp_printf(&mp_plat_print, "%s\n", buf2); - - // format where precision is trimmed to avoid buffer overflow - mp_format_float(1, buf2, sizeof(buf2), 'e', 0, '+'); - mp_printf(&mp_plat_print, "%s\n", buf2); - } - - // binary - { - mp_printf(&mp_plat_print, "# binary\n"); - - // call function with float and double typecodes - float far[1]; - double dar[1]; - mp_binary_set_val_array_from_int('f', far, 0, 123); - mp_printf(&mp_plat_print, "%.0f\n", (double)far[0]); - mp_binary_set_val_array_from_int('d', dar, 0, 456); - mp_printf(&mp_plat_print, "%.0lf\n", dar[0]); - } - // VM { mp_printf(&mp_plat_print, "# VM\n"); @@ -558,14 +754,26 @@ static mp_obj_t extra_coverage(void) { fun_bc.context = &context; fun_bc.child_table = NULL; fun_bc.bytecode = (const byte *)"\x01"; // just needed for n_state + #if MICROPY_PY_SYS_SETTRACE + struct _mp_raw_code_t rc = {}; + fun_bc.rc = &rc; + #endif mp_code_state_t *code_state = m_new_obj_var(mp_code_state_t, state, mp_obj_t, 1); code_state->fun_bc = &fun_bc; code_state->ip = (const byte *)"\x00"; // just needed for an invalid opcode code_state->sp = &code_state->state[0]; code_state->exc_sp_idx = 0; code_state->old_globals = NULL; + #if MICROPY_STACKLESS + code_state->prev = NULL; + #endif + #if MICROPY_PY_SYS_SETTRACE + code_state->prev_state = NULL; + code_state->frame = NULL; + #endif + mp_vm_return_kind_t ret = mp_execute_bytecode(code_state, MP_OBJ_NULL); - mp_printf(&mp_plat_print, "%d %d\n", ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError); + mp_printf(&mp_plat_print, "%d %d\n", (int)ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError); } // scheduler @@ -622,9 +830,25 @@ static mp_obj_t extra_coverage(void) { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); } mp_handle_pending(true); + + // CIRCUITPY-CHANGE: not turned on in CircuitPython + #if MICROPY_SCHEDULER_STATIC_NODES + coverage_sched_function_continue = true; + mp_sched_schedule_node(&mp_coverage_sched_node, coverage_sched_function); + for (int i = 0; i < 3; ++i) { + mp_printf(&mp_plat_print, "loop\n"); + mp_handle_pending(true); + } + // Clear this flag to prevent the function scheduling itself again + coverage_sched_function_continue = false; + // Will only run the first time through this loop, then not scheduled again + for (int i = 0; i < 3; ++i) { + mp_handle_pending(true); + } + #endif } - // CIRCUITPY-CHANGE: ringbuf is different + // CIRCUITPY-CHANGE: ringbuf is quite different // ringbuf { #define RINGBUF_SIZE 99 @@ -636,36 +860,36 @@ static mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# ringbuf\n"); // Single-byte put/get with empty ringbuf. - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); ringbuf_put(&ringbuf, 22); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_get(&ringbuf)); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); // Two-byte put/get with empty ringbuf. ringbuf_put16(&ringbuf, 0xaa55); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); // Two-byte put with full ringbuf. for (int i = 0; i < RINGBUF_SIZE; ++i) { ringbuf_put(&ringbuf, i); } - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x11bb)); // Two-byte put with one byte free. ringbuf_get(&ringbuf); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x3377)); ringbuf_get(&ringbuf); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0xcc99)); for (int i = 0; i < RINGBUF_SIZE - 2; ++i) { ringbuf_get(&ringbuf); } mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); // Two-byte put with wrap around on first byte: ringbuf_clear(&ringbuf); @@ -777,7 +1001,7 @@ static mp_obj_t extra_coverage(void) { mp_obj_streamtest_t *s2 = mp_obj_malloc(mp_obj_streamtest_t, &mp_type_stest_textio2); // return a tuple of data for testing on the Python side - mp_obj_t items[] = {(mp_obj_t)&str_no_hash_obj, (mp_obj_t)&bytes_no_hash_obj, MP_OBJ_FROM_PTR(s), MP_OBJ_FROM_PTR(s2)}; + mp_obj_t items[] = {MP_OBJ_FROM_PTR(&str_no_hash_obj), MP_OBJ_FROM_PTR(&bytes_no_hash_obj), MP_OBJ_FROM_PTR(s), MP_OBJ_FROM_PTR(s2)}; return mp_obj_new_tuple(MP_ARRAY_SIZE(items), items); } MP_DEFINE_CONST_FUN_OBJ_0(extra_coverage_obj, extra_coverage); diff --git a/ports/unix/coveragecpp.cpp b/ports/unix/coveragecpp.cpp index 377b5acf763..8ba308f6468 100644 --- a/ports/unix/coveragecpp.cpp +++ b/ports/unix/coveragecpp.cpp @@ -1,12 +1,77 @@ extern "C" { -// CIRCUITPY-CHANGE: do not include everything: it causes compilation warnings -#include "py/obj.h" +// Include the complete public API to verify everything compiles as C++. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include } +// Invoke all (except one, see below) public API macros which initialize structs to make sure +// they are C++-compatible, meaning they explicitly initialize all struct members. +mp_obj_t f0(); +MP_DEFINE_CONST_FUN_OBJ_0(f0_obj, f0); +mp_obj_t f1(mp_obj_t); +MP_DEFINE_CONST_FUN_OBJ_1(f1_obj, f1); +mp_obj_t f2(mp_obj_t, mp_obj_t); +MP_DEFINE_CONST_FUN_OBJ_2(f2_obj, f2); +mp_obj_t f3(mp_obj_t, mp_obj_t, mp_obj_t); +MP_DEFINE_CONST_FUN_OBJ_3(f3_obj, f3); +mp_obj_t fvar(size_t, const mp_obj_t *); +MP_DEFINE_CONST_FUN_OBJ_VAR(fvar_obj, 1, fvar); +mp_obj_t fvarbetween(size_t, const mp_obj_t *); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fvarbetween_obj, 1, 2, fvarbetween); +mp_obj_t fkw(size_t, const mp_obj_t *, mp_map_t *); +MP_DEFINE_CONST_FUN_OBJ_KW(fkw_obj, 1, fkw); + +static const mp_rom_map_elem_t table[] = { + { MP_ROM_QSTR(MP_QSTR_f0), MP_ROM_PTR(&f0_obj) }, +}; +MP_DEFINE_CONST_MAP(map, table); +MP_DEFINE_CONST_DICT(dict, table); + +static const qstr attrtuple_fields[] = { + MP_QSTR_f0, +}; +MP_DEFINE_ATTRTUPLE(attrtuple, attrtuple_fields, 1, MP_ROM_PTR(&f0_obj)); + +void nlr_cb(void *); +void nlr_cb(void *){ +} + +// The MP_DEFINE_CONST_OBJ_TYPE macro is not C++-compatible because each of the +// MP_DEFINE_CONST_OBJ_TYPE_NARGS_X macros only initializes some of _mp_obj_type_t's +// .slot_index_xxx members but that cannot be fixed to be done in a deterministic way. + + #if defined(MICROPY_UNIX_COVERAGE) // Just to test building of C++ code. static mp_obj_t extra_cpp_coverage_impl() { + MP_DEFINE_NLR_JUMP_CALLBACK_FUNCTION_1(ctx, nlr_cb, (void *) nlr_cb); + + // To avoid 'error: unused variable [-Werror,-Wunused-const-variable]'. + (void) ctx; + (void) f0_obj; + (void) f1_obj; + (void) f2_obj; + (void) f3_obj; + (void) fvar_obj; + (void) fvarbetween_obj; + (void) fkw_obj; + (void) map; + (void) dict; + (void) attrtuple; return mp_const_none; } diff --git a/ports/unix/input.c b/ports/unix/input.c index 31926a5a8e1..260e9eac8c9 100644 --- a/ports/unix/input.c +++ b/ports/unix/input.c @@ -104,6 +104,9 @@ void prompt_write_history(void) { #if MICROPY_USE_READLINE == 1 char *home = getenv("HOME"); if (home != NULL) { + if (MP_STATE_THREAD(gc_lock_depth) != 0) { + return; + } vstr_t vstr; vstr_init(&vstr, 50); vstr_printf(&vstr, "%s/.micropython.history", home); diff --git a/ports/unix/main.c b/ports/unix/main.c index ce8b8913637..dc72d79127c 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -54,38 +54,11 @@ #include "extmod/vfs_posix.h" #include "genhdr/mpversion.h" #include "input.h" - -// CIRCUITPY-CHANGE -#if defined(MICROPY_UNIX_COVERAGE) -#include "py/objstr.h" -typedef int os_getenv_err_t; -mp_obj_t common_hal_os_getenv(const char *key, mp_obj_t default_); -os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len); -os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value); - -static mp_obj_t mod_os_getenv_int(mp_obj_t var_in) { - mp_int_t value; - os_getenv_err_t result = common_hal_os_getenv_int(mp_obj_str_get_str(var_in), &value); - if (result == 0) { - return mp_obj_new_int(value); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_int_obj, mod_os_getenv_int); - -static mp_obj_t mod_os_getenv_str(mp_obj_t var_in) { - char buf[4096]; - os_getenv_err_t result = common_hal_os_getenv_str(mp_obj_str_get_str(var_in), buf, sizeof(buf)); - if (result == 0) { - return mp_obj_new_str_copy(&mp_type_str, (byte *)buf, strlen(buf)); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_str_obj, mod_os_getenv_str); -#endif +#include "stack_size.h" +#include "shared/runtime/pyexec.h" // Command line options, with their defaults -static bool compile_only = false; +bool mp_compile_only = false; static uint emit_opt = MP_EMIT_OPT_NONE; #if MICROPY_ENABLE_GC @@ -119,7 +92,8 @@ static void stderr_print_strn(void *env, const char *str, size_t len) { const mp_print_t mp_stderr_print = {NULL, stderr_print_strn}; -#define FORCED_EXIT (0x100) +// CIRCUITPY-CHANGE: be consistent about using PYEXEC_FORCED_EXIT +// #define FORCED_EXIT (0x100) // If exc is SystemExit, return value where FORCED_EXIT bit set, // and lower 8 bits are SystemExit value. For all other exceptions, // return 1. @@ -132,7 +106,8 @@ static int handle_uncaught_exception(mp_obj_base_t *exc) { if (exit_val != mp_const_none && !mp_obj_get_int_maybe(exit_val, &val)) { val = 1; } - return FORCED_EXIT | (val & 255); + // CIRCUITPY-CHANGE: be consistent about using PYEXEC_FORCED_EXIT + return PYEXEC_FORCED_EXIT | (val & 255); } // Report all other exceptions @@ -141,8 +116,6 @@ static int handle_uncaught_exception(mp_obj_base_t *exc) { } #define LEX_SRC_STR (1) -#define LEX_SRC_VSTR (2) -#define LEX_SRC_FILENAME (3) #define LEX_SRC_STDIN (4) // Returns standard error codes: 0 for success, 1 for all other errors, @@ -158,19 +131,13 @@ static int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu if (source_kind == LEX_SRC_STR) { const char *line = source; lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false); - } else if (source_kind == LEX_SRC_VSTR) { - const vstr_t *vstr = source; - lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false); - } else if (source_kind == LEX_SRC_FILENAME) { - const char *filename = (const char *)source; - lex = mp_lexer_new_from_file(qstr_from_str(filename)); } else { // LEX_SRC_STDIN lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false); } qstr source_name = lex->source_name; - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ if (input_kind == MP_PARSE_FILE_INPUT) { mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); } @@ -180,7 +147,7 @@ static int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu #if defined(MICROPY_UNIX_COVERAGE) // allow to print the parse tree in the coverage build - if (mp_verbose_flag >= 3) { + if (MP_STATE_VM(mp_verbose_flag) >= 3) { printf("----------------\n"); mp_parse_node_print(&mp_plat_print, parse_tree.root, 0); printf("----------------\n"); @@ -189,7 +156,7 @@ static int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu mp_obj_t module_fun = mp_compile(&parse_tree, source_name, is_repl); - if (!compile_only) { + if (!mp_compile_only) { // execute it mp_call_function_0(module_fun); } @@ -226,92 +193,32 @@ static char *strjoin(const char *s1, int sep_char, const char *s2) { #endif static int do_repl(void) { - mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION); - mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE); - mp_hal_stdout_tx_str("\nUse Ctrl-D to exit, Ctrl-E for paste mode\n"); - #if MICROPY_USE_READLINE == 1 - // use MicroPython supplied readline + // use MicroPython supplied readline-based REPL - vstr_t line; - vstr_init(&line, 16); + int ret = 0; for (;;) { - mp_hal_stdio_mode_raw(); - - input_restart: - vstr_reset(&line); - int ret = readline(&line, mp_repl_get_ps1()); - mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT; - - if (ret == CHAR_CTRL_C) { - // cancel input - mp_hal_stdout_tx_str("\r\n"); - goto input_restart; - } else if (ret == CHAR_CTRL_D) { - // EOF - printf("\n"); - mp_hal_stdio_mode_orig(); - vstr_clear(&line); - return 0; - } else if (ret == CHAR_CTRL_E) { - // paste mode - mp_hal_stdout_tx_str("\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\n=== "); - vstr_reset(&line); - for (;;) { - char c = mp_hal_stdin_rx_chr(); - if (c == CHAR_CTRL_C) { - // cancel everything - mp_hal_stdout_tx_str("\n"); - goto input_restart; - } else if (c == CHAR_CTRL_D) { - // end of input - mp_hal_stdout_tx_str("\n"); - break; - } else { - // add char to buffer and echo - vstr_add_byte(&line, c); - if (c == '\r') { - mp_hal_stdout_tx_str("\n=== "); - } else { - mp_hal_stdout_tx_strn(&c, 1); - } - } - } - parse_input_kind = MP_PARSE_FILE_INPUT; - } else if (line.len == 0) { - if (ret != 0) { - printf("\n"); + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if ((ret = pyexec_raw_repl()) != 0) { + break; } - goto input_restart; } else { - // got a line with non-zero length, see if it needs continuing - while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) { - vstr_add_byte(&line, '\n'); - ret = readline(&line, mp_repl_get_ps2()); - if (ret == CHAR_CTRL_C) { - // cancel everything - printf("\n"); - goto input_restart; - } else if (ret == CHAR_CTRL_D) { - // stop entering compound statement - break; - } + if ((ret = pyexec_friendly_repl()) != 0) { + break; } } - - mp_hal_stdio_mode_orig(); - - ret = execute_from_lexer(LEX_SRC_VSTR, &line, parse_input_kind, true); - if (ret & FORCED_EXIT) { - return ret; - } } + return ret; #else // use simple readline + mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION); + mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE); + mp_hal_stdout_tx_str("\nUse Ctrl-D to exit, Ctrl-E for paste mode\n"); + for (;;) { char *line = prompt((char *)mp_repl_get_ps1()); if (line == NULL) { @@ -331,7 +238,8 @@ static int do_repl(void) { int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true); free(line); - if (ret & FORCED_EXIT) { + // CIRCUITPY-CHANGE: be consistent about using PYEXEC_FORCED_EXIT + if (ret & PYEXEC_FORCED_EXIT) { return ret; } } @@ -339,12 +247,44 @@ static int do_repl(void) { #endif } +static inline int convert_pyexec_result(int ret) { + #if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING + // With exit code handling enabled: + // pyexec returns exit code with PYEXEC_FORCED_EXIT flag set for SystemExit + // Unix port expects: 0 for success, non-zero for error/exit + if (ret & PYEXEC_FORCED_EXIT) { + // SystemExit: extract exit code from lower bits + return ret & 0xFF; + } + // Normal execution or exception: return as-is (0 for success, 1 for exception) + return ret; + #else + // pyexec returns 1 for success, 0 for exception, PYEXEC_FORCED_EXIT for SystemExit + // Convert to unix port's expected codes: 0 for success, 1 for exception, FORCED_EXIT|val for SystemExit + if (ret == 1) { + return 0; // success + } else if (ret & PYEXEC_FORCED_EXIT) { + return ret; // SystemExit with exit value in lower 8 bits + } else { + return 1; // exception + } + #endif +} + static int do_file(const char *file) { - return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false); + // CIRCUITPY-CHANGE: pyexec_file result arg + pyexec_result_t pyexec_result; + return convert_pyexec_result(pyexec_file(file, &pyexec_result)); } static int do_str(const char *str) { - return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false); + vstr_t vstr; + vstr.buf = (char *)str; + vstr.len = strlen(str); + // CIRCUITPY-CHANGE: pyexec_vstr result arg + pyexec_result_t pyexec_result; + int ret = pyexec_vstr(&vstr, true, &pyexec_result); + return convert_pyexec_result(ret); } static void print_help(char **argv) { @@ -413,7 +353,7 @@ static void pre_process_options(int argc, char **argv) { } if (0) { } else if (strcmp(argv[a + 1], "compile-only") == 0) { - compile_only = true; + mp_compile_only = true; } else if (strcmp(argv[a + 1], "emit=bytecode") == 0) { emit_opt = MP_EMIT_OPT_BYTECODE; #if MICROPY_EMIT_NATIVE @@ -485,10 +425,13 @@ static void set_sys_argv(char *argv[], int argc, int start_arg) { #if MICROPY_PY_SYS_EXECUTABLE extern mp_obj_str_t mp_sys_executable_obj; -static char executable_path[MICROPY_ALLOC_PATH_MAX]; +static char *executable_path = NULL; static void sys_set_excecutable(char *argv0) { - if (realpath(argv0, executable_path)) { + if (executable_path == NULL) { + executable_path = realpath(argv0, NULL); + } + if (executable_path != NULL) { mp_obj_str_set_data(&mp_sys_executable_obj, (byte *)executable_path, strlen(executable_path)); } } @@ -508,11 +451,7 @@ int main(int argc, char **argv) { #endif // Define a reasonable stack limit to detect stack overflow. - mp_uint_t stack_size = 40000 * (sizeof(void *) / 4); - #if defined(__arm__) && !defined(__thumb2__) - // ARM (non-Thumb) architectures require more stack. - stack_size *= 2; - #endif + mp_uint_t stack_size = 40000 * UNIX_STACK_MULTIPLIER; // We should capture stack top ASAP after start, and it should be // captured guaranteedly before any other stack variables are allocated. @@ -645,24 +584,9 @@ MP_NOINLINE int main_(int argc, char **argv) { // CIRCUITPY-CHANGE: test native base classes work as needed by CircuitPython libraries. extern const mp_obj_type_t native_base_class_type; mp_store_global(MP_QSTR_NativeBaseClass, MP_OBJ_FROM_PTR(&native_base_class_type)); - mp_store_global(MP_QSTR_getenv_int, MP_OBJ_FROM_PTR(&mod_os_getenv_int_obj)); - mp_store_global(MP_QSTR_getenv_str, MP_OBJ_FROM_PTR(&mod_os_getenv_str_obj)); } #endif - // Here is some example code to create a class and instance of that class. - // First is the Python, then the C code. - // - // class TestClass: - // pass - // test_obj = TestClass() - // test_obj.attr = 42 - // - // mp_obj_t test_class_type, test_class_instance; - // test_class_type = mp_obj_new_type(qstr_from_str("TestClass"), mp_const_empty_tuple, mp_obj_new_dict(0)); - // mp_store_name(qstr_from_str("test_obj"), test_class_instance = mp_call_function_0(test_class_type)); - // mp_store_attr(test_class_instance, qstr_from_str("attr"), mp_obj_new_int(42)); - /* printf("bytes:\n"); printf(" total %d\n", m_get_total_bytes_allocated()); @@ -716,12 +640,18 @@ MP_NOINLINE int main_(int argc, char **argv) { subpkg_tried = false; reimport: + mp_hal_set_interrupt_char(CHAR_CTRL_C); if (nlr_push(&nlr) == 0) { mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args); + mp_hal_set_interrupt_char(-1); + mp_handle_pending(true); nlr_pop(); } else { // uncaught exception - return handle_uncaught_exception(nlr.ret_val) & 0xff; + mp_hal_set_interrupt_char(-1); + mp_handle_pending(false); + ret = handle_uncaught_exception(nlr.ret_val) & 0xff; + break; } // If this module is a package, see if it has a `__main__.py`. @@ -744,7 +674,7 @@ MP_NOINLINE int main_(int argc, char **argv) { a += 1; #if MICROPY_DEBUG_PRINTERS } else if (strcmp(argv[a], "-v") == 0) { - mp_verbose_flag++; + MP_STATE_VM(mp_verbose_flag)++; #endif } else if (strncmp(argv[a], "-O", 2) == 0) { if (unichar_isdigit(argv[a][2])) { @@ -758,11 +688,9 @@ MP_NOINLINE int main_(int argc, char **argv) { return invalid_args(); } } else { - char *pathbuf = malloc(PATH_MAX); - char *basedir = realpath(argv[a], pathbuf); + char *basedir = realpath(argv[a], NULL); if (basedir == NULL) { mp_printf(&mp_stderr_print, "%s: can't open file '%s': [Errno %d] %s\n", argv[0], argv[a], errno, strerror(errno)); - free(pathbuf); // CPython exits with 2 in such case ret = 2; break; @@ -771,7 +699,7 @@ MP_NOINLINE int main_(int argc, char **argv) { // Set base dir of the script as first entry in sys.path. char *p = strrchr(basedir, '/'); mp_obj_list_store(mp_sys_path, MP_OBJ_NEW_SMALL_INT(0), mp_obj_new_str_via_qstr(basedir, p - basedir)); - free(pathbuf); + free(basedir); set_sys_argv(argv, argc, a); ret = do_file(argv[a]); @@ -805,13 +733,13 @@ MP_NOINLINE int main_(int argc, char **argv) { #endif #if MICROPY_PY_MICROPYTHON_MEM_INFO - if (mp_verbose_flag) { + if (MP_STATE_VM(mp_verbose_flag)) { mp_micropython_mem_info(0, NULL); } #endif #if MICROPY_PY_BLUETOOTH - void mp_bluetooth_deinit(void); + int mp_bluetooth_deinit(void); mp_bluetooth_deinit(); #endif @@ -837,8 +765,20 @@ MP_NOINLINE int main_(int argc, char **argv) { #endif #endif + #if MICROPY_PY_SYS_EXECUTABLE && !defined(NDEBUG) + // Again, make memory leak detector happy + free(executable_path); + #endif + // printf("total bytes = %d\n", m_get_total_bytes_allocated()); - return ret & 0xff; + + // CIRCUITPY-CHANGE: handle PYEXEC_UNHANDLED_EXCEPTION + if (ret == PYEXEC_UNHANDLED_EXCEPTION) { + // Return exit status code 1 so the invoker knows there was an uncaught exception. + return 1; + } else { + return ret & 0xff; + } } void nlr_jump_fail(void *val) { diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index b469e932e0d..c16d40ad3b4 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -446,7 +446,7 @@ static unsigned long long ffi_get_int_value(mp_obj_t o) { return MP_OBJ_SMALL_INT_VALUE(o); } else { unsigned long long res; - mp_obj_int_to_bytes_impl(o, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res); + mp_obj_int_to_bytes(o, sizeof(res), (byte *)&res, MP_ENDIANNESS_BIG, false, false); return res; } } diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c index dbce61aec11..0a29a94fbd4 100644 --- a/ports/unix/modjni.c +++ b/ports/unix/modjni.c @@ -357,7 +357,7 @@ static void jmethod_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki (void)kind; mp_obj_jmethod_t *self = MP_OBJ_TO_PTR(self_in); // Variable value printed as cast to int - mp_printf(print, "", qstr_str(self->name)); + mp_printf(print, "", (qstr)self->name); } #define IMATCH(s, static) ((!strncmp(s, static, sizeof(static) - 1)) && (s += sizeof(static) - 1)) diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 896bf351b83..28f232e42bc 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -32,13 +32,12 @@ #include "py/runtime.h" #include "py/mphal.h" -// CIRCUITPY-CHANGE: enhanced getenv +// CIRCUITPY-CHANGE: use shared-module os getenv #if defined(MICROPY_UNIX_COVERAGE) #include "py/objstr.h" -typedef int os_getenv_err_t; +#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" mp_obj_t common_hal_os_getenv(const char *key, mp_obj_t default_); -os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len); -os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value); #endif static mp_obj_t mp_os_getenv(size_t n_args, const mp_obj_t *args) { @@ -58,30 +57,7 @@ static mp_obj_t mp_os_getenv(size_t n_args, const mp_obj_t *args) { } return mp_obj_new_str_from_cstr(s); } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_os_getenv_obj, 1, 2, mp_os_getenv); - -// CIRCUITPY-CHANGE: getenv differences -#if defined(MICROPY_UNIX_COVERAGE) -static mp_obj_t mp_os_getenv_int(mp_obj_t var_in) { - mp_int_t value; - os_getenv_err_t result = common_hal_os_getenv_int(mp_obj_str_get_str(var_in), &value); - if (result == 0) { - return mp_obj_new_int(value); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mp_os_getenv_int_obj, mp_os_getenv_int); - -static mp_obj_t mp_os_getenv_str(mp_obj_t var_in) { - char buf[4096]; - os_getenv_err_t result = common_hal_os_getenv_str(mp_obj_str_get_str(var_in), buf, sizeof(buf)); - if (result == 0) { - return mp_obj_new_str_copy(&mp_type_str, (byte *)buf, strlen(buf)); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mp_os_getenv_str_obj, mp_os_getenv_str); -#endif +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_os_getenv_obj, 1, 2, mp_os_getenv); static mp_obj_t mp_os_putenv(mp_obj_t key_in, mp_obj_t value_in) { const char *key = mp_obj_str_get_str(key_in); @@ -131,15 +107,6 @@ static mp_obj_t mp_os_system(mp_obj_t cmd_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(mp_os_system_obj, mp_os_system); -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); - mp_hal_get_random(n, vstr.buf); - return mp_obj_new_bytes_from_vstr(&vstr); -} -static MP_DEFINE_CONST_FUN_OBJ_1(mp_os_urandom_obj, mp_os_urandom); - static mp_obj_t mp_os_errno(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { return MP_OBJ_NEW_SMALL_INT(errno); diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index fbd94b5ecd1..97c9b292d06 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -34,6 +34,7 @@ #include "py/mphal.h" #include "py/runtime.h" +#include "shared/timeutils/timeutils.h" #ifdef _WIN32 static inline int msec_sleep_tv(struct timeval *tv) { @@ -94,6 +95,7 @@ static mp_obj_t mp_time_sleep(mp_obj_t arg) { tv.tv_sec = (suseconds_t)ipart; int res; while (1) { + mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS); MP_THREAD_GIL_EXIT(); res = sleep_select(0, NULL, NULL, NULL, &tv); MP_THREAD_GIL_ENTER(); @@ -103,7 +105,6 @@ static mp_obj_t mp_time_sleep(mp_obj_t arg) { if (res != -1 || errno != EINTR) { break; } - mp_handle_pending(true); // printf("select: EINTR: %ld:%ld\n", tv.tv_sec, tv.tv_usec); #else break; @@ -113,13 +114,13 @@ static mp_obj_t mp_time_sleep(mp_obj_t arg) { #else int seconds = mp_obj_get_int(arg); for (;;) { + mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS); MP_THREAD_GIL_EXIT(); seconds = sleep(seconds); MP_THREAD_GIL_ENTER(); if (seconds == 0) { break; } - mp_handle_pending(true); } #endif return mp_const_none; @@ -130,12 +131,7 @@ static mp_obj_t mod_time_gm_local_time(size_t n_args, const mp_obj_t *args, stru if (n_args == 0) { t = time(NULL); } else { - #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE - mp_float_t val = mp_obj_get_float(args[0]); - t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val); - #else - t = mp_obj_get_int(args[0]); - #endif + t = (time_t)timeutils_obj_get_timestamp(args[0]); } struct tm *tm = time_func(&t); @@ -193,10 +189,10 @@ static mp_obj_t mod_time_mktime(mp_obj_t tuple) { time.tm_isdst = -1; // auto-detect } time_t ret = mktime(&time); - if (ret == -1) { + if (ret == (time_t)-1) { mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("invalid mktime usage")); } - return mp_obj_new_int(ret); + return timeutils_obj_from_timestamp(ret); } MP_DEFINE_CONST_FUN_OBJ_1(mod_time_mktime_obj, mod_time_mktime); diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 4d9fe9f1dc4..7c2ede3bad3 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -32,6 +32,9 @@ // features to work on Unix-like systems, see mpconfigvariant.h (and // mpconfigvariant_common.h) for feature enabling. +// For time_t, needed by MICROPY_TIMESTAMP_IMPL_TIME_T. +#include + // For size_t and ssize_t #include @@ -41,6 +44,7 @@ // CIRCUITPY-CHANGE #define CIRCUITPY_MICROPYTHON_ADVANCED (1) #define MICROPY_PY_ASYNC_AWAIT (1) +#define MICROPY_PY_DOUBLE_TYPECODE (1) #define MICROPY_PY_UCTYPES (0) #ifndef MICROPY_CONFIG_ROM_LEVEL @@ -50,13 +54,20 @@ #ifndef MICROPY_PY_SYS_PLATFORM #if defined(__APPLE__) && defined(__MACH__) #define MICROPY_PY_SYS_PLATFORM "darwin" +#elif defined(__FreeBSD__) + #define MICROPY_PY_SYS_PLATFORM "freebsd" #else #define MICROPY_PY_SYS_PLATFORM "linux" #endif #endif #ifndef MICROPY_PY_SYS_PATH_DEFAULT -#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:/usr/lib/micropython" +#if defined(__FreeBSD__) +#define SYSTEM_LIB_PATH "/usr/local/lib/micropython" +#else +#define SYSTEM_LIB_PATH "/usr/lib/micropython" +#endif +#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:" SYSTEM_LIB_PATH #endif #define MP_STATE_PORT MP_STATE_VM @@ -78,21 +89,6 @@ #define MICROPY_EMIT_ARM (1) #endif -// Type definitions for the specific machine based on the word size. -#ifndef MICROPY_OBJ_REPR -#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 of actual size. -typedef int mp_int_t; // must be pointer size -typedef unsigned int mp_uint_t; // must be pointer size -#endif -#else -// Assume that if we already defined the obj repr then we also defined types. -#endif - // Cannot include , as it may lead to symbol name clashes #if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) typedef long long mp_off_t; @@ -115,9 +111,12 @@ typedef long mp_off_t; // CIRCUITPY-CHANGE #define MICROPY_ENABLE_SELECTIVE_COLLECT (1) -#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__) || (defined(__riscv) && (__riscv_xlen == 64))) -// Fall back to setjmp() implementation for discovery of GC pointers in registers. -#define MICROPY_GCREGS_SETJMP (1) +// Fall back to setjmp() implementation for discovery of GC pointers in registers +// if running on intel-based macOS, or on architectures for which there is no +// specialised GC pointer discovery mechanism. +#if (defined(__APPLE__) && defined(__MACH__) && (defined(__i386__) || defined(__x86_64__))) || \ + (!(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__) || (defined(__riscv) && __riscv_xlen <= 64) || (defined(__loongarch__) && defined(__loongarch64)))) +#define MICROPY_GCREGS_SETJMP (1) #endif // Enable the VFS, and enable the posix "filesystem". @@ -135,6 +134,9 @@ typedef long mp_off_t; // VFS stat functions should return time values relative to 1970/1/1 #define MICROPY_EPOCH_IS_1970 (1) +// port modtime functions use time_t +#define MICROPY_TIMESTAMP_IMPL (MICROPY_TIMESTAMP_IMPL_TIME_T) + // Assume that select() call, interrupted with a signal, and erroring // with EINTR, updates remaining timeout value. #define MICROPY_SELECT_REMAINING_TIME (1) @@ -145,6 +147,9 @@ typedef long mp_off_t; #define MICROPY_STACKLESS_STRICT (0) #endif +// Recursive mutex is needed when threading is enabled, regardless of GIL setting. +#define MICROPY_PY_THREAD_RECURSIVE_MUTEX (MICROPY_PY_THREAD) + // Implementation of the machine module. #define MICROPY_PY_MACHINE_INCLUDEFILE "ports/unix/modmachine.c" @@ -172,6 +177,12 @@ typedef long mp_off_t; // Enable sys.executable. #define MICROPY_PY_SYS_EXECUTABLE (1) +// Enable support for compile-only mode. +#define MICROPY_PYEXEC_COMPILE_ONLY (1) + +// Enable handling of sys.exit() exit codes. +#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (1) + #define MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128) // Bare-metal ports don't have stderr. Printing debug to stderr may give tests diff --git a/ports/unix/mpconfigport.mk b/ports/unix/mpconfigport.mk index 26c04faf4c5..5260bd46aa1 100644 --- a/ports/unix/mpconfigport.mk +++ b/ports/unix/mpconfigport.mk @@ -1,8 +1,5 @@ # Enable/disable modules and 3rd-party libs to be included in interpreter -# Build 32-bit binaries on a 64-bit host -MICROPY_FORCE_32BIT = 0 - # This variable can take the following values: # 0 - no readline, just simple stdin input # 1 - use MicroPython version of readline @@ -14,6 +11,7 @@ MICROPY_PY_BTREE = 0 # _thread module using pthreads MICROPY_PY_THREAD = 1 +MICROPY_PY_THREAD_GIL = 0 # Subset of CPython termios module MICROPY_PY_TERMIOS = 1 @@ -54,5 +52,4 @@ MICROPY_VFS_LFS2 = 0 # CIRCUITPY-CHANGE CIRCUITPY_ULAB = 1 CIRCUITPY_MESSAGE_COMPRESSION_LEVEL = 1 -MICROPY_EMIT_NATIVE = 0 CFLAGS += -DCIRCUITPY=1 diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h index 7f71217632a..91d44d1688d 100644 --- a/ports/unix/mphalport.h +++ b/ports/unix/mphalport.h @@ -25,7 +25,6 @@ */ #include #include -// CIRCUITPY-CHANGE: extra include #include #ifndef CHAR_CTRL_C @@ -38,6 +37,20 @@ #define MICROPY_END_ATOMIC_SECTION(x) (void)x; mp_thread_unix_end_atomic_section() #endif +// In lieu of a WFI(), slow down polling from being a tight loop. +// +// Note that we don't delay for the full TIMEOUT_MS, as execution +// can't be woken from the delay. +#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) \ + do { \ + MP_THREAD_GIL_EXIT(); \ + mp_hal_delay_us(500); \ + MP_THREAD_GIL_ENTER(); \ + } while (0) + +// The port provides `mp_hal_stdio_mode_raw()` and `mp_hal_stdio_mode_orig()`. +#define MICROPY_HAL_HAS_STDIO_MODE_SWITCH (1) + // CIRCUITPY-CHANGE: mp_hal_set_interrupt_char(int) instead of char void mp_hal_set_interrupt_char(int c); bool mp_hal_is_interrupted(void); @@ -110,3 +123,15 @@ enum { void mp_hal_get_mac(int idx, uint8_t buf[6]); #endif + +#if defined(__linux__) && (defined(__ARM_32BIT_STATE) || defined(__riscv)) +#if __has_builtin(__builtin___clear_cache) +#define MP_HAL_CLEAN_DCACHE(fun_data, fun_len) \ + do { \ + __builtin___clear_cache((void *)fun_data, (char *)fun_data + fun_len); \ + } while (0) +#endif +#endif + +// Global variable to control compile-only mode. +extern bool mp_compile_only; diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 5172645bc14..a41b3ec9f47 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -31,6 +31,7 @@ #include "py/runtime.h" #include "py/mpthread.h" #include "py/gc.h" +#include "stack_size.h" #if MICROPY_PY_THREAD @@ -45,8 +46,14 @@ // potential conflict with other uses of the more commonly used SIGUSR1. #ifdef SIGRTMIN #define MP_THREAD_GC_SIGNAL (SIGRTMIN + 5) +#ifdef __ANDROID__ +#define MP_THREAD_TERMINATE_SIGNAL (SIGRTMIN + 6) +#endif #else #define MP_THREAD_GC_SIGNAL (SIGUSR1) +#ifdef __ANDROID__ +#define MP_THREAD_TERMINATE_SIGNAL (SIGUSR2) +#endif #endif // This value seems to be about right for both 32-bit and 64-bit builds. @@ -107,6 +114,18 @@ static void mp_thread_gc(int signo, siginfo_t *info, void *context) { } } +// On Android, pthread_cancel and pthread_setcanceltype are not implemented. +// To achieve that result a new signal handler responding on either +// (SIGRTMIN + 6) or SIGUSR2 is installed on every child thread. The sole +// purpose of this new signal handler is to terminate the thread in a safe +// asynchronous manner. + +#ifdef __ANDROID__ +static void mp_thread_terminate(int signo, siginfo_t *info, void *context) { + pthread_exit(NULL); +} +#endif + void mp_thread_init(void) { pthread_key_create(&tls_key, NULL); pthread_setspecific(tls_key, &mp_state_ctx.thread); @@ -135,6 +154,14 @@ void mp_thread_init(void) { sa.sa_sigaction = mp_thread_gc; sigemptyset(&sa.sa_mask); sigaction(MP_THREAD_GC_SIGNAL, &sa, NULL); + + // Install a signal handler for asynchronous termination if needed. + #if defined(__ANDROID__) + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = mp_thread_terminate; + sigemptyset(&sa.sa_mask); + sigaction(MP_THREAD_TERMINATE_SIGNAL, &sa, NULL); + #endif } void mp_thread_deinit(void) { @@ -142,7 +169,11 @@ void mp_thread_deinit(void) { while (thread->next != NULL) { mp_thread_t *th = thread; thread = thread->next; + #if defined(__ANDROID__) + pthread_kill(th->id, MP_THREAD_TERMINATE_SIGNAL); + #else pthread_cancel(th->id); + #endif free(th); } mp_thread_unix_end_atomic_section(); @@ -200,7 +231,9 @@ void mp_thread_start(void) { } #endif + #if !defined(__ANDROID__) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + #endif mp_thread_unix_begin_atomic_section(); for (mp_thread_t *th = thread; th != NULL; th = th->next) { if (th->id == pthread_self()) { @@ -212,14 +245,14 @@ void mp_thread_start(void) { } mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { - // default stack size is 8k machine-words + // default stack size if (*stack_size == 0) { - *stack_size = 8192 * sizeof(void *); + *stack_size = 32768 * UNIX_STACK_MULTIPLIER; } // minimum stack size is set by pthreads - if (*stack_size < PTHREAD_STACK_MIN) { - *stack_size = PTHREAD_STACK_MIN; + if (*stack_size < (size_t)PTHREAD_STACK_MIN) { + *stack_size = (size_t)PTHREAD_STACK_MIN; } // ensure there is enough stack to include a stack-overflow margin diff --git a/ports/unix/stack_size.h b/ports/unix/stack_size.h new file mode 100644 index 00000000000..95ec502b0f8 --- /dev/null +++ b/ports/unix/stack_size.h @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Angus Gratton + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_UNIX_STACK_SIZE_H +#define MICROPY_INCLUDED_UNIX_STACK_SIZE_H + +#include "py/misc.h" + +// Define scaling factors for the stack size (also applies to main thread) +#ifndef UNIX_STACK_MULTIPLIER + +#if defined(__arm__) && !defined(__thumb2__) +// ARM (non-Thumb) architectures require more stack. +#define UNIX_STACK_MUL_ARM 2 +#else +#define UNIX_STACK_MUL_ARM 1 +#endif + +#if MP_SANITIZER_BUILD +// Sanitizer features consume significant stack in some cases +// This multiplier can probably be removed when using GCC 12 or newer. +#define UNIX_STACK_MUL_SANITIZERS 4 +#else +#define UNIX_STACK_MUL_SANITIZERS 1 +#endif + +#if defined(_MSC_VER) +// Similarly Windows seems to require more stack +#define UNIX_STACK_MUL_WINDOWS 2 +#else +#define UNIX_STACK_MUL_WINDOWS 1 +#endif + +// Double the stack size for 64-bit builds, plus additional scalings +#define UNIX_STACK_MULTIPLIER ((sizeof(void *) / 4) * (UNIX_STACK_MUL_ARM)*(UNIX_STACK_MUL_SANITIZERS)*(UNIX_STACK_MUL_WINDOWS)) + +#endif // UNIX_STACK_MULTIPLIER + +#endif // MICROPY_INCLUDED_UNIX_STACK_SIZE_H diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index 238d1cb5ee8..ac75f20eee4 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -117,12 +117,12 @@ void mp_hal_stdio_mode_raw(void) { termios.c_lflag = 0; termios.c_cc[VMIN] = 1; termios.c_cc[VTIME] = 0; - tcsetattr(0, TCSAFLUSH, &termios); + tcsetattr(0, TCSANOW, &termios); } void mp_hal_stdio_mode_orig(void) { // restore terminal settings - tcsetattr(0, TCSAFLUSH, &orig_termios); + tcsetattr(0, TCSANOW, &orig_termios); } #endif @@ -251,9 +251,13 @@ uint64_t mp_hal_time_ns(void) { #ifndef mp_hal_delay_ms void mp_hal_delay_ms(mp_uint_t ms) { - mp_uint_t start = mp_hal_ticks_ms(); - while (mp_hal_ticks_ms() - start < ms) { - mp_event_wait_ms(1); + if (ms) { + mp_uint_t start = mp_hal_ticks_ms(); + while (mp_hal_ticks_ms() - start < ms) { + mp_event_wait_ms(1); + } + } else { + mp_handle_pending(true); } } #endif diff --git a/ports/unix/variants/coverage/manifest.py b/ports/unix/variants/coverage/manifest.py index 37f2531a842..2d459103ef2 100644 --- a/ports/unix/variants/coverage/manifest.py +++ b/ports/unix/variants/coverage/manifest.py @@ -1,5 +1,5 @@ add_library("unix-ffi", "$(MPY_LIB_DIR)/unix-ffi") freeze_as_str("frzstr") freeze_as_mpy("frzmpy") -freeze_mpy("$(MPY_DIR)/tests/frozen") +freeze_mpy("$(MPY_DIR)/tests/assets") require("ssl") diff --git a/ports/unix/variants/coverage/mpconfigvariant.h b/ports/unix/variants/coverage/mpconfigvariant.h index ca79d3d0d2b..03f77ec14c6 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.h +++ b/ports/unix/variants/coverage/mpconfigvariant.h @@ -39,11 +39,22 @@ // Enable additional features. #define MICROPY_DEBUG_PARSE_RULE_NAME (1) +// CIRCUITPY-CHANGE: off +#define MICROPY_PY_SYS_SETTRACE (0) #define MICROPY_TRACKED_ALLOC (1) #define MICROPY_WARNINGS_CATEGORY (1) #undef MICROPY_VFS_ROM_IOCTL #define MICROPY_VFS_ROM_IOCTL (1) #define MICROPY_PY_CRYPTOLIB_CTR (1) +// CIRCUITPY-CHANGE: off +#define MICROPY_SCHEDULER_STATIC_NODES (0) + +// Enable os.uname for attrtuple coverage test +#define MICROPY_PY_OS_UNAME (1) +#define MICROPY_HW_BOARD_NAME "a machine" +#define MICROPY_HW_MCU_NAME MICROPY_PY_SYS_PLATFORM +// Keep the standard banner message +#define MICROPY_BANNER_MACHINE MICROPY_PY_SYS_PLATFORM " [" MICROPY_PLATFORM_COMPILER "] version" // CIRCUITPY-CHANGE: Disable things never used in circuitpython #define MICROPY_PY_CRYPTOLIB (0) diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index 6ec0e85377c..beab74832cb 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -12,8 +12,6 @@ CFLAGS += \ LDFLAGS += -fprofile-arcs -ftest-coverage FROZEN_MANIFEST ?= $(VARIANT_DIR)/manifest.py -# CIRCUITPY-CHANGE: don't include user C modules -# USER_C_MODULES = $(TOP)/examples/usercmodule # CIRCUITPY-CHANGE: use CircuitPython bindings and implementations SRC_QRIO := $(patsubst ../../%,%,$(wildcard ../../shared-bindings/qrio/*.c ../../shared-module/qrio/*.c ../../lib/quirc/lib/*.c)) @@ -37,7 +35,9 @@ SRC_BITMAP := \ shared-bindings/audiodelays/Echo.c \ shared-bindings/audiodelays/Chorus.c \ shared-bindings/audiodelays/PitchShift.c \ + shared-bindings/audiodelays/GranularPitchShift.c \ shared-bindings/audiodelays/MultiTapDelay.c \ + shared-bindings/audiodelays/Flanger.c \ shared-bindings/audiodelays/__init__.c \ shared-bindings/audiofilters/Distortion.c \ shared-bindings/audiofilters/Filter.c \ @@ -85,7 +85,9 @@ SRC_BITMAP := \ shared-module/audiodelays/Echo.c \ shared-module/audiodelays/Chorus.c \ shared-module/audiodelays/PitchShift.c \ + shared-module/audiodelays/GranularPitchShift.c \ shared-module/audiodelays/MultiTapDelay.c \ + shared-module/audiodelays/Flanger.c \ shared-module/audiodelays/__init__.c \ shared-module/audiofilters/Distortion.c \ shared-module/audiofilters/Filter.c \ @@ -106,7 +108,6 @@ SRC_BITMAP := \ shared-module/floppyio/__init__.c \ shared-module/jpegio/__init__.c \ shared-module/jpegio/JpegDecoder.c \ - shared-module/os/getenv.c \ shared-module/rainbowio/__init__.c \ shared-module/struct/__init__.c \ shared-module/synthio/__init__.c \ @@ -147,6 +148,10 @@ SRC_C += $(addprefix lib/mp3/src/, \ $(BUILD)/lib/mp3/src/buffers.o: CFLAGS += -include "shared-module/audiomp3/__init__.h" -D'MPDEC_ALLOCATOR(x)=malloc(x)' -D'MPDEC_FREE(x)=free(x)' -fwrapv +# mp3dec.h only recognizes a fixed list of platforms and errors out on anything +# else, including aarch64. Ask for the portable C code path, like espressif does. +CFLAGS += -DMP3DEC_GENERIC + CFLAGS += \ -DCIRCUITPY_AESIO=1 \ -DCIRCUITPY_AUDIOCORE=1 \ @@ -164,8 +169,8 @@ CFLAGS += \ -DCIRCUITPY_GIFIO=1 \ -DCIRCUITPY_JPEGIO=1 \ -DCIRCUITPY_LOCALE=1 \ - -DCIRCUITPY_OS_GETENV=1 \ -DCIRCUITPY_RAINBOWIO=1 \ + -DCIRCUITPY_SETTINGS_TOML=1 \ -DCIRCUITPY_STRUCT=1 \ -DCIRCUITPY_SYNTHIO=1 \ -DCIRCUITPY_SYNTHIO_MAX_CHANNELS=14 \ diff --git a/ports/unix/variants/longlong/mpconfigvariant.h b/ports/unix/variants/longlong/mpconfigvariant.h new file mode 100644 index 00000000000..1554d537c04 --- /dev/null +++ b/ports/unix/variants/longlong/mpconfigvariant.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * 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. + */ + +// This config exists to test that the MICROPY_LONGINT_IMPL_LONGLONG variant +// (i.e. minimal form of "big integer" that's backed by 64-bit int only) builds +// and passes tests. + +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) + +// We build it on top of REPR C, which uses memory-efficient floating point +// objects encoded directly mp_obj_t (30 bits only). +// Therefore this variant should be built for a 32-bits target. + +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) + +// Set base feature level. +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) + +// Enable extra Unix features. +#include "../mpconfigvariant_common.h" diff --git a/ports/unix/variants/longlong/mpconfigvariant.mk b/ports/unix/variants/longlong/mpconfigvariant.mk new file mode 100644 index 00000000000..9fe20cd584d --- /dev/null +++ b/ports/unix/variants/longlong/mpconfigvariant.mk @@ -0,0 +1,8 @@ +# build interpreter with "bigints" implemented as "longlong" + +# This needs to be built for a 32-bits target, otherwise small ints will +# essentially be 64-bit wide. + +MICROPY_PY_FFI := 0 + +MPY_TOOL_FLAGS = -mlongint-impl longlong diff --git a/ports/unix/variants/minimal/mpconfigvariant.h b/ports/unix/variants/minimal/mpconfigvariant.h index 97ed786b8f4..0e280a8f730 100644 --- a/ports/unix/variants/minimal/mpconfigvariant.h +++ b/ports/unix/variants/minimal/mpconfigvariant.h @@ -49,6 +49,7 @@ #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) #define MICROPY_ENABLE_COMPILER (1) #define MICROPY_ENABLE_EXTERNAL_IMPORT (1) +#define MICROPY_STACK_CHECK (1) #define MICROPY_FULL_CHECKS (1) #define MICROPY_HELPER_REPL (1) #define MICROPY_KBD_EXCEPTION (1) @@ -61,6 +62,5 @@ #define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) #define MICROPY_PY_GENERATOR_PEND_THROW (1) -// Enable just the sys and os built-in modules. -#define MICROPY_PY_SYS (1) +// Add just the os built-in module. #define MICROPY_PY_OS (1) diff --git a/ports/unix/variants/mpconfigvariant_common.h b/ports/unix/variants/mpconfigvariant_common.h index 9eeed879736..382579ead61 100644 --- a/ports/unix/variants/mpconfigvariant_common.h +++ b/ports/unix/variants/mpconfigvariant_common.h @@ -29,7 +29,7 @@ // Send raise KeyboardInterrupt directly from the signal handler rather than // scheduling it into the VM. -#define MICROPY_ASYNC_KBD_INTR (1) +#define MICROPY_ASYNC_KBD_INTR (!MICROPY_PY_THREAD_GIL) // Enable helpers for printing debugging information. #ifndef MICROPY_DEBUG_PRINTERS @@ -83,7 +83,9 @@ #define MICROPY_PY_GC_COLLECT_RETVAL (1) // Enable detailed error messages and warnings. +#ifndef MICROPY_ERROR_REPORTING #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +#endif #define MICROPY_WARNINGS (1) #define MICROPY_PY_STR_BYTES_CMP_WARN (1) @@ -104,12 +106,6 @@ #define MICROPY_PY_TIME_CUSTOM_SLEEP (1) #define MICROPY_PY_TIME_INCLUDEFILE "ports/unix/modtime.c" -#if MICROPY_PY_SSL -#define MICROPY_PY_HASHLIB_MD5 (1) -#define MICROPY_PY_HASHLIB_SHA1 (1) -#define MICROPY_PY_CRYPTOLIB (1) -#endif - // The "select" module is enabled by default, but disable select.select(). #define MICROPY_PY_SELECT_POSIX_OPTIMISATIONS (1) #define MICROPY_PY_SELECT_SELECT (0) diff --git a/ports/unix/variants/nanbox/mpconfigvariant.h b/ports/unix/variants/nanbox/mpconfigvariant.h index 7b13b7dc6ce..c9e9c1f63d9 100644 --- a/ports/unix/variants/nanbox/mpconfigvariant.h +++ b/ports/unix/variants/nanbox/mpconfigvariant.h @@ -41,10 +41,3 @@ #define MICROPY_EMIT_X64 (0) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_ARM (0) - -#include - -typedef int64_t mp_int_t; -typedef uint64_t mp_uint_t; -#define UINT_FMT "%llu" -#define INT_FMT "%lld" diff --git a/ports/unix/variants/nanbox/mpconfigvariant.mk b/ports/unix/variants/nanbox/mpconfigvariant.mk index e588e657efc..6d63a86e9b0 100644 --- a/ports/unix/variants/nanbox/mpconfigvariant.mk +++ b/ports/unix/variants/nanbox/mpconfigvariant.mk @@ -1,3 +1,4 @@ # build interpreter with nan-boxing as object model (object repr D) -MICROPY_FORCE_32BIT = 1 +# This needs to be built for a 32-bits target, as object representation D is +# only meant to work on 32-bits machines. diff --git a/ports/zephyr-cp/AGENTS.md b/ports/zephyr-cp/AGENTS.md new file mode 100644 index 00000000000..e8e240bde80 --- /dev/null +++ b/ports/zephyr-cp/AGENTS.md @@ -0,0 +1,8 @@ +- Build a board by doing `make BOARD=_`. +- The corresponding configuration files are in `boards//`, including the + board's devicetree overlay (`board.overlay`) and Kconfig fragment (`board.conf`). The Makefile + passes them to Zephyr; the overlay replaces `app.overlay`, so include it if the board wants it. +- To flash it on a board do `make BOARD=_ flash`. +- Zephyr board docs are at `zephyr/boards//`. +- Run zephyr-cp tests with `make test`. +- Do not add new translatable error strings (`MP_ERROR_TEXT`). Instead, use `raise_zephyr_error()` or `CHECK_ZEPHYR_RESULT()` from `bindings/zephyr_kernel/__init__.h` to convert Zephyr errno values into Python exceptions. diff --git a/ports/zephyr-cp/CLAUDE.md b/ports/zephyr-cp/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/ports/zephyr-cp/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/ports/zephyr-cp/CMakeLists.txt b/ports/zephyr-cp/CMakeLists.txt index e35b4b7c764..9d115f1e176 100644 --- a/ports/zephyr-cp/CMakeLists.txt +++ b/ports/zephyr-cp/CMakeLists.txt @@ -5,6 +5,15 @@ project(circuitpython) target_sources(app PRIVATE zephyr_main.c) +# Add I2C emulator control for native_sim testing +if(CONFIG_BOARD_NATIVE_SIM) + target_sources(app PRIVATE native_sim_i2c_emul_control.c) +endif() + +if(CONFIG_TRACING_PERFETTO) + zephyr_include_directories(${ZEPHYR_BINARY_DIR}/subsys/tracing/perfetto/proto) +endif() + # From: https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/application_development/external_lib/CMakeLists.txt # The external static library that we are linking with does not know # how to build for this platform so we export all the flags used in diff --git a/ports/zephyr-cp/Kconfig b/ports/zephyr-cp/Kconfig new file mode 100644 index 00000000000..015864100ec --- /dev/null +++ b/ports/zephyr-cp/Kconfig @@ -0,0 +1,104 @@ +# CircuitPython Zephyr port — application Kconfig +# +# Sources Zephyr's main Kconfig, then adds CircuitPython-specific defaults. +# Boards can override any of these in their boards/.conf file. + +osource "$(ZEPHYR_BASE)/Kconfig.zephyr" + +# ===== Peripheral defaults — enabled by default, boards can disable ===== + +config I2C + default y + +config SPI + default y + +config SPI_ASYNC + default y + +config I2S + default y + +config UART_LINE_CTRL + default y + +config ENTROPY_GENERATOR + default y + +# ===== Bluetooth defaults ===== + +# Use a variable for the chosen name so the comma isn't parsed as an argument separator +DT_BT_HCI_CHOSEN := zephyr,bt-hci + +config BT + default $(dt_chosen_enabled,$(DT_BT_HCI_CHOSEN)) + +config BT_PERIPHERAL + default y + +config BT_CENTRAL + default y + +config BT_BROADCASTER + default y + +config BT_OBSERVER + default y + +config BT_EXT_ADV + default y + +config BT_DEVICE_APPEARANCE_DYNAMIC + default y + +config BT_DEVICE_NAME_DYNAMIC + default y + +config BT_DEVICE_NAME_MAX + default 28 + +config BT_L2CAP_TX_MTU + default 253 + +# BT Buffers +config BT_BUF_CMD_TX_SIZE + default 255 + +config BT_BUF_EVT_RX_COUNT + default 16 + +config BT_BUF_EVT_RX_SIZE + default 255 + +config BT_BUF_ACL_TX_COUNT + default 3 + +config BT_BUF_ACL_TX_SIZE + default 251 + +config BT_BUF_ACL_RX_COUNT_EXTRA + default 1 + +config BT_BUF_ACL_RX_SIZE + default 255 + +config BT_GATT_DYNAMIC_DB + default y + +config BT_GATT_CLIENT + default y + +config BT_SMP + default y + +config BT_BONDABLE + default y + +config SETTINGS + default y + +config BT_SETTINGS + default y + +config BT_KEYS_OVERWRITE_OLDEST + default y diff --git a/ports/zephyr-cp/Kconfig.sysbuild b/ports/zephyr-cp/Kconfig.sysbuild index cd74ff13592..11b49446f42 100644 --- a/ports/zephyr-cp/Kconfig.sysbuild +++ b/ports/zephyr-cp/Kconfig.sysbuild @@ -8,6 +8,7 @@ config NET_CORE_BOARD default "nrf5340dk/nrf5340/cpunet" if $(BOARD) = "nrf5340dk" default "nrf7002dk/nrf5340/cpunet" if $(BOARD) = "nrf7002dk" default "nrf5340_audio_dk/nrf5340/cpunet" if $(BOARD) = "nrf5340_audio_dk" + default "nrf5340bsim/nrf5340/cpunet" if $(BOARD) = "nrf5340bsim" config NET_CORE_IMAGE_HCI_IPC bool "HCI IPC image on network core" diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index 217e094e3dc..1fc5040fefa 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -8,11 +8,51 @@ BUILD ?= build-$(BOARD) TRANSLATION ?= en_US -.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash debug clean menuconfig +# Compute shield args once. Command-line SHIELD/SHIELDS values override board defaults from circuitpython.toml. +ifneq ($(strip $(BOARD)),) +WEST_SHIELD_ARGS := $(shell SHIELD_ORIGIN="$(origin SHIELD)" SHIELDS_ORIGIN="$(origin SHIELDS)" SHIELD="$(SHIELD)" SHIELDS="$(SHIELDS)" python cptools/get_west_shield_args.py $(BOARD)) +endif + +WEST_CMAKE_ARGS := -DZEPHYR_BOARD_ALIASES=$(CURDIR)/boards/board_aliases.cmake -Dzephyr-cp_TRANSLATION=$(TRANSLATION) + +# Board files live in the board's own folder as board.overlay / board.conf. Zephyr only auto-applies +# boards/.overlay and boards/.conf named after the RESOLVED Zephyr board, so it finds +# neither those (wrong directory) nor files named after a board declared through cp_board_alias() +# (wrong name) - the build silently produces a different firmware instead of warning. Pass them +# explicitly when they exist. +CP_BOARD_DIR := $(CURDIR)/boards/$(firstword $(subst _, ,$(BOARD)))/$(patsubst $(firstword $(subst _, ,$(BOARD)))_%,%,$(BOARD)) +# DTC_OVERLAY_FILE, not EXTRA_: a board overlay REPLACES app.overlay (Zephyr only falls back to +# app.overlay when no board overlay is found), which is why the board overlays here include it +# themselves - and why one board that has no USB deliberately does not. Adding the overlay instead +# would force app.overlay on every board. socs/ ships .conf only, so nothing else is displaced. +CP_BOARD_OVERLAY := $(wildcard $(CP_BOARD_DIR)/board.overlay) +ifneq ($(CP_BOARD_OVERLAY),) +WEST_CMAKE_ARGS += -Dzephyr-cp_DTC_OVERLAY_FILE=$(CP_BOARD_OVERLAY) +endif +CP_BOARD_CONF := $(wildcard $(CP_BOARD_DIR)/board.conf) + +# When DEBUG=1, apply additional Kconfig fragments for debug-friendly settings. +DEBUG_CONF_FILE ?= $(CURDIR)/debug.conf +ifeq ($(DEBUG),1) +ifneq ($(CP_BOARD_CONF),) +CP_BOARD_CONF := $(CP_BOARD_CONF);$(DEBUG_CONF_FILE) +else +CP_BOARD_CONF := $(DEBUG_CONF_FILE) +endif +endif +ifneq ($(CP_BOARD_CONF),) +WEST_CMAKE_ARGS += -Dzephyr-cp_EXTRA_CONF_FILE=$(CP_BOARD_CONF) +endif + +.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug debug-jlink debugserver attach run run-sim clean menuconfig all clean-all sim clean-sim test fetch-port-submodules + +export BSIM_COMPONENTS_PATH := $(CURDIR)/tools/bsim/components +export BSIM_OUT_PATH := $(CURDIR)/tools/bsim $(BUILD)/zephyr-cp/zephyr/zephyr.elf: python cptools/pre_zephyr_build_prep.py $(BOARD) - west build -b $(BOARD) -d $(BUILD) --sysbuild -- -DZEPHYR_BOARD_ALIASES=$(CURDIR)/boards/board_aliases.cmake -Dzephyr-cp_TRANSLATION=$(TRANSLATION) + west build -b $(BOARD) -d $(BUILD) $(WEST_SHIELD_ARGS) --sysbuild -- $(WEST_CMAKE_ARGS) + python ../../tools/build_memory_info.py $(BUILD)/zephyr-cp/zephyr/zephyr.map $(BUILD) --image $(BUILD)/zephyr-cp/zephyr/zephyr.bin $(BUILD)/firmware.elf: $(BUILD)/zephyr-cp/zephyr/zephyr.elf cp $^ $@ @@ -20,14 +60,89 @@ $(BUILD)/firmware.elf: $(BUILD)/zephyr-cp/zephyr/zephyr.elf $(BUILD)/firmware.hex: $(BUILD)/zephyr-cp/zephyr/zephyr.elf cp $(BUILD)/zephyr-cp/zephyr/zephyr.hex $@ +$(BUILD)/firmware.exe: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + cp $(BUILD)/zephyr-cp/zephyr/zephyr.exe $@ + +$(BUILD)/firmware.uf2: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + cp $(BUILD)/zephyr-cp/zephyr/zephyr.uf2 $@ + +$(BUILD)/firmware.rps: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + cp $(BUILD)/zephyr-cp/zephyr/zephyr.rps $@ + flash: $(BUILD)/zephyr-cp/zephyr/zephyr.elf west flash -d $(BUILD) +recover: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + west flash --recover -d $(BUILD) + debug: $(BUILD)/zephyr-cp/zephyr/zephyr.elf west debug -d $(BUILD) +debug-jlink: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + west debug --runner jlink -d $(BUILD) + +debugserver: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + west debugserver -d $(BUILD) + +attach: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + west attach -d $(BUILD) + +run: $(BUILD)/firmware.exe + $^ + +run-sim: + $(MAKE) BOARD=native_native_sim BUILD=build-native_native_sim build-native_native_sim/firmware.exe + truncate -s 2M build-native_native_sim/flash.bin + mformat -i build-native_native_sim/flash.bin :: + @if [ -d CIRCUITPY ] && [ -n "$$(find CIRCUITPY -mindepth 1 -print -quit)" ]; then \ + echo "Populating build-native_native_sim/flash.bin from ./CIRCUITPY"; \ + mcopy -s -i build-native_native_sim/flash.bin CIRCUITPY/* ::; \ + fi + build-native_native_sim/firmware.exe --flash=build-native_native_sim/flash.bin --flash_rm -wait_uart -rt --i2s_capture=build-native_native_sim/i2s_capture.wav + menuconfig: - west build --sysbuild -d $(BUILD) -t menuconfig + west build $(WEST_SHIELD_ARGS) --sysbuild -d $(BUILD) -t menuconfig -- $(WEST_CMAKE_ARGS) clean: rm -rf $(BUILD) + +fetch-port-submodules: + python ../../tools/ci_fetch_deps.py zephyr-cp + +# Build all boards. The + prefix allows jobserver file descriptors to be passed through. +# This enables parallel builds across all boards when invoked with `make -jN all`. +all: + +python cptools/build_all_boards.py --continue-on-error + +clean-all: + rm -rf build build-* + +# Build all sim boards concurrently using the same jobserver as `make all`. +sim: + +python cptools/build_all_boards.py --vendor native --continue-on-error + +clean-sim: + rm -rf $(wildcard build-native_*) + +# Every board the test suite uses: native sim (non-asan + asan) and the bsim +# boards (tests/bsim/conftest.py parametrizes over both). Zephyr samples for +# bsim tests are built on demand by the zephyr_sample fixture. +TEST_BOARDS := native_native_sim native_native_sim_asan native_nrf5340bsim native_nrf54lm20bsim + +# Delegate to a sub-make with BOARD set so the per-board build rule (and its +# shield args + bsim prep) applies. The targets are phony: the west builds are +# incremental, so this just keeps the test binaries fresh. +define test_board_rule +.PHONY: test-build-$(1) +test-build-$(1): + +$$(MAKE) BOARD=$(1) BUILD=build-$(1) build-$(1)/zephyr-cp/zephyr/zephyr.elf +endef +$(foreach board,$(TEST_BOARDS),$(eval $(call test_board_rule,$(board)))) + +# CI runs this as three jobs, one per board family, narrowing TEST_BOARDS and +# PYTEST_ARGS; see .github/workflows/run-zephyr-tests.yml. +PYTEST_ARGS ?= tests/ + +test: $(TEST_BOARDS:%=test-build-%) + pytest cptools/tests + pytest -v $(PYTEST_ARGS) diff --git a/ports/zephyr-cp/README.md b/ports/zephyr-cp/README.md index 4d08936cad6..d051097c83d 100644 --- a/ports/zephyr-cp/README.md +++ b/ports/zephyr-cp/README.md @@ -15,11 +15,11 @@ pip install west west init -l zephyr-config west update west zephyr-export -pip install -r lib/zephyr/scripts/requirements.txt +pip install -r zephyr/scripts/requirements.txt west sdk install ``` -Now to build from the top level: +Now to build from `ports/zephyr-cp`: ```sh make BOARD=nordic_nrf7002dk @@ -28,6 +28,77 @@ make BOARD=nordic_nrf7002dk This uses Zephyr's cmake to generate Makefiles that then delegate to `tools/cpbuild/build_circuitpython.py` to build the CircuitPython bits in parallel. +## Native simulator build container + +Building the native sim requires `libsdl2-dev:i386` and other 32bit dependencies that +can cause conflicts on 64bit systems resulting in the removal of 64bit versions of critical +software such as the display manager and network manager. A Containerfile and a few scripts +are provided to set up a container to make the native sim build inside without affecting the +host system. + +The container automatically mounts this instance of the circuitpython repo inside at +`/home/dev/circuitpython`. Changes made in the repo inside the container and on the host PC +will sync automatically between host and container. + +To use the container file: + +1. Build the container with `podman build -t zephyr-cp-dev -f native_sim_build_Containerfile .` +2. Run/Start the container by running `./native_sim_build_run_container.sh` on the host PC. + The script will automatically run or start based on whether the container has been run before. +3. Init requirements inside the container with `./native_sim_build_init_container.sh` + +To delete the container and cleanup associated files: +```sh +podman ps -a --filter ancestor=zephyr-cp-dev -q | xargs -r podman rm -f +podman rmi zephyr-cp-dev +podman image prune -f +podman rm -f zcp +``` + +## Running the native simulator + +From `ports/zephyr-cp`, run: + +```sh +make run-sim +``` + +`run-sim` starts the native simulator in realtime. +It prints the PTY path to connect to the simulator REPL. +If a local `./CIRCUITPY/` folder exists, its files are used as the simulator's CIRCUITPY drive. + +Edit files in `./CIRCUITPY` (for example `code.py`) and rerun `make run-sim` to test changes. + +## Shields + +Board defaults can be set in `boards///circuitpython.toml`: + +```toml +SHIELDS = ["shield1", "shield2"] +``` + +For example, `boards/renesas/ek_ra8d1/circuitpython.toml` enables: + +```toml +SHIELDS = ["rtkmipilcdb00000be"] +``` + +You can override shield selection from the command line: + +```sh +# Single shield +make BOARD=renesas_ek_ra8d1 SHIELD=rtkmipilcdb00000be + +# Multiple shields (comma, semicolon, or space separated) +make BOARD=my_vendor_my_board SHIELDS="shield1,shield2" +``` + +Behavior and precedence: + +- If `SHIELD` or `SHIELDS` is explicitly provided, it overrides board defaults. +- If neither is provided, defaults from `circuitpython.toml` are used. +- Use `SHIELD=` (empty) to disable a board default shield for one build. + ## Testing other boards [Any Zephyr board](https://docs.zephyrproject.org/latest/boards/index.html#) can @@ -45,3 +116,13 @@ west build -b nrf52840dk/nrf52840 ``` This is already supported in `ports/nordic` as `pca10056`. + +The manifest in `zephyr-config/west.yml` skips the HALs of vendors that no board +here uses, so a board from one of them needs its entry removed from the +`name-blocklist` and a `west update` to fetch it. For the +`esp32s3_devkitc` board, that is `hal_espressif`: + +```sh +west update +west build -b esp32s3_devkitc/esp32s3/procpu +``` diff --git a/ports/zephyr-cp/app.overlay b/ports/zephyr-cp/app.overlay new file mode 100644 index 00000000000..bb2be8924f6 --- /dev/null +++ b/ports/zephyr-cp/app.overlay @@ -0,0 +1,22 @@ +&zephyr_udc0 { + cdc_acm_console: cdc_acm_console { + compatible = "zephyr,cdc-acm-uart"; + label = "CircuitPython Console"; + }; + cdc_acm_data: cdc_acm_data { + compatible = "zephyr,cdc-acm-uart"; + label = "CircuitPython Data"; + }; +}; + +/ { + hid_dev_0: hid_dev_0 { + compatible = "zephyr,hid-device"; + label = "HID0"; + protocol-code = "none"; + in-polling-period-us = <1000>; + in-report-size = <64>; + out-polling-period-us = <1000>; + out-report-size = <64>; + }; +}; diff --git a/ports/zephyr-cp/background.c b/ports/zephyr-cp/background.c index 9afade89136..56e9e98f1f2 100644 --- a/ports/zephyr-cp/background.c +++ b/ports/zephyr-cp/background.c @@ -9,17 +9,7 @@ #include "py/runtime.h" #include "supervisor/port.h" -#if CIRCUITPY_DISPLAYIO -#include "shared-module/displayio/__init__.h" -#endif - -#if CIRCUITPY_AUDIOBUSIO -#include "common-hal/audiobusio/I2SOut.h" -#endif - -#if CIRCUITPY_AUDIOPWMIO -#include "common-hal/audiopwmio/PWMAudioOut.h" -#endif +#include void port_start_background_tick(void) { } @@ -28,18 +18,12 @@ void port_finish_background_tick(void) { } void port_background_tick(void) { - #if CIRCUITPY_AUDIOPWMIO - audiopwmout_background(); - #endif - #if CIRCUITPY_AUDIOBUSIO - i2s_background(); - #endif -} - -// Allow boards to override this. -MP_WEAK void board_background_task(void) { + // No, ticks. We use Zephyr threads instead. } void port_background_task(void) { - board_background_task(); + // Make sure time advances in the simulator. + #if defined(CONFIG_ARCH_POSIX) + k_busy_wait(100); + #endif } diff --git a/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.c b/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.c new file mode 100644 index 00000000000..fc0fb9ecc4f --- /dev/null +++ b/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.c @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/hostnetwork/HostNetwork.h" + +#include "py/runtime.h" + +//| class HostNetwork: +//| """Native networking for the host simulator.""" +//| +//| def __init__(self) -> None: +//| """Create a HostNetwork instance.""" +//| ... +//| +static mp_obj_t hostnetwork_hostnetwork_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, 0, false); + + hostnetwork_hostnetwork_obj_t *self = mp_obj_malloc(hostnetwork_hostnetwork_obj_t, &hostnetwork_hostnetwork_type); + common_hal_hostnetwork_hostnetwork_construct(self); + return MP_OBJ_FROM_PTR(self); +} + +static const mp_rom_map_elem_t hostnetwork_hostnetwork_locals_dict_table[] = { +}; +static MP_DEFINE_CONST_DICT(hostnetwork_hostnetwork_locals_dict, hostnetwork_hostnetwork_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + hostnetwork_hostnetwork_type, + MP_QSTR_HostNetwork, + MP_TYPE_FLAG_NONE, + make_new, hostnetwork_hostnetwork_make_new, + locals_dict, &hostnetwork_hostnetwork_locals_dict + ); diff --git a/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.h b/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.h new file mode 100644 index 00000000000..009d8c06087 --- /dev/null +++ b/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.h @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +} hostnetwork_hostnetwork_obj_t; + +extern const mp_obj_type_t hostnetwork_hostnetwork_type; + +void common_hal_hostnetwork_hostnetwork_construct(hostnetwork_hostnetwork_obj_t *self); diff --git a/ports/zephyr-cp/bindings/hostnetwork/__init__.c b/ports/zephyr-cp/bindings/hostnetwork/__init__.c new file mode 100644 index 00000000000..92302b67d0e --- /dev/null +++ b/ports/zephyr-cp/bindings/hostnetwork/__init__.c @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" + +#include "bindings/hostnetwork/__init__.h" +#include "bindings/hostnetwork/HostNetwork.h" + +//| """Host networking support for the native simulator.""" +//| + +static const mp_rom_map_elem_t hostnetwork_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_hostnetwork) }, + { MP_ROM_QSTR(MP_QSTR_HostNetwork), MP_ROM_PTR(&hostnetwork_hostnetwork_type) }, +}; +static MP_DEFINE_CONST_DICT(hostnetwork_module_globals, hostnetwork_module_globals_table); + +const mp_obj_module_t hostnetwork_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&hostnetwork_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_hostnetwork, hostnetwork_module); diff --git a/ports/zephyr-cp/bindings/hostnetwork/__init__.h b/ports/zephyr-cp/bindings/hostnetwork/__init__.h new file mode 100644 index 00000000000..a6731546bde --- /dev/null +++ b/ports/zephyr-cp/bindings/hostnetwork/__init__.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "bindings/hostnetwork/HostNetwork.h" + +extern hostnetwork_hostnetwork_obj_t common_hal_hostnetwork_obj; diff --git a/ports/zephyr-cp/bindings/zephyr_display/Display.c b/ports/zephyr-cp/bindings/zephyr_display/Display.c new file mode 100644 index 00000000000..0923618c50a --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_display/Display.c @@ -0,0 +1,195 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/zephyr_display/Display.h" + +#include "py/objproperty.h" +#include "py/objtype.h" +#include "py/runtime.h" +#include "shared-bindings/displayio/Group.h" +#include "shared-module/displayio/__init__.h" + +static mp_obj_t zephyr_display_display_make_new(const mp_obj_type_t *type, + size_t n_args, + size_t n_kw, + const mp_obj_t *all_args) { + (void)type; + (void)n_args; + (void)n_kw; + (void)all_args; + mp_raise_NotImplementedError(NULL); + return mp_const_none; +} + +static zephyr_display_display_obj_t *native_display(mp_obj_t display_obj) { + mp_obj_t native = mp_obj_cast_to_native_base(display_obj, &zephyr_display_display_type); + mp_obj_assert_native_inited(native); + return MP_OBJ_TO_PTR(native); +} + +static mp_obj_t zephyr_display_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) { + (void)self_in; + (void)group_in; + mp_raise_AttributeError(MP_ERROR_TEXT(".show(x) removed. Use .root_group = x")); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_show_obj, zephyr_display_display_obj_show); + +static mp_obj_t zephyr_display_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_target_frames_per_second, + ARG_minimum_frames_per_second, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_target_frames_per_second, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 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); + + zephyr_display_display_obj_t *self = native_display(pos_args[0]); + + uint32_t maximum_ms_per_real_frame = NO_FPS_LIMIT; + mp_int_t minimum_frames_per_second = args[ARG_minimum_frames_per_second].u_int; + if (minimum_frames_per_second > 0) { + maximum_ms_per_real_frame = 1000 / minimum_frames_per_second; + } + + uint32_t target_ms_per_frame; + if (args[ARG_target_frames_per_second].u_obj == mp_const_none) { + target_ms_per_frame = NO_FPS_LIMIT; + } else { + target_ms_per_frame = 1000 / mp_obj_get_int(args[ARG_target_frames_per_second].u_obj); + } + + return mp_obj_new_bool(common_hal_zephyr_display_display_refresh( + self, + target_ms_per_frame, + maximum_ms_per_real_frame)); +} +MP_DEFINE_CONST_FUN_OBJ_KW(zephyr_display_display_refresh_obj, 1, zephyr_display_display_obj_refresh); + +static mp_obj_t zephyr_display_display_obj_get_auto_refresh(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return mp_obj_new_bool(common_hal_zephyr_display_display_get_auto_refresh(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_auto_refresh_obj, zephyr_display_display_obj_get_auto_refresh); + +static mp_obj_t zephyr_display_display_obj_set_auto_refresh(mp_obj_t self_in, mp_obj_t auto_refresh) { + zephyr_display_display_obj_t *self = native_display(self_in); + common_hal_zephyr_display_display_set_auto_refresh(self, mp_obj_is_true(auto_refresh)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_set_auto_refresh_obj, zephyr_display_display_obj_set_auto_refresh); + +MP_PROPERTY_GETSET(zephyr_display_display_auto_refresh_obj, + (mp_obj_t)&zephyr_display_display_get_auto_refresh_obj, + (mp_obj_t)&zephyr_display_display_set_auto_refresh_obj); + +static mp_obj_t zephyr_display_display_obj_get_brightness(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + mp_float_t brightness = common_hal_zephyr_display_display_get_brightness(self); + if (brightness < 0) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Brightness not adjustable")); + } + return mp_obj_new_float(brightness); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_brightness_obj, zephyr_display_display_obj_get_brightness); + +static mp_obj_t zephyr_display_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) { + zephyr_display_display_obj_t *self = native_display(self_in); + mp_float_t brightness = mp_obj_get_float(brightness_obj); + if (brightness < 0.0f || brightness > 1.0f) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be %d-%d"), MP_QSTR_brightness, 0, 1); + } + bool ok = common_hal_zephyr_display_display_set_brightness(self, brightness); + if (!ok) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Brightness not adjustable")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_set_brightness_obj, zephyr_display_display_obj_set_brightness); + +MP_PROPERTY_GETSET(zephyr_display_display_brightness_obj, + (mp_obj_t)&zephyr_display_display_get_brightness_obj, + (mp_obj_t)&zephyr_display_display_set_brightness_obj); + +static mp_obj_t zephyr_display_display_obj_get_width(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_zephyr_display_display_get_width(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_width_obj, zephyr_display_display_obj_get_width); +MP_PROPERTY_GETTER(zephyr_display_display_width_obj, (mp_obj_t)&zephyr_display_display_get_width_obj); + +static mp_obj_t zephyr_display_display_obj_get_height(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_zephyr_display_display_get_height(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_height_obj, zephyr_display_display_obj_get_height); +MP_PROPERTY_GETTER(zephyr_display_display_height_obj, (mp_obj_t)&zephyr_display_display_get_height_obj); + +static mp_obj_t zephyr_display_display_obj_get_rotation(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_zephyr_display_display_get_rotation(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_rotation_obj, zephyr_display_display_obj_get_rotation); + +static mp_obj_t zephyr_display_display_obj_set_rotation(mp_obj_t self_in, mp_obj_t value) { + zephyr_display_display_obj_t *self = native_display(self_in); + common_hal_zephyr_display_display_set_rotation(self, mp_obj_get_int(value)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_set_rotation_obj, zephyr_display_display_obj_set_rotation); + +MP_PROPERTY_GETSET(zephyr_display_display_rotation_obj, + (mp_obj_t)&zephyr_display_display_get_rotation_obj, + (mp_obj_t)&zephyr_display_display_set_rotation_obj); + +static mp_obj_t zephyr_display_display_obj_get_root_group(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return common_hal_zephyr_display_display_get_root_group(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_root_group_obj, zephyr_display_display_obj_get_root_group); + +static mp_obj_t zephyr_display_display_obj_set_root_group(mp_obj_t self_in, mp_obj_t group_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + displayio_group_t *group = NULL; + if (group_in != mp_const_none) { + group = MP_OBJ_TO_PTR(native_group(group_in)); + } + + bool ok = common_hal_zephyr_display_display_set_root_group(self, group); + if (!ok) { + mp_raise_ValueError(MP_ERROR_TEXT("Group already used")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_set_root_group_obj, zephyr_display_display_obj_set_root_group); + +MP_PROPERTY_GETSET(zephyr_display_display_root_group_obj, + (mp_obj_t)&zephyr_display_display_get_root_group_obj, + (mp_obj_t)&zephyr_display_display_set_root_group_obj); + +static const mp_rom_map_elem_t zephyr_display_display_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&zephyr_display_display_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&zephyr_display_display_refresh_obj) }, + + { MP_ROM_QSTR(MP_QSTR_auto_refresh), MP_ROM_PTR(&zephyr_display_display_auto_refresh_obj) }, + { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&zephyr_display_display_brightness_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&zephyr_display_display_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&zephyr_display_display_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&zephyr_display_display_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_root_group), MP_ROM_PTR(&zephyr_display_display_root_group_obj) }, +}; +static MP_DEFINE_CONST_DICT(zephyr_display_display_locals_dict, zephyr_display_display_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + zephyr_display_display_type, + MP_QSTR_Display, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, zephyr_display_display_make_new, + locals_dict, &zephyr_display_display_locals_dict); diff --git a/ports/zephyr-cp/bindings/zephyr_display/Display.h b/ports/zephyr-cp/bindings/zephyr_display/Display.h new file mode 100644 index 00000000000..a50dda8fe8b --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_display/Display.h @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/displayio/Group.h" +#include "common-hal/zephyr_display/Display.h" + +extern const mp_obj_type_t zephyr_display_display_type; + +#define NO_FPS_LIMIT 0xffffffff + +void common_hal_zephyr_display_display_construct_from_device(zephyr_display_display_obj_t *self, + const struct device *device, + uint16_t rotation, + bool auto_refresh); + +bool common_hal_zephyr_display_display_refresh(zephyr_display_display_obj_t *self, + uint32_t target_ms_per_frame, + uint32_t maximum_ms_per_real_frame); + +bool common_hal_zephyr_display_display_get_auto_refresh(zephyr_display_display_obj_t *self); +void common_hal_zephyr_display_display_set_auto_refresh(zephyr_display_display_obj_t *self, bool auto_refresh); + +uint16_t common_hal_zephyr_display_display_get_width(zephyr_display_display_obj_t *self); +uint16_t common_hal_zephyr_display_display_get_height(zephyr_display_display_obj_t *self); +uint16_t common_hal_zephyr_display_display_get_rotation(zephyr_display_display_obj_t *self); +void common_hal_zephyr_display_display_set_rotation(zephyr_display_display_obj_t *self, int rotation); + +mp_float_t common_hal_zephyr_display_display_get_brightness(zephyr_display_display_obj_t *self); +bool common_hal_zephyr_display_display_set_brightness(zephyr_display_display_obj_t *self, mp_float_t brightness); + +mp_obj_t common_hal_zephyr_display_display_get_root_group(zephyr_display_display_obj_t *self); +bool common_hal_zephyr_display_display_set_root_group(zephyr_display_display_obj_t *self, displayio_group_t *root_group); diff --git a/ports/zephyr-cp/bindings/zephyr_display/__init__.c b/ports/zephyr-cp/bindings/zephyr_display/__init__.c new file mode 100644 index 00000000000..eecfeeaec58 --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_display/__init__.c @@ -0,0 +1,24 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" + +#include "bindings/zephyr_display/Display.h" + +static const mp_rom_map_elem_t zephyr_display_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr_display) }, + { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&zephyr_display_display_type) }, +}; + +static MP_DEFINE_CONST_DICT(zephyr_display_module_globals, zephyr_display_module_globals_table); + +const mp_obj_module_t zephyr_display_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&zephyr_display_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_zephyr_display, zephyr_display_module); diff --git a/ports/zephyr-cp/bindings/zephyr_display/__init__.h b/ports/zephyr-cp/bindings/zephyr_display/__init__.h new file mode 100644 index 00000000000..4256bfac2fe --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_display/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/ports/zephyr-cp/bindings/zephyr_serial/UART.c b/ports/zephyr-cp/bindings/zephyr_serial/UART.c deleted file mode 100644 index dbb643645f5..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_serial/UART.c +++ /dev/null @@ -1,291 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include - -#include "bindings/zephyr_serial/UART.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/util.h" - -#include "shared/runtime/context_manager_helpers.h" -#include "shared/runtime/interrupt_char.h" - -#include "py/stream.h" -#include "py/objproperty.h" -#include "py/objtype.h" -#include "py/runtime.h" -#include "py/stream.h" - -#define STREAM_DEBUG(...) (void)0 -// #define STREAM_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) - -//| class UART: -//| """A bidirectional serial protocol. Already initialized for Zephyr defined -//| busses in :py:mod:`board`. -//| -//| .. raw:: html -//| -//|

-//|

-//| Available on these boards -//|
    -//| {% for board in support_matrix_reverse["zephyr_serial.UART"] %} -//|
  • {{ board }} -//| {% endfor %} -//|
-//|
-//|

-//| -//| """ -//| - -static void validate_timeout(mp_float_t timeout) { - mp_arg_validate_int_range((int)timeout, 0, 100, MP_QSTR_timeout); -} - -// Helper to ensure we have the native super class instead of a subclass. -static zephyr_serial_uart_obj_t *native_uart(mp_obj_t uart_obj) { - mp_obj_t native_uart = mp_obj_cast_to_native_base(uart_obj, MP_OBJ_FROM_PTR(&zephyr_serial_uart_type)); - if (native_uart == MP_OBJ_NULL) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("Must be a %q subclass."), MP_QSTR_UART); - } - mp_obj_assert_native_inited(native_uart); - return MP_OBJ_TO_PTR(native_uart); -} - - -//| def deinit(self) -> None: -//| """Deinitialises the UART and releases any hardware resources for reuse.""" -//| ... -//| -static mp_obj_t _zephyr_serial_uart_obj_deinit(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - zephyr_serial_uart_deinit(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_deinit_obj, _zephyr_serial_uart_obj_deinit); - -static void check_for_deinit(zephyr_serial_uart_obj_t *self) { - if (zephyr_serial_uart_deinited(self)) { - raise_deinited_error(); - } -} - -//| def __enter__(self) -> UART: -//| """No-op used by Context Managers.""" -//| ... -//| -// Provided by context manager helper. - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -// Provided by context manager helper. - -// These are standard stream methods. Code is in py/stream.c. -// -//| def read(self, nbytes: Optional[int] = None) -> Optional[bytes]: -//| """Read bytes. If ``nbytes`` is specified then read at most that many -//| bytes. Otherwise, read everything that arrives until the connection -//| times out. Providing the number of bytes expected is highly recommended -//| because it will be faster. If no bytes are read, return ``None``. -//| -//| .. note:: When no bytes are read due to a timeout, this function returns ``None``. -//| This matches the behavior of `io.RawIOBase.read` in Python 3, but -//| differs from pyserial which returns ``b''`` in that situation. -//| -//| :return: Data read -//| :rtype: bytes or None""" -//| ... -//| - -//| def readinto(self, buf: WriteableBuffer) -> Optional[int]: -//| """Read bytes into the ``buf``. Read at most ``len(buf)`` bytes. -//| -//| :return: number of bytes read and stored into ``buf`` -//| :rtype: int or None (on a non-blocking error) -//| -//| *New in CircuitPython 4.0:* No length parameter is permitted.""" -//| ... -//| - -//| def readline(self) -> bytes: -//| """Read a line, ending in a newline character, or -//| return ``None`` if a timeout occurs sooner, or -//| return everything readable if no newline is found and -//| ``timeout=0`` -//| -//| :return: the line read -//| :rtype: bytes or None""" -//| ... -//| - -//| def write(self, buf: ReadableBuffer) -> Optional[int]: -//| """Write the buffer of bytes to the bus. -//| -//| *New in CircuitPython 4.0:* ``buf`` must be bytes, not a string. -//| -//| :return: the number of bytes written -//| :rtype: int or None""" -//| ... -//| - -// These three methods are used by the shared stream methods. -static mp_uint_t _zephyr_serial_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { - STREAM_DEBUG("_zephyr_serial_uart_read stream %d\n", size); - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - byte *buf = buf_in; - - // make sure we want at least 1 char - if (size == 0) { - return 0; - } - - return zephyr_serial_uart_read(self, buf, size, errcode); -} - -static mp_uint_t _zephyr_serial_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - const byte *buf = buf_in; - - return zephyr_serial_uart_write(self, buf, size, errcode); -} - -static mp_uint_t _zephyr_serial_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - mp_uint_t ret; - if (request == MP_STREAM_POLL) { - mp_uint_t flags = arg; - ret = 0; - if ((flags & MP_STREAM_POLL_RD) && zephyr_serial_uart_rx_characters_available(self) > 0) { - ret |= MP_STREAM_POLL_RD; - } - if ((flags & MP_STREAM_POLL_WR) && zephyr_serial_uart_ready_to_tx(self)) { - ret |= MP_STREAM_POLL_WR; - } - } else { - *errcode = MP_EINVAL; - ret = MP_STREAM_ERROR; - } - return ret; -} - -//| baudrate: int -//| """The current baudrate.""" -static mp_obj_t _zephyr_serial_uart_obj_get_baudrate(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(zephyr_serial_uart_get_baudrate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_get_baudrate_obj, _zephyr_serial_uart_obj_get_baudrate); - -static mp_obj_t _zephyr_serial_uart_obj_set_baudrate(mp_obj_t self_in, mp_obj_t baudrate) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - zephyr_serial_uart_set_baudrate(self, mp_obj_get_int(baudrate)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(_zephyr_serial_uart_set_baudrate_obj, _zephyr_serial_uart_obj_set_baudrate); - - -MP_PROPERTY_GETSET(_zephyr_serial_uart_baudrate_obj, - (mp_obj_t)&_zephyr_serial_uart_get_baudrate_obj, - (mp_obj_t)&_zephyr_serial_uart_set_baudrate_obj); - -//| in_waiting: int -//| """The number of bytes in the input buffer, available to be read""" -static mp_obj_t _zephyr_serial_uart_obj_get_in_waiting(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(zephyr_serial_uart_rx_characters_available(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_get_in_waiting_obj, _zephyr_serial_uart_obj_get_in_waiting); - -MP_PROPERTY_GETTER(_zephyr_serial_uart_in_waiting_obj, - (mp_obj_t)&_zephyr_serial_uart_get_in_waiting_obj); - -//| timeout: float -//| """The current timeout, in seconds (float).""" -//| -static mp_obj_t _zephyr_serial_uart_obj_get_timeout(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - return mp_obj_new_float(zephyr_serial_uart_get_timeout(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_get_timeout_obj, _zephyr_serial_uart_obj_get_timeout); - -static mp_obj_t _zephyr_serial_uart_obj_set_timeout(mp_obj_t self_in, mp_obj_t timeout) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - mp_float_t timeout_float = mp_obj_get_float(timeout); - validate_timeout(timeout_float); - zephyr_serial_uart_set_timeout(self, timeout_float); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(_zephyr_serial_uart_set_timeout_obj, _zephyr_serial_uart_obj_set_timeout); - - -MP_PROPERTY_GETSET(_zephyr_serial_uart_timeout_obj, - (mp_obj_t)&_zephyr_serial_uart_get_timeout_obj, - (mp_obj_t)&_zephyr_serial_uart_set_timeout_obj); - -//| def reset_input_buffer(self) -> None: -//| """Discard any unread characters in the input buffer.""" -//| ... -//| -//| -static mp_obj_t _zephyr_serial_uart_obj_reset_input_buffer(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - zephyr_serial_uart_clear_rx_buffer(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_reset_input_buffer_obj, _zephyr_serial_uart_obj_reset_input_buffer); - -static const mp_rom_map_elem_t _zephyr_serial_uart_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&_zephyr_serial_uart_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&_zephyr_serial_uart_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, - - // Standard stream methods. - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - - { MP_ROM_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&_zephyr_serial_uart_reset_input_buffer_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&_zephyr_serial_uart_baudrate_obj) }, - { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&_zephyr_serial_uart_in_waiting_obj) }, - { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&_zephyr_serial_uart_timeout_obj) }, - -}; -static MP_DEFINE_CONST_DICT(_zephyr_serial_uart_locals_dict, _zephyr_serial_uart_locals_dict_table); - -static const mp_stream_p_t uart_stream_p = { - .read = _zephyr_serial_uart_read, - .write = _zephyr_serial_uart_write, - .ioctl = _zephyr_serial_uart_ioctl, - .is_text = false, - // Disallow optional length argument for .readinto() - .pyserial_readinto_compatibility = true, -}; - -MP_DEFINE_CONST_OBJ_TYPE( - zephyr_serial_uart_type, - MP_QSTR_UART, - MP_TYPE_FLAG_ITER_IS_ITERNEXT | MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - locals_dict, &_zephyr_serial_uart_locals_dict, - iter, mp_stream_unbuffered_iter, - protocol, &uart_stream_p - ); diff --git a/ports/zephyr-cp/bindings/zephyr_serial/UART.h b/ports/zephyr-cp/bindings/zephyr_serial/UART.h deleted file mode 100644 index 704b9a2d605..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_serial/UART.h +++ /dev/null @@ -1,41 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/zephyr_serial/UART.h" -#include "py/ringbuf.h" - -#include - -extern const mp_obj_type_t zephyr_serial_uart_type; - -// Construct an underlying UART object. -extern void zephyr_serial_uart_construct(zephyr_serial_uart_obj_t *self, - const struct device *const uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer); - -extern void zephyr_serial_uart_deinit(zephyr_serial_uart_obj_t *self); -extern bool zephyr_serial_uart_deinited(zephyr_serial_uart_obj_t *self); - -// Read characters. len is in characters NOT bytes! -extern size_t zephyr_serial_uart_read(zephyr_serial_uart_obj_t *self, - uint8_t *data, size_t len, int *errcode); - -// Write characters. len is in characters NOT bytes! -extern size_t zephyr_serial_uart_write(zephyr_serial_uart_obj_t *self, - const uint8_t *data, size_t len, int *errcode); - -extern uint32_t zephyr_serial_uart_get_baudrate(zephyr_serial_uart_obj_t *self); -extern void zephyr_serial_uart_set_baudrate(zephyr_serial_uart_obj_t *self, uint32_t baudrate); -extern mp_float_t zephyr_serial_uart_get_timeout(zephyr_serial_uart_obj_t *self); -extern void zephyr_serial_uart_set_timeout(zephyr_serial_uart_obj_t *self, mp_float_t timeout); - -extern uint32_t zephyr_serial_uart_rx_characters_available(zephyr_serial_uart_obj_t *self); -extern void zephyr_serial_uart_clear_rx_buffer(zephyr_serial_uart_obj_t *self); -extern bool zephyr_serial_uart_ready_to_tx(zephyr_serial_uart_obj_t *self); - -extern void zephyr_serial_uart_never_reset(zephyr_serial_uart_obj_t *self); diff --git a/ports/zephyr-cp/bindings/zephyr_serial/__init__.c b/ports/zephyr-cp/bindings/zephyr_serial/__init__.c deleted file mode 100644 index f4a3c7b92e3..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_serial/__init__.c +++ /dev/null @@ -1,32 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include - -#include "py/obj.h" -#include "py/runtime.h" - -#include "shared-bindings/microcontroller/Pin.h" -#include "bindings/zephyr_serial/__init__.h" -#include "bindings/zephyr_serial/UART.h" - -#include "py/runtime.h" - -//| """Zephyr UART driver for fixed busses.""" - -static const mp_rom_map_elem_t zephyr_serial_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr_serial) }, - { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&zephyr_serial_uart_type) }, -}; - -static MP_DEFINE_CONST_DICT(zephyr_serial_module_globals, zephyr_serial_module_globals_table); - -const mp_obj_module_t zephyr_serial_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&zephyr_serial_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_zephyr_serial, zephyr_serial_module); diff --git a/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..334a3e98fb2 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Adafruit Industries LLC CLUE nRF52840 Express" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has displayio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = true # Zephyr board has zephyr_display +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.conf b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.conf new file mode 100644 index 00000000000..cfa31e2fdcf --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.conf @@ -0,0 +1,6 @@ +CONFIG_USE_DT_CODE_PARTITION=y + +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n + +# Enable the ST7789V TFT via the Zephyr display subsystem +CONFIG_DISPLAY=y diff --git a/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.overlay b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.overlay new file mode 100644 index 00000000000..586165dfe06 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.overlay @@ -0,0 +1,49 @@ +/ { + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + }; +}; + +&zephyr_udc0 { + /delete-node/ board_cdc_acm_uart; +}; + + +&gd25q16 { + /delete-node/ partitions; +}; + +/delete-node/ &storage_partition; +/delete-node/ &code_partition; + +&flash0 { + partitions { + code_partition: partition@26000 { + compatible = "zephyr,mapped-partition"; + label = "Application"; + reg = <0x00026000 0x000c4000>; + }; + + storage_partition: partition@ea000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x000ea000 0x00008000>; + }; + + nvm_partition: partition@f2000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0x000f2000 0x00002000>; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/circuitpython.toml new file mode 100644 index 00000000000..4af0c99d878 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/circuitpython.toml @@ -0,0 +1,7 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex", "uf2"] +USB_VID=0x239A +USB_PID=0x8072 +NAME="CLUE nRF52840 Express" + +# Non-Zephyr build of the same board; nvm and CIRCUITPY must sit where it puts them. +counterpart = "nordic/clue_nrf52840_express" diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..90ceb326be4 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Adafruit Industries LLC Feather Bluefruit Sense" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.conf b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.conf new file mode 100644 index 00000000000..6d7299ec6e6 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.conf @@ -0,0 +1,3 @@ +CONFIG_USE_DT_CODE_PARTITION=y + +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.overlay b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.overlay new file mode 100644 index 00000000000..586165dfe06 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.overlay @@ -0,0 +1,49 @@ +/ { + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + }; +}; + +&zephyr_udc0 { + /delete-node/ board_cdc_acm_uart; +}; + + +&gd25q16 { + /delete-node/ partitions; +}; + +/delete-node/ &storage_partition; +/delete-node/ &code_partition; + +&flash0 { + partitions { + code_partition: partition@26000 { + compatible = "zephyr,mapped-partition"; + label = "Application"; + reg = <0x00026000 0x000c4000>; + }; + + storage_partition: partition@ea000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x000ea000 0x00008000>; + }; + + nvm_partition: partition@f2000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0x000f2000 0x00002000>; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/circuitpython.toml new file mode 100644 index 00000000000..5dfa12f79df --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/circuitpython.toml @@ -0,0 +1,7 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +USB_VID=0x239A +USB_PID=0x8088 +NAME="Feather Bluefruit Sense" + +# Non-Zephyr build of the same board; nvm and CIRCUITPY must sit where it puts them. +counterpart = "nordic/feather_bluefruit_sense" diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..902d9e8a320 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Adafruit Industries LLC Feather nRF52840 Express" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.conf b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.conf new file mode 100644 index 00000000000..6d7299ec6e6 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.conf @@ -0,0 +1,3 @@ +CONFIG_USE_DT_CODE_PARTITION=y + +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.overlay b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.overlay new file mode 100644 index 00000000000..586165dfe06 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.overlay @@ -0,0 +1,49 @@ +/ { + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + }; +}; + +&zephyr_udc0 { + /delete-node/ board_cdc_acm_uart; +}; + + +&gd25q16 { + /delete-node/ partitions; +}; + +/delete-node/ &storage_partition; +/delete-node/ &code_partition; + +&flash0 { + partitions { + code_partition: partition@26000 { + compatible = "zephyr,mapped-partition"; + label = "Application"; + reg = <0x00026000 0x000c4000>; + }; + + storage_partition: partition@ea000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x000ea000 0x00008000>; + }; + + nvm_partition: partition@f2000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0x000f2000 0x00002000>; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml new file mode 100644 index 00000000000..8f97aca1d3d --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml @@ -0,0 +1,7 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +USB_VID=0x239A +USB_PID=0x802A +NAME="Feather nRF52840 Express" + +# Non-Zephyr build of the same board; nvm and CIRCUITPY must sit where it puts them. +counterpart = "nordic/feather_nrf52840_express" diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..05d9ca80a7f --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Adafruit Industries LLC Feather RP2040" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.conf b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.conf new file mode 100644 index 00000000000..91c3c15b37d --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.conf @@ -0,0 +1 @@ +CONFIG_GPIO=y diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.overlay b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.overlay new file mode 100644 index 00000000000..71c30f06406 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.overlay @@ -0,0 +1,44 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + ranges; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + code_partition: partition@100 { + compatible = "zephyr,mapped-partition"; + label = "code-partition"; + reg = <0x100 (0xfe000 - 0x100)>; + read-only; + }; + + storage_partition: partition@fe000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0xfe000 0x1000>; + }; + + nvm_partition: partition@ff000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0xff000 0x1000>; + }; + + circuitpy_partition: partition@100000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x100000 (DT_SIZE_M(8) - 0x100000)>; + }; + }; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/circuitpython.toml new file mode 100644 index 00000000000..4e992a212f4 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/circuitpython.toml @@ -0,0 +1,4 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] + +# Non-Zephyr build of the same board; nvm and CIRCUITPY must sit where it puts them. +counterpart = "raspberrypi/adafruit_feather_rp2040" diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index b8df9fb87f5..e1faa7c3888 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -1,8 +1,59 @@ -set(pca10056_BOARD_ALIAS nrf52840dk/nrf52840) -set(renesas_ek_ra6m5_BOARD_ALIAS ek_ra6m5) -set(renesas_ek_ra8d1_BOARD_ALIAS ek_ra8d1) -set(nordic_nrf54l15dk_BOARD_ALIAS nrf54l15dk/nrf54l15/cpuapp) -set(nordic_nrf5340dk_BOARD_ALIAS nrf5340dk/nrf5340/cpuapp) -set(nordic_nrf7002dk_BOARD_ALIAS nrf7002dk/nrf5340/cpuapp) -set(st_stm32h7b3i_dk_BOARD_ALIAS stm32h7b3i_dk) -set(st_nucleo_u575zi_q_BOARD_ALIAS nucleo_u575zi_q/stm32u575xx) +# Workaround for Zephyr alias handling with BOARD_QUALIFIERS in newer Zephyr. +# +# Instead of using _BOARD_ALIAS variables, translate BOARD directly so +# we don't end up with a spurious trailing '/' in BOARD_QUALIFIERS. +macro(cp_board_alias alias target) + if(BOARD STREQUAL "${alias}") + if(NOT "${target}" MATCHES "^([^@/]+)(@[^@/]+)?(/([^@]+))?$") + message(FATAL_ERROR "Invalid alias target '${target}'") + endif() + + set(BOARD_ALIAS "${alias}" CACHE STRING "Board alias, provided by user") + set(BOARD "${CMAKE_MATCH_1}") + + if(CMAKE_MATCH_2) + string(REPLACE "@" "" _rev "${CMAKE_MATCH_2}") + set(BOARD_REVISION "${_rev}") + else() + unset(BOARD_REVISION) + endif() + + if(CMAKE_MATCH_4) + set(BOARD_QUALIFIERS "${CMAKE_MATCH_4}") + else() + unset(BOARD_QUALIFIERS) + endif() + endif() +endmacro() + +cp_board_alias(pca10056 nrf52840dk/nrf52840) +cp_board_alias(adafruit_feather_nrf52840_zephyr adafruit_feather_nrf52840/nrf52840/uf2) +cp_board_alias(adafruit_clue_nrf52840_zephyr adafruit_clue_nrf52840/nrf52840/uf2) +cp_board_alias(adafruit_feather_nrf52840_sense_zephyr adafruit_feather_nrf52840/nrf52840/sense/uf2) +cp_board_alias(adafruit_feather_rp2040_zephyr adafruit_feather_rp2040/rp2040) +cp_board_alias(renesas_ek_ra6m5 ek_ra6m5) +cp_board_alias(renesas_ek_ra8d1 ek_ra8d1) +cp_board_alias(renesas_da14695_dk_usb da14695_dk_usb) +cp_board_alias(native_native_sim native_sim/native) +cp_board_alias(native_native_sim_asan native_sim/native) +cp_board_alias(native_nrf5340bsim nrf5340bsim/nrf5340/cpuapp) +cp_board_alias(native_nrf54lm20bsim nrf54lm20bsim/nrf54lm20a/cpuapp) +cp_board_alias(nordic_nrf54l15dk nrf54l15dk/nrf54l15/cpuapp) +cp_board_alias(nordic_nrf54l15tag nrf54l15tag/nrf54l15/cpuapp) +cp_board_alias(nordic_nrf54lm20dk nrf54lm20dk/nrf54lm20a/cpuapp) +cp_board_alias(nordic_nrf54h20dk nrf54h20dk/nrf54h20/cpuapp) +cp_board_alias(nordic_nrf5340dk nrf5340dk/nrf5340/cpuapp) +cp_board_alias(nordic_nrf7002dk nrf7002dk/nrf5340/cpuapp) +cp_board_alias(nxp_frdm_mcxn947 frdm_mcxn947/mcxn947/cpu0) +cp_board_alias(nxp_frdm_rw612 frdm_rw612) +cp_board_alias(nxp_mimxrt1170_evk mimxrt1170_evk@A/mimxrt1176/cm7) +cp_board_alias(st_stm32h7b3i_dk stm32h7b3i_dk) +cp_board_alias(st_stm32h750b_dk stm32h750b_dk/stm32h750xx/ext_flash_app) +cp_board_alias(st_stm32wba65i_dk1 stm32wba65i_dk1) +cp_board_alias(st_nucleo_u575zi_q nucleo_u575zi_q/stm32u575xx) +cp_board_alias(raspberrypi_rpi_pico_zephyr rpi_pico/rp2040) +cp_board_alias(raspberrypi_rpi_pico_w_zephyr rpi_pico/rp2040/w) +cp_board_alias(raspberrypi_rpi_pico2_zephyr rpi_pico2/rp2350a/m33) +cp_board_alias(raspberrypi_rpi_pico2_w_zephyr rpi_pico2/rp2350a/m33/w) +cp_board_alias(st_nucleo_n657x0_q nucleo_n657x0_q/stm32n657xx) +cp_board_alias(silabs_siwx917_dk2605a siwx917_dk2605a) diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml new file mode 100644 index 00000000000..e738a839210 --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "zephyr Native simulator - native_sim" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = true # Zephyr board has audiobusio +audiocore = true # Zephyr board has audiobusio +audiodelays = true # Zephyr board has audiobusio +audiofilewriter = false +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio +audioi2sin = false +audioio = false +audiomixer = true # Zephyr board has audiobusio +audiomp3 = true # Zephyr board has audiobusio +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has displayio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true # Zephyr networking enabled +hostnetwork = true # Zephyr board has hostnetwork +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = true # Zephyr networking enabled +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = true # Zephyr board has audiobusio +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = true # Zephyr board has zephyr_display +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/native/native_sim/board.conf b/ports/zephyr-cp/boards/native/native_sim/board.conf new file mode 100644 index 00000000000..a550d70dacc --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim/board.conf @@ -0,0 +1,48 @@ +# No Bluetooth hardware on native_sim +CONFIG_BT=n + +CONFIG_EMUL=y +CONFIG_GPIO=y +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=n + +# So we can test safe mode +CONFIG_NATIVE_SIM_REBOOT=y + +CONFIG_TRACING=y +CONFIG_TRACING_PERFETTO=y +CONFIG_TRACING_SYNC=y +CONFIG_TRACING_BACKEND_POSIX=y +CONFIG_TRACING_GPIO=y + +# I2C emulation for testing +CONFIG_I2C_EMUL=y + +# Display emulation for display/terminal golden tests. +CONFIG_DISPLAY=y +CONFIG_SDL_DISPLAY=y +# Don't require hardware acceleration so the software renderer can be used. +CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n + +# EEPROM emulation for testing +CONFIG_EEPROM=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT2X_EMUL=y + +# I2S SDL emulation for audio testing +CONFIG_I2S_SDL=y + +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_ETH_NATIVE_TAP=n +CONFIG_NET_DRIVERS=y +CONFIG_NET_SOCKETS_OFFLOAD=y +CONFIG_NET_NATIVE_OFFLOADED_SOCKETS=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 + +CONFIG_NET_LOG=y + +CONFIG_MBEDTLS=y +CONFIG_PSA_WANT_ALG_SHA_1=y +CONFIG_PSA_WANT_ALG_SHA_256=y diff --git a/ports/zephyr-cp/boards/native/native_sim/board.overlay b/ports/zephyr-cp/boards/native/native_sim/board.overlay new file mode 100644 index 00000000000..d59a13db80d --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim/board.overlay @@ -0,0 +1,63 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Device tree overlay for CircuitPython on native_sim. + * Adds simulated SRAM region required by CircuitPython build system. + */ + +#include + +/ { + sram0: memory@20000000 { + device_type = "memory"; + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_M(1)>; + zephyr,memory-region = "SRAM"; + }; + + chosen { + zephyr,sram = &sram0; + /delete-property/ zephyr,flash; + /delete-property/ zephyr,code-partition; + }; +}; + +&flash0 { + /delete-node/ partitions; + partitions { + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00000000 DT_SIZE_K(2032)>; + }; + + storage_partition: partition@1fc000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x001fc000 DT_SIZE_K(8)>; + }; + + nvm_partition: partition@1fe000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0x001fe000 0x00002000>; + }; + }; +}; + +/* Add emulated I2C devices for testing */ +&i2c0 { + at24_eeprom: eeprom@50 { + compatible = "atmel,at24"; + reg = <0x50>; + size = <256>; + pagesize = <8>; + address-width = <8>; + timeout = <5>; + }; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml b/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml new file mode 100644 index 00000000000..7177c825f17 --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["exe"] diff --git a/ports/zephyr-cp/boards/native/native_sim_asan/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim_asan/autogen_board_info.toml new file mode 100644 index 00000000000..e738a839210 --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim_asan/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "zephyr Native simulator - native_sim" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = true # Zephyr board has audiobusio +audiocore = true # Zephyr board has audiobusio +audiodelays = true # Zephyr board has audiobusio +audiofilewriter = false +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio +audioi2sin = false +audioio = false +audiomixer = true # Zephyr board has audiobusio +audiomp3 = true # Zephyr board has audiobusio +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has displayio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true # Zephyr networking enabled +hostnetwork = true # Zephyr board has hostnetwork +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = true # Zephyr networking enabled +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = true # Zephyr board has audiobusio +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = true # Zephyr board has zephyr_display +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/native/native_sim_asan/board.conf b/ports/zephyr-cp/boards/native/native_sim_asan/board.conf new file mode 100644 index 00000000000..62ebc476a8e --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim_asan/board.conf @@ -0,0 +1,51 @@ +# Build with AddressSanitizer to catch memory errors in tests. +CONFIG_ASAN=y + +# No Bluetooth hardware on native_sim +CONFIG_BT=n + +CONFIG_EMUL=y +CONFIG_GPIO=y +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=n + +# So we can test safe mode +CONFIG_NATIVE_SIM_REBOOT=y + +CONFIG_TRACING=y +CONFIG_TRACING_PERFETTO=y +CONFIG_TRACING_SYNC=y +CONFIG_TRACING_BACKEND_POSIX=y +CONFIG_TRACING_GPIO=y + +# I2C emulation for testing +CONFIG_I2C_EMUL=y + +# Display emulation for display/terminal golden tests. +CONFIG_DISPLAY=y +CONFIG_SDL_DISPLAY=y +# Don't require hardware acceleration so the software renderer can be used. +CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n + +# EEPROM emulation for testing +CONFIG_EEPROM=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT2X_EMUL=y + +# I2S SDL emulation for audio testing +CONFIG_I2S_SDL=y + +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_ETH_NATIVE_TAP=n +CONFIG_NET_DRIVERS=y +CONFIG_NET_SOCKETS_OFFLOAD=y +CONFIG_NET_NATIVE_OFFLOADED_SOCKETS=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 + +CONFIG_NET_LOG=y + +CONFIG_MBEDTLS=y +CONFIG_PSA_WANT_ALG_SHA_1=y +CONFIG_PSA_WANT_ALG_SHA_256=y diff --git a/ports/zephyr-cp/boards/native/native_sim_asan/board.overlay b/ports/zephyr-cp/boards/native/native_sim_asan/board.overlay new file mode 100644 index 00000000000..33cbc530998 --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim_asan/board.overlay @@ -0,0 +1,8 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Device tree overlay for CircuitPython on native_sim with AddressSanitizer. + * Identical hardware description to the non-asan board, so just reuse it. + */ + +#include "../native_sim/board.overlay" diff --git a/ports/zephyr-cp/boards/native/native_sim_asan/circuitpython.toml b/ports/zephyr-cp/boards/native/native_sim_asan/circuitpython.toml new file mode 100644 index 00000000000..7177c825f17 --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim_asan/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["exe"] diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml new file mode 100644 index 00000000000..737f642dea3 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "zephyr nRF5340 simulated boards (BabbleSim)" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/board.conf b/ports/zephyr-cp/boards/native/nrf5340bsim/board.conf new file mode 100644 index 00000000000..2579bf28d67 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/board.conf @@ -0,0 +1,20 @@ +# Configuration for nrf5340bsim simulated board +# Mirror settings from native_sim.conf for compatibility + +CONFIG_GPIO=y + +# Enable Bluetooth stack - bsim is for BT simulation +CONFIG_BT_HCI=y +CONFIG_BT_HCI_VS=y + +# Override Kconfig default +CONFIG_BT_BUF_CMD_TX_COUNT=2 + +# Ensure the network core image starts when using native simulator +CONFIG_NATIVE_SIMULATOR_AUTOSTART_MCU=y + +CONFIG_TRACING=y +CONFIG_TRACING_PERFETTO=y +CONFIG_TRACING_SYNC=y +CONFIG_TRACING_BACKEND_POSIX=y +CONFIG_TRACING_GPIO=y diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/board.overlay b/ports/zephyr-cp/boards/native/nrf5340bsim/board.overlay new file mode 100644 index 00000000000..5f0c9fd7af8 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/board.overlay @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/ { + chosen { + zephyr,sram = &sram0; + }; +}; + +&sram0 { + compatible = "zephyr,memory-region", "mmio-sram"; + zephyr,memory-region = "SRAM"; +}; + +&flash0 { + /delete-node/ partitions; + partitions { + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00000000 DT_SIZE_K(1008)>; + }; + + storage_partition: partition@fc000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x000fc000 DT_SIZE_K(16)>; + }; + }; +}; + +/* Note: bsim doesn't have USB, so we don't include app.overlay */ diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml new file mode 100644 index 00000000000..7177c825f17 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["exe"] diff --git a/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml new file mode 100644 index 00000000000..fba8b5ebd52 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "zephyr nRF54LM20 simulated boards (BabbleSim)" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/native/nrf54lm20bsim/board.conf b/ports/zephyr-cp/boards/native/nrf54lm20bsim/board.conf new file mode 100644 index 00000000000..e2a9595c2a3 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf54lm20bsim/board.conf @@ -0,0 +1,27 @@ +# Configuration for nrf54lm20bsim simulated board + +CONFIG_GPIO=y + +# Enable Bluetooth stack - bsim is for BT simulation +CONFIG_BT_HCI=y +CONFIG_BT_HCI_VS=y + +# Match nrf54lm20dk hardware: support dynamic TX power control +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y + +# Override Kconfig default +CONFIG_BT_BUF_CMD_TX_COUNT=2 + +# The bsim native_sim does not drive the BLE controller ticker time-slot +# mechanism used for radio-synchronized flash operations. With the default +# SOC_FLASH_NRF_RADIO_SYNC_TICKER, flash erase/write waits on a semaphore +# that is never given, hanging for ~34s (FLASH_TIMEOUT_MS) per operation. +# Disable radio sync so flash operations run directly, matching nrf5340bsim +# (which uses an IPC-based controller and so defaults to _NONE). +CONFIG_SOC_FLASH_NRF_RADIO_SYNC_NONE=y + +CONFIG_TRACING=y +CONFIG_TRACING_PERFETTO=y +CONFIG_TRACING_SYNC=y +CONFIG_TRACING_BACKEND_POSIX=y +CONFIG_TRACING_GPIO=y diff --git a/ports/zephyr-cp/boards/native/nrf54lm20bsim/board.overlay b/ports/zephyr-cp/boards/native/nrf54lm20bsim/board.overlay new file mode 100644 index 00000000000..ed5831ec5a3 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf54lm20bsim/board.overlay @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/ { + sram0: memory@20000000 { + device_type = "memory"; + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(511)>; + zephyr,memory-region = "SRAM"; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; + +&cpuapp_rram { + /delete-node/ partitions; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00000000 (DT_SIZE_K(2036) - DT_SIZE_K(32))>; + }; + + storage_partition: partition@1f5000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x001f5000 DT_SIZE_K(32)>; + }; + }; +}; + +/* Note: bsim doesn't have USB, so we don't include app.overlay */ diff --git a/ports/zephyr-cp/boards/native/nrf54lm20bsim/circuitpython.toml b/ports/zephyr-cp/boards/native/nrf54lm20bsim/circuitpython.toml new file mode 100644 index 00000000000..7177c825f17 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf54lm20bsim/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["exe"] diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 222a325e346..2c2194316a1 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -2,113 +2,130 @@ name = "Nordic Semiconductor nRF5340 DK" [modules] -__future__ = false -_bleio = false +__future__ = true +_bleio = true # Zephyr board has _bleio _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false atexit = false -audiobusio = false -audiocore = false -audiodelays = false -audiofilters = false -audiofreeverb = false +audiobusio = true # Zephyr board has audiobusio +audiocore = true # Zephyr board has audiobusio +audiodelays = true # Zephyr board has audiobusio +audiofilewriter = false +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio +audioi2sin = false audioio = false -audiomixer = false -audiomp3 = false +audiomixer = true # Zephyr board has audiobusio +audiomp3 = true # Zephyr board has audiobusio audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false -board = false -busdisplay = false -busio = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +emmcio = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false -gifio = false +getpass = true +gifio = true # Zephyr board has busio gnss = false -hashlib = false -i2cdisplaybus = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false -lvfontio = false -math = false +lvfontio = true # Zephyr board has busio +math = true max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false microcontroller = true -msgpack = false +mipidsi = false +msgpack = true neopixel_write = false nvm = false onewireio = false os = true paralleldisplaybus = false +picogame = false ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +qspibus = false +rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false -synthio = false -terminalio = false -tilepalettemapper = false +supervisor = true +synthio = true # Zephyr board has audiobusio +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false -zephyr_serial = true -zlib = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/board.overlay b/ports/zephyr-cp/boards/nordic/nrf5340dk/board.overlay new file mode 100644 index 00000000000..6b7ee85de7c --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/board.overlay @@ -0,0 +1,32 @@ +&pinctrl { + i2s0_default_alt: i2s0_default_alt { + group1 { + psels = , + , + , + , + ; + }; + }; +}; + +&clock { + hfclkaudio-frequency = <11289600>; +}; + +i2s_rxtx: &i2s0 { + status = "okay"; + pinctrl-0 = <&i2s0_default_alt>; + pinctrl-names = "default"; + clock-source = "ACLK"; +}; + +/* Remove slot1 (OTA), expand slot0 to use the space. + * CircuitPython doesn't use OTA updates. */ +&slot0_partition { + reg = <0x00010000 0x000E0000>; +}; + +/delete-node/ &slot1_partition; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/circuitpython.toml index bf17d26d91b..cc7e3ae8c4a 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/circuitpython.toml @@ -1,3 +1,3 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] USB_VID=0x239A USB_PID=0x8166 diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml new file mode 100644 index 00000000000..69b7eab3840 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Nordic Semiconductor nRF54H20 DK" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = false # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = false # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/board.conf b/ports/zephyr-cp/boards/nordic/nrf54h20dk/board.conf new file mode 100644 index 00000000000..3aca8d77007 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/board.conf @@ -0,0 +1,11 @@ +CONFIG_FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE=4096 + +# BLE overflows flash on this board. +CONFIG_BT=n + +# Reduce flash usage for this board. +CONFIG_LOG=y +CONFIG_LOG_MAX_LEVEL=2 +CONFIG_ASSERT=n +CONFIG_FRAME_POINTER=n +CONFIG_HW_STACK_PROTECTION=n diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/board.overlay b/ports/zephyr-cp/boards/nordic/nrf54h20dk/board.overlay new file mode 100644 index 00000000000..e557179992b --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/board.overlay @@ -0,0 +1,55 @@ +&gpio6 { + status = "okay"; + zephyr,pm-device-runtime-auto; +}; + +&exmif { + status = "okay"; + zephyr,pm-device-runtime-auto; +}; + +&mx25uw63 { + status = "okay"; +}; + +/* + * SDA = P2.11 + * SCL = P2.10 + */ + +&pinctrl { + i2c130_default: i2c130_default { + group1 { + psels = , + ; + }; + }; + + i2c130_sleep: i2c130_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&i2c130 { + clock-frequency = ; + pinctrl-0 = <&i2c130_default>; + pinctrl-1 = <&i2c130_sleep>; + pinctrl-names = "default", "sleep"; + zephyr,concat-buf-size = <256>; + memory-regions = <&cpuapp_dma_region>; + status = "okay"; +}; + +/* Remove slot1 (OTA), expand slot0 to use the space. + * CircuitPython doesn't use OTA updates. */ +&slot0_partition { + reg = <0x40000 DT_SIZE_K(656)>; +}; + +/delete-node/ &slot1_partition; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml new file mode 100644 index 00000000000..7cf2501b2b1 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml @@ -0,0 +1,2 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "hex"] +DISABLED_MODULES=["jpegio", "gifio", "tilepalettemapper"] diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 41631c3d6c0..a90aa98af34 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -2,15 +2,15 @@ name = "Nordic Semiconductor nRF54L15 DK" [modules] -__future__ = false -_bleio = false +__future__ = true +_bleio = true # Zephyr board has _bleio _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -18,97 +18,114 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false -board = false -busdisplay = false -busio = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +emmcio = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false -gifio = false +getpass = true +gifio = true # Zephyr board has busio gnss = false -hashlib = false -i2cdisplaybus = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false -lvfontio = false -math = false +lvfontio = true # Zephyr board has busio +math = true max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false microcontroller = true -msgpack = false +mipidsi = false +msgpack = true neopixel_write = false nvm = false onewireio = false os = true paralleldisplaybus = false +picogame = false ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +qspibus = false +rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false +usb_audio = false usb_cdc = false usb_hid = false usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false -zephyr_serial = true -zlib = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/board.overlay b/ports/zephyr-cp/boards/nordic/nrf54l15dk/board.overlay new file mode 100644 index 00000000000..7ffd2dec4d6 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/board.overlay @@ -0,0 +1,28 @@ +// nRF54L15 DK doesn't have USB, so no app.overlay for CDC ACM. + +// I2C bus on P1.8 (SDA) and P1.10 (SCL). +&pinctrl { + i2c21_default: i2c21_default { + group1 { + psels = , + ; + bias-pull-up; + }; + }; + + i2c21_sleep: i2c21_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&i2c21 { + clock-frequency = ; + pinctrl-0 = <&i2c21_default>; + pinctrl-1 = <&i2c21_sleep>; + pinctrl-names = "default", "sleep"; + status = "okay"; +}; diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/circuitpython.toml index 3272dd4c5f3..00c797b1dad 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/circuitpython.toml @@ -1 +1 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "hex"] diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml new file mode 100644 index 00000000000..b5bc0dee33b --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Nordic Semiconductor nRF54L15 TAG" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15tag/board.conf b/ports/zephyr-cp/boards/nordic/nrf54l15tag/board.conf new file mode 100644 index 00000000000..2627ebe2e5f --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54l15tag/board.conf @@ -0,0 +1,4 @@ +# Enable UART console (not enabled in the Zephyr board defconfig) +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15tag/board.overlay b/ports/zephyr-cp/boards/nordic/nrf54l15tag/board.overlay new file mode 100644 index 00000000000..ddf5c8f7e8f --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54l15tag/board.overlay @@ -0,0 +1,39 @@ +// No app.overlay because it doesn't have USB. + +// The nrf54l15tag Zephyr board doesn't enable a UART or set zephyr,console, +// unlike the nrf54l15dk. Set up UART30 as the console using available pins. +&uart30 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart30_default>; + pinctrl-1 = <&uart30_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&pinctrl { + uart30_default: uart30_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart30_sleep: uart30_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +/ { + chosen { + zephyr,console = &uart30; + zephyr,shell-uart = &uart30; + zephyr,uart-mcumgr = &uart30; + }; +}; diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15tag/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54l15tag/circuitpython.toml new file mode 100644 index 00000000000..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54l15tag/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] diff --git a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml new file mode 100644 index 00000000000..828e2eaafbf --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Nordic Semiconductor nRF54LM20 DK" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.conf b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.conf new file mode 100644 index 00000000000..19f8cea27a2 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.conf @@ -0,0 +1,10 @@ +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y + +# Work around a latent bug in soc_flash_nrf_ticker.c: with the default +# NRF_RRAM_WRITE_BUFFER_SIZE=1, FLASH_SLOT_WRITE (500 us) < +# FLASH_SYNC_SWITCHING_TIME (1700 us), so `interval = duration - +# FLASH_SYNC_SWITCHING_TIME` underflows and the next flash slot is scheduled +# ~71 minutes out. Any write larger than a single 16-byte slot then times out +# (-ETIMEDOUT / -116), e.g. persisting bond keys right after pairing. +# See zephyr/tests/boards/nrf/rram/overlay-radio_sync.conf. +CONFIG_NRF_RRAM_WRITE_BUFFER_SIZE=32 diff --git a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.overlay b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.overlay new file mode 100644 index 00000000000..0f48a5a5d46 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.overlay @@ -0,0 +1,52 @@ +// nRF54LM20 DK has USB. Include the main app overlay for USB CDC ACM console and data. +#include "../../../app.overlay" + +// Link application starting at 0x0 instead of slot0_partition (no mcuboot yet). +/ { + chosen { + zephyr,code-partition = &cpuapp_rram; + }; +}; + +// Enable the external MX25R6435F 8MB QSPI flash (connected via SPIM00). +&mx25r64 { + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + label = "circuitpy"; + reg = <0x00000000 DT_SIZE_M(8)>; + }; + }; +}; + +// I2C bus on P1.13 (SDA) and P1.23 (SCL). +&pinctrl { + i2c21_default: i2c21_default { + group1 { + psels = , + ; + bias-pull-up; + }; + }; + + i2c21_sleep: i2c21_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&i2c21 { + clock-frequency = ; + pinctrl-0 = <&i2c21_default>; + pinctrl-1 = <&i2c21_sleep>; + pinctrl-names = "default", "sleep"; + status = "okay"; +}; diff --git a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/circuitpython.toml new file mode 100644 index 00000000000..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index ea009aa36e1..6b7b93cce5c 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "Nordic Semiconductor nRF7002 DK" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false @@ -18,97 +18,114 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false -board = false -busdisplay = false -busio = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +emmcio = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false -gifio = false +getpass = true +gifio = false # Zephyr board has busio gnss = false -hashlib = false -i2cdisplaybus = false +hashlib = true # Zephyr networking enabled +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false -ipaddress = false +ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = false +jpegio = false # Zephyr board has busio keypad = false keypad_demux = false locale = false -lvfontio = false -math = false +lvfontio = true # Zephyr board has busio +math = true max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false microcontroller = true -msgpack = false +mipidsi = false +msgpack = true neopixel_write = false nvm = false onewireio = false os = true paralleldisplaybus = false +picogame = false ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +qspibus = false +rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = true # Zephyr networking enabled spitarget = false ssl = true # Zephyr networking enabled storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = false # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = true # Zephyr board has wifi +zephyr_display = false zephyr_kernel = false -zephyr_serial = true zlib = false +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/board.conf b/ports/zephyr-cp/boards/nordic/nrf7002dk/board.conf new file mode 100644 index 00000000000..346dcf5e7e2 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/board.conf @@ -0,0 +1,13 @@ +CONFIG_NETWORKING=y +CONFIG_WIFI=y +CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n + +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y + +CONFIG_LOG=n +CONFIG_ASSERT=n +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_BT=n +# Settings only stores BT bond keys here. With BT off, its NVS backend would +# still need storage_partition, which board.overlay removes. +CONFIG_SETTINGS=n diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/board.overlay b/ports/zephyr-cp/boards/nordic/nrf7002dk/board.overlay new file mode 100644 index 00000000000..cec4fbb2b98 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/board.overlay @@ -0,0 +1,16 @@ +/* Remove slot1 (OTA) and storage, expand slot0 to use the space. + * CircuitPython doesn't use OTA updates, and nothing here uses the settings + * NVS: CONFIG_BT=n, and CIRCUITPY lives on the external mx25r64. */ +&slot0_partition { + /* Shrink mcuboot to 48KB, absorb slot1 and storage, run to end of flash */ + reg = <0x0000C000 0x000F4000>; +}; + +&boot_partition { + reg = <0x00000000 0x0000C000>; +}; + +/delete-node/ &slot1_partition; +/delete-node/ &storage_partition; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml index 76b10578813..badaffb8e1b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml @@ -1,4 +1,12 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] USB_VID=0x239A USB_PID=0x8168 BLOBS=["nrf_wifi"] +DISABLED_MODULES=["aesio", "adafruit_bus_device", "zlib", "jpegio", "tilepalettemapper", "gifio"] + +# ulab is on by default. This board has under 3 KB of flash headroom, and +# ulab costs about 90 KB, so it opts out. +CIRCUITPY_ULAB = false + +# The same 3 KB is why radio.ping() is off here too. +CIRCUITPY_WIFI_PING = false diff --git a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf deleted file mode 100644 index fa0532e8150..00000000000 --- a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf deleted file mode 100644 index 6f01624bb3a..00000000000 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ /dev/null @@ -1,12 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_WIFI=y - -CONFIG_MBEDTLS_TLS_VERSION_1_2=y -CONFIG_MBEDTLS_USE_PSA_CRYPTO=n - -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml new file mode 100644 index 00000000000..c6c217056b7 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "NXP Semiconductors FRDM-MCXN947" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = true # Zephyr board has audiobusio +audiocore = true # Zephyr board has audiobusio +audiodelays = true # Zephyr board has audiobusio +audiofilewriter = false +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio +audioi2sin = false +audioio = false +audiomixer = true # Zephyr board has audiobusio +audiomp3 = true # Zephyr board has audiobusio +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = true # Zephyr board has audiobusio +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.conf b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.conf new file mode 100644 index 00000000000..61f2d18ca3c --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.conf @@ -0,0 +1 @@ +CONFIG_DMA_TCD_QUEUE_SIZE=4 diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.overlay b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.overlay new file mode 100644 index 00000000000..3eef280f220 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.overlay @@ -0,0 +1,23 @@ +&w25q64jvssiq { + /delete-node/ partitions; + + partitions { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + storage_partition: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x0 DT_SIZE_K(32)>; + }; + + circuitpy_partition: partition@8000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00008000 (DT_SIZE_M(8) - DT_SIZE_K(32))>; + }; + }; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/circuitpython.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/circuitpython.toml new file mode 100644 index 00000000000..3272dd4c5f3 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml new file mode 100644 index 00000000000..dfe32e2da1f --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "NXP Semiconductors FRDM-RW612" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true # Zephyr networking enabled +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = true # Zephyr networking enabled +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = true # Zephyr networking enabled +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = true # Zephyr board has wifi +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/board.conf b/ports/zephyr-cp/boards/nxp/frdm_rw612/board.conf new file mode 100644 index 00000000000..f8d1dfa0ad6 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/board.conf @@ -0,0 +1,25 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +CONFIG_WIFI=y +CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + +CONFIG_NET_HOSTNAME_ENABLE=y +CONFIG_NET_HOSTNAME_DYNAMIC=y +CONFIG_NET_HOSTNAME="circuitpython" + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y +CONFIG_MBEDTLS_ENTROPY_C=y +CONFIG_MBEDTLS_CTR_DRBG_C=y + +# Override Kconfig default (3) +CONFIG_BT_BUF_ACL_TX_COUNT=8 + +CONFIG_UDC_WORKQUEUE_STACK_SIZE=1024 diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/board.overlay b/ports/zephyr-cp/boards/nxp/frdm_rw612/board.overlay new file mode 100644 index 00000000000..9153fd433ab --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/board.overlay @@ -0,0 +1,17 @@ +&w25q512jvfiq { + partitions { + /delete-node/ partition@620000; + storage_partition: partition@620000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x00620000 DT_SIZE_K(32)>; + }; + circuitpy_partition: partition@628000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00628000 (DT_SIZE_M(58) - DT_SIZE_K(128) - DT_SIZE_K(32))>; + }; + }; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/circuitpython.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/circuitpython.toml new file mode 100644 index 00000000000..9bceea470ca --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/circuitpython.toml @@ -0,0 +1,5 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +BLOBS=["hal_nxp"] + +[blob_fetch_args] +hal_nxp = ["--allow-regex", "^rw61x/"] diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml new file mode 100644 index 00000000000..e82b015f969 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "NXP Semiconductors MIMXRT1170-EVK" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = true # Zephyr board has audiobusio +audiocore = true # Zephyr board has audiobusio +audiodelays = true # Zephyr board has audiobusio +audiofilewriter = false +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio +audioi2sin = false +audioio = false +audiomixer = true # Zephyr board has audiobusio +audiomp3 = true # Zephyr board has audiobusio +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = true # Zephyr board has audiobusio +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.conf b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.conf new file mode 100644 index 00000000000..61f2d18ca3c --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.conf @@ -0,0 +1 @@ +CONFIG_DMA_TCD_QUEUE_SIZE=4 diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.overlay b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.overlay new file mode 100644 index 00000000000..cd5f0089494 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.overlay @@ -0,0 +1,21 @@ +&is25wp128 { + partitions { + /delete-node/ partition@e20000; + storage_partition: partition@e20000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x00e20000 DT_SIZE_K(32)>; + }; + circuitpy_partition: partition@e28000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00e28000 (DT_SIZE_M(2) - DT_SIZE_K(128) - DT_SIZE_K(32))>; + }; + }; +}; + +&sai1 { + mclk-output; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/circuitpython.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/circuitpython.toml new file mode 100644 index 00000000000..3272dd4c5f3 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..ed813ea69c3 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Raspberry Pi Foundation Raspberry Pi Pico 2" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true # Zephyr networking enabled +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = true # Zephyr networking enabled +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = true # Zephyr networking enabled +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = true # Zephyr board has wifi +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.conf b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.conf new file mode 100644 index 00000000000..8fcc1c0b9ae --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.conf @@ -0,0 +1,20 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +CONFIG_WIFI=y +CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + +CONFIG_NET_HOSTNAME_ENABLE=y +CONFIG_NET_HOSTNAME_DYNAMIC=y +CONFIG_NET_HOSTNAME="circuitpython" + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y +CONFIG_MBEDTLS_ENTROPY_C=y +CONFIG_MBEDTLS_CTR_DRBG_C=y diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.overlay b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.overlay new file mode 100644 index 00000000000..436cfc83276 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.overlay @@ -0,0 +1,33 @@ +&flash0 { + partitions { + #address-cells = <1>; + #size-cells = <1>; + + code_partition: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "code-partition"; + reg = <0x0 0x17f000>; + read-only; + }; + + storage_partition: partition@17f000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x17f000 0x1000>; + }; + + nvm_partition: partition@180000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(4) - 0x181000)>; + }; + }; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/circuitpython.toml new file mode 100644 index 00000000000..c042e1581c0 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/circuitpython.toml @@ -0,0 +1,5 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +BLOBS=["hal_infineon"] + +# Non-Zephyr build of the same board; nvm and CIRCUITPY must sit where it puts them. +counterpart = "raspberrypi/raspberry_pi_pico2_w" diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..9a4fd0543fa --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Raspberry Pi Foundation Raspberry Pi Pico 2" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/board.overlay b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/board.overlay new file mode 100644 index 00000000000..a8ce944ab8a --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/board.overlay @@ -0,0 +1,33 @@ +&flash0 { + partitions { + #address-cells = <1>; + #size-cells = <1>; + + code_partition: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "code-partition"; + reg = <0x0 0xfe000>; + read-only; + }; + + storage_partition: partition@fe000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0xfe000 0x1000>; + }; + + nvm_partition: partition@ff000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0xff000 0x1000>; + }; + + circuitpy_partition: partition@100000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x100000 (DT_SIZE_M(4) - 0x100000)>; + }; + }; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/circuitpython.toml new file mode 100644 index 00000000000..75ceb6ba60d --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/circuitpython.toml @@ -0,0 +1,4 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] + +# Non-Zephyr build of the same board; nvm and CIRCUITPY must sit where it puts them. +counterpart = "raspberrypi/raspberry_pi_pico2" diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..2cad2417bfa --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Raspberry Pi Foundation Raspberry Pi Pico" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true # Zephyr networking enabled +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = true # Zephyr networking enabled +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = true # Zephyr networking enabled +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = true # Zephyr board has wifi +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.conf b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.conf new file mode 100644 index 00000000000..1e2d7ae1cd2 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.conf @@ -0,0 +1,22 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +CONFIG_WIFI=y +CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + +CONFIG_NET_HOSTNAME_ENABLE=y +CONFIG_NET_HOSTNAME_DYNAMIC=y +CONFIG_NET_HOSTNAME="circuitpython" + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y +CONFIG_MBEDTLS_ENTROPY_C=y +CONFIG_MBEDTLS_CTR_DRBG_C=y + +CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.overlay b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.overlay new file mode 100644 index 00000000000..3130d8dc5aa --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.overlay @@ -0,0 +1,44 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + ranges; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + code_partition: partition@100 { + compatible = "zephyr,mapped-partition"; + label = "code-partition"; + reg = <0x100 (0x17f000 - 0x100)>; + read-only; + }; + + storage_partition: partition@17f000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x17f000 0x1000>; + }; + + nvm_partition: partition@180000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(2) - 0x181000)>; + }; + }; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/circuitpython.toml new file mode 100644 index 00000000000..deb99e3effa --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/circuitpython.toml @@ -0,0 +1,5 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +BLOBS=["hal_infineon"] + +# Non-Zephyr build of the same board; nvm and CIRCUITPY must sit where it puts them. +counterpart = "raspberrypi/raspberry_pi_pico_w" diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..442978a5cfe --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Raspberry Pi Foundation Raspberry Pi Pico" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/board.overlay b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/board.overlay new file mode 100644 index 00000000000..bfd690085a7 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/board.overlay @@ -0,0 +1,44 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + ranges; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + code_partition: partition@100 { + compatible = "zephyr,mapped-partition"; + label = "code-partition"; + reg = <0x100 (0xfe000 - 0x100)>; + read-only; + }; + + storage_partition: partition@fe000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0xfe000 0x1000>; + }; + + nvm_partition: partition@ff000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0xff000 0x1000>; + }; + + circuitpy_partition: partition@100000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x100000 (DT_SIZE_M(2) - 0x100000)>; + }; + }; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/circuitpython.toml new file mode 100644 index 00000000000..fae9877df08 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/circuitpython.toml @@ -0,0 +1,4 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] + +# Non-Zephyr build of the same board; nvm and CIRCUITPY must sit where it puts them. +counterpart = "raspberrypi/raspberry_pi_pico" diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml new file mode 100644 index 00000000000..e51c13c1ee6 --- /dev/null +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Renesas Electronics Corporation DA14695 Development Kit USB" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/board.overlay b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/board.overlay new file mode 100644 index 00000000000..6a8343384c9 --- /dev/null +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/board.overlay @@ -0,0 +1,19 @@ +/* Remove slot1 (OTA), expand slot0 to use the space. + * CircuitPython doesn't use OTA updates. */ +&slot0_partition { + reg = <0x00010000 DT_SIZE_K(1024)>; +}; + +/delete-node/ &slot1_partition; + +&flash0 { + partitions{ + circuitpy_partition: partition@118000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x118000 (DT_SIZE_M(4) - DT_SIZE_K(1120))>; + }; + }; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml new file mode 100644 index 00000000000..f7fad6bc444 --- /dev/null +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml @@ -0,0 +1,2 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +BLOBS=["hal_renesas"] diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index a96d1bad1d2..710f7387fe3 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -2,15 +2,15 @@ name = "Renesas Electronics Corporation RA6M5 Evaluation Kit" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -18,97 +18,114 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false -board = false -busdisplay = false -busio = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +emmcio = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false -gifio = false +getpass = true +gifio = true # Zephyr board has busio gnss = false -hashlib = false -i2cdisplaybus = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false -lvfontio = false -math = false +lvfontio = true # Zephyr board has busio +math = true max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false microcontroller = true -msgpack = false +mipidsi = false +msgpack = true neopixel_write = false nvm = false onewireio = false os = true paralleldisplaybus = false +picogame = false ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +qspibus = false +rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false -usb_cdc = false # No TinyUSB settings for r7fa6m5bh3cfc -usb_hid = false +usb_audio = false +usb_cdc = true +usb_hid = true usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false -zephyr_serial = true -zlib = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/circuitpython.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/circuitpython.toml index 3272dd4c5f3..13ff40aa042 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/circuitpython.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/circuitpython.toml @@ -1 +1,3 @@ +# TX is on pin P411. RX is on pin P410. + CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index e4946decb19..700960cfcab 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -2,15 +2,15 @@ name = "Renesas Electronics Corporation RA8D1 Evaluation Kit" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -18,97 +18,114 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false -board = false -busdisplay = false -busio = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has displayio dotclockframebuffer = false dualbank = false -epaperdisplay = false +emmcio = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false -gifio = false +getpass = true +gifio = true # Zephyr board has busio gnss = false -hashlib = false -i2cdisplaybus = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false -lvfontio = false -math = false +lvfontio = true # Zephyr board has busio +math = true max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false microcontroller = true -msgpack = false +mipidsi = false +msgpack = true neopixel_write = false nvm = false onewireio = false os = true paralleldisplaybus = false +picogame = false ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +qspibus = false +rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false -usb_cdc = false # No TinyUSB settings for r7fa8d1bhecbd -usb_hid = false +usb_audio = false +usb_cdc = true +usb_hid = true usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false +zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false -zephyr_serial = true -zlib = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/board.conf b/ports/zephyr-cp/boards/renesas/ek_ra8d1/board.conf new file mode 100644 index 00000000000..451f4199116 --- /dev/null +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/board.conf @@ -0,0 +1,12 @@ + +# Enable Zephyr display subsystem so DT chosen zephyr,display creates a device. +CONFIG_DISPLAY=y + +# RA8 USB can generate bursts of UDC/USBD events (especially with HS + MSC). +# Keep queues/buffers larger to avoid dropped events that can desynchronize +# control-transfer state (e.g. "udc: Cannot determine the next stage"). +CONFIG_UDC_RENESAS_RA_MAX_QMESSAGES=32 +CONFIG_USBD_MAX_UDC_MSG=32 +CONFIG_USBD_MSG_SLAB_COUNT=32 +CONFIG_UDC_BUF_COUNT=32 +CONFIG_UDC_BUF_POOL_SIZE=2048 diff --git a/ports/zephyr-cp/boards/ek_ra8d1.overlay b/ports/zephyr-cp/boards/renesas/ek_ra8d1/board.overlay similarity index 58% rename from ports/zephyr-cp/boards/ek_ra8d1.overlay rename to ports/zephyr-cp/boards/renesas/ek_ra8d1/board.overlay index 29735d02b8f..416be7b510e 100644 --- a/ports/zephyr-cp/boards/ek_ra8d1.overlay +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/board.overlay @@ -1,3 +1,5 @@ &s28hl512t { /delete-node/ partitions; }; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/circuitpython.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/circuitpython.toml index 3272dd4c5f3..0e19d8d7157 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/circuitpython.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/circuitpython.toml @@ -1 +1,2 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +SHIELDS = ["rtkmipilcdb00000be"] diff --git a/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/autogen_board_info.toml b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/autogen_board_info.toml new file mode 100644 index 00000000000..7f56bc19de7 --- /dev/null +++ b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Silicon Labs SiWx917 Wi-Fi 6 and Bluetooth LE SoC Dev Kit (BRD2605A)" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true # Zephyr networking enabled +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = true # Zephyr networking enabled +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = true # Zephyr networking enabled +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = true # Zephyr board has wifi +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.conf b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.conf new file mode 100644 index 00000000000..0ad2a578ee8 --- /dev/null +++ b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.conf @@ -0,0 +1,93 @@ +# The upstream board defconfig does not enable GPIO, so no gpio device structs +# are instantiated and the generated board.c fails to link. +CONFIG_GPIO=y + +# getaddrinfo() calls k_calloc(), which is compiled out when the kernel heap is +# zero-sized. prj.conf also draws thread stacks from this heap. +CONFIG_HEAP_MEM_POOL_SIZE=16384 + +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +# Not implied by the options above, and the siwx91x driver defaults to the +# native stack. Without it association and DHCP still work, since DHCP is UDP, +# while every SOCK_STREAM socket fails. +CONFIG_NET_TCP=y + +# Every Zephyr socket also takes a zvfs file descriptor, which defaults to 0. +CONFIG_ZVFS_OPEN_MAX=8 + +# Poll slots for the socket-service thread, a separate budget from OPEN_MAX. +# The thread polls one entry beyond the number of registered services, so this +# must be strictly greater than that count. DNS_RESOLVER registers one service +# and MDNS_RESPONDER two, so the Zephyr default of 3 is one short and the +# service thread fails at boot, leaving every socket it owns unread. +CONFIG_ZVFS_POLL_MAX=6 + +# dns_resolve_reconfigure() is additive by default: it fills free slots and +# stops when there are none, then still returns 0. With one server slot held by +# DHCP, assigning to radio.dns would install nothing and report success. This +# makes reconfigure rebuild the list instead, which is the replace semantics +# the binding implies by exposing dns as a settable Sequence[str]. +CONFIG_DNS_RECONFIGURE_CLEANUP=y + +# Incoming connections are bounded by the net_conn array, not the TCP context +# slab. At the default of 8 the web workflow refuses connections during a burst +# because teardown cannot recycle slots fast enough, since each closed +# connection holds its slot for TIME_WAIT. 12 leaves enough headroom, and the +# context slab is raised alongside it so the slab is not the tighter bound. +CONFIG_NET_MAX_CONTEXTS=12 +CONFIG_NET_MAX_CONN=12 + +# Zephyr's console (printk, boot banner, driver logs) goes to SEGGER RTT over +# the existing SWD connection rather than sharing the UART with the REPL, where +# net event printks interleave with and corrupt the REPL stream. CircuitPython's +# REPL is unaffected: supervisor/serial.c takes its device from +# DT_CHOSEN(zephyr_console) and drives it directly. +CONFIG_USE_SEGGER_RTT=y +CONFIG_RTT_CONSOLE=y +CONFIG_UART_CONSOLE=n + +CONFIG_WIFI=y +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + +# Answers .local and advertises services registered through +# mdns.Server.advertise_service(). Zephyr's responder is push-only, so +# mdns.Server.find() has nothing to search with yet. +CONFIG_MDNS_RESPONDER=y +CONFIG_DNS_SD=y +CONFIG_MDNS_RESPONDER_DNS_SD=y + +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y +CONFIG_MBEDTLS_ENTROPY_C=y +CONFIG_MBEDTLS_CTR_DRBG_C=y + +# Long writes need at least one prepare slot. Zephyr's unconditional default of +# 0 rejects any write that does not fit a single ATT_WRITE_REQ, and only an +# explicit assignment here overrides it. +CONFIG_BT_ATT_PREPARE_COUNT=2 + +# Zephyr's default preferred supervision timeout is 420ms, which the peripheral +# pushes onto the central shortly into every connection. That is thin on a +# single-antenna part whose network processor shares the radio with Wi-Fi. +# 400 = 4.0s, Apple's accessory guideline value. +CONFIG_BT_PERIPHERAL_PREF_MIN_INT=24 +CONFIG_BT_PERIPHERAL_PREF_MAX_INT=40 +CONFIG_BT_PERIPHERAL_PREF_LATENCY=0 +CONFIG_BT_PERIPHERAL_PREF_TIMEOUT=400 + +# The controller reports 15 ACL TX buffers while the host defaults to 3, which +# it warns about at boot. Match the host to the controller. +CONFIG_BT_BUF_ACL_TX_COUNT=15 + +# DHCP hands us a resolver, but the resolver subsystem has to be present for +# socketpool.getaddrinfo() and radio.ipv4_dns to work. +CONFIG_DNS_RESOLVER=y + +# DMA for the GSPI controller, which serves the breakout pads. +CONFIG_DMA=y diff --git a/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.overlay b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.overlay new file mode 100644 index 00000000000..f345c30b9b0 --- /dev/null +++ b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.overlay @@ -0,0 +1,69 @@ +// Replaces the port's app.overlay, which does `&zephyr_udc0 { ... }` to add a +// CDC-ACM console. The SiWG917 has no USB device controller, so the console +// falls back to the Zephyr console on &ulpuart, reaching the host over the +// on-board J-Link VCOM. + +// CIRCUITPY filesystem. +// +// supervisor/flash.c needs a partition labeled `circuitpy_partition`, and the +// whole 8 MB is already partitioned by siwg917m111mgtba.dtsi with no +// unallocated space to claim. The upper region is owned by the network +// processor, which refuses M4 writes there, so CIRCUITPY is carved out of the +// M4's own code_partition, shrunk from 2008K to 1M. Overflowing that fails at +// link time rather than corrupting the filesystem. +&flash0 { + partitions { + code_partition: partition@202000 { + compatible = "zephyr,mapped-partition"; + label = "code_partition"; + reg = <0x00202000 0x00100000>; + }; + + circuitpy_partition: partition@302000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00302000 0x000f6000>; + }; + }; +}; + +// GSPI on the breakout pads. The board .dts leaves spi0 disabled and wires +// nothing, so the pin assignment here is taken from the mapping Silicon Labs +// ships for this board in +// zephyr/tests/drivers/spi/spi_loopback/boards/siwx917_dk2605a.overlay: +// CLK on pad 3, MOSI on pad 5, MISO on pad 7, CS on gpiob 12. +// +// spi0 is the SoC's only SPI controller node and is compatible "silabs,gspi". +// The on-board IMU is on a separate ULP SPI bus that has no controller node in +// devicetree, so it is not reachable through this one. +&pinctrl0 { + spi0_default: spi0_default { + out { + pinmux = , ; + }; + + in { + pinmux = ; + }; + }; +}; + +&spi0 { + status = "okay"; + cs-gpios = <&gpiob 12 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; + + dmas = <&gpdma 0 11>, <&gpdma 1 10>; + dma-names = "tx", "rx"; +}; + +&gpdma { + status = "okay"; +}; + +// 8 MB of PSRAM on the QSPI2 path. Present in ram_bounds; the Python heap does +// not use it yet. +&psram { + status = "okay"; +}; diff --git a/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/circuitpython.toml b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/circuitpython.toml new file mode 100644 index 00000000000..1f15a6f8349 --- /dev/null +++ b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["rps"] diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml new file mode 100644 index 00000000000..f2b7a9c78b7 --- /dev/null +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "STMicroelectronics Nucleo N657X0-Q" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml new file mode 100644 index 00000000000..e8de92166db --- /dev/null +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml @@ -0,0 +1,5 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] + +# This part executes from RAM and is already at 93% of it, so it cannot +# absorb the roughly 90 KB ulab adds. +CIRCUITPY_ULAB = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 7519d881768..8f32deab204 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -2,15 +2,15 @@ name = "STMicroelectronics Nucleo U575ZI Q" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -18,97 +18,114 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false -board = false -busdisplay = false -busio = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +emmcio = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false -gifio = false +getpass = true +gifio = true # Zephyr board has busio gnss = false -hashlib = false -i2cdisplaybus = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false -lvfontio = false -math = false +lvfontio = true # Zephyr board has busio +math = true max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false microcontroller = true -msgpack = false +mipidsi = false +msgpack = true neopixel_write = false nvm = false onewireio = false os = true paralleldisplaybus = false +picogame = false ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +qspibus = false +rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false -zephyr_serial = true -zlib = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml new file mode 100644 index 00000000000..7f7146c8e10 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "STMicroelectronics STM32H750B Discovery Kit" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has displayio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = true # Zephyr board has zephyr_display +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/board.conf b/ports/zephyr-cp/boards/st/stm32h750b_dk/board.conf new file mode 100644 index 00000000000..24afffb8e88 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/board.conf @@ -0,0 +1,2 @@ +# Enable Zephyr display subsystem so the built-in LTDC panel is available. +CONFIG_DISPLAY=y diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/board.overlay b/ports/zephyr-cp/boards/st/stm32h750b_dk/board.overlay new file mode 100644 index 00000000000..7e038bb77aa --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/board.overlay @@ -0,0 +1,21 @@ +&ext_flash { + partitions { + /delete-node/ partition@7800000; + + storage_partition: partition@7800000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x7800000 DT_SIZE_K(32)>; + }; + + circuitpy_partition: partition@7808000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x7808000 (DT_SIZE_M(8) - DT_SIZE_K(32))>; + }; + }; +}; + +&rng { + status = "okay"; +}; diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/circuitpython.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/circuitpython.toml new file mode 100644 index 00000000000..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index e029020982d..666515bca60 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -2,15 +2,15 @@ name = "STMicroelectronics STM32H7B3I Discovery kit" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -18,97 +18,114 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false -board = false -busdisplay = false -busio = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has displayio dotclockframebuffer = false dualbank = false -epaperdisplay = false +emmcio = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false -gifio = false +getpass = true +gifio = true # Zephyr board has busio gnss = false -hashlib = false -i2cdisplaybus = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false -lvfontio = false -math = false +lvfontio = true # Zephyr board has busio +math = true max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false microcontroller = true -msgpack = false +mipidsi = false +msgpack = true neopixel_write = false nvm = false onewireio = false os = true paralleldisplaybus = false +picogame = false ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +qspibus = false +rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false -usb_cdc = false -usb_hid = false +usb_audio = false +usb_cdc = true +usb_hid = true usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false +zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false -zephyr_serial = true -zlib = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.conf b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.conf new file mode 100644 index 00000000000..24afffb8e88 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.conf @@ -0,0 +1,2 @@ +# Enable Zephyr display subsystem so the built-in LTDC panel is available. +CONFIG_DISPLAY=y diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.overlay b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.overlay new file mode 100644 index 00000000000..75e497714c9 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.overlay @@ -0,0 +1,45 @@ +&mx25lm51245 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@0 { + label = "storage"; + reg = <0x00000000 DT_SIZE_K(32)>; + }; + + circuitpy_partition: partition@8000 { + label = "circuitpy"; + reg = <0x00008000 (DT_SIZE_M(64) - DT_SIZE_K(32))>; + }; + }; +}; + +&sram5 { + status = "disabled"; +}; + +&rng { + status = "okay"; +}; + +&fdcan1 { + status = "disabled"; +}; + +/ { + chosen { + /delete-property/ zephyr,canbus; + }; +}; + +zephyr_udc0: &usbotg_hs { + pinctrl-0 = <&usb_otg_hs_dm_pa11 &usb_otg_hs_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml new file mode 100644 index 00000000000..84d17af7c12 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -0,0 +1,131 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "STMicroelectronics STM32WBA65I Discovery kit" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = true # Always enabled +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +emmcio = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +picogame = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.conf b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.conf new file mode 100644 index 00000000000..d83be8dddb5 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.conf @@ -0,0 +1,10 @@ +# USB OTG on STM32WBA requires VOS Range 1. Keep HCLK > 16 MHz. +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=32000000 + +# Bluetooth doesn't start up for some reason. +# CONFIG_BT=y +# CONFIG_BT_PERIPHERAL=y +# CONFIG_BT_CENTRAL=y + +# Board-specific BT calibration +CONFIG_BT_STM32WBA_USE_TEMP_BASED_CALIB=n diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.overlay b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.overlay new file mode 100644 index 00000000000..da2c7427c4a --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.overlay @@ -0,0 +1,77 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + ranges; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + + slot0_partition: partition@10000 { + compatible = "zephyr,mapped-partition"; + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(928)>; + }; + + storage_partition: partition@f80000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x001e0000 DT_SIZE_K(64)>; + }; + + circuitpy_partition: partition@108000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00108000 DT_SIZE_K(992)>; + }; + }; +}; + +&rng { + status = "okay"; +}; + +/* + * USB on STM32WBA requires VOS Range 1. Zephyr selects VOS from HCLK, and + * 16 MHz keeps it in Range 2, which trips an assertion in udc_stm32. + * Run SYSCLK from full 32 MHz HSE so VOS is set to Range 1. + */ +&clk_hse { + /delete-property/ hse-div2; +}; + +&rcc { + clock-frequency = ; + ahb5-prescaler = <1>; +}; + +zephyr_udc0: &usbotg_hs { + status = "okay"; +}; + +&otghs_phy { + /* OTG HS clock source is 32 MHz HSE */ + clocks = <&rcc STM32_CLOCK(AHB2, 15)>, + <&rcc STM32_SRC_HSE OTGHS_SEL(0)>; + clock-reference = "SYSCFG_OTG_HS_PHY_CLK_32MHz"; + status = "okay"; +}; + +&bt_hci_wba { + /* Use HASH IRQ to allocate Radio SW Low Process (Warning HASH is not used) */ + interrupts = <66 0>, <61 14>; + interrupt-names = "radio", "radio-sw-low"; +}; + +&ieee802154 { + /* Use HASH IRQ to allocate Radio SW Low Process (Warning HASH is not used) */ + interrupts = <66 0>, <61 14>; + interrupt-names = "radio", "radio-sw-low"; +}; + +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml new file mode 100644 index 00000000000..fb3dfea6867 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml @@ -0,0 +1,2 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] +BLOBS=["hal_stm32"] diff --git a/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay b/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay deleted file mode 100644 index 88ad0415485..00000000000 --- a/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay +++ /dev/null @@ -1,7 +0,0 @@ -&mx25lm51245 { - /delete-node/ partitions; -}; - -&rng { - status = "okay"; -}; diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c new file mode 100644 index 00000000000..7819e68676e --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -0,0 +1,944 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/_bleio/__init__.h" +#include "common-hal/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Address.h" +#include "shared-module/_bleio/Address.h" +#include "shared-module/_bleio/ScanResults.h" +#include "supervisor/background_callback.h" +#include "supervisor/shared/bluetooth/bluetooth.h" +#include "supervisor/shared/tick.h" + +bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; + +// Background pump: drains the BLE file-transfer / serial PacketBuffers by +// calling supervisor_bluetooth_background(). Queued from GATT write callbacks +// and connection events so the VM processes incoming data promptly. +static background_callback_t bluetooth_background_cb = {NULL, NULL}; + +static void bluetooth_adapter_background(void *data) { + (void)data; + supervisor_bluetooth_background(); +} + +void bleio_request_bluetooth_background(void) { + if (bluetooth_background_cb.fun != NULL) { + background_callback_add_core(&bluetooth_background_cb); + } +} + +static bool scan_callbacks_registered = false; +static bleio_scanresults_obj_t *active_scan_results = NULL; +static struct bt_le_scan_cb scan_callbacks; +static bool ble_advertising = false; +// True when advertising was started by the BLE workflow (supervisor) rather +// than user code. Lets the workflow restart its own adverts without disturbing +// user-initiated advertising. +static bool ble_advertising_internal = false; +// Set to true when common_hal_bleio_adapter_set_enabled(true) brings the stack up. +// set_enabled(false) clears this flag and stops advertising and scanning, but +// the controller keeps running. +static bool ble_adapter_enabled = false; + +#define BLEIO_ADV_MAX_FIELDS 16 +#define BLEIO_ADV_MAX_DATA_LEN 31 +static struct bt_data adv_data[BLEIO_ADV_MAX_FIELDS]; +static struct bt_data scan_resp_data[BLEIO_ADV_MAX_FIELDS]; +static uint8_t adv_data_storage[BLEIO_ADV_MAX_DATA_LEN]; +static uint8_t scan_resp_storage[BLEIO_ADV_MAX_DATA_LEN]; + +static uint8_t bleio_address_type_from_zephyr(const bt_addr_le_t *addr) { + if (addr == NULL) { + return BLEIO_ADDRESS_TYPE_PUBLIC; + } + + switch (addr->type) { + case BT_ADDR_LE_PUBLIC: + case BT_ADDR_LE_PUBLIC_ID: + return BLEIO_ADDRESS_TYPE_PUBLIC; + case BT_ADDR_LE_RANDOM: + case BT_ADDR_LE_RANDOM_ID: + case BT_ADDR_LE_UNRESOLVED: + if (BT_ADDR_IS_RPA(&addr->a)) { + return BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_RESOLVABLE; + } + if (BT_ADDR_IS_NRPA(&addr->a)) { + return BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE; + } + return BLEIO_ADDRESS_TYPE_RANDOM_STATIC; + default: + return BLEIO_ADDRESS_TYPE_PUBLIC; + } +} + +static uint8_t bleio_address_type_to_zephyr(uint8_t type) { + switch (type) { + case BLEIO_ADDRESS_TYPE_PUBLIC: + return BT_ADDR_LE_PUBLIC; + case BLEIO_ADDRESS_TYPE_RANDOM_STATIC: + case BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_RESOLVABLE: + case BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE: + return BT_ADDR_LE_RANDOM; + default: + return BT_ADDR_LE_PUBLIC; + } +} + +static bleio_connection_internal_t *bleio_connection_find_by_conn(const struct bt_conn *conn) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + if (connection->conn == conn) { + return connection; + } + } + + return NULL; +} + +static bleio_connection_internal_t *bleio_connection_track(struct bt_conn *conn) { + bleio_connection_internal_t *connection = bleio_connection_find_by_conn(conn); + if (connection == NULL) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *candidate = &bleio_connections[i]; + if (candidate->conn == NULL) { + connection = candidate; + break; + } + } + } + + if (connection == NULL) { + return NULL; + } + + if (connection->conn == NULL) { + connection->conn = bt_conn_ref(conn); + } + + return connection; +} + +static void bleio_connection_clear(bleio_connection_internal_t *self) { + if (self == NULL) { + return; + } + + if (self->conn != NULL) { + bt_conn_unref(self->conn); + self->conn = NULL; + } + + self->connection_obj = mp_const_none; + self->pair_status = PAIR_NOT_PAIRED; + self->sec_err = 0; + self->user_owned = false; +} + +static void bleio_connection_release(bleio_connection_internal_t *connection, uint8_t reason) { + if (connection == NULL) { + return; + } + + if (connection->connection_obj != mp_const_none) { + bleio_connection_obj_t *connection_obj = MP_OBJ_TO_PTR(connection->connection_obj); + connection_obj->connection = NULL; + connection_obj->disconnect_reason = reason; + } + + bleio_connection_clear(connection); + common_hal_bleio_adapter_obj.connection_objs = NULL; +} + +// Per-connection ATT MTU exchange parameters. The params struct must persist +// until the exchange callback fires, so it lives for the lifetime of the slot. +static struct bt_gatt_exchange_params mtu_exchange_params[BLEIO_TOTAL_CONNECTION_COUNT]; + +static void on_mtu_exchanged(struct bt_conn *conn, uint8_t err, + struct bt_gatt_exchange_params *params) { + (void)conn; + (void)params; + if (err == 0) { + // Wake the workflow so outgoing_packet_length is recomputed with the + // now-larger negotiated MTU. + bleio_request_bluetooth_background(); + } +} + +static void bleio_connected_cb(struct bt_conn *conn, uint8_t err) { + if (err != 0) { + return; + } + + bleio_connection_internal_t *connection = bleio_connection_track(conn); + if (connection == NULL) { + bt_conn_disconnect(conn, BT_HCI_ERR_CONN_LIMIT_EXCEEDED); + return; + } + + // Initiate an ATT MTU exchange so the negotiated MTU reflects the larger + // payload our stack supports (CONFIG_BT_L2CAP_TX_MTU). Many centrals do + // this themselves, but if they don't we'd be stuck at the default 23-byte + // MTU (20-byte payload). That forces the file-transfer workflow to split + // protocol messages across notifications in ways peers can't reassemble + // (e.g. a listdir_entry whose second fragment begins with a 0x00 flags + // byte is misread as "unknown command 0x00"). bt_gatt_exchange_mtu returns + // -EALREADY if the peer already initiated, so this is safe either way. + size_t idx = (size_t)(connection - bleio_connections); + mtu_exchange_params[idx].func = on_mtu_exchanged; + int mtu_err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params[idx]); + (void)mtu_err; + + // A peripheral connection belongs to whoever started the advertising it + // answered: the BLE workflow (internal) or user code. Central connections + // are marked in common_hal_bleio_adapter_connect(). + connection->user_owned = !ble_advertising_internal; + + // When connectable advertising results in a connection, the controller + // auto-stops advertising. Clear our flag to match (we cannot call + // stop_advertising() here because this callback runs in Zephyr's BT + // thread context). + ble_advertising = false; + ble_advertising_internal = false; + + common_hal_bleio_adapter_obj.connection_objs = NULL; + + // Pump the workflow once now, and arm the recurring background callback + // so future GATT writes / events get drained by the VM. + bluetooth_background_cb.fun = bluetooth_adapter_background; + bluetooth_background_cb.data = NULL; + bluetooth_adapter_background(NULL); +} + +static void bleio_disconnected_cb(struct bt_conn *conn, uint8_t reason) { + bleio_connection_discovery_abort(); + bleio_connection_release(bleio_connection_find_by_conn(conn), reason); + bleio_request_bluetooth_background(); +} + +static void bleio_security_changed_cb(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err) { + bleio_connection_internal_t *connection = bleio_connection_find_by_conn(conn); + if (connection == NULL) { + return; + } + + if (err == BT_SECURITY_ERR_SUCCESS && level > BT_SECURITY_L1) { + // Security was established (encryption enabled). + // This happens both on first-time pairing and when reconnecting + // with stored bond keys. + connection->pair_status = PAIR_PAIRED; + } else if (err != BT_SECURITY_ERR_SUCCESS) { + connection->pair_status = PAIR_NOT_PAIRED; + connection->sec_err = (uint8_t)err; + } +} + +BT_CONN_CB_DEFINE(bleio_connection_callbacks) = { + .connected = bleio_connected_cb, + .disconnected = bleio_disconnected_cb, + .security_changed = bleio_security_changed_cb, +}; + +static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) { + if (active_scan_results == NULL || info == NULL || buf == NULL) { + return; + } + + const bool connectable = (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0; + const bool scan_response = (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0; + const bt_addr_le_t *addr = info->addr; + + uint8_t addr_bytes[NUM_BLEIO_ADDRESS_BYTES] = {0}; + if (addr != NULL) { + memcpy(addr_bytes, addr->a.val, sizeof(addr_bytes)); + } + + shared_module_bleio_scanresults_append(active_scan_results, + supervisor_ticks_ms64(), + connectable, + scan_response, + info->rssi, + addr_bytes, + bleio_address_type_from_zephyr(addr), + buf->data, + buf->len); +} + +static void scan_timeout_cb(void) { + if (active_scan_results == NULL) { + return; + } + shared_module_bleio_scanresults_set_done(active_scan_results, true); + active_scan_results = NULL; +} + +// We need to disassemble the full advertisement packet because the Zephyr takes +// in each ADT in an array. +static size_t bleio_parse_adv_data(const uint8_t *raw, size_t raw_len, struct bt_data *out, + size_t out_len, uint8_t *storage, size_t storage_len) { + size_t count = 0; + size_t offset = 0; + size_t storage_offset = 0; + + while (offset < raw_len) { + uint8_t field_len = raw[offset]; + if (field_len == 0) { + offset++; + continue; + } + uint8_t data_len = field_len - 1; + if (offset + field_len + 1 > raw_len || + count >= out_len || + storage_offset + data_len > storage_len) { + return 0; + } + uint8_t type = raw[offset + 1]; + memcpy(storage + storage_offset, raw + offset + 2, data_len); + out[count].type = type; + out[count].data_len = data_len; + out[count].data = storage + storage_offset; + storage_offset += data_len; + count++; + offset += field_len + 1; + } + + return count; +} + +static uint16_t bleio_validate_and_convert_timeout(mp_float_t timeout) { + mp_arg_validate_float_range(timeout, 0, UINT16_MAX, MP_QSTR_timeout); + + if (timeout <= 0.0f) { + return 0; + } + + const mp_int_t timeout_units = + mp_arg_validate_int_range((mp_int_t)(timeout * 100.0f + 0.5f), 1, UINT16_MAX, MP_QSTR_timeout); + + return (uint16_t)timeout_units; +} + +// Start the Zephyr Bluetooth host and load its settings (identity, bond keys, +// CCC state) if that hasn't happened yet. Returns 0 or a negative Zephyr errno. +// +// This is separate from set_enabled() because the BLE workflow asks about +// bonds (is_bonded_to_central(), erase_bonding()) in supervisor_bluetooth_init(), +// before it enables the adapter in supervisor_start_bluetooth(). Bond keys live +// in the settings subsystem and are only in RAM after settings_load(), so those +// calls must be able to bring the stack up on their own. Nothing here powers the +// controller down later: set_enabled(false) leaves it running. +static int bleio_adapter_ensure_stack_ready(void) { + if (bt_is_ready()) { + return 0; + } + int err = bt_enable(NULL); + if (err != 0 && err != -EALREADY) { + return err; + } + + // bt_init() returns early without setting BT_DEV_READY when + // CONFIG_BT_SETTINGS=y and no identity is loaded yet. + // Load settings so the BT settings handler fires and calls + // bt_finalize_init() which sets BT_DEV_READY. + settings_load(); + return 0; +} + +void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { + if (enabled == ble_adapter_enabled) { + return; + } + if (enabled) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_clear(&bleio_connections[i]); + } + int err = bleio_adapter_ensure_stack_ready(); + if (err != 0) { + raise_zephyr_error(err); + } + // Ensure a local identity exists so advertising/connections work and the + // name is stable across reboots. bt_id_create persists the identity when + // CONFIG_BT_SETTINGS is enabled. bleio_adapter_reset_name() reads the + // identity address back via common_hal_bleio_adapter_get_address(). + bt_addr_le_t id_addrs[CONFIG_BT_ID_MAX]; + size_t id_count = CONFIG_BT_ID_MAX; + bt_id_get(id_addrs, &id_count); + if (id_count == 0 || bt_addr_le_eq(&id_addrs[BT_ID_DEFAULT], BT_ADDR_LE_ANY)) { + (void)bt_id_create(NULL, NULL); + bt_id_get(id_addrs, &id_count); + } + bleio_adapter_reset_name(self); + ble_adapter_enabled = true; + return; + } + + // On Zephyr bsim + HCI IPC, disabling and immediately re-enabling BLE can + // race endpoint rebinding during soft reload. Keep the controller running, + // but present adapter.enabled=False to CircuitPython code. + common_hal_bleio_adapter_stop_scan(self); + common_hal_bleio_adapter_stop_advertising(self); + ble_adapter_enabled = false; +} + +bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { + return ble_adapter_enabled; +} + +mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self) { + struct bt_hci_cp_vs_read_tx_power_level *cp; + struct bt_hci_rp_vs_read_tx_power_level *rp; + struct net_buf *buf, *rsp = NULL; + + buf = bt_hci_cmd_alloc(K_MSEC(1000)); + if (!buf) { + mp_raise_msg(&mp_type_MemoryError, NULL); + } + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle_type = BT_HCI_VS_LL_HANDLE_TYPE_ADV; + cp->handle = 0; + + int err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_READ_TX_POWER_LEVEL, buf, &rsp); + if (err) { + raise_zephyr_error(err); + } + + rp = (void *)rsp->data; + int8_t power = rp->tx_power_level; + net_buf_unref(rsp); + return power; +} + +// Non-raising variant of common_hal_bleio_adapter_set_tx_power for use from the +// BLE workflow, which runs outside the VM. Returns 0 on success. +static int bleio_adapter_set_tx_power_noraise(mp_int_t tx_power) { + struct bt_hci_cp_vs_write_tx_power_level *cp; + struct net_buf *buf, *rsp = NULL; + + buf = bt_hci_cmd_alloc(K_MSEC(3000)); + if (!buf) { + return -ENOMEM; + } + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle_type = BT_HCI_VS_LL_HANDLE_TYPE_ADV; + cp->handle = 0; + cp->tx_power_level = (int8_t)tx_power; + + int err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL, buf, &rsp); + if (err) { + return err; + } + + net_buf_unref(rsp); + return 0; +} + +void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power) { + int err = bleio_adapter_set_tx_power_noraise(tx_power); + if (err) { + raise_zephyr_error(err); + } +} + +bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { + // Report the local identity address, which is the same address used to + // derive the default adapter name in common_hal_bleio_adapter_set_enabled. + bt_addr_le_t id_addrs[CONFIG_BT_ID_MAX]; + size_t id_count = CONFIG_BT_ID_MAX; + bt_id_get(id_addrs, &id_count); + if (id_count == 0 || bt_addr_le_eq(&id_addrs[BT_ID_DEFAULT], BT_ADDR_LE_ANY)) { + (void)bt_id_create(NULL, NULL); + bt_id_get(id_addrs, &id_count); + } + + const bt_addr_le_t *addr = &id_addrs[BT_ID_DEFAULT]; + // Cache the address on the adapter so this can be called before the heap + // is available (e.g. from bleio_adapter_reset_name). The shared + // common_hal_bleio_address_construct() converts the raw address bytes + // into the Address object. + common_hal_bleio_address_construct(&self->address, addr->a.val, + bleio_address_type_from_zephyr(addr)); + self->address.base.type = &bleio_address_type; + return &self->address; +} + +bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { + mp_raise_NotImplementedError(NULL); +} + +mp_obj_str_t *common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) { + (void)self; + const char *name = bt_get_name(); + return mp_obj_new_str(name, strlen(name)); +} + +void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char *name) { + (void)self; + size_t len = strlen(name); + int err = 0; + if (len > CONFIG_BT_DEVICE_NAME_MAX) { + char truncated[CONFIG_BT_DEVICE_NAME_MAX + 1]; + memcpy(truncated, name, CONFIG_BT_DEVICE_NAME_MAX); + truncated[CONFIG_BT_DEVICE_NAME_MAX] = '\0'; + err = bt_set_name(truncated); + } else { + err = bt_set_name(name); + } + if (err != 0) { + raise_zephyr_error(err); + } +} + +// Internal start_advertising used by the BLE workflow (file transfer + serial +// services). Runs outside the VM, so it must not raise. Returns 0 on success or +// a positive errno on failure. A timeout of 0 means advertise indefinitely. +// This is the core implementation; common_hal_bleio_adapter_start_advertising() +// delegates here and translates errors into exceptions. +uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, + bool connectable, bool anonymous, uint32_t timeout, float interval, + const uint8_t *advertising_data, uint16_t advertising_data_len, + const uint8_t *scan_response_data, uint16_t scan_response_data_len, + mp_int_t tx_power, const bleio_address_obj_t *directed_to) { + (void)directed_to; + (void)interval; + (void)anonymous; + (void)timeout; + + if (advertising_data_len > BLEIO_ADV_MAX_DATA_LEN || + scan_response_data_len > BLEIO_ADV_MAX_DATA_LEN) { + return (uint32_t)EINVAL; + } + + // Don't disturb advertising that is already active (either user code or the + // workflow's own previous advert). The caller is responsible for stopping + // first if a restart is desired. + if (ble_advertising) { + return (uint32_t)EBUSY; + } + + bt_addr_le_t id_addrs[CONFIG_BT_ID_MAX]; + size_t id_count = CONFIG_BT_ID_MAX; + bt_id_get(id_addrs, &id_count); + if (id_count == 0 || bt_addr_le_eq(&id_addrs[BT_ID_DEFAULT], BT_ADDR_LE_ANY)) { + int id = bt_id_create(NULL, NULL); + if (id < 0) { + return (uint32_t)(-id); + } + } + + size_t adv_count = bleio_parse_adv_data(advertising_data, + advertising_data_len, + adv_data, + BLEIO_ADV_MAX_FIELDS, + adv_data_storage, + sizeof(adv_data_storage)); + if (adv_count == 0) { + return (uint32_t)EINVAL; + } + + size_t scan_resp_count = 0; + if (scan_response_data_len > 0) { + scan_resp_count = bleio_parse_adv_data(scan_response_data, + scan_response_data_len, + scan_resp_data, + BLEIO_ADV_MAX_FIELDS, + scan_resp_storage, + sizeof(scan_resp_storage)); + if (scan_resp_count == 0) { + return (uint32_t)EINVAL; + } + } + + struct bt_le_adv_param adv_params; + if (connectable) { + adv_params = (struct bt_le_adv_param)BT_LE_ADV_PARAM_INIT( + BT_LE_ADV_OPT_CONN, + BT_GAP_ADV_FAST_INT_MIN_1, + BT_GAP_ADV_FAST_INT_MAX_1, + NULL); + } else if (scan_resp_count > 0) { + adv_params = (struct bt_le_adv_param)BT_LE_ADV_PARAM_INIT( + BT_LE_ADV_OPT_SCANNABLE, + BT_GAP_ADV_FAST_INT_MIN_2, + BT_GAP_ADV_FAST_INT_MAX_2, + NULL); + } else { + adv_params = (struct bt_le_adv_param)BT_LE_ADV_PARAM_INIT( + 0, + BT_GAP_ADV_FAST_INT_MIN_2, + BT_GAP_ADV_FAST_INT_MAX_2, + NULL); + } + + // Best-effort TX power: the vendor HCI command may not exist on all + // controllers, so ignore failures here. + (void)bleio_adapter_set_tx_power_noraise(tx_power); + + int err = bt_le_adv_start(&adv_params, + adv_data, + adv_count, + scan_resp_count > 0 ? scan_resp_data : NULL, + scan_resp_count); + if (err) { + return (uint32_t)(-err); + } + + ble_advertising = true; + // Default to workflow-owned; the public wrapper overrides this for user code. + ble_advertising_internal = true; + return 0; +} + +void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, + bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, + mp_buffer_info_t *advertising_data_bufinfo, + mp_buffer_info_t *scan_response_data_bufinfo, + mp_int_t tx_power, const bleio_address_obj_t *directed_to) { + (void)directed_to; + (void)interval; + + if (advertising_data_bufinfo->len > BLEIO_ADV_MAX_DATA_LEN || + scan_response_data_bufinfo->len > BLEIO_ADV_MAX_DATA_LEN) { + mp_raise_ValueError(MP_ERROR_TEXT("Data too large for advertisement packet")); + } + + if (timeout != 0) { + mp_raise_NotImplementedError(NULL); + } + + if (anonymous) { + mp_raise_NotImplementedError(NULL); + } + + if (ble_advertising) { + if (!ble_advertising_internal) { + // User code is already advertising. + raise_zephyr_error(-EALREADY); + } + // The workflow is advertising. Stop it so user code can take over. + common_hal_bleio_adapter_stop_advertising(self); + } + + uint32_t status = _common_hal_bleio_adapter_start_advertising(self, + connectable, + anonymous, + timeout, + interval, + advertising_data_bufinfo->buf, + advertising_data_bufinfo->len, + scan_response_data_bufinfo->buf, + scan_response_data_bufinfo->len, + tx_power, + directed_to); + if (status == (uint32_t)EINVAL) { + mp_raise_ValueError(MP_ERROR_TEXT("Invalid advertising data")); + } + if (status != 0) { + raise_zephyr_error(-(int)status); + } + + // Mark as user-owned so the workflow won't clobber it. + ble_advertising_internal = false; +} + +void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { + (void)self; + if (!ble_advertising) { + return; + } + bt_le_adv_stop(); + ble_advertising = false; + ble_advertising_internal = false; +} + +bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { + (void)self; + return ble_advertising; +} + +mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t *prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active) { + (void)extended; + + if (self->scan_results != NULL) { + if (!shared_module_bleio_scanresults_get_done(self->scan_results)) { + common_hal_bleio_adapter_stop_scan(self); + } else { + self->scan_results = NULL; + } + } + + int err = 0; + + self->scan_results = shared_module_bleio_new_scanresults(buffer_size, prefixes, prefix_length, minimum_rssi); + active_scan_results = self->scan_results; + + if (!scan_callbacks_registered) { + scan_callbacks.recv = scan_recv_cb; + scan_callbacks.timeout = scan_timeout_cb; + err = bt_le_scan_cb_register(&scan_callbacks); + if (err != 0) { + self->scan_results = NULL; + active_scan_results = NULL; + raise_zephyr_error(err); + } + scan_callbacks_registered = true; + } + + uint16_t interval_units = (uint16_t)((interval / 0.000625f) + 0.5f); + uint16_t window_units = (uint16_t)((window / 0.000625f) + 0.5f); + uint16_t timeout_units = bleio_validate_and_convert_timeout(timeout); + + struct bt_le_scan_param scan_params = { + .type = active ? BT_LE_SCAN_TYPE_ACTIVE : BT_LE_SCAN_TYPE_PASSIVE, + /* Do not filter duplicates: the application merges advertisement and + * scan-response packets and needs to observe updated advertisements + * from the same device (e.g. when user code replaces the workflow + * advert). */ + .options = 0, + .interval = interval_units, + .window = window_units, + .timeout = (uint16_t)timeout_units, + .interval_coded = 0, + .window_coded = 0, + }; + + err = bt_le_scan_start(&scan_params, NULL); + if (err != 0) { + self->scan_results = NULL; + active_scan_results = NULL; + raise_zephyr_error(err); + } + + return MP_OBJ_FROM_PTR(self->scan_results); +} + +void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { + if (self->scan_results == NULL) { + return; + } + bt_le_scan_stop(); + shared_module_bleio_scanresults_set_done(self->scan_results, true); + active_scan_results = NULL; + self->scan_results = NULL; +} + +bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { + if (!ble_adapter_enabled) { + return false; + } + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn != NULL) { + return true; + } + } + + return false; +} + +mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) { + if (!ble_adapter_enabled) { + self->connection_objs = NULL; + return mp_const_empty_tuple; + } + + if (self->connection_objs != NULL) { + return self->connection_objs; + } + + size_t total_connected = 0; + mp_obj_t items[BLEIO_TOTAL_CONNECTION_COUNT]; + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + if (connection->conn == NULL) { + continue; + } + + if (connection->connection_obj == mp_const_none) { + connection->connection_obj = bleio_connection_new_from_internal(connection); + } + + items[total_connected] = connection->connection_obj; + total_connected++; + } + + self->connection_objs = mp_obj_new_tuple(total_connected, items); + return self->connection_objs; +} + +mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { + common_hal_bleio_adapter_stop_scan(self); + + const uint16_t timeout_units = bleio_validate_and_convert_timeout(timeout); + + bt_addr_le_t peer = { + .type = bleio_address_type_to_zephyr(address->type), + }; + memcpy(peer.a.val, address->bytes, NUM_BLEIO_ADDRESS_BYTES); + + struct bt_conn_le_create_param create_params = BT_CONN_LE_CREATE_PARAM_INIT( + BT_CONN_LE_OPT_NONE, + BT_GAP_SCAN_FAST_INTERVAL, + BT_GAP_SCAN_FAST_INTERVAL); + create_params.timeout = timeout_units; + + struct bt_conn *conn = NULL; + int err = bt_conn_le_create(&peer, &create_params, BT_LE_CONN_PARAM_DEFAULT, &conn); + if (err != 0) { + raise_zephyr_error(err); + } + + while (true) { + struct bt_conn_info info; + err = bt_conn_get_info(conn, &info); + if (err == 0) { + if (info.state == BT_CONN_STATE_CONNECTED) { + break; + } + + if (info.state == BT_CONN_STATE_DISCONNECTED) { + bt_conn_unref(conn); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Failed to connect: timeout")); + } + } else if (err != -ENOTCONN) { + bt_conn_unref(conn); + raise_zephyr_error(err); + } + + RUN_BACKGROUND_TASKS; + } + + bleio_connection_internal_t *connection = bleio_connection_find_by_conn(conn); + if (connection == NULL) { + connection = bleio_connection_track(conn); + } + + if (connection == NULL) { + bt_conn_unref(conn); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Failed to connect: internal error")); + } + + // bt_conn_le_create() gave us a ref in `conn`; `connection` keeps its own + // ref via bleio_connection_track(). Drop the create ref now. + bt_conn_unref(conn); + + // Only user code connects in the central role. + connection->user_owned = true; + + self->connection_objs = NULL; + return bleio_connection_new_from_internal(connection); +} + +struct bond_collect_ctx { + bt_addr_le_t *addrs; + size_t *count; + size_t max; +}; + +static void bond_iterator_collect(const struct bt_bond_info *info, void *user_data) { + struct bond_collect_ctx *ctx = (struct bond_collect_ctx *)user_data; + if (*ctx->count < ctx->max) { + bt_addr_le_copy(&ctx->addrs[*ctx->count], &info->addr); + (*ctx->count)++; + } +} + +static void bond_iterator_check(const struct bt_bond_info *info, void *user_data) { + (void)info; + bool *has_bonds = (bool *)user_data; + *has_bonds = true; +} + +void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) { + // Can be called from Python as _bleio.adapter.erase_bonding(), and from + // supervisor_bluetooth_init() on a discovery-mode boot, before the adapter is + // enabled. Bond keys are only visible once the stack is up and settings are + // loaded; without this the loop below finds nothing and the bond reappears + // when the workflow starts. The workflow call runs before the VM, so a failure + // to start the stack is ignored here rather than raised. + if (bleio_adapter_ensure_stack_ready() != 0) { + return; + } + + // Unpair all bonded devices for all local identities. + for (uint8_t id = 0; id < CONFIG_BT_ID_MAX; id++) { + // bt_unpair takes an addr; use bt_foreach_bond to iterate and unpair. + // We need to collect addresses first since we can't unpair during iteration. + bt_addr_le_t addrs[CONFIG_BT_MAX_PAIRED]; + size_t addr_count = 0; + + bt_foreach_bond(id, bond_iterator_collect, &(struct bond_collect_ctx) { + .addrs = addrs, + .count = &addr_count, + .max = CONFIG_BT_MAX_PAIRED + }); + + for (size_t i = 0; i < addr_count; i++) { + bt_unpair(id, &addrs[i]); + } + } + + // Reset pairing state on all connections + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connections[i].pair_status = PAIR_NOT_PAIRED; + bleio_connections[i].sec_err = 0; + } +} + +bool common_hal_bleio_adapter_is_bonded_to_central(bleio_adapter_obj_t *self) { + // Called only by the BLE workflow, from supervisor_bluetooth_init() before + // the adapter is enabled and from supervisor_bluetooth_background(); see + // erase_bonding() above. Runs before the VM, so don't raise. + if (bleio_adapter_ensure_stack_ready() != 0) { + return false; + } + + // Check if any bond exists for any local identity. + for (uint8_t id = 0; id < CONFIG_BT_ID_MAX; id++) { + bool has_bonds = false; + bt_foreach_bond(id, bond_iterator_check, &has_bonds); + if (has_bonds) { + return true; + } + } + return false; +} + +void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) { + gc_collect_root((void **)adapter, sizeof(bleio_adapter_obj_t) / sizeof(size_t)); + gc_collect_root((void **)bleio_connections, sizeof(bleio_connections) / sizeof(size_t)); +} + +bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void) { + return &common_hal_bleio_adapter_obj; +} + +uint16_t bleio_adapter_get_name(char *buf, uint16_t len) { + const char *name = bt_get_name(); + uint16_t full_len = strlen(name); + if (len > 0) { + uint16_t copy_len = len < full_len ? len : full_len; + memcpy(buf, name, copy_len); + } + return full_len; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.h b/ports/zephyr-cp/common-hal/_bleio/Adapter.h new file mode 100644 index 00000000000..ba84e810bfe --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.h @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "py/objtuple.h" + +#include "shared-bindings/_bleio/Address.h" +#include "shared-bindings/_bleio/Connection.h" +#include "shared-bindings/_bleio/ScanResults.h" + +#define BLEIO_TOTAL_CONNECTION_COUNT CONFIG_BT_MAX_CONN + +extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; + +typedef struct { + mp_obj_base_t base; + bleio_scanresults_obj_t *scan_results; + mp_obj_t name; + mp_obj_tuple_t *connection_objs; + bool user_advertising; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; +} bleio_adapter_obj_t; + +void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); + +// Queue a background run of supervisor_bluetooth_background() so the VM drains +// incoming BLE PacketBuffer data. Safe to call from Zephyr BT/workqueue context. +void bleio_request_bluetooth_background(void); diff --git a/ports/zephyr-cp/common-hal/_bleio/Attribute.c b/ports/zephyr-cp/common-hal/_bleio/Attribute.c new file mode 100644 index 00000000000..6312f3d46b8 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Attribute.c @@ -0,0 +1,8 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Attribute is defined in shared-module, no port-specific implementation needed diff --git a/ports/zephyr-cp/common-hal/_bleio/Attribute.h b/ports/zephyr-cp/common-hal/_bleio/Attribute.h new file mode 100644 index 00000000000..24b0f78a106 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Attribute.h @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/_bleio/Attribute.h" diff --git a/ports/zephyr-cp/common-hal/_bleio/Characteristic.c b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c new file mode 100644 index 00000000000..e1ba8b7349f --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c @@ -0,0 +1,413 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include +#include +#include + +#include "py/runtime.h" +#include "py/gc.h" +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" +#include "common-hal/_bleio/__init__.h" +#include "common-hal/_bleio/CharacteristicBuffer.h" +#include "common-hal/_bleio/Connection.h" +#include "common-hal/_bleio/UUID.h" +#include "common-hal/_bleio/PacketBuffer.h" +#include "shared-bindings/_bleio/CharacteristicBuffer.h" +#include "shared-bindings/_bleio/PacketBuffer.h" +#include "supervisor/port_heap.h" + +// CCCD write callback — captures the subscribing connection for PacketBuffer. +ssize_t bleio_ccc_write_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, uint16_t value) { + struct bt_gatt_ccc_managed_user_data *ccc_data = + (struct bt_gatt_ccc_managed_user_data *)attr->user_data; + bleio_characteristic_obj_t *characteristic = + (bleio_characteristic_obj_t *)((char *)ccc_data + - offsetof(bleio_characteristic_obj_t, zephyr_ccc)); + + if (characteristic->observer != mp_const_none && + mp_obj_is_type(characteristic->observer, &bleio_packet_buffer_type)) { + bleio_packet_buffer_set_conn( + MP_OBJ_TO_PTR(characteristic->observer), + value != 0 ? conn : NULL); + } + return sizeof(value); +} + +uint16_t bleio_security_to_zephyr_perm( + bleio_attribute_security_mode_t read_perm, + bleio_attribute_security_mode_t write_perm, + bleio_characteristic_properties_t props) { + uint16_t perm = 0; + + if (props & CHAR_PROP_READ) { + switch (read_perm) { + case SECURITY_MODE_OPEN: + perm |= BT_GATT_PERM_READ; + break; + case SECURITY_MODE_ENC_NO_MITM: + perm |= BT_GATT_PERM_READ_ENCRYPT; + break; + case SECURITY_MODE_ENC_WITH_MITM: + perm |= BT_GATT_PERM_READ_AUTHEN; + break; + case SECURITY_MODE_LESC_ENC_WITH_MITM: + perm |= BT_GATT_PERM_READ_LESC; + break; + default: + break; + } + } + + if (props & (CHAR_PROP_WRITE | CHAR_PROP_WRITE_NO_RESPONSE)) { + switch (write_perm) { + case SECURITY_MODE_OPEN: + perm |= BT_GATT_PERM_WRITE; + break; + case SECURITY_MODE_ENC_NO_MITM: + perm |= BT_GATT_PERM_WRITE_ENCRYPT; + break; + case SECURITY_MODE_ENC_WITH_MITM: + perm |= BT_GATT_PERM_WRITE_AUTHEN; + break; + case SECURITY_MODE_LESC_ENC_WITH_MITM: + perm |= BT_GATT_PERM_WRITE_LESC; + break; + default: + break; + } + } + + return perm; +} + +ssize_t bleio_char_read_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { + bleio_characteristic_obj_t *self = attr->user_data; + (void)conn; + return bt_gatt_attr_read(conn, attr, buf, len, offset, + self->current_value, self->current_value_len); +} + +ssize_t bleio_char_write_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) { + bleio_characteristic_obj_t *self = attr->user_data; + (void)flags; + if (offset + len > self->max_length) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + memcpy(self->current_value + offset, buf, len); + if (offset + len > self->current_value_len) { + self->current_value_len = offset + len; + } + + // Notify any observer (e.g., CharacteristicBuffer, PacketBuffer) of the write. + if (self->observer != mp_const_none) { + if (mp_obj_is_type(self->observer, &bleio_characteristic_buffer_type)) { + bleio_characteristic_buffer_extend(MP_OBJ_TO_PTR(self->observer), buf, len); + } else if (mp_obj_is_type(self->observer, &bleio_packet_buffer_type)) { + bleio_packet_buffer_extend(MP_OBJ_TO_PTR(self->observer), conn, buf, len); + } + } + + return len; +} + +void bleio_ccc_changed_cb(const struct bt_gatt_attr *attr, uint16_t value) { + // Track subscription state if needed in the future. + (void)attr; + (void)value; +} + +bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self) { + return self->props; +} + +mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) { + if (self->descriptor_list == NULL) { + return mp_const_empty_tuple; + } + return mp_obj_new_tuple(self->descriptor_list->len, self->descriptor_list->items); +} + +bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) { + return self->service; +} + +bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self) { + return self->uuid; +} + +size_t common_hal_bleio_characteristic_get_max_length(bleio_characteristic_obj_t *self) { + return self->max_length; +} + +size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t *buf, size_t len) { + if (self->service != NULL && self->service->is_remote) { + // Remote characteristic: read via GATT client + bleio_connection_obj_t *connection = MP_OBJ_TO_PTR(self->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + return bleio_gattc_read_sync(connection->connection->conn, + self->handle, buf, len); + } + + // Local characteristic + size_t copy_len = self->current_value_len; + if (copy_len > len) { + copy_len = len; + } + memcpy(buf, self->current_value, copy_len); + return copy_len; +} + +void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, + bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, + bleio_characteristic_properties_t props, + bleio_attribute_security_mode_t read_perm, + bleio_attribute_security_mode_t write_perm, + mp_int_t max_length, bool fixed_length, + mp_buffer_info_t *initial_value_bufinfo, + const char *user_description) { + + self->service = service; + self->uuid = uuid; + self->handle = handle; + self->props = props; + self->read_perm = read_perm; + self->write_perm = write_perm; + self->max_length = max_length; + self->fixed_length = fixed_length; + self->observer = mp_const_none; + // The descriptor list is an mp_obj (GC object). When constructed before + // gc_init() (e.g. the BLE workflow at boot), the GC heap isn't available, + // so leave it NULL and lazily create it on first use. Matches the nordic + // port's handling. + if (gc_alloc_possible()) { + self->descriptor_list = mp_obj_new_list(0, NULL); + } else { + self->descriptor_list = NULL; + } + + // Allocate value buffer + self->current_value = port_malloc(max_length, false); + memset(self->current_value, 0, max_length); + self->current_value_alloc = max_length; + self->current_value_len = 0; + + // Copy initial value if provided + if (initial_value_bufinfo != NULL && initial_value_bufinfo->len > 0) { + size_t len = initial_value_bufinfo->len; + if (len > (size_t)max_length) { + len = max_length; + } + memcpy(self->current_value, initial_value_bufinfo->buf, len); + self->current_value_len = len; + } + + // Convert UUID to Zephyr format + bleio_uuid_to_zephyr(uuid, &self->zephyr_uuid); + + if (service->is_remote) { + // Remote characteristic: just add to the service's list + mp_obj_list_append(MP_OBJ_FROM_PTR(service->characteristic_list), + MP_OBJ_FROM_PTR(self)); + } else { + common_hal_bleio_service_add_characteristic(service, self, + initial_value_bufinfo, user_description); + + // Create a Descriptor object for user_description (CUD 0x2901) + if (user_description != NULL && user_description[0] != '\0') { + bleio_uuid_obj_t *desc_uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); + common_hal_bleio_uuid_construct(desc_uuid, 0x2901, NULL); + + bleio_descriptor_obj_t *descriptor = mp_obj_malloc(bleio_descriptor_obj_t, &bleio_descriptor_type); + + size_t desc_len = strlen(user_description); + mp_buffer_info_t desc_bufinfo = { + .buf = (void *)user_description, + .len = desc_len, + }; + + common_hal_bleio_descriptor_construct( + descriptor, self, desc_uuid, + SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, + desc_len, false, &desc_bufinfo); + + common_hal_bleio_characteristic_add_descriptor(self, descriptor); + } + } +} + +bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self) { + return self->service == NULL; +} + +void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) { + // Nothing to do - service handles unregistration + if (self->current_value != NULL) { + port_free(self->current_value); + self->current_value = NULL; + self->current_value_alloc = 0; + self->current_value_len = 0; + } +} + +// Struct for tracking GATT notification subscriptions on remote characteristics. +typedef struct { + struct bt_gatt_subscribe_params params; + uint16_t value_handle; + uint16_t ccc_handle; + bleio_characteristic_obj_t *characteristic; + volatile bool subscribed; +} zephyr_subscription_t; + +static uint8_t on_gattc_notify(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) { + zephyr_subscription_t *sub = CONTAINER_OF(params, zephyr_subscription_t, params); + if (sub->characteristic != NULL && + sub->characteristic->observer != mp_const_none) { + if (mp_obj_is_type(sub->characteristic->observer, &bleio_characteristic_buffer_type)) { + bleio_characteristic_buffer_extend( + MP_OBJ_TO_PTR(sub->characteristic->observer), data, length); + } else if (mp_obj_is_type(sub->characteristic->observer, &bleio_packet_buffer_type)) { + bleio_packet_buffer_extend( + MP_OBJ_TO_PTR(sub->characteristic->observer), conn, data, length); + } + } + return BT_GATT_ITER_CONTINUE; +} + +void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { + // Only valid for remote characteristics (client-side). + if (self->service == NULL || !self->service->is_remote) { + return; + } + + bleio_connection_obj_t *connection_obj = MP_OBJ_TO_PTR(self->service->connection); + if (connection_obj == NULL || connection_obj->connection == NULL || + connection_obj->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + struct bt_conn *conn = connection_obj->connection->conn; + + if (!notify && !indicate) { + // Unsubscribe from any existing subscription. + // We don't track subscriptions per-characteristic yet, + // so just return for now. + return; + } + + if (self->cccd_handle == 0) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("No CCCD for this Characteristic")); + } + + // Allocate subscription tracking from port heap (won't move on GC). + // Note: Simplified - we allocate a new subscription each time. + // A production implementation would track and reuse subscriptions. + zephyr_subscription_t *sub = port_malloc(sizeof(zephyr_subscription_t), false); + if (sub == NULL) { + mp_raise_msg(&mp_type_MemoryError, NULL); + } + + // Zero-initialize the entire structure so that unset fields + // (subscribe, flags, discover_params, work_q, node) are NULL/0 + // rather than garbage from the heap. bt_gatt_subscribe checks + // subscribe==NULL to decide whether to do a synchronous write. + memset(sub, 0, sizeof(zephyr_subscription_t)); + + sub->characteristic = self; + sub->value_handle = self->handle; + sub->ccc_handle = self->cccd_handle; + sub->subscribed = false; + + sub->params.notify = on_gattc_notify; + sub->params.value_handle = self->handle; + sub->params.ccc_handle = self->cccd_handle; + sub->params.value = notify ? BT_GATT_CCC_NOTIFY : BT_GATT_CCC_INDICATE; + + int err = bt_gatt_subscribe(conn, &sub->params); + if (err != 0) { + port_free(sub); + raise_zephyr_error(err); + } + sub->subscribed = true; +} + +void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { + if (self->service != NULL && self->service->is_remote) { + // Remote characteristic: write via GATT client + bleio_connection_obj_t *connection = MP_OBJ_TO_PTR(self->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + if (self->props & CHAR_PROP_WRITE_NO_RESPONSE) { + int err = bt_gatt_write_without_response( + connection->connection->conn, + self->handle, + bufinfo->buf, bufinfo->len, false); + if (err != 0) { + raise_zephyr_error(err); + } + } else { + bleio_gattc_write_sync(connection->connection->conn, + self->handle, bufinfo->buf, bufinfo->len); + } + return; + } + + // Local characteristic + size_t len = bufinfo->len; + if (len > self->max_length) { + len = self->max_length; + } + memcpy(self->current_value, bufinfo->buf, len); + self->current_value_len = len; + + // If NOTIFY and service is registered, send notification + if ((self->props & CHAR_PROP_NOTIFY) && self->service != NULL && + self->service->registered) { + bt_gatt_notify(NULL, &self->service->attrs[self->value_attr_index], + self->current_value, self->current_value_len); + } +} + +void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, + bleio_descriptor_obj_t *descriptor) { + if (self->descriptor_list == NULL) { + self->descriptor_list = mp_obj_new_list(0, NULL); + } + mp_obj_list_append(MP_OBJ_FROM_PTR(self->descriptor_list), + MP_OBJ_FROM_PTR(descriptor)); + // Descriptors added after characteristic construction would need + // service re-registration; for now the common case is handled by + // Service.add_characteristic which adds descriptors at registration time. +} + +void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer) { + self->observer = observer; +} + +void bleio_characteristic_clear_observer(bleio_characteristic_obj_t *self) { + self->observer = mp_const_none; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Characteristic.h b/ports/zephyr-cp/common-hal/_bleio/Characteristic.h new file mode 100644 index 00000000000..f4a578c888a --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.h @@ -0,0 +1,63 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" +#include "py/objlist.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "shared-module/_bleio/Characteristic.h" +#include "common-hal/_bleio/Descriptor.h" +#include "common-hal/_bleio/Service.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct _bleio_characteristic_obj { + mp_obj_base_t base; + bleio_service_obj_t *service; + bleio_uuid_obj_t *uuid; + mp_obj_t observer; + uint8_t *current_value; + uint16_t current_value_len; + uint16_t current_value_alloc; + uint16_t max_length; + uint16_t def_handle; + uint16_t handle; + bleio_characteristic_properties_t props; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; + mp_obj_list_t *descriptor_list; + uint16_t user_desc_handle; + uint16_t cccd_handle; + uint16_t sccd_handle; + bool fixed_length; + // Zephyr GATT server fields: + struct bt_gatt_chrc zephyr_chrc; + struct bt_uuid_128 zephyr_uuid; + struct bt_gatt_ccc_managed_user_data zephyr_ccc; + size_t value_attr_index; // index in service attrs for notify +} bleio_characteristic_obj_t; + +void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer); +void bleio_characteristic_clear_observer(bleio_characteristic_obj_t *self); + +// Callbacks used by Service.c when building GATT attr table +ssize_t bleio_char_read_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset); +ssize_t bleio_char_write_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, const void *buf, uint16_t len, + uint16_t offset, uint8_t flags); +void bleio_ccc_changed_cb(const struct bt_gatt_attr *attr, uint16_t value); +ssize_t bleio_ccc_write_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, uint16_t value); + +// Permission mapping helper +uint16_t bleio_security_to_zephyr_perm( + bleio_attribute_security_mode_t read_perm, + bleio_attribute_security_mode_t write_perm, + bleio_characteristic_properties_t props); diff --git a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c new file mode 100644 index 00000000000..9ce48ac97c4 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c @@ -0,0 +1,136 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include + +#include + +#include "py/runtime.h" +#include "py/stream.h" + +#include "shared/runtime/interrupt_char.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Connection.h" +#include "shared-bindings/_bleio/CharacteristicBuffer.h" + +#include "supervisor/shared/tick.h" + +#include "common-hal/_bleio/CharacteristicBuffer.h" +#include "common-hal/_bleio/Characteristic.h" + +// Zephyr's ring_buf is safe for single-producer/single-consumer without +// locks. The GATT callbacks (system workqueue) are the sole producer; +// the CircuitPython VM (main thread) is the sole consumer. + +// Called from Zephyr GATT callbacks (system workqueue context). +void bleio_characteristic_buffer_extend(bleio_characteristic_buffer_obj_t *self, + const uint8_t *data, size_t len) { + if (self->watch_for_interrupt_char) { + for (size_t i = 0; i < len; i++) { + if (data[i] == mp_interrupt_char) { + mp_sched_keyboard_interrupt(); + ring_buf_reset(&self->ringbuf); + } else { + ring_buf_put(&self->ringbuf, &data[i], 1); + } + } + } else { + ring_buf_put(&self->ringbuf, data, len); + } +} + +void _common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, + bleio_characteristic_obj_t *characteristic, + mp_float_t timeout, + uint8_t *buffer, size_t buffer_size, + void *static_handler_entry, + bool watch_for_interrupt_char) { + + self->characteristic = characteristic; + self->timeout_ms = timeout * 1000; + self->watch_for_interrupt_char = watch_for_interrupt_char; + self->ringbuf_data = buffer; + ring_buf_init(&self->ringbuf, buffer_size, buffer); + + // Set ourselves as the characteristic's observer so we receive + // incoming writes (local) and notifications (remote). + bleio_characteristic_set_observer(characteristic, MP_OBJ_FROM_PTR(self)); +} + +// Assumes that timeout and buffer_size have been validated before call. +void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, + bleio_characteristic_obj_t *characteristic, + mp_float_t timeout, + size_t buffer_size) { + uint8_t *buffer = m_malloc_without_collect(buffer_size); + _common_hal_bleio_characteristic_buffer_construct(self, characteristic, timeout, + buffer, buffer_size, NULL, false); +} + +uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, + uint8_t *data, size_t len, int *errcode) { + uint64_t start_ticks = supervisor_ticks_ms64(); + + // Wait for all bytes received or timeout + while ((ring_buf_size_get(&self->ringbuf) < len) && + (supervisor_ticks_ms64() - start_ticks < self->timeout_ms)) { + RUN_BACKGROUND_TASKS; + // Allow user to break out of a timeout with a KeyboardInterrupt. + if (mp_hal_is_interrupted()) { + return 0; + } + } + + return ring_buf_get(&self->ringbuf, data, len); +} + +uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available( + bleio_characteristic_buffer_obj_t *self) { + return ring_buf_size_get(&self->ringbuf); +} + +void common_hal_bleio_characteristic_buffer_clear_rx_buffer( + bleio_characteristic_buffer_obj_t *self) { + ring_buf_reset(&self->ringbuf); +} + +bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { + return self->characteristic == NULL; +} + +void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) { + if (common_hal_bleio_characteristic_buffer_deinited(self)) { + return; + } + bleio_characteristic_clear_observer(self->characteristic); + self->characteristic = NULL; + // ringbuf_data was allocated with m_malloc_without_collect; free it. + m_free(self->ringbuf_data); + self->ringbuf_data = NULL; +} + +bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self) { + bleio_characteristic_obj_t *characteristic = self->characteristic; + if (characteristic == NULL || characteristic->service == NULL) { + return false; + } + + if (!characteristic->service->is_remote) { + // Local service: we're always "connected" as long as the service exists. + return true; + } + + // Remote service: check if the connection is still active. + if (characteristic->service->connection == mp_const_none) { + return false; + } + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(characteristic->service->connection); + return common_hal_bleio_connection_get_connected(connection); +} diff --git a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h new file mode 100644 index 00000000000..85a5d253be2 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +#include "py/obj.h" +#include "shared-bindings/_bleio/Characteristic.h" + +typedef struct { + mp_obj_base_t base; + bleio_characteristic_obj_t *characteristic; + uint32_t timeout_ms; + struct ring_buf ringbuf; + uint8_t *ringbuf_data; + bool watch_for_interrupt_char; +} bleio_characteristic_buffer_obj_t; + +// Called from GATT callbacks (system workqueue context) to push +// data into the CharacteristicBuffer ring buffer. +void bleio_characteristic_buffer_extend(bleio_characteristic_buffer_obj_t *self, + const uint8_t *data, size_t len); diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.c b/ports/zephyr-cp/common-hal/_bleio/Connection.c new file mode 100644 index 00000000000..12b2a8efe5f --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.c @@ -0,0 +1,738 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include + +#include +#include +#include +#include + +#include "py/runtime.h" +#include "shared/runtime/interrupt_char.h" +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Connection.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" +#include "common-hal/_bleio/__init__.h" +#include "common-hal/_bleio/Characteristic.h" +#include "supervisor/port_heap.h" + +// Discovery context passed through Zephyr callbacks. +typedef struct { + volatile bool done; + volatile int err; +} discovery_context_t; + +// Convert a Zephyr bt_uuid to a CircuitPython bleio UUID object. +// Must be called OUTSIDE Zephyr callback context. +static bleio_uuid_obj_t *bleio_uuid_from_zephyr(const struct bt_uuid *zuuid) { + bleio_uuid_obj_t *uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); + if (zuuid->type == BT_UUID_TYPE_16) { + common_hal_bleio_uuid_construct(uuid, BT_UUID_16(zuuid)->val, NULL); + } else { + // Both Zephyr and CP store UUID bytes in little-endian order. + const struct bt_uuid_128 *uuid128 = BT_UUID_128(zuuid); + common_hal_bleio_uuid_construct(uuid, + (uuid128->val[13] << 8) | uuid128->val[12], uuid128->val); + } + return uuid; +} + +// Temporary storage for discovered services before creating CP objects. +// Each node is port_malloc'd in the callback and appended to a sys_slist. +typedef struct { + sys_snode_t node; + struct bt_uuid_128 uuid; + uint16_t start_handle; + uint16_t end_handle; +} discovered_service_t; + +// Temporary storage for discovered characteristics before creating CP objects. +typedef struct { + sys_snode_t node; + struct bt_uuid_128 uuid; + uint16_t value_handle; + uint16_t decl_handle; + uint8_t properties; +} discovered_char_t; + +// Temporary storage for discovered descriptors. +typedef struct { + sys_snode_t node; + struct bt_uuid_128 uuid; + uint16_t handle; +} discovered_desc_t; + +// File-scope discovery state for synchronous blocking. +static discovery_context_t *active_discovery_ctx; +static sys_slist_t discovered_list; +static struct bt_gatt_discover_params discovery_params; + +// Called from the disconnect callback (BT workqueue context) to abort any +// in-flight GATT discovery. Without this the main thread's spin loop would +// hang waiting for a callback that will never come, and the caller would then +// NULL-dereference the now-cleared connection in bt_gatt_discover(). +void bleio_connection_discovery_abort(void) { + discovery_context_t *ctx = active_discovery_ctx; + if (ctx != NULL) { + ctx->err = -ENOTCONN; + ctx->done = true; + } +} + +static uint8_t on_service_discovered(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + discovery_context_t *ctx = active_discovery_ctx; + + if (attr == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + discovered_service_t *ds = port_malloc(sizeof(discovered_service_t), false); + if (ds == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + struct bt_gatt_service_val *svc_val = (struct bt_gatt_service_val *)attr->user_data; + ds->start_handle = attr->handle; + ds->end_handle = svc_val->end_handle; + + // Copy UUID into our storage + if (svc_val->uuid->type == BT_UUID_TYPE_16) { + ds->uuid.uuid.type = BT_UUID_TYPE_16; + ((struct bt_uuid_16 *)&ds->uuid)->val = BT_UUID_16(svc_val->uuid)->val; + } else { + memcpy(&ds->uuid, svc_val->uuid, sizeof(struct bt_uuid_128)); + } + + sys_slist_append(&discovered_list, &ds->node); + + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t on_characteristic_discovered(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + discovery_context_t *ctx = active_discovery_ctx; + + if (attr == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + discovered_char_t *dc = port_malloc(sizeof(discovered_char_t), false); + if (dc == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; + dc->value_handle = chrc->value_handle; + dc->decl_handle = attr->handle; + dc->properties = chrc->properties; + + // Copy UUID into our storage + if (chrc->uuid->type == BT_UUID_TYPE_16) { + dc->uuid.uuid.type = BT_UUID_TYPE_16; + ((struct bt_uuid_16 *)&dc->uuid)->val = BT_UUID_16(chrc->uuid)->val; + } else { + memcpy(&dc->uuid, chrc->uuid, sizeof(struct bt_uuid_128)); + } + + sys_slist_append(&discovered_list, &dc->node); + + return BT_GATT_ITER_CONTINUE; +} + +// Pairing: characteristic pointer with its declaration handle for descriptor discovery. +typedef struct { + bleio_characteristic_obj_t *characteristic; + uint16_t decl_handle; +} char_with_decl_t; + +// Forward declaration for use by descriptor discovery. +static void free_discovered_list(void); +static void bleio_discovery_check_connected(struct bt_conn *conn, + discovery_context_t *ctx); + +// Callback for descriptor discovery. +static uint8_t on_descriptor_discovered(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + discovery_context_t *ctx = active_discovery_ctx; + + if (attr == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + discovered_desc_t *dd = port_malloc(sizeof(discovered_desc_t), false); + if (dd == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + dd->handle = attr->handle; + + // Copy UUID into our storage + if (attr->uuid->type == BT_UUID_TYPE_16) { + dd->uuid.uuid.type = BT_UUID_TYPE_16; + ((struct bt_uuid_16 *)&dd->uuid)->val = BT_UUID_16(attr->uuid)->val; + } else { + memcpy(&dd->uuid, attr->uuid, sizeof(struct bt_uuid_128)); + } + + sys_slist_append(&discovered_list, &dd->node); + + return BT_GATT_ITER_CONTINUE; +} + +// Create descriptors from discovered_list and add them to the characteristic. +// Called OUTSIDE the Zephyr callback context. Drains and frees all nodes. +static void create_descriptors_from_discovered(bleio_characteristic_obj_t *characteristic) { + sys_snode_t *node; + while ((node = sys_slist_get(&discovered_list)) != NULL) { + discovered_desc_t *dd = CONTAINER_OF(node, discovered_desc_t, node); + + bleio_uuid_obj_t *uuid = bleio_uuid_from_zephyr(&dd->uuid.uuid); + + // Remember handles for certain well-known descriptors. + if (dd->uuid.uuid.type == BT_UUID_TYPE_16) { + switch (((struct bt_uuid_16 *)&dd->uuid)->val) { + case 0x2902: + characteristic->cccd_handle = dd->handle; + break; + case 0x2903: + characteristic->sccd_handle = dd->handle; + break; + case 0x2901: + characteristic->user_desc_handle = dd->handle; + break; + default: + break; + } + } + + bleio_descriptor_obj_t *descriptor = + mp_obj_malloc(bleio_descriptor_obj_t, &bleio_descriptor_type); + + // Remote descriptors: set characteristic and UUID only. + // Reads/writes go over GATT via the handle. + descriptor->characteristic = characteristic; + descriptor->uuid = uuid; + descriptor->handle = dd->handle; + descriptor->read_perm = SECURITY_MODE_OPEN; + descriptor->write_perm = SECURITY_MODE_OPEN; + descriptor->max_length = 20; + descriptor->fixed_length = false; + descriptor->value = m_malloc(20); + memset(descriptor->value, 0, 20); + descriptor->value_length = 0; + + common_hal_bleio_characteristic_add_descriptor(characteristic, descriptor); + + port_free(dd); + } +} + +// Discover descriptors for a single characteristic. +static void discover_descriptors_for_characteristic(struct bt_conn *conn, + discovery_context_t *ctx, bleio_characteristic_obj_t *characteristic, + uint16_t end_handle) { + // Bail cleanly if the link dropped before this phase began. + bleio_discovery_check_connected(conn, ctx); + uint16_t start = characteristic->handle + 1; + if (start > end_handle) { + return; + } + + sys_slist_init(&discovered_list); + ctx->done = false; + ctx->err = 0; + + memset(&discovery_params, 0, sizeof(discovery_params)); + discovery_params.uuid = NULL; + discovery_params.start_handle = start; + discovery_params.end_handle = end_handle; + discovery_params.type = BT_GATT_DISCOVER_DESCRIPTOR; + discovery_params.func = on_descriptor_discovered; + + int err = bt_gatt_discover(conn, &discovery_params); + if (err != 0) { + free_discovered_list(); + if (err == -ENOENT) { + return; + } + raise_zephyr_error(err); + } + + while (!ctx->done) { + RUN_BACKGROUND_TASKS; + } + + // The link may have dropped while we were waiting. + bleio_discovery_check_connected(conn, ctx); + + create_descriptors_from_discovered(characteristic); +} + +// Create CircuitPython characteristic objects from the discovered_list. +// Called OUTSIDE the Zephyr callback context so MP allocations are safe. +// Drains and frees all nodes from the list. +// Returns the number of characteristics created and fills the chars_out array +// (which must be large enough). +static size_t create_characteristics_from_discovered(bleio_service_obj_t *service, + char_with_decl_t *chars_out, size_t max_chars) { + size_t count = 0; + sys_snode_t *node; + while ((node = sys_slist_get(&discovered_list)) != NULL) { + discovered_char_t *dc = CONTAINER_OF(node, discovered_char_t, node); + + bleio_uuid_obj_t *uuid = bleio_uuid_from_zephyr(&dc->uuid.uuid); + + bleio_characteristic_properties_t props = 0; + if (dc->properties & BT_GATT_CHRC_BROADCAST) { + props |= CHAR_PROP_BROADCAST; + } + if (dc->properties & BT_GATT_CHRC_READ) { + props |= CHAR_PROP_READ; + } + if (dc->properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) { + props |= CHAR_PROP_WRITE_NO_RESPONSE; + } + if (dc->properties & BT_GATT_CHRC_WRITE) { + props |= CHAR_PROP_WRITE; + } + if (dc->properties & BT_GATT_CHRC_NOTIFY) { + props |= CHAR_PROP_NOTIFY; + } + if (dc->properties & BT_GATT_CHRC_INDICATE) { + props |= CHAR_PROP_INDICATE; + } + + bleio_characteristic_obj_t *characteristic = + mp_obj_malloc(bleio_characteristic_obj_t, &bleio_characteristic_type); + + // Use max_length=20 for remote chars - reads go over the wire. + common_hal_bleio_characteristic_construct( + characteristic, service, + dc->value_handle, uuid, props, + SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, + 20, false, NULL, NULL); + + if (count < max_chars) { + chars_out[count].characteristic = characteristic; + chars_out[count].decl_handle = dc->decl_handle; + } + count++; + + port_free(dc); + } + return count; +} + +// Helper to drain and free all nodes from the discovered_list. +static void free_discovered_list(void) { + sys_snode_t *node; + while ((node = sys_slist_get(&discovered_list)) != NULL) { + port_free(node); + } +} + +// The link dropped during discovery: the disconnect callback cleared +// connection->conn (so a subsequent bt_gatt_discover() would NULL-deref, since +// CONFIG_ASSERT is off) and/or aborted the active discovery (ctx->err set). +// Stop discovery cleanly with a "Not connected" exception instead of +// crashing or hanging on the spin loop. +static void bleio_discovery_check_connected(struct bt_conn *conn, + discovery_context_t *ctx) { + if (conn == NULL || ctx->err != 0) { + free_discovered_list(); + active_discovery_ctx = NULL; + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } +} + +// Discover characteristics for a single remote service. +static void discover_characteristics_for_service(struct bt_conn *conn, + discovery_context_t *ctx, bleio_service_obj_t *service) { + // Bail cleanly if the link dropped before this phase began. + bleio_discovery_check_connected(conn, ctx); + // Need at least 2 handles: one for the service declaration, one for a characteristic + if (service->end_handle <= service->start_handle) { + return; + } + + sys_slist_init(&discovered_list); + ctx->done = false; + ctx->err = 0; + + memset(&discovery_params, 0, sizeof(discovery_params)); + discovery_params.uuid = NULL; + discovery_params.start_handle = service->start_handle + 1; + discovery_params.end_handle = service->end_handle; + discovery_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + discovery_params.func = on_characteristic_discovered; + + int err = bt_gatt_discover(conn, &discovery_params); + if (err != 0) { + free_discovered_list(); + // -ENOENT means no characteristics found in the range, which is fine. + if (err == -ENOENT) { + return; + } + raise_zephyr_error(err); + } + + while (!ctx->done) { + RUN_BACKGROUND_TASKS; + } + + // The link may have dropped while we were waiting. + bleio_discovery_check_connected(conn, ctx); + + // Create CP objects outside of callback context where MP allocations are safe. + // This drains and frees the list nodes. + char_with_decl_t chars[16]; + size_t num_chars = create_characteristics_from_discovered(service, chars, 16); + + // Discover descriptors for each characteristic. + // The descriptor range for char[i] is from char[i].handle+1 to + // char[i+1].decl_handle-1 (or service.end_handle for the last). + for (size_t i = 0; i < num_chars && i < 16; i++) { + uint16_t desc_end; + if (i + 1 < num_chars) { + desc_end = chars[i + 1].decl_handle - 1; + } else { + desc_end = service->end_handle; + } + discover_descriptors_for_characteristic(conn, ctx, + chars[i].characteristic, desc_end); + } +} + +// ===== PAIRING / BONDING ===== + +// Auth info callbacks to track pairing completion/failure +static struct bt_conn_auth_info_cb auth_info_cb; +static bool auth_info_cb_registered = false; + +static void on_pairing_complete(struct bt_conn *conn, bool bonded) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn == conn) { + bleio_connections[i].pair_status = PAIR_PAIRED; + bleio_connections[i].sec_err = 0; + break; + } + } +} + +static void on_pairing_failed(struct bt_conn *conn, enum bt_security_err reason) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn == conn) { + bleio_connections[i].pair_status = PAIR_NOT_PAIRED; + bleio_connections[i].sec_err = (uint8_t)reason; + break; + } + } +} + +void bleio_connection_register_auth_callbacks(void) { + if (!auth_info_cb_registered) { + auth_info_cb.pairing_complete = on_pairing_complete; + auth_info_cb.pairing_failed = on_pairing_failed; + bt_conn_auth_info_cb_register(&auth_info_cb); + auth_info_cb_registered = true; + } +} + +void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) { + (void)bond; // Bonding is enabled globally via CONFIG_BT_BONDABLE=y + + if (self == NULL || self->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + // Already paired? + if (self->pair_status == PAIR_PAIRED) { + return; + } + + // Ensure auth callbacks are registered + bleio_connection_register_auth_callbacks(); + + self->pair_status = PAIR_WAITING; + self->sec_err = 0; + + int err = bt_conn_set_security(self->conn, BT_SECURITY_L2); + if (err != 0) { + self->pair_status = PAIR_NOT_PAIRED; + raise_zephyr_error(err); + } + + // bt_conn_set_security may return 0 immediately if already encrypted + // (e.g., reconnection with stored bond keys). Check current security level. + if (bt_conn_get_security(self->conn) > BT_SECURITY_L1) { + self->pair_status = PAIR_PAIRED; + return; + } + + // Wait for pairing to complete. Zephyr's SMP reports each attempt via + // pairing_failed before auto-restarting security (smp.c), so a stale-bond + // retry shows up as an intermediate BT_SECURITY_ERR_PIN_OR_KEY_MISSING + // followed by a fresh attempt that can succeed. Ride through those and + // rely on Zephyr to signal the end: success (PAIR_PAIRED), SMP_TIMEOUT + // dropping the link (observed as conn == NULL), or a user interrupt. + while (self->pair_status != PAIR_PAIRED + && self->conn != NULL + && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + } + + if (mp_hal_is_interrupted()) { + if (self->conn != NULL) { + bt_conn_auth_cancel(self->conn); + } + self->pair_status = PAIR_NOT_PAIRED; + return; + } + + if (self->pair_status == PAIR_PAIRED) { + return; + } + + // Reuse the messages shared with the nordic _bleio implementation + // (check_sec_status). A dropped link clears sec_err, so it falls through + // to the "unspecified issue" message alongside the explicit UNSPECIFIED + // error code rather than introducing a zephyr-specific "Pairing failed" + // string. + uint8_t sec_err_code = self->sec_err; + if (sec_err_code == BT_SECURITY_ERR_UNSPECIFIED || sec_err_code == 0) { + mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. The pairing request on the other device may have been declined or ignored.")); + } else { + mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unknown security error: 0x%04x"), sec_err_code); + } +} + +void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) { + if (self == NULL || self->conn == NULL) { + return; + } + + int err = bt_conn_disconnect(self->conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err != 0 && err != -ENOTCONN) { + raise_zephyr_error(err); + } + + // The connection may now be disconnecting; force connections tuple rebuild. + common_hal_bleio_adapter_obj.connection_objs = NULL; +} + +bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) { + if (self == NULL || self->connection == NULL) { + return false; + } + + bleio_connection_internal_t *connection = self->connection; + if (connection->conn == NULL) { + return false; + } + + struct bt_conn_info info; + if (bt_conn_get_info(connection->conn, &info) != 0) { + return false; + } + + return info.state == BT_CONN_STATE_CONNECTED || info.state == BT_CONN_STATE_DISCONNECTING; +} + +mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_internal_t *self) { + if (self == NULL || self->conn == NULL) { + return 20; + } + + uint16_t mtu = bt_gatt_get_mtu(self->conn); + if (mtu < 3) { + return 20; + } + return mtu - 3; +} + +bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { + if (self == NULL || self->connection == NULL) { + return false; + } + return self->connection->pair_status == PAIR_PAIRED; +} + +// Authenticated (MITM-protected) pairing - numeric comparison - is implemented on the +// espressif port only. This port can't tell a "Just Works" bond from an authenticated +// one, so report the conservative answer rather than a guarantee it can't make. +bool common_hal_bleio_connection_get_authenticated(bleio_connection_obj_t *self) { + return false; +} + +mp_obj_t common_hal_bleio_connection_get_numeric_comparison(bleio_connection_obj_t *self) { + return mp_const_none; +} + +void common_hal_bleio_connection_confirm_pairing(bleio_connection_obj_t *self, bool accept) { + mp_raise_NotImplementedError(NULL); +} + +mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist) { + bleio_connection_internal_t *connection = self->connection; + if (connection == NULL || connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + discovery_context_t ctx; + ctx.done = false; + ctx.err = 0; + + active_discovery_ctx = &ctx; + sys_slist_init(&discovered_list); + + // Create the result list for service objects. + mp_obj_list_t *service_list = mp_obj_new_list(0, NULL); + + // Discover primary services (callback appends nodes to discovered_list). + // When a whitelist is given, pass each UUID to Zephyr so filtering happens + // on the remote device — only matching services are returned. + if (service_uuids_whitelist == mp_const_none) { + memset(&discovery_params, 0, sizeof(discovery_params)); + discovery_params.uuid = NULL; + discovery_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discovery_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discovery_params.type = BT_GATT_DISCOVER_PRIMARY; + discovery_params.func = on_service_discovered; + + int err = bt_gatt_discover(connection->conn, &discovery_params); + if (err != 0) { + free_discovered_list(); + active_discovery_ctx = NULL; + raise_zephyr_error(err); + } + + while (!ctx.done) { + RUN_BACKGROUND_TASKS; + } + + // The link may have dropped during primary discovery. + bleio_discovery_check_connected(connection->conn, &ctx); + } else { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); + mp_obj_t uuid_obj; + while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + bleio_uuid_obj_t *cp_uuid = mp_arg_validate_type(uuid_obj, &bleio_uuid_type, MP_QSTR_uuid); + + memset(&discovery_params, 0, sizeof(discovery_params)); + discovery_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discovery_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discovery_params.type = BT_GATT_DISCOVER_PRIMARY; + discovery_params.func = on_service_discovered; + + // Set the Zephyr UUID filter. Stack variables are safe because + // bt_gatt_discover is synchronous (we spin until ctx.done). + union { + struct bt_uuid_16 u16; + struct bt_uuid_128 u128; + } z_uuid; + if (cp_uuid->size == BT_UUID_SIZE_16) { + z_uuid.u16.uuid.type = BT_UUID_TYPE_16; + z_uuid.u16.val = cp_uuid->uuid16; + discovery_params.uuid = &z_uuid.u16.uuid; + } else { + z_uuid.u128.uuid.type = BT_UUID_TYPE_128; + memcpy(z_uuid.u128.val, cp_uuid->uuid128, 16); + discovery_params.uuid = &z_uuid.u128.uuid; + } + + ctx.done = false; + ctx.err = 0; + + int err = bt_gatt_discover(connection->conn, &discovery_params); + if (err != 0) { + free_discovered_list(); + active_discovery_ctx = NULL; + raise_zephyr_error(err); + } + + while (!ctx.done) { + RUN_BACKGROUND_TASKS; + } + + // The link may have dropped during this UUID's discovery; stop + // before the next iteration clears ctx.err and crashes on a NULL conn. + bleio_discovery_check_connected(connection->conn, &ctx); + } + } + + // Create CP service objects outside callback context where MP allocations are safe. + // Drain and free the discovered service nodes. + mp_obj_list_t *result_list = service_list; + sys_snode_t *snode; + while ((snode = sys_slist_get(&discovered_list)) != NULL) { + discovered_service_t *ds = CONTAINER_OF(snode, discovered_service_t, node); + bleio_uuid_obj_t *uuid = bleio_uuid_from_zephyr(&ds->uuid.uuid); + bleio_service_obj_t *service = mp_obj_malloc(bleio_service_obj_t, &bleio_service_type); + common_hal_bleio_service_from_remote_service(service, self, uuid, false); + service->start_handle = ds->start_handle; + service->end_handle = ds->end_handle; + mp_obj_list_append(MP_OBJ_FROM_PTR(service_list), MP_OBJ_FROM_PTR(service)); + port_free(ds); + } + + // Discover characteristics for each service + for (size_t i = 0; i < result_list->len; i++) { + bleio_service_obj_t *svc = MP_OBJ_TO_PTR(result_list->items[i]); + if (svc->start_handle < svc->end_handle) { + // discover_characteristics_for_service re-checks, but guard here + // too so we don't enter the phase after a mid-loop disconnect. + bleio_discovery_check_connected(connection->conn, &ctx); + discover_characteristics_for_service(connection->conn, &ctx, svc); + } + } + + active_discovery_ctx = NULL; + + return mp_obj_new_tuple(result_list->len, result_list->items); +} + +mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval) { + mp_raise_NotImplementedError(NULL); +} + +mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection) { + if (connection == NULL) { + return mp_const_none; + } + + if (connection->connection_obj != mp_const_none) { + return connection->connection_obj; + } + + bleio_connection_obj_t *connection_obj = mp_obj_malloc(bleio_connection_obj_t, &bleio_connection_type); + connection_obj->connection = connection; + connection_obj->disconnect_reason = 0; + connection->connection_obj = MP_OBJ_FROM_PTR(connection_obj); + + return connection->connection_obj; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.h b/ports/zephyr-cp/common-hal/_bleio/Connection.h new file mode 100644 index 00000000000..9565fd31b8b --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.h @@ -0,0 +1,40 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" + +struct bt_conn; + +typedef enum { + PAIR_NOT_PAIRED, + PAIR_WAITING, + PAIR_PAIRED, +} pair_status_t; + +typedef struct { + struct bt_conn *conn; + mp_obj_t connection_obj; + volatile pair_status_t pair_status; + uint8_t sec_err; // Security error code from pairing attempt + // True if user code initiated this connection or accepted it with its own + // advertising. bleio_user_reset() disconnects only these; the BLE workflow + // connection is not user-owned and survives VM restarts. + bool user_owned; +} bleio_connection_internal_t; + +typedef struct { + mp_obj_base_t base; + bleio_connection_internal_t *connection; + uint8_t disconnect_reason; +} bleio_connection_obj_t; + +mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); +void bleio_connection_register_auth_callbacks(void); diff --git a/ports/zephyr-cp/common-hal/_bleio/Descriptor.c b/ports/zephyr-cp/common-hal/_bleio/Descriptor.c new file mode 100644 index 00000000000..a2219d8b5cd --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.c @@ -0,0 +1,109 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "common-hal/_bleio/__init__.h" +#include "common-hal/_bleio/Characteristic.h" +#include "common-hal/_bleio/Connection.h" +#include "supervisor/port_heap.h" + +void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, + bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, + bleio_attribute_security_mode_t read_perm, + bleio_attribute_security_mode_t write_perm, + mp_int_t max_length, bool fixed_length, + mp_buffer_info_t *initial_value_bufinfo) { + + self->characteristic = characteristic; + self->uuid = uuid; + self->read_perm = read_perm; + self->write_perm = write_perm; + self->max_length = max_length; + self->fixed_length = fixed_length; + + // Allocate value buffer + self->value = m_malloc(max_length); + memset(self->value, 0, max_length); + self->value_length = 0; + + // Copy initial value if provided + if (initial_value_bufinfo != NULL && initial_value_bufinfo->len > 0) { + size_t len = initial_value_bufinfo->len; + if (len > (size_t)max_length) { + len = max_length; + } + memcpy(self->value, initial_value_bufinfo->buf, len); + self->value_length = len; + } + + // Convert UUID to Zephyr format + bleio_uuid_to_zephyr(uuid, &self->zephyr_uuid); +} + +bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { + return self->uuid; +} + +bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self) { + return (bleio_characteristic_obj_t *)self->characteristic; +} + +static bool descriptor_is_remote(bleio_descriptor_obj_t *self) { + return self->characteristic != NULL && + self->characteristic->service != NULL && + self->characteristic->service->is_remote; +} + +size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t *buf, size_t len) { + if (descriptor_is_remote(self)) { + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(self->characteristic->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + return bleio_gattc_read_sync(connection->connection->conn, + self->handle, buf, len); + } + + // Local descriptor + size_t copy_len = self->value_length; + if (copy_len > len) { + copy_len = len; + } + memcpy(buf, self->value, copy_len); + return copy_len; +} + +void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) { + if (descriptor_is_remote(self)) { + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(self->characteristic->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + bleio_gattc_write_sync(connection->connection->conn, + self->handle, bufinfo->buf, bufinfo->len); + return; + } + + // Local descriptor + size_t len = bufinfo->len; + if (len > self->max_length) { + len = self->max_length; + } + memcpy(self->value, bufinfo->buf, len); + self->value_length = len; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Descriptor.h b/ports/zephyr-cp/common-hal/_bleio/Descriptor.h new file mode 100644 index 00000000000..b6d3ab4452e --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.h @@ -0,0 +1,31 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "common-hal/_bleio/UUID.h" + +// Forward declaration to break circular dependency +struct _bleio_characteristic_obj; + +typedef struct _bleio_descriptor_obj { + mp_obj_base_t base; + bleio_uuid_obj_t *uuid; + uint16_t handle; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; + uint16_t max_length; + bool fixed_length; + uint8_t *value; + uint16_t value_length; + struct _bleio_characteristic_obj *characteristic; + struct bt_uuid_128 zephyr_uuid; +} bleio_descriptor_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c new file mode 100644 index 00000000000..6e3f42a6729 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c @@ -0,0 +1,629 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" + +#include "shared/runtime/interrupt_char.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Connection.h" +#include "shared-bindings/_bleio/PacketBuffer.h" +#include "shared-bindings/microcontroller/__init__.h" + +#include "supervisor/shared/tick.h" +#include "supervisor/port_heap.h" + +#include "common-hal/_bleio/Characteristic.h" +#include "common-hal/_bleio/PacketBuffer.h" +#include "common-hal/_bleio/Adapter.h" +#include "common-hal/_bleio/Connection.h" +#include "common-hal/_bleio/__init__.h" +#include "bindings/zephyr_kernel/__init__.h" + +// Zephyr's ring_buf is safe for single-producer/single-consumer without +// locks. The GATT callbacks (system workqueue) are the sole producer of +// incoming data; the CircuitPython VM (main thread) is the sole consumer. + +// Forward declarations. +static bool conn_is_valid(bleio_packet_buffer_obj_t *self); +static void packet_buffer_send_work_handler(struct k_work *work); +static void notify_complete_cb(struct bt_conn *conn, void *user_data); + +// Called from Zephyr GATT callbacks (system workqueue context). +// Wraps incoming data with a uint16_t length prefix and pushes into ringbuf. +// Tracks the first connection so notifications target the right peer. +void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, + struct bt_conn *conn, const uint8_t *data, size_t len) { + // Track the first/current connection for notifications. + if (conn != NULL) { + conn_is_valid(self); // clear stale conn if needed + if (self->conn == NULL) { + self->conn = conn; + } + } + if (len > UINT16_MAX) { + return; + } + + uint16_t packet_len = (uint16_t)len; + size_t total = sizeof(uint16_t) + len; + + // If the packet doesn't fit, drop oldest packets to make room. + while (ring_buf_space_get(&self->ringbuf) < total) { + uint16_t old_len; + if (ring_buf_size_get(&self->ringbuf) < sizeof(uint16_t)) { + // Not enough data for a length prefix, just reset. + ring_buf_reset(&self->ringbuf); + break; + } + uint32_t peeked = ring_buf_peek(&self->ringbuf, (uint8_t *)&old_len, sizeof(uint16_t)); + if (peeked < sizeof(uint16_t)) { + ring_buf_reset(&self->ringbuf); + break; + } + // Discard the length prefix + ring_buf_get(&self->ringbuf, (uint8_t *)&old_len, sizeof(uint16_t)); + // Discard the packet data + size_t to_discard = old_len; + if (to_discard > ring_buf_size_get(&self->ringbuf)) { + to_discard = ring_buf_size_get(&self->ringbuf); + } + uint8_t discard_buf[32]; + while (to_discard > 0) { + size_t chunk = to_discard > sizeof(discard_buf) ? sizeof(discard_buf) : to_discard; + ring_buf_get(&self->ringbuf, discard_buf, chunk); + to_discard -= chunk; + } + } + + ring_buf_put(&self->ringbuf, (uint8_t *)&packet_len, sizeof(uint16_t)); + ring_buf_put(&self->ringbuf, data, len); + + // Wake the VM background task so it drains the ring buffer promptly. + bleio_request_bluetooth_background(); +} + +void bleio_packet_buffer_set_conn(bleio_packet_buffer_obj_t *self, + struct bt_conn *conn) { + self->conn = conn; +} + +// Returns true if the tracked connection is still connected. +// Clears self->conn if the connection is stale. +static bool conn_is_valid(bleio_packet_buffer_obj_t *self) { + if (self->conn == NULL) { + return false; + } + struct bt_conn_info info; + if (bt_conn_get_info(self->conn, &info) != 0 || + info.state == BT_CONN_STATE_DISCONNECTED) { + self->conn = NULL; + return false; + } + return true; +} + +// Completion callback for bt_gatt_notify_cb. Runs on the system workqueue (per +// the Zephyr bt_gatt_notify_cb contract) — the same context send_work runs in +// — so packet_queued is single-threaded here and needs no lock. +static void notify_complete_cb(struct bt_conn *conn, void *user_data) { + (void)conn; + bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *)user_data; + self->packet_queued = false; + // Drain the other buffer now that this notify is done. K_NO_WAIT runs + // send_work immediately, cancelling any pending delayed retry. + k_work_reschedule(&self->send_work, K_NO_WAIT); +} + +// The deferred sender. Runs only on the system workqueue (submitted by the VM +// on write/flush and by notify_complete_cb on completion). It is the sole +// caller of bt_gatt_notify_cb, so packet_queued / pending_index / pending_size +// are touched here and in the VM's brief critical section — nowhere else. +static void packet_buffer_send_work_handler(struct k_work *work) { + bleio_packet_buffer_obj_t *self = CONTAINER_OF( + k_work_delayable_from_work(work), bleio_packet_buffer_obj_t, send_work); + + // Server-side notify path only; clients write directly. characteristic is + // NULL after deinit, so bail before touching it (notify_complete_cb() can + // reschedule send_work after teardown). + bleio_characteristic_obj_t *c = self->characteristic; + if (c == NULL || self->client) { + return; + } + if (!conn_is_valid(self)) { + // The peer is gone: drop everything staged, and clear packet_queued even + // if a notification was handed to bt_gatt_notify_cb() already and its + // notify_complete_cb() has not run. It never will: Zephyr does not call + // the ATT callback for a PDU destroyed by a disconnect (att.c + // att_on_sent_cb(): "Bearer not connected, dropping ATT cb"). If + // packet_queued stayed set, the early return below would skip every + // later send on this buffer, even after the peer reconnects. + self->pending_size = 0; + self->packet_queued = false; + return; + } + + // A notification has been handed to bt_gatt_notify_cb() and its + // notify_complete_cb() has not run yet. That callback reschedules send_work, + // so this handler will run again once the controller has sent the PDU. + if (self->packet_queued) { + return; + } + if (self->pending_size == 0) { + return; // nothing staged + } + + // Staging keeps pending_size <= the negotiated ATT MTU payload, so the + // whole staged packet fits in one notification. + struct bt_gatt_notify_params params = { + .attr = &c->service->attrs[c->value_attr_index], + .data = self->outgoing[self->pending_index], + .len = self->pending_size, + .func = notify_complete_cb, + .user_data = self, + }; + + int err = bt_gatt_notify_cb(self->conn, ¶ms); + if (err == 0) { + // Accepted by the controller; the payload was copied into a PDU and + // will go out at the next connection event. Hand this buffer off and + // let the VM fill the other one while it's in flight. + self->packet_queued = true; + self->pending_size = 0; + self->pending_index ^= 1; // VM fills the other buffer next + return; + } + if (err == -ENOMEM || err == -EAGAIN) { + // No ATT TX buffer right now. The ATT TX pool is shared across all ATT + // traffic on all connections, so it can be full from other + // notifies/indications/responses even when we have nothing in flight. + // Running on the workqueue makes the allocator use K_NO_WAIT: it returns + // NULL and the stack returns -ENOMEM *before* copying or queueing a PDU — + // nothing sent, nothing dropped; the bytes are still in + // outgoing[pending_index]. Leave the data staged and reschedule ourselves + // after a short delay so we retry even when the VM is idle (no write/flush + // to drive us). The delay — not an immediate resubmit — keeps the workqueue + // from busy-looping against a full pool. + k_work_reschedule(&self->send_work, K_MSEC(2)); + return; + } + if (err == -ENOTCONN) { + // Peer disconnected — forget the connection too. (We're here only when + // packet_queued is clear, so no in-flight completion is owed.) + self->conn = NULL; + } + // Any other error is not transient: -ENOTCONN (peer gone), -EPERM (link not + // encrypted and the characteristic requires it), -EINVAL (peer not + // subscribed; CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION), -ENOENT (attribute not + // registered). Retrying would spin forever and wedge this buffer. Drop the + // staged packet, as nordic and espressif do on non-resource errors, and + // cancel any pending delayed retry. + self->pending_size = 0; + self->packet_queued = false; + k_work_cancel_delayable(&self->send_work); +} + +// Shared core for both the Python-facing (allocating) and workflow +// (caller-supplied static buffer) constructors. Wires the ring buffer, the two +// outgoing buffers, the characteristic observer, and (for client-side) CCCD +// subscription. No GC heap allocation happens here. +static void packet_buffer_init_common(bleio_packet_buffer_obj_t *self, + bleio_characteristic_obj_t *characteristic, + uint8_t *ringbuf_data, size_t ringbuf_size, bool owns_ringbuf_data, + uint8_t *outgoing0, uint8_t *outgoing1, + bool owns_outgoing0, bool owns_outgoing1, + size_t max_packet_size) { + + self->characteristic = characteristic; + self->timeout_ms = 0; + self->max_packet_size = max_packet_size; + self->conn = NULL; + self->client = (characteristic->service != NULL && characteristic->service->is_remote); + self->outgoing[0] = outgoing0; + self->outgoing[1] = outgoing1; + self->owns_outgoing[0] = owns_outgoing0; + self->owns_outgoing[1] = owns_outgoing1; + self->pending_index = 0; + self->pending_size = 0; + self->packet_queued = false; + + self->ringbuf_data = ringbuf_data; + self->ringbuf_size = ringbuf_size; + self->owns_ringbuf_data = owns_ringbuf_data; + if (ringbuf_data != NULL && ringbuf_size > 0) { + ring_buf_init(&self->ringbuf, ringbuf_size, ringbuf_data); + } else { + // No incoming buffer (e.g. a server-side NOTIFY-only characteristic). + ring_buf_init(&self->ringbuf, 0, NULL); + } + + // The deferred sender drives server-side notifications. Client-side writes + // go out synchronously and never schedule it, but initializing it always is + // harmless and keeps flush()/deinit() simple. + k_work_init_delayable(&self->send_work, packet_buffer_send_work_handler); + + // Set ourselves as the characteristic's observer so GATT write/notify + // callbacks push incoming data into our ring buffer. + bleio_characteristic_set_observer(characteristic, MP_OBJ_FROM_PTR(self)); + + bleio_characteristic_properties_t props = + common_hal_bleio_characteristic_get_properties(characteristic); + + // For client-side characteristics with NOTIFY/INDICATE, subscribe to + // notifications from the remote peer. + if (self->client && (props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE))) { + bool do_notify = (props & CHAR_PROP_NOTIFY) != 0; + bool do_indicate = (props & CHAR_PROP_INDICATE) != 0; + common_hal_bleio_characteristic_set_cccd(characteristic, do_notify, do_indicate); + } +} + +void common_hal_bleio_packet_buffer_construct( + bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, + size_t buffer_size, size_t max_packet_size) { + + bleio_characteristic_properties_t props = + common_hal_bleio_characteristic_get_properties(characteristic); + bool client = (characteristic->service != NULL && characteristic->service->is_remote); + + // Allocate ring buffer: buffer_size packets, each with 2-byte length prefix + size_t ringbuf_size = buffer_size * (sizeof(uint16_t) + max_packet_size); + uint8_t *ringbuf_data = port_malloc(ringbuf_size, false); + + // Allocate outgoing buffers. Client-side writes go out directly and only + // need one scratch buffer. Server-side notifications ping-pong between two + // buffers so the VM can fill one while the other is in flight. + uint8_t *outgoing0 = NULL; + uint8_t *outgoing1 = NULL; + bool owns0 = false; + bool owns1 = false; + if (client) { + outgoing0 = port_malloc(max_packet_size, false); + owns0 = true; + } else if (props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { + outgoing0 = port_malloc(max_packet_size, false); + outgoing1 = port_malloc(max_packet_size, false); + owns0 = true; + owns1 = true; + } + + packet_buffer_init_common(self, characteristic, + ringbuf_data, ringbuf_size, true, + outgoing0, outgoing1, owns0, owns1, + max_packet_size); +} + +// Allocation-free version for BLE workflow use. The caller supplies static +// buffers so this can run before gc_init() without touching the GC heap. +// outgoing_buffer1 -> outgoing[0], outgoing_buffer2 -> outgoing[1]. +void _common_hal_bleio_packet_buffer_construct( + bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, + uint32_t *incoming_buffer, size_t incoming_buffer_size, + uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, + ble_event_handler_t *static_handler_entry) { + (void)static_handler_entry; + + uint8_t *ringbuf_data = (uint8_t *)incoming_buffer; + size_t ringbuf_size = incoming_buffer_size; + + bleio_characteristic_properties_t props = + common_hal_bleio_characteristic_get_properties(characteristic); + bool client = (characteristic->service != NULL && characteristic->service->is_remote); + + uint8_t *outgoing0 = NULL; + uint8_t *outgoing1 = NULL; + bool owns0 = false; + bool owns1 = false; + + if (client) { + // Client-side: one scratch buffer for synchronous writes. + if (outgoing_buffer1 != NULL) { + outgoing0 = (uint8_t *)outgoing_buffer1; + } else { + outgoing0 = port_malloc(max_packet_size, false); + owns0 = true; + } + } else if (props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { + // Server-side: two buffers to ping-pong between. + if (outgoing_buffer1 != NULL) { + outgoing0 = (uint8_t *)outgoing_buffer1; + } else { + outgoing0 = port_malloc(max_packet_size, false); + owns0 = true; + } + if (outgoing_buffer2 != NULL) { + outgoing1 = (uint8_t *)outgoing_buffer2; + } else { + outgoing1 = port_malloc(max_packet_size, false); + owns1 = true; + } + } + + packet_buffer_init_common(self, characteristic, + ringbuf_data, ringbuf_size, false, + outgoing0, outgoing1, owns0, owns1, + max_packet_size); +} + +mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, + uint8_t *data, size_t len) { + // Need at least 2 bytes for the length prefix + if (ring_buf_size_get(&self->ringbuf) < sizeof(uint16_t)) { + return 0; + } + + // Peek at the packet length (don't consume yet) + uint16_t packet_length; + uint32_t peeked = ring_buf_peek(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); + if (peeked < sizeof(uint16_t)) { + return 0; + } + + mp_int_t ret; + if (packet_length > len) { + // Packet is longer than requested. Return negative of overrun value. + ret = len - packet_length; + // Discard the packet + ring_buf_get(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); + if (packet_length <= ring_buf_size_get(&self->ringbuf)) { + // Discard data in chunks + uint8_t discard[32]; + size_t remaining = packet_length; + while (remaining > 0) { + size_t chunk = remaining > sizeof(discard) ? sizeof(discard) : remaining; + ring_buf_get(&self->ringbuf, discard, chunk); + remaining -= chunk; + } + } + } else { + // Consume the length prefix + ring_buf_get(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); + // Read packet data + ring_buf_get(&self->ringbuf, data, packet_length); + ret = packet_length; + } + + return ret; +} + +mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, + const uint8_t *data, size_t len, uint8_t *header, size_t header_len) { + if (self->outgoing[0] == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Writes not supported on Characteristic")); + } + + mp_int_t outgoing_packet_length = + common_hal_bleio_packet_buffer_get_outgoing_packet_length(self); + if (outgoing_packet_length < 0) { + return -1; + } + + mp_int_t total_len = len + header_len; + if (total_len > outgoing_packet_length) { + mp_raise_ValueError_varg( + MP_ERROR_TEXT("Total data to write is larger than %q"), + MP_QSTR_outgoing_packet_length); + } + if (total_len > (mp_int_t)self->max_packet_size) { + mp_raise_ValueError_varg( + MP_ERROR_TEXT("Total data to write is larger than %q"), + MP_QSTR_max_packet_size); + } + + // Client-side (remote characteristic): write the request directly to the + // remote GATT server. The server-side path below stages into a double + // buffer and drains it from the system workqueue via send_work, so handle + // client writes separately (and synchronously). + if (self->characteristic != NULL && + self->characteristic->service != NULL && + self->characteristic->service->is_remote) { + bleio_characteristic_obj_t *c = self->characteristic; + bleio_connection_obj_t *connection = MP_OBJ_TO_PTR(c->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + return -1; + } + struct bt_conn *conn = connection->connection->conn; + + // Combine header + data into the outgoing buffer (max_packet_size). + memcpy(self->outgoing[0], header, header_len); + memcpy(self->outgoing[0] + header_len, data, len); + size_t total = header_len + len; + + if (c->props & CHAR_PROP_WRITE_NO_RESPONSE) { + // Fire-and-forget write. Retry on transient "no TX buffer" + // (-EAGAIN) so paced protocols (e.g. BLE file transfer) don't + // silently drop data. + int err; + while ((err = bt_gatt_write_without_response(conn, c->handle, + self->outgoing[0], total, false)) == -EAGAIN) { + RUN_BACKGROUND_TASKS; + } + if (err != 0) { + raise_zephyr_error(err); + } + } else if (c->props & CHAR_PROP_WRITE) { + bleio_gattc_write_sync(conn, c->handle, self->outgoing[0], total); + } else { + // No write property; nothing to send. + return -1; + } + return (mp_int_t)total; + } + + // Server-side notify path: stage header + data into the pending buffer, + // then hand it to send_work on the system workqueue. bt_gatt_notify_cb + // blocks (K_FOREVER) off the workqueue, so we never call it here; send_work + // does, and the completion callback paces us to one notification in flight. + // The header prefixes each packet, so it's only written when the packet is + // empty (pending_size == 0). pending_size counts bytes staged but not yet + // accepted by the controller. + + if (mp_hal_is_interrupted()) { + return -1; + } + + // If this write would overflow the current packet, wait for send_work to + // drain it (which requires the in-flight notification to complete first). + if ((size_t)len + self->pending_size > (size_t)outgoing_packet_length) { + while (self->pending_size != 0 && + conn_is_valid(self) && + !mp_hal_is_interrupted()) { + k_work_reschedule(&self->send_work, K_NO_WAIT); + RUN_BACKGROUND_TASKS; + } + } + if (!conn_is_valid(self) || mp_hal_is_interrupted()) { + return -1; + } + + size_t num_bytes_written = 0; + + // send_work (system workqueue) may preempt us and modify pending_index / + // pending_size / packet_queued, so guard the append. + common_hal_mcu_disable_interrupts(); + { + uint8_t *pending = self->outgoing[self->pending_index]; + if (self->pending_size == 0 && header_len > 0) { + memcpy(pending, header, header_len); + self->pending_size += header_len; + num_bytes_written += header_len; + } + memcpy(pending + self->pending_size, data, len); + self->pending_size += len; + num_bytes_written += len; + } + common_hal_mcu_enable_interrupts(); + + // If no notification is in flight, kick the deferred sender to drain what + // we just staged (K_NO_WAIT runs it immediately, cancelling any pending + // delayed retry). If one is in flight, its completion will resubmit. + if (!self->packet_queued) { + k_work_reschedule(&self->send_work, K_NO_WAIT); + } + return (mp_int_t)num_bytes_written; +} + +mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length( + bleio_packet_buffer_obj_t *self) { + if (self->characteristic == NULL) { + return -1; + } + + if (self->characteristic->service != NULL && + self->characteristic->service->is_remote && + self->characteristic->service->connection != mp_const_none && + (common_hal_bleio_characteristic_get_properties(self->characteristic) & + (CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) { + // We are receiving from a remote service via NOTIFY/INDICATE. + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(self->characteristic->service->connection); + if (connection != NULL && connection->connection != NULL && + common_hal_bleio_connection_get_connected(connection)) { + return common_hal_bleio_connection_get_max_packet_length(connection->connection); + } + return -1; + } + return self->characteristic->max_length; +} + +mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length( + bleio_packet_buffer_obj_t *self) { + if (self->characteristic == NULL) { + return -1; + } + + if (self->characteristic->service != NULL && + !self->characteristic->service->is_remote && + (common_hal_bleio_characteristic_get_properties(self->characteristic) & + (CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) { + // We are sending to a client via NOTIFY/INDICATE. The maximum payload + // per packet is bounded by the negotiated ATT MTU (ATT_MTU - 3 for the + // opcode and handle in a Handle Value Notification PDU). Without a + // current connection we can't know the MTU, so return -1 to signal + // that writes aren't possible yet. + if (!conn_is_valid(self)) { + return -1; + } + uint16_t mtu = bt_gatt_get_mtu(self->conn); + if (mtu < 3) { + return -1; + } + mp_int_t mtu_payload = (mp_int_t)mtu - 3; + return MIN(MIN(mtu_payload, (mp_int_t)self->max_packet_size), + (mp_int_t)self->characteristic->max_length); + } + // Writing to remote characteristic or local without NOTIFY + return MIN(self->characteristic->max_length, self->max_packet_size); +} + +void common_hal_bleio_packet_buffer_flush(bleio_packet_buffer_obj_t *self) { + // Wait until everything written has been handed to the controller AND its + // completion has fired (we pace to one notification in flight at a time). + // send_work runs on the system workqueue, which is higher priority than + // this thread, so k_work_reschedule(K_NO_WAIT) lets it preempt us; + // RUN_BACKGROUND_TASKS advances simulated time / lets completion callbacks + // fire so packet_queued clears. For client-side writes (synchronous) there + // is nothing pending, so this returns immediately. + while ((self->pending_size != 0 || self->packet_queued) && + conn_is_valid(self) && + !mp_hal_is_interrupted()) { + k_work_reschedule(&self->send_work, K_NO_WAIT); + RUN_BACKGROUND_TASKS; + } +} + +bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { + return self->characteristic == NULL; +} + +void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { + if (common_hal_bleio_packet_buffer_deinited(self)) { + return; + } + bleio_characteristic_clear_observer(self->characteristic); + self->characteristic = NULL; + // Cancel any pending delayed retry so it can't fire after we free the + // buffers (or after the object is gone). + k_work_cancel_delayable(&self->send_work); + // Free buffers if we own them (port_malloc'd). The BLE workflow path + // supplies static buffers that must not be freed. + if (self->owns_ringbuf_data && self->ringbuf_data != NULL) { + port_free(self->ringbuf_data); + } + self->ringbuf_data = NULL; + for (int i = 0; i < 2; i++) { + if (self->owns_outgoing[i] && self->outgoing[i] != NULL) { + port_free(self->outgoing[i]); + } + self->outgoing[i] = NULL; + } +} + +bool common_hal_bleio_packet_buffer_connected(bleio_packet_buffer_obj_t *self) { + if (common_hal_bleio_packet_buffer_deinited(self)) { + return false; + } + // Check if the characteristic's connection is still active. + if (self->characteristic->service != NULL && + self->characteristic->service->is_remote) { + if (self->characteristic->service->connection == mp_const_none) { + return false; + } + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(self->characteristic->service->connection); + return common_hal_bleio_connection_get_connected(connection); + } + return true; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h new file mode 100644 index 00000000000..67216775257 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h @@ -0,0 +1,79 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include +#include + +#include "py/obj.h" +#include "shared-bindings/_bleio/Characteristic.h" + +struct bt_conn; + +typedef void *ble_event_handler_t; + +typedef struct { + mp_obj_base_t base; + bleio_characteristic_obj_t *characteristic; + uint32_t timeout_ms; + // Store the connection we are talking to. We expect to talk over a single + // connection at a time. + struct bt_conn *conn; + bool client; + // The current MTU negotiated with the active connection. + size_t max_packet_size; + + // ringbuf to store incoming packets. + struct ring_buf ringbuf; + uint8_t *ringbuf_data; + size_t ringbuf_size; + + // Outgoing path. Two fixed buffers alternate so the VM can keep filling one + // while the other is in flight with the controller. + // + // outgoing[pending_index] is the buffer the VM is filling (pending_size + // bytes staged, not yet sent). packet_queued means a notification has been + // accepted by the controller and its completion callback hasn't fired yet + // — at most one is in flight at a time. + // + uint8_t *outgoing[2]; + uint8_t pending_index; // which buffer the VM is filling + volatile uint16_t pending_size; // bytes staged in outgoing[pending_index] + volatile bool packet_queued; // a notification is in flight + + // send_work is a delayable work item, the only caller of bt_gatt_notify_cb + // (that API blocks (K_FOREVER) off the workqueue but returns -ENOMEM from + // it). It's rescheduled with K_NO_WAIT to drain after a write/completion, + // and with a short delay on -ENOMEM so it self-retries even when the VM is + // idle and the shared ATT TX pool is full from other traffic. It and the + // completion callback both run on the workqueue (serialized with each + // other); the VM is the only other toucher of these fields and guards its + // read-modify-write with common_hal_mcu_disable_interrupts() (the workqueue + // preempts the VM, so the critical section keeps it out while we append). + // bt_gatt_notify_cb copies the payload into a PDU on success, so the source + // buffer may be reused once the call returns 0; the completion callback + // paces us to one in flight and makes flush() accurate. + struct k_work_delayable send_work; + + // Ownership: true if the buffer was port_malloc'd and should be freed in + // deinit; false if it is a caller-supplied static buffer (the BLE workflow + // path, which runs before gc_init()). + bool owns_ringbuf_data; + bool owns_outgoing[2]; +} bleio_packet_buffer_obj_t; + +// Called from GATT callbacks (system workqueue context) to push +// data into the PacketBuffer ring buffer with length-prefix framing. +void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, + struct bt_conn *conn, const uint8_t *data, size_t len); + +// Called from CCCD write callback to record the subscribing connection. +void bleio_packet_buffer_set_conn(bleio_packet_buffer_obj_t *self, + struct bt_conn *conn); diff --git a/ports/zephyr-cp/common-hal/_bleio/Service.c b/ports/zephyr-cp/common-hal/_bleio/Service.c new file mode 100644 index 00000000000..4333ee21c25 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Service.c @@ -0,0 +1,346 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// GATT server service implementation for Zephyr. +// +// Each bleio Service owns a dynamically-allocated array of bt_gatt_attr +// (the Zephyr GATT attribute table). When a Characteristic is added, we +// append 2-4 attrs (declaration, value, optional CCC, optional CUD) and +// (re-)register the service with bt_gatt_service_register(). +// +// IMPORTANT: Zephyr's BT_UUID_GATT_PRIMARY / BT_UUID_GATT_CHRC / … macros +// expand to compound-literal pointers. Inside a function those have automatic +// storage duration and become dangling once the function returns. We therefore +// declare file-scope static const UUIDs (_uuid_primary, _uuid_chrc, …) and +// reference those from every bt_gatt_attr we build. + +#include +#include + +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "supervisor/port_heap.h" +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Service.h" +#include "common-hal/_bleio/__init__.h" +#include "common-hal/_bleio/Characteristic.h" + +#define INITIAL_ATTR_CAPACITY 16 + +// Standard GATT UUIDs with static storage duration. +// BT_UUID_GATT_PRIMARY etc. expand to compound literals which have automatic +// storage when used inside functions - the resulting pointers dangle after the +// function returns. These static constants persist for the lifetime of the +// program. +static const struct bt_uuid_16 _uuid_primary = BT_UUID_INIT_16(BT_UUID_GATT_PRIMARY_VAL); +static const struct bt_uuid_16 _uuid_secondary = BT_UUID_INIT_16(BT_UUID_GATT_SECONDARY_VAL); +static const struct bt_uuid_16 _uuid_chrc = BT_UUID_INIT_16(BT_UUID_GATT_CHRC_VAL); +static const struct bt_uuid_16 _uuid_ccc = BT_UUID_INIT_16(BT_UUID_GATT_CCC_VAL); +static const struct bt_uuid_16 _uuid_cud = BT_UUID_INIT_16(BT_UUID_GATT_CUD_VAL); + +// User-created services live on the GC heap, but once registered, Zephyr's GATT +// database holds a pointer to the bt_gatt_service node inside the object. So a +// registered heap service must stay reachable until it is unregistered, and it +// must be unregistered before the heap it lives in goes away. The zephyr port never +// restarts the Bluetooth stack (set_enabled(false) leaves it running), so the +// database is never cleared for us: bleio_user_reset() unregisters the services at the +// end of every VM run. Same pattern as ports/espressif/common-hal/_bleio/Service.c. +static bleio_service_obj_t *_retained_services; + +static void service_retain(bleio_service_obj_t *self) { + if (!gc_ptr_on_heap((void *)self)) { + // Statically allocated workflow service; the supervisor owns its lifetime. + return; + } + for (bleio_service_obj_t *it = _retained_services; it != NULL; it = it->next_retained) { + if (it == self) { + return; + } + } + self->next_retained = _retained_services; + _retained_services = self; +} + +static void service_release(bleio_service_obj_t *self) { + bleio_service_obj_t **prev = &_retained_services; + for (bleio_service_obj_t *it = *prev; it != NULL; it = it->next_retained) { + if (it == self) { + *prev = it->next_retained; + it->next_retained = NULL; + return; + } + prev = &it->next_retained; + } +} + +// One pointer is enough: the GC traces next_retained through the rest of the chain. +void bleio_service_gc_collect(void) { + gc_collect_ptr(_retained_services); +} + +void bleio_service_unregister_retained(void) { + while (_retained_services != NULL) { + bleio_service_obj_t *service = _retained_services; + // The characteristics' value buffers are on the port heap and nothing + // else frees them once the VM heap is gone. + mp_obj_list_t *list = service->characteristic_list; + if (list != NULL) { + for (size_t i = 0; i < list->len; i++) { + common_hal_bleio_characteristic_deinit(MP_OBJ_TO_PTR(list->items[i])); + } + } + // Unregisters from Zephyr, frees attrs, and removes it from this list. + common_hal_bleio_service_deinit(service); + } +} + +// Zephyr write permission for the CCC descriptor. If reading the characteristic +// value requires encryption or authentication, so does subscribing to it; +// otherwise a client could get the value from notifications without ever being +// made to pair. An unencrypted write then gets Insufficient Encryption or +// Authentication, which is what makes a host pair. Same as espressif (#11236). +// NO_ACCESS on read is not a link-security level, so it leaves the CCC writable; +// nordic differs and makes such a characteristic unsubscribable. +static uint16_t ccc_write_perm(bleio_attribute_security_mode_t read_perm) { + switch (read_perm) { + case SECURITY_MODE_ENC_NO_MITM: + return BT_GATT_PERM_WRITE_ENCRYPT; + case SECURITY_MODE_ENC_WITH_MITM: + return BT_GATT_PERM_WRITE_AUTHEN; + case SECURITY_MODE_LESC_ENC_WITH_MITM: + return BT_GATT_PERM_WRITE_LESC; + default: + return BT_GATT_PERM_WRITE; + } +} + +static void service_ensure_capacity(bleio_service_obj_t *self, size_t needed) { + if (self->attr_count + needed <= self->attr_capacity) { + return; + } + size_t new_capacity = self->attr_capacity; + while (new_capacity < self->attr_count + needed) { + new_capacity *= 2; + } + struct bt_gatt_attr *new_attrs = port_realloc(self->attrs, + new_capacity * sizeof(struct bt_gatt_attr), false); + self->attrs = new_attrs; + self->attr_capacity = new_capacity; +} + +uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, + bleio_uuid_obj_t *uuid, bool is_secondary, + mp_obj_list_t *characteristic_list) { + self->uuid = uuid; + self->is_secondary = is_secondary; + self->is_remote = false; + self->connection = mp_const_none; + self->characteristic_list = characteristic_list; + self->start_handle = 0; + self->end_handle = 0; + self->registered = false; + self->next_retained = NULL; + + // Convert UUID to Zephyr format + bleio_uuid_to_zephyr(uuid, &self->zephyr_uuid); + + // Allocate attrs array + self->attr_capacity = INITIAL_ATTR_CAPACITY; + self->attrs = port_malloc(self->attr_capacity * sizeof(struct bt_gatt_attr), false); + memset(self->attrs, 0, self->attr_capacity * sizeof(struct bt_gatt_attr)); + self->attr_count = 0; + + // Add primary/secondary service declaration at index 0 + const struct bt_uuid *svc_type_uuid = is_secondary + ? (const struct bt_uuid *)&_uuid_secondary + : (const struct bt_uuid *)&_uuid_primary; + self->attrs[0] = (struct bt_gatt_attr) { + .uuid = svc_type_uuid, + .perm = BT_GATT_PERM_READ, + .read = bt_gatt_attr_read_service, + .user_data = (void *)&self->zephyr_uuid, + }; + self->attr_count = 1; + + return 0; +} + +void common_hal_bleio_service_construct(bleio_service_obj_t *self, + bleio_uuid_obj_t *uuid, bool is_secondary) { + mp_obj_list_t *char_list = mp_obj_new_list(0, NULL); + _common_hal_bleio_service_construct(self, uuid, is_secondary, char_list); +} + +void common_hal_bleio_service_deinit(bleio_service_obj_t *self) { + if (self->registered) { + bt_gatt_service_unregister(&self->zephyr_service); + self->registered = false; + } + service_release(self); + if (self->attrs != NULL) { + port_free(self->attrs); + self->attrs = NULL; + self->attr_capacity = 0; + self->attr_count = 0; + } +} + +void common_hal_bleio_service_from_remote_service(bleio_service_obj_t *self, + bleio_connection_obj_t *connection, bleio_uuid_obj_t *uuid, bool is_secondary) { + self->uuid = uuid; + self->is_secondary = is_secondary; + self->is_remote = true; + self->connection = MP_OBJ_FROM_PTR(connection); + self->characteristic_list = mp_obj_new_list(0, NULL); + self->start_handle = 0; + self->end_handle = 0; + self->registered = false; + self->next_retained = NULL; + self->attrs = NULL; + self->attr_count = 0; + self->attr_capacity = 0; + bleio_uuid_to_zephyr(uuid, &self->zephyr_uuid); +} + +bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { + return self->uuid; +} + +mp_obj_tuple_t *common_hal_bleio_service_get_characteristics(bleio_service_obj_t *self) { + return mp_obj_new_tuple(self->characteristic_list->len, self->characteristic_list->items); +} + +bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { + return self->is_remote; +} + +bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { + return self->is_secondary; +} + +void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, + bleio_characteristic_obj_t *characteristic, + mp_buffer_info_t *initial_value_bufinfo, + const char *user_description) { + + if (self->registered) { + bt_gatt_service_unregister(&self->zephyr_service); + self->registered = false; + } + + // Calculate how many attrs we need: + // 1 = characteristic declaration, 1 = value attr + // +1 if NOTIFY|INDICATE (CCC descriptor) + // +1 if user_description + size_t attrs_needed = 2; + bool needs_ccc = (characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) != 0; + bool needs_user_desc = (user_description != NULL && user_description[0] != '\0'); + if (needs_ccc) { + attrs_needed++; + } + if (needs_user_desc) { + attrs_needed++; + } + + service_ensure_capacity(self, attrs_needed); + + // Map CP properties to Zephyr BT spec properties + uint8_t zephyr_props = 0; + if (characteristic->props & CHAR_PROP_BROADCAST) { + zephyr_props |= BT_GATT_CHRC_BROADCAST; + } + if (characteristic->props & CHAR_PROP_READ) { + zephyr_props |= BT_GATT_CHRC_READ; + } + if (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) { + zephyr_props |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; + } + if (characteristic->props & CHAR_PROP_WRITE) { + zephyr_props |= BT_GATT_CHRC_WRITE; + } + if (characteristic->props & CHAR_PROP_NOTIFY) { + zephyr_props |= BT_GATT_CHRC_NOTIFY; + } + if (characteristic->props & CHAR_PROP_INDICATE) { + zephyr_props |= BT_GATT_CHRC_INDICATE; + } + + // Set up the Zephyr chrc struct in the characteristic + characteristic->zephyr_chrc.uuid = &characteristic->zephyr_uuid.uuid; + characteristic->zephyr_chrc.value_handle = 0; + characteristic->zephyr_chrc.properties = zephyr_props; + + // Map permissions + uint16_t perm = bleio_security_to_zephyr_perm( + characteristic->read_perm, characteristic->write_perm, characteristic->props); + + // Attr: characteristic declaration + size_t idx = self->attr_count; + self->attrs[idx] = (struct bt_gatt_attr) { + .uuid = (const struct bt_uuid *)&_uuid_chrc, + .perm = BT_GATT_PERM_READ, + .read = bt_gatt_attr_read_chrc, + .user_data = &characteristic->zephyr_chrc, + }; + idx++; + + // Attr: characteristic value (UUID points into characteristic, which persists) + characteristic->value_attr_index = idx; + self->attrs[idx] = (struct bt_gatt_attr) { + .uuid = &characteristic->zephyr_uuid.uuid, + .perm = perm, + .read = (characteristic->props & CHAR_PROP_READ) ? bleio_char_read_cb : NULL, + .write = (characteristic->props & (CHAR_PROP_WRITE | CHAR_PROP_WRITE_NO_RESPONSE)) ? bleio_char_write_cb : NULL, + .user_data = characteristic, + }; + idx++; + + // Attr: CCC descriptor (for NOTIFY/INDICATE) + if (needs_ccc) { + characteristic->zephyr_ccc = (struct bt_gatt_ccc_managed_user_data) + BT_GATT_CCC_MANAGED_USER_DATA_INIT(bleio_ccc_changed_cb, bleio_ccc_write_cb, NULL); + self->attrs[idx] = (struct bt_gatt_attr) { + .uuid = (const struct bt_uuid *)&_uuid_ccc, + .perm = BT_GATT_PERM_READ | ccc_write_perm(characteristic->read_perm), + .read = bt_gatt_attr_read_ccc, + .write = bt_gatt_attr_write_ccc, + .user_data = &characteristic->zephyr_ccc, + }; + idx++; + } + + // Attr: user description descriptor + if (needs_user_desc) { + self->attrs[idx] = (struct bt_gatt_attr) { + .uuid = (const struct bt_uuid *)&_uuid_cud, + .perm = BT_GATT_PERM_READ, + .read = bt_gatt_attr_read_cud, + .user_data = (void *)user_description, + }; + idx++; + } + + self->attr_count = idx; + + // Add characteristic to list + mp_obj_list_append(MP_OBJ_FROM_PTR(self->characteristic_list), + MP_OBJ_FROM_PTR(characteristic)); + + // Register the service + self->zephyr_service.attrs = self->attrs; + self->zephyr_service.attr_count = self->attr_count; + int err = bt_gatt_service_register(&self->zephyr_service); + if (err != 0) { + raise_zephyr_error(err); + } + self->registered = true; + // Zephyr now points into this object; keep it alive until unregistered. + service_retain(self); +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Service.h b/ports/zephyr-cp/common-hal/_bleio/Service.h new file mode 100644 index 00000000000..75731bc6e09 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Service.h @@ -0,0 +1,43 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" +#include "py/objlist.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct bleio_service_obj { + mp_obj_base_t base; + bleio_uuid_obj_t *uuid; + mp_obj_t connection; + mp_obj_list_t *characteristic_list; + uint16_t start_handle; + uint16_t end_handle; + bool is_remote; + bool is_secondary; + // Zephyr GATT server fields: + struct bt_gatt_service zephyr_service; + struct bt_gatt_attr *attrs; + size_t attr_count; + size_t attr_capacity; + struct bt_uuid_128 zephyr_uuid; + bool registered; + // Link in the list of heap services retained while Zephyr's GATT database + // refers to them. See bleio_service_unregister_retained(). + struct bleio_service_obj *next_retained; +} bleio_service_obj_t; + +// Unregister every user-created service still in Zephyr's GATT database and +// free their port-heap buffers. Call from bleio_user_reset(), while the GC heap +// the service objects live in is still valid. +void bleio_service_unregister_retained(void); + +// Mark the retained services as reachable during a GC pass. +void bleio_service_gc_collect(void); diff --git a/ports/zephyr-cp/common-hal/_bleio/UUID.c b/ports/zephyr-cp/common-hal/_bleio/UUID.c new file mode 100644 index 00000000000..9e963b1b0bc --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.c @@ -0,0 +1,50 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/runtime.h" +#include "shared-bindings/_bleio/UUID.h" + +void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]) { + self->uuid16 = (uint16_t)uuid16; + if (uuid128 == NULL) { + // 16-bit UUID — only bytes 12-13 matter; rest is zero (matching ble_hci). + self->size = BT_UUID_SIZE_16; + memset(self->uuid128, 0, 16); + self->uuid128[12] = uuid16 & 0xff; + self->uuid128[13] = (uuid16 >> 8) & 0xff; + } else { + // 128-bit UUID — uuid128 has bytes 12-13 zeroed, uuid16 is extracted from them + self->size = BT_UUID_SIZE_128; + memcpy(self->uuid128, uuid128, 16); + // Restore the 16-bit portion from uuid16 into bytes 12-13 (little-endian). + self->uuid128[12] = uuid16 & 0xff; + self->uuid128[13] = uuid16 >> 8; + } +} + +uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) { + return self->uuid16; +} + +void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]) { + memcpy(uuid128, self->uuid128, 16); +} + +uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self) { + return self->size == BT_UUID_SIZE_16 ? 16 : 128; +} + +void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t *buf) { + if (self->size == BT_UUID_SIZE_16) { + buf[0] = self->uuid128[12]; + buf[1] = self->uuid128[13]; + } else { + memcpy(buf, self->uuid128, 16); + } +} diff --git a/ports/zephyr-cp/common-hal/_bleio/UUID.h b/ports/zephyr-cp/common-hal/_bleio/UUID.h new file mode 100644 index 00000000000..9a0743a1b60 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.h @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t uuid128[16]; + uint8_t size; // BT_UUID_SIZE_16 (2) or BT_UUID_SIZE_128 (16) + uint16_t uuid16; +} bleio_uuid_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.c b/ports/zephyr-cp/common-hal/_bleio/__init__.c new file mode 100644 index 00000000000..b51db00835a --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.c @@ -0,0 +1,209 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "common-hal/_bleio/Adapter.h" +#include "common-hal/_bleio/__init__.h" +#include "bindings/zephyr_kernel/__init__.h" +#include "common-hal/_bleio/Connection.h" +#include "common-hal/_bleio/Service.h" +#include "supervisor/shared/bluetooth/bluetooth.h" +#include "supervisor/shared/tick.h" + +// The singleton _bleio.Adapter object +bleio_adapter_obj_t common_hal_bleio_adapter_obj; + +// Called once by the BLE workflow at boot and again on every `import _bleio`, +// so it must not disturb a running adapter: the workflow may be advertising or +// connected by the time user code imports the module. Starting the BLE stack happens in +// common_hal_bleio_adapter_set_enabled(), which the importer calls next. +void common_hal_bleio_init(void) { + common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; + bleio_connection_register_auth_callbacks(); +} + +// Tear down user BLE state at the end of a VM run, leaving the BLE workflow +// connection up. Runs while the VM heap is still valid. +void bleio_user_reset(void) { + if (common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + // Stop any user scanning or advertising. + common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); + common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); + + // Disconnect the connections that user code initiated or accepted with its + // own advertising. The BLE workflow connection is not user-owned and stays up. + // + // Clear each connection's pointer into the VM heap first: the heap is about + // to go away, and a disconnect completes asynchronously, possibly after the heap + // is gone. + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + connection->connection_obj = mp_const_none; + if (connection->conn != NULL && connection->user_owned) { + common_hal_bleio_connection_disconnect(connection); + } + } + + // Remove references to any VM heap objects. + common_hal_bleio_adapter_obj.connection_objs = NULL; + common_hal_bleio_adapter_obj.scan_results = NULL; + } + + // Remove user-created services from Zephyr's GATT database and free their + // buffers. Zephyr indicates Service Changed to connected peers itself, and + // records it for bonded peers to receive when they next connect. + bleio_service_unregister_retained(); + + // Maybe start advertising the BLE workflow. + supervisor_bluetooth_background(); +} + +// Called after the VM heap is gone. On nordic and espressif this restarts the +// BLE stack when user code created GATT services, because their stacks can't +// remove services one at a time. Zephyr can, and bleio_user_reset() already did, +// so there is nothing left that requires dropping the workflow connection. +void bleio_reset(void) { + common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; + bleio_clear_user_services_created(); +} + +void common_hal_bleio_gc_collect(void) { + bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); + bleio_service_gc_collect(); +} + +// ======================================================================= +// Shared synchronous GATT helpers +// ======================================================================= + +typedef struct { + uint8_t *buf; + size_t buf_len; + size_t read_len; + volatile bool done; + volatile int err; +} gattc_read_ctx_t; + +typedef struct { + volatile bool done; + volatile int err; +} gattc_write_ctx_t; + +static gattc_read_ctx_t *active_read_ctx; +static gattc_write_ctx_t *active_write_ctx; +static struct bt_gatt_read_params read_params; +static struct bt_gatt_write_params write_params; + +static uint8_t on_gattc_read(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) { + gattc_read_ctx_t *ctx = active_read_ctx; + if (ctx == NULL) { + return BT_GATT_ITER_STOP; + } + + if (err) { + ctx->err = err; + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + if (data == NULL || length == 0) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + size_t copy_len = length; + if (ctx->read_len + copy_len > ctx->buf_len) { + copy_len = ctx->buf_len - ctx->read_len; + } + if (copy_len > 0) { + memcpy(ctx->buf + ctx->read_len, data, copy_len); + ctx->read_len += copy_len; + } + + ctx->done = true; + return BT_GATT_ITER_STOP; +} + +static void on_gattc_write(struct bt_conn *conn, uint8_t err, + struct bt_gatt_write_params *params) { + gattc_write_ctx_t *ctx = active_write_ctx; + if (ctx == NULL) { + return; + } + ctx->err = err; + ctx->done = true; +} + +size_t bleio_gattc_read_sync(struct bt_conn *conn, uint16_t handle, + uint8_t *buf, size_t len) { + gattc_read_ctx_t ctx = { + .buf = buf, + .buf_len = len, + .read_len = 0, + .done = false, + .err = 0, + }; + active_read_ctx = &ctx; + + memset(&read_params, 0, sizeof(read_params)); + read_params.func = on_gattc_read; + read_params.handle_count = 1; + read_params.single.handle = handle; + read_params.single.offset = 0; + + int err = bt_gatt_read(conn, &read_params); + if (err != 0) { + active_read_ctx = NULL; + raise_zephyr_error(err); + } + + while (!ctx.done) { + RUN_BACKGROUND_TASKS; + } + active_read_ctx = NULL; + + if (ctx.err != 0) { + raise_zephyr_error(ctx.err); + } + + return ctx.read_len; +} + +void bleio_gattc_write_sync(struct bt_conn *conn, uint16_t handle, + const uint8_t *data, size_t len) { + gattc_write_ctx_t ctx = { + .done = false, + .err = 0, + }; + active_write_ctx = &ctx; + + memset(&write_params, 0, sizeof(write_params)); + write_params.func = on_gattc_write; + write_params.handle = handle; + write_params.offset = 0; + write_params.data = data; + write_params.length = len; + + int err = bt_gatt_write(conn, &write_params); + if (err != 0) { + active_write_ctx = NULL; + raise_zephyr_error(err); + } + + while (!ctx.done) { + RUN_BACKGROUND_TASKS; + } + active_write_ctx = NULL; + + if (ctx.err != 0) { + raise_zephyr_error(ctx.err); + } +} diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.h b/ports/zephyr-cp/common-hal/_bleio/__init__.h new file mode 100644 index 00000000000..72dc249d142 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.h @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include +#include +#include + +#include "common-hal/_bleio/UUID.h" + +// Convert a CircuitPython bleio UUID to a Zephyr bt_uuid stored in caller- +// provided bt_uuid_128 storage. For 16-bit UUIDs we reinterpret the storage +// as bt_uuid_16 and write .val (at offset 2, matching Zephyr's struct layout). +// For 128-bit UUIDs the 16-byte value is copied directly into bt_uuid_128.val. +// The result can be used as `&out->uuid` wherever a `const struct bt_uuid *` +// is needed; Zephyr dispatches on the .type field at runtime. +static inline void bleio_uuid_to_zephyr(const bleio_uuid_obj_t *cp_uuid, + struct bt_uuid_128 *out) { + if (cp_uuid->size == BT_UUID_SIZE_16) { + out->uuid.type = BT_UUID_TYPE_16; + ((struct bt_uuid_16 *)out)->val = + (cp_uuid->uuid128[13] << 8) | cp_uuid->uuid128[12]; + } else { + out->uuid.type = BT_UUID_TYPE_128; + // Both CP and Zephyr store UUID bytes in little-endian order. + memcpy(out->val, cp_uuid->uuid128, 16); + } +} + +// Shared synchronous GATT helpers — wrap Zephyr's async bt_gatt_read/write +// into a blocking call with RUN_BACKGROUND_TASKS spinning. +size_t bleio_gattc_read_sync(struct bt_conn *conn, uint16_t handle, + uint8_t *buf, size_t len); +void bleio_gattc_write_sync(struct bt_conn *conn, uint16_t handle, + const uint8_t *data, size_t len); + +// Abort any in-flight remote GATT discovery; called from the disconnect +// callback so discover_remote_services() fails cleanly instead of hanging +// or NULL-dereferencing the cleared connection. +void bleio_connection_discovery_abort(void); diff --git a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c new file mode 100644 index 00000000000..27577b59cd7 --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c @@ -0,0 +1,308 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiobusio/I2SOut.h" + +#include +#include +#include +#include +#include + +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" +#include "py/runtime.h" + +#if CIRCUITPY_AUDIOBUSIO_I2SOUT + +#define AUDIO_THREAD_STACK_SIZE 2048 +#define AUDIO_THREAD_PRIORITY 5 + +// Forward declarations +static void fill_buffer(audiobusio_i2sout_obj_t *self, uint8_t *buffer, size_t buffer_size); +static void audio_thread_func(void *self_in, void *unused1, void *unused2); + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_audiobusio_i2sout_construct_from_device(audiobusio_i2sout_obj_t *self, const struct device *i2s_device) { + self->base.type = &audiobusio_i2sout_type; + self->i2s_dev = i2s_device; + self->left_justified = false; + self->playing = false; + self->paused = false; + self->sample = NULL; + self->slab_buffer = NULL; + self->thread_stack = NULL; + self->thread_id = NULL; + self->block_size = 0; + + return MP_OBJ_FROM_PTR(self); +} + +// Standard audiobusio construct - not used in Zephyr port (devices come from device tree) +void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, + const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); + } + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_I2S); +} + +bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t *self) { + return self->i2s_dev == NULL; +} + +void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self) { + if (common_hal_audiobusio_i2sout_deinited(self)) { + return; + } + + // Stop playback (which will free buffers) + common_hal_audiobusio_i2sout_stop(self); + + // Note: Pins and I2S device are managed by Zephyr, not released here + self->i2s_dev = NULL; +} + +static void fill_buffer(audiobusio_i2sout_obj_t *self, uint8_t *buffer, size_t buffer_size) { + if (self->sample == NULL || self->paused || self->stopping) { + // Fill with silence + memset(buffer, 0, buffer_size); + return; + } + + uint32_t bytes_filled = 0; + while (bytes_filled < buffer_size) { + uint8_t *sample_buffer; + uint32_t sample_buffer_length; + + audioio_get_buffer_result_t result = audiosample_get_buffer( + self->sample, false, 0, &sample_buffer, &sample_buffer_length); + + if (result == GET_BUFFER_ERROR) { + // Error getting buffer, stop playback + self->stopping = true; + memset(buffer + bytes_filled, 0, buffer_size - bytes_filled); + return; + } + + // Copy the returned data first, even when this is the final buffer + // (GET_BUFFER_DONE). A single-buffer sample returns its entire buffer + // together with GET_BUFFER_DONE on the first call, so handling DONE + // before the copy would drop the audio and produce silence. + uint32_t bytes_to_copy = sample_buffer_length; + if (bytes_filled + bytes_to_copy > buffer_size) { + bytes_to_copy = buffer_size - bytes_filled; + } + + memcpy(buffer + bytes_filled, sample_buffer, bytes_to_copy); + bytes_filled += bytes_to_copy; + + if (result == GET_BUFFER_DONE) { + if (self->loop) { + // Reset to beginning + audiosample_reset_buffer(self->sample, false, 0); + } else { + // Final buffer copied; stop once this block drains. + self->stopping = true; + i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DRAIN); + memset(buffer + bytes_filled, 0, buffer_size - bytes_filled); + return; + } + } + } +} + +static void audio_thread_func(void *self_in, void *unused1, void *unused2) { + audiobusio_i2sout_obj_t *self = (audiobusio_i2sout_obj_t *)self_in; + + while (!self->stopping) { + uint8_t *next_buffer = NULL; + // Wait until I2S has freed the buffer it is sending. + if (k_mem_slab_alloc(&self->mem_slab, (void **)&next_buffer, K_FOREVER) != 0) { + break; + } + if (self->stopping) { + // Stopping so break. + k_mem_slab_free(&self->mem_slab, next_buffer); + break; + } + fill_buffer(self, next_buffer, self->block_size); + + // Write to I2S + int ret = i2s_write(self->i2s_dev, next_buffer, self->block_size); + if (ret < 0) { + printk("i2s_write failed: %d\n", ret); + k_mem_slab_free(&self->mem_slab, next_buffer); + // Error writing, stop playback + self->playing = false; + break; + } + } +} + +void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, + mp_obj_t sample, bool loop) { + // Stop any existing playback + if (self->playing) { + common_hal_audiobusio_i2sout_stop(self); + } + + audiosample_check(sample); + + // Get sample information + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); + uint32_t sample_rate = audiosample_get_sample_rate(sample); + uint8_t channel_count = audiosample_get_channel_count(sample); + + // Store sample parameters + self->sample = sample; + self->loop = loop; + self->bytes_per_sample = bits_per_sample / 8; + self->channel_count = channel_count; + self->stopping = false; + + // Get buffer structure from the sample + bool single_buffer, samples_signed; + uint32_t max_buffer_length; + uint8_t sample_spacing; + audiosample_get_buffer_structure(sample, /* single_channel_output */ false, + &single_buffer, &samples_signed, &max_buffer_length, &sample_spacing); + + // Use max_buffer_length from the sample as the block size + self->block_size = max_buffer_length; + if (channel_count == 1) { + // Make room for stereo samples. + self->block_size *= 2; + } + size_t block_size = self->block_size; + uint32_t num_blocks = 4; // Use 4 blocks for buffering + + // Allocate memory slab buffer + self->slab_buffer = m_malloc(self->block_size * num_blocks); + + // Initialize memory slab + int ret = k_mem_slab_init(&self->mem_slab, self->slab_buffer, block_size, num_blocks); + CHECK_ZEPHYR_RESULT(ret); + + // Configure I2S + struct i2s_config config; + config.word_size = bits_per_sample; + config.channels = 2; + config.format = self->left_justified ? I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED : I2S_FMT_DATA_FORMAT_I2S; + config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER; + config.frame_clk_freq = sample_rate; + config.mem_slab = &self->mem_slab; + config.block_size = block_size; + config.timeout = 1000; // Not a k_timeout_t. In milliseconds. + + // Configure returns EINVAL if the I2S device is not ready. We loop on this + // because it should be ready after it comes to a complete stop. + ret = -EAGAIN; + while (ret == -EAGAIN) { + ret = i2s_configure(self->i2s_dev, I2S_DIR_TX, &config); + } + if (ret != 0) { + common_hal_audiobusio_i2sout_stop(self); + raise_zephyr_error(ret); + } + + // Fill every slab before starting playback to avoid underruns. + for (uint32_t i = 0; i < num_blocks; i++) { + uint8_t *buf = NULL; + k_mem_slab_alloc(&self->mem_slab, (void **)&buf, K_NO_WAIT); + fill_buffer(self, buf, block_size); + ret = i2s_write(self->i2s_dev, buf, block_size); + if (ret < 0) { + printk("i2s_write failed: %d\n", ret); + k_mem_slab_free(&self->mem_slab, buf); + common_hal_audiobusio_i2sout_stop(self); + raise_zephyr_error(ret); + } + } + + // Allocate thread stack with proper MPU alignment for HW stack protection + self->thread_stack = k_thread_stack_alloc(AUDIO_THREAD_STACK_SIZE, 0); + + // Create and start audio processing thread + self->thread_id = k_thread_create(&self->thread, self->thread_stack, + AUDIO_THREAD_STACK_SIZE, + audio_thread_func, + self, NULL, NULL, + AUDIO_THREAD_PRIORITY, 0, K_NO_WAIT); + // Start I2S + ret = i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START); + if (ret < 0) { + common_hal_audiobusio_i2sout_stop(self); + raise_zephyr_error(ret); + } + + self->playing = true; +} + +void common_hal_audiobusio_i2sout_stop(audiobusio_i2sout_obj_t *self) { + if (!self->playing) { + return; + } + + self->playing = false; + self->paused = false; + self->stopping = true; + + // Stop I2S + i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DROP); + + // Wait for thread to finish + if (self->thread_id != NULL) { + k_thread_join(self->thread_id, K_FOREVER); + self->thread_id = NULL; + } + + // Free thread stack + if (self->thread_stack != NULL) { + k_thread_stack_free(self->thread_stack); + self->thread_stack = NULL; + } + + // Free buffers + if (self->slab_buffer != NULL) { + m_free(self->slab_buffer); + self->slab_buffer = NULL; + } + + self->sample = NULL; +} + +bool common_hal_audiobusio_i2sout_get_playing(audiobusio_i2sout_obj_t *self) { + return self->playing; +} + +void common_hal_audiobusio_i2sout_pause(audiobusio_i2sout_obj_t *self) { + if (!self->playing || self->paused) { + return; + } + + self->paused = true; + i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_STOP); +} + +void common_hal_audiobusio_i2sout_resume(audiobusio_i2sout_obj_t *self) { + if (!self->playing || !self->paused) { + return; + } + + self->paused = false; + // Thread will automatically resume filling buffers + i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START); +} + +bool common_hal_audiobusio_i2sout_get_paused(audiobusio_i2sout_obj_t *self) { + return self->paused; +} + +#endif // CIRCUITPY_AUDIOBUSIO_I2SOUT diff --git a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.h b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.h new file mode 100644 index 00000000000..916471fa833 --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.h @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" + +#include +#include +#include + +#if CIRCUITPY_AUDIOBUSIO_I2SOUT + +typedef struct { + mp_obj_base_t base; + const struct device *i2s_dev; + const mcu_pin_obj_t *bit_clock; + const mcu_pin_obj_t *word_select; + const mcu_pin_obj_t *data; + const mcu_pin_obj_t *main_clock; + mp_obj_t sample; + struct k_mem_slab mem_slab; + char *slab_buffer; + struct k_thread thread; + k_thread_stack_t *thread_stack; + k_tid_t thread_id; + size_t block_size; + bool left_justified; + bool playing; + bool paused; + bool loop; + bool stopping; + bool single_buffer; + uint8_t bytes_per_sample; + uint8_t channel_count; +} audiobusio_i2sout_obj_t; + +mp_obj_t common_hal_audiobusio_i2sout_construct_from_device(audiobusio_i2sout_obj_t *self, const struct device *i2s_device); + +void i2sout_reset(void); + +#endif // CIRCUITPY_AUDIOBUSIO_I2SOUT diff --git a/ports/zephyr-cp/common-hal/audiobusio/PDMIn.c b/ports/zephyr-cp/common-hal/audiobusio/PDMIn.c new file mode 100644 index 00000000000..3d3cfef5258 --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/PDMIn.c @@ -0,0 +1,39 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiobusio/PDMIn.h" + +#include "py/runtime.h" + +#if CIRCUITPY_AUDIOBUSIO_PDMIN + +void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, + const mcu_pin_obj_t *clock_pin, const mcu_pin_obj_t *data_pin, + uint32_t sample_rate, uint8_t bit_depth, bool mono, uint8_t oversample) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_audiobusio_pdmin_deinited(audiobusio_pdmin_obj_t *self) { + return true; +} + +void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t *self) { +} + +uint8_t common_hal_audiobusio_pdmin_get_bit_depth(audiobusio_pdmin_obj_t *self) { + return 0; +} + +uint32_t common_hal_audiobusio_pdmin_get_sample_rate(audiobusio_pdmin_obj_t *self) { + return 0; +} + +uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *self, + uint16_t *output_buffer, uint32_t output_buffer_length) { + return 0; +} + +#endif // CIRCUITPY_AUDIOBUSIO_PDMIN diff --git a/ports/zephyr-cp/common-hal/audiobusio/PDMIn.h b/ports/zephyr-cp/common-hal/audiobusio/PDMIn.h new file mode 100644 index 00000000000..195a436f3cf --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/PDMIn.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "common-hal/microcontroller/Pin.h" + +#if CIRCUITPY_AUDIOBUSIO_PDMIN + +typedef struct { + mp_obj_base_t base; +} audiobusio_pdmin_obj_t; + +#endif // CIRCUITPY_AUDIOBUSIO_PDMIN diff --git a/ports/zephyr-cp/common-hal/audiobusio/__init__.c b/ports/zephyr-cp/common-hal/audiobusio/__init__.c new file mode 100644 index 00000000000..5d2e802904d --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// No special initialization required for audiobusio diff --git a/ports/zephyr-cp/common-hal/audiobusio/__init__.h b/ports/zephyr-cp/common-hal/audiobusio/__init__.h new file mode 100644 index 00000000000..8ba7882bf94 --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/__init__.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// No common definitions needed for audiobusio diff --git a/ports/zephyr-cp/common-hal/busio/I2C.c b/ports/zephyr-cp/common-hal/busio/I2C.c new file mode 100644 index 00000000000..84e95721b27 --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/I2C.c @@ -0,0 +1,152 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/busio/I2C.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include +#include +#include + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_i2c_construct_from_device(busio_i2c_obj_t *self, const struct device *i2c_device) { + self->base.type = &busio_i2c_type; + self->i2c_device = i2c_device; + k_mutex_init(&self->mutex); + self->has_lock = false; + return MP_OBJ_FROM_PTR(self); +} + +// Standard busio construct - not used in Zephyr port (devices come from device tree) +void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, + uint32_t frequency, uint32_t timeout_ms) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_I2C); +} + +bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { + // Always leave it active (managed by Zephyr) + return false; +} + +void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return; + } + // Always leave it active (managed by Zephyr) +} + +void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { + // Not needed for Zephyr port +} + +bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { + if (common_hal_busio_i2c_deinited(self)) { + return false; + } + + // Try a zero-length write to probe for device + uint8_t dummy; + int ret = i2c_write(self->i2c_device, &dummy, 0, addr); + return ret == 0; +} + +bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return false; + } + + self->has_lock = k_mutex_lock(&self->mutex, K_NO_WAIT) == 0; + return self->has_lock; +} + +bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { + return self->has_lock; +} + +void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + self->has_lock = false; + k_mutex_unlock(&self->mutex); +} + +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, + const uint8_t *data, size_t len) { + + if (common_hal_busio_i2c_deinited(self)) { + return -MP_EIO; + } + + int ret = i2c_write(self->i2c_device, data, len, addr); + if (ret != 0) { + // Map Zephyr error codes to errno + if (ret == -ENOTSUP) { + return -MP_EOPNOTSUPP; + } else if (ret == -EIO || ret == -ENXIO) { + return -MP_EIO; + } else if (ret == -EBUSY) { + return -MP_EBUSY; + } + return -MP_EIO; + } + + return 0; +} + +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, + uint8_t *data, size_t len) { + + if (common_hal_busio_i2c_deinited(self)) { + return -MP_EIO; + } + + if (len == 0) { + return 0; + } + + int ret = i2c_read(self->i2c_device, data, len, addr); + if (ret != 0) { + // Map Zephyr error codes to errno + if (ret == -ENOTSUP) { + return -MP_EOPNOTSUPP; + } else if (ret == -EIO || ret == -ENXIO) { + return -MP_EIO; + } else if (ret == -EBUSY) { + return -MP_EBUSY; + } + return -MP_EIO; + } + + return 0; +} + +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, + uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { + + if (common_hal_busio_i2c_deinited(self)) { + return -MP_EIO; + } + + // Use i2c_write_read for combined transaction with repeated start + int ret = i2c_write_read(self->i2c_device, addr, out_data, out_len, in_data, in_len); + if (ret != 0) { + // Map Zephyr error codes to errno + if (ret == -ENOTSUP) { + return -MP_EOPNOTSUPP; + } else if (ret == -EIO || ret == -ENXIO) { + return -MP_EIO; + } else if (ret == -EBUSY) { + return -MP_EBUSY; + } + return -MP_EIO; + } + + return 0; +} + +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + // Not needed for Zephyr port (devices are managed by Zephyr) +} diff --git a/ports/zephyr-cp/common-hal/busio/I2C.h b/ports/zephyr-cp/common-hal/busio/I2C.h new file mode 100644 index 00000000000..4fa877739b7 --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/I2C.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include + +typedef struct { + mp_obj_base_t base; + const struct device *i2c_device; + struct k_mutex mutex; + bool has_lock; +} busio_i2c_obj_t; + +// Helper function to construct from Zephyr device tree device +mp_obj_t common_hal_busio_i2c_construct_from_device(busio_i2c_obj_t *self, const struct device *i2c_device); diff --git a/ports/zephyr-cp/common-hal/busio/SPI.c b/ports/zephyr-cp/common-hal/busio/SPI.c new file mode 100644 index 00000000000..2864c90b490 --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/SPI.c @@ -0,0 +1,281 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/busio/SPI.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "shared/runtime/interrupt_char.h" +#include "supervisor/port.h" + +#include +#include +#include + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_spi_construct_from_device(busio_spi_obj_t *self, const struct device *spi_device) { + self->base.type = &busio_spi_type; + self->spi_device = spi_device; + k_mutex_init(&self->mutex); + self->has_lock = false; + self->active_config = 0; + + k_poll_signal_init(&self->signal); + + // Default configuration for both config slots + self->config[0].frequency = 100000; + self->config[0].operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_LINES_SINGLE; + self->config[1].frequency = 100000; + self->config[1].operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_LINES_SINGLE; + + return MP_OBJ_FROM_PTR(self); +} + +// Standard busio construct - not used in Zephyr port (devices come from device tree) +void common_hal_busio_spi_construct(busio_spi_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *miso, bool half_duplex) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_SPI); +} + +bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { + // Always leave it active + return false; +} + +void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return; + } + // Always leave it active +} + +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + // Not needed for Zephyr port +} + +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + self->has_lock = k_mutex_lock(&self->mutex, K_NO_WAIT) == 0; + return self->has_lock; +} + +bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { + return self->has_lock; +} + +void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { + self->has_lock = false; + k_mutex_unlock(&self->mutex); +} + +bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + // Set operation mode based on polarity and phase + uint16_t operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(bits) | SPI_LINES_SINGLE; + + if (polarity) { + operation |= SPI_MODE_CPOL; + } + if (phase) { + operation |= SPI_MODE_CPHA; + } + + // Check if settings have changed. We must switch to the other config slot if they have because + // Zephyr drivers are allowed to use the pointer value to know if it has changed. + struct spi_config *current_config = &self->config[self->active_config]; + if (current_config->frequency != baudrate || current_config->operation != operation) { + // Settings changed, switch to the other config slot + self->active_config = 1 - self->active_config; + + // Update the new active configuration + self->config[self->active_config].frequency = baudrate; + self->config[self->active_config].operation = operation; + } + + return true; +} + +bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + if (len == 0) { + return true; + } + + const struct spi_buf tx_buf = { + .buf = (void *)data, + .len = len + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + // Initialize the signal for async operation + k_poll_signal_reset(&self->signal); + + int ret = spi_transceive_signal(self->spi_device, &self->config[self->active_config], &tx, NULL, &self->signal); + if (ret != 0) { + return false; + } + + // Wait for the transfer to complete while running background tasks + int signaled = 0; + int result = 0; + while (!signaled && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + k_poll_signal_check(&self->signal, &signaled, &result); + } + + return signaled && result == 0; +} + +bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + if (len == 0) { + return true; + } + + // For read, we need to write dummy bytes + // We'll allocate a temporary buffer if write_value is not 0 + uint8_t *tx_data = NULL; + bool need_free = false; + bool used_port_malloc = false; + + if (write_value != 0) { + // Use port_malloc if GC isn't active, otherwise use m_malloc + if (gc_alloc_possible()) { + tx_data = m_malloc(len); + } else { + tx_data = port_malloc(len, false); + used_port_malloc = true; + } + if (tx_data == NULL) { + return false; + } + memset(tx_data, write_value, len); + need_free = true; + } + + const struct spi_buf tx_buf = { + .buf = tx_data, + .len = tx_data ? len : 0 + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = tx_data ? 1 : 0 + }; + + const struct spi_buf rx_buf = { + .buf = data, + .len = len + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1 + }; + + // Initialize the signal for async operation + k_poll_signal_reset(&self->signal); + + int ret = spi_transceive_signal(self->spi_device, &self->config[self->active_config], &tx, &rx, &self->signal); + + if (need_free) { + if (used_port_malloc) { + port_free(tx_data); + } else { + m_free(tx_data); + } + } + + if (ret != 0) { + return false; + } + + // Wait for the transfer to complete while running background tasks + int signaled = 0; + int result = 0; + while (!signaled && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + k_poll_signal_check(&self->signal, &signaled, &result); + } + + return signaled && result == 0; +} + +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + if (len == 0) { + return true; + } + + const struct spi_buf tx_buf = { + .buf = (void *)data_out, + .len = len + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + const struct spi_buf rx_buf = { + .buf = data_in, + .len = len + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1 + }; + + // Initialize the signal for async operation + k_poll_signal_reset(&self->signal); + + int ret = spi_transceive_signal(self->spi_device, &self->config[self->active_config], &tx, &rx, &self->signal); + if (ret != 0) { + return false; + } + + // Wait for the transfer to complete while running background tasks + int signaled = 0; + int result = 0; + while (!signaled && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + k_poll_signal_check(&self->signal, &signaled, &result); + } + + return signaled && result == 0; +} + +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) { + return self->config[self->active_config].frequency; +} + +uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t *self) { + return (self->config[self->active_config].operation & SPI_MODE_CPHA) ? 1 : 0; +} + +uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { + return (self->config[self->active_config].operation & SPI_MODE_CPOL) ? 1 : 0; +} + +void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { + // Not needed for Zephyr port (devices are managed by Zephyr) +} diff --git a/ports/zephyr-cp/common-hal/busio/SPI.h b/ports/zephyr-cp/common-hal/busio/SPI.h new file mode 100644 index 00000000000..87411c9825c --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/SPI.h @@ -0,0 +1,24 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include +#include + +typedef struct { + mp_obj_base_t base; + const struct device *spi_device; + struct k_mutex mutex; + bool has_lock; + struct spi_config config[2]; // Two configs for pointer comparison by driver + uint8_t active_config; // Index of currently active config (0 or 1) + struct k_poll_signal signal; +} busio_spi_obj_t; + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_spi_construct_from_device(busio_spi_obj_t *self, const struct device *spi_device); diff --git a/ports/zephyr-cp/common-hal/busio/UART.c b/ports/zephyr-cp/common-hal/busio/UART.c new file mode 100644 index 00000000000..af1de0e9023 --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/UART.c @@ -0,0 +1,156 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/busio/UART.h" + +#include "shared/runtime/interrupt_char.h" +#include "py/mpconfig.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/stream.h" + +#include +#include + +#include +#include +LOG_MODULE_REGISTER(busio_uart); + +/* + * Read characters from UART until line end is detected. Afterwards push the + * data to the message queue. + */ +static void serial_cb(const struct device *dev, void *user_data) { + busio_uart_obj_t *self = (busio_uart_obj_t *)user_data; + + uint8_t c; + + uart_irq_update(dev); + + if (!uart_irq_rx_ready(dev)) { + return; + } + + /* read until FIFO empty */ + while (uart_fifo_read(dev, &c, 1) == 1) { + if (mp_interrupt_char == c) { + common_hal_busio_uart_clear_rx_buffer(self); + mp_sched_keyboard_interrupt(); + } else if (!self->rx_paused) { + if (k_msgq_put(&self->msgq, &c, K_NO_WAIT) != 0) { + self->rx_paused = true; + } + } + } +} + +void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) { + // Not needed for Zephyr port (devices are managed by Zephyr) +} + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_uart_construct_from_device(busio_uart_obj_t *self, const struct device *uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer) { + self->base.type = &busio_uart_type; + self->uart_device = uart_device; + int ret = uart_irq_callback_user_data_set(uart_device, serial_cb, self); + + if (ret < 0) { + LOG_ERR("Failed to set UART IRQ callback: %d", ret); + } + + k_msgq_init(&self->msgq, receiver_buffer, 1, receiver_buffer_size); + + self->timeout = K_FOREVER; + self->write_timeout = K_FOREVER; + self->rx_paused = false; + uart_irq_rx_enable(uart_device); + + return MP_OBJ_FROM_PTR(self); +} + +// Standard busio construct - not used in Zephyr port (devices come from device tree) +void common_hal_busio_uart_construct(busio_uart_obj_t *self, + const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, + const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, + const mcu_pin_obj_t *rs485_dir, bool rs485_invert, + uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, + mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, + bool sigint_enabled) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_UART); +} + +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { + return !device_is_ready(self->uart_device); +} + +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { + // Leave it active (managed by Zephyr) +} + +// Read characters. +size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { + size_t count = 0; + while (count < len && k_msgq_get(&self->msgq, data + count, self->timeout) == 0) { + count++; + } + if (count > 0) { + self->rx_paused = false; + } + + return count; +} + +// Write characters. +size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { + for (int i = 0; i < len; i++) { + uart_poll_out(self->uart_device, data[i]); + } + + return len; +} + +uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) { + struct uart_config config; + uart_config_get(self->uart_device, &config); + return config.baudrate; +} + +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) { + struct uart_config config; + uart_config_get(self->uart_device, &config); + config.baudrate = baudrate; + uart_configure(self->uart_device, &config); +} + +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { + return (mp_float_t)self->timeout.ticks / 1000000.0; +} + +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) { + self->timeout = K_USEC((uint64_t)(timeout * 1000000)); +} + +mp_float_t common_hal_busio_uart_get_write_timeout(busio_uart_obj_t *self) { + return (mp_float_t)self->write_timeout.ticks / 1000000.0; +} + +void common_hal_busio_uart_set_write_timeout(busio_uart_obj_t *self, mp_float_t write_timeout) { + self->write_timeout = K_USEC((uint64_t)(write_timeout * 1000000)); +} + +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { + return k_msgq_num_used_get(&self->msgq); +} + +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { + k_msgq_purge(&self->msgq); +} + +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { + return true; +} diff --git a/ports/zephyr-cp/common-hal/busio/UART.h b/ports/zephyr-cp/common-hal/busio/UART.h new file mode 100644 index 00000000000..be0b7ff83a9 --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/UART.h @@ -0,0 +1,33 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include + +typedef struct { + mp_obj_base_t base; + + const struct device *uart_device; + struct k_msgq msgq; + + k_timeout_t timeout; + k_timeout_t write_timeout; + + bool rx_paused; // set by irq if no space in rbuf +} busio_uart_obj_t; + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_uart_construct_from_device(busio_uart_obj_t *self, const struct device *uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer); + +// Internal helper for clearing buffer +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self); + +// Zephyr-port-specific write-timeout accessors, used by usb_cdc/Serial.c. +mp_float_t common_hal_busio_uart_get_write_timeout(busio_uart_obj_t *self); +void common_hal_busio_uart_set_write_timeout(busio_uart_obj_t *self, mp_float_t write_timeout); diff --git a/ports/zephyr-cp/common-hal/busio/__init__.c b/ports/zephyr-cp/common-hal/busio/__init__.c new file mode 100644 index 00000000000..135a53f4907 --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// No busio module functions. diff --git a/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.c b/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.c new file mode 100644 index 00000000000..494b21cb02d --- /dev/null +++ b/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.c @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/hostnetwork/HostNetwork.h" + +hostnetwork_hostnetwork_obj_t common_hal_hostnetwork_obj = { + .base = { &hostnetwork_hostnetwork_type }, +}; + +void common_hal_hostnetwork_hostnetwork_construct(hostnetwork_hostnetwork_obj_t *self) { + (void)self; +} diff --git a/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.h b/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.h new file mode 100644 index 00000000000..a6731546bde --- /dev/null +++ b/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "bindings/hostnetwork/HostNetwork.h" + +extern hostnetwork_hostnetwork_obj_t common_hal_hostnetwork_obj; diff --git a/ports/zephyr-cp/common-hal/microcontroller/Processor.c b/ports/zephyr-cp/common-hal/microcontroller/Processor.c index ddc8b97056d..54ae6b91c61 100644 --- a/ports/zephyr-cp/common-hal/microcontroller/Processor.c +++ b/ports/zephyr-cp/common-hal/microcontroller/Processor.c @@ -14,6 +14,34 @@ #include #include +#if defined(CONFIG_WIFI) +#include + +// Fallback for SoCs with no hwinfo driver, where hwinfo_get_device_id() returns +// -ENOSYS and cpu.uid would otherwise be all zeros. A WiFi link address is +// per-device, so it is a better answer than nothing, and at least one vendor +// (Silicon Labs, for the siwx91x) defines that part's unique ID as exactly this: +// the WiFi MAC zero-extended to eight bytes. +// +// This is not a burned-in serial. A MAC can generally be reprogrammed by vendor +// tooling, so cpu.uid must not be relied on as tamper proof where it comes from +// here. Boards whose SoC has a real hwinfo driver never reach this path. +static ssize_t uid_from_wifi_mac(uint8_t raw_id[]) { + if (COMMON_HAL_MCU_PROCESSOR_UID_LENGTH < 8) { + return -1; + } + struct net_if *iface = net_if_get_first_wifi(); + struct net_linkaddr *addr = (iface != NULL) ? net_if_get_link_addr(iface) : NULL; + if (addr == NULL || addr->len != 6) { + return -1; + } + raw_id[0] = 0; + raw_id[1] = 0; + memcpy(&raw_id[2], addr->addr, 6); + return 8; +} +#endif + float common_hal_mcu_processor_get_temperature(void) { return 0.0; @@ -21,7 +49,11 @@ float common_hal_mcu_processor_get_temperature(void) { extern uint32_t SystemCoreClock; uint32_t common_hal_mcu_processor_get_frequency(void) { + #ifdef __ARM__ return SystemCoreClock; + #else + return CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; + #endif } float common_hal_mcu_processor_get_voltage(void) { @@ -30,6 +62,14 @@ float common_hal_mcu_processor_get_voltage(void) { void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { ssize_t len = hwinfo_get_device_id(raw_id, COMMON_HAL_MCU_PROCESSOR_UID_LENGTH); + #if defined(CONFIG_WIFI) + if (len < 0) { + ssize_t mac_len = uid_from_wifi_mac(raw_id); + if (mac_len > 0) { + len = mac_len; + } + } + #endif if (len < 0) { printk("UID retrieval failed: %d\n", len); len = 0; @@ -41,6 +81,21 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - mcu_reset_reason_t r = RESET_REASON_UNKNOWN; - return r; + #if defined(CONFIG_HWINFO) + uint32_t cause = 0; + if (hwinfo_get_reset_cause(&cause) == 0) { + if (cause & RESET_POR) { + return MCU_RESET_REASON_POWER_ON; + } else if (cause & RESET_SOFTWARE) { + return MCU_RESET_REASON_SOFTWARE; + } else if (cause & RESET_WATCHDOG) { + return MCU_RESET_REASON_WATCHDOG; + } else if (cause & RESET_BROWNOUT) { + return MCU_RESET_REASON_BROWNOUT; + } else if (cause & RESET_PIN) { + return MCU_RESET_REASON_RESET_PIN; + } + } + #endif + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/zephyr-cp/common-hal/microcontroller/__init__.c b/ports/zephyr-cp/common-hal/microcontroller/__init__.c index 6ebf5f4c368..be33cd26c9a 100644 --- a/ports/zephyr-cp/common-hal/microcontroller/__init__.c +++ b/ports/zephyr-cp/common-hal/microcontroller/__init__.c @@ -11,7 +11,7 @@ #include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Processor.h" -// #include "shared-bindings/nvm/ByteArray.h" +#include "shared-bindings/nvm/ByteArray.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Processor.h" @@ -93,14 +93,12 @@ const mcu_processor_obj_t common_hal_mcu_processor_obj = { }, }; -#if CIRCUITPY_NVM && CIRCUITPY_INTERNAL_NVM_SIZE > 0 +#if CIRCUITPY_NVM // The singleton nvm.ByteArray object. const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = { .base = { .type = &nvm_bytearray_type, }, - .start_address = (uint8_t *)CIRCUITPY_INTERNAL_NVM_START_ADDR, - .len = CIRCUITPY_INTERNAL_NVM_SIZE, }; #endif diff --git a/ports/zephyr-cp/common-hal/nvm/ByteArray.c b/ports/zephyr-cp/common-hal/nvm/ByteArray.c new file mode 100644 index 00000000000..b8f552d6773 --- /dev/null +++ b/ports/zephyr-cp/common-hal/nvm/ByteArray.c @@ -0,0 +1,103 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "common-hal/nvm/ByteArray.h" +#include "shared-bindings/nvm/ByteArray.h" + +#include + +#include +#include + +#define NVM_PARTITION nvm_partition + +#if FIXED_PARTITION_EXISTS(NVM_PARTITION) + +static const struct flash_area *nvm_area = NULL; +static size_t nvm_erase_size = 0; + +static bool ensure_nvm_open(void) { + if (nvm_area != NULL) { + return true; + } + int rc = flash_area_open(FIXED_PARTITION_ID(NVM_PARTITION), &nvm_area); + if (rc != 0) { + return false; + } + + const struct device *dev = flash_area_get_device(nvm_area); + struct flash_pages_info info; + flash_get_page_info_by_offs(dev, nvm_area->fa_off, &info); + nvm_erase_size = info.size; + + return true; +} + +uint32_t common_hal_nvm_bytearray_get_length(const nvm_bytearray_obj_t *self) { + if (!ensure_nvm_open()) { + return 0; + } + return nvm_area->fa_size; +} + +bool common_hal_nvm_bytearray_set_bytes(const nvm_bytearray_obj_t *self, + uint32_t start_index, uint8_t *values, uint32_t len) { + if (!ensure_nvm_open()) { + return false; + } + + uint32_t address = start_index; + while (len > 0) { + uint32_t page_offset = address % nvm_erase_size; + uint32_t page_start = address - page_offset; + uint32_t write_len = MIN(len, nvm_erase_size - page_offset); + + uint8_t *buffer = m_malloc(nvm_erase_size); + if (buffer == NULL) { + return false; + } + + // Read the full erase page. + int rc = flash_area_read(nvm_area, page_start, buffer, nvm_erase_size); + if (rc != 0) { + m_free(buffer); + return false; + } + + // Modify the relevant bytes. + memcpy(buffer + page_offset, values, write_len); + + // Erase the page. + rc = flash_area_erase(nvm_area, page_start, nvm_erase_size); + if (rc != 0) { + m_free(buffer); + return false; + } + + // Write the page back. + rc = flash_area_write(nvm_area, page_start, buffer, nvm_erase_size); + m_free(buffer); + if (rc != 0) { + return false; + } + + address += write_len; + values += write_len; + len -= write_len; + } + return true; +} + +void common_hal_nvm_bytearray_get_bytes(const nvm_bytearray_obj_t *self, + uint32_t start_index, uint32_t len, uint8_t *values) { + if (!ensure_nvm_open()) { + return; + } + flash_area_read(nvm_area, start_index, values, len); +} + +#endif // FIXED_PARTITION_EXISTS(NVM_PARTITION) diff --git a/ports/zephyr-cp/common-hal/nvm/ByteArray.h b/ports/zephyr-cp/common-hal/nvm/ByteArray.h new file mode 100644 index 00000000000..9c771aaa3a9 --- /dev/null +++ b/ports/zephyr-cp/common-hal/nvm/ByteArray.h @@ -0,0 +1,13 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +} nvm_bytearray_obj_t; diff --git a/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.c b/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.c new file mode 100644 index 00000000000..d36b571535a --- /dev/null +++ b/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.c @@ -0,0 +1,129 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include "common-hal/rotaryio/IncrementalEncoder.h" +#include "shared-bindings/rotaryio/IncrementalEncoder.h" +#include "shared-module/rotaryio/IncrementalEncoder.h" + +#include "bindings/zephyr_kernel/__init__.h" +#include "py/runtime.h" + +#include +#include +#include +#include + +static void incrementalencoder_gpio_callback(const struct device *port, + struct gpio_callback *cb, gpio_port_pins_t pins) { + (void)port; + (void)pins; + rotaryio_incrementalencoder_gpio_callback_t *callback = + CONTAINER_OF(cb, rotaryio_incrementalencoder_gpio_callback_t, callback); + rotaryio_incrementalencoder_obj_t *self = callback->encoder; + if (self == NULL || self->pin_a == NULL) { + return; + } + + int a = gpio_pin_get(self->pin_a->port, self->pin_a->number); + int b = gpio_pin_get(self->pin_b->port, self->pin_b->number); + if (a < 0 || b < 0) { + return; + } + uint8_t new_state = ((uint8_t)a << 1) | (uint8_t)b; + shared_module_softencoder_state_update(self, new_state); +} + +void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t *self, + const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b) { + // Ensure object starts in its deinit state. + common_hal_rotaryio_incrementalencoder_mark_deinit(self); + + self->pin_a = pin_a; + self->pin_b = pin_b; + self->divisor = 4; + + if (!device_is_ready(pin_a->port) || !device_is_ready(pin_b->port)) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(-ENODEV); + } + + int result = gpio_pin_configure(pin_a->port, pin_a->number, GPIO_INPUT | GPIO_PULL_UP); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + result = gpio_pin_configure(pin_b->port, pin_b->number, GPIO_INPUT | GPIO_PULL_UP); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + self->callback_a.encoder = self; + gpio_init_callback(&self->callback_a.callback, incrementalencoder_gpio_callback, + BIT(pin_a->number)); + result = gpio_add_callback(pin_a->port, &self->callback_a.callback); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + self->callback_b.encoder = self; + gpio_init_callback(&self->callback_b.callback, incrementalencoder_gpio_callback, + BIT(pin_b->number)); + result = gpio_add_callback(pin_b->port, &self->callback_b.callback); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + result = gpio_pin_interrupt_configure(pin_a->port, pin_a->number, GPIO_INT_EDGE_BOTH); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + result = gpio_pin_interrupt_configure(pin_b->port, pin_b->number, GPIO_INT_EDGE_BOTH); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + int a = gpio_pin_get(pin_a->port, pin_a->number); + int b = gpio_pin_get(pin_b->port, pin_b->number); + uint8_t quiescent_state = ((uint8_t)(a > 0) << 1) | (uint8_t)(b > 0); + shared_module_softencoder_state_init(self, quiescent_state); + + claim_pin(pin_a); + claim_pin(pin_b); +} + +bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self) { + return self->pin_a == NULL; +} + +void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t *self) { + if (common_hal_rotaryio_incrementalencoder_deinited(self)) { + return; + } + + // Best-effort cleanup. During failed construct(), some of these may not be + // initialized yet. Ignore cleanup errors. + gpio_pin_interrupt_configure(self->pin_a->port, self->pin_a->number, GPIO_INT_DISABLE); + gpio_pin_interrupt_configure(self->pin_b->port, self->pin_b->number, GPIO_INT_DISABLE); + gpio_remove_callback(self->pin_a->port, &self->callback_a.callback); + gpio_remove_callback(self->pin_b->port, &self->callback_b.callback); + + reset_pin(self->pin_a); + reset_pin(self->pin_b); + + common_hal_rotaryio_incrementalencoder_mark_deinit(self); +} + +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { + self->pin_a = NULL; + self->pin_b = NULL; +} diff --git a/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.h b/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.h new file mode 100644 index 00000000000..a0d2bb392e2 --- /dev/null +++ b/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.h @@ -0,0 +1,31 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "common-hal/microcontroller/Pin.h" +#include "py/obj.h" + +typedef struct rotaryio_incrementalencoder_obj rotaryio_incrementalencoder_obj_t; + +typedef struct { + struct gpio_callback callback; + rotaryio_incrementalencoder_obj_t *encoder; +} rotaryio_incrementalencoder_gpio_callback_t; + +struct rotaryio_incrementalencoder_obj { + mp_obj_base_t base; + const mcu_pin_obj_t *pin_a; + const mcu_pin_obj_t *pin_b; + rotaryio_incrementalencoder_gpio_callback_t callback_a; + rotaryio_incrementalencoder_gpio_callback_t callback_b; + uint8_t state; // + int8_t sub_count; // count intermediate transitions between detents + int8_t divisor; // Number of quadrature edges required per count + mp_int_t position; +}; diff --git a/ports/zephyr-cp/common-hal/zephyr_spi/__init__.c b/ports/zephyr-cp/common-hal/rotaryio/__init__.c similarity index 84% rename from ports/zephyr-cp/common-hal/zephyr_spi/__init__.c rename to ports/zephyr-cp/common-hal/rotaryio/__init__.c index d3a4d472733..67cae26a8b7 100644 --- a/ports/zephyr-cp/common-hal/zephyr_spi/__init__.c +++ b/ports/zephyr-cp/common-hal/rotaryio/__init__.c @@ -4,4 +4,4 @@ // // SPDX-License-Identifier: MIT -// No zephyr_spi module functions. +// No rotaryio module functions. diff --git a/ports/zephyr-cp/common-hal/socketpool/Socket.c b/ports/zephyr-cp/common-hal/socketpool/Socket.c index 857526a12de..bb626857a98 100644 --- a/ports/zephyr-cp/common-hal/socketpool/Socket.c +++ b/ports/zephyr-cp/common-hal/socketpool/Socket.c @@ -20,165 +20,110 @@ #include "supervisor/shared/tick.h" #include "supervisor/workflow.h" -#include - -// void socketpool_resolve_host_or_throw(int family, int type, const char *hostname, struct sockaddr_storage *addr, int port) { -// // struct addrinfo *result_i; -// // const struct addrinfo hints = { -// // .ai_family = family, -// // .ai_socktype = type, -// // }; -// // int error = socketpool_getaddrinfo_common(hostname, port, &hints, &result_i); -// if (true) { -// common_hal_socketpool_socketpool_raise_gaierror_noname(); -// } -// // memcpy(addr, result_i->ai_addr, sizeof(struct sockaddr_storage)); -// // lwip_freeaddrinfo(result_i); -// } - -// static void resolve_host_or_throw(socketpool_socket_obj_t *self, const char *hostname, struct sockaddr_storage *addr, int port) { -// socketpool_resolve_host_or_throw(self->family, self->type, hostname, addr, port); -// } - -// StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE]; - -// /* Socket state table: -// * 0 := Closed (unused) -// * 1 := Open -// * 2 := Closing (remove from rfds) -// * Index into socket_fd_state is calculated from actual lwip fd. idx := fd - LWIP_SOCKET_OFFSET -// */ -// #define FDSTATE_CLOSED 0 -// #define FDSTATE_OPEN 1 -// #define FDSTATE_CLOSING 2 -// static uint8_t socket_fd_state[CONFIG_LWIP_MAX_SOCKETS]; +#include +#include +#include +#include +#include -// How long to wait between checks for a socket to connect. -#define SOCKET_CONNECT_POLL_INTERVAL_MS 100 +#include +#include +#include -// static socketpool_socket_obj_t *user_socket[CONFIG_LWIP_MAX_SOCKETS]; -// StaticTask_t socket_select_task_buffer; -// TaskHandle_t socket_select_task_handle; -// static int socket_change_fd = -1; - -// static void socket_select_task(void *arg) { -// uint64_t signal; -// fd_set readfds; -// fd_set excptfds; - -// while (true) { -// FD_ZERO(&readfds); -// FD_ZERO(&excptfds); -// FD_SET(socket_change_fd, &readfds); -// int max_fd = socket_change_fd; -// for (size_t i = 0; i < MP_ARRAY_SIZE(socket_fd_state); i++) { -// if ((socket_fd_state[i] == FDSTATE_OPEN) && (user_socket[i] == NULL)) { -// int sockfd = i + LWIP_SOCKET_OFFSET; -// max_fd = MAX(max_fd, sockfd); -// FD_SET(sockfd, &readfds); -// FD_SET(sockfd, &excptfds); -// } -// } - -// int num_triggered = select(max_fd + 1, &readfds, NULL, &excptfds, NULL); -// // Hard error (or someone closed a socket on another thread) -// if (num_triggered == -1) { -// assert(errno == EBADF); -// continue; -// } - -// assert(num_triggered > 0); - -// // Notice event trigger -// if (FD_ISSET(socket_change_fd, &readfds)) { -// read(socket_change_fd, &signal, sizeof(signal)); -// num_triggered--; -// } - -// // Handle active FDs, close the dead ones -// for (size_t i = 0; i < MP_ARRAY_SIZE(socket_fd_state); i++) { -// int sockfd = i + LWIP_SOCKET_OFFSET; -// if (socket_fd_state[i] != FDSTATE_CLOSED) { -// if (FD_ISSET(sockfd, &readfds) || FD_ISSET(sockfd, &excptfds)) { -// if (socket_fd_state[i] == FDSTATE_CLOSING) { -// socket_fd_state[i] = FDSTATE_CLOSED; -// num_triggered--; -// } -// } -// } -// } - -// if (num_triggered > 0) { -// // Wake up CircuitPython by queuing request -// supervisor_workflow_request_background(); -// ulTaskNotifyTake(pdTRUE, portMAX_DELAY); -// } -// } - -// close(socket_change_fd); -// socket_change_fd = -1; -// vTaskDelete(NULL); -// } +#define SOCKETPOOL_IP_STR_LEN 48 -void socket_user_reset(void) { - // if (socket_change_fd < 0) { - // esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT(); - // ESP_ERROR_CHECK(esp_vfs_eventfd_register(&config)); - - // // Clear initial socket states - // for (size_t i = 0; i < MP_ARRAY_SIZE(socket_fd_state); i++) { - // socket_fd_state[i] = FDSTATE_CLOSED; - // user_socket[i] = NULL; - // } - // socket_change_fd = eventfd(0, 0); - // // Run this at the same priority as CP so that the web workflow background task can be - // // queued while CP is running. Both tasks can still sleep and, therefore, sleep overall. - // socket_select_task_handle = xTaskCreateStaticPinnedToCore(socket_select_task, - // "socket_select", - // 2 * configMINIMAL_STACK_SIZE, - // NULL, - // uxTaskPriorityGet(NULL), - // socket_select_stack, - // &socket_select_task_buffer, - // xPortGetCoreID()); - // } else { - // // Not init - close open user sockets - // for (size_t i = 0; i < MP_ARRAY_SIZE(socket_fd_state); i++) { - // if ((socket_fd_state[i] == FDSTATE_OPEN) && user_socket[i]) { - // common_hal_socketpool_socket_close(user_socket[i]); - // } - // } - // } +static mp_obj_t _format_address(const struct sockaddr *addr, int family) { + char ip_str[SOCKETPOOL_IP_STR_LEN]; + const struct sockaddr_in *a = (void *)addr; + + switch (family) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + case AF_INET6: + zsock_inet_ntop(family, &((const struct sockaddr_in6 *)a)->sin6_addr, ip_str, sizeof(ip_str)); + break; + #endif + default: + case AF_INET: + zsock_inet_ntop(family, &((const struct sockaddr_in *)a)->sin_addr, ip_str, sizeof(ip_str)); + break; + } + return mp_obj_new_str(ip_str, strlen(ip_str)); } -// Unblock select task (ok if not blocked yet) -void socketpool_socket_poll_resume(void) { - // if (socket_select_task_handle) { - // xTaskNotifyGive(socket_select_task_handle); - // } +static mp_obj_t _sockaddr_to_tuple(const struct sockaddr_storage *sockaddr) { + mp_obj_t args[4] = { + _format_address((const struct sockaddr *)sockaddr, sockaddr->ss_family), + }; + int n = 2; + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (sockaddr->ss_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const void *)sockaddr; + args[1] = MP_OBJ_NEW_SMALL_INT(ntohs(addr6->sin6_port)); + args[2] = MP_OBJ_NEW_SMALL_INT(addr6->sin6_flowinfo); + args[3] = MP_OBJ_NEW_SMALL_INT(addr6->sin6_scope_id); + n = 4; + } else + #endif + { + const struct sockaddr_in *addr = (const void *)sockaddr; + args[1] = MP_OBJ_NEW_SMALL_INT(ntohs(addr->sin_port)); + } + return mp_obj_new_tuple(n, args); } -// The writes below send an event to the socket select task so that it redoes the -// select with the new open socket set. +static void socketpool_resolve_host_or_throw(int family, int type, const char *hostname, struct sockaddr_storage *addr, int port) { + const struct zsock_addrinfo hints = { + .ai_family = family, + .ai_socktype = type, + }; + struct zsock_addrinfo *result_i = NULL; + char service_buf[6]; + + snprintf(service_buf, sizeof(service_buf), "%d", port); + + int error = zsock_getaddrinfo(hostname, service_buf, &hints, &result_i); + if (error != 0 || result_i == NULL) { + // Report what the resolver said. A null result with no error is the + // one case that really is "not found". + if (error == 0) { + error = DNS_EAI_NONAME; + } + common_hal_socketpool_socketpool_raise_gaierror(error); + } -// static bool register_open_socket(int fd) { -// if (fd < FD_SETSIZE) { -// socket_fd_state[fd - LWIP_SOCKET_OFFSET] = FDSTATE_OPEN; -// user_socket[fd - LWIP_SOCKET_OFFSET] = NULL; + memcpy(addr, result_i->ai_addr, sizeof(struct sockaddr_storage)); + zsock_freeaddrinfo(result_i); +} -// uint64_t signal = 1; -// write(socket_change_fd, &signal, sizeof(signal)); -// socketpool_socket_poll_resume(); -// return true; -// } -// return false; -// } +static void resolve_host_or_throw(socketpool_socket_obj_t *self, const char *hostname, struct sockaddr_storage *addr, int port) { + socketpool_resolve_host_or_throw(self->family, self->type, hostname, addr, port); +} -// static void mark_user_socket(int fd, socketpool_socket_obj_t *obj) { -// socket_fd_state[fd - LWIP_SOCKET_OFFSET] = FDSTATE_OPEN; -// user_socket[fd - LWIP_SOCKET_OFFSET] = obj; -// // No need to wakeup select task -// } +// How long to wait between checks for a socket to connect. +#define SOCKET_CONNECT_POLL_INTERVAL_MS 100 + +void socket_user_reset(void) { + // User sockets are heap objects with __del__ bound to close(). + // During VM shutdown/reset, gc_sweep_all() runs finalizers, so sockets + // are closed there rather than being tracked and closed explicitly here. +} + +static struct k_work_delayable socketpool_poll_work; +static bool socketpool_poll_work_initialized; + +static void socketpool_poll_work_handler(struct k_work *work) { + (void)work; + supervisor_workflow_request_background(); +} + +// Unblock select task (ok if not blocked yet) +void socketpool_socket_poll_resume(void) { + if (!socketpool_poll_work_initialized) { + k_work_init_delayable(&socketpool_poll_work, socketpool_poll_work_handler); + socketpool_poll_work_initialized = true; + } + k_work_schedule(&socketpool_poll_work, K_MSEC(10)); +} static bool _socketpool_socket(socketpool_socketpool_obj_t *self, socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type, @@ -212,16 +157,23 @@ static bool _socketpool_socket(socketpool_socketpool_obj_t *self, sock->pool = self; sock->timeout_ms = (uint)-1; - // Create LWIP socket - // int socknum = -1; - // socknum = lwip_socket(sock->family, sock->type, sock->ipproto); - // if (socknum < 0) { - // return false; - // } + int socknum = zsock_socket(sock->family, sock->type, sock->ipproto); + if (socknum < 0) { + return false; + } + + sock->num = socknum; - // sock->num = socknum; - // // Sockets should be nonblocking in most cases - // lwip_fcntl(socknum, F_SETFL, O_NONBLOCK); + // Enable address reuse by default to avoid bind failures on recently-used ports. + int reuseaddr = 1; + if (zsock_setsockopt(socknum, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) < 0) { + // Ignore if SO_REUSEADDR is unsupported. + } + + // Sockets should be nonblocking in most cases. + if (zsock_fcntl(socknum, F_SETFL, ZVFS_O_NONBLOCK) < 0) { + // Ignore if non-blocking is unsupported. + } return true; } @@ -235,11 +187,6 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self, return false; } - // This shouldn't happen since we have room for the same number of sockets as LWIP. - // if (!register_open_socket(sock->num)) { - // lwip_close(sock->num); - // return false; - // } return true; } @@ -260,13 +207,12 @@ socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_ if (!_socketpool_socket(self, family, type, proto, sock)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Out of sockets")); } - // mark_user_socket(sock->num, sock); return sock; } int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, socketpool_socket_obj_t *accepted) { struct sockaddr_storage peer_addr; - // socklen_t socklen = sizeof(peer_addr); + socklen_t socklen = sizeof(peer_addr); int newsoc = -1; bool timed_out = false; uint64_t start_ticks = supervisor_ticks_ms64(); @@ -277,11 +223,14 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; } RUN_BACKGROUND_TASKS; - // newsoc = lwip_accept(self->num, (struct sockaddr *)&peer_addr, &socklen); + newsoc = zsock_accept(self->num, (struct sockaddr *)&peer_addr, &socklen); // In non-blocking mode, fail instead of timing out if (newsoc == -1 && (self->timeout_ms == 0 || mp_hal_is_interrupted())) { return -MP_EAGAIN; } + if (newsoc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { + return -errno; + } } if (timed_out) { @@ -293,18 +242,14 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, } // We got a socket. New client socket will not be non-blocking by default, so make it non-blocking. - // lwip_fcntl(newsoc, F_SETFL, O_NONBLOCK); + if (zsock_fcntl(newsoc, F_SETFL, ZVFS_O_NONBLOCK) < 0) { + // Ignore if non-blocking is unsupported. + } if (accepted != NULL) { // Error if called with open socket object. assert(common_hal_socketpool_socket_get_closed(accepted)); - // Register if system socket - // if (!register_open_socket(newsoc)) { - // lwip_close(newsoc); - // return -MP_EBADF; - // } - // Replace the old accepted socket with the new one. accepted->num = newsoc; accepted->pool = self->pool; @@ -313,7 +258,7 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, } if (peer_out) { - *peer_out = sockaddr_to_tuple(&peer_addr); + *peer_out = _sockaddr_to_tuple(&peer_addr); } return newsoc; @@ -327,7 +272,6 @@ socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_o if (newsoc > 0) { // Create the socket - // mark_user_socket(newsoc, sock); sock->base.type = &socketpool_socket_type; sock->num = newsoc; sock->pool = self->pool; @@ -343,40 +287,42 @@ socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_o size_t common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port) { - // struct sockaddr_storage bind_addr; + struct sockaddr_storage bind_addr; const char *broadcast = ""; + uint32_t local_port = port; - // bind_addr.ss_family = self->family; + memset(&bind_addr, 0, sizeof(bind_addr)); + bind_addr.ss_family = self->family; #if CIRCUITPY_SOCKETPOOL_IPV6 if (self->family == AF_INET6) { struct sockaddr_in6 *addr6 = (void *)&bind_addr; - addr6->sin6_port = htons(port); + addr6->sin6_port = htons(local_port); // no ipv6 broadcast if (hostlen == 0) { memset(&addr6->sin6_addr, 0, sizeof(addr6->sin6_addr)); } else { - socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, port); + socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, local_port); } } else #endif { - // struct sockaddr_in *addr4 = (void *)&bind_addr; - // addr4->sin_port = htons(port); + struct sockaddr_in *addr4 = (void *)&bind_addr; + addr4->sin_port = htons(local_port); if (hostlen == 0) { - // addr4->sin_addr.s_addr = IPADDR_ANY; + addr4->sin_addr.s_addr = htonl(INADDR_ANY); } else if (hostlen == strlen(broadcast) && memcmp(host, broadcast, strlen(broadcast)) == 0) { - // addr4->sin_addr.s_addr = IPADDR_BROADCAST; + addr4->sin_addr.s_addr = htonl(INADDR_BROADCAST); } else { - // socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, port); + socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, local_port); } } - // int result = lwip_bind(self->num, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); - // if (result == 0) { - // return 0; - // } + int result = zsock_bind(self->num, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); + if (result == 0) { + return 0; + } return errno; } @@ -390,20 +336,11 @@ void socketpool_socket_close(socketpool_socket_obj_t *self) { } #endif self->connected = false; - // int fd = self->num; - // Ignore bogus/closed sockets - // if (fd >= LWIP_SOCKET_OFFSET) { - // if (user_socket[fd - LWIP_SOCKET_OFFSET] == NULL) { - // socket_fd_state[fd - LWIP_SOCKET_OFFSET] = FDSTATE_CLOSING; - // lwip_shutdown(fd, SHUT_RDWR); - // lwip_close(fd); - // } else { - // lwip_shutdown(fd, SHUT_RDWR); - // lwip_close(fd); - // socket_fd_state[fd - LWIP_SOCKET_OFFSET] = FDSTATE_CLOSED; - // user_socket[fd - LWIP_SOCKET_OFFSET] = NULL; - // } - // } + int fd = self->num; + if (fd >= 0) { + zsock_shutdown(fd, ZSOCK_SHUT_RDWR); + zsock_close(fd); + } self->num = -1; } @@ -413,16 +350,11 @@ void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) { void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port) { - // struct sockaddr_storage addr; - // resolve_host_or_throw(self, host, &addr, port); - - // Replace above with function call ----- + (void)hostlen; + struct sockaddr_storage addr; + resolve_host_or_throw(self, host, &addr, port); - // Emulate SO_CONTIMEO, which is not implemented by lwip. - // All our sockets are non-blocking, so we check the timeout ourselves. - - int result = -1; - // result = lwip_connect(self->num, (struct sockaddr *)&addr, addr.s2_len); + int result = zsock_connect(self->num, (struct sockaddr *)&addr, sizeof(addr)); if (result == 0) { // Connected immediately. @@ -436,12 +368,7 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, return; } - // struct timeval timeout = { - // .tv_sec = 0, - // .tv_usec = SOCKET_CONNECT_POLL_INTERVAL_MS * 1000, - // }; - - // Keep checking, using select(), until timeout expires, at short intervals. + // Keep checking, using poll(), until timeout expires, at short intervals. // This allows ctrl-C interrupts to be detected and background tasks to run. mp_uint_t timeout_left = self->timeout_ms; @@ -452,14 +379,22 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, return; } - // fd_set fds; - // FD_ZERO(&fds); - // FD_SET(self->num, &fds); + struct zsock_pollfd fd = { + .fd = self->num, + .events = ZSOCK_POLLOUT, + }; + int poll_timeout = SOCKET_CONNECT_POLL_INTERVAL_MS; + if (self->timeout_ms == (uint)-1) { + poll_timeout = -1; + } else if (timeout_left < SOCKET_CONNECT_POLL_INTERVAL_MS) { + poll_timeout = timeout_left; + } - // result = select(self->num + 1, NULL, &fds, NULL, &timeout); + result = zsock_poll(&fd, 1, poll_timeout); if (result == 0) { - // No change to fd's after waiting for timeout, so try again if some time is still left. - // Don't wrap below 0, because we're using a uint. + if (self->timeout_ms == (uint)-1) { + continue; + } if (timeout_left < SOCKET_CONNECT_POLL_INTERVAL_MS) { timeout_left = 0; } else { @@ -469,16 +404,14 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, } if (result < 0) { - // Some error happened when doing select(); error is in errno. mp_raise_OSError(errno); } - // select() indicated the socket is writable. Check if any connection error occurred. int error_code = 0; - // socklen_t socklen = sizeof(error_code); - // result = getsockopt(self->num, SOL_SOCKET, SO_ERROR, &error_code, &socklen); + socklen_t socklen = sizeof(error_code); + result = zsock_getsockopt(self->num, SOL_SOCKET, SO_ERROR, &error_code, &socklen); if (result < 0 || error_code != 0) { - mp_raise_OSError(errno); + mp_raise_OSError(error_code != 0 ? error_code : errno); } self->connected = true; return; @@ -498,17 +431,15 @@ bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t *self) { } bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *self, int backlog) { - // return lwip_listen(self->num, backlog) == 0; - return false; + return zsock_listen(self->num, backlog) == 0; } mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *self, uint8_t *buf, uint32_t len, mp_obj_t *source_out) { - // struct sockaddr_storage source_addr; - // socklen_t socklen = sizeof(source_addr); + struct sockaddr_storage source_addr; + socklen_t socklen = sizeof(source_addr); - // LWIP Socket uint64_t start_ticks = supervisor_ticks_ms64(); int received = -1; bool timed_out = false; @@ -519,11 +450,18 @@ mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *se timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; } RUN_BACKGROUND_TASKS; - // received = lwip_recvfrom(self->num, buf, len, 0, (struct sockaddr *)&source_addr, &socklen); + received = zsock_recvfrom(self->num, buf, len, ZSOCK_MSG_DONTWAIT, (struct sockaddr *)&source_addr, &socklen); - // In non-blocking mode, fail instead of looping - if (received == -1 && self->timeout_ms == 0) { - mp_raise_OSError(MP_EAGAIN); + if (received < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + mp_raise_OSError(errno); + } + + if (received == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + // In non-blocking mode, fail instead of looping + if (self->timeout_ms == 0) { + mp_raise_OSError(MP_EAGAIN); + } + continue; } } @@ -537,7 +475,7 @@ mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *se } if (source_out) { - // *source_out = sockaddr_to_tuple(&source_addr); + *source_out = _sockaddr_to_tuple(&source_addr); } return received; @@ -549,7 +487,6 @@ int socketpool_socket_recv_into(socketpool_socket_obj_t *self, bool timed_out = false; if (self->num != -1) { - // LWIP Socket uint64_t start_ticks = supervisor_ticks_ms64(); received = -1; while (received == -1 && @@ -558,7 +495,16 @@ int socketpool_socket_recv_into(socketpool_socket_obj_t *self, timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; } RUN_BACKGROUND_TASKS; - // received = lwip_recv(self->num, (void *)buf, len, 0); + received = zsock_recv(self->num, (void *)buf, len, ZSOCK_MSG_DONTWAIT); + if (received < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + return -errno; + } + if (received < 1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + if (self->timeout_ms == 0) { + return -MP_EAGAIN; + } + continue; + } // In non-blocking mode, fail instead of looping if (received < 1 && self->timeout_ms == 0) { if ((received == 0) || (errno == ENOTCONN)) { @@ -597,9 +543,7 @@ mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t *self, int socketpool_socket_send(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len) { int sent = -1; if (self->num != -1) { - // LWIP Socket - // TODO: deal with potential failure/add timeout? - // sent = lwip_send(self->num, buf, len, 0); + sent = zsock_send(self->num, buf, len, 0); } else { sent = -MP_EBADF; } @@ -626,15 +570,15 @@ mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t *self, const mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port, const uint8_t *buf, uint32_t len) { - // struct sockaddr_storage addr; - // resolve_host_or_throw(self, host, &addr, port); + (void)hostlen; + struct sockaddr_storage addr; + resolve_host_or_throw(self, host, &addr, port); - // int bytes_sent = lwip_sendto(self->num, buf, len, 0, (struct sockaddr *)&addr, addr.s2_len); - // if (bytes_sent < 0) { - // mp_raise_BrokenPipeError(); - // return 0; - // } - int bytes_sent = 0; + int bytes_sent = zsock_sendto(self->num, buf, len, 0, (struct sockaddr *)&addr, sizeof(addr)); + if (bytes_sent < 0) { + mp_raise_BrokenPipeError(); + return 0; + } return bytes_sent; } @@ -648,7 +592,44 @@ mp_int_t common_hal_socketpool_socket_get_type(socketpool_socket_obj_t *self) { int common_hal_socketpool_socket_setsockopt(socketpool_socket_obj_t *self, int level, int optname, const void *value, size_t optlen) { - int err = 0; // lwip_setsockopt(self->num, level, optname, value, optlen); + int zephyr_level = level; + int zephyr_optname = optname; + + switch (level) { + case SOCKETPOOL_SOL_SOCKET: + zephyr_level = SOL_SOCKET; + break; + case SOCKETPOOL_IPPROTO_IP: + zephyr_level = IPPROTO_IP; + break; + case SOCKETPOOL_IPPROTO_TCP: + zephyr_level = IPPROTO_TCP; + break; + case SOCKETPOOL_IPPROTO_UDP: + zephyr_level = IPPROTO_UDP; + break; + #if CIRCUITPY_SOCKETPOOL_IPV6 + case SOCKETPOOL_IPPROTO_IPV6: + zephyr_level = IPPROTO_IPV6; + break; + #endif + } + + if (zephyr_level == SOL_SOCKET) { + switch (optname) { + case SOCKETPOOL_SO_REUSEADDR: + zephyr_optname = SO_REUSEADDR; + break; + } + } else if (zephyr_level == IPPROTO_TCP) { + switch (optname) { + case SOCKETPOOL_TCP_NODELAY: + zephyr_optname = TCP_NODELAY; + break; + } + } + + int err = zsock_setsockopt(self->num, zephyr_level, zephyr_optname, value, optlen); if (err != 0) { return -errno; } @@ -656,29 +637,23 @@ int common_hal_socketpool_socket_setsockopt(socketpool_socket_obj_t *self, int l } bool common_hal_socketpool_readable(socketpool_socket_obj_t *self) { - // struct timeval immediate = {0, 0}; + struct zsock_pollfd fd = { + .fd = self->num, + .events = ZSOCK_POLLIN, + }; - // fd_set fds; - // FD_ZERO(&fds); - // FD_SET(self->num, &fds); - // int num_triggered = select(self->num + 1, &fds, NULL, &fds, &immediate); - - // including returning true in the error case - // return num_triggered != 0; - return false; + int num_triggered = zsock_poll(&fd, 1, 0); + return num_triggered > 0; } bool common_hal_socketpool_writable(socketpool_socket_obj_t *self) { - // struct timeval immediate = {0, 0}; - - // fd_set fds; - // FD_ZERO(&fds); - // FD_SET(self->num, &fds); - // int num_triggered = select(self->num + 1, NULL, &fds, &fds, &immediate); + struct zsock_pollfd fd = { + .fd = self->num, + .events = ZSOCK_POLLOUT, + }; - // including returning true in the error case - // return num_triggered != 0; - return false; + int num_triggered = zsock_poll(&fd, 1, 0); + return num_triggered > 0; } void socketpool_socket_move(socketpool_socket_obj_t *self, socketpool_socket_obj_t *sock) { diff --git a/ports/zephyr-cp/common-hal/socketpool/SocketPool.c b/ports/zephyr-cp/common-hal/socketpool/SocketPool.c index 4531c5bf1b7..2df1af69187 100644 --- a/ports/zephyr-cp/common-hal/socketpool/SocketPool.c +++ b/ports/zephyr-cp/common-hal/socketpool/SocketPool.c @@ -8,114 +8,120 @@ #include "common-hal/socketpool/Socket.h" #include "py/runtime.h" +#if CIRCUITPY_HOSTNETWORK +#include "bindings/hostnetwork/__init__.h" +#endif +#if CIRCUITPY_WIFI #include "shared-bindings/wifi/__init__.h" +#endif #include "common-hal/socketpool/__init__.h" +#include +#include + +#include +#include + void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *self, mp_obj_t radio) { - if (radio != MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj)) { - mp_raise_ValueError(MP_ERROR_TEXT("SocketPool can only be used with wifi.radio")); + bool is_wifi = false; + #if CIRCUITPY_WIFI + is_wifi = radio == MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj); + #endif + bool is_hostnetwork = false; + #if CIRCUITPY_HOSTNETWORK + is_hostnetwork = mp_obj_is_type(radio, &hostnetwork_hostnetwork_type); + #endif + if (!(is_wifi || is_hostnetwork)) { + mp_raise_ValueError(MP_ERROR_TEXT("SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork")); } } // common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking. -// int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) { -// // As of 2022, the version of lwip in esp-idf does not handle the -// // trailing-dot syntax of domain names, so emulate it. -// // Remove this once https://github.com/espressif/esp-idf/issues/10013 has -// // been implemented -// if (host) { -// size_t strlen_host = strlen(host); -// if (strlen_host && host[strlen_host - 1] == '.') { -// mp_obj_t nodot = mp_obj_new_str(host, strlen_host - 1); -// host = mp_obj_str_get_str(nodot); -// } -// } - -// // char service_buf[6]; -// // snprintf(service_buf, sizeof(service_buf), "%d", service); - -// // return lwip_getaddrinfo(host, service_buf, hints, res); -// return 0; -// } - -// static mp_obj_t format_address(const struct sockaddr *addr, int family) { -// char ip_str[IPADDR_STRLEN_MAX]; // big enough for any supported address type -// const struct sockaddr_in *a = (void *)addr; - -// switch (family) { -// #if CIRCUITPY_SOCKETPOOL_IPV6 -// case AF_INET6: -// inet_ntop(family, &((const struct sockaddr_in6 *)a)->sin6_addr, ip_str, sizeof(ip_str)); -// break; -// #endif -// default: -// case AF_INET: -// inet_ntop(family, &((const struct sockaddr_in *)a)->sin_addr, ip_str, sizeof(ip_str)); -// break; -// } -// return mp_obj_new_str(ip_str, strlen(ip_str)); -// } - -// static mp_obj_t convert_sockaddr(const struct addrinfo *ai, int port) { -// #if CIRCUITPY_SOCKETPOOL_IPV6 -// mp_int_t n_tuple = ai->ai_family == AF_INET6 ? 4 : 2; -// #else -// mp_int_t n_tuple = 2; -// #endif -// mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_tuple, NULL)); -// result->items[0] = format_address(ai->ai_addr, ai->ai_family); -// result->items[1] = MP_OBJ_NEW_SMALL_INT(port); -// #if CIRCUITPY_SOCKETPOOL_IPV6 -// if (ai->ai_family == AF_INET6) { -// const struct sockaddr_in6 *ai6 = (void *)ai->ai_addr; -// result->items[2] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_flowinfo); -// result->items[3] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_scope_id); -// } -// #endif -// return result; -// } - -// static mp_obj_t convert_addrinfo(const struct addrinfo *ai, int port) { -// MP_STATIC_ASSERT(AF_INET == SOCKETPOOL_AF_INET); -// #if CIRCUITPY_SOCKETPOOL_IPV6 -// MP_STATIC_ASSERT(AF_INET6 == SOCKETPOOL_AF_INET6); -// #endif -// // MP_STATIC_ASSERT(AF_UNSPEC == SOCKETPOOL_AF_UNSPEC); -// mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); -// result->items[0] = MP_OBJ_NEW_SMALL_INT(ai->ai_family); -// result->items[1] = MP_OBJ_NEW_SMALL_INT(ai->ai_socktype); -// result->items[2] = MP_OBJ_NEW_SMALL_INT(ai->ai_protocol); -// result->items[3] = ai->ai_canonname ? mp_obj_new_str(ai->ai_canonname, strlen(ai->ai_canonname)) : MP_OBJ_NEW_QSTR(MP_QSTR_); -// result->items[4] = convert_sockaddr(ai, port); -// return result; -// } +static int socketpool_getaddrinfo_common(const char *host, int service, const struct zsock_addrinfo *hints, struct zsock_addrinfo **res) { + char service_buf[6]; + snprintf(service_buf, sizeof(service_buf), "%d", service); + + return zsock_getaddrinfo(host, service_buf, hints, res); +} + +#define SOCKETPOOL_IP_STR_LEN 48 + +static mp_obj_t format_address(const struct sockaddr *addr, int family) { + char ip_str[SOCKETPOOL_IP_STR_LEN]; + const struct sockaddr_in *a = (void *)addr; + + switch (family) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + case AF_INET6: + zsock_inet_ntop(family, &((const struct sockaddr_in6 *)a)->sin6_addr, ip_str, sizeof(ip_str)); + break; + #endif + default: + case AF_INET: + zsock_inet_ntop(family, &((const struct sockaddr_in *)a)->sin_addr, ip_str, sizeof(ip_str)); + break; + } + return mp_obj_new_str(ip_str, strlen(ip_str)); +} + +static mp_obj_t convert_sockaddr(const struct zsock_addrinfo *ai, int port) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + mp_int_t n_tuple = ai->ai_family == AF_INET6 ? 4 : 2; + #else + mp_int_t n_tuple = 2; + #endif + mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_tuple, NULL)); + result->items[0] = format_address(ai->ai_addr, ai->ai_family); + result->items[1] = MP_OBJ_NEW_SMALL_INT(port); + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (ai->ai_family == AF_INET6) { + const struct sockaddr_in6 *ai6 = (void *)ai->ai_addr; + result->items[2] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_flowinfo); + result->items[3] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_scope_id); + } + #endif + return result; +} + +static mp_obj_t convert_addrinfo(const struct zsock_addrinfo *ai, int port) { + mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); + result->items[0] = MP_OBJ_NEW_SMALL_INT(ai->ai_family); + result->items[1] = MP_OBJ_NEW_SMALL_INT(ai->ai_socktype); + result->items[2] = MP_OBJ_NEW_SMALL_INT(ai->ai_protocol); + result->items[3] = ai->ai_canonname ? mp_obj_new_str(ai->ai_canonname, strlen(ai->ai_canonname)) : MP_OBJ_NEW_QSTR(MP_QSTR_); + result->items[4] = convert_sockaddr(ai, port); + return result; +} mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags) { - // const struct addrinfo hints = { - // .ai_flags = flags, - // .ai_family = family, - // .ai_protocol = proto, - // .ai_socktype = type, - // }; - - // struct addrinfo *res = NULL; - // int err = socketpool_getaddrinfo_common(host, port, &hints, &res); - if (true) { - common_hal_socketpool_socketpool_raise_gaierror_noname(); + const struct zsock_addrinfo hints = { + .ai_flags = flags, + .ai_family = family, + .ai_protocol = proto, + .ai_socktype = type, + }; + + struct zsock_addrinfo *res = NULL; + int err = socketpool_getaddrinfo_common(host, port, &hints, &res); + if (err != 0 || res == NULL) { + if (err == 0) { + err = DNS_EAI_NONAME; + } + common_hal_socketpool_socketpool_raise_gaierror(err); } nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t result = mp_obj_new_list(0, NULL); - // for (struct addrinfo *ai = res; ai; ai = ai->ai_next) { - // mp_obj_list_append(result, convert_addrinfo(ai, port)); - // } + for (struct zsock_addrinfo *ai = res; ai; ai = ai->ai_next) { + mp_obj_list_append(result, convert_addrinfo(ai, port)); + } nlr_pop(); - // lwip_freeaddrinfo(res); + zsock_freeaddrinfo(res); return result; } else { - // lwip_freeaddrinfo(res); + zsock_freeaddrinfo(res); nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); } } diff --git a/ports/zephyr-cp/common-hal/socketpool/SocketPool.h b/ports/zephyr-cp/common-hal/socketpool/SocketPool.h index 64f91e01e1c..7891a8b8e48 100644 --- a/ports/zephyr-cp/common-hal/socketpool/SocketPool.h +++ b/ports/zephyr-cp/common-hal/socketpool/SocketPool.h @@ -6,6 +6,9 @@ #pragma once +#include +#include + #include "py/obj.h" typedef struct { diff --git a/ports/zephyr-cp/common-hal/usb_cdc/Serial.c b/ports/zephyr-cp/common-hal/usb_cdc/Serial.c new file mode 100644 index 00000000000..715955d6e0f --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_cdc/Serial.c @@ -0,0 +1,69 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared/runtime/interrupt_char.h" +#include "shared-bindings/usb_cdc/Serial.h" +#include "shared-bindings/busio/UART.h" +#include "common-hal/busio/UART.h" +#include "supervisor/shared/tick.h" + +mp_obj_t common_hal_usb_cdc_serial_construct_from_device(usb_cdc_serial_obj_t *self, const struct device *uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer) { + common_hal_busio_uart_construct_from_device(self, uart_device, receiver_buffer_size, receiver_buffer); + self->base.type = &usb_cdc_serial_type; + return MP_OBJ_FROM_PTR(self); +} + +size_t common_hal_usb_cdc_serial_read(usb_cdc_serial_obj_t *self, uint8_t *data, size_t len, int *errcode) { + return common_hal_busio_uart_read(self, data, len, errcode); +} + +size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode) { + return common_hal_busio_uart_write(self, data, len, errcode); +} + +uint32_t common_hal_usb_cdc_serial_get_in_waiting(usb_cdc_serial_obj_t *self) { + return common_hal_busio_uart_rx_characters_available(self); +} + +uint32_t common_hal_usb_cdc_serial_get_out_waiting(usb_cdc_serial_obj_t *self) { + // Return number of FIFO bytes currently occupied. + // return CFG_TUD_CDC_TX_BUFSIZE - tud_cdc_n_write_available(self->idx); + return 0; +} + +void common_hal_usb_cdc_serial_reset_input_buffer(usb_cdc_serial_obj_t *self) { + common_hal_busio_uart_clear_rx_buffer(self); +} + +uint32_t common_hal_usb_cdc_serial_reset_output_buffer(usb_cdc_serial_obj_t *self) { + // return tud_cdc_n_write_clear(self->idx); + return 0; +} + +uint32_t common_hal_usb_cdc_serial_flush(usb_cdc_serial_obj_t *self) { + // return tud_cdc_n_write_flush(self->idx); + return 0; +} + +bool common_hal_usb_cdc_serial_get_connected(usb_cdc_serial_obj_t *self) { + return !common_hal_busio_uart_deinited(self); +} + +mp_float_t common_hal_usb_cdc_serial_get_timeout(usb_cdc_serial_obj_t *self) { + return common_hal_busio_uart_get_timeout(self); +} + +void common_hal_usb_cdc_serial_set_timeout(usb_cdc_serial_obj_t *self, mp_float_t timeout) { + common_hal_busio_uart_set_timeout(self, timeout); +} + +mp_float_t common_hal_usb_cdc_serial_get_write_timeout(usb_cdc_serial_obj_t *self) { + return common_hal_busio_uart_get_write_timeout(self); +} + +void common_hal_usb_cdc_serial_set_write_timeout(usb_cdc_serial_obj_t *self, mp_float_t write_timeout) { + common_hal_busio_uart_set_write_timeout(self, write_timeout); +} diff --git a/ports/zephyr-cp/common-hal/usb_cdc/Serial.h b/ports/zephyr-cp/common-hal/usb_cdc/Serial.h new file mode 100644 index 00000000000..9a110545a37 --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_cdc/Serial.h @@ -0,0 +1,14 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-bindings/busio/UART.h" + +typedef busio_uart_obj_t usb_cdc_serial_obj_t; + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_usb_cdc_serial_construct_from_device(usb_cdc_serial_obj_t *self, const struct device *uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer); diff --git a/ports/zephyr-cp/common-hal/usb_cdc/__init__.c b/ports/zephyr-cp/common-hal/usb_cdc/__init__.c new file mode 100644 index 00000000000..7bcae396733 --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_cdc/__init__.c @@ -0,0 +1,40 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/gc.h" +#include "py/obj.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "py/objtuple.h" +#include "shared-bindings/usb_cdc/__init__.h" +#include "shared-bindings/usb_cdc/Serial.h" +#include "supervisor/usb.h" + +static bool usb_cdc_console_is_enabled; +static bool usb_cdc_data_is_enabled; + +void usb_cdc_set_defaults(void) { + common_hal_usb_cdc_enable(true, + false); +} + +bool usb_cdc_console_enabled(void) { + return usb_cdc_console_is_enabled; +} + +bool usb_cdc_data_enabled(void) { + return usb_cdc_data_is_enabled; +} + +bool common_hal_usb_cdc_disable(void) { + return common_hal_usb_cdc_enable(false, false); +} + +bool common_hal_usb_cdc_enable(bool console, bool data) { + usb_cdc_console_is_enabled = console; + usb_cdc_data_is_enabled = data; + return true; +} diff --git a/ports/zephyr-cp/common-hal/usb_cdc/__init__.h b/ports/zephyr-cp/common-hal/usb_cdc/__init__.h new file mode 100644 index 00000000000..daf06d580ad --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_cdc/__init__.h @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/mpconfig.h" +#include "py/objtuple.h" +#include "supervisor/usb.h" + +bool usb_cdc_console_enabled(void); +bool usb_cdc_data_enabled(void); + +void usb_cdc_set_defaults(void); diff --git a/ports/zephyr-cp/common-hal/usb_hid/Device.c b/ports/zephyr-cp/common-hal/usb_hid/Device.c new file mode 100644 index 00000000000..ba263d44d74 --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_hid/Device.c @@ -0,0 +1,150 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 hathach for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/usb_hid/Device.h" +#include "shared-module/usb_hid/__init__.h" +#include "shared-module/usb_hid/Device.h" +#include "shared-module/usb_hid/report_descriptors.h" +#include "common-hal/usb_hid/__init__.h" +#include "supervisor/shared/tick.h" + +const usb_hid_device_obj_t usb_hid_device_keyboard_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = keyboard_report_descriptor, + .report_descriptor_length = sizeof(keyboard_report_descriptor), + .usage_page = 0x01, + .usage = 0x06, + .num_report_ids = 1, + .report_ids = { 0x01, }, + .in_report_lengths = { 8, }, + .out_report_lengths = { 1, }, +}; + +const usb_hid_device_obj_t usb_hid_device_mouse_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = mouse_report_descriptor, + .report_descriptor_length = sizeof(mouse_report_descriptor), + .usage_page = 0x01, + .usage = 0x02, + .num_report_ids = 1, + .report_ids = { 0x02, }, + .in_report_lengths = { 4, }, + .out_report_lengths = { 0, }, +}; + +const usb_hid_device_obj_t usb_hid_device_consumer_control_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = consumer_control_report_descriptor, + .report_descriptor_length = sizeof(consumer_control_report_descriptor), + .usage_page = 0x0C, + .usage = 0x01, + .num_report_ids = 1, + .report_ids = { 0x03 }, + .in_report_lengths = { 2, }, + .out_report_lengths = { 0, }, +}; + +char *custom_usb_hid_interface_name; + +static size_t get_report_id_idx(usb_hid_device_obj_t *self, size_t report_id) { + for (size_t i = 0; i < self->num_report_ids; i++) { + if (report_id == self->report_ids[i]) { + return i; + } + } + return CIRCUITPY_USB_HID_MAX_REPORT_IDS_PER_DESCRIPTOR; +} + +uint8_t common_hal_usb_hid_device_validate_report_id(usb_hid_device_obj_t *self, mp_int_t report_id_arg) { + if (report_id_arg == -1 && self->num_report_ids == 1) { + return self->report_ids[0]; + } + if (!(report_id_arg >= 0 && + get_report_id_idx(self, (size_t)report_id_arg) < CIRCUITPY_USB_HID_MAX_REPORT_IDS_PER_DESCRIPTOR)) { + mp_arg_error_invalid(MP_QSTR_report_id); + } + return (uint8_t)report_id_arg; +} + +void common_hal_usb_hid_device_construct(usb_hid_device_obj_t *self, mp_obj_t report_descriptor, uint16_t usage_page, uint16_t usage, size_t num_report_ids, uint8_t *report_ids, uint8_t *in_report_lengths, uint8_t *out_report_lengths) { + mp_arg_validate_length_max( + num_report_ids, CIRCUITPY_USB_HID_MAX_REPORT_IDS_PER_DESCRIPTOR, MP_QSTR_report_ids); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(report_descriptor, &bufinfo, MP_BUFFER_READ); + self->report_descriptor_length = bufinfo.len; + + uint8_t *descriptor_bytes = gc_alloc(bufinfo.len, false); + memcpy(descriptor_bytes, bufinfo.buf, bufinfo.len); + self->report_descriptor = descriptor_bytes; + + self->usage_page = usage_page; + self->usage = usage; + self->num_report_ids = num_report_ids; + memcpy(self->report_ids, report_ids, num_report_ids); + memcpy(self->in_report_lengths, in_report_lengths, num_report_ids); + memcpy(self->out_report_lengths, out_report_lengths, num_report_ids); +} + +uint16_t common_hal_usb_hid_device_get_usage_page(usb_hid_device_obj_t *self) { + return self->usage_page; +} + +uint16_t common_hal_usb_hid_device_get_usage(usb_hid_device_obj_t *self) { + return self->usage; +} + +void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t *report, uint8_t len, uint8_t report_id) { + size_t id_idx = get_report_id_idx(self, report_id); + + mp_arg_validate_length(len, self->in_report_lengths[id_idx], MP_QSTR_report); + + // Wait until interface is ready, timeout = 2 seconds + uint64_t end_ticks = supervisor_ticks_ms64() + 2000; + while ((supervisor_ticks_ms64() < end_ticks) && !usb_hid_ready()) { + RUN_BACKGROUND_TASKS; + } + + if (!usb_hid_submit_report(report_id, report, len)) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("USB error")); + } +} + +mp_obj_t common_hal_usb_hid_device_get_last_received_report(usb_hid_device_obj_t *self, uint8_t report_id) { + size_t id_idx = get_report_id_idx(self, report_id); + if (!self->out_report_buffers_updated[id_idx]) { + return mp_const_none; + } + self->out_report_buffers_updated[id_idx] = false; + return mp_obj_new_bytes(self->out_report_buffers[id_idx], self->out_report_lengths[id_idx]); +} + +void usb_hid_device_create_report_buffers(usb_hid_device_obj_t *self) { + for (size_t i = 0; i < self->num_report_ids; i++) { + self->in_report_buffers[i] = + self->in_report_lengths[i] > 0 + ? gc_alloc(self->in_report_lengths[i], false) + : NULL; + + self->out_report_buffers[i] = + self->out_report_lengths[i] > 0 + ? gc_alloc(self->out_report_lengths[i], false) + : NULL; + } + memset(self->out_report_buffers_updated, 0, sizeof(self->out_report_buffers_updated)); +} diff --git a/ports/zephyr-cp/common-hal/usb_hid/__init__.c b/ports/zephyr-cp/common-hal/usb_hid/__init__.c new file mode 100644 index 00000000000..552a91e102b --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_hid/__init__.c @@ -0,0 +1,377 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/usb_hid/__init__.h" +#include "shared-bindings/usb_hid/Device.h" +#include "shared-module/usb_hid/Device.h" +#include "supervisor/port.h" + +#include +#include +#include +#include +#include + +#define MAX_HID_DEVICES 8 + +static usb_hid_device_obj_t hid_devices[MAX_HID_DEVICES]; +// If 0, USB HID is disabled. +static mp_int_t num_hid_devices; +// Which boot device is available? 0: no boot devices, 1: boot keyboard, 2: boot mouse. +static uint8_t hid_boot_device; +// Whether a boot device was requested by a SET_PROTOCOL request from the host. +static bool hid_boot_device_requested; +// This tuple is stored in usb_hid.devices. +static mp_obj_tuple_t *hid_devices_tuple; + +// Whether the HID interface is ready (USB configured). +static bool hid_interface_ready; + +static mp_obj_tuple_t default_hid_devices_tuple = { + .base = { + .type = &mp_type_tuple, + }, + .len = 3, + .items = { + MP_OBJ_FROM_PTR(&usb_hid_device_keyboard_obj), + MP_OBJ_FROM_PTR(&usb_hid_device_mouse_obj), + MP_OBJ_FROM_PTR(&usb_hid_device_consumer_control_obj), + }, +}; + +// These describe the standard descriptors used for boot keyboard and mouse, +// which don't use report IDs. +static const usb_hid_device_obj_t boot_keyboard_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = NULL, + .report_descriptor_length = 0, + .usage_page = 0x01, + .usage = 0x06, + .num_report_ids = 1, + .report_ids = { 0, }, + .in_report_lengths = { 8, }, + .out_report_lengths = { 1, }, +}; + +static const usb_hid_device_obj_t boot_mouse_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = NULL, + .report_descriptor_length = 0, + .usage_page = 0x01, + .usage = 0x02, + .num_report_ids = 1, + .report_ids = { 0, }, + .in_report_lengths = { 4, }, + .out_report_lengths = { 0, }, +}; + +bool usb_hid_enabled(void) { + return num_hid_devices > 0; +} + +uint8_t usb_hid_boot_device(void) { + return hid_boot_device; +} + +// Returns 1 or 2 if host requested a boot device and boot protocol was enabled. +uint8_t common_hal_usb_hid_get_boot_device(void) { + return hid_boot_device_requested ? hid_boot_device : 0; +} + +void usb_hid_set_defaults(void) { + hid_boot_device = 0; + hid_boot_device_requested = false; + hid_interface_ready = false; + common_hal_usb_hid_enable( + CIRCUITPY_USB_HID_ENABLED_DEFAULT ? &default_hid_devices_tuple : mp_const_empty_tuple, 0); +} + +// Make up a fresh tuple containing the device objects saved in the static +// devices table. Save the tuple in usb_hid.devices. +static void usb_hid_set_devices_from_hid_devices(void) { + mp_obj_t tuple_items[num_hid_devices]; + for (mp_int_t i = 0; i < num_hid_devices; i++) { + tuple_items[i] = &hid_devices[i]; + } + hid_devices_tuple = mp_obj_new_tuple(num_hid_devices, tuple_items); + usb_hid_set_devices(hid_devices_tuple); +} + +bool common_hal_usb_hid_disable(void) { + return common_hal_usb_hid_enable(mp_const_empty_tuple, 0); +} + +bool common_hal_usb_hid_enable(const mp_obj_t devices, uint8_t boot_device) { + // We can't change the devices once USB is connected. + if (hid_interface_ready) { + return false; + } + + const mp_int_t num_devices = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(devices)); + mp_arg_validate_length_max(num_devices, MAX_HID_DEVICES, MP_QSTR_devices); + + num_hid_devices = num_devices; + hid_boot_device = boot_device; + + // Remember the devices in static storage so they live across VMs. + for (mp_int_t i = 0; i < num_hid_devices; i++) { + usb_hid_device_obj_t *device = + MP_OBJ_TO_PTR(mp_obj_subscr(devices, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); + memcpy(&hid_devices[i], device, sizeof(usb_hid_device_obj_t)); + } + + usb_hid_set_devices_from_hid_devices(); + + return true; +} + +// Called when HID devices are ready to be used, when code.py or the REPL starts running. +void usb_hid_setup_devices(void) { + // If the host requested a boot device, replace the current list of devices + // with a single-element tuple containing the proper boot device. + if (hid_boot_device_requested) { + memcpy(&hid_devices[0], + hid_boot_device == 1 ? &boot_keyboard_obj : &boot_mouse_obj, + sizeof(usb_hid_device_obj_t)); + num_hid_devices = 1; + } + + usb_hid_set_devices_from_hid_devices(); + + // Create report buffers on the heap. + for (mp_int_t i = 0; i < num_hid_devices; i++) { + usb_hid_device_create_report_buffers(&hid_devices[i]); + } +} + +// Build the combined HID report descriptor from all devices. +static uint8_t *hid_report_descriptor = NULL; + +size_t usb_hid_report_descriptor_length(void) { + size_t total_hid_report_descriptor_length = 0; + for (mp_int_t i = 0; i < num_hid_devices; i++) { + total_hid_report_descriptor_length += hid_devices[i].report_descriptor_length; + } + return total_hid_report_descriptor_length; +} + +void usb_hid_build_report_descriptor(void) { + if (!usb_hid_enabled()) { + return; + } + size_t report_length = usb_hid_report_descriptor_length(); + hid_report_descriptor = port_malloc(report_length, false); + if (hid_report_descriptor == NULL) { + return; + } + + uint8_t *report_descriptor_start = hid_report_descriptor; + for (mp_int_t i = 0; i < num_hid_devices; i++) { + usb_hid_device_obj_t *device = &hid_devices[i]; + memcpy(report_descriptor_start, device->report_descriptor, device->report_descriptor_length); + report_descriptor_start += device->report_descriptor_length; + // Clear the heap pointer to the bytes of the descriptor. + device->report_descriptor = NULL; + } +} + +void usb_hid_gc_collect(void) { + gc_collect_ptr(hid_devices_tuple); + + for (mp_int_t device_idx = 0; device_idx < num_hid_devices; device_idx++) { + gc_collect_ptr((void *)hid_devices[device_idx].report_descriptor); + + for (size_t id_idx = 0; id_idx < hid_devices[device_idx].num_report_ids; id_idx++) { + gc_collect_ptr(hid_devices[device_idx].in_report_buffers[id_idx]); + gc_collect_ptr(hid_devices[device_idx].out_report_buffers[id_idx]); + } + } +} + +bool usb_hid_get_device_with_report_id(uint8_t report_id, usb_hid_device_obj_t **device_out, size_t *id_idx_out) { + for (uint8_t device_idx = 0; device_idx < num_hid_devices; device_idx++) { + usb_hid_device_obj_t *device = &hid_devices[device_idx]; + for (size_t id_idx = 0; id_idx < device->num_report_ids; id_idx++) { + if (device->report_ids[id_idx] == report_id) { + *device_out = device; + *id_idx_out = id_idx; + return true; + } + } + } + return false; +} + +// ===== Zephyr USBD HID Device Callbacks ===== + +static void hid_iface_ready(const struct device *dev, const bool ready) { + hid_interface_ready = ready; +} + +static int hid_get_report(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, uint8_t *const buf) { + // Support Input Report and Feature Report + if (type != HID_REPORT_TYPE_INPUT && type != HID_REPORT_TYPE_FEATURE) { + return -ENOTSUP; + } + + usb_hid_device_obj_t *hid_device; + size_t id_idx; + if (!usb_hid_get_device_with_report_id(id, &hid_device, &id_idx)) { + return 0; + } + if (!hid_device->in_report_buffers[id_idx]) { + return 0; + } + + uint8_t in_len = hid_device->in_report_lengths[id_idx]; + const uint8_t *src = hid_device->in_report_buffers[id_idx]; + + // When the descriptor uses Report IDs (id != 0), the on-wire report is + // prefixed with the Report ID byte. Zephyr sends the buffer verbatim, so + // prepend the ID here. id == 0 means no Report ID item -> no prefix. + if (id != 0) { + if (len == 0) { + return 0; + } + buf[0] = id; + uint16_t copy_len = len - 1; + if (copy_len > in_len) { + copy_len = in_len; + } + memcpy(&buf[1], src, copy_len); + return 1 + copy_len; + } + + uint16_t copy_len = len; + if (copy_len > in_len) { + copy_len = in_len; + } + memcpy(buf, src, copy_len); + return copy_len; +} + +static int hid_set_report(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, const uint8_t *const buf) { + uint8_t report_id = id; + const uint8_t *data = buf; + uint16_t data_len = len; + + if (report_id != 0 && len > 0) { + // Descriptor uses Report IDs: the on-wire SET_REPORT data stage is + // prefixed with the Report ID byte. Zephyr passes the raw payload, so + // strip the leading ID byte (it should match the id from wValue). + if (buf[0] == report_id) { + data = &buf[1]; + data_len = len - 1; + } + } else if (report_id == 0 && len > 0) { + // id==0 normally means no Report ID item (no prefix). But if no device + // has report ID 0 with a matching out length, treat the first byte as a + // report ID (host sent a prefixed report despite id==0). + usb_hid_device_obj_t *hid0 = NULL; + size_t idx0; + if (!(usb_hid_get_device_with_report_id(0, &hid0, &idx0) && + hid0 && hid0->out_report_buffers[idx0] && + hid0->out_report_lengths[idx0] == len)) { + report_id = buf[0]; + data = &buf[1]; + data_len = len - 1; + } + } + + // Look up the device for the resolved report_id. + usb_hid_device_obj_t *hid_device = NULL; + size_t id_idx; + if (!usb_hid_get_device_with_report_id(report_id, &hid_device, &id_idx)) { + return -EINVAL; + } + + if (hid_device->out_report_buffers[id_idx] && + hid_device->out_report_lengths[id_idx] == data_len) { + memcpy(hid_device->out_report_buffers[id_idx], data, data_len); + hid_device->out_report_buffers_updated[id_idx] = true; + return 0; + } + + return -EINVAL; +} + +static void hid_set_protocol(const struct device *dev, const uint8_t proto) { + hid_boot_device_requested = (proto == HID_PROTOCOL_BOOT); +} + +static struct hid_device_ops hid_ops = { + .iface_ready = hid_iface_ready, + .get_report = hid_get_report, + .set_report = hid_set_report, + .set_protocol = hid_set_protocol, +}; + +// ===== HID Device Registration ===== + +// Get the Zephyr HID device for submitting reports +static const struct device *hid_zephyr_dev; + +const struct device *usb_hid_get_zephyr_device(void) { + return hid_zephyr_dev; +} + +void usb_hid_init_devices(void) { + if (!usb_hid_enabled()) { + return; + } + + hid_zephyr_dev = DEVICE_DT_GET_ONE(zephyr_hid_device); + if (!device_is_ready(hid_zephyr_dev)) { + return; + } + + usb_hid_build_report_descriptor(); + if (hid_report_descriptor == NULL) { + return; + } + + int ret = hid_device_register(hid_zephyr_dev, + hid_report_descriptor, + usb_hid_report_descriptor_length(), + &hid_ops); + if (ret != 0) { + return; + } +} + +bool usb_hid_ready(void) { + return hid_zephyr_dev != NULL && hid_interface_ready; +} + +// Submit an input report through Zephyr's HID device. +// Called from common_hal_usb_hid_device_send_report(). +bool usb_hid_submit_report(uint8_t report_id, const uint8_t *report, uint8_t len) { + if (hid_zephyr_dev == NULL || !hid_interface_ready) { + return false; + } + + // Send report_id zero without a prefix + if (report_id == 0) { + return hid_device_submit_report(hid_zephyr_dev, len, report) == 0; + } + + uint8_t __attribute__((aligned(sizeof(void *)))) report_buffer[1 + len]; + report_buffer[0] = report_id; + memcpy(&report_buffer[1], report, len); + return hid_device_submit_report(hid_zephyr_dev, len + 1, report_buffer) == 0; +} diff --git a/ports/zephyr-cp/common-hal/usb_hid/__init__.h b/ports/zephyr-cp/common-hal/usb_hid/__init__.h new file mode 100644 index 00000000000..1985ea29549 --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_hid/__init__.h @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/usb_hid/Device.h" +#include "supervisor/usb.h" + +extern usb_hid_device_obj_t usb_hid_devices[]; + +bool usb_hid_enabled(void); +uint8_t usb_hid_boot_device(void); +void usb_hid_set_defaults(void); +void usb_hid_setup_devices(void); +size_t usb_hid_report_descriptor_length(void); +void usb_hid_build_report_descriptor(void); +bool usb_hid_get_device_with_report_id(uint8_t report_id, usb_hid_device_obj_t **device_out, size_t *id_idx_out); +void usb_hid_gc_collect(void); + +// For supervisor/usb.c integration +void usb_hid_init_devices(void); + +// For Device.c send_report +bool usb_hid_ready(void); +bool usb_hid_submit_report(uint8_t report_id, const uint8_t *report, uint8_t len); diff --git a/ports/zephyr-cp/common-hal/wifi/Network.c b/ports/zephyr-cp/common-hal/wifi/Network.c index 44c049f88c1..dad9293a149 100644 --- a/ports/zephyr-cp/common-hal/wifi/Network.c +++ b/ports/zephyr-cp/common-hal/wifi/Network.c @@ -6,6 +6,8 @@ #include +#include "py/objlist.h" + #include "shared-bindings/wifi/Network.h" #include "shared-bindings/wifi/AuthMode.h" @@ -34,35 +36,44 @@ mp_obj_t common_hal_wifi_network_get_country(wifi_network_obj_t *self) { } mp_obj_t common_hal_wifi_network_get_authmode(wifi_network_obj_t *self) { + // Translate Zephyr's wifi_security_type. An empty list would read as an + // open network to any caller checking for AUTHMODE_OPEN. uint32_t authmode_mask = 0; - // switch (self->record.authmode) { - // case WIFI_AUTH_OPEN: - // authmode_mask = AUTHMODE_OPEN; - // break; - // case WIFI_AUTH_WEP: - // authmode_mask = AUTHMODE_WEP; - // break; - // case WIFI_AUTH_WPA_PSK: - // authmode_mask = AUTHMODE_WPA | AUTHMODE_PSK; - // break; - // case WIFI_AUTH_WPA2_PSK: - // authmode_mask = AUTHMODE_WPA2 | AUTHMODE_PSK; - // break; - // case WIFI_AUTH_WPA_WPA2_PSK: - // authmode_mask = AUTHMODE_WPA | AUTHMODE_WPA2 | AUTHMODE_PSK; - // break; - // case WIFI_AUTH_WPA2_ENTERPRISE: - // authmode_mask = AUTHMODE_WPA2 | AUTHMODE_ENTERPRISE; - // break; - // case WIFI_AUTH_WPA3_PSK: - // authmode_mask = AUTHMODE_WPA3 | AUTHMODE_PSK; - // break; - // case WIFI_AUTH_WPA2_WPA3_PSK: - // authmode_mask = AUTHMODE_WPA2 | AUTHMODE_WPA3 | AUTHMODE_PSK; - // break; - // default: - // break; - // } + switch (self->scan_result.security) { + case WIFI_SECURITY_TYPE_NONE: + authmode_mask = AUTHMODE_OPEN; + break; + case WIFI_SECURITY_TYPE_WEP: + authmode_mask = AUTHMODE_WEP; + break; + case WIFI_SECURITY_TYPE_WPA_PSK: + authmode_mask = AUTHMODE_WPA | AUTHMODE_PSK; + break; + case WIFI_SECURITY_TYPE_PSK: + case WIFI_SECURITY_TYPE_PSK_SHA256: + authmode_mask = AUTHMODE_WPA2 | AUTHMODE_PSK; + break; + case WIFI_SECURITY_TYPE_SAE: // == WIFI_SECURITY_TYPE_SAE_HNP (alias) + case WIFI_SECURITY_TYPE_SAE_H2E: + case WIFI_SECURITY_TYPE_SAE_AUTO: + case WIFI_SECURITY_TYPE_SAE_EXT_KEY: + case WIFI_SECURITY_TYPE_FT_SAE: + authmode_mask = AUTHMODE_WPA3 | AUTHMODE_PSK; + break; + case WIFI_SECURITY_TYPE_WPA_AUTO_PERSONAL: + authmode_mask = AUTHMODE_WPA | AUTHMODE_WPA2 | AUTHMODE_WPA3 | AUTHMODE_PSK; + break; + case WIFI_SECURITY_TYPE_EAP: // == WIFI_SECURITY_TYPE_EAP_TLS (alias) + case WIFI_SECURITY_TYPE_EAP_PEAP_MSCHAPV2: + case WIFI_SECURITY_TYPE_EAP_PEAP_GTC: + case WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2: + case WIFI_SECURITY_TYPE_EAP_PEAP_TLS: + case WIFI_SECURITY_TYPE_FT_EAP: + authmode_mask = AUTHMODE_WPA2 | AUTHMODE_ENTERPRISE; + break; + default: + break; + } mp_obj_t authmode_list = mp_obj_new_list(0, NULL); if (authmode_mask != 0) { for (uint8_t i = 0; i < 32; i++) { diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 726b406b3ca..a85f6bbb736 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -25,14 +25,25 @@ #include "bindings/zephyr_kernel/__init__.h" #include +#include +#include +// dns_resolve_get_default() for radio.ipv4_dns. +#include #include +#if CIRCUITPY_WIFI_PING +// net_icmp_* for radio.ping(). +#include +#endif #include #include +#include #if CIRCUITPY_MDNS #include "common-hal/mdns/Server.h" #endif +LOG_MODULE_DECLARE(cp_wifi); + #define MAC_ADDRESS_LENGTH 6 // static void set_mode_station(wifi_radio_obj_t *self, bool state) { @@ -85,14 +96,20 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { // #if CIRCUITPY_MDNS // mdns_server_deinit_singleton(); // #endif - printk("net_if_down\n"); - CHECK_ZEPHYR_RESULT(net_if_down(self->sta_netif)); + LOG_DBG("net_if_down"); + int res = net_if_down(self->sta_netif); + if (res < 0 && res != -EALREADY) { + raise_zephyr_error(res); + } self->started = false; return; } if (!self->started && enabled) { - printk("net_if_up\n"); - CHECK_ZEPHYR_RESULT(net_if_up(self->sta_netif)); + LOG_DBG("net_if_up"); + int res = net_if_up(self->sta_netif); + if (res < 0 && res != -EALREADY) { + raise_zephyr_error(res); + } self->started = true; self->current_scan = NULL; // common_hal_wifi_radio_set_tx_power(self, CIRCUITPY_WIFI_DEFAULT_TX_POWER); @@ -112,8 +129,13 @@ void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *host } mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { - uint8_t mac[MAC_ADDRESS_LENGTH]; - // esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); + uint8_t mac[MAC_ADDRESS_LENGTH] = { 0 }; + if (self->sta_netif != NULL) { + struct net_linkaddr *addr = net_if_get_link_addr(self->sta_netif); + if (addr != NULL && addr->len >= MAC_ADDRESS_LENGTH) { + memcpy(mac, addr->addr, MAC_ADDRESS_LENGTH); + } + } return mp_obj_new_bytes(mac, MAC_ADDRESS_LENGTH); } @@ -208,13 +230,11 @@ void common_hal_wifi_radio_set_mac_address_ap(wifi_radio_obj_t *self, const uint } mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self, uint8_t start_channel, uint8_t stop_channel) { - printk("common_hal_wifi_radio_start_scanning_networks\n"); + LOG_DBG("common_hal_wifi_radio_start_scanning_networks"); if (self->current_scan != NULL) { - printk("Already scanning for wifi networks\n"); mp_raise_RuntimeError(MP_ERROR_TEXT("Already scanning for wifi networks")); } if (!common_hal_wifi_radio_get_enabled(self)) { - printk("WiFi is not enabled\n"); mp_raise_RuntimeError(MP_ERROR_TEXT("WiFi is not enabled")); } @@ -240,12 +260,12 @@ mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self, u K_POLL_MODE_NOTIFY_ONLY, &scan->msgq); wifi_scannednetworks_scan_next_channel(scan); - printk("common_hal_wifi_radio_start_scanning_networks done %p\n", scan); + LOG_DBG("common_hal_wifi_radio_start_scanning_networks done %p", scan); return scan; } void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self) { - printk("common_hal_wifi_radio_stop_scanning_networks\n"); + LOG_DBG("common_hal_wifi_radio_stop_scanning_networks"); // Return early if self->current_scan is NULL to avoid hang if (self->current_scan == NULL) { return; @@ -450,17 +470,170 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t // // We're connected, allow us to retry if we get disconnected. // self->retries_left = self->starting_retries; // } + + struct wifi_connect_req_params params = { 0 }; + + params.ssid = ssid; + params.ssid_length = ssid_len; + params.band = WIFI_FREQ_BAND_2_4_GHZ; + params.channel = channel == 0 ? WIFI_CHANNEL_ANY : channel; + params.mfp = WIFI_MFP_OPTIONAL; + params.timeout = SYS_FOREVER_MS; + + if (password_len > 0) { + params.psk = password; + params.psk_length = password_len; + // WPA_AUTO_PERSONAL lets the driver settle on WPA2 or WPA3 with the AP + // rather than us guessing: it maps to WPA3-transition, which an AP in + // either mode accepts. WIFI_SECURITY_TYPE_UNKNOWN is not an option, the + // driver rejects it with -ENOTSUP. + params.security = WIFI_SECURITY_TYPE_WPA_AUTO_PERSONAL; + } else { + params.security = WIFI_SECURITY_TYPE_NONE; + } + + if (bssid_len == WIFI_MAC_ADDR_LEN) { + memcpy(params.bssid, bssid, WIFI_MAC_ADDR_LEN); + } + + // Already associated to the network being asked for: leave the link alone. + // supervisor_start_web_workflow() calls connect() on every invocation, so + // tearing the association down here would churn the link continuously. + if (self->connected && + ssid_len == self->current_ssid_len && + memcmp(ssid, self->current_ssid, ssid_len) == 0) { + return WIFI_RADIO_ERROR_NONE; + } + + // Switching networks. Connecting while associated returns -EALREADY and the + // failure path takes the interface down, so disconnect first. + if (self->connected) { + // A failure here is tolerated on purpose: if the interface really is + // unusable, the connect below returns a proper error to the caller. + (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, self->sta_netif, NULL, 0); + // Give the controller a moment to tear the association down. + for (int i = 0; i < 40 && self->connected; i++) { + RUN_BACKGROUND_TASKS; + k_msleep(50); + } + self->connected = false; + } + + self->connected = false; + self->last_connect_status = -1; + self->last_disconnect_reason = 0; + k_sem_reset(&self->connect_sem); + + int res = net_mgmt(NET_REQUEST_WIFI_CONNECT, self->sta_netif, ¶ms, sizeof(params)); + if (res == -EALREADY) { + // Record the SSID as the success path does, so the early return above + // matches on a later connect() to the same network. + self->connected = true; + self->current_ssid_len = MIN(ssid_len, sizeof(self->current_ssid)); + memcpy(self->current_ssid, ssid, self->current_ssid_len); + return WIFI_RADIO_ERROR_NONE; + } + if (res < 0) { + return WIFI_RADIO_ERROR_UNSPECIFIED; + } + + // Wait for NET_EVENT_WIFI_CONNECT_RESULT (or a DISCONNECT_RESULT standing + // in for a failed attempt), staying responsive to ctrl-C. + mp_float_t timeout_s = timeout <= 0 ? (mp_float_t)10 : timeout; + int64_t deadline = k_uptime_get() + (int64_t)(timeout_s * 1000); + bool signalled = false; + while (k_uptime_get() < deadline) { + RUN_BACKGROUND_TASKS; + if (k_sem_take(&self->connect_sem, K_MSEC(50)) == 0) { + signalled = true; + break; + } + if (mp_hal_is_interrupted()) { + return WIFI_RADIO_ERROR_UNSPECIFIED; + } + } + + if (!signalled) { + return WIFI_RADIO_ERROR_HANDSHAKE_TIMEOUT; + } + if (!self->connected) { + switch (self->last_connect_status) { + case WIFI_STATUS_CONN_WRONG_PASSWORD: + return WIFI_RADIO_ERROR_AUTH_FAIL; + case WIFI_STATUS_CONN_AP_NOT_FOUND: + return WIFI_RADIO_ERROR_NO_AP_FOUND; + case WIFI_STATUS_CONN_TIMEOUT: + return WIFI_RADIO_ERROR_HANDSHAKE_TIMEOUT; + default: + return WIFI_RADIO_ERROR_CONNECTION_FAIL; + } + } + + // Remember which network this association is for, so a later connect() for + // the same SSID can return without disturbing it. + self->current_ssid_len = MIN(ssid_len, sizeof(self->current_ssid)); + memcpy(self->current_ssid, ssid, self->current_ssid_len); + + // Associated. Ask for an address; the AP side of DHCP can take a moment. + #if defined(CONFIG_NET_DHCPV4) + net_dhcpv4_start(self->sta_netif); + int64_t ip_deadline = k_uptime_get() + 15000; + while (k_uptime_get() < ip_deadline) { + if (net_if_ipv4_get_global_addr(self->sta_netif, NET_ADDR_PREFERRED) != NULL) { + break; + } + if (mp_hal_is_interrupted()) { + break; + } + RUN_BACKGROUND_TASKS; + k_msleep(50); + } + #endif + return WIFI_RADIO_ERROR_NONE; } bool common_hal_wifi_radio_get_connected(wifi_radio_obj_t *self) { - // return self->sta_mode && esp_netif_is_netif_up(self->netif); - return false; + return self->connected && self->sta_netif != NULL && + net_if_is_up(self->sta_netif); } mp_obj_t common_hal_wifi_radio_get_ap_info(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { - return mp_const_none; + if (self->sta_netif == NULL || !self->connected) { + return mp_const_none; + } + + // NET_REQUEST_WIFI_IFACE_STATUS carries everything a wifi.Network needs, so + // this reports the live association without spending a scan on it. + struct wifi_iface_status status = { 0 }; + if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, self->sta_netif, + &status, sizeof(status)) != 0) { + return mp_const_none; + } + + // Associated is the weakest state that has a meaningful BSSID and RSSI. + if (status.state < WIFI_STATE_ASSOCIATED) { + return mp_const_none; + } + + // wifi.Network wraps a scan result, so translate the status into one. + wifi_network_obj_t *ap_info = mp_obj_malloc(wifi_network_obj_t, &wifi_network_type); + size_t ssid_len = MIN(status.ssid_len, sizeof(ap_info->scan_result.ssid) - 1); + memcpy(ap_info->scan_result.ssid, status.ssid, ssid_len); + ap_info->scan_result.ssid[ssid_len] = '\0'; + ap_info->scan_result.ssid_length = ssid_len; + memcpy(ap_info->scan_result.mac, status.bssid, WIFI_MAC_ADDR_LEN); + ap_info->scan_result.mac_length = WIFI_MAC_ADDR_LEN; + ap_info->scan_result.band = status.band; + ap_info->scan_result.channel = status.channel; + ap_info->scan_result.security = status.security; + ap_info->scan_result.wpa3_ent_type = status.wpa3_ent_type; + ap_info->scan_result.mfp = status.mfp; + // status.rssi is int, scan_result.rssi is int8_t. Clamp, since a truncated + // value would wrap to a positive dBm. + ap_info->scan_result.rssi = (int8_t)MIN(MAX(status.rssi, INT8_MIN), INT8_MAX); + return MP_OBJ_FROM_PTR(ap_info); + // } // // Make sure the interface is in STA mode @@ -493,11 +666,23 @@ mp_obj_t common_hal_wifi_radio_get_ap_info(wifi_radio_obj_t *self) { } mp_obj_t common_hal_wifi_radio_get_ipv4_gateway(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return mp_const_none; + } + // net_if_ip.ipv4 only exists with CONFIG_NET_IPV4, and this file builds for + // every Wi-Fi board in the port, not just ones that enable it. + #if defined(CONFIG_NET_IPV4) + const struct net_if_config *cfg = net_if_get_config(self->sta_netif); + if (cfg == NULL || cfg->ip.ipv4 == NULL) { + return mp_const_none; + } + if (cfg->ip.ipv4->gw.s_addr == 0) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(cfg->ip.ipv4->gw.s_addr); + #else return mp_const_none; - // } - // esp_netif_get_ip_info(self->netif, &self->ip_info); - // return common_hal_ipaddress_new_ipv4address(self->ip_info.gw.addr); + #endif } mp_obj_t common_hal_wifi_radio_get_ipv4_gateway_ap(wifi_radio_obj_t *self) { @@ -509,11 +694,24 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_gateway_ap(wifi_radio_obj_t *self) { } mp_obj_t common_hal_wifi_radio_get_ipv4_subnet(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return mp_const_none; + } + // See get_ipv4_gateway: net_if_ip.ipv4 needs CONFIG_NET_IPV4. + #if defined(CONFIG_NET_IPV4) + struct net_if_ipv4 *ipv4 = self->sta_netif->config.ip.ipv4; + if (ipv4 == NULL) { + return mp_const_none; + } + for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + if (ipv4->unicast[i].ipv4.is_used && + ipv4->unicast[i].ipv4.addr_state == NET_ADDR_PREFERRED) { + return common_hal_ipaddress_new_ipv4address( + ipv4->unicast[i].netmask.s_addr); + } + } + #endif return mp_const_none; - // } - // esp_netif_get_ip_info(self->netif, &self->ip_info); - // return common_hal_ipaddress_new_ipv4address(self->ip_info.netmask.addr); } mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self) { @@ -556,31 +754,48 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self) { // } mp_obj_t common_hal_wifi_radio_get_addresses(wifi_radio_obj_t *self) { - // return common_hal_wifi_radio_get_addresses_netif(self, self->netif); - return mp_const_none; + // shared-bindings documents this as Sequence[str], empty when not + // connected, so format as a dotted-quad string rather than returning an + // IPv4Address object. Same address as wifi_radio_get_ipv4_address(). + uint32_t ipv4_address = wifi_radio_get_ipv4_address(self); + if (ipv4_address == 0) { + return mp_const_empty_tuple; + } + uint8_t *octets = (uint8_t *)&ipv4_address; + char buf[16]; + snprintf(buf, sizeof(buf), "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); + mp_obj_t args[] = { mp_obj_new_str(buf, strlen(buf)) }; + return mp_obj_new_tuple(MP_ARRAY_SIZE(args), args); } mp_obj_t common_hal_wifi_radio_get_addresses_ap(wifi_radio_obj_t *self) { - // return common_hal_wifi_radio_get_addresses_netif(self, self->ap_netif); - return mp_const_none; + // AP mode is unimplemented here, but mp_const_none is still the wrong type + // for the Sequence[str] contract. + return mp_const_empty_tuple; } uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { - // return 0; - // } - // esp_netif_get_ip_info(self->netif, &self->ip_info); - // return self->ip_info.ip.addr; - return 0; + // Raw uint32_t sibling of common_hal_wifi_radio_get_ipv4_address(), + // used internally by supervisor/shared/web_workflow/web_workflow.c. + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return 0; + } + struct in_addr *addr = net_if_ipv4_get_global_addr(self->sta_netif, NET_ADDR_PREFERRED); + if (addr == NULL) { + return 0; + } + return addr->s_addr; } mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { - // return mp_const_none; - // } - // esp_netif_get_ip_info(self->netif, &self->ip_info); - // return common_hal_ipaddress_new_ipv4address(self->ip_info.ip.addr); - return mp_const_none; + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return mp_const_none; + } + struct in_addr *addr = net_if_ipv4_get_global_addr(self->sta_netif, NET_ADDR_PREFERRED); + if (addr == NULL) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(addr->s_addr); } mp_obj_t common_hal_wifi_radio_get_ipv4_address_ap(wifi_radio_obj_t *self) { @@ -593,20 +808,26 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_address_ap(wifi_radio_obj_t *self) { } mp_obj_t common_hal_wifi_radio_get_ipv4_dns(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { - // return mp_const_none; - // } - - // esp_netif_get_dns_info(self->netif, ESP_NETIF_DNS_MAIN, &self->dns_info); - - // if (self->dns_info.ip.type != ESP_IPADDR_TYPE_V4) { - // return mp_const_none; - // } - // // dns_info is of type esp_netif_dns_info_t, which is just ever so slightly - // // different than esp_netif_ip_info_t used for - // // common_hal_wifi_radio_get_ipv4_address (includes both ipv4 and 6), - // // so some extra jumping is required to get to the actual address - // return common_hal_ipaddress_new_ipv4address(self->dns_info.ip.u_addr.ip4.addr); + // Zephyr keeps resolver state in the DNS resolve context rather than on + // the interface, so read it there. + #if defined(CONFIG_DNS_RESOLVER) + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return mp_const_none; + } + struct dns_resolve_context *ctx = dns_resolve_get_default(); + if (ctx == NULL) { + return mp_const_none; + } + for (int i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS; i++) { + if (ctx->servers[i].dns_server.sa_family == AF_INET) { + struct sockaddr_in *addr = + (struct sockaddr_in *)&ctx->servers[i].dns_server; + if (addr->sin_addr.s_addr != 0) { + return common_hal_ipaddress_new_ipv4address(addr->sin_addr.s_addr); + } + } + } + #endif return mp_const_none; } @@ -679,58 +900,187 @@ void common_hal_wifi_radio_set_ipv4_address_ap(wifi_radio_obj_t *self, mp_obj_t // common_hal_wifi_radio_start_dhcp_server(self); // restart access point DHCP } -// static void ping_success_cb(esp_ping_handle_t hdl, void *args) { -// wifi_radio_obj_t *self = (wifi_radio_obj_t *)args; -// esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &self->ping_elapsed_time, sizeof(self->ping_elapsed_time)); -// } +#if CIRCUITPY_WIFI_PING +// Zephyr delivers the echo reply on the network RX thread, not the caller's, so +// the two halves share this state through the ICMP context's user_data. It lives +// on the calling thread's stack, hence the cleanup discipline in ping() below. +typedef struct { + struct k_sem reply_sem; + int64_t sent_ms; + int64_t elapsed_ms; + uint16_t identifier; + uint16_t sequence; +} ping_session_t; + +// Zephyr keeps struct net_icmpv4_echo_req in subsys/net/ip/icmpv4.h, a private +// header that code outside the net stack cannot include, so mirror the four +// bytes that follow the ICMP header here. +struct ping_echo_hdr { + uint16_t identifier; + uint16_t sequence; +} __packed; + +// An echo carries no port number, so the sequence is the only thing telling two +// back-to-back requests apart; without it a late reply would be reported as the +// next call's round trip. The identifier is randomized once per boot. +static uint16_t ping_identifier; +static uint16_t ping_sequence; + +static enum net_verdict ping_reply_handler(struct net_icmp_ctx *ctx, + struct net_pkt *pkt, + struct net_icmp_ip_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr, + void *user_data) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(echo_access, struct ping_echo_hdr); + ping_session_t *session = user_data; + struct ping_echo_hdr *echo; + + (void)ctx; + (void)ip_hdr; + (void)icmp_hdr; + + if (session == NULL) { + return NET_CONTINUE; + } + + // net_pkt_get_data() leaves the cursor where it found it, which the + // NET_CONTINUE below relies on: the next handler starts at the echo header. + echo = (struct ping_echo_hdr *)net_pkt_get_data(pkt, &echo_access); + if (echo == NULL) { + return NET_CONTINUE; + } + + if (net_ntohs(echo->identifier) != session->identifier || + net_ntohs(echo->sequence) != session->sequence) { + // A reply to an earlier ping of ours, or to somebody else's. Leave it + // alone rather than waking the caller with a round trip time that + // belongs to a different request. + return NET_CONTINUE; + } + + // Stamp arrival here rather than after k_sem_take() returns, so the + // measurement does not absorb the woken thread's scheduling delay. + session->elapsed_ms = k_uptime_get() - session->sent_ms; + k_sem_give(&session->reply_sem); + + return NET_OK; +} mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, mp_float_t timeout) { - // esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG(); - // ipaddress_ipaddress_to_esp_idf(ip_address, &ping_config.target_addr); - // ping_config.count = 1; - - // // We must fetch ping information using the callback mechanism, because the session storage is freed when - // // the ping session is done, even before esp_ping_delete_session(). - // esp_ping_callbacks_t ping_callbacks = { - // .on_ping_success = ping_success_cb, - // .cb_args = (void *)self, - // }; + // radio.ping() is documented to take an ipaddress.IPv4Address. + if (!mp_obj_is_type(ip_address, &ipaddress_ipv4address_type)) { + mp_raise_ValueError(MP_ERROR_TEXT("Only IPv4 addresses supported")); + } - // size_t timeout_ms = timeout * 1000; + // get_packed() takes a concrete ipaddress_ipv4address_obj_t *, so the + // MP_OBJ_TO_PTR is needed under object representations C and D. + ipaddress_ipv4address_obj_t *addr_obj = MP_OBJ_TO_PTR(ip_address); + size_t packed_len; + const char *packed = mp_obj_str_get_data( + common_hal_ipaddress_ipv4address_get_packed(addr_obj), &packed_len); + if (packed_len != sizeof(struct net_in_addr)) { + mp_raise_ValueError(MP_ERROR_TEXT("Only IPv4 addresses supported")); + } - // // ESP-IDF creates a task to do the ping session. It shuts down when done, but only after a one second delay. - // // Calling common_hal_wifi_radio_ping() too fast will cause resource exhaustion. - // esp_ping_handle_t ping; - // if (esp_ping_new_session(&ping_config, &ping_callbacks, &ping) != ESP_OK) { - // // Wait for old task to go away and then try again. - // // Empirical testing shows we have to wait at least two seconds, despite the task - // // having a one-second timeout. - // common_hal_time_delay_ms(2000); - // // Return if interrupted now, to show the interruption as KeyboardInterrupt instead of the - // // IDF error. - // if (mp_hal_is_interrupted()) { - // return (uint32_t)(-1); - // } - // CHECK_ESP_RESULT(esp_ping_new_session(&ping_config, &ping_callbacks, &ping)); - // } + // This Zephyr renamed the socket address types, so the destination is a + // struct net_sockaddr_in carrying NET_AF_INET, not a sockaddr_in/AF_INET. + struct net_sockaddr_in dst = { + .sin_family = NET_AF_INET, + }; + memcpy(&dst.sin_addr, packed, sizeof(dst.sin_addr)); + + if (ping_identifier == 0) { + // Seeded lazily. sys_rand16_get() may legitimately return 0, in which + // case we simply reseed on the next call. + ping_identifier = sys_rand16_get(); + } - // // Use all ones as a flag that the elapsed time was not set (ping failed or timed out). - // self->ping_elapsed_time = (uint32_t)(-1); + ping_session_t session = { + .identifier = ping_identifier, + .sequence = ++ping_sequence, + .elapsed_ms = -1, + }; + k_sem_init(&session.reply_sem, 0, 1); + + struct net_icmp_ctx icmp_ctx; + int res = net_icmp_init_ctx(&icmp_ctx, NET_AF_INET, NET_ICMPV4_ECHO_REPLY, 0, + ping_reply_handler); + if (res < 0) { + LOG_DBG("ping: net_icmp_init_ctx failed (%d)", res); + return -1; + } - // esp_ping_start(ping); + struct net_icmp_ping_params params = { + .identifier = session.identifier, + .sequence = session.sequence, + .tc_tos = 0, + // A negative priority leaves the packet at the stack default and lets + // tc_tos drive the DSCP/ECN bits instead. + .priority = -1, + .data = NULL, + .data_size = 0, + }; + + session.sent_ms = k_uptime_get(); + + // A NULL sta_netif is fine; the stack picks an interface from the + // destination. This is the blocking send, as Zephyr's net shell uses: it + // waits up to a second for a buffer, so a ping can take timeout + 1s. + res = net_icmp_send_echo_request(&icmp_ctx, self->sta_netif, + (struct net_sockaddr *)&dst, ¶ms, &session); + if (res < 0) { + LOG_DBG("ping: send failed (%d)", res); + (void)net_icmp_cleanup_ctx(&icmp_ctx); + return -1; + } - // uint32_t start_time = common_hal_time_monotonic_ms(); - // while ((self->ping_elapsed_time == (uint32_t)(-1)) && - // (common_hal_time_monotonic_ms() - start_time < timeout_ms) && - // !mp_hal_is_interrupted()) { - // RUN_BACKGROUND_TASKS; - // } - // esp_ping_stop(ping); - // esp_ping_delete_session(ping); + // Wait for ping_reply_handler() to signal, staying responsive to ctrl-C at + // the same 50 ms granularity as the association wait in + // common_hal_wifi_radio_connect(). + mp_float_t timeout_s = timeout <= 0 ? (mp_float_t)0.5 : timeout; + int64_t deadline = k_uptime_get() + (int64_t)(timeout_s * 1000); + bool replied = false; + while (true) { + int64_t remaining_ms = deadline - k_uptime_get(); + if (remaining_ms <= 0) { + break; + } + + // Poll in 50 ms slices so ctrl-C stays responsive, clamped to the + // caller's deadline so a reply arriving after the timeout is not + // reported as a success. MIN() is avoided here because py/misc.h and + // zephyr/sys/util.h both define it and this file includes both. + int64_t wait_ms = remaining_ms < 50 ? remaining_ms : 50; + + if (k_sem_take(&session.reply_sem, K_MSEC(wait_ms)) == 0) { + replied = true; + break; + } + if (mp_hal_is_interrupted()) { + break; + } + } + + // Unregister before returning. net_icmp_cleanup_ctx() takes the same mutex + // the stack holds while dispatching handlers, so once it returns no handler + // can still be looking at session, which lives on this stack frame. This + // has to happen on every exit path, including the error paths above. + (void)net_icmp_cleanup_ctx(&icmp_ctx); + + if (!replied || session.elapsed_ms < 0) { + return -1; + } - // return (mp_int_t)self->ping_elapsed_time; - return 0; + // shared-bindings turns exactly -1 into None and divides anything else by + // 1000, so every failure path must return -1, not 0. + return (mp_int_t)session.elapsed_ms; } +#else +mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, mp_float_t timeout) { + // Boards that turn ping off to save flash report no reply. + return -1; +} +#endif void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self) { // Only bother to scan the actual object references. diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.h b/ports/zephyr-cp/common-hal/wifi/Radio.h index f177f493685..2500079df09 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.h +++ b/ports/zephyr-cp/common-hal/wifi/Radio.h @@ -11,7 +11,9 @@ #include "shared-bindings/wifi/ScannedNetworks.h" #include "shared-bindings/wifi/Network.h" +#include #include +#include // Event bits for the Radio event group. #define WIFI_SCAN_DONE_BIT BIT0 @@ -38,6 +40,16 @@ typedef struct { uint8_t retries_left; uint8_t starting_retries; uint8_t last_disconnect_reason; + // Signalled from the net_mgmt event handler when a connect attempt + // finishes, so common_hal_wifi_radio_connect() can wait on the result. + struct k_sem connect_sem; + // Latest wifi_conn_status from NET_EVENT_WIFI_CONNECT_RESULT. + int last_connect_status; + bool connected; + // SSID of the association that `connected` refers to, so that a connect() + // for the network we are already on can return without touching the link. + uint8_t current_ssid[WIFI_SSID_MAX_LEN]; + size_t current_ssid_len; } wifi_radio_obj_t; extern void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self); diff --git a/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c b/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c index 3a6c21c5b83..d7df14ffa5c 100644 --- a/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c +++ b/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c @@ -16,14 +16,18 @@ #include "shared-bindings/wifi/Network.h" #include "shared-bindings/wifi/Radio.h" #include "shared-bindings/wifi/ScannedNetworks.h" +#include "bindings/zephyr_kernel/__init__.h" #include +#include #include +LOG_MODULE_DECLARE(cp_wifi); + void wifi_scannednetworks_scan_result(wifi_scannednetworks_obj_t *self, struct wifi_scan_result *result) { if (k_msgq_put(&self->msgq, result, K_NO_WAIT) != 0) { - printk("Dropping scan result!\n"); + LOG_WRN("Dropping scan result"); } } @@ -103,7 +107,7 @@ void wifi_scannednetworks_scan_next_channel(wifi_scannednetworks_obj_t *self) { } else { int res = net_mgmt(NET_REQUEST_WIFI_SCAN, self->netif, ¶ms, sizeof(params)); if (res != 0) { - printk("Failed to start wifi scan %d\n", res); + LOG_ERR("Failed to start wifi scan %d", res); raise_zephyr_error(res); wifi_scannednetworks_done(self); } else { diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 57f073a9cbb..182ae5a3c30 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -22,15 +22,24 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include "supervisor/port.h" #include "supervisor/workflow.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + #if CIRCUITPY_STATUS_BAR #include "supervisor/shared/status_bar.h" #endif #include +#include #include +#include + #define MAC_ADDRESS_LENGTH 6 +LOG_MODULE_REGISTER(cp_wifi, CONFIG_LOG_DEFAULT_LEVEL); + static void schedule_background_on_cp_core(void *arg) { #if CIRCUITPY_STATUS_BAR supervisor_status_bar_request_update(false); @@ -44,62 +53,89 @@ static void schedule_background_on_cp_core(void *arg) { static struct net_mgmt_event_callback wifi_cb; static struct net_mgmt_event_callback ipv4_cb; -static void _event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { +static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) { wifi_radio_obj_t *self = &common_hal_wifi_radio_obj; - printk("_event_handler cb %p event %08x if %p\n", cb, mgmt_event, iface); + (void)iface; switch (mgmt_event) { - case NET_EVENT_WIFI_SCAN_RESULT: - printk("NET_EVENT_WIFI_SCAN_RESULT\n"); - struct wifi_scan_result *result = (struct wifi_scan_result *)cb->info; - if (self->current_scan != NULL) { + case NET_EVENT_WIFI_SCAN_RESULT: { + LOG_DBG("NET_EVENT_WIFI_SCAN_RESULT"); + const struct wifi_scan_result *result = cb->info; + if (result != NULL && self->current_scan != NULL) { wifi_scannednetworks_scan_result(self->current_scan, result); } break; + } case NET_EVENT_WIFI_SCAN_DONE: - printk("NET_EVENT_WIFI_SCAN_DONE\n"); + LOG_DBG("NET_EVENT_WIFI_SCAN_DONE (thread: %s prio=%d)", + k_thread_name_get(k_current_get()), + k_thread_priority_get(k_current_get())); if (self->current_scan != NULL) { k_poll_signal_raise(&self->current_scan->channel_done, 0); } break; - case NET_EVENT_WIFI_CONNECT_RESULT: - printk("NET_EVENT_WIFI_CONNECT_RESULT\n"); + case NET_EVENT_WIFI_CONNECT_RESULT: { + const struct wifi_status *status = cb->info; + self->last_connect_status = status != NULL ? status->status : -1; + self->connected = self->last_connect_status == WIFI_STATUS_CONN_SUCCESS; + LOG_DBG("NET_EVENT_WIFI_CONNECT_RESULT status %d", self->last_connect_status); + k_sem_give(&self->connect_sem); break; - case NET_EVENT_WIFI_DISCONNECT_RESULT: - printk("NET_EVENT_WIFI_DISCONNECT_RESULT\n"); + } + case NET_EVENT_WIFI_DISCONNECT_RESULT: { + const struct wifi_status *status = cb->info; + self->last_disconnect_reason = status != NULL ? (uint8_t)status->status : 0; + self->connected = false; + LOG_DBG("NET_EVENT_WIFI_DISCONNECT_RESULT reason %d", self->last_disconnect_reason); + // A disconnect can also be the failure result of a connect attempt, + // so release any waiter rather than letting it sit until timeout. + k_sem_give(&self->connect_sem); break; + } case NET_EVENT_WIFI_IFACE_STATUS: - printk("NET_EVENT_WIFI_IFACE_STATUS\n"); + LOG_DBG("NET_EVENT_WIFI_IFACE_STATUS"); break; case NET_EVENT_WIFI_TWT: - printk("NET_EVENT_WIFI_TWT\n"); + LOG_DBG("NET_EVENT_WIFI_TWT"); break; case NET_EVENT_WIFI_TWT_SLEEP_STATE: - printk("NET_EVENT_WIFI_TWT_SLEEP_STATE\n"); + LOG_DBG("NET_EVENT_WIFI_TWT_SLEEP_STATE"); break; case NET_EVENT_WIFI_RAW_SCAN_RESULT: - printk("NET_EVENT_WIFI_RAW_SCAN_RESULT\n"); + LOG_DBG("NET_EVENT_WIFI_RAW_SCAN_RESULT"); break; case NET_EVENT_WIFI_DISCONNECT_COMPLETE: - printk("NET_EVENT_WIFI_DISCONNECT_COMPLETE\n"); + LOG_DBG("NET_EVENT_WIFI_DISCONNECT_COMPLETE"); break; case NET_EVENT_WIFI_SIGNAL_CHANGE: - printk("NET_EVENT_WIFI_SIGNAL_CHANGE\n"); + LOG_DBG("NET_EVENT_WIFI_SIGNAL_CHANGE"); break; case NET_EVENT_WIFI_NEIGHBOR_REP_COMP: - printk("NET_EVENT_WIFI_NEIGHBOR_REP_COMP\n"); + LOG_DBG("NET_EVENT_WIFI_NEIGHBOR_REP_COMP"); break; case NET_EVENT_WIFI_AP_ENABLE_RESULT: - printk("NET_EVENT_WIFI_AP_ENABLE_RESULT\n"); + LOG_DBG("NET_EVENT_WIFI_AP_ENABLE_RESULT"); break; case NET_EVENT_WIFI_AP_DISABLE_RESULT: - printk("NET_EVENT_WIFI_AP_DISABLE_RESULT\n"); + LOG_DBG("NET_EVENT_WIFI_AP_DISABLE_RESULT"); break; case NET_EVENT_WIFI_AP_STA_CONNECTED: - printk("NET_EVENT_WIFI_AP_STA_CONNECTED\n"); + LOG_DBG("NET_EVENT_WIFI_AP_STA_CONNECTED"); break; case NET_EVENT_WIFI_AP_STA_DISCONNECTED: - printk("NET_EVENT_WIFI_AP_STA_DISCONNECTED\n"); + LOG_DBG("NET_EVENT_WIFI_AP_STA_DISCONNECTED"); + break; + case NET_EVENT_IPV4_ADDR_ADD: + // DHCP bound, or a static address was configured. The address is read + // live by the ipv4_address getter, so nothing is stored here; the + // status bar just needs a refresh or it keeps showing "No IP". + LOG_DBG("NET_EVENT_IPV4_ADDR_ADD"); + schedule_background_on_cp_core(NULL); + break; + default: + // Print all 64 bits. The layer lives in the high bits, so a 32-bit + // print collapses every unhandled event in a layer to one value. + LOG_DBG("unhandled net event %llx", (unsigned long long)mgmt_event); break; } } @@ -184,7 +220,7 @@ static bool wifi_user_initiated; void common_hal_wifi_init(bool user_initiated) { wifi_radio_obj_t *self = &common_hal_wifi_radio_obj; - printk("common_hal_wifi_init\n"); + LOG_DBG("common_hal_wifi_init"); if (wifi_inited) { if (user_initiated && !wifi_user_initiated) { @@ -195,6 +231,9 @@ void common_hal_wifi_init(bool user_initiated) { wifi_inited = true; wifi_user_initiated = user_initiated; self->base.type = &wifi_radio_type; + k_sem_init(&self->connect_sem, 0, 1); + self->connected = false; + self->last_connect_status = -1; // struct net_if *default_iface = net_if_get_default(); // printk("default interface %p\n", default_iface); @@ -211,8 +250,8 @@ void common_hal_wifi_init(bool user_initiated) { // } self->sta_netif = net_if_get_wifi_sta(); self->ap_netif = net_if_get_wifi_sap(); - printk("sta_netif %p\n", self->sta_netif); - printk("ap_netif %p\n", self->ap_netif); + LOG_DBG("sta_netif %p", self->sta_netif); + LOG_DBG("ap_netif %p", self->ap_netif); struct wifi_iface_status status = { 0 }; @@ -220,39 +259,39 @@ void common_hal_wifi_init(bool user_initiated) { CHECK_ZEPHYR_RESULT(net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, self->sta_netif, &status, sizeof(struct wifi_iface_status))); if (net_if_is_up(self->sta_netif)) { - printk("STA is up\n"); + LOG_DBG("STA is up"); } else { - printk("STA is down\n"); + LOG_DBG("STA is down"); } if (net_if_is_carrier_ok(self->sta_netif)) { - printk("STA carrier is ok\n"); + LOG_DBG("STA carrier is ok"); } else { - printk("STA carrier is not ok\n"); + LOG_DBG("STA carrier is not ok"); } if (net_if_is_dormant(self->sta_netif)) { - printk("STA is dormant\n"); + LOG_DBG("STA is dormant"); } else { - printk("STA is not dormant\n"); + LOG_DBG("STA is not dormant"); } } if (self->ap_netif != NULL) { int res = net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, self->ap_netif, &status, sizeof(struct wifi_iface_status)); - printk("AP status request response %d\n", res); + LOG_DBG("AP status request response %d", res); if (net_if_is_up(self->ap_netif)) { - printk("AP is up\n"); + LOG_DBG("AP is up"); } else { - printk("AP is down\n"); + LOG_DBG("AP is down"); } if (net_if_is_carrier_ok(self->ap_netif)) { - printk("AP carrier is ok\n"); + LOG_DBG("AP carrier is ok"); } else { - printk("AP carrier is not ok\n"); + LOG_DBG("AP carrier is not ok"); } if (net_if_is_dormant(self->ap_netif)) { - printk("AP is dormant\n"); + LOG_DBG("AP is dormant"); } else { - printk("AP is not dormant\n"); + LOG_DBG("AP is not dormant"); } } @@ -266,6 +305,7 @@ void common_hal_wifi_init(bool user_initiated) { // self->ap_mode = 0; net_mgmt_init_event_callback(&wifi_cb, _event_handler, + NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE | NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT | @@ -281,6 +321,7 @@ void common_hal_wifi_init(bool user_initiated) { net_mgmt_add_event_callback(&wifi_cb); net_mgmt_add_event_callback(&ipv4_cb); + #if defined(CONFIG_NET_HOSTNAME) // Set the default hostname capped at NET_HOSTNAME_MAX_LEN characters. We trim off // the start of the board name (likely manufacturer) because the end is // often more unique to the board. @@ -291,22 +332,34 @@ void common_hal_wifi_init(bool user_initiated) { board_trim++; } - char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; - struct net_linkaddr *mac = net_if_get_link_addr(self->sta_netif); - if (mac->len < MAC_ADDRESS_LENGTH) { - printk("MAC address too short"); + #if CIRCUITPY_SETTINGS_TOML + char hostname[NET_HOSTNAME_MAX_LEN]; + if (settings_get_str("CIRCUITPY_WIFI_HOSTNAME", hostname, sizeof(hostname)) == SETTINGS_OK) { + CHECK_ZEPHYR_RESULT(net_hostname_set(hostname, strlen(hostname))); + } + #else + if (false) { } - snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac->addr[0], mac->addr[1], mac->addr[2], mac->addr[3], mac->addr[4], mac->addr[5]); + #endif + else { + char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; + struct net_linkaddr *mac = net_if_get_link_addr(self->sta_netif); + if (mac->len < MAC_ADDRESS_LENGTH) { + LOG_ERR("MAC address too short"); + } + snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac->addr[0], mac->addr[1], mac->addr[2], mac->addr[3], mac->addr[4], mac->addr[5]); - if (net_hostname_set(cpy_default_hostname, strlen(cpy_default_hostname)) != 0) { - printk("setting hostname failed\n"); + CHECK_ZEPHYR_RESULT(net_hostname_set(cpy_default_hostname, strlen(cpy_default_hostname))); } + #else + LOG_WRN("Hostname support disabled in Zephyr config"); + #endif // set station mode to avoid the default SoftAP common_hal_wifi_radio_start_station(self); // start wifi common_hal_wifi_radio_set_enabled(self, true); - printk("common_hal_wifi_init done\n"); + LOG_DBG("common_hal_wifi_init done"); } void wifi_user_reset(void) { @@ -317,7 +370,7 @@ void wifi_user_reset(void) { } void wifi_reset(void) { - printk("wifi_reset\n"); + LOG_DBG("wifi_reset"); if (!wifi_inited) { return; } diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.h b/ports/zephyr-cp/common-hal/wifi/__init__.h index dab519b1a5f..937ac699021 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.h +++ b/ports/zephyr-cp/common-hal/wifi/__init__.h @@ -8,6 +8,8 @@ #include "py/obj.h" +#include + struct sockaddr_storage; void wifi_reset(void); diff --git a/ports/zephyr-cp/common-hal/zephyr_display/Display.c b/ports/zephyr-cp/common-hal/zephyr_display/Display.c new file mode 100644 index 00000000000..d1585b5f291 --- /dev/null +++ b/ports/zephyr-cp/common-hal/zephyr_display/Display.c @@ -0,0 +1,440 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/zephyr_display/Display.h" + +#include + +#include "bindings/zephyr_kernel/__init__.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/display.h" +#include "supervisor/shared/tick.h" + +static const displayio_area_t *zephyr_display_get_refresh_areas(zephyr_display_display_obj_t *self) { + if (self->core.full_refresh) { + self->core.area.next = NULL; + return &self->core.area; + } else if (self->core.current_group != NULL) { + return displayio_group_get_refresh_areas(self->core.current_group, NULL); + } + return NULL; +} + +static enum display_pixel_format zephyr_display_select_pixel_format(const struct display_capabilities *caps) { + uint32_t formats = caps->supported_pixel_formats; + + if (formats & PIXEL_FORMAT_RGB_565) { + return PIXEL_FORMAT_RGB_565; + } + if (formats & PIXEL_FORMAT_RGB_888) { + return PIXEL_FORMAT_RGB_888; + } + if (formats & PIXEL_FORMAT_ARGB_8888) { + return PIXEL_FORMAT_ARGB_8888; + } + if (formats & PIXEL_FORMAT_RGB_565X) { + return PIXEL_FORMAT_RGB_565X; + } + if (formats & PIXEL_FORMAT_L_8) { + return PIXEL_FORMAT_L_8; + } + if (formats & PIXEL_FORMAT_AL_88) { + return PIXEL_FORMAT_AL_88; + } + if (formats & PIXEL_FORMAT_MONO01) { + return PIXEL_FORMAT_MONO01; + } + if (formats & PIXEL_FORMAT_MONO10) { + return PIXEL_FORMAT_MONO10; + } + return caps->current_pixel_format; +} + +static void zephyr_display_select_colorspace(zephyr_display_display_obj_t *self, + uint16_t *color_depth, + uint8_t *bytes_per_cell, + bool *grayscale, + bool *pixels_in_byte_share_row, + bool *reverse_pixels_in_byte, + bool *reverse_bytes_in_word) { + *color_depth = 16; + *bytes_per_cell = 2; + *grayscale = false; + *pixels_in_byte_share_row = false; + *reverse_pixels_in_byte = false; + *reverse_bytes_in_word = false; + + if (self->pixel_format == PIXEL_FORMAT_RGB_565X) { + // RGB_565X is big-endian RGB_565, so byte-swap from native LE. + *reverse_bytes_in_word = true; + } else if (self->pixel_format == PIXEL_FORMAT_RGB_888) { + *color_depth = 24; + *bytes_per_cell = 3; + *reverse_bytes_in_word = false; + } else if (self->pixel_format == PIXEL_FORMAT_ARGB_8888) { + *color_depth = 32; + *bytes_per_cell = 4; + *reverse_bytes_in_word = false; + } else if (self->pixel_format == PIXEL_FORMAT_L_8 || + self->pixel_format == PIXEL_FORMAT_AL_88) { + *color_depth = 8; + *bytes_per_cell = 1; + *grayscale = true; + *reverse_bytes_in_word = false; + } else if (self->pixel_format == PIXEL_FORMAT_MONO01 || + self->pixel_format == PIXEL_FORMAT_MONO10) { + bool vtiled = self->capabilities.screen_info & SCREEN_INFO_MONO_VTILED; + bool msb_first = self->capabilities.screen_info & SCREEN_INFO_MONO_MSB_FIRST; + *color_depth = 1; + *bytes_per_cell = 1; + *grayscale = true; + *pixels_in_byte_share_row = !vtiled; + *reverse_pixels_in_byte = msb_first; + *reverse_bytes_in_word = false; + } +} + +void common_hal_zephyr_display_display_construct_from_device(zephyr_display_display_obj_t *self, + const struct device *device, + uint16_t rotation, + bool auto_refresh) { + self->auto_refresh = false; + + if (device == NULL || !device_is_ready(device)) { + raise_zephyr_error(-ENODEV); + } + + self->device = device; + display_get_capabilities(self->device, &self->capabilities); + + self->pixel_format = zephyr_display_select_pixel_format(&self->capabilities); + if (self->pixel_format != self->capabilities.current_pixel_format) { + (void)display_set_pixel_format(self->device, self->pixel_format); + display_get_capabilities(self->device, &self->capabilities); + self->pixel_format = self->capabilities.current_pixel_format; + } + + uint16_t color_depth; + uint8_t bytes_per_cell; + bool grayscale; + bool pixels_in_byte_share_row; + bool reverse_pixels_in_byte; + bool reverse_bytes_in_word; + zephyr_display_select_colorspace(self, &color_depth, &bytes_per_cell, + &grayscale, &pixels_in_byte_share_row, &reverse_pixels_in_byte, + &reverse_bytes_in_word); + + displayio_display_core_construct( + &self->core, + self->capabilities.x_resolution, + self->capabilities.y_resolution, + 0, + color_depth, + grayscale, + pixels_in_byte_share_row, + bytes_per_cell, + reverse_pixels_in_byte, + reverse_bytes_in_word); + + self->native_frames_per_second = 60; + self->native_ms_per_frame = 1000 / self->native_frames_per_second; + self->first_manual_refresh = !auto_refresh; + + if (rotation != 0) { + common_hal_zephyr_display_display_set_rotation(self, rotation); + } + + (void)display_blanking_off(self->device); + + displayio_display_core_set_root_group(&self->core, &circuitpython_splash); + common_hal_zephyr_display_display_set_auto_refresh(self, auto_refresh); +} + +uint16_t common_hal_zephyr_display_display_get_width(zephyr_display_display_obj_t *self) { + return displayio_display_core_get_width(&self->core); +} + +uint16_t common_hal_zephyr_display_display_get_height(zephyr_display_display_obj_t *self) { + return displayio_display_core_get_height(&self->core); +} + +mp_float_t common_hal_zephyr_display_display_get_brightness(zephyr_display_display_obj_t *self) { + (void)self; + return -1; +} + +bool common_hal_zephyr_display_display_set_brightness(zephyr_display_display_obj_t *self, mp_float_t brightness) { + (void)self; + (void)brightness; + return false; +} + +static bool zephyr_display_refresh_area(zephyr_display_display_obj_t *self, const displayio_area_t *area) { + uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof(uint32_t); + + displayio_area_t clipped; + if (!displayio_display_core_clip_area(&self->core, area, &clipped)) { + return true; + } + + uint16_t rows_per_buffer = displayio_area_height(&clipped); + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; + // For AL_88, displayio fills at 1 byte/pixel (L_8) but output needs 2 bytes/pixel, + // so halve the effective pixels_per_word for buffer sizing. + uint8_t effective_pixels_per_word = pixels_per_word; + if (self->pixel_format == PIXEL_FORMAT_AL_88) { + effective_pixels_per_word = sizeof(uint32_t) / 2; + } + uint16_t pixels_per_buffer = displayio_area_size(&clipped); + uint16_t subrectangles = 1; + + // When pixels_in_byte_share_row is false (mono vtiled), 8 vertical pixels + // pack into one column byte. The byte layout needs width * ceil(height/8) + // bytes, which can exceed the pixel-count-based buffer size. + bool vtiled = self->core.colorspace.depth < 8 && + !self->core.colorspace.pixels_in_byte_share_row; + + bool needs_subdivision = displayio_area_size(&clipped) > buffer_size * effective_pixels_per_word; + if (vtiled && !needs_subdivision) { + uint16_t width = displayio_area_width(&clipped); + uint16_t height = displayio_area_height(&clipped); + uint32_t vtiled_bytes = (uint32_t)width * ((height + 7) / 8); + needs_subdivision = vtiled_bytes > buffer_size * sizeof(uint32_t); + } + + if (needs_subdivision) { + rows_per_buffer = buffer_size * effective_pixels_per_word / displayio_area_width(&clipped); + if (vtiled) { + rows_per_buffer = (rows_per_buffer / 8) * 8; + if (rows_per_buffer == 0) { + rows_per_buffer = 8; + } + } + if (rows_per_buffer == 0) { + rows_per_buffer = 1; + } + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } + // Ensure buffer is large enough for vtiled packing. + if (vtiled) { + uint16_t width = displayio_area_width(&clipped); + uint16_t vtiled_words = (width * ((rows_per_buffer + 7) / 8) + sizeof(uint32_t) - 1) / sizeof(uint32_t); + if (vtiled_words > buffer_size) { + buffer_size = vtiled_words; + } + } + // Ensure buffer is large enough for AL_88 expansion. + if (self->pixel_format == PIXEL_FORMAT_AL_88) { + uint16_t al88_words = (pixels_per_buffer * 2 + sizeof(uint32_t) - 1) / sizeof(uint32_t); + if (al88_words > buffer_size) { + buffer_size = al88_words; + } + } + } + + uint32_t buffer[buffer_size]; + uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask[mask_length]; + + uint16_t remaining_rows = displayio_area_height(&clipped); + + for (uint16_t j = 0; j < subrectangles; j++) { + displayio_area_t subrectangle = { + .x1 = clipped.x1, + .y1 = clipped.y1 + rows_per_buffer * j, + .x2 = clipped.x2, + .y2 = clipped.y1 + rows_per_buffer * (j + 1), + }; + + if (remaining_rows < rows_per_buffer) { + subrectangle.y2 = subrectangle.y1 + remaining_rows; + } + remaining_rows -= rows_per_buffer; + + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); + + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); + + uint16_t width = displayio_area_width(&subrectangle); + uint16_t height = displayio_area_height(&subrectangle); + size_t pixel_count = (size_t)width * (size_t)height; + + if (self->pixel_format == PIXEL_FORMAT_MONO10) { + uint8_t *bytes = (uint8_t *)buffer; + size_t byte_count = (pixel_count + 7) / 8; + for (size_t i = 0; i < byte_count; i++) { + bytes[i] = ~bytes[i]; + } + } + + if (self->pixel_format == PIXEL_FORMAT_AL_88) { + uint8_t *bytes = (uint8_t *)buffer; + for (size_t i = pixel_count; i > 0; i--) { + bytes[(i - 1) * 2 + 1] = 0xFF; + bytes[(i - 1) * 2] = bytes[i - 1]; + } + } + + // Compute buf_size based on the Zephyr pixel format. + uint32_t buf_size_bytes; + if (self->pixel_format == PIXEL_FORMAT_MONO01 || + self->pixel_format == PIXEL_FORMAT_MONO10) { + buf_size_bytes = (pixel_count + 7) / 8; + } else if (self->pixel_format == PIXEL_FORMAT_AL_88) { + buf_size_bytes = pixel_count * 2; + } else { + buf_size_bytes = pixel_count * (self->core.colorspace.depth / 8); + } + + struct display_buffer_descriptor desc = { + .buf_size = buf_size_bytes, + .width = width, + .height = height, + .pitch = width, + .frame_incomplete = false, + }; + + int err = display_write(self->device, subrectangle.x1, subrectangle.y1, &desc, buffer); + if (err < 0) { + return false; + } + + RUN_BACKGROUND_TASKS; + } + + return true; +} + +static void zephyr_display_refresh(zephyr_display_display_obj_t *self) { + if (!displayio_display_core_start_refresh(&self->core)) { + return; + } + + const displayio_area_t *current_area = zephyr_display_get_refresh_areas(self); + while (current_area != NULL) { + if (!zephyr_display_refresh_area(self, current_area)) { + break; + } + current_area = current_area->next; + } + + displayio_display_core_finish_refresh(&self->core); +} + +void common_hal_zephyr_display_display_set_rotation(zephyr_display_display_obj_t *self, int rotation) { + bool transposed = (self->core.rotation == 90 || self->core.rotation == 270); + bool will_transposed = (rotation == 90 || rotation == 270); + if (transposed != will_transposed) { + int tmp = self->core.width; + self->core.width = self->core.height; + self->core.height = tmp; + } + + displayio_display_core_set_rotation(&self->core, rotation); + + if (self == &displays[0].zephyr_display) { + supervisor_stop_terminal(); + supervisor_start_terminal(self->core.width, self->core.height); + } + + if (self->core.current_group != NULL) { + displayio_group_update_transform(self->core.current_group, &self->core.transform); + } +} + +uint16_t common_hal_zephyr_display_display_get_rotation(zephyr_display_display_obj_t *self) { + return self->core.rotation; +} + +bool common_hal_zephyr_display_display_refresh(zephyr_display_display_obj_t *self, + uint32_t target_ms_per_frame, + uint32_t maximum_ms_per_real_frame) { + if (!self->auto_refresh && !self->first_manual_refresh && (target_ms_per_frame != NO_FPS_LIMIT)) { + uint64_t current_time = supervisor_ticks_ms64(); + uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh; + if (current_ms_since_real_refresh > maximum_ms_per_real_frame) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Below minimum frame rate")); + } + uint32_t current_ms_since_last_call = current_time - self->last_refresh_call; + self->last_refresh_call = current_time; + if (current_ms_since_last_call > target_ms_per_frame) { + return false; + } + uint32_t remaining_time = target_ms_per_frame - (current_ms_since_real_refresh % target_ms_per_frame); + while (supervisor_ticks_ms64() - self->last_refresh_call < remaining_time) { + RUN_BACKGROUND_TASKS; + } + } + self->first_manual_refresh = false; + zephyr_display_refresh(self); + return true; +} + +bool common_hal_zephyr_display_display_get_auto_refresh(zephyr_display_display_obj_t *self) { + return self->auto_refresh; +} + +void common_hal_zephyr_display_display_set_auto_refresh(zephyr_display_display_obj_t *self, bool auto_refresh) { + self->first_manual_refresh = !auto_refresh; + if (auto_refresh != self->auto_refresh) { + if (auto_refresh) { + supervisor_enable_tick(); + } else { + supervisor_disable_tick(); + } + } + self->auto_refresh = auto_refresh; +} + +void zephyr_display_display_background(zephyr_display_display_obj_t *self) { + if (self->auto_refresh && (supervisor_ticks_ms64() - self->core.last_refresh) > self->native_ms_per_frame) { + zephyr_display_refresh(self); + } +} + +void release_zephyr_display(zephyr_display_display_obj_t *self) { + common_hal_zephyr_display_display_set_auto_refresh(self, false); + release_display_core(&self->core); + self->device = NULL; + self->base.type = &mp_type_NoneType; +} + +void zephyr_display_display_collect_ptrs(zephyr_display_display_obj_t *self) { + (void)self; + displayio_display_core_collect_ptrs(&self->core); +} + +void zephyr_display_display_reset(zephyr_display_display_obj_t *self) { + if (self->device != NULL && device_is_ready(self->device)) { + common_hal_zephyr_display_display_set_auto_refresh(self, true); + displayio_display_core_set_root_group(&self->core, &circuitpython_splash); + self->core.full_refresh = true; + } else { + release_zephyr_display(self); + } +} + +mp_obj_t common_hal_zephyr_display_display_get_root_group(zephyr_display_display_obj_t *self) { + if (self->core.current_group == NULL) { + return mp_const_none; + } + return self->core.current_group; +} + +bool common_hal_zephyr_display_display_set_root_group(zephyr_display_display_obj_t *self, displayio_group_t *root_group) { + return displayio_display_core_set_root_group(&self->core, root_group); +} diff --git a/ports/zephyr-cp/common-hal/zephyr_display/Display.h b/ports/zephyr-cp/common-hal/zephyr_display/Display.h new file mode 100644 index 00000000000..bdec1e96ba5 --- /dev/null +++ b/ports/zephyr-cp/common-hal/zephyr_display/Display.h @@ -0,0 +1,31 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" +#include "shared-module/displayio/display_core.h" + +typedef struct { + mp_obj_base_t base; + displayio_display_core_t core; + const struct device *device; + struct display_capabilities capabilities; + enum display_pixel_format pixel_format; + uint64_t last_refresh_call; + uint16_t native_frames_per_second; + uint16_t native_ms_per_frame; + bool auto_refresh; + bool first_manual_refresh; +} zephyr_display_display_obj_t; + +void zephyr_display_display_background(zephyr_display_display_obj_t *self); +void zephyr_display_display_collect_ptrs(zephyr_display_display_obj_t *self); +void zephyr_display_display_reset(zephyr_display_display_obj_t *self); +void release_zephyr_display(zephyr_display_display_obj_t *self); diff --git a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c b/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c deleted file mode 100644 index d5bb0d44669..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c +++ /dev/null @@ -1,92 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries -// SPDX-FileCopyrightText: Copyright (c) 2018 Artur Pacholec -// SPDX-FileCopyrightText: Copyright (c) 2017 hathach -// SPDX-FileCopyrightText: Copyright (c) 2016 Sandeep Mistry All right reserved. -// -// SPDX-License-Identifier: MIT - -#include "shared-bindings/busio/I2C.h" -#include "shared-bindings/microcontroller/__init__.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "supervisor/shared/tick.h" -#include "py/mperrno.h" -#include "py/runtime.h" - - -void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { - // never_reset_pin_number(self->scl_pin_number); - // never_reset_pin_number(self->sda_pin_number); -} - -void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - -} - -bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { - // return self->sda_pin_number == NO_PIN; - return true; -} - -void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { - if (common_hal_busio_i2c_deinited(self)) { - return; - } - - // nrfx_twim_uninit(&self->twim_peripheral->twim); - - // reset_pin_number(self->sda_pin_number); - // reset_pin_number(self->scl_pin_number); - - // self->twim_peripheral->in_use = false; - // common_hal_busio_i2c_mark_deinit(self); -} - -void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { - // self->sda_pin_number = NO_PIN; -} - -// nrfx_twim_tx doesn't support 0-length data so we fall back to the hal API -bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - bool found = true; - - return found; -} - -bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { - if (common_hal_busio_i2c_deinited(self)) { - return false; - } - bool grabbed_lock = false; - return grabbed_lock; -} - -bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { - return self->has_lock; -} - -void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { - self->has_lock = false; -} - -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { - return 0; -} - -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { - if (len == 0) { - return 0; - } - -} - -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, - uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); - if (result != 0) { - return result; - } - - return common_hal_busio_i2c_read(self, addr, in_data, in_len); -} diff --git a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h b/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h deleted file mode 100644 index 22e9251b3f1..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h +++ /dev/null @@ -1,17 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - // twim_peripheral_t *twim_peripheral; - bool has_lock; - uint8_t scl_pin_number; - uint8_t sda_pin_number; -} busio_i2c_obj_t; diff --git a/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c b/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c index 042f06b0ed2..178f33e028d 100644 --- a/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c +++ b/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c @@ -6,11 +6,15 @@ #include "bindings/zephyr_kernel/__init__.h" #include "py/runtime.h" +#include #include - +#include void raise_zephyr_error(int err) { + if (err == 0) { + return; + } switch (-err) { case EALREADY: printk("EALREADY\n"); @@ -39,7 +43,20 @@ void raise_zephyr_error(int err) { case ENOTSUP: printk("ENOTSUP\n"); break; + case EADDRINUSE: + printk("EADDRINUSE\n"); + break; + case EIO: + printk("EIO\n"); + break; + case ENOSYS: + printk("ENOSYS\n"); + break; + case EINVAL: + printk("EINVAL\n"); + break; default: printk("Zephyr error %d\n", err); } + mp_raise_OSError(-err); } diff --git a/ports/zephyr-cp/common-hal/zephyr_serial/UART.c b/ports/zephyr-cp/common-hal/zephyr_serial/UART.c deleted file mode 100644 index fcc05c22f1a..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_serial/UART.c +++ /dev/null @@ -1,130 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "shared-bindings/microcontroller/__init__.h" -#include "bindings/zephyr_serial/UART.h" - -#include "shared/runtime/interrupt_char.h" -#include "py/mpconfig.h" -#include "py/gc.h" -#include "py/mperrno.h" -#include "py/runtime.h" -#include "py/stream.h" - -#include -#include - -#include - -/* - * Read characters from UART until line end is detected. Afterwards push the - * data to the message queue. - */ -static void serial_cb(const struct device *dev, void *user_data) { - zephyr_serial_uart_obj_t *self = (zephyr_serial_uart_obj_t *)user_data; - - uint8_t c; - - if (!uart_irq_update(dev)) { - return; - } - - if (!uart_irq_rx_ready(dev)) { - return; - } - - /* read until FIFO empty */ - while (uart_fifo_read(dev, &c, 1) == 1) { - if (mp_interrupt_char == c) { - zephyr_serial_uart_clear_rx_buffer(self); - mp_sched_keyboard_interrupt(); - } else if (!self->rx_paused) { - if (k_msgq_put(&self->msgq, &c, K_NO_WAIT) != 0) { - self->rx_paused = true; - } - } - } -} - -void zephyr_serial_uart_never_reset(zephyr_serial_uart_obj_t *self) { -} - - -void zephyr_serial_uart_construct(zephyr_serial_uart_obj_t *self, const struct device *const uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer) { - self->uart_device = uart_device; - int ret = uart_irq_callback_user_data_set(uart_device, serial_cb, self); - - - k_msgq_init(&self->msgq, receiver_buffer, 1, receiver_buffer_size); - - if (ret < 0) { - if (ret == -ENOTSUP) { - printk("Interrupt-driven UART API support not enabled\n"); - } else if (ret == -ENOSYS) { - printk("UART device does not support interrupt-driven API\n"); - } else { - printk("Error setting UART callback: %d\n", ret); - } - return; - } - self->timeout = K_USEC(100); - uart_irq_rx_enable(uart_device); -} - -bool zephyr_serial_uart_deinited(zephyr_serial_uart_obj_t *self) { - return !device_is_ready(self->uart_device); -} - -void zephyr_serial_uart_deinit(zephyr_serial_uart_obj_t *self) { -} - -// Read characters. -size_t zephyr_serial_uart_read(zephyr_serial_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { - size_t count = 0; - while (count < len && k_msgq_get(&self->msgq, data + count, self->timeout) == 0) { - count++; - } - if (count > 0) { - self->rx_paused = false; - } - - return count; -} - -// Write characters. -size_t zephyr_serial_uart_write(zephyr_serial_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { - for (int i = 0; i < len; i++) { - uart_poll_out(self->uart_device, data[i]); - } - - return len; -} - -uint32_t zephyr_serial_uart_get_baudrate(zephyr_serial_uart_obj_t *self) { - return 0; -} - -void zephyr_serial_uart_set_baudrate(zephyr_serial_uart_obj_t *self, uint32_t baudrate) { -} - -mp_float_t zephyr_serial_uart_get_timeout(zephyr_serial_uart_obj_t *self) { - return 0; -} - -void zephyr_serial_uart_set_timeout(zephyr_serial_uart_obj_t *self, mp_float_t timeout) { -} - -uint32_t zephyr_serial_uart_rx_characters_available(zephyr_serial_uart_obj_t *self) { - return k_msgq_num_used_get(&self->msgq); -} - -void zephyr_serial_uart_clear_rx_buffer(zephyr_serial_uart_obj_t *self) { - k_msgq_purge(&self->msgq); -} - -bool zephyr_serial_uart_ready_to_tx(zephyr_serial_uart_obj_t *self) { - return true; -} diff --git a/ports/zephyr-cp/common-hal/zephyr_serial/UART.h b/ports/zephyr-cp/common-hal/zephyr_serial/UART.h deleted file mode 100644 index 4e220ee6307..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_serial/UART.h +++ /dev/null @@ -1,22 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "py/obj.h" - -#include - -typedef struct { - mp_obj_base_t base; - - const struct device *uart_device; - struct k_msgq msgq; - - k_timeout_t timeout; - - bool rx_paused; // set by irq if no space in rbuf -} zephyr_serial_uart_obj_t; diff --git a/ports/zephyr-cp/common-hal/zephyr_spi/SPI.c b/ports/zephyr-cp/common-hal/zephyr_spi/SPI.c deleted file mode 100644 index 5601492fd69..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_spi/SPI.c +++ /dev/null @@ -1,74 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries -// SPDX-FileCopyrightText: Copyright (c) 2018 Artur Pacholec -// -// SPDX-License-Identifier: MIT - -#include - -#include "shared-bindings/busio/SPI.h" -#include "py/mperrno.h" -#include "py/runtime.h" - -void spi_reset(void) { -} - -void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { -} - -void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { - -} - -bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { -} - -void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { - if (common_hal_busio_spi_deinited(self)) { - return; - } -} - -bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { - return true; -} - -bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { - if (common_hal_busio_spi_deinited(self)) { - return false; - } - bool grabbed_lock = false; - return grabbed_lock; -} - -bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { - return self->has_lock; -} - -void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { - self->has_lock = false; -} - -bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { - return true; -} - -bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { - return true; -} - -bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { - return true; -} - -uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) { -} - -uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t *self) { - return 0; -} - -uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { - return 0; -} diff --git a/ports/zephyr-cp/common-hal/zephyr_spi/SPI.h b/ports/zephyr-cp/common-hal/zephyr_spi/SPI.h deleted file mode 100644 index 5a1c91c8f0f..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_spi/SPI.h +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - // const spim_peripheral_t *spim_peripheral; - bool has_lock; - uint8_t clock_pin_number; - uint8_t MOSI_pin_number; - uint8_t MISO_pin_number; -} busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/zephyr-cp/cptools/board_tools.py b/ports/zephyr-cp/cptools/board_tools.py index 088b4bb5491..305abab3f19 100644 --- a/ports/zephyr-cp/cptools/board_tools.py +++ b/ports/zephyr-cp/cptools/board_tools.py @@ -1,3 +1,6 @@ +import tomllib + + def find_mpconfigboard(portdir, board_id): next_underscore = board_id.find("_") while next_underscore != -1: @@ -8,3 +11,27 @@ def find_mpconfigboard(portdir, board_id): return p next_underscore = board_id.find("_", next_underscore + 1) return None + + +def load_mpconfigboard(portdir, board_id): + mpconfigboard_path = find_mpconfigboard(portdir, board_id) + if mpconfigboard_path is None or not mpconfigboard_path.exists(): + return None, {} + + with mpconfigboard_path.open("rb") as f: + return mpconfigboard_path, tomllib.load(f) + + +def get_shields(mpconfigboard): + shields = mpconfigboard.get("SHIELDS") + if shields is None: + shields = mpconfigboard.get("SHIELD") + + if shields is None: + return [] + if isinstance(shields, str): + return [shields] + if isinstance(shields, (list, tuple)): + return [str(shield) for shield in shields] + + return [str(shields)] diff --git a/ports/zephyr-cp/cptools/build_all_boards.py b/ports/zephyr-cp/cptools/build_all_boards.py new file mode 100755 index 00000000000..8505e732efe --- /dev/null +++ b/ports/zephyr-cp/cptools/build_all_boards.py @@ -0,0 +1,520 @@ +#!/usr/bin/env python3 +""" +Build all CircuitPython boards for the Zephyr port. + +This script discovers all boards by finding circuitpython.toml files +and builds them in parallel while sharing a single jobserver across +all builds. + +This is agent generated and works. Don't bother reading too closely because it +is just a tool for us. +""" + +import argparse +import concurrent.futures +import os +import pathlib +import shlex +import subprocess +import sys +import time + + +class Jobserver: + def __init__(self, read_fd, write_fd, jobs=None, owns_fds=False): + self.read_fd = read_fd + self.write_fd = write_fd + self.jobs = jobs + self.owns_fds = owns_fds + + def acquire(self): + while True: + try: + os.read(self.read_fd, 1) + return + except InterruptedError: + continue + + def release(self): + while True: + try: + os.write(self.write_fd, b"+") + return + except InterruptedError: + continue + + def pass_fds(self): + return (self.read_fd, self.write_fd) + + def close(self): + if self.owns_fds: + os.close(self.read_fd) + os.close(self.write_fd) + + +def _parse_makeflags_jobserver(makeflags): + jobserver_auth = None + jobs = None + + for token in shlex.split(makeflags): + if token == "-j" or token == "--jobs": + continue + if token.startswith("-j") and token != "-j": + try: + jobs = int(token[2:]) + except ValueError: + pass + elif token.startswith("--jobs="): + try: + jobs = int(token.split("=", 1)[1]) + except ValueError: + pass + elif token.startswith("--jobserver-auth=") or token.startswith("--jobserver-fds="): + jobserver_auth = token.split("=", 1)[1] + + if not jobserver_auth: + return None, jobs, False + + if jobserver_auth.startswith("fifo:"): + fifo_path = jobserver_auth[len("fifo:") :] + read_fd = os.open(fifo_path, os.O_RDONLY) + write_fd = os.open(fifo_path, os.O_WRONLY) + os.set_inheritable(read_fd, True) + os.set_inheritable(write_fd, True) + return (read_fd, write_fd), jobs, True + + if "," in jobserver_auth: + read_fd, write_fd = jobserver_auth.split(",", 1) + return (int(read_fd), int(write_fd)), jobs, False + + return None, jobs, False + + +def _create_jobserver(jobs): + read_fd, write_fd = os.pipe() + os.set_inheritable(read_fd, True) + os.set_inheritable(write_fd, True) + for _ in range(jobs): + os.write(write_fd, b"+") + return Jobserver(read_fd, write_fd, jobs=jobs, owns_fds=True) + + +def _jobserver_from_env(): + makeflags = os.environ.get("MAKEFLAGS", "") + fds, jobs, owns_fds = _parse_makeflags_jobserver(makeflags) + if not fds: + return None, jobs + read_fd, write_fd = fds + os.set_inheritable(read_fd, True) + os.set_inheritable(write_fd, True) + return Jobserver(read_fd, write_fd, jobs=jobs, owns_fds=owns_fds), jobs + + +def discover_boards(port_dir): + """ + Discover all boards by finding circuitpython.toml files. + + Returns a list of (vendor, board) tuples. + """ + boards = [] + boards_dir = port_dir / "boards" + + # Find all circuitpython.toml files + for toml_file in boards_dir.glob("*/*/circuitpython.toml"): + # Extract vendor and board from path: boards/vendor/board/circuitpython.toml + parts = toml_file.relative_to(boards_dir).parts + if len(parts) == 3: + vendor = parts[0] + board = parts[1] + boards.append((vendor, board)) + + return sorted(boards) + + +def build_board( + port_dir, + vendor, + board, + extra_args=None, + jobserver=None, + env=None, + log_dir=None, +): + """ + Build a single board using make. + + Args: + port_dir: Path to the zephyr-cp port directory + vendor: Board vendor name + board: Board name + extra_args: Additional arguments to pass to make + jobserver: Jobserver instance to limit parallel builds + env: Environment variables for the subprocess + log_dir: Directory to write build logs + + Returns: + (success: bool, elapsed_time: float, output: str, log_path: pathlib.Path) + """ + board_id = f"{vendor}_{board}" + start_time = time.time() + log_path = None + + cmd = ["make", f"BOARD={board_id}"] + + # Add extra arguments (like -j) + if extra_args: + cmd.extend(extra_args) + + if jobserver: + jobserver.acquire() + + try: + result = subprocess.run( + cmd, + cwd=port_dir, + # Inherit stdin alongside jobserver file descriptors + stdin=sys.stdin, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + env=env, + pass_fds=jobserver.pass_fds() if jobserver else (), + ) + elapsed = time.time() - start_time + output = result.stdout or "" + if log_dir: + log_path = log_dir / f"{board_id}.log" + log_path.write_text(output) + return result.returncode == 0, elapsed, output, log_path + except KeyboardInterrupt: + raise + finally: + if jobserver: + jobserver.release() + + +def _format_status(status): + state = status["state"] + elapsed = status.get("elapsed") + if state == "queued": + return "QUEUED" + if state == "running": + return f"RUNNING {elapsed:.1f}s" + if state == "success": + return f"SUCCESS {elapsed:.1f}s" + if state == "failed": + return f"FAILED {elapsed:.1f}s" + if state == "skipped": + return "SKIPPED" + return state.upper() + + +def _build_status_table(boards, statuses, start_time, stop_submitting): + from rich.table import Table + from rich.text import Text + + elapsed = time.time() - start_time + title = f"Building {len(boards)} boards | Elapsed: {elapsed:.1f}s" + if stop_submitting: + title += " | STOPPING AFTER FAILURE" + + table = Table(title=title) + table.add_column("#", justify="right") + table.add_column("Board", no_wrap=True) + table.add_column("Status", no_wrap=True) + + for i, (vendor, board) in enumerate(boards): + board_id = f"{vendor}_{board}" + status_text = _format_status(statuses[i]) + state = statuses[i]["state"] + style = None + if state == "success": + style = "green" + elif state == "failed": + style = "red" + table.add_row( + f"{i + 1}/{len(boards)}", + board_id, + Text(status_text, style=style) if style else status_text, + ) + + return table + + +def _run_builds_tui( + port_dir, + boards, + extra_args, + jobserver, + env, + log_dir, + max_workers, + continue_on_error, +): + from rich.live import Live + + statuses = [ + {"state": "queued", "elapsed": 0.0, "start": None, "log_path": None} for _ in boards + ] + results = [] + futures = {} + next_index = 0 + stop_submitting = False + start_time = time.time() + + with Live( + _build_status_table(boards, statuses, start_time, stop_submitting), + refresh_per_second=4, + transient=False, + ) as live: + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + while next_index < len(boards) and len(futures) < max_workers: + vendor, board = boards[next_index] + statuses[next_index]["state"] = "running" + statuses[next_index]["start"] = time.time() + future = executor.submit( + build_board, + port_dir, + vendor, + board, + extra_args, + jobserver, + env, + log_dir, + ) + futures[future] = next_index + next_index += 1 + + while futures: + for status in statuses: + if status["state"] == "running": + status["elapsed"] = time.time() - status["start"] + + live.update(_build_status_table(boards, statuses, start_time, stop_submitting)) + + done, _ = concurrent.futures.wait( + futures, + timeout=0.1, + return_when=concurrent.futures.FIRST_COMPLETED, + ) + for future in done: + index = futures.pop(future) + vendor, board = boards[index] + success, elapsed, _output, log_path = future.result() + statuses[index]["elapsed"] = elapsed + statuses[index]["log_path"] = log_path + statuses[index]["state"] = "success" if success else "failed" + results.append((vendor, board, success, elapsed)) + + if not success and not continue_on_error: + stop_submitting = True + + if not stop_submitting and next_index < len(boards): + vendor, board = boards[next_index] + statuses[next_index]["state"] = "running" + statuses[next_index]["start"] = time.time() + future = executor.submit( + build_board, + port_dir, + vendor, + board, + extra_args, + jobserver, + env, + log_dir, + ) + futures[future] = next_index + next_index += 1 + + if stop_submitting: + for index in range(next_index, len(boards)): + if statuses[index]["state"] == "queued": + statuses[index]["state"] = "skipped" + + live.update(_build_status_table(boards, statuses, start_time, stop_submitting)) + + return results, stop_submitting + + +def _run_builds_plain( + port_dir, + boards, + extra_args, + jobserver, + env, + log_dir, + max_workers, + continue_on_error, +): + results = [] + futures = {} + next_index = 0 + stop_submitting = False + + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + while next_index < len(boards) and len(futures) < max_workers: + vendor, board = boards[next_index] + future = executor.submit( + build_board, + port_dir, + vendor, + board, + extra_args, + jobserver, + env, + log_dir, + ) + futures[future] = (vendor, board) + next_index += 1 + + while futures: + done, _ = concurrent.futures.wait( + futures, + return_when=concurrent.futures.FIRST_COMPLETED, + ) + for future in done: + vendor, board = futures.pop(future) + success, elapsed, _output, _log_path = future.result() + board_id = f"{vendor}_{board}" + status = "SUCCESS" if success else "FAILURE" + print(f"{board_id}: {status} ({elapsed:.1f}s)") + results.append((vendor, board, success, elapsed)) + + if not success and not continue_on_error: + stop_submitting = True + + if not stop_submitting and next_index < len(boards): + vendor, board = boards[next_index] + future = executor.submit( + build_board, + port_dir, + vendor, + board, + extra_args, + jobserver, + env, + log_dir, + ) + futures[future] = (vendor, board) + next_index += 1 + + return results, stop_submitting + + +def main(): + parser = argparse.ArgumentParser( + description="Build all CircuitPython boards for the Zephyr port", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Build all boards in parallel with 32 jobserver slots + %(prog)s -j32 + + # Build all boards using make's jobserver (recommended) + make -j32 all +""", + ) + parser.add_argument( + "-j", + "--jobs", + type=int, + default=None, + help="Number of shared jobserver slots across all board builds", + ) + parser.add_argument( + "--continue-on-error", + action="store_true", + help="Continue building remaining boards even if one fails", + ) + parser.add_argument( + "--vendor", + type=str, + default=None, + help="Only build boards from this vendor (e.g. 'native' for sim boards)", + ) + + args = parser.parse_args() + + if args.jobs is not None and args.jobs < 1: + print("ERROR: --jobs must be at least 1") + return 2 + + # Get the port directory + port_dir = pathlib.Path(__file__).parent.resolve().parent + + # Discover all boards + boards = discover_boards(port_dir) + + if args.vendor: + boards = [(v, b) for v, b in boards if v == args.vendor] + + if not boards: + print("ERROR: No boards found!") + return 1 + + # Prepare jobserver and extra make arguments + jobserver, detected_jobs = _jobserver_from_env() + env = os.environ.copy() + + extra_args = [] + jobserver_jobs = detected_jobs + + if not jobserver: + jobserver_jobs = args.jobs if args.jobs else (os.cpu_count() or 1) + jobserver = _create_jobserver(jobserver_jobs) + env["MAKEFLAGS"] = ( + f"-j{jobserver_jobs} --jobserver-auth={jobserver.read_fd},{jobserver.write_fd}" + ) + + max_workers = jobserver_jobs + if max_workers is None: + max_workers = min(len(boards), os.cpu_count() or 1) + max_workers = max(1, min(len(boards), max_workers)) + + # Build all boards + log_dir = port_dir / "build-logs" + log_dir.mkdir(parents=True, exist_ok=True) + + try: + use_tui = sys.stdout.isatty() + if use_tui: + try: + import rich # noqa: F401 + except ImportError: + use_tui = False + + if use_tui: + results, stop_submitting = _run_builds_tui( + port_dir, + boards, + extra_args, + jobserver, + env, + log_dir, + max_workers, + args.continue_on_error, + ) + else: + results, stop_submitting = _run_builds_plain( + port_dir, + boards, + extra_args, + jobserver, + env, + log_dir, + max_workers, + args.continue_on_error, + ) + except KeyboardInterrupt: + print("\n\nBuild interrupted by user.") + return 130 # Standard exit code for SIGINT + finally: + if jobserver: + jobserver.close() + + failed = [r for r in results if not r[2]] + return 0 if len(failed) == 0 else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 61e103e9fe1..0a2a6ed0ae9 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -1,16 +1,16 @@ import asyncio -import colorlog -import sys import logging import os import pathlib -import tomllib -import tomlkit -import yaml import pickle +import sys -import cpbuild import board_tools +import colorlog +import cpbuild +import tomlkit +import tomllib +import yaml logger = logging.getLogger(__name__) @@ -43,6 +43,7 @@ ALWAYS_ON_MODULES = ["sys", "collections"] DEFAULT_MODULES = [ + "__future__", "time", "os", "microcontroller", @@ -51,9 +52,95 @@ "json", "random", "digitalio", - "zephyr_serial", + "rotaryio", + "rainbowio", + "traceback", + "warnings", + "supervisor", + "errno", + "io", + "math", + "msgpack", + "aesio", + "hashlib", + "zlib", + "adafruit_bus_device", + "getpass", + "storage", + "binascii", + "re", + "asyncio", + "select", ] -MPCONFIG_FLAGS = ["ulab", "nvm", "displayio", "warnings", "alarm", "array", "json"] +# Flags that don't match with with a *bindings module. Some used by adafruit_requests +MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math", "binascii"] + +# extmod-based modules that should appear in the autogen list even though they +# don't have shared-bindings/ or bindings/ directories. +EXTMOD_MODULES = ["asyncio", "binascii", "json", "re", "select"] + +# List of other modules (the value) that can be enabled when another one (the key) is. +REVERSE_DEPENDENCIES = { + "audiobusio": ["audiocore"], + "audiocore": [ + "audiodelays", + "audiofilters", + "audiofreeverb", + "audiomixer", + "audiomp3", + "synthio", + ], + "busio": ["fourwire", "i2cdisplaybus", "sdcardio", "sharpdisplay"], + "fourwire": ["displayio", "busdisplay", "epaperdisplay"], + "i2cdisplaybus": ["displayio", "busdisplay", "epaperdisplay"], + # Zephyr display backends need displayio and, by extension, terminalio so + # the REPL console appears on the display by default. + "zephyr_display": ["displayio"], + "displayio": [ + "vectorio", + "bitmapfilter", + "bitmaptools", + "terminalio", + "lvfontio", + "tilepalettemapper", + "fontio", + "gifio", + "jpegio", + ], + "sharpdisplay": ["framebufferio"], + "framebufferio": ["displayio"], +} + +# Other flags to set when a module is enabled +EXTRA_FLAGS = { + "audiobusio": {"AUDIOBUSIO_I2SOUT": 1, "AUDIOBUSIO_PDMIN": 0}, + "busio": {"BUSIO_SPI": 1, "BUSIO_I2C": 1}, + "rotaryio": {"ROTARYIO_SOFTENCODER": 1}, + "synthio": {"SYNTHIO_MAX_CHANNELS": 12}, +} + +# Library sources. Will be globbed from the top level directory +# No QSTR processing or CIRCUITPY specific flags +LIBRARY_SOURCE = { + "audiomp3": ["lib/mp3/src/*.c"], + "zlib": [ + "lib/uzlib/tinflate.c", + "lib/uzlib/tinfzlib.c", + "lib/uzlib/tinfgzip.c", + "lib/uzlib/adler32.c", + "lib/uzlib/crc32.c", + ], + "jpegio": ["lib/tjpgd/src/tjpgd.c"], + "gifio": ["lib/AnimatedGIF/gif.c"], +} + +SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os", "rotaryio"] + +# Mapping from module directory name to the flag name used in CIRCUITPY_ +MODULE_FLAG_NAMES = { + "__future__": "FUTURE", + "_bleio": "BLEIO", +} async def preprocess_and_split_defs(compiler, source_file, build_path, flags): @@ -84,10 +171,17 @@ async def preprocess_and_split_defs(compiler, source_file, build_path, flags): async def collect_defs(mode, build_path): output_file = build_path / f"{mode}defs.collected" splitdir = build_path / "genhdr" / mode + to_collect = list(splitdir.glob(f"**/*.{mode}")) + batch_size = 50 await cpbuild.run_command( - ["cat", "-s", *splitdir.glob(f"**/*.{mode}"), ">", output_file], + ["cat", "-s", *to_collect[:batch_size], ">", output_file], splitdir, ) + for i in range(0, len(to_collect), batch_size): + await cpbuild.run_command( + ["cat", "-s", *to_collect[i : i + batch_size], ">>", output_file], + splitdir, + ) return output_file @@ -162,54 +256,116 @@ async def generate_root_pointer_header(build_path): ) -TINYUSB_SETTINGS = { - "": { - "CFG_TUSB_MCU": "OPT_MCU_MIMXRT10XX", - "CFG_TUD_CDC_RX_BUFSIZE": 640, - "CFG_TUD_CDC_TX_BUFSIZE": 512, - }, - "stm32u575xx": {"CFG_TUSB_MCU": "OPT_MCU_STM32U5"}, - "nrf52840": {"CFG_TUSB_MCU": "OPT_MCU_NRF5X"}, - "nrf5340": {"CFG_TUSB_MCU": "OPT_MCU_NRF5X"}, - # "r7fa8d1bhecbd": {"CFG_TUSB_MCU": "OPT_MCU_RAXXX", "USB_HIGHSPEED": "1", "USBHS_USB_INT_RESUME_IRQn": "54", "USBFS_INT_IRQn": "54", "CIRCUITPY_USB_DEVICE_INSTANCE": "1"}, - # ifeq ($(CHIP_FAMILY),$(filter $(CHIP_FAMILY),MIMXRT1011 MIMXRT1015)) - # CFLAGS += -DCFG_TUD_MIDI_RX_BUFSIZE=512 -DCFG_TUD_MIDI_TX_BUFSIZE=64 -DCFG_TUD_MSC_BUFSIZE=512 - # else - # CFLAGS += -DCFG_TUD_MIDI_RX_BUFSIZE=512 -DCFG_TUD_MIDI_TX_BUFSIZE=512 -DCFG_TUD_MSC_BUFSIZE=1024 - # endif -} +async def generate_display_resources(output_path, translation, font, extra_characters): + await cpbuild.run_command( + [ + "python", + srcdir / "tools" / "gen_display_resources.py", + "--font", + srcdir / font, + "--sample_file", + srcdir / "locale" / f"{translation}.po", + "--extra_characters", + repr(extra_characters), + "--output_c_file", + output_path, + ], + srcdir, + check_hash=[output_path], + ) -TINYUSB_SOURCE = { - "stm32u575xx": [ - "src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c", - "src/portable/synopsys/dwc2/dcd_dwc2.c", - "src/portable/synopsys/dwc2/hcd_dwc2.c", - "src/portable/synopsys/dwc2/dwc2_common.c", - ], - "nrf52840": [ - "src/portable/nordic/nrf5x/dcd_nrf5x.c", - ], - "nrf5340": [ - "src/portable/nordic/nrf5x/dcd_nrf5x.c", - ], - # "r7fa8d1bhecbd": [ - # "src/portable/renesas/rusb2/dcd_rusb2.c", - # "src/portable/renesas/rusb2/hcd_rusb2.c", - # "src/portable/renesas/rusb2/rusb2_common.c", - # ], -} +async def generate_web_workflow_static(output_path, static_files): + await cpbuild.run_command( + [ + "python", + srcdir / "tools" / "gen_web_workflow_static.py", + "--output_c_file", + output_path, + *static_files, + ], + srcdir, + check_hash=[output_path], + ) + + +def determine_enabled_modules(board_info, portdir, srcdir): + """Determine which CircuitPython modules should be enabled based on board capabilities. + + Args: + board_info: Dictionary containing board hardware capabilities + portdir: Path to the port directory (ports/zephyr-cp) + srcdir: Path to the CircuitPython source root + + Returns: + tuple: (enabled_modules set, module_reasons dict) + """ + enabled_modules = set(DEFAULT_MODULES) + module_reasons = {} + + # The board module is always built: shared-bindings/board/__init__.c and the + # generated pin/board.c are compiled unconditionally in build_circuitpython(). + enabled_modules.add("board") + module_reasons["board"] = "Always enabled" + + if board_info["wifi"]: + enabled_modules.add("wifi") + module_reasons["wifi"] = "Zephyr board has wifi" + + if board_info["flash_count"] > 0: + enabled_modules.add("storage") + module_reasons["storage"] = "Zephyr board has flash" + + network_enabled = board_info.get("wifi", False) or board_info.get("hostnetwork", False) + + if network_enabled: + enabled_modules.add("ipaddress") + module_reasons["ipaddress"] = "Zephyr networking enabled" + enabled_modules.add("socketpool") + module_reasons["socketpool"] = "Zephyr networking enabled" + enabled_modules.add("hashlib") + module_reasons["hashlib"] = "Zephyr networking enabled" + + if board_info.get("wifi", False) or board_info.get("ethernet", False): + enabled_modules.add("ssl") + module_reasons["ssl"] = "Zephyr networking enabled" + + for port_module in (portdir / "bindings").iterdir(): + if not board_info.get(port_module.name, False): + continue + enabled_modules.add(port_module.name) + module_reasons[port_module.name] = f"Zephyr board has {port_module.name}" + + for shared_module in (srcdir / "shared-bindings").iterdir(): + if not board_info.get(shared_module.name, False) or not shared_module.glob("*.c"): + continue + enabled_modules.add(shared_module.name) + module_reasons[shared_module.name] = f"Zephyr board has {shared_module.name}" -async def build_circuitpython(): + more_modules = [] + more_modules.extend(REVERSE_DEPENDENCIES.get(shared_module.name, [])) + while more_modules: + reverse_dependency = more_modules.pop(0) + if reverse_dependency in enabled_modules: + continue + logger.debug(f"Enabling {reverse_dependency} because {shared_module.name} is enabled") + enabled_modules.add(reverse_dependency) + more_modules.extend(REVERSE_DEPENDENCIES.get(reverse_dependency, [])) + module_reasons[reverse_dependency] = f"Zephyr board has {shared_module.name}" + + return enabled_modules, module_reasons + + +async def build_circuitpython(): # noqa: C901 circuitpython_flags = ["-DCIRCUITPY"] port_flags = [] enable_mpy_native = False - full_build = False + full_build = True usb_host = False - tusb_mem_align = 4 + zephyr_board = cmake_args["BOARD"] board = cmake_args["BOARD_ALIAS"] if not board: - board = cmake_args["BOARD"] + board = zephyr_board translation = cmake_args["TRANSLATION"] if not translation: translation = "en_US" @@ -218,26 +374,36 @@ async def build_circuitpython(): lto = cmake_args.get("LTO", "n") == "y" circuitpython_flags.append(f"-DCIRCUITPY_ENABLE_MPY_NATIVE={1 if enable_mpy_native else 0}") circuitpython_flags.append(f"-DCIRCUITPY_FULL_BUILD={1 if full_build else 0}") + circuitpython_flags.append("-DCIRCUITPY_OPT_LOAD_ATTR_FAST_PATH=1") + circuitpython_flags.append(f"-DCIRCUITPY_OPT_MAP_LOOKUP_CACHE={1 if full_build else 0}") + circuitpython_flags.append(f"-DCIRCUITPY_SETTINGS_TOML={1 if full_build else 0}") + circuitpython_flags.append(f"-DMICROPY_PY_ASYNC_AWAIT={1 if full_build else 0}") + circuitpython_flags.append(f"-DMICROPY_PY_ASYNCIO={1 if full_build else 0}") + circuitpython_flags.append(f"-DMICROPY_PY_SELECT={1 if full_build else 0}") + circuitpython_flags.append(f"-DMICROPY_PY_SELECT_SELECT={1 if full_build else 0}") + circuitpython_flags.append("-DCIRCUITPY_STATUS_BAR=1") circuitpython_flags.append(f"-DCIRCUITPY_USB_HOST={1 if usb_host else 0}") - circuitpython_flags.append(f'-DCIRCUITPY_BOARD_ID=\\"{board}\\"') - circuitpython_flags.append(f"-DCIRCUITPY_TUSB_MEM_ALIGN={tusb_mem_align}") + circuitpython_flags.append(f"-DCIRCUITPY_BOARD_ID='\"{board}\"'") circuitpython_flags.append(f"-DCIRCUITPY_TRANSLATE_OBJECT={1 if lto else 0}") circuitpython_flags.append("-DINTERNAL_FLASH_FILESYSTEM") circuitpython_flags.append("-DLONGINT_IMPL_MPZ") circuitpython_flags.append("-DCIRCUITPY_SSL_MBEDTLS") - circuitpython_flags.append('-DFFCONF_H=\\"lib/oofatfs/ffconf.h\\"') + circuitpython_flags.append("-DFFCONF_H='\"lib/oofatfs/ffconf.h\"'") + circuitpython_flags.append( + "-D_DEFAULT_SOURCE" + ) # To get more from picolibc to match newlib such as M_PI circuitpython_flags.extend(("-I", srcdir)) - circuitpython_flags.extend(("-I", srcdir / "lib/tinyusb/src")) - circuitpython_flags.extend(("-I", srcdir / "supervisor/shared/usb")) circuitpython_flags.extend(("-I", builddir)) circuitpython_flags.extend(("-I", portdir)) - # circuitpython_flags.extend(("-I", srcdir / "ports" / port / "peripherals")) - - # circuitpython_flags.extend(("-I", build_path / board_id)) genhdr = builddir / "genhdr" genhdr.mkdir(exist_ok=True, parents=True) version_header = genhdr / "mpversion.h" + mpconfigboard_fn = board_tools.find_mpconfigboard(portdir, board) + mpconfigboard = {"USB_VID": 0x1209, "USB_PID": 0x000C, "USB_INTERFACE_NAME": "CircuitPython"} + if mpconfigboard_fn is not None and mpconfigboard_fn.exists(): + with mpconfigboard_fn.open("rb") as f: + mpconfigboard.update(tomllib.load(f)) async with asyncio.TaskGroup() as tg: tg.create_task( cpbuild.run_command( @@ -254,13 +420,10 @@ async def build_circuitpython(): ) ) - board_autogen_task = tg.create_task(zephyr_dts_to_cp_board(builddir, zephyrbuilddir)) + board_autogen_task = tg.create_task( + zephyr_dts_to_cp_board(zephyr_board, portdir, builddir, zephyrbuilddir, mpconfigboard) + ) board_info = board_autogen_task.result() - mpconfigboard_fn = board_tools.find_mpconfigboard(portdir, board) - mpconfigboard = { - "USB_VID": 0x1209, - "USB_PID": 0x000C, - } if mpconfigboard_fn is None: mpconfigboard_fn = ( portdir / "boards" / board_info["vendor_id"] / board / "circuitpython.toml" @@ -268,31 +431,32 @@ async def build_circuitpython(): logging.warning( f"Could not find board config at: boards/{board_info['vendor_id']}/{board}" ) - elif mpconfigboard_fn.exists(): - with mpconfigboard_fn.open("rb") as f: - mpconfigboard = tomllib.load(f) autogen_board_info_fn = mpconfigboard_fn.parent / "autogen_board_info.toml" - enabled_modules = set(DEFAULT_MODULES) - module_reasons = {} - if board_info["wifi"]: - enabled_modules.add("wifi") - module_reasons["wifi"] = "Zephyr board has wifi" + creator_id = mpconfigboard.get("CIRCUITPY_CREATOR_ID", mpconfigboard.get("USB_VID", 0x1209)) + creation_id = mpconfigboard.get("CIRCUITPY_CREATION_ID", mpconfigboard.get("USB_PID", 0x000C)) + circuitpython_flags.append(f"-DCIRCUITPY_CREATOR_ID=0x{creator_id:08x}") + circuitpython_flags.append(f"-DCIRCUITPY_CREATION_ID=0x{creation_id:08x}") - if board_info["flash_count"] > 0: - enabled_modules.add("storage") - module_reasons["storage"] = "Zephyr board has flash" + vendor = mpconfigboard.get("VENDOR", board_info["vendor"]) + name = mpconfigboard.get("NAME", board_info["name"]) - if "wifi" in enabled_modules: - enabled_modules.add("socketpool") - enabled_modules.add("ssl") - module_reasons["socketpool"] = "Zephyr networking enabled" - module_reasons["ssl"] = "Zephyr networking enabled" + enabled_modules, module_reasons = determine_enabled_modules(board_info, portdir, srcdir) + for m in mpconfigboard.get("DISABLED_MODULES", []): + enabled_modules.discard(m) + + web_workflow_enabled = board_info.get("wifi", False) or board_info.get("hostnetwork", False) circuitpython_flags.extend(board_info["cflags"]) + circuitpython_flags.append(f"-DCIRCUITPY_WEB_WORKFLOW={1 if web_workflow_enabled else 0}") supervisor_source = [ "main.c", + "extmod/modjson.c", + "extmod/modbinascii.c", + "extmod/modre.c", + "extmod/modasyncio.c", + "extmod/modselect.c", "extmod/vfs_fat.c", "lib/tlsf/tlsf.c", portdir / "background.c", @@ -301,7 +465,10 @@ async def build_circuitpython(): portdir / "common-hal/microcontroller/Processor.c", portdir / "common-hal/os/__init__.c", "shared/readline/readline.c", + "shared/runtime/buffer_helper.c", "shared/runtime/context_manager_helpers.c", + "shared/runtime/gchelper_generic.c", + "shared/runtime/gchelper_native.c", "shared/runtime/pyexec.c", "shared/runtime/interrupt_char.c", "shared/runtime/stdout_helpers.c", @@ -319,139 +486,69 @@ async def build_circuitpython(): supervisor_source = [pathlib.Path(p) for p in supervisor_source] supervisor_source.extend(board_info["source_files"]) supervisor_source.extend(top.glob("supervisor/shared/*.c")) + ble_workflow_enabled = "_bleio" in enabled_modules + if ble_workflow_enabled: + supervisor_source.append(top / "supervisor/shared/bluetooth/bluetooth.c") + # BLE workflow = file transfer + serial services, matching other ports. + supervisor_source.append(top / "supervisor/shared/bluetooth/file_transfer.c") + supervisor_source.append(top / "supervisor/shared/bluetooth/serial.c") + circuitpython_flags.append(f"-DCIRCUITPY_BLE_FILE_SERVICE={1 if ble_workflow_enabled else 0}") + circuitpython_flags.append( + f"-DCIRCUITPY_BLE_SERIAL_SERVICE={1 if ble_workflow_enabled else 0}" + ) supervisor_source.append(top / "supervisor/shared/translate/translate.c") - # if web_workflow: - # supervisor_source.extend(top.glob("supervisor/shared/web_workflow/*.c")) + if web_workflow_enabled: + supervisor_source.extend(top.glob("supervisor/shared/web_workflow/*.c")) - usb_num_endpoint_pairs = board_info.get("usb_num_endpoint_pairs", 0) - soc = board_info["soc"] - usb_ok = usb_num_endpoint_pairs > 0 and soc in TINYUSB_SETTINGS - circuitpython_flags.append(f"-DCIRCUITPY_TINYUSB={1 if usb_ok else 0}") + usb_ok = board_info.get("usb_device", False) circuitpython_flags.append(f"-DCIRCUITPY_USB_DEVICE={1 if usb_ok else 0}") - tinyusb_files = [] if usb_ok: enabled_modules.add("usb_cdc") - for setting in TINYUSB_SETTINGS[soc]: - circuitpython_flags.append(f"-D{setting}={TINYUSB_SETTINGS[soc][setting]}") - tinyusb_files.extend((top / "lib" / "tinyusb" / path for path in TINYUSB_SOURCE[soc])) + enabled_modules.add("usb_hid") + + usb_num_endpoint_pairs = board_info.get("usb_num_endpoint_pairs", 4) + circuitpython_flags.append(f"-DUSB_NUM_ENDPOINT_PAIRS={usb_num_endpoint_pairs}") + circuitpython_flags.append("-DCIRCUITPY_USB_HID_ENABLED_DEFAULT=1") + for macro in ("USB_PID", "USB_VID"): + print(f"Setting {macro} to {mpconfigboard.get(macro)}") circuitpython_flags.append(f"-D{macro}=0x{mpconfigboard.get(macro):04x}") + circuitpython_flags.append( + f"-DUSB_INTERFACE_NAME='\"{mpconfigboard['USB_INTERFACE_NAME']}\"'" + ) for macro, limit, value in ( - ("USB_PRODUCT", 16, board_info["name"]), - ("USB_MANUFACTURER", 8, board_info["vendor"]), + ("USB_PRODUCT", 16, name), + ("USB_MANUFACTURER", 8, vendor), ): circuitpython_flags.append(f"-D{macro}='\"{value}\"'") circuitpython_flags.append(f"-D{macro}_{limit}='\"{value[:limit]}\"'") - usb_interface_name = "CircuitPython" + circuitpython_flags.append("-DCIRCUITPY_USB_CDC_CONSOLE_ENABLED_DEFAULT=1") + circuitpython_flags.append("-DCIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT=0") - circuitpython_flags.append("-DCFG_TUSB_OS=OPT_OS_ZEPHYR") - circuitpython_flags.append(f"-DUSB_INTERFACE_NAME='\"{usb_interface_name}\"'") - circuitpython_flags.append(f"-DUSB_NUM_ENDPOINT_PAIRS={usb_num_endpoint_pairs}") - for direction in ("IN", "OUT"): - circuitpython_flags.append(f"-DUSB_NUM_{direction}_ENDPOINTS={usb_num_endpoint_pairs}") - # USB is special because it doesn't have a matching module. - msc_enabled = board_info["flash_count"] > 0 - if msc_enabled: - circuitpython_flags.append("-DCFG_TUD_MSC_BUFSIZE=1024") - circuitpython_flags.append("-DCIRCUITPY_USB_MSC_ENABLED_DEFAULT=1") - tinyusb_files.append(top / "lib/tinyusb/src/class/msc/msc_device.c") - supervisor_source.append(top / "supervisor/shared/usb/usb_msc_flash.c") - circuitpython_flags.append(f"-DCIRCUITPY_USB_MSC={1 if msc_enabled else 0}") - if "usb_cdc" in enabled_modules: - tinyusb_files.extend(top.glob("lib/tinyusb/*.c")) - tinyusb_files.append(top / "lib/tinyusb/src/class/cdc/cdc_device.c") - circuitpython_flags.append("-DCFG_TUD_CDC_RX_BUFSIZE=640") - circuitpython_flags.append("-DCFG_TUD_CDC_TX_BUFSIZE=512") - circuitpython_flags.append("-DCFG_TUD_CDC=2") - circuitpython_flags.append("-DCIRCUITPY_USB_CDC_CONSOLE_ENABLED_DEFAULT=1") - circuitpython_flags.append("-DCIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT=0") - - if "usb_hid_enabled_default" not in mpconfigboard: - mpconfigboard["usb_hid_enabled_default"] = usb_num_endpoint_pairs >= 5 - if "usb_midi_enabled_default" not in mpconfigboard: - mpconfigboard["usb_midi_enabled_default"] = usb_num_endpoint_pairs >= 8 - - tinyusb_files.extend( - (top / "lib/tinyusb/src/common/tusb_fifo.c", top / "lib/tinyusb/src/tusb.c") - ) supervisor_source.extend( - (portdir / "supervisor/usb.c", top / "supervisor/shared/usb/usb.c") + (portdir / "supervisor/usb.c", srcdir / "supervisor/shared/usb.c") ) - tinyusb_files.extend( - ( - top / "lib/tinyusb/src/device/usbd.c", - top / "lib/tinyusb/src/device/usbd_control.c", - ) - ) - supervisor_source.extend( - (top / "supervisor/shared/usb/usb_desc.c", top / "supervisor/shared/usb/usb_device.c") - ) - elif usb_num_endpoint_pairs > 0: - module_reasons["usb_cdc"] = f"No TinyUSB settings for {soc}" - - circuitpython_flags.append(f"-DCIRCUITPY_PORT_SERIAL={0 if usb_ok else 1}") - # ifeq ($(CIRCUITPY_USB_HID), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/class/hid/hid_device.c \ - # shared-bindings/usb_hid/__init__.c \ - # shared-bindings/usb_hid/Device.c \ - # shared-module/usb_hid/__init__.c \ - # shared-module/usb_hid/Device.c \ - - # endif - - # ifeq ($(CIRCUITPY_USB_MIDI), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/class/midi/midi_device.c \ - # shared-bindings/usb_midi/__init__.c \ - # shared-bindings/usb_midi/PortIn.c \ - # shared-bindings/usb_midi/PortOut.c \ - # shared-module/usb_midi/__init__.c \ - # shared-module/usb_midi/PortIn.c \ - # shared-module/usb_midi/PortOut.c \ - - # endif - - # ifeq ($(CIRCUITPY_USB_VIDEO), 1) - # SRC_SUPERVISOR += \ - # shared-bindings/usb_video/__init__.c \ - # shared-module/usb_video/__init__.c \ - # shared-bindings/usb_video/USBFramebuffer.c \ - # shared-module/usb_video/USBFramebuffer.c \ - # lib/tinyusb/src/class/video/video_device.c \ - - # CFLAGS += -DCFG_TUD_VIDEO=1 -DCFG_TUD_VIDEO_STREAMING=1 -DCFG_TUD_VIDEO_STREAMING_EP_BUFSIZE=256 -DCFG_TUD_VIDEO_STREAMING_BULK=1 - # endif - - # ifeq ($(CIRCUITPY_USB_VENDOR), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/class/vendor/vendor_device.c \ - - # endif - - # ifeq ($(CIRCUITPY_TINYUSB_HOST), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/host/hub.c \ - # lib/tinyusb/src/host/usbh.c \ - - # endif - - # ifeq ($(CIRCUITPY_USB_KEYBOARD_WORKFLOW), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/class/hid/hid_host.c \ - # supervisor/shared/usb/host_keyboard.c \ - - # endif - - if "ssl" in enabled_modules: + creator_id = mpconfigboard.get("CIRCUITPY_CREATOR_ID", mpconfigboard.get("USB_VID")) + creation_id = mpconfigboard.get("CIRCUITPY_CREATION_ID", mpconfigboard.get("USB_PID")) + if creator_id is not None: + circuitpython_flags.append(f"-DCIRCUITPY_CREATOR_ID=0x{creator_id:08x}") + if creation_id is not None: + circuitpython_flags.append(f"-DCIRCUITPY_CREATION_ID=0x{creation_id:08x}") + + # Always use port serial. It'll switch between USB and UART automatically. + circuitpython_flags.append("-DCIRCUITPY_PORT_SERIAL=1") + + if "hashlib" in enabled_modules: + circuitpython_flags.append("-DCIRCUITPY_HASHLIB_MBEDTLS=1") + if "ssl" not in enabled_modules: + circuitpython_flags.append("-DCIRCUITPY_HASHLIB_MBEDTLS_ONLY=1") + + if "ssl" in enabled_modules or "hashlib" in enabled_modules: # TODO: Figure out how to get these paths from zephyr - circuitpython_flags.append('-DMBEDTLS_CONFIG_FILE=\\"config-tls-generic.h\\"') - circuitpython_flags.extend( - ("-isystem", portdir / "modules" / "crypto" / "tinycrypt" / "lib" / "include") - ) + circuitpython_flags.append("-DMBEDTLS_CONFIG_FILE='\"config-mbedtls.h\"'") circuitpython_flags.extend( ("-isystem", portdir / "modules" / "crypto" / "mbedtls" / "include") ) @@ -459,27 +556,42 @@ async def build_circuitpython(): ("-isystem", portdir / "modules" / "crypto" / "mbedtls" / "configs") ) circuitpython_flags.extend( - ("-isystem", portdir / "modules" / "crypto" / "mbedtls" / "include") + ("-isystem", portdir / "modules" / "crypto" / "tf-psa-crypto" / "include") + ) + circuitpython_flags.extend( + ( + "-isystem", + portdir + / "modules" + / "crypto" + / "tf-psa-crypto" + / "drivers" + / "builtin" + / "include", + ) ) circuitpython_flags.extend(("-isystem", zephyrdir / "modules" / "mbedtls" / "configs")) - supervisor_source.append(top / "lib" / "mbedtls_config" / "crt_bundle.c") + if "ssl" in enabled_modules: + supervisor_source.append(top / "lib" / "mbedtls_config" / "crt_bundle.c") # Make sure all modules have a setting by filling in defaults. hal_source = [] + library_sources = [] autogen_board_info = tomlkit.document() autogen_board_info.add( tomlkit.comment( "This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info." ) ) - autogen_board_info.add("name", board_info["vendor"] + " " + board_info["name"]) + autogen_board_info.add("name", vendor + " " + name) autogen_modules = tomlkit.table() autogen_board_info.add("modules", autogen_modules) for module in sorted( list(top.glob("shared-bindings/*")) + list(portdir.glob("bindings/*")), key=lambda x: x.name, ): - if not module.is_dir(): + # Skip files and directories without C source files (like artifacts from a docs build) + if not module.is_dir() or len(list(module.glob("*.c"))) == 0: continue enabled = module.name in enabled_modules # print(f"Module {module.name} enabled: {enabled}") @@ -487,32 +599,91 @@ async def build_circuitpython(): if module.name in module_reasons: v.comment(module_reasons[module.name]) autogen_modules.add(module.name, v) - circuitpython_flags.append(f"-DCIRCUITPY_{module.name.upper()}={1 if enabled else 0}") + flag_name = MODULE_FLAG_NAMES.get(module.name, module.name.upper()) + circuitpython_flags.append(f"-DCIRCUITPY_{flag_name}={1 if enabled else 0}") + + if enabled: + if module.name in EXTRA_FLAGS: + for flag, value in EXTRA_FLAGS[module.name].items(): + circuitpython_flags.append(f"-DCIRCUITPY_{flag}={value}") if enabled: hal_source.extend(portdir.glob(f"bindings/{module.name}/*.c")) + len_before = len(hal_source) hal_source.extend(top.glob(f"ports/zephyr-cp/common-hal/{module.name}/*.c")) - hal_source.extend(top.glob(f"shared-bindings/{module.name}/*.c")) - hal_source.extend(top.glob(f"shared-module/{module.name}/*.c")) + # Only include shared-module/*.c if no common-hal/*.c files were found + if len(hal_source) == len_before or module.name in SHARED_MODULE_AND_COMMON_HAL: + hal_source.extend(top.glob(f"shared-module/{module.name}/**/*.c")) + # The USB HID report descriptors are shared with the TinyUSB ports and + # have no common-hal override, so always compile them. + if module.name == "usb_hid": + hal_source.append(top / "shared-module/usb_hid/report_descriptors.c") + hal_source.extend(top.glob(f"shared-bindings/{module.name}/**/*.c")) + if module.name in LIBRARY_SOURCE: + for library_source in LIBRARY_SOURCE[module.name]: + library_sources.extend(top.glob(library_source)) + + autogen_modules.add(tomlkit.comment("extmod modules shared with MicroPython")) + for extmod_module in EXTMOD_MODULES: + enabled = extmod_module in enabled_modules + v = tomlkit.item(enabled) + if extmod_module in module_reasons: + v.comment(module_reasons[extmod_module]) + autogen_modules.add(extmod_module, v) + flag_name = MODULE_FLAG_NAMES.get(extmod_module, extmod_module.upper()) + circuitpython_flags.append(f"-DCIRCUITPY_{flag_name}={1 if enabled else 0}") if os.environ.get("CI", "false") == "true": - # Fail the build if it isn't up to date. + # Warn if it isn't up to date. if ( not autogen_board_info_fn.exists() or autogen_board_info_fn.read_text() != tomlkit.dumps(autogen_board_info) ): - logger.error("autogen_board_info.toml is out of date.") - raise RuntimeError( + logger.warning( f"autogen_board_info.toml is missing or out of date. Please run `make BOARD={board}` locally and commit {autogen_board_info_fn}." ) - elif autogen_board_info_fn.parent.exists(): + # Also as an annotation, so it shows on the run and next to the file in the + # pull request rather than in one board log out of 29. The board builds once + # per language, so only the first build of it says anything. + reported = builddir / "autogen_board_info.reported" + if not reported.exists(): + reported.touch() + print( + f"::warning file={autogen_board_info_fn.relative_to(srcdir)}::" + f"out of date, run `make BOARD={board}` and commit it", + flush=True, + ) + + if autogen_board_info_fn.parent.exists(): autogen_board_info_fn.write_text(tomlkit.dumps(autogen_board_info)) for mpflag in MPCONFIG_FLAGS: enabled = mpflag in DEFAULT_MODULES circuitpython_flags.append(f"-DCIRCUITPY_{mpflag.upper()}={1 if enabled else 0}") + # ulab is on by default and boards that cannot spare the flash set + # CIRCUITPY_ULAB = false in their circuitpython.toml. Flags mirror py/py.mk. + ulab_enabled = mpconfigboard.get("CIRCUITPY_ULAB", True) + circuitpython_flags.append(f"-DCIRCUITPY_ULAB={1 if ulab_enabled else 0}") + if ulab_enabled: + circuitpython_flags.extend( + ( + "-DMODULE_ULAB_ENABLED=1", + "-DULAB_HAS_USER_MODULE=0", + "-iquote", + str(top / "extmod" / "ulab" / "code"), + ) + ) + # radio.ping() builds on Zephyr's ICMP API. On by default; boards that cannot + # spare the flash set CIRCUITPY_WIFI_PING = false in their circuitpython.toml + # and radio.ping() then reports no reply, as it does for an unreachable host. + circuitpython_flags.append( + f"-DCIRCUITPY_WIFI_PING={1 if mpconfigboard.get('CIRCUITPY_WIFI_PING', True) else 0}" + ) + source_files = supervisor_source + hal_source + ["extmod/vfs.c"] + if ulab_enabled: + source_files.extend(sorted((top / "extmod" / "ulab" / "code").rglob("*.c"))) assembly_files = [] for file in top.glob("py/*.c"): source_files.append(file) @@ -558,6 +729,23 @@ async def build_circuitpython(): tg.create_task(generate_module_header(board_build)) tg.create_task(generate_root_pointer_header(board_build)) + if "terminalio" in enabled_modules: + output_path = board_build / f"autogen_display_resources-{translation}.c" + font_path = srcdir / mpconfigboard.get( + "CIRCUITPY_DISPLAY_FONT", "tools/fonts/ter-u12n.bdf" + ) + extra_characters = mpconfigboard.get("CIRCUITPY_FONT_EXTRA_CHARACTERS", "") + tg.create_task( + generate_display_resources(output_path, translation, font_path, extra_characters) + ) + source_files.append(output_path) + + if web_workflow_enabled: + output_path = board_build / "autogen_web_workflow_static.c" + static_files = sorted((srcdir / "supervisor/shared/web_workflow/static").glob("*")) + tg.create_task(generate_web_workflow_static(output_path, static_files)) + source_files.append(output_path) + # This file is generated by the QSTR/translation process. source_files.append(builddir / f"translations-{translation}.c") # These files don't include unique QSTRs. They just need to be compiled. @@ -575,14 +763,16 @@ async def build_circuitpython(): source_files.append(portdir / "common-hal/zephyr_kernel/__init__.c") # source_files.append(srcdir / "ports" / port / "peripherals" / "nrf" / "nrf52840" / "pins.c") - assembly_files.append(srcdir / "supervisor/shared/cpu_regs.S") - source_files.extend(assembly_files) - source_files.extend(tinyusb_files) - objects = [] async with asyncio.TaskGroup() as tg: + for source_file in library_sources: + source_file = top / source_file + build_file = source_file.with_suffix(".o") + object_file = builddir / (build_file.relative_to(top)) + objects.append(object_file) + tg.create_task(compiler.compile(source_file, object_file)) for source_file in source_files: source_file = top / source_file build_file = source_file.with_suffix(".o") diff --git a/ports/zephyr-cp/cptools/check_partitions.py b/ports/zephyr-cp/cptools/check_partitions.py new file mode 100644 index 00000000000..05fb982f4a1 --- /dev/null +++ b/ports/zephyr-cp/cptools/check_partitions.py @@ -0,0 +1,430 @@ +#!/usr/bin/env python3 +"""Check the flash partition layout a board's devicetree actually resolved to. + +Board overlays in ``boards/`` routinely rebuild the ``partitions`` node so the +board gets a CIRCUITPY filesystem. Rebuilding it is easy to get subtly wrong in +a way nothing reports: drop the ``ranges;`` the board DTS declared and +devicetree stops translating partition addresses into the SoC's address space, +so every partition resolves to a bare offset instead. The build still succeeds. +What changes is anything keyed off the address -- on RP2040, +``RP2_REQUIRES_SECOND_STAGE_BOOT`` matches the code partition against +0x10000100, so a partition left at 0x100 silently turns it off and the UF2 is +built for the wrong address with no second stage bootloader linked in. + +A board that CircuitPython also builds from another port (``counterpart`` in its +``circuitpython.toml``) is additionally compared with that build: nvm and the +CIRCUITPY drive must sit exactly where ``ports/`` puts them, or switching +firmware between the two builds loses the user's data. The expected placement +is derived from the counterpart's configuration files the same way its +``mpconfigport.h`` derives it. + +This reads the ``edt.pickle`` a build already produced, so it costs no build +time -- point it at build directories after building, or run it with no +arguments to check every build directory in the port. + + python cptools/check_partitions.py # every build-* dir + python cptools/check_partitions.py build-raspberrypi_rpi_pico_zephyr + python cptools/check_partitions.py --board raspberrypi_rpi_pico_zephyr build-x + +Exits non-zero when a layout has problems. +""" + +import argparse +import pathlib +import pickle +import re +import sys +import tomllib + +import board_tools + +PORT_DIR = pathlib.Path(__file__).resolve().parent.parent +TOP = PORT_DIR.parent.parent +EDT_MODULE = PORT_DIR / "zephyr" / "scripts" / "dts" / "python-devicetree" / "src" + +# Parity with the non-Zephyr build. A board that CircuitPython also builds from another +# port (ports/raspberrypi, ports/nordic) names it in circuitpython.toml: +# +# counterpart = "raspberrypi/raspberry_pi_pico_w" +# +# The nvm and CIRCUITPY drive of the Zephyr build then have to sit exactly where that +# build puts them, so that switching firmware between the two never loses user data. +# The expected placement is derived from the counterpart's own configuration files, the +# same way its mpconfigport.h derives it, rather than copied into the overlay by hand. +DEFINE_RE = re.compile(r"^\s*#\s*define\s+([A-Za-z_]\w*)\s+(.+?)\s*(?://.*|/\*.*)?$", re.MULTILINE) +CFLAG_DEFINE_RE = re.compile(r"-D([A-Za-z_]\w*)=(?:'([^']*)'|\"([^\"]*)\"|(\S+))") +MK_ASSIGN_RE = re.compile(r"^\s*([A-Za-z_]\w*)\s*[?:+]?=\s*(.*?)\s*$", re.MULTILINE) +IDENTIFIER_RE = re.compile(r"(?]+$") + + +def load_edt(build_dir): + """Load the pickled devicetree a build produced, or None if there is none.""" + edt_path = build_dir / "zephyr-cp" / "zephyr" / "edt.pickle" + if not edt_path.is_file(): + edt_path = build_dir / "zephyr" / "edt.pickle" + if not edt_path.is_file(): + return None + sys.path.insert(0, str(EDT_MODULE)) + with open(edt_path, "rb") as f: + return pickle.load(f) + + +def partition_device(node): + """Walk up to the NVM device owning a partition. + + The device is the first ancestor carrying ``reg``; the ``partitions`` + grouping node in between has none. + """ + parent = getattr(node, "parent", None) + while parent is not None: + if parent.props.get("reg") is not None: + return parent + parent = getattr(parent, "parent", None) + return None + + +def device_size(node): + """Total size of an NVM device. + + External SPI/QSPI NOR carries its capacity in the ``size`` property (in + bits) and uses ``reg`` for the chip select, so reading ``reg`` alone gives + 0 for exactly the devices CIRCUITPY usually lives on. + """ + size = node.props.get("size") + if size: + return size.val // 8 + reg = node.props.get("reg") + if reg and len(reg.val) >= 2: + return reg.val[1] + return 0 + + +def is_partition_child(node): + """True for any node under a ``partitions`` grouping node. + + Membership is positional rather than by ``compatible``: an overlay may add + a partition carrying neither ``zephyr,mapped-partition`` nor a + ``fixed-partitions`` parent, and it still occupies the space and still is + what the layout means to describe. + """ + parent = getattr(node, "parent", None) + return parent is not None and getattr(parent, "name", "") == "partitions" + + +def iter_partitions(edt): + """Yield ``(node, device, offset, size, mapped)`` for every partition.""" + for node in edt.nodes: + mapped = "zephyr,mapped-partition" in getattr(node, "compats", []) + if not mapped and not is_partition_child(node): + continue + reg = node.props.get("reg") + if not reg or len(reg.val) < 2: + continue + dev = partition_device(node) + if dev is None: + continue + if mapped and (not getattr(node, "regs", None) or not getattr(dev, "regs", None)): + continue + yield node, dev, reg.val[0], reg.val[1], mapped + + +def check_layout(edt): + """Return a list of problems with the resolved layout. + + Mapped partitions are checked for address translation; every partition is + checked for overlap and for running past the end of its device. Erase-page + alignment is not checked: RP2040 deliberately puts its code partition at + 0x100, directly behind the 256-byte second stage bootloader. + """ + problems = [] + by_device = {} + for node, dev, offset, size, mapped in iter_partitions(edt): + label = node.labels[0] if node.labels else node.name + dev_label = dev.labels[0] if dev.labels else dev.name + total = device_size(dev) + if mapped: + # Test the resolved address against the device's own window rather + # than against base + reg. Both forms are in use: a partition reg + # is usually an offset, but some overlays write the absolute + # address and leave the partitions node without ranges, which + # resolves to the same correct address. What is never right is a + # partition resolving outside the device it lives in -- which is + # exactly what a rebuilt partitions node missing ranges; produces, + # since the offset is then left untranslated. + base = dev.regs[0].addr + actual = node.regs[0].addr + if total and not (base <= actual < base + total): + problems.append( + f"{label}: resolves to 0x{actual:x}, outside {dev_label} " + f"(0x{base:x}-0x{base + total:x}) -- address translation is " + f"broken; does the partitions node declare ranges;?" + ) + # Geometry below is compared in offsets from the device base, so a + # partition declared either way lands in the same space. When the + # translation is broken the difference is meaningless (and often + # negative), so keep the declared offset rather than running the + # geometry checks on nonsense. + translated = actual - base + if 0 <= translated and (not total or translated < total): + offset = translated + by_device.setdefault(dev_label, (dev, total, []))[2].append((label, offset, size)) + + for dev_label, (dev, total, parts) in sorted(by_device.items()): + ordered = sorted(parts, key=lambda p: p[1]) + for label, offset, size in ordered: + if total and offset + size > total: + problems.append( + f"{label}: ends at 0x{offset + size:x}, past the end of " + f"{dev_label} (0x{total:x})" + ) + # A running high-water mark, not neighbouring pairs: a partition + # spanning several later ones only overlaps its immediate successor in + # a pairwise walk. + high_label, high_end = None, 0 + for label, offset, size in ordered: + if offset < high_end: + problems.append( + f"{high_label} (ends 0x{high_end:x}) overlaps " + f"{label} (starts 0x{offset:x}) on {dev_label}" + ) + if offset + size > high_end: + high_label, high_end = label, offset + size + return problems + + +def read_defines(paths): + """Collect ``#define``s, ``-D`` flags and make assignments from configuration files. + + The first definition of a name wins, and files earlier in ``paths`` take + precedence, so list the board's files before the port's defaults. + """ + defines = {} + for path in paths: + if not path.is_file(): + continue + text = path.read_text() + if path.suffix == ".mk": + for match in CFLAG_DEFINE_RE.finditer(text): + value = next(v for v in match.groups()[1:] if v is not None) + defines.setdefault(match.group(1), value) + for match in MK_ASSIGN_RE.finditer(text): + defines.setdefault(match.group(1), match.group(2)) + else: + for match in DEFINE_RE.finditer(text): + defines.setdefault(match.group(1), match.group(2)) + return defines + + +def evaluate(defines, name, default=None): + """Integer value of a define, following references to other defines. + + Returns ``default`` when the name is undefined and None when it cannot be + evaluated, so that a layout is never declared correct on a guess. + """ + expr = defines.get(name) + if expr is None: + return default + for ident in sorted(set(IDENTIFIER_RE.findall(expr)), key=len, reverse=True): + value = evaluate(defines, ident) + if value is None: + return None + expr = re.sub(rf"(?/`` under ``ports/`` and ``flash_size`` the + size of the internal flash. Returns ``{"nvm": (offset, size), "circuitpy": + (offset, size)}``; ``"circuitpy"`` is the string ``"external"`` when that + build uses a whole external flash chip as the drive. Raises ValueError when + the port's rules are unknown or a value cannot be derived. + """ + port, _, board = counterpart.partition("/") + port_dir = TOP / "ports" / port + board_dir = port_dir / "boards" / board + if not board_dir.is_dir(): + raise ValueError(f"{counterpart}: no such board under ports/") + defines = read_defines( + [ + board_dir / "mpconfigboard.mk", + board_dir / "mpconfigboard.h", + port_dir / "mpconfigport.mk", + port_dir / "mpconfigport.h", + ] + ) + + def value(name, default=None): + result = evaluate(defines, name, default) + if result is None: + raise ValueError(f"{counterpart}: cannot evaluate {name}") + return result + + if port == "raspberrypi": + # ports/raspberrypi/mpconfigport.h: nvm directly follows the firmware region, + # the drive follows nvm (and the saves partition on boards that have one). + firmware = value("CIRCUITPY_FIRMWARE_SIZE") + nvm_size = value("CIRCUITPY_INTERNAL_NVM_SIZE") + drive = firmware + nvm_size + value("CIRCUITPY_SAVES_PARTITION_SIZE", 0) + return {"nvm": (firmware, nvm_size), "circuitpy": (drive, flash_size - drive)} + if port == "nordic": + # ports/nordic/mpconfigport.h: the bootloader sits at the top of flash, an + # internal filesystem (when there is one) directly below it and nvm below that. + bootloader = ( + flash_size + - value("BOOTLOADER_SIZE") + - value("BOOTLOADER_SETTINGS_SIZE") + - value("BOOTLOADER_MBR_SIZE") + ) + external = any( + defines.get(flag, "0").strip() == "1" + for flag in ("QSPI_FLASH_FILESYSTEM", "SPI_FLASH_FILESYSTEM") + ) + fs_size = 0 if external else value("CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE") + fs_start = bootloader - fs_size + nvm_size = value("CIRCUITPY_INTERNAL_NVM_SIZE") + return { + "nvm": (fs_start - nvm_size, nvm_size), + "circuitpy": "external" if external else (fs_start, fs_size), + } + raise ValueError(f"{counterpart}: no layout rules known for port {port}") + + +def is_internal_flash(node): + return "soc-nv-flash" in getattr(node, "compats", []) + + +def is_external_flash(node): + return node.props.get("size") is not None and any( + "nor" in compat for compat in getattr(node, "compats", []) + ) + + +def check_parity(edt, counterpart): + """Return problems where the layout differs from the non-Zephyr ``counterpart``.""" + internal = [node for node in edt.nodes if is_internal_flash(node)] + if not internal: + return [f"no soc-nv-flash device to compare with {counterpart}"] + try: + expected = reference_layout(counterpart, device_size(internal[0])) + except ValueError as e: + return [str(e)] + + partitions = {} + for node, dev, offset, size, mapped in iter_partitions(edt): + label = node.labels[0] if node.labels else node.name + partitions[label] = (dev, offset, size) + + problems = [] + + def compare(label, want): + found = partitions.get(label) + if found is None: + problems.append( + f"{label}: missing, {counterpart} has it at 0x{want[0]:x}+0x{want[1]:x}" + ) + return + dev, offset, size = found + if not is_internal_flash(dev): + problems.append(f"{label}: not on the internal flash, unlike {counterpart}") + if (offset, size) != want: + problems.append( + f"{label}: 0x{offset:x}+0x{size:x}, {counterpart} has it at " + f"0x{want[0]:x}+0x{want[1]:x}" + ) + + compare("nvm_partition", expected["nvm"]) + if expected["circuitpy"] == "external": + # supervisor/flash.c uses the first flash device no partition covers as the + # drive, which is the whole chip only while the chip carries no partitions. + if "circuitpy_partition" in partitions: + problems.append( + f"circuitpy_partition: declared, but {counterpart} uses the whole " + f"external flash as the drive" + ) + external = [node for node in edt.nodes if is_external_flash(node)] + if not external: + problems.append(f"no external flash, but {counterpart} keeps the drive on one") + for dev, offset, size in partitions.values(): + if is_external_flash(dev): + problems.append( + f"{dev.labels[0] if dev.labels else dev.name}: carries partitions, " + f"but {counterpart} uses the whole chip as the drive" + ) + break + else: + compare("circuitpy_partition", expected["circuitpy"]) + return problems + + +def counterpart_of(board_id): + """The ``counterpart`` a board declares in its circuitpython.toml, if any.""" + toml_path = board_tools.find_mpconfigboard(PORT_DIR, board_id) if board_id else None + if toml_path is None: + return None + with toml_path.open("rb") as f: + return tomllib.load(f).get("counterpart") + + +def main(): + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument( + "build_dirs", + nargs="*", + help="Build directories to check (default: every build-* in the port)", + ) + parser.add_argument( + "--board", + help="Board built in the (single) build directory; default: taken from its name", + ) + args = parser.parse_args() + + dirs = [pathlib.Path(d) for d in args.build_dirs] + if not dirs: + dirs = sorted(p for p in PORT_DIR.glob("build-*") if p.is_dir()) + if not dirs: + print("No build directories found; build a board first.", file=sys.stderr) + return 1 + if args.board and len(dirs) != 1: + parser.error("--board applies to exactly one build directory") + + failed = [] + checked = 0 + for build_dir in dirs: + edt = load_edt(build_dir) + if edt is None: + continue + checked += 1 + n_parts = sum(1 for _ in iter_partitions(edt)) + problems = check_layout(edt) + board = args.board or build_dir.name.removeprefix("build-") + counterpart = counterpart_of(board) + if counterpart: + problems += check_parity(edt, counterpart) + if problems: + failed.append(build_dir.name) + print(f"{build_dir.name}:") + for problem in problems: + print(f" FAIL {problem}") + else: + # Say how much was inspected: a board whose overlay defines no + # partitions at all would otherwise be indistinguishable from a + # verified-good one. + parity = f", matches ports/{counterpart}" if counterpart else "" + print(f"{build_dir.name}: ok ({n_parts} partitions checked{parity})") + + if not checked: + print("No build directory held an edt.pickle; build a board first.", file=sys.stderr) + return 1 + if failed: + print(f"\n{len(failed)} board(s) with layout problems: {', '.join(failed)}") + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/ports/zephyr-cp/cptools/compat2driver.py b/ports/zephyr-cp/cptools/compat2driver.py index 2b818c4c237..8cd3c248265 100644 --- a/ports/zephyr-cp/cptools/compat2driver.py +++ b/ports/zephyr-cp/cptools/compat2driver.py @@ -1,18 +1,31 @@ # This file was generated by gen_compat2driver.py COMPAT_TO_DRIVER = { # adc + "adi_ad4050_adc": "adc", + "adi_ad4052_adc": "adc", "adi_ad4114_adc": "adc", + "adi_ad4130_adc": "adc", + "adi_ad4170_adc": "adc", + "adi_ad4190_adc": "adc", + "adi_ad4195_adc": "adc", "adi_ad559x_adc": "adc", + "adi_ad7124_adc": "adc", "adi_max32_adc": "adc", "ambiq_adc": "adc", "atmel_sam0_adc": "adc", "atmel_sam_adc": "adc", "atmel_sam_afec": "adc", + "bflb_adc": "adc", + "ene_kb106x_adc": "adc", "ene_kb1200_adc": "adc", "espressif_esp32_adc": "adc", "gd_gd32_adc": "adc", - "infineon_cat1_adc": "adc", + "infineon_adc": "adc", + "infineon_autanalog_sar_adc": "adc", + "infineon_hppass_sar_adc": "adc", + "infineon_sar_adc": "adc", "infineon_xmc4xxx_adc": "adc", + "ite_it51xxx_adc": "adc", "ite_it8xxx2_adc": "adc", "lltc_ltc2451": "adc", "maxim_max11102": "adc", @@ -26,6 +39,8 @@ "maxim_max11117": "adc", "maxim_max11253": "adc", "maxim_max11254": "adc", + "microchip_adc_g1": "adc", + "microchip_mcp356xr": "adc", "microchip_xec_adc": "adc", "nordic_nrf_adc": "adc", "nordic_nrf_saadc": "adc", @@ -37,13 +52,23 @@ "nxp_lpc_lpadc": "adc", "nxp_mcux_12b1msps_sar": "adc", "nxp_s32_adc_sar": "adc", + "nxp_sar_adc": "adc", "nxp_vf610_adc": "adc", "raspberrypi_pico_adc": "adc", - "renesas_ra_adc": "adc", + "realtek_rts5912_adc": "adc", + "renesas_ra_adc12": "adc", + "renesas_ra_adc16": "adc", + "renesas_rx_adc": "adc", + "renesas_rz_adc": "adc", + "renesas_rz_adc_c": "adc", + "renesas_rz_adc_e": "adc", + "renesas_rza2m_adc": "adc", "renesas_smartbond_adc": "adc", "renesas_smartbond_sdadc": "adc", + "sifli_sf32lb_gpadc": "adc", "silabs_gecko_adc": "adc", - "silabs_gecko_iadc": "adc", + "silabs_iadc": "adc", + "silabs_siwx91x_adc": "adc", "st_stm32_adc": "adc", "st_stm32wb0_adc": "adc", "telink_b91_adc": "adc", @@ -55,10 +80,27 @@ "ti_ads1114": "adc", "ti_ads1115": "adc", "ti_ads1119": "adc", + "ti_ads114s06": "adc", "ti_ads114s08": "adc", + "ti_ads124s06": "adc", + "ti_ads124s08": "adc", "ti_ads131m02": "adc", "ti_ads7052": "adc", + "ti_ads7950": "adc", + "ti_ads7951": "adc", + "ti_ads7952": "adc", + "ti_ads7953": "adc", + "ti_ads7954": "adc", + "ti_ads7955": "adc", + "ti_ads7956": "adc", + "ti_ads7957": "adc", + "ti_ads7958": "adc", + "ti_ads7959": "adc", + "ti_ads7960": "adc", + "ti_ads7961": "adc", + "ti_am335x_adc": "adc", "ti_cc13xx_cc26xx_adc": "adc", + "ti_cc23x0_adc": "adc", "ti_cc32xx_adc": "adc", "ti_lmp90077": "adc", "ti_lmp90078": "adc", @@ -72,40 +114,65 @@ "ti_tla2022": "adc", "ti_tla2024": "adc", "vnd_adc": "adc", + "wch_adc": "adc", "zephyr_adc_emul": "adc", # # audio + "ambiq_pdm": "audio", + "cirrus_cs43l22": "audio", + "dlg_da7212": "audio", + "maxim_max98091": "audio", + "nordic_nrf_pdm": "audio", "nxp_dmic": "audio", + "nxp_micfil": "audio", + "sifli_sf32lb_audcodec": "audio", "st_mpxxdtyy": "audio", + "ti_pcm1681": "audio", "ti_tas6422dac": "audio", + "ti_tlv320aic3110": "audio", "ti_tlv320dac": "audio", "wolfson_wm8904": "audio", + "wolfson_wm8962": "audio", + # + # audio/mic_privacy/intel + "intel_adsp_mic_privacy": "audio/mic_privacy/intel", # # auxdisplay + "gpio_7_segment": "auxdisplay", "hit_hd44780": "auxdisplay", "jhd_jhd1313": "auxdisplay", "noritake_itron": "auxdisplay", "ptc_pt6314": "auxdisplay", "sparkfun_serlcd": "auxdisplay", + "titanmec_tm1637": "auxdisplay", # # bbram "ite_it8xxx2_bbram": "bbram", "microchip_xec_bbram": "bbram", + "motorola_mc146818_bbram": "bbram", "nuvoton_npcx_bbram": "bbram", + "realtek_rts5912_bbram": "bbram", "st_stm32_bbram": "bbram", "zephyr_bbram_emul": "bbram", # + # biometrics + "adh_tech_gt5x": "biometrics", + "zephyr_biometrics_emul": "biometrics", + "zhiantec_zfm_x0": "biometrics", + # # bluetooth/hci "ambiq_bt_hci_spi": "bluetooth/hci", "espressif_esp32_bt_hci": "bluetooth/hci", - "infineon_cat1_bless_hci": "bluetooth/hci", + "infineon_bless_hci": "bluetooth/hci", + "infineon_bt_hci_uart": "bluetooth/hci", "infineon_cyw208xx_hci": "bluetooth/hci", - "infineon_cyw43xxx_bt_hci": "bluetooth/hci", "nxp_bt_hci_uart": "bluetooth/hci", "nxp_hci_ble": "bluetooth/hci", "renesas_bt_hci_da1453x": "bluetooth/hci", "renesas_bt_hci_da1469x": "bluetooth/hci", + "sifli_sf32lb_mailbox": "bluetooth/hci", "silabs_bt_hci_efr32": "bluetooth/hci", + "silabs_siwx91x_bt_hci": "bluetooth/hci", "st_hci_spi_v1": "bluetooth/hci", "st_hci_spi_v2": "bluetooth/hci", "st_hci_stm32wb0": "bluetooth/hci", @@ -116,8 +183,13 @@ "zephyr_bt_hci_spi": "bluetooth/hci", "zephyr_bt_hci_uart": "bluetooth/hci", "zephyr_bt_hci_userchan": "bluetooth/hci", + "zephyr_bt_hci_ll_sw_split": "bluetooth/hci", + # + # cache + "bflb_l1c": "cache", # # can + "adi_max32_can": "can", "atmel_sam0_can": "can", "atmel_sam_can": "can", "espressif_esp32_twai": "can", @@ -132,6 +204,7 @@ "nxp_s32_canxl": "can", "renesas_ra_canfd": "can", "renesas_rcar_can": "can", + "renesas_rz_canfd": "can", "st_stm32_bxcan": "can", "st_stm32_fdcan": "can", "st_stm32h7_fdcan": "can", @@ -145,21 +218,43 @@ # # charger "maxim_max20335_charger": "charger", + "nxp_pca9422_charger": "charger", + "nxp_pf1550_charger": "charger", "sbs_sbs_charger": "charger", "ti_bq24190": "charger", "ti_bq25180": "charger", + "ti_bq25186": "charger", + "ti_bq25188": "charger", + "ti_bq25713": "charger", + "x_powers_axp2101_charger": "charger", + "zephyr_charger_gpio": "charger", # # clock_control "adi_max32_gcr": "clock_control", + "alif_clockctrl": "clock_control", "ambiq_clkctrl": "clock_control", "arm_beetle_syscon": "clock_control", "arm_scmi_clock": "clock_control", "aspeed_ast10x0_clock": "clock_control", "atmel_sam_pmc": "clock_control", - "espressif_esp32_rtc": "clock_control", + "bflb_bl60x_clock_controller": "clock_control", + "bflb_bl61x_clock_controller": "clock_control", + "bflb_bl70x_clock_controller": "clock_control", + "espressif_esp32_clock": "clock_control", "fixed_clock": "clock_control", + "focaltech_ft9001_cpm": "clock_control", "gd_gd32_cctl": "clock_control", + "infineon_fixed_clock": "clock_control", + "infineon_fixed_factor_clock": "clock_control", + "infineon_peri_div": "clock_control", "intel_agilex5_clock": "clock_control", + "ite_it51xxx_ecpm": "clock_control", + "microchip_pic32cm_jh_clock": "clock_control", + "microchip_pic32cm_pl_clock": "clock_control", + "microchip_pic32cz_ca_clock": "clock_control", + "microchip_sam_d5x_e5x_clock": "clock_control", + "microchip_sam_pmc": "clock_control", + "microchip_sama7g5_sckc": "clock_control", "microchip_xec_pcr": "clock_control", "nordic_nrf54h_hfxo": "clock_control", "nordic_nrf_auxpll": "clock_control", @@ -167,7 +262,9 @@ "nordic_nrf_fll16m": "clock_control", "nordic_nrf_hsfll_global": "clock_control", "nordic_nrf_hsfll_local": "clock_control", + "nordic_nrf_iron_hsfll_local": "clock_control", "nordic_nrf_lfclk": "clock_control", + "nordic_nrfs_audiopll": "clock_control", "nuvoton_npcm_pcc": "clock_control", "nuvoton_npcx_pcc": "clock_control", "nuvoton_numaker_scc": "clock_control", @@ -179,27 +276,51 @@ "nxp_kinetis_sim": "clock_control", "nxp_lpc11u6x_syscon": "clock_control", "nxp_lpc_syscon": "clock_control", + "nxp_mc_cgm": "clock_control", "nxp_s32_clock": "clock_control", "nxp_scg_k4": "clock_control", "openisa_rv32m1_pcc": "clock_control", "pwm_clock": "clock_control", "raspberrypi_pico_clock_controller": "clock_control", + "realtek_bee_cctl": "clock_control", + "realtek_rts5817_clock": "clock_control", "realtek_rts5912_sccon": "clock_control", "renesas_r8a7795_cpg_mssr": "clock_control", "renesas_r8a779f0_cpg_mssr": "clock_control", + "renesas_ra_cgc_subclk": "clock_control", + "renesas_rx_cgc_pclk": "clock_control", + "renesas_rx_cgc_pll": "clock_control", + "renesas_rx_cgc_root_clock": "clock_control", + "renesas_rz_cgc": "clock_control", + "renesas_rz_cpg": "clock_control", + "renesas_rza2m_cpg": "clock_control", + "sifli_sf32lb_hxt48": "clock_control", + "sifli_sf32lb_rcc_clk": "clock_control", "silabs_series_clock": "clock_control", "silabs_si32_ahb": "clock_control", "silabs_si32_apb": "clock_control", "silabs_si32_pll": "clock_control", + "silabs_siwx91x_clock": "clock_control", "smartbond_clock": "clock_control", "st_stm32_clock_mco": "clock_control", "st_stm32_clock_mux": "clock_control", "st_stm32f1_clock_mco": "clock_control", + "ti_k2g_sci_clk": "clock_control", "wch_rcc": "clock_control", # # comparator + "ite_it51xxx_vcmp": "comparator", + "microchip_ac_g1_comparator": "comparator", "nordic_nrf_comp": "comparator", "nordic_nrf_lpcomp": "comparator", + "nxp_acomp": "comparator", + "nxp_cmp": "comparator", + "nxp_hscmp": "comparator", + "renesas_ra_acmphs": "comparator", + "renesas_ra_lvd": "comparator", + "renesas_rx_lvd": "comparator", + "silabs_acmp": "comparator", + "st_stm32_comp": "comparator", "zephyr_fake_comp": "comparator", # # coredump @@ -208,21 +329,34 @@ # counter "adi_max32_counter": "counter", "adi_max32_rtc_counter": "counter", + "adi_max32_wut": "counter", "ambiq_counter": "counter", "andestech_atcpit100": "counter", "arm_cmsdk_dtimer": "counter", "arm_cmsdk_timer": "counter", "atmel_sam0_tc32": "counter", "atmel_sam_tc": "counter", + "espressif_esp32_counter": "counter", "espressif_esp32_rtc_timer": "counter", - "espressif_esp32_timer": "counter", "gd_gd32_timer": "counter", - "infineon_cat1_counter": "counter", + "infineon_counter": "counter", + "infineon_tcpwm_counter": "counter", + "ite_it51xxx_counter": "counter", + "ite_it8xxx2_counter": "counter", "maxim_ds3231": "counter", "microchip_mcp7940n": "counter", + "microchip_sam_pit64b_counter": "counter", + "microchip_tc_g1_counter": "counter", + "microchip_tcc_g1_counter": "counter", "microchip_xec_timer": "counter", + "microcrystal_rv3032_counter": "counter", + "neorv32_gptmr": "counter", "nordic_nrf_rtc": "counter", "nordic_nrf_timer": "counter", + "nuvoton_npck_lct": "counter", + "nuvoton_npcx_lct_v1": "counter", + "nuvoton_npcx_lct_v2": "counter", + "nxp_ftm": "counter", "nxp_imx_epit": "counter", "nxp_imx_gpt": "counter", "nxp_imx_qtmr": "counter", @@ -231,37 +365,68 @@ "nxp_lpc_ctimer": "counter", "nxp_lpc_rtc": "counter", "nxp_lpc_rtc_highres": "counter", + "nxp_lpit": "counter", "nxp_mrt": "counter", "nxp_pit": "counter", "nxp_rtc": "counter", + "nxp_rtc_jdp": "counter", "nxp_s32_sys_timer": "counter", + "nxp_stm": "counter", "nxp_tpm_timer": "counter", + "raspberrypi_pico_pit": "counter", + "raspberrypi_pico_pit_channel": "counter", "raspberrypi_pico_timer": "counter", + "realtek_rts5912_slwtimer": "counter", + "realtek_rts5912_timer": "counter", "renesas_ra_agt_counter": "counter", + "renesas_rz_cmtw_counter": "counter", + "renesas_rz_gtm_counter": "counter", "renesas_smartbond_timer": "counter", + "silabs_burtc_counter": "counter", "silabs_gecko_rtcc": "counter", - "silabs_gecko_stimer": "counter", + "silabs_timer_counter": "counter", "snps_dw_timers": "counter", "st_stm32_counter": "counter", + "ti_cc23x0_lgpt": "counter", + "ti_cc23x0_rtc": "counter", + "ti_mspm0_timer_counter": "counter", "xlnx_xps_timer_1_00_a": "counter", - "zephyr_native_posix_counter": "counter", + "zephyr_native_sim_counter": "counter", + # + # crc + "nxp_crc": "crc", + "nxp_lpc_crc": "crc", + "renesas_ra_crc": "crc", + "sifli_sf32lb_crc": "crc", # # crypto "atmel_ataes132a": "crypto", + "espressif_esp32_aes": "crypto", + "espressif_esp32_sha": "crypto", "intel_adsp_sha": "crypto", + "ite_it51xxx_sha": "crypto", "ite_it8xxx2_sha": "crypto", "ite_it8xxx2_sha_v2": "crypto", + "microchip_sha_g1_crypto": "crypto", "microchip_xec_symcr": "crypto", "nordic_nrf_ecb": "crypto", "nuvoton_npcx_sha": "crypto", "nxp_mcux_dcp": "crypto", + "nxp_s32_crypto_hse_mu": "crypto", + "raspberrypi_pico_sha256": "crypto", + "realtek_rts5912_sha": "crypto", "renesas_smartbond_crypto": "crypto", "silabs_si32_aes": "crypto", "st_stm32_aes": "crypto", "st_stm32_cryp": "crypto", + "st_stm32_hash": "crypto", + "ti_cc23x0_aes": "crypto", # # dac "adi_ad559x_dac": "dac", + "adi_ad5601": "dac", + "adi_ad5611": "dac", + "adi_ad5621": "dac", "adi_ad5628": "dac", "adi_ad5648": "dac", "adi_ad5668": "dac", @@ -279,15 +444,21 @@ "adi_max22017_dac": "dac", "atmel_sam0_dac": "dac", "atmel_sam_dac": "dac", + "atmel_samd5x_dac": "dac", "espressif_esp32_dac": "dac", "gd_gd32_dac": "dac", + "microchip_dac_g1": "dac", "microchip_mcp4725": "dac", "microchip_mcp4728": "dac", + "nxp_dac12": "dac", "nxp_gau_dac": "dac", "nxp_kinetis_dac": "dac", "nxp_kinetis_dac32": "dac", "nxp_lpdac": "dac", + "renesas_ra_dac": "dac", + "silabs_vdac": "dac", "st_stm32_dac": "dac", + "ti_dac161s997": "dac", "ti_dacx0501": "dac", "vnd_dac": "dac", # @@ -303,9 +474,19 @@ # dai/intel/ssp "intel_ssp_dai": "dai/intel/ssp", # + # dai/nxp/esai + "nxp_dai_esai": "dai/nxp/esai", + # + # dai/nxp/micfil + "nxp_dai_micfil": "dai/nxp/micfil", + # # dai/nxp/sai "nxp_dai_sai": "dai/nxp/sai", # + # debug + "nordic_coresight_nrf": "debug", + "silabs_pti": "debug", + # # disk "st_stm32_sdmmc": "disk", "zephyr_flash_disk": "disk", @@ -317,42 +498,52 @@ "nvme_controller": "disk/nvme", # # display + "chipone_co5300": "display", "frida_nt35510": "display", "galaxycore_gc9x01x": "display", + "himax_hx8379c": "display", "himax_hx8394": "display", "ilitek_ili9806e_dsi": "display", "intel_multiboot_framebuffer": "display", "istech_ist3931": "display", + "jdi_lpm013m126": "display", "led_strip_matrix": "display", "maxim_max7219": "display", "nxp_dcnano_lcdif": "display", "nxp_imx_elcdif": "display", + "nxp_imx_lcdifv3": "display", "orisetech_otm8009a": "display", "raydium_rm67162": "display", "raydium_rm68200": "display", "renesas_ra_glcdc": "display", "renesas_smartbond_display": "display", "sharp_ls0xx": "display", + "sitronix_st75256": "display", + "sitronix_st7701": "display", "sitronix_st7735r": "display", "sitronix_st7789v": "display", "sitronix_st7796s": "display", "solomon_ssd1322": "display", "st_stm32_ltdc": "display", + "waveshare_dsi2dpi": "display", "zephyr_dummy_dc": "display", + "zephyr_hub12": "display", "zephyr_sdl_dc": "display", # # dma "adi_max32_dma": "dma", "altr_msgdma": "dma", - "andestech_atcdmac300": "dma", + "andestech_atcdmacx00": "dma", + "arm_dma_pl330": "dma", "atmel_sam0_dmac": "dma", "atmel_sam_xdmac": "dma", + "bflb_dma": "dma", "brcm_iproc_pax_dma_v1": "dma", "brcm_iproc_pax_dma_v2": "dma", "espressif_esp32_gdma": "dma", "gd_gd32_dma": "dma", "gd_gd32_dma_v1": "dma", - "infineon_cat1_dma": "dma", + "infineon_dma": "dma", "infineon_xmc4xxx_dma": "dma", "intel_adsp_gpdma": "dma", "intel_adsp_hda_host_in": "dma", @@ -361,7 +552,11 @@ "intel_adsp_hda_link_out": "dma", "intel_lpss": "dma", "intel_sedi_dma": "dma", + "microchip_dmac_g1_dma": "dma", "microchip_xec_dmac": "dma", + "nuvoton_npcx_gdma": "dma", + "nxp_4ch_dma": "dma", + "nxp_edma": "dma", "nxp_lpc_dma": "dma", "nxp_mcux_edma": "dma", "nxp_pxp": "dma", @@ -369,9 +564,15 @@ "nxp_smartdma": "dma", "nxp_sof_host_dma": "dma", "raspberrypi_pico_dma": "dma", + "renesas_ra_dma": "dma", + "renesas_rz_dmac": "dma", + "renesas_rz_dmac_b": "dma", "renesas_smartbond_dma": "dma", + "sifli_sf32lb_dmac": "dma", + "silabs_gpdma": "dma", "silabs_ldma": "dma", "silabs_si32_dma": "dma", + "silabs_siwx91x_dma": "dma", "snps_designware_dma": "dma", "snps_designware_dma_axi": "dma", "st_stm32_bdma": "dma", @@ -380,6 +581,8 @@ "st_stm32_dma_v2bis": "dma", "st_stm32_dmamux": "dma", "st_stm32u5_dma": "dma", + "ti_cc23x0_dma": "dma", + "wch_wch_dma": "dma", "xlnx_axi_dma_1_00_a": "dma", "xlnx_eth_dma": "dma", "zephyr_dma_emul": "dma", @@ -389,40 +592,57 @@ # # edac "intel_ibecc": "edac", + "nxp_erm": "edac", + "xlnx_zynqmp_ddrc_2_40a": "edac", # # eeprom "atmel_at24": "eeprom", "fujitsu_mb85rcxx": "eeprom", "fujitsu_mb85rsxx": "eeprom", + "infineon_fm25xxx": "eeprom", "microchip_xec_eeprom": "eeprom", "nxp_lpc11u6x_eeprom": "eeprom", "st_stm32_eeprom": "eeprom", - "ti_tmp116_eeprom": "eeprom", + "ti_tmp11x_eeprom": "eeprom", "zephyr_emu_eeprom": "eeprom", "zephyr_fake_eeprom": "eeprom", "zephyr_sim_eeprom": "eeprom", # # entropy "adi_max32_trng": "entropy", + "adi_maxq10xx_trng": "entropy", + "ambiq_puf_trng": "entropy", "atmel_sam_trng": "entropy", + "brcm_iproc_rng200": "entropy", "espressif_esp32_trng": "entropy", + "gd_gd32_trng": "entropy", "litex_prbs": "entropy", + "microchip_trng_g1_entropy": "entropy", "neorv32_trng": "entropy", + "nordic_nrf_cracen_ctrdrbg": "entropy", "nordic_nrf_rng": "entropy", "nuvoton_npcx_drbg": "entropy", + "nxp_ele_trng": "entropy", "nxp_imx_caam": "entropy", "nxp_kinetis_rnga": "entropy", "nxp_kinetis_trng": "entropy", "nxp_lpc_rng": "entropy", "openisa_rv32m1_trng": "entropy", + "raspberrypi_pico_rng": "entropy", "renesas_smartbond_trng": "entropy", + "sensry_sy1xx_trng": "entropy", + "sifli_sf32lb_trng": "entropy", "silabs_gecko_semailbox": "entropy", "silabs_gecko_trng": "entropy", + "silabs_siwx91x_rng": "entropy", "st_stm32_rng": "entropy", + "st_stm32_rng_noirq": "entropy", "telink_b91_trng": "entropy", "ti_cc13xx_cc26xx_trng": "entropy", + "ti_mspm0_trng": "entropy", + "virtio_device4": "entropy", "zephyr_bt_hci_entropy": "entropy", - "zephyr_native_posix_rng": "entropy", + "zephyr_native_sim_rng": "entropy", "zephyr_psa_crypto_rng": "entropy", # # espi @@ -435,6 +655,7 @@ "nuvoton_npcx_espi": "espi", "nuvoton_npcx_espi_taf": "espi", "nuvoton_npcx_host_sub": "espi", + "realtek_rts5912_espi": "espi", "zephyr_espi_emul_controller": "espi", # # ethernet @@ -448,26 +669,40 @@ "litex_liteeth": "ethernet", "microchip_enc28j60": "ethernet", "microchip_enc424j600": "ethernet", - "microchip_ksz8794": "ethernet", - "microchip_ksz8863": "ethernet", "microchip_lan865x": "ethernet", "microchip_lan9250": "ethernet", "nuvoton_numaker_ethernet": "ethernet", - "nxp_imx_netc_psi": "ethernet", + "nxp_enet": "ethernet", + "nxp_enet1g": "ethernet", + "nxp_enet_mac": "ethernet", "nxp_s32_gmac": "ethernet", "nxp_s32_netc_psi": "ethernet", "nxp_s32_netc_vsi": "ethernet", "renesas_ra_ethernet": "ethernet", + "sensry_sy1xx_mac": "ethernet", "siemens_ivshmem_eth": "ethernet", "silabs_gecko_ethernet": "ethernet", "smsc_lan91c111": "ethernet", + "smsc_lan91c111_mdio": "ethernet", "smsc_lan9220": "ethernet", "snps_designware_ethernet": "ethernet", "snps_ethernet_cyclonev": "ethernet", "st_stm32_ethernet": "ethernet", "ti_stellaris_ethernet": "ethernet", + "virtio_net": "ethernet", "vnd_ethernet": "ethernet", "wiznet_w5500": "ethernet", + "wiznet_w6100": "ethernet", + "xlnx_axi_ethernet_1_00_a": "ethernet", + "xlnx_gem": "ethernet", + "xlnx_xps_ethernetlite_1_00_a_mac": "ethernet", + "xlnx_xps_ethernetlite_3_00_a_mac": "ethernet", + # + # ethernet/dsa + "microchip_ksz8463": "ethernet/dsa", + "microchip_ksz8794": "ethernet/dsa", + "microchip_ksz8863": "ethernet/dsa", + "nxp_netc_switch": "ethernet/dsa", # # ethernet/dwc_xgmac "snps_dwcxgmac": "ethernet/dwc_xgmac", @@ -476,57 +711,102 @@ "nxp_enet_qos": "ethernet/eth_nxp_enet_qos", "nxp_enet_qos_mac": "ethernet/eth_nxp_enet_qos", # - # ethernet/nxp_enet - "nxp_enet": "ethernet/nxp_enet", - "nxp_enet1g": "ethernet/nxp_enet", - "nxp_enet_mac": "ethernet/nxp_enet", - "nxp_kinetis_ethernet": "ethernet/nxp_enet", + # ethernet/intel + "intel_eth_plat": "ethernet/intel", + "intel_igc_mac": "ethernet/intel", + # + # ethernet/mdio + "adi_adin2111_mdio": "ethernet/mdio", + "atmel_sam_mdio": "ethernet/mdio", + "espressif_esp32_mdio": "ethernet/mdio", + "infineon_xmc4xxx_mdio": "ethernet/mdio", + "intel_igc_mdio": "ethernet/mdio", + "litex_liteeth_mdio": "ethernet/mdio", + "microchip_lan865x_mdio": "ethernet/mdio", + "nxp_enet_mdio": "ethernet/mdio", + "nxp_enet_qos_mdio": "ethernet/mdio", + "nxp_imx_netc_emdio": "ethernet/mdio", + "nxp_s32_gmac_mdio": "ethernet/mdio", + "nxp_s32_netc_emdio": "ethernet/mdio", + "renesas_ra_mdio": "ethernet/mdio", + "sensry_sy1xx_mdio": "ethernet/mdio", + "snps_dwcxgmac_mdio": "ethernet/mdio", + "st_stm32_mdio": "ethernet/mdio", + "xlnx_axi_ethernet_1_00_a_mdio": "ethernet/mdio", + "xlnx_xps_ethernetlite_1_00_a_mdio": "ethernet/mdio", + "xlnx_xps_ethernetlite_3_00_a_mdio": "ethernet/mdio", + "zephyr_mdio_gpio": "ethernet/mdio", + # + # ethernet/nxp_imx_netc + "nxp_imx_netc_blk_ctrl": "ethernet/nxp_imx_netc", + "nxp_imx_netc_psi": "ethernet/nxp_imx_netc", # # ethernet/phy "adi_adin1100_phy": "ethernet/phy", "adi_adin2111_phy": "ethernet/phy", "davicom_dm8806_phy": "ethernet/phy", "ethernet_phy": "ethernet/phy", + "ethernet_phy_fixed_link": "ethernet/phy", "microchip_ksz8081": "ethernet/phy", + "microchip_ksz9131": "ethernet/phy", + "microchip_lan8742": "ethernet/phy", "microchip_t1s_phy": "ethernet/phy", "microchip_vsc8541": "ethernet/phy", + "motorcomm_yt8521": "ethernet/phy", "nxp_tja1103": "ethernet/phy", + "nxp_tja11xx": "ethernet/phy", "qca_ar8031": "ethernet/phy", "realtek_rtl8211f": "ethernet/phy", "ti_dp83825": "ethernet/phy", + "ti_dp83867": "ethernet/phy", # # firmware/scmi + "arm_scmi": "firmware/scmi", "arm_scmi_shmem": "firmware/scmi", # + # firmware/tisci + "ti_k2g_sci": "firmware/tisci", + # # flash "adi_max32_flash_controller": "flash", - "altr_nios2_qspi_nor": "flash", + "adi_max32_spixf_nor": "flash", "ambiq_flash_controller": "flash", "andestech_qspi_nor": "flash", + "andestech_qspi_nor_xip": "flash", + "atmel_at25xv021a": "flash", "atmel_at45": "flash", "atmel_sam0_nvmctrl": "flash", "atmel_sam_flash_controller": "flash", + "bflb_flash_controller": "flash", "cdns_nand": "flash", "cdns_qspi_nor": "flash", "espressif_esp32_flash_controller": "flash", "gd_gd32_flash_controller": "flash", - "infineon_cat1_flash_controller": "flash", - "infineon_cat1_qspi_flash": "flash", + "infineon_flash_controller": "flash", + "infineon_qspi_flash": "flash", "infineon_xmc4xxx_flash_controller": "flash", + "ite_it51xxx_manual_flash_1k": "flash", "ite_it8xxx2_flash_controller": "flash", + "jedec_mspi_nor": "flash", + "jedec_spi_nand": "flash", "jedec_spi_nor": "flash", + "microchip_nvmctrl_g1_flash": "flash", "mspi_atxp032": "flash", + "mspi_is25xx0xx": "flash", + "netsol_s3axx04": "flash", "nordic_mram": "flash", "nordic_nrf51_flash_controller": "flash", "nordic_nrf52_flash_controller": "flash", "nordic_nrf53_flash_controller": "flash", "nordic_nrf91_flash_controller": "flash", + "nordic_nrf_mramc": "flash", "nordic_qspi_nor": "flash", "nordic_rram_controller": "flash", "nuvoton_npcx_fiu_nor": "flash", "nuvoton_npcx_fiu_qspi": "flash", "nuvoton_numaker_fmc": "flash", "nuvoton_numaker_rmc": "flash", + "nxp_c40_flash_controller": "flash", "nxp_iap_fmc11": "flash", "nxp_iap_fmc54": "flash", "nxp_iap_fmc55": "flash", @@ -535,18 +815,31 @@ "nxp_imx_flexspi_mx25um51345g": "flash", "nxp_imx_flexspi_nor": "flash", "nxp_kinetis_ftfa": "flash", + "nxp_kinetis_ftfc": "flash", "nxp_kinetis_ftfe": "flash", "nxp_kinetis_ftfl": "flash", "nxp_msf1": "flash", + "nxp_s32_qspi_hyperflash": "flash", "nxp_s32_qspi_nor": "flash", + "nxp_s32_xspi_hyperram": "flash", + "nxp_xspi_nor": "flash", "openisa_rv32m1_ftfe": "flash", "raspberrypi_pico_flash_controller": "flash", + "realtek_rts5912_flash_controller": "flash", "renesas_ra_flash_hp_controller": "flash", + "renesas_ra_flash_lp_controller": "flash", + "renesas_ra_mram_controller": "flash", "renesas_ra_ospi_b_nor": "flash", "renesas_ra_qspi_nor": "flash", + "renesas_rx_flash": "flash", + "renesas_rz_qspi_spibsc": "flash", + "renesas_rz_qspi_xspi": "flash", "renesas_smartbond_flash_controller": "flash", + "sifli_sf32lb_mpi_qspi_nor": "flash", "silabs_gecko_flash_controller": "flash", + "silabs_series2_flash_controller": "flash", "silabs_si32_flash_controller": "flash", + "silabs_siwx91x_flash_controller": "flash", "st_stm32_flash_controller": "flash", "st_stm32_ospi_nor": "flash", "st_stm32_qspi_nor": "flash", @@ -556,6 +849,7 @@ "st_stm32wba_flash_controller": "flash", "telink_b91_flash_controller": "flash", "ti_cc13xx_cc26xx_flash_controller": "flash", + "ti_cc23x0_flash_controller": "flash", "zephyr_mspi_emul_flash": "flash", "zephyr_sim_flash": "flash", # @@ -568,12 +862,27 @@ "renesas_slg47115": "fpga", "xlnx_fpga": "fpga", # + # fuel_gauge/axp2101 + "x_powers_axp2101_fuel_gauge": "fuel_gauge/axp2101", + # # fuel_gauge/bq27z746 "ti_bq27z746": "fuel_gauge/bq27z746", # + # fuel_gauge/bq40z50 + "ti_bq40z50": "fuel_gauge/bq40z50", + # # fuel_gauge/composite "zephyr_fuel_gauge_composite": "fuel_gauge/composite", # + # fuel_gauge/hy4245 + "hycon_hy4245": "fuel_gauge/hy4245", + # + # fuel_gauge/lc709203f + "onnn_lc709203f": "fuel_gauge/lc709203f", + # + # fuel_gauge/ltc2959 + "adi_ltc2959": "fuel_gauge/ltc2959", + # # fuel_gauge/max17048 "maxim_max17048": "fuel_gauge/max17048", # @@ -581,47 +890,63 @@ "sbs_sbs_gauge": "fuel_gauge/sbs_gauge", "sbs_sbs_gauge_new_api": "fuel_gauge/sbs_gauge", # + # fuel_gauge/sy24561 + "silergy_sy24561": "fuel_gauge/sy24561", + # # gnss "gnss_nmea_generic": "gnss", "luatos_air530z": "gnss", "quectel_lc26g": "gnss", "quectel_lc76g": "gnss", "quectel_lc86g": "gnss", - "u_blox_m8": "gnss", "zephyr_gnss_emul": "gnss", # + # gnss/u_blox + "u_blox_f9p": "gnss/u_blox", + "u_blox_m8": "gnss/u_blox", + # # gpio "adi_ad559x_gpio": "gpio", "adi_adp5585_gpio": "gpio", "adi_max14906_gpio": "gpio", + "adi_max14915_gpio": "gpio", "adi_max14916_gpio": "gpio", + "adi_max14917_gpio": "gpio", "adi_max22017_gpio": "gpio", "adi_max22190_gpio": "gpio", + "adi_max22199_gpio": "gpio", "adi_max32_gpio": "gpio", + "aesc_gpio": "gpio", "altr_pio_1_0": "gpio", "ambiq_gpio_bank": "gpio", "andestech_atcgpio100": "gpio", "arm_cmsdk_gpio": "gpio", + "arm_mmio32_gpio": "gpio", "atmel_sam0_gpio": "gpio", "atmel_sam4l_gpio": "gpio", "atmel_sam_gpio": "gpio", "awinic_aw9523b_gpio": "gpio", + "bflb_bl60x_70x_gpio": "gpio", + "bflb_bl61x_gpio": "gpio", "brcm_bcm2711_gpio": "gpio", "brcm_brcmstb_gpio": "gpio", "brcm_iproc_gpio": "gpio", "cypress_cy8c95xx_gpio_port": "gpio", "cypress_psoc6_gpio": "gpio", "efinix_sapphire_gpio": "gpio", + "ene_kb106x_gpio": "gpio", "ene_kb1200_gpio": "gpio", "espressif_esp32_gpio": "gpio", + "espressif_esp32_lpgpio": "gpio", "fcs_fxl6408": "gpio", "gaisler_grgpio": "gpio", "gd_gd32_gpio": "gpio", - "infineon_cat1_gpio": "gpio", + "infineon_gpio": "gpio", "infineon_tle9104_gpio": "gpio", "infineon_xmc4xxx_gpio": "gpio", "intel_gpio": "gpio", "intel_sedi_gpio": "gpio", + "ite_it51xxx_gpio": "gpio", "ite_it8801_gpio": "gpio", "ite_it8xxx2_gpio": "gpio", "ite_it8xxx2_gpio_v2": "gpio", @@ -636,12 +961,13 @@ "microchip_mcp23s09": "gpio", "microchip_mcp23s17": "gpio", "microchip_mcp23s18": "gpio", - "microchip_mec5_gpio": "gpio", "microchip_mpfs_gpio": "gpio", + "microchip_port_g1_gpio": "gpio", + "microchip_sam_pio4": "gpio", "microchip_xec_gpio": "gpio", - "microchip_xec_gpio_v2": "gpio", "neorv32_gpio": "gpio", "nordic_npm1300_gpio": "gpio", + "nordic_npm1304_gpio": "gpio", "nordic_npm2100_gpio": "gpio", "nordic_npm6001_gpio": "gpio", "nordic_nrf_gpio": "gpio", @@ -656,27 +982,38 @@ "nxp_kinetis_gpio": "gpio", "nxp_lpc11u6x_gpio": "gpio", "nxp_lpc_gpio_port": "gpio", + "nxp_pca6408": "gpio", + "nxp_pca6416": "gpio", "nxp_pca9538": "gpio", "nxp_pca9539": "gpio", "nxp_pca9554": "gpio", "nxp_pca9555": "gpio", "nxp_pca95xx": "gpio", + "nxp_pcal6408": "gpio", "nxp_pcal6408a": "gpio", + "nxp_pcal6416": "gpio", "nxp_pcal6416a": "gpio", "nxp_pcal6524": "gpio", "nxp_pcal6534": "gpio", + "nxp_pcal9538": "gpio", + "nxp_pcal9539": "gpio", + "nxp_pcal9722": "gpio", "nxp_pcf857x": "gpio", - "nxp_s32_gpio": "gpio", "nxp_sc18im704_gpio": "gpio", + "nxp_sc18is606_gpio": "gpio", + "nxp_siul2_gpio": "gpio", "openisa_rv32m1_gpio": "gpio", "quicklogic_eos_s3_gpio": "gpio", - "raspberrypi_pico_gpio": "gpio", + "raspberrypi_pico_gpio_port": "gpio", "raspberrypi_rp1_gpio": "gpio", + "realtek_ameba_gpio": "gpio", + "realtek_bee_gpio": "gpio", "realtek_rts5912_gpio": "gpio", - "renesas_ra_gpio": "gpio", "renesas_ra_gpio_ioport": "gpio", "renesas_rcar_gpio": "gpio", + "renesas_rx_gpio": "gpio", "renesas_rz_gpio": "gpio", + "renesas_rza2m_gpio": "gpio", "renesas_rzt2m_gpio": "gpio", "renesas_smartbond_gpio": "gpio", "richtek_rt1718s": "gpio", @@ -685,18 +1022,25 @@ "semtech_sx1509b": "gpio", "sensry_sy1xx_gpio": "gpio", "sifive_gpio0": "gpio", + "sifli_sf32lb_gpio": "gpio", "silabs_gecko_gpio_port": "gpio", + "silabs_gpio": "gpio", "silabs_si32_gpio": "gpio", + "silabs_siwx91x_gpio": "gpio", + "silabs_siwx91x_gpio_uulp": "gpio", "snps_creg_gpio": "gpio", "snps_designware_gpio": "gpio", + "st_mfxstm32l152": "gpio", "st_stm32_gpio": "gpio", "st_stmpe1600": "gpio", "telink_b91_gpio": "gpio", - "ti_ads114s0x_gpio": "gpio", + "ti_ads1x4s0x_gpio": "gpio", "ti_cc13xx_cc26xx_gpio": "gpio", + "ti_cc23x0_gpio": "gpio", "ti_cc32xx_gpio": "gpio", "ti_davinci_gpio": "gpio", "ti_lmp90xxx_gpio": "gpio", + "ti_mspm0_gpio": "gpio", "ti_sn74hc595": "gpio", "ti_stellaris_gpio": "gpio", "ti_tca6424a": "gpio", @@ -710,11 +1054,15 @@ "zephyr_gpio_emul": "gpio", "zephyr_gpio_emul_sdl": "gpio", # - # haptics - "ti_drv2605": "haptics", + # haptics/cirrus + "cirrus_cs40l5x": "haptics/cirrus", + # + # haptics/ti + "ti_drv2605": "haptics/ti", # # hdlc_rcp_if "nxp_hdlc_rcp_if": "hdlc_rcp_if", + "spi_hdlc_rcp_if": "hdlc_rcp_if", "uart_hdlc_rcp_if": "hdlc_rcp_if", # # hwinfo @@ -728,7 +1076,9 @@ "nxp_lpc_uid": "hwinfo", # # hwspinlock + "nxp_sema42": "hwspinlock", "sqn_hwspinlock": "hwspinlock", + "vnd_hwspinlock": "hwspinlock", # # i2c "adi_max32_i2c": "i2c", @@ -740,47 +1090,68 @@ "atmel_sam_i2c_twi": "i2c", "atmel_sam_i2c_twihs": "i2c", "atmel_sam_i2c_twim": "i2c", + "bflb_i2c": "i2c", "brcm_iproc_i2c": "i2c", + "cdns_i2c": "i2c", "ene_kb1200_i2c": "i2c", "espressif_esp32_i2c": "i2c", "fsl_imx21_i2c": "i2c", "gd_gd32_i2c": "i2c", "gpio_i2c": "i2c", "gpio_i2c_switch": "i2c", - "infineon_cat1_i2c": "i2c", + "infineon_i2c": "i2c", "infineon_xmc4xxx_i2c": "i2c", "intel_sedi_i2c": "i2c", "ite_enhance_i2c": "i2c", + "ite_it51xxx_i2c": "i2c", "ite_it8xxx2_i2c": "i2c", "litex_i2c": "i2c", + "litex_litei2c": "i2c", "microchip_mpfs_i2c": "i2c", + "microchip_sercom_g1_i2c": "i2c", "microchip_xec_i2c": "i2c", "microchip_xec_i2c_v2": "i2c", + "nordic_nrf_twi": "i2c", + "nordic_nrf_twim": "i2c", "nordic_nrf_twis": "i2c", "nuvoton_npcx_i2c_ctrl": "i2c", "nuvoton_npcx_i2c_port": "i2c", "nuvoton_numaker_i2c": "i2c", + "nxp_ii2c": "i2c", "nxp_kinetis_i2c": "i2c", "nxp_lpc11u6x_i2c": "i2c", "nxp_lpc_i2c": "i2c", "nxp_lpi2c": "i2c", "nxp_sc18im704_i2c": "i2c", "openisa_rv32m1_lpi2c": "i2c", + "realtek_rts5912_i2c": "i2c", + "renesas_ra_i2c_sci": "i2c", + "renesas_ra_i2c_sci_b": "i2c", "renesas_ra_iic": "i2c", "renesas_rcar_i2c": "i2c", + "renesas_rx_i2c": "i2c", + "renesas_rz_iic": "i2c", + "renesas_rz_riic": "i2c", + "renesas_rza2m_riic": "i2c", "renesas_smartbond_i2c": "i2c", + "sensry_sy1xx_i2c": "i2c", "sifive_i2c0": "i2c", + "sifli_sf32lb_i2c": "i2c", "silabs_gecko_i2c": "i2c", + "silabs_i2c": "i2c", + "snps_designware_i2c": "i2c", "st_stm32_i2c_v1": "i2c", "st_stm32_i2c_v2": "i2c", "telink_b91_i2c": "i2c", "ti_cc13xx_cc26xx_i2c": "i2c", + "ti_cc23x0_i2c": "i2c", "ti_cc32xx_i2c": "i2c", "ti_omap_i2c": "i2c", "ti_tca9544a": "i2c", "ti_tca9546a": "i2c", "ti_tca9548a": "i2c", "vnd_i2c": "i2c", + "wch_i2c": "i2c", "xlnx_xps_iic_2_00_a": "i2c", "xlnx_xps_iic_2_1": "i2c", "zephyr_i2c_emul_controller": "i2c", @@ -789,26 +1160,42 @@ "zephyr_i2c_target_eeprom": "i2c/target", # # i2s + "adi_max32_i2s": "i2s", + "ambiq_i2s": "i2s", "atmel_sam_ssc": "i2s", "espressif_esp32_i2s": "i2s", + "infineon_i2s": "i2s", + "nordic_nrf_i2s": "i2s", "nxp_lpc_i2s": "i2s", "nxp_mcux_i2s": "i2s", + "renesas_ra_i2s_ssie": "i2s", + "silabs_siwx91x_i2s": "i2s", "st_stm32_i2s": "i2s", + "st_stm32_sai": "i2s", "vnd_i2s": "i2s", + "zephyr_i2s_sdl": "i2s", # # i3c + "adi_max32_i3c": "i3c", "cdns_i3c": "i3c", + "ite_it51xxx_i3cm": "i3c", + "ite_it51xxx_i3cs": "i3c", "nuvoton_npcx_i3c": "i3c", "nxp_mcux_i3c": "i3c", + "renesas_ra_i3c": "i3c", + "snps_designware_i3c": "i3c", "st_stm32_i3c": "i3c", "vnd_i3c": "i3c", # # ieee802154 "atmel_rf2xx": "ieee802154", "decawave_dw1000": "ieee802154", + "espressif_esp32_ieee802154": "ieee802154", "nordic_nrf_ieee802154": "ieee802154", "nxp_kw41z_ieee802154": "ieee802154", "nxp_mcr20a": "ieee802154", + "nxp_mcxw_ieee802154": "ieee802154", + "st_stm32wba_ieee802154": "ieee802154", "telink_b91_zb": "ieee802154", "ti_cc1200": "ieee802154", "ti_cc13xx_cc26xx_ieee802154": "ieee802154", @@ -819,10 +1206,15 @@ # input "adc_keys": "input", "analog_axis": "input", + "arduino_modulino_buttons": "input", + "bflb_irx": "input", + "chipsemi_chsc5x": "input", "chipsemi_chsc6x": "input", "cirque_pinnacle": "input", + "cypress_cy8cmbr3xxx": "input", "espressif_esp32_touch": "input", "focaltech_ft5336": "input", + "focaltech_ft6146": "input", "futaba_sbus": "input", "goodix_gt911": "input", "gpio_kbd_matrix": "input", @@ -830,22 +1222,35 @@ "gpio_qdec": "input", "hynitron_cst816s": "input", "ilitek_ili2132a": "input", + "ite_it51xxx_kbd": "input", "ite_it8801_kbd": "input", "ite_it8xxx2_kbd": "input", "microchip_cap12xx": "input", "microchip_xec_kbd": "input", "nintendo_nunchuk": "input", "nuvoton_npcx_kbd": "input", + "nxp_mcux_kpp": "input", + "parade_tma525b": "input", "pixart_pat912x": "input", "pixart_paw32xx": "input", "pixart_pmw3610": "input", + "realtek_rts5912_kbd": "input", + "renesas_ra_ctsu": "input", + "renesas_ra_ctsu_button": "input", + "renesas_ra_ctsu_slider": "input", + "renesas_ra_ctsu_wheel": "input", + "renesas_rx_ctsu": "input", "sitronix_cf1133": "input", + "st_stm32_tsc": "input", "st_stmpe811": "input", + "vishay_vs1838b": "input", + "wch_ch9350l": "input", "xptek_xpt2046": "input", "zephyr_input_sdl_touch": "input", "zephyr_native_linux_evdev": "input", # # interrupt_controller + "adi_max32_rv32_intc": "interrupt_controller", "arm_gic_v1": "interrupt_controller", "arm_gic_v2": "interrupt_controller", "arm_gic_v3": "interrupt_controller", @@ -853,24 +1258,33 @@ "atmel_sam0_eic": "interrupt_controller", "gaisler_irqmp": "interrupt_controller", "gd_gd32_exti": "interrupt_controller", + "hazard3_hazard3_intc": "interrupt_controller", "infineon_xmc4xxx_intc": "interrupt_controller", "intel_ace_intc": "interrupt_controller", "intel_cavs_intc": "interrupt_controller", "intel_ioapic": "interrupt_controller", "intel_loapic": "interrupt_controller", "intel_vt_d": "interrupt_controller", + "ite_it51xxx_wuc": "interrupt_controller", "ite_it8xxx2_wuc": "interrupt_controller", "litex_vexriscv_intc0": "interrupt_controller", "mediatek_adsp_intc": "interrupt_controller", + "microchip_eic_g1_intc": "interrupt_controller", "microchip_xec_ecia": "interrupt_controller", "nuclei_eclic": "interrupt_controller", "nuvoton_npcx_miwu": "interrupt_controller", + "nxp_gint": "interrupt_controller", "nxp_irqsteer_intc": "interrupt_controller", "nxp_pint": "interrupt_controller", - "nxp_s32_siul2_eirq": "interrupt_controller", "nxp_s32_wkpu": "interrupt_controller", + "nxp_siul2_eirq": "interrupt_controller", "openisa_rv32m1_intmux": "interrupt_controller", - "renesas_ra_interrupt_controller_unit": "interrupt_controller", + "renesas_rx_grp_intc": "interrupt_controller", + "renesas_rx_icu": "interrupt_controller", + "renesas_rz_ext_irq": "interrupt_controller", + "renesas_rz_tint": "interrupt_controller", + "riscv_clic": "interrupt_controller", + "riscv_imsic": "interrupt_controller", "shared_irq": "interrupt_controller", "sifive_plic_1_0_0": "interrupt_controller", "snps_arcv2_intc": "interrupt_controller", @@ -878,6 +1292,7 @@ "st_stm32wb0_gpio_intc": "interrupt_controller", "swerv_pic": "interrupt_controller", "ti_vim": "interrupt_controller", + "wch_exti": "interrupt_controller", "wch_pfic": "interrupt_controller", # # ipm @@ -893,20 +1308,23 @@ "xlnx_zynqmp_ipi_mailbox": "ipm", "zephyr_mbox_ipm": "ipm", # - # kscan - "zephyr_kscan_input": "kscan", - # # led + "arduino_modulino_buttons_leds": "led", + "dac_leds": "led", "gpio_leds": "led", "holtek_ht16k33": "led", "issi_is31fl3194": "led", "issi_is31fl3216a": "led", "issi_is31fl3733": "led", + "leds_group_multicolor": "led", "microchip_xec_bbled": "led", "nordic_npm1300_led": "led", + "nordic_npm1304_led": "led", + "nxp_pca9533": "led", "nxp_pca9633": "led", "onnn_ncp5623": "led", "pwm_leds": "led", + "sct_sct2024": "led", "ti_lp3943": "led", "ti_lp5009": "led", "ti_lp5012": "led", @@ -920,6 +1338,7 @@ # # led_strip "apa_apa102": "led_strip", + "arduino_modulino_pixels": "led_strip", "greeled_lpd8803": "led_strip", "greeled_lpd8806": "led_strip", "ti_tlc5971": "led_strip", @@ -928,14 +1347,23 @@ "worldsemi_ws2812_i2s": "led_strip", "worldsemi_ws2812_rpi_pico_pio": "led_strip", "worldsemi_ws2812_spi": "led_strip", + "worldsemi_ws2812_uart": "led_strip", # # lora "reyax_rylrxxx": "lora", - "semtech_sx1272": "lora", - "semtech_sx1276": "lora", + # + # lora/loramac-node + "semtech_sx1272": "lora/loramac-node", + "semtech_sx1276": "lora/loramac-node", + # + # lora/native/sx126x + "semtech_sx1261": "lora/native/sx126x", + "semtech_sx1262": "lora/native/sx126x", + "st_stm32wl_subghz_radio": "lora/native/sx126x", # # mbox "andestech_mbox_plic_sw": "mbox", + "arm_mhuv3": "mbox", "espressif_mbox_esp32": "mbox", "linaro_ivshmem_mbox": "mbox", "nordic_mbox_nrf_ipc": "mbox", @@ -948,45 +1376,44 @@ "nxp_mbox_imx_mu": "mbox", "nxp_mbox_mailbox": "mbox", "nxp_s32_mru": "mbox", + "raspberrypi_pico_mbox": "mbox", + "renesas_ra_ipc_mbox": "mbox", + "renesas_rz_mhu_mbox": "mbox", "st_mbox_stm32_hsem": "mbox", - # - # mdio - "adi_adin2111_mdio": "mdio", - "atmel_sam_mdio": "mdio", - "espressif_esp32_mdio": "mdio", - "infineon_xmc4xxx_mdio": "mdio", - "litex_liteeth_mdio": "mdio", - "microchip_lan865x_mdio": "mdio", - "nxp_enet_mdio": "mdio", - "nxp_enet_qos_mdio": "mdio", - "nxp_imx_netc_emdio": "mdio", - "nxp_s32_gmac_mdio": "mdio", - "nxp_s32_netc_emdio": "mdio", - "renesas_ra_mdio": "mdio", - "smsc_lan91c111_mdio": "mdio", - "snps_dwcxgmac_mdio": "mdio", - "st_stm32_mdio": "mdio", - "zephyr_mdio_gpio": "mdio", + "ti_omap_mailbox": "mbox", + "ti_secure_proxy": "mbox", + "xlnx_mbox_versal_ipi_mailbox": "mbox", # # memc + "adi_max32_hpb": "memc", "atmel_sam_smc": "memc", + "bflb_bl61x_psram": "memc", "mspi_aps6404l": "memc", + "mspi_aps_z8": "memc", "nxp_imx_flexspi": "memc", + "nxp_imx_flexspi_is66wvs8m8": "memc", "nxp_imx_flexspi_s27ks0641": "memc", "nxp_imx_flexspi_w956a8mbya": "memc", "nxp_s32_qspi": "memc", + "nxp_s32_xspi": "memc", + "nxp_xspi": "memc", + "nxp_xspi_psram": "memc", "renesas_ra_sdram": "memc", "renesas_smartbond_nor_psram": "memc", "sifive_fu740_c000_ddr": "memc", + "silabs_siwx91x_qspi_memory": "memc", "st_stm32_fmc": "memc", "st_stm32_fmc_nor_psram": "memc", "st_stm32_fmc_sdram": "memc", + "st_stm32_ospi_psram": "memc", + "st_stm32_xspi_psram": "memc", "st_stm32h7_fmc": "memc", # # mfd "adi_ad559x": "mfd", "adi_adp5585": "mfd", "adi_max22017": "mfd", + "adi_maxq10xx": "mfd", "awinic_aw9523b": "mfd", "infineon_tle9104": "mfd", "ite_it8801_altctrl": "mfd", @@ -994,18 +1421,29 @@ "maxim_ds3231_mfd": "mfd", "maxim_max20335": "mfd", "maxim_max31790": "mfd", + "microchip_sam_flexcom": "mfd", + "microcrystal_rv3032_mfd": "mfd", + "motorola_mc146818_mfd": "mfd", "nordic_npm1300": "mfd", + "nordic_npm1304": "mfd", "nordic_npm2100": "mfd", "nordic_npm6001": "mfd", "nuvoton_nct38xx": "mfd", "nxp_lp_flexcomm": "mfd", + "nxp_pca9422": "mfd", + "nxp_pf1550": "mfd", + "nxp_sc18is606": "mfd", "rohm_bd8lb600fs": "mfd", - "x_powers_axp192": "mfd", # # mipi_dbi + "bflb_dbi": "mipi_dbi", + "espressif_esp32_lcd_cam_mipi_dbi": "mipi_dbi", "nxp_lcdic": "mipi_dbi", + "nxp_mipi_dbi_dcnano_lcdif": "mipi_dbi", "nxp_mipi_dbi_flexio_lcdif": "mipi_dbi", + "raspberrypi_pico_mipi_dbi_pio": "mipi_dbi", "renesas_smartbond_mipi_dbi": "mipi_dbi", + "sifli_sf32lb_lcdc_mipi_dbi": "mipi_dbi", "st_stm32_fmc_mipi_dbi": "mipi_dbi", "zephyr_mipi_dbi_bitbang": "mipi_dbi", "zephyr_mipi_dbi_spi": "mipi_dbi", @@ -1013,6 +1451,7 @@ # mipi_dsi "nxp_imx_mipi_dsi": "mipi_dsi", "nxp_mipi_dsi_2l": "mipi_dsi", + "nxp_mipi_dsi_dwc": "mipi_dsi", "renesas_ra_mipi_dsi": "mipi_dsi", "st_stm32_mipi_dsi": "mipi_dsi", "vnd_mipi_dsi": "mipi_dsi", @@ -1022,6 +1461,8 @@ # # misc/ethos_u "arm_ethos_u": "misc/ethos_u", + "nuvoton_numaker_npu": "misc/ethos_u", + "renesas_ra_npu": "misc/ethos_u", # # misc/ft8xx "ftdi_ft800": "misc/ft8xx", @@ -1029,12 +1470,22 @@ # misc/grove_lcd_rgb "seeed_grove_lcd_rgb": "misc/grove_lcd_rgb", # + # misc/interconn/renesas_elc + "renesas_ra_elc": "misc/interconn/renesas_elc", + # # misc/mcux_flexio "nxp_flexio": "misc/mcux_flexio", # # misc/nordic_vpr_launcher "nordic_nrf_vpr_coprocessor": "misc/nordic_vpr_launcher", # + # misc/nxp_imx93_mediamix + "nxp_imx93_mediamix": "misc/nxp_imx93_mediamix", + # + # misc/nxp_rtxxx_dsp_ctrl + "nxp_rt600_dsp_ctrl": "misc/nxp_rtxxx_dsp_ctrl", + "nxp_rt700_dsp_ctrl_hifi4": "misc/nxp_rtxxx_dsp_ctrl", + # # misc/nxp_s32_emios "nxp_s32_emios": "misc/nxp_s32_emios", # @@ -1044,20 +1495,32 @@ # misc/renesas_ra_external_interrupt "renesas_ra_external_interrupt": "misc/renesas_ra_external_interrupt", # + # misc/renesas_rx_dtc + "renesas_rx_dtc": "misc/renesas_rx_dtc", + # + # misc/renesas_rx_external_interrupt + "renesas_rx_external_interrupt": "misc/renesas_rx_external_interrupt", + # + # misc/stm32n6_axisram + "st_stm32n6_ramcfg": "misc/stm32n6_axisram", + # # misc/timeaware_gpio "intel_timeaware_gpio": "misc/timeaware_gpio", # # mm + "intel_adsp_mtl_tlb": "mm", "intel_adsp_tlb": "mm", # # modem "nordic_nrf91_slm": "modem", "quectel_bg95": "modem", + "quectel_bg96": "modem", "quectel_bg9x": "modem", "quectel_eg25_g": "modem", - "simcom_sim7080": "modem", + "quectel_eg800q": "modem", + "simcom_a76xx": "modem", "sqn_gm02s": "modem", - "swir_hl7800": "modem", + "st_st87mxx": "modem", "telit_me310g1": "modem", "telit_me910g1": "modem", "u_blox_lara_r6": "modem", @@ -1065,10 +1528,36 @@ "u_blox_sara_r5": "modem", "wnc_m14a2a": "modem", # + # modem/hl78xx + "swir_hl7800": "modem/hl78xx", + "swir_hl7800_gnss": "modem/hl78xx", + "swir_hl7800_offload": "modem/hl78xx", + "swir_hl7812": "modem/hl78xx", + "swir_hl7812_gnss": "modem/hl78xx", + "swir_hl7812_offload": "modem/hl78xx", + # + # modem/simcom/sim7080 + "simcom_sim7080": "modem/simcom/sim7080", + # # mspi "ambiq_mspi_controller": "mspi", + "snps_designware_ssi": "mspi", + "st_stm32_ospi_controller": "mspi", + "st_stm32_qspi_controller": "mspi", + "st_stm32_xspi_controller": "mspi", "zephyr_mspi_emul_controller": "mspi", # + # opamp + "nxp_opamp": "opamp", + "nxp_opamp_fast": "opamp", + "st_stm32_opamp": "opamp", + # + # otp + "nxp_ocotp": "otp", + "sifli_sf32lb_efuse": "otp", + "st_stm32_bsec": "otp", + "zephyr_otp_emul": "otp", + # # pcie/controller "brcm_brcmstb_pcie": "pcie/controller", # @@ -1086,10 +1575,12 @@ "nuvoton_npcx_peci": "peci", # # pinctrl + "alif_pinctrl": "pinctrl", + "brcm_bcm2711_pinctrl": "pinctrl", + "ene_kb106x_pinctrl": "pinctrl", "ene_kb1200_pinctrl": "pinctrl", "infineon_xmc4xxx_pinctrl": "pinctrl", "ite_it8xxx2_pinctrl_func": "pinctrl", - "microchip_mec5_pinctrl": "pinctrl", "microchip_xec_pinctrl": "pinctrl", "nuvoton_numaker_pinctrl": "pinctrl", "nuvoton_numicro_pinctrl": "pinctrl", @@ -1099,12 +1590,19 @@ "realtek_rts5912_pinctrl": "pinctrl", "sensry_sy1xx_pinctrl": "pinctrl", "sifive_pinctrl": "pinctrl", + "sifli_sf32lb52x_pinmux": "pinctrl", "silabs_dbus_pinctrl": "pinctrl", + "silabs_siwx91x_pinctrl": "pinctrl", "snps_emsdp_pinctrl": "pinctrl", "telink_b91_pinctrl": "pinctrl", "ti_cc13xx_cc26xx_pinctrl": "pinctrl", + "ti_cc23x0_pinctrl": "pinctrl", "ti_cc32xx_pinctrl": "pinctrl", "ti_k3_pinctrl": "pinctrl", + "ti_mspm0_pinctrl": "pinctrl", + "wch_00x_afio": "pinctrl", + "wch_20x_30x_afio": "pinctrl", + "wch_afio": "pinctrl", "xlnx_pinctrl_zynq": "pinctrl", "xlnx_pinctrl_zynqmp": "pinctrl", # @@ -1112,46 +1610,69 @@ "renesas_rcar_pfc": "pinctrl/renesas/rcar", # # pinctrl/renesas/rz + "renesas_rza2m_pinctrl": "pinctrl/renesas/rz", "renesas_rzt2m_pinctrl": "pinctrl/renesas/rz", # # pm_cpu_ops + "arm_fvp_pwrc": "pm_cpu_ops", "arm_psci_0_2": "pm_cpu_ops", "arm_psci_1_1": "pm_cpu_ops", # # power_domain + "arm_scmi_power_domain": "power_domain", "intel_adsp_power_domain": "power_domain", + "nordic_nrfs_gdpwr": "power_domain", + "nordic_nrfs_swext": "power_domain", "nxp_scu_pd": "power_domain", "power_domain_gpio": "power_domain", "power_domain_gpio_monitor": "power_domain", + "power_domain_soc_state_change": "power_domain", + "silabs_siwx91x_power_domain": "power_domain", + "ti_sci_pm_domain": "power_domain", # # ps2 + "ite_it51xxx_ps2": "ps2", "microchip_xec_ps2": "ps2", "nuvoton_npcx_ps2_channel": "ps2", "nuvoton_npcx_ps2_ctrl": "ps2", # + # psi5 + "nxp_s32_psi5": "psi5", + # # ptp_clock "nxp_enet_ptp_clock": "ptp_clock", + "nxp_netc_ptp_clock": "ptp_clock", # # pwm "adi_max32_pwm": "pwm", + "ambiq_ctimer_pwm": "pwm", + "ambiq_timer_pwm": "pwm", "atmel_sam0_tc_pwm": "pwm", "atmel_sam0_tcc_pwm": "pwm", "atmel_sam_pwm": "pwm", + "bflb_pwm_1": "pwm", + "bflb_pwm_2": "pwm", + "ene_kb106x_pwm": "pwm", "ene_kb1200_pwm": "pwm", "espressif_esp32_ledc": "pwm", "espressif_esp32_mcpwm": "pwm", "fsl_imx27_pwm": "pwm", "gd_gd32_pwm": "pwm", - "infineon_cat1_pwm": "pwm", + "infineon_tcpwm_pwm": "pwm", "infineon_xmc4xxx_ccu4_pwm": "pwm", "infineon_xmc4xxx_ccu8_pwm": "pwm", "intel_blinky_pwm": "pwm", + "ite_it51xxx_pwm": "pwm", "ite_it8801_pwm": "pwm", "ite_it8xxx2_pwm": "pwm", "litex_pwm": "pwm", "maxim_max31790_pwm": "pwm", + "microchip_tc_g1_pwm": "pwm", + "microchip_tcc_g1_pwm": "pwm", "microchip_xec_pwm": "pwm", "microchip_xec_pwmbbled": "pwm", + "neorv32_pwm": "pwm", + "nordic_nrf_pwm": "pwm", "nordic_nrf_sw_pwm": "pwm", "nuvoton_npcx_pwm": "pwm", "nuvoton_numaker_pwm": "pwm", @@ -1167,14 +1688,27 @@ "nxp_sctimer_pwm": "pwm", "openisa_rv32m1_tpm": "pwm", "raspberrypi_pico_pwm": "pwm", + "realtek_rts5912_pwm": "pwm", "renesas_pwm_rcar": "pwm", "renesas_ra_pwm": "pwm", + "renesas_rx_mtu_pwm": "pwm", + "renesas_rz_gpt_pwm": "pwm", + "renesas_rz_mtu_pwm": "pwm", + "renesas_rza2m_gpt_pwm": "pwm", "sifive_pwm0": "pwm", + "sifli_sf32lb_atim_pwm": "pwm", + "sifli_sf32lb_gpt_pwm": "pwm", "silabs_gecko_pwm": "pwm", + "silabs_letimer_pwm": "pwm", + "silabs_siwx91x_pwm": "pwm", + "silabs_timer_pwm": "pwm", "st_stm32_pwm": "pwm", "telink_b91_pwm": "pwm", "ti_cc13xx_cc26xx_timer_pwm": "pwm", + "ti_cc23x0_lgpt_pwm": "pwm", + "ti_mspm0_timer_pwm": "pwm", "vnd_pwm": "pwm", + "wch_gptm_pwm": "pwm", "xlnx_xps_timer_1_00_a_pwm": "pwm", "zephyr_fake_pwm": "pwm", # @@ -1185,70 +1719,110 @@ "mps_mpm54304": "regulator", "nordic_npm1100": "regulator", "nordic_npm1300_regulator": "regulator", + "nordic_npm1304_regulator": "regulator", "nordic_npm2100_regulator": "regulator", "nordic_npm6001_regulator": "regulator", "nxp_pca9420": "regulator", + "nxp_pca9422_regulator": "regulator", + "nxp_pf1550_regulator": "regulator", "nxp_vref": "regulator", + "nxp_vrefv1": "regulator", "raspberrypi_core_supply_regulator": "regulator", "regulator_fixed": "regulator", "regulator_gpio": "regulator", "renesas_smartbond_regulator": "regulator", - "x_powers_axp192_regulator": "regulator", + "st_stm32_vrefbuf": "regulator", + "ti_tps55287": "regulator", "zephyr_fake_regulator": "regulator", # # reset "aspeed_ast10x0_reset": "reset", + "focaltech_ft9001_cpm_rctl": "reset", "gd_gd32_rctl": "reset", "intel_socfpga_reset": "reset", + "microchip_mpfs_reset": "reset", + "microchip_rstc_g1_reset": "reset", "nuvoton_npcx_rst": "reset", "nuvoton_numaker_rst": "reset", "nxp_lpc_syscon_reset": "reset", + "nxp_mrcc_reset": "reset", "nxp_rstctl": "reset", "raspberrypi_pico_reset": "reset", + "realtek_rts5817_reset": "reset", + "reset_mmio": "reset", + "sifli_sf32lb_rcc_rctl": "reset", "st_stm32_rcc_rctl": "reset", # # retained_mem "nordic_nrf_gpregret": "retained_mem", + "silabs_buram": "retained_mem", "zephyr_retained_ram": "retained_mem", "zephyr_retained_reg": "retained_mem", # # rtc + "adi_max31331": "rtc", "ambiq_am1805": "rtc", "ambiq_rtc": "rtc", "atmel_sam_rtc": "rtc", - "infineon_cat1_rtc": "rtc", + "epson_rx8130ce_rtc": "rtc", + "infineon_rtc": "rtc", "infineon_xmc4xxx_rtc": "rtc", + "maxim_ds1302": "rtc", "maxim_ds1307": "rtc", + "maxim_ds1337": "rtc", "maxim_ds3231_rtc": "rtc", + "microchip_rtc_g1": "rtc", + "microchip_rtc_g2": "rtc", "microcrystal_rv3028": "rtc", + "microcrystal_rv3032": "rtc", "microcrystal_rv8803": "rtc", "microcrystal_rv_8263_c8": "rtc", "motorola_mc146818": "rtc", "nuvoton_numaker_rtc": "rtc", "nxp_irtc": "rtc", + "nxp_pcf2123": "rtc", + "nxp_pcf85063a": "rtc", "nxp_pcf8523": "rtc", "nxp_pcf8563": "rtc", "raspberrypi_pico_rtc": "rtc", + "realtek_rts5912_rtc": "rtc", + "renesas_ra_rtc": "rtc", "renesas_smartbond_rtc": "rtc", + "sifli_sf32lb_rtc": "rtc", + "silabs_siwx91x_rtc": "rtc", "st_stm32_rtc": "rtc", + "ti_bq32002": "rtc", + "ti_mspm0_rtc": "rtc", "zephyr_fake_rtc": "rtc", + "zephyr_rtc_counter": "rtc", "zephyr_rtc_emul": "rtc", # # sdhc + "adi_max32_sdhc": "sdhc", + "ambiq_sdio": "sdhc", "atmel_sam_hsmci": "sdhc", "cdns_sdhc": "sdhc", "espressif_esp32_sdhc_slot": "sdhc", - "infineon_cat1_sdhc_sdio": "sdhc", + "infineon_sdhc_sdio": "sdhc", "intel_emmc_host": "sdhc", + "microchip_sama7g5_sdmmc": "sdhc", "nxp_imx_usdhc": "sdhc", "nxp_lpc_sdif": "sdhc", "renesas_ra_sdhc": "sdhc", "renesas_rcar_mmc": "sdhc", + "st_stm32_sdio": "sdhc", + "xlnx_versal_8_9a": "sdhc", "zephyr_sdhc_spi_slot": "sdhc", # # sensor/a01nyub "dfrobot_a01nyub": "sensor/a01nyub", # + # sensor/adi/ad2s1210 + "adi_ad2s1210": "sensor/adi/ad2s1210", + # + # sensor/adi/ade7978 + "adi_ade7978": "sensor/adi/ade7978", + # # sensor/adi/adltc2990 "adi_adltc2990": "sensor/adi/adltc2990", # @@ -1271,12 +1845,24 @@ # sensor/adi/adxl372 "adi_adxl372": "sensor/adi/adxl372", # + # sensor/adi/max30210 + "adi_max30210": "sensor/adi/max30210", + # + # sensor/adi/max32664c + "maxim_max32664c": "sensor/adi/max32664c", + # + # sensor/als31300 + "allegro_als31300": "sensor/als31300", + # # sensor/amd_sb_tsi "amd_sb_tsi": "sensor/amd_sb_tsi", # # sensor/amg88xx "panasonic_amg88xx": "sensor/amg88xx", # + # sensor/ams/ams_as5048 + "ams_as5048": "sensor/ams/ams_as5048", + # # sensor/ams/ams_as5600 "ams_as5600": "sensor/ams/ams_as5600", # @@ -1339,6 +1925,12 @@ # sensor/bosch/bmc150_magn "bosch_bmc150_magn": "sensor/bosch/bmc150_magn", # + # sensor/bosch/bme280 + "bosch_bme280": "sensor/bosch/bme280", + # + # sensor/bosch/bme680 + "bosch_bme680": "sensor/bosch/bme680", + # # sensor/bosch/bmg160 "bosch_bmg160": "sensor/bosch/bmg160", # @@ -1355,6 +1947,12 @@ # sensor/bosch/bmi323 "bosch_bmi323": "sensor/bosch/bmi323", # + # sensor/bosch/bmm150 + "bosch_bmm150": "sensor/bosch/bmm150", + # + # sensor/bosch/bmm350 + "bosch_bmm350": "sensor/bosch/bmm350", + # # sensor/bosch/bmp180 "bosch_bmp180": "sensor/bosch/bmp180", # @@ -1362,6 +1960,12 @@ "bosch_bmp388": "sensor/bosch/bmp388", "bosch_bmp390": "sensor/bosch/bmp388", # + # sensor/bosch/bmp581 + "bosch_bmp581": "sensor/bosch/bmp581", + # + # sensor/broadcom/afbr_s50 + "brcm_afbr_s50": "sensor/broadcom/afbr_s50", + # # sensor/current_amp "current_sense_amplifier": "sensor/current_amp", # @@ -1377,6 +1981,9 @@ # sensor/espressif/pcnt_esp32 "espressif_esp32_pcnt": "sensor/espressif/pcnt_esp32", # + # sensor/everlight/als_pt19 + "everlight_als_pt19": "sensor/everlight/als_pt19", + # # sensor/explorir_m "gss_explorir_m": "sensor/explorir_m", # @@ -1414,6 +2021,12 @@ # sensor/infineon/xmc4xxx_temp "infineon_xmc4xxx_temp": "sensor/infineon/xmc4xxx_temp", # + # sensor/ist8310 + "isentek_ist8310": "sensor/ist8310", + # + # sensor/ite/ite_tach_it51xxx + "ite_it51xxx_tach": "sensor/ite/ite_tach_it51xxx", + # # sensor/ite/ite_tach_it8xxx2 "ite_it8xxx2_tach": "sensor/ite/ite_tach_it8xxx2", # @@ -1423,6 +2036,9 @@ # sensor/jedec/jc42 "jedec_jc_42_4_temp": "sensor/jedec/jc42", # + # sensor/liteon/ltrf216a + "liteon_ltrf216a": "sensor/liteon/ltrf216a", + # # sensor/lm35 "lm35": "sensor/lm35", # @@ -1432,9 +2048,6 @@ # sensor/lm77 "lm77": "sensor/lm77", # - # sensor/ltrf216a - "ltr_f216a": "sensor/ltrf216a", - # # sensor/maxim/ds18b20 "maxim_ds18b20": "sensor/maxim/ds18b20", "maxim_ds18s20": "sensor/maxim/ds18b20", @@ -1458,6 +2071,9 @@ # sensor/maxim/max31855 "maxim_max31855": "sensor/maxim/max31855", # + # sensor/maxim/max31865 + "maxim_max31865": "sensor/maxim/max31865", + # # sensor/maxim/max31875 "maxim_max31875": "sensor/maxim/max31875", # @@ -1467,11 +2083,15 @@ # sensor/maxim/max6675 "maxim_max6675": "sensor/maxim/max6675", # + # sensor/mb7040 + "maxbotix_mb7040": "sensor/mb7040", + # # sensor/meas/ms5607 "meas_ms5607": "sensor/meas/ms5607", # # sensor/meas/ms5837 - "meas_ms5837": "sensor/meas/ms5837", + "meas_ms5837_02ba": "sensor/meas/ms5837", + "meas_ms5837_30ba": "sensor/meas/ms5837", # # sensor/melexis/mlx90394 "melexis_mlx90394": "sensor/melexis/mlx90394", @@ -1479,6 +2099,9 @@ # sensor/memsic/mc3419 "memsic_mc3419": "sensor/memsic/mc3419", # + # sensor/memsic/mmc56x3 + "memsic_mmc56x3": "sensor/memsic/mmc56x3", + # # sensor/mhz19b "winsen_mhz19b": "sensor/mhz19b", # @@ -1491,14 +2114,18 @@ # sensor/microchip/mcp970x "microchip_mcp970x": "sensor/microchip/mcp970x", # + # sensor/microchip/mtch9010 + "microchip_mtch9010": "sensor/microchip/mtch9010", + # # sensor/microchip/tcn75a "microchip_tcn75a": "sensor/microchip/tcn75a", # # sensor/nct75 "onnn_nct75": "sensor/nct75", # - # sensor/nordic/npm1300_charger - "nordic_npm1300_charger": "sensor/nordic/npm1300_charger", + # sensor/nordic/npm13xx_charger + "nordic_npm1300_charger": "sensor/nordic/npm13xx_charger", + "nordic_npm1304_charger": "sensor/nordic/npm13xx_charger", # # sensor/nordic/npm2100_vbat "nordic_npm2100_vbat": "sensor/nordic/npm2100_vbat", @@ -1520,6 +2147,9 @@ # sensor/nuvoton/nuvoton_adc_cmp_npcx "nuvoton_adc_cmp": "sensor/nuvoton/nuvoton_adc_cmp_npcx", # + # sensor/nuvoton/nuvoton_adc_v2t_npcx + "nuvoton_npcx_adc_v2t": "sensor/nuvoton/nuvoton_adc_v2t_npcx", + # # sensor/nuvoton/nuvoton_tach_npcx "nuvoton_npcx_tach": "sensor/nuvoton/nuvoton_tach_npcx", # @@ -1541,9 +2171,21 @@ # sensor/nxp/nxp_kinetis_temp "nxp_kinetis_temperature": "sensor/nxp/nxp_kinetis_temp", # + # sensor/nxp/nxp_lpadc_temp40 + "nxp_lpadc_temp40": "sensor/nxp/nxp_lpadc_temp40", + # + # sensor/nxp/nxp_pmc_tmpsns + "nxp_pmc_tmpsns": "sensor/nxp/nxp_pmc_tmpsns", + # # sensor/nxp/nxp_tempmon "nxp_tempmon": "sensor/nxp/nxp_tempmon", # + # sensor/nxp/nxp_tempsense + "nxp_tempsense": "sensor/nxp/nxp_tempsense", + # + # sensor/nxp/nxp_tmpsns + "nxp_tmpsns": "sensor/nxp/nxp_tmpsns", + # # sensor/nxp/p3t1755 "nxp_p3t1755": "sensor/nxp/p3t1755", # @@ -1553,12 +2195,40 @@ # sensor/nxp/qdec_nxp_s32 "nxp_qdec_s32": "sensor/nxp/qdec_nxp_s32", # + # sensor/nxp/qdec_tpm + "nxp_tpm_qdec": "sensor/nxp/qdec_tpm", + # + # sensor/omron/2smpb_02e + "omron_2smpb_02e": "sensor/omron/2smpb_02e", + # + # sensor/omron/d6f + "omron_d6f_p0001": "sensor/omron/d6f", + "omron_d6f_p0010": "sensor/omron/d6f", + # + # sensor/pixart/paa3905 + "pixart_paa3905": "sensor/pixart/paa3905", + # + # sensor/pixart/paj7620 + "pixart_paj7620": "sensor/pixart/paj7620", + # + # sensor/pixart/pat9136 + "pixart_pat9136": "sensor/pixart/pat9136", + # # sensor/pms7003 "plantower_pms7003": "sensor/pms7003", # + # sensor/pni/rm3100 + "pni_rm3100": "sensor/pni/rm3100", + # + # sensor/pzem004t + "peacefair_pzem004t": "sensor/pzem004t", + # # sensor/qdec_sam "atmel_sam_tc_qdec": "sensor/qdec_sam", # + # sensor/realtek/rts5912 + "realtek_rts5912_tach": "sensor/realtek/rts5912", + # # sensor/renesas/hs300x "renesas_hs300x": "sensor/renesas/hs300x", # @@ -1571,12 +2241,21 @@ # sensor/rohm/bd8lb600fs "rohm_bd8lb600fs_diagnostics": "sensor/rohm/bd8lb600fs", # + # sensor/rohm/bh1730 + "rohm_bh1730": "sensor/rohm/bh1730", + # # sensor/rohm/bh1750 "rohm_bh1750": "sensor/rohm/bh1750", # + # sensor/rohm/bh1790 + "rohm_bh1790": "sensor/rohm/bh1790", + # # sensor/rpi_pico_temp "raspberrypi_pico_temp": "sensor/rpi_pico_temp", # + # sensor/rv3032_temp + "microcrystal_rv3032_temp": "sensor/rv3032_temp", + # # sensor/s11059 "hamamatsu_s11059": "sensor/s11059", # @@ -1606,6 +2285,9 @@ # sensor/sensirion/sts4x "sensirion_sts4x": "sensor/sensirion/sts4x", # + # sensor/sifli/sf32lb_tsen + "sifli_sf32lb_tsen": "sensor/sifli/sf32lb_tsen", + # # sensor/silabs/si7006 "sensirion_sht21": "sensor/silabs/si7006", "silabs_si7006": "sensor/silabs/si7006", @@ -1643,6 +2325,9 @@ # sensor/st/iis3dhhc "st_iis3dhhc": "sensor/st/iis3dhhc", # + # sensor/st/iis3dwb + "st_iis3dwb": "sensor/st/iis3dwb", + # # sensor/st/ism330dhcx "st_ism330dhcx": "sensor/st/ism330dhcx", # @@ -1702,7 +2387,16 @@ "st_lsm6dso16is": "sensor/st/lsm6dso16is", # # sensor/st/lsm6dsv16x + "DT_DRV_COMPAT_LSM6DSV16X": "sensor/st/lsm6dsv16x", + "DT_DRV_COMPAT_LSM6DSV32X": "sensor/st/lsm6dsv16x", "st_lsm6dsv16x": "sensor/st/lsm6dsv16x", + "st_lsm6dsv32x": "sensor/st/lsm6dsv16x", + # + # sensor/st/lsm6dsvxxx + "st_ism6hg256x": "sensor/st/lsm6dsvxxx", + "st_lsm6dsv320x": "sensor/st/lsm6dsvxxx", + "st_lsm6dsv80x": "sensor/st/lsm6dsvxxx", + "st_lsm6dsvxxx": "sensor/st/lsm6dsvxxx", # # sensor/st/lsm9ds0_gyro "st_lsm9ds0_gyro": "sensor/st/lsm9ds0_gyro", @@ -1713,6 +2407,9 @@ # sensor/st/lsm9ds1 "st_lsm9ds1": "sensor/st/lsm9ds1", # + # sensor/st/lsm9ds1_mag + "st_lsm9ds1_mag": "sensor/st/lsm9ds1_mag", + # # sensor/st/qdec_stm32 "st_stm32_qdec": "sensor/st/qdec_stm32", # @@ -1745,18 +2442,36 @@ # sensor/sx9500 "semtech_sx9500": "sensor/sx9500", # + # sensor/tach_gpio + "zephyr_tach_gpio": "sensor/tach_gpio", + # + # sensor/tdk/icm40627 + "invensense_icm40627": "sensor/tdk/icm40627", + # # sensor/tdk/icm42605 "invensense_icm42605": "sensor/tdk/icm42605", # - # sensor/tdk/icm42670 - "invensense_icm42670p": "sensor/tdk/icm42670", - "invensense_icm42670s": "sensor/tdk/icm42670", + # sensor/tdk/icm4268x + "invensense_icm42688": "sensor/tdk/icm4268x", + "invensense_icm4268x": "sensor/tdk/icm4268x", # - # sensor/tdk/icm42688 - "invensense_icm42688": "sensor/tdk/icm42688", + # sensor/tdk/icm42x70 + "invensense_icm42370p": "sensor/tdk/icm42x70", + "invensense_icm42670p": "sensor/tdk/icm42x70", + "invensense_icm42670s": "sensor/tdk/icm42x70", # - # sensor/tdk/icp10125 - "invensense_icp10125": "sensor/tdk/icp10125", + # sensor/tdk/icm45686 + "invensense_icm45605": "sensor/tdk/icm45686", + "invensense_icm45605s": "sensor/tdk/icm45686", + "invensense_icm45686": "sensor/tdk/icm45686", + "invensense_icm45686s": "sensor/tdk/icm45686", + "invensense_icm45688p": "sensor/tdk/icm45686", + # + # sensor/tdk/icp101xx + "invensense_icp101xx": "sensor/tdk/icp101xx", + # + # sensor/tdk/icp201xx + "invensense_icp201xx": "sensor/tdk/icp201xx", # # sensor/tdk/mpu6050 "invensense_mpu6050": "sensor/tdk/mpu6050", @@ -1776,26 +2491,34 @@ # sensor/ti/ina219 "ti_ina219": "sensor/ti/ina219", # - # sensor/ti/ina226 - "ti_ina226": "sensor/ti/ina226", - # - # sensor/ti/ina23x - "ti_ina230": "sensor/ti/ina23x", - "ti_ina236": "sensor/ti/ina23x", - "ti_ina237": "sensor/ti/ina23x", + # sensor/ti/ina2xx + "ti_ina226": "sensor/ti/ina2xx", + "ti_ina228": "sensor/ti/ina2xx", + "ti_ina230": "sensor/ti/ina2xx", + "ti_ina232": "sensor/ti/ina2xx", + "ti_ina236": "sensor/ti/ina2xx", + "ti_ina237": "sensor/ti/ina2xx", # # sensor/ti/ina3221 "ti_ina3221": "sensor/ti/ina3221", # + # sensor/ti/ina7xx + "ti_ina7xx": "sensor/ti/ina7xx", + # # sensor/ti/lm95234 "national_lm95234": "sensor/ti/lm95234", # - # sensor/ti/opt3001 - "ti_opt3001": "sensor/ti/opt3001", + # sensor/ti/opt300x + "ti_opt3001": "sensor/ti/opt300x", + "ti_opt3004": "sensor/ti/opt300x", + "ti_opt300x": "sensor/ti/opt300x", # # sensor/ti/ti_hdc "ti_hdc": "sensor/ti/ti_hdc", # + # sensor/ti/ti_hdc302x + "ti_hdc302x": "sensor/ti/ti_hdc302x", + # # sensor/ti/tmag5170 "ti_tmag5170": "sensor/ti/tmag5170", # @@ -1807,6 +2530,7 @@ # # sensor/ti/tmp108 "ams_as6212": "sensor/ti/tmp108", + "ams_as6221": "sensor/ti/tmp108", "ti_tmp108": "sensor/ti/tmp108", # # sensor/ti/tmp112 @@ -1815,8 +2539,11 @@ # sensor/ti/tmp114 "ti_tmp114": "sensor/ti/tmp114", # - # sensor/ti/tmp116 - "ti_tmp116": "sensor/ti/tmp116", + # sensor/ti/tmp11x + "ti_tmp11x": "sensor/ti/tmp11x", + # + # sensor/ti/tmp435 + "ti_tmp435": "sensor/ti/tmp435", # # sensor/tsic_xx6 "ist_tsic_xx6": "sensor/tsic_xx6", @@ -1830,6 +2557,12 @@ # sensor/vishay/vcnl4040 "vishay_vcnl4040": "sensor/vishay/vcnl4040", # + # sensor/vishay/veml6031 + "vishay_veml6031": "sensor/vishay/veml6031", + # + # sensor/vishay/veml6046 + "vishay_veml6046": "sensor/vishay/veml6046", + # # sensor/vishay/veml7700 "vishay_veml7700": "sensor/vishay/veml7700", # @@ -1839,37 +2572,65 @@ # sensor/wsen/wsen_hids_2525020210002 "we_wsen_hids_2525020210002": "sensor/wsen/wsen_hids_2525020210002", # + # sensor/wsen/wsen_isds_2536030320001 + "we_wsen_isds_2536030320001": "sensor/wsen/wsen_isds_2536030320001", + # + # sensor/wsen/wsen_itds_2533020201601 + "we_wsen_itds_2533020201601": "sensor/wsen/wsen_itds_2533020201601", + # + # sensor/wsen/wsen_pads_2511020213301 + "we_wsen_pads_2511020213301": "sensor/wsen/wsen_pads_2511020213301", + # + # sensor/wsen/wsen_pdms_25131308XXX05 + "we_wsen_pdms_25131308xxx05": "sensor/wsen/wsen_pdms_25131308XXX05", + # # sensor/wsen/wsen_pdus_25131308XXXXX "we_wsen_pdus_25131308xxxxx": "sensor/wsen/wsen_pdus_25131308XXXXX", # + # sensor/wsen/wsen_tids_2521020222501 + "we_wsen_tids_2521020222501": "sensor/wsen/wsen_tids_2521020222501", + # + # sensor/xbr818 + "phosense_xbr818": "sensor/xbr818", + # + # sent + "nxp_s32_sent": "sent", + # # serial "SBSA_COMPAT": "serial", "adi_max32_uart": "serial", + "aesc_uart": "serial", "altr_jtag_uart": "serial", "altr_uart": "serial", + "ambiq_uart": "serial", "arm_cmsdk_uart": "serial", "arm_pl011": "serial", "atmel_sam0_uart": "serial", "atmel_sam_uart": "serial", "atmel_sam_usart": "serial", + "bflb_uart": "serial", "brcm_bcm2711_aux_uart": "serial", "cdns_uart": "serial", "cypress_psoc6_uart": "serial", "efinix_sapphire_uart0": "serial", + "ene_kb106x_uart": "serial", "ene_kb1200_uart": "serial", + "espressif_esp32_lpuart": "serial", "espressif_esp32_uart": "serial", "espressif_esp32_usb_serial": "serial", + "focaltech_ft9001_usart": "serial", "gaisler_apbuart": "serial", "gd_gd32_usart": "serial", - "infineon_cat1_uart": "serial", + "infineon_uart": "serial", "infineon_xmc4xxx_uart": "serial", "intel_lw_uart": "serial", "intel_sedi_uart": "serial", + "ite_it51xxx_uart": "serial", "ite_it8xxx2_uart": "serial", "litex_uart": "serial", "lowrisc_opentitan_uart": "serial", "microchip_coreuart": "serial", - "microchip_mec5_uart": "serial", + "microchip_sercom_g1_uart": "serial", "microchip_xec_uart": "serial", "neorv32_uart": "serial", "nordic_nrf_uart": "serial", @@ -1888,38 +2649,51 @@ "openisa_rv32m1_lpuart": "serial", "quicklogic_usbserialport_s3b": "serial", "raspberrypi_pico_uart_pio": "serial", + "realtek_ameba_loguart": "serial", + "realtek_bee_uart": "serial", "realtek_rts5912_uart": "serial", "renesas_ra8_uart_sci_b": "serial", "renesas_ra_sci_uart": "serial", - "renesas_ra_uart_sci": "serial", "renesas_rcar_hscif": "serial", "renesas_rcar_scif": "serial", + "renesas_rx_uart_sci": "serial", + "renesas_rx_uart_sci_qemu": "serial", + "renesas_rz_sci_b_uart": "serial", + "renesas_rz_sci_uart": "serial", "renesas_rz_scif_uart": "serial", + "renesas_rza2m_scif_uart": "serial", "renesas_rzt2m_uart": "serial", "renesas_smartbond_uart": "serial", "segger_rtt_uart": "serial", "sensry_sy1xx_uart": "serial", "sifive_uart0": "serial", + "sifli_sf32lb_usart": "serial", "silabs_eusart_uart": "serial", "silabs_gecko_leuart": "serial", "silabs_gecko_uart": "serial", "silabs_gecko_usart": "serial", "silabs_si32_usart": "serial", + "silabs_usart_uart": "serial", "snps_hostlink_uart": "serial", "st_stm32_uart": "serial", "telink_b91_uart": "serial", "ti_cc13xx_cc26xx_uart": "serial", + "ti_cc23x0_uart": "serial", "ti_cc32xx_uart": "serial", "ti_msp432p4xx_uart": "serial", + "ti_mspm0_uart": "serial", "ti_stellaris_uart": "serial", + "virtio_console": "serial", "vnd_serial": "serial", "wch_usart": "serial", "xen_hvc_consoleio": "serial", "xlnx_xps_uartlite_1_00_a": "serial", "xlnx_xuartps": "serial", - "zephyr_native_posix_uart": "serial", + "zephyr_native_pty_uart": "serial", "zephyr_native_tty_uart": "serial", "zephyr_nus_uart": "serial", + "zephyr_uart_bitbang": "serial", + "zephyr_uart_bridge": "serial", "zephyr_uart_emul": "serial", # # sip_svc @@ -1938,22 +2712,29 @@ "arm_pl022": "spi", "atmel_sam0_spi": "spi", "atmel_sam_spi": "spi", + "bflb_spi": "spi", + "cdns_spi": "spi", "cypress_psoc6_spi": "spi", + "egis_et171_spi": "spi", "espressif_esp32_spi": "spi", "gaisler_spimctrl": "spi", "gd_gd32_spi": "spi", - "infineon_cat1_spi": "spi", + "infineon_spi": "spi", "infineon_xmc4xxx_spi": "spi", "intel_penwell_spi": "spi", "intel_sedi_spi": "spi", + "ite_it51xxx_spi": "spi", "ite_it8xxx2_spi": "spi", "litex_spi": "spi", "litex_spi_litespi": "spi", "lowrisc_opentitan_spi": "spi", "microchip_mpfs_qspi": "spi", "microchip_mpfs_spi": "spi", + "microchip_sercom_g1_spi": "spi", "microchip_xec_qmspi": "spi", "microchip_xec_qmspi_ldma": "spi", + "nordic_nrf_spi": "spi", + "nordic_nrf_spim": "spi", "nuvoton_npcx_spip": "spi", "nuvoton_numaker_spi": "spi", "nxp_dspi": "spi", @@ -1961,20 +2742,33 @@ "nxp_imx_ecspi": "spi", "nxp_lpc_spi": "spi", "nxp_s32_spi": "spi", + "nxp_sc18is606_spi": "spi", "opencores_spi_simple": "spi", "openisa_rv32m1_lpspi": "spi", "raspberrypi_pico_spi_pio": "spi", + "realtek_rts5912_spi": "spi", "renesas_ra8_spi_b": "spi", "renesas_ra_spi": "spi", + "renesas_ra_spi_sci": "spi", + "renesas_ra_spi_sci_b": "spi", + "renesas_rx_rspi": "spi", + "renesas_rz_rspi": "spi", + "renesas_rz_spi": "spi", "renesas_smartbond_spi": "spi", + "sensry_sy1xx_spi": "spi", "sifive_spi0": "spi", + "sifli_sf32lb_spi": "spi", "silabs_eusart_spi": "spi", + "silabs_gspi": "spi", "silabs_usart_spi": "spi", "snps_designware_spi": "spi", "st_stm32_spi": "spi", "telink_b91_spi": "spi", "ti_cc13xx_cc26xx_spi": "spi", + "ti_cc23x0_spi": "spi", + "ti_omap_mcspi": "spi", "vnd_spi": "spi", + "wch_spi": "spi", "xlnx_xps_spi_2_00_a": "spi", "zephyr_spi_bitbang": "spi", "zephyr_spi_emul_controller": "spi", @@ -1983,68 +2777,92 @@ "nxp_lpspi": "spi/spi_nxp_lpspi", # # stepper - "zephyr_fake_stepper": "stepper", - "zephyr_gpio_stepper": "stepper", + "zephyr_fake_stepper_ctrl": "stepper", + "zephyr_fake_stepper_driver": "stepper", + # + # stepper/adi_tmc/tmc22xx + "adi_tmc2209": "stepper/adi_tmc/tmc22xx", + # + # stepper/adi_tmc/tmc50xx + "adi_tmc50xx": "stepper/adi_tmc/tmc50xx", + "adi_tmc50xx_stepper_ctrl": "stepper/adi_tmc/tmc50xx", + "adi_tmc50xx_stepper_driver": "stepper/adi_tmc/tmc50xx", + # + # stepper/adi_tmc/tmc51xx + "adi_tmc51xx": "stepper/adi_tmc/tmc51xx", + "adi_tmc51xx_stepper_ctrl": "stepper/adi_tmc/tmc51xx", + "adi_tmc51xx_stepper_driver": "stepper/adi_tmc/tmc51xx", # - # stepper/adi_tmc - "adi_tmc2209": "stepper/adi_tmc", - "adi_tmc5041": "stepper/adi_tmc", + # stepper/allegro + "allegro_a4979": "stepper/allegro", + # + # stepper/gpio_stepper + "zephyr_gpio_step_dir_stepper_ctrl": "stepper/gpio_stepper", + "zephyr_h_bridge_stepper_ctrl": "stepper/gpio_stepper", # # stepper/ti - "ti_drv8424": "stepper/ti", + "ti_drv84xx": "stepper/ti", # # syscon + "bflb_efuse": "syscon", "syscon": "syscon", # # tee/optee "linaro_optee_tz": "tee/optee", # # timer + "adi_max32_rv32_sys_timer": "timer", "ambiq_stimer": "timer", - "andestech_machine_timer": "timer", "atmel_sam0_rtc": "timer", "gaisler_gptimer": "timer", + "infineon_lp_timer": "timer", "intel_adsp_timer": "timer", "intel_hpet": "timer", + "ite_it51xxx_timer": "timer", "ite_it8xxx2_timer": "timer", "litex_timer0": "timer", - "lowrisc_machine_timer": "timer", - "microchip_mec5_ktimer": "timer", + "microchip_sam_pit64b": "timer", "microchip_xec_rtos_timer": "timer", - "neorv32_machine_timer": "timer", - "niosv_machine_timer": "timer", - "nuclei_systimer": "timer", "nuvoton_npcx_itim_timer": "timer", "nxp_gpt_hw_timer": "timer", - "nxp_kinetis_lptmr": "timer", "nxp_lptmr": "timer", "nxp_os_timer": "timer", "openisa_rv32m1_lptmr": "timer", "realtek_rts5912_rtmr": "timer", + "renesas_ra_ulpt_timer": "timer", "renesas_rcar_cmt": "timer", - "scr_machine_timer": "timer", - "sifive_clint0": "timer", + "renesas_rx_timer_cmt": "timer", + "renesas_rz_gtm_os_timer": "timer", + "renesas_rza2m_ostm": "timer", + "riscv_machine_timer": "timer", "silabs_gecko_burtc": "timer", "st_stm32_lptim": "timer", "sy1xx_sys_timer": "timer", - "telink_machine_timer": "timer", "ti_am654_timer": "timer", "ti_cc13xx_cc26xx_rtc_timer": "timer", + "ti_cc23x0_rtc_timer": "timer", + "ti_cc23x0_systim_timer": "timer", "wch_systick": "timer", "xlnx_ttcps": "timer", # # usb/bc12 "diodes_pi3usb9201": "usb/bc12", # + # usb/common/stm32 + "*/": "usb/common/stm32", + "st_stm32u5_otghs_phy": "usb/common/stm32", + # # usb/device - "atmel_sam0_usb": "usb/device", "atmel_sam_usbc": "usb/device", "atmel_sam_usbhs": "usb/device", # # usb/udc + "adi_max32_usbhs": "usb/udc", "ambiq_usb": "usb/udc", + "atmel_sam0_usb": "usb/udc", "ite_it82xx2_usb": "usb/udc", "nordic_nrf_usbd": "usb/udc", + "nuvoton_numaker_hsusbd": "usb/udc", "nuvoton_numaker_usbd": "usb/udc", "nxp_ehci": "usb/udc", "nxp_kinetis_usbd": "usb/udc", @@ -2061,6 +2879,10 @@ # # usb/uhc "maxim_max3421e_spi": "usb/uhc", + "nxp_uhc_ehci": "usb/uhc", + "nxp_uhc_ip3516hs": "usb/uhc", + "nxp_uhc_khci": "usb/uhc", + "nxp_uhc_ohci": "usb/uhc", "zephyr_uhc_virtual": "usb/uhc", # # usb_c/ppc @@ -2069,6 +2891,7 @@ # # usb_c/tcpc "nuvoton_numaker_tcpc": "usb_c/tcpc", + "onnn_fusb307_tcpc": "usb_c/tcpc", "parade_ps8xxx": "usb_c/tcpc", "richtek_rt1715": "usb_c/tcpc", "st_stm32_ucpd": "usb_c/tcpc", @@ -2080,19 +2903,34 @@ # # video "aptina_mt9m114": "video", - "espressif_esp32_lcd_cam": "video", + "espressif_esp32_lcd_cam_dvp": "video", "galaxycore_gc2145": "video", + "himax_hm01b0": "video", + "himax_hm0360": "video", "nxp_imx_csi": "video", "nxp_mipi_csi2rx": "video", "nxp_video_smartdma": "video", "ovti_ov2640": "video", "ovti_ov5640": "video", + "ovti_ov5642": "video", "ovti_ov7670": "video", + "ovti_ov7675": "video", "ovti_ov7725": "video", + "ovti_ov9655": "video", + "renesas_ra_ceu": "video", + "sony_imx335": "video", + "st_mipid02": "video", "st_stm32_dcmi": "video", - "zephyr_sw_generator": "video", + "st_stm32_dcmipp": "video", + "st_stm32_jpeg": "video", + "st_stm32_venc": "video", "zephyr_video_emul_imager": "video", "zephyr_video_emul_rx": "video", + "zephyr_video_sw_generator": "video", + # + # virtio + "virtio_mmio": "virtio", + "virtio_pci": "virtio", # # virtualization "qemu_ivshmem": "virtualization", @@ -2109,45 +2947,66 @@ # # watchdog "adi_max32_watchdog": "watchdog", + "adi_max42500_watchdog": "watchdog", "ambiq_watchdog": "watchdog", "andestech_atcwdt200": "watchdog", "arm_cmsdk_watchdog": "watchdog", "atmel_sam0_watchdog": "watchdog", + "atmel_sam4l_watchdog": "watchdog", "atmel_sam_watchdog": "watchdog", + "bflb_wdt": "watchdog", + "ene_kb106x_watchdog": "watchdog", "ene_kb1200_watchdog": "watchdog", "espressif_esp32_watchdog": "watchdog", "espressif_esp32_xt_wdt": "watchdog", "gd_gd32_fwdgt": "watchdog", "gd_gd32_wwdgt": "watchdog", - "infineon_cat1_watchdog": "watchdog", + "infineon_watchdog": "watchdog", "infineon_xmc4xxx_watchdog": "watchdog", "intel_adsp_watchdog": "watchdog", "intel_tco_wdt": "watchdog", + "ite_it51xxx_watchdog": "watchdog", "ite_it8xxx2_watchdog": "watchdog", "litex_watchdog": "watchdog", "lowrisc_opentitan_aontimer": "watchdog", + "microchip_wdt_g1": "watchdog", "microchip_xec_watchdog": "watchdog", "nordic_npm1300_wdt": "watchdog", + "nordic_npm1304_wdt": "watchdog", "nordic_npm2100_wdt": "watchdog", "nordic_npm6001_wdt": "watchdog", + "nordic_nrf_wdt": "watchdog", "nuvoton_npcx_watchdog": "watchdog", "nuvoton_numaker_wwdt": "watchdog", + "nxp_cop": "watchdog", + "nxp_ewm": "watchdog", "nxp_fs26_wdog": "watchdog", "nxp_imx_wdog": "watchdog", "nxp_kinetis_wdog": "watchdog", "nxp_lpc_wwdt": "watchdog", + "nxp_rtwdog": "watchdog", "nxp_s32_swt": "watchdog", "nxp_wdog32": "watchdog", "raspberrypi_pico_watchdog": "watchdog", + "realtek_rts5817_watchdog": "watchdog", + "realtek_rts5912_watchdog": "watchdog", + "renesas_rx_iwdt": "watchdog", + "renesas_rz_wdt": "watchdog", "renesas_smartbond_watchdog": "watchdog", "sifive_wdt": "watchdog", + "sifli_sf32lb_wdt": "watchdog", "silabs_gecko_wdog": "watchdog", + "silabs_siwx91x_wdt": "watchdog", "snps_designware_watchdog": "watchdog", "st_stm32_watchdog": "watchdog", "st_stm32_window_watchdog": "watchdog", "ti_cc13xx_cc26xx_watchdog": "watchdog", + "ti_cc23x0_wdt": "watchdog", "ti_cc32xx_watchdog": "watchdog", + "ti_j7_rti_wdt": "watchdog", "ti_tps382x": "watchdog", + "wch_iwdg": "watchdog", + "xlnx_versal_wwdt": "watchdog", "xlnx_xps_timebase_wdt_1_00_a": "watchdog", # # wifi/esp32/src @@ -2156,16 +3015,25 @@ # wifi/esp_at "espressif_esp_at": "wifi/esp_at", # + # wifi/esp_hosted + "espressif_esp_hosted": "wifi/esp_hosted", + # # wifi/eswifi "inventek_eswifi": "wifi/eswifi", "inventek_eswifi_uart": "wifi/eswifi", # + # wifi/infineon + "infineon_airoc_wifi": "wifi/infineon", + # # wifi/nrf_wifi/off_raw_tx/src "nordic_wlan": "wifi/nrf_wifi/off_raw_tx/src", # # wifi/nxp "nxp_wifi": "wifi/nxp", # + # wifi/siwx91x + "silabs_siwx91x_wifi": "wifi/siwx91x", + # # wifi/winc1500 "atmel_winc1500": "wifi/winc1500", } diff --git a/ports/zephyr-cp/cptools/cpbuild.py b/ports/zephyr-cp/cptools/cpbuild.py index ef836b3df8a..edaf020c264 100644 --- a/ports/zephyr-cp/cptools/cpbuild.py +++ b/ports/zephyr-cp/cptools/cpbuild.py @@ -1,15 +1,14 @@ import asyncio -import inspect +import atexit +import hashlib +import json import logging import os import pathlib -import shlex -import time -import hashlib -import atexit -import json import re -import sys +import tempfile +import time +from typing import Optional logger = logging.getLogger(__name__) @@ -111,7 +110,14 @@ def _create_semaphore(): max_track = 0 -async def run_command(command, working_directory, description=None, check_hash=[], extradeps=[]): +async def run_command( + command, + working_directory, + description=None, + check_hash=[], + extradeps=[], + responsefile: Optional[pathlib.Path] = None, +): """ Runs a command asynchronously. The command should ideally be a list of strings and pathlib.Path objects. If all of the paths haven't been modified since the last @@ -124,26 +130,39 @@ async def run_command(command, working_directory, description=None, check_hash=[ Paths in check_hash are hashed before and after the command. If the hash is the same, then the old mtimes are reset. This is helpful if a command may produce - the same result and you don't want the rest of the build impacted. + the same result and you don't want the rest of the build impacted + + responsefile is used to store the command line arguments if they are too long for the OS. + The arguments will be replaced with @ and tried again. + If None, commands that are too long will fail. """ paths = [] + responsefile_contents = None if isinstance(command, list): for i, part in enumerate(command): if isinstance(part, pathlib.Path): paths.append(part) part = part.relative_to(working_directory, walk_up=True) - # if isinstance(part, list): command[i] = str(part) - command = " ".join(command) + command_string = " ".join(command) + + # When on windows, use a responsefile if the command string is >= 8192 + if responsefile is not None and os.name == "nt" and len(command_string) >= 8192: + # Escape backslashes + responsefile_contents = "\n".join(part.replace("\\", "\\\\") for part in command[1:]) + responsefile.write_text(responsefile_contents) + command_string = f"{command[0]} -v @{responsefile}" + else: + command_string = command - command_hash = hashlib.sha3_256(command.encode("utf-8")) + command_hash = hashlib.sha3_256(command_string.encode("utf-8")) command_hash.update(str(working_directory).encode("utf-8")) command_hash = command_hash.hexdigest() # If a command is run multiple times, then wait for the first one to continue. Don't run it again. if command_hash in ALREADY_RUN: - logger.debug(f"Already running {command_hash} {command}") + logger.debug(f"Already running {command_hash} {command_string}") await ALREADY_RUN[command_hash].wait() return ALREADY_RUN[command_hash] = asyncio.Event() @@ -169,7 +188,7 @@ async def run_command(command, working_directory, description=None, check_hash=[ run_reason = f"{p.relative_to(working_directory, walk_up=True)} is newer" break if nothing_newer: - logger.debug(f"Nothing newer {command[-32:]}") + logger.debug(f"Nothing newer {command_string[-32:]}") ALREADY_RUN[command_hash].set() return else: @@ -196,7 +215,7 @@ async def run_command(command, working_directory, description=None, check_hash=[ track = tracks.pop() start_time = time.perf_counter_ns() // 1000 process = await asyncio.create_subprocess_shell( - command, + command_string, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd=working_directory, @@ -242,22 +261,25 @@ async def run_command(command, working_directory, description=None, check_hash=[ raise cancellation if description: logger.info(f"{description} ({run_reason})") - logger.debug(command) + logger.debug(command_string) else: - logger.info(f"{command} ({run_reason})") + logger.info(f"{command_string} ({run_reason})") if old_newest_file == newest_file: logger.error("No files were modified by the command.") raise RuntimeError() else: if command_hash in LAST_BUILD_TIMES: del LAST_BUILD_TIMES[command_hash] + logger.error(command_string) + if responsefile_contents: + logger.error(f"Response file contents:\n{responsefile_contents}") + logger.error(f"Return code: {process.returncode}") if stdout: logger.info(stdout.decode("utf-8").strip()) if stderr: logger.warning(stderr.decode("utf-8").strip()) if not stdout and not stderr: logger.warning("No output") - logger.error(command) if cancellation: raise cancellation raise RuntimeError() @@ -335,8 +357,8 @@ async def preprocess( ): output_file.parent.mkdir(parents=True, exist_ok=True) depfile = output_file.parent / (output_file.name + ".d") - if depfile.exists(): - pass + responsefile = output_file.parent / (output_file.name + ".rsp") + await run_command( [ self.c_compiler, @@ -354,6 +376,7 @@ async def preprocess( description=f"Preprocess {source_file.relative_to(self.srcdir)} -> {output_file.relative_to(self.builddir)}", working_directory=self.srcdir, check_hash=[output_file], + responsefile=responsefile, ) async def compile( @@ -365,6 +388,7 @@ async def compile( output_file = self.builddir / output_file output_file.parent.mkdir(parents=True, exist_ok=True) depfile = output_file.with_suffix(".d") + responsefile = output_file.with_suffix(".rsp") extradeps = [] if depfile.exists(): depfile_contents = depfile.read_text().split() @@ -375,25 +399,30 @@ async def compile( extradeps.append(pathlib.Path(dep)) else: extradeps.append(self.srcdir / dep) + await run_command( - [self.c_compiler, self.cflags, "-MMD", "-c", source_file, *flags, "-o", output_file], + [ + self.c_compiler, + self.cflags, + "-MMD", + "-c", + source_file, + *flags, + "-o", + output_file, + ], description=f"Compile {source_file.relative_to(self.srcdir)} -> {output_file.relative_to(self.builddir)}", working_directory=self.srcdir, extradeps=extradeps, + responsefile=responsefile, ) async def archive(self, objects: list[pathlib.Path], output_file: pathlib.Path): output_file.parent.mkdir(parents=True, exist_ok=True) - # Do one file at a time so that we don't have a long command line. run_command - # should skip unchanged files ok. - input_files = output_file.with_suffix(output_file.suffix + ".input_files") - input_file_content = "\n".join(str(p) for p in objects) - # Windows paths have \ as separator but ar wants them as / (like UNIX) - input_file_content = input_file_content.replace("\\", "/") - input_files.write_text(input_file_content) + responsefile = output_file.with_suffix(".rsp") await run_command( - [self.ar, "rvs", output_file, f"@{input_files}"], + [self.ar, "rvs", output_file, *objects], description=f"Create archive {output_file.relative_to(self.srcdir)}", working_directory=self.srcdir, - extradeps=objects, + responsefile=responsefile, ) diff --git a/ports/zephyr-cp/cptools/gen_compat2driver.py b/ports/zephyr-cp/cptools/gen_compat2driver.py index 0cb6a16f9da..ffe8da18596 100644 --- a/ports/zephyr-cp/cptools/gen_compat2driver.py +++ b/ports/zephyr-cp/cptools/gen_compat2driver.py @@ -2,8 +2,8 @@ mapping = {} -drivers = pathlib.Path("lib/zephyr/drivers") -for p in drivers.glob("**/*.c"): +drivers = pathlib.Path("zephyr/drivers") +for p in drivers.glob("**/*.[ch]"): for line in p.open(): if line.startswith("#define DT_DRV_COMPAT"): compat = line.rsplit(None, 1)[-1].strip() diff --git a/ports/zephyr-cp/cptools/get_west_shield_args.py b/ports/zephyr-cp/cptools/get_west_shield_args.py new file mode 100644 index 00000000000..deda6bf5f26 --- /dev/null +++ b/ports/zephyr-cp/cptools/get_west_shield_args.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +"""Resolve shield arguments for west build. + +Priority: +1. SHIELD / SHIELDS make variables (if explicitly provided) +2. SHIELD / SHIELDS from boards///circuitpython.toml +""" + +import argparse +import os +import pathlib +import re +import shlex + +import board_tools + + +def split_shields(raw): + if not raw: + return [] + + return [shield for shield in re.split(r"[,;\s]+", raw.strip()) if shield] + + +def dedupe(values): + deduped = [] + seen = set() + + for value in values: + if value in seen: + continue + seen.add(value) + deduped.append(value) + + return deduped + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("board") + args = parser.parse_args() + + portdir = pathlib.Path(__file__).resolve().parent.parent + + _, mpconfigboard = board_tools.load_mpconfigboard(portdir, args.board) + + shield_origin = os.environ.get("SHIELD_ORIGIN", "undefined") + shields_origin = os.environ.get("SHIELDS_ORIGIN", "undefined") + + shield_override = os.environ.get("SHIELD", "") + shields_override = os.environ.get("SHIELDS", "") + + override_requested = shield_origin != "undefined" or shields_origin != "undefined" + + if override_requested: + shields = split_shields(shield_override) + split_shields(shields_override) + else: + shields = board_tools.get_shields(mpconfigboard) + + shields = dedupe(shields) + + west_shield_args = [] + for shield in shields: + west_shield_args.extend(("--shield", shield)) + + print(shlex.join(west_shield_args)) + + +if __name__ == "__main__": + main() diff --git a/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py b/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py index 0ed280cbc67..f42fc1a3a85 100644 --- a/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py +++ b/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py @@ -2,7 +2,6 @@ import pathlib import subprocess import sys -import tomllib import board_tools @@ -10,14 +9,20 @@ board = sys.argv[-1] -mpconfigboard = board_tools.find_mpconfigboard(portdir, board) -if mpconfigboard is None: +_, mpconfigboard = board_tools.load_mpconfigboard(portdir, board) +if not mpconfigboard: # Assume it doesn't need any prep. sys.exit(0) -with mpconfigboard.open("rb") as f: - mpconfigboard = tomllib.load(f) - blobs = mpconfigboard.get("BLOBS", []) +blob_fetch_args = mpconfigboard.get("blob_fetch_args", {}) for blob in blobs: - subprocess.run(["west", "blobs", "fetch", blob], check=True) + args = blob_fetch_args.get(blob, []) + subprocess.run(["west", "blobs", "fetch", blob, *args], check=True) + +if board.endswith("bsim"): + subprocess.run( + ["make", "everything", "-j", "8"], + cwd=portdir / "tools" / "bsim", + check=True, + ) diff --git a/ports/zephyr-cp/cptools/tests/README.md b/ports/zephyr-cp/cptools/tests/README.md new file mode 100644 index 00000000000..6bc8aa43ce6 --- /dev/null +++ b/ports/zephyr-cp/cptools/tests/README.md @@ -0,0 +1,28 @@ +# Zephyr2CP Tests + +This directory contains unit tests for the `zephyr2cp.py` module using real device tree parsing and pytest. + +## Running Tests + +To run all tests: +```bash +cd /home/tannewt/repos/circuitpython/ports/zephyr-cp +make test +``` + +For verbose output: +```bash +pytest test_zephyr2cp.py -v +``` + +To run specific test classes: +```bash +pytest test_zephyr2cp.py::TestFindFlashDevices -v +pytest test_zephyr2cp.py::TestFindRAMRegions -v +pytest test_zephyr2cp.py::TestIntegration -v +``` + +To run a specific test: +```bash +pytest test_zephyr2cp.py::TestFindFlashDevices::test_valid_flash_device -v +``` diff --git a/ports/zephyr-cp/cptools/tests/test_check_partitions.py b/ports/zephyr-cp/cptools/tests/test_check_partitions.py new file mode 100644 index 00000000000..e8f9d470662 --- /dev/null +++ b/ports/zephyr-cp/cptools/tests/test_check_partitions.py @@ -0,0 +1,398 @@ +"""Unit tests for cptools/check_partitions.py using real device tree parsing. + +Each case here is a layout that actually occurs in this port, so the checks are +exercised against devicetree as edtlib resolves it rather than against +hand-built stand-ins. +""" + +import pathlib +import sys +import tempfile + +import pytest + +portdir = pathlib.Path(__file__).parent.parent.parent +sys.path.append(str(portdir / "zephyr/scripts/dts/python-devicetree/src/")) + +from devicetree import edtlib # noqa: E402 + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent)) + +from check_partitions import ( # noqa: E402 + check_layout, + check_parity, + device_size, + evaluate, + iter_partitions, + read_defines, + reference_layout, +) + +BINDINGS = [str(portdir / "zephyr/dts/bindings")] + + +def parse_dts_string(dts_content): + """Parse device tree source and return the resolved edtlib.EDT.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".dts", delete=False) as f: + f.write(dts_content) + f.flush() + temp_path = f.name + + try: + return edtlib.EDT(temp_path, BINDINGS) + finally: + pathlib.Path(temp_path).unlink() + + +def xip_flash(partitions, ranges="ranges;", size="0x200000"): + """A memory-mapped flash at 0x10000000, the RP2040 arrangement. + + ``ranges`` is what the overlays get wrong: the board DTS declares it on the + partitions node, and an overlay that deletes and rebuilds that node without + it leaves every partition untranslated. + """ + return f"""/dts-v1/; + +/ {{ + #address-cells = <1>; + #size-cells = <1>; + + soc {{ + #address-cells = <1>; + #size-cells = <1>; + ranges; + + flash0: flash@10000000 {{ + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + reg = <0x10000000 {size}>; + ranges = <0x0 0x10000000 {size}>; + #address-cells = <1>; + #size-cells = <1>; + + partitions {{ + {ranges} + #address-cells = <1>; + #size-cells = <1>; +{partitions} + }}; + }}; + }}; +}}; +""" + + +MAPPED_PARTS = """ + code_partition: partition@100 { + compatible = "zephyr,mapped-partition"; + label = "code-partition"; + reg = <0x100 0x17ff00>; + }; + + circuitpy_partition: partition@180000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x180000 0x80000>; + }; +""" + + +class TestAddressTranslation: + """The partitions node must keep translating addresses to the SoC's space.""" + + def test_missing_ranges_is_reported(self): + """This is the bug the checker exists for: without ranges; on the + rebuilt partitions node the partitions resolve to bare offsets.""" + edt = parse_dts_string(xip_flash(MAPPED_PARTS, ranges="")) + problems = check_layout(edt) + + assert len(problems) == 2 + assert any("code_partition" in p and "0x100" in p for p in problems) + assert all("ranges" in p for p in problems) + + def test_ranges_present_passes(self): + """The same layout with ranges; must be clean, or the check would only + ever be able to fail.""" + edt = parse_dts_string(xip_flash(MAPPED_PARTS)) + + assert check_layout(edt) == [] + + def test_absolute_addresses_pass(self): + """Some overlays write the absolute address into reg and leave the + partitions node without ranges. That resolves to the same correct + address, so it must not be reported.""" + parts = """ + code_partition: partition@10000100 { + compatible = "zephyr,mapped-partition"; + label = "code-partition"; + reg = <0x10000100 0x17ff00>; + }; +""" + edt = parse_dts_string(xip_flash(parts, ranges="")) + + assert check_layout(edt) == [] + + def test_flash_based_at_zero_passes(self): + """On a device based at 0 -- the nRF arrangement -- the translated and + the bare value coincide, so nothing is wrong either way.""" + dts = """/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + soc { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + reg = <0x0 0x100000>; + ranges = <0x0 0x0 0x100000>; + #address-cells = <1>; + #size-cells = <1>; + + partitions { + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@10000 { + compatible = "zephyr,mapped-partition"; + label = "image-0"; + reg = <0x10000 0x10000>; + }; + }; + }; + }; +}; +""" + edt = parse_dts_string(dts) + + assert check_layout(edt) == [] + + +class TestPartitionDiscovery: + """What counts as a partition is decided by position, not by compatible.""" + + def test_partition_without_compatible_is_seen(self): + """An overlay may add a partition carrying no compatible at all. It + still occupies the space, and treating it as absent would report a + board that has a filesystem as having none.""" + parts = """ + storage_partition: partition@180000 { + label = "storage"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 0x7f000>; + }; +""" + edt = parse_dts_string(xip_flash(parts)) + labels = [node.labels[0] for node, _dev, _off, _size, _mapped in iter_partitions(edt)] + + assert "storage_partition" in labels + assert "circuitpy_partition" in labels + + +class TestDeviceSize: + """Bus-attached flash keeps its capacity in size, not in reg.""" + + def test_size_property_wins_over_chip_select(self): + """An SPI NOR's reg is a chip select. Reading a size out of it gives 0, + which would silently skip every check on the device CIRCUITPY usually + lives on.""" + dts = """/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + soc { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + spi@0 { + compatible = "vnd,spi"; + reg = <0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + mx25r64: mx25r6435f@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + size = <67108864>; + spi-max-frequency = <8000000>; + jedec-id = [c2 28 17]; + }; + }; + }; +}; +""" + edt = parse_dts_string(dts) + node = edt.get_node("/soc/spi@0/mx25r6435f@0") + + assert device_size(node) == 8 * 1024 * 1024 + + +class TestGeometry: + """Partitions must not overlap or leave their device.""" + + def test_partition_spanning_several_others_is_reported(self): + """Comparing neighbouring pairs only would catch the first overlap and + miss the rest, so a partition covering three others must report more + than once.""" + parts = """ + slot0_partition: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "image-0"; + reg = <0x0 0x30000>; + }; + + nvm_partition: partition@10000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0x10000 0x1000>; + }; + + storage_partition: partition@20000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x20000 0x1000>; + }; +""" + edt = parse_dts_string(xip_flash(parts)) + problems = [p for p in check_layout(edt) if "overlaps" in p] + + assert len(problems) == 2 + + def test_partition_past_end_of_device_is_reported(self): + """A partition may not run past the flash it lives in.""" + parts = """ + circuitpy_partition: partition@1f0000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x1f0000 0x20000>; + }; +""" + edt = parse_dts_string(xip_flash(parts)) + + assert any("past the end" in p for p in check_layout(edt)) + + +class TestEmptyLayout: + """A board whose overlay defines nothing must not look verified.""" + + def test_no_partitions_yields_nothing_checked(self): + """check_layout has nothing to complain about here, which is why the + caller reports how many partitions it inspected: an empty layout and a + good one are otherwise indistinguishable.""" + edt = parse_dts_string(xip_flash("")) + + assert check_layout(edt) == [] + assert list(iter_partitions(edt)) == [] + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__])) + + +class TestParity: + """Agreement with the non-Zephyr build of the same board. + + The reference values are what ports/raspberrypi/mpconfigport.h and + ports/nordic/mpconfigport.h derive for these boards; the tests read the real + board files so a change there is caught here. + """ + + def test_evaluate_follows_references(self): + defines = {"A": "(2 * B)", "B": "(512 * 1024)", "C": "A + UNKNOWN"} + assert evaluate(defines, "A") == 1024 * 1024 + assert evaluate(defines, "B") == 512 * 1024 + assert evaluate(defines, "C") is None + assert evaluate(defines, "MISSING", 7) == 7 + + def test_read_defines_precedence(self, tmp_path): + mk = tmp_path / "mpconfigboard.mk" + mk.write_text( + "CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)'\nQSPI_FLASH_FILESYSTEM = 1\n" + ) + header = tmp_path / "mpconfigport.h" + header.write_text( + "#ifndef CIRCUITPY_FIRMWARE_SIZE\n#define CIRCUITPY_FIRMWARE_SIZE (1020 * 1024)\n#endif\n" + ) + defines = read_defines([mk, header]) + assert evaluate(defines, "CIRCUITPY_FIRMWARE_SIZE") == 1536 * 1024 + assert defines["QSPI_FLASH_FILESYSTEM"] == "1" + + def test_raspberrypi_default_firmware_size(self): + layout = reference_layout("raspberrypi/raspberry_pi_pico", 0x200000) + assert layout["nvm"] == (0xFF000, 0x1000) + assert layout["circuitpy"] == (0x100000, 0x100000) + + def test_raspberrypi_board_firmware_size(self): + layout = reference_layout("raspberrypi/raspberry_pi_pico_w", 0x200000) + assert layout["nvm"] == (0x180000, 0x1000) + assert layout["circuitpy"] == (0x181000, 0x7F000) + + def test_nordic_external_drive(self): + layout = reference_layout("nordic/feather_nrf52840_express", 0x100000) + assert layout["nvm"] == (0xF2000, 0x2000) + assert layout["circuitpy"] == "external" + + def test_unknown_port_and_board_rejected(self): + with pytest.raises(ValueError): + reference_layout("espressif/adafruit_feather_esp32s3", 0x400000) + with pytest.raises(ValueError): + reference_layout("raspberrypi/no_such_board", 0x200000) + + def rp2040_layout(self, nvm_offset): + return xip_flash( + f""" + code_partition: partition@100 {{ + compatible = "zephyr,mapped-partition"; + reg = <0x100 0xfdf00>; + }}; + nvm_partition: partition@{nvm_offset:x} {{ + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0x{nvm_offset:x} 0x1000>; + }}; + circuitpy_partition: partition@100000 {{ + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x100000 0x100000>; + }}; + """ + ) + + def test_parity_matches(self): + edt = parse_dts_string(self.rp2040_layout(0xFF000)) + assert check_parity(edt, "raspberrypi/raspberry_pi_pico") == [] + + def test_parity_reports_moved_nvm(self): + edt = parse_dts_string(self.rp2040_layout(0xFE000)) + problems = check_parity(edt, "raspberrypi/raspberry_pi_pico") + assert len(problems) == 1 + assert "nvm_partition" in problems[0] + assert "0xfe000" in problems[0] and "0xff000" in problems[0] + + def test_parity_reports_missing_partition(self): + edt = parse_dts_string( + xip_flash( + """ + code_partition: partition@100 { + compatible = "zephyr,mapped-partition"; + reg = <0x100 0xfdf00>; + }; + """ + ) + ) + problems = check_parity(edt, "raspberrypi/raspberry_pi_pico") + assert any(p.startswith("nvm_partition: missing") for p in problems) + assert any(p.startswith("circuitpy_partition: missing") for p in problems) diff --git a/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py b/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py new file mode 100644 index 00000000000..b147ae0605e --- /dev/null +++ b/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py @@ -0,0 +1,589 @@ +import sys +import pathlib +import tempfile + +# Add devicetree library to path +portdir = pathlib.Path(__file__).parent.parent.parent +sys.path.append(str(portdir / "zephyr/scripts/dts/python-devicetree/src/")) + +from devicetree import dtlib + +# Add parent directory to path to import zephyr2cp +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent)) + +# Mock cpbuild before importing +sys.modules["cpbuild"] = type(sys)("cpbuild") +sys.modules["cpbuild"].run_in_thread = lambda x: x + +from zephyr2cp import find_flash_devices, find_ram_regions, BLOCKED_FLASH_COMPAT, MINIMUM_RAM_SIZE + + +def parse_dts_string(dts_content): + """ + Parse a device tree string and return the dtlib.DT object. + + Args: + dts_content: String containing device tree source + + Returns: + dtlib.DT object with parsed device tree + """ + with tempfile.NamedTemporaryFile(mode="w", suffix=".dts", delete=False) as f: + f.write(dts_content) + f.flush() + temp_path = f.name + + try: + dt = dtlib.DT(temp_path) + return dt + finally: + pathlib.Path(temp_path).unlink() + + +class TestFindFlashDevices: + """Test suite for find_flash_devices function.""" + + def test_no_compatible_returns_empty(self): + """Test that device tree with no flash devices returns empty list.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + memory@0 { + reg = <0x0 0x100000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert result == [] + + def test_chosen_flash_excluded(self): + """Test that chosen flash nodes are excluded.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0x0 0x100000>; + }; + + chosen { + zephyr,flash = &flash0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert result == [], "Chosen flash should be excluded" + + def test_blocked_compat_excluded(self): + """Test that blocked compatible strings are excluded.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + qspi0: qspi@40000 { + compatible = "renesas,ra-qspi"; + reg = <0x40000 0x1000>; + }; + + spi0: spi@50000 { + compatible = "nordic,nrf-spim"; + reg = <0x50000 0x1000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert result == [], "Blocked flash controllers should be excluded" + + def test_valid_flash_device(self): + """Test that valid flash device is detected.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0 0x100000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert len(result) == 1 + assert result[0] == "flash0" + + def test_valid_flash_device_multiple_drivers(self): + """Test that valid flash device is detected.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "other,driver", "jedec,spi-nor"; + reg = <0x0 0x100000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert len(result) == 1 + assert result[0] == "flash0" + + def test_external_flash_not_chosen(self): + """Test external flash is included when internal is chosen.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + internal_flash: flash@0 { + compatible = "soc-nv-flash"; + reg = <0x0 0x100000>; + }; + + external_flash: flash@1000000 { + compatible = "jedec,spi-nor"; + reg = <0x1000000 0x800000>; + }; + + chosen { + zephyr,flash = &internal_flash; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + + # Should only include external flash, not chosen internal flash + assert len(result) == 1 + assert "external_flash" in result[0] + assert "internal_flash" not in result[0] + + def test_disabled_flash_excluded(self): + """Test that disabled flash devices are excluded.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0 0x100000>; + status = "disabled"; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert result == [], "Disabled flash should be excluded" + + +class TestFindRAMRegions: + """Test suite for find_ram_regions function.""" + + def test_no_ram_returns_empty(self): + """Test that device tree with no RAM returns empty list.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash@0 { + compatible = "soc-nv-flash"; + reg = <0x0 0x100000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + assert result == [] + + def test_chosen_sram_basic(self): + """Test chosen sram region is detected correctly.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + + assert len(result) == 1 + label, start, end, size, path = result[0] + + assert label == "sram0" + assert start == "z_mapped_end" + assert ( + end + == "(uint32_t*) (DT_REG_ADDR(DT_NODELABEL(sram0)) + DT_REG_SIZE(DT_NODELABEL(sram0)))" + ) + assert size == 0x40000 + + def test_memory_region_with_custom_name(self): + """Test memory region with zephyr,memory-region property.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + + reserved_mem: memory@30000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x30000000 0x10000>; + zephyr,memory-region = "CUSTOM_REGION"; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + + # Should have both regions, chosen first + assert len(result) == 2 + + # First should be chosen SRAM + assert result[0][0] == "sram0" + + # Second should be custom region + label, start, end, size, path = result[1] + assert label == "reserved_mem" + assert start == "__CUSTOM_REGION_end" + + def test_memory_region_requires_sram_or_device_type(self): + """Test memory regions require mmio-sram compatibility or device_type=memory.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + + reserved_mem: memory@30000000 { + compatible = "zephyr,memory-region"; + reg = <0x30000000 0x10000>; + zephyr,memory-region = "CUSTOM_REGION"; + }; + + external_mem: memory@40000000 { + compatible = "zephyr,memory-region"; + device_type = "memory"; + reg = <0x40000000 0x20000>; + zephyr,memory-region = "EXT_REGION"; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + + assert len(result) == 2 + assert result[0][0] == "sram0" + assert result[1][0] == "external_mem" + + def test_disabled_ram_excluded(self): + """Test that disabled RAM regions are excluded.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + + sram1: memory@30000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x30000000 0x10000>; + status = "disabled"; + zephyr,memory-region = "CUSTOM_REGION"; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + + # Should only have chosen SRAM, not disabled one + assert len(result) == 1 + assert result[0][0] == "sram0" + + +class TestIntegration: + """Integration tests with realistic device tree configurations.""" + + def test_typical_nrf_board_configuration(self): + """Test typical Nordic nRF board with internal and external flash.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + soc { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0x0 0x100000>; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + }; + + external_flash: spi_flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0 0x800000>; + }; + + chosen { + zephyr,flash = &flash0; + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + + # Test flash detection + flashes = find_flash_devices(dt) + assert len(flashes) == 1, "Should find external flash only" + assert "external_flash" in flashes[0] + + # Test RAM detection + rams = find_ram_regions(dt) + assert len(rams) == 1, "Should find chosen SRAM only" + assert rams[0][0] == "sram0" + + def test_board_with_nrf5340_regions(self): + """Test that RAM subregions are included with the right addresses.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + chosen { + zephyr,sram = &sram0_image; + }; + /* node '/soc/peripheral@50000000/qspi@2b000' defined in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:475 */ + qspi: qspi@2b000 { + compatible = "nordic,nrf-qspi"; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:476 */ + #address-cells = < 0x1 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:477 */ + #size-cells = < 0x0 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:478 */ + reg = < 0x2b000 0x1000 >, + < 0x10000000 0x10000000 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:479 */ + reg-names = "qspi", + "qspi_mm"; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:480 */ + interrupts = < 0x2b 0x1 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:481 */ + status = "okay"; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:118 */ + + /* node '/soc/peripheral@50000000/qspi@2b000/mx25r6435f@0' defined in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:123 */ + mx25r64: mx25r6435f@0 { + compatible = "nordic,qspi-nor"; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:124 */ + reg = < 0x0 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:125 */ + writeoc = "pp4io"; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:127 */ + readoc = "read4io"; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:129 */ + sck-frequency = < 0x7a1200 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:130 */ + jedec-id = [ C2 28 17 ]; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:131 */ + sfdp-bfp = [ E5 20 F1 FF FF FF FF 03 44 EB 08 6B 08 3B 04 BB EE FF FF FF FF FF 00 FF FF FF 00 + FF 0C 20 0F 52 10 D8 00 FF 23 72 F5 00 82 ED 04 CC 44 83 68 44 30 B0 30 B0 F7 C4 + D5 5C 00 BE 29 FF F0 D0 FF FF ]; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:132 */ + size = < 0x4000000 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:136 */ + has-dpd; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:137 */ + t-enter-dpd = < 0x2710 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:138 */ + t-exit-dpd = < 0x88b8 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:139 */ + }; + }; + + /* node '/soc/memory@20000000' defined in zephyr/dts/arm/nordic/nrf5340_cpuapp.dtsi:55 */ + sram0: memory@20000000 { + compatible = "mmio-sram"; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp.dtsi:56 */ + #address-cells = < 0x1 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp.dtsi:57 */ + #size-cells = < 0x1 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp.dtsi:58 */ + reg = < 0x20000000 0x80000 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi:15 */ + ranges = < 0x0 0x20000000 0x80000 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi:16 */ + + /* node '/soc/memory@20000000/sram@0' defined in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:16 */ + sram0_image: sram@0 { + reg = < 0x0 0x70000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:18 */ + ranges = < 0x0 0x0 0x70000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:19 */ + #address-cells = < 0x1 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:20 */ + #size-cells = < 0x1 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:21 */ + + /* node '/soc/memory@20000000/sram@0/sram0_image@0' defined in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:23 */ + sram0_s: sram0_image@0 { + reg = < 0x0 0x40000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:25 */ + }; + }; + + /* node '/soc/memory@20000000/sram@40000' defined in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:33 */ + sram0_ns: sram@40000 { + reg = < 0x40000 0x40000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:35 */ + ranges = < 0x0 0x40000 0x40000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:36 */ + #address-cells = < 0x1 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:37 */ + #size-cells = < 0x1 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:38 */ + + /* node '/soc/memory@20000000/sram@40000/sram0_ns@0' defined in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:40 */ + sram0_ns_app: sram0_ns@0 { + reg = < 0x0 0x30000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:42 */ + }; + }; + + /* node '/soc/memory@20000000/sram@70000' defined in zephyr/dts/vendor/nordic/nrf5340_shared_sram_partition.dtsi:27 */ + sram0_shared: sram@70000 { + reg = < 0x70000 0x10000 >; /* in zephyr/dts/vendor/nordic/nrf5340_shared_sram_partition.dtsi:29 */ + phandle = < 0x11 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_ipc.dtsi:9 */ + }; + }; +}; +""" + dt = parse_dts_string(dts) + flashes = find_flash_devices(dt) + rams = find_ram_regions(dt) + + # Should only get chosen SRAM + assert len(rams) == 1 + assert rams[0][0] == "sram0_image" + + assert len(flashes) == 1 + assert flashes[0] == "mx25r64" + + def test_board_with_chosen_memory_region(self): + """Test that RAM subregions are included with the right addresses.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + chosen { + zephyr,sram = &axisram2; /* in zephyr/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi:18 */ + }; + + + /* node '/memory@34000000' defined in zephyr/dts/arm/st/n6/stm32n6.dtsi:42 */ + axisram1: memory@34000000 { + compatible = "zephyr,memory-region", + "mmio-sram"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:43 */ + zephyr,memory-region = "AXISRAM1"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:44 */ + reg = < 0x34000000 0x200000 >; /* in zephyr/dts/arm/st/n6/stm32n657X0.dtsi:12 */ + }; + + /* node '/memory@34180400' defined in zephyr/dts/arm/st/n6/stm32n6.dtsi:47 */ + axisram2: memory@34180400 { + compatible = "zephyr,memory-region", + "mmio-sram"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:48 */ + zephyr,memory-region = "AXISRAM2"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:49 */ + reg = < 0x34180400 0x7fc00 >; /* in zephyr/dts/arm/st/n6/stm32n657X0.dtsi:17 */ + }; + + /* node '/soc/ramcfg@42023100' defined in zephyr/dts/arm/st/n6/stm32n6.dtsi:251 */ + ramcfg_sram3_axi: ramcfg@42023100 { + compatible = "st,stm32n6-ramcfg"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:252 */ + #address-cells = < 0x1 >; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:253 */ + #size-cells = < 0x1 >; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:254 */ + reg = < 0x42023100 0x80 >; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:255 */ + + /* node '/soc/ramcfg@42023100/memory@34200000' defined in zephyr/dts/arm/st/n6/stm32n6.dtsi:259 */ + axisram3: memory@34200000 { + compatible = "zephyr,memory-region", + "mmio-sram"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:260 */ + zephyr,memory-region = "AXISRAM3"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:261 */ + zephyr,memory-attr = < 0x100000 >; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:262 */ + reg = < 0x34200000 0x70000 >; /* in zephyr/dts/arm/st/n6/stm32n657X0.dtsi:23 */ + status = "disabled"; /* in zephyr/dts/arm/st/n6/stm32n657X0.dtsi:24 */ + }; + }; +}; +""" + dt = parse_dts_string(dts) + rams = find_ram_regions(dt) + + print(rams) + + # Should only get chosen SRAM + assert len(rams) == 2 + assert rams[0][0] == "axisram2" + assert rams[1][0] == "axisram1" diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index cd0e3a6f2aa..cc40ccfda85 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -1,16 +1,37 @@ import logging import pathlib -import cpbuild +import re -from devicetree import dtlib +import cpbuild import yaml - from compat2driver import COMPAT_TO_DRIVER +from devicetree import dtlib logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + +# GPIO flags defined here: include/zephyr/dt-bindings/gpio/gpio.h +GPIO_ACTIVE_LOW = 1 << 0 + +# A region has to be big enough to host TLSF's control structure to be usable as +# the first heap pool, and TLSF sizes that structure from the maximum heap size +# rather than from the region: at an 8 MB maximum it is 2412 bytes. Anything +# smaller than this is not worth adding as a later pool either. The previous +# value of 1024 let through two SiWx917 regions that are exactly 0x400 bytes, +# /memory@0 (reserved for the network processor) and /memory-dma@24061c00, +# neither of which should ever be in the Python heap. +MINIMUM_RAM_SIZE = 8192 MANUAL_COMPAT_TO_DRIVER = { "renesas_ra_nv_flash": "flash", + "soc_nv_flash": "flash", + "nordic_nrf_uarte": "serial", + "nordic_nrf_uart": "serial", + "nordic_nrf_twim": "i2c", + "nordic_nrf_twi": "i2c", + "nordic_nrf_spim": "spi", + "nordic_nrf_spi": "spi", + "nordic_nrf_i2s": "i2s", } # These are controllers, not the flash devices themselves. @@ -20,6 +41,10 @@ "nordic,nrf-spim", ) +BUSIO_CLASSES = {"serial": "UART", "i2c": "I2C", "spi": "SPI"} + +AUDIOBUSIO_CLASSES = {"i2s": "I2SOut"} + CONNECTORS = { "mikro-bus": [ "AN", @@ -82,6 +107,117 @@ "D12", "D13", ], + "adafruit-clue": [ + ["P0", "D0", "A2", "RX"], + ["P1", "D1", "A3", "TX"], + ["P2", "D2", "A4"], + ["P3", "D3", "A5"], + ["P4", "D4", "A6"], + ["P5", "D5", "BUTTON_A"], + ["P6", "D6"], + ["P7", "D7"], + ["P8", "D8"], + ["P9", "D9"], + ["P10", "D10", "A7"], + ["P11", "D11", "BUTTON_B"], + ["P12", "D12", "A0"], + ["P13", "D13", "SCK"], + ["P14", "D14", "MISO"], + ["P15", "D15", "MOSI"], + ["P16", "D16", "A1"], + ["P17", "D17", "L", "LED"], + ["P18", "D18", "NEOPIXEL"], + ["P19", "D19", "SCL"], + ["P20", "D20", "SDA"], + ], + "nordic,expansion-board-header": [ + "P1_04", + "P1_05", + "P1_06", + "P1_07", + "P1_08", + "P1_09", + "P1_10", + "P1_11", + "P1_12", + "P1_13", + "P1_14", + ], + "arducam,dvp-20pin-connector": [ + "SCL", + "SDA", + "VS", + "HS", + "PCLK", + "XCLK", + "D7", + "D6", + "D5", + "D4", + "D3", + "D2", + "D1", + "D0", + "PEN", + "PDN", + "GPIO0", + "GPIO1", + ], + "nxp,cam-44pins-connector": ["CAM_RESETB", "CAM_PWDN"], + "nxp,lcd-8080": [ + "TOUCH_SCL", + "TOUCH_SDA", + "TOUCH_INT", + "BACKLIGHT", + "RESET", + "LCD_DC", + "LCD_CS", + "LCD_WR", + "LCD_RD", + "LCD_TE", + "LCD_D0", + "LCD_D1", + "LCD_D2", + "LCD_D3", + "LCD_D4", + "LCD_D5", + "LCD_D6", + "LCD_D7", + "LCD_D8", + "LCD_D9", + "LCD_D10", + "LCD_D11", + "LCD_D12", + "LCD_D13", + "LCD_D14", + "LCD_D15", + ], + "nxp,lcd-pmod": [ + "LCD_WR", + "TOUCH_SCL", + "LCD_DC", + "TOUCH_SDA", + "LCD_MOSI", + "TOUCH_RESET", + "LCD_CS", + "TOUCH_INT", + ], + "raspberrypi,csi-connector": [ + "CSI_D0_N", + "CSI_D0_P", + "CSI_D1_N", + "CSI_D1_P", + "CSI_CK_N", + "CSI_CK_P", + "CSI_D2_N", + "CSI_D2_P", + "CSI_D3_N", + "CSI_D3_P", + "IO0", + "IO1", + "I2C_SCL", + "I2C_SDA", + ], "renesas,ra-gpio-mipi-header": [ "IIC_SDA", "DISP_BLEN", @@ -89,26 +225,342 @@ "DISP_INT", "DISP_RST", ], + "renesas,ra-parallel-graphics-header": [ + "DISP_BLEN", + "IIC_SDA", + "DISP_INT", + "IIC_SCL", + "DISP_RST", + "LCDC_TCON0", + "LCDC_CLK", + "LCDC_TCON2", + "LCDC_TCON1", + "LCDC_EXTCLK", + "LCDC_TCON3", + "LCDC_DATA01", + "LCDC_DATA00", + "LCDC_DATA03", + "LCDC_DATA02", + "LCDC_DATA05", + "LCDC_DATA04", + "LCDC_DATA07", + "LCDC_DATA16", + "LCDC_DATA09", + "LCDC_DATA08", + "LCDC_DATA11", + "LCDC_DATA10", + "LCDC_DATA13", + "LCDC_DATA12", + "LCDC_DATA15", + "LCDC_DATA14", + "LCDC_DATA17", + "LCDC_DATA16", + "LCDC_DATA19", + "LCDC_DATA18", + "LCDC_DATA21", + "LCDC_DATA20", + "LCDC_DATA23", + "LCDC_DATA22", + ], + "st,stm32-dcmi-camera-fpu-330zh": [ + "SCL", + "SDA", + "RESET", + "PEN", + "VS", + "HS", + "PCLK", + "D7", + "D6", + "D5", + "D4", + "D3", + "D2", + "D1", + "D0", + ], + "raspberrypi,pico-header": [ + "GP0", + "GP1", + "GP2", + "GP3", + "GP4", + "GP5", + "GP6", + "GP7", + "GP8", + "GP9", + "GP10", + "GP11", + "GP12", + "GP13", + "GP14", + "GP15", + "GP16", + "GP17", + "GP18", + "GP19", + "GP20", + "GP21", + "GP22", + ["GP26_A0", "GP26", "A0"], + ["GP27_A1", "GP27", "A1"], + ["GP28_A2", "GP28", "A2"], + ], } +EXCEPTIONAL_DRIVERS = ["entropy", "gpio", "led"] + + +def find_flash_devices(device_tree): + """ + Find all flash devices from a device tree. + + Args: + device_tree: Parsed device tree (dtlib.DT object) + + Returns: + List of device tree flash device reference strings + """ + # Build path2chosen mapping + path2chosen = {} + for k in device_tree.root.nodes["chosen"].props: + value = device_tree.root.nodes["chosen"].props[k] + path2chosen[value.to_path()] = k + + flashes = [] + logger.debug("Flash devices:") + + # Traverse all nodes in the device tree + remaining_nodes = set([device_tree.root]) + while remaining_nodes: + node = remaining_nodes.pop() + remaining_nodes.update(node.nodes.values()) + + # Get compatible strings + compatible = [] + if "compatible" in node.props: + compatible = node.props["compatible"].to_strings() + + # Get status + status = node.props.get("status", None) + if status is None: + status = "okay" + else: + status = status.to_string() + + # Check if this is a flash device + if not compatible or status != "okay": + continue + + # Check for flash driver via compat2driver + drivers = [] + for c in compatible: + underscored = c.replace(",", "_").replace("-", "_") + driver = COMPAT_TO_DRIVER.get(underscored, None) + if not driver: + driver = MANUAL_COMPAT_TO_DRIVER.get(underscored, None) + if driver: + drivers.append(driver) + logger.debug(f" {node.labels[0] if node.labels else node.name} drivers: {drivers}") + + if "flash" not in drivers: + continue + + # Skip chosen nodes because they are used by Zephyr + if node in path2chosen: + logger.debug( + f" skipping flash {node.labels[0] if node.labels else node.name} (chosen)" + ) + continue + + # Skip blocked flash compatibles (controllers, not actual flash devices) + if compatible[0] in BLOCKED_FLASH_COMPAT: + logger.debug( + f" skipping flash {node.labels[0] if node.labels else node.name} (blocked compat)" + ) + continue + + # Skip soc-nv-flash nodes whose parent is itself a flash device — the + # parent is the real Zephyr device (e.g. nxp,imx-flexspi-nor) and the + # child has no driver-instantiated symbol. + if "soc-nv-flash" in compatible and node.parent is not None: + parent_compat = [] + if "compatible" in node.parent.props: + parent_compat = node.parent.props["compatible"].to_strings() + parent_drivers = [] + for c in parent_compat: + underscored = c.replace(",", "_").replace("-", "_") + d = COMPAT_TO_DRIVER.get(underscored) or MANUAL_COMPAT_TO_DRIVER.get(underscored) + if d: + parent_drivers.append(d) + if "flash" in parent_drivers: + logger.debug( + f" skipping flash {node.labels[0] if node.labels else node.name} (parent is flash device)" + ) + continue + + if node.labels: + flashes.append(node.labels[0]) + + logger.debug("Flash devices:") + for flash in flashes: + logger.debug(f" {flash}") + + return flashes + + +def _label_to_end(label): + return f"(uint32_t*) (DT_REG_ADDR(DT_NODELABEL({label})) + DT_REG_SIZE(DT_NODELABEL({label})))" + + +def find_ram_regions(device_tree): + """ + Find all RAM regions from a device tree. Includes the zephyr,sram node and + any zephyr,memory-region nodes. + + Returns: + List of RAM region info tuples: (label, start, end, size, path) + """ + rams = [] + chosen = None + # Get the chosen SRAM node directly + if "zephyr,sram" in device_tree.root.nodes["chosen"].props: + chosen = device_tree.root.nodes["chosen"].props["zephyr,sram"].to_path() + label = chosen.labels[0] + size = chosen.props["reg"].to_nums()[1] + logger.debug(f"Found chosen SRAM node: {label} with size {size}") + rams.append((label, "z_mapped_end", _label_to_end(label), size, chosen.path)) + + # Traverse all nodes in the device tree to find memory-region nodes + remaining_nodes = set([device_tree.root]) + while remaining_nodes: + node = remaining_nodes.pop() + + # Check status first so we don't add child nodes that aren't active. + status = node.props.get("status", None) + if status is None: + status = "okay" + else: + status = status.to_string() + + if status != "okay": + continue + + if node == chosen: + continue + + remaining_nodes.update(node.nodes.values()) + + if "compatible" not in node.props or not node.labels: + continue + + compatible = node.props["compatible"].to_strings() + + if "zephyr,memory-region" not in compatible or "zephyr,memory-region" not in node.props: + continue + + is_mmio_sram = "mmio-sram" in compatible + device_type = node.props.get("device_type") + has_memory_device_type = device_type and device_type.to_string() == "memory" + if not (is_mmio_sram or has_memory_device_type): + continue + + size = node.props["reg"].to_nums()[1] + + start = "__" + node.props["zephyr,memory-region"].to_string() + "_end" + end = _label_to_end(node.labels[0]) + + # Filter by minimum size + if size >= MINIMUM_RAM_SIZE: + logger.debug( + f"Adding extra RAM info: ({node.labels[0]}, {start}, {end}, {size}, {node.path})" + ) + info = (node.labels[0], start, end, size, node.path) + rams.append(info) + + return rams + + +# gpio-keys nodes identify a key with `zephyr,code` rather than the optional and +# deprecated `label`, so the code is the only name a modern board gives. +INPUT_KEY_NAMES = {} + + +def _populate_input_key_names(): + header = ( + pathlib.Path(__file__).parent.parent + / "zephyr" + / "include" + / "zephyr" + / "dt-bindings" + / "input" + / "input-event-codes.h" + ) + if not header.exists(): + return + pattern = re.compile(r"^#define\s+INPUT_(?PKEY_\w+)\s+(?P\d+)") + for line in header.read_text().splitlines(): + match = pattern.match(line) + if match: + INPUT_KEY_NAMES.setdefault(int(match.group("code")), match.group("name")) + + +_populate_input_key_names() + @cpbuild.run_in_thread -def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 +def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfigboard=None): # noqa: C901 board_dir = builddir / "board" # Auto generate board files from device tree. board_info = { "wifi": False, "usb_device": False, + "_bleio": False, + "hostnetwork": board_id in ["native_sim"], + "audiobusio": False, } + config_bt_enabled = False + config_bt_found = False + config_present = True + config = zephyrbuilddir / ".config" + if not config.exists(): + config_present = False + else: + for line in config.read_text().splitlines(): + if line.startswith("CONFIG_BT="): + config_bt_enabled = line.strip().endswith("=y") + config_bt_found = True + break + if line.startswith("# CONFIG_BT is not set"): + config_bt_enabled = False + config_bt_found = True + break + runners = zephyrbuilddir / "runners.yaml" runners = yaml.safe_load(runners.read_text()) zephyr_board_dir = pathlib.Path(runners["config"]["board_dir"]) board_yaml = zephyr_board_dir / "board.yml" board_yaml = yaml.safe_load(board_yaml.read_text()) - board_info["vendor_id"] = board_yaml["board"]["vendor"] - vendor_index = zephyr_board_dir.parent / "index.rst" + if "board" not in board_yaml and "boards" in board_yaml: + for board in board_yaml["boards"]: + if board["name"] == board_id: + board_yaml = board + break + else: + board_yaml = board_yaml["board"] + board_info["vendor_id"] = board_yaml["vendor"] + # Most vendors put boards directly in boards//, but some group + # them further, like boards/silabs/dev_kits/. Walk up to the directory + # named for the vendor so we read the vendor's index.rst and not a category's. + vendor_dir = zephyr_board_dir.parent + for parent in zephyr_board_dir.parents: + if parent.name == board_info["vendor_id"]: + vendor_dir = parent + break + vendor_index = vendor_dir / "index.rst" if vendor_index.exists(): vendor_index = vendor_index.read_text() vendor_index = vendor_index.split("\n") @@ -116,9 +568,11 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 else: vendor_name = board_info["vendor_id"] board_info["vendor"] = vendor_name - soc_name = board_yaml["board"]["socs"][0]["name"] + soc_name = board_yaml["socs"][0]["name"] board_info["soc"] = soc_name - board_name = board_yaml["board"]["full_name"] + board_name = board_yaml["full_name"] + if mpconfigboard and "NAME" in mpconfigboard: + board_name = mpconfigboard["NAME"] board_info["name"] = board_name # board_id_yaml = zephyr_board_dir / (zephyr_board_dir.name + ".yaml") # board_id_yaml = yaml.safe_load(board_id_yaml.read_text()) @@ -126,27 +580,43 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 # board_name = board_id_yaml["name"] dts = zephyrbuilddir / "zephyr.dts" - edt_pickle = dtlib.DT(dts) + device_tree = dtlib.DT(dts) node2alias = {} - for alias in edt_pickle.alias2node: - node = edt_pickle.alias2node[alias] + for alias in device_tree.alias2node: + node = device_tree.alias2node[alias] if node not in node2alias: node2alias[node] = [] node2alias[node].append(alias) ioports = {} all_ioports = [] board_names = {} - flashes = [] - rams = [] status_led = None + status_led_inverted = False + boot_button = None path2chosen = {} chosen2path = {} + + # Find flash and RAM regions using extracted functions + flashes = find_flash_devices(device_tree) + rams = find_ram_regions(device_tree) # Returns filtered and sorted list + + # Store active Zephyr device labels per-driver so that we can make them available via board. + active_zephyr_devices = {} usb_num_endpoint_pairs = 0 - for k in edt_pickle.root.nodes["chosen"].props: - value = edt_pickle.root.nodes["chosen"].props[k] + ble_hardware_present = False + for k in device_tree.root.nodes["chosen"].props: + value = device_tree.root.nodes["chosen"].props[k] path2chosen[value.to_path()] = k chosen2path[k] = value.to_path() - remaining_nodes = set([edt_pickle.root]) + + chosen_display = chosen2path.get("zephyr,display") + if chosen_display is not None: + status = chosen_display.props.get("status", None) + if status is None or status.to_string() == "okay": + board_info["zephyr_display"] = True + board_info["displayio"] = True + + remaining_nodes = set([device_tree.root]) while remaining_nodes: node = remaining_nodes.pop() remaining_nodes.update(node.nodes.values()) @@ -161,52 +631,23 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 compatible = [] if "compatible" in node.props: compatible = node.props["compatible"].to_strings() - logger.debug(node.name, status) + logger.debug(f"{node.name}: {status}") + logger.debug(f"compatible: {compatible}") chosen = None if node in path2chosen: chosen = path2chosen[node] - logger.debug(" chosen:", chosen) + logger.debug(f" chosen: {chosen}") for c in compatible: underscored = c.replace(",", "_").replace("-", "_") driver = COMPAT_TO_DRIVER.get(underscored, None) - if "mmio" in c: - logger.debug(" ", c, node.labels, node.props) - address, size = node.props["reg"].to_nums() - end = address + size - if chosen == "zephyr,sram": - start = "z_mapped_end" - elif "zephyr,memory-region" in node.props: - start = "__" + node.props["zephyr,memory-region"].to_string() + "_end" - else: - # Check to see if the chosen sram is a subset of this region. If it is, - # then do as above for a smaller region and assume the rest is reserved. - chosen_sram = chosen2path["zephyr,sram"] - chosen_address, chosen_size = chosen_sram.props["reg"].to_nums() - chosen_end = chosen_address + chosen_size - if address <= chosen_address <= end and address <= chosen_end <= end: - start = "z_mapped_end" - address = chosen_address - size = chosen_size - end = chosen_end - else: - start = address - info = (node.labels[0], start, end, size, node.path) - if chosen == "zephyr,sram": - rams.insert(0, info) - else: - rams.append(info) if not driver: driver = MANUAL_COMPAT_TO_DRIVER.get(underscored, None) - logger.debug(" ", underscored, driver) - if not driver: + logger.debug(f" {c} -> {underscored} -> {driver}") + if not driver or status != "okay": continue - if driver == "flash" and status == "okay": - if not chosen and compatible[0] not in BLOCKED_FLASH_COMPAT: - # Skip chosen nodes because they are used by Zephyr. - flashes.append(f"DEVICE_DT_GET(DT_NODELABEL({node.labels[0]}))") - else: - logger.debug(" skipping due to blocked compat") - if driver == "usb/udc" and status == "okay": + if driver == "flash": + pass # Handled by find_flash_devices() + elif driver == "usb/udc" or "zephyr_udc0" in node.labels: board_info["usb_device"] = True props = node.props if "num-bidir-endpoints" not in props: @@ -220,8 +661,28 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 single_direction_endpoints.append(props[eps].to_num() if eps in props else 0) # Count separate in/out pairs as bidirectional. usb_num_endpoint_pairs += min(single_direction_endpoints) - if driver.startswith("wifi") and status == "okay": + elif driver.startswith("wifi"): board_info["wifi"] = True + elif driver == "bluetooth/hci": + ble_hardware_present = True + elif driver in AUDIOBUSIO_CLASSES: + # audiobusio driver (i2s, audio/dmic) + board_info["audiobusio"] = True + logger.info(f"Supported audiobusio driver: {driver}") + if driver not in active_zephyr_devices: + active_zephyr_devices[driver] = [] + active_zephyr_devices[driver].append(node.labels) + elif driver in EXCEPTIONAL_DRIVERS: + pass + elif driver in BUSIO_CLASSES: + # busio driver (i2c, spi, uart) + board_info["busio"] = True + logger.info(f"Supported busio driver: {driver}") + if driver not in active_zephyr_devices: + active_zephyr_devices[driver] = [] + active_zephyr_devices[driver].append(node.labels) + else: + logger.warning(f"Unsupported driver: {driver}") if gpio: if "ngpios" in node.props: @@ -231,22 +692,37 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 all_ioports.append(node.labels[0]) if status == "okay": ioports[node.labels[0]] = set(range(0, ngpios)) - if gpio_map: - i = 0 - for offset, t, label in gpio_map._markers: - if not label: - continue - num = int.from_bytes(gpio_map.value[offset + 4 : offset + 8], "big") - if (label, num) not in board_names: - board_names[(label, num)] = [] - board_names[(label, num)].append(CONNECTORS[compatible[0]][i]) - i += 1 + if gpio_map and compatible and compatible[0] != "gpio-nexus": + connector_pins = CONNECTORS.get(compatible[0], None) + if connector_pins is None: + logger.warning(f"Unsupported connector mapping compatible: {compatible[0]}") + else: + i = 0 + for offset, t, label in gpio_map._markers: + if not label: + continue + if i >= len(connector_pins): + logger.warning( + f"Connector mapping for {compatible[0]} has more pins than names; " + f"stopping at {len(connector_pins)}" + ) + break + num = int.from_bytes(gpio_map.value[offset + 4 : offset + 8], "big") + if (label, num) not in board_names: + board_names[(label, num)] = [] + pin_entry = connector_pins[i] + if isinstance(pin_entry, list): + board_names[(label, num)].extend(pin_entry) + else: + board_names[(label, num)].append(pin_entry) + i += 1 if "gpio-leds" in compatible: for led in node.nodes: led = node.nodes[led] props = led.props ioport = props["gpios"]._markers[1][2] num = int.from_bytes(props["gpios"].value[4:8], "big") + flags = int.from_bytes(props["gpios"].value[8:12], "big") if "label" in props: if (ioport, num) not in board_names: board_names[(ioport, num)] = [] @@ -257,31 +733,55 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 if "led0" in node2alias[led]: board_names[(ioport, num)].append("LED") status_led = (ioport, num) + status_led_inverted = flags & GPIO_ACTIVE_LOW board_names[(ioport, num)].extend(node2alias[led]) if "gpio-keys" in compatible: for key in node.nodes: - props = node.nodes[key].props + key_node = node.nodes[key] + props = key_node.props ioport = props["gpios"]._markers[1][2] num = int.from_bytes(props["gpios"].value[4:8], "big") if (ioport, num) not in board_names: board_names[(ioport, num)] = [] - board_names[(ioport, num)].append(props["label"].to_string()) - if key in node2alias: - if "sw0" in node2alias[key]: + # `label` is optional and deprecated on gpio-keys. Modern + # boards identify keys with `zephyr,code`, so fall back to the + # name of that code. + if "label" in props: + board_names[(ioport, num)].append(props["label"].to_string()) + elif "zephyr,code" in props: + key_code = props["zephyr,code"].to_num() + if key_code in INPUT_KEY_NAMES: + board_names[(ioport, num)].append(INPUT_KEY_NAMES[key_code]) + if key_node in node2alias: + aliases = node2alias[key_node] + if "sw0" in aliases: board_names[(ioport, num)].append("BUTTON") - board_names[(ioport, num)].extend(node2alias[key]) - - a, b = all_ioports[:2] - i = 0 - while a[i] == b[i]: - i += 1 - shared_prefix = a[:i] - for ioport in ioports: - if not ioport.startswith(shared_prefix): - shared_prefix = "" - break + # The sw0 alias designates the conventional first user + # button, so prefer it as the boot button. + boot_button = (ioport, num) + board_names[(ioport, num)].extend(aliases) + # Default to the first button in device tree order when no sw0 + # alias has designated one yet. + if boot_button is None: + boot_button = (ioport, num) + + if len(all_ioports) > 1: + a, b = all_ioports[:2] + i = 0 + max_i = min(len(a), len(b)) + while i < max_i and a[i] == b[i]: + i += 1 + shared_prefix = a[:i] + for ioport in ioports: + if not ioport.startswith(shared_prefix): + shared_prefix = "" + break + elif all_ioports: + shared_prefix = all_ioports[0] + else: + shared_prefix = "" pin_defs = [] pin_declarations = ["#pragma once"] @@ -292,6 +792,8 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 pin_object_name = f"P{ioport[len(shared_prefix) :].upper()}_{num:02d}" if status_led and (ioport, num) == status_led: status_led = pin_object_name + if boot_button and (ioport, num) == boot_button: + boot_button = pin_object_name pin_defs.append( f"const mcu_pin_obj_t pin_{pin_object_name} = {{ .base.type = &mcu_pin_type, .port = DEVICE_DT_GET(DT_NODELABEL({ioport})), .number = {num}}};" ) @@ -302,7 +804,13 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 board_pin_names = board_names.get((ioport, num), []) for board_pin_name in board_pin_names: - board_pin_name = board_pin_name.upper().replace(" ", "_").replace("-", "_") + board_pin_name = ( + board_pin_name.upper() + .replace(" ", "_") + .replace("-", "_") + .replace("(", "") + .replace(")", "") + ) board_pin_mapping.append( f"{{ MP_ROM_QSTR(MP_QSTR_{board_pin_name}), MP_ROM_PTR(&pin_{pin_object_name}) }}," ) @@ -312,33 +820,176 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 board_pin_mapping = "\n ".join(board_pin_mapping) mcu_pin_mapping = "\n ".join(mcu_pin_mapping) + zephyr_binding_headers = [] + zephyr_binding_objects = [] + zephyr_binding_labels = [] + i2sout_instance_names = [] + for driver, instances in active_zephyr_devices.items(): + # Determine if this is busio or audiobusio + if driver in BUSIO_CLASSES: + module = "busio" + driverclass = BUSIO_CLASSES[driver] + elif driver in AUDIOBUSIO_CLASSES: + module = "audiobusio" + driverclass = AUDIOBUSIO_CLASSES[driver] + else: + continue + + zephyr_binding_headers.append(f'#include "shared-bindings/{module}/{driverclass}.h"') + + # Designate a main device such as board.I2C or board.I2S. + if len(instances) == 1: + instances[0].append(driverclass) + else: + # Check to see if a main device has already been designated + found_main = False + for labels in instances: + for label in labels: + if label == driverclass: + found_main = True + if not found_main: + for priority_label in (f"zephyr_{driver}", f"arduino_{driver}"): + for labels in instances: + if priority_label in labels: + labels.append(driverclass) + found_main = True + break + if found_main: + break + for labels in instances: + instance_name = f"{driver.replace('/', '_')}_{labels[0]}" + c_function_name = f"_{instance_name}" + singleton_ptr = f"{c_function_name}_singleton" + function_object = f"{c_function_name}_obj" + obj_type = f"{module}_{driverclass.lower()}" + + # Handle special cases for different drivers + if driver == "serial": + # UART needs a receiver buffer + buffer_decl = f"static byte {instance_name}_buffer[128];" + construct_call = f"common_hal_busio_uart_construct_from_device(&{instance_name}_obj, DEVICE_DT_GET(DT_NODELABEL({labels[0]})), 128, {instance_name}_buffer)" + else: + # Default case (I2C, SPI, I2S) + buffer_decl = "" + construct_call = f"common_hal_{module}_{driverclass.lower()}_construct_from_device(&{instance_name}_obj, DEVICE_DT_GET(DT_NODELABEL({labels[0]})))" + + if driver == "i2s": + i2sout_instance_names.append(instance_name) + + zephyr_binding_objects.append( + f"""{buffer_decl} +static {obj_type}_obj_t {instance_name}_obj; +static mp_obj_t {singleton_ptr} = mp_const_none; +static mp_obj_t {c_function_name}(void) {{ + if ({singleton_ptr} != mp_const_none) {{ + return {singleton_ptr}; + }} + {singleton_ptr} = {construct_call}; + return {singleton_ptr}; +}} +static MP_DEFINE_CONST_FUN_OBJ_0({function_object}, {c_function_name});""".lstrip() + ) + for label in labels: + zephyr_binding_labels.append( + f"{{ MP_ROM_QSTR(MP_QSTR_{label.upper()}), MP_ROM_PTR(&{function_object}) }}," + ) + zephyr_binding_headers = "\n".join(zephyr_binding_headers) + zephyr_binding_objects = "\n".join(zephyr_binding_objects) + zephyr_binding_labels = "\n".join(zephyr_binding_labels) + + # Generate i2sout_reset() that stops all board I2SOut instances + if i2sout_instance_names: + stop_calls = "\n ".join( + f"common_hal_audiobusio_i2sout_stop(&{name}_obj);" for name in i2sout_instance_names + ) + i2sout_reset_func = f""" +void i2sout_reset(void) {{ + {stop_calls} +}}""" + else: + i2sout_reset_func = "" + + zephyr_display_header = "" + zephyr_display_object = "" + zephyr_display_board_entry = "" + if board_info.get("zephyr_display", False): + zephyr_display_header = """ +#include +#include +#include "shared-module/displayio/__init__.h" +#include "bindings/zephyr_display/Display.h" + """.strip() + zephyr_display_object = """ +void board_init(void) { +#if CIRCUITPY_ZEPHYR_DISPLAY && DT_HAS_CHOSEN(zephyr_display) + // Always allocate a display slot so board.DISPLAY is at least a valid + // NoneType object even if the underlying Zephyr display is unavailable. + primary_display_t *display_obj = allocate_display(); + if (display_obj == NULL) { + return; + } + + zephyr_display_display_obj_t *display = &display_obj->zephyr_display; + display->base.type = &mp_type_NoneType; + + const struct device *display_dev = device_get_binding(DEVICE_DT_NAME(DT_CHOSEN(zephyr_display))); + if (display_dev == NULL || !device_is_ready(display_dev)) { + return; + } + + display->base.type = &zephyr_display_display_type; + common_hal_zephyr_display_display_construct_from_device(display, display_dev, 0, true); +#endif +} + """.strip() + zephyr_display_board_entry = ( + "{ MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].zephyr_display) }," + ) + board_dir.mkdir(exist_ok=True, parents=True) header = board_dir / "mpconfigboard.h" if status_led: status_led = f"#define MICROPY_HW_LED_STATUS (&pin_{status_led})\n" + status_led_inverted = ( + f"#define MICROPY_HW_LED_STATUS_INVERTED ({'1' if status_led_inverted else '0'})\n" + ) else: status_led = "" + status_led_inverted = "" + if boot_button: + boot_button = f"#define CIRCUITPY_BOOT_BUTTON (&pin_{boot_button})\n" + else: + boot_button = "" ram_list = [] ram_externs = [] max_size = 0 for ram in rams: device, start, end, size, path = ram max_size = max(max_size, size) - if isinstance(start, str): + # We always start at the end of a Zephyr linker section so we need the externs and &. + # Native/simulated boards don't have real memory-mapped RAM, so we allocate static arrays. + if board_id in ["native_sim"] or "bsim" in board_id: + ram_externs.append("// This is a native board so we provide all of RAM for our heaps.") + ram_externs.append(f"static uint32_t _{device}[{size // 4}]; // {path}") + start = f"(const uint32_t *) (_{device})" + end = f"(const uint32_t *)(_{device} + {size // 4})" + else: ram_externs.append(f"extern uint32_t {start};") start = "&" + start - else: - start = f"(uint32_t*) 0x{start:08x}" - ram_list.append(f" {start}, (uint32_t*) 0x{end:08x}, // {path}") + ram_list.append(f" {start}, {end}, // {path}") ram_list = "\n".join(ram_list) ram_externs = "\n".join(ram_externs) + flashes = [f"DEVICE_DT_GET(DT_NODELABEL({flash}))" for flash in flashes] + new_header_content = f"""#pragma once #define MICROPY_HW_BOARD_NAME "{board_name}" #define MICROPY_HW_MCU_NAME "{soc_name}" #define CIRCUITPY_RAM_DEVICE_COUNT {len(rams)} {status_led} +{status_led_inverted} +{boot_button} """ if not header.exists() or header.read_text() != new_header_content: header.write_text(new_header_content) @@ -348,16 +999,33 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 pins.write_text(pin_declarations) board_c = board_dir / "board.c" + hostnetwork_include = "" + hostnetwork_entry = "" + if board_info.get("hostnetwork", False): + hostnetwork_include = ( + '#if CIRCUITPY_HOSTNETWORK\n#include "bindings/hostnetwork/__init__.h"\n#endif\n' + ) + hostnetwork_entry = ( + "#if CIRCUITPY_HOSTNETWORK\n" + " { MP_ROM_QSTR(MP_QSTR_NETWORK), MP_ROM_PTR(&common_hal_hostnetwork_obj) },\n" + "#endif\n" + ) + new_board_c_content = f""" // This file is autogenerated by build_circuitpython.py #include "shared-bindings/board/__init__.h" +{hostnetwork_include} + #include #include "py/obj.h" #include "py/mphal.h" +{zephyr_binding_headers} +{zephyr_display_header} + const struct device* const flashes[] = {{ {", ".join(flashes)} }}; const int circuitpy_flash_device_count = {len(flashes)}; @@ -369,6 +1037,10 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 {pin_defs} +{zephyr_binding_objects} +{zephyr_display_object} +{i2sout_reset_func} + static const mp_rom_map_elem_t mcu_pin_globals_table[] = {{ {mcu_pin_mapping} }}; @@ -377,17 +1049,36 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 static const mp_rom_map_elem_t board_module_globals_table[] = {{ CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS +{hostnetwork_entry} +{zephyr_display_board_entry} {board_pin_mapping} -// {{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }}, +{zephyr_binding_labels} + }}; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); """ - if not board_c.exists() or new_board_c_content != board_c.read_text(): - board_c.write_text(new_board_c_content) + board_c.write_text(new_board_c_content) + if ble_hardware_present: + if not config_present: + raise RuntimeError( + "Missing Zephyr .config; CONFIG_BT must be set explicitly when BLE hardware is present." + ) + if not config_bt_found: + raise RuntimeError( + "CONFIG_BT is missing from Zephyr .config; set it explicitly when BLE hardware is present." + ) + + board_info["_bleio"] = ble_hardware_present and config_bt_enabled board_info["source_files"] = [board_c] board_info["cflags"] = ("-I", board_dir) board_info["flash_count"] = len(flashes) + board_info["rotaryio"] = bool(ioports) board_info["usb_num_endpoint_pairs"] = usb_num_endpoint_pairs + + # Detect NVM partition from the device tree. + nvm_node = device_tree.label2node.get("nvm_partition") + board_info["nvm"] = nvm_node is not None + return board_info diff --git a/ports/zephyr-cp/debug.conf b/ports/zephyr-cp/debug.conf new file mode 100644 index 00000000000..2f12db119f8 --- /dev/null +++ b/ports/zephyr-cp/debug.conf @@ -0,0 +1,52 @@ +CONFIG_DEBUG=y +CONFIG_DEBUG_OPTIMIZATIONS=y +CONFIG_LOG_MAX_LEVEL=4 + +CONFIG_STACK_SENTINEL=y +CONFIG_DEBUG_THREAD_INFO=y +CONFIG_EXCEPTION_STACK_TRACE=y + +CONFIG_ASSERT=y +CONFIG_LOG_BLOCK_IN_THREAD=y +CONFIG_FRAME_POINTER=y + +CONFIG_FLASH_LOG_LEVEL_DBG=y +CONFIG_LOG_MODE_IMMEDIATE=y + +# Quiet the UDC device-controller drivers in the debug build. The DWC2 driver +# logs "Prepare RX 0x%02x doeptsiz 0x%x" (LOG_INF) on every OUT endpoint RX +# prepare, which is noisy. Drop UDC_DRIVER to WRN to keep errors/warnings +# while compiling out INF/DBG. (Shared by all udc drivers; only one is active +# per board.) +CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y + +# Bluetooth: enable BT host debug logging so success paths print, not just +# LOG_ERR. In particular bt_keys logs "Stored keys for " (LOG_DBG) on a +# successful bt_keys_store(); without this only the failure message +# "Failed to save keys (err -116)" is visible. Also enable the adjacent +# modules (SMP drives pairing, BT_SETTINGS is the NVS backend that returns +# the store err) so the -EALREADY (-116) store-failure context is complete. +CONFIG_BT_KEYS_LOG_LEVEL_DBG=y +CONFIG_BT_SETTINGS_LOG_LEVEL_DBG=y +CONFIG_BT_SMP_LOG_LEVEL_DBG=y + +# Bump stacks for debug build - verbose logging consumes more stack. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 +CONFIG_MAIN_STACK_SIZE=32768 +CONFIG_ISR_STACK_SIZE=4096 +CONFIG_UDC_DWC2_STACK_SIZE=4096 +CONFIG_UDC_NRF_THREAD_STACK_SIZE=4096 +CONFIG_USBD_THREAD_STACK_SIZE=4096 +CONFIG_USBD_MSC_STACK_SIZE=4096 +CONFIG_IDLE_STACK_SIZE=1024 + +# Bluetooth stacks: debug logging + assertions + LOG_MODE_IMMEDIATE consume +# substantial extra stack in the BT host RX workqueue (runs all event callbacks, +# including SMP/pairing) and the long workqueue (deferred SMP/pairing/crypto + +# NVS bond-key store). Zephyr's own SMP/pairing test app +# (tests/bluetooth/tester/prj.conf) uses 4096 for BT_RX_STACK_SIZE. +# (BT_CTLR_RX_PRIO_STACK_SIZE is bumped in the Zephyr controller Kconfig +# default since it's a hidden symbol. BT_HCI_TX/BT_CTLR_RX are also hidden and +# haven't overflowed — left at their defaults.) +CONFIG_BT_RX_STACK_SIZE=4096 +CONFIG_BT_LONG_WQ_STACK_SIZE=4096 diff --git a/ports/zephyr-cp/docs/perfetto-tracing.md b/ports/zephyr-cp/docs/perfetto-tracing.md new file mode 100644 index 00000000000..ff35d361f70 --- /dev/null +++ b/ports/zephyr-cp/docs/perfetto-tracing.md @@ -0,0 +1,150 @@ +# Perfetto Tracing + +The Zephyr port supports Perfetto tracing for performance analysis. This document +describes how to capture, validate, and view traces. + +## Capturing Traces + +Traces are written to `circuitpython.perfetto-trace` in the port directory when +running with tracing enabled (e.g., on native_sim). + +## Validating Traces + +### Using trace_processor + +The Perfetto trace_processor tool can validate and query trace files: + +```bash +~/repos/perfetto/tools/trace_processor circuitpython.perfetto-trace +``` + +This will download the trace_processor binary if needed and open an interactive +SQL shell. If the trace loads successfully, you can query it: + +```sql +SELECT COUNT(*) FROM slice; +``` + +### Using the Perfetto UI + +Open https://ui.perfetto.dev and drag your trace file onto the page. + +## Debugging Invalid Traces + +### Common Error: Packets Skipped Due to Invalid Incremental State + +If trace_processor reports packets being skipped with messages like: + +``` +packet_skipped_seq_needs_incremental_state_invalid +``` + +This means packets have `SEQ_NEEDS_INCREMENTAL_STATE` (value 2) set but no +prior packet set `SEQ_INCREMENTAL_STATE_CLEARED` (value 1) to initialize the +incremental state. + +**Root Cause**: The process descriptor packet (which sets `SEQ_INCREMENTAL_STATE_CLEARED`) +must be emitted before any other trace packets. + +**Diagnosis**: Use protoc to inspect the raw trace: + +```bash +protoc --decode_raw < circuitpython.perfetto-trace | head -100 +``` + +Look for field 13 (sequence_flags) in the first few packets: + +- `13: 1` = SEQ_INCREMENTAL_STATE_CLEARED (good - should be first) +- `13: 2` = SEQ_NEEDS_INCREMENTAL_STATE (requires prior cleared packet) + +A valid trace should have the process descriptor with `13: 1` as one of the +first packets. + +**Fix**: Ensure `perfetto_start()` is called before any trace events are emitted. +The descriptor emit functions in `perfetto_encoder.c` should check: + +```c +if (!started) { + perfetto_start(); +} +``` + +### Analyzing Raw Trace Structure + +To understand the trace structure: + +```bash +# Count total packets +protoc --decode_raw < circuitpython.perfetto-trace | grep -c "^1 {" + +# Find all sequence_flags values +protoc --decode_raw < circuitpython.perfetto-trace | grep "13:" | sort | uniq -c + +# Look for track descriptors (field 60) +protoc --decode_raw < circuitpython.perfetto-trace | grep -A20 "60 {" + +# Look for process descriptors (field 3 inside track_descriptor) +protoc --decode_raw < circuitpython.perfetto-trace | grep -B5 "3 {" +``` + +### Key Protobuf Field Numbers + +TracePacket fields: + +| Field | Description | +|-------|-------------| +| 8 | timestamp | +| 10 | trusted_packet_sequence_id | +| 11 | track_event | +| 12 | interned_data | +| 13 | sequence_flags | +| 60 | track_descriptor | + +TrackDescriptor fields (inside field 60): + +| Field | Description | +|-------|-------------| +| 1 | uuid | +| 2 | name | +| 3 | process (ProcessDescriptor) | +| 4 | thread (ThreadDescriptor) | +| 5 | parent_uuid | + +## Build Verification + +After modifying tracing code, verify the build is updated: + +```bash +# Check source vs object file timestamps +ls -la zephyr/subsys/tracing/perfetto/perfetto_encoder.c +ls -la zephyr/build/zephyr/subsys/tracing/perfetto/CMakeFiles/subsys__tracing__perfetto.dir/perfetto_encoder.c.obj +``` + +The object file timestamp must be newer than the source file timestamp. If not, +rebuild the project before capturing a new trace. + +## Architecture + +The tracing implementation consists of: + +- `perfetto_encoder.c`: Encodes trace packets using nanopb +- `perfetto_top.c`: Implements Zephyr tracing hooks (sys_trace_*) +- `perfetto_encoder.h`: Public API and UUID definitions + +Key UUIDs: + +| Constant | Value | Description | +|----------|-------|-------------| +| PROCESS_UUID | 1 | Root process track | +| ISR_TRACK_UUID | 2 | Interrupt service routine track | +| TRACE_TRACK_UUID | 3 | Top-level trace track | + +### Initialization Flow + +1. `SYS_INIT` calls `perfetto_init()` at POST_KERNEL priority 0 +2. `perfetto_init()` calls `perfetto_encoder_init()` +3. `perfetto_initialized` is set to true +4. Thread hooks start firing +5. First emit function calls `perfetto_start()` +6. `perfetto_start()` emits process descriptor with `SEQ_INCREMENTAL_STATE_CLEARED` +7. Subsequent packets use `SEQ_NEEDS_INCREMENTAL_STATE` diff --git a/ports/zephyr-cp/mpconfigport.h b/ports/zephyr-cp/mpconfigport.h index 5b5b077a371..9e7bc62c0fe 100644 --- a/ports/zephyr-cp/mpconfigport.h +++ b/ports/zephyr-cp/mpconfigport.h @@ -17,6 +17,14 @@ #define CIRCUITPY_DEBUG_TINYUSB 0 +// NVM size is determined at runtime from the Zephyr partition table. +#define CIRCUITPY_INTERNAL_NVM_SIZE 1 + +// Disable native _Float16 handling for host builds. +#define MICROPY_FLOAT_USE_NATIVE_FLT16 (0) + +#define MICROPY_NLR_THUMB_USE_LONG_JUMP (1) + //////////////////////////////////////////////////////////////////////////////////////////////////// // This also includes mpconfigboard.h. diff --git a/ports/zephyr-cp/mphalport.h b/ports/zephyr-cp/mphalport.h index b3adf5830d0..ee696a4f043 100644 --- a/ports/zephyr-cp/mphalport.h +++ b/ports/zephyr-cp/mphalport.h @@ -13,7 +13,12 @@ #include "py/mpconfig.h" #include "supervisor/shared/tick.h" +#include + #define mp_hal_ticks_ms() ((mp_uint_t)supervisor_ticks_ms32()) -#define mp_hal_delay_us(us) NRFX_DELAY_US((uint32_t)(us)) + +static inline void mp_hal_delay_us(mp_uint_t us) { + k_busy_wait((uint32_t)us); +} bool mp_hal_stdin_any(void); diff --git a/ports/zephyr-cp/native_sim_build_Containerfile b/ports/zephyr-cp/native_sim_build_Containerfile new file mode 100644 index 00000000000..3cd1a677da3 --- /dev/null +++ b/ports/zephyr-cp/native_sim_build_Containerfile @@ -0,0 +1,40 @@ +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC +ENV PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig + +RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y --no-install-recommends \ + git cmake ninja-build gperf ccache dfu-util device-tree-compiler \ + wget python3 python3-dev python3-pip python3-venv python3-setuptools \ + python3-tk python3-wheel xz-utils file make gcc \ + gcc-multilib g++-multilib libc6-dev-i386 \ + libsdl2-dev:i386 libsdl2-image-dev:i386 \ + libmagic1 mtools pkg-config ca-certificates unzip \ + protobuf-compiler sudo \ + && rm -rf /var/lib/apt/lists/* + +# Remove the default ubuntu:24.04 'ubuntu' user (UID 1000) so 'dev' can take +# UID 1000 — required for --userns=keep-id to map host UID 1000 to 'dev'. +RUN userdel -r ubuntu 2>/dev/null || true \ + && useradd -m -u 1000 -s /bin/bash dev \ + && echo 'dev ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/dev \ + && chmod 440 /etc/sudoers.d/dev +USER dev +WORKDIR /home/dev + +RUN python3 -m venv /home/dev/.venv +ENV PATH="/home/dev/.venv/bin:${PATH}" +RUN pip install --no-cache-dir west pytest pyelftools pyyaml intelhex protobuf grpcio-tools + +# The repo is expected to be bind-mounted here at runtime: +# podman run -v ~/circuitpython:/home/dev/circuitpython:Z --userns=keep-id ... +# On first run, inside the container do: +# cd ~/circuitpython/ports/zephyr-cp +# west init -l zephyr-config +# west update +# west zephyr-export +# pip install -r zephyr/scripts/requirements.txt +# pip install -r ../../requirements-dev.txt +# west sdk install -t x86_64-zephyr-elf +# python ../../tools/ci_fetch_deps.py zephyr-cp +WORKDIR /home/dev/circuitpython/ports/zephyr-cp +CMD ["/bin/bash"] diff --git a/ports/zephyr-cp/native_sim_build_init_container.sh b/ports/zephyr-cp/native_sim_build_init_container.sh new file mode 100755 index 00000000000..19831e1fcc2 --- /dev/null +++ b/ports/zephyr-cp/native_sim_build_init_container.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# One-time setup to run INSIDE the zephyr-cp-dev container on the first +# launch against a fresh bind-mounted circuitpython checkout. +# +# Usage (inside the container): +# cd ~/circuitpython/ports/zephyr-cp +# ./native_sim_build_init_container.sh +# +# Safe to re-run; west/pip/etc. are idempotent. +set -euo pipefail + +git config --global --add safe.directory /home/dev/circuitpython + +cd "$(dirname "${BASH_SOURCE[0]}")" + +echo "==> west init" +if [ ! -d .west ]; then + west init -l zephyr-config +else + echo " (already initialized, skipping)" +fi + +echo "==> west update" +west update + +echo "==> west zephyr-export" +west zephyr-export + +echo "==> pip install Zephyr requirements" +pip install -r zephyr/scripts/requirements.txt + +echo "==> pip install CircuitPython dev requirements" +pip install -r ../../requirements-dev.txt + +echo "==> west sdk install (x86_64-zephyr-elf)" +west sdk install -t x86_64-zephyr-elf + +echo "==> fetch port submodules" +python ../../tools/ci_fetch_deps.py zephyr-cp + +echo +echo "First-run setup complete." +echo "You can now build with: make BOARD=native_native_sim" diff --git a/ports/zephyr-cp/native_sim_build_run_container.sh b/ports/zephyr-cp/native_sim_build_run_container.sh new file mode 100755 index 00000000000..e30aca22b46 --- /dev/null +++ b/ports/zephyr-cp/native_sim_build_run_container.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Launch (or re-attach to) the zephyr-cp-dev container with the enclosing +# circuitpython checkout bind-mounted at /home/dev/circuitpython. Works from +# any CWD — the mount is resolved relative to this script's location. +# +# On first invocation, creates a persistent container named "zcp". On +# subsequent invocations, re-starts the same container so installed state +# (e.g. the Zephyr SDK under /home/dev/zephyr-sdk-*) survives across sessions. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +CONTAINER_NAME="zcp" +IMAGE="zephyr-cp-dev" + +if podman container exists "$CONTAINER_NAME"; then + exec podman start -ai "$CONTAINER_NAME" +else + exec podman run -it --name "$CONTAINER_NAME" \ + -v "$REPO_ROOT:/home/dev/circuitpython:Z" \ + --userns=keep-id \ + "$IMAGE" "$@" +fi diff --git a/ports/zephyr-cp/native_sim_i2c_emul_control.c b/ports/zephyr-cp/native_sim_i2c_emul_control.c new file mode 100644 index 00000000000..de467122a7b --- /dev/null +++ b/ports/zephyr-cp/native_sim_i2c_emul_control.c @@ -0,0 +1,169 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Command-line control for enabling/disabling emulated I2C devices + * on native_sim. This allows testing device hot-plug and error scenarios. + */ + +#include +#include +#include +#include +#include +#include + +#include "nsi_cmdline.h" +#include "posix_native_task.h" + +LOG_MODULE_REGISTER(i2c_emul_control, LOG_LEVEL_INF); + +#define MAX_DISABLED_DEVICES 16 + +struct disabled_device { + const char *name; + const struct emul *emul; + struct i2c_emul_api mock_api; + bool disabled; +}; + +static struct disabled_device disabled_devices[MAX_DISABLED_DEVICES]; +static int num_disabled_devices = 0; + +static char *disabled_device_args[MAX_DISABLED_DEVICES]; +static int num_disabled_device_args = 0; + +/* + * Mock transfer function that returns -EIO (NACK) when device is disabled, + * or -ENOSYS to fall back to the real emulator. + */ +static int disabled_device_transfer(const struct emul *target, + struct i2c_msg *msgs, + int num_msgs, + int addr) { + ARG_UNUSED(msgs); + ARG_UNUSED(num_msgs); + ARG_UNUSED(addr); + + for (int i = 0; i < num_disabled_devices; i++) { + if (disabled_devices[i].emul == target) { + if (disabled_devices[i].disabled) { + LOG_DBG("Device %s is disabled, returning -EIO", + disabled_devices[i].name); + return -EIO; + } + break; + } + } + /* Fall back to normal emulator behavior */ + return -ENOSYS; +} + +int i2c_emul_control_disable_device(const char *name) { + const struct emul *emul = emul_get_binding(name); + if (!emul) { + LOG_ERR("Emulator '%s' not found", name); + return -ENODEV; + } + + if (emul->bus_type != EMUL_BUS_TYPE_I2C) { + LOG_ERR("Emulator '%s' is not an I2C device", name); + return -EINVAL; + } + + /* Find existing entry or create new one */ + int idx = -1; + for (int i = 0; i < num_disabled_devices; i++) { + if (disabled_devices[i].emul == emul) { + idx = i; + break; + } + } + + if (idx < 0) { + if (num_disabled_devices >= MAX_DISABLED_DEVICES) { + LOG_ERR("Too many disabled devices"); + return -ENOMEM; + } + idx = num_disabled_devices++; + disabled_devices[idx].name = name; + disabled_devices[idx].emul = emul; + disabled_devices[idx].mock_api.transfer = disabled_device_transfer; + + /* Install our mock_api to intercept transfers */ + emul->bus.i2c->mock_api = &disabled_devices[idx].mock_api; + } + + disabled_devices[idx].disabled = true; + LOG_INF("Disabled I2C emulator: %s", name); + return 0; +} + +int i2c_emul_control_enable_device(const char *name) { + for (int i = 0; i < num_disabled_devices; i++) { + if (strcmp(disabled_devices[i].name, name) == 0) { + disabled_devices[i].disabled = false; + LOG_INF("Enabled I2C emulator: %s", name); + return 0; + } + } + LOG_ERR("Device '%s' not in disabled list", name); + return -ENODEV; +} + +bool i2c_emul_control_is_disabled(const char *name) { + for (int i = 0; i < num_disabled_devices; i++) { + if (strcmp(disabled_devices[i].name, name) == 0) { + return disabled_devices[i].disabled; + } + } + return false; +} + +/* Command-line option handler */ +static void cmd_disable_i2c_device(char *argv, int offset) { + /* The value is at argv + offset (after the '=' in --disable-i2c=value) */ + char *value = argv + offset; + if (num_disabled_device_args < MAX_DISABLED_DEVICES) { + disabled_device_args[num_disabled_device_args++] = value; + } else { + printk("i2c_emul_control: Too many --disable-i2c arguments, ignoring: %s\n", value); + } +} + +static struct args_struct_t i2c_emul_args[] = { + { + .option = "disable-i2c", + .name = "device", + .type = 's', + .call_when_found = cmd_disable_i2c_device, + .descript = "Disable an emulated I2C device by name (can be repeated). " + "Example: --disable-i2c=bmi160" + }, + ARG_TABLE_ENDMARKER +}; + +static void register_cmdline_opts(void) { + nsi_add_command_line_opts(i2c_emul_args); +} + +/* Register command-line options early in boot */ +NATIVE_TASK(register_cmdline_opts, PRE_BOOT_1, 0); + +static int apply_disabled_devices(void) { + LOG_DBG("Applying %d disabled device(s)", num_disabled_device_args); + for (int i = 0; i < num_disabled_device_args; i++) { + int rc = i2c_emul_control_disable_device(disabled_device_args[i]); + if (rc != 0) { + LOG_WRN("Failed to disable I2C device '%s': %d", + disabled_device_args[i], rc); + } + } + return 0; +} + +/* + * Apply after emulators are initialized. + * I2C emulators are registered at POST_KERNEL level, so we need to run + * at APPLICATION level to ensure they exist. + */ +SYS_INIT(apply_disabled_devices, APPLICATION, 99); diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index f769d7dc6b8..80a28a9c272 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -1,28 +1,89 @@ -CONFIG_SYS_HEAP_RUNTIME_STATS=y +CONFIG_SYS_HEAP_RUNTIME_STATS=n CONFIG_FLASH=y CONFIG_FLASH_MAP=y -CONFIG_STD_C23=y +CONFIG_USE_DT_CODE_PARTITION=y CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_FLASH_MAP_LABELS=y CONFIG_MAIN_STACK_SIZE=24288 -CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 -CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 + +# The system workqueue is used by BT settings delayed store (NVS flash writes +# during bond key save). RRAM flash drivers on nRF54L need more than the +# default 1024 bytes to avoid stack overflow. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=3072 CONFIG_THREAD_STACK_INFO=y -CONFIG_STACK_SENTINEL=y -CONFIG_DEBUG_THREAD_INFO=y -CONFIG_DEBUG_INFO=y +CONFIG_ARCH_POSIX_UPDATE_STACK_INFO=y +CONFIG_STACK_SENTINEL=n +CONFIG_DEBUG_THREAD_INFO=n +CONFIG_EXCEPTION_STACK_TRACE=n + +CONFIG_USB_DEVICE_STACK_NEXT=y +CONFIG_USBD_CDC_ACM_CLASS=y +CONFIG_USBD_HID_SUPPORT=y +CONFIG_USBD_MSC_STACK_SIZE=1536 +CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n -CONFIG_USB_DEVICE_STACK=n +CONFIG_USBD_MSC_CLASS=y +CONFIG_USBD_MSC_LUNS_PER_INSTANCE=1 CONFIG_HWINFO=y CONFIG_REBOOT=y -CONFIG_ENTROPY_GENERATOR=y - -CONFIG_ASSERT=y +CONFIG_ASSERT=n CONFIG_LOG_BLOCK_IN_THREAD=y CONFIG_EVENTS=y + +CONFIG_SERIAL=y + +CONFIG_LOG=y +CONFIG_LOG_MAX_LEVEL=2 +CONFIG_FRAME_POINTER=n + +CONFIG_NET_HOSTNAME_ENABLE=y +CONFIG_NET_HOSTNAME_DYNAMIC=y +CONFIG_NET_HOSTNAME="circuitpython" + +CONFIG_DYNAMIC_THREAD=y +CONFIG_DYNAMIC_THREAD_ALLOC=y +CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y + +CONFIG_FPU=y + +CONFIG_MBEDTLS=y + +# Override Kconfig default not taking effect. The BLE file-transfer workflow +# packs up to BLEIO_PACKET_BUFFER_MAX_PACKET_SIZE (512) bytes per notification, +# so the L2CAP/ATT MTU must accommodate a 512-byte payload plus the 3-byte +# ATT header (opcode + handle). Without this the default with SMP is only 65, +# and notifications larger than the negotiated MTU fail with +# "No ATT channel for MTU". +CONFIG_BT_L2CAP_TX_MTU=515 +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_RX_STACK_SIZE=2048 +CONFIG_BT_LONG_WQ_STACK_SIZE=3072 +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_PSA_CRYPTO=y +CONFIG_PSA_WANT_ALG_SHA_1=y +CONFIG_PSA_WANT_ALG_SHA_256=y + +# Settings storage backend for BT bond keys +# SECTOR_COUNT is set high — the init code caps it to what fits in the storage +# partition: min(sector_count, partition_size / sector_size) +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_SETTINGS_NVS_SECTOR_COUNT=256 + +# Zephyr's host reserves a connection object for a connectable advertiser, and +# the controller sizes its RX node pool from this too. With the default of 1, +# user code cannot connect as a central or start a timed scan while the BLE +# workflow advertises. 5 matches nordic. About 2.9 KB of RAM per connection. +CONFIG_BT_MAX_CONN=5 + +# Number of stored bonds. The default of 1 means bonding to a second peer +# evicts the BLE workflow's bond (BT_KEYS_OVERWRITE_OLDEST). 3 matches +# espressif's NimBLE default; nordic keeps dozens. +CONFIG_BT_MAX_PAIRED=3 diff --git a/ports/zephyr-cp/socs/nrf5340_cpuapp.conf b/ports/zephyr-cp/socs/nrf5340_cpuapp.conf index bf70997d83f..734d26db8e9 100644 --- a/ports/zephyr-cp/socs/nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/socs/nrf5340_cpuapp.conf @@ -1,4 +1,3 @@ -CONFIG_NRFX_UARTE0=y -CONFIG_NRFX_UARTE1=y +CONFIG_NRFX_UARTE=y CONFIG_NRFX_POWER=y diff --git a/ports/zephyr-cp/socs/stm32h7b3xx.conf b/ports/zephyr-cp/socs/stm32h7b3xx.conf index 3c7daeb753d..14a93b52ce8 100644 --- a/ports/zephyr-cp/socs/stm32h7b3xx.conf +++ b/ports/zephyr-cp/socs/stm32h7b3xx.conf @@ -1,4 +1 @@ -CONFIG_USE_STM32_LL_USB=y -CONFIG_USE_STM32_HAL_PCD=y - CONFIG_MEMC=y diff --git a/ports/zephyr-cp/socs/stm32u575xx.conf b/ports/zephyr-cp/socs/stm32u575xx.conf index 78cefbfef40..e69de29bb2d 100644 --- a/ports/zephyr-cp/socs/stm32u575xx.conf +++ b/ports/zephyr-cp/socs/stm32u575xx.conf @@ -1,2 +0,0 @@ -CONFIG_USE_STM32_LL_USB=y -CONFIG_USE_STM32_HAL_PCD=y diff --git a/ports/zephyr-cp/supervisor/flash.c b/ports/zephyr-cp/supervisor/flash.c index 6b893f89abe..a13bb3cffcb 100644 --- a/ports/zephyr-cp/supervisor/flash.c +++ b/ports/zephyr-cp/supervisor/flash.c @@ -21,7 +21,7 @@ #include #define CIRCUITPY_PARTITION circuitpy_partition -static struct flash_area *filesystem_area = NULL; +static const struct flash_area *filesystem_area = NULL; #if !FIXED_PARTITION_EXISTS(CIRCUITPY_PARTITION) static struct flash_area _dynamic_area; @@ -31,15 +31,14 @@ static struct flash_area _dynamic_area; extern const struct device *const flashes[]; extern const int circuitpy_flash_device_count; -// Size of an erase area +// Size of an erase page. static size_t _page_size; -// Size of a write area -static size_t _row_size; +// The value a flash byte has after being erased (usually 0xFF, but can differ). +static uint8_t _erase_value; -// Number of file system blocks in a page. +// Number of FILESYSTEM_BLOCK_SIZE blocks in an erase page. static size_t _blocks_per_page; -static size_t _rows_per_block; static uint32_t _page_mask; #define NO_PAGE_LOADED 0xFFFFFFFF @@ -49,14 +48,41 @@ static uint32_t _current_page_address; static uint32_t _scratch_page_address; -// Track which blocks (up to 32) in the current sector currently live in the -// cache. -static uint32_t _dirty_mask; -static uint32_t _loaded_mask; +// Per-block flags packed into a uint8_t array (one byte per block). +#define ROW_LOADED 0x01 // Block data is present in the cache. +#define ROW_DIRTY 0x02 // Block has been modified since last flush. +#define ROW_ERASED 0x04 // Block is all 0xFF; no need to write after erase. + +static uint8_t *_row_flags = NULL; + +static inline void _clear_row_flags(void) { + if (_row_flags != NULL) { + memset(_row_flags, 0, _blocks_per_page); + } +} + +static inline bool _any_dirty(void) { + for (size_t i = 0; i < _blocks_per_page; i++) { + if (_row_flags[i] & ROW_DIRTY) { + return true; + } + } + return false; +} + +// Check if a buffer is entirely the erase value. +static bool _buffer_is_erased(const uint8_t *buf, size_t len) { + for (size_t i = 0; i < len; i++) { + if (buf[i] != _erase_value) { + return false; + } + } + return true; +} // Table of pointers to each cached block. Should be zero'd after allocation. -#define FLASH_CACHE_TABLE_NUM_ENTRIES (_blocks_per_page * _rows_per_block) -#define FLASH_CACHE_TABLE_SIZE (FLASH_CACHE_TABLE_NUM_ENTRIES * sizeof (uint8_t *)) +#define FLASH_CACHE_TABLE_NUM_ENTRIES (_blocks_per_page) +#define FLASH_CACHE_TABLE_SIZE (FLASH_CACHE_TABLE_NUM_ENTRIES * sizeof(uint8_t *)) static uint8_t **flash_cache_table = NULL; static K_MUTEX_DEFINE(_mutex); @@ -111,6 +137,10 @@ void supervisor_flash_init(void) { const struct device *d = flashes[i]; printk("flash %p %s\n", d, d->name); + if (!device_is_ready(d)) { + printk(" not ready\n"); + continue; + } if (covered_by_areas[i]) { printk(" covered by flash area\n"); continue; @@ -167,52 +197,44 @@ void supervisor_flash_init(void) { return; } - const struct device *d = flash_area_get_device(filesystem_area); - _row_size = flash_get_write_block_size(d); - if (_row_size < 256) { - if (256 % _row_size == 0) { - _row_size = 256; - } else { - size_t new_row_size = _row_size; - while (new_row_size < 256) { - new_row_size += _row_size; - } - _row_size = new_row_size; - } - } struct flash_pages_info first_info; + const struct device *d = flash_area_get_device(filesystem_area); + const struct flash_parameters *fp = flash_get_parameters(d); + _erase_value = fp->erase_value; flash_get_page_info_by_offs(d, filesystem_area->fa_off, &first_info); struct flash_pages_info last_info; - flash_get_page_info_by_offs(d, filesystem_area->fa_off + filesystem_area->fa_size - _row_size, &last_info); + flash_get_page_info_by_offs(d, filesystem_area->fa_off + filesystem_area->fa_size - FILESYSTEM_BLOCK_SIZE, &last_info); _page_size = first_info.size; if (_page_size < FILESYSTEM_BLOCK_SIZE) { _page_size = FILESYSTEM_BLOCK_SIZE; } - printk(" erase page size %d\n", _page_size); - // Makes sure that a cached page has 32 or fewer rows. Our dirty mask is - // only 32 bits. - while (_page_size / _row_size > 32) { - _row_size *= 2; - } - printk(" write row size %d\n", _row_size); _blocks_per_page = _page_size / FILESYSTEM_BLOCK_SIZE; - printk(" blocks per page %d\n", _blocks_per_page); - _rows_per_block = FILESYSTEM_BLOCK_SIZE / _row_size; _page_mask = ~(_page_size - 1); + printk(" erase page size %d\n", _page_size); + printk(" blocks per page %d\n", _blocks_per_page); + + _row_flags = port_malloc(_blocks_per_page, false); + if (_row_flags == NULL) { + printk("Unable to allocate row flags (%d bytes)\n", _blocks_per_page); + filesystem_area = NULL; + return; + } + memset(_row_flags, 0, _blocks_per_page); + // The last page is the scratch sector. - _scratch_page_address = last_info.start_offset; + _scratch_page_address = last_info.start_offset - filesystem_area->fa_off; _current_page_address = NO_PAGE_LOADED; } uint32_t supervisor_flash_get_block_size(void) { - return 512; + return FILESYSTEM_BLOCK_SIZE; } uint32_t supervisor_flash_get_block_count(void) { if (filesystem_area == NULL) { return 0; } - return (_scratch_page_address - filesystem_area->fa_off) / 512; + return _scratch_page_address / FILESYSTEM_BLOCK_SIZE; } @@ -241,10 +263,8 @@ static bool write_flash(uint32_t address, const uint8_t *data, uint32_t data_len static bool block_erased(uint32_t sector_address) { uint8_t short_buffer[4]; if (read_flash(sector_address, short_buffer, 4)) { - for (uint16_t i = 0; i < 4; i++) { - if (short_buffer[i] != 0xff) { - return false; - } + if (!_buffer_is_erased(short_buffer, 4)) { + return false; } } else { return false; @@ -253,10 +273,8 @@ static bool block_erased(uint32_t sector_address) { // Now check the full length. uint8_t full_buffer[FILESYSTEM_BLOCK_SIZE]; if (read_flash(sector_address, full_buffer, FILESYSTEM_BLOCK_SIZE)) { - for (uint16_t i = 0; i < FILESYSTEM_BLOCK_SIZE; i++) { - if (short_buffer[i] != 0xff) { - return false; - } + if (!_buffer_is_erased(full_buffer, FILESYSTEM_BLOCK_SIZE)) { + return false; } } else { return false; @@ -274,17 +292,26 @@ static bool erase_page(uint32_t sector_address) { return res == 0; } -// Sector is really 24 bits. static bool copy_block(uint32_t src_address, uint32_t dest_address) { - // Copy row by row to minimize RAM buffer. - uint8_t buffer[_row_size]; - for (uint32_t i = 0; i < FILESYSTEM_BLOCK_SIZE / _row_size; i++) { - if (!read_flash(src_address + i * _row_size, buffer, _row_size)) { - return false; - } - if (!write_flash(dest_address + i * _row_size, buffer, _row_size)) { - return false; - } + uint8_t buffer[FILESYSTEM_BLOCK_SIZE]; + if (!read_flash(src_address, buffer, FILESYSTEM_BLOCK_SIZE)) { + return false; + } + if (!write_flash(dest_address, buffer, FILESYSTEM_BLOCK_SIZE)) { + return false; + } + return true; +} + +// Load a block into the ram cache and set its flags. Returns false on read error. +static bool _load_block_into_cache(size_t block_index) { + if (!read_flash(_current_page_address + block_index * FILESYSTEM_BLOCK_SIZE, + flash_cache_table[block_index], FILESYSTEM_BLOCK_SIZE)) { + return false; + } + _row_flags[block_index] |= ROW_LOADED; + if (_buffer_is_erased(flash_cache_table[block_index], FILESYSTEM_BLOCK_SIZE)) { + _row_flags[block_index] |= ROW_ERASED; } return true; } @@ -299,12 +326,12 @@ static bool flush_scratch_flash(void) { // cached. bool copy_to_scratch_ok = true; for (size_t i = 0; i < _blocks_per_page; i++) { - if ((_dirty_mask & (1 << i)) == 0) { + if (!(_row_flags[i] & ROW_DIRTY)) { copy_to_scratch_ok = copy_to_scratch_ok && copy_block(_current_page_address + i * FILESYSTEM_BLOCK_SIZE, _scratch_page_address + i * FILESYSTEM_BLOCK_SIZE); } - _loaded_mask |= (1 << i); + _row_flags[i] |= ROW_LOADED; } if (!copy_to_scratch_ok) { // TODO(tannewt): Do more here. We opted to not erase and copy bad data @@ -337,7 +364,7 @@ static void release_ram_cache(void) { port_free(flash_cache_table); flash_cache_table = NULL; _current_page_address = NO_PAGE_LOADED; - _loaded_mask = 0; + _clear_row_flags(); } // Attempts to allocate a new set of page buffers for caching a full sector in @@ -346,7 +373,7 @@ static void release_ram_cache(void) { static bool allocate_ram_cache(void) { flash_cache_table = port_malloc(FLASH_CACHE_TABLE_SIZE, false); if (flash_cache_table == NULL) { - // Not enough space even for the cache table. + printk("Unable to allocate ram cache table\n"); return false; } @@ -355,21 +382,20 @@ static bool allocate_ram_cache(void) { bool success = true; for (size_t i = 0; i < _blocks_per_page && success; i++) { - for (size_t j = 0; j < _rows_per_block && success; j++) { - uint8_t *page_cache = port_malloc(_row_size, false); - if (page_cache == NULL) { - success = false; - break; - } - flash_cache_table[i * _rows_per_block + j] = page_cache; + uint8_t *block_cache = port_malloc(FILESYSTEM_BLOCK_SIZE, false); + if (block_cache == NULL) { + success = false; + break; } + flash_cache_table[i] = block_cache; } // We couldn't allocate enough so give back what we got. if (!success) { + printk("Unable to allocate ram cache pages\n"); release_ram_cache(); } - _loaded_mask = 0; + _clear_row_flags(); _current_page_address = NO_PAGE_LOADED; return success; } @@ -382,7 +408,7 @@ static bool flush_ram_cache(bool keep_cache) { return true; } - if (_current_page_address == NO_PAGE_LOADED || _dirty_mask == 0) { + if (_current_page_address == NO_PAGE_LOADED || !_any_dirty()) { if (!keep_cache) { release_ram_cache(); } @@ -393,21 +419,12 @@ static bool flush_ram_cache(bool keep_cache) { // erase below. bool copy_to_ram_ok = true; for (size_t i = 0; i < _blocks_per_page; i++) { - if ((_loaded_mask & (1 << i)) == 0) { - for (size_t j = 0; j < _rows_per_block; j++) { - copy_to_ram_ok = read_flash( - _current_page_address + (i * _rows_per_block + j) * _row_size, - flash_cache_table[i * _rows_per_block + j], - _row_size); - if (!copy_to_ram_ok) { - break; - } + if (!(_row_flags[i] & ROW_LOADED)) { + if (!_load_block_into_cache(i)) { + copy_to_ram_ok = false; + break; } } - if (!copy_to_ram_ok) { - break; - } - _loaded_mask |= (1 << i); } if (!copy_to_ram_ok) { @@ -417,14 +434,19 @@ static bool flush_ram_cache(bool keep_cache) { erase_page(_current_page_address); // Lastly, write all the data in ram that we've cached. for (size_t i = 0; i < _blocks_per_page; i++) { - for (size_t j = 0; j < _rows_per_block; j++) { - write_flash(_current_page_address + (i * _rows_per_block + j) * _row_size, - flash_cache_table[i * _rows_per_block + j], - _row_size); + // Skip blocks that are entirely erased — the page erase already + // set them to 0xFF so writing would be redundant. + if (_row_flags[i] & ROW_ERASED) { + continue; } + write_flash(_current_page_address + i * FILESYSTEM_BLOCK_SIZE, + flash_cache_table[i], + FILESYSTEM_BLOCK_SIZE); + } + // Nothing is dirty anymore. Clear dirty but keep loaded and erased. + for (size_t i = 0; i < _blocks_per_page; i++) { + _row_flags[i] &= ~ROW_DIRTY; } - // Nothing is dirty anymore. Some may already be in the cache cleanly. - _dirty_mask = 0; // We're done with the cache for now so give it back. if (!keep_cache) { @@ -487,15 +509,10 @@ static bool _flash_read_block(uint8_t *dest, uint32_t block) { // Mask out the lower bits that designate the address within the sector. uint32_t page_address = address & _page_mask; size_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % _blocks_per_page; - uint32_t mask = 1 << (block_index); // We're reading from the currently cached sector. - if (_current_page_address == page_address && (mask & _loaded_mask) > 0) { + if (_current_page_address == page_address && (_row_flags[block_index] & ROW_LOADED)) { if (flash_cache_table != NULL) { - for (int i = 0; i < _rows_per_block; i++) { - memcpy(dest + i * _row_size, - flash_cache_table[block_index * _rows_per_block + i], - _row_size); - } + memcpy(dest, flash_cache_table[block_index], FILESYSTEM_BLOCK_SIZE); return true; } uint32_t scratch_block_address = _scratch_page_address + block_index * FILESYSTEM_BLOCK_SIZE; @@ -514,7 +531,6 @@ static bool _flash_write_block(const uint8_t *data, uint32_t block) { // Mask out the lower bits that designate the address within the sector. uint32_t page_address = address & _page_mask; size_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % _blocks_per_page; - uint32_t mask = 1 << (block_index); // Flush the cache if we're moving onto a different page. if (_current_page_address != page_address) { // Check to see if we'd write to an erased block and aren't writing to @@ -529,19 +545,12 @@ static bool _flash_write_block(const uint8_t *data, uint32_t block) { erase_page(_scratch_page_address); } _current_page_address = page_address; - _dirty_mask = 0; - _loaded_mask = 0; + _clear_row_flags(); } - _dirty_mask |= mask; - _loaded_mask |= mask; - + _row_flags[block_index] = ROW_DIRTY | ROW_LOADED; // Copy the block to the appropriate cache. if (flash_cache_table != NULL) { - for (int i = 0; i < _rows_per_block; i++) { - memcpy(flash_cache_table[block_index * _rows_per_block + i], - data + i * _row_size, - _row_size); - } + memcpy(flash_cache_table[block_index], data, FILESYSTEM_BLOCK_SIZE); return true; } else { uint32_t scratch_block_address = _scratch_page_address + block_index * FILESYSTEM_BLOCK_SIZE; diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 860584c2b19..e26f256bb2b 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -7,15 +7,44 @@ #include "supervisor/port.h" #include "mpconfigboard.h" +#include "supervisor/shared/tick.h" + +#if CIRCUITPY_AUDIOBUSIO_I2SOUT +#include "common-hal/audiobusio/I2SOut.h" +#endif + +#include #include #include #include +#include + +#if defined(CONFIG_ARCH_POSIX) +#include +#include +#include + +#include "cmdline.h" +#include "nsi_host_trampolines.h" +#include "posix_board_if.h" +#include "posix_native_task.h" +#endif #include "lib/tlsf/tlsf.h" #include +#include + +#if defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM) +#include "perfetto_encoder.h" +#include +#define CIRCUITPY_PERFETTO_TRACK_GROUP_UUID 0x3000ULL +#define CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID 0x3001ULL +#define CIRCUITPY_PERFETTO_OUTER_HEAP_USED_UUID 0x3002ULL +#endif static tlsf_t heap; +static size_t tlsf_heap_used = 0; // Auto generated in pins.c extern const struct device *const rams[]; @@ -23,15 +52,178 @@ extern const uint32_t *const ram_bounds[]; extern const size_t circuitpy_max_ram_size; static pool_t pools[CIRCUITPY_RAM_DEVICE_COUNT]; +static uint8_t valid_pool_count = 0; +static bool zephyr_malloc_active = false; +static void *zephyr_malloc_top = NULL; +static void *zephyr_malloc_bottom = NULL; static K_EVENT_DEFINE(main_needed); +static struct k_timer tick_timer; + +#if defined(CONFIG_ARCH_POSIX) +// Number of VM runs before exiting. +// <= 0 means run forever. +// INT32_MAX means option was not provided. +static int32_t native_sim_port_resets = INT32_MAX; +static uint32_t native_sim_reset_port_count = 0; + +// Path to a file used to preserve retained memory across the execv reboot, or +// NULL if disabled. Set with --retained-memory= (see +// cp_retained_save/restore()). +static const char *native_sim_retained_memory; + +typedef struct { + uint32_t saved_word; + uint32_t port_reset_count; +} cp_retained_data_t; + +static struct args_struct_t native_sim_port_args[] = { + { + .option = "port-resets", + .name = "count", + .type = 'i', + .dest = &native_sim_port_resets, + .descript = "Exit native_sim after this many port_reset() calls. " + "Example: --port-resets=2" + }, + { + .option = "retained-memory", + .name = "path", + .type = 's', + .dest = (void *)&native_sim_retained_memory, + .descript = "File used to preserve some state" + " across the process re-exec reboot. " + "Example: --retained-memory=/tmp/cp_retained.bin" + }, + ARG_TABLE_ENDMARKER +}; + +static void native_sim_register_cmdline_opts(void) { + native_add_command_line_opts(native_sim_port_args); +} + +NATIVE_TASK(native_sim_register_cmdline_opts, PRE_BOOT_1, 0); +#endif + +#if defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM) +static bool perfetto_circuitpython_tracks_emitted; + +static void perfetto_emit_outer_heap_stats(void) { + if (!perfetto_start()) { + return; + } + size_t total = tlsf_heap_used; + #if defined(CONFIG_COMMON_LIBC_MALLOC) && defined(CONFIG_SYS_HEAP_RUNTIME_STATS) + extern int malloc_runtime_stats_get(struct sys_memory_stats *stats); + struct sys_memory_stats stats; + if (malloc_runtime_stats_get(&stats) == 0) { + total += stats.allocated_bytes; + } + #endif + perfetto_emit_counter(CIRCUITPY_PERFETTO_OUTER_HEAP_USED_UUID, (int64_t)total); + Z_SPIN_DELAY(1); +} + +static void perfetto_emit_circuitpython_tracks(void) { + if (perfetto_circuitpython_tracks_emitted) { + return; + } + if (!perfetto_start()) { + return; + } + perfetto_emit_track_descriptor(CIRCUITPY_PERFETTO_TRACK_GROUP_UUID, + perfetto_get_process_uuid(), + "CircuitPython"); + perfetto_emit_counter_track_descriptor(CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID, + CIRCUITPY_PERFETTO_TRACK_GROUP_UUID, + "VM Heap Used", + PERFETTO_COUNTER_UNIT_BYTES); + perfetto_emit_counter_track_descriptor(CIRCUITPY_PERFETTO_OUTER_HEAP_USED_UUID, + CIRCUITPY_PERFETTO_TRACK_GROUP_UUID, + "Outer Heap Used", + PERFETTO_COUNTER_UNIT_BYTES); + perfetto_circuitpython_tracks_emitted = true; +} +#else +static inline void perfetto_emit_outer_heap_stats(void) { +} + +static inline void perfetto_emit_circuitpython_tracks(void) { +} +#endif + +static void _tick_function(struct k_timer *timer_id) { + supervisor_tick(); +} + +// Save and retrieve a word from memory that is preserved over reset. Used for safe mode. +static __noinit uint32_t cp_saved_word; + +void port_set_saved_word(uint32_t value) { + cp_saved_word = value; +} + +uint32_t port_get_saved_word(void) { + return cp_saved_word; +} + +// Save and restore retained memory across the native_sim/bsim reboot. Opt in +// with --retained-memory=. +#if defined(CONFIG_ARCH_POSIX) +static void cp_retained_save(void) { + const char *path = native_sim_retained_memory; + if (path == NULL || path[0] == '\0') { + return; + } + int fd = nsi_host_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) { + return; + } + cp_retained_data_t data = { + .saved_word = cp_saved_word, + .port_reset_count = native_sim_reset_port_count, + }; + (void)nsi_host_write(fd, &data, sizeof(data)); + (void)nsi_host_close(fd); +} + +static void cp_retained_restore(void) { + const char *path = native_sim_retained_memory; + if (path == NULL || path[0] == '\0') { + return; + } + int fd = nsi_host_open(path, O_RDONLY, 0 /* unused */); + if (fd < 0) { + return; // First boot: no save file yet. + } + cp_retained_data_t data = { 0 }; + (void)nsi_host_read(fd, &data, sizeof(data)); + (void)nsi_host_close(fd); + cp_saved_word = data.saved_word; + native_sim_reset_port_count = data.port_reset_count; +} +#endif + safe_mode_t port_init(void) { + #if defined(CONFIG_ARCH_POSIX) + cp_retained_restore(); + #endif + + // We run CircuitPython at the lowest priority (just higher than idle.) + // This allows networking and USB to preempt us. + k_thread_priority_set(k_current_get(), CONFIG_NUM_PREEMPT_PRIORITIES - 1); + k_timer_init(&tick_timer, _tick_function, NULL); + perfetto_emit_circuitpython_tracks(); return SAFE_MODE_NONE; } // Reset the microcontroller completely. void reset_cpu(void) { + #if defined(CONFIG_ARCH_POSIX) + cp_retained_save(); + #endif + // Try a warm reboot first. It won't return if it works but isn't always // implemented. sys_reboot(SYS_REBOOT_WARM); @@ -42,7 +234,19 @@ void reset_cpu(void) { } void reset_port(void) { + #if CIRCUITPY_AUDIOBUSIO_I2SOUT + i2sout_reset(); + #endif + #if defined(CONFIG_ARCH_POSIX) + native_sim_reset_port_count++; + if (native_sim_port_resets != INT32_MAX && + native_sim_port_resets > 0 && + native_sim_reset_port_count >= (uint32_t)(native_sim_port_resets + 1)) { + printk("posix: exiting after %d port resets\n", native_sim_port_resets); + posix_exit(0); + } + #endif } void reset_to_bootloader(void) { @@ -57,34 +261,66 @@ void port_wake_main_task_from_isr(void) { k_event_set(&main_needed, 1); } -void port_yield(void) { +void port_task_yield(void) { k_yield(); } +void port_task_sleep_ms(uint32_t msecs) { + k_msleep(msecs); +} + void port_boot_info(void) { } // Get stack limit address uint32_t *port_stack_get_limit(void) { - return k_current_get()->stack_info.start; + return (uint32_t *)k_current_get()->stack_info.start; } // Get stack top address uint32_t *port_stack_get_top(void) { _thread_stack_info_t stack_info = k_current_get()->stack_info; - return stack_info.start + stack_info.size - stack_info.delta; -} - -// Save and retrieve a word from memory that is preserved over reset. Used for safe mode. -void port_set_saved_word(uint32_t) { - -} -uint32_t port_get_saved_word(void) { - return 0; + uint32_t *top = (uint32_t *)(stack_info.start + stack_info.size - stack_info.delta); + #if defined(CONFIG_ARCH_POSIX) + // On hosted builds the thread stack is a pthread stack. pthread_getattr_np(), + // which the POSIX arch uses to fix up stack_info, can report a size larger + // than the real mapping (ASan intercepts it and inflates the size). The GC + // scans up to the returned top, so clamp it to the end of the mapping that + // contains the current stack pointer. + // + // Only ever clamp *downwards*: /proc/self/maps merges adjacent anonymous + // mappings with the same flags, so the line containing our stack pointer + // routinely covers several thread stacks at once (e.g. 0xf63c2000-0xf73c4000 + // for two 8MB stacks). Taking its end as the top made the GC scan megabytes + // past this thread's stack, into the neighbouring thread's live stack -- and + // segfault whenever the range had an unmapped hole (a guard page, or a stack + // that has since been freed). + volatile uint32_t stack_probe; + uintptr_t sp = (uintptr_t)&stack_probe; + FILE *maps = fopen("/proc/self/maps", "r"); + if (maps != NULL) { + char line[256]; + unsigned long low, high; + while (fgets(line, sizeof(line), maps) != NULL) { + if (sscanf(line, "%lx-%lx", &low, &high) == 2 && low <= sp && sp < high) { + if (high < (uintptr_t)top) { + top = (uint32_t *)high; + } + break; + } + } + fclose(maps); + } + #endif + return top; } uint64_t port_get_raw_ticks(uint8_t *subticks) { + // Make sure time advances in the simulator. + #if defined(CONFIG_ARCH_POSIX) + k_busy_wait(100); + #endif int64_t uptime = k_uptime_ticks() * 32768 / CONFIG_SYS_CLOCK_TICKS_PER_SEC; if (subticks != NULL) { *subticks = uptime % 32; @@ -94,12 +330,12 @@ uint64_t port_get_raw_ticks(uint8_t *subticks) { // Enable 1/1024 second tick. void port_enable_tick(void) { - + k_timer_start(&tick_timer, K_USEC(1000000 / 1024), K_USEC(1000000 / 1024)); } // Disable 1/1024 second tick. void port_disable_tick(void) { - + k_timer_stop(&tick_timer); } static k_timeout_t next_timeout; @@ -123,36 +359,118 @@ void port_idle_until_interrupt(void) { // Zephyr doesn't maintain one multi-heap. So, make our own using TLSF. void port_heap_init(void) { + // Do a test malloc to determine if Zephyr has an outer heap that may + // overlap with a memory region we've identified in ram_bounds. We'll + // corrupt each other if we both use it. + #ifdef CONFIG_COMMON_LIBC_MALLOC + uint32_t *test_malloc = malloc(32); + free(test_malloc); // Free right away so we don't forget. We don't actually write it anyway. + zephyr_malloc_active = test_malloc != NULL; + #endif + for (size_t i = 0; i < CIRCUITPY_RAM_DEVICE_COUNT; i++) { uint32_t *heap_bottom = ram_bounds[2 * i]; uint32_t *heap_top = ram_bounds[2 * i + 1]; size_t size = (heap_top - heap_bottom) * sizeof(uint32_t); + // The linker script may fill up a region we thought we could use at + // build time. (The ram_bounds values are sometimes determined by the + // linker.) So, we need to guard against regions that aren't actually + // free. + if (size < 1024) { + printk("Skipping region because the linker filled it up.\n"); + continue; + } + #ifdef CONFIG_COMMON_LIBC_MALLOC + // Skip a ram region if our test malloc is within it. We'll use Zephyr's + // malloc to share that space with Zephyr. + if (heap_bottom <= test_malloc && test_malloc < heap_top) { + zephyr_malloc_top = heap_top; + zephyr_malloc_bottom = heap_bottom; + printk("Skipping region because Zephyr malloc is within bounds\n"); + pools[i] = NULL; + continue; + } + #endif printk("Init heap at %p - %p with size %d\n", heap_bottom, heap_top, size); // If this crashes, then make sure you've enabled all of the Kconfig needed for the drivers. - if (i == 0) { + if (valid_pool_count == 0) { heap = tlsf_create_with_pool(heap_bottom, size, circuitpy_max_ram_size); + if (heap == NULL) { + // Can happen for a region the linker filled almost to the top, + // which the build-time MINIMUM_RAM_SIZE filter cannot predict + // because it only sees the devicetree size. + printk("Heap creation failed at %p; trying the next region\n", heap_bottom); + pools[i] = NULL; + continue; + } pools[i] = tlsf_get_pool(heap); } else { pools[i] = tlsf_add_pool(heap, heap_bottom + 1, size - sizeof(uint32_t)); } + valid_pool_count++; } + perfetto_emit_outer_heap_stats(); #if !DT_HAS_CHOSEN(zephyr_sram) #error "No SRAM!" #endif } void *port_malloc(size_t size, bool dma_capable) { - void *block = tlsf_malloc(heap, size); + void *block = NULL; + if (valid_pool_count > 0) { + block = tlsf_malloc(heap, size); + } + if (block != NULL) { + tlsf_heap_used += tlsf_block_size(block); + } + #ifdef CONFIG_COMMON_LIBC_MALLOC + if (block == NULL) { + block = malloc(size); + } + #endif + if (block != NULL) { + perfetto_emit_outer_heap_stats(); + } return block; } void port_free(void *ptr) { - tlsf_free(heap, ptr); + if (ptr == NULL) { + return; + } + if (valid_pool_count > 0 && !(ptr >= zephyr_malloc_bottom && ptr < zephyr_malloc_top)) { + tlsf_heap_used -= tlsf_block_size(ptr); + tlsf_free(heap, ptr); + } else { + #ifdef CONFIG_COMMON_LIBC_MALLOC + free(ptr); + #endif + } + perfetto_emit_outer_heap_stats(); } void *port_realloc(void *ptr, size_t size, bool dma_capable) { - return tlsf_realloc(heap, ptr, size); + if (ptr == NULL) { + return port_malloc(size, dma_capable); + } + if (valid_pool_count > 0 && !(ptr >= zephyr_malloc_bottom && ptr < zephyr_malloc_top)) { + size_t old_size = tlsf_block_size(ptr); + void *new_block = tlsf_realloc(heap, ptr, size); + if (new_block != NULL) { + tlsf_heap_used = tlsf_heap_used - old_size + tlsf_block_size(new_block); + perfetto_emit_outer_heap_stats(); + } + return new_block; + } + #ifdef CONFIG_COMMON_LIBC_MALLOC + void *new_block = realloc(ptr, size); + if (new_block != NULL) { + perfetto_emit_outer_heap_stats(); + } + return new_block; + #endif + return NULL; } static bool max_size_walker(void *ptr, size_t size, int used, void *user) { @@ -165,9 +483,26 @@ static bool max_size_walker(void *ptr, size_t size, int used, void *user) { size_t port_heap_get_largest_free_size(void) { size_t max_size = 0; - for (size_t i = 0; i < CIRCUITPY_RAM_DEVICE_COUNT; i++) { - tlsf_walk_pool(pools[i], max_size_walker, &max_size); + if (valid_pool_count > 0) { + for (size_t i = 0; i < CIRCUITPY_RAM_DEVICE_COUNT; i++) { + if (pools[i] == NULL) { + continue; + } + tlsf_walk_pool(pools[i], max_size_walker, &max_size); + } + // IDF does this. Not sure why. + return tlsf_fit_size(heap, max_size); + } + return 64 * 1024; +} + +void assert_post_action(const char *file, unsigned int line) { + // printk("Assertion failed at %s:%u\n", file, line); + // Check that this is arm + #if defined(__arm__) + __asm__ ("bkpt"); + #endif + while (1) { + ; } - // IDF does this. Not sure why. - return tlsf_fit_size(heap, max_size); } diff --git a/ports/zephyr-cp/supervisor/serial.c b/ports/zephyr-cp/supervisor/serial.c index 97e2bee9ce5..3ae3e73fa10 100644 --- a/ports/zephyr-cp/supervisor/serial.c +++ b/ports/zephyr-cp/supervisor/serial.c @@ -6,52 +6,80 @@ #include "supervisor/shared/serial.h" -#include "bindings/zephyr_serial/UART.h" +#include "supervisor/zephyr-cp.h" -static zephyr_serial_uart_obj_t zephyr_console; +#if CIRCUITPY_USB_DEVICE == 1 +#include "shared-bindings/usb_cdc/Serial.h" +usb_cdc_serial_obj_t *usb_console; +#else +#include "shared-bindings/busio/UART.h" +static busio_uart_obj_t uart_console; static uint8_t buffer[64]; +#endif void port_serial_early_init(void) { #if CIRCUITPY_USB_DEVICE == 0 - zephyr_console.base.type = &zephyr_serial_uart_type; - zephyr_serial_uart_construct(&zephyr_console, DEVICE_DT_GET(DT_CHOSEN(zephyr_console)), sizeof(buffer), buffer); + uart_console.base.type = &busio_uart_type; + common_hal_busio_uart_construct_from_device(&uart_console, DEVICE_DT_GET(DT_CHOSEN(zephyr_console)), sizeof(buffer), buffer); #endif } void port_serial_init(void) { + #if CIRCUITPY_USB_DEVICE == 1 + usb_console = usb_cdc_serial_get_console(); + #endif } bool port_serial_connected(void) { #if CIRCUITPY_USB_DEVICE == 1 - return false; + if (usb_console == NULL) { + return false; + } + return common_hal_usb_cdc_serial_get_connected(usb_console); #else return true; #endif } char port_serial_read(void) { - #if CIRCUITPY_USB_DEVICE == 0 + #if CIRCUITPY_USB_DEVICE == 1 + if (usb_console == NULL) { + return -1; + } char buf[1]; - size_t count = zephyr_serial_uart_read(&zephyr_console, buf, 1, NULL); + size_t count = common_hal_usb_cdc_serial_read(usb_console, buf, 1, NULL); if (count == 0) { return -1; } return buf[0]; #else - return -1; + char buf[1]; + size_t count = common_hal_busio_uart_read(&uart_console, buf, 1, NULL); + if (count == 0) { + return -1; + } + return buf[0]; #endif } uint32_t port_serial_bytes_available(void) { - #if CIRCUITPY_USB_DEVICE == 0 - return zephyr_serial_uart_rx_characters_available(&zephyr_console); + #if CIRCUITPY_USB_DEVICE == 1 + if (usb_console == NULL) { + return 0; + } + return common_hal_usb_cdc_serial_get_in_waiting(usb_console); #else - return 0; + return common_hal_busio_uart_rx_characters_available(&uart_console); #endif } void port_serial_write_substring(const char *text, uint32_t length) { - #if CIRCUITPY_USB_DEVICE == 0 - zephyr_serial_uart_write(&zephyr_console, text, length, NULL); + #if CIRCUITPY_USB_DEVICE == 1 + if (usb_console == NULL) { + return; + } + common_hal_usb_cdc_serial_write(usb_console, text, length, NULL); + #else + common_hal_busio_uart_write(&uart_console, text, length, NULL); #endif } diff --git a/ports/zephyr-cp/supervisor/usb.c b/ports/zephyr-cp/supervisor/usb.c index 18eb2847ad9..6d3bf3286dd 100644 --- a/ports/zephyr-cp/supervisor/usb.c +++ b/ports/zephyr-cp/supervisor/usb.c @@ -1,202 +1,461 @@ #include "supervisor/usb.h" -#include "tusb_option.h" +#include "shared-bindings/usb_cdc/__init__.h" +#include "shared-bindings/usb_cdc/Serial.h" -#if CFG_TUSB_MCU == OPT_MCU_STM32U5 -#include +#if CIRCUITPY_USB_HID +#include "common-hal/usb_hid/__init__.h" #endif -#if CFG_TUSB_MCU == OPT_MCU_NRF5X -#include -#include -#endif +#include "supervisor/zephyr-cp.h" + +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "lib/oofatfs/diskio.h" +#include "lib/oofatfs/ff.h" #include +#include #include -#include #include - -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) -#define UDC_IRQ_NAME otghs -#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otgfs) -#define UDC_IRQ_NAME otgfs -#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usb) -#define UDC_IRQ_NAME usb -#elif DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_usb) -#define UDC_IRQ_NAME usbhs_ir +#include +#include +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbd) +#include #endif -#if DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_usb) -#define USB_NAME usbhs -#else -#define USB_NAME zephyr_udc0 -#endif +#include "shared-module/storage/__init__.h" +#include "supervisor/filesystem.h" +#include "supervisor/shared/reload.h" + +#include +LOG_MODULE_REGISTER(cpusb, CONFIG_LOG_DEFAULT_LEVEL); + +#define USB_DEVICE DT_NODELABEL(zephyr_udc0) + +USBD_DEVICE_DEFINE(main_usbd, + DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), + USB_VID, USB_PID); + +USBD_DESC_LANG_DEFINE(main_lang); +USBD_DESC_MANUFACTURER_DEFINE(main_mfr, USB_MANUFACTURER); +USBD_DESC_PRODUCT_DEFINE(main_product, USB_PRODUCT); -#define USB_DEVICE DT_NODELABEL(USB_NAME) +USBD_DESC_CONFIG_DEFINE(fs_cfg_desc, "FS Configuration"); +USBD_DESC_CONFIG_DEFINE(hs_cfg_desc, "HS Configuration"); -#ifdef UDC_IRQ_NAME -#define UDC_IRQ DT_IRQ_BY_NAME(USB_DEVICE, UDC_IRQ_NAME, irq) -#define UDC_IRQ_PRI DT_IRQ_BY_NAME(USB_DEVICE, UDC_IRQ_NAME, priority) -#else -#define UDC_IRQ DT_IRQ(USB_DEVICE, irq) -#define UDC_IRQ_PRI DT_IRQ(USB_DEVICE, priority) +/* doc configuration instantiation start */ +static const uint8_t attributes = 0; + +USBD_CONFIGURATION_DEFINE(main_fs_config, + attributes, + 100, &fs_cfg_desc); + +USBD_CONFIGURATION_DEFINE(main_hs_config, + attributes, + 100, &hs_cfg_desc); + +static usb_cdc_serial_obj_t usb_cdc_console_obj; +static usb_cdc_serial_obj_t usb_cdc_data_obj; + +#ifndef USBD_DEFINE_MSC_LUN +#error "MSC not enabled" #endif -PINCTRL_DT_DEFINE(USB_DEVICE); -static const struct pinctrl_dev_config *usb_pcfg = - PINCTRL_DT_DEV_CONFIG_GET(USB_DEVICE); +#define LUN_COUNT 1 +#define MSC_FLASH_BLOCK_SIZE 512 + +// The ellipsis range in the designated initializer of `ejected` is not standard C, +// but it works in both gcc and clang. +static bool locked[LUN_COUNT] = { [0 ... (LUN_COUNT - 1)] = false}; + +// Set to true if a write was in a file data or metadata area, +// as opposed to in the filesystem metadata area (e.g., dirty bit). +// Used to determine if an auto-reload is warranted. +static bool content_write[LUN_COUNT] = { [0 ... (LUN_COUNT - 1)] = false}; + +int _zephyr_disk_init(struct disk_info *disk); +int _zephyr_disk_status(struct disk_info *disk); +int _zephyr_disk_read(struct disk_info *disk, uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector); +int _zephyr_disk_write(struct disk_info *disk, const uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector); +int _zephyr_disk_ioctl(struct disk_info *disk, uint8_t cmd, void *buff); + +static const struct disk_operations disk_ops = { + .init = _zephyr_disk_init, + .status = _zephyr_disk_status, + .read = _zephyr_disk_read, + .write = _zephyr_disk_write, + .ioctl = _zephyr_disk_ioctl, +}; -#if CFG_TUSB_MCU == OPT_MCU_NRF5X -// Value is chosen to be as same as NRFX_POWER_USB_EVT_* in nrfx_power.h -enum { - USB_EVT_DETECTED = 0, - USB_EVT_REMOVED = 1, - USB_EVT_READY = 2 +static struct disk_info circuitpy_disk = { + .name = "CIRCUITPY", + .ops = &disk_ops, + .dev = NULL }; -#ifdef NRF5340_XXAA - #define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC - #define VBUSDETECT_Msk USBREG_USBREGSTATUS_VBUSDETECT_Msk - #define OUTPUTRDY_Msk USBREG_USBREGSTATUS_OUTPUTRDY_Msk - #define GPIOTE_IRQn GPIOTE1_IRQn -#else - #define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_RC - #define VBUSDETECT_Msk POWER_USBREGSTATUS_VBUSDETECT_Msk - #define OUTPUTRDY_Msk POWER_USBREGSTATUS_OUTPUTRDY_Msk -#endif +USBD_DEFINE_MSC_LUN(circuitpy_lun, "CIRCUITPY", "Zephyr", "FlashDisk", "0.00"); -// tinyusb function that handles power event (detected, ready, removed) -// We must call it within SD's SOC event handler, or set it as power event handler if SD is not enabled. -extern void tusb_hal_nrf_power_event(uint32_t event); -// nrf power callback, could be unused if SD is enabled or usb is disabled (board_test example) -TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) { - tusb_hal_nrf_power_event((uint32_t)event); +int _zephyr_disk_init(struct disk_info *disk) { + printk("Initializing disk\n"); + return 0; } -#endif -void init_usb_hardware(void) { - #if CFG_TUSB_MCU == OPT_MCU_RAXXX - #if !USBHS_PHY_CLOCK_SOURCE_IS_XTAL - if (data->udc_cfg.usb_speed == USBD_SPEED_HS) { - LOG_ERR("High-speed operation is not supported in case PHY clock source is not " - "XTAL"); - return; +int _zephyr_disk_status(struct disk_info *disk) { + fs_user_mount_t *root = filesystem_circuitpy(); + int lun = 0; + if (root == NULL) { + printk("Status: No media\n"); + return DISK_STATUS_NOMEDIA; } - #endif + if (!filesystem_is_writable_by_usb(root)) { + printk("Status: Read-only\n"); + return DISK_STATUS_WR_PROTECT; + } + // Lock the blockdev once we say we're writable. + if (!locked[lun] && !blockdev_lock(root)) { + printk("Status: Locked\n"); + return DISK_STATUS_WR_PROTECT; + } + locked[lun] = true; + return DISK_STATUS_OK; +} + +int _zephyr_disk_read(struct disk_info *disk, uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector) { + fs_user_mount_t *root = filesystem_circuitpy(); + + uint32_t disk_block_count; + disk_ioctl(root, GET_SECTOR_COUNT, &disk_block_count); - R_ICU->IELSR[UDC_IRQ] = ELC_EVENT_USBHS_USB_INT_RESUME; + if (start_sector + num_sector > disk_block_count) { + return -EIO; + } + disk_read(root, data_buf, start_sector, num_sector); + return 0; +} + +int _zephyr_disk_write(struct disk_info *disk, const uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector) { + fs_user_mount_t *root = filesystem_circuitpy(); + int lun = 0; + autoreload_suspend(AUTORELOAD_SUSPEND_USB); + disk_write(root, data_buf, start_sector, num_sector); + // Since by getting here we assume the mount is read-only to + // CircuitPython let's update the cached FatFs sector if it's the one + // we just wrote. + if + #if FF_MAX_SS != FF_MIN_SS + (root->fatfs.ssize == MSC_FLASH_BLOCK_SIZE) + #else + // The compiler can optimize this away. + (FF_MAX_SS == FILESYSTEM_BLOCK_SIZE) #endif + { + if (start_sector == root->fatfs.winsect && start_sector > 0) { + memcpy(root->fatfs.win, + data_buf + MSC_FLASH_BLOCK_SIZE * (root->fatfs.winsect - start_sector), + MSC_FLASH_BLOCK_SIZE); + } + } + // A write to an lba below fatbase is in the filesystem metadata (BPB) area or the "Reserved Region", + // and is probably setting or clearing the dirty bit. This should not trigger auto-reload. + // All other writes will trigger auto-reload. + if (start_sector >= root->fatfs.fatbase) { + content_write[lun] = true; + } + return 0; +} - IRQ_CONNECT(UDC_IRQ, UDC_IRQ_PRI, usb_irq_handler, 0, 0); +int _zephyr_disk_ioctl(struct disk_info *disk, uint8_t cmd, void *buff) { + + fs_user_mount_t *root = filesystem_circuitpy(); + int lun = 0; + switch (cmd) { + case DISK_IOCTL_GET_SECTOR_COUNT: + disk_ioctl(root, GET_SECTOR_COUNT, buff); + return 0; + case DISK_IOCTL_GET_SECTOR_SIZE: + disk_ioctl(root, GET_SECTOR_SIZE, buff); + return 0; + case DISK_IOCTL_CTRL_SYNC: + disk_ioctl(root, CTRL_SYNC, buff); + autoreload_resume(AUTORELOAD_SUSPEND_USB); + + // This write is complete; initiate an autoreload if this was a file data or metadata write, + // not just a dirty-bit write. + if (content_write[lun] && lun == 0) { + autoreload_trigger(); + content_write[lun] = false; + } + return 0; + default: + printk("Unsupported disk ioctl %02x\n", cmd); + return -ENOTSUP; + } + return 0; +} - /* Configure USB GPIOs */ - int err = pinctrl_apply_state(usb_pcfg, PINCTRL_STATE_DEFAULT); - if (err < 0) { - printk("USB pinctrl setup failed (%d)\n", err); - } else { - printk("USB pins setup\n"); +// Tracks whether the USB host has selected a configuration, i.e. the device has +// enumerated. Written from the USBD message callback (USBD thread or system +// workqueue context) and read from the CircuitPython VM thread, so keep it +// volatile to avoid the compiler caching stale values. +static volatile bool usb_configured = false; + +static void _msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg) { + LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type)); + + if (usbd_can_detect_vbus(ctx)) { + if (msg->type == USBD_MSG_VBUS_READY) { + usb_configured = false; + if (usbd_enable(ctx)) { + LOG_ERR("Failed to enable device support"); + } + } + + if (msg->type == USBD_MSG_VBUS_REMOVED) { + usb_configured = false; + if (usbd_disable(ctx)) { + LOG_ERR("Failed to disable device support"); + } + } + } + + // A non-zero configuration value means the host has enumerated us. + // A value of zero (or a bus reset / VBUS removal) unconfigures us. + if (msg->type == USBD_MSG_CONFIGURATION) { + usb_configured = (msg->status != 0); + } else if (msg->type == USBD_MSG_RESET) { + usb_configured = false; } +} -// #ifdef USB_DRD_FS -// // STM32U535/STM32U545 +void usb_init(void) { + printk("Initializing USB\n"); + int err; -// /* Enable USB power on Pwrctrl CR2 register */ -// HAL_PWREx_EnableVddUSB(); + printk("Adding language descriptor\n"); + err = usbd_add_descriptor(&main_usbd, &main_lang); + if (err) { + LOG_ERR("Failed to initialize language descriptor (%d)", err); + return; + } -// /* USB clock enable */ -// __HAL_RCC_USB_FS_CLK_ENABLE(); + err = usbd_add_descriptor(&main_usbd, &main_mfr); + if (err) { + LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); + return; + } -// #endif + err = usbd_add_descriptor(&main_usbd, &main_product); + if (err) { + LOG_ERR("Failed to initialize product descriptor (%d)", err); + return; + } - #if CFG_TUSB_MCU == OPT_MCU_STM32U5 && defined(USB_OTG_FS) - /* Enable USB power on Pwrctrl CR2 register */ - // HAL_PWREx_EnableVddUSB(); - LL_PWR_EnableVddUSB(); + bool console = usb_cdc_console_enabled(); + if (console) { + uint8_t *receiver_buffer = port_malloc(128, true); + if (receiver_buffer != NULL) { + common_hal_usb_cdc_serial_construct_from_device(&usb_cdc_console_obj, DEVICE_DT_GET(DT_NODELABEL(cdc_acm_console)), 128, receiver_buffer); + } else { + console = false; + } + } + usb_cdc_set_console(console ? MP_OBJ_FROM_PTR(&usb_cdc_console_obj) : mp_const_none); + + bool data = usb_cdc_data_enabled(); + if (data) { + uint8_t *receiver_buffer = port_malloc(128, true); + if (receiver_buffer != NULL) { + common_hal_usb_cdc_serial_construct_from_device(&usb_cdc_data_obj, DEVICE_DT_GET(DT_NODELABEL(cdc_acm_data)), 128, receiver_buffer); + } else { + data = false; + } + } + usb_cdc_set_data(data ? MP_OBJ_FROM_PTR(&usb_cdc_data_obj) : mp_const_none); - /* USB clock enable */ - __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); + err = disk_access_register(&circuitpy_disk); + if (err) { + printk("Failed to register disk access %d\n", err); + return; + } - #endif + if (USBD_SUPPORTS_HIGH_SPEED && + usbd_caps_speed(&main_usbd) == USBD_SPEED_HS) { + printk("Adding High-Speed configuration\n"); + err = usbd_add_configuration(&main_usbd, USBD_SPEED_HS, + &main_hs_config); + if (err) { + LOG_ERR("Failed to add High-Speed configuration"); + return; + } + + printk("Registering High-Speed cdc_acm class\n"); + if (usb_cdc_console_enabled()) { + err = usbd_register_class(&main_usbd, "cdc_acm_0", USBD_SPEED_HS, 1); + if (err) { + printk("Failed to add register classes %d\n", err); + return; + } + } + + if (usb_cdc_data_enabled()) { + err = usbd_register_class(&main_usbd, "cdc_acm_1", USBD_SPEED_HS, 1); + if (err) { + printk("Failed to add register classes %d\n", err); + return; + } + } + + err = usbd_register_class(&main_usbd, "msc_0", USBD_SPEED_HS, 1); + if (err) { + printk("Failed to add register MSC class %d\n", err); + return; + } else { + printk("Registered MSC class for high speed\n"); + } + + #if CIRCUITPY_USB_HID + if (usb_hid_enabled()) { + printk("Registering High-Speed hid class\n"); + err = usbd_register_class(&main_usbd, "hid_0", USBD_SPEED_HS, 1); + if (err) { + printk("Failed to register HID class (HS) %d\n", err); + return; + } + } + #endif -// #ifdef USB_OTG_HS -// // STM59x/Ax/Fx/Gx only have 1 USB HS port + usbd_device_set_code_triple(&main_usbd, USBD_SPEED_HS, + USB_BCC_MISCELLANEOUS, 0x02, 0x01); + } -// #if CFG_TUSB_OS == OPT_OS_FREERTOS -// // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) -// NVIC_SetPriority(OTG_HS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); -// #endif + /* doc configuration register start */ + printk("Adding Full-Speed configuration\n"); + err = usbd_add_configuration(&main_usbd, USBD_SPEED_FS, + &main_fs_config); + if (err) { + LOG_ERR("Failed to add Full-Speed configuration"); + return; + } + /* doc configuration register end */ -// /* USB clock enable */ -// __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); -// __HAL_RCC_USBPHYC_CLK_ENABLE(); + /* doc functions register start */ -// /* Enable USB power on Pwrctrl CR2 register */ -// HAL_PWREx_EnableVddUSB(); -// HAL_PWREx_EnableUSBHSTranceiverSupply(); + if (usb_cdc_console_enabled()) { + printk("Registering Full-Speed cdc_acm class\n"); + err = usbd_register_class(&main_usbd, "cdc_acm_0", USBD_SPEED_FS, 1); + if (err) { + printk("Failed to add register classes\n"); + return; + } + } -// /*Configuring the SYSCFG registers OTG_HS PHY*/ -// HAL_SYSCFG_EnableOTGPHY(SYSCFG_OTG_HS_PHY_ENABLE); + if (usb_cdc_data_enabled()) { + printk("Registering Full-Speed cdc_acm class\n"); + err = usbd_register_class(&main_usbd, "cdc_acm_1", USBD_SPEED_FS, 1); + if (err) { + printk("Failed to add register classes\n"); + return; + } + } -// // Disable VBUS sense (B device) -// USB_OTG_HS->GCCFG &= ~USB_OTG_GCCFG_VBDEN; + err = usbd_register_class(&main_usbd, "msc_0", USBD_SPEED_FS, 1); + if (err) { + printk("Failed to add register MSC class %d\n", err); + return; + } + /* doc functions register end */ + + #if CIRCUITPY_USB_HID + if (usb_hid_enabled()) { + printk("Registering Full-Speed hid class\n"); + err = usbd_register_class(&main_usbd, "hid_0", USBD_SPEED_FS, 1); + if (err) { + printk("Failed to register HID class (FS) %d\n", err); + return; + } + } + #endif -// // B-peripheral session valid override enable -// USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBVALEXTOEN; -// USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBVALOVAL; -// #endif // USB_OTG_FS + usbd_device_set_code_triple(&main_usbd, USBD_SPEED_FS, + USB_BCC_MISCELLANEOUS, 0x02, 0x01); + printk("Setting self powered\n"); + usbd_self_powered(&main_usbd, attributes & USB_SCD_SELF_POWERED); + printk("Registering callback\n"); + err = usbd_msg_register_cb(&main_usbd, _msg_cb); + if (err) { + LOG_ERR("Failed to register message callback"); + return; + } - #if CFG_TUSB_MCU == OPT_MCU_NRF5X - #ifdef CONFIG_HAS_HW_NRF_USBREG - /* Use CLOCK/POWER priority for compatibility with other series where - * USB events are handled by CLOCK interrupt handler. - */ - IRQ_CONNECT(USBREGULATOR_IRQn, - DT_IRQ(DT_INST(0, nordic_nrf_clock), priority), - nrfx_isr, nrfx_usbreg_irq_handler, 0); - irq_enable(USBREGULATOR_IRQn); + #if CIRCUITPY_USB_HID + printk("Initializing HID\n"); + usb_hid_init_devices(); #endif - // USB power may already be ready at this time -> no event generated - // We need to invoke the handler based on the status initially - uint32_t usb_reg; - { - // Power module init - static const nrfx_power_config_t pwr_cfg = { - .dcdcen = (DT_PROP(DT_INST(0, nordic_nrf5x_regulator), regulator_initial_mode) - == NRF5X_REG_MODE_DCDC), - #if NRFX_POWER_SUPPORTS_DCDCEN_VDDH - .dcdcenhv = COND_CODE_1(CONFIG_SOC_SERIES_NRF52X, - (DT_NODE_HAS_STATUS_OKAY(DT_INST(0, nordic_nrf52x_regulator_hv))), - (DT_NODE_HAS_STATUS_OKAY(DT_INST(0, nordic_nrf53x_regulator_hv)))), - #endif - }; - nrfx_power_init(&pwr_cfg); - - // Register tusb function as USB power handler - // cause cast-function-type warning - const nrfx_power_usbevt_config_t config = {.handler = power_event_handler}; - nrfx_power_usbevt_init(&config); - nrfx_power_usbevt_enable(); - - // USB power may already be ready at this time -> no event generated - // We need to invoke the handler based on the status initially - #ifdef NRF5340_XXAA - usb_reg = NRF_USBREGULATOR->USBREGSTATUS; + + printk("usbd_init\n"); + err = usbd_init(&main_usbd); + if (err) { + LOG_ERR("Failed to initialize device support (%d)", err); + return; + } + + printk("USB initialized\n"); + + if (!usbd_can_detect_vbus(&main_usbd)) { + /* No VBUS detection — just enable unconditionally. */ + err = usbd_enable(&main_usbd); + if (err) { + LOG_ERR("Failed to enable device support (%d)", err); + return; + } + } else { + #if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbd) + /* + * On nRF52 USBD, the UDC driver enables VBUS detection interrupts + * inside usbd_init(). If USB is already plugged in, the VBUS_READY + * event arrives before usbd_init() sets status.initialized = true, + * causing a __ASSERT in usbd_thread (with CONFIG_ASSERT=y) that kills + * the event-processing thread. Our _msg_cb then never receives + * VBUS_READY, and USB never enumerates. + * + * Work around the race by checking the current VBUS state directly. + * udc_nrf_enable() does not require VBUS to be present, so it's safe + * to call usbd_enable() if VBUS is already up. + */ + nrfx_power_usb_state_t vbus = nrfx_power_usbstatus_get(); + if (vbus != NRFX_POWER_USB_STATE_DISCONNECTED) { + err = usbd_enable(&main_usbd); + if (err) { + LOG_ERR("Failed to enable device support (%d)", err); + return; + } + } #else - usb_reg = NRF_POWER->USBREGSTATUS; + /* + * On nRF54 USBHS, VBUS events arrive via NRFS IPC which has a natural + * startup delay, so the assert race doesn't occur. Additionally, + * udc_enable() blocks until VBUS is ready, so we must NOT call + * usbd_enable() here — let _msg_cb handle it on VBUS_READY. + */ #endif } +} - if (usb_reg & VBUSDETECT_Msk) { - tusb_hal_nrf_power_event(USB_EVT_DETECTED); - } - if (usb_reg & OUTPUTRDY_Msk) { - tusb_hal_nrf_power_event(USB_EVT_READY); - } +bool usb_connected(void) { + // Mirrors TinyUSB's tud_ready(): configured (mounted) and not suspended. + return usb_configured && !usbd_is_suspended(&main_usbd); +} - printk("usb started hopefully\n"); - #endif +void usb_disconnect(void) { +} +usb_cdc_serial_obj_t *usb_cdc_serial_get_console(void) { + if (usb_cdc_console_enabled()) { + return &usb_cdc_console_obj; + } + return NULL; } diff --git a/ports/zephyr-cp/supervisor/zephyr-cp.h b/ports/zephyr-cp/supervisor/zephyr-cp.h new file mode 100644 index 00000000000..ecf7d42e3b4 --- /dev/null +++ b/ports/zephyr-cp/supervisor/zephyr-cp.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/usb_cdc/Serial.h" + +usb_cdc_serial_obj_t *usb_cdc_serial_get_console(void); diff --git a/ports/zephyr-cp/sysbuild.cmake b/ports/zephyr-cp/sysbuild.cmake index f0968e05b5c..bea5c588a2a 100644 --- a/ports/zephyr-cp/sysbuild.cmake +++ b/ports/zephyr-cp/sysbuild.cmake @@ -13,9 +13,11 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) BOARD ${SB_CONFIG_NET_CORE_BOARD} ) - set(${NET_APP}_CONF_FILE - ${NET_APP_SRC_DIR}/nrf5340_cpunet_iso-bt_ll_sw_split.conf + set(${NET_APP}_OVERLAY_CONFIG + ${NET_APP_SRC_DIR}/extra-cis-bt_ll_sw_split.conf CACHE INTERNAL "" ) + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + native_simulator_set_final_executable(${DEFAULT_IMAGE}) endif() diff --git a/ports/zephyr-cp/sysbuild/hci_ipc.conf b/ports/zephyr-cp/sysbuild/hci_ipc.conf new file mode 100644 index 00000000000..20dc067f3e4 --- /dev/null +++ b/ports/zephyr-cp/sysbuild/hci_ipc.conf @@ -0,0 +1,3 @@ +# Enable dynamic TX power control so that BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL +# is supported by the controller. +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y diff --git a/ports/zephyr-cp/tests/TEST_IDEAS.md b/ports/zephyr-cp/tests/TEST_IDEAS.md new file mode 100644 index 00000000000..6ef71d7a5a0 --- /dev/null +++ b/ports/zephyr-cp/tests/TEST_IDEAS.md @@ -0,0 +1,623 @@ +# CircuitPython Simulator Test Ideas + +Test ideas for the native_sim simulator, organized by module/category. + +## Core Python / Interpreter + +### 1. Multiple file priority +Test that boot.py runs before code.py, and main.py is used as fallback when code.py doesn't exist. + +```python +# boot.py +print("boot.py ran") + +# code.py +print("code.py ran") +``` + +Expected output order: "boot.py ran" then "code.py ran" + +### 2. Exception handling +Verify tracebacks print correctly with file/line info, and exception types propagate properly. + +```python +def inner(): + raise ValueError("test error") + +def outer(): + inner() + +outer() +``` + +### 3. Memory / gc module +Test `gc.collect()`, `gc.mem_free()`, `gc.mem_alloc()`, and behavior under memory pressure. + +```python +import gc +gc.collect() +free_before = gc.mem_free() +data = [0] * 1000 +free_after = gc.mem_free() +assert free_after < free_before +del data +gc.collect() +free_final = gc.mem_free() +print("done") +``` + +### 4. Import system +Test importing frozen modules vs filesystem modules, verify import errors are clear. + +```python +import sys +import board +import digitalio +print(f"modules loaded: {len(sys.modules)}") +print("done") +``` + +--- + +## digitalio + +### 5. Input mode +Test reading GPIO input state. May require trace file injection or loopback configuration. + +```python +import board +import digitalio + +pin = digitalio.DigitalInOut(board.D0) +pin.direction = digitalio.Direction.INPUT +value = pin.value +print(f"input value: {value}") +print("done") +``` + +### 6. Pull resistors +Verify pull-up/pull-down configuration affects input readings. + +```python +import board +import digitalio + +pin = digitalio.DigitalInOut(board.D0) +pin.direction = digitalio.Direction.INPUT +pin.pull = digitalio.Pull.UP +value_up = pin.value +pin.pull = digitalio.Pull.DOWN +value_down = pin.value +print(f"pull-up: {value_up}, pull-down: {value_down}") +print("done") +``` + +### 7. Direction switching +Switch same pin between input/output modes multiple times. + +```python +import board +import digitalio + +pin = digitalio.DigitalInOut(board.D0) +pin.direction = digitalio.Direction.OUTPUT +pin.value = True +pin.direction = digitalio.Direction.INPUT +_ = pin.value +pin.direction = digitalio.Direction.OUTPUT +pin.value = False +print("done") +``` + +--- + +## time module + +### 8. time.sleep() precision +Verify sleep timing via Perfetto trace timestamps. Use GPIO transitions as timing markers. + +```python +import time +import board +import digitalio + +led = digitalio.DigitalInOut(board.LED) +led.direction = digitalio.Direction.OUTPUT + +led.value = True +time.sleep(0.05) # 50ms +led.value = False +time.sleep(0.1) # 100ms +led.value = True +time.sleep(0.05) # 50ms +led.value = False +print("done") +``` + +Verify trace shows: 50ms high, 100ms low, 50ms high pattern. + +### 9. time.monotonic() +Test monotonic clock increments correctly and never goes backward. + +```python +import time + +samples = [] +for _ in range(10): + samples.append(time.monotonic()) + time.sleep(0.01) + +# Verify monotonic increase +for i in range(1, len(samples)): + assert samples[i] > samples[i-1], "monotonic went backward!" + +elapsed = samples[-1] - samples[0] +assert 0.08 < elapsed < 0.15, f"unexpected elapsed: {elapsed}" +print("done") +``` + +### 10. time.localtime / struct_time +Test time structure operations if available. + +```python +import time + +t = time.localtime() +print(f"year: {t.tm_year}") +print(f"month: {t.tm_mon}") +print(f"day: {t.tm_mday}") +print("done") +``` + +--- + +## microcontroller + +### 11. microcontroller.cpu properties +Test frequency, temperature, UID properties. + +```python +import microcontroller + +print(f"frequency: {microcontroller.cpu.frequency}") +print(f"uid: {microcontroller.cpu.uid.hex()}") +print("done") +``` + +### 12. Safe mode +Trigger and verify safe mode entry (requires CONFIG_NATIVE_SIM_REBOOT=y). + +```python +import microcontroller +# This would trigger safe mode - test carefully +# microcontroller.on_next_reset(microcontroller.RunMode.SAFE_MODE) +# microcontroller.reset() +print("done") +``` + +### 13. Reset reason +Test microcontroller.reset_reason after various reset types. + +```python +import microcontroller + +reason = microcontroller.reset_reason +print(f"reset reason: {reason}") +print("done") +``` + +--- + +## os module + +### 14. os.uname() +Verify returns correct system info for native_sim. + +```python +import os + +info = os.uname() +print(f"sysname: {info.sysname}") +print(f"machine: {info.machine}") +print(f"release: {info.release}") +print("done") +``` + +### 15. Filesystem operations +Test os.listdir(), os.stat(), os.remove(). + +```python +import os + +# List root +files = os.listdir("/") +print(f"root files: {files}") + +# Stat a file +if "code.py" in files: + stat = os.stat("/code.py") + print(f"code.py size: {stat[6]}") + +print("done") +``` + +### 16. os.getenv() +Test environment variable reading. + +```python +import os + +# May return None if not set +path = os.getenv("PATH") +print(f"PATH exists: {path is not None}") +print("done") +``` + +--- + +## board module + +### 17. board.board_id +Verify board ID matches expected value. + +```python +import board + +print(f"board_id: {board.board_id}") +assert board.board_id == "native_native_sim" +print("done") +``` + +### 18. Pin availability +Test that board.LED and other defined pins exist. + +```python +import board + +assert hasattr(board, "LED"), "board.LED missing" +print(f"LED pin: {board.LED}") +print("done") +``` + +--- + +## Filesystem + +### 19. File read/write +Create, read, and modify files on CIRCUITPY. + +```python +# Write a test file +with open("/test.txt", "w") as f: + f.write("hello world") + +# Read it back +with open("/test.txt", "r") as f: + content = f.read() + +assert content == "hello world" +print("done") +``` + +### 20. Directory operations +Test mkdir, rmdir, nested paths. + +```python +import os + +# Create directory +os.mkdir("/testdir") +assert "testdir" in os.listdir("/") + +# Create file in directory +with open("/testdir/file.txt", "w") as f: + f.write("nested") + +# Clean up +os.remove("/testdir/file.txt") +os.rmdir("/testdir") +assert "testdir" not in os.listdir("/") +print("done") +``` + +### 21. Large file handling +Test with larger files approaching flash limits. + +```python +import gc + +# Write 10KB file +data = "x" * 10240 +with open("/large.txt", "w") as f: + f.write(data) + +# Verify size +import os +stat = os.stat("/large.txt") +assert stat[6] == 10240 + +# Clean up +os.remove("/large.txt") +gc.collect() +print("done") +``` + +--- + +## Error Conditions + +### 22. Syntax error in code.py +Verify graceful error message when code.py has syntax error. + +```python +# code.py with intentional syntax error: +def broken( + print("missing close paren" +``` + +Expected: Clear syntax error message with line number. + +### 23. Runtime error +Verify traceback format shows file, line, and function. + +```python +def cause_error(): + x = 1 / 0 + +cause_error() +``` + +Expected: Traceback showing ZeroDivisionError with line info. + +### 24. Keyboard interrupt +Test Ctrl+C handling via PTY if applicable. + +```python +import time + +print("starting long loop") +for i in range(100): + print(f"iteration {i}") + time.sleep(0.1) +print("done") +``` + +Send Ctrl+C during execution, verify clean KeyboardInterrupt. + +--- + +## busio (if emulation available) + +### 25. busio.UART +Basic UART operations if configured. + +```python +import board +import busio + +# Check if UART pins exist +if hasattr(board, "TX") and hasattr(board, "RX"): + uart = busio.UART(board.TX, board.RX, baudrate=115200) + uart.write(b"test") + uart.deinit() +print("done") +``` + +### 26. busio.I2C scan +Scan for emulated I2C devices. + +```python +import board +import busio + +if hasattr(board, "SCL") and hasattr(board, "SDA"): + i2c = busio.I2C(board.SCL, board.SDA) + while not i2c.try_lock(): + pass + devices = i2c.scan() + print(f"I2C devices: {[hex(d) for d in devices]}") + i2c.unlock() + i2c.deinit() +print("done") +``` + +### 27. busio.SPI +Basic SPI transfer to emulated device. + +```python +import board +import busio + +if hasattr(board, "SCK") and hasattr(board, "MOSI"): + spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=getattr(board, "MISO", None)) + while not spi.try_lock(): + pass + spi.configure(baudrate=1000000) + result = bytearray(4) + spi.write_readinto(b"\x00\x00\x00\x00", result) + spi.unlock() + spi.deinit() +print("done") +``` + +--- + +## Serial/PTY Input + +These tests require extending conftest.py to support writing to the PTY, not just reading. + +### 28. Basic serial input +Test reading single characters from serial via PTY write. + +```python +import sys + +print("ready") +char = sys.stdin.read(1) +print(f"received: {repr(char)}") +print("done") +``` + +**Test harness**: After seeing "ready", write "A" to PTY, verify output shows "received: 'A'". + +### 29. input() function +Test the built-in input() function with PTY input. + +```python +print("ready") +name = input("Enter name: ") +print(f"hello {name}") +print("done") +``` + +**Test harness**: After seeing "Enter name:", write "World\n" to PTY, verify "hello World". + +### 30. Serial line buffering +Test reading a complete line with newline termination. + +```python +import sys + +print("ready") +line = sys.stdin.readline() +print(f"got: {repr(line)}") +print("done") +``` + +**Test harness**: Write "test line\n" to PTY, verify complete line received. + +### 31. usb_cdc.console data read +Test reading from usb_cdc.console.data if available. + +```python +import usb_cdc + +print("ready") +if usb_cdc.console: + while not usb_cdc.console.in_waiting: + pass + data = usb_cdc.console.read(usb_cdc.console.in_waiting) + print(f"console got: {data}") +print("done") +``` + +**Test harness**: Write bytes to PTY, verify they're received via usb_cdc.console. + +### 32. REPL interaction +Test entering REPL mode and executing commands interactively. + +```python +# No code.py - boots to REPL +``` + +**Test harness**: +1. Boot with empty/no code.py to get REPL prompt +2. Write "1 + 1\r\n" to PTY +3. Verify output contains "2" +4. Write "print('hello')\r\n" +5. Verify output contains "hello" + +### 33. Ctrl+C interrupt via PTY +Test sending Ctrl+C (0x03) to interrupt running code. + +```python +import time + +print("starting") +for i in range(100): + print(f"loop {i}") + time.sleep(0.1) +print("completed") # Should not reach this +``` + +**Test harness**: +1. Wait for "loop 5" in output +2. Write b"\x03" (Ctrl+C) to PTY +3. Verify KeyboardInterrupt raised +4. Verify "completed" NOT in output + +### 34. Ctrl+D soft reload via PTY +Test sending Ctrl+D (0x04) to trigger soft reload. + +```python +print("first run") +import time +time.sleep(10) # Long sleep to allow interrupt +print("done") +``` + +**Test harness**: +1. Wait for "first run" +2. Write b"\x04" (Ctrl+D) to PTY +3. Verify code restarts (see "first run" again or reload message) + +### 35. Serial input timeout +Test behavior when waiting for input with timeout. + +```python +import sys +import select + +print("ready") +# Poll for input with timeout +readable, _, _ = select.select([sys.stdin], [], [], 0.5) +if readable: + data = sys.stdin.read(1) + print(f"got: {repr(data)}") +else: + print("timeout") +print("done") +``` + +**Test harness**: Don't send anything, verify "timeout" appears. + +--- + +## Fixture Changes for PTY Input + +The `run_circuitpython` fixture in conftest.py needs to be extended: + +```python +@dataclass +class SimulatorResult: + output: str + trace_file: Path + pty_write_fd: int # New: file descriptor for writing to PTY + +def _run(code: str | None, timeout: float = 5.0, ...) -> SimulatorResult: + # Open PTY for both read AND write + pty_fd = os.open(pty_path, os.O_RDWR | os.O_NONBLOCK) + # ... +``` + +Or provide a callback/queue mechanism: + +```python +def _run(code, timeout=5.0, input_sequence=None): + """ + input_sequence: list of (trigger_text, bytes_to_send) tuples + When trigger_text is seen in output, send bytes_to_send to PTY + """ +``` + +--- + +## Implementation Priority + +Suggested order for implementation: + +### Phase 1: Basic module tests (no fixture changes) +1. **#17 board.board_id** - Quick sanity check +2. **#14 os.uname()** - Tests another module, simple +3. **#9 time.monotonic()** - Core timing functionality +4. **#8 time.sleep() precision** - Builds on GPIO trace infrastructure +5. **#1 Multiple file priority** - Tests interpreter boot sequence +6. **#19 File read/write** - Tests filesystem layer +7. **#3 Memory / gc** - Tests memory management +8. **#2 Exception handling** - Tests error reporting + +### Phase 2: PTY input tests (requires fixture extension) +9. **#28 Basic serial input** - Foundation for all input tests +10. **#33 Ctrl+C interrupt** - Important for interactive use +11. **#29 input() function** - Common user pattern +12. **#32 REPL interaction** - Tests interactive mode diff --git a/ports/zephyr-cp/tests/__init__.py b/ports/zephyr-cp/tests/__init__.py new file mode 100644 index 00000000000..78b9a17a676 --- /dev/null +++ b/ports/zephyr-cp/tests/__init__.py @@ -0,0 +1,216 @@ +from pathlib import Path + +import serial +import subprocess +import threading +import time + + +class StdSerial: + def __init__(self, stdin, stdout): + self.stdin = stdin + self.stdout = stdout + + def read(self, amount=None): + data = self.stdout.read(amount) + if data == b"": + raise EOFError("stdout closed") + return data + + def write(self, buf): + if self.stdin is None: + return + self.stdin.write(buf) + self.stdin.flush() + + def close(self): + if self.stdin is not None: + self.stdin.close() + self.stdout.close() + + def read_some(self, limit=65536): + # read1() hands back whatever is already buffered and does at most one + # read on the pipe, so it blocks only when nothing has arrived yet. + data = self.stdout.read1(limit) + if data == b"": + raise EOFError("stdout closed") + return data + + @property + def in_waiting(self): + if self.stdout is None: + return 0 + return len(self.stdout.peek()) + + +class SerialSaver: + """Capture serial output in a background thread so output isn't missed.""" + + def __init__(self, serial_obj, name="serial"): + self.all_output = "" + self.all_input = "" + self.serial = serial_obj + self.name = name + + self._stop = threading.Event() + self._lock = threading.Lock() + self._cv = threading.Condition(self._lock) + self._read_some = getattr(serial_obj, "read_some", None) + self._reader = threading.Thread(target=self._reader_loop, daemon=True) + self._reader.start() + + def _reader_loop(self): + while not self._stop.is_set(): + try: + if self._read_some is not None: + read = self._read_some() + else: + read = self.serial.read(1) + # in_waiting is a non-blocking check on a real serial port, + # so draining it here is free. + waiting = self.serial.in_waiting + if waiting: + read += self.serial.read(waiting) + except Exception: + # Serial port closed or device disconnected. + break + + if read == b"": + # Timeout with no data — keep waiting. Only a real + # exception or an explicit stop should end the loop. + continue + + text = read.decode("utf-8", errors="replace") + with self._cv: + self.all_output += text + self._cv.notify_all() + in_waiting = 0 + try: + in_waiting = self.serial.in_waiting + except OSError: + pass + if in_waiting > 0: + self.all_output += self.serial.read().decode("utf-8", errors="replace") + + def wait_for(self, text, timeout=10): + with self._cv: + while text not in self.all_output and self._reader.is_alive(): + if not self._cv.wait(timeout=timeout): + break + if text not in self.all_output: + tail = self.all_output[-400:] + raise TimeoutError( + f"Timed out waiting for {text!r} on {self.name}. Output tail:\n{tail}" + ) + + def read(self, amount=None): + # Kept for compatibility with existing callers. + return + + def close(self): + if not self.serial: + return + + self._stop.set() + self._reader.join(timeout=1.0) + try: + self.serial.close() + except Exception: + pass + self.serial = None + + def write(self, text): + self.all_input += text + self.serial.write(text.encode("utf-8")) + + +class NativeSimProcess: + def __init__(self, cmd, timeout=5, trace_file=None, env=None, flash_file=None): + if trace_file: + cmd.append(f"--trace-file={trace_file}") + + self._timeout = timeout + self.trace_file = trace_file + self.flash_file = flash_file + print("Running", " ".join(cmd)) + self._proc = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=None, + env=env, + ) + if self._proc.stdout is None: + raise RuntimeError("Failed to capture simulator stdout") + + # Discard the test warning + uart_pty_line = self._proc.stdout.readline().decode("utf-8") + if "connected to pseudotty:" not in uart_pty_line: + raise RuntimeError("Failed to connect to UART") + pty_path = uart_pty_line.strip().rsplit(":", maxsplit=1)[1].strip() + self.serial = SerialSaver( + serial.Serial(pty_path, baudrate=115200, timeout=0.05, write_timeout=0), + name="uart0", + ) + self.debug_serial = SerialSaver( + StdSerial(self._proc.stdin, self._proc.stdout), name="debug" + ) + # Offset into debug_serial output for finding the next UART PTY path. + self._pty_search_offset = 0 + + def reconnect_serial(self, timeout=30.0): + """Wait for the simulator to reboot (execv) and reopen the UART. + + native_sim/bsim reboot by re-executing the process; the UART PTY master + fd is O_CLOEXEC so it closes on execv and a new PTY is opened. The new + "connected to pseudotty: " line is printed to the process stdout + (which survives execv), so it shows up in debug_serial. This method waits + for that line and reopens ``self.serial`` on the new PTY. + """ + import time + + marker = "connected to pseudotty:" + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + if self._proc.poll() is not None: + return False + out = self.debug_serial.all_output + idx = out.find(marker, self._pty_search_offset) + newline = out.find("\n", idx) if idx >= 0 else -1 + if idx >= 0 and newline >= 0: + line = out[idx:newline] + pty_path = line.strip().rsplit(":", maxsplit=1)[1].strip() + self._pty_search_offset = newline + 1 + try: + self.serial.close() + except Exception: + pass + self.serial = SerialSaver( + serial.Serial(pty_path, baudrate=115200, timeout=0.05, write_timeout=0), + name="uart0", + ) + return True + time.sleep(0.05) + return False + + def shutdown(self): + if self._proc.poll() is None: + self._proc.terminate() + self._proc.wait(timeout=self._timeout) + + self.serial.close() + self.debug_serial.close() + + def display_capture_paths(self) -> list[Path]: + """Return paths to numbered PNG capture files produced by trace-driven capture.""" + pattern = getattr(self, "_capture_png_pattern", None) + count = getattr(self, "_capture_count", 0) + if not pattern or count == 0: + return [] + return [Path(pattern % i) for i in range(count)] + + def wait_until_done(self): + start_time = time.monotonic() + while self._proc.poll() is None and time.monotonic() - start_time < self._timeout: + time.sleep(0.01) + self.shutdown() diff --git a/tests/feature_check/coverage.py.exp b/ports/zephyr-cp/tests/bsim/__init__.py similarity index 100% rename from tests/feature_check/coverage.py.exp rename to ports/zephyr-cp/tests/bsim/__init__.py diff --git a/ports/zephyr-cp/tests/bsim/conftest.py b/ports/zephyr-cp/tests/bsim/conftest.py new file mode 100644 index 00000000000..a0c2c9fca27 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/conftest.py @@ -0,0 +1,273 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Pytest fixtures for CircuitPython bsim testing.""" + +import logging +import os +import shutil +import subprocess +from pathlib import Path + +import pytest + +from .. import SerialSaver, StdSerial + +logger = logging.getLogger(__name__) + +ZEPHYR_CP = Path(__file__).resolve().parents[2] +BSIM_ROOT = ZEPHYR_CP / "tools/bsim" +BSIM_PHY_BINARY = BSIM_ROOT / "bin/bs_2G4_phy_v1" + + +@pytest.fixture +def native_sim_env() -> dict[str, str]: + env = os.environ.copy() + env["BSIM_OUT_PATH"] = str(BSIM_ROOT) + env["BSIM_COMPONENTS_PATH"] = str(BSIM_ROOT / "components") + lib_path = str(BSIM_ROOT / "lib") + existing = env.get("LD_LIBRARY_PATH", "") + env["LD_LIBRARY_PATH"] = f"{lib_path}:{existing}" if existing else lib_path + return env + + +@pytest.fixture(params=["native_nrf5340bsim", "native_nrf54lm20bsim"]) +def board(request): + """Parametrized board fixture for bsim tests. + + Overrides the parent conftest's board fixture to run each test on both + bsim boards. + """ + return request.param + + +@pytest.fixture +def bsim_phy_binary(): + """Return path to BabbleSim PHY binary, skip if not present.""" + if not BSIM_PHY_BINARY.exists(): + pytest.skip(f"bs_2G4_phy_v1 not found: {BSIM_PHY_BINARY}") + return BSIM_PHY_BINARY + + +class BsimPhyInstance: + def __init__(self, proc: subprocess.Popen, serial: SerialSaver, timeout: float): + self.proc = proc + self.serial = serial + self.timeout = timeout + + def finish_sim(self) -> None: + self.serial.wait_for("Cleaning up", timeout=self.timeout + 5) + + def shutdown(self) -> None: + if self.proc.poll() is None: + self.proc.terminate() + self.proc.wait(timeout=2) + self.serial.close() + + +class ZephyrSampleProcess: + def __init__(self, proc: subprocess.Popen, timeout: float): + self._proc = proc + self._timeout = timeout + if proc.stdout is None: + raise RuntimeError("Failed to capture Zephyr sample stdout") + self.serial = SerialSaver(StdSerial(None, proc.stdout), name="zephyr sample") + + def shutdown(self) -> None: + if self._proc.poll() is None: + self._proc.terminate() + self._proc.wait(timeout=self._timeout) + self.serial.close() + + +@pytest.fixture +def bsim_phy(request, bsim_phy_binary, native_sim_env, sim_id): + duration_marker = request.node.get_closest_marker("duration") + duration = float(duration_marker.args[0]) if duration_marker else 20.0 + + devices = 1 + if "circuitpython2" in request.fixturenames or "zephyr_sample" in request.fixturenames: + devices = 2 + + sample_marker = request.node.get_closest_marker("zephyr_sample") + if sample_marker is not None: + sample_device_id = int(sample_marker.kwargs.get("device_id", 1)) + devices = max(devices, sample_device_id + 1) + + # Do not pass -sim_length: if the PHY exits on simulated time, device 0 can + # still be flushing UART output and test output can get truncated. Instead, + # let pytest own process lifetime and terminate the PHY at fixture teardown. + cmd = [ + "stdbuf", + "-oL", + str(bsim_phy_binary), + "-v=9", # Cleaning up level is on 9. Connecting is 7. + f"-s={sim_id}", + f"-D={devices}", + "-argschannel", + "-at=40", # 40 dB attenuation (default 60) so RSSI ~ -40 dBm + ] + print("Running:", " ".join(cmd)) + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + env=native_sim_env, + cwd=BSIM_ROOT / "bin", + ) + if proc.stdout is None: + raise RuntimeError("Failed to capture bsim phy stdout") + + # stdbuf -oL forces line-buffered stdout so SerialSaver can + # stream-read PHY output in real time. Wrapping in StdSerial + # ensures the reader thread exits on EOF when the PHY process + # terminates, rather than spinning on empty timeout reads. + phy_output = SerialSaver(StdSerial(None, proc.stdout), name="bsim phy") + try: + phy_output.wait_for("Connecting", timeout=2) + except TimeoutError: + if proc.poll() is not None: + print(phy_output.all_output) + raise RuntimeError("bsim PHY exited immediately") + # Assume bsim is running + + phy = BsimPhyInstance(proc, phy_output, timeout=duration) + yield phy + phy.shutdown() + + print("bsim phy output:") + print(phy_output.all_output) + + +def _build_zephyr_sample(build_dir: Path, source_dir: Path, board: str) -> Path: + if shutil.which("west") is None: + raise RuntimeError("west not found") + + cmd = [ + "west", + "build", + "-b", + board, + "-d", + str(build_dir), + "-p=auto", + str(source_dir), + ] + logger.info("Building Zephyr sample: %s", " ".join(cmd)) + subprocess.run(cmd, check=True, cwd=ZEPHYR_CP) + + return build_dir / "zephyr/zephyr.exe" + + +@pytest.fixture +def zephyr_sample(request, bsim_phy, native_sim_env, sim_id): + marker = request.node.get_closest_marker("zephyr_sample") + if marker is None or len(marker.args) != 1: + raise RuntimeError( + "zephyr_sample fixture requires @pytest.mark.zephyr_sample('')" + ) + + sample = marker.args[0] + board = marker.kwargs.get("board", "nrf52_bsim") + device_id = int(marker.kwargs.get("device_id", 1)) + timeout = float(marker.kwargs.get("timeout", 10.0)) + + sample_rel = str(sample).removeprefix("zephyr/samples/") + source_dir = ZEPHYR_CP / "zephyr/samples" / sample_rel + if not source_dir.exists(): + source_dir = ZEPHYR_CP / sample # port-local sample + if not source_dir.exists(): + pytest.skip(f"Zephyr sample not found: {source_dir}") + + build_name = f"build-bsim-sample-{sample_rel.replace('/', '_')}-{board}" + build_dir = ZEPHYR_CP / build_name + binary = build_dir / "zephyr/zephyr.exe" + + needs_rebuild = False + if not binary.exists(): + needs_rebuild = True + else: + # Rebuild if any source file is newer than the binary. + binary_mtime = binary.stat().st_mtime + for root, _dirs, files in os.walk(source_dir): + for f in files: + if Path(root, f).stat().st_mtime > binary_mtime: + needs_rebuild = True + break + if needs_rebuild: + break + + if needs_rebuild: + try: + binary = _build_zephyr_sample(build_dir, source_dir, board) + except (subprocess.CalledProcessError, RuntimeError) as exc: + pytest.skip(f"Failed to build Zephyr sample {sample_rel}: {exc}") + + if not binary.exists(): + pytest.skip(f"Zephyr sample binary not found: {binary}") + + cmd = [ + str(binary), + f"-s={sim_id}", + f"-d={device_id}", + "-disconnect_on_exit=1", + ] + logger.info("Running: %s", " ".join(cmd)) + proc = subprocess.Popen( + cmd, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + env=native_sim_env, + ) + sample_proc = ZephyrSampleProcess(proc, timeout=timeout) + yield sample_proc + sample_proc.shutdown() + + print("Zephyr sample output:") + print(sample_proc.serial.all_output) + + +FROZEN_ROOT = (ZEPHYR_CP / "../../frozen").resolve() + + +def get_library_files(name: str) -> dict[str, str]: + """Return a dict mapping CIRCUITPY paths to file contents for all + .py files in a frozen library, suitable for circuitpy_drive. + + Looks up ``name`` under the ``frozen/`` directory (e.g. + ``get_library_files("adafruit_ble")`` walks + ``frozen/Adafruit_CircuitPython_BLE/adafruit_ble/``). + """ + files: dict[str, str] = {} + + # Try directory-style library: *//**/*.py + py_files = sorted(FROZEN_ROOT.glob(f"*/{name}/**/*.py")) + if py_files: + repo_dir = py_files[0].relative_to(FROZEN_ROOT).parts[0] + lib_parent = FROZEN_ROOT / repo_dir + for py_file in py_files: + rel = py_file.relative_to(lib_parent) + files[str(rel)] = py_file.read_text(encoding="utf-8") + return files + + # Try single-file module: */.py + py_files = list(FROZEN_ROOT.glob(f"*/{name}.py")) + if py_files: + py_file = py_files[0] + files[name + ".py"] = py_file.read_text(encoding="utf-8") + return files + + raise FileNotFoundError(f"Library {name!r} not found under {FROZEN_ROOT}") + + +# pytest markers are defined inside out meaning the bottom one is first in the +# list and the top is last. So use negative indices to reverse them. +@pytest.fixture +def circuitpython1(circuitpython): + return circuitpython[-1] + + +@pytest.fixture +def circuitpython2(circuitpython): + return circuitpython[-2] diff --git a/ports/zephyr-cp/tests/bsim/samples/central_battery_client/CMakeLists.txt b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/CMakeLists.txt new file mode 100644 index 00000000000..d3635c95059 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(central_battery_client) + +target_sources(app PRIVATE + src/main.c +) diff --git a/ports/zephyr-cp/tests/bsim/samples/central_battery_client/prj.conf b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/prj.conf new file mode 100644 index 00000000000..56a790677be --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/prj.conf @@ -0,0 +1,4 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_GATT_CLIENT=y +CONFIG_LOG=y diff --git a/ports/zephyr-cp/tests/bsim/samples/central_battery_client/src/main.c b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/src/main.c new file mode 100644 index 00000000000..34ed2fa09b9 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/src/main.c @@ -0,0 +1,212 @@ +/* + * SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries + * SPDX-License-Identifier: MIT + * + * Zephyr BLE central that connects to a device named "CPSVC", + * discovers Battery Service (0x180F), reads Battery Level (0x2A19), + * prints the value, and disconnects. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +static struct bt_conn *default_conn; +static struct bt_gatt_discover_params discover_params; +static struct bt_gatt_read_params read_params; + +/* Battery Service UUID: 0x180F */ +static struct bt_uuid_16 bas_uuid = BT_UUID_INIT_16(0x180F); +/* Battery Level Characteristic UUID: 0x2A19 */ +static struct bt_uuid_16 bat_level_uuid = BT_UUID_INIT_16(0x2A19); + +static uint16_t bat_level_handle; + +static void start_scan(void); + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) { + if (default_conn) { + return; + } + + /* Only interested in connectable devices */ + if (type != BT_GAP_ADV_TYPE_ADV_IND && + type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + return; + } + + /* Clone ad data so we can parse it without affecting the original */ + struct net_buf_simple ad_copy; + uint8_t ad_buf[64]; + size_t copy_len = ad->len < sizeof(ad_buf) ? ad->len : sizeof(ad_buf); + memcpy(ad_buf, ad->data, copy_len); + net_buf_simple_init_with_data(&ad_copy, ad_buf, copy_len); + + char addr_str[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Found CPSVC device: %s (RSSI %d)\n", addr_str, rssi); + + if (bt_le_scan_stop()) { + return; + } + + int err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &default_conn); + if (err) { + printk("Create conn failed (%d)\n", err); + start_scan(); + } +} + +static void start_scan(void) { + int err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } + printk("Scanning started\n"); +} + +static uint8_t read_battery_level_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) { + if (err) { + printk("Read failed (err %d)\n", err); + } else if (data && length >= 1) { + uint8_t level = ((const uint8_t *)data)[0]; + printk("Battery Level: %d\n", level); + } else { + printk("Read returned no data\n"); + } + + /* Disconnect after reading */ + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + + return BT_GATT_ITER_STOP; +} + +static uint8_t discover_char_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + printk("Characteristic discovery complete\n"); + return BT_GATT_ITER_STOP; + } + + struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; + + if (bt_uuid_cmp(chrc->uuid, &bat_level_uuid.uuid) == 0) { + bat_level_handle = chrc->value_handle; + printk("Found Battery Level characteristic, handle: %u\n", bat_level_handle); + + /* Read the battery level */ + read_params.func = read_battery_level_cb; + read_params.handle_count = 1; + read_params.single.handle = bat_level_handle; + read_params.single.offset = 0; + + int err = bt_gatt_read(conn, &read_params); + if (err) { + printk("Read request failed (err %d)\n", err); + } + return BT_GATT_ITER_STOP; + } + + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t discover_service_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + printk("Service discovery complete, BAS not found\n"); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + return BT_GATT_ITER_STOP; + } + + printk("Found Battery Service, handle: %u\n", attr->handle); + + /* Now discover characteristics within this service */ + discover_params.uuid = &bat_level_uuid.uuid; + discover_params.start_handle = attr->handle + 1; + discover_params.end_handle = 0xFFFF; + discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + discover_params.func = discover_char_cb; + + int err = bt_gatt_discover(conn, &discover_params); + if (err) { + printk("Characteristic discovery failed (err %d)\n", err); + } + + return BT_GATT_ITER_STOP; +} + +static void connected(struct bt_conn *conn, uint8_t err) { + char addr[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err) { + printk("Failed to connect to %s (%u)\n", addr, err); + bt_conn_unref(default_conn); + default_conn = NULL; + start_scan(); + return; + } + + if (conn != default_conn) { + return; + } + + printk("Connected: %s\n", addr); + + /* Discover Battery Service */ + discover_params.uuid = &bas_uuid.uuid; + discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; + discover_params.func = discover_service_cb; + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + printk("Service discovery failed (err %d)\n", err); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) { + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != default_conn) { + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(default_conn); + default_conn = NULL; +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +int main(void) { + int err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + printk("Bluetooth initialized\n"); + start_scan(); + return 0; +} diff --git a/ports/zephyr-cp/tests/bsim/samples/central_nus_client/CMakeLists.txt b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/CMakeLists.txt new file mode 100644 index 00000000000..d5deacef980 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(central_nus_client) + +target_sources(app PRIVATE + src/main.c +) diff --git a/ports/zephyr-cp/tests/bsim/samples/central_nus_client/prj.conf b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/prj.conf new file mode 100644 index 00000000000..56a790677be --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/prj.conf @@ -0,0 +1,4 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_GATT_CLIENT=y +CONFIG_LOG=y diff --git a/ports/zephyr-cp/tests/bsim/samples/central_nus_client/src/main.c b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/src/main.c new file mode 100644 index 00000000000..9825a3e7a5e --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/src/main.c @@ -0,0 +1,302 @@ +/* + * SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries + * SPDX-License-Identifier: MIT + * + * Zephyr BLE central that connects to a device named "CPNUS", + * discovers Nordic UART Service (NUS), writes to the RX characteristic, + * subscribes to TX notifications, receives data, and disconnects. + * + * NUS UUIDs: + * Service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E + * TX (peripheral→central, notify): 6E400003-B5A3-F393-E0A9-E50E24DCCA9E + * RX (central→peripheral, write): 6E400002-B5A3-F393-E0A9-E50E24DCCA9E + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +static struct bt_conn *default_conn; +static struct bt_gatt_discover_params discover_params; + +/* Real NUS 128-bit UUIDs in little-endian byte order. + * These match the standard Nordic UART Service UUIDs: + * Service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E + * TX: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E + * RX: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E + */ +static struct bt_uuid_128 nus_service_uuid = BT_UUID_INIT_128( + 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, + 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E); +static struct bt_uuid_128 nus_tx_uuid = BT_UUID_INIT_128( + 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, + 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E); +static struct bt_uuid_128 nus_rx_uuid = BT_UUID_INIT_128( + 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, + 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E); + +static uint16_t tx_handle; +static uint16_t rx_handle; +static bool tx_notify_enabled; +static bool rx_written; +static bool received; +static uint8_t received_data[32]; +static uint16_t received_len; + +static void start_scan(void); + +/* Check if advertisement data contains a name */ +static bool ad_has_name(struct net_buf_simple *ad, const char *name) { + size_t name_len = strlen(name); + + while (ad->len > 1) { + uint8_t field_len = net_buf_simple_pull_u8(ad); + if (field_len == 0 || field_len > ad->len) { + break; + } + uint8_t type = net_buf_simple_pull_u8(ad); + field_len--; + + if ((type == BT_DATA_NAME_COMPLETE || type == BT_DATA_NAME_SHORTENED) && + field_len == name_len && + memcmp(ad->data, name, name_len) == 0) { + return true; + } + net_buf_simple_pull(ad, field_len); + } + return false; +} + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) { + if (default_conn) { + return; + } + + /* Only interested in connectable devices */ + if (type != BT_GAP_ADV_TYPE_ADV_IND && + type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + return; + } + + /* Clone ad data so we can parse it */ + struct net_buf_simple ad_copy; + uint8_t ad_buf[64]; + size_t copy_len = ad->len < sizeof(ad_buf) ? ad->len : sizeof(ad_buf); + memcpy(ad_buf, ad->data, copy_len); + net_buf_simple_init_with_data(&ad_copy, ad_buf, copy_len); + + if (!ad_has_name(&ad_copy, "CPNUS")) { + return; + } + + char addr_str[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Found CPNUS device: %s (RSSI %d)\n", addr_str, rssi); + + if (bt_le_scan_stop()) { + return; + } + + int err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &default_conn); + if (err) { + printk("Create conn failed (%d)\n", err); + start_scan(); + } +} + +static void start_scan(void) { + int err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } + printk("Scanning started\n"); +} + +/* TX notification callback */ +static uint8_t on_tx_notify(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) { + if (data) { + memcpy(received_data, data, length < sizeof(received_data) ? + length : sizeof(received_data)); + received_len = length; + received = true; + printk("NUS: received '"); + for (uint16_t i = 0; i < received_len; i++) { + printk("%c", received_data[i]); + } + printk("'\n"); + + /* Disconnect after receiving response */ + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } + return BT_GATT_ITER_CONTINUE; +} + +static struct bt_gatt_subscribe_params tx_subscribe_params; + +/* Step 5: Subscribe to TX notifications */ +static void subscribe_tx(struct bt_conn *conn) { + tx_subscribe_params.notify = on_tx_notify; + tx_subscribe_params.value = BT_GATT_CCC_NOTIFY; + tx_subscribe_params.value_handle = tx_handle; + tx_subscribe_params.ccc_handle = tx_handle + 1; + + int err = bt_gatt_subscribe(conn, &tx_subscribe_params); + if (err) { + printk("TX subscribe failed (err %d)\n", err); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } else { + tx_notify_enabled = true; + printk("TX notify enabled\n"); + } +} + +/* Step 4: Write to RX characteristic (central→peripheral) using write-without-response */ +static void write_rx(struct bt_conn *conn) { + static uint8_t data[] = "Hello"; + + int err = bt_gatt_write_without_response(conn, rx_handle, + data, 5, false); + if (err) { + printk("RX write request failed (err %d)\n", err); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + return; + } + rx_written = true; + printk("RX write complete\n"); + + /* Now subscribe to TX to receive the response */ + subscribe_tx(conn); +} + +/* Step 3: Discover characteristics to find TX and RX handles */ +static uint8_t discover_char_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + printk("Characteristic discovery complete\n"); + if (rx_handle == 0 || tx_handle == 0) { + printk("NUS characteristics not found\n"); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + return BT_GATT_ITER_STOP; + } + if (rx_handle) { + printk("Writing to RX...\n"); + write_rx(conn); + } + return BT_GATT_ITER_STOP; + } + + struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; + + if (bt_uuid_cmp(chrc->uuid, &nus_rx_uuid.uuid) == 0) { + rx_handle = chrc->value_handle; + printk("Found NUS RX, handle: %u\n", rx_handle); + } else if (bt_uuid_cmp(chrc->uuid, &nus_tx_uuid.uuid) == 0) { + tx_handle = chrc->value_handle; + printk("Found NUS TX, handle: %u\n", tx_handle); + } + + return BT_GATT_ITER_CONTINUE; +} + +/* Step 2: Discover characteristics within the NUS service */ +static uint8_t discover_service_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + printk("Service discovery complete, NUS not found\n"); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + return BT_GATT_ITER_STOP; + } + + printk("Found NUS, handle: %u\n", attr->handle); + + /* Discover characteristics within this service */ + discover_params.uuid = NULL; + discover_params.start_handle = attr->handle + 1; + discover_params.end_handle = 0xFFFF; + discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + discover_params.func = discover_char_cb; + + int err = bt_gatt_discover(conn, &discover_params); + if (err) { + printk("Char discovery failed (err %d)\n", err); + } + + return BT_GATT_ITER_STOP; +} + +/* Step 1: Connected - discover NUS */ +static void connected(struct bt_conn *conn, uint8_t err) { + char addr[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err) { + printk("Failed to connect to %s (%u)\n", addr, err); + bt_conn_unref(default_conn); + default_conn = NULL; + start_scan(); + return; + } + + if (conn != default_conn) { + return; + } + + printk("Connected: %s\n", addr); + + /* Discover NUS */ + discover_params.uuid = &nus_service_uuid.uuid; + discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; + discover_params.func = discover_service_cb; + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + printk("Service discovery failed (err %d)\n", err); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) { + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != default_conn) { + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(default_conn); + default_conn = NULL; +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +int main(void) { + int err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + printk("Bluetooth initialized\n"); + start_scan(); + return 0; +} diff --git a/ports/zephyr-cp/tests/bsim/samples/observer/CMakeLists.txt b/ports/zephyr-cp/tests/bsim/samples/observer/CMakeLists.txt new file mode 100644 index 00000000000..59d999d7052 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/observer/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(observer) + +target_sources(app PRIVATE + src/main.c + src/observer.c +) diff --git a/ports/zephyr-cp/tests/bsim/samples/observer/prj.conf b/ports/zephyr-cp/tests/bsim/samples/observer/prj.conf new file mode 100644 index 00000000000..a328b3700a9 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/observer/prj.conf @@ -0,0 +1,2 @@ +CONFIG_BT=y +CONFIG_BT_OBSERVER=y diff --git a/ports/zephyr-cp/tests/bsim/samples/observer/src/main.c b/ports/zephyr-cp/tests/bsim/samples/observer/src/main.c new file mode 100644 index 00000000000..db8ce6bab95 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/observer/src/main.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +int observer_start(void); + +int main(void) { + int err; + + printk("Starting Observer Demo\n"); + + /* Initialize the Bluetooth Subsystem */ + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + (void)observer_start(); + + printk("Exiting %s thread.\n", __func__); + return 0; +} diff --git a/ports/zephyr-cp/tests/bsim/samples/observer/src/observer.c b/ports/zephyr-cp/tests/bsim/samples/observer/src/observer.c new file mode 100644 index 00000000000..fc896bf593d --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/observer/src/observer.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) { + printk("Device found: %s (RSSI %d), type %u, AD data len %u\n", + bt_addr_le_str(addr), rssi, type, ad->len); +} + +#if defined(CONFIG_BT_EXT_ADV) +#define NAME_LEN 30 + +static bool data_cb(struct bt_data *data, void *user_data) { + char *name = user_data; + uint8_t len; + + switch (data->type) { + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + len = MIN(data->data_len, NAME_LEN - 1); + (void)memcpy(name, data->data, len); + name[len] = '\0'; + return false; + default: + return true; + } +} + +static const char *phy2str(uint8_t phy) { + switch (phy) { + case BT_GAP_LE_PHY_NONE: + return "No packets"; + case BT_GAP_LE_PHY_1M: + return "LE 1M"; + case BT_GAP_LE_PHY_2M: + return "LE 2M"; + case BT_GAP_LE_PHY_CODED: + return "LE Coded"; + default: + return "Unknown"; + } +} + +static void scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *buf) { + char name[NAME_LEN]; + uint8_t data_status; + uint16_t data_len; + + (void)memset(name, 0, sizeof(name)); + + data_len = buf->len; + bt_data_parse(buf, data_cb, name); + + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(info->adv_props); + + printk("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i " + "Data status: %u, AD data len: %u Name: %s " + "C:%u S:%u D:%u SR:%u E:%u Pri PHY: %s, Sec PHY: %s, " + "Interval: 0x%04x (%u ms), SID: %u\n", + bt_addr_le_str(info->addr), info->adv_type, info->tx_power, info->rssi, + data_status, data_len, name, + (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0, + (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0, + (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0, + (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0, + (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0, + phy2str(info->primary_phy), phy2str(info->secondary_phy), + info->interval, info->interval * 5 / 4, info->sid); +} + +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv, +}; +#endif /* CONFIG_BT_EXT_ADV */ + +static int scan_start(void) { + /* 30 ms continuous active scanning. Duplicate filtering is disabled so + * that updated advertisements from the same device (e.g. when user + * code replaces the workflow advert) are reported again. + */ + struct bt_le_scan_param scan_param = { + .type = BT_LE_SCAN_TYPE_ACTIVE, + .options = 0, + .interval = BT_GAP_SCAN_FAST_INTERVAL_MIN, + .window = BT_GAP_SCAN_FAST_WINDOW, + }; + int err; + + #if defined(CONFIG_BT_EXT_ADV) + scan_param.options |= BT_LE_SCAN_OPT_CODED; + #endif /* CONFIG_BT_EXT_ADV */ + +scan_start_retry: + printk("Starting scanning...\n"); + err = bt_le_scan_start(&scan_param, device_found); + if (err) { + if ((scan_param.options & BT_LE_SCAN_OPT_CODED) != 0U) { + printk("Failed to start scanning with Coded PHY (err %d), retrying " + "without...\n", err); + + scan_param.options &= ~BT_LE_SCAN_OPT_CODED; + + goto scan_start_retry; + } + + printk("Start scanning failed (err %d)\n", err); + + return err; + } + + printk("success.\n"); + + return 0; +} + +int observer_start(void) { + int err; + + #if defined(CONFIG_BT_EXT_ADV) + bt_le_scan_cb_register(&scan_callbacks); + printk("Registered scan callbacks\n"); + #endif /* CONFIG_BT_EXT_ADV */ + + err = scan_start(); + if (err != 0) { + return err; + } + + return 0; +} diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py new file mode 100644 index 00000000000..12165750274 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Basic BabbleSim connectivity tests for bsim.""" + +import pytest + +from .conftest import get_library_files + +BSIM_CODE = """\ +print("bsim ready") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) +@pytest.mark.duration(20) +def test_bsim_dual_instance_connect(bsim_phy, circuitpython1, circuitpython2, board): + """Run two bsim instances on the same sim id and verify UART output.""" + + # Wait for both devices to complete before checking output. + circuitpython1.wait_until_done() + circuitpython2.wait_until_done() + + output0 = circuitpython1.serial.all_output + output1 = circuitpython2.serial.all_output + + assert f"Board ID:{board}" in output0 + assert f"Board ID:{board}" in output1 + assert "bsim ready" in output0 + assert "bsim ready" in output1 + + +# --- adafruit_ble library import --- + +BSIM_BLE_IMPORT_CODE = """\ +import adafruit_ble + +print("adafruit_ble version", adafruit_ble.__version__) +print("adafruit_ble repo", adafruit_ble.__repo__) +print("done") +""" + + +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_BLE_IMPORT_CODE, **get_library_files("adafruit_ble")} +) +def test_bsim_ble_library_import(bsim_phy, circuitpython): + """Import adafruit_ble from CIRCUITPY and verify basic attributes.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "adafruit_ble version" in output + assert "adafruit_ble repo" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_adapter.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_adapter.py new file mode 100644 index 00000000000..29092b0641c --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_adapter.py @@ -0,0 +1,149 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE adapter state tests for bsim.""" + +import pytest + + +# --- Enable/disable cycle --- + +BSIM_ENABLE_DISABLE_CODE = """\ +import _bleio + +adapter = _bleio.adapter + +# Check initial state (should be enabled after boot) +print("enabled start", adapter.enabled) + +# Disable +adapter.enabled = False +print("enabled false", adapter.enabled) + +# Re-enable +adapter.enabled = True +print("enabled true", adapter.enabled) + +# Verify it reports as enabled +print("enabled final", adapter.enabled) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_ENABLE_DISABLE_CODE}) +def test_bsim_adapter_enable_disable(bsim_phy, circuitpython): + """Toggle adapter.enabled and verify state.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "enabled start True" in output + assert "enabled false False" in output + assert "enabled true True" in output + assert "enabled final True" in output + assert "done" in output + + +# --- Disable stops advertising --- + +BSIM_DISABLE_STOPS_ADV_CODE = """\ +import _bleio + +adapter = _bleio.adapter + +name = b"CPADV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +adapter.start_advertising(advertisement, connectable=False) +print("advertising", adapter.advertising) + +adapter.enabled = False +print("advertising after disable", adapter.advertising) + +adapter.enabled = True +print("advertising after enable", adapter.advertising) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_DISABLE_STOPS_ADV_CODE}) +def test_bsim_adapter_disable_stops_advertising(bsim_phy, circuitpython): + """Disabling the adapter stops advertising.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "advertising True" in output + assert "advertising after disable False" in output + assert "advertising after enable False" in output + assert "done" in output + + +# --- Adapter state across soft reload --- + +BSIM_ENABLE_RELOAD_CODE = """\ +import time +import _bleio + +adapter = _bleio.adapter + +print("enabled", adapter.enabled) +print("advertising", adapter.advertising) +print("connected", adapter.connected) +print("done") +# The sim exits right after the second run's VM cleanup (port_resets). Give the +# UART time to deliver the lines above to the pty before that happens. +time.sleep(0.5) +""" + + +@pytest.mark.port_resets(3) +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": BSIM_ENABLE_RELOAD_CODE}) +def test_bsim_adapter_state_after_reload(bsim_phy, circuitpython): + """Adapter state is consistent across a soft reload. + + The BLE workflow is advertising on this device, and `import _bleio` must not + disturb it, so adapter.advertising reads True on both runs (as on nordic). + """ + circuitpython.serial.wait_for("done") + circuitpython.serial.wait_for("Press any key to enter the REPL") + circuitpython.serial.write("\x04") + + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert output.count("enabled True") >= 2 + assert output.count("advertising True") >= 2 + assert output.count("connected False") >= 2 + + +# --- Adapter name truncation --- + +BSIM_NAME_TRUNCATION_CODE = """\ +import _bleio + +adapter = _bleio.adapter + +# Set a very long name +long_name = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%" +adapter.name = long_name + +# Read back — should be truncated to fit CONFIG_BT_DEVICE_NAME_MAX +name = adapter.name +print("name len", len(name)) +print("name", name) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_NAME_TRUNCATION_CODE}) +def test_bsim_adapter_name_truncation(bsim_phy, circuitpython): + """Very long adapter.name is truncated to fit Zephyr limit.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "name len" in output + # Should be truncated — length must be less than input (72 chars) + name_line = [l for l in output.split("\n") if "name len" in l][0] + name_len = int(name_line.split()[-1]) + assert name_len < 72 + assert "done" in output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py new file mode 100644 index 00000000000..fe2d66881e7 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -0,0 +1,262 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE advertising tests for bsim.""" + +import logging +import re + +import pytest + + +logger = logging.getLogger(__name__) + +BSIM_ADV_CODE = """\ +import _bleio +import time + +name = b"CPADV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +adapter = _bleio.adapter +print("adv start") +adapter.start_advertising(advertisement, connectable=False) +print("adv started") +time.sleep(4) +adapter.stop_advertising() +print("adv stop") +""" + +BSIM_ADV_INTERRUPT_RELOAD_CODE = """\ +import _bleio +import time + +name = b"CPADV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +adapter = _bleio.adapter +print("adv run start") +adapter.start_advertising(advertisement, connectable=False) +print("adv running") +time.sleep(10) +adapter.stop_advertising() +print("adv run done") +""" + + +BSIM_TX_POWER_DEFAULT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"CPTXPWR" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("advertising default") +adapter.start_advertising(advertisement) +time.sleep(4) +adapter.stop_advertising() +print("done") +""" + +BSIM_TX_POWER_LOW_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"CPTXPWR" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("advertising low") +adapter.start_advertising(advertisement, tx_power=-20) +time.sleep(4) +adapter.stop_advertising() +print("done") +""" + + +# Advertiser: primary advert carries a distinctive marker; the scan response +# carries a different marker. If the adapter merges them they'd arrive as one +# entry, but the adapter does not merge — they come as separate ScanEntry +# objects distinguished by `scan_response`. +BSIM_ADVERT_SCAN_RESPONSE_ADV_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"ADVADV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +sname = b"SCANRSP" +scan_response = bytes((len(sname) + 1, 0x09)) + sname + +print("adv start") +adapter.start_advertising(advertisement, scan_response=scan_response, connectable=True) +time.sleep(10) +adapter.stop_advertising() +print("adv done") +""" + +BSIM_ADVERT_SCAN_RESPONSE_SCAN_CODE = """\ +import _bleio + +adapter = _bleio.adapter +print("scan start") +saw_primary = False +saw_scan_response = False +for entry in adapter.start_scan(active=True, timeout=12.0): + data = entry.advertisement_bytes + if b"ADVADV" in data and not entry.scan_response: + saw_primary = True + print("primary") + if b"SCANRSP" in data and entry.scan_response: + saw_scan_response = True + print("scan_response") + if saw_primary and saw_scan_response: + print("both") + break +adapter.stop_scan() +print("scan done", saw_primary, saw_scan_response) +""" + +# Disable the workflow on the advertiser so only its custom advert is on air. +BSIM_ADVERT_SCAN_RESPONSE_SETTINGS = "CIRCUITPY_BLE_WORKFLOW = false\n" + + +@pytest.mark.zephyr_sample("tests/bsim/samples/observer") +@pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_CODE}) +@pytest.mark.duration(60) +def test_bsim_advertise_and_scan(bsim_phy, circuitpython, zephyr_sample): + """Advertise from CircuitPython and verify Zephyr observer sees traffic.""" + observer = zephyr_sample + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + observer_output = observer.serial.all_output + assert "adv start" in cp_output + assert "adv started" in cp_output + assert "adv stop" in cp_output + assert "Device found:" in observer_output + assert "AD data len 10" in observer_output + + +@pytest.mark.zephyr_sample("tests/bsim/samples/observer") +@pytest.mark.port_resets(3) +@pytest.mark.duration(60) +@pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_INTERRUPT_RELOAD_CODE}) +def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): + """Ensure advertising resumes after Ctrl-C and a reload.""" + observer = zephyr_sample + + circuitpython.serial.wait_for("adv running") + observer.serial.wait_for("Device found:") + observer_count_before = observer.serial.all_output.count("Device found:") + + circuitpython.serial.write("\x03") + # Real AES for the link layer adds CPU overhead that can delay the + # interpreter noticing SIGINT beyond the default wait_for timeout. + circuitpython.serial.wait_for("KeyboardInterrupt", timeout=20) + + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + observer_output = observer.serial.all_output + logger.info(observer_output) + logger.info(cp_output) + + assert "adv run start" in cp_output + assert "KeyboardInterrupt" in cp_output + assert cp_output.count("adv running") >= 2 + assert cp_output.count("adv run done") >= 1 + assert observer_output.count("Device found:") >= observer_count_before + 1 + assert "Already advertising" not in cp_output + + +@pytest.mark.zephyr_sample("tests/bsim/samples/observer") +@pytest.mark.duration(40) +@pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_DEFAULT_CODE}) +def test_bsim_tx_power_default_rssi(board, bsim_phy, circuitpython, zephyr_sample): + """Verify default TX power produces expected RSSI.""" + observer = zephyr_sample + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + obs_output = observer.serial.all_output + + assert "advertising default" in cp_output + assert "done" in cp_output + + # Observer: "Device found: (RSSI ), type , AD data len " + # Advertisement is 12 bytes: flags (3) + name (9). + # With 40 dB channel attenuation and 0 dBm TX → RSSI ~ -39. + expected_rssi = -39 + rssi_pattern = re.compile(r"RSSI (-?\d+)\), type \d+, AD data len 12") + all_rssi = [int(m.group(1)) for m in rssi_pattern.finditer(obs_output)] + logger.info("RSSI values: %s", all_rssi) + + assert len(all_rssi) > 0, "Observer saw no advertisements" + assert all_rssi[0] == expected_rssi, f"Expected RSSI {expected_rssi}, got {all_rssi[0]}" + + +@pytest.mark.zephyr_sample("tests/bsim/samples/observer") +@pytest.mark.duration(40) +@pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_LOW_CODE}) +def test_bsim_tx_power_low_rssi(bsim_phy, circuitpython, zephyr_sample): + """Verify low TX power reduces RSSI.""" + observer = zephyr_sample + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + obs_output = observer.serial.all_output + + assert "advertising low" in cp_output + assert "done" in cp_output + + # With 40 dB channel attenuation and -20 dBm TX → RSSI ~ -59 + rssi_pattern = re.compile(r"RSSI (-?\d+)\), type \d+, AD data len 12") + all_rssi = [int(m.group(1)) for m in rssi_pattern.finditer(obs_output)] + logger.info("RSSI values: %s", all_rssi) + + assert len(all_rssi) > 0, "Observer saw no advertisements" + assert all_rssi[0] < -39, f"Expected lower RSSI with -20 dBm TX, got {all_rssi[0]}" + + +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_ADVERT_SCAN_RESPONSE_ADV_CODE, + "settings.toml": BSIM_ADVERT_SCAN_RESPONSE_SETTINGS, + } +) +@pytest.mark.circuitpy_drive({"code.py": BSIM_ADVERT_SCAN_RESPONSE_SCAN_CODE}) +def test_bsim_scan_response_not_merged(bsim_phy, circuitpython1, circuitpython2): + """The adapter does not merge advertisement and scan response. + + The advertiser sends a primary advert (marker "ADVADV") and a scan + response (marker "SCANRSP") as separate packets. With duplicate filtering + disabled and no merging in the adapter, the scanner observes them as two + distinct ScanEntry objects: one with scan_response=False (the primary + advert) and one with scan_response=True (the scan response). + """ + scanner = circuitpython2 + + scanner.wait_until_done() + + scanner_output = scanner.serial.all_output + assert "primary" in scanner_output, ( + f"primary advert entry not observed separately: {scanner_output}" + ) + assert "scan_response" in scanner_output, ( + f"scan response entry not observed separately: {scanner_output}" + ) + assert "both" in scanner_output, ( + f"did not observe both advert and scan response: {scanner_output}" + ) + assert "scan done True True" in scanner_output, f"scan did not confirm both: {scanner_output}" diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py new file mode 100644 index 00000000000..5a52e03a151 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py @@ -0,0 +1,118 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE central connection tests for bsim.""" + +import pytest + + +BSIM_CONNECT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("connect start") +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable: + target = entry.address + print("found target") + break +adapter.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No connectable target found") + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected, adapter.connected, len(adapter.connections)) +connection.disconnect() + +for _ in range(40): + if not connection.connected and not adapter.connected: + break + time.sleep(0.1) + +print("disconnected", connection.connected, adapter.connected, len(adapter.connections)) +""" + +BSIM_RECONNECT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("run start") +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable: + target = entry.address + print("run found target") + break +adapter.stop_scan() +print("run have target", target is not None) + +if target is None: + raise RuntimeError("No connectable target found") + +connection = adapter.connect(target, timeout=5.0) +print("run connected", connection.connected, adapter.connected, len(adapter.connections)) +connection.disconnect() + +for _ in range(50): + if not connection.connected and not adapter.connected and len(adapter.connections) == 0: + break + time.sleep(0.1) + +print("run disconnected", connection.connected, adapter.connected, len(adapter.connections)) +""" + + +@pytest.mark.zephyr_sample("bluetooth/peripheral") +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CONNECT_CODE}) +def test_bsim_connect_zephyr_peripheral(bsim_phy, circuitpython, zephyr_sample): + """Connect to the Zephyr peripheral sample and disconnect cleanly.""" + peripheral = zephyr_sample + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + peripheral_output = peripheral.serial.all_output + + assert "connect start" in cp_output + assert "found target" in cp_output + assert "have target True" in cp_output + assert "connected True True 1" in cp_output + assert "disconnected False False 0" in cp_output + + assert "Advertising successfully started" in peripheral_output + assert "Connected" in peripheral_output + + +@pytest.mark.zephyr_sample("bluetooth/peripheral_sc_only") +@pytest.mark.port_resets(3) +@pytest.mark.duration(26) +@pytest.mark.circuitpy_drive({"code.py": BSIM_RECONNECT_CODE}) +def test_bsim_reconnect_zephyr_peripheral(bsim_phy, circuitpython, zephyr_sample): + """Connect/disconnect, soft reload, then connect/disconnect again.""" + peripheral = zephyr_sample + + circuitpython.serial.wait_for("run disconnected") + circuitpython.serial.wait_for("Press any key to enter the REPL") + circuitpython.serial.write("\x04") + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + peripheral_output = peripheral.serial.all_output + + assert cp_output.count("run start") >= 2 + assert cp_output.count("run found target") >= 2 + assert cp_output.count("run have target True") >= 2 + assert cp_output.count("run connected True True 1") >= 2 + assert cp_output.count("run disconnected False False 0") >= 2 + + assert "Advertising successfully started" in peripheral_output + assert peripheral_output.count("Connected") >= 2 diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py new file mode 100644 index 00000000000..6d5cf418147 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py @@ -0,0 +1,131 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE descriptor tests for bsim.""" + +import pytest + +# =================================================================== +# Server: characteristic with user_description +# =================================================================== + +BSIM_DESC_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0x180F)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0x2A19), + properties=_bleio.Characteristic.READ, + read_perm=_bleio.Attribute.OPEN, + write_perm=_bleio.Attribute.NO_ACCESS, + max_length=1, fixed_length=True, initial_value=bytes([75]), + user_description="Battery Level", +) +print("service created") + +# Check local descriptors list +descs = char.descriptors +print("num descriptors", len(descs)) +for d in descs: + print("desc uuid", d.uuid.uuid16) + print("desc value", list(d.value)) + +name = b"CPDESC" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +# =================================================================== +# Client: connects and reads the remote user description +# =================================================================== + +BSIM_DESC_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("client start") +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPDESC" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0x180F)]) +char = services[0].characteristics[0] + +print("char value", list(char.value)) + +descs = char.descriptors +print("num descriptors", len(descs)) +for d in descs: + print("desc uuid", hex(d.uuid.uuid16)) + print("desc value", list(d.value)) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": BSIM_DESC_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_DESC_CLIENT_CODE}) +def test_bsim_descriptor_user_description(bsim_phy, circuitpython1, circuitpython2): + """Server creates a characteristic with user_description; + client discovers the service and reads the descriptor.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + # Server: user_description creates a CUD descriptor (0x2901) on the characteristic + assert "service created" in server_output + assert "num descriptors 1" in server_output + assert "desc uuid 10497" in server_output # 0x2901 + assert ( + "desc value [66, 97, 116, 116, 101, 114, 121, 32, 76, 101, 118, 101, 108]" in server_output + ) + assert "connected True" in server_output + + # Client: discovers and reads the remote descriptor + assert "found server" in client_output + assert "char value [75]" in client_output + assert "num descriptors 1" in client_output + assert "desc uuid 0x2901" in client_output + assert ( + "desc value [66, 97, 116, 116, 101, 114, 121, 32, 76, 101, 118, 101, 108]" in client_output + ) + assert "done" in client_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py new file mode 100644 index 00000000000..b64fb2125f1 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py @@ -0,0 +1,126 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE adapter name tests for bsim. + +Covers reading the default adapter name (derived from the device address), +setting a custom name and reading it back, and verifying the default name is +re-applied every time the adapter is re-enabled. +""" + +import re + +import pytest + + +# The address prints as
in big-endian/expected order. +# The default name is "CIRCUITPY" plus the last two octets (ee, ff) concatenated +# without colons, e.g. an address of
-> "CIRCUITPYd224". +ADDRESS_RE = re.compile( + r"
" +) + +# Strip ANSI/OSC escape sequences (e.g. terminal title updates) and carriage +# returns that CircuitPython interleaves with code.py output. +_ANSI_RE = re.compile(r"\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[[0-9;?]*[A-Za-z]") + + +def _clean(output: str) -> str: + return _ANSI_RE.sub("", output).replace("\r", "") + + +def _expected_default_name(address_repr: str) -> str: + m = ADDRESS_RE.search(address_repr) + assert m is not None, f"unexpected address repr: {address_repr!r}" + return "CIRCUITPY" + m.group(5) + m.group(6) + + +# --- Default name is derived from the adapter address --- + +BSIM_DEFAULT_NAME_CODE = """\ +import _bleio + +adapter = _bleio.adapter +adapter.enabled = True +print("default name", adapter.name) +print("address", adapter.address) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_DEFAULT_NAME_CODE}) +def test_bsim_default_name_matches_address(bsim_phy, circuitpython): + """The default name is CIRCUITPY plus the last two address octets.""" + circuitpython.wait_until_done() + + output = _clean(circuitpython.serial.all_output) + name = re.search(r"(?m)^default name (\S+)$", output).group(1) + address_repr = re.search(r"(?m)^address (.+)$", output).group(1).strip() + + assert name == _expected_default_name(address_repr) + assert re.search(r"(?m)^done$", output) is not None + + +# --- Set a custom name and read it back --- + +BSIM_SET_NAME_CODE = """\ +import _bleio + +adapter = _bleio.adapter +adapter.enabled = True +adapter.name = "CPNAME" +print("name", adapter.name) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_SET_NAME_CODE}) +def test_bsim_set_name(bsim_phy, circuitpython): + """Set the BLE name and read it back on bsim.""" + circuitpython.wait_until_done() + + output = _clean(circuitpython.serial.all_output) + assert re.search(r"(?m)^name CPNAME$", output) is not None + assert re.search(r"(?m)^done$", output) is not None + + +# --- Re-enabling the adapter restores the default name --- + +BSIM_NAME_RESET_ON_ENABLE_CODE = """\ +import _bleio + +adapter = _bleio.adapter + +adapter.enabled = True +print("default", adapter.name) + +adapter.name = "CUSTOM" +print("custom", adapter.name) + +# Re-enabling re-applies the default name derived from the address. +adapter.enabled = False +adapter.enabled = True +print("reset", adapter.name) +print("address", adapter.address) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_NAME_RESET_ON_ENABLE_CODE}) +def test_bsim_name_resets_on_enable(bsim_phy, circuitpython): + """Disabling and re-enabling the adapter restores the default name.""" + circuitpython.wait_until_done() + + output = _clean(circuitpython.serial.all_output) + default_name = re.search(r"(?m)^default (\S+)$", output).group(1) + assert re.search(r"(?m)^custom CUSTOM$", output) is not None + reset_name = re.search(r"(?m)^reset (\S+)$", output).group(1) + address_repr = re.search(r"(?m)^address (.+)$", output).group(1).strip() + + # The custom name is gone and the address-derived default is back. + assert reset_name != "CUSTOM" + assert reset_name == _expected_default_name(address_repr) + # The re-applied default matches the boot-time default. + assert reset_name == default_name + assert re.search(r"(?m)^done$", output) is not None diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py new file mode 100644 index 00000000000..1336d37fbd0 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py @@ -0,0 +1,183 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Nordic UART Service (NUS) tests for bsim — using adafruit_ble library.""" + +import pytest + +from .conftest import get_library_files + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") + +# ---- Test 1: CP peripheral hosts NUS, Zephyr central writes and reads ---- + +BSIM_NUS_PERIPHERAL_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.services.nordic import UARTService + +ble = BLERadio() +uart = UARTService() +print("service created") + +advertisement = ProvideServicesAdvertisement(uart) +advertisement.complete_name = "CPNUS" +ble.start_advertising(advertisement) +print("advertising") + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +# Wait for data to arrive from central +data = uart.read(5) +print("received", data) + +# Send a response back +uart.write(b"World") +print("sent response") + +time.sleep(1.0) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.zephyr_sample("tests/bsim/samples/central_nus_client") +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_NUS_PERIPHERAL_CODE, + "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n", + **_ADAFRUIT_BLE, + } +) +def test_bsim_nus_peripheral(bsim_phy, circuitpython, zephyr_sample): + """CP hosts NUS peripheral; Zephyr central writes to RX, reads TX notifications.""" + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + sample_output = zephyr_sample.serial.all_output + + assert "service created" in cp_output + assert "connected True" in cp_output + assert "received" in cp_output + assert "sent response" in cp_output + assert "NUS: received 'World'" in sample_output + + +# ---- Test 2: CP-to-CP NUS (peripheral + central) ---- + +BSIM_NUS_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.services.nordic import UARTService + +ble = BLERadio() +uart = UARTService() +print("service created") + +advertisement = ProvideServicesAdvertisement(uart) +advertisement.complete_name = "CP2CP" +ble.start_advertising(advertisement) +print("advertising") + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +# Read incoming data from central +data = uart.read(6) +print("received", data) + +# Respond back +uart.write(b"OK!") +print("sent response") + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_NUS_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.services.nordic import UARTService + +ble = BLERadio() + +print("client start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=8.0): + if adv.connectable and adv.complete_name == "CP2CP": + target = adv + print("found server") + break +ble.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) +print("connected", connection.connected) + +uart = connection[UARTService] +print("discovered services", 1) + +# Write to server +uart.write(b"Hello!") +print("wrote to rx") + +data = uart.read(3) +print("received", data) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": BSIM_NUS_SERVER_CODE, **_ADAFRUIT_BLE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_NUS_CLIENT_CODE, **_ADAFRUIT_BLE}) +def test_bsim_nus_cp_to_cp(bsim_phy, circuitpython1, circuitpython2): + """CP peripheral hosts NUS; CP central writes to RX, reads TX via notifications.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "received" in server_output + assert "sent response" in server_output + + assert "client start" in client_output + assert "found server" in client_output + assert "have target True" in client_output + assert "connected True" in client_output + assert "discovered services 1" in client_output + assert "wrote to rx" in client_output + assert "received b'OK!'" in client_output + assert "done" in client_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py new file mode 100644 index 00000000000..d5ff222ff5d --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py @@ -0,0 +1,1140 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""PacketBuffer tests for bsim.""" + +import re + +import pytest + + +# ---- Test 1: Server-side PacketBuffer incoming (WRITE characteristic) ---- + +BSIM_PB_SERVER_IN_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +# Wrap in PacketBuffer for incoming packets +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBIN" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Read first incoming packet +data = bytearray(20) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("packet1", data[:n]) + +# Read second incoming packet +n2 = 0 +deadline2 = time.monotonic() + 5.0 +while n2 == 0 and time.monotonic() < deadline2: + n2 = pb.readinto(data) + if n2 == 0: + time.sleep(0.05) +print("packet2", data[:n2]) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_CLIENT_IN_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBIN" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +print("discovered services", len(services)) + +remote_char = services[0].characteristics[0] +print("found char") + +# Write two packets +remote_char.value = bytes([0x01, 0x02, 0x03, 0x04]) +print("wrote packet1") + +time.sleep(0.3) + +remote_char.value = bytes([0xAA, 0xBB, 0xCC, 0xDD, 0xEE]) +print("wrote packet2") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(25) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_SERVER_IN_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_CLIENT_IN_CODE}) +def test_bsim_packet_buffer_server_incoming(bsim_phy, circuitpython1, circuitpython2): + """PacketBuffer on server-side WRITE characteristic receives framed packets.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "packet1" in server_output + assert "packet2" in server_output + assert "done" in server_output + + assert "found server" in client_output + assert "wrote packet1" in client_output + assert "wrote packet2" in client_output + + +# ---- Test 2: Server-side PacketBuffer write/flush (NOTIFY response) ---- + +BSIM_PB_BIDI_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +# Wrap in PacketBuffer for incoming packets and outgoing notifications +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBBI" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Read incoming packet from client +data = bytearray(20) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("received", data[:n]) + +# Write response back (via NOTIFY) — sends immediately via completion callback +pb.write(bytes([0x52, 0x45, 0x53, 0x50])) # "RESP" +print("sent response") + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_BIDI_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBBI" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +print("discovered services", len(services)) + +remote_char = services[0].characteristics[0] +print("found char, props", remote_char.properties) + +# Write a packet to the server +remote_char.value = bytes([0x48, 0x45, 0x4C, 0x4C, 0x4F]) # "HELLO" +print("wrote hello") + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_BIDI_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_BIDI_CLIENT_CODE}) +def test_bsim_packet_buffer_bidirectional(bsim_phy, circuitpython1, circuitpython2): + """Bidirectional PacketBuffer: server receives WRITE, sends NOTIFY response.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "received" in server_output + assert "sent response" in server_output + assert "done" in server_output + + assert "found server" in client_output + assert "wrote hello" in client_output + assert "done" in client_output + + +# ---- Test 3: PacketBuffer with multiple queued incoming packets ---- + +BSIM_PB_QUEUE_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +# Small buffer: only 1 packet, small max_packet_size +pb = _bleio.PacketBuffer(char, buffer_size=1, max_packet_size=10) +print("service created") + +name = b"CPPBQU" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Wait for client to send all packets +time.sleep(1.0) + +# Read packets - with buffer_size=1, oldest packets are dropped +data = bytearray(20) + +n1 = pb.readinto(data) +print("pkt1", data[:n1]) + +n2 = pb.readinto(data) +print("pkt2", data[:n2]) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_QUEUE_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBQU" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write 3 packets quickly (buffer only holds 2, so oldest should be dropped) +remote_char.value = bytes([0x01, 0x02, 0x03]) +print("wrote pkt1") + +time.sleep(0.1) + +remote_char.value = bytes([0x04, 0x05, 0x06]) +print("wrote pkt2") + +time.sleep(0.1) + +remote_char.value = bytes([0x07, 0x08, 0x09]) +print("wrote pkt3") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_QUEUE_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_QUEUE_CLIENT_CODE}) +def test_bsim_packet_buffer_queue(bsim_phy, circuitpython1, circuitpython2): + """PacketBuffer queues multiple packets; oldest dropped when buffer full.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + # With buffer_size=1, only the last packet(s) remain + assert "pkt1" in server_output + assert "pkt2" in server_output + assert "done" in server_output + + assert "wrote pkt1" in client_output + assert "wrote pkt2" in client_output + assert "wrote pkt3" in client_output + + +# ---- Test 4: readinto with buffer too small returns negative ---- + +BSIM_PB_OVERFLOW_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBOV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Try to read a 5-byte packet into a 3-byte buffer -> ValueError +try: + data = bytearray(3) + n = 0 + deadline = time.monotonic() + 5.0 + while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) + print("unexpected success", n) +except ValueError as e: + print("valueerror", e) + +time.sleep(0.5) +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_OVERFLOW_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBOV" in entry.advertisement_bytes: + target = entry.address + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write a 5-byte packet, but server only has a 3-byte read buffer +remote_char.value = bytes([0x01, 0x02, 0x03, 0x04, 0x05]) +print("wrote 5 bytes") + +time.sleep(0.5) +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(25) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_OVERFLOW_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_OVERFLOW_CLIENT_CODE}) +def test_bsim_packet_buffer_readinto_overflow(bsim_phy, circuitpython1, circuitpython2): + """readinto returns negative when packet is larger than buffer.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "valueerror" in server_output + + assert "wrote 5 bytes" in client_output + + +# ---- Test 5: write() with header kwarg ---- + +BSIM_PB_HEADER_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBHD" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Read an incoming packet +data = bytearray(20) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("received", data[:n]) + +# Response: write body with a header — header goes at start of packet +pb.write(bytes([0x42, 0x4F, 0x44, 0x59]), header=bytes([0x48, 0x44])) # "HD" + "BODY" +print("sent with header") + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_HEADER_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBHD" in entry.advertisement_bytes: + target = entry.address + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write a packet to trigger the server's response +remote_char.value = bytes([0x47, 0x4F]) +print("wrote trigger") + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(25) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_HEADER_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_HEADER_CLIENT_CODE}) +def test_bsim_packet_buffer_write_header(bsim_phy, circuitpython1, circuitpython2): + """write() header kwarg prepends to packet body.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "received" in server_output + assert "sent with header" in server_output + + assert "wrote trigger" in client_output + + +# ---- Test 6: incoming_packet_length / outgoing_packet_length ---- + +BSIM_PB_LENGTHS_CODE = """\ +import _bleio + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +pb = _bleio.PacketBuffer(char, buffer_size=2, max_packet_size=15) + +# incoming_packet_length reflects the max we can receive (characteristic max_length) +print("incoming", pb.incoming_packet_length) +# outgoing_packet_length requires a connection to know the negotiated ATT MTU, +# so without one it raises ValueError (server-side NOTIFY is MTU-bounded). +try: + print("outgoing", pb.outgoing_packet_length) +except ValueError as e: + print("outgoing valueerror", e) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_LENGTHS_CODE}) +def test_bsim_packet_buffer_packet_lengths(bsim_phy, circuitpython): + """incoming_packet_length and outgoing_packet_length properties.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + + # Server-side local characteristic: + # incoming = max_length = 20 + # outgoing requires a connection to know the ATT MTU, so it raises without one. + assert "incoming 20" in output + assert "outgoing valueerror" in output + assert "done" in output + + +# ---- Test 7: disconnect / reconnect, conn tracking ---- + +BSIM_PB_RECONNECT_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBRC" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) + +# First connection +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected1", adapter.connected) + +# Read first packet +data = bytearray(20) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("packet1", data[:n]) + +# Send a response to confirm the tracked conn works +pb.write(bytes([0x41, 0x43, 0x4B])) # "ACK" +print("sent ack1") + +# Wait for disconnect +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("disconnected") + +# Start advertising again for second connection +adapter.start_advertising(advertisement, connectable=True) + +# Second connection +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected2", adapter.connected) + +# Read second packet (should track new conn) +n2 = 0 +deadline2 = time.monotonic() + 5.0 +while n2 == 0 and time.monotonic() < deadline2: + n2 = pb.readinto(data) + if n2 == 0: + time.sleep(0.05) +print("packet2", data[:n2]) + +pb.write(bytes([0x41, 0x43, 0x4B])) # "ACK" +print("sent ack2") + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_RECONNECT_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +# First connection +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBRC" in entry.advertisement_bytes: + target = entry.address + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected1", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write first packet +remote_char.value = bytes([0x46, 0x49, 0x52, 0x53, 0x54]) # "FIRST" +print("wrote first") + +time.sleep(0.5) + +# Disconnect +connection.disconnect() +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("disconnected") + +# Wait for server to re-advertise +time.sleep(0.5) + +# Second connection +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBRC" in entry.advertisement_bytes: + target = entry.address + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected2", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write second packet +remote_char.value = bytes([0x53, 0x45, 0x43, 0x4E, 0x44]) # "SECOND" +print("wrote second") + +time.sleep(0.5) +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PB_RECONNECT_SERVER_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PB_RECONNECT_CLIENT_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +def test_bsim_packet_buffer_reconnect(bsim_phy, circuitpython1, circuitpython2): + """PacketBuffer tracks conn through disconnect / reconnect.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected1 True" in server_output + assert "packet1" in server_output + assert "sent ack1" in server_output + assert "disconnected" in server_output + assert "connected2 True" in server_output + assert "packet2" in server_output + assert "sent ack2" in server_output + + assert "wrote first" in client_output + assert "wrote second" in client_output + + +# ---- Test 8: outgoing_packet_length bounded by negotiated MTU ---- +# +# Regression test for the "No ATT channel for MTU" bug. The server-side +# PacketBuffer's outgoing_packet_length must be bounded by the negotiated +# ATT MTU (ATT_MTU - 3), not just max_packet_size. Without that bounding, +# the workflow packs a notification larger than the MTU and bt_gatt_notify_cb +# fails silently ("No ATT channel for MTU"), so the client never receives it. +# +# The characteristic is configured with max_length=600 and max_packet_size=600, +# deliberately larger than any plausible negotiated ATT MTU (the stack supports +# up to CONFIG_BT_L2CAP_TX_MTU = 515, payload 512). So without the fix, +# outgoing_packet_length returns 600 and the 600-byte notification always +# exceeds the MTU and is dropped — regardless of whether an MTU exchange +# happened. With the fix, outgoing_packet_length is ATT_MTU - 3 (≤ 512) and the +# notification fits and is delivered. + +BSIM_PB_MTU_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=600, fixed_length=False, +) + +# max_packet_size deliberately larger than any negotiated ATT MTU so that an +# unbounded outgoing_packet_length always produces an oversized, undeliverable +# notification regardless of MTU-exchange timing. +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=600) +print("service created") + +name = b"CPPBMT" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Wait for the client to subscribe (CCCD write) and send a trigger write. +data = bytearray(600) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("trigger", data[:n]) + +# The negotiated ATT MTU determines the largest notification payload. The +# connection's max_packet_length is ATT_MTU - 3. +conn = adapter.connections[0] +mtu_payload = conn.max_packet_length +print("mtu_payload", mtu_payload) + +# outgoing_packet_length must be bounded by the MTU, not max_packet_size. +opl = pb.outgoing_packet_length +print("outgoing", opl) + +# Send a response sized exactly to outgoing_packet_length, like the BLE +# file-transfer workflow does. With the fix this fits the MTU and is delivered. +response = bytes([0xAA]) * opl +pb.write(response) +print("sent", len(response)) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_MTU_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBMT" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] +print("found char, props", remote_char.properties) + +# Creating a client-side PacketBuffer on a NOTIFY characteristic writes the +# CCCD to subscribe, which gives the server a connection to notify. +client_pb = _bleio.PacketBuffer(remote_char, buffer_size=4, max_packet_size=600) +print("subscribed") + +# Trigger the server's response with a direct write. +remote_char.value = b"GO" +print("wrote trigger") + +# Read the notification response. Without the MTU fix the server sends an +# oversized notification that the ATT layer drops, so this times out. +buf = bytearray(600) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = client_pb.readinto(buf) + if n == 0: + time.sleep(0.05) +if n > 0: + print("received_ok", n, bytes(buf[:n])) +else: + print("received_none") + +time.sleep(0.5) +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_MTU_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_MTU_CLIENT_CODE}) +def test_bsim_packet_buffer_outgoing_mtu_bounded(bsim_phy, circuitpython1, circuitpython2): + """Server-side outgoing_packet_length is bounded by the negotiated ATT MTU. + + Without the fix, outgoing_packet_length returns max_packet_size (200) and + the resulting notification exceeds the bsim default ATT MTU (23), so the + ATT layer drops it ("No ATT channel for MTU") and the client receives + nothing. With the fix, outgoing_packet_length is ATT_MTU - 3 (20) and the + notification is delivered to the client. + """ + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "trigger" in server_output + + # outgoing_packet_length must not exceed the connection's MTU-derived + # max_packet_length. Without the fix this is 200 vs 20. + mtu_match = re.search(r"mtu_payload (\d+)", server_output) + outgoing_match = re.search(r"outgoing (\d+)", server_output) + assert mtu_match is not None, f"mtu_payload not printed: {server_output}" + assert outgoing_match is not None, f"outgoing not printed: {server_output}" + mtu_payload = int(mtu_match.group(1)) + outgoing = int(outgoing_match.group(1)) + assert outgoing <= mtu_payload, ( + f"outgoing_packet_length {outgoing} exceeds MTU payload {mtu_payload}; " + "notifications this size would be dropped by the ATT layer" + ) + assert outgoing < 600, f"outgoing_packet_length {outgoing} not bounded below max_packet_size" + + # The notification sized to outgoing_packet_length must actually arrive. + assert "received_ok" in client_output, ( + f"client never received the notification (MTU-bound bug): {client_output}" + ) + assert "received_none" not in client_output + + received_match = re.search(r"received_ok (\d+)", client_output) + assert received_match is not None + received = int(received_match.group(1)) + assert received == outgoing, f"client received {received} bytes, server sent {outgoing}" + + +# ---- Test: client-side PacketBuffer write (remote WRITE_NO_RESPONSE) ---- +# +# Covers the client-side write path in common_hal_bleio_packet_buffer_write +# (the is_remote branch): a CP central wraps a remote characteristic in a +# _bleio.PacketBuffer and writes to it via pb.write(...), which must reach the +# peripheral's server-side PacketBuffer. This mirrors how the BLE file-transfer +# library sends commands (raw.write). It also exercises the header+data combine +# in the client write path via pb.write(data, header=...). +# +# The characteristic uses WRITE_NO_RESPONSE | NOTIFY with open permissions, so +# no pairing is required and the test runs on both bsim boards. + +BSIM_PB_CLIENT_WRITE_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE_NO_RESPONSE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.OPEN, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +# Server-side PacketBuffer: reads incoming WRITE_NO_RESPONSE, echoes via NOTIFY. +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBCW" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +data = bytearray(20) +for _ in range(2): + n = 0 + deadline = time.monotonic() + 5.0 + while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) + print("received", bytes(data[:n])) + # Echo the packet straight back over NOTIFY. + pb.write(bytes(data[:n])) + print("echoed", bytes(data[:n])) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_CLIENT_WRITE_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBCW" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +print("discovered services", len(services)) + +remote_char = services[0].characteristics[0] +print("found char, props", remote_char.properties) + +# Client-side PacketBuffer on the remote characteristic: subscribes to NOTIFY +# (readinto) and writes to the remote (pb.write -> client-side write path). +cpb = _bleio.PacketBuffer(remote_char, buffer_size=4, max_packet_size=20) + +# Write 1: plain write (no header) — exercises bt_gatt_write_without_response. +cpb.write(b"PING") +print("wrote ping") + +# Write 2: write with a header — exercises the header+data combine in the +# client write path. "B" + "ODY" is sent as a single "BODY" packet. +cpb.write(b"ODY", header=b"B") +print("wrote body with header") + +# Read both NOTIFY echoes back. +buf = bytearray(20) +for _ in range(2): + n = 0 + deadline = time.monotonic() + 5.0 + while n == 0 and time.monotonic() < deadline: + n = cpb.readinto(buf) + if n == 0: + time.sleep(0.05) + print("client received", bytes(buf[:n])) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(35) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_CLIENT_WRITE_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_CLIENT_WRITE_CLIENT_CODE}) +def test_bsim_packet_buffer_client_write(bsim_phy, circuitpython1, circuitpython2): + """A CP central writes to a remote characteristic via a client-side + PacketBuffer (pb.write), and the peripheral echoes it back over NOTIFY. + + Covers the client-side write path (remote WRITE_NO_RESPONSE), including the + header+data combine, mirroring how the BLE file-transfer library sends + commands. + """ + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + # Server received both client writes (plain + header-combined). + assert "received b'PING'" in server_output, ( + f"server never received the plain client write: {server_output}" + ) + assert "received b'BODY'" in server_output, ( + f"server never received the header-combined client write: {server_output}" + ) + assert "echoed b'PING'" in server_output + assert "echoed b'BODY'" in server_output + assert "done" in server_output + + # Client wrote both and got both echoes back over NOTIFY. + assert "wrote ping" in client_output, f"client plain write did not complete: {client_output}" + assert "wrote body with header" in client_output, ( + f"client header write did not complete: {client_output}" + ) + # Be vague here because PING and BODY may be in separate packets or merged. + assert "b'PING" in client_output, f"client never received the PING echo: {client_output}" + assert "BODY'" in client_output, f"client never received the BODY echo: {client_output}" + assert "done" in client_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py new file mode 100644 index 00000000000..850b2fc8957 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py @@ -0,0 +1,364 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE pairing tests for the bsim boards.""" + +import pytest + +BSIM_PERIPHERAL_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"PAIRPERIPH" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("peripheral start") +adapter.start_advertising(advertisement, connectable=True) +print("peripheral advertising", adapter.advertising) + +# Wait for connection +timeout = time.monotonic() + 12.0 +while not adapter.connected and time.monotonic() < timeout: + time.sleep(0.01) + +if not adapter.connected: + print("peripheral connect timed out") + raise SystemExit(1) + +print("peripheral connected", adapter.connected) + +# Wait for pairing to complete (central initiates it) +# The peripheral's SMP module responds automatically. +timeout = time.monotonic() + 10.0 +paired = False +while time.monotonic() < timeout: + if adapter.connected and len(adapter.connections) > 0: + conn = adapter.connections[0] + if conn.paired: + paired = True + break + time.sleep(0.1) + +print("peripheral paired", paired) + +# Wait for disconnect +timeout = time.monotonic() + 10.0 +while adapter.connected and time.monotonic() < timeout: + time.sleep(0.1) + +print("peripheral disconnected", adapter.connected, len(adapter.connections)) +""" + +BSIM_CENTRAL_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("central start") +target = None +for entry in adapter.start_scan(timeout=8.0, active=True): + if entry.connectable and b"PAIRPERIPH" in entry.advertisement_bytes: + target = entry.address + print("central found target") + break +adapter.stop_scan() +print("central have target", target is not None) + +if target is None: + raise RuntimeError("No connectable target found") + +connection = adapter.connect(target, timeout=5.0) +print("central connected", connection.connected, adapter.connected, len(adapter.connections)) + +# Pair with the peripheral (Just Works pairing) +connection.pair() +print("central paired", connection.paired) + +# Disconnect cleanly +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while (connection.connected or adapter.connected) and time.monotonic() < timeout: + time.sleep(0.1) + +print("central disconnected", connection.connected, adapter.connected, len(adapter.connections)) +""" + + +@pytest.mark.duration(22) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PERIPHERAL_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CENTRAL_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +def test_bsim_pairing_cp_to_cp(bsim_phy, board, circuitpython1, circuitpython2): + """Two CP instances: device 0 peripheral, device 1 central pairs to it.""" + peripheral = circuitpython1 + central = circuitpython2 + + central.wait_until_done() + peripheral.wait_until_done() + + periph_output = peripheral.serial.all_output + central_output = central.serial.all_output + + # Peripheral assertions + assert "peripheral start" in periph_output + assert "peripheral advertising True" in periph_output + assert "peripheral connected True" in periph_output + assert "peripheral paired True" in periph_output + assert "peripheral disconnected False 0" in periph_output + + # Central assertions + assert "central start" in central_output + assert "central found target" in central_output + assert "central have target True" in central_output + assert "central connected True True 1" in central_output + assert "central paired True" in central_output + assert "central disconnected False False 0" in central_output + + +BSIM_CENTRAL_PAIRED_PROPERTY_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("central start") +target = None +for entry in adapter.start_scan(timeout=8.0, active=True): + if entry.connectable and b"PAIRPERIPH" in entry.advertisement_bytes: + target = entry.address + print("central found target") + break +adapter.stop_scan() + +if target is None: + raise RuntimeError("No connectable target found") + +connection = adapter.connect(target, timeout=5.0) +print("central connected", connection.connected) + +# Check paired is False before pairing +print("central paired before", connection.paired) + +connection.pair() +print("central paired after", connection.paired) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while (connection.connected or adapter.connected) and time.monotonic() < timeout: + time.sleep(0.1) + +print("central disconnected", connection.connected) +""" + + +@pytest.mark.duration(22) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PERIPHERAL_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_CENTRAL_PAIRED_PROPERTY_CODE, + "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n", + } +) +def test_bsim_pairing_paired_property(bsim_phy, board, circuitpython1, circuitpython2): + """Verify connection.paired transitions from False to True after pairing.""" + peripheral = circuitpython1 + central = circuitpython2 + + central.wait_until_done() + peripheral.wait_until_done() + + periph_output = peripheral.serial.all_output + central_output = central.serial.all_output + + assert "peripheral paired True" in periph_output + + assert "central paired before False" in central_output + assert "central paired after True" in central_output + assert "central disconnected False" in central_output + + +BSIM_PERIPHERAL_BOND_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"BONDPERIPH" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("peripheral start") + +# First connection - pair +adapter.start_advertising(advertisement, connectable=True) +print("peripheral advertising", adapter.advertising) + +timeout = time.monotonic() + 12.0 +while not adapter.connected and time.monotonic() < timeout: + time.sleep(0.01) + +if not adapter.connected: + print("peripheral connect1 timed out") + raise SystemExit(1) + +print("peripheral connected1", adapter.connected) + +# Wait for pairing +timeout = time.monotonic() + 10.0 +paired = False +while time.monotonic() < timeout: + if adapter.connected and len(adapter.connections) > 0: + conn = adapter.connections[0] + if conn.paired: + paired = True + break + time.sleep(0.1) + +print("peripheral paired1", paired) + +# Wait for disconnect +timeout = time.monotonic() + 10.0 +while adapter.connected and time.monotonic() < timeout: + time.sleep(0.1) + +print("peripheral disconnected1", adapter.connected, len(adapter.connections)) + +# Second connection - bond should persist through storage. +# Calling pair() uses the stored bond keys without re-pairing. +time.sleep(0.5) +adapter.start_advertising(advertisement, connectable=True) +print("peripheral advertising2", adapter.advertising) + +timeout = time.monotonic() + 12.0 +while not adapter.connected and time.monotonic() < timeout: + time.sleep(0.01) + +if not adapter.connected: + print("peripheral connect2 timed out") + raise SystemExit(1) + +print("peripheral connected2", adapter.connected) + +# Request security to restore bond encryption +conn = adapter.connections[0] +conn.pair() +print("peripheral paired2", conn.paired) + +# Wait for disconnect +timeout = time.monotonic() + 10.0 +while adapter.connected and time.monotonic() < timeout: + time.sleep(0.1) + +print("peripheral disconnected2", adapter.connected) +""" + +BSIM_CENTRAL_BOND_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("central start") +target_addr = None +for entry in adapter.start_scan(timeout=8.0, active=True): + if entry.connectable and b"BONDPERIPH" in entry.advertisement_bytes: + target_addr = entry.address + print("central found target") + break +adapter.stop_scan() +print("central have target", target_addr is not None) + +if target_addr is None: + raise RuntimeError("No connectable target found") + +# First connection - pair +connection = adapter.connect(target_addr, timeout=5.0) +print("central connected1", connection.connected, adapter.connected, len(adapter.connections)) + +print("central paired before1", connection.paired) +connection.pair() +print("central paired after1", connection.paired) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while (connection.connected or adapter.connected) and time.monotonic() < timeout: + time.sleep(0.1) + +print("central disconnected1", connection.connected, adapter.connected) + +# Second connection - bond should be restored from storage. +# Calling pair() uses the stored bond keys without re-pairing. +time.sleep(1.0) +connection2 = adapter.connect(target_addr, timeout=5.0) +print("central connected2", connection2.connected, adapter.connected, len(adapter.connections)) + +connection2.pair() +print("central paired bond", connection2.paired) + +connection2.disconnect() + +timeout = time.monotonic() + 4.0 +while (connection2.connected or adapter.connected) and time.monotonic() < timeout: + time.sleep(0.1) + +print("central disconnected2", connection2.connected, adapter.connected) +""" + + +@pytest.mark.duration(35) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PERIPHERAL_BOND_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CENTRAL_BOND_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +def test_bsim_bonding_persistence(bsim_phy, board, circuitpython1, circuitpython2): + """Verify bonds are saved to storage and survive disconnect/reconnect. + + Central pairs with peripheral, disconnects, then reconnects. + On the second connection the bond should be restored from storage + and connection.paired should be True without calling pair() again. + """ + peripheral = circuitpython1 + central = circuitpython2 + + central.wait_until_done() + peripheral.wait_until_done() + + periph_output = peripheral.serial.all_output + central_output = central.serial.all_output + + # Peripheral assertions - first connection + assert "peripheral start" in periph_output + assert "peripheral advertising True" in periph_output + assert "peripheral connected1 True" in periph_output + assert "peripheral paired1 True" in periph_output + assert "peripheral disconnected1 False 0" in periph_output + # Peripheral - second connection (private advertising, bond restored from storage) + assert "peripheral advertising2 True" in periph_output + assert "peripheral connected2 True" in periph_output + assert "peripheral paired2 True" in periph_output + assert "peripheral disconnected2 False" in periph_output + + # Central assertions - first connection + assert "central start" in central_output + assert "central found target" in central_output + assert "central have target True" in central_output + assert "central connected1 True True 1" in central_output + assert "central paired before1 False" in central_output + assert "central paired after1 True" in central_output + assert "central disconnected1 False False" in central_output + # Central - second connection (bond restored from storage) + assert "central connected2 True True 1" in central_output + assert "central paired bond True" in central_output + assert "central disconnected2 False False" in central_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py new file mode 100644 index 00000000000..ff99b789f0c --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py @@ -0,0 +1,121 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE peripheral connection tests for bsim.""" + +import pytest + + +BSIM_PERIPHERAL_CODE = """\ +import _bleio +import time +import sys + +adapter = _bleio.adapter + +name = b"CPPERIPH" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("peripheral start") +adapter.start_advertising(advertisement, connectable=True) +print("advertising", adapter.advertising) + +was_connected = False +timeout = time.monotonic() + 8.0 +while not was_connected and time.monotonic() < timeout: + time.sleep(0.01) + was_connected = adapter.connected + +if not was_connected: + print("connect timed out") + sys.exit(-1) + +print("connected", was_connected, "advertising", adapter.advertising) + +if was_connected: + timeout = time.monotonic() + 8.0 + while adapter.connected and time.monotonic() < timeout: + time.sleep(0.1) + +print("disconnected", adapter.connected, len(adapter.connections)) +""" + +BSIM_CENTRAL_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("central start") +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPERIPH" in entry.advertisement_bytes: + target = entry.address + print("found peripheral") + break +adapter.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No connectable peripheral found") + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected, adapter.connected, len(adapter.connections)) +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while (connection.connected or adapter.connected) and time.monotonic() < timeout: + time.sleep(0.1) + +print("disconnected", connection.connected, adapter.connected, len(adapter.connections)) +""" + + +@pytest.mark.zephyr_sample("bluetooth/central") +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PERIPHERAL_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +def test_bsim_peripheral_zephyr_central(bsim_phy, circuitpython, zephyr_sample): + """Advertise as connectable from CP; Zephyr central connects and disconnects.""" + central = zephyr_sample + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + central_output = central.serial.all_output + + assert "peripheral start" in cp_output + assert "advertising True" in cp_output + assert "connected True advertising False" in cp_output + assert "disconnected False 0" in cp_output + + assert "Scanning successfully started" in central_output + assert "Connected:" in central_output + assert "Disconnected:" in central_output + + +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CENTRAL_CODE}) +def test_bsim_peripheral_cp_central(bsim_phy, circuitpython1, circuitpython2): + """Two CP instances: device 0 peripheral, device 1 central.""" + peripheral = circuitpython1 + central = circuitpython2 + + central.wait_until_done() + peripheral.wait_until_done() + + periph_output = peripheral.serial.all_output + central_output = central.serial.all_output + + assert "peripheral start" in periph_output + assert "advertising True" in periph_output + assert "connected True advertising False" in periph_output + assert "disconnected False 0" in periph_output + + assert "central start" in central_output + assert "found peripheral" in central_output + assert "have target True" in central_output + assert "connected True True 1" in central_output + assert "disconnected False False 0" in central_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py new file mode 100644 index 00000000000..15de1787cdc --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py @@ -0,0 +1,161 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE scanning tests for bsim.""" + +import pytest + + +BSIM_SCAN_CODE = """\ +import _bleio + +adapter = _bleio.adapter +print("scan start") +scan = adapter.start_scan(timeout=4.0, active=True) +found = False +for entry in scan: + if b"zephyrproject" in entry.advertisement_bytes: + print("found beacon") + found = True + break +adapter.stop_scan() +print("scan done", found) +""" + +BSIM_SCAN_RELOAD_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("scan run start") +found = False +for entry in adapter.start_scan(active=True): + if b"zephyrproject" in entry.advertisement_bytes: + print("found beacon run") + found = True + break +adapter.stop_scan() +print("scan run done", found) +""" + +BSIM_SCAN_RELOAD_NO_STOP_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("scan run start") +found = False +for entry in adapter.start_scan(active=True): + if b"zephyrproject" in entry.advertisement_bytes: + print("found beacon run") + found = True + break +print("scan run done", found) +""" + +BSIM_SCAN_ENTRY_PROPS_CODE = """\ +import _bleio + +adapter = _bleio.adapter +print("scan start") +found = None +for entry in adapter.start_scan(timeout=4.0, active=True): + if b"zephyrproject" in entry.advertisement_bytes: + found = entry + break +adapter.stop_scan() + +if found is not None: + print("rssi", found.rssi <= 0 and found.rssi > -100) + print("connectable", found.connectable) + print("scan_response", found.scan_response) + print("address_bytes", len(found.address.address_bytes)) + print("address_type", found.address.type in (0, 1, 2, 3)) + print("adv_bytes_type", isinstance(found.advertisement_bytes, bytes)) +else: + print("no entry found") +print("done") +""" + +BSIM_SCAN_PASSIVE_CODE = """\ +import _bleio + +adapter = _bleio.adapter +print("scan passive start") +found = False +for entry in adapter.start_scan(timeout=4.0, active=False): + if b"zephyrproject" in entry.advertisement_bytes: + print("found beacon passive") + found = True + break +adapter.stop_scan() +print("scan passive done", found) +""" + + +@pytest.mark.zephyr_sample("bluetooth/beacon") +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_CODE}) +def test_bsim_scan_zephyr_beacon(bsim_phy, circuitpython, zephyr_sample): + """Scan for Zephyr beacon sample advertisement using bsim.""" + _ = zephyr_sample + + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "scan start" in output + assert "found beacon" in output + assert "scan done True" in output + + +@pytest.mark.zephyr_sample("bluetooth/beacon") +@pytest.mark.port_resets(3) +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_RELOAD_CODE}) +def test_bsim_scan_zephyr_beacon_reload(bsim_phy, circuitpython, zephyr_sample): + """Scan for Zephyr beacon, soft reload, and scan again.""" + _ = zephyr_sample + + circuitpython.serial.wait_for("scan run done") + circuitpython.serial.wait_for("Press any key to enter the REPL") + circuitpython.serial.write("\x04") + + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert output.count("scan run start") >= 2 + assert output.count("found beacon run") >= 2 + assert output.count("scan run done True") >= 2 + + +@pytest.mark.zephyr_sample("bluetooth/beacon") +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_ENTRY_PROPS_CODE}) +def test_bsim_scan_entry_properties(bsim_phy, circuitpython, zephyr_sample): + """Verify ScanEntry properties: rssi, connectable, scan_response, address, advertisement_bytes.""" + _ = zephyr_sample + + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "rssi True" in output + assert "connectable False" in output # beacon is non-connectable + assert "scan_response False" in output + assert "address_bytes 6" in output + assert "address_type True" in output + assert "adv_bytes_type True" in output + assert "done" in output + + +@pytest.mark.zephyr_sample("bluetooth/beacon") +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_PASSIVE_CODE}) +def test_bsim_scan_passive(bsim_phy, circuitpython, zephyr_sample): + """Passive scan finds Zephyr beacon.""" + _ = zephyr_sample + + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "scan passive start" in output + assert "found beacon passive" in output + assert "scan passive done True" in output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py new file mode 100644 index 00000000000..1d4174835d0 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py @@ -0,0 +1,715 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE GATT service tests for bsim.""" + +import pytest + +from .conftest import get_library_files + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") + +# --------------------------------------------------------------------------- +# Shared service libraries +# --------------------------------------------------------------------------- + +BATTERY_LIB = """ +from adafruit_ble.services import Service +from adafruit_ble.characteristics import Characteristic, Attribute +from adafruit_ble.uuid import StandardUUID + + +class BatteryService(Service): + uuid = StandardUUID(0x180F) + level = Characteristic( + uuid=StandardUUID(0x2A19), + properties=Characteristic.READ | Characteristic.WRITE, + read_perm=Attribute.OPEN, + write_perm=Attribute.OPEN, + max_length=1, + fixed_length=True, + initial_value=bytes([75]), + )""" + +HEART_RATE_LIB = """ +from adafruit_ble.services import Service +from adafruit_ble.characteristics import Characteristic, Attribute +from adafruit_ble.uuid import StandardUUID + + +class HeartRateService(Service): + uuid = StandardUUID(0x180D) + measurement = Characteristic( + uuid=StandardUUID(0x2A37), + properties=Characteristic.READ, + read_perm=Attribute.OPEN, + write_perm=Attribute.NO_ACCESS, + max_length=2, + fixed_length=True, + initial_value=bytes([0, 72]), + )""" + +# =================================================================== +# Test 1: Battery Service (Zephyr central) +# =================================================================== + +BSIM_SERVICE_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService + +ble = BLERadio() +svc = BatteryService() +print("service created") + +advertisement = ProvideServicesAdvertisement(svc) +ble.start_advertising(advertisement) +print("advertising") + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.zephyr_sample("tests/bsim/samples/central_battery_client") +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_SERVICE_CODE, + "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n", + "battery_service.py": BATTERY_LIB, + **_ADAFRUIT_BLE, + } +) +def test_bsim_service_battery(bsim_phy, circuitpython, zephyr_sample): + """CP hosts BatteryService; Zephyr central reads battery level.""" + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + sample_output = zephyr_sample.serial.all_output + + assert "service created" in cp_output + assert "connected True" in cp_output + assert "Battery Level: 75" in sample_output + + +# =================================================================== +# Test 2: CP client reads/writes CP peripheral +# =================================================================== + +BSIM_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService + +ble = BLERadio() +svc = BatteryService() +print("service created") + +advertisement = ProvideServicesAdvertisement(svc) +ble.start_advertising(advertisement) +print("advertising") + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) + +print("final value", list(svc.level)) +print("done") +""" + +BSIM_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService + +ble = BLERadio() + +print("client start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + print("found server") + break +ble.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) +print("connected", connection.connected) + +svc = connection[BatteryService] +print("discovered services", 1) +print("discovered chars", 1) # BatteryService has one characteristic + +print("battery level", list(svc.level)) + +# Write a new value +svc.level = bytes([42]) +print("wrote new value") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) + +print("disconnected", not connection.connected) +""" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_SERVER_CODE, "battery_service.py": BATTERY_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CLIENT_CODE, "battery_service.py": BATTERY_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_cp_client(bsim_phy, circuitpython1, circuitpython2): + """CP peripheral hosts BatteryService; CP central discovers, reads, and writes.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "final value [42]" in server_output + + assert "client start" in client_output + assert "found server" in client_output + assert "discovered services 1" in client_output + assert "discovered chars 1" in client_output + assert "battery level [75]" in client_output + assert "wrote new value" in client_output + assert "disconnected True" in client_output + + +# =================================================================== +# Test 3: Discover all services (no whitelist) +# =================================================================== + +BSIM_DISCOVER_ALL_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService +from heart_rate import HeartRateService + +ble = BLERadio() +bas = BatteryService() +hrs = HeartRateService() +print("services created") + +advertisement = ProvideServicesAdvertisement(bas, hrs) +ble.start_advertising(advertisement) + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_DISCOVER_ALL_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService +from heart_rate import HeartRateService + +ble = BLERadio() + +print("client start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=8.0): + if adv.connectable: + target = adv + print("found server") + break +ble.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) +print("connected", connection.connected) + +# Discover ALL services (no whitelist) — use _bleio directly. +all_services = connection._bleio_connection.discover_remote_services() +print("total services", len(all_services)) + +# Filter to our two known UUIDs (ignore GATT/GAP services the stack may expose) +user_svcs = [s for s in all_services if s.uuid.uuid16 in (0x180F, 0x180D)] +print("user services", len(user_svcs)) + +uuids = sorted([s.uuid.uuid16 for s in user_svcs]) +print("service uuids", uuids) + +# Now read characteristics via adafruit_ble Service bindings. +if BatteryService in connection: + bas = connection[BatteryService] + print("char", hex(0x2a19), list(bas.level)) + +if HeartRateService in connection: + hrs = connection[HeartRateService] + print("char", hex(0x2a37), list(hrs.measurement)) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(35) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_DISCOVER_ALL_SERVER_CODE, + "battery_service.py": BATTERY_LIB, + "heart_rate.py": HEART_RATE_LIB, + **_ADAFRUIT_BLE, + } +) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_DISCOVER_ALL_CLIENT_CODE, + "battery_service.py": BATTERY_LIB, + "heart_rate.py": HEART_RATE_LIB, + **_ADAFRUIT_BLE, + } +) +def test_bsim_service_discover_all(bsim_phy, circuitpython1, circuitpython2): + """Discover all services without a UUID whitelist, verify two user services found.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + client_output = client.serial.all_output + + assert "user services 2" in client_output + assert "service uuids [6157, 6159]" in client_output # 0x180D=6157, 0x180F=6159 + assert "char 0x2a37 [0, 72]" in client_output + assert "char 0x2a19 [75]" in client_output + + +# =================================================================== +# Test 4: Write-no-response (uses MultiService from multi_service module) +# =================================================================== + +MULTI_LIB = """ +from adafruit_ble.services import Service +from adafruit_ble.characteristics import Characteristic, Attribute +from adafruit_ble.uuid import StandardUUID + + +class MultiService(Service): + uuid = StandardUUID(0x180F) + char_a = Characteristic( + uuid=StandardUUID(0x2A19), + properties=Characteristic.READ, + read_perm=Attribute.OPEN, + write_perm=Attribute.NO_ACCESS, + max_length=1, + fixed_length=True, + initial_value=bytes([10]), + ) + char_b = Characteristic( + uuid=StandardUUID(0x2A1A), + properties=Characteristic.READ | Characteristic.WRITE_NO_RESPONSE, + read_perm=Attribute.OPEN, + write_perm=Attribute.OPEN, + max_length=1, + fixed_length=True, + initial_value=bytes([20]), + ) + char_c = Characteristic( + uuid=StandardUUID(0x2A1B), + properties=Characteristic.READ, + read_perm=Attribute.OPEN, + write_perm=Attribute.NO_ACCESS, + max_length=1, + fixed_length=True, + initial_value=bytes([30]), + )""" + + +BSIM_MULTI_CHAR_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from multi_service import MultiService + +ble = BLERadio() +svc = MultiService() +# Force binding +svc.char_a +svc.char_b +svc.char_c +print("service created") + +advertisement = ProvideServicesAdvertisement(svc) +ble.start_advertising(advertisement) + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) + +print("char_b final", list(svc.char_b)) +print("done") +""" + +BSIM_WRITE_NR_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from multi_service import MultiService + +ble = BLERadio() + +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + break +ble.stop_scan() + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) + +svc = connection[MultiService] + +print("initial", list(svc.char_b)) + +# Write-no-response +svc.char_b = bytes([99]) +print("wrote wnr") + +# Give the server time to process the write +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(25) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_MULTI_CHAR_SERVER_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_WRITE_NR_CLIENT_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_write_no_response(bsim_phy, circuitpython1, circuitpython2): + """Client writes a characteristic using WRITE_NO_RESPONSE.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "char_b final [99]" in server_output + assert "initial [20]" in client_output + assert "wrote wnr" in client_output + + +# =================================================================== +# Test 5: Multiple characteristics on one service +# =================================================================== + +BSIM_MULTI_CHAR_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from multi_service import MultiService + +ble = BLERadio() + +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + break +ble.stop_scan() + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) + +svc = connection[MultiService] +print("num chars", 3) + +# Read each characteristic +print("char", hex(0x2A19), list(svc.char_a)) +print("char", hex(0x2A1A), list(svc.char_b)) +print("char", hex(0x2A1B), list(svc.char_c)) + +# Write to the second characteristic +svc.char_b = bytes([77]) +print("wrote 0x2a1a") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(25) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_MULTI_CHAR_SERVER_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_MULTI_CHAR_CLIENT_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_multi_char(bsim_phy, circuitpython1, circuitpython2): + """Service with three characteristics: discover all, read each, write one.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "num chars 3" in client_output + assert "char 0x2a19 [10]" in client_output + assert "char 0x2a1a [20]" in client_output + assert "char 0x2a1b [30]" in client_output + assert "wrote 0x2a1a" in client_output + assert "char_b final [77]" in server_output + + +# =================================================================== +# Test 6: 128-bit custom UUID +# =================================================================== + +CUSTOM_LIB = """ +from adafruit_ble.services import Service +from adafruit_ble.characteristics import Characteristic, Attribute +from adafruit_ble.uuid import VendorUUID + + +class CustomService(Service): + uuid = VendorUUID("12345678-1234-5678-1234-56789abcdef0") + data = Characteristic( + uuid=VendorUUID("12345678-1234-5678-1234-56789abcdef1"), + properties=Characteristic.READ | Characteristic.WRITE, + read_perm=Attribute.OPEN, + write_perm=Attribute.OPEN, + max_length=4, + fixed_length=False, + initial_value=bytes([0xDE, 0xAD]), + )""" + +BSIM_CUSTOM_UUID_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from custom_service import CustomService + +ble = BLERadio() +svc = CustomService() +print("service created") + +advertisement = ProvideServicesAdvertisement(svc) +ble.start_advertising(advertisement) + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) + +print("final value", list(svc.data)) +print("done") +""" + +BSIM_CUSTOM_UUID_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from custom_service import CustomService + +ble = BLERadio() + +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + break +ble.stop_scan() + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) + +svc = connection[CustomService] +print("discovered services", 1) + +print("char value", list(svc.data)) + +svc.data = bytes([0xBE, 0xEF]) +print("wrote custom") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(25) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CUSTOM_UUID_SERVER_CODE, "custom_service.py": CUSTOM_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CUSTOM_UUID_CLIENT_CODE, "custom_service.py": CUSTOM_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_custom_uuid(bsim_phy, circuitpython1, circuitpython2): + """128-bit custom UUID service: discover, read, and write.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "discovered services 1" in client_output + assert "char value [222, 173]" in client_output # 0xDE, 0xAD + assert "wrote custom" in client_output + assert "final value [190, 239]" in server_output # 0xBE, 0xEF + + +# =================================================================== +# Test 7: Empty discovery result +# =================================================================== + +BSIM_EMPTY_DISC_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from heart_rate import HeartRateService + +ble = BLERadio() + +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + print("found server") + break +ble.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) +print("connected", connection.connected) + +# Ask for Heart Rate Service which doesn't exist on this server +found = HeartRateService in connection +print("found services", 1 if found else 0) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CUSTOM_UUID_SERVER_CODE, "custom_service.py": CUSTOM_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_EMPTY_DISC_CLIENT_CODE, "heart_rate.py": HEART_RATE_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_empty_discovery(bsim_phy, circuitpython1, circuitpython2): + """Filter for a UUID that doesn't exist, verify empty tuple returned.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + client_output = client.serial.all_output + + assert "found services 0" in client_output + assert "done" in client_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_uuid.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_uuid.py new file mode 100644 index 00000000000..9dcf3b13847 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_uuid.py @@ -0,0 +1,331 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE UUID tests for bsim.""" + +import pytest + + +# --- 16-bit UUIDs --- + +BSIM_UUID_16BIT_CODE = """\ +import _bleio + +u16 = _bleio.UUID(0x180F) +print("uuid16", u16.uuid16) +print("size", u16.size) +print("str", str(u16)) +print("repr", repr(u16)) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_CODE}) +def test_bsim_uuid_16bit_basic(bsim_phy, circuitpython): + """Construct a 16-bit UUID and verify all properties.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "uuid16 6159" in output # 0x180F = 6159 + assert "size 16" in output + assert "UUID(0x180f)" in output + assert "done" in output + + +BSIM_UUID_16BIT_EQ_CODE = """\ +import _bleio + +a = _bleio.UUID(0x180F) +b = _bleio.UUID(0x180F) +c = _bleio.UUID(0x180D) + +print("eq_same", a == b) +print("eq_diff", a == c) +print("neq_diff", a != c) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_EQ_CODE}) +def test_bsim_uuid_16bit_equality(bsim_phy, circuitpython): + """16-bit UUID equality: same value is equal, different values are not.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "eq_same True" in output + assert "eq_diff False" in output + assert "neq_diff True" in output + assert "done" in output + + +BSIM_UUID_16BIT_HASH_CODE = """\ +import _bleio + +a = _bleio.UUID(0x180F) +b = _bleio.UUID(0x180F) + +# Same UUID should hash the same +print("hash_same", hash(a) == hash(b)) + +# Can be used as dict keys +d = {a: "battery"} +print("dict_lookup", d[_bleio.UUID(0x180F)]) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_HASH_CODE}) +def test_bsim_uuid_16bit_hash(bsim_phy, circuitpython): + """16-bit UUID can be hashed and used as dict keys.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "hash_same True" in output + assert "dict_lookup battery" in output + assert "done" in output + + +BSIM_UUID_16BIT_PACK_CODE = """\ +import _bleio + +u16 = _bleio.UUID(0x180F) +buf = bytearray(4) +u16.pack_into(buf) +print("packed", list(buf[:2])) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_PACK_CODE}) +def test_bsim_uuid_16bit_pack_into(bsim_phy, circuitpython): + """pack_into for 16-bit UUID writes 2 bytes in little-endian.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + # 0x180F in little-endian: byte[0]=0x0F, byte[1]=0x18 + assert "packed [15, 24]" in output # 0x0F=15, 0x18=24 + assert "done" in output + + +BSIM_UUID_16BIT_PACK_OFFSET_CODE = """\ +import _bleio + +u16 = _bleio.UUID(0x2A19) +buf = bytearray(6) +u16.pack_into(buf, offset=4) +print("packed", list(buf)) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_PACK_OFFSET_CODE}) +def test_bsim_uuid_16bit_pack_into_offset(bsim_phy, circuitpython): + """pack_into with offset writes at the correct position.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + # 0x2A19 = 10777, little-endian: [0x19, 0x2A] = [25, 42] + assert "packed [0, 0, 0, 0, 25, 42]" in output + assert "done" in output + + +# --- 128-bit UUID string parsing --- + +BSIM_UUID_128BIT_STR_CODE = """\ +import _bleio + +u128 = _bleio.UUID("12345678-1234-5678-1234-56789abcdef0") +print("uuid16", u128.uuid16) +print("size", u128.size) +print("uuid128_len", len(u128.uuid128)) +# Bytes 12-13 are zeroed by shared-bindings (extracted as uuid16) +# First 4 bytes of uuid128 are [f0, de, bc, 9a] in LE +print("bytes_0_3", list(u128.uuid128[:4])) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_128BIT_STR_CODE}) +def test_bsim_uuid_128bit_string(bsim_phy, circuitpython): + """Construct a 128-bit UUID from a hex string.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 128" in output + # uuid16 extracted from bytes 12-13: 0x5678 = 22136 + assert "uuid16 22136" in output + assert "uuid128_len 16" in output + # Bytes 12-13 are restored from uuid16 by common_hal_bleio_uuid_construct + # First 4 bytes of uuid128 are [f0, de, bc, 9a] in LE + assert "bytes_0_3 [240, 222, 188, 154]" in output + assert "done" in output + + +# --- 128-bit UUID bytes construction --- + +BSIM_UUID_128BIT_BYTES_CODE = """\ +import _bleio + +raw = bytes([0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, + 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56]) +u128 = _bleio.UUID(raw) +print("size", u128.size) +# uuid16 extracted from raw[12:14] = [0x34, 0x12] → 0x1234 = 4660 +print("uuid16", u128.uuid16) +print("uuid128_len", len(u128.uuid128)) +# Bytes 12-13 are restored from uuid16 by common_hal_bleio_uuid_construct +print("bytes_12_13", list(u128.uuid128[12:14])) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_128BIT_BYTES_CODE}) +def test_bsim_uuid_128bit_bytes(bsim_phy, circuitpython): + """Construct a 128-bit UUID from a 16-byte buffer.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 128" in output + assert "uuid16 4660" in output + assert "uuid128_len 16" in output + # Bytes 12-13 restored from uuid16: 0x1234 → [0x34, 0x12] = [52, 18] + assert "bytes_12_13 [52, 18]" in output + assert "done" in output + + +# --- 128-bit UUID equality --- + +BSIM_UUID_128BIT_EQ_CODE = """\ +import _bleio + +a = _bleio.UUID("12345678-1234-5678-1234-56789abcdef0") +b = _bleio.UUID("12345678-1234-5678-1234-56789abcdef0") +c = _bleio.UUID("00000000-0000-1000-8000-00805f9b34fb") + +print("eq_same", a == b) +print("eq_diff", a == c) +print("neq_diff", a != c) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_128BIT_EQ_CODE}) +def test_bsim_uuid_128bit_equality(bsim_phy, circuitpython): + """128-bit UUID equality: same bytes equal, different not.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "eq_same True" in output + assert "eq_diff False" in output + assert "neq_diff True" in output + assert "done" in output + + +# --- 16-bit vs 128-bit UUID equality (should not be equal even if same value) --- + +BSIM_UUID_CROSS_SIZE_EQ_CODE = """\ +import _bleio + +# 0x180F as 16-bit +u16 = _bleio.UUID(0x180F) + +# 0x180F expanded to 128-bit base UUID +# Bluetooth base: 00000000-0000-1000-8000-00805F9B34FB +# With 0x180F: 0000180F-0000-1000-8000-00805F9B34FB +u128 = _bleio.UUID("0000180f-0000-1000-8000-00805f9b34fb") + +print("size_16", u16.size) +print("size_128", u128.size) +# Per spec, 16-bit and 128-bit are NOT equal even if values match +print("cross_eq", u16 == u128) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_CROSS_SIZE_EQ_CODE}) +def test_bsim_uuid_cross_size_equality(bsim_phy, circuitpython): + """16-bit and 128-bit UUIDs are not equal even with same value.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size_16 16" in output + assert "size_128 128" in output + assert "cross_eq False" in output + assert "done" in output + + +# --- Invalid UUID string --- + +BSIM_UUID_INVALID_STR_CODE = """\ +import _bleio + +try: + u = _bleio.UUID("not-a-uuid") + print("should not reach") +except ValueError as e: + print("value_error", "not" in str(e) or "UUID" in str(e)) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_INVALID_STR_CODE}) +def test_bsim_uuid_invalid_string(bsim_phy, circuitpython): + """Invalid UUID string raises ValueError.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "value_error True" in output + assert "done" in output + + +# --- UUID 128-bit: uuid128 property works, uuid16 returns 16-bit part --- + +BSIM_UUID_128BIT_PROPS_CODE = """\ +import _bleio + +u128 = _bleio.UUID("12345678-1234-5678-1234-56789abcdef0") +print("size", u128.size) +# uuid128 returns 16 bytes (bytes 12-13 are restored from uuid16) +b = u128.uuid128 +print("uuid128_len", len(b)) +# uuid16 is the 16-bit part from bytes 12-13, extracted and then restored +print("uuid16", u128.uuid16) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_128BIT_PROPS_CODE}) +def test_bsim_uuid_128bit_properties(bsim_phy, circuitpython): + """128-bit UUID exposes uuid128 bytes and uuid16 from bytes 12-13.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 128" in output + assert "uuid128_len 16" in output + assert "uuid16 22136" in output + assert "done" in output + + +# --- 16-bit uuid128 raises AttributeError --- + +BSIM_UUID_16BIT_NO_UUID128_CODE = """\ +import _bleio + +u16 = _bleio.UUID(0x180F) +try: + _ = u16.uuid128 + print("should not reach") +except AttributeError: + print("attr_error ok") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_NO_UUID128_CODE}) +def test_bsim_uuid_16bit_no_uuid128(bsim_phy, circuitpython): + """Accessing uuid128 on a 16-bit UUID raises AttributeError.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "attr_error ok" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_advertising.py new file mode 100644 index 00000000000..a6e9bc6e0dd --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_advertising.py @@ -0,0 +1,112 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Advertising test for the supervisor BLE workflow (bsim). + +The supervisor's built-in BLE workflow (file-transfer + serial services and +advertising) starts automatically at boot, independent of user code. One +CircuitPython device runs an idle code.py so its workflow advertises; a second +CircuitPython device scans with the adafruit_ble library and verifies the +workflow's advertisement carries the File Transfer service UUID (0xFEBB) and +the CIRCUITPY device name. + +The second device disables its own workflow via settings.toml so only the +first device advertises. +""" + +import logging +import re + +import pytest + +from .conftest import get_library_files + +logger = logging.getLogger(__name__) + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") + +# Device 1: idle code.py. The supervisor workflow advertises during the sleep. +WORKFLOW_IDLE_CODE = """\ +import time +time.sleep(15) +""" + +# Device 2: scan for the workflow advertisement. The workflow puts the +# File Transfer service UUID (0xFEBB) in the primary advertisement and the full +# "CIRCUITPYxxxx" name in the scan response, so those arrive as separate +# Advertisement objects (service list vs. scan response). +SCANNER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising import Advertisement +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.uuid import StandardUUID + +ble = BLERadio() +print("scan start") +found_ft = False +found_name = False +ft_rssi = None +for adv in ble.start_scan(ProvideServicesAdvertisement, Advertisement, timeout=15, active=True): + if isinstance(adv, ProvideServicesAdvertisement) and StandardUUID(0xFEBB) in adv.services: + found_ft = True + ft_rssi = adv.rssi + print("ft_uuid febb") + name = adv.complete_name or adv.short_name or "" + if name: + found_name = True + print("cp_name", name) + if found_ft and found_name: + print("workflow found") + print("ft_rssi", ft_rssi) + break +ble.stop_scan() +print("scan done", found_ft, found_name, ft_rssi) +""" + +# Disable the workflow on the scanner so it doesn't advertise alongside device 1. +SCANNER_SETTINGS = "CIRCUITPY_BLE_WORKFLOW = false\n" + + +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive({"code.py": WORKFLOW_IDLE_CODE}) +@pytest.mark.circuitpy_drive( + { + "code.py": SCANNER_CODE, + "settings.toml": SCANNER_SETTINGS, + **_ADAFRUIT_BLE, + } +) +def test_bsim_workflow_advertises(bsim_phy, circuitpython1, circuitpython2): + """The supervisor BLE workflow advertises 0xFEBB and the CIRCUITPY name.""" + workflow = circuitpython1 + scanner = circuitpython2 + + scanner.wait_until_done() + + scanner_output = scanner.serial.all_output + assert "ft_uuid febb" in scanner_output, ( + f"File Transfer service UUID 0xFEBB not observed: {scanner_output}" + ) + # The device name currently advertises as the controller default ("Zephyr"); + # the CIRCUITPY name is configured separately, at which point this will + # observe the full "CIRCUITPY..." name. Either way a name must be present. + assert "cp_name" in scanner_output, f"device name not observed: {scanner_output}" + assert "workflow found" in scanner_output, ( + f"workflow advertisement not fully observed: {scanner_output}" + ) + + # The workflow advertises its public advert at reduced TX power (-20 dBm), + # so with the 40 dB channel attenuation the RSSI is ~ -59, well below the + # 0 dBm baseline of -39 seen for user advertisements. + rssi_match = re.search(r"ft_rssi (-?\d+)", scanner_output) + assert rssi_match, f"ft_rssi not observed: {scanner_output}" + ft_rssi = int(rssi_match.group(1)) + logger.info("workflow ft_rssi: %d", ft_rssi) + assert ft_rssi < -39, f"Expected reduced-TX-power RSSI (< -39), got {ft_rssi}" + + # The workflow device should not have entered safe mode. + workflow_output = workflow.serial.all_output + assert "safe mode" not in workflow_output.lower(), ( + f"workflow device entered safe mode: {workflow_output}" + ) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_file_transfer.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_file_transfer.py new file mode 100644 index 00000000000..a7c383febe1 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_file_transfer.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""File Transfer service test for the supervisor BLE workflow (bsim). + +A second CircuitPython device connects to the supervisor's BLE workflow +(advertised with the File Transfer service UUID 0xFEBB), pairs, and uses the +Adafruit_CircuitPython_BLE_File_Transfer library to list the workflow device's +root directory. +""" + +import pytest + +from .conftest import get_library_files + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") +_ADAFRUIT_BLE_FILE_TRANSFER = get_library_files("adafruit_ble_file_transfer") + +# Device 1: idle code.py; its workflow exposes the File Transfer service. +WORKFLOW_IDLE_CODE = """\ +import time +time.sleep(25) +""" + +# Device 2: connect, pair, and listdir("/") over the File Transfer service. +CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.uuid import StandardUUID +from adafruit_ble_file_transfer import FileTransferService, FileTransferClient + +ble = BLERadio() + +# Wait for the workflow device's file transfer server to finish starting up +# before scanning. +time.sleep(5) +print("scan start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=15, active=True): + if StandardUUID(0xFEBB) in adv.services: + target = adv + print("found workflow") + break +ble.stop_scan() +if target is None: + print("no workflow") + raise SystemExit(1) + +connection = ble.connect(target, timeout=10) +print("connected", connection.connected) +connection.pair() +print("paired", connection.paired) + +service = connection[FileTransferService] +print("ft version", service.version) +client = FileTransferClient(service) + +entries = client.listdir("/") +names = [e[0] for e in entries] +print("ft names", names) +if "code.py" in names: + print("ft code.py listed") +print("ft done") +connection.disconnect() +""" + +CLIENT_SETTINGS = "CIRCUITPY_BLE_WORKFLOW = false\n" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": WORKFLOW_IDLE_CODE}) +@pytest.mark.circuitpy_drive( + { + "code.py": CLIENT_CODE, + "settings.toml": CLIENT_SETTINGS, + **_ADAFRUIT_BLE_FILE_TRANSFER, + **_ADAFRUIT_BLE, + } +) +def test_bsim_workflow_file_transfer(board, bsim_phy, circuitpython1, circuitpython2): + """The supervisor BLE workflow's File Transfer service can list files.""" + workflow = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + + client_output = client.serial.all_output + assert "found workflow" in client_output, f"client never found the workflow: {client_output}" + assert "paired True" in client_output, f"pairing did not succeed: {client_output}" + assert "ft version 4" in client_output, ( + f"File Transfer version characteristic is not 4: {client_output}" + ) + assert "ft code.py listed" in client_output, ( + f"listdir did not include code.py: {client_output}" + ) + assert "ft done" in client_output, f"file transfer did not complete: {client_output}" + + workflow_output = workflow.serial.all_output + assert "safe mode" not in workflow_output.lower(), ( + f"workflow device entered safe mode: {workflow_output}" + ) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_nus.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_nus.py new file mode 100644 index 00000000000..ebc0bbcc69c --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_nus.py @@ -0,0 +1,146 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Serial (Nordic-UART-style) service test for the supervisor BLE workflow +(bsim). + +The supervisor's BLE workflow exposes a CircuitPython serial service whose RX +characteristic accepts console stdin (write, encrypted) and whose TX +characteristic emits console stdout via notifications (encrypted). One +CircuitPython device runs code.py that reads a line with `input()` and echoes +it back with `print()`; a second CircuitPython device connects, pairs, +subscribes to TX, writes a line to RX, and verifies the echo comes back over TX. +""" + +import pytest + +from .conftest import get_library_files + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") + +# Device 1: read a line from console stdin (BLE RX) and echo it to console +# stdout (mirrored to BLE TX). `input()` blocks until the central writes, so the +# device stays alive for the exchange. +WORKFLOW_CODE = """\ +import time +print("nus ready") +try: + line = input() +except EOFError: + line = "" +print("nus_echo:" + line) +# Keep the VM alive briefly so the BLE TX notification carrying the echo is +# actually transmitted over the link before the device exits. Without this the +# notification is queued but never sent because the process shuts down right +# after code.py finishes. +time.sleep(3) +""" + +# Device 2: connect, pair, discover the CircuitPython serial service, subscribe +# to TX, write a line to RX, and read the echo back over TX. +CLIENT_CODE = """\ +import time +import _bleio +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.uuid import StandardUUID + +ble = BLERadio() + +# Wait for the workflow device's serial service to finish starting up +# before scanning. Connecting too soon after the workflow's BLE init races +# with a Zephyr connection-parameter update and the link drops shortly +# after pairing. +time.sleep(5) +print("scan start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=15, active=True): + if StandardUUID(0xFEBB) in adv.services: + target = adv + print("found workflow") + break +ble.stop_scan() +if target is None: + print("no workflow") + raise SystemExit(1) + +connection = ble.connect(target, timeout=10) +print("connected", connection.connected) +connection.pair() +print("paired", connection.paired) + +# CircuitPython serial service UUID (128-bit, "nhtyPtiucriC" base + 0x0001). +serial_uuid = _bleio.UUID(b"nhtyPtiucriC\\x01\\x00\\xaf\\xad") +services = connection._bleio_connection.discover_remote_services([serial_uuid]) +svc = services[0] +print("serial service", svc.uuid.uuid16) + +rx_char = None +tx_char = None +for ch in svc.characteristics: + if ch.uuid.uuid16 == 0x0002: + rx_char = ch + elif ch.uuid.uuid16 == 0x0003: + tx_char = ch +print("rx", rx_char is not None, "tx", tx_char is not None) + +# Subscribe to TX notifications (client-side PacketBuffer writes the CCCD). +tx_pb = _bleio.PacketBuffer(tx_char, buffer_size=4, max_packet_size=128) + +# Write a line to RX (console stdin). RX has WRITE_NO_RESPONSE, so `.value =` +# does a GATT write without response. +rx_char.value = b"ZZZ\\r" +print("rx written") + +buf = bytearray(128) +got = b"" +deadline = time.monotonic() + 10 +while time.monotonic() < deadline: + n = tx_pb.readinto(buf) + if n: + got += bytes(buf[:n]) + if b"nus_echo:ZZZ" in got: + print("nus_received nus_echo:ZZZ") + break +print("nus done", b"nus_echo:ZZZ" in got) +connection.disconnect() +""" + +CLIENT_SETTINGS = "CIRCUITPY_BLE_WORKFLOW = false\n" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": WORKFLOW_CODE}) +@pytest.mark.circuitpy_drive( + { + "code.py": CLIENT_CODE, + "settings.toml": CLIENT_SETTINGS, + **_ADAFRUIT_BLE, + } +) +def test_bsim_workflow_nus(board, bsim_phy, circuitpython1, circuitpython2): + """The supervisor BLE workflow's serial service echoes console I/O over BLE.""" + workflow = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + + client_output = client.serial.all_output + assert "found workflow" in client_output, f"client never found the workflow: {client_output}" + assert "paired True" in client_output, f"pairing did not succeed: {client_output}" + assert "serial service 1" in client_output, ( + f"CircuitPython serial service not discovered: {client_output}" + ) + assert "rx True tx True" in client_output, ( + f"RX/TX characteristics not discovered: {client_output}" + ) + assert "rx written" in client_output, f"RX write failed: {client_output}" + assert "nus_received nus_echo:ZZZ" in client_output, ( + f"echo 'nus_echo:ZZZ' never received over TX: {client_output}" + ) + assert "nus done True" in client_output, f"echo not confirmed: {client_output}" + + workflow_output = workflow.serial.all_output + assert "safe mode" not in workflow_output.lower(), ( + f"workflow device entered safe mode: {workflow_output}" + ) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_reload.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_reload.py new file mode 100644 index 00000000000..cc56b1108e3 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_reload.py @@ -0,0 +1,190 @@ +# SPDX-FileCopyrightText: 2026 Dan Halbert for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""The supervisor BLE workflow connection survives a VM reload (bsim). + +A second CircuitPython device connects to the workflow, pairs, and lists the +root directory. The test then interrupts the workflow device's code.py and +reloads it with Ctrl-D, the same path as typing at the "Press any key" prompt +or saving a file from the web editor. The connection must stay up and file +transfer must still work afterwards. + +In the variant where code.py created a `_bleio.Service`, that service must be +gone from the GATT table after the reload, while the workflow connection still +survives: Zephyr can unregister services individually, so no stack restart is +needed. +""" + +import pytest + +from .conftest import get_library_files + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") +_ADAFRUIT_BLE_FILE_TRANSFER = get_library_files("adafruit_ble_file_transfer") + +# Device 1, plain: idle code.py until the test interrupts it. +WORKFLOW_IDLE_CODE = """\ +import supervisor +import time +print("run", supervisor.runtime.run_reason) +print("workflow ready") +# Idle in short sleeps: on zephyr-cp a Ctrl-C from the UART console is only +# noticed when the current time.sleep() ends, so keep each one brief. +while True: + time.sleep(0.5) +""" + +# Device 1, with a user service: create a Battery Service only on the first +# run, so that after the reload it must have been removed by the supervisor, +# not recreated by code.py. +WORKFLOW_SERVICE_CODE = """\ +import supervisor +import time +import _bleio +print("run", supervisor.runtime.run_reason) +if supervisor.runtime.run_reason == supervisor.RunReason.STARTUP: + service = _bleio.Service(_bleio.UUID(0x180F)) + _bleio.Characteristic.add_to_service( + service, _bleio.UUID(0x2A19), + properties=_bleio.Characteristic.READ, + read_perm=_bleio.Attribute.OPEN, + write_perm=_bleio.Attribute.NO_ACCESS, + max_length=1, fixed_length=True, initial_value=b"\\x64", + ) + print("user service created") +print("workflow ready") +# Idle in short sleeps: on zephyr-cp a Ctrl-C from the UART console is only +# noticed when the current time.sleep() ends, so keep each one brief. +while True: + time.sleep(0.5) +""" + +# Device 2: connect, pair, list files, report whether the Battery Service is +# present, then wait through the reload and do it all again on the same +# connection. +CLIENT_CODE = """\ +import time +import _bleio +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.uuid import StandardUUID +from adafruit_ble_file_transfer import FileTransferService, FileTransferClient + +BATTERY = _bleio.UUID(0x180F) + +ble = BLERadio() + +# Wait for the workflow device's file transfer server to finish starting up +# before scanning. +time.sleep(5) +print("scan start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=15, active=True): + if StandardUUID(0xFEBB) in adv.services: + target = adv + print("found workflow") + break +ble.stop_scan() +if target is None: + print("no workflow") + raise SystemExit(1) + +connection = ble.connect(target, timeout=10) +print("connected", connection.connected) +connection.pair() +print("paired", connection.paired) + +def battery_present(): + services = connection._bleio_connection.discover_remote_services() + return any(s.uuid == BATTERY for s in services) + +def list_root(tag): + service = connection[FileTransferService] + client = FileTransferClient(service) + names = [e[0] for e in client.listdir("/")] + print("ft names", tag, names) + print("ft code.py listed", tag, "code.py" in names) + +print("battery before", battery_present()) +list_root("before") +print("client ready for reload") + +# The test reloads the workflow device now. Give it time to come back. +time.sleep(20) +print("still connected", connection.connected) +list_root("after") +print("battery after", battery_present()) +print("client done") +connection.disconnect() +""" + +CLIENT_SETTINGS = "CIRCUITPY_BLE_WORKFLOW = false\n" + +CLIENT_DRIVE = { + "code.py": CLIENT_CODE, + "settings.toml": CLIENT_SETTINGS, + **_ADAFRUIT_BLE_FILE_TRANSFER, + **_ADAFRUIT_BLE, +} + + +def _reload_workflow_and_check(workflow, client): + client.serial.wait_for("client ready for reload", timeout=90) + + # Interrupt code.py, then reload from the "Press any key" prompt. Before the + # fix, the first byte at that prompt restarted the BLE stack and dropped the + # workflow connection. + workflow.serial.write("\x03") + workflow.serial.wait_for("KeyboardInterrupt", timeout=30) + workflow.serial.write("\x04") + workflow.serial.wait_for("RunReason.REPL_RELOAD", timeout=30) + + client.serial.wait_for("client done", timeout=90) + + client_output = client.serial.all_output + assert "paired True" in client_output, f"pairing did not succeed: {client_output}" + assert "ft code.py listed before True" in client_output, ( + f"listdir before reload did not include code.py: {client_output}" + ) + assert "still connected True" in client_output, ( + f"workflow connection did not survive the reload: {client_output}" + ) + assert "ft code.py listed after True" in client_output, ( + f"listdir after reload did not include code.py: {client_output}" + ) + + workflow_output = workflow.serial.all_output + assert "safe mode" not in workflow_output.lower(), ( + f"workflow device entered safe mode: {workflow_output}" + ) + return client_output + + +@pytest.mark.port_resets(3) +@pytest.mark.duration(90) +@pytest.mark.circuitpy_drive({"code.py": WORKFLOW_IDLE_CODE}) +@pytest.mark.circuitpy_drive(CLIENT_DRIVE) +def test_bsim_workflow_reload_keeps_connection(board, bsim_phy, circuitpython1, circuitpython2): + """A Ctrl-D reload with no user services leaves the workflow connection up.""" + client_output = _reload_workflow_and_check(circuitpython1, circuitpython2) + assert "battery before False" in client_output + assert "battery after False" in client_output + + +@pytest.mark.port_resets(3) +@pytest.mark.duration(90) +@pytest.mark.circuitpy_drive({"code.py": WORKFLOW_SERVICE_CODE}) +@pytest.mark.circuitpy_drive(CLIENT_DRIVE) +def test_bsim_workflow_reload_removes_user_service( + board, bsim_phy, circuitpython1, circuitpython2 +): + """A reload removes a user-created service without dropping the connection.""" + workflow = circuitpython1 + client_output = _reload_workflow_and_check(workflow, circuitpython2) + assert "user service created" in workflow.serial.all_output + assert "battery before True" in client_output, ( + f"client did not see the user service before the reload: {client_output}" + ) + assert "battery after False" in client_output, ( + f"user service still present after the reload: {client_output}" + ) diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py new file mode 100644 index 00000000000..6a5f9de60d7 --- /dev/null +++ b/ports/zephyr-cp/tests/conftest.py @@ -0,0 +1,426 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Pytest fixtures for CircuitPython native_sim testing.""" + +import logging +import os +import subprocess +from pathlib import Path + +import pytest +import serial + +from .perfetto_input_trace import write_input_trace + +from perfetto.trace_processor import TraceProcessor + +from . import NativeSimProcess + +logger = logging.getLogger(__name__) + + +def pytest_addoption(parser): + parser.addoption( + "--update-goldens", + action="store_true", + default=False, + help="Overwrite golden images with captured output instead of comparing.", + ) + + +def pytest_configure(config): + config.addinivalue_line( + "markers", "circuitpy_drive(files): run CircuitPython with files in the flash image" + ) + config.addinivalue_line( + "markers", "disable_i2c_devices(*names): disable native_sim I2C emulator devices" + ) + config.addinivalue_line( + "markers", "circuitpython_board(board_id): which board id to use in the test" + ) + config.addinivalue_line( + "markers", + "zephyr_sample(sample, board='nrf52_bsim', device_id=1): build and run a Zephyr sample for bsim tests", + ) + config.addinivalue_line( + "markers", + "duration(seconds): native_sim timeout and bsim PHY simulation duration", + ) + config.addinivalue_line( + "markers", + "port_resets(count): stop native_sim after count port_reset()s (default: 2)", + ) + config.addinivalue_line( + "markers", + "input_trace(trace): inject input signal trace data into native_sim", + ) + config.addinivalue_line( + "markers", + "native_sim_rt: run native_sim in realtime mode (-rt instead of -no-rt)", + ) + config.addinivalue_line( + "markers", + "display(capture_times_ns=None): run test with SDL display; " + "capture_times_ns is a list of nanosecond timestamps for trace-triggered captures", + ) + config.addinivalue_line( + "markers", + "display_pixel_format(format): override the display pixel format " + "(e.g. 'RGB_565', 'ARGB_8888')", + ) + config.addinivalue_line( + "markers", + "display_mono_vtiled(value): override the mono vtiled screen_info flag (True or False)", + ) + config.addinivalue_line( + "markers", + "flash_config(erase_block_size=N, total_size=N): override flash simulator parameters", + ) + + +ZEPHYR_CP = Path(__file__).parent.parent +BUILD_DIR = ZEPHYR_CP / "build-native_native_sim" +BINARY = BUILD_DIR / "zephyr-cp/zephyr/zephyr.exe" + + +def _iter_uart_tx_slices(trace_file: Path) -> list[tuple[int, int, str, str]]: + """Return UART TX slices as (timestamp_ns, duration_ns, text, device_name).""" + tp = TraceProcessor(file_path=str(trace_file)) + result = tp.query( + """ + SELECT s.ts, s.dur, s.name, dev.name AS device_name + FROM slice s + JOIN track tx ON s.track_id = tx.id + JOIN track dev ON tx.parent_id = dev.id + JOIN track uart ON dev.parent_id = uart.id + WHERE tx.name = "TX" AND uart.name = "UART" + ORDER BY s.ts + """ + ) + return [ + (int(row.ts), int(row.dur or 0), row.name or "", row.device_name or "UART") + for row in result + ] + + +def log_uart_trace_output(trace_file: Path) -> None: + """Log UART TX output from Perfetto trace with timestamps for line starts.""" + if not logger.isEnabledFor(logging.INFO): + return + slices = _iter_uart_tx_slices(trace_file) + if not slices: + return + + buffers: dict[str, list[str]] = {} + line_start_ts: dict[str, int | None] = {} + + for ts, dur, text, device in slices: + if device not in buffers: + buffers[device] = [] + line_start_ts[device] = None + + if not text: + continue + + char_step = dur / max(len(text), 1) if dur > 0 else 0.0 + for idx, ch in enumerate(text): + if line_start_ts[device] is None: + line_start_ts[device] = int(ts + idx * char_step) + buffers[device].append(ch) + if ch == "\n": + line_text = "".join(buffers[device]).rstrip("\n") + logger.info( + "UART trace %s @%d ns: %s", + device, + line_start_ts[device], + repr(line_text), + ) + buffers[device] = [] + line_start_ts[device] = None + + for device, buf in buffers.items(): + if buf: + logger.info( + "UART trace %s @%d ns (partial): %s", + device, + line_start_ts[device] or 0, + repr("".join(buf)), + ) + + +# Native_sim boards each test runs against: the non-asan default and the +# asan-enabled build, so memory errors fail tests. +NATIVE_BOARDS = ["native_native_sim", "native_native_sim_asan"] + + +@pytest.fixture(params=NATIVE_BOARDS) +def board(request): + """Parametrized over both native_sim builds (non-asan and asan). + + The bsim conftest overrides this fixture with its own bsim boards. + """ + board = request.node.get_closest_marker("circuitpython_board") + if board is not None: + return board.args[0] + return request.param + + +@pytest.fixture +def native_sim_binary(request, board): + """Return path to native_sim binary, skip if not built.""" + build_dir = ZEPHYR_CP / f"build-{board}" + binary = build_dir / "zephyr-cp/zephyr/zephyr.exe" + + if not binary.exists(): + pytest.skip(f"binary not built: {binary}") + return binary + + +@pytest.fixture +def native_sim_env() -> dict[str, str]: + env = {} + # Always pick the video driver explicitly. Always using dummy works in a + # bubblewrap sandbox and avoids GL teardown issues on GitHub Actions. + if not os.environ.get("SDL_VIDEODRIVER"): + env["SDL_VIDEODRIVER"] = "dummy" + return env + + +PIXEL_FORMAT_BITMASK = { + "RGB_888": 1 << 0, + "MONO01": 1 << 1, + "MONO10": 1 << 2, + "ARGB_8888": 1 << 3, + "RGB_565": 1 << 4, + "BGR_565": 1 << 5, + "L_8": 1 << 6, + "AL_88": 1 << 7, +} + + +@pytest.fixture +def pixel_format(request) -> str: + """Indirect-parametrize fixture: adds display_pixel_format marker.""" + fmt = request.param + request.node.add_marker(pytest.mark.display_pixel_format(fmt)) + return fmt + + +@pytest.fixture +def sim_id(request) -> str: + return request.node.nodeid.replace("/", "_") + + +@pytest.fixture +def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp_path): + """Run CircuitPython with given code string and return PTY output.""" + + instance_count = 1 + if "circuitpython1" in request.fixturenames and "circuitpython2" in request.fixturenames: + instance_count = 2 + + drives = list(request.node.iter_markers_with_node("circuitpy_drive")) + if len(drives) != instance_count: + raise RuntimeError(f"not enough drives for {instance_count} instances") + + input_trace_markers = list(request.node.iter_markers_with_node("input_trace")) + if len(input_trace_markers) > 1: + raise RuntimeError("expected at most one input_trace marker") + + input_trace = None + if input_trace_markers and len(input_trace_markers[0][1].args) == 1: + input_trace = input_trace_markers[0][1].args[0] + + input_trace_file = None + if input_trace is not None: + input_trace_file = tmp_path / "input.perfetto" + write_input_trace(input_trace_file, input_trace) + + marker = request.node.get_closest_marker("duration") + if marker is None: + timeout = 10 + else: + timeout = marker.args[0] + + resets_marker = request.node.get_closest_marker("port_resets") + # Main does one reset on start up and then one on each VM clean up. It also + # does one after printing the safe mode message. + if resets_marker is None: + port_resets = 2 + else: + port_resets = int(resets_marker.args[0]) + + display_marker = request.node.get_closest_marker("display") + if display_marker is None: + display_marker = request.node.get_closest_marker("display_capture") + + capture_times_ns = None + if display_marker is not None: + capture_times_ns = display_marker.kwargs.get("capture_times_ns", None) + + pixel_format_marker = request.node.get_closest_marker("display_pixel_format") + pixel_format = None + if pixel_format_marker is not None and pixel_format_marker.args: + pixel_format = pixel_format_marker.args[0] + + mono_vtiled_marker = request.node.get_closest_marker("display_mono_vtiled") + mono_vtiled = None + if mono_vtiled_marker is not None and mono_vtiled_marker.args: + mono_vtiled = mono_vtiled_marker.args[0] + + # If capture_times_ns is set, merge display_capture track into input trace. + if capture_times_ns is not None: + if input_trace is None: + input_trace = {} + else: + input_trace = dict(input_trace) + input_trace["display_capture"] = list(capture_times_ns) + if input_trace_file is None: + input_trace_file = tmp_path / "input.perfetto" + write_input_trace(input_trace_file, input_trace) + + use_realtime = request.node.get_closest_marker("native_sim_rt") is not None + + flash_config_marker = request.node.get_closest_marker("flash_config") + flash_total_size = 2 * 1024 * 1024 # default 2MB + flash_erase_block_size = None + flash_write_block_size = None + if flash_config_marker: + flash_total_size = flash_config_marker.kwargs.get("total_size", flash_total_size) + flash_erase_block_size = flash_config_marker.kwargs.get("erase_block_size", None) + flash_write_block_size = flash_config_marker.kwargs.get("write_block_size", None) + + procs = [] + for i in range(instance_count): + flash = tmp_path / f"flash-{i}.bin" + flash.write_bytes(b"\xff" * flash_total_size) + files = None + if len(drives[i][1].args) == 1: + files = drives[i][1].args[0] + if files is not None: + subprocess.run(["mformat", "-i", str(flash), "::"], check=True) + tmp_drive = tmp_path / f"drive{i}" + tmp_drive.mkdir(exist_ok=True) + + fat_dirs_created = set() + for name, content in files.items(): + src = tmp_drive / name + src.parent.mkdir(parents=True, exist_ok=True) + if isinstance(content, bytes): + src.write_bytes(content) + else: + src.write_text(content) + # Create parent directories on the FAT image. + fat_dir = Path(name).parent + for fat_part in [*reversed(fat_dir.parents), fat_dir]: + if fat_part == Path("."): + continue + fat_path = "::" + str(fat_part) + if fat_path not in fat_dirs_created: + subprocess.run(["mmd", "-i", str(flash), fat_path], check=True) + fat_dirs_created.add(fat_path) + subprocess.run(["mcopy", "-i", str(flash), str(src), f"::{name}"], check=True) + + trace_file = tmp_path / f"trace-{i}.perfetto" + + if "bsim" in board: + # nRF54 bsim boards use RRAMC (--flash), others use NVMC (--flash_app) + flash_arg = "--flash" if "nrf54" in board else "--flash_app" + cmd = [str(native_sim_binary), f"{flash_arg}={flash}"] + if instance_count > 1: + cmd.append("-disconnect_on_exit=1") + # nRF54 bsim boards: console UART is SERIAL20 (bsim instance 1), others use instance 0 + uart_n = "1" if "nrf54" in board else "0" + cmd.extend( + ( + f"-s={sim_id}", + f"-d={i}", + f"-uart{uart_n}_pty", + f"-uart{uart_n}_pty_wait_for_readers", + "-uart_pty_wait", + # Use the real AES implementation (libCryptov1.so) for the + # link layer instead of BabbleSim's plain-text stand-in. + # The nRF54L HW models route AES through several different + # stand-ins (ECB/CCM copy the data, CRACEN scrambles it), + # which are not consistent with each other, so LE + # encryption only works with real AES. Zephyr's own bsim + # encryption tests pass -RealEncryption=1 for the same + # reason. + "-RealEncryption=1", + f"--port-resets={port_resets}", + ) + ) + else: + cmd = [str(native_sim_binary), f"--flash={flash}"] + realtime_flag = "-rt" if use_realtime else "-no-rt" + cmd.extend( + ( + realtime_flag, + "-display_headless", + "-i2s_earless", + "-wait_uart", + f"--port-resets={port_resets}", + ) + ) + # Capture tests hold their last frame forever; stop the simulator at the + # test's duration in simulated time instead of waiting out the timeout. + if capture_times_ns and not use_realtime: + cmd.append(f"-stop_at={timeout}") + + # Always preserve retained memory (e.g. the safe-mode saved word) in + # in case of reboot. + cmd.append(f"--retained-memory={tmp_path / f'retained-{i}.bin'}") + + if flash_erase_block_size is not None: + cmd.append(f"--flash_erase_block_size={flash_erase_block_size}") + if flash_write_block_size is not None: + cmd.append(f"--flash_write_block_size={flash_write_block_size}") + if flash_config_marker and "total_size" in flash_config_marker.kwargs: + cmd.append(f"--flash_total_size={flash_total_size}") + + if input_trace_file is not None: + cmd.append(f"--input-trace={input_trace_file}") + + marker = request.node.get_closest_marker("disable_i2c_devices") + if marker and len(marker.args) > 0: + for device in marker.args: + cmd.append(f"--disable-i2c={device}") + + if pixel_format is not None: + cmd.append(f"--display_pixel_format={PIXEL_FORMAT_BITMASK[pixel_format]}") + + if mono_vtiled is not None: + cmd.append(f"--display_mono_vtiled={'true' if mono_vtiled else 'false'}") + + env = os.environ.copy() + env.update(native_sim_env) + + capture_png_pattern = None + if capture_times_ns is not None: + if instance_count == 1: + capture_png_pattern = str(tmp_path / "frame_%d.png") + else: + capture_png_pattern = str(tmp_path / f"frame-{i}_%d.png") + cmd.append(f"--display_capture_png={capture_png_pattern}") + + logger.info("Running: %s", " ".join(cmd)) + proc = NativeSimProcess(cmd, timeout, trace_file, env, flash_file=flash) + proc.display_dump = None + proc._capture_png_pattern = capture_png_pattern + proc._capture_count = len(capture_times_ns) if capture_times_ns is not None else 0 + procs.append(proc) + if instance_count == 1: + yield procs[0] + else: + yield procs + for i, proc in enumerate(procs): + if instance_count > 1: + print(f"---------- Instance {i} -----------") + proc.shutdown() + + print("All serial output:") + print(proc.serial.all_output) + print() + print("All debug serial output:") + print(proc.debug_serial.all_output) diff --git a/ports/zephyr-cp/tests/docs/babblesim.md b/ports/zephyr-cp/tests/docs/babblesim.md new file mode 100644 index 00000000000..75d45079b2e --- /dev/null +++ b/ports/zephyr-cp/tests/docs/babblesim.md @@ -0,0 +1,81 @@ +# BabbleSim testing + +This document describes how to build and run CircuitPython tests against the +BabbleSim (bsim) nRF5340 board. + +## Board target + +We use the Zephyr BabbleSim board for the nRF5340 application core: + +- Zephyr board: `nrf5340bsim/nrf5340/cpuapp` +- CircuitPython board alias: `native_nrf5340bsim` + +The tests expect two bsim instances to run in the same simulation, which allows +future BLE/802.15.4 multi-node tests. + +## Prerequisites + +BabbleSim needs to be available to Zephyr. Either: + +- Use the repo-provided `tools/bsim` checkout (if present) +- Or set environment variables: + +``` +export BSIM_COMPONENTS_PATH=/path/to/bsim/components +export BSIM_OUT_PATH=/path/to/bsim +``` + +## Build + +``` +CCACHE_TEMPDIR=/tmp/ccache-tmp make -j BOARD=native_nrf5340bsim +``` + +If you do not use ccache, you can omit `CCACHE_TEMPDIR`. + +## Run the bsim test + +``` +pytest tests/test_bsim_basics.py -v +``` + +## BLE scan + advertising tests + +The BLE tests run multiple bsim instances and build Zephyr samples on-demand: + +- `tests/test_bsim_ble_scan.py` scans for the Zephyr beacon sample +- `tests/test_bsim_ble_advertising.py` advertises from CircuitPython while the + Zephyr observer sample scans + +The fixtures build the Zephyr samples if missing: + +- Beacon: `zephyr/samples/bluetooth/beacon` (board `nrf52_bsim`) +- Observer: `zephyr/samples/bluetooth/observer` (board `nrf52_bsim`) + +Run the tests with: + +``` +pytest tests/test_bsim_ble_scan.py -v +pytest tests/test_bsim_ble_advertising.py -v +``` + +## Pytest markers + +For bsim-specific test tuning: + +- `@pytest.mark.duration(seconds)` controls simulation runtime/timeout. + +Example: + +```py +pytestmark = pytest.mark.duration(30.0) +``` + +## Notes + +- The bsim test spawns two instances that share a sim id. It only checks UART + output for now, but is the base for BLE/Thread multi-node tests. +- The BLE tests rely on the sysbuild HCI IPC net-core image for the nRF5340 + simulator (enabled via `sysbuild.conf`). +- The board uses a custom devicetree overlay to provide the SRAM region and + CircuitPython flash partition expected by the port. diff --git a/ports/zephyr-cp/tests/docs/i2c_emulator_cmdline_control.md b/ports/zephyr-cp/tests/docs/i2c_emulator_cmdline_control.md new file mode 100644 index 00000000000..8ee2925915c --- /dev/null +++ b/ports/zephyr-cp/tests/docs/i2c_emulator_cmdline_control.md @@ -0,0 +1,306 @@ +# Command-Line Control of Emulated I2C Devices in native_sim + +This document describes an approach for enabling/disabling emulated I2C devices +at runtime via command-line options in Zephyr's native_sim environment. + +## Background + +Zephyr's I2C emulation framework (`zephyr,i2c-emul-controller`) provides: + +1. **Bus emulation** - Fake I2C controller that routes transfers to emulated devices +2. **Device emulators** - Software implementations of I2C peripherals (sensors, etc.) +3. **Backend APIs** - Test interfaces for manipulating emulator state + +However, there's no built-in mechanism to enable/disable emulated devices from the +command line. This capability would be useful for: + +- Testing device hot-plug scenarios +- Simulating hardware failures +- Testing error handling paths in CircuitPython + +## Relevant Zephyr APIs + +### I2C Emulator Structure + +From `include/zephyr/drivers/i2c_emul.h`: + +```c +struct i2c_emul { + sys_snode_t node; + const struct emul *target; + const struct i2c_emul_api *api; + struct i2c_emul_api *mock_api; // If non-NULL, takes precedence + uint16_t addr; +}; + +struct i2c_emul_api { + i2c_emul_transfer_t transfer; +}; +``` + +Key insight: The `mock_api` field allows overriding the normal transfer function. +If `mock_api->transfer()` returns `-ENOSYS`, it falls back to the real API. + +### Command-Line Registration + +From `boards/native/native_sim/cmdline.h`: + +```c +void native_add_command_line_opts(struct args_struct_t *args); +``` + +### Emulator Lookup + +From `include/zephyr/drivers/emul.h`: + +```c +const struct emul *emul_get_binding(const char *name); +``` + +## Implementation Approach + +### 1. Create a Disabled Device Registry + +Track which devices are "disabled" (should NACK all transactions): + +```c +// i2c_emul_cmdline.c + +#include +#include +#include +#include "nsi_cmdline.h" + +#define MAX_DISABLED_DEVICES 16 + +static struct { + const char *name; + const struct emul *emul; + struct i2c_emul_api mock_api; + struct i2c_emul_api *original_mock_api; + bool disabled; +} disabled_devices[MAX_DISABLED_DEVICES]; + +static int num_disabled_devices = 0; +``` + +### 2. Mock Transfer Function + +Return `-EIO` (simulates NACK) when device is disabled: + +```c +static int disabled_device_transfer(const struct emul *target, + struct i2c_msg *msgs, + int num_msgs, + int addr) +{ + // Find this device in our registry + for (int i = 0; i < num_disabled_devices; i++) { + if (disabled_devices[i].emul == target) { + if (disabled_devices[i].disabled) { + // Device is disabled - simulate NACK + return -EIO; + } + break; + } + } + // Fall back to normal emulator behavior + return -ENOSYS; +} +``` + +### 3. Enable/Disable Functions + +```c +int i2c_emul_cmdline_disable_device(const char *name) +{ + const struct emul *emul = emul_get_binding(name); + if (!emul || emul->bus_type != EMUL_BUS_TYPE_I2C) { + return -ENODEV; + } + + // Find or create registry entry + int idx = -1; + for (int i = 0; i < num_disabled_devices; i++) { + if (disabled_devices[i].emul == emul) { + idx = i; + break; + } + } + + if (idx < 0) { + if (num_disabled_devices >= MAX_DISABLED_DEVICES) { + return -ENOMEM; + } + idx = num_disabled_devices++; + disabled_devices[idx].name = name; + disabled_devices[idx].emul = emul; + disabled_devices[idx].mock_api.transfer = disabled_device_transfer; + + // Save and replace mock_api + disabled_devices[idx].original_mock_api = emul->bus.i2c->mock_api; + emul->bus.i2c->mock_api = &disabled_devices[idx].mock_api; + } + + disabled_devices[idx].disabled = true; + return 0; +} + +int i2c_emul_cmdline_enable_device(const char *name) +{ + for (int i = 0; i < num_disabled_devices; i++) { + if (strcmp(disabled_devices[i].name, name) == 0) { + disabled_devices[i].disabled = false; + return 0; + } + } + return -ENODEV; +} +``` + +### 4. Command-Line Option Registration + +```c +static char *disabled_device_args[MAX_DISABLED_DEVICES]; +static int num_disabled_device_args = 0; + +static void cmd_disable_i2c_device(char *argv, int offset) +{ + ARG_UNUSED(offset); + if (num_disabled_device_args < MAX_DISABLED_DEVICES) { + disabled_device_args[num_disabled_device_args++] = argv; + } +} + +static struct args_struct_t i2c_emul_args[] = { + { + .option = "disable-i2c", + .name = "device_name", + .type = 's', + .call_when_found = cmd_disable_i2c_device, + .descript = "Disable an emulated I2C device (can be repeated)" + }, + ARG_TABLE_ENDMARKER +}; + +static void register_cmdline_opts(void) +{ + native_add_command_line_opts(i2c_emul_args); +} + +// Hook into native_sim initialization +NATIVE_TASK(register_cmdline_opts, PRE_BOOT_1, 0); + +static void apply_disabled_devices(void) +{ + for (int i = 0; i < num_disabled_device_args; i++) { + int rc = i2c_emul_cmdline_disable_device(disabled_device_args[i]); + if (rc != 0) { + printk("Warning: Failed to disable I2C device '%s': %d\n", + disabled_device_args[i], rc); + } + } +} + +// Apply after emulators are initialized +NATIVE_TASK(apply_disabled_devices, PRE_BOOT_3, 0); +``` + +### 5. Usage + +After building with this code: + +```bash +# Disable a sensor at startup +./build/zephyr/zephyr.exe --disable-i2c=bmi160@68 + +# Disable multiple devices +./build/zephyr/zephyr.exe --disable-i2c=bmi160@68 --disable-i2c=sht4x@44 +``` + +## Runtime Control Extension + +For runtime enable/disable (not just at startup), you could: + +### Option A: Use a Named Pipe / FIFO + +```c +// Create a FIFO that accepts commands +// "disable bmi160@68" or "enable bmi160@68" +static void *cmdline_control_thread(void *arg) +{ + int fd = open("/tmp/i2c_emul_control", O_RDONLY); + char buf[256]; + while (read(fd, buf, sizeof(buf)) > 0) { + if (strncmp(buf, "disable ", 8) == 0) { + i2c_emul_cmdline_disable_device(buf + 8); + } else if (strncmp(buf, "enable ", 7) == 0) { + i2c_emul_cmdline_enable_device(buf + 7); + } + } + return NULL; +} +``` + +### Option B: Signal Handler + +Use `SIGUSR1`/`SIGUSR2` with a config file that specifies which device to toggle. + +### Option C: Shared Memory + +Map a shared memory region that external tools can write to for device state. + +## Integration with CircuitPython Tests + +For pytest-based tests, you could: + +```python +import subprocess +import os + +class NativeSimProcess: + def __init__(self, exe_path): + self.exe_path = exe_path + self.control_fifo = "/tmp/i2c_emul_control" + + def start(self, disabled_devices=None): + args = [self.exe_path] + if disabled_devices: + for dev in disabled_devices: + args.extend(["--disable-i2c", dev]) + self.proc = subprocess.Popen(args, ...) + + def disable_device(self, name): + """Runtime disable via FIFO""" + with open(self.control_fifo, 'w') as f: + f.write(f"disable {name}\n") + + def enable_device(self, name): + """Runtime enable via FIFO""" + with open(self.control_fifo, 'w') as f: + f.write(f"enable {name}\n") +``` + +## Alternative: Device Tree Approach + +For compile-time configuration, use device tree overlays: + +```dts +// boards/native_sim_no_bmi160.overlay +&bmi160 { + status = "disabled"; +}; +``` + +Build separate variants: +```bash +west build -b native_sim -- -DDTC_OVERLAY_FILE=boards/native_sim_no_bmi160.overlay +``` + +## References + +- Zephyr I2C Emulation: `zephyr/drivers/i2c/i2c_emul.c` +- Emulator Framework: `zephyr/doc/hardware/emulator/bus_emulators.rst` +- Native Sim Docs: `zephyr/boards/native/native_sim/doc/index.rst` +- Command-line handling: `zephyr/boards/native/native_sim/cmdline.c` +- Example mock API usage: `zephyr/tests/drivers/sensor/bmi160/src/i2c.c` diff --git a/ports/zephyr-cp/tests/docs/web_workflow.md b/ports/zephyr-cp/tests/docs/web_workflow.md new file mode 100644 index 00000000000..eb6742b8a3e --- /dev/null +++ b/ports/zephyr-cp/tests/docs/web_workflow.md @@ -0,0 +1,37 @@ +# Web Workflow native_sim Tests + +These tests validate CircuitPython's web workflow support in the Zephyr native_sim port, including filesystem write behavior with and without USB-style write protection. + +## Coverage + +- `test_web_workflow_hostnetwork`: Verifies the web workflow HTTP server responds and enforces authentication (`/edit/` returns `401 Unauthorized`). +- `test_web_workflow_write_code_py_conflict`: Exercises a write attempt while the filesystem is protected (no `boot.py` remount). The DELETE request should return `409 Conflict`. +- `test_web_workflow_write_code_py_remount`: Uses a `boot.py` remount to allow CircuitPython to write. A PUT request updates `code.py`, and a subsequent GET verifies the contents. + +## Filesystem Setup + +The tests create a flash image with: + +- `settings.toml` containing `CIRCUITPY_WEB_API_PASSWORD="testpass"` so the web workflow starts using the on-device settings file. +- `boot.py` (for the remount test only) with: + ```python + import storage + storage.remount("/", readonly=False) + ``` + This disables concurrent write protection so the web workflow can write to CIRCUITPY. + +## Running the Tests + +Build native_sim (if needed): + +```bash +make BOARD=native_native_sim +``` + +Run the tests: + +```bash +pytest -q ports/zephyr-cp/tests/test_web_workflow.py::test_web_workflow_hostnetwork -vv +pytest -q ports/zephyr-cp/tests/test_web_workflow.py::test_web_workflow_write_code_py_conflict -vv +pytest -q ports/zephyr-cp/tests/test_web_workflow.py::test_web_workflow_write_code_py_remount -vv +``` diff --git a/ports/zephyr-cp/tests/perfetto_input_trace.py b/ports/zephyr-cp/tests/perfetto_input_trace.py new file mode 100644 index 00000000000..494c9cdcadf --- /dev/null +++ b/ports/zephyr-cp/tests/perfetto_input_trace.py @@ -0,0 +1,159 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries LLC +# SPDX-License-Identifier: MIT + +"""Utilities for creating Perfetto input trace files for native_sim tests. + +This module can be used directly from Python or from the command line: + + python -m tests.perfetto_input_trace input_trace.json output.perfetto + +Input JSON format — counter tracks use [timestamp, value] pairs, instant +tracks use bare timestamps: + +{ + "gpio_emul.01": [[8000000000, 0], [9000000000, 1], [10000000000, 0]], + "display_capture": [500000000, 1000000000] +} +""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path +from typing import Mapping, Sequence + +# Counter tracks: list of (timestamp, value) pairs. +# Instant tracks: list of timestamps (bare ints). +InputTraceData = Mapping[str, Sequence[tuple[int, int] | int]] + + +def _load_perfetto_pb2(): + from perfetto.protos.perfetto.trace import perfetto_trace_pb2 as perfetto_pb2 + + return perfetto_pb2 + + +def _is_instant_track(events: Sequence) -> bool: + """Return True if *events* is a list of bare timestamps (instant track).""" + if not events: + return False + return isinstance(events[0], int) + + +def build_input_trace(trace_data: InputTraceData, *, sequence_id: int = 1): + """Build a Perfetto Trace protobuf for input replay counter and instant tracks.""" + perfetto_pb2 = _load_perfetto_pb2() + trace = perfetto_pb2.Trace() + + seq_incremental_state_cleared = 1 + seq_needs_incremental_state = 2 + + for idx, (track_name, events) in enumerate(trace_data.items()): + track_uuid = 1001 + idx + instant = _is_instant_track(events) + + desc_packet = trace.packet.add() + desc_packet.timestamp = 0 + desc_packet.trusted_packet_sequence_id = sequence_id + if idx == 0: + desc_packet.sequence_flags = seq_incremental_state_cleared + desc_packet.track_descriptor.uuid = track_uuid + desc_packet.track_descriptor.name = track_name + if not instant: + desc_packet.track_descriptor.counter.unit = ( + perfetto_pb2.CounterDescriptor.Unit.UNIT_COUNT + ) + + if instant: + for ts in events: + event_packet = trace.packet.add() + event_packet.timestamp = ts + event_packet.trusted_packet_sequence_id = sequence_id + event_packet.sequence_flags = seq_needs_incremental_state + event_packet.track_event.type = perfetto_pb2.TrackEvent.Type.TYPE_INSTANT + event_packet.track_event.track_uuid = track_uuid + else: + for ts, value in events: + event_packet = trace.packet.add() + event_packet.timestamp = ts + event_packet.trusted_packet_sequence_id = sequence_id + event_packet.sequence_flags = seq_needs_incremental_state + event_packet.track_event.type = perfetto_pb2.TrackEvent.Type.TYPE_COUNTER + event_packet.track_event.track_uuid = track_uuid + event_packet.track_event.counter_value = value + + return trace + + +def write_input_trace( + trace_file: Path, trace_data: InputTraceData, *, sequence_id: int = 1 +) -> None: + """Write input replay data to a Perfetto trace file.""" + trace = build_input_trace(trace_data, sequence_id=sequence_id) + trace_file.parent.mkdir(parents=True, exist_ok=True) + trace_file.write_bytes(trace.SerializeToString()) + + +def _parse_trace_json(data: object) -> dict[str, list[tuple[int, int]] | list[int]]: + if not isinstance(data, dict): + raise ValueError("top-level JSON value must be an object") + + parsed: dict[str, list[tuple[int, int]] | list[int]] = {} + for track_name, events in data.items(): + if not isinstance(track_name, str): + raise ValueError("track names must be strings") + if not isinstance(events, list): + raise ValueError(f"track {track_name!r} must map to a list of events") + + if not events: + parsed[track_name] = [] + continue + + # Distinguish instant (bare ints) vs counter ([ts, value] pairs). + if isinstance(events[0], (int, float)): + parsed[track_name] = [int(ts) for ts in events] + else: + parsed_events: list[tuple[int, int]] = [] + for event in events: + if not isinstance(event, (list, tuple)) or len(event) != 2: + raise ValueError( + f"track {track_name!r} events must be [timestamp, value] pairs " + "or bare timestamps" + ) + timestamp_ns, value = event + parsed_events.append((int(timestamp_ns), int(value))) + parsed[track_name] = parsed_events + + return parsed + + +def _build_arg_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + description="Generate a Perfetto input trace file used by native_sim --input-trace" + ) + parser.add_argument("input_json", type=Path, help="Path to input trace JSON") + parser.add_argument("output_trace", type=Path, help="Output .perfetto file path") + parser.add_argument( + "--sequence-id", + type=int, + default=1, + help="trusted_packet_sequence_id to use (default: 1)", + ) + return parser + + +def main(argv: Sequence[str] | None = None) -> int: + parser = _build_arg_parser() + args = parser.parse_args(argv) + + trace_json = json.loads(args.input_json.read_text()) + trace_data = _parse_trace_json(trace_json) + write_input_trace(args.output_trace, trace_data, sequence_id=args.sequence_id) + + print(f"Wrote {args.output_trace} ({len(trace_data)} tracks)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/ports/zephyr-cp/tests/test_adafruit_bus_device.py b/ports/zephyr-cp/tests/test_adafruit_bus_device.py new file mode 100644 index 00000000000..3022838506e --- /dev/null +++ b/ports/zephyr-cp/tests/test_adafruit_bus_device.py @@ -0,0 +1,236 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test adafruit_bus_device.i2c_device.I2CDevice against the AT24 EEPROM emulator.""" + +import pytest + + +PROBE_OK_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) +print(f"device created: {type(device).__name__}") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": PROBE_OK_CODE}) +def test_i2cdevice_probe_success(circuitpython): + """Constructing I2CDevice with probe=True succeeds when AT24 is present at 0x50.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "device created: I2CDevice" in output + assert "done" in output + + +PROBE_FAIL_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +try: + device = I2CDevice(i2c, 0x51) + print("unexpected_success") +except ValueError as e: + print(f"probe_failed: {e}") +except OSError as e: + print(f"probe_failed: {e}") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": PROBE_FAIL_CODE}) +def test_i2cdevice_probe_failure(circuitpython): + """Constructing I2CDevice with probe=True raises when no device responds.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "probe_failed" in output + assert "unexpected_success" not in output + assert "done" in output + + +PROBE_DISABLED_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +# probe=False should not raise even without a device at this address +device = I2CDevice(i2c, 0x51, probe=False) +print(f"device created: {type(device).__name__}") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": PROBE_DISABLED_CODE}) +def test_i2cdevice_probe_disabled(circuitpython): + """Constructing I2CDevice with probe=False succeeds regardless of device presence.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "device created: I2CDevice" in output + assert "done" in output + + +READ_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) + +# Read first byte by writing the memory address, then reading. +buf = bytearray(1) +with device: + device.write(bytes([0x00])) + device.readinto(buf) +print(f"AT24 byte 0: 0x{buf[0]:02X}") +if buf[0] == 0xFF: + print("eeprom_valid") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": READ_CODE}) +def test_i2cdevice_write_then_readinto_separate(circuitpython): + """write() followed by readinto() inside a single context manager block reads EEPROM data.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "AT24 byte 0: 0xFF" in output + assert "eeprom_valid" in output + assert "done" in output + + +WRITE_THEN_READINTO_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) + +out_buf = bytes([0x00]) +in_buf = bytearray(4) +with device: + device.write_then_readinto(out_buf, in_buf) +print(f"first 4 bytes: {[hex(b) for b in in_buf]}") +if all(b == 0xFF for b in in_buf): + print("eeprom_valid") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_THEN_READINTO_CODE}) +def test_i2cdevice_write_then_readinto_atomic(circuitpython): + """write_then_readinto() performs an atomic write+read against the EEPROM.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "first 4 bytes:" in output + assert "eeprom_valid" in output + assert "done" in output + + +WRITE_READBACK_CODE = """\ +import board +import time +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) + +# Write four bytes starting at EEPROM address 0x10. +payload = bytes([0xDE, 0xAD, 0xBE, 0xEF]) +with device: + device.write(bytes([0x10]) + payload) + +# EEPROM needs a moment to commit the write internally. +time.sleep(0.01) + +readback = bytearray(4) +with device: + device.write_then_readinto(bytes([0x10]), readback) +print(f"readback: {[hex(b) for b in readback]}") +if bytes(readback) == payload: + print("readback_ok") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_READBACK_CODE}) +def test_i2cdevice_write_then_read_roundtrip(circuitpython): + """Writing bytes to the EEPROM and reading them back returns the written values.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "readback_ok" in output + assert "done" in output + + +SLICE_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) + +# Use start/end kwargs to send only a slice of the outgoing buffer. +out = bytearray([0xAA, 0x00, 0xBB]) +dest = bytearray(4) +with device: + # Only send the middle byte (the memory address 0x00). + device.write_then_readinto(out, dest, out_start=1, out_end=2, in_start=0, in_end=2) +print(f"partial read: {[hex(b) for b in dest]}") +# Only the first two entries should have been written by the read. +if dest[0] == 0xFF and dest[1] == 0xFF and dest[2] == 0x00 and dest[3] == 0x00: + print("slice_ok") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": SLICE_CODE}) +def test_i2cdevice_buffer_slices(circuitpython): + """write_then_readinto honors out_start/out_end and in_start/in_end bounds.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "slice_ok" in output + assert "done" in output + + +DISABLED_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +try: + device = I2CDevice(i2c, 0x50) + print("unexpected_success") +except (ValueError, OSError) as e: + print(f"probe_failed: {e}") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": DISABLED_CODE}) +@pytest.mark.disable_i2c_devices("eeprom@50") +def test_i2cdevice_probe_fails_when_device_disabled(circuitpython): + """Probe fails when the AT24 emulator device is disabled on the bus.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "probe_failed" in output + assert "unexpected_success" not in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_aesio.py b/ports/zephyr-cp/tests/test_aesio.py new file mode 100644 index 00000000000..3ae016ac8e3 --- /dev/null +++ b/ports/zephyr-cp/tests/test_aesio.py @@ -0,0 +1,223 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the aesio module.""" + +import pytest + +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + + +KEY = b"Sixteen byte key" +PLAINTEXT = b"CircuitPython!!!" # 16 bytes + + +ECB_CODE = """\ +import aesio + +key = b'Sixteen byte key' +inp = b'CircuitPython!!!' +outp = bytearray(len(inp)) +cipher = aesio.AES(key, aesio.MODE_ECB) +cipher.encrypt_into(inp, outp) +print(f"ciphertext_hex: {outp.hex()}") + +decrypted = bytearray(len(outp)) +cipher.decrypt_into(bytes(outp), decrypted) +print(f"decrypted: {bytes(decrypted)}") +print(f"match: {bytes(decrypted) == inp}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": ECB_CODE}) +def test_aesio_ecb(circuitpython): + """AES-ECB round-trips and matches CPython cryptography's output.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + encryptor = Cipher(algorithms.AES(KEY), modes.ECB()).encryptor() + expected_hex = (encryptor.update(PLAINTEXT) + encryptor.finalize()).hex() + assert f"ciphertext_hex: {expected_hex}" in output + assert "match: True" in output + assert "done" in output + + +IV = b"InitializationVe" # 16 bytes +CBC_PLAINTEXT = b"CircuitPython!!!" * 2 # 32 bytes, multiple of 16 +CTR_PLAINTEXT = b"CircuitPython is fun to use!" # 28 bytes, arbitrary length + + +CBC_CODE = """\ +import aesio + +key = b'Sixteen byte key' +iv = b'InitializationVe' +inp = b'CircuitPython!!!' * 2 +outp = bytearray(len(inp)) +cipher = aesio.AES(key, aesio.MODE_CBC, iv) +print(f"mode: {cipher.mode}") +cipher.encrypt_into(inp, outp) +print(f"ciphertext_hex: {outp.hex()}") + +# Re-create cipher to reset IV state for decryption. +cipher2 = aesio.AES(key, aesio.MODE_CBC, iv) +decrypted = bytearray(len(outp)) +cipher2.decrypt_into(bytes(outp), decrypted) +print(f"match: {bytes(decrypted) == inp}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CBC_CODE}) +def test_aesio_cbc(circuitpython): + """AES-CBC round-trips and matches CPython cryptography's output.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + encryptor = Cipher(algorithms.AES(KEY), modes.CBC(IV)).encryptor() + expected_hex = (encryptor.update(CBC_PLAINTEXT) + encryptor.finalize()).hex() + assert "mode: 2" in output + assert f"ciphertext_hex: {expected_hex}" in output + assert "match: True" in output + assert "done" in output + + +CTR_CODE = """\ +import aesio + +key = b'Sixteen byte key' +iv = b'InitializationVe' +inp = b'CircuitPython is fun to use!' +outp = bytearray(len(inp)) +cipher = aesio.AES(key, aesio.MODE_CTR, iv) +print(f"mode: {cipher.mode}") +cipher.encrypt_into(inp, outp) +print(f"ciphertext_hex: {outp.hex()}") + +cipher2 = aesio.AES(key, aesio.MODE_CTR, iv) +decrypted = bytearray(len(outp)) +cipher2.decrypt_into(bytes(outp), decrypted) +print(f"decrypted: {bytes(decrypted)}") +print(f"match: {bytes(decrypted) == inp}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CTR_CODE}) +def test_aesio_ctr(circuitpython): + """AES-CTR handles arbitrary-length buffers and matches CPython output.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + encryptor = Cipher(algorithms.AES(KEY), modes.CTR(IV)).encryptor() + expected_hex = (encryptor.update(CTR_PLAINTEXT) + encryptor.finalize()).hex() + assert "mode: 6" in output + assert f"ciphertext_hex: {expected_hex}" in output + assert "match: True" in output + assert "done" in output + + +REKEY_CODE = """\ +import aesio + +key1 = b'Sixteen byte key' +key2 = b'Another 16 byte!' +inp = b'CircuitPython!!!' + +cipher = aesio.AES(key1, aesio.MODE_ECB) +out1 = bytearray(16) +cipher.encrypt_into(inp, out1) +print(f"ct1_hex: {out1.hex()}") + +cipher.rekey(key2) +out2 = bytearray(16) +cipher.encrypt_into(inp, out2) +print(f"ct2_hex: {out2.hex()}") +print(f"different: {bytes(out1) != bytes(out2)}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": REKEY_CODE}) +def test_aesio_rekey(circuitpython): + """rekey() switches the active key; ciphertexts match CPython for both keys.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + enc1 = Cipher(algorithms.AES(b"Sixteen byte key"), modes.ECB()).encryptor() + ct1 = (enc1.update(PLAINTEXT) + enc1.finalize()).hex() + enc2 = Cipher(algorithms.AES(b"Another 16 byte!"), modes.ECB()).encryptor() + ct2 = (enc2.update(PLAINTEXT) + enc2.finalize()).hex() + assert f"ct1_hex: {ct1}" in output + assert f"ct2_hex: {ct2}" in output + assert "different: True" in output + assert "done" in output + + +MODE_PROPERTY_CODE = """\ +import aesio + +key = b'Sixteen byte key' +iv = b'InitializationVe' +cipher = aesio.AES(key, aesio.MODE_ECB) +print(f"initial: {cipher.mode}") +print(f"ECB={aesio.MODE_ECB} CBC={aesio.MODE_CBC} CTR={aesio.MODE_CTR}") + +for name, m in (("ECB", aesio.MODE_ECB), ("CBC", aesio.MODE_CBC), ("CTR", aesio.MODE_CTR)): + cipher.mode = m + print(f"set_{name}: {cipher.mode}") + +try: + cipher.mode = 99 +except NotImplementedError as e: + print(f"bad_mode: NotImplementedError") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": MODE_PROPERTY_CODE}) +def test_aesio_mode_property(circuitpython): + """The mode property is readable, writable, and rejects unsupported values.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "initial: 1" in output + assert "ECB=1 CBC=2 CTR=6" in output + assert "set_ECB: 1" in output + assert "set_CBC: 2" in output + assert "set_CTR: 6" in output + assert "bad_mode: NotImplementedError" in output + assert "done" in output + + +KEY_LENGTHS_CODE = """\ +import aesio + +inp = b'CircuitPython!!!' +for key in (b'A' * 16, b'B' * 24, b'C' * 32): + cipher = aesio.AES(key, aesio.MODE_ECB) + out = bytearray(16) + cipher.encrypt_into(inp, out) + print(f"len{len(key)}: {out.hex()}") + +try: + aesio.AES(b'too short', aesio.MODE_ECB) +except ValueError: + print("bad_key: ValueError") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": KEY_LENGTHS_CODE}) +def test_aesio_key_lengths(circuitpython): + """AES-128/192/256 keys all work and match CPython; bad key length raises.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + for key in (b"A" * 16, b"B" * 24, b"C" * 32): + encryptor = Cipher(algorithms.AES(key), modes.ECB()).encryptor() + expected = (encryptor.update(PLAINTEXT) + encryptor.finalize()).hex() + assert f"len{len(key)}: {expected}" in output + assert "bad_key: ValueError" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_audiobusio.py b/ports/zephyr-cp/tests/test_audiobusio.py new file mode 100644 index 00000000000..9d03e976bc9 --- /dev/null +++ b/ports/zephyr-cp/tests/test_audiobusio.py @@ -0,0 +1,290 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries LLC +# SPDX-License-Identifier: MIT + +"""Test audiobusio I2SOut functionality on native_sim.""" + +from pathlib import Path + +import pytest +from perfetto.trace_processor import TraceProcessor + + +I2S_PLAY_CODE = """\ +import array +import math +import audiocore +import board +import time + +# Generate a 440 Hz sine wave, 16-bit signed stereo at 16000 Hz +sample_rate = 16000 +length = sample_rate // 440 # ~36 samples per period +values = [] +for i in range(length): + v = int(math.sin(math.pi * 2 * i / length) * 30000) + values.append(v) # left + values.append(v) # right + +sample = audiocore.RawSample( + array.array("h", values), + sample_rate=sample_rate, + channel_count=2, +) + +dac = board.I2S0() +print("playing") +dac.play(sample, loop=True) +time.sleep(0.5) +dac.stop() +print("stopped") +print("done") +""" + + +def parse_i2s_trace(trace_file: Path, track_name: str) -> list[tuple[int, int]]: + """Parse I2S counter trace from Perfetto trace file.""" + tp = TraceProcessor(file_path=str(trace_file)) + result = tp.query( + f""" + SELECT c.ts, c.value + FROM counter c + JOIN track t ON c.track_id = t.id + WHERE t.name LIKE "%{track_name}" + ORDER BY c.ts + """ + ) + return [(int(row.ts), int(row.value)) for row in result] + + +@pytest.mark.duration(10) +@pytest.mark.circuitpy_drive({"code.py": I2S_PLAY_CODE}) +def test_i2s_play_and_stop(circuitpython): + """Test I2SOut play and stop produce expected output and correct waveform traces.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "playing" in output + assert "stopped" in output + assert "done" in output + + # Check that Perfetto trace has I2S counter tracks with data + left_trace = parse_i2s_trace(circuitpython.trace_file, "Left") + right_trace = parse_i2s_trace(circuitpython.trace_file, "Right") + + # Should have counter events (initial zero + audio data) + assert len(left_trace) > 10, f"Expected many Left channel events, got {len(left_trace)}" + assert len(right_trace) > 10, f"Expected many Right channel events, got {len(right_trace)}" + + # Verify timestamps are spread out (not all the same) + left_timestamps = [ts for ts, _ in left_trace] + assert left_timestamps[-1] > left_timestamps[1], "Timestamps should increase over time" + time_span_ns = left_timestamps[-1] - left_timestamps[1] + # We play for 0.5s, so span should be at least 100ms + assert time_span_ns > 100_000_000, f"Expected >100ms time span, got {time_span_ns / 1e6:.1f}ms" + + # Audio data should contain non-zero values (sine wave) + # Skip the initial zero value + left_values = [v for _, v in left_trace if v != 0] + right_values = [v for _, v in right_trace if v != 0] + assert len(left_values) > 5, "Left channel has too few non-zero values" + assert len(right_values) > 5, "Right channel has too few non-zero values" + + # Sine wave should have both positive and negative values + assert any(v > 0 for v in left_values), "Left channel has no positive values" + assert any(v < 0 for v in left_values), "Left channel has no negative values" + + # Verify amplitude is in the expected range (we generate with amplitude 30000) + max_left = max(left_values) + min_left = min(left_values) + assert max_left > 20000, f"Left max {max_left} too low, expected >20000" + assert min_left < -20000, f"Left min {min_left} too high, expected <-20000" + + # Left and right should match (we write the same value to both channels) + # Compare a subset of matching timestamps + left_by_ts = dict(left_trace) + right_by_ts = dict(right_trace) + common_ts = sorted(set(left_by_ts.keys()) & set(right_by_ts.keys())) + mismatches = 0 + for ts in common_ts[:100]: + if left_by_ts[ts] != right_by_ts[ts]: + mismatches += 1 + assert mismatches == 0, ( + f"{mismatches} L/R mismatches in first {min(100, len(common_ts))} common timestamps" + ) + + +I2S_PLAY_NO_STOP_CODE = """\ +import array +import math +import audiocore +import board +import time + +sample_rate = 16000 +length = sample_rate // 440 +values = [] +for i in range(length): + v = int(math.sin(math.pi * 2 * i / length) * 30000) + values.append(v) + values.append(v) + +sample = audiocore.RawSample( + array.array("h", values), + sample_rate=sample_rate, + channel_count=2, +) + +dac = board.I2S0() +dac.play(sample, loop=True) +print("playing") +time.sleep(0.2) +# Exit without calling dac.stop() — reset_port should clean up +print("exiting") +""" + + +@pytest.mark.duration(15) +@pytest.mark.port_resets(3) +@pytest.mark.circuitpy_drive({"code.py": I2S_PLAY_NO_STOP_CODE}) +def test_i2s_stops_on_code_exit(circuitpython): + """Test I2S is stopped by reset_port when code.py exits without explicit stop.""" + # First run: plays audio then exits without stopping + circuitpython.serial.wait_for("exiting") + circuitpython.serial.wait_for("Press any key to enter the REPL") + # Trigger soft reload + circuitpython.serial.write("\x04") + + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + # Should see "playing" and "exiting" at least twice (once per run) + assert output.count("playing") >= 2 + assert output.count("exiting") >= 2 + + +I2S_PAUSE_RESUME_CODE = """\ +import array +import math +import audiocore +import board +import time + +sample_rate = 16000 +length = sample_rate // 440 +values = [] +for i in range(length): + v = int(math.sin(math.pi * 2 * i / length) * 30000) + values.append(v) + values.append(v) + +sample = audiocore.RawSample( + array.array("h", values), + sample_rate=sample_rate, + channel_count=2, +) + +dac = board.I2S0() +dac.play(sample, loop=True) +print("playing") +time.sleep(0.2) + +dac.pause() +print("paused") +assert dac.paused +time.sleep(0.1) + +dac.resume() +print("resumed") +assert not dac.paused +time.sleep(0.2) + +dac.stop() +print("done") +""" + + +@pytest.mark.duration(10) +@pytest.mark.circuitpy_drive({"code.py": I2S_PAUSE_RESUME_CODE}) +def test_i2s_pause_resume(circuitpython): + """Test I2SOut pause and resume work correctly.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "playing" in output + assert "paused" in output + assert "resumed" in output + assert "done" in output + + +I2S_PLAY_LOOP_FALSE_CODE = """\ +import array +import math +import audiocore +import board +import time + +# 440 Hz sine, 16-bit signed stereo at 16000 Hz, several periods. +sample_rate = 16000 +length = sample_rate // 440 +periods = 10 +values = [] +for _ in range(periods): + for i in range(length): + v = int(math.sin(math.pi * 2 * i / length) * 30000) + values.append(v) # left + values.append(v) # right + +# Default single_buffer=True: get_buffer returns the whole buffer together with +# GET_BUFFER_DONE on the very first call. With loop=False that buffer used to be +# discarded before being copied, producing silence (issue #10539). +sample = audiocore.RawSample( + array.array("h", values), + sample_rate=sample_rate, + channel_count=2, +) + +dac = board.I2S0() +print("playing") +dac.play(sample, loop=False) +time.sleep(0.5) +# Stop explicitly so this test does not depend on `playing` clearing on its own. +dac.stop() +print("done") +""" + + +@pytest.mark.duration(10) +@pytest.mark.circuitpy_drive({"code.py": I2S_PLAY_LOOP_FALSE_CODE}) +def test_i2s_play_non_looping_single_buffer(circuitpython): + """A single-buffer RawSample played with loop=False must be heard, not dropped. + + Regression test for #10539: the final buffer, returned together with + GET_BUFFER_DONE, was discarded before being copied, so a single-buffer + sample (whole buffer + DONE on the first get_buffer call) produced silence. + """ + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "playing" in output + assert "done" in output + + left_trace = parse_i2s_trace(circuitpython.trace_file, "Left") + right_trace = parse_i2s_trace(circuitpython.trace_file, "Right") + + # The sine wave must actually reach the I2S output. On the bug every value is + # zero (silence) because the sole buffer was dropped. + left_values = [v for _, v in left_trace if v != 0] + right_values = [v for _, v in right_trace if v != 0] + assert len(left_values) > 5, "Left channel is silent; non-looping sample was dropped" + assert len(right_values) > 5, "Right channel is silent; non-looping sample was dropped" + + # A sine wave has both positive and negative excursions at the expected amplitude. + assert max(left_values) > 20000, f"Left max {max(left_values)} too low" + assert min(left_values) < -20000, f"Left min {min(left_values)} too high" + + # We wrote the same value to both channels. + left_by_ts = dict(left_trace) + right_by_ts = dict(right_trace) + common_ts = sorted(set(left_by_ts) & set(right_by_ts)) + mismatches = sum(1 for ts in common_ts[:100] if left_by_ts[ts] != right_by_ts[ts]) + assert mismatches == 0, f"{mismatches} L/R mismatches in first common timestamps" diff --git a/ports/zephyr-cp/tests/test_basics.py b/ports/zephyr-cp/tests/test_basics.py new file mode 100644 index 00000000000..0120ad660d8 --- /dev/null +++ b/ports/zephyr-cp/tests/test_basics.py @@ -0,0 +1,117 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test basic native_sim functionality.""" + +import pytest + + +@pytest.mark.circuitpy_drive(None) +def test_blank_flash_hello_world(board, circuitpython): + """Test that an erased flash shows code.py output header.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"Board ID:{board}" in output + assert "UID:" in output + assert "code.py output:" in output + assert "Hello World" in output + assert "done" in output + + +# --- PTY Input Tests --- + + +INPUT_CODE = """\ +import sys + +print("ready") +char = sys.stdin.read(1) +print(f"received: {repr(char)}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": INPUT_CODE}) +def test_basic_serial_input(circuitpython): + """Test reading single character from serial via PTY write.""" + circuitpython.serial.wait_for("ready") + circuitpython.serial.write("A") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "ready" in output + assert "received: 'A'" in output + assert "done" in output + + +INPUT_FUNC_CODE = """\ +print("ready") +name = input("Enter name: ") +print(f"hello {name}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": INPUT_FUNC_CODE}) +def test_input_function(circuitpython): + """Test the built-in input() function with PTY input.""" + circuitpython.serial.wait_for("Enter name:") + circuitpython.serial.write("World\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "ready" in output + assert "Enter name:" in output + assert "hello World" in output + assert "done" in output + + +INTERRUPT_CODE = """\ +import time + +print("starting") +for i in range(100): + print(f"loop {i}") + time.sleep(0.1) +print("completed") +""" + + +@pytest.mark.circuitpy_drive({"code.py": INTERRUPT_CODE}) +def test_ctrl_c_interrupt(circuitpython): + """Test sending Ctrl+C (0x03) to interrupt running code.""" + circuitpython.serial.wait_for("loop 5") + circuitpython.serial.write("\x03") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "starting" in output + assert "loop 5" in output + assert "KeyboardInterrupt" in output + assert "completed" not in output + + +RELOAD_CODE = """\ +print("first run") +import time +time.sleep(1) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": RELOAD_CODE}) +@pytest.mark.port_resets(3) +def test_ctrl_d_soft_reload(circuitpython): + """Test sending Ctrl+D (0x04) to trigger soft reload.""" + circuitpython.serial.wait_for("first run") + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() + + # Should see "first run" appear multiple times due to reload + # or see a soft reboot message + output = circuitpython.serial.all_output + assert "first run" in output + # The soft reload should restart the code before "done" is printed + assert "done" in output + assert output.count("first run") > 1 diff --git a/ports/zephyr-cp/tests/test_digitalio.py b/ports/zephyr-cp/tests/test_digitalio.py new file mode 100644 index 00000000000..22c64f7b83f --- /dev/null +++ b/ports/zephyr-cp/tests/test_digitalio.py @@ -0,0 +1,171 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries LLC +# SPDX-License-Identifier: MIT + +"""Test digitalio functionality on native_sim.""" + +import re +from pathlib import Path + +import pytest +from perfetto.trace_processor import TraceProcessor + + +DIGITALIO_INPUT_TRACE_READ_CODE = """\ +import time +import digitalio +import microcontroller + +pin = digitalio.DigitalInOut(microcontroller.pin.P_01) +pin.direction = digitalio.Direction.INPUT + +start = time.monotonic() +last = pin.value +print(f"t_abs={time.monotonic():.3f} initial={last}") + +# Poll long enough to observe a high pulse injected through input trace. +while time.monotonic() - start < 8.0: + value = pin.value + if value != last: + print(f"t_abs={time.monotonic():.3f} edge={value}") + last = value + time.sleep(0.05) + +print(f"t_abs={time.monotonic():.3f} done") +""" + + +DIGITALIO_INPUT_TRACE = { + "gpio_emul.01": [ + (8_000_000_000, 0), + (9_000_000_000, 1), + (10_000_000_000, 0), + ], +} + + +@pytest.mark.duration(14.0) +@pytest.mark.circuitpy_drive({"code.py": DIGITALIO_INPUT_TRACE_READ_CODE}) +@pytest.mark.input_trace(DIGITALIO_INPUT_TRACE) +def test_digitalio_reads_input_trace(circuitpython): + """Test DigitalInOut input reads values injected via input trace.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + + initial_match = re.search(r"t_abs=([0-9]+\.[0-9]+) initial=False", output) + edge_match = re.search(r"t_abs=([0-9]+\.[0-9]+) edge=True", output) + done_match = re.search(r"t_abs=([0-9]+\.[0-9]+) done", output) + + assert initial_match is not None + assert edge_match is not None + assert done_match is not None + + initial_abs = float(initial_match.group(1)) + edge_abs = float(edge_match.group(1)) + done_abs = float(done_match.group(1)) + + # Input trace edge is at 9.0s for gpio_emul.01. + assert 8.5 <= edge_abs <= 9.5 + assert initial_abs <= edge_abs <= done_abs + + +BLINK_CODE = """\ +import time +import board +import digitalio + +led = digitalio.DigitalInOut(board.LED) +led.direction = digitalio.Direction.OUTPUT + +for i in range(3): + print(f"LED on {i}") + led.value = True + time.sleep(0.1) + print(f"LED off {i}") + led.value = False + time.sleep(0.1) + +print("done") +""" + + +def parse_gpio_trace(trace_file: Path, pin_name: str = "gpio_emul.00") -> list[tuple[int, int]]: + """Parse GPIO trace from Perfetto trace file.""" + tp = TraceProcessor(file_path=str(trace_file)) + result = tp.query( + f''' + SELECT c.ts, c.value + FROM counter c + JOIN track t ON c.track_id = t.id + WHERE t.name = "{pin_name}" + ORDER BY c.ts + ''' + ) + return [(row.ts, int(row.value)) for row in result] + + +@pytest.mark.circuitpy_drive({"code.py": BLINK_CODE}) +def test_digitalio_blink_output(circuitpython): + """Test blink program produces expected output and GPIO traces.""" + circuitpython.wait_until_done() + + # Check serial output + output = circuitpython.serial.all_output + assert "LED on 0" in output + assert "LED off 0" in output + assert "LED on 2" in output + assert "LED off 2" in output + assert "done" in output + + # Check GPIO traces - LED is on gpio_emul.00 + gpio_trace = parse_gpio_trace(circuitpython.trace_file, "gpio_emul.00") + + # Deduplicate by timestamp (keep last value at each timestamp) + by_timestamp = {} + for ts, val in gpio_trace: + by_timestamp[ts] = val + sorted_trace = sorted(by_timestamp.items()) + + # Find transition points (where value changes), skipping initialization at ts=0 + transitions = [] + for i in range(1, len(sorted_trace)): + prev_ts, prev_val = sorted_trace[i - 1] + curr_ts, curr_val = sorted_trace[i] + if prev_val != curr_val and curr_ts > 0: + transitions.append((curr_ts, curr_val)) + + # We expect at least 6 transitions (3 on + 3 off) from the blink loop + assert len(transitions) >= 6, f"Expected at least 6 transitions, got {len(transitions)}" + + # Verify timing between consecutive transitions + # Each sleep is 0.1s = 100ms = 100,000,000 ns + expected_interval_ns = 100_000_000 + tolerance_ns = 20_000_000 # 20ms tolerance + + # Find a sequence of 6 consecutive transitions with ~100ms intervals (the blink loop) + # This filters out initialization and cleanup noise + blink_transitions = [] + for i in range(len(transitions) - 1): + interval = transitions[i + 1][0] - transitions[i][0] + if abs(interval - expected_interval_ns) < tolerance_ns: + if not blink_transitions: + blink_transitions.append(transitions[i]) + blink_transitions.append(transitions[i + 1]) + elif blink_transitions: + # Found end of blink sequence + break + + assert len(blink_transitions) >= 6, ( + f"Expected at least 6 blink transitions with ~100ms intervals, got {len(blink_transitions)}" + ) + + # Verify timing between blink transitions + for i in range(1, min(6, len(blink_transitions))): + prev_ts = blink_transitions[i - 1][0] + curr_ts = blink_transitions[i][0] + interval = curr_ts - prev_ts + assert abs(interval - expected_interval_ns) < tolerance_ns, ( + f"Transition interval {interval / 1_000_000:.1f}ms deviates from " + f"expected {expected_interval_ns / 1_000_000:.1f}ms by more than " + f"{tolerance_ns / 1_000_000:.1f}ms tolerance" + ) diff --git a/ports/zephyr-cp/tests/test_flash.py b/ports/zephyr-cp/tests/test_flash.py new file mode 100644 index 00000000000..e2e5f4de14f --- /dev/null +++ b/ports/zephyr-cp/tests/test_flash.py @@ -0,0 +1,171 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test flash filesystem with various erase block sizes.""" + +import subprocess + +import pytest + + +def read_file_from_flash(flash_file, path): + """Extract a file from the FAT filesystem in the flash image.""" + result = subprocess.run( + ["mcopy", "-i", str(flash_file), f"::{path}", "-"], + capture_output=True, + ) + if result.returncode != 0: + raise FileNotFoundError( + f"Failed to read ::{path} from {flash_file}: {result.stderr.decode()}" + ) + return result.stdout.decode() + + +WRITE_READ_CODE = """\ +import storage +storage.remount("/", readonly=False) +with open("/test.txt", "w") as f: + f.write("hello flash") +with open("/test.txt", "r") as f: + content = f.read() +print(f"content: {content}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_READ_CODE}) +def test_flash_default_erase_size(circuitpython): + """Test filesystem write/read with default 4KB erase blocks.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "content: hello flash" in output + assert "done" in output + + content = read_file_from_flash(circuitpython.flash_file, "test.txt") + assert content == "hello flash" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_READ_CODE}) +@pytest.mark.flash_config(erase_block_size=65536) +def test_flash_64k_erase_blocks(circuitpython): + """Test filesystem write/read with 64KB erase blocks (128 blocks per page).""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "content: hello flash" in output + assert "done" in output + + content = read_file_from_flash(circuitpython.flash_file, "test.txt") + assert content == "hello flash" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_READ_CODE}) +@pytest.mark.flash_config(erase_block_size=262144, total_size=4 * 1024 * 1024) +def test_flash_256k_erase_blocks(circuitpython): + """Test filesystem write/read with 256KB erase blocks (like RA8D1 OSPI).""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "content: hello flash" in output + assert "done" in output + + content = read_file_from_flash(circuitpython.flash_file, "test.txt") + assert content == "hello flash" + + +MULTI_FILE_CODE = """\ +import storage +storage.remount("/", readonly=False) +for i in range(5): + name = f"/file{i}.txt" + with open(name, "w") as f: + f.write(f"data{i}" * 100) +print("multi_file_ok") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": MULTI_FILE_CODE}) +@pytest.mark.flash_config(erase_block_size=262144, total_size=4 * 1024 * 1024) +def test_flash_256k_multi_file(circuitpython): + """Test multiple file writes with 256KB erase blocks to exercise cache flushing.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "multi_file_ok" in output + + for i in range(5): + content = read_file_from_flash(circuitpython.flash_file, f"file{i}.txt") + assert content == f"data{i}" * 100, f"file{i}.txt mismatch" + + +EXISTING_DATA_CODE = """\ +import storage +storage.remount("/", readonly=False) + +# Write a file to populate the erase page. +original_data = "A" * 4000 +with open("/original.txt", "w") as f: + f.write(original_data) + +# Force a flush so the data is written to flash. +storage.remount("/", readonly=True) +storage.remount("/", readonly=False) + +# Now write a small new file. This updates FAT metadata and directory +# entries that share an erase page with original.txt, exercising the +# read-modify-write cycle on the cached page. +with open("/small.txt", "w") as f: + f.write("tiny") + +# Read back original to check it survived. +with open("/original.txt", "r") as f: + readback = f.read() +if readback == original_data: + print("existing_data_ok") +else: + print(f"MISMATCH: got {len(readback)} bytes") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EXISTING_DATA_CODE}) +@pytest.mark.flash_config(erase_block_size=262144, total_size=4 * 1024 * 1024) +def test_flash_256k_existing_data_survives(circuitpython): + """Test that existing data in an erase page survives when new data is written. + + With 256KB erase blocks (512 blocks per page), writing to any block in + the page triggers an erase-rewrite of the entire page. Existing blocks + must be preserved through the read-modify-write cycle. + """ + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "existing_data_ok" in output + + # Verify both files survived on the actual flash image. + original = read_file_from_flash(circuitpython.flash_file, "original.txt") + assert original == "A" * 4000, f"original.txt corrupted: got {len(original)} bytes" + + small = read_file_from_flash(circuitpython.flash_file, "small.txt") + assert small == "tiny" + + +OVERWRITE_CODE = """\ +import storage +storage.remount("/", readonly=False) +with open("/overwrite.txt", "w") as f: + f.write("first version") +with open("/overwrite.txt", "w") as f: + f.write("second version") +print("overwrite_ok") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": OVERWRITE_CODE}) +@pytest.mark.flash_config(erase_block_size=262144, total_size=4 * 1024 * 1024) +def test_flash_256k_overwrite(circuitpython): + """Test overwriting a file with 256KB erase blocks to exercise erase-rewrite cycle.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "overwrite_ok" in output + + content = read_file_from_flash(circuitpython.flash_file, "overwrite.txt") + assert content == "second version" diff --git a/ports/zephyr-cp/tests/test_getpass.py b/ports/zephyr-cp/tests/test_getpass.py new file mode 100644 index 00000000000..541d91078b3 --- /dev/null +++ b/ports/zephyr-cp/tests/test_getpass.py @@ -0,0 +1,182 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the getpass core module.""" + +import pytest + + +DEFAULT_PROMPT_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass() +print(f"got: {pw}") +print(f"length: {len(pw)}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": DEFAULT_PROMPT_CODE}) +def test_getpass_default_prompt(circuitpython): + """getpass() with no args prints 'Password: ' and returns the typed string.""" + circuitpython.serial.wait_for("ready") + circuitpython.serial.wait_for("Password:") + circuitpython.serial.write("hunter2\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "Password:" in output + assert "got: hunter2" in output + assert "length: 7" in output + assert "done" in output + + +CUSTOM_PROMPT_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass("Enter secret: ") +print(f"got: {pw}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CUSTOM_PROMPT_CODE}) +def test_getpass_custom_prompt(circuitpython): + """A user-supplied prompt string is written before reading input.""" + circuitpython.serial.wait_for("Enter secret:") + circuitpython.serial.write("s3cr3t\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "Enter secret:" in output + assert "got: s3cr3t" in output + assert "done" in output + + +NO_ECHO_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass("Pwd: ") +print("---boundary---") +print(f"got: {pw}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": NO_ECHO_CODE}) +def test_getpass_does_not_echo(circuitpython): + """Characters typed during getpass are not echoed back to the terminal.""" + circuitpython.serial.wait_for("Pwd:") + secret = "TopSecret123" + circuitpython.serial.write(secret + "\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + # Split around the boundary: nothing typed should appear before it, + # but the printed value appears after. + pre, _, post = output.partition("---boundary---") + assert secret not in pre + assert f"got: {secret}" in post + assert "done" in post + + +BACKSPACE_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass("P: ") +print(f"got: {pw}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BACKSPACE_CODE}) +def test_getpass_backspace(circuitpython): + """Backspace (0x7f) removes the previous character from the buffer.""" + circuitpython.serial.wait_for("P:") + # Type "abcX", then backspace, then "d" -> "abcd" + circuitpython.serial.write("abcX\x7fd\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "got: abcd" in output + assert "done" in output + + +CTRL_C_CODE = """\ +import getpass + +print("ready") +try: + getpass.getpass("Pwd: ") + print("no exception") +except KeyboardInterrupt: + print("interrupted") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CTRL_C_CODE}) +def test_getpass_ctrl_c_raises_keyboard_interrupt(circuitpython): + """Sending Ctrl+C while getpass is reading raises KeyboardInterrupt.""" + circuitpython.serial.wait_for("Pwd:") + circuitpython.serial.write("\x03") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "interrupted" in output + assert "no exception" not in output + assert "done" in output + + +CTRL_D_EMPTY_CODE = """\ +import getpass + +print("ready") +try: + getpass.getpass("Pwd: ") + print("no exception") +except EOFError: + print("eof") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CTRL_D_EMPTY_CODE}) +def test_getpass_ctrl_d_empty_raises_eof(circuitpython): + """Ctrl+D with an empty buffer raises EOFError.""" + circuitpython.serial.wait_for("Pwd:") + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "eof" in output + assert "no exception" not in output + assert "done" in output + + +EMPTY_INPUT_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass("Pwd: ") +print(f"length: {len(pw)}") +print(f"empty: {pw == ''}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EMPTY_INPUT_CODE}) +def test_getpass_empty_input(circuitpython): + """Pressing return immediately yields an empty string.""" + circuitpython.serial.wait_for("Pwd:") + circuitpython.serial.write("\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "length: 0" in output + assert "empty: True" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_hashlib.py b/ports/zephyr-cp/tests/test_hashlib.py new file mode 100644 index 00000000000..94463ba1e99 --- /dev/null +++ b/ports/zephyr-cp/tests/test_hashlib.py @@ -0,0 +1,152 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the hashlib module against CPython hashlib.""" + +import hashlib + +import pytest + + +SHORT_DATA = b"CircuitPython!" +CHUNK_A = b"Hello, " +CHUNK_B = b"CircuitPython world!" +LONG_DATA = b"The quick brown fox jumps over the lazy dog." * 64 + + +SHA256_CODE = """\ +import hashlib + +h = hashlib.new("sha256", b"CircuitPython!") +print(f"digest_size: {h.digest_size}") +print(f"digest_hex: {h.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": SHA256_CODE}) +def test_hashlib_sha256_basic(circuitpython): + """sha256 digest on a small buffer matches CPython hashlib.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + expected = hashlib.sha256(SHORT_DATA).hexdigest() + assert "digest_size: 32" in output + assert f"digest_hex: {expected}" in output + assert "done" in output + + +SHA1_CODE = """\ +import hashlib + +h = hashlib.new("sha1", b"CircuitPython!") +print(f"digest_size: {h.digest_size}") +print(f"digest_hex: {h.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": SHA1_CODE}) +def test_hashlib_sha1_basic(circuitpython): + """sha1 digest on a small buffer matches CPython hashlib.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + expected = hashlib.sha1(SHORT_DATA).hexdigest() + assert "digest_size: 20" in output + assert f"digest_hex: {expected}" in output + assert "done" in output + + +UPDATE_CODE = """\ +import hashlib + +h = hashlib.new("sha256") +h.update(b"Hello, ") +h.update(b"CircuitPython world!") +print(f"chunked_hex: {h.digest().hex()}") + +h2 = hashlib.new("sha256", b"Hello, CircuitPython world!") +print(f"oneshot_hex: {h2.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": UPDATE_CODE}) +def test_hashlib_sha256_update_chunks(circuitpython): + """Multiple update() calls produce the same digest as a single buffer, and match CPython.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + expected = hashlib.sha256(CHUNK_A + CHUNK_B).hexdigest() + assert f"chunked_hex: {expected}" in output + assert f"oneshot_hex: {expected}" in output + assert "done" in output + + +LONG_CODE = """\ +import hashlib + +data = b"The quick brown fox jumps over the lazy dog." * 64 +h = hashlib.new("sha256", data) +print(f"sha256_hex: {h.digest().hex()}") + +h1 = hashlib.new("sha1", data) +print(f"sha1_hex: {h1.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": LONG_CODE}) +def test_hashlib_long_input(circuitpython): + """Digests of a multi-block input match CPython for both sha1 and sha256.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"sha256_hex: {hashlib.sha256(LONG_DATA).hexdigest()}" in output + assert f"sha1_hex: {hashlib.sha1(LONG_DATA).hexdigest()}" in output + assert "done" in output + + +EMPTY_CODE = """\ +import hashlib + +h = hashlib.new("sha256", b"") +print(f"empty256: {h.digest().hex()}") + +h = hashlib.new("sha1", b"") +print(f"empty1: {h.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EMPTY_CODE}) +def test_hashlib_empty_input(circuitpython): + """Empty-input digests match CPython well-known values.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"empty256: {hashlib.sha256(b'').hexdigest()}" in output + assert f"empty1: {hashlib.sha1(b'').hexdigest()}" in output + assert "done" in output + + +BAD_ALGO_CODE = """\ +import hashlib + +try: + hashlib.new("md5", b"data") +except ValueError: + print("bad_algo: ValueError") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BAD_ALGO_CODE}) +def test_hashlib_unsupported_algorithm(circuitpython): + """Unsupported algorithm names raise ValueError.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "bad_algo: ValueError" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_i2c.py b/ports/zephyr-cp/tests/test_i2c.py new file mode 100644 index 00000000000..ec5229faa2f --- /dev/null +++ b/ports/zephyr-cp/tests/test_i2c.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test I2C functionality on native_sim.""" + +import pytest + +I2C_SCAN_CODE = """\ +import board + +i2c = board.I2C() +while not i2c.try_lock(): + pass +devices = i2c.scan() +print(f"I2C devices: {[hex(d) for d in devices]}") +i2c.unlock() +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": I2C_SCAN_CODE}) +def test_i2c_scan(circuitpython): + """Test I2C bus scanning finds emulated devices. + + The AT24 EEPROM emulator responds to zero-length probe writes, + so it should appear in scan results at address 0x50. + """ + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "I2C devices:" in output + # AT24 EEPROM should be at address 0x50 + assert "0x50" in output + assert "done" in output + + +AT24_READ_CODE = """\ +import board + +i2c = board.I2C() +while not i2c.try_lock(): + pass + +# AT24 EEPROM at address 0x50 +AT24_ADDR = 0x50 + +# Read first byte from address 0 +result = bytearray(1) +try: + i2c.writeto_then_readfrom(AT24_ADDR, bytes([0x00]), result) + value = result[0] + print(f"AT24 byte 0: 0x{value:02X}") + # Fresh EEPROM should be 0xFF + if value == 0xFF: + print("eeprom_valid") + else: + print(f"unexpected value: expected 0xFF, got 0x{value:02X}") +except OSError as e: + print(f"I2C error: {e}") + +i2c.unlock() +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": AT24_READ_CODE}) +def test_i2c_at24_read(circuitpython): + """Test reading from AT24 EEPROM emulator.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "AT24 byte 0: 0xFF" in output + assert "eeprom_valid" in output + assert "done" in output + + +@pytest.mark.circuitpy_drive({"code.py": I2C_SCAN_CODE}) +@pytest.mark.disable_i2c_devices("eeprom@50") +def test_i2c_device_disabled(circuitpython): + """Test that disabled I2C device doesn't appear in scan.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "I2C devices:" in output + # AT24 at 0x50 should NOT appear when disabled + assert "0x50" not in output + assert "done" in output + + +@pytest.mark.circuitpy_drive({"code.py": AT24_READ_CODE}) +@pytest.mark.disable_i2c_devices("eeprom@50") +def test_i2c_device_disabled_communication_fails(circuitpython): + """Test that communication with disabled I2C device fails.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + # Should get an I2C error when trying to communicate + assert "I2C error" in output + assert "eeprom_valid" not in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_msgpack.py b/ports/zephyr-cp/tests/test_msgpack.py new file mode 100644 index 00000000000..09bed35209c --- /dev/null +++ b/ports/zephyr-cp/tests/test_msgpack.py @@ -0,0 +1,137 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the msgpack module.""" + +import pytest + + +ROUNDTRIP_CODE = """\ +import msgpack +from io import BytesIO + +obj = {"list": [True, False, None, 1, 3.125], "str": "blah"} +b = BytesIO() +msgpack.pack(obj, b) +encoded = b.getvalue() +print(f"encoded_len: {len(encoded)}") +print(f"encoded_hex: {encoded.hex()}") + +b.seek(0) +decoded = msgpack.unpack(b) +print(f"decoded: {decoded}") +print(f"match: {decoded == obj}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": ROUNDTRIP_CODE}) +def test_msgpack_roundtrip(circuitpython): + """Pack and unpack a dict containing the basic msgpack types.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "match: True" in output + assert "done" in output + + +USE_LIST_CODE = """\ +import msgpack +from io import BytesIO + +b = BytesIO() +msgpack.pack([1, 2, 3], b) + +b.seek(0) +as_list = msgpack.unpack(b) +print(f"as_list: {as_list} type={type(as_list).__name__}") + +b.seek(0) +as_tuple = msgpack.unpack(b, use_list=False) +print(f"as_tuple: {as_tuple} type={type(as_tuple).__name__}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": USE_LIST_CODE}) +def test_msgpack_use_list(circuitpython): + """use_list=False should return a tuple instead of a list.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "as_list: [1, 2, 3] type=list" in output + assert "as_tuple: (1, 2, 3) type=tuple" in output + assert "done" in output + + +EXTTYPE_CODE = """\ +from msgpack import pack, unpack, ExtType +from io import BytesIO + +class MyClass: + def __init__(self, val): + self.value = val + +data = MyClass(b"my_value") + +def encoder(obj): + if isinstance(obj, MyClass): + return ExtType(1, obj.value) + return f"no encoder for {obj}" + +def decoder(code, data): + if code == 1: + return MyClass(data) + return f"no decoder for type {code}" + +buf = BytesIO() +pack(data, buf, default=encoder) +buf.seek(0) +decoded = unpack(buf, ext_hook=decoder) +print(f"decoded_type: {type(decoded).__name__}") +print(f"decoded_value: {decoded.value}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EXTTYPE_CODE}) +def test_msgpack_exttype(circuitpython): + """ExtType with a custom encoder/decoder should round-trip.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "decoded_type: MyClass" in output + assert "decoded_value: b'my_value'" in output + assert "done" in output + + +EXTTYPE_PROPS_CODE = """\ +from msgpack import ExtType + +e = ExtType(5, b"hello") +print(f"code: {e.code}") +print(f"data: {e.data}") + +e.code = 10 +print(f"new_code: {e.code}") + +try: + ExtType(128, b"x") +except (ValueError, OverflowError) as ex: + print(f"range_error: {type(ex).__name__}") + +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EXTTYPE_PROPS_CODE}) +def test_msgpack_exttype_properties(circuitpython): + """ExtType exposes code/data as read/write properties and rejects out-of-range codes.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "code: 5" in output + assert "data: b'hello'" in output + assert "new_code: 10" in output + assert "range_error:" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_nvm.py b/ports/zephyr-cp/tests/test_nvm.py new file mode 100644 index 00000000000..910cf6eb052 --- /dev/null +++ b/ports/zephyr-cp/tests/test_nvm.py @@ -0,0 +1,73 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test NVM functionality on native_sim.""" + +import pytest + + +NVM_BASIC_CODE = """\ +import microcontroller + +nvm = microcontroller.nvm +print(f"nvm length: {len(nvm)}") + +# Write some bytes +nvm[0] = 42 +nvm[1] = 99 +print(f"nvm[0]: {nvm[0]}") +print(f"nvm[1]: {nvm[1]}") + +# Write a slice +nvm[2:5] = b"\\x01\\x02\\x03" +print(f"nvm[2:5]: {list(nvm[2:5])}") + +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": NVM_BASIC_CODE}) +def test_nvm_read_write(circuitpython): + """Test basic NVM read and write operations.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "nvm length: 8192" in output + assert "nvm[0]: 42" in output + assert "nvm[1]: 99" in output + assert "nvm[2:5]: [1, 2, 3]" in output + assert "done" in output + + +NVM_PERSIST_CODE = """\ +import microcontroller + +nvm = microcontroller.nvm +value = nvm[0] +print(f"nvm[0]: {value}") + +if value == 255: + # First run: write a marker + nvm[0] = 123 + print("wrote marker") +else: + print(f"marker found: {value}") + +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": NVM_PERSIST_CODE}) +@pytest.mark.port_resets(3) +def test_nvm_persists_across_reload(circuitpython): + """Test that NVM data persists across soft reloads.""" + circuitpython.serial.wait_for("wrote marker") + # Trigger soft reload + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "nvm[0]: 255" in output + assert "wrote marker" in output + assert "marker found: 123" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_reset.py b/ports/zephyr-cp/tests/test_reset.py new file mode 100644 index 00000000000..af64cee726d --- /dev/null +++ b/ports/zephyr-cp/tests/test_reset.py @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test that a plain microcontroller.reset() reboots back into CircuitPython. + +This is like the safe-mode test (test_saved_word.py) but without changing the +run mode: no sentinel is armed, so the reboot should be a normal boot that +runs code.py again instead of entering safe mode. +""" + +import pytest + + +RESET_CODE = """\ +import microcontroller +reason = microcontroller.cpu.reset_reason +print("reset reason:", reason) +if reason == microcontroller.ResetReason.POWER_ON: + print("resetting") + microcontroller.reset() +else: + print("not resetting") +""" + + +@pytest.mark.circuitpy_drive({"code.py": RESET_CODE}) +@pytest.mark.duration(30) +@pytest.mark.port_resets(4) # Two startups and two code.py +def test_plain_reset_reboots_into_circuitpython(circuitpython): + """microcontroller.reset() reboots into code.py and reports a software reset.""" + circuitpython.serial.wait_for("resetting", timeout=30) + + assert circuitpython.reconnect_serial(timeout=30), "simulator did not reboot" + + circuitpython.serial.wait_for("not resetting", timeout=30) + + all_output = circuitpython.serial.all_output + assert "reset reason: microcontroller.ResetReason.SOFTWARE" in all_output + assert "Running in safe mode" not in all_output diff --git a/ports/zephyr-cp/tests/test_rotaryio.py b/ports/zephyr-cp/tests/test_rotaryio.py new file mode 100644 index 00000000000..e9a5c1913cb --- /dev/null +++ b/ports/zephyr-cp/tests/test_rotaryio.py @@ -0,0 +1,132 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries LLC +# SPDX-License-Identifier: MIT + +"""Test rotaryio functionality on native_sim.""" + +import pytest + + +ROTARY_CODE_5S = """\ +import time +import microcontroller +import rotaryio + +encoder = rotaryio.IncrementalEncoder(microcontroller.pin.P_01, microcontroller.pin.P_02) + +time.sleep(5.0) # Sleep long enough for trace events to complete +print(f"position={encoder.position}") +print("done") +""" + + +ROTARY_CODE_7S = """\ +import time +import microcontroller +import rotaryio + +encoder = rotaryio.IncrementalEncoder(microcontroller.pin.P_01, microcontroller.pin.P_02) + +time.sleep(7.0) # Sleep long enough for trace events to complete +print(f"position={encoder.position}") +print("done") +""" + + +CLOCKWISE_TRACE = { + "gpio_emul.01": [ + (4_000_000_000, 0), # 4.0s: initial state (low) + (4_100_000_000, 1), # 4.1s: A goes high (A leads) + (4_300_000_000, 0), # 4.3s: A goes low + ], + "gpio_emul.02": [ + (4_000_000_000, 0), # 4.0s: initial state (low) + (4_200_000_000, 1), # 4.2s: B goes high (B follows) + (4_400_000_000, 0), # 4.4s: B goes low + ], +} + +COUNTERCLOCKWISE_TRACE = { + "gpio_emul.01": [ + (4_000_000_000, 0), # 4.0s: initial state (low) + (4_200_000_000, 1), # 4.2s: A goes high (A follows) + (4_400_000_000, 0), # 4.4s: A goes low + ], + "gpio_emul.02": [ + (4_000_000_000, 0), # 4.0s: initial state (low) + (4_100_000_000, 1), # 4.1s: B goes high (B leads) + (4_300_000_000, 0), # 4.3s: B goes low + ], +} + +BOTH_DIRECTIONS_TRACE = { + "gpio_emul.01": [ + (4_000_000_000, 0), # Initial state + # First clockwise detent + (4_100_000_000, 1), # A rises (leads) + (4_300_000_000, 0), # A falls + # Second clockwise detent + (4_500_000_000, 1), # A rises (leads) + (4_700_000_000, 0), # A falls + # First counter-clockwise detent + (5_000_000_000, 1), # A rises (follows) + (5_200_000_000, 0), # A falls + # Second counter-clockwise detent + (5_400_000_000, 1), # A rises (follows) + (5_600_000_000, 0), # A falls + # Third counter-clockwise detent + (5_800_000_000, 1), # A rises (follows) + (6_000_000_000, 0), # A falls + ], + "gpio_emul.02": [ + (4_000_000_000, 0), # Initial state + # First clockwise detent + (4_200_000_000, 1), # B rises (follows) + (4_400_000_000, 0), # B falls + # Second clockwise detent + (4_600_000_000, 1), # B rises (follows) + (4_800_000_000, 0), # B falls + # First counter-clockwise detent + (4_900_000_000, 1), # B rises (leads) + (5_100_000_000, 0), # B falls + # Second counter-clockwise detent + (5_300_000_000, 1), # B rises (leads) + (5_500_000_000, 0), # B falls + # Third counter-clockwise detent + (5_700_000_000, 1), # B rises (leads) + (5_900_000_000, 0), # B falls + ], +} + + +@pytest.mark.circuitpy_drive({"code.py": ROTARY_CODE_5S}) +@pytest.mark.input_trace(CLOCKWISE_TRACE) +def test_rotaryio_incrementalencoder_clockwise(circuitpython): + """Test clockwise rotation increments position.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "position=1" in output + assert "done" in output + + +@pytest.mark.circuitpy_drive({"code.py": ROTARY_CODE_5S}) +@pytest.mark.input_trace(COUNTERCLOCKWISE_TRACE) +def test_rotaryio_incrementalencoder_counterclockwise(circuitpython): + """Test counter-clockwise rotation decrements position.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "position=-1" in output + assert "done" in output + + +@pytest.mark.duration(12.0) +@pytest.mark.circuitpy_drive({"code.py": ROTARY_CODE_7S}) +@pytest.mark.input_trace(BOTH_DIRECTIONS_TRACE) +def test_rotaryio_incrementalencoder_both_directions(circuitpython): + """Test rotation in both directions: 2 clockwise, then 3 counter-clockwise.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "position=-1" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_saved_word.py b/ports/zephyr-cp/tests/test_saved_word.py new file mode 100644 index 00000000000..ac615f87247 --- /dev/null +++ b/ports/zephyr-cp/tests/test_saved_word.py @@ -0,0 +1,35 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test that the safe-mode saved word survives a hard reboot on native_sim/bsim.""" + +import pytest + + +SAFE_MODE_RESET_CODE = """\ +import microcontroller +if microcontroller.cpu.reset_reason == microcontroller.ResetReason.POWER_ON: + microcontroller.on_next_reset(microcontroller.RunMode.SAFE_MODE) + print("resetting") + microcontroller.reset() +else: + print("not resetting") +""" + + +@pytest.mark.circuitpy_drive({"code.py": SAFE_MODE_RESET_CODE}) +@pytest.mark.duration(30) +@pytest.mark.port_resets(4) +def test_saved_word_survives_reboot_into_safe_mode(circuitpython): + """The saved word persists across a hard reboot and triggers safe mode.""" + circuitpython.serial.wait_for("resetting", timeout=30) + + # microcontroller.reset() re-execs the process; the UART PTY is O_CLOEXEC so + # a new one is opened after reboot. Reconnect to it. + assert circuitpython.reconnect_serial(timeout=30), "simulator did not reboot" + + # The next boot restores the saved word (the SAFE_MODE sentinel) and enters + # safe mode instead of running code.py. + circuitpython.serial.wait_for("Running in safe mode", timeout=30) + + assert "Running in safe mode" in circuitpython.serial.all_output diff --git a/ports/zephyr-cp/tests/test_storage.py b/ports/zephyr-cp/tests/test_storage.py new file mode 100644 index 00000000000..8805a582b6b --- /dev/null +++ b/ports/zephyr-cp/tests/test_storage.py @@ -0,0 +1,162 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the `storage` core module on native_sim.""" + +import pytest + + +REMOUNT_READWRITE_CODE = """\ +import storage +storage.remount("/", readonly=False) +with open("/rw.txt", "w") as f: + f.write("writable") +with open("/rw.txt", "r") as f: + print(f"content: {f.read()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": REMOUNT_READWRITE_CODE}) +def test_storage_remount_readwrite(circuitpython): + """remount with readonly=False allows writes to /.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "content: writable" in output + assert "done" in output + + +REMOUNT_READONLY_CODE = """\ +import storage +storage.remount("/", readonly=True) +try: + with open("/should_fail.txt", "w") as f: + f.write("nope") + print("unexpected: write succeeded") +except OSError as e: + print(f"caught OSError: errno={e.errno}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": REMOUNT_READONLY_CODE}) +def test_storage_remount_readonly_blocks_writes(circuitpython): + """remount with readonly=True prevents writes to /.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "caught OSError" in output + assert "unexpected: write succeeded" not in output + assert "done" in output + + +GETMOUNT_CODE = """\ +import storage +mount = storage.getmount("/") +print(f"type: {type(mount).__name__}") +print(f"readonly: {mount.readonly}") +# label attribute should be accessible +print(f"label: {mount.label!r}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": GETMOUNT_CODE}) +def test_storage_getmount(circuitpython): + """getmount('/') returns the VfsFat object for the root mount.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "type: VfsFat" in output + assert "readonly:" in output + assert "label:" in output + assert "done" in output + + +GETMOUNT_MISSING_CODE = """\ +import storage +try: + storage.getmount("/does_not_exist") + print("unexpected: getmount succeeded") +except OSError as e: + print(f"caught OSError: errno={e.errno}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": GETMOUNT_MISSING_CODE}) +def test_storage_getmount_missing(circuitpython): + """getmount on an unmounted path raises OSError.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "caught OSError" in output + assert "unexpected: getmount succeeded" not in output + assert "done" in output + + +REMOUNT_PERSISTS_CODE = """\ +import storage +storage.remount("/", readonly=False) +with open("/persist.txt", "w") as f: + f.write("across-reload") +print("wrote persist.txt") +""" + +REMOUNT_PERSISTS_READ_CODE = """\ +with open("/persist.txt", "r") as f: + print(f"readback: {f.read()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": REMOUNT_PERSISTS_CODE}) +@pytest.mark.port_resets(3) +def test_storage_remount_persists_across_reload(circuitpython): + """Data written after remount(readonly=False) persists across soft reload.""" + circuitpython.serial.wait_for("wrote persist.txt") + # Replace code.py via raw REPL-style approach: write new file then reload. + # Simpler: just trigger a soft reload and check the file is still there. + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "wrote persist.txt" in output + + +LABEL_CODE = """\ +import storage +storage.remount("/", readonly=False) +mount = storage.getmount("/") +mount.label = "CIRCUITPY" +print(f"label: {mount.label!r}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": LABEL_CODE}) +def test_storage_set_label(circuitpython): + """VfsFat.label can be set when mounted read-write.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "label: 'CIRCUITPY'" in output + assert "done" in output + + +UMOUNT_MISSING_CODE = """\ +import storage +# Unmounting an unmounted path should raise. +try: + storage.umount("/not_mounted") + print("unexpected: umount succeeded") +except OSError as e: + print(f"umount OSError: errno={e.errno}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": UMOUNT_MISSING_CODE}) +def test_storage_umount_missing(circuitpython): + """umount on an unmounted path raises OSError.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "umount OSError" in output + assert "unexpected:" not in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_web_workflow.py b/ports/zephyr-cp/tests/test_web_workflow.py new file mode 100644 index 00000000000..d3a00782a33 --- /dev/null +++ b/ports/zephyr-cp/tests/test_web_workflow.py @@ -0,0 +1,142 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Tests for web workflow on native_sim.""" + +from __future__ import annotations + +import json +import re + +import pytest +import requests + + +pytestmark = pytest.mark.native_sim_rt + +WEB_WORKFLOW_PORT = 8090 +WEB_WORKFLOW_PASSWORD = "testpass" + +WEB_WORKFLOW_CODE = """\ +import time + +# Keep the VM alive while the web workflow starts. +time.sleep(3) +""" + +WEB_WORKFLOW_UPDATED_CODE = """\ +print("updated") +""" + +WEB_WORKFLOW_SETTINGS = f"""\ +CIRCUITPY_WEB_API_PASSWORD="{WEB_WORKFLOW_PASSWORD}" +CIRCUITPY_WEB_API_PORT={WEB_WORKFLOW_PORT} +""" + +WEB_WORKFLOW_SETTINGS_PORT_80 = f"""\ +CIRCUITPY_WEB_API_PASSWORD="{WEB_WORKFLOW_PASSWORD}" +CIRCUITPY_WEB_API_PORT=80 +""" + +WEB_WORKFLOW_BOOT = """\ +import storage + +storage.remount("/", readonly=False) +""" + + +@pytest.mark.circuitpy_drive( + { + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS, + } +) +def test_web_workflow_hostnetwork(circuitpython): + """Ensure web workflow responds over hostnetwork.""" + circuitpython.serial.wait_for(f"127.0.0.1:{WEB_WORKFLOW_PORT}") + response = requests.get(f"http://127.0.0.1:{WEB_WORKFLOW_PORT}/edit/", timeout=1.0) + + assert response.status_code == 401 + + +@pytest.mark.circuitpy_drive( + { + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS, + } +) +def test_web_workflow_version_json_hostnetwork_ip_and_port(circuitpython): + """Ensure /cp/version.json reports hostnetwork endpoint with configured port.""" + circuitpython.serial.wait_for(f"127.0.0.1:{WEB_WORKFLOW_PORT}") + response = requests.get( + f"http://127.0.0.1:{WEB_WORKFLOW_PORT}/cp/version.json", + auth=("", WEB_WORKFLOW_PASSWORD), + timeout=1.0, + ) + + assert response.status_code == 200 + + payload = json.loads(response.text) + assert payload["ip"] == "127.0.0.1" + assert payload["port"] == WEB_WORKFLOW_PORT + + +@pytest.mark.circuitpy_drive( + { + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS, + } +) +def test_web_workflow_status_line_hostnetwork_non_default_port(circuitpython): + """Status line should include hostnetwork IP and non-default port.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + + # Remove ANSI control sequences before matching. + output = re.sub(r"\x1b\[[0-9;]*[A-Za-z]", "", output) + assert "127.0.0.1:8090" in output + + +@pytest.mark.circuitpy_drive( + { + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS_PORT_80, + } +) +def test_web_workflow_status_line_hostnetwork_default_port(circuitpython): + """Status line should show IP without :80 for default HTTP port.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + + output = re.sub(r"\x1b\[[0-9;]*[A-Za-z]", "", output) + assert "127.0.0.1" in output + assert "127.0.0.1:80" not in output + + +@pytest.mark.circuitpy_drive( + { + "boot.py": WEB_WORKFLOW_BOOT, + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS, + } +) +def test_web_workflow_write_code_py_remount(circuitpython): + """Ensure web workflow can update code.py after remounting.""" + circuitpython.serial.wait_for(f"127.0.0.1:{WEB_WORKFLOW_PORT}") + body = WEB_WORKFLOW_UPDATED_CODE.encode("utf-8") + + response = requests.put( + f"http://127.0.0.1:{WEB_WORKFLOW_PORT}/fs/code.py", + auth=("", WEB_WORKFLOW_PASSWORD), + data=body, + timeout=1.0, + ) + assert response.status_code in (201, 204) + + response = requests.get( + f"http://127.0.0.1:{WEB_WORKFLOW_PORT}/fs/code.py", + auth=("", WEB_WORKFLOW_PASSWORD), + timeout=1.0, + ) + assert response.status_code == 200 + assert WEB_WORKFLOW_UPDATED_CODE in response.text diff --git a/ports/zephyr-cp/tests/test_zlib.py b/ports/zephyr-cp/tests/test_zlib.py new file mode 100644 index 00000000000..bd89d8e1c25 --- /dev/null +++ b/ports/zephyr-cp/tests/test_zlib.py @@ -0,0 +1,110 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the zlib module against CPython zlib. + +CircuitPython's zlib only implements ``decompress``; these tests compress data +with CPython and verify the zephyr-cp port decodes it back to the same bytes. +""" + +import zlib + +import pytest + + +PLAIN_TEXT = b"CircuitPython running on Zephyr says hello!" +REPEATED_TEXT = b"The quick brown fox jumps over the lazy dog. " * 32 +BINARY_BLOB = bytes(range(256)) * 4 + + +def _make_code(compressed: bytes, wbits: int, expected_len: int) -> str: + return ( + "import zlib\n" + f"compressed = {compressed!r}\n" + f"out = zlib.decompress(compressed, {wbits})\n" + f'print(f"out_len: {{len(out)}}")\n' + f'print(f"expected_len: {expected_len}")\n' + 'print(f"out_hex: {out.hex()}")\n' + 'print("done")\n' + ) + + +ZLIB_COMPRESSED = zlib.compress(PLAIN_TEXT) +ZLIB_CODE = _make_code(ZLIB_COMPRESSED, wbits=15, expected_len=len(PLAIN_TEXT)) + + +@pytest.mark.circuitpy_drive({"code.py": ZLIB_CODE}) +def test_zlib_decompress_zlib_format(circuitpython): + """Data produced by CPython zlib.compress() round-trips through CircuitPython zlib.decompress().""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(PLAIN_TEXT)}" in output + assert f"out_hex: {PLAIN_TEXT.hex()}" in output + assert "done" in output + + +REPEATED_COMPRESSED = zlib.compress(REPEATED_TEXT) +REPEATED_CODE = _make_code(REPEATED_COMPRESSED, wbits=15, expected_len=len(REPEATED_TEXT)) + + +@pytest.mark.circuitpy_drive({"code.py": REPEATED_CODE}) +def test_zlib_decompress_repeated(circuitpython): + """Highly-compressible repeated input decompresses correctly (back-references).""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(REPEATED_TEXT)}" in output + # Repeated text has many back-references; shrinks a lot. + assert len(REPEATED_COMPRESSED) < len(REPEATED_TEXT) // 4 + assert f"out_hex: {REPEATED_TEXT.hex()}" in output + assert "done" in output + + +BINARY_COMPRESSED = zlib.compress(BINARY_BLOB) +BINARY_CODE = _make_code(BINARY_COMPRESSED, wbits=15, expected_len=len(BINARY_BLOB)) + + +@pytest.mark.circuitpy_drive({"code.py": BINARY_CODE}) +def test_zlib_decompress_binary_bytes(circuitpython): + """Decompression preserves every byte value (0x00-0xFF).""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(BINARY_BLOB)}" in output + assert f"out_hex: {BINARY_BLOB.hex()}" in output + assert "done" in output + + +# Raw DEFLATE stream (no zlib header/trailer). +_raw_compressor = zlib.compressobj(wbits=-15) +RAW_COMPRESSED = _raw_compressor.compress(PLAIN_TEXT) + _raw_compressor.flush() +RAW_CODE = _make_code(RAW_COMPRESSED, wbits=-15, expected_len=len(PLAIN_TEXT)) + + +@pytest.mark.circuitpy_drive({"code.py": RAW_CODE}) +def test_zlib_decompress_raw_deflate(circuitpython): + """Raw DEFLATE streams (wbits=-15) decompress to the original bytes.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(PLAIN_TEXT)}" in output + assert f"out_hex: {PLAIN_TEXT.hex()}" in output + assert "done" in output + + +# Gzip wrapper (wbits=31). +_gzip_compressor = zlib.compressobj(wbits=31) +GZIP_COMPRESSED = _gzip_compressor.compress(PLAIN_TEXT) + _gzip_compressor.flush() +GZIP_CODE = _make_code(GZIP_COMPRESSED, wbits=31, expected_len=len(PLAIN_TEXT)) + + +@pytest.mark.circuitpy_drive({"code.py": GZIP_CODE}) +def test_zlib_decompress_gzip_format(circuitpython): + """Gzip-wrapped streams (wbits=31) decompress to the original bytes.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(PLAIN_TEXT)}" in output + assert f"out_hex: {PLAIN_TEXT.hex()}" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/zephyr_display/README.md b/ports/zephyr-cp/tests/zephyr_display/README.md new file mode 100644 index 00000000000..6b502021543 --- /dev/null +++ b/ports/zephyr-cp/tests/zephyr_display/README.md @@ -0,0 +1,45 @@ +# Zephyr Display Golden Tests + +This directory contains native_sim golden-image tests for the Zephyr-specific `zephyr_display` path. + +## What is tested + +- `board.DISPLAY` is present and usable. +- CircuitPython terminal/console tilegrids are attached to the default display root group. +- Deterministic console terminal output matches a checked-in golden image. +- `zephyr_display` pixel format constants are exposed. +- `displayio` rendering produces expected stripe colors at sampled pixel locations. + +## Files + +- `test_zephyr_display.py` – pytest tests. +- `golden/terminal_console_output_320x240.png` – console terminal output golden reference image. + +## How capture works + +These tests use trace-driven SDL display capture triggered by Perfetto instant events: + +- `--input-trace=` provides a Perfetto trace containing a `"display_capture"` track + with instant events at the desired capture timestamps. +- `--display_capture_png=` specifies the output PNG pattern (may contain `%d` for + a sequence number). +- `--display_headless` runs SDL in headless/hidden-window mode (always enabled for native_sim tests). + +The test harness sets these flags automatically when tests use +`@pytest.mark.display(capture_times_ns=[...])`. + +## Regenerating the console golden image + +```bash +rm -rf /tmp/zephyr-display-golden +pytest -q ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py::test_console_output_golden \ + --basetemp=/tmp/zephyr-display-golden +cp /tmp/zephyr-display-golden/test_console_output_golden0/frame_0.png \ + ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.png +``` + +## Running the tests + +```bash +pytest -q ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py +``` diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240.png new file mode 100644 index 00000000000..5739b8ee156 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_AL_88.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_AL_88.png new file mode 100644 index 00000000000..6bdb72b802c Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_AL_88.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_ARGB_8888.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_ARGB_8888.png new file mode 100644 index 00000000000..90b422792db Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_ARGB_8888.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_BGR_565.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_BGR_565.png new file mode 100644 index 00000000000..5739b8ee156 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_BGR_565.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_L_8.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_L_8.png new file mode 100644 index 00000000000..6bdb72b802c Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_L_8.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_MONO01.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_MONO01.png new file mode 100644 index 00000000000..b22de4417ab Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_MONO01.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_MONO10.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_MONO10.png new file mode 100644 index 00000000000..b22de4417ab Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_MONO10.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_565.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_565.png new file mode 100644 index 00000000000..5739b8ee156 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_565.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_888.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_888.png new file mode 100644 index 00000000000..c4301da47c5 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_888.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_00_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_00_320x240.png new file mode 100644 index 00000000000..8f7fc051365 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_00_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_01_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_01_320x240.png new file mode 100644 index 00000000000..67d17856c7d Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_01_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_02_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_02_320x240.png new file mode 100644 index 00000000000..99c832b68ec Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_02_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_03_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_03_320x240.png new file mode 100644 index 00000000000..38f403a2ad3 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_03_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_04_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_04_320x240.png new file mode 100644 index 00000000000..2a6649a0014 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_04_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_05_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_05_320x240.png new file mode 100644 index 00000000000..507a9290937 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_05_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_06_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_06_320x240.png new file mode 100644 index 00000000000..217b98f680b Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_06_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_07_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_07_320x240.png new file mode 100644 index 00000000000..507a9290937 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_07_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_08_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_08_320x240.png new file mode 100644 index 00000000000..2a6649a0014 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_08_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_09_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_09_320x240.png new file mode 100644 index 00000000000..38f403a2ad3 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_09_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_10_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_10_320x240.png new file mode 100644 index 00000000000..99c832b68ec Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_10_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_11_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_11_320x240.png new file mode 100644 index 00000000000..67d17856c7d Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_11_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_12_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_12_320x240.png new file mode 100644 index 00000000000..8f7fc051365 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_12_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/jpegio_test_pattern_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/jpegio_test_pattern_320x240.png new file mode 100644 index 00000000000..4987b76ff80 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/jpegio_test_pattern_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.mask.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.mask.png new file mode 100644 index 00000000000..c675e2e5fa7 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.mask.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.png new file mode 100644 index 00000000000..77577a65601 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_AL_88.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_AL_88.png new file mode 100644 index 00000000000..f9ceedebe4a Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_AL_88.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_ARGB_8888.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_ARGB_8888.png new file mode 100644 index 00000000000..90b422792db Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_ARGB_8888.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_BGR_565.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_BGR_565.png new file mode 100644 index 00000000000..77577a65601 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_BGR_565.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_L_8.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_L_8.png new file mode 100644 index 00000000000..f9ceedebe4a Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_L_8.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01.png new file mode 100644 index 00000000000..59928bcd107 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01_no_vtiled.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01_no_vtiled.png new file mode 100644 index 00000000000..59928bcd107 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01_no_vtiled.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10.png new file mode 100644 index 00000000000..59928bcd107 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10_no_vtiled.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10_no_vtiled.png new file mode 100644 index 00000000000..59928bcd107 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10_no_vtiled.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_565.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_565.png new file mode 100644 index 00000000000..77577a65601 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_565.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_888.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_888.png new file mode 100644 index 00000000000..28d51925cae Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_888.png differ diff --git a/ports/zephyr-cp/tests/zephyr_display/test.gif b/ports/zephyr-cp/tests/zephyr_display/test.gif new file mode 100644 index 00000000000..4f96816a1f0 Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/test.gif differ diff --git a/ports/zephyr-cp/tests/zephyr_display/test.jpg b/ports/zephyr-cp/tests/zephyr_display/test.jpg new file mode 100644 index 00000000000..488357f506a Binary files /dev/null and b/ports/zephyr-cp/tests/zephyr_display/test.jpg differ diff --git a/ports/zephyr-cp/tests/zephyr_display/test_gifio.py b/ports/zephyr-cp/tests/zephyr_display/test_gifio.py new file mode 100644 index 00000000000..d4a665e2d44 --- /dev/null +++ b/ports/zephyr-cp/tests/zephyr_display/test_gifio.py @@ -0,0 +1,201 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +import shutil +from pathlib import Path + +import pytest +from PIL import Image + + +_TEST_GIF_PATH = Path(__file__).parent / "test.gif" +_TEST_GIF_BYTES = _TEST_GIF_PATH.read_bytes() + + +def _read_image(path: Path) -> tuple[int, int, bytes]: + with Image.open(path) as img: + rgb = img.convert("RGB") + return rgb.width, rgb.height, rgb.tobytes() + + +def _golden_compare_or_update(request, captures, golden_path): + if not captures or not captures[0].exists(): + pytest.skip("display capture was not produced") + + if request.config.getoption("--update-goldens"): + golden_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(captures[0], golden_path) + return + + gw, gh, gpx = _read_image(golden_path) + dw, dh, dpx = _read_image(captures[0]) + assert (dw, dh) == (gw, gh) + assert gpx == dpx + + +GIFIO_METADATA_CODE = """\ +import gifio + +odg = gifio.OnDiskGif('/test.gif') +print('size', odg.width, odg.height) +print('frame_count', odg.frame_count) +print('duration', round(odg.duration, 3)) +print('min_delay', round(odg.min_delay, 3)) +print('max_delay', round(odg.max_delay, 3)) + +delay = odg.next_frame() +print('delay', round(delay, 3)) + +bitmap = odg.bitmap +print('bitmap_size', bitmap.width, bitmap.height) + +for i in range(min(odg.width, 8)): + print('px', i, hex(bitmap[i, 0])) + +odg.deinit() +print('deinited') + +try: + odg.next_frame() +except Exception as e: + print('after_deinit', type(e).__name__) + +print('done') +""" + + +GIFIO_DECODE_CODE = """\ +import board +import displayio +import time +from gifio import OnDiskGif + +odg = OnDiskGif('/test.gif') +print('size', odg.width, odg.height) +print('frame_count', odg.frame_count) + +scale = 10 +tg = displayio.TileGrid( + odg.bitmap, + pixel_shader=displayio.ColorConverter( + input_colorspace=displayio.Colorspace.RGB565_SWAPPED + ), +) +g = displayio.Group(scale=scale) +g.x = (board.DISPLAY.width - odg.width * scale) // 2 +g.y = (board.DISPLAY.height - odg.height * scale) // 2 +g.append(tg) + +board.DISPLAY.auto_refresh = False +board.DISPLAY.root_group = g + +# Pin the render loop to a known point in simulated time so that the +# capture_times_ns schedule below lands on each GIF frame while it is on screen. +LOOP_START = 10.0 +FRAME_HOLD = 2.0 +while time.monotonic() < LOOP_START: + time.sleep(0.05) +print('loop_start', round(time.monotonic(), 3)) + +for frame_index in range(odg.frame_count): + odg.next_frame() + board.DISPLAY.refresh() + print('rendered', frame_index, round(time.monotonic(), 3)) + # Hold this frame on screen; the capture for this frame is scheduled + # for the middle of this window. + target = LOOP_START + (frame_index + 1) * FRAME_HOLD + while time.monotonic() < target: + time.sleep(0.05) + +print('done') +while True: + time.sleep(1) +""" + + +# Keep these in sync with LOOP_START / FRAME_HOLD in GIFIO_DECODE_CODE. +_DECODE_LOOP_START_S = 10.0 +_DECODE_FRAME_HOLD_S = 2.0 +_DECODE_FRAME_COUNT = 13 +# Capture at the midpoint of each frame's hold window. +_DECODE_CAPTURE_TIMES_NS = [ + int( + (_DECODE_LOOP_START_S + i * _DECODE_FRAME_HOLD_S + _DECODE_FRAME_HOLD_S / 2) + * 1_000_000_000 + ) + for i in range(_DECODE_FRAME_COUNT) +] + + +GIFIO_WRITER_CODE = """\ +import displayio +import gifio +import os + +width, height = 8, 4 +buf = bytearray(width * height * 2) +for i in range(width * height): + # RGB565 gradient + value = (i * 0x0841) & 0xFFFF + buf[2 * i] = (value >> 8) & 0xFF + buf[2 * i + 1] = value & 0xFF + +path = '/out.gif' +with gifio.GifWriter(path, width, height, displayio.Colorspace.RGB565, loop=True) as writer: + writer.add_frame(buf, 0.1) + writer.add_frame(buf, 0.2) + +size = os.stat(path)[6] +print('wrote_size', size) + +with open(path, 'rb') as f: + header = f.read(6) +print('header', header) + +print('done') +""" + + +_GIFIO_METADATA_DRIVE = {"code.py": GIFIO_METADATA_CODE, "test.gif": _TEST_GIF_BYTES} +_GIFIO_DECODE_DRIVE = {"code.py": GIFIO_DECODE_CODE, "test.gif": _TEST_GIF_BYTES} +_GIFIO_WRITER_DRIVE = {"code.py": GIFIO_WRITER_CODE} + + +@pytest.mark.circuitpy_drive(_GIFIO_METADATA_DRIVE) +def test_gifio_metadata(circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 16 16" in output + assert "frame_count 13" in output + assert "bitmap_size 16 16" in output + assert "min_delay 0.08" in output + assert "max_delay 0.08" in output + # 13 frames * 0.08s = 1.04s + assert "duration 1.04" in output + assert "delay 0.08" in output + assert "deinited" in output + # Using a deinited OnDiskGif should raise an exception. + assert "after_deinit" in output + assert "done" in output + + +@pytest.mark.circuitpy_drive(_GIFIO_DECODE_DRIVE) +@pytest.mark.display(capture_times_ns=_DECODE_CAPTURE_TIMES_NS) +@pytest.mark.duration(60) +def test_gifio_decode(request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 16 16" in output + assert "frame_count 13" in output + for frame_index in range(_DECODE_FRAME_COUNT): + assert f"rendered {frame_index}" in output + assert "done" in output + + captures = circuitpython.display_capture_paths() + assert len(captures) == _DECODE_FRAME_COUNT + golden_dir = Path(__file__).parent / "golden" + for frame_index, capture in enumerate(captures): + golden = golden_dir / f"gifio_frame_{frame_index:02d}_320x240.png" + _golden_compare_or_update(request, [capture], golden) diff --git a/ports/zephyr-cp/tests/zephyr_display/test_jpegio.py b/ports/zephyr-cp/tests/zephyr_display/test_jpegio.py new file mode 100644 index 00000000000..6368be7a5cf --- /dev/null +++ b/ports/zephyr-cp/tests/zephyr_display/test_jpegio.py @@ -0,0 +1,87 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +import shutil +from pathlib import Path + +import pytest +from PIL import Image + + +_TEST_JPG_PATH = Path(__file__).parent / "test.jpg" +_TEST_JPG_BYTES = _TEST_JPG_PATH.read_bytes() + + +def _read_image(path: Path) -> tuple[int, int, bytes]: + with Image.open(path) as img: + rgb = img.convert("RGB") + return rgb.width, rgb.height, rgb.tobytes() + + +def _golden_compare_or_update(request, captures, golden_path): + if not captures or not captures[0].exists(): + pytest.skip("display capture was not produced") + + if request.config.getoption("--update-goldens"): + golden_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(captures[0], golden_path) + return + + gw, gh, gpx = _read_image(golden_path) + dw, dh, dpx = _read_image(captures[0]) + assert (dw, dh) == (gw, gh) + assert gpx == dpx + + +JPEGIO_DECODE_CODE = """\ +import board +import displayio +import time +from jpegio import JpegDecoder + +decoder = JpegDecoder() +width, height = decoder.open("/test.jpg") +print('size', width, height) + +bitmap = displayio.Bitmap(width, height, 65535) +decoder.decode(bitmap) + +for i in range(min(width, 8)): + print('px', i, hex(bitmap[i, 0])) + +scale = 10 +tg = displayio.TileGrid( + bitmap, + pixel_shader=displayio.ColorConverter( + input_colorspace=displayio.Colorspace.RGB565_SWAPPED + ), +) +g = displayio.Group(scale=scale) +g.x = (board.DISPLAY.width - width * scale) // 2 +g.y = (board.DISPLAY.height - height * scale) // 2 +g.append(tg) + +board.DISPLAY.auto_refresh = False +board.DISPLAY.root_group = g +board.DISPLAY.refresh() +print('rendered') +while True: + time.sleep(1) +""" + + +_JPEGIO_DRIVE = {"code.py": JPEGIO_DECODE_CODE, "test.jpg": _TEST_JPG_BYTES} + + +@pytest.mark.circuitpy_drive(_JPEGIO_DRIVE) +@pytest.mark.display(capture_times_ns=[14_000_000_000]) +@pytest.mark.duration(18) +def test_jpegio_decode(request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 20 20" in output + assert "rendered" in output + + golden = Path(__file__).parent / "golden" / "jpegio_test_pattern_320x240.png" + _golden_compare_or_update(request, circuitpython.display_capture_paths(), golden) diff --git a/ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py b/ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py new file mode 100644 index 00000000000..6700c42ec4a --- /dev/null +++ b/ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py @@ -0,0 +1,365 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +import colorsys +import shutil +import struct +from pathlib import Path + +import pytest +from PIL import Image + + +def _read_image(path: Path) -> tuple[int, int, bytes]: + """Read an image file and return (width, height, RGB bytes).""" + with Image.open(path) as img: + rgb = img.convert("RGB") + return rgb.width, rgb.height, rgb.tobytes() + + +def _read_mask(golden_path: Path) -> bytes | None: + """Load the companion mask PNG for a golden image, if it exists. + + Non-zero pixels are masked (skipped during comparison). + """ + mask_path = golden_path.with_suffix(".mask.png") + if not mask_path.exists(): + return None + with Image.open(mask_path) as img: + return img.convert("L").tobytes() + + +def _assert_pixels_equal_masked( + golden_pixels: bytes, actual_pixels: bytes, mask: bytes | None = None +): + """Assert pixels match, skipping positions where the mask is non-zero.""" + assert len(golden_pixels) == len(actual_pixels) + for i in range(0, len(golden_pixels), 3): + if mask is not None and mask[i // 3] != 0: + continue + if golden_pixels[i : i + 3] != actual_pixels[i : i + 3]: + pixel = i // 3 + assert False, ( + f"Pixel {pixel} mismatch: " + f"golden={tuple(golden_pixels[i : i + 3])} " + f"actual={tuple(actual_pixels[i : i + 3])}" + ) + + +BOARD_DISPLAY_AVAILABLE_CODE = """\ +import board +print(hasattr(board, 'DISPLAY')) +print(type(board.DISPLAY).__name__) +print(board.DISPLAY.width, board.DISPLAY.height) +print('done') +""" + + +@pytest.mark.circuitpy_drive({"code.py": BOARD_DISPLAY_AVAILABLE_CODE}) +@pytest.mark.display +@pytest.mark.duration(8) +def test_board_display_available(circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "True" in output + assert "Display" in output + assert "320 240" in output + assert "done" in output + + +CONSOLE_TERMINAL_PRESENT_CODE = """\ +import board + +root = board.DISPLAY.root_group +has_terminal_tilegrids = ( + type(root).__name__ == 'Group' and + len(root) >= 2 and + type(root[0]).__name__ == 'TileGrid' and + type(root[-1]).__name__ == 'TileGrid' +) +print('has_terminal_tilegrids:', has_terminal_tilegrids) +print('done') +""" + + +@pytest.mark.circuitpy_drive({"code.py": CONSOLE_TERMINAL_PRESENT_CODE}) +@pytest.mark.display +@pytest.mark.duration(8) +def test_console_terminal_present_by_default(circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "has_terminal_tilegrids: True" in output + assert "done" in output + + +CONSOLE_OUTPUT_GOLDEN_CODE = """\ +import time +time.sleep(0.25) +print('done') +while True: + time.sleep(1) +""" + + +def _golden_compare_or_update(request, captures, golden_path, mask_path=None): + """Compare captured PNG against golden, or update golden if --update-goldens. + + mask_path overrides the default companion mask lookup (golden.mask.png). + """ + if not captures or not captures[0].exists(): + pytest.skip("display capture was not produced") + + if request.config.getoption("--update-goldens"): + golden_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(captures[0], golden_path) + return + + gw, gh, gpx = _read_image(golden_path) + dw, dh, dpx = _read_image(captures[0]) + if mask_path is not None: + mask = _read_mask(mask_path) + else: + mask = _read_mask(golden_path) + + assert (dw, dh) == (gw, gh) + _assert_pixels_equal_masked(gpx, dpx, mask) + + +@pytest.mark.circuitpy_drive({"code.py": CONSOLE_OUTPUT_GOLDEN_CODE}) +@pytest.mark.display(capture_times_ns=[4_000_000_000]) +@pytest.mark.duration(8) +def test_console_output_golden(request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "done" in output + + golden = Path(__file__).parent / "golden" / "terminal_console_output_320x240.png" + _golden_compare_or_update(request, circuitpython.display_capture_paths(), golden) + + +PIXEL_FORMATS = ["ARGB_8888", "RGB_888", "RGB_565", "BGR_565", "L_8", "AL_88", "MONO01", "MONO10"] + +# Shared mask: the same screen regions vary regardless of pixel format. +_CONSOLE_GOLDEN_MASK = Path(__file__).parent / "golden" / "terminal_console_output_320x240.png" + + +@pytest.mark.circuitpy_drive({"code.py": CONSOLE_OUTPUT_GOLDEN_CODE}) +@pytest.mark.display(capture_times_ns=[4_000_000_000]) +@pytest.mark.duration(8) +@pytest.mark.parametrize( + "pixel_format", + PIXEL_FORMATS, + indirect=True, +) +def test_console_output_golden_pixel_format(pixel_format, request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "done" in output + + golden_name = f"terminal_console_output_320x240_{pixel_format}.png" + golden = Path(__file__).parent / "golden" / golden_name + _golden_compare_or_update( + request, circuitpython.display_capture_paths(), golden, _CONSOLE_GOLDEN_MASK + ) + + +MONO_NO_VTILED_FORMATS = ["MONO01", "MONO10"] + + +@pytest.mark.circuitpy_drive({"code.py": CONSOLE_OUTPUT_GOLDEN_CODE}) +@pytest.mark.display(capture_times_ns=[4_000_000_000]) +@pytest.mark.display_mono_vtiled(False) +@pytest.mark.duration(8) +@pytest.mark.parametrize( + "pixel_format", + MONO_NO_VTILED_FORMATS, + indirect=True, +) +def test_console_output_golden_mono_no_vtiled(pixel_format, request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "done" in output + + golden_name = f"terminal_console_output_320x240_{pixel_format}_no_vtiled.png" + golden = Path(__file__).parent / "golden" / golden_name + _golden_compare_or_update( + request, circuitpython.display_capture_paths(), golden, _CONSOLE_GOLDEN_MASK + ) + + +def _generate_gradient_bmp(width, height): + """Generate a 24-bit BMP with HSL color gradient. + + Hue sweeps left to right, lightness goes from black (bottom) to white (top), + saturation is 1.0. + """ + row_size = width * 3 + row_padding = (4 - (row_size % 4)) % 4 + padded_row_size = row_size + row_padding + pixel_data_size = padded_row_size * height + file_size = 14 + 40 + pixel_data_size + + header = struct.pack( + "<2sIHHI", + b"BM", + file_size, + 0, + 0, + 14 + 40, + ) + info = struct.pack( + "stack_adjust < 0x100) { emit_al(as, asm_arm_op_sub_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust)); } else { - asm_arm_mov_reg_i32_optimised(as, ASM_ARM_REG_R8, as->stack_adjust); - emit_al(as, asm_arm_op_sub_reg(ASM_ARM_REG_SP, ASM_ARM_REG_SP, ASM_ARM_REG_R8)); + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, as->stack_adjust); + emit_al(as, asm_arm_op_sub_reg(ASM_ARM_REG_SP, ASM_ARM_REG_SP, REG_TEMP)); } } } @@ -182,8 +182,8 @@ void asm_arm_exit(asm_arm_t *as) { if (as->stack_adjust < 0x100) { emit_al(as, asm_arm_op_add_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust)); } else { - asm_arm_mov_reg_i32_optimised(as, ASM_ARM_REG_R8, as->stack_adjust); - emit_al(as, asm_arm_op_add_reg(ASM_ARM_REG_SP, ASM_ARM_REG_SP, ASM_ARM_REG_R8)); + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, as->stack_adjust); + emit_al(as, asm_arm_op_add_reg(ASM_ARM_REG_SP, ASM_ARM_REG_SP, REG_TEMP)); } } @@ -293,10 +293,10 @@ void asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) { void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num) { if (local_num >= 0x40) { - // mov r8, #local_num*4 - // add rd, sp, r8 - asm_arm_mov_reg_i32_optimised(as, ASM_ARM_REG_R8, local_num << 2); - emit_al(as, asm_arm_op_add_reg(rd, ASM_ARM_REG_SP, ASM_ARM_REG_R8)); + // mov temp, #local_num*4 + // add rd, sp, temp + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, local_num << 2); + emit_al(as, asm_arm_op_add_reg(rd, ASM_ARM_REG_SP, REG_TEMP)); } else { // add rd, sp, #local_num*4 emit_al(as, asm_arm_op_add_imm(rd, ASM_ARM_REG_SP, local_num << 2)); @@ -333,14 +333,22 @@ void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs) { emit_al(as, 0x1a00050 | (rd << 12) | (rs << 8) | rd); } -void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { - // ldr rd, [rn, #off] - emit_al(as, 0x5900000 | (rn << 16) | (rd << 12) | byte_offset); +void asm_arm_ldr_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { + if (byte_offset < 0x1000) { + // ldr rd, [rn, #off] + emit_al(as, 0x5900000 | (rn << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // ldr rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7900000 | (rn << 16) | (rd << 12) | REG_TEMP); + } } -void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn) { - // ldrh rd, [rn] - emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12)); +void asm_arm_ldrh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { + // ldrh doesn't support scaled register index + emit_al(as, 0x1a00080 | (REG_TEMP << 12) | rn); // mov temp, rn, lsl #1 + emit_al(as, 0x19000b0 | (rm << 16) | (rd << 12) | REG_TEMP); // ldrh rd, [rm, temp]; } void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { @@ -348,31 +356,69 @@ void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offs // ldrh rd, [rn, #off] emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12) | ((byte_offset & 0xf0) << 4) | (byte_offset & 0xf)); } else { - // mov r8, #off - // ldrh rd, [rn, r8] - asm_arm_mov_reg_i32_optimised(as, ASM_ARM_REG_R8, byte_offset); - emit_al(as, 0x19000b0 | (rn << 16) | (rd << 12) | ASM_ARM_REG_R8); + // mov temp, #off + // ldrh rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x19000b0 | (rn << 16) | (rd << 12) | REG_TEMP); } } -void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn) { - // ldrb rd, [rn] - emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12)); +void asm_arm_ldrb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { + // ldrb rd, [rm, rn] + emit_al(as, 0x7d00000 | (rm << 16) | (rd << 12) | rn); +} + +void asm_arm_ldrb_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { + if (byte_offset < 0x1000) { + // ldrb rd, [rn, #off] + emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // ldrb rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7d00000 | (rn << 16) | (rd << 12) | REG_TEMP); + } } -void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm, uint byte_offset) { - // str rd, [rm, #off] - emit_al(as, 0x5800000 | (rm << 16) | (rd << 12) | byte_offset); +void asm_arm_ldr_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { + // ldr rd, [rm, rn, lsl #2] + emit_al(as, 0x7900100 | (rm << 16) | (rd << 12) | rn); } -void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm) { - // strh rd, [rm] - emit_al(as, 0x1c000b0 | (rm << 16) | (rd << 12)); +void asm_arm_str_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset) { + if (byte_offset < 0x1000) { + // str rd, [rm, #off] + emit_al(as, 0x5800000 | (rm << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // str rd, [rm, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7800000 | (rm << 16) | (rd << 12) | REG_TEMP); + } } -void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm) { - // strb rd, [rm] - emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12)); +void asm_arm_strh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { + if (byte_offset < 0x100) { + // strh rd, [rn, #off] + emit_al(as, 0x1c000b0 | (rn << 16) | (rd << 12) | ((byte_offset & 0xf0) << 4) | (byte_offset & 0xf)); + } else { + // mov temp, #off + // strh rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x18000b0 | (rn << 16) | (rd << 12) | REG_TEMP); + } +} + +void asm_arm_strb_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset) { + if (byte_offset < 0x1000) { + // strb rd, [rm, #off] + emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // strb rd, [rm, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7c00000 | (rm << 16) | (rd << 12) | REG_TEMP); + } } void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { @@ -382,8 +428,8 @@ void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { // strh doesn't support scaled register index - emit_al(as, 0x1a00080 | (ASM_ARM_REG_R8 << 12) | rn); // mov r8, rn, lsl #1 - emit_al(as, 0x18000b0 | (rm << 16) | (rd << 12) | ASM_ARM_REG_R8); // strh rd, [rm, r8] + emit_al(as, 0x1a00080 | (REG_TEMP << 12) | rn); // mov temp, rn, lsl #1 + emit_al(as, 0x18000b0 | (rm << 16) | (rd << 12) | REG_TEMP); // strh rd, [rm, temp] } void asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { @@ -398,7 +444,7 @@ void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) { rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted - if (SIGNED_FIT24(rel)) { + if (MP_FIT_SIGNED(24, rel)) { emit(as, cond | 0xa000000 | (rel & 0xffffff)); } else { printf("asm_arm_bcc: branch does not fit in 24 bits\n"); diff --git a/py/asmarm.h b/py/asmarm.h index a0e057fce44..7a68e4c640f 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -50,21 +50,21 @@ #define ASM_ARM_REG_LR (ASM_ARM_REG_R14) #define ASM_ARM_REG_PC (ASM_ARM_REG_R15) -#define ASM_ARM_CC_EQ (0x0 << 28) -#define ASM_ARM_CC_NE (0x1 << 28) -#define ASM_ARM_CC_CS (0x2 << 28) -#define ASM_ARM_CC_CC (0x3 << 28) -#define ASM_ARM_CC_MI (0x4 << 28) -#define ASM_ARM_CC_PL (0x5 << 28) -#define ASM_ARM_CC_VS (0x6 << 28) -#define ASM_ARM_CC_VC (0x7 << 28) -#define ASM_ARM_CC_HI (0x8 << 28) -#define ASM_ARM_CC_LS (0x9 << 28) -#define ASM_ARM_CC_GE (0xa << 28) -#define ASM_ARM_CC_LT (0xb << 28) -#define ASM_ARM_CC_GT (0xc << 28) -#define ASM_ARM_CC_LE (0xd << 28) -#define ASM_ARM_CC_AL (0xe << 28) +#define ASM_ARM_CC_EQ (0x0u << 28) +#define ASM_ARM_CC_NE (0x1u << 28) +#define ASM_ARM_CC_CS (0x2u << 28) +#define ASM_ARM_CC_CC (0x3u << 28) +#define ASM_ARM_CC_MI (0x4u << 28) +#define ASM_ARM_CC_PL (0x5u << 28) +#define ASM_ARM_CC_VS (0x6u << 28) +#define ASM_ARM_CC_VC (0x7u << 28) +#define ASM_ARM_CC_HI (0x8u << 28) +#define ASM_ARM_CC_LS (0x9u << 28) +#define ASM_ARM_CC_GE (0xau << 28) +#define ASM_ARM_CC_LT (0xbu << 28) +#define ASM_ARM_CC_GT (0xcu << 28) +#define ASM_ARM_CC_LE (0xdu << 28) +#define ASM_ARM_CC_AL (0xeu << 28) typedef struct _asm_arm_t { mp_asm_base_t base; @@ -109,13 +109,18 @@ void asm_arm_lsr_reg_reg(asm_arm_t *as, uint rd, uint rs); void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs); // memory -void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn, uint byte_offset); -void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn); +void asm_arm_ldr_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset); void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset); -void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn); -void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm, uint byte_offset); -void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm); -void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm); +void asm_arm_ldrb_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset); +void asm_arm_str_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset); +void asm_arm_strh_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset); +void asm_arm_strb_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset); + +// load from array +void asm_arm_ldr_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); +void asm_arm_ldrh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); +void asm_arm_ldrb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); + // store to array void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); @@ -160,12 +165,12 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); // Holds a pointer to mp_fun_table #define REG_FUN_TABLE ASM_ARM_REG_FUN_TABLE -#define ASM_T asm_arm_t -#define ASM_END_PASS asm_arm_end_pass -#define ASM_ENTRY asm_arm_entry -#define ASM_EXIT asm_arm_exit +#define ASM_T asm_arm_t +#define ASM_END_PASS asm_arm_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_arm_entry((as), (num_locals)) +#define ASM_EXIT asm_arm_exit -#define ASM_JUMP asm_arm_b_label +#define ASM_JUMP asm_arm_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ asm_arm_cmp_reg_i8(as, reg, 0); \ @@ -203,18 +208,30 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_arm_sub_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_arm_mul_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 4 * (word_offset)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_arm_ldrb_reg_reg((as), (reg_dest), (reg_base)) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_arm_ldrh_reg_reg((as), (reg_dest), (reg_base)) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_arm_ldrh_reg_reg_offset((as), (reg_dest), (reg_base), 2 * (uint16_offset)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0) - -#define ASM_STORE_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_str_reg_reg((as), (reg_dest), (reg_base), 4 * (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_value, reg_base) asm_arm_strb_reg_reg((as), (reg_value), (reg_base)) -#define ASM_STORE16_REG_REG(as, reg_value, reg_base) asm_arm_strh_reg_reg((as), (reg_value), (reg_base)) -#define ASM_STORE32_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_arm_ldrb_reg_reg_offset((as), (reg_dest), (reg_base), (byte_offset)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, halfword_offset) asm_arm_ldrh_reg_reg_offset((as), (reg_dest), (reg_base), 2 * (halfword_offset)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_ldr_reg_reg_offset((as), (reg_dest), (reg_base), 4 * (word_offset)) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_value, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_value), (reg_base), (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_value, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_value), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_value, reg_base, byte_offset) asm_arm_strb_reg_reg_offset((as), (reg_value), (reg_base), (byte_offset)) +#define ASM_STORE16_REG_REG(as, reg_value, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_value), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_value, reg_base, halfword_offset) asm_arm_strh_reg_reg_offset((as), (reg_value), (reg_base), 2 * (halfword_offset)) +#define ASM_STORE32_REG_REG(as, reg_value, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_value), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_value, reg_base, word_offset) asm_arm_str_reg_reg_offset((as), (reg_value), (reg_base), 4 * (word_offset)) + +#define ASM_LOAD8_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_arm_ldrb_reg_reg_reg((as), (reg_dest), (reg_base), (reg_index)) +#define ASM_LOAD16_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_arm_ldrh_reg_reg_reg((as), (reg_dest), (reg_base), (reg_index)) +#define ASM_LOAD32_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_arm_ldr_reg_reg_reg((as), (reg_dest), (reg_base), (reg_index)) +#define ASM_STORE8_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_arm_strb_reg_reg_reg((as), (reg_val), (reg_base), (reg_index)) +#define ASM_STORE16_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_arm_strh_reg_reg_reg((as), (reg_val), (reg_base), (reg_index)) +#define ASM_STORE32_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_arm_str_reg_reg_reg((as), (reg_val), (reg_base), (reg_index)) + +#define ASM_CLR_REG(as, reg_dest) asm_arm_eor_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_dest)) #endif // GENERIC_ASM_API diff --git a/py/asmbase.c b/py/asmbase.c index 3fce543a7f4..07dbf4430f9 100644 --- a/py/asmbase.c +++ b/py/asmbase.c @@ -53,7 +53,7 @@ void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) { } else { // allocating executable RAM is platform specific MP_PLAT_ALLOC_EXEC(as->code_offset, (void **)&as->code_base, &as->code_size); - assert(as->code_base != NULL); + assert(as->code_size == 0 || as->code_base != NULL); } as->pass = pass; as->suppress = false; @@ -102,7 +102,7 @@ void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) { // align must be a multiple of 2 void mp_asm_base_align(mp_asm_base_t *as, unsigned int align) { - as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); + as->code_offset = (as->code_offset + align - 1) & (~(size_t)(align - 1)); } // this function assumes a little endian machine diff --git a/py/asmrv32.c b/py/asmrv32.c index c24d05a1384..53481d1d0f3 100644 --- a/py/asmrv32.c +++ b/py/asmrv32.c @@ -36,6 +36,8 @@ #if MICROPY_EMIT_RV32 #include "py/asmrv32.h" +#include "py/mpstate.h" +#include "py/persistentcode.h" #if MICROPY_DEBUG_VERBOSE #define DEBUG_PRINT (1) @@ -51,6 +53,14 @@ ((((value) & ~((1U << ((bits) - 1)) - 1)) == 0) || \ (((value) & ~((1U << ((bits) - 1)) - 1)) == ~((1U << ((bits) - 1)) - 1))) +static bool asm_rv32_allow_zba_opcodes(void) { + return asm_rv32_allowed_extensions() & RV32_EXT_ZBA; +} + +static bool asm_rv32_allow_zcmp_opcodes(void) { + return asm_rv32_allowed_extensions() & RV32_EXT_ZCMP; +} + /////////////////////////////////////////////////////////////////////////////// void asm_rv32_emit_word_opcode(asm_rv32_t *state, mp_uint_t word) { @@ -212,6 +222,14 @@ static void adjust_stack(asm_rv32_t *state, mp_int_t stack_size) { return; } + // WARNING: If REG_TEMP0 is not set to a caller-saved register, then this + // bit has to be rewritten to avoid clobbering the temporary + // register when performing the stack adjustment. + + MP_STATIC_ASSERT(((REG_TEMP0 >= ASM_RV32_REG_T0) && (REG_TEMP0 <= ASM_RV32_REG_T2)) || \ + ((REG_TEMP0 >= ASM_RV32_REG_A0) && (REG_TEMP0 <= ASM_RV32_REG_A7)) || \ + ((REG_TEMP0 >= ASM_RV32_REG_T3) && (REG_TEMP0 <= ASM_RV32_REG_T6))); + // li temporary, stack_size // c.add sp, temporary load_full_immediate(state, REG_TEMP0, stack_size); @@ -243,6 +261,45 @@ static void emit_function_epilogue(asm_rv32_t *state, mp_uint_t registers) { state->saved_registers_mask = old_saved_registers_mask; } +static mp_uint_t compute_zcmp_sequence_length(mp_uint_t registers) { + // Can only handle RA and S0..S11 and must have at least one entry. + assert((registers != 0) && (registers & (~0x0FFC0302U)) == 0 && "Invalid Zcmp registers set."); + mp_uint_t length = 32 - mp_clz(((registers & 0x00000002) >> 1) | ((registers & 0x00000300) >> 7) | ((registers & 0x0FFC0000) >> 15)); + return length == 12 ? 13 : length; +} + +#define EMIT_ASSERT(state, condition, message) assert((((state)->base.pass != MP_ASM_PASS_EMIT) ? true : (condition)) && (message)) + +static void emit_compressed_function_prologue(asm_rv32_t *state, mp_uint_t registers_mask) { + mp_uint_t sequence_length = compute_zcmp_sequence_length(registers_mask); + mp_uint_t allocated_stack = (sequence_length + 3) & (mp_uint_t)-4; + EMIT_ASSERT(state, allocated_stack >= sequence_length, "Incorrect allocated stack calculation."); + mp_uint_t tail_slack = allocated_stack - sequence_length; + mp_uint_t locals_left = (state->locals_count < tail_slack) ? 0 : (state->locals_count - tail_slack); + mp_uint_t adjustment_chunks = MIN(3, locals_left / 4); + EMIT_ASSERT(state, (adjustment_chunks * 4) <= locals_left, "Incorrect adjustment chunks rounding."); + locals_left -= adjustment_chunks * 4; + EMIT_ASSERT(state, locals_left <= (MP_INT_MAX / sizeof(uint32_t)), "Too many locals."); + mp_int_t stack_size = (mp_int_t)(locals_left * sizeof(uint32_t)); + asm_rv32_opcode_cmpush(state, MIN(3 + sequence_length, 15), adjustment_chunks); + // CM.PUSH allocates a stack block and then puts the registers *at the end* + // of the block, so for example "CM.PUSH {RA, S0-S11}, -64" will put RA at + // SP + 60, not at SP + 0. + adjust_stack(state, -stack_size); + // The stack size is expressed in bytes and as a multiple of 4, hence the + // bottom two bits are not used. Since there can be up to three adjustment + // chunks, that number can be expressed in two bits, fitting nicely in the + // existing variable. + state->stack_size = ((mp_uint_t)stack_size) | adjustment_chunks; +} + +static void emit_compressed_function_epilogue(asm_rv32_t *state, mp_uint_t registers_mask) { + mp_uint_t sequence_length = compute_zcmp_sequence_length(registers_mask); + mp_uint_t stack_size = state->stack_size & (mp_uint_t)(~0x03U); + adjust_stack(state, stack_size); + asm_rv32_opcode_cmpopret(state, MIN(3 + sequence_length, 15), state->stack_size & 0x03); +} + static bool calculate_displacement_for_label(asm_rv32_t *state, mp_uint_t label, ptrdiff_t *displacement) { assert(displacement != NULL && "Displacement pointer is NULL"); @@ -254,16 +311,24 @@ static bool calculate_displacement_for_label(asm_rv32_t *state, mp_uint_t label, /////////////////////////////////////////////////////////////////////////////// void asm_rv32_entry(asm_rv32_t *state, mp_uint_t locals) { + state->locals_count = locals; state->saved_registers_mask |= (1U << REG_FUN_TABLE) | (1U << REG_LOCAL_1) | \ (1U << REG_LOCAL_2) | (1U << REG_LOCAL_3); - state->locals_count = locals; - emit_function_prologue(state, state->saved_registers_mask); + if (asm_rv32_allow_zcmp_opcodes()) { + emit_compressed_function_prologue(state, state->saved_registers_mask); + } else { + emit_function_prologue(state, state->saved_registers_mask); + } } void asm_rv32_exit(asm_rv32_t *state) { - emit_function_epilogue(state, state->saved_registers_mask); - // c.jr ra - asm_rv32_opcode_cjr(state, ASM_RV32_REG_RA); + if (asm_rv32_allow_zcmp_opcodes()) { + emit_compressed_function_epilogue(state, state->saved_registers_mask); + } else { + emit_function_epilogue(state, state->saved_registers_mask); + // c.jr ra + asm_rv32_opcode_cjr(state, ASM_RV32_REG_RA); + } } void asm_rv32_end_pass(asm_rv32_t *state) { @@ -450,18 +515,23 @@ void asm_rv32_emit_mov_reg_local_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t asm_rv32_opcode_cadd(state, rd, ASM_RV32_REG_SP); } -void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { - mp_int_t scaled_offset = offset * sizeof(ASM_WORD_SIZE); +// ((word: 4) << 8) | ((halfword: 4) << 4) | (byte: 4) +#define RV32_LOAD_OPCODE_FT3(size) ((0x0254 >> (size << 2)) & 0x0F) + +void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); - if (scaled_offset >= 0 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && FIT_UNSIGNED(scaled_offset, 6)) { + int32_t scaled_offset = offset << operation_size; + + if (scaled_offset >= 0 && operation_size == 2 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && MP_FIT_UNSIGNED(6, scaled_offset)) { // c.lw rd', offset(rs') asm_rv32_opcode_clw(state, RV32_MAP_IN_C_REGISTER_WINDOW(rd), RV32_MAP_IN_C_REGISTER_WINDOW(rs), scaled_offset); return; } - if (FIT_SIGNED(scaled_offset, 12)) { - // lw rd, offset(rs) - asm_rv32_opcode_lw(state, rd, rs, scaled_offset); + if (MP_FIT_SIGNED(12, scaled_offset)) { + // lbu|lhu|lw rd, offset(rs) + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, RV32_LOAD_OPCODE_FT3(operation_size), rd, rs, scaled_offset)); return; } @@ -469,12 +539,12 @@ void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_ mp_uint_t lower = 0; split_immediate(scaled_offset, &upper, &lower); - // lui rd, HI(offset) ; Or c.lui if possible - // c.add rd, rs - // lw rd, LO(offset)(rd) + // lui rd, HI(offset) ; Or c.lui if possible + // c.add rd, rs + // lbu|lhu|lw rd, LO(offset)(rd) load_upper_immediate(state, rd, upper); asm_rv32_opcode_cadd(state, rd, rs); - asm_rv32_opcode_lw(state, rd, rd, lower); + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, RV32_LOAD_OPCODE_FT3(operation_size), rd, rd, lower)); } void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) { @@ -497,12 +567,20 @@ void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) { asm_rv32_opcode_jalr(state, ASM_RV32_REG_ZERO, REG_TEMP2, lower); } -void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { - mp_int_t scaled_offset = offset * ASM_WORD_SIZE; +void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + int32_t scaled_offset = offset << operation_size; - if (FIT_SIGNED(scaled_offset, 12)) { - // sw rd, offset(rs) - asm_rv32_opcode_sw(state, rd, rs, scaled_offset); + if (scaled_offset >= 0 && operation_size == 2 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && MP_FIT_UNSIGNED(6, scaled_offset)) { + // c.sw rd', offset(rs') + asm_rv32_opcode_csw(state, RV32_MAP_IN_C_REGISTER_WINDOW(rd), RV32_MAP_IN_C_REGISTER_WINDOW(rs), scaled_offset); + return; + } + + if (MP_FIT_SIGNED(12, scaled_offset)) { + // sb|sh|sw rd, offset(rs) + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, operation_size, rs, rd, scaled_offset)); return; } @@ -510,12 +588,12 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint mp_uint_t lower = 0; split_immediate(scaled_offset, &upper, &lower); - // lui temporary, HI(offset) ; Or c.lui if possible - // c.add temporary, rs - // sw rd, LO(offset)(temporary) + // lui temporary, HI(offset) ; Or c.lui if possible + // c.add temporary, rs + // sb|sh|sw rd, LO(offset)(temporary) load_upper_immediate(state, REG_TEMP2, upper); asm_rv32_opcode_cadd(state, REG_TEMP2, rs); - asm_rv32_opcode_sw(state, rd, REG_TEMP2, lower); + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, operation_size, REG_TEMP2, rd, lower)); } void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label) { @@ -530,27 +608,6 @@ void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t labe asm_rv32_opcode_addi(state, rd, rd, lower); } -void asm_rv32_emit_load16_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { - mp_int_t scaled_offset = offset * sizeof(uint16_t); - - if (FIT_SIGNED(scaled_offset, 12)) { - // lhu rd, offset(rs) - asm_rv32_opcode_lhu(state, rd, rs, scaled_offset); - return; - } - - mp_uint_t upper = 0; - mp_uint_t lower = 0; - split_immediate(scaled_offset, &upper, &lower); - - // lui rd, HI(offset) ; Or c.lui if possible - // c.add rd, rs - // lhu rd, LO(offset)(rd) - load_upper_immediate(state, rd, upper); - asm_rv32_opcode_cadd(state, rd, rs); - asm_rv32_opcode_lhu(state, rd, rd, lower); -} - void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs) { if (rs == rd) { // c.li rd, 0 @@ -562,14 +619,38 @@ void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs) asm_rv32_opcode_xor(state, rd, rd, rs); } +// WARNING: The scaled offset will be stored in REG_TEMP2. +static void asm_rv32_fix_up_scaled_reg_reg_reg(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + if (operation_size > 0 && asm_rv32_allow_zba_opcodes()) { + // sh{1,2}add rs1, rs2, rs1 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 1 << operation_size, 0x10, REG_TEMP2, rs2, rs1)); + } else { + if (operation_size > 0) { + asm_rv32_opcode_slli(state, REG_TEMP2, rs2, operation_size); + asm_rv32_opcode_cadd(state, REG_TEMP2, rs1); + } else { + asm_rv32_opcode_add(state, REG_TEMP2, rs1, rs2); + } + } +} + +void asm_rv32_emit_load_reg_reg_reg(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size) { + asm_rv32_fix_up_scaled_reg_reg_reg(state, rs1, rs2, operation_size); + asm_rv32_emit_load_reg_reg_offset(state, rd, REG_TEMP2, 0, operation_size); +} + +void asm_rv32_emit_store_reg_reg_reg(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size) { + asm_rv32_fix_up_scaled_reg_reg_reg(state, rs1, rs2, operation_size); + asm_rv32_emit_store_reg_reg_offset(state, rd, REG_TEMP2, 0, operation_size); +} + void asm_rv32_meta_comparison_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd) { - // c.li rd, 1 ; - // beq rs1, rs2, 6 ; PC + 0 - // c.li rd, 0 ; PC + 4 - // ... ; PC + 6 - asm_rv32_opcode_cli(state, rd, 1); - asm_rv32_opcode_beq(state, rs1, rs2, 6); - asm_rv32_opcode_cli(state, rd, 0); + // sub rd, rs1, rs2 + // sltiu rd, rd, 1 + asm_rv32_opcode_sub(state, rd, rs1, rs2); + asm_rv32_opcode_sltiu(state, rd, rd, 1); } void asm_rv32_meta_comparison_ne(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd) { @@ -580,26 +661,15 @@ void asm_rv32_meta_comparison_ne(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2 } void asm_rv32_meta_comparison_lt(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison) { - // slt(u) rd, rs1, rs2 - if (unsigned_comparison) { - asm_rv32_opcode_sltu(state, rd, rs1, rs2); - } else { - asm_rv32_opcode_slt(state, rd, rs1, rs2); - } + // slt|sltu rd, rs1, rs2 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, (0x02 | (unsigned_comparison ? 1 : 0)), 0x00, rd, rs1, rs2)); } void asm_rv32_meta_comparison_le(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison) { - // c.li rd, 1 ; - // beq rs1, rs2, 8 ; PC + 0 - // slt(u) rd, rs1, rs2 ; PC + 4 - // ... ; PC + 8 - asm_rv32_opcode_cli(state, rd, 1); - asm_rv32_opcode_beq(state, rs1, rs2, 8); - if (unsigned_comparison) { - asm_rv32_opcode_sltu(state, rd, rs1, rs2); - } else { - asm_rv32_opcode_slt(state, rd, rs1, rs2); - } + // slt[u] rd, rs2, rs1 + // xori rd, rd, 1 + asm_rv32_meta_comparison_lt(state, rs2, rs1, rd, unsigned_comparison); + asm_rv32_opcode_xori(state, rd, rd, 1); } #endif // MICROPY_EMIT_RV32 diff --git a/py/asmrv32.h b/py/asmrv32.h index b09f48eb12f..f71fe72706a 100644 --- a/py/asmrv32.h +++ b/py/asmrv32.h @@ -122,6 +122,19 @@ typedef struct _asm_rv32_t { mp_uint_t locals_stack_offset; } asm_rv32_t; +enum { + RV32_EXT_NONE = 0, + RV32_EXT_ZBA = 1 << 0, + RV32_EXT_ZCMP = 1 << 1, + + RV32_EXT_ALL = RV32_EXT_ZBA | RV32_EXT_ZCMP +}; + +typedef struct _asm_rv32_backend_options_t { + // This is a bitmask holding a combination of RV32_EXT_* entries. + uint8_t allowed_extensions; +} asm_rv32_backend_options_t; + void asm_rv32_entry(asm_rv32_t *state, mp_uint_t locals); void asm_rv32_exit(asm_rv32_t *state); void asm_rv32_end_pass(asm_rv32_t *state); @@ -184,6 +197,18 @@ void asm_rv32_end_pass(asm_rv32_t *state); ((rs & 0x07) << 7) | ((imm & 0x40) >> 1) | ((imm & 0x38) << 7) | \ ((imm & 0x04) << 4)) +#define RV32_ENCODE_TYPE_CMPP(op, ft6, ft2, rlist, imm) \ + ((op & 0x03) | ((ft6 & 0x3F) << 10) | ((ft2 & 0x03) << 8) | \ + ((rlist & 0x0F) << 4) | ((imm & 0x03) << 2)) + +#define RV32_ENCODE_TYPE_CMMV(op, ft6, ft2, r1s, r2s) \ + ((op & 0x03) | ((ft6 & 0x3F) << 10) | ((ft2 & 0x03) << 5) | \ + ((((r1s >= ASM_RV32_REG_S0 && r1s <= ASM_RV32_REG_S1) ? \ + (r1s - ASM_RV32_REG_S0) : (r1s - ASM_RV32_REG_S2 + 2)) & 0x07) << 7) | \ + ((((r2s >= ASM_RV32_REG_S0 && r2s <= ASM_RV32_REG_S1) ? \ + (r2s - ASM_RV32_REG_S0) : (r2s - ASM_RV32_REG_S2 + 2)) & 0x07) << 2)) + + #define RV32_ENCODE_TYPE_CR(op, ft4, rs1, rs2) \ ((op & 0x03) | ((rs2 & 0x1F) << 2) | ((rs1 & 0x1F) << 7) | ((ft4 & 0x0F) << 12)) @@ -427,6 +452,42 @@ static inline void asm_rv32_opcode_cxor(asm_rv32_t *state, mp_uint_t rd, mp_uint asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CA(0x01, 0x23, 0x01, rd, rs)); } +// CM.MVA01S R1S', R2S' +static inline void asm_rv32_opcode_cmmva01s(asm_rv32_t *state, mp_uint_t r1s, mp_uint_t r2s) { + // CMMV: 101011 ... 11 ... 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CMMV(0x02, 0x2B, 0x03, r1s, r2s)); +} + +// CM.MVSA01 R1S', R2S' +static inline void asm_rv32_opcode_cmmvsa01(asm_rv32_t *state, mp_uint_t r1s, mp_uint_t r2s) { + // CMMV: 101011 ... 01 ... 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CMMV(0x02, 0x2B, 0x01, r1s, r2s)); +} + +// CM.POP {REG_LIST}, IMMEDIATE +static inline void asm_rv32_opcode_cmpop(asm_rv32_t *state, mp_uint_t reg_list, mp_uint_t immediate) { + // CMPP: 10111010 .... .. 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CMPP(0x02, 0x2E, 0x02, reg_list, immediate)); +} + +// CM.POPRET {REG_LIST}, IMMEDIATE +static inline void asm_rv32_opcode_cmpopret(asm_rv32_t *state, mp_uint_t reg_list, mp_uint_t immediate) { + // CMPP: 10111110 .... .. 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CMPP(0x02, 0x2F, 0x02, reg_list, immediate)); +} + +// CM.POPRETZ {REG_LIST}, IMMEDIATE +static inline void asm_rv32_opcode_cmpopretz(asm_rv32_t *state, mp_uint_t reg_list, mp_uint_t immediate) { + // CMPP: 10111100 .... .. 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CMPP(0x02, 0x2F, 0x00, reg_list, immediate)); +} + +// CM.PUSH {REG_LIST}, -IMMEDIATE +static inline void asm_rv32_opcode_cmpush(asm_rv32_t *state, mp_uint_t reg_list, mp_uint_t immediate) { + // CMPP: 10111000 .... .. 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CMPP(0x02, 0x2E, 0x00, reg_list, immediate)); +} + // CSRRC RD, RS, IMMEDIATE static inline void asm_rv32_opcode_csrrc(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t immediate) { // I: ............ ..... 011 ..... 1110011 @@ -583,6 +644,24 @@ static inline void asm_rv32_opcode_remu(asm_rv32_t *state, mp_uint_t rd, mp_uint asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x07, 0x01, rd, rs1, rs2)); } +// SH1ADD RD, RS1, RS2 +static inline void asm_rv32_opcode_sh1add(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0010000 ..... ..... 010 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x02, 0x10, rd, rs1, rs2)); +} + +// SH2ADD RD, RS1, RS2 +static inline void asm_rv32_opcode_sh2add(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0010000 ..... ..... 100 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x04, 0x10, rd, rs1, rs2)); +} + +// SH3ADD RD, RS1, RS2 +static inline void asm_rv32_opcode_sh3add(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0010000 ..... ..... 110 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x06, 0x10, rd, rs1, rs2)); +} + // SLL RD, RS1, RS2 static inline void asm_rv32_opcode_sll(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { // R: 0000000 ..... ..... 001 ..... 0110011 @@ -679,6 +758,20 @@ static inline void asm_rv32_opcode_xori(asm_rv32_t *state, mp_uint_t rd, mp_uint asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x13, 0x04, rd, rs, immediate)); } +#define MICROPY_RV32_EXTENSIONS \ + ((MICROPY_EMIT_RV32_ZBA ? RV32_EXT_ZBA : 0) | \ + (MICROPY_EMIT_RV32_ZCMP ? RV32_EXT_ZCMP : 0)) + +static inline uint8_t asm_rv32_allowed_extensions(void) { + uint8_t extensions = MICROPY_RV32_EXTENSIONS; + #if MICROPY_DYNAMIC_COMPILER + if (mp_dynamic_compiler.backend_options != NULL) { + extensions |= ((asm_rv32_backend_options_t *)mp_dynamic_compiler.backend_options)->allowed_extensions; + } + #endif + return extensions; +} + #define ASM_WORD_SIZE (4) #define ASM_HALFWORD_SIZE (2) @@ -687,13 +780,13 @@ static inline void asm_rv32_opcode_xori(asm_rv32_t *state, mp_uint_t rd, mp_uint #define REG_ARG_2 ASM_RV32_REG_A1 #define REG_ARG_3 ASM_RV32_REG_A2 #define REG_ARG_4 ASM_RV32_REG_A3 -#define REG_TEMP0 ASM_RV32_REG_T1 -#define REG_TEMP1 ASM_RV32_REG_T2 -#define REG_TEMP2 ASM_RV32_REG_T3 +#define REG_TEMP0 ASM_RV32_REG_A4 +#define REG_TEMP1 ASM_RV32_REG_A5 +#define REG_TEMP2 ASM_RV32_REG_A6 #define REG_FUN_TABLE ASM_RV32_REG_S1 #define REG_LOCAL_1 ASM_RV32_REG_S3 -#define REG_LOCAL_2 ASM_RV32_REG_S4 -#define REG_LOCAL_3 ASM_RV32_REG_S5 +#define REG_LOCAL_2 ASM_RV32_REG_S2 +#define REG_LOCAL_3 ASM_RV32_REG_S4 #define REG_ZERO ASM_RV32_REG_ZERO void asm_rv32_meta_comparison_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd); @@ -702,6 +795,8 @@ void asm_rv32_meta_comparison_lt(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2 void asm_rv32_meta_comparison_le(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison); void asm_rv32_emit_optimised_load_immediate(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate); +void asm_rv32_emit_load_reg_reg_reg(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size); +void asm_rv32_emit_store_reg_reg_reg(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size); #ifdef GENERIC_ASM_API @@ -709,17 +804,16 @@ void asm_rv32_emit_call_ind(asm_rv32_t *state, mp_uint_t index); void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label); void asm_rv32_emit_jump_if_reg_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t label); void asm_rv32_emit_jump_if_reg_nonzero(asm_rv32_t *state, mp_uint_t rs, mp_uint_t label); -void asm_rv32_emit_load16_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset); -void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset); +void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size); void asm_rv32_emit_mov_local_reg(asm_rv32_t *state, mp_uint_t local, mp_uint_t rs); void asm_rv32_emit_mov_reg_local_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local); void asm_rv32_emit_mov_reg_local(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local); void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label); void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs); -void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_uint_t base, mp_int_t offset); +void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_uint_t base, int32_t offset, mp_uint_t operation_size); #define ASM_T asm_rv32_t -#define ASM_ENTRY(state, labels) asm_rv32_entry(state, labels) +#define ASM_ENTRY(state, labels, name) asm_rv32_entry(state, labels) #define ASM_EXIT(state) asm_rv32_exit(state) #define ASM_END_PASS(state) asm_rv32_end_pass(state) @@ -732,12 +826,13 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_ #define ASM_JUMP_IF_REG_NONZERO(state, rs, label, bool_test) asm_rv32_emit_jump_if_reg_nonzero(state, rs, label) #define ASM_JUMP_IF_REG_ZERO(state, rs, label, bool_test) asm_rv32_emit_jump_if_reg_eq(state, rs, ASM_RV32_REG_ZERO, label) #define ASM_JUMP_REG(state, rs) asm_rv32_opcode_cjr(state, rs) -#define ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load16_reg_reg_offset(state, rd, rs, offset) -#define ASM_LOAD16_REG_REG(state, rd, rs) asm_rv32_opcode_lhu(state, rd, rs, 0) -#define ASM_LOAD32_REG_REG(state, rd, rs) ASM_LOAD_REG_REG_OFFSET(state, rd, rs, 0) -#define ASM_LOAD8_REG_REG(state, rd, rs) asm_rv32_opcode_lbu(state, rd, rs, 0) -#define ASM_LOAD_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset) -#define ASM_LOAD_REG_REG(state, rd, rs) ASM_LOAD32_REG_REG(state, rd, rs) +#define ASM_LOAD_REG_REG_OFFSET(state, rd, rs, offset) ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset) +#define ASM_LOAD8_REG_REG(state, rd, rs) ASM_LOAD8_REG_REG_OFFSET(state, rd, rs, 0) +#define ASM_LOAD16_REG_REG(state, rd, rs) ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, 0) +#define ASM_LOAD32_REG_REG(state, rd, rs) ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, 0) +#define ASM_LOAD8_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 0) +#define ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 1) +#define ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 2) #define ASM_LSL_REG_REG(state, rd, rs) asm_rv32_opcode_sll(state, rd, rd, rs) #define ASM_LSR_REG_REG(state, rd, rs) asm_rv32_opcode_srl(state, rd, rd, rs) #define ASM_MOV_LOCAL_REG(state, local, rs) asm_rv32_emit_mov_local_reg(state, local, rs) @@ -750,14 +845,22 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_ #define ASM_NEG_REG(state, rd) asm_rv32_opcode_sub(state, rd, ASM_RV32_REG_ZERO, rd) #define ASM_NOT_REG(state, rd) asm_rv32_opcode_xori(state, rd, rd, -1) #define ASM_OR_REG_REG(state, rd, rs) asm_rv32_opcode_or(state, rd, rd, rs) -#define ASM_STORE16_REG_REG(state, rs1, rs2) asm_rv32_opcode_sh(state, rs1, rs2, 0) -#define ASM_STORE32_REG_REG(state, rs1, rs2) ASM_STORE_REG_REG_OFFSET(state, rs1, rs2, 0) -#define ASM_STORE8_REG_REG(state, rs1, rs2) asm_rv32_opcode_sb(state, rs1, rs2, 0) -#define ASM_STORE_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset) -#define ASM_STORE_REG_REG(state, rs1, rs2) ASM_STORE32_REG_REG(state, rs1, rs2) +#define ASM_STORE_REG_REG_OFFSET(state, rd, rs, offset) ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) +#define ASM_STORE8_REG_REG(state, rs1, rs2) ASM_STORE8_REG_REG_OFFSET(state, rs1, rs2, 0) +#define ASM_STORE16_REG_REG(state, rs1, rs2) ASM_STORE16_REG_REG_OFFSET(state, rs1, rs2, 0) +#define ASM_STORE32_REG_REG(state, rs1, rs2) ASM_STORE32_REG_REG_OFFSET(state, rs1, rs2, 0) +#define ASM_STORE8_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 0) +#define ASM_STORE16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 1) +#define ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 2) #define ASM_SUB_REG_REG(state, rd, rs) asm_rv32_opcode_sub(state, rd, rd, rs) #define ASM_XOR_REG_REG(state, rd, rs) asm_rv32_emit_optimised_xor(state, rd, rs) -#define ASM_CLR_REG(state, rd) +#define ASM_CLR_REG(state, rd) asm_rv32_emit_optimised_xor(state, rd, rd) +#define ASM_LOAD8_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_load_reg_reg_reg(state, rd, rs1, rs2, 0) +#define ASM_LOAD16_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_load_reg_reg_reg(state, rd, rs1, rs2, 1) +#define ASM_LOAD32_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_load_reg_reg_reg(state, rd, rs1, rs2, 2) +#define ASM_STORE8_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_store_reg_reg_reg(state, rd, rs1, rs2, 0) +#define ASM_STORE16_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_store_reg_reg_reg(state, rd, rs1, rs2, 1) +#define ASM_STORE32_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_store_reg_reg_reg(state, rd, rs1, rs2, 2) #endif diff --git a/py/asmthumb.c b/py/asmthumb.c index 420815e8026..4226ae28127 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -37,7 +37,6 @@ #include "py/asmthumb.h" #include "py/misc.h" -#define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32) #define UNSIGNED_FIT7(x) ((uint32_t)(x) < 128) #define UNSIGNED_FIT8(x) (((x) & 0xffffff00) == 0) #define UNSIGNED_FIT16(x) (((x) & 0xffff0000) == 0) @@ -52,12 +51,6 @@ #define OP_SUB_W_RRI_HI(reg_src) (0xf2a0 | (reg_src)) #define OP_SUB_W_RRI_LO(reg_dest, imm11) ((imm11 << 4 & 0x7000) | reg_dest << 8 | (imm11 & 0xff)) -#define OP_LDR_W_HI(reg_base) (0xf8d0 | (reg_base)) -#define OP_LDR_W_LO(reg_dest, imm12) ((reg_dest) << 12 | (imm12)) - -#define OP_LDRH_W_HI(reg_base) (0xf8b0 | (reg_base)) -#define OP_LDRH_W_LO(reg_dest, imm12) ((reg_dest) << 12 | (imm12)) - static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) { return mp_asm_base_get_cur_to_write_bytes(&as->base, n); } @@ -253,7 +246,7 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) { void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) { assert(reg_dest < ASM_THUMB_REG_R15); // mov[wt] reg_dest, #i16_src - asm_thumb_op32(as, mov_op | ((i16_src >> 1) & 0x0400) | ((i16_src >> 12) & 0xf), ((i16_src << 4) & 0x7000) | (reg_dest << 8) | (i16_src & 0xff)); + asm_thumb_op32(as, mov_op | ((i16_src >> 1) & 0x0400) | ((i16_src >> 12) & 0xf), (((uint16_t)i16_src << 4) & 0x7000) | (reg_dest << 8) | (i16_src & 0xff)); } static void asm_thumb_mov_rlo_i16(asm_thumb_t *as, uint rlo_dest, int i16_src) { @@ -274,9 +267,8 @@ bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { #define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff)) -// all these bit-arithmetic operations need coverage testing! -#define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f)) -#define OP_BCC_W_LO(byte_offset) (0x8000 | ((byte_offset) & 0x2000) | (((byte_offset) >> 1) & 0x0fff)) +#define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 12) & 0x003f)) +#define OP_BCC_W_LO(byte_offset) (0x8000 | (((byte_offset) >> 5) & 0x2000) | (((byte_offset) >> 8) & 0x0800) | (((byte_offset) >> 1) & 0x07ff)) bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) { mp_uint_t dest = get_label_dest(as, label); @@ -432,11 +424,6 @@ void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label) { asm_thumb_add_reg_reg(as, rlo_dest, ASM_THUMB_REG_R15); // 2 bytes } -// ARMv7-M only -static inline void asm_thumb_ldr_reg_reg_i12(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) { - asm_thumb_op32(as, OP_LDR_W_HI(reg_base), OP_LDR_W_LO(reg_dest, word_offset * 4)); -} - // emits code for: reg_dest = reg_base + offset << offset_shift static void asm_thumb_add_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint offset_shift) { if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8) { @@ -450,12 +437,12 @@ static void asm_thumb_add_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint re asm_thumb_lsl_rlo_rlo_i5(as, reg_dest, reg_dest, offset_shift); asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_base); } else if (reg_dest != reg_base) { - asm_thumb_mov_rlo_i16(as, reg_dest, offset << offset_shift); - asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_dest); + asm_thumb_mov_reg_i32_optimised(as, reg_dest, offset << offset_shift); + asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_base); } else { uint reg_other = reg_dest ^ 7; asm_thumb_op16(as, OP_PUSH_RLIST((1 << reg_other))); - asm_thumb_mov_rlo_i16(as, reg_other, offset << offset_shift); + asm_thumb_mov_reg_i32_optimised(as, reg_other, offset << offset_shift); asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_other); asm_thumb_op16(as, OP_POP_RLIST((1 << reg_other))); } @@ -464,30 +451,50 @@ static void asm_thumb_add_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint re } } -void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) { - if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5(word_offset)) { - asm_thumb_ldr_rlo_rlo_i5(as, reg_dest, reg_base, word_offset); - } else if (asm_thumb_allow_armv7m(as)) { - asm_thumb_ldr_reg_reg_i12(as, reg_dest, reg_base, word_offset); +#define OP_LDR_STR_W_HI(operation_size, reg) ((0xf880 | (operation_size) << 5) | (reg)) +#define OP_LDR_STR_W_LO(reg, imm12) (((reg) << 12) | (imm12)) + +#define OP_LDR 0x01 +#define OP_STR 0x00 + +#define OP_LDR_W 0x10 +#define OP_STR_W 0x00 + +static const uint8_t OP_LDR_STR_TABLE[3] = { + 0x0E, 0x10, 0x0C +}; + +void asm_thumb_load_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size out of range."); + + if (MP_FIT_UNSIGNED(5, offset) && (reg_dest < ASM_THUMB_REG_R8) && (reg_base < ASM_THUMB_REG_R8)) { + // Can use T1 encoding + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_LDR) << 11) | (offset << 6) | (reg_base << 3) | reg_dest); + } else if (asm_thumb_allow_armv7m(as) && MP_FIT_UNSIGNED(12, offset << operation_size)) { + // Can use T3 encoding + asm_thumb_op32(as, (OP_LDR_STR_W_HI(operation_size, reg_base) | OP_LDR_W), OP_LDR_STR_W_LO(reg_dest, (offset << operation_size))); } else { - asm_thumb_add_reg_reg_offset(as, reg_dest, reg_base, word_offset - 31, 2); - asm_thumb_ldr_rlo_rlo_i5(as, reg_dest, reg_dest, 31); + // Must use the generic sequence + asm_thumb_add_reg_reg_offset(as, reg_dest, reg_base, offset - 31, operation_size); + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_LDR) << 11) | (31 << 6) | (reg_dest << 3) | (reg_dest)); } } -// ARMv7-M only -static inline void asm_thumb_ldrh_reg_reg_i12(asm_thumb_t *as, uint reg_dest, uint reg_base, uint uint16_offset) { - asm_thumb_op32(as, OP_LDRH_W_HI(reg_base), OP_LDRH_W_LO(reg_dest, uint16_offset * 2)); -} +void asm_thumb_store_reg_reg_offset(asm_thumb_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size out of range."); -void asm_thumb_ldrh_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint uint16_offset) { - if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5(uint16_offset)) { - asm_thumb_ldrh_rlo_rlo_i5(as, reg_dest, reg_base, uint16_offset); - } else if (asm_thumb_allow_armv7m(as)) { - asm_thumb_ldrh_reg_reg_i12(as, reg_dest, reg_base, uint16_offset); + if (MP_FIT_UNSIGNED(5, offset) && (reg_src < ASM_THUMB_REG_R8) && (reg_base < ASM_THUMB_REG_R8)) { + // Can use T1 encoding + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_STR) << 11) | (offset << 6) | (reg_base << 3) | reg_src); + } else if (asm_thumb_allow_armv7m(as) && MP_FIT_UNSIGNED(12, offset << operation_size)) { + // Can use T3 encoding + asm_thumb_op32(as, (OP_LDR_STR_W_HI(operation_size, reg_base) | OP_STR_W), OP_LDR_STR_W_LO(reg_src, (offset << operation_size))); } else { - asm_thumb_add_reg_reg_offset(as, reg_dest, reg_base, uint16_offset - 31, 1); - asm_thumb_ldrh_rlo_rlo_i5(as, reg_dest, reg_dest, 31); + // Must use the generic sequence + asm_thumb_op16(as, OP_PUSH_RLIST(1 << reg_base)); + asm_thumb_add_reg_reg_offset(as, reg_base, reg_base, offset - 31, operation_size); + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_STR) << 11) | (31 << 6) | (reg_base << 3) | reg_src); + asm_thumb_op16(as, OP_POP_RLIST(1 << reg_base)); } } @@ -495,6 +502,7 @@ void asm_thumb_ldrh_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint r #define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff)) #define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff)) +// In Thumb1 mode, this may clobber r1. void asm_thumb_b_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; @@ -514,19 +522,40 @@ void asm_thumb_b_label(asm_thumb_t *as, uint label) { if (asm_thumb_allow_armv7m(as)) { asm_thumb_op32(as, OP_BW_HI(rel), OP_BW_LO(rel)); } else { + // this code path has to be the same instruction size irrespective of the value of rel + bool need_align = as->base.code_offset & 2u; if (SIGNED_FIT12(rel)) { - // this code path has to be the same number of instructions irrespective of rel asm_thumb_op16(as, OP_B_N(rel)); - } else { asm_thumb_op16(as, ASM_THUMB_OP_NOP); - if (dest != (mp_uint_t)-1) { - // we have an actual branch > 12 bits; this is not handled yet - mp_raise_NotImplementedError(MP_ERROR_TEXT("native method too big")); + asm_thumb_op16(as, ASM_THUMB_OP_NOP); + asm_thumb_op16(as, ASM_THUMB_OP_NOP); + if (need_align) { + asm_thumb_op16(as, ASM_THUMB_OP_NOP); + } + } else { + // do a large jump using: + // (nop) + // ldr r1, [pc, _data] + // add pc, r1 + // _data: .word rel + // + // note: can't use r0 as a temporary because native code can have the return value + // in that register and use a large jump to get to the exit point of the function + + rel -= 2; // account for the "ldr r1, [pc, _data]" + if (need_align) { + asm_thumb_op16(as, ASM_THUMB_OP_NOP); + rel -= 2; // account for this nop } + asm_thumb_ldr_rlo_pcrel_i8(as, ASM_THUMB_REG_R1, 0); + asm_thumb_add_reg_reg(as, ASM_THUMB_REG_R15, ASM_THUMB_REG_R1); + asm_thumb_op16(as, rel & 0xffff); + asm_thumb_op16(as, rel >> 16); } } } +// In Thumb1 mode, this may clobber r1. void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; @@ -547,8 +576,15 @@ void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); } else { // reverse the sense of the branch to jump over a longer branch - asm_thumb_op16(as, OP_BCC_N(cond ^ 1, 0)); + size_t code_offset_start = as->base.code_offset; + byte *c = asm_thumb_get_cur_to_write_bytes(as, 2); asm_thumb_b_label(as, label); + size_t bytes_to_skip = as->base.code_offset - code_offset_start; + uint16_t op = OP_BCC_N(cond ^ 1, bytes_to_skip - 4); + if (c != NULL) { + c[0] = op; + c[1] = op >> 8; + } } } @@ -569,7 +605,7 @@ void asm_thumb_b_rel12(asm_thumb_t *as, int rel) { void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp) { // Load ptr to function from table, indexed by fun_id, then call it - asm_thumb_ldr_reg_reg_i12_optimised(as, reg_temp, ASM_THUMB_REG_FUN_TABLE, fun_id); + asm_thumb_load_reg_reg_offset(as, reg_temp, ASM_THUMB_REG_FUN_TABLE, fun_id, 2); asm_thumb_op16(as, OP_BLX(reg_temp)); } diff --git a/py/asmthumb.h b/py/asmthumb.h index 0584ed3227a..229912c5385 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -251,6 +251,50 @@ static inline void asm_thumb_bx_reg(asm_thumb_t *as, uint r_src) { asm_thumb_format_5(as, ASM_THUMB_FORMAT_5_BX, 0, r_src); } +// FORMAT 7: load/store with register offset +// FORMAT 8: load/store sign-extended byte/halfword + +#define ASM_THUMB_FORMAT_7_LDR (0x5800) +#define ASM_THUMB_FORMAT_7_STR (0x5000) +#define ASM_THUMB_FORMAT_7_WORD_TRANSFER (0x0000) +#define ASM_THUMB_FORMAT_7_BYTE_TRANSFER (0x0400) +#define ASM_THUMB_FORMAT_8_LDRH (0x5A00) +#define ASM_THUMB_FORMAT_8_STRH (0x5200) + +#define ASM_THUMB_FORMAT_7_8_ENCODE(op, rlo_dest, rlo_base, rlo_index) \ + ((op) | ((rlo_index) << 6) | ((rlo_base) << 3) | ((rlo_dest))) + +static inline void asm_thumb_format_7_8(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_base, uint rlo_index) { + assert(rlo_dest < ASM_THUMB_REG_R8); + assert(rlo_base < ASM_THUMB_REG_R8); + assert(rlo_index < ASM_THUMB_REG_R8); + asm_thumb_op16(as, ASM_THUMB_FORMAT_7_8_ENCODE(op, rlo_dest, rlo_base, rlo_index)); +} + +static inline void asm_thumb_ldrb_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_LDR | ASM_THUMB_FORMAT_7_BYTE_TRANSFER, rlo_dest, rlo_base, rlo_index); +} + +static inline void asm_thumb_ldrh_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_8_LDRH, rlo_dest, rlo_base, rlo_index); +} + +static inline void asm_thumb_ldr_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_LDR | ASM_THUMB_FORMAT_7_WORD_TRANSFER, rlo_dest, rlo_base, rlo_index); +} + +static inline void asm_thumb_strb_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_STR | ASM_THUMB_FORMAT_7_BYTE_TRANSFER, rlo_src, rlo_base, rlo_index); +} + +static inline void asm_thumb_strh_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_8_STRH, rlo_dest, rlo_base, rlo_index); +} + +static inline void asm_thumb_str_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_STR | ASM_THUMB_FORMAT_7_WORD_TRANSFER, rlo_src, rlo_base, rlo_index); +} + // FORMAT 9: load/store with immediate offset // For word transfers the offset must be aligned, and >>2 @@ -273,24 +317,6 @@ static inline void asm_thumb_format_9_10(asm_thumb_t *as, uint op, uint rlo_dest asm_thumb_op16(as, ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset)); } -static inline void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_src, rlo_base, word_offset); -} -static inline void asm_thumb_strb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_src, rlo_base, byte_offset); -} -static inline void asm_thumb_strh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint uint16_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_STRH, rlo_src, rlo_base, uint16_offset); -} -static inline void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_dest, rlo_base, word_offset); -} -static inline void asm_thumb_ldrb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_dest, rlo_base, byte_offset); -} -static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint uint16_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, uint16_offset); -} static inline void asm_thumb_lsl_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_src, uint shift) { asm_thumb_format_1(as, ASM_THUMB_FORMAT_1_LSL, rlo_dest, rlo_src, shift); } @@ -338,8 +364,10 @@ void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label); -void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset); // convenience -void asm_thumb_ldrh_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint uint16_offset); // convenience +// Generate optimised load dest, [src, #offset] sequence +void asm_thumb_load_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size); +// Generate optimised store src, [dest, #offset] sequence +void asm_thumb_store_reg_reg_offset(asm_thumb_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size); void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch @@ -376,12 +404,12 @@ void asm_thumb_b_rel12(asm_thumb_t *as, int rel); #define REG_FUN_TABLE ASM_THUMB_REG_FUN_TABLE -#define ASM_T asm_thumb_t -#define ASM_END_PASS asm_thumb_end_pass -#define ASM_ENTRY asm_thumb_entry -#define ASM_EXIT asm_thumb_exit +#define ASM_T asm_thumb_t +#define ASM_END_PASS asm_thumb_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_thumb_entry((as), (num_locals)) +#define ASM_EXIT asm_thumb_exit -#define ASM_JUMP asm_thumb_b_label +#define ASM_JUMP asm_thumb_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ asm_thumb_cmp_rlo_i8(as, reg, 0); \ @@ -419,18 +447,50 @@ void asm_thumb_b_rel12(asm_thumb_t *as, int rel); #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_thumb_sub_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_MUL, (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_thumb_ldr_reg_reg_i12_optimised((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrb_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrh_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_thumb_ldrh_reg_reg_i12_optimised((as), (reg_dest), (reg_base), (uint16_offset)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) - -#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_thumb_strb_rlo_rlo_i5((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_thumb_strh_rlo_rlo_i5((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_thumb_load_reg_reg_offset((as), (reg_dest), (reg_base), (byte_offset), 0) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, halfword_offset) asm_thumb_load_reg_reg_offset((as), (reg_dest), (reg_base), (halfword_offset), 1) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_thumb_load_reg_reg_offset((as), (reg_dest), (reg_base), (word_offset), 2) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_thumb_store_reg_reg_offset((as), (reg_src), (reg_base), (byte_offset), 0) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, halfword_offset) asm_thumb_store_reg_reg_offset((as), (reg_src), (reg_base), (halfword_offset), 1) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_thumb_store_reg_reg_offset((as), (reg_src), (reg_base), (word_offset), 2) + +#define ASM_LOAD8_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_thumb_ldrb_rlo_rlo_rlo((as), (reg_dest), (reg_base), (reg_index)) +#define ASM_LOAD16_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_thumb_lsl_rlo_rlo_i5((as), REG_TEMP2, (reg_index), 1); \ + asm_thumb_ldrh_rlo_rlo_rlo((as), (reg_dest), (reg_base), REG_TEMP2); \ + } while (0) +#define ASM_LOAD32_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_thumb_lsl_rlo_rlo_i5((as), REG_TEMP2, (reg_index), 2); \ + asm_thumb_ldr_rlo_rlo_rlo((as), (reg_dest), (reg_base), REG_TEMP2); \ + } while (0) +#define ASM_STORE8_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_thumb_strb_rlo_rlo_rlo((as), (reg_val), (reg_base), (reg_index)) +#define ASM_STORE16_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_thumb_op16((as), 0xB400 | (1 << reg_index)); \ + asm_thumb_lsl_rlo_rlo_i5((as), (reg_index), (reg_index), 1); \ + asm_thumb_strh_rlo_rlo_rlo((as), (reg_val), (reg_base), (reg_index)); \ + asm_thumb_op16((as), 0xBC00 | (1 << reg_index)); \ + } while (0) +#define ASM_STORE32_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_thumb_op16((as), 0xB400 | (1 << reg_index)); \ + asm_thumb_lsl_rlo_rlo_i5((as), (reg_index), (reg_index), 2); \ + asm_thumb_str_rlo_rlo_rlo((as), (reg_val), (reg_base), (reg_index)); \ + asm_thumb_op16((as), 0xBC00 | (1 << reg_index)); \ + } while (0) + +#define ASM_CLR_REG(as, reg_dest) asm_thumb_mov_rlo_i8((as), (reg_dest), 0) #endif // GENERIC_ASM_API diff --git a/py/asmx64.h b/py/asmx64.h index 03070b5f63d..8e2c2679428 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -155,12 +155,12 @@ void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32); // Holds a pointer to mp_fun_table #define REG_FUN_TABLE ASM_X64_REG_FUN_TABLE -#define ASM_T asm_x64_t -#define ASM_END_PASS asm_x64_end_pass -#define ASM_ENTRY asm_x64_entry -#define ASM_EXIT asm_x64_exit +#define ASM_T asm_x64_t +#define ASM_END_PASS asm_x64_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_x64_entry((as), (num_locals)) +#define ASM_EXIT asm_x64_exit -#define ASM_JUMP asm_x64_jmp_label +#define ASM_JUMP asm_x64_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ if (bool_test) { \ @@ -206,18 +206,23 @@ void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32); #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x64_sub_r64_r64((as), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x64_mul_r64_r64((as), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem64_to_r64((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x64_mov_mem64_to_r64((as), (reg_base), 8 * (word_offset), (reg_dest)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem8_to_r64zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 2 * (uint16_offset), (reg_dest)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem32_to_r64zx((as), (reg_base), 0, (reg_dest)) - -#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 8 * (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, qword_offset) asm_x64_mov_mem64_to_r64((as), (reg_base), 8 * (qword_offset), (reg_dest)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_x64_mov_mem8_to_r64zx((as), (reg_base), (byte_offset), (reg_dest)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 2 * (word_offset), (reg_dest)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, dword_offset) asm_x64_mov_mem32_to_r64zx((as), (reg_base), 4 * (dword_offset), (reg_dest)) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, qword_offset) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 8 * (qword_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), (byte_offset)) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 2 * (word_offset)) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (dword_offset)) + +#define ASM_CLR_REG(as, reg_dest) asm_x64_xor_r64_r64((as), (reg_dest), (reg_dest)) #endif // GENERIC_ASM_API diff --git a/py/asmx86.h b/py/asmx86.h index 7796d697626..3d95dbee733 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -150,12 +150,12 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r // Holds a pointer to mp_fun_table #define REG_FUN_TABLE ASM_X86_REG_FUN_TABLE -#define ASM_T asm_x86_t -#define ASM_END_PASS asm_x86_end_pass -#define ASM_ENTRY asm_x86_entry -#define ASM_EXIT asm_x86_exit +#define ASM_T asm_x86_t +#define ASM_END_PASS asm_x86_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_x86_entry((as), (num_locals)) +#define ASM_EXIT asm_x86_exit -#define ASM_JUMP asm_x86_jmp_label +#define ASM_JUMP asm_x86_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ if (bool_test) { \ @@ -201,18 +201,23 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x86_sub_r32_r32((as), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x86_mul_r32_r32((as), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x86_mov_mem32_to_r32((as), (reg_base), 4 * (word_offset), (reg_dest)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem8_to_r32zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 2 * (uint16_offset), (reg_dest)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest)) - -#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, dword_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (dword_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_x86_mov_mem8_to_r32zx((as), (reg_base), (byte_offset), (reg_dest)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 2 * (word_offset), (reg_dest)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, dword_offset) asm_x86_mov_mem32_to_r32((as), (reg_base), 4 * (dword_offset), (reg_dest)) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), (dword_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), (byte_offset)) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 2 * (word_offset)) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (dword_offset)) + +#define ASM_CLR_REG(as, reg_dest) asm_x86_xor_r32_r32((as), (reg_dest), (reg_dest)) #endif // GENERIC_ASM_API diff --git a/py/asmxtensa.c b/py/asmxtensa.c index 0fbe351dcf3..18aea4ea29d 100644 --- a/py/asmxtensa.c +++ b/py/asmxtensa.c @@ -34,9 +34,20 @@ #include "py/asmxtensa.h" +#if N_XTENSAWIN +#define REG_TEMP ASM_XTENSA_REG_TEMPORARY_WIN +#else +#define REG_TEMP ASM_XTENSA_REG_TEMPORARY +#endif + #define WORD_SIZE (4) +#define SIGNED_FIT6(x) ((((x) & 0xffffffe0) == 0) || (((x) & 0xffffffe0) == 0xffffffe0)) #define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)) #define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)) +#define SIGNED_FIT18(x) ((((x) & 0xfffe0000) == 0) || (((x) & 0xfffe0000) == 0xfffe0000)) + +#define ET_OUT_OF_RANGE MP_ERROR_TEXT("ERROR: xtensa %q out of range") +#define ET_NOT_ALIGNED MP_ERROR_TEXT("ERROR: %q %q not word-aligned") void asm_xtensa_end_pass(asm_xtensa_t *as) { as->num_const = as->cur_const; @@ -47,9 +58,9 @@ void asm_xtensa_end_pass(asm_xtensa_t *as) { if (as->base.pass == MP_ASM_PASS_EMIT) { uint8_t *d = as->base.code_base; printf("XTENSA ASM:"); - for (int i = 0; i < ((as->base.code_size + 15) & ~15); ++i) { + for (size_t i = 0; i < ((as->base.code_size + 15) & ~15); ++i) { if (i % 16 == 0) { - printf("\n%08x:", (uint32_t)&d[i]); + printf("\n%p:", &d[i]); } if (i % 2 == 0) { printf(" "); @@ -62,10 +73,12 @@ void asm_xtensa_end_pass(asm_xtensa_t *as) { } void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) { - // jump over the constants - asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); - mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte - as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); + if (as->num_const > 0) { + // jump over the constants + asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); + mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte + as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); + } // adjust the stack-pointer to store a0, a12, a13, a14, a15 and locals, 16-byte aligned as->stack_adjust = (((ASM_XTENSA_NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15; @@ -102,10 +115,12 @@ void asm_xtensa_exit(asm_xtensa_t *as) { } void asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals) { - // jump over the constants - asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); - mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte - as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); + if (as->num_const > 0) { + // jump over the constants + asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); + mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte + as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); + } as->stack_adjust = 32 + ((((ASM_XTENSA_NUM_REGS_SAVED_WIN + num_locals) * WORD_SIZE) + 15) & ~15); asm_xtensa_op_entry(as, ASM_XTENSA_REG_A1, as->stack_adjust); @@ -146,22 +161,60 @@ void asm_xtensa_j_label(asm_xtensa_t *as, uint label) { asm_xtensa_op_j(as, rel); } +static bool calculate_branch_displacement(asm_xtensa_t *as, uint label, ptrdiff_t *displacement) { + assert(displacement != NULL && "Displacement pointer is NULL"); + + uint32_t label_offset = get_label_dest(as, label); + *displacement = (ptrdiff_t)(label_offset - as->base.code_offset - 4); + return (label_offset != (uint32_t)-1) && (*displacement < 0); +} + void asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label) { - uint32_t dest = get_label_dest(as, label); - int32_t rel = dest - as->base.code_offset - 4; - if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT12(rel)) { - printf("ERROR: xtensa bccz out of range\n"); + ptrdiff_t rel = 0; + bool can_emit_short_jump = calculate_branch_displacement(as, label, &rel); + + if (can_emit_short_jump && SIGNED_FIT12(rel)) { + // Backwards BCCZ opcodes with an offset that fits in 12 bits can + // be emitted without any change. + asm_xtensa_op_bccz(as, cond, reg, rel); + return; + } + + // Range is effectively extended to 18 bits, as a more complex jump code + // sequence is emitted. + if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT18(rel - 6)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_bccz); } - asm_xtensa_op_bccz(as, cond, reg, rel); + + // ~BCCZ skip ; +0 <- Condition is flipped here (EQ -> NE, etc.) + // J addr ; +3 + // skip: ; +6 + asm_xtensa_op_bccz(as, cond ^ 1, reg, 6 - 4); + asm_xtensa_op_j(as, rel - 3); } void asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label) { - uint32_t dest = get_label_dest(as, label); - int32_t rel = dest - as->base.code_offset - 4; - if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT8(rel)) { - printf("ERROR: xtensa bcc out of range\n"); + ptrdiff_t rel = 0; + bool can_emit_short_jump = calculate_branch_displacement(as, label, &rel); + + if (can_emit_short_jump && SIGNED_FIT8(rel)) { + // Backwards BCC opcodes with an offset that fits in 8 bits can + // be emitted without any change. + asm_xtensa_op_bcc(as, cond, reg1, reg2, rel); + return; } - asm_xtensa_op_bcc(as, cond, reg1, reg2, rel); + + // Range is effectively extended to 18 bits, as a more complex jump code + // sequence is emitted. + if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT18(rel - 6)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_bcc); + } + + // ~BCC skip ; +0 <- Condition is flipped here (EQ -> NE, etc.) + // J addr ; +3 + // skip: ; +6 + asm_xtensa_op_bcc(as, cond ^ 8, reg1, reg2, 6 - 4); + asm_xtensa_op_j(as, rel - 3); } // convenience function; reg_dest must be different from reg_src[12] @@ -179,6 +232,8 @@ size_t asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { // store the constant in the table if (as->const_table != NULL) { as->const_table[as->cur_const] = i32; + } else { + assert((as->base.pass != MP_ASM_PASS_EMIT) && "Constants table was not built."); } ++as->cur_const; return loc; @@ -240,17 +295,53 @@ void asm_xtensa_l32i_optimised(asm_xtensa_t *as, uint reg_dest, uint reg_base, u } else if (word_offset < 256) { asm_xtensa_op_l32i(as, reg_dest, reg_base, word_offset); } else { - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("asm overflow")); + asm_xtensa_mov_reg_i32_optimised(as, reg_dest, word_offset * 4); + asm_xtensa_op_add_n(as, reg_dest, reg_base, reg_dest); + asm_xtensa_op_l32i_n(as, reg_dest, reg_dest, 0); } } -void asm_xtensa_s32i_optimised(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset) { - if (word_offset < 16) { - asm_xtensa_op_s32i_n(as, reg_src, reg_base, word_offset); - } else if (word_offset < 256) { - asm_xtensa_op_s32i(as, reg_src, reg_base, word_offset); +void asm_xtensa_load_reg_reg_offset(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + if (operation_size == 2 && MP_FIT_UNSIGNED(4, offset)) { + asm_xtensa_op_l32i_n(as, reg_dest, reg_base, offset); + return; + } + + if (MP_FIT_UNSIGNED(8, offset)) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, operation_size, reg_base, reg_dest, offset)); + return; + } + + asm_xtensa_mov_reg_i32_optimised(as, reg_dest, offset << operation_size); + asm_xtensa_op_add_n(as, reg_dest, reg_base, reg_dest); + if (operation_size == 2) { + asm_xtensa_op_l32i_n(as, reg_dest, reg_dest, 0); + } else { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, operation_size, reg_dest, reg_dest, 0)); + } +} + +void asm_xtensa_store_reg_reg_offset(asm_xtensa_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + if (operation_size == 2 && MP_FIT_UNSIGNED(4, offset)) { + asm_xtensa_op_s32i_n(as, reg_src, reg_base, offset); + return; + } + + if (MP_FIT_UNSIGNED(8, offset)) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0x04 | operation_size, reg_base, reg_src, offset)); + return; + } + + asm_xtensa_mov_reg_i32_optimised(as, REG_TEMP, offset << operation_size); + asm_xtensa_op_add_n(as, REG_TEMP, reg_base, REG_TEMP); + if (operation_size == 2) { + asm_xtensa_op_s32i_n(as, reg_src, REG_TEMP, 0); } else { - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("asm overflow")); + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0x04 | operation_size, REG_TEMP, reg_src, 0)); } } @@ -264,4 +355,47 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx) { asm_xtensa_op_callx8(as, ASM_XTENSA_REG_A8); } +void asm_xtensa_bit_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t bit, mp_uint_t label, mp_uint_t condition) { + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset - 4; + if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT8(rel)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_bit_branch); + } + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(7, condition | ((bit >> 4) & 0x01), reg, bit & 0x0F, rel & 0xFF)); +} + +void asm_xtensa_call0(asm_xtensa_t *as, mp_uint_t label) { + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset - 3; + if (as->base.pass == MP_ASM_PASS_EMIT) { + if ((dest & 0x03) != 0) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_call0, MP_QSTR_target); + } + if ((rel & 0x03) != 0) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_call0, MP_QSTR_location); + } + if (!SIGNED_FIT18(rel)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_call0); + } + } + asm_xtensa_op_call0(as, rel); +} + +void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label) { + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset; + if (as->base.pass == MP_ASM_PASS_EMIT) { + if ((dest & 0x03) != 0) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_l32r, MP_QSTR_target); + } + if ((rel & 0x03) != 0) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_l32r, MP_QSTR_location); + } + if (!SIGNED_FIT18(rel) || (rel >= 0)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_l32r); + } + } + asm_xtensa_op_l32r(as, reg, as->base.code_offset, dest); +} + #endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN diff --git a/py/asmxtensa.h b/py/asmxtensa.h index a8c39206bd0..1002511ddcc 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -64,9 +64,11 @@ #define ASM_XTENSA_REG_A14 (14) #define ASM_XTENSA_REG_A15 (15) -// for bccz +// for bccz and bcci #define ASM_XTENSA_CCZ_EQ (0) #define ASM_XTENSA_CCZ_NE (1) +#define ASM_XTENSA_CCZ_LT (2) +#define ASM_XTENSA_CCZ_GE (3) // for bcc and setcc #define ASM_XTENSA_CC_NONE (0) @@ -291,15 +293,24 @@ void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src); void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label); -void asm_xtensa_l32i_optimised(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint word_offset); -void asm_xtensa_s32i_optimised(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset); +void asm_xtensa_load_reg_reg_offset(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size); +void asm_xtensa_store_reg_reg_offset(asm_xtensa_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size); void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); +void asm_xtensa_bit_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t bit, mp_uint_t label, mp_uint_t condition); +void asm_xtensa_immediate_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t immediate, mp_uint_t label, mp_uint_t cond); +void asm_xtensa_call0(asm_xtensa_t *as, mp_uint_t label); +void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label); // Holds a pointer to mp_fun_table #define ASM_XTENSA_REG_FUN_TABLE ASM_XTENSA_REG_A15 #define ASM_XTENSA_REG_FUN_TABLE_WIN ASM_XTENSA_REG_A7 +// Internal temporary register (currently aliased to REG_ARG_5 for xtensa, +// and to REG_TEMP2 for xtensawin). +#define ASM_XTENSA_REG_TEMPORARY ASM_XTENSA_REG_A6 +#define ASM_XTENSA_REG_TEMPORARY_WIN ASM_XTENSA_REG_A12 + // CIRCUITPY-CHANGE: prevent #if warning #if defined(GENERIC_ASM_API) && GENERIC_ASM_API @@ -330,9 +341,9 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); #define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED #define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE -#define ASM_ENTRY(as, nlocal) asm_xtensa_entry((as), (nlocal)) -#define ASM_EXIT(as) asm_xtensa_exit((as)) -#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) +#define ASM_ENTRY(as, nlocal, name) asm_xtensa_entry((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) #else // Configuration for windowed calls with window size 8 @@ -360,9 +371,9 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); #define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED_WIN #define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE_WIN -#define ASM_ENTRY(as, nlocal) asm_xtensa_entry_win((as), (nlocal)) -#define ASM_EXIT(as) asm_xtensa_exit_win((as)) -#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind_win((as), (idx)) +#define ASM_ENTRY(as, nlocal, name) asm_xtensa_entry_win((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit_win((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind_win((as), (idx)) #endif @@ -408,16 +419,53 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_sub((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mull((as), (reg_dest), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_l32i_optimised((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l8ui((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), (uint16_offset)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_xtensa_load_reg_reg_offset((as), (reg_dest), (reg_base), (byte_offset), 0) +#define ASM_LOAD8_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_xtensa_op_add_n((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_l8ui((as), (reg_dest), (reg_base), 0); \ + } while (0) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, halfword_offset) asm_xtensa_load_reg_reg_offset((as), (reg_dest), (reg_base), (halfword_offset), 1) +#define ASM_LOAD16_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_xtensa_op_addx2((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), 0); \ + } while (0) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_load_reg_reg_offset((as), (reg_dest), (reg_base), (word_offset), 2) +#define ASM_LOAD32_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_xtensa_op_addx4((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), 0); \ + } while (0) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_xtensa_store_reg_reg_offset((as), (reg_src), (reg_base), (byte_offset), 0) +#define ASM_STORE8_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_xtensa_op_add_n((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_s8i((as), (reg_val), (reg_base), 0); \ + } while (0) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, halfword_offset) asm_xtensa_store_reg_reg_offset((as), (reg_src), (reg_base), (halfword_offset), 1) +#define ASM_STORE16_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_xtensa_op_addx2((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_s16i((as), (reg_val), (reg_base), 0); \ + } while (0) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_store_reg_reg_offset((as), (reg_dest), (reg_base), (word_offset), 2) +#define ASM_STORE32_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_xtensa_op_addx4((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_s32i_n((as), (reg_val), (reg_base), 0); \ + } while (0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_s32i_optimised((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s8i((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s16i((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s32i_n((as), (reg_src), (reg_base), 0) +#define ASM_CLR_REG(as, reg_dest) asm_xtensa_op_movi_n((as), (reg_dest), 0) #endif // GENERIC_ASM_API diff --git a/py/bc.c b/py/bc.c index c2956030e38..fcd8d8e1337 100644 --- a/py/bc.c +++ b/py/bc.c @@ -88,7 +88,7 @@ const byte *mp_decode_uint_skip(const byte *ptr) { return ptr; } -static NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { +static MP_NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE // generic message, used also for other argument issues (void)f; @@ -104,7 +104,7 @@ static NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, // CIRCUITPY-CHANGE: more specific mp_raise routine mp_raise_TypeError_varg( MP_ERROR_TEXT("%q() takes %d positional arguments but %d were given"), - mp_obj_fun_get_name(MP_OBJ_FROM_PTR(f)), expected, given); + mp_obj_fun_bc_get_name(f), expected, given); #endif } @@ -336,7 +336,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw mp_setup_code_state_helper(code_state, n_args, n_kw, args); } -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE // On entry code_state should be allocated somewhere (stack/heap) and // contain the following valid entries: // - code_state->fun_bc should contain a pointer to the function object diff --git a/py/bc.h b/py/bc.h index 7658f66414f..3b7a6fe1c96 100644 --- a/py/bc.h +++ b/py/bc.h @@ -226,6 +226,7 @@ typedef struct _mp_compiled_module_t { bool has_native; size_t n_qstr; size_t n_obj; + size_t arch_flags; #endif } mp_compiled_module_t; @@ -303,7 +304,7 @@ static inline void mp_module_context_alloc_tables(mp_module_context_t *context, size_t nq = (n_qstr * sizeof(qstr_short_t) + sizeof(mp_uint_t) - 1) / sizeof(mp_uint_t); size_t no = n_obj; // CIRCUITPY-CHANGE - mp_uint_t *mem = m_malloc_items(nq + no); + mp_uint_t *mem = (mp_uint_t *)m_malloc_items(nq + no); context->constants.qstr_table = (qstr_short_t *)mem; context->constants.obj_table = (mp_obj_t *)(mem + nq); #else @@ -316,25 +317,35 @@ static inline void mp_module_context_alloc_tables(mp_module_context_t *context, #endif } +typedef struct _mp_code_lineinfo_t { + size_t bc_increment; + size_t line_increment; +} mp_code_lineinfo_t; + +static inline mp_code_lineinfo_t mp_bytecode_decode_lineinfo(const byte **line_info) { + mp_code_lineinfo_t result; + size_t c = (*line_info)[0]; + if ((c & 0x80) == 0) { + // 0b0LLBBBBB encoding + result.bc_increment = c & 0x1f; + result.line_increment = c >> 5; + *line_info += 1; + } else { + // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) + result.bc_increment = c & 0xf; + result.line_increment = ((c << 4) & 0x700) | (*line_info)[1]; + *line_info += 2; + } + return result; +} + static inline size_t mp_bytecode_get_source_line(const byte *line_info, const byte *line_info_top, size_t bc_offset) { size_t source_line = 1; while (line_info < line_info_top) { - size_t c = *line_info; - size_t b, l; - if ((c & 0x80) == 0) { - // 0b0LLBBBBB encoding - b = c & 0x1f; - l = c >> 5; - line_info += 1; - } else { - // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) - b = c & 0xf; - l = ((c << 4) & 0x700) | line_info[1]; - line_info += 2; - } - if (bc_offset >= b) { - bc_offset -= b; - source_line += l; + mp_code_lineinfo_t decoded = mp_bytecode_decode_lineinfo(&line_info); + if (bc_offset >= decoded.bc_increment) { + bc_offset -= decoded.bc_increment; + source_line += decoded.line_increment; } else { // found source line corresponding to bytecode offset break; diff --git a/py/binary.c b/py/binary.c index 728f29815cd..c7fbebcaca4 100644 --- a/py/binary.c +++ b/py/binary.c @@ -42,6 +42,12 @@ #define alignof(type) offsetof(struct { char c; type t; }, t) #endif +// MicroPython V1.x truncates integers when writing into arrays, +// MicroPython V2 will raise OverflowError in these cases, same as CPython +// CIRCUITPY-CHANGE: CircuitPython raises OverflowError like CPython, +// rather than truncating like MicroPython V1.x. +#define OVERFLOW_CHECKS (1) + size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) { size_t size = 0; int align = 1; @@ -71,8 +77,7 @@ size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) { case 'Q': size = 8; break; - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'P': case 'O': case 'S': @@ -128,8 +133,7 @@ size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) { align = alignof(long long); size = sizeof(long long); break; - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'P': case 'O': case 'S': @@ -208,7 +212,7 @@ static float mp_decode_half_float(uint16_t hf) { ++e; } - fpu.i = ((hf & 0x8000) << 16) | (e << 23) | (m << 13); + fpu.i = ((hf & 0x8000u) << 16) | (e << 23) | (m << 13); return fpu.f; } @@ -289,20 +293,17 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) { #if MICROPY_PY_BUILTINS_FLOAT case 'f': return mp_obj_new_float_from_f(((float *)p)[index]); - #if MICROPY_PY_DOUBLE_TYPECODE case 'd': return mp_obj_new_float_from_d(((double *)p)[index]); #endif - #endif - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES - // Extension to CPython: array of objects + // Extension to CPython: array of objects + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'O': return ((mp_obj_t *)p)[index]; // Extension to CPython: array of pointers case 'P': return mp_obj_new_int((mp_int_t)(uintptr_t)((void **)p)[index]); - #endif + #endif } return MP_OBJ_NEW_SMALL_INT(val); } @@ -352,14 +353,11 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p); - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - if (MICROPY_NONSTANDARD_TYPECODES && (val_type == 'O')) { + if (MICROPY_PY_STRUCT_UNSAFE_TYPECODES && val_type == 'O') { return (mp_obj_t)(mp_uint_t)val; - #if MICROPY_NONSTANDARD_TYPECODES - } else if (val_type == 'S') { + } else if (MICROPY_PY_STRUCT_UNSAFE_TYPECODES && val_type == 'S') { const char *s_val = (const char *)(uintptr_t)(mp_uint_t)val; return mp_obj_new_str_from_cstr(s_val); - #endif #if MICROPY_PY_BUILTINS_FLOAT } else if (val_type == 'e') { return mp_obj_new_float_from_f(mp_decode_half_float(val)); @@ -369,7 +367,6 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * float f; } fpu = {val}; return mp_obj_new_float_from_f(fpu.f); - #if MICROPY_PY_DOUBLE_TYPECODE } else if (val_type == 'd') { union { uint64_t i; @@ -377,7 +374,6 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * } fpu = {val}; return mp_obj_new_float_from_d(fpu.f); #endif - #endif } else if (is_signed(val_type)) { if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) { return mp_obj_new_int((mp_int_t)val); @@ -393,7 +389,21 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * } } -void mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val) { +void mp_binary_set_int(size_t dest_sz, byte *dest, size_t val_sz, mp_uint_t val, bool big_endian) { + if (dest_sz > val_sz) { + // zero/sign extension if needed + int c = ((mp_int_t)val < 0) ? 0xff : 0x00; + memset(dest, c, dest_sz); + + // big endian: write val_sz bytes at end of 'dest' + if (big_endian) { + dest += dest_sz - val_sz; + } + } else if (dest_sz < val_sz) { + // truncate 'val' into 'dest' + val_sz = dest_sz; + } + if (MP_ENDIANNESS_LITTLE && !big_endian) { memcpy(dest, &val, val_sz); } else if (MP_ENDIANNESS_BIG && big_endian) { @@ -430,8 +440,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p mp_uint_t val; switch (val_type) { - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'O': val = (mp_uint_t)val_in; break; @@ -449,6 +458,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p val = fp_sp.i; break; } + // CIRCUITPY-CHANGE #if MICROPY_PY_DOUBLE_TYPECODE case 'd': { union { @@ -461,139 +471,156 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p val = fp_dp.i64; } else { int be = struct_type == '>'; - mp_binary_set_int(sizeof(uint32_t), be, p, fp_dp.i32[MP_ENDIANNESS_BIG ^ be]); + mp_binary_set_int(sizeof(uint32_t), p, sizeof(uint32_t), fp_dp.i32[MP_ENDIANNESS_BIG ^ be], be); + // Now fall through and copy the second word, below p += sizeof(uint32_t); + size = sizeof(uint32_t); val = fp_dp.i32[MP_ENDIANNESS_LITTLE ^ be]; } break; } #endif #endif - default: { - // CIRCUITPY-CHANGE: add overflow checks - bool signed_type = is_signed(val_type); + default: + // Typecode is a standard integer #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (mp_obj_is_exact_type(val_in, &mp_type_int)) { - // It's a longint. - mp_obj_int_buffer_overflow_check(val_in, size, signed_type); - mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p); + #if !OVERFLOW_CHECKS + if (size <= sizeof(mp_uint_t)) { + // Aligned store; byte-wise path corrupts word-only registers. + val = mp_obj_int_get_truncated(val_in); + break; + } + #endif + mp_obj_int_to_bytes(val_in, size, p, struct_type == '>', is_signed(val_type), OVERFLOW_CHECKS); return; } #endif - // CIRCUITPY-CHANGE: add overflow checks - { - val = mp_obj_get_int(val_in); - // Small int checking is separate, to be fast. - mp_small_int_buffer_overflow_check(val, size, signed_type); - // zero/sign extend if needed - if (MP_BYTES_PER_OBJ_WORD < 8 && size > sizeof(val)) { - int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00; - memset(p, c, size); - if (struct_type == '>') { - p += size - sizeof(val); - } - } - break; - } - } + val = mp_obj_get_int(val_in); + #if OVERFLOW_CHECKS + // CIRCUITPY-CHANGE: small ints are checked too. + mp_small_int_buffer_overflow_check(val, size, is_signed(val_type)); + #endif + break; // Fall through to mp_binary_set_int } - mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val); + mp_binary_set_int(size, p, sizeof(val), val, struct_type == '>'); } +static void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val); + void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in) { switch (typecode) { #if MICROPY_PY_BUILTINS_FLOAT case 'f': ((float *)p)[index] = mp_obj_get_float_to_f(val_in); break; - #if MICROPY_PY_DOUBLE_TYPECODE case 'd': ((double *)p)[index] = mp_obj_get_float_to_d(val_in); break; #endif - #endif - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES // Extension to CPython: array of objects case 'O': ((mp_obj_t *)p)[index] = val_in; break; #endif - default: { - // CIRCUITPY-CHANGE: add overflow checks - size_t size = mp_binary_get_size('@', typecode, NULL); - bool signed_type = is_signed(typecode); - + // In all remaining cases the type code is an integer + default: #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (mp_obj_is_exact_type(val_in, &mp_type_int)) { - // It's a long int. - mp_obj_int_buffer_overflow_check(val_in, size, signed_type); - mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG, - size, (uint8_t *)p + index * size); + size_t size = mp_binary_get_size('@', typecode, NULL); + #if !OVERFLOW_CHECKS + if (size <= sizeof(mp_int_t)) { + // Aligned store; byte-wise path corrupts word-only registers. + mp_binary_set_val_array_from_int(typecode, p, index, + mp_obj_int_get_truncated(val_in)); + return; + } + #endif + p = (uint8_t *)p + index * size; + byte *dest; + #if OVERFLOW_CHECKS + // If mp_obj_int_to_bytes() might overflow then need to write into a temporary buffer first + assert(size <= sizeof(uint64_t)); + uint64_t temp_buf; + dest = (uint8_t *)&temp_buf; + #else + dest = p; + #endif + mp_obj_int_to_bytes(val_in, size, dest, MP_ENDIANNESS_BIG, is_signed(typecode), OVERFLOW_CHECKS); + #if OVERFLOW_CHECKS + memcpy(p, dest, size); + #endif return; } #endif - // CIRCUITPY-CHANGE: add overflow checks - mp_int_t val = mp_obj_get_int(val_in); - // Small int checking is separate, to be fast. - mp_small_int_buffer_overflow_check(val, size, signed_type); - mp_binary_set_val_array_from_int(typecode, p, index, val); - } + mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in)); } } -void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val) { +#if OVERFLOW_CHECKS +#define SET_VAL_AS(TYPE, IS_SIGNED) do { \ + TYPE tmp = val; \ + if ((mp_int_t)tmp == val && (IS_SIGNED || val >= 0)) { \ + ((TYPE *)p)[index] = tmp; \ + } else { \ + goto raise; \ + } \ +} while (0) +#else +#define SET_VAL_AS(TYPE, _IS_SIGNED) do { \ + ((TYPE *)p)[index] = val; \ +} while (0) +#endif + +static void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val) { switch (typecode) { case 'b': - ((signed char *)p)[index] = val; + SET_VAL_AS(signed char, true); break; case BYTEARRAY_TYPECODE: case 'B': - ((unsigned char *)p)[index] = val; + SET_VAL_AS(unsigned char, false); break; case 'h': - ((short *)p)[index] = val; + SET_VAL_AS(short, true); break; case 'H': - ((unsigned short *)p)[index] = val; + SET_VAL_AS(unsigned short, false); break; case 'i': - ((int *)p)[index] = val; + SET_VAL_AS(int, true); break; case 'I': - ((unsigned int *)p)[index] = val; + SET_VAL_AS(unsigned int, false); break; case 'l': - ((long *)p)[index] = val; + SET_VAL_AS(long, true); break; case 'L': - ((unsigned long *)p)[index] = val; + SET_VAL_AS(unsigned long, false); break; #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE case 'q': - ((long long *)p)[index] = val; + SET_VAL_AS(long long, true); break; case 'Q': - ((unsigned long long *)p)[index] = val; - break; - #endif - #if MICROPY_PY_BUILTINS_FLOAT - case 'f': - ((float *)p)[index] = (float)val; - break; - #if MICROPY_PY_DOUBLE_TYPECODE - case 'd': - ((double *)p)[index] = (double)val; + SET_VAL_AS(unsigned long long, false); break; #endif - #endif - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES - // Extension to CPython: array of pointers + // Extension to CPython: array of pointers + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'P': ((void **)p)[index] = (void *)(uintptr_t)val; break; - #endif + #endif } + + return; + + #if OVERFLOW_CHECKS +raise: + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("integer out of range")); + #endif } diff --git a/py/binary.h b/py/binary.h index 5c645bcaaa9..851dc50110e 100644 --- a/py/binary.h +++ b/py/binary.h @@ -37,10 +37,9 @@ size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign); mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index); void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in); -void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val); mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr); void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr); long long mp_binary_get_int(size_t size, bool is_signed, bool big_endian, const byte *src); -void mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val); +void mp_binary_set_int(size_t dest_sz, byte *dest, size_t val_sz, mp_uint_t val, bool big_endian); #endif // MICROPY_INCLUDED_PY_BINARY_H diff --git a/py/builtin.h b/py/builtin.h index 6efe3e8faca..388bc847005 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -138,6 +138,7 @@ extern const mp_obj_module_t mp_module_sys; extern const mp_obj_module_t mp_module_errno; extern const mp_obj_module_t mp_module_uctypes; extern const mp_obj_module_t mp_module_machine; +extern const mp_obj_module_t mp_module_math; extern const char MICROPY_PY_BUILTINS_HELP_TEXT[]; diff --git a/py/builtinhelp.c b/py/builtinhelp.c index d041d6915a6..d3d7aa402c8 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -31,10 +31,19 @@ #include "genhdr/mpversion.h" #include "py/builtin.h" #include "py/mpconfig.h" +#include "py/objlist.h" #include "py/objmodule.h" #if MICROPY_PY_BUILTINS_HELP +#if MICROPY_PY_BUILTINS_HELP_NUM_COLUMNS <= 0 +#error "MICROPY_PY_BUILTINS_HELP_NUM_COLUMNS must be more than 0" +#endif + +#if MICROPY_PY_BUILTINS_HELP_COLUMN_WIDTH <= 0 +#error "MICROPY_PY_BUILTINS_HELP_COLUMN_WIDTH must be more than 0" +#endif + const char mp_help_default_text[] = "Welcome to MicroPython!\n" "\n" @@ -98,12 +107,10 @@ static void mp_help_print_modules(void) { mp_obj_list_sort(1, &list, (mp_map_t *)&mp_const_empty_map); // print the list of modules in a column-first order - #define NUM_COLUMNS (4) - #define COLUMN_WIDTH (18) size_t len; mp_obj_t *items; mp_obj_list_get(list, &len, &items); - unsigned int num_rows = (len + NUM_COLUMNS - 1) / NUM_COLUMNS; + unsigned int num_rows = (len + MICROPY_PY_BUILTINS_HELP_NUM_COLUMNS - 1) / MICROPY_PY_BUILTINS_HELP_NUM_COLUMNS; for (unsigned int i = 0; i < num_rows; ++i) { unsigned int j = i; for (;;) { @@ -112,9 +119,9 @@ static void mp_help_print_modules(void) { if (j >= len) { break; } - int gap = COLUMN_WIDTH - l; + int gap = MICROPY_PY_BUILTINS_HELP_COLUMN_WIDTH - l; while (gap < 1) { - gap += COLUMN_WIDTH; + gap += MICROPY_PY_BUILTINS_HELP_COLUMN_WIDTH; } while (gap--) { mp_print_str(MP_PYTHON_PRINTER, " "); @@ -162,9 +169,8 @@ static void mp_help_print_obj(const mp_obj_t obj) { } if (map != NULL) { for (uint i = 0; i < map->alloc; i++) { - mp_obj_t key = map->table[i].key; - if (key != MP_OBJ_NULL) { - mp_help_print_info_about_object(key, map->table[i].value); + if (mp_map_slot_is_filled(map, i)) { + mp_help_print_info_about_object(map->table[i].key, map->table[i].value); } } } diff --git a/py/builtinimport.c b/py/builtinimport.c index e4e06d8e2cc..ff5b02979ee 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -105,7 +105,26 @@ static mp_import_stat_t stat_module(vstr_t *path) { mp_import_stat_t stat = stat_path(path); DEBUG_printf("stat %s: %d\n", vstr_str(path), stat); if (stat == MP_IMPORT_STAT_DIR) { - return stat; + // CIRCUITPY-CHANGE: match CPython import precedence. A regular + // package (directory with __init__.py/.mpy) takes precedence, then a + // sibling .py/.mpy module, and only then a namespace package + // (directory without __init__). See + // https://docs.python.org/3/reference/import.html#regular-packages + size_t orig_len = path->len; + vstr_add_str(path, PATH_SEP_CHAR "__init__.py"); + mp_import_stat_t init_stat = stat_file_py_or_mpy(path); + path->len = orig_len; + if (init_stat == MP_IMPORT_STAT_FILE) { + return MP_IMPORT_STAT_DIR; + } + + vstr_add_str(path, ".py"); + mp_import_stat_t file_stat = stat_file_py_or_mpy(path); + if (file_stat == MP_IMPORT_STAT_FILE) { + return file_stat; + } + path->len = orig_len; + return MP_IMPORT_STAT_DIR; } // Not a directory, add .py and try as a file. @@ -118,7 +137,7 @@ static mp_import_stat_t stat_module(vstr_t *path) { // path (i.e. "/mod_name(.py)"). static mp_import_stat_t stat_top_level(qstr mod_name, vstr_t *dest) { DEBUG_printf("stat_top_level: '%s'\n", qstr_str(mod_name)); - #if MICROPY_PY_SYS + #if MICROPY_PY_SYS && MICROPY_PY_SYS_PATH size_t path_num; mp_obj_t *path_items; mp_obj_get_array(mp_sys_path, &path_num, &path_items); @@ -155,7 +174,7 @@ static mp_import_stat_t stat_top_level(qstr mod_name, vstr_t *dest) { #if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER static void do_load_from_lexer(mp_module_context_t *context, mp_lexer_t *lex) { - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ qstr source_name = lex->source_name; mp_store_attr(MP_OBJ_FROM_PTR(&context->module), MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif @@ -168,7 +187,7 @@ static void do_load_from_lexer(mp_module_context_t *context, mp_lexer_t *lex) { #if (MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD) || MICROPY_MODULE_FROZEN_MPY static void do_execute_proto_fun(const mp_module_context_t *context, mp_proto_fun_t proto_fun, qstr source_name) { - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ mp_store_attr(MP_OBJ_FROM_PTR(&context->module), MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #else (void)source_name; @@ -227,7 +246,7 @@ static void do_load(mp_module_context_t *module_obj, vstr_t *file) { if (frozen_type == MP_FROZEN_MPY) { const mp_frozen_module_t *frozen = modref; module_obj->constants = frozen->constants; - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ qstr frozen_file_qstr = qstr_from_str(file_str + frozen_path_prefix_len); #else qstr frozen_file_qstr = MP_QSTRnull; @@ -240,7 +259,9 @@ static void do_load(mp_module_context_t *module_obj, vstr_t *file) { #endif // MICROPY_MODULE_FROZEN + #if MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER) qstr file_qstr = qstr_from_str(file_str); + #endif // If we support loading .mpy files then check if the file extension is of // the correct format and, if so, load and execute the file. @@ -270,7 +291,7 @@ static void do_load(mp_module_context_t *module_obj, vstr_t *file) { // Convert a relative (to the current module) import, going up "level" levels, // into an absolute import. -static void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len) { +static void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len, mp_obj_t globals) { // What we want to do here is to take the name of the current module, // remove trailing components, and concatenate the passed-in // module name. @@ -279,7 +300,7 @@ static void evaluate_relative_import(mp_int_t level, const char **module_name, s // module's position in the package hierarchy." // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name - mp_obj_t current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); + mp_obj_t current_module_name_obj = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__)); assert(current_module_name_obj != MP_OBJ_NULL); #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT && MICROPY_CPYTHON_COMPAT @@ -287,12 +308,12 @@ static void evaluate_relative_import(mp_int_t level, const char **module_name, s // This is a module loaded by -m command-line switch (e.g. unix port), // and so its __name__ has been set to "__main__". Get its real name // that we stored during import in the __main__ attribute. - current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + current_module_name_obj = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); } #endif // If we have a __path__ in the globals dict, then we're a package. - bool is_pkg = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); + bool is_pkg = mp_map_lookup(mp_obj_dict_get_map(globals), MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); #if DEBUG_PRINT DEBUG_printf("Current module/package: "); @@ -370,7 +391,7 @@ static mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, // Immediately return if the module at this level is already loaded. mp_map_elem_t *elem; - #if MICROPY_PY_SYS + #if MICROPY_PY_SYS && MICROPY_PY_SYS_PATH // If sys.path is empty, the intention is to force using a built-in. This // means we should also ignore any loaded modules with the same name // which may have come from the filesystem. @@ -406,6 +427,7 @@ static mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, // all the locations in sys.path. stat = stat_top_level(level_mod_name, &path); + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES // If filesystem failed, now try and see if it matches an extensible // built-in module. if (stat == MP_IMPORT_STAT_NO_EXIST) { @@ -414,6 +436,7 @@ static mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, return module_obj; } } + #endif } else { DEBUG_printf("Searching for sub-module\n"); @@ -577,10 +600,19 @@ mp_obj_t mp_builtin___import___default(size_t n_args, const mp_obj_t *args) { const char *module_name = mp_obj_str_get_data(module_name_obj, &module_name_len); if (level != 0) { + // This is the dict with all global symbols. + mp_obj_t globals = MP_OBJ_FROM_PTR(mp_globals_get()); + if (n_args >= 2 && args[1] != mp_const_none) { + globals = args[1]; + if (!mp_obj_is_type(globals, &mp_type_dict)) { + mp_raise_TypeError(NULL); + } + } + // Turn "foo.bar" with level=3 into ".foo.bar". // Current module name is extracted from globals().__name__. - evaluate_relative_import(level, &module_name, &module_name_len); // module_name is now an absolute module path. + evaluate_relative_import(level, &module_name, &module_name_len, globals); } if (module_name_len == 0) { @@ -656,11 +688,13 @@ mp_obj_t mp_builtin___import___default(size_t n_args, const mp_obj_t *args) { if (module_obj != MP_OBJ_NULL) { return module_obj; } + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES // Now try as an extensible built-in (e.g. `time`). module_obj = mp_module_get_builtin(module_name_qstr, true); if (module_obj != MP_OBJ_NULL) { return module_obj; } + #endif // Couldn't find the module, so fail #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk old mode 100644 new mode 100755 index d6569bc39bd..d91ac8ad23b --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -122,6 +122,9 @@ endif ifeq ($(CIRCUITPY_AUDIOBUSIO),1) SRC_PATTERNS += audiobusio/% endif +ifeq ($(CIRCUITPY_AUDIOI2SIN),1) +SRC_PATTERNS += audioi2sin/% +endif ifeq ($(CIRCUITPY_AUDIOIO),1) SRC_PATTERNS += audioio/% endif @@ -146,6 +149,12 @@ endif ifeq ($(CIRCUITPY_AUDIOMP3),1) SRC_PATTERNS += audiomp3/% endif +ifeq ($(CIRCUITPY_AUDIOSPEED),1) +SRC_PATTERNS += audiospeed/% +endif +ifeq ($(CIRCUITPY_AUDIOFILEWRITER),1) +SRC_PATTERNS += audiofilewriter/% +endif ifeq ($(CIRCUITPY_AURORA_EPAPER),1) SRC_PATTERNS += aurora_epaper/% endif @@ -201,12 +210,18 @@ endif ifeq ($(CIRCUITPY_DISPLAYIO),1) SRC_PATTERNS += displayio/% endif +ifeq ($(CIRCUITPY_DOTCLOCKFRAMEBUFFER),1) +SRC_PATTERNS += dotclockframebuffer/% +endif ifeq ($(CIRCUITPY_DUALBANK),1) SRC_PATTERNS += dualbank/% endif ifeq ($(CIRCUITPY__EVE),1) SRC_PATTERNS += _eve/% endif +ifeq ($(CIRCUITPY_EMMCIO),1) +SRC_PATTERNS += emmcio/% +endif ifeq ($(CIRCUITPY_EPAPERDISPLAY),1) SRC_PATTERNS += epaperdisplay/% endif @@ -255,6 +270,9 @@ endif ifeq ($(CIRCUITPY_I2CTARGET),1) SRC_PATTERNS += i2ctarget/% endif +ifeq ($(CIRCUITPY_I2CIOEXPANDER),1) +SRC_PATTERNS += i2cioexpander/% +endif ifeq ($(CIRCUITPY_IMAGECAPTURE),1) SRC_PATTERNS += imagecapture/% endif @@ -282,6 +300,9 @@ endif ifeq ($(CIRCUITPY_MAX3421E),1) SRC_PATTERNS += max3421e/% endif +ifeq ($(CIRCUITPY_MCP4822),1) +SRC_PATTERNS += mcp4822/% +endif ifeq ($(CIRCUITPY_MDNS),1) SRC_PATTERNS += mdns/% endif @@ -294,6 +315,9 @@ endif ifeq ($(CIRCUITPY_MICROCONTROLLER),1) SRC_PATTERNS += microcontroller/% endif +ifeq ($(CIRCUITPY_MIPIDSI),1) +SRC_PATTERNS += mipidsi/% +endif ifeq ($(CIRCUITPY_MSGPACK),1) SRC_PATTERNS += msgpack/% endif @@ -348,8 +372,8 @@ endif ifeq ($(CIRCUITPY_RGBMATRIX),1) SRC_PATTERNS += rgbmatrix/% endif -ifeq ($(CIRCUITPY_DOTCLOCKFRAMEBUFFER),1) -SRC_PATTERNS += dotclockframebuffer/% +ifeq ($(CIRCUITPY_QSPIBUS),1) +SRC_PATTERNS += qspibus/% endif ifeq ($(CIRCUITPY_RP2PIO),1) SRC_PATTERNS += rp2pio/% @@ -384,6 +408,9 @@ endif ifeq ($(CIRCUITPY_STAGE),1) SRC_PATTERNS += _stage/% endif +ifeq ($(CIRCUITPY_PICOGAME),1) +SRC_PATTERNS += picogame/% +endif ifeq ($(CIRCUITPY_STORAGE),1) SRC_PATTERNS += storage/% endif @@ -432,6 +459,9 @@ endif ifeq ($(CIRCUITPY_USB_VIDEO),1) SRC_PATTERNS += usb_video/% endif +ifeq ($(CIRCUITPY_USB_AUDIO),1) +SRC_PATTERNS += usb_audio/% +endif ifeq ($(CIRCUITPY_USB_HOST),1) SRC_PATTERNS += usb_host/% endif @@ -459,6 +489,9 @@ endif ifeq ($(CIRCUITPY_WIFI),1) SRC_PATTERNS += wifi/% endif +ifeq ($(CIRCUITPY_WIZNET),1) +SRC_PATTERNS += wiznet/% +endif ifeq ($(CIRCUITPY_ZLIB),1) SRC_PATTERNS += zlib/% endif @@ -490,6 +523,8 @@ SRC_COMMON_HAL_ALL = \ audiobusio/I2SOut.c \ audiobusio/PDMIn.c \ audiobusio/__init__.c \ + audioi2sin/I2SIn.c \ + audioi2sin/__init__.c \ audioio/AudioOut.c \ audioio/__init__.c \ audiopwmio/PWMAudioOut.c \ @@ -511,6 +546,8 @@ SRC_COMMON_HAL_ALL = \ dotclockframebuffer/DotClockFramebuffer.c \ dotclockframebuffer/__init__.c \ dualbank/__init__.c \ + emmcio/EMMC.c \ + emmcio/__init__.c \ floppyio/__init__.c \ frequencyio/FrequencyIn.c \ frequencyio/__init__.c \ @@ -523,6 +560,8 @@ SRC_COMMON_HAL_ALL = \ i2ctarget/I2CTarget.c \ i2ctarget/__init__.c \ max3421e/Max3421E.c \ + mcp4822/__init__.c \ + mcp4822/MCP4822.c \ memorymap/__init__.c \ memorymap/AddressRange.c \ microcontroller/__init__.c \ @@ -531,6 +570,9 @@ SRC_COMMON_HAL_ALL = \ mdns/__init__.c \ mdns/Server.c \ mdns/RemoteService.c \ + mipidsi/Bus.c \ + mipidsi/Display.c \ + mipidsi/__init__.c \ neopixel_write/__init__.c \ nvm/ByteArray.c \ nvm/__init__.c \ @@ -543,6 +585,8 @@ SRC_COMMON_HAL_ALL = \ pulseio/__init__.c \ pwmio/PWMOut.c \ pwmio/__init__.c \ + qspibus/QSPIBus.c \ + qspibus/__init__.c \ rclcpy/__init__.c \ rclcpy/Node.c \ rclcpy/Publisher.c \ @@ -570,6 +614,12 @@ SRC_COMMON_HAL_ALL = \ wifi/ScannedNetworks.c \ wifi/__init__.c \ +# The fast Display backend is the only common-hal picogame source; include it +# only on ports that provide it (others use the portable bus.send renderer). +ifeq ($(CIRCUITPY_PICOGAME_FAST_DISPLAY),1) +SRC_COMMON_HAL_ALL += picogame/Display.c +endif + SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL)) ifeq ($(CIRCUITPY_BLEIO_HCI),1) @@ -597,6 +647,11 @@ endif # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_BINDINGS_ENUMS = \ $(filter $(SRC_PATTERNS), \ + picogame/Bitmap.c \ + picogame/Sprite.c \ + picogame/StripDraw.c \ + picogame/Triangles.c \ + picogame/Framebuffer.c \ _bleio/Address.c \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ @@ -606,6 +661,7 @@ $(filter $(SRC_PATTERNS), \ canio/Match.c \ codeop/__init__.c \ countio/Edge.c \ + digitalio/DigitalInOutProtocol.c \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ @@ -667,15 +723,25 @@ SRC_SHARED_MODULE_ALL = \ _stage/Layer.c \ _stage/Text.c \ _stage/__init__.c \ + picogame/__init__.c \ + picogame/Scene.c \ + picogame/Tilemap.c \ + picogame/Particles.c \ + picogame/Canvas.c \ aesio/__init__.c \ aesio/aes.c \ atexit/__init__.c \ audiocore/RawSample.c \ audiocore/WaveFile.c \ audiocore/__init__.c \ + audiospeed/Resampler.c \ + audiospeed/SpeedChanger.c \ + audiospeed/__init__.c \ audiodelays/Echo.c \ audiodelays/Chorus.c \ + audiodelays/Flanger.c \ audiodelays/PitchShift.c \ + audiodelays/GranularPitchShift.c \ audiodelays/MultiTapDelay.c \ audiodelays/__init__.c \ audiofilters/Distortion.c \ @@ -684,6 +750,8 @@ SRC_SHARED_MODULE_ALL = \ audiofilters/__init__.c \ audiofreeverb/__init__.c \ audiofreeverb/Freeverb.c \ + audiofilewriter/AudioFileWriter.c \ + audiofilewriter/__init__.c \ audioio/__init__.c \ audiomixer/Mixer.c \ audiomixer/MixerVoice.c \ @@ -717,8 +785,12 @@ SRC_SHARED_MODULE_ALL = \ displayio/area.c \ displayio/__init__.c \ dotclockframebuffer/__init__.c \ + emmcio/__init__.c \ epaperdisplay/__init__.c \ epaperdisplay/EPaperDisplay.c \ + i2cioexpander/IOExpander.c \ + i2cioexpander/IOPin.c \ + i2cioexpander/__init__.c \ floppyio/__init__.c \ fontio/BuiltinFont.c \ fontio/__init__.c \ @@ -901,15 +973,58 @@ $(BUILD)/lib/tjpgd/src/tjpgd.o: CFLAGS += -Wno-shadow -Wno-cast-align endif ifeq ($(CIRCUITPY_HASHLIB_MBEDTLS_ONLY),1) -SRC_MOD += $(addprefix lib/mbedtls/library/, \ - sha1.c \ - sha256.c \ - sha512.c \ - platform_util.c \ - ) +# mbedtls 4.x moved the crypto implementations out of lib/mbedtls/library into the +# tf-psa-crypto submodule and made the legacy mbedtls_sha256_*() headers private, so +# hashlib goes through the PSA hash API. That needs the PSA core, whose driver dispatch +# layer is generated rather than shipped -- see the same rule in ports/raspberrypi/Makefile. +SRC_MOD += \ + $(addprefix lib/mbedtls/tf-psa-crypto/core/, \ + psa_crypto.c \ + psa_crypto_client.c \ + psa_crypto_slot_management.c \ + psa_util.c \ + ) \ + $(addprefix lib/mbedtls/tf-psa-crypto/drivers/builtin/src/, \ + psa_crypto_hash.c \ + psa_util_internal.c \ + sha1.c \ + sha256.c \ + ) \ + $(addprefix lib/mbedtls/tf-psa-crypto/platform/, \ + platform.c \ + platform_util.c \ + ) \ + lib/mbedtls/tf-psa-crypto/utilities/constant_time.c \ + lib/mbedtls_config/hashlib_psa_port.c + +MBEDTLS_HASHLIB_GEN := $(BUILD)/tf-psa-crypto +MBEDTLS_HASHLIB_WRAPPERS_H := $(MBEDTLS_HASHLIB_GEN)/psa_crypto_driver_wrappers.h +MBEDTLS_HASHLIB_WRAPPERS_C := $(MBEDTLS_HASHLIB_GEN)/psa_crypto_driver_wrappers_no_static.c +SRC_MOD += $(MBEDTLS_HASHLIB_WRAPPERS_C:$(BUILD)/%=%) + +# The script writes both files at once; naming both as targets would run it twice. +$(MBEDTLS_HASHLIB_WRAPPERS_C): $(MBEDTLS_HASHLIB_WRAPPERS_H) + @true + +$(MBEDTLS_HASHLIB_WRAPPERS_H): $(TOP)/lib/mbedtls/tf-psa-crypto/scripts/generate_driver_wrappers.py + $(STEPECHO) "GEN $@" + $(Q)mkdir -p $(MBEDTLS_HASHLIB_GEN) + $(Q)PYTHONPATH=$(TOP)/lib/mbedtls/framework/scripts $(PYTHON) $< $(MBEDTLS_HASHLIB_GEN) + +# psa_crypto.c and friends #include the generated header. +$(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)): $(MBEDTLS_HASHLIB_WRAPPERS_H) + CFLAGS += \ - -isystem $(TOP)/lib/mbedtls/include \ - -DMBEDTLS_CONFIG_FILE='"$(TOP)/lib/mbedtls_config/mbedtls_config_hashlib.h"' \ + -I$(MBEDTLS_HASHLIB_GEN) \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/include \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/drivers/builtin/include \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/drivers/builtin/src \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/core \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/dispatch \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/extras \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/platform \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/utilities \ + -DTF_PSA_CRYPTO_CONFIG_FILE='"$(TOP)/lib/mbedtls_config/tf_psa_crypto_config_hashlib.h"' \ endif @@ -946,7 +1061,6 @@ SRC_SHARED_MODULE_INTERNAL = \ $(filter $(SRC_PATTERNS), \ displayio/bus_core.c \ displayio/display_core.c \ - os/getenv.c \ usb/utf16le.c \ ) @@ -992,7 +1106,6 @@ endif # Sources used in all ports except unix. SRC_CIRCUITPY_COMMON = \ - shared/libc/string0.c \ shared/readline/readline.c \ lib/oofatfs/ff.c \ lib/oofatfs/ffunicode.c \ @@ -1004,6 +1117,10 @@ SRC_CIRCUITPY_COMMON = \ shared/runtime/stdout_helpers.c \ shared/runtime/sys_stdio_mphal.c +ifeq ($(CIRCUITPY_LIBC_STRING0),1) +SRC_CIRCUITPY_COMMON += shared/libc/string0.c +endif + ifeq ($(CIRCUITPY_QRIO),1) SRC_CIRCUITPY_COMMON += lib/quirc/lib/decode.c lib/quirc/lib/identify.c lib/quirc/lib/quirc.c lib/quirc/lib/version_db.c $(BUILD)/lib/quirc/lib/%.o: CFLAGS += -Wno-type-limits -Wno-shadow -Wno-sign-compare -include shared-module/qrio/quirc_alloc.h diff --git a/py/circuitpy_mkenv.mk b/py/circuitpy_mkenv.mk index 7bdf943a14d..6416d6bd19c 100644 --- a/py/circuitpy_mkenv.mk +++ b/py/circuitpy_mkenv.mk @@ -43,6 +43,10 @@ ifneq ($(VALID_BOARD),) include boards/$(BOARD)/mpconfigboard.mk endif +# user-specific settings that mpconfigport does not override +# (i.e. mpconfigport.mk uses "foo ?= bar") +-include user_pre_mpconfigport.mk + # Port-specific include mpconfigport.mk @@ -52,6 +56,10 @@ ifneq ($(VALID_BOARD),) include $(TOP)/py/circuitpy_mpconfig.mk endif +# user-specific overrides of hard-coded settings +# (i.e. xxx.mk uses "foo = bar") +-include user_post_mpconfigport.mk + # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h @@ -62,3 +70,6 @@ include $(TOP)/supervisor/supervisor.mk # Include make rules and variables common across CircuitPython builds. include $(TOP)/py/circuitpy_defns.mk + +# user specific +-include user_post_circuitpy_defns.mk diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 2754d57b01c..53c4b955688 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -17,6 +17,10 @@ // Always 1: defined in circuitpy_mpconfig.mk // #define CIRCUITPY (1) +#ifndef MP_SSIZE_MAX +#define MP_SSIZE_MAX (0x7fffffff) +#endif + // REPR_C encodes qstrs, 31-bit ints, and 30-bit floats in a single 32-bit word. #ifndef MICROPY_OBJ_REPR #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C) @@ -42,10 +46,18 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_PY_BLUETOOTH (0) #define MICROPY_PY_LWIP_SLIP (0) #define MICROPY_PY_OS_DUPTERM (0) +#define MICROPY_PYEXEC_COMPILE_ONLY (0) #define MICROPY_ROM_TEXT_COMPRESSION (0) #define MICROPY_VFS_LFS1 (0) #define MICROPY_VFS_LFS2 (0) +// Always turn on exit code handling +#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (1) + +#ifndef MICROPY_GCREGS_SETJMP +#define MICROPY_GCREGS_SETJMP (0) +#endif + // Sorted alphabetically for easy finding. // // default is 128; consider raising to reduce fragmentation. @@ -66,7 +78,9 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_ENABLE_SELECTIVE_COLLECT (1) #define MICROPY_ENABLE_GC (1) #define MICROPY_ENABLE_PYSTACK (1) -#define MICROPY_TRACKED_ALLOC (CIRCUITPY_SSL_MBEDTLS) +// mbedtls allocates through m_tracked_calloc/m_tracked_free. hashlib-only ports need +// them too as of mbedtls 4.x: hashlib uses mbedtls_md_*(), which allocates on the heap. +#define MICROPY_TRACKED_ALLOC (CIRCUITPY_SSL_MBEDTLS || CIRCUITPY_HASHLIB_MBEDTLS_ONLY) #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_EPOCH_IS_1970 (1) #define MICROPY_ERROR_REPORTING (CIRCUITPY_FULL_BUILD ? MICROPY_ERROR_REPORTING_NORMAL : MICROPY_ERROR_REPORTING_TERSE) @@ -84,7 +98,6 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_MEM_STATS (0) #define MICROPY_MODULE_BUILTIN_INIT (1) #define MICROPY_MODULE_BUILTIN_SUBPACKAGES (1) -#define MICROPY_NONSTANDARD_TYPECODES (0) #define MICROPY_OPT_COMPUTED_GOTO (1) #define MICROPY_OPT_COMPUTED_GOTO_SAVE_SPACE (CIRCUITPY_COMPUTED_GOTO_SAVE_SPACE) #define MICROPY_OPT_LOAD_ATTR_FAST_PATH (CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH) @@ -92,6 +105,7 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_OPT_MPZ_BITWISE (0) #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) #define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_PERSISTENT_CODE_LOAD_NATIVE (CIRCUITPY_LOAD_NATIVE || CIRCUITPY_ENABLE_MPY_NATIVE) #define MICROPY_PY_ARRAY (CIRCUITPY_ARRAY) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) @@ -137,6 +151,7 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_PY_RE (CIRCUITPY_RE) // Supplanted by shared-bindings/struct #define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_STRUCT_UNSAFE_TYPECODES (0) #define MICROPY_PY_SYS (CIRCUITPY_SYS) #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_STDFILES (1) @@ -177,6 +192,9 @@ extern void common_hal_mcu_enable_interrupts(void); #define FILESYSTEM_BLOCK_SIZE (512) #define MICROPY_VFS (1) +// CIRCUITPY-CHANGE: CircuitPython's flash/SD block devices are native +// (supervisor/shared/flash.c sets MP_BLOCKDEV_FLAG_NATIVE). +#define MICROPY_VFS_BLOCKDEV_NATIVE (1) #define MICROPY_VFS_FAT (MICROPY_VFS) #define MICROPY_READER_VFS (MICROPY_VFS) @@ -184,26 +202,16 @@ extern void common_hal_mcu_enable_interrupts(void); #define BYTES_PER_WORD (4) +// Bit 0 of a code pointer selects the Thumb instruction set. +#if defined(__thumb__) #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1)) +#else +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)(p)) +#endif // Track stack usage. Expose results via ustack module. #define MICROPY_MAX_STACK_USAGE (0) -#define UINT_FMT "%u" -#define INT_FMT "%d" -#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 of actual size. -typedef int mp_int_t; // must be pointer size -typedef unsigned int mp_uint_t; // must be pointer size -#endif -#if __GNUC__ >= 10 // on recent gcc versions we can check that this is so -_Static_assert(sizeof(mp_int_t) == sizeof(void *)); -_Static_assert(sizeof(mp_uint_t) == sizeof(void *)); -#endif typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) @@ -265,6 +273,10 @@ typedef long mp_off_t; #define MICROPY_PY_COLLECTIONS_DEQUE_SUBSCR (CIRCUITPY_FULL_BUILD) #endif +#ifndef MICROPY_PY_DELATTR_SETATTR +#define MICROPY_PY_DELATTR_SETATTR (CIRCUITPY_FULL_BUILD) +#endif + #ifndef MICROPY_PY_DOUBLE_TYPECODE #define MICROPY_PY_DOUBLE_TYPECODE (CIRCUITPY_FULL_BUILD ? 1 : 0) #endif @@ -299,12 +311,10 @@ typedef long mp_off_t; #ifdef LONGINT_IMPL_MPZ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) -#define MP_SSIZE_MAX (0x7fffffff) #endif #ifdef LONGINT_IMPL_LONGLONG #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) -#define MP_SSIZE_MAX (0x7fffffff) #endif #ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS @@ -317,10 +327,17 @@ typedef long mp_off_t; // Default board buses. +#ifndef CIRCUITPY_MUTABLE_BOARD +#define CIRCUITPY_MUTABLE_BOARD (0) +#endif + #ifndef CIRCUITPY_BOARD_I2C #if defined(DEFAULT_I2C_BUS_SCL) && defined(DEFAULT_I2C_BUS_SDA) #define CIRCUITPY_BOARD_I2C (1) #define CIRCUITPY_BOARD_I2C_PIN {{.scl = DEFAULT_I2C_BUS_SCL, .sda = DEFAULT_I2C_BUS_SDA}} +#ifndef CIRCUITPY_BOARD_I2C_SPEED +#define CIRCUITPY_BOARD_I2C_SPEED (100000) +#endif #else #define CIRCUITPY_BOARD_I2C (0) #endif @@ -383,9 +400,11 @@ typedef long mp_off_t; #define CIRCUITPY_DISPLAY_LIMIT (1) #endif -// Framebuffer area size in bytes. Rounded down to power of four for alignment. +// Display area buffer size in bytes for _refresh_area() VLA. +// Allocated on stack; boards with larger displays can override per-board. +// Default 512 bytes = 128 uint32_t words. #ifndef CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE -#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (128) +#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (512) #endif #else @@ -520,6 +539,11 @@ void background_callback_run_all(void); #ifndef CIRCUITPY_SDCARD_USB #if CIRCUITPY_USB_DEVICE #define CIRCUITPY_SDCARD_USB (CIRCUITPY_SDCARDIO && CIRCUITPY_USB_MSC) +// Default value of CIRCUITPY_SDCARD_USB in settings.toml. +#ifndef CIRCUITPY_SDCARD_USB_DEFAULT +// True for most boards. +#define CIRCUITPY_SDCARD_USB_DEFAULT (true) +#endif #else #define CIRCUITPY_SDCARD_USB (0) #endif @@ -539,10 +563,18 @@ void background_callback_run_all(void); #define CIRCUITPY_USB_DEVICE_INSTANCE 0 #endif +#ifndef CIRCUITPY_USB_DEVICE_HIGH_SPEED +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED 0 +#endif + #ifndef CIRCUITPY_USB_HOST_INSTANCE #define CIRCUITPY_USB_HOST_INSTANCE -1 #endif +#ifndef CIRCUITPY_USB_HOST_HIGH_SPEED +#define CIRCUITPY_USB_HOST_HIGH_SPEED 0 +#endif + // If the port requires certain USB endpoint numbers, define these in mpconfigport.h. #ifndef USB_CDC_EP_NUM_NOTIFICATION @@ -642,7 +674,7 @@ void background_callback_run_all(void); // Align the internal sector buffer. Useful when it is passed into TinyUSB for // loads. #ifndef MICROPY_FATFS_WINDOW_ALIGNMENT -#define MICROPY_FATFS_WINDOW_ALIGNMENT CIRCUITPY_TUSB_MEM_ALIGN +#define MICROPY_FATFS_WINDOW_ALIGNMENT 64 // Espressif is strictest #endif #define FF_FS_CASE_INSENSITIVE_COMPARISON_ASCII_ONLY (1) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk old mode 100644 new mode 100755 index 8c838a41218..178f424d5c0 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -62,6 +62,15 @@ CFLAGS += -DCIRCUITPY_FULL_BUILD=$(CIRCUITPY_FULL_BUILD) # increased build time CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 9 +# By default, use our copy of TLSF. Some vendor SDKs may provide their own +# implementation of TLSF, which can be used instead by setting CIRCUITPY_LIB_TLSF=0. +CIRCUITPY_LIB_TLSF ?= 1 + +# By default, use our copy of string0 (memcpy and friends) because it is optimized. Some vendor SDKs +# or ROMs may provide their own implementation of string0, which can be used instead by setting +# CIRCUITPY_LIBC_STRING0=0. +CIRCUITPY_LIBC_STRING0 ?= 1 + # Reduce the size of in-flash properties. Requires support in the .ld linker # file, so not enabled by default. CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 0 @@ -95,6 +104,10 @@ CFLAGS += -DCIRCUITPY_AESIO=$(CIRCUITPY_AESIO) CIRCUITPY_ALARM ?= 0 CFLAGS += -DCIRCUITPY_ALARM=$(CIRCUITPY_ALARM) +# Whether `alarm.exit_and_deep_sleep_until_alarms()` supports `preserve_dios`. +CIRCUITPY_ALARM_PRESERVE_DIOS ?= 0 +CFLAGS += -DCIRCUITPY_ALARM_PRESERVE_DIOS=$(CIRCUITPY_ALARM_PRESERVE_DIOS) + CIRCUITPY_ALARM_TOUCH ?= $(CIRCUITPY_ALARM) CFLAGS += -DCIRCUITPY_ALARM_TOUCH=$(CIRCUITPY_ALARM_TOUCH) @@ -126,6 +139,10 @@ CFLAGS += -DCIRCUITPY_AUDIOBUSIO_I2SOUT=$(CIRCUITPY_AUDIOBUSIO_I2SOUT) CIRCUITPY_AUDIOBUSIO_PDMIN ?= $(CIRCUITPY_AUDIOBUSIO) CFLAGS += -DCIRCUITPY_AUDIOBUSIO_PDMIN=$(CIRCUITPY_AUDIOBUSIO_PDMIN) +# I2S audio input (separate core module `audioi2sin`). +CIRCUITPY_AUDIOI2SIN ?= 0 +CFLAGS += -DCIRCUITPY_AUDIOI2SIN=$(CIRCUITPY_AUDIOI2SIN) + CIRCUITPY_AUDIOIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO) @@ -146,6 +163,9 @@ CFLAGS += -DCIRCUITPY_AUDIOCORE_DEBUG=$(CIRCUITPY_AUDIOCORE_DEBUG) CIRCUITPY_AUDIOMP3 ?= $(call enable-if-all,$(CIRCUITPY_FULL_BUILD) $(CIRCUITPY_AUDIOCORE)) CFLAGS += -DCIRCUITPY_AUDIOMP3=$(CIRCUITPY_AUDIOMP3) +CIRCUITPY_AUDIOSPEED ?= 0 +CFLAGS += -DCIRCUITPY_AUDIOSPEED=$(CIRCUITPY_AUDIOSPEED) + CIRCUITPY_AUDIOEFFECTS ?= 0 CIRCUITPY_AUDIODELAYS ?= $(CIRCUITPY_AUDIOEFFECTS) CFLAGS += -DCIRCUITPY_AUDIODELAYS=$(CIRCUITPY_AUDIODELAYS) @@ -154,6 +174,9 @@ CFLAGS += -DCIRCUITPY_AUDIOFILTERS=$(CIRCUITPY_AUDIOFILTERS) CIRCUITPY_AUDIOFREEVERB ?= $(CIRCUITPY_AUDIOEFFECTS) CFLAGS += -DCIRCUITPY_AUDIOFREEVERB=$(CIRCUITPY_AUDIOFREEVERB) +CIRCUITPY_AUDIOFILEWRITER ?= 0 +CFLAGS += -DCIRCUITPY_AUDIOFILEWRITER=$(CIRCUITPY_AUDIOFILEWRITER) + CIRCUITPY_AURORA_EPAPER ?= 0 CFLAGS += -DCIRCUITPY_AURORA_EPAPER=$(CIRCUITPY_AURORA_EPAPER) @@ -232,6 +255,12 @@ CFLAGS += -DCIRCUITPY_CYW43=$(CIRCUITPY_CYW43) CIRCUITPY_DIGITALIO ?= 1 CFLAGS += -DCIRCUITPY_DIGITALIO=$(CIRCUITPY_DIGITALIO) +# Enable the DigitalInOut protocol on the native DigitalInOut type. +# This allows other C code to use DigitalInOut objects polymorphically. +# Disable on small builds to save space. +CIRCUITPY_DIGITALINOUT_PROTOCOL ?= $(CIRCUITPY_FULL_BUILD) +CFLAGS += -DCIRCUITPY_DIGITALINOUT_PROTOCOL=$(CIRCUITPY_DIGITALINOUT_PROTOCOL) + CIRCUITPY_COPROC ?= 0 CFLAGS += -DCIRCUITPY_COPROC=$(CIRCUITPY_COPROC) @@ -247,6 +276,10 @@ CFLAGS += -DCIRCUITPY_BUSDISPLAY=$(CIRCUITPY_BUSDISPLAY) CIRCUITPY_FOURWIRE ?= $(CIRCUITPY_DISPLAYIO) CFLAGS += -DCIRCUITPY_FOURWIRE=$(CIRCUITPY_FOURWIRE) +# QSPI bus protocol for quad-SPI displays (like RM690B0) +CIRCUITPY_QSPIBUS ?= 0 +CFLAGS += -DCIRCUITPY_QSPIBUS=$(CIRCUITPY_QSPIBUS) + CIRCUITPY_EPAPERDISPLAY ?= $(CIRCUITPY_DISPLAYIO) CFLAGS += -DCIRCUITPY_EPAPERDISPLAY=$(CIRCUITPY_EPAPERDISPLAY) @@ -276,13 +309,18 @@ CFLAGS += -DCIRCUITPY_VECTORIO=$(CIRCUITPY_VECTORIO) CIRCUITPY_DUALBANK ?= 0 CFLAGS += -DCIRCUITPY_DUALBANK=$(CIRCUITPY_DUALBANK) +# eMMC block device. Only nordic implements it. +CIRCUITPY_EMMCIO ?= 0 +CFLAGS += -DCIRCUITPY_EMMCIO=$(CIRCUITPY_EMMCIO) + +# Mount the eMMC at boot and expose it over USB MSC. +CIRCUITPY_EMMC_USB ?= $(CIRCUITPY_EMMCIO) +CFLAGS += -DCIRCUITPY_EMMC_USB=$(CIRCUITPY_EMMC_USB) + # Enabled micropython.native decorator (experimental) CIRCUITPY_ENABLE_MPY_NATIVE ?= 0 CFLAGS += -DCIRCUITPY_ENABLE_MPY_NATIVE=$(CIRCUITPY_ENABLE_MPY_NATIVE) -CIRCUITPY_OS_GETENV ?= $(CIRCUITPY_FULL_BUILD) -CFLAGS += -DCIRCUITPY_OS_GETENV=$(CIRCUITPY_OS_GETENV) - CIRCUITPY_ERRNO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_ERRNO=$(CIRCUITPY_ERRNO) @@ -334,9 +372,15 @@ CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS=$(CIRCUITPY_HASHLIB_MBEDTLS) CIRCUITPY_HASHLIB_MBEDTLS_ONLY ?= $(call enable-if-all,$(CIRCUITPY_HASHLIB_MBEDTLS) $(call enable-if-not,$(CIRCUITPY_SSL))) CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS_ONLY=$(CIRCUITPY_HASHLIB_MBEDTLS_ONLY) +# Always zero because it is for Zephyr only +CFLAGS += -DCIRCUITPY_HOSTNETWORK=0 + CIRCUITPY_I2CTARGET ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_I2CTARGET=$(CIRCUITPY_I2CTARGET) +CIRCUITPY_I2CIOEXPANDER ?= 0 +CFLAGS += -DCIRCUITPY_I2CIOEXPANDER=$(CIRCUITPY_I2CIOEXPANDER) + CIRCUITPY_IMAGECAPTURE ?= 0 CFLAGS += -DCIRCUITPY_IMAGECAPTURE=$(CIRCUITPY_IMAGECAPTURE) @@ -375,6 +419,9 @@ CFLAGS += -DCIRCUITPY_KEYPAD_SHIFTREGISTERKEYS=$(CIRCUITPY_KEYPAD_SHIFTREGISTERK CIRCUITPY_KEYPAD_DEMUX ?= $(CIRCUITPY_KEYPAD) CFLAGS += -DCIRCUITPY_KEYPAD_DEMUX=$(CIRCUITPY_KEYPAD_DEMUX) +CIRCUITPY_LOAD_NATIVE ?= 0 +CFLAGS += -DCIRCUITPY_LOAD_NATIVE=$(CIRCUITPY_LOAD_NATIVE) + CIRCUITPY_LOCALE ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_LOCALE=$(CIRCUITPY_LOCALE) @@ -396,6 +443,9 @@ CFLAGS += -DCIRCUITPY_MEMORYMONITOR=$(CIRCUITPY_MEMORYMONITOR) CIRCUITPY_MICROCONTROLLER ?= 1 CFLAGS += -DCIRCUITPY_MICROCONTROLLER=$(CIRCUITPY_MICROCONTROLLER) +CIRCUITPY_MIPIDSI ?= 0 +CFLAGS += -DCIRCUITPY_MIPIDSI=$(CIRCUITPY_MIPIDSI) + CIRCUITPY_MSGPACK ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_MSGPACK=$(CIRCUITPY_MSGPACK) @@ -508,12 +558,15 @@ CFLAGS += -DCIRCUITPY_SDCARDIO=$(CIRCUITPY_SDCARDIO) CIRCUITPY_SDIOIO ?= 0 CFLAGS += -DCIRCUITPY_SDIOIO=$(CIRCUITPY_SDIOIO) -CIRCUITPY_SERIAL_BLE ?= 0 -CFLAGS += -DCIRCUITPY_SERIAL_BLE=$(CIRCUITPY_SERIAL_BLE) +CIRCUITPY_BLE_SERIAL_SERVICE ?= 0 +CFLAGS += -DCIRCUITPY_BLE_SERIAL_SERVICE=$(CIRCUITPY_BLE_SERIAL_SERVICE) CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY?= 0 CFLAGS += -DCIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY=$(CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY) +CIRCUITPY_SETTINGS_TOML ?= $(CIRCUITPY_FULL_BUILD) +CFLAGS += -DCIRCUITPY_SETTINGS_TOML=$(CIRCUITPY_SETTINGS_TOML) + CIRCUITPY_SHARPDISPLAY ?= $(CIRCUITPY_FRAMEBUFFERIO) CFLAGS += -DCIRCUITPY_SHARPDISPLAY=$(CIRCUITPY_SHARPDISPLAY) @@ -541,6 +594,28 @@ CFLAGS += -DCIRCUITPY_SSL_MBEDTLS=$(CIRCUITPY_SSL_MBEDTLS) CIRCUITPY_STAGE ?= 0 CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE) +# PicoPad 2D game engine (off by default). +CIRCUITPY_PICOGAME ?= 0 +CFLAGS += -DCIRCUITPY_PICOGAME=$(CIRCUITPY_PICOGAME) +# Fast async-DMA Display backend: needs a port-specific common-hal (the raspberrypi and +# espressif ports provide one). Boards without it use the portable bus.send renderer. +CIRCUITPY_PICOGAME_FAST_DISPLAY ?= 0 +CFLAGS += -DCIRCUITPY_PICOGAME_FAST_DISPLAY=$(CIRCUITPY_PICOGAME_FAST_DISPLAY) +# Does this board's panel controller support 12-bit RGB444 (COLMOD)? A capability flag the +# board declares (ST7789/ST7735 = 1, ILI9341 = 0); exposed as picogame.RGB444_SUPPORTED so +# a game can enable Display(rgb444=...) only where it works. Default 0 (safe RGB565). +CIRCUITPY_PICOGAME_RGB444 ?= 0 +CFLAGS += -DCIRCUITPY_PICOGAME_RGB444=$(CIRCUITPY_PICOGAME_RGB444) +# Full-frame RAM-framebuffer render backend for scanout-buffer platforms (RP2350 DVI/HSTX +# boards like the Fruit Jam). Off by default so flash-tight SPI-only boards don't carry it. +CIRCUITPY_PICOGAME_FRAMEBUFFER ?= 0 +CFLAGS += -DCIRCUITPY_PICOGAME_FRAMEBUFFER=$(CIRCUITPY_PICOGAME_FRAMEBUFFER) +# Float vs 16.16 fixed path for the 3D helpers: the default follows the architecture +# (see shared-module/picogame/__init__.h); set 0/1 here only to override for a board. +ifneq ($(CIRCUITPY_PICOGAME_FPU),) +CFLAGS += -DCIRCUITPY_PICOGAME_FPU=$(CIRCUITPY_PICOGAME_FPU) +endif + CIRCUITPY_STATUS_BAR ?= 1 CFLAGS += -DCIRCUITPY_STATUS_BAR=$(CIRCUITPY_STATUS_BAR) @@ -639,6 +714,9 @@ CFLAGS += -DCIRCUITPY_USB_HID_ENABLED_DEFAULT=$(CIRCUITPY_USB_HID_ENABLED_DEFAUL CIRCUITPY_USB_VIDEO ?= 0 CFLAGS += -DCIRCUITPY_USB_VIDEO=$(CIRCUITPY_USB_VIDEO) +CIRCUITPY_USB_AUDIO ?= 0 +CFLAGS += -DCIRCUITPY_USB_AUDIO=$(CIRCUITPY_USB_AUDIO) + CIRCUITPY_USB_HOST ?= 0 CFLAGS += -DCIRCUITPY_USB_HOST=$(CIRCUITPY_USB_HOST) @@ -682,6 +760,9 @@ CFLAGS += -DCIRCUITPY_USB_KEYBOARD_WORKFLOW=$(CIRCUITPY_USB_KEYBOARD_WORKFLOW) CIRCUITPY_USTACK ?= 0 CFLAGS += -DCIRCUITPY_USTACK=$(CIRCUITPY_USTACK) +# Zephyr display integration is only built by ports/zephyr-cp. +CFLAGS += -DCIRCUITPY_ZEPHYR_DISPLAY=0 + # for decompressing utilities CIRCUITPY_ZLIB ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_ZLIB=$(CIRCUITPY_ZLIB) @@ -709,6 +790,9 @@ CFLAGS += -DCIRCUITPY_WATCHDOG=$(CIRCUITPY_WATCHDOG) CIRCUITPY_WIFI ?= 0 CFLAGS += -DCIRCUITPY_WIFI=$(CIRCUITPY_WIFI) +CIRCUITPY_WIZNET ?= 0 +CFLAGS += -DCIRCUITPY_WIZNET=$(CIRCUITPY_WIZNET) + CIRCUITPY_WEB_WORKFLOW ?= $(CIRCUITPY_WIFI) CFLAGS += -DCIRCUITPY_WEB_WORKFLOW=$(CIRCUITPY_WEB_WORKFLOW) diff --git a/py/compile.c b/py/compile.c index c7dd2fd4761..ae3526e2f2a 100644 --- a/py/compile.c +++ b/py/compile.c @@ -103,6 +103,7 @@ static const emit_method_table_t *emit_native_table[] = { &emit_native_xtensa_method_table, &emit_native_xtensawin_method_table, &emit_native_rv32_method_table, + NULL, &emit_native_debug_method_table, }; @@ -146,7 +147,7 @@ static const emit_inline_asm_method_table_t *emit_asm_table[] = { &emit_inline_thumb_method_table, &emit_inline_thumb_method_table, &emit_inline_xtensa_method_table, - NULL, + &emit_inline_xtensa_method_table, &emit_inline_rv32_method_table, }; @@ -2422,6 +2423,14 @@ static void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar compile_syntax_error(comp, (mp_parse_node_t)pns_arg, MP_ERROR_TEXT("* arg after **")); return; } + if (n_keyword) { + // Support for *arg after kwarg is a CPython feature omitted + // from MicroPython in order to reduce code size. See + // https://github.com/micropython/micropython/issues/11439 for + // more info. + compile_syntax_error(comp, (mp_parse_node_t)pns_arg, MP_ERROR_TEXT("* arg after kwarg")); + return; + } #if MICROPY_DYNAMIC_COMPILER if (i >= (size_t)mp_dynamic_compiler.small_int_bits - 1) #else @@ -3295,7 +3304,9 @@ static void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind } // check structure of parse node - assert(MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0])); + if (!MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0])) { + goto not_an_instruction; + } if (!MP_PARSE_NODE_IS_NULL(pns2->nodes[1])) { goto not_an_instruction; } @@ -3566,7 +3577,7 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool // TODO this can be improved by calculating it during SCOPE pass // but that requires some other structural changes to the asm emitters #if MICROPY_DYNAMIC_COMPILER - if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSA) + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSA || mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSAWIN) #endif { compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); @@ -3587,6 +3598,13 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool case MP_EMIT_OPT_NATIVE_PYTHON: case MP_EMIT_OPT_VIPER: if (emit_native == NULL) { + // The check looks like this to work around a false + // warning in GCC 13 (and possibly later), where it + // assumes that the check will always fail. + if ((uintptr_t)NATIVE_EMITTER_TABLE == (uintptr_t)NULL) { + comp->compile_error = mp_obj_new_exception_msg(&mp_type_NotImplementedError, MP_ERROR_TEXT("cannot emit native code for this architecture")); + goto emit_finished; + } emit_native = NATIVE_EMITTER(new)(&comp->emit_common, &comp->compile_error, &comp->next_label, max_num_labels); } comp->emit_method_table = NATIVE_EMITTER_TABLE; @@ -3619,6 +3637,10 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool } } + #if MICROPY_EMIT_NATIVE +emit_finished: + #endif + if (comp->compile_error != MP_OBJ_NULL) { // if there is no line number for the error then use the line // number for the start of this scope @@ -3650,7 +3672,7 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool #if MICROPY_DEBUG_PRINTERS // now that the module context is valid, the raw codes can be printed - if (mp_verbose_flag >= 2) { + if (MP_STATE_VM(mp_verbose_flag) >= 2) { for (scope_t *s = comp->scope_head; s != NULL; s = s->next) { mp_raw_code_t *rc = s->raw_code; if (rc->kind == MP_CODE_BYTECODE) { diff --git a/py/cstack.h b/py/cstack.h index b12a18e13fc..bcd919d31f9 100644 --- a/py/cstack.h +++ b/py/cstack.h @@ -35,7 +35,7 @@ void mp_cstack_init_with_sp_here(size_t stack_size); -inline static void mp_cstack_init_with_top(void *top, size_t stack_size) { +static inline void mp_cstack_init_with_top(void *top, size_t stack_size) { MP_STATE_THREAD(stack_top) = (char *)top; #if MICROPY_STACK_CHECK @@ -54,7 +54,7 @@ void mp_cstack_check(void); #else -inline static void mp_cstack_check(void) { +static inline void mp_cstack_check(void) { // No-op when stack checking is disabled } diff --git a/py/dynruntime.h b/py/dynruntime.h index e87cf6591c4..9eea5ca6e5c 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -70,8 +70,8 @@ #define m_realloc(ptr, new_num_bytes) (m_realloc_dyn((ptr), (new_num_bytes))) #define m_realloc_maybe(ptr, new_num_bytes, allow_move) (m_realloc_maybe_dyn((ptr), (new_num_bytes), (allow_move))) -static NORETURN inline void m_malloc_fail_dyn(size_t num_bytes) { - mp_fun_table.raise_msg( +static MP_NORETURN inline void m_malloc_fail_dyn(size_t num_bytes) { + mp_fun_table.raise_msg_str( mp_fun_table.load_global(MP_QSTR_MemoryError), "memory allocation failed"); } @@ -289,7 +289,7 @@ static inline void *mp_obj_malloc_helper_dyn(size_t num_bytes, const mp_obj_type #define nlr_raise(o) (mp_raise_dyn(o)) #define mp_raise_type_arg(type, arg) (mp_raise_dyn(mp_obj_new_exception_arg1_dyn((type), (arg)))) -// CIRCUITPY-CHANGE: use str +// CIRCUITPY-CHANGE: use mp_raise_msg_str #define mp_raise_msg(type, msg) (mp_fun_table.raise_msg_str((type), (msg))) #define mp_raise_OSError(er) (mp_raise_OSError_dyn(er)) #define mp_raise_NotImplementedError(msg) (mp_raise_msg(&mp_type_NotImplementedError, (msg))) @@ -301,14 +301,14 @@ static inline mp_obj_t mp_obj_new_exception_arg1_dyn(const mp_obj_type_t *exc_ty return mp_call_function_n_kw(MP_OBJ_FROM_PTR(exc_type), 1, 0, &args[0]); } -static NORETURN inline void mp_raise_dyn(mp_obj_t o) { +static MP_NORETURN inline void mp_raise_dyn(mp_obj_t o) { mp_fun_table.raise(o); for (;;) { } } // CIRCUITPY-CHANGE: new routine -static NORETURN inline void mp_raise_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) { +static MP_NORETURN inline void mp_raise_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) { mp_fun_table.raise(mp_obj_new_exception_arg1_dyn(exc_type, arg)); for (;;) { } diff --git a/py/dynruntime.mk b/py/dynruntime.mk index 807befb464a..cab609b13b0 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -1,7 +1,8 @@ # Makefile fragment for generating native .mpy files from C source # MPY_DIR must be set to the top of the MicroPython source tree -BUILD ?= build +BUILD ?= build-$(ARCH) +CC = $(CROSS)gcc ECHO = @echo RM = /bin/rm @@ -39,7 +40,7 @@ MPY_CROSS_FLAGS += -march=$(ARCH) SRC_O += $(addprefix $(BUILD)/, $(patsubst %.c,%.o,$(filter %.c,$(SRC))) $(patsubst %.S,%.o,$(filter %.S,$(SRC)))) SRC_MPY += $(addprefix $(BUILD)/, $(patsubst %.py,%.mpy,$(filter %.py,$(SRC)))) -CLEAN_EXTRA += $(MOD).mpy .mpy_ld_cache +CLEAN_EXTRA += $(MOD).mpy .mpy_ld_cache-$(ARCH) ################################################################################ # Architecture configuration @@ -47,14 +48,14 @@ CLEAN_EXTRA += $(MOD).mpy .mpy_ld_cache ifeq ($(ARCH),x86) # x86 -CROSS = -CFLAGS_ARCH += -m32 -fno-stack-protector +CROSS = i686-linux-gnu- +CFLAGS_ARCH += -fno-stack-protector MICROPY_FLOAT_IMPL ?= double else ifeq ($(ARCH),x64) # x64 -CROSS = +CROSS = x86_64-linux-gnu- CFLAGS_ARCH += -fno-stack-protector MICROPY_FLOAT_IMPL ?= double @@ -63,14 +64,14 @@ else ifeq ($(ARCH),armv6m) # thumb CROSS = arm-none-eabi- CFLAGS_ARCH += -mthumb -mcpu=cortex-m0 -MICROPY_FLOAT_IMPL ?= none +MICROPY_FLOAT_IMPL ?= float else ifeq ($(ARCH),armv7m) # thumb CROSS = arm-none-eabi- CFLAGS_ARCH += -mthumb -mcpu=cortex-m3 -MICROPY_FLOAT_IMPL ?= none +MICROPY_FLOAT_IMPL ?= float else ifeq ($(ARCH),armv7emsp) @@ -106,30 +107,57 @@ else ifeq ($(ARCH),rv32imc) # rv32imc CROSS = riscv64-unknown-elf- CFLAGS_ARCH += -march=rv32imac -mabi=ilp32 -mno-relax -# If Picolibc is available then select it explicitly. Ubuntu 22.04 ships its +MICROPY_FLOAT_IMPL ?= none +PICOLIBC_BASE := riscv64-unknown-elf +PICOLIBC_TARGET := rv32imac/ilp32 + +else ifeq ($(ARCH),rv64imc) + +# rv64imc +CROSS = riscv64-unknown-elf- +CFLAGS_ARCH += -march=rv64imac -mabi=lp64 -mno-relax +MICROPY_FLOAT_IMPL ?= none +PICOLIBC_BASE := riscv64-unknown-elf +PICOLIBC_TARGET := rv64imac/lp64 + +else +$(error architecture '$(ARCH)' not supported) +endif + +ifneq ($(findstring -musl,$(shell $(CC) -dumpmachine)),) +USE_MUSL := 1 +endif + +ifeq ($(ARCH),$(filter $(ARCH),rv32imc rv64imc)) +# If Picolibc is available then select it explicitly. Ubuntu 24.04 ships its # bare metal RISC-V toolchain with Picolibc rather than Newlib, and the default # is "nosys" so a value must be provided. To avoid having per-distro # workarounds, always select Picolibc if available. -PICOLIBC_SPECS := $(shell $(CROSS)gcc --print-file-name=picolibc.specs) +PICOLIBC_SPECS := $(shell $(CC) --print-file-name=picolibc.specs) ifneq ($(PICOLIBC_SPECS),picolibc.specs) +# LLVM toolchains supporting more than one target seem to ignore the `-march` +# flag passed when looking up the specs file, so if your system has Picolibc +# libraries for more than one architectures supported by the compiler the +# lookup will return the first available file. +# +# For example, on Ubuntu 24.02 if you have both `picolibc-aarch64-linux-gnu` +# and `picolibc-riscv64-unknown-elf` packages installed, the Qualcomm LLVM +# toolchain (which supports both AArch64 and RISC-V 64) will always return the +# AArch64 picolibc specs even when building for RISC-V. +ifeq ($(shell grep -q "$(PICOLIBC_BASE)" "$(PICOLIBC_SPECS)"; echo $$?),0) CFLAGS_ARCH += -specs=$(PICOLIBC_SPECS) USE_PICOLIBC := 1 -PICOLIBC_ARCH := rv32imac -PICOLIBC_ABI := ilp32 endif - -MICROPY_FLOAT_IMPL ?= none - -else -$(error architecture '$(ARCH)' not supported) +endif endif MICROPY_FLOAT_IMPL_UPPER = $(shell echo $(MICROPY_FLOAT_IMPL) | tr '[:lower:]' '[:upper:]') CFLAGS += $(CFLAGS_ARCH) -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_$(MICROPY_FLOAT_IMPL_UPPER) +CFLAGS += $(CFLAGS_EXTRA) ifeq ($(LINK_RUNTIME),1) # All of these picolibc-specific directives are here to work around a -# limitation of Ubuntu 22.04's RISC-V bare metal toolchain. In short, the +# limitation of Ubuntu 24.04's RISC-V bare metal toolchain. In short, the # specific version of GCC in use (10.2.0) does not seem to take into account # extra paths provided by an explicitly passed specs file when performing name # resolution via `--print-file-name`. @@ -140,34 +168,56 @@ ifeq ($(LINK_RUNTIME),1) # flags that are passed to GCC. The `PICOLIBC_ROOT` environment variable is # checked to override the starting point for the library file search, and if # it is not set then the default value is used, assuming that this is running -# on an Ubuntu 22.04 machine. +# on an Ubuntu 24.04 machine. # # This should be revised when the CI base image is updated to a newer Ubuntu # version (that hopefully contains a newer RISC-V compiler) or to another Linux # distribution. ifeq ($(USE_PICOLIBC),1) LIBM_NAME := libc.a +else ifeq ($(USE_MUSL),1) +LIBM_NAME := libc.a else LIBM_NAME := libm.a endif -LIBGCC_PATH := $(realpath $(shell $(CROSS)gcc $(CFLAGS) --print-libgcc-file-name)) -LIBM_PATH := $(realpath $(shell $(CROSS)gcc $(CFLAGS) --print-file-name=$(LIBM_NAME))) +# Clang will output the path to libclang_rt.builtins.a instead. The problem is +# that some symbols are duplicated between the builtins library and libc.a. In +# these cases let's leave it to the user to figure out how to handle this for +# the time being. +TOOLCHAIN_LIBGCC := $(realpath $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)) +ifneq ($(findstring clang,$(shell $(CC) --version)),clang) +LIBGCC_PATH = $(TOOLCHAIN_LIBGCC) +else +ifneq ($(LINK_CLANG_CLANGRT),0) +LIBGCC_PATH = $(TOOLCHAIN_LIBGCC) +else +LIBGCC_PATH = +endif +endif +LIBM_PATH := $(realpath $(shell $(CC) $(CFLAGS) --print-file-name=$(LIBM_NAME))) ifeq ($(USE_PICOLIBC),1) ifeq ($(LIBM_PATH),) -# The CROSS toolchain prefix usually ends with a dash, but that may not be -# always the case. If the prefix ends with a dash it has to be taken out as -# Picolibc's architecture directory won't have it in its name. GNU Make does -# not have any facility to perform character-level text manipulation so we -# shell out to sed. -CROSS_PREFIX := $(shell echo $(CROSS) | sed -e 's/-$$//') -PICOLIBC_ROOT ?= /usr/lib/picolibc/$(CROSS_PREFIX)/lib -LIBM_PATH := $(PICOLIBC_ROOT)/$(PICOLIBC_ARCH)/$(PICOLIBC_ABI)/$(LIBM_NAME) +PICOLIBC_ROOT ?= /usr/lib/picolibc/$(PICOLIBC_BASE)/lib +LIBM_PATH := $(PICOLIBC_ROOT)/$(PICOLIBC_TARGET)/$(LIBM_NAME) endif endif -MPY_LD_FLAGS += $(addprefix -l, $(LIBGCC_PATH) $(LIBM_PATH)) +ifneq ($(LINK_CLANG_LIBC),) +ifeq ($(findstring clang,$(shell $(CC) --version)),clang) +LIBC_PATH := $(realpath $(shell $(CC) $(CFLAGS) --print-file-name=libc.a)) +else +LIBC_PATH = +endif +else +LIBC_PATH = +endif +MPY_LD_FLAGS += $(addprefix -l, $(LIBGCC_PATH) $(LIBM_PATH) $(LIBC_PATH)) +endif +ifneq ($(MPY_EXTERN_SYM_FILE),) +MPY_LD_FLAGS += --externs "$(realpath $(MPY_EXTERN_SYM_FILE))" +endif +ifneq ($(ARCH_FLAGS),) +MPY_LD_FLAGS += --arch-flags "$(ARCH_FLAGS)" endif - -CFLAGS += $(CFLAGS_EXTRA) ################################################################################ # Build rules @@ -193,12 +243,12 @@ $(CONFIG_H): $(SRC) # Build .o from .c source files $(BUILD)/%.o: %.c $(CONFIG_H) Makefile $(ECHO) "CC $<" - $(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $< + $(Q)$(CC) $(CFLAGS) -o $@ -c $< # Build .o from .S source files $(BUILD)/%.o: %.S $(CONFIG_H) Makefile $(ECHO) "AS $<" - $(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $< + $(Q)$(CC) $(CFLAGS) -o $@ -c $< # Build .mpy from .py source files $(BUILD)/%.mpy: %.py @@ -206,11 +256,11 @@ $(BUILD)/%.mpy: %.py $(Q)$(MPY_CROSS) $(MPY_CROSS_FLAGS) -o $@ $< # Build native .mpy from object files -$(BUILD)/$(MOD).native.mpy: $(SRC_O) +$(BUILD)/$(MOD).mpy: $(SRC_O) $(ECHO) "LINK $<" $(Q)$(MPY_LD) --arch $(ARCH) --qstrs $(CONFIG_H) $(MPY_LD_FLAGS) -o $@ $^ # Build final .mpy from all intermediate .mpy files -$(MOD).mpy: $(BUILD)/$(MOD).native.mpy $(SRC_MPY) +$(MOD).mpy: $(BUILD)/$(MOD).mpy $(SRC_MPY) $(ECHO) "GEN $@" $(Q)$(MPY_TOOL) --merge -o $@ $^ diff --git a/py/emitbc.c b/py/emitbc.c index 0bcac8a1676..5f133ab070b 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -432,6 +432,12 @@ void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) { // If we compile with -O3, don't store line numbers. return; } + #if MICROPY_DYNAMIC_COMPILER + if (!mp_dynamic_compiler.include_source_lines) { + // Don't store line numbers if explicitly disabled. + return; + } + #endif if (source_line > emit->last_source_line) { mp_uint_t bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset; mp_uint_t lines_to_skip = source_line - emit->last_source_line; diff --git a/py/emitcommon.c b/py/emitcommon.c index a9eb6e2021f..1369c544c54 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -25,6 +25,7 @@ */ #include +#include #include "py/emit.h" #include "py/nativeglue.h" @@ -72,7 +73,25 @@ static bool strictly_equal(mp_obj_t a, mp_obj_t b) { } return true; } else { - return mp_obj_equal(a, b); + if (!mp_obj_equal(a, b)) { + return false; + } + #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_COMP_CONST_FLOAT + if (a_type == &mp_type_float) { + mp_float_t a_val = mp_obj_float_get(a); + // CIRCUITPY-CHANGE: ignore float equal warning + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" + if (a_val == (mp_float_t)0.0) { + // Although 0.0 == -0.0, they are not strictly_equal and + // must be stored as two different constants in .mpy files + mp_float_t b_val = mp_obj_float_get(b); + return signbit(a_val) == signbit(b_val); + } + #pragma GCC diagnostic pop + } + #endif + return true; } } diff --git a/py/emitglue.c b/py/emitglue.c index 8cc14bdc54e..3b479079af0 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -32,6 +32,7 @@ #include #include "py/emitglue.h" +#include "py/mphal.h" #include "py/runtime0.h" #include "py/bc.h" #include "py/objfun.h" @@ -49,10 +50,6 @@ #define DEBUG_OP_printf(...) (void)0 #endif -#if MICROPY_DEBUG_PRINTERS -mp_uint_t mp_verbose_flag = 0; -#endif - mp_raw_code_t *mp_emit_glue_new_raw_code(void) { mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1); rc->kind = MP_CODE_RESERVED; @@ -97,7 +94,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, #endif } -#if MICROPY_EMIT_MACHINE_CODE +#if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, const void *fun_data, mp_uint_t fun_len, mp_raw_code_t **children, #if MICROPY_PERSISTENT_CODE_SAVE @@ -112,7 +109,7 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, cons // Some architectures require flushing/invalidation of the I/D caches, // so that the generated native code which was created in data RAM will // be available for execution from instruction RAM. - #if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB + #if defined(__thumb__) || defined(__thumb2__) // CIRCUITPY-CHANGE: prevent warning #if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT == 1 // Flush D-cache, so the code emitted is stored in RAM. @@ -120,10 +117,10 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, cons // Invalidate I-cache, so the newly-created code is reloaded from RAM. SCB_InvalidateICache(); #endif - #elif MICROPY_EMIT_ARM + #elif defined(__arm__) #if (defined(__linux__) && defined(__GNUC__)) || __ARM_ARCH == 7 __builtin___clear_cache((void *)fun_data, (char *)fun_data + fun_len); - #elif defined(__arm__) + #else // Flush I-cache and D-cache. asm volatile ( "0:" @@ -133,6 +130,9 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, cons "mcr p15, 0, r0, c7, c7, 0\n" // invalidate I-cache and D-cache : : : "r0", "cc"); #endif + #elif defined(__riscv) && defined(MP_HAL_CLEAN_DCACHE) + // Flush the D-cache. + MP_HAL_CLEAN_DCACHE(fun_data, fun_len); #endif rc->kind = kind; @@ -189,7 +189,7 @@ mp_obj_t mp_make_function_from_proto_fun(mp_proto_fun_t proto_fun, const mp_modu // def_kw_args must be MP_OBJ_NULL or a dict assert(def_args == NULL || def_args[1] == MP_OBJ_NULL || mp_obj_is_type(def_args[1], &mp_type_dict)); - #if MICROPY_MODULE_FROZEN_MPY + #if MICROPY_MODULE_FROZEN_MPY || MICROPY_PY_FUNCTION_ATTRS_CODE if (mp_proto_fun_is_bytecode(proto_fun)) { const uint8_t *bc = proto_fun; mp_obj_t fun = mp_obj_new_fun_bc(def_args, bc, context, NULL); @@ -215,7 +215,7 @@ mp_obj_t mp_make_function_from_proto_fun(mp_proto_fun_t proto_fun, const mp_modu // make the function, depending on the raw code kind mp_obj_t fun; switch (rc->kind) { - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE case MP_CODE_NATIVE_PY: fun = mp_obj_new_fun_native(def_args, rc->fun_data, context, rc->children); // Check for a generator function, and if so change the type of the object diff --git a/py/emitglue.h b/py/emitglue.h index d19503b823f..674807910c1 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -83,7 +83,7 @@ typedef struct _mp_raw_code_t { #if MICROPY_PERSISTENT_CODE_SAVE uint32_t fun_data_len; // for mp_raw_code_save uint16_t n_children; - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE uint16_t prelude_offset; #endif #if MICROPY_PY_SYS_SETTRACE @@ -116,7 +116,7 @@ typedef struct _mp_raw_code_truncated_t { #if MICROPY_PERSISTENT_CODE_SAVE uint32_t fun_data_len; uint16_t n_children; - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE uint16_t prelude_offset; #endif #if MICROPY_PY_SYS_SETTRACE diff --git a/py/emitinlinerv32.c b/py/emitinlinerv32.c index a539242b84d..b175ae0ddc8 100644 --- a/py/emitinlinerv32.c +++ b/py/emitinlinerv32.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -196,7 +197,6 @@ typedef enum { CALL_R, // Opcode Register CALL_RL, // Opcode Register, Label CALL_N, // Opcode - CALL_I, // Opcode Immediate CALL_RII, // Opcode Register, Register, Immediate CALL_RIR, // Opcode Register, Immediate(Register) CALL_COUNT @@ -210,7 +210,6 @@ typedef enum { #define U (1 << 2) // Unsigned immediate #define Z (1 << 3) // Non-zero -typedef void (*call_l_t)(asm_rv32_t *state, mp_uint_t label_index); typedef void (*call_ri_t)(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate); typedef void (*call_rri_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_int_t immediate); typedef void (*call_rii_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t immediate1, mp_int_t immediate2); @@ -225,7 +224,7 @@ typedef struct _opcode_t { uint16_t argument1_mask : 4; uint16_t argument2_mask : 4; uint16_t argument3_mask : 4; - uint16_t arguments_count : 2; + uint16_t parse_nodes : 2; // 2 bits available here uint32_t calling_convention : 4; uint32_t argument1_kind : 4; @@ -234,7 +233,8 @@ typedef struct _opcode_t { uint32_t argument2_shift : 4; uint32_t argument3_kind : 4; uint32_t argument3_shift : 4; - // 4 bits available here + uint32_t required_extensions : 1; + // 3 bits available here void *emitter; } opcode_t; @@ -297,88 +297,91 @@ static const uint32_t OPCODE_MASKS[] = { }; static const opcode_t OPCODES[] = { - { MP_QSTR_add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_add }, - { MP_QSTR_addi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_addi }, - { MP_QSTR_and_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_and }, - { MP_QSTR_andi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_andi }, - { MP_QSTR_auipc, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, asm_rv32_opcode_auipc }, - { MP_QSTR_beq, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_beq }, - { MP_QSTR_bge, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bge }, - { MP_QSTR_bgeu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bgeu }, - { MP_QSTR_blt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_blt }, - { MP_QSTR_bltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bltu }, - { MP_QSTR_bne, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bne }, - { MP_QSTR_csrrc, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_csrrc }, - { MP_QSTR_csrrs, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_csrrs }, - { MP_QSTR_csrrw, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_csrrw }, - { MP_QSTR_csrrci, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, asm_rv32_opcode_csrrci }, - { MP_QSTR_csrrsi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, asm_rv32_opcode_csrrsi }, - { MP_QSTR_csrrwi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, asm_rv32_opcode_csrrwi }, - { MP_QSTR_c_add, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, asm_rv32_opcode_cadd }, - { MP_QSTR_c_addi, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, IZ, 0, N, 0, asm_rv32_opcode_caddi }, - { MP_QSTR_c_addi4spn, MASK_0000FF00, MASK_000003FC, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 0, N, 0, asm_rv32_opcode_caddi4spn }, - { MP_QSTR_c_and, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_cand }, - { MP_QSTR_c_andi, MASK_0000FF00, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, RC, 0, I, 0, N, 0, asm_rv32_opcode_candi }, - { MP_QSTR_c_beqz, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, asm_rv32_opcode_cbeqz }, - { MP_QSTR_c_bnez, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, asm_rv32_opcode_cbnez }, - { MP_QSTR_c_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_cebreak }, - { MP_QSTR_c_j, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, asm_rv32_opcode_cj }, - { MP_QSTR_c_jal, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, asm_rv32_opcode_cjal }, - { MP_QSTR_c_jalr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, asm_rv32_opcode_cjalr }, - { MP_QSTR_c_jr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, asm_rv32_opcode_cjr }, - { MP_QSTR_c_li, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, asm_rv32_opcode_cli }, - { MP_QSTR_c_lui, MASK_FFFFFFFA, MASK_0001F800, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 12, N, 0, asm_rv32_opcode_clui }, - { MP_QSTR_c_lw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 3, CALL_RIR, RC, 0, I, 0, RC, 0, asm_rv32_opcode_clw }, - { MP_QSTR_c_lwsp, MASK_FFFFFFFE, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, asm_rv32_opcode_clwsp }, - { MP_QSTR_c_mv, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, asm_rv32_opcode_cmv }, - { MP_QSTR_c_nop, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_cnop }, - { MP_QSTR_c_or, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_cor }, - { MP_QSTR_c_slli, MASK_FFFFFFFE, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, R, 0, IU, 0, N, 0, asm_rv32_opcode_cslli }, - { MP_QSTR_c_srai, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, asm_rv32_opcode_csrai }, - { MP_QSTR_c_srli, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, asm_rv32_opcode_csrli }, - { MP_QSTR_c_sub, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_csub }, - { MP_QSTR_c_sw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 3, CALL_RIR, RC, 0, I, 0, RC, 0, asm_rv32_opcode_csw }, - { MP_QSTR_c_swsp, MASK_FFFFFFFF, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, asm_rv32_opcode_cswsp }, - { MP_QSTR_c_xor, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_cxor }, - { MP_QSTR_div, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_div }, - { MP_QSTR_divu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_divu }, - { MP_QSTR_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_ebreak }, - { MP_QSTR_ecall, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_ecall }, - { MP_QSTR_jal, MASK_FFFFFFFF, MASK_001FFFFE, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, asm_rv32_opcode_jal }, - { MP_QSTR_jalr, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_jalr }, - { MP_QSTR_la, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, opcode_la }, - { MP_QSTR_lb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lb }, - { MP_QSTR_lbu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lbu }, - { MP_QSTR_lh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lh }, - { MP_QSTR_lhu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lhu }, - { MP_QSTR_li, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, opcode_li }, - { MP_QSTR_lui, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, asm_rv32_opcode_lui }, - { MP_QSTR_lw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lw }, - { MP_QSTR_mv, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, asm_rv32_opcode_cmv }, - { MP_QSTR_mul, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mul }, - { MP_QSTR_mulh, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mulh }, - { MP_QSTR_mulhsu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mulhsu }, - { MP_QSTR_mulhu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mulhu }, - { MP_QSTR_or_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_or }, - { MP_QSTR_ori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_ori }, - { MP_QSTR_rem, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_rem }, - { MP_QSTR_remu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_remu }, - { MP_QSTR_sb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_sb }, - { MP_QSTR_sh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_sh }, - { MP_QSTR_sll, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sll }, - { MP_QSTR_slli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_slli }, - { MP_QSTR_slt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_slt }, - { MP_QSTR_slti, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_slti }, - { MP_QSTR_sltiu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_sltiu }, - { MP_QSTR_sltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sltu }, - { MP_QSTR_sra, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sra }, - { MP_QSTR_srai, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_srai }, - { MP_QSTR_srl, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_srl }, - { MP_QSTR_srli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_srli }, - { MP_QSTR_sub, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sub }, - { MP_QSTR_sw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_sw }, - { MP_QSTR_xor, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_xor }, - { MP_QSTR_xori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_xori }, + { MP_QSTR_add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_add }, + { MP_QSTR_addi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_addi }, + { MP_QSTR_and_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_and }, + { MP_QSTR_andi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_andi }, + { MP_QSTR_auipc, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, RV32_EXT_NONE, asm_rv32_opcode_auipc }, + { MP_QSTR_beq, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_beq }, + { MP_QSTR_bge, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_bge }, + { MP_QSTR_bgeu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_bgeu }, + { MP_QSTR_blt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_blt }, + { MP_QSTR_bltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_bltu }, + { MP_QSTR_bne, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_bne }, + { MP_QSTR_csrrc, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrc }, + { MP_QSTR_csrrs, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrs }, + { MP_QSTR_csrrw, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrw }, + { MP_QSTR_csrrci, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrci }, + { MP_QSTR_csrrsi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrsi }, + { MP_QSTR_csrrwi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrwi }, + { MP_QSTR_c_add, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cadd }, + { MP_QSTR_c_addi, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, IZ, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_caddi }, + { MP_QSTR_c_addi4spn, MASK_0000FF00, MASK_000003FC, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_caddi4spn }, + { MP_QSTR_c_and, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cand }, + { MP_QSTR_c_andi, MASK_0000FF00, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, RC, 0, I, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_candi }, + { MP_QSTR_c_beqz, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cbeqz }, + { MP_QSTR_c_bnez, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cbnez }, + { MP_QSTR_c_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cebreak }, + { MP_QSTR_c_j, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cj }, + { MP_QSTR_c_jal, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cjal }, + { MP_QSTR_c_jalr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cjalr }, + { MP_QSTR_c_jr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cjr }, + { MP_QSTR_c_li, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cli }, + { MP_QSTR_c_lui, MASK_FFFFFFFA, MASK_0001F800, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 12, N, 0, RV32_EXT_NONE, asm_rv32_opcode_clui }, + { MP_QSTR_c_lw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 2, CALL_RIR, RC, 0, I, 0, RC, 0, RV32_EXT_NONE, asm_rv32_opcode_clw }, + { MP_QSTR_c_lwsp, MASK_FFFFFFFE, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_clwsp }, + { MP_QSTR_c_mv, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cmv }, + { MP_QSTR_c_nop, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cnop }, + { MP_QSTR_c_or, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cor }, + { MP_QSTR_c_slli, MASK_FFFFFFFE, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, R, 0, IU, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cslli }, + { MP_QSTR_c_srai, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_csrai }, + { MP_QSTR_c_srli, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_csrli }, + { MP_QSTR_c_sub, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_csub }, + { MP_QSTR_c_sw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 2, CALL_RIR, RC, 0, I, 0, RC, 0, RV32_EXT_NONE, asm_rv32_opcode_csw }, + { MP_QSTR_c_swsp, MASK_FFFFFFFF, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cswsp }, + { MP_QSTR_c_xor, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cxor }, + { MP_QSTR_div, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_div }, + { MP_QSTR_divu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_divu }, + { MP_QSTR_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_ebreak }, + { MP_QSTR_ecall, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_ecall }, + { MP_QSTR_jal, MASK_FFFFFFFF, MASK_001FFFFE, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_jal }, + { MP_QSTR_jalr, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_jalr }, + { MP_QSTR_la, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, RV32_EXT_NONE, opcode_la }, + { MP_QSTR_lb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lb }, + { MP_QSTR_lbu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lbu }, + { MP_QSTR_lh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lh }, + { MP_QSTR_lhu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lhu }, + { MP_QSTR_li, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, RV32_EXT_NONE, opcode_li }, + { MP_QSTR_lui, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, RV32_EXT_NONE, asm_rv32_opcode_lui }, + { MP_QSTR_lw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lw }, + { MP_QSTR_mv, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cmv }, + { MP_QSTR_mul, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_mul }, + { MP_QSTR_mulh, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_mulh }, + { MP_QSTR_mulhsu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_mulhsu }, + { MP_QSTR_mulhu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_mulhu }, + { MP_QSTR_or_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_or }, + { MP_QSTR_ori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_ori }, + { MP_QSTR_rem, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_rem }, + { MP_QSTR_remu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_remu }, + { MP_QSTR_sb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sb }, + { MP_QSTR_sh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sh }, + { MP_QSTR_sh1add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_ZBA, asm_rv32_opcode_sh1add }, + { MP_QSTR_sh2add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_ZBA, asm_rv32_opcode_sh2add }, + { MP_QSTR_sh3add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_ZBA, asm_rv32_opcode_sh3add }, + { MP_QSTR_sll, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sll }, + { MP_QSTR_slli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_slli }, + { MP_QSTR_slt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_slt }, + { MP_QSTR_slti, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_slti }, + { MP_QSTR_sltiu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_sltiu }, + { MP_QSTR_sltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sltu }, + { MP_QSTR_sra, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sra }, + { MP_QSTR_srai, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_srai }, + { MP_QSTR_srl, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_srl }, + { MP_QSTR_srli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_srli }, + { MP_QSTR_sub, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sub }, + { MP_QSTR_sw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sw }, + { MP_QSTR_xor, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_xor }, + { MP_QSTR_xori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_xori }, }; #undef RC @@ -388,9 +391,9 @@ static const opcode_t OPCODES[] = { // These two checks assume the bitmasks are contiguous. -static bool is_in_signed_mask(mp_uint_t mask, mp_uint_t value) { - mp_uint_t leading_zeroes = mp_clz(mask); - if (leading_zeroes == 0 || leading_zeroes > 32) { +static bool is_in_signed_mask(uint32_t mask, mp_uint_t value) { + uint32_t leading_zeroes = mp_clz(mask); + if (leading_zeroes == 0) { return true; } mp_uint_t positive_mask = ~(mask & ~(1U << (31 - leading_zeroes))); @@ -435,9 +438,9 @@ static bool validate_integer(mp_uint_t value, mp_uint_t mask, mp_uint_t flags) { #define ET_WRONG_ARGUMENTS_COUNT MP_ERROR_TEXT("opcode '%q': expecting %d arguments") #define ET_OUT_OF_RANGE MP_ERROR_TEXT("opcode '%q' argument %d: out of range") -static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, - const opcode_t *opcode, mp_parse_node_t node, mp_uint_t node_index) { +static bool serialise_argument(emit_inline_asm_t *emit, const opcode_t *opcode, mp_parse_node_t node, mp_uint_t node_index, mp_uint_t *serialised) { assert((node_index < 3) && "Invalid argument node number."); + assert(serialised && "Serialised value pointer is NULL."); uint32_t kind = 0; uint32_t shift = 0; @@ -466,17 +469,19 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, break; } + mp_uint_t serialised_value = 0; + switch (kind & 0x03) { case N: assert(mask == OPCODE_MASKS[MASK_NOT_USED] && "Invalid mask index for missing operand."); - return true; + break; case R: { mp_uint_t register_index; if (!parse_register_node(node, ®ister_index, false)) { emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_register)); + ET_WRONG_ARGUMENT_KIND, opcode->qstring, node_index + 1, MP_QSTR_register)); return false; } @@ -484,11 +489,11 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("opcode '%q' argument %d: unknown register"), - opcode_qstr, node_index + 1)); + opcode->qstring, node_index + 1)); return false; } - return true; + serialised_value = (kind & C) ? RV32_MAP_IN_C_REGISTER_WINDOW(register_index) : register_index; } break; @@ -497,11 +502,11 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, if (!mp_parse_node_get_int_maybe(node, &object)) { emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_integer)); + ET_WRONG_ARGUMENT_KIND, opcode->qstring, node_index + 1, MP_QSTR_integer)); return false; } - mp_uint_t immediate = mp_obj_get_int_truncated(object) << shift; + mp_uint_t immediate = ((mp_uint_t)mp_obj_get_int_truncated(object)) << shift; if (kind & U) { if (!is_in_unsigned_mask(mask, immediate)) { goto out_of_range; @@ -516,7 +521,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, goto zero_immediate; } - return true; + serialised_value = immediate; } break; @@ -524,7 +529,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, if (!MP_PARSE_NODE_IS_ID(node)) { emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_label)); + ET_WRONG_ARGUMENT_KIND, opcode->qstring, node_index + 1, MP_QSTR_label)); return false; } @@ -534,7 +539,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("opcode '%q' argument %d: undefined label '%q'"), - opcode_qstr, node_index + 1, qstring)); + opcode->qstring, node_index + 1, qstring)); return false; } @@ -548,43 +553,45 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, goto out_of_range; } } - return true; + + serialised_value = displacement; } break; default: assert(!"Unknown argument kind"); + MP_UNREACHABLE; break; } - return false; + *serialised = serialised_value; + return true; out_of_range: emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode_qstr, node_index + 1)); + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode->qstring, node_index + 1)); return false; zero_immediate: emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("opcode '%q' argument %d: must not be zero"), - opcode_qstr, node_index + 1)); + opcode->qstring, node_index + 1)); return false; } -static bool parse_register_offset_node(emit_inline_asm_t *emit, qstr opcode_qstr, const opcode_t *opcode_data, mp_parse_node_t node, mp_uint_t node_index, mp_parse_node_t *register_node, mp_parse_node_t *offset_node, bool *negative) { - assert(register_node != NULL && "Register node pointer is NULL."); - assert(offset_node != NULL && "Offset node pointer is NULL."); - assert(negative != NULL && "Negative pointer is NULL."); +static bool serialise_register_offset_node(emit_inline_asm_t *emit, const opcode_t *opcode_data, mp_parse_node_t node, mp_uint_t node_index, mp_uint_t *offset, mp_uint_t *base) { + assert(offset && "Attempting to store the offset value into NULL."); + assert(base && "Attempting to store the base register into NULL."); if (!MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_atom_expr_normal) && !MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_factor_2)) { goto invalid_structure; } mp_parse_node_struct_t *node_struct = (mp_parse_node_struct_t *)node; - *negative = false; + bool negative = false; if (MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_factor_2)) { if (MP_PARSE_NODE_IS_TOKEN_KIND(node_struct->nodes[0], MP_TOKEN_OP_MINUS)) { - *negative = true; + negative = true; } else { if (!MP_PARSE_NODE_IS_TOKEN_KIND(node_struct->nodes[0], MP_TOKEN_OP_PLUS)) { goto invalid_structure; @@ -596,184 +603,281 @@ static bool parse_register_offset_node(emit_inline_asm_t *emit, qstr opcode_qstr node_struct = (mp_parse_node_struct_t *)node_struct->nodes[1]; } - if (*negative) { + if (negative) { // If the value is negative, RULE_atom_expr_normal's first token will be the // offset stripped of its negative marker; range check will then fail if the // default method is used, so a custom check is used instead. mp_obj_t object; if (!mp_parse_node_get_int_maybe(node_struct->nodes[0], &object)) { emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_WRONG_ARGUMENT_KIND, opcode_qstr, 2, MP_QSTR_integer)); + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_WRONG_ARGUMENT_KIND, opcode_data->qstring, 2, MP_QSTR_integer)); return false; } mp_uint_t value = mp_obj_get_int_truncated(object); value = (~value + 1) & (mp_uint_t)-1; if (!validate_integer(value << opcode_data->argument2_shift, OPCODE_MASKS[opcode_data->argument2_mask], opcode_data->argument2_kind)) { emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode_qstr, 2)); + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode_data->qstring, 2)); return false; } + *offset = value; } else { - if (!validate_argument(emit, opcode_qstr, opcode_data, node_struct->nodes[0], 1)) { + if (!serialise_argument(emit, opcode_data, node_struct->nodes[0], 1, offset)) { return false; } } - *offset_node = node_struct->nodes[0]; node_struct = (mp_parse_node_struct_t *)node_struct->nodes[1]; - if (!validate_argument(emit, opcode_qstr, opcode_data, node_struct->nodes[0], 2)) { + if (!serialise_argument(emit, opcode_data, node_struct->nodes[0], 2, base)) { return false; } - *register_node = node_struct->nodes[0]; return true; invalid_structure: emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_offset)); + ET_WRONG_ARGUMENT_KIND, opcode_data->qstring, node_index + 1, MP_QSTR_offset)); return false; } -static void handle_opcode(emit_inline_asm_t *emit, qstr opcode, const opcode_t *opcode_data, mp_parse_node_t *arguments) { - mp_uint_t rd = 0; - mp_uint_t rs1 = 0; - mp_uint_t rs2 = 0; - +static void handle_opcode(emit_inline_asm_t *emit, const opcode_t *opcode_data, mp_uint_t *arguments) { switch (opcode_data->calling_convention) { - case CALL_RRR: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C); - parse_register_node(arguments[2], &rs2, opcode_data->argument3_kind & C); - ((call_rrr_t)opcode_data->emitter)(&emit->as, rd, rs1, rs2); + case CALL_RRR: + ((call_rrr_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]); break; - } - case CALL_RR: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C); - ((call_rr_t)opcode_data->emitter)(&emit->as, rd, rs1); + case CALL_RR: + ((call_rr_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1]); break; - } - case CALL_RRI: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C); - mp_obj_t object; - mp_parse_node_get_int_maybe(arguments[2], &object); - mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument3_shift; - ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, immediate); + case CALL_RRI: + ((call_rri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]); break; - } - case CALL_RI: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - mp_obj_t object; - mp_parse_node_get_int_maybe(arguments[1], &object); - mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift; - ((call_ri_t)opcode_data->emitter)(&emit->as, rd, immediate); + case CALL_RI: + ((call_ri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1]); break; - } - case CALL_R: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - ((call_r_t)opcode_data->emitter)(&emit->as, rd); + case CALL_R: + ((call_r_t)opcode_data->emitter)(&emit->as, arguments[0]); break; - } - case CALL_RRL: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C); - qstr qstring; - mp_uint_t label_index = lookup_label(emit, arguments[2], &qstring); - ptrdiff_t displacement = label_code_offset(emit, label_index); - ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, displacement); + case CALL_RRL: + ((call_rri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], (ptrdiff_t)arguments[2]); break; - } - case CALL_RL: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - qstr qstring; - mp_uint_t label_index = lookup_label(emit, arguments[1], &qstring); - ptrdiff_t displacement = label_code_offset(emit, label_index); - ((call_ri_t)opcode_data->emitter)(&emit->as, rd, displacement); + case CALL_RL: + ((call_ri_t)opcode_data->emitter)(&emit->as, arguments[0], (ptrdiff_t)arguments[1]); break; - } - case CALL_L: { - qstr qstring; - mp_uint_t label_index = lookup_label(emit, arguments[0], &qstring); - ptrdiff_t displacement = label_code_offset(emit, label_index); - ((call_i_t)opcode_data->emitter)(&emit->as, displacement); + case CALL_L: + ((call_i_t)opcode_data->emitter)(&emit->as, (ptrdiff_t)arguments[0]); break; - } case CALL_N: ((call_n_t)opcode_data->emitter)(&emit->as); break; - case CALL_I: { - mp_obj_t object; - mp_parse_node_get_int_maybe(arguments[0], &object); - mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument1_shift; - ((call_i_t)opcode_data->emitter)(&emit->as, immediate); - break; - } - - case CALL_RII: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - mp_obj_t object; - mp_parse_node_get_int_maybe(arguments[1], &object); - mp_uint_t immediate1 = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift; - mp_parse_node_get_int_maybe(arguments[2], &object); - mp_uint_t immediate2 = mp_obj_get_int_truncated(object) << opcode_data->argument3_shift; - ((call_rii_t)opcode_data->emitter)(&emit->as, rd, immediate1, immediate2); + case CALL_RII: + ((call_rii_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]); break; - } case CALL_RIR: - assert(!"Should not get here."); + // The last two arguments indices are swapped on purpose. + ((call_rri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[2], arguments[1]); break; default: assert(!"Unhandled call convention."); + MP_UNREACHABLE; break; } } -static bool handle_load_store_opcode_with_offset(emit_inline_asm_t *emit, qstr opcode, const opcode_t *opcode_data, mp_parse_node_t *argument_nodes) { - mp_parse_node_t nodes[3] = {0}; - if (!validate_argument(emit, opcode, opcode_data, argument_nodes[0], 0)) { +static bool extract_register_list(emit_inline_asm_t *emit, qstr opcode, mp_parse_node_t node, mp_uint_t *reglist) { + assert(reglist != NULL && "Register list pointer is NULL."); + + // As per §28.9, valid register list values are as follows: + // + // {ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2}, ..., {ra, s0-s8}, + // {ra, s0-s9}, {ra, s0-s11} + // + // {ra, s0-s10} is *not* valid + + // case 1: {ra} + // PN_atom_brace { ID("ra") } + // + // case 2: {ra,s0} -> + // PN_atom_brace { PN_dictorsetmaker { ID("ra") + // PN_dictorsetmaker_list { ID("s0") } } } + // + // case 3: {ra,s0-s1} -> + // PN_atom_brace { PN_dictorsetmaker { ID("ra") + // PN_dictorsetmaker_list { PN_arith_expr { + // ID("s0") TOKEN(MP_TOKEN_OP_MINUS) ID("s1") } } } } + + if (!MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_atom_brace) || + MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t *)node) != 1) { return false; } - nodes[0] = argument_nodes[0]; - bool negative = false; - if (!parse_register_offset_node(emit, opcode, opcode_data, argument_nodes[1], 1, &nodes[1], &nodes[2], &negative)) { - return false; + + mp_parse_node_struct_t *nodes = (mp_parse_node_struct_t *)node; + mp_uint_t register_id = 0; + + if (MP_PARSE_NODE_IS_ID(nodes->nodes[0])) { + if (!parse_register_node(nodes->nodes[0], ®ister_id, false)) { + return false; + } + *reglist = 4; + return register_id == ASM_RV32_REG_RA; } - mp_uint_t rd = 0; - mp_uint_t rs1 = 0; - if (!parse_register_node(nodes[0], &rd, opcode_data->argument1_kind & C)) { + if (!MP_PARSE_NODE_IS_STRUCT_KIND(nodes->nodes[0], PN_dictorsetmaker) || + MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t *)nodes->nodes[0]) != 2) { return false; } - if (!parse_register_node(nodes[1], &rs1, opcode_data->argument3_kind & C)) { + nodes = (mp_parse_node_struct_t *)nodes->nodes[0]; + if (!MP_PARSE_NODE_IS_ID(nodes->nodes[0]) || + !MP_PARSE_NODE_IS_STRUCT_KIND(nodes->nodes[1], PN_dictorsetmaker_list) || + !parse_register_node(nodes->nodes[0], ®ister_id, false) || + register_id != ASM_RV32_REG_RA) { return false; } - - mp_obj_t object; - mp_parse_node_get_int_maybe(nodes[2], &object); - mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift; - if (negative) { - immediate = (~immediate + 1) & (mp_uint_t)-1; + mp_parse_node_t *list_nodes; + size_t list_nodes_count = mp_parse_node_extract_list(&nodes->nodes[1], PN_dictorsetmaker_list2, &list_nodes); + if (list_nodes_count != 1 || !MP_PARSE_NODE_IS_STRUCT_KIND(list_nodes[0], PN_dictorsetmaker_list)) { + return false; } - if (!is_in_signed_mask(OPCODE_MASKS[opcode_data->argument2_mask], immediate)) { - emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode, 2)); + nodes = (mp_parse_node_struct_t *)list_nodes[0]; + if (MP_PARSE_NODE_STRUCT_NUM_NODES(nodes) != 1) { return false; } + if (MP_PARSE_NODE_IS_ID(nodes->nodes[0])) { + if (!parse_register_node(nodes->nodes[0], ®ister_id, false) || + register_id != ASM_RV32_REG_S0) { + return false; + } + *reglist = 5; + return true; + } - ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, immediate); - return true; + if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes->nodes[0], PN_arith_expr)) { + nodes = (mp_parse_node_struct_t *)nodes->nodes[0]; + if (MP_PARSE_NODE_STRUCT_NUM_NODES(nodes) != 3 || + !MP_PARSE_NODE_IS_ID(nodes->nodes[0]) || + !MP_PARSE_NODE_IS_TOKEN_KIND(nodes->nodes[1], MP_TOKEN_OP_MINUS) || + !MP_PARSE_NODE_IS_ID(nodes->nodes[2])) { + return false; + } + if (!parse_register_node(nodes->nodes[0], ®ister_id, false) || + register_id != ASM_RV32_REG_S0) { + return false; + } + if (!parse_register_node(nodes->nodes[2], ®ister_id, false) || + register_id == ASM_RV32_REG_S10) { + return false; + } + if (register_id == ASM_RV32_REG_S1) { + *reglist = 6; + return true; + } + if (register_id >= ASM_RV32_REG_S2 && register_id <= ASM_RV32_REG_S11) { + *reglist = 7 + MIN(register_id, ASM_RV32_REG_S10) - ASM_RV32_REG_S2; + return true; + } + } + + return false; +} + +static const qstr_short_t ZCMP_OPCODE_NAMES[] = { + MP_QSTR_cm_push, MP_QSTR_cm_pop, MP_QSTR_cm_popret, + MP_QSTR_cm_popretz, MP_QSTR_cm_mva01s, MP_QSTR_cm_mvsa01, +}; + +static const void *ZCMP_OPCODE_HANDLERS[] = { + asm_rv32_opcode_cmpush, asm_rv32_opcode_cmpop, + asm_rv32_opcode_cmpopret, asm_rv32_opcode_cmpopretz, + asm_rv32_opcode_cmmva01s, asm_rv32_opcode_cmmvsa01, +}; + +typedef void (*call_xi_t)(asm_rv32_t *state, mp_uint_t register_list, mp_int_t adjustment); +typedef void (*call_ss_t)(asm_rv32_t *state, mp_uint_t r1, mp_uint_t r2); + +static bool handle_zcmp_opcode(emit_inline_asm_t *emit, qstr opcode, mp_parse_node_t *argument_nodes) { + mp_uint_t argument_index = 0; + + for (size_t index = 0; index < MP_ARRAY_SIZE(ZCMP_OPCODE_NAMES); index++) { + if (ZCMP_OPCODE_NAMES[index] != opcode) { + continue; + } + const void *handler = ZCMP_OPCODE_HANDLERS[index]; + if (opcode == MP_QSTR_cm_mva01s || opcode == MP_QSTR_cm_mvsa01) { + mp_uint_t register_lhs = 0; + mp_uint_t register_rhs = 0; + + if (!parse_register_node(argument_nodes[0], ®ister_lhs, false) || + ((1U << register_lhs) & 0x00FC0300) == 0) { + goto invalid_s_register; + } + + if (!parse_register_node(argument_nodes[1], ®ister_rhs, false) || + ((1U << register_rhs) & 0x00FC0300) == 0) { + argument_index = 1; + goto invalid_s_register; + } + + if (register_lhs == register_rhs) { + emit_inline_rv32_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + MP_ERROR_TEXT("opcode '%q': registers must be different"), + opcode)); + return false; + } + + ((call_ss_t)handler)(&emit->as, register_lhs, register_rhs); + return true; + } + + mp_uint_t register_list; + if (!extract_register_list(emit, opcode, argument_nodes[0], ®ister_list)) { + emit_inline_rv32_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + MP_ERROR_TEXT("opcode '%q': malformed register list"), + opcode)); + return false; + } + + mp_obj_t stack_adjustment_object; + if (!mp_parse_node_get_int_maybe(argument_nodes[1], &stack_adjustment_object)) { + emit_inline_rv32_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + ET_WRONG_ARGUMENT_KIND, opcode, 2, MP_QSTR_integer)); + return false; + } + mp_int_t stack_adjustment = mp_obj_get_int(stack_adjustment_object); + // Either 0, 16, 32, or 48. + if ((abs((int32_t)stack_adjustment) & ~0x30U) != 0 || + ((opcode == MP_QSTR_cm_push) && stack_adjustment > 0) || + ((opcode != MP_QSTR_cm_push) && stack_adjustment < 0)) { + emit_inline_rv32_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + MP_ERROR_TEXT("opcode '%q': invalid stack adjustment"), + opcode)); + return false; + } + ((call_xi_t)handler)(&emit->as, register_list, abs((int32_t)stack_adjustment)); + return true; + } + + return false; + +invalid_s_register: + emit_inline_rv32_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + MP_ERROR_TEXT("opcode '%q' argument %d: wrong register(s)"), + opcode, argument_index + 1)); + return false; } static void emit_inline_rv32_opcode(emit_inline_asm_t *emit, qstr opcode, mp_uint_t arguments_count, mp_parse_node_t *argument_nodes) { @@ -785,10 +889,13 @@ static void emit_inline_rv32_opcode(emit_inline_asm_t *emit, qstr opcode, mp_uin } } - if (!opcode_data) { - emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - MP_ERROR_TEXT("unknown RV32 instruction '%q'"), opcode)); + if ((asm_rv32_allowed_extensions() & RV32_EXT_ZCMP) && !opcode_data && (arguments_count == 2) && handle_zcmp_opcode(emit, opcode, argument_nodes)) { + return; + } + + if (!opcode_data || (asm_rv32_allowed_extensions() & opcode_data->required_extensions) != opcode_data->required_extensions) { + emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + MP_ERROR_TEXT("invalid RV32 instruction '%q'"), opcode)); return; } @@ -796,36 +903,36 @@ static void emit_inline_rv32_opcode(emit_inline_asm_t *emit, qstr opcode, mp_uin assert((opcode_data->argument2_mask < MP_ARRAY_SIZE(OPCODE_MASKS)) && "Argument #2 opcode mask index out of bounds."); assert((opcode_data->argument3_mask < MP_ARRAY_SIZE(OPCODE_MASKS)) && "Argument #3 opcode mask index out of bounds."); assert((opcode_data->calling_convention < CALL_COUNT) && "Calling convention index out of bounds."); - if (opcode_data->calling_convention != CALL_RIR) { - if (opcode_data->arguments_count != arguments_count) { - emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENTS_COUNT, opcode, opcode_data->arguments_count)); - return; - } - if (opcode_data->arguments_count >= 1 && !validate_argument(emit, opcode, opcode_data, argument_nodes[0], 0)) { + mp_uint_t serialised_arguments[3] = { 0 }; + if (arguments_count != opcode_data->parse_nodes) { + emit_inline_rv32_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + ET_WRONG_ARGUMENTS_COUNT, opcode, opcode_data->parse_nodes)); + return; + } + + if (opcode_data->parse_nodes >= 1 && !serialise_argument(emit, opcode_data, argument_nodes[0], 0, &serialised_arguments[0])) { + return; + } + if (opcode_data->calling_convention == CALL_RIR) { + // "register, offset(base)" calls require some preprocessing to + // split the offset and base nodes - not to mention that if the offset + // is negative, the parser won't see the offset as a single node but as + // a sequence of the minus sign token followed by the number itself. + + if (!serialise_register_offset_node(emit, opcode_data, argument_nodes[1], 1, &serialised_arguments[1], &serialised_arguments[2])) { return; } - if (opcode_data->arguments_count >= 2 && !validate_argument(emit, opcode, opcode_data, argument_nodes[1], 1)) { + } else { + if (opcode_data->parse_nodes >= 2 && !serialise_argument(emit, opcode_data, argument_nodes[1], 1, &serialised_arguments[1])) { return; } - if (opcode_data->arguments_count >= 3 && !validate_argument(emit, opcode, opcode_data, argument_nodes[2], 2)) { + if (opcode_data->parse_nodes >= 3 && !serialise_argument(emit, opcode_data, argument_nodes[2], 2, &serialised_arguments[2])) { return; } - handle_opcode(emit, opcode, opcode_data, argument_nodes); - return; - } - - assert((opcode_data->argument2_kind & U) == 0 && "Offset must not be unsigned."); - assert((opcode_data->argument2_kind & Z) == 0 && "Offset can be zero."); - - if (arguments_count != 2) { - emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_WRONG_ARGUMENTS_COUNT, opcode, 2)); - return; } - handle_load_store_opcode_with_offset(emit, opcode, opcode_data, argument_nodes); + handle_opcode(emit, opcode_data, serialised_arguments); } #undef N diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index d6596337ae5..9c82921edfc 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -364,24 +364,15 @@ static int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_ return 0; } -typedef struct _cc_name_t { byte cc; - byte name[2]; -} cc_name_t; -static const cc_name_t cc_name_table[] = { - { ASM_THUMB_CC_EQ, { 'e', 'q' }}, - { ASM_THUMB_CC_NE, { 'n', 'e' }}, - { ASM_THUMB_CC_CS, { 'c', 's' }}, - { ASM_THUMB_CC_CC, { 'c', 'c' }}, - { ASM_THUMB_CC_MI, { 'm', 'i' }}, - { ASM_THUMB_CC_PL, { 'p', 'l' }}, - { ASM_THUMB_CC_VS, { 'v', 's' }}, - { ASM_THUMB_CC_VC, { 'v', 'c' }}, - { ASM_THUMB_CC_HI, { 'h', 'i' }}, - { ASM_THUMB_CC_LS, { 'l', 's' }}, - { ASM_THUMB_CC_GE, { 'g', 'e' }}, - { ASM_THUMB_CC_LT, { 'l', 't' }}, - { ASM_THUMB_CC_GT, { 'g', 't' }}, - { ASM_THUMB_CC_LE, { 'l', 'e' }}, +#define ENCODE_CC(c1, c2) (((uint16_t)(c1) << 8) | (uint16_t)(c2)) + +// Positions in the table match the condition code value. +static const uint16_t CONDITION_CODES[] = { + ENCODE_CC('e', 'q'), ENCODE_CC('n', 'e'), ENCODE_CC('c', 's'), + ENCODE_CC('c', 'c'), ENCODE_CC('m', 'i'), ENCODE_CC('p', 'l'), + ENCODE_CC('v', 's'), ENCODE_CC('v', 'c'), ENCODE_CC('h', 'i'), + ENCODE_CC('l', 's'), ENCODE_CC('g', 'e'), ENCODE_CC('l', 't'), + ENCODE_CC('g', 't'), ENCODE_CC('l', 'e'), }; typedef struct _format_4_op_t { byte op; @@ -574,9 +565,11 @@ static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a || (op_len == 5 && op_str[3] == '_' && (op_str[4] == 'n' || (ARMV7M && op_str[4] == 'w'))))) { mp_uint_t cc = -1; - for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) { - if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) { - cc = cc_name_table[i].cc; + uint16_t condition_code = ENCODE_CC(op_str[1], op_str[2]); + for (size_t i = 0; i < MP_ARRAY_SIZE(CONDITION_CODES); ++i) { + if (condition_code == CONDITION_CODES[i]) { + cc = i; + break; } } if (cc == (mp_uint_t)-1) { @@ -592,12 +585,14 @@ static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a } } else if (ARMV7M && op_str[0] == 'i' && op_str[1] == 't') { const char *arg_str = get_arg_str(pn_args[0]); + if (strlen(arg_str) != 2) { + goto unknown_op; + } mp_uint_t cc = -1; - for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) { - if (arg_str[0] == cc_name_table[i].name[0] - && arg_str[1] == cc_name_table[i].name[1] - && arg_str[2] == '\0') { - cc = cc_name_table[i].cc; + uint16_t condition_code = ENCODE_CC(arg_str[0], arg_str[1]); + for (size_t i = 0; i < MP_ARRAY_SIZE(CONDITION_CODES); ++i) { + if (condition_code == CONDITION_CODES[i]) { + cc = i; break; } } diff --git a/py/emitinlinextensa.c b/py/emitinlinextensa.c index fed259cfc6b..c58754d47c3 100644 --- a/py/emitinlinextensa.c +++ b/py/emitinlinextensa.c @@ -35,6 +35,18 @@ #if MICROPY_EMIT_INLINE_XTENSA +#include "py/persistentcode.h" + +static inline bool emit_windowed_code() { + #if MICROPY_DYNAMIC_COMPILER + return mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSAWIN; + #elif MICROPY_EMIT_XTENSAWIN + return true; + #else + return false; + #endif +} + struct _emit_inline_asm_t { asm_xtensa_t as; uint16_t pass; @@ -73,11 +85,19 @@ static void emit_inline_xtensa_start_pass(emit_inline_asm_t *emit, pass_kind_t p memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); } mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); - asm_xtensa_entry(&emit->as, 0); + if (emit_windowed_code()) { + asm_xtensa_entry_win(&emit->as, 0); + } else { + asm_xtensa_entry(&emit->as, 0); + } } static void emit_inline_xtensa_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) { - asm_xtensa_exit(&emit->as); + if (emit_windowed_code()) { + asm_xtensa_exit_win(&emit->as); + } else { + asm_xtensa_exit(&emit->as); + } asm_xtensa_end_pass(&emit->as); } @@ -168,127 +188,273 @@ static int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_ return 0; } -#define RRR (0) -#define RRI8 (1) -#define RRI8_B (2) - -typedef struct _opcode_table_3arg_t { - uint16_t name; // actually a qstr, which should fit in 16 bits - uint8_t type; - uint8_t a0 : 4; - uint8_t a1 : 4; -} opcode_table_3arg_t; - -static const opcode_table_3arg_t opcode_table_3arg[] = { - // arithmetic opcodes: reg, reg, reg - {MP_QSTR_and_, RRR, 0, 1}, - {MP_QSTR_or_, RRR, 0, 2}, - {MP_QSTR_xor, RRR, 0, 3}, - {MP_QSTR_add, RRR, 0, 8}, - {MP_QSTR_sub, RRR, 0, 12}, - {MP_QSTR_mull, RRR, 2, 8}, - - // load/store/addi opcodes: reg, reg, imm - // upper nibble of type encodes the range of the immediate arg - {MP_QSTR_l8ui, RRI8 | 0x10, 2, 0}, - {MP_QSTR_l16ui, RRI8 | 0x30, 2, 1}, - {MP_QSTR_l32i, RRI8 | 0x50, 2, 2}, - {MP_QSTR_s8i, RRI8 | 0x10, 2, 4}, - {MP_QSTR_s16i, RRI8 | 0x30, 2, 5}, - {MP_QSTR_s32i, RRI8 | 0x50, 2, 6}, - {MP_QSTR_l16si, RRI8 | 0x30, 2, 9}, - {MP_QSTR_addi, RRI8 | 0x00, 2, 12}, - - // branch opcodes: reg, reg, label - {MP_QSTR_ball, RRI8_B, ASM_XTENSA_CC_ALL, 0}, - {MP_QSTR_bany, RRI8_B, ASM_XTENSA_CC_ANY, 0}, - {MP_QSTR_bbc, RRI8_B, ASM_XTENSA_CC_BC, 0}, - {MP_QSTR_bbs, RRI8_B, ASM_XTENSA_CC_BS, 0}, - {MP_QSTR_beq, RRI8_B, ASM_XTENSA_CC_EQ, 0}, - {MP_QSTR_bge, RRI8_B, ASM_XTENSA_CC_GE, 0}, - {MP_QSTR_bgeu, RRI8_B, ASM_XTENSA_CC_GEU, 0}, - {MP_QSTR_blt, RRI8_B, ASM_XTENSA_CC_LT, 0}, - {MP_QSTR_bnall, RRI8_B, ASM_XTENSA_CC_NALL, 0}, - {MP_QSTR_bne, RRI8_B, ASM_XTENSA_CC_NE, 0}, - {MP_QSTR_bnone, RRI8_B, ASM_XTENSA_CC_NONE, 0}, +static const qstr_short_t BRANCH_OPCODE_NAMES[] = { + MP_QSTR_bnone, MP_QSTR_beq, MP_QSTR_blt, MP_QSTR_bltu, MP_QSTR_ball, + MP_QSTR_bbc, MP_QSTR_, MP_QSTR_, MP_QSTR_bany, MP_QSTR_bne, + MP_QSTR_bge, MP_QSTR_bgeu, MP_QSTR_bnall, MP_QSTR_bbs, +}; + +#define RRR_R0 (1 << 4) +#define RRR_R1 (2 << 4) +#define RRR_R2 (3 << 4) + +#define RRR (0) +#define RRI8 (1) +#define RRRN (2) + +static const struct opcode_entry_t { + qstr_short_t name; + uint16_t operands : 2; + uint16_t op2 : 4; + uint16_t op1 : 4; + uint16_t op0 : 4; + // 2 bits available here + uint32_t r : 6; + uint32_t s : 6; + uint32_t t : 6; + uint32_t shift : 3; + uint32_t kind : 2; + // 9 bits available here +} OPCODE_TABLE[] = { + { MP_QSTR_abs_, 2, 6, 0, 0, RRR_R0, 1, RRR_R1, 0, RRR }, + { MP_QSTR_add, 3, 8, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_add_n, 3, 0, 0, 10, RRR_R0, RRR_R1, RRR_R2, 0, RRRN }, + { MP_QSTR_addi, 3, 0, 0, 2, 12, RRR_R1, RRR_R0, 0, RRI8 }, + { MP_QSTR_addx2, 3, 9, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_addx4, 3, 10, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_addx8, 3, 11, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_and_, 3, 1, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_callx0, 1, 0, 0, 0, 0, RRR_R0, 12, 0, RRR }, + { MP_QSTR_jx, 1, 0, 0, 0, 0, RRR_R0, 10, 0, RRR }, + { MP_QSTR_l16si, 3, 0, 0, 2, 9, RRR_R1, RRR_R0, 3, RRI8 }, + { MP_QSTR_l16ui, 3, 0, 0, 2, 1, RRR_R1, RRR_R0, 3, RRI8 }, + { MP_QSTR_l32i, 3, 0, 0, 2, 2, RRR_R1, RRR_R0, 5, RRI8 }, + { MP_QSTR_l8ui, 3, 0, 0, 2, 0, RRR_R1, RRR_R0, 1, RRI8 }, + { MP_QSTR_mov, 2, 0, 0, 13, 0, RRR_R1, RRR_R0, 0, RRRN }, + { MP_QSTR_mov_n, 2, 0, 0, 13, 0, RRR_R1, RRR_R0, 0, RRRN }, + { MP_QSTR_mull, 3, 8, 2, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_neg, 2, 6, 0, 0, RRR_R0, 0, RRR_R1, 0, RRR }, + { MP_QSTR_nop, 0, 0, 0, 0, 2, 0, 15, 0, RRR }, + { MP_QSTR_nop_n, 0, 0, 0, 13, 15, 0, 3, 0, RRRN }, + { MP_QSTR_nsa, 2, 4, 0, 0, 14, RRR_R1, RRR_R0, 0, RRR }, + { MP_QSTR_nsau, 2, 4, 0, 0, 15, RRR_R1, RRR_R0, 0, RRR }, + { MP_QSTR_or_, 3, 2, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_ret, 0, 0, 0, 13, 15, 0, 0, 0, RRRN }, + { MP_QSTR_ret_n, 0, 0, 0, 13, 15, 0, 0, 0, RRRN }, + { MP_QSTR_s16i, 3, 0, 0, 2, 5, RRR_R1, RRR_R0, 3, RRI8 }, + { MP_QSTR_s32i, 3, 0, 0, 2, 6, RRR_R1, RRR_R0, 5, RRI8 }, + { MP_QSTR_s8i, 3, 0, 0, 2, 4, RRR_R1, RRR_R0, 1, RRI8 }, + { MP_QSTR_sll, 2, 10, 1, 0, RRR_R0, RRR_R1, 0, 0, RRR }, + { MP_QSTR_sra, 2, 11, 1, 0, RRR_R0, 0, RRR_R1, 0, RRR }, + { MP_QSTR_src, 3, 8, 1, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_srl, 2, 9, 1, 0, RRR_R0, 0, RRR_R1, 0, RRR }, + { MP_QSTR_ssa8b, 1, 4, 0, 0, 3, RRR_R0, 0, 0, RRR }, + { MP_QSTR_ssa8l, 1, 4, 0, 0, 2, RRR_R0, 0, 0, RRR }, + { MP_QSTR_ssl, 1, 4, 0, 0, 1, RRR_R0, 0, 0, RRR }, + { MP_QSTR_ssr, 1, 4, 0, 0, 0, RRR_R0, 0, 0, RRR }, + { MP_QSTR_sub, 3, 12, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_subx2, 3, 13, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_subx4, 3, 14, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_subx8, 3, 15, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + { MP_QSTR_xor, 3, 3, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR }, + #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES + { MP_QSTR_dsync, 0, 0, 0, 0, 2, 0, 3, 0, RRR }, + { MP_QSTR_esync, 0, 0, 0, 0, 2, 0, 2, 0, RRR }, + { MP_QSTR_extw, 0, 0, 0, 0, 2, 0, 13, 0, RRR }, + { MP_QSTR_ill, 0, 0, 0, 0, 2, 0, 0, 0, RRR }, + { MP_QSTR_ill_n, 0, 0, 0, 13, 15, 0, 6, 0, RRRN }, + { MP_QSTR_isync, 0, 0, 0, 0, 2, 0, 0, 0, RRR }, + { MP_QSTR_memw, 0, 0, 0, 0, 2, 0, 12, 0, RRR }, + { MP_QSTR_rer, 2, 4, 0, 0, 6, RRR_R1, RRR_R0, 0, RRR }, + { MP_QSTR_rsync, 0, 0, 0, 0, 2, 0, 1, 0, RRR }, + { MP_QSTR_wer, 2, 4, 0, 0, 7, RRR_R1, RRR_R0, 0, RRR }, + #endif +}; + +// The index of the first four qstrs matches the CCZ condition value to be +// embedded into the opcode. +static const qstr_short_t BCCZ_OPCODES[] = { + MP_QSTR_beqz, MP_QSTR_bnez, MP_QSTR_bltz, MP_QSTR_bgez, + MP_QSTR_beqz_n, MP_QSTR_bnez_n }; static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) { size_t op_len; const char *op_str = (const char *)qstr_data(op, &op_len); - if (n_args == 0) { - if (op == MP_QSTR_ret_n) { - asm_xtensa_op_ret_n(&emit->as); - } else { - goto unknown_op; + for (size_t index = 0; index < MP_ARRAY_SIZE(OPCODE_TABLE); index++) { + const struct opcode_entry_t *entry = &OPCODE_TABLE[index]; + if (entry->name == op) { + if (n_args != entry->operands) { + goto unknown_op; + } + + uint32_t opcode = ((entry->r & 0x0F) << 12) | ((entry->s & 0x0F) << 8) | ((entry->t & 0x0F) << 4) | entry->op0; + if (entry->kind == RRR) { + opcode |= (entry->op2 << 20) | (entry->op1 << 16); + } else if (entry->kind == RRI8) { + int min = 0; + int max = 0; + int shift = entry->shift; + if (shift > 0) { + shift >>= 1; + max = 0xFF << shift; + } else { + min = -128; + max = 127; + } + uint32_t immediate = get_arg_i(emit, op_str, pn_args[2], min, max); + opcode |= ((immediate >> shift) & 0xFF) << 16; + } + if (entry->r >= RRR_R0) { + opcode |= get_arg_reg(emit, op_str, pn_args[(entry->r >> 4) - 1]) << 12; + } + if (entry->s >= RRR_R0) { + opcode |= get_arg_reg(emit, op_str, pn_args[(entry->s >> 4) - 1]) << 8; + } + if (entry->t >= RRR_R0) { + opcode |= get_arg_reg(emit, op_str, pn_args[(entry->t >> 4) - 1]) << 4; + } + if (entry->kind == RRRN) { + assert((opcode >> 16) == 0 && "Stray bits in narrow opcode"); + asm_xtensa_op16(&emit->as, (uint16_t)(opcode & 0xFFFF)); + } else { + asm_xtensa_op24(&emit->as, opcode); + } + return; } + } - } else if (n_args == 1) { - if (op == MP_QSTR_callx0) { - uint r0 = get_arg_reg(emit, op_str, pn_args[0]); - asm_xtensa_op_callx0(&emit->as, r0); - } else if (op == MP_QSTR_j) { + if (n_args == 1) { + if (op == MP_QSTR_j) { int label = get_arg_label(emit, op_str, pn_args[0]); asm_xtensa_j_label(&emit->as, label); - } else if (op == MP_QSTR_jx) { - uint r0 = get_arg_reg(emit, op_str, pn_args[0]); - asm_xtensa_op_jx(&emit->as, r0); + } else if (op == MP_QSTR_ssai) { + mp_uint_t sa = get_arg_i(emit, op_str, pn_args[0], 0, 31); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 4, sa & 0x0F, (sa >> 4) & 0x01)); + } else if (op == MP_QSTR_call0) { + mp_uint_t label = get_arg_label(emit, op_str, pn_args[0]); + asm_xtensa_call0(&emit->as, label); + #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES + } else if (op == MP_QSTR_fsync) { + mp_uint_t imm3 = get_arg_i(emit, op_str, pn_args[0], 0, 7); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 0, 2, 8 | imm3, 0)); + #endif } else { goto unknown_op; } - } else if (n_args == 2) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); - if (op == MP_QSTR_beqz) { - int label = get_arg_label(emit, op_str, pn_args[1]); - asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_EQ, r0, label); - } else if (op == MP_QSTR_bnez) { - int label = get_arg_label(emit, op_str, pn_args[1]); - asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_NE, r0, label); - } else if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) { - // we emit mov.n for both "mov" and "mov_n" opcodes - uint r1 = get_arg_reg(emit, op_str, pn_args[1]); - asm_xtensa_op_mov_n(&emit->as, r0, r1); - } else if (op == MP_QSTR_movi) { + for (size_t index = 0; index < MP_ARRAY_SIZE(BCCZ_OPCODES); index++) { + if (op == BCCZ_OPCODES[index]) { + mp_uint_t label = get_arg_label(emit, op_str, pn_args[1]); + asm_xtensa_bccz_reg_label(&emit->as, index & 0x03, r0, label); + return; + } + } + if (op == MP_QSTR_movi) { // for convenience we emit l32r if the integer doesn't fit in movi uint32_t imm = get_arg_i(emit, op_str, pn_args[1], 0, 0); asm_xtensa_mov_reg_i32(&emit->as, r0, imm); - } else { + } else if (op == MP_QSTR_l32r) { + mp_uint_t label = get_arg_label(emit, op_str, pn_args[1]); + asm_xtensa_l32r(&emit->as, r0, label); + } else if (op == MP_QSTR_movi_n) { + mp_int_t imm = get_arg_i(emit, op_str, pn_args[1], -32, 95); + asm_xtensa_op_movi_n(&emit->as, r0, imm); + } else + #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES + if (op == MP_QSTR_rsr) { + mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 3, 0, sr, r0)); + } else if (op == MP_QSTR_rur) { + mp_uint_t imm8 = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 3, 14, r0, (imm8 >> 4) & 0x0F, imm8 & 0x0F)); + } else if (op == MP_QSTR_wsr) { + mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 3, 1, sr, r0)); + } else if (op == MP_QSTR_wur) { + mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 3, 15, sr, r0)); + } else if (op == MP_QSTR_xsr) { + mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 1, 6, sr, r0)); + } else + #endif + { goto unknown_op; } - } else if (n_args == 3) { - // search table for 3 arg instructions - for (uint i = 0; i < MP_ARRAY_SIZE(opcode_table_3arg); i++) { - const opcode_table_3arg_t *o = &opcode_table_3arg[i]; - if (op == o->name) { - uint r0 = get_arg_reg(emit, op_str, pn_args[0]); - uint r1 = get_arg_reg(emit, op_str, pn_args[1]); - if (o->type == RRR) { - uint r2 = get_arg_reg(emit, op_str, pn_args[2]); - asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, o->a0, o->a1, r0, r1, r2)); - } else if (o->type == RRI8_B) { - int label = get_arg_label(emit, op_str, pn_args[2]); - asm_xtensa_bcc_reg_reg_label(&emit->as, o->a0, r0, r1, label); - } else { - int shift, min, max; - if ((o->type & 0xf0) == 0) { - shift = 0; - min = -128; - max = 127; - } else { - shift = (o->type & 0xf0) >> 5; - min = 0; - max = 0xff << shift; - } - uint32_t imm = get_arg_i(emit, op_str, pn_args[2], min, max); - asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(o->a0, o->a1, r1, r0, (imm >> shift) & 0xff)); - } + for (size_t index = 0; index < MP_ARRAY_SIZE(BRANCH_OPCODE_NAMES); index++) { + if (BRANCH_OPCODE_NAMES[index] == op) { + int r0 = get_arg_reg(emit, op_str, pn_args[0]); + int r1 = get_arg_reg(emit, op_str, pn_args[1]); + int label = get_arg_label(emit, op_str, pn_args[2]); + asm_xtensa_bcc_reg_reg_label(&emit->as, index, r0, r1, label); return; } } - goto unknown_op; + + if (op == MP_QSTR_addi_n) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_int_t imm4 = get_arg_i(emit, op_str, pn_args[2], -1, 15); + asm_xtensa_op16(&emit->as, ASM_XTENSA_ENCODE_RRRN(11, r0, r1, (imm4 != 0 ? imm4 : -1))); + } else if (op == MP_QSTR_addmi) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_int_t imm8 = get_arg_i(emit, op_str, pn_args[2], -128 * 256, 127 * 256); + if ((imm8 & 0xFF) != 0) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("%d is not a multiple of %d"), imm8, 256)); + } else { + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(2, 13, r1, r0, imm8 >> 8)); + } + } else if (op == MP_QSTR_bbci) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t bit = get_arg_i(emit, op_str, pn_args[1], 0, 31); + mp_int_t label = get_arg_label(emit, op_str, pn_args[2]); + asm_xtensa_bit_branch(&emit->as, r0, bit, label, 6); + } else if (op == MP_QSTR_bbsi) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t bit = get_arg_i(emit, op_str, pn_args[1], 0, 31); + mp_uint_t label = get_arg_label(emit, op_str, pn_args[2]); + asm_xtensa_bit_branch(&emit->as, r0, bit, label, 14); + } else if (op == MP_QSTR_slli) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t bits = 32 - get_arg_i(emit, op_str, pn_args[2], 1, 31); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 0 | ((bits >> 4) & 0x01), r0, r1, bits & 0x0F)); + } else if (op == MP_QSTR_srai) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t bits = get_arg_i(emit, op_str, pn_args[2], 0, 31); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 2 | ((bits >> 4) & 0x01), r0, bits & 0x0F, r1)); + } else if (op == MP_QSTR_srli) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t bits = get_arg_i(emit, op_str, pn_args[2], 0, 15); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 4, r0, bits, r1)); + } else if (op == MP_QSTR_l32i_n) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t imm = get_arg_i(emit, op_str, pn_args[2], 0, 60); + if ((imm & 0x03) != 0) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("%d is not a multiple of %d"), imm, 4)); + } else { + asm_xtensa_op_l32i_n(&emit->as, r0, r1, imm >> 2); + } + } else if (op == MP_QSTR_s32i_n) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t imm = get_arg_i(emit, op_str, pn_args[2], 0, 60); + if ((imm & 0x03) != 0) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("%d is not a multiple of %d"), imm, 4)); + } else { + asm_xtensa_op_s32i_n(&emit->as, r0, r1, imm >> 2); + } + } else { + goto unknown_op; + } } else { goto unknown_op; diff --git a/py/emitnative.c b/py/emitnative.c index a888418e5df..9ac62f6d362 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -222,12 +222,6 @@ static const uint8_t reg_local_table[MAX_REGS_FOR_LOCAL_VARS] = {REG_LOCAL_1, RE *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \ } while (0) -#if N_RV32 -#define FIT_SIGNED(value, bits) \ - ((((value) & ~((1U << ((bits) - 1)) - 1)) == 0) || \ - (((value) & ~((1U << ((bits) - 1)) - 1)) == ~((1U << ((bits) - 1)) - 1))) -#endif - typedef enum { STACK_VALUE, STACK_REG, @@ -252,6 +246,7 @@ typedef enum { VTYPE_BUILTIN_CAST = 0x70 | MP_NATIVE_TYPE_OBJ, } vtype_kind_t; +#if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_NONE static qstr vtype_to_qstr(vtype_kind_t vtype) { switch (vtype) { case VTYPE_PYOBJ: @@ -275,6 +270,7 @@ static qstr vtype_to_qstr(vtype_kind_t vtype) { return MP_QSTR_None; } } +#endif typedef struct _stack_info_t { vtype_kind_t vtype; @@ -330,9 +326,14 @@ struct _emit_t { ASM_T *as; }; -#ifndef REG_ZERO +#ifdef REG_ZERO +#define ASM_MOV_LOCAL_MP_OBJ_NULL(as, local_num, reg_temp) \ + ASM_MOV_LOCAL_REG(as, local_num, REG_ZERO) +#else #define REG_ZERO REG_TEMP0 -#define ASM_CLR_REG(state, rd) ASM_XOR_REG_REG(state, rd, rd) +#define ASM_MOV_LOCAL_MP_OBJ_NULL(as, local_num, reg_temp) \ + ASM_CLR_REG(as, reg_temp); \ + ASM_MOV_LOCAL_REG(as, local_num, reg_temp) #endif static void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj); @@ -341,6 +342,12 @@ static void emit_native_global_exc_exit(emit_t *emit); static void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj); emit_t *EXPORT_FUN(new)(mp_emit_common_t * emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels) { + // Generated code performing exception handling assumes that MP_OBJ_NULL + // equals to 0 to simplify some checks, leveraging dedicated opcodes for + // comparisons against 0. If this assumption does not hold true anymore + // then generated code won't work correctly. + MP_STATIC_ASSERT(MP_OBJ_NULL == 0); + emit_t *emit = m_new0(emit_t, 1); emit->emit_common = emit_common; emit->error_slot = error_slot; @@ -467,6 +474,30 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->stack_info[i].vtype = VTYPE_UNBOUND; } + char *qualified_name = NULL; + + #if N_DEBUG + scope_t *current_scope = scope; + vstr_t *qualified_name_vstr = vstr_new(qstr_len(current_scope->simple_name)); + size_t fragment_length = 0; + const byte *fragment_pointer; + for (;;) { + fragment_pointer = qstr_data(current_scope->simple_name, &fragment_length); + vstr_hint_size(qualified_name_vstr, fragment_length); + memmove(qualified_name_vstr->buf + fragment_length, qualified_name_vstr->buf, qualified_name_vstr->len); + memcpy(qualified_name_vstr->buf, fragment_pointer, fragment_length); + qualified_name_vstr->len += fragment_length; + if (current_scope->parent == NULL || current_scope->parent->simple_name == MP_QSTR__lt_module_gt_) { + break; + } + vstr_ins_char(qualified_name_vstr, 0, '.'); + current_scope = current_scope->parent; + } + qualified_name = vstr_null_terminated_str(qualified_name_vstr); + #else + (void)qualified_name; + #endif + mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); // generate code for entry to function @@ -513,7 +544,7 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop } // Entry to function - ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs); + ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs, qualified_name); #if N_X86 asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1); @@ -584,7 +615,7 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset); - ASM_ENTRY(emit->as, emit->code_state_start); + ASM_ENTRY(emit->as, emit->code_state_start, qualified_name); // Reset the state size for the state pointed to by REG_GENERATOR_STATE emit->code_state_start = 0; @@ -616,7 +647,7 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->stack_start = emit->code_state_start + SIZEOF_CODE_STATE; // Allocate space on C-stack for code_state structure, which includes state - ASM_ENTRY(emit->as, emit->stack_start + emit->n_state); + ASM_ENTRY(emit->as, emit->stack_start + emit->n_state, qualified_name); // Prepare incoming arguments for call to mp_setup_code_state @@ -682,6 +713,10 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop } } } + + #if N_DEBUG + vstr_free(qualified_name_vstr); + #endif } static inline void emit_native_write_code_info_byte(emit_t *emit, byte val) { @@ -1150,7 +1185,7 @@ static void emit_native_leave_exc_stack(emit_t *emit, bool start_of_handler) { // Optimisation: PC is already cleared by global exc handler return; } - ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET); + ASM_CLR_REG(emit->as, REG_RET); } else { // Found new active handler, get its PC ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label); @@ -1247,8 +1282,7 @@ static void emit_native_global_exc_entry(emit_t *emit) { ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, true); } else { // Clear the unwind state - ASM_CLR_REG(emit->as, REG_ZERO); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_ZERO); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_ZERO); // clear nlr.ret_val, because it's passed to mp_native_raise regardless // of whether there was an exception or not @@ -1268,8 +1302,7 @@ static void emit_native_global_exc_entry(emit_t *emit) { ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, global_except_label, true); // Clear PC of current code block, and jump there to resume execution - ASM_CLR_REG(emit->as, REG_ZERO); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_ZERO); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_ZERO); ASM_JUMP_REG(emit->as, REG_LOCAL_1); // Global exception handler: check for valid exception handler @@ -1311,8 +1344,7 @@ static void emit_native_global_exc_entry(emit_t *emit) { // Check LOCAL_IDX_THROW_VAL for any injected value ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_THROW_VAL(emit)); - ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); emit_call(emit, MP_F_NATIVE_RAISE); } } @@ -1579,87 +1611,50 @@ static void emit_native_load_subscr(emit_t *emit) { switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory - // TODO optimise to use thumb ldrb r1, [r2, r3] + #ifdef ASM_LOAD8_REG_REG_OFFSET + ASM_LOAD8_REG_REG_OFFSET(emit->as, REG_RET, reg_base, index_value); + #else if (index_value != 0) { // index is non-zero - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_ldrb_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 12)) { - asm_rv32_opcode_lbu(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_op_l8ui(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif need_reg_single(emit, reg_index, 0); ASM_MOV_REG_IMM(emit->as, reg_index, index_value); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base reg_base = reg_index; } ASM_LOAD8_REG_REG(emit->as, REG_RET, reg_base); // load from (base+index) + #endif break; } case VTYPE_PTR16: { // pointer to 16-bit memory + #ifdef ASM_LOAD16_REG_REG_OFFSET + ASM_LOAD16_REG_REG_OFFSET(emit->as, REG_RET, reg_base, index_value); + #else if (index_value != 0) { // index is a non-zero immediate - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_ldrh_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 11)) { - asm_rv32_opcode_lhu(emit->as, REG_RET, reg_base, index_value << 1); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_op_l16ui(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif need_reg_single(emit, reg_index, 0); ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base reg_base = reg_index; } ASM_LOAD16_REG_REG(emit->as, REG_RET, reg_base); // load from (base+2*index) + #endif break; } case VTYPE_PTR32: { // pointer to 32-bit memory + #ifdef ASM_LOAD32_REG_REG_OFFSET + ASM_LOAD32_REG_REG_OFFSET(emit->as, REG_RET, reg_base, index_value); + #else if (index_value != 0) { // index is a non-zero immediate - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_ldr_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 10)) { - asm_rv32_opcode_lw(emit->as, REG_RET, reg_base, index_value << 2); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_l32i_optimised(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif need_reg_single(emit, reg_index, 0); ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base reg_base = reg_index; } ASM_LOAD32_REG_REG(emit->as, REG_RET, reg_base); // load from (base+4*index) + #endif break; } default: @@ -1680,40 +1675,36 @@ static void emit_native_load_subscr(emit_t *emit) { switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory - // TODO optimise to use thumb ldrb r1, [r2, r3] + #ifdef ASM_LOAD8_REG_REG_REG + ASM_LOAD8_REG_REG_REG(emit->as, REG_RET, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_LOAD8_REG_REG(emit->as, REG_RET, REG_ARG_1); // store value to (base+index) + #endif break; } case VTYPE_PTR16: { // pointer to 16-bit memory - #if N_XTENSA || N_XTENSAWIN - asm_xtensa_op_addx2(emit->as, REG_ARG_1, reg_index, REG_ARG_1); - asm_xtensa_op_l16ui(emit->as, REG_RET, REG_ARG_1, 0); - break; - #endif + #ifdef ASM_LOAD16_REG_REG_REG + ASM_LOAD16_REG_REG_REG(emit->as, REG_RET, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_LOAD16_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+2*index) + #endif break; } case VTYPE_PTR32: { // pointer to word-size memory - #if N_RV32 - asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2); - asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2); - asm_rv32_opcode_lw(emit->as, REG_RET, REG_ARG_1, 0); - break; - #elif N_XTENSA || N_XTENSAWIN - asm_xtensa_op_addx4(emit->as, REG_ARG_1, reg_index, REG_ARG_1); - asm_xtensa_op_l32i_n(emit->as, REG_RET, REG_ARG_1, 0); - break; - #endif + #ifdef ASM_LOAD32_REG_REG_REG + ASM_LOAD32_REG_REG_REG(emit->as, REG_RET, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_LOAD32_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+4*index) + #endif break; } default: @@ -1856,92 +1847,47 @@ static void emit_native_store_subscr(emit_t *emit) { switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory - // TODO optimise to use thumb strb r1, [r2, r3] + #ifdef ASM_STORE8_REG_REG_OFFSET + ASM_STORE8_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value); + #else if (index_value != 0) { // index is non-zero - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_strb_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 12)) { - asm_rv32_opcode_sb(emit->as, reg_value, reg_base, index_value); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_op_s8i(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif ASM_MOV_REG_IMM(emit->as, reg_index, index_value); - #if N_ARM - asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); - return; - #endif ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base reg_base = reg_index; } ASM_STORE8_REG_REG(emit->as, reg_value, reg_base); // store value to (base+index) + #endif break; } case VTYPE_PTR16: { // pointer to 16-bit memory + #ifdef ASM_STORE16_REG_REG_OFFSET + ASM_STORE16_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value); + #else if (index_value != 0) { // index is a non-zero immediate - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_strh_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 11)) { - asm_rv32_opcode_sh(emit->as, reg_value, reg_base, index_value << 1); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_op_s16i(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base reg_base = reg_index; } ASM_STORE16_REG_REG(emit->as, reg_value, reg_base); // store value to (base+2*index) + #endif break; } case VTYPE_PTR32: { // pointer to 32-bit memory + #ifdef ASM_STORE32_REG_REG_OFFSET + ASM_STORE32_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value); + #else if (index_value != 0) { // index is a non-zero immediate - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_str_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 10)) { - asm_rv32_opcode_sw(emit->as, reg_value, reg_base, index_value << 2); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_s32i_optimised(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_ARM - ASM_MOV_REG_IMM(emit->as, reg_index, index_value); - asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); - return; - #endif ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base reg_base = reg_index; } ASM_STORE32_REG_REG(emit->as, reg_value, reg_base); // store value to (base+4*index) + #endif break; } default: @@ -1972,50 +1918,36 @@ static void emit_native_store_subscr(emit_t *emit) { switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory - // TODO optimise to use thumb strb r1, [r2, r3] - #if N_ARM - asm_arm_strb_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); - break; - #endif + #ifdef ASM_STORE8_REG_REG_REG + ASM_STORE8_REG_REG_REG(emit->as, reg_value, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_STORE8_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+index) + #endif break; } case VTYPE_PTR16: { // pointer to 16-bit memory - #if N_ARM - asm_arm_strh_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); - break; - #elif N_XTENSA || N_XTENSAWIN - asm_xtensa_op_addx2(emit->as, REG_ARG_1, reg_index, REG_ARG_1); - asm_xtensa_op_s16i(emit->as, reg_value, REG_ARG_1, 0); - break; - #endif + #ifdef ASM_STORE16_REG_REG_REG + ASM_STORE16_REG_REG_REG(emit->as, reg_value, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_STORE16_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+2*index) + #endif break; } case VTYPE_PTR32: { // pointer to 32-bit memory - #if N_ARM - asm_arm_str_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); - break; - #elif N_RV32 - asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2); - asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2); - asm_rv32_opcode_sw(emit->as, reg_value, REG_ARG_1, 0); - break; - #elif N_XTENSA || N_XTENSAWIN - asm_xtensa_op_addx4(emit->as, REG_ARG_1, reg_index, REG_ARG_1); - asm_xtensa_op_s32i_n(emit->as, reg_value, REG_ARG_1, 0); - break; - #endif + #ifdef ASM_STORE32_REG_REG_REG + ASM_STORE32_REG_REG_REG(emit->as, reg_value, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_STORE32_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+4*index) + #endif break; } default: @@ -2051,7 +1983,7 @@ static void emit_native_delete_attr(emit_t *emit, qstr qst) { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); - ASM_XOR_REG_REG(emit->as, REG_ARG_3, REG_ARG_3); // arg3 = value (null for delete) + ASM_CLR_REG(emit->as, REG_ARG_3); // arg3 = value (null for delete) emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post(emit); } @@ -2197,7 +2129,7 @@ static void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t exc // No finally, handle the jump ourselves // First, restore the exception handler address for the jump if (e < emit->exc_stack) { - ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET); + ASM_CLR_REG(emit->as, REG_RET); } else { ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label); } @@ -2328,8 +2260,7 @@ static void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { // Replace exception with MP_OBJ_NULL. emit_native_label_assign(emit, *emit->label_slot); - ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); // end of with cleanup nlr_catch block emit_native_label_assign(emit, *emit->label_slot + 1); @@ -2436,8 +2367,7 @@ static void emit_native_for_iter_end(emit_t *emit) { static void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { if (within_exc_handler) { // Cancel any active exception so subsequent handlers don't see it - ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); } else { emit_native_leave_exc_stack(emit, false); } @@ -2450,22 +2380,23 @@ static void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { if (op == MP_UNARY_OP_POSITIVE) { // No-operation, just leave the argument on the stack. } else if (op == MP_UNARY_OP_NEGATIVE) { - int reg = REG_RET; - emit_pre_pop_reg_flexible(emit, &vtype, ®, reg, reg); - ASM_NEG_REG(emit->as, reg); - emit_post_push_reg(emit, vtype, reg); + emit_pre_pop_reg(emit, &vtype, REG_RET); + ASM_NEG_REG(emit->as, REG_RET); + emit_post_push_reg(emit, vtype, REG_RET); } else if (op == MP_UNARY_OP_INVERT) { + emit_pre_pop_reg(emit, &vtype, REG_RET); #ifdef ASM_NOT_REG - int reg = REG_RET; - emit_pre_pop_reg_flexible(emit, &vtype, ®, reg, reg); - ASM_NOT_REG(emit->as, reg); + ASM_NOT_REG(emit->as, REG_RET); #else - int reg = REG_RET; - emit_pre_pop_reg_flexible(emit, &vtype, ®, REG_ARG_1, reg); - ASM_MOV_REG_IMM(emit->as, REG_ARG_1, -1); - ASM_XOR_REG_REG(emit->as, reg, REG_ARG_1); + #if REG_RET != REG_ARG_1 + int reg = REG_ARG_1; + #else + int reg = REG_ARG_2; + #endif + ASM_MOV_REG_IMM(emit->as, reg, -1); + ASM_XOR_REG_REG(emit->as, REG_RET, reg); #endif - emit_post_push_reg(emit, vtype, reg); + emit_post_push_reg(emit, vtype, REG_RET); } else { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT("'not' not implemented"), mp_binary_op_method_name[op]); @@ -3048,8 +2979,9 @@ static void emit_native_return_value(emit_t *emit) { static void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { DEBUG_printf("raise_varargs(%d)\n", n_args); - (void)n_args; - assert(n_args == 1); + if (n_args != 1) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("native raise")); + } vtype_kind_t vtype_exc; emit_pre_pop_reg(emit, &vtype_exc, REG_ARG_1); // arg1 = object to raise if (vtype_exc != VTYPE_PYOBJ) { @@ -3122,8 +3054,7 @@ static void emit_native_yield(emit_t *emit, int kind) { if (kind == MP_EMIT_YIELD_VALUE) { // Check LOCAL_IDX_THROW_VAL for any injected value ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_THROW_VAL(emit)); - ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); emit_call(emit, MP_F_NATIVE_RAISE); } else { // Label loop entry diff --git a/py/emitndebug.c b/py/emitndebug.c index bd896a75c8d..27c3bbdcef7 100644 --- a/py/emitndebug.c +++ b/py/emitndebug.c @@ -108,8 +108,8 @@ static void asm_debug_end_pass(asm_debug_t *as) { (void)as; } -static void asm_debug_entry(asm_debug_t *as, int num_locals) { - asm_debug_printf(as, "ENTRY(num_locals=%d)\n", num_locals); +static void asm_debug_entry(asm_debug_t *as, int num_locals, char *name) { + asm_debug_printf(as, "ENTRY(%s, num_locals=%d)\n", name != NULL ? name : "?", num_locals); } static void asm_debug_exit(asm_debug_t *as) { @@ -134,7 +134,7 @@ static void asm_debug_reg_imm(asm_debug_t *as, const char *op, int reg, int imm) #if !MICROPY_PERSISTENT_CODE_SAVE static void asm_debug_reg_qstr(asm_debug_t *as, const char *op, int reg, int qst) { - asm_debug_printf(as, "%s(%s, %s)\n", op, reg_name_table[reg], qstr_str(qst)); + asm_debug_printf(as, "%s(%s, %q)\n", op, reg_name_table[reg], (qstr)qst); } #endif @@ -195,8 +195,8 @@ static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int r #define ASM_T asm_debug_t #define ASM_END_PASS asm_debug_end_pass -#define ASM_ENTRY(as, num_locals) \ - asm_debug_entry(as, num_locals) +#define ASM_ENTRY(as, num_locals, name) \ + asm_debug_entry(as, num_locals, name) #define ASM_EXIT(as) \ asm_debug_exit(as) @@ -251,8 +251,6 @@ static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int r #define ASM_MUL_REG_REG(as, reg_dest, reg_src) \ asm_debug_reg_reg(as, "mul", reg_dest, reg_src) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) \ - asm_debug_reg_reg(as, "load", reg_dest, reg_base) #define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) \ asm_debug_reg_reg_offset(as, "load", reg_dest, reg_base, word_offset) #define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) \ @@ -264,8 +262,6 @@ static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int r #define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) \ asm_debug_reg_reg(as, "load32", reg_dest, reg_base) -#define ASM_STORE_REG_REG(as, reg_src, reg_base) \ - asm_debug_reg_reg(as, "store", reg_src, reg_base) #define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) \ asm_debug_reg_reg_offset(as, "store", reg_src, reg_base, word_offset) #define ASM_STORE8_REG_REG(as, reg_src, reg_base) \ @@ -275,6 +271,9 @@ static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int r #define ASM_STORE32_REG_REG(as, reg_src, reg_base) \ asm_debug_reg_reg(as, "store32", reg_src, reg_base) +#define ASM_CLR_REG(as, reg_dest) \ + asm_debug_reg(as, "clr", reg_dest) + // Word indices of REG_LOCAL_x in nlr_buf_t #define NLR_BUF_IDX_LOCAL_1 (5) // rbx diff --git a/py/formatfloat.c b/py/formatfloat.c index b4348122ff4..1ea34f84bf7 100644 --- a/py/formatfloat.c +++ b/py/formatfloat.c @@ -33,394 +33,537 @@ #include #include #include "py/formatfloat.h" +#include "py/parsenum.h" /*********************************************************************** Routine for converting a arbitrary floating point number into a string. - The code in this function was inspired from Fred Bayer's pdouble.c. - Since pdouble.c was released as Public Domain, I'm releasing this - code as public domain as well. + The code in this function was inspired from Dave Hylands's previous + version, which was itself inspired from Fred Bayer's pdouble.c. The original code can be found in https://github.com/dhylands/format-float - Dave Hylands - ***********************************************************************/ -#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT -// 1 sign bit, 8 exponent bits, and 23 mantissa bits. -// exponent values 0 and 255 are reserved, exponent can be 1 to 254. -// exponent is stored with a bias of 127. -// The min and max floats are on the order of 1x10^37 and 1x10^-37 - -#define FPTYPE float -#define FPCONST(x) x##F -#define FPROUND_TO_ONE 0.9999995F -#define FPDECEXP 32 -#define FPMIN_BUF_SIZE 6 // +9e+99 +// Float formatting debug code is intended for use in ports/unix only, +// as it uses the libc float printing function as a reference. +#define DEBUG_FLOAT_FORMATTING 0 + +#if DEBUG_FLOAT_FORMATTING +#define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__) +#else +#define DEBUG_PRINTF(...) +#endif + +#if MICROPY_FLOAT_FORMAT_IMPL == MICROPY_FLOAT_FORMAT_IMPL_EXACT || MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define MP_FFUINT_FMT "%lu" +#else +#define MP_FFUINT_FMT "%u" +#endif + +static inline int fp_expval(mp_float_t x) { + mp_float_union_t fb = { x }; + return (int)fb.p.exp - MP_FLOAT_EXP_OFFSET; +} -#define FLT_SIGN_MASK 0x80000000 +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE -static inline int fp_signbit(float x) { - mp_float_union_t fb = {x}; - return fb.i & FLT_SIGN_MASK; +static inline int fp_isless1(mp_float_t x) { + return x < 1.0; } -#define fp_isnan(x) isnan(x) -#define fp_isinf(x) isinf(x) -static inline int fp_iszero(float x) { - mp_float_union_t fb = {x}; - return fb.i == 0; + +static inline int fp_iszero(mp_float_t x) { + return x == 0.0; } -static inline int fp_isless1(float x) { - mp_float_union_t fb = {x}; + +#if MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_APPROX +static inline int fp_equal(mp_float_t x, mp_float_t y) { + return x == y; +} +#else +static inline mp_float_t fp_diff(mp_float_t x, mp_float_t y) { + return x - y; +} +#endif + +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + +// The functions below are roughly equivalent to the ones above, +// but they are optimized to reduce code footprint by skipping +// handling for special values such as nan, inf, +/-0.0 +// for ports where FP support is done in software. +// +// They also take into account lost bits of REPR_C as needed. + +static inline int fp_isless1(mp_float_t x) { + mp_float_union_t fb = { x }; return fb.i < 0x3f800000; } -#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +static inline int fp_iszero(mp_float_t x) { + mp_float_union_t x_check = { x }; + return !x_check.i; // this is valid for REPR_C as well +} -// CIRCUITPY-CHANGE: prevent warnings -#pragma GCC diagnostic ignored "-Wfloat-equal" -#define FPTYPE double -#define FPCONST(x) x -#define FPROUND_TO_ONE 0.999999999995 -#define FPDECEXP 256 -#define FPMIN_BUF_SIZE 7 // +9e+199 -#define fp_signbit(x) signbit(x) -#define fp_isnan(x) isnan(x) -#define fp_isinf(x) isinf(x) -#define fp_iszero(x) (x == 0) -#define fp_isless1(x) (x < 1.0) +#if MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_APPROX +static inline int fp_equal(mp_float_t x, mp_float_t y) { + mp_float_union_t x_check = { x }; + mp_float_union_t y_check = { y }; + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C + return (x_check.i & ~3) == (y_check.i & ~3); + #else + return x_check.i == y_check.i; + #endif +} +#else +static inline mp_float_t fp_diff(mp_float_t x, mp_float_t y) { + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C + mp_float_union_t x_check = { x }; + mp_float_union_t y_check = { y }; + x_check.i &= ~3; + y_check.i &= ~3; + return x_check.f - y_check.f; + #else + return x - y; + #endif +} +#endif -#endif // MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT/DOUBLE +#endif -static inline int fp_expval(FPTYPE x) { - mp_float_union_t fb = {x}; - return (int)((fb.i >> MP_FLOAT_FRAC_BITS) & (~(0xFFFFFFFF << MP_FLOAT_EXP_BITS))) - MP_FLOAT_EXP_OFFSET; +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define FPMIN_BUF_SIZE 6 // +9e+99 +#define MAX_MANTISSA_DIGITS (9) +#define SAFE_MANTISSA_DIGITS (6) +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define FPMIN_BUF_SIZE 7 // +9e+199 +#define MAX_MANTISSA_DIGITS (19) +#define SAFE_MANTISSA_DIGITS (16) +#endif + +// Internal formatting flags +#define FMT_MODE_E 0x01 // render using scientific notation (%e) +#define FMT_MODE_G 0x02 // render using general format (%g) +#define FMT_MODE_F 0x04 // render using using expanded fixed-point format (%f) +#define FMT_E_CASE 0x20 // don't change this value (used for case conversion!) + +static char *mp_prepend_zeros(char *s, int cnt) { + *s++ = '0'; + *s++ = '.'; + while (cnt > 0) { + *s++ = '0'; + cnt--; + } + return s; } -int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) { +// Helper to convert a decimal mantissa (provided as an mp_large_float_uint_t) to string +static int mp_format_mantissa(mp_large_float_uint_t mantissa, mp_large_float_uint_t mantissa_cap, char *buf, char *s, + int num_digits, int max_exp_zeros, int trailing_zeros, int dec, int e, int fmt_flags) { - char *s = buf; + DEBUG_PRINTF("mantissa=" MP_FFUINT_FMT " exp=%d (cap=" MP_FFUINT_FMT "):\n", mantissa, e, mantissa_cap); - if (buf_size <= FPMIN_BUF_SIZE) { - // FPMIN_BUF_SIZE is the minimum size needed to store any FP number. - // If the buffer does not have enough room for this (plus null terminator) - // then don't try to format the float. + if (mantissa) { + // If rounding/searching created an extra digit or removed too many, fix mantissa first + if (mantissa >= mantissa_cap) { + if (fmt_flags & FMT_MODE_F) { + assert(e >= 0); + num_digits++; + dec++; + } else { + mantissa /= 10; + e++; + } + } + } - if (buf_size >= 2) { - *s++ = '?'; + // When 'g' format is used, replace small exponents by explicit zeros + if ((fmt_flags & FMT_MODE_G) && e != 0) { + if (e >= 0) { + // If 0 < e < max_exp_zeros, expand positive exponent into trailing zeros + if (e < max_exp_zeros) { + dec += e; + if (dec >= num_digits) { + trailing_zeros = dec - (num_digits - 1); + } + e = 0; + } + } else { + // If -4 <= e < 0, expand negative exponent without losing significant digits + if (e >= -4) { + int cnt = 0; + while (e < 0 && !(mantissa % 10)) { + mantissa /= 10; + cnt++; + e++; + } + num_digits -= cnt; + s = mp_prepend_zeros(s, cnt - e - 1); + dec = 255; + e = 0; + } } - if (buf_size >= 1) { - *s = '\0'; + } + + // Convert the integer mantissa to string + for (int digit = num_digits - 1; digit >= 0; digit--) { + int digit_ofs = (digit > dec ? digit + 1 : digit); + s[digit_ofs] = '0' + (int)(mantissa % 10); + mantissa /= 10; + } + int dot = (dec >= 255); + if (dec + 1 < num_digits) { + dot = 1; + s++; + s[dec] = '.'; + } + s += num_digits; + #if DEBUG_FLOAT_FORMATTING + *s = 0; + DEBUG_PRINTF(" = %s exp=%d num_digits=%d zeros=%d dec=%d\n", buf, e, num_digits, trailing_zeros, dec); + #endif + + // Append or remove trailing zeros, as required by format + if (trailing_zeros) { + dec -= num_digits - 1; + while (trailing_zeros--) { + if (!dec--) { + *s++ = '.'; + dot = 1; + } + *s++ = '0'; } - return buf_size >= 2; } - if (fp_signbit(f) && !fp_isnan(f)) { - *s++ = '-'; - f = -f; - } else { - if (sign) { - *s++ = sign; + if (fmt_flags & FMT_MODE_G) { + // 'g' format requires to remove trailing zeros after decimal point + if (dot) { + while (s[-1] == '0') { + s--; + } + if (s[-1] == '.') { + s--; + } + } + } + + // Append the exponent if needed + if (((e != 0) || (fmt_flags & FMT_MODE_E)) && !(fmt_flags & FMT_MODE_F)) { + *s++ = 'E' | (fmt_flags & FMT_E_CASE); + if (e >= 0) { + *s++ = '+'; + } else { + *s++ = '-'; + e = -e; } + if (e >= 100) { + *s++ = '0' + (e / 100); + } + *s++ = '0' + ((e / 10) % 10); + *s++ = '0' + (e % 10); } + *s = '\0'; + DEBUG_PRINTF(" ===> %s\n", buf); - // buf_remaining contains bytes available for digits and exponent. - // It is buf_size minus room for the sign and null byte. - int buf_remaining = buf_size - 1 - (s - buf); + return s - buf; +} +// minimal value expected for buf_size, to avoid checking everywhere for overflow +#define MIN_BUF_SIZE (MAX_MANTISSA_DIGITS + 10) + +int mp_format_float(mp_float_t f_entry, char *buf_entry, size_t buf_size, char fmt, int prec, char sign) { + assert(buf_size >= MIN_BUF_SIZE); + + // Handle sign + mp_float_t f = f_entry; + char *buf = buf_entry; + if (signbit(f_entry) && !isnan(f_entry)) { + f = -f; + sign = '-'; + } + if (sign) { + *buf++ = sign; + buf_size--; + } + + // Handle inf/nan + char uc = fmt & 0x20; { - char uc = fmt & 0x20; - if (fp_isinf(f)) { + char *s = buf; + if (isinf(f)) { *s++ = 'I' ^ uc; *s++ = 'N' ^ uc; *s++ = 'F' ^ uc; goto ret; - } else if (fp_isnan(f)) { + } else if (isnan(f)) { *s++ = 'N' ^ uc; *s++ = 'A' ^ uc; *s++ = 'N' ^ uc; ret: *s = '\0'; - return s - buf; + return s - buf_entry; } } + // Decode format character + int fmt_flags = (unsigned char)uc; // setup FMT_E_CASE, clear all other bits + char lofmt = (char)(fmt | 0x20); // fmt in lowercase + if (lofmt == 'f') { + fmt_flags |= FMT_MODE_F; + } else if (lofmt == 'g') { + fmt_flags |= FMT_MODE_G; + } else { + fmt_flags |= FMT_MODE_E; + } + + // When precision is unspecified, default to 6 if (prec < 0) { prec = 6; } - char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt - fmt |= 0x20; // Force fmt to be lowercase - char org_fmt = fmt; - if (fmt == 'g' && prec == 0) { - prec = 1; + // Use high precision for `repr`, but switch to exponent mode + // after 16 digits in any case to match CPython behaviour + int max_exp_zeros = (prec < (int)buf_size - 3 ? prec : (int)buf_size - 3); + if (prec == MP_FLOAT_REPR_PREC) { + prec = MAX_MANTISSA_DIGITS; + max_exp_zeros = 16; } - int e; - int dec = 0; - char e_sign = '\0'; - int num_digits = 0; - int signed_e = 0; - // Approximate power of 10 exponent from binary exponent. - // abs(e_guess) is lower bound on abs(power of 10 exponent). - int e_guess = (int)(fp_expval(f) * FPCONST(0.3010299956639812)); // 1/log2(10). - if (fp_iszero(f)) { - e = 0; - if (fmt == 'f') { - // Truncate precision to prevent buffer overflow - if (prec + 2 > buf_remaining) { - prec = buf_remaining - 2; - } - num_digits = prec + 1; - } else { - // Truncate precision to prevent buffer overflow - if (prec + 6 > buf_remaining) { - prec = buf_remaining - 6; - } - if (fmt == 'e') { - e_sign = '+'; - } + // Precompute the exact decimal exponent of f, such that + // abs(e) is lower bound on abs(power of 10 exponent). + int e = 0; + if (!fp_iszero(f)) { + // Approximate power of 10 exponent from binary exponent. + e = (int)(fp_expval(f) * MICROPY_FLOAT_CONST(0.3010299956639812)); // 1/log2(10). + int positive_exp = !fp_isless1(f); + mp_float_t u_base = (mp_float_t)mp_decimal_exp((mp_large_float_t)1.0, e + positive_exp); + while ((f >= u_base) == positive_exp) { + e += (positive_exp ? 1 : -1); + u_base = (mp_float_t)mp_decimal_exp((mp_large_float_t)1.0, e + positive_exp); } - } else if (fp_isless1(f)) { - FPTYPE f_entry = f; // Save f in case we go to 'f' format. - // Build negative exponent - e = -e_guess; - FPTYPE u_base = MICROPY_FLOAT_C_FUN(pow)(10, -e); - while (u_base > f) { - ++e; - u_base = MICROPY_FLOAT_C_FUN(pow)(10, -e); - } - // Normalize out the inferred unit. Use divide because - // pow(10, e) * pow(10, -e) is slightly < 1 for some e in float32 - // (e.g. print("%.12f" % ((1e13) * (1e-13)))) - f /= u_base; - - // If the user specified 'g' format, and e is <= 4, then we'll switch - // to the fixed format ('f') - - if (fmt == 'f' || (fmt == 'g' && e <= 4)) { - fmt = 'f'; - dec = 0; + } - if (org_fmt == 'g') { - prec += (e - 1); - } + // For 'e' format, prec is # digits after the decimal + // For 'f' format, prec is # digits after the decimal + // For 'g' format, prec is the max number of significant digits + // + // For 'e' & 'g' format, there will be a single digit before the decimal + // For 'f' format, zeros must be expanded instead of using an exponent. + // Make sure there is enough room in the buffer for them, or switch to format 'g'. + if ((fmt_flags & FMT_MODE_F) && e > 0) { + int req_size = e + prec + 2; + if (req_size > (int)buf_size) { + fmt_flags ^= FMT_MODE_F; + fmt_flags |= FMT_MODE_G; + prec++; + } + } - // truncate precision to prevent buffer overflow - if (prec + 2 > buf_remaining) { - prec = buf_remaining - 2; + // To work independently of the format, we precompute: + // - the max number of significant digits to produce + // - the number of leading zeros to prepend (mode f only) + // - the number of trailing zeros to append + int max_digits = prec; + int lead_zeros = 0; + int trail_zeros = 0; + if (fmt_flags & FMT_MODE_F) { + if (max_digits > (int)buf_size - 3) { + // cannot satisfy requested number of decimals given buf_size, sorry + max_digits = (int)buf_size - 3; + } + if (e < 0) { + if (max_digits > 2 && e < -2) { + // Insert explicit leading zeros + lead_zeros = (-e < max_digits ? -e : max_digits) - 2; + max_digits -= lead_zeros; + } else { + max_digits++; } - - num_digits = prec; - signed_e = 0; - f = f_entry; - ++num_digits; } else { - // For e & g formats, we'll be printing the exponent, so set the - // sign. - e_sign = '-'; - dec = 0; - - if (prec > (buf_remaining - FPMIN_BUF_SIZE)) { - prec = buf_remaining - FPMIN_BUF_SIZE; - if (fmt == 'g') { - prec++; - } - } - signed_e = -e; + max_digits += e + 1; } } else { - // Build positive exponent. - // We don't modify f at this point to avoid inaccuracies from - // scaling it. Instead, we find the product of powers of 10 - // that is not greater than it, and use that to start the - // mantissa. - e = e_guess; - FPTYPE next_u = MICROPY_FLOAT_C_FUN(pow)(10, e + 1); - while (f >= next_u) { - ++e; - next_u = MICROPY_FLOAT_C_FUN(pow)(10, e + 1); + if (!(fmt_flags & FMT_MODE_G) || max_digits == 0) { + max_digits++; } + } + if (max_digits > MAX_MANTISSA_DIGITS) { + // use trailing zeros to avoid overflowing the mantissa + trail_zeros = max_digits - MAX_MANTISSA_DIGITS; + max_digits = MAX_MANTISSA_DIGITS; + } + int overhead = (fmt_flags & FMT_MODE_F ? 3 : FPMIN_BUF_SIZE + 1); + if (trail_zeros > (int)buf_size - max_digits - overhead) { + // cannot satisfy requested number of decimals given buf_size, sorry + trail_zeros = (int)buf_size - max_digits - overhead; + } - // If the user specified fixed format (fmt == 'f') and e makes the - // number too big to fit into the available buffer, then we'll - // switch to the 'e' format. - - if (fmt == 'f') { - if (e >= buf_remaining) { - fmt = 'e'; - } else if ((e + prec + 2) > buf_remaining) { - prec = buf_remaining - e - 2; - if (prec < 0) { - // This means no decimal point, so we can add one back - // for the decimal. - prec++; - } - } - } - if (fmt == 'e' && prec > (buf_remaining - FPMIN_BUF_SIZE)) { - prec = buf_remaining - FPMIN_BUF_SIZE; - } - if (fmt == 'g') { - // Truncate precision to prevent buffer overflow - if (prec + (FPMIN_BUF_SIZE - 1) > buf_remaining) { - prec = buf_remaining - (FPMIN_BUF_SIZE - 1); - } - } - // If the user specified 'g' format, and e is < prec, then we'll switch - // to the fixed format. + // When the caller asks for more precision than available for sure, + // Look for a shorter (rounded) representation first, and only dig + // into more digits if there is no short representation. + int num_digits = (SAFE_MANTISSA_DIGITS < max_digits ? SAFE_MANTISSA_DIGITS : max_digits); +try_again: + ; - if (fmt == 'g' && e < prec) { - fmt = 'f'; - prec -= (e + 1); - } - if (fmt == 'f') { - dec = e; - num_digits = prec + e + 1; + char *s = buf; + int extra_zeros = trail_zeros + (max_digits - num_digits); + int decexp; + int dec = 0; + + if (fp_iszero(f)) { + // no need for scaling 0.0 + decexp = 0; + } else if (fmt_flags & FMT_MODE_F) { + decexp = num_digits - 1; + if (e < 0) { + // Negative exponent: we keep a single leading zero in the mantissa, + // as using more would waste precious digits needed for accuracy. + if (lead_zeros > 0) { + // We are using leading zeros + s = mp_prepend_zeros(s, lead_zeros); + decexp += lead_zeros + 1; + dec = 255; // no decimal dot + } else { + // Small negative exponent, work directly on the mantissa + dec = 0; + } } else { - e_sign = '+'; + // Positive exponent: we will add trailing zeros separately + decexp -= e; + dec = e; } - signed_e = e; + } else { + decexp = num_digits - e - 1; } - if (prec < 0) { - // This can happen when the prec is trimmed to prevent buffer overflow - prec = 0; + DEBUG_PRINTF("input=%.19g e=%d fmt=%c max_d=%d num_d=%d decexp=%d dec=%d l0=%d r0=%d\n", + (double)f, e, lofmt, max_digits, num_digits, decexp, dec, lead_zeros, extra_zeros); + + // At this point, + // - buf points to beginning of output buffer for the unsigned representation + // - num_digits == the number of mantissa digits to add + // - (dec + 1) == the number of digits to print before adding a decimal point + // - decexp == the power of 10 exponent to apply to f to get the decimal mantissa + // - e == the power of 10 exponent to append ('e' or 'g' format) + mp_large_float_uint_t mantissa_cap = 10; + for (int n = 1; n < num_digits; n++) { + mantissa_cap *= 10; } - // At this point e contains the absolute value of the power of 10 exponent. - // (dec + 1) == the number of dgits before the decimal. - - // For e, prec is # digits after the decimal - // For f, prec is # digits after the decimal - // For g, prec is the max number of significant digits - // - // For e & g there will be a single digit before the decimal - // for f there will be e digits before the decimal - - if (fmt == 'e') { - num_digits = prec + 1; - } else if (fmt == 'g') { - if (prec == 0) { - prec = 1; + // Build the decimal mantissa into a large uint + mp_large_float_uint_t mantissa = 1; + if (sizeof(mp_large_float_t) == sizeof(mp_float_t) && num_digits > SAFE_MANTISSA_DIGITS && decexp > 1) { + // if we don't have large floats, use integer multiply to produce the last digits + if (num_digits > SAFE_MANTISSA_DIGITS + 1 && decexp > 2) { + mantissa = 100; + decexp -= 2; + } else { + mantissa = 10; + decexp -= 1; } - num_digits = prec; } - - int d = 0; - for (int digit_index = signed_e; num_digits >= 0; --digit_index) { - FPTYPE u_base = FPCONST(1.0); - if (digit_index > 0) { - // Generate 10^digit_index for positive digit_index. - u_base = MICROPY_FLOAT_C_FUN(pow)(10, digit_index); - } - for (d = 0; d < 9; ++d) { - if (f < u_base) { - break; - } - f -= u_base; - } - // We calculate one more digit than we display, to use in rounding - // below. So only emit the digit if it's one that we display. - if (num_digits > 0) { - // Emit this number (the leading digit). - *s++ = '0' + d; - if (dec == 0 && prec > 0) { - *s++ = '.'; - } - } - --dec; - --num_digits; - if (digit_index <= 0) { - // Once we get below 1.0, we scale up f instead of calculating - // negative powers of 10 in u_base. This provides better - // renditions of exact decimals like 1/16 etc. - f *= FPCONST(10.0); + mp_large_float_t mantissa_f = mp_decimal_exp((mp_large_float_t)f, decexp); + mantissa *= (mp_large_float_uint_t)(mantissa_f + (mp_large_float_t)0.5); + DEBUG_PRINTF("input=%.19g fmt=%c num_digits=%d dec=%d mantissa=" MP_FFUINT_FMT " r0=%d\n", (double)f, lofmt, num_digits, dec, mantissa, extra_zeros); + + // Finally convert the decimal mantissa to a floating-point string, according to formatting rules + int reprlen = mp_format_mantissa(mantissa, mantissa_cap, buf, s, num_digits, max_exp_zeros, extra_zeros, dec, e, fmt_flags); + assert(reprlen + 1 <= (int)buf_size); + + #if MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_APPROX + + if (num_digits < max_digits) { + // The initial precision might not be sufficient for an exact representation + // for all numbers. If the result is not exact, restart using next precision. + // parse the resulting number and compare against the original + mp_float_t check; + DEBUG_PRINTF("input=%.19g, compare to float('%s')\n", (double)f, buf); + mp_parse_float_internal(buf, reprlen, &check); + if (!fp_equal(check, f)) { + num_digits++; + DEBUG_PRINTF("Not perfect, retry using more digits (%d)\n", num_digits); + goto try_again; } } - // Rounding. If the next digit to print is >= 5, round up. - if (d >= 5) { - char *rs = s; - rs--; - while (1) { - if (*rs == '.') { - rs--; - continue; - } - if (*rs < '0' || *rs > '9') { - // + or - - rs++; // So we sit on the digit to the right of the sign - break; + + #else + + // The initial decimal mantissa might not have been be completely accurate due + // to the previous loating point operations. The best way to verify this is to + // parse the resulting number and compare against the original + mp_float_t check; + DEBUG_PRINTF("input=%.19g, compare to float('%s')\n", (double)f, buf); + mp_parse_float_internal(buf, reprlen, &check); + mp_float_t diff = fp_diff(check, f); + mp_float_t best_diff = diff; + mp_large_float_uint_t best_mantissa = mantissa; + + if (fp_iszero(diff)) { + // we have a perfect match + DEBUG_PRINTF(MP_FFUINT_FMT ": perfect match (direct)\n", mantissa); + } else { + // In order to get the best possible representation, we will perform a + // dichotomic search for a reversible representation. + // This will also provide optimal rounding on the fly. + unsigned err_range = 1; + if (num_digits > SAFE_MANTISSA_DIGITS) { + err_range <<= 3 * (num_digits - SAFE_MANTISSA_DIGITS); + } + int maxruns = 3 + 3 * (MAX_MANTISSA_DIGITS - SAFE_MANTISSA_DIGITS); + while (maxruns-- > 0) { + // update mantissa according to dichotomic search + if (signbit(diff)) { + mantissa += err_range; + } else { + // mantissa is expected to always have more significant digits than err_range + assert(mantissa >= err_range); + mantissa -= err_range; } - if (*rs < '9') { - (*rs)++; + // retry conversion + reprlen = mp_format_mantissa(mantissa, mantissa_cap, buf, s, num_digits, max_exp_zeros, extra_zeros, dec, e, fmt_flags); + assert(reprlen + 1 <= (int)buf_size); + DEBUG_PRINTF("input=%.19g, compare to float('%s')\n", (double)f, buf); + mp_parse_float_internal(buf, reprlen, &check); + DEBUG_PRINTF("check=%.19g num_digits=%d e=%d mantissa=" MP_FFUINT_FMT "\n", (double)check, num_digits, e, mantissa); + diff = fp_diff(check, f); + if (fp_iszero(diff)) { + // we have a perfect match + DEBUG_PRINTF(MP_FFUINT_FMT ": perfect match\n", mantissa); break; } - *rs = '0'; - if (rs == buf) { - break; + // keep track of our best estimate + mp_float_t delta = MICROPY_FLOAT_C_FUN(fabs)(diff) - MICROPY_FLOAT_C_FUN(fabs)(best_diff); + if (signbit(delta) || (fp_iszero(delta) && !(mantissa % 10u))) { + best_diff = diff; + best_mantissa = mantissa; } - rs--; - } - if (*rs == '0') { - // We need to insert a 1 - if (rs[1] == '.' && fmt != 'f') { - // We're going to round 9.99 to 10.00 - // Move the decimal point - rs[0] = '.'; - rs[1] = '0'; - if (e_sign == '-') { - e--; - if (e == 0) { - e_sign = '+'; - } - } else { - e++; - } + // string repr is not perfect: continue a dichotomic improvement + DEBUG_PRINTF(MP_FFUINT_FMT ": %.19g, err_range=%d\n", mantissa, (double)check, err_range); + if (err_range > 1) { + err_range >>= 1; } else { - // Need at extra digit at the end to make room for the leading '1' - // but if we're at the buffer size limit, just drop the final digit. - if ((size_t)(s + 1 - buf) < buf_size) { - s++; + // We have tried all possible mantissa, without finding a reversible repr. + // Check if we have an alternate precision to try. + if (num_digits < max_digits) { + num_digits++; + DEBUG_PRINTF("Failed to find a perfect match, try with more digits (%d)\n", num_digits); + goto try_again; } + // Otherwise, keep the closest one, which is either the first one or the last one. + if (mantissa == best_mantissa) { + // Last guess is the best one + DEBUG_PRINTF(MP_FFUINT_FMT ": last guess was the best one\n", mantissa); + } else { + // We had a better guess earlier + DEBUG_PRINTF(MP_FFUINT_FMT ": use best guess\n", mantissa); + reprlen = mp_format_mantissa(best_mantissa, mantissa_cap, buf, s, num_digits, max_exp_zeros, extra_zeros, dec, e, fmt_flags); + } + break; } - char *ss = s; - while (ss > rs) { - *ss = ss[-1]; - ss--; - } - *rs = '1'; } } + #endif - // verify that we did not overrun the input buffer so far - assert((size_t)(s + 1 - buf) <= buf_size); - - if (org_fmt == 'g' && prec > 0) { - // Remove trailing zeros and a trailing decimal point - while (s[-1] == '0') { - s--; - } - if (s[-1] == '.') { - s--; - } - } - // Append the exponent - if (e_sign) { - *s++ = e_char; - *s++ = e_sign; - if (FPMIN_BUF_SIZE == 7 && e >= 100) { - *s++ = '0' + (e / 100); - } - *s++ = '0' + ((e / 10) % 10); - *s++ = '0' + (e % 10); - } - *s = '\0'; - - // verify that we did not overrun the input buffer - assert((size_t)(s + 1 - buf) <= buf_size); - - return s - buf; + return buf + reprlen - buf_entry; } #endif // MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE diff --git a/py/formatfloat.h b/py/formatfloat.h index 9a1643b4ddf..7b1414672b7 100644 --- a/py/formatfloat.h +++ b/py/formatfloat.h @@ -29,6 +29,7 @@ #include "py/mpconfig.h" #if MICROPY_PY_BUILTINS_FLOAT +#define MP_FLOAT_REPR_PREC (99) // magic `prec` value for optimal `repr` behaviour int mp_format_float(mp_float_t f, char *buf, size_t bufSize, char fmt, int prec, char sign); #endif diff --git a/py/gc.c b/py/gc.c index c6da81d495c..57bad018e76 100644 --- a/py/gc.c +++ b/py/gc.c @@ -32,6 +32,12 @@ #include "py/gc.h" #include "py/runtime.h" +#if defined(__ZEPHYR__) +#include +#include +#include +#endif + #if MICROPY_DEBUG_VALGRIND #include #endif @@ -45,6 +51,12 @@ #include "shared-module/memorymonitor/__init__.h" #endif +#if defined(__ZEPHYR__) && defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM) +#include "perfetto_encoder.h" +#define CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID 0x3001ULL +#define CIRCUITPY_PERFETTO_VM_HEAP_MAX_FREE_UUID 0x3002ULL +#endif + #if MICROPY_ENABLE_GC #if MICROPY_DEBUG_VERBOSE // print debugging info @@ -135,6 +147,16 @@ #define CTB_SET(area, block) do { area->gc_collect_table_start[(block) / BLOCKS_PER_CTB] |= (1 << ((block) & 7)); } while (0) #define CTB_CLEAR(area, block) do { area->gc_collect_table_start[(block) / BLOCKS_PER_CTB] &= (~(1 << ((block) & 7))); } while (0) +#if MICROPY_PY_WEAKREF +// WTB = weakref table byte +// if set, then the corresponding block may have a weakref in MP_STATE_VM(mp_weakref_map). +#define BLOCKS_PER_WTB (8) + +#define WTB_GET(area, block) ((area->gc_weakref_table_start[(block) / BLOCKS_PER_WTB] >> ((block) & 7)) & 1) +#define WTB_SET(area, block) do { area->gc_weakref_table_start[(block) / BLOCKS_PER_WTB] |= (1 << ((block) & 7)); } while (0) +#define WTB_CLEAR(area, block) do { area->gc_weakref_table_start[(block) / BLOCKS_PER_WTB] &= (~(1 << ((block) & 7))); } while (0) +#endif + #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL #define GC_MUTEX_INIT() mp_thread_recursive_mutex_init(&MP_STATE_MEM(gc_mutex)) #define GC_ENTER() mp_thread_recursive_mutex_lock(&MP_STATE_MEM(gc_mutex), 1) @@ -158,6 +180,32 @@ void __attribute__ ((noinline)) gc_log_change(uint32_t start_block, uint32_t len #pragma GCC pop_options #endif +#if defined(__ZEPHYR__) && defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM) +static void gc_perfetto_emit_heap_stats(void) { + if (!perfetto_start()) { + return; + } + gc_info_t info; + gc_info(&info); + perfetto_emit_counter(CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID, (int64_t)info.used); + Z_SPIN_DELAY(1); +} + +static void gc_perfetto_emit_heap_stopped(void) { + if (!perfetto_start()) { + return; + } + perfetto_emit_counter(CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID, 0); + Z_SPIN_DELAY(1); +} +#else +static inline void gc_perfetto_emit_heap_stats(void) { +} + +static inline void gc_perfetto_emit_heap_stopped(void) { +} +#endif + // Static functions for individual steps of the GC mark/sweep sequence static void gc_collect_start_common(void); static void *gc_get_ptr(void **ptrs, int i); @@ -173,10 +221,11 @@ static void gc_sweep_free_blocks(void); // TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool static void gc_setup_area(mp_state_mem_area_t *area, void *start, void *end) { // CIRCUITPY-CHANGE: Updated calculation to include selective collect table - // calculate parameters for GC (T=total, A=alloc table, F=finaliser table, C=collect table, P=pool; all in bytes): - // T = A + F + C + P + // calculate parameters for GC (T=total, A=alloc table, F=finaliser table, C=collect table, W=weakref table, P=pool; all in bytes): + // T = A + F + C + W + P // F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB // C = A * BLOCKS_PER_ATB / BLOCKS_PER_CTB + // W = A * BLOCKS_PER_ATB / BLOCKS_PER_WTB // P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK size_t total_byte_len = (byte *)end - (byte *)start; @@ -192,6 +241,10 @@ static void gc_setup_area(mp_state_mem_area_t *area, void *start, void *end) { bits_per_block += MP_BITS_PER_BYTE / BLOCKS_PER_CTB; // Add bits for CTB #endif + #if MICROPY_PY_WEAKREF + bits_per_block += MP_BITS_PER_BYTE / BLOCKS_PER_WTB; // Add bits for WTB + #endif + bits_per_block += MP_BITS_PER_BYTE * BYTES_PER_BLOCK; // Add bits for the block itself // Calculate the allocation table size @@ -219,6 +272,12 @@ static void gc_setup_area(mp_state_mem_area_t *area, void *start, void *end) { next_table += gc_collect_table_byte_len; #endif + #if MICROPY_PY_WEAKREF + size_t gc_weakref_table_byte_len = (gc_pool_block_len + BLOCKS_PER_WTB - 1) / BLOCKS_PER_WTB; + area->gc_weakref_table_start = next_table; + next_table += gc_weakref_table_byte_len; + #endif + // Set pool pointers area->gc_pool_start = (byte *)end - gc_pool_block_len * BYTES_PER_BLOCK; area->gc_pool_end = end; @@ -235,6 +294,10 @@ static void gc_setup_area(mp_state_mem_area_t *area, void *start, void *end) { #if MICROPY_GC_SPLIT_HEAP area->next = NULL; + + // Update the global min/max region that covers all heaps + MP_STATE_MEM(area_pool_min) = MIN(MP_STATE_MEM(area_pool_min), area->gc_pool_start); + MP_STATE_MEM(area_pool_max) = MAX(MP_STATE_MEM(area_pool_max), area->gc_pool_end); #endif DEBUG_printf("GC layout:\n"); @@ -254,6 +317,12 @@ static void gc_setup_area(mp_state_mem_area_t *area, void *start, void *end) { gc_collect_table_byte_len, gc_collect_table_byte_len * BLOCKS_PER_CTB); #endif + #if MICROPY_PY_WEAKREF + DEBUG_printf(" weakref table at %p, length " UINT_FMT " bytes, " + UINT_FMT " blocks\n", area->gc_weakref_table_start, + gc_weakref_table_byte_len, + gc_weakref_table_byte_len * BLOCKS_PER_WTB); + #endif DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", area->gc_pool_start, gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len); @@ -264,6 +333,13 @@ void gc_init(void *start, void *end) { end = (void *)((uintptr_t)end & (~(BYTES_PER_BLOCK - 1))); DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte *)end - (byte *)start); + #if MICROPY_GC_SPLIT_HEAP + // Note: min/max are deliberately swapped here, gc_setup_area() will update them to + // the correct values for the min/max of the first actual pool region + MP_STATE_MEM(area_pool_min) = end; + MP_STATE_MEM(area_pool_max) = start; + #endif + gc_setup_area(&MP_STATE_MEM(area), start, end); // set last free ATB index to start of heap @@ -284,6 +360,7 @@ void gc_init(void *start, void *end) { #endif GC_MUTEX_INIT(); + gc_perfetto_emit_heap_stats(); } #if MICROPY_GC_SPLIT_HEAP @@ -317,12 +394,16 @@ static size_t compute_heap_size(size_t total_blocks) { size_t atb_bytes = (total_blocks + BLOCKS_PER_ATB - 1) / BLOCKS_PER_ATB; size_t ftb_bytes = 0; size_t ctb_bytes = 0; + size_t wtb_bytes = 0; #if MICROPY_ENABLE_FINALISER ftb_bytes = (total_blocks + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB; #endif #if MICROPY_ENABLE_SELECTIVE_COLLECT ctb_bytes = (total_blocks + BLOCKS_PER_CTB - 1) / BLOCKS_PER_CTB; #endif + #if MICROPY_PY_WEAKREF + wtb_bytes = (total_blocks + BLOCKS_PER_WTB - 1) / BLOCKS_PER_WTB; + #endif size_t pool_bytes = total_blocks * BYTES_PER_BLOCK; // Compute bytes needed to build a heap with total_blocks blocks. @@ -332,6 +413,7 @@ static size_t compute_heap_size(size_t total_blocks) { + ALLOC_TABLE_GAP_BYTE + ftb_bytes + ctb_bytes + + wtb_bytes + pool_bytes + BYTES_PER_BLOCK; // Extra block of bytes to account for end pointer alignment @@ -425,6 +507,7 @@ void gc_deinit(void) { // Run any finalisers before we stop using the heap. This will also free // any additional heap areas (but not the first.) gc_sweep_all(); + gc_perfetto_emit_heap_stopped(); memset(&MP_STATE_MEM(area), 0, sizeof(MP_STATE_MEM(area))); } @@ -457,12 +540,24 @@ bool gc_ptr_on_heap(const void *ptr) { } #if MICROPY_GC_SPLIT_HEAP -// Returns the area to which this pointer belongs, or NULL if it isn't -// allocated on the GC-managed heap. -static inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) { - if (((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) != 0) { // must be aligned on a block - return NULL; +static mp_state_mem_area_t *gc_get_ptr_area(const void *ptr); + +// Returns the area to which this arbitrary pointer belongs, or NULL if it isn't +// allocated on the GC-managed heap. Contains "fast path" inline checks for invalid +// data which isn't a pointer to the heap. Equivalent of VERIFY_PTR for the non-split-heap case. +static inline MP_ALWAYSINLINE mp_state_mem_area_t *gc_verify_ptr_get_area(const void *ptr) { + // These inline checks are similar to VERIFY_PTR macro, below + if ((byte *)ptr < MP_STATE_MEM(area_pool_min) || (byte *)ptr > MP_STATE_MEM(area_pool_max)) { + return NULL; // not in the overall pool region } + if (((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) != 0) { + return NULL; // not aligned on a block boundary + } + return gc_get_ptr_area(ptr); +} + +// Returns the area to which a pointer belongs. Assumes pointer is valid to a heap block. +static mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) { for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) { if (ptr >= (void *)area->gc_pool_start // must be above start of pool && ptr < (void *)area->gc_pool_end) { // must be below end of pool @@ -471,7 +566,7 @@ static inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) { } return NULL; } -#endif +#else // ptr should be of type void* #define VERIFY_PTR(ptr) ( \ @@ -480,11 +575,24 @@ static inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) { && ptr < (void *)MP_STATE_MEM(area).gc_pool_end /* must be below end of pool */ \ ) -#ifndef TRACE_MARK +#endif + +#ifdef TRACE_MARK +#error "TRACE_MARK is replaced by TRACE_MARK_R and TRACE_MARK_S" +#endif +// R for root pointer, S for subtree. +#ifndef TRACE_MARK_R +#if DEBUG_PRINT +#define TRACE_MARK_R(block, ptr) DEBUG_printf("gc_mark_r(%p)\n", ptr) +#else +#define TRACE_MARK_R(block, ptr) +#endif +#endif +#ifndef TRACE_MARK_S #if DEBUG_PRINT -#define TRACE_MARK(block, ptr) DEBUG_printf("gc_mark(%p)\n", ptr) +#define TRACE_MARK_S(block, ptr) DEBUG_printf("gc_mark_s(%p)\n", ptr) #else -#define TRACE_MARK(block, ptr) +#define TRACE_MARK_S(block, ptr) #endif #endif @@ -524,7 +632,7 @@ void gc_collect_root(void **ptrs, size_t len) { MICROPY_GC_HOOK_LOOP(i); void *ptr = gc_get_ptr(ptrs, i); #if MICROPY_GC_SPLIT_HEAP - mp_state_mem_area_t *area = gc_get_ptr_area(ptr); + mp_state_mem_area_t *area = gc_verify_ptr_get_area(ptr); if (!area) { continue; } @@ -536,6 +644,7 @@ void gc_collect_root(void **ptrs, size_t len) { size_t block = BLOCK_FROM_PTR(area, ptr); if (ATB_GET_KIND(area, block) == AT_HEAD) { // An unmarked head: mark it, and mark all its children + TRACE_MARK_R(block, ptr); ATB_HEAD_TO_MARK(area, block); #if MICROPY_GC_SPLIT_HEAP gc_mark_subtree(area, block); @@ -592,7 +701,7 @@ static void MP_NO_INSTRUMENT PLACE_IN_ITCM(gc_mark_subtree)(size_t block) // If this is a heap pointer that hasn't been marked, mark it and push // it's children to the stack. #if MICROPY_GC_SPLIT_HEAP - mp_state_mem_area_t *ptr_area = gc_get_ptr_area(ptr); + mp_state_mem_area_t *ptr_area = gc_verify_ptr_get_area(ptr); if (!ptr_area) { // Not a heap-allocated pointer (might even be random data). continue; @@ -609,7 +718,7 @@ static void MP_NO_INSTRUMENT PLACE_IN_ITCM(gc_mark_subtree)(size_t block) continue; } // An unmarked head. Mark it, and push it on gc stack. - TRACE_MARK(ptr_block, ptr); + TRACE_MARK_S(ptr_block, ptr); ATB_HEAD_TO_MARK(ptr_area, ptr_block); if (sp < MICROPY_ALLOC_GC_STACK_SIZE) { MP_STATE_MEM(gc_block_stack)[sp] = ptr_block; @@ -654,6 +763,10 @@ void gc_collect_end(void) { } MP_STATE_THREAD(gc_lock_depth) &= ~GC_COLLECT_FLAG; GC_EXIT(); + #if MICROPY_PY_WEAKREF + gc_weakref_sweep(); + #endif + gc_perfetto_emit_heap_stats(); } static void gc_deal_with_stack_overflow(void) { @@ -679,12 +792,16 @@ static void gc_deal_with_stack_overflow(void) { // Run finalisers for all to-be-freed blocks static void gc_sweep_run_finalisers(void) { - #if MICROPY_ENABLE_FINALISER + #if MICROPY_ENABLE_FINALISER || MICROPY_PY_WEAKREF + #if MICROPY_ENABLE_FINALISER && MICROPY_PY_WEAKREF + MP_STATIC_ASSERT(BLOCKS_PER_FTB == BLOCKS_PER_WTB); + #endif for (const mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) { assert(area->gc_last_used_block <= area->gc_alloc_table_byte_len * BLOCKS_PER_ATB); // Small speed optimisation: skip over empty FTB blocks size_t ftb_end = area->gc_last_used_block / BLOCKS_PER_FTB; // index is inclusive for (size_t ftb_idx = 0; ftb_idx <= ftb_end; ftb_idx++) { + #if MICROPY_ENABLE_FINALISER byte ftb = area->gc_finaliser_table_start[ftb_idx]; size_t block = ftb_idx * BLOCKS_PER_FTB; while (ftb) { @@ -714,9 +831,26 @@ static void gc_sweep_run_finalisers(void) { ftb >>= 1; block++; } + #endif + #if MICROPY_PY_WEAKREF + byte wtb = area->gc_weakref_table_start[ftb_idx]; + block = ftb_idx * BLOCKS_PER_WTB; + while (wtb) { + MICROPY_GC_HOOK_LOOP(block); + if (wtb & 1) { // WTB_GET(area, block) shortcut + if (ATB_GET_KIND(area, block) == AT_HEAD) { + mp_obj_base_t *obj = (mp_obj_base_t *)PTR_FROM_BLOCK(area, block); + gc_weakref_about_to_be_freed(obj); + WTB_CLEAR(area, block); + } + } + wtb >>= 1; + block++; + } + #endif } } - #endif // MICROPY_ENABLE_FINALISER + #endif // MICROPY_ENABLE_FINALISER || MICROPY_PY_WEAKREF } // Free unmarked heads and their tails @@ -874,6 +1008,44 @@ void gc_info(gc_info_t *info) { GC_EXIT(); } +// Fast version of gc_info that only computes total/used/free. +void gc_info_fast(gc_info_t *info) { + GC_ENTER(); + memset(info, 0, sizeof(*info)); + const uint8_t lut[16] = {2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}; + for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) { + size_t free_blocks = 0; + info->total += area->gc_pool_end - area->gc_pool_start; + for (size_t i = 0; i < area->gc_alloc_table_byte_len; i++) { + uint8_t atb = area->gc_alloc_table_start[i]; + free_blocks += lut[atb & 0xF] + lut[atb >> 4]; + } + info->free += free_blocks; + } + info->free *= BYTES_PER_BLOCK; + info->used = info->total - info->free; + GC_EXIT(); +} + +#if MICROPY_PY_WEAKREF +// Mark the GC heap pointer as having a weakref. +void gc_weakref_mark(void *ptr) { + mp_state_mem_area_t *area; + #if MICROPY_GC_SPLIT_HEAP + area = gc_get_ptr_area(ptr); + assert(area); + #else + assert(VERIFY_PTR(ptr)); + area = &MP_STATE_MEM(area); + #endif + + size_t block = BLOCK_FROM_PTR(area, ptr); + assert(ATB_GET_KIND(area, block) == AT_HEAD); + + WTB_SET(area, block); +} +#endif + // CIRCUITPY-CHANGE: New function. // C code may be used when the VM heap isn't active. This function // allows that code to test if it is. It can use the outer pool if needed. @@ -1069,6 +1241,8 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) { memorymonitor_track_allocation(end_block - start_block + 1); #endif + gc_perfetto_emit_heap_stats(); + return ret_ptr; } @@ -1118,6 +1292,11 @@ void gc_free(void *ptr) { FTB_CLEAR(area, block); #endif + #if MICROPY_PY_WEAKREF + // Objects that have a weak reference should not be explicitly freed. + assert(!WTB_GET(area, block)); + #endif + #if MICROPY_GC_SPLIT_HEAP if (MP_STATE_MEM(gc_last_free_area) != area) { // We freed something but it isn't the current area. Reset the @@ -1150,6 +1329,7 @@ void gc_free(void *ptr) { } while (ATB_GET_KIND(area, block) == AT_TAIL); GC_EXIT(); + gc_perfetto_emit_heap_stats(); #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(&mp_plat_print); @@ -1290,6 +1470,8 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { memorymonitor_track_allocation(new_blocks); #endif + gc_perfetto_emit_heap_stats(); + return ptr_in; } @@ -1327,6 +1509,8 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { memorymonitor_track_allocation(new_blocks); #endif + gc_perfetto_emit_heap_stats(); + return ptr_in; } @@ -1399,7 +1583,7 @@ void gc_dump_alloc_table(const mp_print_t *print) { } if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) { // there are at least 2 lines containing only free blocks, so abbreviate their printing - mp_printf(print, "\n (%u lines all free)", (uint)(bl2 - bl) / DUMP_BYTES_PER_LINE); + mp_printf(print, "\n (%u lines all free)", (uint)((bl2 - bl) / DUMP_BYTES_PER_LINE)); bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1)); if (bl >= area->gc_alloc_table_byte_len * BLOCKS_PER_ATB) { // got to end of heap @@ -1442,7 +1626,7 @@ void gc_dump_alloc_table(const mp_print_t *print) { break; } */ - /* this prints the uPy object type of the head block */ + /* this prints the MicroPython object type of the head block */ case AT_HEAD: { // CIRCUITPY-CHANGE: compiler warning avoidance #pragma GCC diagnostic push diff --git a/py/gc.h b/py/gc.h index 0752478d1f2..0f693d49222 100644 --- a/py/gc.h +++ b/py/gc.h @@ -71,6 +71,11 @@ bool gc_alloc_possible(void); // Use this function to sweep the whole heap and run all finalisers void gc_sweep_all(void); +// These functions are used to manage weakrefs. +void gc_weakref_mark(void *ptr); +void gc_weakref_about_to_be_freed(void *ptr); +void gc_weakref_sweep(void); + enum { GC_ALLOC_FLAG_HAS_FINALISER = 1, // CIRCUITPY-CHANGE @@ -103,6 +108,7 @@ typedef struct _gc_info_t { } gc_info_t; void gc_info(gc_info_t *info); +void gc_info_fast(gc_info_t *info); void gc_dump_info(const mp_print_t *print); void gc_dump_alloc_table(const mp_print_t *print); diff --git a/py/lexer.c b/py/lexer.c index 98a10c87b2e..22ff4d2cd3a 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -35,11 +35,8 @@ #if MICROPY_ENABLE_COMPILER #define TAB_SIZE (8) - -// TODO seems that CPython allows NULL byte in the input stream -// don't know if that's intentional or not, but we don't allow it - -#define MP_LEXER_EOF ((unichar)MP_READER_EOF) +#define MP_LEXER_EOF ('\0') +#define MP_LEXER_INVALID_BYTE ('\1') #define CUR_CHAR(lex) ((lex)->chr0) static bool is_end(mp_lexer_t *lex) { @@ -62,7 +59,11 @@ static bool is_char_or3(mp_lexer_t *lex, byte c1, byte c2, byte c3) { return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3; } -#if MICROPY_PY_FSTRINGS +#if MICROPY_PY_TSTRINGS +static bool is_char_or5(mp_lexer_t *lex, byte c1, byte c2, byte c3, byte c4, byte c5) { + return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3 || lex->chr0 == c4 || lex->chr0 == c5; +} +#elif MICROPY_PY_FSTRINGS static bool is_char_or4(mp_lexer_t *lex, byte c1, byte c2, byte c3, byte c4) { return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3 || lex->chr0 == c4; } @@ -111,7 +112,11 @@ static bool is_following_odigit(mp_lexer_t *lex) { static bool is_string_or_bytes(mp_lexer_t *lex) { return is_char_or(lex, '\'', '\"') - #if MICROPY_PY_FSTRINGS + #if MICROPY_PY_TSTRINGS + || (is_char_or5(lex, 'r', 'u', 'b', 'f', 't') && is_char_following_or(lex, '\'', '\"')) + || (((is_char_and(lex, 'r', 'f') || is_char_and(lex, 'f', 'r') || is_char_and(lex, 'r', 't') || is_char_and(lex, 't', 'r')) + && is_char_following_following_or(lex, '\'', '\"'))) + #elif MICROPY_PY_FSTRINGS || (is_char_or4(lex, 'r', 'u', 'b', 'f') && is_char_following_or(lex, '\'', '\"')) || (((is_char_and(lex, 'r', 'f') || is_char_and(lex, 'f', 'r')) && is_char_following_following_or(lex, '\'', '\"'))) @@ -148,45 +153,51 @@ static void next_char(mp_lexer_t *lex) { lex->chr0 = lex->chr1; lex->chr1 = lex->chr2; - // and add the next byte from either the fstring args or the reader + // and add the next byte from either inject_chrs or the reader + mp_uint_t chr2; +fetch_next_byte: #if MICROPY_PY_FSTRINGS - if (lex->fstring_args_idx) { - // if there are saved chars, then we're currently injecting fstring args - if (lex->fstring_args_idx < lex->fstring_args.len) { - lex->chr2 = lex->fstring_args.buf[lex->fstring_args_idx++]; - } else { - // no more fstring arg bytes - lex->chr2 = '\0'; - } - - if (lex->chr0 == '\0') { - // consumed all fstring data, restore saved input queue - lex->chr0 = lex->chr0_saved; - lex->chr1 = lex->chr1_saved; - lex->chr2 = lex->chr2_saved; - // stop consuming fstring arg data - vstr_reset(&lex->fstring_args); - lex->fstring_args_idx = 0; + if (lex->inject_chrs_idx) { + // if there are saved chars, then we're currently injecting them + chr2 = lex->inject_chrs.buf[lex->inject_chrs_idx++]; + if (lex->inject_chrs_idx >= lex->inject_chrs.len) { + // consumed all injected characters, switch back to the input stream + vstr_reset(&lex->inject_chrs); + lex->inject_chrs_idx = 0; } } else #endif { - lex->chr2 = lex->reader.readbyte(lex->reader.data); + // get next byte from the reader + chr2 = lex->reader.readbyte(lex->reader.data); + + // convert stream mp_uint_t value to lexer uint8_t value: + // - MP_READER_EOF indicates end-of-stream, for which lexer uses MP_LEXER_EOF + // - MP_LEXER_EOF is not allowed in the input stream, as is converted to + // MP_LEXER_INVALID_BYTE so it's not interpreted as end-of-stream + // - all other byte values (1 through 255 inclusive) are passed through as-is + if (chr2 == MP_READER_EOF) { + chr2 = MP_LEXER_EOF; + } else if (chr2 == MP_LEXER_EOF) { + chr2 = MP_LEXER_INVALID_BYTE; + } } if (lex->chr1 == '\r') { // CR is a new line, converted to LF lex->chr1 = '\n'; - if (lex->chr2 == '\n') { + if (chr2 == '\n') { // CR LF is a single new line, throw out the extra LF - lex->chr2 = lex->reader.readbyte(lex->reader.data); + goto fetch_next_byte; } } // check if we need to insert a newline at end of file - if (lex->chr2 == MP_LEXER_EOF && lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n') { - lex->chr2 = '\n'; + if (chr2 == MP_LEXER_EOF && lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n') { + chr2 = '\n'; } + + lex->chr2 = chr2; } static void indent_push(mp_lexer_t *lex, size_t indent) { @@ -309,7 +320,7 @@ static bool get_hex(mp_lexer_t *lex, size_t num_digits, mp_uint_t *result) { return true; } -static void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) { +static void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring, bool is_tstring) { // get first quoting character char quote_char = '\''; if (is_char(lex, '\"')) { @@ -333,8 +344,7 @@ static void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) #if MICROPY_PY_FSTRINGS if (is_fstring) { // assume there's going to be interpolation, so prep the injection data - // fstring_args_idx==0 && len(fstring_args)>0 means we're extracting the args. - // only when fstring_args_idx>0 will we consume the arg data + // len(fstring_args)>0 means we're extracting the args. // lex->fstring_args is reset when finished, so at this point there are two cases: // - lex->fstring_args is empty: start of a new f-string // - lex->fstring_args is non-empty: concatenation of adjacent f-strings @@ -343,20 +353,52 @@ static void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) } } #endif + #if MICROPY_PY_TSTRINGS + if (is_tstring) { + if (vstr_len(&lex->fstring_args) == 0) { + vstr_add_byte(&lex->vstr, '('); + vstr_add_byte(&lex->vstr, '('); + for (size_t q = 0; q < num_quotes; ++q) { + vstr_add_byte(&lex->vstr, quote_char); + } + } + } + #endif + + #if MICROPY_PY_TSTRINGS + size_t tstring_num_interpolations = 0; + size_t end_of_format_index = 0; + size_t nested_formatting_in_tstring = 0; + bool nested_formatting_needs_fstring = false; + #endif while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\n')) && n_closing < num_quotes) { if (is_char(lex, quote_char)) { n_closing += 1; vstr_add_char(&lex->vstr, CUR_CHAR(lex)); + #if MICROPY_PY_TSTRINGS + } else if (is_tstring && is_char(lex, '\n')) { + // handle multi-line t-strings + vstr_add_byte(&lex->vstr, '\\'); + vstr_add_byte(&lex->vstr, 'n'); + #endif } else { n_closing = 0; #if MICROPY_PY_FSTRINGS - while (is_fstring && is_char(lex, '{')) { + while ((is_fstring || is_tstring) && is_char(lex, '{')) { + #if MICROPY_PY_TSTRINGS + if (nested_formatting_in_tstring) { + ++nested_formatting_in_tstring; + break; + } + #endif next_char(lex); if (is_char(lex, '{')) { // "{{" is passed through unchanged to be handled by str.format - vstr_add_byte(&lex->vstr, '{'); + if (!is_tstring) { + vstr_add_byte(&lex->vstr, '{'); + } next_char(lex); } else { // wrap each argument in (), e.g. @@ -393,23 +435,102 @@ static void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) vstr_add_byte(&lex->fstring_args, c); next_char(lex); } + #if MICROPY_PY_TSTRINGS + bool was_debug = false; + #endif if (lex->fstring_args.buf[lex->fstring_args.len - 1] == '=') { // if the last character of the arg was '=', then inject "arg=" before the '{'. // f'{a=}' --> 'a={}'.format(a) vstr_add_strn(&lex->vstr, lex->fstring_args.buf + i, lex->fstring_args.len - i); // remove the trailing '=' lex->fstring_args.len--; + #if MICROPY_PY_TSTRINGS + was_debug = true; + #endif + } + #if MICROPY_PY_TSTRINGS + if (is_tstring) { + // truncate trailing spaces + while (lex->fstring_args.len && unichar_isspace(lex->fstring_args.buf[lex->fstring_args.len - 1])) { + lex->fstring_args.len--; + } + } + #endif + if (lex->fstring_args.len == i) { + // empty format, eg f'{}' + // (should apply to both f-strings and t-strings, needs test) + lex->tok_kind = MP_TOKEN_MALFORMED_FSTRING; } // close the paren-wrapped arg to .format(). vstr_add_byte(&lex->fstring_args, ')'); // comma-separate args to .format(). vstr_add_byte(&lex->fstring_args, ','); + #if MICROPY_PY_TSTRINGS + if (is_tstring) { + // start the interpolation part + + // duplicate expression to a string + vstr_add_byte(&lex->fstring_args, quote_char); + size_t nn = lex->fstring_args.len - i - 3; + for (size_t j = 0; j < nn; ++j) { + byte b = lex->fstring_args.buf[i + j]; + if (b == quote_char) { + vstr_add_byte(&lex->fstring_args, '\\'); + } else if (b == '\\') { + vstr_add_byte(&lex->fstring_args, '\\'); + } + vstr_add_byte(&lex->fstring_args, b); + } + vstr_add_byte(&lex->fstring_args, quote_char); + vstr_add_byte(&lex->fstring_args, ','); + + // start next part of string as next __template__ argument + for (size_t q = 0; q < num_quotes; ++q) { + vstr_add_byte(&lex->vstr, quote_char); + } + vstr_add_byte(&lex->vstr, ','); + for (size_t q = 0; q < num_quotes; ++q) { + vstr_add_byte(&lex->vstr, quote_char); + } + + // process conv and format spec + if (is_char(lex, '!')) { + next_char(lex); + vstr_add_byte(&lex->fstring_args, quote_char); + vstr_add_byte(&lex->fstring_args, CUR_CHAR(lex)); + next_char(lex); + vstr_add_byte(&lex->fstring_args, quote_char); + vstr_add_byte(&lex->fstring_args, ','); + } else if (was_debug && !is_char(lex, ':')) { + vstr_add_str(&lex->fstring_args, "'r',"); + } else { + vstr_add_str(&lex->fstring_args, "None,"); + } + + // start format str + if (is_char(lex, ':')) { + next_char(lex); + } + nested_formatting_in_tstring = 1; + end_of_format_index = lex->vstr.len; + } + #endif } vstr_add_byte(&lex->vstr, '{'); + goto continue_outer; } #endif - if (is_char(lex, '\\')) { + if (is_tstring && is_char(lex, '\\')) { + // it'll be reparsed as a string + vstr_add_byte(&lex->vstr, '\\'); + if (is_raw) { + vstr_add_byte(&lex->vstr, '\\'); + } else { + next_char(lex); + vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); + } + } else if (is_char(lex, '\\')) { next_char(lex); unichar c = CUR_CHAR(lex); if (is_raw) { @@ -417,11 +538,9 @@ static void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) vstr_add_char(&lex->vstr, '\\'); } else { switch (c) { - // note: "c" can never be MP_LEXER_EOF because next_char - // always inserts a newline at the end of the input stream case '\n': - c = MP_LEXER_EOF; - break; // backslash escape the newline, just ignore it + // backslash escape the newline, just ignore it + goto continue_parsing_string_literal; case '\\': break; case '\'': @@ -492,33 +611,61 @@ static void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) break; } } - if (c != MP_LEXER_EOF) { - #if MICROPY_PY_BUILTINS_STR_UNICODE - if (c < 0x110000 && lex->tok_kind == MP_TOKEN_STRING) { - // Valid unicode character in a str object. - vstr_add_char(&lex->vstr, c); - } else if (c < 0x100 && lex->tok_kind == MP_TOKEN_BYTES) { - // Valid byte in a bytes object. - vstr_add_byte(&lex->vstr, c); - } - #else - if (c < 0x100) { - // Without unicode everything is just added as an 8-bit byte. - vstr_add_byte(&lex->vstr, c); - } - #endif - else { - // Character out of range; this raises a generic SyntaxError. - lex->tok_kind = MP_TOKEN_INVALID; + #if MICROPY_PY_BUILTINS_STR_UNICODE + if (c < 0x110000 && lex->tok_kind == MP_TOKEN_STRING) { + // Valid unicode character in a str object. + vstr_add_char(&lex->vstr, c); + } else if (c < 0x100 && lex->tok_kind == MP_TOKEN_BYTES) { + // Valid byte in a bytes object. + vstr_add_byte(&lex->vstr, c); + } + #else + if (c < 0x100) { + // Without unicode everything is just added as an 8-bit byte. + vstr_add_byte(&lex->vstr, c); + } + #endif + else { + // Character out of range; this raises a generic SyntaxError. + lex->tok_kind = MP_TOKEN_INVALID; + } + #if MICROPY_PY_TSTRINGS + } else if (is_tstring && nested_formatting_in_tstring && is_char(lex, '}')) { + if (--nested_formatting_in_tstring > 0) { + nested_formatting_needs_fstring = true; + vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); + } else { + // finished the current interpolation + ++tstring_num_interpolations; + if (nested_formatting_needs_fstring) { + vstr_add_byte(&lex->fstring_args, 'f'); + nested_formatting_needs_fstring = false; } + vstr_add_byte(&lex->fstring_args, quote_char); + vstr_add_strn(&lex->fstring_args, lex->vstr.buf + end_of_format_index + 1, lex->vstr.len - end_of_format_index - 1); + lex->vstr.len = end_of_format_index; + vstr_add_byte(&lex->fstring_args, quote_char); + vstr_add_byte(&lex->fstring_args, ','); } + #endif } else { // Add the "character" as a byte so that we remain 8-bit clean. // This way, strings are parsed correctly whether or not they contain utf-8 chars. vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); + #if MICROPY_PY_TSTRINGS + if (is_tstring && is_char_and(lex, '}', '}')) { + next_char(lex); + } else if (is_tstring && is_char(lex, '}')) { + lex->tok_kind = MP_TOKEN_MALFORMED_FSTRING; + } + #endif } } + continue_parsing_string_literal: next_char(lex); + #if MICROPY_PY_FSTRINGS + continue_outer:; + #endif } // check we got the required end quotes @@ -526,8 +673,23 @@ static void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) lex->tok_kind = MP_TOKEN_LONELY_STRING_OPEN; } - // cut off the end quotes from the token text - vstr_cut_tail_bytes(&lex->vstr, n_closing); + #if MICROPY_PY_TSTRINGS + if (is_tstring) { + if (nested_formatting_in_tstring > 0) { + lex->tok_kind = MP_TOKEN_MALFORMED_FSTRING; + } + + if (1 + tstring_num_interpolations * 4 > 255) { + // too many arguments for function call, so wrap interpolations in a tuple + vstr_ins_byte(&lex->fstring_args, 0, '('); + vstr_add_byte(&lex->fstring_args, ')'); + } + } else + #endif + { + // cut off the end quotes from the token text + vstr_cut_tail_bytes(&lex->vstr, n_closing); + } } // This function returns whether it has crossed a newline or not. @@ -559,23 +721,6 @@ static bool skip_whitespace(mp_lexer_t *lex, bool stop_at_newline) { } void mp_lexer_to_next(mp_lexer_t *lex) { - #if MICROPY_PY_FSTRINGS - if (lex->fstring_args.len && lex->fstring_args_idx == 0) { - // moving onto the next token means the literal string is complete. - // switch into injecting the format args. - vstr_add_byte(&lex->fstring_args, ')'); - lex->chr0_saved = lex->chr0; - lex->chr1_saved = lex->chr1; - lex->chr2_saved = lex->chr2; - lex->chr0 = lex->fstring_args.buf[0]; - lex->chr1 = lex->fstring_args.buf[1]; - lex->chr2 = lex->fstring_args.buf[2]; - // we've already extracted 3 chars, but setting this non-zero also - // means we'll start consuming the fstring data - lex->fstring_args_idx = 3; - } - #endif - // start new token text vstr_reset(&lex->vstr); @@ -635,11 +780,16 @@ void mp_lexer_to_next(mp_lexer_t *lex) { // MP_TOKEN_END is used to indicate that this is the first string token lex->tok_kind = MP_TOKEN_END; + #if MICROPY_PY_TSTRINGS + bool had_tstring = false; + #endif + // Loop to accumulate string/bytes literals do { // parse type codes bool is_raw = false; bool is_fstring = false; + bool is_tstring = false; mp_token_kind_t kind = MP_TOKEN_STRING; int n_char = 0; if (is_char(lex, 'u')) { @@ -659,11 +809,17 @@ void mp_lexer_to_next(mp_lexer_t *lex) { n_char = 2; } #if MICROPY_PY_FSTRINGS - if (is_char_following(lex, 'f')) { + else if (is_char_following(lex, 'f')) { is_fstring = true; n_char = 2; } #endif + #if MICROPY_PY_TSTRINGS + else if (is_char_following(lex, 't')) { + is_tstring = true; + n_char = 2; + } + #endif } #if MICROPY_PY_FSTRINGS else if (is_char(lex, 'f')) { @@ -675,6 +831,22 @@ void mp_lexer_to_next(mp_lexer_t *lex) { } } #endif + #if MICROPY_PY_TSTRINGS + else if (is_char(lex, 't')) { + is_tstring = true; + n_char = 1; + if (is_char_following(lex, 'r')) { + is_raw = true; + n_char = 2; + } + } + #endif + + #if MICROPY_PY_TSTRINGS + if (is_tstring) { + had_tstring = true; + } + #endif // Set or check token kind if (lex->tok_kind == MP_TOKEN_END) { @@ -693,13 +865,52 @@ void mp_lexer_to_next(mp_lexer_t *lex) { } // Parse the literal - parse_string_literal(lex, is_raw, is_fstring); + parse_string_literal(lex, is_raw, is_fstring, is_tstring); // Skip whitespace so we can check if there's another string following skip_whitespace(lex, true); } while (is_string_or_bytes(lex)); + #if MICROPY_PY_TSTRINGS + if (had_tstring) { + vstr_add_byte(&lex->vstr, ','); + vstr_add_byte(&lex->vstr, ')'); + vstr_add_byte(&lex->vstr, ','); + vstr_ins_strn(&lex->fstring_args, 0, lex->vstr.buf, lex->vstr.len); + if (lex->tok_kind > MP_TOKEN_MALFORMED_FSTRING) { + // next token is __template__ for the function + lex->tok_kind = MP_TOKEN_NAME; + vstr_reset(&lex->vstr); + vstr_add_str(&lex->vstr, "__template__"); + } + } + #endif + + #if MICROPY_PY_FSTRINGS + if (lex->fstring_args.len) { + // If there was an f-string then it's now complete. + // Switch into injecting the format args. + vstr_add_byte(&lex->fstring_args, ')'); + if (lex->inject_chrs_idx == 0) { + // switch from stream to inject_chrs + char *s = vstr_add_len(&lex->inject_chrs, 3); + s[0] = lex->chr0; + s[1] = lex->chr1; + s[2] = lex->chr2; + } else { + // already consuming from inject_chrs, rewind cached chars to insert new ones + assert(lex->inject_chrs_idx >= 3); + lex->inject_chrs_idx -= 3; + } + vstr_ins_strn(&lex->inject_chrs, lex->inject_chrs_idx, lex->fstring_args.buf, lex->fstring_args.len); + vstr_reset(&lex->fstring_args); + lex->chr0 = lex->inject_chrs.buf[lex->inject_chrs_idx++]; + lex->chr1 = lex->inject_chrs.buf[lex->inject_chrs_idx++]; + lex->chr2 = lex->inject_chrs.buf[lex->inject_chrs_idx++]; + } + #endif + } else if (is_head_of_identifier(lex)) { lex->tok_kind = MP_TOKEN_NAME; @@ -857,8 +1068,9 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) { lex->indent_level = m_new(uint16_t, lex->alloc_indent_level); vstr_init(&lex->vstr, 32); #if MICROPY_PY_FSTRINGS + vstr_init(&lex->inject_chrs, 0); + lex->inject_chrs_idx = 0; vstr_init(&lex->fstring_args, 0); - lex->fstring_args_idx = 0; #endif // store sentinel for first indentation level @@ -915,6 +1127,7 @@ void mp_lexer_free(mp_lexer_t *lex) { lex->reader.close(lex->reader.data); vstr_clear(&lex->vstr); #if MICROPY_PY_FSTRINGS + vstr_clear(&lex->inject_chrs); vstr_clear(&lex->fstring_args); #endif m_del(uint16_t, lex->indent_level, lex->alloc_indent_level); diff --git a/py/lexer.h b/py/lexer.h index 6e6c3e8f23e..b1257d55948 100644 --- a/py/lexer.h +++ b/py/lexer.h @@ -162,10 +162,8 @@ typedef struct _mp_lexer_t { qstr source_name; // name of source mp_reader_t reader; // stream source - unichar chr0, chr1, chr2; // current cached characters from source - #if MICROPY_PY_FSTRINGS - unichar chr0_saved, chr1_saved, chr2_saved; // current cached characters from alt source - #endif + uint32_t chr0; // first cached byte from source (32-bits for efficient access) + uint8_t chr1, chr2; // subsequent cached bytes from source size_t line; // current source line size_t column; // current source column @@ -182,8 +180,9 @@ typedef struct _mp_lexer_t { mp_token_kind_t tok_kind; // token kind vstr_t vstr; // token data #if MICROPY_PY_FSTRINGS + vstr_t inject_chrs; // characters currently being injected into the stream + size_t inject_chrs_idx; // current index into inject_chrs vstr_t fstring_args; // extracted arguments to pass to .format() - size_t fstring_args_idx; // how many bytes of fstring_args have been read #endif } mp_lexer_t; diff --git a/py/make_root_pointers.py b/py/make_root_pointers.py index efe398b8227..5da343c1270 100644 --- a/py/make_root_pointers.py +++ b/py/make_root_pointers.py @@ -6,8 +6,6 @@ "struct _mp_state_vm_t" in py/mpstate.h """ -from __future__ import print_function - import argparse import io import re diff --git a/py/makecompresseddata.py b/py/makecompresseddata.py index 1bce3e8e837..a6fa7db00b2 100644 --- a/py/makecompresseddata.py +++ b/py/makecompresseddata.py @@ -1,5 +1,3 @@ -from __future__ import print_function - import collections import re import sys diff --git a/py/makemoduledefs.py b/py/makemoduledefs.py index 29162ab387c..c8fdc21f6fb 100644 --- a/py/makemoduledefs.py +++ b/py/makemoduledefs.py @@ -14,8 +14,6 @@ the built-in version. """ -from __future__ import print_function - import sys import re import io @@ -87,19 +85,25 @@ def generate_module_table_header(modules): ) ) + # There should always be at least one module (__main__ in runtime.c) + assert mod_defs + print("\n#define MICROPY_REGISTERED_MODULES \\") for mod_def in sorted(mod_defs): print(" {mod_def} \\".format(mod_def=mod_def)) - print("// MICROPY_REGISTERED_MODULES") - print("\n#define MICROPY_REGISTERED_EXTENSIBLE_MODULES \\") + # There are not necessarily any extensible modules (e.g., bare-arm or minimal x86) + print("\n#define MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES ", len(extensible_mod_defs)) - for mod_def in sorted(extensible_mod_defs): - print(" {mod_def} \\".format(mod_def=mod_def)) + if extensible_mod_defs: + print("\n#define MICROPY_REGISTERED_EXTENSIBLE_MODULES \\") + + for mod_def in sorted(extensible_mod_defs): + print(" {mod_def} \\".format(mod_def=mod_def)) - print("// MICROPY_REGISTERED_EXTENSIBLE_MODULES") + print("// MICROPY_REGISTERED_EXTENSIBLE_MODULES") def generate_module_delegations(delegations): diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 45cc896f925..3fdb2d5476b 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -1,31 +1,13 @@ """ Process raw qstr file and output qstr data with length, hash and data bytes. -This script works with Python 2.7, 3.3 and 3.4. - -CIRCUITPY-CHANGE: -For documentation about the format of compressed translated strings, see -supervisor/shared/translate/translate.h +This script works with Python 3.3+. """ -from __future__ import print_function - - import re import sys -# CIRCUITPY-CHANGE -if hasattr(sys.stdout, "reconfigure"): - sys.stdout.reconfigure(encoding="utf-8") - sys.stderr.reconfigure(errors="backslashreplace") - -# Python 2/3 compatibility: -# - iterating through bytes is different -# - codepoint2name from html.entities is hard-coded -if sys.version_info[0] == 2: - bytes_cons = lambda val, enc=None: bytearray(val) -elif sys.version_info[0] == 3: # Also handles MicroPython - bytes_cons = bytes +bytes_cons = bytes # fmt: off codepoint2name = { @@ -51,7 +33,7 @@ 954: "kappa", 8656: "lArr", 955: "lambda", 9001: "lang", 171: "laquo", 8592: "larr", 8968: "lceil", 8220: "ldquo", 8804: "le", 8970: "lfloor", 8727: "lowast", 9674: "loz", 8206: "lrm", 8249: "lsaquo", 8216: "lsquo", 60: "lt", 175: "macr", 8212: "mdash", 181: "micro", 183: "middot", 8722: "minus", - 956: "mu", 8711: "nabla", 160: "nbsp", 8211: "ndash", 8800: "ne", 8715: "ni", 172: "not", 8713: "notin", + 956: "mu", 8711: "nabla", 160: "nbsp", 8211: "ndash", 8800: "ne", 8715: "ni", 172: "not", 8713: "notin", # codespell:ignore notin 8836: "nsub", 241: "ntilde", 957: "nu", 243: "oacute", 244: "ocirc", 339: "oelig", 242: "ograve", 8254: "oline", 969: "omega", 959: "omicron", 8853: "oplus", 8744: "or", 170: "ordf", 186: "ordm", 248: "oslash", 245: "otilde", 8855: "otimes", 246: "ouml", 182: "para", 8706: "part", 8240: "permil", @@ -67,7 +49,6 @@ 253: "yacute", 165: "yen", 255: "yuml", 950: "zeta", 8205: "zwj", 8204: "zwnj" } # fmt: on -# end compatibility code codepoint2name[ord("-")] = "hyphen" diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index a4039857694..3bc81bf5961 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -2,11 +2,9 @@ This script processes the output from the C preprocessor and extracts all qstr. Each qstr is transformed into a qstr definition of the form 'Q(...)'. -This script works with Python 3.x (CIRCUITPY-CHANGE: not 2.x) +This script works with Python 3.3+. """ -from __future__ import print_function - import io import os import re @@ -96,10 +94,36 @@ def preprocess(): except OSError: pass + # These regex's are used to filter the preprocessed data, keeping only those lines + # that are subsequently needed by the `process_file` step. The regexs are kept + # short so they are as efficient as possible. (The stm32 port needs symbols of the + # form `micropy_hw_xxx` so they are also kept.) + re_line_file = re.compile(rb"^#(?:line)?\s+\d+\s\"") + re_mp_info = re.compile(rb"MP_COMP|MP_QSTR|MP_REGI|micropy_hw") + def pp(flags): def run(files): try: - return subprocess.check_output(args.pp + flags + files) + filtered_lines = [] + cmd = args.pp + flags + files + with subprocess.Popen(cmd, stdout=subprocess.PIPE) as proc: + for line in proc.stdout: + if line.isspace(): + pass + elif re_line_file.match(line): + # CIRCUITPY-CHANGE: keep every file marker, not just + # the one preceding an MP symbol. CircuitPython + # attributes MP_COMPRESSED_ROM_TEXT found in headers + # to the enclosing C source, so process_file needs + # the C source markers even when the symbol itself + # comes from a header. + filtered_lines.append(line) + elif re_mp_info.search(line): + filtered_lines.append(line) + proc.wait() + if proc.returncode: + raise PreprocessorError("command failed: " + " ".join(cmd)) + return b"".join(filtered_lines) except subprocess.CalledProcessError as er: raise PreprocessorError(str(er)) @@ -139,6 +163,7 @@ def qstr_unescape(qstr): return qstr +# CIRCUITPY-CHANGE: output_filename as an arg def process_file(f, output_filename=None): # match gcc-like output (# n "file") and msvc-like output (#line n "file") re_line = re.compile(r"^#(?:line)?\s+\d+\s\"([^\"]+)\"") @@ -292,6 +317,7 @@ class Args: args.input_filename = sys.argv[3] # Unused for command=cat args.output_dir = sys.argv[4] args.output_file = None if len(sys.argv) == 5 else sys.argv[5] # Unused for command=split + # CIRCUITPY-CHANGE if args.output_file == "_": args.output_file = None @@ -306,6 +332,7 @@ class Args: if args.command == "split": with io.open(args.input_filename, encoding="utf-8") as infile: + # CIRCUITPY-CHANGE: pass output_file process_file(infile, args.output_file) if args.command == "cat": diff --git a/py/maketranslationdata.py b/py/maketranslationdata.py index 3933387b645..22b0ed1eeb9 100644 --- a/py/maketranslationdata.py +++ b/py/maketranslationdata.py @@ -6,13 +6,13 @@ supported CPython version are unintended. For documentation about the format of compressed translated strings, see -supervisor/shared/translate/translate.h +supervisor/shared/translate/compressed_string.h """ from __future__ import print_function import bisect -from dataclasses import dataclass +from dataclasses import dataclass, field import re import sys @@ -73,6 +73,102 @@ '"': '\\"', } +# Symbol values with a special meaning, as characters. Must match +# translation_symbol_t in supervisor/shared/translate/compressed_string.h. +SYMBOL_QSTR = "\1" +SYMBOL_RARE_INDEX = "\2" +SYMBOL_RARE_RAW = "\3" +RESERVED_CHARS = {SYMBOL_QSTR, SYMBOL_RARE_INDEX, SYMBOL_RARE_RAW} + +# The first non-ASCII symbol value in the dense alphabet. +ALPHABET_BASE = 0x80 + +# Huffman codes are chosen per "class" of the previously decoded character. +# These base classes are fixed in the C decoder (translate.c, base_class()) and +# must match translation_class_t in supervisor/shared/translate/compressed_string.h; +# the generator collapses them with class_map[] into TRANSLATION_CLASSES tables. +CLASS_START_OR_SPACE = 0 +CLASS_LOWER = 1 +CLASS_UPPER = 2 +CLASS_DIGIT = 3 +CLASS_OTHER = 4 +CLASS_PERCENT = 5 +CLASS_NON_ASCII = 6 +NUM_BASE_CLASSES = 7 +# Presets to try. Each is the list of Huffman tables to build, each table +# naming the base classes that share it. class_map_for() turns one into the +# class_map[] the decoder uses. +CLASS_PRESETS = ( + # one table: the tables cost more than they save + [ + [ + CLASS_START_OR_SPACE, + CLASS_LOWER, + CLASS_UPPER, + CLASS_DIGIT, + CLASS_OTHER, + CLASS_PERCENT, + CLASS_NON_ASCII, + ] + ], + # space, letter, other + [ + [CLASS_START_OR_SPACE], + [CLASS_LOWER, CLASS_UPPER, CLASS_NON_ASCII], + [CLASS_DIGIT, CLASS_OTHER, CLASS_PERCENT], + ], + # non-ASCII shares the lowercase table + [ + [CLASS_START_OR_SPACE], + [CLASS_LOWER, CLASS_NON_ASCII], + [CLASS_UPPER], + [CLASS_DIGIT], + [CLASS_OTHER], + [CLASS_PERCENT], + ], + # non-ASCII has its own table + [ + [CLASS_START_OR_SPACE], + [CLASS_LOWER], + [CLASS_UPPER], + [CLASS_DIGIT], + [CLASS_OTHER], + [CLASS_PERCENT], + [CLASS_NON_ASCII], + ], +) + + +def class_map_for(preset): + """class_map[] for a preset: base class -> index of the table it uses.""" + class_map = [None] * NUM_BASE_CLASSES + for table, classes in enumerate(preset): + for cls in classes: + assert class_map[cls] is None, f"class {cls} in two tables" + class_map[cls] = table + assert None not in class_map, "every base class needs a table" + return tuple(class_map) + + +def base_class(c): + """Class of the character preceding the next symbol; None means start of string. + Computed on the (possibly remapped) character: remapped characters are >= 0x80 + exactly when the original is, which is all the classification looks at.""" + if c is None or c == " ": + return CLASS_START_OR_SPACE + o = ord(c) + if 0x61 <= o <= 0x7A: + return CLASS_LOWER + if 0x41 <= o <= 0x5A: + return CLASS_UPPER + if 0x30 <= o <= 0x39: + return CLASS_DIGIT + if o == 0x25: # '%' + return CLASS_PERCENT + if o >= 0x80: + return CLASS_NON_ASCII + return CLASS_OTHER + # this must match the equivalent function in qstr.c def compute_hash(qstr, bytes_hash): @@ -140,100 +236,183 @@ def iter_substrings(s, minlen, maxlen): yield s[begin : begin + n] -translation_requires_uint16 = {"cs", "ja", "ko", "pl", "tr", "zh_Latn_pinyin"} +# Non-ASCII characters that do not get a dense symbol are "rare". While the text +# is being processed they are remapped into two private-use ranges so that they +# stay single characters: those used more than once become an index into +# rare_chars[], those used once are coded as a raw 16-bit code point. +RARE_IDX_BASE = 0xF0000 +RARE_RAW_BASE = 0x100000 +RARE_SPLIT = re.compile("[\U000f0000-\U0010ffff]") +# Dense alphabet sizes to try when a language has more non-ASCII characters +# than fit; the rest of the code points go to the dictionary. +DENSE_ALPHABET_TRIES = (32, 48, 64, 80) -def compute_unicode_offset(texts): - all_ch = set(" ".join(texts)) - ch_160 = sorted(c for c in all_ch if 160 <= ord(c) < 255) - ch_256 = sorted(c for c in all_ch if 255 < ord(c)) - if not ch_256: - return 0, 0 - min_256 = ord(min(ch_256)) - span = ord(max(ch_256)) - ord(min(ch_256)) + 1 +@dataclass +class EncodingTable: + # One entry per class table: list of symbols in canonical order. + values: list + # One entry per class table: list of code-length counts, padded to lengths_row. + lengths: list + lengths_row: int + class_map: tuple + # Per class table: symbol -> canonical code (string of '0'/'1'). + canonical: list + # Dictionary words, in remapped characters, sorted by length. + words: list + word_start: int + # Dense alphabet: index -> original character. + alphabet: list + # Rare characters coded by index -> original character. + rare_idx_chars: list + rare_index_bits: int + # Original character -> remapped character (identity for ASCII). + remap: dict + translation_qstr_bits: int + qstrs: dict + qstrs_inv: dict + # Remapped text -> token list used to encode it. A token is a str (character + # or word) or a ("q", qstr) tuple. + tokens: dict = field(default_factory=dict) - if ch_160: - max_160 = ord(max(ch_160)) + 1 - else: - max_160 = max(160, 255 - span) - if max_160 + span > 256: - return 0, 0 +def remap_text(text, remap): + return "".join(remap.get(c, c) for c in text) - offstart = max_160 - offset = min_256 - max_160 - return offstart, offset +def is_qstr(token): + return isinstance(token, tuple) -@dataclass -class EncodingTable: - values: object - lengths: object - words: object - canonical: object - extractor: object - apply_offset: object - remove_offset: object - translation_qstr_bits: int - qstrs: object - qstrs_inv: object +def is_rare(token): + return len(token) == 1 and ord(token) >= RARE_IDX_BASE -def compute_huffman_coding(qstrs, translation_name, translations, f, compression_level): - # possible future improvement: some languages are better when consider len(k) > 2. try both? - qstrs = dict((k, v) for k, v in qstrs.items() if len(k) > 3) - qstr_strs = list(qstrs.keys()) - texts = [t[1] for t in translations] - words = [] - start_unused = 0x80 - end_unused = 0xFF - max_ord = 0 - offstart, offset = compute_unicode_offset(texts) - - def apply_offset(c): - oc = ord(c) - if oc >= offstart: - oc += offset - return chr(oc) - - def remove_offset(c): - oc = ord(c) - if oc >= offstart: - oc = oc - offset - try: - return chr(oc) - except Exception as e: - raise ValueError(f"remove_offset {offstart=} {oc=}") from e +def token_len(token): + return len(token[1]) if is_qstr(token) else len(token) + + +def token_symbol(token): + """The Huffman symbol a token is coded as. qstrs and rare characters are + coded as an escape symbol followed by a fixed number of bits.""" + if is_qstr(token): + return SYMBOL_QSTR + if is_rare(token): + return SYMBOL_RARE_RAW if ord(token) >= RARE_RAW_BASE else SYMBOL_RARE_INDEX + return token - for text in texts: - for c in text: - c = remove_offset(c) - ord_c = ord(c) - max_ord = max(ord_c, max_ord) - if 0x80 <= ord_c < 0xFF: - end_unused = min(ord_c, end_unused) - max_words = end_unused - 0x80 - if compression_level < 5: - max_words = 0 - - bits_per_codepoint = 16 if max_ord > 255 else 8 - values_type = "uint16_t" if max_ord > 255 else "uint8_t" - translation_name = translation_name.split("/")[-1].split(".")[0] - if max_ord > 255 and translation_name not in translation_requires_uint16: - raise ValueError( - f"Translation {translation_name} expected to fit in 8 bits but required 16 bits" - ) - # Prune the qstrs to only those that appear in the texts - qstr_counters = collections.Counter() - qstr_extractor = TextSplitter(qstr_strs) - for t in texts: - for qstr in qstr_extractor.iter(t): - if qstr in qstr_strs: - qstr_counters[qstr] += 1 - qstr_strs = list(qstr_counters.keys()) +def token_extra_bits(token, qstr_bits, rare_index_bits): + """Fixed-width bits that follow the token's Huffman symbol.""" + if is_qstr(token): + return qstr_bits + if is_rare(token): + return 16 if ord(token) >= RARE_RAW_BASE else rare_index_bits + return 0 + +def code_lengths(counter): + """Huffman code lengths for a symbol counter. A lone symbol gets a 1-bit code.""" + if len(counter) == 1: + return {next(iter(counter)): 1} + cb = huffman.codebook(counter.items()) + return {k: len(v) for k, v in cb.items()} + + +def canonical_codes(lengths): + """Canonical Huffman codes from a symbol -> length dict. + Returns (values in canonical order, per-length counts, symbol -> code).""" + if not lengths: + return [], [], {} + values = [] + length_count = collections.Counter() + canonical = {} + renumbered = 0 + last_length = None + for atom, length in sorted(lengths.items(), key=lambda x: (x[1], x[0])): + values.append(atom) + length_count[length] += 1 + if last_length: + renumbered <<= length - last_length + canonical[atom] = "{0:0{width}b}".format(renumbered, width=length) + renumbered += 1 + last_length = length + counts = [length_count.get(i, 0) for i in range(1, max(length_count) + 2)] + return values, counts, canonical + + +def parse_optimal( + text, + lens, + class_map, + words_by_first, + qstrs_by_first, + qstr_bits, + rare_index_bits, + unknown_len=32, +): + """Tokenize text with the fewest bits given per-class code lengths. + Symbols missing from a class table are allowed at a penalty so a parse always exists.""" + n = len(text) + best = [math.inf] * (n + 1) + back = [None] * (n + 1) + best[0] = 0 + for i in range(n): + if best[i] == math.inf: + continue + table = lens[class_map[base_class(text[i - 1] if i else None)]] + c = text[i] + cands = [c] + for w in words_by_first.get(c, ()): + if text.startswith(w, i): + cands.append(w) + for q in qstrs_by_first.get(c, ()): + if text.startswith(q, i): + cands.append(("q", q)) + for tok in cands: + cost = table.get(token_symbol(tok), unknown_len) + cost += token_extra_bits(tok, qstr_bits, rare_index_bits) + j = i + token_len(tok) + if best[i] + cost < best[j]: + best[j] = best[i] + cost + back[j] = tok + out = [] + i = n + while i > 0: + tok = back[i] + out.append(tok) + i -= token_len(tok) + out.reverse() + return out + + +def tally(texts, tokens, class_map): + """Symbol counts per class table for the given tokenizations.""" + counts = collections.defaultdict(collections.Counter) + for text in texts: + pos = 0 + for tok in tokens[text]: + cls = class_map[base_class(text[pos - 1] if pos else None)] + counts[cls][token_symbol(tok)] += 1 + pos += token_len(tok) + return counts + + +def encoded_bits(text, tokens, lens, class_map, qstr_bits, rare_index_bits): + bits = 0 + pos = 0 + for tok in tokens: + cls = class_map[base_class(text[pos - 1] if pos else None)] + bits += lens[cls][token_symbol(tok)] + bits += token_extra_bits(tok, qstr_bits, rare_index_bits) + pos += token_len(tok) + return bits + + +def find_words(texts, qstrs, qstr_strs, max_words): + """Greedy dictionary search: repeatedly add the 2- to 11-gram estimated to + save the most bits until the dictionary is full or nothing pays off.""" + words = [] while len(words) < max_words: # Until the dictionary is filled to capacity, use a heuristic to find # the best "word" (2- to 11-gram) to add to it. @@ -248,7 +427,7 @@ def remove_offset(c): for t in texts: for atom in extractor.iter(t): if atom in qstrs: - atom = "\1" + atom = SYMBOL_QSTR counter[atom] += 1 cb = huffman.codebook(counter.items()) lengths = sorted(dict((v, len(cb[k])) for k, v in counter.items()).items()) @@ -284,15 +463,18 @@ def est_len(occ): # The difference between the two is the estimated net savings, in bits. def est_net_savings(s, occ): savings = occ * (bit_length(s) - est_len(occ)) - cost = len(s) * bits_per_codepoint + 24 + cost = len(s) * 8 + 24 return savings - cost counter = collections.Counter() for t in texts: for found, word in extractor.iter_words(t): if not found: - for substr in iter_substrings(word, minlen=2, maxlen=11): - counter[substr] += 1 + # Words are stored as 8-bit symbols, so they cannot contain + # rare (escaped) characters: split around them. + for piece in RARE_SPLIT.split(word): + for substr in iter_substrings(piece, minlen=2, maxlen=11): + counter[substr] += 1 # Score the candidates we found. This is a semi-empirical formula that # attempts to model the number of bits saved as closely as possible. @@ -319,90 +501,239 @@ def est_net_savings(s, occ): word = scores[0][0] words.append(word) + return words + + +def compute_huffman_coding(qstrs, translation_name, translations, f, compression_level): + # possible future improvement: some languages are better when consider len(k) > 2. try both? + qstrs = dict((k, v) for k, v in qstrs.items() if len(k) > 3) + all_qstr_strs = list(qstrs.keys()) + original_texts = [t[1] for t in translations] + + for text in original_texts: + bad = RESERVED_CHARS.intersection(text) + if bad: + raise ValueError(f"Translation contains reserved character {bad!r}: {text!r}") + if any(ord(c) >= RARE_IDX_BASE for c in text): + raise ValueError(f"Translation contains private-use character: {text!r}") + + max_translation_encoded_length = max(len(t.encode("utf-8")) for t in original_texts) + encoded_length_bits = max_translation_encoded_length.bit_length() + use_qstrs = compression_level > 3 + + # Non-ASCII characters by decreasing frequency. The most frequent ones are + # renumbered from 0x80 (the dense alphabet), so that all symbols fit in 8 + # bits; the rest are escaped. + hi_count = collections.Counter(c for t in original_texts for c in t if ord(c) >= 0x80) + hi_chars = [c for c, _ in hi_count.most_common()] + if len(hi_chars) <= 0x7F: + dense_tries = (len(hi_chars),) + else: + dense_tries = DENSE_ALPHABET_TRIES + + def encode(dense_count): + alphabet = hi_chars[:dense_count] + rare = hi_chars[dense_count:] + rare_idx_chars = [c for c in rare if hi_count[c] > 1] + rare_raw_chars = [c for c in rare if hi_count[c] == 1] + rare_index_bits = (len(rare_idx_chars) - 1).bit_length() if rare_idx_chars else 0 + remap = {c: chr(ALPHABET_BASE + i) for i, c in enumerate(alphabet)} + remap.update({c: chr(RARE_IDX_BASE + i) for i, c in enumerate(rare_idx_chars)}) + remap.update({c: chr(RARE_RAW_BASE + i) for i, c in enumerate(rare_raw_chars)}) + word_start = ALPHABET_BASE + len(alphabet) + max_words = 0x100 - word_start if compression_level >= 5 else 0 + + texts = [remap_text(t, remap) for t in original_texts] + + # Prune the qstrs to only those that appear in the texts + qstr_counters = collections.Counter() + qstr_extractor = TextSplitter(all_qstr_strs) + for t in texts: + for qstr in qstr_extractor.iter(t): + if qstr in qstrs: + qstr_counters[qstr] += 1 + qstr_strs = list(qstr_counters.keys()) + + words = find_words(texts, qstrs, qstr_strs, max_words) + + # Now that the dictionary is fixed, find the tokenization of each string + # that takes the fewest bits, with Huffman codes chosen per class of the + # previous character. Code lengths and tokenization depend on each other, + # so iterate a few rounds from the greedy tokenization; the final + # tokenization and the codes built from it are what get emitted, so they + # are always consistent. + dp_qstrs = qstr_strs if use_qstrs else [] + # Upper bound on the qstr index width while parsing; the real width is computed below. + est_qstr_bits = max([0] + [qstrs[q] for q in dp_qstrs]).bit_length() + words_by_first = collections.defaultdict(list) + for w in words: + words_by_first[w[0]].append(w) + qstrs_by_first = collections.defaultdict(list) + for q in dp_qstrs: + qstrs_by_first[q[0]].append(q) + + greedy = TextSplitter(words + dp_qstrs) + greedy_tokens = {} + for t in texts: + greedy_tokens[t] = [("q", a) if a in qstrs else a for a in greedy.iter(t)] + + def table_bytes(class_map, counts, used_words): + nclasses = max(class_map) + 1 + row = max(max(code_lengths(cn).values()) for cn in counts.values()) + 1 + n = sum(len(cn) for cn in counts.values()) # values + n += nclasses * row # lengths + n += 2 * (nclasses + 1) # values_offset + n += NUM_BASE_CLASSES # class_map + n += sum(len(w) for w in used_words) # words + if used_words: + n += len(used_words[-1]) - len(used_words[0]) + 1 # wlencount + n += 2 * len(alphabet) + n += 2 * len(rare_idx_chars) + return n + + best = None + for preset in CLASS_PRESETS: + class_map = class_map_for(preset) + tokens = greedy_tokens + counts = tally(texts, tokens, class_map) + lens = {cls: code_lengths(cn) for cls, cn in counts.items()} + for _ in range(3): + tokens = { + t: parse_optimal( + t, + lens, + class_map, + words_by_first, + qstrs_by_first, + est_qstr_bits, + rare_index_bits, + ) + for t in texts + } + counts = tally(texts, tokens, class_map) + lens = {cls: code_lengths(cn) for cls, cn in counts.items()} + used_symbols = set().union(*counts.values()) + used_words = sorted((w for w in words if w in used_symbols), key=len) + size = table_bytes(class_map, counts, used_words) + sum( + ( + encoded_length_bits + + encoded_bits(t, tokens[t], lens, class_map, est_qstr_bits, rare_index_bits) + + 7 + ) + // 8 + for t in texts + ) + if best is None or size < best[0]: + best = (size, class_map, tokens, lens, used_words) + size, class_map, tokens, lens, words = best + return size, dict( + class_map=class_map, + tokens=tokens, + lens=lens, + words=words, + alphabet=alphabet, + rare_idx_chars=rare_idx_chars, + rare_raw_chars=rare_raw_chars, + rare_index_bits=rare_index_bits, + remap=remap, + word_start=word_start, + ) - splitters = words[:] - if compression_level > 3: - splitters.extend(qstr_strs) + size, r = min((encode(k) for k in dense_tries), key=lambda x: x[0]) + class_map = r["class_map"] + tokens = r["tokens"] + lens = r["lens"] + words = r["words"] + alphabet = r["alphabet"] + rare_idx_chars = r["rare_idx_chars"] + rare_raw_chars = r["rare_raw_chars"] + rare_index_bits = r["rare_index_bits"] + remap = r["remap"] + word_start = r["word_start"] - words.sort(key=len) - extractor = TextSplitter(splitters) - counter = collections.Counter() used_qstr = 0 - for t in texts: - for atom in extractor.iter(t): - if atom in qstrs: - used_qstr = max(used_qstr, qstrs[atom]) - atom = "\1" - counter[atom] += 1 - cb = huffman.codebook(counter.items()) + for toks in tokens.values(): + for tok in toks: + if is_qstr(tok): + used_qstr = max(used_qstr, qstrs[tok[1]]) + translation_qstr_bits = used_qstr.bit_length() - word_start = start_unused word_end = word_start + len(words) - 1 - f.write(f"// # words {len(words)}\n") - f.write(f"// words {words}\n") - - values = [] - length_count = {} - renumbered = 0 - last_length = None - canonical = {} - for atom, code in sorted(cb.items(), key=lambda x: (len(x[1]), x[0])): - if atom in qstr_strs: - atom = "\1" - values.append(atom) - length = len(code) - if length not in length_count: - length_count[length] = 0 - length_count[length] += 1 - if last_length: - renumbered <<= length - last_length - # print(f"atom={repr(atom)} code={code}", file=sys.stderr) - canonical[atom] = "{0:0{width}b}".format(renumbered, width=length) - if len(atom) > 1: - o = words.index(atom) + 0x80 - s = "".join(C_ESCAPES.get(ch1, ch1) for ch1 in atom) - f.write(f"// {o} {s} {counter[atom]} {canonical[atom]} {renumbered}\n") - else: - s = C_ESCAPES.get(atom, atom) - canonical[atom] = "{0:0{width}b}".format(renumbered, width=length) - o = ord(atom) - f.write(f"// {o} {s} {counter[atom]} {canonical[atom]} {renumbered}\n") - renumbered += 1 - last_length = length - lengths = bytearray() - f.write(f"// length count {length_count}\n") + word_code = {w: chr(word_start + i) for i, w in enumerate(words)} - for i in range(1, max(length_count) + 2): - lengths.append(length_count.get(i, 0)) - f.write(f"// values {values} lengths {len(lengths)} {lengths}\n") + def symbol_value(sym): + return ord(word_code.get(sym, sym)) - f.write(f"// {values} {lengths}\n") - values = [(atom if len(atom) == 1 else chr(0x80 + words.index(atom))) for atom in values] - max_translation_encoded_length = max( - len(translation.encode("utf-8")) for (original, translation) in translations - ) + nclasses = max(class_map) + 1 + values = [] + lengths_rows = [] + canonical = [] + for cls in range(nclasses): + # Symbols are ordered by (length, value) so that the C decoder's canonical + # walk lands on the same index. + table = lens.get(cls, {}) + by_value = {chr(symbol_value(s)): l for s, l in table.items()} + v, counts_row, canon = canonical_codes(by_value) + values.append([ord(x) for x in v]) + lengths_rows.append(counts_row) + canonical.append({s: canon[chr(symbol_value(s))] for s in table}) + lengths_row = max(1, max(len(r) for r in lengths_rows)) + lengths_rows = [r + [0] * (lengths_row - len(r)) for r in lengths_rows] + assert all(len(code) >= 1 for canon in canonical for code in canon.values()) + assert all(v < 0x100 for vs in values for v in vs) + + unmap = {v: k for k, v in remap.items()} + f.write(f"// # words {len(words)}\n") + f.write("// words {}\n".format([remap_text(w, unmap) for w in words])) + f.write(f"// # alphabet {len(alphabet)}\n") + f.write(f"// # rare chars by index {len(rare_idx_chars)}, raw {len(rare_raw_chars)}\n") + f.write(f"// class_map {class_map} tables {nclasses}\n") + for cls in range(nclasses): + f.write(f"// class {cls}: {len(values[cls])} symbols, lengths {lengths_rows[cls]}\n") maxlen = len(words[-1]) if words else 0 minlen = len(words[0]) if words else 0 wlencount = [len([None for w in words if len(w) == l]) for l in range(minlen, maxlen + 1)] - translation_qstr_bits = used_qstr.bit_length() - - f.write("typedef {} mchar_t;\n".format(values_type)) - f.write("const uint8_t lengths[] = {{ {} }};\n".format(", ".join(map(str, lengths)))) + f.write("#define compress_max_length_bits ({})\n".format(encoded_length_bits)) + f.write("#define TRANSLATION_CLASSES {}\n".format(nclasses)) + f.write("#define LENGTHS_ROW {}\n".format(lengths_row)) f.write( - "const mchar_t values[] = {{ {} }};\n".format( - ", ".join(str(ord(remove_offset(u))) for u in values) + "const uint8_t class_map[{}] = {{ {} }};\n".format( + NUM_BASE_CLASSES, ", ".join(map(str, class_map)) ) ) f.write( - "#define compress_max_length_bits ({})\n".format( - max_translation_encoded_length.bit_length() + "const uint8_t lengths[] = {{ {} }};\n".format( + ", ".join(str(x) for row in lengths_rows for x in row) ) ) + offsets = [0] + for v in values: + offsets.append(offsets[-1] + len(v)) f.write( - "const mchar_t words[] = {{ {} }};\n".format( - ", ".join(str(ord(remove_offset(c))) for w in words for c in w) + "const uint16_t values_offset[{}] = {{ {} }};\n".format( + nclasses + 1, ", ".join(map(str, offsets)) + ) + ) + f.write( + "const uint8_t values[] = {{ {} }};\n".format(", ".join(str(x) for v in values for x in v)) + ) + f.write("#define alphabet_size {}\n".format(len(alphabet))) + f.write( + "const uint16_t alphabet[] = {{ {} }};\n".format(", ".join(str(ord(c)) for c in alphabet)) + ) + f.write("#define rare_index_count {}\n".format(len(rare_idx_chars))) + f.write("#define rare_index_bits {}\n".format(rare_index_bits)) + f.write("#define rare_raw_count {}\n".format(len(rare_raw_chars))) + f.write( + "const uint16_t rare_chars[] = {{ {} }};\n".format( + ", ".join(str(ord(c)) for c in rare_idx_chars) + ) + ) + f.write( + "const uint8_t words[] = {{ {} }};\n".format( + ", ".join(str(ord(c)) for w in words for c in w) ) ) f.write("const uint8_t wlencount[] = {{ {} }};\n".format(", ".join(str(p) for p in wlencount))) @@ -410,30 +741,33 @@ def est_net_savings(s, occ): f.write("#define word_end {}\n".format(word_end)) f.write("#define minlen {}\n".format(minlen)) f.write("#define maxlen {}\n".format(maxlen)) - f.write("#define translation_offstart {}\n".format(offstart)) - f.write("#define translation_offset {}\n".format(offset)) f.write("#define translation_qstr_bits {}\n".format(translation_qstr_bits)) qstrs_inv = dict((v, k) for k, v in qstrs.items()) return EncodingTable( values, - lengths, - words, + lengths_rows, + lengths_row, + class_map, canonical, - extractor, - apply_offset, - remove_offset, + words, + word_start, + alphabet, + rare_idx_chars, + rare_index_bits, + remap, translation_qstr_bits, qstrs, qstrs_inv, + tokens, ) def decompress(encoding_table, encoded, encoded_length_bits): - qstrs_inv = encoding_table.qstrs_inv - values = encoding_table.values - lengths = encoding_table.lengths - words = encoding_table.words + """Decode as the C decoder does (translate.c). Returns the original text.""" + et = encoding_table + alphabet_size = len(et.alphabet) + word_end = et.word_start + len(et.words) - 1 def bititer(): for byte in encoded: @@ -449,10 +783,25 @@ def getnbits(n): return bits dec = [] + last = None length = getnbits(encoded_length_bits) + decoded = 0 + + def emit_char(c): + nonlocal last, decoded + dec.append(c) + decoded += len(c.encode("utf-8")) + last = c[-1] - i = 0 - while i < length: + def emit(u): + if ALPHABET_BASE <= u < ALPHABET_BASE + alphabet_size: + emit_char(et.alphabet[u - ALPHABET_BASE]) + else: + emit_char(chr(u)) + + while decoded < length: + cls = et.class_map[base_class(last)] + lengths = et.lengths[cls] bits = 0 bit_length = 0 max_code = lengths[0] @@ -461,28 +810,33 @@ def getnbits(n): bits = (bits << 1) | nextbit() bit_length += 1 if max_code > 0 and bits < max_code: - # print('{0:0{width}b}'.format(bits, width=bit_length)) break max_code = (max_code << 1) + lengths[bit_length] searched_length += lengths[bit_length] - - v = values[searched_length + bits - max_code] - if v == chr(1): - qstr_idx = getnbits(encoding_table.translation_qstr_bits) - v = qstrs_inv[qstr_idx] - elif v >= chr(0x80) and v < chr(0x80 + len(words)): - v = words[ord(v) - 0x80] - i += len(v.encode("utf-8")) - dec.append(v) + v = et.values[cls][searched_length + bits - max_code] + if v == 1: + qstr_idx = getnbits(et.translation_qstr_bits) + emit_char(et.qstrs_inv[qstr_idx]) + elif v == 2: + emit_char(et.rare_idx_chars[getnbits(et.rare_index_bits)]) + elif v == 3: + emit_char(chr(getnbits(16))) + elif et.word_start <= v <= word_end: + for c in et.words[v - et.word_start]: + emit(ord(c)) + else: + emit(v) return "".join(dec) def compress(encoding_table, decompressed, encoded_length_bits, len_translation_encoded): + """Encode a translation using the tokenization chosen in compute_huffman_coding().""" if not isinstance(decompressed, str): raise TypeError() - qstrs = encoding_table.qstrs - canonical = encoding_table.canonical - extractor = encoding_table.extractor + et = encoding_table + text = remap_text(decompressed, et.remap) + tokens = et.tokens[text] + unmap = {v: k for k, v in et.remap.items()} enc = 1 @@ -494,17 +848,25 @@ def put_bits(enc, b, n): enc = put_bit(enc, b & (1 << i)) return enc + def put_code(enc, cls, sym): + for b in et.canonical[cls][sym]: + enc = put_bit(enc, b == "1") + return enc + enc = put_bits(enc, len_translation_encoded, encoded_length_bits) - for atom in extractor.iter(decompressed): - if atom in qstrs: - can = canonical["\1"] - else: - can = canonical[atom] - for b in can: - enc = put_bit(enc, b == "1") - if atom in qstrs: - enc = put_bits(enc, qstrs[atom], encoding_table.translation_qstr_bits) + pos = 0 + for tok in tokens: + cls = et.class_map[base_class(text[pos - 1] if pos else None)] + enc = put_code(enc, cls, token_symbol(tok)) + if is_qstr(tok): + enc = put_bits(enc, et.qstrs[tok[1]], et.translation_qstr_bits) + elif is_rare(tok): + if ord(tok) >= RARE_RAW_BASE: + enc = put_bits(enc, ord(unmap[tok]), 16) + else: + enc = put_bits(enc, ord(tok) - RARE_IDX_BASE, et.rare_index_bits) + pos += token_len(tok) while enc.bit_length() % 8 != 1: enc = put_bit(enc, 0) @@ -527,11 +889,23 @@ def esc_char(m): def parse_qstrs(infile): r = {} - rx = re.compile(r'QDEF[01]\([A-Za-z0-9_]+,\s*\d+,\s*\d+,\s*(?P"(?:[^"\\\\]*|\\.)")\)') + rx = re.compile( + r'QDEF(?P[01])\([A-Za-z0-9_]+,\s*\d+,\s*\d+,\s*(?P"(?:[^"\\\\]|\\.)*")\)' + ) content = infile.read() - for i, mat in enumerate(rx.findall(content, re.M)): - mat = eval(mat) - r[mat] = i + matches = rx.finditer(content) + qdef0_qstrs = [] + qdef1_qstrs = [] + for match in matches: + qstr = eval(match.group("cstr")) + if match.group("pool") == "0": + qdef0_qstrs.append(qstr) + else: + qdef1_qstrs.append(qstr) + for i, qstr in enumerate(qdef0_qstrs): + r[qstr] = i + for i, qstr in enumerate(qdef1_qstrs, start=len(qdef0_qstrs)): + r[qstr] = i return r diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py index 307bfac1e9a..94321ef0bad 100644 --- a/py/makeversionhdr.py +++ b/py/makeversionhdr.py @@ -5,8 +5,6 @@ This script works with Python 3.7 and newer """ -from __future__ import print_function - import argparse import sys import os diff --git a/py/malloc.c b/py/malloc.c index fcf930ecfaa..5882a463323 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -54,9 +54,11 @@ // freely accessed - for interfacing with system and 3rd-party libs for // example. On the other hand, some (e.g. bare-metal) ports may use GC // heap as system heap, so, to avoid warnings, we do undef's first. -// CIRCUITPY-CHANGE: Add selective collect support to malloc to optimize GC for large buffers +#undef malloc #undef free #undef realloc +#define malloc(b) gc_alloc((b), false) +#define malloc_with_finaliser(b) gc_alloc((b), true) #define free gc_free #define realloc(ptr, n) gc_realloc(ptr, n, true) #define realloc_ext(ptr, n, mv) gc_realloc(ptr, n, mv) @@ -68,6 +70,7 @@ #error MICROPY_ENABLE_FINALISER requires MICROPY_ENABLE_GC #endif +// CIRCUITPY-CHANGE: Add selective collect support to malloc to optimize GC for large buffers #if MICROPY_ENABLE_SELECTIVE_COLLECT #error MICROPY_ENABLE_SELECTIVE_COLLECT requires MICROPY_ENABLE_GC #endif @@ -85,7 +88,7 @@ static void *realloc_ext(void *ptr, size_t n_bytes, bool allow_move) { #endif // MICROPY_ENABLE_GC -// CIRCUITPY-CHANGE: Add malloc helper with flags instead of a list of bools. +// CIRCUITPY-CHANGE: Add malloc helper to factor out flag handling and allow combinations. void *m_malloc_helper(size_t num_bytes, uint8_t flags) { void *ptr; #if MICROPY_ENABLE_GC @@ -112,7 +115,6 @@ void *m_malloc_helper(size_t num_bytes, uint8_t flags) { MP_STATE_MEM(current_bytes_allocated) += num_bytes; UPDATE_PEAK(); #endif - // CIRCUITPY-CHANGE // If this config is set then the GC clears all memory, so we don't need to. #if !MICROPY_GC_CONSERVATIVE_CLEAR if (flags & M_MALLOC_ENSURE_ZEROED) { @@ -124,26 +126,37 @@ void *m_malloc_helper(size_t num_bytes, uint8_t flags) { } void *m_malloc(size_t num_bytes) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: use helper return m_malloc_helper(num_bytes, M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT); } void *m_malloc_maybe(size_t num_bytes) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: use helper return m_malloc_helper(num_bytes, M_MALLOC_COLLECT); } +#if MICROPY_ENABLE_FINALISER +void *m_malloc_with_finaliser(size_t num_bytes) { + // CIRCUITPY-CHANGE: use helper + return m_malloc_helper(num_bytes, M_MALLOC_COLLECT | M_MALLOC_WITH_FINALISER); +} +#endif + void *m_malloc0(size_t num_bytes) { - return m_malloc_helper(num_bytes, M_MALLOC_ENSURE_ZEROED | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT); + // CIRCUITPY-CHANGE: use helper + return m_malloc_helper(num_bytes, + (MICROPY_GC_CONSERVATIVE_CLEAR ? 0 : M_MALLOC_ENSURE_ZEROED) + | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT); } +// CIRCUITPY-CHANGE: add selective collect void *m_malloc_without_collect(size_t num_bytes) { - // CIRCUITPY-CHANGE return m_malloc_helper(num_bytes, M_MALLOC_RAISE_ERROR); } +// CIRCUITPY-CHANGE: add selective collect void *m_malloc_maybe_without_collect(size_t num_bytes) { - // CIRCUITPY-CHANGE + return m_malloc_helper(num_bytes, 0); } @@ -224,6 +237,31 @@ void m_free(void *ptr) #if MICROPY_TRACKED_ALLOC +#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL +// If there's no GIL, use the GC recursive mutex to protect the tracked node linked list +// under m_tracked_head. +// +// (For ports with GIL, the expectation is to only call tracked alloc functions +// while holding the GIL.) + +static inline void m_tracked_node_lock(void) { + mp_thread_recursive_mutex_lock(&MP_STATE_MEM(gc_mutex), 1); +} + +static inline void m_tracked_node_unlock(void) { + mp_thread_recursive_mutex_unlock(&MP_STATE_MEM(gc_mutex)); +} + +#else + +static inline void m_tracked_node_lock(void) { +} + +static inline void m_tracked_node_unlock(void) { +} + +#endif + #define MICROPY_TRACKED_ALLOC_STORE_SIZE (!MICROPY_ENABLE_GC) typedef struct _m_tracked_node_t { @@ -235,8 +273,18 @@ typedef struct _m_tracked_node_t { uint8_t data[]; } m_tracked_node_t; +// Helper to get data size of a tracked node, abstracting MICROPY_TRACKED_ALLOC_STORE_SIZE. +static inline size_t get_tracked_node_size(m_tracked_node_t *node) { + #if MICROPY_TRACKED_ALLOC_STORE_SIZE + return node->size; + #else + return gc_nbytes(node) - sizeof(m_tracked_node_t); + #endif +} + #if MICROPY_DEBUG_VERBOSE static size_t m_tracked_count_links(size_t *nb) { + m_tracked_node_lock(); m_tracked_node_t *node = MP_STATE_VM(m_tracked_head); size_t n = 0; *nb = 0; @@ -249,6 +297,7 @@ static size_t m_tracked_count_links(size_t *nb) { #endif node = node->next; } + m_tracked_node_unlock(); return n; } #endif @@ -263,12 +312,14 @@ void *m_tracked_calloc(size_t nmemb, size_t size) { size_t n = m_tracked_count_links(&nb); DEBUG_printf("m_tracked_calloc(%u, %u) -> (%u;%u) %p\n", (int)nmemb, (int)size, (int)n, (int)nb, node); #endif + m_tracked_node_lock(); if (MP_STATE_VM(m_tracked_head) != NULL) { MP_STATE_VM(m_tracked_head)->prev = node; } node->prev = NULL; node->next = MP_STATE_VM(m_tracked_head); MP_STATE_VM(m_tracked_head) = node; + m_tracked_node_unlock(); #if MICROPY_TRACKED_ALLOC_STORE_SIZE node->size = nmemb * size; #endif @@ -278,6 +329,42 @@ void *m_tracked_calloc(size_t nmemb, size_t size) { return &node->data[0]; } +void *m_tracked_realloc(void *ptr_in, size_t n_bytes) { + // Handle pure allocation + if (ptr_in == NULL) { + return m_tracked_calloc(1, n_bytes); + } + + // Handle pure free + if (n_bytes == 0) { + m_tracked_free(ptr_in); + return NULL; + } + // To keep the implementation simple, we always allocate a new buffer and copy the old data into it. + // This could be optimised if faster performance or lower worst-case memory usage is required. + + // Get old size + // CIRCUITPY-CHANGE: cast to avoid compiler warning + m_tracked_node_t *old_node = (m_tracked_node_t *)(void *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t)); + size_t old_size = get_tracked_node_size(old_node); + + // Allocate new buffer + void *new_ptr = m_tracked_calloc(1, n_bytes); + if (new_ptr == NULL) { + // Allocation failed, return NULL but leave original pointer intact + return NULL; + } + + // Copy data (minimum of old and new size) + size_t copy_size = MIN(old_size, n_bytes); + memcpy(new_ptr, ptr_in, copy_size); + + // Free old buffer + m_tracked_free(ptr_in); + + return new_ptr; +} + void m_tracked_free(void *ptr_in) { if (ptr_in == NULL) { return; @@ -286,15 +373,12 @@ void m_tracked_free(void *ptr_in) { m_tracked_node_t *node = (m_tracked_node_t *)(void *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t)); #if MICROPY_DEBUG_VERBOSE size_t data_bytes; - #if MICROPY_TRACKED_ALLOC_STORE_SIZE - data_bytes = node->size; - #else - data_bytes = gc_nbytes(node); - #endif + data_bytes = get_tracked_node_size(node); size_t nb; size_t n = m_tracked_count_links(&nb); DEBUG_printf("m_tracked_free(%p, [%p, %p], nbytes=%u, links=%u;%u)\n", node, node->prev, node->next, (int)data_bytes, (int)n, (int)nb); - #endif + #endif // MICROPY_DEBUG_VERBOSE + m_tracked_node_lock(); if (node->next != NULL) { node->next->prev = node->prev; } @@ -303,6 +387,7 @@ void m_tracked_free(void *ptr_in) { } else { MP_STATE_VM(m_tracked_head) = node->next; } + m_tracked_node_unlock(); m_free(node #if MICROPY_MALLOC_USES_ALLOCATED_SIZE #if MICROPY_TRACKED_ALLOC_STORE_SIZE diff --git a/py/manifest.cmake b/py/manifest.cmake new file mode 100644 index 00000000000..446fb063b7e --- /dev/null +++ b/py/manifest.cmake @@ -0,0 +1,73 @@ +# Extract c_module() entries from MICROPY_FROZEN_MANIFEST and append them to +# USER_C_MODULES. Included from py/usermod.cmake; the port must have resolved +# MICROPY_FROZEN_MANIFEST (and any board-config default / cmake-command-line +# override) before usermod.cmake runs. +# +# Also sets default MICROPY_MANIFEST_* path variables that are forwarded to +# makemanifest.py here for c_module extraction and again from py/mkrules.cmake +# for the frozen content generation step, so both passes substitute the same +# values into manifest path expressions. + +if(MICROPY_FROZEN_MANIFEST) + # Set default path variables to be passed to makemanifest.py. These are + # available in path substitutions inside the manifest. Additional variables + # can be set per-board in mpconfigboard.cmake or on the cmake command line. + # MICROPY_LIB_DIR is set in py.cmake (included before usermod.cmake). + if(NOT DEFINED MICROPY_MANIFEST_PORT_DIR) + set(MICROPY_MANIFEST_PORT_DIR ${MICROPY_PORT_DIR}) + endif() + if(NOT DEFINED MICROPY_MANIFEST_BOARD_DIR) + set(MICROPY_MANIFEST_BOARD_DIR ${MICROPY_BOARD_DIR}) + endif() + if(NOT DEFINED MICROPY_MANIFEST_MPY_DIR) + set(MICROPY_MANIFEST_MPY_DIR ${MICROPY_DIR}) + endif() + if(NOT DEFINED MICROPY_MANIFEST_MPY_LIB_DIR) + set(MICROPY_MANIFEST_MPY_LIB_DIR ${MICROPY_LIB_DIR}) + endif() + + # Find all MICROPY_MANIFEST_* variables and turn them into command line + # arguments. Stored in MICROPY_MAKEMANIFEST_ARGS (outside the + # MICROPY_MANIFEST_ namespace) so it doesn't self-match the regex above + # on subsequent cmake configures. + get_cmake_property(_manifest_vars VARIABLES) + list(FILTER _manifest_vars INCLUDE REGEX "MICROPY_MANIFEST_.*") + set(MICROPY_MAKEMANIFEST_ARGS) + foreach(_manifest_var IN LISTS _manifest_vars) + list(APPEND MICROPY_MAKEMANIFEST_ARGS "-v") + string(REGEX REPLACE "MICROPY_MANIFEST_(.*)" "\\1" _manifest_var_name ${_manifest_var}) + list(APPEND MICROPY_MAKEMANIFEST_ARGS "${_manifest_var_name}=${${_manifest_var}}") + endforeach() + + # Skip extraction during UPDATE_SUBMODULES (require() would fail) and when + # micropython-lib is not initialised. Matches py/manifest.mk behaviour: + # warn and continue with an empty c_module list rather than fatal. + if(EXISTS ${MICROPY_FROZEN_MANIFEST} AND NOT UPDATE_SUBMODULES) + if(EXISTS ${MICROPY_LIB_DIR}/README.md) + if(NOT Python3_EXECUTABLE) + find_package(Python3 REQUIRED COMPONENTS Interpreter) + endif() + + execute_process( + COMMAND "${Python3_EXECUTABLE}" "${MICROPY_DIR}/tools/makemanifest.py" + --list-c-modules ${MICROPY_MAKEMANIFEST_ARGS} "${MICROPY_FROZEN_MANIFEST}" + OUTPUT_VARIABLE MANIFEST_C_MODULES + ERROR_VARIABLE MANIFEST_ERROR + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE MANIFEST_RESULT + ) + + if(NOT MANIFEST_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to extract C modules from manifest: ${MICROPY_FROZEN_MANIFEST}\nError: ${MANIFEST_ERROR}") + endif() + + if(MANIFEST_C_MODULES) + string(REPLACE "\n" ";" MANIFEST_C_MODULES_LIST "${MANIFEST_C_MODULES}") + list(APPEND USER_C_MODULES ${MANIFEST_C_MODULES_LIST}) + list(REMOVE_DUPLICATES USER_C_MODULES) + endif() + else() + message(WARNING "c_module() extraction skipped: micropython-lib not initialised, run 'make BOARD=${MICROPY_BOARD} submodules'") + endif() + endif() +endif() diff --git a/py/manifest.mk b/py/manifest.mk new file mode 100644 index 00000000000..43ad64be34e --- /dev/null +++ b/py/manifest.mk @@ -0,0 +1,58 @@ +# Manifest processing for freeze(), require(), include(), and c_module(). +# This file handles both C module extraction and frozen Python content generation. + +ifneq ($(FROZEN_MANIFEST),) + +# Set default path variables to be passed to makemanifest.py. These will be +# available in path substitutions. Additional variables can be set per-board +# in mpconfigboard.mk or on the make command line. +MICROPY_MANIFEST_PORT_DIR ?= $(CURDIR) +MICROPY_MANIFEST_BOARD_DIR ?= $(BOARD_DIR) +MICROPY_MANIFEST_MPY_DIR ?= $(TOP) +MICROPY_MANIFEST_MPY_LIB_DIR ?= $(MPY_LIB_DIR) + +# Find all MICROPY_MANIFEST_* variables and turn them into command line +# arguments. Values must not contain whitespace (GNU make word-splits). +MANIFEST_VARIABLES = $(foreach var,$(filter MICROPY_MANIFEST_%, $(.VARIABLES)),-v "$(subst MICROPY_MANIFEST_,,$(var))=$($(var))") + +# Skip c_module extraction for targets that don't need a build. +MANIFEST_NON_BUILD_GOALS := clean clean-prog submodules help print-cfg print-def +MANIFEST_GOALS := $(filter-out $(MANIFEST_NON_BUILD_GOALS),$(or $(MAKECMDGOALS),build)) + +# Extract C module paths up front so downstream rules see them. Skipped when +# micropython-lib isn't initialised (require() would fail) or for non-build +# targets. $(shell) collapses newlines, so c_module() paths cannot contain +# whitespace on the make side (the cmake side handles it correctly). +MANIFEST_C_MODULES := +ifneq ($(MANIFEST_GOALS),) +ifeq ($(wildcard $(FROZEN_MANIFEST)),$(FROZEN_MANIFEST)) +ifeq ($(wildcard $(MPY_LIB_DIR)/README.md),$(MPY_LIB_DIR)/README.md) +MANIFEST_C_MODULES := $(shell $(MAKE_MANIFEST) --list-c-modules $(MANIFEST_VARIABLES) $(FROZEN_MANIFEST)) +# Treat a populated, non-zero .SHELLSTATUS as failure. GNU make < 4.2 (eg +# macOS 3.81) leaves .SHELLSTATUS empty, in which case skip the check; an +# empty filter result means "succeed (status was 0, or unavailable)". +ifneq ($(filter-out 0,$(.SHELLSTATUS)),) +$(error makemanifest.py --list-c-modules failed (exit $(.SHELLSTATUS)) for $(FROZEN_MANIFEST)) +endif +else +$(warning c_module() extraction skipped: micropython-lib not initialised, run 'make submodules') +endif +endif +endif + +# Merge manifest c_modules into USER_C_MODULES. $(sort) also de-duplicates; +# this changes USER_C_MODULES iteration order vs cmake's list(REMOVE_DUPLICATES) +# which preserves first occurrence. Module include order should not be +# behaviour-sensitive so this is acceptable. +USER_C_MODULES := $(sort $(USER_C_MODULES) $(MANIFEST_C_MODULES)) + +# Frozen content rule, requires $(BUILD) and other variables from the port. +ifdef BUILD +# CIRCUITPY-CHANGE: FROZEN_MANIFEST is generated into $(BUILD) during the build +# (py/circuitpy_mpconfig.mk), so it must be a prerequisite here. +$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h $(BUILD)/genhdr/root_pointers.h $(FROZEN_MANIFEST) | $(MICROPY_MPYCROSS_DEPENDENCY) + $(Q)test -e "$(MPY_LIB_DIR)/README.md" || (echo -e $(HELP_MPY_LIB_SUBMODULE); false) + $(Q)$(MAKE_MANIFEST) -o $@ $(MANIFEST_VARIABLES) -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST) +endif + +endif # FROZEN_MANIFEST diff --git a/py/misc.h b/py/misc.h index 22f32147124..a7498e66d17 100644 --- a/py/misc.h +++ b/py/misc.h @@ -26,6 +26,9 @@ #ifndef MICROPY_INCLUDED_PY_MISC_H #define MICROPY_INCLUDED_PY_MISC_H +#include +#include "py/mpconfig.h" + // a mini library of useful types and functions /** types *******************************************************/ @@ -33,13 +36,25 @@ #include #include #include - -// CIRCUITPY-CHANGE: include directly instead of depending on previous includes -#include "mpconfig.h" +// CIRCUITPY-CHANGE: #ifdef instead of #if +#ifdef __cplusplus // Required on at least one compiler to get ULLONG_MAX +#include +#else +#include +#endif typedef unsigned char byte; typedef unsigned int uint; +#ifndef __has_builtin +#define __has_builtin(x) (0) +#endif +#ifndef __has_feature +// This macro is supported by Clang and gcc>=14 +#define __has_feature(x) (0) +#endif + + /** generic ops *************************************************/ #ifndef MIN @@ -54,6 +69,7 @@ typedef unsigned int uint; #define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x) // Static assertion macro +// CIRCUITPY-CHANGE: defined() #if defined(__cplusplus) #define MP_STATIC_ASSERT(cond) static_assert((cond), #cond) #elif __GNUC__ >= 5 || __STDC_VERSION__ >= 201112L @@ -70,6 +86,7 @@ typedef unsigned int uint; #if defined(_MSC_VER) || defined(__cplusplus) #define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)1) #else +// CIRCUITPY-CHANGE: defined() #if defined(__clang__) #pragma GCC diagnostic ignored "-Wgnu-folding-constant" #endif @@ -98,9 +115,9 @@ typedef unsigned int uint; #define m_new0(type, num) ((type *)(m_malloc0(sizeof(type) * (num)))) #define m_new_obj(type) (m_new(type, 1)) #define m_new_obj_maybe(type) (m_new_maybe(type, 1)) -#define m_new_obj_var(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc_helper(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num), M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT)) -#define m_new_obj_var0(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc_helper(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num), M_MALLOC_ENSURE_ZEROED | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT)) -#define m_new_obj_var_maybe(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc_helper(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num), M_MALLOC_COLLECT)) +#define m_new_obj_var(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num))) +#define m_new_obj_var0(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc0(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num))) +#define m_new_obj_var_maybe(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc_maybe(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num))) #if MICROPY_MALLOC_USES_ALLOCATED_SIZE #define m_renew(type, ptr, old_num, new_num) ((type *)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num)))) #define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type *)(m_realloc_maybe((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num), (allow_move)))) @@ -126,9 +143,13 @@ typedef unsigned int uint; void *m_malloc_helper(size_t num_bytes, uint8_t flags); void *m_malloc(size_t num_bytes); void *m_malloc_maybe(size_t num_bytes); +void *m_malloc_with_finaliser(size_t num_bytes); void *m_malloc0(size_t num_bytes); + +// CIRCUITPY-CHANGE: _without_collect void *m_malloc_without_collect(size_t num_bytes); void *m_malloc_maybe_without_collect(size_t num_bytes); + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes); void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move); @@ -138,12 +159,13 @@ void *m_realloc(void *ptr, size_t new_num_bytes); void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move); void m_free(void *ptr); #endif -NORETURN void m_malloc_fail(size_t num_bytes); +MP_NORETURN void m_malloc_fail(size_t num_bytes); #if MICROPY_TRACKED_ALLOC // These alloc/free functions track the pointers in a linked list so the GC does not reclaim // them. They can be used by code that requires traditional C malloc/free semantics. void *m_tracked_calloc(size_t nmemb, size_t size); +void *m_tracked_realloc(void *ptr_in, size_t n_bytes); void m_tracked_free(void *ptr_in); #endif @@ -161,7 +183,7 @@ size_t m_get_peak_bytes_allocated(void); // align ptr to the nearest multiple of "alignment" #define MP_ALIGN(ptr, alignment) (void *)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1)) -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: addition #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) /** unichar / UTF-8 *********************************************/ @@ -244,33 +266,31 @@ void vstr_add_byte(vstr_t *vstr, byte v); void vstr_add_char(vstr_t *vstr, unichar chr); void vstr_add_str(vstr_t *vstr, const char *str); void vstr_add_strn(vstr_t *vstr, const char *str, size_t len); -void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b); -void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr); +char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len); +static inline void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b) { + char *s = vstr_ins_blank_bytes(vstr, byte_pos, 1); + *s = b; +} +static inline void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr) { + // TODO UNICODE + char *s = vstr_ins_blank_bytes(vstr, char_pos, 1); + *s = (char)chr; +} +static inline void vstr_ins_strn(vstr_t *vstr, size_t byte_pos, const char *str, size_t len) { + char *s = vstr_ins_blank_bytes(vstr, byte_pos, len); + memcpy(s, str, len); +} void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut); void vstr_cut_tail_bytes(vstr_t *vstr, size_t bytes_to_cut); void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut); void vstr_printf(vstr_t *vstr, const char *fmt, ...); - -/** non-dynamic size-bounded variable buffer/string *************/ - -#define CHECKBUF(buf, max_size) char buf[max_size + 1]; size_t buf##_len = max_size; char *buf##_p = buf; -#define CHECKBUF_RESET(buf, max_size) buf##_len = max_size; buf##_p = buf; -#define CHECKBUF_APPEND(buf, src, src_len) \ - { size_t l = MIN(src_len, buf##_len); \ - memcpy(buf##_p, src, l); \ - buf##_len -= l; \ - buf##_p += l; } -#define CHECKBUF_APPEND_0(buf) { *buf##_p = 0; } -#define CHECKBUF_LEN(buf) (buf##_p - buf) - #ifdef va_start void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap); #endif -// Debugging helpers -int DEBUG_printf(const char *fmt, ...); +/** debugging helpers *******************************************/ -extern mp_uint_t mp_verbose_flag; +int DEBUG_printf(const char *fmt, ...); /** float internals *************/ @@ -308,6 +328,25 @@ typedef union _mp_float_union_t { mp_float_uint_t i; } mp_float_union_t; +#if MICROPY_FLOAT_FORMAT_IMPL == MICROPY_FLOAT_FORMAT_IMPL_EXACT + +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +// Exact float conversion requires using internally a bigger sort of floating point +typedef double mp_large_float_t; +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +typedef long double mp_large_float_t; +#endif +// Always use a 64 bit mantissa for formatting and parsing +typedef uint64_t mp_large_float_uint_t; + +#else // MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_EXACT + +// No bigger floating points +typedef mp_float_t mp_large_float_t; +typedef mp_float_uint_t mp_large_float_uint_t; + +#endif + #endif // MICROPY_PY_BUILTINS_FLOAT /** ROM string compression *************/ @@ -405,34 +444,30 @@ static inline uint32_t mp_ctz(uint32_t x) { return _BitScanForward(&tz, x) ? tz : 0; } -// Workaround for 'warning C4127: conditional expression is constant'. -static inline bool mp_check(bool value) { - return value; -} - static inline uint32_t mp_popcount(uint32_t x) { return __popcnt(x); } -#else +#else // _MSC_VER #define mp_clz(x) __builtin_clz(x) #define mp_clzl(x) __builtin_clzl(x) #define mp_clzll(x) __builtin_clzll(x) #define mp_ctz(x) __builtin_ctz(x) -#define mp_check(x) (x) -#if defined __has_builtin #if __has_builtin(__builtin_popcount) #define mp_popcount(x) __builtin_popcount(x) -#endif -#endif -#if !defined(mp_popcount) +#else static inline uint32_t mp_popcount(uint32_t x) { x = x - ((x >> 1) & 0x55555555); x = (x & 0x33333333) + ((x >> 2) & 0x33333333); x = (x + (x >> 4)) & 0x0F0F0F0F; - return x * 0x01010101; + return (x * 0x01010101) >> 24; } -#endif -#endif +#endif // __has_builtin(__builtin_popcount) +#endif // _MSC_VER + +#define MP_FIT_UNSIGNED(bits, value) (((value) & (~0U << (bits))) == 0) +#define MP_FIT_SIGNED(bits, value) \ + (MP_FIT_UNSIGNED(((bits) - 1), (value)) || \ + (((value) & (~0U << ((bits) - 1))) == (~0U << ((bits) - 1)))) // mp_int_t can be larger than long, i.e. Windows 64-bit, nan-box variants static inline uint32_t mp_clz_mpi(mp_int_t x) { @@ -448,16 +483,133 @@ static inline uint32_t mp_clz_mpi(mp_int_t x) { } return zeroes; #else - MP_STATIC_ASSERT(sizeof(mp_int_t) == sizeof(long long) - || sizeof(mp_int_t) == sizeof(long)); + #if MP_INT_MAX == INT_MAX + return mp_clz((unsigned)x); + #elif MP_INT_MAX == LONG_MAX + return mp_clzl((unsigned long)x); + #elif MP_INT_MAX == LLONG_MAX + return mp_clzll((unsigned long long)x); + #else + #error Unexpected MP_INT_MAX value + #endif + #endif +} + +// Overflow-checked operations + +// Integer overflow builtins were added to GCC 5, but __has_builtin only in GCC 10 +// +// Note that the builtins has a defined result when overflow occurs, whereas the custom +// functions below don't update the result if an overflow would occur (to avoid UB). +#define MP_GCC_HAS_BUILTIN_OVERFLOW (__GNUC__ >= 5) + +#if MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC - // ugly, but should compile to single intrinsic unless O0 is set - if (mp_check(sizeof(mp_int_t) == sizeof(long))) { - return mp_clzl((unsigned long)x); +#define mp_mul_ull_overflow __builtin_umulll_overflow +#define mp_mul_ll_overflow __builtin_smulll_overflow +static inline bool mp_mul_mp_int_t_overflow(mp_int_t x, mp_int_t y, mp_int_t *res) { + // __builtin_mul_overflow is a type-generic function, this inline ensures the argument + // types are checked to match mp_int_t. + return __builtin_mul_overflow(x, y, res); +} + +#else + +bool mp_mul_ll_overflow(long long int x, long long int y, long long int *res); +bool mp_mul_mp_int_t_overflow(mp_int_t x, mp_int_t y, mp_int_t *res); +static inline bool mp_mul_ull_overflow(unsigned long long int x, unsigned long long int y, unsigned long long int *res) { + if (y > 0 && x > (ULLONG_MAX / y)) { + return true; // overflow + } + *res = x * y; + return false; +} + +#endif + +#if __has_builtin(__builtin_saddll_overflow) || MP_GCC_HAS_BUILTIN_OVERFLOW +#define mp_add_ll_overflow __builtin_saddll_overflow +#else +static inline bool mp_add_ll_overflow(long long int lhs, long long int rhs, long long int *res) { + bool overflow; + + if (rhs > 0) { + overflow = (lhs > LLONG_MAX - rhs); } else { - return mp_clzll((unsigned long long)x); + overflow = (lhs < LLONG_MIN - rhs); } - #endif + + if (!overflow) { + *res = lhs + rhs; + } + + return overflow; } +#endif + +#if __has_builtin(__builtin_ssubll_overflow) || MP_GCC_HAS_BUILTIN_OVERFLOW +#define mp_sub_ll_overflow __builtin_ssubll_overflow +#else +static inline bool mp_sub_ll_overflow(long long int lhs, long long int rhs, long long int *res) { + bool overflow; + + if (rhs > 0) { + overflow = (lhs < LLONG_MIN + rhs); + } else { + overflow = (lhs > LLONG_MAX + rhs); + } + + if (!overflow) { + *res = lhs - rhs; + } + + return overflow; +} +#endif + + +// Helper macros for detecting if sanitizers are enabled +// +// Use sparingly, not for masking issues reported by sanitizers! +// +// Can be detected automatically in Clang and gcc>=14, need to be +// set manually otherwise. +#ifndef MP_UBSAN +#define MP_UBSAN __has_feature(undefined_behavior_sanitizer) +#endif + +#ifndef MP_ASAN +#define MP_ASAN __has_feature(address_sanitizer) +#endif + +#ifndef MP_SANITIZER_BUILD +#define MP_SANITIZER_BUILD (MP_UBSAN || MP_ASAN) +#endif + +// halfword/word/longword swapping macros + +#if __has_builtin(__builtin_bswap16) +#define MP_BSWAP16(x) __builtin_bswap16(x) +#else +#define MP_BSWAP16(x) ((uint16_t)((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF))) +#endif + +#if __has_builtin(__builtin_bswap32) +#define MP_BSWAP32(x) __builtin_bswap32(x) +#else +#define MP_BSWAP32(x) \ + ((uint32_t)((((x) & 0xFF) << 24) | (((x) & 0xFF00) << 8) | \ + (((x) >> 8) & 0xFF00) | (((x) >> 24) & 0xFF))) +#endif + +#if __has_builtin(__builtin_bswap64) +#define MP_BSWAP64(x) __builtin_bswap64(x) +#else +#define MP_BSWAP64(x) \ + ((uint64_t)((((x) & 0xFF) << 56) | (((x) & 0xFF00) << 40) | \ + (((x) & 0xFF0000) << 24) | (((x) & 0xFF000000) << 8) | \ + (((x) >> 8) & 0xFF000000) | (((x) >> 24) & 0xFF0000) | \ + (((x) >> 40) & 0xFF00) | (((x) >> 56) & 0xFF))) +#endif #endif // MICROPY_INCLUDED_PY_MISC_H diff --git a/py/mkrules.cmake b/py/mkrules.cmake index 4374b8b4da3..0903f81d897 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -14,6 +14,9 @@ set(MICROPY_MODULEDEFS "${MICROPY_GENHDR_DIR}/moduledefs.h") set(MICROPY_ROOT_POINTERS_SPLIT "${MICROPY_GENHDR_DIR}/root_pointers.split") set(MICROPY_ROOT_POINTERS_COLLECTED "${MICROPY_GENHDR_DIR}/root_pointers.collected") set(MICROPY_ROOT_POINTERS "${MICROPY_GENHDR_DIR}/root_pointers.h") +set(MICROPY_COMPRESSED_SPLIT "${MICROPY_GENHDR_DIR}/compressed.split") +set(MICROPY_COMPRESSED_COLLECTED "${MICROPY_GENHDR_DIR}/compressed.collected") +set(MICROPY_COMPRESSED_DATA "${MICROPY_GENHDR_DIR}/compressed.data.h") if(NOT MICROPY_PREVIEW_VERSION_2) set(MICROPY_PREVIEW_VERSION_2 0) @@ -32,6 +35,13 @@ if(MICROPY_BOARD) ) endif() +# Need to do this before extracting MICROPY_CPP_DEF below. +if(MICROPY_ROM_TEXT_COMPRESSION) + target_compile_definitions(${MICROPY_TARGET} PUBLIC + MICROPY_ROM_TEXT_COMPRESSION=\(1\) + ) +endif() + # Need to do this before extracting MICROPY_CPP_DEF below. Rest of frozen # manifest handling is at the end of this file. if(MICROPY_FROZEN_MANIFEST) @@ -84,6 +94,18 @@ target_sources(${MICROPY_TARGET} PRIVATE ${MICROPY_ROOT_POINTERS} ) +if(MICROPY_ROM_TEXT_COMPRESSION) + target_sources(${MICROPY_TARGET} PRIVATE + ${MICROPY_COMPRESSED_DATA} + ) +endif() + +# Ensure genhdr directory is removed on clean + +set_property(TARGET ${MICROPY_TARGET} APPEND PROPERTY ADDITIONAL_CLEAN_FILES + "${MICROPY_GENHDR_DIR}" +) + # Command to force the build of another command # Generate mpversion.h @@ -197,20 +219,53 @@ add_custom_command( DEPENDS ${MICROPY_ROOT_POINTERS_COLLECTED} ${MICROPY_PY_DIR}/make_root_pointers.py ) +# Generate compressed.data.h + +add_custom_command( + OUTPUT ${MICROPY_COMPRESSED_SPLIT} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py split compress ${MICROPY_QSTRDEFS_LAST} ${MICROPY_GENHDR_DIR}/compress _ + COMMAND touch ${MICROPY_COMPRESSED_SPLIT} + DEPENDS ${MICROPY_QSTRDEFS_LAST} + VERBATIM + COMMAND_EXPAND_LISTS +) + +add_custom_command( + OUTPUT ${MICROPY_COMPRESSED_COLLECTED} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py cat compress _ ${MICROPY_GENHDR_DIR}/compress ${MICROPY_COMPRESSED_COLLECTED} + BYPRODUCTS "${MICROPY_COMPRESSED_COLLECTED}.hash" + DEPENDS ${MICROPY_COMPRESSED_SPLIT} + VERBATIM + COMMAND_EXPAND_LISTS +) + +add_custom_command( + OUTPUT ${MICROPY_COMPRESSED_DATA} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makecompresseddata.py ${MICROPY_COMPRESSED_COLLECTED} > ${MICROPY_COMPRESSED_DATA} + DEPENDS ${MICROPY_COMPRESSED_COLLECTED} ${MICROPY_PY_DIR}/makecompresseddata.py +) + # Build frozen code if enabled if(MICROPY_FROZEN_MANIFEST) set(MICROPY_FROZEN_CONTENT "${CMAKE_BINARY_DIR}/frozen_content.c") + set_property(TARGET ${MICROPY_TARGET} APPEND PROPERTY ADDITIONAL_CLEAN_FILES + "${CMAKE_BINARY_DIR}/frozen_mpy" + ) + target_sources(${MICROPY_TARGET} PRIVATE ${MICROPY_FROZEN_CONTENT} ) # Note: target_compile_definitions already added earlier. - if(NOT MICROPY_LIB_DIR) + # Ensure micropython-lib is included in submodule updates, but only when + # MICROPY_LIB_DIR points at the in-tree submodule location; a user + # overriding MICROPY_LIB_DIR to an out-of-tree checkout shouldn't have + # the submodule updated. + if(MICROPY_LIB_DIR STREQUAL "${MICROPY_DIR}/lib/micropython-lib") list(APPEND GIT_SUBMODULES lib/micropython-lib) - set(MICROPY_LIB_DIR ${MICROPY_DIR}/lib/micropython-lib) endif() if(NOT UPDATE_SUBMODULES AND NOT EXISTS ${MICROPY_LIB_DIR}/README.md) @@ -226,9 +281,13 @@ if(MICROPY_FROZEN_MANIFEST) if(NOT MICROPY_MAKE_EXECUTABLE) set(MICROPY_MAKE_EXECUTABLE make) endif() + # Clear FROZEN_MANIFEST/USER_C_MODULES in the mpy-cross sub-make so a + # shell-env FROZEN_MANIFEST=... doesn't leak in and trigger + # manifest.mk against the wrong cwd. mkrules.mk does the same for the + # make-based port path. add_custom_command( OUTPUT ${MICROPY_MPYCROSS_DEPENDENCY} - COMMAND ${MICROPY_MAKE_EXECUTABLE} -C ${MICROPY_DIR}/mpy-cross USER_C_MODULES= + COMMAND ${MICROPY_MAKE_EXECUTABLE} -C ${MICROPY_DIR}/mpy-cross USER_C_MODULES= FROZEN_MANIFEST= ) endif() @@ -238,27 +297,13 @@ if(MICROPY_FROZEN_MANIFEST) set(MICROPY_CROSS_FLAGS "-f${MICROPY_CROSS_FLAGS}") endif() - # Set default path variables to be passed to makemanifest.py. These will - # be available in path substitutions. Additional variables can be set - # per-board in mpconfigboard.cmake. - set(MICROPY_MANIFEST_PORT_DIR ${MICROPY_PORT_DIR}) - set(MICROPY_MANIFEST_BOARD_DIR ${MICROPY_BOARD_DIR}) - set(MICROPY_MANIFEST_MPY_DIR ${MICROPY_DIR}) - set(MICROPY_MANIFEST_MPY_LIB_DIR ${MICROPY_LIB_DIR}) - - # Find all MICROPY_MANIFEST_* variables and turn them into command line arguments. - get_cmake_property(_manifest_vars VARIABLES) - list(FILTER _manifest_vars INCLUDE REGEX "MICROPY_MANIFEST_.*") - foreach(_manifest_var IN LISTS _manifest_vars) - list(APPEND _manifest_var_args "-v") - string(REGEX REPLACE "MICROPY_MANIFEST_(.*)" "\\1" _manifest_var_name ${_manifest_var}) - list(APPEND _manifest_var_args "${_manifest_var_name}=${${_manifest_var}}") - endforeach() - + # MICROPY_MAKEMANIFEST_ARGS is populated by py/manifest.cmake (included via + # py/usermod.cmake before this file). Reuse that list so both the c_module + # extraction pass and the frozen content step substitute the same values. add_custom_target( BUILD_FROZEN_CONTENT ALL BYPRODUCTS ${MICROPY_FROZEN_CONTENT} - COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} ${_manifest_var_args} -b "${CMAKE_BINARY_DIR}" ${MICROPY_CROSS_FLAGS} --mpy-tool-flags=${MICROPY_MPY_TOOL_FLAGS} ${MICROPY_FROZEN_MANIFEST} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} ${MICROPY_MAKEMANIFEST_ARGS} -b "${CMAKE_BINARY_DIR}" ${MICROPY_CROSS_FLAGS} --mpy-tool-flags=${MICROPY_MPY_TOOL_FLAGS} ${MICROPY_FROZEN_MANIFEST} DEPENDS ${MICROPY_QSTRDEFS_GENERATED} ${MICROPY_ROOT_POINTERS} diff --git a/py/mkrules.mk b/py/mkrules.mk index f364297f0f2..fe4bf9a3d16 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -11,6 +11,7 @@ ifeq ($(MICROPY_PREVIEW_VERSION_2),1) CFLAGS += -DMICROPY_PREVIEW_VERSION_2=1 endif +# CIRCUITPY-CHANGE: point to CircuitPython documentation HELP_BUILD_ERROR ?= "See \033[1;31mhttps://learn.adafruit.com/building-circuitpython; Adafruit Discord \#circuitpython-dev\033[0m" HELP_MPY_LIB_SUBMODULE ?= "\033[1;31mError: micropython-lib submodule is not initialized.\033[0m Run 'make submodules'" @@ -38,10 +39,24 @@ CFLAGS += -DMICROPY_BOARD_BUILD_NAME=\"$(BOARD)-$(BOARD_VARIANT)\" endif endif +# Add default C++ compiler flags based on CFLAGS. For use with C++ user modules. +# CIRCUITPY-CHANGE: CircuitPython enables C-only warnings that g++ rejects, in +# py/circuitpy_defns.mk and in the port Makefiles, so strip those too. +CXXFLAGS += $(filter-out -std=c11 -std=c99 -std=gnu11 -std=gnu99 -Werror-implicit-function-declaration -Werror=missing-prototypes -Werror=old-style-definition -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wstrict-prototypes,$(CFLAGS) $(CXXFLAGS_MOD)) + +# Add LDFLAGS to link libstdc++ on bare metal ports. Added only if a port has +# -nostdlib in LDFLAGS and C++ source files are provided. +ifneq ($(findstring nostdlib,"$(LDFLAGS)"),) +ifneq ($(SRC_CXX)$(SRC_USERMOD_CXX)$(SRC_USERMOD_LIB_CXX),) +LIBSTDCPP_FILE_NAME = "$(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a)" +LDFLAGS += -L"$(shell dirname $(LIBSTDCPP_FILE_NAME))" +endif +endif + # QSTR generation uses the same CFLAGS, with these modifications. QSTR_GEN_FLAGS = -DNO_QSTR # Note: := to force evaluation immediately. -QSTR_GEN_CFLAGS := $(CFLAGS) +QSTR_GEN_CFLAGS := $(filter-out -g%,$(CFLAGS)) QSTR_GEN_CFLAGS += $(QSTR_GEN_FLAGS) QSTR_GEN_CXXFLAGS := $(CXXFLAGS) QSTR_GEN_CXXFLAGS += $(QSTR_GEN_FLAGS) @@ -62,13 +77,13 @@ QSTR_GEN_CXXFLAGS += $(QSTR_GEN_FLAGS) # can be located. By following this scheme, it allows a single build rule # to be used to compile all .c files. +vpath %.S . $(TOP) $(USER_C_MODULES) $(USERMOD_DIR_PARENTS) # CIRCUITPY-CHANGE: use STEPECHO -vpath %.S . $(TOP) $(USER_C_MODULES) $(BUILD)/%.o: %.S $(STEPECHO) "CC $<" $(Q)$(CC) $(CFLAGS) -c -o $@ $< -vpath %.s . $(TOP) $(USER_C_MODULES) +vpath %.s . $(TOP) $(USER_C_MODULES) $(USERMOD_DIR_PARENTS) $(BUILD)/%.o: %.s $(STEPECHO) "AS $<" $(Q)$(AS) $(AFLAGS) -o $@ $< @@ -99,11 +114,11 @@ $(Q)$(CXX) $(CXXFLAGS) -c -MD -MF $(@:.o=.d) -o $@ $< || (echo -e $(HELP_BUILD_E endef # CIRCUITPY-CHANGE: add $(BUILD) -vpath %.c . $(TOP) $(USER_C_MODULES) $(BUILD) +vpath %.c . $(TOP) $(USER_C_MODULES) $(USERMOD_DIR_PARENTS) $(BUILD) $(BUILD)/%.o: %.c $(call compile_c) -vpath %.cpp . $(TOP) $(USER_C_MODULES) +vpath %.cpp . $(TOP) $(USER_C_MODULES) $(USERMOD_DIR_PARENTS) $(BUILD)/%.o: %.cpp $(call compile_cxx) @@ -112,6 +127,14 @@ $(BUILD)/%.pp: %.c $(STEPECHO) "PreProcess $<" $(Q)$(CPP) $(CFLAGS) -Wp,-C,-dD,-dI -o $@ $< +.PHONY: $(BUILD)/%.sz +$(BUILD)/%.sz: $(BUILD)/%.o + $(Q)$(SIZE) $< + +# Special case for compiling auto-generated source files. +$(BUILD)/%.o: $(BUILD)/%.c + $(call compile_c) + # The following rule uses | to create an order only prerequisite. Order only # prerequisites only get built if they don't exist. They don't cause timestamp # checking to be performed. @@ -179,7 +202,7 @@ $(HEADER_BUILD)/compressed.collected: $(HEADER_BUILD)/compressed.split # will be created if they don't exist. OBJ_DIRS = $(sort $(dir $(OBJ))) $(OBJ): | $(OBJ_DIRS) -// CIRCUITPY-CHANGE: use $(Q) +# CIRCUITPY-CHANGE: use $(Q) $(OBJ_DIRS): $(Q)$(MKDIR) -p $@ @@ -187,9 +210,12 @@ $(HEADER_BUILD): $(Q)$(MKDIR) -p $@ ifneq ($(MICROPY_MPYCROSS_DEPENDENCY),) -# to automatically build mpy-cross, if needed +# Build mpy-cross automatically if needed. Clear USER_C_MODULES and +# FROZEN_MANIFEST so a port build with either set doesn't leak them into the +# mpy-cross sub-make and cause manifest.mk there to parse the port's manifest +# from the wrong cwd. $(MICROPY_MPYCROSS_DEPENDENCY): - $(MAKE) -C "$(abspath $(dir $@)..)" USER_C_MODULES= + $(MAKE) -C "$(abspath $(dir $@)..)" USER_C_MODULES= FROZEN_MANIFEST= endif ifneq ($(FROZEN_DIR),) @@ -211,12 +237,6 @@ endif CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY CFLAGS += -DMICROPY_MODULE_FROZEN_STR - -# CIRCUITPY-CHANGE: FROZEN_MANIFEST is constructed at build time -# to build frozen_content.c from a manifest -$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h $(BUILD)/genhdr/root_pointers.h $(FROZEN_MANIFEST) | $(MICROPY_MPYCROSS_DEPENDENCY) - $(Q)test -e "$(MPY_LIB_DIR)/README.md" || (echo -e $(HELP_MPY_LIB_SUBMODULE); false) - $(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST) endif ifneq ($(PROG),) @@ -235,7 +255,7 @@ $(BUILD)/$(PROG): $(OBJ) $(ECHO) "LINK $@" # Do not pass COPT here - it's *C* compiler optimizations. For example, # we may want to compile using Thumb, but link with non-Thumb libc. - $(Q)$(CC) -o $@ $^ $(LIB) $(LDFLAGS) + $(Q)$(CC) -o $@ $^ $(LIBS) $(LDFLAGS) ifndef DEBUG ifdef STRIP $(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $@ @@ -260,7 +280,7 @@ submodules: $(ECHO) "Updating submodules: $(GIT_SUBMODULES)" ifneq ($(GIT_SUBMODULES),) $(Q)cd $(TOP) && git submodule sync $(GIT_SUBMODULES) - $(Q)cd $(TOP) && git submodule update --init --filter=blob:none $(GIT_SUBMODULES) || \ + $(Q)cd $(TOP) && git submodule update --init --filter=blob:none $(GIT_SUBMODULES) 2>/dev/null || \ git submodule update --init $(GIT_SUBMODULES) endif .PHONY: submodules diff --git a/py/modbuiltins.c b/py/modbuiltins.c index cdeacc25f71..327783996fb 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -138,7 +138,7 @@ static mp_obj_t mp_builtin_chr(mp_obj_t o_in) { #if MICROPY_PY_BUILTINS_STR_UNICODE mp_uint_t c = mp_obj_get_int(o_in); if (c >= 0x110000) { - mp_raise_ValueError(MP_ERROR_TEXT("chr() arg not in range(0x110000)")); + mp_raise_ValueError(MP_ERROR_TEXT("char not in range(0x110000)")); } VSTR_FIXED(buf, 4); vstr_add_char(&buf, c); @@ -155,6 +155,7 @@ static mp_obj_t mp_builtin_chr(mp_obj_t o_in) { } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr); +#if MICROPY_PY_BUILTINS_DIR static mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { mp_obj_t dir = mp_obj_new_list(0, NULL); if (n_args == 0) { @@ -188,6 +189,7 @@ static mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { return dir; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir); +#endif static mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) { return mp_binary_op(MP_BINARY_OP_DIVMOD, o1_in, o2_in); @@ -366,18 +368,21 @@ static mp_obj_t mp_builtin_ord(mp_obj_t o_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord); static mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) { - switch (n_args) { - case 2: - return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]); - default: - #if !MICROPY_PY_BUILTINS_POW3 - mp_raise_NotImplementedError(MP_ERROR_TEXT("3-arg pow() not supported")); - #elif MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_MPZ - return mp_binary_op(MP_BINARY_OP_MODULO, mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]), args[2]); - #else - return mp_obj_int_pow3(args[0], args[1], args[2]); - #endif + // Treat pow(x, y, None) as pow(x, y), matching CPython. + if (n_args == 2 + #if MICROPY_PY_BUILTINS_POW3 + || args[2] == mp_const_none + #endif + ) { + return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]); } + #if !MICROPY_PY_BUILTINS_POW3 + mp_raise_NotImplementedError(MP_ERROR_TEXT("3-arg pow() not supported")); + #elif MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_MPZ + return mp_binary_op(MP_BINARY_OP_MODULO, mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]), args[2]); + #else + return mp_obj_int_pow3(args[0], args[1], args[2]); + #endif } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow); @@ -607,6 +612,9 @@ MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_builtin_locals); // These are defined in terms of MicroPython API functions right away MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_obj_id); MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len); +#if MICROPY_PY_TSTRINGS +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___template___obj, 1, MP_OBJ_FUN_ARGS_MAX, mp_obj_new_template); +#endif static const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_builtins) }, @@ -615,6 +623,9 @@ static const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___build_class__), MP_ROM_PTR(&mp_builtin___build_class___obj) }, { MP_ROM_QSTR(MP_QSTR___import__), MP_ROM_PTR(&mp_builtin___import___obj) }, { MP_ROM_QSTR(MP_QSTR___repl_print__), MP_ROM_PTR(&mp_builtin___repl_print___obj) }, + #if MICROPY_PY_TSTRINGS + { MP_ROM_QSTR(MP_QSTR___template__), MP_ROM_PTR(&mp_builtin___template___obj) }, + #endif // built-in types { MP_ROM_QSTR(MP_QSTR_bool), MP_ROM_PTR(&mp_type_bool) }, @@ -686,7 +697,9 @@ static const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR_delattr), MP_ROM_PTR(&mp_builtin_delattr_obj) }, #endif + #if MICROPY_PY_BUILTINS_DIR { MP_ROM_QSTR(MP_QSTR_dir), MP_ROM_PTR(&mp_builtin_dir_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_divmod), MP_ROM_PTR(&mp_builtin_divmod_obj) }, #if MICROPY_PY_BUILTINS_EVAL_EXEC { MP_ROM_QSTR(MP_QSTR_eval), MP_ROM_PTR(&mp_builtin_eval_obj) }, diff --git a/py/modio.c b/py/modio.c index d3e563dbcf4..fdee484376f 100644 --- a/py/modio.c +++ b/py/modio.c @@ -63,6 +63,10 @@ static mp_uint_t iobase_read_write(mp_obj_t obj, void *buf, mp_uint_t size, int } mp_int_t ret = mp_obj_get_int(ret_obj); if (ret >= 0) { + if ((mp_uint_t)ret > size) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } return ret; } else { *errcode = -ret; @@ -169,12 +173,13 @@ static mp_obj_t bufwriter_flush(mp_obj_t self_in) { int err; mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err); (void)out_sz; - // TODO: try to recover from a case of non-blocking stream, e.g. move - // remaining chunk to the beginning of buffer. - assert(out_sz == self->len); - self->len = 0; if (err != 0) { mp_raise_OSError(err); + } else { + // TODO: try to recover from a case of non-blocking stream, e.g. move + // remaining chunk to the beginning of buffer. + assert(out_sz == self->len); + self->len = 0; } } diff --git a/py/modmath.c b/py/modmath.c index 2b41bbcd7d1..2a9ed1b7f22 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -37,7 +37,7 @@ #define MP_PI_4 MICROPY_FLOAT_CONST(0.78539816339744830962) #define MP_3_PI_4 MICROPY_FLOAT_CONST(2.35619449019234492885) -static NORETURN void math_error(void) { +static MP_NORETURN void math_error(void) { mp_raise_ValueError(MP_ERROR_TEXT("math domain error")); } @@ -99,12 +99,16 @@ mp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) { MATH_FUN_1(sqrt, sqrt) // pow(x, y): returns x to the power of y #if MICROPY_PY_MATH_POW_FIX_NAN -mp_float_t pow_func(mp_float_t x, mp_float_t y) { +mp_float_t MICROPY_FLOAT_C_FUN(pow_func)(mp_float_t x, mp_float_t y) { // pow(base, 0) returns 1 for any base, even when base is NaN // pow(+1, exponent) returns 1 for any exponent, even when exponent is NaN if (x == MICROPY_FLOAT_CONST(1.0) || y == MICROPY_FLOAT_CONST(0.0)) { return MICROPY_FLOAT_CONST(1.0); } + // pow(base, NaN) returns NaN for any other value of base + if (isnan(y)) { + return y; + } return MICROPY_FLOAT_C_FUN(pow)(x, y); } MATH_FUN_2(pow, pow_func) @@ -161,6 +165,11 @@ MATH_FUN_2(atan2, atan2) MATH_FUN_1_TO_INT(ceil, ceil) // copysign(x, y) static mp_float_t MICROPY_FLOAT_C_FUN(copysign_func)(mp_float_t x, mp_float_t y) { + #if MICROPY_PY_MATH_COPYSIGN_FIX_NAN + if (isnan(y)) { + y = 0.0; + } + #endif return MICROPY_FLOAT_C_FUN(copysign)(x, y); } MATH_FUN_2(copysign, copysign_func) diff --git a/py/modmicropython.c b/py/modmicropython.c index ff25af8ff7e..5e1b3253427 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -100,7 +100,7 @@ static mp_obj_t mp_micropython_qstr_info(size_t n_args, const mp_obj_t *args) { size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); mp_printf(&mp_plat_print, "qstr pool: n_pool=%u, n_qstr=%u, n_str_data_bytes=%u, n_total_bytes=%u\n", - n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + (uint)n_pool, (uint)n_qstr, (uint)n_str_data_bytes, (uint)n_total_bytes); if (n_args == 1) { // arg given means dump qstr data qstr_dump_data(); @@ -163,13 +163,35 @@ static MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd #endif #if MICROPY_ENABLE_SCHEDULER + +#if MICROPY_KBD_EXCEPTION && MICROPY_SCHEDULER_STATIC_NODES +static mp_sched_node_t mp_keyboard_interrupt_sched_node; +static void mp_sched_keyboard_interrupt_wrapper(mp_sched_node_t *node) { + mp_sched_keyboard_interrupt(); +} +#endif + static mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { + #if MICROPY_KBD_EXCEPTION + if (function == MP_OBJ_FROM_PTR(&mp_micropython_kbd_intr_obj)) { + #if MICROPY_SCHEDULER_STATIC_NODES + // Allow calling `micropython.schedule(micropython.kbd_intr, None)` as a + // special case to schedule a keyboard interrupt. + mp_sched_schedule_node(&mp_keyboard_interrupt_sched_node, mp_sched_keyboard_interrupt_wrapper); + return mp_const_none; + #else + // Signal that passing `micropython.kbd_intr` is not supported. + mp_raise_ValueError(NULL); + #endif + } + #endif if (!mp_sched_schedule(function, arg)) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("schedule queue full")); } return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_2(mp_micropython_schedule_obj, mp_micropython_schedule); + #endif static const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { diff --git a/py/modstring.c b/py/modstring.c new file mode 100644 index 00000000000..26e0c2d83cb --- /dev/null +++ b/py/modstring.c @@ -0,0 +1,56 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2026 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/obj.h" + +#if MICROPY_PY_TSTRINGS + +static const mp_rom_map_elem_t mp_module_string_templatelib_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_string_dot_templatelib) }, + { MP_ROM_QSTR(MP_QSTR_Template), MP_ROM_PTR(&mp_type_template) }, + { MP_ROM_QSTR(MP_QSTR_Interpolation), MP_ROM_PTR(&mp_type_interpolation) }, +}; +static MP_DEFINE_CONST_DICT(mp_module_string_templatelib_globals, mp_module_string_templatelib_globals_table); + +static const mp_obj_module_t mp_module_string_templatelib = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mp_module_string_templatelib_globals, +}; + +static const mp_rom_map_elem_t mp_module_string_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_string) }, + { MP_ROM_QSTR(MP_QSTR_templatelib), MP_ROM_PTR(&mp_module_string_templatelib) }, +}; +static MP_DEFINE_CONST_DICT(mp_module_string_globals, mp_module_string_globals_table); + +const mp_obj_module_t mp_module_string = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mp_module_string_globals, +}; + +MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_string, mp_module_string); + +#endif // MICROPY_PY_TSTRINGS diff --git a/py/modsys.c b/py/modsys.c index 2adbc0b7bd6..bbae93d0c3f 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -95,8 +95,16 @@ static const MP_DEFINE_STR_OBJ(mp_sys_implementation_machine_obj, MICROPY_BANNER MP_ROM_PTR(&mp_sys_implementation_machine_obj) #if MICROPY_PERSISTENT_CODE_LOAD +// Note: Adding architecture flags to _mpy will break if the flags information +// takes up more bits than what is available in a small-int value. +#if MICROPY_EMIT_RV32 +#include "py/asmrv32.h" +#define MPY_FILE_ARCH_FLAGS (MICROPY_RV32_EXTENSIONS << 16) +#else +#define MPY_FILE_ARCH_FLAGS (0) +#endif #define SYS_IMPLEMENTATION_ELEMS__MPY \ - , MP_ROM_INT(MPY_FILE_HEADER_INT) + , MP_ROM_INT(MPY_FILE_HEADER_INT | MPY_FILE_ARCH_FLAGS) #else #define SYS_IMPLEMENTATION_ELEMS__MPY #endif @@ -113,6 +121,18 @@ static const MP_DEFINE_STR_OBJ(mp_sys_implementation__build_obj, MICROPY_BOARD_B #define SYS_IMPLEMENTATION_ELEMS__BUILD #endif +#if MICROPY_PY_THREAD +#if MICROPY_PY_THREAD_GIL +#define SYS_IMPLEMENTATION_ELEMS__THREAD \ + , MP_ROM_QSTR(MP_QSTR_GIL) +#else +#define SYS_IMPLEMENTATION_ELEMS__THREAD \ + , MP_ROM_QSTR(MP_QSTR_unsafe) +#endif +#else +#define SYS_IMPLEMENTATION_ELEMS__THREAD +#endif + #if MICROPY_PREVIEW_VERSION_2 #define SYS_IMPLEMENTATION_ELEMS__V2 \ , MP_ROM_TRUE @@ -130,6 +150,9 @@ static const qstr impl_fields[] = { #if defined(MICROPY_BOARD_BUILD_NAME) MP_QSTR__build, #endif + #if MICROPY_PY_THREAD + MP_QSTR__thread, + #endif #if MICROPY_PREVIEW_VERSION_2 MP_QSTR__v2, #endif @@ -137,20 +160,21 @@ static const qstr impl_fields[] = { static MP_DEFINE_ATTRTUPLE( mp_sys_implementation_obj, impl_fields, - 3 + MICROPY_PERSISTENT_CODE_LOAD + MICROPY_BOARD_BUILD + MICROPY_PREVIEW_VERSION_2, + 3 + MICROPY_PERSISTENT_CODE_LOAD + MICROPY_BOARD_BUILD + MICROPY_PY_THREAD + MICROPY_PREVIEW_VERSION_2, SYS_IMPLEMENTATION_ELEMS_BASE SYS_IMPLEMENTATION_ELEMS__MPY SYS_IMPLEMENTATION_ELEMS__BUILD + SYS_IMPLEMENTATION_ELEMS__THREAD SYS_IMPLEMENTATION_ELEMS__V2 ); #else static const mp_rom_obj_tuple_t mp_sys_implementation_obj = { {&mp_type_tuple}, 3 + MICROPY_PERSISTENT_CODE_LOAD, - // Do not include SYS_IMPLEMENTATION_ELEMS__BUILD or SYS_IMPLEMENTATION_ELEMS__V2 - // because SYS_IMPLEMENTATION_ELEMS__MPY may be empty if + // Do not include SYS_IMPLEMENTATION_ELEMS__BUILD, SYS_IMPLEMENTATION_ELEMS__THREAD + // or SYS_IMPLEMENTATION_ELEMS__V2 because SYS_IMPLEMENTATION_ELEMS__MPY may be empty if // MICROPY_PERSISTENT_CODE_LOAD is disabled, which means they'll share - // the same index. Cannot query _build or _v2 if MICROPY_PY_ATTRTUPLE is + // the same index. Cannot query _build, _thread or _v2 if MICROPY_PY_ATTRTUPLE is // disabled. { SYS_IMPLEMENTATION_ELEMS_BASE diff --git a/py/modweakref.c b/py/modweakref.c new file mode 100644 index 00000000000..3360a4e2095 --- /dev/null +++ b/py/modweakref.c @@ -0,0 +1,314 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2026 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/gc.h" +#include "py/runtime.h" + +#if MICROPY_PY_WEAKREF + +// Macros to obfuscate a heap pointer as a small integer object. +#define PTR_TO_INT_OBJ(ptr) (MP_OBJ_NEW_SMALL_INT(((uintptr_t)ptr) >> 1)) +#define PTR_FROM_INT_OBJ(obj) ((void *)(MP_OBJ_SMALL_INT_VALUE((obj)) << 1)) + +// Macros to convert between a weak reference and a heap pointer. +#define WEAK_REFERENCE_FROM_HEAP_PTR(ptr) PTR_TO_INT_OBJ(ptr) +#define WEAK_REFERENCE_TO_HEAP_PTR(weak_ref) PTR_FROM_INT_OBJ(weak_ref) + +// Macros to manage ref-finalizer linked-list pointers. +// - mp_obj_ref_t is obfuscated as a small integer object so it's not traced by the GC. +// - mp_obj_finalize_t is stored as-is so it is traced by the GC. +#define REF_FIN_LIST_OBJ_IS_FIN(r) (!mp_obj_is_small_int((r))) +#define REF_FIN_LIST_OBJ_TO_PTR(r) ((mp_obj_ref_t *)(mp_obj_is_small_int((r)) ? PTR_FROM_INT_OBJ((r)) : MP_OBJ_TO_PTR((r)))) +#define REF_FIN_LIST_OBJ_FROM_REF(r) (PTR_TO_INT_OBJ((r))) +#define REF_FIN_LIST_OBJ_FROM_FIN(r) (MP_OBJ_FROM_PTR((r))) +#define REF_FIN_LIST_OBJ_TAIL (PTR_TO_INT_OBJ(NULL)) + +// weakref.ref() instance. +typedef struct _mp_obj_ref_t { + mp_obj_base_t base; + mp_obj_t ref_fin_next; + mp_obj_t obj_weak_ref; + mp_obj_t callback; +} mp_obj_ref_t; + +// weakref.finalize() instance. +// This is an extension of weakref.ref() and shares a lot of code with it. +typedef struct _mp_obj_finalize_t { + mp_obj_ref_t base; + size_t n_args; + size_t n_kw; + mp_obj_t *args; +} mp_obj_finalize_t; + +static const mp_obj_type_t mp_type_ref; +static const mp_obj_type_t mp_type_finalize; + +static mp_obj_t ref___del__(mp_obj_t self_in); + +void gc_weakref_about_to_be_freed(void *ptr) { + mp_obj_t idx = WEAK_REFERENCE_FROM_HEAP_PTR(ptr); + mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_weakref_map), idx, MP_MAP_LOOKUP); + if (elem != NULL) { + // Mark element as being freed. + elem->key = mp_const_none; + } +} + +void gc_weakref_sweep(void) { + mp_map_t *map = &MP_STATE_VM(mp_weakref_map); + for (size_t i = 0; i < map->alloc; i++) { + if (map->table[i].key == mp_const_none) { + // Element was just freed, so call all the registered callbacks. + --map->used; + map->table[i].key = MP_OBJ_SENTINEL; + mp_obj_ref_t *ref = REF_FIN_LIST_OBJ_TO_PTR(map->table[i].value); + map->table[i].value = MP_OBJ_NULL; + while (ref != NULL) { + // Invalidate the weak reference. + assert(ref->obj_weak_ref != mp_const_none); + ref->obj_weak_ref = mp_const_none; + + // Call any registered callbacks. + if (ref->callback != mp_const_none) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + if (ref->base.type == &mp_type_ref) { + // weakref.ref() type. + mp_call_function_1(ref->callback, MP_OBJ_FROM_PTR(ref)); + } else { + // weakref.finalize() type. + mp_obj_finalize_t *fin = (mp_obj_finalize_t *)ref; + mp_call_function_n_kw(fin->base.callback, fin->n_args, fin->n_kw, fin->args); + } + nlr_pop(); + } else { + mp_printf(MICROPY_ERROR_PRINTER, "Unhandled exception in weakref callback:\n"); + mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + } + + // Unlink the node. + mp_obj_ref_t *ref_fin_next = REF_FIN_LIST_OBJ_TO_PTR(ref->ref_fin_next); + ref->ref_fin_next = REF_FIN_LIST_OBJ_TAIL; + ref = ref_fin_next; + } + } + } +} + +static mp_obj_t mp_obj_ref_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + if (type == &mp_type_ref) { + // weakref.ref() type. + mp_arg_check_num(n_args, n_kw, 1, 2, false); + } else { + // weakref.finalize() type. + mp_arg_check_num(n_args, n_kw, 2, MP_OBJ_FUN_ARGS_MAX, true); + } + + // Validate the input object can have a weakref. + void *ptr = NULL; + if (mp_obj_is_obj(args[0])) { + ptr = MP_OBJ_TO_PTR(args[0]); + if (gc_nbytes(ptr) == 0) { + ptr = NULL; + } + } + if (ptr == NULL) { + mp_raise_TypeError(MP_ERROR_TEXT("not a heap object")); + } + + // Create or get the entry in mp_weakref_map corresponding to this object. + mp_obj_t obj_weak_reference = WEAK_REFERENCE_FROM_HEAP_PTR(ptr); + mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_weakref_map), obj_weak_reference, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + if (elem->value == MP_OBJ_NULL) { + // This heap object does not have any existing weakref's, so initialise it. + elem->value = REF_FIN_LIST_OBJ_TAIL; + gc_weakref_mark(ptr); + } + + mp_obj_ref_t *self; + if (type == &mp_type_ref) { + // Create a new weakref.ref() object. + self = mp_obj_malloc_with_finaliser(mp_obj_ref_t, type); + // Link this new ref into the list of all refs/finalizers pointing to this object. + // To ensure it will *NOT* be traced by the GC (the user must manually hold onto it), + // store an integer version of the object after any weakref.finalize() objects (so + // the weakref.finalize() objects continue to be traced by the GC). + mp_obj_t *link = &elem->value; + while (REF_FIN_LIST_OBJ_IS_FIN(*link)) { + link = &REF_FIN_LIST_OBJ_TO_PTR(*link)->ref_fin_next; + } + self->ref_fin_next = *link; + *link = REF_FIN_LIST_OBJ_FROM_REF(self); + } else { + // Create a new weakref.finalize() object. + mp_obj_finalize_t *self_fin = mp_obj_malloc(mp_obj_finalize_t, type); + self_fin->n_args = n_args - 2; + self_fin->n_kw = n_kw; + size_t n_args_kw = self_fin->n_args + self_fin->n_kw * 2; + if (n_args_kw == 0) { + self_fin->args = NULL; + } else { + self_fin->args = m_new(mp_obj_t, n_args_kw); + memcpy(self_fin->args, args + 2, n_args_kw * sizeof(mp_obj_t)); + } + self = &self_fin->base; + // Link this new finalizer into the list of all refs/finalizers pointing to this object. + // To ensure it will be traced by the GC, store its pointer at the start of the list. + self->ref_fin_next = elem->value; + elem->value = REF_FIN_LIST_OBJ_FROM_FIN(self_fin); + } + + // Populate the object weak reference, and the callback. + self->obj_weak_ref = obj_weak_reference; + if (n_args > 1) { + self->callback = args[1]; + } else { + self->callback = mp_const_none; + } + + return MP_OBJ_FROM_PTR(self); +} + +static mp_obj_t mp_obj_ref_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_ref_t *self = MP_OBJ_TO_PTR(self_in); + if (self->obj_weak_ref == mp_const_none) { + return mp_const_none; + } + if (self->base.type == &mp_type_ref) { + // weakref.ref() type. + return MP_OBJ_FROM_PTR(WEAK_REFERENCE_TO_HEAP_PTR(self->obj_weak_ref)); + } else { + // weakref.finalize() type. + mp_obj_finalize_t *self_fin = MP_OBJ_TO_PTR(self_in); + ref___del__(self_in); + return mp_call_function_n_kw(self_fin->base.callback, self_fin->n_args, self_fin->n_kw, self_fin->args); + } +} + +static mp_obj_t ref___del__(mp_obj_t self_in) { + mp_obj_ref_t *self = MP_OBJ_TO_PTR(self_in); + mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_weakref_map), self->obj_weak_ref, MP_MAP_LOOKUP); + if (elem != NULL) { + for (mp_obj_t *link = &elem->value; REF_FIN_LIST_OBJ_TO_PTR(*link) != NULL; link = &REF_FIN_LIST_OBJ_TO_PTR(*link)->ref_fin_next) { + if (self == REF_FIN_LIST_OBJ_TO_PTR(*link)) { + // Unlink and clear this node. + *link = self->ref_fin_next; + self->ref_fin_next = REF_FIN_LIST_OBJ_TAIL; + self->obj_weak_ref = mp_const_none; + break; + } + } + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(ref___del___obj, ref___del__); + +static mp_obj_t finalize_peek_detach_helper(mp_obj_t self_in, bool detach) { + mp_obj_finalize_t *self = MP_OBJ_TO_PTR(self_in); + if (self->base.obj_weak_ref == mp_const_none) { + return mp_const_none; + } + mp_obj_t tuple[4] = { + MP_OBJ_FROM_PTR(WEAK_REFERENCE_TO_HEAP_PTR(self->base.obj_weak_ref)), + self->base.callback, + mp_obj_new_tuple(self->n_args, self->args), + mp_obj_dict_make_new(&mp_type_dict, 0, self->n_kw, self->args + self->n_args), + }; + if (detach) { + ref___del__(self_in); + } + return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); +} + +static mp_obj_t finalize_peek(mp_obj_t self_in) { + return finalize_peek_detach_helper(self_in, false); +} +static MP_DEFINE_CONST_FUN_OBJ_1(finalize_peek_obj, finalize_peek); + +static mp_obj_t finalize_detach(mp_obj_t self_in) { + return finalize_peek_detach_helper(self_in, true); +} +static MP_DEFINE_CONST_FUN_OBJ_1(finalize_detach_obj, finalize_detach); + +static void mp_obj_finalize_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // Store/delete attribute, unsupported. + return; + } + + if (attr == MP_QSTR_alive) { + mp_obj_finalize_t *self = MP_OBJ_TO_PTR(self_in); + dest[0] = mp_obj_new_bool(self->base.obj_weak_ref != mp_const_none); + return; + } else if (attr == MP_QSTR_peek) { + dest[0] = MP_OBJ_FROM_PTR(&finalize_peek_obj); + dest[1] = self_in; + } else if (attr == MP_QSTR_detach) { + dest[0] = MP_OBJ_FROM_PTR(&finalize_detach_obj); + dest[1] = self_in; + } +} + +static const mp_rom_map_elem_t ref_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ref___del___obj) }, +}; +static MP_DEFINE_CONST_DICT(ref_locals_dict, ref_locals_dict_table); + +static MP_DEFINE_CONST_OBJ_TYPE( + mp_type_ref, + MP_QSTR_ref, + MP_TYPE_FLAG_NONE, + make_new, mp_obj_ref_make_new, + call, mp_obj_ref_call, + locals_dict, &ref_locals_dict + ); + +static MP_DEFINE_CONST_OBJ_TYPE( + mp_type_finalize, + MP_QSTR_finalize, + MP_TYPE_FLAG_NONE, + make_new, mp_obj_ref_make_new, + call, mp_obj_ref_call, + attr, mp_obj_finalize_attr + ); + +static const mp_rom_map_elem_t mp_module_weakref_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_weakref) }, + { MP_ROM_QSTR(MP_QSTR_ref), MP_ROM_PTR(&mp_type_ref) }, + { MP_ROM_QSTR(MP_QSTR_finalize), MP_ROM_PTR(&mp_type_finalize) }, +}; +static MP_DEFINE_CONST_DICT(mp_module_weakref_globals, mp_module_weakref_globals_table); + +const mp_obj_module_t mp_module_weakref = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mp_module_weakref_globals, +}; + +MP_REGISTER_ROOT_POINTER(mp_map_t mp_weakref_map); +MP_REGISTER_MODULE(MP_QSTR_weakref, mp_module_weakref); + +#endif // MICROPY_PY_WEAKREF diff --git a/py/mpconfig.h b/py/mpconfig.h index a4895820061..39a8681d73a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -26,6 +26,15 @@ #ifndef MICROPY_INCLUDED_PY_MPCONFIG_H #define MICROPY_INCLUDED_PY_MPCONFIG_H +#include +#include + +#if defined(__cplusplus) // Required on at least one compiler to get ULLONG_MAX +#include +#else +#include +#endif + // CIRCUITPY-CHANGE // Is this a CircuitPython build? #ifndef CIRCUITPY @@ -40,7 +49,7 @@ // as well as a fallback to generate MICROPY_GIT_TAG if the git repo or tags // are unavailable. #define MICROPY_VERSION_MAJOR 1 -#define MICROPY_VERSION_MINOR 25 +#define MICROPY_VERSION_MINOR 29 #define MICROPY_VERSION_MICRO 0 #define MICROPY_VERSION_PRERELEASE 0 @@ -173,6 +182,81 @@ #define MICROPY_OBJ_IMMEDIATE_OBJS (MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D) #endif +// Definition of the `mp_int_t` and `mp_uint_t` types and associated macros. +// Normally, it suffices for the platform to do nothing: A type as wide +// as a pointer is chosen, unless nanboxing (REPR_D) is selected, in +// which case a 64-bit type is chosen to match the assumed size of +// double-precision floats. +// +// In the case of exceptions, the port, board, or variant must define +// MP_INT_TYPE as MP_INT_TYPE_OTHER and provide all the typedefs and +// defines. +#define MP_INT_TYPE_INTPTR (0) +#define MP_INT_TYPE_INT64 (1) +#define MP_INT_TYPE_OTHER (2) + +#if !defined(MP_INT_TYPE) +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D +#define MP_INT_TYPE (MP_INT_TYPE_INT64) +#else +#define MP_INT_TYPE (MP_INT_TYPE_INTPTR) +#endif +#endif + +#if MP_INT_TYPE == MP_INT_TYPE_INTPTR +typedef intptr_t mp_int_t; +// Use size_t so kw-function signatures and other size-typed APIs match without +// triggering -Wincompatible-pointer-types under newer GCCs where size_t and +// uintptr_t are distinct types of the same width (e.g. picolibc on 32-bit ARM). +typedef size_t mp_uint_t; +#define MP_INT_MAX INTPTR_MAX +#define MP_INT_MIN INTPTR_MIN +#define MP_UINT_MAX SIZE_MAX +#elif MP_INT_TYPE == MP_INT_TYPE_INT64 +typedef int64_t mp_int_t; +typedef uint64_t mp_uint_t; +#define MP_INT_MAX INT64_MAX +#define MP_INT_MIN INT64_MIN +#define MP_UINT_MAX INT64_UMAX +#endif + +// mp_printf format support for mp_int_t. In the unusual case that MP_INT_MAX doesn't +// match any of the standard C types (int/long/long long), provide all 3 +// macros. Otherwise, rely on these automatic definitions. +#if !defined(INT_FMT) +#if MP_INT_MAX == INT_MAX +#define INT_FMT "%d" +#define UINT_FMT "%u" +#define HEX_FMT "%x" +#elif MP_INT_MAX == LONG_MAX +#define INT_FMT "%ld" +#define UINT_FMT "%lu" +#define HEX_FMT "%lx" +#elif MP_INT_MAX == LLONG_MAX +#define INT_FMT "%lld" +#define UINT_FMT "%llu" +#define HEX_FMT "%llx" +#else +#error Unexpected MP_INT_MAX value +#endif +#endif + +// mp_printf format support for size_t. In the unusual case that SIZE_MAX doesn't +// match any of the standard C types (int/long/long long), provide a +// macro. Otherwise, rely on these automatic definitions. +#if !defined(SIZE_FMT) +#if SIZE_MAX == UINT_MAX +#define SIZE_FMT "%u" +#elif SIZE_MAX == ULONG_MAX +#define SIZE_FMT "%lu" +#elif SIZE_MAX == ULLONG_MAX +#define SIZE_FMT "%llu" +#else +#error Unexpected SIZE_MAX value +#endif +#endif + + /*****************************************************************************/ /* Memory allocation policy */ @@ -342,6 +426,11 @@ #define MICROPY_PERSISTENT_CODE_LOAD (0) #endif +// Whether to support loading of persistent native code +#ifndef MICROPY_PERSISTENT_CODE_LOAD_NATIVE +#define MICROPY_PERSISTENT_CODE_LOAD_NATIVE (MICROPY_EMIT_MACHINE_CODE) +#endif + // Whether to support saving of persistent code, i.e. for mpy-cross to // generate .mpy files. Enabling this enables additional metadata on raw code // objects which is also required for sys.settrace. @@ -362,7 +451,7 @@ // Whether generated code can persist independently of the VM/runtime instance // This is enabled automatically when needed by other features #ifndef MICROPY_PERSISTENT_CODE -#define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE || MICROPY_MODULE_FROZEN_MPY) +#define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_LOAD_NATIVE || MICROPY_PERSISTENT_CODE_SAVE || MICROPY_MODULE_FROZEN_MPY) #endif // Whether bytecode uses a qstr_table to map internal qstr indices in the bytecode @@ -390,7 +479,11 @@ // Whether to emit ARMv7-M instruction support in thumb native code #ifndef MICROPY_EMIT_THUMB_ARMV7M +#if defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2 #define MICROPY_EMIT_THUMB_ARMV7M (1) +#else +#define MICROPY_EMIT_THUMB_ARMV7M (0) +#endif #endif // Whether to enable the thumb inline assembler @@ -400,7 +493,11 @@ // Whether to enable float support in the Thumb2 inline assembler #ifndef MICROPY_EMIT_INLINE_THUMB_FLOAT +#if defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2 && defined(__ARM_FP) #define MICROPY_EMIT_INLINE_THUMB_FLOAT (1) +#else +#define MICROPY_EMIT_INLINE_THUMB_FLOAT (0) +#endif #endif // Whether to emit ARM native code @@ -418,6 +515,11 @@ #define MICROPY_EMIT_INLINE_XTENSA (0) #endif +// Whether to support uncommon Xtensa inline assembler opcodes +#ifndef MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES +#define MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES (0) +#endif + // Whether to emit Xtensa-Windowed native code #ifndef MICROPY_EMIT_XTENSAWIN #define MICROPY_EMIT_XTENSAWIN (0) @@ -428,9 +530,14 @@ #define MICROPY_EMIT_RV32 (0) #endif -// CIRCUITPY-CHANGE: make sure MICROPY_EMIT_NATIVE_DEBUG is defined -#ifndef MICROPY_EMIT_NATIVE_DEBUG -#define MICROPY_EMIT_NATIVE_DEBUG (0) +// Whether to emit RISC-V RV32 Zba opcodes in native code +#ifndef MICROPY_EMIT_RV32_ZBA +#define MICROPY_EMIT_RV32_ZBA (0) +#endif + +// Whether to emit RISC-V RV32 Zcmp opcodes in native code +#ifndef MICROPY_EMIT_RV32_ZCMP +#define MICROPY_EMIT_RV32_ZCMP (0) #endif // Whether to enable the RISC-V RV32 inline assembler @@ -438,13 +545,23 @@ #define MICROPY_EMIT_INLINE_RV32 (0) #endif +// Whether to enable the human-readable native instructions emitter +#ifndef MICROPY_EMIT_NATIVE_DEBUG +#define MICROPY_EMIT_NATIVE_DEBUG (0) +#endif + // Convenience definition for whether any native emitter is enabled #define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN || MICROPY_EMIT_RV32 || MICROPY_EMIT_NATIVE_DEBUG) // Some architectures cannot read byte-wise from executable memory. In this case // the prelude for a native function (which usually sits after the machine code) // must be separated and placed somewhere where it can be read byte-wise. +// CIRCUITPY-CHANGE: also when only loading native code on windowed Xtensa. +#if defined(__XTENSA_WINDOWED_ABI__) +#define MICROPY_EMIT_NATIVE_PRELUDE_SEPARATE_FROM_MACHINE_CODE (MICROPY_EMIT_XTENSAWIN || MICROPY_PERSISTENT_CODE_LOAD_NATIVE) +#else #define MICROPY_EMIT_NATIVE_PRELUDE_SEPARATE_FROM_MACHINE_CODE (MICROPY_EMIT_XTENSAWIN) +#endif // Convenience definition for whether any inline assembler emitter is enabled #define MICROPY_EMIT_INLINE_ASM (MICROPY_EMIT_INLINE_THUMB || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_INLINE_RV32) @@ -452,6 +569,10 @@ // Convenience definition for whether any native or inline assembler emitter is enabled #define MICROPY_EMIT_MACHINE_CODE (MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM) +// Convenience definition for whether native code has to be dealt with (either +// generated or loaded from a file). This does not cover inline asm code. +#define MICROPY_ENABLE_NATIVE_CODE (MICROPY_EMIT_NATIVE || MICROPY_PERSISTENT_CODE_LOAD_NATIVE) + /*****************************************************************************/ /* Compiler configuration */ @@ -497,6 +618,13 @@ #define MICROPY_COMP_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif +// Whether to enable float constant folding like 1.2+3.4 (when MICROPY_COMP_CONST_FOLDING is also enabled) +// and constant optimisation like id = const(1.2) (when MICROPY_COMP_CONST is also enabled) +// and constant lookup like math.inf (when MICROPY_COMP_MODULE_CONST is also enabled) +#ifndef MICROPY_COMP_CONST_FLOAT +#define MICROPY_COMP_CONST_FLOAT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) +#endif + // Whether to enable optimisation of: a, b = c, d // Costs 124 bytes (Thumb2) #ifndef MICROPY_COMP_DOUBLE_TUPLE_ASSIGN @@ -727,6 +855,13 @@ #define MICROPY_STACK_CHECK_MARGIN (0) #endif +// The size of a separate stack used for hard IRQ handlers, which should be +// checked instead of the main stack when running a hard callback. 0 implies +// there is no separate ISR stack to check. +#ifndef MICROPY_STACK_SIZE_HARD_IRQ +#define MICROPY_STACK_SIZE_HARD_IRQ (0) +#endif + // Whether to have an emergency exception buffer #ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) @@ -896,8 +1031,25 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT) #endif -#ifndef MICROPY_PY_DOUBLE_TYPECODE -#define MICROPY_PY_DOUBLE_TYPECODE (MICROPY_PY_BUILTINS_FLOAT) +// Float to string conversion implementations +// +// Note that the EXACT method is only available if the compiler supports +// floating points larger than mp_float_t: +// - with MICROPY_FLOAT_IMPL_FLOAT, the compiler needs to support `double` +// - with MICROPY_FLOAT_IMPL_DOUBLE, the compiler needs to support `long double` +// +#define MICROPY_FLOAT_FORMAT_IMPL_BASIC (0) // smallest code, but inexact +#define MICROPY_FLOAT_FORMAT_IMPL_APPROX (1) // slightly bigger, almost perfect +#define MICROPY_FLOAT_FORMAT_IMPL_EXACT (2) // bigger code, and 100% exact repr + +#ifndef MICROPY_FLOAT_FORMAT_IMPL +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define MICROPY_FLOAT_FORMAT_IMPL (MICROPY_FLOAT_FORMAT_IMPL_APPROX) +#elif defined(__SIZEOF_LONG_DOUBLE__) && __SIZEOF_LONG_DOUBLE__ > __SIZEOF_DOUBLE__ +#define MICROPY_FLOAT_FORMAT_IMPL (MICROPY_FLOAT_FORMAT_IMPL_EXACT) +#else +#define MICROPY_FLOAT_FORMAT_IMPL (MICROPY_FLOAT_FORMAT_IMPL_APPROX) +#endif #endif // Whether to use the native _Float16 for 16-bit float support @@ -932,6 +1084,64 @@ typedef double mp_float_t; #define MICROPY_FULL_CHECKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif +// Ports can choose to use timestamps based on 2000-01-01 or 1970-01-01 +// Default is timestamps based on 2000-01-01 +#if !defined(MICROPY_EPOCH_IS_2000) && !defined(MICROPY_EPOCH_IS_1970) +#define MICROPY_EPOCH_IS_2000 (1) +#define MICROPY_EPOCH_IS_1970 (0) +#elif !defined(MICROPY_EPOCH_IS_1970) +#define MICROPY_EPOCH_IS_1970 (1 - (MICROPY_EPOCH_IS_2000)) +#elif !defined(MICROPY_EPOCH_IS_2000) +#define MICROPY_EPOCH_IS_2000 (1 - (MICROPY_EPOCH_IS_1970)) +#endif + +// To maintain reasonable compatibility with CPython on embedded systems, +// and avoid breaking anytime soon, time functions are defined to work +// at least between 1970 and 2099 (included) on any machine. +// +// Specific ports can enable extended date support +// - after 2099 using MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND +// - before 1970 using MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE +// The largest possible range is year 1600 to year 3000 +// +// By default, extended date support is only enabled for machines using 64 bit pointers, +// but it can be enabled by specific ports +#ifndef MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE +#if MP_SSIZE_MAX > 2147483647 +#define MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE (1) +#else +#define MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE (0) +#endif +#endif + +// When support for dates <1970 is enabled, supporting >=2100 does not cost anything +#ifndef MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND +#define MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND (MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE) +#endif + +// The type to be used to represent platform-specific timestamps depends on the choices above +#define MICROPY_TIMESTAMP_IMPL_LONG_LONG (0) +#define MICROPY_TIMESTAMP_IMPL_UINT (1) +#define MICROPY_TIMESTAMP_IMPL_TIME_T (2) + +#ifndef MICROPY_TIMESTAMP_IMPL +#if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE || MICROPY_EPOCH_IS_2000 +#define MICROPY_TIMESTAMP_IMPL (MICROPY_TIMESTAMP_IMPL_LONG_LONG) +#else +#define MICROPY_TIMESTAMP_IMPL (MICROPY_TIMESTAMP_IMPL_UINT) +#endif +#endif + +// `mp_timestamp_t` is the type that should be used by the port +// to represent timestamps, and is referenced to the platform epoch +#if MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_LONG_LONG +typedef long long mp_timestamp_t; +#elif MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_UINT +typedef mp_uint_t mp_timestamp_t; +#elif MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_TIME_T +typedef time_t mp_timestamp_t; +#endif + // Whether POSIX-semantics non-blocking streams are supported #ifndef MICROPY_STREAMS_NON_BLOCK #define MICROPY_STREAMS_NON_BLOCK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) @@ -943,6 +1153,22 @@ typedef double mp_float_t; #define MICROPY_STREAMS_POSIX_API (0) #endif +// Whether to delegate error raising to stream implementations using the +// MP_STREAM_RAISE_ERROR ioctl to support raising more detailed messages. +#ifndef MICROPY_STREAMS_DELEGATE_ERROR +#define MICROPY_STREAMS_DELEGATE_ERROR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + +// Whether to process __all__ when importing all public symbols from a module. +#ifndef MICROPY_MODULE___ALL__ +#define MICROPY_MODULE___ALL__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES) +#endif + +// Whether to set __file__ on imported modules. +#ifndef MICROPY_MODULE___FILE__ +#define MICROPY_MODULE___FILE__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) +#endif + // Whether modules can use MP_REGISTER_MODULE_DELEGATION() to delegate failed // attribute lookups to a custom handler function. #ifndef MICROPY_MODULE_ATTR_DELEGATION @@ -967,7 +1193,7 @@ typedef double mp_float_t; // have __init__ methods. Instead, the top-level package's __init__ should // initialise all sub-packages. #ifndef MICROPY_MODULE_BUILTIN_SUBPACKAGES -#define MICROPY_MODULE_BUILTIN_SUBPACKAGES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING) +#define MICROPY_MODULE_BUILTIN_SUBPACKAGES (MICROPY_PY_TSTRINGS || MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING) #endif // Whether to support module-level __getattr__ (see PEP 562) @@ -1030,6 +1256,16 @@ typedef double mp_float_t; #define MICROPY_ENABLE_VM_ABORT (0) #endif +// Whether to handle abort behavior in pyexec code +#ifndef MICROPY_PYEXEC_ENABLE_VM_ABORT +#define MICROPY_PYEXEC_ENABLE_VM_ABORT (0) +#endif + +// Whether to set exit codes according to the exit reason (keyboard interrupt, crash, normal exit, ...) +#ifndef MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING +#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (0) +#endif + // Support for internal scheduler #ifndef MICROPY_ENABLE_SCHEDULER #define MICROPY_ENABLE_SCHEDULER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) @@ -1050,6 +1286,11 @@ typedef double mp_float_t; #define MICROPY_VFS (0) #endif +// Whether to include support for fast native block devices. +#ifndef MICROPY_VFS_BLOCKDEV_NATIVE +#define MICROPY_VFS_BLOCKDEV_NATIVE (0) +#endif + // Whether to include support for writable filesystems. #ifndef MICROPY_VFS_WRITABLE #define MICROPY_VFS_WRITABLE (1) @@ -1065,6 +1306,11 @@ typedef double mp_float_t; #define MICROPY_VFS_POSIX (0) #endif +// Whether to include support for writable POSIX filesystems. +#ifndef MICROPY_VFS_POSIX_WRITABLE +#define MICROPY_VFS_POSIX_WRITABLE (1) +#endif + // Support for VFS FAT component, to mount a FAT filesystem within VFS #ifndef MICROPY_VFS_FAT #define MICROPY_VFS_FAT (0) @@ -1102,10 +1348,18 @@ typedef double mp_float_t; // Whether to implement the __code__ attribute on functions, and function constructor #ifndef MICROPY_PY_FUNCTION_ATTRS_CODE -#define MICROPY_PY_FUNCTION_ATTRS_CODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES) +#define MICROPY_PY_FUNCTION_ATTRS_CODE (MICROPY_PY_MARSHAL || MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES) +#endif + +// Whether bound_method can just use == (feature disabled), or requires a call to +// mp_obj_equal (feature enabled), to test equality of the self and meth entities. +// This is only needed if objects and functions can be identical without being the +// same thing, eg when using an object proxy. +#ifndef MICROPY_PY_BOUND_METHOD_FULL_EQUALITY_CHECK +#define MICROPY_PY_BOUND_METHOD_FULL_EQUALITY_CHECK (0) #endif -// Whether to support the descriptors __get__, __set__, __delete__ +// Whether to support the descriptors __get__, __set__, __delete__, __set_name__ // This costs some code size and makes load/store/delete of instance // attributes slower for the classes that use this feature #ifndef MICROPY_PY_DESCRIPTORS @@ -1129,6 +1383,12 @@ typedef double mp_float_t; #define MICROPY_PY_FSTRINGS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif +// Support for template strings, t-strings (see PEP 750, Python 3.14+) +// Requires MICROPY_PY_FSTRINGS to be enabled. +#ifndef MICROPY_PY_TSTRINGS +#define MICROPY_PY_TSTRINGS (MICROPY_PY_FSTRINGS && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES) +#endif + // Support for assignment expressions with := (see PEP 572, Python 3.8+) #ifndef MICROPY_PY_ASSIGN_EXPR #define MICROPY_PY_ASSIGN_EXPR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) @@ -1155,7 +1415,7 @@ typedef double mp_float_t; // Whether str object is proper unicode #ifndef MICROPY_PY_BUILTINS_STR_UNICODE -#define MICROPY_PY_BUILTINS_STR_UNICODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#define MICROPY_PY_BUILTINS_STR_UNICODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES) #endif // Whether to check for valid UTF-8 when converting bytes to str @@ -1163,6 +1423,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_STR_UNICODE_CHECK (MICROPY_PY_BUILTINS_STR_UNICODE) #endif +// Whether bytes.decode() supports the 'ignore' and 'replace' error handlers +#ifndef MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS +#define MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + // Whether str.center() method provided #ifndef MICROPY_PY_BUILTINS_STR_CENTER #define MICROPY_PY_BUILTINS_STR_CENTER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) @@ -1214,7 +1479,7 @@ typedef double mp_float_t; // Whether to support memoryview.itemsize attribute #ifndef MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE -#define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING) +#define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (MICROPY_PY_MACHINE_MEM_BACKUP || MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES) #endif // Whether to support set object @@ -1272,6 +1537,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_ROUND_INT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif +// Whether to implement dir() to enumerate object fields. +#ifndef MICROPY_PY_BUILTINS_DIR +#define MICROPY_PY_BUILTINS_DIR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) +#endif + // Whether to support complete set of special methods for user // classes, or only the most used ones. "Inplace" methods are // controlled by MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS below. @@ -1362,9 +1632,14 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_HELP_MODULES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif -// Whether to set __file__ for imported modules -#ifndef MICROPY_PY___FILE__ -#define MICROPY_PY___FILE__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) +// Use this to configure output of help('modules') +#ifndef MICROPY_PY_BUILTINS_HELP_NUM_COLUMNS +#define MICROPY_PY_BUILTINS_HELP_NUM_COLUMNS (4) +#endif + +// Use this to configure output of help('modules') +#ifndef MICROPY_PY_BUILTINS_HELP_COLUMN_WIDTH +#define MICROPY_PY_BUILTINS_HELP_COLUMN_WIDTH (18) #endif // Whether to provide mem-info related functions in micropython module @@ -1482,6 +1757,7 @@ typedef double mp_float_t; #endif // Whether to provide fix for pow(1, NaN) and pow(NaN, 0), which both should be 1 not NaN. +// Also fixes pow(base, NaN) to return NaN for other values of base. #ifndef MICROPY_PY_MATH_POW_FIX_NAN #define MICROPY_PY_MATH_POW_FIX_NAN (0) #endif @@ -1518,7 +1794,7 @@ typedef double mp_float_t; // Whether to provide "io.IOBase" class to support user streams #ifndef MICROPY_PY_IO_IOBASE -#define MICROPY_PY_IO_IOBASE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#define MICROPY_PY_IO_IOBASE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to provide "io.BytesIO" class @@ -1536,15 +1812,16 @@ typedef double mp_float_t; #define MICROPY_PY_STRUCT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif -// CIRCUITPY-CHANGE -// Whether to provide non-standard typecodes in "struct" module -#ifndef MICROPY_NONSTANDARD_TYPECODES -#define MICROPY_NONSTANDARD_TYPECODES (1) +// Whether struct module provides unsafe and non-standard typecodes O, P, S. +// These typecodes are not in CPython and can cause crashes by accessing arbitrary +// memory. +#ifndef MICROPY_PY_STRUCT_UNSAFE_TYPECODES +#define MICROPY_PY_STRUCT_UNSAFE_TYPECODES (1) #endif // Whether to provide "sys" module #ifndef MICROPY_PY_SYS -#define MICROPY_PY_SYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) +#define MICROPY_PY_SYS (1) #endif // Whether to initialise "sys.path" and "sys.argv" to their defaults in mp_init() @@ -1668,7 +1945,7 @@ typedef double mp_float_t; // implementation). This is present for compatibility but can be disabled to // save space. #ifndef MICROPY_PY_SELECT_SELECT -#define MICROPY_PY_SELECT_SELECT (1) +#define MICROPY_PY_SELECT_SELECT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide the "time" module @@ -1718,6 +1995,11 @@ typedef double mp_float_t; #define MICROPY_PY_THREAD_RECURSIVE_MUTEX (MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL) #endif +// Whether to provide the "weakref" module. +#ifndef MICROPY_PY_WEAKREF +#define MICROPY_PY_WEAKREF (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING) +#endif + // Extended modules #ifndef MICROPY_PY_ASYNCIO @@ -1800,11 +2082,11 @@ typedef double mp_float_t; #endif #ifndef MICROPY_PY_HASHLIB_MD5 -#define MICROPY_PY_HASHLIB_MD5 (0) +#define MICROPY_PY_HASHLIB_MD5 (MICROPY_PY_SSL) #endif #ifndef MICROPY_PY_HASHLIB_SHA1 -#define MICROPY_PY_HASHLIB_SHA1 (0) +#define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL) #endif #ifndef MICROPY_PY_HASHLIB_SHA256 @@ -1812,7 +2094,7 @@ typedef double mp_float_t; #endif #ifndef MICROPY_PY_CRYPTOLIB -#define MICROPY_PY_CRYPTOLIB (0) +#define MICROPY_PY_CRYPTOLIB (MICROPY_PY_SSL) #endif // Depends on MICROPY_PY_CRYPTOLIB @@ -1872,6 +2154,11 @@ typedef double mp_float_t; #define MICROPY_PY_MACHINE_MEMX (MICROPY_PY_MACHINE) #endif +// Whether to provide the "machine.mem_backup" function +#ifndef MICROPY_PY_MACHINE_MEM_BACKUP +#define MICROPY_PY_MACHINE_MEM_BACKUP (0) +#endif + // Whether to provide the "machine.Signal" class #ifndef MICROPY_PY_MACHINE_SIGNAL #define MICROPY_PY_MACHINE_SIGNAL (MICROPY_PY_MACHINE) @@ -1916,6 +2203,16 @@ typedef double mp_float_t; #define MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT (2) #endif +// Whether to enable lwIP bindings to be used as the implementation of the `socket` module +#ifndef MICROPY_PY_LWIP +#define MICROPY_PY_LWIP (0) +#endif + +// Whether to support raw sockets via the `socket.SOCK_RAW` constant +#ifndef MICROPY_PY_LWIP_SOCK_RAW +#define MICROPY_PY_LWIP_SOCK_RAW (MICROPY_PY_LWIP) +#endif + #ifndef MICROPY_PY_SSL #define MICROPY_PY_SSL (0) #endif @@ -1935,6 +2232,11 @@ typedef double mp_float_t; #define MICROPY_PY_SSL_MBEDTLS_NEED_ACTIVE_CONTEXT (MICROPY_PY_SSL_ECDSA_SIGN_ALT) #endif +// Whether to support DTLS protocol (non-CPython feature) +#ifndef MICROPY_PY_SSL_DTLS +#define MICROPY_PY_SSL_DTLS (MICROPY_SSL_MBEDTLS && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + // Whether to provide the "vfs" module #ifndef MICROPY_PY_VFS #define MICROPY_PY_VFS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES && MICROPY_VFS) @@ -2027,7 +2329,7 @@ typedef double mp_float_t; /*****************************************************************************/ /* Miscellaneous settings */ -// All uPy objects in ROM must be aligned on at least a 4 byte boundary +// All MicroPython objects in ROM must be aligned on at least a 4 byte boundary // so that the small-int/qstr/pointer distinction can be made. For machines // that don't do this (eg 16-bit CPU), define the following macro to something // like __attribute__((aligned(4))). @@ -2109,7 +2411,7 @@ typedef double mp_float_t; // can be overridden if needed by defining both MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA // and MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA. #ifndef MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA -#if MICROPY_EMIT_MACHINE_CODE && MICROPY_PERSISTENT_CODE_LOAD +#if (MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE) && MICROPY_PERSISTENT_CODE_LOAD // Pointer tracking is required when loading native code is enabled. #if defined(MP_PLAT_ALLOC_EXEC) || defined(MP_PLAT_COMMIT_EXEC) // If a port defined a custom allocator or commit function for native text, then the @@ -2130,7 +2432,7 @@ typedef double mp_float_t; #define MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA (1) #define MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA (0) #endif -#else // MICROPY_EMIT_MACHINE_CODE && MICROPY_PERSISTENT_CODE_LOAD +#else // (MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE) && MICROPY_PERSISTENT_CODE_LOAD // Pointer tracking not needed when loading native code is disabled. #define MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA (0) #define MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA (0) @@ -2166,25 +2468,13 @@ typedef double mp_float_t; #define MP_SSIZE_MAX SSIZE_MAX #endif -// printf format spec to use for mp_int_t and friends -#ifndef INT_FMT -#if defined(__LP64__) -// Archs where mp_int_t == long, long != int -#define UINT_FMT "%lu" -#define INT_FMT "%ld" -#elif defined(_WIN64) -#define UINT_FMT "%llu" -#define INT_FMT "%lld" -#else -// Archs where mp_int_t == int -#define UINT_FMT "%u" -#define INT_FMT "%d" +// Modifier for function which doesn't return +#ifndef MP_NORETURN +#define MP_NORETURN __attribute__((noreturn)) #endif -#endif // INT_FMT -// Modifier for function which doesn't return -#ifndef NORETURN -#define NORETURN __attribute__((noreturn)) +#if !MICROPY_PREVIEW_VERSION_2 +#define NORETURN MP_NORETURN #endif // Modifier for weak functions @@ -2205,6 +2495,12 @@ typedef double mp_float_t; #define MP_INLINE inline MP_NO_INSTRUMENT #endif +// CIRCUITPY-CHANGE +// Modifier for functions whose return value should not be ignored +#ifndef MP_WARN_UNUSED_RESULT +#define MP_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#endif + // Modifier for functions which should be never inlined #ifndef MP_NOINLINE #define MP_NOINLINE __attribute__((noinline)) @@ -2250,7 +2546,7 @@ typedef double mp_float_t; #ifndef MP_HTOBE16 #if MP_ENDIANNESS_LITTLE -#define MP_HTOBE16(x) ((uint16_t)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))) +#define MP_HTOBE16(x) MP_BSWAP16(x) #define MP_BE16TOH(x) MP_HTOBE16(x) #else #define MP_HTOBE16(x) (x) @@ -2260,7 +2556,7 @@ typedef double mp_float_t; #ifndef MP_HTOBE32 #if MP_ENDIANNESS_LITTLE -#define MP_HTOBE32(x) ((uint32_t)((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff))) +#define MP_HTOBE32(x) MP_BSWAP32(x) #define MP_BE32TOH(x) MP_HTOBE32(x) #else #define MP_HTOBE32(x) (x) @@ -2279,4 +2575,23 @@ typedef double mp_float_t; #define MP_WARN_CAT(x) (NULL) #endif +// If true, use __builtin_mul_overflow (a gcc intrinsic supported by clang) for +// overflow checking when multiplying two small ints. Otherwise, use a portable +// algorithm. +// +// Most MCUs have a 32x32->64 bit multiply instruction, in which case the +// intrinsic is likely to be faster and generate smaller code. The main exception is +// cortex-m0 with __ARM_ARCH_ISA_THUMB == 1. +// +// The intrinsic is in GCC starting with version 5. +#ifndef MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC +#if defined(__ARM_ARCH_ISA_THUMB) && (__GNUC__ >= 5) +#define MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC (__ARM_ARCH_ISA_THUMB >= 2) +#elif (__GNUC__ >= 5) +#define MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC (1) +#else +#define MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC (0) +#endif +#endif + #endif // MICROPY_INCLUDED_PY_MPCONFIG_H diff --git a/py/mperrno.h b/py/mperrno.h index 9e4ecd9419c..6c675125f4e 100644 --- a/py/mperrno.h +++ b/py/mperrno.h @@ -143,6 +143,9 @@ #endif +// Type for return values where 0 indicates success and negative values are negated MP_E* error codes. +typedef int mp_negative_errno_t; + #if MICROPY_PY_ERRNO #include "py/obj.h" diff --git a/py/mphal.h b/py/mphal.h index 95289ac856c..3907641be83 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -27,6 +27,7 @@ #define MICROPY_INCLUDED_PY_MPHAL_H #include +#include #include "py/mpconfig.h" #ifdef MICROPY_MPHALPORT_H diff --git a/py/mpprint.c b/py/mpprint.c index e4e25f5a82e..62e80d1e8e8 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -40,8 +40,20 @@ #include "py/formatfloat.h" #endif -static const char pad_spaces[] = " "; -static const char pad_zeroes[] = "0000000000000000"; +static const char pad_spaces[16] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; +#define pad_spaces_size (sizeof(pad_spaces)) +static const char pad_common[23] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '_', '0', '0', '0', ',', '0', '0'}; +// The contents of pad_common is arranged to provide the following padding +// strings with minimal flash size: +// 0000000000000000 <- pad_zeroes +// 0000_000 <- pad_zeroes_underscore (offset: 12, size 5) +// 000,00 <- pad_zeroes_comma (offset: 17, size 4) +#define pad_zeroes (pad_common + 0) +#define pad_zeroes_size (16) +#define pad_zeroes_underscore (pad_common + 12) +#define pad_zeroes_underscore_size (5) +#define pad_zeroes_comma (pad_common + 17) +#define pad_zeroes_comma_size (4) static void plat_print_strn(void *env, const char *str, size_t len) { (void)env; @@ -58,20 +70,37 @@ int mp_print_str(const mp_print_t *print, const char *str) { return len; } -int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width) { +int mp_print_strn(const mp_print_t *print, const char *str, size_t len, unsigned int flags, char fill, int width) { int left_pad = 0; int right_pad = 0; int pad = width - len; int pad_size; int total_chars_printed = 0; const char *pad_chars; + char grouping = flags >> PF_FLAG_SEP_POS; if (!fill || fill == ' ') { pad_chars = pad_spaces; - pad_size = sizeof(pad_spaces) - 1; - } else if (fill == '0') { + pad_size = pad_spaces_size; + } else if (fill == '0' && !grouping) { pad_chars = pad_zeroes; - pad_size = sizeof(pad_zeroes) - 1; + pad_size = pad_zeroes_size; + } else if (fill == '0') { + if (grouping == '_') { + pad_chars = pad_zeroes_underscore; + pad_size = pad_zeroes_underscore_size; + } else { + pad_chars = pad_zeroes_comma; + pad_size = pad_zeroes_comma_size; + } + // The result will never start with a grouping character. An extra leading zero is added. + // width is dead after this so we can use it in calculation + if (width % pad_size == 0) { + pad++; + width++; + } + // position the grouping character correctly within the pad repetition + pad_chars += pad_size - 1 - width % pad_size; } else { // Other pad characters are fairly unusual, so we'll take the hit // and output them 1 at a time. @@ -201,7 +230,7 @@ static int mp_print_int(const mp_print_t *print, mp_uint_t x, int sgn, int base, return len; } -int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec) { +int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, unsigned int base, int base_char, int flags, char fill, int width, int prec) { // These are the only values for "base" that are required to be supported by this // function, since Python only allows the user to format integers in these bases. // If needed this function could be generalised to handle other values. @@ -248,10 +277,7 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char int prefix_len = prefix - prefix_buf; prefix = prefix_buf; - char comma = '\0'; - if (flags & PF_FLAG_SHOW_COMMA) { - comma = ','; - } + char comma = flags >> PF_FLAG_SEP_POS; // The size of this buffer is rather arbitrary. If it's not large // enough, a dynamic one will be allocated. @@ -340,8 +366,8 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char } #if MICROPY_PY_BUILTINS_FLOAT -int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec) { - char buf[32]; +int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, unsigned int flags, char fill, int width, int prec) { + char buf[36]; char sign = '\0'; int chrs = 0; @@ -352,11 +378,17 @@ int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, c sign = ' '; } - int len = mp_format_float(f, buf, sizeof(buf), fmt, prec, sign); + int len = mp_format_float(f, buf, sizeof(buf) - 3, fmt, prec, sign); char *s = buf; - if ((flags & PF_FLAG_ADD_PERCENT) && (size_t)(len + 1) < sizeof(buf)) { + if ((flags & PF_FLAG_ALWAYS_DECIMAL) && strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) { + buf[len++] = '.'; + buf[len++] = '0'; + buf[len] = '\0'; + } + + if (flags & PF_FLAG_ADD_PERCENT) { buf[len++] = '%'; buf[len] = '\0'; } @@ -376,14 +408,6 @@ int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, c } #endif -// CIRCUITPY-CHANGE -static int print_str_common(const mp_print_t *print, const char *str, int prec, size_t len, int flags, int fill, int width) { - if (prec >= 0 && (size_t)prec < len) { - len = prec; - } - return mp_print_strn(print, str, len, flags, fill, width); -} - int mp_printf(const mp_print_t *print, const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -424,8 +448,6 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { flags |= PF_FLAG_SHOW_SIGN; } else if (*fmt == ' ') { flags |= PF_FLAG_SPACE_SIGN; - } else if (*fmt == '!') { - flags |= PF_FLAG_NO_TRAILZ; } else if (*fmt == '0') { flags |= PF_FLAG_PAD_AFTER_SIGN; fill = '0'; @@ -459,16 +481,36 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { } } - // parse long specifiers (only for LP64 model where they make a difference) - #ifndef __LP64__ - const + // parse long and long long specifiers (only where they make a difference) + #if (MP_INT_MAX > INT_MAX && MP_INT_MAX == LONG_MAX) || defined(MICROPY_UNIX_COVERAGE) + #define SUPPORT_L_FORMAT (1) + #else + #define SUPPORT_L_FORMAT (0) #endif + #if SUPPORT_L_FORMAT bool long_arg = false; + #endif + + #if (MP_INT_MAX > LONG_MAX) || defined(MICROPY_UNIX_COVERAGE) + #define SUPPORT_LL_FORMAT (1) + #else + #define SUPPORT_LL_FORMAT (0) + #endif + #if SUPPORT_LL_FORMAT + bool long_long_arg = false; + #endif + if (*fmt == 'l') { ++fmt; - #ifdef __LP64__ + #if SUPPORT_L_FORMAT long_arg = true; #endif + #if SUPPORT_LL_FORMAT + if (*fmt == 'l') { + ++fmt; + long_long_arg = true; + } + #endif } if (*fmt == '\0') { @@ -492,27 +534,19 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { qstr qst = va_arg(args, qstr); size_t len; const char *str = (const char *)qstr_data(qst, &len); - // CIRCUITPY-CHANGE - chrs += print_str_common(print, str, prec, len, flags, fill, width); - break; - } - // CIRCUITPY-CHANGE: new code to print compressed strings - case 'S': { - mp_rom_error_text_t arg = va_arg(args, mp_rom_error_text_t); - size_t len_with_nul = decompress_length(arg); - size_t len = len_with_nul - 1; - char str[len_with_nul]; - decompress(arg, str); - chrs += print_str_common(print, str, prec, len, flags, fill, width); + if (prec >= 0 && (size_t)prec < len) { + len = prec; + } + chrs += mp_print_strn(print, str, len, flags, fill, width); break; } case 's': { const char *str = va_arg(args, const char *); #ifndef NDEBUG // With debugging enabled, catch printing of null string pointers - if (str == NULL) { - // CIRCUITPY-CHANGE - str = "(null)"; + if (prec != 0 && str == NULL) { + chrs += mp_print_strn(print, "(null)", 6, flags, fill, width); + break; } #endif size_t len = strlen(str); @@ -522,41 +556,58 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { chrs += mp_print_strn(print, str, len, flags, fill, width); break; } - case 'd': { - mp_int_t val; - if (long_arg) { - val = va_arg(args, long int); - } else { - val = va_arg(args, int); - } - chrs += mp_print_int(print, val, 1, 10, 'a', flags, fill, width); - break; - } + case 'd': + case 'p': + case 'P': case 'u': case 'x': case 'X': { - int base = 16 - ((*fmt + 1) & 6); // maps char u/x/X to base 10/16/16 - char fmt_c = (*fmt & 0xf0) - 'P' + 'A'; // maps char u/x/X to char a/a/A + char fmt_chr = *fmt; mp_uint_t val; - if (long_arg) { - val = va_arg(args, unsigned long int); + if (fmt_chr == 'p' || fmt_chr == 'P') { + val = va_arg(args, uintptr_t); + } + #if SUPPORT_LL_FORMAT + else if (long_long_arg) { + val = va_arg(args, unsigned long long); + } + #endif + #if SUPPORT_L_FORMAT + else if (long_arg) { + if (sizeof(long) != sizeof(mp_uint_t) && fmt_chr == 'd') { + val = va_arg(args, long); + } else { + val = va_arg(args, unsigned long); + } + } + #endif + else { + if (sizeof(int) != sizeof(mp_uint_t) && fmt_chr == 'd') { + val = va_arg(args, int); + } else { + val = va_arg(args, unsigned); + } + } + int base; + // Map format char x/p/X/P to a/a/A/A for hex letters. + // It doesn't matter what d/u map to. + char fmt_c = (fmt_chr & 0xf0) - 'P' + 'A'; + if (fmt_chr == 'd' || fmt_chr == 'u') { + base = 10; } else { - val = va_arg(args, unsigned int); + base = 16; + } + // CIRCUITPY-CHANGE: include "0x" for 'p' and 'P'. + if (fmt_chr == 'p' || fmt_chr == 'P') { + #if SUPPORT_INT_BASE_PREFIX + chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags | PF_FLAG_SHOW_PREFIX, fill, width); + #else + chrs += mp_print_strn(print, "0x", 2, flags, fill, width); + #endif } - chrs += mp_print_int(print, val, 0, base, fmt_c, flags, fill, width); + chrs += mp_print_int(print, val, fmt_chr == 'd', base, fmt_c, flags, fill, width); break; } - case 'p': - case 'P': // don't bother to handle upcase for 'P' - // Use unsigned long int to work on both ILP32 and LP64 systems - // CIRCUITPY-CHANGE: print 0x prefix - #if SUPPORT_INT_BASE_PREFIX - chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags | PF_FLAG_SHOW_PREFIX, fill, width); - #else - print->print_strn(print->data, "0x", 2); - chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width) + 2; - #endif - break; #if MICROPY_PY_BUILTINS_FLOAT case 'e': case 'E': @@ -573,18 +624,21 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { break; } #endif - // Because 'l' is eaten above, another 'l' means %ll. We need to support - // this length specifier for OBJ_REPR_D (64-bit NaN boxing). - // TODO Either enable this unconditionally, or provide a specific config var. - #if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64) - case 'l': { - unsigned long long int arg_value = va_arg(args, unsigned long long int); - ++fmt; - assert(*fmt == 'u' || *fmt == 'd' || !"unsupported fmt char"); - chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width); + + // CIRCUITPY-CHANGE: new format code to print compressed strings + case 'S': { + mp_rom_error_text_t arg = va_arg(args, mp_rom_error_text_t); + size_t len_with_nul = decompress_length(arg); + size_t len = len_with_nul - 1; + char str[len_with_nul]; + decompress(arg, str); + if (prec >= 0 && (size_t)prec < len) { + len = prec; + } + chrs += mp_print_strn(print, str, len, flags, fill, width); break; } - #endif + default: // if it's not %% then it's an unsupported format character assert(*fmt == '%' || !"unsupported fmt char"); diff --git a/py/mpprint.h b/py/mpprint.h index e883cc27047..614c61ea415 100644 --- a/py/mpprint.h +++ b/py/mpprint.h @@ -31,13 +31,13 @@ #define PF_FLAG_LEFT_ADJUST (0x001) #define PF_FLAG_SHOW_SIGN (0x002) #define PF_FLAG_SPACE_SIGN (0x004) -#define PF_FLAG_NO_TRAILZ (0x008) -#define PF_FLAG_SHOW_PREFIX (0x010) -#define PF_FLAG_SHOW_COMMA (0x020) -#define PF_FLAG_PAD_AFTER_SIGN (0x040) -#define PF_FLAG_CENTER_ADJUST (0x080) -#define PF_FLAG_ADD_PERCENT (0x100) -#define PF_FLAG_SHOW_OCTAL_LETTER (0x200) +#define PF_FLAG_SHOW_PREFIX (0x008) +#define PF_FLAG_PAD_AFTER_SIGN (0x010) +#define PF_FLAG_CENTER_ADJUST (0x020) +#define PF_FLAG_ADD_PERCENT (0x040) +#define PF_FLAG_SHOW_OCTAL_LETTER (0x080) +#define PF_FLAG_ALWAYS_DECIMAL (0x100) +#define PF_FLAG_SEP_POS (9) // must be above all the above PF_FLAGs #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES #define MP_PYTHON_PRINTER &mp_sys_stdout_print @@ -69,9 +69,9 @@ extern const mp_print_t mp_sys_stdout_print; #endif int mp_print_str(const mp_print_t *print, const char *str); -int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width); +int mp_print_strn(const mp_print_t *print, const char *str, size_t len, unsigned int flags, char fill, int width); #if MICROPY_PY_BUILTINS_FLOAT -int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec); +int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, unsigned int flags, char fill, int width, int prec); #endif int mp_printf(const mp_print_t *print, const char *fmt, ...); diff --git a/py/mpstate.h b/py/mpstate.h index 4c48e9edaf4..25685334a4c 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -71,9 +71,18 @@ enum { // This structure contains dynamic configuration for the compiler. #if MICROPY_DYNAMIC_COMPILER typedef struct mp_dynamic_compiler_t { + // This is used to let mpy-cross pass options to the emitter chosen with + // `native_arch`. The main use case for the time being is to give the + // RV32 emitter extended information about which extensions can be + // optionally used, in order to generate code that's better suited for the + // hardware platform the code will run on. + void *backend_options; uint8_t small_int_bits; // must be <= host small_int_bits uint8_t native_arch; uint8_t nlr_buf_num_regs; + #if MICROPY_ENABLE_SOURCE_LINE + bool include_source_lines; + #endif } mp_dynamic_compiler_t; extern mp_dynamic_compiler_t mp_dynamic_compiler; #endif @@ -116,6 +125,9 @@ typedef struct _mp_state_mem_area_t { #if MICROPY_ENABLE_SELECTIVE_COLLECT byte *gc_collect_table_start; #endif + #if MICROPY_PY_WEAKREF + byte *gc_weakref_table_start; + #endif byte *gc_pool_start; byte *gc_pool_end; @@ -132,6 +144,10 @@ typedef struct _mp_state_mem_t { #endif mp_state_mem_area_t area; + #if MICROPY_GC_SPLIT_HEAP + byte *area_pool_min; // Min of all gc_pool_start values across all areas + byte *area_pool_max; // Max of all gc_pool_end values across all areas + #endif int gc_stack_overflow; MICROPY_GC_STACK_ENTRY_TYPE gc_block_stack[MICROPY_ALLOC_GC_STACK_SIZE]; @@ -245,6 +261,9 @@ typedef struct _mp_state_vm_t { #if MICROPY_EMIT_NATIVE uint8_t default_emit_opt; // one of MP_EMIT_OPT_xxx #endif + #if MICROPY_DEBUG_PRINTERS + mp_uint_t mp_verbose_flag; + #endif #endif // size of the emergency exception buf, if it's dynamically allocated @@ -369,4 +388,7 @@ extern mp_state_thread_t *mp_thread_get_state(void); #define mp_thread_is_main_thread() (true) #endif +// CIRCUITPY-CHANGE: defined in main.c +bool vm_is_running(void); + #endif // MICROPY_INCLUDED_PY_MPSTATE_H diff --git a/py/mpz.c b/py/mpz.c index 7d8bc03ca86..062777af566 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1360,7 +1360,7 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { can have dest, lhs, rhs the same; mod can't be the same as dest */ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) { - if (lhs->len == 0 || rhs->neg != 0 || (mod->len == 1 && mod->dig[0] == 1)) { + if (rhs->neg != 0 || (mod->len == 1 && mod->dig[0] == 1)) { mpz_set_from_int(dest, 0); return; } @@ -1368,6 +1368,15 @@ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t mpz_set_from_int(dest, 1); if (rhs->len == 0) { + // Python style modulo: 1 % mod is 1 + mod, as abs(mod) >= 2 here + if (mod->neg) { + mpz_add_inpl(dest, dest, mod); + } + return; + } + + if (lhs->len == 0) { + mpz_set_from_int(dest, 0); return; } @@ -1541,7 +1550,8 @@ mp_int_t mpz_hash(const mpz_t *z) { mp_uint_t val = 0; mpz_dig_t *d = z->dig + z->len; - while (d-- > z->dig) { + while (d > z->dig) { + d--; val = (val << DIG_SIZE) | *d; } @@ -1556,11 +1566,12 @@ bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) { mp_uint_t val = 0; mpz_dig_t *d = i->dig + i->len; - while (d-- > i->dig) { + while (d > i->dig) { if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> DIG_SIZE)) { // will overflow return false; } + d--; val = (val << DIG_SIZE) | *d; } @@ -1581,11 +1592,12 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) { mp_uint_t val = 0; mpz_dig_t *d = i->dig + i->len; - while (d-- > i->dig) { + while (d > i->dig) { if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) { // will overflow return false; } + d--; val = (val << DIG_SIZE) | *d; } @@ -1599,16 +1611,17 @@ bool mpz_as_bytes(const mpz_t *z, bool big_endian, bool as_signed, size_t len, b b += len; } mpz_dig_t *zdig = z->dig; + byte fill_byte = z->neg ? 0xFF : 0x00; int bits = 0; mpz_dbl_dig_t d = 0; mpz_dbl_dig_t carry = 1; + mpz_dig_t val = 0; size_t olen = len; // bytes in output buffer - bool ok = true; for (size_t zlen = z->len; zlen > 0; --zlen) { bits += DIG_SIZE; d = (d << DIG_SIZE) | *zdig++; for (; bits >= 8; bits -= 8, d >>= 8) { - mpz_dig_t val = d; + val = d; if (z->neg) { val = (~val & 0xff) + carry; carry = val >> 8; @@ -1616,7 +1629,9 @@ bool mpz_as_bytes(const mpz_t *z, bool big_endian, bool as_signed, size_t len, b if (!olen) { // Buffer is full, only OK if all remaining bytes are zeroes - ok = ok && ((byte)val == 0); + if ((byte)val != fill_byte) { + return false; + } continue; } @@ -1629,16 +1644,17 @@ bool mpz_as_bytes(const mpz_t *z, bool big_endian, bool as_signed, size_t len, b } } - if (as_signed && olen == 0 && len > 0) { - // If output exhausted then ensure there was enough space for the sign bit - byte most_sig = big_endian ? buf[0] : buf[len - 1]; - ok = ok && (bool)(most_sig & 0x80) == (bool)z->neg; - } else { + // Check if the most significant bit is set incorrectly for a signed value + if (olen == 0 && as_signed && ((val & 0x80) != (fill_byte & 0x80))) { + return false; + } + + if (olen > 0) { // fill remainder of buf with zero/sign extension of the integer - memset(big_endian ? buf : b, z->neg ? 0xff : 0x00, olen); + memset(big_endian ? buf : b, fill_byte, olen); } - return ok; + return true; } #if MICROPY_PY_BUILTINS_FLOAT @@ -1646,7 +1662,8 @@ mp_float_t mpz_as_float(const mpz_t *i) { mp_float_t val = 0; mpz_dig_t *d = i->dig + i->len; - while (d-- > i->dig) { + while (d > i->dig) { + d--; val = val * DIG_BASE + *d; } @@ -1676,6 +1693,8 @@ size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, ch size_t ilen = i->len; + int n_comma = (base == 10) ? 3 : 4; + char *s = str; if (ilen == 0) { if (prefix) { @@ -1721,7 +1740,7 @@ size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, ch break; } } - if (!done && comma && (s - last_comma) == 3) { + if (!done && comma && (s - last_comma) == n_comma) { *s++ = comma; last_comma = s; } diff --git a/py/nativeglue.c b/py/nativeglue.c index 3b072ba8c38..c632cd36534 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -43,7 +43,7 @@ #define DEBUG_printf(...) (void)0 #endif -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE int mp_native_type_from_qstr(qstr qst) { switch (qst) { @@ -93,7 +93,7 @@ mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) { #endif -#if MICROPY_EMIT_MACHINE_CODE +#if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE // convert a native value to a MicroPython object based on type mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { @@ -117,7 +117,7 @@ mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { #endif -#if MICROPY_EMIT_NATIVE && !MICROPY_DYNAMIC_COMPILER +#if MICROPY_ENABLE_NATIVE_CODE && !MICROPY_DYNAMIC_COMPILER #if !MICROPY_PY_BUILTINS_SET mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) { @@ -323,7 +323,11 @@ const mp_fun_table_t mp_fun_table = { mp_printf, mp_vprintf, // CIRCUITPY-CHANGE: mp_raise_msg_str instead of mp_raise_msg + #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE + NULL, + #else mp_raise_msg_str, + #endif mp_obj_get_type, mp_obj_new_str, mp_obj_new_bytes, @@ -359,8 +363,8 @@ const mp_fun_table_t mp_fun_table = { &mp_stream_write_obj, }; -#elif MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER +#elif MICROPY_ENABLE_NATIVE_CODE && MICROPY_DYNAMIC_COMPILER const int mp_fun_table; -#endif // MICROPY_EMIT_NATIVE +#endif // MICROPY_ENABLE_NATIVE_CODE diff --git a/py/nativeglue.h b/py/nativeglue.h index 00ed9f3f4fc..f6ba600c99f 100644 --- a/py/nativeglue.h +++ b/py/nativeglue.h @@ -143,7 +143,7 @@ typedef struct _mp_fun_table_t { int (*printf_)(const mp_print_t *print, const char *fmt, ...); int (*vprintf_)(const mp_print_t *print, const char *fmt, va_list args); #if defined(__GNUC__) - NORETURN // Only certain compilers support no-return attributes in function pointer declarations + MP_NORETURN // Only certain compilers support no-return attributes in function pointer declarations #endif // CIRCUITPY-CHANGE: raise_msg_str instead of raise_msg void (*raise_msg_str)(const mp_obj_type_t *exc_type, const char *msg); @@ -184,9 +184,9 @@ typedef struct _mp_fun_table_t { const mp_obj_fun_builtin_var_t *stream_write_obj; } mp_fun_table_t; -#if (MICROPY_EMIT_NATIVE && !MICROPY_DYNAMIC_COMPILER) || MICROPY_ENABLE_DYNRUNTIME +#if (MICROPY_ENABLE_NATIVE_CODE && !MICROPY_DYNAMIC_COMPILER) || MICROPY_ENABLE_DYNRUNTIME extern const mp_fun_table_t mp_fun_table; -#elif MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER +#elif MICROPY_ENABLE_NATIVE_CODE && MICROPY_DYNAMIC_COMPILER // In dynamic-compiler mode eliminate dependency on entries in mp_fun_table. // This only needs to be an independent pointer, content doesn't matter. extern const int mp_fun_table; diff --git a/py/nlr.c b/py/nlr.c index 7ab0c0955a2..de2a38ceff3 100644 --- a/py/nlr.c +++ b/py/nlr.c @@ -81,7 +81,7 @@ void nlr_call_jump_callbacks(nlr_buf_t *nlr) { } #if MICROPY_ENABLE_VM_ABORT -NORETURN void nlr_jump_abort(void) { +MP_NORETURN void nlr_jump_abort(void) { MP_STATE_THREAD(nlr_top) = MP_STATE_VM(nlr_abort); nlr_jump(NULL); } diff --git a/py/nlr.h b/py/nlr.h index 340627b7aa1..72ea1368e93 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -46,6 +46,7 @@ #define MICROPY_NLR_NUM_REGS_XTENSAWIN (17) #define MICROPY_NLR_NUM_REGS_RV32I (14) #define MICROPY_NLR_NUM_REGS_RV64I (14) +#define MICROPY_NLR_NUM_REGS_LOONG64 (13) // *FORMAT-OFF* @@ -111,6 +112,13 @@ #else #error Unsupported RISC-V variant. #endif +#elif defined(__loongarch__) + #if defined(__loongarch64) + #define MICROPY_NLR_LOONG64 (1) + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_LOONG64) + #else + #error Unsupported Loongarch variant. + #endif #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" @@ -122,6 +130,10 @@ #define MICROPY_NLR_AARCH64 (0) #endif +#ifndef MICROPY_NLR_LOONG64 +#define MICROPY_NLR_LOONG64 (0) +#endif + #ifndef MICROPY_NLR_MIPS #define MICROPY_NLR_MIPS (0) #endif @@ -233,18 +245,18 @@ unsigned int nlr_push(nlr_buf_t *); unsigned int nlr_push_tail(nlr_buf_t *top); void nlr_pop(void); -NORETURN void nlr_jump(void *val); +MP_NORETURN void nlr_jump(void *val); #if MICROPY_ENABLE_VM_ABORT #define nlr_set_abort(buf) MP_STATE_VM(nlr_abort) = buf #define nlr_get_abort() MP_STATE_VM(nlr_abort) -NORETURN void nlr_jump_abort(void); +MP_NORETURN void nlr_jump_abort(void); #endif // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather // should bail out with a fatal error. -NORETURN void nlr_jump_fail(void *val); +MP_NORETURN void nlr_jump_fail(void *val); // use nlr_raise instead of nlr_jump so that debugging is easier #ifndef MICROPY_DEBUG_NLR diff --git a/py/nlraarch64.c b/py/nlraarch64.c index d6d87ebc50d..3318004b5e0 100644 --- a/py/nlraarch64.c +++ b/py/nlraarch64.c @@ -56,7 +56,7 @@ __asm( #endif ); -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) MP_STATIC_ASSERT(offsetof(nlr_buf_t, regs) == 16); // asm assumes it diff --git a/py/nlrloong64.c b/py/nlrloong64.c new file mode 100644 index 00000000000..7a12b2ec904 --- /dev/null +++ b/py/nlrloong64.c @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2026 Alessandro Gatti + * + * 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/mpstate.h" + +#if MICROPY_NLR_LOONG64 + +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); + +__asm( + ".globl nlr_push \n" + "nlr_push: \n" + ".cfi_startproc \n" + "st.d $r1, $r4, 16 \n" /* Store RA. */ + "st.d $r23, $r4, 24 \n" /* Store S0. */ + "st.d $r24, $r4, 32 \n" /* Store S1. */ + "st.d $r25, $r4, 40 \n" /* Store S2. */ + "st.d $r26, $r4, 48 \n" /* Store S3. */ + "st.d $r27, $r4, 56 \n" /* Store S4. */ + "st.d $r28, $r4, 64 \n" /* Store S5. */ + "st.d $r29, $r4, 72 \n" /* Store S6. */ + "st.d $r30, $r4, 80 \n" /* Store S7. */ + "st.d $r31, $r4, 88 \n" /* Store S8. */ + "st.d $r22, $r4, 96 \n" /* Store S9. */ + "st.d $r21, $r4, 104 \n" /* Marked as reserved in the ABI. */ + "st.d $r3, $r4, 112 \n" /* Store SP. */ + "b nlr_push_tail \n" /* Jump to the C part. */ + ".cfi_endproc \n" + ); + +MP_NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + __asm volatile ( + "add.d $r4, $r0, %0 \n" + "ld.d $r1, $r4, 16 \n" /* Retrieve RA. */ + "ld.d $r23, $r4, 24 \n" /* Retrieve S0. */ + "ld.d $r24, $r4, 32 \n" /* Retrieve S1. */ + "ld.d $r25, $r4, 40 \n" /* Retrieve S2. */ + "ld.d $r26, $r4, 48 \n" /* Retrieve S3. */ + "ld.d $r27, $r4, 56 \n" /* Retrieve S4. */ + "ld.d $r28, $r4, 64 \n" /* Retrieve S5. */ + "ld.d $r29, $r4, 72 \n" /* Retrieve S6. */ + "ld.d $r30, $r4, 80 \n" /* Retrieve S7. */ + "ld.d $r31, $r4, 88 \n" /* Retrieve S8. */ + "ld.d $r22, $r4, 96 \n" /* Retrieve S9. */ + "ld.d $r21, $r4, 104 \n" + "ld.d $r3, $r4, 112 \n" /* Retrieve SP. */ + "addi.d $r4, $r0, 1 \n" /* Return 1 for a non-local return. */ + "ret \n" /* Return. */ + : + : "r" (top) + : "memory" + ); + MP_UNREACHABLE +} + +#endif diff --git a/py/nlrmips.c b/py/nlrmips.c index cba52b16a26..5c55db7e268 100644 --- a/py/nlrmips.c +++ b/py/nlrmips.c @@ -57,7 +57,7 @@ __asm( ".end nlr_push \n" ); -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm( "move $4, %0 \n" diff --git a/py/nlrpowerpc.c b/py/nlrpowerpc.c index 8a69fe1eeca..cb94473968d 100644 --- a/py/nlrpowerpc.c +++ b/py/nlrpowerpc.c @@ -72,43 +72,44 @@ unsigned int nlr_push(nlr_buf_t *nlr) { "bctr ;" : : "r" (&nlr->regs), "r" (nlr) - : + : "r4" ); return 0; } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm__ volatile ( - "ld 3, 0x0(%0) ;" + "mr 4, %0 ;" + "ld 3, 0x0(4) ;" "cmpdi 3, 0x4eed ; " // Check canary "bne . ; " - "ld 0, 0x08(%0) ;" - "ld 1, 0x10(%0) ;" - "ld 2, 0x18(%0) ;" - "ld 14, 0x20(%0) ;" - "ld 15, 0x28(%0) ;" - "ld 16, 0x30(%0) ;" - "ld 17, 0x38(%0) ;" - "ld 18, 0x40(%0) ;" - "ld 19, 0x48(%0) ;" - "ld 20, 0x50(%0) ;" - "ld 21, 0x58(%0) ;" - "ld 22, 0x60(%0) ;" - "ld 23, 0x68(%0) ;" - "ld 24, 0x70(%0) ;" - "ld 25, 0x78(%0) ;" - "ld 26, 0x80(%0) ;" - "ld 27, 0x88(%0) ;" - "ld 28, 0x90(%0) ;" - "ld 29, 0x98(%0) ;" - "ld 30, 0xA0(%0) ;" - "ld 31, 0xA8(%0) ;" - "ld 3, 0xB0(%0) ;" + "ld 0, 0x08(4) ;" + "ld 1, 0x10(4) ;" + "ld 2, 0x18(4) ;" + "ld 14, 0x20(4) ;" + "ld 15, 0x28(4) ;" + "ld 16, 0x30(4) ;" + "ld 17, 0x38(4) ;" + "ld 18, 0x40(4) ;" + "ld 19, 0x48(4) ;" + "ld 20, 0x50(4) ;" + "ld 21, 0x58(4) ;" + "ld 22, 0x60(4) ;" + "ld 23, 0x68(4) ;" + "ld 24, 0x70(4) ;" + "ld 25, 0x78(4) ;" + "ld 26, 0x80(4) ;" + "ld 27, 0x88(4) ;" + "ld 28, 0x90(4) ;" + "ld 29, 0x98(4) ;" + "ld 30, 0xA0(4) ;" + "ld 31, 0xA8(4) ;" + "ld 3, 0xB0(4) ;" "mtcr 3 ;" - "ld 3, 0xB8(%0) ;" + "ld 3, 0xB8(4) ;" "mtlr 3 ; " "li 3, 1;" "blr ;" @@ -161,43 +162,44 @@ unsigned int nlr_push(nlr_buf_t *nlr) { "bctr ;" : : "r" (&nlr->regs), "r" (nlr) - : + : "r4" ); return 0; } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm__ volatile ( - "l 3, 0x0(%0) ;" + "mr 4, %0 ;" + "l 3, 0x0(4) ;" "cmpdi 3, 0x4eed ; " // Check canary "bne . ; " - "l 0, 0x04(%0) ;" - "l 1, 0x08(%0) ;" - "l 2, 0x0c(%0) ;" - "l 14, 0x10(%0) ;" - "l 15, 0x14(%0) ;" - "l 16, 0x18(%0) ;" - "l 17, 0x1c(%0) ;" - "l 18, 0x20(%0) ;" - "l 19, 0x24(%0) ;" - "l 20, 0x28(%0) ;" - "l 21, 0x2c(%0) ;" - "l 22, 0x30(%0) ;" - "l 23, 0x34(%0) ;" - "l 24, 0x38(%0) ;" - "l 25, 0x3c(%0) ;" - "l 26, 0x40(%0) ;" - "l 27, 0x44(%0) ;" - "l 28, 0x48(%0) ;" - "l 29, 0x4c(%0) ;" - "l 30, 0x50(%0) ;" - "l 31, 0x54(%0) ;" - "l 3, 0x58(%0) ;" + "l 0, 0x04(4) ;" + "l 1, 0x08(4) ;" + "l 2, 0x0c(4) ;" + "l 14, 0x10(4) ;" + "l 15, 0x14(4) ;" + "l 16, 0x18(4) ;" + "l 17, 0x1c(4) ;" + "l 18, 0x20(4) ;" + "l 19, 0x24(4) ;" + "l 20, 0x28(4) ;" + "l 21, 0x2c(4) ;" + "l 22, 0x30(4) ;" + "l 23, 0x34(4) ;" + "l 24, 0x38(4) ;" + "l 25, 0x3c(4) ;" + "l 26, 0x40(4) ;" + "l 27, 0x44(4) ;" + "l 28, 0x48(4) ;" + "l 29, 0x4c(4) ;" + "l 30, 0x50(4) ;" + "l 31, 0x54(4) ;" + "l 3, 0x58(4) ;" "mtcr 3 ;" - "l 3, 0x5c(%0) ;" + "l 3, 0x5c(4) ;" "mtlr 3 ; " "li 3, 1;" "blr ;" diff --git a/py/nlrrv32.c b/py/nlrrv32.c index 9a12ede400d..565a8629db5 100644 --- a/py/nlrrv32.c +++ b/py/nlrrv32.c @@ -50,7 +50,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { ); } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "add x10, x0, %0 \n" // Load nlr_buf address. diff --git a/py/nlrrv64.c b/py/nlrrv64.c index e7ba79797b8..b7d1467b8f6 100644 --- a/py/nlrrv64.c +++ b/py/nlrrv64.c @@ -50,7 +50,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { ); } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "add x10, x0, %0 \n" // Load nlr_buf address. diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 0aa1f053a23..1791d8b4929 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -36,8 +36,7 @@ // For reference, arm/thumb callee save regs are: // r4-r11, r13=sp -// CIRCUITPY-CHANGE: added returns_twice -__attribute__((naked, returns_twice)) unsigned int nlr_push(nlr_buf_t *nlr) { +__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { // If you get a linker error here, indicating that a relocation doesn't // fit, try the following (in that order): @@ -92,6 +91,10 @@ __attribute__((naked, returns_twice)) unsigned int nlr_push(nlr_buf_t *nlr) { "b nlr_push_tail \n" // do the rest in C #endif #endif + // CIRCUITPY-CHANGE: add input and clobbers to prevent smashing registers. + : // output operands + : "r" (nlr) // input operands + : "r1", "r2", "r3" // clobbers ); #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) @@ -101,7 +104,7 @@ __attribute__((naked, returns_twice)) unsigned int nlr_push(nlr_buf_t *nlr) { #endif } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( @@ -141,7 +144,8 @@ NORETURN void nlr_jump(void *val) { "bx lr \n" // return : // output operands : "r" (top) // input operands - : "memory" // clobbered registers + // CIRCUITPY-CHANGE: better comment + : "memory" // clobbers ); MP_UNREACHABLE diff --git a/py/nlrx64.c b/py/nlrx64.c index d1ad91ff7d7..51224729fc9 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -100,7 +100,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { #endif } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( diff --git a/py/nlrx86.c b/py/nlrx86.c index 085e30d2034..82e139dd8e8 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -40,23 +40,35 @@ __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); #endif #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 8 -// Since gcc 8.0 the naked attribute is supported -#define USE_NAKED (1) -#define UNDO_PRELUDE (0) +// Since gcc 8.0 the naked and no-sanitize attributes are supported + #define NLR_PUSH_ATTRIBUTE __attribute__((naked, no_sanitize("unreachable"))) + #define UNDO_PRELUDE (0) + #define ARG_USED(x) (void)x; + #define NLR_UNREACHABLE __builtin_unreachable(); #elif defined(__ZEPHYR__) || defined(__ANDROID__) // Zephyr and Android use a different calling convention by default -#define USE_NAKED (0) -#define UNDO_PRELUDE (0) + #define NLR_PUSH_ATTRIBUTE /* NOTHING */ + #define UNDO_PRELUDE (0) + #define ARG_USED(x) (void)x; + #define NLR_UNREACHABLE return 0; +#elif defined(__clang__) +// clang on Ubuntu 24.04 enables -fsanitize=unreachable by default, but this +// destroys the content of the ebx register. + #define NLR_PUSH_ATTRIBUTE __attribute__((naked, no_sanitize("unreachable"))) + #define UNDO_PRELUDE (0) + #define ARG_USED(x) /* NOTHING */ + #define NLR_UNREACHABLE /* NOTHING */ #else -#define USE_NAKED (0) -#define UNDO_PRELUDE (1) +// gcc before 8 unavoidably emits a 'push %ebp' prologue instruction + #define NLR_PUSH_ATTRIBUTE /* NOTHING */ + #define UNDO_PRELUDE (1) + #define ARG_USED(x) (void)x; + #define NLR_UNREACHABLE return 0; #endif -#if USE_NAKED -__attribute__((naked)) -#endif +NLR_PUSH_ATTRIBUTE unsigned int nlr_push(nlr_buf_t *nlr) { - (void)nlr; + ARG_USED(nlr) __asm volatile ( #if UNDO_PRELUDE @@ -73,12 +85,10 @@ unsigned int nlr_push(nlr_buf_t *nlr) { "jmp nlr_push_tail \n" // do the rest in C ); - #if !USE_NAKED - return 0; // needed to silence compiler warning - #endif + NLR_UNREACHABLE } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index ff7af6edeef..2d1bf35e381 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -55,7 +55,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( diff --git a/py/obj.c b/py/obj.c index 29ae76557f8..b65ac53d23a 100644 --- a/py/obj.c +++ b/py/obj.c @@ -157,7 +157,7 @@ void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t if (MP_OBJ_TYPE_HAS_SLOT(type, print)) { MP_OBJ_TYPE_GET_SLOT(type, print)((mp_print_t *)print, o_in, kind); } else { - mp_printf(print, "<%q>", type->name); + mp_printf(print, "<%q>", (qstr)type->name); } } @@ -417,6 +417,36 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) { return val; } +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE +mp_uint_t mp_obj_get_uint(mp_const_obj_t arg) { + if (!mp_obj_is_exact_type(arg, &mp_type_int)) { + mp_obj_t as_int = mp_unary_op(MP_UNARY_OP_INT_MAYBE, (mp_obj_t)arg); + if (as_int == MP_OBJ_NULL) { + mp_raise_TypeError_int_conversion(arg); + } + arg = as_int; + } + return mp_obj_int_get_uint_checked(arg); +} + +long long mp_obj_get_ll(mp_const_obj_t arg) { + if (!mp_obj_is_exact_type(arg, &mp_type_int)) { + mp_obj_t as_int = mp_unary_op(MP_UNARY_OP_INT_MAYBE, (mp_obj_t)arg); + if (as_int == MP_OBJ_NULL) { + mp_raise_TypeError_int_conversion(arg); + } + arg = as_int; + } + if (mp_obj_is_small_int(arg)) { + return MP_OBJ_SMALL_INT_VALUE(arg); + } else { + long long res; + mp_obj_int_to_bytes((mp_obj_t)arg, sizeof(res), (byte *)&res, MP_ENDIANNESS_BIG, false, false); + return res; + } +} +#endif + mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) { if (mp_obj_is_int(arg)) { return mp_obj_int_get_truncated(arg); diff --git a/py/obj.h b/py/obj.h index 38db17cba44..368ac96dbd2 100644 --- a/py/obj.h +++ b/py/obj.h @@ -117,7 +117,7 @@ extern const struct _mp_obj_float_t mp_const_float_inf_obj; extern const struct _mp_obj_float_t mp_const_float_nan_obj; #endif -#define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float) +#define mp_obj_is_float(o) mp_obj_is_exact_type((o), &mp_type_float) mp_float_t mp_obj_float_get(mp_obj_t self_in); mp_obj_t mp_obj_new_float(mp_float_t value); #endif @@ -162,7 +162,7 @@ extern const struct _mp_obj_float_t mp_const_float_inf_obj; extern const struct _mp_obj_float_t mp_const_float_nan_obj; #endif -#define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float) +#define mp_obj_is_float(o) mp_obj_is_exact_type((o), &mp_type_float) mp_float_t mp_obj_float_get(mp_obj_t self_in); mp_obj_t mp_obj_new_float(mp_float_t value); #endif @@ -184,13 +184,15 @@ static inline bool mp_obj_is_small_int(mp_const_obj_t o) { #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) #if MICROPY_PY_BUILTINS_FLOAT -#define MP_OBJ_NEW_CONST_FLOAT(f) MP_ROM_PTR((mp_obj_t)((((((uint64_t)f) & ~3) | 2) + 0x80800000) & 0xffffffff)) +#include +// note: MP_OBJ_NEW_CONST_FLOAT should be a MP_ROM_PTR but that macro isn't available yet +#define MP_OBJ_NEW_CONST_FLOAT(f) ((mp_obj_t)((((((uint64_t)f) & ~3) | 2) + 0x80800000) & 0xffffffff)) #define mp_const_float_e MP_OBJ_NEW_CONST_FLOAT(0x402df854) #define mp_const_float_pi MP_OBJ_NEW_CONST_FLOAT(0x40490fdb) +#define mp_const_float_nan MP_OBJ_NEW_CONST_FLOAT(0x7fc00000) #if MICROPY_PY_MATH_CONSTANTS #define mp_const_float_tau MP_OBJ_NEW_CONST_FLOAT(0x40c90fdb) #define mp_const_float_inf MP_OBJ_NEW_CONST_FLOAT(0x7f800000) -#define mp_const_float_nan MP_OBJ_NEW_CONST_FLOAT(0xffc00000) #endif static inline bool mp_obj_is_float(mp_const_obj_t o) { @@ -204,9 +206,17 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) { mp_float_t f; mp_uint_t u; } num = {.u = ((mp_uint_t)o - 0x80800000u) & ~3u}; + // Rather than always truncating toward zero, which creates a strong + // bias, copy the two previous bits to fill in the two missing bits. + // This appears to be a pretty good heuristic. + num.u |= (num.u >> 2) & 3u; return num.f; } static inline mp_obj_t mp_obj_new_float(mp_float_t f) { + if (isnan(f)) { + // prevent creation of bad nanboxed pointers via array.array or struct + return mp_const_float_nan; + } union { mp_float_t f; mp_uint_t u; @@ -257,8 +267,10 @@ static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) { #error MICROPY_OBJ_REPR_D requires MICROPY_FLOAT_IMPL_DOUBLE #endif +#include #define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))} #define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))} +#define mp_const_float_nan {((mp_obj_t)((uint64_t)0x7ff8000000000000 + 0x8004000000000000))} #if MICROPY_PY_MATH_CONSTANTS #define mp_const_float_tau {((mp_obj_t)((uint64_t)0x401921fb54442d18 + 0x8004000000000000))} #define mp_const_float_inf {((mp_obj_t)((uint64_t)0x7ff0000000000000 + 0x8004000000000000))} @@ -276,6 +288,13 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) { return num.f; } static inline mp_obj_t mp_obj_new_float(mp_float_t f) { + if (isnan(f)) { + // prevent creation of bad nanboxed pointers via array.array or struct + struct { + uint64_t r; + } num = mp_const_float_nan; + return num.r; + } union { mp_float_t f; uint64_t r; @@ -371,25 +390,25 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; #define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed_t obj_name = \ - {{&mp_type_fun_builtin_0}, .fun._0 = fun_name} + {.base = {.type = &mp_type_fun_builtin_0}, .fun = {._0 = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed_t obj_name = \ - {{&mp_type_fun_builtin_1}, .fun._1 = fun_name} + {.base = {.type = &mp_type_fun_builtin_1}, .fun = {._1 = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed_t obj_name = \ - {{&mp_type_fun_builtin_2}, .fun._2 = fun_name} + {.base = {.type = &mp_type_fun_builtin_2}, .fun = {._2 = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed_t obj_name = \ - {{&mp_type_fun_builtin_3}, .fun._3 = fun_name} + {.base = {.type = &mp_type_fun_builtin_3}, .fun = {._3 = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \ const mp_obj_fun_builtin_var_t obj_name = \ - {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, false), .fun.var = fun_name} + {.base = {.type = &mp_type_fun_builtin_var}, .sig = MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, false), .fun = {.var = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \ const mp_obj_fun_builtin_var_t obj_name = \ - {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun.var = fun_name} + {.base = {.type = &mp_type_fun_builtin_var}, .sig = MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun = {.var = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \ const mp_obj_fun_builtin_var_t obj_name = \ - {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name} + {.base = {.type = &mp_type_fun_builtin_var}, .sig = MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun = {.kw = fun_name}} // CIRCUITPY-CHANGE #define MP_DEFINE_CONST_PROP_GET(obj_name, fun_name) \ @@ -516,9 +535,7 @@ static inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) { void mp_map_init(mp_map_t *map, size_t n); void mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table); -mp_map_t *mp_map_new(size_t n); void mp_map_deinit(mp_map_t *map); -void mp_map_free(mp_map_t *map); mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); void mp_map_clear(mp_map_t *map); void mp_map_dump(mp_map_t *map); @@ -555,6 +572,10 @@ typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *); typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); // Flags for type behaviour (mp_obj_type_t.flags) +// If MP_TYPE_FLAG_IS_SUBCLASSED is set, then subclasses of this class have been created. +// Mutations to this class that would require updating all subclasses must be rejected. +// If MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS is set, then attribute lookups involving this +// class need to additionally check for special accessor methods, such as from descriptors. // If MP_TYPE_FLAG_EQ_NOT_REFLEXIVE is clear then __eq__ is reflexive (A==A returns True). // If MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE is clear then the type can't be equal to an // instance of any different class that also clears this flag. If this flag is set @@ -572,6 +593,8 @@ typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); // If MP_TYPE_FLAG_ITER_IS_STREAM is set then the type implicitly gets a "return self" // getiter, and mp_stream_unbuffered_iter for iternext. // If MP_TYPE_FLAG_INSTANCE_TYPE is set then this is an instance type (i.e. defined in Python). +// If MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE is set then the "subscr" slot allows a stack +// allocated slice to be passed in (no references to it will be retained after the call). #define MP_TYPE_FLAG_NONE (0x0000) #define MP_TYPE_FLAG_IS_SUBCLASSED (0x0001) #define MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002) @@ -585,8 +608,9 @@ typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); #define MP_TYPE_FLAG_ITER_IS_CUSTOM (0x0100) #define MP_TYPE_FLAG_ITER_IS_STREAM (MP_TYPE_FLAG_ITER_IS_ITERNEXT | MP_TYPE_FLAG_ITER_IS_CUSTOM) #define MP_TYPE_FLAG_INSTANCE_TYPE (0x0200) +#define MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE (0x0400) // CIRCUITPY-CHANGE: check for valid types in json dumps -#define MP_TYPE_FLAG_PRINT_JSON (0x0400) +#define MP_TYPE_FLAG_PRINT_JSON (0x0800) typedef enum { PRINT_STR = 0, @@ -787,25 +811,6 @@ typedef struct _mp_obj_full_type_t { #define _MP_OBJ_TYPE_SLOT_TYPE_parent (const void *) #define _MP_OBJ_TYPE_SLOT_TYPE_locals_dict (struct _mp_obj_dict_t *) -// Implementation of MP_DEFINE_CONST_OBJ_TYPE for each number of arguments. -// Do not use these directly, instead use MP_DEFINE_CONST_OBJ_TYPE. -// Generated with: -// for i in range(13): -// print(f"#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_{i}(_struct_type, _typename, _name, _flags{''.join(f', f{j+1}, v{j+1}' for j in range(i))}) const _struct_type _typename = {{ .base = {{ &mp_type_type }}, .flags = _flags, .name = _name{''.join(f', .slot_index_##f{j+1} = {j+1}' for j in range(i))}{', .slots = { ' + ''.join(f'v{j+1}, ' for j in range(i)) + '}' if i else '' } }}") -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_0(_struct_type, _typename, _name, _flags) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_1(_struct_type, _typename, _name, _flags, f1, v1) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slots = { v1, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_2(_struct_type, _typename, _name, _flags, f1, v1, f2, v2) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slots = { v1, v2, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_3(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slots = { v1, v2, v3, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_4(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slots = { v1, v2, v3, v4, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_5(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slots = { v1, v2, v3, v4, v5, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_6(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slots = { v1, v2, v3, v4, v5, v6, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_7(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slots = { v1, v2, v3, v4, v5, v6, v7, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_8(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_9(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, v9, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_10(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slot_index_##f10 = 10, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_11(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10, f11, v11) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slot_index_##f10 = 10, .slot_index_##f11 = 11, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, } } -#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_12(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10, f11, v11, f12, v12) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slot_index_##f10 = 10, .slot_index_##f11 = 11, .slot_index_##f12 = 12, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, } } - // Because the mp_obj_type_t instances are in (zero-initialised) ROM, we take // slot_index_foo=0 to mean that the slot is unset. This also simplifies checking // if the slot is set. That means that we need to store index+1 in slot_index_foo @@ -819,6 +824,34 @@ typedef struct _mp_obj_full_type_t { #define MP_OBJ_TYPE_OFFSETOF_SLOT(f) (offsetof(mp_obj_type_t, slot_index_##f)) #define MP_OBJ_TYPE_HAS_SLOT_BY_OFFSET(t, offset) (*(uint8_t *)((char *)(t) + (offset)) != 0) +// Implementation of MP_DEFINE_CONST_OBJ_TYPE for each number of arguments. +// Do not use these directly, instead use MP_DEFINE_CONST_OBJ_TYPE. +// Generated with: +// for i in range(13): +// args = ['_struct_type', '_typename', '_name', '_flags'] +// struct = ['.base = { &mp_type_type }', '.flags = _flags', '.name = _name'] +// slots = [] +// for j in range(i): +// args += [f"f{j+1}", f"v{j+1}"] +// struct += [f".slot_index_##f{j+1} = {j+1}"] +// slots += [f"(const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f{j+1} v{j+1}"] +// if slots: +// struct += [f".slots = {{ {', '.join(slots)} }}"] +// print(f"#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_{i}({', '.join(args)}) const _struct_type _typename = {{ {', '.join(struct)} }}") +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_0(_struct_type, _typename, _name, _flags) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_1(_struct_type, _typename, _name, _flags, f1, v1) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_2(_struct_type, _typename, _name, _flags, f1, v1, f2, v2) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_3(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_4(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f4 v4 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_5(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f4 v4, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f5 v5 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_6(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f4 v4, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f5 v5, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f6 v6 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_7(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f4 v4, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f5 v5, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f6 v6, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f7 v7 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_8(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f4 v4, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f5 v5, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f6 v6, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f7 v7, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f8 v8 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_9(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f4 v4, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f5 v5, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f6 v6, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f7 v7, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f8 v8, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f9 v9 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_10(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slot_index_##f10 = 10, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f4 v4, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f5 v5, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f6 v6, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f7 v7, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f8 v8, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f9 v9, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f10 v10 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_11(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10, f11, v11) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slot_index_##f10 = 10, .slot_index_##f11 = 11, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f4 v4, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f5 v5, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f6 v6, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f7 v7, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f8 v8, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f9 v9, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f10 v10, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f11 v11 } } +#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_12(_struct_type, _typename, _name, _flags, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10, f11, v11, f12, v12) const _struct_type _typename = { .base = { &mp_type_type }, .flags = _flags, .name = _name, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slot_index_##f10 = 10, .slot_index_##f11 = 11, .slot_index_##f12 = 12, .slots = { (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f1 v1, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f2 v2, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f3 v3, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f4 v4, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f5 v5, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f6 v6, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f7 v7, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f8 v8, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f9 v9, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f10 v10, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f11 v11, (const void *)_MP_OBJ_TYPE_SLOT_TYPE_##f12 v12 } } + // Workaround for https://docs.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview?view=msvc-160#macro-arguments-are-unpacked #define MP_DEFINE_CONST_OBJ_TYPE_EXPAND(x) x @@ -827,7 +860,7 @@ typedef struct _mp_obj_full_type_t { #define MP_DEFINE_CONST_OBJ_TYPE_NARGS(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, N, ...) MP_DEFINE_CONST_OBJ_TYPE_NARGS_##N // This macros is used to define a object type in ROM. -// Invoke as MP_DEFINE_CONST_OBJ_TYPE(_typename, _name, _flags, _make_new [, slot, func]*) +// Invoke as MP_DEFINE_CONST_OBJ_TYPE(_typename, _name, _flags, [, slot, func]*) // It uses the number of arguments to select which MP_DEFINE_CONST_OBJ_TYPE_* // macro to use based on the number of arguments. It works by shifting the // numeric values 12, 11, ... 0 by the number of arguments, such that the @@ -842,12 +875,14 @@ extern const mp_obj_type_t mp_type_NoneType; extern const mp_obj_type_t mp_type_bool; extern const mp_obj_type_t mp_type_int; extern const mp_obj_type_t mp_type_str; +extern const mp_obj_type_t mp_type_template; +extern const mp_obj_type_t mp_type_interpolation; extern const mp_obj_type_t mp_type_bytes; extern const mp_obj_type_t mp_type_bytearray; extern const mp_obj_type_t mp_type_memoryview; extern const mp_obj_type_t mp_type_float; extern const mp_obj_type_t mp_type_complex; -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: add traceback support extern const mp_obj_type_t mp_type_traceback; extern const mp_obj_type_t mp_type_tuple; extern const mp_obj_type_t mp_type_list; @@ -909,7 +944,7 @@ extern const mp_obj_type_t mp_type_ImportError; extern const mp_obj_type_t mp_type_IndentationError; extern const mp_obj_type_t mp_type_IndexError; extern const mp_obj_type_t mp_type_KeyboardInterrupt; -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: add ReloadException extern const mp_obj_type_t mp_type_ReloadException; extern const mp_obj_type_t mp_type_KeyError; extern const mp_obj_type_t mp_type_LookupError; @@ -917,9 +952,9 @@ extern const mp_obj_type_t mp_type_MemoryError; extern const mp_obj_type_t mp_type_NameError; extern const mp_obj_type_t mp_type_NotImplementedError; extern const mp_obj_type_t mp_type_OSError; -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: add ConnectionError extern const mp_obj_type_t mp_type_ConnectionError; -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: add BrokenPipeError extern const mp_obj_type_t mp_type_BrokenPipeError; extern const mp_obj_type_t mp_type_OverflowError; extern const mp_obj_type_t mp_type_RuntimeError; @@ -927,6 +962,7 @@ extern const mp_obj_type_t mp_type_StopAsyncIteration; extern const mp_obj_type_t mp_type_StopIteration; extern const mp_obj_type_t mp_type_SyntaxError; extern const mp_obj_type_t mp_type_SystemExit; +// CIRCUITPY-CHANGE: add TimeoutError extern const mp_obj_type_t mp_type_TimeoutError; extern const mp_obj_type_t mp_type_TypeError; extern const mp_obj_type_t mp_type_UnicodeError; @@ -991,11 +1027,11 @@ void *mp_obj_malloc_helper(size_t num_bytes, const mp_obj_type_t *type); // Object allocation macros for allocating objects that have a finaliser. #if MICROPY_ENABLE_FINALISER #define mp_obj_malloc_with_finaliser(struct_type, obj_type) ((struct_type *)mp_obj_malloc_with_finaliser_helper(sizeof(struct_type), obj_type)) -#define mp_obj_malloc_var_with_finaliser(struct_type, var_type, var_num, obj_type) ((struct_type *)mp_obj_malloc_with_finaliser_helper(sizeof(struct_type) + sizeof(var_type) * (var_num), obj_type)) +#define mp_obj_malloc_var_with_finaliser(struct_type, var_field, var_type, var_num, obj_type) ((struct_type *)mp_obj_malloc_with_finaliser_helper(offsetof(struct_type, var_field) + sizeof(var_type) * (var_num), obj_type)) void *mp_obj_malloc_with_finaliser_helper(size_t num_bytes, const mp_obj_type_t *type); #else #define mp_obj_malloc_with_finaliser(struct_type, obj_type) mp_obj_malloc(struct_type, obj_type) -#define mp_obj_malloc_var_with_finaliser(struct_type, var_type, var_num, obj_type) mp_obj_malloc_var(struct_type, var_type, var_num, obj_type) +#define mp_obj_malloc_var_with_finaliser(struct_type, var_field, var_type, var_num, obj_type) mp_obj_malloc_var(struct_type, var_field, var_type, var_num, obj_type) #endif // These macros are derived from more primitive ones and are used to @@ -1015,8 +1051,13 @@ void *mp_obj_malloc_with_finaliser_helper(size_t num_bytes, const mp_obj_type_t MP_STATIC_ASSERT_NONCONSTEXPR((t) != &mp_type_str), assert((t) != &mp_type_str), \ MP_STATIC_ASSERT_NONCONSTEXPR((t) != &mp_type_NoneType), assert((t) != &mp_type_NoneType), \ 1) +#if MICROPY_PY_BUILTINS_FLOAT +#define mp_type_assert_not_float(t) (MP_STATIC_ASSERT_NONCONSTEXPR((t) != &mp_type_float), assert((t) != &mp_type_float), 1) +#else +#define mp_type_assert_not_float(t) (1) +#endif -#define mp_obj_is_type(o, t) (mp_type_assert_not_bool_int_str_nonetype(t) && mp_obj_is_exact_type(o, t)) +#define mp_obj_is_type(o, t) (mp_type_assert_not_bool_int_str_nonetype(t) && mp_type_assert_not_float(t) && mp_obj_is_exact_type(o, t)) #if MICROPY_OBJ_IMMEDIATE_OBJS // bool's are immediates, not real objects, so test for the 2 possible values. #define mp_obj_is_bool(o) ((o) == mp_const_false || (o) == mp_const_true) @@ -1032,7 +1073,6 @@ bool mp_obj_is_dict_or_ordereddict(mp_obj_t o); // type check is done on iter method to allow tuple, namedtuple, attrtuple #define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), iter) == mp_obj_tuple_getiter) -mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict); static inline mp_obj_t mp_obj_new_bool(mp_int_t x) { return x ? mp_const_true : mp_const_false; } @@ -1053,12 +1093,15 @@ mp_obj_t mp_obj_new_str_from_utf8_vstr(vstr_t *vstr); // input data must be vali #endif mp_obj_t mp_obj_new_bytes_from_vstr(vstr_t *vstr); mp_obj_t mp_obj_new_bytes(const byte *data, size_t len); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine mp_obj_t mp_obj_new_bytes_of_zeros(size_t len); mp_obj_t mp_obj_new_bytearray(size_t n, const void *items); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine mp_obj_t mp_obj_new_bytearray_of_zeros(size_t n); mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items); +#if MICROPY_PY_TSTRINGS +mp_obj_t mp_obj_new_template(size_t n_args, const mp_obj_t *args); +#endif #if MICROPY_PY_BUILTINS_FLOAT mp_obj_t mp_obj_new_int_from_float(mp_float_t val); mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag); @@ -1092,7 +1135,7 @@ mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items); const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in); const char *mp_obj_get_type_str(mp_const_obj_t o_in); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine #define mp_obj_get_type_qstr(o_in) (mp_obj_get_type((o_in))->name) bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects mp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type); @@ -1100,7 +1143,7 @@ mp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); void mp_obj_print(mp_obj_t o, mp_print_kind_t kind); void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine void mp_obj_print_exception_with_limit(const mp_print_t *print, mp_obj_t exc, mp_int_t limit); bool mp_obj_is_true(mp_obj_t arg); @@ -1114,6 +1157,8 @@ static inline bool mp_obj_is_integer(mp_const_obj_t o) { } mp_int_t mp_obj_get_int(mp_const_obj_t arg); +mp_uint_t mp_obj_get_uint(mp_const_obj_t arg); +long long mp_obj_get_ll(mp_const_obj_t arg); mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg); bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value); #if MICROPY_PY_BUILTINS_FLOAT @@ -1163,7 +1208,7 @@ bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type); void mp_obj_exception_clear_traceback(mp_obj_t self_in); void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block); void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine mp_obj_t mp_obj_exception_get_traceback_obj(mp_obj_t self_in); mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in); mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args); @@ -1234,21 +1279,6 @@ mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_flo #define mp_obj_is_float(o) (false) #endif -// tuple -void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); -void mp_obj_tuple_del(mp_obj_t self_in); -mp_int_t mp_obj_tuple_hash(mp_obj_t self_in); - -// list -// CIRCUITPY-CHANGE -mp_obj_t mp_obj_list_clear(mp_obj_t self_in); -mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); -mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value); -void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); -void mp_obj_list_set_len(mp_obj_t self_in, size_t len); -void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); -mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); - // dict typedef struct _mp_obj_dict_t { mp_obj_base_t base; @@ -1305,7 +1335,6 @@ typedef struct _mp_obj_fun_builtin_var_t { } fun; } mp_obj_fun_builtin_var_t; -qstr mp_obj_fun_get_name(mp_const_obj_t fun); mp_obj_t mp_identity(mp_obj_t self); MP_DECLARE_CONST_FUN_OBJ_1(mp_identity_obj); @@ -1320,9 +1349,6 @@ typedef struct _mp_obj_module_t { mp_obj_base_t base; mp_obj_dict_t *globals; } mp_obj_module_t; -static inline mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t module) { - return ((mp_obj_module_t *)MP_OBJ_TO_PTR(module))->globals; -} // staticmethod and classmethod types; defined here so we can make const versions // this structure is used for instances of both staticmethod and classmethod @@ -1336,7 +1362,7 @@ typedef struct _mp_rom_obj_static_class_method_t { } mp_rom_obj_static_class_method_t; // property -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: extra args const mp_obj_t *mp_obj_property_get(mp_obj_t self_in, size_t *n_proxy); // sequence helpers diff --git a/py/objarray.c b/py/objarray.c index 0be1947167d..f22cbb9fbe8 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -126,6 +126,19 @@ static mp_obj_array_t *array_new(char typecode, size_t n) { #endif #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY +static void array_extend_impl(mp_obj_array_t *array, mp_obj_t arg, char typecode, size_t len) { + mp_obj_t iterable = mp_getiter(arg, NULL); + mp_obj_t item; + size_t i = 0; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (len == 0) { + array_append(MP_OBJ_FROM_PTR(array), item); + } else { + mp_binary_set_val_array(typecode, array->items, i++, item); + } + } +} + static mp_obj_t array_construct(char typecode, mp_obj_t initializer) { // bytearrays can be raw-initialised from anything with the buffer protocol // other arrays can only be raw-initialised from bytes and bytearray objects @@ -158,18 +171,7 @@ static mp_obj_t array_construct(char typecode, mp_obj_t initializer) { } mp_obj_array_t *array = array_new(typecode, len); - - mp_obj_t iterable = mp_getiter(initializer, NULL); - mp_obj_t item; - size_t i = 0; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (len == 0) { - array_append(MP_OBJ_FROM_PTR(array), item); - } else { - mp_binary_set_val_array(typecode, array->items, i++, item); - } - } - + array_extend_impl(array, initializer, typecode, len); return MP_OBJ_FROM_PTR(array); } #endif @@ -209,7 +211,10 @@ static mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, // 1 arg, an integer: construct a blank bytearray of that length mp_uint_t len = mp_obj_get_int(args[0]); mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len); + // If this config is set then the GC clears all memory, so we don't need to. + #if !MICROPY_GC_CONSERVATIVE_CLEAR memset(o->items, 0, len); + #endif return MP_OBJ_FROM_PTR(o); } else { // 1 arg: construct the bytearray from that @@ -298,7 +303,7 @@ static void memoryview_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); dest[0] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->typecode & TYPECODE_MASK, NULL)); } - // CIRCUITPY-CHANGE: prevent warning + // CIRCUITPY-CHANGE: add MICROPY_CPYTHON_COMPAT #if MICROPY_PY_BUILTINS_BYTES_HEX || MICROPY_CPYTHON_COMPAT else { // Need to forward to locals dict. @@ -493,39 +498,42 @@ static mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) { // allow to extend by anything that has the buffer protocol (extension to CPython) mp_buffer_info_t arg_bufinfo; - // CIRCUITPY-CHANGE: allow appending an iterable - if (mp_get_buffer(arg_in, &arg_bufinfo, MP_BUFFER_READ)) { - size_t sz = mp_binary_get_size('@', self->typecode, NULL); - - // convert byte count to element count - size_t len = arg_bufinfo.len / sz; - - // make sure we have enough room to extend - // TODO: alloc policy; at the moment we go conservative - if (self->free < len) { - self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz); - self->free = 0; - } else { - self->free -= len; - } + if (!mp_get_buffer(arg_in, &arg_bufinfo, MP_BUFFER_READ)) { + array_extend_impl(self, arg_in, 0, 0); + return mp_const_none; + } - // extend - mp_seq_copy((byte *)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte); - self->len += len; - } else { - // Otherwise argument must be an iterable of items to append - mp_obj_t iterable = mp_getiter(arg_in, NULL); - mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - array_append(self_in, item); + size_t sz = mp_binary_get_size('@', self->typecode, NULL); + + // convert byte count to element count + size_t len = arg_bufinfo.len / sz; + + // make sure we have enough room to extend + // TODO: alloc policy; at the moment we go conservative + if (self->free < len) { + self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz); + self->free = 0; + + if (self_in == arg_in) { + // Get arg_bufinfo again in case self->items has moved + // + // (Note not possible to handle case that arg_in is a memoryview into self) + mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ); } + } else { + self->free -= len; } + + // extend + mp_seq_copy((byte *)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte); + self->len += len; + return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(mp_obj_array_extend_obj, array_extend); #endif -// CIRCUITPY-CHANGE: buffer_finder used belo +// CIRCUITPY-CHANGE: buffer_finder used below #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_CPYTHON_COMPAT static mp_obj_t buffer_finder(size_t n_args, const mp_obj_t *args, int direction, bool is_index) { mp_check_self(mp_obj_is_type(args[0], &mp_type_bytearray)); @@ -564,7 +572,6 @@ static mp_obj_t buffer_finder(size_t n_args, const mp_obj_t *args, int direction } return MP_OBJ_NEW_SMALL_INT(p - (const byte *)haystack_bufinfo.buf); } - // CIRCUITPY-CHANGE: provides find, rfind, index static mp_obj_t buffer_find(size_t n_args, const mp_obj_t *args) { return buffer_finder(n_args, args, 1, false); @@ -667,7 +674,7 @@ static mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_seq_replace_slice_no_grow(dest_items, o->len, slice.start, slice.stop, src_items + src_offs, src_len, item_sz); // CIRCUITPY-CHANGE - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES // Clear "freed" elements at the end of list // TODO: This is actually only needed for typecode=='O' mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz); @@ -803,7 +810,7 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_DEFINE_CONST_OBJ_TYPE( mp_type_bytearray, MP_QSTR_bytearray, - MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER, + MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER | MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE, make_new, bytearray_make_new, print, array_print, iter, array_iterator_new, @@ -842,7 +849,7 @@ MP_DEFINE_CONST_DICT(memoryview_locals_dict, memoryview_locals_dict_table); MP_DEFINE_CONST_OBJ_TYPE( mp_type_memoryview, MP_QSTR_memoryview, - MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER, + MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER | MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE, make_new, memoryview_make_new, iter, array_iterator_new, unary_op, array_unary_op, diff --git a/py/objboundmeth.c b/py/objboundmeth.c index e3503ff154a..6df67f7bf9e 100644 --- a/py/objboundmeth.c +++ b/py/objboundmeth.c @@ -102,7 +102,11 @@ static mp_obj_t bound_meth_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_ } mp_obj_bound_meth_t *lhs = MP_OBJ_TO_PTR(lhs_in); mp_obj_bound_meth_t *rhs = MP_OBJ_TO_PTR(rhs_in); + #if MICROPY_PY_BOUND_METHOD_FULL_EQUALITY_CHECK + return mp_obj_new_bool(mp_obj_equal(lhs->self, rhs->self) && mp_obj_equal(lhs->meth, rhs->meth)); + #else return mp_obj_new_bool(lhs->self == rhs->self && lhs->meth == rhs->meth); + #endif } #if MICROPY_PY_FUNCTION_ATTRS diff --git a/py/objcell.c b/py/objcell.c index 95966c7917c..5c030c7405a 100644 --- a/py/objcell.c +++ b/py/objcell.c @@ -30,7 +30,7 @@ static void cell_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_cell_t *o = MP_OBJ_TO_PTR(o_in); - mp_printf(print, "obj); + mp_printf(print, "obj); if (o->obj == MP_OBJ_NULL) { mp_print_str(print, "(nil)"); } else { diff --git a/py/objcode.c b/py/objcode.c index 9b98a696798..09904f10f36 100644 --- a/py/objcode.c +++ b/py/objcode.c @@ -69,6 +69,7 @@ static mp_obj_tuple_t *code_consts(const mp_module_context_t *context, const mp_ return consts; } +#if !MICROPY_PREVIEW_VERSION_2 static mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) { // const mp_bytecode_prelude_t *prelude = &rc->prelude; uint start = 0; @@ -106,6 +107,68 @@ static mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) { m_del(byte, buffer, buffer_size); return o; } +#endif + +static mp_obj_t code_colines_iter(mp_obj_t); +static mp_obj_t code_colines_next(mp_obj_t); +typedef struct _mp_obj_colines_iter_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + const mp_raw_code_t *rc; + mp_uint_t bc; + mp_uint_t source_line; + const byte *ci; +} mp_obj_colines_iter_t; + +static mp_obj_t code_colines_iter(mp_obj_t self_in) { + mp_obj_code_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_colines_iter_t *iter = mp_obj_malloc(mp_obj_colines_iter_t, &mp_type_polymorph_iter); + iter->iternext = code_colines_next; + iter->rc = self->rc; + iter->bc = 0; + iter->source_line = 1; + iter->ci = self->rc->prelude.line_info; + return MP_OBJ_FROM_PTR(iter); +} +static MP_DEFINE_CONST_FUN_OBJ_1(code_colines_obj, code_colines_iter); + +static mp_obj_t code_colines_next(mp_obj_t iter_in) { + mp_obj_colines_iter_t *iter = MP_OBJ_TO_PTR(iter_in); + const byte *ci_end = iter->rc->prelude.line_info_top; + + mp_uint_t start = iter->bc; + mp_uint_t line_no = iter->source_line; + bool another = true; + + while (another && iter->ci < ci_end) { + another = false; + mp_code_lineinfo_t decoded = mp_bytecode_decode_lineinfo(&iter->ci); + iter->bc += decoded.bc_increment; + iter->source_line += decoded.line_increment; + + if (decoded.bc_increment == 0) { + line_no = iter->source_line; + another = true; + } else if (decoded.line_increment == 0) { + another = true; + } + } + + if (another) { + mp_uint_t prelude_size = (iter->rc->prelude.opcodes - (const byte *)iter->rc->fun_data); + mp_uint_t bc_end = iter->rc->fun_data_len - prelude_size; + if (iter->bc >= bc_end) { + return MP_OBJ_STOP_ITERATION; + } else { + iter->bc = bc_end; + } + } + + mp_uint_t end = iter->bc; + mp_obj_t next[3] = {MP_OBJ_NEW_SMALL_INT(start), MP_OBJ_NEW_SMALL_INT(end), MP_OBJ_NEW_SMALL_INT(line_no)}; + + return mp_obj_new_tuple(MP_ARRAY_SIZE(next), next); +} static void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { @@ -137,12 +200,18 @@ static void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { case MP_QSTR_co_names: dest[0] = MP_OBJ_FROM_PTR(o->dict_locals); break; + #if !MICROPY_PREVIEW_VERSION_2 case MP_QSTR_co_lnotab: if (!o->lnotab) { o->lnotab = raw_code_lnotab(rc); } dest[0] = o->lnotab; break; + #endif + case MP_QSTR_co_lines: + dest[0] = MP_OBJ_FROM_PTR(&code_colines_obj); + dest[1] = self_in; + break; } } @@ -168,7 +237,9 @@ mp_obj_t mp_obj_new_code(const mp_module_context_t *context, const mp_raw_code_t o->context = context; o->rc = rc; o->dict_locals = mp_locals_get(); // this is a wrong! how to do this properly? + #if !MICROPY_PREVIEW_VERSION_2 o->lnotab = MP_OBJ_NULL; + #endif return MP_OBJ_FROM_PTR(o); } diff --git a/py/objcode.h b/py/objcode.h index 8db9a34b6e1..7be15e23f52 100644 --- a/py/objcode.h +++ b/py/objcode.h @@ -72,15 +72,16 @@ static inline const void *mp_code_get_proto_fun(mp_obj_code_t *self) { #include "py/emitglue.h" -#define MP_CODE_QSTR_MAP(context, idx) (context->constants.qstr_table[idx]) +#define MP_CODE_QSTR_MAP(context, idx) ((qstr)(context->constants.qstr_table[idx])) typedef struct _mp_obj_code_t { - // TODO this was 4 words mp_obj_base_t base; const mp_module_context_t *context; const mp_raw_code_t *rc; mp_obj_dict_t *dict_locals; + #if !MICROPY_PREVIEW_VERSION_2 mp_obj_t lnotab; + #endif } mp_obj_code_t; mp_obj_t mp_obj_new_code(const mp_module_context_t *context, const mp_raw_code_t *rc, bool result_required); diff --git a/py/objcomplex.c b/py/objcomplex.c index d7287efdc13..88f4444f09e 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -49,29 +49,18 @@ typedef struct _mp_obj_complex_t { static void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in); - #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT - char buf[16]; - #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C - const int precision = 6; - #else - const int precision = 7; - #endif - #else - char buf[32]; - const int precision = 16; - #endif - if (o->real == 0) { - mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); - mp_printf(print, "%sj", buf); + const char *suffix; + int flags = 0; + if (o->real != 0) { + mp_print_str(print, "("); + mp_print_float(print, o->real, 'g', 0, '\0', -1, MP_FLOAT_REPR_PREC); + flags = PF_FLAG_SHOW_SIGN; + suffix = "j)"; } else { - mp_format_float(o->real, buf, sizeof(buf), 'g', precision, '\0'); - mp_printf(print, "(%s", buf); - if (o->imag >= 0 || isnan(o->imag)) { - mp_print_str(print, "+"); - } - mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); - mp_printf(print, "%sj)", buf); + suffix = "j"; } + mp_print_float(print, o->imag, 'g', flags, '\0', -1, MP_FLOAT_REPR_PREC); + mp_print_str(print, suffix); } static mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { diff --git a/py/objdict.c b/py/objdict.c index 79a606f0970..d459d1ae486 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -101,7 +101,7 @@ static void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ #endif } if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) { - mp_printf(print, "%q(", self->base.type->name); + mp_printf(print, "%q(", (qstr)self->base.type->name); } mp_print_str(print, "{"); size_t cur = 0; @@ -616,7 +616,8 @@ static mp_obj_t dict_view_unary_op(mp_unary_op_t op, mp_obj_t o_in) { if (op == MP_UNARY_OP_HASH && o->kind == MP_DICT_VIEW_VALUES) { return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in); } - return MP_OBJ_NULL; + // delegate all other ops to dict unary op handler + return dict_unary_op(op, o->dict); } static mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { diff --git a/py/objexcept.c b/py/objexcept.c index 6a6b1e4d4a7..6efb0f50672 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -166,7 +166,7 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; bool is_subclass = kind & PRINT_EXC_SUBCLASS; if (!is_subclass && (k == PRINT_REPR || k == PRINT_EXC)) { - mp_print_str(print, qstr_str(o->base.type->name)); + mp_print_str(print, mp_obj_get_type_str(o_in)); } if (k == PRINT_EXC) { @@ -610,7 +610,14 @@ bool mp_obj_is_exception_type(mp_obj_t self_in) { // return true if the given object is an instance of an exception type bool mp_obj_is_exception_instance(mp_obj_t self_in) { - return mp_obj_is_exception_type(MP_OBJ_FROM_PTR(mp_obj_get_type(self_in))); + if (mp_obj_is_native_exception_instance(self_in)) { + return true; + } + if (!mp_obj_is_exception_type(MP_OBJ_FROM_PTR(mp_obj_get_type(self_in)))) { + return false; + } + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + return self->subobj[0] != MP_OBJ_FROM_PTR((void *)&mp_native_base_init_wrapper_obj); } // Return true if exception (type or instance) is a subclass of given diff --git a/py/objfloat.c b/py/objfloat.c index 3610c2b8586..ecc0f61a6ab 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -34,6 +34,11 @@ #if MICROPY_PY_BUILTINS_FLOAT +// Workaround a bug in Windows SDK version 10.0.26100.0, where NAN is no longer constant. +#if defined(_MSC_VER) && !defined(_UCRT_NOISY_NAN) +#define _UCRT_NOISY_NAN +#endif + #include #include "py/formatfloat.h" @@ -51,13 +56,6 @@ #define M_PI (3.14159265358979323846) #endif -// Workaround a bug in recent MSVC where NAN is no longer constant. -// (By redefining back to the previous MSVC definition of NAN) -#if defined(_MSC_VER) && _MSC_VER >= 1942 -#undef NAN -#define NAN (-(float)(((float)(1e+300 * 1e+300)) * 0.0F)) -#endif - typedef struct _mp_obj_float_t { mp_obj_base_t base; mp_float_t value; @@ -116,23 +114,7 @@ mp_int_t mp_float_hash(mp_float_t src) { static void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_float_t o_val = mp_obj_float_get(o_in); - #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT - char buf[16]; - #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C - const int precision = 6; - #else - const int precision = 7; - #endif - #else - char buf[32]; - const int precision = 16; - #endif - mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0'); - mp_print_str(print, buf); - if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) { - // Python floats always have decimal point (unless inf or nan) - mp_print_str(print, ".0"); - } + mp_print_float(print, o_val, 'g', PF_FLAG_ALWAYS_DECIMAL, '\0', -1, MP_FLOAT_REPR_PREC); } static mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -324,6 +306,10 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t lhs_val = MICROPY_FLOAT_CONST(1.0); break; } + if (isnan(rhs_val)) { + lhs_val = rhs_val; + break; + } #endif lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val); break; diff --git a/py/objfun.c b/py/objfun.c index e6a923d59e8..6392a6c8730 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -135,11 +135,10 @@ MP_DEFINE_CONST_OBJ_TYPE( /******************************************************************************/ /* byte code functions */ -qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) { - const mp_obj_fun_bc_t *fun = MP_OBJ_TO_PTR(fun_in); +qstr mp_obj_fun_bc_get_name(const mp_obj_fun_bc_t *fun) { const byte *bc = fun->bytecode; - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE if (fun->base.type == &mp_type_fun_native || fun->base.type == &mp_type_native_gen_wrap) { bc = mp_obj_fun_native_get_prelude_ptr(fun); } @@ -184,7 +183,8 @@ static mp_obj_t fun_bc_make_new(const mp_obj_type_t *type, size_t n_args, size_t static void fun_bc_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_fun_bc_t *o = MP_OBJ_TO_PTR(o_in); - mp_printf(print, "", mp_obj_fun_get_name(o_in), o); + // CIRCUITPY-CHANGE: %p already prints "0x", so don't include it explicitly. + mp_printf(print, "", mp_obj_fun_bc_get_name(o), o); } #endif @@ -363,21 +363,33 @@ void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // not load attribute return; } + const mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); if (attr == MP_QSTR___name__) { - dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(self_in)); + dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_bc_get_name(self)); } if (attr == MP_QSTR___globals__) { - mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); dest[0] = MP_OBJ_FROM_PTR(self->context->module.globals); } #if MICROPY_PY_FUNCTION_ATTRS_CODE if (attr == MP_QSTR___code__) { - const mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); - if ((self->base.type == &mp_type_fun_bc - || self->base.type == &mp_type_gen_wrap) - && self->child_table == NULL) { + if (self->base.type == &mp_type_fun_bc + || self->base.type == &mp_type_gen_wrap) { #if MICROPY_PY_BUILTINS_CODE <= MICROPY_PY_BUILTINS_CODE_BASIC - dest[0] = mp_obj_new_code(self->context->constants, self->bytecode); + #if MICROPY_PERSISTENT_CODE_SAVE + #error "MICROPY_PERSISTENT_CODE_SAVE can't be enabled at this level of MICROPY_PY_BUILTINS_CODE" + #endif + mp_proto_fun_t proto_fun; + if (self->child_table != NULL) { + mp_raw_code_truncated_t *rc = m_new0(mp_raw_code_truncated_t, 1); + rc->kind = MP_CODE_BYTECODE; + rc->is_generator = self->base.type == &mp_type_gen_wrap; + rc->fun_data = self->bytecode; + rc->children = (mp_raw_code_t **)self->child_table; + proto_fun = rc; + } else { + proto_fun = self->bytecode; + } + dest[0] = mp_obj_new_code(self->context->constants, proto_fun); #else dest[0] = mp_obj_new_code(self->context, self->rc, true); #endif @@ -447,7 +459,7 @@ mp_obj_t mp_obj_new_fun_bc(const mp_obj_t *def_args, const byte *code, const mp_ /******************************************************************************/ /* native functions */ -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE // CIRCUITPY-CHANGE: PLACE_IN_ITCM static mp_obj_t PLACE_IN_ITCM(fun_native_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -477,13 +489,9 @@ MP_DEFINE_CONST_OBJ_TYPE( call, fun_native_call ); -#endif // MICROPY_EMIT_NATIVE - /******************************************************************************/ /* viper functions */ -#if MICROPY_EMIT_NATIVE - static mp_obj_t fun_viper_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_cstack_check(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); @@ -498,7 +506,7 @@ MP_DEFINE_CONST_OBJ_TYPE( call, fun_viper_call ); -#endif // MICROPY_EMIT_NATIVE +#endif // MICROPY_ENABLE_NATIVE_CODE /******************************************************************************/ /* inline assembler functions */ diff --git a/py/objfun.h b/py/objfun.h index 4059343983c..0fcc25ff09c 100644 --- a/py/objfun.h +++ b/py/objfun.h @@ -51,9 +51,10 @@ typedef struct _mp_obj_fun_asm_t { } mp_obj_fun_asm_t; mp_obj_t mp_obj_new_fun_bc(const mp_obj_t *def_args, const byte *code, const mp_module_context_t *cm, struct _mp_raw_code_t *const *raw_code_table); +qstr mp_obj_fun_bc_get_name(const mp_obj_fun_bc_t *fun); void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE static inline mp_obj_t mp_obj_new_fun_native(const mp_obj_t *def_args, const void *fun_data, const mp_module_context_t *mc, struct _mp_raw_code_t *const *child_table) { mp_obj_fun_bc_t *o = (mp_obj_fun_bc_t *)MP_OBJ_TO_PTR(mp_obj_new_fun_bc(def_args, (const byte *)fun_data, mc, child_table)); diff --git a/py/objgenerator.c b/py/objgenerator.c index de063d38458..83cf6715bbc 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -114,7 +114,7 @@ MP_DEFINE_CONST_OBJ_TYPE( /******************************************************************************/ // native generator wrapper -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE // Based on mp_obj_gen_instance_t. typedef struct _mp_obj_gen_instance_native_t { @@ -184,7 +184,7 @@ MP_DEFINE_CONST_OBJ_TYPE( ); #endif -#endif // MICROPY_EMIT_NATIVE +#endif // MICROPY_ENABLE_NATIVE_CODE /******************************************************************************/ /* generator instance */ @@ -192,7 +192,7 @@ MP_DEFINE_CONST_OBJ_TYPE( static void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self); + mp_printf(print, "", mp_obj_fun_bc_get_name(self->code_state.fun_bc), self); } // CIRCUITPY-CHANGE @@ -200,7 +200,7 @@ static void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_pri static void coro_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self); + mp_printf(print, "", mp_obj_fun_bc_get_name(self->code_state.fun_bc), self); } #endif @@ -237,7 +237,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ // If the generator is started, allow sending a value. void *state_start = self->code_state.state - 1; - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) { state_start = ((mp_obj_gen_instance_native_t *)self)->code_state.state - 1; } @@ -259,7 +259,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ mp_vm_return_kind_t ret_kind; - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) { // A native generator. typedef uintptr_t (*mp_fun_native_gen_t)(void *, mp_obj_t); @@ -297,7 +297,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ case MP_VM_RETURN_EXCEPTION: { self->code_state.ip = 0; - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) { *ret_val = ((mp_obj_gen_instance_native_t *)self)->code_state.state[0]; } else diff --git a/py/objint.c b/py/objint.c index b12f09c9d38..e8f7f51052a 100644 --- a/py/objint.c +++ b/py/objint.c @@ -30,7 +30,7 @@ #include "py/parsenum.h" #include "py/smallint.h" -#include "py/objint.h" +#include "py/objint_impl.h" #include "py/objstr.h" #include "py/runtime.h" #include "py/binary.h" @@ -99,8 +99,8 @@ static mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE e = u.i[MP_ENDIANNESS_LITTLE]; #endif -#define MP_FLOAT_SIGN_SHIFT_I32 ((MP_FLOAT_FRAC_BITS + MP_FLOAT_EXP_BITS) % 32) -#define MP_FLOAT_EXP_SHIFT_I32 (MP_FLOAT_FRAC_BITS % 32) + #define MP_FLOAT_SIGN_SHIFT_I32 ((MP_FLOAT_FRAC_BITS + MP_FLOAT_EXP_BITS) % 32) + #define MP_FLOAT_EXP_SHIFT_I32 (MP_FLOAT_FRAC_BITS % 32) if (e & (1U << MP_FLOAT_SIGN_SHIFT_I32)) { #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE @@ -117,9 +117,15 @@ static mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { } // 8 * sizeof(uintptr_t) counts the number of bits for a small int // TODO provide a way to configure this properly + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B + if (e <= ((8 * sizeof(uintptr_t) + MP_FLOAT_EXP_BIAS - 4) << MP_FLOAT_EXP_SHIFT_I32)) { + return MP_FP_CLASS_FIT_SMALLINT; + } + #else if (e <= ((8 * sizeof(uintptr_t) + MP_FLOAT_EXP_BIAS - 3) << MP_FLOAT_EXP_SHIFT_I32)) { return MP_FP_CLASS_FIT_SMALLINT; } + #endif #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG if (e <= (((sizeof(long long) * MP_BITS_PER_BYTE) + MP_FLOAT_EXP_BIAS - 2) << MP_FLOAT_EXP_SHIFT_I32)) { return MP_FP_CLASS_FIT_LONGINT; @@ -201,17 +207,17 @@ static const uint8_t log_base2_floor[] = { 3, 3, 3, 3, 3, 3, 3, 4, /* if needed, these are the values for higher bases - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 5 + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 5 */ }; size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma) { assert(2 <= base && base <= 16); size_t num_digits = num_bits / log_base2_floor[base - 1] + 1; - size_t num_commas = comma ? num_digits / 3 : 0; + size_t num_commas = comma ? (base == 10 ? num_digits / 3 : num_digits / 4): 0; size_t prefix_len = prefix ? strlen(prefix) : 0; return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte } @@ -249,10 +255,11 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co char sign = '\0'; if (num < 0) { - num = -num; + num = -(fmt_uint_t)num; sign = '-'; } + int n_comma = (base == 10) ? 3 : 4; size_t needed_size = mp_int_format_size(sizeof(fmt_int_t) * 8, base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); @@ -277,7 +284,7 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co c += '0'; } *(--b) = c; - if (comma && num != 0 && b > str && (last_comma - b) == 3) { + if (comma && num != 0 && b > str && (last_comma - b) == n_comma) { *(--b) = comma; last_comma = b; } @@ -302,74 +309,9 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co return b; } -// CIRCUITPY-CHANGE: more thorough checking -#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - -void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed) { - if (is_signed) { - // self must be < 2**(bits - 1) - mp_obj_t edge = mp_binary_op(MP_BINARY_OP_LSHIFT, - mp_obj_new_int(1), - mp_obj_new_int(nbytes * 8 - 1)); - - if (mp_binary_op(MP_BINARY_OP_LESS, self_in, edge) == mp_const_true) { - // and >= -2**(bits - 1) - edge = mp_unary_op(MP_UNARY_OP_NEGATIVE, edge); - if (mp_binary_op(MP_BINARY_OP_MORE_EQUAL, self_in, edge) == mp_const_true) { - return; - } - } - } else { - // self must be >= 0 - if (mp_obj_int_sign(self_in) >= 0) { - // and < 2**(bits) - mp_obj_t edge = mp_binary_op(MP_BINARY_OP_LSHIFT, - mp_obj_new_int(1), - mp_obj_new_int(nbytes * 8)); - - if (mp_binary_op(MP_BINARY_OP_LESS, self_in, edge) == mp_const_true) { - return; - } - } - } - - mp_raise_OverflowError_varg(MP_ERROR_TEXT("value must fit in %d byte(s)"), nbytes); -} - -#endif // MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - +// CIRCUITPY-CHANGE: also called from py/binary.c, so not static here. void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed) { - // Fast path for zero. - if (val == 0) { - return; - } - - // Trying to store negative values in unsigned bytes falls through to failure. - if (is_signed || val >= 0) { - - if (nbytes >= sizeof(val)) { - // All non-negative N bit signed integers fit in an unsigned N bit integer. - // This case prevents shifting too far below. - return; - } - - if (is_signed) { - mp_int_t edge = ((mp_int_t)1 << (nbytes * 8 - 1)); - if (-edge <= val && val < edge) { - return; - } - // Out of range, fall through to failure. - } else { - // Unsigned. We already know val >= 0. - mp_int_t edge = ((mp_int_t)1 << (nbytes * 8)); - if (val < edge) { - return; - } - } - // Fall through to failure. - } - - mp_raise_OverflowError_varg(MP_ERROR_TEXT("value must fit in %d byte(s)"), nbytes); + mp_obj_small_int_buffer_overflow_check(val, nbytes, is_signed); } #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE @@ -440,6 +382,10 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { return MP_OBJ_SMALL_INT_VALUE(self_in); } +void mp_obj_int_to_bytes(mp_obj_t self_in, size_t buf_len, byte *buf, bool big_endian, bool is_signed, bool overflow_check) { + mp_obj_small_int_to_bytes(MP_OBJ_SMALL_INT_VALUE(self_in), buf_len, buf, big_endian, is_signed, overflow_check); +} + #endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE // This dispatcher function is expected to be independent of the implementation of long int @@ -449,7 +395,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp // false acts as 0 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(0)); } else if (rhs_in == mp_const_true) { - // true acts as 0 + // true acts as 1 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1)); } else if (op == MP_BINARY_OP_MULTIPLY) { if (mp_obj_is_str_or_bytes(rhs_in) || mp_obj_is_type(rhs_in, &mp_type_tuple) || mp_obj_is_type(rhs_in, &mp_type_list)) { @@ -532,49 +478,31 @@ static mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t static MP_DEFINE_CONST_FUN_OBJ_KW(int_from_bytes_fun_obj, 2, int_from_bytes); static MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_bytes_fun_obj)); -// CIRCUITPY-CHANGE: supports signed static mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_length, ARG_byteorder, ARG_signed }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_length, MP_ARG_INT, {.u_int = 1} }, - // CIRCUITPY-CHANGE: not required and given a default value. - { MP_QSTR_byteorder, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_big)} }, + { MP_QSTR_length, MP_ARG_INT, { .u_int = 1 } }, + { MP_QSTR_byteorder, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_QSTR(MP_QSTR_big) } }, { MP_QSTR_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; 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_int_t len = args[ARG_length].u_int; - if (len < 0) { + mp_obj_t self = pos_args[0]; + + mp_int_t dlen = args[ARG_length].u_int; + if (dlen < 0) { mp_raise_ValueError(NULL); } - mp_obj_t self = pos_args[0]; - bool big_endian = args[ARG_byteorder].u_obj != MP_OBJ_NEW_QSTR(MP_QSTR_little); - bool signed_ = args[ARG_signed].u_bool; - vstr_t vstr; - vstr_init_len(&vstr, len); + vstr_init_len(&vstr, dlen); byte *data = (byte *)vstr.buf; - memset(data, 0, len); - #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - if (!mp_obj_is_small_int(self)) { - mp_obj_int_buffer_overflow_check(self, len, signed_); - mp_obj_int_to_bytes_impl(self, big_endian, len, data); - } else - #endif - { - mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self); - // Small int checking is separate, to be fast. - mp_small_int_buffer_overflow_check(val, len, signed_); - size_t l = MIN((size_t)len, sizeof(val)); - if (val < 0) { - // Sign extend negative numbers. - memset(data, -1, len); - } - mp_binary_set_int(l, big_endian, data + (big_endian ? (len - l) : 0), val); - } + bool big_endian = args[ARG_byteorder].u_obj != MP_OBJ_NEW_QSTR(MP_QSTR_little); + bool signed_ = args[ARG_signed].u_bool; + + mp_obj_int_to_bytes(self, dlen, data, big_endian, signed_, true); return mp_obj_new_bytes_from_vstr(&vstr); } diff --git a/py/objint.h b/py/objint.h index 92466bae4e2..94c53190d8b 100644 --- a/py/objint.h +++ b/py/objint.h @@ -53,19 +53,17 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co int base, const char *prefix, char base_char, char comma); char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); -// CIRCUITPY-CHANGE -#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE -void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed); -#endif - -void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed); mp_int_t mp_obj_int_hash(mp_obj_t self_in); // CIRCUITPY-CHANGE mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in); mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf); -// Returns true if 'self_in' fit into 'len' bytes of 'buf' without overflowing, 'buf' is truncated otherwise. -bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); +// Write an integer to a byte sequence. +// If overflow_check is true, raises OverflowError if 'self_in' doesn't fit. If false, truncate to fit. +void mp_obj_int_to_bytes(mp_obj_t self_in, size_t buf_len, byte *buf, bool big_endian, bool is_signed, bool overflow_check); + +// CIRCUITPY-CHANGE: raises OverflowError if val does not fit in nbytes. +void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed); int mp_obj_int_sign(mp_obj_t self_in); mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in); mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); diff --git a/py/objint_impl.h b/py/objint_impl.h new file mode 100644 index 00000000000..b1af4d6244d --- /dev/null +++ b/py/objint_impl.h @@ -0,0 +1,98 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2026 Angus Gratton + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* This header provides some inline implementations of functions used by multiple objint*.c + files. + + Implementations here should only be called by one of the objint*.c files. If + called from more than one place in a single firmware, place into objint.c and + define in objint.h + */ +#ifndef MICROPY_INCLUDED_PY_OBJINT_IMPL_H +#define MICROPY_INCLUDED_PY_OBJINT_IMPL_H + +#include "py/binary.h" +#include "py/objint.h" +#include "py/runtime.h" + +static void mp_obj_int_raise_to_bytes_overflow_error(size_t nbytes) { + mp_raise_msg_varg(&mp_type_OverflowError, MP_ERROR_TEXT("value would overflow a %d byte buffer"), nbytes); +} + +static void mp_obj_int_raise_unsigned_negative_overflow_error(void) { + mp_raise_msg_varg(&mp_type_OverflowError, MP_ERROR_TEXT("can't convert negative int to unsigned")); +} + +static void mp_obj_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed) { + // Fast path for zero. + if (val == 0) { + return; + } + + if (!is_signed && val < 0) { + // Trying to store negative values in unsigned bytes + mp_obj_int_raise_unsigned_negative_overflow_error(); + } + + if (nbytes >= sizeof(val)) { + // All N bit small integers fit in an unsigned N bit integer. + // This case prevents shifting too far below. + return; + } + + if (nbytes == 0) { + // Can't fit a non-negative value in 0 bytes (prevents negative left shift, below) + goto raise; + } + + if (is_signed) { + mp_int_t edge = ((mp_int_t)1 << (nbytes * 8 - 1)); + if (-edge <= val && val < edge) { + return; + } + // Out of range, fall through to raise. + } else { + // Unsigned. We already know val >= 0. + mp_int_t edge = ((mp_int_t)1 << (nbytes * 8)); + if (val < edge) { + return; + } + // Fall through to raise. + } + +raise: + mp_obj_int_raise_to_bytes_overflow_error(nbytes); +} + +static inline void mp_obj_small_int_to_bytes(mp_int_t val, size_t buf_len, byte *buf, bool big_endian, bool is_signed, bool overflow_check) { + if (overflow_check) { + mp_obj_small_int_buffer_overflow_check(val, buf_len, is_signed); + } + mp_binary_set_int(buf_len, buf, sizeof(val), val, big_endian); + +} + +#endif // MICROPY_INCLUDED_PY_OBJINT_IMPL_H diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 0fad693c7ad..49ac0b429fc 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -29,7 +29,7 @@ #include #include "py/smallint.h" -#include "py/objint.h" +#include "py/objint_impl.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_FLOAT @@ -43,6 +43,10 @@ const mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; #endif +static void raise_long_long_overflow(void) { + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("result overflows long long storage")); +} + // CIRCUITPY-CHANGE: bit_length mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in) { assert(mp_obj_is_type(self_in, &mp_type_int)); @@ -69,42 +73,6 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf return mp_obj_new_int_from_ll(value); } -bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { - assert(mp_obj_is_exact_type(self_in, &mp_type_int)); - mp_obj_int_t *self = self_in; - long long val = self->val; - size_t slen; // Number of bytes to represent val - - // This logic has a twin in objint.c - if (val > 0) { - slen = (sizeof(long long) * 8 - mp_clzll(val) + 7) / 8; - } else if (val < -1) { - slen = (sizeof(long long) * 8 - mp_clzll(~val) + 8) / 8; - } else { - // clz of 0 is defined, so 0 and -1 map to 0 and 1 - slen = -val; - } - - if (slen > len) { - return false; // Would overflow - // TODO: Determine whether to copy and truncate, as some callers probably expect this...? - } - - if (big_endian) { - byte *b = buf + len; - while (b > buf) { - *--b = val; - val >>= 8; - } - } else { - for (; len > 0; --len) { - *buf++ = val; - val >>= 8; - } - } - return true; -} - int mp_obj_int_sign(mp_obj_t self_in) { mp_longint_impl_t val; if (mp_obj_is_small_int(self_in)) { @@ -132,7 +100,6 @@ mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { // small int if the value fits without truncation case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val); - case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: @@ -159,6 +126,8 @@ mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { long long lhs_val; long long rhs_val; + bool overflow = false; + long long result; if (mp_obj_is_small_int(lhs_in)) { lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); @@ -171,21 +140,41 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in); } else if (mp_obj_is_exact_type(rhs_in, &mp_type_int)) { rhs_val = ((mp_obj_int_t *)rhs_in)->val; + #if MICROPY_PY_BUILTINS_FLOAT + } else if (mp_obj_is_float(rhs_in)) { + return mp_obj_float_binary_op(op, (mp_float_t)lhs_val, rhs_in); + #endif + #if MICROPY_PY_BUILTINS_COMPLEX + } else if (mp_obj_is_type(rhs_in, &mp_type_complex)) { + return mp_obj_complex_binary_op(op, (mp_float_t)lhs_val, 0, rhs_in); + #endif } else { // delegate to generic function to check for extra cases return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); } + #if MICROPY_PY_BUILTINS_FLOAT + if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) { + if (rhs_val == 0) { + goto zero_division; + } + return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val); + } + #endif + switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: - return mp_obj_new_int_from_ll(lhs_val + rhs_val); + overflow = mp_add_ll_overflow(lhs_val, rhs_val, &result); + break; case MP_BINARY_OP_SUBTRACT: case MP_BINARY_OP_INPLACE_SUBTRACT: - return mp_obj_new_int_from_ll(lhs_val - rhs_val); + overflow = mp_sub_ll_overflow(lhs_val, rhs_val, &result); + break; case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: - return mp_obj_new_int_from_ll(lhs_val * rhs_val); + overflow = mp_mul_ll_overflow(lhs_val, rhs_val, &result); + break; case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: if (rhs_val == 0) { @@ -211,9 +200,21 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i case MP_BINARY_OP_LSHIFT: case MP_BINARY_OP_INPLACE_LSHIFT: - return mp_obj_new_int_from_ll(lhs_val << (int)rhs_val); + if (rhs_val < 0) { + // negative shift not allowed + mp_raise_ValueError(MP_ERROR_TEXT("negative shift count")); + } + overflow = rhs_val >= (long long)(sizeof(long long) * MP_BITS_PER_BYTE) + || lhs_val > (LLONG_MAX >> rhs_val) + || lhs_val < (LLONG_MIN >> rhs_val); + result = (unsigned long long)lhs_val << rhs_val; + break; case MP_BINARY_OP_RSHIFT: case MP_BINARY_OP_INPLACE_RSHIFT: + if ((int)rhs_val < 0) { + // negative shift not allowed + mp_raise_ValueError(MP_ERROR_TEXT("negative shift count")); + } return mp_obj_new_int_from_ll(lhs_val >> (int)rhs_val); case MP_BINARY_OP_POWER: @@ -225,18 +226,18 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mp_raise_ValueError(MP_ERROR_TEXT("negative power with no float support")); #endif } - long long ans = 1; - while (rhs_val > 0) { + result = 1; + while (rhs_val > 0 && !overflow) { if (rhs_val & 1) { - ans *= lhs_val; + overflow = mp_mul_ll_overflow(result, lhs_val, &result); } - if (rhs_val == 1) { + if (rhs_val == 1 || overflow) { break; } rhs_val /= 2; - lhs_val *= lhs_val; + overflow = mp_mul_ll_overflow(lhs_val, lhs_val, &lhs_val); } - return mp_obj_new_int_from_ll(ans); + break; } case MP_BINARY_OP_LESS: @@ -254,8 +255,14 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return MP_OBJ_NULL; // op not supported } + if (overflow) { + raise_long_long_overflow(); + } + + return mp_obj_new_int_from_ll(result); + zero_division: - mp_raise_ZeroDivisionError(); + mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero")); } mp_obj_t mp_obj_new_int(mp_int_t value) { @@ -277,22 +284,12 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) { } mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { - // TODO raise an exception if the unsigned long long won't fit if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) { - mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("ulonglong too large")); + raise_long_long_overflow(); } return mp_obj_new_int_from_ll(val); } -mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { - // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated - // TODO check overflow - char *endptr; - mp_obj_t result = mp_obj_new_int_from_ll(strtoll(*str, &endptr, base)); - *str = endptr; - return result; -} - mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { if (mp_obj_is_small_int(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); @@ -303,8 +300,33 @@ mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { } mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { - // TODO: Check overflow - return mp_obj_int_get_truncated(self_in); + if (mp_obj_is_small_int(self_in)) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + const mp_obj_int_t *self = self_in; + long long value = self->val; + mp_int_t truncated = (mp_int_t)value; + if ((long long)truncated == value) { + return truncated; + } + } + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting long int to machine word")); +} + +mp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in) { + if (mp_obj_is_small_int(self_in)) { + if (MP_OBJ_SMALL_INT_VALUE(self_in) >= 0) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } + } else { + const mp_obj_int_t *self = self_in; + long long value = self->val; + mp_uint_t truncated = (mp_uint_t)value; + if (value >= 0 && (long long)truncated == value) { + return truncated; + } + } + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting long int to machine word")); } #if MICROPY_PY_BUILTINS_FLOAT @@ -315,4 +337,88 @@ mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { } #endif +// Same as the general mp_small_int_buffer_overflow_check() in objint_impl.h, but using 64-bit integers +static void longint_buffer_overflow_check(mp_longint_impl_t val, size_t nbytes, bool is_signed) { + // Fast path for zero. + if (val == 0) { + return; + } + + if (!is_signed && val < 0) { + // Trying to store negative values in unsigned bytes + mp_obj_int_raise_unsigned_negative_overflow_error(); + } + + if (nbytes >= sizeof(val)) { + // All non-negative N bit signed integers fit in an unsigned N bit integer. + // This case prevents shifting too far below. + return; + } + + if (nbytes == 0) { + // Can't fit a non-zero value in 0 bytes (prevents negative left shift below) + goto raise; + } + + if (is_signed) { + mp_longint_impl_t edge = 1LL << (nbytes * 8 - 1); + if (-edge <= val && val < edge) { + return; + } + // Out of range, fall through to failure. + } else { + // Unsigned. We already know val >= 0. + mp_longint_impl_t edge = 1LL << (nbytes * 8); + if (val < edge) { + return; + } + // Fall through to failure. + } + +raise: + mp_obj_int_raise_to_bytes_overflow_error(nbytes); +} + +static void longint_to_bytes(long long val, bool big_endian, size_t len, byte *buf) { + MP_STATIC_ASSERT(sizeof(mp_uint_t) == 4); + mp_uint_t lower = val; + mp_uint_t upper = (val >> 32); + + if (big_endian) { + if (len > 4) { + // write the least significant 4 bytes at the end + mp_binary_set_int(4, buf + len - 4, sizeof(lower), lower, true); + // write most significant bytes at the start, extending if necessary + mp_binary_set_int(len - 4, buf, sizeof(upper), upper, true); + } else { + mp_binary_set_int(len, buf, sizeof(lower), lower, true); + } + } else { + // write the least significant 4 bytes at the start + mp_binary_set_int(len > 4 ? len - 4 : len, buf, sizeof(lower), lower, false); + if (len > 4) { + // write the most significant bytes at the end, extending if necessary + mp_binary_set_int(len - 4, buf + 4, sizeof(upper), upper, false); + } + } +} + +void mp_obj_int_to_bytes(mp_obj_t self_in, size_t buf_len, byte *buf, bool big_endian, bool is_signed, bool overflow_check) { + mp_longint_impl_t val; + if (mp_obj_is_exact_type(self_in, &mp_type_int)) { + const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + val = self->val; + } else { + // self_in is either a smallint, or another type convertible to mp_int_t (i.e. bool) + val = mp_obj_get_int(self_in); + } + + // Note: to save code size we don't call mp_obj_small_int_to_bytes() here, + // as the longint implementation is very similar + if (overflow_check) { + longint_buffer_overflow_check(val, buf_len, is_signed); + } + longint_to_bytes(val, big_endian, buf_len, buf); +} + #endif diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 111f53009fb..f002dfe68a9 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -30,7 +30,7 @@ #include "py/parsenumbase.h" #include "py/smallint.h" -#include "py/objint.h" +#include "py/objint_impl.h" #include "py/runtime.h" #if MICROPY_PY_BUILTINS_FLOAT @@ -119,12 +119,6 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf return MP_OBJ_FROM_PTR(o); } -bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { - assert(mp_obj_is_exact_type(self_in, &mp_type_int)); - mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); - return mpz_as_bytes(&self->mpz, big_endian, self->mpz.neg, len, buf); -} - int mp_obj_int_sign(mp_obj_t self_in) { if (mp_obj_is_small_int(self_in)) { mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self_in); @@ -364,9 +358,10 @@ static mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { if (!mp_obj_is_int(base) || !mp_obj_is_int(exponent) || !mp_obj_is_int(modulus)) { mp_raise_TypeError(MP_ERROR_TEXT("pow() with 3 arguments requires integers")); + } else if (modulus == MP_OBJ_NEW_SMALL_INT(0)) { + mp_raise_ValueError(MP_ERROR_TEXT("divide by zero")); } else { - mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int - mp_obj_int_t *res_p = (mp_obj_int_t *)MP_OBJ_TO_PTR(result); + mp_obj_int_t *res_p = mp_obj_int_new_mpz(); mpz_t l_temp, r_temp, m_temp; mpz_t *lhs = mp_mpz_for_int(base, &l_temp); @@ -389,7 +384,7 @@ mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { if (mod == &m_temp) { mpz_deinit(mod); } - return result; + return MP_OBJ_FROM_PTR(res_p); } } #endif @@ -482,4 +477,22 @@ mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { } #endif +void mp_obj_int_to_bytes(mp_obj_t self_in, size_t buf_len, byte *buf, bool big_endian, bool is_signed, bool overflow_check) { + if (mp_obj_is_exact_type(self_in, &mp_type_int)) { + const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + const mpz_t *mpz = &self->mpz; + if (overflow_check && !is_signed && mpz->neg) { + mp_obj_int_raise_unsigned_negative_overflow_error(); + } + if (!mpz_as_bytes(mpz, big_endian, is_signed, buf_len, buf) && overflow_check) { + mp_obj_int_raise_to_bytes_overflow_error(buf_len); + } + } else { + // self_in is either a smallint, or another type convertible to mp_int_t (i.e. bool) + mp_int_t val = mp_obj_get_int(self_in); + mp_obj_small_int_to_bytes(val, buf_len, buf, big_endian, is_signed, overflow_check); + } +} + + #endif diff --git a/py/objlist.c b/py/objlist.c index 3137e9fa534..3edf1e4244b 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -118,7 +118,7 @@ static mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } static mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: allow subclassing mp_obj_list_t *o = native_list(lhs); switch (op) { case MP_BINARY_OP_ADD: { @@ -142,7 +142,7 @@ static mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { if (n < 0) { n = 0; } - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: overflow check (PR#1279) size_t new_len = mp_seq_multiply_len(o->len, n); mp_obj_list_t *s = list_new(new_len); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); @@ -171,76 +171,66 @@ static mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { } static mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { - // CIRCUITPY-CHANGE - mp_obj_list_t *self = native_list(self_in); - if (value == MP_OBJ_NULL) { - // delete - #if MICROPY_PY_BUILTINS_SLICE - if (mp_obj_is_type(index, &mp_type_slice)) { - mp_bound_slice_t slice; - if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { - mp_raise_NotImplementedError(NULL); + #if MICROPY_PY_BUILTINS_SLICE + if (mp_obj_is_type(index, &mp_type_slice)) { + // CIRCUITPY-CHANGE: handle subclassing + mp_obj_list_t *self = native_list(self_in); + mp_bound_slice_t slice; + bool fast = mp_seq_get_fast_slice_indexes(self->len, index, &slice); + if (value == MP_OBJ_SENTINEL) { + // load + if (!fast) { + return mp_seq_extract_slice(self->items, &slice); } - - mp_int_t len_adj = slice.start - slice.stop; - assert(len_adj <= 0); - mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items /*NULL*/, 0, sizeof(*self->items)); + mp_obj_list_t *res = list_new(slice.stop - slice.start); + mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); + return MP_OBJ_FROM_PTR(res); + } + // assign/delete + if (value == MP_OBJ_NULL) { + // delete is equivalent to slice assignment of an empty sequence + value = mp_const_empty_tuple; + } + if (!fast) { + mp_raise_NotImplementedError(NULL); + } + size_t value_len; + mp_obj_t *value_items; + mp_obj_get_array(value, &value_len, &value_items); + mp_int_t len_adj = value_len - (slice.stop - slice.start); + if (len_adj > 0) { + if (self->len + len_adj > self->alloc) { + // TODO: Might optimize memory copies here by checking if block can + // be grown inplace or not + self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj); + self->alloc = self->len + len_adj; + } + mp_seq_replace_slice_grow_inplace(self->items, self->len, + slice.start, slice.stop, value_items, value_len, len_adj, sizeof(*self->items)); + } else { + mp_seq_replace_slice_no_grow(self->items, self->len, + slice.start, slice.stop, value_items, value_len, sizeof(*self->items)); // Clear "freed" elements at the end of list mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); - self->len += len_adj; - return mp_const_none; + // TODO: apply allocation policy re: alloc_size } - #endif - // CIRCUITPY-CHANGE - mp_obj_t args[2] = {MP_OBJ_FROM_PTR(self), index}; + self->len += len_adj; + return mp_const_none; + } + #endif + if (value == MP_OBJ_NULL) { + // delete + // CIRCUITPY-CHANGE: handle subclassing + mp_obj_t args[2] = {MP_OBJ_FROM_PTR(self_in), index}; list_pop(2, args); return mp_const_none; } else if (value == MP_OBJ_SENTINEL) { // load - #if MICROPY_PY_BUILTINS_SLICE - if (mp_obj_is_type(index, &mp_type_slice)) { - mp_bound_slice_t slice; - if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { - return mp_seq_extract_slice(self->items, &slice); - } - mp_obj_list_t *res = list_new(slice.stop - slice.start); - mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); - return MP_OBJ_FROM_PTR(res); - } - #endif + // CIRCUITPY-CHANGE: handle subclassing + mp_obj_list_t *self = native_list(self_in); size_t index_val = mp_get_index(self->base.type, self->len, index, false); return self->items[index_val]; } else { - #if MICROPY_PY_BUILTINS_SLICE - if (mp_obj_is_type(index, &mp_type_slice)) { - size_t value_len; - mp_obj_t *value_items; - mp_obj_get_array(value, &value_len, &value_items); - mp_bound_slice_t slice_out; - if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) { - mp_raise_NotImplementedError(NULL); - } - mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start); - if (len_adj > 0) { - if (self->len + len_adj > self->alloc) { - // TODO: Might optimize memory copies here by checking if block can - // be grown inplace or not - self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj); - self->alloc = self->len + len_adj; - } - mp_seq_replace_slice_grow_inplace(self->items, self->len, - slice_out.start, slice_out.stop, value_items, value_len, len_adj, sizeof(*self->items)); - } else { - mp_seq_replace_slice_no_grow(self->items, self->len, - slice_out.start, slice_out.stop, value_items, value_len, sizeof(*self->items)); - // Clear "freed" elements at the end of list - mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); - // TODO: apply allocation policy re: alloc_size - } - self->len += len_adj; - return mp_const_none; - } - #endif mp_obj_list_store(self_in, index, value); return mp_const_none; } @@ -252,7 +242,7 @@ static mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); if (self->len >= self->alloc) { self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); @@ -266,7 +256,7 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { static mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); if (mp_obj_is_type(arg_in, &mp_type_list)) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); mp_obj_list_t *arg = native_list(arg_in); @@ -285,7 +275,7 @@ static mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { return mp_const_none; // return None, as per CPython } -// CIRCUITPY-CHANGE: used elsewhere so not static; impl is different +// CIRCUITPY-CHANGE: provide version for C use outside this file inline mp_obj_t mp_obj_list_pop(mp_obj_list_t *self, size_t index) { if (self->len == 0) { // CIRCUITPY-CHANGE: more specific mp_raise @@ -303,18 +293,28 @@ inline mp_obj_t mp_obj_list_pop(mp_obj_list_t *self, size_t index) { return ret; } -// CIRCUITPY-CHANGE static mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); mp_obj_list_t *self = native_list(args[0]); size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); + // CIRCUITPY-CHANGE: use factored-out pop code return mp_obj_list_pop(self, index); } +// "head" is actually the *exclusive lower bound* of the range to sort. That is, +// the first element to be sorted is `head[1]`, not `head[0]`. Similarly `tail` +// is an *inclusive upper bound* of the range to sort. That is, the final +// element to sort is `tail[0]`, not `tail[-1]`. +// +// The pivot element is always chosen as `tail[0]`. +// +// These unusual choices allows structuring the partitioning +// process as a do/while loop, which generates smaller code than the equivalent +// code with usual C bounds & a while or for loop. static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) { mp_cstack_check(); - while (head < tail) { - mp_obj_t *h = head - 1; + while (tail - head > 1) { // So long as at least 2 elements remain + mp_obj_t *h = head; mp_obj_t *t = tail; mp_obj_t v = key_fn == MP_OBJ_NULL ? tail[0] : mp_call_function_1(key_fn, tail[0]); // get pivot using key_fn for (;;) { @@ -325,19 +325,21 @@ static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj if (h >= t) { break; } + // A pair of objects must be swapped to the other side of the partition mp_obj_t x = h[0]; h[0] = t[0]; t[0] = x; } + // Place the pivot element in the proper position mp_obj_t x = h[0]; h[0] = tail[0]; tail[0] = x; // do the smaller recursive call first, to keep stack within O(log(N)) - if (t - head < tail - h - 1) { + if (t - head < tail - h) { mp_quicksort(head, t, key_fn, binop_less_result); - head = h + 1; + head = h; } else { - mp_quicksort(h + 1, tail, key_fn, binop_less_result); + mp_quicksort(h, tail, key_fn, binop_less_result); tail = t; } } @@ -362,7 +364,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ mp_obj_list_t *self = native_list(pos_args[0]); if (self->len > 1) { - mp_quicksort(self->items, self->items + self->len - 1, + mp_quicksort(self->items - 1, self->items + self->len - 1, args.key.u_obj == mp_const_none ? MP_OBJ_NULL : args.key.u_obj, args.reverse.u_bool ? mp_const_false : mp_const_true); } @@ -370,10 +372,10 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ return mp_const_none; } -// CIRCUITPY-CHANGE: used elsewhere so not static +// CIRCUITPY-CHANGE: rename and make not static for use elsewhere mp_obj_t mp_obj_list_clear(mp_obj_t self_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); self->len = 0; self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC); @@ -384,27 +386,28 @@ mp_obj_t mp_obj_list_clear(mp_obj_t self_in) { static mp_obj_t list_copy(mp_obj_t self_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); return mp_obj_new_list(self->len, self->items); } static mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); return mp_seq_count_obj(self->items, self->len, value); } static mp_obj_t list_index(size_t n_args, const mp_obj_t *args) { mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } -// CIRCUITPY-CHANGE: used elsewhere so not static -inline void mp_obj_list_insert(mp_obj_list_t *self, size_t index, mp_obj_t obj) { +// CIRCUITPY-CHANGE: factor out for C use elsewhere; not meant to emulate Python API +inline void mp_obj_list_insert(mp_obj_list_t *self_in, size_t index, mp_obj_t obj) { + mp_obj_list_t *self = native_list(self_in); mp_obj_list_append(MP_OBJ_FROM_PTR(self), mp_const_none); for (size_t i = self->len - 1; i > index; --i) { @@ -428,7 +431,7 @@ static mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { if ((size_t)index > self->len) { index = self->len; } - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: use factored-out insert code mp_obj_list_insert(self, index, obj); return mp_const_none; } @@ -526,27 +529,6 @@ mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) { return MP_OBJ_FROM_PTR(o); } -void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { - // CIRCUITPY-CHANGE - mp_obj_list_t *self = native_list(self_in); - *len = self->len; - *items = self->items; -} - -void mp_obj_list_set_len(mp_obj_t self_in, size_t len) { - // trust that the caller knows what it's doing - // TODO realloc if len got much smaller than alloc - mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); - self->len = len; -} - -void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { - // CIRCUITPY-CHANGE - mp_obj_list_t *self = native_list(self_in); - size_t i = mp_get_index(self->base.type, self->len, index, false); - self->items[i] = value; -} - /******************************************************************************/ /* list iterator */ @@ -578,3 +560,22 @@ mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t * o->cur = cur; return MP_OBJ_FROM_PTR(o); } + +mp_obj_list_t *mp_obj_list_optional_arg(mp_obj_t arg_in, size_t min_len) { + if (arg_in == MP_OBJ_NULL || arg_in == mp_const_none) { + return MP_OBJ_TO_PTR(mp_obj_new_list(min_len, NULL)); + } else { + return mp_obj_list_ensure(arg_in, min_len); + } +} + +mp_obj_list_t *mp_obj_list_ensure(mp_obj_t in, size_t min_len) { + if (!mp_obj_is_type(in, &mp_type_list)) { + mp_raise_TypeError(NULL); + } + mp_obj_list_t *list = MP_OBJ_TO_PTR(in); + if (list->len < min_len) { + mp_raise_ValueError(NULL); + } + return list; +} diff --git a/py/objlist.h b/py/objlist.h index 3fd49baf29f..6d5b3107443 100644 --- a/py/objlist.h +++ b/py/objlist.h @@ -37,8 +37,41 @@ typedef struct _mp_obj_list_t { void mp_obj_list_init(mp_obj_list_t *o, size_t n); mp_obj_t mp_obj_list_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args); +mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); +mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); +mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value); +// CIRCUITPY-CHANGE: public routine +mp_obj_t mp_obj_list_clear(mp_obj_t self_in); // CIRCUITPY-CHANGE: new public functions mp_obj_t mp_obj_list_pop(mp_obj_list_t *self, size_t index); void mp_obj_list_insert(mp_obj_list_t *self, size_t index, mp_obj_t obj); +static inline void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { + // CIRCUITPY-CHANGE: handle subclassing + mp_obj_list_t *self = (mp_obj_list_t *)MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(self_in, MP_OBJ_FROM_PTR(&mp_type_list))); + *len = self->len; + *items = self->items; +} + +static inline void mp_obj_list_set_len(mp_obj_t self_in, size_t len) { + // trust that the caller knows what it's doing + // TODO realloc if len got much smaller than alloc + mp_obj_list_t *self = (mp_obj_list_t *)MP_OBJ_TO_PTR(self_in); + self->len = len; +} + +static inline void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + // CIRCUITPY-CHANGE: handle subclassing + mp_obj_list_t *self = (mp_obj_list_t *)MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(self_in, MP_OBJ_FROM_PTR(&mp_type_list))); + size_t i = mp_get_index(self->base.type, self->len, index, false); + self->items[i] = value; +} + +// Helper function for pattern of an optional argument which can be a list of a specified size, and is +// allocated on-demand otherwise +mp_obj_list_t *mp_obj_list_optional_arg(mp_obj_t arg_in, size_t min_len); + +// Ensure provided object is a list of minimum length min_len. Raises TypeError & ValueError otherwise. +mp_obj_list_t *mp_obj_list_ensure(mp_obj_t in, size_t min_len); + #endif // MICROPY_INCLUDED_PY_OBJLIST_H diff --git a/py/objmodule.c b/py/objmodule.c index a5c1dee968e..84b6a10f9ab 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -34,11 +34,6 @@ #include "py/runtime.h" #include "py/builtin.h" -// CIRCUITPY-CHANGE -#if CIRCUITPY_WARNINGS -#include "shared-module/warnings/__init__.h" -#endif - static void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); @@ -49,7 +44,7 @@ static void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin module_name = mp_obj_str_get_str(elem->value); } - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ // If we store __file__ to imported modules then try to lookup this // symbol to give more information about the module. elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP); @@ -157,11 +152,13 @@ static const mp_rom_map_elem_t mp_builtin_module_table[] = { }; MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); +#if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES static const mp_rom_map_elem_t mp_builtin_extensible_module_table[] = { // built-in modules declared with MP_REGISTER_EXTENSIBLE_MODULE() MICROPY_REGISTERED_EXTENSIBLE_MODULES }; MP_DEFINE_CONST_MAP(mp_builtin_extensible_module_map, mp_builtin_extensible_module_table); +#endif #if MICROPY_MODULE_ATTR_DELEGATION && defined(MICROPY_MODULE_DELEGATIONS) typedef struct _mp_module_delegation_entry_t { @@ -178,13 +175,13 @@ static const mp_module_delegation_entry_t mp_builtin_module_delegation_table[] = // Attempts to find (and initialise) a built-in, otherwise returns // MP_OBJ_NULL. mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) { - // CIRCUITPY-CHANGE - #if CIRCUITPY_PARALLELDISPLAYBUS && CIRCUITPY_WARNINGS - if (module_name == MP_QSTR_paralleldisplay) { - warnings_warn(&mp_type_FutureWarning, MP_ERROR_TEXT("%q renamed %q"), MP_QSTR_paralleldisplay, MP_QSTR_paralleldisplaybus); - } + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES + const mp_map_t *map = extensible ? &mp_builtin_extensible_module_map : &mp_builtin_module_map; + #else + const mp_map_t *map = &mp_builtin_module_map; #endif - mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)(extensible ? &mp_builtin_extensible_module_map : &mp_builtin_module_map), MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + if (!elem) { #if MICROPY_PY_SYS // Special case for sys, which isn't extensible but can always be @@ -194,6 +191,7 @@ mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) { } #endif + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES if (extensible) { // At this point we've already tried non-extensible built-ins, the // filesystem, and now extensible built-ins. No match, so fail @@ -210,6 +208,7 @@ mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) { // the old behaviour of the u-prefix being used to force a built-in // import. // CIRCUITPY-CHANGE: Don't look for `ufoo`. + #endif return MP_OBJ_NULL; } diff --git a/py/objmodule.h b/py/objmodule.h index 8b14cd9fc3d..4724270a11c 100644 --- a/py/objmodule.h +++ b/py/objmodule.h @@ -32,13 +32,23 @@ // Only include module definitions when not doing qstr extraction, because the // qstr extraction stage also generates this module definition header file. #include "genhdr/moduledefs.h" +// CIRCUITPY-CHANGE: avoid undef warning +#else +#define MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES (0) #endif extern const mp_map_t mp_builtin_module_map; + +#if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES extern const mp_map_t mp_builtin_extensible_module_map; +#endif mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible); void mp_module_generic_attr(qstr attr, mp_obj_t *dest, const uint16_t *keys, mp_obj_t *values); +static inline mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t module) { + return ((mp_obj_module_t *)MP_OBJ_TO_PTR(module))->globals; +} + #endif // MICROPY_INCLUDED_PY_OBJMODULE_H diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index b6bbe6e05d8..d687dbfda59 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -73,7 +73,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(namedtuple_asdict_obj, namedtuple_asdict); void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_namedtuple_t *o = MP_OBJ_TO_PTR(o_in); - mp_printf(print, "%q", o->tuple.base.type->name); + mp_printf(print, "%q", (qstr)o->tuple.base.type->name); const qstr *fields = ((mp_obj_namedtuple_type_t *)o->tuple.base.type)->fields; mp_obj_attrtuple_print_helper(print, fields, &o->tuple); } diff --git a/py/objrange.c b/py/objrange.c index bde2ebaabb4..dea9fe5f296 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -41,9 +41,9 @@ typedef struct _mp_obj_range_it_t { static mp_obj_t range_it_iternext(mp_obj_t o_in) { mp_obj_range_it_t *o = MP_OBJ_TO_PTR(o_in); if ((o->step > 0 && o->cur < o->stop) || (o->step < 0 && o->cur > o->stop)) { - mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(o->cur); + mp_int_t cur = o->cur; o->cur += o->step; - return o_out; + return mp_obj_new_int(cur); } else { return MP_OBJ_STOP_ITERATION; } @@ -133,7 +133,7 @@ static mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len > 0); case MP_UNARY_OP_LEN: - return MP_OBJ_NEW_SMALL_INT(len); + return mp_obj_new_int(len); default: return MP_OBJ_NULL; // op not supported } @@ -165,20 +165,16 @@ static mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { #if MICROPY_PY_BUILTINS_SLICE if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; - mp_seq_get_fast_slice_indexes(len, index, &slice); + mp_obj_slice_indices(index, len, &slice); mp_obj_range_t *o = mp_obj_malloc(mp_obj_range_t, &mp_type_range); o->start = self->start + slice.start * self->step; o->stop = self->start + slice.stop * self->step; o->step = slice.step * self->step; - if (slice.step < 0) { - // Negative slice steps have inclusive stop, so adjust for exclusive - o->stop -= self->step; - } return MP_OBJ_FROM_PTR(o); } #endif size_t index_val = mp_get_index(self->base.type, len, index, false); - return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step); + return mp_obj_new_int(self->start + index_val * self->step); } else { return MP_OBJ_NULL; // op not supported } diff --git a/py/objringio.c b/py/objringio.c index ba1ec25307e..0025b26be3b 100644 --- a/py/objringio.c +++ b/py/objringio.c @@ -39,22 +39,19 @@ typedef struct _micropython_ringio_obj_t { static mp_obj_t micropython_ringio_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_int_t buff_size = -1; mp_buffer_info_t bufinfo = {NULL, 0, 0}; if (!mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) { - buff_size = mp_obj_get_int(args[0]); + bufinfo.len = mp_obj_get_int(args[0]) + 1; + bufinfo.buf = m_new(uint8_t, bufinfo.len); } - micropython_ringio_obj_t *self = mp_obj_malloc(micropython_ringio_obj_t, type); - if (bufinfo.buf != NULL) { - // buffer passed in, use it directly for ringbuffer. - self->ringbuffer.buf = bufinfo.buf; - self->ringbuffer.size = bufinfo.len; - self->ringbuffer.iget = self->ringbuffer.iput = 0; - } else { - // Allocate new buffer, add one extra to buff_size as ringbuf consumes one byte for tracking. - ringbuf_alloc(&(self->ringbuffer), buff_size + 1); + if (bufinfo.len < 2 || bufinfo.len > UINT16_MAX) { + mp_raise_ValueError(NULL); } + micropython_ringio_obj_t *self = mp_obj_malloc(micropython_ringio_obj_t, type); + self->ringbuffer.buf = bufinfo.buf; + self->ringbuffer.size = bufinfo.len; + self->ringbuffer.iget = self->ringbuffer.iput = 0; return MP_OBJ_FROM_PTR(self); } diff --git a/py/objstr.c b/py/objstr.c index 1874cdb01d0..1db72dc22f5 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -33,6 +33,7 @@ #include "py/objlist.h" #include "py/runtime.h" #include "py/cstack.h" +#include "py/objtuple.h" // CIRCUITPY-CHANGE const char nibble_to_hex_upper[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', @@ -46,7 +47,7 @@ static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ #endif static mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); -static NORETURN void bad_implicit_conversion(mp_obj_t self_in); +static MP_NORETURN void bad_implicit_conversion(mp_obj_t self_in); static mp_obj_t mp_obj_new_str_type_from_vstr(const mp_obj_type_t *type, vstr_t *vstr); @@ -74,6 +75,14 @@ static void check_is_str_or_bytes(mp_obj_t self_in) { mp_check_self(mp_obj_is_str_or_bytes(self_in)); } +static mp_obj_t make_empty_str_of_type(const mp_obj_type_t *type) { + if (type == &mp_type_str) { + return MP_OBJ_NEW_QSTR(MP_QSTR_); // empty str + } else { + return mp_const_empty_bytes; + } +} + static const byte *get_substring_data(const mp_obj_t obj, size_t n_args, const mp_obj_t *args, size_t *len) { // Get substring data from obj, using args[0,1] to specify start and end indices. GET_STR_DATA_LEN(obj, str, str_len); @@ -185,6 +194,79 @@ static void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t } } +#if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK && MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS +// Build a new string from data containing invalid UTF-8 or ASCII, either skipping the +// invalid bytes (errors=="ignore") or replacing them with U+FFFD +// (errors=="replace"). +static mp_obj_t str_from_invalid(mp_encoding_t encoding, const mp_obj_type_t *type, const byte *str_data, size_t str_len, qstr errors) { + bool do_replace = (errors == MP_QSTR_replace); + bool is_utf8 = (encoding == MP_ENCODING_UTF8); + vstr_t vstr; + vstr_init(&vstr, str_len); + const byte *p = str_data; + const byte *end = str_data + str_len; + + while (p < end) { + byte c = *p; + if (c < 0x80) { + // Valid ASCII + vstr_add_byte(&vstr, c); + p++; + } else if (is_utf8 && c >= 0xc0 && c < 0xf8) { + // Potential multi-byte sequence + uint8_t need = (0xe5 >> ((c >> 3) & 0x6)) & 3; + const byte *seq_start = p; + p++; + + // Check continuation bytes + uint8_t got = 0; + while (got < need && p < end && UTF8_IS_CONT(*p)) { + got++; + p++; + } + + if (got == need) { + // Valid complete sequence, decode and add the character + unichar ch = *seq_start & (0x7f >> need); + for (uint8_t i = 0; i < need; i++) { + ch = (ch << 6) | (seq_start[i + 1] & 0x3f); + } + vstr_add_char(&vstr, ch); + } else if (do_replace) { + // Invalid or incomplete sequence - replace with U+FFFD + vstr_add_char(&vstr, 0xFFFD); + } + // For 'ignore' mode, do nothing (skip invalid bytes) + } else if (do_replace) { + // Invalid start byte or non-ascii char - replace with U+FFFD + vstr_add_char(&vstr, 0xFFFD); + p++; + } else { + // Invalid start byte or non-ascii char - skip for 'ignore' mode + p++; + } + } + + return mp_obj_new_str_type_from_vstr(type, &vstr); +} +#endif // MICROPY_PY_BUILTINS_STR_UNICODE_CHECK && MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS + +#if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK +static mp_encoding_t parse_encoding_arg(qstr encoding) { + if (encoding == MP_QSTR_utf_hyphen_8 || encoding == MP_QSTR_utf8) { + return MP_ENCODING_UTF8; + } + if (encoding == MP_QSTR_ascii) { + return MP_ENCODING_ASCII; + } + #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE + mp_raise_type(&mp_type_LookupError); + #else + mp_raise_msg_varg(&mp_type_LookupError, MP_ERROR_TEXT("unknown encoding: %q"), encoding); + #endif +} +#endif + mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { #if MICROPY_CPYTHON_COMPAT if (n_kw != 0) { @@ -206,36 +288,61 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ return mp_obj_new_str_type_from_vstr(type, &vstr); } - default: // 2 or 3 args - // TODO: validate 2nd/3rd args + default: { // 2 or 3 args + // Extract the source data. + const byte *str_data; + size_t str_len; if (mp_obj_is_type(args[0], &mp_type_bytes)) { - GET_STR_DATA_LEN(args[0], str_data, str_len); - GET_STR_HASH(args[0], str_hash); - if (str_hash == 0) { - str_hash = qstr_compute_hash(str_data, str_len); + // Immutable bytes can be referenced directly (zero-copy); + GET_STR_DATA_LEN(args[0], bytes_data, bytes_len); + str_data = bytes_data; + str_len = bytes_len; + } else { + // any other buffer object is mutable sob its data must be copied. + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + str_data = bufinfo.buf; + str_len = bufinfo.len; + } + + #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK + mp_encoding_t encoding = parse_encoding_arg(mp_obj_str_get_qstr(args[1])); + if (!unicode_encoding_check(encoding, str_data, str_len)) { + #if MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS + // Check if error handler is specified (3rd argument) + qstr errors = MP_QSTR_; // default to "" + if (n_args >= 3 && args[2] != mp_const_none) { + errors = mp_obj_str_get_qstr(args[2]); } - #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK - if (!utf8_check(str_data, str_len)) { - mp_raise_msg(&mp_type_UnicodeError, NULL); + if (errors == MP_QSTR_ignore || errors == MP_QSTR_replace) { + return str_from_invalid(encoding, type, str_data, str_len, errors); } - #endif + #endif // MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS + mp_raise_msg(&mp_type_UnicodeError, NULL); + } + #endif // MICROPY_PY_BUILTINS_STR_UNICODE_CHECK - // Check if a qstr with this data already exists - qstr q = qstr_find_strn((const char *)str_data, str_len); - if (q != MP_QSTRnull) { - return MP_OBJ_NEW_QSTR(q); - } + // Check if a qstr with this data already exists + qstr q = qstr_find_strn((const char *)str_data, str_len); + if (q != MP_QSTRnull) { + return MP_OBJ_NEW_QSTR(q); + } - mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len)); - o->data = str_data; - o->hash = str_hash; - return MP_OBJ_FROM_PTR(o); - } else { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); - // This will utf-8 check the input. - return mp_obj_new_str(bufinfo.buf, bufinfo.len); + if (!mp_obj_is_type(args[0], &mp_type_bytes)) { + // Source is a mutable buffer: copy the data. + return mp_obj_new_str_copy(type, str_data, str_len); + } + + // Source is immutable bytes: reference its data without copying. + GET_STR_HASH(args[0], str_hash); + if (str_hash == 0) { + str_hash = qstr_compute_hash(str_data, str_len); } + mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len)); + o->data = str_data; + o->hash = str_hash; + return MP_OBJ_FROM_PTR(o); + } } } @@ -266,11 +373,20 @@ static mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size mp_raise_TypeError(MP_ERROR_TEXT("string argument without an encoding")); #endif } + GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); if (str_hash == 0) { str_hash = qstr_compute_hash(str_data, str_len); } + + #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK + mp_encoding_t encoding = parse_encoding_arg(mp_obj_str_get_qstr(args[1])); + if (encoding == MP_ENCODING_ASCII && !unicode_encoding_check(MP_ENCODING_ASCII, str_data, str_len)) { + mp_raise_msg(&mp_type_UnicodeError, NULL); + } + #endif + mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(&mp_type_bytes, NULL, str_len)); o->data = str_data; o->hash = str_hash; @@ -288,7 +404,10 @@ static mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size } vstr_t vstr; vstr_init_len(&vstr, len); + // If this config is set then the GC clears all memory, so we don't need to. + #if !MICROPY_GC_CONSERVATIVE_CLEAR memset(vstr.buf, 0, len); + #endif return mp_obj_new_bytes_from_vstr(&vstr); } @@ -372,8 +491,7 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mp_obj_t *args = &rhs_in; size_t n_args = 1; mp_obj_t dict = MP_OBJ_NULL; - if (mp_obj_is_type(rhs_in, &mp_type_tuple)) { - // TODO: Support tuple subclasses? + if (mp_obj_is_tuple_compatible(rhs_in)) { mp_obj_tuple_get(rhs_in, &n_args, &args); } else if (mp_obj_is_type(rhs_in, &mp_type_dict)) { dict = rhs_in; @@ -395,11 +513,7 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return MP_OBJ_NULL; // op not supported } if (n <= 0) { - if (lhs_type == &mp_type_str) { - return MP_OBJ_NEW_QSTR(MP_QSTR_); // empty str - } else { - return mp_const_empty_bytes; - } + return make_empty_str_of_type(lhs_type); } // CIRCUITPY-CHANGE: more careful checking of length size_t new_len = mp_seq_multiply_len(lhs_len, n); @@ -780,11 +894,29 @@ static mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, b const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); check_is_str_or_bytes(args[0]); - // check argument type - str_check_arg_type(self_type, args[1]); - GET_STR_DATA_LEN(args[0], haystack, haystack_len); - GET_STR_DATA_LEN(args[1], needle, needle_len); + + mp_int_t val; + byte needle_data; + const byte *needle; + size_t needle_len; + if (self_type != &mp_type_str && mp_obj_get_int_maybe(args[1], &val)) { + // Allow {bytes/bytearray}.{find,index}(int). + #if MICROPY_FULL_CHECKS + if (val < 0 || val > 255) { + mp_raise_ValueError(MP_ERROR_TEXT("bytes value out of range")); + } + #endif + needle_data = val; + needle = &needle_data; + needle_len = 1; + } else { + // check argument type + str_check_arg_type(self_type, args[1]); + GET_STR_DATA_LEN(args[1], needle_tmp, needle_len_tmp); + needle = needle_tmp; + needle_len = needle_len_tmp; + } const byte *start = haystack; const byte *end = haystack + haystack_len; @@ -920,11 +1052,7 @@ static mp_obj_t str_uni_strip(int type, size_t n_args, const mp_obj_t *args) { if (!first_good_char_pos_set) { // string is all whitespace, return '' - if (self_type == &mp_type_str) { - return MP_OBJ_NEW_QSTR(MP_QSTR_); - } else { - return mp_const_empty_bytes; - } + return make_empty_str_of_type(self_type); } assert(last_good_char_pos >= first_good_char_pos); @@ -958,14 +1086,33 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip); static mp_obj_t str_center(mp_obj_t str_in, mp_obj_t width_in) { GET_STR_DATA_LEN(str_in, str, str_len); mp_uint_t width = mp_obj_get_int(width_in); + + #if MICROPY_PY_BUILTINS_STR_UNICODE + // Get character count (not byte count) for proper Unicode handling + size_t char_len = utf8_charlen(str, str_len); + if (char_len >= width) { + return str_in; + } + // Calculate padding: width is in characters, need to convert to bytes for allocation + mp_uint_t padding_chars = width - char_len; + // Padding is always spaces (1 byte each), plus the original string bytes + mp_uint_t total_bytes = padding_chars + str_len; + #else + // Non-Unicode build: byte length equals character length if (str_len >= width) { return str_in; } + mp_uint_t total_bytes = width; + #endif // MICROPY_PY_BUILTINS_STR_UNICODE vstr_t vstr; - vstr_init_len(&vstr, width); - memset(vstr.buf, ' ', width); + vstr_init_len(&vstr, total_bytes); + memset(vstr.buf, ' ', total_bytes); + #if MICROPY_PY_BUILTINS_STR_UNICODE + int left = padding_chars / 2; + #else int left = (width - str_len) / 2; + #endif // MICROPY_PY_BUILTINS_STR_UNICODE memcpy(vstr.buf + left, str, str_len); return mp_obj_new_str_type_from_vstr(mp_obj_get_type(str_in), &vstr); } @@ -1018,7 +1165,7 @@ static mp_obj_t arg_as_int(mp_obj_t arg) { #endif #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE -static NORETURN void terse_str_format_value_error(void) { +static MP_NORETURN void terse_str_format_value_error(void) { mp_raise_ValueError(MP_ERROR_TEXT("bad format string")); } #else @@ -1026,6 +1173,23 @@ static NORETURN void terse_str_format_value_error(void) { #define terse_str_format_value_error() #endif +// Print the character with the code point given by the integer object arg. +// Used by both the str.format and the modulo (%c) formatters. +static void mp_print_char(const mp_print_t *print, mp_obj_t arg, unsigned int flags, char fill, int width) { + #if MICROPY_FULL_CHECKS + mp_uint_t c = mp_obj_get_int(arg); + if (c >= 0x110000) { + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("char not in range(0x110000)")); + } + VSTR_FIXED(ch_vstr, 4); + vstr_add_char(&ch_vstr, c); + mp_print_strn(print, ch_vstr.buf, ch_vstr.len, flags, fill, width); + #else + char ch = mp_obj_get_int(arg); + mp_print_strn(print, &ch, 1, flags, fill, width); + #endif +} + static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *arg_i, size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { vstr_t vstr; mp_print_t print; @@ -1205,7 +1369,7 @@ static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar int width = -1; int precision = -1; char type = '\0'; - int flags = 0; + unsigned int flags = 0; if (format_spec) { // The format specifier (from http://docs.python.org/2/library/string.html#formatspec) @@ -1250,8 +1414,9 @@ static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } } s = str_to_int(s, stop, &width); - if (*s == ',') { - flags |= PF_FLAG_SHOW_COMMA; + if (*s == ',' || *s == '_') { + MP_STATIC_ASSERT((unsigned)'_' << PF_FLAG_SEP_POS >> PF_FLAG_SEP_POS == '_'); + flags |= (unsigned)*s << PF_FLAG_SEP_POS; s++; } if (*s == '.') { @@ -1318,13 +1483,12 @@ static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar continue; case 'c': { - char ch = mp_obj_get_int(arg); - mp_print_strn(&print, &ch, 1, flags, fill, width); + mp_print_char(&print, arg, flags, fill, width); continue; } case '\0': // No explicit format type implies 'd' - case 'n': // I don't think we support locales in uPy so use 'd' + case 'n': // I don't think we support locales in MicroPython so use 'd' case 'd': mp_print_mp_int(&print, arg, 10, 'a', flags, fill, width, 0); continue; @@ -1615,8 +1779,7 @@ static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ } mp_print_strn(&print, s, 1, flags, ' ', width); } else if (arg_looks_integer(arg)) { - char ch = mp_obj_get_int(arg); - mp_print_strn(&print, &ch, 1, flags, ' ', width); + mp_print_char(&print, arg, flags, ' ', width); } else { mp_raise_TypeError(MP_ERROR_TEXT("%%c needs int or char")); } @@ -1857,15 +2020,9 @@ static mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, int direction) { } mp_obj_t result[3]; - if (self_type == &mp_type_str) { - result[0] = MP_OBJ_NEW_QSTR(MP_QSTR_); - result[1] = MP_OBJ_NEW_QSTR(MP_QSTR_); - result[2] = MP_OBJ_NEW_QSTR(MP_QSTR_); - } else { - result[0] = mp_const_empty_bytes; - result[1] = mp_const_empty_bytes; - result[2] = mp_const_empty_bytes; - } + result[0] = make_empty_str_of_type(self_type); + result[1] = make_empty_str_of_type(self_type); + result[2] = make_empty_str_of_type(self_type); if (direction > 0) { result[0] = self_in; @@ -1984,6 +2141,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower); #if MICROPY_CPYTHON_COMPAT // These methods are superfluous in the presence of str() and bytes() // constructors. + // TODO: should accept kwargs too static mp_obj_t bytes_decode(size_t n_args, const mp_obj_t *args) { mp_obj_t new_args[2]; @@ -2022,7 +2180,7 @@ mp_obj_t mp_obj_bytes_hex(size_t n_args, const mp_obj_t *args, const mp_obj_type // Code below assumes non-zero buffer length when computing size with // separator, so handle the zero-length case here. if (bufinfo.len == 0) { - return mp_const_empty_bytes; + return make_empty_str_of_type(type); } vstr_t vstr; @@ -2314,7 +2472,7 @@ static mp_obj_t mp_obj_new_str_type_from_vstr(const mp_obj_type_t *type, vstr_t mp_obj_t mp_obj_new_str_from_vstr(vstr_t *vstr) { #if MICROPY_PY_BUILTINS_STR_UNICODE && MICROPY_PY_BUILTINS_STR_UNICODE_CHECK - if (!utf8_check((byte *)vstr->buf, vstr->len)) { + if (!unicode_encoding_check(MP_ENCODING_UTF8, (byte *)vstr->buf, vstr->len)) { mp_raise_msg(&mp_type_UnicodeError, NULL); } #endif // MICROPY_PY_BUILTINS_STR_UNICODE && MICROPY_PY_BUILTINS_STR_UNICODE_CHECK @@ -2334,7 +2492,7 @@ mp_obj_t mp_obj_new_bytes_from_vstr(vstr_t *vstr) { mp_obj_t mp_obj_new_str(const char *data, size_t len) { #if MICROPY_PY_BUILTINS_STR_UNICODE && MICROPY_PY_BUILTINS_STR_UNICODE_CHECK - if (!utf8_check((byte *)data, len)) { + if (!unicode_encoding_check(MP_ENCODING_UTF8, (byte *)data, len)) { mp_raise_msg(&mp_type_UnicodeError, NULL); } #endif @@ -2395,7 +2553,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { } } -static NORETURN void bad_implicit_conversion(mp_obj_t self_in) { +static MP_NORETURN void bad_implicit_conversion(mp_obj_t self_in) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE mp_raise_TypeError(MP_ERROR_TEXT("can't convert to str implicitly")); #else diff --git a/py/objstrunicode.c b/py/objstrunicode.c index a158b912365..6dbdccb77fa 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -57,11 +57,11 @@ static void uni_print_quoted(const mp_print_t *print, const byte *str_data, uint mp_printf(print, "%c", quote_char); const byte *s = str_data, *top = str_data + str_len; while (s < top) { + const byte *seq_start = s; unichar ch; ch = utf8_get_char(s); - // CIRCUITPY-CHANGE: print printable Unicode chars - const byte *start = s; s = utf8_next_char(s); + size_t seq_len = s - seq_start; if (ch == quote_char) { mp_printf(print, "\\%c", quote_char); } else if (ch == '\\') { @@ -79,12 +79,15 @@ static void uni_print_quoted(const mp_print_t *print, const byte *str_data, uint mp_printf(print, "\\x%02x", ch); } else if ((0x2000 <= ch && ch <= 0x200f) || ch == 0x2028 || ch == 0x2029 || ch == 0xffff) { mp_printf(print, "\\u%04x", ch); - } else if (ch == 0x1ffff) { + } else if (ch >= 0xd800 && ch < 0xe000) { + // Surrogate (0xD800-0xDFFF) - output as \uXXXX escape. + mp_printf(print, "\\u%04x", ch); + } else if (ch == 0x1ffff || ch >= 0x110000) { + // Invalid - output as \UXXXXXXXX escape. mp_printf(print, "\\U%08x", ch); } else { - // Print the full character out. - int width = s - start; - mp_print_strn(print, (const char *)start, width, 0, ' ', width); + // CIRCUITPY-CHANGE: print printable Unicode chars out in full. + mp_print_strn(print, (const char *)seq_start, seq_len, 0, ' ', seq_len); } } mp_printf(print, "%c", quote_char); diff --git a/py/objtemplate.c b/py/objtemplate.c new file mode 100644 index 00000000000..86451350a21 --- /dev/null +++ b/py/objtemplate.c @@ -0,0 +1,395 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Koudai Aono + * Copyright (c) 2026 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#if MICROPY_PY_TSTRINGS + +typedef struct _mp_obj_template_t { + mp_obj_base_t base; + mp_obj_t strings; + mp_obj_t interpolations; +} mp_obj_template_t; + +typedef struct _mp_obj_interpolation_t { + mp_obj_base_t base; + mp_obj_t value; + mp_obj_t expression; + mp_obj_t conversion; + mp_obj_t format_spec; +} mp_obj_interpolation_t; + +static mp_obj_t mp_obj_new_interpolation(mp_obj_t value, mp_obj_t expr, mp_obj_t conv, mp_obj_t spec); + +static mp_obj_t mp_obj_template_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, MP_OBJ_FUN_ARGS_MAX, false); + + mp_obj_t strings_obj; + mp_obj_t interpolations_obj; + + if (n_args == 0) { + mp_obj_t empty = MP_OBJ_NEW_QSTR(MP_QSTR_); + strings_obj = mp_obj_new_tuple(1, &empty); + interpolations_obj = mp_obj_new_tuple(0, NULL); + } else { + size_t n_interpolations = 0; + size_t n_str_args = 0; + for (size_t i = 0; i < n_args; i++) { + if (mp_obj_is_exact_type(args[i], &mp_type_interpolation)) { + n_interpolations++; + } else if (mp_obj_is_str(args[i])) { + n_str_args++; + } else { + mp_raise_TypeError(MP_ERROR_TEXT("expected str or Interpolation")); + } + } + + if (n_interpolations == 0) { + if (n_str_args == 1) { + strings_obj = mp_obj_new_tuple(1, &args[0]); + } else { + size_t total_len = 0; + for (size_t i = 0; i < n_args; i++) { + size_t str_len; + (void)mp_obj_str_get_data(args[i], &str_len); + total_len += str_len; + } + vstr_t vstr; + vstr_init(&vstr, total_len); + for (size_t i = 0; i < n_args; i++) { + size_t str_len; + const char *str_data = mp_obj_str_get_data(args[i], &str_len); + vstr_add_strn(&vstr, str_data, str_len); + } + mp_obj_t str_items[1]; + str_items[0] = mp_obj_new_str_from_vstr(&vstr); + strings_obj = mp_obj_new_tuple(1, str_items); + } + interpolations_obj = mp_obj_new_tuple(0, NULL); + } else { + size_t n_strings = n_interpolations + 1; + mp_obj_tuple_t *strings_tuple = mp_obj_malloc_var(mp_obj_tuple_t, items, mp_obj_t, n_strings, &mp_type_tuple); + mp_obj_tuple_t *interpolations_tuple = mp_obj_malloc_var(mp_obj_tuple_t, items, mp_obj_t, n_interpolations, &mp_type_tuple); + strings_tuple->len = n_strings; + interpolations_tuple->len = n_interpolations; + + size_t string_idx = 0; + size_t interp_idx = 0; + mp_obj_t current_str = MP_OBJ_NULL; + bool current_vstr_active = false; + vstr_t current_vstr = {0}; + + for (size_t i = 0; i <= n_args; i++) { + if (i == n_args || mp_obj_is_exact_type(args[i], &mp_type_interpolation)) { + mp_obj_t out_str; + if (current_vstr_active) { + out_str = mp_obj_new_str_from_vstr(¤t_vstr); + current_vstr_active = false; + } else if (current_str != MP_OBJ_NULL) { + out_str = current_str; + } else { + out_str = MP_OBJ_NEW_QSTR(MP_QSTR_); + } + strings_tuple->items[string_idx++] = out_str; + current_str = MP_OBJ_NULL; + if (i < n_args) { + interpolations_tuple->items[interp_idx++] = args[i]; + } + } else { + size_t str_len; + const char *str_data = mp_obj_str_get_data(args[i], &str_len); + if (current_vstr_active) { + vstr_add_strn(¤t_vstr, str_data, str_len); + } else if (current_str == MP_OBJ_NULL) { + current_str = args[i]; + } else { + size_t prev_len; + const char *prev_data = mp_obj_str_get_data(current_str, &prev_len); + vstr_init(¤t_vstr, prev_len + str_len); + vstr_add_strn(¤t_vstr, prev_data, prev_len); + vstr_add_strn(¤t_vstr, str_data, str_len); + current_vstr_active = true; + current_str = MP_OBJ_NULL; + } + } + } + + strings_obj = MP_OBJ_FROM_PTR(strings_tuple); + interpolations_obj = MP_OBJ_FROM_PTR(interpolations_tuple); + } + } + + mp_obj_template_t *self = mp_obj_malloc(mp_obj_template_t, type); + self->strings = strings_obj; + self->interpolations = interpolations_obj; + return MP_OBJ_FROM_PTR(self); +} + +static void mp_obj_template_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_template_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "%q(%q=", (qstr)MP_QSTR_Template, (qstr)MP_QSTR_strings); + mp_obj_print_helper(print, self->strings, PRINT_REPR); + mp_printf(print, ", %q=", (qstr)MP_QSTR_interpolations); + mp_obj_print_helper(print, self->interpolations, PRINT_REPR); + mp_print_str(print, ")"); +} + +static mp_obj_t mp_obj_template_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + mp_obj_template_t *lhs = MP_OBJ_TO_PTR(lhs_in); + + switch (op) { + case MP_BINARY_OP_ADD: { + if (!mp_obj_is_exact_type(rhs_in, &mp_type_template)) { + return MP_OBJ_NULL; // op not supported + } + + mp_obj_template_t *rhs = MP_OBJ_TO_PTR(rhs_in); + + mp_obj_tuple_t *lhs_strings = MP_OBJ_TO_PTR(lhs->strings); + mp_obj_tuple_t *lhs_interps = MP_OBJ_TO_PTR(lhs->interpolations); + mp_obj_tuple_t *rhs_strings = MP_OBJ_TO_PTR(rhs->strings); + mp_obj_tuple_t *rhs_interps = MP_OBJ_TO_PTR(rhs->interpolations); + + size_t new_strings_len = lhs_strings->len + rhs_strings->len - 1; + size_t new_interps_len = lhs_interps->len + rhs_interps->len; + + // Create tuples directly to avoid GC issues. + mp_obj_tuple_t *new_strings_tuple = mp_obj_malloc_var(mp_obj_tuple_t, items, mp_obj_t, new_strings_len, &mp_type_tuple); + mp_obj_tuple_t *new_interps_tuple = mp_obj_malloc_var(mp_obj_tuple_t, items, mp_obj_t, new_interps_len, &mp_type_tuple); + new_strings_tuple->len = new_strings_len; + new_interps_tuple->len = new_interps_len; + + // Copy all but the last string from lhs. + for (size_t i = 0; i < lhs_strings->len - 1; i++) { + new_strings_tuple->items[i] = lhs_strings->items[i]; + } + + // Merge last string from lhs with first string from rhs. + size_t lhs_last_len, rhs_first_len; + const char *lhs_last_str = mp_obj_str_get_data(lhs_strings->items[lhs_strings->len - 1], &lhs_last_len); + const char *rhs_first_str = mp_obj_str_get_data(rhs_strings->items[0], &rhs_first_len); + + vstr_t vstr; + vstr_init(&vstr, lhs_last_len + rhs_first_len); + vstr_add_strn(&vstr, lhs_last_str, lhs_last_len); + vstr_add_strn(&vstr, rhs_first_str, rhs_first_len); + new_strings_tuple->items[lhs_strings->len - 1] = mp_obj_new_str_from_vstr(&vstr); + + // Copy remaining strings from rhs. + for (size_t i = 1; i < rhs_strings->len; i++) { + new_strings_tuple->items[lhs_strings->len - 1 + i] = rhs_strings->items[i]; + } + + // Copy interpolations from both sides. + for (size_t i = 0; i < lhs_interps->len; i++) { + new_interps_tuple->items[i] = lhs_interps->items[i]; + } + + for (size_t i = 0; i < rhs_interps->len; i++) { + new_interps_tuple->items[lhs_interps->len + i] = rhs_interps->items[i]; + } + + mp_obj_template_t *result = mp_obj_malloc(mp_obj_template_t, &mp_type_template); + result->strings = MP_OBJ_FROM_PTR(new_strings_tuple); + result->interpolations = MP_OBJ_FROM_PTR(new_interps_tuple); + return MP_OBJ_FROM_PTR(result); + } + + default: + return MP_OBJ_NULL; // op not supported + } +} + +static void mp_obj_template_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + mp_obj_template_t *self = MP_OBJ_TO_PTR(self_in); + + if (dest[0] == MP_OBJ_NULL) { + // Load attribute. + if (attr == MP_QSTR_strings) { + dest[0] = self->strings; + } else if (attr == MP_QSTR_interpolations) { + dest[0] = self->interpolations; + } else if (attr == MP_QSTR_values) { + mp_obj_tuple_t *interps = MP_OBJ_TO_PTR(self->interpolations); + mp_obj_tuple_t *values_tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(interps->len, NULL)); + for (size_t i = 0; i < interps->len; i++) { + mp_obj_interpolation_t *interp = MP_OBJ_TO_PTR(interps->items[i]); + values_tuple->items[i] = interp->value; + } + dest[0] = MP_OBJ_FROM_PTR(values_tuple); + } + } +} + +typedef struct _mp_obj_template_iter_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_t template; + size_t index; +} mp_obj_template_iter_t; + +static mp_obj_t template_iter_iternext(mp_obj_t self_in) { + mp_obj_template_iter_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_template_t *tmpl = MP_OBJ_TO_PTR(self->template); + mp_obj_tuple_t *strings = MP_OBJ_TO_PTR(tmpl->strings); + mp_obj_tuple_t *interps = MP_OBJ_TO_PTR(tmpl->interpolations); + + while (self->index < strings->len + interps->len) { + if ((self->index & 1) == 0) { + // A string. + mp_obj_t str_obj = strings->items[self->index++ / 2]; + size_t str_len; + mp_obj_str_get_data(str_obj, &str_len); + if (str_len > 0) { + return str_obj; + } + } else { + // An interpolation. + return interps->items[self->index++ / 2]; + } + } + + return MP_OBJ_STOP_ITERATION; +} + +static mp_obj_t mp_obj_template_iter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_template_iter_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_template_iter_t *iter = (mp_obj_template_iter_t *)iter_buf; + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = template_iter_iternext; + iter->template = self_in; + iter->index = 0; + return MP_OBJ_FROM_PTR(iter); +} + +MP_DEFINE_CONST_OBJ_TYPE( + mp_type_template, + MP_QSTR_Template, + MP_TYPE_FLAG_NONE, + make_new, mp_obj_template_make_new, + print, mp_obj_template_print, + binary_op, mp_obj_template_binary_op, + attr, mp_obj_template_attr, + iter, mp_obj_template_iter + ); + +mp_obj_t mp_obj_new_template(size_t n_args, const mp_obj_t *args) { + mp_obj_template_t *o = mp_obj_malloc(mp_obj_template_t, &mp_type_template); + o->strings = args[0]; + if (n_args == 2) { + // Unpack interpolations from second argument (which is a tuple). + mp_obj_t *iargs; + mp_obj_get_array(args[1], &n_args, &iargs); + args = iargs; + } else { + // Unpack interpolations directly from arguments. + --n_args; + ++args; + } + size_t n_interpolations = n_args / 4; + mp_obj_tuple_t *interpolations = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_interpolations, NULL)); + for (size_t i = 0; i < n_interpolations; ++i) { + interpolations->items[i] = mp_obj_new_interpolation(args[i * 4], args[i * 4 + 1], args[i * 4 + 2], args[i * 4 + 3]); + } + o->interpolations = MP_OBJ_FROM_PTR(interpolations); + return MP_OBJ_FROM_PTR(o); +} + +///////////////////////////////////////////////////////////////// + +static mp_obj_t mp_obj_interpolation_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_value, ARG_expression, ARG_conversion, ARG_format_spec }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_expression, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_)} }, + { MP_QSTR_conversion, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_format_spec, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_)} }, + }; + + 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); + + mp_obj_interpolation_t *self = mp_obj_malloc(mp_obj_interpolation_t, &mp_type_interpolation); + self->value = args[ARG_value].u_obj; + self->expression = args[ARG_expression].u_obj; + self->conversion = args[ARG_conversion].u_obj; + self->format_spec = args[ARG_format_spec].u_obj; + + return MP_OBJ_FROM_PTR(self); +} + +static void mp_obj_interpolation_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_interpolation_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "%q(", (qstr)MP_QSTR_Interpolation); + mp_obj_print_helper(print, self->value, PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, self->expression, PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, self->conversion, PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, self->format_spec, PRINT_REPR); + mp_print_str(print, ")"); +} + +static void mp_obj_interpolation_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + mp_obj_interpolation_t *self = MP_OBJ_TO_PTR(self_in); + + if (dest[0] == MP_OBJ_NULL) { + // load attribute + if (attr == MP_QSTR_value) { + dest[0] = self->value; + } else if (attr == MP_QSTR_expression) { + dest[0] = self->expression; + } else if (attr == MP_QSTR_conversion) { + dest[0] = self->conversion; + } else if (attr == MP_QSTR_format_spec) { + dest[0] = self->format_spec; + } + } +} + +static mp_obj_t mp_obj_new_interpolation(mp_obj_t value, mp_obj_t expression, mp_obj_t conversion, mp_obj_t format_spec) { + mp_obj_interpolation_t *o = mp_obj_malloc(mp_obj_interpolation_t, &mp_type_interpolation); + o->value = value; + o->expression = expression; + o->conversion = conversion; + o->format_spec = format_spec; + return MP_OBJ_FROM_PTR(o); +} + +MP_DEFINE_CONST_OBJ_TYPE( + mp_type_interpolation, + MP_QSTR_Interpolation, + MP_TYPE_FLAG_NONE, + make_new, mp_obj_interpolation_make_new, + print, mp_obj_interpolation_print, + attr, mp_obj_interpolation_attr + ); + +#endif // MICROPY_PY_TSTRINGS diff --git a/py/objtuple.c b/py/objtuple.c index e0b31edaf23..6808f6c6e0a 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -31,9 +31,6 @@ #include "py/objtuple.h" #include "py/runtime.h" -// type check is done on getiter method to allow tuple, namedtuple, attrtuple -#define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), iter) == mp_obj_tuple_getiter) - /******************************************************************************/ /* tuple */ @@ -107,20 +104,27 @@ static mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg } } +static mp_obj_tuple_t *tuple_subclass_helper(mp_obj_t obj) { + assert(obj != MP_OBJ_NULL); + const mp_obj_type_t *tuple_type = mp_obj_get_type(obj); + if (MP_OBJ_TYPE_GET_SLOT_OR_NULL(tuple_type, iter) != mp_obj_tuple_getiter) { + // Slow path for user subclasses + obj = mp_obj_cast_to_native_base(obj, MP_OBJ_FROM_PTR(&mp_type_tuple)); + if (obj == MP_OBJ_NULL) { + return NULL; + } + } + return MP_OBJ_TO_PTR(obj); +} + // Don't pass MP_BINARY_OP_NOT_EQUAL here static mp_obj_t tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { mp_check_self(mp_obj_is_tuple_compatible(self_in)); - const mp_obj_type_t *another_type = mp_obj_get_type(another_in); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); - if (MP_OBJ_TYPE_GET_SLOT_OR_NULL(another_type, iter) != mp_obj_tuple_getiter) { - // Slow path for user subclasses - another_in = mp_obj_cast_to_native_base(another_in, MP_OBJ_FROM_PTR(&mp_type_tuple)); - if (another_in == MP_OBJ_NULL) { - return MP_OBJ_NULL; - } + mp_obj_tuple_t *another = tuple_subclass_helper(another_in); + if (!another) { + return MP_OBJ_NULL; } - mp_obj_tuple_t *another = MP_OBJ_TO_PTR(another_in); - return mp_obj_new_bool(mp_seq_cmp_objs(op, self->items, self->len, another->items, another->len)); } @@ -149,10 +153,10 @@ mp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: { - if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(rhs)), MP_OBJ_FROM_PTR(&mp_type_tuple))) { + mp_obj_tuple_t *p = tuple_subclass_helper(rhs); + if (!p) { return MP_OBJ_NULL; // op not supported } - mp_obj_tuple_t *p = MP_OBJ_TO_PTR(rhs); mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len + p->len, NULL)); mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); return MP_OBJ_FROM_PTR(s); @@ -267,19 +271,6 @@ mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { return MP_OBJ_FROM_PTR(o); } -void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { - assert(mp_obj_is_tuple_compatible(self_in)); - mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); - *len = self->len; - *items = &self->items[0]; -} - -void mp_obj_tuple_del(mp_obj_t self_in) { - assert(mp_obj_is_type(self_in, &mp_type_tuple)); - mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); - m_del_var(mp_obj_tuple_t, items, mp_obj_t, self->len, self); -} - /******************************************************************************/ /* tuple iterator */ diff --git a/py/objtuple.h b/py/objtuple.h index e2d010e6c5a..f0b081faad6 100644 --- a/py/objtuple.h +++ b/py/objtuple.h @@ -28,6 +28,9 @@ #include "py/obj.h" +// type check is done on getiter method to allow tuple, namedtuple, attrtuple +#define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), iter) == mp_obj_tuple_getiter) + typedef struct _mp_obj_tuple_t { mp_obj_base_t base; size_t len; @@ -49,6 +52,13 @@ mp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs); mp_obj_t mp_obj_tuple_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value); mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf); +static inline void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { + assert(mp_obj_is_tuple_compatible(self_in)); + mp_obj_tuple_t *self = (mp_obj_tuple_t *)MP_OBJ_TO_PTR(self_in); + *len = self->len; + *items = &self->items[0]; +} + extern const mp_obj_type_t mp_type_attrtuple; // CIRCUITPY-CHANGE @@ -57,7 +67,7 @@ extern const mp_obj_type_t mp_type_attrtuple; #define MP_DEFINE_ATTRTUPLE(tuple_obj_name, fields, nitems, ...) \ const mp_rom_obj_tuple_t tuple_obj_name = { \ - .base = {&mp_type_attrtuple}, \ + .base = {.type = &mp_type_attrtuple}, \ .len = nitems, \ .items = { __VA_ARGS__, MP_ROM_PTR((void *)fields) } \ } diff --git a/py/objtype.c b/py/objtype.c index 074d6f39293..e0b35a55d33 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -44,6 +44,7 @@ #define ENABLE_SPECIAL_ACCESSORS \ (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY) +static mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict); static mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo); static mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); @@ -111,7 +112,7 @@ static mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *pos_args return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_KW(native_base_init_wrapper_obj, 1, native_base_init_wrapper); +MP_DEFINE_CONST_FUN_OBJ_KW(mp_native_base_init_wrapper_obj, 1, native_base_init_wrapper); #if !MICROPY_CPYTHON_COMPAT static @@ -125,7 +126,7 @@ mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_ // object. It doesn't matter which object, so long as it can be uniquely // distinguished from a native class that is initialised. if (num_native_bases != 0) { - o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj); + o->subobj[0] = MP_OBJ_FROM_PTR(&mp_native_base_init_wrapper_obj); } return o; } @@ -136,7 +137,7 @@ mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_ // code so it must call this method to ensure that the given object has been __init__'d and is // valid. void mp_obj_assert_native_inited(mp_obj_t native_object) { - if (native_object == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) { + if (native_object == MP_OBJ_FROM_PTR(&mp_native_base_init_wrapper_obj)) { mp_raise_NotImplementedError(MP_ERROR_TEXT("Call super().__init__() before accessing native object.")); } } @@ -394,7 +395,7 @@ static mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_arg // If the type had a native base that was not explicitly initialised // (constructed) by the Python __init__() method then construct it now. - if (native_base != NULL && o->subobj[0] == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) { + if (native_base != NULL && o->subobj[0] == MP_OBJ_FROM_PTR(&mp_native_base_init_wrapper_obj)) { o->subobj[0] = MP_OBJ_TYPE_GET_SLOT(native_base, make_new)(native_base, n_args, n_kw, args); } @@ -690,8 +691,8 @@ static void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des // try __getattr__ if (attr != MP_QSTR___getattr__) { #if MICROPY_PY_DESCRIPTORS - // With descriptors enabled, don't delegate lookups of __get__/__set__/__delete__. - if (attr == MP_QSTR___get__ || attr == MP_QSTR___set__ || attr == MP_QSTR___delete__) { + // With descriptors enabled, don't delegate lookups of __get__/__set__/__delete__/__set_name__. + if (attr == MP_QSTR___get__ || attr == MP_QSTR___set__ || attr == MP_QSTR___delete__ || attr == MP_QSTR___set_name__) { return; } #endif @@ -996,7 +997,7 @@ static bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { #endif #if MICROPY_PY_DESCRIPTORS static const uint8_t to_check[] = { - MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__, + MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__, // not needed for MP_QSTR___set_name__ though }; for (size_t i = 0; i < MP_ARRAY_SIZE(to_check); ++i) { mp_obj_t dest_temp[2]; @@ -1010,10 +1011,52 @@ static bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { } #endif +#if MICROPY_PY_DESCRIPTORS +// Shared data layout for the __set_name__ call and a linked list of calls to be made. +typedef union _setname_list_t setname_list_t; +union _setname_list_t { + mp_obj_t call[4]; + struct { + mp_obj_t _meth; + mp_obj_t _self; + setname_list_t *next; // can use the "owner" argument position temporarily for the linked list + mp_obj_t _name; + }; +}; + +// Append any `__set_name__` method on `value` to the setname list, with its per-attr args +static setname_list_t *setname_maybe_bind_append(setname_list_t *tail, mp_obj_t name, mp_obj_t value) { + // make certain our type-punning is safe: + MP_STATIC_ASSERT_NONCONSTEXPR(offsetof(setname_list_t, next) == offsetof(setname_list_t, call[2])); + + // tail is a blank list entry + mp_load_method_maybe(value, MP_QSTR___set_name__, tail->call); + if (tail->call[1] != MP_OBJ_NULL) { + // Each time a __set_name__ is found, leave it in-place in the former tail and allocate a new tail + tail->next = m_new_obj(setname_list_t); + tail->next->next = NULL; + tail->call[3] = name; + return tail->next; + } else { + return tail; + } +} + +// Execute the captured `__set_name__` calls, destroying the setname list in the process. +static inline void setname_consume_call_all(setname_list_t *head, mp_obj_t owner) { + setname_list_t *next; + while ((next = head->next) != NULL) { + head->call[2] = owner; + mp_call_method_n_kw(2, 0, head->call); + head = next; + } +} +#endif + static void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "", self->name); + mp_printf(print, "", (qstr)self->name); } static mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -1043,7 +1086,7 @@ static mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp if (!MP_OBJ_TYPE_HAS_SLOT(self, make_new)) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE - mp_raise_TypeError(MP_ERROR_TEXT("cannot create instance")); + mp_raise_TypeError(MP_ERROR_TEXT("can't create instance")); #else // CIRCUITPY-CHANGE: more specific mp_raise mp_raise_TypeError_varg(MP_ERROR_TEXT("can't create '%q' instances"), self->name); @@ -1159,7 +1202,7 @@ MP_DEFINE_CONST_OBJ_TYPE( attr, type_attr ); -mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { +static mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { // Verify input objects have expected type if (!mp_obj_is_type(bases_tuple, &mp_type_tuple)) { mp_raise_TypeError(NULL); @@ -1252,20 +1295,38 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) } } + #if MICROPY_PY_DESCRIPTORS + // To avoid any dynamic allocations when no __set_name__ exists, + // the head of this list is kept on the stack (marked blank with `next = NULL`). + setname_list_t setname_list = { .next = NULL }; + setname_list_t *setname_tail = &setname_list; + #endif + #if ENABLE_SPECIAL_ACCESSORS - // Check if the class has any special accessor methods - if (!(o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { - for (size_t i = 0; i < locals_ptr->map.alloc; i++) { - if (mp_map_slot_is_filled(&locals_ptr->map, i)) { - const mp_map_elem_t *elem = &locals_ptr->map.table[i]; - if (check_for_special_accessors(elem->key, elem->value)) { - o->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS; - break; - } + // Check if the class has any special accessor methods, + // and accumulate bound __set_name__ methods that need to be called + for (size_t i = 0; i < locals_ptr->map.alloc; i++) { + #if !MICROPY_PY_DESCRIPTORS + // __set_name__ needs to scan the entire locals map, can't early-terminate + if (o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS) { + break; + } + #endif + + if (mp_map_slot_is_filled(&locals_ptr->map, i)) { + const mp_map_elem_t *elem = &locals_ptr->map.table[i]; + + if (!(o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS) // elidable when the early-termination check is enabled + && check_for_special_accessors(elem->key, elem->value)) { + o->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS; } + + #if MICROPY_PY_DESCRIPTORS + setname_tail = setname_maybe_bind_append(setname_tail, elem->key, elem->value); + #endif } } - #endif + #endif // ENABLE_SPECIAL_ACCESSORS const mp_obj_type_t *native_base; size_t num_native_bases = instance_count_native_bases(o, &native_base); @@ -1273,8 +1334,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) mp_raise_TypeError(MP_ERROR_TEXT("multiple bases have instance lay-out conflict")); } - mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(o, locals_dict)->map; - mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(&locals_ptr->map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP); if (elem != NULL) { // __new__ slot exists; check if it is a function if (mp_obj_is_fun(elem->value)) { @@ -1283,6 +1343,10 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) } } + #if MICROPY_PY_DESCRIPTORS + setname_consume_call_all(&setname_list, MP_OBJ_FROM_PTR(o)); + #endif + return MP_OBJ_FROM_PTR(o); } @@ -1383,7 +1447,7 @@ static void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { if (dest[0] == MP_OBJ_SENTINEL) { // Looked up native __init__ so defer to it - dest[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj); + dest[0] = MP_OBJ_FROM_PTR(&mp_native_base_init_wrapper_obj); dest[1] = self->obj; // CIRCUITPY-CHANGE: better support for properties } else { diff --git a/py/objtype.h b/py/objtype.h index 07a8e1cffd9..098b7699da9 100644 --- a/py/objtype.h +++ b/py/objtype.h @@ -55,4 +55,7 @@ mp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf); // CIRCUITPY-CHANGE: addition void mp_obj_assert_native_inited(mp_obj_t native_object); +// upstream v1.28: exposed so py/objexcept.c can reference it directly +MP_DECLARE_CONST_FUN_OBJ_KW(mp_native_base_init_wrapper_obj); + #endif // MICROPY_INCLUDED_PY_OBJTYPE_H diff --git a/py/objzip.c b/py/objzip.c index dd2b39ee071..300448b665f 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -50,19 +50,20 @@ static mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ static mp_obj_t zip_iternext(mp_obj_t self_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_zip)); mp_obj_zip_t *self = MP_OBJ_TO_PTR(self_in); - if (self->n_iters == 0) { - return MP_OBJ_STOP_ITERATION; - } - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->n_iters, NULL)); - + mp_obj_tuple_t *tuple = NULL; for (size_t i = 0; i < self->n_iters; i++) { mp_obj_t next = mp_iternext(self->iters[i]); if (next == MP_OBJ_STOP_ITERATION) { - mp_obj_tuple_del(MP_OBJ_FROM_PTR(tuple)); return MP_OBJ_STOP_ITERATION; } + if (tuple == NULL) { + tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->n_iters, NULL)); + } tuple->items[i] = next; } + if (tuple == NULL) { + return MP_OBJ_STOP_ITERATION; + } return MP_OBJ_FROM_PTR(tuple); } diff --git a/py/parse.c b/py/parse.c index a393b0ee8c1..203527c782d 100644 --- a/py/parse.c +++ b/py/parse.c @@ -341,18 +341,34 @@ static uint8_t peek_rule(parser_t *parser, size_t n) { } #endif -bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) { +#if MICROPY_COMP_CONST_FOLDING || MICROPY_EMIT_INLINE_ASM +static bool mp_parse_node_get_number_maybe(mp_parse_node_t pn, mp_obj_t *o) { if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { *o = MP_OBJ_NEW_SMALL_INT(MP_PARSE_NODE_LEAF_SMALL_INT(pn)); return true; } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn; *o = mp_parse_node_extract_const_object(pns); - return mp_obj_is_int(*o); + return mp_obj_is_int(*o) + #if MICROPY_COMP_CONST_FLOAT + || mp_obj_is_float(*o) + #endif + ; } else { return false; } } +#endif + +#if MICROPY_EMIT_INLINE_ASM +bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) { + return mp_parse_node_get_number_maybe(pn, o) + #if MICROPY_COMP_CONST_FLOAT + && mp_obj_is_int(*o) + #endif + ; +} +#endif #if MICROPY_COMP_CONST_TUPLE || MICROPY_COMP_CONST static bool mp_parse_node_is_const(mp_parse_node_t pn) { @@ -480,10 +496,10 @@ void mp_parse_node_print(const mp_print_t *print, mp_parse_node_t pn, size_t ind uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn); switch (MP_PARSE_NODE_LEAF_KIND(pn)) { case MP_PARSE_NODE_ID: - mp_printf(print, "id(%s)\n", qstr_str(arg)); + mp_printf(print, "id(%q)\n", (qstr)arg); break; case MP_PARSE_NODE_STRING: - mp_printf(print, "str(%s)\n", qstr_str(arg)); + mp_printf(print, "str(%q)\n", (qstr)arg); break; default: assert(MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN); @@ -647,12 +663,32 @@ static const mp_rom_map_elem_t mp_constants_table[] = { #if MICROPY_PY_UCTYPES { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, #endif + #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH && MICROPY_COMP_CONST_FLOAT + { MP_ROM_QSTR(MP_QSTR_math), MP_ROM_PTR(&mp_module_math) }, + #endif // Extra constants as defined by a port MICROPY_PORT_CONSTANTS }; static MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); #endif +static bool binary_op_maybe(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs, mp_obj_t *res) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t tmp = mp_binary_op(op, lhs, rhs); + nlr_pop(); + #if MICROPY_PY_BUILTINS_COMPLEX + if (mp_obj_is_type(tmp, &mp_type_complex)) { + return false; + } + #endif + *res = tmp; + return true; + } else { + return false; + } +} + static bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *num_args) { if (rule_id == RULE_or_test || rule_id == RULE_and_test) { @@ -711,7 +747,7 @@ static bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *nu } static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { - // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 + // this code does folding of arbitrary numeric expressions, eg 1 + 2 * 3 + 4 // it does not do partial folding, eg 1 + 2 + x -> 3 + x mp_obj_t arg0; @@ -721,7 +757,7 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { || rule_id == RULE_power) { // folding for binary ops: | ^ & ** mp_parse_node_t pn = peek_result(parser, num_args - 1); - if (!mp_parse_node_get_int_maybe(pn, &arg0)) { + if (!mp_parse_node_get_number_maybe(pn, &arg0)) { return false; } mp_binary_op_t op; @@ -737,58 +773,45 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { for (ssize_t i = num_args - 2; i >= 0; --i) { pn = peek_result(parser, i); mp_obj_t arg1; - if (!mp_parse_node_get_int_maybe(pn, &arg1)) { + if (!mp_parse_node_get_number_maybe(pn, &arg1)) { return false; } - if (op == MP_BINARY_OP_POWER && mp_obj_int_sign(arg1) < 0) { - // ** can't have negative rhs + if (!binary_op_maybe(op, arg0, arg1, &arg0)) { return false; } - arg0 = mp_binary_op(op, arg0, arg1); } } else if (rule_id == RULE_shift_expr || rule_id == RULE_arith_expr || rule_id == RULE_term) { // folding for binary ops: << >> + - * @ / % // mp_parse_node_t pn = peek_result(parser, num_args - 1); - if (!mp_parse_node_get_int_maybe(pn, &arg0)) { + if (!mp_parse_node_get_number_maybe(pn, &arg0)) { return false; } for (ssize_t i = num_args - 2; i >= 1; i -= 2) { pn = peek_result(parser, i - 1); mp_obj_t arg1; - if (!mp_parse_node_get_int_maybe(pn, &arg1)) { + if (!mp_parse_node_get_number_maybe(pn, &arg1)) { return false; } mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, i)); - if (tok == MP_TOKEN_OP_AT || tok == MP_TOKEN_OP_SLASH) { - // Can't fold @ or / - return false; - } mp_binary_op_t op = MP_BINARY_OP_LSHIFT + (tok - MP_TOKEN_OP_DBL_LESS); - int rhs_sign = mp_obj_int_sign(arg1); - if (op <= MP_BINARY_OP_RSHIFT) { - // << and >> can't have negative rhs - if (rhs_sign < 0) { - return false; - } - } else if (op >= MP_BINARY_OP_FLOOR_DIVIDE) { - // % and // can't have zero rhs - if (rhs_sign == 0) { - return false; - } + if (!binary_op_maybe(op, arg0, arg1, &arg0)) { + return false; } - arg0 = mp_binary_op(op, arg0, arg1); } } else if (rule_id == RULE_factor_2) { // folding for unary ops: + - ~ mp_parse_node_t pn = peek_result(parser, 0); - if (!mp_parse_node_get_int_maybe(pn, &arg0)) { + if (!mp_parse_node_get_number_maybe(pn, &arg0)) { return false; } mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, 1)); mp_unary_op_t op; if (tok == MP_TOKEN_OP_TILDE) { + if (!mp_obj_is_int(arg0)) { + return false; + } op = MP_UNARY_OP_INVERT; } else { assert(tok == MP_TOKEN_OP_PLUS || tok == MP_TOKEN_OP_MINUS); // should be @@ -802,50 +825,54 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { if (!MP_PARSE_NODE_IS_NULL(pn1) && !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign) || MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_assign_list))) { - // this node is of the form = + // this node is of the form = or : = mp_parse_node_t pn0 = peek_result(parser, 1); - if (MP_PARSE_NODE_IS_ID(pn0) - && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_atom_expr_normal) - && MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t *)pn1)->nodes[0]) - && MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)pn1)->nodes[0]) == MP_QSTR_const - && MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t *)pn1)->nodes[1], RULE_trailer_paren) - ) { - // code to assign dynamic constants: id = const(value) - - // get the id - qstr id = MP_PARSE_NODE_LEAF_ARG(pn0); - - // get the value - mp_parse_node_t pn_value = ((mp_parse_node_struct_t *)((mp_parse_node_struct_t *)pn1)->nodes[1])->nodes[0]; - if (!mp_parse_node_is_const(pn_value)) { - mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, - MP_ERROR_TEXT("not a constant")); - mp_obj_exception_add_traceback(exc, parser->lexer->source_name, - ((mp_parse_node_struct_t *)pn1)->source_line, MP_QSTRnull); - nlr_raise(exc); - } - mp_obj_t value = mp_parse_node_convert_to_obj(pn_value); - - // store the value in the table of dynamic constants - mp_map_elem_t *elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); - assert(elem->value == MP_OBJ_NULL); - elem->value = value; - - // If the constant starts with an underscore then treat it as a private - // variable and don't emit any code to store the value to the id. - if (qstr_str(id)[0] == '_') { - pop_result(parser); // pop const(value) - pop_result(parser); // pop id - push_result_rule(parser, 0, RULE_pass_stmt, 0); // replace with "pass" - return true; + if (MP_PARSE_NODE_IS_ID(pn0)) { + if (MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_annassign)) { + // extract annassign rhs + pn1 = ((mp_parse_node_struct_t *)pn1)->nodes[1]; } + if (MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_atom_expr_normal) + && MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t *)pn1)->nodes[0]) + && MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)pn1)->nodes[0]) == MP_QSTR_const + && MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t *)pn1)->nodes[1], RULE_trailer_paren)) { + // code to assign dynamic constants: id = const(value) + + // get the id + qstr id = MP_PARSE_NODE_LEAF_ARG(pn0); + + // get the value + mp_parse_node_t pn_value = ((mp_parse_node_struct_t *)((mp_parse_node_struct_t *)pn1)->nodes[1])->nodes[0]; + if (!mp_parse_node_is_const(pn_value)) { + mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, + MP_ERROR_TEXT("not a constant")); + mp_obj_exception_add_traceback(exc, parser->lexer->source_name, + ((mp_parse_node_struct_t *)pn1)->source_line, MP_QSTRnull); + nlr_raise(exc); + } + mp_obj_t value = mp_parse_node_convert_to_obj(pn_value); + + // store the value in the table of dynamic constants + mp_map_elem_t *elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + assert(elem->value == MP_OBJ_NULL); + elem->value = value; + + // If the constant starts with an underscore then treat it as a private + // variable and don't emit any code to store the value to the id. + if (qstr_str(id)[0] == '_') { + pop_result(parser); // pop const(value) + pop_result(parser); // pop id + push_result_rule(parser, 0, RULE_pass_stmt, 0); // replace with "pass" + return true; + } - // replace const(value) with value - pop_result(parser); - push_result_node(parser, pn_value); + // replace const(value) with value + pop_result(parser); + push_result_node(parser, pn_value); - // finished folding this assignment, but we still want it to be part of the tree - return false; + // finished folding this assignment, but we still want it to be part of the tree + return false; + } } } return false; @@ -860,7 +887,7 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { return false; } // id1.id2 - // look it up in constant table, see if it can be replaced with an integer + // look it up in constant table, see if it can be replaced with an integer or a float mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pn1; assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); qstr q_base = MP_PARSE_NODE_LEAF_ARG(pn0); @@ -871,7 +898,7 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { } mp_obj_t dest[2]; mp_load_method_maybe(elem->value, q_attr, dest); - if (!(dest[0] != MP_OBJ_NULL && mp_obj_is_int(dest[0]) && dest[1] == MP_OBJ_NULL)) { + if (!(dest[0] != MP_OBJ_NULL && (mp_obj_is_int(dest[0]) || mp_obj_is_float(dest[0])) && dest[1] == MP_OBJ_NULL)) { return false; } arg0 = dest[0]; diff --git a/py/parsenum.c b/py/parsenum.c index 874216f08d0..c52f040e1a2 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -28,6 +28,7 @@ #include #include "py/runtime.h" +#include "py/misc.h" #include "py/parsenumbase.h" #include "py/parsenum.h" #include "py/smallint.h" @@ -36,7 +37,7 @@ #include #endif -static NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { +static MP_NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { // if lex!=NULL then the parser called us and we need to convert the // exception's type from ValueError to SyntaxError and add traceback info if (lex != NULL) { @@ -46,6 +47,27 @@ static NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { nlr_raise(exc); } +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_LONGLONG +// For the common small integer parsing case, we parse directly to mp_int_t and +// check that the value doesn't overflow a smallint (in which case we fail over +// to bigint parsing if supported) +typedef mp_int_t parsed_int_t; + +#define PARSED_INT_MUL_OVERFLOW mp_mul_mp_int_t_overflow +#define PARSED_INT_FITS MP_SMALL_INT_FITS +#else +// In the special case where bigint support is long long, we save code size by +// parsing directly to long long and then return either a bigint or smallint +// from the same result. +// +// To avoid pulling in (slow) signed 64-bit math routines we do the initial +// parsing to an unsigned long long and only convert to signed at the end. +typedef unsigned long long parsed_int_t; + +#define PARSED_INT_MUL_OVERFLOW mp_mul_ull_overflow +#define PARSED_INT_FITS(I) ((I) <= (unsigned long long)LLONG_MAX + 1) +#endif + mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, mp_lexer_t *lex) { const byte *restrict str = (const byte *)str_; const byte *restrict top = str + len; @@ -77,7 +99,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m str += mp_parse_num_base((const char *)str, top - str, &base); // string should be an integer number - mp_int_t int_val = 0; + parsed_int_t parsed_val = 0; const byte *restrict str_val_start = str; for (; str < top; str++) { // get next digit as a value @@ -99,25 +121,32 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m break; } - // add next digi and check for overflow - if (mp_small_int_mul_overflow(int_val, base)) { + // add next digit and check for overflow + if (PARSED_INT_MUL_OVERFLOW(parsed_val, base, &parsed_val)) { goto overflow; } - int_val = int_val * base + dig; - if (!MP_SMALL_INT_FITS(int_val)) { + parsed_val += dig; + if (!PARSED_INT_FITS(parsed_val)) { goto overflow; } } - // negate value if needed - if (neg) { - int_val = -int_val; + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_LONGLONG + // The PARSED_INT_FITS check above ensures parsed_val fits in small int representation + ret_val = MP_OBJ_NEW_SMALL_INT(neg ? (-parsed_val) : parsed_val); +have_ret_val: + #else + // The PARSED_INT_FITS check above ensures parsed_val won't overflow signed long long + long long signed_val = -parsed_val; + if (!neg) { + if (signed_val == LLONG_MIN) { + goto overflow; + } + signed_val = -signed_val; } + ret_val = mp_obj_new_int_from_ll(signed_val); // Could be large or small int + #endif - // create the small int - ret_val = MP_OBJ_NEW_SMALL_INT(int_val); - -have_ret_val: // check we parsed something if (str == str_val_start) { goto value_error; @@ -136,6 +165,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m return ret_val; overflow: + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_LONGLONG // reparse using long int { const char *s2 = (const char *)str_val_start; @@ -143,6 +173,9 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m str = (const byte *)s2; goto have_ret_val; } + #else + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("result overflows long long storage")); + #endif value_error: { @@ -167,6 +200,8 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m } } +#if MICROPY_PY_BUILTINS_FLOAT + enum { REAL_IMAG_STATE_START = 0, REAL_IMAG_STATE_HAVE_REAL = 1, @@ -179,27 +214,81 @@ typedef enum { PARSE_DEC_IN_EXP, } parse_dec_in_t; -#if MICROPY_PY_BUILTINS_FLOAT // MANTISSA_MAX is used to retain precision while not overflowing mantissa -// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float -// EXACT_POWER_OF_10 is the largest value of x so that 10^x can be stored exactly in a float -// Note: EXACT_POWER_OF_10 is at least floor(log_5(2^mantissa_length)). Indeed, 10^n = 2^n * 5^n -// so we only have to store the 5^n part in the mantissa (the 2^n part will go into the float's -// exponent). +#define MANTISSA_MAX (sizeof(mp_large_float_uint_t) == 8 ? 0x1999999999999998ULL : 0x19999998U) + +// MAX_EXACT_POWER_OF_5 is the largest value of x so that 5^x can be stored exactly in a float #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT -#define MANTISSA_MAX 0x19999998U -#define SMALL_NORMAL_VAL (1e-37F) -#define SMALL_NORMAL_EXP (-37) -#define EXACT_POWER_OF_10 (9) +#define MAX_EXACT_POWER_OF_5 (10) #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE -#define MANTISSA_MAX 0x1999999999999998ULL -#define SMALL_NORMAL_VAL (1e-307) -#define SMALL_NORMAL_EXP (-307) -#define EXACT_POWER_OF_10 (22) +#define MAX_EXACT_POWER_OF_5 (22) #endif +// Helper to compute `num * (10.0 ** dec_exp)` +mp_large_float_t mp_decimal_exp(mp_large_float_t num, int dec_exp) { + // CIRCUITPY-CHANGE: ignore float equal warning + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" + if (dec_exp == 0 || num == (mp_large_float_t)(0.0)) { + return num; + } + #pragma GCC diagnostic pop + + #if MICROPY_FLOAT_FORMAT_IMPL == MICROPY_FLOAT_FORMAT_IMPL_EXACT + + // If the assert below fails, it means you have chosen MICROPY_FLOAT_FORMAT_IMPL_EXACT + // manually on a platform where `larger floats` are not supported, which would + // result in inexact conversions. To fix this issue, change your `mpconfigport.h` + // and select MICROPY_FLOAT_FORMAT_IMPL_APPROX instead + assert(sizeof(mp_large_float_t) > sizeof(mp_float_t)); + + // Perform power using simple multiplications, to avoid + // dependency to higher-precision pow() function + int neg_exp = (dec_exp < 0); + if (neg_exp) { + dec_exp = -dec_exp; + } + mp_large_float_t res = num; + mp_large_float_t expo = (mp_large_float_t)10.0; + while (dec_exp) { + if (dec_exp & 1) { + if (neg_exp) { + res /= expo; + } else { + res *= expo; + } + } + dec_exp >>= 1; + if (dec_exp) { + expo *= expo; + } + } + return res; + + #else + // MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_EXACT + + mp_float_union_t res = {num}; + // Multiply first by (2.0 ** dec_exp) via the exponent + // - this will ensure that the result of `pow()` is always in mp_float_t range + // when the result is expected to be in mp_float_t range (e.g. during format) + // - we don't need to care about p.exp overflow, as (5.0 ** dec_exp) will anyway + // force the final result toward the proper edge if needed (0.0 or inf) + res.p.exp += dec_exp; + // Use positive exponents when they are more precise then negative + if (dec_exp < 0 && dec_exp >= -MAX_EXACT_POWER_OF_5) { + res.f /= MICROPY_FLOAT_C_FUN(pow)(5, -dec_exp); + } else { + res.f *= MICROPY_FLOAT_C_FUN(pow)(5, dec_exp); + } + return (mp_large_float_t)res.f; + + #endif +} + + // Break out inner digit accumulation routine to ease trailing zero deferral. -static mp_float_uint_t accept_digit(mp_float_uint_t p_mantissa, unsigned int dig, int *p_exp_extra, int in) { +static mp_large_float_uint_t accept_digit(mp_large_float_uint_t p_mantissa, unsigned int dig, int *p_exp_extra, int in) { // Core routine to ingest an additional digit. if (p_mantissa < MANTISSA_MAX) { // dec_val won't overflow so keep accumulating @@ -216,6 +305,85 @@ static mp_float_uint_t accept_digit(mp_float_uint_t p_mantissa, unsigned int dig return p_mantissa; } } + +// Helper to parse an unsigned decimal number into a mp_float_t +const char *mp_parse_float_internal(const char *str, size_t len, mp_float_t *res) { + const char *top = str + len; + + parse_dec_in_t in = PARSE_DEC_IN_INTG; + bool exp_neg = false; + mp_large_float_uint_t mantissa = 0; + int exp_val = 0; + int exp_extra = 0; + int trailing_zeros_intg = 0, trailing_zeros_frac = 0; + while (str < top) { + unsigned int dig = *str++; + if ('0' <= dig && dig <= '9') { + dig -= '0'; + if (in == PARSE_DEC_IN_EXP) { + // don't overflow exp_val when adding next digit, instead just truncate + // it and the resulting float will still be correct, either inf or 0.0 + // (use INT_MAX/2 to allow adding exp_extra at the end without overflow) + if (exp_val < (INT_MAX / 2 - 9) / 10) { + exp_val = 10 * exp_val + dig; + } + } else { + if (dig == 0 || mantissa >= MANTISSA_MAX) { + // Defer treatment of zeros in fractional part. If nothing comes afterwards, ignore them. + // Also, once we reach MANTISSA_MAX, treat every additional digit as a trailing zero. + if (in == PARSE_DEC_IN_INTG) { + ++trailing_zeros_intg; + } else { + ++trailing_zeros_frac; + } + } else { + // Time to un-defer any trailing zeros. Intg zeros first. + while (trailing_zeros_intg) { + mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_INTG); + --trailing_zeros_intg; + } + while (trailing_zeros_frac) { + mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_FRAC); + --trailing_zeros_frac; + } + mantissa = accept_digit(mantissa, dig, &exp_extra, in); + } + } + } else if (in == PARSE_DEC_IN_INTG && dig == '.') { + in = PARSE_DEC_IN_FRAC; + } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) { + in = PARSE_DEC_IN_EXP; + if (str < top) { + if (str[0] == '+') { + str++; + } else if (str[0] == '-') { + str++; + exp_neg = true; + } + } + if (str == top) { + return NULL; + } + } else if (dig == '_') { + continue; + } else { + // unknown character + str--; + break; + } + } + + // work out the exponent + if (exp_neg) { + exp_val = -exp_val; + } + exp_val += exp_extra + trailing_zeros_intg; + + // At this point, we just need to multiply the mantissa by its base 10 exponent. + *res = (mp_float_t)mp_decimal_exp(mantissa, exp_val); + + return str; +} #endif // MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_COMPLEX @@ -253,111 +421,23 @@ parse_start:; const char *str_val_start = str; // determine what the string is - if (str < top && (str[0] | 0x20) == 'i') { - // string starts with 'i', should be 'inf' or 'infinity' (case insensitive) - if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') { - // inf - str += 3; - dec_val = (mp_float_t)INFINITY; - if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') { - // infinity - str += 5; - } - } - } else if (str < top && (str[0] | 0x20) == 'n') { - // string starts with 'n', should be 'nan' (case insensitive) - if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') { - // NaN - str += 3; - dec_val = MICROPY_FLOAT_C_FUN(nan)(""); + if (str + 2 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') { + // 'inf' or 'infinity' (case insensitive) + str += 3; + dec_val = (mp_float_t)INFINITY; + if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') { + // infinity + str += 5; } + } else if (str + 2 < top && (str[0] | 0x20) == 'n' && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') { + // 'nan' (case insensitive) + str += 3; + dec_val = MICROPY_FLOAT_C_FUN(nan)(""); } else { // string should be a decimal number - parse_dec_in_t in = PARSE_DEC_IN_INTG; - bool exp_neg = false; - mp_float_uint_t mantissa = 0; - int exp_val = 0; - int exp_extra = 0; - int trailing_zeros_intg = 0, trailing_zeros_frac = 0; - while (str < top) { - unsigned int dig = *str++; - if ('0' <= dig && dig <= '9') { - dig -= '0'; - if (in == PARSE_DEC_IN_EXP) { - // don't overflow exp_val when adding next digit, instead just truncate - // it and the resulting float will still be correct, either inf or 0.0 - // (use INT_MAX/2 to allow adding exp_extra at the end without overflow) - if (exp_val < (INT_MAX / 2 - 9) / 10) { - exp_val = 10 * exp_val + dig; - } - } else { - if (dig == 0 || mantissa >= MANTISSA_MAX) { - // Defer treatment of zeros in fractional part. If nothing comes afterwards, ignore them. - // Also, once we reach MANTISSA_MAX, treat every additional digit as a trailing zero. - if (in == PARSE_DEC_IN_INTG) { - ++trailing_zeros_intg; - } else { - ++trailing_zeros_frac; - } - } else { - // Time to un-defer any trailing zeros. Intg zeros first. - while (trailing_zeros_intg) { - mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_INTG); - --trailing_zeros_intg; - } - while (trailing_zeros_frac) { - mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_FRAC); - --trailing_zeros_frac; - } - mantissa = accept_digit(mantissa, dig, &exp_extra, in); - } - } - } else if (in == PARSE_DEC_IN_INTG && dig == '.') { - in = PARSE_DEC_IN_FRAC; - } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) { - in = PARSE_DEC_IN_EXP; - if (str < top) { - if (str[0] == '+') { - str++; - } else if (str[0] == '-') { - str++; - exp_neg = true; - } - } - if (str == top) { - goto value_error; - } - } else if (dig == '_') { - continue; - } else { - // unknown character - str--; - break; - } - } - - // work out the exponent - if (exp_neg) { - exp_val = -exp_val; - } - - // apply the exponent, making sure it's not a subnormal value - exp_val += exp_extra + trailing_zeros_intg; - dec_val = (mp_float_t)mantissa; - if (exp_val < SMALL_NORMAL_EXP) { - exp_val -= SMALL_NORMAL_EXP; - dec_val *= SMALL_NORMAL_VAL; - } - - // At this point, we need to multiply the mantissa by its base 10 exponent. If possible, - // we would rather manipulate numbers that have an exact representation in IEEE754. It - // turns out small positive powers of 10 do, whereas small negative powers of 10 don't. - // So in that case, we'll yield a division of exact values rather than a multiplication - // of slightly erroneous values. - if (exp_val < 0 && exp_val >= -EXACT_POWER_OF_10) { - dec_val /= MICROPY_FLOAT_C_FUN(pow)(10, -exp_val); - } else { - dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val); + str = mp_parse_float_internal(str, top - str, &dec_val); + if (!str) { + goto value_error; } } diff --git a/py/parsenum.h b/py/parsenum.h index f444632d230..d532cb194a5 100644 --- a/py/parsenum.h +++ b/py/parsenum.h @@ -34,6 +34,11 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, size_t len, int base, mp_lexer_t *lex); +#if MICROPY_PY_BUILTINS_FLOAT +mp_large_float_t mp_decimal_exp(mp_large_float_t num, int dec_exp); +const char *mp_parse_float_internal(const char *str, size_t len, mp_float_t *res); +#endif + #if MICROPY_PY_BUILTINS_COMPLEX mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex); diff --git a/py/persistentcode.c b/py/persistentcode.c index 93f4c33deb4..7542a97f000 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -63,6 +63,10 @@ typedef struct _bytecode_prelude_t { uint code_info_size; } bytecode_prelude_t; +#if MICROPY_EMIT_RV32 +#include "py/asmrv32.h" +#endif + #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #if MICROPY_PERSISTENT_CODE_LOAD @@ -72,6 +76,8 @@ typedef struct _bytecode_prelude_t { static int read_byte(mp_reader_t *reader); static size_t read_uint(mp_reader_t *reader); +#if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE + #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA // An mp_obj_list_t that tracks native text/BSS/rodata to prevent the GC from reclaiming them. @@ -86,8 +92,6 @@ static void track_root_pointer(void *ptr) { #endif -#if MICROPY_EMIT_MACHINE_CODE - typedef struct _reloc_info_t { mp_reader_t *reader; mp_module_context_t *context; @@ -225,7 +229,7 @@ static mp_obj_t mp_obj_new_str_static(const mp_obj_type_t *type, const byte *dat static mp_obj_t load_obj(mp_reader_t *reader) { byte obj_type = read_byte(reader); - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE if (obj_type == MP_PERSISTENT_OBJ_FUN_TABLE) { return MP_OBJ_FROM_PTR(&mp_fun_table); } else @@ -298,14 +302,14 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co bool has_children = !!(kind_len & 4); size_t fun_data_len = kind_len >> 3; - #if !MICROPY_EMIT_MACHINE_CODE + #if !(MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE) if (kind != MP_CODE_BYTECODE) { mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); } #endif uint8_t *fun_data = NULL; - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE size_t prelude_offset = 0; mp_uint_t native_scope_flags = 0; mp_uint_t native_n_pos_args = 0; @@ -325,7 +329,7 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co read_bytes(reader, fun_data, fun_data_len); } - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE } else { // Allocate memory for native data and load it size_t fun_alloc; @@ -352,7 +356,7 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co size_t n_children = 0; mp_raw_code_t **children = NULL; - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE // Load optional BSS/rodata for viper. uint8_t *rodata = NULL; uint8_t *bss = NULL; @@ -407,7 +411,7 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co #endif scope_flags); - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE } else { const uint8_t *prelude_ptr = NULL; #if MICROPY_EMIT_NATIVE_PRELUDE_SEPARATE_FROM_MACHINE_CODE @@ -422,15 +426,17 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co // Relocate and commit code to executable address space reloc_info_t ri = {reader, context, rodata, bss}; + #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA + if (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) { + // Track the function data memory so it's not reclaimed by the GC. + track_root_pointer(fun_data); + } + #endif #if defined(MP_PLAT_COMMIT_EXEC) void *opt_ri = (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL; fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len, opt_ri); #else if (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) { - #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA - // Track the function data memory so it's not reclaimed by the GC. - track_root_pointer(fun_data); - #endif // Do the relocations. mp_native_relocate(&ri, fun_data, (uintptr_t)fun_data); } @@ -480,7 +486,7 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { || header[3] > MP_SMALL_INT_BITS) { mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); } - if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE) { + if (arch != MP_NATIVE_ARCH_NONE) { if (!MPY_FEATURE_ARCH_TEST(arch)) { if (MPY_FEATURE_ARCH_TEST(MP_NATIVE_ARCH_NONE)) { // On supported ports this can be resolved by enabling feature, eg @@ -492,6 +498,23 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { } } + size_t arch_flags = 0; + if (MPY_FEATURE_ARCH_FLAGS_TEST(header[2])) { + #if MICROPY_EMIT_RV32 + arch_flags = read_uint(reader); + + if (MPY_FEATURE_ARCH_TEST(MP_NATIVE_ARCH_RV32IMC)) { + if ((arch_flags & (size_t)asm_rv32_allowed_extensions()) != arch_flags) { + mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); + } + } else + #endif + { + (void)arch_flags; + mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); + } + } + size_t n_qstr = read_uint(reader); size_t n_obj = read_uint(reader); mp_module_context_alloc_tables(cm->context, n_qstr, n_obj); @@ -513,6 +536,7 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { cm->has_native = MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE; cm->n_qstr = n_qstr; cm->n_obj = n_obj; + cm->arch_flags = arch_flags; #endif // Deregister exception handler and close the reader. @@ -545,9 +569,8 @@ static void mp_print_bytes(mp_print_t *print, const byte *data, size_t len) { print->print_strn(print->data, (const char *)data, len); } -#define BYTES_FOR_INT ((MP_BYTES_PER_OBJ_WORD * 8 + 6) / 7) static void mp_print_uint(mp_print_t *print, size_t n) { - byte buf[BYTES_FOR_INT]; + byte buf[MP_ENCODE_UINT_MAX_BYTES]; byte *p = buf + sizeof(buf); *--p = n & 0x7f; n >>= 7; @@ -682,7 +705,7 @@ void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print) { byte header[4] = { 'C', MPY_VERSION, - cm->has_native ? MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC) : 0, + (cm->arch_flags != 0 ? MPY_FEATURE_ARCH_FLAGS : 0) | (cm->has_native ? MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC) : 0), #if MICROPY_DYNAMIC_COMPILER mp_dynamic_compiler.small_int_bits, #else @@ -691,6 +714,10 @@ void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print) { }; mp_print_bytes(print, header, sizeof(header)); + if (cm->arch_flags) { + mp_print_uint(print, cm->arch_flags); + } + // Number of entries in constant table. mp_print_uint(print, cm->n_qstr); mp_print_uint(print, cm->n_obj); @@ -769,7 +796,7 @@ static void bit_vector_clear(bit_vector_t *self) { static bool bit_vector_is_set(bit_vector_t *self, size_t index) { const size_t bits_size = sizeof(*self->bits) * MP_BITS_PER_BYTE; return index / bits_size < self->alloc - && (self->bits[index / bits_size] & (1 << (index % bits_size))) != 0; + && (self->bits[index / bits_size] & ((uintptr_t)1 << (index % bits_size))) != 0; } static void bit_vector_set(bit_vector_t *self, size_t index) { @@ -780,7 +807,7 @@ static void bit_vector_set(bit_vector_t *self, size_t index) { self->bits = m_renew(uintptr_t, self->bits, self->alloc, new_alloc); self->alloc = new_alloc; } - self->bits[index / bits_size] |= 1 << (index % bits_size); + self->bits[index / bits_size] |= (uintptr_t)1 << (index % bits_size); } typedef struct _mp_opcode_t { @@ -828,8 +855,28 @@ static mp_opcode_t mp_opcode_decode(const uint8_t *ip) { return op; } -mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, const uint8_t *bytecode) { - const uint8_t *fun_data = bytecode; +typedef struct _mp_raw_code_simplified_t { + const uint8_t *fun_data; + struct _mp_raw_code_simplified_t *children; + size_t fun_data_len; + size_t n_children; +} mp_raw_code_simplified_t; + +static void proto_fun_to_raw_code_simplified(const void *proto_fun, bit_vector_t *qstr_table_used, bit_vector_t *obj_table_used, mp_raw_code_simplified_t *rcs) { + const uint8_t *fun_data; + mp_raw_code_t **children; + if (mp_proto_fun_is_bytecode(proto_fun)) { + fun_data = proto_fun; + children = NULL; + } else { + const mp_raw_code_t *rc = proto_fun; + if (rc->kind != MP_CODE_BYTECODE) { + mp_raise_ValueError(MP_ERROR_TEXT("function must be bytecode")); + } + fun_data = rc->fun_data; + children = rc->children; + } + const uint8_t *fun_data_top = fun_data + gc_nbytes(fun_data); // Extract function information. @@ -837,20 +884,12 @@ mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, cons MP_BC_PRELUDE_SIG_DECODE(ip); MP_BC_PRELUDE_SIZE_DECODE(ip); - // Track the qstrs used by the function. - bit_vector_t qstr_table_used; - bit_vector_init(&qstr_table_used); - - // Track the objects used by the function. - bit_vector_t obj_table_used; - bit_vector_init(&obj_table_used); - const byte *ip_names = ip; mp_uint_t simple_name = mp_decode_uint(&ip_names); - bit_vector_set(&qstr_table_used, simple_name); + bit_vector_set(qstr_table_used, simple_name); for (size_t i = 0; i < n_pos_args + n_kwonly_args; ++i) { mp_uint_t arg_name = mp_decode_uint(&ip_names); - bit_vector_set(&qstr_table_used, arg_name); + bit_vector_set(qstr_table_used, arg_name); } // Skip pass source code info and cell info. @@ -858,20 +897,74 @@ mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, cons ip += n_info + n_cell; // Decode bytecode. + size_t n_children = 0; while (ip < fun_data_top) { mp_opcode_t op = mp_opcode_decode(ip); if (op.opcode == MP_BC_BASE_RESERVED) { // End of opcodes. fun_data_top = ip; - } else if (op.opcode == MP_BC_LOAD_CONST_OBJ) { - bit_vector_set(&obj_table_used, op.arg); } else if (op.format == MP_BC_FORMAT_QSTR) { - bit_vector_set(&qstr_table_used, op.arg); + bit_vector_set(qstr_table_used, op.arg); + } else if (op.opcode == MP_BC_LOAD_CONST_OBJ) { + bit_vector_set(obj_table_used, op.arg); + } else if (op.opcode == MP_BC_MAKE_FUNCTION + || op.opcode == MP_BC_MAKE_FUNCTION_DEFARGS + || op.opcode == MP_BC_MAKE_CLOSURE + || op.opcode == MP_BC_MAKE_CLOSURE_DEFARGS) { + if ((mp_uint_t)op.arg + 1 > n_children) { + n_children = (mp_uint_t)op.arg + 1; + } } ip += op.size; } - mp_uint_t fun_data_len = fun_data_top - fun_data; + rcs->fun_data = fun_data; + rcs->fun_data_len = fun_data_top - fun_data; + rcs->n_children = n_children; + rcs->children = NULL; + + if (n_children) { + rcs->children = m_new(mp_raw_code_simplified_t, n_children); + for (size_t i = 0; i < n_children; ++i) { + proto_fun_to_raw_code_simplified(children[i], qstr_table_used, obj_table_used, &rcs->children[i]); + } + } +} + +static void save_raw_code_simplified(mp_print_t *print, const mp_raw_code_simplified_t *rcs) { + // Save function kind and data length. + mp_print_uint(print, rcs->fun_data_len << 3 | (rcs->n_children != 0) << 2); + + // Save function code. + mp_print_bytes(print, rcs->fun_data, rcs->fun_data_len); + + // Save (and free) children. + if (rcs->n_children) { + mp_print_uint(print, rcs->n_children); + for (size_t i = 0; i < rcs->n_children; ++i) { + save_raw_code_simplified(print, &rcs->children[i]); + } + m_del(mp_raw_code_simplified_t, rcs->children, rcs->n_children); + } +} + +mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, mp_proto_fun_t proto_fun) { + // Track the qstrs used by the function. + bit_vector_t qstr_table_used; + bit_vector_init(&qstr_table_used); + + // Track the objects used by the function. + bit_vector_t obj_table_used; + bit_vector_init(&obj_table_used); + + #if MICROPY_PY_BUILTINS_CODE >= MICROPY_PY_BUILTINS_CODE_FULL + // Make sure the filename appears in the qstr table. + bit_vector_set(&qstr_table_used, 0); + #endif + + // Convert function into a simplified raw code tree. + mp_raw_code_simplified_t rcs; + proto_fun_to_raw_code_simplified(proto_fun, &qstr_table_used, &obj_table_used, &rcs); mp_print_t print; vstr_t vstr; @@ -906,11 +999,8 @@ mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, cons bit_vector_clear(&qstr_table_used); bit_vector_clear(&obj_table_used); - // Save function kind and data length. - mp_print_uint(&print, fun_data_len << 3); - - // Save function code. - mp_print_bytes(&print, fun_data, fun_data_len); + // Save the bytecode data (also free the simplified raw code tree at the same time). + save_raw_code_simplified(&print, &rcs); // Create and return bytes representing the .mpy data. return mp_obj_new_bytes_from_vstr(&vstr); diff --git a/py/persistentcode.h b/py/persistentcode.h index 46b474e57f7..9a9d8605641 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -50,34 +50,47 @@ // Macros to encode/decode native architecture to/from the feature byte #define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2) -#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2) +#define MPY_FEATURE_DECODE_ARCH(feat) (((feat) >> 2) & 0x2F) // Define the host architecture -#if MICROPY_EMIT_X86 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) -#elif MICROPY_EMIT_X64 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) -#elif MICROPY_EMIT_THUMB - #if defined(__thumb2__) - #if defined(__ARM_FP) && (__ARM_FP & 8) == 8 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMDP) - #elif defined(__ARM_FP) && (__ARM_FP & 4) == 4 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMSP) +#if MICROPY_PERSISTENT_CODE_LOAD_NATIVE + #if defined(__i386__) || defined(_M_IX86) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) + #elif defined(__x86_64__) || defined(_M_X64) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) + #elif defined(__thumb2__) || defined(__thumb__) + #if defined(__thumb2__) + #if defined(__ARM_FP) && (__ARM_FP & 8) == 8 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMDP) + #elif defined(__ARM_FP) && (__ARM_FP & 4) == 4 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMSP) + #else + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EM) + #endif #else - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EM) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6M) + #endif + #define MPY_FEATURE_ARCH_TEST(x) (MP_NATIVE_ARCH_ARMV6M <= (x) && (x) <= MPY_FEATURE_ARCH) + #elif defined(__arm__) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) + #elif defined(__xtensa__) + #include + #if XCHAL_HAVE_WINDOWED + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) + #else + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) + #endif + #elif defined(__riscv) + #if __riscv_xlen == 32 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_RV32IMC) + #elif __riscv_xlen == 64 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_RV64IMC) + #else + #error "Unsupported RISC-V architecture." #endif #else - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6M) + #error "Unsupported native architecture." #endif - #define MPY_FEATURE_ARCH_TEST(x) (MP_NATIVE_ARCH_ARMV6M <= (x) && (x) <= MPY_FEATURE_ARCH) -#elif MICROPY_EMIT_ARM - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) -#elif MICROPY_EMIT_XTENSA - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) -#elif MICROPY_EMIT_XTENSAWIN - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) -#elif MICROPY_EMIT_RV32 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_RV32IMC) #else #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) #endif @@ -90,6 +103,10 @@ #define MPY_FILE_HEADER_INT (MPY_VERSION \ | (MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH)) << 8) +// Architecture-specific flags are present in the .mpy file +#define MPY_FEATURE_ARCH_FLAGS (0x40) +#define MPY_FEATURE_ARCH_FLAGS_TEST(x) (((x) & MPY_FEATURE_ARCH_FLAGS) == MPY_FEATURE_ARCH_FLAGS) + enum { MP_NATIVE_ARCH_NONE = 0, MP_NATIVE_ARCH_X86, @@ -103,6 +120,7 @@ enum { MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN, MP_NATIVE_ARCH_RV32IMC, + MP_NATIVE_ARCH_RV64IMC, MP_NATIVE_ARCH_DEBUG, // this entry should always be last }; @@ -126,7 +144,7 @@ void mp_raw_code_load_file(qstr filename, mp_compiled_module_t *ctx); void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print); void mp_raw_code_save_file(mp_compiled_module_t *cm, qstr filename); -mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, const uint8_t *bytecode); +mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, mp_proto_fun_t proto_fun); void mp_native_relocate(void *reloc, uint8_t *text, uintptr_t reloc_text); diff --git a/py/profile.c b/py/profile.c index 397d0291f9f..0523a1806e7 100644 --- a/py/profile.c +++ b/py/profile.c @@ -80,7 +80,7 @@ static void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t "", frame, MP_CODE_QSTR_MAP(code->context, 0), - frame->lineno, + (int)frame->lineno, MP_CODE_QSTR_MAP(code->context, prelude->qstr_block_name_idx) ); } @@ -173,7 +173,7 @@ static mp_obj_t mp_prof_callback_invoke(mp_obj_t callback, prof_callback_args_t mp_prof_is_executing = false; if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) { - mp_handle_pending(true); + mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS); } return top; } diff --git a/py/py.cmake b/py/py.cmake index 6c180ae53e6..9d4fa15bd41 100644 --- a/py/py.cmake +++ b/py/py.cmake @@ -4,6 +4,12 @@ set(MICROPY_PY_DIR "${MICROPY_DIR}/py") list(APPEND MICROPY_INC_CORE "${MICROPY_DIR}") +# Set MICROPY_LIB_DIR default if not already set by the port. +# This needs to happen before usermod.cmake is included (for c_module() in manifests). +if(NOT MICROPY_LIB_DIR) + set(MICROPY_LIB_DIR ${MICROPY_DIR}/lib/micropython-lib) +endif() + # All py/ source files set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/argcheck.c @@ -49,15 +55,19 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/modio.c ${MICROPY_PY_DIR}/modmath.c ${MICROPY_PY_DIR}/modmicropython.c + ${MICROPY_PY_DIR}/modstring.c ${MICROPY_PY_DIR}/modstruct.c ${MICROPY_PY_DIR}/modsys.c ${MICROPY_PY_DIR}/modthread.c ${MICROPY_PY_DIR}/moderrno.c + ${MICROPY_PY_DIR}/modweakref.c ${MICROPY_PY_DIR}/mpprint.c ${MICROPY_PY_DIR}/mpstate.c ${MICROPY_PY_DIR}/mpz.c ${MICROPY_PY_DIR}/nativeglue.c ${MICROPY_PY_DIR}/nlr.c + ${MICROPY_PY_DIR}/nlraarch64.c + ${MICROPY_PY_DIR}/nlrloong64.c ${MICROPY_PY_DIR}/nlrmips.c ${MICROPY_PY_DIR}/nlrpowerpc.c ${MICROPY_PY_DIR}/nlrrv32.c @@ -105,6 +115,7 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/objstr.c ${MICROPY_PY_DIR}/objstringio.c ${MICROPY_PY_DIR}/objstrunicode.c + ${MICROPY_PY_DIR}/objtemplate.c # CIRCUITPY-CHANGE: add objtraceback.c ${MICROPY_PY_DIR}/objtraceback.c ${MICROPY_PY_DIR}/objtuple.c diff --git a/py/py.mk b/py/py.mk index c05327bf81d..8326ea4b637 100644 --- a/py/py.mk +++ b/py/py.mk @@ -24,21 +24,15 @@ QSTR_GLOBAL_REQUIREMENTS += $(HEADER_BUILD)/mpversion.h # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 -# Enable building 32-bit code on 64-bit host. -ifeq ($(MICROPY_FORCE_32BIT),1) -CC += -m32 -CXX += -m32 -LD += -m32 -endif - # External modules written in C. + +# Process manifest for C module extraction (appends to USER_C_MODULES). +include $(TOP)/py/manifest.mk + ifneq ($(USER_C_MODULES),) # pre-define USERMOD variables as expanded so that variables are immediate # expanded as they're added to them -# Confirm the provided path exists, show abspath if not to make it clearer to fix. -$(if $(wildcard $(USER_C_MODULES)/.),,$(error USER_C_MODULES doesn't exist: $(abspath $(USER_C_MODULES)))) - # C/C++ files that are included in the QSTR/module build SRC_USERMOD_C := SRC_USERMOD_CXX := @@ -50,28 +44,58 @@ SRC_USERMOD_LIB_ASM := CFLAGS_USERMOD := CXXFLAGS_USERMOD := LDFLAGS_USERMOD := +LIBS_USERMOD := # Backwards compatibility with older user c modules that set SRC_USERMOD # added to SRC_USERMOD_C below SRC_USERMOD := -$(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \ - $(eval USERMOD_DIR = $(patsubst %/,%,$(dir $(module))))\ - $(info Including User C Module from $(USERMOD_DIR))\ - $(eval include $(module))\ +# For each C module directory, scan for micropython.mk and include it. +# Accumulate USERMOD_DIRS so we can later strip each module's parent path +# from its source files while preserving the module basename in the build +# tree (e.g. build/cexample/foo.o, not build/foo.o, so files that share a +# name across modules don't collide on the same .o target). +USERMOD_DIRS := +$(foreach _UDIR, $(USER_C_MODULES), \ + $(if $(wildcard $(_UDIR)/.),,$(error USER_C_MODULES path doesn't exist: $(abspath $(_UDIR)))) \ + $(foreach module, $(wildcard $(_UDIR)/micropython.mk) $(wildcard $(_UDIR)/*/micropython.mk), \ + $(eval USERMOD_DIR = $(patsubst %/,%,$(dir $(module))))\ + $(eval USERMOD_DIRS += $(USERMOD_DIR))\ + $(info Including User C Module from $(USERMOD_DIR))\ + $(eval include $(module))\ + )\ ) SRC_USERMOD_C += $(SRC_USERMOD) -SRC_USERMOD_PATHFIX_C += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD_C)) -SRC_USERMOD_PATHFIX_CXX += $(patsubst $(USER_C_MODULES)/%.cpp,%.cpp,$(SRC_USERMOD_CXX)) -SRC_USERMOD_PATHFIX_LIB_C += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD_LIB_C)) -SRC_USERMOD_PATHFIX_LIB_CXX += $(patsubst $(USER_C_MODULES)/%.cpp,%.cpp,$(SRC_USERMOD_LIB_CXX)) -SRC_USERMOD_PATHFIX_LIB_ASM += $(patsubst $(USER_C_MODULES)/%.S,%.S,$(SRC_USERMOD_LIB_ASM)) +# Strip each USERMOD_DIR's leading path from source files, keeping the module +# basename as the leading directory so build outputs land at +# BUILD//.o. Uses per-directory patsubst on the paths as-is +# rather than $(abspath) so a parent directory containing whitespace doesn't +# break word-based patsubst. +SRC_USERMOD_PATHFIX_C := $(SRC_USERMOD_C) +SRC_USERMOD_PATHFIX_CXX := $(SRC_USERMOD_CXX) +SRC_USERMOD_PATHFIX_LIB_C := $(SRC_USERMOD_LIB_C) +SRC_USERMOD_PATHFIX_LIB_CXX := $(SRC_USERMOD_LIB_CXX) +SRC_USERMOD_PATHFIX_LIB_ASM := $(SRC_USERMOD_LIB_ASM) +USERMOD_DIRS := $(sort $(USERMOD_DIRS)) +$(foreach _MDIR, $(USERMOD_DIRS), \ + $(eval _MBASE := $(notdir $(_MDIR))) \ + $(eval SRC_USERMOD_PATHFIX_C := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_C))) \ + $(eval SRC_USERMOD_PATHFIX_CXX := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_CXX))) \ + $(eval SRC_USERMOD_PATHFIX_LIB_C := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_LIB_C))) \ + $(eval SRC_USERMOD_PATHFIX_LIB_CXX := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_LIB_CXX))) \ + $(eval SRC_USERMOD_PATHFIX_LIB_ASM := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_LIB_ASM))) \ +) + +# Parent directories of each USERMOD_DIR, added to vpath below so paths like +# cexample/foo.c (produced by the patsubst above) resolve to source files. +USERMOD_DIR_PARENTS := $(sort $(foreach _MDIR, $(USERMOD_DIRS), $(patsubst %/,%,$(dir $(_MDIR))))) CFLAGS += $(CFLAGS_USERMOD) CXXFLAGS += $(CXXFLAGS_USERMOD) LDFLAGS += $(LDFLAGS_USERMOD) +LIBS += $(LIBS_USERMOD) SRC_QSTR += $(SRC_USERMOD_PATHFIX_C) $(SRC_USERMOD_PATHFIX_CXX) PY_O += $(addprefix $(BUILD)/, $(SRC_USERMOD_PATHFIX_C:.c=.o)) @@ -107,6 +131,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ nlrxtensa.o \ nlrrv32.o \ nlrrv64.o \ + nlrloong64.o \ nlrsetjmp.o \ malloc.o \ gc.o \ @@ -191,12 +216,14 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ objnamedtuple.o \ objrange.o \ objreversed.o \ + objringio.o \ objset.o \ objsingleton.o \ objslice.o \ objstr.o \ objstrunicode.o \ objstringio.o \ + objtemplate.o \ objtraceback.o \ objtuple.o \ objtype.o \ @@ -216,10 +243,12 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ modmath.o \ modcmath.o \ modmicropython.o \ + modstring.o \ modstruct.o \ modsys.o \ moderrno.o \ modthread.o \ + modweakref.o \ vm.o \ bc.o \ showbc.o \ @@ -273,6 +302,14 @@ $(HEADER_BUILD)/compressed.data.h: $(HEADER_BUILD)/compressed.collected $(HEADER_BUILD)/$(TRANSLATION).mo: $(TOP)/locale/$(TRANSLATION).po | $(HEADER_BUILD) $(Q)$(PYTHON) $(TOP)/tools/msgfmt.py -o $@ $^ +# Records which TRANSLATION the generated header was built for. It is rewritten +# only when the language changes, so that building another language in the +# same build directory regenerates compressed_translations.generated.h and +# translations-*.c instead of linking one language's strings against another +# language's tables. +$(HEADER_BUILD)/translation.stamp: FORCE | $(HEADER_BUILD) + $(Q)if [ "$$(cat $@ 2>/dev/null)" != "$(TRANSLATION)" ]; then echo "$(TRANSLATION)" > $@; fi + # translations-*.c is generated as a side-effect of building compressed_translations.generated.h # Specifying both in a single rule actually causes the rule to be run twice! # This alternative makes it run just once. @@ -281,7 +318,7 @@ $(HEADER_BUILD)/$(TRANSLATION).mo: $(TOP)/locale/$(TRANSLATION).po | $(HEADER_BU $(PY_BUILD)/translations-$(TRANSLATION).c: $(HEADER_BUILD)/compressed_translations.generated.h @true -$(HEADER_BUILD)/compressed_translations.generated.h: $(PY_SRC)/maketranslationdata.py $(HEADER_BUILD)/$(TRANSLATION).mo $(HEADER_BUILD)/qstrdefs.generated.h +$(HEADER_BUILD)/compressed_translations.generated.h: $(PY_SRC)/maketranslationdata.py $(HEADER_BUILD)/$(TRANSLATION).mo $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/translation.stamp $(STEPECHO) "GEN $@" $(Q)mkdir -p $(PY_BUILD) $(Q)$(PYTHON) $(PY_SRC)/maketranslationdata.py --compression_filename $(HEADER_BUILD)/compressed_translations.generated.h --translation $(HEADER_BUILD)/$(TRANSLATION).mo --translation_filename $(PY_BUILD)/translations-$(TRANSLATION).c --qstrdefs_filename $(HEADER_BUILD)/qstrdefs.generated.h --compression_level $(CIRCUITPY_MESSAGE_COMPRESSION_LEVEL) $(HEADER_BUILD)/qstrdefs.preprocessed.h @@ -289,7 +326,7 @@ $(HEADER_BUILD)/compressed_translations.generated.h: $(PY_SRC)/maketranslationda PY_CORE_O += $(PY_BUILD)/translations-$(TRANSLATION).o # build a list of registered modules for py/objmodule.c. -$(HEADER_BUILD)/moduledefs.h: $(HEADER_BUILD)/moduledefs.collected +$(HEADER_BUILD)/moduledefs.h: $(HEADER_BUILD)/moduledefs.collected $(PY_SRC)/makemoduledefs.py @$(ECHO) "GEN $@" $(Q)$(PYTHON) $(PY_SRC)/makemoduledefs.py $< > $@ diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 01e784efc3a..afa57afa248 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -68,3 +68,7 @@ Q(utf-8) #if MICROPY_MODULE_FROZEN Q(.frozen) #endif + +#if MICROPY_PY_TSTRINGS +Q(string.templatelib) +#endif diff --git a/py/repl.c b/py/repl.c index c9a20305c79..bbfdd2ea6a6 100644 --- a/py/repl.c +++ b/py/repl.c @@ -181,8 +181,11 @@ static bool test_qstr(mp_obj_t obj, qstr name) { return dest[0] != MP_OBJ_NULL; } else { // try builtin module - return mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP) || - mp_map_lookup((mp_map_t *)&mp_builtin_extensible_module_map, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP); + return mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP) + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES + || mp_map_lookup((mp_map_t *)&mp_builtin_extensible_module_map, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP) + #endif + ; } } @@ -237,6 +240,10 @@ static void print_completions(const mp_print_t *print, for (qstr q = q_first; q <= q_last; ++q) { size_t d_len; const char *d_str = (const char *)qstr_data(q, &d_len); + // filter out words that begin with underscore unless there's already a partial match + if (s_len == 0 && d_str[0] == '_') { + continue; + } if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { if (test_qstr(obj, q)) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; diff --git a/py/runtime.c b/py/runtime.c index 9def98380fa..62a7262fee5 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -116,6 +116,9 @@ void mp_init(void) { #if MICROPY_EMIT_NATIVE MP_STATE_VM(default_emit_opt) = MP_EMIT_OPT_NONE; #endif + #if MICROPY_DEBUG_PRINTERS + MP_STATE_VM(mp_verbose_flag) = 0; + #endif #endif // init global module dict @@ -134,7 +137,7 @@ void mp_init(void) { MP_STATE_VM(mp_module_builtins_override_dict) = NULL; #endif - #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA + #if (MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE) && (MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA) MP_STATE_VM(persistent_code_root_pointers) = MP_OBJ_NULL; #endif @@ -191,6 +194,10 @@ void mp_init(void) { MP_STATE_VM(usbd) = MP_OBJ_NULL; #endif + #if MICROPY_PY_WEAKREF + mp_map_init(&MP_STATE_VM(mp_weakref_map), 0); + #endif + #if MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_VM(gil_mutex)); #endif @@ -446,7 +453,7 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs // Operations that can overflow: // + result always fits in mp_int_t, then handled by SMALL_INT check // - result always fits in mp_int_t, then handled by SMALL_INT check - // * checked explicitly + // * checked explicitly for fit in mp_int_t, then handled by SMALL_INT check // / if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check // % if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check // << checked explicitly @@ -505,30 +512,16 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs break; case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: { - - // If long long type exists and is larger than mp_int_t, then - // we can use the following code to perform overflow-checked multiplication. - // Otherwise (eg in x64 case) we must use mp_small_int_mul_overflow. - #if 0 - // compute result using long long precision - long long res = (long long)lhs_val * (long long)rhs_val; - if (res > MP_SMALL_INT_MAX || res < MP_SMALL_INT_MIN) { - // result overflowed SMALL_INT, so return higher precision integer - return mp_obj_new_int_from_ll(res); - } else { - // use standard precision - lhs_val = (mp_int_t)res; - } - #endif - - if (mp_small_int_mul_overflow(lhs_val, rhs_val)) { + mp_int_t int_res; + if (mp_mul_mp_int_t_overflow(lhs_val, rhs_val, &int_res)) { // use higher precision lhs = mp_obj_new_int_from_ll(lhs_val); goto generic_binary_op; } else { // use standard precision - return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); + lhs_val = int_res; } + break; } case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: @@ -568,19 +561,19 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs mp_int_t ans = 1; while (rhs_val > 0) { if (rhs_val & 1) { - if (mp_small_int_mul_overflow(ans, lhs_val)) { + if (mp_mul_mp_int_t_overflow(ans, lhs_val, &ans)) { goto power_overflow; } - ans *= lhs_val; } if (rhs_val == 1) { break; } rhs_val /= 2; - if (mp_small_int_mul_overflow(lhs_val, lhs_val)) { + mp_int_t int_res; + if (mp_mul_mp_int_t_overflow(lhs_val, lhs_val, &int_res)) { goto power_overflow; } - lhs_val *= lhs_val; + lhs_val = int_res; } lhs_val = ans; } @@ -976,7 +969,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob // unpacked items are stored in reverse order into the array pointed to by items // CIRCUITPY-CHANGE: noline -void __attribute__((noinline, )) mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { +MP_NOINLINE void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { size_t seq_len; if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) { mp_obj_t *seq_items; @@ -1301,6 +1294,19 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { mp_raise_msg_varg(&mp_type_AttributeError, MP_ERROR_TEXT("type object '%q' has no attribute '%q'"), ((mp_obj_type_t *)MP_OBJ_TO_PTR(base))->name, attr); + #if MICROPY_MODULE___ALL__ && MICROPY_ERROR_REPORTING >= MICROPY_ERROR_REPORTING_DETAILED + } else if (mp_obj_is_type(base, &mp_type_module)) { + // report errors in __all__ as done by CPython + mp_obj_t dest_name[2]; + qstr module_name = MP_QSTR_; + mp_load_method_maybe(base, MP_QSTR___name__, dest_name); + if (mp_obj_is_qstr(dest_name[0])) { + module_name = mp_obj_str_get_qstr(dest_name[0]); + } + mp_raise_msg_varg(&mp_type_AttributeError, + MP_ERROR_TEXT("module '%q' has no attribute '%q'"), + module_name, attr); + #endif } else { mp_raise_msg_varg(&mp_type_AttributeError, MP_ERROR_TEXT("'%s' object has no attribute '%q'"), @@ -1605,7 +1611,7 @@ mp_obj_t mp_make_raise_obj(mp_obj_t o) { } if (mp_obj_is_exception_instance(o)) { - // o is an instance of an exception, so use it as the exception + // o is a fully-constructed instance of an exception, so use it as the exception return o; } else { // o cannot be used as an exception, so return a type error (which will be raised by the caller) @@ -1619,7 +1625,7 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { // build args array mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(name); - args[1] = mp_const_none; // TODO should be globals + args[1] = MP_OBJ_FROM_PTR(mp_globals_get()); // globals of the current context args[2] = mp_const_none; // TODO should be locals args[3] = fromlist; args[4] = level; @@ -1639,20 +1645,17 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { } // CIRCUITPY-CHANGE: noinline -mp_obj_t __attribute__((noinline, )) mp_import_from(mp_obj_t module, qstr name) { +MP_NOINLINE mp_obj_t mp_import_from(mp_obj_t module, qstr name) { DEBUG_printf("import from %p %s\n", module, qstr_str(name)); mp_obj_t dest[2]; mp_load_method_maybe(module, name, dest); - if (dest[1] != MP_OBJ_NULL) { - // Hopefully we can't import bound method from an object - import_error: - mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("can't import name %q"), name); - } - - if (dest[0] != MP_OBJ_NULL) { + // Importing a bound method from a class instance. + return mp_obj_new_bound_meth(dest[0], dest[1]); + } else if (dest[0] != MP_OBJ_NULL) { + // Importing a function or attribute. return dest[0]; } @@ -1685,13 +1688,46 @@ mp_obj_t __attribute__((noinline, )) mp_import_from(mp_obj_t module, qstr name) goto import_error; #endif + +import_error: + mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("can't import name %q"), name); } void mp_import_all(mp_obj_t module) { DEBUG_printf("import all %p\n", module); - // TODO: Support __all__ - mp_map_t *map = &mp_obj_module_get_globals(module)->map; + mp_obj_t dest[2]; + + #if MICROPY_MODULE___ALL__ + mp_load_method_protected(module, MP_QSTR___all__, dest, false); + if (dest[0] != MP_OBJ_NULL) { + // When __all__ is defined, we must explicitly load all specified + // symbols, possibly invoking the module __getattr__ function + size_t len; + mp_obj_t *items; + mp_obj_get_array(dest[0], &len, &items); + for (size_t i = 0; i < len; i++) { + qstr qname = mp_obj_str_get_qstr(items[i]); + mp_load_method(module, qname, dest); + mp_store_name(qname, dest[0]); + } + return; + } + #endif + + #if MICROPY_CPYTHON_COMPAT + // Load the dict from the module. In MicroPython, if __dict__ is + // available then it always returns a native mp_obj_dict_t instance. + mp_load_method(module, MP_QSTR___dict__, dest); + #else + // Without MICROPY_CPYTHON_COMPAT __dict__ is not available, so just + // assume the given module is actually an mp_obj_module_t instance. + dest[0] = MP_OBJ_FROM_PTR(mp_obj_module_get_globals(module)); + #endif + + // By default, the set of public names includes all names found in the module's + // namespace which do not begin with an underscore character ('_') + mp_map_t *map = mp_obj_dict_get_map(dest[0]); for (size_t i = 0; i < map->alloc; i++) { if (mp_map_slot_is_filled(map, i)) { // Entry in module global scope may be generated programmatically @@ -1747,7 +1783,7 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i #endif // MICROPY_ENABLE_COMPILER // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void m_malloc_fail(size_t num_bytes) { +MP_COLD MP_NORETURN void m_malloc_fail(size_t num_bytes) { DEBUG_printf("memory allocation failed, allocating %u bytes\n", (uint)num_bytes); #if MICROPY_ENABLE_GC if (gc_is_locked()) { @@ -1761,29 +1797,29 @@ NORETURN MP_COLD void m_malloc_fail(size_t num_bytes) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_type(const mp_obj_type_t *exc_type) { +MP_COLD MP_NORETURN void mp_raise_type(const mp_obj_type_t *exc_type) { nlr_raise(mp_obj_new_exception(exc_type)); } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_ValueError_no_msg(void) { +MP_COLD MP_NORETURN void mp_raise_ValueError_no_msg(void) { mp_raise_type(&mp_type_ValueError); } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_TypeError_no_msg(void) { +MP_COLD MP_NORETURN void mp_raise_TypeError_no_msg(void) { mp_raise_type(&mp_type_TypeError); } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_NotImplementedError_no_msg(void) { +MP_COLD MP_NORETURN void mp_raise_NotImplementedError_no_msg(void) { mp_raise_type(&mp_type_NotImplementedError); } #else // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg) { if (msg == NULL) { nlr_raise(mp_obj_new_exception(exc_type)); } else { @@ -1792,24 +1828,24 @@ NORETURN MP_COLD void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_t } // CIRCUITPY-CHANGE: new function for use below. -NORETURN MP_COLD void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list argptr) { +MP_COLD MP_NORETURN void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list argptr) { mp_obj_t exception = mp_obj_new_exception_msg_vlist(exc_type, fmt, argptr); nlr_raise(exception); } // CIRCUITPY-CHANGE: MP_COLD and use mp_raise_msg_vlist() -NORETURN MP_COLD void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(exc_type, fmt, argptr); va_end(argptr); } -NORETURN MP_COLD void mp_raise_ValueError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_ValueError, msg); } -NORETURN MP_COLD void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg) { +MP_COLD MP_NORETURN void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg) { if (msg == NULL) { nlr_raise(mp_obj_new_exception(exc_type)); } else { @@ -1818,17 +1854,17 @@ NORETURN MP_COLD void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_AttributeError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_AttributeError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_AttributeError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_RuntimeError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_RuntimeError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_RuntimeError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_RuntimeError, fmt, argptr); @@ -1836,17 +1872,17 @@ NORETURN MP_COLD void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_ImportError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_ImportError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_ImportError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_IndexError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_IndexError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_IndexError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_IndexError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_IndexError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_IndexError, fmt, argptr); @@ -1854,7 +1890,7 @@ NORETURN MP_COLD void mp_raise_IndexError_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_ValueError, fmt, argptr); @@ -1862,12 +1898,12 @@ NORETURN MP_COLD void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_TypeError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_TypeError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_TypeError, fmt, argptr); @@ -1875,12 +1911,12 @@ NORETURN MP_COLD void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_OSError_msg(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_OSError_msg(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_OSError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) { +MP_COLD MP_NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) { mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(errno_), str, @@ -1889,7 +1925,7 @@ NORETURN MP_COLD void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_OSError, fmt, argptr); @@ -1897,21 +1933,23 @@ NORETURN MP_COLD void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_ConnectionError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_ConnectionError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_ConnectionError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_BrokenPipeError(void) { +MP_COLD MP_NORETURN void mp_raise_BrokenPipeError(void) { mp_raise_type_arg(&mp_type_BrokenPipeError, MP_OBJ_NEW_SMALL_INT(MP_EPIPE)); } -NORETURN MP_COLD void mp_raise_NotImplementedError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } +#endif + // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_NotImplementedError, fmt, argptr); @@ -1919,7 +1957,7 @@ NORETURN MP_COLD void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_OverflowError, fmt, argptr); @@ -1927,11 +1965,11 @@ NORETURN MP_COLD void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...) } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg) { +MP_COLD MP_NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg) { nlr_raise(mp_obj_new_exception_arg1(exc_type, arg)); } -NORETURN void mp_raise_StopIteration(mp_obj_t arg) { +MP_NORETURN void mp_raise_StopIteration(mp_obj_t arg) { if (arg == MP_OBJ_NULL) { mp_raise_type(&mp_type_StopIteration); } else { @@ -1939,7 +1977,7 @@ NORETURN void mp_raise_StopIteration(mp_obj_t arg) { } } -NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg) { +MP_NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE (void)arg; mp_raise_TypeError(MP_ERROR_TEXT("can't convert to int")); @@ -1950,12 +1988,12 @@ NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg) { } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_OSError(int errno_) { +MP_COLD MP_NORETURN void mp_raise_OSError(int errno_) { mp_raise_type_arg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_)); } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_OSError_with_filename(int errno_, const char *filename) { +MP_COLD MP_NORETURN void mp_raise_OSError_with_filename(int errno_, const char *filename) { vstr_t vstr; vstr_init(&vstr, 32); vstr_printf(&vstr, "can't open %s", filename); @@ -1965,13 +2003,12 @@ NORETURN MP_COLD void mp_raise_OSError_with_filename(int errno_, const char *fil } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_ZeroDivisionError(void) { +MP_COLD MP_NORETURN void mp_raise_ZeroDivisionError(void) { mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("division by zero")); } #if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_recursion_depth(void) { +MP_COLD MP_NORETURN void mp_raise_recursion_depth(void) { mp_raise_RuntimeError(MP_ERROR_TEXT("maximum recursion depth exceeded")); } #endif -#endif diff --git a/py/runtime.h b/py/runtime.h index a2d69638ffc..38fb05db568 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -37,11 +37,12 @@ #include "supervisor/shared/translate/translate.h" // For use with mp_call_function_1_from_nlr_jump_callback. +// Initialize an nlr_jump_callback_node_call_function_1_t struct for use with +// nlr_push_jump_callback(&ctx.callback, mp_call_function_1_from_nlr_jump_callback); #define MP_DEFINE_NLR_JUMP_CALLBACK_FUNCTION_1(ctx, f, a) \ - nlr_jump_callback_node_call_function_1_t ctx = { \ - .func = (void (*)(void *))(f), \ - .arg = (a), \ - } + nlr_jump_callback_node_call_function_1_t ctx; \ + ctx.func = (void (*)(void *))(f); \ + ctx.arg = (a) typedef enum { MP_VM_RETURN_NORMAL, @@ -58,6 +59,13 @@ typedef enum { MP_ARG_KW_ONLY = 0x200, } mp_arg_flag_t; +// These first two enum values match the original signature of `mp_handle_pending(bool)`. +typedef enum { + MP_HANDLE_PENDING_CALLBACKS_AND_CLEAR_EXCEPTIONS = false, + MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS = true, + MP_HANDLE_PENDING_CALLBACKS_ONLY, +} mp_handle_pending_behaviour_t; + typedef union _mp_arg_val_t { bool u_bool; mp_int_t u_int; @@ -106,7 +114,8 @@ void mp_sched_keyboard_interrupt(void); #if MICROPY_ENABLE_VM_ABORT void mp_sched_vm_abort(void); #endif -void mp_handle_pending(bool raise_exc); + +void mp_handle_pending(mp_handle_pending_behaviour_t behavior); #if MICROPY_ENABLE_SCHEDULER void mp_sched_lock(void); @@ -134,7 +143,7 @@ void mp_event_wait_indefinite(void); void mp_event_wait_ms(mp_uint_t timeout_ms); // extra printing method specifically for mp_obj_t's which are integral type -int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec); +int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, unsigned base, int base_char, int flags, char fill, int width, int prec); void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig); static inline void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) { @@ -142,11 +151,11 @@ static inline void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_mi } void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); -NORETURN void mp_arg_error_terse_mismatch(void); -NORETURN void mp_arg_error_unimpl_kw(void); +MP_NORETURN void mp_arg_error_terse_mismatch(void); +MP_NORETURN void mp_arg_error_unimpl_kw(void); // CIRCUITPY-CHANGE: arg validation routines -NORETURN void mp_arg_error_invalid(qstr arg_name); +MP_NORETURN void mp_arg_error_invalid(qstr arg_name); mp_int_t mp_arg_validate_int(mp_int_t i, mp_int_t required_i, qstr arg_name); mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name); mp_int_t mp_arg_validate_int_max(mp_int_t i, mp_int_t j, qstr arg_name); @@ -194,9 +203,16 @@ static inline void mp_thread_init_state(mp_state_thread_t *ts, size_t stack_size ts->gc_lock_depth = 0; // There are no pending jump callbacks or exceptions yet + ts->nlr_top = NULL; ts->nlr_jump_callback_top = NULL; ts->mp_pending_exception = MP_OBJ_NULL; + #if MICROPY_PY_SYS_SETTRACE + ts->prof_trace_callback = MP_OBJ_NULL; + ts->prof_callback_is_executing = false; + ts->current_code_state = NULL; + #endif + // If locals/globals are not given, inherit from main thread if (locals == NULL) { locals = mp_state_ctx.thread.dict_locals; @@ -274,10 +290,10 @@ mp_obj_t mp_import_from(mp_obj_t module, qstr name); void mp_import_all(mp_obj_t module); #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE -NORETURN void mp_raise_type(const mp_obj_type_t *exc_type); -NORETURN void mp_raise_ValueError_no_msg(void); -NORETURN void mp_raise_TypeError_no_msg(void); -NORETURN void mp_raise_NotImplementedError_no_msg(void); +MP_NORETURN void mp_raise_type(const mp_obj_type_t *exc_type); +MP_NORETURN void mp_raise_ValueError_no_msg(void); +MP_NORETURN void mp_raise_TypeError_no_msg(void); +MP_NORETURN void mp_raise_NotImplementedError_no_msg(void); #define mp_raise_msg(exc_type, msg) mp_raise_type(exc_type) #define mp_raise_msg_varg(exc_type, ...) mp_raise_type(exc_type) #define mp_raise_ValueError(msg) mp_raise_ValueError_no_msg() @@ -285,46 +301,46 @@ NORETURN void mp_raise_NotImplementedError_no_msg(void); #define mp_raise_NotImplementedError(msg) mp_raise_NotImplementedError_no_msg() #else #define mp_raise_type(exc_type) mp_raise_msg(exc_type, NULL) -NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg); -NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg); -NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg); -NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg); #endif // CIRCUITPY-CHANGE: new mp_raise routines -NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg); -NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg); -NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt +MP_NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg); +MP_NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt , ...); -NORETURN void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list argptr); +MP_NORETURN void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list argptr); // Only use this string version in native mpy files. Otherwise, use the compressed string version. -NORETURN void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg); - -NORETURN void mp_raise_AttributeError(mp_rom_error_text_t msg); -NORETURN void mp_raise_BrokenPipeError(void); -NORETURN void mp_raise_ConnectionError(mp_rom_error_text_t msg); -NORETURN void mp_raise_ImportError(mp_rom_error_text_t msg); -NORETURN void mp_raise_IndexError(mp_rom_error_text_t msg); -NORETURN void mp_raise_IndexError_varg(mp_rom_error_text_t msg, ...); -NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg); -NORETURN void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str); -NORETURN void mp_raise_OSError(int errno_); -NORETURN void mp_raise_OSError_msg(mp_rom_error_text_t msg); -NORETURN void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_OSError_with_filename(int errno_, const char *filename); -NORETURN void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_recursion_depth(void); -NORETURN void mp_raise_RuntimeError(mp_rom_error_text_t msg); -NORETURN void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_StopIteration(mp_obj_t arg); -NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg); -NORETURN void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg); -NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg); -NORETURN void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_ZeroDivisionError(void); +MP_NORETURN void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg); + +MP_NORETURN void mp_raise_AttributeError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_BrokenPipeError(void); +MP_NORETURN void mp_raise_ConnectionError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_ImportError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_IndexError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_IndexError_varg(mp_rom_error_text_t msg, ...); +MP_NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str); +MP_NORETURN void mp_raise_OSError(int errno_); +MP_NORETURN void mp_raise_OSError_msg(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_OSError_with_filename(int errno_, const char *filename); +MP_NORETURN void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_recursion_depth(void); +MP_NORETURN void mp_raise_RuntimeError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_StopIteration(mp_obj_t arg); +MP_NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg); +MP_NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_ZeroDivisionError(void); #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG #undef mp_check_self diff --git a/py/runtime_utils.c b/py/runtime_utils.c index 98252c31220..33da558e30f 100644 --- a/py/runtime_utils.c +++ b/py/runtime_utils.c @@ -53,3 +53,59 @@ mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2 return MP_OBJ_NULL; } } + +#if !MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC +bool mp_mul_ll_overflow(long long int x, long long int y, long long int *res) { + bool overflow; + + // Check for multiply overflow; see CERT INT32-C + if (x > 0) { // x is positive + if (y > 0) { // x and y are positive + overflow = (x > (LLONG_MAX / y)); + } else { // x positive, y nonpositive + overflow = (y < (LLONG_MIN / x)); + } // x positive, y nonpositive + } else { // x is nonpositive + if (y > 0) { // x is nonpositive, y is positive + overflow = (x < (LLONG_MIN / y)); + } else { // x and y are nonpositive + overflow = (x != 0 && y < (LLONG_MAX / x)); + } // End if x and y are nonpositive + } // End if x is nonpositive + + if (!overflow) { + *res = x * y; + } + + return overflow; +} + +bool mp_mul_mp_int_t_overflow(mp_int_t x, mp_int_t y, mp_int_t *res) { + // Check for multiply overflow; see CERT INT32-C + if (x > 0) { // x is positive + if (y > 0) { // x and y are positive + if (x > (MP_INT_MAX / y)) { + return true; + } + } else { // x positive, y nonpositive + if (y < (MP_INT_MIN / x)) { + return true; + } + } // x positive, y nonpositive + } else { // x is nonpositive + if (y > 0) { // x is nonpositive, y is positive + if (x < (MP_INT_MIN / y)) { + return true; + } + } else { // x and y are nonpositive + if (x != 0 && y < (MP_INT_MAX / x)) { + return true; + } + } // End if x and y are nonpositive + } // End if x is nonpositive + + // Result doesn't overflow + *res = x * y; + return false; +} +#endif diff --git a/py/scheduler.c b/py/scheduler.c index 92e5af6b31b..e75927dbe0b 100644 --- a/py/scheduler.c +++ b/py/scheduler.c @@ -97,17 +97,21 @@ static inline void mp_sched_run_pending(void) { #if MICROPY_SCHEDULER_STATIC_NODES // Run all pending C callbacks. - while (MP_STATE_VM(sched_head) != NULL) { - mp_sched_node_t *node = MP_STATE_VM(sched_head); - MP_STATE_VM(sched_head) = node->next; - if (MP_STATE_VM(sched_head) == NULL) { - MP_STATE_VM(sched_tail) = NULL; - } - mp_sched_callback_t callback = node->callback; - node->callback = NULL; - MICROPY_END_ATOMIC_SECTION(atomic_state); - callback(node); - atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_sched_node_t *original_tail = MP_STATE_VM(sched_tail); + if (original_tail != NULL) { + mp_sched_node_t *node; + do { + node = MP_STATE_VM(sched_head); + MP_STATE_VM(sched_head) = node->next; + if (MP_STATE_VM(sched_head) == NULL) { + MP_STATE_VM(sched_tail) = NULL; + } + mp_sched_callback_t callback = node->callback; + node->callback = NULL; + MICROPY_END_ATOMIC_SECTION(atomic_state); + callback(node); + atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + } while (node != original_tail); // Don't execute any callbacks scheduled during this run } #endif @@ -218,24 +222,27 @@ MP_REGISTER_ROOT_POINTER(mp_sched_item_t sched_queue[MICROPY_SCHEDULER_DEPTH]); // Called periodically from the VM or from "waiting" code (e.g. sleep) to // process background tasks and pending exceptions (e.g. KeyboardInterrupt). -void mp_handle_pending(bool raise_exc) { +void mp_handle_pending(mp_handle_pending_behaviour_t behavior) { + bool handle_exceptions = (behavior != MP_HANDLE_PENDING_CALLBACKS_ONLY); + bool raise_exceptions = (behavior == MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS); + // Handle pending VM abort. #if MICROPY_ENABLE_VM_ABORT - if (MP_STATE_VM(vm_abort) && mp_thread_is_main_thread()) { + if (handle_exceptions && MP_STATE_VM(vm_abort) && mp_thread_is_main_thread()) { MP_STATE_VM(vm_abort) = false; - if (raise_exc && nlr_get_abort() != NULL) { + if (raise_exceptions && nlr_get_abort() != NULL) { nlr_jump_abort(); } } #endif // Handle any pending exception. - if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) { + if (handle_exceptions && MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); mp_obj_t obj = MP_STATE_THREAD(mp_pending_exception); if (obj != MP_OBJ_NULL) { MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL; - if (raise_exc) { + if (raise_exceptions) { MICROPY_END_ATOMIC_SECTION(atomic_state); nlr_raise(obj); } @@ -265,7 +272,7 @@ void mp_event_handle_nowait(void) { #else // Process any port layer (non-blocking) events. MICROPY_INTERNAL_EVENT_HOOK; - mp_handle_pending(true); + mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS); #endif } diff --git a/py/sequence.c b/py/sequence.c index ac7ad5368b9..6bbc62f0f7f 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -34,18 +34,13 @@ #define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; } // CIRCUITPY-CHANGE: detect sequence overflow -#if __GNUC__ < 5 -// n.b. does not actually detect overflow! -#define __builtin_mul_overflow(a, b, x) (*(x) = (a) * (b), false) -#endif - // Detect when a multiply causes an overflow. size_t mp_seq_multiply_len(size_t item_sz, size_t len) { - size_t new_len; - if (__builtin_mul_overflow(item_sz, len, &new_len)) { + mp_int_t new_len; + if (mp_mul_mp_int_t_overflow(item_sz, len, &new_len)) { mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow")); } - return new_len; + return (size_t)new_len; } // Implements backend of sequence * integer operation. Assumes elements are diff --git a/py/showbc.c b/py/showbc.c index 6913d18c1ca..68e2f33138c 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -99,8 +99,8 @@ void mp_bytecode_print(const mp_print_t *print, const mp_raw_code_t *rc, size_t #else qstr source_file = cm->source_file; #endif - mp_printf(print, "File %s, code block '%s' (descriptor: %p, bytecode @%p %u bytes)\n", - qstr_str(source_file), qstr_str(block_name), rc, ip_start, (unsigned)fun_data_len); + mp_printf(print, "File %q, code block '%q' (descriptor: %p, bytecode @%p %u bytes)\n", + source_file, block_name, rc, ip_start, (unsigned)fun_data_len); // raw bytecode dump size_t prelude_size = ip - ip_start + n_info + n_cell; @@ -121,7 +121,7 @@ void mp_bytecode_print(const mp_print_t *print, const mp_raw_code_t *rc, size_t #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE qst = cm->qstr_table[qst]; #endif - mp_printf(print, " %s", qstr_str(qst)); + mp_printf(print, " %q", qst); } mp_printf(print, "\n"); @@ -144,17 +144,9 @@ void mp_bytecode_print(const mp_print_t *print, const mp_raw_code_t *rc, size_t mp_uint_t source_line = 1; mp_printf(print, " bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); for (const byte *ci = code_info; ci < line_info_top;) { - if ((ci[0] & 0x80) == 0) { - // 0b0LLBBBBB encoding - bc += ci[0] & 0x1f; - source_line += ci[0] >> 5; - ci += 1; - } else { - // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) - bc += ci[0] & 0xf; - source_line += ((ci[0] << 4) & 0x700) | ci[1]; - ci += 2; - } + mp_code_lineinfo_t decoded = mp_bytecode_decode_lineinfo(&ci); + bc += decoded.bc_increment; + source_line += decoded.line_increment; mp_printf(print, " bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); } } @@ -197,7 +189,7 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip_start, case MP_BC_LOAD_CONST_STRING: DECODE_QSTR; - mp_printf(print, "LOAD_CONST_STRING '%s'", qstr_str(qst)); + mp_printf(print, "LOAD_CONST_STRING '%q'", qst); break; case MP_BC_LOAD_CONST_OBJ: @@ -222,27 +214,27 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip_start, case MP_BC_LOAD_NAME: DECODE_QSTR; - mp_printf(print, "LOAD_NAME %s", qstr_str(qst)); + mp_printf(print, "LOAD_NAME %q", qst); break; case MP_BC_LOAD_GLOBAL: DECODE_QSTR; - mp_printf(print, "LOAD_GLOBAL %s", qstr_str(qst)); + mp_printf(print, "LOAD_GLOBAL %q", qst); break; case MP_BC_LOAD_ATTR: DECODE_QSTR; - mp_printf(print, "LOAD_ATTR %s", qstr_str(qst)); + mp_printf(print, "LOAD_ATTR %q", qst); break; case MP_BC_LOAD_METHOD: DECODE_QSTR; - mp_printf(print, "LOAD_METHOD %s", qstr_str(qst)); + mp_printf(print, "LOAD_METHOD %q", qst); break; case MP_BC_LOAD_SUPER_METHOD: DECODE_QSTR; - mp_printf(print, "LOAD_SUPER_METHOD %s", qstr_str(qst)); + mp_printf(print, "LOAD_SUPER_METHOD %q", qst); break; case MP_BC_LOAD_BUILD_CLASS: @@ -265,17 +257,17 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip_start, case MP_BC_STORE_NAME: DECODE_QSTR; - mp_printf(print, "STORE_NAME %s", qstr_str(qst)); + mp_printf(print, "STORE_NAME %q", qst); break; case MP_BC_STORE_GLOBAL: DECODE_QSTR; - mp_printf(print, "STORE_GLOBAL %s", qstr_str(qst)); + mp_printf(print, "STORE_GLOBAL %q", qst); break; case MP_BC_STORE_ATTR: DECODE_QSTR; - mp_printf(print, "STORE_ATTR %s", qstr_str(qst)); + mp_printf(print, "STORE_ATTR %q", qst); break; case MP_BC_STORE_SUBSCR: @@ -294,12 +286,12 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip_start, case MP_BC_DELETE_NAME: DECODE_QSTR; - mp_printf(print, "DELETE_NAME %s", qstr_str(qst)); + mp_printf(print, "DELETE_NAME %q", qst); break; case MP_BC_DELETE_GLOBAL: DECODE_QSTR; - mp_printf(print, "DELETE_GLOBAL %s", qstr_str(qst)); + mp_printf(print, "DELETE_GLOBAL %q", qst); break; case MP_BC_DUP_TOP: @@ -514,12 +506,12 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip_start, case MP_BC_IMPORT_NAME: DECODE_QSTR; - mp_printf(print, "IMPORT_NAME '%s'", qstr_str(qst)); + mp_printf(print, "IMPORT_NAME '%q'", qst); break; case MP_BC_IMPORT_FROM: DECODE_QSTR; - mp_printf(print, "IMPORT_FROM '%s'", qstr_str(qst)); + mp_printf(print, "IMPORT_FROM '%q'", qst); break; case MP_BC_IMPORT_STAR: @@ -535,10 +527,10 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip_start, mp_printf(print, "STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI); } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { mp_uint_t op = ip[-1] - MP_BC_UNARY_OP_MULTI; - mp_printf(print, "UNARY_OP " UINT_FMT " %s", op, qstr_str(mp_unary_op_method_name[op])); + mp_printf(print, "UNARY_OP " UINT_FMT " %q", op, (qstr)mp_unary_op_method_name[op]); } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) { mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI; - mp_printf(print, "BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op])); + mp_printf(print, "BINARY_OP " UINT_FMT " %q", op, (qstr)mp_binary_op_method_name[op]); } else { mp_printf(print, "code %p, byte code 0x%02x not implemented\n", ip - 1, ip[-1]); assert(0); diff --git a/py/smallint.c b/py/smallint.c index aa542ca7bf2..eb99b58667a 100644 --- a/py/smallint.c +++ b/py/smallint.c @@ -26,32 +26,6 @@ #include "py/smallint.h" -bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y) { - // Check for multiply overflow; see CERT INT32-C - if (x > 0) { // x is positive - if (y > 0) { // x and y are positive - if (x > (MP_SMALL_INT_MAX / y)) { - return true; - } - } else { // x positive, y nonpositive - if (y < (MP_SMALL_INT_MIN / x)) { - return true; - } - } // x positive, y nonpositive - } else { // x is nonpositive - if (y > 0) { // x is nonpositive, y is positive - if (x < (MP_SMALL_INT_MIN / y)) { - return true; - } - } else { // x and y are nonpositive - if (x != 0 && y < (MP_SMALL_INT_MAX / x)) { - return true; - } - } // End if x and y are nonpositive - } // End if x is nonpositive - return false; -} - mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor) { // Python specs require that mod has same sign as second operand dividend %= divisor; diff --git a/py/smallint.h b/py/smallint.h index 584e0018d1b..ec5b0af3b28 100644 --- a/py/smallint.h +++ b/py/smallint.h @@ -68,7 +68,6 @@ // The number of bits in a MP_SMALL_INT including the sign bit. #define MP_SMALL_INT_BITS (MP_IMAX_BITS(MP_SMALL_INT_MAX) + 1) -bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y); mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor); mp_int_t mp_small_int_floor_divide(mp_int_t num, mp_int_t denom); diff --git a/py/stream.c b/py/stream.c index fbf7fd878a1..d3b0a0d80e2 100644 --- a/py/stream.c +++ b/py/stream.c @@ -107,6 +107,17 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("stream operation not supported")); } +static MP_NORETURN void mp_stream_raise_error(mp_obj_t stream, int error) { + #if MICROPY_STREAMS_DELEGATE_ERROR + const mp_stream_p_t *stream_p = mp_get_stream(stream); + if (stream_p->ioctl != NULL) { + int err; + stream_p->ioctl(stream, MP_STREAM_RAISE_ERROR, error, &err); + } + #endif + mp_raise_OSError(error); +} + static mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { // What to do if sz < -1? Python docs don't specify this case. // CPython does a readall, but here we silently let negatives through, @@ -150,7 +161,7 @@ static mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl } break; } - mp_raise_OSError(error); + mp_stream_raise_error(args[0], error); } if (out_sz < more_bytes) { @@ -218,7 +229,7 @@ static mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl // this as EOF. return mp_const_none; } - mp_raise_OSError(error); + mp_stream_raise_error(args[0], error); } else { vstr.len = out_sz; if (stream_p->is_text) { @@ -249,7 +260,7 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte fla // no single byte could be readily written to it." return mp_const_none; } - mp_raise_OSError(error); + mp_stream_raise_error(self_in, error); } else { return MP_OBJ_NEW_SMALL_INT(out_sz); } @@ -260,9 +271,14 @@ void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE); } -static mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { +static mp_obj_t stream_readinto_write_generic(size_t n_args, const mp_obj_t *args, byte flags) { mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + mp_get_buffer_raise(args[1], &bufinfo, (flags & MP_STREAM_RW_WRITE) ? MP_BUFFER_READ : MP_BUFFER_WRITE); + + // CPython extension, allow optional maximum length and offset: + // - stream.operation(buf, max_len) + // - stream.operation(buf, off, max_len) + // Similar to https://docs.python.org/3/library/socket.html#socket.socket.recv_into size_t max_len = (size_t)-1; size_t off = 0; if (n_args == 3) { @@ -275,45 +291,31 @@ static mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { } } bufinfo.len -= off; - return mp_stream_write(args[0], (byte *)bufinfo.buf + off, MIN(bufinfo.len, max_len), MP_STREAM_RW_WRITE); + + // Perform the readinto or write operation. + return mp_stream_write(args[0], (byte *)bufinfo.buf + off, MIN(bufinfo.len, max_len), flags); +} + +static mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { + return stream_readinto_write_generic(n_args, args, MP_STREAM_RW_WRITE); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj, 2, 4, stream_write_method); -static mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE | MP_STREAM_RW_ONCE); +static mp_obj_t stream_write1_method(size_t n_args, const mp_obj_t *args) { + return stream_readinto_write_generic(n_args, args, MP_STREAM_RW_WRITE | MP_STREAM_RW_ONCE); } -MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write1_obj, 2, 4, stream_write1_method); static mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); - - // CPython extension: if 2nd arg is provided, that's max len to read, - // instead of full buffer. Similar to - // https://docs.python.org/3/library/socket.html#socket.socket.recv_into - mp_uint_t len = bufinfo.len; - if (n_args > 2) { - len = mp_obj_get_int(args[2]); - if (len > bufinfo.len) { - len = bufinfo.len; - } - } - - int error; - mp_uint_t out_sz = mp_stream_read_exactly(args[0], bufinfo.buf, len, &error); - if (error != 0) { - if (mp_is_nonblocking_error(error)) { - return mp_const_none; - } - mp_raise_OSError(error); - } else { - return MP_OBJ_NEW_SMALL_INT(out_sz); - } + return stream_readinto_write_generic(n_args, args, MP_STREAM_RW_READ); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto); +static mp_obj_t stream_readinto1(size_t n_args, const mp_obj_t *args) { + return stream_readinto_write_generic(n_args, args, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto1_obj, 2, 3, stream_readinto1); + static mp_obj_t stream_readall(mp_obj_t self_in) { const mp_stream_p_t *stream_p = mp_get_stream(self_in); @@ -335,7 +337,7 @@ static mp_obj_t stream_readall(mp_obj_t self_in) { } break; } - mp_raise_OSError(error); + mp_stream_raise_error(self_in, error); } if (out_sz == 0) { break; @@ -393,7 +395,7 @@ static mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) goto done; } } - mp_raise_OSError(error); + mp_stream_raise_error(args[0], error); } if (out_sz == 0) { done: @@ -443,7 +445,7 @@ mp_obj_t mp_stream_close(mp_obj_t 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); + mp_stream_raise_error(stream, error); } return mp_const_none; } @@ -458,20 +460,20 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream___exit___obj, 4, 4, mp_stream___ex static mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { // TODO: Could be uint64 mp_off_t offset = mp_obj_get_int(args[1]); - int whence = SEEK_SET; + int whence = MP_SEEK_SET; if (n_args == 3) { whence = mp_obj_get_int(args[2]); } // In POSIX, it's error to seek before end of stream, we enforce it here. - if (whence == SEEK_SET && offset < 0) { + if (whence == MP_SEEK_SET && offset < 0) { mp_raise_OSError(MP_EINVAL); } int error; mp_off_t res = mp_stream_seek(args[0], offset, whence, &error); if (res == (mp_off_t)-1) { - mp_raise_OSError(error); + mp_stream_raise_error(args[0], error); } // TODO: Could be uint64 @@ -481,7 +483,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj, 2, 3, stream_seek); static mp_obj_t stream_tell(mp_obj_t self) { mp_obj_t offset = MP_OBJ_NEW_SMALL_INT(0); - mp_obj_t whence = MP_OBJ_NEW_SMALL_INT(SEEK_CUR); + mp_obj_t whence = MP_OBJ_NEW_SMALL_INT(MP_SEEK_CUR); const mp_obj_t args[3] = {self, offset, whence}; return stream_seek(3, args); } @@ -493,7 +495,7 @@ mp_obj_t mp_stream_flush(mp_obj_t self) { int error; mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error); if (res == MP_STREAM_ERROR) { - mp_raise_OSError(error); + mp_stream_raise_error(self, error); } return mp_const_none; } @@ -514,7 +516,7 @@ static mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { int error; mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error); if (res == MP_STREAM_ERROR) { - mp_raise_OSError(error); + mp_stream_raise_error(args[0], error); } return mp_obj_new_int(res); diff --git a/py/stream.h b/py/stream.h index 5e1cd5d4413..153800c3808 100644 --- a/py/stream.h +++ b/py/stream.h @@ -27,6 +27,7 @@ #ifndef MICROPY_INCLUDED_PY_STREAM_H #define MICROPY_INCLUDED_PY_STREAM_H +#include "py/mpconfig.h" #include "py/obj.h" // CIRCUITPY-CHANGE #include "py/proto.h" @@ -35,17 +36,20 @@ #define MP_STREAM_ERROR ((mp_uint_t)-1) // Stream ioctl request codes -#define MP_STREAM_FLUSH (1) -#define MP_STREAM_SEEK (2) -#define MP_STREAM_POLL (3) -#define MP_STREAM_CLOSE (4) -#define MP_STREAM_TIMEOUT (5) // Get/set timeout (single op) -#define MP_STREAM_GET_OPTS (6) // Get stream options -#define MP_STREAM_SET_OPTS (7) // Set stream options -#define MP_STREAM_GET_DATA_OPTS (8) // Get data/message options -#define MP_STREAM_SET_DATA_OPTS (9) // Set data/message options -#define MP_STREAM_GET_FILENO (10) // Get fileno of underlying file -#define MP_STREAM_GET_BUFFER_SIZE (11) // Get preferred buffer size for file +#define MP_STREAM_FLUSH (1) +#define MP_STREAM_SEEK (2) +#define MP_STREAM_POLL (3) +#define MP_STREAM_CLOSE (4) +#define MP_STREAM_TIMEOUT (5) // Get/set timeout (single op) +#define MP_STREAM_GET_OPTS (6) // Get stream options +#define MP_STREAM_SET_OPTS (7) // Set stream options +#define MP_STREAM_GET_DATA_OPTS (8) // Get data/message options +#define MP_STREAM_SET_DATA_OPTS (9) // Set data/message options +#define MP_STREAM_GET_FILENO (10) // Get fileno of underlying file +#define MP_STREAM_GET_BUFFER_SIZE (11) // Get preferred buffer size for file +#if MICROPY_STREAMS_DELEGATE_ERROR +#define MP_STREAM_RAISE_ERROR (12) // Raise an error with detailed error string +#endif // These poll ioctl values are compatible with Linux #define MP_STREAM_POLL_RD (0x0001) @@ -72,8 +76,12 @@ struct mp_stream_seek_t { typedef struct _mp_stream_p_t { // CIRCUITPY-CHANGE MP_PROTOCOL_HEAD - // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values - // are implementation-dependent, but will be exposed to user, e.g. via exception). + // On error, functions should return MP_STREAM_ERROR and fill in *errcode + // (values are are implementation-dependent, but will be exposed to user). + // If MICROPY_STREAMS_DELEGATE_ERROR is enabled and ioctl is not null the + // stream will receive a MP_STREAM_RAISE_ERROR ioctl request with the arg + // containing the errcode, so it may raise a more detailed error. If that + // ioctl returns without raising, an OSError with the errcode will raised. mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode); mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); @@ -87,10 +95,11 @@ typedef struct _mp_stream_p_t { MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto1_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj); -MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write1_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_close_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream___exit___obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj); diff --git a/py/unicode.c b/py/unicode.c index 81a37880f3c..4f6a273fe74 100644 --- a/py/unicode.c +++ b/py/unicode.c @@ -180,7 +180,7 @@ mp_uint_t unichar_xdigit_value(unichar c) { #if MICROPY_PY_BUILTINS_STR_UNICODE -bool utf8_check(const byte *p, size_t len) { +bool unicode_encoding_check(mp_encoding_t encoding, const byte *p, size_t len) { uint8_t need = 0; const byte *end = p + len; for (; p < end; p++) { @@ -193,7 +193,7 @@ bool utf8_check(const byte *p, size_t len) { return 0; } } else { - if (c >= 0xc0) { + if (encoding == MP_ENCODING_UTF8 && c >= 0xc0) { if (c >= 0xf8) { // mismatch return 0; diff --git a/py/unicode.h b/py/unicode.h index c1fb517894f..7b82c466e51 100644 --- a/py/unicode.h +++ b/py/unicode.h @@ -29,7 +29,14 @@ #include "py/mpconfig.h" #include "py/misc.h" +typedef enum { + MP_ENCODING_UTF8, + MP_ENCODING_ASCII, +} mp_encoding_t; + mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr); -bool utf8_check(const byte *p, size_t len); + +// Returns true if bytes in buffer 'p' are valid according to encoding. +bool unicode_encoding_check(mp_encoding_t encoding, const byte *p, size_t len); #endif // MICROPY_INCLUDED_PY_UNICODE_H diff --git a/py/usermod.cmake b/py/usermod.cmake index 4a8b99ff31b..648f315b9d5 100644 --- a/py/usermod.cmake +++ b/py/usermod.cmake @@ -39,6 +39,13 @@ function(usermod_gather_sources SOURCES_VARNAME INCLUDE_DIRECTORIES_VARNAME INCL endif() endfunction() +# Extract c_module() entries from MICROPY_FROZEN_MANIFEST and merge them into +# USER_C_MODULES, so the loop below picks them up alongside USER_C_MODULES paths +# passed on the cmake command line. The port is responsible for resolving +# MICROPY_FROZEN_MANIFEST (including any board-config defaults) before +# including this file. +include(${MICROPY_DIR}/py/manifest.cmake) + # Include CMake files for user modules. if (USER_C_MODULES) foreach(USER_C_MODULE_PATH ${USER_C_MODULES}) diff --git a/py/vm.c b/py/vm.c index 6fd17782619..fcb6d9f184e 100644 --- a/py/vm.c +++ b/py/vm.c @@ -205,6 +205,22 @@ static mp_obj_t get_active_exception(mp_exc_stack_t *exc_sp, mp_exc_stack_t *exc return MP_OBJ_NULL; } +#if MICROPY_PY_BUILTINS_SLICE +// This function is marked "no inline" so it doesn't increase the C stack usage of the main VM function. +MP_NOINLINE static mp_obj_t *build_slice_stack_allocated(byte op, mp_obj_t *sp, mp_obj_t step) { + mp_obj_t stop = sp[2]; + mp_obj_t start = sp[1]; + mp_obj_slice_t slice = { .base = { .type = &mp_type_slice }, .start = start, .stop = stop, .step = step }; + if (op == MP_BC_LOAD_SUBSCR) { + SET_TOP(mp_obj_subscr(TOP(), MP_OBJ_FROM_PTR(&slice), MP_OBJ_SENTINEL)); + } else { // MP_BC_STORE_SUBSCR + mp_obj_subscr(TOP(), MP_OBJ_FROM_PTR(&slice), sp[-1]); + sp -= 2; + } + return sp; +} +#endif + // fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc) // sp points to bottom of stack which grows up // returns: @@ -871,9 +887,20 @@ unwind_jump:; // 3-argument slice includes step step = POP(); } - mp_obj_t stop = POP(); - mp_obj_t start = TOP(); - SET_TOP(mp_obj_new_slice(start, stop, step)); + if ((*ip == MP_BC_LOAD_SUBSCR || *ip == MP_BC_STORE_SUBSCR) + && (mp_obj_get_type(sp[-2])->flags & MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE)) { + // Fast path optimisation for when the BUILD_SLICE is immediately followed + // by a LOAD/STORE_SUBSCR for an accepting type, to avoid needing to allocate + // the slice on the heap. In some cases (e.g. a[1:3] = x) this can result + // in no allocations at all. We can't do this for instance types because + // the get/set/delattr implementation may keep a reference to the slice. + byte op = *ip++; + sp = build_slice_stack_allocated(op, sp - 2, step); + } else { + mp_obj_t stop = POP(); + mp_obj_t start = TOP(); + SET_TOP(mp_obj_new_slice(start, stop, step)); + } DISPATCH(); } #endif @@ -1353,7 +1380,7 @@ unwind_jump:; MICROPY_VM_HOOK_LOOP // Check for pending exceptions or scheduled tasks to run. - // Note: it's safe to just call mp_handle_pending(true), but + // Note: it's safe to just call mp_handle_pending(...), but // we can inline the check for the common case where there is // neither. if ( @@ -1375,7 +1402,7 @@ unwind_jump:; #endif ) { MARK_EXC_IP_SELECTIVE(); - mp_handle_pending(true); + mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS); } #if MICROPY_PY_THREAD_GIL diff --git a/py/vstr.c b/py/vstr.c index 00972edf897..95607d11bb8 100644 --- a/py/vstr.c +++ b/py/vstr.c @@ -51,7 +51,7 @@ void vstr_init(vstr_t *vstr, size_t alloc) { // Init the vstr so it allocs exactly enough ram to hold a null-terminated // string of the given length, and set the length. void vstr_init_len(vstr_t *vstr, size_t len) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: check for invalid length if (len == SIZE_MAX) { m_malloc_fail(len); } @@ -187,33 +187,21 @@ void vstr_add_strn(vstr_t *vstr, const char *str, size_t len) { vstr->len += len; } -static char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len) { +char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len) { size_t l = vstr->len; if (byte_pos > l) { byte_pos = l; } - if (byte_len > 0) { - // ensure room for the new bytes - vstr_ensure_extra(vstr, byte_len); - // copy up the string to make room for the new bytes - memmove(vstr->buf + byte_pos + byte_len, vstr->buf + byte_pos, l - byte_pos); - // increase the length - vstr->len += byte_len; - } + // ensure room for the new bytes + vstr_ensure_extra(vstr, byte_len); + // copy up the string to make room for the new bytes + memmove(vstr->buf + byte_pos + byte_len, vstr->buf + byte_pos, l - byte_pos); + // increase the length + vstr->len += byte_len; + // return a pointer to the location to insert new bytes at return vstr->buf + byte_pos; } -void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b) { - char *s = vstr_ins_blank_bytes(vstr, byte_pos, 1); - *s = b; -} - -void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr) { - // TODO UNICODE - char *s = vstr_ins_blank_bytes(vstr, char_pos, 1); - *s = chr; -} - void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut) { vstr_cut_out_bytes(vstr, 0, bytes_to_cut); } diff --git a/pyproject.toml b/pyproject.toml index 0db7eb70a78..6c865ea2037 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,35 +1,27 @@ -# SPDX-FileCopyrightText: 2024 Scott Shawcroft for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -[tool.setuptools_scm] # can be empty if no extra settings are needed, presence enables setuptools-scm - -# Ruff settings copied from MicroPython - [tool.ruff] -target-version = "py37" - +target-version = "py312" line-length = 99 -# Exclude third-party code from linting and formatting. Ruff doesn't know how to ignore submodules. -# Exclude the following tests: -# repl_: not real python files -# viper_args: uses f(*) +builtins = [ "const", "execfile", "micropython", "ptr", "ptr8", "ptr16", "ptr32", "uint" ] +# Include Python source files that don't end with .py +extend-include = [ "tools/cc1" ] +# Exclude third-party code from linting and formatting extend-exclude = [ + # CIRCUITPY-CHANGES "extmod/ulab", "frozen", "lib", "ports/analog/msdk", "ports/atmel-samd/asf4", "ports/broadcom/peripherals", + "ports/espress/tools", "ports/espressif/esp-idf", "ports/espressif/esp-protocols", "ports/raspberrypi/sdk", "ports/silabs/gecko_sdk", "ports/silabs/tools/slc_cli_linux", "ports/stm/st_driver", - "tests/*/repl_*.py", - "tests/micropython/viper_args.py", + "tests/cpydiff/syntax_assign_expr.py", # intentionally incorrect CPython code "tools/adabot", "tools/bitmap_font", "tools/cc1", @@ -40,8 +32,19 @@ extend-exclude = [ ] # Exclude third-party code, and exclude the following tests: # basics: needs careful attention before applying automatic formatting -format.exclude = [ "tests/basics/*.py" ] -lint.extend-select = [ "C9", "PLC" ] +# repl_: not real python files +# tstring: ruff does not support template strings +# viper_args: uses f(*) +format.exclude = [ + "tests/*/repl_*.py", + "tests/basics/*.py", + "tests/cmdline/cmd_compile_only_error.py", + "tests/feature_check/tstring.py", + "tests/micropython/heapalloc_fail_tstring.py", + "tests/micropython/test_normalize_newlines.py", + "tests/micropython/viper_args.py", +] +lint.extend-select = [ "C9", "PLC", "W292" ] lint.ignore = [ "E401", "E402", @@ -51,11 +54,54 @@ lint.ignore = [ "F401", "F403", "F405", - "PLC1901", + "PLC0206", + "PLC0415", # conditional imports are common in MicroPython +] +lint.exclude = [ + # Ruff finds Python SyntaxError in these files + "tests/basics/string_module_tstring.py", + "tests/basics/string_tstring_basic.py", + "tests/basics/string_tstring_basic1.py", + "tests/basics/string_tstring_constructor.py", + "tests/basics/string_tstring_errors1.py", + "tests/basics/string_tstring_format1.py", + "tests/basics/string_tstring_interpolation1.py", + "tests/basics/string_tstring_operations.py", + "tests/basics/string_tstring_parser1.py", + "tests/cmdline/cmd_compile_only_error.py", + "tests/cmdline/repl_autocomplete.py", + "tests/cmdline/repl_autocomplete_underscore.py", + "tests/cmdline/repl_autoindent.py", + "tests/cmdline/repl_basic.py", + "tests/cmdline/repl_cont.py", + "tests/cmdline/repl_ctrl_c_interrupt_execution.py", + "tests/cmdline/repl_emacs_keys.py", + "tests/cmdline/repl_paste.py", + "tests/cmdline/repl_words_move.py", + "tests/feature_check/repl_emacs_check.py", + "tests/feature_check/repl_words_move_check.py", + "tests/feature_check/tstring.py", + "tests/micropython/heapalloc_fail_tstring.py", + "tests/micropython/viper_args.py", ] # manifest.py files are evaluated with some global names pre-defined lint.per-file-ignores."**/manifest.py" = [ "F821" ] lint.per-file-ignores."ports/**/boards/**/manifest_*.py" = [ "F821" ] -# Exclude all tests from linting (does not apply to formatting). +lint.per-file-ignores."ports/cc3200/tools/uniflash.py" = [ "E711" ] +# Exclude all tests from linting. lint.per-file-ignores."tests/**/*.py" = [ "ALL" ] +# Uses assignment expressions. +lint.per-file-ignores."tests/cpydiff/syntax_assign_expr.py" = [ "F821" ] lint.mccabe.max-complexity = 40 + +[tool.codespell] +count = "" +ignore-regex = "\\b[A-Z]{3}\\b" +# CIRCUITPY-CHANGE: aranges +ignore-words-list = "ans,aranges,asend,deques,dout,emac,extint,hsi,iput,mis,notin,numer,ser,shft,synopsys,technic,ure,curren" +quiet-level = 3 +skip = """\ + */build*,./.git,./drivers/cc3100,./lib,./ports/cc3200/FreeRTOS,./ports/cc3200/bootmgr/sl,./ports/cc3200/hal,./ports/c\ + c3200/simplelink,./ports/cc3200/telnet,./ports/esp32/managed_components,./ports/nrf/drivers/bluetooth/s1*,./ports/pso\ + c-edge/boards/*/bsp-cfg,./ports/stm32/usbhost,./tests,ACKNOWLEDGEMENTS,\ + """ diff --git a/requirements-dev.txt b/requirements-dev.txt index 261a5cc2c7f..f66b804a43b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,8 +3,11 @@ cascadetoml jinja2 typer +# for generating mbedtls's PSA driver wrappers (jinja2, above, is also required) +jsonschema + sh -click +click<8.2.0 cpp-coveralls requests @@ -24,6 +27,7 @@ intelhex # for building & testing natmods pyelftools +ar cryptography @@ -40,3 +44,7 @@ setuptools # For zephyr port tomlkit +pytest +pytest-rerunfailures +pytest-xdist +perfetto diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 839b8b19add..da8537c931e 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -8,11 +8,16 @@ #include #include "py/objproperty.h" +#include "py/objstr.h" #include "py/runtime.h" #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Adapter.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + #define ADV_INTERVAL_MIN (0.02f) #define ADV_INTERVAL_MIN_STRING "0.02" #define ADV_INTERVAL_MAX (10.24f) @@ -134,8 +139,11 @@ MP_PROPERTY_GETSET(bleio_adapter_address_obj, //| name: str //| """name of the BLE adapter used once connected. -//| The name is "CIRCUITPY" + the last four hex digits of ``adapter.address``, -//| to make it easy to distinguish multiple CircuitPython boards.""" +//| The default name is "CIRCUITPY" plus the last four hex digits of +//| ``adapter.address``, to make it easy to distinguish multiple +//| CircuitPython boards. Set ``CIRCUITPY_BLE_NAME`` in settings.toml to +//| override it. The default is re-applied each time the adapter is +//| enabled.""" //| static mp_obj_t _bleio_adapter_get_name(mp_obj_t self) { return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_name(self)); @@ -153,6 +161,37 @@ MP_PROPERTY_GETSET(bleio_adapter_name_obj, (mp_obj_t)&bleio_adapter_get_name_obj, (mp_obj_t)&bleio_adapter_set_name_obj); +void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { + #if CIRCUITPY_SETTINGS_TOML + // Let the user override the default name from settings.toml. Use the + // allocation-free settings_get_str (not os.getenv), because ports call + // this from common_hal_bleio_adapter_set_enabled() which can run before + // the VM/gc heap is initialized. + char ble_name[32]; + settings_err_t result = settings_get_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); + if (result == SETTINGS_OK) { + common_hal_bleio_adapter_set_name(self, ble_name); + return; + } + #endif + + // Default to "CIRCUITPY" plus the last four hex digits of the adapter + // address so multiple boards are distinguishable. The address bytes are + // little-endian, so address[0] is the least-significant byte. If the port + // cannot provide an address, fall back to the literal "CIRCUITPYxxxx". + char default_ble_name[] = "CIRCUITPYxxxx"; + bleio_address_obj_t *address = common_hal_bleio_adapter_get_address(self); + if (address != NULL) { + uint8_t addr_bytes[NUM_BLEIO_ADDRESS_BYTES]; + common_hal_bleio_address_get_bytes(address, addr_bytes); + default_ble_name[ 9] = nibble_to_hex_lower[addr_bytes[1] >> 4 & 0xf]; + default_ble_name[10] = nibble_to_hex_lower[addr_bytes[1] & 0xf]; + default_ble_name[11] = nibble_to_hex_lower[addr_bytes[0] >> 4 & 0xf]; + default_ble_name[12] = nibble_to_hex_lower[addr_bytes[0] & 0xf]; + } + common_hal_bleio_adapter_set_name(self, default_ble_name); +} + //| def start_advertising( //| self, //| data: ReadableBuffer, @@ -215,7 +254,7 @@ static mp_obj_t bleio_adapter_start_advertising(mp_uint_t n_args, const mp_obj_t args[ARG_interval].u_obj = mp_obj_new_float(ADV_INTERVAL_DEFAULT); } - const mp_float_t interval = mp_obj_get_float(args[ARG_interval].u_obj); + const mp_float_t interval = mp_arg_validate_type_float(args[ARG_interval].u_obj, MP_QSTR_interval); if (interval < ADV_INTERVAL_MIN || interval > ADV_INTERVAL_MAX) { mp_raise_ValueError_varg(MP_ERROR_TEXT("interval must be in range %s-%s"), ADV_INTERVAL_MIN_STRING, ADV_INTERVAL_MAX_STRING); @@ -223,7 +262,7 @@ static mp_obj_t bleio_adapter_start_advertising(mp_uint_t n_args, const mp_obj_t bool connectable = args[ARG_connectable].u_bool; bool anonymous = args[ARG_anonymous].u_bool; - uint32_t timeout = args[ARG_timeout].u_int; + const uint32_t timeout = (uint32_t)mp_arg_validate_int_min(args[ARG_timeout].u_int, 0, MP_QSTR_timeout); if (data_bufinfo.len > 31 && connectable && scan_response_bufinfo.len > 0) { mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Cannot have scan responses for extended, connectable advertisements.")); } @@ -306,7 +345,7 @@ static mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args mp_float_t timeout = 0.0f; if (args[ARG_timeout].u_obj != mp_const_none) { - timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + timeout = mp_arg_validate_obj_float_non_negative(args[ARG_timeout].u_obj, 0.0f, MP_QSTR_timeout); } if (args[ARG_interval].u_obj == MP_OBJ_NULL) { @@ -317,7 +356,7 @@ static mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args args[ARG_window].u_obj = mp_obj_new_float(WINDOW_DEFAULT); } - const mp_float_t interval = mp_obj_get_float(args[ARG_interval].u_obj); + const mp_float_t interval = mp_arg_validate_type_float(args[ARG_interval].u_obj, MP_QSTR_interval); if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { mp_raise_ValueError_varg(MP_ERROR_TEXT("interval must be in range %s-%s"), INTERVAL_MIN_STRING, INTERVAL_MAX_STRING); } @@ -329,7 +368,7 @@ static mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args } #pragma GCC diagnostic pop - const mp_float_t window = mp_obj_get_float(args[ARG_window].u_obj); + const mp_float_t window = mp_arg_validate_type_float(args[ARG_window].u_obj, MP_QSTR_window); if (window > interval) { mp_raise_ValueError(MP_ERROR_TEXT("window must be <= interval")); } @@ -344,7 +383,9 @@ static mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args } } - return common_hal_bleio_adapter_start_scan(self, prefix_bufinfo.buf, prefix_bufinfo.len, args[ARG_extended].u_bool, args[ARG_buffer_size].u_int, timeout, interval, window, args[ARG_minimum_rssi].u_int, args[ARG_active].u_bool); + const mp_int_t buffer_size = mp_arg_validate_int_min(args[ARG_buffer_size].u_int, 1, MP_QSTR_buffer_size); + + return common_hal_bleio_adapter_start_scan(self, prefix_bufinfo.buf, prefix_bufinfo.len, args[ARG_extended].u_bool, buffer_size, timeout, interval, window, args[ARG_minimum_rssi].u_int, args[ARG_active].u_bool); } static MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_start_scan_obj, 1, bleio_adapter_start_scan); @@ -416,7 +457,8 @@ static mp_obj_t bleio_adapter_connect(mp_uint_t n_args, const mp_obj_t *pos_args mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); bleio_address_obj_t *address = mp_arg_validate_type(args[ARG_address].u_obj, &bleio_address_type, MP_QSTR_address); - mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + const mp_float_t timeout = + mp_arg_validate_obj_float_non_negative(args[ARG_timeout].u_obj, 0.0f, MP_QSTR_timeout); return common_hal_bleio_adapter_connect(self, address, timeout); } diff --git a/shared-bindings/_bleio/Adapter.h b/shared-bindings/_bleio/Adapter.h index 0bc6f051ff3..1035461d35a 100644 --- a/shared-bindings/_bleio/Adapter.h +++ b/shared-bindings/_bleio/Adapter.h @@ -35,6 +35,13 @@ uint16_t bleio_adapter_get_name(char *buf, uint16_t len); extern mp_obj_str_t *common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self); extern void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char *name); +// Resets the adapter's device name to the default: the CIRCUITPY_BLE_NAME setting value if +// set, otherwise "CIRCUITPY" plus the last four hex digits of the adapter's address (read via +// common_hal_bleio_adapter_get_address). Every port calls this from its +// common_hal_bleio_adapter_set_enabled once the controller is ready, so the default name is +// derived the same way everywhere. +void bleio_adapter_reset_name(bleio_adapter_obj_t *self); + // Returns 0 if ok, otherwise a BLE stack specific error code. extern uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, float interval, diff --git a/shared-bindings/_bleio/Address.c b/shared-bindings/_bleio/Address.c index 58f8a8adc1e..ac5c47bec8a 100644 --- a/shared-bindings/_bleio/Address.c +++ b/shared-bindings/_bleio/Address.c @@ -37,20 +37,18 @@ static mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_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); - bleio_address_obj_t *self = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - const mp_obj_t address = args[ARG_address].u_obj; mp_buffer_info_t buf_info; mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ); - if (buf_info.len != NUM_BLEIO_ADDRESS_BYTES) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("Address must be %d bytes long"), NUM_BLEIO_ADDRESS_BYTES); - } + mp_arg_validate_length(buf_info.len, NUM_BLEIO_ADDRESS_BYTES, MP_QSTR_address); - const mp_int_t address_type = args[ARG_address_type].u_int; - if (address_type < BLEIO_ADDRESS_TYPE_MIN || address_type > BLEIO_ADDRESS_TYPE_MAX) { - mp_arg_error_invalid(MP_QSTR_address_type); - } + const mp_int_t address_type = + mp_arg_validate_int_range(args[ARG_address_type].u_int, + BLEIO_ADDRESS_TYPE_MIN, + BLEIO_ADDRESS_TYPE_MAX, + MP_QSTR_address_type); + bleio_address_obj_t *self = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); common_hal_bleio_address_construct(self, buf_info.buf, address_type); return MP_OBJ_FROM_PTR(self); @@ -110,10 +108,8 @@ static mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_o bleio_address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); bleio_address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); return mp_obj_new_bool( - mp_obj_equal(common_hal_bleio_address_get_address_bytes(lhs), - common_hal_bleio_address_get_address_bytes(rhs)) && - common_hal_bleio_address_get_type(lhs) == - common_hal_bleio_address_get_type(rhs)); + lhs->type == rhs->type && + memcmp(lhs->bytes, rhs->bytes, NUM_BLEIO_ADDRESS_BYTES) == 0); } else { return mp_const_false; @@ -132,13 +128,9 @@ static mp_obj_t bleio_address_unary_op(mp_unary_op_t op, mp_obj_t self_in) { switch (op) { // Two Addresses are equal if their address bytes and address_type are equal case MP_UNARY_OP_HASH: { - mp_obj_t bytes = common_hal_bleio_address_get_address_bytes(MP_OBJ_TO_PTR(self_in)); - GET_STR_HASH(bytes, h); - if (h == 0) { - GET_STR_DATA_LEN(bytes, data, len); - h = qstr_compute_hash(data, len); - } - h ^= common_hal_bleio_address_get_type(MP_OBJ_TO_PTR(self_in)); + bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t h = (mp_int_t)qstr_compute_hash(self->bytes, NUM_BLEIO_ADDRESS_BYTES); + h ^= self->type; return MP_OBJ_NEW_SMALL_INT(h); } default: @@ -148,11 +140,7 @@ static mp_obj_t bleio_address_unary_op(mp_unary_op_t op, mp_obj_t self_in) { static void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t buf_info; - mp_obj_t address_bytes = common_hal_bleio_address_get_address_bytes(self); - mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ); - - const uint8_t *buf = (uint8_t *)buf_info.buf; + const uint8_t *buf = self->bytes; mp_printf(print, "
", buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); } diff --git a/shared-bindings/_bleio/Address.h b/shared-bindings/_bleio/Address.h index c869ccf55cb..a61f28c0369 100644 --- a/shared-bindings/_bleio/Address.h +++ b/shared-bindings/_bleio/Address.h @@ -20,6 +20,10 @@ extern const mp_obj_type_t bleio_address_type; -extern void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type); +extern void common_hal_bleio_address_construct(bleio_address_obj_t *self, const uint8_t *bytes, uint8_t address_type); extern mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self); extern uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self); +// Copies the raw address bytes (little-endian BD_ADDR, NUM_BLEIO_ADDRESS_BYTES) +// into the given buffer. Allocation-free, so it is safe to use before the heap +// is initialized (e.g. when deriving the default adapter name). +extern void common_hal_bleio_address_get_bytes(bleio_address_obj_t *self, uint8_t bytes[NUM_BLEIO_ADDRESS_BYTES]); diff --git a/shared-bindings/_bleio/Attribute.h b/shared-bindings/_bleio/Attribute.h index 51278dc0157..60a941a5772 100644 --- a/shared-bindings/_bleio/Attribute.h +++ b/shared-bindings/_bleio/Attribute.h @@ -14,3 +14,7 @@ extern const mp_obj_type_t bleio_attribute_type; extern void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode); + +// True for the security modes that demand a man-in-the-middle-protected (authenticated) +// link: pairing must use numeric comparison or passkey entry, not "Just Works". +extern bool bleio_attribute_security_mode_requires_mitm(bleio_attribute_security_mode_t security_mode); diff --git a/shared-bindings/_bleio/Characteristic.c b/shared-bindings/_bleio/Characteristic.c index 8d6ac43e487..0ed4c2b7eaa 100644 --- a/shared-bindings/_bleio/Characteristic.c +++ b/shared-bindings/_bleio/Characteristic.c @@ -116,9 +116,10 @@ static mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_ } mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); - if (initial_value_bufinfo.len > max_length || - (fixed_length && initial_value_bufinfo.len != max_length)) { - mp_raise_ValueError(MP_ERROR_TEXT("initial_value length is wrong")); + if (fixed_length) { + mp_arg_validate_length(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); + } else { + mp_arg_validate_length_max(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); } const char *user_description = NULL; diff --git a/shared-bindings/_bleio/CharacteristicBuffer.c b/shared-bindings/_bleio/CharacteristicBuffer.c index 5ffff0dcba7..07394256933 100644 --- a/shared-bindings/_bleio/CharacteristicBuffer.c +++ b/shared-bindings/_bleio/CharacteristicBuffer.c @@ -118,7 +118,7 @@ static mp_uint_t bleio_characteristic_buffer_write(mp_obj_t self_in, const void return 0; } -static mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); raise_error_if_not_connected(self); diff --git a/shared-bindings/_bleio/Connection.c b/shared-bindings/_bleio/Connection.c index 4a81d753433..275fa0d435d 100644 --- a/shared-bindings/_bleio/Connection.c +++ b/shared-bindings/_bleio/Connection.c @@ -165,6 +165,78 @@ MP_PROPERTY_GETTER(bleio_connection_paired_obj, (mp_obj_t)&bleio_connection_get_paired_obj); +//| authenticated: bool +//| """True if the link is encrypted *and* authenticated against +//| man-in-the-middle attacks - i.e. LE Secure Connections numeric comparison (or +//| passkey entry) completed. A plain encrypted-but-unauthenticated ("Just Works") +//| link reads ``False``. +//| +//| Ports that don't implement authenticated pairing always report ``False``, +//| even for a bonded link.""" +static mp_obj_t bleio_connection_get_authenticated(mp_obj_t self_in) { + bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_bleio_connection_get_authenticated(self)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_get_authenticated_obj, bleio_connection_get_authenticated); + +MP_PROPERTY_GETTER(bleio_connection_authenticated_obj, + (mp_obj_t)&bleio_connection_get_authenticated_obj); + + +//| numeric_comparison: Optional[int] +//| """When the peer has started LE Secure Connections pairing and is waiting for the +//| user to confirm a 6-digit numeric-comparison value, this is that value (an ``int``, +//| 0-999999); otherwise ``None``. Poll it, show the value to the user, then answer +//| with `confirm_pairing`. This is the peripheral side of pairing: the peer drives +//| the procedure, so unlike `pair` this never blocks. +//| +//| Numeric comparison happens automatically when a central pairs to reach a +//| characteristic whose ``read_perm`` / ``write_perm`` is +//| `Attribute.LESC_ENCRYPT_WITH_MITM`. A peripheral with a display and a button +//| services it roughly like this:: +//| +//| while connection.connected: +//| code = connection.numeric_comparison +//| if code is not None: +//| display.show(f"Pair? {code:06d}") +//| connection.confirm_pairing(accept=button_a.value) +//| if connection.authenticated: +//| break +//| time.sleep(0.1) +//| +//| Only implemented on the espressif port.""" +static mp_obj_t bleio_connection_get_numeric_comparison(mp_obj_t self_in) { + bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_bleio_connection_get_numeric_comparison(self); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_get_numeric_comparison_obj, bleio_connection_get_numeric_comparison); + +MP_PROPERTY_GETTER(bleio_connection_numeric_comparison_obj, + (mp_obj_t)&bleio_connection_get_numeric_comparison_obj); + + +//| def confirm_pairing(self, accept: bool) -> None: +//| """Answer a pending numeric-comparison pairing request (see +//| `numeric_comparison`). Pass ``accept=True`` if the value shown on the +//| peer matches the one shown here, ``accept=False`` to reject and abort pairing. +//| +//| :raises ConnectionError: if the connection has dropped. +//| :raises _bleio.BluetoothError: if no numeric-comparison request is pending - +//| nothing was offered on `numeric_comparison`, or it already expired +//| because the peer disconnected or the pairing procedure timed out.""" +//| ... +//| +static mp_obj_t bleio_connection_confirm_pairing(mp_obj_t self_in, mp_obj_t accept_in) { + bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_connection_confirm_pairing(self, mp_obj_is_true(accept_in)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(bleio_connection_confirm_pairing_obj, bleio_connection_confirm_pairing); + + //| connection_interval: float //| """Time between transmissions in milliseconds. Will be multiple of 1.25ms. Lower numbers //| increase speed and decrease latency but increase power consumption. @@ -223,12 +295,15 @@ MP_PROPERTY_GETTER(bleio_connection_max_packet_length_obj, static const mp_rom_map_elem_t bleio_connection_locals_dict_table[] = { // Methods { MP_ROM_QSTR(MP_QSTR_pair), MP_ROM_PTR(&bleio_connection_pair_obj) }, + { MP_ROM_QSTR(MP_QSTR_confirm_pairing), MP_ROM_PTR(&bleio_connection_confirm_pairing_obj) }, { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_connection_disconnect_obj) }, { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_connection_discover_remote_services_obj) }, // Properties { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_connection_connected_obj) }, { MP_ROM_QSTR(MP_QSTR_paired), MP_ROM_PTR(&bleio_connection_paired_obj) }, + { MP_ROM_QSTR(MP_QSTR_authenticated), MP_ROM_PTR(&bleio_connection_authenticated_obj) }, + { MP_ROM_QSTR(MP_QSTR_numeric_comparison), MP_ROM_PTR(&bleio_connection_numeric_comparison_obj) }, { MP_ROM_QSTR(MP_QSTR_connection_interval), MP_ROM_PTR(&bleio_connection_connection_interval_obj) }, { MP_ROM_QSTR(MP_QSTR_max_packet_length), MP_ROM_PTR(&bleio_connection_max_packet_length_obj) }, }; diff --git a/shared-bindings/_bleio/Connection.h b/shared-bindings/_bleio/Connection.h index 4be4992fb2f..fbc856c7d45 100644 --- a/shared-bindings/_bleio/Connection.h +++ b/shared-bindings/_bleio/Connection.h @@ -18,6 +18,9 @@ void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self); bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self); mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_internal_t *self); bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self); +bool common_hal_bleio_connection_get_authenticated(bleio_connection_obj_t *self); +mp_obj_t common_hal_bleio_connection_get_numeric_comparison(bleio_connection_obj_t *self); +void common_hal_bleio_connection_confirm_pairing(bleio_connection_obj_t *self, bool accept); mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist); mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self); diff --git a/shared-bindings/_bleio/Descriptor.c b/shared-bindings/_bleio/Descriptor.c index 57cc605029f..9e29f57d8dd 100644 --- a/shared-bindings/_bleio/Descriptor.c +++ b/shared-bindings/_bleio/Descriptor.c @@ -99,9 +99,10 @@ static mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_o } } mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); - if (initial_value_bufinfo.len > max_length || - (fixed_length && initial_value_bufinfo.len != max_length)) { - mp_raise_ValueError(MP_ERROR_TEXT("initial_value length is wrong")); + if (fixed_length) { + mp_arg_validate_length(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); + } else { + mp_arg_validate_length_max(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); } bleio_descriptor_obj_t *descriptor = mp_obj_malloc(bleio_descriptor_obj_t, &bleio_descriptor_type); diff --git a/shared-bindings/_bleio/PacketBuffer.c b/shared-bindings/_bleio/PacketBuffer.c index 47d71ebd55a..aa1e6e8645a 100644 --- a/shared-bindings/_bleio/PacketBuffer.c +++ b/shared-bindings/_bleio/PacketBuffer.c @@ -57,7 +57,10 @@ static mp_obj_t bleio_packet_buffer_make_new(const mp_obj_type_t *type, size_t n size_t max_packet_size = common_hal_bleio_characteristic_get_max_length(characteristic); if (args[ARG_max_packet_size].u_obj != mp_const_none) { - max_packet_size = mp_obj_get_int(args[ARG_max_packet_size].u_obj); + const mp_int_t max_packet_size_int = + mp_arg_validate_type_int(args[ARG_max_packet_size].u_obj, MP_QSTR_max_packet_size); + max_packet_size = + (size_t)mp_arg_validate_int_min(max_packet_size_int, 1, MP_QSTR_max_packet_size); } bleio_packet_buffer_obj_t *self = mp_obj_malloc(bleio_packet_buffer_obj_t, &bleio_packet_buffer_type); diff --git a/shared-bindings/_bleio/PacketBuffer.h b/shared-bindings/_bleio/PacketBuffer.h index 1a872512da2..24fb24bce78 100644 --- a/shared-bindings/_bleio/PacketBuffer.h +++ b/shared-bindings/_bleio/PacketBuffer.h @@ -6,6 +6,7 @@ #pragma once +#include "shared-bindings/_bleio/Characteristic.h" #include "common-hal/_bleio/PacketBuffer.h" extern const mp_obj_type_t bleio_packet_buffer_type; @@ -21,13 +22,11 @@ void common_hal_bleio_packet_buffer_construct( bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, size_t buffer_size, size_t max_packet_size); // Allocation free version for BLE workflow use. -#if CIRCUITPY_SERIAL_BLE || CIRCUITPY_BLE_FILE_SERVICE void _common_hal_bleio_packet_buffer_construct( bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, uint32_t *incoming_buffer, size_t incoming_buffer_size, - uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t outgoing_buffer_size, + uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, ble_event_handler_t *static_handler_entry); -#endif mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, const uint8_t *data, size_t len, uint8_t *header, size_t header_len); mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len); mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self); diff --git a/shared-bindings/_bleio/Service.c b/shared-bindings/_bleio/Service.c index cea9a68e694..920d66a3de2 100644 --- a/shared-bindings/_bleio/Service.c +++ b/shared-bindings/_bleio/Service.c @@ -8,6 +8,7 @@ #include "py/objproperty.h" #include "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Service.h" #include "shared-bindings/_bleio/UUID.h" @@ -45,6 +46,9 @@ static mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, bleio_service_obj_t *service = mp_obj_malloc_with_finaliser(bleio_service_obj_t, &bleio_service_type); common_hal_bleio_service_construct(service, uuid, is_secondary); + // Remember that there are services that were created by the user. + // bleio_reset() needs this to know what kind of reset to do. + bleio_set_user_services_created(); return MP_OBJ_FROM_PTR(service); } diff --git a/shared-bindings/_bleio/UUID.c b/shared-bindings/_bleio/UUID.c index 2d28d5a9b61..eef8546e253 100644 --- a/shared-bindings/_bleio/UUID.c +++ b/shared-bindings/_bleio/UUID.c @@ -34,20 +34,18 @@ static mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); - bleio_uuid_obj_t *self = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); - const mp_obj_t value = all_args[0]; uint8_t uuid128[16]; if (mp_obj_is_int(value)) { - mp_int_t uuid16 = mp_obj_get_int(value); - if (uuid16 < 0 || uuid16 > 0xffff) { - mp_raise_ValueError(MP_ERROR_TEXT("UUID integer value must be 0-0xffff")); - } + const mp_int_t uuid16 = + mp_arg_validate_int_range(mp_obj_get_int(value), 0, 0xffff, MP_QSTR_value); // NULL means no 128-bit value. + bleio_uuid_obj_t *self = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); common_hal_bleio_uuid_construct(self, uuid16, NULL); + return MP_OBJ_FROM_PTR(self); } else { if (mp_obj_is_str(value)) { // 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' @@ -82,9 +80,7 @@ static mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, si mp_raise_ValueError(MP_ERROR_TEXT("UUID value is not str, int or byte buffer")); } - if (bufinfo.len != 16) { - mp_raise_ValueError(MP_ERROR_TEXT("Byte buffer must be 16 bytes.")); - } + mp_arg_validate_length(bufinfo.len, 16, MP_QSTR_value); memcpy(uuid128, bufinfo.buf, 16); } @@ -93,10 +89,12 @@ static mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, si uint32_t uuid16 = (uuid128[13] << 8) | uuid128[12]; uuid128[12] = 0; uuid128[13] = 0; + + bleio_uuid_obj_t *self = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); common_hal_bleio_uuid_construct(self, uuid16, uuid128); - } - return MP_OBJ_FROM_PTR(self); + return MP_OBJ_FROM_PTR(self); + } } //| uuid16: int @@ -171,12 +169,12 @@ static mp_obj_t bleio_uuid_pack_into(mp_uint_t n_args, const mp_obj_t *pos_args, mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); - size_t offset = args[ARG_offset].u_int; - if (offset + common_hal_bleio_uuid_get_size(self) / 8 > bufinfo.len) { - mp_raise_ValueError(MP_ERROR_TEXT("Buffer + offset too small %d %d %d")); - } + const mp_int_t offset = + mp_arg_validate_int_range(args[ARG_offset].u_int, 0, (mp_int_t)bufinfo.len, MP_QSTR_offset); + const size_t packed_len = common_hal_bleio_uuid_get_size(self) / 8; + mp_arg_validate_length_min(bufinfo.len - (size_t)offset, packed_len, MP_QSTR_buffer); - common_hal_bleio_uuid_pack_into(self, bufinfo.buf + offset); + common_hal_bleio_uuid_pack_into(self, (uint8_t *)bufinfo.buf + (size_t)offset); return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_KW(bleio_uuid_pack_into_obj, 1, bleio_uuid_pack_into); diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c index 3bf8c1a2c9c..202542c3d05 100644 --- a/shared-bindings/_bleio/__init__.c +++ b/shared-bindings/_bleio/__init__.c @@ -56,7 +56,7 @@ //| //| MP_DEFINE_BLEIO_EXCEPTION(BluetoothError, Exception) -NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t fmt, ...) { +MP_NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_bleio_BluetoothError, fmt, argptr); @@ -72,7 +72,7 @@ NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t fmt, ...) { //| //| MP_DEFINE_BLEIO_EXCEPTION(RoleError, bleio_BluetoothError) -NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg) { +MP_NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_bleio_RoleError, msg); } @@ -83,7 +83,7 @@ NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg) { //| //| MP_DEFINE_BLEIO_EXCEPTION(SecurityError, bleio_BluetoothError) -NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t fmt, ...) { +MP_NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_bleio_SecurityError, fmt, argptr); @@ -91,6 +91,20 @@ NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t fmt, ...) { nlr_raise(exception); } +static bool _user_services_created; + +bool bleio_get_user_services_created(void) { + return _user_services_created; +} + +void bleio_set_user_services_created(void) { + _user_services_created = true; +} + +void bleio_clear_user_services_created(void) { + _user_services_created = false; +} + // Called when _bleio is imported. static mp_obj_t bleio___init__(void) { // HCI cannot be enabled on import, because we need to setup the HCI adapter first. diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h index faf11ea1d06..0e8a9212e6b 100644 --- a/shared-bindings/_bleio/__init__.h +++ b/shared-bindings/_bleio/__init__.h @@ -39,25 +39,31 @@ void bleio_user_reset(void); // Completely resets the BLE stack including BLE connections. void bleio_reset(void); +// True if user code created a local GATT service during this VM run. Set by the +// shared-bindings Service constructor; the supervisor constructs its BLE workflow +// services through common-hal directly and does not set it. User-created services +// can only be removed from the stack's GATT table by a full stack reset, so a +// port's bleio_reset() uses this to decide whether that reset, which drops all +// connections, is needed at all. +bool bleio_get_user_services_created(void); + +// Record that user code created a local GATT service. +void bleio_set_user_services_created(void); + +// Clear the flag reported by bleio_get_user_services_created(). Call after a full +// stack reset, so the next VM run starts out clean. +void bleio_clear_user_services_created(void); + // Init any state needed before calling any bleio functions including those // having to do with bonding. This doesn't enable the BLE adapter though. void common_hal_bleio_init(void); extern mp_obj_t bleio_set_adapter(mp_obj_t adapter_obj); -NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t msg, ...); -NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg); -NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t msg, ...); +MP_NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t msg, ...); +MP_NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t msg, ...); bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void); -void common_hal_bleio_check_connected(uint16_t conn_handle); - -uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); -void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); - -size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); -void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); -size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); -void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); void common_hal_bleio_gc_collect(void); diff --git a/shared-bindings/_stage/Layer.c b/shared-bindings/_stage/Layer.c index de4861a70ee..0d7a1bfbd5e 100644 --- a/shared-bindings/_stage/Layer.c +++ b/shared-bindings/_stage/Layer.c @@ -38,38 +38,38 @@ static mp_obj_t layer_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, 4, 5, false); - layer_obj_t *self = mp_obj_malloc(layer_obj_t, type); - - self->width = mp_obj_get_int(args[0]); - self->height = mp_obj_get_int(args[1]); - self->x = 0; - self->y = 0; - self->frame = 0; - self->rotation = false; + mp_uint_t width = mp_arg_validate_int_min(mp_obj_get_int(args[0]), 0, MP_QSTR_width); + mp_uint_t height = mp_arg_validate_int_min(mp_obj_get_int(args[1]), 0, MP_QSTR_height); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); - self->graphic = bufinfo.buf; - if (bufinfo.len != 2048) { - mp_raise_ValueError(MP_ERROR_TEXT("graphic must be 2048 bytes long")); - } + mp_buffer_info_t graphic_bufinfo; + mp_get_buffer_raise(args[2], &graphic_bufinfo, MP_BUFFER_READ); + mp_arg_validate_length(graphic_bufinfo.len, 2048, MP_QSTR_graphic); - mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); - self->palette = bufinfo.buf; - if (bufinfo.len != 32) { - mp_raise_ValueError(MP_ERROR_TEXT("palette must be 32 bytes long")); - } + mp_buffer_info_t palette_bufinfo; + mp_get_buffer_raise(args[3], &palette_bufinfo, MP_BUFFER_READ); + mp_arg_validate_length(palette_bufinfo.len, 32, MP_QSTR_palette); + mp_buffer_info_t map_bufinfo = { .buf = NULL }; if (n_args > 4) { - mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ); - self->map = bufinfo.buf; - if (bufinfo.len < (self->width * self->height) / 2) { + mp_get_buffer_raise(args[4], &map_bufinfo, MP_BUFFER_READ); + if (map_bufinfo.len < (width * height) / 2) { mp_raise_ValueError(MP_ERROR_TEXT("map buffer too small")); } - } else { - self->map = NULL; } + // Only allocate after validation is finished. + layer_obj_t *self = mp_obj_malloc(layer_obj_t, type); + + self->width = width; + self->height = height; + self->x = 0; + self->y = 0; + self->frame = 0; + self->rotation = false; + self->graphic = graphic_bufinfo.buf; + self->palette = palette_bufinfo.buf; + self->map = map_bufinfo.buf; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/_stage/Text.c b/shared-bindings/_stage/Text.c index ecd4f644a78..0013ffb6697 100644 --- a/shared-bindings/_stage/Text.c +++ b/shared-bindings/_stage/Text.c @@ -38,32 +38,32 @@ static mp_obj_t text_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, 5, 5, false); - text_obj_t *self = mp_obj_malloc(text_obj_t, type); + mp_uint_t width = mp_arg_validate_int_min(mp_obj_get_int(args[0]), 0, MP_QSTR_width); + mp_uint_t height = mp_arg_validate_int_min(mp_obj_get_int(args[1]), 0, MP_QSTR_height); - self->width = mp_obj_get_int(args[0]); - self->height = mp_obj_get_int(args[1]); - self->x = 0; - self->y = 0; - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); - self->font = bufinfo.buf; - if (bufinfo.len != 2048) { - mp_raise_ValueError(MP_ERROR_TEXT("font must be 2048 bytes long")); - } + mp_buffer_info_t font_bufinfo; + mp_get_buffer_raise(args[2], &font_bufinfo, MP_BUFFER_READ); + mp_arg_validate_length(font_bufinfo.len, 2048, MP_QSTR_font); - mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); - self->palette = bufinfo.buf; - if (bufinfo.len != 32) { - mp_raise_ValueError(MP_ERROR_TEXT("palette must be 32 bytes long")); - } + mp_buffer_info_t palette_bufinfo; + mp_get_buffer_raise(args[3], &palette_bufinfo, MP_BUFFER_READ); + mp_arg_validate_length(palette_bufinfo.len, 32, MP_QSTR_palette); - mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ); - self->chars = bufinfo.buf; - if (bufinfo.len < self->width * self->height) { + mp_buffer_info_t chars_bufinfo; + mp_get_buffer_raise(args[4], &chars_bufinfo, MP_BUFFER_READ); + if (chars_bufinfo.len < width * height) { mp_raise_ValueError(MP_ERROR_TEXT("chars buffer too small")); } + text_obj_t *self = mp_obj_malloc(text_obj_t, type); + self->width = width; + self->height = height; + self->x = 0; + self->y = 0; + self->font = font_bufinfo.buf; + self->palette = palette_bufinfo.buf; + self->chars = chars_bufinfo.buf; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c b/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c index 32d418923fb..5fb821ceade 100644 --- a/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c +++ b/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c @@ -47,8 +47,6 @@ //| ... //| static mp_obj_t adafruit_bus_device_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - adafruit_bus_device_i2cdevice_obj_t *self = - mp_obj_malloc(adafruit_bus_device_i2cdevice_obj_t, &adafruit_bus_device_i2cdevice_type); enum { ARG_i2c, ARG_device_address, ARG_probe }; static const mp_arg_t allowed_args[] = { { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -60,12 +58,14 @@ static mp_obj_t adafruit_bus_device_i2cdevice_make_new(const mp_obj_type_t *type mp_obj_t *i2c = args[ARG_i2c].u_obj; + adafruit_bus_device_i2cdevice_obj_t *self = + mp_obj_malloc(adafruit_bus_device_i2cdevice_obj_t, &adafruit_bus_device_i2cdevice_type); common_hal_adafruit_bus_device_i2cdevice_construct(MP_OBJ_TO_PTR(self), i2c, args[ARG_device_address].u_int); if (args[ARG_probe].u_bool == true) { common_hal_adafruit_bus_device_i2cdevice_probe_for_device(self); } - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); } //| def __enter__(self) -> I2CDevice: diff --git a/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c b/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c index f62aedc47e3..2f4895e38ce 100644 --- a/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +++ b/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c @@ -59,8 +59,6 @@ //| ... //| static mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - adafruit_bus_device_spidevice_obj_t *self = - mp_obj_malloc(adafruit_bus_device_spidevice_obj_t, &adafruit_bus_device_spidevice_type); enum { ARG_spi, ARG_chip_select, ARG_cs_active_value, ARG_baudrate, ARG_polarity, ARG_phase, ARG_extra_clocks }; static const mp_arg_t allowed_args[] = { { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -78,12 +76,11 @@ static mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type mp_arg_validate_type_or_none(args[ARG_chip_select].u_obj, &digitalio_digitalinout_type, MP_QSTR_chip_select); - common_hal_adafruit_bus_device_spidevice_construct(MP_OBJ_TO_PTR(self), spi, args[ARG_chip_select].u_obj, args[ARG_cs_active_value].u_bool, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, - args[ARG_phase].u_int, args[ARG_extra_clocks].u_int); - if (args[ARG_chip_select].u_obj != mp_const_none) { - digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj), - true, DRIVE_MODE_PUSH_PULL); + digitalinout_result_t result = + common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj), + true, + DRIVE_MODE_PUSH_PULL); #if CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY if (result == DIGITALINOUT_INPUT_ONLY) { mp_raise_NotImplementedError(MP_ERROR_TEXT("Pin is input only")); @@ -93,7 +90,19 @@ static mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type #endif } - return (mp_obj_t)self; + adafruit_bus_device_spidevice_obj_t *self = + mp_obj_malloc(adafruit_bus_device_spidevice_obj_t, &adafruit_bus_device_spidevice_type); + common_hal_adafruit_bus_device_spidevice_construct(MP_OBJ_TO_PTR(self), + spi, + args[ARG_chip_select].u_obj, + args[ARG_cs_active_value].u_bool, + args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, + args[ARG_phase].u_int, + args[ARG_extra_clocks].u_int); + + + return MP_OBJ_FROM_PTR(self); } //| def __enter__(self) -> busio.SPI: diff --git a/shared-bindings/adafruit_pixelbuf/PixelBuf.c b/shared-bindings/adafruit_pixelbuf/PixelBuf.c index cdffbfa627a..4144f086b98 100644 --- a/shared-bindings/adafruit_pixelbuf/PixelBuf.c +++ b/shared-bindings/adafruit_pixelbuf/PixelBuf.c @@ -24,7 +24,7 @@ #include "extmod/ulab/code/ndarray.h" #endif -static NORETURN void invalid_byteorder(void) { +static MP_NORETURN void invalid_byteorder(void) { mp_arg_error_invalid(MP_QSTR_byteorder); } diff --git a/shared-bindings/aesio/aes.c b/shared-bindings/aesio/aes.c index a6916042fda..eeb685a6652 100644 --- a/shared-bindings/aesio/aes.c +++ b/shared-bindings/aesio/aes.c @@ -55,8 +55,6 @@ static mp_obj_t aesio_aes_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - aesio_aes_obj_t *self = mp_obj_malloc(aesio_aes_obj_t, &aesio_aes_type); - enum { ARG_key, ARG_mode, ARG_IV, ARG_counter, ARG_segment_size }; static const mp_arg_t allowed_args[] = { {MP_QSTR_key, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, @@ -100,8 +98,14 @@ static mp_obj_t aesio_aes_make_new(const mp_obj_type_t *type, size_t n_args, iv = bufinfo.buf; } - common_hal_aesio_aes_construct(self, key, key_length, iv, mode, - args[ARG_counter].u_int); + int counter = 0; + if (args[ARG_counter].u_obj != MP_OBJ_NULL) { + counter = mp_obj_get_int_truncated(args[ARG_counter].u_obj); + } + + aesio_aes_obj_t *self = mp_obj_malloc(aesio_aes_obj_t, &aesio_aes_type); + common_hal_aesio_aes_construct(self, key, key_length, iv, mode, counter); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/alarm/SleepMemory.c b/shared-bindings/alarm/SleepMemory.c index e6d65de4555..383c2a4e613 100644 --- a/shared-bindings/alarm/SleepMemory.c +++ b/shared-bindings/alarm/SleepMemory.c @@ -12,9 +12,11 @@ #include "shared-bindings/alarm/SleepMemory.h" //| class SleepMemory: -//| """Store raw bytes in RAM that persists during deep sleep. +//| """Store raw bytes in RAM that persists across deep sleep and software resets. //| The class acts as a ``bytearray``. -//| If power is lost, the memory contents are lost. +//| Contents are preserved across ``microcontroller.reset()``, watchdog resets, +//| and deep sleep wake. Contents are lost when power is removed and restored, +//| or on brown-out reset. //| //| Note that this class can't be imported and used directly. The sole //| instance of :class:`SleepMemory` is available at diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index e9f2db324d5..ff3aa2f02f6 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -122,6 +122,9 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OB //| //| If no alarms are specified, the microcontroller will deep sleep until reset. //| +//| You cannot initiate a deep sleep from the REPL. +//| You must call `exit_and_deep_sleep_until_alarms()` from a program file. +//| //| :param circuitpython_typing.Alarm alarms: the alarms that can wake the microcontroller. //| :param Sequence[digitalio.DigitalInOut] preserve_dios: A sequence of `DigitalInOut` objects //| whose state should be preserved during deep sleep. @@ -134,6 +137,8 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OB //| //| Preserving `DigitalInOut` states during deep sleep can be used to ensure that //| external or on-board devices are powered or unpowered during sleep, among other purposes. +//| Once the board wakes up from deep sleep, the `DigitalInOut` states are no longer preserved +//| and must be restored by your code. //| //| On some microcontrollers, some pins cannot remain in their original state for hardware reasons. //| @@ -190,6 +195,11 @@ static mp_obj_t alarm_exit_and_deep_sleep_until_alarms(size_t n_args, const mp_o mp_obj_t preserve_dios = args[ARG_preserve_dios].u_obj; const size_t num_dios = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(preserve_dios)); + #if !CIRCUITPY_ALARM_PRESERVE_DIOS + if (num_dios > 0) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); + } + #endif digitalio_digitalinout_obj_t *dios_array[num_dios]; for (mp_uint_t i = 0; i < num_dios; i++) { diff --git a/shared-bindings/alarm/__init__.h b/shared-bindings/alarm/__init__.h index af92b381137..5b8823162cc 100644 --- a/shared-bindings/alarm/__init__.h +++ b/shared-bindings/alarm/__init__.h @@ -24,7 +24,14 @@ extern mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const // it will exit idle as if deep sleep was exited extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios); -extern NORETURN void common_hal_alarm_enter_deep_sleep(void); +extern MP_NORETURN void common_hal_alarm_enter_deep_sleep(void); + +#if CIRCUITPY_ALARM_PRESERVE_DIOS +// Clear any pin preservations set up for deep sleep (real or fake), releasing +// held pins so they can be reset. Only declared on ports that implement +// `preserve_dios`. +extern void common_hal_alarm_clear_pin_preservations(void); +#endif // May be used to re-initialize peripherals like GPIO, if the VM reset returned // them to a default state diff --git a/shared-bindings/alarm/pin/PinAlarm.c b/shared-bindings/alarm/pin/PinAlarm.c index 8d93ca8d0de..4633fdb233c 100644 --- a/shared-bindings/alarm/pin/PinAlarm.c +++ b/shared-bindings/alarm/pin/PinAlarm.c @@ -42,7 +42,6 @@ //| ... //| static mp_obj_t alarm_pin_pinalarm_make_new(const mp_obj_type_t *type, mp_uint_t n_args, size_t n_kw, const mp_obj_t *all_args) { - alarm_pin_pinalarm_obj_t *self = mp_obj_malloc(alarm_pin_pinalarm_obj_t, &alarm_pin_pinalarm_type); enum { ARG_pin, ARG_value, ARG_edge, ARG_pull }; static const mp_arg_t allowed_args[] = { { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -55,6 +54,7 @@ static mp_obj_t alarm_pin_pinalarm_make_new(const mp_obj_type_t *type, mp_uint_t const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); + alarm_pin_pinalarm_obj_t *self = mp_obj_malloc(alarm_pin_pinalarm_obj_t, &alarm_pin_pinalarm_type); common_hal_alarm_pin_pinalarm_construct(self, pin, args[ARG_value].u_bool, diff --git a/shared-bindings/alarm/time/TimeAlarm.c b/shared-bindings/alarm/time/TimeAlarm.c index 0277c22fc44..1f1e214bd4b 100644 --- a/shared-bindings/alarm/time/TimeAlarm.c +++ b/shared-bindings/alarm/time/TimeAlarm.c @@ -46,8 +46,6 @@ mp_obj_t MP_WEAK rtc_get_time_source_time(void) { //| static mp_obj_t alarm_time_timealarm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - alarm_time_timealarm_obj_t *self = mp_obj_malloc(alarm_time_timealarm_obj_t, &alarm_time_timealarm_type); - enum { ARG_monotonic_time, ARG_epoch_time }; static const mp_arg_t allowed_args[] = { { MP_QSTR_monotonic_time, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, @@ -75,7 +73,7 @@ static mp_obj_t alarm_time_timealarm_make_new(const mp_obj_type_t *type, #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE mp_raise_ValueError(MP_ERROR_TEXT("epoch_time not supported on this board")); #else - mp_uint_t epoch_time_secs = mp_obj_int_get_checked(args[ARG_epoch_time].u_obj); + mp_uint_t epoch_time_secs = mp_arg_validate_type_int(args[ARG_epoch_time].u_obj, MP_QSTR_epoch_time); timeutils_struct_time_t tm; struct_time_to_tm(rtc_get_time_source_time(), &tm); @@ -92,6 +90,7 @@ static mp_obj_t alarm_time_timealarm_make_new(const mp_obj_type_t *type, mp_raise_ValueError(MP_ERROR_TEXT("Time is in the past.")); } + alarm_time_timealarm_obj_t *self = mp_obj_malloc(alarm_time_timealarm_obj_t, &alarm_time_timealarm_type); common_hal_alarm_time_timealarm_construct(self, monotonic_time); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/alarm/touch/TouchAlarm.c b/shared-bindings/alarm/touch/TouchAlarm.c index f25e826cff0..eac3f37b8f4 100644 --- a/shared-bindings/alarm/touch/TouchAlarm.c +++ b/shared-bindings/alarm/touch/TouchAlarm.c @@ -21,13 +21,12 @@ //| may be limited due to hardware restrictions, particularly for deep-sleep alarms. //| //| **Limitations:** Not available on SAMD, Nordic, or RP2040. +//| On Espressif, only available on ESP32, ESP32-S2, ESP32-S3, and ESP32-P4. //| """ //| ... //| static mp_obj_t alarm_touch_touchalarm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - alarm_touch_touchalarm_obj_t *self = mp_obj_malloc(alarm_touch_touchalarm_obj_t, &alarm_touch_touchalarm_type); - enum { ARG_pin }; static const mp_arg_t allowed_args[] = { { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -38,6 +37,7 @@ static mp_obj_t alarm_touch_touchalarm_make_new(const mp_obj_type_t *type, const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); + alarm_touch_touchalarm_obj_t *self = mp_obj_malloc(alarm_touch_touchalarm_obj_t, &alarm_touch_touchalarm_type); common_hal_alarm_touch_touchalarm_construct(self, pin); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/analogbufio/BufferedIn.c b/shared-bindings/analogbufio/BufferedIn.c index a25610207b4..398823809b0 100644 --- a/shared-bindings/analogbufio/BufferedIn.c +++ b/shared-bindings/analogbufio/BufferedIn.c @@ -60,10 +60,8 @@ static mp_obj_t analogbufio_bufferedin_make_new(const mp_obj_type_t *type, size_ // Validate Pin const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); - // Create local object - analogbufio_bufferedin_obj_t *self = mp_obj_malloc_with_finaliser(analogbufio_bufferedin_obj_t, &analogbufio_bufferedin_type); - - // Call local interface in ports/common-hal/analogbufio + analogbufio_bufferedin_obj_t *self = + mp_obj_malloc_with_finaliser(analogbufio_bufferedin_obj_t, &analogbufio_bufferedin_type); common_hal_analogbufio_bufferedin_construct(self, pin, args[ARG_sample_rate].u_int); return MP_OBJ_FROM_PTR(self); @@ -128,7 +126,7 @@ static mp_obj_t analogbufio_bufferedin_obj_readinto(size_t n_args, const mp_obj_ mp_obj_t buffer = args[ARG_buffer].u_obj; // Buffer defined and allocated by user mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); uint8_t bytes_per_sample = 1; if (bufinfo.typecode == 'H') { bytes_per_sample = 2; diff --git a/shared-bindings/audiobusio/I2SOut.c b/shared-bindings/audiobusio/I2SOut.c index 9aaf7421c65..7769352a1da 100644 --- a/shared-bindings/audiobusio/I2SOut.c +++ b/shared-bindings/audiobusio/I2SOut.c @@ -25,6 +25,7 @@ //| *, //| main_clock: Optional[microcontroller.Pin] = None, //| left_justified: bool = False, +//| external_clock: bool = False, //| ) -> None: //| """Create a I2SOut object associated with the given pins. //| @@ -34,6 +35,15 @@ //| :param ~microcontroller.Pin main_clock: The main clock pin //| :param bool left_justified: True when data bits are aligned with the word select clock. False //| when they are shifted by one to match classic I2S protocol. +//| :param bool external_clock: True when this object follows an externally supplied clock: +//| ``bit_clock`` and ``word_select`` are inputs driven by something else, another I2S +//| object (the clock source), or a codec, rather than generated by this object. Not +//| supported on all ports. +//| +//| In external clock mode ``bit_clock`` and ``word_select`` do not have to be sequential +//| GPIOs, and they may be shared with another I2S object. `play` cannot retime the bus, so +//| the sample's ``sample_rate`` must equal the external frame rate or the pitch will be +//| wrong. If the incoming clock stops, output stalls with its last sample held. //| //| Simple 8ksps 440 Hz sine wave on `Metro M0 Express `_ //| using `UDA1334 Breakout `_:: @@ -82,24 +92,35 @@ static mp_obj_t audiobusio_i2sout_make_new(const mp_obj_type_t *type, size_t n_a mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_I2SOut); return NULL; // Not reachable. #else - enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, ARG_left_justified }; + enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, ARG_left_justified, ARG_external_clock }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bit_clock, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_word_select, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_main_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, - { MP_QSTR_left_justified, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_left_justified, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_external_clock, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; 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 mcu_pin_obj_t *bit_clock = validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); - const mcu_pin_obj_t *word_select = validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); + bool external_clock = args[ARG_external_clock].u_bool; + + // In external clock mode the clock pins are only read, so they may already + // be owned by whatever is driving them; let the port decide if the sharing + // is legal. + const mcu_pin_obj_t *bit_clock = external_clock + ? validate_obj_is_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock) + : validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); + const mcu_pin_obj_t *word_select = external_clock + ? validate_obj_is_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select) + : validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj, MP_QSTR_data); const mcu_pin_obj_t *main_clock = validate_obj_is_free_pin_or_none(args[ARG_main_clock].u_obj, MP_QSTR_main_clock); audiobusio_i2sout_obj_t *self = mp_obj_malloc_with_finaliser(audiobusio_i2sout_obj_t, &audiobusio_i2sout_type); - common_hal_audiobusio_i2sout_construct(self, bit_clock, word_select, data, main_clock, args[ARG_left_justified].u_bool); + common_hal_audiobusio_i2sout_construct(self, bit_clock, word_select, data, main_clock, + args[ARG_left_justified].u_bool, external_clock); return MP_OBJ_FROM_PTR(self); #endif @@ -144,6 +165,8 @@ static void check_for_deinit(audiobusio_i2sout_obj_t *self) { //| //| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. //| +//| Mono samples will be converted to stereo by copying value to both the left channel and the right channel. +//| //| The sample itself should consist of 8 bit or 16 bit samples.""" //| ... //| diff --git a/shared-bindings/audiobusio/I2SOut.h b/shared-bindings/audiobusio/I2SOut.h index a53997ef91b..bc3c944b08d 100644 --- a/shared-bindings/audiobusio/I2SOut.h +++ b/shared-bindings/audiobusio/I2SOut.h @@ -16,7 +16,7 @@ extern const mp_obj_type_t audiobusio_i2sout_type; void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, - const mcu_pin_obj_t *main_clock, bool left_justified); + const mcu_pin_obj_t *main_clock, bool left_justified, bool external_clock); void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self); bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t *self); diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index 2a3fd3540c3..075c089841c 100644 --- a/shared-bindings/audiobusio/PDMIn.c +++ b/shared-bindings/audiobusio/PDMIn.c @@ -48,7 +48,7 @@ //| //| **Limitations:** On SAMD and RP2040, supports only 8 or 16 bit mono input, with 64x oversampling. //| On nRF52840, supports only 16 bit mono input at 16 kHz; oversampling is fixed at 64x. Not provided -//| on nRF52833 for space reasons. Not available on Espressif. +//| on nRF52833 for space reasons. On Espressif, only available on ESP32, ESP32-S3, and ESP32-P4. //| //| For example, to record 8-bit unsigned samples to a buffer:: //| @@ -96,18 +96,17 @@ static mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar const mcu_pin_obj_t *clock_pin = validate_obj_is_free_pin(args[ARG_clock_pin].u_obj, MP_QSTR_clock_pin); const mcu_pin_obj_t *data_pin = validate_obj_is_free_pin(args[ARG_data_pin].u_obj, MP_QSTR_data_pin); - // create PDMIn object from the given pin - audiobusio_pdmin_obj_t *self = mp_obj_malloc_with_finaliser(audiobusio_pdmin_obj_t, &audiobusio_pdmin_type); - - uint32_t sample_rate = args[ARG_sample_rate].u_int; - uint8_t bit_depth = args[ARG_bit_depth].u_int; - if (bit_depth % 8 != 0) { + uint32_t sample_rate = mp_arg_validate_int_min(args[ARG_sample_rate].u_int, 1, MP_QSTR_sample_rate); + mp_int_t requested_bit_depth = args[ARG_bit_depth].u_int; + if (requested_bit_depth != 8 && requested_bit_depth != 16) { mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be multiple of 8."), MP_QSTR_bit_depth); } - uint8_t oversample = args[ARG_oversample].u_int; - if (oversample % 8 != 0) { + uint8_t bit_depth = requested_bit_depth; + mp_int_t requested_oversample = args[ARG_oversample].u_int; + if (requested_oversample < 8 || requested_oversample > 255 || requested_oversample % 8 != 0) { mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be multiple of 8."), MP_QSTR_oversample); } + uint8_t oversample = requested_oversample; bool mono = args[ARG_mono].u_bool; mp_float_t startup_delay = (args[ARG_startup_delay].u_obj == MP_OBJ_NULL) @@ -115,6 +114,7 @@ static mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar : mp_obj_get_float(args[ARG_startup_delay].u_obj); mp_arg_validate_float_range(startup_delay, 0.0f, 1.0f, MP_QSTR_startup_delay); + audiobusio_pdmin_obj_t *self = mp_obj_malloc_with_finaliser(audiobusio_pdmin_obj_t, &audiobusio_pdmin_type); common_hal_audiobusio_pdmin_construct(self, clock_pin, data_pin, sample_rate, bit_depth, mono, oversample); @@ -155,11 +155,11 @@ static void check_for_deinit(audiobusio_pdmin_obj_t *self) { // Provided by context manager helper. -//| def record(self, destination: WriteableBuffer, destination_length: int) -> None: +//| def record(self, destination: WriteableBuffer, destination_length: int) -> int: //| """Records destination_length bytes of samples to destination. This is //| blocking. //| -//| An IOError may be raised when the destination is too slow to record the +//| An OSError may be raised when the destination is too slow to record the //| audio at the given rate. For internal flash, writing all 1s to the file //| before recording is recommended to speed up writes. //| @@ -176,22 +176,22 @@ static mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destinat mp_buffer_info_t bufinfo; if (mp_obj_is_type(destination, &mp_type_fileio)) { mp_raise_NotImplementedError(MP_ERROR_TEXT("Cannot record to a file")); - } else if (mp_get_buffer(destination, &bufinfo, MP_BUFFER_WRITE)) { - if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { - mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); - } - uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self); - if (bufinfo.typecode != 'H' && bit_depth == 16) { - mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be an array of type 'H' for bit_depth = 16")); - } else if (bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE && bit_depth == 8) { - mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8")); - } - // length is the buffer length in slots, not bytes. - uint32_t length_written = - common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length); - return MP_OBJ_NEW_SMALL_INT(length_written); } - return mp_const_none; + + mp_get_buffer_raise(destination, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { + mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); + } + uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self); + if (bufinfo.typecode != 'H' && bit_depth == 16) { + mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be an array of type 'H' for bit_depth = 16")); + } else if (bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE && bit_depth == 8) { + mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8")); + } + // length is the buffer length in slots, not bytes. + uint32_t length_written = + common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length); + return MP_OBJ_NEW_SMALL_INT(length_written); } MP_DEFINE_CONST_FUN_OBJ_3(audiobusio_pdmin_record_obj, audiobusio_pdmin_obj_record); diff --git a/shared-bindings/audiocore/RawSample.c b/shared-bindings/audiocore/RawSample.c index 30c1d1ad600..8dc57903286 100644 --- a/shared-bindings/audiocore/RawSample.c +++ b/shared-bindings/audiocore/RawSample.c @@ -90,7 +90,6 @@ static mp_obj_t audioio_rawsample_make_new(const mp_obj_type_t *type, size_t n_a 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); - audioio_rawsample_obj_t *self = mp_obj_malloc(audioio_rawsample_obj_t, &audioio_rawsample_type); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); uint8_t bytes_per_sample = 1; @@ -103,9 +102,16 @@ static mp_obj_t audioio_rawsample_make_new(const mp_obj_type_t *type, size_t n_a if (!args[ARG_single_buffer].u_bool && bufinfo.len % (bytes_per_sample * args[ARG_channel_count].u_int * 2) != 0) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Length of %q must be an even multiple of channel_count * type_size"), MP_QSTR_buffer); } - common_hal_audioio_rawsample_construct(self, ((uint8_t *)bufinfo.buf), bufinfo.len, - bytes_per_sample, signed_samples, args[ARG_channel_count].u_int, - args[ARG_sample_rate].u_int, args[ARG_single_buffer].u_bool); + + audioio_rawsample_obj_t *self = mp_obj_malloc(audioio_rawsample_obj_t, &audioio_rawsample_type); + common_hal_audioio_rawsample_construct(self, + ((uint8_t *)bufinfo.buf), + bufinfo.len, + bytes_per_sample, + signed_samples, + args[ARG_channel_count].u_int, + args[ARG_sample_rate].u_int, + args[ARG_single_buffer].u_bool); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiocore/WaveFile.c b/shared-bindings/audiocore/WaveFile.c index 4ba7d24bfd2..d0aa011313c 100644 --- a/shared-bindings/audiocore/WaveFile.c +++ b/shared-bindings/audiocore/WaveFile.c @@ -27,7 +27,8 @@ //| :param Union[str, typing.BinaryIO] file: The name of a wave file (preferred) or an already opened wave file //| :param ~circuitpython_typing.WriteableBuffer buffer: Optional pre-allocated buffer, //| that will be split in half and used for double-buffering of the data. -//| The buffer must be 8 to 1024 bytes long. +//| The buffer must be 8 to 1024 bytes long and a multiple of 8 bytes, so that each half +//| holds a whole number of 32-bit words. //| If not provided, two 256 byte buffers are initially allocated internally. //| //| Playing a wave file from flash:: @@ -60,7 +61,6 @@ static mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_ar arg = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), arg, MP_ROM_QSTR(MP_QSTR_rb)); } - audioio_wavefile_obj_t *self = mp_obj_malloc(audioio_wavefile_obj_t, &audioio_wavefile_type); if (!mp_obj_is_type(arg, &mp_type_vfs_fat_fileio)) { mp_raise_TypeError(MP_ERROR_TEXT("file must be a file opened in byte mode")); } @@ -71,7 +71,12 @@ static mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_ar mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); buffer = bufinfo.buf; buffer_size = mp_arg_validate_length_range(bufinfo.len, 8, 1024, MP_QSTR_buffer); + if (buffer_size % 8 != 0) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 8); + } } + + audioio_wavefile_obj_t *self = mp_obj_malloc(audioio_wavefile_obj_t, &audioio_wavefile_type); common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(arg), buffer, buffer_size); diff --git a/shared-bindings/audiocore/__init__.c b/shared-bindings/audiocore/__init__.c index b2b6c4da0f3..2dadc8877f9 100644 --- a/shared-bindings/audiocore/__init__.c +++ b/shared-bindings/audiocore/__init__.c @@ -145,7 +145,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_sample_rate_obj, audiosample_obj_get_s static mp_obj_t audiosample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { audiosample_base_t *self = MP_OBJ_TO_PTR(self_in); audiosample_check_for_deinit(self); - audiosample_set_sample_rate(audiosample_check(self_in), mp_obj_get_int(sample_rate)); + audiosample_set_sample_rate(audiosample_check(self_in), + (uint32_t)mp_arg_validate_int_min(mp_obj_get_int(sample_rate), 1, MP_QSTR_sample_rate)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(audiosample_set_sample_rate_obj, audiosample_obj_set_sample_rate); diff --git a/shared-bindings/audiodelays/Chorus.c b/shared-bindings/audiodelays/Chorus.c index 87922ff110b..41bcbb7ef93 100644 --- a/shared-bindings/audiodelays/Chorus.c +++ b/shared-bindings/audiodelays/Chorus.c @@ -58,7 +58,7 @@ //| //| audio = audiobusio.I2SOut(bit_clock=board.GP20, word_select=board.GP21, data=board.GP22) //| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) -//| chorus = audiodelays.Chorus(max_delay_ms=50, delay_ms=5, buffer_size=1024, channel_count=1, sample_rate=44100) +//| chorus = audiodelays.Chorus(max_delay_ms=50, voices=4, delay_ms=5, buffer_size=1024, channel_count=1, sample_rate=44100) //| chorus.play(synth) //| audio.play(chorus) //| diff --git a/shared-bindings/audiodelays/Chorus.h b/shared-bindings/audiodelays/Chorus.h index 10c6448df89..63e9ba9c28d 100644 --- a/shared-bindings/audiodelays/Chorus.h +++ b/shared-bindings/audiodelays/Chorus.h @@ -18,10 +18,6 @@ void common_hal_audiodelays_chorus_construct(audiodelays_chorus_obj_t *self, uin void common_hal_audiodelays_chorus_deinit(audiodelays_chorus_obj_t *self); bool common_hal_audiodelays_chorus_deinited(audiodelays_chorus_obj_t *self); -uint32_t common_hal_audiodelays_chorus_get_sample_rate(audiodelays_chorus_obj_t *self); -uint8_t common_hal_audiodelays_chorus_get_channel_count(audiodelays_chorus_obj_t *self); -uint8_t common_hal_audiodelays_chorus_get_bits_per_sample(audiodelays_chorus_obj_t *self); - mp_obj_t common_hal_audiodelays_chorus_get_delay_ms(audiodelays_chorus_obj_t *self); void common_hal_audiodelays_chorus_set_delay_ms(audiodelays_chorus_obj_t *self, mp_obj_t delay_ms); diff --git a/shared-bindings/audiodelays/Echo.c b/shared-bindings/audiodelays/Echo.c index dbb496c61b9..f1c79de0e13 100644 --- a/shared-bindings/audiodelays/Echo.c +++ b/shared-bindings/audiodelays/Echo.c @@ -25,6 +25,7 @@ //| max_delay_ms: int = 500, //| delay_ms: synthio.BlockInput = 250.0, //| decay: synthio.BlockInput = 0.7, +//| filter: Optional[synthio.Biquad | Tuple[synthio.Biquad]] = None, //| mix: synthio.BlockInput = 0.25, //| buffer_size: int = 512, //| sample_rate: int = 8000, @@ -45,6 +46,7 @@ //| :param int max_delay_ms: The maximum time the echo can be in milliseconds //| :param synthio.BlockInput delay_ms: The current time of the echo delay in milliseconds. Must be less the max_delay_ms //| :param synthio.BlockInput decay: The rate the echo fades. 0.0 = instant; 1.0 = never. +//| :param Optional[synthio.Biquad|Tuple[synthio.Biquad]] filter: A normalized biquad filter object or tuple of normalized biquad filter objects. A copy of the samples are processed sequentially by each filter before writing into the echo buffer. The original samples are not affected by this argument. //| :param synthio.BlockInput mix: The mix as a ratio of the sample (0.0) to the effect (1.0). //| :param int buffer_size: The total size in bytes of each of the two playback buffers to use //| :param int sample_rate: The sample rate to be used @@ -76,11 +78,12 @@ //| ... //| static mp_obj_t audiodelays_echo_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_max_delay_ms, ARG_delay_ms, ARG_decay, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, ARG_freq_shift, }; + enum { ARG_max_delay_ms, ARG_delay_ms, ARG_decay, ARG_filter, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, ARG_freq_shift, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_max_delay_ms, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 500 } }, { MP_QSTR_delay_ms, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_decay, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } }, { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, @@ -103,7 +106,7 @@ static mp_obj_t audiodelays_echo_make_new(const mp_obj_type_t *type, size_t n_ar } audiodelays_echo_obj_t *self = mp_obj_malloc(audiodelays_echo_obj_t, &audiodelays_echo_type); - common_hal_audiodelays_echo_construct(self, max_delay_ms, args[ARG_delay_ms].u_obj, args[ARG_decay].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate, args[ARG_freq_shift].u_bool); + common_hal_audiodelays_echo_construct(self, max_delay_ms, args[ARG_delay_ms].u_obj, args[ARG_decay].u_obj, args[ARG_filter].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate, args[ARG_freq_shift].u_bool); return MP_OBJ_FROM_PTR(self); } @@ -177,6 +180,29 @@ MP_PROPERTY_GETSET(audiodelays_echo_decay_obj, (mp_obj_t)&audiodelays_echo_get_decay_obj, (mp_obj_t)&audiodelays_echo_set_decay_obj); + +//| filter: synthio.Biquad | Tuple[synthio.Biquad] | None +//| """A normalized biquad filter object or tuple of normalized biquad filter objects. A copy of the samples are processed sequentially by each filter before writing into the echo buffer. The original samples are not affected by this property.""" +//| +static mp_obj_t audiodelays_echo_obj_get_filter(mp_obj_t self_in) { + audiodelays_echo_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_audiodelays_echo_get_filter(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_echo_get_filter_obj, audiodelays_echo_obj_get_filter); + +static mp_obj_t audiodelays_echo_obj_set_filter(mp_obj_t self_in, mp_obj_t filter_in) { + audiodelays_echo_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_echo_set_filter(self, filter_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_echo_set_filter_obj, audiodelays_echo_obj_set_filter); + +MP_PROPERTY_GETSET(audiodelays_echo_filter_obj, + (mp_obj_t)&audiodelays_echo_get_filter_obj, + (mp_obj_t)&audiodelays_echo_set_filter_obj); + + //| mix: synthio.BlockInput //| """The rate the echo mix between 0 and 1 where 0 is only sample, 0.5 is an equal mix of the sample and the effect and 1 is all effect.""" static mp_obj_t audiodelays_echo_obj_get_mix(mp_obj_t self_in) { @@ -285,6 +311,7 @@ static const mp_rom_map_elem_t audiodelays_echo_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiodelays_echo_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_delay_ms), MP_ROM_PTR(&audiodelays_echo_delay_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_decay), MP_ROM_PTR(&audiodelays_echo_decay_obj) }, + { MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&audiodelays_echo_filter_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_echo_mix_obj) }, { MP_ROM_QSTR(MP_QSTR_freq_shift), MP_ROM_PTR(&audiodelays_echo_freq_shift_obj) }, AUDIOSAMPLE_FIELDS, diff --git a/shared-bindings/audiodelays/Echo.h b/shared-bindings/audiodelays/Echo.h index 83d454ed05c..67b7436b896 100644 --- a/shared-bindings/audiodelays/Echo.h +++ b/shared-bindings/audiodelays/Echo.h @@ -11,7 +11,7 @@ extern const mp_obj_type_t audiodelays_echo_type; void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_t max_delay_ms, - mp_obj_t delay_ms, mp_obj_t decay, mp_obj_t mix, + mp_obj_t delay_ms, mp_obj_t decay, mp_obj_t filter, mp_obj_t mix, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate, bool freq_shift); @@ -26,6 +26,9 @@ void common_hal_audiodelays_echo_set_freq_shift(audiodelays_echo_obj_t *self, bo mp_obj_t common_hal_audiodelays_echo_get_decay(audiodelays_echo_obj_t *self); void common_hal_audiodelays_echo_set_decay(audiodelays_echo_obj_t *self, mp_obj_t decay); +mp_obj_t common_hal_audiodelays_echo_get_filter(audiodelays_echo_obj_t *self); +void common_hal_audiodelays_echo_set_filter(audiodelays_echo_obj_t *self, mp_obj_t arg); + mp_obj_t common_hal_audiodelays_echo_get_mix(audiodelays_echo_obj_t *self); void common_hal_audiodelays_echo_set_mix(audiodelays_echo_obj_t *self, mp_obj_t arg); diff --git a/shared-bindings/audiodelays/Flanger.c b/shared-bindings/audiodelays/Flanger.c new file mode 100644 index 00000000000..7c16e164944 --- /dev/null +++ b/shared-bindings/audiodelays/Flanger.c @@ -0,0 +1,389 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared-bindings/audiodelays/Flanger.h" +#include "shared-module/audiodelays/Flanger.h" +#include "shared-bindings/audiocore/__init__.h" + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/util.h" +#include "shared-module/synthio/block.h" + +//| class Flanger: +//| """A Flanger effect""" +//| +//| def __init__( +//| self, +//| max_delay_ms: int = 10, +//| min_delay_ms: synthio.BlockInput = 1.0, +//| rate: synthio.BlockInput = 0.5, +//| depth: synthio.BlockInput = 0.5, +//| feedback: synthio.BlockInput = 0.5, +//| mix: synthio.BlockInput = 0.5, +//| invert: bool = False, +//| buffer_size: int = 512, +//| sample_rate: int = 8000, +//| bits_per_sample: int = 16, +//| samples_signed: bool = True, +//| channel_count: int = 1, +//| ) -> None: +//| """Create a Flanger effect by mixing the sample with a copy of itself taken from a very +//| short delay whose length is continuously swept up and down by an internal low frequency +//| oscillator. The moving delay creates a comb filter whose notches sweep through the +//| spectrum, and the ``feedback`` path routes the delayed signal back into the delay line +//| to sharpen those notches into resonant peaks. +//| +//| The delay is swept upwards from ``min_delay_ms`` towards ``max_delay_ms``:: +//| +//| sweep_top = min_delay_ms + depth * (max_delay_ms - min_delay_ms) +//| current_delay = min_delay_ms + triangle_lfo() * (sweep_top - min_delay_ms) +//| +//| where ``triangle_lfo()`` ranges from 0.0 to 1.0 at ``rate`` Hz. Because the sweep runs +//| upwards from a floor rather than around a centre, no combination of ``min_delay_ms`` and +//| ``depth`` can push the delay outside of the buffer. +//| +//| +//| :param int max_delay_ms: The maximum delay the flanger can sweep to in milliseconds, valid range is 1-100. +//| :param synthio.BlockInput min_delay_ms: The shortest delay of the sweep in milliseconds. Clamped between the length of one sample and max_delay_ms. +//| :param synthio.BlockInput rate: The frequency of the sweep in hertz. Clamped between 0.0 and 20.0. A rate of 0.0 holds the delay still. +//| :param synthio.BlockInput depth: How much of the range above min_delay_ms is swept, from 0.0 to 1.0. +//| :param synthio.BlockInput feedback: How much of the delayed signal is fed back into the delay line, from -0.95 to 0.95. Negative values invert the polarity of the feedback. +//| :param synthio.BlockInput mix: How much of the wet audio to include along with the original signal, from 0.0 to 1.0. +//| :param bool invert: Subtract the wet signal from the dry signal instead of adding it, which flips which frequencies cancel. +//| :param int buffer_size: The total size in bytes of each of the two playback buffers to use +//| :param int sample_rate: The sample rate to be used +//| :param int channel_count: The number of channels the source samples contain. 1 = mono; 2 = stereo. +//| :param int bits_per_sample: The bits per sample of the effect +//| :param bool samples_signed: Effect is signed (True) or unsigned (False) +//| +//| Adding a flanger to a synth:: +//| +//| import time +//| import board +//| import audiobusio +//| import synthio +//| import audiodelays +//| +//| audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WS, board.I2S_DOUT) +//| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) +//| flanger = audiodelays.Flanger(max_delay_ms=10, min_delay_ms=1.0, rate=0.3, depth=0.8, +//| feedback=0.7, mix=1.0, buffer_size=1024, +//| channel_count=1, sample_rate=44100) +//| audio.play(flanger.play(synth)) +//| +//| note = synthio.Note(261) +//| while True: +//| synth.press(note) +//| time.sleep(3) +//| synth.release(note) +//| time.sleep(1)""" +//| ... +//| +static mp_obj_t audiodelays_flanger_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_max_delay_ms, ARG_min_delay_ms, ARG_rate, ARG_depth, ARG_feedback, ARG_mix, ARG_invert, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_max_delay_ms, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 10 } }, + { MP_QSTR_min_delay_ms, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_rate, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_depth, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_feedback, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_invert, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1 } }, + }; + + 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); + + mp_int_t max_delay_ms = mp_arg_validate_int_range(args[ARG_max_delay_ms].u_int, 1, 100, MP_QSTR_max_delay_ms); + + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, 2, MP_QSTR_channel_count); + mp_int_t sample_rate = mp_arg_validate_int_min(args[ARG_sample_rate].u_int, 1, MP_QSTR_sample_rate); + mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; + if (bits_per_sample != 8 && bits_per_sample != 16) { + mp_raise_ValueError(MP_ERROR_TEXT("bits_per_sample must be 8 or 16")); + } + + audiodelays_flanger_obj_t *self = mp_obj_malloc(audiodelays_flanger_obj_t, &audiodelays_flanger_type); + common_hal_audiodelays_flanger_construct(self, max_delay_ms, args[ARG_min_delay_ms].u_obj, args[ARG_rate].u_obj, args[ARG_depth].u_obj, args[ARG_feedback].u_obj, args[ARG_mix].u_obj, args[ARG_invert].u_bool, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the Flanger.""" +//| ... +//| +static mp_obj_t audiodelays_flanger_deinit(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_deinit_obj, audiodelays_flanger_deinit); + +static void check_for_deinit(audiodelays_flanger_obj_t *self) { + audiosample_check_for_deinit(&self->base); +} + +//| def __enter__(self) -> Flanger: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +static mp_obj_t audiodelays_flanger_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audiodelays_flanger_deinit(args[0]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiodelays_flanger___exit___obj, 4, 4, audiodelays_flanger_obj___exit__); + + +//| min_delay_ms: synthio.BlockInput +//| """The shortest delay of the sweep in milliseconds. This is the floor that the sweep runs +//| upwards from. Clamped between the length of a single sample and ``max_delay_ms``.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_min_delay_ms(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_audiodelays_flanger_get_min_delay_ms(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_min_delay_ms_obj, audiodelays_flanger_obj_get_min_delay_ms); + +static mp_obj_t audiodelays_flanger_obj_set_min_delay_ms(mp_obj_t self_in, mp_obj_t min_delay_ms_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_min_delay_ms(self, min_delay_ms_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_min_delay_ms_obj, audiodelays_flanger_obj_set_min_delay_ms); + +MP_PROPERTY_GETSET(audiodelays_flanger_min_delay_ms_obj, + (mp_obj_t)&audiodelays_flanger_get_min_delay_ms_obj, + (mp_obj_t)&audiodelays_flanger_set_min_delay_ms_obj); + +//| rate: synthio.BlockInput +//| """The frequency of the delay sweep in hertz. Clamped between 0.0 and 20.0. A rate of 0.0 +//| holds the delay still, which leaves a fixed comb filter.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_rate(mp_obj_t self_in) { + return common_hal_audiodelays_flanger_get_rate(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_rate_obj, audiodelays_flanger_obj_get_rate); + +static mp_obj_t audiodelays_flanger_obj_set_rate(mp_obj_t self_in, mp_obj_t rate_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_rate(self, rate_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_rate_obj, audiodelays_flanger_obj_set_rate); + +MP_PROPERTY_GETSET(audiodelays_flanger_rate_obj, + (mp_obj_t)&audiodelays_flanger_get_rate_obj, + (mp_obj_t)&audiodelays_flanger_set_rate_obj); + +//| depth: synthio.BlockInput +//| """How much of the range between ``min_delay_ms`` and ``max_delay_ms`` the sweep covers, from +//| 0.0 to 1.0. A depth of 0.0 leaves a static short delay.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_depth(mp_obj_t self_in) { + return common_hal_audiodelays_flanger_get_depth(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_depth_obj, audiodelays_flanger_obj_get_depth); + +static mp_obj_t audiodelays_flanger_obj_set_depth(mp_obj_t self_in, mp_obj_t depth_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_depth(self, depth_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_depth_obj, audiodelays_flanger_obj_set_depth); + +MP_PROPERTY_GETSET(audiodelays_flanger_depth_obj, + (mp_obj_t)&audiodelays_flanger_get_depth_obj, + (mp_obj_t)&audiodelays_flanger_set_depth_obj); + +//| feedback: synthio.BlockInput +//| """How much of the delayed signal is fed back into the delay line, clamped between -0.95 and +//| 0.95. Larger magnitudes give a more resonant, ringing sweep. Negative values invert the +//| polarity of the feedback for the hollower variant.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_feedback(mp_obj_t self_in) { + return common_hal_audiodelays_flanger_get_feedback(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_feedback_obj, audiodelays_flanger_obj_get_feedback); + +static mp_obj_t audiodelays_flanger_obj_set_feedback(mp_obj_t self_in, mp_obj_t feedback_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_feedback(self, feedback_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_feedback_obj, audiodelays_flanger_obj_set_feedback); + +MP_PROPERTY_GETSET(audiodelays_flanger_feedback_obj, + (mp_obj_t)&audiodelays_flanger_get_feedback_obj, + (mp_obj_t)&audiodelays_flanger_set_feedback_obj); + +//| mix: synthio.BlockInput +//| """How much of the wet audio to include along with the original signal, clamped between 0.0 +//| and 1.0 where 0.0 is only the sample and 1.0 is the full effect.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_mix(mp_obj_t self_in) { + return common_hal_audiodelays_flanger_get_mix(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_mix_obj, audiodelays_flanger_obj_get_mix); + +static mp_obj_t audiodelays_flanger_obj_set_mix(mp_obj_t self_in, mp_obj_t mix_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_mix(self, mix_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_mix_obj, audiodelays_flanger_obj_set_mix); + +MP_PROPERTY_GETSET(audiodelays_flanger_mix_obj, + (mp_obj_t)&audiodelays_flanger_get_mix_obj, + (mp_obj_t)&audiodelays_flanger_set_mix_obj); + +//| invert: bool +//| """Whether the wet signal is subtracted from the dry signal instead of added to it. This +//| flips which frequencies the comb filter cancels, the same as the polarity switch on a +//| flanger pedal.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_invert(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_audiodelays_flanger_get_invert(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_invert_obj, audiodelays_flanger_obj_get_invert); + +static mp_obj_t audiodelays_flanger_obj_set_invert(mp_obj_t self_in, mp_obj_t invert_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_invert(self, mp_obj_is_true(invert_in)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_invert_obj, audiodelays_flanger_obj_set_invert); + +MP_PROPERTY_GETSET(audiodelays_flanger_invert_obj, + (mp_obj_t)&audiodelays_flanger_get_invert_obj, + (mp_obj_t)&audiodelays_flanger_set_invert_obj); + +//| lfo_value: float +//| """The current value of the internal LFO that sweeps the delay time, from 0.0 at +//| `min_delay_ms` to 1.0 at the top of the sweep. The LFO only advances while audio is being +//| played. (read-only)""" +//| +static mp_obj_t audiodelays_flanger_obj_get_lfo_value(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_float(common_hal_audiodelays_flanger_get_lfo_value(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_lfo_value_obj, audiodelays_flanger_obj_get_lfo_value); + +MP_PROPERTY_GETTER(audiodelays_flanger_lfo_value_obj, + (mp_obj_t)&audiodelays_flanger_get_lfo_value_obj); + +//| playing: bool +//| """True when the effect is playing a sample. (read-only)""" +//| +static mp_obj_t audiodelays_flanger_obj_get_playing(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiodelays_flanger_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_playing_obj, audiodelays_flanger_obj_get_playing); + +MP_PROPERTY_GETTER(audiodelays_flanger_playing_obj, + (mp_obj_t)&audiodelays_flanger_get_playing_obj); + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Flanger: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: Flanger""" +//| ... +//| +static mp_obj_t audiodelays_flanger_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED, {} }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + 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_obj_t sample = args[ARG_sample].u_obj; + common_hal_audiodelays_flanger_play(self, sample, args[ARG_loop].u_bool); + + return MP_OBJ_FROM_PTR(self); +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_flanger_play_obj, 1, audiodelays_flanger_obj_play); + +//| def stop(self) -> None: +//| """Stops playback of the sample.""" +//| ... +//| +//| +static mp_obj_t audiodelays_flanger_obj_stop(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_audiodelays_flanger_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_stop_obj, audiodelays_flanger_obj_stop); + +static const mp_rom_map_elem_t audiodelays_flanger_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiodelays_flanger_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiodelays_flanger___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiodelays_flanger_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiodelays_flanger_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiodelays_flanger_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_min_delay_ms), MP_ROM_PTR(&audiodelays_flanger_min_delay_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiodelays_flanger_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_depth), MP_ROM_PTR(&audiodelays_flanger_depth_obj) }, + { MP_ROM_QSTR(MP_QSTR_feedback), MP_ROM_PTR(&audiodelays_flanger_feedback_obj) }, + { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_flanger_mix_obj) }, + { MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&audiodelays_flanger_invert_obj) }, + { MP_ROM_QSTR(MP_QSTR_lfo_value), MP_ROM_PTR(&audiodelays_flanger_lfo_value_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(audiodelays_flanger_locals_dict, audiodelays_flanger_locals_dict_table); + +static const audiosample_p_t audiodelays_flanger_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audiodelays_flanger_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiodelays_flanger_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + audiodelays_flanger_type, + MP_QSTR_Flanger, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiodelays_flanger_make_new, + locals_dict, &audiodelays_flanger_locals_dict, + protocol, &audiodelays_flanger_proto + ); diff --git a/shared-bindings/audiodelays/Flanger.h b/shared-bindings/audiodelays/Flanger.h new file mode 100644 index 00000000000..f139e842dbd --- /dev/null +++ b/shared-bindings/audiodelays/Flanger.h @@ -0,0 +1,43 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiodelays/Flanger.h" + +extern const mp_obj_type_t audiodelays_flanger_type; + +void common_hal_audiodelays_flanger_construct(audiodelays_flanger_obj_t *self, uint32_t max_delay_ms, + mp_obj_t min_delay_ms, mp_obj_t rate, mp_obj_t depth, mp_obj_t feedback, mp_obj_t mix, bool invert, + uint32_t buffer_size, uint8_t bits_per_sample, + bool samples_signed, uint8_t channel_count, uint32_t sample_rate); + +void common_hal_audiodelays_flanger_deinit(audiodelays_flanger_obj_t *self); +bool common_hal_audiodelays_flanger_deinited(audiodelays_flanger_obj_t *self); + +mp_obj_t common_hal_audiodelays_flanger_get_min_delay_ms(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_min_delay_ms(audiodelays_flanger_obj_t *self, mp_obj_t min_delay_ms); + +mp_obj_t common_hal_audiodelays_flanger_get_rate(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_rate(audiodelays_flanger_obj_t *self, mp_obj_t rate); + +mp_obj_t common_hal_audiodelays_flanger_get_depth(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_depth(audiodelays_flanger_obj_t *self, mp_obj_t depth); + +mp_obj_t common_hal_audiodelays_flanger_get_feedback(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_feedback(audiodelays_flanger_obj_t *self, mp_obj_t feedback); + +mp_obj_t common_hal_audiodelays_flanger_get_mix(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_mix(audiodelays_flanger_obj_t *self, mp_obj_t arg); + +mp_float_t common_hal_audiodelays_flanger_get_lfo_value(audiodelays_flanger_obj_t *self); + +bool common_hal_audiodelays_flanger_get_invert(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_invert(audiodelays_flanger_obj_t *self, bool invert); + +bool common_hal_audiodelays_flanger_get_playing(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_play(audiodelays_flanger_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_audiodelays_flanger_stop(audiodelays_flanger_obj_t *self); diff --git a/shared-bindings/audiodelays/GranularPitchShift.c b/shared-bindings/audiodelays/GranularPitchShift.c new file mode 100644 index 00000000000..afbda30156a --- /dev/null +++ b/shared-bindings/audiodelays/GranularPitchShift.c @@ -0,0 +1,315 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared-bindings/audiodelays/GranularPitchShift.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-module/audiodelays/GranularPitchShift.h" + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/util.h" +#include "shared-module/synthio/block.h" + +//| class GranularPitchShift: +//| """A granular-synthesis pitch shift effect""" +//| +//| def __init__( +//| self, +//| semitones: synthio.BlockInput = 0.0, +//| mix: synthio.BlockInput = 1.0, +//| grain_size: int = 1024, +//| density: int = 2, +//| spread: float = 0.0, +//| buffer_size: int = 512, +//| sample_rate: int = 8000, +//| bits_per_sample: int = 16, +//| samples_signed: bool = True, +//| channel_count: int = 1, +//| ) -> None: +//| """Create a pitch shift effect that shifts pitch using granular synthesis: a cloud of +//| short, overlapping, individually-enveloped grains resampled from a capture buffer. Unlike +//| `PitchShift` (a single crossfaded window), the overlapping grains tend to sound smoother +//| and less "robotic" at large shifts. This effect introduces a slight delay in the output +//| proportional to ``grain_size``. +//| +//| The mix parameter allows you to change how much of the unchanged sample passes through to +//| the output to how much of the effect audio you hear as the output. +//| +//| :param synthio.BlockInput semitones: The amount of pitch shifting in semitones (1/12th of an octave) +//| :param synthio.BlockInput mix: The mix as a ratio of the sample (0.0) to the effect (1.0) +//| :param int grain_size: The length in samples of each grain +//| :param int density: The number of overlapping grains (overlap factor). Must be between 1 and 8. +//| :param float spread: The amount of random jitter applied to each grain's start position, +//| from 0.0 (deterministic; every grain starts at the same offset) to 1.0 (maximum jitter). +//| Higher values give the classic granular "cloud" texture. Jitter is always backward in +//| time, so it never introduces additional latency beyond ``grain_size``. +//| :param int buffer_size: The total size in bytes of each of the two playback buffers to use +//| :param int sample_rate: The sample rate to be used +//| :param int channel_count: The number of channels the source samples contain. 1 = mono; 2 = stereo. +//| :param int bits_per_sample: The bits per sample of the effect +//| :param bool samples_signed: Effect is signed (True) or unsigned (False) +//| +//| Shifting the pitch of a synth by 5 semitones:: +//| +//| import time +//| import board +//| import audiobusio +//| import synthio +//| import audiodelays +//| from pwmio import PWMOut +//| import adafruit_tlv320 +//| +//| mclk_pwm = PWMOut(board.I2S_MCLK, frequency=15_000_000, duty_cycle=2**15) +//| i2c = board.I2C() +//| dac = adafruit_tlv320.TLV320DAC3100(i2c) +//| dac.configure_clocks(sample_rate=44100, bit_depth=16, mclk_freq=15_000_000) +//| dac.headphone_output = True +//| audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN) +//| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) +//| pitch_shift = audiodelays.GranularPitchShift(semitones=5.0, mix=1.0, spread=0.25, grain_size=2048, density=2, buffer_size=1024, channel_count=1, sample_rate=44100) +//| pitch_shift.play(synth) +//| audio.play(pitch_shift) +//| +//| while True: +//| for notenum in (60, 64, 67, 71): +//| synth.press(notenum) +//| time.sleep(0.25) +//| synth.release_all()""" +//| ... +//| +static mp_obj_t audiodelays_granular_pitch_shift_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_semitones, ARG_mix, ARG_grain_size, ARG_density, ARG_spread, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_semitones, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(0)} }, + { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(1)} }, + { MP_QSTR_grain_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, + { MP_QSTR_density, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_spread, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(0)} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1 } }, + }; + + 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); + + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, 2, MP_QSTR_channel_count); + mp_int_t sample_rate = mp_arg_validate_int_min(args[ARG_sample_rate].u_int, 1, MP_QSTR_sample_rate); + mp_int_t grain_size = mp_arg_validate_int_min(args[ARG_grain_size].u_int, 2, MP_QSTR_grain_size); + mp_int_t density = mp_arg_validate_int_range(args[ARG_density].u_int, 1, GRANULAR_MAX_GRAINS, MP_QSTR_density); + mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; + if (bits_per_sample != 8 && bits_per_sample != 16) { + mp_raise_ValueError(MP_ERROR_TEXT("bits_per_sample must be 8 or 16")); + } + + audiodelays_granular_pitch_shift_obj_t *self = + mp_obj_malloc(audiodelays_granular_pitch_shift_obj_t, &audiodelays_granular_pitch_shift_type); + common_hal_audiodelays_granular_pitch_shift_construct(self, + args[ARG_semitones].u_obj, + args[ARG_mix].u_obj, + grain_size, + density, + mp_obj_get_float(args[ARG_spread].u_obj), + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); + + return MP_OBJ_FROM_PTR(self); +} + + +//| def deinit(self) -> None: +//| """Deinitialises the GranularPitchShift.""" +//| ... +//| +static mp_obj_t audiodelays_granular_pitch_shift_deinit(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_deinit_obj, audiodelays_granular_pitch_shift_deinit); + +static void check_for_deinit(audiodelays_granular_pitch_shift_obj_t *self) { + audiosample_check_for_deinit(&self->base); +} + + +//| def __enter__(self) -> GranularPitchShift: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audiodelays_granular_pitch_shift_deinit(args[0]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiodelays_granular_pitch_shift___exit___obj, 4, 4, audiodelays_granular_pitch_shift_obj___exit__); + + +//| semitones: synthio.BlockInput +//| """The amount of pitch shifting in semitones (1/12th of an octave).""" +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj_get_semitones(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_audiodelays_granular_pitch_shift_get_semitones(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_get_semitones_obj, audiodelays_granular_pitch_shift_obj_get_semitones); + +static mp_obj_t audiodelays_granular_pitch_shift_obj_set_semitones(mp_obj_t self_in, mp_obj_t semitones_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_set_semitones(self, semitones_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_granular_pitch_shift_set_semitones_obj, audiodelays_granular_pitch_shift_obj_set_semitones); + +MP_PROPERTY_GETSET(audiodelays_granular_pitch_shift_semitones_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_get_semitones_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_set_semitones_obj); + + +//| mix: synthio.BlockInput +//| """The output mix between 0 and 1 where 0 is only sample and 1 is all effect.""" +static mp_obj_t audiodelays_granular_pitch_shift_obj_get_mix(mp_obj_t self_in) { + return common_hal_audiodelays_granular_pitch_shift_get_mix(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_get_mix_obj, audiodelays_granular_pitch_shift_obj_get_mix); + +static mp_obj_t audiodelays_granular_pitch_shift_obj_set_mix(mp_obj_t self_in, mp_obj_t mix_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_set_mix(self, mix_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_granular_pitch_shift_set_mix_obj, audiodelays_granular_pitch_shift_obj_set_mix); + +MP_PROPERTY_GETSET(audiodelays_granular_pitch_shift_mix_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_get_mix_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_set_mix_obj); + + +//| spread: float +//| """The amount of random jitter applied to each grain's start position, from 0.0 +//| (deterministic) to 1.0 (maximum jitter). Higher values give a thicker granular texture.""" +static mp_obj_t audiodelays_granular_pitch_shift_obj_get_spread(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_float(common_hal_audiodelays_granular_pitch_shift_get_spread(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_get_spread_obj, audiodelays_granular_pitch_shift_obj_get_spread); + +static mp_obj_t audiodelays_granular_pitch_shift_obj_set_spread(mp_obj_t self_in, mp_obj_t spread_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_set_spread(self, mp_obj_get_float(spread_in)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_granular_pitch_shift_set_spread_obj, audiodelays_granular_pitch_shift_obj_set_spread); + +MP_PROPERTY_GETSET(audiodelays_granular_pitch_shift_spread_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_get_spread_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_set_spread_obj); + + +//| playing: bool +//| """True when the effect is playing a sample. (read-only)""" +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj_get_playing(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiodelays_granular_pitch_shift_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_get_playing_obj, audiodelays_granular_pitch_shift_obj_get_playing); + +MP_PROPERTY_GETTER(audiodelays_granular_pitch_shift_playing_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_get_playing_obj); + + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> GranularPitchShift: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: GranularPitchShift""" +//| ... +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED, {} }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + 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_obj_t sample = args[ARG_sample].u_obj; + common_hal_audiodelays_granular_pitch_shift_play(self, sample, args[ARG_loop].u_bool); + + return MP_OBJ_FROM_PTR(self); +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_granular_pitch_shift_play_obj, 1, audiodelays_granular_pitch_shift_obj_play); + + +//| def stop(self) -> None: +//| """Stops playback of the sample.""" +//| ... +//| +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj_stop(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_stop_obj, audiodelays_granular_pitch_shift_obj_stop); + + +static const mp_rom_map_elem_t audiodelays_granular_pitch_shift_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiodelays_granular_pitch_shift_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiodelays_granular_pitch_shift___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiodelays_granular_pitch_shift_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiodelays_granular_pitch_shift_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiodelays_granular_pitch_shift_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_semitones), MP_ROM_PTR(&audiodelays_granular_pitch_shift_semitones_obj) }, + { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_granular_pitch_shift_mix_obj) }, + { MP_ROM_QSTR(MP_QSTR_spread), MP_ROM_PTR(&audiodelays_granular_pitch_shift_spread_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(audiodelays_granular_pitch_shift_locals_dict, audiodelays_granular_pitch_shift_locals_dict_table); + +static const audiosample_p_t audiodelays_granular_pitch_shift_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audiodelays_granular_pitch_shift_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiodelays_granular_pitch_shift_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + audiodelays_granular_pitch_shift_type, + MP_QSTR_GranularPitchShift, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiodelays_granular_pitch_shift_make_new, + locals_dict, &audiodelays_granular_pitch_shift_locals_dict, + protocol, &audiodelays_granular_pitch_shift_proto + ); diff --git a/shared-bindings/audiodelays/GranularPitchShift.h b/shared-bindings/audiodelays/GranularPitchShift.h new file mode 100644 index 00000000000..e5a518110bd --- /dev/null +++ b/shared-bindings/audiodelays/GranularPitchShift.h @@ -0,0 +1,31 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiodelays/GranularPitchShift.h" + +extern const mp_obj_type_t audiodelays_granular_pitch_shift_type; + +void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_pitch_shift_obj_t *self, + mp_obj_t semitones, mp_obj_t mix, uint32_t grain_size, uint32_t density, + mp_float_t spread, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, + uint8_t channel_count, uint32_t sample_rate); + +void common_hal_audiodelays_granular_pitch_shift_deinit(audiodelays_granular_pitch_shift_obj_t *self); + +mp_obj_t common_hal_audiodelays_granular_pitch_shift_get_semitones(audiodelays_granular_pitch_shift_obj_t *self); +void common_hal_audiodelays_granular_pitch_shift_set_semitones(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t semitones); + +mp_obj_t common_hal_audiodelays_granular_pitch_shift_get_mix(audiodelays_granular_pitch_shift_obj_t *self); +void common_hal_audiodelays_granular_pitch_shift_set_mix(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t arg); + +mp_float_t common_hal_audiodelays_granular_pitch_shift_get_spread(audiodelays_granular_pitch_shift_obj_t *self); +void common_hal_audiodelays_granular_pitch_shift_set_spread(audiodelays_granular_pitch_shift_obj_t *self, mp_float_t spread); + +bool common_hal_audiodelays_granular_pitch_shift_get_playing(audiodelays_granular_pitch_shift_obj_t *self); +void common_hal_audiodelays_granular_pitch_shift_play(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_audiodelays_granular_pitch_shift_stop(audiodelays_granular_pitch_shift_obj_t *self); diff --git a/shared-bindings/audiodelays/PitchShift.c b/shared-bindings/audiodelays/PitchShift.c index b94df7d9edd..49950df6a34 100644 --- a/shared-bindings/audiodelays/PitchShift.c +++ b/shared-bindings/audiodelays/PitchShift.c @@ -94,8 +94,18 @@ static mp_obj_t audiodelays_pitch_shift_make_new(const mp_obj_type_t *type, size mp_raise_ValueError(MP_ERROR_TEXT("bits_per_sample must be 8 or 16")); } - audiodelays_pitch_shift_obj_t *self = mp_obj_malloc(audiodelays_pitch_shift_obj_t, &audiodelays_pitch_shift_type); - common_hal_audiodelays_pitch_shift_construct(self, args[ARG_semitones].u_obj, args[ARG_mix].u_obj, args[ARG_window].u_int, args[ARG_overlap].u_int, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + audiodelays_pitch_shift_obj_t *self = + mp_obj_malloc(audiodelays_pitch_shift_obj_t, &audiodelays_pitch_shift_type); + common_hal_audiodelays_pitch_shift_construct(self, + args[ARG_semitones].u_obj, + args[ARG_mix].u_obj, + args[ARG_window].u_int, + args[ARG_overlap].u_int, + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); return MP_OBJ_FROM_PTR(self); } @@ -176,6 +186,28 @@ MP_PROPERTY_GETSET(audiodelays_pitch_shift_mix_obj, (mp_obj_t)&audiodelays_pitch_shift_set_mix_obj); +//| freeze: bool +//| """If True, the window buffer won't accept new audio information and will be "frozen" in +//| it's current state, resulting in a sustaining tone. Normal operation is resumed when set to +//| False. If the audio buffer is reset, this value will also be reset to False.""" +static mp_obj_t audiodelays_pitch_shift_obj_get_freeze(mp_obj_t self_in) { + return mp_obj_new_bool(common_hal_audiodelays_pitch_shift_get_freeze(self_in)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_pitch_shift_get_freeze_obj, audiodelays_pitch_shift_obj_get_freeze); + +static mp_obj_t audiodelays_pitch_shift_obj_set_freeze(mp_obj_t self_in, mp_obj_t freeze_in) { + audiodelays_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + bool freeze = mp_obj_is_true(freeze_in); + common_hal_audiodelays_pitch_shift_set_freeze(self, freeze); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_pitch_shift_set_freeze_obj, audiodelays_pitch_shift_obj_set_freeze); + +MP_PROPERTY_GETSET(audiodelays_pitch_shift_freeze_obj, + (mp_obj_t)&audiodelays_pitch_shift_get_freeze_obj, + (mp_obj_t)&audiodelays_pitch_shift_set_freeze_obj); + + //| playing: bool //| """True when the effect is playing a sample. (read-only)""" //| @@ -245,6 +277,7 @@ static const mp_rom_map_elem_t audiodelays_pitch_shift_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiodelays_pitch_shift_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_semitones), MP_ROM_PTR(&audiodelays_pitch_shift_semitones_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_pitch_shift_mix_obj) }, + { MP_ROM_QSTR(MP_QSTR_freeze), MP_ROM_PTR(&audiodelays_pitch_shift_freeze_obj) }, AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audiodelays_pitch_shift_locals_dict, audiodelays_pitch_shift_locals_dict_table); diff --git a/shared-bindings/audiodelays/PitchShift.h b/shared-bindings/audiodelays/PitchShift.h index 78c78b5ea82..5544d1a0aff 100644 --- a/shared-bindings/audiodelays/PitchShift.h +++ b/shared-bindings/audiodelays/PitchShift.h @@ -23,6 +23,9 @@ void common_hal_audiodelays_pitch_shift_set_semitones(audiodelays_pitch_shift_ob mp_obj_t common_hal_audiodelays_pitch_shift_get_mix(audiodelays_pitch_shift_obj_t *self); void common_hal_audiodelays_pitch_shift_set_mix(audiodelays_pitch_shift_obj_t *self, mp_obj_t arg); +bool common_hal_audiodelays_pitch_shift_get_freeze(audiodelays_pitch_shift_obj_t *self); +void common_hal_audiodelays_pitch_shift_set_freeze(audiodelays_pitch_shift_obj_t *self, bool freeze); + bool common_hal_audiodelays_pitch_shift_get_playing(audiodelays_pitch_shift_obj_t *self); void common_hal_audiodelays_pitch_shift_play(audiodelays_pitch_shift_obj_t *self, mp_obj_t sample, bool loop); void common_hal_audiodelays_pitch_shift_stop(audiodelays_pitch_shift_obj_t *self); diff --git a/shared-bindings/audiodelays/__init__.c b/shared-bindings/audiodelays/__init__.c index e93052eabfd..6ee7a82ab79 100644 --- a/shared-bindings/audiodelays/__init__.c +++ b/shared-bindings/audiodelays/__init__.c @@ -12,7 +12,9 @@ #include "shared-bindings/audiodelays/__init__.h" #include "shared-bindings/audiodelays/Echo.h" #include "shared-bindings/audiodelays/Chorus.h" +#include "shared-bindings/audiodelays/Flanger.h" #include "shared-bindings/audiodelays/PitchShift.h" +#include "shared-bindings/audiodelays/GranularPitchShift.h" #include "shared-bindings/audiodelays/MultiTapDelay.h" //| """Support for audio delay effects @@ -25,7 +27,9 @@ static const mp_rom_map_elem_t audiodelays_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiodelays) }, { MP_ROM_QSTR(MP_QSTR_Echo), MP_ROM_PTR(&audiodelays_echo_type) }, { MP_ROM_QSTR(MP_QSTR_Chorus), MP_ROM_PTR(&audiodelays_chorus_type) }, + { MP_ROM_QSTR(MP_QSTR_Flanger), MP_ROM_PTR(&audiodelays_flanger_type) }, { MP_ROM_QSTR(MP_QSTR_PitchShift), MP_ROM_PTR(&audiodelays_pitch_shift_type) }, + { MP_ROM_QSTR(MP_QSTR_GranularPitchShift), MP_ROM_PTR(&audiodelays_granular_pitch_shift_type) }, { MP_ROM_QSTR(MP_QSTR_MultiTapDelay), MP_ROM_PTR(&audiodelays_multi_tap_delay_type) }, }; diff --git a/shared-bindings/audiofilewriter/AudioFileWriter.c b/shared-bindings/audiofilewriter/AudioFileWriter.c new file mode 100644 index 00000000000..8dbdba5d448 --- /dev/null +++ b/shared-bindings/audiofilewriter/AudioFileWriter.c @@ -0,0 +1,183 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/audiofilewriter/AudioFileWriter.h" +#include "shared-bindings/util.h" + +// ~1 s of 16 kHz mono 16-bit PCM. Sized to absorb a worst-case SD-write stall. +#define AUDIOFILEWRITER_DEFAULT_BUFFER_SIZE (32 * 1024) + +//| class AudioFileWriter: +//| """Streams an audio source to a ``.wav`` file in the background. +//| +//| ``AudioFileWriter`` is the inverse of `audiocore.WaveFile`: rather than being +//| an audio *source* played by an `audioio.AudioOut`, it is a *sink* that +//| drives an audio source (a microphone, ``synthio``, or an ``audiofilters``/ +//| ``audiodelays``/``audiofreeverb``/``audiospeed`` effect chain) and writes +//| the resulting PCM to a file as a WAV. +//| +//| Recording runs on a background pump paced to the source's real-time rate, +//| so it does not block and does not require a Python read loop.""" +//| +//| def __init__(self, file: typing.BinaryIO, *, buffer_size: int = 32768) -> None: +//| """Create an ``AudioFileWriter`` that writes to ``file``. +//| +//| :param typing.BinaryIO file: An already-open writable binary stream +//| (a file opened in ``"wb"`` mode, or an `io.BytesIO`). The stream must +//| support seeking so the WAV header sizes can be patched when recording +//| stops. ``AudioFileWriter`` does not close it; the caller owns it. +//| :param int buffer_size: Size in bytes of the internal RAM ring that +//| decouples file-write latency from the source. Larger values tolerate +//| longer write stalls (e.g. a slow SD card) at the cost of RAM. +//| Minimum valid value, and default, is ``512``. Must be at least the +//| size of the source buffer. +//| +//| The audio format (sample rate, channel count, bit depth) is taken from +//| the source at `play()` time, so there are no format arguments here. +//| +//| Recording synthio to SD:: +//| +//| import time +//| import synthio +//| from audiofilewriter import AudioFileWriter +//| import storage +//| +//| SAMPLE_RATE = 16000 +//| OUTPUT_PATH = "/sd/demo_file.wav" +//| +//| C_major_scale = [60, 62, 64, 65, 67, 69, 71, 72, 71, 69, 67, 65, 64, 62, 60] +//| synth = synthio.Synthesizer(sample_rate=SAMPLE_RATE) +//| +//| with open(OUTPUT_PATH, "wb") as f: +//| writer = AudioFileWriter(f) +//| writer.play(synth) +//| for note in C_major_scale: +//| synth.press(note) +//| time.sleep(0.1) +//| synth.release(note) +//| time.sleep(0.10) +//| writer.stop() +//| print("Done ->", OUTPUT_PATH) +//| """ +//| ... +//| +static mp_obj_t audiofilewriter_audiofilewriter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_file, ARG_buffer_size }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = AUDIOFILEWRITER_DEFAULT_BUFFER_SIZE} }, + }; + 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); + + // A buffer smaller than one source buffer is useless; require a sane floor. + mp_int_t buffer_size = mp_arg_validate_int_min(args[ARG_buffer_size].u_int, 512, MP_QSTR_buffer_size); + + audiofilewriter_audiofilewriter_obj_t *self = mp_obj_malloc(audiofilewriter_audiofilewriter_obj_t, &audiofilewriter_audiofilewriter_type); + common_hal_audiofilewriter_audiofilewriter_construct(self, args[ARG_file].u_obj, (uint32_t)buffer_size); + + return MP_OBJ_FROM_PTR(self); +} + +static void check_for_deinit(audiofilewriter_audiofilewriter_obj_t *self) { + if (common_hal_audiofilewriter_audiofilewriter_deinited(self)) { + raise_deinited_error(); + } +} + +//| def deinit(self) -> None: +//| """Stops recording (patching the WAV header) and releases resources.""" +//| ... +//| +static mp_obj_t audiofilewriter_audiofilewriter_deinit(mp_obj_t self_in) { + audiofilewriter_audiofilewriter_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofilewriter_audiofilewriter_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiofilewriter_audiofilewriter_deinit_obj, audiofilewriter_audiofilewriter_deinit); + +//| def __enter__(self) -> AudioFileWriter: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample) -> None: +//| """Begin recording ``sample`` to the file. Does not block. +//| +//| Writes a WAV header (in the format of ``sample``) and starts the +//| background pump. ``sample`` must be an 8-bit or 16-bit mono or stereo +//| audio source. Use `playing` to tell when a finite source has finished, +//| or call `stop()` to end recording of a continuous source (e.g. a mic).""" +//| ... +//| +static mp_obj_t audiofilewriter_audiofilewriter_obj_play(mp_obj_t self_in, mp_obj_t sample_in) { + audiofilewriter_audiofilewriter_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_audiofilewriter_audiofilewriter_play(self, sample_in); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(audiofilewriter_audiofilewriter_play_obj, audiofilewriter_audiofilewriter_obj_play); + +//| def stop(self) -> None: +//| """Stop recording, flush the RAM ring to the file, and patch the WAV +//| header sizes. The file is left open for the caller to close.""" +//| ... +//| +static mp_obj_t audiofilewriter_audiofilewriter_obj_stop(mp_obj_t self_in) { + audiofilewriter_audiofilewriter_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_audiofilewriter_audiofilewriter_stop(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiofilewriter_audiofilewriter_stop_obj, audiofilewriter_audiofilewriter_obj_stop); + +//| playing: bool +//| """True while recording is in progress. Becomes False on its own when a +//| finite source finishes, or after `stop()`. (read-only)""" +//| +static mp_obj_t audiofilewriter_audiofilewriter_obj_get_playing(mp_obj_t self_in) { + audiofilewriter_audiofilewriter_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiofilewriter_audiofilewriter_get_playing(self)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiofilewriter_audiofilewriter_get_playing_obj, audiofilewriter_audiofilewriter_obj_get_playing); + +MP_PROPERTY_GETTER(audiofilewriter_audiofilewriter_playing_obj, + (mp_obj_t)&audiofilewriter_audiofilewriter_get_playing_obj); + +static const mp_rom_map_elem_t audiofilewriter_audiofilewriter_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiofilewriter_audiofilewriter_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiofilewriter_audiofilewriter_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiofilewriter_audiofilewriter_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiofilewriter_audiofilewriter_playing_obj) }, +}; +static MP_DEFINE_CONST_DICT(audiofilewriter_audiofilewriter_locals_dict, audiofilewriter_audiofilewriter_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + audiofilewriter_audiofilewriter_type, + MP_QSTR_AudioFileWriter, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiofilewriter_audiofilewriter_make_new, + locals_dict, &audiofilewriter_audiofilewriter_locals_dict + ); diff --git a/shared-bindings/audiofilewriter/AudioFileWriter.h b/shared-bindings/audiofilewriter/AudioFileWriter.h new file mode 100644 index 00000000000..22d456979b9 --- /dev/null +++ b/shared-bindings/audiofilewriter/AudioFileWriter.h @@ -0,0 +1,23 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include "shared-module/audiofilewriter/AudioFileWriter.h" + +extern const mp_obj_type_t audiofilewriter_audiofilewriter_type; + +void common_hal_audiofilewriter_audiofilewriter_construct(audiofilewriter_audiofilewriter_obj_t *self, + mp_obj_t file, uint32_t buffer_size); + +void common_hal_audiofilewriter_audiofilewriter_deinit(audiofilewriter_audiofilewriter_obj_t *self); +bool common_hal_audiofilewriter_audiofilewriter_deinited(audiofilewriter_audiofilewriter_obj_t *self); + +void common_hal_audiofilewriter_audiofilewriter_play(audiofilewriter_audiofilewriter_obj_t *self, mp_obj_t sample); +void common_hal_audiofilewriter_audiofilewriter_stop(audiofilewriter_audiofilewriter_obj_t *self); +bool common_hal_audiofilewriter_audiofilewriter_get_playing(audiofilewriter_audiofilewriter_obj_t *self); diff --git a/shared-bindings/audiofilewriter/__init__.c b/shared-bindings/audiofilewriter/__init__.c new file mode 100644 index 00000000000..e67a74b9451 --- /dev/null +++ b/shared-bindings/audiofilewriter/__init__.c @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/audiofilewriter/__init__.h" +#include "shared-bindings/audiofilewriter/AudioFileWriter.h" + +//| """Support for streaming audio to a WAV file""" + +static const mp_rom_map_elem_t audiofilewriter_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiofilewriter) }, + { MP_ROM_QSTR(MP_QSTR_AudioFileWriter), MP_ROM_PTR(&audiofilewriter_audiofilewriter_type) }, +}; + +static MP_DEFINE_CONST_DICT(audiofilewriter_module_globals, audiofilewriter_module_globals_table); + +const mp_obj_module_t audiofilewriter_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&audiofilewriter_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_audiofilewriter, audiofilewriter_module); diff --git a/shared-bindings/audiofilewriter/__init__.h b/shared-bindings/audiofilewriter/__init__.h new file mode 100644 index 00000000000..779b49ffd8d --- /dev/null +++ b/shared-bindings/audiofilewriter/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-bindings/audiofilters/Distortion.c b/shared-bindings/audiofilters/Distortion.c index 8de4c1d1ea3..97f3288acc7 100644 --- a/shared-bindings/audiofilters/Distortion.c +++ b/shared-bindings/audiofilters/Distortion.c @@ -145,8 +145,21 @@ static mp_obj_t audiofilters_distortion_make_new(const mp_obj_type_t *type, size mode = validate_distortion_mode(args[ARG_mode].u_obj, MP_QSTR_mode); } - audiofilters_distortion_obj_t *self = mp_obj_malloc(audiofilters_distortion_obj_t, &audiofilters_distortion_type); - common_hal_audiofilters_distortion_construct(self, args[ARG_drive].u_obj, args[ARG_pre_gain].u_obj, args[ARG_post_gain].u_obj, mode, args[ARG_soft_clip].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + audiofilters_distortion_obj_t *self = + mp_obj_malloc(audiofilters_distortion_obj_t, &audiofilters_distortion_type); + common_hal_audiofilters_distortion_construct(self, + args[ARG_drive].u_obj, + args[ARG_pre_gain].u_obj, + args[ARG_post_gain].u_obj, + mode, + args[ARG_soft_clip].u_bool, + args[ARG_mix].u_obj, + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiofilters/Filter.c b/shared-bindings/audiofilters/Filter.c index 426fff22616..2d0d12b226a 100644 --- a/shared-bindings/audiofilters/Filter.c +++ b/shared-bindings/audiofilters/Filter.c @@ -91,7 +91,14 @@ static mp_obj_t audiofilters_filter_make_new(const mp_obj_type_t *type, size_t n } audiofilters_filter_obj_t *self = mp_obj_malloc(audiofilters_filter_obj_t, &audiofilters_filter_type); - common_hal_audiofilters_filter_construct(self, args[ARG_filter].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + common_hal_audiofilters_filter_construct(self, + args[ARG_filter].u_obj, + args[ARG_mix].u_obj, + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiofilters/Phaser.c b/shared-bindings/audiofilters/Phaser.c index 9f713afce5f..2aed9623b72 100644 --- a/shared-bindings/audiofilters/Phaser.c +++ b/shared-bindings/audiofilters/Phaser.c @@ -91,7 +91,16 @@ static mp_obj_t audiofilters_phaser_make_new(const mp_obj_type_t *type, size_t n } audiofilters_phaser_obj_t *self = mp_obj_malloc(audiofilters_phaser_obj_t, &audiofilters_phaser_type); - common_hal_audiofilters_phaser_construct(self, args[ARG_frequency].u_obj, args[ARG_feedback].u_obj, args[ARG_mix].u_obj, args[ARG_stages].u_int, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + common_hal_audiofilters_phaser_construct(self, + args[ARG_frequency].u_obj, + args[ARG_feedback].u_obj, + args[ARG_mix].u_obj, + args[ARG_stages].u_int, + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiofreeverb/Freeverb.c b/shared-bindings/audiofreeverb/Freeverb.c index 12eb7ef70ab..83c9eb7c01f 100644 --- a/shared-bindings/audiofreeverb/Freeverb.c +++ b/shared-bindings/audiofreeverb/Freeverb.c @@ -24,6 +24,8 @@ //| self, //| roomsize: synthio.BlockInput = 0.5, //| damp: synthio.BlockInput = 0.5, +//| pre_filter: Optional[synthio.Biquad | Tuple[synthio.Biquad]] = None, +//| post_filter: Optional[synthio.Biquad | Tuple[synthio.Biquad]] = None, //| mix: synthio.BlockInput = 0.5, //| buffer_size: int = 512, //| sample_rate: int = 8000, @@ -40,6 +42,8 @@ //| //| :param synthio.BlockInput roomsize: The size of the room. 0.0 = smallest; 1.0 = largest. //| :param synthio.BlockInput damp: How much the walls absorb. 0.0 = least; 1.0 = most. +//| :param Optional[synthio.Biquad|Tuple[synthio.Biquad]] pre_filter: A normalized biquad filter object or tuple of normalized biquad filter objects. The sample is processed sequentially by each "Pre-EQ" filter before being fed to the reverb effect. +//| :param Optional[synthio.Biquad|Tuple[synthio.Biquad]] post_filter: A normalized biquad filter object or tuple of normalized biquad filter objects. The output of the reverb effect is processed sequentially by each "Post-EQ" filter before being mixed with the original sample. //| :param synthio.BlockInput mix: The mix as a ratio of the sample (0.0) to the effect (1.0). //| :param int buffer_size: The total size in bytes of each of the two playback buffers to use //| :param int sample_rate: The sample rate to be used @@ -70,10 +74,12 @@ //| ... //| static mp_obj_t audiofreeverb_freeverb_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_roomsize, ARG_damp, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + enum { ARG_roomsize, ARG_damp, ARG_pre_filter, ARG_post_filter, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_roomsize, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_damp, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_pre_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } }, + { MP_QSTR_post_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } }, { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, @@ -96,7 +102,7 @@ static mp_obj_t audiofreeverb_freeverb_make_new(const mp_obj_type_t *type, size_ } audiofreeverb_freeverb_obj_t *self = mp_obj_malloc(audiofreeverb_freeverb_obj_t, &audiofreeverb_freeverb_type); - common_hal_audiofreeverb_freeverb_construct(self, args[ARG_roomsize].u_obj, args[ARG_damp].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + common_hal_audiofreeverb_freeverb_construct(self, args[ARG_roomsize].u_obj, args[ARG_damp].u_obj, args[ARG_pre_filter].u_obj, args[ARG_post_filter].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); return MP_OBJ_FROM_PTR(self); } @@ -165,6 +171,51 @@ MP_PROPERTY_GETSET(audiofreeverb_freeverb_damp_obj, (mp_obj_t)&audiofreeverb_freeverb_get_damp_obj, (mp_obj_t)&audiofreeverb_freeverb_set_damp_obj); + +//| pre_filter: synthio.Biquad | Tuple[synthio.Biquad] | None +//| """A normalized biquad filter object or tuple of normalized biquad filter objects. The sample is processed sequentially by each "Pre-EQ" filter before being fed to the reverb effect.""" +//| +static mp_obj_t audiofreeverb_freeverb_obj_get_pre_filter(mp_obj_t self_in) { + audiofreeverb_freeverb_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_audiofreeverb_freeverb_get_pre_filter(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofreeverb_freeverb_get_pre_filter_obj, audiofreeverb_freeverb_obj_get_pre_filter); + +static mp_obj_t audiofreeverb_freeverb_obj_set_pre_filter(mp_obj_t self_in, mp_obj_t filter_in) { + audiofreeverb_freeverb_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofreeverb_freeverb_set_pre_filter(self, filter_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiofreeverb_freeverb_set_pre_filter_obj, audiofreeverb_freeverb_obj_set_pre_filter); + +MP_PROPERTY_GETSET(audiofreeverb_freeverb_pre_filter_obj, + (mp_obj_t)&audiofreeverb_freeverb_get_pre_filter_obj, + (mp_obj_t)&audiofreeverb_freeverb_set_pre_filter_obj); + + +//| post_filter: synthio.Biquad | Tuple[synthio.Biquad] | None +//| """A normalized biquad filter object or tuple of normalized biquad filter objects. The output of the reverb effect is processed sequentially by each "Post-EQ" filter before being mixed with the original sample.""" +//| +static mp_obj_t audiofreeverb_freeverb_obj_get_post_filter(mp_obj_t self_in) { + audiofreeverb_freeverb_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_audiofreeverb_freeverb_get_post_filter(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofreeverb_freeverb_get_post_filter_obj, audiofreeverb_freeverb_obj_get_post_filter); + +static mp_obj_t audiofreeverb_freeverb_obj_set_post_filter(mp_obj_t self_in, mp_obj_t filter_in) { + audiofreeverb_freeverb_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofreeverb_freeverb_set_post_filter(self, filter_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiofreeverb_freeverb_set_post_filter_obj, audiofreeverb_freeverb_obj_set_post_filter); + +MP_PROPERTY_GETSET(audiofreeverb_freeverb_post_filter_obj, + (mp_obj_t)&audiofreeverb_freeverb_get_post_filter_obj, + (mp_obj_t)&audiofreeverb_freeverb_set_post_filter_obj); + + //| mix: synthio.BlockInput //| """The rate the reverb mix between 0 and 1 where 0 is only sample and 1 is all effect.""" static mp_obj_t audiofreeverb_freeverb_obj_get_mix(mp_obj_t self_in) { @@ -251,6 +302,8 @@ static const mp_rom_map_elem_t audiofreeverb_freeverb_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiofreeverb_freeverb_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_roomsize), MP_ROM_PTR(&audiofreeverb_freeverb_roomsize_obj) }, { MP_ROM_QSTR(MP_QSTR_damp), MP_ROM_PTR(&audiofreeverb_freeverb_damp_obj) }, + { MP_ROM_QSTR(MP_QSTR_pre_filter), MP_ROM_PTR(&audiofreeverb_freeverb_pre_filter_obj) }, + { MP_ROM_QSTR(MP_QSTR_post_filter), MP_ROM_PTR(&audiofreeverb_freeverb_post_filter_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiofreeverb_freeverb_mix_obj) }, AUDIOSAMPLE_FIELDS, }; diff --git a/shared-bindings/audiofreeverb/Freeverb.h b/shared-bindings/audiofreeverb/Freeverb.h index 913953ebecf..7eed9775006 100644 --- a/shared-bindings/audiofreeverb/Freeverb.h +++ b/shared-bindings/audiofreeverb/Freeverb.h @@ -11,23 +11,25 @@ extern const mp_obj_type_t audiofreeverb_freeverb_type; void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *self, - mp_obj_t roomsize, mp_obj_t damp, mp_obj_t mix, + mp_obj_t roomsize, mp_obj_t damp, mp_obj_t pre_filter, mp_obj_t post_filter, mp_obj_t mix, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate); void common_hal_audiofreeverb_freeverb_deinit(audiofreeverb_freeverb_obj_t *self); bool common_hal_audiofreeverb_freeverb_deinited(audiofreeverb_freeverb_obj_t *self); -uint32_t common_hal_audiofreeverb_freeverb_get_sample_rate(audiofreeverb_freeverb_obj_t *self); -uint8_t common_hal_audiofreeverb_freeverb_get_channel_count(audiofreeverb_freeverb_obj_t *self); -uint8_t common_hal_audiofreeverb_freeverb_get_bits_per_sample(audiofreeverb_freeverb_obj_t *self); - mp_obj_t common_hal_audiofreeverb_freeverb_get_roomsize(audiofreeverb_freeverb_obj_t *self); void common_hal_audiofreeverb_freeverb_set_roomsize(audiofreeverb_freeverb_obj_t *self, mp_obj_t feedback); mp_obj_t common_hal_audiofreeverb_freeverb_get_damp(audiofreeverb_freeverb_obj_t *self); void common_hal_audiofreeverb_freeverb_set_damp(audiofreeverb_freeverb_obj_t *self, mp_obj_t damp); +mp_obj_t common_hal_audiofreeverb_freeverb_get_pre_filter(audiofreeverb_freeverb_obj_t *self); +void common_hal_audiofreeverb_freeverb_set_pre_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t arg); + +mp_obj_t common_hal_audiofreeverb_freeverb_get_post_filter(audiofreeverb_freeverb_obj_t *self); +void common_hal_audiofreeverb_freeverb_set_post_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t arg); + mp_obj_t common_hal_audiofreeverb_freeverb_get_mix(audiofreeverb_freeverb_obj_t *self); void common_hal_audiofreeverb_freeverb_set_mix(audiofreeverb_freeverb_obj_t *self, mp_obj_t mix); diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c new file mode 100644 index 00000000000..22f1fb2aaad --- /dev/null +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -0,0 +1,361 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "extmod/vfs_fat.h" +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/mphal.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audioi2sin/I2SIn.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-module/audiocore/__init__.h" +#include "shared-bindings/util.h" + +//| class I2SIn: +//| """Record an input I2S audio stream from an external I2S source such as a MEMS microphone.""" +//| +//| def __init__( +//| self, +//| bit_clock: microcontroller.Pin, +//| word_select: microcontroller.Pin, +//| data: microcontroller.Pin, +//| *, +//| main_clock: Optional[microcontroller.Pin] = None, +//| sample_rate: int = 16000, +//| bit_depth: int = 16, +//| output_bit_depth: Optional[int] = None, +//| mono: bool = True, +//| left_justified: bool = False, +//| samples_signed: bool = True, +//| external_clock: bool = False, +//| ) -> None: +//| """Create an I2SIn object associated with the given pins. This allows you to +//| record audio signals from an external I2S source (e.g. an I2S MEMS microphone +//| like the SPH0645LM4H or INMP441). +//| +//| The pin signature mirrors `audiobusio.I2SOut` so users can swap classes; +//| recording parameters mirror `audiobusio.PDMIn`. +//| +//| :param ~microcontroller.Pin bit_clock: The bit clock (or serial clock) pin +//| :param ~microcontroller.Pin word_select: The word select (or left/right clock) pin +//| :param ~microcontroller.Pin data: The data input pin +//| :param ~microcontroller.Pin main_clock: The main clock pin. Not all ports support this. +//| :param int sample_rate: Target sample rate of the resulting samples. Check `sample_rate` for actual value. +//| :param int bit_depth: Number of bits per sample on the I2S bus. Must be 8, 16, 24, or +//| 32. 8-bit only supported on espressif. The destination buffer typecode is determined +//| by ``output_bit_depth`` (or ``bit_depth`` when ``output_bit_depth`` is ``None``): +//| +//| +----------------+------------------+----------------------+ +//| | samples_signed | output_bit_depth | Required typecode(s) | +//| +================+==================+======================+ +//| | True | 24 or 32 | ``'i'`` | +//| +----------------+------------------+----------------------+ +//| | True | 16 | ``'h'`` | +//| +----------------+------------------+----------------------+ +//| | True | 8 | ``'b'`` or BYTEARRAY | +//| +----------------+------------------+----------------------+ +//| | False | 24 or 32 | ``'I'`` | +//| +----------------+------------------+----------------------+ +//| | False | 16 | ``'H'`` | +//| +----------------+------------------+----------------------+ +//| | False | 8 | ``'B'`` or BYTEARRAY | +//| +----------------+------------------+----------------------+ +//| +//| Note that 24-bit samples from mics like the SPH0645LM4H / INMP441 are +//| transported in 32-bit slots, so use ``bit_depth=32`` and an ``'I'`` buffer. +//| :param int output_bit_depth: If set, recorded samples are rescaled from +//| ``bit_depth`` to this width before being written to the destination buffer +//| (8, 16, 24, or 32). Widening bit-replicates so full-scale input maps to +//| full-scale output (e.g. 16-bit ``0xFFFF`` -> 24-bit ``0xFFFFFF``); narrowing +//| arithmetic-shifts the value right (sign-preserving when ``samples_signed`` is +//| True). When ``None`` (the default) the destination buffer holds samples at +//| ``bit_depth`` (a 24-bit sample still occupies a 32-bit ``'i'``/``'I'`` slot, +//| sign-extended without rescaling). +//| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise. +//| :param bool left_justified: True when data bits are aligned with the word select clock. False +//| when they are shifted by one to match classic I2S protocol. Set True for mics like the SPH0645LM4H. +//| :param bool samples_signed: Samples are signed (True) or unsigned (False). I2S mics deliver signed +//| two's-complement PCM natively; set False to have the recorded samples converted to unsigned PCM +//| (the top/sign bit is flipped, matching the WAV convention for unsigned samples). +//| :param bool external_clock: True when this object follows an externally supplied clock: +//| ``bit_clock`` and ``word_select`` are inputs driven by something else. Like an +//| `audiobusio.I2SOut` object (the clock source), or a codec, rather than generated by +//| this object. Not supported on all ports. +//| +//| In external clock mode ``bit_clock`` and ``word_select`` do not have to be sequential +//| GPIOs, and they may be shared with another I2S object. ``sample_rate`` becomes a +//| declaration rather than a measurement: the real rate is whatever the external word select +//| runs at, and `sample_rate` still reports the declared value. If the incoming clock stops, +//| `record` blocks (interruptible with Ctrl-C). +//| +//| Example, recording 16-bit mono samples from an INMP441:: +//| +//| import array +//| import audioi2sin +//| import board +//| +//| buf = array.array("h", [0] * 16000) +//| with audioi2sin.I2SIn(board.D9, board.D10, board.D11, +//| sample_rate=16000, bit_depth=16) as mic: +//| mic.record(buf, len(buf)) +//| +//| """ +//| ... +//| +static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + #if !CIRCUITPY_AUDIOI2SIN + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_I2SIn); + return NULL; // Not reachable. + #else + enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, + ARG_sample_rate, ARG_bit_depth, ARG_output_bit_depth, + ARG_mono, ARG_left_justified, ARG_samples_signed, + ARG_external_clock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bit_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_word_select, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_main_clock, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_sample_rate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16000} }, + { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, + { MP_QSTR_output_bit_depth, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_left_justified, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_samples_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_external_clock, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + bool external_clock = args[ARG_external_clock].u_bool; + + // In external clock mode the clock pins are only read, so they may already + // be owned by whatever is driving them; let the port decide if the sharing + // is legal. + const mcu_pin_obj_t *bit_clock = external_clock + ? validate_obj_is_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock) + : validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); + const mcu_pin_obj_t *word_select = external_clock + ? validate_obj_is_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select) + : validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); + const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj, MP_QSTR_data); + const mcu_pin_obj_t *main_clock = validate_obj_is_free_pin_or_none(args[ARG_main_clock].u_obj, MP_QSTR_main_clock); + + uint32_t sample_rate = args[ARG_sample_rate].u_int; + uint8_t bit_depth = args[ARG_bit_depth].u_int; + if (bit_depth != 8 && bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be 8, 16, 24, or 32"), MP_QSTR_bit_depth); + } + uint8_t output_bit_depth; + mp_obj_t output_bit_depth_obj = args[ARG_output_bit_depth].u_obj; + if (output_bit_depth_obj == mp_const_none) { + output_bit_depth = bit_depth; + } else { + mp_int_t v = mp_obj_get_int(output_bit_depth_obj); + if (v != 8 && v != 16 && v != 24 && v != 32) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be 8, 16, 24, or 32"), MP_QSTR_output_bit_depth); + } + output_bit_depth = (uint8_t)v; + } + bool mono = args[ARG_mono].u_bool; + bool left_justified = args[ARG_left_justified].u_bool; + bool samples_signed = args[ARG_samples_signed].u_bool; + + audioi2sin_i2sin_obj_t *self = mp_obj_malloc_with_finaliser(audioi2sin_i2sin_obj_t, &audioi2sin_i2sin_type); + common_hal_audioi2sin_i2sin_construct(self, bit_clock, word_select, data, main_clock, + sample_rate, bit_depth, output_bit_depth, mono, left_justified, samples_signed, + external_clock); + + return MP_OBJ_FROM_PTR(self); + #endif +} + +#if CIRCUITPY_AUDIOI2SIN +//| def deinit(self) -> None: +//| """Deinitialises the I2SIn and releases any hardware resources for reuse.""" +//| ... +//| +static mp_obj_t audioi2sin_i2sin_deinit(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audioi2sin_i2sin_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_deinit_obj, audioi2sin_i2sin_deinit); + +static void check_for_deinit(audioi2sin_i2sin_obj_t *self) { + if (common_hal_audioi2sin_i2sin_deinited(self)) { + raise_deinited_error(); + } +} + +//| def __enter__(self) -> I2SIn: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def record(self, destination: WriteableBuffer, destination_length: int) -> int: +//| """Records destination_length samples to destination. This is blocking. +//| +//| :return: The number of samples recorded. If this is less than ``destination_length``, +//| some samples were missed due to processing time.""" +//| ... +//| +static mp_obj_t audioi2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destination, mp_obj_t destination_length) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_obj); + check_for_deinit(self); + uint32_t length = mp_arg_validate_type_int(destination_length, MP_QSTR_length); + mp_arg_validate_length_min(length, 0, MP_QSTR_length); + + mp_buffer_info_t bufinfo; + if (mp_obj_is_type(destination, &mp_type_fileio)) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("Cannot record to a file")); + } + mp_get_buffer_raise(destination, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { + mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); + } + uint8_t output_bit_depth = self->base.bits_per_sample; + char error_type = ' '; + bool samples_signed = common_hal_audioi2sin_i2sin_get_samples_signed(self); + if (samples_signed) { + if ((output_bit_depth == 24 || output_bit_depth == 32) && bufinfo.typecode != 'i') { + error_type = 'i'; + } else if (output_bit_depth == 16 && bufinfo.typecode != 'h') { + error_type = 'h'; + } else if (output_bit_depth == 8 && bufinfo.typecode != 'b' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + error_type = 'b'; // NOTE: Not identifying as bytearray + } + } else { + if ((output_bit_depth == 24 || output_bit_depth == 32) && bufinfo.typecode != 'I') { + error_type = 'I'; + } else if (output_bit_depth == 16 && bufinfo.typecode != 'H') { + error_type = 'H'; + } else if (output_bit_depth == 8 && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + error_type = 'B'; + } + } + if (error_type != ' ') { + mp_raise_TypeError_varg( + MP_ERROR_TEXT("invalid destination buffer, must be an array of type: %c"), + error_type + ); + } + uint32_t length_written = + common_hal_audioi2sin_i2sin_record_to_buffer(self, bufinfo.buf, length); + return MP_OBJ_NEW_SMALL_INT(length_written); +} +MP_DEFINE_CONST_FUN_OBJ_3(audioi2sin_i2sin_record_obj, audioi2sin_i2sin_obj_record); + +//| sample_rate: int +//| """The configured (nominal) sample rate, in Hz. This is the rate reported to +//| the audio pipeline so it matches the output/consumer it is played into. The +//| true capture rate may differ from this by a fraction of a Hz due to internal +//| clock limitations.""" +//| +//| bits_per_sample: int +//| """The number of bits per sample as it is streamed through the audio pipeline. +//| (read-only)""" +//| +//| channel_count: int +//| """The number of channels (1 for mono, 2 for stereo). (read-only)""" +//| + +//| bit_depth: int +//| """The actual bit depth of the recording. (read-only)""" +//| +//| +static mp_obj_t audioi2sin_i2sin_obj_get_bit_depth(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioi2sin_i2sin_get_bit_depth(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_bit_depth_obj, audioi2sin_i2sin_obj_get_bit_depth); + +MP_PROPERTY_GETTER(audioi2sin_i2sin_bit_depth_obj, + (mp_obj_t)&audioi2sin_i2sin_get_bit_depth_obj); + + +//| samples_signed: bool +//| """True if recorded samples are signed PCM, False for unsigned. (read-only)""" +//| +//| +static mp_obj_t audioi2sin_i2sin_obj_get_samples_signed(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audioi2sin_i2sin_get_samples_signed(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_samples_signed_obj, audioi2sin_i2sin_obj_get_samples_signed); + +MP_PROPERTY_GETTER(audioi2sin_i2sin_samples_signed_obj, + (mp_obj_t)&audioi2sin_i2sin_get_samples_signed_obj); + + +//| overflow: bool +//| """True if samples were dropped because they were not read fast enough, +//| since the last time this was checked. (read-only) +//| +//| Reading this clears the flag, so it reports whether an overflow happened +//| in the interval since the previous read rather than at any time in the +//| past. `record` and streaming playback both set it; a streaming consumer +//| has no other way to notice it is falling behind. +//| +//| Not all ports can detect overflow; those report False always.""" +//| +//| +static mp_obj_t audioi2sin_i2sin_obj_get_overflow(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audioi2sin_i2sin_get_overflow(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_overflow_obj, audioi2sin_i2sin_obj_get_overflow); + +MP_PROPERTY_GETTER(audioi2sin_i2sin_overflow_obj, + (mp_obj_t)&audioi2sin_i2sin_get_overflow_obj); + +static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&audioi2sin_i2sin_record_obj) }, + // sample_rate / bits_per_sample / channel_count come from the audiosample + // protocol's shared property getters. + AUDIOSAMPLE_FIELDS, + { MP_ROM_QSTR(MP_QSTR_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_bit_depth_obj) }, + { MP_ROM_QSTR(MP_QSTR_samples_signed), MP_ROM_PTR(&audioi2sin_i2sin_samples_signed_obj) }, + { MP_ROM_QSTR(MP_QSTR_overflow), MP_ROM_PTR(&audioi2sin_i2sin_overflow_obj) }, +}; +static MP_DEFINE_CONST_DICT(audioi2sin_i2sin_locals_dict, audioi2sin_i2sin_locals_dict_table); + +static const audiosample_p_t audioi2sin_i2sin_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)common_hal_audioi2sin_i2sin_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)common_hal_audioi2sin_i2sin_get_buffer, +}; +#endif // CIRCUITPY_AUDIOI2SIN + +MP_DEFINE_CONST_OBJ_TYPE( + audioi2sin_i2sin_type, + MP_QSTR_I2SIn, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audioi2sin_i2sin_make_new + #if CIRCUITPY_AUDIOI2SIN + , locals_dict, &audioi2sin_i2sin_locals_dict + , protocol, &audioi2sin_i2sin_proto + #endif + ); diff --git a/shared-bindings/audioi2sin/I2SIn.h b/shared-bindings/audioi2sin/I2SIn.h new file mode 100644 index 00000000000..25f5489015d --- /dev/null +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -0,0 +1,45 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-bindings/microcontroller/Pin.h" + +#if CIRCUITPY_AUDIOI2SIN +#include "common-hal/audioi2sin/I2SIn.h" +#include "shared-module/audiocore/__init__.h" +#endif + +extern const mp_obj_type_t audioi2sin_i2sin_type; + +#if CIRCUITPY_AUDIOI2SIN +void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, + const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, + uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, + bool mono, bool left_justified, bool samples_signed, + bool external_clock); +void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self); +bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self); +uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, + void *buffer, uint32_t length); +uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self); +uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self); +bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self); +// Reads and clears the sticky "samples were dropped" flag. +bool common_hal_audioi2sin_i2sin_get_overflow(audioi2sin_i2sin_obj_t *self); + +// audiosample protocol: streaming source support. fill_buffer converts the +// frames currently available from the live mic into `buffer` (output depth, +// interleaved), padding with silence on underrun; it never blocks. +void common_hal_audioi2sin_i2sin_fill_buffer(audioi2sin_i2sin_obj_t *self, + uint8_t *buffer, uint32_t frames); +void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, + bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t common_hal_audioi2sin_i2sin_get_buffer( + audioi2sin_i2sin_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length); +#endif diff --git a/shared-bindings/audioi2sin/__init__.c b/shared-bindings/audioi2sin/__init__.c new file mode 100644 index 00000000000..45ba16cb01a --- /dev/null +++ b/shared-bindings/audioi2sin/__init__.c @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audioi2sin/__init__.h" +#include "shared-bindings/audioi2sin/I2SIn.h" + +//| """Support for recording audio from an I2S input source. +//| +//| The `audioi2sin` module contains the `I2SIn` class for recording audio +//| from an external I2S source such as a MEMS microphone (e.g. SPH0645LM4H +//| or INMP441). +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed. To do so, either call :py:meth:`!deinit` or use a +//| context manager.""" + +static const mp_rom_map_elem_t audioi2sin_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audioi2sin) }, + { MP_ROM_QSTR(MP_QSTR_I2SIn), MP_ROM_PTR(&audioi2sin_i2sin_type) }, +}; + +static MP_DEFINE_CONST_DICT(audioi2sin_module_globals, audioi2sin_module_globals_table); + +const mp_obj_module_t audioi2sin_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&audioi2sin_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_audioi2sin, audioi2sin_module); diff --git a/shared-bindings/audioi2sin/__init__.h b/shared-bindings/audioi2sin/__init__.h new file mode 100644 index 00000000000..779b49ffd8d --- /dev/null +++ b/shared-bindings/audioi2sin/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-bindings/audioio/AudioOut.c b/shared-bindings/audioio/AudioOut.c index 82aecefa370..8ea068ceb8f 100644 --- a/shared-bindings/audioio/AudioOut.c +++ b/shared-bindings/audioio/AudioOut.c @@ -103,7 +103,10 @@ static mp_obj_t audioio_audioout_make_new(const mp_obj_type_t *type, size_t n_ar // create AudioOut object from the given pin audioio_audioout_obj_t *self = mp_obj_malloc_with_finaliser(audioio_audioout_obj_t, &audioio_audioout_type); - common_hal_audioio_audioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int); + common_hal_audioio_audioout_construct(self, + left_channel_pin, + right_channel_pin, + args[ARG_quiescent_value].u_int); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiomixer/Mixer.c b/shared-bindings/audiomixer/Mixer.c index 516d079cd2a..89f0e3479da 100644 --- a/shared-bindings/audiomixer/Mixer.c +++ b/shared-bindings/audiomixer/Mixer.c @@ -185,10 +185,8 @@ static mp_obj_t audiomixer_mixer_obj_play(size_t n_args, const mp_obj_t *pos_arg 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 v = args[ARG_voice].u_int; - if (v > (self->voice_count - 1)) { - mp_arg_error_invalid(MP_QSTR_voice); - } + uint8_t v = mp_arg_validate_int_range(args[ARG_voice].u_int, 0, self->voice_count - 1, + MP_QSTR_voice); audiomixer_mixervoice_obj_t *voice = MP_OBJ_TO_PTR(self->voice[v]); mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiomixer_mixervoice_play(voice, sample, args[ARG_loop].u_bool); @@ -212,10 +210,8 @@ static mp_obj_t audiomixer_mixer_obj_stop_voice(size_t n_args, const mp_obj_t *p 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 v = args[ARG_voice].u_int; - if (v > (self->voice_count - 1)) { - mp_arg_error_invalid(MP_QSTR_voice); - } + uint8_t v = mp_arg_validate_int_range(args[ARG_voice].u_int, 0, self->voice_count - 1, + MP_QSTR_voice); audiomixer_mixervoice_obj_t *voice = MP_OBJ_TO_PTR(self->voice[v]); common_hal_audiomixer_mixervoice_stop(voice); return mp_const_none; diff --git a/shared-bindings/audiomixer/MixerVoice.c b/shared-bindings/audiomixer/MixerVoice.c index 128c214d447..4957fab3884 100644 --- a/shared-bindings/audiomixer/MixerVoice.c +++ b/shared-bindings/audiomixer/MixerVoice.c @@ -29,8 +29,8 @@ // TODO: support mono or stereo voices static mp_obj_t audiomixer_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { mp_arg_check_num(n_args, n_kw, 0, 0, false); - audiomixer_mixervoice_obj_t *self = mp_obj_malloc(audiomixer_mixervoice_obj_t, &audiomixer_mixervoice_type); + audiomixer_mixervoice_obj_t *self = mp_obj_malloc(audiomixer_mixervoice_obj_t, &audiomixer_mixervoice_type); common_hal_audiomixer_mixervoice_construct(self); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/audiomixer/MixerVoice.h b/shared-bindings/audiomixer/MixerVoice.h index d60820f7f57..89c87218e7c 100644 --- a/shared-bindings/audiomixer/MixerVoice.h +++ b/shared-bindings/audiomixer/MixerVoice.h @@ -14,6 +14,7 @@ extern const mp_obj_type_t audiomixer_mixervoice_type; void common_hal_audiomixer_mixervoice_construct(audiomixer_mixervoice_obj_t *self); void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t *self, audiomixer_mixer_obj_t *parent); void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_audiomixer_mixervoice_reset_buffer(audiomixer_mixervoice_obj_t *self); void common_hal_audiomixer_mixervoice_stop(audiomixer_mixervoice_obj_t *self); void common_hal_audiomixer_mixervoice_end(audiomixer_mixervoice_obj_t *self); mp_obj_t common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t *self); diff --git a/shared-bindings/audiomp3/MP3Decoder.c b/shared-bindings/audiomp3/MP3Decoder.c index ff6c77e8572..433b308c156 100644 --- a/shared-bindings/audiomp3/MP3Decoder.c +++ b/shared-bindings/audiomp3/MP3Decoder.c @@ -91,8 +91,6 @@ static mp_obj_t audiomp3_mp3file_make_new(const mp_obj_type_t *type, size_t n_ar stream = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), stream, MP_ROM_QSTR(MP_QSTR_rb)); } - audiomp3_mp3file_obj_t *self = mp_obj_malloc_with_finaliser(audiomp3_mp3file_obj_t, &audiomp3_mp3file_type); - const mp_stream_p_t *stream_p = mp_get_stream_raise(stream, MP_STREAM_OP_READ); if (stream_p->is_text) { @@ -106,6 +104,8 @@ static mp_obj_t audiomp3_mp3file_make_new(const mp_obj_type_t *type, size_t n_ar buffer = bufinfo.buf; buffer_size = bufinfo.len; } + + audiomp3_mp3file_obj_t *self = mp_obj_malloc_with_finaliser(audiomp3_mp3file_obj_t, &audiomp3_mp3file_type); common_hal_audiomp3_mp3file_construct(self, stream, buffer, buffer_size); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/audiomp3/MP3Decoder.h b/shared-bindings/audiomp3/MP3Decoder.h index 0b485b4bca1..e316b061248 100644 --- a/shared-bindings/audiomp3/MP3Decoder.h +++ b/shared-bindings/audiomp3/MP3Decoder.h @@ -19,5 +19,5 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t *self, void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t stream); void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self); -float common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t *self); +mp_float_t common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t *self); uint32_t common_hal_audiomp3_mp3file_get_samples_decoded(audiomp3_mp3file_obj_t *self); diff --git a/shared-bindings/audiopwmio/PWMAudioOut.c b/shared-bindings/audiopwmio/PWMAudioOut.c index 3c961433641..5b8d071924b 100644 --- a/shared-bindings/audiopwmio/PWMAudioOut.c +++ b/shared-bindings/audiopwmio/PWMAudioOut.c @@ -100,8 +100,10 @@ static mp_obj_t audiopwmio_pwmaudioout_make_new(const mp_obj_type_t *type, size_ // create AudioOut object from the given pin // The object is created with a finaliser as some ports use these (rather than 'reset' functions) // to ensure resources are collected at interpreter shutdown. - audiopwmio_pwmaudioout_obj_t *self = mp_obj_malloc_with_finaliser(audiopwmio_pwmaudioout_obj_t, &audiopwmio_pwmaudioout_type); - common_hal_audiopwmio_pwmaudioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int); + audiopwmio_pwmaudioout_obj_t *self = + mp_obj_malloc_with_finaliser(audiopwmio_pwmaudioout_obj_t, &audiopwmio_pwmaudioout_type); + common_hal_audiopwmio_pwmaudioout_construct(self, + left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiospeed/Resampler.c b/shared-bindings/audiospeed/Resampler.c new file mode 100644 index 00000000000..8abf52905d4 --- /dev/null +++ b/shared-bindings/audiospeed/Resampler.c @@ -0,0 +1,113 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/audiospeed/Resampler.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/util.h" +#include "shared-module/audiospeed/Resampler.h" + +//| class Resampler: +//| """Wraps an audio sample to match it to the destination sample rate.""" +//| +//| def __init__(self) -> None: +//| """Create a Resampler that wraps ``source``. +//| +//| :param audiosample source: The audio source to resample. +//| +//| Playing a wave file through a mixer with half the sample rate:: +//| +//| import board +//| import audiocore +//| import audiomixer +//| import audiospeed +//| import audioio +//| +//| wav = audiocore.WaveFile("sample.wav") +//| resampler = audiospeed.Resampler(wav) +//| mixer = audiomixer.Mixer( +//| channel_count=wav.channel_count, +//| bits_per_sample=wav.bits_per_sample, +//| sample_rate=wav.sample_rate // 2, +//| ) +//| audio = audioio.AudioOut(board.A0) +//| audio.play(mixer) +//| mixer.play(resampler) +//| """ +//| ... +//| +static mp_obj_t audiospeed_resampler_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_source }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_source, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + 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); + + // Validate source implements audiosample protocol + mp_obj_t source = args[ARG_source].u_obj; + audiosample_check(source); + + audiospeed_resampler_obj_t *self = mp_obj_malloc(audiospeed_resampler_obj_t, &audiospeed_resampler_type); + common_hal_audiospeed_resampler_construct(self, source); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the Resampler and releases all memory resources for reuse.""" +//| ... +//| +static mp_obj_t audiospeed_resampler_deinit(mp_obj_t self_in) { + audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiospeed_resampler_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_resampler_deinit_obj, audiospeed_resampler_deinit); + +//| rate: float +//| """Playback speed multiplier.""" +//| +static mp_obj_t audiospeed_resampler_obj_get_rate(mp_obj_t self_in) { + audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(&self->base.base); + return common_hal_audiospeed_resampler_get_rate(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_resampler_get_rate_obj, audiospeed_resampler_obj_get_rate); + +MP_PROPERTY_GETTER(audiospeed_resampler_rate_obj, + (mp_obj_t)&audiospeed_resampler_get_rate_obj); + +static const mp_rom_map_elem_t audiospeed_resampler_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiospeed_resampler_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiospeed_resampler_rate_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(audiospeed_resampler_locals_dict, audiospeed_resampler_locals_dict_table); + +static const audiosample_p_t audiospeed_resampler_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audiospeed_resampler_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiospeed_resampler_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + audiospeed_resampler_type, + MP_QSTR_Resampler, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiospeed_resampler_make_new, + locals_dict, &audiospeed_resampler_locals_dict, + protocol, &audiospeed_resampler_proto + ); diff --git a/shared-bindings/audiospeed/Resampler.h b/shared-bindings/audiospeed/Resampler.h new file mode 100644 index 00000000000..7a744474bd1 --- /dev/null +++ b/shared-bindings/audiospeed/Resampler.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiospeed/Resampler.h" + +extern const mp_obj_type_t audiospeed_resampler_type; + +void common_hal_audiospeed_resampler_construct(audiospeed_resampler_obj_t *self, mp_obj_t source); +void common_hal_audiospeed_resampler_deinit(audiospeed_resampler_obj_t *self); + +mp_obj_t common_hal_audiospeed_resampler_get_rate(audiospeed_resampler_obj_t *self); + +void audiospeed_resampler_set_sample_rate(audiospeed_resampler_obj_t *self, uint32_t sample_rate); diff --git a/shared-bindings/audiospeed/SpeedChanger.c b/shared-bindings/audiospeed/SpeedChanger.c new file mode 100644 index 00000000000..bcac6b7ff20 --- /dev/null +++ b/shared-bindings/audiospeed/SpeedChanger.c @@ -0,0 +1,123 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/audiospeed/SpeedChanger.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/util.h" +#include "shared-module/audiospeed/__init__.h" +#include "shared-module/audiospeed/SpeedChanger.h" + +//| class SpeedChanger: +//| """Wraps an audio sample to play it back at a different speed. +//| +//| Uses nearest-neighbor resampling with a fixed-point phase accumulator +//| for CPU-efficient variable-speed playback.""" +//| +//| def __init__(self, source: circuitpython_typing.AudioSample, rate: float = 1.0) -> None: +//| """Create a SpeedChanger that wraps ``source``. +//| +//| :param audiosample source: The audio source to resample. +//| :param float rate: Playback speed multiplier. 1.0 = normal, 2.0 = double speed, +//| 0.5 = half speed. Must be positive. +//| +//| Playing a wave file at 1.5x speed:: +//| +//| import board +//| import audiocore +//| import audiospeed +//| import audioio +//| +//| wav = audiocore.WaveFile("drum.wav") +//| fast = audiospeed.SpeedChanger(wav, rate=1.5) +//| audio = audioio.AudioOut(board.A0) +//| audio.play(fast) +//| +//| # Change speed during playback: +//| fast.rate = 2.0 # double speed +//| fast.rate = 0.5 # half speed +//| """ +//| ... +//| +static mp_obj_t audiospeed_speedchanger_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_source, ARG_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_source, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_rate, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + }; + 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); + + // Validate source implements audiosample protocol + mp_obj_t source = args[ARG_source].u_obj; + audiosample_check(source); + + audiospeed_speedchanger_obj_t *self = mp_obj_malloc(audiospeed_speedchanger_obj_t, &audiospeed_speedchanger_type); + common_hal_audiospeed_speedchanger_construct(self, source, args[ARG_rate].u_obj); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the SpeedChanger and releases all memory resources for reuse.""" +//| ... +//| +static mp_obj_t audiospeed_speedchanger_deinit(mp_obj_t self_in) { + audiospeed_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiospeed_speedchanger_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_speedchanger_deinit_obj, audiospeed_speedchanger_deinit); + +//| rate: float +//| """Playback speed multiplier. Can be changed during playback.""" +//| +static mp_obj_t audiospeed_speedchanger_obj_get_rate(mp_obj_t self_in) { + audiospeed_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(&self->base); + return common_hal_audiospeed_speedchanger_get_rate(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_speedchanger_get_rate_obj, audiospeed_speedchanger_obj_get_rate); + +static mp_obj_t audiospeed_speedchanger_obj_set_rate(mp_obj_t self_in, mp_obj_t rate_obj) { + audiospeed_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(&self->base); + common_hal_audiospeed_speedchanger_set_rate(self, rate_obj); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiospeed_speedchanger_set_rate_obj, audiospeed_speedchanger_obj_set_rate); + +MP_PROPERTY_GETSET(audiospeed_speedchanger_rate_obj, + (mp_obj_t)&audiospeed_speedchanger_get_rate_obj, + (mp_obj_t)&audiospeed_speedchanger_set_rate_obj); + +static const mp_rom_map_elem_t audiospeed_speedchanger_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiospeed_speedchanger_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiospeed_speedchanger_rate_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(audiospeed_speedchanger_locals_dict, audiospeed_speedchanger_locals_dict_table); + +static const audiosample_p_t audiospeed_speedchanger_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audiospeed_speedchanger_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiospeed_speedchanger_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + audiospeed_speedchanger_type, + MP_QSTR_SpeedChanger, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiospeed_speedchanger_make_new, + locals_dict, &audiospeed_speedchanger_locals_dict, + protocol, &audiospeed_speedchanger_proto + ); diff --git a/shared-bindings/audiospeed/SpeedChanger.h b/shared-bindings/audiospeed/SpeedChanger.h new file mode 100644 index 00000000000..bc0b166b612 --- /dev/null +++ b/shared-bindings/audiospeed/SpeedChanger.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiospeed/SpeedChanger.h" + +extern const mp_obj_type_t audiospeed_speedchanger_type; + +void common_hal_audiospeed_speedchanger_construct(audiospeed_speedchanger_obj_t *self, + mp_obj_t source, mp_obj_t rate_obj); +void common_hal_audiospeed_speedchanger_deinit(audiospeed_speedchanger_obj_t *self); + +void common_hal_audiospeed_speedchanger_set_rate(audiospeed_speedchanger_obj_t *self, mp_obj_t rate_obj); +mp_obj_t common_hal_audiospeed_speedchanger_get_rate(audiospeed_speedchanger_obj_t *self); diff --git a/shared-bindings/audiospeed/__init__.c b/shared-bindings/audiospeed/__init__.c new file mode 100644 index 00000000000..3eca41e6467 --- /dev/null +++ b/shared-bindings/audiospeed/__init__.c @@ -0,0 +1,30 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/audiospeed/Resampler.h" +#include "shared-bindings/audiospeed/SpeedChanger.h" + +//| """Audio processing tools""" + +static const mp_rom_map_elem_t audiospeed_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiospeed) }, + { MP_ROM_QSTR(MP_QSTR_Resampler), MP_ROM_PTR(&audiospeed_resampler_type) }, + { MP_ROM_QSTR(MP_QSTR_SpeedChanger), MP_ROM_PTR(&audiospeed_speedchanger_type) }, +}; + +static MP_DEFINE_CONST_DICT(audiospeed_module_globals, audiospeed_module_globals_table); + +const mp_obj_module_t audiospeed_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&audiospeed_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_audiospeed, audiospeed_module); diff --git a/shared-bindings/audiospeed/__init__.h b/shared-bindings/audiospeed/__init__.h new file mode 100644 index 00000000000..c4a52e5819d --- /dev/null +++ b/shared-bindings/audiospeed/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-bindings/aurora_epaper/aurora_framebuffer.c b/shared-bindings/aurora_epaper/aurora_framebuffer.c index f1bb1693284..49e0b34a856 100644 --- a/shared-bindings/aurora_epaper/aurora_framebuffer.c +++ b/shared-bindings/aurora_epaper/aurora_framebuffer.c @@ -64,7 +64,7 @@ //| ) -> None: //| """Create a framebuffer for the Aurora CoG display. //| -//| .. note:: Displays of size 1.9" and 2.6" are not tested, and may exibit unexpected behavior. +//| .. note:: Displays of size 1.9" and 2.6" are not tested, and may exhibit unexpected behavior. //| //| :param busio.SPI spi_bus: The SPI bus that the display is connected to //| :param microcontroller.Pin chip_select: The pin connected to the displays chip select input diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c index d1a200d39b5..06e0b01ed34 100644 --- a/shared-bindings/bitbangio/I2C.c +++ b/shared-bindings/bitbangio/I2C.c @@ -22,8 +22,8 @@ //| //| def __init__( //| self, -//| scl: microcontroller.Pin, -//| sda: microcontroller.Pin, +//| scl: Union[microcontroller.Pin, digitalio.DigitalInOutProtocol], +//| sda: Union[microcontroller.Pin, digitalio.DigitalInOutProtocol], //| *, //| frequency: int = 400000, //| timeout: int = 255, @@ -40,8 +40,8 @@ //| bit unpacking. Instead, use an existing driver or make one with //| :ref:`Register ` data descriptors. //| -//| :param ~microcontroller.Pin scl: The clock pin -//| :param ~microcontroller.Pin sda: The data pin +//| :param ~microcontroller.Pin scl: The clock pin or DigitalInOut object +//| :param ~microcontroller.Pin sda: The data pin or DigitalInOut object //| :param int frequency: The clock frequency of the bus //| :param int timeout: The maximum clock stretching timeout in microseconds""" //| ... @@ -57,12 +57,12 @@ static mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_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 mcu_pin_obj_t *scl = validate_obj_is_free_pin(args[ARG_scl].u_obj, MP_QSTR_scl); - const mcu_pin_obj_t *sda = validate_obj_is_free_pin(args[ARG_sda].u_obj, MP_QSTR_sda); + mp_int_t frequency = mp_arg_validate_int_min(args[ARG_frequency].u_int, 1, MP_QSTR_frequency); bitbangio_i2c_obj_t *self = mp_obj_malloc_with_finaliser(bitbangio_i2c_obj_t, &bitbangio_i2c_type); - shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int); - return (mp_obj_t)self; + shared_module_bitbangio_i2c_construct(self, args[ARG_scl].u_obj, args[ARG_sda].u_obj, frequency, args[ARG_timeout].u_int); + + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: diff --git a/shared-bindings/bitbangio/I2C.h b/shared-bindings/bitbangio/I2C.h index 022be3692a6..cc9cd21b601 100644 --- a/shared-bindings/bitbangio/I2C.h +++ b/shared-bindings/bitbangio/I2C.h @@ -16,8 +16,8 @@ extern const mp_obj_type_t bitbangio_i2c_type; // Initializes the hardware peripheral. extern void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, - const mcu_pin_obj_t *scl, - const mcu_pin_obj_t *sda, + mp_obj_t scl, + mp_obj_t sda, uint32_t frequency, uint32_t us_timeout); diff --git a/shared-bindings/bitbangio/SPI.c b/shared-bindings/bitbangio/SPI.c index 8938ae4898d..a70ef82cd05 100644 --- a/shared-bindings/bitbangio/SPI.c +++ b/shared-bindings/bitbangio/SPI.c @@ -33,9 +33,9 @@ //| //| def __init__( //| self, -//| clock: microcontroller.Pin, -//| MOSI: Optional[microcontroller.Pin] = None, -//| MISO: Optional[microcontroller.Pin] = None, +//| clock: Union[microcontroller.Pin, digitalio.DigitalInOutProtocol], +//| MOSI: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, +//| MISO: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, //| ) -> None: //| """Construct an SPI object on the given pins. //| @@ -48,9 +48,9 @@ //| :ref:`Register ` data descriptors. //| //| -//| :param ~microcontroller.Pin clock: the pin to use for the clock. -//| :param ~microcontroller.Pin MOSI: the Main Out Selected In pin. -//| :param ~microcontroller.Pin MISO: the Main In Selected Out pin.""" +//| :param ~microcontroller.Pin clock: the pin to use for the clock or DigitalInOut object +//| :param ~microcontroller.Pin MOSI: the Main Out Selected In pin or DigitalInOut object +//| :param ~microcontroller.Pin MISO: the Main In Selected Out pin or DigitalInOut object""" //| ... //| @@ -65,13 +65,9 @@ static mp_obj_t bitbangio_spi_make_new(const mp_obj_type_t *type, size_t n_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 mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); - const mcu_pin_obj_t *mosi = validate_obj_is_free_pin_or_none(args[ARG_MOSI].u_obj, MP_QSTR_mosi); - const mcu_pin_obj_t *miso = validate_obj_is_free_pin_or_none(args[ARG_MISO].u_obj, MP_QSTR_miso); - bitbangio_spi_obj_t *self = mp_obj_malloc(bitbangio_spi_obj_t, &bitbangio_spi_type); - shared_module_bitbangio_spi_construct(self, clock, mosi, miso); - return (mp_obj_t)self; + shared_module_bitbangio_spi_construct(self, args[ARG_clock].u_obj, args[ARG_MOSI].u_obj, args[ARG_MISO].u_obj); + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: @@ -137,12 +133,13 @@ static mp_obj_t bitbangio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint32_t baudrate = (uint32_t)mp_arg_validate_int_min(args[ARG_baudrate].u_int, 1, MP_QSTR_baudrate); uint8_t polarity = (uint8_t)mp_arg_validate_int_range(args[ARG_polarity].u_int, 0, 1, MP_QSTR_polarity); uint8_t phase = (uint8_t)mp_arg_validate_int_range(args[ARG_phase].u_int, 0, 1, MP_QSTR_phase); uint8_t bits = (uint8_t)mp_arg_validate_int_range(args[ARG_bits].u_int, 8, 9, MP_QSTR_bits); - shared_module_bitbangio_spi_configure(self, args[ARG_baudrate].u_int, polarity, phase, bits); + shared_module_bitbangio_spi_configure(self, baudrate, polarity, phase, bits); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_spi_configure_obj, 1, bitbangio_spi_configure); diff --git a/shared-bindings/bitbangio/SPI.h b/shared-bindings/bitbangio/SPI.h index dbe821683b0..19ec05152ad 100644 --- a/shared-bindings/bitbangio/SPI.h +++ b/shared-bindings/bitbangio/SPI.h @@ -16,8 +16,7 @@ extern const mp_obj_type_t bitbangio_spi_type; // Construct an underlying SPI object. extern void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self, - const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *miso); + mp_obj_t clock, mp_obj_t mosi, mp_obj_t miso); extern void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self); extern bool shared_module_bitbangio_spi_deinited(bitbangio_spi_obj_t *self); diff --git a/shared-bindings/bitmapfilter/__init__.c b/shared-bindings/bitmapfilter/__init__.c index 7c5344dde11..8d01ad482b2 100644 --- a/shared-bindings/bitmapfilter/__init__.c +++ b/shared-bindings/bitmapfilter/__init__.c @@ -137,7 +137,7 @@ static mp_obj_t bitmapfilter_morph(size_t n_args, const mp_obj_t *pos_args, mp_m mp_float_t m = get_m(args[ARG_mul].u_obj, weight_sum); shared_module_bitmapfilter_morph(bitmap, mask, sq_n_weights / 2, iweights, m, b, - args[ARG_threshold].u_bool, args[ARG_offset].u_bool, args[ARG_invert].u_bool); + args[ARG_threshold].u_bool, args[ARG_offset].u_int, args[ARG_invert].u_bool); return args[ARG_bitmap].u_obj; } MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_morph_obj, 0, bitmapfilter_morph); diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c index 709e4582113..a56075344e8 100644 --- a/shared-bindings/bitmaptools/__init__.c +++ b/shared-bindings/bitmaptools/__init__.c @@ -185,8 +185,8 @@ static mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args ARG_angle, ARG_scale, ARG_skip_index}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, {MP_QSTR_ox, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to destination->width / 2 {MP_QSTR_oy, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to destination->height / 2 @@ -206,9 +206,9 @@ static mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap - displayio_bitmap_t *source = MP_OBJ_TO_PTR(args[ARG_source_bitmap].u_obj); // the source bitmap + displayio_bitmap_t *source = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_source_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap)); // the source bitmap // ensure that the destination bitmap has at least as many `bits_per_value` as the source if (destination->bits_per_value < source->bits_per_value) { @@ -311,6 +311,7 @@ MAKE_ENUM_TYPE(bitmaptools, BlendMode, bitmaptools_blendmode); //| blendmode: Optional[BlendMode] = BlendMode.Normal, //| skip_source1_index: Union[int, None] = None, //| skip_source2_index: Union[int, None] = None, +//| mask: Optional[displayio.Bitmap] = None, //| ) -> None: //| """Alpha blend the two source bitmaps into the destination. //| @@ -326,6 +327,11 @@ MAKE_ENUM_TYPE(bitmaptools, BlendMode, bitmaptools_blendmode); //| :param bitmaptools.BlendMode blendmode: The blend mode to use. Default is Normal. //| :param int skip_source1_index: Bitmap palette or luminance index in source_bitmap_1 that will not be blended, set to None to blend all pixels //| :param int skip_source2_index: Bitmap palette or luminance index in source_bitmap_2 that will not be blended, set to None to blend all pixels +//| :param displayio.Bitmap mask: Optional 8-bits-per-value grayscale mask bitmap controlling per-pixel opacity of ``source_bitmap_2``. +//| The mask must have the same width and height as the other bitmaps and a ``bits_per_value`` of 8. A mask value of 0 +//| means ``source_bitmap_2`` is fully transparent at that pixel (only ``source_bitmap_1`` contributes); a value of 255 means +//| ``source_bitmap_2`` is fully opaque at that pixel (subject to ``factor2``). Intermediate values scale ``factor2`` linearly. +//| Pass ``None`` to disable per-pixel masking. //| //| For the L8 colorspace, the bitmaps must have a bits-per-value of 8. //| For the RGB colorspaces, they must have a bits-per-value of 16.""" @@ -333,7 +339,7 @@ MAKE_ENUM_TYPE(bitmaptools, BlendMode, bitmaptools_blendmode); //| static mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum {ARG_dest_bitmap, ARG_source_bitmap_1, ARG_source_bitmap_2, ARG_colorspace, ARG_factor_1, ARG_factor_2, ARG_blendmode, ARG_skip_source1_index, ARG_skip_source2_index}; + enum {ARG_dest_bitmap, ARG_source_bitmap_1, ARG_source_bitmap_2, ARG_colorspace, ARG_factor_1, ARG_factor_2, ARG_blendmode, ARG_skip_source1_index, ARG_skip_source2_index, ARG_mask}; static const mp_arg_t allowed_args[] = { {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = NULL}}, @@ -345,6 +351,7 @@ static mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, {MP_QSTR_blendmode, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = (void *)&bitmaptools_blendmode_Normal_obj}}, {MP_QSTR_skip_source1_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, {MP_QSTR_skip_source2_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + {MP_QSTR_mask, MP_ARG_KW_ONLY | 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); @@ -411,13 +418,64 @@ static mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, skip_source2_index_none = false; } + displayio_bitmap_t *mask = NULL; + if (args[ARG_mask].u_obj != mp_const_none) { + mask = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_mask].u_obj, &displayio_bitmap_type, MP_QSTR_mask)); + if (mask->width != destination->width || mask->height != destination->height) { + mp_raise_ValueError(MP_ERROR_TEXT("Mask bitmap size must match the other bitmaps")); + } + if (mask->bits_per_value != 8) { + mp_raise_ValueError(MP_ERROR_TEXT("Mask bitmap must have 8 bits per pixel")); + } + } + common_hal_bitmaptools_alphablend(destination, source1, source2, colorspace, factor1, factor2, blendmode, skip_source1_index, - skip_source1_index_none, skip_source2_index, skip_source2_index_none); + skip_source1_index_none, skip_source2_index, skip_source2_index_none, mask); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_alphablend_obj, 0, bitmaptools_alphablend); +//| def replace_color( +//| dest_bitmap: displayio.Bitmap, old_color: int, new_color: int +//| ) -> None: +//| """Replace any pixels of ``old_color`` with ``new_color`` in the ``bitmap`` +//| +//| :param displayio.Bitmap bitmap: Bitmap that will be changed +//| :param int old_color: Bitmap palette index that will overwritten +//| :param int new_color: Bitmap palette index that will get put in the bitmap""" +//| ... +//| +//| +static mp_obj_t bitmaptools_obj_replace_color(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum {ARG_bitmap, ARG_old_color, ARG_new_color}; + + static const mp_arg_t allowed_args[] = { + {MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_old_color, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_new_color, MP_ARG_REQUIRED | MP_ARG_INT}, + }; + 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); + + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap)); + + uint32_t old_color, new_color, color_depth; + old_color = args[ARG_old_color].u_int; + new_color = args[ARG_new_color].u_int; + + color_depth = (1 << destination->bits_per_value); + if (color_depth <= old_color || color_depth <= new_color) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_color); + } + + common_hal_bitmaptools_replace_color(destination, old_color, new_color); + + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_replace_color_obj, 0, bitmaptools_obj_replace_color); + //| def fill_region( //| dest_bitmap: displayio.Bitmap, x1: int, y1: int, x2: int, y2: int, value: int //| ) -> None: @@ -438,14 +496,14 @@ static mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_a enum {ARG_dest_bitmap, ARGS_X1_Y1_X2_Y2, ARG_value}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, ALLOWED_ARGS_X1_Y1_X2_Y2(MP_ARG_REQUIRED, MP_ARG_REQUIRED), - {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT}, }; 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); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap uint32_t value, color_depth; value = args[ARG_value].u_int; @@ -487,10 +545,10 @@ static mp_obj_t bitmaptools_obj_boundary_fill(size_t n_args, const mp_obj_t *pos enum {ARG_dest_bitmap, ARG_x, ARG_y, ARG_fill_color_value, ARG_replaced_color_value}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_fill_color_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_fill_color_value, MP_ARG_REQUIRED | MP_ARG_INT}, {MP_QSTR_replaced_color_value, MP_ARG_INT, {.u_int = INT_MAX} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -548,17 +606,17 @@ static mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_arg enum {ARG_dest_bitmap, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_value}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT}, }; 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); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap uint32_t value, color_depth; value = args[ARG_value].u_int; @@ -635,16 +693,16 @@ static mp_obj_t bitmaptools_obj_draw_polygon(size_t n_args, const mp_obj_t *pos_ enum {ARG_dest_bitmap, ARG_xs, ARG_ys, ARG_value, ARG_close}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_xs, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_ys, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_xs, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_ys, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT}, {MP_QSTR_close, MP_ARG_BOOL, {.u_bool = true}}, }; 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); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap mp_buffer_info_t xs_buf, ys_buf; mp_get_buffer_raise(args[ARG_xs].u_obj, &xs_buf, MP_BUFFER_READ); @@ -717,8 +775,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_polygon_obj, 0, bitmaptools_obj_draw static mp_obj_t bitmaptools_arrayblit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_bitmap, ARG_data, ARGS_X1_Y1_X2_Y2, ARG_skip_index }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, ALLOWED_ARGS_X1_Y1_X2_Y2(0, 0), { MP_QSTR_skip_index, MP_ARG_OBJ, {.u_obj = mp_const_none } }, }; @@ -782,9 +840,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_arrayblit_obj, 0, bitmaptools_arrayblit); static mp_obj_t bitmaptools_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_bitmap, ARG_file, ARG_bits_per_pixel, ARG_element_size, ARG_reverse_pixels_in_element, ARG_swap_bytes_in_element, ARG_reverse_rows }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_bits_per_pixel, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_bits_per_pixel, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_element_size, MP_ARG_INT, { .u_int = 1 } }, { MP_QSTR_reverse_pixels_in_element, MP_ARG_BOOL, { .u_bool = false } }, { MP_QSTR_swap_bytes_in_element, MP_ARG_BOOL, { .u_bool = false } }, @@ -873,9 +931,9 @@ MAKE_ENUM_TYPE(bitmaptools, DitherAlgorithm, bitmaptools_dither_algorithm); static mp_obj_t bitmaptools_dither(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_dest_bitmap, ARG_source_bitmap, ARG_source_colorspace, ARG_algorithm }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_source_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_source_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_algorithm, MP_ARG_OBJ, { .u_obj = MP_ROM_PTR((void *)&dither_algorithm_Atkinson_obj) } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -977,7 +1035,7 @@ static mp_obj_t bitmaptools_obj_draw_circle(size_t n_args, const mp_obj_t *pos_a 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); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap uint32_t value, color_depth; value = args[ARG_value].u_int; @@ -1038,10 +1096,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_circle_obj, 0, bitmaptools_obj_draw_ static mp_obj_t bitmaptools_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum {ARG_destination, ARG_source, ARG_x, ARG_y, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_source_index, ARG_skip_dest_index}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} }, - {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} }, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, + {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, ALLOWED_ARGS_X1_Y1_X2_Y2(0, 0), {MP_QSTR_skip_source_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, {MP_QSTR_skip_dest_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, @@ -1103,6 +1161,7 @@ static const mp_rom_map_elem_t bitmaptools_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) }, { MP_ROM_QSTR(MP_QSTR_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) }, { MP_ROM_QSTR(MP_QSTR_alphablend), MP_ROM_PTR(&bitmaptools_alphablend_obj) }, + { MP_ROM_QSTR(MP_QSTR_replace_color), MP_ROM_PTR(&bitmaptools_replace_color_obj) }, { MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) }, { MP_ROM_QSTR(MP_QSTR_boundary_fill), MP_ROM_PTR(&bitmaptools_boundary_fill_obj) }, { MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) }, diff --git a/shared-bindings/bitmaptools/__init__.h b/shared-bindings/bitmaptools/__init__.h index 21116b8bd42..20236983bac 100644 --- a/shared-bindings/bitmaptools/__init__.h +++ b/shared-bindings/bitmaptools/__init__.h @@ -42,6 +42,9 @@ void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination, int16_t x2, int16_t y2, uint32_t value); +void common_hal_bitmaptools_replace_color(displayio_bitmap_t *destination, + uint32_t old_color, uint32_t new_color); + void common_hal_bitmaptools_boundary_fill(displayio_bitmap_t *destination, int16_t x, int16_t y, uint32_t fill_color_value, uint32_t replaced_color_value); @@ -66,7 +69,8 @@ void common_hal_bitmaptools_arrayblit(displayio_bitmap_t *self, void *data, int void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bitmap_t *source_bitmap, displayio_colorspace_t colorspace, bitmaptools_dither_algorithm_t algorithm); void common_hal_bitmaptools_alphablend(displayio_bitmap_t *destination, displayio_bitmap_t *source1, displayio_bitmap_t *source2, displayio_colorspace_t colorspace, mp_float_t factor1, mp_float_t factor2, - bitmaptools_blendmode_t blendmode, uint32_t skip_source1_index, bool skip_source1_index_none, uint32_t skip_source2_index, bool skip_source2_index_none); + bitmaptools_blendmode_t blendmode, uint32_t skip_source1_index, bool skip_source1_index_none, uint32_t skip_source2_index, bool skip_source2_index_none, + displayio_bitmap_t *mask); typedef struct { union { diff --git a/shared-bindings/board/__init__.h b/shared-bindings/board/__init__.h index 7c9a59d2dbd..43343099730 100644 --- a/shared-bindings/board/__init__.h +++ b/shared-bindings/board/__init__.h @@ -11,22 +11,23 @@ #include "shared-bindings/microcontroller/Pin.h" // for the pin definitions +#if CIRCUITPY_MUTABLE_BOARD +extern mp_obj_dict_t board_module_globals; +#else extern const mp_obj_dict_t board_module_globals; +#endif static const MP_DEFINE_STR_OBJ(board_module_id_obj, CIRCUITPY_BOARD_ID); -bool common_hal_board_is_i2c(mp_obj_t obj); mp_obj_t common_hal_board_get_i2c(const mp_int_t instance); mp_obj_t common_hal_board_create_i2c(const mp_int_t instance); mp_obj_t board_i2c(size_t n_args, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ_0(board_i2c_obj); -bool common_hal_board_is_spi(mp_obj_t obj); mp_obj_t common_hal_board_get_spi(const mp_int_t instance); mp_obj_t common_hal_board_create_spi(const mp_int_t instance); mp_obj_t board_spi(size_t n_args, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ_0(board_spi_obj); -bool common_hal_board_is_uart(mp_obj_t obj); mp_obj_t common_hal_board_get_uart(const mp_int_t instance); mp_obj_t common_hal_board_create_uart(const mp_int_t instance); mp_obj_t board_uart(size_t n_args, const mp_obj_t *args); @@ -41,3 +42,7 @@ MP_DECLARE_CONST_FUN_OBJ_0(board_uart_obj); #define CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS \ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_board) }, \ { MP_ROM_QSTR(MP_QSTR_board_id), MP_ROM_PTR(&board_module_id_obj) }, + +#define CIRCUITPYTHON_MUTABLE_BOARD_DICT_STANDARD_ITEMS \ + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_board) }, \ + { MP_ROM_QSTR(MP_QSTR_board_id), MP_OBJ_FROM_PTR(&board_module_id_obj) }, diff --git a/shared-bindings/busdisplay/BusDisplay.c b/shared-bindings/busdisplay/BusDisplay.c index 297a8690577..0bf171a5d08 100644 --- a/shared-bindings/busdisplay/BusDisplay.c +++ b/shared-bindings/busdisplay/BusDisplay.c @@ -122,7 +122,6 @@ //| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence. //| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on. //| :param bool SH1107_addressing: Special quirk for SH1107, use upper/lower column set and page set -//| :param int set_vertical_scroll: This parameter is accepted but ignored for backwards compatibility. It will be removed in a future release. //| :param int backlight_pwm_frequency: The frequency to use to drive the PWM for backlight brightness control. Default is 50000. //| """ //| ... @@ -133,7 +132,7 @@ static mp_obj_t busdisplay_busdisplay_make_new(const mp_obj_type_t *type, size_t ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, - ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, + ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, ARG_SH1107_addressing, ARG_backlight_pwm_frequency }; @@ -154,7 +153,6 @@ static mp_obj_t busdisplay_busdisplay_make_new(const mp_obj_type_t *type, size_t { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} }, { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} }, { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} }, - { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} }, { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_BRIGHTNESS_COMMAND} }, { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index 8aa35ec6e07..b619dfa1140 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -67,7 +67,7 @@ static mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz busio_i2c_obj_t *self = mp_obj_malloc_with_finaliser(busio_i2c_obj_t, &busio_i2c_type); common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); #else mp_raise_NotImplementedError(NULL); #endif // CIRCUITPY_BUSIO_I2C @@ -106,13 +106,13 @@ static void check_for_deinit(busio_i2c_obj_t *self) { // Provided by context manager helper. static void check_lock(busio_i2c_obj_t *self) { - asm (""); + __asm__ (""); if (!common_hal_busio_i2c_has_lock(self)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Function requires lock")); } } -//| def probe(self, address: int) -> List[int]: +//| def probe(self, address: int) -> bool: //| """Check if a device at the specified address responds. //| //| :param int address: 7-bit device address @@ -228,10 +228,10 @@ static mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, start *= stride_in_bytes; length *= stride_in_bytes; - uint8_t status = + mp_negative_errno_t status = common_hal_busio_i2c_read(self, args[ARG_address].u_int, ((uint8_t *)bufinfo.buf) + start, length); if (status != 0) { - mp_raise_OSError(status); + mp_raise_OSError(-status); } return mp_const_none; @@ -290,11 +290,11 @@ static mp_obj_t busio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_ma length *= stride_in_bytes; // do the transfer - uint8_t status = + mp_negative_errno_t status = common_hal_busio_i2c_write(self, args[ARG_address].u_int, ((uint8_t *)bufinfo.buf) + start, length); if (status != 0) { - mp_raise_OSError(status); + mp_raise_OSError(-status); } return mp_const_none; @@ -369,7 +369,7 @@ static mp_obj_t busio_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *p int32_t in_start = args[ARG_in_start].u_int; const int32_t in_end = args[ARG_in_end].u_int; normalize_buffer_bounds(&in_start, in_end, &in_length); - mp_arg_validate_length_min(in_length, 1, MP_QSTR_out_buffer); + mp_arg_validate_length_min(in_length, 1, MP_QSTR_in_buffer); // Treat start and length in terms of bytes from now on. out_start *= out_stride_in_bytes; @@ -377,10 +377,10 @@ static mp_obj_t busio_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *p in_start *= in_stride_in_bytes; in_length *= in_stride_in_bytes; - uint8_t status = common_hal_busio_i2c_write_read(self, args[ARG_address].u_int, + mp_negative_errno_t status = common_hal_busio_i2c_write_read(self, args[ARG_address].u_int, ((uint8_t *)out_bufinfo.buf) + out_start, out_length, ((uint8_t *)in_bufinfo.buf) + in_start, in_length); if (status != 0) { - mp_raise_OSError(status); + mp_raise_OSError(-status); } return mp_const_none; diff --git a/shared-bindings/busio/I2C.h b/shared-bindings/busio/I2C.h index 55f2d0f0108..2978a907544 100644 --- a/shared-bindings/busio/I2C.h +++ b/shared-bindings/busio/I2C.h @@ -7,6 +7,7 @@ #pragma once #include "py/obj.h" +#include "py/mperrno.h" #include "common-hal/microcontroller/Pin.h" #include "common-hal/busio/I2C.h" @@ -35,17 +36,17 @@ extern void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self); // Probe the bus to see if a device acknowledges the given address. extern bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr); -// Write to the device and return 0 on success or an appropriate error code from mperrno.h -extern uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, +// Write to the device and return 0 on success or a negative error code from mperrno.h +extern mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, const uint8_t *data, size_t len); // Reads memory of the i2c device picking up where it left off and return 0 on -// success or an appropriate error code from mperrno.h -extern uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, +// success or a negative error code from mperrno.h +extern mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *data, size_t len); // Do a write and then a read in the same I2C transaction. -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t address, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len); // This is used by the supervisor to claim I2C devices indefinitely. diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 0c8ae1bfdd7..6ff74880266 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -9,17 +9,17 @@ #include +#include "py/binary.h" +#include "py/mperrno.h" +#include "py/objproperty.h" +#include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/util.h" - #include "shared/runtime/buffer_helper.h" #include "shared/runtime/context_manager_helpers.h" -#include "py/binary.h" -#include "py/mperrno.h" -#include "py/objproperty.h" -#include "py/runtime.h" - +#include "shared/runtime/interrupt_char.h" +#include "supervisor/shared/tick.h" //| class SPI: //| """A 3-4 wire serial protocol @@ -88,7 +88,6 @@ // TODO(tannewt): Support LSB SPI. static mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_BUSIO_SPI - busio_spi_obj_t *self = mp_obj_malloc(busio_spi_obj_t, &busio_spi_type); enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -107,6 +106,7 @@ static mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, siz mp_raise_ValueError(MP_ERROR_TEXT("Must provide MISO or MOSI pin")); } + busio_spi_obj_t *self = mp_obj_malloc_with_finaliser(busio_spi_obj_t, &busio_spi_type); common_hal_busio_spi_construct(self, clock, mosi, miso, args[ARG_half_duplex].u_bool); return MP_OBJ_FROM_PTR(self); #else @@ -140,7 +140,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_deinit_obj, busio_spi_obj_deinit); // Provided by context manager helper. static void check_lock(busio_spi_obj_t *self) { - asm (""); + __asm__ (""); if (!common_hal_busio_spi_has_lock(self)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Function requires lock")); } @@ -157,9 +157,12 @@ static void check_for_deinit(busio_spi_obj_t *self) { //| ) -> None: //| """Configures the SPI bus. The SPI object must be locked. //| -//| :param int baudrate: the desired clock rate in Hertz. The actual clock rate may be higher or lower -//| due to the granularity of available clock settings. +//| :param int baudrate: the desired clock rate in Hertz. The value is treated as a ceiling: +//| the actual clock rate may be lower due to the granularity of available clock settings, +//| but it will not exceed the given value. //| Check the `frequency` attribute for the actual clock rate. +//| **Limitations**: On Zephyr, the ceiling behavior may be violated, and +//| the `frequency` value does not reflect the actual baudrate. //| :param int polarity: the base state of the clock line (0 or 1) //| :param int phase: the edge of the clock that data is captured. First (0) //| or second (1). Rising or falling depends on clock polarity. @@ -168,13 +171,7 @@ static void check_for_deinit(busio_spi_obj_t *self) { //| .. note:: On the SAMD21, it is possible to set the baudrate to 24 MHz, but that //| speed is not guaranteed to work. 12 MHz is the next available lower speed, and is //| within spec for the SAMD21. -//| -//| .. note:: On the nRF52840, these baudrates are available: 125kHz, 250kHz, 1MHz, 2MHz, 4MHz, -//| and 8MHz. -//| If you pick a a baudrate other than one of these, the nearest lower -//| baudrate will be chosen, with a minimum of 125kHz. -//| Two SPI objects may be created, except on the Circuit Playground Bluefruit, -//| which allows only one (to allow for an additional I2C object).""" +//| """ //| ... //| @@ -445,9 +442,14 @@ static mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 1, busio_spi_write_readinto); //| frequency: int -//| """The actual SPI bus frequency. This may not match the frequency requested -//| due to internal limitations.""" +//| """The actual SPI bus frequency. This may be lower than the frequency requested +//| due to internal limitations, but it will not be higher. //| +//| **Limitations**: On Zephyr, the returned value does not reflect the actual baudrate, +//| because there is `no way to fetch the actual chosen frequency +//| `_. +//| In addition, on Zephyr, the ceiling behavior described in `configure` may be violated. +//| """ //| static mp_obj_t busio_spi_obj_get_frequency(mp_obj_t self_in) { @@ -466,6 +468,7 @@ MP_PROPERTY_GETTER(busio_spi_frequency_obj, static const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { #if CIRCUITPY_BUSIO_SPI { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&busio_spi_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, @@ -493,3 +496,17 @@ MP_DEFINE_CONST_OBJ_TYPE( busio_spi_obj_t *validate_obj_is_spi_bus(mp_obj_t obj, qstr arg_name) { return mp_arg_validate_type(obj, &busio_spi_type, arg_name); } + +// Wait as long as needed for the lock. This is used by SD card access from USB. +// The default implementation is to busy-wait while running the background tasks. espressif is different. +bool common_hal_busio_spi_wait_for_lock(busio_spi_obj_t *self, uint32_t timeout_ms) { + uint64_t deadline = supervisor_ticks_ms64() + timeout_ms; + while (supervisor_ticks_ms64() < deadline && + !mp_hal_is_interrupted()) { + if (common_hal_busio_spi_try_lock(self)) { + return true; + } + RUN_BACKGROUND_TASKS; + } + return false; +} diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h index 69e582411a1..76ed697d665 100644 --- a/shared-bindings/busio/SPI.h +++ b/shared-bindings/busio/SPI.h @@ -22,6 +22,10 @@ extern void common_hal_busio_spi_construct(busio_spi_obj_t *self, extern void common_hal_busio_spi_deinit(busio_spi_obj_t *self); extern bool common_hal_busio_spi_deinited(busio_spi_obj_t *self); +// Mark as deinit without deiniting. This is used by displayio after copying the +// object elsewhere and prevents the heap from deiniting the object. +extern void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self); + extern bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits); extern bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self); @@ -50,3 +54,7 @@ uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self); extern void common_hal_busio_spi_never_reset(busio_spi_obj_t *self); extern busio_spi_obj_t *validate_obj_is_spi_bus(mp_obj_t obj_in, qstr arg_name); + +// Wait as long as needed for the lock. This is used by SD card access from USB. +// For most ports, busy-wait while running the background tasks. +MP_WEAK bool common_hal_busio_spi_wait_for_lock(busio_spi_obj_t *self, uint32_t timeout_ms); diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c index 4714c3ee073..81e970a98f4 100644 --- a/shared-bindings/busio/UART.c +++ b/shared-bindings/busio/UART.c @@ -157,7 +157,7 @@ static mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, si common_hal_busio_uart_construct(self, tx, rx, rts, cts, rs485_dir, rs485_invert, args[ARG_baudrate].u_int, bits, parity, stop, timeout, buffer_size, NULL, false); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); #else mp_raise_NotImplementedError(NULL); #endif // CIRCUITPY_BUSIO_UART @@ -277,7 +277,7 @@ static mp_uint_t busio_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_ return common_hal_busio_uart_write(self, buf, size, errcode); } -static mp_uint_t busio_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t busio_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { busio_uart_obj_t *self = native_uart(self_in); check_for_deinit(self); mp_uint_t ret; diff --git a/shared-bindings/camera/Camera.c b/shared-bindings/camera/Camera.c index 6f42fa08bcf..f0991082e50 100644 --- a/shared-bindings/camera/Camera.c +++ b/shared-bindings/camera/Camera.c @@ -41,10 +41,10 @@ //| ... //| static mp_obj_t camera_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - camera_obj_t *self = mp_obj_malloc(camera_obj_t, &camera_type); // No arguments mp_arg_check_num(n_args, n_kw, 0, 0, false); + camera_obj_t *self = mp_obj_malloc(camera_obj_t, &camera_type); common_hal_camera_construct(self); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/canio/Match.c b/shared-bindings/canio/Match.c index 5e44a7ce4ed..e7c3dba42aa 100644 --- a/shared-bindings/canio/Match.c +++ b/shared-bindings/canio/Match.c @@ -47,7 +47,8 @@ static mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, s canio_match_obj_t *self = mp_obj_malloc(canio_match_obj_t, &canio_match_type); common_hal_canio_match_construct(self, id, mask, args[ARG_extended].u_bool); - return self; + + return MP_OBJ_FROM_PTR(self); } //| id: int diff --git a/shared-bindings/canio/Message.c b/shared-bindings/canio/Message.c index c40892b5edb..848b5b15e43 100644 --- a/shared-bindings/canio/Message.c +++ b/shared-bindings/canio/Message.c @@ -41,7 +41,8 @@ static mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, canio_message_obj_t *self = mp_obj_malloc(canio_message_obj_t, &canio_message_type); common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, args[ARG_extended].u_bool); - return self; + + return MP_OBJ_FROM_PTR(self); } //| id: int diff --git a/shared-bindings/canio/RemoteTransmissionRequest.c b/shared-bindings/canio/RemoteTransmissionRequest.c index 966fee71215..bdc91c494a4 100644 --- a/shared-bindings/canio/RemoteTransmissionRequest.c +++ b/shared-bindings/canio/RemoteTransmissionRequest.c @@ -42,7 +42,8 @@ static mp_obj_t canio_remote_transmission_request_make_new(const mp_obj_type_t * canio_remote_transmission_request_obj_t *self = mp_obj_malloc(canio_remote_transmission_request_obj_t, &canio_remote_transmission_request_type); common_hal_canio_remote_transmission_request_construct(self, args[ARG_id].u_int, length, args[ARG_extended].u_bool); - return self; + + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/canio/__init__.c b/shared-bindings/canio/__init__.c index c65b119ff24..2300a6652dd 100644 --- a/shared-bindings/canio/__init__.c +++ b/shared-bindings/canio/__init__.c @@ -36,7 +36,7 @@ //| //| Other implementations of the CAN device may exist (for instance, attached //| via an SPI bus). If so their constructor arguments may differ, but -//| otherwise we encourage implementors to follow the API that the core uses. +//| otherwise we encourage implementers to follow the API that the core uses. //| //| For more information on working with this module, refer to //| `this Learn Guide on using it `_. diff --git a/shared-bindings/countio/Counter.c b/shared-bindings/countio/Counter.c index c2e3ddc7404..9f8bd00645c 100644 --- a/shared-bindings/countio/Counter.c +++ b/shared-bindings/countio/Counter.c @@ -66,8 +66,8 @@ static mp_obj_t countio_counter_make_new(const mp_obj_type_t *type, size_t n_arg const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); const countio_edge_t edge = validate_edge(args[ARG_edge].u_obj, MP_QSTR_edge); const digitalio_pull_t pull = validate_pull(args[ARG_pull].u_obj, MP_QSTR_pull); - countio_counter_obj_t *self = mp_obj_malloc_with_finaliser(countio_counter_obj_t, &countio_counter_type); + countio_counter_obj_t *self = mp_obj_malloc_with_finaliser(countio_counter_obj_t, &countio_counter_type); common_hal_countio_counter_construct(self, pin, edge, pull); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index a29fdcc371c..52d48e54d32 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -17,6 +17,7 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" #include "shared-bindings/digitalio/Direction.h" #include "shared-bindings/digitalio/DriveMode.h" #include "shared-bindings/digitalio/Pull.h" @@ -70,9 +71,9 @@ static mp_obj_t digitalio_digitalinout_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); - digitalio_digitalinout_obj_t *self = mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); - const mcu_pin_obj_t *pin = common_hal_digitalio_validate_pin(args[0]); + + digitalio_digitalinout_obj_t *self = mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); common_hal_digitalio_digitalinout_construct(self, pin); return MP_OBJ_FROM_PTR(self); @@ -133,6 +134,8 @@ static mp_obj_t digitalio_digitalinout_switch_to_output(size_t n_args, const mp_ digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL; if (args[ARG_drive_mode].u_rom_obj == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { drive_mode = DRIVE_MODE_OPEN_DRAIN; + } else if (args[ARG_drive_mode].u_rom_obj != MP_ROM_PTR(&digitalio_drive_mode_push_pull_obj)) { + mp_arg_error_invalid(MP_QSTR_drive_mode); } // do the transfer check_result(common_hal_digitalio_digitalinout_switch_to_output(self, args[ARG_value].u_bool, drive_mode)); @@ -190,9 +193,9 @@ static mp_obj_t digitalio_digitalinout_obj_get_direction(mp_obj_t self_in) { check_for_deinit(self); digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self); if (direction == DIRECTION_INPUT) { - return (mp_obj_t)&digitalio_direction_input_obj; + return MP_OBJ_FROM_PTR(&digitalio_direction_input_obj); } - return (mp_obj_t)&digitalio_direction_output_obj; + return MP_OBJ_FROM_PTR(&digitalio_direction_output_obj); } MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_direction_obj, digitalio_digitalinout_obj_get_direction); @@ -254,9 +257,9 @@ static mp_obj_t digitalio_digitalinout_obj_get_drive_mode(mp_obj_t self_in) { } digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self); if (drive_mode == DRIVE_MODE_PUSH_PULL) { - return (mp_obj_t)&digitalio_drive_mode_push_pull_obj; + return MP_OBJ_FROM_PTR(&digitalio_drive_mode_push_pull_obj); } - return (mp_obj_t)&digitalio_drive_mode_open_drain_obj; + return MP_OBJ_FROM_PTR(&digitalio_drive_mode_open_drain_obj); } MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_drive_mode_obj, digitalio_digitalinout_obj_get_drive_mode); @@ -270,6 +273,8 @@ static mp_obj_t digitalio_digitalinout_obj_set_drive_mode(mp_obj_t self_in, mp_o digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL; if (drive_mode == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { c_drive_mode = DRIVE_MODE_OPEN_DRAIN; + } else if (drive_mode != MP_ROM_PTR(&digitalio_drive_mode_push_pull_obj)) { + mp_arg_error_invalid(MP_QSTR_drive_mode); } check_result(common_hal_digitalio_digitalinout_set_drive_mode(self, c_drive_mode)); return mp_const_none; @@ -341,12 +346,91 @@ static const mp_rom_map_elem_t digitalio_digitalinout_locals_dict_table[] = { static MP_DEFINE_CONST_DICT(digitalio_digitalinout_locals_dict, digitalio_digitalinout_locals_dict_table); +// Protocol implementation - thin wrappers to match protocol signature +void digitalinout_deinit(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_digitalio_digitalinout_deinit(self); +} + +bool digitalinout_deinited(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_deinited(self); +} + +digitalinout_result_t digitalinout_switch_to_input(mp_obj_t self_in, digitalio_pull_t pull) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_switch_to_input(self, pull); +} + +digitalinout_result_t digitalinout_switch_to_output(mp_obj_t self_in, bool value, digitalio_drive_mode_t drive_mode) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_switch_to_output(self, value, drive_mode); +} + +digitalio_direction_t digitalinout_get_direction(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_get_direction(self); +} + +mp_negative_errno_t digitalinout_set_value(mp_obj_t self_in, bool value) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_digitalio_digitalinout_set_value(self, value); + return 0; +} + +mp_negative_errno_t digitalinout_get_value(mp_obj_t self_in, bool *value) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + *value = common_hal_digitalio_digitalinout_get_value(self); + return 0; +} + +digitalinout_result_t digitalinout_set_drive_mode(mp_obj_t self_in, digitalio_drive_mode_t drive_mode) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_set_drive_mode(self, drive_mode); +} + +digitalio_drive_mode_t digitalinout_get_drive_mode(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_get_drive_mode(self); +} + +digitalinout_result_t digitalinout_set_pull(mp_obj_t self_in, digitalio_pull_t pull) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_set_pull(self, pull); +} + +digitalio_pull_t digitalinout_get_pull(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_get_pull(self); +} + +#if CIRCUITPY_DIGITALINOUT_PROTOCOL +static const digitalinout_p_t digitalinout_digitalinout_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_DigitalInOut) + .deinit = digitalinout_deinit, + .deinited = digitalinout_deinited, + .switch_to_input = digitalinout_switch_to_input, + .switch_to_output = digitalinout_switch_to_output, + .get_direction = digitalinout_get_direction, + .get_value = digitalinout_get_value, + .set_value = digitalinout_set_value, + .get_drive_mode = digitalinout_get_drive_mode, + .set_drive_mode = digitalinout_set_drive_mode, + .get_pull = digitalinout_get_pull, + .set_pull = digitalinout_set_pull, +}; +#endif + MP_DEFINE_CONST_OBJ_TYPE( digitalio_digitalinout_type, MP_QSTR_DigitalInOut, MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, make_new, digitalio_digitalinout_make_new, locals_dict, &digitalio_digitalinout_locals_dict + #if CIRCUITPY_DIGITALINOUT_PROTOCOL + , + protocol, &digitalinout_digitalinout_proto + #endif ); // Helper for validating digitalio.DigitalInOut arguments diff --git a/shared-bindings/digitalio/DigitalInOut.h b/shared-bindings/digitalio/DigitalInOut.h index f030e27a60b..8d3fe8c00a2 100644 --- a/shared-bindings/digitalio/DigitalInOut.h +++ b/shared-bindings/digitalio/DigitalInOut.h @@ -28,6 +28,9 @@ typedef enum { #endif } digitalinout_result_t; +// Include protocol after types are defined +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" + typedef enum { DIGITALINOUT_REG_READ, DIGITALINOUT_REG_WRITE, @@ -54,3 +57,16 @@ digitalio_digitalinout_obj_t *assert_digitalinout(mp_obj_t obj); volatile uint32_t *common_hal_digitalio_digitalinout_get_reg(digitalio_digitalinout_obj_t *self, digitalinout_reg_op_t op, uint32_t *mask); bool common_hal_digitalio_has_reg_op(digitalinout_reg_op_t op); + +// Protocol wrapper functions - always available for direct calls +void digitalinout_deinit(mp_obj_t self_in); +bool digitalinout_deinited(mp_obj_t self_in); +digitalinout_result_t digitalinout_switch_to_input(mp_obj_t self_in, digitalio_pull_t pull); +digitalinout_result_t digitalinout_switch_to_output(mp_obj_t self_in, bool value, digitalio_drive_mode_t drive_mode); +digitalio_direction_t digitalinout_get_direction(mp_obj_t self_in); +mp_negative_errno_t digitalinout_set_value(mp_obj_t self_in, bool value); +mp_negative_errno_t digitalinout_get_value(mp_obj_t self_in, bool *value); +digitalinout_result_t digitalinout_set_drive_mode(mp_obj_t self_in, digitalio_drive_mode_t drive_mode); +digitalio_drive_mode_t digitalinout_get_drive_mode(mp_obj_t self_in); +digitalinout_result_t digitalinout_set_pull(mp_obj_t self_in, digitalio_pull_t pull); +digitalio_pull_t digitalinout_get_pull(mp_obj_t self_in); diff --git a/shared-bindings/digitalio/DigitalInOutProtocol.c b/shared-bindings/digitalio/DigitalInOutProtocol.c new file mode 100644 index 00000000000..48b428ad463 --- /dev/null +++ b/shared-bindings/digitalio/DigitalInOutProtocol.c @@ -0,0 +1,397 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" + +#include "py/obj.h" +#include "py/objtype.h" +#include "py/proto.h" +#include "py/runtime.h" +#include "py/nlr.h" +#include "py/gc.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/digitalio/Direction.h" +#include "shared-bindings/digitalio/DriveMode.h" +#include "shared-bindings/digitalio/Pull.h" +#include "shared-bindings/util.h" +#include "supervisor/port_heap.h" + +//| from typing import Protocol, Optional +//| +//| class DigitalInOutProtocol(Protocol): +//| """Protocol for digital input/output pin control. +//| +//| Any object that implements this protocol can be used as a digital pin, +//| providing compatibility with code expecting a `digitalio.DigitalInOut`. +//| """ +//| +//| def deinit(self) -> None: +//| """Deinitialize the pin and release hardware resources.""" +//| ... +//| +//| def deinited(self) -> bool: +//| """Check whether the pin has been deinitialized. +//| +//| :return: True if deinitialized, False otherwise +//| """ +//| ... +//| +//| def switch_to_input(self, pull: Optional[digitalio.Pull] = None) -> None: +//| """Configure the pin as a digital input. +//| +//| :param pull: Pull resistor configuration (UP, DOWN, or None) +//| """ +//| ... +//| +//| def switch_to_output( +//| self, +//| value: bool = False, +//| drive_mode: digitalio.DriveMode = digitalio.DriveMode.PUSH_PULL +//| ) -> None: +//| """Configure the pin as a digital output. +//| +//| :param value: Initial output value (default False) +//| :param drive_mode: Output drive mode (PUSH_PULL or OPEN_DRAIN) +//| """ +//| ... +//| +//| @property +//| def direction(self) -> digitalio.Direction: +//| """The pin direction (INPUT or OUTPUT).""" +//| ... +//| +//| @direction.setter +//| def direction(self, value: digitalio.Direction) -> None: +//| ... +//| +//| @property +//| def value(self) -> bool: +//| """The digital logic level of the pin.""" +//| ... +//| +//| @value.setter +//| def value(self, val: bool) -> None: +//| ... +//| +//| @property +//| def pull(self) -> Optional[digitalio.Pull]: +//| """The pull resistor configuration for inputs (UP, DOWN, or None).""" +//| ... +//| +//| @pull.setter +//| def pull(self, pul: Optional[digitalio.Pull]) -> None: +//| ... +//| +//| @property +//| def drive_mode(self) -> digitalio.DriveMode: +//| """The drive mode for outputs (PUSH_PULL or OPEN_DRAIN).""" +//| ... +//| +//| @drive_mode.setter +//| def drive_mode(self, mode: digitalio.DriveMode) -> None: +//| ... +//| +// C Implementation Notes: +// ----------------------- +// For C implementations, define a digitalinout_p_t protocol structure and assign it +// to your type's protocol field in MP_DEFINE_CONST_OBJ_TYPE. +// +// Example: +// static const digitalinout_p_t my_type_proto = { +// MP_PROTO_IMPLEMENT(MP_QSTR_DigitalInOut) +// .construct = my_construct_func, +// .deinit = my_deinit_func, +// .deinited = my_deinited_func, +// .switch_to_input = my_switch_to_input_func, +// .switch_to_output = my_switch_to_output_func, +// .get_direction = my_get_direction_func, +// .get_value = my_get_value_func, +// .set_value = my_set_value_func, +// .get_drive_mode = my_get_drive_mode_func, +// .set_drive_mode = my_set_drive_mode_func, +// .get_pull = my_get_pull_func, +// .set_pull = my_set_pull_func, +// }; +// +// MP_DEFINE_CONST_OBJ_TYPE( +// my_type, +// MP_QSTR_MyType, +// MP_TYPE_FLAG_NONE, +// make_new, my_make_new, +// protocol, &my_type_proto +// ); +// +// See shared-bindings/digitalio/DigitalInOut.c for a complete example. +// + +#if CIRCUITPY_DIGITALINOUT_PROTOCOL +static void check_object_has_method(mp_obj_t obj, qstr method_name) { + mp_obj_t dest[2]; + mp_load_method_protected(obj, method_name, dest, true); + if (dest[0] == MP_OBJ_NULL) { + mp_raise_TypeError_varg(MP_ERROR_TEXT("%q object missing '%q' method"), MP_OBJ_TO_PTR(obj), method_name); + } +} + +static void check_object_has_attr(mp_obj_t obj, qstr attr_name) { + mp_obj_t dest[2]; + mp_load_method_protected(obj, attr_name, dest, true); + if (dest[0] == MP_OBJ_NULL) { + mp_raise_TypeError_varg(MP_ERROR_TEXT("%q object missing '%q' attribute"), MP_OBJ_TO_PTR(obj), attr_name); + } +} +#endif + +mp_obj_t digitalinout_protocol_from_pin( + mp_obj_t pin_or_dio, + qstr arg_name, + bool allow_none, + bool use_port_allocation, + bool *out_owns_pin) { + + *out_owns_pin = false; + + // Handle None case + if (allow_none && pin_or_dio == mp_const_none) { + return mp_const_none; + } + + // Check if it's a Pin + if (mp_obj_is_type(pin_or_dio, &mcu_pin_type)) { + // Validate the pin is free + const mcu_pin_obj_t *pin; + if (allow_none) { + pin = validate_obj_is_free_pin_or_none(pin_or_dio, arg_name); + if (pin == NULL) { + return mp_const_none; + } + } else { + pin = validate_obj_is_free_pin(pin_or_dio, arg_name); + } + + // Allocate and construct a DigitalInOut object + // Use port_malloc if GC is not available or if forced + digitalio_digitalinout_obj_t *dio; + if (use_port_allocation) { + dio = port_malloc(sizeof(digitalio_digitalinout_obj_t), false); + } else { + dio = m_malloc(sizeof(digitalio_digitalinout_obj_t)); + } + dio->base.type = &digitalio_digitalinout_type; + mp_obj_t dio_obj = MP_OBJ_FROM_PTR(dio); + *out_owns_pin = true; + + digitalinout_result_t result = common_hal_digitalio_digitalinout_construct(dio_obj, pin); + if (result != DIGITALINOUT_OK) { + // Free the allocation on error + if (use_port_allocation) { + port_free(dio); + } + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q init failed"), arg_name); + } + return dio_obj; + } + + #if CIRCUITPY_DIGITALINOUT_PROTOCOL + // Check if it natively implements the DigitalInOutProtocol + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, pin_or_dio); + if (proto != NULL) { + // Native protocol support - use it directly + return pin_or_dio; + } + + // Verify the object has the required methods/attributes + check_object_has_method(pin_or_dio, MP_QSTR_deinit); + check_object_has_method(pin_or_dio, MP_QSTR_switch_to_input); + check_object_has_method(pin_or_dio, MP_QSTR_switch_to_output); + check_object_has_attr(pin_or_dio, MP_QSTR_deinited); + check_object_has_attr(pin_or_dio, MP_QSTR_direction); + check_object_has_attr(pin_or_dio, MP_QSTR_value); + check_object_has_attr(pin_or_dio, MP_QSTR_drive_mode); + check_object_has_attr(pin_or_dio, MP_QSTR_pull); + + // Object has all required attributes - use it as DigitalInOutProtocol + return pin_or_dio; + #else + mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object does not support '%q'"), + mp_obj_get_type_qstr(pin_or_dio), MP_QSTR_DigitalInOut); + #endif +} + +// These functions are only used when CIRCUITPY_DIGITALINOUT_PROTOCOL is enabled. +// Otherwise, the digitalinout_* functions are called directly. +#if CIRCUITPY_DIGITALINOUT_PROTOCOL +void digitalinout_protocol_deinit(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->deinit) { + proto->deinit(self); + return; + } + + // Fallback to Python method call + mp_obj_t dest[2]; + mp_load_method_maybe(self, MP_QSTR_deinit, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, dest); + return; + } +} + +bool digitalinout_protocol_deinited(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->deinited) { + return proto->deinited(self); + } + + // Try as attribute + mp_obj_t attr = mp_load_attr(self, MP_QSTR_deinited); + return mp_obj_is_true(attr); +} + +digitalinout_result_t digitalinout_protocol_switch_to_input(mp_obj_t self, digitalio_pull_t pull) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->switch_to_input) { + return proto->switch_to_input(self, pull); + } + + // Fallback to Python method call + mp_obj_t dest[3]; + mp_load_method_maybe(self, MP_QSTR_switch_to_input, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_obj_t pull_obj = mp_const_none; + if (pull == PULL_UP) { + pull_obj = MP_OBJ_FROM_PTR(&digitalio_pull_up_obj); + } else if (pull == PULL_DOWN) { + pull_obj = MP_OBJ_FROM_PTR(&digitalio_pull_down_obj); + } + dest[2] = pull_obj; + mp_call_method_n_kw(1, 0, dest); + return DIGITALINOUT_OK; + } + + return DIGITALINOUT_PIN_BUSY; +} + +digitalinout_result_t digitalinout_protocol_switch_to_output(mp_obj_t self, bool value, digitalio_drive_mode_t drive_mode) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->switch_to_output) { + return proto->switch_to_output(self, value, drive_mode); + } + + // Fallback to Python method call + mp_obj_t dest[4]; + mp_load_method_maybe(self, MP_QSTR_switch_to_output, dest); + if (dest[0] != MP_OBJ_NULL) { + dest[2] = mp_obj_new_bool(value); + dest[3] = (drive_mode == DRIVE_MODE_PUSH_PULL) ? + MP_OBJ_FROM_PTR(&digitalio_drive_mode_push_pull_obj) : + MP_OBJ_FROM_PTR(&digitalio_drive_mode_open_drain_obj); + mp_call_method_n_kw(2, 0, dest); + return DIGITALINOUT_OK; + } + + mp_raise_TypeError(MP_ERROR_TEXT("object does not support DigitalInOut protocol")); +} + +digitalio_direction_t digitalinout_protocol_get_direction(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->get_direction) { + return proto->get_direction(self); + } + + // Fallback to Python attribute access + mp_obj_t direction = mp_load_attr(self, MP_QSTR_direction); + if (direction == MP_ROM_PTR(&digitalio_direction_input_obj)) { + return DIRECTION_INPUT; + } + return DIRECTION_OUTPUT; +} + +mp_negative_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->set_value) { + return proto->set_value(self, value); + } + + // Fallback to Python attribute assignment + mp_store_attr(self, MP_QSTR_value, mp_obj_new_bool(value)); + return 0; +} + +mp_negative_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->get_value) { + return proto->get_value(self, value); + } + + // Fallback to Python attribute access + *value = mp_obj_is_true(mp_load_attr(self, MP_QSTR_value)); + return 0; +} + +digitalinout_result_t digitalinout_protocol_set_drive_mode(mp_obj_t self, digitalio_drive_mode_t drive_mode) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->set_drive_mode) { + return proto->set_drive_mode(self, drive_mode); + } + + // Fallback to Python attribute assignment + mp_obj_t drive_mode_obj = (drive_mode == DRIVE_MODE_PUSH_PULL) ? + MP_OBJ_FROM_PTR(&digitalio_drive_mode_push_pull_obj) : + MP_OBJ_FROM_PTR(&digitalio_drive_mode_open_drain_obj); + mp_store_attr(self, MP_QSTR_drive_mode, drive_mode_obj); + return DIGITALINOUT_OK; +} + +digitalio_drive_mode_t digitalinout_protocol_get_drive_mode(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->get_drive_mode) { + return proto->get_drive_mode(self); + } + + // Fallback to Python attribute access + mp_obj_t drive_mode = mp_load_attr(self, MP_QSTR_drive_mode); + if (drive_mode == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { + return DRIVE_MODE_OPEN_DRAIN; + } + return DRIVE_MODE_PUSH_PULL; +} + +digitalinout_result_t digitalinout_protocol_set_pull(mp_obj_t self, digitalio_pull_t pull) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->set_pull) { + return proto->set_pull(self, pull); + } + + // Fallback to Python attribute assignment + mp_obj_t pull_obj = mp_const_none; + if (pull == PULL_UP) { + pull_obj = MP_OBJ_FROM_PTR(&digitalio_pull_up_obj); + } else if (pull == PULL_DOWN) { + pull_obj = MP_OBJ_FROM_PTR(&digitalio_pull_down_obj); + } + mp_store_attr(self, MP_QSTR_pull, pull_obj); + return DIGITALINOUT_OK; +} + +digitalio_pull_t digitalinout_protocol_get_pull(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); + if (proto && proto->get_pull) { + return proto->get_pull(self); + } + + // Fallback to Python attribute access + mp_obj_t pull = mp_load_attr(self, MP_QSTR_pull); + if (pull == MP_OBJ_FROM_PTR(&digitalio_pull_up_obj)) { + return PULL_UP; + } else if (pull == MP_OBJ_FROM_PTR(&digitalio_pull_down_obj)) { + return PULL_DOWN; + } + return PULL_NONE; +} + +#endif // CIRCUITPY_DIGITALINOUT_PROTOCOL diff --git a/shared-bindings/digitalio/DigitalInOutProtocol.h b/shared-bindings/digitalio/DigitalInOutProtocol.h new file mode 100644 index 00000000000..6cb92a3735f --- /dev/null +++ b/shared-bindings/digitalio/DigitalInOutProtocol.h @@ -0,0 +1,83 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" +#include "py/proto.h" +#include "py/mperrno.h" +#include "shared-bindings/digitalio/Direction.h" +#include "shared-bindings/digitalio/DriveMode.h" +#include "shared-bindings/digitalio/Pull.h" + +// Protocol structure for DigitalInOut implementations +// Note: mcu_pin_obj_t and digitalinout_result_t are defined by files that include this header +typedef struct _digitalinout_p_t { + MP_PROTOCOL_HEAD // MP_QSTR_DigitalInOut + void (*deinit)(mp_obj_t self); + bool (*deinited)(mp_obj_t self); + digitalinout_result_t (*switch_to_input)(mp_obj_t self, digitalio_pull_t pull); + digitalinout_result_t (*switch_to_output)(mp_obj_t self, bool value, digitalio_drive_mode_t drive_mode); + digitalio_direction_t (*get_direction)(mp_obj_t self); + mp_negative_errno_t (*set_value)(mp_obj_t self, bool value); // Return 0 if ok + mp_negative_errno_t (*get_value)(mp_obj_t self, bool *value); // Return 0 if ok + digitalinout_result_t (*set_drive_mode)(mp_obj_t self, digitalio_drive_mode_t drive_mode); + digitalio_drive_mode_t (*get_drive_mode)(mp_obj_t self); + digitalinout_result_t (*set_pull)(mp_obj_t self, digitalio_pull_t pull); + digitalio_pull_t (*get_pull)(mp_obj_t self); +} digitalinout_p_t; + +// Protocol helper functions +// These functions work with any object that implements the DigitalInOut protocol, +// either through native C protocol or Python attributes/methods. + +// Converts a Pin or DigitalInOutProtocol to a DigitalInOutProtocol object. +// If pin_or_dio is a Pin, allocates and initializes a DigitalInOut object. +// If pin_or_dio is already a DigitalInOutProtocol, returns it directly. +// If allow_none is true and pin_or_dio is None, returns None. +// If force_port_allocation is true, uses port_malloc instead of GC allocation. +// Sets *out_owns_pin to true if a new DigitalInOut was allocated (caller must deinit and free). +// Returns the DigitalInOutProtocol object to use. +// Raises an exception on error. +// Note: To free allocated objects, deinit first, then use gc_ptr_on_heap() to determine +// if port_free() should be called (if not on heap) or let GC handle it (if on heap). +mp_obj_t digitalinout_protocol_from_pin( + mp_obj_t pin_or_dio, + qstr arg_name, + bool allow_none, + bool force_port_allocation, + bool *out_owns_pin); + +#if CIRCUITPY_DIGITALINOUT_PROTOCOL +// Protocol helper functions that do protocol lookup or Python fallback +void digitalinout_protocol_deinit(mp_obj_t self); +bool digitalinout_protocol_deinited(mp_obj_t self); +digitalinout_result_t digitalinout_protocol_switch_to_input(mp_obj_t self, digitalio_pull_t pull); +digitalinout_result_t digitalinout_protocol_switch_to_output(mp_obj_t self, bool value, digitalio_drive_mode_t drive_mode); +digitalio_direction_t digitalinout_protocol_get_direction(mp_obj_t self); +mp_negative_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value); +mp_negative_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value); +digitalinout_result_t digitalinout_protocol_set_drive_mode(mp_obj_t self, digitalio_drive_mode_t drive_mode); +digitalio_drive_mode_t digitalinout_protocol_get_drive_mode(mp_obj_t self); +digitalinout_result_t digitalinout_protocol_set_pull(mp_obj_t self, digitalio_pull_t pull); +digitalio_pull_t digitalinout_protocol_get_pull(mp_obj_t self); +#else +// When protocol is disabled, map directly to native DigitalInOut functions +#define digitalinout_protocol_deinit digitalinout_deinit +#define digitalinout_protocol_deinited digitalinout_deinited +#define digitalinout_protocol_switch_to_input digitalinout_switch_to_input +#define digitalinout_protocol_switch_to_output digitalinout_switch_to_output +#define digitalinout_protocol_get_direction digitalinout_get_direction +#define digitalinout_protocol_set_value digitalinout_set_value +#define digitalinout_protocol_get_value digitalinout_get_value +#define digitalinout_protocol_set_drive_mode digitalinout_set_drive_mode +#define digitalinout_protocol_get_drive_mode digitalinout_get_drive_mode +#define digitalinout_protocol_set_pull digitalinout_set_pull +#define digitalinout_protocol_get_pull digitalinout_get_pull +#endif diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index e2721cfdef2..bfd037016d4 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -39,7 +39,6 @@ static mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, siz mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); displayio_colorconverter_t *self = mp_obj_malloc(displayio_colorconverter_t, &displayio_colorconverter_type); - common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool, (displayio_colorspace_t)cp_enum_value(&displayio_colorspace_type, args[ARG_input_colorspace].u_obj, MP_QSTR_input_colorspace)); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index 560fb66a675..fb5cabf05bf 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -17,7 +17,7 @@ #include "shared-bindings/displayio/ColorConverter.h" #include "shared-bindings/displayio/OnDiskBitmap.h" #include "shared-bindings/displayio/Palette.h" -#ifdef CIRCUITPY_TILEPALETTEMAPPER +#if CIRCUITPY_TILEPALETTEMAPPER #include "shared-bindings/tilepalettemapper/TilePaletteMapper.h" #endif @@ -133,6 +133,7 @@ static mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_ bitmap_width / tile_width, bitmap_height / tile_height, pixel_shader, args[ARG_width].u_int, args[ARG_height].u_int, tile_width, tile_height, x, y, args[ARG_default_tile].u_int); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c index e0c35d3bce4..970c4826476 100644 --- a/shared-bindings/displayio/__init__.c +++ b/shared-bindings/displayio/__init__.c @@ -79,7 +79,12 @@ //| afterwards. This may take seconds to complete if an active EPaperDisplay is refreshing. //| //| Use this once in your code.py if you initialize a display. Place it right before the -//| initialization so the display is active as long as possible.""" +//| initialization so the display is active as long as possible. +//| +//| Once you release a builtin display (one that is initialized automatically, not by user code), +//| the display will remain released even if you restart the CircuitPython VM, for instance by typing ctrl-D. +//| The display is not re-initialized until you do a hard reset or manually initialize it again. +//| """ //| ... //| //| diff --git a/shared-bindings/displayio/__init__.h b/shared-bindings/displayio/__init__.h index 88e9650cf44..583f6b217fa 100644 --- a/shared-bindings/displayio/__init__.h +++ b/shared-bindings/displayio/__init__.h @@ -49,4 +49,5 @@ typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length); typedef void (*display_bus_end_transaction)(mp_obj_t bus); +typedef void (*display_bus_flush)(mp_obj_t bus); typedef void (*display_bus_collect_ptrs)(mp_obj_t bus); diff --git a/shared-bindings/dotclockframebuffer/DotClockFramebuffer.c b/shared-bindings/dotclockframebuffer/DotClockFramebuffer.c index faa0c21b097..beee1f07a5b 100644 --- a/shared-bindings/dotclockframebuffer/DotClockFramebuffer.c +++ b/shared-bindings/dotclockframebuffer/DotClockFramebuffer.c @@ -54,13 +54,6 @@ //| When a board has dedicated dot clock framebuffer pins and/or timings, they are intended to be used in the constructor with ``**`` dictionary unpacking like so: //| ``DotClockFramebuffer(**board.TFT_PINS, **board.TFT_TIMINGS)`` //| -//| On Espressif-family microcontrollers, this driver requires that the -//| ``CIRCUITPY_RESERVED_PSRAM`` in ``settings.toml`` be large enough to hold the -//| framebuffer. Generally, boards with built-in displays or display connectors -//| will have a default setting that is large enough for typical use. If the -//| constructor raises a MemoryError or an IDFError, this probably indicates the -//| setting is too small and should be increased. -//| //| TFT connection parameters: //| //| :param microcontroller.Pin de: The "data enable" input to the display diff --git a/shared-bindings/dotclockframebuffer/__init__.c b/shared-bindings/dotclockframebuffer/__init__.c index b8dbf8c1897..700cd067178 100644 --- a/shared-bindings/dotclockframebuffer/__init__.c +++ b/shared-bindings/dotclockframebuffer/__init__.c @@ -104,7 +104,7 @@ static mp_obj_t ioexpander_send_init_sequence(size_t n_args, const mp_obj_t *pos mp_arg_validate_int_range(cs_bit, 0, max_bit, MP_QSTR_cs_bit); mp_arg_validate_int_range(mosi_bit, 0, max_bit, MP_QSTR_mosi_bit); mp_arg_validate_int_range(clk_bit, 0, max_bit, MP_QSTR_clk_bit); - mp_arg_validate_int_range(gpio_data, 0, (1 << (max_bit * 8)) - 1, MP_QSTR_gpio_data); + mp_arg_validate_int_range(gpio_data, 0, (1 << (gpio_data_len * 8)) - 1, MP_QSTR_gpio_data); mp_int_t reset_mask = 0; if (args[ARG_reset_bit].u_obj != MP_ROM_NONE) { mp_int_t reset_bit = mp_arg_validate_int_range(mp_arg_validate_type_int(args[ARG_reset_bit].u_obj, MP_QSTR_reset_bit), 0, max_bit, MP_QSTR_reset_bit); diff --git a/shared-bindings/dualbank/__init__.c b/shared-bindings/dualbank/__init__.c index 2c00a5b0100..160ce4947a7 100644 --- a/shared-bindings/dualbank/__init__.c +++ b/shared-bindings/dualbank/__init__.c @@ -34,7 +34,7 @@ //| This module is unavailable as the flash is only large enough for one app partition. //| //| Boards with flash ``>2MB``: -//| This module is enabled/disabled at runtime based on whether the ``CIRCUITPY`` drive +//| This module is enabled/disabled at runtime based on whether the **CIRCUITPY** drive //| is extended or not. See `storage.erase_filesystem()` for more information. //| //| .. code-block:: python diff --git a/shared-bindings/emmcio/EMMC.c b/shared-bindings/emmcio/EMMC.c new file mode 100644 index 00000000000..8286daf9e20 --- /dev/null +++ b/shared-bindings/emmcio/EMMC.c @@ -0,0 +1,485 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" + +#include "extmod/vfs.h" + +#include "shared-bindings/emmcio/EMMC.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared/runtime/context_manager_helpers.h" +#include "common-hal/emmcio/EMMC.h" + +static void check_for_deinit(emmcio_emmc_obj_t *self) { + if (common_hal_emmcio_emmc_deinited(self)) { + raise_deinited_error(); + } +} + +//| class EMMC: +//| """eMMC as a block device""" +//| +//| def __init__( +//| self, +//| *, +//| clock: microcontroller.Pin, +//| command: microcontroller.Pin, +//| data: microcontroller.Pin, +//| reset: Optional[microcontroller.Pin] = None, +//| vccq: Optional[microcontroller.Pin] = None, +//| high_speed: bool = False, +//| write_enabled: bool = False, +//| ) -> None: +//| """Power up the card and make it ready for block access. +//| +//| Only one `EMMC` object may exist at a time. Call `deinit()`, or use +//| the object as a context manager, to release the card and its pins. +//| +//| :param ~microcontroller.Pin clock: the card's CLK pin +//| :param ~microcontroller.Pin command: the card's CMD pin +//| :param ~microcontroller.Pin data: the card's DAT0 pin. The bus is +//| 1-bit, so this is a single pin. +//| :param ~microcontroller.Pin reset: the card's RST_n pin, if the board +//| wires one +//| :param ~microcontroller.Pin vccq: a pin gating the card's I/O rail, +//| if the board has one +//| :param bool high_speed: Run the bus at its faster clock rate. Raises +//| an `OSError` if the card will not make the switch. +//| :param bool write_enabled: Allow `writeblocks()`. When `False`, the +//| object is read-only and every write path refuses. +//| +//| :raises ValueError: if the pins are unusable or already in use, or +//| if the card is owned by the USB drive. +//| :raises OSError: if the card does not come up. ``emmcio failure: n`` +//| names the MMC command that did not answer (``8`` being the +//| extended CSD), and ``high_speed failure: n`` how far the switch +//| got: ``0`` the card does not advertise 52 MHz, ``1`` no CMD6 +//| response, ``2`` the card never released DAT0, ``3`` it never came +//| back to the transfer state, ``4`` the EXT_CSD readback did not +//| take, ``5`` the 32 MHz smoke test failed, ``7`` the card rejected +//| HS_TIMING. +//| +//| Mount the card's filesystem:: +//| +//| import board +//| import emmcio +//| import storage +//| +//| emmc = emmcio.EMMC( +//| clock=board.EMMC_CLK, +//| command=board.EMMC_CMD, +//| data=board.EMMC_DAT0, +//| reset=board.EMMC_RESET, +//| vccq=board.EMMC_VCCQ, +//| high_speed=True, +//| write_enabled=True, +//| ) +//| storage.mount(storage.VfsFat(emmc), "/sd") +//| """ +//| ... +//| +static mp_obj_t emmcio_emmc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_clock, ARG_command, ARG_data, ARG_reset, ARG_vccq, ARG_high_speed, ARG_write_enabled }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, + { MP_QSTR_command, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, + { MP_QSTR_reset, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_vccq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_high_speed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_write_enabled, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + 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 mcu_pin_obj_t *clock = validate_obj_is_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *command = validate_obj_is_pin(args[ARG_command].u_obj, MP_QSTR_command); + const mcu_pin_obj_t *data = validate_obj_is_pin(args[ARG_data].u_obj, MP_QSTR_data); + const mcu_pin_obj_t *reset = validate_obj_is_pin_or_none(args[ARG_reset].u_obj, MP_QSTR_reset); + const mcu_pin_obj_t *vccq = validate_obj_is_pin_or_none(args[ARG_vccq].u_obj, MP_QSTR_vccq); + + // Every line is a separate net, so two of them being the same pin is a + // wiring mistake, not a configuration. + const mcu_pin_obj_t *pins[] = { clock, command, data, reset, vccq }; + const qstr names[] = { MP_QSTR_clock, MP_QSTR_command, MP_QSTR_data, MP_QSTR_reset, MP_QSTR_vccq }; + for (size_t i = 0; i < MP_ARRAY_SIZE(pins); i++) { + for (size_t j = i + 1; j < MP_ARRAY_SIZE(pins); j++) { + if (pins[i] != NULL && pins[i] == pins[j]) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q and %q must be different"), + names[i], names[j]); + } + } + } + + emmcio_emmc_obj_t *self = mp_obj_malloc(emmcio_emmc_obj_t, &emmcio_emmc_type); + // An OSError means the card itself did not come up; a ValueError means the + // wiring or the hardware is unusable. + int detail = 0; + switch (common_hal_emmcio_emmc_construct(self, clock, command, data, reset, vccq, + args[ARG_high_speed].u_bool, args[ARG_write_enabled].u_bool, &detail)) { + case EMMCIO_OK: + break; + case EMMCIO_ERR_PIN_PORT: + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q pin"), (qstr)detail); + break; + case EMMCIO_ERR_SPI_IN_USE: + mp_raise_ValueError(MP_ERROR_TEXT("SPI peripheral in use")); + break; + case EMMCIO_ERR_PIN_IN_USE: + mp_raise_ValueError(MP_ERROR_TEXT("Hardware in use, try alternative pins")); + break; + case EMMCIO_ERR_USB_OWNED: + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_emmcio); + break; + case EMMCIO_ERR_IN_USE: + mp_raise_ValueError(MP_ERROR_TEXT("Peripheral in use")); + break; + case EMMCIO_ERR_INIT: + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_emmcio, detail); + break; + case EMMCIO_ERR_HIGH_SPEED: + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_high_speed, detail); + break; + } + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Release the card and the pins it uses. Any further use of this +//| object raises a `ValueError`.""" +//| ... +//| +static mp_obj_t emmcio_emmc_deinit(mp_obj_t self_in) { + common_hal_emmcio_emmc_deinit(MP_OBJ_TO_PTR(self_in)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(emmcio_emmc_deinit_obj, emmcio_emmc_deinit); + +//| def __enter__(self) -> EMMC: +//| """No-op used by Context Managers.""" +//| ... +//| +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +static mp_obj_t emmcio_emmc_obj___exit__(size_t n_args, const mp_obj_t *args) { + return emmcio_emmc_deinit(args[0]); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(emmcio_emmc___exit___obj, 4, 4, emmcio_emmc_obj___exit__); + +#define CHUNK_BLOCKS 64u + +static int emmc_read_chunked(emmcio_emmc_obj_t *self, uint8_t *out, mp_uint_t start, mp_uint_t count, bool from_vm) { + mp_uint_t total = common_hal_emmcio_emmc_get_block_count(self); + if (count == 0 || start >= total || count > total - start) { + return -MP_EINVAL; + } + for (mp_uint_t done = 0; done < count;) { + mp_uint_t run = MIN(CHUNK_BLOCKS, count - done); + bool ok = false; + for (int attempt = 0; attempt < 3 && !ok; attempt++) { + ok = common_hal_emmcio_emmc_readblocks(start + done, out + done * EMMC_BLOCK_SIZE, run); + } + if (!ok) { + return -MP_EIO; + } + done += run; + RUN_BACKGROUND_TASKS; + if (from_vm) { + mp_handle_pending(true); + } + } + return 0; +} + +//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None: +//| """Read into ``buf`` starting at ``start_block``. +//| +//| :param int start_block: the first block to read +//| :param WriteableBuffer buf: a buffer whose length is a non-zero +//| multiple of `block_size` +//| +//| :raises ValueError: if ``buf`` is the wrong length, or the requested +//| blocks run past the end of the card. +//| :raises OSError: if the card fails to deliver the data.""" +//| ... +//| +static mp_obj_t emmcio_emmc_readblocks(mp_obj_t self_in, mp_obj_t start_in, mp_obj_t buf_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len == 0 || (bufinfo.len % EMMC_BLOCK_SIZE) != 0) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 512); + } + mp_uint_t start = mp_obj_get_int_truncated(start_in); + mp_uint_t count = bufinfo.len / EMMC_BLOCK_SIZE; + mp_uint_t total = common_hal_emmcio_emmc_get_block_count(self); + if (start >= total || count > total - start) { + mp_raise_ValueError(MP_ERROR_TEXT("address out of range")); + } + + int err = emmc_read_chunked(self, bufinfo.buf, start, count, true); + if (err != 0) { + mp_raise_OSError(-err); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(emmcio_emmc_readblocks_obj, emmcio_emmc_readblocks); + +static int emmc_write_chunked(emmcio_emmc_obj_t *self, const uint8_t *src, mp_uint_t start, mp_uint_t count, bool from_vm) { + mp_uint_t total = common_hal_emmcio_emmc_get_block_count(self); + if (count == 0 || start >= total || count > total - start) { + return -MP_EINVAL; + } + for (mp_uint_t done = 0; done < count;) { + mp_uint_t run = MIN(CHUNK_BLOCKS, count - done); + bool ok = false; + for (int attempt = 0; attempt < 3 && !ok; attempt++) { + ok = common_hal_emmcio_emmc_writeblocks(start + done, src + done * EMMC_BLOCK_SIZE, run); + } + if (!ok) { + return -MP_EIO; + } + done += run; + RUN_BACKGROUND_TASKS; + if (from_vm) { + mp_handle_pending(true); + } + } + return 0; +} + +//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None: +//| """Write ``buf`` to the card starting at ``start_block``. +//| +//| :param int start_block: the first block to write +//| :param ReadableBuffer buf: a buffer whose length is a non-zero +//| multiple of `block_size` +//| +//| :raises RuntimeError: if this object was not constructed with +//| ``write_enabled=True``. +//| :raises ValueError: if ``buf`` is the wrong length, or the requested +//| blocks run past the end of the card. +//| :raises OSError: if the write fails.""" +//| ... +//| +static mp_obj_t emmcio_emmc_writeblocks(mp_obj_t self_in, mp_obj_t start_in, mp_obj_t buf_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (!self->write_enabled) { + mp_raise_msg(&mp_type_RuntimeError, + MP_ERROR_TEXT("Read-only")); + } + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len == 0 || (bufinfo.len % EMMC_BLOCK_SIZE) != 0) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 512); + } + mp_uint_t start = mp_obj_get_int_truncated(start_in); + mp_uint_t count = bufinfo.len / EMMC_BLOCK_SIZE; + mp_uint_t total = common_hal_emmcio_emmc_get_block_count(self); + if (start >= total || count > total - start) { + mp_raise_ValueError(MP_ERROR_TEXT("address out of range")); + } + + int err = emmc_write_chunked(self, bufinfo.buf, start, count, true); + if (err != 0) { + mp_raise_OSError(-err); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(emmcio_emmc_writeblocks_obj, emmcio_emmc_writeblocks); + +//| def ioctl(self, op: int, arg: int) -> Optional[int]: +//| """Perform a block-device control operation, as required by the +//| block-device protocol. Returns `None` for operations this device does +//| not implement.""" +//| ... +//| +static mp_obj_t emmcio_emmc_ioctl(mp_obj_t self_in, mp_obj_t op_in, mp_obj_t arg_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + uint32_t out = 0; + if (!common_hal_emmcio_emmc_ioctl(mp_obj_get_int_truncated(op_in), + mp_obj_get_int_truncated(arg_in), &out)) { + return mp_const_none; + } + return mp_obj_new_int_from_uint(out); +} +static MP_DEFINE_CONST_FUN_OBJ_3(emmcio_emmc_ioctl_obj, emmcio_emmc_ioctl); + +mp_uint_t emmcio_emmc_readblocks_native(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t nblocks) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (common_hal_emmcio_emmc_deinited(self)) { + return -MP_ENODEV; + } + return emmc_read_chunked(self, buf, start_block, nblocks, false); +} + +mp_uint_t emmcio_emmc_writeblocks_native(mp_obj_t self_in, const uint8_t *buf, + uint32_t start_block, uint32_t nblocks) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (common_hal_emmcio_emmc_deinited(self)) { + return -MP_ENODEV; + } + + if (!self->write_enabled) { + return -MP_EROFS; + } + return emmc_write_chunked(self, buf, start_block, nblocks, false); +} + +bool emmcio_emmc_ioctl_native(mp_obj_t self_in, uint32_t cmd, uint32_t arg, + size_t *out_value) { + + (void)self_in; + uint32_t out = 0; + bool ok = common_hal_emmcio_emmc_ioctl(cmd, arg, &out); + *out_value = out; + return ok; +} + +bool emmcio_emmc_is_write_enabled(mp_obj_t self_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + return !common_hal_emmcio_emmc_deinited(self) && self->write_enabled; +} + +//| def read_ext_csd(self) -> bytes: +//| """Read the card's 512-byte extended CSD register.""" +//| ... +//| +static mp_obj_t emmcio_emmc_read_ext_csd(mp_obj_t self_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + uint8_t ext_csd[EMMC_BLOCK_SIZE]; + if (!common_hal_emmcio_emmc_read_ext_csd(ext_csd)) { + mp_raise_OSError(MP_EIO); + } + return mp_obj_new_bytes(ext_csd, sizeof(ext_csd)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(emmcio_emmc_read_ext_csd_obj, emmcio_emmc_read_ext_csd); + +//| def status(self) -> int: +//| """Read the card's 32-bit status register.""" +//| ... +//| +static mp_obj_t emmcio_emmc_status(mp_obj_t self_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + uint8_t r1[6]; + if (!common_hal_emmcio_emmc_read_status(r1)) { + mp_raise_OSError(MP_EIO); + } + uint32_t status = ((uint32_t)r1[1] << 24) | ((uint32_t)r1[2] << 16) | + ((uint32_t)r1[3] << 8) | (uint32_t)r1[4]; + return mp_obj_new_int_from_uint(status); +} +static MP_DEFINE_CONST_FUN_OBJ_1(emmcio_emmc_status_obj, emmcio_emmc_status); + +//| count: int +//| """The number of blocks on the card.""" +//| +static mp_obj_t emmcio_emmc_get_count(mp_obj_t self_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_int_from_uint(common_hal_emmcio_emmc_get_block_count(self)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(emmcio_emmc_get_count_obj, emmcio_emmc_get_count); +MP_PROPERTY_GETTER(emmcio_emmc_count_obj, (mp_obj_t)&emmcio_emmc_get_count_obj); + +//| block_size: int +//| """The size of one block, in bytes.""" +//| +static mp_obj_t emmcio_emmc_get_block_size(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(EMMC_BLOCK_SIZE); +} +static MP_DEFINE_CONST_FUN_OBJ_1(emmcio_emmc_get_block_size_obj, emmcio_emmc_get_block_size); +MP_PROPERTY_GETTER(emmcio_emmc_block_size_obj, (mp_obj_t)&emmcio_emmc_get_block_size_obj); + +//| cid: bytes +//| """The card's 16-byte identification register.""" +//| +static mp_obj_t emmcio_emmc_get_cid(mp_obj_t self_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bytes(common_hal_emmcio_emmc_get_cid(self), 16); +} +static MP_DEFINE_CONST_FUN_OBJ_1(emmcio_emmc_get_cid_obj, emmcio_emmc_get_cid); +MP_PROPERTY_GETTER(emmcio_emmc_cid_obj, (mp_obj_t)&emmcio_emmc_get_cid_obj); + +//| write_enabled: bool +//| """Whether `writeblocks()` is permitted on this object.""" +//| +static mp_obj_t emmcio_emmc_get_write_enabled(mp_obj_t self_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(self->write_enabled); +} +static MP_DEFINE_CONST_FUN_OBJ_1(emmcio_emmc_get_write_enabled_obj, emmcio_emmc_get_write_enabled); +MP_PROPERTY_GETTER(emmcio_emmc_write_enabled_obj, (mp_obj_t)&emmcio_emmc_get_write_enabled_obj); + +//| high_speed: bool +//| """Whether the card is running at its faster clock rate.""" +//| +static mp_obj_t emmcio_emmc_get_high_speed(mp_obj_t self_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_emmcio_emmc_get_high_speed(self)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(emmcio_emmc_get_high_speed_obj, emmcio_emmc_get_high_speed); +MP_PROPERTY_GETTER(emmcio_emmc_high_speed_obj, (mp_obj_t)&emmcio_emmc_get_high_speed_obj); + +//| frequency: int +//| """The bus clock rate in Hz.""" +//| +static mp_obj_t emmcio_emmc_get_frequency(mp_obj_t self_in) { + emmcio_emmc_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_int_from_uint(common_hal_emmcio_emmc_get_frequency(self)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(emmcio_emmc_get_frequency_obj, emmcio_emmc_get_frequency); +MP_PROPERTY_GETTER(emmcio_emmc_frequency_obj, (mp_obj_t)&emmcio_emmc_get_frequency_obj); + +static const mp_rom_map_elem_t emmcio_emmc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&emmcio_emmc_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&emmcio_emmc___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&emmcio_emmc_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&emmcio_emmc_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&emmcio_emmc_ioctl_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_ext_csd), MP_ROM_PTR(&emmcio_emmc_read_ext_csd_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&emmcio_emmc_status_obj) }, + + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&emmcio_emmc_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_high_speed), MP_ROM_PTR(&emmcio_emmc_high_speed_obj) }, + { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&emmcio_emmc_frequency_obj) }, + { MP_ROM_QSTR(MP_QSTR_block_size), MP_ROM_PTR(&emmcio_emmc_block_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_cid), MP_ROM_PTR(&emmcio_emmc_cid_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_enabled), MP_ROM_PTR(&emmcio_emmc_write_enabled_obj) }, +}; +static MP_DEFINE_CONST_DICT(emmcio_emmc_locals_dict, emmcio_emmc_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + emmcio_emmc_type, + MP_QSTR_EMMC, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + locals_dict, &emmcio_emmc_locals_dict, + make_new, emmcio_emmc_make_new + ); diff --git a/shared-bindings/emmcio/EMMC.h b/shared-bindings/emmcio/EMMC.h new file mode 100644 index 00000000000..1adfdcafef2 --- /dev/null +++ b/shared-bindings/emmcio/EMMC.h @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#define EMMC_BLOCK_SIZE 512u + +extern const mp_obj_type_t emmcio_emmc_type; + +// Why bring-up failed. The binding turns these into exceptions; the automount +// path just gives up. +typedef enum { + EMMCIO_OK = 0, + EMMCIO_ERR_PIN_PORT, // detail: qstr of the pin the port cannot drive + EMMCIO_ERR_SPI_IN_USE, + EMMCIO_ERR_PIN_IN_USE, + EMMCIO_ERR_USB_OWNED, + EMMCIO_ERR_IN_USE, + EMMCIO_ERR_INIT, // detail: the MMC command that did not answer + EMMCIO_ERR_HIGH_SPEED, // detail: the switch step it stopped at +} emmcio_construct_result_t; + +// ---- native block-device protocol ----------------------------------------- +// +// The same shape sdcardio and sdioio present, so extmod/vfs_blockdev.c can +// bypass the Python method call. + +// 0 on success, negative errno on failure. Never raises. +mp_uint_t emmcio_emmc_readblocks_native(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t nblocks); + +// 0 on success, -MP_EROFS on an object without write_enabled=True, other +// negative errno on failure. Never raises. +mp_uint_t emmcio_emmc_writeblocks_native(mp_obj_t self_in, const uint8_t *buf, + uint32_t start_block, uint32_t nblocks); + +// false = op not implemented, the caller turns that into None. +bool emmcio_emmc_ioctl_native(mp_obj_t self_in, uint32_t cmd, uint32_t arg, + size_t *out_value); + +// Whether this object may write at all +bool emmcio_emmc_is_write_enabled(mp_obj_t self_in); diff --git a/shared-bindings/emmcio/__init__.c b/shared-bindings/emmcio/__init__.c new file mode 100644 index 00000000000..2caf1f8aeb3 --- /dev/null +++ b/shared-bindings/emmcio/__init__.c @@ -0,0 +1,32 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/emmcio/EMMC.h" + +//| """Block device access to the on-board eMMC +//| +//| The `emmcio` module exposes an eMMC chip as a block device. +//| It provides no filesystem of its own: to read files, hand an `EMMC` +//| object to `storage.VfsFat` and mount it. +//| +//| """ +//| + +static const mp_rom_map_elem_t emmcio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_emmcio) }, + { MP_ROM_QSTR(MP_QSTR_EMMC), MP_ROM_PTR(&emmcio_emmc_type) }, +}; +static MP_DEFINE_CONST_DICT(emmcio_module_globals, emmcio_module_globals_table); + +const mp_obj_module_t emmcio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&emmcio_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_emmcio, emmcio_module); diff --git a/shared-bindings/emmcio/__init__.h b/shared-bindings/emmcio/__init__.h new file mode 100644 index 00000000000..efe68c01b70 --- /dev/null +++ b/shared-bindings/emmcio/__init__.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Clear module state on every VM reset. The card's rail has already been cut +// by then, so the state must not pretend to survive. +void emmcio_reset(void); diff --git a/shared-bindings/floppyio/__init__.c b/shared-bindings/floppyio/__init__.c index 09034b4675d..f32a0759953 100644 --- a/shared-bindings/floppyio/__init__.c +++ b/shared-bindings/floppyio/__init__.c @@ -147,10 +147,10 @@ static mp_obj_t floppyio_mfm_readinto(size_t n_args, const mp_obj_t *pos_args, m mp_buffer_info_t bufinfo_validity; uint8_t validity_buf[n_sectors]; if (args[ARG_validity].u_obj) { - mp_get_buffer_raise(args[ARG_validity].u_obj, &bufinfo_validity, MP_BUFFER_READ); + mp_get_buffer_raise(args[ARG_validity].u_obj, &bufinfo_validity, MP_BUFFER_WRITE); mp_arg_validate_length_min(bufinfo_validity.len, n_sectors, MP_QSTR_validity); if (args[ARG_clear_validity].u_bool) { - memset(validity_buf, 0, sizeof(validity_buf)); + memset(bufinfo_validity.buf, 0, n_sectors); } } else { bufinfo_validity.buf = &validity_buf; diff --git a/shared-bindings/fourwire/FourWire.c b/shared-bindings/fourwire/FourWire.c index 083cf21a003..608645aaebf 100644 --- a/shared-bindings/fourwire/FourWire.c +++ b/shared-bindings/fourwire/FourWire.c @@ -30,9 +30,9 @@ //| self, //| spi_bus: busio.SPI, //| *, -//| command: Optional[microcontroller.Pin], -//| chip_select: Optional[microcontroller.Pin], -//| reset: Optional[microcontroller.Pin] = None, +//| command: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, +//| chip_select: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, +//| reset: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, //| baudrate: int = 24000000, //| polarity: int = 0, //| phase: int = 0, @@ -73,10 +73,6 @@ static mp_obj_t fourwire_fourwire_make_new(const mp_obj_type_t *type, size_t n_a 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 mcu_pin_obj_t *command = validate_obj_is_free_pin_or_none(args[ARG_command].u_obj, MP_QSTR_command); - const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin_or_none(args[ARG_chip_select].u_obj, MP_QSTR_chip_select); - const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj, MP_QSTR_reset); - mp_obj_t spi = mp_arg_validate_type(args[ARG_spi_bus].u_obj, &busio_spi_type, MP_QSTR_spi_bus); fourwire_fourwire_obj_t *self = &allocate_display_bus_or_raise()->fourwire_bus; @@ -86,7 +82,7 @@ static mp_obj_t fourwire_fourwire_make_new(const mp_obj_type_t *type, size_t n_a uint8_t phase = (uint8_t)mp_arg_validate_int_range(args[ARG_phase].u_int, 0, 1, MP_QSTR_phase); common_hal_fourwire_fourwire_construct(self, - MP_OBJ_TO_PTR(spi), command, chip_select, reset, args[ARG_baudrate].u_int, polarity, phase); + MP_OBJ_TO_PTR(spi), args[ARG_command].u_obj, args[ARG_chip_select].u_obj, args[ARG_reset].u_obj, args[ARG_baudrate].u_int, polarity, phase); return self; } diff --git a/shared-bindings/fourwire/FourWire.h b/shared-bindings/fourwire/FourWire.h index 515a466b4b9..3e77c25434d 100644 --- a/shared-bindings/fourwire/FourWire.h +++ b/shared-bindings/fourwire/FourWire.h @@ -16,8 +16,8 @@ extern const mp_obj_type_t fourwire_fourwire_type; void common_hal_fourwire_fourwire_construct(fourwire_fourwire_obj_t *self, - busio_spi_obj_t *spi, const mcu_pin_obj_t *command, - const mcu_pin_obj_t *chip_select, const mcu_pin_obj_t *reset, uint32_t baudrate, + busio_spi_obj_t *spi, mp_obj_t command, + mp_obj_t chip_select, mp_obj_t reset, uint32_t baudrate, uint8_t polarity, uint8_t phase); void common_hal_fourwire_fourwire_deinit(fourwire_fourwire_obj_t *self); diff --git a/shared-bindings/gifio/OnDiskGif.c b/shared-bindings/gifio/OnDiskGif.c index 092d9dd19cf..a710998bacb 100644 --- a/shared-bindings/gifio/OnDiskGif.c +++ b/shared-bindings/gifio/OnDiskGif.c @@ -112,7 +112,7 @@ static mp_obj_t gifio_ondiskgif_make_new(const mp_obj_type_t *type, size_t n_arg 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); - mp_obj_t filename = all_args[0]; + mp_obj_t filename = args[ARG_filename].u_obj; if (mp_obj_is_str(filename)) { filename = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), filename, MP_ROM_QSTR(MP_QSTR_rb)); } diff --git a/shared-bindings/gnss/GNSS.c b/shared-bindings/gnss/GNSS.c index 95c3ed975d5..3df23979c9e 100644 --- a/shared-bindings/gnss/GNSS.c +++ b/shared-bindings/gnss/GNSS.c @@ -38,7 +38,6 @@ //| ... //| static mp_obj_t gnss_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - gnss_obj_t *self = mp_obj_malloc(gnss_obj_t, &gnss_type); enum { ARG_system }; static const mp_arg_t allowed_args[] = { { MP_QSTR_system, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -63,7 +62,9 @@ static mp_obj_t gnss_make_new(const mp_obj_type_t *type, size_t n_args, size_t n mp_raise_TypeError(MP_ERROR_TEXT("System entry must be gnss.SatelliteSystem")); } + gnss_obj_t *self = mp_obj_malloc(gnss_obj_t, &gnss_type); common_hal_gnss_construct(self, selection); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/hashlib/__init__.c b/shared-bindings/hashlib/__init__.c index bfe19dee107..354529cfa77 100644 --- a/shared-bindings/hashlib/__init__.c +++ b/shared-bindings/hashlib/__init__.c @@ -20,7 +20,7 @@ //| //| def new(name: str, data: bytes = b"") -> hashlib.Hash: //| """Returns a Hash object setup for the named algorithm. Raises ValueError when the named -//| algorithm is unsupported. +//| algorithm is unsupported. Supported algorithms for ``name`` are ``'sha1'`` and ``'sha256'``. //| //| :return: a hash object for the given algorithm //| :rtype: hashlib.Hash""" diff --git a/shared-bindings/i2cioexpander/IOExpander.c b/shared-bindings/i2cioexpander/IOExpander.c new file mode 100644 index 00000000000..3efa0fd1868 --- /dev/null +++ b/shared-bindings/i2cioexpander/IOExpander.c @@ -0,0 +1,247 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-bindings/i2cioexpander/IOExpander.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/util.h" +#include "shared/runtime/context_manager_helpers.h" + +//| class IOExpander: +//| """Control a generic I2C-based GPIO expander +//| +//| IOExpander provides a simple interface to I2C-based GPIO expanders that +//| use basic register reads and writes for control. The expander provides +//| individual pins through the `pins` attribute that implement the +//| DigitalInOutProtocol. +//| """ +//| +//| def __init__( +//| self, +//| i2c: busio.I2C, +//| address: int, +//| num_pins: int, +//| set_value_reg: Optional[int] = None, +//| get_value_reg: Optional[int] = None, +//| set_direction_reg: Optional[int] = None, +//| ) -> None: +//| """Initialize an I2C GPIO expander +//| +//| :param busio.I2C i2c: The I2C bus the expander is connected to +//| :param int address: The I2C device address +//| :param int num_pins: The number of GPIO pins (8 or 16) +//| :param int set_value_reg: Register address to write pin values (optional) +//| :param int get_value_reg: Register address to read pin values (optional) +//| :param int set_direction_reg: Register address to set pin directions (optional) +//| """ +//| ... + +static mp_obj_t i2cioexpander_ioexpander_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_i2c, ARG_address, ARG_num_pins, ARG_set_value_reg, ARG_get_value_reg, ARG_set_direction_reg }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_num_pins, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_set_value_reg, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_get_value_reg, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_set_direction_reg, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + 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); + + // Validate I2C object + mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c].u_obj, &busio_i2c_type, MP_QSTR_i2c); + + // Validate address + int address = args[ARG_address].u_int; + if (address < 0 || address > 0x7F) { + mp_raise_ValueError(MP_ERROR_TEXT("address out of range")); + } + + // Validate num_pins + int num_pins = args[ARG_num_pins].u_int; + if (num_pins != 8 && num_pins != 16) { + mp_raise_ValueError(MP_ERROR_TEXT("num_pins must be 8 or 16")); + } + + // Convert and validate register parameters + uint16_t set_value_reg = NO_REGISTER; + if (args[ARG_set_value_reg].u_obj != mp_const_none) { + mp_int_t reg = mp_obj_get_int(args[ARG_set_value_reg].u_obj); + mp_arg_validate_int_range(reg, 0, 255, MP_QSTR_set_value_reg); + set_value_reg = reg; + } + + uint16_t get_value_reg = NO_REGISTER; + if (args[ARG_get_value_reg].u_obj != mp_const_none) { + mp_int_t reg = mp_obj_get_int(args[ARG_get_value_reg].u_obj); + mp_arg_validate_int_range(reg, 0, 255, MP_QSTR_get_value_reg); + get_value_reg = reg; + } + + uint16_t set_direction_reg = NO_REGISTER; + if (args[ARG_set_direction_reg].u_obj != mp_const_none) { + mp_int_t reg = mp_obj_get_int(args[ARG_set_direction_reg].u_obj); + mp_arg_validate_int_range(reg, 0, 255, MP_QSTR_set_direction_reg); + set_direction_reg = reg; + } + + i2cioexpander_ioexpander_obj_t *self = + mp_obj_malloc(i2cioexpander_ioexpander_obj_t, &i2cioexpander_ioexpander_type); + common_hal_i2cioexpander_ioexpander_construct( + self, + i2c, + address, + num_pins, + set_value_reg, + get_value_reg, + set_direction_reg); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialize the expander. No further operations are possible.""" +//| ... +static mp_obj_t i2cioexpander_ioexpander_deinit(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_i2cioexpander_ioexpander_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_deinit_obj, i2cioexpander_ioexpander_deinit); + +//| def __enter__(self) -> IOExpander: +//| """No-op used by Context Managers.""" +//| ... +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +static mp_obj_t i2cioexpander_ioexpander___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_i2cioexpander_ioexpander_deinit(MP_OBJ_TO_PTR(args[0])); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cioexpander_ioexpander___exit___obj, 4, 4, i2cioexpander_ioexpander___exit__); + +//| @property +//| def input_value(self) -> int: +//| """Read the live value of all pins at once. Returns an integer where each +//| bit represents a pin's current state.""" +//| ... +static mp_obj_t i2cioexpander_ioexpander_obj_get_input_value(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t value; + if (!common_hal_i2cioexpander_ioexpander_get_input_value(self, &value)) { + mp_raise_OSError(MP_EIO); + } + return MP_OBJ_NEW_SMALL_INT(value); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_input_value_obj, i2cioexpander_ioexpander_obj_get_input_value); + +MP_PROPERTY_GETTER(i2cioexpander_ioexpander_input_value_obj, + (mp_obj_t)&i2cioexpander_ioexpander_get_input_value_obj); + +//| @property +//| def output_value(self) -> int: +//| """Get or set the cached output value. Reading returns the last value written, +//| not the live pin state. Writing updates the output pins.""" +//| ... +//| @output_value.setter +//| def output_value(self, val: int) -> None: ... +static mp_obj_t i2cioexpander_ioexpander_obj_get_output_value(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t value; + common_hal_i2cioexpander_ioexpander_get_output_value(self, &value); + return mp_obj_new_int(value); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_output_value_obj, i2cioexpander_ioexpander_obj_get_output_value); + +static mp_obj_t i2cioexpander_ioexpander_obj_set_output_value(mp_obj_t self_in, mp_obj_t value) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_negative_errno_t result = common_hal_i2cioexpander_ioexpander_set_output_value(self, mp_obj_get_int(value)); + if (result != 0) { + mp_raise_OSError(result); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_ioexpander_set_output_value_obj, i2cioexpander_ioexpander_obj_set_output_value); + +MP_PROPERTY_GETSET(i2cioexpander_ioexpander_output_value_obj, + (mp_obj_t)&i2cioexpander_ioexpander_get_output_value_obj, + (mp_obj_t)&i2cioexpander_ioexpander_set_output_value_obj); + +//| @property +//| def output_mask(self) -> int: +//| """Get or set which pins are configured as outputs. Each bit in the mask +//| represents a pin: 1 for output, 0 for input.""" +//| ... +//| @output_mask.setter +//| def output_mask(self, val: int) -> None: ... +static mp_obj_t i2cioexpander_ioexpander_obj_get_output_mask(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t output_mask; + common_hal_i2cioexpander_ioexpander_get_output_mask(self, &output_mask); + return mp_obj_new_int(output_mask); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_output_mask_obj, i2cioexpander_ioexpander_obj_get_output_mask); + +static mp_obj_t i2cioexpander_ioexpander_obj_set_output_mask(mp_obj_t self_in, mp_obj_t value) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_negative_errno_t result = common_hal_i2cioexpander_ioexpander_set_output_mask(self, mp_obj_get_int(value)); + if (result != 0) { + mp_raise_OSError(result); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_ioexpander_set_output_mask_obj, i2cioexpander_ioexpander_obj_set_output_mask); + +MP_PROPERTY_GETSET(i2cioexpander_ioexpander_output_mask_obj, + (mp_obj_t)&i2cioexpander_ioexpander_get_output_mask_obj, + (mp_obj_t)&i2cioexpander_ioexpander_set_output_mask_obj); + +//| @property +//| def pins(self) -> Tuple[IOPin, ...]: +//| """A tuple of `IOPin` objects that implement the DigitalInOutProtocol. +//| Each pin can be used like a digitalio.DigitalInOut object.""" +//| ... +static mp_obj_t i2cioexpander_ioexpander_obj_get_pins(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_ioexpander_get_pins(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_pins_obj, i2cioexpander_ioexpander_obj_get_pins); + +MP_PROPERTY_GETTER(i2cioexpander_ioexpander_pins_obj, + (mp_obj_t)&i2cioexpander_ioexpander_get_pins_obj); + +static const mp_rom_map_elem_t i2cioexpander_ioexpander_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&i2cioexpander_ioexpander_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cioexpander_ioexpander___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_input_value), MP_ROM_PTR(&i2cioexpander_ioexpander_input_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_output_value), MP_ROM_PTR(&i2cioexpander_ioexpander_output_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_output_mask), MP_ROM_PTR(&i2cioexpander_ioexpander_output_mask_obj) }, + { MP_ROM_QSTR(MP_QSTR_pins), MP_ROM_PTR(&i2cioexpander_ioexpander_pins_obj) }, +}; +static MP_DEFINE_CONST_DICT(i2cioexpander_ioexpander_locals_dict, i2cioexpander_ioexpander_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + i2cioexpander_ioexpander_type, + MP_QSTR_IOExpander, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, i2cioexpander_ioexpander_make_new, + locals_dict, &i2cioexpander_ioexpander_locals_dict + ); diff --git a/shared-bindings/i2cioexpander/IOExpander.h b/shared-bindings/i2cioexpander/IOExpander.h new file mode 100644 index 00000000000..5c93c6250cc --- /dev/null +++ b/shared-bindings/i2cioexpander/IOExpander.h @@ -0,0 +1,34 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-module/i2cioexpander/IOExpander.h" + +extern const mp_obj_type_t i2cioexpander_ioexpander_type; + +void common_hal_i2cioexpander_ioexpander_construct( + i2cioexpander_ioexpander_obj_t *self, + mp_obj_t i2c, + uint8_t address, + uint8_t num_pins, + uint16_t set_value_reg, + uint16_t get_value_reg, + uint16_t set_direction_reg); + +void common_hal_i2cioexpander_ioexpander_deinit(i2cioexpander_ioexpander_obj_t *self); +bool common_hal_i2cioexpander_ioexpander_deinited(i2cioexpander_ioexpander_obj_t *self); + +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_get_input_value(i2cioexpander_ioexpander_obj_t *self, size_t *value); +// No error return because this returns a cached value. +void common_hal_i2cioexpander_ioexpander_get_output_value(i2cioexpander_ioexpander_obj_t *self, size_t *value); +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_set_output_value(i2cioexpander_ioexpander_obj_t *self, size_t value); + +void common_hal_i2cioexpander_ioexpander_get_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t *mask); +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_set_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t mask); + +mp_obj_t common_hal_i2cioexpander_ioexpander_get_pins(i2cioexpander_ioexpander_obj_t *self); diff --git a/shared-bindings/i2cioexpander/IOPin.c b/shared-bindings/i2cioexpander/IOPin.c new file mode 100644 index 00000000000..bba229bd31e --- /dev/null +++ b/shared-bindings/i2cioexpander/IOPin.c @@ -0,0 +1,326 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/i2cioexpander/IOPin.h" +#include "shared-module/i2cioexpander/IOPin.h" + +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" +#include "shared-bindings/digitalio/Direction.h" +#include "shared-bindings/digitalio/DriveMode.h" +#include "shared-bindings/digitalio/Pull.h" +#include "shared-bindings/util.h" + +static void check_result(digitalinout_result_t result) { + switch (result) { + case DIGITALINOUT_OK: + return; + case DIGITALINOUT_PIN_BUSY: + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_Pin); + #if CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY + case DIGITALINOUT_INPUT_ONLY: + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_direction); + #endif + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL + case DIGITALINOUT_INVALID_PULL: + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pull); + #endif + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE + case DIGITALINOUT_INVALID_DRIVE_MODE: + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_drive_mode); + #endif + } +} + +static inline void check_for_deinit(i2cioexpander_iopin_obj_t *self) { + if (common_hal_i2cioexpander_iopin_deinited(self)) { + raise_deinited_error(); + } +} +//| class IOPin: +//| """Control a single pin on an `IOExpander` in the same way as `DigitalInOut`. +//| +//| Not constructed directly. Get from `IOExpander.pins` instead. +//| """ +//| + +//| def switch_to_output( +//| self, value: bool = False, drive_mode: digitalio.DriveMode = digitalio.DriveMode.PUSH_PULL +//| ) -> None: +//| """Set the drive mode and value and then switch to writing out digital values. +//| +//| :param bool value: default value to set upon switching +//| :param digitalio.DriveMode drive_mode: drive mode for the output""" +//| ... +static mp_obj_t i2cioexpander_iopin_switch_to_output(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_value, ARG_drive_mode }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_value, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_drive_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&digitalio_drive_mode_push_pull_obj)} }, + }; + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + 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); + + digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL; + if (args[ARG_drive_mode].u_rom_obj == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { + drive_mode = DRIVE_MODE_OPEN_DRAIN; + } + check_result(common_hal_i2cioexpander_iopin_switch_to_output(self, args[ARG_value].u_bool, drive_mode)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(i2cioexpander_iopin_switch_to_output_obj, 1, i2cioexpander_iopin_switch_to_output); + +//| def switch_to_input(self, pull: Optional[digitalio.Pull] = None) -> None: +//| """Set the pull and then switch to read in digital values. +//| +//| :param digitalio.Pull pull: pull configuration for the input""" +//| ... +static mp_obj_t i2cioexpander_iopin_switch_to_input(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_pull }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + }; + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + 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); + + check_result(common_hal_i2cioexpander_iopin_switch_to_input(self, validate_pull(args[ARG_pull].u_rom_obj, MP_QSTR_pull))); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(i2cioexpander_iopin_switch_to_input_obj, 1, i2cioexpander_iopin_switch_to_input); + +//| direction: digitalio.Direction +//| """The direction of the pin.""" +static mp_obj_t i2cioexpander_iopin_obj_get_direction(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + digitalio_direction_t direction = common_hal_i2cioexpander_iopin_get_direction(self); + if (direction == DIRECTION_INPUT) { + return MP_OBJ_FROM_PTR(&digitalio_direction_input_obj); + } + return MP_OBJ_FROM_PTR(&digitalio_direction_output_obj); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_get_direction_obj, i2cioexpander_iopin_obj_get_direction); + +static mp_obj_t i2cioexpander_iopin_obj_set_direction(mp_obj_t self_in, mp_obj_t value) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (value == MP_ROM_PTR(&digitalio_direction_input_obj)) { + check_result(common_hal_i2cioexpander_iopin_switch_to_input(self, PULL_NONE)); + } else if (value == MP_ROM_PTR(&digitalio_direction_output_obj)) { + check_result(common_hal_i2cioexpander_iopin_switch_to_output(self, false, DRIVE_MODE_PUSH_PULL)); + } else { + mp_arg_error_invalid(MP_QSTR_direction); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_iopin_set_direction_obj, i2cioexpander_iopin_obj_set_direction); + +MP_PROPERTY_GETSET(i2cioexpander_iopin_direction_obj, + (mp_obj_t)&i2cioexpander_iopin_get_direction_obj, + (mp_obj_t)&i2cioexpander_iopin_set_direction_obj); + +//| value: bool +//| """The digital logic level of the pin.""" +static mp_obj_t i2cioexpander_iopin_obj_get_value(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + bool value; + mp_negative_errno_t res = common_hal_i2cioexpander_iopin_get_value(self, &value); + if (res != 0) { + mp_raise_OSError(-res); + } + return mp_obj_new_bool(value); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_get_value_obj, i2cioexpander_iopin_obj_get_value); + +static mp_obj_t i2cioexpander_iopin_obj_set_value(mp_obj_t self_in, mp_obj_t value) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_INPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Cannot set value when direction is input.")); + return mp_const_none; + } + mp_negative_errno_t res = common_hal_i2cioexpander_iopin_set_value(self, mp_obj_is_true(value)); + if (res != 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_iopin_set_value_obj, i2cioexpander_iopin_obj_set_value); + +MP_PROPERTY_GETSET(i2cioexpander_iopin_value_obj, + (mp_obj_t)&i2cioexpander_iopin_get_value_obj, + (mp_obj_t)&i2cioexpander_iopin_set_value_obj); + +//| drive_mode: digitalio.DriveMode +//| """The pin drive mode.""" +static mp_obj_t i2cioexpander_iopin_obj_get_drive_mode(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_INPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Drive mode not used when direction is input.")); + return mp_const_none; + } + digitalio_drive_mode_t drive_mode = common_hal_i2cioexpander_iopin_get_drive_mode(self); + if (drive_mode == DRIVE_MODE_PUSH_PULL) { + return MP_OBJ_FROM_PTR(&digitalio_drive_mode_push_pull_obj); + } + return MP_OBJ_FROM_PTR(&digitalio_drive_mode_open_drain_obj); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_get_drive_mode_obj, i2cioexpander_iopin_obj_get_drive_mode); + +static mp_obj_t i2cioexpander_iopin_obj_set_drive_mode(mp_obj_t self_in, mp_obj_t drive_mode) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_INPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Drive mode not used when direction is input.")); + return mp_const_none; + } + digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL; + if (drive_mode == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { + c_drive_mode = DRIVE_MODE_OPEN_DRAIN; + } + check_result(common_hal_i2cioexpander_iopin_set_drive_mode(self, c_drive_mode)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_iopin_set_drive_mode_obj, i2cioexpander_iopin_obj_set_drive_mode); + +MP_PROPERTY_GETSET(i2cioexpander_iopin_drive_mode_obj, + (mp_obj_t)&i2cioexpander_iopin_get_drive_mode_obj, + (mp_obj_t)&i2cioexpander_iopin_set_drive_mode_obj); + +//| pull: Optional[digitalio.Pull] +//| """The pin pull direction.""" +static mp_obj_t i2cioexpander_iopin_obj_get_pull(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_OUTPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Pull not used when direction is output.")); + return mp_const_none; + } + digitalio_pull_t pull = common_hal_i2cioexpander_iopin_get_pull(self); + if (pull == PULL_UP) { + return MP_OBJ_FROM_PTR(&digitalio_pull_up_obj); + } else if (pull == PULL_DOWN) { + return MP_OBJ_FROM_PTR(&digitalio_pull_down_obj); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_get_pull_obj, i2cioexpander_iopin_obj_get_pull); + +static mp_obj_t i2cioexpander_iopin_obj_set_pull(mp_obj_t self_in, mp_obj_t pull_obj) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_OUTPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Pull not used when direction is output.")); + return mp_const_none; + } + check_result(common_hal_i2cioexpander_iopin_set_pull(self, validate_pull(pull_obj, MP_QSTR_pull))); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_iopin_set_pull_obj, i2cioexpander_iopin_obj_set_pull); + +MP_PROPERTY_GETSET(i2cioexpander_iopin_pull_obj, + (mp_obj_t)&i2cioexpander_iopin_get_pull_obj, + (mp_obj_t)&i2cioexpander_iopin_set_pull_obj); + +// Protocol implementation for DigitalInOutProtocol +static void iopin_protocol_deinit(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_i2cioexpander_iopin_deinit(self); +} + +static bool iopin_protocol_deinited(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_deinited(self); +} + +static digitalinout_result_t iopin_protocol_switch_to_input(mp_obj_t self_in, digitalio_pull_t pull) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_switch_to_input(self, pull); +} + +static digitalinout_result_t iopin_protocol_switch_to_output(mp_obj_t self_in, bool value, digitalio_drive_mode_t drive_mode) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_switch_to_output(self, value, drive_mode); +} + +static digitalio_direction_t iopin_protocol_get_direction(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_get_direction(self); +} + +static mp_negative_errno_t iopin_protocol_get_value(mp_obj_t self_in, bool *value) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_get_value(self, value); +} + +static mp_negative_errno_t iopin_protocol_set_value(mp_obj_t self_in, bool value) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_set_value(self, value); +} + +static digitalio_drive_mode_t iopin_protocol_get_drive_mode(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_get_drive_mode(self); +} + +static digitalinout_result_t iopin_protocol_set_drive_mode(mp_obj_t self_in, digitalio_drive_mode_t drive_mode) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_set_drive_mode(self, drive_mode); +} + +static digitalio_pull_t iopin_protocol_get_pull(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_get_pull(self); +} + +static digitalinout_result_t iopin_protocol_set_pull(mp_obj_t self_in, digitalio_pull_t pull) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_set_pull(self, pull); +} + +static const digitalinout_p_t iopin_digitalinout_p = { + MP_PROTO_IMPLEMENT(MP_QSTR_DigitalInOut) + .deinit = iopin_protocol_deinit, + .deinited = iopin_protocol_deinited, + .switch_to_input = iopin_protocol_switch_to_input, + .switch_to_output = iopin_protocol_switch_to_output, + .get_direction = iopin_protocol_get_direction, + .get_value = iopin_protocol_get_value, + .set_value = iopin_protocol_set_value, + .get_drive_mode = iopin_protocol_get_drive_mode, + .set_drive_mode = iopin_protocol_set_drive_mode, + .get_pull = iopin_protocol_get_pull, + .set_pull = iopin_protocol_set_pull, +}; + +static const mp_rom_map_elem_t i2cioexpander_iopin_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_switch_to_input), MP_ROM_PTR(&i2cioexpander_iopin_switch_to_input_obj) }, + { MP_ROM_QSTR(MP_QSTR_switch_to_output), MP_ROM_PTR(&i2cioexpander_iopin_switch_to_output_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_direction), MP_ROM_PTR(&i2cioexpander_iopin_direction_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&i2cioexpander_iopin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_drive_mode), MP_ROM_PTR(&i2cioexpander_iopin_drive_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_pull), MP_ROM_PTR(&i2cioexpander_iopin_pull_obj) }, +}; +static MP_DEFINE_CONST_DICT(i2cioexpander_iopin_locals_dict, i2cioexpander_iopin_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + i2cioexpander_iopin_type, + MP_QSTR_IOPin, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + protocol, &iopin_digitalinout_p, + locals_dict, &i2cioexpander_iopin_locals_dict + ); diff --git a/shared-bindings/i2cioexpander/IOPin.h b/shared-bindings/i2cioexpander/IOPin.h new file mode 100644 index 00000000000..c8155c71aa1 --- /dev/null +++ b/shared-bindings/i2cioexpander/IOPin.h @@ -0,0 +1,46 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-module/i2cioexpander/IOPin.h" + +extern const mp_obj_type_t i2cioexpander_iopin_type; + +mp_negative_errno_t i2cioexpander_iopin_construct( + i2cioexpander_iopin_obj_t *self, + i2cioexpander_ioexpander_obj_t *expander, + uint8_t pin_number); + +void common_hal_i2cioexpander_iopin_deinit(i2cioexpander_iopin_obj_t *self); +bool common_hal_i2cioexpander_iopin_deinited(i2cioexpander_iopin_obj_t *self); + +digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_input( + i2cioexpander_iopin_obj_t *self, + digitalio_pull_t pull); + +digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_output( + i2cioexpander_iopin_obj_t *self, + bool value, + digitalio_drive_mode_t drive_mode); + +digitalio_direction_t common_hal_i2cioexpander_iopin_get_direction(i2cioexpander_iopin_obj_t *self); + +mp_negative_errno_t common_hal_i2cioexpander_iopin_set_value(i2cioexpander_iopin_obj_t *self, bool value); +mp_negative_errno_t common_hal_i2cioexpander_iopin_get_value(i2cioexpander_iopin_obj_t *self, bool *value); + +digitalinout_result_t common_hal_i2cioexpander_iopin_set_drive_mode( + i2cioexpander_iopin_obj_t *self, + digitalio_drive_mode_t drive_mode); + +digitalio_drive_mode_t common_hal_i2cioexpander_iopin_get_drive_mode(i2cioexpander_iopin_obj_t *self); + +digitalinout_result_t common_hal_i2cioexpander_iopin_set_pull( + i2cioexpander_iopin_obj_t *self, + digitalio_pull_t pull); + +digitalio_pull_t common_hal_i2cioexpander_iopin_get_pull(i2cioexpander_iopin_obj_t *self); diff --git a/shared-bindings/i2cioexpander/__init__.c b/shared-bindings/i2cioexpander/__init__.c new file mode 100644 index 00000000000..106c45c3768 --- /dev/null +++ b/shared-bindings/i2cioexpander/__init__.c @@ -0,0 +1,49 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/i2cioexpander/__init__.h" +#include "shared-bindings/i2cioexpander/IOExpander.h" + +//| """Support for I2C-based GPIO expanders +//| +//| The `i2cioexpander` module contains classes to support I2C-based GPIO expanders +//| that can be controlled via simple register reads and writes. +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed if the program continues after use. To do so, either +//| call :py:meth:`!deinit` or use a context manager. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +//| Example:: +//| +//| import board +//| import busio +//| import i2cioexpander +//| +//| i2c = busio.I2C(board.SCL, board.SDA) +//| expander = i2cioexpander.IOExpander(i2c, 0x20, 8, 0x01, 0x00, 0x03) +//| pin0 = expander.pins[0] +//| pin0.switch_to_output(value=True) +//| """ + +static const mp_rom_map_elem_t i2cioexpander_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2cioexpander) }, + { MP_ROM_QSTR(MP_QSTR_IOExpander), MP_ROM_PTR(&i2cioexpander_ioexpander_type) }, +}; + +static MP_DEFINE_CONST_DICT(i2cioexpander_module_globals, i2cioexpander_module_globals_table); + +const mp_obj_module_t i2cioexpander_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&i2cioexpander_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_i2cioexpander, i2cioexpander_module); diff --git a/shared-bindings/i2cioexpander/__init__.h b/shared-bindings/i2cioexpander/__init__.h new file mode 100644 index 00000000000..e0d06686868 --- /dev/null +++ b/shared-bindings/i2cioexpander/__init__.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Nothing now. diff --git a/shared-bindings/i2ctarget/I2CTarget.c b/shared-bindings/i2ctarget/I2CTarget.c index 8586d1843cc..94dbf4e8be4 100644 --- a/shared-bindings/i2ctarget/I2CTarget.c +++ b/shared-bindings/i2ctarget/I2CTarget.c @@ -26,7 +26,8 @@ static mp_obj_t mp_obj_new_i2ctarget_i2c_target_request(i2ctarget_i2c_target_obj self->address = address; self->is_read = is_read; self->is_restart = is_restart; - return (mp_obj_t)self; + + return MP_OBJ_FROM_PTR(self); } //| class I2CTarget: @@ -50,7 +51,6 @@ static mp_obj_t mp_obj_new_i2ctarget_i2c_target_request(i2ctarget_i2c_target_obj //| ... //| static mp_obj_t i2ctarget_i2c_target_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - i2ctarget_i2c_target_obj_t *self = mp_obj_malloc_with_finaliser(i2ctarget_i2c_target_obj_t, &i2ctarget_i2c_target_type); enum { ARG_scl, ARG_sda, ARG_addresses, ARG_smbus }; static const mp_arg_t allowed_args[] = { { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -78,8 +78,10 @@ static mp_obj_t i2ctarget_i2c_target_make_new(const mp_obj_type_t *type, size_t mp_raise_ValueError(MP_ERROR_TEXT("addresses is empty")); } + i2ctarget_i2c_target_obj_t *self = mp_obj_malloc_with_finaliser(i2ctarget_i2c_target_obj_t, &i2ctarget_i2c_target_type); common_hal_i2ctarget_i2c_target_construct(self, scl, sda, addresses, i, args[ARG_smbus].u_bool); - return (mp_obj_t)self; + + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: diff --git a/shared-bindings/imagecapture/ParallelImageCapture.c b/shared-bindings/imagecapture/ParallelImageCapture.c index 866edb489ce..427eaeb3793 100644 --- a/shared-bindings/imagecapture/ParallelImageCapture.c +++ b/shared-bindings/imagecapture/ParallelImageCapture.c @@ -58,7 +58,6 @@ static mp_obj_t imagecapture_parallelimagecapture_make_new(const mp_obj_type_t * imagecapture_parallelimagecapture_obj_t *self = mp_obj_malloc(imagecapture_parallelimagecapture_obj_t, &imagecapture_parallelimagecapture_type); - common_hal_imagecapture_parallelimagecapture_construct(self, pins, pin_count, clock, vsync, href); return self; diff --git a/shared-bindings/ipaddress/IPv4Address.c b/shared-bindings/ipaddress/IPv4Address.c index 5aab02e9f5c..6c11f528506 100644 --- a/shared-bindings/ipaddress/IPv4Address.c +++ b/shared-bindings/ipaddress/IPv4Address.c @@ -38,8 +38,10 @@ static mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t uint32_t value; uint8_t *buf = NULL; - if (mp_obj_get_int_maybe(address, (mp_int_t *)&value)) { + mp_int_t int_value; + if (mp_obj_get_int_maybe(address, &int_value)) { // We're done. + value = (uint32_t)int_value; buf = (uint8_t *)&value; } else if (mp_obj_is_str(address)) { GET_STR_DATA_LEN(address, str_data, str_len); @@ -49,17 +51,17 @@ static mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t buf = (uint8_t *)&value; } else { mp_buffer_info_t buf_info; - if (mp_get_buffer(address, &buf_info, MP_BUFFER_READ)) { - if (buf_info.len != 4) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("Address must be %d bytes long"), 4); - } - buf = buf_info.buf; + if (!mp_get_buffer(address, &buf_info, MP_BUFFER_READ)) { + mp_arg_error_invalid(MP_QSTR_address); + } + if (buf_info.len != 4) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Address must be %d bytes long"), 4); } + buf = buf_info.buf; } ipaddress_ipv4address_obj_t *self = mp_obj_malloc(ipaddress_ipv4address_obj_t, &ipaddress_ipv4address_type); - common_hal_ipaddress_ipv4address_construct(self, buf, 4); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/ipaddress/__init__.c b/shared-bindings/ipaddress/__init__.c index 60bc6226ba1..db8d22948a1 100644 --- a/shared-bindings/ipaddress/__init__.c +++ b/shared-bindings/ipaddress/__init__.c @@ -30,7 +30,7 @@ bool ipaddress_parse_ipv4address(const char *str_data, size_t str_len, uint32_t period_count++; } } - if (period_count > 3) { + if (period_count != 3) { return false; } @@ -50,7 +50,13 @@ bool ipaddress_parse_ipv4address(const char *str_data, size_t str_len, uint32_t } last_period = period_index[i] + 1; if (ip_out != NULL) { + if (!mp_obj_is_small_int(octet)) { + return false; + } mp_int_t int_octet = MP_OBJ_SMALL_INT_VALUE(octet); + if (int_octet < 0 || int_octet > 255) { + return false; + } *ip_out |= int_octet << (i * 8); } } diff --git a/shared-bindings/is31fl3741/IS31FL3741.c b/shared-bindings/is31fl3741/IS31FL3741.c index 0c6b3479b04..71c4437a1d2 100644 --- a/shared-bindings/is31fl3741/IS31FL3741.c +++ b/shared-bindings/is31fl3741/IS31FL3741.c @@ -38,7 +38,6 @@ static mp_obj_t is31fl3741_IS31FL3741_make_new(const mp_obj_type_t *type, size_t mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus); is31fl3741_IS31FL3741_obj_t *self = mp_obj_malloc(is31fl3741_IS31FL3741_obj_t, &is31fl3741_IS31FL3741_type); - common_hal_is31fl3741_IS31FL3741_construct(self, MP_OBJ_TO_PTR(i2c), args[ARG_addr].u_int diff --git a/shared-bindings/jpegio/JpegDecoder.c b/shared-bindings/jpegio/JpegDecoder.c index 13287a23650..d55de7b67e0 100644 --- a/shared-bindings/jpegio/JpegDecoder.c +++ b/shared-bindings/jpegio/JpegDecoder.c @@ -23,13 +23,18 @@ //| Example:: //| //| from jpegio import JpegDecoder -//| from displayio import Bitmap +//| from displayio import Bitmap, TileGrid, ColorConverter, Colorspace +//| import supervisor //| //| decoder = JpegDecoder() //| width, height = decoder.open("/sd/example.jpg") //| bitmap = Bitmap(width, height, 65535) //| decoder.decode(bitmap) -//| # .. do something with bitmap +//| tg = TileGrid(bitmap, pixel_shader=ColorConverter(input_colorspace=Colorspace.RGB565_SWAPPED)) +//| supervisor.runtime.display.root_group = tg +//| while True: +//| pass +//| //| """ //| //| def __init__(self) -> None: @@ -43,7 +48,6 @@ static mp_obj_t jpegio_jpegdecoder_make_new(const mp_obj_type_t *type, size_t n_ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); jpegio_jpegdecoder_obj_t *self = mp_obj_malloc(jpegio_jpegdecoder_obj_t, &jpegio_jpegdecoder_type); - self->base.type = &jpegio_jpegdecoder_type; common_hal_jpegio_jpegdecoder_construct(self); return MP_OBJ_FROM_PTR(self); @@ -137,7 +141,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(jpegio_jpegdecoder_open_obj, jpegio_jpegdecoder_open); //| """ //| //| -static mp_obj_t jpegio_jpegdecoder_decode(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +static mp_obj_t jpegio_jpegdecoder_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { jpegio_jpegdecoder_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); enum { ARG_bitmap, ARG_scale, ARG_x, ARG_y, ARGS_X1_Y1_X2_Y2, ARG_skip_source_index, ARG_skip_dest_index }; diff --git a/shared-bindings/keypad/Event.c b/shared-bindings/keypad/Event.c index 51e446e8362..f83e01e785e 100644 --- a/shared-bindings/keypad/Event.c +++ b/shared-bindings/keypad/Event.c @@ -26,7 +26,6 @@ //| ... //| static mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - keypad_event_obj_t *self = mp_obj_malloc(keypad_event_obj_t, &keypad_event_type); enum { ARG_key_number, ARG_pressed, ARG_timestamp }; static const mp_arg_t allowed_args[] = { { MP_QSTR_key_number, MP_ARG_INT, {.u_int = 0} }, @@ -45,7 +44,9 @@ static mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, } (void)mp_obj_get_int_truncated(timestamp); // ensure that timestamp is an integer + keypad_event_obj_t *self = mp_obj_malloc(keypad_event_obj_t, &keypad_event_type); common_hal_keypad_event_construct(self, key_number, args[ARG_pressed].u_bool, timestamp); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index edb32c2c5c7..f8d45eac62f 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -81,7 +81,6 @@ static mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_KEYPAD_KEYMATRIX - keypad_keymatrix_obj_t *self = mp_obj_malloc(keypad_keymatrix_obj_t, &keypad_keymatrix_type); enum { ARG_row_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events, ARG_debounce_threshold }; static const mp_arg_t allowed_args[] = { { MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -123,7 +122,9 @@ static mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar column_pins_array[column] = pin; } + keypad_keymatrix_obj_t *self = mp_obj_malloc(keypad_keymatrix_obj_t, &keypad_keymatrix_type); common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events, debounce_threshold); + return MP_OBJ_FROM_PTR(self); #else mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_KeyMatrix); @@ -194,7 +195,7 @@ static mp_obj_t keypad_keymatrix_key_number_to_row_column(mp_obj_t self_in, mp_o const mp_uint_t key_number = (mp_uint_t)mp_arg_validate_int_range( mp_obj_get_int(key_number_in), - 0, (mp_int_t)common_hal_keypad_generic_get_key_count(self), + 0, (mp_int_t)common_hal_keypad_generic_get_key_count(self) - 1, MP_QSTR_key_number); mp_uint_t row; @@ -220,10 +221,10 @@ static mp_obj_t keypad_keymatrix_row_column_to_key_number(mp_obj_t self_in, mp_o check_for_deinit(self); const mp_uint_t row = (mp_uint_t)mp_arg_validate_int_range( - mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_row_count(self), MP_QSTR_row); + mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_row_count(self) - 1, MP_QSTR_row); const mp_int_t column = (mp_uint_t)mp_arg_validate_int_range( - mp_obj_get_int(column_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_column_count(self), MP_QSTR_column); + mp_obj_get_int(column_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_column_count(self) - 1, MP_QSTR_column); return MP_OBJ_NEW_SMALL_INT( (mp_int_t)common_hal_keypad_keymatrix_row_column_to_key_number(self, row, column)); diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 64e8e51a67d..5fd065fc627 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -81,7 +81,6 @@ static mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_KEYPAD_KEYS - keypad_keys_obj_t *self = mp_obj_malloc(keypad_keys_obj_t, &keypad_keys_type); enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_interval, ARG_max_events, ARG_debounce_threshold }; static const mp_arg_t allowed_args[] = { { MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -112,6 +111,7 @@ static mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, s validate_obj_is_free_pin(mp_obj_subscr(pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL), MP_QSTR_pin); } + keypad_keys_obj_t *self = mp_obj_malloc(keypad_keys_obj_t, &keypad_keys_type); common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events, debounce_threshold); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index 1347735b5d2..7f89a11ecf1 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -88,8 +88,6 @@ static mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS - keypad_shiftregisterkeys_obj_t *self = - mp_obj_malloc(keypad_shiftregisterkeys_obj_t, &keypad_shiftregisterkeys_type); enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_key_count, ARG_value_when_pressed, ARG_interval, ARG_max_events, ARG_debounce_threshold }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -160,6 +158,8 @@ static mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); const uint8_t debounce_threshold = (uint8_t)mp_arg_validate_int_range(args[ARG_debounce_threshold].u_int, 1, 127, MP_QSTR_debounce_threshold); + keypad_shiftregisterkeys_obj_t *self = + mp_obj_malloc(keypad_shiftregisterkeys_obj_t, &keypad_shiftregisterkeys_type); common_hal_keypad_shiftregisterkeys_construct( self, clock, num_data_pins, data_pins_array, latch, value_to_latch, num_key_counts, key_count_array, value_when_pressed, interval, max_events, debounce_threshold); diff --git a/shared-bindings/keypad_demux/DemuxKeyMatrix.c b/shared-bindings/keypad_demux/DemuxKeyMatrix.c index f1b5ecae9ce..ba8d857c6a3 100644 --- a/shared-bindings/keypad_demux/DemuxKeyMatrix.c +++ b/shared-bindings/keypad_demux/DemuxKeyMatrix.c @@ -80,7 +80,6 @@ //| static mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - keypad_demux_demuxkeymatrix_obj_t *self = mp_obj_malloc(keypad_demux_demuxkeymatrix_obj_t, &keypad_demux_demuxkeymatrix_type); enum { ARG_row_addr_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_transpose, ARG_interval, ARG_max_events, ARG_debounce_threshold }; static const mp_arg_t allowed_args[] = { { MP_QSTR_row_addr_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -123,8 +122,10 @@ static mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type, column_pins_array[column] = pin; } + keypad_demux_demuxkeymatrix_obj_t *self = mp_obj_malloc(keypad_demux_demuxkeymatrix_obj_t, &keypad_demux_demuxkeymatrix_type); // Last arg is use_gc_allocator, true during VM use. common_hal_keypad_demux_demuxkeymatrix_construct(self, num_row_addr_pins, row_addr_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, args[ARG_transpose].u_bool, interval, max_events, debounce_threshold, true); + return MP_OBJ_FROM_PTR(self); } @@ -190,7 +191,7 @@ static mp_obj_t keypad_demux_demuxkeymatrix_key_number_to_row_column(mp_obj_t se const mp_uint_t key_number = (mp_uint_t)mp_arg_validate_int_range( mp_obj_get_int(key_number_in), - 0, (mp_int_t)common_hal_keypad_generic_get_key_count(self), + 0, (mp_int_t)common_hal_keypad_generic_get_key_count(self) - 1, MP_QSTR_key_number); mp_uint_t row; @@ -216,10 +217,10 @@ static mp_obj_t keypad_demux_demuxkeymatrix_row_column_to_key_number(mp_obj_t se check_for_deinit(self); const mp_uint_t row = (mp_uint_t)mp_arg_validate_int_range( - mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_demux_demuxkeymatrix_get_row_count(self), MP_QSTR_row); + mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_demux_demuxkeymatrix_get_row_count(self) - 1, MP_QSTR_row); const mp_int_t column = (mp_uint_t)mp_arg_validate_int_range( - mp_obj_get_int(column_in), 0, (mp_int_t)common_hal_keypad_demux_demuxkeymatrix_get_column_count(self), MP_QSTR_column); + mp_obj_get_int(column_in), 0, (mp_int_t)common_hal_keypad_demux_demuxkeymatrix_get_column_count(self) - 1, MP_QSTR_column); return MP_OBJ_NEW_SMALL_INT( (mp_int_t)common_hal_keypad_demux_demuxkeymatrix_row_column_to_key_number(self, row, column)); diff --git a/shared-bindings/math/__init__.c b/shared-bindings/math/__init__.c index 54fe53280ca..49ca2958d8c 100644 --- a/shared-bindings/math/__init__.c +++ b/shared-bindings/math/__init__.c @@ -26,7 +26,7 @@ //| """ //| -static NORETURN void math_error(void) { +static MP_NORETURN void math_error(void) { mp_raise_ValueError(MP_ERROR_TEXT("math domain error")); } diff --git a/shared-bindings/mcp4822/MCP4822.c b/shared-bindings/mcp4822/MCP4822.c new file mode 100644 index 00000000000..f192caf4052 --- /dev/null +++ b/shared-bindings/mcp4822/MCP4822.c @@ -0,0 +1,243 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/mcp4822/MCP4822.h" +#include "shared-bindings/util.h" + +//| class MCP4822: +//| """Output audio to an MCP4822 dual-channel 12-bit SPI DAC.""" +//| +//| def __init__( +//| self, +//| clock: microcontroller.Pin, +//| mosi: microcontroller.Pin, +//| cs: microcontroller.Pin, +//| *, +//| gain: int = 1, +//| ) -> None: +//| """Create an MCP4822 object associated with the given SPI pins. +//| +//| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin +//| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin +//| :param ~microcontroller.Pin cs: The chip select (CS) pin +//| :param int gain: DAC output gain, 1 for 1x (0-2.048V) or 2 for 2x (0-4.096V). Default 1. +//| +//| Simple 8ksps 440 Hz sine wave:: +//| +//| import mcp4822 +//| import audiocore +//| import board +//| import array +//| import time +//| import math +//| +//| length = 8000 // 440 +//| sine_wave = array.array("H", [0] * length) +//| for i in range(length): +//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15) +//| +//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) +//| dac = mcp4822.MCP4822(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(sine_wave, loop=True) +//| time.sleep(1) +//| dac.stop() +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audiocore +//| import mcp4822 +//| +//| f = open("sound.wav", "rb") +//| wav = audiocore.WaveFile(f) +//| +//| dac = mcp4822.MCP4822(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(wav) +//| while dac.playing: +//| pass""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_clock, ARG_mosi, ARG_cs, ARG_gain }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_gain, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, + }; + 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 mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); + const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + const mp_int_t gain = mp_arg_validate_int_range(args[ARG_gain].u_int, 1, 2, MP_QSTR_gain); + + mcp4822_mcp4822_obj_t *self = mp_obj_malloc_with_finaliser(mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); + common_hal_mcp4822_mcp4822_construct(self, clock, mosi, cs, (uint8_t)gain); + + return MP_OBJ_FROM_PTR(self); +} + +static void check_for_deinit(mcp4822_mcp4822_obj_t *self) { + if (common_hal_mcp4822_mcp4822_deinited(self)) { + raise_deinited_error(); + } +} + +//| def deinit(self) -> None: +//| """Deinitialises the MCP4822 and releases any hardware resources for reuse.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_deinit(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_mcp4822_mcp4822_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_deinit_obj, mcp4822_mcp4822_deinit); + +//| def __enter__(self) -> MCP4822: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. +//| +//| The sample itself should consist of 8 bit or 16 bit samples.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + 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_obj_t sample = args[ARG_sample].u_obj; + common_hal_mcp4822_mcp4822_play(self, sample, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mcp4822_mcp4822_play_obj, 1, mcp4822_mcp4822_obj_play); + +//| def stop(self) -> None: +//| """Stops playback.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_stop(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_mcp4822_mcp4822_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_stop_obj, mcp4822_mcp4822_obj_stop); + +//| playing: bool +//| """True when the audio sample is being output. (read-only)""" +//| +static mp_obj_t mcp4822_mcp4822_obj_get_playing(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mcp4822_mcp4822_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_get_playing_obj, mcp4822_mcp4822_obj_get_playing); + +MP_PROPERTY_GETTER(mcp4822_mcp4822_playing_obj, + (mp_obj_t)&mcp4822_mcp4822_get_playing_obj); + +//| def pause(self) -> None: +//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_pause(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (!common_hal_mcp4822_mcp4822_get_playing(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Not playing")); + } + common_hal_mcp4822_mcp4822_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_pause_obj, mcp4822_mcp4822_obj_pause); + +//| def resume(self) -> None: +//| """Resumes sample playback after :py:func:`pause`.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_resume(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (common_hal_mcp4822_mcp4822_get_paused(self)) { + common_hal_mcp4822_mcp4822_resume(self); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_resume_obj, mcp4822_mcp4822_obj_resume); + +//| paused: bool +//| """True when playback is paused. (read-only)""" +//| +//| +static mp_obj_t mcp4822_mcp4822_obj_get_paused(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mcp4822_mcp4822_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_get_paused_obj, mcp4822_mcp4822_obj_get_paused); + +MP_PROPERTY_GETTER(mcp4822_mcp4822_paused_obj, + (mp_obj_t)&mcp4822_mcp4822_get_paused_obj); + +static const mp_rom_map_elem_t mcp4822_mcp4822_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mcp4822_mcp4822_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mcp4822_mcp4822_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&mcp4822_mcp4822_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&mcp4822_mcp4822_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&mcp4822_mcp4822_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mcp4822_mcp4822_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&mcp4822_mcp4822_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&mcp4822_mcp4822_paused_obj) }, +}; +static MP_DEFINE_CONST_DICT(mcp4822_mcp4822_locals_dict, mcp4822_mcp4822_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + mcp4822_mcp4822_type, + MP_QSTR_MCP4822, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, mcp4822_mcp4822_make_new, + locals_dict, &mcp4822_mcp4822_locals_dict + ); diff --git a/shared-bindings/mcp4822/MCP4822.h b/shared-bindings/mcp4822/MCP4822.h new file mode 100644 index 00000000000..b129aec3061 --- /dev/null +++ b/shared-bindings/mcp4822/MCP4822.h @@ -0,0 +1,25 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/mcp4822/MCP4822.h" +#include "common-hal/microcontroller/Pin.h" + +extern const mp_obj_type_t mcp4822_mcp4822_type; + +void common_hal_mcp4822_mcp4822_construct(mcp4822_mcp4822_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs, uint8_t gain); + +void common_hal_mcp4822_mcp4822_deinit(mcp4822_mcp4822_obj_t *self); +bool common_hal_mcp4822_mcp4822_deinited(mcp4822_mcp4822_obj_t *self); +void common_hal_mcp4822_mcp4822_play(mcp4822_mcp4822_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_mcp4822_mcp4822_stop(mcp4822_mcp4822_obj_t *self); +bool common_hal_mcp4822_mcp4822_get_playing(mcp4822_mcp4822_obj_t *self); +void common_hal_mcp4822_mcp4822_pause(mcp4822_mcp4822_obj_t *self); +void common_hal_mcp4822_mcp4822_resume(mcp4822_mcp4822_obj_t *self); +bool common_hal_mcp4822_mcp4822_get_paused(mcp4822_mcp4822_obj_t *self); diff --git a/shared-bindings/mcp4822/__init__.c b/shared-bindings/mcp4822/__init__.c new file mode 100644 index 00000000000..bac2136d9e7 --- /dev/null +++ b/shared-bindings/mcp4822/__init__.c @@ -0,0 +1,36 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/mcp4822/__init__.h" +#include "shared-bindings/mcp4822/MCP4822.h" + +//| """Audio output via MCP4822 dual-channel 12-bit SPI DAC. +//| +//| The `mcp4822` module provides the `MCP4822` class for non-blocking +//| audio playback through the Microchip MCP4822 SPI DAC using PIO and DMA. +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed. To do so, either call :py:meth:`!deinit` or use a +//| context manager.""" + +static const mp_rom_map_elem_t mcp4822_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mcp4822) }, + { MP_ROM_QSTR(MP_QSTR_MCP4822), MP_ROM_PTR(&mcp4822_mcp4822_type) }, +}; + +static MP_DEFINE_CONST_DICT(mcp4822_module_globals, mcp4822_module_globals_table); + +const mp_obj_module_t mcp4822_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mcp4822_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_mcp4822, mcp4822_module); diff --git a/shared-bindings/mcp4822/__init__.h b/shared-bindings/mcp4822/__init__.h new file mode 100644 index 00000000000..c4a52e5819d --- /dev/null +++ b/shared-bindings/mcp4822/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-bindings/mdns/RemoteService.c b/shared-bindings/mdns/RemoteService.c index b3ee3d7f7b7..b00313729fc 100644 --- a/shared-bindings/mdns/RemoteService.c +++ b/shared-bindings/mdns/RemoteService.c @@ -93,18 +93,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_ipv4_address_obj, _mdns_remotes MP_PROPERTY_GETTER(mdns_remoteservice_ipv4_address_obj, (mp_obj_t)&mdns_remoteservice_get_ipv4_address_obj); -//| def __del__(self) -> None: -//| """Deletes the RemoteService object.""" -//| ... -//| -//| -static mp_obj_t mdns_remoteservice_obj_deinit(mp_obj_t self_in) { - mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_mdns_remoteservice_deinit(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_deinit_obj, mdns_remoteservice_obj_deinit); - static const mp_rom_map_elem_t mdns_remoteservice_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&mdns_remoteservice_hostname_obj) }, { MP_ROM_QSTR(MP_QSTR_instance_name), MP_ROM_PTR(&mdns_remoteservice_instance_name_obj) }, @@ -112,8 +100,6 @@ static const mp_rom_map_elem_t mdns_remoteservice_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_protocol), MP_ROM_PTR(&mdns_remoteservice_protocol_obj) }, { MP_ROM_QSTR(MP_QSTR_port), MP_ROM_PTR(&mdns_remoteservice_port_obj) }, { MP_ROM_QSTR(MP_QSTR_ipv4_address), MP_ROM_PTR(&mdns_remoteservice_ipv4_address_obj) }, - - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mdns_remoteservice_deinit_obj) }, }; static MP_DEFINE_CONST_DICT(mdns_remoteservice_locals_dict, mdns_remoteservice_locals_dict_table); diff --git a/shared-bindings/mdns/RemoteService.h b/shared-bindings/mdns/RemoteService.h index a5ffe897e4e..c7efa64083d 100644 --- a/shared-bindings/mdns/RemoteService.h +++ b/shared-bindings/mdns/RemoteService.h @@ -19,7 +19,6 @@ const char *common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_o const char *common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self); mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self); mp_obj_t common_hal_mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self); -void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self); // For internal use. uint32_t mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self); diff --git a/shared-bindings/mdns/Server.c b/shared-bindings/mdns/Server.c index 86fb2eb6d7a..1c16348d425 100644 --- a/shared-bindings/mdns/Server.c +++ b/shared-bindings/mdns/Server.c @@ -150,7 +150,14 @@ static mp_obj_t _mdns_server_find(mp_uint_t n_args, const mp_obj_t *pos_args, mp } static MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_find_obj, 1, _mdns_server_find); -//| def advertise_service(self, *, service_type: str, protocol: str, port: int) -> None: +//| def advertise_service( +//| self, +//| *, +//| service_type: str, +//| protocol: str, +//| port: int, +//| txt_records: Optional[Sequence[str]] = None, +//| ) -> None: //| """Respond to queries for the given service with the given port. //| //| ``service_type`` and ``protocol`` can only occur on one port. Any call after the first @@ -158,8 +165,8 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_find_obj, 1, _mdns_server_find); //| //| If web workflow is active, the port it uses can't also be used to advertise a service. //| -//| **Limitations**: Publishing up to 32 TXT records is only supported on the RP2040 Pico W board at -//| this time. +//| **Limitations**: Publishing TXT records (up to 32) is supported only on RP2xxx. +//| There is currently no TXT record support on Espressif boards. //| //| :param str service_type: The service type such as "_http" //| :param str protocol: The service protocol such as "_tcp" diff --git a/shared-bindings/memorymap/AddressRange.c b/shared-bindings/memorymap/AddressRange.c index efc55ad37d7..5f7ee0deb95 100644 --- a/shared-bindings/memorymap/AddressRange.c +++ b/shared-bindings/memorymap/AddressRange.c @@ -92,7 +92,6 @@ static mp_obj_t memorymap_addressrange_make_new(const mp_obj_type_t *type, size_ } memorymap_addressrange_obj_t *self = mp_obj_malloc(memorymap_addressrange_obj_t, &memorymap_addressrange_type); - common_hal_memorymap_addressrange_construct(self, (uint8_t *)start, length); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/memorymonitor/AllocationAlarm.c b/shared-bindings/memorymonitor/AllocationAlarm.c index 5475e2d7db4..00cfbbd9fe1 100644 --- a/shared-bindings/memorymonitor/AllocationAlarm.c +++ b/shared-bindings/memorymonitor/AllocationAlarm.c @@ -48,7 +48,6 @@ static mp_obj_t memorymonitor_allocationalarm_make_new(const mp_obj_type_t *type memorymonitor_allocationalarm_obj_t *self = mp_obj_malloc(memorymonitor_allocationalarm_obj_t, &memorymonitor_allocationalarm_type); - common_hal_memorymonitor_allocationalarm_construct(self, minimum_block_count); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/memorymonitor/__init__.c b/shared-bindings/memorymonitor/__init__.c index 64d0140ff79..e364344b363 100644 --- a/shared-bindings/memorymonitor/__init__.c +++ b/shared-bindings/memorymonitor/__init__.c @@ -25,7 +25,7 @@ //| MP_DEFINE_MEMORYMONITOR_EXCEPTION(AllocationError, Exception) -NORETURN void mp_raise_memorymonitor_AllocationError(mp_rom_error_text_t fmt, ...) { +MP_NORETURN void mp_raise_memorymonitor_AllocationError(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_memorymonitor_AllocationError, fmt, argptr); diff --git a/shared-bindings/memorymonitor/__init__.h b/shared-bindings/memorymonitor/__init__.h index 28480bea7b5..5f141b924d0 100644 --- a/shared-bindings/memorymonitor/__init__.h +++ b/shared-bindings/memorymonitor/__init__.h @@ -23,4 +23,4 @@ void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_pr extern const mp_obj_type_t mp_type_memorymonitor_AllocationError; -NORETURN void mp_raise_memorymonitor_AllocationError(mp_rom_error_text_t msg, ...); +MP_NORETURN void mp_raise_memorymonitor_AllocationError(mp_rom_error_text_t msg, ...); diff --git a/shared-bindings/microcontroller/Pin.c b/shared-bindings/microcontroller/Pin.c index e74d54b0770..1fcde50e060 100644 --- a/shared-bindings/microcontroller/Pin.c +++ b/shared-bindings/microcontroller/Pin.c @@ -175,14 +175,14 @@ void validate_pins(qstr what, uint8_t *pin_nos, mp_int_t max_pins, mp_obj_t seq, } } -NORETURN void raise_ValueError_invalid_pin(void) { +MP_NORETURN void raise_ValueError_invalid_pin(void) { mp_arg_error_invalid(MP_QSTR_pin); } -NORETURN void raise_ValueError_invalid_pins(void) { +MP_NORETURN void raise_ValueError_invalid_pins(void) { mp_arg_error_invalid(MP_QSTR_pins); } -NORETURN void raise_ValueError_invalid_pin_name(qstr pin_name) { +MP_NORETURN void raise_ValueError_invalid_pin_name(qstr pin_name) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q pin"), pin_name); } diff --git a/shared-bindings/microcontroller/Pin.h b/shared-bindings/microcontroller/Pin.h index 1245b5f23e4..8ddca71bfbb 100644 --- a/shared-bindings/microcontroller/Pin.h +++ b/shared-bindings/microcontroller/Pin.h @@ -21,9 +21,9 @@ void validate_no_duplicate_pins(mp_obj_t seq, qstr arg_name); void validate_no_duplicate_pins_2(mp_obj_t seq1, mp_obj_t seq2, qstr arg_name1, qstr arg_name2); void validate_list_is_free_pins(qstr what, const mcu_pin_obj_t **pins_out, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out); void validate_pins(qstr what, uint8_t *pin_nos, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out); -NORETURN void raise_ValueError_invalid_pin(void); -NORETURN void raise_ValueError_invalid_pins(void); -NORETURN void raise_ValueError_invalid_pin_name(qstr pin_name); +MP_NORETURN void raise_ValueError_invalid_pin(void); +MP_NORETURN void raise_ValueError_invalid_pins(void); +MP_NORETURN void raise_ValueError_invalid_pin_name(qstr pin_name); void assert_pin_free(const mcu_pin_obj_t *pin); diff --git a/shared-bindings/microcontroller/ResetReason.c b/shared-bindings/microcontroller/ResetReason.c index e16e8a056fb..46eb23e36aa 100644 --- a/shared-bindings/microcontroller/ResetReason.c +++ b/shared-bindings/microcontroller/ResetReason.c @@ -9,14 +9,14 @@ #include "shared-bindings/microcontroller/ResetReason.h" -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, POWER_ON, RESET_REASON_POWER_ON); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, BROWNOUT, RESET_REASON_BROWNOUT); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, SOFTWARE, RESET_REASON_SOFTWARE); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, DEEP_SLEEP_ALARM, RESET_REASON_DEEP_SLEEP_ALARM); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESET_PIN, RESET_REASON_RESET_PIN); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, WATCHDOG, RESET_REASON_WATCHDOG); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, UNKNOWN, RESET_REASON_UNKNOWN); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESCUE_DEBUG, RESET_REASON_RESCUE_DEBUG); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, POWER_ON, MCU_RESET_REASON_POWER_ON); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, BROWNOUT, MCU_RESET_REASON_BROWNOUT); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, SOFTWARE, MCU_RESET_REASON_SOFTWARE); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, DEEP_SLEEP_ALARM, MCU_RESET_REASON_DEEP_SLEEP_ALARM); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESET_PIN, MCU_RESET_REASON_RESET_PIN); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, WATCHDOG, MCU_RESET_REASON_WATCHDOG); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, UNKNOWN, MCU_RESET_REASON_UNKNOWN); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESCUE_DEBUG, MCU_RESET_REASON_RESCUE_DEBUG); //| class ResetReason: //| """The reason the microcontroller was last reset""" diff --git a/shared-bindings/microcontroller/ResetReason.h b/shared-bindings/microcontroller/ResetReason.h index 61ff80639a6..772d7ff4ba4 100644 --- a/shared-bindings/microcontroller/ResetReason.h +++ b/shared-bindings/microcontroller/ResetReason.h @@ -10,14 +10,14 @@ #include "py/enum.h" typedef enum { - RESET_REASON_POWER_ON, - RESET_REASON_BROWNOUT, - RESET_REASON_SOFTWARE, - RESET_REASON_DEEP_SLEEP_ALARM, - RESET_REASON_RESET_PIN, - RESET_REASON_WATCHDOG, - RESET_REASON_UNKNOWN, - RESET_REASON_RESCUE_DEBUG, + MCU_RESET_REASON_POWER_ON, + MCU_RESET_REASON_BROWNOUT, + MCU_RESET_REASON_SOFTWARE, + MCU_RESET_REASON_DEEP_SLEEP_ALARM, + MCU_RESET_REASON_RESET_PIN, + MCU_RESET_REASON_WATCHDOG, + MCU_RESET_REASON_UNKNOWN, + MCU_RESET_REASON_RESCUE_DEBUG, } mcu_reset_reason_t; extern const mp_obj_type_t mcu_reset_reason_type; diff --git a/shared-bindings/microcontroller/__init__.h b/shared-bindings/microcontroller/__init__.h index 2a4a9732781..5c5902ff965 100644 --- a/shared-bindings/microcontroller/__init__.h +++ b/shared-bindings/microcontroller/__init__.h @@ -20,7 +20,7 @@ extern void common_hal_mcu_disable_interrupts(void); extern void common_hal_mcu_enable_interrupts(void); extern void common_hal_mcu_on_next_reset(mcu_runmode_t runmode); -NORETURN extern void common_hal_mcu_reset(void); +MP_NORETURN extern void common_hal_mcu_reset(void); extern const mp_obj_dict_t mcu_pin_globals; diff --git a/shared-bindings/mipidsi/Bus.c b/shared-bindings/mipidsi/Bus.c new file mode 100644 index 00000000000..bac3cd3c75e --- /dev/null +++ b/shared-bindings/mipidsi/Bus.c @@ -0,0 +1,84 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-bindings/mipidsi/Bus.h" +#include "shared-bindings/util.h" +#include "shared/runtime/context_manager_helpers.h" + +//| class Bus: +//| def __init__( +//| self, +//| *, +//| frequency: int = 500_000_000, +//| num_lanes: int = 2, +//| ) -> None: +//| """Create a MIPI DSI Bus object. +//| +//| This creates a DSI bus interface. The specific pins used are determined by the board. +//| DSI supports 1-4 data lanes. +//| +//| :param int frequency: the high speed clock frequency in Hz (default 500 MHz) +//| :param int num_lanes: the number of data lanes to use (default 2, range 1-4) +//| """ +//| +// +// +// All MCUs we support only have one DSI bus but it can be shared between multiple displays. One +// display may live longer than the VM, so we need to allocate the bus outside the VM. To simplify +// memory tracking, we use a global object for the bus. +// +static mipidsi_bus_obj_t _mipidsi_bus_obj; + +static mp_obj_t mipidsi_bus_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_frequency, ARG_num_lanes }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 500000000} }, + { MP_QSTR_num_lanes, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 2} }, + }; + 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); + + _mipidsi_bus_obj.base.type = &mipidsi_bus_type; + mipidsi_bus_obj_t *self = &_mipidsi_bus_obj; + + mp_uint_t frequency = (mp_uint_t)mp_arg_validate_int_min(args[ARG_frequency].u_int, 1, MP_QSTR_frequency); + uint8_t num_lanes = (uint8_t)mp_arg_validate_int_range(args[ARG_num_lanes].u_int, 1, 4, MP_QSTR_num_lanes); + + common_hal_mipidsi_bus_construct(self, frequency, num_lanes); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Free the resources (pins, timers, etc.) associated with this +//| `mipidsi.Bus` instance. After deinitialization, no further operations +//| may be performed.""" +//| ... +//| +static mp_obj_t mipidsi_bus_deinit(mp_obj_t self_in) { + mipidsi_bus_obj_t *self = (mipidsi_bus_obj_t *)self_in; + common_hal_mipidsi_bus_deinit(self); + return mp_const_none; +} + +static MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_bus_deinit_obj, mipidsi_bus_deinit); + +static const mp_rom_map_elem_t mipidsi_bus_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mipidsi_bus_deinit_obj) }, +}; +static MP_DEFINE_CONST_DICT(mipidsi_bus_locals_dict, mipidsi_bus_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + mipidsi_bus_type, + MP_QSTR_Bus, + MP_TYPE_FLAG_NONE, + make_new, mipidsi_bus_make_new, + locals_dict, &mipidsi_bus_locals_dict + ); diff --git a/shared-bindings/mipidsi/Bus.h b/shared-bindings/mipidsi/Bus.h new file mode 100644 index 00000000000..f2fd13f7fc1 --- /dev/null +++ b/shared-bindings/mipidsi/Bus.h @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/mipidsi/Bus.h" + +extern const mp_obj_type_t mipidsi_bus_type; + +void common_hal_mipidsi_bus_construct(mipidsi_bus_obj_t *self, mp_uint_t frequency, uint8_t num_lanes); +void common_hal_mipidsi_bus_deinit(mipidsi_bus_obj_t *self); +bool common_hal_mipidsi_bus_deinited(mipidsi_bus_obj_t *self); diff --git a/shared-bindings/mipidsi/Display.c b/shared-bindings/mipidsi/Display.c new file mode 100644 index 00000000000..149d31e52a9 --- /dev/null +++ b/shared-bindings/mipidsi/Display.c @@ -0,0 +1,300 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/objtype.h" + +#include "shared-bindings/mipidsi/Display.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/framebufferio/FramebufferDisplay.h" + +//| class Display: +//| def __init__( +//| self, +//| bus: Bus, +//| init_sequence: ReadableBuffer, +//| *, +//| width: int, +//| height: int, +//| hsync_pulse_width: int, +//| hsync_back_porch: int, +//| hsync_front_porch: int, +//| vsync_pulse_width: int, +//| vsync_back_porch: int, +//| vsync_front_porch: int, +//| pixel_clock_frequency: int, +//| virtual_channel: int = 0, +//| rotation: int = 0, +//| color_depth: int = 16, +//| backlight_pin: Optional[microcontroller.Pin] = None, +//| brightness: float = 1.0, +//| native_frames_per_second: int = 60, +//| backlight_on_high: bool = True, +//| ) -> None: +//| """Create a MIPI DSI Display object connected to the given bus. +//| +//| This allocates a framebuffer and configures the DSI display to use the +//| specified virtual channel for communication. +//| +//| The framebuffer pixel format varies depending on color_depth: +//| +//| * 16 - Each two bytes is a pixel in RGB565 format. +//| * 24 - Each three bytes is a pixel in RGB888 format. +//| +//| A Display is often used in conjunction with a +//| `framebufferio.FramebufferDisplay`. +//| +//| :param Bus bus: the DSI bus to use +//| :param ~circuitpython_typing.ReadableBuffer init_sequence: Byte-packed initialization sequence for the display +//| :param int width: the width of the framebuffer in pixels +//| :param int height: the height of the framebuffer in pixels +//| :param int hsync_pulse_width: horizontal sync pulse width in pixel clocks +//| :param int hsync_back_porch: horizontal back porch in pixel clocks +//| :param int hsync_front_porch: horizontal front porch in pixel clocks +//| :param int vsync_pulse_width: vertical sync pulse width in lines +//| :param int vsync_back_porch: vertical back porch in lines +//| :param int vsync_front_porch: vertical front porch in lines +//| :param int pixel_clock_frequency: pixel clock frequency in Hz +//| :param int virtual_channel: the DSI virtual channel (0-3) +//| :param int rotation: the rotation of the display in degrees clockwise (0, 90, 180, 270) +//| :param int color_depth: the color depth of the framebuffer in bits (16 or 24) +//| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight +//| :param float brightness: Initial display brightness (0.0 to 1.0) +//| :param int native_frames_per_second: Number of display refreshes per second +//| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on +//| """ +//| + +static mp_obj_t mipidsi_display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_hsync_pulse_width, ARG_hsync_back_porch, + ARG_hsync_front_porch, ARG_vsync_pulse_width, ARG_vsync_back_porch, ARG_vsync_front_porch, + ARG_pixel_clock_frequency, ARG_virtual_channel, ARG_rotation, + ARG_color_depth, ARG_backlight_pin, ARG_brightness, ARG_native_frames_per_second, + ARG_backlight_on_high }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_hsync_pulse_width, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_hsync_back_porch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_hsync_front_porch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_vsync_pulse_width, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_vsync_back_porch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_vsync_front_porch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pixel_clock_frequency, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_virtual_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_rotation, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_color_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, + { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, + { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} }, + { MP_QSTR_backlight_on_high, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + }; + 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); + + mipidsi_display_obj_t *self = &allocate_display_bus_or_raise()->mipidsi; + self->base.type = &mipidsi_display_type; + + mipidsi_bus_obj_t *bus = mp_arg_validate_type(args[ARG_bus].u_obj, &mipidsi_bus_type, MP_QSTR_bus); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_init_sequence].u_obj, &bufinfo, MP_BUFFER_READ); + + const mcu_pin_obj_t *backlight_pin = + validate_obj_is_free_pin_or_none(args[ARG_backlight_pin].u_obj, MP_QSTR_backlight_pin); + + mp_float_t brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + + mp_int_t rotation = args[ARG_rotation].u_int; + if (rotation % 90 != 0) { + mp_raise_ValueError(MP_ERROR_TEXT("Display rotation must be in 90 degree increments")); + } + + mp_uint_t virtual_channel = (mp_uint_t)mp_arg_validate_int_range(args[ARG_virtual_channel].u_int, 0, 3, MP_QSTR_virtual_channel); + mp_uint_t width = (mp_uint_t)mp_arg_validate_int_min(args[ARG_width].u_int, 0, MP_QSTR_width); + mp_uint_t height = (mp_uint_t)mp_arg_validate_int_min(args[ARG_height].u_int, 0, MP_QSTR_height); + mp_uint_t color_depth = args[ARG_color_depth].u_int; + + if (color_depth != 16 && color_depth != 24) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_color_depth); + } + + common_hal_mipidsi_display_construct(self, bus, bufinfo.buf, bufinfo.len, virtual_channel, width, height, + rotation, color_depth, MP_OBJ_TO_PTR(backlight_pin), brightness, + args[ARG_native_frames_per_second].u_int, + args[ARG_backlight_on_high].u_bool, + args[ARG_hsync_pulse_width].u_int, + args[ARG_hsync_back_porch].u_int, + args[ARG_hsync_front_porch].u_int, + args[ARG_vsync_pulse_width].u_int, + args[ARG_vsync_back_porch].u_int, + args[ARG_vsync_front_porch].u_int, + args[ARG_pixel_clock_frequency].u_int); + + return MP_OBJ_FROM_PTR(self); +} + +// Helper to ensure we have the native super class instead of a subclass. +static mipidsi_display_obj_t *native_display(mp_obj_t display_obj) { + mp_obj_t native_display = mp_obj_cast_to_native_base(display_obj, &mipidsi_display_type); + mp_obj_assert_native_inited(native_display); + return MP_OBJ_TO_PTR(native_display); +} + +//| def deinit(self) -> None: +//| """Free the resources (pins, timers, etc.) associated with this +//| `mipidsi.Display` instance. After deinitialization, no further operations +//| may be performed.""" +//| ... +//| +static mp_obj_t mipidsi_display_deinit(mp_obj_t self_in) { + mipidsi_display_obj_t *self = native_display(self_in); + common_hal_mipidsi_display_deinit(self); + return mp_const_none; +} + +static MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_display_deinit_obj, mipidsi_display_deinit); + +static void check_for_deinit(mipidsi_display_obj_t *self) { + if (common_hal_mipidsi_display_deinited(self)) { + raise_deinited_error(); + } +} + +//| width: int +//| """The width of the framebuffer, in pixels.""" +static mp_obj_t mipidsi_display_get_width(mp_obj_t self_in) { + mipidsi_display_obj_t *self = native_display(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_mipidsi_display_get_width(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_display_get_width_obj, mipidsi_display_get_width); +MP_PROPERTY_GETTER(mipidsi_display_width_obj, + (mp_obj_t)&mipidsi_display_get_width_obj); + +//| height: int +//| """The height of the framebuffer, in pixels.""" +//| +//| +static mp_obj_t mipidsi_display_get_height(mp_obj_t self_in) { + mipidsi_display_obj_t *self = native_display(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_mipidsi_display_get_height(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_display_get_height_obj, mipidsi_display_get_height); + +MP_PROPERTY_GETTER(mipidsi_display_height_obj, + (mp_obj_t)&mipidsi_display_get_height_obj); + +//| color_depth: int +//| """The color depth of the framebuffer.""" +static mp_obj_t mipidsi_display_get_color_depth(mp_obj_t self_in) { + mipidsi_display_obj_t *self = native_display(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_mipidsi_display_get_color_depth(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_display_get_color_depth_obj, mipidsi_display_get_color_depth); +MP_PROPERTY_GETTER(mipidsi_display_color_depth_obj, + (mp_obj_t)&mipidsi_display_get_color_depth_obj); + + +static const mp_rom_map_elem_t mipidsi_display_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mipidsi_display_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&mipidsi_display_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&mipidsi_display_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_color_depth), MP_ROM_PTR(&mipidsi_display_color_depth_obj) }, +}; +static MP_DEFINE_CONST_DICT(mipidsi_display_locals_dict, mipidsi_display_locals_dict_table); + +static void mipidsi_display_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) { + common_hal_mipidsi_display_get_buffer(self_in, bufinfo, 0); +} + +static float mipidsi_display_get_brightness_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_brightness(self_in); +} + +static bool mipidsi_display_set_brightness_proto(mp_obj_t self_in, mp_float_t value) { + common_hal_mipidsi_display_set_brightness(self_in, value); + return true; +} + +// These versions exist so that the prototype matches the protocol, +// avoiding a type cast that can hide errors +static void mipidsi_display_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) { + (void)dirty_row_bitmap; + common_hal_mipidsi_display_refresh(self_in); +} + +static void mipidsi_display_deinit_proto(mp_obj_t self_in) { + common_hal_mipidsi_display_deinit(self_in); +} + +static int mipidsi_display_get_width_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_width(self_in); +} + +static int mipidsi_display_get_height_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_height(self_in); +} + +static int mipidsi_display_get_color_depth_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_color_depth(self_in); +} + +static bool mipidsi_display_get_grayscale_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_grayscale(self_in); +} + +static int mipidsi_display_get_bytes_per_cell_proto(mp_obj_t self_in) { + return 1; +} + +static int mipidsi_display_get_native_frames_per_second_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_native_frames_per_second(self_in); +} + +static bool mipidsi_display_get_pixels_in_byte_share_row_proto(mp_obj_t self_in) { + return true; +} + +static int mipidsi_display_get_row_stride_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_row_stride(self_in); +} + +static const framebuffer_p_t mipidsi_display_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer) + .get_bufinfo = mipidsi_display_get_bufinfo, + .set_brightness = mipidsi_display_set_brightness_proto, + .get_brightness = mipidsi_display_get_brightness_proto, + .get_width = mipidsi_display_get_width_proto, + .get_height = mipidsi_display_get_height_proto, + .get_color_depth = mipidsi_display_get_color_depth_proto, + .get_grayscale = mipidsi_display_get_grayscale_proto, + .get_row_stride = mipidsi_display_get_row_stride_proto, + .get_bytes_per_cell = mipidsi_display_get_bytes_per_cell_proto, + .get_native_frames_per_second = mipidsi_display_get_native_frames_per_second_proto, + .get_pixels_in_byte_share_row = mipidsi_display_get_pixels_in_byte_share_row_proto, + .swapbuffers = mipidsi_display_swapbuffers, + .deinit = mipidsi_display_deinit_proto, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + mipidsi_display_type, + MP_QSTR_Display, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + locals_dict, &mipidsi_display_locals_dict, + make_new, mipidsi_display_make_new, + buffer, common_hal_mipidsi_display_get_buffer, + protocol, &mipidsi_display_proto + ); diff --git a/shared-bindings/mipidsi/Display.h b/shared-bindings/mipidsi/Display.h new file mode 100644 index 00000000000..09cf130bf4a --- /dev/null +++ b/shared-bindings/mipidsi/Display.h @@ -0,0 +1,46 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/mipidsi/Display.h" +#include "shared-bindings/mipidsi/Bus.h" +#include "common-hal/microcontroller/Pin.h" + +extern const mp_obj_type_t mipidsi_display_type; + +void common_hal_mipidsi_display_construct(mipidsi_display_obj_t *self, + mipidsi_bus_obj_t *bus, + const uint8_t *init_sequence, + size_t init_sequence_len, + mp_uint_t virtual_channel, + mp_uint_t width, + mp_uint_t height, + mp_int_t rotation, + mp_uint_t color_depth, + const mcu_pin_obj_t *backlight_pin, + mp_float_t brightness, + mp_uint_t native_frames_per_second, + bool backlight_on_high, + mp_uint_t hsync_pulse_width, + mp_uint_t hsync_back_porch, + mp_uint_t hsync_front_porch, + mp_uint_t vsync_pulse_width, + mp_uint_t vsync_back_porch, + mp_uint_t vsync_front_porch, + mp_uint_t pixel_clock_frequency); +void common_hal_mipidsi_display_deinit(mipidsi_display_obj_t *self); +bool common_hal_mipidsi_display_deinited(mipidsi_display_obj_t *self); +void common_hal_mipidsi_display_refresh(mipidsi_display_obj_t *self); +mp_float_t common_hal_mipidsi_display_get_brightness(mipidsi_display_obj_t *self); +bool common_hal_mipidsi_display_set_brightness(mipidsi_display_obj_t *self, mp_float_t brightness); +int common_hal_mipidsi_display_get_width(mipidsi_display_obj_t *self); +int common_hal_mipidsi_display_get_height(mipidsi_display_obj_t *self); +int common_hal_mipidsi_display_get_row_stride(mipidsi_display_obj_t *self); +int common_hal_mipidsi_display_get_color_depth(mipidsi_display_obj_t *self); +int common_hal_mipidsi_display_get_native_frames_per_second(mipidsi_display_obj_t *self); +bool common_hal_mipidsi_display_get_grayscale(mipidsi_display_obj_t *self); +mp_int_t common_hal_mipidsi_display_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); diff --git a/shared-bindings/mipidsi/__init__.c b/shared-bindings/mipidsi/__init__.c new file mode 100644 index 00000000000..0b6b8565929 --- /dev/null +++ b/shared-bindings/mipidsi/__init__.c @@ -0,0 +1,30 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/mipidsi/Bus.h" +#include "shared-bindings/mipidsi/Display.h" + +//| """Low-level routines for interacting with MIPI DSI""" + +static const mp_rom_map_elem_t mipidsi_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mipidsi) }, + { MP_ROM_QSTR(MP_QSTR_Bus), MP_ROM_PTR(&mipidsi_bus_type) }, + { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&mipidsi_display_type) }, +}; + +static MP_DEFINE_CONST_DICT(mipidsi_module_globals, mipidsi_module_globals_table); + +const mp_obj_module_t mipidsi_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mipidsi_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_mipidsi, mipidsi_module); diff --git a/shared-bindings/mipidsi/__init__.h b/shared-bindings/mipidsi/__init__.h new file mode 100644 index 00000000000..972a7c082fd --- /dev/null +++ b/shared-bindings/mipidsi/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-bindings/msgpack/ExtType.c b/shared-bindings/msgpack/ExtType.c index f66abda8fa2..c69416f9773 100644 --- a/shared-bindings/msgpack/ExtType.c +++ b/shared-bindings/msgpack/ExtType.c @@ -18,7 +18,6 @@ //| :param bytes data: representation.""" //| static mp_obj_t mod_msgpack_exttype_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - mod_msgpack_extype_obj_t *self = mp_obj_malloc(mod_msgpack_extype_obj_t, &mod_msgpack_exttype_type); enum { ARG_code, ARG_data }; static const mp_arg_t allowed_args[] = { { MP_QSTR_code, MP_ARG_INT | MP_ARG_REQUIRED }, @@ -28,11 +27,12 @@ static mp_obj_t mod_msgpack_exttype_make_new(const mp_obj_type_t *type, size_t n mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); int code = mp_arg_validate_int_range(args[ARG_code].u_int, 0, 127, MP_QSTR_code); + mp_obj_t data = args[ARG_data].u_obj; + mod_msgpack_extype_obj_t *self = mp_obj_malloc(mod_msgpack_extype_obj_t, &mod_msgpack_exttype_type); self->code = code; - - mp_obj_t data = args[ARG_data].u_obj; self->data = data; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/nvm/ByteArray.c b/shared-bindings/nvm/ByteArray.c index be01c1f7064..b2783006267 100644 --- a/shared-bindings/nvm/ByteArray.c +++ b/shared-bindings/nvm/ByteArray.c @@ -35,7 +35,7 @@ //| static mp_obj_t nvm_bytearray_unary_op(mp_unary_op_t op, mp_obj_t self_in) { nvm_bytearray_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint16_t len = common_hal_nvm_bytearray_get_length(self); + uint32_t len = common_hal_nvm_bytearray_get_length(self); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len != 0); diff --git a/shared-bindings/onewireio/OneWire.c b/shared-bindings/onewireio/OneWire.c index a3750ae5e07..2f69424cc23 100644 --- a/shared-bindings/onewireio/OneWire.c +++ b/shared-bindings/onewireio/OneWire.c @@ -43,8 +43,8 @@ static mp_obj_t onewireio_onewire_make_new(const mp_obj_type_t *type, size_t n_a const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); onewireio_onewire_obj_t *self = mp_obj_malloc(onewireio_onewire_obj_t, &onewireio_onewire_type); - common_hal_onewireio_onewire_construct(self, pin); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/os/__init__.c b/shared-bindings/os/__init__.c index 5e28c02452d..bbf5a5025c1 100644 --- a/shared-bindings/os/__init__.c +++ b/shared-bindings/os/__init__.c @@ -67,7 +67,7 @@ static MP_DEFINE_ATTRTUPLE( ); static mp_obj_t os_uname(void) { - return (mp_obj_t)&os_uname_info_obj; + return MP_OBJ_FROM_PTR(&os_uname_info_obj); } static MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); @@ -94,11 +94,20 @@ static mp_obj_t os_getcwd(void) { MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd); //| def getenv(key: str, default: Optional[str] = None) -> Optional[str]: -//| """Get the environment variable value for the given key or return ``default``. +//| """Get the environment variable value for the given ``key`` from the +//| ``/settings.toml`` file. +//| If ``key`` is not present or the value is ill-formed, return the ``default`` value. +//| The value is returned as a string even if it can be parsed as an integer or boolean. +//| No errors are raised if the value is not a valid TOML value; instead the original +//| string is returned, or ``default`` if no value can be retrieved at all. //| -//| This may load values from disk so cache the result instead of calling this often. +//| If you want to retrieve the value as a ``str``, ``bool``, or ``int``, use `supervisor.get_setting()`. //| -//| On boards that do not support ``settings.toml`` reading in the core, this function will raise NotImplementedError. +//| The ``settings.toml`` file is re-scanned on every call, +//| so cache the result instead of calling `getenv()` frequently. +//| +//| On boards that do not support ``settings.toml`` reading in the core, +//| this function will raise NotImplementedError. //| //| .. raw:: html //| @@ -118,7 +127,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd); //| //| static mp_obj_t os_getenv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML enum { ARG_key, ARG_default }; static const mp_arg_t allowed_args[] = { { MP_QSTR_key, MP_ARG_REQUIRED | MP_ARG_OBJ }, diff --git a/shared-bindings/paralleldisplaybus/ParallelBus.c b/shared-bindings/paralleldisplaybus/ParallelBus.c index dfe363bdcb7..7f8749501fb 100644 --- a/shared-bindings/paralleldisplaybus/ParallelBus.c +++ b/shared-bindings/paralleldisplaybus/ParallelBus.c @@ -85,14 +85,16 @@ static mp_obj_t paralleldisplaybus_parallelbus_make_new(const mp_obj_type_t *typ mp_raise_ValueError(MP_ERROR_TEXT("Specify exactly one of data0 or data_pins")); } + uint32_t frequency = (uint32_t)mp_arg_validate_int_min(args[ARG_frequency].u_int, 1, MP_QSTR_frequency); + if (specified_data0) { const mcu_pin_obj_t *data0 = validate_obj_is_free_pin(args[ARG_data0].u_obj, MP_QSTR_data0); - common_hal_paralleldisplaybus_parallelbus_construct(self, data0, command, chip_select, write, read, reset, args[ARG_frequency].u_int); + common_hal_paralleldisplaybus_parallelbus_construct(self, data0, command, chip_select, write, read, reset, frequency); } else { uint8_t num_pins; const mcu_pin_obj_t *data_pins[16]; validate_list_is_free_pins(MP_QSTR_data_pins, data_pins, (mp_int_t)MP_ARRAY_SIZE(data_pins), args[ARG_data_pins].u_obj, &num_pins); - common_hal_paralleldisplaybus_parallelbus_construct_nonsequential(self, num_pins, data_pins, command, chip_select, write, read, reset, args[ARG_frequency].u_int); + common_hal_paralleldisplaybus_parallelbus_construct_nonsequential(self, num_pins, data_pins, command, chip_select, write, read, reset, frequency); } return self; } diff --git a/shared-bindings/paralleldisplaybus/__init__.c b/shared-bindings/paralleldisplaybus/__init__.c index 24d968c9e31..19a381570ba 100644 --- a/shared-bindings/paralleldisplaybus/__init__.c +++ b/shared-bindings/paralleldisplaybus/__init__.c @@ -29,6 +29,3 @@ const mp_obj_module_t paralleldisplaybus_module = { }; MP_REGISTER_MODULE(MP_QSTR_paralleldisplaybus, paralleldisplaybus_module); - -// Remove in CircuitPython 10 -MP_REGISTER_MODULE(MP_QSTR_paralleldisplay, paralleldisplaybus_module); diff --git a/shared-bindings/picogame/Bitmap.c b/shared-bindings/picogame/Bitmap.c new file mode 100644 index 00000000000..8c970a5a0c0 --- /dev/null +++ b/shared-bindings/picogame/Bitmap.c @@ -0,0 +1,242 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.Bitmap: pixel data (PAL8 or RGB565) shared by sprites, tilemaps and blits. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// --------------------------------------------------------------------------- +// Bitmap +// --------------------------------------------------------------------------- + +//| class Bitmap: +//| """An image atlas of one or more frames that all share one size. RGB565 +//| pixel data and palette entries must be in the display's transfer byte +//| order (use :py:func:`rgb565` to build colors); PAL8 pixel data are +//| palette indices. +//| +//| The bitmap references the caller-provided data without copying or modifying +//| it. The backing buffer may live in RAM or in read-only memory.""" +//| +//| def __init__( +//| self, +//| data: ReadableBuffer, +//| width: int, +//| height: int, +//| *, +//| format: int = RGB565, +//| palette: Optional[ReadableBuffer] = None, +//| frames: int = 1, +//| stride: int = 0, +//| transparent: Optional[int] = None, +//| ) -> None: +//| """:param ~circuitpython_typing.ReadableBuffer data: RGB565 pixel data in +//| the display's transfer byte order, or palette indices for ``PAL8`` +//| :param int width: width of one frame in pixels +//| :param int height: height of one frame in pixels +//| :param int format: :py:data:`RGB565` (2 bytes per pixel) or :py:data:`PAL8` +//| (1 byte per pixel, indexing ``palette``) +//| :param ~circuitpython_typing.ReadableBuffer palette: for ``PAL8``, a buffer +//| of transfer-order RGB565 colors, two bytes per entry. Every byte in +//| ``data`` must be a valid palette index, that is, less than +//| ``len(palette) // 2``. +//| :param int frames: number of equal-size frames, laid out left to right in +//| one horizontal atlas +//| :param int stride: distance between two rows in pixels. ``0``, the +//| default, means ``width * frames``; set it explicitly to reference a +//| sub-region of a wider image. +//| :param int transparent: color (``RGB565``) or index (``PAL8``) that is +//| skipped when drawing. Defaults to `None`, fully opaque.""" +//| ... +//| +static mp_obj_t picogame_bitmap_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_data, ARG_width, ARG_height, ARG_format, ARG_palette, ARG_frames, ARG_stride, ARG_transparent }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PICOGAME_FMT_RGB565} }, + { MP_QSTR_palette, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_frames, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_stride, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + 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); + + // bound BEFORE any arithmetic: an unbounded width could overflow width*frames (int32) and wrap + // small, slipping past the size guards below into an undersized buffer (OOB read in the blitter). + mp_int_t width = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 65535, MP_QSTR_width); + mp_int_t height = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 65535, MP_QSTR_height); + mp_int_t frames = mp_arg_validate_int_range(args[ARG_frames].u_int, 1, 255, MP_QSTR_frames); + mp_int_t format = args[ARG_format].u_int; + if (format != PICOGAME_FMT_RGB565 && format != PICOGAME_FMT_PAL8) { + mp_raise_ValueError(MP_ERROR_TEXT("Invalid format")); + } + mp_int_t stride = args[ARG_stride].u_int; + if (stride <= 0) { + stride = width * frames; + } + // stride must hold the whole horizontal atlas, and the dims must fit the uint16_t fields, + // or blits index past a row / the stored stride truncates. + mp_arg_validate_int_max(width * frames, 65535, MP_QSTR_width); + mp_arg_validate_int_max(stride, 65535, MP_QSTR_stride); + mp_arg_validate_int_min(stride, width * frames, MP_QSTR_stride); + + mp_buffer_info_t data_info; + mp_get_buffer_raise(args[ARG_data].u_obj, &data_info, MP_BUFFER_READ); + + const uint16_t *palette = NULL; + mp_obj_t palette_obj = MP_OBJ_NULL; + size_t pal_len = 0; + if (format == PICOGAME_FMT_PAL8) { + if (args[ARG_palette].u_obj == mp_const_none) { + mp_arg_error_invalid(MP_QSTR_palette); // PAL8 needs one + } + mp_buffer_info_t pal_info; + mp_get_buffer_raise(args[ARG_palette].u_obj, &pal_info, MP_BUFFER_READ); + palette = pal_info.buf; + palette_obj = args[ARG_palette].u_obj; + pal_len = pal_info.len; + } + + size_t bpp = (format == PICOGAME_FMT_PAL8) ? 1 : 2; + // 64-bit: stride*height*bpp can exceed 32 bits (stride,height <= 65535) and wrap small in a 32-bit + // size_t, letting a tiny buffer pass this check -> OOB read in the blitter. Compute + compare wide. + uint64_t need = (uint64_t)stride * (uint64_t)height * (uint64_t)bpp; + if ((uint64_t)data_info.len < need) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + if (format == PICOGAME_FMT_PAL8 && pal_len < 2) { + // Need >=1 entry so pal[0] is valid. Contract (see blitter): PAL8 indices MUST be < palette + // length. The caller may write indices into the (mutable) `data` buffer directly, so we cannot + // validate once here. An out-of-range index is undefined behaviour (reads past the palette: + // usually a garbage colour, but it may fault on some platforms). Per-pixel clamping was dropped + // for speed - see the "restore full bounds-safety" note in the PAL8 blit loop if it's needed. + mp_arg_validate_length_min(pal_len, 1, MP_QSTR_palette); + } + + picogame_bitmap_obj_t *self = mp_obj_malloc(picogame_bitmap_obj_t, type); + self->data_obj = args[ARG_data].u_obj; + self->palette_obj = palette_obj; + self->data = data_info.buf; + self->palette = palette; + self->width = width; + self->height = height; + self->stride = stride; + self->frames = frames; + self->format = format; + // palette length in entries (informational; blitter assumes indices < this - see blit contract). + self->pal_entries = (uint16_t)((pal_len / 2) > 65535 ? 65535 : (pal_len / 2)); + if (args[ARG_transparent].u_obj != mp_const_none) { + self->transparent = mp_obj_get_int(args[ARG_transparent].u_obj); + self->has_transparent = true; + } else { + self->transparent = 0; + self->has_transparent = false; + } + return MP_OBJ_FROM_PTR(self); +} + +//| +//| width: int +//| """Width of one frame in pixels. (read-only)""" +//| height: int +//| """Height of one frame in pixels. (read-only)""" +//| frames: int +//| """Number of frames in the atlas. (read-only)""" +static mp_obj_t bitmap_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->width); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_width_obj, bitmap_get_width); +MP_PROPERTY_GETTER(bitmap_width_obj, (mp_obj_t)&bitmap_get_width_obj); + +static mp_obj_t bitmap_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->height); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_height_obj, bitmap_get_height); +MP_PROPERTY_GETTER(bitmap_height_obj, (mp_obj_t)&bitmap_get_height_obj); + +static mp_obj_t bitmap_get_frames(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->frames); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_frames_obj, bitmap_get_frames); +MP_PROPERTY_GETTER(bitmap_frames_obj, (mp_obj_t)&bitmap_get_frames_obj); + +//| format: int +//| """:py:data:`RGB565` or :py:data:`PAL8`. (read-only)""" +static mp_obj_t bitmap_get_format(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->format); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_format_obj, bitmap_get_format); +MP_PROPERTY_GETTER(bitmap_format_obj, (mp_obj_t)&bitmap_get_format_obj); + +//| stride: int +//| """Row stride in pixels. (read-only)""" +static mp_obj_t bitmap_get_stride(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->stride); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_stride_obj, bitmap_get_stride); +MP_PROPERTY_GETTER(bitmap_stride_obj, (mp_obj_t)&bitmap_get_stride_obj); + +//| palette: Optional[ReadableBuffer] +//| """The ``PAL8`` palette buffer this Bitmap was built with, or `None` for +//| ``RGB565``. (read-only)""" +static mp_obj_t bitmap_get_palette(mp_obj_t self_in) { + picogame_bitmap_obj_t *self = MP_OBJ_TO_PTR(self_in); + return (self->palette_obj == MP_OBJ_NULL) ? mp_const_none : self->palette_obj; +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_palette_obj, bitmap_get_palette); +MP_PROPERTY_GETTER(bitmap_palette_obj, (mp_obj_t)&bitmap_get_palette_obj); + +//| transparent: Optional[int] +//| """The transparent color or index, or `None` if the Bitmap is fully +//| opaque. (read-only)""" +//| +//| +static mp_obj_t bitmap_get_transparent(mp_obj_t self_in) { + picogame_bitmap_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->has_transparent ? MP_OBJ_NEW_SMALL_INT(self->transparent) : mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_transparent_obj, bitmap_get_transparent); +MP_PROPERTY_GETTER(bitmap_transparent_obj, (mp_obj_t)&bitmap_get_transparent_obj); + +static const mp_rom_map_elem_t picogame_bitmap_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&bitmap_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&bitmap_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_frames), MP_ROM_PTR(&bitmap_frames_obj) }, + { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&bitmap_format_obj) }, + { MP_ROM_QSTR(MP_QSTR_stride), MP_ROM_PTR(&bitmap_stride_obj) }, + { MP_ROM_QSTR(MP_QSTR_palette), MP_ROM_PTR(&bitmap_palette_obj) }, + { MP_ROM_QSTR(MP_QSTR_transparent), MP_ROM_PTR(&bitmap_transparent_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_bitmap_locals_dict, picogame_bitmap_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_bitmap_type, + MP_QSTR_Bitmap, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_bitmap_make_new, + locals_dict, &picogame_bitmap_locals_dict + ); diff --git a/shared-bindings/picogame/Bitmap.h b/shared-bindings/picogame/Bitmap.h new file mode 100644 index 00000000000..44e2a2fb1aa --- /dev/null +++ b/shared-bindings/picogame/Bitmap.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Bitmap.h" + +extern const mp_obj_type_t picogame_bitmap_type; diff --git a/shared-bindings/picogame/Canvas.c b/shared-bindings/picogame/Canvas.c new file mode 100644 index 00000000000..675826936ff --- /dev/null +++ b/shared-bindings/picogame/Canvas.c @@ -0,0 +1,623 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/fontio/BuiltinFont.h" +#include "shared-module/picogame/Canvas.h" + +//| class Canvas: +//| """A RAM drawing surface composited as a `Scene` layer. Draw primitives +//| into it; only redrawn areas repaint. Colors come from +//| :py:func:`rgb565`.""" +//| +//| def __init__( +//| self, +//| width: int, +//| height: int, +//| *, +//| transparent: Optional[int] = None, +//| buffer: Optional[WriteableBuffer] = None, +//| ) -> None: +//| """:param int width: surface width in pixels +//| :param int height: surface height in pixels +//| :param int transparent: color that is skipped when the canvas is +//| composited; `None` makes every pixel opaque +//| :param ~circuitpython_typing.WriteableBuffer buffer: optional caller-owned +//| pixel buffer of at least ``width * height * 2`` bytes (for example a +//| ``bytearray`` or a writable ``memoryview``). The canvas draws into it +//| instead of allocating its own.""" +//| ... +//| +static mp_obj_t picogame_canvas_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_width, ARG_height, ARG_transparent, ARG_buffer }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_buffer, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + 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); + + mp_int_t w = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 1024, MP_QSTR_width); + mp_int_t h = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 1024, MP_QSTR_height); + + picogame_canvas_obj_t *self = mp_obj_malloc(picogame_canvas_obj_t, type); + self->w = w; + self->h = h; + self->x = 0; + self->y = 0; + if (args[ARG_buffer].u_obj != mp_const_none) { + // external buffer (e.g. an arena slice) - draw into it, don't allocate/own it + mp_buffer_info_t bi; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bi, MP_BUFFER_RW); + if (bi.len < (size_t)w * h * 2) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + if ((uintptr_t)bi.buf & 1) { // odd byte address -> uint16 pixel stores fault on Cortex-M0+ + mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 2); + } + self->data = bi.buf; + self->data_obj = args[ARG_buffer].u_obj; // keep the backing object alive (GC-traced) + } else { + // Pure pixel data, no Python pointers -> exempt from the conservative GC scan + // (shorter gc.collect() pauses; a 150x60 canvas is 18 KB the mark phase can skip). + self->data = m_malloc_without_collect((size_t)w * h * sizeof(uint16_t)); + self->data_obj = MP_OBJ_NULL; + } + if (args[ARG_transparent].u_obj != mp_const_none) { + self->transparent = mp_obj_get_int(args[ARG_transparent].u_obj); + self->has_transparent = true; + } else { + self->transparent = 0; + self->has_transparent = false; + } + uint16_t fill = self->has_transparent ? self->transparent : 0; + for (size_t i = 0; i < (size_t)w * h; i++) { + self->data[i] = fill; + } + picogame_canvas_dirty_reset(self); + return MP_OBJ_FROM_PTR(self); +} + +static picogame_canvas_obj_t *cv_self(mp_obj_t o) { + return MP_OBJ_TO_PTR(o); +} + +// Shared int-arg unpacker for the plain drawing trampolines below: every one of them is +// "self + N ints -> void", and the inlined per-wrapper mp_obj_get_int runs cost ~70-120 B +// each at -Os. One loop here + a tiny per-wrapper stub keeps the flash cost per method at +// ~2 calls. n comes from the VAR_BETWEEN exact arity, so v[] is always fully written. +static picogame_canvas_obj_t *cv_args(const mp_obj_t *a, size_t n, int *v) { + for (size_t i = 1; i < n; i++) { + v[i - 1] = mp_obj_get_int(a[i]); + } + return cv_self(a[0]); +} + +//| def clear(self, color: int) -> None: +//| """Fill the whole surface with ``color``.""" +//| ... +//| +static mp_obj_t canvas_clear(mp_obj_t self_in, mp_obj_t color) { + picogame_canvas_clear(cv_self(self_in), mp_obj_get_int(color)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(canvas_clear_obj, canvas_clear); + +//| +//| def pixel(self, x: int, y: int, color: int) -> None: +//| """Set a single pixel.""" +//| ... +//| +static mp_obj_t canvas_pixel(size_t n, const mp_obj_t *a) { + int v[3]; + picogame_canvas_pixel(cv_args(a, n, v), v[0], v[1], v[2]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_pixel_obj, 4, 4, canvas_pixel); + +//| +//| def fill_rect(self, x: int, y: int, w: int, h: int, color: int) -> None: +//| """Fill an axis-aligned rectangle.""" +//| ... +//| +static mp_obj_t canvas_fill_rect(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_fill_rect(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_rect_obj, 6, 6, canvas_fill_rect); + +//| +//| def blit( +//| self, +//| bitmap: Bitmap, +//| x: int, +//| y: int, +//| frame: int = 0, +//| flip_x: bool = False, +//| flip_y: bool = False, +//| ) -> None: +//| """Copy one frame of ``bitmap``, selected by ``frame``, into the canvas +//| at ``(x, y)``, honoring the bitmap's transparent color.""" +//| ... +//| +static mp_obj_t canvas_blit(size_t n, const mp_obj_t *a) { + picogame_bitmap_obj_t *bm = MP_OBJ_TO_PTR( + mp_arg_validate_type(a[1], &picogame_bitmap_type, MP_QSTR_bitmap)); + // Same domain as Sprite.frame (uint8): a negative frame would survive the blitter's + // wrap (C % keeps the sign) and read before the sheet data. + int frame = (n > 4) ? (int)mp_arg_validate_int_range(mp_obj_get_int(a[4]), 0, 255, MP_QSTR_frame) : 0; + bool fx = (n > 5) ? mp_obj_is_true(a[5]) : false; + bool fy = (n > 6) ? mp_obj_is_true(a[6]) : false; + picogame_canvas_blit(cv_self(a[0]), bm, mp_obj_get_int(a[2]), mp_obj_get_int(a[3]), frame, fx, fy); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_blit_obj, 4, 7, canvas_blit); + +//| def mode7( +//| self, +//| texture: Bitmap, +//| horizon: int, +//| y_off: int, +//| z: int, +//| rx0: int, +//| ry0: int, +//| rsx: int, +//| rsy: int, +//| cam_x: int, +//| cam_y: int, +//| ) -> None: +//| """Fill rows below ``horizon`` with a perspective projection of ``texture``. +//| The ``picogame_mode7`` helper computes the camera terms from an angle, +//| position and field of view. +//| +//| :param Bitmap texture: texture whose width and height are powers of two +//| :param int horizon: first canvas row to fill +//| :param int y_off: vertical offset of the projection, in rows +//| :param int z: camera height (signed 16.16 fixed-point) +//| :param int rx0: ray x at the left column (signed 16.16 fixed-point) +//| :param int ry0: ray y at the left column (signed 16.16 fixed-point) +//| :param int rsx: per-column ray step x (signed 16.16 fixed-point) +//| :param int rsy: per-column ray step y (signed 16.16 fixed-point) +//| :param int cam_x: camera x position (signed 16.16 fixed-point) +//| :param int cam_y: camera y position (signed 16.16 fixed-point)""" +//| ... +//| +static mp_obj_t canvas_mode7(size_t n, const mp_obj_t *a) { + picogame_bitmap_obj_t *tex = MP_OBJ_TO_PTR( + mp_arg_validate_type(a[1], &picogame_bitmap_type, MP_QSTR_texture)); + picogame_canvas_mode7(cv_self(a[0]), tex, + mp_obj_get_int(a[2]), mp_obj_get_int(a[3]), mp_obj_get_int(a[4]), + mp_obj_get_int(a[5]), mp_obj_get_int(a[6]), mp_obj_get_int(a[7]), + mp_obj_get_int(a[8]), mp_obj_get_int(a[9]), mp_obj_get_int(a[10])); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_mode7_obj, 11, 11, canvas_mode7); + +//| def fill_triangles( +//| self, +//| verts: ReadableBuffer, +//| colors: ReadableBuffer, +//| n: int, +//| x_off: int = 0, +//| y_off: int = 0, +//| ) -> None: +//| """Fill a batch of triangles in one call, which is faster than repeated +//| :py:meth:`fill_triangle` calls for many triangles. +//| +//| :param ~circuitpython_typing.ReadableBuffer verts: ``6 * n`` ``int16`` +//| values: x0, y0, x1, y1, x2, y2 per triangle +//| :param ~circuitpython_typing.ReadableBuffer colors: ``n`` ``uint16`` colors, +//| one per triangle +//| :param int n: number of triangles +//| :param int x_off: added to every x before clipping +//| :param int y_off: added to every y before clipping +//| +//| The offsets translate the whole batch, so one screen-space batch can be +//| replayed into each `StripDraw` view by passing the negated view origin +//| (``x_off=-vx, y_off=-vy``); triangles outside the view are skipped.""" +//| ... +//| +static mp_obj_t canvas_fill_triangles(size_t na, const mp_obj_t *a) { + picogame_canvas_obj_t *cv = cv_self(a[0]); + mp_buffer_info_t vi, ci; + mp_get_buffer_raise(a[1], &vi, MP_BUFFER_READ); + mp_get_buffer_raise(a[2], &ci, MP_BUFFER_READ); + int n = mp_obj_get_int(a[3]); + int xo = na > 4 ? mp_obj_get_int(a[4]) : 0; + int yo = na > 5 ? mp_obj_get_int(a[5]) : 0; + const int16_t *v = vi.buf; + const uint16_t *col = ci.buf; + int cap_v = (int)(vi.len / 12); // 6 int16 = 12 bytes per triangle + int cap_c = (int)(ci.len >> 1); + if (n > cap_v) { + n = cap_v; + } + if (n > cap_c) { + n = cap_c; + } + picogame_fill_triangle_batch(cv, v, col, n, xo, yo); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_triangles_obj, 4, 6, canvas_fill_triangles); + +//| def vspans( +//| self, +//| x0s: ReadableBuffer, +//| x1s: ReadableBuffer, +//| tops: ReadableBuffer, +//| bots: ReadableBuffer, +//| colors: ReadableBuffer, +//| n: int, +//| x_off: int = 0, +//| y_off: int = 0, +//| ) -> None: +//| """Fill a batch of vertical color spans in one call. Span ``i`` covers +//| columns ``x0s[i]`` through ``x1s[i]`` (exclusive) and rows ``tops[i]`` +//| through ``bots[i]`` (exclusive) in color ``colors[i]``. +//| +//| :param ~circuitpython_typing.ReadableBuffer x0s: ``n`` ``uint16`` left edges +//| :param ~circuitpython_typing.ReadableBuffer x1s: ``n`` ``uint16`` exclusive +//| right edges +//| :param ~circuitpython_typing.ReadableBuffer tops: ``n`` ``uint16`` top rows +//| :param ~circuitpython_typing.ReadableBuffer bots: ``n`` ``uint16`` exclusive +//| bottom rows +//| :param ~circuitpython_typing.ReadableBuffer colors: ``n`` ``uint16`` colors +//| :param int n: number of spans +//| :param int x_off: added to every x before clipping +//| :param int y_off: added to every y before clipping +//| +//| The offsets translate the whole batch, so one screen-space batch (for +//| example `raycast` wall runs) can be replayed into each `StripDraw` view by +//| passing the negated view origin; spans outside the view are skipped.""" +//| ... +//| +static mp_obj_t canvas_vspans(size_t na, const mp_obj_t *a) { + picogame_canvas_obj_t *cv = cv_self(a[0]); + // five equal-shape uint16 arrays in a row: fetch + shortest-length fold in one loop + mp_buffer_info_t bi5[5]; + size_t cap = (size_t)-1; + for (int i = 0; i < 5; i++) { + mp_get_buffer_raise(a[1 + i], &bi5[i], MP_BUFFER_READ); + if (bi5[i].len < cap) { + cap = bi5[i].len; + } + } + int n = mp_obj_get_int(a[6]); + int xo = na > 7 ? mp_obj_get_int(a[7]) : 0; + int yo = na > 8 ? mp_obj_get_int(a[8]) : 0; + if (n > (int)(cap >> 1)) { + n = (int)(cap >> 1); // never read past the shortest array + } + const uint16_t *x0s = bi5[0].buf; + const uint16_t *x1s = bi5[1].buf; + const uint16_t *tops = bi5[2].buf; + const uint16_t *bots = bi5[3].buf; + const uint16_t *cols = bi5[4].buf; + int cw = cv->w, ch = cv->h; + for (int i = 0; i < n; i++) { + int t = tops[i] + yo, b = bots[i] + yo; + if (b <= 0 || t >= ch || b <= t) { + continue; // span outside this band + } + int x0 = x0s[i] + xo, x1 = x1s[i] + xo; + if (x1 <= 0 || x0 >= cw || x1 <= x0) { + continue; + } + picogame_canvas_fill_rect(cv, x0, t, x1 - x0, b - t, cols[i]); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_vspans_obj, 7, 9, canvas_vspans); + +//| def road( +//| self, +//| ri0: int, +//| tab: ReadableBuffer, +//| rl: ReadableBuffer, +//| rr: ReadableBuffer, +//| d05_q8: int, +//| d07_q8: int, +//| colors: ReadableBuffer, +//| ) -> None: +//| """Draw one racing-road strip from precomputed tables. A low-level +//| interface used by the ``picogame_road`` helper, which builds the tables. +//| +//| :param int ri0: road-table row of this surface's row 0; negative values +//| are sky rows +//| :param ~circuitpython_typing.ReadableBuffer tab: ``int16`` rows of +//| ``edge_w``, ``dash_hw``, ``wb05_q8``, ``wb07_q8``, ``flags`` +//| :param ~circuitpython_typing.ReadableBuffer rl: ``int16`` per-row left +//| edges, as computed by :py:func:`road_edges` +//| :param ~circuitpython_typing.ReadableBuffer rr: ``int16`` per-row right +//| edges +//| :param int d05_q8: scroll phase (Q8 fixed-point) +//| :param int d07_q8: scroll phase (Q8 fixed-point) +//| :param ~circuitpython_typing.ReadableBuffer colors: six ``uint16`` colors, +//| in order: sky, road a, road b, rumble a, rumble b, dash""" +//| ... +//| +static mp_obj_t canvas_road(size_t n, const mp_obj_t *a) { + mp_buffer_info_t tabi, rli, rri, coli; + mp_get_buffer_raise(a[2], &tabi, MP_BUFFER_READ); + mp_get_buffer_raise(a[3], &rli, MP_BUFFER_READ); + mp_get_buffer_raise(a[4], &rri, MP_BUFFER_READ); + mp_get_buffer_raise(a[7], &coli, MP_BUFFER_READ); + int ntab = (int)(tabi.len / (5 * 2)); + int nedge = (int)(rli.len < rri.len ? rli.len : rri.len) / 2; + if (nedge < ntab) { + ntab = nedge; // never read past the shorter per-frame arrays + } + if (ntab <= 0 || coli.len < 6 * 2) { + return mp_const_none; + } + picogame_canvas_road(cv_self(a[0]), mp_obj_get_int(a[1]), + (const int16_t *)tabi.buf, ntab, (const int16_t *)rli.buf, (const int16_t *)rri.buf, + mp_obj_get_int(a[5]), mp_obj_get_int(a[6]), (const uint16_t *)coli.buf); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_road_obj, 8, 8, canvas_road); + +//| def rect(self, x: int, y: int, w: int, h: int, color: int) -> None: +//| """Draw a one-pixel rectangle outline.""" +//| ... +//| +static mp_obj_t canvas_rect(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_rect(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_rect_obj, 6, 6, canvas_rect); + +//| +//| def line(self, x0: int, y0: int, x1: int, y1: int, color: int) -> None: +//| """Draw a one-pixel line between two points.""" +//| ... +//| +static mp_obj_t canvas_line(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_line(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_line_obj, 6, 6, canvas_line); + +//| +//| def fill_circle(self, cx: int, cy: int, r: int, color: int) -> None: +//| """Fill a circle of radius ``r`` centered on ``(cx, cy)``.""" +//| ... +//| +static mp_obj_t canvas_fill_circle(size_t n, const mp_obj_t *a) { + int v[4]; + picogame_canvas_fill_circle(cv_args(a, n, v), v[0], v[1], v[2], v[3]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_circle_obj, 5, 5, canvas_fill_circle); + +//| +//| def circle(self, cx: int, cy: int, r: int, color: int) -> None: +//| """Draw a one-pixel circle outline.""" +//| ... +//| +static mp_obj_t canvas_circle(size_t n, const mp_obj_t *a) { + int v[4]; + picogame_canvas_circle(cv_args(a, n, v), v[0], v[1], v[2], v[3]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_circle_obj, 5, 5, canvas_circle); + +//| +//| def ring(self, cx: int, cy: int, r: int, thickness: int, color: int) -> None: +//| """Draw a circle outline ``thickness`` pixels wide, grown inwards from radius ``r``.""" +//| ... +//| +static mp_obj_t canvas_ring(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_ring(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_ring_obj, 6, 6, canvas_ring); + +//| +//| def triangle( +//| self, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int +//| ) -> None: +//| """Draw a one-pixel triangle outline through the three points.""" +//| ... +//| +static mp_obj_t canvas_triangle(size_t n, const mp_obj_t *a) { + int v[7]; + picogame_canvas_triangle(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4], v[5], v[6]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_triangle_obj, 8, 8, canvas_triangle); + +//| +//| def fill_triangle( +//| self, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int +//| ) -> None: +//| """Fill a triangle. See :py:meth:`fill_triangles` to submit a whole batch +//| in one call.""" +//| ... +//| +static mp_obj_t canvas_fill_triangle(size_t n, const mp_obj_t *a) { + int v[7]; + picogame_canvas_fill_triangle(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4], v[5], v[6]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_triangle_obj, 8, 8, canvas_fill_triangle); + +//| +//| def ellipse(self, cx: int, cy: int, rx: int, ry: int, color: int) -> None: +//| """Draw a one-pixel ellipse outline with radii ``rx``/``ry``.""" +//| ... +//| +static mp_obj_t canvas_ellipse(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_ellipse(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_ellipse_obj, 6, 6, canvas_ellipse); + +//| +//| def fill_ellipse(self, cx: int, cy: int, rx: int, ry: int, color: int) -> None: +//| """Fill an ellipse with radii ``rx``/``ry``.""" +//| ... +//| +static mp_obj_t canvas_fill_ellipse(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_fill_ellipse(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_ellipse_obj, 6, 6, canvas_fill_ellipse); + +//| +//| def fill_round_rect(self, x: int, y: int, w: int, h: int, r: int, color: int) -> None: +//| """Fill a rectangle with corners rounded to radius ``r``.""" +//| ... +//| +static mp_obj_t canvas_fill_round_rect(size_t n, const mp_obj_t *a) { + int v[6]; + picogame_canvas_fill_round_rect(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4], v[5]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_round_rect_obj, 7, 7, canvas_fill_round_rect); + +//| +//| def frame3d(self, x: int, y: int, w: int, h: int, light: int, dark: int) -> None: +//| """Draw a one-pixel bevelled frame: top and left edges in ``light``, bottom and +//| right in ``dark``, giving a raised look (swap the two for a sunken one).""" +//| ... +//| +static mp_obj_t canvas_frame3d(size_t n, const mp_obj_t *a) { + int v[6]; + picogame_canvas_frame3d(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4], v[5]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_frame3d_obj, 7, 7, canvas_frame3d); + +//| +//| def text( +//| self, x: int, y: int, s: str, fg: int, font: fontio.BuiltinFont, bg: int | None = None +//| ) -> None: +//| """Draw ``s`` into the surface, rasterizing each glyph from ``font`` as it +//| is drawn; no memory is retained between calls. Only ASCII characters are +//| supported. If ``bg`` is given the glyph background is filled with it, +//| otherwise it is transparent. Inside a `StripDraw` callback the view is a +//| Canvas, so ``view.text(...)`` draws text directly into the frame.""" +//| ... +//| +static mp_obj_t canvas_text(size_t n, const mp_obj_t *a) { + const char *s = mp_obj_str_get_str(a[3]); + mp_int_t fg = mp_obj_get_int(a[4]); + const void *font = MP_OBJ_TO_PTR(mp_arg_validate_type(a[5], &fontio_builtinfont_type, MP_QSTR_font)); + bool has_bg = (n >= 7) && (a[6] != mp_const_none); + uint16_t bg = has_bg ? (uint16_t)mp_obj_get_int(a[6]) : 0; + picogame_canvas_text(cv_self(a[0]), mp_obj_get_int(a[1]), mp_obj_get_int(a[2]), + s, (uint16_t)fg, bg, has_bg, font); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_text_obj, 6, 7, canvas_text); + +//| def move(self, x: int, y: int) -> None: +//| """Move the surface's top-left corner to (x, y) and mark both the old and new area dirty.""" +//| ... +//| +static mp_obj_t canvas_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + picogame_canvas_obj_t *self = cv_self(self_in); + int nx = mp_obj_get_int(x_in), ny = mp_obj_get_int(y_in); + if (nx == self->x && ny == self->y) { + return mp_const_none; // unchanged -> avoid an avoidable repaint + } + // dirty old + new extents so the move repaints both + picogame_canvas_dirty_union(self, self->x, self->y, self->x + self->w, self->y + self->h); + self->x = nx; + self->y = ny; + picogame_canvas_dirty_union(self, self->x, self->y, self->x + self->w, self->y + self->h); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(canvas_move_obj, canvas_move); + +//| +//| x: int +//| """Horizontal position of the canvas top-left corner. (read-only) +//| +//| Set with :py:meth:`move`.""" +//| y: int +//| """Vertical position of the canvas top-left corner. (read-only) +//| +//| Set with :py:meth:`move`.""" +//| width: int +//| """Surface width in pixels. (read-only)""" +//| height: int +//| """Surface height in pixels. (read-only)""" +//| +//| +static mp_obj_t canvas_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(cv_self(self_in)->x); +} +static MP_DEFINE_CONST_FUN_OBJ_1(canvas_get_x_obj, canvas_get_x); +MP_PROPERTY_GETTER(canvas_x_obj, (mp_obj_t)&canvas_get_x_obj); + +static mp_obj_t canvas_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(cv_self(self_in)->y); +} +static MP_DEFINE_CONST_FUN_OBJ_1(canvas_get_y_obj, canvas_get_y); +MP_PROPERTY_GETTER(canvas_y_obj, (mp_obj_t)&canvas_get_y_obj); + +static mp_obj_t canvas_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(cv_self(self_in)->w); +} +static MP_DEFINE_CONST_FUN_OBJ_1(canvas_get_width_obj, canvas_get_width); +MP_PROPERTY_GETTER(canvas_width_obj, (mp_obj_t)&canvas_get_width_obj); + +static mp_obj_t canvas_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(cv_self(self_in)->h); +} +static MP_DEFINE_CONST_FUN_OBJ_1(canvas_get_height_obj, canvas_get_height); +MP_PROPERTY_GETTER(canvas_height_obj, (mp_obj_t)&canvas_get_height_obj); + +static const mp_rom_map_elem_t picogame_canvas_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&canvas_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&canvas_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&canvas_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&canvas_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&canvas_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&canvas_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&canvas_fill_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&canvas_blit_obj) }, + { MP_ROM_QSTR(MP_QSTR_mode7), MP_ROM_PTR(&canvas_mode7_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_triangles), MP_ROM_PTR(&canvas_fill_triangles_obj) }, + { MP_ROM_QSTR(MP_QSTR_vspans), MP_ROM_PTR(&canvas_vspans_obj) }, + { MP_ROM_QSTR(MP_QSTR_road), MP_ROM_PTR(&canvas_road_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&canvas_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&canvas_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_circle), MP_ROM_PTR(&canvas_fill_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&canvas_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_ring), MP_ROM_PTR(&canvas_ring_obj) }, + { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&canvas_triangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_triangle), MP_ROM_PTR(&canvas_fill_triangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_ellipse), MP_ROM_PTR(&canvas_ellipse_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_ellipse), MP_ROM_PTR(&canvas_fill_ellipse_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_round_rect), MP_ROM_PTR(&canvas_fill_round_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_frame3d), MP_ROM_PTR(&canvas_frame3d_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&canvas_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&canvas_move_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_canvas_locals_dict, picogame_canvas_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_canvas_type, + MP_QSTR_Canvas, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_canvas_make_new, + locals_dict, &picogame_canvas_locals_dict + ); diff --git a/shared-bindings/picogame/Canvas.h b/shared-bindings/picogame/Canvas.h new file mode 100644 index 00000000000..fb37aa9f898 --- /dev/null +++ b/shared-bindings/picogame/Canvas.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Canvas.h" + +extern const mp_obj_type_t picogame_canvas_type; diff --git a/shared-bindings/picogame/Display.c b/shared-bindings/picogame/Display.c new file mode 100644 index 00000000000..e2e42b158c1 --- /dev/null +++ b/shared-bindings/picogame/Display.c @@ -0,0 +1,128 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" // brings in the board config (CIRCUITPY_PICOGAME_FAST_DISPLAY) + +// The fast DMA Display backend is port-specific (needs a common-hal). Ports without it +// (e.g. ESP32) build picogame with this whole type compiled out and use Scene's portable +// bus.send renderer instead - so picogame stays buildable on any CircuitPython port. +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" +#include "shared-bindings/picogame/Sprite.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/picogame/__init__.h" +#include "common-hal/picogame/Display.h" + +//| class Display: +//| """An accelerated display backend that wraps an existing +//| :py:class:`~busdisplay.BusDisplay` and sends pixels with asynchronous, +//| double-buffered DMA. It reuses the wrapped display's bus, window commands +//| and dimensions. +//| +//| Constructing it raises :py:class:`NotImplementedError` when +//| :py:data:`FAST_DISPLAY_SUPPORTED` is `False`.""" +//| +//| def __init__(self, display: busdisplay.BusDisplay, *, rgb444: bool = False) -> None: +//| """:param ~busdisplay.BusDisplay display: the display to wrap +//| :param bool rgb444: drive the panel in 12-bit RGB444 instead of 16-bit +//| RGB565, reducing bus traffic at the cost of color depth (4,096 colors +//| instead of 65,536). The panel controller must support 12-bit color; +//| ST7789 and ST7735 do, ILI9341 does not. See :py:data:`RGB444_SUPPORTED`.""" +//| ... +//| +static mp_obj_t picogame_display_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_display, ARG_rgb444 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_display, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_rgb444, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + mp_obj_t native = mp_obj_cast_to_native_base(args[ARG_display].u_obj, &busdisplay_busdisplay_type); + // MP_OBJ_NULL for a non-BusDisplay: validate the ORIGINAL object (NULL's type is unreadable). + if (native == MP_OBJ_NULL || !mp_obj_is_type(native, &busdisplay_busdisplay_type)) { + mp_arg_validate_type(args[ARG_display].u_obj, &busdisplay_busdisplay_type, MP_QSTR_display); + } + picogame_display_obj_t *self = mp_obj_malloc(picogame_display_obj_t, type); + common_hal_picogame_display_construct(self, MP_OBJ_TO_PTR(native), args[ARG_rgb444].u_bool); + return MP_OBJ_FROM_PTR(self); +} + +//| def render( +//| self, +//| sprites: List[Sprite], +//| buffer_a: WriteableBuffer, +//| buffer_b: WriteableBuffer, +//| x0: int, +//| y0: int, +//| x1: int, +//| y1: int, +//| *, +//| background: int = 0, +//| ) -> None: +//| """Render ``sprites`` into the screen region from ``(x0, y0)`` up to, but +//| not including, ``(x1, y1)``, and send it with asynchronous DMA. ``buffer_a`` and ``buffer_b`` are two +//| equal strip buffers of at least ``(x1 - x0) * 2`` bytes each, used for +//| double buffering. +//| +//| This method accepts sprites only. For mixed layer kinds use a `Scene` or +//| the module-level :py:func:`render`.""" +//| ... +//| +//| +static mp_obj_t picogame_display_render(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sprites, ARG_buffer_a, ARG_buffer_b, ARG_x0, ARG_y0, ARG_x1, ARG_y1, ARG_background }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sprites, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer_a, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer_b, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x0, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y0, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_background, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + }; + picogame_display_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + size_t n = 0; + mp_obj_t *items; + mp_obj_get_array(args[ARG_sprites].u_obj, &n, &items); + for (size_t i = 0; i < n; i++) { + mp_arg_validate_type(items[i], &picogame_sprite_type, MP_QSTR_sprite); + } + + mp_buffer_info_t ba, bb; + mp_get_buffer_raise(args[ARG_buffer_a].u_obj, &ba, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[ARG_buffer_b].u_obj, &bb, MP_BUFFER_WRITE); + size_t buf_pixels = (ba.len < bb.len ? ba.len : bb.len) / 2; + + // kinds == NULL: every item is a sprite (the layered path handles this). + common_hal_picogame_display_render(self, items, NULL, n, + (uint16_t *)ba.buf, (uint16_t *)bb.buf, buf_pixels, + args[ARG_x0].u_int, args[ARG_y0].u_int, args[ARG_x1].u_int, args[ARG_y1].u_int, + args[ARG_background].u_int, 0, 0); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_display_render_obj, 8, picogame_display_render); + +static const mp_rom_map_elem_t picogame_display_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&picogame_display_render_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_display_locals_dict, picogame_display_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_display_type, + MP_QSTR_Display, + MP_TYPE_FLAG_NONE, + make_new, picogame_display_make_new, + locals_dict, &picogame_display_locals_dict + ); + +#endif // CIRCUITPY_PICOGAME_FAST_DISPLAY diff --git a/shared-bindings/picogame/Display.h b/shared-bindings/picogame/Display.h new file mode 100644 index 00000000000..6034124d88d --- /dev/null +++ b/shared-bindings/picogame/Display.h @@ -0,0 +1,13 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "common-hal/picogame/Display.h" +#endif + +extern const mp_obj_type_t picogame_display_type; diff --git a/shared-bindings/picogame/Framebuffer.c b/shared-bindings/picogame/Framebuffer.c new file mode 100644 index 00000000000..05b1612f190 --- /dev/null +++ b/shared-bindings/picogame/Framebuffer.c @@ -0,0 +1,170 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.Framebuffer: a RAM render target used in place of a BusDisplay. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// --------------------------------------------------------------------------- +// Framebuffer (a RAM render target used in place of a BusDisplay; scanout-buffer +// platforms - WASM playground, desktop sim, FruitJam DVI/HSTX) +// --------------------------------------------------------------------------- +//| class Framebuffer: +//| """A RAM framebuffer render target that a `Scene` or :py:func:`render` can +//| draw into instead of a :py:class:`~busdisplay.BusDisplay`, for example the +//| scanout buffer of a :py:class:`picodvi.Framebuffer`. +//| +//| Constructing it raises :py:class:`NotImplementedError` when +//| :py:data:`FRAMEBUFFER_SUPPORTED` is `False`.""" +//| +//| def __init__( +//| self, +//| buffer: WriteableBuffer, +//| width: int, +//| height: int, +//| *, +//| native_rgb565: bool = False, +//| rgb332: bool = False, +//| ) -> None: +//| """:param ~circuitpython_typing.WriteableBuffer buffer: caller-owned target +//| buffer of at least ``width * height * 2`` bytes, or ``width * height`` +//| bytes with ``rgb332=True`` +//| :param int width: target width in pixels +//| :param int height: target height in pixels +//| :param bool native_rgb565: fill the buffer with native-endian RGB565, the +//| format 16-bit scanout targets expect. By default the buffer holds +//| transfer-order RGB565. +//| :param bool rgb332: fill the buffer with 8-bit RGB332, the format of 8-bit +//| scanout targets +//| +//| ``native_rgb565`` and ``rgb332`` cannot both be true. Bitmaps, palettes and +//| :py:func:`rgb565` values stay transfer-order RGB565 regardless of the +//| output format.""" +//| ... +//| +//| width: int +//| """Target width in pixels. (read-only)""" +//| height: int +//| """Target height in pixels. (read-only)""" +//| +//| +// Static SRAM compose strip (see the scratch comment in make_new). 640*16*2 = 20 KB .bss, +// only on CIRCUITPY_PICOGAME_FRAMEBUFFER builds (fb boards have the SRAM to spare). +#define PICOGAME_FB_SCRATCH_MAX_W 640 +static uint16_t picogame_fb_scratch_sram[PICOGAME_FB_SCRATCH_MAX_W * PICOGAME_FB_SCRATCH_H]; + +static mp_obj_t picogame_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_buffer, ARG_width, ARG_height, ARG_native_rgb565, ARG_rgb332 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_native_rgb565, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_rgb332, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + mp_int_t width = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 4096, MP_QSTR_width); + mp_int_t height = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 4096, MP_QSTR_height); + if (args[ARG_native_rgb565].u_bool && args[ARG_rgb332].u_bool) { + mp_arg_error_invalid(MP_QSTR_format); // native_rgb565 and rgb332 are exclusive + } + bool rgb332 = args[ARG_rgb332].u_bool; + + mp_buffer_info_t bi; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bi, MP_BUFFER_WRITE); + uint64_t need = (uint64_t)width * (uint64_t)height * (rgb332 ? 1u : 2u); + if ((uint64_t)bi.len < need) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + + picogame_framebuffer_obj_t *self = mp_obj_malloc(picogame_framebuffer_obj_t, type); + self->buffer = args[ARG_buffer].u_obj; + self->fb = (uint16_t *)bi.buf; + self->width = width; + self->height = height; + self->fmt = rgb332 ? PICOGAME_FB_RGB332 + : (args[ARG_native_rgb565].u_bool ? PICOGAME_FB_NATIVE565 : PICOGAME_FB_WIRE565); + // A LIVE scanout buffer (picodvi/HDMI) is read continuously, so picogame_render_framebuffer + // composes each band into this PRIVATE strip and only memcpys the FINISHED band into the fb. + // That serves BOTH targets: (a) native -> also byte-swap the strip so the fb never holds wire + // (no pink); (b) wire -> no swap, but the off-screen compose still stops the beam from sampling + // a half-composited region (background filled, sprite not yet drawn) = no sprite/HUD flicker. + // Always allocated for the FB target; the WASM/sim path (read out after present, not live) just + // pays a small strip + one memcpy. See PICOGAME_FB_SCRATCH_H. + // + // The scratch must be FAST memory: on a PSRAM-heap board (Fruit Jam) a heap bytearray + // lands in external PSRAM and every compose write pays QSPI latency (measured 8.7 vs + // 64+ MB/s SRAM; a full-res StripDraw frame ballooned refresh to ~30-38 ms). One static + // SRAM strip serves every Framebuffer (compose is synchronous) up to 640 px wide; wider + // targets fall back to the heap. + self->scratch_buf = mp_const_none; + self->scratch = NULL; + self->scratch_rows = 0; + { + int rows = PICOGAME_FB_SCRATCH_H; + if (rows > height) { + rows = height; + } + if (width <= PICOGAME_FB_SCRATCH_MAX_W) { + self->scratch = picogame_fb_scratch_sram; + } else { + mp_obj_t sb = mp_obj_new_bytearray_of_zeros((size_t)width * (size_t)rows * 2u); + mp_buffer_info_t sbi; + mp_get_buffer_raise(sb, &sbi, MP_BUFFER_WRITE); + self->scratch_buf = sb; + self->scratch = (uint16_t *)sbi.buf; + } + self->scratch_rows = rows; + } + return MP_OBJ_FROM_PTR(self); +} + +static mp_obj_t picogame_framebuffer_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_framebuffer_obj_t *)MP_OBJ_TO_PTR(self_in))->width); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_framebuffer_get_width_obj, picogame_framebuffer_get_width); +MP_PROPERTY_GETTER(picogame_framebuffer_width_obj, (mp_obj_t)&picogame_framebuffer_get_width_obj); + +static mp_obj_t picogame_framebuffer_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_framebuffer_obj_t *)MP_OBJ_TO_PTR(self_in))->height); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_framebuffer_get_height_obj, picogame_framebuffer_get_height); +MP_PROPERTY_GETTER(picogame_framebuffer_height_obj, (mp_obj_t)&picogame_framebuffer_get_height_obj); + +static const mp_rom_map_elem_t picogame_framebuffer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&picogame_framebuffer_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&picogame_framebuffer_height_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_framebuffer_locals_dict, picogame_framebuffer_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_framebuffer_type, + MP_QSTR_Framebuffer, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_framebuffer_make_new, + locals_dict, &picogame_framebuffer_locals_dict + ); +#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER diff --git a/shared-bindings/picogame/Framebuffer.h b/shared-bindings/picogame/Framebuffer.h new file mode 100644 index 00000000000..99112b8fa03 --- /dev/null +++ b/shared-bindings/picogame/Framebuffer.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/__init__.h" // picogame_framebuffer_obj_t + +extern const mp_obj_type_t picogame_framebuffer_type; diff --git a/shared-bindings/picogame/Particles.c b/shared-bindings/picogame/Particles.c new file mode 100644 index 00000000000..bc7f286b46a --- /dev/null +++ b/shared-bindings/picogame/Particles.c @@ -0,0 +1,137 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-module/picogame/Particles.h" + +static void reset_dirty(picogame_particles_obj_t *self) { + // INT32 sentinels (not int16): bbox fields are int32 + positions 24.8, so a big-world emitter past + // +-32767 px must still accumulate. (Matches picogame_dirty_reset; update()/clear() use it too.) + self->cx1 = self->px1 = 0x7fffffff; + self->cy1 = self->py1 = 0x7fffffff; + self->cx2 = self->px2 = -0x7fffffff - 1; + self->cy2 = self->py2 = -0x7fffffff - 1; +} + +//| class Particles: +//| """A pooled particle layer (small moving dots), drawn as one Scene layer. +//| Add it to a Scene, ``emit()`` bursts, and call ``tick()`` each frame.""" +//| +//| def __init__( +//| self, capacity: int, *, size: int = 1, gravity: float = 0.0, fade: bool = False +//| ) -> None: +//| """``capacity`` is how many particles may be alive at once; the pool is +//| allocated once here and never grows. If :py:meth:`emit` would exceed it, +//| the excess particles are dropped. +//| +//| ``size`` is the square side of one particle in pixels. ``gravity`` is added to +//| each particle's vertical speed every :py:meth:`tick`. ``fade=True`` dims +//| particles towards the end of their life instead of letting them vanish at full +//| brightness.""" +//| ... +//| +static mp_obj_t picogame_particles_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_capacity, ARG_size, ARG_gravity, ARG_fade }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_capacity, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_gravity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_fade, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + mp_int_t cap = mp_arg_validate_int_range(args[ARG_capacity].u_int, 1, 4096, MP_QSTR_capacity); + mp_int_t size = mp_arg_validate_int_range(args[ARG_size].u_int, 1, 8, MP_QSTR_size); + mp_float_t gravity = (args[ARG_gravity].u_obj == mp_const_none) + ? 0.0f : mp_obj_get_float(args[ARG_gravity].u_obj); + if (gravity > 127.99f) { // clamp to the int16 8.8 range: gravity*256 must fit + gravity = 127.99f; // [-32768, 32767]; |g|>=128 would flip the sign + } else if (gravity < -128.0f) { + gravity = -128.0f; + } + + picogame_particles_obj_t *self = mp_obj_malloc(picogame_particles_obj_t, type); + self->cap = cap; + self->count = 0; + self->size = size; + self->gravity = (int16_t)(gravity * 256); + self->fade = args[ARG_fade].u_bool; + // Pure numeric arrays, no Python pointers -> exempt from the conservative GC scan + // (shorter gc.collect() pauses; fixed at construction, never m_renew'd). + self->px = m_malloc_without_collect(cap * sizeof(int32_t)); + self->py = m_malloc_without_collect(cap * sizeof(int32_t)); + self->vx = m_malloc_without_collect(cap * sizeof(int16_t)); + self->vy = m_malloc_without_collect(cap * sizeof(int16_t)); + self->life = m_malloc_without_collect(cap * sizeof(uint16_t)); + self->life0 = m_malloc_without_collect(cap * sizeof(uint16_t)); + self->color = m_malloc_without_collect(cap * sizeof(uint16_t)); + reset_dirty(self); + return MP_OBJ_FROM_PTR(self); +} + +//| +//| def emit( +//| self, x: int, y: int, count: int, speed: int = 1, life: int = 30, color: int = 0xFFFF +//| ) -> None: +//| """Spawn ``count`` particles at ``(x, y)``, living ``life`` ticks, in +//| ``color`` (default white). Each particle's horizontal and vertical velocity is chosen +//| independently from ``-speed`` through ``speed`` pixels per tick.""" +//| ... +//| +static mp_obj_t picogame_particles_emit_fun(size_t n_args, const mp_obj_t *args) { + picogame_particles_obj_t *self = MP_OBJ_TO_PTR(args[0]); + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + int count = mp_arg_validate_int_min(mp_obj_get_int(args[3]), 0, MP_QSTR_count); + // speed*256 must fit the int16_t velocity (8.8) -> cap 127; life is stored as uint16_t. + int speed = (n_args > 4) ? mp_arg_validate_int_range(mp_obj_get_int(args[4]), 0, 127, MP_QSTR_speed) : 1; + int life = (n_args > 5) ? mp_arg_validate_int_range(mp_obj_get_int(args[5]), 1, 65535, MP_QSTR_life) : 30; + uint16_t color = (n_args > 6) + ? mp_arg_validate_int_range(mp_obj_get_int(args[6]), 0, 0xFFFF, MP_QSTR_color) : 0xFFFF; + picogame_particles_emit(self, x, y, count, speed, life, color); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_particles_emit_obj, 4, 7, picogame_particles_emit_fun); + +//| def tick(self) -> None: +//| """Advance all particles one step (movement, gravity, aging).""" +//| ... +//| +static mp_obj_t picogame_particles_tick(mp_obj_t self_in) { + picogame_particles_update(MP_OBJ_TO_PTR(self_in)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_particles_tick_obj, picogame_particles_tick); + +//| def clear(self) -> None: +//| """Remove all particles.""" +//| ... +//| +//| +static mp_obj_t picogame_particles_clear_method(mp_obj_t self_in) { + picogame_particles_clear(MP_OBJ_TO_PTR(self_in)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_particles_clear_obj, picogame_particles_clear_method); + +static const mp_rom_map_elem_t picogame_particles_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_emit), MP_ROM_PTR(&picogame_particles_emit_obj) }, + { MP_ROM_QSTR(MP_QSTR_tick), MP_ROM_PTR(&picogame_particles_tick_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picogame_particles_clear_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_particles_locals_dict, picogame_particles_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_particles_type, + MP_QSTR_Particles, + MP_TYPE_FLAG_NONE, + make_new, picogame_particles_make_new, + locals_dict, &picogame_particles_locals_dict + ); diff --git a/shared-bindings/picogame/Particles.h b/shared-bindings/picogame/Particles.h new file mode 100644 index 00000000000..8f8b37ab819 --- /dev/null +++ b/shared-bindings/picogame/Particles.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Particles.h" + +extern const mp_obj_type_t picogame_particles_type; diff --git a/shared-bindings/picogame/Scene.c b/shared-bindings/picogame/Scene.c new file mode 100644 index 00000000000..c62da12f45c --- /dev/null +++ b/shared-bindings/picogame/Scene.c @@ -0,0 +1,568 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include +#include "shared-module/picogame/pg_compat.h" +#include "py/objtuple.h" +#include "py/objlist.h" +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Sprite.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" +#endif +#include "shared-module/picogame/Scene.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Tilemap.h" +#include "shared-module/picogame/Particles.h" +#include "shared-module/picogame/Canvas.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "common-hal/picogame/Display.h" +#endif + +#define SCENE_INIT_CAP 8 +#define PICOGAME_MAX_DIRTY_RECTS 6 // separate regions repainted per refresh + +// Classify the `display` arg into a render backend and return the object Scene should +// store: a fast picogame.Display (DMA), a picogame.Framebuffer (RAM scanout buffer, when +// built in), or a plain busdisplay (portable bus.send). Sets *fast / *fb_target +// accordingly; for a busdisplay it accepts a SUBCLASS (e.g. adafruit_st7789.ST7789) by +// casting to its native base and returns that. Raises TypeError otherwise. This is where +// the flag-gated type checks live, so the constructor body stays clean. +static mp_obj_t scene_resolve_target(mp_obj_t disp, bool *fast, bool *fb_target) { + *fast = false; + *fb_target = false; + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + { + // Accept subclasses too (same as the busdisplay path below): resolve to the + // native base object, which the C renderer can safely cast. + mp_obj_t ndisp = mp_obj_cast_to_native_base(disp, &picogame_display_type); + if (ndisp != MP_OBJ_NULL && mp_obj_is_type(ndisp, &picogame_display_type)) { + *fast = true; + return ndisp; + } + } + #endif + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + { + mp_obj_t nfb = mp_obj_cast_to_native_base(disp, &picogame_framebuffer_type); + if (nfb != MP_OBJ_NULL && mp_obj_is_type(nfb, &picogame_framebuffer_type)) { + *fb_target = true; // refresh() composites dirty rects straight into its RAM buffer + return nfb; + } + } + #endif + // Plain busdisplay: accept a subclass by casting to its native base; the portable + // renderer treats self->display as a busdisplay_busdisplay_obj_t directly. + mp_obj_t native = mp_obj_cast_to_native_base(disp, &busdisplay_busdisplay_type); + // MP_OBJ_NULL for a non-BusDisplay: validate the ORIGINAL object (NULL's type is unreadable). + if (native == MP_OBJ_NULL || !mp_obj_is_type(native, &busdisplay_busdisplay_type)) { + mp_arg_validate_type(disp, &busdisplay_busdisplay_type, MP_QSTR_display); + } + return native; +} + +//| class Scene: +//| """A retained-mode scene with dirty-rectangle rendering for a `Display`, +//| :py:class:`~busdisplay.BusDisplay` or `Framebuffer` target. Add layers once +//| (insertion order is bottom to top), mutate them each frame, then call +//| :py:meth:`refresh`; only the regions reported changed are repainted.""" +//| +//| def __init__( +//| self, +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], +//| buffer_a: Optional[WriteableBuffer] = None, +//| buffer_b: Optional[WriteableBuffer] = None, +//| *, +//| background: int = 0, +//| top: int = 0, +//| bottom: int = 0, +//| left: int = 0, +//| right: int = 0, +//| ) -> None: +//| """:param display: the render target +//| :param ~circuitpython_typing.WriteableBuffer buffer_a: a strip buffer, +//| typically ``display.width * STRIP_H * 2`` bytes. Its size sets the +//| strip height: each strip is ``size // (display.width * 2)`` rows. Two +//| buffers let the next strip be composited while the previous one is +//| being sent. On a `Framebuffer` target there are no strips and the +//| buffers are unused; both default to `None`. +//| :param ~circuitpython_typing.WriteableBuffer buffer_b: the second strip +//| buffer, sized like ``buffer_a`` +//| :param int background: color that exposed areas are cleared to +//| :param int top: rows at the top edge the scene never renders into +//| :param int bottom: rows at the bottom edge the scene never renders into +//| :param int left: columns at the left edge the scene never renders into +//| :param int right: columns at the right edge the scene never renders into +//| +//| The four border insets reserve screen edges for content the application +//| draws itself, for example with :py:func:`render`; the scene renders only +//| the inner rectangle and never repaints the border.""" +//| ... +//| +static mp_obj_t picogame_scene_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_display, ARG_buffer_a, ARG_buffer_b, ARG_background, + ARG_top, ARG_bottom, ARG_left, ARG_right }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_display, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer_a, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_buffer_b, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_background, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_top, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // reserved border insets: + { MP_QSTR_bottom, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // the scene renders only the + { MP_QSTR_left, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // inner play rect; the app + { MP_QSTR_right, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // owns the border around it + }; + 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); + + // Resolve the render backend (fast Display / Framebuffer / busdisplay) - all the + // flag-gated type checks are concentrated in scene_resolve_target(). + bool fast, fb_target; + mp_obj_t disp = scene_resolve_target(args[ARG_display].u_obj, &fast, &fb_target); + + // The framebuffer path composites directly into the target, so it needs no strip + // buffers; the SPI/DMA paths do. Validate them only when they'll be used. (When + // CIRCUITPY_PICOGAME_FRAMEBUFFER is off, fb_target is always false -> always validated, + // as before.) + if (!fb_target) { + mp_buffer_info_t tmp; + mp_get_buffer_raise(args[ARG_buffer_a].u_obj, &tmp, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[ARG_buffer_b].u_obj, &tmp, MP_BUFFER_WRITE); + } + + picogame_scene_obj_t *self = mp_obj_malloc(picogame_scene_obj_t, type); + self->display = disp; + self->fast = fast; + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + self->fb_target = fb_target; + #endif + self->buf_a = args[ARG_buffer_a].u_obj; + self->buf_b = args[ARG_buffer_b].u_obj; + self->background = args[ARG_background].u_int; + self->count = 0; + self->cap = SCENE_INIT_CAP; + self->items = m_new(mp_obj_t, SCENE_INIT_CAP); + self->kinds = m_new(uint8_t, SCENE_INIT_CAP); + self->snap = m_new(picogame_snapshot_t, SCENE_INIT_CAP); + self->cleared = false; + self->ox = 0; + self->oy = 0; + self->top = args[ARG_top].u_int; + self->bottom = args[ARG_bottom].u_int; + self->left = args[ARG_left].u_int; + self->right = args[ARG_right].u_int; + mp_obj_t zeros[4] = { + MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_NEW_SMALL_INT(0), + MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_NEW_SMALL_INT(0), + }; + self->dirty_rect = mp_obj_new_list(4, zeros); // reused every refresh + return MP_OBJ_FROM_PTR(self); +} + +// On a full repaint, sync sprite snapshots to current and drain the layer +// dirties (tilemap/particles/canvas) so they don't re-report a stale region. +static void snapshot_sync(picogame_scene_obj_t *self) { + int a, b, c, d; + for (uint16_t i = 0; i < self->count; i++) { + uint8_t kind = self->kinds[i] & PICOGAME_KIND_MASK; + if (kind == PICOGAME_KIND_TILEMAP) { + picogame_tilemap_take_dirty(MP_OBJ_TO_PTR(self->items[i]), &a, &b, &c, &d); + } else if (kind == PICOGAME_KIND_PARTICLES) { + picogame_particles_take_dirty(MP_OBJ_TO_PTR(self->items[i]), &a, &b, &c, &d); + } else if (kind == PICOGAME_KIND_CANVAS) { + picogame_canvas_take_dirty(MP_OBJ_TO_PTR(self->items[i]), &a, &b, &c, &d); + } else if (kind == PICOGAME_KIND_STRIPDRAW) { + // Immediate-mode layer: no retained state to snapshot/drain. + } else if (kind == PICOGAME_KIND_TRIANGLES) { + // Screen-space batch: drain the count-set dirty so it doesn't re-report. + int e, f, g, hh; + picogame_dirty_take(&((picogame_triangles_obj_t *)MP_OBJ_TO_PTR(self->items[i]))->dx1, + &e, &f, &g, &hh); + } else { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self->items[i]); + picogame_bitmap_obj_t *bm = s->bitmap; + int ax1, ay1, ax2, ay2; + picogame_sprite_aabb(s, &ax1, &ay1, &ax2, &ay2); + self->snap[i].x = ax1; + self->snap[i].y = ay1; + self->snap[i].w = ax2 - ax1; + self->snap[i].h = ay2 - ay1; + self->snap[i].bitmap = (void *)bm; + self->snap[i].frame = s->frame; + self->snap[i].flags = s->flags; + self->snap[i].scale = s->scale; + self->snap[i].angle = s->angle; + self->snap[i].seq = s->seq; + self->snap[i].dither = s->dither; + self->snap[i].flash_color = s->flash_color; + } + } +} + +//| +//| def add( +//| self, item: Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles], *, fixed: bool = False +//| ) -> Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]: +//| """Add a layer of any kind, drawn starting with the next refresh; insertion +//| order is bottom to top. Returns the added item. +//| +//| ``fixed=True`` pins the item to the screen so it ignores the view offset +//| set by :py:meth:`set_view`, for example for a HUD over a scrolling world. +//| `StripDraw` and `Triangles` layers always draw in screen coordinates and +//| are unaffected by both ``fixed`` and the view offset.""" +//| ... +//| +static void scene_add_one(picogame_scene_obj_t *self, mp_obj_t item_in, bool fixed) { + uint8_t kind; + kind = picogame_kind_of(item_in); + if (fixed) { + kind |= PICOGAME_KIND_FIXED; + } + if (self->count >= self->cap) { + if (self->cap >= 0x8000) { // next doubling overflows uint16_t -> m_renew(0) shrink + m_malloc_fail((size_t)self->cap * 2); // next doubling overflows the count type + } + uint16_t new_cap = self->cap * 2; + self->items = m_renew(mp_obj_t, self->items, self->cap, new_cap); + self->kinds = m_renew(uint8_t, self->kinds, self->cap, new_cap); + self->snap = m_renew(picogame_snapshot_t, self->snap, self->cap, new_cap); + self->cap = new_cap; + } + self->items[self->count] = item_in; + self->kinds[self->count] = kind; + // Snapshot starts all-zero ("invisible", nothing diffed against garbage - m_renew doesn't + // zero), so a newly added layer is detected as changed and drawn on the next refresh. + memset(&self->snap[self->count], 0, sizeof(picogame_snapshot_t)); + self->count++; + // Honour "drawn on the next refresh" for EVERY kind: the zeroed snapshot covers sprites, + // but a re-add()ed Canvas/Tilemap whose dirty flag was already consumed would otherwise + // stay invisible until some other change. add() is a cold path -> force a full repaint. + self->cleared = false; +} + +static mp_obj_t picogame_scene_add(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_item, ARG_fixed }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_item, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_fixed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + scene_add_one(MP_OBJ_TO_PTR(pos_args[0]), args[ARG_item].u_obj, args[ARG_fixed].u_bool); + return args[ARG_item].u_obj; // constructive: return the added item for `x = scene.add(...)` +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_scene_add_obj, 2, picogame_scene_add); + +//| def add_all(self, items: Iterable[Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]]) -> None: +//| """Add several layers at once, bottom to top in iteration order.""" +//| ... +//| +static mp_obj_t picogame_scene_add_all(mp_obj_t self_in, mp_obj_t iterable) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t iter = mp_getiter(iterable, NULL); + mp_obj_t item; + while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + scene_add_one(self, item, false); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(picogame_scene_add_all_obj, picogame_scene_add_all); + +//| def remove(self, item: Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]) -> None: +//| """Remove a previously added item; the draw order of the rest is unchanged. +//| The next refresh repaints the scene, so the item leaves no ghost. The item +//| itself is untouched and may be added again later. Raises +//| :py:class:`ValueError` if the item is not in the scene.""" +//| ... +//| +static mp_obj_t picogame_scene_remove(mp_obj_t self_in, mp_obj_t item_in) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + for (uint16_t i = 0; i < self->count; i++) { + if (self->items[i] != item_in) { + continue; + } + self->count--; + for (uint16_t j = i; j < self->count; j++) { // keep draw order: shift the tail down + self->items[j] = self->items[j + 1]; + self->kinds[j] = self->kinds[j + 1]; + self->snap[j] = self->snap[j + 1]; + } + self->items[self->count] = mp_const_none; // release the GC reference + self->cleared = false; // full repaint next refresh: background covers where it was + return mp_const_none; + } + mp_arg_error_invalid(MP_QSTR_item); +} +static MP_DEFINE_CONST_FUN_OBJ_2(picogame_scene_remove_obj, picogame_scene_remove); + +//| def invalidate(self) -> None: +//| """Force the scene's whole render area to repaint on the next refresh.""" +//| ... +//| +static mp_obj_t picogame_scene_invalidate(mp_obj_t self_in) { + ((picogame_scene_obj_t *)MP_OBJ_TO_PTR(self_in))->cleared = false; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_invalidate_obj, picogame_scene_invalidate); + +//| def set_view(self, ox: int, oy: int) -> None: +//| """Set the screen position ``(ox, oy)`` of scene coordinate ``(0, 0)``: +//| a scene point ``(x, y)`` is drawn at ``(x + ox, y + oy)``. Use a constant +//| offset to center a small scene, or update it each frame to scroll, which +//| repaints the whole render area.""" +//| ... +//| +static mp_obj_t picogame_scene_set_view(mp_obj_t self_in, mp_obj_t ox_in, mp_obj_t oy_in) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + int ox = mp_obj_get_int(ox_in); + int oy = mp_obj_get_int(oy_in); + if (ox != self->ox || oy != self->oy) { + self->ox = ox; + self->oy = oy; + self->cleared = false; // the whole view shifted -> full repaint next refresh + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(picogame_scene_set_view_obj, picogame_scene_set_view); + +//| view: Tuple[int, int] +//| """The current view offset ``(ox, oy)`` as set by :py:meth:`set_view`. (read-only)""" +static mp_obj_t picogame_scene_get_view(mp_obj_t self_in) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t t[2] = { MP_OBJ_NEW_SMALL_INT(self->ox), MP_OBJ_NEW_SMALL_INT(self->oy) }; + return mp_obj_new_tuple(2, t); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_get_view_obj, picogame_scene_get_view); +MP_PROPERTY_GETTER(picogame_scene_view_obj, (mp_obj_t)&picogame_scene_get_view_obj); + +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer] +//| """The render target this Scene was built with. (read-only)""" +//| +static mp_obj_t picogame_scene_get_display(mp_obj_t self_in) { + return ((picogame_scene_obj_t *)MP_OBJ_TO_PTR(self_in))->display; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_get_display_obj, picogame_scene_get_display); +MP_PROPERTY_GETTER(picogame_scene_display_obj, (mp_obj_t)&picogame_scene_get_display_obj); + +// Compute the frame's dirty rectangles for a WxH target, clipped to the play rect +// [left, w-right) x [top, h-bottom). On the first refresh (or after invalidate) this is +// a single full-screen rect + a snapshot sync; afterwards it diffs against the previous +// frame. Returns the rect count written to `rects` (0 = nothing to repaint). +// Backend-agnostic, so the SPI/fast and framebuffer paths share the exact dirty logic. +static int scene_collect_dirty_rects(picogame_scene_obj_t *self, int w, int h, picogame_rect_t *rects) { + int nr; + if (self->cleared) { + nr = picogame_scene_compute_dirty_rects(self->items, self->kinds, self->snap, + self->count, w, h, self->ox, self->oy, rects, PICOGAME_MAX_DIRTY_RECTS); + if (nr == 0) { + return 0; + } + } else { + rects[0].x1 = 0; + rects[0].y1 = 0; + rects[0].x2 = w; + rects[0].y2 = h; + nr = 1; + snapshot_sync(self); + // NOTE: cleared flips to true only after the RENDER completes (see the callers) - + // the snapshots are already advanced here, so an exception mid-render would + // otherwise leave a partially painted frame that no later refresh repairs. + } + + // Clip every dirty rect to the play rect [left, w-right) x [top, h-bottom); the + // reserved border is the app's, so the scene never paints into it. Drop empty rects. + int pa_x1 = self->left; + int pa_x2 = w - self->right; + int pa_y1 = self->top; + int pa_y2 = h - self->bottom; + int kept = 0; + for (int i = 0; i < nr; i++) { + int rx1 = rects[i].x1 < pa_x1 ? pa_x1 : rects[i].x1; + int rx2 = rects[i].x2 > pa_x2 ? pa_x2 : rects[i].x2; + int ry1 = rects[i].y1 < pa_y1 ? pa_y1 : rects[i].y1; + int ry2 = rects[i].y2 > pa_y2 ? pa_y2 : rects[i].y2; + if (rx1 >= rx2 || ry1 >= ry2) { + continue; + } + rects[kept].x1 = rx1; + rects[kept].y1 = ry1; + rects[kept].x2 = rx2; + rects[kept].y2 = ry2; + kept++; + } + return kept; +} + +// Store the bounding union of `nr` rects into the reusable dirty_rect list (no per-frame +// tuple allocation) and return it. Shared by both refresh backends. +static mp_obj_t scene_store_dirty(picogame_scene_obj_t *self, const picogame_rect_t *rects, int nr, int w, int h) { + int ux1 = w, uy1 = h, ux2 = 0, uy2 = 0; + for (int i = 0; i < nr; i++) { + if (rects[i].x1 < ux1) { + ux1 = rects[i].x1; + } + if (rects[i].y1 < uy1) { + uy1 = rects[i].y1; + } + if (rects[i].x2 > ux2) { + ux2 = rects[i].x2; + } + if (rects[i].y2 > uy2) { + uy2 = rects[i].y2; + } + } + mp_obj_list_store(self->dirty_rect, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_NEW_SMALL_INT(ux1)); + mp_obj_list_store(self->dirty_rect, MP_OBJ_NEW_SMALL_INT(1), MP_OBJ_NEW_SMALL_INT(uy1)); + mp_obj_list_store(self->dirty_rect, MP_OBJ_NEW_SMALL_INT(2), MP_OBJ_NEW_SMALL_INT(ux2)); + mp_obj_list_store(self->dirty_rect, MP_OBJ_NEW_SMALL_INT(3), MP_OBJ_NEW_SMALL_INT(uy2)); + return self->dirty_rect; +} + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Retained-mode refresh against a RAM framebuffer target (scanout-buffer platforms: +// WASM playground, desktop sim, FruitJam DVI/HSTX). Same dirty-rect logic as the SPI +// path (via the shared helpers), but each rect is composited straight into the target +// with picogame_render_framebuffer - no strip buffers, no bus transaction. A latched +// StripDraw BaseException is re-raised (no bus to close). Self-contained here so +// picogame_scene_refresh() keeps its original SPI/fast shape. +static mp_obj_t scene_refresh_fb(picogame_scene_obj_t *self) { + picogame_framebuffer_obj_t *fbt = MP_OBJ_TO_PTR(self->display); + int w = fbt->width; + int h = fbt->height; + + // Emulated invert (pg.invert on a Framebuffer) just toggled -> recomposite the WHOLE frame so the + // negative flip covers the whole screen, not only this frame's dirty rects (like a panel INVON). + if (picogame_fb_take_invert_dirty()) { + self->cleared = false; + } + + picogame_rect_t rects[PICOGAME_MAX_DIRTY_RECTS]; + int nr = scene_collect_dirty_rects(self, w, h, rects); + if (nr == 0) { + return mp_const_none; + } + + // Snapshots are already advanced; stay in the needs-full-repaint state until the + // render completes, so a BaseException mid-render (Ctrl-C in a StripDraw) leaves a + // scene whose NEXT refresh repaints everything instead of keeping a torn frame. + self->cleared = false; + for (int i = 0; i < nr; i++) { + mp_obj_t exc = picogame_render_framebuffer(fbt->fb, fbt->width, fbt->height, fbt->fmt, + fbt->scratch, fbt->scratch_rows, + self->items, self->kinds, self->count, + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2, + self->background, self->ox, self->oy); + if (exc != MP_OBJ_NULL) { + nlr_raise(MP_OBJ_TO_PTR(exc)); // cleared stays false -> full repaint next refresh + } + } + self->cleared = true; + return scene_store_dirty(self, rects, nr, w, h); +} +#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER + +//| def refresh(self) -> Optional[list]: +//| """Repaint the regions changed by the scene's layers since the previous +//| refresh. Returns the bounding dirty rectangle as a list +//| ``[x1, y1, x2, y2]`` with exclusive ``x2``/``y2``, or `None` if nothing +//| changed. The returned list object is reused: read it before the next +//| ``refresh()`` call.""" +//| ... +//| +//| +static mp_obj_t picogame_scene_refresh(mp_obj_t self_in) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + if (self->fb_target) { + return scene_refresh_fb(self); + } + #endif + + // Resolve the underlying busdisplay from either backend. + busdisplay_busdisplay_obj_t *bd; + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + picogame_display_obj_t *disp = NULL; + if (self->fast) { + disp = MP_OBJ_TO_PTR(self->display); + bd = disp->display; + } else + #endif + { + bd = MP_OBJ_TO_PTR(self->display); + } + int w = bd->core.width; + int h = bd->core.height; + + picogame_rect_t rects[PICOGAME_MAX_DIRTY_RECTS]; + int nr = scene_collect_dirty_rects(self, w, h, rects); + if (nr == 0) { + return mp_const_none; + } + + mp_buffer_info_t a, b; + mp_get_buffer_raise(self->buf_a, &a, MP_BUFFER_WRITE); + mp_get_buffer_raise(self->buf_b, &b, MP_BUFFER_WRITE); + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + size_t buf_pixels = (a.len < b.len ? a.len : b.len) / 2; // fast path double-buffers + #endif + + // Render each dirty rect independently; return their bounding union (kept for + // the existing "dirty WxH" debug prints). + // Snapshots are already advanced; stay in the needs-full-repaint state until the + // render completes, so a BaseException mid-render (Ctrl-C in a StripDraw) leaves a + // scene whose NEXT refresh repaints everything instead of keeping a torn frame. + self->cleared = false; + for (int i = 0; i < nr; i++) { + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + if (self->fast) { + common_hal_picogame_display_render(disp, self->items, self->kinds, self->count, + (uint16_t *)a.buf, (uint16_t *)b.buf, buf_pixels, + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2, + self->background, self->ox, self->oy); + } else + #endif + { + // Portable single-buffer bus.send path (any CircuitPython port). + picogame_render_region(bd, self->items, self->kinds, self->count, + (uint16_t *)a.buf, a.len / 2, + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2, + self->background, self->ox, self->oy); + } + } + self->cleared = true; + + return scene_store_dirty(self, rects, nr, w, h); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_refresh_obj, picogame_scene_refresh); + +static const mp_rom_map_elem_t picogame_scene_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&picogame_scene_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_add_all), MP_ROM_PTR(&picogame_scene_add_all_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&picogame_scene_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&picogame_scene_refresh_obj) }, + { MP_ROM_QSTR(MP_QSTR_invalidate), MP_ROM_PTR(&picogame_scene_invalidate_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_view), MP_ROM_PTR(&picogame_scene_set_view_obj) }, + { MP_ROM_QSTR(MP_QSTR_view), MP_ROM_PTR(&picogame_scene_view_obj) }, + { MP_ROM_QSTR(MP_QSTR_display), MP_ROM_PTR(&picogame_scene_display_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_scene_locals_dict, picogame_scene_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_scene_type, + MP_QSTR_Scene, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_scene_make_new, + locals_dict, &picogame_scene_locals_dict + ); diff --git a/shared-bindings/picogame/Scene.h b/shared-bindings/picogame/Scene.h new file mode 100644 index 00000000000..733968b06ca --- /dev/null +++ b/shared-bindings/picogame/Scene.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Scene.h" + +extern const mp_obj_type_t picogame_scene_type; diff --git a/shared-bindings/picogame/Sprite.c b/shared-bindings/picogame/Sprite.c new file mode 100644 index 00000000000..37f13775681 --- /dev/null +++ b/shared-bindings/picogame/Sprite.c @@ -0,0 +1,615 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.Sprite: a positioned, animatable instance of a Bitmap. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// --------------------------------------------------------------------------- +// Sprite +// --------------------------------------------------------------------------- + +// Int pixel/scale -> 24.8 fixed-point. Shift through unsigned so a wild coordinate (e.g. 100_000_000, +// in 32-bit mp_int range but not after <<8) wraps modularly instead of hitting signed-overflow UB. +// Costs nothing over a plain shift; for any real on-screen coordinate the result is identical. +static int32_t pg_int_to_fp8(mp_int_t v) { + return (int32_t)((uint32_t)v << 8); +} + +//| class Sprite: +//| """A positioned, animatable instance of a :py:class:`Bitmap`.""" +//| +//| def __init__( +//| self, +//| bitmap: Bitmap, +//| x: int = 0, +//| y: int = 0, +//| *, +//| frame: int = 0, +//| visible: bool = True, +//| flip_x: bool = False, +//| flip_y: bool = False, +//| ) -> None: +//| """Place ``bitmap`` with its top-left corner at ``(x, y)`` in scene +//| coordinates, showing the frame selected by ``frame``. Scene coordinates +//| follow the view offset, so the sprite moves with a scrolling world. +//| +//| ``visible=False`` creates the sprite without drawing it, for example to +//| pre-allocate a pool of sprites up front. ``flip_x`` and ``flip_y`` mirror +//| the frame at draw time.""" +//| ... +//| +static mp_obj_t picogame_sprite_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_bitmap, ARG_x, ARG_y, ARG_frame, ARG_visible, ARG_flip_x, ARG_flip_y }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_frame, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_visible, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_flip_x, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_flip_y, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + mp_obj_t bitmap_obj = mp_arg_validate_type(args[ARG_bitmap].u_obj, &picogame_bitmap_type, MP_QSTR_bitmap); + + picogame_sprite_obj_t *self = mp_obj_malloc(picogame_sprite_obj_t, type); + self->bitmap = MP_OBJ_TO_PTR(bitmap_obj); + self->x = pg_int_to_fp8(args[ARG_x].u_int); // pixel -> 24.8 fixed-point (overflow-clamped) + self->y = pg_int_to_fp8(args[ARG_y].u_int); + self->frame = args[ARG_frame].u_int; + self->flags = (args[ARG_visible].u_bool ? PICOGAME_SPR_VISIBLE : 0) + | (args[ARG_flip_x].u_bool ? PICOGAME_SPR_FLIP_X : 0) + | (args[ARG_flip_y].u_bool ? PICOGAME_SPR_FLIP_Y : 0); + self->anchor_x = 0; // default pivot = top-left (0, 0) + self->anchor_y = 0; + self->scale = 256; // 8.8 fixed-point: 256 = 1.0x (no scaling) + self->angle = 0; // no rotation -> axis-aligned fast path + self->flash_color = 0; + self->dither = 0; + self->data = mp_const_none; + self->seq = 0; // dirty-rect change counter (mp_obj_malloc zeroes anyway; explicit) + return MP_OBJ_FROM_PTR(self); +} + +static void set_flag(picogame_sprite_obj_t *self, uint8_t flag, bool on) { + if (on) { + self->flags |= flag; + } else { + self->flags &= ~flag; + } +} + +// shadow / flash / dither are mutually exclusive (one blit effect at a time); setting one ON +// clears the others, so "the last effect you set wins". Turning one OFF clears ONLY its own flag, +// so clearing an effect you never enabled (e.g. spr.flash = 0) can't wipe a different active one. +#define PICOGAME_SPR_FX_MASK (PICOGAME_SPR_SHADOW | PICOGAME_SPR_FLASH | PICOGAME_SPR_DITHER | PICOGAME_SPR_TINT) +static void set_effect(picogame_sprite_obj_t *self, uint8_t flag, bool on) { + if (on) { + self->flags = (uint8_t)((self->flags & ~PICOGAME_SPR_FX_MASK) | flag); + } else { + self->flags &= (uint8_t) ~flag; + } +} + +// Round a float to 24.8 fixed-point (shared by the position/scale/anchor setters so the soft-float +// round sequence is emitted once, not per call site). +static int32_t pg_round_fp8(mp_float_t f) { + return (int32_t)(f * 256 + (f >= 0 ? (mp_float_t)0.5 : (mp_float_t)-0.5)); +} + + +// Accept an int or float and store as 24.8 fixed-point (rounded). Integer fast path avoids +// software float on RP2040 - game code sets x/y (via move/setters) every frame, usually with ints. +static int32_t obj_to_fp(mp_obj_t o) { + if (mp_obj_is_int(o)) { + return pg_int_to_fp8(mp_obj_get_int(o)); + } + mp_float_t f = mp_obj_get_float(o); + return pg_round_fp8(f); +} + +//| +//| frame: int +//| """Which frame of the bitmap's atlas to draw, starting at 0. Stepping this +//| animates the sprite.""" +//| visible: bool +//| """`False` hides the sprite. It stays in the scene and the area under it +//| repaints.""" +//| flip_x: bool +//| """Mirror the frame horizontally at draw time.""" +//| flip_y: bool +//| """Mirror the frame vertically at draw time.""" +//| x: int +//| """Horizontal pixel position in scene coordinates. Setting accepts a float +//| for sub-pixel placement; reading returns the floored pixel.""" +//| y: int +//| """Vertical pixel position in scene coordinates. Setting accepts a float +//| for sub-pixel placement; reading returns the floored pixel.""" +//| fx: float +//| """Horizontal sub-pixel position, for example ``sprite.fx += 2.4``.""" +//| fy: float +//| """Vertical sub-pixel position, for example ``sprite.fy += 2.4``.""" +// FLASH NOTE (property objects vs. a single `attr` handler): Sprite (and the other property-dense +// types) expose each attribute as its own getter/setter + MP_PROPERTY object below - the standard +// CircuitPython shared-bindings idiom (~423 such uses across CP). Collapsing these onto ONE `attr` +// load/store function per type (a qstr switch, like py/objcomplex.c's complex_attr for .real/.imag) +// would save ~3-4 KB of flash across the whole binding layer (Sprite alone ~1.5-2.5 KB). It is a +// valid MicroPython mechanism and would NOT break the .pyi stubs (those are generated from the //| +// comments, not the C property objects). We deliberately KEEP property objects: they are the +// idiomatic, most readable shared-bindings form and keep every type's definition uniform. Revisit +// only if flash becomes critical (then convert Sprite first - the densest cluster - not every type). +static mp_obj_t sprite_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x >> 8); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_x_obj, sprite_get_x); +static mp_obj_t sprite_set_x(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x = obj_to_fp(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_x_obj, sprite_set_x); +MP_PROPERTY_GETSET(sprite_x_obj, (mp_obj_t)&sprite_get_x_obj, (mp_obj_t)&sprite_set_x_obj); + +static mp_obj_t sprite_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y >> 8); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_y_obj, sprite_get_y); +static mp_obj_t sprite_set_y(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y = obj_to_fp(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_y_obj, sprite_set_y); +MP_PROPERTY_GETSET(sprite_y_obj, (mp_obj_t)&sprite_get_y_obj, (mp_obj_t)&sprite_set_y_obj); + +static mp_obj_t sprite_get_fx(mp_obj_t self_in) { + return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x * (mp_float_t)(1.0 / 256.0)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_fx_obj, sprite_get_fx); +// set_fx is byte-identical to set_x (both store obj_to_fp(v) into ->x) -> reuse set_x's fun obj. +MP_PROPERTY_GETSET(sprite_fx_obj, (mp_obj_t)&sprite_get_fx_obj, (mp_obj_t)&sprite_set_x_obj); + +static mp_obj_t sprite_get_fy(mp_obj_t self_in) { + return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y * (mp_float_t)(1.0 / 256.0)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_fy_obj, sprite_get_fy); +// set_fy is byte-identical to set_y -> reuse set_y's fun obj. +MP_PROPERTY_GETSET(sprite_fy_obj, (mp_obj_t)&sprite_get_fy_obj, (mp_obj_t)&sprite_set_y_obj); + +static mp_obj_t sprite_get_frame(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->frame); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_frame_obj, sprite_get_frame); +static mp_obj_t sprite_set_frame(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->frame = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_frame_obj, sprite_set_frame); +MP_PROPERTY_GETSET(sprite_frame_obj, (mp_obj_t)&sprite_get_frame_obj, (mp_obj_t)&sprite_set_frame_obj); + +static mp_obj_t sprite_get_visible(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_VISIBLE) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_visible_obj, sprite_get_visible); +static mp_obj_t sprite_set_visible(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_VISIBLE, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_visible_obj, sprite_set_visible); +MP_PROPERTY_GETSET(sprite_visible_obj, (mp_obj_t)&sprite_get_visible_obj, (mp_obj_t)&sprite_set_visible_obj); + +static mp_obj_t sprite_get_flip_x(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_FLIP_X) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flip_x_obj, sprite_get_flip_x); +static mp_obj_t sprite_set_flip_x(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_FLIP_X, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flip_x_obj, sprite_set_flip_x); +MP_PROPERTY_GETSET(sprite_flip_x_obj, (mp_obj_t)&sprite_get_flip_x_obj, (mp_obj_t)&sprite_set_flip_x_obj); + +static mp_obj_t sprite_get_flip_y(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_FLIP_Y) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flip_y_obj, sprite_get_flip_y); +static mp_obj_t sprite_set_flip_y(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_FLIP_Y, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flip_y_obj, sprite_set_flip_y); +MP_PROPERTY_GETSET(sprite_flip_y_obj, (mp_obj_t)&sprite_get_flip_y_obj, (mp_obj_t)&sprite_set_flip_y_obj); + +//| scale: float +//| """Uniform draw scale using nearest-neighbor sampling. ``1.0`` is native size; +//| fractional values are allowed. The anchor point stays put.""" +static mp_obj_t sprite_get_scale(mp_obj_t self_in) { + return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->scale * (mp_float_t)(1.0 / 256.0)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_scale_obj, sprite_get_scale); +static mp_obj_t sprite_set_scale(mp_obj_t self_in, mp_obj_t v) { + int q; + if (mp_obj_is_int(v)) { // int fast path (no software float on RP2040) + q = pg_int_to_fp8(mp_obj_get_int(v)); // overflow-clamped <<8 + } else { + mp_float_t f = mp_obj_get_float(v); + q = pg_round_fp8(f); + } + if (q < 1) { + q = 1; + } + if (q > 65535) { + q = 65535; + } + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->scale = (uint16_t)q; + self->xf_valid = 0; // affine cache depends on scale + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_scale_obj, sprite_set_scale); +MP_PROPERTY_GETSET(sprite_scale_obj, (mp_obj_t)&sprite_get_scale_obj, (mp_obj_t)&sprite_set_scale_obj); + +//| angle: float +//| """Rotation in degrees about the anchor; ``0`` is unrotated. Values are stored +//| as whole degrees. Rotation uses nearest-neighbor sampling.""" +static mp_obj_t sprite_get_angle(mp_obj_t self_in) { + return mp_obj_new_float((mp_float_t)((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->angle); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_angle_obj, sprite_get_angle); +static mp_obj_t sprite_set_angle(mp_obj_t self_in, mp_obj_t v) { + int a; + if (mp_obj_is_int(v)) { // int fast path (no software float on RP2040) + a = mp_obj_get_int(v); + } else { + mp_float_t f = mp_obj_get_float(v); + a = (int)(f + (f >= 0 ? (mp_float_t)0.5 : (mp_float_t)-0.5)); + } + a %= 360; + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->angle = (int16_t)a; + self->xf_valid = 0; // affine cache depends on angle + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_angle_obj, sprite_set_angle); +MP_PROPERTY_GETSET(sprite_angle_obj, (mp_obj_t)&sprite_get_angle_obj, (mp_obj_t)&sprite_set_angle_obj); + +//| shadow: bool +//| """Draw opaque pixels by darkening the destination instead of writing color, +//| producing a shadow silhouette or a dimming overlay. Mutually exclusive with +//| `flash`, `dither` and `tint`.""" +static mp_obj_t sprite_get_shadow(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_SHADOW) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_shadow_obj, sprite_get_shadow); +static mp_obj_t sprite_set_shadow(mp_obj_t self_in, mp_obj_t v) { + set_effect(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_SHADOW, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_shadow_obj, sprite_set_shadow); +MP_PROPERTY_GETSET(sprite_shadow_obj, (mp_obj_t)&sprite_get_shadow_obj, (mp_obj_t)&sprite_set_shadow_obj); + +//| flash: int +//| """Draw opaque pixels as one solid color instead of their own, for example as +//| a brief hit flash. Set to a color from :py:func:`rgb565` to enable, ``0`` to +//| disable. Because ``0`` disables the effect, pure black cannot be the flash +//| color; use a near-black color instead. Mutually exclusive with `shadow`, +//| `dither` and `tint`.""" +static mp_obj_t sprite_get_flash(mp_obj_t self_in) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_FLASH) ? s->flash_color : 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flash_obj, sprite_get_flash); +static mp_obj_t sprite_set_flash(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + // Falsy (None / False / 0) turns flash OFF. A non-zero colour enables it. (You can't flash + // pure black - use a near-black colour if you ever need that; off is the common case.) + if (!mp_obj_is_true(v)) { + set_effect(s, PICOGAME_SPR_FLASH, false); + } else { + s->flash_color = (uint16_t)mp_obj_get_int(v); + set_effect(s, PICOGAME_SPR_FLASH, true); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flash_obj, sprite_set_flash); +MP_PROPERTY_GETSET(sprite_flash_obj, (mp_obj_t)&sprite_get_flash_obj, (mp_obj_t)&sprite_set_flash_obj); + +//| dither: int +//| """Approximate transparency with an ordered (Bayer) dither pattern; there is +//| no alpha blending. ``0`` is opaque (off), ``8`` is about half transparent and +//| ``16`` is invisible. Mutually exclusive with `shadow`, `flash` and `tint`.""" +static mp_obj_t sprite_get_dither(mp_obj_t self_in) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_DITHER) ? s->dither : 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_dither_obj, sprite_get_dither); +static mp_obj_t sprite_set_dither(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + int lv = mp_obj_get_int(v); + if (lv < 0) { + lv = 0; + } + if (lv > 16) { + lv = 16; + } + s->dither = (uint8_t)lv; + set_effect(s, PICOGAME_SPR_DITHER, lv > 0); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_dither_obj, sprite_set_dither); +MP_PROPERTY_GETSET(sprite_dither_obj, (mp_obj_t)&sprite_get_dither_obj, (mp_obj_t)&sprite_set_dither_obj); + +//| tint: int +//| """Multiply opaque pixels by a color from :py:func:`rgb565`, preserving the +//| sprite's shading (unlike `flash`, which replaces it). ``0`` disables, so pure +//| black cannot be the tint color. Mutually exclusive with `shadow`, `flash` +//| and `dither`.""" +static mp_obj_t sprite_get_tint(mp_obj_t self_in) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_TINT) ? s->flash_color : 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_tint_obj, sprite_get_tint); +static mp_obj_t sprite_set_tint(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + if (!mp_obj_is_true(v)) { + set_effect(s, PICOGAME_SPR_TINT, false); + } else { + s->flash_color = (uint16_t)mp_obj_get_int(v); // shared colour field with flash + set_effect(s, PICOGAME_SPR_TINT, true); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_tint_obj, sprite_set_tint); +MP_PROPERTY_GETSET(sprite_tint_obj, (mp_obj_t)&sprite_get_tint_obj, (mp_obj_t)&sprite_set_tint_obj); + +//| transpose: bool +//| """Transpose the frame by swapping its x and y axes. Combined with `flip_x` +//| and `flip_y` this yields all 8 orthogonal orientations. Applies only at +//| ``scale == 1.0`` and ``angle == 0``; for rotation combined with scaling use +//| `angle`. The drawn footprint swaps width and height.""" +static mp_obj_t sprite_get_transpose(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_TRANSPOSE) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_transpose_obj, sprite_get_transpose); +static mp_obj_t sprite_set_transpose(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_TRANSPOSE, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_transpose_obj, sprite_set_transpose); +MP_PROPERTY_GETSET(sprite_transpose_obj, (mp_obj_t)&sprite_get_transpose_obj, (mp_obj_t)&sprite_set_transpose_obj); + +//| data: Any +//| """Arbitrary per-sprite user payload for game state (default None).""" +static mp_obj_t sprite_get_data(mp_obj_t self_in) { + return ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->data; +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_data_obj, sprite_get_data); +static mp_obj_t sprite_set_data(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->data = v; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_data_obj, sprite_set_data); +MP_PROPERTY_GETSET(sprite_data_obj, (mp_obj_t)&sprite_get_data_obj, (mp_obj_t)&sprite_set_data_obj); + +//| bitmap: Bitmap +//| """The sprite's source bitmap. Assigning a new one swaps the graphics and may +//| change the sprite's size; the scene repaints both the old and new bounds on +//| the next refresh.""" +static mp_obj_t sprite_get_bitmap(mp_obj_t self_in) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->bitmap != NULL ? MP_OBJ_FROM_PTR(self->bitmap) : mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_bitmap_obj, sprite_get_bitmap); +static mp_obj_t sprite_set_bitmap(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t bm = mp_arg_validate_type(v, &picogame_bitmap_type, MP_QSTR_bitmap); + self->bitmap = MP_OBJ_TO_PTR(bm); + self->xf_valid = 0; // affine cache depends on bitmap dims + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_bitmap_obj, sprite_set_bitmap); +MP_PROPERTY_GETSET(sprite_bitmap_obj, (mp_obj_t)&sprite_get_bitmap_obj, (mp_obj_t)&sprite_set_bitmap_obj); + +//| anchor: Tuple[float, float] +//| """Pivot as fractions of the bitmap size: ``(0, 0)`` = top-left (default), +//| ``(0.5, 0.5)`` = center, ``(0.5, 1.0)`` = bottom-center. ``x``/``y`` then +//| refer to this point, so rotating frames or swapping to a different size +//| stays aligned. Stored in 1/256 steps.""" +//| +static mp_obj_t sprite_get_anchor(mp_obj_t self_in) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t t[2] = { + mp_obj_new_float(self->anchor_x * (mp_float_t)(1.0 / 256.0)), + mp_obj_new_float(self->anchor_y * (mp_float_t)(1.0 / 256.0)), + }; + return mp_obj_new_tuple(2, t); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_anchor_obj, sprite_get_anchor); +static int anchor_to_fp(mp_obj_t o) { + mp_float_t f = mp_obj_get_float(o); + int v = pg_round_fp8(f); + return v < 0 ? 0 : (v > 256 ? 256 : v); +} +static mp_obj_t sprite_set_anchor(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t len; + mp_obj_t *items; + mp_obj_get_array(v, &len, &items); + mp_arg_validate_length(len, 2, MP_QSTR_anchor); + self->anchor_x = anchor_to_fp(items[0]); + self->anchor_y = anchor_to_fp(items[1]); + self->xf_valid = 0; // affine cache depends on the pivot + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_anchor_obj, sprite_set_anchor); +MP_PROPERTY_GETSET(sprite_anchor_obj, (mp_obj_t)&sprite_get_anchor_obj, (mp_obj_t)&sprite_set_anchor_obj); + +//| def move(self, x: float, y: float) -> None: +//| """Set the sprite position. Accepts floats for sub-pixel placement.""" +//| ... +//| +static mp_obj_t sprite_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->x = obj_to_fp(x_in); + self->y = obj_to_fp(y_in); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(sprite_move_obj, sprite_move); + +//| def touch(self) -> None: +//| """Force this sprite to repaint on the next :py:meth:`Scene.refresh` even +//| though none of its tracked properties (position, frame, scale, angle, +//| bitmap) changed. Call it after mutating the bitmap's backing buffer in +//| place, which the dirty-region tracking cannot otherwise detect.""" +//| ... +//| +static mp_obj_t sprite_touch(mp_obj_t self_in) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->seq++; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_touch_obj, sprite_touch); + +// Fill (x1,y1,x2,y2) from a Sprite (its drawn aabb), a (x,y) point, or a (x1,y1,x2,y2) rect. +static void pg_obj_to_box(mp_obj_t o, int *x1, int *y1, int *x2, int *y2) { + if (mp_obj_is_type(o, &picogame_sprite_type)) { + picogame_sprite_aabb(MP_OBJ_TO_PTR(o), x1, y1, x2, y2); + return; + } + if (mp_obj_is_type(o, &mp_type_tuple) || mp_obj_is_type(o, &mp_type_list)) { + size_t len; + mp_obj_t *items; + mp_obj_get_array(o, &len, &items); + if (len == 2) { // a point -> a zero-size box + *x1 = *x2 = mp_obj_get_int(items[0]); + *y1 = *y2 = mp_obj_get_int(items[1]); + return; + } + if (len == 4) { // a rect + *x1 = mp_obj_get_int(items[0]); + *y1 = mp_obj_get_int(items[1]); + *x2 = mp_obj_get_int(items[2]); + *y2 = mp_obj_get_int(items[3]); + return; + } + } + mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), + MP_QSTR_other, MP_QSTR_Sprite, MP_QSTR_tuple, mp_obj_get_type(o)->name); +} + +//| def overlaps( +//| self, +//| other: Union[Sprite, Tuple[int, int], Tuple[int, int, int, int]], +//| inset: int = 0, +//| ) -> bool: +//| """Return `True` if this sprite's drawn rectangle overlaps ``other``. Bounds +//| are inclusive, so touching edges count as an overlap. ``other`` may be +//| another `Sprite`, a point ``(x, y)`` or a rectangle ``(x1, y1, x2, y2)``. +//| The rectangle accounts for anchor, scale and rotation. ``inset`` shrinks +//| this sprite's rectangle by that many pixels on each side.""" +//| ... +//| +static mp_obj_t sprite_overlaps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_other, ARG_inset }; + static const mp_arg_t allowed[] = { + { MP_QSTR_other, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_inset, MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed), allowed, args); + int ax1, ay1, ax2, ay2, bx1, by1, bx2, by2; + picogame_sprite_aabb(MP_OBJ_TO_PTR(pos_args[0]), &ax1, &ay1, &ax2, &ay2); + pg_obj_to_box(args[ARG_other].u_obj, &bx1, &by1, &bx2, &by2); + int in = args[ARG_inset].u_int; // inset shrinks the CALLER's box (kw or positional) + bool hit = ((ax1 + in) <= bx2) && ((ax2 - in) >= bx1) && + ((ay1 + in) <= by2) && ((ay2 - in) >= by1); + return mp_obj_new_bool(hit); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(sprite_overlaps_obj, 2, sprite_overlaps); + +//| def near(self, other: Union[Sprite, Tuple[int, int]], r: int) -> bool: +//| """Return `True` when the distance between centers is less than ``r`` +//| pixels. ``other`` may be a `Sprite` or a point ``(x, y)``. Centers come +//| from the drawn rectangle, so the test accounts for the anchor.""" +//| ... +//| +//| +static mp_obj_t sprite_near(mp_obj_t self_in, mp_obj_t other_in, mp_obj_t r_in) { + int ax1, ay1, ax2, ay2; + picogame_sprite_aabb(MP_OBJ_TO_PTR(self_in), &ax1, &ay1, &ax2, &ay2); + int acx = (ax1 + ax2) / 2, acy = (ay1 + ay2) / 2, bcx, bcy; + if (mp_obj_is_type(other_in, &picogame_sprite_type)) { + int bx1, by1, bx2, by2; + picogame_sprite_aabb(MP_OBJ_TO_PTR(other_in), &bx1, &by1, &bx2, &by2); + bcx = (bx1 + bx2) / 2; + bcy = (by1 + by2) / 2; + } else { + size_t len; + mp_obj_t *items; + mp_obj_get_array(other_in, &len, &items); + if (len != 2) { + mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), + MP_QSTR_other, MP_QSTR_Sprite, MP_QSTR_tuple, mp_obj_get_type(other_in)->name); + } + bcx = mp_obj_get_int(items[0]); + bcy = mp_obj_get_int(items[1]); + } + mp_int_t r = mp_obj_get_int(r_in), dx = acx - bcx, dy = acy - bcy; + return mp_obj_new_bool(dx * dx + dy * dy < r * r); +} +static MP_DEFINE_CONST_FUN_OBJ_3(sprite_near_obj, sprite_near); + +static const mp_rom_map_elem_t picogame_sprite_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&sprite_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&sprite_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_fx), MP_ROM_PTR(&sprite_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_fy), MP_ROM_PTR(&sprite_fy_obj) }, + { MP_ROM_QSTR(MP_QSTR_frame), MP_ROM_PTR(&sprite_frame_obj) }, + { MP_ROM_QSTR(MP_QSTR_visible), MP_ROM_PTR(&sprite_visible_obj) }, + { MP_ROM_QSTR(MP_QSTR_flip_x), MP_ROM_PTR(&sprite_flip_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_flip_y), MP_ROM_PTR(&sprite_flip_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&sprite_scale_obj) }, + { MP_ROM_QSTR(MP_QSTR_angle), MP_ROM_PTR(&sprite_angle_obj) }, + { MP_ROM_QSTR(MP_QSTR_shadow), MP_ROM_PTR(&sprite_shadow_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash), MP_ROM_PTR(&sprite_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&sprite_dither_obj) }, + { MP_ROM_QSTR(MP_QSTR_tint), MP_ROM_PTR(&sprite_tint_obj) }, + { MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&sprite_transpose_obj) }, + { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&sprite_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&sprite_bitmap_obj) }, + { MP_ROM_QSTR(MP_QSTR_anchor), MP_ROM_PTR(&sprite_anchor_obj) }, + { MP_ROM_QSTR(MP_QSTR_overlaps), MP_ROM_PTR(&sprite_overlaps_obj) }, + { MP_ROM_QSTR(MP_QSTR_near), MP_ROM_PTR(&sprite_near_obj) }, + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&sprite_move_obj) }, + { MP_ROM_QSTR(MP_QSTR_touch), MP_ROM_PTR(&sprite_touch_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_sprite_locals_dict, picogame_sprite_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_sprite_type, + MP_QSTR_Sprite, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_sprite_make_new, + locals_dict, &picogame_sprite_locals_dict + ); diff --git a/shared-bindings/picogame/Sprite.h b/shared-bindings/picogame/Sprite.h new file mode 100644 index 00000000000..97c38c8b762 --- /dev/null +++ b/shared-bindings/picogame/Sprite.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Sprite.h" + +extern const mp_obj_type_t picogame_sprite_type; diff --git a/shared-bindings/picogame/StripDraw.c b/shared-bindings/picogame/StripDraw.c new file mode 100644 index 00000000000..45bfc591e35 --- /dev/null +++ b/shared-bindings/picogame/StripDraw.c @@ -0,0 +1,241 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.StripDraw: an immediate-mode draw layer that holds no pixel buffer. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-bindings/picogame/StripDraw.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// --------------------------------------------------------------------------- +// StripDraw (immediate-mode draw layer; struct in shared-module/picogame/__init__.h) +// --------------------------------------------------------------------------- + +//| class StripDraw: +//| """An immediate-mode draw layer that holds no pixel buffer. On each refresh, +//| for every render strip overlapping its rectangle, ``callback(view, vx, vy, +//| vw, vh)`` is called with a `Canvas` view of the live strip buffer, so the +//| callback draws primitives directly into the frame. StripDraw layers always +//| draw in screen coordinates and ignore the scene's view offset. +//| +//| ``(vx, vy)`` is the view origin in screen coordinates and ``(vw, vh)`` is +//| its size: to draw a screen point ``(sx, sy)``, draw at ``(sx - vx, sy - vy)`` +//| in ``view``. The view may span the full render-region width even when the +//| layer is narrower (the layer's rectangle only limits which rows are drawn), +//| so fill your own rectangle with :py:meth:`Canvas.fill_rect` rather than +//| ``view.clear()``, which fills the whole width. +//| +//| Moving or resizing the layer by assigning :py:attr:`x`, :py:attr:`y`, +//| :py:attr:`width` or :py:attr:`height` can leave the old area stale; call +//| :py:meth:`Scene.invalidate` afterwards for a clean repaint.""" +//| +//| def __init__( +//| self, +//| callback: Callable[[Canvas, int, int, int, int], None], +//| x: int = 0, +//| y: int = 0, +//| width: int = 0, +//| height: int = 0, +//| *, +//| always_dirty: bool = True, +//| ) -> None: +//| """:param callback: called for each overlapping render strip as +//| ``callback(view, vx, vy, vw, vh)`` +//| :param int x: left edge of the layer's screen rectangle +//| :param int y: top edge of the layer's screen rectangle +//| :param int width: rectangle width in pixels +//| :param int height: rectangle height in pixels +//| :param bool always_dirty: when `True` the layer redraws every refresh; +//| when `False`, call :py:meth:`invalidate` after its content changes""" +//| ... +//| +static mp_obj_t picogame_stripdraw_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_callback, ARG_x, ARG_y, ARG_width, ARG_height, ARG_always_dirty }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_width, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_height, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_always_dirty, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + }; + 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); + + picogame_stripdraw_obj_t *self = mp_obj_malloc(picogame_stripdraw_obj_t, type); + self->callback = args[ARG_callback].u_obj; + self->x = args[ARG_x].u_int; + self->y = args[ARG_y].u_int; + self->w = args[ARG_width].u_int; + self->h = args[ARG_height].u_int; + self->faulted = false; + self->always_dirty = args[ARG_always_dirty].u_bool; + picogame_dirty_reset(&self->dx1); // render once on first refresh (even when always_dirty=False) + picogame_dirty_union(&self->dx1, self->x, self->y, self->x + self->w, self->y + self->h); + // A buffer-less Canvas reused as the per-strip drawing view: its `data` is + // repointed at the live strip each blit, so no surface RAM is allocated here. + picogame_canvas_obj_t *view = mp_obj_malloc(picogame_canvas_obj_t, &picogame_canvas_type); + view->data = NULL; + view->data_obj = MP_OBJ_NULL; + view->w = 0; + view->h = 0; + view->x = 0; + view->y = 0; + view->transparent = 0; + view->has_transparent = false; + picogame_canvas_dirty_reset(view); + self->view = MP_OBJ_FROM_PTR(view); + return MP_OBJ_FROM_PTR(self); +} + +//| +//| x: int +//| """Left edge of the layer's screen rectangle.""" +//| y: int +//| """Top edge of the layer's screen rectangle.""" +//| width: int +//| """Width of the layer's screen rectangle in pixels.""" +//| height: int +//| """Height of the layer's screen rectangle in pixels.""" +static mp_obj_t sd_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_x_obj, sd_get_x); +static mp_obj_t sd_set_x(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_x_obj, sd_set_x); +MP_PROPERTY_GETSET(sd_x_obj, (mp_obj_t)&sd_get_x_obj, (mp_obj_t)&sd_set_x_obj); + +static mp_obj_t sd_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->y); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_y_obj, sd_get_y); +static mp_obj_t sd_set_y(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->y = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_y_obj, sd_set_y); +MP_PROPERTY_GETSET(sd_y_obj, (mp_obj_t)&sd_get_y_obj, (mp_obj_t)&sd_set_y_obj); + +static mp_obj_t sd_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->w); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_width_obj, sd_get_width); +static mp_obj_t sd_set_width(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->w = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_width_obj, sd_set_width); +MP_PROPERTY_GETSET(sd_width_obj, (mp_obj_t)&sd_get_width_obj, (mp_obj_t)&sd_set_width_obj); + +static mp_obj_t sd_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->h); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_height_obj, sd_get_height); +static mp_obj_t sd_set_height(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->h = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_height_obj, sd_set_height); +MP_PROPERTY_GETSET(sd_height_obj, (mp_obj_t)&sd_get_height_obj, (mp_obj_t)&sd_set_height_obj); + +//| always_dirty: bool +//| """When `True` (the default) the rectangle repaints every frame, for animated +//| content. When `False` the layer renders once initially and then repaints only +//| after an :py:meth:`invalidate` call or when overlapped by another dirty +//| layer; call :py:meth:`invalidate` after each content change.""" +//| +static mp_obj_t sd_get_always_dirty(mp_obj_t self_in) { + return mp_obj_new_bool(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->always_dirty); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_always_dirty_obj, sd_get_always_dirty); +static mp_obj_t sd_set_always_dirty(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->always_dirty = mp_obj_is_true(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_always_dirty_obj, sd_set_always_dirty); +MP_PROPERTY_GETSET(sd_always_dirty_obj, (mp_obj_t)&sd_get_always_dirty_obj, (mp_obj_t)&sd_set_always_dirty_obj); + +//| def invalidate(self, x: int = 0, y: int = 0, w: int = 0, h: int = 0) -> None: +//| """Mark the layer dirty so it repaints on the next refresh; only needed +//| when ``always_dirty`` is `False`. +//| +//| With no arguments the whole layer repaints. To repaint one region, pass +//| all four values as a rectangle in the view-local coordinates the draw +//| callback uses; passing only some of them raises :py:class:`ValueError`. +//| Repeated calls accumulate, and the rectangle is clamped to the layer.""" +//| ... +//| +//| +static mp_obj_t sd_invalidate(size_t n_args, const mp_obj_t *args) { + picogame_stripdraw_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args != 1 && n_args != 5) { + // A partial rectangle is a bug, not a request for "everything". + mp_arg_error_invalid(MP_QSTR_rect); + } + if (n_args >= 5) { // (x, y, w, h) in view-local coords -> clamped scene rect + int x1 = self->x + mp_obj_get_int(args[1]); + int y1 = self->y + mp_obj_get_int(args[2]); + int x2 = x1 + mp_obj_get_int(args[3]); + int y2 = y1 + mp_obj_get_int(args[4]); + if (x1 < self->x) { + x1 = self->x; + } + if (y1 < self->y) { + y1 = self->y; + } + if (x2 > self->x + self->w) { + x2 = self->x + self->w; + } + if (y2 > self->y + self->h) { + y2 = self->y + self->h; + } + if (x2 > x1 && y2 > y1) { + picogame_dirty_union(&self->dx1, x1, y1, x2, y2); + } + } else { // whole layer + picogame_dirty_union(&self->dx1, self->x, self->y, self->x + self->w, self->y + self->h); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sd_invalidate_obj, 1, 5, sd_invalidate); + +static const mp_rom_map_elem_t picogame_stripdraw_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&sd_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&sd_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&sd_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&sd_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_always_dirty), MP_ROM_PTR(&sd_always_dirty_obj) }, + { MP_ROM_QSTR(MP_QSTR_invalidate), MP_ROM_PTR(&sd_invalidate_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_stripdraw_locals_dict, picogame_stripdraw_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_stripdraw_type, + MP_QSTR_StripDraw, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_stripdraw_make_new, + locals_dict, &picogame_stripdraw_locals_dict + ); diff --git a/shared-bindings/picogame/StripDraw.h b/shared-bindings/picogame/StripDraw.h new file mode 100644 index 00000000000..68c1506bacf --- /dev/null +++ b/shared-bindings/picogame/StripDraw.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +extern const mp_obj_type_t picogame_stripdraw_type; diff --git a/shared-bindings/picogame/Tilemap.c b/shared-bindings/picogame/Tilemap.c new file mode 100644 index 00000000000..955deef1b96 --- /dev/null +++ b/shared-bindings/picogame/Tilemap.c @@ -0,0 +1,247 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-module/picogame/Tilemap.h" + +//| class Tilemap: +//| """A grid of tile indices into a tileset `Bitmap`, where each bitmap frame +//| is one tile. Add it to a `Scene` as a background layer; setting tiles or +//| moving the map marks only the affected area dirty.""" +//| +//| def __init__(self, tileset: Bitmap, cols: int, rows: int) -> None: +//| """:param Bitmap tileset: the tile images, one frame per tile +//| :param int cols: map width in tiles +//| :param int rows: map height in tiles""" +//| ... +//| +static mp_obj_t picogame_tilemap_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_tileset, ARG_cols, ARG_rows }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_tileset, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_cols, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_rows, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + 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); + mp_obj_t tileset_obj = mp_arg_validate_type(args[ARG_tileset].u_obj, &picogame_bitmap_type, MP_QSTR_tileset); + // Cap cols/rows (not just floor): an unbounded cols*rows overflows the size_t map/orient + // allocation on a 32-bit port, desyncing alloc size from the index space (same family as the + // Bitmap width*frames guard). 1024 each -> product <= 1M, far below SIZE_MAX; oversize maps + // MemoryError at alloc (safe). + mp_int_t map_w = mp_arg_validate_int_range(args[ARG_cols].u_int, 1, 1024, MP_QSTR_cols); + mp_int_t map_h = mp_arg_validate_int_range(args[ARG_rows].u_int, 1, 1024, MP_QSTR_rows); + + mp_obj_t map_obj = mp_obj_new_bytearray_of_zeros((size_t)map_w * map_h); + mp_buffer_info_t mi; + mp_get_buffer_raise(map_obj, &mi, MP_BUFFER_RW); + + picogame_tilemap_obj_t *self = mp_obj_malloc(picogame_tilemap_obj_t, type); + self->tileset = MP_OBJ_TO_PTR(tileset_obj); + self->tileset_obj = tileset_obj; + self->map = mi.buf; + self->map_obj = map_obj; + self->orient = NULL; // orientation plane allocated lazily on first flipped/rotated tile + self->orient_obj = mp_const_none; + self->map_w = map_w; + self->map_h = map_h; + self->x = 0; + self->y = 0; + picogame_tilemap_dirty_reset(self); + return MP_OBJ_FROM_PTR(self); +} + +//| def get_tile(self, tx: int, ty: int) -> int: +//| """Return the tile index at (tx, ty). Out-of-range reads as 0.""" +//| ... +//| +static mp_obj_t picogame_tilemap_get_tile(mp_obj_t self_in, mp_obj_t tx_in, mp_obj_t ty_in) { + picogame_tilemap_obj_t *self = MP_OBJ_TO_PTR(self_in); + int tx = mp_obj_get_int(tx_in); + int ty = mp_obj_get_int(ty_in); + if (tx < 0 || ty < 0 || tx >= self->map_w || ty >= self->map_h) { + return MP_OBJ_NEW_SMALL_INT(0); + } + return MP_OBJ_NEW_SMALL_INT(self->map[(size_t)ty * self->map_w + tx]); +} +static MP_DEFINE_CONST_FUN_OBJ_3(picogame_tilemap_get_tile_obj, picogame_tilemap_get_tile); + +//| def set_tile( +//| self, +//| tx: int, +//| ty: int, +//| value: int, +//| *, +//| flip_x: bool = False, +//| flip_y: bool = False, +//| transpose: bool = False, +//| ) -> None: +//| """Set the tile at ``(tx, ty)`` and mark it dirty. The keyword flags orient +//| the tile at draw time; together they yield all 8 orientations (4 rotations +//| times mirror), so one stored tile can serve as several. The flags can +//| represent the remap table emitted by the ``png2picogame.py --dedup`` +//| tool. Out-of-range writes are ignored.""" +//| ... +//| +static mp_obj_t picogame_tilemap_set_tile(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_tx, ARG_ty, ARG_value, ARG_flip_x, ARG_flip_y, ARG_transpose }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_tx, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_ty, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_flip_x, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_flip_y, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_transpose, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + picogame_tilemap_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + int tx = args[ARG_tx].u_int; + int ty = args[ARG_ty].u_int; + if (tx < 0 || ty < 0 || tx >= self->map_w || ty >= self->map_h) { + return mp_const_none; + } + size_t off = (size_t)ty * self->map_w + tx; + uint8_t v = args[ARG_value].u_int & 0xff; + uint8_t o = 0; + if (args[ARG_flip_x].u_bool) { + o |= 1; + } + if (args[ARG_flip_y].u_bool) { + o |= 2; + } + if (args[ARG_transpose].u_bool) { + o |= 4; + } + // Allocate the orientation plane lazily - only maps that actually use flips/rotation + // pay the RAM (1 byte/cell). + if (o != 0 && self->orient == NULL) { + mp_obj_t ob = mp_obj_new_bytearray_of_zeros((size_t)self->map_w * self->map_h); + mp_buffer_info_t oi; + mp_get_buffer_raise(ob, &oi, MP_BUFFER_RW); + self->orient = oi.buf; + self->orient_obj = ob; + } + uint8_t old_o = self->orient ? self->orient[off] : 0; + if (self->map[off] != v || old_o != o) { + self->map[off] = v; + if (self->orient) { + self->orient[off] = o; + } + int tw = self->tileset ? self->tileset->width : 0; + int th = self->tileset ? self->tileset->height : 0; + int sx = self->x + tx * tw; + int sy = self->y + ty * th; + picogame_tilemap_dirty_union(self, sx, sy, sx + tw, sy + th); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_tilemap_set_tile_obj, 4, picogame_tilemap_set_tile); + +//| def move(self, x: int, y: int) -> None: +//| """Move the whole map to pixel (x, y).""" +//| ... +//| +static mp_obj_t picogame_tilemap_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + picogame_tilemap_obj_t *self = MP_OBJ_TO_PTR(self_in); + int nx = mp_obj_get_int(x_in), ny = mp_obj_get_int(y_in); + if (nx == self->x && ny == self->y) { + return mp_const_none; // unchanged -> avoid a full-tilemap repaint + } + int ox1, oy1, ox2, oy2; + picogame_tilemap_extent(self, &ox1, &oy1, &ox2, &oy2); + self->x = nx; + self->y = ny; + int nx1, ny1, nx2, ny2; + picogame_tilemap_extent(self, &nx1, &ny1, &nx2, &ny2); + picogame_tilemap_dirty_union(self, ox1, oy1, ox2, oy2); + picogame_tilemap_dirty_union(self, nx1, ny1, nx2, ny2); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(picogame_tilemap_move_obj, picogame_tilemap_move); + +//| def fill(self, value: int) -> None: +//| """Set every tile to ``value``.""" +//| ... +//| +static mp_obj_t picogame_tilemap_fill(mp_obj_t self_in, mp_obj_t value_in) { + picogame_tilemap_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint8_t v = mp_obj_get_int(value_in) & 0xff; + size_t total = (size_t)self->map_w * self->map_h; + for (size_t i = 0; i < total; i++) { + self->map[i] = v; + if (self->orient) { + self->orient[i] = 0; // a plain fill clears any per-cell orientation + } + } + int x1, y1, x2, y2; + picogame_tilemap_extent(self, &x1, &y1, &x2, &y2); + picogame_tilemap_dirty_union(self, x1, y1, x2, y2); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(picogame_tilemap_fill_obj, picogame_tilemap_fill); + +//| x: int +//| """Horizontal position of the map's top-left corner. (read-only) +//| +//| Set with :py:meth:`move`.""" +//| y: int +//| """Vertical position of the map's top-left corner. (read-only) +//| +//| Set with :py:meth:`move`.""" +//| cols: int +//| """Map width in tiles. (read-only)""" +//| rows: int +//| """Map height in tiles. (read-only)""" +//| +//| +static mp_obj_t tilemap_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_tilemap_obj_t *)MP_OBJ_TO_PTR(self_in))->x); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tilemap_get_x_obj, tilemap_get_x); +MP_PROPERTY_GETTER(tilemap_x_obj, (mp_obj_t)&tilemap_get_x_obj); + +static mp_obj_t tilemap_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_tilemap_obj_t *)MP_OBJ_TO_PTR(self_in))->y); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tilemap_get_y_obj, tilemap_get_y); +MP_PROPERTY_GETTER(tilemap_y_obj, (mp_obj_t)&tilemap_get_y_obj); + +static mp_obj_t tilemap_get_cols(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_tilemap_obj_t *)MP_OBJ_TO_PTR(self_in))->map_w); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tilemap_get_cols_obj, tilemap_get_cols); +MP_PROPERTY_GETTER(tilemap_cols_obj, (mp_obj_t)&tilemap_get_cols_obj); + +static mp_obj_t tilemap_get_rows(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_tilemap_obj_t *)MP_OBJ_TO_PTR(self_in))->map_h); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tilemap_get_rows_obj, tilemap_get_rows); +MP_PROPERTY_GETTER(tilemap_rows_obj, (mp_obj_t)&tilemap_get_rows_obj); + +static const mp_rom_map_elem_t picogame_tilemap_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_get_tile), MP_ROM_PTR(&picogame_tilemap_get_tile_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_tile), MP_ROM_PTR(&picogame_tilemap_set_tile_obj) }, + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&picogame_tilemap_move_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&picogame_tilemap_fill_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&tilemap_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&tilemap_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_cols), MP_ROM_PTR(&tilemap_cols_obj) }, + { MP_ROM_QSTR(MP_QSTR_rows), MP_ROM_PTR(&tilemap_rows_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_tilemap_locals_dict, picogame_tilemap_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_tilemap_type, + MP_QSTR_Tilemap, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_tilemap_make_new, + locals_dict, &picogame_tilemap_locals_dict + ); diff --git a/shared-bindings/picogame/Tilemap.h b/shared-bindings/picogame/Tilemap.h new file mode 100644 index 00000000000..9c1308f9eaa --- /dev/null +++ b/shared-bindings/picogame/Tilemap.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Tilemap.h" + +extern const mp_obj_type_t picogame_tilemap_type; diff --git a/shared-bindings/picogame/Triangles.c b/shared-bindings/picogame/Triangles.c new file mode 100644 index 00000000000..4401a1b9c66 --- /dev/null +++ b/shared-bindings/picogame/Triangles.c @@ -0,0 +1,102 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.Triangles: a retained screen-space triangle batch rasterised in C. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-bindings/picogame/Triangles.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +//| class Triangles: +//| """A retained triangle batch drawn as a `Scene` layer. The batch is +//| rasterized directly into each render strip; no per-strip Python runs and no +//| pixel buffer is held. Triangles layers always draw in screen coordinates and +//| ignore the scene's view offset. +//| +//| For each frame: project points with :py:func:`project`, write triangles +//| into the buffers in back-to-front order, set :py:attr:`count`, then call +//| :py:meth:`Scene.refresh`.""" +//| +//| def __init__(self, verts: ReadableBuffer, colors: ReadableBuffer) -> None: +//| """:param ~circuitpython_typing.ReadableBuffer verts: caller-owned buffer of +//| ``int16`` values, six per triangle: x0, y0, x1, y1, x2, y2. Refill it in +//| place each frame. +//| :param ~circuitpython_typing.ReadableBuffer colors: caller-owned buffer of +//| ``uint16`` colors, one per triangle""" +//| ... +//| +static mp_obj_t picogame_triangles_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + mp_arg_check_num(n_args, n_kw, 2, 2, false); + picogame_triangles_obj_t *self = mp_obj_malloc(picogame_triangles_obj_t, type); + mp_buffer_info_t vi, ci; + mp_get_buffer_raise(all_args[0], &vi, MP_BUFFER_READ); + mp_get_buffer_raise(all_args[1], &ci, MP_BUFFER_READ); + self->verts_obj = all_args[0]; + self->colors_obj = all_args[1]; + self->verts = (const int16_t *)vi.buf; + self->colors = (const uint16_t *)ci.buf; + size_t cap_v = vi.len / 12; // 6 int16 = 12 bytes per triangle + size_t cap_c = ci.len >> 1; + self->cap = (uint16_t)(cap_v < cap_c ? cap_v : cap_c); + self->count = 0; + picogame_dirty_reset(&self->dx1); + return MP_OBJ_FROM_PTR(self); +} + +//| count: int +//| """How many triangles of the batch draw on the next refresh, clamped to the +//| buffer capacity. Assigning marks the layer dirty for a full repaint.""" +//| +//| +static mp_obj_t tri_get_count(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_triangles_obj_t *)MP_OBJ_TO_PTR(self_in))->count); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tri_get_count_obj, tri_get_count); +static mp_obj_t tri_set_count(mp_obj_t self_in, mp_obj_t v) { + picogame_triangles_obj_t *self = MP_OBJ_TO_PTR(self_in); + int n = mp_obj_get_int(v); + if (n < 0) { + n = 0; + } + if (n > self->cap) { + n = self->cap; + } + self->count = (uint16_t)n; + picogame_dirty_union(&self->dx1, 0, 0, 32767, 32767); // clipped to the play rect later + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(tri_set_count_obj, tri_set_count); +MP_PROPERTY_GETSET(tri_count_obj, (mp_obj_t)&tri_get_count_obj, (mp_obj_t)&tri_set_count_obj); + +static const mp_rom_map_elem_t picogame_triangles_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&tri_count_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_triangles_locals_dict, picogame_triangles_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_triangles_type, + MP_QSTR_Triangles, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_triangles_make_new, + locals_dict, &picogame_triangles_locals_dict + ); diff --git a/shared-bindings/picogame/Triangles.h b/shared-bindings/picogame/Triangles.h new file mode 100644 index 00000000000..86175fcea51 --- /dev/null +++ b/shared-bindings/picogame/Triangles.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +extern const mp_obj_type_t picogame_triangles_type; diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c new file mode 100644 index 00000000000..1812c3860fa --- /dev/null +++ b/shared-bindings/picogame/__init__.c @@ -0,0 +1,1048 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame: 2D game engine bindings for the PicoPad and similar boards. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#include "shared-bindings/picogame/Display.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-bindings/picogame/StripDraw.h" +#include "shared-bindings/picogame/Triangles.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// --------------------------------------------------------------------------- +// Module-level functions +// --------------------------------------------------------------------------- + +// Cast a (possibly subclassed) BusDisplay arg to its native object, raising if it isn't one. +// Also accepts the pg.Display fast-DMA wrapper (unwrapped to its underlying busdisplay - the +// portable send path): any handle that identifies the panel works wherever a display is +// expected, so the same object a Scene renders through also works for render()/invert(). +// Without this, code holding the wrapper (custom setup, rgb444) worked on ports WITHOUT the +// fast backend and TypeError'd on ports WITH it. +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Resolve a Framebuffer, or a subclass of it, to the native object; NULL otherwise. +static picogame_framebuffer_obj_t *pg_fb_native(mp_obj_t obj) { + mp_obj_t nfb = mp_obj_cast_to_native_base(obj, &picogame_framebuffer_type); + if (nfb != MP_OBJ_NULL && mp_obj_is_type(nfb, &picogame_framebuffer_type)) { + return MP_OBJ_TO_PTR(nfb); + } + return NULL; +} +#endif + +static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + if (mp_obj_is_type(obj, &picogame_display_type)) { + return ((picogame_display_obj_t *)MP_OBJ_TO_PTR(obj))->display; + } + #endif + mp_obj_t native = mp_obj_cast_to_native_base(obj, &busdisplay_busdisplay_type); + // The cast yields MP_OBJ_NULL for a non-BusDisplay: validate the ORIGINAL object so the + // error names its real type (reading the type of NULL is a hard fault on RP2350). + if (native == MP_OBJ_NULL || !mp_obj_is_type(native, &busdisplay_busdisplay_type)) { + mp_arg_validate_type(obj, &busdisplay_busdisplay_type, MP_QSTR_display); + } + return MP_OBJ_TO_PTR(native); +} + +//| """Rendering core for games +//| +//| The `picogame` module composites sprites, tilemaps, drawing canvases, +//| particle layers, 3D triangle batches and immediate-mode callbacks into a +//| small reusable strip buffer and sends each strip to the display, so a full-screen game does not +//| need a full-screen buffer. A :py:class:`Scene` tracks what changed and +//| repaints only those regions when :py:meth:`Scene.refresh` is called. +//| +//| A scene targets a :py:class:`~busdisplay.BusDisplay`, an accelerated +//| :py:class:`Display` or a RAM :py:class:`Framebuffer`. picogame drives the +//| display itself, so it requires ``display.auto_refresh = False`` and cannot +//| show displayio groups on the same display at the same time. +//| +//| Most programs start with :py:class:`Scene`, :py:class:`Sprite` and +//| :py:class:`Bitmap`. +//| +//| .. note:: +//| This module is the engine's rendering and compute core and is fully +//| usable on its own. The pure-Python `picogame helper libraries +//| `_ +//| (``picogame_game``, ``picogame_ray`` and others) build a complete game +//| framework on top of it: display, input and audio setup that adapts to +//| the board, game-loop timing, sprite pools and collision helpers, +//| animation, text, HUD and menus, sound effects and music, visual +//| effects, saved games, scene loading and pseudo-3D cameras. A desktop +//| simulator, asset-conversion tools, examples and tutorials live in the +//| `picogame repository `_, with +//| documentation at `picogame.makerclass.cz +//| `_. +//| +//| Example:: +//| +//| import array +//| import board +//| import time +//| +//| import picogame +//| +//| display = board.DISPLAY +//| display.auto_refresh = False +//| +//| size = display.width * picogame.STRIP_H * 2 +//| scene = picogame.Scene(display, bytearray(size), bytearray(size)) +//| +//| # One solid white 8x8 frame. +//| white = picogame.rgb565(255, 255, 255) +//| bitmap = picogame.Bitmap(array.array("H", [white] * 64), 8, 8) +//| player = scene.add(picogame.Sprite(bitmap, x=0, y=display.height // 2)) +//| +//| while True: +//| player.x = (player.x + 1) % display.width +//| scene.refresh() +//| time.sleep(0.02) +//| +//| This moves a white square across the screen, repainting only the pixels +//| that changed each frame.""" +//| +//| RGB565: int +//| """16-bit color bitmap format (transfer byte order).""" +//| PAL8: int +//| """8-bit paletted bitmap format.""" +//| +//| STRIP_H: int +//| """Recommended render-strip height in rows for this build. Sizing a `Scene` +//| strip buffer as ``display.width * STRIP_H * 2`` bytes yields strips this +//| tall.""" +//| +//| FPU: int +//| """``1`` when `project` uses hardware floating point (its buffers are +//| ``float32``), ``0`` when it uses signed 16.16 fixed-point ``int32``.""" +//| +//| API_LEVEL: int +//| """Version of the picogame API. Helper libraries compare this value against +//| the API level they target.""" +//| +//| RGB444_SUPPORTED: bool +//| """Whether `Display` supports ``rgb444=True`` on this board.""" +//| +//| FAST_DISPLAY_SUPPORTED: bool +//| """Whether the accelerated `Display` backend is available on this board.""" +//| +//| FRAMEBUFFER_SUPPORTED: bool +//| """Whether `Framebuffer` is available on this board.""" +//| +//| +//| def rgb565(r: int, g: int, b: int) -> int: +//| """Build an RGB565 color in the display's transfer byte order from 8-bit +//| components. Every color integer in this module is such a value.""" +//| ... +//| +//| +static mp_obj_t picogame_rgb565(mp_obj_t r_in, mp_obj_t g_in, mp_obj_t b_in) { + int r = mp_obj_get_int(r_in) & 0xff; + int g = mp_obj_get_int(g_in) & 0xff; + int b = mp_obj_get_int(b_in) & 0xff; + uint16_t c = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3); + uint16_t wire = (uint16_t)((c >> 8) | (c << 8)); + return MP_OBJ_NEW_SMALL_INT(wire); +} +static MP_DEFINE_CONST_FUN_OBJ_3(picogame_rgb565_obj, picogame_rgb565); + +//| def invert( +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], on: bool +//| ) -> None: +//| """Enable or disable color inversion. +//| +//| Bus displays receive the controller's inversion command (INVON/INVOFF), which +//| takes effect immediately and sends no pixel data; the controller must support +//| it (ST7789 and ST7735 do). A `Framebuffer` target is instead inverted during +//| composition, starting with the next refresh.""" +//| ... +//| +//| +static mp_obj_t picogame_invert(mp_obj_t display_in, mp_obj_t on_in) { + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + // A Framebuffer target (RP2350 DVI, the WASM playground) has no hardware INVON/INVOFF - + // emulate the flash by XORing the composite (mirrors the Scene/render Framebuffer handling). + { + mp_obj_t nfb = mp_obj_cast_to_native_base(display_in, &picogame_framebuffer_type); + if (nfb != MP_OBJ_NULL && mp_obj_is_type(nfb, &picogame_framebuffer_type)) { + picogame_fb_set_invert(mp_obj_is_true(on_in)); + return mp_const_none; + } + } + #endif + picogame_set_invert(pg_get_display(display_in), mp_obj_is_true(on_in)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(picogame_invert_obj, picogame_invert); + +//| def render( +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], +//| layers: List[Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]], +//| buffer: Optional[WriteableBuffer], +//| x0: int, +//| y0: int, +//| x1: int, +//| y1: int, +//| *, +//| background: int = 0, +//| ) -> None: +//| """Render ``layers`` into the screen region from ``(x0, y0)`` up to, but not +//| including, ``(x1, y1)``, and push it to ``display``, without a `Scene`. +//| +//| :param display: the render target +//| :param layers: layers of any kind, drawn bottom to top +//| :param ~circuitpython_typing.WriteableBuffer buffer: a reusable strip buffer of +//| at least ``(x1 - x0) * 2`` bytes; ignored (may be `None`) on a +//| `Framebuffer` target +//| :param int x0: left edge of the region +//| :param int y0: top edge of the region +//| :param int x1: right edge of the region (exclusive) +//| :param int y1: bottom edge of the region (exclusive) +//| :param int background: color the region is cleared to first""" +//| ... +//| +//| + +// Map a layer object to its PICOGAME_KIND_*, or raise the one shared TypeError. Both +// Scene.add() and pg.render() classify through here (one type chain, one message). +uint8_t picogame_kind_of(mp_obj_t o) { + if (mp_obj_is_type(o, &picogame_sprite_type)) { + return PICOGAME_KIND_SPRITE; + } + if (mp_obj_is_type(o, &picogame_stripdraw_type)) { + return PICOGAME_KIND_STRIPDRAW; + } + if (mp_obj_is_type(o, &picogame_tilemap_type)) { + return PICOGAME_KIND_TILEMAP; + } + if (mp_obj_is_type(o, &picogame_particles_type)) { + return PICOGAME_KIND_PARTICLES; + } + if (mp_obj_is_type(o, &picogame_canvas_type)) { + return PICOGAME_KIND_CANVAS; + } + if (mp_obj_is_type(o, &picogame_triangles_type)) { + return PICOGAME_KIND_TRIANGLES; + } + mp_arg_error_invalid(MP_QSTR_item); // the accepted layer types are listed in the docs +} + +static mp_obj_t picogame_render_fun(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_display, ARG_layers, ARG_buffer, ARG_x0, ARG_y0, ARG_x1, ARG_y1, ARG_background }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_display, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_layers, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x0, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y0, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_background, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + }; + 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); + + // Accept a picogame.Framebuffer (RAM scanout buffer) as the target too, when built + // in: immediate render composites straight into it (no strip buffer, no bus), so + // pg.render(board.DISPLAY, ...) works when board.DISPLAY is a Framebuffer - the HUD / + // HudBar / immediate-mode path on scanout-buffer platforms. Mirrors the Scene change. + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + picogame_framebuffer_obj_t *fbt = + pg_fb_native(args[ARG_display].u_obj); + busdisplay_busdisplay_obj_t *display = fbt ? NULL : pg_get_display(args[ARG_display].u_obj); + #else + busdisplay_busdisplay_obj_t *display = pg_get_display(args[ARG_display].u_obj); + #endif + + size_t n = 0; + mp_obj_t *items; + mp_obj_get_array(args[ARG_layers].u_obj, &n, &items); + + // Classify items into layer kinds. All-Sprite lists stay on the NULL-kinds fast path (no alloc - + // the common case). Any non-Sprite layer (StripDraw/Canvas/Tilemap/Particles) builds a small kinds + // array so immediate render uses the SAME multi-layer blitter the Scene does - e.g. a StripDraw + // composited straight into the strip with `view.text()` = 0-RAM immediate HUD / text screen. + uint8_t kbuf[16]; + uint8_t *kinds = NULL; + for (size_t i = 0; i < n; i++) { + if (!mp_obj_is_type(items[i], &picogame_sprite_type)) { + kinds = (n <= MP_ARRAY_SIZE(kbuf)) ? kbuf : m_new(uint8_t, n); + break; + } + } + if (kinds != NULL) { + for (size_t i = 0; i < n; i++) { + // (an unknown type raises from kind_of; the GC reclaims a heap `kinds`) + kinds[i] = picogame_kind_of(items[i]); + } + } + + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + if (fbt != NULL) { + // Framebuffer target: composite the region straight into it (no strip buffer, no + // bus). Same compositor as the SPI path; re-raise a latched StripDraw exception. + mp_obj_t exc = picogame_render_framebuffer(fbt->fb, fbt->width, fbt->height, fbt->fmt, + fbt->scratch, fbt->scratch_rows, + items, kinds, n, + args[ARG_x0].u_int, args[ARG_y0].u_int, args[ARG_x1].u_int, args[ARG_y1].u_int, + args[ARG_background].u_int, 0, 0); + if (kinds != NULL && n > MP_ARRAY_SIZE(kbuf)) { + m_del(uint8_t, kinds, n); + } + if (exc != MP_OBJ_NULL) { + nlr_raise(MP_OBJ_TO_PTR(exc)); + } + return mp_const_none; + } + #endif + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); + + if (kinds == NULL) { + picogame_render(display, items, n, + (uint16_t *)bufinfo.buf, bufinfo.len / 2, + args[ARG_x0].u_int, args[ARG_y0].u_int, args[ARG_x1].u_int, args[ARG_y1].u_int, + args[ARG_background].u_int); + } else { + picogame_render_region(display, items, kinds, n, + (uint16_t *)bufinfo.buf, bufinfo.len / 2, + args[ARG_x0].u_int, args[ARG_y0].u_int, args[ARG_x1].u_int, args[ARG_y1].u_int, + args[ARG_background].u_int, 0, 0); + if (n > MP_ARRAY_SIZE(kbuf)) { + m_del(uint8_t, kinds, n); + } + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_render_obj, 7, picogame_render_fun); + +//| def collide( +//| x1: int, y1: int, x2: int, y2: int, ax1: int, ay1: int, ax2: int = ..., ay2: int = ... +//| ) -> bool: +//| """Return whether an inclusive rectangle overlaps another rectangle or contains +//| a point. Both corners are part of the rectangle, so touching edges count as an +//| overlap. +//| +//| With six arguments, test rectangle ``(x1, y1, x2, y2)`` against the point +//| ``(ax1, ay1)``; with eight, test it against the rectangle +//| ``(ax1, ay1, ax2, ay2)``. +//| +//| Unlike the pixel regions used by `render`, whose upper bounds are excluded, +//| collision bounds are inclusive.""" +//| ... +//| +//| +static mp_obj_t picogame_collide(size_t n_args, const mp_obj_t *args) { + int x1 = mp_obj_get_int(args[0]); + int y1 = mp_obj_get_int(args[1]); + int x2 = mp_obj_get_int(args[2]); + int y2 = mp_obj_get_int(args[3]); + bool hit; + if (n_args == 8) { + int bx1 = mp_obj_get_int(args[4]); + int by1 = mp_obj_get_int(args[5]); + int bx2 = mp_obj_get_int(args[6]); + int by2 = mp_obj_get_int(args[7]); + hit = (x1 <= bx2) && (x2 >= bx1) && (y1 <= by2) && (y2 >= by1); + } else if (n_args == 6) { + int px = mp_obj_get_int(args[4]); + int py = mp_obj_get_int(args[5]); + hit = (px >= x1) && (px <= x2) && (py >= y1) && (py <= y2); + } else { + mp_raise_TypeError(MP_ERROR_TEXT("argument num/types mismatch")); + } + return mp_obj_new_bool(hit); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_collide_obj, 6, 8, picogame_collide); + +// ---- procedural value-noise in C (the desktop simulator sim/picogame.py mirrors it) ---- +// The CANONICAL implementation is FIXED-POINT (Q16.16 coords, Q0.16 values), exposed +// under the plain names value2d/value1d/fbm2d/fbm1d (see further down). It benchmarked +// ~1.8x faster than float on-device (0.649 s vs 1.186 s / 5000 fbm2d), so the float +// version was retired (2026-06-18) to free flash for future engine features. +// The float reference is preserved but DISABLED in the `#if 0` below (cf. PicoLibSDK's +// own Noise2D, which is likewise float) - revive by flipping it to `#if 1` and pointing +// the module table at the *_obj names instead of the *_fx_obj ones. +#if 0 // float reference implementation - superseded by the fixed-point path below +static inline float pg_nhash(int32_t x, int32_t y, int32_t seed) { + uint32_t h = (uint32_t)x * 374761393u + (uint32_t)y * 668265263u + (uint32_t)seed * 362437u; + h = (h ^ (h >> 13)) * 1274126177u; + h = h ^ (h >> 16); + return (float)(h & 0xFFFFu) / 65535.0f; +} +static inline float pg_nsmooth(float t) { + return t * t * (3.0f - 2.0f * t); +} +static inline int32_t pg_ifloor(float x) { + int32_t i = (int32_t)x; + return (x < (float)i) ? i - 1 : i; +} +static float pg_value2d(float x, float y, int32_t seed) { + int32_t xi = pg_ifloor(x), yi = pg_ifloor(y); + float xf = x - (float)xi, yf = y - (float)yi; + float a = pg_nhash(xi, yi, seed), b = pg_nhash(xi + 1, yi, seed); + float c = pg_nhash(xi, yi + 1, seed), d = pg_nhash(xi + 1, yi + 1, seed); + float u = pg_nsmooth(xf), v = pg_nsmooth(yf); + return (a * (1.0f - u) + b * u) * (1.0f - v) + (c * (1.0f - u) + d * u) * v; +} +static float pg_value1d(float x, int32_t seed) { + int32_t xi = pg_ifloor(x); + float xf = x - (float)xi; + float a = pg_nhash(xi, 0, seed), b = pg_nhash(xi + 1, 0, seed); + return a + (b - a) * pg_nsmooth(xf); +} + +//| def value2d(x: float, y: float, *, seed: int = 0) -> float: +//| """Smooth 2-D value noise in ``0..1``.""" +//| ... +//| +//| +static mp_obj_t picogame_value2d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_seed, MP_ARG_INT, {.u_int = 0}} }; + mp_arg_val_t a[3]; + mp_arg_parse_all(n_args, pos, kw, 3, spec, a); + return mp_obj_new_float(pg_value2d(mp_obj_get_float(a[0].u_obj), mp_obj_get_float(a[1].u_obj), a[2].u_int)); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_value2d_obj, 2, picogame_value2d); + +//| def value1d(x: float, *, seed: int = 0) -> float: +//| """Smooth 1-D value noise in ``0..1``.""" +//| ... +static mp_obj_t picogame_value1d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_seed, MP_ARG_INT, {.u_int = 0}} }; + mp_arg_val_t a[2]; + mp_arg_parse_all(n_args, pos, kw, 2, spec, a); + return mp_obj_new_float(pg_value1d(mp_obj_get_float(a[0].u_obj), a[1].u_int)); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_value1d_obj, 1, picogame_value1d); +#endif // float value2d / value1d + +// Shared arg spec for both fbm2d (disabled float) and fbm2d_fx (active fixed-point). +static const mp_arg_t pg_fbm2d_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_octaves, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 4} }, + { MP_QSTR_seed, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_lacunarity, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_gain, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, +}; + +#if 0 // float reference fbm - superseded by the fixed-point path below +//| def fbm2d(x: float, y: float, *, octaves: int = 4, seed: int = 0, lacunarity: float = 2.0, gain: float = 0.5) -> float: +//| """Fractal (fBm) 2-D noise in ``0..1``: ``octaves`` layers of :py:func:`value2d`, each +//| ``lacunarity`` times finer and ``gain`` times weaker than the last.""" +//| ... +static mp_obj_t picogame_fbm2d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + mp_arg_val_t a[6]; + mp_arg_parse_all(n_args, pos, kw, 6, pg_fbm2d_args, a); + float x = mp_obj_get_float(a[0].u_obj), y = mp_obj_get_float(a[1].u_obj); + int octaves = a[2].u_int; + int32_t seed = a[3].u_int; + float lac = (a[4].u_obj == MP_OBJ_NULL) ? 2.0f : mp_obj_get_float(a[4].u_obj); + float gain = (a[5].u_obj == MP_OBJ_NULL) ? 0.5f : mp_obj_get_float(a[5].u_obj); + float total = 0.0f, amp = 1.0f, freq = 1.0f, norm = 0.0f; + for (int i = 0; i < octaves; i++) { + total += amp * pg_value2d(x * freq, y * freq, seed); + norm += amp; + amp *= gain; + freq *= lac; + } + return mp_obj_new_float(norm > 0.0f ? total / norm : 0.0f); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm2d_obj, 2, picogame_fbm2d); + +//| def fbm1d(x: float, *, octaves: int = 4, seed: int = 0, lacunarity: float = 2.0, gain: float = 0.5) -> float: +//| """Fractal (fBm) 1-D noise in ``0..1``: ``octaves`` layers of +//| :py:func:`value1d`, each ``lacunarity`` times finer and ``gain`` times +//| weaker than the last.""" +//| ... +//| +//| +static mp_obj_t picogame_fbm1d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_octaves, MP_ARG_INT, {.u_int = 4}}, {MP_QSTR_seed, MP_ARG_INT, {.u_int = 0}}, + {MP_QSTR_lacunarity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_gain, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}} }; + mp_arg_val_t a[5]; + mp_arg_parse_all(n_args, pos, kw, 5, spec, a); + float x = mp_obj_get_float(a[0].u_obj); + int octaves = a[1].u_int; + int32_t seed = a[2].u_int; + float lac = (a[3].u_obj == MP_OBJ_NULL) ? 2.0f : mp_obj_get_float(a[3].u_obj); + float gain = (a[4].u_obj == MP_OBJ_NULL) ? 0.5f : mp_obj_get_float(a[4].u_obj); + float total = 0.0f, amp = 1.0f, freq = 1.0f, norm = 0.0f; + for (int i = 0; i < octaves; i++) { + total += amp * pg_value1d(x * freq, seed); + norm += amp; + amp *= gain; + freq *= lac; + } + return mp_obj_new_float(norm > 0.0f ? total / norm : 0.0f); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm1d_obj, 1, picogame_fbm1d); +#endif // float fbm2d / fbm1d + +// ---- fixed-point (Q16.16 coords, Q0.16 values) noise: the CANONICAL value-noise impl, +// exposed under the plain names value2d/value1d/fbm2d/fbm1d. The inner math is integer +// (float only at the Python boundary); ~1.8x faster than the retired float path. ---- +static inline uint32_t pg_nhash_raw(int32_t x, int32_t y, int32_t seed) { + uint32_t h = (uint32_t)x * 374761393u + (uint32_t)y * 668265263u + (uint32_t)seed * 362437u; + h = (h ^ (h >> 13)) * 1274126177u; + return (h ^ (h >> 16)) & 0xFFFFu; // Q0.16 in [0,1) +} +static inline uint32_t pg_smooth16(uint32_t t) { // t,result Q0.16: t*t*(3-2t) + uint32_t t2 = (t * t) >> 16; + uint32_t e = (3u << 16) - 2u * t; + return (uint32_t)(((uint64_t)t2 * e) >> 16); +} +static inline uint32_t pg_lerp16(uint32_t a, uint32_t b, uint32_t u) { + return (uint32_t)((int32_t)a + (int32_t)(((int64_t)((int32_t)b - (int32_t)a) * (int32_t)u) >> 16)); +} +static uint32_t pg_value2d_fx(int32_t X, int32_t Y, int32_t seed) { // X,Y Q16.16 -> Q0.16 + int32_t xi = X >> 16, yi = Y >> 16; + uint32_t xf = (uint32_t)(X - (xi << 16)), yf = (uint32_t)(Y - (yi << 16)); + uint32_t a = pg_nhash_raw(xi, yi, seed), b = pg_nhash_raw(xi + 1, yi, seed); + uint32_t c = pg_nhash_raw(xi, yi + 1, seed), d = pg_nhash_raw(xi + 1, yi + 1, seed); + uint32_t u = pg_smooth16(xf), v = pg_smooth16(yf); + return pg_lerp16(pg_lerp16(a, b, u), pg_lerp16(c, d, u), v); +} +// (1-D value noise == the 2-D sampler at Y=0, bit for bit: v = smooth16(0) = 0 makes the +// outer lerp return its first argument, which is exactly lerp(hash(xi,0), hash(xi+1,0), u). +// So the 1-D entry points below just call pg_value2d_fx(X, 0, seed) - no separate kernel.) +#define PG_Q16(f) ((int32_t)((f) * 65536.0f)) + +static mp_obj_t picogame_value2d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_seed, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0}} }; + mp_arg_val_t a[3]; + mp_arg_parse_all(n_args, pos, kw, 3, spec, a); + int32_t v = pg_value2d_fx(PG_Q16(mp_obj_get_float(a[0].u_obj)), PG_Q16(mp_obj_get_float(a[1].u_obj)), a[2].u_int); + return mp_obj_new_float((float)v * (1.0f / 65536.0f)); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_value2d_fx_obj, 2, picogame_value2d_fx); + +static mp_obj_t picogame_value1d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_seed, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0}} }; + mp_arg_val_t a[2]; + mp_arg_parse_all(n_args, pos, kw, 2, spec, a); + int32_t v = pg_value2d_fx(PG_Q16(mp_obj_get_float(a[0].u_obj)), 0, a[1].u_int); + return mp_obj_new_float((float)v * (1.0f / 65536.0f)); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_value1d_fx_obj, 1, picogame_value1d_fx); + +// Shared fBm octave accumulator (the 1-D entry passes Y=0; sy is then 0 every octave, +// which the value sampler maps to the exact 1-D lattice - see the note above). +static mp_obj_t pg_fbm_eval(int32_t X, int32_t Y, int octaves, int32_t seed, + const mp_arg_val_t *lac, const mp_arg_val_t *gain) { + int32_t lacq = (lac->u_obj == MP_OBJ_NULL) ? (2 << 16) : PG_Q16(mp_obj_get_float(lac->u_obj)); + int32_t gainq = (gain->u_obj == MP_OBJ_NULL) ? (1 << 15) : PG_Q16(mp_obj_get_float(gain->u_obj)); + int32_t amp = 1 << 16, freq = 1 << 16; + int64_t total = 0, norm = 0; + for (int i = 0; i < octaves; i++) { + int32_t sx = (int32_t)(((int64_t)X * freq) >> 16), sy = (int32_t)(((int64_t)Y * freq) >> 16); + total += ((int64_t)amp * pg_value2d_fx(sx, sy, seed)) >> 16; + norm += amp; + amp = (int32_t)(((int64_t)amp * gainq) >> 16); + freq = (int32_t)(((int64_t)freq * lacq) >> 16); + } + return mp_obj_new_float(norm ? (float)total / (float)norm : 0.0f); +} + +static mp_obj_t picogame_fbm2d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + mp_arg_val_t a[6]; + mp_arg_parse_all(n_args, pos, kw, 6, pg_fbm2d_args, a); + return pg_fbm_eval(PG_Q16(mp_obj_get_float(a[0].u_obj)), PG_Q16(mp_obj_get_float(a[1].u_obj)), + a[2].u_int, a[3].u_int, &a[4], &a[5]); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm2d_fx_obj, 2, picogame_fbm2d_fx); + +static mp_obj_t picogame_fbm1d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_octaves, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 4}}, {MP_QSTR_seed, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0}}, + {MP_QSTR_lacunarity, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_gain, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL}} }; + mp_arg_val_t a[5]; + mp_arg_parse_all(n_args, pos, kw, 5, spec, a); + return pg_fbm_eval(PG_Q16(mp_obj_get_float(a[0].u_obj)), 0, + a[1].u_int, a[2].u_int, &a[3], &a[4]); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm1d_fx_obj, 1, picogame_fbm1d_fx); + + +//| def project( +//| cam: ReadableBuffer, +//| pts: ReadableBuffer, +//| n: int, +//| out_sx: WriteableBuffer, +//| out_sy: WriteableBuffer, +//| ) -> None: +//| """Batch-project ``n`` 3D world points to screen coordinates. +//| +//| When :py:data:`FPU` is ``1``, ``cam`` and ``pts`` hold ``float32`` elements; +//| otherwise they hold signed 16.16 fixed-point ``int32`` elements. +//| +//| :param ~circuitpython_typing.ReadableBuffer cam: 15 camera parameters, in order: +//| eye x/y/z, right x/z (the camera cannot roll, so right has no y +//| component), up x/y/z, forward x/y/z, focal length, screen center x/y, +//| near-plane distance +//| :param ~circuitpython_typing.ReadableBuffer pts: ``3 * n`` world coordinates +//| (x, y, z per point) +//| :param int n: number of points +//| :param ~circuitpython_typing.WriteableBuffer out_sx: at least ``n`` ``int16`` +//| values; receives screen x, or the sentinel ``-32768`` for a point behind +//| the near plane +//| :param ~circuitpython_typing.WriteableBuffer out_sy: at least ``n`` ``int16`` +//| values; receives screen y, or ``-32768`` for a point behind the near plane""" +//| ... +//| +// project(cam, pts, n, out_sx, out_sy) - batch perspective projection of `n` 3D points to screen. +// cam = 15 camera params: ex,ey,ez, rx,rz, ux,uy,uz, fx,fy,fz, focal, cx0, cy0, near +// pts = n*3 world coords (x,y,z per point) +// out_sx/out_sy = int16 screen coords; a point behind the near plane gets sentinel -32768 +// On an FPU board (CIRCUITPY_PICOGAME_FPU) cam/pts are float32; else they are 16.16 fixed int32. +// This is the shared hot path for blocky pseudo-3D (project the 8 corners of each box, then fill). +static mp_obj_t picogame_project(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t ci, pi, xi, yi; + mp_get_buffer_raise(args[0], &ci, MP_BUFFER_READ); + mp_get_buffer_raise(args[1], &pi, MP_BUFFER_READ); + int n = mp_obj_get_int(args[2]); + mp_get_buffer_raise(args[3], &xi, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[4], &yi, MP_BUFFER_WRITE); + int16_t *osx = xi.buf; + int16_t *osy = yi.buf; + if (n > (int)(xi.len >> 1)) { + n = (int)(xi.len >> 1); + } + #if CIRCUITPY_PICOGAME_FPU + const float *cam = ci.buf; + const float *pts = pi.buf; + float ex = cam[0], ey = cam[1], ez = cam[2]; + float rx = cam[3], rz = cam[4]; + float ux = cam[5], uy = cam[6], uz = cam[7]; + float fx = cam[8], fy = cam[9], fz = cam[10]; + float focal = cam[11], cx0 = cam[12], cy0 = cam[13], near = cam[14]; + for (int i = 0; i < n; i++) { + float X = pts[i * 3] - ex, Y = pts[i * 3 + 1] - ey, Z = pts[i * 3 + 2] - ez; + float cz = X * fx + Y * fy + Z * fz; + if (cz < near) { + osx[i] = -32768; + osy[i] = -32768; + continue; + } + float k = focal / cz; // hardware divide on an FPU part + osx[i] = (int16_t)(cx0 + (X * rx + Z * rz) * k); + osy[i] = (int16_t)(cy0 - (X * ux + Y * uy + Z * uz) * k); + } + #else + const int32_t *cam = ci.buf; // all values 16.16 + const int32_t *pts = pi.buf; + int32_t ex = cam[0], ey = cam[1], ez = cam[2]; + int32_t rx = cam[3], rz = cam[4]; + int32_t ux = cam[5], uy = cam[6], uz = cam[7]; + int32_t fx = cam[8], fy = cam[9], fz = cam[10]; + int32_t focal = cam[11], cx0 = cam[12], cy0 = cam[13], near = cam[14]; + // Full-precision Q16 dot products (int64 mul per term). A Q8-prescaled-basis/MULS variant was + // ~30% faster, but its error grows with |coord| (~0.2%/axis) and k = focal/cz AMPLIFIES it near + // the near plane - host-measured 23-34 px warps on close fly-bys at a file-browser world scale + // (walls visibly broke). Correctness first: Q16 keeps the worst error a few px at any cz >= near, + // for coords up to +-32k units; still ~4-5x faster than the same math in Python on the M0+. + #define FMUL(a, b) ((int32_t)(((int64_t)(a) * (b)) >> 16)) + for (int i = 0; i < n; i++) { + int32_t X = pts[i * 3] - ex, Y = pts[i * 3 + 1] - ey, Z = pts[i * 3 + 2] - ez; + int32_t cz = FMUL(X, fx) + FMUL(Y, fy) + FMUL(Z, fz); + if (cz < near) { + osx[i] = -32768; + osy[i] = -32768; + continue; + } + // focal/cz in 16.16. A 32-bit divide (focal<<8 = Q24, cz>>8 = Q8 -> Q16) is ~4x cheaper than + // an int64 divide on the M0+ (no HW divide) and the lost cz precision costs <0.02 px (host- + // measured). Needs FOCAL < ~250 (focal<<8 in uint32) and near >= 1/256 (cz>>8 nonzero). + int32_t k = (int32_t)(((uint32_t)focal << 8) / (uint32_t)(cz >> 8)); + int32_t rr = FMUL(X, rx) + FMUL(Z, rz); + int32_t uu = FMUL(X, ux) + FMUL(Y, uy) + FMUL(Z, uz); + osx[i] = (int16_t)((cx0 + FMUL(rr, k)) >> 16); + osy[i] = (int16_t)((cy0 - FMUL(uu, k)) >> 16); + } +#undef FMUL + #endif + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_project_obj, 5, 5, picogame_project); + + + +//| def raycast( +//| map: ReadableBuffer, +//| mw: int, +//| mh: int, +//| posx: int, +//| posy: int, +//| lrx: int, +//| lry: int, +//| srx: int, +//| sry: int, +//| sh: int, +//| stride: int, +//| ncols: int, +//| wcolors: ReadableBuffer, +//| top: WriteableBuffer, +//| bot: WriteableBuffer, +//| col: WriteableBuffer, +//| dist: WriteableBuffer, +//| runs: Optional[WriteableBuffer] = None, +//| ) -> Optional[int]: +//| """Cast one frame of wall-finding rays across the screen columns of a +//| grid-map view. A low-level interface used by the ``picogame_ray`` helper, +//| which computes these inputs. +//| +//| All fixed-point arguments are signed 16.16 integers. +//| +//| :param ~circuitpython_typing.ReadableBuffer map: at least ``mw * mh`` wall-type +//| bytes, row-major; 0 is empty +//| :param int mw: map width in cells +//| :param int mh: map height in cells +//| :param int posx: camera x position (fixed-point) +//| :param int posy: camera y position (fixed-point) +//| :param int lrx: x of the column-0 ray direction (fixed-point) +//| :param int lry: y of the column-0 ray direction (fixed-point) +//| :param int srx: per-column ray step x (fixed-point) +//| :param int sry: per-column ray step y (fixed-point) +//| :param int sh: screen height in pixels +//| :param int stride: pixel width of one column +//| :param int ncols: number of columns to cast +//| :param ~circuitpython_typing.ReadableBuffer wcolors: two ``uint16`` colors per +//| wall type: near face at ``[type * 2]``, side face at ``[type * 2 + 1]`` +//| :param ~circuitpython_typing.WriteableBuffer top: at least ``ncols`` ``uint16`` +//| values; receives each column's wall top row +//| :param ~circuitpython_typing.WriteableBuffer bot: at least ``ncols`` ``uint16`` +//| values; receives each column's wall bottom row +//| :param ~circuitpython_typing.WriteableBuffer col: at least ``ncols`` ``uint16`` +//| values; receives each column's wall color +//| :param ~circuitpython_typing.WriteableBuffer dist: at least ``ncols`` ``int32`` +//| values; receives each column's perpendicular distance (fixed-point) +//| :param ~circuitpython_typing.WriteableBuffer runs: optional; at least +//| ``5 * ncols`` ``uint16`` values, laid out as five ``ncols``-long planes +//| (x0s, x1s, tops, bots, colors). When given, adjacent equal columns are +//| merged into wall runs suitable for :py:meth:`Canvas.vspans` and the run +//| count is returned; otherwise `None` is returned.""" +//| ... +//| +// C DDA wall raycaster for picogame_ray.Raycaster - INTEGER ONLY (16.16 fixed-point, no FPU; the paint, +// temporal invalidate, pose-cache and billboard math stay in Python; Python does the once-per-frame +// trig and passes Q16 ray params). map: read-only bytes, mw*mh wall types (0 = empty). pos*, l*x/l*y +// (leftRay, column 0), s*x/s*y (rayStep per column) are all 16.16. wcolors: uint16[(maxtype+1)*2] - +// [t*2] near, [t*2+1] side colour. top/bot/col: uint16 write buffers (len>=ncols); dist: int32 write +// buffer (perpendicular distance, 16.16). The int64 divides/muls are ONLY the per-column setup +// (O(ncols)); the DDA step loop is pure 32-bit. Mirrors the Python float fallback closely. +// Optional arg 17 (runs - ONE uint16 write buffer, len>=5*ncols, laid out as five ncols-long +// planes [x0s | x1s | tops | bots | colors]): also emit the RLE-MERGED wall runs (adjacent equal +// columns fused; x in PIXELS = column*stride) and return the run count. The planes feed +// Canvas.vspans directly as memoryview slices. This hoists picogame_ray's per-frame Python merge +// loop into the same C pass (measured 2-6.5 ms/frame of interpreted merge at stride=1 on RP2040). +// Callers clamp the LAST run's x1 to the screen width (stride rounding can overshoot by = 18) { // run outputs requested + mp_buffer_info_t q; + mp_get_buffer_raise(args[17], &q, MP_BUFFER_WRITE); + int cap = (int)(q.len / 10); // five uint16 planes + if (ncols > cap) { + ncols = cap; // never write past the run planes + } + r0 = q.buf; + r1 = r0 + cap; + rt = r1 + cap; + rb = rt + cap; + rcol = rb + cap; + } + const uint8_t *map = mi.buf; + const uint16_t *wc = wi.buf; + int wc_types = (int)(wi.len >> 2); + uint16_t *top = ti.buf; + uint16_t *bot = bi.buf; + uint16_t *col = ci.buf; + int32_t *dist_out = di.buf; // perpendicular distance, 16.16 + int half = sh >> 1; + int imapx0 = posx >> 16; + int imapy0 = posy >> 16; + int32_t fracx = posx & 0xFFFF; // fractional part of pos, 16.16 + int32_t fracy = posy & 0xFFFF; + const int32_t DD_CAP = (int32_t)1 << 24; // cap deltaDist so a 64-step accumulation stays in int32 + if (ncols > (int)(ti.len >> 1)) { + ncols = (int)(ti.len >> 1); + } + for (int c = 0; c < ncols; c++) { + int mapx = imapx0; + int mapy = imapy0; + int32_t ax = rdx < 0 ? -rdx : rdx; + int32_t ay = rdy < 0 ? -rdy : rdy; + // deltaDist = |1/rayDir| in 16.16 = (1<<32)/|rayDir_q16| (int64; per-column setup, not per-step) + int64_t ddx64 = ax ? (((int64_t)1 << 32) / ax) : (int64_t)DD_CAP; + int64_t ddy64 = ay ? (((int64_t)1 << 32) / ay) : (int64_t)DD_CAP; + int32_t ddx = ddx64 > DD_CAP ? DD_CAP : (int32_t)ddx64; + int32_t ddy = ddy64 > DD_CAP ? DD_CAP : (int32_t)ddy64; + int stepx, stepy; + int32_t sidex, sidey; + // sideDist to the first grid line = (fractional distance) * deltaDist, 16.16 (int64 mul, setup only) + if (rdx < 0) { + stepx = -1; + sidex = (int32_t)(((int64_t)fracx * ddx) >> 16); + } else { + stepx = 1; + sidex = (int32_t)(((int64_t)(65536 - fracx) * ddx) >> 16); + } + if (rdy < 0) { + stepy = -1; + sidey = (int32_t)(((int64_t)fracy * ddy) >> 16); + } else { + stepy = 1; + sidey = (int32_t)(((int64_t)(65536 - fracy) * ddy) >> 16); + } + int side = 0; + int cell = 1; + for (int i = 0; i < 64; i++) { // DDA - pure 32-bit + if (sidex < sidey) { + sidex += ddx; + mapx += stepx; + side = 0; + } else { + sidey += ddy; + mapy += stepy; + side = 1; + } + cell = (mapx >= 0 && mapx < mw && mapy >= 0 && mapy < mh) ? map[mapy * mw + mapx] : 1; + if (cell) { + break; + } + } + int32_t perp = (side == 0) ? (sidex - ddx) : (sidey - ddy); // perpWallDist, 16.16 + if (perp < 655) { + perp = 655; // ~0.01 in 16.16 + } + int lh = (int)(((int32_t)sh << 16) / perp); // sh / perpWallDist (px); 32-bit (sh<<16 <= ~15.7M) + int t = half - (lh >> 1); + int b = t + lh; + if (t < 0) { + t = 0; + } + if (b > sh) { + b = sh; + } + top[c] = (uint16_t)t; + bot[c] = (uint16_t)b; + int ct = (cell < wc_types) ? cell : 1; // unknown type -> type 1 (matches Python default) + col[c] = wc[ct * 2 + side]; + dist_out[c] = perp; + rdx += srx; // accumulate ray direction for the next column (no overflow) + rdy += sry; + } + if (r0 && ncols > 0) { + // post-pass RLE over the just-written (cache-hot) column arrays: one flush point + int nr = 0; + int rstart = 0; + for (int c = 1; c <= ncols; c++) { + if (c == ncols || top[c] != top[rstart] || bot[c] != bot[rstart] || col[c] != col[rstart]) { + r0[nr] = (uint16_t)(rstart * stride); + r1[nr] = (uint16_t)(c * stride); + rt[nr] = top[rstart]; + rb[nr] = bot[rstart]; + rcol[nr] = col[rstart]; + nr++; + rstart = c; + } + } + return MP_OBJ_NEW_SMALL_INT(nr); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_raycast_obj, 17, 18, picogame_raycast); + + + +//| def road_edges( +//| rl: WriteableBuffer, +//| rr: WriteableBuffer, +//| hw: ReadableBuffer, +//| n: int, +//| cx0: int, +//| dist: int, +//| cfg: ReadableBuffer, +//| ) -> None: +//| """Compute one racing-road frame's left and right edge columns. A low-level +//| interface used by the ``picogame_road`` helper, which packs these inputs. +//| +//| Walks ``n`` screen rows bottom-up, accumulating the road curve, and writes the +//| edge x coordinates into ``rl`` and ``rr``. +//| +//| :param ~circuitpython_typing.WriteableBuffer rl: at least ``n`` ``int16`` values; +//| receives the left edge per row +//| :param ~circuitpython_typing.WriteableBuffer rr: at least ``n`` ``int16`` values; +//| receives the right edge per row +//| :param ~circuitpython_typing.ReadableBuffer hw: at least ``n`` ``int32`` per-row +//| half-widths (signed 16.16 fixed-point) +//| :param int n: number of rows to compute +//| :param int cx0: screen center x including lateral offset (signed 16.16 fixed-point) +//| :param int dist: integer world distance +//| :param ~circuitpython_typing.ReadableBuffer cfg: seven ``int32`` curve parameters, +//| in order: ``f1_q20``, ``f2_q20``, ``amp1k_q16``, ``amp2k_q16``, ``world_step``, +//| ``curve_step``, ``d_row_off``""" +//| ... +//| +// road_edges(rl, rr, hw, n, cx0, dist, cfg) - one racing-road frame's curve accumulator + integer +// edges in one call (the OutRun-genre compute_road loop; core + cfg layout documented in +// shared-module). rl/rr = int16 out, hw = int32 Q16 half-widths, cx0 = Q16 screen centre +// (incl. lateral), dist = integer world distance, cfg = int32[7]. +static mp_obj_t picogame_road_edges_fn(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t rli, rri, hwi, cfgi; + mp_get_buffer_raise(args[0], &rli, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[1], &rri, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[2], &hwi, MP_BUFFER_READ); + mp_get_buffer_raise(args[6], &cfgi, MP_BUFFER_READ); + int n = mp_obj_get_int(args[3]); + int cap = (int)(rli.len < rri.len ? rli.len : rri.len) / 2; + if (n > cap) { + n = cap; + } + if (n > (int)(hwi.len / 4)) { + n = (int)(hwi.len / 4); + } + if (n <= 0 || cfgi.len < 7 * 4) { + return mp_const_none; + } + picogame_road_edges((int16_t *)rli.buf, (int16_t *)rri.buf, (const int32_t *)hwi.buf, n, + mp_obj_get_int(args[4]), mp_obj_get_int(args[5]), (const int32_t *)cfgi.buf); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_road_edges_obj, 7, 7, picogame_road_edges_fn); + + + +// Builds without a given display backend still expose its type: constructing it raises, the same +// way an unsupported rgb444= does, instead of the module changing shape with build flags. +#if !CIRCUITPY_PICOGAME_FAST_DISPLAY || !CIRCUITPY_PICOGAME_FRAMEBUFFER +static mp_obj_t pg_stub_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("Operation or feature not supported")); +} +#endif +#if !CIRCUITPY_PICOGAME_FAST_DISPLAY +MP_DEFINE_CONST_OBJ_TYPE(picogame_display_type, MP_QSTR_Display, MP_TYPE_FLAG_NONE, make_new, pg_stub_make_new); +#endif +#if !CIRCUITPY_PICOGAME_FRAMEBUFFER +MP_DEFINE_CONST_OBJ_TYPE(picogame_framebuffer_type, MP_QSTR_Framebuffer, MP_TYPE_FLAG_NONE, make_new, pg_stub_make_new); +#endif + +static const mp_rom_map_elem_t picogame_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picogame) }, + { MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&picogame_bitmap_type) }, + { MP_ROM_QSTR(MP_QSTR_Sprite), MP_ROM_PTR(&picogame_sprite_type) }, + { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&picogame_display_type) }, + { MP_ROM_QSTR(MP_QSTR_Scene), MP_ROM_PTR(&picogame_scene_type) }, + { MP_ROM_QSTR(MP_QSTR_Tilemap), MP_ROM_PTR(&picogame_tilemap_type) }, + { MP_ROM_QSTR(MP_QSTR_Particles), MP_ROM_PTR(&picogame_particles_type) }, + { MP_ROM_QSTR(MP_QSTR_Canvas), MP_ROM_PTR(&picogame_canvas_type) }, + { MP_ROM_QSTR(MP_QSTR_StripDraw), MP_ROM_PTR(&picogame_stripdraw_type) }, + { MP_ROM_QSTR(MP_QSTR_Triangles), MP_ROM_PTR(&picogame_triangles_type) }, + { MP_ROM_QSTR(MP_QSTR_Framebuffer), MP_ROM_PTR(&picogame_framebuffer_type) }, + { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&picogame_render_obj) }, + { MP_ROM_QSTR(MP_QSTR_raycast), MP_ROM_PTR(&picogame_raycast_obj) }, + { MP_ROM_QSTR(MP_QSTR_road_edges), MP_ROM_PTR(&picogame_road_edges_obj) }, + { MP_ROM_QSTR(MP_QSTR_project), MP_ROM_PTR(&picogame_project_obj) }, + // True when the pseudo-3D/math primitives use the hardware-float path (FPU board). Python packs + // camera/point buffers as float32 when this is set, else as 16.16 fixed int32. + { MP_ROM_QSTR(MP_QSTR_FPU), MP_ROM_INT(CIRCUITPY_PICOGAME_FPU) }, + { MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&picogame_invert_obj) }, + { MP_ROM_QSTR(MP_QSTR_collide), MP_ROM_PTR(&picogame_collide_obj) }, + // Canonical noise = the fixed-point implementation (float retired; see `#if 0` above). + { MP_ROM_QSTR(MP_QSTR_value2d), MP_ROM_PTR(&picogame_value2d_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_value1d), MP_ROM_PTR(&picogame_value1d_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_fbm2d), MP_ROM_PTR(&picogame_fbm2d_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_fbm1d), MP_ROM_PTR(&picogame_fbm1d_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_rgb565), MP_ROM_PTR(&picogame_rgb565_obj) }, + { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(PICOGAME_FMT_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_PAL8), MP_ROM_INT(PICOGAME_FMT_PAL8) }, + // Engine API level: bump by 1 whenever the PYTHON-VISIBLE surface grows (new method/property/ + // module function/constant), so picogame-libs can diagnose a too-old firmware up front + // ("needs API_LEVEL >= N") instead of failing later with a random missing attribute. + // Level 1 = the 2026-07 surface (post API-freeze + Canvas.text/Framebuffer/StripDraw + // always_dirty). Older firmwares have no attribute at all -> getattr(pg, "API_LEVEL", 0). + { MP_ROM_QSTR(MP_QSTR_API_LEVEL), MP_ROM_INT(1) }, + // Build-time capability flag: does THIS board's panel controller support 12-bit RGB444 + // (COLMOD)? The board declares it (it knows its controller); a game reads it to enable + // Display(rgb444=...) only where it works - one codebase runs on ST7789 AND ILI9341. + #if CIRCUITPY_PICOGAME_RGB444 + { MP_ROM_QSTR(MP_QSTR_RGB444_SUPPORTED), MP_ROM_TRUE }, + #else + { MP_ROM_QSTR(MP_QSTR_RGB444_SUPPORTED), MP_ROM_FALSE }, + #endif + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + { MP_ROM_QSTR(MP_QSTR_FAST_DISPLAY_SUPPORTED), MP_ROM_TRUE }, + #else + { MP_ROM_QSTR(MP_QSTR_FAST_DISPLAY_SUPPORTED), MP_ROM_FALSE }, + #endif + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + { MP_ROM_QSTR(MP_QSTR_FRAMEBUFFER_SUPPORTED), MP_ROM_TRUE }, + #else + { MP_ROM_QSTR(MP_QSTR_FRAMEBUFFER_SUPPORTED), MP_ROM_FALSE }, + #endif + // Build-time default render-strip height (rows). picogame_game.setup() uses it when strip_h is + // None; games can override per call; a board can override the default in mpconfigboard.h. + // MEASURED (RP2040): with async DMA double-buffering, SMALL strips overlap render+transfer best -> + // 8 is both fastest and least RAM (the two w*strip_h*2 buffers shrink). WITHOUT the DMA backend + // there's no overlap, so a blocking send per strip makes LARGER strips win -> 24. + #ifndef PICOGAME_STRIP_H + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + #define PICOGAME_STRIP_H 8 + #else + #define PICOGAME_STRIP_H 24 + #endif + #endif + { MP_ROM_QSTR(MP_QSTR_STRIP_H), MP_ROM_INT(PICOGAME_STRIP_H) }, +}; +static MP_DEFINE_CONST_DICT(picogame_module_globals, picogame_module_globals_table); + +const mp_obj_module_t picogame_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&picogame_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_picogame, picogame_module); diff --git a/shared-bindings/picogame/__init__.h b/shared-bindings/picogame/__init__.h new file mode 100644 index 00000000000..9bfca623beb --- /dev/null +++ b/shared-bindings/picogame/__init__.h @@ -0,0 +1,12 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + + +uint8_t picogame_kind_of(mp_obj_t o); diff --git a/shared-bindings/ps2io/Ps2.c b/shared-bindings/ps2io/Ps2.c index 8766ea7a2a1..90e6b0b6045 100644 --- a/shared-bindings/ps2io/Ps2.c +++ b/shared-bindings/ps2io/Ps2.c @@ -58,7 +58,6 @@ static mp_obj_t ps2io_ps2_make_new(const mp_obj_type_t *type, size_t n_args, siz const mcu_pin_obj_t *data_pin = validate_obj_is_free_pin(args[ARG_data_pin].u_obj, MP_QSTR_data_pin); ps2io_ps2_obj_t *self = mp_obj_malloc(ps2io_ps2_obj_t, &ps2io_ps2_type); - common_hal_ps2io_ps2_construct(self, data_pin, clock_pin); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/pulseio/PulseIn.c b/shared-bindings/pulseio/PulseIn.c index d9e6bfd7aec..830f7b7c62c 100644 --- a/shared-bindings/pulseio/PulseIn.c +++ b/shared-bindings/pulseio/PulseIn.c @@ -69,7 +69,6 @@ static mp_obj_t pulseio_pulsein_make_new(const mp_obj_type_t *type, size_t n_arg const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); pulseio_pulsein_obj_t *self = mp_obj_malloc_with_finaliser(pulseio_pulsein_obj_t, &pulseio_pulsein_type); - common_hal_pulseio_pulsein_construct(self, pin, args[ARG_maxlen].u_int, args[ARG_idle_state].u_bool); diff --git a/shared-bindings/pulseio/PulseOut.c b/shared-bindings/pulseio/PulseOut.c index 947aa4b518e..58c98b8e2cc 100644 --- a/shared-bindings/pulseio/PulseOut.c +++ b/shared-bindings/pulseio/PulseOut.c @@ -62,6 +62,7 @@ static mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_ar pulseio_pulseout_obj_t *self = mp_obj_malloc_with_finaliser(pulseio_pulseout_obj_t, &pulseio_pulseout_type); common_hal_pulseio_pulseout_construct(self, pin, frequency, duty_cycle); + return MP_OBJ_FROM_PTR(self); #else mp_raise_NotImplementedError(NULL); diff --git a/shared-bindings/pwmio/PWMOut.c b/shared-bindings/pwmio/PWMOut.c index 97dbd2079f7..7cfb0d8a13f 100644 --- a/shared-bindings/pwmio/PWMOut.c +++ b/shared-bindings/pwmio/PWMOut.c @@ -25,14 +25,8 @@ void common_hal_pwmio_pwmout_raise_error(pwmout_result_t result) { case PWMOUT_INVALID_FREQUENCY: mp_arg_error_invalid(MP_QSTR_frequency); break; - case PWMOUT_INVALID_FREQUENCY_ON_PIN: - mp_arg_error_invalid(MP_QSTR_frequency); - break; - case PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE: - mp_arg_error_invalid(MP_QSTR_variable_frequency); - break; case PWMOUT_INTERNAL_RESOURCES_IN_USE: - mp_raise_RuntimeError(MP_ERROR_TEXT("Internal resource(s) in use")); + mp_raise_RuntimeError(MP_ERROR_TEXT("Conflicting settings for shared resource")); break; default: case PWMOUT_INITIALIZATION_ERROR: @@ -145,7 +139,8 @@ static mp_obj_t pwmio_pwmout_make_new(const mp_obj_type_t *type, size_t n_args, const mcu_pin_obj_t *pin = validate_obj_is_free_pin(parsed_args[ARG_pin].u_obj, MP_QSTR_pin); - uint16_t duty_cycle = parsed_args[ARG_duty_cycle].u_int; + uint16_t duty_cycle = (uint16_t)mp_arg_validate_int_range( + parsed_args[ARG_duty_cycle].u_int, 0, 0xffff, MP_QSTR_duty_cycle); uint32_t frequency = parsed_args[ARG_frequency].u_int; bool variable_frequency = parsed_args[ARG_variable_frequency].u_bool; diff --git a/shared-bindings/pwmio/PWMOut.h b/shared-bindings/pwmio/PWMOut.h index d8bab978228..3c3093ae628 100644 --- a/shared-bindings/pwmio/PWMOut.h +++ b/shared-bindings/pwmio/PWMOut.h @@ -15,8 +15,6 @@ typedef enum pwmout_result_t { PWMOUT_OK, PWMOUT_INVALID_PIN, PWMOUT_INVALID_FREQUENCY, - PWMOUT_INVALID_FREQUENCY_ON_PIN, - PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE, PWMOUT_INTERNAL_RESOURCES_IN_USE, PWMOUT_INITIALIZATION_ERROR, } pwmout_result_t; diff --git a/shared-bindings/qrio/QRDecoder.c b/shared-bindings/qrio/QRDecoder.c index 6a36d8b0265..e8977bc1efe 100644 --- a/shared-bindings/qrio/QRDecoder.c +++ b/shared-bindings/qrio/QRDecoder.c @@ -34,7 +34,7 @@ static mp_obj_t qrio_qrdecoder_make_new(const mp_obj_type_t *type, size_t n_args qrio_qrdecoder_obj_t *self = mp_obj_malloc(qrio_qrdecoder_obj_t, &qrio_qrdecoder_type_obj); shared_module_qrio_qrdecoder_construct(self, args[ARG_width].u_int, args[ARG_height].u_int); - return self; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/qspibus/QSPIBus.c b/shared-bindings/qspibus/QSPIBus.c new file mode 100644 index 00000000000..24c3089213f --- /dev/null +++ b/shared-bindings/qspibus/QSPIBus.c @@ -0,0 +1,199 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT + +#include + +#include "shared-bindings/qspibus/QSPIBus.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared-module/displayio/__init__.h" + +#include "py/binary.h" +#include "py/obj.h" +#include "py/runtime.h" + +static void check_for_deinit(qspibus_qspibus_obj_t *self) { + if (common_hal_qspibus_qspibus_deinited(self)) { + raise_deinited_error(); + } +} + +//| class QSPIBus: +//| """QSPI bus for quad-SPI displays.""" +//| +//| def __init__( +//| self, +//| *, +//| clock: microcontroller.Pin, +//| data0: microcontroller.Pin, +//| data1: microcontroller.Pin, +//| data2: microcontroller.Pin, +//| data3: microcontroller.Pin, +//| cs: microcontroller.Pin, +//| dcx: Optional[microcontroller.Pin] = None, +//| reset: Optional[microcontroller.Pin] = None, +//| frequency: int = 80_000_000, +//| ) -> None: +//| """Create a QSPIBus object for quad-SPI display communication. +//| +//| :param ~microcontroller.Pin clock: QSPI clock pin +//| :param ~microcontroller.Pin data0: QSPI data line 0 +//| :param ~microcontroller.Pin data1: QSPI data line 1 +//| :param ~microcontroller.Pin data2: QSPI data line 2 +//| :param ~microcontroller.Pin data3: QSPI data line 3 +//| :param ~microcontroller.Pin cs: Chip select pin +//| :param ~microcontroller.Pin dcx: Optional data/command select pin. +//| Reserved for future hardware paths. Current ESP32-S3 implementation +//| uses encoded QSPI command words and does not require explicit DCX. +//| :param ~microcontroller.Pin reset: Optional reset pin +//| :param int frequency: Bus frequency in Hz (1-80MHz) +//| """ +//| ... +//| +static mp_obj_t qspibus_qspibus_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + + enum { ARG_clock, ARG_data0, ARG_data1, ARG_data2, ARG_data3, ARG_cs, ARG_dcx, ARG_reset, ARG_frequency }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_data0, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_data1, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_data2, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_data3, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_dcx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_reset, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 80000000} }, + }; + + 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 mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *data0 = validate_obj_is_free_pin(args[ARG_data0].u_obj, MP_QSTR_data0); + const mcu_pin_obj_t *data1 = validate_obj_is_free_pin(args[ARG_data1].u_obj, MP_QSTR_data1); + const mcu_pin_obj_t *data2 = validate_obj_is_free_pin(args[ARG_data2].u_obj, MP_QSTR_data2); + const mcu_pin_obj_t *data3 = validate_obj_is_free_pin(args[ARG_data3].u_obj, MP_QSTR_data3); + const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + const mcu_pin_obj_t *dcx = validate_obj_is_free_pin_or_none(args[ARG_dcx].u_obj, MP_QSTR_dcx); + const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj, MP_QSTR_reset); + + uint32_t frequency = (uint32_t)mp_arg_validate_int_range(args[ARG_frequency].u_int, 1, 80000000, MP_QSTR_frequency); + + qspibus_qspibus_obj_t *self = &allocate_display_bus_or_raise()->qspi_bus; + self->base.type = &qspibus_qspibus_type; + common_hal_qspibus_qspibus_construct(self, clock, data0, data1, data2, data3, cs, dcx, reset, frequency); + + return MP_OBJ_FROM_PTR(self); +} + +//| def reset(self) -> None: +//| """Perform a hardware reset using the reset pin. +//| +//| :raises RuntimeError: if no reset pin was provided at construction. +//| """ +//| ... +//| +static mp_obj_t qspibus_qspibus_obj_reset(mp_obj_t self_in) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (!common_hal_qspibus_qspibus_reset(MP_OBJ_FROM_PTR(self))) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("No %q pin"), MP_QSTR_reset); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(qspibus_qspibus_reset_obj, qspibus_qspibus_obj_reset); + +//| def send( +//| self, command: int, data: ReadableBuffer, *, toggle_every_byte: bool = False +//| ) -> None: +//| """Sends the given command value followed by the full set of data. Display state, such as +//| vertical scroll, set via ``send`` may or may not be reset once the code is done.""" +//| ... +//| +static mp_obj_t qspibus_qspibus_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_command, ARG_data }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, + }; + + 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); + + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + + uint8_t command = (uint8_t)mp_arg_validate_int_range(args[ARG_command].u_int, 0, 255, MP_QSTR_command); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); + + // Flush any pending command from a prior write_command() call. + // begin_transaction() returns false while has_pending_command is set, + // so entering the wait loop without flushing would spin forever. + if (self->has_pending_command) { + common_hal_qspibus_qspibus_write_data(self, NULL, 0); + } + + // Wait for display bus to be available, then acquire transaction. + while (!common_hal_qspibus_qspibus_begin_transaction(MP_OBJ_FROM_PTR(self))) { + RUN_BACKGROUND_TASKS; + } + common_hal_qspibus_qspibus_send(MP_OBJ_FROM_PTR(self), DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, &command, 1); + common_hal_qspibus_qspibus_send(MP_OBJ_FROM_PTR(self), DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t *)bufinfo.buf), bufinfo.len); + common_hal_qspibus_qspibus_end_transaction(MP_OBJ_FROM_PTR(self)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(qspibus_qspibus_send_obj, 1, qspibus_qspibus_send); + +//| def write_command(self, command: int) -> None: +//| """Stage a command byte for subsequent :py:meth:`write_data`. +//| +//| If a previously staged command had no data, it is sent as +//| a command-only transaction before staging the new one. +//| """ +//| ... +//| +static mp_obj_t qspibus_qspibus_write_command(mp_obj_t self_in, mp_obj_t command_obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + uint8_t command = (uint8_t)mp_arg_validate_int_range(mp_obj_get_int(command_obj), 0, 255, MP_QSTR_command); + common_hal_qspibus_qspibus_write_command(self, command); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(qspibus_qspibus_write_command_obj, qspibus_qspibus_write_command); + +//| def write_data(self, data: ReadableBuffer) -> None: +//| """Send payload bytes for the most recently staged command.""" +//| ... +//| +static mp_obj_t qspibus_qspibus_write_data(mp_obj_t self_in, mp_obj_t data_obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); + common_hal_qspibus_qspibus_write_data(self, (const uint8_t *)bufinfo.buf, bufinfo.len); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(qspibus_qspibus_write_data_obj, qspibus_qspibus_write_data); + +static const mp_rom_map_elem_t qspibus_qspibus_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&qspibus_qspibus_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&qspibus_qspibus_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_command), MP_ROM_PTR(&qspibus_qspibus_write_command_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_data), MP_ROM_PTR(&qspibus_qspibus_write_data_obj) }, +}; +static MP_DEFINE_CONST_DICT(qspibus_qspibus_locals_dict, qspibus_qspibus_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + qspibus_qspibus_type, + MP_QSTR_QSPIBus, + MP_TYPE_FLAG_NONE, + make_new, qspibus_qspibus_make_new, + locals_dict, &qspibus_qspibus_locals_dict + ); diff --git a/shared-bindings/qspibus/QSPIBus.h b/shared-bindings/qspibus/QSPIBus.h new file mode 100644 index 00000000000..140b639279d --- /dev/null +++ b/shared-bindings/qspibus/QSPIBus.h @@ -0,0 +1,53 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" + +#include "shared-bindings/displayio/__init__.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/qspibus/QSPIBus.h" + +extern const mp_obj_type_t qspibus_qspibus_type; + +void common_hal_qspibus_qspibus_construct( + qspibus_qspibus_obj_t *self, + const mcu_pin_obj_t *clock, + const mcu_pin_obj_t *data0, + const mcu_pin_obj_t *data1, + const mcu_pin_obj_t *data2, + const mcu_pin_obj_t *data3, + const mcu_pin_obj_t *cs, + const mcu_pin_obj_t *dcx, + const mcu_pin_obj_t *reset, + uint32_t frequency); + +void common_hal_qspibus_qspibus_deinit(qspibus_qspibus_obj_t *self); +bool common_hal_qspibus_qspibus_deinited(qspibus_qspibus_obj_t *self); + +void common_hal_qspibus_qspibus_write_command( + qspibus_qspibus_obj_t *self, + uint8_t command); +void common_hal_qspibus_qspibus_write_data( + qspibus_qspibus_obj_t *self, + const uint8_t *data, + size_t len); + +bool common_hal_qspibus_qspibus_reset(mp_obj_t obj); +bool common_hal_qspibus_qspibus_bus_free(mp_obj_t obj); +bool common_hal_qspibus_qspibus_begin_transaction(mp_obj_t obj); +void common_hal_qspibus_qspibus_send( + mp_obj_t obj, + display_byte_type_t data_type, + display_chip_select_behavior_t chip_select, + const uint8_t *data, + uint32_t data_length); +void common_hal_qspibus_qspibus_end_transaction(mp_obj_t obj); +void common_hal_qspibus_qspibus_flush(mp_obj_t obj); +void common_hal_qspibus_qspibus_collect_ptrs(mp_obj_t obj); diff --git a/shared-bindings/qspibus/__init__.c b/shared-bindings/qspibus/__init__.c new file mode 100644 index 00000000000..0281c41c804 --- /dev/null +++ b/shared-bindings/qspibus/__init__.c @@ -0,0 +1,50 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/qspibus/__init__.h" +#include "shared-bindings/qspibus/QSPIBus.h" + +//| """QSPI bus protocol for quad-SPI displays +//| +//| The `qspibus` module provides a low-level QSPI bus interface for displays +//| that use four data lines. It is analogous to `fourwire` for standard SPI. +//| +//| Use :class:`qspibus.QSPIBus` to create a bus instance. +//| +//| Example usage:: +//| +//| import board +//| import qspibus +//| import displayio +//| +//| displayio.release_displays() +//| +//| bus = qspibus.QSPIBus( +//| clock=board.LCD_CLK, +//| data0=board.LCD_D0, +//| data1=board.LCD_D1, +//| data2=board.LCD_D2, +//| data3=board.LCD_D3, +//| cs=board.LCD_CS, +//| reset=board.LCD_RESET, +//| frequency=80_000_000, +//| ) +//| """ + +static const mp_rom_map_elem_t qspibus_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_qspibus) }, + { MP_ROM_QSTR(MP_QSTR_QSPIBus), MP_ROM_PTR(&qspibus_qspibus_type) }, +}; + +static MP_DEFINE_CONST_DICT(qspibus_module_globals, qspibus_module_globals_table); + +const mp_obj_module_t qspibus_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&qspibus_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_qspibus, qspibus_module); diff --git a/shared-bindings/qspibus/__init__.h b/shared-bindings/qspibus/__init__.h new file mode 100644 index 00000000000..9b4ca243327 --- /dev/null +++ b/shared-bindings/qspibus/__init__.h @@ -0,0 +1,8 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/qspibus/QSPIBus.h" diff --git a/shared-bindings/rainbowio/__init__.c b/shared-bindings/rainbowio/__init__.c index a085669d7ff..e02df713eeb 100644 --- a/shared-bindings/rainbowio/__init__.c +++ b/shared-bindings/rainbowio/__init__.c @@ -16,7 +16,8 @@ //| //| def colorwheel(n: float) -> int: //| """C implementation of the common colorwheel() function found in many examples. -//| Returns the colorwheel RGB value as an integer value for n (usable in neopixel and dotstar). +//| Takes a hue, a value between 0-255, and returns an RGB tuple encoded as an +//| integer value (usable in neopixel and dotstar). //| """ //| ... //| diff --git a/shared-bindings/random/__init__.c b/shared-bindings/random/__init__.c index 81201e6f8ab..89ff3572ea9 100644 --- a/shared-bindings/random/__init__.c +++ b/shared-bindings/random/__init__.c @@ -116,6 +116,9 @@ static mp_obj_t random_randint(mp_obj_t a_in, mp_obj_t b_in) { if (a > b) { mp_raise_ValueError(NULL); } + if (b == (mp_int_t)(~(mp_uint_t)0 >> 1)) { + mp_raise_ValueError(NULL); + } return mp_obj_new_int(shared_modules_random_randrange(a, b + 1, 1)); } static MP_DEFINE_CONST_FUN_OBJ_2(random_randint_obj, random_randint); diff --git a/shared-bindings/rclcpy/Node.c b/shared-bindings/rclcpy/Node.c index a2fa9bd36a6..4097fbc1515 100644 --- a/shared-bindings/rclcpy/Node.c +++ b/shared-bindings/rclcpy/Node.c @@ -50,7 +50,8 @@ static mp_obj_t rclcpy_node_make_new(const mp_obj_type_t *type, size_t n_args, s rclcpy_node_obj_t *self = mp_obj_malloc_with_finaliser(rclcpy_node_obj_t, &rclcpy_node_type); common_hal_rclcpy_node_construct(self, node_name, namespace); - return (mp_obj_t)self; + + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: @@ -90,7 +91,7 @@ static mp_obj_t rclcpy_node_create_publisher(mp_obj_t self_in, mp_obj_t topic) { rclcpy_publisher_obj_t *publisher = mp_obj_malloc_with_finaliser(rclcpy_publisher_obj_t, &rclcpy_publisher_type); common_hal_rclcpy_publisher_construct(publisher, self, topic_name); - return (mp_obj_t)publisher; + return MP_OBJ_FROM_PTR(publisher); } static MP_DEFINE_CONST_FUN_OBJ_2(rclcpy_node_create_publisher_obj, rclcpy_node_create_publisher); diff --git a/shared-bindings/rclcpy/__init__.c b/shared-bindings/rclcpy/__init__.c index a6631642ea7..e195294cde6 100644 --- a/shared-bindings/rclcpy/__init__.c +++ b/shared-bindings/rclcpy/__init__.c @@ -112,7 +112,8 @@ static mp_obj_t rclcpy_create_node(size_t n_args, const mp_obj_t *pos_args, mp_m rclcpy_node_obj_t *self = mp_obj_malloc_with_finaliser(rclcpy_node_obj_t, &rclcpy_node_type); common_hal_rclcpy_node_construct(self, node_name, namespace); - return (mp_obj_t)self; + + return MP_OBJ_FROM_PTR(self); } static MP_DEFINE_CONST_FUN_OBJ_KW(rclcpy_create_node_obj, 2, rclcpy_create_node); diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index e6d8453eae1..506009f64d6 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -9,7 +9,8 @@ #include "py/objarray.h" #include "shared-bindings/sdcardio/SDCard.h" -#include "shared-module/sdcardio/SDCard.h" +#include "shared-bindings/util.h" + #include "common-hal/busio/SPI.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/microcontroller/Pin.h" @@ -24,7 +25,10 @@ //| with ``storage.VfsFat`` to allow file I/O to an SD card.""" //| //| def __init__( -//| self, bus: busio.SPI, cs: microcontroller.Pin, baudrate: int = 8000000 +//| self, +//| bus: busio.SPI, +//| cs: Union[microcontroller.Pin, digitalio.DigitalInOutProtocol], +//| baudrate: int = 8000000 //| ) -> None: //| """Construct an SPI SD Card object with the given properties //| @@ -37,10 +41,18 @@ //| the microcontroller) //| //| .. important:: -//| If the same SPI bus is shared with other peripherals, it is important that -//| the SD card be initialized before accessing any other peripheral on the bus. -//| Failure to do so can prevent the SD card from being recognized until it is -//| powered off or re-inserted. +//| When the SPI bus is shared with other peripherals, every CS pin on +//| the bus must be in a known HIGH (deselected) state before any SPI +//| transaction occurs. This is normally guaranteed by a hardware +//| pull-up on each CS line, but on boards where a co-resident +//| peripheral's CS floats (for example the Feather RP2040 RFM, whose +//| ``RFM_CS`` has no pull-up), that CS must be driven HIGH in +//| software before the SD card is initialized. If any CS is allowed +//| to float low, the SPI bus can be corrupted during SD card init +//| and the card may not be recognized until it is powered off or +//| re-inserted. The order in which peripherals are constructed is +//| secondary; what matters is that all CS lines are HIGH (deselected) +//| before any SPI transaction. //| //| Example usage: //| @@ -52,12 +64,20 @@ //| import sdcardio //| import storage //| +//| # Make sure to make an "sd" folder on CIRCUITPY +//| //| sd = sdcardio.SDCard(board.SPI(), board.SD_CS) //| vfs = storage.VfsFat(sd) //| storage.mount(vfs, '/sd') -//| os.listdir('/sd')""" +//| print(os.listdir('/sd'))""" //| +static void check_for_deinit(sdcardio_sdcard_obj_t *self) { + if (common_hal_sdcardio_sdcard_deinited(self)) { + raise_deinited_error(); + } +} + static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_spi, ARG_cs, ARG_baudrate, NUM_ARGS }; static const mp_arg_t allowed_args[] = { @@ -70,13 +90,11 @@ static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_arg mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj, MP_QSTR_spi); - const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); - - sdcardio_sdcard_obj_t *self = mp_obj_malloc(sdcardio_sdcard_obj_t, &sdcardio_SDCard_type); - common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int); + sdcardio_sdcard_obj_t *self = mp_obj_malloc_with_finaliser(sdcardio_sdcard_obj_t, &sdcardio_SDCard_type); + common_hal_sdcardio_sdcard_construct(self, spi, args[ARG_cs].u_obj, args[ARG_baudrate].u_int); - return self; + return MP_OBJ_FROM_PTR(self); } @@ -89,6 +107,7 @@ static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_arg //| static mp_obj_t sdcardio_sdcard_count(mp_obj_t self_in) { sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); return mp_obj_new_int_from_ull(common_hal_sdcardio_sdcard_get_blockcount(self)); } MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_count_obj, sdcardio_sdcard_count); @@ -116,10 +135,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_deinit_obj, sdcardio_sdcard_deinit); //| static mp_obj_t _sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); + uint32_t start_block = mp_obj_get_int(start_block_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; int result = common_hal_sdcardio_sdcard_readblocks(self, start_block, &bufinfo); if (result < 0) { mp_raise_OSError(-result); @@ -137,6 +158,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, _sdcardio_sdcard_readb //| static mp_obj_t sdcardio_sdcard_sync(mp_obj_t self_in) { sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); int result = common_hal_sdcardio_sdcard_sync(self); if (result < 0) { mp_raise_OSError(-result); @@ -158,10 +180,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_sync_obj, sdcardio_sdcard_sync); //| static mp_obj_t _sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); + uint32_t start_block = mp_obj_get_int(start_block_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; int result = common_hal_sdcardio_sdcard_writeblocks(self, start_block, &bufinfo); if (result < 0) { mp_raise_OSError(-result); @@ -173,6 +197,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, _sdcardio_sdcard_writ static const mp_rom_map_elem_t sdcardio_sdcard_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdcardio_sdcard_count_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdcardio_sdcard_readblocks_obj) }, { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&sdcardio_sdcard_sync_obj) }, { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdcardio_sdcard_writeblocks_obj) }, diff --git a/shared-bindings/sdcardio/SDCard.h b/shared-bindings/sdcardio/SDCard.h index ac27b47aa4d..4251575f8fd 100644 --- a/shared-bindings/sdcardio/SDCard.h +++ b/shared-bindings/sdcardio/SDCard.h @@ -7,17 +7,20 @@ #pragma once +#include "py/mperrno.h" #include "shared-module/sdcardio/SDCard.h" extern const mp_obj_type_t sdcardio_SDCard_type; -void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *cs, int baudrate); +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, mp_obj_t cs, int baudrate); void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self); +bool common_hal_sdcardio_sdcard_deinited(sdcardio_sdcard_obj_t *self); void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); +void common_hal_sdcardio_sdcard_mark_deinit(sdcardio_sdcard_obj_t *self); int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self); -int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); -int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self); -int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); +mp_negative_errno_t common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); +mp_negative_errno_t common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self); +mp_negative_errno_t common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); // Used by native vfs blockdev. mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); diff --git a/shared-bindings/sdioio/SDCard.c b/shared-bindings/sdioio/SDCard.c index 892cecd3fb4..baf1e1660e8 100644 --- a/shared-bindings/sdioio/SDCard.c +++ b/shared-bindings/sdioio/SDCard.c @@ -67,7 +67,6 @@ //| static mp_obj_t sdioio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - sdioio_sdcard_obj_t *self = mp_obj_malloc(sdioio_sdcard_obj_t, &sdioio_SDCard_type); enum { ARG_clock, ARG_command, ARG_data, ARG_frequency, NUM_ARGS }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, @@ -86,6 +85,7 @@ static mp_obj_t sdioio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, uint8_t num_data; validate_list_is_free_pins(MP_QSTR_data, data_pins, MP_ARRAY_SIZE(data_pins), args[ARG_data].u_obj, &num_data); + sdioio_sdcard_obj_t *self = mp_obj_malloc(sdioio_sdcard_obj_t, &sdioio_SDCard_type); common_hal_sdioio_sdcard_construct(self, clock, command, num_data, data_pins, args[ARG_frequency].u_int); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/sdioio/SDCard.h b/shared-bindings/sdioio/SDCard.h index dfeaf8fca89..042521aea50 100644 --- a/shared-bindings/sdioio/SDCard.h +++ b/shared-bindings/sdioio/SDCard.h @@ -7,6 +7,7 @@ #pragma once #include "py/obj.h" +#include "py/mperrno.h" #include "common-hal/microcontroller/Pin.h" #include "common-hal/sdioio/SDCard.h" @@ -35,9 +36,14 @@ uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t *self); // Return number of device blocks uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t *self); -// Read or write blocks -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); +// Read or write blocks - returns 0 on success or negative error code from mperrno.h +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); + +// Used by native vfs blockdev. +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *out_value); // This is used by the supervisor to claim SDIO devices indefinitely. extern void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self); diff --git a/shared-bindings/sdioio/__init__.c b/shared-bindings/sdioio/__init__.c index 45f1219f95a..d2e66f9633d 100644 --- a/shared-bindings/sdioio/__init__.c +++ b/shared-bindings/sdioio/__init__.c @@ -15,7 +15,7 @@ //| """Interface to an SD card via the SDIO bus""" static const mp_rom_map_elem_t sdioio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdio) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdioio) }, { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdioio_SDCard_type) }, }; diff --git a/shared-bindings/socketpool/Socket.c b/shared-bindings/socketpool/Socket.c index 5dac9d150e8..35adb20bbfb 100644 --- a/shared-bindings/socketpool/Socket.c +++ b/shared-bindings/socketpool/Socket.c @@ -446,7 +446,7 @@ static mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, return ret; } -static mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/shared-bindings/socketpool/Socket.h b/shared-bindings/socketpool/Socket.h index a883ebd5054..295f86e7371 100644 --- a/shared-bindings/socketpool/Socket.h +++ b/shared-bindings/socketpool/Socket.h @@ -6,6 +6,7 @@ #pragma once +#include "py/mperrno.h" #include "common-hal/socketpool/Socket.h" extern const mp_obj_type_t socketpool_socket_type; diff --git a/shared-bindings/socketpool/SocketPool.c b/shared-bindings/socketpool/SocketPool.c index e139e3a077a..f50a7a5fcfe 100644 --- a/shared-bindings/socketpool/SocketPool.c +++ b/shared-bindings/socketpool/SocketPool.c @@ -24,21 +24,20 @@ //| a pool of sockets provided by the underlying OS. //| """ //| -//| def __init__(self, radio: wifi.Radio) -> None: +//| def __init__(self, radio: Union[wifi.Radio, hostnetwork.HostNetwork]) -> None: //| """Create a new SocketPool object for the provided radio //| -//| :param wifi.Radio radio: The (connected) network hardware to associate -//| with this SocketPool; currently, this will always be the object -//| returned by :py:attr:`wifi.radio` +//| :param radio: The (connected) network interface to associate with this +//| SocketPool, such as :py:attr:`wifi.radio` or :py:attr:`board.NETWORK`. //| """ //| ... //| static mp_obj_t socketpool_socketpool_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); - socketpool_socketpool_obj_t *s = mp_obj_malloc_with_finaliser(socketpool_socketpool_obj_t, &socketpool_socketpool_type); mp_obj_t radio = args[0]; + socketpool_socketpool_obj_t *s = mp_obj_malloc_with_finaliser(socketpool_socketpool_obj_t, &socketpool_socketpool_type); common_hal_socketpool_socketpool_construct(s, radio); return MP_OBJ_FROM_PTR(s); @@ -190,16 +189,28 @@ MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &socketpool_socketpool_locals_dict ); -MP_WEAK NORETURN -void common_hal_socketpool_socketpool_raise_gaierror_noname(void) { +MP_WEAK MP_NORETURN +void common_hal_socketpool_socketpool_raise_gaierror(int err) { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 64, &print); - mp_printf(&print, "%S", MP_ERROR_TEXT("Name or service not known")); + // Only EAI_NONAME means the name was not found. Other codes cover + // unrelated failures, such as an unsupported family, so use the generic + // message for those rather than one that would be misleading. + if (err == SOCKETPOOL_EAI_NONAME) { + mp_printf(&print, "%S", MP_ERROR_TEXT("Name or service not known")); + } else { + mp_cprintf(&print, MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_getaddrinfo, err); + } mp_obj_t exc_args[] = { - MP_OBJ_NEW_SMALL_INT(SOCKETPOOL_EAI_NONAME), + MP_OBJ_NEW_SMALL_INT(err), mp_obj_new_str_from_vstr(&vstr), }; nlr_raise(mp_obj_new_exception_args(&mp_type_gaierror, MP_ARRAY_SIZE(exc_args), exc_args)); } + +MP_WEAK MP_NORETURN +void common_hal_socketpool_socketpool_raise_gaierror_noname(void) { + common_hal_socketpool_socketpool_raise_gaierror(SOCKETPOOL_EAI_NONAME); +} diff --git a/shared-bindings/socketpool/SocketPool.h b/shared-bindings/socketpool/SocketPool.h index 36035ed00e1..1d0a3bbccff 100644 --- a/shared-bindings/socketpool/SocketPool.h +++ b/shared-bindings/socketpool/SocketPool.h @@ -25,6 +25,7 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self, socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type, int proto, socketpool_socket_obj_t *sock); -NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void); +MP_NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void); +MP_NORETURN void common_hal_socketpool_socketpool_raise_gaierror(int err); mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags); diff --git a/shared-bindings/spitarget/SPITarget.c b/shared-bindings/spitarget/SPITarget.c index eca92d80027..08f6d554f3a 100644 --- a/shared-bindings/spitarget/SPITarget.c +++ b/shared-bindings/spitarget/SPITarget.c @@ -33,7 +33,6 @@ //| ... //| static mp_obj_t spitarget_spi_target_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - spitarget_spi_target_obj_t *self = mp_obj_malloc(spitarget_spi_target_obj_t, &spitarget_spi_target_type); enum { ARG_sck, ARG_mosi, ARG_miso, ARG_ss }; static const mp_arg_t allowed_args[] = { { MP_QSTR_sck, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -49,7 +48,9 @@ static mp_obj_t spitarget_spi_target_make_new(const mp_obj_type_t *type, size_t const mcu_pin_obj_t *miso = validate_obj_is_free_pin(args[ARG_miso].u_obj, MP_QSTR_miso); const mcu_pin_obj_t *ss = validate_obj_is_free_pin(args[ARG_ss].u_obj, MP_QSTR_ss); + spitarget_spi_target_obj_t *self = mp_obj_malloc(spitarget_spi_target_obj_t, &spitarget_spi_target_type); common_hal_spitarget_spi_target_construct(self, sck, mosi, miso, ss); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/ssl/SSLContext.c b/shared-bindings/ssl/SSLContext.c index 078a716cdb8..9546c50ed7c 100644 --- a/shared-bindings/ssl/SSLContext.c +++ b/shared-bindings/ssl/SSLContext.c @@ -26,7 +26,6 @@ static mp_obj_t ssl_sslcontext_make_new(const mp_obj_type_t *type, size_t n_args mp_arg_check_num(n_args, n_kw, 0, 1, false); ssl_sslcontext_obj_t *s = mp_obj_malloc(ssl_sslcontext_obj_t, &ssl_sslcontext_type); - common_hal_ssl_sslcontext_construct(s); return MP_OBJ_FROM_PTR(s); diff --git a/shared-bindings/ssl/SSLSocket.c b/shared-bindings/ssl/SSLSocket.c index 92440f9ea30..98f67878d04 100644 --- a/shared-bindings/ssl/SSLSocket.c +++ b/shared-bindings/ssl/SSLSocket.c @@ -106,7 +106,7 @@ static MP_DEFINE_CONST_FUN_OBJ_2(ssl_sslsocket_connect_obj, ssl_sslsocket_connec //| def listen(self, backlog: int) -> None: //| """Set socket to listen for incoming connections //| -//| :param ~int backlog: length of backlog queue for waiting connetions""" +//| :param ~int backlog: length of backlog queue for waiting connections""" //| ... //| static mp_obj_t ssl_sslsocket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { @@ -291,7 +291,7 @@ static mp_uint_t sslsocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si return readwrite_common(self_in, common_hal_ssl_sslsocket_send, buf, size, errorcode); } -static mp_uint_t sslsocket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t sslsocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/shared-bindings/ssl/__init__.c b/shared-bindings/ssl/__init__.c index 0d10090e9cb..51a3ad3cfc4 100644 --- a/shared-bindings/ssl/__init__.c +++ b/shared-bindings/ssl/__init__.c @@ -27,9 +27,9 @@ static mp_obj_t ssl_create_default_context(void) { ssl_sslcontext_obj_t *s = mp_obj_malloc(ssl_sslcontext_obj_t, &ssl_sslcontext_type); - common_hal_ssl_create_default_context(s); - return s; + + return MP_OBJ_FROM_PTR(s); } MP_DEFINE_CONST_FUN_OBJ_0(ssl_create_default_context_obj, ssl_create_default_context); diff --git a/shared-bindings/storage/__init__.c b/shared-bindings/storage/__init__.c index 14ec16f3096..b5f19529be1 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -93,7 +93,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(storage_umount_obj, storage_umount); //| ) -> None: //| """Remounts the given path with new parameters. //| -//| This can always be done from boot.py. After boot, it can only be done when the host computer +//| This can always be done from ``boot.py``. After boot, it can only be done when the host computer //| doesn't have write access and CircuitPython isn't currently writing to the filesystem. An //| exception will be raised if this is the case. Some host OSes allow you to eject a drive which //| will allow for remounting. @@ -140,24 +140,24 @@ static mp_obj_t storage_getmount(const mp_obj_t mnt_in) { MP_DEFINE_CONST_FUN_OBJ_1(storage_getmount_obj, storage_getmount); //| def erase_filesystem(extended: Optional[bool] = None) -> None: -//| """Erase and re-create the ``CIRCUITPY`` filesystem. +//| """Erase and re-create the **CIRCUITPY** filesystem. //| -//| On boards that present USB-visible ``CIRCUITPY`` drive (e.g., SAMD21 and SAMD51), +//| On boards that present USB-visible **CIRCUITPY** drive (e.g., SAMD21 and SAMD51), //| then call `microcontroller.reset()` to restart CircuitPython and have the -//| host computer remount CIRCUITPY. +//| host computer remount **CIRCUITPY**. //| -//| This function can be called from the REPL when ``CIRCUITPY`` +//| This function can be called from the REPL when **CIRCUITPY** //| has become corrupted. //| //| :param bool extended: On boards that support ``dualbank`` module -//| and the ``extended`` parameter, the ``CIRCUITPY`` storage can be +//| and the ``extended`` parameter, the **CIRCUITPY** storage can be //| extended by setting this to `True`. If this isn't provided or //| set to `None` (default), the existing configuration will be used. //| //| .. note:: New firmware starts with storage extended. In case of an existing //| filesystem (e.g. uf2 load), the existing extension setting is preserved. //| -//| .. warning:: All the data on ``CIRCUITPY`` will be lost, and +//| .. warning:: All the data on **CIRCUITPY** will be lost, and //| CircuitPython will restart on certain boards.""" //| ... //| @@ -187,9 +187,11 @@ static mp_obj_t storage_erase_filesystem(size_t n_args, const mp_obj_t *pos_args MP_DEFINE_CONST_FUN_OBJ_KW(storage_erase_filesystem_obj, 0, storage_erase_filesystem); //| def disable_usb_drive() -> None: -//| """Disable presenting ``CIRCUITPY`` as a USB mass storage device. -//| By default, the device is enabled and ``CIRCUITPY`` is visible. -//| Can be called in ``boot.py``, before USB is connected.""" +//| """Disable presenting **CIRCUITPY** as a USB mass storage device. +//| By default, the device is enabled and **CIRCUITPY** is visible, if USB is available. +//| Must called in ``boot.py``, before USB is connected. +// If you want to disable the USB drive after `boot.py` has run, see `unsafe_disable_usb_drive()`. +//| """ //| ... //| //| @@ -205,15 +207,82 @@ static mp_obj_t storage_disable_usb_drive(void) { } MP_DEFINE_CONST_FUN_OBJ_0(storage_disable_usb_drive_obj, storage_disable_usb_drive); +//| def unsafe_disable_usb_drive() -> None: +//| """Disable presenting **CIRCUITPY** as a USB mass storage device even if in use. +//| By default, the device is enabled and **CIRCUITPY** is visible. +//| After the call, **CIRCUITPY** will be read/write to your code and from the REPL but not appear over USB. +//| +//| Unlike `disable_usb_drive()`, `unsafe_disable_usb_drive()` can be called +//| after ``code.py`` starts or from the REPL, after USB has started. +//| +//| .. warning:: If ``unsafe_disable_usb_drive()`` is called when the host is in the middle of writing **CIRCUITPY**, +//| filesystem corruption can occur. +//| It is similar to the sudden physical removal of a USB drive. +//| Before calling ``unsafe_disable_usb_drive()``, +//| make sure the host has finished any writes to **CIRCUITPY**. +//| +//| * On Windows, do one of these: +//| +//| * Eject ("Safely Remove") the **CIRCUITPY** drive. +//| * Use a "sync" program, such as `Sysinternals Sync `__. +//| * Programmatically call ``_commit()`` or ``_flushall()`` or similar. +//| +//| * On Linux or macOS, do one of these: +//| +//| * Eject (unmount) the **CIRCUITPY** drive. +//| * Type ``sync`` in a terminal. +//| * Programmatically call ``sync()`` or ``fsync()``. +//| +//| * If none of the above are possible or convenient, wait several seconds to allow any writes to complete. +//| This can be unreliable, as the interval to wait depends on the host operating system +//| and how the drive is mounted. +//| In some operating systems, you can specify that the drive be mounted as "sync on write", +//| so that all writes happen immediately. +//| +//| When `unsafe_disable_usb_drive()` is called after USB has started, +//| the **CIRCUITPY** USB drive logical unit (LUN) will report as "not ready", +//| causing the host to unmount it. +//| The drive can be made ready and available again by calling `enable_usb_drive()`. +//| When `disable_usb_drive` is called after ``code.py`` starts or in the REPL, +//| the call will delay 2.5 seconds before returning, +//| so that host has time to detect that the drive is not ready. +//| The host polls the device approximately every one or two seconds. +//| +//| When the USB drive is disabled, **CIRCUITPY** becomes read/write, and can be written +//| from user code or the REPL. This is easier than arranging for a `remount()` in ``boot.py``. +//| Code editors and file uploaders can use this feature to write files via the REPL. +//| +//| If `unsafe_disable_usb_drive()` is called in ``boot.py``, it is identical to calling +//| `disable_usb_drive()`. +//| """ +//| ... +//| +//| +static mp_obj_t storage_unsafe_disable_usb_drive(void) { + #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_MSC + if (!common_hal_storage_unsafe_disable_usb_drive()) { + #else + if (true) { + #endif + mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot change USB devices now")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(storage_unsafe_disable_usb_drive_obj, storage_unsafe_disable_usb_drive); + //| def enable_usb_drive() -> None: -//| """Enabled presenting ``CIRCUITPY`` as a USB mass storage device. -//| By default, the device is enabled and ``CIRCUITPY`` is visible, -//| so you do not normally need to call this function. -//| Can be called in ``boot.py``, before USB is connected. +//| """Enable presenting **CIRCUITPY** as a USB mass storage device. +//| By default, the device is enabled and **CIRCUITPY** is visible, +//| so you do not normally need to call this function in ``boot.py``. +//| +//| If you call `enable_usb_drive()` after ``code.py`` starts or in the REPL, +//| you can reverse the effect of a previous `unsafe_disable_usb_drive()`. +//| The **CIRCUITPY** drive will reappear to the host, and become read-only again +//| if it was previously read-only. //| -//| If you enable too many devices at once, you will run out of USB endpoints. +//| If you enable too many USB devices at once, you will run out of USB endpoints. //| The number of available endpoints varies by microcontroller. -//| CircuitPython will go into safe mode after running boot.py to inform you if +//| CircuitPython will go into safe mode after running ``boot.py`` to inform you if //| not enough endpoints are available. //| """ //| ... @@ -234,13 +303,14 @@ MP_DEFINE_CONST_FUN_OBJ_0(storage_enable_usb_drive_obj, storage_enable_usb_drive static const mp_rom_map_elem_t storage_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_storage) }, - { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&storage_mount_obj) }, - { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&storage_umount_obj) }, - { MP_ROM_QSTR(MP_QSTR_remount), MP_ROM_PTR(&storage_remount_obj) }, - { MP_ROM_QSTR(MP_QSTR_getmount), MP_ROM_PTR(&storage_getmount_obj) }, - { MP_ROM_QSTR(MP_QSTR_erase_filesystem), MP_ROM_PTR(&storage_erase_filesystem_obj) }, - { MP_ROM_QSTR(MP_QSTR_disable_usb_drive), MP_ROM_PTR(&storage_disable_usb_drive_obj) }, - { MP_ROM_QSTR(MP_QSTR_enable_usb_drive), MP_ROM_PTR(&storage_enable_usb_drive_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&storage_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&storage_umount_obj) }, + { MP_ROM_QSTR(MP_QSTR_remount), MP_ROM_PTR(&storage_remount_obj) }, + { MP_ROM_QSTR(MP_QSTR_getmount), MP_ROM_PTR(&storage_getmount_obj) }, + { MP_ROM_QSTR(MP_QSTR_erase_filesystem), MP_ROM_PTR(&storage_erase_filesystem_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_usb_drive), MP_ROM_PTR(&storage_disable_usb_drive_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_usb_drive), MP_ROM_PTR(&storage_enable_usb_drive_obj) }, + { MP_ROM_QSTR(MP_QSTR_unsafe_disable_usb_drive), MP_ROM_PTR(&storage_unsafe_disable_usb_drive_obj) }, //| class VfsFat: //| def __init__(self, block_device: BlockDevice) -> None: diff --git a/shared-bindings/storage/__init__.h b/shared-bindings/storage/__init__.h index ed3e8d44e4a..0e53c78b153 100644 --- a/shared-bindings/storage/__init__.h +++ b/shared-bindings/storage/__init__.h @@ -16,7 +16,8 @@ void common_hal_storage_umount_path(const char *path); void common_hal_storage_umount_object(mp_obj_t vfs_obj); void common_hal_storage_remount(const char *path, bool readonly, bool disable_concurrent_write_protection); mp_obj_t common_hal_storage_getmount(const char *path); -NORETURN void common_hal_storage_erase_filesystem(bool extended); +MP_NORETURN void common_hal_storage_erase_filesystem(bool extended); bool common_hal_storage_disable_usb_drive(void); +bool common_hal_storage_unsafe_disable_usb_drive(void); bool common_hal_storage_enable_usb_drive(void); diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c index 7b497639939..5b2885f26c0 100644 --- a/shared-bindings/supervisor/Runtime.c +++ b/shared-bindings/supervisor/Runtime.c @@ -20,12 +20,12 @@ #include "supervisor/shared/status_leds.h" #include "supervisor/shared/bluetooth/bluetooth.h" -#if CIRCUITPY_DISPLAYIO -#include "shared-bindings/displayio/__init__.h" +#if CIRCUITPY_USB_DEVICE +#include "supervisor/usb.h" #endif -#if CIRCUITPY_TINYUSB -#include "tusb.h" +#if CIRCUITPY_DISPLAYIO +#include "shared-bindings/displayio/__init__.h" #endif static supervisor_run_reason_t _run_reason; @@ -52,7 +52,7 @@ static supervisor_run_reason_t _run_reason; //| """Returns the USB enumeration status (read-only).""" static mp_obj_t supervisor_runtime_get_usb_connected(mp_obj_t self) { #if CIRCUITPY_USB_DEVICE - return mp_obj_new_bool(tud_ready()); + return mp_obj_new_bool(usb_connected()); #else return mp_const_false; #endif @@ -153,10 +153,13 @@ MP_PROPERTY_GETSET(supervisor_runtime_autoreload_obj, //| ble_workflow: bool //| """Enable/Disable ble workflow until a reset. This prevents BLE advertising outside of the VM and -//| the services used for it.""" +//| the services used for it. +//| If ``CIRCUITPY_BLE_WORKFLOW=false`` is present in ``settings.toml``, setting `ble_workflow` +//| to ``True`` has no effect. +//| """ //| static mp_obj_t supervisor_runtime_get_ble_workflow(mp_obj_t self) { - #if CIRCUITPY_BLE_FILE_SERVICE && CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE && CIRCUITPY_BLE_SERIAL_SERVICE return mp_obj_new_bool(supervisor_bluetooth_workflow_is_enabled()); #else return mp_const_false; @@ -165,7 +168,7 @@ static mp_obj_t supervisor_runtime_get_ble_workflow(mp_obj_t self) { MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_ble_workflow_obj, supervisor_runtime_get_ble_workflow); static mp_obj_t supervisor_runtime_set_ble_workflow(mp_obj_t self, mp_obj_t state_in) { - #if CIRCUITPY_BLE_FILE_SERVICE && CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE && CIRCUITPY_BLE_SERIAL_SERVICE if (mp_obj_is_true(state_in)) { supervisor_bluetooth_enable_workflow(); } else { diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c index f2fc14c3c9a..a331249998a 100644 --- a/shared-bindings/supervisor/__init__.c +++ b/shared-bindings/supervisor/__init__.c @@ -21,6 +21,10 @@ #include "supervisor/usb.h" #endif +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/supervisor/__init__.h" #include "shared-bindings/time/__init__.h" @@ -360,6 +364,71 @@ static mp_obj_t supervisor_set_usb_identification(size_t n_args, const mp_obj_t } MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_usb_identification_obj, 0, supervisor_set_usb_identification); +//| def get_setting(key: str, default: object=None) -> int | float | str | bool: +//| """ +//| Get and parse the value for the given ``key`` from the ``/settings.toml`` file. +//| If ``key`` is not found or ``settings.toml`` is not present, return the ``default`` value. +//| +//| :param str key: The setting key to retrieve +//| :return: The setting value as an ``int``, ``float``, ``str``, or ``bool`` depending on the value in the file +//| +//| :raises ValueError: If the value cannot be parsed as a valid TOML value. +//| +//| The value must be parseable as one of these types: +//| +//| - ``str``: Double-quoted string. +//| The string may include Unicode characters, and ``\\u`` Unicode escapes. Backslash-escaped characters +//| ``\\b``, ``\\r``, ``\\n``, ``\\t``, ``\\v``, ``\\v`` are also allowed. +//| - ``int``: signed or unsigned integer. +//| - ``bool``: lower-case ``true`` or ``false``. +//| The values are returned as Python ``True`` or ``False`` values. +//| - ``float``: signed or unsigned decimal number with a ``.`` or exponent, or ``inf``, ``inf``, ``nan``. +//| +//| Example:: +//| +//| # settings.toml: +//| WIDTH = 42 +//| color = "red" +//| DEBUG = true +//| RATIO = 1.5 +//| +//| import supervisor +//| print(supervisor.get_setting("WIDTH")) # prints 42 +//| print(supervisor.get_setting("color")) # prints 'red' +//| print(supervisor.get_setting("DEBUG")) # prints True +//| print(supervisor.get_setting("RATIO")) # prints 1.5 +//| """ +//| ... +//| +static mp_obj_t supervisor_get_setting(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + #if CIRCUITPY_SETTINGS_TOML + enum { ARG_key, ARG_default }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_key, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_default, MP_ARG_OBJ, {.u_rom_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, (mp_arg_val_t *)&args); + + const char *key = mp_obj_str_get_str(args[ARG_key].u_obj); + mp_obj_t value; + settings_err_t result = settings_get_obj(key, &value); + + switch (result) { + case SETTINGS_OK: + return value; + case SETTINGS_ERR_NOT_FOUND: + case SETTINGS_ERR_OPEN: + return args[ARG_default].u_obj; + default: + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_value); + } + #else + mp_raise_NotImplementedError(NULL); + #endif +} +MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_get_setting_obj, 1, supervisor_get_setting); + static const mp_rom_map_elem_t supervisor_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) }, { MP_ROM_QSTR(MP_QSTR_runtime), MP_ROM_PTR(&common_hal_supervisor_runtime_obj) }, @@ -373,6 +442,7 @@ static const mp_rom_map_elem_t supervisor_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_set_next_code_file), MP_ROM_PTR(&supervisor_set_next_code_file_obj) }, { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&supervisor_ticks_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_get_previous_traceback), MP_ROM_PTR(&supervisor_get_previous_traceback_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_setting), MP_ROM_PTR(&supervisor_get_setting_obj) }, { MP_ROM_QSTR(MP_QSTR_reset_terminal), MP_ROM_PTR(&supervisor_reset_terminal_obj) }, { MP_ROM_QSTR(MP_QSTR_set_usb_identification), MP_ROM_PTR(&supervisor_set_usb_identification_obj) }, { MP_ROM_QSTR(MP_QSTR_status_bar), MP_ROM_PTR(&shared_module_supervisor_status_bar_obj) }, diff --git a/shared-bindings/synthio/LFO.c b/shared-bindings/synthio/LFO.c index ee2d67d3089..2dfae22a577 100644 --- a/shared-bindings/synthio/LFO.c +++ b/shared-bindings/synthio/LFO.c @@ -103,17 +103,17 @@ static mp_obj_t synthio_lfo_make_new(const mp_obj_type_t *type_in, size_t n_args } self->waveform_obj = args[ARG_waveform].u_obj; - mp_obj_t result = MP_OBJ_FROM_PTR(self); - properties_construct_helper(result, lfo_properties + 1, args + 1, MP_ARRAY_SIZE(lfo_properties) - 1); + mp_obj_t self_obj = MP_OBJ_FROM_PTR(self); + properties_construct_helper(self_obj, lfo_properties + 1, args + 1, MP_ARRAY_SIZE(lfo_properties) - 1); // Force computation of the LFO's initial output synthio_global_rate_scale = 0; self->base.last_tick = synthio_global_tick - 1; synthio_block_slot_t slot; - synthio_block_assign_slot(MP_OBJ_FROM_PTR(result), &slot, MP_QSTR_self); + synthio_block_assign_slot(self_obj, &slot, MP_QSTR_self); (void)synthio_block_slot_get(&slot); - return result; + return self_obj; }; //| waveform: Optional[ReadableBuffer] diff --git a/shared-bindings/synthio/Math.c b/shared-bindings/synthio/Math.c index 5e943b44d0f..96857fb3513 100644 --- a/shared-bindings/synthio/Math.c +++ b/shared-bindings/synthio/Math.c @@ -157,10 +157,10 @@ static mp_obj_t synthio_math_make_new_common(mp_arg_val_t args[MP_ARRAY_SIZE(mat self->base.last_tick = synthio_global_tick; - mp_obj_t result = MP_OBJ_FROM_PTR(self); - properties_construct_helper(result, math_properties, args, MP_ARRAY_SIZE(math_properties)); + mp_obj_t self_obj = MP_OBJ_FROM_PTR(self); + properties_construct_helper(self_obj, math_properties, args, MP_ARRAY_SIZE(math_properties)); - return result; + return self_obj; }; //| a: BlockInput diff --git a/shared-bindings/synthio/MidiTrack.c b/shared-bindings/synthio/MidiTrack.c index db75a543c61..6adb11e06c3 100644 --- a/shared-bindings/synthio/MidiTrack.c +++ b/shared-bindings/synthio/MidiTrack.c @@ -70,10 +70,9 @@ static mp_obj_t synthio_miditrack_make_new(const mp_obj_type_t *type, size_t n_a mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); synthio_miditrack_obj_t *self = mp_obj_malloc(synthio_miditrack_obj_t, &synthio_miditrack_type); - common_hal_synthio_miditrack_construct(self, (uint8_t *)bufinfo.buf, bufinfo.len, - args[ARG_tempo].u_int, + mp_arg_validate_int_min(args[ARG_tempo].u_int, 1, MP_QSTR_tempo), args[ARG_sample_rate].u_int, args[ARG_waveform].u_obj, mp_const_none, diff --git a/shared-bindings/synthio/Note.c b/shared-bindings/synthio/Note.c index 95dd51fe6b0..183c59d5fbd 100644 --- a/shared-bindings/synthio/Note.c +++ b/shared-bindings/synthio/Note.c @@ -61,11 +61,11 @@ static mp_obj_t synthio_note_make_new(const mp_obj_type_t *type_in, size_t n_arg mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(note_properties), note_properties, args); synthio_note_obj_t *self = mp_obj_malloc(synthio_note_obj_t, &synthio_note_type); + mp_obj_t self_obj = MP_OBJ_FROM_PTR(self); - mp_obj_t result = MP_OBJ_FROM_PTR(self); - properties_construct_helper(result, note_properties, args, MP_ARRAY_SIZE(note_properties)); + properties_construct_helper(self_obj, note_properties, args, MP_ARRAY_SIZE(note_properties)); - return result; + return self_obj; }; //| frequency: float diff --git a/shared-bindings/synthio/Synthesizer.c b/shared-bindings/synthio/Synthesizer.c index fb39e8ef50e..a5d053df302 100644 --- a/shared-bindings/synthio/Synthesizer.c +++ b/shared-bindings/synthio/Synthesizer.c @@ -62,9 +62,8 @@ static mp_obj_t synthio_synthesizer_make_new(const mp_obj_type_t *type, size_t n mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); synthio_synthesizer_obj_t *self = mp_obj_malloc(synthio_synthesizer_obj_t, &synthio_synthesizer_type); - common_hal_synthio_synthesizer_construct(self, - args[ARG_sample_rate].u_int, + mp_arg_validate_int_min(args[ARG_sample_rate].u_int, 1, MP_QSTR_sample_rate), args[ARG_channel_count].u_int, args[ARG_waveform].u_obj, args[ARG_envelope].u_obj); diff --git a/shared-bindings/synthio/__init__.c b/shared-bindings/synthio/__init__.c index 6d42880541d..5ef0b58b710 100644 --- a/shared-bindings/synthio/__init__.c +++ b/shared-bindings/synthio/__init__.c @@ -252,19 +252,12 @@ static mp_obj_t synthio_from_file(size_t n_args, const mp_obj_t *pos_args, mp_ma } synthio_miditrack_obj_t *result = mp_obj_malloc(synthio_miditrack_obj_t, &synthio_miditrack_type); - common_hal_synthio_miditrack_construct(result, buffer, track_size, tempo, args[ARG_sample_rate].u_int, args[ARG_waveform].u_obj, mp_const_none, args[ARG_envelope].u_obj ); - #if MICROPY_MALLOC_USES_ALLOCATED_SIZE - m_free(buffer, track_size); - #else - m_free(buffer); - #endif - return MP_OBJ_FROM_PTR(result); } MP_DEFINE_CONST_FUN_OBJ_KW(synthio_from_file_obj, 1, synthio_from_file); diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c index f8394dcc17d..320d4cc667a 100644 --- a/shared-bindings/terminalio/Terminal.c +++ b/shared-bindings/terminalio/Terminal.c @@ -21,7 +21,10 @@ #endif //| class Terminal: -//| """Display a character stream with a TileGrid +//| """Terminal manages tile indices and cursor position based on VT100 commands. The ``font`` should be +//| a `fontio.BuiltinFont` and the ``scroll_area`` TileGrid's bitmap should match the font's bitmap. +//| +//| Display a character stream with a TileGrid //| //| ASCII control: //| @@ -75,6 +78,52 @@ //| +--------+------------+------------+ //| | White | 37 | 47 | //| +--------+------------+------------+ +//| +//| Example Usage: +//| +//| .. code-block:: python +//| +//| import time +//| import displayio +//| import supervisor +//| from displayio import Group, TileGrid +//| from terminalio import FONT, Terminal +//| +//| main_group = Group() +//| display = supervisor.runtime.display +//| font_bb = FONT.get_bounding_box() +//| screen_size = (display.width // font_bb[0], display.height // font_bb[1]) +//| char_size = FONT.get_bounding_box() +//| +//| palette = displayio.Palette(2) +//| palette[0] = 0x000000 +//| palette[1] = 0xffffff +//| +//| tilegrid = TileGrid( +//| bitmap=FONT.bitmap, width=screen_size[0], height=screen_size[1], +//| tile_width=char_size[0], tile_height=char_size[1], pixel_shader=palette) +//| +//| terminal = Terminal(tilegrid, FONT) +//| +//| main_group.append(tilegrid) +//| display.root_group = main_group +//| +//| message = "Hello World\\n" +//| terminal.write(message) +//| +//| print(terminal.cursor_x, terminal.cursor_y) +//| move_cursor = chr(27) + "[10;10H" +//| terminal.write(f"Moving the cursor\\n{move_cursor} To here") +//| +//| cursor_home = chr(27) + f"[{screen_size[1]};0H" +//| terminal.write(cursor_home) +//| i = 1 +//| while True: +//| terminal.write(f"Writing again {i}\\n") +//| i = i + 1 +//| time.sleep(1) +//| +//| //| """ //| //| def __init__( @@ -84,8 +133,6 @@ //| *, //| status_bar: Optional[displayio.TileGrid] = None, //| ) -> None: -//| """Terminal manages tile indices and cursor position based on VT100 commands. The font should be -//| a `fontio.BuiltinFont` and the TileGrid's bitmap should match the font's bitmap.""" //| ... //| @@ -129,8 +176,8 @@ static mp_obj_t terminalio_terminal_make_new(const mp_obj_type_t *type, size_t n mp_arg_validate_int_min(scroll_area->width_in_tiles * scroll_area->height_in_tiles, 2, MP_QSTR_scroll_area_area); terminalio_terminal_obj_t *self = mp_obj_malloc(terminalio_terminal_obj_t, &terminalio_terminal_type); - common_hal_terminalio_terminal_construct(self, scroll_area, font, status_bar); + return MP_OBJ_FROM_PTR(self); } @@ -175,7 +222,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(terminalio_terminal_get_cursor_y_obj, terminalio_termi MP_PROPERTY_GETTER(terminalio_terminal_cursor_y_obj, (mp_obj_t)&terminalio_terminal_get_cursor_y_obj); -static mp_uint_t terminalio_terminal_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t terminalio_terminal_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { terminalio_terminal_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/shared-bindings/tilepalettemapper/TilePaletteMapper.c b/shared-bindings/tilepalettemapper/TilePaletteMapper.c index ed3e928957f..c22ea47bf26 100644 --- a/shared-bindings/tilepalettemapper/TilePaletteMapper.c +++ b/shared-bindings/tilepalettemapper/TilePaletteMapper.c @@ -45,7 +45,6 @@ static mp_obj_t tilepalettemapper_tilepalettemapper_make_new(const mp_obj_type_t mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported %q type"), MP_QSTR_pixel_shader); } - tilepalettemapper_tilepalettemapper_t *self = mp_obj_malloc(tilepalettemapper_tilepalettemapper_t, &tilepalettemapper_tilepalettemapper_type); common_hal_tilepalettemapper_tilepalettemapper_construct(self, pixel_shader, args[ARG_input_color_count].u_int); diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 8a591da3688..b6d36baeb5f 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -22,12 +22,12 @@ //| //| //| def monotonic() -> float: -//| """Returns an always increasing value of time with an unknown reference +//| """Returns an always increasing value of time, in fractional seconds, with an unknown reference //| point. Only use it to compare against other values from `time.monotonic()` //| during the same code run. //| //| On most boards, `time.monotonic()` converts a 64-bit millisecond tick counter -//| to a float. Floats on most boards are encoded in 30 bits internally, with +//| to seconds, as a float. Floats on most boards are encoded in 30 bits internally, with //| effectively 22 bits of precision. The float returned by `time.monotonic()` will //| accurately represent time to millisecond precision only up to 2**22 milliseconds //| (about 1.165 hours). @@ -206,7 +206,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); //| def monotonic_ns() -> int: //| """Return the time of the monotonic clock, which cannot go backward, in nanoseconds. //| Not available on boards without long integer support. -//| Only use it to compare against other values from `time.monotonic()` +//| Only use it to compare against other values from `time.monotonic_ns()` //| during a single code run. //| //| :return: the current time diff --git a/shared-bindings/touchio/TouchIn.c b/shared-bindings/touchio/TouchIn.c index 19d97bd9d7c..2250e88f599 100644 --- a/shared-bindings/touchio/TouchIn.c +++ b/shared-bindings/touchio/TouchIn.c @@ -56,7 +56,7 @@ static mp_obj_t touchio_touchin_make_new(const mp_obj_type_t *type, touchio_touchin_obj_t *self = mp_obj_malloc(touchio_touchin_obj_t, &touchio_touchin_type); common_hal_touchio_touchin_construct(self, pin, pull); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: diff --git a/shared-bindings/traceback/__init__.c b/shared-bindings/traceback/__init__.c index ca1e6fe976a..651ec2c0142 100644 --- a/shared-bindings/traceback/__init__.c +++ b/shared-bindings/traceback/__init__.c @@ -36,10 +36,18 @@ static void traceback_exception_common(bool is_print_exception, mp_print_t *prin mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t value = args[ARG_value].u_obj; + mp_obj_t tb_obj = args[ARG_tb].u_obj; + + // Both or neither of value and tb must be supplied. + if ((value != MP_OBJ_NULL && tb_obj == MP_OBJ_NULL) || + (value == MP_OBJ_NULL && tb_obj != MP_OBJ_NULL)) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Supply both or neither of %q and %q"), MP_QSTR_value, MP_QSTR_tb); + } + if (value == MP_OBJ_NULL) { value = args[ARG_exc].u_obj; } - mp_obj_t tb_obj = args[ARG_tb].u_obj; + mp_obj_t limit_obj = args[ARG_limit].u_obj; #if MICROPY_CPYTHON_EXCEPTION_CHAIN bool chain = args[ARG_chain].u_bool; @@ -105,21 +113,21 @@ static void traceback_exception_common(bool is_print_exception, mp_print_t *prin //| def format_exception( //| exc: BaseException | Type[BaseException], //| /, -//| value: Optional[BaseException] = None, +//| value: BaseException, //| tb: Optional[TracebackType] = None, //| limit: Optional[int] = None, //| chain: Optional[bool] = True, //| ) -> List[str]: //| """Format a stack trace and the exception information. //| -//| If the exception value is passed in ``exc``, then this exception value and its -//| associated traceback are used. This is compatible with CPython 3.10 and newer. +//| If the exception value is passed in ``exc``, and ``value`` and ``tb`` are not supplied, +//| then this exception value and its associated traceback are used. +//| This is compatible with CPython 3.10 and newer. //| -//| If the exception value is passed in ``value``, then any value passed in for -//| ``exc`` is ignored. ``value`` is used as the exception value and the -//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is None, -//| no traceback will be shown. This is compatible with CPython 3.5 and -//| newer. +//| If the exception value is passed in ``value``, then both ``value`` and ``tb`` must be supplied. +//| Any value passed in for ``exc`` is *ignored*. ``value`` is used as the exception value and the +//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is `None`, +//| no traceback will be shown. This is compatible with CPython 3.5 and newer. //| //| The arguments have the same meaning as the corresponding arguments //| to print_exception(). The return value is a list of strings, each @@ -128,8 +136,8 @@ static void traceback_exception_common(bool is_print_exception, mp_print_t *prin //| printed as does print_exception(). //| //| :param exc: The exception. Must be an instance of `BaseException`. Unused if value is specified. -//| :param value: If specified, is used in place of ``exc``. -//| :param TracebackType tb: When value is alsp specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed. +//| :param value: If specified, is used in place of ``exc``, and ``tb`` must also be specified. +//| :param tb: When ``value`` is also specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed. //| :param int limit: Print up to limit stack trace entries (starting from the caller’s frame) if limit is positive. //| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed. //| :param bool chain: If `True` then chained exceptions will be printed. @@ -150,7 +158,7 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(traceback_format_exception_obj, 0, traceback_f //| def print_exception( //| exc: BaseException | Type[BaseException], //| /, -//| value: Optional[BaseException] = None, +//| value: BaseException, //| tb: Optional[TracebackType] = None, //| limit: Optional[int] = None, //| file: Optional[io.FileIO] = None, @@ -158,18 +166,18 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(traceback_format_exception_obj, 0, traceback_f //| ) -> None: //| """Prints exception information and stack trace entries. //| -//| If the exception value is passed in ``exc``, then this exception value and its -//| associated traceback are used. This is compatible with CPython 3.10 and newer. +//| If the exception value is passed in ``exc``, and ``value`` and ``tb`` are not supplied, +//| then this exception value and its associated traceback are used. +//| This is compatible with CPython 3.10 and newer. //| -//| If the exception value is passed in ``value``, then any value passed in for -//| ``exc`` is ignored. ``value`` is used as the exception value and the -//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is None, -//| no traceback will be shown. This is compatible with CPython 3.5 and -//| newer. +//| If the exception value is passed in ``value``, then both ``value`` and ``tb`` must be supplied. +//| Any value passed in for ``exc`` is *ignored*. ``value`` is used as the exception value and the +//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is `None`, +//| no traceback will be shown. This is compatible with CPython 3.5 and newer. //| //| :param exc: The exception. Must be an instance of `BaseException`. Unused if value is specified. -//| :param value: If specified, is used in place of ``exc``. -//| :param tb: When value is alsp specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed. +//| :param value: If specified, is used in place of ``exc``, and ``tb`` must also be specified. +//| :param tb: When ``value`` is also specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed. //| :param int limit: Print up to limit stack trace entries (starting from the caller’s frame) if limit is positive. //| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed. //| :param io.FileIO file: If file is omitted or `None`, the output goes to `sys.stderr`; otherwise it should be an open diff --git a/shared-bindings/usb/core/Device.c b/shared-bindings/usb/core/Device.c index 683115a8421..bc6c6296899 100644 --- a/shared-bindings/usb/core/Device.c +++ b/shared-bindings/usb/core/Device.c @@ -226,23 +226,35 @@ MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_write_obj, 2, usb_core_device_write); //| def read( -//| self, endpoint: int, size_or_buffer: array.array, timeout: Optional[int] = None +//| self, +//| endpoint: int, +//| size_or_buffer: array.array, +//| timeout: Optional[int] = None, +//| *, +//| raise_on_timeout: bool = True, //| ) -> int: //| """Read data from the endpoint. //| //| :param int endpoint: the bEndpointAddress you want to communicate with. //| :param array.array size_or_buffer: the array to read data into. PyUSB also allows size but CircuitPython only support array to force deliberate memory use. //| :param int timeout: Time to wait specified in milliseconds. (Different from most CircuitPython!) +//| :param bool raise_on_timeout: when False, an elapsed timeout returns ``0`` +//| instead of raising `usb.core.USBTimeoutError`. Polling an interrupt +//| endpoint every frame (e.g. a HID gamepad in a game loop) treats "no +//| new report yet" as a normal outcome; the exception object each such +//| poll would otherwise allocate is measurable garbage-collector +//| pressure on small heaps. //| :returns: the number of bytes read //| """ //| ... //| static mp_obj_t usb_core_device_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_endpoint, ARG_size_or_buffer, ARG_timeout }; + enum { ARG_endpoint, ARG_size_or_buffer, ARG_timeout, ARG_raise_on_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_size_or_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_raise_on_timeout, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_for_deinit(self); @@ -252,7 +264,7 @@ static mp_obj_t usb_core_device_read(size_t n_args, const mp_obj_t *pos_args, mp mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_size_or_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); - return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_read(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int)); + return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_read(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int, args[ARG_raise_on_timeout].u_bool)); } MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_read_obj, 2, usb_core_device_read); diff --git a/shared-bindings/usb/core/Device.h b/shared-bindings/usb/core/Device.h index 28c2cfbe198..51338f61228 100644 --- a/shared-bindings/usb/core/Device.h +++ b/shared-bindings/usb/core/Device.h @@ -26,7 +26,7 @@ mp_int_t common_hal_usb_core_device_get_speed(usb_core_device_obj_t *self); void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, mp_int_t configuration); mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t endpoint, const uint8_t *buffer, mp_int_t len, mp_int_t timeout); -mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout); +mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout, bool raise_on_timeout); mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, mp_int_t bmRequestType, mp_int_t bRequest, mp_int_t wValue, mp_int_t wIndex, diff --git a/shared-bindings/usb/core/__init__.c b/shared-bindings/usb/core/__init__.c index 545e182ea99..29dab285084 100644 --- a/shared-bindings/usb/core/__init__.c +++ b/shared-bindings/usb/core/__init__.c @@ -30,7 +30,7 @@ //| //| MP_DEFINE_USB_CORE_EXCEPTION(USBError, OSError) -NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...) { +MP_NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...) { mp_obj_t exception; if (fmt == NULL) { exception = mp_obj_new_exception(&mp_type_usb_core_USBError); @@ -50,7 +50,7 @@ NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...) { //| //| MP_DEFINE_USB_CORE_EXCEPTION(USBTimeoutError, usb_core_USBError) -NORETURN void mp_raise_usb_core_USBTimeoutError(void) { +MP_NORETURN void mp_raise_usb_core_USBTimeoutError(void) { mp_raise_type(&mp_type_usb_core_USBTimeoutError); } @@ -90,9 +90,10 @@ static mp_obj_t _next_device(usb_core_devices_obj_t *iter) { // We passed the filters. Now make a properly allocated object to // return to the user. usb_core_device_obj_t *self = mp_obj_malloc(usb_core_device_obj_t, &usb_core_device_type); - common_hal_usb_core_device_construct(self, i); + iter->next_index = i + 1; + return MP_OBJ_FROM_PTR(self); } // Iter is done. diff --git a/shared-bindings/usb/core/__init__.h b/shared-bindings/usb/core/__init__.h index 0dc08fae532..adb8430a6c3 100644 --- a/shared-bindings/usb/core/__init__.h +++ b/shared-bindings/usb/core/__init__.h @@ -25,8 +25,8 @@ void usb_core_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_k extern const mp_obj_type_t mp_type_usb_core_USBError; extern const mp_obj_type_t mp_type_usb_core_USBTimeoutError; -NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_usb_core_USBTimeoutError(void); +MP_NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_usb_core_USBTimeoutError(void); // Find is all Python object oriented so we don't need a separate common-hal API // for it. It uses the device common-hal instead. diff --git a/shared-bindings/usb_audio/USBMicrophone.c b/shared-bindings/usb_audio/USBMicrophone.c new file mode 100644 index 00000000000..c66c78942dd --- /dev/null +++ b/shared-bindings/usb_audio/USBMicrophone.c @@ -0,0 +1,178 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/usb_audio/USBMicrophone.h" +#include "shared-bindings/util.h" +#include "shared-module/usb_audio/__init__.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" + +//| class USBMicrophone: +//| """Streams an audio sample to the host computer as a USB Audio Class microphone. +//| +//| A ``USBMicrophone`` is a *consumer* of an audio sample, exactly like +//| `audioio.AudioOut`, `audiobusio.I2SOut` and `audiopwmio.PWMAudioOut`. The +//| samples it pulls are streamed to the host PC over USB rather than to a pin, +//| so the board appears as a microphone. +//| +//| You cannot create an instance of `usb_audio.USBMicrophone`. +//| +//| There is a single shared instance, available as ``usb_audio.usb_microphone`` +//| once ``usb_audio.enable()`` has configured an input (microphone) stream in +//| ``boot.py``. Until then ``usb_audio.usb_microphone`` is ``None``.""" +//| + + + +static mp_obj_t usb_audio_usbmicrophone_deinit(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_usb_audio_usbmicrophone_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_deinit_obj, usb_audio_usbmicrophone_deinit); + +static void check_for_deinit(usb_audio_usbmicrophone_obj_t *self) { + if (common_hal_usb_audio_usbmicrophone_deinited(self)) { + raise_deinited_error(); + } +} + +//| def __enter__(self) -> USBMicrophone: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| """Streams the sample to the host once when loop=False and continuously when +//| loop=True. Does not block. Use `playing` to block. +//| +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer`, +//| `audiomp3.MP3Decoder` or `synthio.Synthesizer`.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + 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); + + common_hal_usb_audio_usbmicrophone_play(self, args[ARG_sample].u_obj, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(usb_audio_usbmicrophone_play_obj, 1, usb_audio_usbmicrophone_obj_play); + +//| def stop(self) -> None: +//| """Stops streaming and resets to the start of the sample.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_obj_stop(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_usb_audio_usbmicrophone_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_stop_obj, usb_audio_usbmicrophone_obj_stop); + +//| playing: bool +//| """True when an audio sample is being streamed even if `paused`. (read-only)""" +//| +static mp_obj_t usb_audio_usbmicrophone_obj_get_playing(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_usb_audio_usbmicrophone_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_get_playing_obj, usb_audio_usbmicrophone_obj_get_playing); + +MP_PROPERTY_GETTER(usb_audio_usbmicrophone_playing_obj, + (mp_obj_t)&usb_audio_usbmicrophone_get_playing_obj); + +//| def pause(self) -> None: +//| """Stops streaming temporarily while remembering the position. Use `resume` to resume.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_obj_pause(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (!common_hal_usb_audio_usbmicrophone_get_playing(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Not playing")); + } + common_hal_usb_audio_usbmicrophone_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_pause_obj, usb_audio_usbmicrophone_obj_pause); + +//| def resume(self) -> None: +//| """Resumes streaming after :py:func:`pause`.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_obj_resume(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (common_hal_usb_audio_usbmicrophone_get_paused(self)) { + common_hal_usb_audio_usbmicrophone_resume(self); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_resume_obj, usb_audio_usbmicrophone_obj_resume); + +//| paused: bool +//| """True when streaming is paused. (read-only)""" +//| +//| +static mp_obj_t usb_audio_usbmicrophone_obj_get_paused(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_usb_audio_usbmicrophone_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_get_paused_obj, usb_audio_usbmicrophone_obj_get_paused); + +MP_PROPERTY_GETTER(usb_audio_usbmicrophone_paused_obj, + (mp_obj_t)&usb_audio_usbmicrophone_get_paused_obj); + +static const mp_rom_map_elem_t usb_audio_usbmicrophone_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usb_audio_usbmicrophone_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&usb_audio_usbmicrophone_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&usb_audio_usbmicrophone_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&usb_audio_usbmicrophone_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&usb_audio_usbmicrophone_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&usb_audio_usbmicrophone_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&usb_audio_usbmicrophone_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&usb_audio_usbmicrophone_paused_obj) }, +}; +static MP_DEFINE_CONST_DICT(usb_audio_usbmicrophone_locals_dict, usb_audio_usbmicrophone_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + usb_audio_USBMicrophone_type, + MP_QSTR_USBMicrophone, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + locals_dict, &usb_audio_usbmicrophone_locals_dict + ); diff --git a/shared-bindings/usb_audio/USBMicrophone.h b/shared-bindings/usb_audio/USBMicrophone.h new file mode 100644 index 00000000000..4fe096778bc --- /dev/null +++ b/shared-bindings/usb_audio/USBMicrophone.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/usb_audio/USBMicrophone.h" + +extern const mp_obj_type_t usb_audio_USBMicrophone_type; + +void common_hal_usb_audio_usbmicrophone_construct(usb_audio_usbmicrophone_obj_t *self); +void common_hal_usb_audio_usbmicrophone_deinit(usb_audio_usbmicrophone_obj_t *self); +bool common_hal_usb_audio_usbmicrophone_deinited(usb_audio_usbmicrophone_obj_t *self); +void common_hal_usb_audio_usbmicrophone_play(usb_audio_usbmicrophone_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_usb_audio_usbmicrophone_stop(usb_audio_usbmicrophone_obj_t *self); +bool common_hal_usb_audio_usbmicrophone_get_playing(usb_audio_usbmicrophone_obj_t *self); +void common_hal_usb_audio_usbmicrophone_pause(usb_audio_usbmicrophone_obj_t *self); +void common_hal_usb_audio_usbmicrophone_resume(usb_audio_usbmicrophone_obj_t *self); +bool common_hal_usb_audio_usbmicrophone_get_paused(usb_audio_usbmicrophone_obj_t *self); diff --git a/shared-bindings/usb_audio/USBSpeaker.c b/shared-bindings/usb_audio/USBSpeaker.c new file mode 100644 index 00000000000..78c5e6099b9 --- /dev/null +++ b/shared-bindings/usb_audio/USBSpeaker.c @@ -0,0 +1,167 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/usb_audio/USBSpeaker.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/util.h" +#include "shared-module/usb_audio/__init__.h" + +//| class USBSpeaker: +//| """Plays audio streamed from the host computer as a USB Audio Class speaker. +//| +//| A ``USBSpeaker`` is a *source* of audio samples, exactly like +//| `audiocore.RawSample` or `audiocore.WaveFile`. The host PC streams audio to +//| the board over USB, and the ``USBSpeaker`` hands that audio to a consumer +//| such as `audiobusio.I2SOut`, `audiopwmio.PWMAudioOut` or `audioio.AudioOut` +//| (optionally through the effect modules), so the board appears as a speaker. +//| +//| You cannot create an instance of `usb_audio.USBSpeaker`. +//| +//| There is a single shared instance, available as ``usb_audio.usb_speaker`` +//| once ``usb_audio.enable()`` has configured an output (speaker) stream in +//| ``boot.py``. Until then ``usb_audio.usb_speaker`` is ``None``. +//| +//| .. code-block:: py +//| +//| # boot.py +//| import usb_audio +//| usb_audio.enable(sample_rate=16000, channel_count=1, +//| microphone=False, speaker=True) +//| +//| .. code-block:: py +//| +//| # code.py +//| import board +//| import usb_audio +//| import audiobusio +//| +//| spk = usb_audio.usb_speaker +//| out = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) +//| out.play(spk, loop=True) +//| while True: +//| pass +//| +//| """ + +static mp_obj_t usb_audio_usbspeaker_deinit(mp_obj_t self_in) { + usb_audio_usbspeaker_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_usb_audio_usbspeaker_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbspeaker_deinit_obj, usb_audio_usbspeaker_deinit); + +static void check_for_deinit(usb_audio_usbspeaker_obj_t *self) { + audiosample_check_for_deinit(&self->base); +} + +//| def read(self, destination: circuitpython_typing.WriteableBuffer, destination_length: int) -> int: +//| """Copies up to ``destination_length`` of the most recent samples streamed +//| from the host into ``destination``, for analysis such as an audio-reactive +//| effect or VU meter. This does not block: it returns whatever the host has +//| delivered so far, which may be fewer than ``destination_length`` samples +//| (or zero when the host is not streaming). +//| +//| ``destination`` must be an ``array.array`` of 16-bit signed samples +//| (typecode ``"h"``), matching the negotiated speaker format. +//| +//| Reading consumes the samples, so a ``USBSpeaker`` being read this way +//| should not also be passed to an output backend's ``play()`` at the same +//| time. +//| +//| :return: The number of samples copied into ``destination``.""" +//| ... +//| +static mp_obj_t usb_audio_usbspeaker_obj_read(mp_obj_t self_in, mp_obj_t destination, mp_obj_t destination_length) { + usb_audio_usbspeaker_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + uint32_t length = mp_arg_validate_type_int(destination_length, MP_QSTR_length); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(destination, &bufinfo, MP_BUFFER_WRITE); + // The negotiated speaker format is 16-bit signed PCM, so require a matching + // 'h' array. This keeps the copy a straight memcpy with no conversion. + if (bufinfo.typecode != 'h') { + mp_raise_TypeError(MP_ERROR_TEXT("destination must be an array of type 'h'")); + } + size_t capacity = bufinfo.len / sizeof(int16_t); + if (capacity < length) { + length = capacity; + } + + uint32_t length_read = common_hal_usb_audio_usbspeaker_read(self, bufinfo.buf, length); + return MP_OBJ_NEW_SMALL_INT(length_read); +} +static MP_DEFINE_CONST_FUN_OBJ_3(usb_audio_usbspeaker_read_obj, usb_audio_usbspeaker_obj_read); + +//| def __enter__(self) -> USBSpeaker: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| connected: bool +//| """True while the host is streaming audio to this speaker. (read-only)""" +//| +//| +static mp_obj_t usb_audio_usbspeaker_obj_get_connected(mp_obj_t self_in) { + usb_audio_usbspeaker_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_usb_audio_usbspeaker_get_connected(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbspeaker_get_connected_obj, usb_audio_usbspeaker_obj_get_connected); + +MP_PROPERTY_GETTER(usb_audio_usbspeaker_connected_obj, + (mp_obj_t)&usb_audio_usbspeaker_get_connected_obj); + +//| sample_rate: int +//| """The sample rate negotiated with the host in ``boot.py``. (read-only)""" +//| +//| bits_per_sample: int +//| """The bit depth negotiated with the host in ``boot.py``. (read-only)""" +//| +//| channel_count: int +//| """The number of channels negotiated with the host in ``boot.py``. (read-only)""" +//| +//| +static const mp_rom_map_elem_t usb_audio_usbspeaker_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usb_audio_usbspeaker_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&usb_audio_usbspeaker_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&usb_audio_usbspeaker_read_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&usb_audio_usbspeaker_connected_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(usb_audio_usbspeaker_locals_dict, usb_audio_usbspeaker_locals_dict_table); + +static const audiosample_p_t usb_audio_usbspeaker_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)usb_audio_usbspeaker_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)usb_audio_usbspeaker_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + usb_audio_USBSpeaker_type, + MP_QSTR_USBSpeaker, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + locals_dict, &usb_audio_usbspeaker_locals_dict, + protocol, &usb_audio_usbspeaker_proto + ); diff --git a/shared-bindings/usb_audio/USBSpeaker.h b/shared-bindings/usb_audio/USBSpeaker.h new file mode 100644 index 00000000000..30d2b0862a3 --- /dev/null +++ b/shared-bindings/usb_audio/USBSpeaker.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/usb_audio/USBSpeaker.h" + +extern const mp_obj_type_t usb_audio_USBSpeaker_type; + +void common_hal_usb_audio_usbspeaker_construct(usb_audio_usbspeaker_obj_t *self); +void common_hal_usb_audio_usbspeaker_deinit(usb_audio_usbspeaker_obj_t *self); +bool common_hal_usb_audio_usbspeaker_deinited(usb_audio_usbspeaker_obj_t *self); +bool common_hal_usb_audio_usbspeaker_get_connected(usb_audio_usbspeaker_obj_t *self); +uint32_t common_hal_usb_audio_usbspeaker_read(usb_audio_usbspeaker_obj_t *self, void *buffer, uint32_t length); diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c new file mode 100644 index 00000000000..31d3ab549fd --- /dev/null +++ b/shared-bindings/usb_audio/__init__.c @@ -0,0 +1,155 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/usb_audio/__init__.h" +#include "shared-bindings/usb_audio/USBMicrophone.h" +#include "shared-bindings/usb_audio/USBSpeaker.h" +#include "shared-module/usb_audio/__init__.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" + +//| """Stream audio to a host computer via USB +//| +//| This makes your CircuitPython device identify to the host computer as a USB +//| Audio Class (UAC2) microphone: the board is the audio *source* and streams +//| samples to the host over a USB isochronous IN endpoint. +//| +//| This mode requires 2 IN endpoints and 2 interfaces. +//| Generally, microcontrollers have a limit on the number of endpoints. If you exceed the number +//| of endpoints, CircuitPython will automatically enter Safe Mode. Even in this case, you may be +//| able to enable USB audio by also disabling other USB functions, such as +//| `usb_hid` or `usb_midi`. +//| +//| To enable this mode, you must configure the audio format in ``boot.py`` and then +//| use the `usb_microphone` singleton instance in ``code.py``. +//| +//| .. code-block:: py +//| +//| # boot.py +//| import usb_audio +//| usb_audio.enable(sample_rate=16000) +//| +//| .. code-block:: py +//| +//| # code.py +//| import time +//| import usb_audio +//| import synthio +//| +//| # usb_audio.usb_microphone is a singleton instance (created by enable() above), +//| # not a class you construct. It is a consumer of an audio sample, just like +//| # audioio.AudioOut: the samples it pulls are streamed to the host PC instead +//| # of to a pin. +//| mic = usb_audio.usb_microphone +//| synth = synthio.Synthesizer(sample_rate=16000, channel_count=1) +//| mic.play(synth, loop=True) +//| +//| c_major_scale = [60, 62, 64, 65, 67, 69, 71, 72] +//| try: +//| while True: +//| for note in c_major_scale: +//| synth.press(note) +//| time.sleep(0.1) +//| synth.release(note) +//| time.sleep(0.05) +//| except KeyboardInterrupt: +//| pass +//| mic.stop() +//| +//| The ``sample_rate`` and ``channel_count`` of the sample played must match the values passed to `enable`, +//| and the sample must be 16-bit signed; otherwise ``play`` raises a ``ValueError``. +//| +//| This interface is experimental and may change without notice even in stable +//| versions of CircuitPython.""" +//| +//| + +//| usb_microphone: Optional[USBMicrophone] +//| """The shared `USBMicrophone` singleton instance, or ``None`` until +//| ``usb_audio.enable()`` has configured an input (microphone) stream in ``boot.py``. +//| `USBMicrophone` is exposed only as a type; you do not construct it.""" +//| +//| usb_speaker: Optional[USBSpeaker] +//| """The shared `USBSpeaker` singleton instance, or ``None`` until +//| ``usb_audio.enable()`` has configured an output (speaker) stream in ``boot.py``. +//| `USBSpeaker` is exposed only as a type; you do not construct it.""" +//| + +//| def enable( +//| sample_rate: int = 16000, +//| channel_count: int = 1, +//| microphone: bool = True, +//| speaker: bool = False, +//| ) -> None: +//| """Enable the USB audio interface with the given PCM format. +//| +//| This function may only be used from ``boot.py``. +//| +//| :param int sample_rate: Samples per second of the streamed audio. +//| :param int channel_count: Number of channels. Either mono (1) or stereo (2) is supported. +//| :param bool microphone: Present a microphone (audio flows board -> host). Enabled by default. +//| :param bool speaker: Present a speaker (audio flows host -> board). +//| +//| Enabling both ``microphone`` and ``speaker`` presents a combined headset. At +//| least one of the two must be enabled.""" +//| +//| +static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample_rate, ARG_channel_count, ARG_microphone, ARG_speaker }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample_rate, MP_ARG_INT, { .u_int = 16000 } }, + { MP_QSTR_channel_count, MP_ARG_INT, { .u_int = 1 } }, + { MP_QSTR_microphone, MP_ARG_BOOL, { .u_bool = true } }, + { MP_QSTR_speaker, MP_ARG_BOOL, { .u_bool = false } }, + }; + 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); + + mp_int_t sample_rate = mp_arg_validate_int_range(args[ARG_sample_rate].u_int, 1, USB_AUDIO_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_N_CHANNELS, MP_QSTR_channel_count); + bool microphone = args[ARG_microphone].u_bool; + bool speaker = args[ARG_speaker].u_bool; + + if (!microphone && !speaker) { + mp_raise_ValueError(MP_ERROR_TEXT("At least one of microphone and speaker must be enabled")); + } + + if (!shared_module_usb_audio_enable(sample_rate, channel_count, microphone, speaker)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot change USB devices now")); + } + + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(usb_audio_enable_obj, 0, usb_audio_enable); + +mp_map_elem_t usb_audio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_audio) }, + // USBMicrophone and USBSpeaker are the classes, exposed only for typing and + // isinstance() checks; you do not construct them. The usable objects are the + // pre-made singleton instances installed at the usb_microphone / usb_speaker + // attributes below. + { MP_ROM_QSTR(MP_QSTR_USBMicrophone), MP_OBJ_FROM_PTR(&usb_audio_USBMicrophone_type) }, + { MP_ROM_QSTR(MP_QSTR_USBSpeaker), MP_OBJ_FROM_PTR(&usb_audio_USBSpeaker_type) }, + // usb_microphone and usb_speaker are the singleton instances, like + // usb_midi.ports. usb_audio_setup_singletons() replaces these None + // placeholders with the real instances at the start of each VM when the + // matching direction was enabled in boot.py. + { MP_ROM_QSTR(MP_QSTR_usb_microphone), MP_ROM_NONE }, + { MP_ROM_QSTR(MP_QSTR_usb_speaker), MP_ROM_NONE }, + { MP_ROM_QSTR(MP_QSTR_enable), MP_OBJ_FROM_PTR(&usb_audio_enable_obj) }, +}; + +// This isn't const so the singleton instances can be installed dynamically. +MP_DEFINE_MUTABLE_DICT(usb_audio_module_globals, usb_audio_module_globals_table); + +const mp_obj_module_t usb_audio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&usb_audio_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_usb_audio, usb_audio_module); diff --git a/shared-bindings/usb_audio/__init__.h b/shared-bindings/usb_audio/__init__.h new file mode 100644 index 00000000000..f9ad0eeeb78 --- /dev/null +++ b/shared-bindings/usb_audio/__init__.h @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include "shared-module/usb_audio/__init__.h" + +// The module globals dict is mutable so the USBMicrophone and USBSpeaker +// singleton instances can be installed at runtime (see usb_audio_setup_singletons). +extern mp_obj_dict_t usb_audio_module_globals; diff --git a/shared-bindings/usb_cdc/Serial.c b/shared-bindings/usb_cdc/Serial.c index 4d6851351af..9bbc2b78f35 100644 --- a/shared-bindings/usb_cdc/Serial.c +++ b/shared-bindings/usb_cdc/Serial.c @@ -100,7 +100,7 @@ static mp_uint_t usb_cdc_serial_write_stream(mp_obj_t self_in, const void *buf_i return common_hal_usb_cdc_serial_write(self, buf, size, errcode); } -static mp_uint_t usb_cdc_serial_ioctl_stream(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t usb_cdc_serial_ioctl_stream(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret = 0; switch (request) { @@ -194,7 +194,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_reset_output_buffer_obj, usb_cdc_serial static mp_obj_t usb_cdc_serial_get_timeout(mp_obj_t self_in) { usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_float_t timeout = common_hal_usb_cdc_serial_get_timeout(self); - return (timeout < 0.0f) ? mp_const_none : mp_obj_new_float(self->timeout); + return (timeout < 0.0f) ? mp_const_none : mp_obj_new_float(timeout); } MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_timeout_obj, usb_cdc_serial_get_timeout); @@ -219,7 +219,7 @@ MP_PROPERTY_GETSET(usb_cdc_serial_timeout_obj, static mp_obj_t usb_cdc_serial_get_write_timeout(mp_obj_t self_in) { usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_float_t write_timeout = common_hal_usb_cdc_serial_get_write_timeout(self); - return (write_timeout < 0.0f) ? mp_const_none : mp_obj_new_float(self->write_timeout); + return (write_timeout < 0.0f) ? mp_const_none : mp_obj_new_float(write_timeout); } MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_write_timeout_obj, usb_cdc_serial_get_write_timeout); diff --git a/shared-bindings/usb_cdc/Serial.h b/shared-bindings/usb_cdc/Serial.h index 30249cef389..091f7514a4f 100644 --- a/shared-bindings/usb_cdc/Serial.h +++ b/shared-bindings/usb_cdc/Serial.h @@ -6,7 +6,11 @@ #pragma once +#if defined(__ZEPHYR__) && __ZEPHYR__ == 1 +#include "common-hal/usb_cdc/Serial.h" +#else #include "shared-module/usb_cdc/Serial.h" +#endif extern const mp_obj_type_t usb_cdc_serial_type; diff --git a/shared-bindings/usb_cdc/__init__.h b/shared-bindings/usb_cdc/__init__.h index 34099f7e8fd..154f259f410 100644 --- a/shared-bindings/usb_cdc/__init__.h +++ b/shared-bindings/usb_cdc/__init__.h @@ -6,7 +6,11 @@ #pragma once +#if defined(__ZEPHYR__) && __ZEPHYR__ == 1 +#include "common-hal/usb_cdc/__init__.h" +#else #include "shared-module/usb_cdc/__init__.h" +#endif // Set the module dict entries. void usb_cdc_set_console(mp_obj_t serial_obj); diff --git a/shared-bindings/usb_hid/Device.c b/shared-bindings/usb_hid/Device.c index a4a0e8680e5..aa8af56a185 100644 --- a/shared-bindings/usb_hid/Device.c +++ b/shared-bindings/usb_hid/Device.c @@ -75,7 +75,6 @@ //| static mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - usb_hid_device_obj_t *self = mp_obj_malloc(usb_hid_device_obj_t, &usb_hid_device_type); enum { ARG_report_descriptor, ARG_usage_page, ARG_usage, ARG_report_ids, ARG_in_report_lengths, ARG_out_report_lengths }; static const mp_arg_t allowed_args[] = { { MP_QSTR_report_descriptor, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -141,9 +140,10 @@ static mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args mp_raise_ValueError_varg(MP_ERROR_TEXT("%q length must be %d"), MP_QSTR_report_id_space_0, 1); } + usb_hid_device_obj_t *self = mp_obj_malloc(usb_hid_device_obj_t, &usb_hid_device_type); common_hal_usb_hid_device_construct( self, descriptor, usage_page, usage, report_ids_count, report_ids_array, in_report_lengths_array, out_report_lengths_array); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); } @@ -156,6 +156,10 @@ static mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args //| The ``report`` itself will be discarded, to prevent unwanted extraneous characters, //| mouse clicks, etc. //| +//| If the host has put the interface in boot protocol, the boot device sends its report +//| without a report ID, and `send_report()` on any other device discards the report, +//| because the host reads only the boot device. +//| //| Note: Host operating systems allow enabling and disabling specific devices //| and kinds of devices to do wakeup. //| The defaults are different for different operating systems. diff --git a/shared-bindings/usb_hid/__init__.c b/shared-bindings/usb_hid/__init__.c index 47f7f03c493..1bedaf3edf0 100644 --- a/shared-bindings/usb_hid/__init__.c +++ b/shared-bindings/usb_hid/__init__.c @@ -25,6 +25,10 @@ //| the `devices` tuple is **replaced** when ``code.py`` starts with a single-element tuple //| containing a `Device` that describes the boot device chosen (keyboard or mouse). //| The request for a boot device overrides any other HID devices. +//| +//| If the host requests a boot device after ``code.py`` has started, `devices` is not replaced. +//| The boot device then sends reports in the boot format, with no report ID, and +//| `Device.send_report()` on any other device does nothing, because the host ignores it. //| """ //| //| diff --git a/shared-bindings/usb_host/Port.c b/shared-bindings/usb_host/Port.c index 41e8513a1e8..2c61e641a05 100644 --- a/shared-bindings/usb_host/Port.c +++ b/shared-bindings/usb_host/Port.c @@ -42,7 +42,7 @@ static mp_obj_t usb_host_port_make_new(const mp_obj_type_t *type, usb_host_port_obj_t *self = common_hal_usb_host_port_construct(dp, dm); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); } static const mp_rom_map_elem_t usb_host_port_locals_dict_table[] = { diff --git a/shared-bindings/usb_midi/PortIn.c b/shared-bindings/usb_midi/PortIn.c index d62d0b53af1..3f4b19fdec2 100644 --- a/shared-bindings/usb_midi/PortIn.c +++ b/shared-bindings/usb_midi/PortIn.c @@ -60,7 +60,7 @@ static mp_uint_t usb_midi_portin_read(mp_obj_t self_in, void *buf_in, mp_uint_t return common_hal_usb_midi_portin_read(self, buf, size, errcode); } -static mp_uint_t usb_midi_portin_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t usb_midi_portin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { usb_midi_portin_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/shared-bindings/usb_midi/PortOut.c b/shared-bindings/usb_midi/PortOut.c index 89c83810188..35856ff25fa 100644 --- a/shared-bindings/usb_midi/PortOut.c +++ b/shared-bindings/usb_midi/PortOut.c @@ -42,7 +42,7 @@ static mp_uint_t usb_midi_portout_write(mp_obj_t self_in, const void *buf_in, mp return common_hal_usb_midi_portout_write(self, buf, size, errcode); } -static mp_uint_t usb_midi_portout_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t usb_midi_portout_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { usb_midi_portout_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/shared-bindings/util.h b/shared-bindings/util.h index d53e5c6e8da..11f0a00db71 100644 --- a/shared-bindings/util.h +++ b/shared-bindings/util.h @@ -9,7 +9,7 @@ #include "py/mpprint.h" #include "py/runtime.h" -NORETURN void raise_deinited_error(void); +MP_NORETURN void raise_deinited_error(void); void properties_print_helper(const mp_print_t *print, mp_obj_t self_in, const mp_arg_t *properties, size_t n_properties); void properties_construct_helper(mp_obj_t self_in, const mp_arg_t *args, const mp_arg_val_t *vals, size_t n_properties); bool path_exists(const char *path); diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index ff29609fc4e..834f1fbff50 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -69,7 +69,7 @@ mp_obj_t vectorio_vector_shape_make_new(const mp_obj_t shape, const mp_obj_t pix } else if (mp_obj_is_type(shape, &vectorio_circle_type)) { common_hal_vectorio_circle_set_on_dirty(self->ishape.shape, on_dirty); } else { - mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported %q type"), MP_QSTR_shape); + // Already excluded due to previous else-if chain. } return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/wifi/Monitor.c b/shared-bindings/wifi/Monitor.c index fb09c4b4f77..9350a160a07 100644 --- a/shared-bindings/wifi/Monitor.c +++ b/shared-bindings/wifi/Monitor.c @@ -19,7 +19,11 @@ //| def __init__(self, channel: Optional[int] = 1, queue: Optional[int] = 128) -> None: //| """Initialize `wifi.Monitor` singleton. //| -//| :param int channel: The WiFi channel to scan. +//| :param int channel: The WiFi channel to scan. On dual-band radios, +//| 5 GHz channels (36 and above) may also be given. A channel the +//| radio does not support raises `ValueError`. While the station is +//| connected the radio stays on the station's channel, and +//| `channel` reports that channel. //| :param int queue: The queue size for buffering the packet. //| //| """ @@ -35,7 +39,9 @@ static mp_obj_t wifi_monitor_make_new(const mp_obj_type_t *type, size_t n_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); - mp_int_t channel = mp_arg_validate_int_range(args[ARG_channel].u_int, 1, 13, MP_QSTR_channel); + // 165 is the highest channel in the scan pattern. Channels the radio + // doesn't support are rejected by the port rather than here. + mp_int_t channel = mp_arg_validate_int_range(args[ARG_channel].u_int, 1, 165, MP_QSTR_channel); mp_int_t queue = mp_arg_validate_int_min(args[ARG_queue].u_int, 0, MP_QSTR_queue); wifi_monitor_obj_t *self = MP_STATE_VM(wifi_monitor_singleton); @@ -49,17 +55,16 @@ static mp_obj_t wifi_monitor_make_new(const mp_obj_type_t *type, size_t n_args, } //| channel: int -//| """The WiFi channel to scan.""" +//| """The WiFi channel to scan. A channel the radio does not support raises +//| `ValueError`. While the station is connected the radio stays on the +//| station's channel, and this reports that channel.""" static mp_obj_t wifi_monitor_obj_get_channel(mp_obj_t self_in) { return common_hal_wifi_monitor_get_channel(self_in); } MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_get_channel_obj, wifi_monitor_obj_get_channel); static mp_obj_t wifi_monitor_obj_set_channel(mp_obj_t self_in, mp_obj_t channel) { - mp_int_t c = mp_obj_get_int(channel); - if (c < 1 || c > 13) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of bounds"), MP_QSTR_channel); - } + mp_int_t c = mp_arg_validate_int_range(mp_obj_get_int(channel), 1, 165, MP_QSTR_channel); common_hal_wifi_monitor_set_channel(self_in, c); return mp_const_none; } diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index 9a7d445fd04..c9aafc903ba 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -6,6 +6,7 @@ #include "shared-bindings/wifi/__init__.h" #include "shared-bindings/wifi/AuthMode.h" +#include "shared-bindings/wifi/Network.h" #include "shared-bindings/wifi/PowerManagement.h" #include @@ -254,10 +255,13 @@ MP_PROPERTY_GETTER(wifi_radio_mac_address_ap_obj, #endif //| def start_scanning_networks( -//| self, *, start_channel: int = 1, stop_channel: int = 11 +//| self, *, start_channel: int = 1, stop_channel: int = 165 //| ) -> Iterable[Network]: //| """Scans for available wifi networks over the given channel range. Make sure the channels are allowed in your country. //| +//| On dual-band radios, 5 GHz channels (36 and above) may also be given. +//| Channel numbers that the radio does not support are skipped. +//| //| .. note:: //| //| In the raspberrypi port (RP2040 CYW43), ``start_channel`` and ``stop_channel`` are ignored. @@ -268,17 +272,19 @@ static mp_obj_t wifi_radio_start_scanning_networks(size_t n_args, const mp_obj_t enum { ARG_start_channel, ARG_stop_channel }; static const mp_arg_t allowed_args[] = { { MP_QSTR_start_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, - { MP_QSTR_stop_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 11} }, + { MP_QSTR_stop_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 165} }, }; wifi_radio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + // 165 is the highest channel in the scan pattern. Channels the radio + // doesn't support are skipped while scanning rather than rejected here. uint8_t start_channel = - (uint8_t)mp_arg_validate_int_range(args[ARG_start_channel].u_int, 1, 14, MP_QSTR_start_channel); + (uint8_t)mp_arg_validate_int_range(args[ARG_start_channel].u_int, 1, 165, MP_QSTR_start_channel); uint8_t stop_channel = - (uint8_t)mp_arg_validate_int_range(args[ARG_stop_channel].u_int, 1, 14, MP_QSTR_stop_channel); + (uint8_t)mp_arg_validate_int_range(args[ARG_stop_channel].u_int, 1, 165, MP_QSTR_stop_channel); // Swap if in reverse order, without complaining. if (start_channel > stop_channel) { uint8_t temp = stop_channel; @@ -336,6 +342,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_station_obj, wifi_radio_stop_station); //| //| If ``channel`` is given, the access point will use that channel unless //| a station is already operating on a different channel. +//| On dual-band radios, 5 GHz channels (36 and above) may also be given. +//| A channel the radio does not support raises `ValueError`. //| //| If ``authmode`` is not None, the access point will use the given authentication modes. //| If a non-empty password is given, ``authmode`` must not include ``OPEN``. @@ -357,7 +365,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_station_obj, wifi_radio_stop_station); //| //| .. note:: //| -//| In the raspberrypi port (RP2040 CYW43), ``max_connections`` is ignored. +//| In the raspberrypi port (RP2040 CYW43), ``max_connections`` is ignored +//| and only 2.4 GHz channels (1-13) are accepted. //| """ //| ... //| @@ -397,7 +406,9 @@ static mp_obj_t wifi_radio_start_ap(size_t n_args, const mp_obj_t *pos_args, mp_ } } - mp_int_t channel = mp_arg_validate_int_range(args[ARG_channel].u_int, 1, 13, MP_QSTR_channel); + // 165 is the highest channel in the scan pattern. Channels the radio + // doesn't support are rejected by the port rather than here. + mp_int_t channel = mp_arg_validate_int_range(args[ARG_channel].u_int, 1, 165, MP_QSTR_channel); if (authmode == AUTHMODE_OPEN && password.len > 0) { mp_raise_ValueError(MP_ERROR_TEXT("AuthMode.OPEN is not used with password")); @@ -438,12 +449,13 @@ MP_PROPERTY_GETTER(wifi_radio_ap_active_obj, //| def connect( //| self, -//| ssid: Union[str, ReadableBuffer], +//| ssid: Optional[Union[str, ReadableBuffer]] = None, //| password: Union[str, ReadableBuffer] = b"", //| *, //| channel: int = 0, //| bssid: Optional[Union[str, ReadableBuffer]] = None, //| timeout: Optional[float] = None, +//| network: Optional[Network] = None, //| ) -> None: //| """Connects to the given ssid and waits for an ip address. Reconnections are handled //| automatically once one connection succeeds. @@ -459,17 +471,22 @@ MP_PROPERTY_GETTER(wifi_radio_ap_active_obj, //| significantly because a full scan doesn't occur. //| //| If ``bssid`` is given and not None, the scan will start at the first channel or the one given and -//| connect to the AP with the given ``bssid`` and ``ssid``.""" +//| connect to the AP with the given ``bssid`` and ``ssid``. +//| +//| If ``network`` is given, it must be a `Network` returned by +//| `start_scanning_networks`. Its ``ssid``, ``bssid`` and ``channel`` are used, so no +//| scan happens. Give either ``ssid`` or ``network``, not both.""" //| ... //| static mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_ssid, ARG_password, ARG_channel, ARG_bssid, ARG_timeout }; + enum { ARG_ssid, ARG_password, ARG_channel, ARG_bssid, ARG_timeout, ARG_network }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_ssid, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_password, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_network, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; wifi_radio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); @@ -481,9 +498,27 @@ static mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_m timeout = mp_obj_get_float(args[ARG_timeout].u_obj); } + mp_obj_t ssid_obj = args[ARG_ssid].u_obj; + mp_obj_t bssid_obj = args[ARG_bssid].u_obj; + mp_int_t channel = args[ARG_channel].u_int; + + if (args[ARG_network].u_obj != mp_const_none) { + if (ssid_obj != mp_const_none) { + mp_raise_TypeError_varg(MP_ERROR_TEXT("Supply either %q or %q, not both"), MP_QSTR_ssid, MP_QSTR_network); + } + wifi_network_obj_t *network = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_network].u_obj, &wifi_network_type, MP_QSTR_network)); + ssid_obj = common_hal_wifi_network_get_ssid(network); + bssid_obj = common_hal_wifi_network_get_bssid(network); + channel = mp_obj_get_int(common_hal_wifi_network_get_channel(network)); + } + + if (ssid_obj == mp_const_none) { + mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' argument required"), MP_QSTR_ssid); + } + mp_buffer_info_t ssid; ssid.len = 0; - mp_get_buffer_raise(args[ARG_ssid].u_obj, &ssid, MP_BUFFER_READ); + mp_get_buffer_raise(ssid_obj, &ssid, MP_BUFFER_READ); mp_arg_validate_length_range(ssid.len, 1, 32, MP_QSTR_ssid); mp_buffer_info_t password; @@ -503,14 +538,14 @@ static mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_m mp_buffer_info_t bssid; bssid.len = 0; // Should probably make sure bssid is just bytes and not something else too - if (args[ARG_bssid].u_obj != mp_const_none) { - mp_get_buffer_raise(args[ARG_bssid].u_obj, &bssid, MP_BUFFER_READ); + if (bssid_obj != mp_const_none) { + mp_get_buffer_raise(bssid_obj, &bssid, MP_BUFFER_READ); if (bssid.len != MAC_ADDRESS_LENGTH) { mp_raise_ValueError(MP_ERROR_TEXT("Invalid BSSID")); } } - wifi_radio_error_t error = common_hal_wifi_radio_connect(self, ssid.buf, ssid.len, password.buf, password.len, args[ARG_channel].u_int, timeout, bssid.buf, bssid.len); + wifi_radio_error_t error = common_hal_wifi_radio_connect(self, ssid.buf, ssid.len, password.buf, password.len, channel, timeout, bssid.buf, bssid.len); if (error == WIFI_RADIO_ERROR_AUTH_FAIL) { mp_raise_ConnectionError(MP_ERROR_TEXT("Authentication failure")); } else if (error == WIFI_RADIO_ERROR_NO_AP_FOUND) { diff --git a/shared-bindings/zlib/__init__.c b/shared-bindings/zlib/__init__.c index a17694d8a2e..f6992418e20 100644 --- a/shared-bindings/zlib/__init__.c +++ b/shared-bindings/zlib/__init__.c @@ -53,7 +53,7 @@ static mp_obj_t zlib_decompress(size_t n_args, const mp_obj_t *args) { mp_int_t wbits = 0; if (n_args > 1) { - wbits = MP_OBJ_SMALL_INT_VALUE(args[1]); + wbits = mp_obj_get_int_truncated(args[1]); } return common_hal_zlib_decompress(args[0], wbits); diff --git a/shared-module/_bleio/Address.c b/shared-module/_bleio/Address.c index b40abb3d560..5a50ba4f28f 100644 --- a/shared-module/_bleio/Address.c +++ b/shared-module/_bleio/Address.c @@ -7,17 +7,24 @@ #include -#include "py/objstr.h" +#include "py/obj.h" #include "shared-bindings/_bleio/Address.h" #include "shared-module/_bleio/Address.h" -void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type) { - self->bytes = mp_obj_new_bytes(bytes, NUM_BLEIO_ADDRESS_BYTES); +void common_hal_bleio_address_construct(bleio_address_obj_t *self, const uint8_t *bytes, uint8_t address_type) { + memcpy(self->bytes, bytes, NUM_BLEIO_ADDRESS_BYTES); self->type = address_type; } mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self) { - return self->bytes; + // Build a bytes object on demand. Address stores its bytes inline, so this + // is only reached from Python (e.g. ``address.address_bytes``) where the + // heap is available. + return mp_obj_new_bytes(self->bytes, NUM_BLEIO_ADDRESS_BYTES); +} + +void common_hal_bleio_address_get_bytes(bleio_address_obj_t *self, uint8_t bytes[NUM_BLEIO_ADDRESS_BYTES]) { + memcpy(bytes, self->bytes, NUM_BLEIO_ADDRESS_BYTES); } uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self) { diff --git a/shared-module/_bleio/Address.h b/shared-module/_bleio/Address.h index 76e7a1177fc..55324770375 100644 --- a/shared-module/_bleio/Address.h +++ b/shared-module/_bleio/Address.h @@ -14,5 +14,8 @@ typedef struct { mp_obj_base_t base; uint8_t type; - mp_obj_t bytes; // a bytes() object + // Little-endian BD_ADDR order: bytes[0] is the least-significant byte. + // Stored inline so an Address can live in static storage (e.g. embedded in + // an adapter) without allocating a separate bytes object. + uint8_t bytes[NUM_BLEIO_ADDRESS_BYTES]; } bleio_address_obj_t; diff --git a/shared-module/_bleio/Attribute.c b/shared-module/_bleio/Attribute.c index b12f2b121de..cfc5999df1e 100644 --- a/shared-module/_bleio/Attribute.c +++ b/shared-module/_bleio/Attribute.c @@ -24,3 +24,14 @@ void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_securi break; } } + +bool bleio_attribute_security_mode_requires_mitm(bleio_attribute_security_mode_t security_mode) { + switch (security_mode) { + case SECURITY_MODE_ENC_WITH_MITM: + case SECURITY_MODE_LESC_ENC_WITH_MITM: + case SECURITY_MODE_SIGNED_WITH_MITM: + return true; + default: + return false; + } +} diff --git a/shared-module/audiocore/WaveFile.c b/shared-module/audiocore/WaveFile.c index 77ca2445edb..16bbf965e8b 100644 --- a/shared-module/audiocore/WaveFile.c +++ b/shared-module/audiocore/WaveFile.c @@ -114,6 +114,7 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t *self, // Try to allocate two buffers, one will be loaded from file and the other // DMAed to DAC. if (buffer_size) { + // buffer_size is a multiple of 8 (checked by the binding) so each half can be padded in place. self->len = buffer_size / 2; self->buffer = buffer; self->second_buffer = buffer + self->len; @@ -193,7 +194,7 @@ audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t * self->bytes_remaining -= length_read; // Pad the last buffer to word align it. if (self->bytes_remaining == 0 && length_read % sizeof(uint32_t) != 0) { - uint32_t pad = length_read % sizeof(uint32_t); + uint32_t pad = sizeof(uint32_t) - length_read % sizeof(uint32_t); length_read += pad; if (self->base.bits_per_sample == 8) { for (uint32_t i = 0; i < pad; i++) { diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 2ee683d75e1..9cd561208f3 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -8,16 +8,24 @@ #include "py/obj.h" #include "py/runtime.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/WaveFile.h" #include "shared-module/audiocore/RawSample.h" #include "shared-module/audiocore/WaveFile.h" +#if CIRCUITPY_AUDIOSPEED +#include "shared-bindings/audiospeed/Resampler.h" +#endif + #include "shared-bindings/audiomixer/Mixer.h" #include "shared-module/audiomixer/Mixer.h" void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel_output, uint8_t audio_channel) { const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); + if (audiosample_deinited(audiosample_cast_obj(sample_obj))) { + return; + } proto->reset_buffer(MP_OBJ_TO_PTR(sample_obj), single_channel_output, audio_channel); } @@ -26,6 +34,11 @@ audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); + if (audiosample_deinited(audiosample_cast_obj(sample_obj))) { + *buffer = NULL; + *buffer_length = 0; + return GET_BUFFER_ERROR; + } return proto->get_buffer(MP_OBJ_TO_PTR(sample_obj), single_channel_output, channel, buffer, buffer_length); } @@ -198,7 +211,12 @@ void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool allow_mono_to_stereo) { const audiosample_base_t *other = audiosample_check(other_in); + audiosample_check_for_deinit(other); + #if !CIRCUITPY_AUDIOSPEED if (other->sample_rate != self->sample_rate) { + #else + if (other->sample_rate != self->sample_rate && !mp_obj_is_type(other_in, &audiospeed_resampler_type)) { + #endif mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); } if ((!allow_mono_to_stereo || (allow_mono_to_stereo && self->channel_count != 2)) && other->channel_count != self->channel_count) { @@ -210,4 +228,11 @@ void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool al if (other->samples_signed != self->samples_signed) { mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); } + + #if CIRCUITPY_AUDIOSPEED + if (mp_obj_is_type(other_in, &audiospeed_resampler_type)) { + audiospeed_resampler_obj_t *other_resampler = MP_OBJ_TO_PTR(other_in); + audiospeed_resampler_set_sample_rate(other_resampler, self->sample_rate); + } + #endif } diff --git a/shared-module/audiocore/__init__.h b/shared-module/audiocore/__init__.h index 920fe752c38..d135ee6c9e9 100644 --- a/shared-module/audiocore/__init__.h +++ b/shared-module/audiocore/__init__.h @@ -114,3 +114,5 @@ void audiosample_convert_u16m_u8s(uint8_t *buffer_out, const uint16_t *buffer_in void audiosample_convert_u16s_u8s(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes); void audiosample_convert_s16m_u8s(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes); void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes); + +#define audiosample_cast_obj(obj) ((audiosample_base_t *)MP_OBJ_TO_PTR(obj)) diff --git a/shared-module/audiodelays/Chorus.c b/shared-module/audiodelays/Chorus.c index 9262c6b4de1..7033df0e272 100644 --- a/shared-module/audiodelays/Chorus.c +++ b/shared-module/audiodelays/Chorus.c @@ -4,6 +4,7 @@ // // SPDX-License-Identifier: MIT #include "shared-bindings/audiodelays/Chorus.h" +#include "shared-bindings/audiocore/__init__.h" #include #include @@ -104,9 +105,7 @@ bool common_hal_audiodelays_chorus_deinited(audiodelays_chorus_obj_t *self) { } void common_hal_audiodelays_chorus_deinit(audiodelays_chorus_obj_t *self) { - if (common_hal_audiodelays_chorus_deinited(self)) { - return; - } + audiosample_mark_deinit(&self->base); self->chorus_buffer = NULL; self->buffer[0] = NULL; self->buffer[1] = NULL; @@ -131,6 +130,10 @@ void chorus_recalculate_delay(audiodelays_chorus_obj_t *self, mp_float_t f_delay // Calculate the current chorus buffer length in bytes uint32_t new_chorus_buffer_len = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * f_delay_ms) * (self->base.channel_count * sizeof(uint16_t)); + if (new_chorus_buffer_len > self->max_chorus_buffer_len) { + new_chorus_buffer_len = self->max_chorus_buffer_len; + } + self->chorus_buffer_len = new_chorus_buffer_len; self->current_delay_ms = f_delay_ms; @@ -219,9 +222,15 @@ audioio_get_buffer_result_t audiodelays_chorus_get_buffer(audiodelays_chorus_obj if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiodelays/Echo.c b/shared-module/audiodelays/Echo.c index 0ca5fc8a750..675c7cb5ebc 100644 --- a/shared-module/audiodelays/Echo.c +++ b/shared-module/audiodelays/Echo.c @@ -11,7 +11,7 @@ #include void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_t max_delay_ms, - mp_obj_t delay_ms, mp_obj_t decay, mp_obj_t mix, + mp_obj_t delay_ms, mp_obj_t decay, mp_obj_t filter, mp_obj_t mix, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate, bool freq_shift) { @@ -59,6 +59,8 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_ // The below section sets up the echo effect's starting values. For a different effect this section will change + common_hal_audiodelays_echo_set_filter(self, filter); + // If we did not receive a BlockInput we need to create a default float value if (decay == MP_OBJ_NULL) { decay = mp_obj_new_float(MICROPY_FLOAT_CONST(0.7)); @@ -106,6 +108,7 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_ void common_hal_audiodelays_echo_deinit(audiodelays_echo_obj_t *self) { audiosample_mark_deinit(&self->base); + audiofilters_deinit_filter_chain(&self->filter); self->echo_buffer = NULL; self->buffer[0] = NULL; self->buffer[1] = NULL; @@ -140,12 +143,13 @@ void recalculate_delay(audiodelays_echo_obj_t *self, mp_float_t f_delay_ms) { uint32_t new_echo_buffer_len = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * f_delay_ms) * sizeof(uint16_t); // Limit to valid range - if (new_echo_buffer_len > max_echo_buffer_len) { - new_echo_buffer_len = max_echo_buffer_len; - } else if (new_echo_buffer_len < self->buffer_len) { + if (new_echo_buffer_len < self->buffer_len) { // If the echo buffer is smaller than our audio buffer, weird things happen new_echo_buffer_len = self->buffer_len; } + if (new_echo_buffer_len > max_echo_buffer_len) { + new_echo_buffer_len = max_echo_buffer_len; + } self->echo_buffer_len = new_echo_buffer_len; @@ -166,6 +170,14 @@ void common_hal_audiodelays_echo_set_decay(audiodelays_echo_obj_t *self, mp_obj_ synthio_block_assign_slot(decay, &self->decay, MP_QSTR_decay); } +mp_obj_t common_hal_audiodelays_echo_get_filter(audiodelays_echo_obj_t *self) { + return self->filter.obj; +} + +void common_hal_audiodelays_echo_set_filter(audiodelays_echo_obj_t *self, mp_obj_t filter_in) { + audiofilters_assign_filter_chain(&self->filter, filter_in, self->base.channel_count); +} + mp_obj_t common_hal_audiodelays_echo_get_mix(audiodelays_echo_obj_t *self) { return self->mix.obj; } @@ -197,6 +209,8 @@ void audiodelays_echo_reset_buffer(audiodelays_echo_obj_t *self, memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); memset(self->echo_buffer, 0, self->max_echo_buffer_len); + + audiofilters_reset_filter_chain(&self->filter, self->base.channel_count); } bool common_hal_audiodelays_echo_get_playing(audiodelays_echo_obj_t *self) { @@ -259,9 +273,15 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } @@ -283,6 +303,9 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * recalculate_delay(self, f_delay_ms); } + // Tick biquad filters + audiofilters_tick_filter_chain(&self->filter); + uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint16_t); uint32_t max_echo_buf_len = (self->max_echo_buffer_len >> (self->base.channel_count - 1)) / sizeof(uint16_t); @@ -318,12 +341,12 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { word = (int16_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = word; + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } else { echo = echo_buffer[echo_buffer_pos + echo_buffer_offset]; word = (int16_t)(echo * decay); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = word; + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } word = (int16_t)(echo * MIN(mix, MICROPY_FLOAT_CONST(1.0))); @@ -403,11 +426,11 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)word; + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } else { word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)word; + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } else { if (self->freq_shift) { @@ -415,12 +438,12 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)word; + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } else { // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)word; + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } diff --git a/shared-module/audiodelays/Echo.h b/shared-module/audiodelays/Echo.h index cc37f7030be..be01563b85a 100644 --- a/shared-module/audiodelays/Echo.h +++ b/shared-module/audiodelays/Echo.h @@ -8,8 +8,10 @@ #include "py/obj.h" #include "shared-module/audiocore/__init__.h" +#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/__init__.h" #include "shared-module/synthio/block.h" +#include "shared-module/synthio/Biquad.h" extern const mp_obj_type_t audiodelays_echo_type; @@ -20,6 +22,7 @@ typedef struct { mp_float_t current_delay_ms; mp_float_t sample_ms; synthio_block_slot_t decay; + audiofilters_filter_chain_t filter; synthio_block_slot_t mix; int8_t *buffer[2]; diff --git a/shared-module/audiodelays/Flanger.c b/shared-module/audiodelays/Flanger.c new file mode 100644 index 00000000000..f0d1bb1e33f --- /dev/null +++ b/shared-module/audiodelays/Flanger.c @@ -0,0 +1,414 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#include "shared-bindings/audiodelays/Flanger.h" +#include "shared-bindings/audiocore/__init__.h" + +#include +#include "py/runtime.h" + +// The largest delay we will ever read, in frames. +#define FLANGER_MAX_DELAY_FRAMES (65535u) + +// Convert a delay in milliseconds to a Q16.16 count of frames, clamped so that both interpolation +// taps always land inside the delay line. +static uint32_t flanger_ms_to_frames_q16(audiodelays_flanger_obj_t *self, mp_float_t ms) { + mp_float_t frames = ms * self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0); + mp_float_t max_frames = (mp_float_t)MIN(self->delay_buffer_frames - 2, FLANGER_MAX_DELAY_FRAMES); + + // A delay of less than one frame would read the frame we are about to overwrite + frames = MIN(MAX(frames, MICROPY_FLOAT_CONST(1.0)), max_frames); + + return (uint32_t)(frames * MICROPY_FLOAT_CONST(65536.0)); +} + +void common_hal_audiodelays_flanger_construct(audiodelays_flanger_obj_t *self, uint32_t max_delay_ms, + mp_obj_t min_delay_ms, mp_obj_t rate, mp_obj_t depth, mp_obj_t feedback, mp_obj_t mix, bool invert, + uint32_t buffer_size, uint8_t bits_per_sample, + bool samples_signed, uint8_t channel_count, uint32_t sample_rate) { + + // Basic format settings every effect and audio sample has + self->base.bits_per_sample = bits_per_sample; + self->base.samples_signed = samples_signed; // Are the samples we provide signed (common is true) + self->base.channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo + self->base.sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.single_buffer = false; + self->base.max_buffer_length = buffer_size; + + // To smooth things out as CircuitPython is doing other tasks most audio objects have a buffer + // A double buffer is set up here so the audio output can use DMA on buffer 1 while we + // write to and create buffer 2. + // This buffer is what is passed to the audio component that plays the effect. + // Samples are set sequentially. For stereo audio they are passed L/R/L/R/... + self->buffer_len = buffer_size; // in bytes + + self->buffer[0] = m_malloc_maybe(self->buffer_len); + if (self->buffer[0] == NULL) { + common_hal_audiodelays_flanger_deinit(self); + m_malloc_fail(self->buffer_len); + } + memset(self->buffer[0], 0, self->buffer_len); + + self->buffer[1] = m_malloc_maybe(self->buffer_len); + if (self->buffer[1] == NULL) { + common_hal_audiodelays_flanger_deinit(self); + m_malloc_fail(self->buffer_len); + } + memset(self->buffer[1], 0, self->buffer_len); + + self->last_buf_idx = 1; // Which buffer to use first, toggle between 0 and 1 + + // Initialize other values most effects will need. + self->sample = NULL; // The current playing sample + self->sample_remaining_buffer = NULL; // Pointer to the start of the sample buffer we have not played + self->sample_buffer_length = 0; // How many samples do we have left to play (these may be 16 bit!) + self->loop = false; // When the sample is done do we loop to the start again or stop (e.g. in a wav file) + self->more_data = false; // Is there still more data to read from the sample or did we finish + + // The below section sets up the flanger effect's starting values. + + // If we did not receive a BlockInput we need to create a default float value + if (min_delay_ms == MP_OBJ_NULL) { + min_delay_ms = mp_obj_new_float(MICROPY_FLOAT_CONST(1.0)); + } + synthio_block_assign_slot(min_delay_ms, &self->min_delay_ms, MP_QSTR_min_delay_ms); + + if (rate == MP_OBJ_NULL) { + rate = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); + } + synthio_block_assign_slot(rate, &self->rate, MP_QSTR_rate); + + if (depth == MP_OBJ_NULL) { + depth = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); + } + synthio_block_assign_slot(depth, &self->depth, MP_QSTR_depth); + + if (feedback == MP_OBJ_NULL) { + feedback = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); + } + synthio_block_assign_slot(feedback, &self->feedback, MP_QSTR_feedback); + + if (mix == MP_OBJ_NULL) { + mix = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); + } + synthio_block_assign_slot(mix, &self->mix, MP_QSTR_mix); + + self->invert = invert; + self->max_delay_ms = max_delay_ms; + + // calculate the length of a single sample in milliseconds + self->sample_ms = MICROPY_FLOAT_CONST(1000.0) / self->base.sample_rate; + + // Allocate the delay line for the largest delay we can sweep to. It is always 16-bit and each + // channel gets its own contiguous region. The two extra frames are interpolation headroom: at + // the top of the sweep the two taps sit at the far end of the line and without the extra room + // the older of the two would alias onto the frame we are about to write. + self->delay_buffer_frames = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * max_delay_ms) + 2; + size_t delay_buffer_size = self->delay_buffer_frames * self->base.channel_count * sizeof(int16_t); + self->delay_buffer = m_malloc_maybe(delay_buffer_size); + if (self->delay_buffer == NULL) { + common_hal_audiodelays_flanger_deinit(self); + m_malloc_fail(delay_buffer_size); + } + memset(self->delay_buffer, 0, delay_buffer_size); + + self->delay_buffer_pos[0] = self->delay_buffer_pos[1] = 0; + self->lfo_phase[0] = self->lfo_phase[1] = 0; + self->lfo_phase_inc = 0; +} + +bool common_hal_audiodelays_flanger_deinited(audiodelays_flanger_obj_t *self) { + if (self->delay_buffer == NULL) { + return true; + } + return false; +} + +void common_hal_audiodelays_flanger_deinit(audiodelays_flanger_obj_t *self) { + audiosample_mark_deinit(&self->base); + self->delay_buffer = NULL; + self->buffer[0] = NULL; + self->buffer[1] = NULL; +} + +mp_obj_t common_hal_audiodelays_flanger_get_min_delay_ms(audiodelays_flanger_obj_t *self) { + return self->min_delay_ms.obj; +} + +void common_hal_audiodelays_flanger_set_min_delay_ms(audiodelays_flanger_obj_t *self, mp_obj_t min_delay_ms) { + synthio_block_assign_slot(min_delay_ms, &self->min_delay_ms, MP_QSTR_min_delay_ms); +} + +mp_obj_t common_hal_audiodelays_flanger_get_rate(audiodelays_flanger_obj_t *self) { + return self->rate.obj; +} + +void common_hal_audiodelays_flanger_set_rate(audiodelays_flanger_obj_t *self, mp_obj_t rate) { + synthio_block_assign_slot(rate, &self->rate, MP_QSTR_rate); +} + +mp_obj_t common_hal_audiodelays_flanger_get_depth(audiodelays_flanger_obj_t *self) { + return self->depth.obj; +} + +void common_hal_audiodelays_flanger_set_depth(audiodelays_flanger_obj_t *self, mp_obj_t depth) { + synthio_block_assign_slot(depth, &self->depth, MP_QSTR_depth); +} + +mp_obj_t common_hal_audiodelays_flanger_get_feedback(audiodelays_flanger_obj_t *self) { + return self->feedback.obj; +} + +void common_hal_audiodelays_flanger_set_feedback(audiodelays_flanger_obj_t *self, mp_obj_t feedback) { + synthio_block_assign_slot(feedback, &self->feedback, MP_QSTR_feedback); +} + +mp_obj_t common_hal_audiodelays_flanger_get_mix(audiodelays_flanger_obj_t *self) { + return self->mix.obj; +} + +void common_hal_audiodelays_flanger_set_mix(audiodelays_flanger_obj_t *self, mp_obj_t arg) { + synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); +} + +// Fold the sawtooth phase accumulator into a triangle in the range 0 to 65535 +static uint32_t flanger_phase_to_triangle(uint32_t phase) { + uint32_t tri = phase >> 15; + if (tri > 65535) { + tri = 131071 - tri; + } + return tri; +} + +mp_float_t common_hal_audiodelays_flanger_get_lfo_value(audiodelays_flanger_obj_t *self) { + return (mp_float_t)flanger_phase_to_triangle(self->lfo_phase[0]) / MICROPY_FLOAT_CONST(65535.0); +} + +bool common_hal_audiodelays_flanger_get_invert(audiodelays_flanger_obj_t *self) { + return self->invert; +} + +void common_hal_audiodelays_flanger_set_invert(audiodelays_flanger_obj_t *self, bool invert) { + self->invert = invert; +} + +void audiodelays_flanger_reset_buffer(audiodelays_flanger_obj_t *self, + bool single_channel_output, + uint8_t channel) { + + memset(self->buffer[0], 0, self->buffer_len); + memset(self->buffer[1], 0, self->buffer_len); + memset(self->delay_buffer, 0, self->delay_buffer_frames * self->base.channel_count * sizeof(int16_t)); + self->delay_buffer_pos[0] = self->delay_buffer_pos[1] = 0; + self->lfo_phase[0] = self->lfo_phase[1] = 0; +} + +bool common_hal_audiodelays_flanger_get_playing(audiodelays_flanger_obj_t *self) { + return self->sample != NULL; +} + +void common_hal_audiodelays_flanger_play(audiodelays_flanger_obj_t *self, mp_obj_t sample, bool loop) { + audiosample_must_match(&self->base, sample, false); + + self->sample = sample; + self->loop = loop; + + audiosample_reset_buffer(self->sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + + // Track remaining sample length in terms of bytes per sample + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + // Store if we have more data in the sample to retrieve + self->more_data = result == GET_BUFFER_MORE_DATA; +} + +void common_hal_audiodelays_flanger_stop(audiodelays_flanger_obj_t *self) { + self->sample = NULL; +} + +audioio_get_buffer_result_t audiodelays_flanger_get_buffer(audiodelays_flanger_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + + if (!single_channel_output) { + channel = 0; + } + + // Switch our buffers to the other buffer + self->last_buf_idx = !self->last_buf_idx; + + // If we are using 16 bit samples we need a 16 bit pointer, 8 bit needs an 8 bit pointer + int16_t *word_buffer = (int16_t *)self->buffer[self->last_buf_idx]; + int8_t *hword_buffer = self->buffer[self->last_buf_idx]; + uint32_t length = self->buffer_len / (self->base.bits_per_sample / 8); + + uint8_t channel_count = self->base.channel_count; + uint32_t frames = self->delay_buffer_frames; + + // For single channel output every word in this call belongs to `channel`. Otherwise the + // channels are interleaved and alternate with every word. + bool single_right = single_channel_output && channel == 1 && channel_count == 2; + + // Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample + while (length != 0) { + // Check if there is no more sample to play, we will either load more data, reset the sample if loop is on or clear the sample + if (self->sample_buffer_length == 0) { + if (!self->more_data) { // The sample has indicated it has no more data to play + if (self->loop && self->sample) { // If we are supposed to loop reset the sample to the start + audiosample_reset_buffer(self->sample, false, 0); + } else { // If we were not supposed to loop the sample, stop playing it + self->sample = NULL; + } + } + if (self->sample) { + // Load another sample buffer to play + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } + } + + if (self->sample == NULL) { + // tick all block inputs so that anything attached to them stays in sync + shared_bindings_synthio_lfo_tick(self->base.sample_rate, length / channel_count); + (void)synthio_block_slot_get(&self->min_delay_ms); + (void)synthio_block_slot_get(&self->rate); + (void)synthio_block_slot_get(&self->depth); + (void)synthio_block_slot_get(&self->feedback); + (void)synthio_block_slot_get(&self->mix); + + if (self->base.samples_signed) { + memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); + } else { + // For unsigned samples set to the middle which is "quiet" + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + uint16_t *uword_buffer = (uint16_t *)word_buffer; + while (length--) { + *uword_buffer++ = 32768; + } + } else { + memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); + } + } + + length = 0; + } else { + // we have a sample to play and flange + // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining + uint32_t num_bytes = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * channel_count); + + int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; // for 16-bit samples + int8_t *sample_hsrc = (int8_t *)self->sample_remaining_buffer; // for 8-bit samples + + // get the effect values we need from the BlockInput + shared_bindings_synthio_lfo_tick(self->base.sample_rate, num_bytes / channel_count); + mp_float_t f_min_delay_ms = synthio_block_slot_get_limited(&self->min_delay_ms, self->sample_ms, (mp_float_t)self->max_delay_ms); + mp_float_t f_rate = synthio_block_slot_get_limited(&self->rate, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(20.0)); + mp_float_t f_depth = synthio_block_slot_get_limited(&self->depth, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); + int32_t feedback = (int32_t)(synthio_block_slot_get_limited(&self->feedback, MICROPY_FLOAT_CONST(-0.95), MICROPY_FLOAT_CONST(0.95)) * 32767); + int32_t mix = (int32_t)(synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * 32767); + + // The sweep runs upward from min_delay_ms towards max_delay_ms rather than around a + // centre, so no combination of min_delay_ms and depth can push it out of the delay line. + mp_float_t sweep_top_ms = f_min_delay_ms + f_depth * ((mp_float_t)self->max_delay_ms - f_min_delay_ms); + uint32_t delay_min_q16 = flanger_ms_to_frames_q16(self, f_min_delay_ms); + uint32_t delay_span_q16 = flanger_ms_to_frames_q16(self, sweep_top_ms) - delay_min_q16; + + // How far the LFO advances each frame. A rate at or above half the sample rate is + // meaningless, and clamping there also keeps the conversion inside a uint32_t. + mp_float_t phase_inc = MIN(f_rate / self->base.sample_rate, MICROPY_FLOAT_CONST(0.5)); + self->lfo_phase_inc = (uint32_t)(phase_inc * MICROPY_FLOAT_CONST(4294967296.0)); + + for (uint32_t i = 0; i < num_bytes; i++) { + bool right_channel = single_channel_output ? single_right : ((i % channel_count) == 1); + + int32_t sample_word = 0; + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + sample_word = sample_src[i]; + } else { + if (self->base.samples_signed) { + sample_word = sample_hsrc[i]; + } else { + // changing from an 8 bit unsigned to signed into a 32-bit signed + sample_word = (int8_t)(((uint8_t)sample_hsrc[i]) ^ 0x80); + } + } + + // Advance this channel's LFO by one frame. Each channel has its own accumulator so + // that the sweep runs at `rate` whether the channels arrive interleaved (both + // accumulators step once per frame) or one channel per call. + self->lfo_phase[right_channel] += self->lfo_phase_inc; + + uint32_t tri = flanger_phase_to_triangle(self->lfo_phase[right_channel]); + + // The delay for this frame, in Q16.16 frames + uint32_t delay_q16 = delay_min_q16 + (uint32_t)(((uint64_t)delay_span_q16 * tri) >> 16); + uint32_t delay_int = delay_q16 >> 16; + uint32_t delay_frac = delay_q16 & 0xffff; + + int16_t *line = self->delay_buffer + (right_channel ? frames : 0); + uint32_t w = self->delay_buffer_pos[right_channel]; + + // Two taps straddling the fractional delay, counted back from the write head. + // delay_int is at most frames - 2 so neither index can escape the region. + uint32_t r0 = w + frames - delay_int; + if (r0 >= frames) { + r0 -= frames; + } + uint32_t r1 = r0 ? r0 - 1 : frames - 1; + + // Linear interpolation between them + int32_t s0 = line[r0]; + int32_t s1 = line[r1]; + int32_t wet = s0 + (((s1 - s0) * (int32_t)delay_frac) >> 16); + + // Write the input plus the regenerated signal back into the line + line[w] = synthio_sat16(sample_word + synthio_sat16(wet * feedback, 15), 0); + self->delay_buffer_pos[right_channel] = (w + 1 == frames) ? 0 : w + 1; + + int32_t word; + if (mix <= 328) { // if mix is zero (0.01 in fixed point), pure sample only + // Note that we still ran the delay line above. + word = sample_word; + } else { + int32_t wet_word = synthio_sat16(wet * mix, 15); + // Add (or, inverted, subtract) original sample + effect + word = self->invert ? sample_word - wet_word : sample_word + wet_word; + word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); + } + + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + word_buffer[i] = word; + if (!self->base.samples_signed) { + word_buffer[i] ^= 0x8000; + } + } else { + // 8-bit samples have no headroom for synthio_mix_down_sample to work with, so + // clamp instead or the sum of the dry and wet signals wraps around + int8_t out = MIN(MAX(word, -128), 127); + if (self->base.samples_signed) { + hword_buffer[i] = out; + } else { + hword_buffer[i] = (uint8_t)out ^ 0x80; + } + } + } + + // Update the remaining length and the buffer positions based on how much we wrote into our buffer + length -= num_bytes; + word_buffer += num_bytes; + hword_buffer += num_bytes; + self->sample_remaining_buffer += (num_bytes * (self->base.bits_per_sample / 8)); + self->sample_buffer_length -= num_bytes; + } + } + + // Finally pass our buffer and length to the calling audio function + *buffer = (uint8_t *)self->buffer[self->last_buf_idx]; + *buffer_length = self->buffer_len; + + // Flanger always returns more data but some effects may return GET_BUFFER_DONE or GET_BUFFER_ERROR (see audiocore/__init__.h) + return GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/audiodelays/Flanger.h b/shared-module/audiodelays/Flanger.h new file mode 100644 index 00000000000..6e8a37f51e2 --- /dev/null +++ b/shared-module/audiodelays/Flanger.h @@ -0,0 +1,62 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#pragma once + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/synthio/block.h" + +extern const mp_obj_type_t audiodelays_flanger_type; + +typedef struct { + audiosample_base_t base; + + // Effect parameters. + synthio_block_slot_t min_delay_ms; // floor of the sweep + synthio_block_slot_t rate; // LFO frequency in Hz + synthio_block_slot_t depth; // 0 to 1, portion of the available range swept + synthio_block_slot_t feedback; // -0.95 to 0.95, regeneration + synthio_block_slot_t mix; // 0 to 1, dry to wet + + uint32_t max_delay_ms; + mp_float_t sample_ms; // length of a single sample in milliseconds + + bool invert; // subtract the wet signal instead of adding it + + int8_t *buffer[2]; + uint8_t last_buf_idx; + uint32_t buffer_len; // max buffer in bytes + + uint8_t *sample_remaining_buffer; + uint32_t sample_buffer_length; + + bool loop; + bool more_data; + + // The delay line is always 16-bit and is split into one contiguous region per channel so + // that read/write positions are plain frame counts and wrapping is a single modulo. + int16_t *delay_buffer; + uint32_t delay_buffer_frames; // frames in each per channel region + uint32_t delay_buffer_pos[2]; // write position in frames, per channel + + // Internal LFO. One phase accumulator per channel so that the sweep advances once per frame + // whether the channels are interleaved in one call or requested one channel at a time. + uint32_t lfo_phase[2]; // Q0.32, wraps naturally + uint32_t lfo_phase_inc; // Q0.32 step per frame, recalculated per chunk from rate + + mp_obj_t sample; +} audiodelays_flanger_obj_t; + +void audiodelays_flanger_reset_buffer(audiodelays_flanger_obj_t *self, + bool single_channel_output, + uint8_t channel); + +audioio_get_buffer_result_t audiodelays_flanger_get_buffer(audiodelays_flanger_obj_t *self, + bool single_channel_output, + uint8_t channel, + uint8_t **buffer, + uint32_t *buffer_length); // length in bytes diff --git a/shared-module/audiodelays/GranularPitchShift.c b/shared-module/audiodelays/GranularPitchShift.c new file mode 100644 index 00000000000..a737307d553 --- /dev/null +++ b/shared-module/audiodelays/GranularPitchShift.c @@ -0,0 +1,478 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#include "shared-bindings/audiodelays/GranularPitchShift.h" +#include "shared-bindings/audiocore/__init__.h" + +#include +#include "py/runtime.h" +#include + +void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_pitch_shift_obj_t *self, + mp_obj_t semitones, mp_obj_t mix, uint32_t grain_size, uint32_t density, + mp_float_t spread, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, + uint8_t channel_count, uint32_t sample_rate) { + + // Basic settings every effect and audio sample has + // These are the effect's values, not the source sample(s) + self->base.bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places + self->base.samples_signed = samples_signed; // Are the samples we provide signed + self->base.channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo + self->base.sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.single_buffer = false; + self->base.max_buffer_length = buffer_size; + + // To smooth things out as CircuitPython is doing other tasks most audio objects have a buffer + // A double buffer is set up here so the audio output can use DMA on buffer 1 while we + // write to and create buffer 2. + // This buffer is what is passed to the audio component that plays the effect. + // Samples are set sequentially. For stereo audio they are passed L/R/L/R/... + self->buffer_len = buffer_size; // in bytes + + self->buffer[0] = m_malloc_without_collect(self->buffer_len); + if (self->buffer[0] == NULL) { + common_hal_audiodelays_granular_pitch_shift_deinit(self); + m_malloc_fail(self->buffer_len); + } + memset(self->buffer[0], 0, self->buffer_len); + + self->buffer[1] = m_malloc_without_collect(self->buffer_len); + if (self->buffer[1] == NULL) { + common_hal_audiodelays_granular_pitch_shift_deinit(self); + m_malloc_fail(self->buffer_len); + } + memset(self->buffer[1], 0, self->buffer_len); + + self->last_buf_idx = 1; // Which buffer to use first, toggle between 0 and 1 + + // Initialize other values most effects will need. + self->sample = NULL; // The current playing sample + self->sample_remaining_buffer = NULL; // Pointer to the start of the sample buffer we have not played + self->sample_buffer_length = 0; // How many samples do we have left to play (these may be 16 bit!) + self->loop = false; // When the sample is done do we loop to the start again or stop (e.g. in a wav file) + self->more_data = false; // Is there still more data to read from the sample or did we finish + + // The below section sets up the effect's starting values. + + synthio_block_assign_slot(semitones, &self->semitones, MP_QSTR_semitones); + synthio_block_assign_slot(mix, &self->mix, MP_QSTR_mix); + + // Grain scheduling parameters. `density` (number of overlapping grains) is + // clamped to the fixed grain pool size so allocation stays deterministic. + self->grain_size = grain_size; + if (density < 1) { + density = 1; + } + if (density > GRANULAR_MAX_GRAINS) { + density = GRANULAR_MAX_GRAINS; + } + self->density = density; + + // Grain-start jitter amount and the PRNG that drives it. Seeded with a fixed + // nonzero constant so xorshift32 never degenerates to the all-zero state and + // the jitter sequence is reproducible from run to run. + common_hal_audiodelays_granular_pitch_shift_set_spread(self, spread); + self->rng_state = 0x1234abcdu; + + // Normalization for the overlap-add gain of the grain envelopes. A Hann + // window overlapped at hop = grain_size / density sums to a constant gain of + // density/2, so we scale the summed grains by 2/density in Q15 to keep the + // output at ~unity. Cap at 1.0 so the degenerate density==1 case (a single + // windowed grain, no overlap partner) is never amplified. + self->grain_gain = (1 << 15) * 2 / density; // 2/density in Q15 + if (self->grain_gain > (1 << 15)) { + self->grain_gain = (1 << 15); + } + + // Capture buffer (the delay line grains read from), stored as 16-bit, + // planar per channel. Length is grain_size * 2 words per channel so a grain + // starting grain_size words behind the write pointer never overruns the live + // write cursor even when reading ahead at a raised pitch + self->capture_len = self->grain_size * 2; // words per channel + uint32_t capture_bytes = self->capture_len * self->base.channel_count * sizeof(int16_t); + self->capture_buffer = m_malloc_without_collect(capture_bytes); + if (self->capture_buffer == NULL) { + common_hal_audiodelays_granular_pitch_shift_deinit(self); + m_malloc_fail(capture_bytes); + } + memset(self->capture_buffer, 0, capture_bytes); + self->write_index = 0; + + // Precompute the grain amplitude envelope: a raised-cosine (Hann) window in + // Q15 (0..32767), indexed directly by a grain's phase. + self->envelope_len = self->grain_size; + uint32_t envelope_bytes = self->envelope_len * sizeof(int16_t); + self->envelope_table = m_malloc_without_collect(envelope_bytes); + if (self->envelope_table == NULL) { + common_hal_audiodelays_granular_pitch_shift_deinit(self); + m_malloc_fail(envelope_bytes); + } + mp_float_t denom = (self->envelope_len > 1) ? (mp_float_t)(self->envelope_len - 1) : MICROPY_FLOAT_CONST(1.0); + for (uint32_t n = 0; n < self->envelope_len; n++) { + mp_float_t w = MICROPY_FLOAT_CONST(0.5) * + (MICROPY_FLOAT_CONST(1.0) - MICROPY_FLOAT_C_FUN(cos)( + MICROPY_FLOAT_CONST(2.0) * MICROPY_FLOAT_CONST(3.14159265358979323846) * (mp_float_t)n / denom)); + self->envelope_table[n] = (int16_t)(w * MICROPY_FLOAT_CONST(32767.0)); + } + + // Deactivate all grains and prime the scheduler so the first grain launches + // immediately on the first output sample. + for (uint32_t i = 0; i < GRANULAR_MAX_GRAINS; i++) { + self->grains[i].active = false; + } + self->samples_until_next_grain = 0; + + // Calculate the fixed-point read-rate increment applied to launched grains. + mp_float_t f_semitones = synthio_block_slot_get(&self->semitones); + granular_pitch_shift_recalculate_rate(self, f_semitones); +} + +void common_hal_audiodelays_granular_pitch_shift_deinit(audiodelays_granular_pitch_shift_obj_t *self) { + audiosample_mark_deinit(&self->base); + self->envelope_table = NULL; + self->capture_buffer = NULL; + self->buffer[0] = NULL; + self->buffer[1] = NULL; +} + +mp_obj_t common_hal_audiodelays_granular_pitch_shift_get_semitones(audiodelays_granular_pitch_shift_obj_t *self) { + return self->semitones.obj; +} + +void common_hal_audiodelays_granular_pitch_shift_set_semitones(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t semitones_in) { + synthio_block_assign_slot(semitones_in, &self->semitones, MP_QSTR_semitones); + mp_float_t semitones = synthio_block_slot_get(&self->semitones); + granular_pitch_shift_recalculate_rate(self, semitones); +} + +void granular_pitch_shift_recalculate_rate(audiodelays_granular_pitch_shift_obj_t *self, mp_float_t semitones) { + self->read_rate = (uint32_t)(MICROPY_FLOAT_C_FUN(pow)(2.0, semitones / MICROPY_FLOAT_CONST(12.0)) * (1 << GRANULAR_PITCH_READ_SHIFT)); + self->current_semitones = semitones; +} + +mp_obj_t common_hal_audiodelays_granular_pitch_shift_get_mix(audiodelays_granular_pitch_shift_obj_t *self) { + return self->mix.obj; +} + +void common_hal_audiodelays_granular_pitch_shift_set_mix(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t arg) { + synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); +} + +mp_float_t common_hal_audiodelays_granular_pitch_shift_get_spread(audiodelays_granular_pitch_shift_obj_t *self) { + return self->spread; +} + +void common_hal_audiodelays_granular_pitch_shift_set_spread(audiodelays_granular_pitch_shift_obj_t *self, mp_float_t spread) { + if (spread < MICROPY_FLOAT_CONST(0.0)) { + spread = MICROPY_FLOAT_CONST(0.0); + } else if (spread > MICROPY_FLOAT_CONST(1.0)) { + spread = MICROPY_FLOAT_CONST(1.0); + } + self->spread = spread; +} + +void audiodelays_granular_pitch_shift_reset_buffer(audiodelays_granular_pitch_shift_obj_t *self, + bool single_channel_output, + uint8_t channel) { + + memset(self->buffer[0], 0, self->buffer_len); + memset(self->buffer[1], 0, self->buffer_len); + memset(self->capture_buffer, 0, self->capture_len * self->base.channel_count * sizeof(int16_t)); + + // Deactivate all grains and reset the scheduler/write cursor. + for (uint32_t i = 0; i < GRANULAR_MAX_GRAINS; i++) { + self->grains[i].active = false; + } + self->samples_until_next_grain = 0; + self->write_index = 0; +} + +bool common_hal_audiodelays_granular_pitch_shift_get_playing(audiodelays_granular_pitch_shift_obj_t *self) { + return self->sample != NULL; +} + +void common_hal_audiodelays_granular_pitch_shift_play(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t sample, bool loop) { + audiosample_must_match(&self->base, sample, false); + + self->sample = sample; + self->loop = loop; + + audiosample_reset_buffer(self->sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + + // Track remaining sample length in terms of bytes per sample + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + // Store if we have more data in the sample to retrieve + self->more_data = result == GET_BUFFER_MORE_DATA; + + return; +} + +void common_hal_audiodelays_granular_pitch_shift_stop(audiodelays_granular_pitch_shift_obj_t *self) { + // When the sample is set to stop playing do any cleanup here + self->sample = NULL; + return; +} + +// xorshift32 PRNG for grain-start jitter. Kept local to this module so the +// effect doesn't depend on the `random` module being enabled in a build. +static uint32_t granular_pitch_shift_rand(audiodelays_granular_pitch_shift_obj_t *self) { + uint32_t x = self->rng_state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + self->rng_state = x; + return x; +} + +// Launch a grain into the first free pool slot, seeded to read from the capture +// buffer starting grain_size words behind the current write cursor (so it reads +// already-captured audio) at the current pitch-shift read rate. When `spread` is +// nonzero the start is jittered up to a further grain_size words backward, which +// is what gives granular synthesis its characteristic "cloud" texture. Jitter is +// always backward (further behind the write cursor), so a grain never reads ahead +// of captured audio and the capture buffer (capture_len == grain_size * 2) is +// never overrun. Grain read state (read_index/phase) is per-frame / +// channel-independent; the per-channel plane offset is applied at read time. +static void granular_pitch_shift_launch_grain(audiodelays_granular_pitch_shift_obj_t *self) { + for (uint32_t g = 0; g < GRANULAR_MAX_GRAINS; g++) { + if (!self->grains[g].active) { + // Backward jitter in [0, spread * grain_size]. Capped at grain_size + // so grain_size + jitter <= capture_len (== grain_size * 2). + uint32_t jitter = 0; + if (self->spread > MICROPY_FLOAT_CONST(0.0)) { + uint32_t max_jitter = (uint32_t)(self->spread * (mp_float_t)self->grain_size); + if (max_jitter > 0) { + jitter = granular_pitch_shift_rand(self) % (max_jitter + 1); + } + } + uint32_t start = (self->write_index + self->capture_len - self->grain_size - jitter) % self->capture_len; + self->grains[g].active = true; + self->grains[g].read_index = start << GRANULAR_PITCH_READ_SHIFT; + self->grains[g].read_rate = self->read_rate; + self->grains[g].phase = 0; + self->grains[g].length = self->grain_size; + return; + } + } +} + +audioio_get_buffer_result_t audiodelays_granular_pitch_shift_get_buffer(audiodelays_granular_pitch_shift_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + + // Grain scheduler + enveloped grain playback with dry/wet `mix` blending. + // Grains are launched at a fixed spacing (grain_size / density) and each + // active grain reads the capture buffer at its own pitch-shifted (fractional, + // linearly interpolated) read rate, scaled by a Hann amplitude envelope so + // overlapping grains fade in/out and add without seam clicks. The summed + // grains are normalized by grain_gain for ~unity overlap-add gain, then + // crossfaded against the dry input via the `mix` slot. The 8/16-bit, + // signed/unsigned, and mono/stereo (planar capture, buf_offset) paths are all + // handled below, mirroring PitchShift. + + if (!single_channel_output) { + channel = 0; + } + + // Switch our buffers to the other buffer + self->last_buf_idx = !self->last_buf_idx; + + // If we are using 16 bit samples we need a 16 bit pointer, 8 bit needs an 8 bit pointer + int16_t *word_buffer = (int16_t *)self->buffer[self->last_buf_idx]; + int8_t *hword_buffer = self->buffer[self->last_buf_idx]; + uint32_t length = self->buffer_len / (self->base.bits_per_sample / 8); + + // The capture buffer (delay line) is always stored as 16-bit, planar per + // channel: channel c occupies capture_buffer[c * capture_len .. ). + int16_t *capture_buffer = self->capture_buffer; + + // Grains are launched this many frames apart (overlap factor `density`). + uint32_t grain_spacing = self->grain_size / self->density; + if (grain_spacing == 0) { + grain_spacing = 1; + } + + // Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample + while (length != 0) { + // Check if there is no more sample to play, we will either load more data, reset the sample if loop is on or clear the sample + if (self->sample_buffer_length == 0) { + if (!self->more_data) { // The sample has indicated it has no more data to play + if (self->loop && self->sample) { // If we are supposed to loop reset the sample to the start + audiosample_reset_buffer(self->sample, false, 0); + } else { // If we were not supposed to loop the sample, stop playing it + self->sample = NULL; + } + } + if (self->sample) { + // Load another sample buffer to play + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + if (result == GET_BUFFER_ERROR) { + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } + } + } + + if (self->sample == NULL) { + if (self->base.samples_signed) { + memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); + } else { + // For unsigned samples set to the middle which is "quiet" + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + for (uint32_t i = 0; i < length; i++) { + word_buffer[i] = (int16_t)0x8000; + } + } else { + memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); + } + } + + // tick all block inputs + shared_bindings_synthio_lfo_tick(self->base.sample_rate, length / self->base.channel_count); + (void)synthio_block_slot_get(&self->semitones); + (void)synthio_block_slot_get(&self->mix); + + length = 0; + } else { + // we have a sample to play and apply effect + // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining + uint32_t n = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * self->base.channel_count); + + int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; // for 16-bit samples + int8_t *sample_hsrc = (int8_t *)self->sample_remaining_buffer; // for 8-bit samples + + // get the effect values we need from the BlockInput. + shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); + mp_float_t semitones = synthio_block_slot_get(&self->semitones); + // Doubled (0.0..2.0) so the crossfade below can hold both dry and wet + // at full gain around the midpoint, matching PitchShift's mix curve. + mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * MICROPY_FLOAT_CONST(2.0); + + // Only recalculate rate if semitones has changed + if (memcmp(&semitones, &self->current_semitones, sizeof(mp_float_t))) { + granular_pitch_shift_recalculate_rate(self, semitones); + } + + for (uint32_t i = 0; i < n; i++) { + bool buf_offset = (channel == 1 || i % self->base.channel_count == 1); + + int32_t sample_word = 0; + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + sample_word = sample_src[i]; + } else { + if (self->base.samples_signed) { + sample_word = sample_hsrc[i]; + } else { + // Changing from an 8 bit unsigned to signed into a 32-bit signed + sample_word = (int8_t)(((uint8_t)sample_hsrc[i]) ^ 0x80); + } + } + + // Write the incoming sample into the capture buffer (the delay + // line grains read from) at the per-channel write cursor. + capture_buffer[self->write_index + self->capture_len * buf_offset] = (int16_t)sample_word; + + // Sum all active grains. Each grain reads the capture buffer at + // its own fractional read cursor (linearly interpolated between + // adjacent words), which is what produces the pitch shift, then + // is scaled by its amplitude envelope (Hann, indexed by the + // grain's phase) so grains fade in/out and overlap-add without + // seam clicks. + int32_t word = 0; + for (uint32_t g = 0; g < GRANULAR_MAX_GRAINS; g++) { + if (!self->grains[g].active) { + continue; + } + uint32_t read_index_fp = self->grains[g].read_index; + uint32_t ipart = read_index_fp >> GRANULAR_PITCH_READ_SHIFT; + uint32_t frac = read_index_fp & ((1 << GRANULAR_PITCH_READ_SHIFT) - 1); + uint32_t index_lo = ipart % self->capture_len; + uint32_t index_hi = (ipart + 1) % self->capture_len; + int32_t sample_lo = capture_buffer[index_lo + self->capture_len * buf_offset]; + int32_t sample_hi = capture_buffer[index_hi + self->capture_len * buf_offset]; + int32_t grain_out = sample_lo + (((sample_hi - sample_lo) * (int32_t)frac) >> GRANULAR_PITCH_READ_SHIFT); + // Apply the grain envelope (Q15). phase < length == envelope_len. + int32_t env = self->envelope_table[self->grains[g].phase]; + word += (grain_out * env) >> 15; + } + + // Normalize the overlap-add gain of the enveloped grains back to + // ~unity (int64 guards the Q15 multiply against overflow). This is + // the fully-wet (pitch-shifted) sample. + word = (int32_t)(((int64_t)word * (int64_t)self->grain_gain) >> 15); + + // Dry/wet crossfade: `mix` is doubled to 0.0..2.0 so both terms + // sit at full gain around the midpoint, then synthio_mix_down_sample + // scales/soft-clips the summed pair back into range (same curve as + // PitchShift). mix=0.0 -> dry input, mix=1.0 -> fully wet. + word = (int32_t)((sample_word * MIN(MICROPY_FLOAT_CONST(2.0) - mix, MICROPY_FLOAT_CONST(1.0))) + (word * MIN(mix, MICROPY_FLOAT_CONST(1.0)))); + word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); + + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + word_buffer[i] = (int16_t)word; + if (!self->base.samples_signed) { + word_buffer[i] ^= 0x8000; + } + } else { + int8_t mixed = (int8_t)word; + if (self->base.samples_signed) { + hword_buffer[i] = mixed; + } else { + hword_buffer[i] = (uint8_t)mixed ^ 0x80; + } + } + + // Per-frame shared work (once per frame: mono every sample, + // interleaved stereo on the right-channel sample) so both + // channels read consistent grain state before it advances. + if (self->base.channel_count == 1 || buf_offset) { + // Advance and retire active grains (they were read above). + for (uint32_t g = 0; g < GRANULAR_MAX_GRAINS; g++) { + if (!self->grains[g].active) { + continue; + } + self->grains[g].read_index += self->grains[g].read_rate; + self->grains[g].phase++; + if (self->grains[g].phase >= self->grains[g].length) { + self->grains[g].active = false; + } + } + + // Launch a new grain when the scheduler counter elapses. + if (self->samples_until_next_grain == 0) { + granular_pitch_shift_launch_grain(self); + self->samples_until_next_grain = grain_spacing; + } else { + self->samples_until_next_grain--; + } + + // Advance the per-channel write cursor. + self->write_index++; + if (self->write_index >= self->capture_len) { + self->write_index = 0; + } + } + } + + // Update the remaining length and the buffer positions based on how much we wrote into our buffer + length -= n; + word_buffer += n; + hword_buffer += n; + self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8)); + self->sample_buffer_length -= n; + } + } + + // Finally pass our buffer and length to the calling audio function + *buffer = (uint8_t *)self->buffer[self->last_buf_idx]; + *buffer_length = self->buffer_len; + + return GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/audiodelays/GranularPitchShift.h b/shared-module/audiodelays/GranularPitchShift.h new file mode 100644 index 00000000000..26ee4804f36 --- /dev/null +++ b/shared-module/audiodelays/GranularPitchShift.h @@ -0,0 +1,104 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#pragma once + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/synthio/__init__.h" +#include "shared-module/synthio/block.h" + +// Fixed-point fractional bits for grain read cursors and read rate. A grain's +// read_index and read_rate are stored as (words << GRANULAR_PITCH_READ_SHIFT), +// mirroring PITCH_READ_SHIFT from PitchShift.h. +#define GRANULAR_PITCH_READ_SHIFT (8) + +// Maximum number of concurrently active grains. `density` is clamped to this at +// construction so the grain pool is a fixed, deterministic allocation. +#define GRANULAR_MAX_GRAINS (8) + +extern const mp_obj_type_t audiodelays_granular_pitch_shift_type; + +// A single grain: a short, independently-scheduled, enveloped read of the +// capture buffer. Retired when `phase` reaches `length`. +typedef struct { + bool active; + uint32_t read_index; // words << GRANULAR_PITCH_READ_SHIFT into the capture buffer + uint32_t read_rate; // words << GRANULAR_PITCH_READ_SHIFT, the pitch-shift increment + uint32_t phase; // samples elapsed since the grain launched + uint32_t length; // grain length in samples (== grain_size) +} audiodelays_granular_grain_t; + +typedef struct { + audiosample_base_t base; + synthio_block_slot_t semitones; + mp_float_t current_semitones; + synthio_block_slot_t mix; + + // Double playback buffers (what we hand back to the audio component). + int8_t *buffer[2]; + uint8_t last_buf_idx; + uint32_t buffer_len; // max buffer in bytes + + // Current sample source bookkeeping. + uint8_t *sample_remaining_buffer; + uint32_t sample_buffer_length; + + bool loop; + bool more_data; + + // Capture buffer (the delay line grains read from). Always stored as 16-bit + // internally, planar per channel: channel c occupies + // capture_buffer[c * capture_len .. (c + 1) * capture_len). + int16_t *capture_buffer; + uint32_t capture_len; // words per channel + uint32_t write_index; // words, per-channel write cursor (0 .. capture_len) + + // Grain pool + scheduler. + audiodelays_granular_grain_t grains[GRANULAR_MAX_GRAINS]; + uint32_t samples_until_next_grain; + + uint32_t grain_size; // samples per grain + uint32_t density; // number of overlapping grains (<= GRANULAR_MAX_GRAINS) + + // Granular jitter: randomizes each grain's start position within the capture + // buffer. 0.0 is fully deterministic (grains always start grain_size words + // behind the write cursor); 1.0 spreads the start up to a further grain_size + // words backward, giving the classic granular "cloud" texture. Jitter is + // always backward (further behind the write cursor) so it never reads ahead + // of captured audio. + mp_float_t spread; + uint32_t rng_state; // xorshift32 state for grain-start jitter + + // Q15 (0..32768) normalization applied to the enveloped grain sum so the + // overlap-add gain of `density` Hann grains stays ~unity (Hann satisfies + // COLA at these hops with a summed gain of density/2, so the factor is + // 2/density, capped at 1.0 so a single grain is never amplified). + uint32_t grain_gain; + + // Precomputed amplitude envelope (raised-cosine / Hann), Q15 (0..32767), + // indexed directly by a grain's phase (envelope_len == grain_size). + int16_t *envelope_table; + uint32_t envelope_len; + + // Fixed-point read-rate increment computed from `semitones`, applied to each + // launched grain's read_rate. + uint32_t read_rate; // words << GRANULAR_PITCH_READ_SHIFT + + mp_obj_t sample; +} audiodelays_granular_pitch_shift_obj_t; + +void granular_pitch_shift_recalculate_rate(audiodelays_granular_pitch_shift_obj_t *self, mp_float_t semitones); + +void audiodelays_granular_pitch_shift_reset_buffer(audiodelays_granular_pitch_shift_obj_t *self, + bool single_channel_output, + uint8_t channel); + +audioio_get_buffer_result_t audiodelays_granular_pitch_shift_get_buffer(audiodelays_granular_pitch_shift_obj_t *self, + bool single_channel_output, + uint8_t channel, + uint8_t **buffer, + uint32_t *buffer_length); // length in bytes diff --git a/shared-module/audiodelays/MultiTapDelay.c b/shared-module/audiodelays/MultiTapDelay.c index 9c33a5eaee7..d4cda65b0ed 100644 --- a/shared-module/audiodelays/MultiTapDelay.c +++ b/shared-module/audiodelays/MultiTapDelay.c @@ -118,12 +118,13 @@ void common_hal_audiodelays_multi_tap_delay_set_delay_ms(audiodelays_multi_tap_d self->delay_buffer_len = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * self->delay_ms) * (self->base.channel_count * sizeof(uint16_t)); // Limit to valid range - if (self->delay_buffer_len > self->max_delay_buffer_len) { - self->delay_buffer_len = self->max_delay_buffer_len; - } else if (self->delay_buffer_len < self->buffer_len) { + if (self->delay_buffer_len < self->buffer_len) { // If the delay buffer is smaller than our audio buffer, weird things happen self->delay_buffer_len = self->buffer_len; } + if (self->delay_buffer_len > self->max_delay_buffer_len) { + self->delay_buffer_len = self->max_delay_buffer_len; + } // Clear the now unused part of the buffer or some weird artifacts appear memset(self->delay_buffer + self->delay_buffer_len, 0, self->max_delay_buffer_len - self->delay_buffer_len); @@ -348,9 +349,15 @@ audioio_get_buffer_result_t audiodelays_multi_tap_delay_get_buffer(audiodelays_m if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiodelays/PitchShift.c b/shared-module/audiodelays/PitchShift.c index 3b8c1a07c7b..809efaf77b1 100644 --- a/shared-module/audiodelays/PitchShift.c +++ b/shared-module/audiodelays/PitchShift.c @@ -58,8 +58,10 @@ void common_hal_audiodelays_pitch_shift_construct(audiodelays_pitch_shift_obj_t synthio_block_assign_slot(semitones, &self->semitones, MP_QSTR_semitones); synthio_block_assign_slot(mix, &self->mix, MP_QSTR_mix); + self->freeze = false; // Allocate the window buffer + mp_arg_validate_int_min(window, sizeof(uint16_t) * channel_count, MP_QSTR_window); self->window_len = window; // bytes self->window_buffer = m_malloc_without_collect(self->window_len); if (self->window_buffer == NULL) { @@ -126,9 +128,18 @@ void common_hal_audiodelays_pitch_shift_set_mix(audiodelays_pitch_shift_obj_t *s synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); } +bool common_hal_audiodelays_pitch_shift_get_freeze(audiodelays_pitch_shift_obj_t *self) { + return self->freeze; +} + +void common_hal_audiodelays_pitch_shift_set_freeze(audiodelays_pitch_shift_obj_t *self, bool freeze) { + self->freeze = freeze; +} + void audiodelays_pitch_shift_reset_buffer(audiodelays_pitch_shift_obj_t *self, bool single_channel_output, uint8_t channel) { + self->freeze = false; memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); @@ -205,9 +216,15 @@ audioio_get_buffer_result_t audiodelays_pitch_shift_get_buffer(audiodelays_pitch if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } @@ -217,7 +234,9 @@ audioio_get_buffer_result_t audiodelays_pitch_shift_get_buffer(audiodelays_pitch } else { // For unsigned samples set to the middle which is "quiet" if (MP_LIKELY(self->base.bits_per_sample == 16)) { - memset(word_buffer, 32768, length * (self->base.bits_per_sample / 8)); + for (uint32_t si = 0; si < length; si++) { + word_buffer[si] = (int16_t)0x8000; + } } else { memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); } @@ -262,15 +281,17 @@ audioio_get_buffer_result_t audiodelays_pitch_shift_get_buffer(audiodelays_pitch } } - if (overlap_size) { - // Copy last sample from overlap and store in buffer - window_buffer[self->window_index + window_size * buf_offset] = overlap_buffer[self->overlap_index + overlap_size * buf_offset]; + if (!self->freeze) { + if (overlap_size) { + // Copy last sample from overlap and store in buffer + window_buffer[self->window_index + window_size * buf_offset] = overlap_buffer[self->overlap_index + overlap_size * buf_offset]; - // Save current sample in overlap - overlap_buffer[self->overlap_index + overlap_size * buf_offset] = (int16_t)sample_word; - } else { - // Write sample to buffer - window_buffer[self->window_index + window_size * buf_offset] = (int16_t)sample_word; + // Save current sample in overlap + overlap_buffer[self->overlap_index + overlap_size * buf_offset] = (int16_t)sample_word; + } else { + // Write sample to buffer + window_buffer[self->window_index + window_size * buf_offset] = (int16_t)sample_word; + } } // Determine how far we are into the overlap @@ -310,17 +331,19 @@ audioio_get_buffer_result_t audiodelays_pitch_shift_get_buffer(audiodelays_pitch } if (self->base.channel_count == 1 || buf_offset) { - // Increment window buffer write pointer - self->window_index++; - if (self->window_index >= window_size) { - self->window_index = 0; - } + if (!self->freeze) { + // Increment window buffer write pointer + self->window_index++; + if (self->window_index >= window_size) { + self->window_index = 0; + } - // Increment overlap buffer pointer - if (overlap_size) { - self->overlap_index++; - if (self->overlap_index >= overlap_size) { - self->overlap_index = 0; + // Increment overlap buffer pointer + if (overlap_size) { + self->overlap_index++; + if (self->overlap_index >= overlap_size) { + self->overlap_index = 0; + } } } diff --git a/shared-module/audiodelays/PitchShift.h b/shared-module/audiodelays/PitchShift.h index dddcfa4efc0..f156186b7f6 100644 --- a/shared-module/audiodelays/PitchShift.h +++ b/shared-module/audiodelays/PitchShift.h @@ -20,6 +20,7 @@ typedef struct { synthio_block_slot_t semitones; mp_float_t current_semitones; synthio_block_slot_t mix; + bool freeze; uint32_t window_len; uint32_t overlap_len; diff --git a/shared-module/audiofilewriter/AudioFileWriter.c b/shared-module/audiofilewriter/AudioFileWriter.c new file mode 100644 index 00000000000..099345888a0 --- /dev/null +++ b/shared-module/audiofilewriter/AudioFileWriter.c @@ -0,0 +1,403 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiofilewriter/AudioFileWriter.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-module/audiocore/__init__.h" + +#include + +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/stream.h" + +#include "supervisor/background_callback.h" +#include "supervisor/shared/tick.h" + +// --------------------------------------------------------------------------- +// Little-endian header helpers +// --------------------------------------------------------------------------- + +static void put_u16le(uint8_t *p, uint16_t v) { + p[0] = (uint8_t)v; + p[1] = (uint8_t)(v >> 8); +} + +static void put_u32le(uint8_t *p, uint32_t v) { + p[0] = (uint8_t)v; + p[1] = (uint8_t)(v >> 8); + p[2] = (uint8_t)(v >> 16); + p[3] = (uint8_t)(v >> 24); +} + +// --------------------------------------------------------------------------- +// Active-writer registry, walked once per supervisor tick. +// +// The list head lives in MP_STATE_VM (see MP_REGISTER_ROOT_POINTER below) so +// that (a) active writers and their reg_next chain are GC-rooted while +// recording, and (b) the list is wiped automatically when the VM heap is +// recreated on soft reset. +// --------------------------------------------------------------------------- + +#define REGISTRY_HEAD ((audiofilewriter_audiofilewriter_obj_t *)MP_STATE_VM(audiofilewriter_linked_list)) + +// Add self to the registry. Called from Python (play()) context, so it must +// guard against a background tick walking the list mid-mutation. +static void audiofilewriter_register(audiofilewriter_audiofilewriter_obj_t *self) { + background_callback_prevent(); + // Avoid double-linking if already present. + bool present = false; + for (audiofilewriter_audiofilewriter_obj_t *w = REGISTRY_HEAD; w != NULL; w = w->reg_next) { + if (w == self) { + present = true; + break; + } + } + if (!present) { + self->reg_next = REGISTRY_HEAD; + MP_STATE_VM(audiofilewriter_linked_list) = self; + } + background_callback_allow(); +} + +// Remove self from the registry. Callers must ensure no background tick is +// walking the list concurrently: either they are the background tick itself +// (single-threaded, so safe), or they wrap the call in prevent/allow. +static void audiofilewriter_unregister(audiofilewriter_audiofilewriter_obj_t *self) { + audiofilewriter_audiofilewriter_obj_t **pp = (audiofilewriter_audiofilewriter_obj_t **)&MP_STATE_VM(audiofilewriter_linked_list); + while (*pp != NULL) { + if (*pp == self) { + *pp = self->reg_next; + self->reg_next = NULL; + return; + } + pp = &(*pp)->reg_next; + } +} + +// --------------------------------------------------------------------------- +// RAM ring +// --------------------------------------------------------------------------- + +// Copy len bytes from src into the ring. The caller guarantees there is room. +// 8-bit signed PCM is flipped to unsigned to match the WAV convention. +static void audiofilewriter_ring_write(audiofilewriter_audiofilewriter_obj_t *self, const uint8_t *src, uint32_t len) { + bool flip = (self->bits_per_sample == 8 && self->samples_signed); + uint32_t i = 0; + while (i < len) { + uint32_t span = self->ring_size - self->ring_head; + if (span > (len - i)) { + span = len - i; + } + if (flip) { + for (uint32_t j = 0; j < span; j++) { + self->ring[self->ring_head + j] = src[i + j] ^ 0x80; + } + } else { + memcpy(self->ring + self->ring_head, src + i, span); + } + self->ring_head += span; + if (self->ring_head == self->ring_size) { + self->ring_head = 0; + } + i += span; + } + self->ring_count += len; +} + +// Drain the ring to the file. Returns false on a write error. Non-raising: +// safe to call from background-task context. +static bool audiofilewriter_flush(audiofilewriter_audiofilewriter_obj_t *self) { + while (self->ring_count > 0) { + uint32_t span = self->ring_size - self->ring_tail; + if (span > self->ring_count) { + span = self->ring_count; + } + int err = 0; + mp_uint_t wrote = mp_stream_write_exactly(self->file, self->ring + self->ring_tail, span, &err); + if (err != 0 || wrote != span) { + return false; + } + self->ring_tail += span; + if (self->ring_tail == self->ring_size) { + self->ring_tail = 0; + } + self->ring_count -= span; + self->data_bytes += span; + } + return true; +} + +// --------------------------------------------------------------------------- +// Header patching + finalize +// --------------------------------------------------------------------------- + +static void audiofilewriter_patch_header(audiofilewriter_audiofilewriter_obj_t *self) { + uint8_t sz[4]; + int err = 0; + + // RIFF chunk size lives at header_offset + 4. + put_u32le(sz, 36 + self->data_bytes); + if (mp_stream_seek(self->file, self->header_offset + 4, MP_SEEK_SET, &err) == (mp_off_t)-1) { + return; + } + mp_stream_write_exactly(self->file, sz, 4, &err); + + // data chunk size lives at header_offset + 40. + put_u32le(sz, self->data_bytes); + if (mp_stream_seek(self->file, self->header_offset + 40, MP_SEEK_SET, &err) == (mp_off_t)-1) { + return; + } + mp_stream_write_exactly(self->file, sz, 4, &err); + + // Leave the cursor at the end of the PCM so the caller can keep appending + // or simply close the file. + mp_stream_seek(self->file, self->header_offset + 44 + self->data_bytes, MP_SEEK_SET, &err); +} + +// Stop pumping, drain, patch the header, and release the source. Idempotent: +// only the first call (while playing) does work. Non-raising. +static void audiofilewriter_finalize(audiofilewriter_audiofilewriter_obj_t *self) { + if (!self->playing) { + return; + } + // Stop the pump first so a background tick can't re-enter us. + self->playing = false; + + audiofilewriter_flush(self); + audiofilewriter_patch_header(self); + + supervisor_disable_tick(); + audiofilewriter_unregister(self); + self->sample = MP_OBJ_NULL; +} + +// --------------------------------------------------------------------------- +// The pump: one real-time-paced step per supervisor tick +// --------------------------------------------------------------------------- + +static void audiofilewriter_pump(audiofilewriter_audiofilewriter_obj_t *self) { + if (!self->playing) { + return; + } + + // The pull granularity through the chain is one source buffer, so we pace + // in whole-buffer units. + int64_t frames_per_pull = (int64_t)(self->source_max_buffer / self->bytes_per_frame); + if (frames_per_pull < 1) { + frames_per_pull = 1; + } + + // Accrue a real-time sample budget from elapsed ticks. + uint64_t now = supervisor_ticks_ms64(); + uint64_t elapsed = now - self->last_tick_ms; + self->last_tick_ms = now; + // Ignore long gaps (GC pause, SD stall) so we don't try to catch up an + // unbounded backlog all at once. + if (elapsed > 100) { + elapsed = 100; + } + self->budget_frames += (int64_t)((elapsed * self->sample_rate) / 1000); + // Never bank more than a single buffer of catch-up. For a LIVE source the + // captured audio sits in the source's own bounded ring; once we fall more + // than that behind, the surplus is already gone, so a large banked budget + // cannot recover it -- it would only burst-drain the source on consecutive + // ticks and then silence-pad, stretching one stall into a long glitch. + // Capping at one buffer yields at most one brief discontinuity per stall. + if (self->budget_frames > frames_per_pull) { + self->budget_frames = frames_per_pull; + } + + // Pull one buffer only once a full buffer of real time has elapsed: strict + // real-time pacing so we never pull ahead of a live source (which would + // only hand back silence). Also require room for a full source buffer. + if (!self->source_done && self->budget_frames >= frames_per_pull && + (self->ring_size - self->ring_count) >= self->source_max_buffer) { + uint8_t *buf = NULL; + uint32_t len = 0; + audioio_get_buffer_result_t res = + audiosample_get_buffer(self->sample, false, 0, &buf, &len); + if (res == GET_BUFFER_ERROR) { + self->source_done = true; + } else { + if (len > 0 && buf != NULL) { + // Defend against a source that hands back more than it advertised. + if (len > self->source_max_buffer) { + len = self->source_max_buffer; + } + audiofilewriter_ring_write(self, buf, len); + self->budget_frames -= (int64_t)(len / self->bytes_per_frame); + } + if (res == GET_BUFFER_DONE) { + self->source_done = true; + } + } + } + + if (!audiofilewriter_flush(self)) { + // File write failed; give up gracefully rather than spin. + self->source_done = true; + } + + if (self->source_done && self->ring_count == 0) { + audiofilewriter_finalize(self); + } +} + +void audiofilewriter_background(void) { + audiofilewriter_audiofilewriter_obj_t *self = REGISTRY_HEAD; + while (self != NULL) { + // Capture next before pumping: pump() may finalize self, which unlinks + // it from the registry (but leaves our saved next pointer valid). + audiofilewriter_audiofilewriter_obj_t *next = self->reg_next; + audiofilewriter_pump(self); + self = next; + } +} + +// Called during soft reset (VM teardown). Any writer still active is abandoned: +// we don't try to touch its file (it may already be gone), we just balance the +// tick-enable count and drop it from the list. +void audiofilewriter_reset(void) { + audiofilewriter_audiofilewriter_obj_t *self = REGISTRY_HEAD; + while (self != NULL) { + audiofilewriter_audiofilewriter_obj_t *next = self->reg_next; + if (self->playing) { + self->playing = false; + supervisor_disable_tick(); + } + self->reg_next = NULL; + self = next; + } + MP_STATE_VM(audiofilewriter_linked_list) = NULL; +} + +// --------------------------------------------------------------------------- +// common-hal surface +// --------------------------------------------------------------------------- + +void common_hal_audiofilewriter_audiofilewriter_construct(audiofilewriter_audiofilewriter_obj_t *self, + mp_obj_t file, uint32_t buffer_size) { + // The file must be a writable, seekable binary stream (a file or BytesIO). + mp_get_stream_raise(file, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + + self->file = file; + self->sample = MP_OBJ_NULL; + self->ring_size = buffer_size; + self->ring = m_malloc(buffer_size); + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + self->playing = false; + self->source_done = false; + self->reg_next = NULL; +} + +bool common_hal_audiofilewriter_audiofilewriter_deinited(audiofilewriter_audiofilewriter_obj_t *self) { + return self->ring == NULL; +} + +void common_hal_audiofilewriter_audiofilewriter_deinit(audiofilewriter_audiofilewriter_obj_t *self) { + if (self->playing) { + common_hal_audiofilewriter_audiofilewriter_stop(self); + } + self->ring = NULL; + self->file = MP_OBJ_NULL; + self->sample = MP_OBJ_NULL; +} + +void common_hal_audiofilewriter_audiofilewriter_play(audiofilewriter_audiofilewriter_obj_t *self, mp_obj_t sample_obj) { + if (self->playing) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Already in progress")); + } + + audiosample_base_t *sample = audiosample_check(sample_obj); + uint32_t rate = audiosample_get_sample_rate(sample); + uint8_t channels = audiosample_get_channel_count(sample); + uint8_t bits = audiosample_get_bits_per_sample(sample); + bool single_buffer, samples_signed; + uint32_t max_buffer_length; + uint8_t spacing; + audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, + &max_buffer_length, &spacing); + + if ((bits != 8 && bits != 16) || channels < 1 || channels > 2) { + mp_raise_ValueError(MP_ERROR_TEXT("Only 8/16-bit mono/stereo is supported")); + } + if (max_buffer_length == 0 || self->ring_size < max_buffer_length) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer_size too small for source")); + } + + self->sample_rate = rate; + self->channel_count = channels; + self->bits_per_sample = bits; + self->samples_signed = samples_signed; + self->bytes_per_frame = (uint8_t)(channels * (bits / 8)); + self->source_max_buffer = max_buffer_length; + + // Remember where the header starts so stop() can patch its size fields, + // then write a placeholder header with zeroed sizes. + int err = 0; + mp_off_t off = mp_stream_seek(self->file, 0, MP_SEEK_CUR, &err); + if (off == (mp_off_t)-1) { + mp_raise_OSError(err ? err : MP_EIO); + } + self->header_offset = (uint32_t)off; + + uint32_t block_align = self->bytes_per_frame; + uint32_t byte_rate = rate * block_align; + uint8_t hdr[44]; + memcpy(hdr + 0, "RIFF", 4); + put_u32le(hdr + 4, 36); // RIFF size (patched at stop) + memcpy(hdr + 8, "WAVE", 4); + memcpy(hdr + 12, "fmt ", 4); + put_u32le(hdr + 16, 16); // fmt chunk size + put_u16le(hdr + 20, 1); // PCM + put_u16le(hdr + 22, channels); + put_u32le(hdr + 24, rate); + put_u32le(hdr + 28, byte_rate); + put_u16le(hdr + 32, (uint16_t)block_align); + put_u16le(hdr + 34, bits); + memcpy(hdr + 36, "data", 4); + put_u32le(hdr + 40, 0); // data size (patched at stop) + + err = 0; + mp_uint_t wrote = mp_stream_write_exactly(self->file, hdr, sizeof(hdr), &err); + if (err != 0 || wrote != sizeof(hdr)) { + mp_raise_OSError(err ? err : MP_EIO); + } + + audiosample_reset_buffer(sample_obj, false, 0); + + self->sample = sample_obj; + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + self->budget_frames = 0; + self->data_bytes = 0; + self->source_done = false; + self->last_tick_ms = supervisor_ticks_ms64(); + self->playing = true; + + audiofilewriter_register(self); + supervisor_enable_tick(); +} + +void common_hal_audiofilewriter_audiofilewriter_stop(audiofilewriter_audiofilewriter_obj_t *self) { + if (!self->playing) { + return; + } + // Keep the background pump out while we finalize from Python context. + background_callback_prevent(); + audiofilewriter_finalize(self); + background_callback_allow(); +} + +bool common_hal_audiofilewriter_audiofilewriter_get_playing(audiofilewriter_audiofilewriter_obj_t *self) { + return self->playing; +} + +MP_REGISTER_ROOT_POINTER(mp_obj_t audiofilewriter_linked_list); diff --git a/shared-module/audiofilewriter/AudioFileWriter.h b/shared-module/audiofilewriter/AudioFileWriter.h new file mode 100644 index 00000000000..0e99e90e915 --- /dev/null +++ b/shared-module/audiofilewriter/AudioFileWriter.h @@ -0,0 +1,67 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" + +// A streaming WAV *sink*: it consumes an audiosample source (a mic, synthio, +// or an effect chain) and writes the resulting PCM to a file. Unlike WaveFile +// it is NOT an audiosample, it is the thing that drives a source, playing the +// role an AudioOut would. +typedef struct _audiofilewriter_audiofilewriter_obj_t { + mp_obj_base_t base; + + // Output stream (anything with write + MP_STREAM_SEEK ioctl: a file or a + // BytesIO). Held so it stays referenced while recording. + mp_obj_t file; + // The source being recorded. Only valid (and referenced) while playing. + mp_obj_t sample; + + // Format, captured from the source at play() time. AudioFileWriter is the + // format authority for the WAV header. + uint32_t sample_rate; + uint8_t channel_count; + uint8_t bits_per_sample; + bool samples_signed; + uint8_t bytes_per_frame; // channel_count * bits_per_sample / 8 + uint32_t source_max_buffer; // largest buffer the source can hand back, bytes + + // RAM ring that decouples SD-write latency from the source. Written by the + // pump, drained to the file by the pump. Only touched from background-task + // context (never an ISR), so no locking is needed. + uint8_t *ring; + uint32_t ring_size; // capacity in bytes + uint32_t ring_head; // write cursor + uint32_t ring_tail; // read cursor + uint32_t ring_count; // bytes currently buffered + + // Real-time pacing: budget accrues sample_rate frames per second of elapsed + // supervisor ticks; a buffer is pulled only when budget is positive. + int64_t budget_frames; + uint64_t last_tick_ms; + + // Absolute file offset of the RIFF header start, so stop() can seek back and + // patch the two size fields once the final length is known. + uint32_t header_offset; + uint32_t data_bytes; // total PCM bytes handed to the file + + bool playing; + bool source_done; // source returned DONE/ERROR; drain then finalize + + // Intrusive linked list of active writers, walked once per supervisor tick. + struct _audiofilewriter_audiofilewriter_obj_t *reg_next; +} audiofilewriter_audiofilewriter_obj_t; + +// Called once per supervisor tick (from supervisor_background_tick), in +// background-task context. Pumps every active writer. +void audiofilewriter_background(void); + +// Called during soft reset to abandon any writer left recording. +void audiofilewriter_reset(void); diff --git a/shared-module/audiofilewriter/__init__.c b/shared-module/audiofilewriter/__init__.c new file mode 100644 index 00000000000..584c821b996 --- /dev/null +++ b/shared-module/audiofilewriter/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT diff --git a/shared-module/audiofilters/Distortion.c b/shared-module/audiofilters/Distortion.c index c4b6b7566ad..1498c402ea0 100644 --- a/shared-module/audiofilters/Distortion.c +++ b/shared-module/audiofilters/Distortion.c @@ -192,9 +192,15 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } @@ -204,7 +210,9 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist } else { // For unsigned samples set to the middle which is "quiet" if (MP_LIKELY(self->base.bits_per_sample == 16)) { - memset(word_buffer, 32768, length * (self->base.bits_per_sample / 8)); + for (uint32_t si = 0; si < length; si++) { + word_buffer[si] = (int16_t)0x8000; + } } else { memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); } @@ -319,7 +327,7 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist // Hard clip if (!self->soft_clip) { - word = MIN(MAX(word, -32767), 32768); + word = MIN(MAX(word, -32767), 32767); } if (MP_LIKELY(self->base.bits_per_sample == 16)) { diff --git a/shared-module/audiofilters/Filter.c b/shared-module/audiofilters/Filter.c index 4cedc810aba..37deaa06b58 100644 --- a/shared-module/audiofilters/Filter.c +++ b/shared-module/audiofilters/Filter.c @@ -5,8 +5,8 @@ // SPDX-License-Identifier: MIT #include "shared-bindings/audiofilters/Filter.h" #include "shared-bindings/audiocore/__init__.h" - #include "shared-module/synthio/Biquad.h" + #include #include "py/runtime.h" @@ -40,8 +40,8 @@ void common_hal_audiofilters_filter_construct(audiofilters_filter_obj_t *self, self->last_buf_idx = 1; // Which buffer to use first, toggle between 0 and 1 // This buffer will be used to process samples through the biquad filter - self->filter_buffer = m_malloc_without_collect(SYNTHIO_MAX_DUR * sizeof(int32_t)); - memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * sizeof(int32_t)); + self->filter_buffer = m_malloc_without_collect(SYNTHIO_MAX_DUR * self->base.channel_count * sizeof(int32_t)); + memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * self->base.channel_count * sizeof(int32_t)); // Initialize other values most effects will need. self->sample = NULL; // The current playing sample @@ -59,60 +59,17 @@ void common_hal_audiofilters_filter_construct(audiofilters_filter_obj_t *self, void common_hal_audiofilters_filter_deinit(audiofilters_filter_obj_t *self) { audiosample_mark_deinit(&self->base); + audiofilters_deinit_filter_chain(&self->filter); self->buffer[0] = NULL; self->buffer[1] = NULL; - self->filter = mp_const_none; - self->filter_buffer = NULL; - self->filter_states = NULL; } void common_hal_audiofilters_filter_set_filter(audiofilters_filter_obj_t *self, mp_obj_t filter_in) { - size_t n_items; - mp_obj_t *items; - mp_obj_t *filter_objs; - - if (filter_in == mp_const_none) { - n_items = 0; - filter_objs = NULL; - } else if (MP_OBJ_TYPE_HAS_SLOT(mp_obj_get_type(filter_in), iter)) { - // convert object to tuple if it wasn't before - filter_in = MP_OBJ_TYPE_GET_SLOT(&mp_type_tuple, make_new)( - &mp_type_tuple, 1, 0, &filter_in); - mp_obj_tuple_get(filter_in, &n_items, &items); - for (size_t i = 0; i < n_items; i++) { - if (!mp_obj_is_type(items[i], &synthio_biquad_type_obj)) { - mp_raise_TypeError_varg( - MP_ERROR_TEXT("%q in %q must be of type %q, not %q"), - MP_QSTR_object, - MP_QSTR_filter, - MP_QSTR_Biquad, - mp_obj_get_type(items[i])->name); - } - } - filter_objs = items; - } else { - n_items = 1; - if (!mp_obj_is_type(filter_in, &synthio_biquad_type_obj)) { - mp_raise_TypeError_varg( - MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), - MP_QSTR_filter, MP_QSTR_Biquad, MP_QSTR_iterable, mp_obj_get_type(filter_in)->name); - } - filter_objs = &self->filter; - } - - // everything has been checked, so we can do the following without fear - - self->filter = filter_in; - self->filter_objs = filter_objs; - self->filter_states = m_renew(biquad_filter_state, - self->filter_states, - self->filter_states_len, - n_items); - self->filter_states_len = n_items; + audiofilters_assign_filter_chain(&self->filter, filter_in, self->base.channel_count); } mp_obj_t common_hal_audiofilters_filter_get_filter(audiofilters_filter_obj_t *self) { - return self->filter; + return self->filter.obj; } mp_obj_t common_hal_audiofilters_filter_get_mix(audiofilters_filter_obj_t *self) { @@ -129,13 +86,9 @@ void audiofilters_filter_reset_buffer(audiofilters_filter_obj_t *self, memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); - memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * sizeof(int32_t)); + memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * self->base.channel_count * sizeof(int32_t)); - if (self->filter_states) { - for (uint8_t i = 0; i < self->filter_states_len; i++) { - synthio_biquad_filter_reset(&self->filter_states[i]); - } - } + audiofilters_reset_filter_chain(&self->filter, self->base.channel_count); } bool common_hal_audiofilters_filter_get_playing(audiofilters_filter_obj_t *self) { @@ -195,9 +148,15 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } @@ -207,9 +166,8 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o (void)synthio_block_slot_get(&self->mix); // Tick biquad filters - for (uint8_t j = 0; j < self->filter_states_len; j++) { - common_hal_synthio_biquad_tick(self->filter_objs[j]); - } + audiofilters_tick_filter_chain(&self->filter); + if (self->base.samples_signed) { memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); } else { @@ -237,7 +195,7 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); - if (mix <= MICROPY_FLOAT_CONST(0.01) || !self->filter_states) { // if mix is zero pure sample only or no biquad filter objects are provided + if (mix <= MICROPY_FLOAT_CONST(0.01) || !self->filter.states) { // if mix is zero pure sample only or no biquad filter objects are provided for (uint32_t i = 0; i < n; i++) { if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = sample_src[i]; @@ -248,46 +206,52 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o } else { uint32_t i = 0; while (i < n) { - uint32_t n_samples = MIN(SYNTHIO_MAX_DUR, n - i); + uint32_t n_samples = MIN(SYNTHIO_MAX_DUR, (n - i) >> (self->base.channel_count - 1)); // Fill filter buffer with samples - for (uint32_t j = 0; j < n_samples; j++) { + for (uint32_t j = 0; j < n_samples * self->base.channel_count; j++) { + bool buf_offset = (j % self->base.channel_count) == 1; + uint32_t k = j / self->base.channel_count; if (MP_LIKELY(self->base.bits_per_sample == 16)) { - self->filter_buffer[j] = sample_src[i + j]; + self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] = sample_src[i + j]; } else { if (self->base.samples_signed) { - self->filter_buffer[j] = sample_hsrc[i + j]; + self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] = sample_hsrc[i + j]; } else { // Be careful here changing from an 8 bit unsigned to signed into a 32-bit signed - self->filter_buffer[j] = (int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80); + self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] = (int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80); } } } // Process biquad filters - for (uint8_t j = 0; j < self->filter_states_len; j++) { - mp_obj_t filter_obj = self->filter_objs[j]; + for (size_t j = 0; j < self->filter.objs_len; j++) { + mp_obj_t filter_obj = self->filter.objs[j]; common_hal_synthio_biquad_tick(filter_obj); - synthio_biquad_filter_samples(filter_obj, &self->filter_states[j], self->filter_buffer, n_samples); + for (uint8_t k = 0; k < self->base.channel_count; k++) { + synthio_biquad_filter_samples(filter_obj, &self->filter.states[j * self->base.channel_count + k], self->filter_buffer + k * SYNTHIO_MAX_DUR, n_samples); + } } // Mix processed signal with original sample and transfer to output buffer - for (uint32_t j = 0; j < n_samples; j++) { + for (uint32_t j = 0; j < n_samples * self->base.channel_count; j++) { + bool buf_offset = (j % self->base.channel_count) == 1; + uint32_t k = j / self->base.channel_count; if (MP_LIKELY(self->base.bits_per_sample == 16)) { - word_buffer[i + j] = synthio_mix_down_sample((int32_t)((sample_src[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[j] * mix)), SYNTHIO_MIX_DOWN_SCALE(2)); + word_buffer[i + j] = synthio_mix_down_sample((int32_t)((sample_src[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * mix)), SYNTHIO_MIX_DOWN_SCALE(2)); if (!self->base.samples_signed) { word_buffer[i + j] ^= 0x8000; } } else { if (self->base.samples_signed) { - hword_buffer[i + j] = (int8_t)((sample_hsrc[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[j] * mix)); + hword_buffer[i + j] = (int8_t)((sample_hsrc[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * mix)); } else { - hword_buffer[i + j] = (uint8_t)(((int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80) * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[j] * mix)) ^ 0x80; + hword_buffer[i + j] = (uint8_t)(((int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80) * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * mix)) ^ 0x80; } } } - i += n_samples; + i += n_samples * self->base.channel_count; } } diff --git a/shared-module/audiofilters/Filter.h b/shared-module/audiofilters/Filter.h index 4447f8a2988..6cb352d4273 100644 --- a/shared-module/audiofilters/Filter.h +++ b/shared-module/audiofilters/Filter.h @@ -9,6 +9,7 @@ #include "shared-bindings/synthio/Biquad.h" #include "shared-module/audiocore/__init__.h" +#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/__init__.h" #include "shared-module/synthio/block.h" #include "shared-module/synthio/Biquad.h" @@ -17,13 +18,9 @@ extern const mp_obj_type_t audiofilters_filter_type; typedef struct { audiosample_base_t base; - mp_obj_t filter; + audiofilters_filter_chain_t filter; synthio_block_slot_t mix; - mp_obj_t *filter_objs; - size_t filter_states_len; - biquad_filter_state *filter_states; - int8_t *buffer[2]; uint8_t last_buf_idx; uint32_t buffer_len; // max buffer in bytes diff --git a/shared-module/audiofilters/Phaser.c b/shared-module/audiofilters/Phaser.c index 01b938c3a00..368824b4b43 100644 --- a/shared-module/audiofilters/Phaser.c +++ b/shared-module/audiofilters/Phaser.c @@ -182,9 +182,15 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiofilters/__init__.c b/shared-module/audiofilters/__init__.c index 83929b4c4fb..7f23afcc59c 100644 --- a/shared-module/audiofilters/__init__.c +++ b/shared-module/audiofilters/__init__.c @@ -3,3 +3,74 @@ // SPDX-FileCopyrightText: Copyright (c) 2024 Cooper Dalrymple // // SPDX-License-Identifier: MIT + +#include "shared-module/audiofilters/__init__.h" + +void audiofilters_assign_filter_chain(audiofilters_filter_chain_t *self, mp_obj_t filter_in, uint8_t channel_count) { + size_t n_items; + mp_obj_t *items; + + if (filter_in == mp_const_none) { + n_items = 0; + items = NULL; + } else if (mp_obj_is_type(filter_in, &mp_type_tuple)) { + mp_obj_tuple_get(filter_in, &n_items, &items); + for (size_t i = 0; i < n_items; i++) { + if (!mp_obj_is_type(items[i], &synthio_biquad_type_obj)) { + mp_raise_TypeError_varg( + MP_ERROR_TEXT("%q in %q must be of type %q, not %q"), + MP_QSTR_object, + MP_QSTR_filter, + MP_QSTR_Biquad, + mp_obj_get_type(items[i])->name); + } + } + } else { + n_items = 1; + if (!mp_obj_is_type(filter_in, &synthio_biquad_type_obj)) { + mp_raise_TypeError_varg( + MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), + MP_QSTR_filter, MP_QSTR_Biquad, MP_QSTR_tuple, mp_obj_get_type(filter_in)->name); + } + items = &self->obj; + } + + // everything has been checked, so we can do the following without fear + + self->obj = filter_in; + self->states = m_renew(biquad_filter_state, + self->states, + self->objs_len * channel_count, + n_items * channel_count); + self->objs = items; + self->objs_len = n_items; +} + +void audiofilters_reset_filter_chain(audiofilters_filter_chain_t *self, uint8_t channel_count) { + if (self->states) { + for (size_t i = 0; i < self->objs_len * channel_count; i++) { + synthio_biquad_filter_reset(&self->states[i]); + } + } +} + +void audiofilters_tick_filter_chain(audiofilters_filter_chain_t *self) { + for (size_t j = 0; j < self->objs_len; j++) { + common_hal_synthio_biquad_tick(self->objs[j]); + } +} + +int32_t audiofilters_process_filter_chain(audiofilters_filter_chain_t *self, uint8_t channel_count, uint8_t channel, int32_t word) { + // Process biquad filters + for (size_t j = 0; j < self->objs_len; j++) { + word = synthio_biquad_filter_sample(self->objs[j], &self->states[j * channel_count + channel], word); + } + return word; +} + +void audiofilters_deinit_filter_chain(audiofilters_filter_chain_t *self) { + self->obj = mp_const_none; + self->objs = NULL; + self->objs_len = 0; + self->states = NULL; +} diff --git a/shared-module/audiofilters/__init__.h b/shared-module/audiofilters/__init__.h index 29d2f672655..2a5a933d96f 100644 --- a/shared-module/audiofilters/__init__.h +++ b/shared-module/audiofilters/__init__.h @@ -5,3 +5,19 @@ // SPDX-License-Identifier: MIT #pragma once + +#include "py/obj.h" +#include "shared-module/synthio/Biquad.h" + +typedef struct audiofilters_filter_chain { + mp_obj_t obj; + mp_obj_t *objs; + size_t objs_len; + biquad_filter_state *states; +} audiofilters_filter_chain_t; + +void audiofilters_assign_filter_chain(audiofilters_filter_chain_t *filter_chain, mp_obj_t filter_in, uint8_t channel_count); +void audiofilters_reset_filter_chain(audiofilters_filter_chain_t *filter_chain, uint8_t channel_count); +void audiofilters_tick_filter_chain(audiofilters_filter_chain_t *filter_chain); +int32_t audiofilters_process_filter_chain(audiofilters_filter_chain_t *filter_chain, uint8_t channel_count, uint8_t channel, int32_t word); +void audiofilters_deinit_filter_chain(audiofilters_filter_chain_t *self); diff --git a/shared-module/audiofreeverb/Freeverb.c b/shared-module/audiofreeverb/Freeverb.c index 28779bdcc84..08498a82c86 100644 --- a/shared-module/audiofreeverb/Freeverb.c +++ b/shared-module/audiofreeverb/Freeverb.c @@ -8,13 +8,14 @@ // Fixed point ideas from - Paul Stoffregen in the Teensy audio library https://github.com/PaulStoffregen/Audio/blob/master/effect_freeverb.cpp // #include "shared-bindings/audiofreeverb/Freeverb.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-module/synthio/__init__.h" #include #include "py/runtime.h" #include -void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *self, mp_obj_t roomsize, mp_obj_t damp, mp_obj_t mix, +void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *self, mp_obj_t roomsize, mp_obj_t damp, mp_obj_t pre_filter, mp_obj_t post_filter, mp_obj_t mix, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate) { @@ -58,6 +59,9 @@ void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *s self->more_data = false; // Is there still more data to read from the sample or did we finish // The below section sets up the reverb effect's starting values. For a different effect this section will change + common_hal_audiofreeverb_freeverb_set_pre_filter(self, pre_filter); + common_hal_audiofreeverb_freeverb_set_post_filter(self, post_filter); + if (roomsize == MP_OBJ_NULL) { roomsize = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); } @@ -92,7 +96,7 @@ void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *s common_hal_audiofreeverb_freeverb_deinit(self); m_malloc_fail(self->combbuffersizes[i]); } - memset(self->combbuffers[i], 0, self->combbuffersizes[i]); + memset(self->combbuffers[i], 0, self->combbuffersizes[i] * sizeof(uint16_t)); self->combbufferindex[i] = 0; self->combfitlers[i] = 0; @@ -110,7 +114,7 @@ void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *s common_hal_audiofreeverb_freeverb_deinit(self); m_malloc_fail(self->allpassbuffersizes[i]); } - memset(self->allpassbuffers[i], 0, self->allpassbuffersizes[i]); + memset(self->allpassbuffers[i], 0, self->allpassbuffersizes[i] * sizeof(uint16_t)); self->allpassbufferindex[i] = 0; } @@ -124,9 +128,9 @@ bool common_hal_audiofreeverb_freeverb_deinited(audiofreeverb_freeverb_obj_t *se } void common_hal_audiofreeverb_freeverb_deinit(audiofreeverb_freeverb_obj_t *self) { - if (common_hal_audiofreeverb_freeverb_deinited(self)) { - return; - } + audiosample_mark_deinit(&self->base); + audiofilters_deinit_filter_chain(&self->pre_filter); + audiofilters_deinit_filter_chain(&self->post_filter); self->buffer[0] = NULL; self->buffer[1] = NULL; } @@ -168,6 +172,22 @@ void audiofreeverb_freeverb_get_damp_fixedpoint(mp_float_t n, int16_t *damp1, in *damp2 = (int16_t)(32768 - *damp1); // inverse of x1 damp2 = 1.0 - damp1 } +mp_obj_t common_hal_audiofreeverb_freeverb_get_pre_filter(audiofreeverb_freeverb_obj_t *self) { + return self->pre_filter.obj; +} + +void common_hal_audiofreeverb_freeverb_set_pre_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t filter_in) { + audiofilters_assign_filter_chain(&self->pre_filter, filter_in, self->base.channel_count); +} + +mp_obj_t common_hal_audiofreeverb_freeverb_get_post_filter(audiofreeverb_freeverb_obj_t *self) { + return self->post_filter.obj; +} + +void common_hal_audiofreeverb_freeverb_set_post_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t filter_in) { + audiofilters_assign_filter_chain(&self->post_filter, filter_in, self->base.channel_count); +} + mp_obj_t common_hal_audiofreeverb_freeverb_get_mix(audiofreeverb_freeverb_obj_t *self) { return self->mix.obj; } @@ -188,6 +208,9 @@ void audiofreeverb_freeverb_reset_buffer(audiofreeverb_freeverb_obj_t *self, memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); + + audiofilters_reset_filter_chain(&self->pre_filter, self->base.channel_count); + audiofilters_reset_filter_chain(&self->post_filter, self->base.channel_count); } bool common_hal_audiofreeverb_freeverb_get_playing(audiofreeverb_freeverb_obj_t *self) { @@ -242,9 +265,15 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } @@ -269,8 +298,14 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free mp_float_t roomsize = synthio_block_slot_get_limited(&self->roomsize, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); int16_t feedback = audiofreeverb_freeverb_get_roomsize_fixedpoint(roomsize); + // Tick biquad filters + audiofilters_tick_filter_chain(&self->pre_filter); + audiofilters_tick_filter_chain(&self->post_filter); + int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; + uint32_t channel_comb_offset = 0, channel_allpass_offset = 0; + for (uint32_t i = 0; i < n; i++) { int32_t sample_word = 0; if (self->sample != NULL) { @@ -279,9 +314,11 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free int32_t word, sum; int16_t input, bufout, output; - uint32_t channel_comb_offset = 0, channel_allpass_offset = 0; - input = synthio_sat16(sample_word * 8738, 17); // Initial input scaled down so we can add reverb + // Apply filters as Pre-EQ + input = (int16_t)audiofilters_process_filter_chain(&self->pre_filter, self->base.channel_count, n % self->base.channel_count, sample_word); + + input = synthio_sat16((int32_t)input * 8738, 17); // Initial input scaled down so we can add reverb sum = 0; // Calculate each of the 8 comb buffers @@ -307,6 +344,9 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free } } + // Apply filters as Post-EQ + output = (int16_t)audiofilters_process_filter_chain(&self->post_filter, self->base.channel_count, n % self->base.channel_count, (int32_t)output); + word = output * 30; // Add some volume back don't have to saturate as next step will word = synthio_sat16(sample_word * mix_sample, 15) + synthio_sat16(word * mix_effect, 15); diff --git a/shared-module/audiofreeverb/Freeverb.h b/shared-module/audiofreeverb/Freeverb.h index 44747f0fc95..1a60a64d39e 100644 --- a/shared-module/audiofreeverb/Freeverb.h +++ b/shared-module/audiofreeverb/Freeverb.h @@ -8,8 +8,10 @@ #include "py/obj.h" #include "shared-module/audiocore/__init__.h" +#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/__init__.h" #include "shared-module/synthio/block.h" +#include "shared-module/synthio/Biquad.h" extern const mp_obj_type_t audiofreeverb_freeverb_type; @@ -17,6 +19,8 @@ typedef struct { audiosample_base_t base; synthio_block_slot_t roomsize; synthio_block_slot_t damp; + audiofilters_filter_chain_t pre_filter; + audiofilters_filter_chain_t post_filter; synthio_block_slot_t mix; int8_t *buffer[2]; diff --git a/shared-module/audioi2sin/__init__.h b/shared-module/audioi2sin/__init__.h new file mode 100644 index 00000000000..852616ee3a7 --- /dev/null +++ b/shared-module/audioi2sin/__init__.h @@ -0,0 +1,71 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +// Rescale an already-normalized signed sample and write it to `buffer` at sample +// index `idx`. `s` is the sign-extended int32 value of the sample at `in_depth` +// scale (the per-port `i2sin_normalize_signed` produces it from the raw FIFO +// word, handling wire-format details like left-justification). This helper does +// the depth conversion + unsigned-WAV flip + container store, which is identical +// across ports. +// +// This path runs only when the caller set `output_bit_depth`, i.e. asked for a +// real bit-depth rescale: upscaling bit-replicates so full-scale input maps to +// full-scale output (e.g. 16-bit 0xFFFF -> 24-bit 0xFFFFFF) and downscaling +// arithmetic-shifts right. This is distinct from the implicit container width +// set by the array typecode (e.g. a 24-bit sample carried in a 32-bit 'i' slot), +// which only sign-extends and is handled by the default (non-converting) path. +// Output element size follows `out_depth`: 1 byte at 8, 2 bytes at 16, 4 bytes +// at 24 or 32. +static inline void shared_audioi2sin_write_converted(void *buffer, uint32_t idx, + int32_t s, uint8_t in_depth, uint8_t out_depth, bool samples_signed) { + int32_t shifted; + if (out_depth > in_depth) { + // Explicit upscale: left-justify the in_depth-bit sample at the top of a + // 32-bit word and replicate the pattern downward so full-scale input + // maps to full-scale output (e.g. 16-bit 0xFFFF -> 24-bit 0xFFFFFF). Two + // steps cover every supported ratio (widest is 8 -> 32); the guard skips + // the second step (and the resulting shift-by->=32 UB) when one suffices. + uint32_t top = (uint32_t)s << (32 - in_depth); + top |= top >> in_depth; + if (in_depth * 2 < out_depth) { + top |= top >> (in_depth * 2); + } + // Arithmetic-shift the high out_depth bits down, sign-extending to int32 + // so a 24-bit value in a 32-bit slot decodes correctly (no-op at 32). + shifted = (int32_t)top >> (32 - out_depth); + } else if (out_depth == in_depth) { + shifted = s; + } else { + shifted = s >> (in_depth - out_depth); + } + uint32_t u = (uint32_t)shifted; + if (!samples_signed) { + // I2S delivers signed PCM; flip the sign bit to match the WAV unsigned + // convention, at the output bit width. + if (out_depth >= 32) { + u ^= 0x80000000u; + } else { + uint32_t mask = (1u << out_depth) - 1u; + u = (u & mask) ^ (1u << (out_depth - 1)); + } + } + switch (out_depth) { + case 8: + ((uint8_t *)buffer)[idx] = (uint8_t)(u & 0xffu); + break; + case 16: + ((uint16_t *)buffer)[idx] = (uint16_t)(u & 0xffffu); + break; + default: // 24 or 32 + ((uint32_t *)buffer)[idx] = u; + break; + } +} diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index b27eafb71a9..464117fae8d 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -66,7 +66,7 @@ void audiomixer_mixer_reset_buffer(audiomixer_mixer_obj_t *self, bool single_channel_output, uint8_t channel) { for (uint8_t i = 0; i < self->voice_count; i++) { - common_hal_audiomixer_mixervoice_stop(self->voice[i]); + common_hal_audiomixer_mixervoice_reset_buffer(self->voice[i]); } } @@ -92,23 +92,23 @@ static inline uint32_t add16signed(uint32_t a, uint32_t b) { } __attribute__((always_inline)) -static inline uint32_t mult16signed(uint32_t val, int32_t mul[2]) { +static inline uint32_t mult16signed(uint32_t val, int32_t lomul, int32_t himul) { #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) - mul[0] <<= 16; - mul[1] <<= 16; + lomul <<= 16; + himul <<= 16; int32_t hi, lo; enum { bits = 16 }; // saturate to 16 bits enum { shift = 15 }; // shift is done automatically - asm volatile ("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul[0]), "r" (val)); - asm volatile ("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul[1]), "r" (val)); - asm volatile ("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); - asm volatile ("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); - asm volatile ("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack + __asm__ volatile ("smulwb %0, %1, %2" : "=r" (lo) : "r" (lomul), "r" (val)); + __asm__ volatile ("smulwt %0, %1, %2" : "=r" (hi) : "r" (himul), "r" (val)); + __asm__ volatile ("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); + __asm__ volatile ("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); + __asm__ volatile ("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack return val; #else uint32_t result = 0; for (int8_t i = 0; i < 2; i++) { - float mod_mul = (float)mul[i] / (float)((1 << 15) - 1); + float mod_mul = (float)(i ? himul : lomul) / (float)((1 << 15) - 1); int16_t ai = (val >> (sizeof(uint16_t) * 8 * i)); int32_t intermediate = (int32_t)(ai * mod_mul); if (intermediate > SHRT_MAX) { @@ -156,23 +156,48 @@ static inline uint32_t pack8(uint32_t val) { } static inline uint32_t copy16lsb(uint32_t val) { + #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) + return __PKHBT(val, val, 16); + #else val &= 0x0000ffff; return val | (val << 16); + #endif } static inline uint32_t copy16msb(uint32_t val) { + #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) + return __PKHTB(val, val, 16); + #else val &= 0xffff0000; return val | (val >> 16); + #endif } -static inline uint32_t copy8lsb(uint32_t val) { - val &= 0x00ff; - return val | (val << 8); -} +// Rather than immediately changing the loudness of audio playback, we keep a separate buffer of +// the "active" loudness and wait until we meet the conditions of a "zero crossing". A zero crossing +// occurs when either the current value is 0 or the value changes from negative to positive or +// vice-versa. This is detected by keeping a copy of the previous frame of audio data and checking +// to see if the sign of the value has changed. By only changing loudness during zero crossings, we +// avoid audible pops/clicks which can be unpleasant. +static void assignmul(uint32_t word, uint32_t *last_word, int32_t *active_lomul, int32_t *active_himul, int32_t pending_lomul, int32_t pending_himul) { + // If the active loudness already matches the pending loudness, exit early. + if (MP_LIKELY(*active_lomul == pending_lomul) && MP_LIKELY(*active_himul == pending_himul)) { + return; + } -static inline uint32_t copy8msb(uint32_t val) { - val &= 0xff00; - return val | (val >> 8); + // Check for a zero crossing: current value is 0 or has changed sign from the previous value. + // We check for the sign change by bitmasking only the top bits of each 16-bit signed value + // packed into the 32-bit word (two's complement). If either bit doesn't match the previous + // value, a sign change has occurred on either the left or right channel. + if ((word & 0xffff0000) == 0 || (word & 0x0000ffff) == 0 || (*last_word != 0 && ((*last_word) & 0x80008000) != (word & 0x80008000))) { + // Copy over our pending loudness. Will cause future calls to `assignmul` to exit early. + *active_lomul = pending_lomul; + *active_himul = pending_himul; + } else { + // Update our copy of the previous word for future comparisons (an initial value of 0 is + // ignored). + *last_word = word; + } } #define ALMOST_ONE (MICROPY_FLOAT_CONST(32767.) / 32768) @@ -194,6 +219,12 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (voice->sample) { // Load another buffer audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t **)&voice->remaining_buffer, &voice->buffer_length); + if (result == GET_BUFFER_ERROR) { + voice->sample = NULL; + voice->buffer_length = 0; + voice->more_data = false; + break; + } // Track length in terms of words. voice->buffer_length /= sizeof(uint32_t); voice->more_data = result == GET_BUFFER_MORE_DATA; @@ -228,47 +259,62 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, uint16_t left_panning_scaled = 32768, right_panning_scaled = 32768; if (MP_LIKELY(self->base.channel_count == 2)) { if (panning >= 0) { - right_panning_scaled = 32767 - panning; + left_panning_scaled = 32767 - panning; } else { - left_panning_scaled = 32767 + panning; + right_panning_scaled = 32767 + panning; } } - int32_t loudness[2] = { level, level }; + int32_t pending_lo_level = level; + int32_t pending_hi_level = level; if (MP_LIKELY(self->base.channel_count == 2)) { - loudness[0] = (left_panning_scaled * loudness[0]) >> 15; - loudness[1] = (right_panning_scaled * loudness[1]) >> 15; + pending_lo_level = (left_panning_scaled * pending_lo_level) >> 15; + pending_hi_level = (right_panning_scaled * pending_hi_level) >> 15; } + int32_t active_lo_level = voice->active_lo_level; + int32_t active_hi_level = voice->active_hi_level; + uint32_t last_word = 0; + // First active voice gets copied over verbatim. if (!voices_active) { if (MP_LIKELY(self->base.bits_per_sample == 16)) { if (MP_LIKELY(self->base.samples_signed)) { if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { - uint32_t v = src[i]; - word_buffer[i] = mult16signed(v, loudness); + uint32_t word = src[i]; + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = mult16signed(word, active_lo_level, active_hi_level); } } else { - for (uint32_t i = 0; i < n; i += 2) { - uint32_t v = src[i >> 1]; - word_buffer[i] = mult16signed(copy16lsb(v), loudness); - word_buffer[i + 1] = mult16signed(copy16msb(v), loudness); + for (uint32_t i = 0; i + 1 < n; i += 2) { + uint32_t word = src[i >> 1]; + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = mult16signed(word_lsb, active_lo_level, active_hi_level); + word = copy16msb(word); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i + 1] = mult16signed(word, active_lo_level, active_hi_level); } } } else { if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { - uint32_t v = src[i]; - v = tosigned16(v); - word_buffer[i] = mult16signed(v, loudness); + uint32_t word = src[i]; + word = tosigned16(word); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = mult16signed(word, active_lo_level, active_hi_level); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { - uint32_t v = src[i >> 1]; - v = tosigned16(v); - word_buffer[i] = mult16signed(copy16lsb(v), loudness); - word_buffer[i + 1] = mult16signed(copy16msb(v), loudness); + uint32_t word = src[i >> 1]; + word = tosigned16(word); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = mult16signed(word_lsb, active_lo_level, active_hi_level); + word = copy16msb(word); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i + 1] = mult16signed(word, active_lo_level, active_hi_level); } } } @@ -281,7 +327,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - word = mult16signed(word, loudness); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word = mult16signed(word, active_lo_level, active_hi_level); hword_buffer[i] = pack8(word); } } else { @@ -290,8 +337,12 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - hword_buffer[i] = pack8(mult16signed(copy16lsb(word), loudness)); - hword_buffer[i + 1] = pack8(mult16signed(copy16msb(word), loudness)); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + hword_buffer[i] = pack8(mult16signed(word_lsb, active_lo_level, active_hi_level)); + word = copy16msb(word); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + hword_buffer[i + 1] = pack8(mult16signed(word, active_lo_level, active_hi_level)); } } } @@ -301,13 +352,18 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; - word_buffer[i] = add16signed(mult16signed(word, loudness), word_buffer[i]); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = add16signed(mult16signed(word, active_lo_level, active_hi_level), word_buffer[i]); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t word = src[i >> 1]; - word_buffer[i] = add16signed(mult16signed(copy16lsb(word), loudness), word_buffer[i]); - word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), loudness), word_buffer[i + 1]); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = add16signed(mult16signed(word_lsb, active_lo_level, active_hi_level), word_buffer[i]); + word = copy16msb(word); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i + 1] = add16signed(mult16signed(word, active_lo_level, active_hi_level), word_buffer[i + 1]); } } } else { @@ -315,14 +371,19 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; word = tosigned16(word); - word_buffer[i] = add16signed(mult16signed(word, loudness), word_buffer[i]); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = add16signed(mult16signed(word, active_lo_level, active_hi_level), word_buffer[i]); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t word = src[i >> 1]; word = tosigned16(word); - word_buffer[i] = add16signed(mult16signed(copy16lsb(word), loudness), word_buffer[i]); - word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), loudness), word_buffer[i + 1]); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = add16signed(mult16signed(word_lsb, active_lo_level, active_hi_level), word_buffer[i]); + word = copy16msb(word); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i + 1] = add16signed(mult16signed(word, active_lo_level, active_hi_level), word_buffer[i + 1]); } } } @@ -335,7 +396,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - word = mult16signed(word, loudness); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word = mult16signed(word, active_lo_level, active_hi_level); word = add16signed(word, unpack8(hword_buffer[i])); hword_buffer[i] = pack8(word); } @@ -345,8 +407,12 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - hword_buffer[i] = pack8(add16signed(mult16signed(copy16lsb(word), loudness), unpack8(hword_buffer[i]))); - hword_buffer[i + 1] = pack8(add16signed(mult16signed(copy16msb(word), loudness), unpack8(hword_buffer[i + 1]))); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + hword_buffer[i] = pack8(add16signed(mult16signed(word_lsb, active_lo_level, active_hi_level), unpack8(hword_buffer[i]))); + word = copy16msb(word); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + hword_buffer[i + 1] = pack8(add16signed(mult16signed(word, active_lo_level, active_hi_level), unpack8(hword_buffer[i + 1]))); } } } @@ -360,6 +426,12 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, voice->remaining_buffer += n >> 1; voice->buffer_length -= n >> 1; } + + // Force the active level to match the pending level in the case that the conditions of a + // zero crossing weren't met within the last `SYNTHIO_MAX_DUR` frames. Will ensure minimal + // delay in level or panning changes at the potential expensive of an audible pop. + voice->active_lo_level = pending_lo_level; + voice->active_hi_level = pending_hi_level; } if (length && !voices_active) { diff --git a/shared-module/audiomixer/MixerVoice.c b/shared-module/audiomixer/MixerVoice.c index 6c23a39215c..af015fc46f1 100644 --- a/shared-module/audiomixer/MixerVoice.c +++ b/shared-module/audiomixer/MixerVoice.c @@ -51,7 +51,7 @@ void common_hal_audiomixer_mixervoice_set_panning(audiomixer_mixervoice_obj_t *s #if CIRCUITPY_SYNTHIO synthio_block_assign_slot(arg, &self->panning, MP_QSTR_panning); #else - self->panning = (uint16_t)(mp_arg_validate_obj_float_range(arg, -1, 1, MP_QSTR_panning) * ((1 << 15) - 1)); + self->panning = (int16_t)(mp_arg_validate_obj_float_range(arg, -1, 1, MP_QSTR_panning) * ((1 << 15) - 1)); #endif } @@ -70,11 +70,17 @@ void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp self->sample = sample; self->loop = loop; - audiosample_reset_buffer(sample, false, 0); - audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t **)&self->remaining_buffer, &self->buffer_length); - // Track length in terms of words. - self->buffer_length /= sizeof(uint32_t); - self->more_data = result == GET_BUFFER_MORE_DATA; + common_hal_audiomixer_mixervoice_reset_buffer(self); +} + +void common_hal_audiomixer_mixervoice_reset_buffer(audiomixer_mixervoice_obj_t *self) { + if (self->sample != NULL) { + audiosample_reset_buffer(self->sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->remaining_buffer, &self->buffer_length); + // Track length in terms of words. + self->buffer_length /= sizeof(uint32_t); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } bool common_hal_audiomixer_mixervoice_get_playing(audiomixer_mixervoice_obj_t *self) { diff --git a/shared-module/audiomixer/MixerVoice.h b/shared-module/audiomixer/MixerVoice.h index 75e7d47faa3..db5cac1ca27 100644 --- a/shared-module/audiomixer/MixerVoice.h +++ b/shared-module/audiomixer/MixerVoice.h @@ -28,4 +28,6 @@ typedef struct { uint16_t level; int16_t panning; #endif + int32_t active_lo_level; + int32_t active_hi_level; } audiomixer_mixervoice_obj_t; diff --git a/shared-module/audiomp3/MP3Decoder.c b/shared-module/audiomp3/MP3Decoder.c index dc22c0be245..04dd8d2d75c 100644 --- a/shared-module/audiomp3/MP3Decoder.c +++ b/shared-module/audiomp3/MP3Decoder.c @@ -120,8 +120,13 @@ static void stream_set_blocking(audiomp3_mp3file_obj_t *self, bool block_ok) { * Sets self->eof if any read of the file returns 0 bytes */ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block_ok) { + // Every return from this function must be preceded by background_callback_allow(); + background_callback_prevent(); + if (self->eof || INPUT_BUFFER_SPACE(self->inbuf) == 0) { - return INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; + bool result = INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; + background_callback_allow(); + return result; } stream_set_blocking(self, block_ok); @@ -135,7 +140,8 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block self->inbuf.read_off = 0; } - for (size_t to_read; !self->eof && (to_read = INPUT_BUFFER_SPACE(self->inbuf)) > 0;) { + for (size_t to_read; !self->eof && INPUT_BUFFER_SPACE(self->inbuf) > 0 && + (to_read = (size_t)INPUT_BUFFER_SPACE(self->inbuf)) > 0;) { uint8_t *write_ptr = self->inbuf.buf + self->inbuf.write_off; ssize_t n_read = stream_read(self->stream, write_ptr, to_read); @@ -145,6 +151,7 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block break; } self->eof = true; + background_callback_allow(); mp_raise_OSError(errcode); } @@ -160,7 +167,10 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block } // Return true iff there are at least some useful bytes in the buffer - return INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; + bool result = INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; + + background_callback_allow(); + return result; } /** Update the inbuf from a background callback. @@ -234,7 +244,8 @@ static void mp3file_skip_id3v2(audiomp3_mp3file_obj_t *self, bool block_ok) { size -= to_consume; // Next, seek in the file after the header - if (stream_lseek(self->stream, SEEK_CUR, size) == 0) { + off_t before = stream_lseek(self->stream, 0, SEEK_CUR); + if (before >= 0 && stream_lseek(self->stream, size, SEEK_CUR) == before + size) { return; } @@ -414,7 +425,7 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self, // We don't reset the buffer index in case we're looping and we have an odd number of buffer // loads background_callback_prevent(); - if (self->eof && stream_lseek(self->stream, SEEK_SET, 0) == 0) { + if (self->eof && stream_lseek(self->stream, 0, SEEK_SET) == 0) { INPUT_BUFFER_CLEAR(self->inbuf); self->eof = 0; self->samples_decoded = 0; @@ -481,8 +492,9 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t * if (self->eof || (err != ERR_MP3_INDATA_UNDERFLOW && err != ERR_MP3_MAINDATA_UNDERFLOW)) { memset(buffer, 0, self->base.max_buffer_length); *buffer_length = 0; + bool underflow = (err == ERR_MP3_INDATA_UNDERFLOW || err == ERR_MP3_MAINDATA_UNDERFLOW); self->eof = true; - return GET_BUFFER_ERROR; + return underflow ? GET_BUFFER_DONE : GET_BUFFER_ERROR; } } @@ -507,14 +519,14 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t * return result; } -float common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t *self) { - float sumsq = 0.f; +mp_float_t common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t *self) { + mp_float_t sumsq = MICROPY_FLOAT_CONST(0.0); // Assumes no DC component to the audio. Is that a safe assumption? int16_t *buffer = (int16_t *)(void *)self->pcm_buffer[self->buffer_index]; for (size_t i = 0; i < self->base.max_buffer_length / sizeof(int16_t); i++) { - sumsq += (float)buffer[i] * buffer[i]; + sumsq += (mp_float_t)buffer[i] * buffer[i]; } - return sqrtf(sumsq) / (self->base.max_buffer_length / sizeof(int16_t)); + return MICROPY_FLOAT_C_FUN(sqrt)(sumsq) / (self->base.max_buffer_length / sizeof(int16_t)); } uint32_t common_hal_audiomp3_mp3file_get_samples_decoded(audiomp3_mp3file_obj_t *self) { diff --git a/shared-module/audiospeed/Resampler.c b/shared-module/audiospeed/Resampler.c new file mode 100644 index 00000000000..cd1ac681246 --- /dev/null +++ b/shared-module/audiospeed/Resampler.c @@ -0,0 +1,44 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiospeed/Resampler.h" + +static void calculate_rate(audiospeed_base_t *self, uint32_t sample_rate) { + if (self->source != NULL && sample_rate) { + self->speed.rate_fp = (uint32_t)((mp_float_t)self->base.sample_rate / sample_rate * (1 << SPEED_SHIFT)); + } else { + audiospeed_set_rate(&self->speed, mp_const_none); + } +} + +void common_hal_audiospeed_resampler_construct(audiospeed_resampler_obj_t *self, mp_obj_t source) { + audiospeed_construct(&self->base, source, mp_const_none); // default rate 1.0 + self->sample_rate = 0; +} + +void common_hal_audiospeed_resampler_deinit(audiospeed_resampler_obj_t *self) { + audiospeed_deinit(&self->base); +} + +mp_obj_t common_hal_audiospeed_resampler_get_rate(audiospeed_resampler_obj_t *self) { + return audiospeed_get_rate(&self->base.speed); +} + +void audiospeed_resampler_set_sample_rate(audiospeed_resampler_obj_t *self, uint32_t sample_rate) { + self->sample_rate = sample_rate; + calculate_rate(&self->base, self->sample_rate); +} + +void audiospeed_resampler_reset_buffer(audiospeed_resampler_obj_t *self, + bool single_channel_output, uint8_t channel) { + audiospeed_reset_buffer(&self->base, single_channel_output, channel); +} + +audioio_get_buffer_result_t audiospeed_resampler_get_buffer(audiospeed_resampler_obj_t *self, + bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + return audiospeed_get_buffer(&self->base, single_channel_output, channel, buffer, buffer_length); +} diff --git a/shared-module/audiospeed/Resampler.h b/shared-module/audiospeed/Resampler.h new file mode 100644 index 00000000000..a105c5c2ab9 --- /dev/null +++ b/shared-module/audiospeed/Resampler.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-module/audiocore/__init__.h" +#include "shared-module/audiospeed/__init__.h" + +typedef struct { + audiospeed_base_t base; + uint32_t sample_rate; +} audiospeed_resampler_obj_t; + +void audiospeed_resampler_reset_buffer(audiospeed_resampler_obj_t *self, + bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t audiospeed_resampler_get_buffer(audiospeed_resampler_obj_t *self, + bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length); diff --git a/shared-module/audiospeed/SpeedChanger.c b/shared-module/audiospeed/SpeedChanger.c new file mode 100644 index 00000000000..1bf21dfab7a --- /dev/null +++ b/shared-module/audiospeed/SpeedChanger.c @@ -0,0 +1,42 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiospeed/SpeedChanger.h" + +#include +#include "py/runtime.h" +#include "py/gc.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-bindings/audiocore/__init__.h" + +void common_hal_audiospeed_speedchanger_construct(audiospeed_speedchanger_obj_t *self, + mp_obj_t source, mp_obj_t rate_obj) { + audiospeed_construct(self, source, rate_obj); +} + +void common_hal_audiospeed_speedchanger_deinit(audiospeed_speedchanger_obj_t *self) { + audiospeed_deinit(self); +} + +void common_hal_audiospeed_speedchanger_set_rate(audiospeed_speedchanger_obj_t *self, mp_obj_t rate_obj) { + audiospeed_set_rate(&self->speed, rate_obj); +} + +mp_obj_t common_hal_audiospeed_speedchanger_get_rate(audiospeed_speedchanger_obj_t *self) { + return audiospeed_get_rate(&self->speed); +} + +void audiospeed_speedchanger_reset_buffer(audiospeed_speedchanger_obj_t *self, + bool single_channel_output, uint8_t channel) { + audiospeed_reset_buffer(self, single_channel_output, channel); +} + +audioio_get_buffer_result_t audiospeed_speedchanger_get_buffer(audiospeed_speedchanger_obj_t *self, + bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + return audiospeed_get_buffer(self, single_channel_output, channel, buffer, buffer_length); +} diff --git a/shared-module/audiospeed/SpeedChanger.h b/shared-module/audiospeed/SpeedChanger.h new file mode 100644 index 00000000000..34969e42bd6 --- /dev/null +++ b/shared-module/audiospeed/SpeedChanger.h @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-module/audiocore/__init__.h" +#include "shared-module/audiospeed/__init__.h" + +typedef audiospeed_base_t audiospeed_speedchanger_obj_t; + +void audiospeed_speedchanger_reset_buffer(audiospeed_speedchanger_obj_t *self, + bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t audiospeed_speedchanger_get_buffer(audiospeed_speedchanger_obj_t *self, + bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length); diff --git a/shared-module/audiospeed/__init__.c b/shared-module/audiospeed/__init__.c new file mode 100644 index 00000000000..19c4c9bf20d --- /dev/null +++ b/shared-module/audiospeed/__init__.c @@ -0,0 +1,176 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/gc.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/audiospeed/__init__.h" +#include "shared-bindings/audiocore/__init__.h" + +// Convert a Python float to 16.16 fixed-point rate +uint32_t audiospeed_rate_to_fp(mp_obj_t rate_obj) { + mp_float_t rate = mp_arg_validate_obj_float_range(rate_obj, 0.001, 1000.0, MP_QSTR_rate); + return (uint32_t)(rate * (1 << SPEED_SHIFT)); +} + +// Convert 16.16 fixed-point rate to Python float +mp_obj_t audiospeed_fp_to_rate(uint32_t rate_fp) { + return mp_obj_new_float((mp_float_t)rate_fp / (1 << SPEED_SHIFT)); +} + +void audiospeed_construct(audiospeed_base_t *self, mp_obj_t source, mp_obj_t rate_obj) { + audiosample_base_t *src_base = audiosample_check(source); + + self->source = source; + self->src_buffer = NULL; + self->src_buffer_length = 0; + self->src_sample_count = 0; + self->source_done = false; + self->source_exhausted = false; + + + // Copy format from source + self->base.sample_rate = src_base->sample_rate; + self->base.channel_count = src_base->channel_count; + self->base.bits_per_sample = src_base->bits_per_sample; + self->base.samples_signed = src_base->samples_signed; + self->base.single_buffer = false; + + audiospeed_set_rate(&self->speed, rate_obj); + audiospeed_reset_phase(&self->speed); + + uint8_t bytes_per_frame = (src_base->bits_per_sample / 8) * src_base->channel_count; + self->output_buffer_length = OUTPUT_BUFFER_FRAMES * bytes_per_frame; + self->base.max_buffer_length = self->output_buffer_length; + + self->output_buffer = m_malloc_without_collect(self->output_buffer_length); + if (self->output_buffer == NULL) { + m_malloc_fail(self->output_buffer_length); + } +} + +void audiospeed_deinit(audiospeed_base_t *self) { + self->output_buffer = NULL; + self->source = MP_OBJ_NULL; + audiosample_mark_deinit(&self->base); +} + +// Fetch the next buffer from the source. Returns false if no data available. +bool audiospeed_fetch_source_buffer(audiospeed_base_t *self) { + if (self->source_exhausted || self->source == NULL) { + return false; + } + uint8_t *buf = NULL; + uint32_t len = 0; + audioio_get_buffer_result_t result = audiosample_get_buffer(self->source, false, 0, &buf, &len); + if (result == GET_BUFFER_ERROR) { + self->source_exhausted = true; + return false; + } + if (len == 0) { + self->source_exhausted = true; + return false; + } + self->src_buffer = buf; + self->src_buffer_length = len; + uint8_t bytes_per_frame = (self->base.bits_per_sample / 8) * self->base.channel_count; + self->src_sample_count = len / bytes_per_frame; + self->source_done = (result == GET_BUFFER_DONE); + // Reset phase to index within this new buffer + audiospeed_reset_phase(&self->speed); + return true; +} + +void audiospeed_reset_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel) { + if (single_channel_output && channel == 1) { + return; + } + audiosample_reset_buffer(self->source, false, 0); + audiospeed_reset_phase(&self->speed); + self->src_buffer = NULL; + self->src_buffer_length = 0; + self->src_sample_count = 0; + self->source_done = false; + self->source_exhausted = false; +} + +audioio_get_buffer_result_t audiospeed_get_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + + // Ensure we have a source buffer + if (self->src_buffer == NULL) { + if (!audiospeed_fetch_source_buffer(self)) { + *buffer = NULL; + *buffer_length = 0; + return GET_BUFFER_DONE; + } + } + + uint8_t bytes_per_sample = self->base.bits_per_sample / 8; + uint8_t channels = self->base.channel_count; + uint8_t bytes_per_frame = bytes_per_sample * channels; + uint32_t out_frames = 0; + uint32_t max_out_frames = self->output_buffer_length / bytes_per_frame; + + if (bytes_per_sample == 1) { + // 8-bit samples + uint8_t *out = self->output_buffer; + while (out_frames < max_out_frames) { + uint32_t src_index = audiospeed_get_index(&self->speed); + // Advance to next source buffer if needed + if (src_index >= self->src_sample_count) { + if (self->source_done) { + self->source_exhausted = true; + break; + } + if (!audiospeed_fetch_source_buffer(self)) { + break; + } + src_index = 0; // phase was reset by fetch + } + uint8_t *src = self->src_buffer + src_index * bytes_per_frame; + for (uint8_t c = 0; c < channels; c++) { + *out++ = src[c]; + } + out_frames++; + audiospeed_increment_phase(&self->speed); + } + } else { + // 16-bit samples + int16_t *out = (int16_t *)self->output_buffer; + while (out_frames < max_out_frames) { + uint32_t src_index = audiospeed_get_index(&self->speed); + if (src_index >= self->src_sample_count) { + if (self->source_done) { + self->source_exhausted = true; + break; + } + if (!audiospeed_fetch_source_buffer(self)) { + break; + } + src_index = 0; + } + int16_t *src = (int16_t *)(self->src_buffer + src_index * bytes_per_frame); + for (uint8_t c = 0; c < channels; c++) { + *out++ = src[c]; + } + out_frames++; + audiospeed_increment_phase(&self->speed); + } + } + + *buffer = self->output_buffer; + *buffer_length = out_frames * bytes_per_frame; + + if (out_frames == 0) { + return GET_BUFFER_DONE; + } + return self->source_exhausted ? GET_BUFFER_DONE : GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/audiospeed/__init__.h b/shared-module/audiospeed/__init__.h new file mode 100644 index 00000000000..4a36a8b79b7 --- /dev/null +++ b/shared-module/audiospeed/__init__.h @@ -0,0 +1,72 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/objproperty.h" +#include "shared-module/audiocore/__init__.h" + +// Fixed-point 16.16 format +#define SPEED_SHIFT 16 +#define SPEED_DEFAULT (1 << SPEED_SHIFT) // default 1.0 + +typedef struct { + // Phase accumulator and rate in 16.16 fixed-point (units: source frames) + uint32_t phase; + uint32_t rate_fp; // 16.16 fixed-point rate +} audiospeed_speed_t; + +uint32_t audiospeed_rate_to_fp(mp_obj_t rate_obj); +mp_obj_t audiospeed_fp_to_rate(uint32_t rate_fp); + +static inline void audiospeed_set_rate(audiospeed_speed_t *self, mp_obj_t rate_obj) { + if (rate_obj != mp_const_none) { + self->rate_fp = audiospeed_rate_to_fp(rate_obj); + } else { + self->rate_fp = SPEED_DEFAULT; + } +} + +static inline mp_obj_t audiospeed_get_rate(audiospeed_speed_t *self) { + return audiospeed_fp_to_rate(self->rate_fp); +} + +static inline void audiospeed_reset_phase(audiospeed_speed_t *self) { + self->phase = 0; +} + +static inline void audiospeed_increment_phase(audiospeed_speed_t *self) { + self->phase += self->rate_fp; +} + +static inline uint32_t audiospeed_get_index(audiospeed_speed_t *self) { + return self->phase >> SPEED_SHIFT; +} + +#define OUTPUT_BUFFER_FRAMES 128 + +typedef struct { + audiosample_base_t base; + mp_obj_t source; + uint8_t *output_buffer; + uint32_t output_buffer_length; // in bytes, allocated size + // Source buffer cache + uint8_t *src_buffer; + uint32_t src_buffer_length; // in bytes + uint32_t src_sample_count; // in frames + audiospeed_speed_t speed; + bool source_done; // source returned DONE on last get_buffer + bool source_exhausted; // source DONE and we consumed all of it +} audiospeed_base_t; + +void audiospeed_construct(audiospeed_base_t *self, mp_obj_t source, mp_obj_t rate_obj); +void audiospeed_deinit(audiospeed_base_t *self); +bool audiospeed_fetch_source_buffer(audiospeed_base_t *self); +void audiospeed_reset_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t audiospeed_get_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length); diff --git a/shared-module/bitbangio/I2C.c b/shared-module/bitbangio/I2C.c index 0089bdc1e1e..84a33f16673 100644 --- a/shared-module/bitbangio/I2C.c +++ b/shared-module/bitbangio/I2C.c @@ -8,10 +8,15 @@ #include "py/mperrno.h" #include "py/obj.h" #include "py/runtime.h" +#include "py/gc.h" #include "common-hal/microcontroller/Pin.h" #include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" static void delay(bitbangio_i2c_obj_t *self) { // We need to use an accurate delay to get acceptable I2C @@ -19,61 +24,81 @@ static void delay(bitbangio_i2c_obj_t *self) { common_hal_mcu_delay_us(self->us_delay); } -static void scl_low(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_set_value(&self->scl, false); +static bool scl_low(bitbangio_i2c_obj_t *self) { + return digitalinout_protocol_set_value(self->scl, false) == 0; } -static void scl_release(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_set_value(&self->scl, true); +static bool scl_release(bitbangio_i2c_obj_t *self) { + if (digitalinout_protocol_set_value(self->scl, true) != 0) { + return false; + } uint32_t count = self->us_timeout; delay(self); // For clock stretching, wait for the SCL pin to be released, with timeout. - common_hal_digitalio_digitalinout_switch_to_input(&self->scl, PULL_UP); - for (; !common_hal_digitalio_digitalinout_get_value(&self->scl) && count; --count) { + digitalinout_protocol_switch_to_input(self->scl, PULL_UP); + bool value; + for (; count; --count) { + if (digitalinout_protocol_get_value(self->scl, &value) != 0) { + return false; + } + if (value) { + break; + } common_hal_mcu_delay_us(1); } - common_hal_digitalio_digitalinout_switch_to_output(&self->scl, true, DRIVE_MODE_OPEN_DRAIN); + digitalinout_protocol_switch_to_output(self->scl, true, DRIVE_MODE_OPEN_DRAIN); // raise exception on timeout if (count == 0) { mp_raise_msg_varg(&mp_type_TimeoutError, MP_ERROR_TEXT("%q too long"), MP_QSTR_timeout); } + return true; } -static void sda_low(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_set_value(&self->sda, false); +static bool sda_low(bitbangio_i2c_obj_t *self) { + return digitalinout_protocol_set_value(self->sda, false) == 0; } -static void sda_release(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_set_value(&self->sda, true); +static bool sda_release(bitbangio_i2c_obj_t *self) { + return digitalinout_protocol_set_value(self->sda, true) == 0; } -static bool sda_read(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_switch_to_input(&self->sda, PULL_UP); - bool value = common_hal_digitalio_digitalinout_get_value(&self->sda); - common_hal_digitalio_digitalinout_switch_to_output(&self->sda, true, DRIVE_MODE_OPEN_DRAIN); - return value; +static bool sda_read(bitbangio_i2c_obj_t *self, bool *value) { + digitalinout_protocol_switch_to_input(self->sda, PULL_UP); + if (digitalinout_protocol_get_value(self->sda, value) != 0) { + return false; + } + digitalinout_protocol_switch_to_output(self->sda, true, DRIVE_MODE_OPEN_DRAIN); + return true; } -static void start(bitbangio_i2c_obj_t *self) { - sda_release(self); +static bool start(bitbangio_i2c_obj_t *self) { + if (!sda_release(self)) { + return false; + } delay(self); scl_release(self); sda_low(self); delay(self); + return true; } -static void stop(bitbangio_i2c_obj_t *self) { +static bool stop(bitbangio_i2c_obj_t *self) { delay(self); - sda_low(self); + if (!sda_low(self)) { + return false; + } delay(self); scl_release(self); sda_release(self); delay(self); + return true; } static int write_byte(bitbangio_i2c_obj_t *self, uint8_t val) { delay(self); - scl_low(self); + if (!scl_low(self)) { + return -1; + } for (int i = 7; i >= 0; i--) { if ((val >> i) & 1) { @@ -90,7 +115,10 @@ static int write_byte(bitbangio_i2c_obj_t *self, uint8_t val) { delay(self); scl_release(self); - int ret = sda_read(self); + bool ret; + if (!sda_read(self, &ret)) { + return -1; + } delay(self); scl_low(self); @@ -99,13 +127,17 @@ static int write_byte(bitbangio_i2c_obj_t *self, uint8_t val) { static bool read_byte(bitbangio_i2c_obj_t *self, uint8_t *val, bool ack) { delay(self); - scl_low(self); + if (!scl_low(self)) { + return false; + } delay(self); uint8_t data = 0; for (int i = 7; i >= 0; i--) { scl_release(self); - data = (data << 1) | sda_read(self); + bool bit; + sda_read(self, &bit); + data = (data << 1) | bit; scl_low(self); delay(self); } @@ -124,8 +156,8 @@ static bool read_byte(bitbangio_i2c_obj_t *self, uint8_t *val, bool ack) { } void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, - const mcu_pin_obj_t *scl, - const mcu_pin_obj_t *sda, + mp_obj_t scl, + mp_obj_t sda, uint32_t frequency, uint32_t us_timeout) { @@ -134,32 +166,42 @@ void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, if (self->us_delay == 0) { self->us_delay = 1; } - digitalinout_result_t result = common_hal_digitalio_digitalinout_construct(&self->scl, scl); - if (result != DIGITALINOUT_OK) { - return; - } - result = common_hal_digitalio_digitalinout_construct(&self->sda, sda); - if (result != DIGITALINOUT_OK) { - common_hal_digitalio_digitalinout_deinit(&self->scl); - return; - } - common_hal_digitalio_digitalinout_switch_to_output(&self->scl, true, DRIVE_MODE_OPEN_DRAIN); - common_hal_digitalio_digitalinout_switch_to_output(&self->sda, true, DRIVE_MODE_OPEN_DRAIN); - stop(self); + // Allocate the pins in the same place as self. + bool use_port_allocation = !gc_alloc_possible() || !gc_ptr_on_heap(self); + + // Convert scl from Pin to DigitalInOutProtocol + self->scl = digitalinout_protocol_from_pin(scl, MP_QSTR_scl, false, use_port_allocation, &self->own_scl); + + // Convert sda from Pin to DigitalInOutProtocol + self->sda = digitalinout_protocol_from_pin(sda, MP_QSTR_sda, false, use_port_allocation, &self->own_sda); + + digitalinout_protocol_switch_to_output(self->scl, true, DRIVE_MODE_OPEN_DRAIN); + digitalinout_protocol_switch_to_output(self->sda, true, DRIVE_MODE_OPEN_DRAIN); + + if (!stop(self)) { + mp_raise_OSError(MP_EIO); + } } bool shared_module_bitbangio_i2c_deinited(bitbangio_i2c_obj_t *self) { // If one is deinited, both will be. - return common_hal_digitalio_digitalinout_deinited(&self->scl); + return digitalinout_protocol_deinited(self->scl); } void shared_module_bitbangio_i2c_deinit(bitbangio_i2c_obj_t *self) { if (shared_module_bitbangio_i2c_deinited(self)) { return; } - common_hal_digitalio_digitalinout_deinit(&self->scl); - common_hal_digitalio_digitalinout_deinit(&self->sda); + // Only deinit and free the pins if we own them + if (self->own_scl) { + digitalinout_protocol_deinit(self->scl); + circuitpy_free_obj(self->scl); + } + if (self->own_sda) { + digitalinout_protocol_deinit(self->sda); + circuitpy_free_obj(self->sda); + } } bool shared_module_bitbangio_i2c_try_lock(bitbangio_i2c_obj_t *self) { @@ -182,24 +224,34 @@ void shared_module_bitbangio_i2c_unlock(bitbangio_i2c_obj_t *self) { } bool shared_module_bitbangio_i2c_probe(bitbangio_i2c_obj_t *self, uint8_t addr) { - start(self); - bool ok = write_byte(self, addr << 1); + if (!start(self)) { + mp_raise_OSError(MP_EIO); + } + int result = write_byte(self, addr << 1); stop(self); - return ok; + if (result < 0) { + mp_raise_OSError(MP_EIO); + } + return result; } uint8_t shared_module_bitbangio_i2c_write(bitbangio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { // start the I2C transaction - start(self); + if (!start(self)) { + return MP_EIO; + } uint8_t status = 0; - if (!write_byte(self, addr << 1)) { + int result = write_byte(self, addr << 1); + if (result < 0) { + status = MP_EIO; + } else if (!result) { status = MP_ENODEV; } if (status == 0) { for (uint32_t i = 0; i < len; i++) { - if (!write_byte(self, data[i])) { + if (write_byte(self, data[i]) <= 0) { status = MP_EIO; break; } @@ -215,9 +267,14 @@ uint8_t shared_module_bitbangio_i2c_write(bitbangio_i2c_obj_t *self, uint16_t ad uint8_t shared_module_bitbangio_i2c_read(bitbangio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { // start the I2C transaction - start(self); + if (!start(self)) { + return MP_EIO; + } uint8_t status = 0; - if (!write_byte(self, (addr << 1) | 1)) { + int addr_result = write_byte(self, (addr << 1) | 1); + if (addr_result < 0) { + status = MP_EIO; + } else if (!addr_result) { status = MP_ENODEV; } diff --git a/shared-module/bitbangio/I2C.h b/shared-module/bitbangio/I2C.h index 3908a3dd374..0cec9186e9b 100644 --- a/shared-module/bitbangio/I2C.h +++ b/shared-module/bitbangio/I2C.h @@ -12,9 +12,11 @@ typedef struct { mp_obj_base_t base; - digitalio_digitalinout_obj_t scl; - digitalio_digitalinout_obj_t sda; + mp_obj_t scl; + mp_obj_t sda; uint32_t us_delay; uint32_t us_timeout; volatile bool locked; + bool own_scl; + bool own_sda; } bitbangio_i2c_obj_t; diff --git a/shared-module/bitbangio/SPI.c b/shared-module/bitbangio/SPI.c index 56e978985ed..854a1cb5118 100644 --- a/shared-module/bitbangio/SPI.c +++ b/shared-module/bitbangio/SPI.c @@ -7,64 +7,66 @@ #include "py/mpconfig.h" #include "py/obj.h" #include "py/runtime.h" +#include "py/gc.h" #include "common-hal/microcontroller/Pin.h" #include "shared-bindings/bitbangio/SPI.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" #include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" #define MAX_BAUDRATE (common_hal_mcu_get_clock_frequency() / 48) void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self, - const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *miso) { - digitalinout_result_t result = common_hal_digitalio_digitalinout_construct(&self->clock, clock); - if (result != DIGITALINOUT_OK) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_clock); - } - common_hal_digitalio_digitalinout_switch_to_output(&self->clock, self->polarity == 1, DRIVE_MODE_PUSH_PULL); + mp_obj_t clock, mp_obj_t mosi, mp_obj_t miso) { - if (mosi != NULL) { - result = common_hal_digitalio_digitalinout_construct(&self->mosi, mosi); - if (result != DIGITALINOUT_OK) { - common_hal_digitalio_digitalinout_deinit(&self->clock); - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_mosi); - } - self->has_mosi = true; - common_hal_digitalio_digitalinout_switch_to_output(&self->mosi, false, DRIVE_MODE_PUSH_PULL); - } + // Allocate the pins in the same place as self. + bool use_port_allocation = !gc_alloc_possible() || !gc_ptr_on_heap(self); - if (miso != NULL) { - // Starts out as input by default, no need to change. - result = common_hal_digitalio_digitalinout_construct(&self->miso, miso); - if (result != DIGITALINOUT_OK) { - common_hal_digitalio_digitalinout_deinit(&self->clock); - if (mosi != NULL) { - common_hal_digitalio_digitalinout_deinit(&self->mosi); - } - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_miso); - } - self->has_miso = true; + // Convert clock from Pin to DigitalInOutProtocol + self->clock = digitalinout_protocol_from_pin(clock, MP_QSTR_clock, false, use_port_allocation, &self->own_clock); + digitalinout_protocol_switch_to_output(self->clock, self->polarity == 1, DRIVE_MODE_PUSH_PULL); + + // Convert mosi from Pin to DigitalInOutProtocol (optional) + self->mosi = digitalinout_protocol_from_pin(mosi, MP_QSTR_mosi, true, use_port_allocation, &self->own_mosi); + self->has_mosi = (self->mosi != mp_const_none); + if (self->has_mosi) { + digitalinout_protocol_switch_to_output(self->mosi, false, DRIVE_MODE_PUSH_PULL); } + + // Convert miso from Pin to DigitalInOutProtocol (optional) + self->miso = digitalinout_protocol_from_pin(miso, MP_QSTR_miso, true, use_port_allocation, &self->own_miso); + self->has_miso = (self->miso != mp_const_none); + // MISO starts out as input by default, no need to change + self->delay_half = 5; self->polarity = 0; self->phase = 0; } bool shared_module_bitbangio_spi_deinited(bitbangio_spi_obj_t *self) { - return common_hal_digitalio_digitalinout_deinited(&self->clock); + return digitalinout_protocol_deinited(self->clock); } void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self) { if (shared_module_bitbangio_spi_deinited(self)) { return; } - common_hal_digitalio_digitalinout_deinit(&self->clock); - if (self->has_mosi) { - common_hal_digitalio_digitalinout_deinit(&self->mosi); + // Only deinit and free the pins if we own them + if (self->own_clock) { + digitalinout_protocol_deinit(self->clock); + circuitpy_free_obj(self->clock); + } + if (self->has_mosi && self->own_mosi) { + digitalinout_protocol_deinit(self->mosi); + circuitpy_free_obj(self->mosi); } - if (self->has_miso) { - common_hal_digitalio_digitalinout_deinit(&self->miso); + if (self->has_miso && self->own_miso) { + digitalinout_protocol_deinit(self->miso); + circuitpy_free_obj(self->miso); } } @@ -80,7 +82,7 @@ void shared_module_bitbangio_spi_configure(bitbangio_spi_obj_t *self, // If the polarity has changed, make sure we re-initialize the idle state // of the clock as well. self->polarity = polarity; - common_hal_digitalio_digitalinout_switch_to_output(&self->clock, polarity == 1, DRIVE_MODE_PUSH_PULL); + digitalinout_protocol_switch_to_output(self->clock, polarity == 1, DRIVE_MODE_PUSH_PULL); } self->phase = phase; } @@ -121,9 +123,15 @@ bool shared_module_bitbangio_spi_write(bitbangio_spi_obj_t *self, const uint8_t for (size_t i = 0; i < len; ++i) { uint8_t data_out = data[i]; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + if (i == 0 && j == 0) { + if (digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1) != 0) { + return false; + } + } else { + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); + } + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); } if (dest != NULL) { dest[i] = data_in; @@ -136,16 +144,22 @@ bool shared_module_bitbangio_spi_write(bitbangio_spi_obj_t *self, const uint8_t for (size_t i = 0; i < len; ++i) { uint8_t data_out = data[i]; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); + if (i == 0 && j == 0) { + if (digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1) != 0) { + return false; + } + } else { + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); + } if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); common_hal_mcu_delay_us(delay_half); } } @@ -176,14 +190,18 @@ bool shared_module_bitbangio_spi_read(bitbangio_spi_obj_t *self, uint8_t *data, if (delay_half <= MICROPY_PY_MACHINE_SPI_MIN_DELAY) { // Clock out zeroes while we read. if (self->has_mosi) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, false); + if (digitalinout_protocol_set_value(self->mosi, false) != 0) { + return false; + } } for (size_t i = 0; i < len; ++i) { uint8_t data_in = 0; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); - data_in = (data_in << 1) | common_hal_digitalio_digitalinout_get_value(&self->miso); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); + bool bit; + digitalinout_protocol_get_value(self->miso, &bit); + data_in = (data_in << 1) | bit; + digitalinout_protocol_set_value(self->clock, self->polarity); } data[i] = data_in; } @@ -191,28 +209,32 @@ bool shared_module_bitbangio_spi_read(bitbangio_spi_obj_t *self, uint8_t *data, } #endif if (self->has_mosi) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, false); + if (digitalinout_protocol_set_value(self->mosi, false) != 0) { + return false; + } } for (size_t i = 0; i < len; ++i) { uint8_t data_out = write_data; uint8_t data_in = 0; for (int j = 0; j < 8; ++j, data_out <<= 1) { if (self->has_mosi) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); } if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); common_hal_mcu_delay_us(delay_half); } - data_in = (data_in << 1) | common_hal_digitalio_digitalinout_get_value(&self->miso); + bool bit; + digitalinout_protocol_get_value(self->miso, &bit); + data_in = (data_in << 1) | bit; if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); common_hal_mcu_delay_us(delay_half); } } @@ -248,10 +270,18 @@ bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self, const uint8 uint8_t data_out = dout[i]; uint8_t data_in = 0; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); - data_in = (data_in << 1) | common_hal_digitalio_digitalinout_get_value(&self->miso); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + if (i == 0 && j == 0) { + if (digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1) != 0) { + return false; + } + } else { + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); + } + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); + bool bit; + digitalinout_protocol_get_value(self->miso, &bit); + data_in = (data_in << 1) | bit; + digitalinout_protocol_set_value(self->clock, self->polarity); } din[i] = data_in; @@ -267,20 +297,28 @@ bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self, const uint8 uint8_t data_out = dout[i]; uint8_t data_in = 0; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); + if (i == 0 && j == 0) { + if (digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1) != 0) { + return false; + } + } else { + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); + } if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); common_hal_mcu_delay_us(delay_half); } - data_in = (data_in << 1) | common_hal_digitalio_digitalinout_get_value(&self->miso); + bool bit; + digitalinout_protocol_get_value(self->miso, &bit); + data_in = (data_in << 1) | bit; if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); common_hal_mcu_delay_us(delay_half); } } diff --git a/shared-module/bitbangio/SPI.h b/shared-module/bitbangio/SPI.h index c19170af7c4..5f3c109b7f6 100644 --- a/shared-module/bitbangio/SPI.h +++ b/shared-module/bitbangio/SPI.h @@ -12,13 +12,16 @@ typedef struct { mp_obj_base_t base; - digitalio_digitalinout_obj_t clock; - digitalio_digitalinout_obj_t mosi; - digitalio_digitalinout_obj_t miso; + mp_obj_t clock; + mp_obj_t mosi; + mp_obj_t miso; uint32_t delay_half; bool has_miso : 1; bool has_mosi : 1; uint8_t polarity : 1; uint8_t phase : 1; volatile bool locked : 1; + bool own_clock; + bool own_mosi; + bool own_miso; } bitbangio_spi_obj_t; diff --git a/shared-module/bitmaptools/__init__.c b/shared-module/bitmaptools/__init__.c index 8a41e387e51..e51881aa5bb 100644 --- a/shared-module/bitmaptools/__init__.c +++ b/shared-module/bitmaptools/__init__.c @@ -204,6 +204,21 @@ void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16 } } +void common_hal_bitmaptools_replace_color(displayio_bitmap_t *destination, + uint32_t old_color, + uint32_t new_color) { + + int16_t x, y; + for (x = 0; x < destination->width; x++) { + for (y = 0; y < destination->height; y++) { + uint32_t pixel_val = common_hal_displayio_bitmap_get_pixel(destination, x, y); + if (pixel_val == old_color) { + displayio_bitmap_write_pixel(destination, x, y, new_color); + } + } + } +} + void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination, int16_t x1, int16_t y1, int16_t x2, int16_t y2, @@ -842,12 +857,15 @@ void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bi } void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitmap_t *source1, displayio_bitmap_t *source2, displayio_colorspace_t colorspace, mp_float_t factor1, mp_float_t factor2, - bitmaptools_blendmode_t blendmode, uint32_t skip_source1_index, bool skip_source1_index_none, uint32_t skip_source2_index, bool skip_source2_index_none) { + bitmaptools_blendmode_t blendmode, uint32_t skip_source1_index, bool skip_source1_index_none, uint32_t skip_source2_index, bool skip_source2_index_none, + displayio_bitmap_t *mask) { displayio_area_t a = {0, 0, dest->width, dest->height, NULL}; displayio_bitmap_set_dirty_area(dest, &a); - int ifactor1 = (int)(factor1 * 256); - int ifactor2 = (int)(factor2 * 256); + int ifactor1_base = (int)(factor1 * 256); + int ifactor2_base = (int)(factor2 * 256); + int ifactor1 = ifactor1_base; + int ifactor2 = ifactor2_base; bool blend_source1, blend_source2; if (colorspace == DISPLAYIO_COLORSPACE_L8) { @@ -855,10 +873,20 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma uint8_t *dptr = (uint8_t *)(dest->data + y * dest->stride); uint8_t *sptr1 = (uint8_t *)(source1->data + y * source1->stride); uint8_t *sptr2 = (uint8_t *)(source2->data + y * source2->stride); + uint8_t *mptr = mask ? (uint8_t *)(mask->data + y * mask->stride) : NULL; int pixel; for (int x = 0; x < dest->width; x++) { blend_source1 = skip_source1_index_none || *sptr1 != (uint8_t)skip_source1_index; blend_source2 = skip_source2_index_none || *sptr2 != (uint8_t)skip_source2_index; + if (mptr) { + uint8_t m = *mptr; + // Scale source2's contribution by the mask (0..255) + ifactor2 = (ifactor2_base * m + 127) / 255; + if (m == 0) { + // Mask says fully transparent: drop source2 entirely + blend_source2 = false; + } + } if (blend_source1 && blend_source2) { // Premultiply by the alpha factor int sda = *sptr1++ *ifactor1; @@ -871,7 +899,8 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma blend = sca + sda * (256 - ifactor2) / 256; } // Divide by the alpha factor - pixel = (blend / (ifactor1 + ifactor2 - ifactor1 * ifactor2 / 256)); + int denom = ifactor1 + ifactor2 - ifactor1 * ifactor2 / 256; + pixel = (denom > 0) ? (blend / denom) : 0; } else if (blend_source1) { // Apply iFactor1 to source1 only pixel = *sptr1++ *ifactor1 / 256; @@ -883,6 +912,9 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma pixel = *dptr; } *dptr++ = MIN(255, MAX(0, pixel)); + if (mptr) { + mptr++; + } } } } else { @@ -892,6 +924,7 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma uint16_t *dptr = (uint16_t *)(dest->data + y * dest->stride); uint16_t *sptr1 = (uint16_t *)(source1->data + y * source1->stride); uint16_t *sptr2 = (uint16_t *)(source2->data + y * source2->stride); + uint8_t *mptr = mask ? (uint8_t *)(mask->data + y * mask->stride) : NULL; for (int x = 0; x < dest->width; x++) { int spix1 = *sptr1++; int spix2 = *sptr2++; @@ -907,11 +940,24 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma blend_source1 = skip_source1_index_none || spix1 != (int)skip_source1_index; blend_source2 = skip_source2_index_none || spix2 != (int)skip_source2_index; + if (mptr) { + uint8_t m = *mptr++; + ifactor2 = (ifactor2_base * m + 127) / 255; + if (m == 0) { + blend_source2 = false; + } + } + if (blend_source1 && blend_source2) { // Blend based on the SVG alpha compositing specs // https://dev.w3.org/SVG/modules/compositing/master/#alphaCompositing int ifactor_blend = ifactor1 + ifactor2 - ifactor1 * ifactor2 / 256; + if (ifactor_blend <= 0) { + // Both factors are zero at this pixel; keep destination. + dptr++; + continue; + } // Premultiply the colors by the alpha factor int red_dca = ((spix1 & r_mask) >> 8) * ifactor1; diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 96735c8dbaa..6bfc0bbf0f1 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -43,15 +43,6 @@ static const board_i2c_pin_t i2c_pin[CIRCUITPY_BOARD_I2C] = CIRCUITPY_BOARD_I2C_ static busio_i2c_obj_t i2c_obj[CIRCUITPY_BOARD_I2C]; static bool i2c_obj_created[CIRCUITPY_BOARD_I2C]; -bool common_hal_board_is_i2c(mp_obj_t obj) { - for (uint8_t instance = 0; instance < CIRCUITPY_BOARD_I2C; instance++) { - if (obj == &i2c_obj[instance]) { - return true; - } - } - return false; -} - mp_obj_t common_hal_board_get_i2c(const mp_int_t instance) { return i2c_obj_created[instance] ? &i2c_obj[instance] : NULL; } @@ -89,15 +80,6 @@ static const board_spi_pin_t spi_pin[CIRCUITPY_BOARD_SPI] = CIRCUITPY_BOARD_SPI_ static busio_spi_obj_t spi_obj[CIRCUITPY_BOARD_SPI]; static bool spi_obj_created[CIRCUITPY_BOARD_SPI]; -bool common_hal_board_is_spi(mp_obj_t obj) { - for (uint8_t instance = 0; instance < CIRCUITPY_BOARD_SPI; instance++) { - if (obj == &spi_obj[instance]) { - return true; - } - } - return false; -} - mp_obj_t common_hal_board_get_spi(const mp_int_t instance) { return spi_obj_created[instance] ? &spi_obj[instance] : NULL; } @@ -136,15 +118,6 @@ static const board_uart_pin_t uart_pin[CIRCUITPY_BOARD_UART] = CIRCUITPY_BOARD_U static busio_uart_obj_t uart_obj[CIRCUITPY_BOARD_UART]; static bool uart_obj_created[CIRCUITPY_BOARD_UART]; -bool common_hal_board_is_uart(mp_obj_t obj) { - for (uint8_t instance = 0; instance < CIRCUITPY_BOARD_UART; instance++) { - if (obj == &uart_obj[instance]) { - return true; - } - } - return false; -} - mp_obj_t common_hal_board_get_uart(const mp_int_t instance) { return uart_obj_created[instance] ? &uart_obj[instance] : NULL; } @@ -183,6 +156,10 @@ void reset_board_buses(void) { } } #endif + #if CIRCUITPY_I2CIOEXPANDER + // Assume the native I2C bus is used for IO Expander pins. + display_using_i2c = true; + #endif if (i2c_obj_created[instance]) { // make sure I2C lock is not held over a soft reset common_hal_busio_i2c_unlock(&i2c_obj[instance]); diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index ac57f3bf3e0..01e0f7a7896 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -6,6 +6,7 @@ #include "shared-bindings/busdisplay/BusDisplay.h" +#include "py/mphal.h" #include "py/runtime.h" #if CIRCUITPY_FOURWIRE #include "shared-bindings/fourwire/FourWire.h" @@ -16,6 +17,7 @@ #if CIRCUITPY_PARALLELDISPLAYBUS #include "shared-bindings/paralleldisplaybus/ParallelBus.h" #endif +#include "shared/runtime/interrupt_char.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/time/__init__.h" #include "shared-module/displayio/__init__.h" @@ -73,6 +75,9 @@ void common_hal_busdisplay_busdisplay_construct(busdisplay_busdisplay_obj_t *sel uint8_t *data = cmd + 2; while (!displayio_display_bus_begin_transaction(&self->bus)) { RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_display); + } } if (self->bus.data_as_commands) { uint8_t full_command[data_size + 1]; @@ -80,7 +85,7 @@ void common_hal_busdisplay_busdisplay_construct(busdisplay_busdisplay_obj_t *sel memcpy(full_command + 1, data, data_size); self->bus.send(self->bus.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, full_command, data_size + 1); } else { - self->bus.send(self->bus.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, cmd, 1); + self->bus.send(self->bus.bus, DISPLAY_COMMAND, data_size > 0 ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED, cmd, 1); self->bus.send(self->bus.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, data, data_size); } displayio_display_bus_end_transaction(&self->bus); @@ -214,7 +219,7 @@ static void _send_pixels(busdisplay_busdisplay_obj_t *self, uint8_t *pixels, uin } static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_area_t *area) { - uint16_t buffer_size = 128; // In uint32_ts + uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof(uint32_t); // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. @@ -256,9 +261,10 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are // Allocated and shared as a uint32_t array so the compiler knows the // alignment everywhere. - uint32_t buffer[buffer_size]; uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t buffer[buffer_size]; uint32_t mask[mask_length]; + uint16_t remaining_rows = displayio_area_height(&clipped); for (uint16_t j = 0; j < subrectangles; j++) { @@ -273,8 +279,6 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are } remaining_rows -= rows_per_buffer; - displayio_display_bus_set_region_to_update(&self->bus, &self->core, &subrectangle); - uint16_t subrectangle_size_bytes; if (self->core.colorspace.depth >= 8) { subrectangle_size_bytes = displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); @@ -287,12 +291,12 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); + displayio_display_bus_set_region_to_update(&self->bus, &self->core, &subrectangle); + // Can't acquire display bus; skip the rest of the data. - if (!displayio_display_bus_is_free(&self->bus)) { + if (!displayio_display_bus_begin_transaction(&self->bus)) { return false; } - - displayio_display_bus_begin_transaction(&self->bus); _send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes); displayio_display_bus_end_transaction(&self->bus); @@ -305,6 +309,10 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are usb_background(); #endif } + + // Drain any remaining asynchronous transfers. + displayio_display_bus_flush(&self->bus); + return true; } @@ -313,7 +321,11 @@ static void _refresh_display(busdisplay_busdisplay_obj_t *self) { // A refresh on this bus is already in progress. Try next display. return; } - displayio_display_core_start_refresh(&self->core); + if (!displayio_display_core_start_refresh(&self->core)) { + // Refresh for this display already in progress. + return; + } + const displayio_area_t *current_area = _get_refresh_areas(self); while (current_area != NULL) { _refresh_area(self, current_area); diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index a2bf685d0f7..84ebffdab6d 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -435,7 +435,7 @@ void displayio_group_finish_refresh(displayio_group_t *self) { } } -displayio_area_t *displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t *tail) { +static displayio_area_t *group_get_refresh_areas_impl(displayio_group_t *self, displayio_area_t *tail) { if (self->item_removed) { self->dirty_area.next = tail; tail = &self->dirty_area; @@ -462,10 +462,76 @@ displayio_area_t *displayio_group_get_refresh_areas(displayio_group_t *self, dis layer = mp_obj_cast_to_native_base( self->members->items[i], &displayio_group_type); if (layer != MP_OBJ_NULL) { - tail = displayio_group_get_refresh_areas(layer, tail); + tail = group_get_refresh_areas_impl(layer, tail); continue; } } return tail; } + +// Filter the dirty-rect list by containment: unlink every area that is fully contained +// in another area in the list (a changing text label is the common case - the group +// dirties the whole label region via item_removed plus one area per glyph, and the +// glyph areas all sit inside the label region). Dropping a covered area is lossless: +// the same pixels are refreshed by the survivor, in fewer transfers. +// +// The nodes are OWNED BY THE ITEMS (TileGrid reuses dirty_area as its tile-space dirty +// accumulator between frames, vectorio keeps its current_area, ...), so their +// coordinates must never be modified here. The ONLY mutation is the .next relink, +// which is safe because every provider unconditionally reassigns .next at link time on +// every get_refresh_areas call and never reads it back. +// +// Nodes at and past `tail` belong to the caller, so the sweep uses `tail` as its end +// sentinel and never looks past it (every in-tree caller passes tail == NULL). +// +// One pass suffices: coordinates never change and unlinking preserves the relative +// order of the remaining nodes, so every pair of surviving nodes is examined. Equal +// areas satisfy the containment test in both directions; testing b-inside-a FIRST +// keeps the earlier node and drops the later one - the two tests must stay an else-if +// chain or equal areas would drop BOTH nodes and lose the area entirely. +static displayio_area_t *filter_out_redundant_areas(displayio_area_t *head, + const displayio_area_t *tail) { + displayio_area_t *a_prev = NULL; + displayio_area_t *a = head; + while (a != tail) { + // The casts from the const .next field are safe: every node before `tail` is a + // mutable item-owned struct; only the field's declared type is pointer-to-const. + displayio_area_t *b_prev = a; + displayio_area_t *b = (displayio_area_t *)a->next; + bool a_dropped = false; + while (b != tail) { + if (b->x1 >= a->x1 && b->y1 >= a->y1 && b->x2 <= a->x2 && b->y2 <= a->y2) { + // b is contained in a (equal areas land here): unlink b. + b_prev->next = b->next; + b = (displayio_area_t *)b_prev->next; + } else if (a->x1 >= b->x1 && a->y1 >= b->y1 && a->x2 <= b->x2 && a->y2 <= b->y2) { + // a is strictly contained in the later b: unlink a and move on. + if (a_prev == NULL) { + head = (displayio_area_t *)a->next; + } else { + a_prev->next = a->next; + } + a_dropped = true; + break; + } else { + b_prev = b; + b = (displayio_area_t *)b->next; + } + } + if (a_dropped) { + a = (a_prev == NULL) ? head : (displayio_area_t *)a_prev->next; + } else { + a_prev = a; + a = (displayio_area_t *)a->next; + } + } + return head; +} + +// Public entry point: displays call this once on their root group, so the whole tree's +// list is filtered in one place and no display type needs its own copy of the logic. +displayio_area_t *displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t *tail) { + displayio_area_t *areas = group_get_refresh_areas_impl(self, tail); + return filter_out_redundant_areas(areas, tail); +} diff --git a/shared-module/displayio/Shape.c b/shared-module/displayio/Shape.c deleted file mode 100644 index 143d37c6c9b..00000000000 --- a/shared-module/displayio/Shape.c +++ /dev/null @@ -1,126 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "shared-bindings/displayio/Shape.h" - -#include - -#include "py/runtime.h" -#include "py/misc.h" - -void common_hal_displayio_shape_construct(displayio_shape_t *self, uint32_t width, - uint32_t height, bool mirror_x, bool mirror_y) { - self->mirror_x = mirror_x; - self->mirror_y = mirror_y; - self->width = width; - if (self->mirror_x) { - width /= 2; - width += self->width % 2; - } - self->half_width = width; - - self->height = height; - if (self->mirror_y) { - height /= 2; - height += self->height % 2; - } - self->half_height = height; - - self->data = m_malloc_without_collect(height * sizeof(uint32_t)); - - for (uint16_t i = 0; i < height; i++) { - self->data[2 * i] = 0; - self->data[2 * i + 1] = width; - } - - self->dirty_area.x1 = 0; - self->dirty_area.x2 = width; - self->dirty_area.y1 = 0; - self->dirty_area.y2 = height; -} - -void common_hal_displayio_shape_set_boundary(displayio_shape_t *self, uint16_t y, uint16_t start_x, uint16_t end_x) { - uint16_t max_y = self->height - 1; - if (self->mirror_y) { - max_y = self->half_height - 1; - } - mp_arg_validate_int_range(y, 0, max_y, MP_QSTR_y); - uint16_t max_x = self->width - 1; - if (self->mirror_x) { - max_x = self->half_width - 1; - } - mp_arg_validate_int_range(start_x, 0, max_x, MP_QSTR_start_x); - mp_arg_validate_int_range(end_x, 0, max_x, MP_QSTR_end_x); - - uint16_t lower_x, upper_x, lower_y, upper_y; - - // find x-boundaries for updating based on current data and start_x, end_x, and mirror_x - lower_x = MIN(start_x, self->data[2 * y]); - - if (self->mirror_x) { - upper_x = self->width - lower_x + 1; // dirty rectangles are treated with max value exclusive - } else { - upper_x = MAX(end_x, self->data[2 * y + 1]) + 1; // dirty rectangles are treated with max value exclusive - } - - // find y-boundaries based on y and mirror_y - lower_y = y; - - if (self->mirror_y) { - upper_y = self->height - lower_y + 1; // dirty rectangles are treated with max value exclusive - } else { - upper_y = y + 1; // dirty rectangles are treated with max value exclusive - } - - self->data[2 * y] = start_x; // update the data array with the new boundaries - self->data[2 * y + 1] = end_x; - - if (self->dirty_area.x1 == self->dirty_area.x2) { // Dirty region is empty - self->dirty_area.x1 = lower_x; - self->dirty_area.x2 = upper_x; - self->dirty_area.y1 = lower_y; - self->dirty_area.y2 = upper_y; - - } else { // Dirty region is not empty - self->dirty_area.x1 = MIN(lower_x, self->dirty_area.x1); - self->dirty_area.x2 = MAX(upper_x, self->dirty_area.x2); - - self->dirty_area.y1 = MIN(lower_y, self->dirty_area.y1); - self->dirty_area.y2 = MAX(upper_y, self->dirty_area.y2); - } -} - -uint32_t common_hal_displayio_shape_get_pixel(void *obj, int16_t x, int16_t y) { - displayio_shape_t *self = obj; - if (x >= self->width || x < 0 || y >= self->height || y < 0) { - return 0; - } - if (self->mirror_x && x >= self->half_width) { - x = self->width - x - 1; - } - if (self->mirror_y && y >= self->half_height) { - y = self->height - y - 1; - } - uint16_t start_x = self->data[2 * y]; - uint16_t end_x = self->data[2 * y + 1]; - if (x < start_x || x > end_x) { - return 0; - } - return 1; -} - -displayio_area_t *displayio_shape_get_refresh_areas(displayio_shape_t *self, displayio_area_t *tail) { - if (self->dirty_area.x1 == self->dirty_area.x2) { - return tail; - } - self->dirty_area.next = tail; - return &self->dirty_area; -} - -void displayio_shape_finish_refresh(displayio_shape_t *self) { - self->dirty_area.x1 = 0; - self->dirty_area.x2 = 0; -} diff --git a/shared-module/displayio/Shape.h b/shared-module/displayio/Shape.h deleted file mode 100644 index 20ee182023f..00000000000 --- a/shared-module/displayio/Shape.h +++ /dev/null @@ -1,28 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include -#include - -#include "py/obj.h" -#include "shared-module/displayio/area.h" - -typedef struct { - mp_obj_base_t base; - uint16_t width; - uint16_t height; - uint16_t half_width; - uint16_t half_height; - uint16_t *data; - bool mirror_x; - bool mirror_y; - displayio_area_t dirty_area; -} displayio_shape_t; - -void displayio_shape_finish_refresh(displayio_shape_t *self); -displayio_area_t *displayio_shape_get_refresh_areas(displayio_shape_t *self, displayio_area_t *tail); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index f3444241b3c..c1309ee0972 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -10,9 +10,11 @@ #include "shared-bindings/displayio/__init__.h" #include "shared/runtime/interrupt_char.h" +#include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/busio/I2C.h" +#include "shared-bindings/busio/SPI.h" #include "shared-bindings/displayio/Bitmap.h" #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/Palette.h" @@ -40,6 +42,13 @@ #include "shared-module/aurora_epaper/aurora_framebuffer.h" #endif +#if CIRCUITPY_MIPIDSI +#include "shared-bindings/mipidsi/Display.h" +#endif +#if CIRCUITPY_ZEPHYR_DISPLAY +#include "bindings/zephyr_display/Display.h" +#endif + #ifdef BOARD_USE_INTERNAL_SPI #include "supervisor/spi_flash_api.h" #endif @@ -63,7 +72,7 @@ displayio_buffer_transform_t null_transform = { .transpose_xy = false }; -#if CIRCUITPY_RGBMATRIX || CIRCUITPY_IS31FL3741 || CIRCUITPY_VIDEOCORE || CIRCUITPY_PICODVI +#if CIRCUITPY_RGBMATRIX || CIRCUITPY_IS31FL3741 || CIRCUITPY_VIDEOCORE || CIRCUITPY_PICODVI || CIRCUITPY_MIPIDSI static bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display_base.type == &framebufferio_framebufferdisplay_type) { @@ -106,6 +115,10 @@ void displayio_background(void) { } else if (display_type == &epaperdisplay_epaperdisplay_type) { epaperdisplay_epaperdisplay_background(&displays[i].epaper_display); #endif + #if CIRCUITPY_ZEPHYR_DISPLAY + } else if (display_type == &zephyr_display_display_type) { + zephyr_display_display_background(&displays[i].zephyr_display); + #endif } } @@ -136,10 +149,17 @@ static void common_hal_displayio_release_displays_impl(bool keep_primary) { } else if (display_type == &framebufferio_framebufferdisplay_type) { release_framebufferdisplay(&displays[i].framebuffer_display); #endif + #if CIRCUITPY_ZEPHYR_DISPLAY + } else if (display_type == &zephyr_display_display_type) { + release_zephyr_display(&displays[i].zephyr_display); + #endif } displays[i].display_base.type = &mp_type_NoneType; } for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (i == primary_display_number) { + continue; + } mp_const_obj_t bus_type = display_buses[i].bus_base.type; if (bus_type == NULL || bus_type == &mp_type_NoneType) { continue; @@ -179,11 +199,21 @@ static void common_hal_displayio_release_displays_impl(bool keep_primary) { } else if (bus_type == &picodvi_framebuffer_type) { common_hal_picodvi_framebuffer_deinit(&display_buses[i].picodvi); #endif + #if CIRCUITPY_MIPIDSI + } else if (bus_type == &mipidsi_display_type) { + common_hal_mipidsi_display_deinit(&display_buses[i].mipidsi); + #endif + #if CIRCUITPY_QSPIBUS + } else if (bus_type == &qspibus_qspibus_type) { + common_hal_qspibus_qspibus_deinit(&display_buses[i].qspi_bus); + #endif } display_buses[i].bus_base.type = &mp_type_NoneType; } - supervisor_stop_terminal(); + if (!keep_primary) { + supervisor_stop_terminal(); + } } void common_hal_displayio_release_displays(void) { @@ -191,8 +221,9 @@ void common_hal_displayio_release_displays(void) { } void reset_displays(void) { - // In CircuitPython 10, release secondary displays before doing anything else: - // common_hal_displayio_release_displays_impl(true); + // TODO: In CircuitPython 11, uncomment the call. + // Release secondary displays. + // common_hal_displayio_release_displays_impl(/*keep_primary*/ true); // The SPI buses used by FourWires may be allocated on the heap so we need to move them inline. for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { @@ -206,21 +237,12 @@ void reset_displays(void) { if (((size_t)fourwire->bus) < ((size_t)&display_buses) || ((size_t)fourwire->bus) > ((size_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT * sizeof(primary_display_bus_t))) { busio_spi_obj_t *original_spi = fourwire->bus; - #if CIRCUITPY_BOARD_SPI - // We don't need to move original_spi if it is a board.SPI object because it is - // statically allocated already. (Doing so would also make it impossible to reference in - // a subsequent VM run.) - if (common_hal_board_is_spi(original_spi)) { + if (!gc_ptr_on_heap(original_spi)) { continue; } - #endif - #ifdef BOARD_USE_INTERNAL_SPI - if (original_spi == (mp_obj_t)(&supervisor_flash_spi_bus)) { - continue; - } - #endif memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t)); fourwire->bus = &fourwire->inline_bus; + // Check for other display buses that use the same spi bus and swap them too. for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) { if (display_buses[j].fourwire_bus.base.type == &fourwire_fourwire_type && @@ -228,6 +250,8 @@ void reset_displays(void) { display_buses[j].fourwire_bus.bus = &fourwire->inline_bus; } } + // Mark the old SPI object so it is considered deinit. + common_hal_busio_spi_mark_deinit(original_spi); } #endif #if CIRCUITPY_I2CDISPLAYBUS @@ -237,14 +261,9 @@ void reset_displays(void) { if (((size_t)i2c->bus) < ((size_t)&display_buses) || ((size_t)i2c->bus) > ((size_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT * sizeof(primary_display_bus_t))) { busio_i2c_obj_t *original_i2c = i2c->bus; - #if CIRCUITPY_BOARD_I2C - // We don't need to move original_i2c if it is a board.I2C object because it is - // statically allocated already. (Doing so would also make it impossible to reference in - // a subsequent VM run.) - if (common_hal_board_is_i2c(original_i2c)) { + if (!gc_ptr_on_heap(original_i2c)) { continue; } - #endif memcpy(&i2c->inline_bus, original_i2c, sizeof(busio_i2c_obj_t)); i2c->bus = &i2c->inline_bus; // Check for other displays that use the same i2c bus and swap them too. @@ -273,22 +292,17 @@ void reset_displays(void) { if (((uint32_t)is31fb->is31fl3741->i2c) < ((uint32_t)&display_buses) || ((uint32_t)is31fb->is31fl3741->i2c) > ((uint32_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT)) { - #if CIRCUITPY_BOARD_I2C - // We don't need to move original_i2c if it is the board.I2C object because it is - // statically allocated already. (Doing so would also make it impossible to reference in - // a subsequent VM run.) - if (common_hal_board_is_i2c(is31fb->is31fl3741->i2c)) { - continue; - } - #endif - is31fl3741_IS31FL3741_obj_t *original_is31 = is31fb->is31fl3741; - memcpy(&is31fb->inline_is31fl3741, original_is31, sizeof(is31fl3741_IS31FL3741_obj_t)); - is31fb->is31fl3741 = &is31fb->inline_is31fl3741; + if (gc_ptr_on_heap(original_is31)) { + memcpy(&is31fb->inline_is31fl3741, original_is31, sizeof(is31fl3741_IS31FL3741_obj_t)); + is31fb->is31fl3741 = &is31fb->inline_is31fl3741; + } busio_i2c_obj_t *original_i2c = is31fb->is31fl3741->i2c; - memcpy(&is31fb->is31fl3741->inline_i2c, original_i2c, sizeof(busio_i2c_obj_t)); - is31fb->is31fl3741->i2c = &is31fb->is31fl3741->inline_i2c; + if (gc_ptr_on_heap(original_i2c)) { + memcpy(&is31fb->is31fl3741->inline_i2c, original_i2c, sizeof(busio_i2c_obj_t)); + is31fb->is31fl3741->i2c = &is31fb->is31fl3741->inline_i2c; + } } if (!any_display_uses_this_framebuffer(&is31fb->base)) { @@ -320,15 +334,20 @@ void reset_displays(void) { #endif #if CIRCUITPY_AURORA_EPAPER } else if (display_bus_type == &aurora_framebuffer_type) { - #if CIRCUITPY_BOARD_SPI aurora_epaper_framebuffer_obj_t *aurora = &display_buses[i].aurora_epaper; - if (common_hal_board_is_spi(aurora->bus)) { + if (gc_ptr_on_heap(aurora->bus)) { common_hal_aurora_epaper_framebuffer_set_free_bus(false); } - #endif // Set to None, gets deinit'd up by display_base display_buses[i].bus_base.type = &mp_type_NoneType; #endif + #if CIRCUITPY_MIPIDSI + } else if (display_bus_type == &mipidsi_display_type) { + mipidsi_display_obj_t *display = &display_buses[i].mipidsi; + if (!any_display_uses_this_framebuffer(&display->base)) { + common_hal_mipidsi_display_deinit(display); + } + #endif } else { // Not an active display bus. continue; @@ -354,6 +373,10 @@ void reset_displays(void) { } else if (display_type == &framebufferio_framebufferdisplay_type) { framebufferio_framebufferdisplay_reset(&displays[i].framebuffer_display); #endif + #if CIRCUITPY_ZEPHYR_DISPLAY + } else if (display_type == &zephyr_display_display_type) { + zephyr_display_display_reset(&displays[i].zephyr_display); + #endif } } } @@ -405,6 +428,10 @@ void displayio_gc_collect(void) { } else if (display_type == &epaperdisplay_epaperdisplay_type) { epaperdisplay_epaperdisplay_collect_ptrs(&displays[i].epaper_display); #endif + #if CIRCUITPY_ZEPHYR_DISPLAY + } else if (display_type == &zephyr_display_display_type) { + zephyr_display_display_collect_ptrs(&displays[i].zephyr_display); + #endif } } } diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index 29b8c64c972..eabff662782 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -38,6 +38,15 @@ #if CIRCUITPY_DOTCLOCKFRAMEBUFFER #include "common-hal/dotclockframebuffer/DotClockFramebuffer.h" #endif +#if CIRCUITPY_MIPIDSI +#include "shared-bindings/mipidsi/Display.h" +#endif +#if CIRCUITPY_QSPIBUS +#include "shared-bindings/qspibus/QSPIBus.h" +#endif +#if CIRCUITPY_ZEPHYR_DISPLAY +#include "bindings/zephyr_display/Display.h" +#endif // Port unique frame buffers. #if CIRCUITPY_VIDEOCORE #include "bindings/videocore/Framebuffer.h" @@ -81,6 +90,12 @@ typedef struct { #if CIRCUITPY_AURORA_EPAPER aurora_epaper_framebuffer_obj_t aurora_epaper; #endif + #if CIRCUITPY_MIPIDSI + mipidsi_display_obj_t mipidsi; + #endif + #if CIRCUITPY_QSPIBUS + qspibus_qspibus_obj_t qspi_bus; + #endif }; } primary_display_bus_t; @@ -96,6 +111,9 @@ typedef struct { #if CIRCUITPY_FRAMEBUFFERIO framebufferio_framebufferdisplay_obj_t framebuffer_display; #endif + #if CIRCUITPY_ZEPHYR_DISPLAY + zephyr_display_display_obj_t zephyr_display; + #endif }; } primary_display_t; diff --git a/shared-module/displayio/bus_core.c b/shared-module/displayio/bus_core.c index e01b9d9eef6..9b3fb426217 100644 --- a/shared-module/displayio/bus_core.c +++ b/shared-module/displayio/bus_core.c @@ -17,6 +17,9 @@ #if CIRCUITPY_PARALLELDISPLAYBUS #include "shared-bindings/paralleldisplaybus/ParallelBus.h" #endif +#if CIRCUITPY_QSPIBUS +#include "shared-bindings/qspibus/QSPIBus.h" +#endif #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/time/__init__.h" #include "shared-module/displayio/__init__.h" @@ -49,6 +52,8 @@ void displayio_display_bus_construct(displayio_display_bus_t *self, self->SH1107_addressing = SH1107_addressing; self->address_little_endian = address_little_endian; + self->flush = NULL; + #if CIRCUITPY_PARALLELDISPLAYBUS if (mp_obj_is_type(bus, ¶lleldisplaybus_parallelbus_type)) { self->bus_reset = common_hal_paralleldisplaybus_parallelbus_reset; @@ -79,17 +84,33 @@ void displayio_display_bus_construct(displayio_display_bus_t *self, self->collect_ptrs = common_hal_i2cdisplaybus_i2cdisplaybus_collect_ptrs; } else #endif + #if CIRCUITPY_QSPIBUS + if (mp_obj_is_type(bus, &qspibus_qspibus_type)) { + self->bus_reset = common_hal_qspibus_qspibus_reset; + self->bus_free = common_hal_qspibus_qspibus_bus_free; + self->begin_transaction = common_hal_qspibus_qspibus_begin_transaction; + self->send = common_hal_qspibus_qspibus_send; + self->end_transaction = common_hal_qspibus_qspibus_end_transaction; + self->flush = common_hal_qspibus_qspibus_flush; + self->collect_ptrs = common_hal_qspibus_qspibus_collect_ptrs; + } else + #endif { mp_raise_ValueError(MP_ERROR_TEXT("Unsupported display bus type")); } self->bus = bus; } +// This is just a hint, and is not a reliable result, since the bus could be grabbed in between this called +// and the attempt to use the bus. Use displayio_display_bus_begin_transaction(), which is atomic. bool displayio_display_bus_is_free(displayio_display_bus_t *self) { return !self->bus || self->bus_free(self->bus); } -bool displayio_display_bus_begin_transaction(displayio_display_bus_t *self) { +MP_WARN_UNUSED_RESULT bool displayio_display_bus_begin_transaction(displayio_display_bus_t *self) { + if (!self->bus) { + return false; + } mp_obj_base_t *bus_base = MP_OBJ_TO_PTR(self->bus); if (bus_base->type == &mp_type_NoneType) { return false; @@ -128,7 +149,9 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d } // Set column. - displayio_display_bus_begin_transaction(self); + if (!displayio_display_bus_begin_transaction(self)) { + return; + } uint8_t data[5]; data[0] = self->column_command; uint8_t data_length = 1; @@ -167,7 +190,9 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d if (self->set_current_column_command != NO_COMMAND) { uint8_t command = self->set_current_column_command; - displayio_display_bus_begin_transaction(self); + if (!displayio_display_bus_begin_transaction(self)) { + return; + } self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); // Only send the first half of data because it is the first coordinate. self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); @@ -176,7 +201,9 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d // Set row. - displayio_display_bus_begin_transaction(self); + if (!displayio_display_bus_begin_transaction(self)) { + return; + } data[0] = self->row_command; data_length = 1; if (!self->data_as_commands) { @@ -211,7 +238,9 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d if (self->set_current_row_command != NO_COMMAND) { uint8_t command = self->set_current_row_command; - displayio_display_bus_begin_transaction(self); + if (!displayio_display_bus_begin_transaction(self)) { + return; + } self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); // Only send the first half of data because it is the first coordinate. self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); @@ -219,6 +248,12 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d } } +void displayio_display_bus_flush(displayio_display_bus_t *self) { + if (self->flush != NULL) { + self->flush(self->bus); + } +} + void displayio_display_bus_collect_ptrs(displayio_display_bus_t *self) { self->collect_ptrs(self->bus); } diff --git a/shared-module/displayio/bus_core.h b/shared-module/displayio/bus_core.h index 838454c92e6..75d03d7f284 100644 --- a/shared-module/displayio/bus_core.h +++ b/shared-module/displayio/bus_core.h @@ -21,6 +21,7 @@ typedef struct { display_bus_begin_transaction begin_transaction; display_bus_send send; display_bus_end_transaction end_transaction; + display_bus_flush flush; display_bus_collect_ptrs collect_ptrs; uint16_t ram_width; uint16_t ram_height; @@ -49,6 +50,10 @@ void displayio_display_bus_end_transaction(displayio_display_bus_t *self); void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area); +// Drain any pending asynchronous transfers on the bus. +// No-op for synchronous buses (FourWire, I2C, ParallelBus). +void displayio_display_bus_flush(displayio_display_bus_t *self); + void release_display_bus(displayio_display_bus_t *self); void displayio_display_bus_collect_ptrs(displayio_display_bus_t *self); diff --git a/shared-module/emmcio/__init__.c b/shared-module/emmcio/__init__.c new file mode 100644 index 00000000000..075451a6ebc --- /dev/null +++ b/shared-module/emmcio/__init__.c @@ -0,0 +1,104 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-module/emmcio/__init__.h" + +#if CIRCUITPY_EMMC_USB + +#include "py/mpstate.h" + +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "lib/oofatfs/ff.h" + +#include "supervisor/filesystem.h" +#include "supervisor/shared/safe_mode.h" +#include "supervisor/shared/settings.h" + +#include "shared-bindings/microcontroller/Pin.h" + +#include "common-hal/emmcio/EMMC.h" + +#if !defined(DEFAULT_EMMC_CLOCK) || !defined(DEFAULT_EMMC_COMMAND) || !defined(DEFAULT_EMMC_DATA) +#error "CIRCUITPY_EMMC_USB needs DEFAULT_EMMC_CLOCK, DEFAULT_EMMC_COMMAND and DEFAULT_EMMC_DATA in mpconfigboard.h" +#endif + +// RST_n and the I/O rail gate are optional: a board that hard-wires either one +// simply does not define it. +#ifndef DEFAULT_EMMC_RESET +#define DEFAULT_EMMC_RESET NULL +#endif +#ifndef DEFAULT_EMMC_VCCQ +#define DEFAULT_EMMC_VCCQ NULL +#endif + + +static mp_vfs_mount_t _emmc_vfs; +static fs_user_mount_t _emmc_usermount; + +static bool _tried; + +#define AUTOMOUNT_BUDGET_US 5000000u + +static void automount_give_up(void) { + common_hal_emmcio_emmc_clear_deadline(); + // Leave the card powered down and the pins released + emmcio_automount_abandon(); +} + +void automount_emmc(void) { + if (_tried) { + return; + } + _tried = true; + + if (get_safe_mode() != SAFE_MODE_NONE) { + return; + } + + bool enabled = true; + (void)settings_get_bool("CIRCUITPY_EMMC_USB", &enabled); + if (!enabled) { + return; + } + + common_hal_emmcio_emmc_set_deadline(AUTOMOUNT_BUDGET_US); + + mp_obj_t dev = emmcio_automount_construct(DEFAULT_EMMC_CLOCK, DEFAULT_EMMC_COMMAND, + DEFAULT_EMMC_DATA, DEFAULT_EMMC_RESET, DEFAULT_EMMC_VCCQ, true, true); + if (dev == MP_OBJ_NULL) { + automount_give_up(); + return; + } + + fs_user_mount_t *vfs = &_emmc_usermount; + vfs->base.type = &mp_fat_vfs_type; + vfs->fatfs.drv = vfs; + // Initialise underlying block device. + vfs->blockdev.block_size = FF_MIN_SS; + mp_vfs_blockdev_init(&vfs->blockdev, dev); + + if (f_mount(&vfs->fatfs) != FR_OK) { + automount_give_up(); + return; + } + + // Same as CIRCUITPY: while a host has the drive, the host owns writing. + filesystem_set_concurrent_write_protection(vfs, true); + filesystem_set_writable_by_usb(vfs, true); + + mp_vfs_mount_t *emmc_vfs = &_emmc_vfs; + emmc_vfs->str = CIRCUITPY_EMMC_MOUNT_PATH; + emmc_vfs->len = sizeof(CIRCUITPY_EMMC_MOUNT_PATH) - 1; + emmc_vfs->obj = MP_OBJ_FROM_PTR(&_emmc_usermount); + emmc_vfs->next = MP_STATE_VM(vfs_mount_table); + MP_STATE_VM(vfs_mount_table) = emmc_vfs; + + // The budget covers bring-up and the mount only + common_hal_emmcio_emmc_clear_deadline(); +} + +#endif // CIRCUITPY_EMMC_USB diff --git a/shared-module/emmcio/__init__.h b/shared-module/emmcio/__init__.h new file mode 100644 index 00000000000..5bef585e438 --- /dev/null +++ b/shared-module/emmcio/__init__.h @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#if CIRCUITPY_EMMC_USB + +#ifndef CIRCUITPY_EMMC_MOUNT_PATH +#define CIRCUITPY_EMMC_MOUNT_PATH "/sd" +#endif + +void automount_emmc(void); + +bool emmcio_is_automounted(void); + +#else + +#include + +static inline bool emmcio_is_automounted(void) { + return false; +} + +#endif diff --git a/shared-module/epaperdisplay/EPaperDisplay.c b/shared-module/epaperdisplay/EPaperDisplay.c index 556db6ae220..d34be9d5c7c 100644 --- a/shared-module/epaperdisplay/EPaperDisplay.c +++ b/shared-module/epaperdisplay/EPaperDisplay.c @@ -153,7 +153,10 @@ static void send_command_sequence(epaperdisplay_epaperdisplay_obj_t *self, data_size = ((data_size & ~DELAY) << 8) + *(cmd + 2); data = cmd + 3; } - displayio_display_bus_begin_transaction(&self->bus); + while (!displayio_display_bus_begin_transaction(&self->bus) && + !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + } self->bus.send(self->bus.bus, DISPLAY_COMMAND, self->chip_select, cmd, 1); self->bus.send(self->bus.bus, DISPLAY_DATA, self->chip_select, data, data_size); displayio_display_bus_end_transaction(&self->bus); @@ -191,6 +194,10 @@ static void epaperdisplay_epaperdisplay_start_refresh(epaperdisplay_epaperdispla // Can't acquire display bus; skip updating this display. Try next display. return; } + if (!displayio_display_core_start_refresh(&self->core)) { + // Refresh on this display already in progress. + return; + } // run start sequence self->bus.bus_reset(self->bus.bus); @@ -201,7 +208,6 @@ static void epaperdisplay_epaperdisplay_start_refresh(epaperdisplay_epaperdispla if (mp_hal_is_interrupted()) { return; } - displayio_display_core_start_refresh(&self->core); } uint32_t common_hal_epaperdisplay_epaperdisplay_get_time_to_refresh(epaperdisplay_epaperdisplay_obj_t *self) { @@ -308,7 +314,10 @@ static bool epaperdisplay_epaperdisplay_refresh_area(epaperdisplay_epaperdisplay if (pass == 1) { write_command = self->write_color_ram_command; } - displayio_display_bus_begin_transaction(&self->bus); + if (!displayio_display_bus_begin_transaction(&self->bus)) { + // Display bus not available now. + return false; + } self->bus.send(self->bus.bus, DISPLAY_COMMAND, self->chip_select, &write_command, 1); displayio_display_bus_end_transaction(&self->bus); @@ -385,7 +394,9 @@ static bool _clean_area(epaperdisplay_epaperdisplay_obj_t *self) { memset(buffer, 0x77, width / 2); uint8_t write_command = self->write_black_ram_command; - displayio_display_bus_begin_transaction(&self->bus); + if (displayio_display_bus_begin_transaction(&self->bus)) { + return false; + } self->bus.send(self->bus.bus, DISPLAY_COMMAND, self->chip_select, &write_command, 1); displayio_display_bus_end_transaction(&self->bus); diff --git a/shared-module/fourwire/FourWire.c b/shared-module/fourwire/FourWire.c index 0a168fa1563..d87cb0cec0f 100644 --- a/shared-module/fourwire/FourWire.c +++ b/shared-module/fourwire/FourWire.c @@ -11,13 +11,15 @@ #include "py/gc.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" +#include "supervisor/port.h" void common_hal_fourwire_fourwire_construct(fourwire_fourwire_obj_t *self, - busio_spi_obj_t *spi, const mcu_pin_obj_t *command, - const mcu_pin_obj_t *chip_select, const mcu_pin_obj_t *reset, uint32_t baudrate, + busio_spi_obj_t *spi, mp_obj_t command, + mp_obj_t chip_select, mp_obj_t reset, uint32_t baudrate, uint8_t polarity, uint8_t phase) { self->bus = spi; @@ -27,31 +29,27 @@ void common_hal_fourwire_fourwire_construct(fourwire_fourwire_obj_t *self, self->polarity = polarity; self->phase = phase; + // Allocate the pins in the same place as self. + bool use_port_allocation = !gc_alloc_possible() || !gc_ptr_on_heap(self); - self->command.base.type = &mp_type_NoneType; - if (command != NULL) { - self->command.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->command, command); - common_hal_digitalio_digitalinout_switch_to_output(&self->command, true, DRIVE_MODE_PUSH_PULL); + self->command = digitalinout_protocol_from_pin(command, MP_QSTR_command, true, use_port_allocation, &self->own_command); + if (self->command != mp_const_none) { + digitalinout_protocol_switch_to_output(self->command, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(command); } - self->reset.base.type = &mp_type_NoneType; - if (reset != NULL) { - self->reset.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->reset, reset); - common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); + + self->reset = digitalinout_protocol_from_pin(reset, MP_QSTR_reset, true, use_port_allocation, &self->own_reset); + if (self->reset != mp_const_none) { + digitalinout_protocol_switch_to_output(self->reset, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(reset); common_hal_fourwire_fourwire_reset(self); } - self->chip_select.base.type = &mp_type_NoneType; - if (chip_select != NULL) { - self->chip_select.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select); - common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL); + self->chip_select = digitalinout_protocol_from_pin(chip_select, MP_QSTR_chip_select, true, use_port_allocation, &self->own_chip_select); + if (self->chip_select != mp_const_none) { + digitalinout_protocol_switch_to_output(self->chip_select, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(chip_select); } - } void common_hal_fourwire_fourwire_deinit(fourwire_fourwire_obj_t *self) { @@ -59,19 +57,33 @@ void common_hal_fourwire_fourwire_deinit(fourwire_fourwire_obj_t *self) { common_hal_busio_spi_deinit(self->bus); } - common_hal_reset_pin(self->command.pin); - common_hal_reset_pin(self->chip_select.pin); - common_hal_reset_pin(self->reset.pin); + // Only deinit and free the pins if we own them + if (self->command != mp_const_none && self->own_command) { + digitalinout_protocol_deinit(self->command); + circuitpy_free_obj(self->command); + } + if (self->chip_select != mp_const_none && self->own_chip_select) { + digitalinout_protocol_deinit(self->chip_select); + circuitpy_free_obj(self->chip_select); + } + if (self->reset != mp_const_none && self->own_reset) { + digitalinout_protocol_deinit(self->reset); + circuitpy_free_obj(self->reset); + } } bool common_hal_fourwire_fourwire_reset(mp_obj_t obj) { fourwire_fourwire_obj_t *self = MP_OBJ_TO_PTR(obj); - if (self->reset.base.type == &mp_type_NoneType) { + if (self->reset == mp_const_none) { + return false; + } + if (digitalinout_protocol_set_value(self->reset, false) != 0) { return false; } - common_hal_digitalio_digitalinout_set_value(&self->reset, false); common_hal_mcu_delay_us(1000); - common_hal_digitalio_digitalinout_set_value(&self->reset, true); + if (digitalinout_protocol_set_value(self->reset, true) != 0) { + return false; + } common_hal_mcu_delay_us(1000); return true; } @@ -92,16 +104,23 @@ bool common_hal_fourwire_fourwire_begin_transaction(mp_obj_t obj) { } common_hal_busio_spi_configure(self->bus, self->frequency, self->polarity, self->phase, 8); - if (self->chip_select.base.type != &mp_type_NoneType) { - common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + if (self->chip_select != mp_const_none) { + // IO Expander CS can fail due to an I2C lock. + if (digitalinout_protocol_set_value(self->chip_select, false) != 0) { + common_hal_busio_spi_unlock(self->bus); + return false; + } } return true; } void common_hal_fourwire_fourwire_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length) { + if (data_length == 0) { + return; + } fourwire_fourwire_obj_t *self = MP_OBJ_TO_PTR(obj); - if (self->command.base.type == &mp_type_NoneType) { + if (self->command == mp_const_none) { // When the data/command pin is not specified, we simulate a 9-bit SPI mode, by // adding a data/command bit to every byte, and then splitting the resulting data back // into 8-bit chunks for transmission. If the length of the data being transmitted @@ -133,24 +152,24 @@ void common_hal_fourwire_fourwire_send(mp_obj_t obj, display_byte_type_t data_ty if (bits > 0) { buffer = buffer << (8 - bits); common_hal_busio_spi_write(self->bus, &buffer, 1); - if (self->chip_select.base.type != &mp_type_NoneType) { + if (self->chip_select != mp_const_none) { // toggle CS to discard superfluous bits - common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); + digitalinout_protocol_set_value(self->chip_select, true); common_hal_mcu_delay_us(1); - common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + digitalinout_protocol_set_value(self->chip_select, false); } } } else { - common_hal_digitalio_digitalinout_set_value(&self->command, data_type == DISPLAY_DATA); + digitalinout_protocol_set_value(self->command, data_type == DISPLAY_DATA); if (chip_select == CHIP_SELECT_TOGGLE_EVERY_BYTE) { // Toggle chip select after each command byte in case the display driver // IC latches commands based on it. for (size_t i = 0; i < data_length; i++) { common_hal_busio_spi_write(self->bus, &data[i], 1); - if (self->chip_select.base.type != &mp_type_NoneType) { - common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); + if (self->chip_select != mp_const_none) { + digitalinout_protocol_set_value(self->chip_select, true); common_hal_mcu_delay_us(1); - common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + digitalinout_protocol_set_value(self->chip_select, false); } } } else { @@ -161,8 +180,8 @@ void common_hal_fourwire_fourwire_send(mp_obj_t obj, display_byte_type_t data_ty void common_hal_fourwire_fourwire_end_transaction(mp_obj_t obj) { fourwire_fourwire_obj_t *self = MP_OBJ_TO_PTR(obj); - if (self->chip_select.base.type != &mp_type_NoneType) { - common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); + if (self->chip_select != mp_const_none) { + digitalinout_protocol_set_value(self->chip_select, true); } common_hal_busio_spi_unlock(self->bus); } diff --git a/shared-module/fourwire/FourWire.h b/shared-module/fourwire/FourWire.h index 629a426b3b0..c239a3dfde3 100644 --- a/shared-module/fourwire/FourWire.h +++ b/shared-module/fourwire/FourWire.h @@ -6,6 +6,8 @@ #pragma once +#include + #include "common-hal/busio/SPI.h" #include "common-hal/digitalio/DigitalInOut.h" #include "shared-module/displayio/Group.h" @@ -14,10 +16,13 @@ typedef struct { mp_obj_base_t base; busio_spi_obj_t *bus; busio_spi_obj_t inline_bus; - digitalio_digitalinout_obj_t command; - digitalio_digitalinout_obj_t chip_select; - digitalio_digitalinout_obj_t reset; + mp_obj_t command; + mp_obj_t chip_select; + mp_obj_t reset; uint32_t frequency; uint8_t polarity; uint8_t phase; + bool own_command; + bool own_chip_select; + bool own_reset; } fourwire_fourwire_obj_t; diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 4ba2b132581..8116f4b0347 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -217,7 +217,10 @@ static void _refresh_display(framebufferio_framebufferdisplay_obj_t *self) { if (!self->bufinfo.buf) { return; } - displayio_display_core_start_refresh(&self->core); + if (!displayio_display_core_start_refresh(&self->core)) { + // Refresh on this display already in progress. + return; + } const displayio_area_t *current_area = _get_refresh_areas(self); if (current_area) { bool transposed = (self->core.rotation == 90 || self->core.rotation == 270); diff --git a/shared-module/gifio/GifWriter.c b/shared-module/gifio/GifWriter.c index bf0b33836cf..d875a844d9f 100644 --- a/shared-module/gifio/GifWriter.c +++ b/shared-module/gifio/GifWriter.c @@ -18,6 +18,12 @@ #define BLOCK_SIZE (126) // (2^7) - 2 // (DO NOT CHANGE!) +#define GIF_HEADER_SIZE (13 + 128 * 3 + 19) +// Each frame writes a 19 byte header ahead of the block data (8 for the +// graphic control extension, 11 for the image descriptor) and a 3 byte end +// code after it. +#define GIF_FRAME_OVERHEAD (19 + 3) + static void handle_error(gifio_gifwriter_t *self) { if (self->error != 0) { mp_raise_OSError(self->error); @@ -68,8 +74,8 @@ void shared_module_gifio_gifwriter_construct(gifio_gifwriter_t *self, mp_obj_t * self->dither = dither; self->own_file = own_file; - size_t nblocks = (width * height + 125) / 126; - self->size = nblocks * 128 + 4; + size_t nblocks = (width * height + BLOCK_SIZE - 1) / BLOCK_SIZE; + self->size = MAX(GIF_HEADER_SIZE, nblocks * 128 + GIF_FRAME_OVERHEAD); self->data = m_malloc_without_collect(self->size); self->cur = 0; self->error = 0; @@ -155,6 +161,15 @@ static const uint8_t g_bayer[4][4] = { }; void shared_module_gifio_gifwriter_add_frame(gifio_gifwriter_t *self, const mp_buffer_info_t *bufinfo, int16_t delay) { + int pixel_count = self->width * self->height; + int blocks = (pixel_count + BLOCK_SIZE - 1) / BLOCK_SIZE; + + size_t needed_bytes = (self->colorspace == DISPLAYIO_COLORSPACE_L8) + ? (size_t)pixel_count + : 2u * (size_t)pixel_count; + mp_get_index(&mp_type_memoryview, bufinfo->len, + MP_OBJ_NEW_SMALL_INT(needed_bytes - 1), false); + if (delay) { write_data(self, (uint8_t []) {'!', 0xF9, 0x04, 0x04}, 4); write_word(self, delay); @@ -167,13 +182,9 @@ void shared_module_gifio_gifwriter_add_frame(gifio_gifwriter_t *self, const mp_b write_word(self, self->height); write_data(self, (uint8_t []) {0x00, 0x07}, 2); // 7-bits - int pixel_count = self->width * self->height; - int blocks = (pixel_count + BLOCK_SIZE - 1) / BLOCK_SIZE; - uint8_t *data = self->data + self->cur; if (self->colorspace == DISPLAYIO_COLORSPACE_L8) { - mp_get_index(&mp_type_memoryview, bufinfo->len, MP_OBJ_NEW_SMALL_INT(pixel_count - 1), false); uint8_t *pixels = bufinfo->buf; for (int i = 0; i < blocks; i++) { @@ -187,7 +198,6 @@ void shared_module_gifio_gifwriter_add_frame(gifio_gifwriter_t *self, const mp_b } } } else if (!self->dither) { - mp_get_index(&mp_type_memoryview, bufinfo->len, MP_OBJ_NEW_SMALL_INT(2 * pixel_count - 1), false); uint16_t *pixels = bufinfo->buf; for (int i = 0; i < blocks; i++) { @@ -208,7 +218,6 @@ void shared_module_gifio_gifwriter_add_frame(gifio_gifwriter_t *self, const mp_b } } } else { - mp_get_index(&mp_type_memoryview, bufinfo->len, MP_OBJ_NEW_SMALL_INT(2 * pixel_count - 1), false); uint16_t *pixels = bufinfo->buf; int x = 0, y = 0; diff --git a/shared-module/hashlib/Hash.c b/shared-module/hashlib/Hash.c index a454966d993..4b46198ac5d 100644 --- a/shared-module/hashlib/Hash.c +++ b/shared-module/hashlib/Hash.c @@ -7,32 +7,23 @@ #include "shared-bindings/hashlib/Hash.h" #include "shared-module/hashlib/__init__.h" -#include "mbedtls/ssl.h" +#include "psa/crypto.h" void common_hal_hashlib_hash_update(hashlib_hash_obj_t *self, const uint8_t *data, size_t datalen) { - if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { - mbedtls_sha1_update_ret(&self->sha1, data, datalen); - return; - } + psa_hash_update(&self->hash_op, data, datalen); } void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, size_t datalen) { if (datalen < common_hal_hashlib_hash_get_digest_size(self)) { return; } - if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { - // We copy the sha1 state so we can continue to update if needed or get - // the digest a second time. - mbedtls_sha1_context copy; - mbedtls_sha1_clone(©, &self->sha1); - mbedtls_sha1_finish_ret(&self->sha1, data); - mbedtls_sha1_clone(&self->sha1, ©); - } + // Clone the operation so we can continue to update or get digest again. + psa_hash_operation_t clone = PSA_HASH_OPERATION_INIT; + psa_hash_clone(&self->hash_op, &clone); + size_t hash_len; + psa_hash_finish(&clone, data, datalen, &hash_len); } size_t common_hal_hashlib_hash_get_digest_size(hashlib_hash_obj_t *self) { - if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { - return 20; - } - return 0; + return PSA_HASH_LENGTH(self->hash_alg); } diff --git a/shared-module/hashlib/Hash.h b/shared-module/hashlib/Hash.h index ccc82037cb7..961335eea7a 100644 --- a/shared-module/hashlib/Hash.h +++ b/shared-module/hashlib/Hash.h @@ -6,13 +6,10 @@ #pragma once -#include "mbedtls/sha1.h" +#include "psa/crypto.h" typedef struct { mp_obj_base_t base; - union { - mbedtls_sha1_context sha1; - }; - // Of MBEDTLS_SSL_HASH_* - uint8_t hash_type; + psa_hash_operation_t hash_op; + psa_algorithm_t hash_alg; } hashlib_hash_obj_t; diff --git a/shared-module/hashlib/__init__.c b/shared-module/hashlib/__init__.c index be3a9f18959..50477a4dc2d 100644 --- a/shared-module/hashlib/__init__.c +++ b/shared-module/hashlib/__init__.c @@ -7,15 +7,22 @@ #include "shared-bindings/hashlib/__init__.h" #include "shared-module/hashlib/__init__.h" -#include "mbedtls/ssl.h" - +#include "psa/crypto.h" bool common_hal_hashlib_new(hashlib_hash_obj_t *self, const char *algorithm) { if (strcmp(algorithm, "sha1") == 0) { - self->hash_type = MBEDTLS_SSL_HASH_SHA1; - mbedtls_sha1_init(&self->sha1); - mbedtls_sha1_starts_ret(&self->sha1); - return true; + self->hash_alg = PSA_ALG_SHA_1; + } else if (strcmp(algorithm, "sha256") == 0) { + self->hash_alg = PSA_ALG_SHA_256; + } else { + return false; + } + // PSA has to be initialized before any of it is used. OK to psa_crypto_init() + // multiple times. On espressif, ESP-IDF has already done this during its own system + // init and this call is a no-op. + if (psa_crypto_init() != PSA_SUCCESS) { + return false; } - return false; + self->hash_op = psa_hash_operation_init(); + return psa_hash_setup(&self->hash_op, self->hash_alg) == PSA_SUCCESS; } diff --git a/shared-module/hashlib/__init__.h b/shared-module/hashlib/__init__.h index f72882a1c03..2088d352f20 100644 --- a/shared-module/hashlib/__init__.h +++ b/shared-module/hashlib/__init__.h @@ -6,11 +6,3 @@ // SPDX-License-Identifier: MIT #pragma once - -#include "mbedtls/version.h" - -#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 diff --git a/shared-module/i2cioexpander/IOExpander.c b/shared-module/i2cioexpander/IOExpander.c new file mode 100644 index 00000000000..f4aac5c0532 --- /dev/null +++ b/shared-module/i2cioexpander/IOExpander.c @@ -0,0 +1,196 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/i2cioexpander/IOExpander.h" +#include "shared-bindings/i2cioexpander/IOPin.h" + +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/busio/I2C.h" +#include "supervisor/port.h" + +void common_hal_i2cioexpander_ioexpander_construct( + i2cioexpander_ioexpander_obj_t *self, + mp_obj_t i2c, + uint8_t address, + uint8_t num_pins, + uint16_t set_value_reg, + uint16_t get_value_reg, + uint16_t set_direction_reg) { + + // Store the I2C bus + self->i2c = (busio_i2c_obj_t *)i2c; + self->address = address; + self->num_pins = num_pins; + self->output_value = 0; + self->output_mask = 0; + + // Parse optional register addresses + self->has_set_value = (set_value_reg != NO_REGISTER); + if (self->has_set_value) { + self->set_value_reg = set_value_reg; + } + + self->has_get_value = (get_value_reg != NO_REGISTER); + if (self->has_get_value) { + self->get_value_reg = get_value_reg; + } + + self->has_set_direction = (set_direction_reg != NO_REGISTER); + if (self->has_set_direction) { + self->set_direction_reg = set_direction_reg; + } + + bool allocate_in_port_heap = !gc_alloc_possible() || !gc_ptr_on_heap(self); + + // Allocate tuple with space for pin objects in items[] + size_t tuple_size = offsetof(mp_obj_tuple_t, items) + sizeof(mp_obj_t) * num_pins; + mp_obj_tuple_t *pins_tuple = allocate_in_port_heap ? port_malloc(tuple_size, false) : m_malloc(tuple_size); + pins_tuple->base.type = &mp_type_tuple; + pins_tuple->len = num_pins; + + // Create IOPin objects for each pin + size_t pin_size = sizeof(i2cioexpander_iopin_obj_t); + for (uint8_t i = 0; i < num_pins; i++) { + i2cioexpander_iopin_obj_t *pin = allocate_in_port_heap ? port_malloc(pin_size, false) : m_malloc(pin_size); + pin->base.type = &i2cioexpander_iopin_type; + i2cioexpander_iopin_construct(pin, self, i); + pins_tuple->items[i] = MP_OBJ_FROM_PTR(pin); + } + + self->pins = pins_tuple; +} + +void common_hal_i2cioexpander_ioexpander_deinit(i2cioexpander_ioexpander_obj_t *self) { + if (gc_alloc_possible() && !gc_ptr_on_heap(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot deinitialize board IOExpander")); + } + for (uint8_t i = 0; i < self->num_pins; i++) { + circuitpy_free_obj(self->pins->items[i]); + } + circuitpy_free_obj(self->pins); + self->i2c = NULL; +} + +bool common_hal_i2cioexpander_ioexpander_deinited(i2cioexpander_ioexpander_obj_t *self) { + return self->i2c == NULL; +} + +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_get_input_value(i2cioexpander_ioexpander_obj_t *self, size_t *value) { + uint8_t buffer[2]; + uint8_t num_bytes = (self->num_pins > 8) ? 2 : 1; + + while (!common_hal_busio_i2c_try_lock(self->i2c)) { + RUN_BACKGROUND_TASKS; + } + + mp_negative_errno_t result; + if (self->has_get_value) { + // Send register address then read + result = common_hal_busio_i2c_write_read( + self->i2c, self->address, &self->get_value_reg, 1, buffer, num_bytes); + } else { + // Read directly without register address + result = common_hal_busio_i2c_read(self->i2c, self->address, buffer, num_bytes); + } + common_hal_busio_i2c_unlock(self->i2c); + + if (result != 0) { + return result; + } + + if (num_bytes == 2) { + *value = buffer[0] | (buffer[1] << 8); + } else { + *value = buffer[0]; + } + return 0; +} + +void common_hal_i2cioexpander_ioexpander_get_output_value(i2cioexpander_ioexpander_obj_t *self, size_t *value) { + *value = self->output_value; +} + +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_set_output_value(i2cioexpander_ioexpander_obj_t *self, size_t value) { + uint8_t buffer[5]; + uint8_t num_bytes = 0; + + // Add register address if provided + if (self->has_set_value) { + buffer[num_bytes++] = self->set_value_reg; + } + + size_t current_value = self->output_value; + if (current_value == value) { + return 0; + } + size_t diff = current_value ^ value; + + // Add value byte(s) but only if a high bit is changed + buffer[num_bytes++] = value & 0xFF; + if (self->num_pins > 8 && (diff >> 8) != 0) { + buffer[num_bytes++] = (value >> 8) & 0xFF; + } + if (self->num_pins > 16 && (diff >> 16) != 0) { + buffer[num_bytes++] = (value >> 16) & 0xFF; + } + if (self->num_pins > 24 && (diff >> 24) != 0) { + buffer[num_bytes++] = (value >> 24) & 0xFF; + } + + if (!common_hal_busio_i2c_try_lock(self->i2c)) { + return -MP_EBUSY; + } + + mp_negative_errno_t result = common_hal_busio_i2c_write(self->i2c, self->address, buffer, num_bytes); + common_hal_busio_i2c_unlock(self->i2c); + if (result == 0) { + self->output_value = value; + } + return result; +} + +void common_hal_i2cioexpander_ioexpander_get_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t *mask) { + *mask = self->output_mask; +} + +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_set_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t mask) { + self->output_mask = mask; + + // Only write to device if direction register is provided + if (!self->has_set_direction) { + return 0; + } + + uint8_t buffer[3]; + uint8_t num_bytes = 0; + + // Add register address + buffer[num_bytes++] = self->set_direction_reg; + + // Invert the mask so 0 indicates output. We taken 1 for output to match output enable. + size_t inverted_mask = ~mask; + + // Add mask byte(s) + buffer[num_bytes++] = inverted_mask & 0xFF; + if (self->num_pins > 8) { + buffer[num_bytes++] = (inverted_mask >> 8) & 0xFF; + } + + if (!common_hal_busio_i2c_try_lock(self->i2c)) { + return -MP_EBUSY; + } + + mp_negative_errno_t result = common_hal_busio_i2c_write(self->i2c, self->address, buffer, num_bytes); + common_hal_busio_i2c_unlock(self->i2c); + return result; +} + +mp_obj_t common_hal_i2cioexpander_ioexpander_get_pins(i2cioexpander_ioexpander_obj_t *self) { + return MP_OBJ_FROM_PTR(self->pins); +} diff --git a/shared-module/i2cioexpander/IOExpander.h b/shared-module/i2cioexpander/IOExpander.h new file mode 100644 index 00000000000..e225bfc75c7 --- /dev/null +++ b/shared-module/i2cioexpander/IOExpander.h @@ -0,0 +1,41 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" +#include "py/objtuple.h" +#include "shared-bindings/busio/I2C.h" + +#define NO_REGISTER (0x100) + +typedef struct { + mp_obj_base_t base; + busio_i2c_obj_t *i2c; + uint8_t address; + uint8_t num_pins; + uint8_t set_value_reg; + uint8_t get_value_reg; + uint8_t set_direction_reg; + size_t output_value; + size_t output_mask; + bool has_set_value; + bool has_get_value; + bool has_set_direction; + mp_obj_tuple_t *pins; +} i2cioexpander_ioexpander_obj_t; + +void common_hal_i2cioexpander_ioexpander_construct( + i2cioexpander_ioexpander_obj_t *self, + mp_obj_t i2c, + uint8_t address, + uint8_t num_pins, + uint16_t set_value_reg, + uint16_t get_value_reg, + uint16_t set_direction_reg); diff --git a/shared-module/i2cioexpander/IOPin.c b/shared-module/i2cioexpander/IOPin.c new file mode 100644 index 00000000000..04642623b3d --- /dev/null +++ b/shared-module/i2cioexpander/IOPin.c @@ -0,0 +1,148 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/i2cioexpander/IOPin.h" +#include "shared-bindings/i2cioexpander/IOExpander.h" + +#include "py/runtime.h" + +mp_negative_errno_t i2cioexpander_iopin_construct( + i2cioexpander_iopin_obj_t *self, + i2cioexpander_ioexpander_obj_t *expander, + uint8_t pin_number) { + + if (pin_number >= expander->num_pins) { + return MP_EINVAL; // Reusing this for "invalid pin" + } + + self->expander = expander; + self->pin_number = pin_number; + self->direction = DIRECTION_INPUT; + + return 0; +} + +void common_hal_i2cioexpander_iopin_deinit(i2cioexpander_iopin_obj_t *self) { + // Switch to input on deinit. + common_hal_i2cioexpander_iopin_switch_to_input(self, PULL_NONE); +} + +bool common_hal_i2cioexpander_iopin_deinited(i2cioexpander_iopin_obj_t *self) { + return self->expander == NULL || common_hal_i2cioexpander_ioexpander_deinited(self->expander); +} + +digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_input( + i2cioexpander_iopin_obj_t *self, + digitalio_pull_t pull) { + + if (pull != PULL_NONE) { + // IO expanders typically don't support pull resistors + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL + return DIGITALINOUT_INVALID_PULL; + #endif + } + + self->direction = DIRECTION_INPUT; + + // Clear the output mask bit for this pin + size_t new_mask = self->expander->output_mask & ~(1 << self->pin_number); + common_hal_i2cioexpander_ioexpander_set_output_mask(self->expander, new_mask); + + return DIGITALINOUT_OK; +} + +digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_output( + i2cioexpander_iopin_obj_t *self, + bool value, + digitalio_drive_mode_t drive_mode) { + + if (drive_mode != DRIVE_MODE_PUSH_PULL) { + // IO expanders typically only support push-pull + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE + return DIGITALINOUT_INVALID_DRIVE_MODE; + #endif + } + + self->direction = DIRECTION_OUTPUT; + + // Set the value first + size_t new_value = self->expander->output_value; + if (value) { + new_value |= (1 << self->pin_number); + } else { + new_value &= ~(1 << self->pin_number); + } + common_hal_i2cioexpander_ioexpander_set_output_value(self->expander, new_value); + + // Set the output mask bit for this pin + size_t new_mask = self->expander->output_mask | (1 << self->pin_number); + common_hal_i2cioexpander_ioexpander_set_output_mask(self->expander, new_mask); + + return DIGITALINOUT_OK; +} + +digitalio_direction_t common_hal_i2cioexpander_iopin_get_direction(i2cioexpander_iopin_obj_t *self) { + return self->direction; +} + +mp_negative_errno_t common_hal_i2cioexpander_iopin_set_value(i2cioexpander_iopin_obj_t *self, bool value) { + size_t current_value; + common_hal_i2cioexpander_ioexpander_get_output_value(self->expander, ¤t_value); + size_t new_value; + if (value) { + new_value = current_value | (1 << self->pin_number); + } else { + new_value = current_value & ~(1 << self->pin_number); + } + if (new_value != current_value) { + return common_hal_i2cioexpander_ioexpander_set_output_value(self->expander, new_value); + } + return 0; +} + +mp_negative_errno_t common_hal_i2cioexpander_iopin_get_value(i2cioexpander_iopin_obj_t *self, bool *value) { + size_t full_value; + mp_negative_errno_t result = common_hal_i2cioexpander_ioexpander_get_input_value(self->expander, &full_value); + if (result != 0) { + return result; + } + *value = (full_value & (1 << self->pin_number)) != 0; + return 0; +} + +digitalinout_result_t common_hal_i2cioexpander_iopin_set_drive_mode( + i2cioexpander_iopin_obj_t *self, + digitalio_drive_mode_t drive_mode) { + + if (drive_mode != DRIVE_MODE_PUSH_PULL) { + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE + return DIGITALINOUT_INVALID_DRIVE_MODE; + #endif + } + + return DIGITALINOUT_OK; +} + +digitalio_drive_mode_t common_hal_i2cioexpander_iopin_get_drive_mode(i2cioexpander_iopin_obj_t *self) { + return DRIVE_MODE_PUSH_PULL; +} + +digitalinout_result_t common_hal_i2cioexpander_iopin_set_pull( + i2cioexpander_iopin_obj_t *self, + digitalio_pull_t pull) { + + if (pull != PULL_NONE) { + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL + return DIGITALINOUT_INVALID_PULL; + #endif + } + + return DIGITALINOUT_OK; +} + +digitalio_pull_t common_hal_i2cioexpander_iopin_get_pull(i2cioexpander_iopin_obj_t *self) { + return PULL_NONE; +} diff --git a/shared-module/i2cioexpander/IOPin.h b/shared-module/i2cioexpander/IOPin.h new file mode 100644 index 00000000000..0c4da8a0213 --- /dev/null +++ b/shared-module/i2cioexpander/IOPin.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" +#include "shared-bindings/digitalio/Direction.h" +#include "shared-bindings/digitalio/DriveMode.h" +#include "shared-bindings/digitalio/Pull.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-module/i2cioexpander/IOExpander.h" + +typedef struct { + mp_obj_base_t base; + i2cioexpander_ioexpander_obj_t *expander; + uint8_t pin_number; + digitalio_direction_t direction; +} i2cioexpander_iopin_obj_t; + +extern const mp_obj_type_t i2cioexpander_iopin_type; diff --git a/shared-module/i2cioexpander/__init__.c b/shared-module/i2cioexpander/__init__.c new file mode 100644 index 00000000000..43e652db897 --- /dev/null +++ b/shared-module/i2cioexpander/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Nothing now. diff --git a/shared-module/jpegio/JpegDecoder.c b/shared-module/jpegio/JpegDecoder.c index 484ba8e7ccd..b70cfccf22d 100644 --- a/shared-module/jpegio/JpegDecoder.c +++ b/shared-module/jpegio/JpegDecoder.c @@ -46,7 +46,7 @@ static void check_jresult(JRESULT j) { msg = MP_ERROR_TEXT("Right format but not supported"); break; case JDR_FMT3: - msg = MP_ERROR_TEXT("Not supported JPEG standard"); + msg = MP_ERROR_TEXT("Unsupported JPEG (may be progressive)"); break; } mp_raise_RuntimeError(msg); @@ -89,7 +89,7 @@ static size_t file_input(JDEC *jd, uint8_t *dest, size_t len) { read = file_input(jd, buf, to_discard); total += read; } while (read != 0 && total != len); - return len; + return total; } int errcode = 0; @@ -147,14 +147,14 @@ static int bitmap_output(JDEC *jd, void *data, JRECT *rect) { int y1 = self->lim.y1 - rect->top; int y2 = self->lim.y2 - rect->top; - if (y2 < y1) { + if (y2 <= 0) { // The last row in the source image to copy FROM is above of this, so // no more pixels on any rows return DECODER_INTERRUPT; } y2 = MIN(y2, src_height); - if (x2 < x1) { + if (x2 <= 0) { // The last column in the source image to copy FROM is left of this, so // no more pixels on this row but could be on subsequent rows return DECODER_CONTINUE; diff --git a/shared-module/lvfontio/OnDiskFont.c b/shared-module/lvfontio/OnDiskFont.c index 368bd381475..efffed63074 100644 --- a/shared-module/lvfontio/OnDiskFont.c +++ b/shared-module/lvfontio/OnDiskFont.c @@ -48,6 +48,7 @@ static inline void free_memory(lvfontio_ondiskfont_t *self, void *ptr) { // Forward declarations for helper functions static int16_t find_codepoint_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint); +static bool slot_has_active_full_width_partner(lvfontio_ondiskfont_t *self, uint16_t slot); static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint); static FRESULT read_bits(FIL *file, size_t num_bits, uint8_t *byte_val, uint8_t *remaining_bits, uint32_t *result); static FRESULT read_glyph_dimensions(FIL *file, lvfontio_ondiskfont_t *self, uint32_t *advance_width, int32_t *bbox_x, int32_t *bbox_y, uint32_t *bbox_w, uint32_t *bbox_h, uint8_t *byte_val, uint8_t *remaining_bits); @@ -224,7 +225,12 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max // Throw away the bitmap bits. read_bits(file, self->header.bits_per_pixel * bbox_w * bbox_h, &byte_val, &remaining_bits, NULL); - if (advances[0] == glyph_advance) { + + if (glyph_advance == 0) { + // Ignore zero-advance glyphs when inferring the terminal cell width. + // Some fonts include placeholders/control glyphs with zero advance, + // which would otherwise skew default_advance_width too small. + } else if (advances[0] == glyph_advance) { advance_count[0]++; } else if (advances[1] == glyph_advance) { advance_count[1]++; @@ -257,6 +263,12 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max *max_slots = advance_count[0] + advance_count[1]; } + if (self->header.default_advance_width == 0) { + self->header.default_advance_width = 1; + } + if (*max_slots == 0) { + *max_slots = 1; + } found_glyf = true; } @@ -344,8 +356,9 @@ static int32_t get_char_id(lvfontio_ondiskfont_t *self, uint32_t codepoint) { for (size_t j = 0; j < self->cmap_ranges[i].entries_count; j++) { // Read code point at the index uint16_t candidate_codepoint_delta; - res = f_read(&self->file, &candidate_codepoint_delta, 2, NULL); - if (res != FR_OK) { + UINT bytes_read; + res = f_read(&self->file, &candidate_codepoint_delta, 2, &bytes_read); + if (res != FR_OK || bytes_read < 2) { return -1; } @@ -574,18 +587,20 @@ int16_t common_hal_lvfontio_ondiskfont_cache_glyph(lvfontio_ondiskfont_t *self, // Check if already cached int16_t existing_slot = find_codepoint_slot(self, codepoint); if (existing_slot >= 0) { - // Glyph is already cached, increment reference count + // Glyph is already cached, increment reference count(s). self->reference_counts[existing_slot]++; // Check if this is a full-width character by looking for a second slot - // with the same codepoint right after this one + // with the same codepoint right after this one, wrapping at the end. + uint16_t next_slot = (existing_slot + 1) % self->max_glyphs; + bool cached_is_full_width = self->codepoints[next_slot] == codepoint; + + if (cached_is_full_width) { + self->reference_counts[next_slot]++; + } + if (is_full_width != NULL) { - if (existing_slot + 1 < self->max_glyphs && - self->codepoints[existing_slot + 1] == codepoint) { - *is_full_width = true; - } else { - *is_full_width = false; - } + *is_full_width = cached_is_full_width; } return existing_slot; @@ -722,12 +737,37 @@ static int16_t find_codepoint_slot(lvfontio_ondiskfont_t *self, uint32_t codepoi for (uint16_t i = 0; i < self->max_glyphs; i++) { int16_t slot = (i + offset) % self->max_glyphs; if (self->codepoints[slot] == codepoint) { + // If this is the second slot of a full-width glyph pair, return the + // first slot so callers always get a canonical index. + if (slot > 0 && self->codepoints[slot - 1] == codepoint) { + return slot - 1; + } return slot; } } return -1; } +static bool slot_has_active_full_width_partner(lvfontio_ondiskfont_t *self, uint16_t slot) { + uint32_t codepoint = self->codepoints[slot]; + if (codepoint == LVFONTIO_INVALID_CODEPOINT) { + return false; + } + + // Don't evict one half of a full-width pair while the other half is still in use. + uint16_t prev_slot = (slot + self->max_glyphs - 1) % self->max_glyphs; + uint16_t next_slot = (slot + 1) % self->max_glyphs; + + if (self->codepoints[prev_slot] == codepoint && self->reference_counts[prev_slot] > 0) { + return true; + } + if (self->codepoints[next_slot] == codepoint && self->reference_counts[next_slot] > 0) { + return true; + } + + return false; +} + static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint) { size_t offset = codepoint % self->max_glyphs; @@ -739,10 +779,11 @@ static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint) } } - // If none found, look for slots with zero reference count, starting at the offset + // If none found, look for slots with zero reference count, starting at the offset. + // Avoid reusing one half of an active full-width glyph pair. for (uint16_t i = 0; i < self->max_glyphs; i++) { int16_t slot = (i + offset) % self->max_glyphs; - if (self->reference_counts[slot] == 0) { + if (self->reference_counts[slot] == 0 && !slot_has_active_full_width_partner(self, slot)) { return slot; } } diff --git a/shared-module/max3421e/Max3421E.c b/shared-module/max3421e/Max3421E.c index 4946e4e7d8d..3448cdd4c75 100644 --- a/shared-module/max3421e/Max3421E.c +++ b/shared-module/max3421e/Max3421E.c @@ -83,7 +83,7 @@ void common_hal_max3421e_max3421e_deinit(max3421e_max3421e_obj_t *self) { // anyway. Don't run background tasks because this function is used by // tuh_task() which is run as a background task. #if CFG_TUSB_OS == OPT_OS_NONE -void osal_task_delay(uint32_t msec) { +void tusb_time_delay_ms_api(uint32_t msec) { uint32_t end_time = common_hal_time_monotonic_ms() + msec; while (common_hal_time_monotonic_ms() < end_time) { if (tuh_callback.prev != NULL) { diff --git a/shared-module/memorymonitor/AllocationSize.c b/shared-module/memorymonitor/AllocationSize.c index f68401a252f..8c73f15db7e 100644 --- a/shared-module/memorymonitor/AllocationSize.c +++ b/shared-module/memorymonitor/AllocationSize.c @@ -60,6 +60,9 @@ void memorymonitor_allocationsizes_track_allocation(size_t block_count) { power_of_two++; block_count >>= 1; } + if (power_of_two >= ALLOCATION_SIZE_BUCKETS) { + power_of_two = ALLOCATION_SIZE_BUCKETS - 1; + } while (as != NULL) { as->buckets[power_of_two]++; as = as->next; diff --git a/shared-module/msgpack/__init__.c b/shared-module/msgpack/__init__.c index a98fb02de39..f0099dd0ccb 100644 --- a/shared-module/msgpack/__init__.c +++ b/shared-module/msgpack/__init__.c @@ -9,6 +9,7 @@ #include "py/obj.h" #include "py/binary.h" +#include "py/cstack.h" #include "py/objarray.h" #include "py/objlist.h" #include "py/objstringio.h" @@ -254,6 +255,7 @@ static void pack_dict(msgpack_stream_t *s, size_t len) { } static void pack(mp_obj_t obj, msgpack_stream_t *s, mp_obj_t default_handler) { + mp_cstack_check(); if (mp_obj_is_small_int(obj)) { // int int32_t x = MP_OBJ_SMALL_INT_VALUE(obj); @@ -293,11 +295,11 @@ static void pack(mp_obj_t obj, msgpack_stream_t *s, mp_obj_t default_handler) { pack(next->value, s, default_handler); } } else if (mp_obj_is_float(obj)) { - union Float { mp_float_t f; + union Float { float f; uint32_t u; }; union Float data; - data.f = mp_obj_float_get(obj); + data.f = (float)mp_obj_float_get(obj); write1(s, 0xca); write4(s, data.u); } else if (obj == mp_const_none) { @@ -326,7 +328,14 @@ static void pack(mp_obj_t obj, msgpack_stream_t *s, mp_obj_t default_handler) { static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list); +static void check_container_size(size_t count, size_t elem_size, qstr name) { + if (count > SIZE_MAX / elem_size) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q too long"), name); + } +} + static mp_obj_t unpack_array_elements(msgpack_stream_t *s, size_t size, mp_obj_t ext_hook, bool use_list) { + check_container_size(size, sizeof(mp_obj_t), MP_QSTR_array); if (use_list) { mp_obj_list_t *t = MP_OBJ_TO_PTR(mp_obj_new_list(size, NULL)); for (size_t i = 0; i < size; i++) { @@ -372,6 +381,7 @@ static mp_obj_t unpack_ext(msgpack_stream_t *s, size_t size, mp_obj_t ext_hook) } static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) { + mp_cstack_check(); uint8_t code = read1(s); if (((code & 0b10000000) == 0) || ((code & 0b11100000) == 0b11100000)) { // int @@ -394,7 +404,9 @@ static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) { size_t len = code & 0b1111; mp_obj_dict_t *d = MP_OBJ_TO_PTR(mp_obj_new_dict(len)); for (size_t i = 0; i < len; i++) { - mp_obj_dict_store(d, unpack(s, ext_hook, use_list), unpack(s, ext_hook, use_list)); + mp_obj_t key = unpack(s, ext_hook, use_list); + mp_obj_t value = unpack(s, ext_hook, use_list); + mp_obj_dict_store(d, key, value); } return MP_OBJ_FROM_PTR(d); } @@ -429,12 +441,12 @@ static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) { return mp_obj_new_int_from_ll((int64_t)read8(s)); case 0xca: { // float union Float { - mp_float_t f; + float f; uint32_t u; }; union Float data; data.u = read4(s); - return mp_obj_new_float(data.f); + return mp_obj_new_float((mp_float_t)data.f); } case 0xcb: { // double union Double { @@ -460,9 +472,12 @@ static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) { case 0xdf: { // map 16 & 32 size_t len = read_size(s, code - 0xde + 1); + check_container_size(len, sizeof(mp_map_elem_t), MP_QSTR_map); mp_obj_dict_t *d = MP_OBJ_TO_PTR(mp_obj_new_dict(len)); for (size_t i = 0; i < len; i++) { - mp_obj_dict_store(d, unpack(s, ext_hook, use_list), unpack(s, ext_hook, use_list)); + mp_obj_t key = unpack(s, ext_hook, use_list); + mp_obj_t value = unpack(s, ext_hook, use_list); + mp_obj_dict_store(d, key, value); } return MP_OBJ_FROM_PTR(d); } diff --git a/shared-module/os/__init__.c b/shared-module/os/__init__.c index 3594c9bb028..2090dcbcdc4 100644 --- a/shared-module/os/__init__.c +++ b/shared-module/os/__init__.c @@ -17,6 +17,10 @@ #include "py/runtime.h" #include "shared-bindings/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + // This provides all VFS related OS functions so that ports can share the code // as needed. @@ -118,8 +122,14 @@ const char *common_hal_os_path_abspath(const char *path) { // Remove the dot output_len = slashes[slash_count - 1]; } else if (component_len == 2 && full_path[i - 1] == '.' && full_path[i - 2] == '.') { - // Remove the double dot and the previous component if it exists - slash_count--; + // Remove the double dot and the previous component if it exists. + // Never rewind past the root: if the root is the only recorded + // boundary (slash_count == 1), ".." at the root is a no-op instead of + // underflowing slash_count to SIZE_MAX and reading slashes[SIZE_MAX] + // out of bounds (matches POSIX "cd .. from / stays at /" semantics). + if (slash_count > 1) { + slash_count--; + } output_len = slashes[slash_count - 1]; } else { slashes[slash_count] = output_len; @@ -281,4 +291,17 @@ void common_hal_os_utime(const char *path, mp_obj_t times) { mp_vfs_proxy_call(vfs, MP_QSTR_utime, 2, args); } +#if CIRCUITPY_SETTINGS_TOML +mp_obj_t common_hal_os_getenv(const char *key, mp_obj_t default_) { + vstr_t vstr; + vstr_init(&vstr, 64); + + settings_err_t result = settings_get_raw_vstr(key, &vstr); + if (result == SETTINGS_OK) { + return mp_obj_new_str_from_vstr(&vstr); + } + return default_; +} +#endif + MP_REGISTER_ROOT_POINTER(const char *cwd_path); diff --git a/shared-module/os/__init__.h b/shared-module/os/__init__.h index d44bae1ffc5..830f7629509 100644 --- a/shared-module/os/__init__.h +++ b/shared-module/os/__init__.h @@ -6,26 +6,5 @@ #pragma once -typedef enum { - GETENV_OK = 0, - GETENV_ERR_OPEN, - GETENV_ERR_UNICODE, - GETENV_ERR_LENGTH, - GETENV_ERR_NOT_FOUND, - GETENV_ERR_UNEXPECTED = 0xff00, // logical or'd with the byte value -} os_getenv_err_t; - -// Allocation free version that returns the full length of the value. -// If it fits, the return value is 0-terminated. The passed in buffer -// may be modified even if an error is returned. Allocation free. -// An error that is not 'open' or 'not found' is printed on the repl. -os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len); - -// Returns GETENV_OK and sets value to the read value. Returns -// GETENV_ERR_... if the value was not numeric. allocation-free. -// If any error code is returned, value is guaranteed not modified -// An error that is not 'open' or 'not found' is printed on the repl. -os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value); - // Not made available to the VM but used by other modules to normalize paths. const char *common_hal_os_path_abspath(const char *path); diff --git a/shared-module/os/getenv.c b/shared-module/os/getenv.c deleted file mode 100644 index c7bfadf3418..00000000000 --- a/shared-module/os/getenv.c +++ /dev/null @@ -1,417 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2022 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -// These functions are separate from __init__.c so that os.getenv() can be -// tested in the unix "coverage" build, without bringing in "our" os module - -#include -#include -#include - -#include "shared-bindings/os/__init__.h" -#include "shared-module/os/__init__.h" - -#include "py/gc.h" -#include "py/misc.h" -#include "py/mpstate.h" -#include "py/mpprint.h" -#include "py/objstr.h" -#include "py/parsenum.h" -#include "py/runtime.h" -#include "supervisor/filesystem.h" - -#define GETENV_PATH "/settings.toml" - -#include "extmod/vfs.h" -#include "extmod/vfs_fat.h" - -#if CIRCUITPY_OS_GETENV -typedef FIL file_arg; -static bool open_file(const char *name, file_arg *active_file) { - #if defined(UNIX) - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t file_obj = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), mp_obj_new_str(name, strlen(name)), MP_ROM_QSTR(MP_QSTR_rb)); - mp_arg_validate_type(file_obj, &mp_type_vfs_fat_fileio, MP_QSTR_file); - pyb_file_obj_t *file = MP_OBJ_TO_PTR(file_obj); - *active_file = file->fp; - nlr_pop(); - return true; - } else { - return false; - } - #else - fs_user_mount_t *fs_mount = filesystem_circuitpy(); - if (fs_mount == NULL) { - return false; - } - FATFS *fatfs = &fs_mount->fatfs; - FRESULT result = f_open(fatfs, active_file, name, FA_READ); - return result == FR_OK; - #endif -} -static void close_file(file_arg *active_file) { - // nothing -} -static bool is_eof(file_arg *active_file) { - return f_eof(active_file) || f_error(active_file); -} - -// Return 0 if there is no next character (EOF). -static uint8_t get_next_byte(FIL *active_file) { - uint8_t character = 0; - UINT quantity_read; - // If there's an error or quantity_read is 0, character will remain 0. - f_read(active_file, &character, 1, &quantity_read); - return character; -} -static void seek_eof(file_arg *active_file) { - f_lseek(active_file, f_size(active_file)); -} - -// For a fixed buffer, record the required size rather than throwing -static void vstr_add_byte_nonstd(vstr_t *vstr, byte b) { - if (!vstr->fixed_buf || vstr->alloc > vstr->len) { - vstr_add_byte(vstr, b); - } else { - vstr->len++; - } -} - -// For a fixed buffer, record the required size rather than throwing -static void vstr_add_char_nonstd(vstr_t *vstr, unichar c) { - size_t ulen = - (c < 0x80) ? 1 : - (c < 0x800) ? 2 : - (c < 0x10000) ? 3 : 4; - if (!vstr->fixed_buf || vstr->alloc > vstr->len + ulen) { - vstr_add_char(vstr, c); - } else { - vstr->len += ulen; - } -} - -static void next_line(file_arg *active_file) { - uint8_t character; - do { - character = get_next_byte(active_file); - } while (character != 0 && character != '\n'); -} - -// Discard whitespace, except for newlines, returning the next character after the whitespace. -// Return 0 if there is no next character (EOF). -static uint8_t consume_whitespace(file_arg *active_file) { - uint8_t character; - do { - character = get_next_byte(active_file); - } while (character != '\n' && character != 0 && unichar_isspace(character)); - return character; -} - -// Starting at the start of a new line, determines if the key matches the given -// key. -// -// If result is true, the key matches and file pointer is pointing just after the "=". -// If the result is false, the key does NOT match and the file pointer is -// pointing at the start of the next line, if any -static bool key_matches(file_arg *active_file, const char *key) { - uint8_t character; - character = consume_whitespace(active_file); - if (character == '[' || character == 0) { - seek_eof(active_file); - return false; - } - while (*key) { - if (character != *key++) { - // A character didn't match the key, so it's not a match - // If the non-matching char was not the end of the line, - // then consume the rest of the line - if (character != '\n') { - next_line(active_file); - } - return false; - } - character = get_next_byte(active_file); - } - // the next character could be whitespace; consume if necessary - if (unichar_isspace(character)) { - character = consume_whitespace(active_file); - } - // If we're not looking at the "=" then the key didn't match - if (character != '=') { - // A character didn't match the key, so it's not a match - // If the non-matching char was not the end of the line, - // then consume the rest of the line - if (character != '\n') { - next_line(active_file); - } - return false; - } - return true; -} - -static os_getenv_err_t read_unicode_escape(file_arg *active_file, int sz, vstr_t *buf) { - char hex_buf[sz + 1]; - for (int i = 0; i < sz; i++) { - hex_buf[i] = get_next_byte(active_file); - } - hex_buf[sz] = 0; - char *end; - unsigned long c = strtoul(hex_buf, &end, 16); - if (end != &hex_buf[sz]) { - return GETENV_ERR_UNEXPECTED | *end; - } - if (c >= 0x110000) { - return GETENV_ERR_UNICODE; - } - vstr_add_char_nonstd(buf, c); - return GETENV_OK; -} - -// Read a quoted string -static os_getenv_err_t read_string_value(file_arg *active_file, vstr_t *buf) { - while (true) { - int character = get_next_byte(active_file); - switch (character) { - case 0: - case '\n': - return GETENV_ERR_UNEXPECTED | character; - - case '"': - character = consume_whitespace(active_file); - switch (character) { - case '#': - next_line(active_file); - MP_FALLTHROUGH; - case 0: - case '\n': - return GETENV_OK; - default: - return GETENV_ERR_UNEXPECTED | character; - } - - case '\\': - character = get_next_byte(active_file); - switch (character) { - case 0: - case '\n': - return GETENV_ERR_UNEXPECTED | character; - case 'b': - character = '\b'; - break; - case 'r': - character = '\r'; - break; - case 'n': - character = '\n'; - break; - case 't': - character = '\t'; - break; - case 'v': - character = '\v'; - break; - case 'f': - character = '\f'; - break; - case 'U': - case 'u': { - int sz = (character == 'u') ? 4 : 8; - os_getenv_err_t res; - res = read_unicode_escape(active_file, sz, buf); - if (res != GETENV_OK) { - return res; - } - continue; - } - // default falls through, other escaped characters - // represent themselves - } - MP_FALLTHROUGH; - default: - vstr_add_byte_nonstd(buf, character); - } - } -} - -// Read a numeric value (non-quoted value) as a string -static os_getenv_err_t read_bare_value(file_arg *active_file, vstr_t *buf, int first_character) { - int character = first_character; - while (true) { - switch (character) { - case 0: - case '\n': - return GETENV_OK; - case '#': - next_line(active_file); - return GETENV_OK; - default: - vstr_add_byte_nonstd(buf, character); - } - character = get_next_byte(active_file); - } -} - -static mp_int_t read_value(file_arg *active_file, vstr_t *buf, bool *quoted) { - uint8_t character; - character = consume_whitespace(active_file); - *quoted = (character == '"'); - - if (*quoted) { - return read_string_value(active_file, buf); - } else { - return read_bare_value(active_file, buf, character); - } -} - -static os_getenv_err_t os_getenv_vstr(const char *path, const char *key, vstr_t *buf, bool *quoted) { - file_arg active_file; - if (!open_file(path, &active_file)) { - return GETENV_ERR_OPEN; - } - - os_getenv_err_t result = GETENV_ERR_NOT_FOUND; - while (!is_eof(&active_file)) { - if (key_matches(&active_file, key)) { - result = read_value(&active_file, buf, quoted); - break; - } - } - close_file(&active_file); - return result; -} - -static os_getenv_err_t os_getenv_buf_terminated(const char *key, char *value, size_t value_len, bool *quoted) { - vstr_t buf; - vstr_init_fixed_buf(&buf, value_len, value); - os_getenv_err_t result = os_getenv_vstr(GETENV_PATH, key, &buf, quoted); - - if (result == GETENV_OK) { - vstr_add_byte_nonstd(&buf, 0); - memcpy(value, buf.buf, MIN(buf.len, value_len)); - if (buf.len > value_len) { // this length includes trailing NUL - result = GETENV_ERR_LENGTH; - } - } - return result; -} - -static void print_dont_raise(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...) { - va_list argptr; - va_start(argptr, fmt); - mp_vcprintf(&mp_plat_print, fmt, argptr); - mp_printf(&mp_plat_print, "\n"); - va_end(argptr); -} - -static void handle_getenv_error(os_getenv_err_t error, void (*handle)(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...)) { - if (error == GETENV_OK) { - return; - } - if (error & GETENV_ERR_UNEXPECTED) { - byte character = (error & 0xff); - char buf[8]; - vstr_t vstr; - vstr_init_fixed_buf(&vstr, sizeof(buf), buf); - mp_print_t print = { .data = &vstr, .print_strn = (mp_print_strn_t)vstr_add_strn }; - - if (character) { - mp_str_print_quoted(&print, &character, 1, true); - } else { - mp_str_print_quoted(&print, (byte *)"EOF", 3, true); - } - handle(&mp_type_ValueError, MP_ERROR_TEXT("Invalid byte %.*s"), vstr.len, vstr.buf); - } else { - switch (error) { - case GETENV_ERR_OPEN: - handle(&mp_type_ValueError, MP_ERROR_TEXT("%S"), MP_ERROR_TEXT("File not found")); - break; - case GETENV_ERR_UNICODE: - handle(&mp_type_ValueError, MP_ERROR_TEXT("%S"), MP_ERROR_TEXT("Invalid unicode escape")); - break; - case GETENV_ERR_NOT_FOUND: - handle(&mp_type_ValueError, MP_ERROR_TEXT("%S"), MP_ERROR_TEXT("Key not found")); - break; - default: - handle(&mp_type_RuntimeError, MP_ERROR_TEXT("%S"), MP_ERROR_TEXT("Internal error")); - break; - } - } -} - -static void common_hal_os_getenv_showerr(const char *key, os_getenv_err_t result) { - if (result != GETENV_OK && result != GETENV_ERR_OPEN && result != GETENV_ERR_NOT_FOUND) { - mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("An error occurred while retrieving '%s':\n"), key); - handle_getenv_error(result, print_dont_raise); - } -} - -static -os_getenv_err_t common_hal_os_getenv_str_inner(const char *key, char *value, size_t value_len) { - bool quoted; - os_getenv_err_t result = os_getenv_buf_terminated(key, value, value_len, "ed); - if (result == GETENV_OK && !quoted) { - result = GETENV_ERR_UNEXPECTED | value[0]; - } - return result; -} - -os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len) { - os_getenv_err_t result = common_hal_os_getenv_str_inner(key, value, value_len); - common_hal_os_getenv_showerr(key, result); - return result; -} - -mp_obj_t common_hal_os_getenv_path(const char *path, const char *key, mp_obj_t default_) { - vstr_t buf; - bool quoted; - - vstr_init(&buf, 64); - os_getenv_err_t result = os_getenv_vstr(path, key, &buf, "ed); - if (result == GETENV_ERR_NOT_FOUND || result == GETENV_ERR_OPEN) { - return default_; - } - handle_getenv_error(result, mp_raise_msg_varg); - - if (quoted) { - return mp_obj_new_str_from_vstr(&buf); - } else { - return mp_parse_num_integer(buf.buf, buf.len, 0, NULL); - } -} - -mp_obj_t common_hal_os_getenv(const char *key, mp_obj_t default_) { - return common_hal_os_getenv_path(GETENV_PATH, key, default_); -} - -static os_getenv_err_t common_hal_os_getenv_int_inner(const char *key, mp_int_t *value) { - char buf[16]; - bool quoted; - os_getenv_err_t result = os_getenv_buf_terminated(key, buf, sizeof(buf), "ed); - if (result != GETENV_OK) { - return result; - } - if (quoted) { - return GETENV_ERR_UNEXPECTED | '"'; - } - char *end; - long num = strtol(buf, &end, 0); - while (unichar_isspace(*end)) { - end++; - } - if (end == buf || *end) { // If the whole buffer was not consumed it's an error - return GETENV_ERR_UNEXPECTED | *end; - } - *value = (mp_int_t)num; - return GETENV_OK; -} - -os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value) { - os_getenv_err_t result = common_hal_os_getenv_int_inner(key, value); - common_hal_os_getenv_showerr(key, result); - return result; -} -#endif diff --git a/shared-module/picogame/Bitmap.h b/shared-module/picogame/Bitmap.h new file mode 100644 index 00000000000..887d904b203 --- /dev/null +++ b/shared-module/picogame/Bitmap.h @@ -0,0 +1,35 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame: 2D game engine for the PicoPad and similar boards. +// Bitmap = an image atlas of one or more equal-size frames, arbitrary width/height. + +#pragma once + +#include +#include +#include "py/obj.h" + +enum { + PICOGAME_FMT_RGB565 = 0, // 2 bytes/pixel, values in display wire order + PICOGAME_FMT_PAL8 = 1, // 1 byte/pixel index into palette (wire-order RGB565) +}; + +typedef struct { + mp_obj_base_t base; + mp_obj_t data_obj; // keep the source buffer alive + mp_obj_t palette_obj; // keep the palette buffer alive (MP_OBJ_NULL for RGB565) + const uint8_t *data; // pixel data + const uint16_t *palette; // wire-order RGB565 entries (PAL8), else NULL + uint16_t width, height; // size of a single frame + uint16_t stride; // atlas width in pixels (>= width * frames for a horizontal atlas) + uint16_t transparent; // transparent key: palette index (PAL8) or wire color (RGB565) + uint16_t pal_entries; // palette length in entries (PAL8; 0 for RGB565). Informational: the + // blitter does NOT clamp - indices must be < this (see PAL8 blit contract). + uint8_t format; // PICOGAME_FMT_* + uint8_t frames; + bool has_transparent; +} picogame_bitmap_obj_t; diff --git a/shared-module/picogame/Canvas.c b/shared-module/picogame/Canvas.c new file mode 100644 index 00000000000..5021dbc95f9 --- /dev/null +++ b/shared-module/picogame/Canvas.c @@ -0,0 +1,630 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared-module/picogame/Canvas.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/fontio/BuiltinFont.h" +#include "shared-bindings/displayio/Bitmap.h" + +// Thin wrappers over the shared int32 accumulator (dx1,dy1,dx2,dy2 are contiguous int32 at the +// struct tail). See picogame_dirty_* in __init__.c. +void picogame_canvas_dirty_reset(picogame_canvas_obj_t *cv) { + picogame_dirty_reset(&cv->dx1); +} + +void picogame_canvas_dirty_union(picogame_canvas_obj_t *cv, int x1, int y1, int x2, int y2) { + picogame_dirty_union(&cv->dx1, x1, y1, x2, y2); +} + +bool picogame_canvas_take_dirty(picogame_canvas_obj_t *cv, int *x1, int *y1, int *x2, int *y2) { + return picogame_dirty_take(&cv->dx1, x1, y1, x2, y2); +} + +// Union a canvas-local rect (clamped to the surface) into the dirty rect (scene coords). +static void mark(picogame_canvas_obj_t *cv, int lx1, int ly1, int lx2, int ly2) { + if (lx1 < 0) { + lx1 = 0; + } + if (ly1 < 0) { + ly1 = 0; + } + if (lx2 > cv->w) { + lx2 = cv->w; + } + if (ly2 > cv->h) { + ly2 = cv->h; + } + if (lx1 >= lx2 || ly1 >= ly2) { + return; + } + picogame_dirty_union(&cv->dx1, cv->x + lx1, cv->y + ly1, cv->x + lx2, cv->y + ly2); +} + +// NOT inlined on purpose: the shape primitives call put() many times (circle = +// 8 calls/iteration). Inlining bloated them (circle was ~1.4 KB); a real call keeps +// them small. Shapes aren't the hot path (the sprite/tilemap blits don't use put). +static __attribute__((noinline)) void put(picogame_canvas_obj_t *cv, int x, int y, uint16_t c) { + if (x >= 0 && y >= 0 && x < cv->w && y < cv->h) { + cv->data[y * cv->w + x] = c; + } +} + +// Fill `n` RGB565 pixels at `p` with `color`, word-filling two pixels per store (half the writes of +// a 16-bit loop); memset for the common 0 case. Handles a leading odd (2-byte-but-not-4-byte) address +// so it stays safe on Cortex-M0+ (RP2040), which faults on an unaligned 32-bit access - a StripDraw +// view's rows into the render strip can start on an odd pixel. This is the per-frame path for +// view.clear / Sky / HUD-bar / Fade fills, so the word-fill is worth it. +static void fill565(uint16_t *p, int n, uint16_t color) { + if (n <= 0) { + return; + } + if (color == 0) { + memset(p, 0, (size_t)n * 2); + return; + } + if ((uintptr_t)p & 3) { // align to 4 bytes: one leading pixel + *p++ = color; + n--; + } + uint32_t w = (uint32_t)color | ((uint32_t)color << 16); + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + uint32_t *w32 = (uint32_t *)p; // now 4-byte aligned + #pragma GCC diagnostic pop + int nw = n >> 1; + for (int i = 0; i < nw; i++) { + w32[i] = w; + } + if (n & 1) { // trailing odd pixel + p[n - 1] = color; + } +} + +// Defined with the filled shapes below; forward-declared for picogame_canvas_road. +static void span565(picogame_canvas_obj_t *cv, int y, int xs, int xe, uint16_t color); + +void picogame_canvas_clear(picogame_canvas_obj_t *cv, uint16_t color) { + fill565(cv->data, cv->w * cv->h, color); + mark(cv, 0, 0, cv->w, cv->h); +} + +void picogame_canvas_pixel(picogame_canvas_obj_t *cv, int x, int y, uint16_t color) { + put(cv, x, y, color); + mark(cv, x, y, x + 1, y + 1); +} + +void picogame_canvas_fill_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t color) { + int x2 = x + w, y2 = y + h; + int cx1 = x < 0 ? 0 : x, cy1 = y < 0 ? 0 : y; + int cx2 = x2 > cv->w ? cv->w : x2, cy2 = y2 > cv->h ? cv->h : y2; + for (int yy = cy1; yy < cy2; yy++) { + fill565(cv->data + yy * cv->w + cx1, cx2 - cx1, color); + } + mark(cv, x, y, x2, y2); +} + +void picogame_canvas_blit(picogame_canvas_obj_t *cv, picogame_bitmap_obj_t *bm, + int x, int y, int frame, bool flip_x, bool flip_y) { + // Composite a bitmap FRAME into the canvas buffer (honours the bitmap's transparent key). + // Reuses the sprite blit path, targeting the canvas's own RGB565 surface instead of a strip. + picogame_blit_bitmap(cv->data, cv->w, cv->h, 0, 0, bm, x, y, frame, flip_x, flip_y, false, NULL); + mark(cv, x, y, x + bm->width, y + bm->height); +} + +// Number of low zero bits (log2 for a power of 2; 0 for non-pow2, caught by caller). +static int log2_pow2(unsigned v) { + int n = 0; + while ((v & 1) == 0 && v > 1) { + v >>= 1; + n++; + } + return n; +} + +// One racing-road strip, all rows in one call (the OutRun-genre "draw_road" scanline loop - profiled +// at ~20-25 ms of Python on picobike: ~4 fill_rect boundary crossings + an int(float) phase per row). +// ri0 = the road-table row of THIS surface's row 0 (vy - horizon_base); negative rows are sky. +// tab = int16[ntab][5]: {edge_w, dash_hw, wb05_q8, wb07_q8, flags(bit0 = dashes allowed)} - static per +// game. rl/rr = per-frame integer road edges (road_edges output). d05/d07 = the frame's scrolling +// stripe/dash phases in Q8; the row's band parity is ((d05+wb05)>>8)&1, matching the Python +// int(d05f + wb05f) & 1 (both non-negative). colors = uint16[6]: {sky, road_a, road_b, rumble_a, +// rumble_b, dash}. Grass underneath and the finish-line chequer stay the caller's job (one fill_rect +// per strip / a few rows near the lap line - no reason to carry them in C). +void picogame_canvas_road(picogame_canvas_obj_t *cv, int ri0, + const int16_t *tab, int ntab, const int16_t *rl, const int16_t *rr, + int32_t d05_q8, int32_t d07_q8, const uint16_t *colors) { + int w = cv->w; + for (int ly = 0; ly < cv->h; ly++) { + int ri = ri0 + ly; + if (ri < 0) { // above the horizon: sky + fill565(&cv->data[ly * w], w, colors[0]); + continue; + } + if (ri >= ntab) { + ri = ntab - 1; + } + const int16_t *t = tab + ri * 5; + int band = (int)(((d05_q8 + t[2]) >> 8) & 1); + uint16_t road = band ? colors[1] : colors[2]; + uint16_t rumble = band ? colors[3] : colors[4]; + int l = rl[ri], r = rr[ri]; + if (r <= l) { + continue; + } + span565(cv, ly, l, r - 1, road); // fill_rect(l, w=r-l) covers l..r-1 + int ew = t[0]; + span565(cv, ly, l, l + ew - 1, rumble); + span565(cv, ly, r - ew, r - 1, rumble); + if ((t[4] & 1) && (((d07_q8 + t[3]) >> 8) & 1)) { + int mid = (l + r) >> 1, dw = t[1]; + span565(cv, ly, mid - dw, mid + dw - 1, colors[5]); + } + } + mark(cv, 0, 0, w, cv->h); +} + +// Context + row walker for the mode7 loop (each row derives rowdist/steps from its own sy). +typedef struct { + picogame_canvas_obj_t *cv; + const uint8_t *data; + const uint16_t *pal; + int fmt, stride, shx, shy, mx, my, horizon, y_off; + int32_t z, rx0, ry0, rsx, rsy, cam_x, cam_y; + bool transp; + uint16_t key; +} mode7_ctx_t; + +static void mode7_rows(void *arg, int lo, int hi) { + mode7_ctx_t *c = arg; + picogame_canvas_obj_t *cv = c->cv; + int w = cv->w; + #if defined(PICOGAME_HAS_INTERP) + int ltw = 16 - c->shx; + int lth = 16 - c->shy; + bool use_interp = (c->fmt == PICOGAME_FMT_PAL8) && !c->transp && c->pal != NULL + && c->stride == c->mx + 1 + && ltw >= 1 && lth >= 1 && ltw + lth <= 16; // lane1 shift = shy-ltw must be >= 0 + #endif + for (int sy = lo; sy < hi; sy++) { + int denom = (sy + c->y_off) - c->horizon; + if (denom <= 0) { + continue; + } + // 32-bit throughout (no 64-bit mul helper on the M0+): rowdist*coeff stays + // within int32 for sane camera params - the Python helper keeps z and the + // ray deltas small; extreme values degrade to wrong pixels, never a crash. + int32_t rowdist = c->z / denom; + int32_t stepx = (rowdist * c->rsx) >> 16; + int32_t stepy = (rowdist * c->rsy) >> 16; + int32_t fx = c->cam_x + ((rowdist * c->rx0) >> 16); + int32_t fy = c->cam_y + ((rowdist * c->ry0) >> 16); + uint16_t *drow = cv->data + sy * w; + #if defined(PICOGAME_HAS_INTERP) + if (use_interp) { + picogame_mode7_row_interp(drow, w, c->data, c->pal, + (uint32_t)fx, (uint32_t)fy, stepx, stepy, c->shx, c->shy, ltw, lth); + continue; + } + #endif + for (int sx = 0; sx < w; sx++) { + int tx = (fx >> c->shx) & c->mx, ty = (fy >> c->shy) & c->my; + uint16_t val; + if (src_pixel_s(c->fmt, c->data, c->pal, c->transp, c->key, ty * c->stride + tx, &val)) { + drow[sx] = val; + } + fx += stepx; + fy += stepy; + } + } +} + +void picogame_canvas_mode7(picogame_canvas_obj_t *cv, picogame_bitmap_obj_t *tex, + int horizon, int y_off, int32_t z, int32_t rx0, int32_t ry0, int32_t rsx, int32_t rsy, + int32_t cam_x, int32_t cam_y) { + // Perspective ground plane (Mode-7 / floorcaster). For each screen row below + // `horizon`, distance = z / (row - horizon) (16.16); the texture-space coord + // of the left edge is cam + distance*ray0, stepping by distance*rayDelta per + // pixel; sample `tex` (power-of-2, so wrap = a mask, and world 1.0 = one tile + // via a shift, no multiply). Integer throughout - no FPU needed (RP2040). + if (tex == NULL) { + return; + } + int tw = tex->width, th = tex->height; + if ((tw & (tw - 1)) || (th & (th - 1))) { // require power-of-2 dims + return; + } + int shx = 16 - log2_pow2((unsigned)tw); // world(1.0) -> one full tile + int shy = 16 - log2_pow2((unsigned)th); + int mx = tw - 1, my = th - 1, stride = tex->stride; + int fmt = tex->format; + const uint8_t *data = tex->data; + const uint16_t *pal = tex->palette; + bool transp = tex->has_transparent; + uint16_t key = tex->transparent; + // sy is a row WITHIN this surface (a StripDraw view is a Canvas onto one strip); + // the absolute screen row is sy + y_off, so the horizon test uses that. y_off = 0 + // for a full-screen Canvas, = the strip's screen y for a StripDraw view (0-RAM floor). + int y0 = horizon - y_off + 1; + if (y0 < 0) { + y0 = 0; + } + mode7_ctx_t ctx = { + cv, data, pal, fmt, stride, shx, shy, mx, my, horizon, y_off, + z, rx0, ry0, rsx, rsy, cam_x, cam_y, transp, key + }; + mode7_rows(&ctx, y0, cv->h); + mark(cv, 0, y0, cv->w, cv->h); +} + +void picogame_canvas_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t color) { + picogame_canvas_fill_rect(cv, x, y, w, 1, color); + picogame_canvas_fill_rect(cv, x, y + h - 1, w, 1, color); + picogame_canvas_fill_rect(cv, x, y, 1, h, color); + picogame_canvas_fill_rect(cv, x + w - 1, y, 1, h, color); +} + +void picogame_canvas_line(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int y1, uint16_t color) { + int dx = x1 - x0, dy = y1 - y0; + int adx = dx < 0 ? -dx : dx; + int ady = dy < 0 ? -dy : dy; + int sx = dx < 0 ? -1 : 1; + int sy = dy < 0 ? -1 : 1; + int err = adx - ady; + int x = x0, y = y0; + while (true) { + put(cv, x, y, color); + if (x == x1 && y == y1) { + break; + } + int e2 = 2 * err; + if (e2 > -ady) { + err -= ady; + x += sx; + } + if (e2 < adx) { + err += adx; + y += sy; + } + } + int lx1 = x0 < x1 ? x0 : x1, ly1 = y0 < y1 ? y0 : y1; + int lx2 = (x0 > x1 ? x0 : x1) + 1, ly2 = (y0 > y1 ? y0 : y1) + 1; + mark(cv, lx1, ly1, lx2, ly2); +} + +// Clamp a row span to the surface and word-fill it (the span-pass idiom shared by the filled +// shapes; the per-pixel put() loops it replaced clipped and indexed every pixel). +static inline int64_t edge_slope(int32_t dx, int32_t dy) { + if (dx >= -32768 && dx <= 32767) { + return (int32_t)(dx << 16) / dy; + } + return ((int64_t)dx << 16) / dy; +} + +static void span565(picogame_canvas_obj_t *cv, int y, int xs, int xe, uint16_t color) { + if (y < 0 || y >= cv->h) { + return; + } + if (xs < 0) { + xs = 0; + } + if (xe >= cv->w) { + xe = cv->w - 1; + } + if (xs <= xe) { + fill565(&cv->data[y * cv->w + xs], xe - xs + 1, color); + } +} + +void picogame_canvas_fill_circle(picogame_canvas_obj_t *cv, int cx, int cy, int r, uint16_t color) { + // A filled circle IS fill_ellipse(r, r) - the ellipse row condition s^2*ry2 <= rr - dy^2*rx2 + // collapses to s^2 <= r^2 - dy^2 (host-proven byte-exact over 36k cases). Same delegation the + // OUTLINE circle already does; only r == 0 needs care (the ellipse rejects rx <= 0, a zero-radius + // circle is one pixel). Flash: this replaced a ~320 B twin of the ellipse body. + if (r < 0) { + return; + } + if (r == 0) { + picogame_canvas_pixel(cv, cx, cy, color); + return; + } + picogame_canvas_fill_ellipse(cv, cx, cy, r, r, color); +} + +void picogame_canvas_circle(picogame_canvas_obj_t *cv, int cx, int cy, int r, uint16_t color) { + picogame_canvas_ellipse(cv, cx, cy, r, r, color); // a circle is an ellipse with rx == ry +} + +void picogame_canvas_ring(picogame_canvas_obj_t *cv, int cx, int cy, int r, int thick, uint16_t color) { + if (r < 0) { + return; + } + int inner = r - thick; + if (inner < 0) { + inner = 0; + } + // Mirrored rows + decremental outer/inner widths, two word-filled spans per row - see fill_circle. + int out = r, ins = inner; + for (int dy = 0; dy <= r; dy++) { + long rr = (long)r * r - (long)dy * dy; // long (like ellipse): int r*r overflows at big radii + while ((long)out * out > rr) { + out--; + } + int two_seg = dy <= inner; + if (two_seg) { + int ri = inner * inner - dy * dy; + while (ins * ins > ri) { + ins--; + } + } + for (int half = 0; half < (dy ? 2 : 1); half++) { + int y = half ? cy - dy : cy + dy; + if (two_seg) { + span565(cv, y, cx - out, cx - ins - 1, color); + span565(cv, y, cx + ins + 1, cx + out, color); + } else { + span565(cv, y, cx - out, cx + out, color); + } + } + } + mark(cv, cx - r, cy - r, cx + r + 1, cy + r + 1); +} + +void picogame_canvas_triangle(picogame_canvas_obj_t *cv, + int x0, int y0, int x1, int y1, int x2, int y2, uint16_t color) { + picogame_canvas_line(cv, x0, y0, x1, y1, color); + picogame_canvas_line(cv, x1, y1, x2, y2, color); + picogame_canvas_line(cv, x2, y2, x0, y0, color); +} + +void picogame_canvas_fill_triangle(picogame_canvas_obj_t *cv, + int x0, int y0, int x1, int y1, int x2, int y2, uint16_t color) { + int X[3] = { x0, x1, x2 }, Y[3] = { y0, y1, y2 }; + for (int i = 0; i < 2; i++) { + for (int j = i + 1; j < 3; j++) { + if (Y[j] < Y[i]) { + int t = Y[i]; + Y[i] = Y[j]; + Y[j] = t; + t = X[i]; + X[i] = X[j]; + X[j] = t; + } + } + } + // Scanline fill via 16.16 edge DDA + word-filled spans. One 64-bit divide per EDGE replaces two + // 32-bit divides per ROW (M0+ has no HW divide, ~75 cyc each; a 20-row wall paid ~40 divides), + // and each row goes through fill565 (word stores) instead of a per-pixel clipped put(). Rows and + // spans clamp to the canvas up front, so a mostly off-screen triangle costs only its visible rows + // (the old loop walked EVERY row of huge triangles and clipped per pixel - quadratic blowup). + // Edge x differs from the old divide by at most 1 px (trunc vs floor; host-verified over 100k + // triangles), and convex quads - the box faces the 3D demos draw - stay seam-hole-free. + int w = cv->w, h = cv->h; + if (Y[0] < h && Y[2] >= 0) { + int64_t sAC = (Y[2] != Y[0]) ? edge_slope(X[2] - X[0], Y[2] - Y[0]) : 0; + int64_t sAB = (Y[1] != Y[0]) ? edge_slope(X[1] - X[0], Y[1] - Y[0]) : 0; + int64_t sBC = (Y[2] != Y[1]) ? edge_slope(X[2] - X[1], Y[2] - Y[1]) : 0; + uint16_t *data = cv->data; + // top half: rows [Y0, Y1) walk edges A->C and A->B + int ys = Y[0] < 0 ? 0 : Y[0]; + int ye = (Y[1] - 1) < (h - 1) ? (Y[1] - 1) : (h - 1); + int64_t accAC = ((int64_t)X[0] << 16) + sAC * (ys - Y[0]); + int64_t acc2 = ((int64_t)X[0] << 16) + sAB * (ys - Y[0]); + for (int y = ys; y <= ye; y++) { + int xac = (int)(accAC >> 16); + int xsh = (int)(acc2 >> 16); + int xs = xac < xsh ? xac : xsh, xe = xac < xsh ? xsh : xac; + if (xs < 0) { + xs = 0; + } + if (xe >= w) { + xe = w - 1; + } + if (xs <= xe) { + fill565(&data[y * w + xs], xe - xs + 1, color); + } + accAC += sAC; + acc2 += sAB; + } + // bottom half: rows [Y1, Y2] walk edges A->C and B->C (a flat bottom degenerates to sBC=0) + ys = Y[1] < 0 ? 0 : Y[1]; + ye = Y[2] < (h - 1) ? Y[2] : (h - 1); + accAC = ((int64_t)X[0] << 16) + sAC * (ys - Y[0]); + acc2 = ((int64_t)X[1] << 16) + sBC * (ys - Y[1]); + for (int y = ys; y <= ye; y++) { + int xac = (int)(accAC >> 16); + int xsh = (int)(acc2 >> 16); + int xs = xac < xsh ? xac : xsh, xe = xac < xsh ? xsh : xac; + if (xs < 0) { + xs = 0; + } + if (xe >= w) { + xe = w - 1; + } + if (xs <= xe) { + fill565(&data[y * w + xs], xe - xs + 1, color); + } + accAC += sAC; + acc2 += sBC; + } + } + int mnx = X[0] < X[1] ? X[0] : X[1]; + mnx = mnx < X[2] ? mnx : X[2]; + int mxx = X[0] > X[1] ? X[0] : X[1]; + mxx = mxx > X[2] ? mxx : X[2]; + mark(cv, mnx, Y[0], mxx + 1, Y[2] + 1); +} + +void picogame_canvas_ellipse(picogame_canvas_obj_t *cv, int cx, int cy, int rx, int ry, uint16_t color) { + if (rx <= 0 || ry <= 0) { + return; + } + // 32-bit `long`: rx2*ry2 stays in range while rx*ry <= 46340 (both radii <~210 px). That covers any + // canvas that fits in RAM on this target. A larger ellipse (only reachable on a big-RAM board with an + // oversized canvas) renders a wrong shape - never a fault, since put() clips every pixel to the canvas. + long rx2 = (long)rx * rx, ry2 = (long)ry * ry, rr = rx2 * ry2; + for (int dy = -ry; dy <= ry; dy++) { + int s = 0; + while ((long)(s + 1) * (s + 1) * ry2 + (long)dy * dy * rx2 <= rr) { + s++; + } + put(cv, cx - s, cy + dy, color); + put(cv, cx + s, cy + dy, color); + } + for (int dx = -rx; dx <= rx; dx++) { + int s = 0; + while ((long)(s + 1) * (s + 1) * rx2 + (long)dx * dx * ry2 <= rr) { + s++; + } + put(cv, cx + dx, cy - s, color); + put(cv, cx + dx, cy + s, color); + } + mark(cv, cx - rx, cy - ry, cx + rx + 1, cy + ry + 1); +} + +void picogame_canvas_fill_ellipse(picogame_canvas_obj_t *cv, int cx, int cy, int rx, int ry, uint16_t color) { + if (rx <= 0 || ry <= 0) { + return; + } + // 32-bit `long`: rx2*ry2 stays in range while rx*ry <= 46340 (both radii <~210 px). That covers any + // canvas that fits in RAM on this target. A larger ellipse (only reachable on a big-RAM board with an + // oversized canvas) renders a wrong shape - never a fault, since put() clips every pixel to the canvas. + long rx2 = (long)rx * rx, ry2 = (long)ry * ry, rr = rx2 * ry2; + // Mirrored rows + decremental width, spans word-filled - see fill_circle. + int s = rx; + for (int dy = 0; dy <= ry; dy++) { + long lim = rr - (long)dy * dy * rx2; // s*s*ry2 <= lim <=> the old (s+1)-increment bound + while ((long)s * s * ry2 > lim) { + s--; + } + span565(cv, cy + dy, cx - s, cx + s, color); + if (dy) { + span565(cv, cy - dy, cx - s, cx + s, color); + } + } + mark(cv, cx - rx, cy - ry, cx + rx + 1, cy + ry + 1); +} + +void picogame_canvas_fill_round_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, int r, uint16_t color) { + if (r > w / 2) { + r = w / 2; + } + if (r > h / 2) { + r = h / 2; + } + if (r < 0) { + r = 0; + } + picogame_canvas_fill_rect(cv, x + r, y, w - 2 * r, h, color); + picogame_canvas_fill_rect(cv, x, y + r, r, h - 2 * r, color); + picogame_canvas_fill_rect(cv, x + w - r, y + r, r, h - 2 * r, color); + picogame_canvas_fill_circle(cv, x + r, y + r, r, color); + picogame_canvas_fill_circle(cv, x + w - r - 1, y + r, r, color); + picogame_canvas_fill_circle(cv, x + r, y + h - r - 1, r, color); + picogame_canvas_fill_circle(cv, x + w - r - 1, y + h - r - 1, r, color); +} + +void picogame_canvas_frame3d(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t light, uint16_t dark) { + picogame_canvas_fill_rect(cv, x, y, w, 1, light); + picogame_canvas_fill_rect(cv, x, y, 1, h, light); + picogame_canvas_fill_rect(cv, x, y + h - 1, w, 1, dark); + picogame_canvas_fill_rect(cv, x + w - 1, y, 1, h, dark); +} + +void picogame_blit_canvas( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_canvas_obj_t *cv, int ox, int oy) { + // Reuse the bitmap blitter by viewing the canvas as a 1-frame RGB565 bitmap. + picogame_bitmap_obj_t bm; + bm.data = (const uint8_t *)cv->data; + bm.palette = NULL; + bm.width = cv->w; + bm.height = cv->h; + bm.stride = cv->w; + bm.transparent = cv->transparent; + bm.format = PICOGAME_FMT_RGB565; + bm.frames = 1; + bm.has_transparent = cv->has_transparent; + picogame_blit_bitmap(buf, region_w, strip_h, x0, strip_top, &bm, + cv->x + ox, cv->y + oy, 0, false, false, false, NULL); +} + +// Composite a string's glyphs straight into the surface in C: rasterize each glyph from the +// font's 1-bit atlas on the fly (no Python glyph cache, no per-call Bitmap/Sprite). Because the +// StripDraw `view` is a Canvas pointing at the live strip buffer, view.text() draws immediate-mode +// text into the frame with zero retained RAM - the same primitive serves retained Canvas screens. +void picogame_canvas_text(picogame_canvas_obj_t *cv, int x, int y, const char *text, + uint16_t fg, uint16_t bg, bool has_bg, const void *font) { + const fontio_builtinfont_t *f = font; + displayio_bitmap_t *sheet = (displayio_bitmap_t *)f->bitmap; + int fw = f->width, fh = f->height; + int tpr = sheet->width / fw; // glyph tiles per atlas row + int x0 = x; + // Hoist the canvas target + read the 1-bpp glyph atlas DIRECTLY (no per-pixel get_pixel/put calls). + // Clip each glyph rect to the canvas ONCE, then the inner loop is atlas-bit -> direct store. This is + // the per-frame path for StripDraw HUD text (repainted every frame), so it's worth the directness. + uint16_t *cdata = cv->data; + int cw = cv->w, ch = cv->h; + bool onebit = (sheet->bits_per_value == 1); // terminalio.FONT is 1-bpp; other fonts take the fallback + const uint8_t *sdata = (const uint8_t *)sheet->data; + int sstride_b = sheet->stride * 4; // atlas row stride in BYTES (stride counts uint32) + for (const uint8_t *p = (const uint8_t *)text; *p; p++) { + uint8_t gi = fontio_builtinfont_get_glyph_index(f, *p); + if (gi != 0xff) { // 0xff = no glyph -> blank advance + int tx = (gi % tpr) * fw, ty = (gi / tpr) * fh; + int gx0 = (x < 0) ? -x : 0; // clip the glyph rect to the canvas once + int gx1 = (x + fw > cw) ? cw - x : fw; + int gy0 = (y < 0) ? -y : 0; + int gy1 = (y + fh > ch) ? ch - y : fh; + for (int gy = gy0; gy < gy1; gy++) { + uint16_t *drow = cdata + (y + gy) * cw + x; // dst; index by gx (x+gx is in-bounds) + int sy = ty + gy; + if (onebit) { + const uint8_t *srow = sdata + (size_t)sy * sstride_b; + for (int gx = gx0; gx < gx1; gx++) { + int sx = tx + gx; + if ((srow[sx >> sheet->x_shift] >> (sheet->x_mask - (sx & sheet->x_mask))) & sheet->bitmask) { + drow[gx] = fg; + } else if (has_bg) { + drow[gx] = bg; + } + } + } else { + for (int gx = gx0; gx < gx1; gx++) { + if (common_hal_displayio_bitmap_get_pixel(sheet, tx + gx, sy)) { + drow[gx] = fg; + } else if (has_bg) { + drow[gx] = bg; + } + } + } + } + } + x += fw; + } + mark(cv, x0, y, x, y + fh); +} + +// Fill a screen-space triangle batch with per-triangle band reject - shared by the +// Canvas.fill_triangles binding and the compositor's Triangles layer (one loop, one place). +void picogame_fill_triangle_batch(picogame_canvas_obj_t *cv, const int16_t *v, + const uint16_t *col, int n, int xo, int yo) { + int cw = cv->w, ch = cv->h; + for (int i = 0; i < n; i++) { + const int16_t *p = v + i * 6; + int y0 = p[1] + yo, y1 = p[3] + yo, y2 = p[5] + yo; + if ((y0 < 0 && y1 < 0 && y2 < 0) || (y0 >= ch && y1 >= ch && y2 >= ch)) { + continue; + } + int x0 = p[0] + xo, x1 = p[2] + xo, x2 = p[4] + xo; + if ((x0 < 0 && x1 < 0 && x2 < 0) || (x0 >= cw && x1 >= cw && x2 >= cw)) { + continue; + } + picogame_canvas_fill_triangle(cv, x0, y0, x1, y1, x2, y2, col[i]); + } +} diff --git a/shared-module/picogame/Canvas.h b/shared-module/picogame/Canvas.h new file mode 100644 index 00000000000..45c73e43326 --- /dev/null +++ b/shared-module/picogame/Canvas.h @@ -0,0 +1,69 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame Canvas: a RAM RGB565 surface (any size) you draw primitives into, +// composited as a Scene layer. The general home for shapes (fill_rect, line, +// circle, pixel) - accumulates a dirty rect (scene coords) so only redrawn +// areas repaint. Colors are wire-order (picogame.rgb565). + +#pragma once + +#include +#include +#include "py/obj.h" +#include "shared-module/picogame/Bitmap.h" + +typedef struct { + mp_obj_base_t base; + uint16_t *data; // w*h wire-order RGB565 + mp_obj_t data_obj; // backing buffer kept alive (MP_OBJ_NULL if m_new'd) + uint16_t w, h; + int32_t x, y; // scene position (int32: a canvas can sit past +-32767 px in a big world) + uint16_t transparent; + bool has_transparent; + int32_t dx1, dy1, dx2, dy2; // accumulated dirty rect (scene coords; int32, see x/y) +} picogame_canvas_obj_t; + +void picogame_canvas_dirty_reset(picogame_canvas_obj_t *cv); +// Grow the dirty rect to also cover a scene-coord rect (no surface clamping). +void picogame_canvas_dirty_union(picogame_canvas_obj_t *cv, int x1, int y1, int x2, int y2); +bool picogame_canvas_take_dirty(picogame_canvas_obj_t *cv, int *x1, int *y1, int *x2, int *y2); + +void picogame_canvas_clear(picogame_canvas_obj_t *cv, uint16_t color); +void picogame_canvas_pixel(picogame_canvas_obj_t *cv, int x, int y, uint16_t color); +void picogame_canvas_fill_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t color); +void picogame_canvas_blit(picogame_canvas_obj_t *cv, picogame_bitmap_obj_t *bm, int x, int y, int frame, bool flip_x, bool flip_y); +void picogame_canvas_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t color); +void picogame_canvas_line(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int y1, uint16_t color); +void picogame_canvas_fill_circle(picogame_canvas_obj_t *cv, int cx, int cy, int r, uint16_t color); +void picogame_canvas_circle(picogame_canvas_obj_t *cv, int cx, int cy, int r, uint16_t color); +void picogame_canvas_ring(picogame_canvas_obj_t *cv, int cx, int cy, int r, int thick, uint16_t color); +void picogame_canvas_triangle(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int y1, int x2, int y2, uint16_t color); +void picogame_canvas_fill_triangle(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int y1, int x2, int y2, uint16_t color); +void picogame_canvas_ellipse(picogame_canvas_obj_t *cv, int cx, int cy, int rx, int ry, uint16_t color); +void picogame_canvas_fill_ellipse(picogame_canvas_obj_t *cv, int cx, int cy, int rx, int ry, uint16_t color); +void picogame_canvas_fill_round_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, int r, uint16_t color); +void picogame_canvas_frame3d(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t light, uint16_t dark); +void picogame_canvas_text(picogame_canvas_obj_t *cv, int x, int y, const char *text, + uint16_t fg, uint16_t bg, bool has_bg, const void *font); +// Mode-7 perspective ground plane: fill rows below `horizon` with a receding view +// of `tex` (power-of-2 dims). Args are 16.16 fixed-point (a Python helper computes +// them from camera angle/pos/fov). See picogame_canvas_mode7 for the exact math. +// One racing-road strip: per-row spans (road/rumbles/dashes/sky) from precomputed tables. +void picogame_canvas_road(picogame_canvas_obj_t *cv, int ri0, + const int16_t *tab, int ntab, const int16_t *rl, const int16_t *rr, + int32_t d05_q8, int32_t d07_q8, const uint16_t *colors); + +void picogame_canvas_mode7(picogame_canvas_obj_t *cv, picogame_bitmap_obj_t *tex, + int horizon, int y_off, int32_t z, int32_t rx0, int32_t ry0, int32_t rsx, int32_t rsy, + int32_t cam_x, int32_t cam_y); + +void picogame_blit_canvas( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_canvas_obj_t *cv, int ox, int oy); + +void picogame_fill_triangle_batch(picogame_canvas_obj_t *cv, const int16_t *v, + const uint16_t *col, int n, int xo, int yo); diff --git a/shared-module/picogame/Particles.c b/shared-module/picogame/Particles.c new file mode 100644 index 00000000000..87e6917f479 --- /dev/null +++ b/shared-module/picogame/Particles.c @@ -0,0 +1,163 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "shared-module/picogame/Particles.h" +#include "shared-module/picogame/__init__.h" + +static uint32_t s_prng = 0x1234abcdu; + +static int32_t prng_range(int32_t lo, int32_t hi) { + s_prng ^= s_prng << 13; + s_prng ^= s_prng >> 17; + s_prng ^= s_prng << 5; + if (hi <= lo) { + return lo; + } + return lo + (int32_t)(s_prng % (uint32_t)(hi - lo + 1)); +} + +static void swap_remove(picogame_particles_obj_t *ps, int i) { + int last = ps->count - 1; + ps->px[i] = ps->px[last]; + ps->py[i] = ps->py[last]; + ps->vx[i] = ps->vx[last]; + ps->vy[i] = ps->vy[last]; + ps->life[i] = ps->life[last]; + ps->life0[i] = ps->life0[last]; + ps->color[i] = ps->color[last]; + ps->count--; +} + +// Dim a wire-order RGB565 color to num/den of its brightness (per channel). +static inline uint16_t scale_wire565(uint16_t wire, int num, int den) { + uint16_t c = (uint16_t)((wire >> 8) | (wire << 8)); // wire -> native + int r = ((c >> 11) & 0x1F) * num / den; + int g = ((c >> 5) & 0x3F) * num / den; + int b = (c & 0x1F) * num / den; + uint16_t out = (uint16_t)((r << 11) | (g << 5) | b); + return (uint16_t)((out >> 8) | (out << 8)); // native -> wire +} + +void picogame_particles_emit(picogame_particles_obj_t *ps, int x, int y, + int count, int speed, int life, uint16_t color) { + int sp = speed * 256; // px/tick -> 8.8 + for (int k = 0; k < count && ps->count < ps->cap; k++) { + int i = ps->count++; + ps->px[i] = x << 8; + ps->py[i] = y << 8; + ps->vx[i] = (int16_t)prng_range(-sp, sp); + ps->vy[i] = (int16_t)prng_range(-sp, sp); + ps->life[i] = life; + ps->life0[i] = (uint16_t)(life > 0 ? life : 1); + ps->color[i] = color; + } +} + +void picogame_particles_update(picogame_particles_obj_t *ps) { + int16_t g = ps->gravity; + int x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff - 1, y2 = -0x7fffffff - 1; // INT32: big-world + int sz = ps->size; + int i = 0; + while (i < ps->count) { + ps->px[i] += ps->vx[i]; + ps->py[i] += ps->vy[i]; + ps->vy[i] += g; + if (ps->life[i] == 0) { + swap_remove(ps, i); + continue; // re-process the swapped-in particle + } + ps->life[i]--; + int sx = ps->px[i] >> 8; + int sy = ps->py[i] >> 8; + if (sx < x1) { + x1 = sx; + } + if (sy < y1) { + y1 = sy; + } + if (sx + sz > x2) { + x2 = sx + sz; + } + if (sy + sz > y2) { + y2 = sy + sz; + } + i++; + } + // current-frame bbox becomes "previous" on the next take_dirty + ps->px1 = ps->cx1; + ps->py1 = ps->cy1; + ps->px2 = ps->cx2; + ps->py2 = ps->cy2; + if (ps->count > 0) { + ps->cx1 = x1; + ps->cy1 = y1; + ps->cx2 = x2; + ps->cy2 = y2; + } else { + picogame_dirty_reset(&ps->cx1); // empty -> INT32 sentinels (cx1,cy1,cx2,cy2 are contiguous) + } +} + +bool picogame_particles_take_dirty(picogame_particles_obj_t *ps, + int *x1, int *y1, int *x2, int *y2) { + int ax1 = ps->cx1 < ps->px1 ? ps->cx1 : ps->px1; + int ay1 = ps->cy1 < ps->py1 ? ps->cy1 : ps->py1; + int ax2 = ps->cx2 > ps->px2 ? ps->cx2 : ps->px2; + int ay2 = ps->cy2 > ps->py2 ? ps->cy2 : ps->py2; + // consume the previous box so a static system stops reporting dirty + ps->px1 = ps->cx1; + ps->py1 = ps->cy1; + ps->px2 = ps->cx2; + ps->py2 = ps->cy2; + if (ax1 >= ax2 || ay1 >= ay2) { + return false; + } + *x1 = ax1; + *y1 = ay1; + *x2 = ax2; + *y2 = ay2; + return true; +} + +void picogame_particles_clear(picogame_particles_obj_t *ps) { + // Move the currently-drawn region into "previous" and empty "current", so the next + // take_dirty reports the old pixels ONCE (erasing the cleared particles) then goes quiet. + ps->px1 = ps->cx1; + ps->py1 = ps->cy1; + ps->px2 = ps->cx2; + ps->py2 = ps->cy2; + picogame_dirty_reset(&ps->cx1); // empty -> INT32 sentinels (cx1,cy1,cx2,cy2 are contiguous) + ps->count = 0; +} + +void picogame_blit_particles( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_particles_obj_t *ps, int ox, int oy) { + int sz = ps->size; + int rx2 = x0 + region_w; + int ry2 = strip_top + strip_h; + for (int i = 0; i < ps->count; i++) { + int sx = (ps->px[i] >> 8) + ox; + int sy = (ps->py[i] >> 8) + oy; + int xs = picogame_imax(sx, x0); + int ys = picogame_imax(sy, strip_top); + int xe = picogame_imin(sx + sz, rx2); + int ye = picogame_imin(sy + sz, ry2); + if (xs >= xe || ys >= ye) { + continue; + } + uint16_t c = ps->color[i]; + if (ps->fade) { + c = scale_wire565(c, ps->life[i], ps->life0[i]); + } + for (int y = ys; y < ye; y++) { + uint16_t *dst = buf + (y - strip_top) * region_w + (xs - x0); + for (int x = xs; x < xe; x++) { + *dst++ = c; + } + } + } +} diff --git a/shared-module/picogame/Particles.h b/shared-module/picogame/Particles.h new file mode 100644 index 00000000000..faaf7a4989b --- /dev/null +++ b/shared-module/picogame/Particles.h @@ -0,0 +1,45 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame particle system: a pooled set of small moving dots rendered as one +// Scene layer (individual sprites would be far too heavy). Positions/velocities +// are 24.8 / 8.8 fixed-point for sub-pixel motion. Tracks a dirty rect spanning +// the previous and current frames so moving particles leave no trails. + +#pragma once + +#include +#include +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + int32_t *px, *py; // position, 24.8 fixed-point, scene coords + int16_t *vx, *vy; // velocity, 8.8 fixed-point per tick + uint16_t *life; // ticks remaining + uint16_t *life0; // life at spawn (for the fade ramp) + uint16_t *color; // wire-order RGB565 + uint16_t cap, count; + int16_t gravity; // 8.8, added to vy each tick + uint8_t size; // particle size in pixels + bool fade; // dim each particle toward black as it ages + // dirty bounding boxes (scene coords): previous frame and current frame. + // int32 (not int16): positions are 24.8 in int32, so emitters past +-32767 px would truncate. + int32_t cx1, cy1, cx2, cy2; + int32_t px1, py1, px2, py2; +} picogame_particles_obj_t; + +void picogame_particles_emit(picogame_particles_obj_t *ps, int x, int y, + int count, int speed, int life, uint16_t color); +void picogame_particles_update(picogame_particles_obj_t *ps); +// Remove all particles, marking their last-drawn region dirty once so they get erased. +void picogame_particles_clear(picogame_particles_obj_t *ps); +// Returns true + the dirty rect (scene coords) spanning last+current frames. +bool picogame_particles_take_dirty(picogame_particles_obj_t *ps, + int *x1, int *y1, int *x2, int *y2); +void picogame_blit_particles( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_particles_obj_t *ps, int ox, int oy); diff --git a/shared-module/picogame/Scene.c b/shared-module/picogame/Scene.c new file mode 100644 index 00000000000..b50a6c7a9b1 --- /dev/null +++ b/shared-module/picogame/Scene.c @@ -0,0 +1,251 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "shared-module/picogame/Scene.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Tilemap.h" +#include "shared-module/picogame/Particles.h" +#include "shared-module/picogame/Canvas.h" + +// Raw change rects collected before merging. Caps how many disjoint changes we +// track in one frame; on overflow we safely fall back to a full-screen repaint. +#define PICOGAME_RAW_RECTS 64 + +static inline bool rects_overlap(const picogame_rect_t *a, const picogame_rect_t *b) { + return a->x1 < b->x2 && b->x1 < a->x2 && a->y1 < b->y2 && b->y1 < a->y2; +} + +static inline void rect_merge(picogame_rect_t *a, const picogame_rect_t *b) { + if (b->x1 < a->x1) { + a->x1 = b->x1; + } + if (b->y1 < a->y1) { + a->y1 = b->y1; + } + if (b->x2 > a->x2) { + a->x2 = b->x2; + } + if (b->y2 > a->y2) { + a->y2 = b->y2; + } +} + +static inline long rect_area(const picogame_rect_t *r) { + return (long)(r->x2 - r->x1) * (long)(r->y2 - r->y1); +} + +// Compute up to `max_rects` mostly-disjoint dirty rectangles (screen coords) and +// update the per-sprite snapshots. Returns the rect count (0 = nothing changed). +// Collecting per-change rects (instead of one union) means scattered movers no +// longer inflate the repaint to the whole screen. +// Out-of-line rect append for compute_dirty_rects below: the old macro expanded ~30 B +// four times; a real (noinline) call keeps each site at argument setup only. +// The rect is CLIPPED to the screen first: a change wholly off-screen (the off-screen half of +// a wrapping parallax pair, a sprite parked outside) takes no slot at all - a scrolling +// background made of many wide strips would otherwise burn two slots per strip and push a +// busy scene into the full-repaint overflow every frame - and a partly visible one is +// stored at its visible size, so the merge pass works on what actually gets repainted. +static __attribute__((noinline)) void add_rect(picogame_rect_t *raw, int *nr, bool *overflow, + int screen_w, int screen_h, int x1, int y1, int x2, int y2) { + if (x1 < 0) { + x1 = 0; + } + if (y1 < 0) { + y1 = 0; + } + if (x2 > screen_w) { + x2 = screen_w; + } + if (y2 > screen_h) { + y2 = screen_h; + } + if (x1 >= x2 || y1 >= y2) { + return; // nothing visible changed + } + if (*nr < PICOGAME_RAW_RECTS) { + raw[*nr].x1 = x1; + raw[*nr].y1 = y1; + raw[*nr].x2 = x2; + raw[*nr].y2 = y2; + (*nr)++; + } else { + *overflow = true; + } +} + +int picogame_scene_compute_dirty_rects( + mp_obj_t *items, uint8_t *kinds, picogame_snapshot_t *snap, size_t n, + int screen_w, int screen_h, int ox, int oy, + picogame_rect_t *out, int max_rects) { + + picogame_rect_t raw[PICOGAME_RAW_RECTS]; + int nr = 0; + bool overflow = false; + + // Rects are stored in SCREEN coords: non-fixed items get the view offset added + // here (per item), fixed (HUD) items don't - so no uniform offset at the end. + #define ADD_RECT(ax, ay, bx, by) \ + add_rect(raw, &nr, &overflow, screen_w, screen_h, (ax) + iox, (ay) + ioy, (bx) + iox, (by) + ioy) + + for (size_t i = 0; i < n; i++) { + uint8_t rawk = kinds[i]; + uint8_t kind = rawk & PICOGAME_KIND_MASK; + // StripDraw and Triangles always composite in screen coordinates (the draw + // path never applies the view offset to them), so their dirty rects must not + // shift with the view either - otherwise a scrolled scene repaints an + // unrelated region and leaves the layer's real change stale on screen. + bool screen_space = kind == PICOGAME_KIND_STRIPDRAW || kind == PICOGAME_KIND_TRIANGLES; + int iox = ((rawk & PICOGAME_KIND_FIXED) || screen_space) ? 0 : ox; + int ioy = ((rawk & PICOGAME_KIND_FIXED) || screen_space) ? 0 : oy; + if (kind != PICOGAME_KIND_SPRITE) { + int tx1, ty1, tx2, ty2; + bool d = false; + if (kind == PICOGAME_KIND_TILEMAP) { + d = picogame_tilemap_take_dirty(MP_OBJ_TO_PTR(items[i]), &tx1, &ty1, &tx2, &ty2); + } else if (kind == PICOGAME_KIND_PARTICLES) { + d = picogame_particles_take_dirty(MP_OBJ_TO_PTR(items[i]), &tx1, &ty1, &tx2, &ty2); + } else if (kind == PICOGAME_KIND_CANVAS) { + d = picogame_canvas_take_dirty(MP_OBJ_TO_PTR(items[i]), &tx1, &ty1, &tx2, &ty2); + } else if (kind == PICOGAME_KIND_STRIPDRAW) { + // No retained pixels to diff. always_dirty -> repaint the whole rect every frame + // (animated content). Otherwise repaint only the accumulated invalidate() rect - the + // same take_dirty contract as Canvas/Tilemap, so on-change UI repaints just its region + // (and still re-runs when another layer's dirty rect overlaps it). + picogame_stripdraw_obj_t *sd = MP_OBJ_TO_PTR(items[i]); + if (sd->always_dirty) { + tx1 = sd->x; + ty1 = sd->y; + tx2 = sd->x + sd->w; + ty2 = sd->y + sd->h; + d = true; + } else { + d = picogame_dirty_take(&sd->dx1, &tx1, &ty1, &tx2, &ty2); + } + } else if (kind == PICOGAME_KIND_TRIANGLES) { + // Screen-space batch: count-set marked a full-screen dirty (clipped later). + picogame_triangles_obj_t *t = MP_OBJ_TO_PTR(items[i]); + d = picogame_dirty_take(&t->dx1, &tx1, &ty1, &tx2, &ty2); + } + if (d) { + ADD_RECT(tx1, ty1, tx2, ty2); + } + continue; + } + + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(items[i]); + picogame_snapshot_t *sn = &snap[i]; + + // Snapshot tracks the drawn screen AABB (already includes scale + rotation), + // so position/anchor/size/scale/angle/bitmap changes are all detected. + int ax1, ay1, ax2, ay2; + picogame_sprite_aabb(s, &ax1, &ay1, &ax2, &ay2); + picogame_bitmap_obj_t *bm = s->bitmap; + bool changed = (ax1 != sn->x) || (ay1 != sn->y) || + ((ax2 - ax1) != sn->w) || ((ay2 - ay1) != sn->h) || + (s->frame != sn->frame) || (s->flags != sn->flags) || + (s->scale != sn->scale) || (s->angle != sn->angle) || + (s->seq != sn->seq) || // touch(): in-place bitmap content change + (s->dither != sn->dither) || // translucency level animation + (s->flash_color != sn->flash_color) || // flash/tint colour-only change (flag stays set) + ((void *)bm != sn->bitmap); + if (!changed) { + continue; + } + + // Old rect = previous AABB (snapshot); new rect = current AABB. + if (sn->flags & PICOGAME_SPR_VISIBLE) { + ADD_RECT(sn->x, sn->y, sn->x + sn->w, sn->y + sn->h); + } + if (s->flags & PICOGAME_SPR_VISIBLE) { + ADD_RECT(ax1, ay1, ax2, ay2); + } + + sn->x = ax1; + sn->y = ay1; + sn->w = ax2 - ax1; + sn->h = ay2 - ay1; + sn->bitmap = (void *)bm; + sn->frame = s->frame; + sn->flags = s->flags; + sn->scale = s->scale; + sn->angle = s->angle; + sn->seq = s->seq; + sn->dither = s->dither; + sn->flash_color = s->flash_color; + } +#undef ADD_RECT + + if (nr == 0) { + return 0; + } + // Too many changes to track individually -> one full-screen repaint is both + // correct and likely cheaper than dozens of windows. + if (overflow) { + out[0].x1 = 0; + out[0].y1 = 0; + out[0].x2 = screen_w; + out[0].y2 = screen_h; + return 1; + } + + // Merge overlapping rects (avoids painting the same pixels twice) until stable. + bool again = true; + while (again) { + again = false; + for (int i = 0; i < nr; i++) { + for (int j = i + 1; j < nr; j++) { + if (rects_overlap(&raw[i], &raw[j])) { + rect_merge(&raw[i], &raw[j]); + raw[j] = raw[nr - 1]; + nr--; + again = true; + j--; + } + } + } + } + + // Cap the count by repeatedly merging the pair that wastes the fewest pixels. + while (nr > max_rects) { + int bi = 0, bj = 1; + long best = -1; + for (int i = 0; i < nr; i++) { + long area_i = rect_area(&raw[i]); // loop-invariant in j -> hoist out + for (int j = i + 1; j < nr; j++) { + picogame_rect_t u = raw[i]; + rect_merge(&u, &raw[j]); + long waste = rect_area(&u) - area_i - rect_area(&raw[j]); + if (best < 0 || waste < best) { + best = waste; + bi = i; + bj = j; + } + } + } + rect_merge(&raw[bi], &raw[bj]); + raw[bj] = raw[nr - 1]; + nr--; + } + + // Rects are already in screen coords (offset applied per item). Clip + drop empties. + int outn = 0; + for (int i = 0; i < nr; i++) { + int x1 = picogame_imax(raw[i].x1, 0); + int y1 = picogame_imax(raw[i].y1, 0); + int x2 = picogame_imin(raw[i].x2, screen_w); + int y2 = picogame_imin(raw[i].y2, screen_h); + if (x1 >= x2 || y1 >= y2) { + continue; + } + out[outn].x1 = x1; + out[outn].y1 = y1; + out[outn].x2 = x2; + out[outn].y2 = y2; + outn++; + } + return outn; +} diff --git a/shared-module/picogame/Scene.h b/shared-module/picogame/Scene.h new file mode 100644 index 00000000000..bd1e83937e3 --- /dev/null +++ b/shared-module/picogame/Scene.h @@ -0,0 +1,80 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame retained-mode scene with dirty-rectangle tracking. The scene owns a +// list of sprites and a snapshot of their state from the previous frame; each +// refresh diffs against the snapshot to compute the changed regions and repaints +// only those: up to PICOGAME_MAX_DIRTY_RECTS (6) mostly-disjoint rectangles, each +// rendered into its own clamped SPI window, so several separated moving objects +// stay cheap; beyond that they merge toward a fuller redraw. + +#pragma once + +#include +#include +#include +#include "py/obj.h" +#include "shared-module/picogame/Sprite.h" + +typedef struct { + int32_t x, y; + int32_t w, h; // drawn SCENE-space AABB (top-left + size) when last drawn - already accounts + // for scale + rotation, so it is the old-rect on any change. int32 (not int16): + // sprite coords are 24.8 in int32, so a big scrolling world exceeds +-32767 px + void *bitmap; // bitmap identity when last drawn (detect graphic swaps); never + // dereferenced - compared for inequality only, so it is safe + // even if the previous bitmap has since been freed + uint16_t scale; // draw scale (8.8) when last drawn - detect scale changes + int16_t angle; // rotation when last drawn - detect rotation changes + uint8_t frame; + uint8_t flags; + uint8_t seq; // sprite.seq when last drawn - detect touch() (in-place content change) + uint8_t dither; // dither level when last drawn - detect translucency animation + uint16_t flash_color; // flash/tint colour when last drawn - detect a colour-only change + // (the effect flag stays set, so without this red->blue wouldn't repaint) +} picogame_snapshot_t; + +typedef struct { + int x1, y1, x2, y2; // screen-space dirty rectangle [x1,x2) x [y1,y2) +} picogame_rect_t; + +typedef struct { + mp_obj_base_t base; + mp_obj_t display; // picogame.Display (transport; also kept alive) + mp_obj_t buf_a; // strip buffer A (kept alive) + mp_obj_t buf_b; // strip buffer B (kept alive) + mp_obj_t *items; // sprite / tilemap objects (GC-scanned -> stay alive) + uint8_t *kinds; // PICOGAME_KIND_* per item + picogame_snapshot_t *snap; // previous-frame state; snap[i] is unused when + // kinds[i] == TILEMAP (tilemaps track their own dirty rect) + uint16_t count; + uint16_t cap; + uint16_t background; + int32_t ox, oy; // view offset: screen position of scene origin (camera/centering); int32 so a + // large-world camera can scroll past +-32767 px without truncating the offset + int16_t top, bottom, left, right; // reserved insets (px): the scene renders only the + // play rect [left, w-right) x [top, h-bottom) and never touches the + // border around it - the app owns it (HUD bars, side panels, frame). + bool cleared; // false until the first full-screen paint (covers stale pixels) + bool fast; // true: display is a fast picogame.Display (DMA); false: a plain + // busdisplay rendered via the portable bus.send fallback + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + bool fb_target; // true: self->display is a picogame.Framebuffer (RAM scanout buffer); + // refresh() composites dirty rects straight into it, no bus. Mutually + // exclusive with `fast` and the busdisplay path. + #endif + mp_obj_t dirty_rect; // reusable [x1,y1,x2,y2] list returned by refresh() (no + // per-frame tuple allocation / GC churn) +} picogame_scene_obj_t; + +// Diff items against snapshots and produce up to `max_rects` mostly-disjoint +// dirty rectangles (screen coords), updating snapshots / draining layer dirties. +// Returns the rect count (0 = nothing changed). Scattered movers yield several +// small rects instead of one screen-spanning union. +int picogame_scene_compute_dirty_rects( + mp_obj_t *items, uint8_t *kinds, picogame_snapshot_t *snap, size_t n, + int screen_w, int screen_h, int ox, int oy, + picogame_rect_t *out, int max_rects); diff --git a/shared-module/picogame/Sprite.h b/shared-module/picogame/Sprite.h new file mode 100644 index 00000000000..157b94e652b --- /dev/null +++ b/shared-module/picogame/Sprite.h @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame: a positioned, animatable instance of a Bitmap. + +#pragma once + +#include +#include "py/obj.h" +#include "shared-module/picogame/Bitmap.h" + +enum { + PICOGAME_SPR_VISIBLE = 1 << 0, + PICOGAME_SPR_FLIP_X = 1 << 1, + PICOGAME_SPR_FLIP_Y = 1 << 2, + PICOGAME_SPR_SHADOW = 1 << 3, // draw opaque pixels as a darkened destination (shadow/dim) + PICOGAME_SPR_FLASH = 1 << 4, // draw opaque pixels as a solid colour (hit-flash) + PICOGAME_SPR_DITHER = 1 << 5, // skip pixels via a Bayer pattern -> fake transparency + PICOGAME_SPR_TINT = 1 << 6, // multiply opaque pixels by a colour (keeps shading) + PICOGAME_SPR_TRANSPOSE = 1 << 7, // swap x/y -> cheap 90deg (with flips = all 8 orientations) +}; + +typedef struct { + mp_obj_base_t base; + picogame_bitmap_obj_t *bitmap; + mp_obj_t data; // arbitrary user payload (game state); GC-scanned + int32_t x, y; // position, 24.8 fixed-point (1/256 px), scene coords + uint16_t anchor_x; // pivot as a 1/256 fraction of width: 0=left, 128~=center, 256=right + uint16_t anchor_y; // pivot as a 1/256 fraction of height: 0=top, 128~=center, 256=bottom + uint16_t scale; // uniform draw scale, 8.8 fixed-point (256 = 1.0x); nearest-neighbour + int16_t angle; // rotation about the anchor, whole degrees (0 = axis-aligned fast path) + uint16_t flash_color; // FLASH mode: wire-order RGB565 that replaces opaque pixels + uint8_t frame; + uint8_t flags; + uint8_t seq; // bumped by touch() to force a repaint after an in-place bitmap mutation + uint8_t dither; // DITHER mode: transparency level 0..16 (0=opaque, 16=invisible) + // ---- affine transform cache (angle != 0 path). Filled lazily on first use, invalidated + // by the scale/angle/bitmap/anchor setters (xf_valid = 0). POSITION-INDEPENDENT: the bbox + // is relative to the sprite's integer position, ic/is are the 16.16 inverse-map steps. + // Saves the trig LUT + 4-corner bbox + two software divides that otherwise re-run once per + // STRIP the sprite touches (~6x/frame at strip_h=8) plus once for the dirty-rect AABB. + uint8_t xf_valid; + int16_t xf_minx, xf_miny, xf_maxx, xf_maxy; // corners bbox relative to (x>>8, y>>8) + int32_t xf_ic, xf_is; // inverse-map steps (16.16) +} picogame_sprite_obj_t; diff --git a/shared-module/picogame/Tilemap.c b/shared-module/picogame/Tilemap.c new file mode 100644 index 00000000000..5be8efb1c37 --- /dev/null +++ b/shared-module/picogame/Tilemap.c @@ -0,0 +1,100 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "shared-module/picogame/Tilemap.h" +#include "shared-module/picogame/__init__.h" + +// Floor division for b > 0. +static inline int floordiv(int a, int b) { + return (a >= 0) ? (a / b) : -(((-a) + b - 1) / b); +} + +// log2 of a power-of-2 (small tile dims), without a __ctzsi2 lib call on the M0+ (no CLZ/RBIT). +static inline int pow2_shift(unsigned v) { + int n = 0; + while (v > 1u) { + v >>= 1; + n++; + } + return n; +} + +// Thin wrappers over the shared int32 accumulator (dx1,dy1,dx2,dy2 are contiguous int32 at the +// struct tail). See picogame_dirty_* in __init__.c. +void picogame_tilemap_dirty_reset(picogame_tilemap_obj_t *tm) { + picogame_dirty_reset(&tm->dx1); +} + +void picogame_tilemap_dirty_union(picogame_tilemap_obj_t *tm, int x1, int y1, int x2, int y2) { + picogame_dirty_union(&tm->dx1, x1, y1, x2, y2); +} + +bool picogame_tilemap_take_dirty(picogame_tilemap_obj_t *tm, int *x1, int *y1, int *x2, int *y2) { + return picogame_dirty_take(&tm->dx1, x1, y1, x2, y2); +} + +void picogame_tilemap_extent(picogame_tilemap_obj_t *tm, int *x1, int *y1, int *x2, int *y2) { + int tw = tm->tileset ? tm->tileset->width : 0; + int th = tm->tileset ? tm->tileset->height : 0; + *x1 = tm->x; + *y1 = tm->y; + *x2 = tm->x + (int)tm->map_w * tw; + *y2 = tm->y + (int)tm->map_h * th; +} + +void picogame_blit_tilemap( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_tilemap_obj_t *tm, int ox, int oy) { + picogame_bitmap_obj_t *ts = tm->tileset; + if (ts == NULL) { + return; + } + int tw = ts->width; + int th = ts->height; + int nframes = ts->frames; + + // Tilemap origin in screen coords (scene position + view offset). + int tmx = tm->x + ox; + int tmy = tm->y + oy; + + // Region in screen coords. + int rx1 = x0, ry1 = strip_top; + int rx2 = x0 + region_w, ry2 = strip_top + strip_h; + + // Tile index range overlapping the region. Tile dims are almost always powers of two (8, 16), + // where floor division is an arithmetic shift (signed >> floors toward -inf, exactly what + // floordiv does) - which skips 4 idiv per strip on the tilemap background. Non-pow2 tiles fall + // back to floordiv. (shx>=0 signals the pow2 fast path; the ctz runs twice per call, not per tile.) + int shx = (tw & (tw - 1)) ? -1 : pow2_shift((unsigned)tw); + int shy = (th & (th - 1)) ? -1 : pow2_shift((unsigned)th); + int tx_lo = (shx >= 0) ? ((rx1 - tmx) >> shx) : floordiv(rx1 - tmx, tw); + int tx_hi = (shx >= 0) ? ((rx2 - 1 - tmx) >> shx) : floordiv(rx2 - 1 - tmx, tw); + int ty_lo = (shy >= 0) ? ((ry1 - tmy) >> shy) : floordiv(ry1 - tmy, th); + int ty_hi = (shy >= 0) ? ((ry2 - 1 - tmy) >> shy) : floordiv(ry2 - 1 - tmy, th); + tx_lo = picogame_imax(tx_lo, 0); + ty_lo = picogame_imax(ty_lo, 0); + tx_hi = picogame_imin(tx_hi, (int)tm->map_w - 1); + ty_hi = picogame_imin(ty_hi, (int)tm->map_h - 1); + + const uint8_t *map = tm->map; // hoist per-tile decode invariants out of the inner loop + const uint8_t *orient = tm->orient; + int map_w = (int)tm->map_w; + for (int ty = ty_lo; ty <= ty_hi; ty++) { + int dy = tmy + ty * th; + size_t row = (size_t)ty * map_w; + for (int tx = tx_lo; tx <= tx_hi; tx++) { + size_t cell = row + tx; + uint8_t idx = map[cell]; + if (idx >= nframes) { + continue; + } + uint8_t o = orient ? orient[cell] : 0; + int dx = tmx + tx * tw; + picogame_blit_bitmap(buf, region_w, strip_h, x0, strip_top, + ts, dx, dy, idx, (o & 1) != 0, (o & 2) != 0, (o & 4) != 0, NULL); + } + } +} diff --git a/shared-module/picogame/Tilemap.h b/shared-module/picogame/Tilemap.h new file mode 100644 index 00000000000..e06e0a626b1 --- /dev/null +++ b/shared-module/picogame/Tilemap.h @@ -0,0 +1,44 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame Tilemap: a grid of tile indices into a tileset Bitmap (each tile = one +// frame of the bitmap). Rendered as a Scene layer; maintains an accumulated dirty +// rectangle (screen coords) so only changed tiles/areas are repainted. + +#pragma once + +#include +#include +#include "py/obj.h" +#include "shared-module/picogame/Bitmap.h" + +typedef struct { + mp_obj_base_t base; + picogame_bitmap_obj_t *tileset; // each frame is a tile (tileset->width x height) + mp_obj_t tileset_obj; // keep alive + uint8_t *map; // map_w*map_h tile indices + mp_obj_t map_obj; // keep alive + uint8_t *orient; // map_w*map_h orientation bits (bit0 flipX, bit1 flipY, + // bit2 transpose); NULL until a tile sets an orientation + mp_obj_t orient_obj; // keep alive (lazily allocated) + uint16_t map_w, map_h; + int32_t x, y; // pixel position of tile (0,0) (int32: big maps scroll past +-32767) + int32_t dx1, dy1, dx2, dy2; // accumulated dirty rect (scene coords; int32, see x/y); x1>=x2 => empty +} picogame_tilemap_obj_t; + +void picogame_tilemap_dirty_reset(picogame_tilemap_obj_t *tm); +void picogame_tilemap_dirty_union(picogame_tilemap_obj_t *tm, int x1, int y1, int x2, int y2); +// Returns true and fills the dirty rect if non-empty, then resets it. +bool picogame_tilemap_take_dirty(picogame_tilemap_obj_t *tm, int *x1, int *y1, int *x2, int *y2); + +// On-screen bounding box of the whole map. +void picogame_tilemap_extent(picogame_tilemap_obj_t *tm, int *x1, int *y1, int *x2, int *y2); + +// Blit the tiles intersecting the strip region into buf. (ox, oy) is the view +// offset added to the tilemap position (scene space -> screen space). +void picogame_blit_tilemap( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_tilemap_obj_t *tm, int ox, int oy); diff --git a/shared-module/picogame/__init__.c b/shared-module/picogame/__init__.c new file mode 100644 index 00000000000..ddd700959ed --- /dev/null +++ b/shared-module/picogame/__init__.c @@ -0,0 +1,1329 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame portable render core: strip-based, arbitrary-size blitting. +// Painter's order: clear strip to background, draw layers/sprites bottom-to-top. + +#include +#include +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Tilemap.h" +#include "shared-module/picogame/Particles.h" +#include "shared-module/picogame/Canvas.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/displayio/display_core.h" +#include "shared-bindings/displayio/__init__.h" + +// Shared dirty-rect accumulator over a contiguous int32 [x1,y1,x2,y2]. Canvas and Tilemap both end in +// `int32_t dx1,dy1,dx2,dy2`, so their public dirty fns are thin wrappers passing &self->dx1 here. +// Sentinels are the INT32 extremes (not int16) so a big-world scene coord past +-32767 px still +// accumulates correctly. +void picogame_dirty_reset(int32_t *r) { + r[0] = 0x7fffffff; + r[1] = 0x7fffffff; + r[2] = -0x7fffffff - 1; + r[3] = -0x7fffffff - 1; +} + +void picogame_dirty_union(int32_t *r, int x1, int y1, int x2, int y2) { + if (x1 < r[0]) { + r[0] = x1; + } + if (y1 < r[1]) { + r[1] = y1; + } + if (x2 > r[2]) { + r[2] = x2; + } + if (y2 > r[3]) { + r[3] = y2; + } +} + +bool picogame_dirty_take(int32_t *r, int *x1, int *y1, int *x2, int *y2) { + bool dirty = (r[0] < r[2]) && (r[1] < r[3]); + if (dirty) { + *x1 = r[0]; + *y1 = r[1]; + *x2 = r[2]; + *y2 = r[3]; + } + picogame_dirty_reset(r); + return dirty; +} + +// Halve each RGB565 channel of a wire-order pixel (50% darken, for shadow mode). +static inline uint16_t picogame_darken(uint16_t wire) { + uint16_t c = (uint16_t)((wire >> 8) | (wire << 8)); // wire -> native RGB565 + // Halve all three channels at once: >>1 shifts every channel right; the 0x7BEF mask clears the two + // bits that would bleed across channel boundaries (R's LSB into G's MSB, G's LSB into B's MSB) + + // R's now-0 top bit. Bit-identical to the per-channel r>>1/g>>1/b>>1 above, ~half the instructions. + uint16_t o = (uint16_t)((c >> 1) & 0x7BEF); + return (uint16_t)((o >> 8) | (o << 8)); // native -> wire +} + +// 4x4 ordered (Bayer) dither thresholds, 0..15. +static const uint8_t picogame_bayer4[4][4] = { + { 0, 8, 2, 10 }, + { 12, 4, 14, 6 }, + { 3, 11, 1, 9 }, + { 15, 7, 13, 5 }, +}; + +// Multiply two wire-order RGB565 pixels per channel (TINT: colour the source, keep its shading). +static inline uint16_t picogame_mul565(uint16_t a, uint16_t b) { + uint16_t ca = (uint16_t)((a >> 8) | (a << 8)); + uint16_t cb = (uint16_t)((b >> 8) | (b << 8)); + // /31 and /63 via reciprocal-multiply (bit-identical over the full product domain 0..961 / 0..3969): + // avoids a soft-divide per tinted pixel on M0+ (no HW divide); pure integer, fine on every MCU. + uint16_t r = (uint16_t)((((ca >> 11) & 0x1f) * ((cb >> 11) & 0x1f) * 529) >> 14); + uint16_t g = (uint16_t)((((ca >> 5) & 0x3f) * ((cb >> 5) & 0x3f) * 2081) >> 17); + uint16_t bl = (uint16_t)(((ca & 0x1f) * (cb & 0x1f) * 529) >> 14); + uint16_t o = (uint16_t)((r << 11) | (g << 5) | bl); + return (uint16_t)((o >> 8) | (o << 8)); +} + +// Write one opaque source pixel through the effect. (x, y) are screen coords (for DITHER). +static inline void picogame_fx_put(uint16_t *dst, uint16_t src, int x, int y, const picogame_fx_t *fx) { + if (fx == NULL) { + *dst = src; + return; + } + switch (fx->mode) { + case PICOGAME_FX_SHADOW: + *dst = picogame_darken(*dst); + break; + case PICOGAME_FX_FLASH: + *dst = fx->color; + break; + case PICOGAME_FX_TINT: + *dst = picogame_mul565(src, fx->color); // colour the sprite, keep its shading + break; + case PICOGAME_FX_DITHER: + if (picogame_bayer4[y & 3][x & 3] >= fx->level) { + *dst = src; // else: pixel skipped -> shows through + } + break; + default: + *dst = src; + break; + } +} + +// Fetch one source pixel from HOISTED scalars: the caller lifts format/data/palette/transparency +// out of the bitmap struct ONCE before its loop, so this does no per-pixel reload of bm fields (a +// `*dst` uint16_t store would otherwise force GCC to reload bm's uint16_t members every pixel). `idx` +// is the linear source offset (srow + sx). Returns false on the transparent key. Used by the scaled / +// affine / transpose paths; the unscaled fast path inlines the read directly. + +void picogame_blit_bitmap( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int dx0, int dy0, int frame, bool fx, bool fy, + bool transpose, const picogame_fx_t *fxm) { + if (bm == NULL) { + return; + } + // Point fxm at a stack copy: its fields (uint16_t color) can't then alias the *dst stores, so the + // effect params stay in registers across the pixel loop instead of reloading every pixel. + picogame_fx_t fxl; + if (fxm != NULL) { + fxl = *fxm; + fxm = &fxl; + } + int sw = bm->width; + int sh = bm->height; + + // Guard the frame index: sprite.frame is a free uint8_t, so an out-of-range + // value (bad wrap / overflow in game code) would read past the sheet data. + // Wrap into [0, frames) - cheap and animation-friendly. + if (bm->frames > 1) { + if (frame >= bm->frames) { // common case is in range: pay a compare, not a divide + frame %= bm->frames; + } + } else { + frame = 0; + } + + int frame_col0 = frame * sw; + int stride0 = bm->stride; + + // Transpose path: swap source x/y (a cheap 90deg rotate when combined with flips -> all 8 + // orientations, no cos/sin/affine). The drawn footprint swaps to sh x sw. Per-pixel sampling + // (no per-row srow precompute), used only when requested; flips + fx still apply. + if (transpose) { + int dw = sh, dh = sw; // footprint swaps + int xs = picogame_imax(dx0, ox), ys = picogame_imax(dy0, oy); + int xe = picogame_imin(dx0 + dw, ox + bw), ye = picogame_imin(dy0 + dh, oy + bh); + if (xs >= xe || ys >= ye) { + return; + } + int t_fmt = bm->format; // hoist bm fields once (see src_pixel_s) + const uint8_t *t_data = bm->data; + const uint16_t *t_pal = bm->palette; + bool t_transp = bm->has_transparent; + uint16_t t_key = bm->transparent; + for (int y = ys; y < ye; y++) { + int ly = y - dy0; // -> source X (0..sw-1) + int su = fx ? sw - 1 - ly : ly; // per-row: source column is constant across the row + uint16_t *dst = buf + (y - oy) * bw + (xs - ox); + int lx = xs - dx0; + int sv = fy ? sh - 1 - lx : lx; // source row: step it, no per-pixel ternary + int svstep = fy ? -1 : 1; + for (int x = xs; x < xe; x++) { + uint16_t val; + if (src_pixel_s(t_fmt, t_data, t_pal, t_transp, t_key, + sv * stride0 + frame_col0 + su, &val)) { + picogame_fx_put(dst, val, x, y, fxm); + } + dst++; + sv += svstep; + } + } + return; + } + + int x_start = picogame_imax(dx0, ox); + int y_start = picogame_imax(dy0, oy); + int x_end = picogame_imin(dx0 + sw, ox + bw); + int y_end = picogame_imin(dy0 + sh, oy + bh); + if (x_start >= x_end || y_start >= y_end) { + return; + } + + int frame_col = frame * sw; + int stride = bm->stride; + bool transp = bm->has_transparent; + + if (bm->format == PICOGAME_FMT_PAL8) { + const uint8_t *data = bm->data; + const uint16_t *pal = bm->palette; + uint8_t key = (uint8_t)bm->transparent; + // Contract: PAL8 indices MUST be < palette length (caller's responsibility). An out-of-range + // index is undefined behaviour: it reads past the palette - usually a garbage colour, but on + // some heap layouts / platforms (e.g. ESP32-S3 heap_caps regions) it CAN fault. We deliberately + // do NOT clamp per pixel: that cost ~3 cyc/px (cmp+sbcs+ands) here, ~8% on blit-bound frames. + // + // TO RESTORE FULL BOUNDS-SAFETY (at that cost) reinstate the clamp - add `unsigned pe = + // bm->pal_entries;` here and `if (idx >= pe) { idx = 0; }` after each `idx = data[...]` in BOTH + // loops below, and the matching guard in src_pixel() (search "blit contract"). + for (int y = y_start; y < y_end; y++) { + int sy = y - dy0; + if (fy) { + sy = sh - 1 - sy; + } + int srow = sy * stride + frame_col; + uint16_t *dst = buf + (y - oy) * bw + (x_start - ox); + int sx = x_start - dx0, xstep = 1; // hoist flip_x: walk sx +/-1, no per-pixel test + if (fx) { + sx = sw - 1 - sx; + xstep = -1; + } + if (fxm == NULL) { // plain copy (most sprites): no per-pixel fx branch/call + #pragma GCC unroll 4 // hot path: unrolling the plain sprite blit is ~6% faster on M0+ (measured), +0.6KB + for (int x = x_start; x < x_end; x++) { + uint8_t idx = data[srow + sx]; + if (!transp || idx != key) { + *dst = pal[idx]; + } + dst++; + sx += xstep; + } + } else { + for (int x = x_start; x < x_end; x++) { + uint8_t idx = data[srow + sx]; + if (!transp || idx != key) { + picogame_fx_put(dst, pal[idx], x, y, fxm); + } + dst++; + sx += xstep; + } + } + } + } else { // PICOGAME_FMT_RGB565 + // bm->data is a GC-allocated Python buffer (>=4-byte aligned), so the 16-bit + // view is safe; xtensa's -Wcast-align can't see that, so silence it here. + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + const uint16_t *data = (const uint16_t *)bm->data; + #pragma GCC diagnostic pop + uint16_t key = bm->transparent; + for (int y = y_start; y < y_end; y++) { + int sy = y - dy0; + if (fy) { + sy = sh - 1 - sy; + } + int srow = sy * stride + frame_col; + uint16_t *dst = buf + (y - oy) * bw + (x_start - ox); + int sx = x_start - dx0, xstep = 1; // hoist flip_x: walk sx +/-1, no per-pixel test + if (fx) { + sx = sw - 1 - sx; + xstep = -1; + } + if (fxm == NULL) { // plain copy (most sprites): no per-pixel fx branch/call + if (!transp && !fx) { // opaque + not x-flipped: the row is contiguous in + // both src and dst -> one memcpy (dst may be 2-byte aligned; memcpy handles that). + memcpy(dst, &data[srow + sx], (size_t)(x_end - x_start) * 2u); + continue; + } + #pragma GCC unroll 4 // hot path: unrolling the plain sprite blit is ~6% faster on M0+ (measured), +0.6KB + for (int x = x_start; x < x_end; x++) { + uint16_t v = data[srow + sx]; + if (!transp || v != key) { + *dst = v; + } + dst++; + sx += xstep; + } + } else { + for (int x = x_start; x < x_end; x++) { + uint16_t v = data[srow + sx]; + if (!transp || v != key) { + picogame_fx_put(dst, v, x, y, fxm); + } + dst++; + sx += xstep; + } + } + } + } +} + + +void picogame_blit_bitmap_scaled( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int dx0, int dy0, int frame, bool fx, bool fy, + uint16_t scale, const picogame_fx_t *fxm) { + if (bm == NULL || scale == 0) { + return; + } + picogame_fx_t fxl; // stack copy: fields don't alias *dst (see blit_bitmap) + if (fxm != NULL) { + fxl = *fxm; + fxm = &fxl; + } + int sw = bm->width, sh = bm->height; + if (bm->frames > 1) { + if (frame >= bm->frames) { // common case is in range: pay a compare, not a divide + frame %= bm->frames; + } + } else { + frame = 0; + } + int dw = (sw * scale) >> 8, dh = (sh * scale) >> 8; + if (dw <= 0 || dh <= 0) { + return; + } + int x_start = picogame_imax(dx0, ox), y_start = picogame_imax(dy0, oy); + int x_end = picogame_imin(dx0 + dw, ox + bw), y_end = picogame_imin(dy0 + dh, oy + bh); + if (x_start >= x_end || y_start >= y_end) { + return; + } + int frame_col = frame * sw, stride = bm->stride; + int s_fmt = bm->format; // hoist bm fields once (see src_pixel_s) + const uint8_t *s_data = bm->data; + const uint16_t *s_pal = bm->palette; + bool s_transp = bm->has_transparent; + uint16_t s_key = bm->transparent; + if (scale == 512 && !fx && !fy && fxm == NULL && !s_transp && s_fmt == PICOGAME_FMT_RGB565 + && (((uintptr_t)s_data & 1) == 0)) { + // 2x integer upscale fast path - the half-res-canvas genre's per-frame blit (a full-screen + // RGB565 bitmap shown through a scale-2 sprite). At scale 512 the DDA step is exactly 2^15, + // so sampling collapses to (rel >> 1): write each source pixel twice, and when two dest rows + // share a source row, memcpy the second from the first (half the reads). Byte-exact vs the + // generic loop (host-verified over 300k random windows/clips/parities). + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + const uint16_t *sd16 = (const uint16_t *)s_data; + #pragma GCC diagnostic pop + int prev_sy = -1; + uint16_t *prev_row = NULL; + int nwin = x_end - x_start; + for (int y = y_start; y < y_end; y++) { + int sy = (y - dy0) >> 1; + uint16_t *drow = buf + (y - oy) * bw + (x_start - ox); + if (sy == prev_sy && prev_row != NULL) { + memcpy(drow, prev_row, (size_t)nwin * 2); + } else { + const uint16_t *srow = sd16 + sy * stride + frame_col; + int rel = x_start - dx0; + uint16_t *d = drow; + int n = nwin; + if (rel & 1) { // leading odd dest column + *d++ = srow[rel >> 1]; + rel++; + n--; + } + const uint16_t *sp = srow + (rel >> 1); + while (n >= 2) { + uint16_t v = *sp++; + d[0] = v; + d[1] = v; + d += 2; + n -= 2; + } + if (n) { + *d = *sp; + } + } + prev_sy = sy; + prev_row = drow; + } + return; + } + if (scale >= 512 && (scale & (scale - 1)) == 0 && !fx && !fy && fxm == NULL && !s_transp + && s_fmt == PICOGAME_FMT_PAL8) { + // Integer upscale, PAL8 - the same idea as the RGB565 2x path above (which exists for the + // half-res-canvas genre), for the format the engine's art actually uses, and for ANY integer + // factor rather than just 2. At an integer scale the DDA collapses: every source pixel maps + // to exactly `nrep` dest pixels and every source row to `nrep` dest rows, so a row is + // rasterized once and its repeats are memcpy'd. + // + // WHY IT MATTERS - it is a RAM technique, not just a speed one: art kept at 1/nrep and + // upscaled costs 1/nrep^2 of the bitmap. A 320x100 PAL8 parallax band is 31.2 kB at 1:1 but + // 7.8 kB at half size, and RP2040 has 25-40 kB of heap. Making the upscale cheap is what + // makes that trade attractive instead of merely possible. + // + // Transparency is deliberately NOT handled here: a skipped pixel must keep ITS OWN row's + // background, so the repeats cannot be memcpy'd, and measurement showed the remaining win + // (0.1-0.2 ms on the small transparent sprites that actually exist) did not justify the flash. + const int nrep = scale >> 8; + const int dy_rel = y_start - dy0, dx_rel = x_start - dx0; + int sy = dy_rel / nrep; + int rem = nrep - (dy_rel % nrep); // dest rows this source row still owns + const int sx0 = dx_rel / nrep, hoff = dx_rel % nrep; + const int nwin = x_end - x_start; + bool draw = true; + uint16_t *rep_from = NULL; + for (int y = y_start; y < y_end; y++) { + uint16_t *drow = buf + (y - oy) * bw + (x_start - ox); + if (draw) { + const uint8_t *sp = s_data + sy * stride + frame_col + sx0; + uint16_t *d = drow; + int n = nwin; + int first = nrep - hoff; // the leading source pixel may be partly clipped + if (first > n) { + first = n; + } + uint16_t c = s_pal[*sp++]; + for (int i = 0; i < first; i++) { + *d++ = c; + } + n -= first; + if (nrep == 2) { // the common case, unrolled: two stores, no counter + while (n >= 2) { + c = s_pal[*sp++]; + d[0] = c; + d[1] = c; + d += 2; + n -= 2; + } + } else { + while (n >= nrep) { + c = s_pal[*sp++]; + for (int i = 0; i < nrep; i++) { + *d++ = c; + } + n -= nrep; + } + } + if (n) { // trailing partial group + c = s_pal[*sp]; + while (n--) { + *d++ = c; + } + } + rep_from = drow; + draw = false; + } else { + memcpy(drow, rep_from, (size_t)nwin * 2); + } + if (--rem == 0) { + sy++; + rem = nrep; + draw = true; + } + } + return; + } + uint32_t step = ((uint32_t)1 << 24) / scale; // source px per dest px, 16.16 + // No per-row sy>=sh / per-pixel sx>=sw clamp: with dw=(sd*scale)>>8 and step=floor(2^24/scale), + // the sampled index ((dw-1)*step)>>16 provably never reaches the source dimension (exhaustively + // verified over the ENTIRE uint16 x uint16 (scale, dim) domain, 0 violations), and xacc> 16); + if (fy) { + sy = sh - 1 - sy; + } + int srow = sy * stride + frame_col; + uint16_t *drow = buf + (y - oy) * bw; + uint32_t xacc = (uint32_t)(x_start - dx0) * step; + for (int x = x_start; x < x_end; x++) { + int sx = (int)(xacc >> 16); + xacc += step; + if (fx) { + sx = sw - 1 - sx; + } + uint16_t val; + if (src_pixel_s(s_fmt, s_data, s_pal, s_transp, s_key, srow + sx, &val)) { + picogame_fx_put(&drow[x - ox], val, x, y, fxm); + } + } + } +} + +// Quarter-wave Q15 sine table (0..90 deg) -> fixed-point trig for the rotation setup, so the +// affine path needs no float `sinf`/`cosf` (RP2040 has no FPU). cos(d) = sin(d+90). +static const int16_t pg_sin_q15_quad[91] = { + 0, 572, 1144, 1715, 2286, 2856, 3425, 3993, 4560, 5126, + 5690, 6252, 6813, 7371, 7927, 8481, 9032, 9580, 10126, 10668, + 11207, 11743, 12275, 12803, 13328, 13848, 14364, 14876, 15383, 15886, + 16383, 16876, 17364, 17846, 18323, 18794, 19260, 19720, 20173, 20621, + 21062, 21497, 21925, 22347, 22762, 23170, 23571, 23964, 24351, 24730, + 25101, 25465, 25821, 26169, 26509, 26841, 27165, 27481, 27788, 28087, + 28377, 28659, 28932, 29196, 29451, 29697, 29934, 30162, 30381, 30591, + 30791, 30982, 31163, 31335, 31498, 31650, 31794, 31927, 32051, 32165, + 32269, 32364, 32448, 32523, 32587, 32642, 32687, 32722, 32747, 32762, + 32767, +}; +static int32_t pg_sin_q15(int deg) { + deg %= 360; + if (deg < 0) { + deg += 360; + } + if (deg <= 90) { + return pg_sin_q15_quad[deg]; + } + if (deg <= 180) { + return pg_sin_q15_quad[180 - deg]; + } + if (deg <= 270) { + return -pg_sin_q15_quad[deg - 180]; + } + return -pg_sin_q15_quad[360 - deg]; +} +static int32_t pg_cos_q15(int deg) { + return pg_sin_q15(deg + 90); +} + +// sin of a Q16 degree angle: lerp between whole-degree LUT entries. The racing-road curvature is +// DOUBLE-integrated over ~170 rows, which amplifies whole-degree quantization into visible pixels +// (host-measured 9 px); one lerp per curvature eval brings the road within 1 px of the float original. +static int32_t pg_sin_q15_lerp(int64_t deg_q16) { + int d0 = (int)(deg_q16 >> 16); + int32_t frac = (int32_t)(deg_q16 & 0xFFFF); + int32_t a = pg_sin_q15(d0); + return a + (int32_t)(((int64_t)(pg_sin_q15(d0 + 1) - a) * frac) >> 16); +} + +// One racing-road frame's curve pass: the bottom-up curvature accumulator + per-row integer edges +// (the OutRun-genre "compute_road" loop - profiled at ~8-10 ms of Python on picobike; this is the +// batch-boundary rule in action: one C call does the frame's whole row loop). Fixed-point throughout: +// cx/ddx accumulate in Q16, curvature = two LUT sines of the world distance. cfg (int32[7]): +// [f1_q20, f2_q20, amp1k_q16, amp2k_q16, world_step, curve_step, d_row_off] - frequencies in +// Q20 degrees/world-unit (Q16 phase-drifts over a long run), amplitudes premultiplied by the +// per-row gain k, curvature re-evaluated every curve_step rows (it varies slowly). Edge stores use +// trunc-toward-zero to match the Python original's int(). Host-proven <=1 px absolute AND row-delta +// smoothness vs the float reference over 8k+ frames (road_edges_test.c). +void picogame_road_edges(int16_t *rl, int16_t *rr, const int32_t *hw_q16, int n, + int32_t cx_q16, int32_t dist, const int32_t *cfg) { + int32_t f1 = cfg[0], f2 = cfg[1], a1k = cfg[2], a2k = cfg[3]; + int32_t wstep = cfg[4], cstep = cfg[5], drow = cfg[6]; + int32_t cx = cx_q16, ddx = 0, ck = 0; + int cnt = 0; + for (int i = n - 1; i >= 0; i--) { + if (cnt == 0) { + int32_t d = dist + (drow - i) * wstep; + ck = (int32_t)(((int64_t)pg_sin_q15_lerp(((int64_t)d * f1) >> 4) * a1k) >> 15) + + (int32_t)(((int64_t)pg_sin_q15_lerp(((int64_t)d * f2) >> 4) * a2k) >> 15); + cnt = cstep; + } + cnt--; + ddx += ck; + cx += ddx; + int32_t vl = cx - hw_q16[i], vr = cx + hw_q16[i]; + rl[i] = (int16_t)(vl >= 0 ? (vl >> 16) : -((-vl) >> 16)); + rr[i] = (int16_t)(vr >= 0 ? (vr >> 16) : -((-vr) >> 16)); + } +} + + +// Forward-transform a w*h rect's 4 corners through (integer pivot, 8.8 scale, Q15 rotation) and +// return the screen-space AABB. INTEGER (Q16) - measured ~40x faster than the old float version on +// the M0+ flagship (soft-float), and faster on every target (measured affine_q16 vs affine_float). +// Runs once per rotated sprite (not per pixel). Each corner is FLOORED (arithmetic >>23 = /(256*32768)), +// so the returned box is <= the true min and the callers' +1/+2 keep the box CONTAINING the sprite +// (the affine blitter clips per pixel anyway, so a >=1px-too-large box only repaints, never clips). +static void corners_bbox(int sw, int sh, int px, int py, int pivx, int pivy, + int32_t scale, int32_t cos_q, int32_t sin_q, int *minx, int *miny, int *maxx, int *maxy) { + int nx = 1 << 30, xx = -(1 << 30), ny = 1 << 30, xy = -(1 << 30); + int cxs[4] = { 0, sw, 0, sw }, cys[4] = { 0, 0, sh, sh }; + for (int k = 0; k < 4; k++) { + int64_t du = (int64_t)(cxs[k] - pivx) * scale; // (corner - pivot) in pixels<<8 + int64_t dv = (int64_t)(cys[k] - pivy) * scale; + int X = px + (int)((du * cos_q - dv * sin_q) >> 23); // >>23 = /(256 * 32768): drop the 8.8 + Q15 + int Y = py + (int)((du * sin_q + dv * cos_q) >> 23); + if (X < nx) { + nx = X; + } + if (X > xx) { + xx = X; + } + if (Y < ny) { + ny = Y; + } + if (Y > xy) { + xy = Y; + } + } + *minx = nx; + *miny = ny; + *maxx = xx; + *maxy = xy; +} + +// Fill the sprite's affine cache (position-relative bbox + 16.16 inverse-map steps) if stale. +// The trig LUT, the 4-corner bbox and the TWO SOFTWARE DIVIDES below used to re-run once per +// strip a rotated sprite touched (~6x/frame at strip_h=8) plus once for the dirty-rect AABB; +// now once per angle/scale/bitmap/anchor change (those setters clear xf_valid). +static void sprite_xform_fill(picogame_sprite_obj_t *s) { + if (s->xf_valid) { + return; + } + int w = (s->bitmap != NULL) ? s->bitmap->width : 0; + int h = (s->bitmap != NULL) ? s->bitmap->height : 0; + int pivx = ((int)s->anchor_x * w) >> 8, pivy = ((int)s->anchor_y * h) >> 8; + int32_t cos_q = pg_cos_q15(s->angle), sin_q = pg_sin_q15(s->angle); // Q15 LUT trig + int minx, miny, maxx, maxy; + corners_bbox(w, h, 0, 0, pivx, pivy, (int32_t)s->scale, cos_q, sin_q, + &minx, &miny, &maxx, &maxy); + // Saturate into the int16 cache fields: an extreme scale x size (public scale allows + // ~256x) could exceed +-32767; a saturated bbox only over/under-covers the clip - the + // blitter clips per strip anyway - instead of wrapping into a wrong-sign rect. + s->xf_minx = (int16_t)(minx < -32768 ? -32768 : (minx > 32767 ? 32767 : minx)); + s->xf_miny = (int16_t)(miny < -32768 ? -32768 : (miny > 32767 ? 32767 : miny)); + s->xf_maxx = (int16_t)(maxx < -32768 ? -32768 : (maxx > 32767 ? 32767 : maxx)); + s->xf_maxy = (int16_t)(maxy < -32768 ? -32768 : (maxy > 32767 ? 32767 : maxy)); + // inverse map (16.16 fixed-point): u = pivx + (ic*(X-px) + is*(Y-py)); + // v = pivy + (-is*(X-px) + ic*(Y-py)) + // ic = (cs/sf)*65536 = cos_q15 * 512 / scale - computed in pure integer (no float). + int32_t nic = cos_q * 512, nis = sin_q * 512; + int sc = (int)s->scale; + if (sc < 1) { + sc = 1; // scale is setter-clamped >= 1; belt for a zeroed struct + } + s->xf_ic = (nic >= 0 ? nic + sc / 2 : nic - sc / 2) / sc; + s->xf_is = (nis >= 0 ? nis + sc / 2 : nis - sc / 2) / sc; + s->xf_valid = 1; +} + +void picogame_blit_bitmap_affine( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int px, int py, int pivx, int pivy, + int frame, bool fx, bool fy, + int minx, int miny, int maxx, int maxy, int32_t ic, int32_t is, + const picogame_fx_t *fxm) { + if (bm == NULL) { + return; + } + picogame_fx_t fxl; // stack copy: fields don't alias *dst (see blit_bitmap) + if (fxm != NULL) { + fxl = *fxm; + fxm = &fxl; + } + int sw = bm->width, sh = bm->height; + if (bm->frames > 1) { + if (frame >= bm->frames) { // common case is in range: pay a compare, not a divide + frame %= bm->frames; + } + } else { + frame = 0; + } + int frame_col = frame * sw, stride = bm->stride; + int a_fmt = bm->format; // hoist bm fields once (see src_pixel_s) + const uint8_t *a_data = bm->data; + const uint16_t *a_pal = bm->palette; + bool a_transp = bm->has_transparent; + uint16_t a_key = bm->transparent; + int x_start = picogame_imax(minx, ox), y_start = picogame_imax(miny, oy); + int x_end = picogame_imin(maxx + 1, ox + bw), y_end = picogame_imin(maxy + 1, oy + bh); + if (x_start >= x_end || y_start >= y_end) { + return; + } + // Fold flip_x/flip_y into the inverse map ONCE, so the inner loop samples the FINAL source coord + // directly - no per-pixel `sw-1-iu`/`sh-1-iv` and no fx/fy branch (one loop variant, fewer live + // values -> fewer register spills). Exact: mirroring u is u'=(sw-1)-u; through the 16.16 floor that + // is `((sw-1-pivx)<<16 + 0xFFFF) - (ic*dxf + is*dyf)`, i.e. negate the u steps + bias the pivot by + // 0xFFFF (so floor(u') == (sw-1) - floor(u) for every in-range pixel). Bit-identical output. + int32_t uxc = ic, uyc = is, upiv = (int32_t)pivx << 16; // u = upiv + uxc*dxf + uyc*dyf + int32_t vxc = -is, vyc = ic, vpiv = (int32_t)pivy << 16; // v = vpiv + vxc*dxf + vyc*dyf + if (fx) { + uxc = -ic; + uyc = -is; + upiv = ((int32_t)(sw - 1 - pivx) << 16) + 0xFFFF; + } + if (fy) { + vxc = is; + vyc = -ic; + vpiv = ((int32_t)(sh - 1 - pivy) << 16) + 0xFFFF; + } + // 32-bit 16.16 accumulators (cheaper than 64-bit on the M0+). Peak magnitude stays well within + // int32 for any sane sprite on a handheld screen. The bounds check keeps an out-of-range sample + // memory-safe (at worst a skipped pixel), never a crash. + for (int y = y_start; y < y_end; y++) { + int dyf = y - py; + int dxf = x_start - px; + int32_t uacc = upiv + uxc * dxf + uyc * dyf; + int32_t vacc = vpiv + vxc * dxf + vyc * dyf; + uint16_t *drow = buf + (y - oy) * bw; + for (int x = x_start; x < x_end; x++) { + int su = uacc >> 16, sv = vacc >> 16; // already the flipped source coords + uacc += uxc; + vacc += vxc; + if (su >= 0 && su < sw && sv >= 0 && sv < sh) { + uint16_t val; + if (src_pixel_s(a_fmt, a_data, a_pal, a_transp, a_key, + sv * stride + frame_col + su, &val)) { + picogame_fx_put(&drow[x - ox], val, x, y, fxm); + } + } + } + } +} + +void picogame_sprite_aabb(const picogame_sprite_obj_t *s, int *x1, int *y1, int *x2, int *y2) { + int w = (s->bitmap != NULL) ? s->bitmap->width : 0; + int h = (s->bitmap != NULL) ? s->bitmap->height : 0; + if (s->angle == 0) { + int sw = (w * s->scale) >> 8, sh = (h * s->scale) >> 8; + if ((s->flags & PICOGAME_SPR_TRANSPOSE) && s->scale == 256) { // transpose only on the fast + int t = sw; // path (scale==256); scaled blitter ignores it, so + sw = sh; // swapping here for scale!=256 would mistrack -> trail + sh = t; + } + int tx = (s->x >> 8) - ((int)s->anchor_x * sw >> 8); + int ty = (s->y >> 8) - ((int)s->anchor_y * sh >> 8); + *x1 = tx; + *y1 = ty; + *x2 = tx + sw; + *y2 = ty + sh; + return; + } + // cache-fill mutates only the derived xf_* fields - logically const for callers + sprite_xform_fill((picogame_sprite_obj_t *)s); + int px = s->x >> 8, py = s->y >> 8; + *x1 = px + s->xf_minx - 1; + *y1 = py + s->xf_miny - 1; + *x2 = px + s->xf_maxx + 2; + *y2 = py + s->xf_maxy + 2; +} + +// TINT on a PAL8 sprite is baked into a stack palette (see blit_sprite) when the palette fits this +// cap, else it falls back to the per-pixel tint. 64 entries = 128 B of transient stack. +#define PICOGAME_TINT_PAL_CAP 64 + +// clip_x/clip_y = the strip buffer's screen origin; vx/vy = view offset added to +// the sprite's scene position to get its screen position. +static void blit_sprite(uint16_t *buf, int bw, int bh, int clip_x, int clip_y, + picogame_sprite_obj_t *spr, int vx, int vy) { + bool fx = (spr->flags & PICOGAME_SPR_FLIP_X) != 0; + bool fy = (spr->flags & PICOGAME_SPR_FLIP_Y) != 0; + bool tr = (spr->flags & PICOGAME_SPR_TRANSPOSE) != 0; // 90deg transpose (fast path only) + // One effect at a time (dither > flash > tint > shadow priority); NULL = no effect (fast path). + picogame_fx_t fxm = { PICOGAME_FX_NONE, 0, 0 }; + if (spr->flags & PICOGAME_SPR_DITHER) { + fxm.mode = PICOGAME_FX_DITHER; + fxm.level = spr->dither; + } else if (spr->flags & PICOGAME_SPR_FLASH) { + fxm.mode = PICOGAME_FX_FLASH; + fxm.color = spr->flash_color; + } else if (spr->flags & PICOGAME_SPR_TINT) { + fxm.mode = PICOGAME_FX_TINT; + fxm.color = spr->flash_color; // shared colour field (flash/tint exclusive) + } else if (spr->flags & PICOGAME_SPR_SHADOW) { + fxm.mode = PICOGAME_FX_SHADOW; + } + const picogame_fx_t *fxp = (fxm.mode == PICOGAME_FX_NONE) ? NULL : &fxm; + // TINT of a PAL8 sprite is a pure function of the palette index -> bake it into a stack palette + // ONCE and blit plain, instead of picogame_mul565 per pixel (~4x on tinted PAL8 sprites; the + // dominant sprite format). Small palettes only; larger ones keep the per-pixel tint. Transparency + // is keyed on the INDEX before the palette lookup, so the (unused) tinted key entry is harmless. + picogame_bitmap_obj_t *bmuse = spr->bitmap; + picogame_bitmap_obj_t bmtint; + uint16_t tpal[PICOGAME_TINT_PAL_CAP]; + if (fxp != NULL && fxm.mode == PICOGAME_FX_TINT && bmuse != NULL && + bmuse->format == PICOGAME_FMT_PAL8 && bmuse->pal_entries <= PICOGAME_TINT_PAL_CAP) { + for (int i = 0; i < bmuse->pal_entries; i++) { + tpal[i] = picogame_mul565(bmuse->palette[i], fxm.color); + } + bmtint = *bmuse; // shallow copy; override only the palette + bmtint.palette = tpal; + bmuse = &bmtint; + fxp = NULL; // tint now baked in -> plain (fast) blit + } + if (spr->angle == 0 && spr->scale == 256) { + int tx, ty; + picogame_sprite_topleft(spr, &tx, &ty); + picogame_blit_bitmap(buf, bw, bh, clip_x, clip_y, bmuse, + tx + vx, ty + vy, spr->frame, fx, fy, tr, fxp); + } else if (spr->angle == 0) { + int tx, ty; + picogame_sprite_topleft(spr, &tx, &ty); + picogame_blit_bitmap_scaled(buf, bw, bh, clip_x, clip_y, bmuse, + tx + vx, ty + vy, spr->frame, fx, fy, spr->scale, fxp); + } else { + sprite_xform_fill(spr); // once per angle/scale change, not per strip + int w = (spr->bitmap != NULL) ? spr->bitmap->width : 0; + int h = (spr->bitmap != NULL) ? spr->bitmap->height : 0; + int pivx = ((int)spr->anchor_x * w) >> 8, pivy = ((int)spr->anchor_y * h) >> 8; + int px = (spr->x >> 8) + vx, py = (spr->y >> 8) + vy; + picogame_blit_bitmap_affine(buf, bw, bh, clip_x, clip_y, bmuse, + px, py, pivx, pivy, spr->frame, fx, fy, + px + spr->xf_minx, py + spr->xf_miny, px + spr->xf_maxx, py + spr->xf_maxy, + spr->xf_ic, spr->xf_is, fxp); + } +} + +mp_obj_t picogame_blit_strip_layers( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + mp_obj_t *items, uint8_t *kinds, size_t n, uint16_t background, int ox, int oy) { + mp_obj_t pending = MP_OBJ_NULL; // a BaseException latched from a StripDraw callback + int npix = region_w * strip_h; + if (background == 0) { + memset(buf, 0, (size_t)npix * 2); // common case (black/clear) -> fast bulk clear + } else { + // word-fill: two packed pixels per uint32 (half the stores). CAUTION: this composites into + // BOTH a GC strip buffer (SPI path, >=4-byte aligned) AND, on framebuffer targets, a raw row + // pointer fb + sy*stride + x0 that starts at an ODD pixel when x0 is odd -> only 2-byte + // aligned. GCC lowers the fill to STRD/STM, which raise an unaligned UsageFault on Cortex-M + // even with CCR.UNALIGN_TRP clear (STRD/STM always require word alignment). So peel one + // leading pixel to reach 4-byte alignment (mirrors picogame_fb_to_native), bulk word-fill, + // then an odd trailing pixel. + uint32_t w = (uint32_t)background | ((uint32_t)background << 16); + int i = 0; + if (npix > 0 && ((uintptr_t)buf & 2u) != 0) { + buf[0] = background; + i = 1; + } + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + uint32_t *w32 = (uint32_t *)(buf + i); // now 4-byte aligned + #pragma GCC diagnostic pop + int nw = (npix - i) >> 1; + for (int k = 0; k < nw; k++) { + w32[k] = w; + } + i += nw << 1; + if (i < npix) { // odd trailing pixel + buf[i] = background; + } + } + for (size_t i = 0; i < n; i++) { + uint8_t raw = (kinds != NULL) ? kinds[i] : PICOGAME_KIND_SPRITE; + uint8_t kind = raw & PICOGAME_KIND_MASK; + // Fixed (HUD) items are drawn in screen space -> no view offset. + int iox = (raw & PICOGAME_KIND_FIXED) ? 0 : ox; + int ioy = (raw & PICOGAME_KIND_FIXED) ? 0 : oy; + if (kind == PICOGAME_KIND_TILEMAP) { + picogame_blit_tilemap(buf, region_w, strip_top, strip_h, x0, + MP_OBJ_TO_PTR(items[i]), iox, ioy); + } else if (kind == PICOGAME_KIND_PARTICLES) { + picogame_blit_particles(buf, region_w, strip_top, strip_h, x0, + MP_OBJ_TO_PTR(items[i]), iox, ioy); + } else if (kind == PICOGAME_KIND_CANVAS) { + picogame_blit_canvas(buf, region_w, strip_top, strip_h, x0, + MP_OBJ_TO_PTR(items[i]), iox, ioy); + } else if (kind == PICOGAME_KIND_STRIPDRAW) { + // Immediate mode: hand the callback a view of the part of THIS strip that + // overlaps the layer's rect (so it can only paint within its rect - a + // full-view fill stays inside it). Skip strips the rect doesn't touch. + picogame_stripdraw_obj_t *sd = MP_OBJ_TO_PTR(items[i]); + int ry0 = sd->y, ry1 = sd->y + sd->h; + int s0 = strip_top > ry0 ? strip_top : ry0; // first screen row to draw + int st_end = strip_top + strip_h; + int s1 = st_end < ry1 ? st_end : ry1; // one past last screen row + if (s0 >= s1) { + continue; // strip is outside the layer + } + picogame_canvas_obj_t *v = MP_OBJ_TO_PTR(sd->view); + v->data = buf + (s0 - strip_top) * region_w; // view row 0 == screen row s0 + v->w = region_w; + v->h = s1 - s0; + v->x = 0; + v->y = 0; + v->has_transparent = false; + mp_obj_t cbargs[5] = { + sd->view, + MP_OBJ_NEW_SMALL_INT(x0), + MP_OBJ_NEW_SMALL_INT(s0), + MP_OBJ_NEW_SMALL_INT(region_w), + MP_OBJ_NEW_SMALL_INT(s1 - s0), + }; + // We're inside an open display bus transaction here, so a raised + // exception must NOT unwind past it (that would wedge the bus / leave a + // DMA running). Catch it, keep the transaction intact, and latch so the + // traceback prints once instead of every strip every frame. + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_n_kw(sd->callback, 5, 0, cbargs); + nlr_pop(); + } else { + mp_obj_t exc = MP_OBJ_FROM_PTR(nlr.ret_val); + if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exc)), + MP_OBJ_FROM_PTR(&mp_type_Exception))) { + // A BaseException (KeyboardInterrupt / ReloadException / SystemExit) must reach the + // supervisor - latch it and stop; the caller re-raises it once the display + // transaction has safely closed, so Ctrl-C and USB auto-reload actually work. + pending = exc; + break; + } + if (!sd->faulted) { + sd->faulted = true; + mp_obj_print_exception(&mp_plat_print, exc); + } + } + } else if (kind == PICOGAME_KIND_TRIANGLES) { + // Retained screen-space triangle batch: pure C per strip (no Python callback, + // so this path needs no Python re-entry mid-compose). Cheap band + // reject vs THIS strip, then the Canvas rasteriser through a stack view over + // the strip buffer. Screen-space by design: the view offset is not applied. + picogame_triangles_obj_t *t = MP_OBJ_TO_PTR(items[i]); + picogame_canvas_obj_t v; + v.data = buf; + v.data_obj = MP_OBJ_NULL; + v.w = region_w; + v.h = strip_h; + v.x = 0; + v.y = 0; + v.transparent = 0; + v.has_transparent = false; + picogame_canvas_dirty_reset(&v); + int xo = -x0; + int yo = -strip_top; + picogame_fill_triangle_batch(&v, t->verts, t->colors, t->count, xo, yo); + } else { + picogame_sprite_obj_t *spr = MP_OBJ_TO_PTR(items[i]); + if (!(spr->flags & PICOGAME_SPR_VISIBLE)) { + continue; + } + blit_sprite(buf, region_w, strip_h, x0, strip_top, spr, iox, ioy); + } + } + return pending; +} + +bool picogame_strip_begin( + picogame_output_t *display, + int *x0p, int *y0p, int *x1p, int *y1p, size_t buffer_pixels, + int *region_w, int *strip_h) { + // Clamp the window to the panel (post-rotation w/h): an out-of-range region makes the controller + // wrap/garble rows. Callers usually pass clamped dirty rects, but StripDraw / direct render_region + // can hand us a rect that runs off the panel. Clamp AND write back through the pointers so the + // caller's strip loop + blit origin use the SAME clamped bounds (else only the GRAM window is + // clamped while the data loop still pushes off-panel rows -> the wrap/garble we're preventing). + int pw = display->core.width, ph = display->core.height; + int x0 = *x0p, y0 = *y0p, x1 = *x1p, y1 = *y1p; + if (x0 < 0) { + x0 = 0; + } + if (y0 < 0) { + y0 = 0; + } + if (x1 > pw) { + x1 = pw; + } + if (y1 > ph) { + y1 = ph; + } + *x0p = x0; + *y0p = y0; + *x1p = x1; + *y1p = y1; + int rw = x1 - x0; + int rh = y1 - y0; + if (rw <= 0 || rh <= 0) { + return false; + } + int sh = (int)(buffer_pixels / (size_t)rw); + if (sh < 1) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + if (sh > rh) { + sh = rh; + } + + displayio_area_t area; + area.x1 = x0; + area.y1 = y0; + area.x2 = x1; + area.y2 = y1; + area.next = NULL; + displayio_display_bus_set_region_to_update(&display->bus, &display->core, &area); + + while (!displayio_display_bus_begin_transaction(&display->bus)) { + RUN_BACKGROUND_TASKS; + } + display->bus.send(display->bus.bus, DISPLAY_COMMAND, + CHIP_SELECT_TOGGLE_EVERY_BYTE, &display->write_ram_command, 1); + + *region_w = rw; + *strip_h = sh; + return true; +} + +// --- output transport seam (busdisplay backend): the ONLY per-strip display ops the generic +// picogame_render_region orchestrator below touches, so a non-CircuitPython port (MicroPython +// framebuf/SPI) swaps just strip_begin + these two + set_invert/set_pixel_format. See __init__.h. +static inline void picogame_out_strip_send(picogame_output_t *display, const uint8_t *data, size_t nbytes) { + display->bus.send(display->bus.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, data, nbytes); +} +static inline void picogame_out_strip_end(picogame_output_t *display) { + displayio_display_bus_end_transaction(&display->bus); +} + +void picogame_render_region( + picogame_output_t *display, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buffer, size_t buffer_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t background, int ox, int oy) { + + int region_w, strip_h; + int cx0 = x0, cy0 = y0, cx1 = x1, cy1 = y1; // strip_begin clamps these to the panel in place + if (!picogame_strip_begin(display, &cx0, &cy0, &cx1, &cy1, buffer_pixels, ®ion_w, &strip_h)) { + return; + } + for (int sy = cy0; sy < cy1; sy += strip_h) { + int sh = picogame_imin(strip_h, cy1 - sy); + mp_obj_t exc = picogame_blit_strip_layers(buffer, region_w, sy, sh, cx0, items, kinds, n, background, ox, oy); + picogame_out_strip_send(display, (uint8_t *)buffer, region_w * sh * 2); + if (exc != MP_OBJ_NULL) { // a StripDraw callback raised a BaseException: close the + picogame_out_strip_end(display); // bus, then re-raise (Ctrl-C / reload) + nlr_raise(MP_OBJ_TO_PTR(exc)); + } + } + picogame_out_strip_end(display); +} + +// Toggle the panel's hardware colour inversion (INVON 0x21 / INVOFF 0x20). Instant, sends NO +// pixel data - a brief invert is a free full-screen "flash" (a 1-bit negative hit look). +void picogame_set_invert(picogame_output_t *display, bool on) { + uint8_t cmd = on ? 0x21 : 0x20; + while (!displayio_display_bus_begin_transaction(&display->bus)) { + RUN_BACKGROUND_TASKS; + } + display->bus.send(display->bus.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &cmd, 1); + displayio_display_bus_end_transaction(&display->bus); +} + +#if CIRCUITPY_PICOGAME_RGB444 +// The RGB444 machinery (this + pack_rgb444 + the Display rgb444 path) is compiled in ONLY when a +// board sets CIRCUITPY_PICOGAME_RGB444=1. It is a transfer-bound-only win (on a CPU-balanced panel +// like the PicoPad's the pack ~= the SPI byte saving, so it loses); default off (port ?= 0) until +// multi-platform experience justifies flipping the default. See pack_rgb444's measured-optimal note. +// Set the panel pixel format (COLMOD 0x3A): rgb444 -> 12-bit RGB444 (0x53), else 16-bit RGB565 +// (0x55). Asserting it on every Display construct also recovers from a previous program that left +// the panel in the other format (survives soft reset). +void picogame_set_pixel_format(picogame_output_t *display, bool rgb444) { + uint8_t cmd = 0x3A; + uint8_t param = rgb444 ? 0x53 : 0x55; + while (!displayio_display_bus_begin_transaction(&display->bus)) { + RUN_BACKGROUND_TASKS; + } + display->bus.send(display->bus.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &cmd, 1); + display->bus.send(display->bus.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ¶m, 1); + displayio_display_bus_end_transaction(&display->bus); +} + +// Pack a strip of `npix` (must be even) WIRE-order RGB565 pixels IN-PLACE to ST7789 12-bit RGB444 +// (2 px -> 3 bytes): R0G0 / B0R1 / G1B1. Returns the packed byte count. Cuts SPI traffic ~25%. +// In-place is safe: the write offset (1.5*i) always trails the read offset (2*i). +size_t picogame_pack_rgb444(uint16_t *buf, size_t npix) { + // Pack wire RGB565 -> ST7789 12-bit RGB444 (2 px -> 3 bytes) in place; the write offset (1.5*i) + // always trails the read offset (2*i). NB: the byte-swap to native order is LOAD-BEARING, not + // waste - it nibble-aligns the channels so each extracts in ~2 ops; extracting straight from the + // wire value makes GREEN (split across the byte boundary) cost ~5 ops and is SLOWER on device + // (measured, M0+). Likewise do NOT wide-unroll (8 registers -> spills). This tight form is the + // measured-optimal pack; RGB444 still loses to RGB565 on a CPU-balanced panel (pack ~= the SPI + // byte saving), so it is a transfer-bound-only option (default off). + uint8_t *out = (uint8_t *)buf; + size_t o = 0; + for (size_t i = 0; i + 1 < npix; i += 2) { + uint32_t w0 = buf[i], w1 = buf[i + 1]; + uint32_t n0 = (w0 >> 8) | (w0 << 8); // wire -> native RGB565 + uint32_t n1 = (w1 >> 8) | (w1 << 8); + uint8_t r0 = (n0 >> 12) & 0xF, g0 = (n0 >> 7) & 0xF, b0 = (n0 >> 1) & 0xF; + uint8_t r1 = (n1 >> 12) & 0xF, g1 = (n1 >> 7) & 0xF, b1 = (n1 >> 1) & 0xF; + out[o++] = (r0 << 4) | g0; + out[o++] = (b0 << 4) | r1; + out[o++] = (g1 << 4) | b1; + } + return o; +} +#endif // CIRCUITPY_PICOGAME_RGB444 + +void picogame_render( + picogame_output_t *display, + mp_obj_t *items, size_t n, + uint16_t *buffer, size_t buffer_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t background) { + picogame_render_region(display, items, NULL, n, buffer, buffer_pixels, + x0, y0, x1, y1, background, 0, 0); +} + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Full-frame RAM-framebuffer backend. Same layered compositor as the SPI strip path +// (picogame_blit_strip_layers -> identical kinds dispatch, view offset, StripDraw), +// but the destination is a caller-owned framebuffer instead of a bus window - no +// transaction, no strip transfer. This is the shared render target for scanout-buffer +// platforms (RP2350 DVI/HSTX, the desktop sim, the WASM playground): the framebuffer +// IS the composite surface, so a region is composited straight into fb in place. +// +// fb : destination, wire-order RGB565, fb_stride*fb_h pixels (caller-owned). +// fb_stride : framebuffer row stride in pixels (>= x1); rows may be wider than x1. +// items/kinds/n, background, ox/oy : the scene layer list, as picogame_render_region. +// [x0,y0,x1,y1): the framebuffer region to (re)composite - a dirty rect, or the frame. +// Bounds are clamped to [0,fb_stride) x [0,fb_h); an empty region is a no-op. +// Returns a latched BaseException raised by a StripDraw callback (the caller re-raises +// it), or MP_OBJ_NULL - the SAME contract as the strip path, minus the bus to close. +// Convert a contiguous run of `n` pixels in place from wire-order to native RGB565. +// `((v&0x00ff00ff)<<8)|((v&0xff00ff00)>>8)` byte-swaps both halfwords of a 32-bit word at once +// (GCC lowers it to a single Cortex REV16), so two pixels per word; unrolled x4 (8 px/iter) so the +// ldr/str stream pipelines on zero-wait SRAM. A run may start at an odd x (partial dirty rect), so +// peel one leading pixel to keep the word accesses 4-byte aligned (unaligned faults on M0+). +// Portable + little-endian, so it also serves the WASM native565 canvas target. +// Emulated full-screen invert for framebuffer targets (RP2350 DVI, the WASM playground) that lack a +// panel's hardware INVON/INVOFF: a flag XORed into the wire->native conversion below, so composited +// pixels come out as their negative. Toggling it (picogame_fb_set_invert) latches a one-shot "the +// whole frame must recomposite" so the flip covers the ENTIRE screen, not just the current dirty +// rects - mirroring a panel INVON, which flips everything already scanned out. The XOR folds into the +// existing REV16 byte-swap for ~free (one extra op per word). +static bool s_fb_invert = false; +static bool s_fb_invert_dirty = false; + +void picogame_fb_set_invert(bool on) { + if (on != s_fb_invert) { + s_fb_invert = on; + s_fb_invert_dirty = true; // one full-frame recomposite so the flip is global, then latch off + } +} + +bool picogame_fb_take_invert_dirty(void) { + bool d = s_fb_invert_dirty; + s_fb_invert_dirty = false; + return d; +} + +static void picogame_fb_to_native(uint16_t *px, int n) { + uint32_t inv = s_fb_invert ? 0xFFFFFFFFu : 0u; // emulated negative flash (0 = normal pass) + int i = 0; + if (n > 0 && ((uintptr_t)px & 2u) != 0) { + px[0] = (uint16_t)(__builtin_bswap16(px[0]) ^ (uint16_t)inv); + i = 1; + } + int pairs = (n - i) >> 1; + uint32_t *w = (uint32_t *)(px + i); + int p = 0; + for (; p + 4 <= pairs; p += 4) { + uint32_t v0 = w[p], v1 = w[p + 1], v2 = w[p + 2], v3 = w[p + 3]; + w[p] = (((v0 & 0x00ff00ffu) << 8) | ((v0 & 0xff00ff00u) >> 8)) ^ inv; + w[p + 1] = (((v1 & 0x00ff00ffu) << 8) | ((v1 & 0xff00ff00u) >> 8)) ^ inv; + w[p + 2] = (((v2 & 0x00ff00ffu) << 8) | ((v2 & 0xff00ff00u) >> 8)) ^ inv; + w[p + 3] = (((v3 & 0x00ff00ffu) << 8) | ((v3 & 0xff00ff00u) >> 8)) ^ inv; + } + for (; p < pairs; p++) { + uint32_t v = w[p]; + w[p] = (((v & 0x00ff00ffu) << 8) | ((v & 0xff00ff00u) >> 8)) ^ inv; + } + i += pairs << 1; + if (i < n) { + px[i] = (uint16_t)(__builtin_bswap16(px[i]) ^ (uint16_t)inv); + } +} + +// Fused wire->native byte-swap AND copy in one pass: read `n` wire pixels from `src`, write them +// NATIVE to `dst` (folding in the emulated invert XOR). Saves the separate in-place swap + memcpy +// (one whole band read+write) on the full-width publish path. REQUIRES src AND dst 4-byte aligned +// (the caller uses it only for a contiguous full-width band, where both are). +static void picogame_fb_to_native_copy(uint16_t *dst, const uint16_t *src, int n) { + uint32_t inv = s_fb_invert ? 0xFFFFFFFFu : 0u; + int pairs = n >> 1; + const uint32_t *s = (const uint32_t *)src; + uint32_t *d = (uint32_t *)dst; + int p = 0; + for (; p + 4 <= pairs; p += 4) { + uint32_t v0 = s[p], v1 = s[p + 1], v2 = s[p + 2], v3 = s[p + 3]; + d[p] = (((v0 & 0x00ff00ffu) << 8) | ((v0 & 0xff00ff00u) >> 8)) ^ inv; + d[p + 1] = (((v1 & 0x00ff00ffu) << 8) | ((v1 & 0xff00ff00u) >> 8)) ^ inv; + d[p + 2] = (((v2 & 0x00ff00ffu) << 8) | ((v2 & 0xff00ff00u) >> 8)) ^ inv; + d[p + 3] = (((v3 & 0x00ff00ffu) << 8) | ((v3 & 0xff00ff00u) >> 8)) ^ inv; + } + for (; p < pairs; p++) { + uint32_t v = s[p]; + d[p] = (((v & 0x00ff00ffu) << 8) | ((v & 0xff00ff00u) >> 8)) ^ inv; + } + if (n & 1) { + dst[n - 1] = (uint16_t)(__builtin_bswap16(src[n - 1]) ^ (uint16_t)inv); + } +} + +// Wire-order RGB565 -> RGB332 publish copy for 8-bit picodvi scanout targets (RRRGGGBB, +// the same quantization displayio's ColorConverter uses), folding in the emulated invert. +// A wire pixel w holds native v byte-swapped: hi(v) = low byte of w, lo(v) = high byte. +// R3 = top 3 of R5 = hi & 0xE0; G3 = top 3 of G6 = (hi & 0x07) << 2; +// B2 = top 2 of B5 = (lo >> 3) & 0x03 +static void picogame_fb_to_rgb332_copy(uint8_t *dst, const uint16_t *src, int n) { + uint8_t inv = s_fb_invert ? 0xFF : 0x00; + for (int i = 0; i < n; i++) { + uint16_t w = src[i]; + uint8_t hi = (uint8_t)w; // wire low byte = native high byte + uint8_t lo = (uint8_t)(w >> 8); + dst[i] = (uint8_t)((hi & 0xE0u) | ((hi & 0x07u) << 2) | ((lo >> 3) & 0x03u)) ^ inv; + } +} + +// Publish-copy context for one framebuffer region: just what fb_publish_band needs. +typedef struct { + uint16_t *fb; + int fb_stride, fmt; + int x0, region_w; + bool full_width; +} fb_bands_arg_t; + +// Publish one FINISHED band from a scratch strip into the fb (wire/native/RGB332, +// full- or partial-width). Shared by the serial loop and both cores of the split. +static void fb_publish_band(const fb_bands_arg_t *a, uint16_t *scratch, int by, int bh) { + uint16_t *fb = a->fb; + int fb_stride = a->fb_stride; + int region_w = a->region_w; + int fmt = a->fmt; + if (a->full_width) { + size_t npix = (size_t)region_w * (size_t)bh; + if (fmt == PICOGAME_FB_RGB332) { + picogame_fb_to_rgb332_copy( + (uint8_t *)fb + (size_t)by * (size_t)fb_stride, scratch, (int)npix); + } else if (fmt == PICOGAME_FB_NATIVE565) { + // Fold the wire->native byte-swap INTO the publish copy (no separate in-place swap). + picogame_fb_to_native_copy(fb + (size_t)by * (size_t)fb_stride, scratch, (int)npix); + } else { + memcpy(fb + (size_t)by * (size_t)fb_stride, scratch, npix * 2u); // wire: HW reads as-is + } + } else if (fmt == PICOGAME_FB_RGB332) { + // Partial-width 8-bit: quantize row by row straight into the byte fb (strided). + for (int r = 0; r < bh; r++) { + picogame_fb_to_rgb332_copy( + (uint8_t *)fb + (size_t)(by + r) * (size_t)fb_stride + a->x0, + scratch + (size_t)r * region_w, region_w); + } + } else { + // Partial-width: swap the scratch in place (NATIVE), then copy row by row (strided). + if (fmt == PICOGAME_FB_NATIVE565) { + picogame_fb_to_native(scratch, region_w * bh); + } + for (int r = 0; r < bh; r++) { + memcpy(fb + (size_t)(by + r) * fb_stride + a->x0, + scratch + (size_t)r * region_w, (size_t)region_w * 2u); + } + } +} + +mp_obj_t picogame_render_framebuffer( + uint16_t *fb, int fb_stride, int fb_h, int fmt, + uint16_t *scratch, int scratch_rows, + mp_obj_t *items, uint8_t *kinds, size_t n, + int x0, int y0, int x1, int y1, + uint16_t background, int ox, int oy) { + if (x0 < 0) { + x0 = 0; + } + if (y0 < 0) { + y0 = 0; + } + if (x1 > fb_stride) { + x1 = fb_stride; + } + if (y1 > fb_h) { + y1 = fb_h; + } + if (x1 <= x0 || y1 <= y0) { + return MP_OBJ_NULL; + } + int region_w = x1 - x0; + + // Tear-free NATIVE path: the framebuffer is a LIVE scanout buffer (picodvi/HDMI reads it + // continuously), so it must NEVER transiently hold wire-order pixels - a beam sampling a + // half-composed region would read byte-swapped bytes (R/B swapped -> pink). Compose+byte-swap + // into a PRIVATE scratch strip, then memcpy the finished NATIVE band into the fb; the fb only + // ever receives fully-native runs. Any residual seam is old-vs-new NATIVE content (a plain + // single-buffer tear, no colour shift) - reduced by the caller's optional vblank sync. Bands of + // scratch_rows keep the scratch small. (Wire targets / no scratch fall through to the direct + // path below, which is correct because a wire fb needs no conversion.) + if (scratch != NULL && scratch_rows > 0) { + // Full-width band: rows are contiguous in BOTH scratch and fb, so the whole band publishes in + // one pass with 4-byte-aligned pointers (fb_stride even). Partial-width rows are strided. + fb_bands_arg_t a = { + fb, fb_stride, fmt, x0, region_w, + (x0 == 0 && region_w == fb_stride) + }; + int nbands = (y1 - y0 + scratch_rows - 1) / scratch_rows; + for (int b = 0; b < nbands; b++) { + int by = y0 + b * scratch_rows; + int bh = (y1 - by) < scratch_rows ? (y1 - by) : scratch_rows; + // Compose region_w x bh OFF-SCREEN into the scratch (wire order) so the beam never sees a + // half-composited region (no sprite/HUD flicker), then publish the FINISHED band into the + // fb. Published even on a latched exception so the fb is never left half-updated. + mp_obj_t exc = picogame_blit_strip_layers( + scratch, region_w, by, bh, x0, items, kinds, n, background, ox, oy); + fb_publish_band(&a, scratch, by, bh); + if (exc != MP_OBJ_NULL) { + return exc; // StripDraw raised; caller re-raises (cleared stays false -> full repaint) + } + } + return MP_OBJ_NULL; + } + // The compositor (blitters, effects, palettes) works in wire order throughout; a NATIVE + // target is converted in place only after a region is fully composed. On a latched StripDraw + // exception the region was partially composed in wire order - convert it anyway so the fb is + // never left half wire / half native (the Scene keeps cleared=false until its render loop + // finishes, so the refresh after the exception repaints the full frame). + + // Fast path: a FULL-WIDTH region has contiguous rows, so the whole rect IS one valid strip + // buffer. Composite it in a SINGLE strip_layers call (h = the whole band) instead of one call + // per row - this amortizes all the per-row/per-layer setup (tile-blit dispatch, clip tests, + // background fill, and crucially one StripDraw Python callback per band instead of per row) + // over the band, and converts the whole contiguous region in one pass. This is the + // full-repaint / camera-scroll case (set_view -> cleared=false -> a full-screen dirty rect). + // (An RGB332 target never reaches these direct paths: its constructor always allocates + // the scratch strip, and the compositor can only write 16-bit wire pixels - composing + // in place inside a byte framebuffer would corrupt it.) + if (x0 == 0 && x1 == fb_stride) { + uint16_t *base = fb + (size_t)y0 * (size_t)fb_stride; + mp_obj_t exc = picogame_blit_strip_layers( + base, fb_stride, y0, y1 - y0, 0, items, kinds, n, background, ox, oy); + if (fmt == PICOGAME_FB_NATIVE565) { + picogame_fb_to_native(base, (y1 - y0) * fb_stride); + } + return exc; // MP_OBJ_NULL on success, else a latched StripDraw exception + } + + // Partial-width region: rows are non-contiguous, so composite (and convert) row by row. + for (int sy = y0; sy < y1; sy++) { + uint16_t *row = fb + (size_t)sy * (size_t)fb_stride + x0; + mp_obj_t exc = picogame_blit_strip_layers( + row, region_w, sy, 1, x0, items, kinds, n, background, ox, oy); + if (fmt == PICOGAME_FB_NATIVE565) { + picogame_fb_to_native(row, region_w); + } + if (exc != MP_OBJ_NULL) { + return exc; // StripDraw raised a BaseException; caller re-raises (no bus open) + } + } + return MP_OBJ_NULL; +} +#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER diff --git a/shared-module/picogame/__init__.h b/shared-module/picogame/__init__.h new file mode 100644 index 00000000000..a4377292219 --- /dev/null +++ b/shared-module/picogame/__init__.h @@ -0,0 +1,308 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include "py/obj.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// Hardware-FPU boards run the pseudo-3D/math primitives (picogame.project) on plain float32 - +// faster than the soft-float-equivalent fixed path and free of 16.16 range limits; no-FPU +// targets (Cortex-M0+) use integer 16.16. Only ONE path is compiled per board. The default +// follows the architecture; a board can override with CIRCUITPY_PICOGAME_FPU=0/1 in its +// mpconfigboard.mk. Python reads `picogame.FPU` to pack camera/point buffers to match. +#ifndef CIRCUITPY_PICOGAME_FPU +#if (defined(__ARM_FP) && (__ARM_FP != 0)) || (defined(__riscv_flen) && (__riscv_flen > 0)) +#define CIRCUITPY_PICOGAME_FPU (1) +#else +#define CIRCUITPY_PICOGAME_FPU (0) +#endif +#endif + +// Sample one texel as wire RGB565; false = transparent (skip). Shared by the sprite/canvas +// blit paths so they inline one copy (see the blit contract: PAL8 indices must be < palette len). +static inline bool src_pixel_s(int format, const uint8_t *data, const uint16_t *pal, + bool transp, uint16_t key, int idx, uint16_t *out) { + if (format == PICOGAME_FMT_PAL8) { + uint8_t i = data[idx]; + if (transp && i == (uint8_t)key) { + return false; + } + *out = pal[i]; // indices must be < palette length (see blit contract) + return true; + } + // GC buffer is >=4-byte aligned; silence xtensa -Wcast-align (see picogame_blit_bitmap). + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + uint16_t v = ((const uint16_t *)data)[idx]; + #pragma GCC diagnostic pop + if (transp && v == key) { + return false; + } + *out = v; + return true; +} + + +// Scene layer kinds (tags stored alongside items so blit/dirty can dispatch +// without cross-referencing shared-bindings type objects). +enum { + PICOGAME_KIND_SPRITE = 0, + PICOGAME_KIND_TILEMAP = 1, + PICOGAME_KIND_PARTICLES = 2, + PICOGAME_KIND_CANVAS = 3, + PICOGAME_KIND_STRIPDRAW = 4, + PICOGAME_KIND_TRIANGLES = 5, + // High bit on a kind = "fixed": the item ignores the scene view offset + // (camera), so HUD / score / dialog stay put while the world scrolls. + PICOGAME_KIND_FIXED = 0x80, + PICOGAME_KIND_MASK = 0x7f, +}; + +// StripDraw: immediate-mode layer. Holds NO pixel buffer - instead its `callback` +// is invoked once per render strip with a Canvas "view" repointed at the live strip +// buffer, so the user draws primitives straight into the strip (zero RAM vs a Canvas, +// which costs w*h*2 bytes). Its rect is repainted every frame (it's for animated / +// scanline content: pseudo-3D, gradients, procedural backgrounds). The view's local +// (0,0) maps to screen (vx, vy) handed to the callback. `faulted` latches after the +// callback raises once, so a buggy callback prints one traceback, not one per strip. +typedef struct { + mp_obj_base_t base; + mp_obj_t callback; // draw(view, vx, vy, vw, vh): vx/vy = screen origin of view (0,0) + mp_obj_t view; // a reused picogame_canvas_obj_t (data repointed each strip) + int32_t x, y, w, h; // scene rect (int32: scene coords, big-world safe) + int32_t dx1, dy1, dx2, dy2; // accumulated dirty rect (scene coords) when !always_dirty - the same + // picogame_dirty_* accumulator Canvas/Tilemap use, so invalidate() can mark + // a sub-rect and the Scene repaints only that region (not the whole layer). + bool faulted; + bool always_dirty; // True: repaint every frame (animated). False: only the dirty rect (on-change UI). +} picogame_stripdraw_obj_t; + +// Triangles: a retained SCREEN-SPACE triangle batch the compositor rasterises entirely +// in C (per strip, band-rejected) - no Python callback per strip, so unlike StripDraw it +// stays composable without re-entering Python mid-frame. verts (int16 x0,y0,x1,y1,x2,y2 per tri) and +// colors (uint16 wire RGB565 per tri) are CALLER-OWNED arrays (refs held for GC; fill +// them in place). Setting `count` selects how many draw and marks the layer dirty +// full-screen (a 3D frame repaints everything anyway). +typedef struct { + mp_obj_base_t base; + mp_obj_t verts_obj, colors_obj; // GC anchors for the caller's arrays + const int16_t *verts; + const uint16_t *colors; + uint16_t count, cap; // cap = what the buffers can hold + int32_t dx1, dy1, dx2, dy2; // dirty accumulator (count-set -> full screen) +} picogame_triangles_obj_t; + +static inline int picogame_imin(int a, int b) { + return a < b ? a : b; +} +static inline int picogame_imax(int a, int b) { + return a > b ? a : b; +} + +// Drawn top-left in scene pixels: the logical position minus the anchor offset +// (anchor is a 1/256 fraction of the bitmap size). Used by BOTH the blitter and +// the dirty-rect tracker so they always agree on where the sprite lands. +static inline void picogame_sprite_topleft(const picogame_sprite_obj_t *s, int *tx, int *ty) { + int w = (s->bitmap != NULL) ? s->bitmap->width : 0; + int h = (s->bitmap != NULL) ? s->bitmap->height : 0; + int sw = (w * s->scale) >> 8; // anchor is a fraction of the SCALED size + int sh = (h * s->scale) >> 8; + // The blitter only honours transpose on the fast path (scale==256); the scaled blitter ignores it. + // Swap the footprint ONLY when scale==256, or aabb/topleft disagree with what's drawn (trailing). + if ((s->flags & PICOGAME_SPR_TRANSPOSE) && s->scale == 256) { // 90deg transpose swaps footprint + int t = sw; // picogame_sprite_aabb, or the blit top-left and the + sw = sh; // tracked dirty rect disagree (sprite trails) + sh = t; + } + *tx = (s->x >> 8) - ((int)s->anchor_x * sw >> 8); + *ty = (s->y >> 8) - ((int)s->anchor_y * sh >> 8); +} + +// Drawn screen-space bounding box of a sprite (accounts for scale + rotation). +// Used by the dirty-rect tracker so it always covers the transformed sprite. +void picogame_sprite_aabb(const picogame_sprite_obj_t *s, int *x1, int *y1, int *x2, int *y2); + +// Per-pixel blit effect, shared by all three blit paths. One mode at a time; a NULL +// pointer means "no effect" (the fast path). SHADOW darkens the destination, FLASH +// replaces opaque pixels with `color`, DITHER skips pixels via a Bayer pattern (0..16 +// transparency) for fake translucency without alpha. +enum { PICOGAME_FX_NONE = 0, PICOGAME_FX_SHADOW, PICOGAME_FX_FLASH, PICOGAME_FX_DITHER, PICOGAME_FX_TINT }; +typedef struct { + uint8_t mode; + uint16_t color; // FLASH: solid colour to write; TINT: colour to multiply by (wire RGB565) + uint8_t level; // DITHER: 0..16 transparency (higher = more pixels skipped) +} picogame_fx_t; + +// Shared dirty-rect accumulator over a contiguous int32 [x1,y1,x2,y2] (Canvas + Tilemap both end in +// dx1,dy1,dx2,dy2). INT32 sentinels so big-world (>32767 px) scene coords still accumulate. +void picogame_dirty_reset(int32_t *r); +void picogame_dirty_union(int32_t *r, int x1, int y1, int x2, int y2); +bool picogame_dirty_take(int32_t *r, int *x1, int *y1, int *x2, int *y2); + +// Blit one frame of a bitmap at screen (dx0, dy0) into the strip buffer that +// covers [ox, ox+bw) x [oy, oy+bh). Shared by sprites and tilemap tiles. +// fxm: per-pixel effect (NULL = plain colour copy). +void picogame_blit_bitmap( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int dx0, int dy0, int frame, bool flip_x, bool flip_y, + bool transpose, const picogame_fx_t *fxm); + +// Nearest-neighbour scaled blit (axis-aligned); scale is 8.8 fixed-point. +void picogame_blit_bitmap_scaled( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int dx0, int dy0, int frame, bool flip_x, bool flip_y, + uint16_t scale, const picogame_fx_t *fxm); + +// Full affine blit (scale + rotation about the anchor); (px,py)=screen anchor point, +// (pivx,pivy)=that anchor in SOURCE pixels. Nearest-neighbour inverse map. The transform is +// PRECOMPUTED by the caller (the sprite's xf_* cache): minx..maxy = the screen-space corner +// bbox, ic/is = the 16.16 inverse-map steps - so a per-strip call does no trig/divides. +void picogame_blit_bitmap_affine( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int px, int py, int pivx, int pivy, + int frame, bool flip_x, bool flip_y, + int minx, int miny, int maxx, int maxy, int32_t ic, int32_t is, + const picogame_fx_t *fxm); + +// ===== OUTPUT TRANSPORT SEAM ===================================================== +// picogame's compositor (picogame_blit_strip_layers) is OUTPUT-AGNOSTIC: it composites +// scene layers into a plain wire-order RGB565 strip buffer, knowing nothing about the +// destination. A physical display is reached only through the small transport contract +// below, so a non-CircuitPython port (e.g. a MicroPython framebuf/SPI backend) can reuse +// the whole compositor AND the generic picogame_render_region orchestrator and reimplement +// ONLY these few functions. `picogame_output_t` is the opaque display handle they take. +// (A RAM-framebuffer destination is a separate backend: picogame_render_framebuffer.) +// +// Strip-path contract a backend provides: +// picogame_strip_begin - open a window for [x0,y0,x1,y1); return strip geometry +// picogame_out_strip_send - push one composited strip (region_w*sh px, wire RGB565) +// picogame_out_strip_end - close the transaction +// picogame_set_invert - panel hardware colour inversion (a free full-screen flash) +// picogame_set_pixel_format - panel COLMOD (RGB565/RGB444), when CIRCUITPY_PICOGAME_RGB444 +// +// CircuitPython backend: picogame_output_t == busdisplay; the impl lives in __init__.c. +typedef busdisplay_busdisplay_obj_t picogame_output_t; + +// Fill a strip with background, then composite items (sprites and tilemaps) in +// order (items[0] = bottom). kinds[i] selects the type; kinds == NULL means +// every item is a sprite. (ox, oy) is the view offset added to item positions +// (scene space -> screen space) for camera/centering. +// Returns a latched BaseException (Ctrl-C / ReloadException) raised by a StripDraw callback, or +// MP_OBJ_NULL. The caller must re-raise it AFTER closing the display transaction. +#if defined(PICOGAME_HAS_INTERP) +// rp2-port SIO-interpolator mode7 row walker. Fast path only: +// PAL8, opaque, stride == tw, log2(tw)+log2(th) <= 16; the caller guards and falls back. +void picogame_mode7_row_interp(uint16_t *dst, int n, + const uint8_t *tex, const uint16_t *pal, + uint32_t fx, uint32_t fy, int32_t stepx, int32_t stepy, + int shx, int shy, int ltw, int lth); +#endif + +// Racing-road curve pass (see the implementation comment in __init__.c). +void picogame_road_edges(int16_t *rl, int16_t *rr, const int32_t *hw_q16, int n, + int32_t cx_q16, int32_t dist, const int32_t *cfg); + +mp_obj_t picogame_blit_strip_layers( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + mp_obj_t *items, uint8_t *kinds, size_t n, uint16_t background, int ox, int oy); + +// Compute strip geometry and open a render window on the display (set region, +// begin transaction, send RAMWR). Returns false if the region is empty; raises +// if the buffer is too small for the region width. Fills *region_w and *strip_h. +bool picogame_strip_begin( + picogame_output_t *display, + int *x0, int *y0, int *x1, int *y1, size_t buffer_pixels, + int *region_w, int *strip_h); // clamps *x0..*y1 to the panel in place (caller loops on them) + +// Portable backend: strip-render a layered scene region to ANY busdisplay via +// its (blocking) bus.send - single buffer, no DMA. Same layer dispatch as the +// fast path (kinds + view offset), so it is the cross-port fallback for Scene on +// targets without the platform DMA Display. `kinds == NULL` => all sprites. +void picogame_render_region( + picogame_output_t *display, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buffer, size_t buffer_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t background, int ox, int oy); + +// Toggle the panel's hardware colour inversion (INVON/INVOFF) - a free full-screen flash. +void picogame_set_invert(picogame_output_t *display, bool on); + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Emulated invert for a picogame.Framebuffer target (no hardware INVON): set the flag (XORed into the +// wire->native conversion) and, via take_invert_dirty(), force one whole-frame recomposite on toggle. +void picogame_fb_set_invert(bool on); +bool picogame_fb_take_invert_dirty(void); +#endif + +#if CIRCUITPY_PICOGAME_RGB444 // compiled in only on boards that opt into RGB444 (default off) +// Set panel pixel format (COLMOD): rgb444 -> 12-bit RGB444, else 16-bit RGB565. +void picogame_set_pixel_format(picogame_output_t *display, bool rgb444); + +// Pack `npix` (even) wire-order RGB565 pixels in `buf` IN-PLACE to 12-bit RGB444; returns bytes. +size_t picogame_pack_rgb444(uint16_t *buf, size_t npix); +#endif + +// Universal sprite-only convenience wrapper over picogame_render_region. +void picogame_render( + picogame_output_t *display, + mp_obj_t *items, size_t n, + uint16_t *buffer, size_t buffer_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t background); + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Rows per compose band for the tear-free NATIVE framebuffer path: composite+byte-swap into a +// private scratch strip, then memcpy the finished NATIVE band into the live scanout buffer - so a +// picodvi/HDMI beam scanning the framebuffer never samples a half-composed WIRE-order region (which +// would read as byte-swapped / pink). Small band = small scratch (width*this*2 bytes). +#define PICOGAME_FB_SCRATCH_H 16 +// A render TARGET that is a caller-owned RAM framebuffer (wire-order RGB565), used in +// place of a BusDisplay for scanout-buffer platforms: the WASM playground (heap +// buffer read out to a canvas), the desktop sim, and FruitJam (the DVI/HSTX scanout +// buffer). Holds a WriteableBuffer alive + a typed view of it; allocation is the +// caller's (a bytearray in WASM, the DVI buffer memoryview on FruitJam), so the engine +// stays platform-neutral. Scene / render can target this instead of a display. +// Output pixel format of a picogame.Framebuffer target. The compositor always works in +// wire-order RGB565; the format only selects the publish conversion. +enum { + PICOGAME_FB_WIRE565 = 0, // no conversion (WASM playground / sim readout) + PICOGAME_FB_NATIVE565 = 1, // byte-swap to native RGB565 (picodvi 16-bit scanout) + PICOGAME_FB_RGB332 = 2, // quantize to RGB332 bytes (picodvi 8-bit scanout, e.g. + // Fruit Jam 640x480 - its max resolution is 8bpp-only) +}; + +typedef struct { + mp_obj_base_t base; + mp_obj_t buffer; // the backing WriteableBuffer (kept alive) + uint16_t *fb; // typed view of buffer.buf: width*height px - RGB565 (2 B/px) for the + // 565 formats; cast to uint8_t* per-pixel bytes for PICOGAME_FB_RGB332 + int width; + int height; + uint8_t fmt; // PICOGAME_FB_* output format (see enum above) + mp_obj_t scratch_buf; // GC-kept bytearray backing `scratch`; mp_const_none if none + uint16_t *scratch; // private compose strip: width*scratch_rows px, or NULL + int scratch_rows; // rows in `scratch` (PICOGAME_FB_SCRATCH_H), 0 if none +} picogame_framebuffer_obj_t; + +// Full-frame RAM-framebuffer backend: same layered compositor as the SPI strip path +// but composited straight into a caller-owned wire-order RGB565 framebuffer (no bus). +// The shared render target for scanout-buffer platforms (RP2350 DVI/HSTX, sim, WASM). +// [x0,y0,x1,y1) is the region to (re)composite (clamped to the framebuffer). Returns a +// latched StripDraw BaseException for the caller to re-raise, or MP_OBJ_NULL. +mp_obj_t picogame_render_framebuffer( + uint16_t *fb, int fb_stride, int fb_h, int fmt, + uint16_t *scratch, int scratch_rows, + mp_obj_t *items, uint8_t *kinds, size_t n, + int x0, int y0, int x1, int y1, + uint16_t background, int ox, int oy); +#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER diff --git a/shared-module/picogame/pg_compat.h b/shared-module/picogame/pg_compat.h new file mode 100644 index 00000000000..92c4168f6d8 --- /dev/null +++ b/shared-module/picogame/pg_compat.h @@ -0,0 +1,64 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// pg_compat.h — the small CircuitPython core-API delta the picogame engine relies on, +// OWNED BY THE ENGINE (not injected by a build-level force-`-include`). On CircuitPython +// this is a pure pass-through (every symbol is native); on a bare MicroPython build it +// supplies the ~9-symbol delta CP added over MicroPython. This lets the SAME engine C +// compile on both without a per-build shim impersonating CircuitPython. +// +// Engine TUs `#include "shared-module/picogame/pg_compat.h"` where they use any of these +// (it replaces the former `#include "py/objproperty.h"` in the bindings TUs). The function +// bodies for the MicroPython branch live in pg_compat_mp.c (compiled ONLY on MicroPython). +#pragma once + +#include "py/runtime.h" + +#if defined(CIRCUITPY) +// CircuitPython: everything below is native — pure pass-through. +#include "py/objproperty.h" +#else +// MicroPython: the core-API delta the engine needs that bare MicroPython lacks. +#include "py/obj.h" + +#ifndef RUN_BACKGROUND_TASKS +#define RUN_BACKGROUND_TASKS (mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS)) +#endif +#ifndef m_malloc_without_collect +#define m_malloc_without_collect(n) m_malloc(n) +#endif +#ifndef mp_raise_RuntimeError +#define mp_raise_RuntimeError(msg) mp_raise_msg(&mp_type_RuntimeError, (msg)) +#endif + +mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name); +mp_int_t mp_arg_validate_int_range(mp_int_t i, mp_int_t min, mp_int_t max, qstr arg_name); +mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_name); +NORETURN void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...); +NORETURN void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...); +mp_obj_t mp_obj_new_bytearray_of_zeros(size_t n); + +// CircuitPython's MP_PROPERTY_GETTER / MP_PROPERTY_GETSET convenience macros. Bare +// MicroPython keeps the property object private to py/objproperty.c; redeclare the +// struct with MP's EXACT layout + the macros in the non-native form (identical to +// CircuitPython's own !MICROPY_PY_OBJ_PROPERTY_NATIVE branch), so the generated +// property objects are ABI-compatible with MP's mp_type_property. +#if MICROPY_PY_BUILTINS_PROPERTY +typedef struct _mp_obj_property_t { + mp_obj_base_t base; + mp_obj_t proxy[3]; // getter, setter, deleter +} mp_obj_property_getset_t; +#ifndef MP_PROPERTY_GETTER +#define MP_PROPERTY_GETTER(P, G) \ + const mp_obj_property_getset_t P = { .base.type = &mp_type_property, .proxy = {G, MP_ROM_NONE, MP_ROM_NONE} } +#endif +#ifndef MP_PROPERTY_GETSET +#define MP_PROPERTY_GETSET(P, G, S) \ + const mp_obj_property_getset_t P = { .base.type = &mp_type_property, .proxy = {G, S, MP_ROM_NONE} } +#endif +#endif // MICROPY_PY_BUILTINS_PROPERTY + +#endif // CIRCUITPY diff --git a/shared-module/rainbowio/__init__.c b/shared-module/rainbowio/__init__.c index 8fdc8867666..20fd83a4fc4 100644 --- a/shared-module/rainbowio/__init__.c +++ b/shared-module/rainbowio/__init__.c @@ -7,7 +7,10 @@ #include "shared-bindings/rainbowio/__init__.h" int32_t colorwheel(mp_float_t pos) { - pos = pos - ((uint32_t)(pos / 256) * 256); + pos = pos - (mp_float_t)((int32_t)(pos / 256) * 256); + if (pos < 0) { + pos += 256; + } int shift1, shift2; if (pos < 85) { shift1 = 8; diff --git a/shared-module/random/__init__.c b/shared-module/random/__init__.c index 26d11313962..65876ab5788 100644 --- a/shared-module/random/__init__.c +++ b/shared-module/random/__init__.c @@ -20,9 +20,11 @@ static uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233; static uint8_t yasmarang_dat = 0; +static bool yasmarang_seeded = false; static uint32_t yasmarang(void) { - if (yasmarang_pad == 0xeda4baba) { + if (!yasmarang_seeded) { + yasmarang_seeded = true; if (!common_hal_os_urandom((uint8_t *)&yasmarang_pad, sizeof(uint32_t))) { yasmarang_pad = common_hal_time_monotonic_ms() & 0xffffffff; } @@ -57,6 +59,7 @@ void shared_modules_random_seed(mp_uint_t seed) { yasmarang_n = 69; yasmarang_d = 233; yasmarang_dat = 0; + yasmarang_seeded = true; } mp_uint_t shared_modules_random_getrandbits(uint8_t n) { diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index bd3ea62d141..5c9050f2662 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -7,15 +7,18 @@ // This implementation largely follows the structure of adafruit_sdcard.py #include "extmod/vfs.h" - #include "shared-bindings/busio/SPI.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/sdcardio/SDCard.h" #include "shared-bindings/time/__init__.h" #include "shared-bindings/util.h" #include "shared-module/sdcardio/SDCard.h" +#include "supervisor/shared/tick.h" #include "py/mperrno.h" +#include "py/mphal.h" +#include "py/gc.h" +#include "supervisor/port.h" #if 0 #define DEBUG_PRINT(...) ((void)mp_printf(&mp_plat_print,##__VA_ARGS__)) @@ -23,7 +26,17 @@ #define DEBUG_PRINT(...) ((void)0) #endif -#define CMD_TIMEOUT (200) +// https://nodeloop.org/guides/sd-card-spi-init-guide/ is an excellent source of info for SPI card use. + +// https://www.taterli.com/wp-content/uploads/2017/05/Physical-Layer-Simplified-SpecificationV6.0.pdf +// specifies timeouts for read (100 ms), write (250 ms), erase (depends on size), and other operations. +// cmd timeout was 250, but did not work on some cards. +// See https://github.com/adafruit/circuitpython/issues/10954 +#define CMD_TIMEOUT_MS (500) +#define SPI_TIMEOUT_MS (250) +// Init ready timeout. +#define READY_TIMEOUT_MS (300) + #define R1_IDLE_STATE (1 << 0) #define R1_ILLEGAL_COMMAND (1 << 2) @@ -32,20 +45,42 @@ #define TOKEN_STOP_TRAN (0xFD) #define TOKEN_DATA (0xFE) +bool common_hal_sdcardio_sdcard_deinited(sdcardio_sdcard_obj_t *self) { + // Also check SPI bus was deinited out from under us. + if (!self->bus || common_hal_busio_spi_deinited(self->bus)) { + return true; + } + return false; +} + +void common_hal_sdcardio_sdcard_mark_deinit(sdcardio_sdcard_obj_t *self) { + self->bus = NULL; +} + static void common_hal_sdcardio_check_for_deinit(sdcardio_sdcard_obj_t *self) { - if (!self->bus) { + if (common_hal_sdcardio_sdcard_deinited(self)) { raise_deinited_error(); } } static bool lock_and_configure_bus(sdcardio_sdcard_obj_t *self) { - common_hal_sdcardio_check_for_deinit(self); + if (common_hal_sdcardio_sdcard_deinited(self)) { + return false; + } + + if (!common_hal_busio_spi_wait_for_lock(self->bus, SPI_TIMEOUT_MS)) { + return false; + } - if (!common_hal_busio_spi_try_lock(self->bus)) { + // Make sure we can still use the SPI bus after grabbing the lock. + // The VM might be in the process of shutting down, and there could be a race. + if (!vm_is_running() && !self->persistent_mount) { + common_hal_busio_spi_unlock(self->bus); return false; } + common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8); - common_hal_digitalio_digitalinout_set_value(&self->cs, false); + digitalinout_protocol_set_value(self->cs, false); return true; } @@ -56,11 +91,10 @@ static void lock_bus_or_throw(sdcardio_sdcard_obj_t *self) { } static void clock_card(sdcardio_sdcard_obj_t *self, int bytes) { - uint8_t buf[] = {0xff}; - common_hal_digitalio_digitalinout_set_value(&self->cs, true); - for (int i = 0; i < bytes; i++) { - common_hal_busio_spi_write(self->bus, buf, 1); - } + uint8_t buf[bytes]; + memset(buf, 0xff, bytes); + digitalinout_protocol_set_value(self->cs, true); + common_hal_busio_spi_write(self->bus, buf, bytes); } static void extraclock_and_unlock_bus(sdcardio_sdcard_obj_t *self) { @@ -83,21 +117,35 @@ static uint8_t CRC7(const uint8_t *data, uint8_t n) { return (crc << 1) | 1; } -#define READY_TIMEOUT_NS (300 * 1000 * 1000) // 300ms -static int wait_for_ready(sdcardio_sdcard_obj_t *self) { - uint64_t deadline = common_hal_time_monotonic_ns() + READY_TIMEOUT_NS; - while (common_hal_time_monotonic_ns() < deadline) { +// Assumes that the spi lock has been acquired. +// +// Mask the incoming value with mask. Use 0xff to not mask. +// if not_match is true, wait for something NOT matching the value. +// Return the response as an int32_t (which is always >= 0), or -1 if timed out. +static int32_t wait_for_masked_response(sdcardio_sdcard_obj_t *self, uint8_t mask, uint8_t response, bool not_match, uint32_t timeout_ms) { + uint64_t deadline = supervisor_ticks_ms64() + timeout_ms; + while (supervisor_ticks_ms64() < deadline) { uint8_t b; common_hal_busio_spi_read(self->bus, &b, 1, 0xff); - if (b == 0xff) { - return 0; + if (((b & mask) == response) ^ not_match) { + return b; } } - return -ETIMEDOUT; + return -1; +} + +// Wait for the given response byte. +static bool wait_for_response(sdcardio_sdcard_obj_t *self, uint8_t response) { + return wait_for_masked_response(self, 0xff, response, false, CMD_TIMEOUT_MS) != -1; +} + +// Wait for 0xff, with a specific timeout. +static bool wait_for_ready(sdcardio_sdcard_obj_t *self) { + return wait_for_masked_response(self, 0xff, 0xff, false, READY_TIMEOUT_MS) != -1; } // Note: this is never called while "in cmd25" (in fact, it's only used by `exit_cmd25`) -static bool cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { +static mp_negative_errno_t cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { uint8_t cmdbuf[2] = {cmd, 0xff}; assert(!self->in_cmd25); @@ -105,17 +153,14 @@ static bool cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); // Wait for the response (response[7] == response) - for (int i = 0; i < CMD_TIMEOUT; i++) { - common_hal_busio_spi_read(self->bus, cmdbuf, 1, 0xff); - if (cmdbuf[0] == response) { - return 0; - } + if (wait_for_response(self, response)) { + return 0; } - return -EIO; + return -MP_EIO; } -static int exit_cmd25(sdcardio_sdcard_obj_t *self) { +static mp_negative_errno_t exit_cmd25(sdcardio_sdcard_obj_t *self) { if (self->in_cmd25) { DEBUG_PRINT("exit cmd25\n"); self->in_cmd25 = false; @@ -126,7 +171,7 @@ static int exit_cmd25(sdcardio_sdcard_obj_t *self) { // In Python API, defaults are response=None, data_block=True, wait=True static int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf, size_t response_len, bool data_block, bool wait) { - int r = exit_cmd25(self); + mp_negative_errno_t r = exit_cmd25(self); if (r < 0) { return r; } @@ -141,48 +186,43 @@ static int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf cmdbuf[5] = CRC7(cmdbuf, 5); if (wait) { - r = wait_for_ready(self); - if (r < 0) { - return r; + if (!wait_for_ready(self)) { + return -MP_ETIMEDOUT; } } common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); // Wait for the response (response[7] == 0) - bool response_received = false; - for (int i = 0; i < CMD_TIMEOUT; i++) { - common_hal_busio_spi_read(self->bus, cmdbuf, 1, 0xff); - if ((cmdbuf[0] & 0x80) == 0) { - response_received = true; - break; - } - } - - if (!response_received) { - return -EIO; + // Now wait for cmd response, which is the high bit being 0. + int32_t response = wait_for_masked_response(self, 0x80, 0, false, CMD_TIMEOUT_MS); + if (response == -1) { + return -MP_EIO; } if (response_buf) { if (data_block) { cmdbuf[1] = 0xff; - do { - // Wait for the start block byte - common_hal_busio_spi_read(self->bus, cmdbuf + 1, 1, 0xff); - } while (cmdbuf[1] != 0xfe); + if (!wait_for_response(self, 0xfe)) { + return -MP_EIO; + } } - common_hal_busio_spi_read(self->bus, response_buf, response_len, 0xff); + if (!common_hal_busio_spi_read(self->bus, response_buf, response_len, 0xff)) { + return -MP_EIO; + } if (data_block) { // Read and discard the CRC-CCITT checksum - common_hal_busio_spi_read(self->bus, cmdbuf + 1, 2, 0xff); + if (!common_hal_busio_spi_read(self->bus, cmdbuf + 1, 2, 0xff)) { + return -MP_EIO; + } } } - return cmdbuf[0]; + return response; } static int block_cmd(sdcardio_sdcard_obj_t *self, int cmd_, int block, void *response_buf, size_t response_len, bool data_block, bool wait) { @@ -190,7 +230,8 @@ static int block_cmd(sdcardio_sdcard_obj_t *self, int cmd_, int block, void *res } static mp_rom_error_text_t init_card_v1(sdcardio_sdcard_obj_t *self) { - for (int i = 0; i < CMD_TIMEOUT; i++) { + uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS; + while (supervisor_ticks_ms64() < deadline) { if (cmd(self, 41, 0, NULL, 0, true, true) == 0) { return NULL; } @@ -199,7 +240,8 @@ static mp_rom_error_text_t init_card_v1(sdcardio_sdcard_obj_t *self) { } static mp_rom_error_text_t init_card_v2(sdcardio_sdcard_obj_t *self) { - for (int i = 0; i < CMD_TIMEOUT; i++) { + uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS; + while (supervisor_ticks_ms64() < deadline) { uint8_t ocr[4]; common_hal_time_delay_ms(50); cmd(self, 58, 0, ocr, sizeof(ocr), false, true); @@ -216,9 +258,11 @@ static mp_rom_error_text_t init_card_v2(sdcardio_sdcard_obj_t *self) { } static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { + // https://nodeloop.org/guides/sd-card-spi-init-guide/ recommends at least 74 bit clocks + // and says 80 bit clocks(10*8) is common. Value below is bytes, not bits. clock_card(self, 10); - common_hal_digitalio_digitalinout_set_value(&self->cs, false); + digitalinout_protocol_set_value(self->cs, false); assert(!self->in_cmd25); self->in_cmd25 = false; // should be false already @@ -274,7 +318,7 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { } if (csd_version == 1) { - self->sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024; + self->sectors = (((csd[7] & 0x3F) << 16 | csd[8] << 8 | csd[9]) + 1) * 1024; } else { uint32_t block_length = 1 << (csd[5] & 0xF); uint32_t c_size = ((csd[6] & 0x3) << 10) | (csd[7] << 2) | ((csd[8] & 0xC) >> 6); @@ -294,13 +338,20 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { return NULL; } -mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate) { +mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mp_obj_t cs, int baudrate, bool persistent_mount) { self->bus = bus; - common_hal_digitalio_digitalinout_construct(&self->cs, cs); - common_hal_digitalio_digitalinout_switch_to_output(&self->cs, true, DRIVE_MODE_PUSH_PULL); + self->persistent_mount = persistent_mount; + + // Allocate the pins in the same place as self. + bool use_port_allocation = !gc_alloc_possible() || !gc_ptr_on_heap(self); + + self->cs = digitalinout_protocol_from_pin(cs, MP_QSTR_cs, false, use_port_allocation, &self->own_cs); + digitalinout_protocol_switch_to_output(self->cs, true, DRIVE_MODE_PUSH_PULL); self->cdv = 512; self->sectors = 0; + + // During initialization, talk to the SPI card between 100 khZ and 400 kHz. After that, can use full speed. self->baudrate = 250000; lock_bus_or_throw(self); @@ -308,7 +359,10 @@ mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio extraclock_and_unlock_bus(self); if (result != NULL) { - common_hal_digitalio_digitalinout_deinit(&self->cs); + if (self->own_cs) { + digitalinout_protocol_deinit(self->cs); + circuitpy_free_obj(self->cs); + } return result; } @@ -317,20 +371,24 @@ mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio } -void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate) { - mp_rom_error_text_t result = sdcardio_sdcard_construct(self, bus, cs, baudrate); +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mp_obj_t cs, int baudrate) { + // User mounted, so persistent_mount=false. + mp_rom_error_text_t result = sdcardio_sdcard_construct(self, bus, cs, baudrate, false); if (result != NULL) { mp_raise_OSError_msg(result); } } void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self) { - if (!self->bus) { + if (common_hal_sdcardio_sdcard_deinited(self)) { return; } common_hal_sdcardio_sdcard_sync(self); - self->bus = 0; - common_hal_digitalio_digitalinout_deinit(&self->cs); + common_hal_sdcardio_sdcard_mark_deinit(self); + if (self->own_cs) { + digitalinout_protocol_deinit(self->cs); + circuitpy_free_obj(self->cs); + } } int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self) { @@ -339,23 +397,25 @@ int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self) { } static int readinto(sdcardio_sdcard_obj_t *self, void *buf, size_t size) { - uint8_t aux[2] = {0, 0}; - while (aux[0] != 0xfe) { - common_hal_busio_spi_read(self->bus, aux, 1, 0xff); + + if (!wait_for_response(self, 0xfe)) { + return -MP_EIO; } common_hal_busio_spi_read(self->bus, buf, size, 0xff); // Read checksum and throw it away - common_hal_busio_spi_read(self->bus, aux, sizeof(aux), 0xff); + uint8_t checksum[2]; + common_hal_busio_spi_read(self->bus, checksum, sizeof(checksum), 0xff); return 0; } +// The mp_uint_t is misleading; negative errors can be returned. mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t nblocks) { // deinit check is in lock_and_configure_bus() sdcardio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!lock_and_configure_bus(self)) { - return MP_EAGAIN; + return -MP_ETIMEDOUT; } int r = 0; size_t buflen = 512 * nblocks; @@ -388,6 +448,7 @@ mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t st } } extraclock_and_unlock_bus(self); + // No caller actually uses this value. return r; } @@ -400,7 +461,9 @@ int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t } static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t size) { - wait_for_ready(self); + if (!wait_for_ready(self)) { + return -MP_ETIMEDOUT; + } uint8_t cmd[2]; cmd[0] = token; @@ -423,12 +486,12 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t // with STATUS 010 indicating "data accepted", and other status bit // combinations indicating failure. // In practice, I was seeing cmd[0] as 0xe5, indicating success - for (int i = 0; i < CMD_TIMEOUT; i++) { + uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS; + while (supervisor_ticks_ms64() < deadline) { common_hal_busio_spi_read(self->bus, cmd, 1, 0xff); - DEBUG_PRINT("i=%02d cmd[0] = 0x%02x\n", i, cmd[0]); if ((cmd[0] & 0b00010001) == 0b00000001) { if ((cmd[0] & 0x1f) != 0x5) { - return -EIO; + return -MP_EIO; } else { break; } @@ -436,9 +499,11 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t } // Wait for the write to finish - do { - common_hal_busio_spi_read(self->bus, cmd, 1, 0xff); - } while (cmd[0] == 0); + + // Wait for a non-zero value. + if (wait_for_masked_response(self, 0xff /*mask*/, 0, true /*not_match*/, CMD_TIMEOUT_MS) == -1) { + return -MP_EIO; + } // Success return 0; @@ -448,7 +513,7 @@ mp_uint_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t s // deinit check is in lock_and_configure_bus() sdcardio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!lock_and_configure_bus(self)) { - return MP_EAGAIN; + return -MP_ETIMEDOUT; } if (!self->in_cmd25 || start_block != self->next_block) { @@ -480,23 +545,21 @@ mp_uint_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t s return 0; } -int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self) { +mp_negative_errno_t common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self) { // deinit check is in lock_and_configure_bus() - lock_and_configure_bus(self); + if (!lock_and_configure_bus(self)) { + return -MP_ETIMEDOUT; + } int r = exit_cmd25(self); extraclock_and_unlock_bus(self); return r; } -int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { - // deinit check is in lock_and_configure_bus() +mp_negative_errno_t common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { if (buf->len % 512 != 0) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 512); } - lock_and_configure_bus(self); - int r = sdcardio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), buf->buf, start_block, buf->len / 512); - extraclock_and_unlock_bus(self); - return r; + return sdcardio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), buf->buf, start_block, buf->len / 512); } bool sdcardio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *out_value) { @@ -504,11 +567,8 @@ bool sdcardio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *o *out_value = 0; switch (cmd) { case MP_BLOCKDEV_IOCTL_DEINIT: - common_hal_sdcardio_sdcard_sync(self); - break; // TODO properly case MP_BLOCKDEV_IOCTL_SYNC: - common_hal_sdcardio_sdcard_sync(self); - break; + return common_hal_sdcardio_sdcard_sync(self) == 0; case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: *out_value = common_hal_sdcardio_sdcard_get_blockcount(self); break; diff --git a/shared-module/sdcardio/SDCard.h b/shared-module/sdcardio/SDCard.h index f9cd64b8125..6af68c274cd 100644 --- a/shared-module/sdcardio/SDCard.h +++ b/shared-module/sdcardio/SDCard.h @@ -17,12 +17,16 @@ typedef struct { mp_obj_base_t base; busio_spi_obj_t *bus; - digitalio_digitalinout_obj_t cs; + mp_obj_t cs; int cdv; int baudrate; uint32_t sectors; uint32_t next_block; bool in_cmd25; + // Automounted SD cards are usually persistent across VM's. Note this as needed to allow access + // when the VM is not running. + bool persistent_mount; + bool own_cs; } sdcardio_sdcard_obj_t; -mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate); +mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mp_obj_t cs, int baudrate, bool persistent_mount); diff --git a/shared-module/sdcardio/__init__.c b/shared-module/sdcardio/__init__.c index 29c890c6870..d53f7a3fabd 100644 --- a/shared-module/sdcardio/__init__.c +++ b/shared-module/sdcardio/__init__.c @@ -6,13 +6,17 @@ #include "shared-module/sdcardio/__init__.h" +#include "py/obj.h" + #include "extmod/vfs_fat.h" +#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/sdcardio/SDCard.h" #include "supervisor/filesystem.h" +#include "supervisor/shared/settings.h" #ifdef DEFAULT_SD_CARD_DETECT static digitalio_digitalinout_obj_t sd_card_detect_pin; @@ -22,7 +26,7 @@ static mp_vfs_mount_t _sdcard_vfs; fs_user_mount_t _sdcard_usermount; static bool _init_error = false; -static bool _mounted = false; +static bool _automounted = false; #ifdef DEFAULT_SD_MOSI static busio_spi_obj_t busio_spi_obj; @@ -42,10 +46,25 @@ void sdcardio_init(void) { void automount_sd_card(void) { #ifdef DEFAULT_SD_CARD_DETECT + #if CIRCUITPY_SETTINGS_TOML + // Honor the runtime CIRCUITPY_SDCARD_USB setting. When disabled, never + // claim the shared SD pins (SCK/MOSI/MISO/CS) via SPI, so they remain free + // for other uses such as sdioio, which drives the same physical pins. + // Read once and cache, matching usb_msc_flash.c's handling. + static int8_t _sdcard_usb_enabled = -1; // -1 unknown, 0 false, 1 true + if (_sdcard_usb_enabled < 0) { + bool setting = true; + (void)settings_get_bool("CIRCUITPY_SDCARD_USB", &setting); + _sdcard_usb_enabled = setting ? 1 : 0; + } + if (!_sdcard_usb_enabled) { + return; + } + #endif if (common_hal_digitalio_digitalinout_get_value(&sd_card_detect_pin) != DEFAULT_SD_CARD_INSERTED) { // No card. _init_error = false; - if (_mounted) { + if (_automounted) { // Unmount the card. mp_vfs_mount_t *cur = MP_STATE_VM(vfs_mount_table); if (cur == &_sdcard_vfs) { @@ -63,11 +82,11 @@ void automount_sd_card(void) { #ifdef DEFAULT_SD_MOSI common_hal_busio_spi_deinit(&busio_spi_obj); #endif - _mounted = false; + _automounted = false; } return; - } else if (_init_error || _mounted) { - // We've already tried and failed to init the card. Don't try again. + } else if (_init_error || _automounted) { + // We've already tried and failed to init the card, or it's still mounted. Don't try again. return; } @@ -81,18 +100,20 @@ void automount_sd_card(void) { common_hal_busio_spi_never_reset(spi_obj); #endif sdcard.base.type = &sdcardio_SDCard_type; - mp_rom_error_text_t error = sdcardio_sdcard_construct(&sdcard, spi_obj, DEFAULT_SD_CS, 25000000); + mp_obj_t cs_obj = MP_OBJ_FROM_PTR(DEFAULT_SD_CS); + mp_rom_error_text_t error = sdcardio_sdcard_construct(&sdcard, spi_obj, cs_obj, 25000000, true); if (error != NULL) { // Failed to communicate with the card. - _mounted = false; + _automounted = false; _init_error = true; #ifdef DEFAULT_SD_MOSI common_hal_busio_spi_deinit(spi_obj); #endif return; } - common_hal_digitalio_digitalinout_never_reset(&sdcard.cs); - + if (mp_obj_is_type(cs_obj, &mcu_pin_type)) { + common_hal_digitalio_digitalinout_never_reset(MP_OBJ_TO_PTR(sdcard.cs)); + } fs_user_mount_t *vfs = &_sdcard_usermount; vfs->base.type = &mp_fat_vfs_type; vfs->fatfs.drv = vfs; @@ -104,7 +125,7 @@ void automount_sd_card(void) { // mount the block device so the VFS methods can be used FRESULT res = f_mount(&vfs->fatfs); if (res != FR_OK) { - _mounted = false; + _automounted = false; _init_error = true; common_hal_sdcardio_sdcard_deinit(&sdcard); #ifdef DEFAULT_SD_MOSI @@ -122,6 +143,6 @@ void automount_sd_card(void) { sdcard_vfs->obj = MP_OBJ_FROM_PTR(&_sdcard_usermount); sdcard_vfs->next = MP_STATE_VM(vfs_mount_table); MP_STATE_VM(vfs_mount_table) = sdcard_vfs; - _mounted = true; + _automounted = true; #endif // DEFAULT_SD_CARD_DETECT } diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index 3c6eaf065df..8b9629b002f 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -54,11 +54,7 @@ static bool common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(sha } void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self) { - if (self->bus != &self->inline_bus - #if CIRCUITPY_BOARD_SPI - && !common_hal_board_is_spi(self->bus) - #endif - ) { + if (self->bus != &self->inline_bus && gc_ptr_on_heap(self->bus)) { memcpy(&self->inline_bus, self->bus, sizeof(busio_spi_obj_t)); self->bus = &self->inline_bus; } diff --git a/shared-module/ssl/SSLContext.c b/shared-module/ssl/SSLContext.c index e58074ea3ea..47e8b9f3149 100644 --- a/shared-module/ssl/SSLContext.c +++ b/shared-module/ssl/SSLContext.c @@ -12,7 +12,15 @@ #include "lib/mbedtls_config/crt_bundle.h" +#include "psa/crypto.h" + void common_hal_ssl_sslcontext_construct(ssl_sslcontext_obj_t *self) { + // TLS is built on PSA crypto, which has to be initialized before any of it is + // used. OK to psa_crypto_init() multiple times. On espressif, ESP-IDF has already done this during + // its own system init and this call is a no-op. + if (psa_crypto_init() != PSA_SUCCESS) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_ssl); + } common_hal_ssl_sslcontext_set_default_verify_paths(self); } diff --git a/shared-module/ssl/SSLSocket.c b/shared-module/ssl/SSLSocket.c index 8911fa2f454..a9969505509 100644 --- a/shared-module/ssl/SSLSocket.c +++ b/shared-module/ssl/SSLSocket.c @@ -13,7 +13,7 @@ #include "shared/netutils/netutils.h" #include "py/mperrno.h" #include "py/mphal.h" -#include "py/objstr.h" +#include "py/objarray.h" #include "py/runtime.h" #include "py/stream.h" #include "supervisor/shared/tick.h" @@ -28,10 +28,6 @@ #include "../../lib/mbedtls_errors/mp_mbedtls_errors.c" #endif -#if MBEDTLS_VERSION_MAJOR >= 3 -#include "shared-bindings/os/__init__.h" -#endif - #ifdef MBEDTLS_DEBUG_C #include "mbedtls/debug.h" static void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) { @@ -44,7 +40,9 @@ static void mbedtls_debug(void *ctx, int level, const char *file, int line, cons #define DEBUG_PRINT(...) do {} while (0) #endif -static NORETURN void mbedtls_raise_error(int err) { +// Raise an OSError for an mbedtls error code. +// `flags` is a bitmask from mbedtls_ssl_get_verify_result(), or 0 if not a verify error. +static MP_NORETURN void mbedtls_raise_error_flags(int err, uint32_t flags) { // _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 @@ -57,37 +55,78 @@ static NORETURN void mbedtls_raise_error(int err) { mp_raise_OSError(MP_EWOULDBLOCK); } + // All ones means mbedtls says it has nothing to report: it set to all ones + // when a verify callback fails, and mbedtls_ssl_get_verify_result() returns + // this when there is no session at all. + if (flags == UINT32_MAX) { + flags = 0; + } + #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_malloc_without_collect(ERR_STR_MAX); - if (o_str == NULL || o_str_buf == NULL) { + // Large enough for the longest mbedtls_strerror() output, which is about 100 + // characters when it joins a high-level and a low-level name with '+', and for + // the longest certificate verification failure name, which is 81 characters. + #define ERR_STR_MAX 128 // mbedtls_strerror truncates if it doesn't fit + // One byte larger than the bound passed to mbedtls_strerror(), so that the + // strncpy() inside it has a bound smaller than the size of buf. Truncation + // there is safe and deliberate, but an equal bound trips -Wstringop-truncation. + char buf[ERR_STR_MAX + 1]; + + // Assemble the error message in a vstr. + // If we run out of heap, catch the MemoryError and fall back to just the error number. + mp_obj_t exc; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + vstr_t vstr; + vstr_init(&vstr, ERR_STR_MAX); + + mbedtls_strerror(err, buf, ERR_STR_MAX); + vstr_add_str(&vstr, buf); + + #if !defined(MBEDTLS_X509_REMOVE_INFO) + // Call mbedtls_x509_crt_verify_info() to get the error string + // for each individual verify error bit. + // This allows for easier string management. + // Several verify errorbits are often set at once: + // mbedtls or's together the error flags of every certificate in the chain. + // For instance, a cert served under the wrong name and signed by an + // unknown CA reports CN_MISMATCH and NOT_TRUSTED together. + for (uint32_t bit = 1; bit != 0; bit <<= 1) { + if ((flags & bit) == 0) { + continue; + } + // The prefix is added to the beginning of the message. + // We drop the supplied trailing newline. + int info_len = mbedtls_x509_crt_verify_info(buf, ERR_STR_MAX, "; ", bit); + if (info_len > 1) { + // -1 to drop the newline. + vstr_add_strn(&vstr, buf, info_len - 1); + } + } + #endif + + mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), mp_obj_new_str_from_utf8_vstr(&vstr) }; + exc = mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args); + nlr_pop(); + } else { + // Could not build the message, so report the number by itself. 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)); + nlr_raise(exc); #else - // mbedtls is compiled without error strings so we simply return the err number + // mbedtls is compiled without error strings, so just return the err number mp_raise_OSError(err); // err is typically a large negative number #endif } +static MP_NORETURN void mbedtls_raise_error(int err) { + mbedtls_raise_error_flags(err, 0); +} + // Because ssl_socket_send and ssl_socket_recv_into are callbacks from mbedtls code, // it is not OK to exit them by raising an exception (nlr_jump'ing through // foreign code is not permitted). Instead, preserve the error number of any OSError @@ -200,16 +239,6 @@ static int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { } -#if MBEDTLS_VERSION_MAJOR >= 3 -static int urandom_adapter(void *unused, unsigned char *buf, size_t n) { - int result = common_hal_os_urandom(buf, n); - if (result) { - return 0; - } - return MBEDTLS_ERR_SSL_INTERNAL_ERROR; -} -#endif - ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t *self, mp_obj_t socket, bool server_side, const char *server_hostname) { @@ -238,20 +267,12 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t 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(4); #endif - mbedtls_entropy_init(&o->entropy); - const byte seed[] = "upy"; - int 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, + int ret = mbedtls_ssl_config_defaults(&o->conf, server_side ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); @@ -273,7 +294,6 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t } else { mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); } - 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 @@ -293,11 +313,7 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t mbedtls_ssl_set_bio(&o->ssl, o, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); if (self->cert_buf.buf != NULL) { - #if MBEDTLS_VERSION_MAJOR >= 3 - ret = mbedtls_pk_parse_key(&o->pkey, self->key_buf.buf, self->key_buf.len + 1, NULL, 0, urandom_adapter, NULL); - #else ret = mbedtls_pk_parse_key(&o->pkey, self->key_buf.buf, self->key_buf.len + 1, NULL, 0); - #endif if (ret != 0) { goto cleanup; } @@ -318,8 +334,6 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t 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_type(&mp_type_MemoryError); @@ -382,8 +396,6 @@ void common_hal_ssl_sslsocket_close(ssl_sslsocket_obj_t *self) { 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); } static void do_handshake(ssl_sslsocket_obj_t *self) { @@ -403,13 +415,20 @@ static void do_handshake(ssl_sslsocket_obj_t *self) { cleanup: self->closed = true; + + // Verification flags are only valid for CERT_VERIFY_FAILED. + // Read them before mbedtls_ssl_free() below: they live in the ssl context's + // session_negotiate and are gone once it is freed. + uint32_t verify_flags = 0; + if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { + verify_flags = mbedtls_ssl_get_verify_result(&self->ssl); + } + 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); if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_type(&mp_type_MemoryError); @@ -418,7 +437,7 @@ static void do_handshake(ssl_sslsocket_obj_t *self) { } else if (ret == MBEDTLS_ERR_X509_BAD_INPUT_DATA) { mp_raise_ValueError(MP_ERROR_TEXT("invalid cert")); } else { - mbedtls_raise_error(ret); + mbedtls_raise_error_flags(ret, verify_flags); } } diff --git a/shared-module/ssl/SSLSocket.h b/shared-module/ssl/SSLSocket.h index f7f3d1ae83c..f3bb858a00d 100644 --- a/shared-module/ssl/SSLSocket.h +++ b/shared-module/ssl/SSLSocket.h @@ -15,15 +15,11 @@ #include "mbedtls/ssl.h" #include "mbedtls/x509_crt.h" #include "mbedtls/pk.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" typedef struct ssl_sslsocket_obj { mp_obj_base_t base; mp_obj_t sock_obj; ssl_sslcontext_obj_t *ssl_context; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt cacert; diff --git a/shared-module/storage/__init__.c b/shared-module/storage/__init__.c index dedcee1ff23..1522136332a 100644 --- a/shared-module/storage/__init__.c +++ b/shared-module/storage/__init__.c @@ -27,7 +27,7 @@ #include "tusb.h" // Is the MSC device enabled? -bool storage_usb_is_enabled; +static volatile bool storage_usb_is_enabled; void storage_usb_set_defaults(void) { storage_usb_is_enabled = CIRCUITPY_USB_MSC_ENABLED_DEFAULT; @@ -38,16 +38,29 @@ bool storage_usb_enabled(void) { } static bool usb_drive_set_enabled(bool enabled) { - // We can't change the descriptors once we're connected. + // We can't change the descriptors once we're connected, but we can make the LUN be ready or not ready. + storage_usb_is_enabled = enabled; if (tud_connected()) { - return false; + // The TEST UNIT READY callback in usb_msc_flash.c checks the value of storage_usb_is_enabled. + // If it's false, TEST UNIT READY will report "not ready" + // Linux and macOS send a TEST UNIT READY poll about every 1.1 seconds or faster. + // Windows polls every 2.1 seconds or so. + // So wait long enough for host to send a TEST UNIT READY and receive a reply. + mp_hal_delay_ms(2500); } filesystem_set_internal_writable_by_usb(enabled); - storage_usb_is_enabled = enabled; return true; } bool common_hal_storage_disable_usb_drive(void) { + if (tud_connected()) { + // Complain if already connected. Use `storage.unsafe_disable_usb_drive()` in that case. + return false; + } + return usb_drive_set_enabled(false); +} + +bool common_hal_storage_unsafe_disable_usb_drive(void) { return usb_drive_set_enabled(false); } @@ -59,6 +72,10 @@ bool common_hal_storage_disable_usb_drive(void) { return false; } +bool common_hal_storage_unsafe_disable_usb_drive(void) { + return false; +} + bool common_hal_storage_enable_usb_drive(void) { return false; } diff --git a/shared-module/struct/__init__.c b/shared-module/struct/__init__.c index 715b5043021..ce71d06b754 100644 --- a/shared-module/struct/__init__.c +++ b/shared-module/struct/__init__.c @@ -14,7 +14,8 @@ #include "shared-bindings/struct/__init__.h" static void struct_validate_format(char fmt) { - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES + if (fmt == 'S' || fmt == 'O') { mp_raise_RuntimeError(MP_ERROR_TEXT("'S' and 'O' are not supported format types")); } @@ -46,7 +47,7 @@ static mp_uint_t get_fmt_num(const char **p) { while (unichar_isdigit(*++num)) { len++; } - mp_uint_t val = (mp_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10, NULL)); + mp_uint_t val = (mp_uint_t)mp_obj_get_int(mp_parse_num_integer(*p, len, 10, NULL)); *p = num; return val; } diff --git a/shared-module/synthio/Biquad.c b/shared-module/synthio/Biquad.c index 08aab81a7bf..baaaa0eed79 100644 --- a/shared-module/synthio/Biquad.c +++ b/shared-module/synthio/Biquad.c @@ -156,7 +156,7 @@ void common_hal_synthio_biquad_tick(mp_obj_t self_in) { case SYNTHIO_PEAKING_EQ: b0 = 1 + alpha * A; b1 = -2 * sc.c; - b2 = 1 + alpha * A; + b2 = 1 - alpha * A; a0 = 1 + alpha / A; a1 = -2 * sc.c; a2 = 1 - alpha / A; @@ -194,7 +194,11 @@ void common_hal_synthio_biquad_tick(mp_obj_t self_in) { } void synthio_biquad_filter_reset(biquad_filter_state *st) { - memset(&st->x, 0, 4 * sizeof(int16_t)); + memset(st, 0, sizeof(*st)); +} + +static inline int32_t biquad_filter_sample(int32_t input, int32_t a1, int32_t a2, int32_t b0, int32_t b1, int32_t b2, int32_t x0, int32_t x1, int32_t y0, int32_t y1) { + return synthio_sat16((b0 * input + b1 * x0 + b2 * x1 - a1 * y0 - a2 * y1 + (1 << (BIQUAD_SHIFT - 1))), BIQUAD_SHIFT); } void synthio_biquad_filter_samples(mp_obj_t self_in, biquad_filter_state *st, int32_t *buffer, size_t n_samples) { @@ -213,7 +217,7 @@ void synthio_biquad_filter_samples(mp_obj_t self_in, biquad_filter_state *st, in for (size_t n = n_samples; n; --n, ++buffer) { int32_t input = *buffer; - int32_t output = synthio_sat16((b0 * input + b1 * x0 + b2 * x1 - a1 * y0 - a2 * y1 + (1 << (BIQUAD_SHIFT - 1))), BIQUAD_SHIFT); + int32_t output = biquad_filter_sample(input, a1, a2, b0, b1, b2, x0, x1, y0, y1); x1 = x0; x0 = input; @@ -226,3 +230,16 @@ void synthio_biquad_filter_samples(mp_obj_t self_in, biquad_filter_state *st, in st->y[0] = y0; st->y[1] = y1; } + +int32_t synthio_biquad_filter_sample(mp_obj_t self_in, biquad_filter_state *st, int32_t input) { + synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in); + + int32_t output = biquad_filter_sample(input, self->a1, self->a2, self->b0, self->b1, self->b2, st->x[0], st->x[1], st->y[0], st->y[1]); + + st->x[1] = st->x[0]; + st->x[0] = input; + st->y[1] = st->y[0]; + st->y[0] = output; + + return output; +} diff --git a/shared-module/synthio/Biquad.h b/shared-module/synthio/Biquad.h index 3b9920ed92f..cc9b4f53b0e 100644 --- a/shared-module/synthio/Biquad.h +++ b/shared-module/synthio/Biquad.h @@ -27,3 +27,4 @@ typedef struct { void common_hal_synthio_biquad_tick(mp_obj_t self_in); void synthio_biquad_filter_reset(biquad_filter_state *st); void synthio_biquad_filter_samples(mp_obj_t self_in, biquad_filter_state *st, int32_t *buffer, size_t n_samples); +int32_t synthio_biquad_filter_sample(mp_obj_t self_in, biquad_filter_state *st, int32_t input); diff --git a/shared-module/synthio/MidiTrack.c b/shared-module/synthio/MidiTrack.c index 1cccd440fad..7c54c36d47f 100644 --- a/shared-module/synthio/MidiTrack.c +++ b/shared-module/synthio/MidiTrack.c @@ -19,6 +19,7 @@ static mp_obj_t parse_note(synthio_miditrack_obj_t *self) { size_t len = self->track.len; if (self->pos + 1 >= len) { record_midi_stream_error(self); + return MP_OBJ_NEW_SMALL_INT(0); } uint8_t note = buffer[(self->pos)++]; if (note > 127 || buffer[(self->pos)++] > 127) { @@ -51,6 +52,9 @@ static void decode_until_pause(synthio_miditrack_obj_t *self) { uint8_t *buffer = self->track.buf; size_t len = self->track.len; do { + if (self->pos >= len) { + break; + } switch (buffer[self->pos++] >> 4) { case 8: { // Note Off mp_obj_t note = parse_note(self); diff --git a/shared-module/synthio/Note.c b/shared-module/synthio/Note.c index c8c307bb415..01c7e4ba487 100644 --- a/shared-module/synthio/Note.c +++ b/shared-module/synthio/Note.c @@ -196,13 +196,11 @@ static uint32_t pitch_bend(uint32_t frequency_scaled, int32_t bend_value) { uint32_t synthio_note_step(synthio_note_obj_t *self, int32_t sample_rate, int16_t dur, int16_t loudness[2]) { int panning = synthio_block_slot_get_scaled(&self->panning, -ALMOST_ONE, ALMOST_ONE); - int left_panning_scaled, right_panning_scaled; + int left_panning_scaled = 32768, right_panning_scaled = 32768; if (panning >= 0) { - left_panning_scaled = 32768; - right_panning_scaled = 32767 - panning; + left_panning_scaled = 32767 - panning; } else { - right_panning_scaled = 32768; - left_panning_scaled = 32767 + panning; + right_panning_scaled = 32767 + panning; } int amplitude = synthio_block_slot_get_scaled(&self->amplitude, -ALMOST_ONE, ALMOST_ONE); diff --git a/shared-module/synthio/__init__.c b/shared-module/synthio/__init__.c index db0c449bfab..6201ad96347 100644 --- a/shared-module/synthio/__init__.c +++ b/shared-module/synthio/__init__.c @@ -224,21 +224,20 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT; uint32_t accum = synth->accum[chan]; - if (dds_rate > lim / 2) { + if (dds_rate > (lim - offset) / 2) { // beyond nyquist, can't play note return false; } - // can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided - if (accum > lim) { - accum = accum % lim + offset; + if (accum >= lim) { + accum = accum < offset ? offset : offset + (accum - offset) % (lim - offset); } // first, fill with waveform for (uint16_t i = 0; i < dur; i++) { accum += dds_rate; // because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed - if (accum > lim) { + if (accum >= lim) { accum = accum - lim + offset; } int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT; @@ -247,31 +246,30 @@ static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *ou synth->accum[chan] = accum; if (ring_dds_rate) { - if (ring_dds_rate > lim / 2) { + accum = synth->ring_accum[chan]; + offset = ring_waveform_start << SYNTHIO_FREQUENCY_SHIFT; + lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT; + + if (ring_dds_rate > (lim - offset) / 2) { // beyond nyquist, can't play ring (but did synth main sound so // return true) return true; } - // now modulate by ring and accumulate - accum = synth->ring_accum[chan]; - offset = ring_waveform_start << SYNTHIO_FREQUENCY_SHIFT; - lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT; - // can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided - if (accum > lim) { - accum = accum % lim + offset; + if (accum >= lim) { + accum = accum < offset ? offset : offset + (accum - offset) % (lim - offset); } for (uint16_t i = 0; i < dur; i++) { accum += ring_dds_rate; // because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed - if (accum > lim) { + if (accum >= lim) { accum = accum - lim + offset; } int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT; - int16_t wi = (ring_waveform[idx] * out_buffer32[i]) / 32768; // consider for synthio_sat16 but had a weird artificat - out_buffer32[i] = wi; + int32_t wi = (ring_waveform[idx] * out_buffer32[i]) / 32768; + out_buffer32[i] = wi > 32767 ? 32767 : wi; } synth->ring_accum[chan] = accum; } @@ -289,17 +287,54 @@ static mp_obj_t synthio_synth_get_note_filter(mp_obj_t note_obj) { return mp_const_none; } -static void sum_with_loudness(int32_t *out_buffer32, int32_t *tmp_buffer32, int16_t loudness[2], size_t dur, int synth_chan) { +// Rather than immediately changing the loudness of audio playback, we keep a separate buffer of +// the "active" loudness and wait until we meet the conditions of a "zero crossing". A zero crossing +// occurs when either the current value is 0 or the value changes from negative to positive or +// vice-versa. This is detected by keeping a copy of the previous frame of audio data and checking +// to see if the sign of the value has changed. By only changing loudness during zero crossings, we +// avoid audible pops/clicks which can be unpleasant. +static void assign_loudness(int32_t word, int32_t *last_word, int16_t active_loudness[2], int16_t pending_loudness[2]) { + // If the active loudness already matches the pending loudness, exit early. + if (MP_LIKELY(active_loudness[0] == pending_loudness[0]) && MP_LIKELY(active_loudness[1] == pending_loudness[1])) { + return; + } + + // Check for a zero crossing: current value is 0 or has changed sign from the previous value. + if (word == 0 || (*last_word != 0 && ((*last_word > 0) == (word < 0) || (*last_word < 0) == (word > 0)))) { + // Copy over our pending loudness. Will cause future calls to `assign_loudness` to exit + // early. + active_loudness[0] = pending_loudness[0]; + active_loudness[1] = pending_loudness[1]; + } else { + // Update our copy of the previous word for future comparisons (an initial value of 0 is + // ignored). + *last_word = word; + } +} + +static void sum_with_loudness(int32_t *out_buffer32, int32_t *tmp_buffer32, int16_t active_loudness[2], int16_t pending_loudness[2], size_t dur, int synth_chan) { + int32_t word, last_word = 0; if (synth_chan == 1) { for (size_t i = 0; i < dur; i++) { - *out_buffer32++ += synthio_sat16((*tmp_buffer32++ *loudness[0]), 16); + word = *tmp_buffer32++; + assign_loudness(word, &last_word, active_loudness, pending_loudness); + *out_buffer32++ += synthio_sat16((word * active_loudness[0]), 16); } } else { for (size_t i = 0; i < dur; i++) { - *out_buffer32++ += synthio_sat16((*tmp_buffer32 * loudness[0]), 16); - *out_buffer32++ += synthio_sat16((*tmp_buffer32++ *loudness[1]), 16); + word = *tmp_buffer32; + assign_loudness(word, &last_word, active_loudness, pending_loudness); + *out_buffer32++ += synthio_sat16((word * active_loudness[0]), 16); + *out_buffer32++ += synthio_sat16((word * active_loudness[1]), 16); + tmp_buffer32++; } } + + // Force the active loudness to match the pending loudness just in case the conditions of a + // zero crossing weren't met within the last `SYNTHIO_MAX_DUR` frames. Will ensure minimal + // delay in amplitude or panning changes at the potential expensive of an audible pop. + active_loudness[0] = pending_loudness[0]; + active_loudness[1] = pending_loudness[1]; } void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t *buffer_length, uint8_t channel) { @@ -351,7 +386,7 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t } // adjust loudness by envelope - sum_with_loudness(out_buffer32, tmp_buffer32, loudness, dur, synth->base.channel_count); + sum_with_loudness(out_buffer32, tmp_buffer32, synth->active_loudness[chan], loudness, dur, synth->base.channel_count); } int16_t *out_buffer16 = (int16_t *)(void *)synth->buffers[synth->buffer_index]; @@ -460,8 +495,15 @@ static int find_channel_with_note(synthio_synth_t *synth, mp_obj_t note) { bool synthio_span_change_note(synthio_synth_t *synth, mp_obj_t old_note, mp_obj_t new_note) { int channel; if (new_note != SYNTHIO_SILENCE && (channel = find_channel_with_note(synth, new_note)) != -1) { - // note already playing, re-enter attack phase - synth->envelope_state[channel].state = SYNTHIO_ENVELOPE_STATE_ATTACK; + if (synth->envelope_state[channel].level == 0) { + // released and already decayed to silence, but not yet reaped: + // treat this like a fresh press, not a swell from 0 + synthio_envelope_state_init(&synth->envelope_state[channel], synthio_synth_get_note_envelope(synth, new_note)); + synth->accum[channel] = 0; + } else { + // note already playing, re-enter attack phase + synth->envelope_state[channel].state = SYNTHIO_ENVELOPE_STATE_ATTACK; + } return true; } channel = find_channel_with_note(synth, old_note); diff --git a/shared-module/synthio/__init__.h b/shared-module/synthio/__init__.h index 5162b49fd55..0335831f80f 100644 --- a/shared-module/synthio/__init__.h +++ b/shared-module/synthio/__init__.h @@ -55,6 +55,7 @@ typedef struct synthio_synth { uint32_t accum[CIRCUITPY_SYNTHIO_MAX_CHANNELS]; uint32_t ring_accum[CIRCUITPY_SYNTHIO_MAX_CHANNELS]; synthio_envelope_state_t envelope_state[CIRCUITPY_SYNTHIO_MAX_CHANNELS]; + int16_t active_loudness[CIRCUITPY_SYNTHIO_MAX_CHANNELS][2]; } synthio_synth_t; typedef struct { diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index 6e73804ea3a..bd363b5e9ae 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -201,12 +201,18 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con #endif const byte *i = data; + const byte *end = data + len; uint16_t start_y = self->cursor_y; - while (i < data + len) { + while (i < end) { unichar c = utf8_get_char(i); - i = utf8_next_char(i); + i++; + // utf8_next_char() assumes NUL-terminated data but callers pass + // length-delimited buffers, so bound the continuation-byte scan. + while (i < end && UTF8_IS_CONT(*i)) { + i++; + } if (self->in_osc_command) { - if (c == 0x1b && i[0] == '\\') { + if (c == 0x1b && i < end && i[0] == '\\') { self->in_osc_command = false; self->status_x = 0; self->status_y = 0; @@ -245,6 +251,10 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con uint8_t n_args = 1; #endif for (; j < 6; j++) { + if (i + j >= end) { + c = 0; + break; + } if ('0' <= i[j] && i[j] <= '9') { vt_args[0] = vt_args[0] * 10 + (i[j] - '0'); } else { @@ -252,10 +262,14 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con break; } } - if (i[0] == '[') { + if (i < end && i[0] == '[') { for (uint8_t i_args = 1; i_args < 3 && c == ';'; i_args++) { vt_args[i_args] = 0; for (++j; j < 12; j++) { + if (i + j >= end) { + c = 0; + break; + } if ('0' <= i[j] && i[j] <= '9') { vt_args[i_args] = vt_args[i_args] * 10 + (i[j] - '0'); #if CIRCUITPY_TERMINALIO_VT100 @@ -267,7 +281,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con } } } - if (c == '?') { + if (c == '?' && i + 4 < end) { #if CIRCUITPY_TERMINALIO_VT100 if (i[2] == '2' && i[3] == '5') { // cursor visibility commands @@ -358,7 +372,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con i += j + 1; } #if CIRCUITPY_TERMINALIO_VT100 - } else if (i[0] == 'M') { + } else if (i < end && i[0] == 'M') { if (self->cursor_y != SCRNMOD(self->vt_scroll_top)) { if (self->cursor_y > 0) { self->cursor_y = self->cursor_y - 1; @@ -400,11 +414,11 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con } start_y = self->cursor_y; i++; - } else if (i[0] == 'D') { + } else if (i < end && i[0] == 'D') { self->cursor_y++; i++; #endif - } else if (i[0] == ']' && c == ';') { + } else if (i < end && i[0] == ']' && c == ';') { self->in_osc_command = true; self->osc_command = vt_args[0]; i += j + 1; @@ -450,6 +464,9 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con start_y = self->cursor_y; } } + if (i > end) { + i = end; + } return i - data; } diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index 83def37de91..a3bb449e87e 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -135,6 +135,7 @@ static bool _wait_for_callback(void) { switch (result) { case XFER_RESULT_SUCCESS: return true; + case XFER_RESULT_ABORTED: case XFER_RESULT_FAILED: mp_raise_usb_core_USBError(NULL); break; @@ -174,7 +175,7 @@ static void _abort_transfer(tuh_xfer_t *xfer) { } // Only frees the transfer buffer on error. -static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer) { +static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer, bool raise_on_timeout) { if (xfer == NULL) { mp_raise_usb_core_USBError(NULL); return 0; @@ -195,12 +196,20 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout // Handle transfer result code from TinyUSB xfer_result_t result = _xfer_result; _xfer_result = XFER_RESULT_INVALID; - if (our_buffer && result != XFER_RESULT_SUCCESS && result != XFER_RESULT_INVALID) { + // Free the bounce buffer only on paths that raise: raising unwinds past + // the caller's cleanup, so it must be freed here. Paths that return + // normally leave ownership with the caller, which copies out of and + // frees the buffer itself (freeing on both sides would be a double free). + bool will_raise = result == XFER_RESULT_ABORTED || result == XFER_RESULT_FAILED || + result == XFER_RESULT_STALLED || + (result == XFER_RESULT_TIMEOUT && raise_on_timeout); + if (our_buffer && will_raise) { port_free(xfer->buffer); } switch (result) { case XFER_RESULT_SUCCESS: return _actual_len; + case XFER_RESULT_ABORTED: case XFER_RESULT_FAILED: mp_raise_usb_core_USBError(NULL); break; @@ -210,12 +219,18 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout case XFER_RESULT_TIMEOUT: // This timeout comes from TinyUSB, so assume that it has stopped the // transfer (note: timeout logic may be unimplemented on TinyUSB side) + if (!raise_on_timeout) { + return 0; + } mp_raise_usb_core_USBTimeoutError(); break; case XFER_RESULT_INVALID: // This timeout comes from CircuitPython, not TinyUSB, so tell TinyUSB - // to stop the transfer and then wait to free the buffer. + // to stop the transfer. _abort_transfer(xfer); + if (!raise_on_timeout) { + return 0; // the caller owns (and frees) the buffer + } if (our_buffer) { port_free(xfer->buffer); } @@ -383,7 +398,7 @@ void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, m } // Raises an exception on failure. Returns the number of bytes transferred (maybe zero) on success. -static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer) { +static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer, bool raise_on_timeout) { _prepare_for_transfer(); xfer->complete_cb = _transfer_done_cb; if (!tuh_edpt_xfer(xfer)) { @@ -393,7 +408,7 @@ static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer) { mp_raise_usb_core_USBError(NULL); return 0; } - return _handle_timed_transfer_callback(xfer, timeout, our_buffer); + return _handle_timed_transfer_callback(xfer, timeout, our_buffer, raise_on_timeout); } static bool _open_endpoint(usb_core_device_obj_t *self, mp_int_t endpoint) { @@ -467,7 +482,7 @@ mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t xfer.ep_addr = endpoint; xfer.buffer = dma_buffer; xfer.buflen = len; - size_t result = _xfer(&xfer, timeout, dma_buffer != buffer); + size_t result = _xfer(&xfer, timeout, dma_buffer != buffer, true); #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE if (dma_buffer != buffer) { port_free(dma_buffer); @@ -476,7 +491,7 @@ mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t return result; } -mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout) { +mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout, bool raise_on_timeout) { if (!_open_endpoint(self, endpoint)) { mp_raise_usb_core_USBError(NULL); return 0; @@ -498,7 +513,7 @@ mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t e xfer.ep_addr = endpoint; xfer.buffer = dma_buffer; xfer.buflen = len; - mp_int_t result = _xfer(&xfer, timeout, dma_buffer != buffer); + mp_int_t result = _xfer(&xfer, timeout, dma_buffer != buffer, raise_on_timeout); #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE // Copy data back to original buffer if needed @@ -554,7 +569,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, mp_raise_usb_core_USBError(NULL); return 0; } - mp_int_t result = (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout, dma_buffer != buffer); + mp_int_t result = (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout, dma_buffer != buffer, true); #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE if (dma_buffer != buffer) { diff --git a/shared-module/usb_audio/USBMicrophone.c b/shared-module/usb_audio/USBMicrophone.c new file mode 100644 index 00000000000..26a185ff0e9 --- /dev/null +++ b/shared-module/usb_audio/USBMicrophone.c @@ -0,0 +1,174 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/misc.h" +#include "py/runtime.h" + +#include "shared-bindings/usb_audio/USBMicrophone.h" +#include "shared-module/usb_audio/__init__.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" +#include "shared-module/audiocore/__init__.h" + +// Only one microphone may feed the single USB IN endpoint at a time. This points +// at the USBMicrophone whose play() was called most recently, or NULL when none +// is streaming. The USB background task pulls from it via +// usb_audio_usbmicrophone_background_fill(). +static usb_audio_usbmicrophone_obj_t *active_microphone = NULL; + +void common_hal_usb_audio_usbmicrophone_construct(usb_audio_usbmicrophone_obj_t *self) { + self->sample = MP_OBJ_NULL; + self->buffer = NULL; + self->buffer_length = 0; + self->loop = false; + self->playing = false; + self->paused = false; + self->deinited = false; + self->more_data = false; +} + +void common_hal_usb_audio_usbmicrophone_deinit(usb_audio_usbmicrophone_obj_t *self) { + common_hal_usb_audio_usbmicrophone_stop(self); + self->deinited = true; +} + +bool common_hal_usb_audio_usbmicrophone_deinited(usb_audio_usbmicrophone_obj_t *self) { + return self->deinited; +} + +void common_hal_usb_audio_usbmicrophone_play(usb_audio_usbmicrophone_obj_t *self, mp_obj_t sample, bool loop) { + // The negotiated USB format is fixed 16-bit signed LE PCM at the rate/channel + // count chosen by usb_audio.enable() in boot.py. Resampling and format + // conversion are out of scope, so the source must already match exactly. This + // mirrors how audiocore's audiosample_must_match() validates an output's input + // (and reuses its error messages), but checks against the USB format rather + // than another audiosample. + audiosample_base_t *sample_base = audiosample_check(sample); + if (audiosample_get_sample_rate(sample_base) != usb_audio_sample_rate) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); + } + if (audiosample_get_channel_count(sample_base) != usb_audio_channel_count) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); + } + if (audiosample_get_bits_per_sample(sample_base) != USB_AUDIO_BITS_PER_SAMPLE) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_bits_per_sample); + } + if (!sample_base->samples_signed) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); + } + + // Start at the beginning and arm the pull loop to request the first chunk. + audiosample_reset_buffer(sample, false, 0); + self->sample = sample; + self->buffer = NULL; + self->buffer_length = 0; + self->loop = loop; + self->playing = true; + self->paused = false; + self->more_data = true; + // Take over the single USB IN endpoint from any other microphone. + active_microphone = self; +} + +void common_hal_usb_audio_usbmicrophone_stop(usb_audio_usbmicrophone_obj_t *self) { + self->sample = MP_OBJ_NULL; + self->buffer = NULL; + self->buffer_length = 0; + self->playing = false; + self->paused = false; + self->more_data = false; + if (active_microphone == self) { + active_microphone = NULL; + } +} + +bool common_hal_usb_audio_usbmicrophone_get_playing(usb_audio_usbmicrophone_obj_t *self) { + return self->playing && !self->paused; +} + +void common_hal_usb_audio_usbmicrophone_pause(usb_audio_usbmicrophone_obj_t *self) { + self->paused = true; +} + +void common_hal_usb_audio_usbmicrophone_resume(usb_audio_usbmicrophone_obj_t *self) { + self->paused = false; +} + +bool common_hal_usb_audio_usbmicrophone_get_paused(usb_audio_usbmicrophone_obj_t *self) { + return self->playing && self->paused; +} + +size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { + usb_audio_usbmicrophone_obj_t *self = active_microphone; + if (self == NULL || !self->playing || self->paused || self->sample == MP_OBJ_NULL) { + return 0; + } + + // The negotiated USB format is 16-bit signed PCM. For this step the + // bound sample is assumed to already be in that format (e.g. a 16-bit signed + // audiocore.RawSample), so its bytes are copied straight through. + size_t filled = 0; + while (filled < max_bytes) { + if (self->buffer_length == 0) { + if (!self->more_data) { + // The previous chunk was the sample's last and we've played it + // out. Loop back to the start or stop. + if (self->loop) { + audiosample_reset_buffer(self->sample, false, 0); + self->more_data = true; + } else { + common_hal_usb_audio_usbmicrophone_stop(self); + break; + } + } + audioio_get_buffer_result_t result = + audiosample_get_buffer(self->sample, false, 0, &self->buffer, &self->buffer_length); + if (result == GET_BUFFER_ERROR) { + common_hal_usb_audio_usbmicrophone_stop(self); + break; + } + self->more_data = (result == GET_BUFFER_MORE_DATA); + if (self->buffer_length == 0) { + // No samples available right now (underrun); the caller fills the + // rest of the frame with silence and we retry next tick. + break; + } + } + + // Bytes written to out, and bytes consumed from the sample's chunk. They + // differ when a mono sample feeds the always-stereo USB stream. + size_t written; + size_t consumed; + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + written = consumed = MIN(self->buffer_length, max_bytes - filled); + memcpy(out + filled, self->buffer, written); + } else { + // Mono source: duplicate each sample into both USB channels. Work in + // whole stereo frames so a partial frame can never be emitted, and + // cap by both what the chunk holds and what still fits in out. + size_t frames = MIN(self->buffer_length / USB_AUDIO_N_BYTES_PER_SAMPLE, + (max_bytes - filled) / USB_AUDIO_BYTES_PER_FRAME); + const int16_t *in = (const int16_t *)(const void *)self->buffer; + int16_t *dest = (int16_t *)(void *)(out + filled); + for (size_t i = 0; i < frames; i++) { + dest[2 * i] = dest[2 * i + 1] = in[i]; + } + written = frames * USB_AUDIO_BYTES_PER_FRAME; + consumed = frames * USB_AUDIO_N_BYTES_PER_SAMPLE; + } + if (written == 0) { + // Less than one whole frame of room left in out (or nothing to copy): + // stop rather than spin. The caller pads the remainder with silence. + break; + } + self->buffer += consumed; + self->buffer_length -= consumed; + filled += written; + } + + return filled; +} diff --git a/shared-module/usb_audio/USBMicrophone.h b/shared-module/usb_audio/USBMicrophone.h new file mode 100644 index 00000000000..74f167e8e43 --- /dev/null +++ b/shared-module/usb_audio/USBMicrophone.h @@ -0,0 +1,33 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +typedef struct usb_audio_usbmicrophone_obj { + mp_obj_base_t base; + // The audiosample currently bound for streaming, or MP_OBJ_NULL. + mp_obj_t sample; + // Cursor into the chunk last returned by audiosample_get_buffer(): the next + // unread byte and the number of bytes still unread in that chunk. + uint8_t *buffer; + uint32_t buffer_length; + bool loop; + bool playing; + bool paused; + bool deinited; + // False once audiosample_get_buffer() reported GET_BUFFER_DONE for the + // current chunk; the chunk is still played out, then we loop or stop. + bool more_data; +} usb_audio_usbmicrophone_obj_t; + +// Pull up to max_bytes of audio (in the negotiated USB PCM format) from whichever +// USBMicrophone is currently playing, writing it into out. Returns the number of +// bytes written, which is < max_bytes (possibly 0) when nothing is streaming or +// the source underruns; the caller pads the remainder with silence. Called from +// the USB background task in shared-module/usb_audio/__init__.c. +size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes); diff --git a/shared-module/usb_audio/USBSpeaker.c b/shared-module/usb_audio/USBSpeaker.c new file mode 100644 index 00000000000..c04ee9b280d --- /dev/null +++ b/shared-module/usb_audio/USBSpeaker.c @@ -0,0 +1,267 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/misc.h" + +#include "shared-bindings/usb_audio/USBSpeaker.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-module/usb_audio/__init__.h" + +#include "tusb.h" + +// The ring is sized independently of the TinyUSB headers (see USBSpeaker.h); +// check it still matches the OUT endpoint's software FIFO so the push side can be +// reasoned about against the USB plumbing. +MP_STATIC_ASSERT(USB_AUDIO_SPEAKER_RING_SIZE == CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); + +// Only one speaker can be fed by the single USB OUT endpoint at a time. This +// points at the most recently constructed USBSpeaker, or NULL when none exists, +// mirroring active_microphone in USBMicrophone.c. The USB background task pushes +// received bytes into it via usb_audio_usbspeaker_background_drain(). +static usb_audio_usbspeaker_obj_t *active_speaker = NULL; + +void common_hal_usb_audio_usbspeaker_construct(usb_audio_usbspeaker_obj_t *self) { + // The pipeline treats the speaker as an ordinary audiosample source, so + // populate base from the format negotiated by usb_audio.enable(). The UAC2 + // format we present is 16-bit signed LE PCM, which is exactly what the + // CircuitPython audio pipeline carries, so no conversion is needed. + self->base.sample_rate = usb_audio_sample_rate; + self->base.bits_per_sample = USB_AUDIO_BITS_PER_SAMPLE; + self->base.channel_count = usb_audio_channel_count; + self->base.samples_signed = true; + self->base.single_buffer = false; + self->base.max_buffer_length = USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE; + + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + self->output_index = 0; + + // The most recently created speaker receives the host's OUT stream. + active_speaker = self; +} + +void common_hal_usb_audio_usbspeaker_deinit(usb_audio_usbspeaker_obj_t *self) { + // Stop directing USB OUT data at this object. The producer (drain) and this + // deinit both run in non-interrupt context, so the pointer swap needs no + // interrupt guard. + if (active_speaker == self) { + active_speaker = NULL; + } + audiosample_mark_deinit(&self->base); +} + +bool common_hal_usb_audio_usbspeaker_deinited(usb_audio_usbspeaker_obj_t *self) { + return audiosample_deinited(&self->base); +} + +bool common_hal_usb_audio_usbspeaker_get_connected(usb_audio_usbspeaker_obj_t *self) { + (void)self; + // True while the host has opened the OUT streaming interface, i.e. it is + // actively sending audio. Speaker-specific so it stays correct when a mic + // shares the same headset function. + return usb_audio_speaker_streaming(); +} + +// --------------------------------------------------------------------+ +// Receive ring (push side, producer = USB background task) +// --------------------------------------------------------------------+ +// +// The ring decouples the two independently clocked stages from +// usb_audio_output_plan.md: USB push (paced by the host's SOF clock, in the +// background task) and the audiosample pull (paced by the output backend's +// sample clock, in its refill interrupt). It is a single-producer/ +// single-consumer ring across an interrupt boundary: +// +// * Producer: usb_audio_usbspeaker_background_drain(), task context. +// * Consumer: usb_audio_usbspeaker_get_buffer(), output DMA/refill ISR. +// +// The consumer is an interrupt, so it can never be preempted by the producer and +// needs no guard of its own. The producer can be preempted by the consumer, and +// its drop-oldest overrun handling touches both cursors, so it does its whole +// read-modify-write with interrupts disabled. + +void usb_audio_usbspeaker_streaming_reset(void) { + usb_audio_usbspeaker_obj_t *self = active_speaker; + if (self == NULL) { + return; + } + common_hal_mcu_disable_interrupts(); + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + common_hal_mcu_enable_interrupts(); +} + +void usb_audio_usbspeaker_background_drain(const uint8_t *in, size_t n) { + usb_audio_usbspeaker_obj_t *self = active_speaker; + if (self == NULL || n == 0) { + return; + } + if (n >= USB_AUDIO_SPEAKER_RING_SIZE) { + // A single chunk larger than the whole ring can only contribute its + // newest tail. (Cannot happen with USB packets << ring size, but keep + // the copies provably in-bounds.) + in += n - USB_AUDIO_SPEAKER_RING_SIZE; + n = USB_AUDIO_SPEAKER_RING_SIZE; + } + + common_hal_mcu_disable_interrupts(); + + size_t free_space = USB_AUDIO_SPEAKER_RING_SIZE - self->ring_count; + if (n > free_space) { + // Overrun: advance the read cursor past the oldest bytes we're about to + // overwrite, keeping latency bounded and following the newest host audio. + size_t drop = n - free_space; + self->ring_tail = (self->ring_tail + drop) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_count -= drop; + } + + // Copy in one or two segments, wrapping at the end of the ring. + size_t first = MIN(n, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_head); + memcpy(&self->ring[self->ring_head], in, first); + if (n > first) { + memcpy(&self->ring[0], in + first, n - first); + } + self->ring_head = (self->ring_head + n) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_count += n; + + common_hal_mcu_enable_interrupts(); +} + +uint32_t common_hal_usb_audio_usbspeaker_read(usb_audio_usbspeaker_obj_t *self, + void *buffer, uint32_t length) { + // Hand the most recent host audio to Python so it can be analysed (e.g. an + // audio-reactive effect or VU meter). This drains the ring just like the + // output backend's get_buffer() does, so it is an alternative *consumer*: + // a USBSpeaker being read this way must not also be play()ed to an output + // backend at the same time, or the two consumers would race on the single + // SPSC ring. + // + // Unlike get_buffer() (which runs in the output refill ISR and so needs no + // guard) this runs in VM/task context and can be preempted by the USB + // producer, so it brackets its read-modify-write with interrupts disabled, + // mirroring usb_audio_usbspeaker_background_drain(). + // The ring holds wire-format frames (always USB_AUDIO_N_CHANNELS channels). + // `length` and the return value count entries in `buffer`, i.e. 16-bit + // samples: a stereo speaker writes one per channel of each frame, a mono one + // keeps only each frame's left channel. + bool mono = usb_audio_channel_count != USB_AUDIO_N_CHANNELS; + size_t samples_per_frame = mono ? 1 : USB_AUDIO_N_CHANNELS; + size_t want = (size_t)(length / samples_per_frame) * USB_AUDIO_BYTES_PER_FRAME; + + common_hal_mcu_disable_interrupts(); + size_t to_copy = MIN(self->ring_count, want); + // Never split a frame across calls (the ring always holds whole UAC2 frames, + // but stay defensive so the returned count is always a whole number). + to_copy -= to_copy % USB_AUDIO_BYTES_PER_FRAME; + + size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); + if (MP_LIKELY(!mono)) { + memcpy(buffer, &self->ring[self->ring_tail], first); + if (to_copy > first) { + memcpy((uint8_t *)buffer + first, &self->ring[0], to_copy - first); + } + } else { + int16_t *word_out = (int16_t *)buffer; + const int16_t *word_ring = (const int16_t *)(const void *)self->ring; + size_t base = self->ring_tail / USB_AUDIO_N_BYTES_PER_SAMPLE; + size_t written = 0; + for (size_t i = 0; i < first / USB_AUDIO_N_BYTES_PER_SAMPLE; i += USB_AUDIO_N_CHANNELS) { + word_out[written++] = word_ring[base + i]; + } + for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_N_BYTES_PER_SAMPLE; i += USB_AUDIO_N_CHANNELS) { + word_out[written++] = word_ring[i]; + } + } + self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_count -= to_copy; + common_hal_mcu_enable_interrupts(); + + return to_copy / USB_AUDIO_BYTES_PER_FRAME * samples_per_frame; +} + +// --------------------------------------------------------------------+ +// audiosample protocol (pull side, consumer = output backend) +// --------------------------------------------------------------------+ + +void usb_audio_usbspeaker_reset_buffer(usb_audio_usbspeaker_obj_t *self, + bool single_channel_output, uint8_t channel) { + (void)single_channel_output; + (void)channel; + // Begin playback from live audio rather than whatever was buffered before: + // drop the ring and restart the double-buffer. Guarded because some ports may + // call reset_buffer outside the initial setup. + common_hal_mcu_disable_interrupts(); + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + common_hal_mcu_enable_interrupts(); + self->output_index = 0; +} + +audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker_obj_t *self, + bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { + + uint32_t half = self->base.max_buffer_length / 2; + uint8_t *out = self->output_buffer + half * self->output_index; + self->output_index = 1 - self->output_index; + + // Consumer side of the SPSC ring (runs in the output backend's refill ISR). + // It is never preempted by the producer, so no interrupt guard is required. + size_t to_copy = MIN(self->ring_count, (size_t)half); + + // Bytes produced in out. The ring always holds wire-format (stereo) frames; + // a mono sample keeps only the left channel of each, so it produces half. + bool mono = usb_audio_channel_count != USB_AUDIO_N_CHANNELS; + size_t produced = mono ? to_copy / 2 : to_copy; + + size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); + if (MP_LIKELY(!mono)) { + memcpy(out, &self->ring[self->ring_tail], first); + if (to_copy > first) { + memcpy(out + first, &self->ring[0], to_copy - first); + } + } else { + // Take the left sample of each stereo frame, across up to two ring + // segments. Indices are in int16 units, counted from the segment start. + int16_t *word_out = (int16_t *)(void *)out; + const int16_t *word_ring = (const int16_t *)(const void *)self->ring; + size_t base = self->ring_tail / USB_AUDIO_N_BYTES_PER_SAMPLE; + size_t written = 0; + for (size_t i = 0; i < first / USB_AUDIO_N_BYTES_PER_SAMPLE; i += USB_AUDIO_N_CHANNELS) { + word_out[written++] = word_ring[base + i]; + } + for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_N_BYTES_PER_SAMPLE; i += USB_AUDIO_N_CHANNELS) { + word_out[written++] = word_ring[i]; + } + } + self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_count -= to_copy; + + // Bytes the caller will be handed, which is all a mono sample can fill. + uint32_t out_length = mono ? half / 2 : half; + if (produced < out_length) { + // Underrun: pad the remainder with silence. Samples are signed, so + // silence is 0. This is the consume-side of the pacing failure mode + // tracked in the usb-audio-artifact-pacing memory: we never spin. + memset(out + produced, 0, out_length - produced); + } + + // Computed the same way as audiocore.RawSample so stereo (interleaved ring) + // can extend it. + if (single_channel_output) { + out += (channel % self->base.channel_count) * (self->base.bits_per_sample / 8); + } + + *buffer = out; + *buffer_length = out_length; + // A live USB stream is infinite; never report DONE or the backend would stop. + return GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/usb_audio/USBSpeaker.h b/shared-module/usb_audio/USBSpeaker.h new file mode 100644 index 00000000000..0760676b53a --- /dev/null +++ b/shared-module/usb_audio/USBSpeaker.h @@ -0,0 +1,73 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" + +// One half-buffer of the audiosample double-buffer holds this many frames. The +// output backend pulls a half each get_buffer() call, so this sets the pull +// granularity and the silence-pad chunk on underrun. It is deliberately +// independent of the USB OUT software FIFO (the ring below) so the push and pull +// stages can be tuned separately, and small enough that two halves sit +// comfortably inside the ring. +#define USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER (128) + +// Bytes per audio frame in the negotiated UAC2 format (stereo 16-bit). +#define USB_AUDIO_SPEAKER_BYTES_PER_FRAME (USB_AUDIO_N_BYTES_PER_SAMPLE * USB_AUDIO_N_CHANNELS) + +// Full owned double-buffer: two halves of FRAMES_PER_BUFFER frames each. Matches +// audiocore.RawSample's convention where base.max_buffer_length is the whole +// buffer and get_buffer() returns half of it. +#define USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE (2 * USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER * USB_AUDIO_SPEAKER_BYTES_PER_FRAME) + +// Host -> board receive ring size. Mirrors CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ +// (16 * the full-speed OUT wMaxPacketSize) but is spelled out from the format +// constants so this struct definition stays free of the TinyUSB headers. A +// MP_STATIC_ASSERT in USBSpeaker.c checks the two stay equal. +#define USB_AUDIO_SPEAKER_OUT_PACKET_SIZE ((USB_AUDIO_MAX_SAMPLE_RATE / 1000 + 1) * USB_AUDIO_SPEAKER_BYTES_PER_FRAME) +#define USB_AUDIO_SPEAKER_RING_SIZE (16 * USB_AUDIO_SPEAKER_OUT_PACKET_SIZE) + +typedef struct usb_audio_usbspeaker_obj { + // First member so the object can be used directly as an audiosample source. + audiosample_base_t base; + + // Host -> board receive ring (the "push" stage). Filled by the USB + // background task via usb_audio_usbspeaker_background_drain() and drained by + // get_buffer(). Single producer (task), single consumer (output DMA ISR); + // see the concurrency notes in USBSpeaker.c. + uint8_t ring[USB_AUDIO_SPEAKER_RING_SIZE]; + size_t ring_head; // next write offset + size_t ring_tail; // next read offset + size_t ring_count; // valid bytes currently in the ring + + // Owned double-buffer returned to the output backend by get_buffer(). + uint8_t output_buffer[USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE]; + uint8_t output_index; // 0 or 1: which half get_buffer() fills next +} usb_audio_usbspeaker_obj_t; + +// audiosample protocol implementation. Not exposed to Python because get_buffer() +// runs in the output backend's refill interrupt. +void usb_audio_usbspeaker_reset_buffer(usb_audio_usbspeaker_obj_t *self, + bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker_obj_t *self, + bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); + +// Push n bytes received on the USB OUT endpoint into the active speaker's ring. +// Called from the USB background task (see usb_audio_task()). No-op when no +// speaker is active. Overrun policy: drop the oldest buffered bytes. +void usb_audio_usbspeaker_background_drain(const uint8_t *in, size_t n); + +// Drop anything buffered in the active speaker's ring so a (re)opened stream +// starts from live audio. Called when the host opens/closes the OUT streaming +// interface. +void usb_audio_usbspeaker_streaming_reset(void); diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c new file mode 100644 index 00000000000..16f5952bc6a --- /dev/null +++ b/shared-module/usb_audio/__init__.c @@ -0,0 +1,714 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/usb_audio/__init__.h" +#include "shared-bindings/usb_audio/USBMicrophone.h" +#include "shared-bindings/usb_audio/USBSpeaker.h" +#include "shared-module/usb_audio/__init__.h" +#include "shared-module/usb_audio/USBMicrophone.h" +#include "shared-module/usb_audio/USBSpeaker.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" + +#include + +#include "py/misc.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "supervisor/port.h" +#include "supervisor/shared/tick.h" +#include "supervisor/usb.h" +#include "tusb.h" + +// Scratch chunk the microphone task hands to TinyUSB. It is written from the USB +// background task for as long as the device is enabled, which outlives every VM, +// so it comes from the port heap rather than the MicroPython heap. Sized by +// enable() for 1 ms at the negotiated rate, in the wire format (always +// USB_AUDIO_N_CHANNELS channels), so a board that never calls enable() pays +// nothing for it. +static int16_t *usb_audio_mic_samples; +static size_t usb_audio_mic_samples_len; + +static bool usb_audio_is_enabled = false; + +// The host opens each AudioStreaming interface independently (alt 0 = idle, alt 1 +// = streaming), so the two directions of a headset are tracked separately. For +// the single-direction microphone/speaker only the matching flag is ever set. +static bool usb_audio_mic_streaming = false; +static bool usb_audio_spk_streaming = false; + +// AudioStreaming interface numbers assigned when the descriptor is built, used to +// route the host's set-interface requests to the right direction. 0xff until a +// descriptor that includes that direction has been emitted. +static uint8_t usb_audio_mic_as_itf = 0xff; +static uint8_t usb_audio_spk_as_itf = 0xff; + +uint32_t usb_audio_sample_rate; +uint8_t usb_audio_channel_count; +bool usb_audio_microphone_enabled; +bool usb_audio_speaker_enabled; + +// Audio control state surfaced to the host. One extra entry for the master channel 0. +static int8_t usb_audio_mute[USB_AUDIO_N_CHANNELS + 1]; +static int16_t usb_audio_volume[USB_AUDIO_N_CHANNELS + 1]; + +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, bool microphone, bool speaker) { + if (tud_connected()) { + return false; + } + + // One scratch chunk (1 ms at the sample rate); we loop until the FIFO reaches + // the setpoint. enable() may be called more than once, so release any chunk + // sized for a previous rate before taking a new one. + port_free(usb_audio_mic_samples); + usb_audio_mic_samples_len = sample_rate / 1000 * USB_AUDIO_BYTES_PER_FRAME; + usb_audio_mic_samples = port_malloc_zero(usb_audio_mic_samples_len, false); + if (usb_audio_mic_samples == NULL) { + usb_audio_mic_samples_len = 0; + return false; + } + + usb_audio_sample_rate = sample_rate; + usb_audio_channel_count = channel_count; + usb_audio_microphone_enabled = microphone; + usb_audio_speaker_enabled = speaker; + usb_audio_is_enabled = true; + + return true; +} + +bool shared_module_usb_audio_disable(void) { + if (tud_connected()) { + return false; + } + usb_audio_is_enabled = false; + port_free(usb_audio_mic_samples); + usb_audio_mic_samples = NULL; + usb_audio_mic_samples_len = 0; + return true; +} + +bool usb_audio_enabled(void) { + return usb_audio_is_enabled; +} + +bool usb_audio_streaming(void) { + return usb_audio_mic_streaming || usb_audio_spk_streaming; +} + +// True while the host has the speaker (OUT) stream open, i.e. it is actively +// sending audio. Used by USBSpeaker.connected so it reflects the speaker +// direction specifically even when a mic shares the same headset function. +bool usb_audio_speaker_streaming(void) { + return usb_audio_spk_streaming; +} + +void usb_audio_setup_singletons(void) { + // USBMicrophone and USBSpeaker are singletons rather than constructible + // classes (like usb_midi.ports). The host-facing format and direction are + // fixed by usb_audio.enable() in boot.py and persist in C globals, but the + // instances themselves live on the GC heap, which is reset between boot.py + // and code.py, so they are rebuilt here once per VM. Each is created only + // when its direction was enabled; otherwise it is left as None. + // + // The objects are held in MP_STATE_VM root pointers so the GC keeps them + // alive for the whole VM (the module globals table is static data and is not + // a GC root, so a reference from there alone would be swept). Rooting the + // microphone also traces its bound audiosample (self->sample). They are then + // installed in the module globals so they are reachable as the + // usb_audio.usb_microphone / usb_audio.usb_speaker attributes. + mp_obj_t microphone = mp_const_none; + mp_obj_t speaker = mp_const_none; + + if (usb_audio_is_enabled) { + const bool has_input = usb_audio_microphone_enabled; + const bool has_output = usb_audio_speaker_enabled; + + if (has_input) { + usb_audio_usbmicrophone_obj_t *self = + mp_obj_malloc_with_finaliser(usb_audio_usbmicrophone_obj_t, &usb_audio_USBMicrophone_type); + common_hal_usb_audio_usbmicrophone_construct(self); + microphone = MP_OBJ_FROM_PTR(self); + } + if (has_output) { + usb_audio_usbspeaker_obj_t *self = + mp_obj_malloc_with_finaliser(usb_audio_usbspeaker_obj_t, &usb_audio_USBSpeaker_type); + common_hal_usb_audio_usbspeaker_construct(self); + speaker = MP_OBJ_FROM_PTR(self); + } + } + + MP_STATE_VM(usb_audio_microphone_singleton) = microphone; + MP_STATE_VM(usb_audio_speaker_singleton) = speaker; + + mp_map_lookup(&usb_audio_module_globals.map, MP_ROM_QSTR(MP_QSTR_usb_microphone), MP_MAP_LOOKUP)->value = + microphone; + mp_map_lookup(&usb_audio_module_globals.map, MP_ROM_QSTR(MP_QSTR_usb_speaker), MP_MAP_LOOKUP)->value = + speaker; +} + +// Hand-rolled UAC2 speaker (host -> board) descriptor WITHOUT an async +// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO20_SPEAKER_STEREO_FB_DESCRIPTOR +// (lib/tinyusb/src/device/usbd.h) but drops the trailing feedback endpoint, so +// the streaming alt-setting declares a single OUT endpoint (_nEPs = 0x01). The +// entity IDs match the mic descriptor (see usb_audio_descriptors.h); only the +// terminal roles reverse: the input terminal is the USB-streaming side and the +// output terminal is the desktop speaker, and the AS interface links the input +// terminal (0x01). Async feedback for true clock matching is a later step. +#define USB_AUDIO_SPEAKER_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN + TUD_AUDIO20_DESC_INPUT_TERM_LEN + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the input terminal */ \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +// Hand-rolled UAC2 microphone (board -> host) descriptor WITHOUT an async +// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR +// (lib/tinyusb/src/device/usbd.h) but drops the trailing feedback endpoint, so +// the streaming alt-setting declares a single IN endpoint (_nEPs = 0x00). Async +// feedback for true clock matching is a later step. +#define USB_AUDIO_MIC_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN + TUD_AUDIO20_DESC_INPUT_TERM_LEN + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +// Hand-rolled UAC2 headset (microphone + speaker both enabled): one audio function +// presenting both a speaker (host -> board OUT) and a microphone (board -> host +// IN) at once. This combines USB_AUDIO_SPEAKER_DESCRIPTOR's speaker chain with +// USB_AUDIO_MIC_DESCRIPTOR's mic chain under a single IAD. The two chains +// must use distinct entity IDs (USB_AUDIO_HS_ENTITY_*; see usb_audio_descriptors.h) +// because they live in the same AudioControl interface, and they share one clock +// source. The function spans three interfaces: AudioControl (_itfnum), the +// speaker AudioStreaming interface (_itfnum + 1, OUT endpoint), and the mic +// AudioStreaming interface (_itfnum + 2, IN endpoint). Neither stream has an +// async feedback endpoint, matching the single-direction descriptors. +#define USB_AUDIO_HEADSET_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) -- 3 interfaces */ \ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x03, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) -- clock + both chains */ \ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN + 2 * (TUD_AUDIO20_DESC_INPUT_TERM_LEN + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2) + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) -- shared by both chains */ \ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ + /* --- Speaker chain (host -> board) --- */ \ + /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ + /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* --- Mic chain (board -> host) --- */ \ + /* Input Terminal Descriptor(4.7.2.4) -- generic microphone */ \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ + /* Output Terminal Descriptor(4.7.2.5) -- USB streaming out to the host */ \ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* --- Speaker AudioStreaming interface (_itfnum + 1) --- */ \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the speaker input terminal */ \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000), \ + /* --- Mic AudioStreaming interface (_itfnum + 2) --- */ \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one IN endpoint */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the mic output terminal */ \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +// Combined headset: both a microphone (board -> host IN) and a speaker +// (host -> board OUT) under one audio function. +static bool usb_audio_direction_is_input_output(void) { + return usb_audio_microphone_enabled && usb_audio_speaker_enabled; +} + +// Speaker only (host -> board OUT), no microphone. +static bool usb_audio_direction_is_output(void) { + return usb_audio_speaker_enabled && !usb_audio_microphone_enabled; +} + +size_t usb_audio_descriptor_length(void) { + if (usb_audio_direction_is_input_output()) { + return USB_AUDIO_HEADSET_DESC_LEN; + } + if (usb_audio_direction_is_output()) { + return USB_AUDIO_SPEAKER_DESC_LEN; + } + return USB_AUDIO_MIC_DESC_LEN; +} + +size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string) { + // Pick the isochronous endpoint number. By default it follows the same + // sequential allocation as every other interface. On ports that pin ISO to a + // fixed, dedicated endpoint (USB_AUDIO_ISO_EP_NUM != 0; see the header for the + // nRF52 case), we use that number instead and leave the sequential counters + // untouched: the dedicated ISO endpoint is a separate hardware resource, so + // it must not consume one of the regular endpoint numbers the other + // interfaces draw from. + const bool forced_iso_ep = (USB_AUDIO_ISO_EP_NUM != 0); + const uint8_t iso_ep_num = forced_iso_ep ? USB_AUDIO_ISO_EP_NUM : descriptor_counts->current_endpoint; + + if (usb_audio_direction_is_input_output()) { + // Combined headset: a speaker AudioStreaming interface (OUT) and a mic + // AudioStreaming interface (IN) under one AudioControl interface, so one + // isochronous endpoint in each direction. + // + // Sequential-allocation ports (e.g. RP2) take a distinct number for each + // direction. Ports that pin ISO to a dedicated endpoint number + // (forced_iso_ep, e.g. nRF52) use that one number for BOTH directions: + // the constraint there is the endpoint *number*, not the direction. The + // nRF52 USBD has a separate ISOIN and ISOOUT on endpoint 8, and TinyUSB + // splits the ISO buffer (ISOSPLIT = HalfIN) when both are open, so 0x08 + // and 0x88 can run at the same time. As in the single-direction branches + // below, the dedicated ISO endpoint is separate hardware and must not + // consume the sequential endpoint numbers the other interfaces draw from. + const uint8_t ep_out = forced_iso_ep ? iso_ep_num : descriptor_counts->current_endpoint; + const uint8_t ep_in = forced_iso_ep ? iso_ep_num : (descriptor_counts->current_endpoint + 1); + + usb_add_interface_string(*current_interface_string, "CircuitPython Headset"); + + const uint8_t usb_audio_descriptor[] = { + USB_AUDIO_HEADSET_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epout*/ ep_out, + /*_epin*/ ep_in | 0x80, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) + }; + + // Speaker AS is the first interface after AudioControl, mic AS the second. + usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; + usb_audio_mic_as_itf = descriptor_counts->current_interface + 2; + + (*current_interface_string)++; + // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus a + // single isochronous endpoint in each direction. On sequential-allocation + // ports the two directions take separate endpoint numbers, consuming two of + // the port's endpoint pairs. On forced_iso_ep ports both directions share + // the dedicated ISO endpoint, which is separate hardware and consumes none. + descriptor_counts->current_interface += 3; + if (!forced_iso_ep) { + descriptor_counts->num_out_endpoints += 1; + descriptor_counts->num_in_endpoints += 1; + descriptor_counts->current_endpoint += 2; + } + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); + } + + if (usb_audio_direction_is_output()) { + usb_add_interface_string(*current_interface_string, "CircuitPython Speaker"); + + // The AudioStreaming interface follows the AudioControl interface. + usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; + + const uint8_t usb_audio_descriptor[] = { + USB_AUDIO_SPEAKER_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epout*/ iso_ep_num, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) + }; + + (*current_interface_string)++; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus a + // single isochronous OUT endpoint. + descriptor_counts->current_interface += 2; + if (!forced_iso_ep) { + descriptor_counts->num_out_endpoints += 1; + descriptor_counts->current_endpoint += 1; + } + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); + } + + usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); + + // The AudioStreaming interface follows the AudioControl interface. + usb_audio_mic_as_itf = descriptor_counts->current_interface + 1; + + const uint8_t usb_audio_descriptor[] = { + USB_AUDIO_MIC_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epin*/ iso_ep_num | 0x80, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) + }; + + (*current_interface_string)++; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus a + // single isochronous IN endpoint. + descriptor_counts->current_interface += 2; + if (!forced_iso_ep) { + descriptor_counts->num_in_endpoints += 1; + descriptor_counts->current_endpoint += 1; + } + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); +} + +// --------------------------------------------------------------------+ +// Speaker (host -> board) receive task +// --------------------------------------------------------------------+ + +// Drain everything the host has delivered to the OUT endpoint since the last +// pass into the active USBSpeaker's ring. TinyUSB's weak rx-done handler has +// already moved the isochronous data into ep_out_ff; we copy it out here, in +// task (non-ISR) context, matching the project's "defer ISR work" rule. The ring +// itself, and the overrun/underrun handling, live in USBSpeaker.c so the data +// sits in the audiosample source the output backend pulls from. +static void usb_audio_speaker_task(void) { + // One USB packet of scratch; we loop until ep_out_ff is empty. + static uint8_t chunk[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; + + while (tud_audio_available() > 0) { + uint16_t got = tud_audio_read(chunk, sizeof(chunk)); + if (got == 0) { + break; + } + // tud_audio_read() never returns more than the buffer it was given, but + // clamp so the compiler can prove the drain copies stay within chunk[] + // once this loop is inlined into it. + if (got > sizeof(chunk)) { + got = sizeof(chunk); + } + usb_audio_usbspeaker_background_drain(chunk, got); + } +} + +// --------------------------------------------------------------------+ +// Microphone (board -> host) transmit task +// --------------------------------------------------------------------+ + +static void usb_audio_microphone_task(void) { + // Pace production by the IN FIFO level. Each pass we top the software FIFO + // back up to its half-full setpoint, generating only the samples the host has + // actually drained since the last pass. This limits our production rate to the + // host's true consumption rate (its USB SOF / audio clock), keeps the FIFO + // around the level TinyUSB's flow control targets so it can send steady + // nominal-size packets, and automatically catches up after any scheduling gap + // (GCpause, other background work) in a single pass instead of underrunning. + // Underruns here showed up to the host as discrete sample-drop/insert splices, + // i.e. the erratic ticking on a held tone. + tu_fifo_t *ep_in_ff = tud_audio_get_ep_in_ff(); + uint16_t const target = tu_fifo_depth(ep_in_ff) / 2; + + uint16_t count; + while ((count = tu_fifo_count(ep_in_ff)) < target) { + size_t want = target - count; + if (want > usb_audio_mic_samples_len) { + want = usb_audio_mic_samples_len; + } + + // Pull the next chunk from whichever USBMicrophone is playing. + bool underran = false; + size_t filled = usb_audio_usbmicrophone_background_fill((uint8_t *)usb_audio_mic_samples, want); + if (filled == 0) { + // No source attached, paused, or fully drained: keep the endpoint + // alive with silence so the host never sees a starved stream. + memset((uint8_t *)usb_audio_mic_samples, 0, want); + } else if (filled < want) { + // The source momentarily underran. Send just what it produced and + // let the FIFO cushion ride until it catches up next pass, rather + // than flooding the stream with a burst of silence. + want = filled; + underran = true; + } + + if (tud_audio_write((uint8_t *)usb_audio_mic_samples, (uint16_t)want) == 0) { + break; // FIFO unexpectedly full / host not ready + } + if (underran) { + break; + } + } +} + +void usb_audio_task(void) { + // Each direction is gated on the host having opened its AudioStreaming + // interface. For a headset both run in the same pass: drain the host's + // speaker audio and refill the mic stream independently. The single-direction + // modes simply never have the other flag set. + if (usb_audio_spk_streaming) { + usb_audio_speaker_task(); + } + if (usb_audio_mic_streaming) { + usb_audio_microphone_task(); + } +} + +// --------------------------------------------------------------------+ +// TinyUSB audio class callbacks (weak symbols overridden here) +// --------------------------------------------------------------------+ + +// Host opened/closed the AudioStreaming alternate setting. The host selects each +// direction's interface independently (a headset has two), so route by interface +// number to the matching streaming flag rather than assuming a single stream. +bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void)rhport; + uint8_t const itf = (uint8_t)tu_u16_low(p_request->wIndex); + bool const streaming = (tu_u16_low(p_request->wValue) != 0); + + if (itf == usb_audio_spk_as_itf) { + usb_audio_spk_streaming = streaming; + // Start each speaker streaming session from live audio: drop anything + // left in the OUT FIFO/ring from a previous session. + tud_audio_clear_ep_out_ff(); + usb_audio_usbspeaker_streaming_reset(); + } else if (itf == usb_audio_mic_as_itf) { + usb_audio_mic_streaming = streaming; + if (streaming) { + // Prime the FIFO for the first frame; after that each completed + // transfer schedules the next refill via tud_audio_tx_done_isr(). + usb_background_schedule(); + } + } + return true; +} + +// Invoked from the audio class transfer-complete path once the next packet has +// been loaded into the EP IN buffer. TinyUSB services audio completions in ISR +// context, so they never queue a USB event. A port that pumps the optional class +// tasks from a task loop sitting behind tud_task() therefore never refills the +// microphone FIFO. Scheduling the refill here keeps usb_audio independent of how +// a port drives TinyUSB. +bool tud_audio_tx_done_isr(uint8_t rhport, uint16_t n_bytes_sent, uint8_t func_id, + uint8_t ep_in, uint8_t cur_alt_setting) { + (void)rhport; + (void)n_bytes_sent; + (void)func_id; + (void)ep_in; + (void)cur_alt_setting; + + usb_background_schedule(); + return true; +} + +bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void)rhport; + uint8_t const itf = (uint8_t)tu_u16_low(p_request->wIndex); + + if (itf == usb_audio_spk_as_itf) { + usb_audio_spk_streaming = false; + tud_audio_clear_ep_out_ff(); + usb_audio_usbspeaker_streaming_reset(); + } else if (itf == usb_audio_mic_as_itf) { + usb_audio_mic_streaming = false; + } + return true; +} + +// Class-specific SET requests for an entity (we accept mute/volume on the feature unit). +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { + (void)rhport; + + uint8_t const channelNum = (uint8_t)tu_u16_low(p_request->wValue); + uint8_t const ctrlSel = (uint8_t)tu_u16_high(p_request->wValue); + uint8_t const entityID = (uint8_t)tu_u16_high(p_request->wIndex); + + // Only current-value requests are supported. + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); + + // A headset exposes a feature unit per direction; the speaker's id matches the + // single-direction USB_AUDIO_ENTITY_FEATURE_UNIT, the mic adds a second one. + // Mute/volume state is shared across them. + if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || + entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { + if (channelNum > USB_AUDIO_N_CHANNELS) { + return false; + } + switch (ctrlSel) { + case AUDIO20_FU_CTRL_MUTE: + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); + usb_audio_mute[channelNum] = ((audio20_control_cur_1_t *)pBuff)->bCur; + return true; + + case AUDIO20_FU_CTRL_VOLUME: + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); + usb_audio_volume[channelNum] = ((audio20_control_cur_2_t *)pBuff)->bCur; + return true; + + default: + return false; + } + } + return false; +} + +// Class-specific GET requests for an entity (clock source, feature unit, input terminal). +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void)rhport; + + uint8_t const channelNum = (uint8_t)tu_u16_low(p_request->wValue); + uint8_t const ctrlSel = (uint8_t)tu_u16_high(p_request->wValue); + uint8_t const entityID = (uint8_t)tu_u16_high(p_request->wIndex); + + // Input terminal connector control. The single-mic descriptor uses + // USB_AUDIO_ENTITY_INPUT_TERMINAL; the headset's microphone input terminal is + // a distinct id. (The USB-streaming input terminals don't advertise a readable + // connector control, so the host won't query them here.) + if (entityID == USB_AUDIO_ENTITY_INPUT_TERMINAL || + entityID == USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL) { + switch (ctrlSel) { + case AUDIO20_TE_CTRL_CONNECTOR: { + audio20_desc_channel_cluster_t ret; + ret.bNrChannels = USB_AUDIO_N_CHANNELS; + ret.bmChannelConfig = (audio20_channel_config_t)0; + ret.iChannelNames = 0; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &ret, sizeof(ret)); + } + default: + return false; + } + } + + // Feature unit (mute/volume) for either the speaker or mic chain. + if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || + entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { + if (channelNum > USB_AUDIO_N_CHANNELS) { + return false; + } + switch (ctrlSel) { + case AUDIO20_FU_CTRL_MUTE: + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &usb_audio_mute[channelNum], sizeof(usb_audio_mute[channelNum])); + + case AUDIO20_FU_CTRL_VOLUME: + switch (p_request->bRequest) { + case AUDIO20_CS_REQ_CUR: + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &usb_audio_volume[channelNum], sizeof(usb_audio_volume[channelNum])); + + case AUDIO20_CS_REQ_RANGE: { + audio20_control_range_2_n_t(1) ret; + ret.wNumSubRanges = 1; + ret.subrange[0].bMin = -90 * 256; // -90 dB + ret.subrange[0].bMax = 90 * 256; // +90 dB + ret.subrange[0].bRes = 256; // 1 dB steps + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &ret, sizeof(ret)); + } + + default: + return false; + } + + default: + return false; + } + } + + // Clock source (sample rate set in usb_audio.enable()). + if (entityID == USB_AUDIO_ENTITY_CLOCK_SOURCE) { + switch (ctrlSel) { + case AUDIO20_CS_CTRL_SAM_FREQ: + switch (p_request->bRequest) { + case AUDIO20_CS_REQ_CUR: { + audio20_control_cur_4_t cur = { .bCur = (int32_t)usb_audio_sample_rate }; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur, sizeof(cur)); + } + + case AUDIO20_CS_REQ_RANGE: { + audio20_control_range_4_n_t(1) ret; + ret.wNumSubRanges = 1; + ret.subrange[0].bMin = (int32_t)usb_audio_sample_rate; + ret.subrange[0].bMax = (int32_t)usb_audio_sample_rate; + ret.subrange[0].bRes = 0; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &ret, sizeof(ret)); + } + + default: + return false; + } + + case AUDIO20_CS_CTRL_CLK_VALID: { + audio20_control_cur_1_t cur = { .bCur = 1 }; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur, sizeof(cur)); + } + + default: + return false; + } + } + + return false; +} + +// Keep the per-VM singleton instances (and, for the microphone, its bound +// audiosample) alive for the GC. Installed in the module globals by +// usb_audio_setup_singletons() and reset to NULL at each VM start. +MP_REGISTER_ROOT_POINTER(mp_obj_t usb_audio_microphone_singleton); +MP_REGISTER_ROOT_POINTER(mp_obj_t usb_audio_speaker_singleton); diff --git a/shared-module/usb_audio/__init__.h b/shared-module/usb_audio/__init__.h new file mode 100644 index 00000000000..5730e6ef60b --- /dev/null +++ b/shared-module/usb_audio/__init__.h @@ -0,0 +1,59 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include + +#include "py/obj.h" +#include "supervisor/usb.h" + +// Enable/disable the USB Audio Class (UAC2) interface. These may only be +// called before USB is connected (i.e. from boot.py); they return false +// otherwise. At least one of microphone/speaker must be true; enabling both +// presents a combined headset. +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, bool microphone, bool speaker); +bool shared_module_usb_audio_disable(void); + +// True once enable() has been called successfully. +bool usb_audio_enabled(void); + +// True while the host has opened either AudioStreaming alternate setting, i.e. it +// is actively listening or sending. This is the real "stream the audio now" +// signal. +bool usb_audio_streaming(void); + +// True while the host has the speaker (host -> board OUT) stream open. Distinct +// from usb_audio_streaming() so USBSpeaker can report its own direction even when +// it shares a headset function with a microphone. +bool usb_audio_speaker_streaming(void); + +// Negotiated audio format, valid when usb_audio_enabled() is true. +extern uint32_t usb_audio_sample_rate; +extern uint8_t usb_audio_channel_count; + +// Which streams were requested in enable(), valid when usb_audio_enabled() is +// true. Both true presents a combined headset. +extern bool usb_audio_microphone_enabled; +extern bool usb_audio_speaker_enabled; + +// Descriptor injection hooks, called from supervisor/shared/usb/usb_desc.c. +size_t usb_audio_descriptor_length(void); +size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string); + +// Background task that streams samples to the host, called from +// supervisor/shared/usb/usb.c. +void usb_audio_task(void); + +// (Re)create the USBMicrophone and USBSpeaker singleton instances for the +// current VM and install them as the usb_audio.usb_microphone and +// usb_audio.usb_speaker module attributes (or None when that direction was not +// enabled in boot.py). Called once per VM from usb_setup_with_vm(), mirroring +// usb_midi_setup_ports(): the instances live on the GC heap, which is reset +// between boot.py and code.py, so they must be rebuilt each time. +void usb_audio_setup_singletons(void); diff --git a/shared-module/usb_audio/tusb_config.h b/shared-module/usb_audio/tusb_config.h new file mode 100644 index 00000000000..d7bfb65b148 --- /dev/null +++ b/shared-module/usb_audio/tusb_config.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h new file mode 100644 index 00000000000..8fba956a2a6 --- /dev/null +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -0,0 +1,147 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +// Fixed audio format for the UAC2 microphone profile. These must have no other +// dependencies because this header is included from the TinyUSB tusb_config.h +// (to size the IN endpoint) as well as from the descriptor/binding code. + +// Actual length, in bytes, of the audio function descriptor emitted for the +// current direction (mic, speaker, or headset). usb_desc.c reads this while +// assembling the configuration descriptor, adding it to total_descriptor_length +// so wTotalLength covers the exact bytes the audio function emits. That value +// MUST equal the descriptor we actually emitted: the three directions differ in +// length, so a compile-time maximum would over-report for the shorter ones and +// make the host swallow the interfaces that follow audio (CDC/MSC), breaking +// their enumeration. The full definition lives in __init__.c (also declared in +// __init__.h for the descriptor builder). +size_t usb_audio_descriptor_length(void); + +// The isochronous IN endpoint's wMaxPacketSize in the USB descriptor is computed +// for this rate, so it is the highest rate usb_audio.enable() will accept. +#define USB_AUDIO_MAX_SAMPLE_RATE (48000) +#define USB_AUDIO_N_CHANNELS (2) + +// 16-bit signed LE PCM. +#define USB_AUDIO_N_BYTES_PER_SAMPLE (2) +#define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) + +// Bytes per audio frame on the wire. The descriptors always declare +// USB_AUDIO_N_CHANNELS channels, whatever channel_count the sample has, so this +// is the granularity every buffer handed to/from TinyUSB must be a multiple of. +#define USB_AUDIO_BYTES_PER_FRAME (USB_AUDIO_N_BYTES_PER_SAMPLE * USB_AUDIO_N_CHANNELS) + +// Endpoint number for the single isochronous audio data endpoint. Most device +// controllers accept an ISO endpoint on any number, so the descriptor builder +// just takes the next sequential one (signalled by 0 here). The nRF52 USBD, +// however, implements isochronous transfers only on a fixed, dedicated endpoint +// number (8): its dcd_edpt_open() rejects any other number for an ISO endpoint, +// so the stream silently never opens and the host sees a mic/speaker that +// transfers no data. Such ports override this (e.g. -DUSB_AUDIO_ISO_EP_NUM=8 in +// the port's mpconfigport.mk) to force the audio endpoint onto that number. +#ifndef USB_AUDIO_ISO_EP_NUM +#define USB_AUDIO_ISO_EP_NUM (0) +#endif + +// Fixed UAC2 entity IDs baked into USB_AUDIO_MIC_DESCRIPTOR and the +// hand-rolled speaker descriptor (USB_AUDIO_SPEAKER_DESCRIPTOR in __init__.c). +// The speaker reuses the same IDs as the mic; only the terminal roles reverse +// (input terminal = USB streaming, output terminal = desktop speaker). +#define USB_AUDIO_ENTITY_INPUT_TERMINAL (0x01) +#define USB_AUDIO_ENTITY_FEATURE_UNIT (0x02) +#define USB_AUDIO_ENTITY_OUTPUT_TERMINAL (0x03) +#define USB_AUDIO_ENTITY_CLOCK_SOURCE (0x04) + +// Combined headset (microphone + speaker both enabled) topology. A single audio function +// carries both a speaker chain (host -> board) and a mic chain (board -> host), +// so every unit/terminal needs an ID unique across the whole function -- unlike +// the single-direction descriptors above, which can reuse the same small set. +// The clock source is shared by both chains. (USB_AUDIO_HEADSET_DESCRIPTOR in +// __init__.c bakes these in.) +#define USB_AUDIO_HS_ENTITY_CLOCK_SOURCE (0x04) +#define USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL (0x01) // USB streaming in from host +#define USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT (0x02) +#define USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL (0x03) // desktop speaker +#define USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL (0x05) // generic microphone +#define USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT (0x06) +#define USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL (0x07) // USB streaming out to host + +// Length of the no-feedback speaker descriptor. It uses the same set of +// sub-descriptors as USB_AUDIO_MIC_DESCRIPTOR (except one isochronous data +// endpoint, no feedback endpoint), so this is identical to +// USB_AUDIO_MIC_DESC_LEN -- but spell it out independently so the two +// can diverge later (e.g. stereo) without silently mis-sizing the descriptor. +// These TUD_AUDIO20_DESC_*_LEN macros come from TinyUSB's usbd.h; this expression +// is only expanded where that header is already included (never at the point +// tusb_config.h includes us), so the header stays dependency-free. +#define USB_AUDIO_SPEAKER_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN \ + + TUD_AUDIO20_DESC_STD_AC_LEN \ + + TUD_AUDIO20_DESC_CS_AC_LEN \ + + TUD_AUDIO20_DESC_CLK_SRC_LEN \ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2) \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) + +#define USB_AUDIO_MIC_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN \ + + TUD_AUDIO20_DESC_STD_AC_LEN \ + + TUD_AUDIO20_DESC_CS_AC_LEN \ + + TUD_AUDIO20_DESC_CLK_SRC_LEN \ + /* mic chain: microphone input terminal -> feature unit -> USB-streaming out */ \ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2) \ + /* mic AudioStreaming interface (alt 0 + alt 1 with IN endpoint) */ \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) + +// Length of the combined headset descriptor (microphone + speaker both enabled): one IAD +// wrapping a single AudioControl interface plus two AudioStreaming interfaces +// (speaker OUT + mic IN). The AC interface declares one shared clock, plus an +// input terminal / feature unit / output terminal for each of the two chains; +// each AS interface contributes a zero-bandwidth alt 0 and a streaming alt 1 +// with one isochronous data endpoint (no feedback endpoint, matching the +// single-direction descriptors). See USB_AUDIO_HEADSET_DESCRIPTOR in __init__.c. +// Expanded only where TinyUSB's usbd.h is already included (never at the point +// tusb_config.h includes us), so this header stays dependency-free. +#define USB_AUDIO_HEADSET_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN \ + + TUD_AUDIO20_DESC_STD_AC_LEN \ + + TUD_AUDIO20_DESC_CS_AC_LEN \ + + TUD_AUDIO20_DESC_CLK_SRC_LEN \ + /* speaker chain: USB-streaming input terminal -> feature unit -> speaker */ \ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2) \ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN \ + /* mic chain: microphone input terminal -> feature unit -> USB-streaming out */ \ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2) \ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN \ + /* speaker AudioStreaming interface (alt 0 + alt 1 with OUT endpoint) */ \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN \ + /* mic AudioStreaming interface (alt 0 + alt 1 with IN endpoint) */ \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) diff --git a/shared-module/usb_cdc/__init__.c b/shared-module/usb_cdc/__init__.c index 9a9f158f28c..644c4ccae79 100644 --- a/shared-module/usb_cdc/__init__.c +++ b/shared-module/usb_cdc/__init__.c @@ -105,7 +105,7 @@ static const uint8_t usb_cdc_descriptor_template[] = { 0xFF, // 54 bEndpointAddress (OUT/H2D) [SET AT RUNTIME] #define CDC_DATA_OUT_ENDPOINT_INDEX 54 0x02, // 55 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 56,57 wMaxPacketSize 512 #else 0x40, 0x00, // 56,57 wMaxPacketSize 64 @@ -118,7 +118,7 @@ static const uint8_t usb_cdc_descriptor_template[] = { 0xFF, // 61 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number] #define CDC_DATA_IN_ENDPOINT_INDEX 61 0x02, // 62 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 63,64 wMaxPacketSize 512 #else 0x40, 0x00, // 63,64 wMaxPacketSize 64 @@ -326,7 +326,7 @@ static const uint8_t usb_vendor_descriptor_template[] = { 0xFF, // 11 bEndpointAddress (IN/D2H) [SET AT RUNTIME: number] #define VENDOR_OUT_ENDPOINT_INDEX 11 0x02, // 12 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 13,14 wMaxPacketSize 512 #else 0x40, 0x00, // 13,14 wMaxPacketSize 64 diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index d6c4697210f..adcea84904e 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -12,45 +12,10 @@ #include "shared-bindings/usb_hid/Device.h" #include "shared-module/usb_hid/__init__.h" #include "shared-module/usb_hid/Device.h" +#include "shared-module/usb_hid/report_descriptors.h" #include "supervisor/shared/tick.h" #include "tusb.h" -static const uint8_t keyboard_report_descriptor[] = { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x06, // Usage (Keyboard) - 0xA1, 0x01, // Collection (Application) - 0x85, 0x01, // Report ID (1) - 0x05, 0x07, // Usage Page (Kbrd/Keypad) - 0x19, 0xE0, // Usage Minimum (0xE0) - 0x29, 0xE7, // Usage Maximum (0xE7) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x08, // Report Count (8) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x95, 0x01, // Report Count (1) - 0x75, 0x08, // Report Size (8) - 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x95, 0x05, // Report Count (5) - 0x75, 0x01, // Report Size (1) - 0x05, 0x08, // Usage Page (LEDs) - 0x19, 0x01, // Usage Minimum (Num Lock) - 0x29, 0x05, // Usage Maximum (Kana) - 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x95, 0x01, // Report Count (1) - 0x75, 0x03, // Report Size (3) - 0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x95, 0x06, // Report Count (6) - 0x75, 0x08, // Report Size (8) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x05, 0x07, // Usage Page (Kbrd/Keypad) - 0x19, 0x00, // Usage Minimum (0x00) - 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF) - 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, // End Collection -}; - const usb_hid_device_obj_t usb_hid_device_keyboard_obj = { .base = { .type = &usb_hid_device_type, @@ -65,42 +30,6 @@ const usb_hid_device_obj_t usb_hid_device_keyboard_obj = { .out_report_lengths = { 1, }, }; -static const uint8_t mouse_report_descriptor[] = { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x02, // Usage (Mouse) - 0xA1, 0x01, // Collection (Application) - 0x09, 0x01, // Usage (Pointer) - 0xA1, 0x00, // Collection (Physical) - 0x85, 0x02, // 10, 11 Report ID (2) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x05, // Usage Maximum (0x05) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x95, 0x05, // Report Count (5) - 0x75, 0x01, // Report Size (1) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x95, 0x01, // Report Count (1) - 0x75, 0x03, // Report Size (3) - 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x15, 0x81, // Logical Minimum (-127) - 0x25, 0x7F, // Logical Maximum (127) - 0x75, 0x08, // Report Size (8) - 0x95, 0x02, // Report Count (2) - 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 0x09, 0x38, // Usage (Wheel) - 0x15, 0x81, // Logical Minimum (-127) - 0x25, 0x7F, // Logical Maximum (127) - 0x75, 0x08, // Report Size (8) - 0x95, 0x01, // Report Count (1) - 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, // End Collection - 0xC0, // End Collection -}; - const usb_hid_device_obj_t usb_hid_device_mouse_obj = { .base = { .type = &usb_hid_device_type, @@ -115,21 +44,6 @@ const usb_hid_device_obj_t usb_hid_device_mouse_obj = { .out_report_lengths = { 0, }, }; -static const uint8_t consumer_control_report_descriptor[] = { - 0x05, 0x0C, // Usage Page (Consumer) - 0x09, 0x01, // Usage (Consumer Control) - 0xA1, 0x01, // Collection (Application) - 0x85, 0x03, // Report ID (3) - 0x75, 0x10, // Report Size (16) - 0x95, 0x01, // Report Count (1) - 0x15, 0x01, // Logical Minimum (1) - 0x26, 0x8C, 0x02, // Logical Maximum (652) - 0x19, 0x01, // Usage Minimum (Consumer Control) - 0x2A, 0x8C, 0x02, // Usage Maximum (AC Send) - 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, // End Collection -}; - const usb_hid_device_obj_t usb_hid_device_consumer_control_obj = { .base = { .type = &usb_hid_device_type, @@ -216,6 +130,19 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t * mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("USB busy")); } + const uint8_t boot_device = usb_hid_boot_device(); + if (boot_device != 0 && tud_hid_get_protocol() == HID_PROTOCOL_BOOT) { + // In boot protocol the host reads the fixed boot report, which carries no report ID, + // and ignores every device other than the boot device. + if (self->usage_page == HID_USAGE_PAGE_DESKTOP && + ((boot_device == 1 && self->usage == HID_USAGE_DESKTOP_KEYBOARD) || + (boot_device == 2 && self->usage == HID_USAGE_DESKTOP_MOUSE))) { + report_id = 0; + } else { + return; + } + } + if (!tud_hid_report(report_id, report, len)) { mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("USB error")); } diff --git a/shared-module/usb_hid/report_descriptors.c b/shared-module/usb_hid/report_descriptors.c new file mode 100644 index 00000000000..fe629153c78 --- /dev/null +++ b/shared-module/usb_hid/report_descriptors.c @@ -0,0 +1,96 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 hathach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Standard HID report descriptors shared between ports. + +#include "shared-module/usb_hid/report_descriptors.h" + +const uint8_t keyboard_report_descriptor[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x01, // Report ID (1) + 0x05, 0x07, // Usage Page (Kbrd/Keypad) + 0x19, 0xE0, // Usage Minimum (0xE0) + 0x29, 0xE7, // Usage Maximum (0xE7) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x05, 0x08, // Usage Page (LEDs) + 0x19, 0x01, // Usage Minimum (Num Lock) + 0x29, 0x05, // Usage Maximum (Kana) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x05, 0x07, // Usage Page (Kbrd/Keypad) + 0x19, 0x00, // Usage Minimum (0x00) + 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection +}; + +const uint8_t mouse_report_descriptor[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x85, 0x02, // 10, 11 Report ID (2) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x05, // Usage Maximum (0x05) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x02, // Report Count (2) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection +}; + +const uint8_t consumer_control_report_descriptor[] = { + 0x05, 0x0C, // Usage Page (Consumer) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x03, // Report ID (3) + 0x75, 0x10, // Report Size (16) + 0x95, 0x01, // Report Count (1) + 0x15, 0x01, // Logical Minimum (1) + 0x26, 0x8C, 0x02, // Logical Maximum (652) + 0x19, 0x01, // Usage Minimum (Consumer Control) + 0x2A, 0x8C, 0x02, // Usage Maximum (AC Send) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection +}; diff --git a/shared-module/usb_hid/report_descriptors.h b/shared-module/usb_hid/report_descriptors.h new file mode 100644 index 00000000000..94a9a752f6a --- /dev/null +++ b/shared-module/usb_hid/report_descriptors.h @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 hathach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Standard HID report descriptors shared between ports. These are plain byte +// arrays with no dependencies, so ports using TinyUSB and ports using other +// USB stacks can both use them. They are defined in report_descriptors.c. +// The explicit sizes let callers use sizeof() and are checked by the compiler +// against the definitions. + +#pragma once + +#include + +extern const uint8_t keyboard_report_descriptor[67]; +extern const uint8_t mouse_report_descriptor[64]; +extern const uint8_t consumer_control_report_descriptor[25]; diff --git a/shared-module/usb_midi/__init__.c b/shared-module/usb_midi/__init__.c index 3808801ff7e..1722911536f 100644 --- a/shared-module/usb_midi/__init__.c +++ b/shared-module/usb_midi/__init__.c @@ -106,7 +106,7 @@ static const uint8_t usb_midi_descriptor_template[] = { 0xFF, // 66 bEndpointAddress (OUT/H2D) [SET AT RUNTIME] #define MIDI_STREAMING_OUT_ENDPOINT_INDEX (66) 0x02, // 67 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 68,69 wMaxPacketSize (512) #else 0x40, 0x00, // 68,69 wMaxPacketSize (64) @@ -126,7 +126,7 @@ static const uint8_t usb_midi_descriptor_template[] = { 0xFF, // 78 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number] #define MIDI_STREAMING_IN_ENDPOINT_INDEX (78) 0x02, // 79 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 80, 81 wMaxPacketSize (512) #else 0x40, 0x00, // 80, 81 wMaxPacketSize (64) diff --git a/shared/libc/abort_.c b/shared/libc/abort_.c index 3051eae81e0..54eab67d3fb 100644 --- a/shared/libc/abort_.c +++ b/shared/libc/abort_.c @@ -1,7 +1,7 @@ #include -NORETURN void abort_(void); +MP_NORETURN void abort_(void); -NORETURN void abort_(void) { +MP_NORETURN void abort_(void) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("abort() called")); } diff --git a/shared/libc/string0.c b/shared/libc/string0.c index 5a9e0ff853a..614581734cb 100644 --- a/shared/libc/string0.c +++ b/shared/libc/string0.c @@ -28,6 +28,7 @@ #include // CIRCUITPY-CHANGE: additional includes +#include // for the atoi() prototype #include #include "py/mpconfig.h" @@ -54,14 +55,14 @@ void *memcpy(void *dst, const void *src, size_t n) { if (n & 2) { // copy half-word - *(uint16_t*)d = *(const uint16_t*)s; - d = (uint32_t*)((uint16_t*)d + 1); - s = (const uint32_t*)((const uint16_t*)s + 1); + *(uint16_t *)d = *(const uint16_t *)s; + d = (uint32_t *)((uint16_t *)d + 1); + s = (const uint32_t *)((const uint16_t *)s + 1); } if (n & 1) { // copy byte - *((uint8_t*)d) = *((const uint8_t*)s); + *((uint8_t *)d) = *((const uint8_t *)s); } } else #endif @@ -88,10 +89,10 @@ void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen) { } void *memmove(void *dest, const void *src, size_t n) { - if (src < dest && (uint8_t*)dest < (const uint8_t*)src + n) { + if (src < dest && (uint8_t *)dest < (const uint8_t *)src + n) { // need to copy backwards - uint8_t *d = (uint8_t*)dest + n - 1; - const uint8_t *s = (const uint8_t*)src + n - 1; + uint8_t *d = (uint8_t *)dest + n - 1; + const uint8_t *s = (const uint8_t *)src + n - 1; for (; n > 0; n--) { *d-- = *s--; } @@ -112,11 +113,11 @@ void *memset(void *s, int c, size_t n) { *s32++ = 0; } if (n & 2) { - *((uint16_t*)s32) = 0; - s32 = (uint32_t*)((uint16_t*)s32 + 1); + *((uint16_t *)s32) = 0; + s32 = (uint32_t *)((uint16_t *)s32 + 1); } if (n & 1) { - *((uint8_t*)s32) = 0; + *((uint8_t *)s32) = 0; } } else #endif @@ -138,8 +139,11 @@ int memcmp(const void *s1, const void *s2, size_t n) { while (n--) { char c1 = *s1_8++; char c2 = *s2_8++; - if (c1 < c2) return -1; - else if (c1 > c2) return 1; + if (c1 < c2) { + return -1; + } else if (c1 > c2) { + return 1; + } } return 0; } @@ -149,8 +153,9 @@ void *memchr(const void *s, int c, size_t n) { const unsigned char *p = s; do { - if (*p++ == c) - return ((void *)(p - 1)); + if (*p++ == c) { + return (void *)(p - 1); + } } while (--n != 0); } return 0; @@ -168,12 +173,19 @@ int strcmp(const char *s1, const char *s2) { while (*s1 && *s2) { char c1 = *s1++; // XXX UTF8 get char, next char char c2 = *s2++; // XXX UTF8 get char, next char - if (c1 < c2) return -1; - else if (c1 > c2) return 1; + if (c1 < c2) { + return -1; + } else if (c1 > c2) { + return 1; + } + } + if (*s2) { + return -1; + } else if (*s1) { + return 1; + } else { + return 0; } - if (*s2) return -1; - else if (*s1) return 1; - else return 0; } int strncmp(const char *s1, const char *s2, size_t n) { @@ -181,13 +193,21 @@ int strncmp(const char *s1, const char *s2, size_t n) { char c1 = *s1++; // XXX UTF8 get char, next char char c2 = *s2++; // XXX UTF8 get char, next char n--; - if (c1 < c2) return -1; - else if (c1 > c2) return 1; + if (c1 < c2) { + return -1; + } else if (c1 > c2) { + return 1; + } + } + if (n == 0) { + return 0; + } else if (*s2) { + return -1; + } else if (*s1) { + return 1; + } else { + return 0; } - if (n == 0) return 0; - else if (*s2) return -1; - else if (*s1) return 1; - else return 0; } char *strcpy(char *dest, const char *src) { @@ -202,21 +222,21 @@ char *strcpy(char *dest, const char *src) { // Public Domain implementation of strncpy from: // http://en.wikibooks.org/wiki/C_Programming/Strings#The_strncpy_function char *strncpy(char *s1, const char *s2, size_t n) { - char *dst = s1; - const char *src = s2; - /* Copy bytes, one at a time. */ - while (n > 0) { - n--; - if ((*dst++ = *src++) == '\0') { - /* If we get here, we found a null character at the end - of s2, so use memset to put null bytes at the end of - s1. */ - memset(dst, '\0', n); - break; - } - } - return s1; - } + char *dst = s1; + const char *src = s2; + /* Copy bytes, one at a time. */ + while (n > 0) { + n--; + if ((*dst++ = *src++) == '\0') { + /* If we get here, we found a null character at the end + of s2, so use memset to put null bytes at the end of + s1. */ + memset(dst, '\0', n); + break; + } + } + return s1; +} // needed because gcc optimises strcpy + strcat to this char *stpcpy(char *dest, const char *src) { @@ -241,29 +261,31 @@ char *strcat(char *dest, const char *src) { // Public Domain implementation of strchr from: // http://en.wikibooks.org/wiki/C_Programming/Strings#The_strchr_function -char *strchr(const char *s, int c) -{ +char *strchr(const char *s, int c) { /* Scan s for the character. When this loop is finished, s will either point to the end of the string or the character we were looking for. */ - while (*s != '\0' && *s != (char)c) + while (*s != '\0' && *s != (char)c) { s++; - return ((*s == c) ? (char *) s : 0); + } + return (*s == c) ? (char *)s : 0; } // Public Domain implementation of strstr from: // http://en.wikibooks.org/wiki/C_Programming/Strings#The_strstr_function -char *strstr(const char *haystack, const char *needle) -{ +char *strstr(const char *haystack, const char *needle) { size_t needlelen; /* Check for the null needle case. */ - if (*needle == '\0') - return (char *) haystack; + if (*needle == '\0') { + return (char *)haystack; + } needlelen = strlen(needle); - for (; (haystack = strchr(haystack, *needle)) != 0; haystack++) - if (strncmp(haystack, needle, needlelen) == 0) - return (char *) haystack; + for (; (haystack = strchr(haystack, *needle)) != 0; haystack++) { + if (strncmp(haystack, needle, needlelen) == 0) { + return (char *)haystack; + } + } return 0; } @@ -282,3 +304,13 @@ size_t strcspn(const char *s, const char *reject) { } return s - ss; } + +// Decimal-only, non-negative integers; no leading whitespace handling. +// Marked weak so a libc-provided atoi() takes precedence if available. +__attribute__((weak)) int atoi(const char *num) { + int value = 0; + while (*num >= '0' && *num <= '9') { + value = value * 10 + (*num++ - '0'); + } + return value; +} diff --git a/shared/memzip/lexermemzip.c b/shared/memzip/lexermemzip.c index aef64ffa0a7..a31fc7f1cdc 100644 --- a/shared/memzip/lexermemzip.c +++ b/shared/memzip/lexermemzip.c @@ -5,8 +5,7 @@ #include "py/mperrno.h" #include "memzip.h" -mp_lexer_t *mp_lexer_new_from_file(qstr filename) -{ +mp_lexer_t *mp_lexer_new_from_file(qstr filename) { void *data; size_t len; diff --git a/shared/memzip/make-memzip.py b/shared/memzip/make-memzip.py index 92a5d6168bb..c060745e6cf 100755 --- a/shared/memzip/make-memzip.py +++ b/shared/memzip/make-memzip.py @@ -7,13 +7,12 @@ # This is somewhat like frozen modules in python, but allows arbitrary files # to be used. -from __future__ import print_function - import argparse import os +import pathlib +import shutil import subprocess import sys -import types def create_zip(zip_filename, zip_dir): @@ -28,7 +27,7 @@ def create_zip(zip_filename, zip_dir): def create_c_from_file(c_filename, zip_filename): with open(zip_filename, "rb") as zip_file: - with open(c_filename, "wb") as c_file: + with open(c_filename, "wt") as c_file: print("#include ", file=c_file) print("", file=c_file) print("const uint8_t memzip_data[] = {", file=c_file) @@ -38,10 +37,7 @@ def create_c_from_file(c_filename, zip_filename): break print(" ", end="", file=c_file) for byte in buf: - if isinstance(byte, types.StringType): - print(" 0x{:02x},".format(ord(byte)), end="", file=c_file) - else: - print(" 0x{:02x},".format(byte), end="", file=c_file) + print(" 0x{:02x},".format(byte), end="", file=c_file) print("", file=c_file) print("};", file=c_file) @@ -69,10 +65,20 @@ def main(): parser.add_argument(dest="source_dir", default="memzip_files") args = parser.parse_args(sys.argv[1:]) + output_zip = pathlib.Path(args.zip_filename) + if output_zip.suffix != ".zip": + args.zip_filename = output_zip.with_suffix(".zip") + output_c = pathlib.Path(args.c_filename) + if output_c.suffix != ".c": + args.c_filename = output_c.with_suffix(".c") + print("args.zip_filename =", args.zip_filename) print("args.c_filename =", args.c_filename) print("args.source_dir =", args.source_dir) + if not shutil.which("zip"): + raise FileNotFoundError("zip archiver not available") + create_zip(args.zip_filename, args.source_dir) create_c_from_file(args.c_filename, args.zip_filename) diff --git a/shared/memzip/memzip.c b/shared/memzip/memzip.c index 3fbea8e1e91..32fd27ffeb4 100644 --- a/shared/memzip/memzip.c +++ b/shared/memzip/memzip.c @@ -65,8 +65,7 @@ bool memzip_is_dir(const char *filename) { } -MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len) -{ +MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len) { const MEMZIP_FILE_HDR *file_hdr = memzip_find_file_header(filename); if (file_hdr == NULL) { return MZ_NO_FILE; diff --git a/shared/memzip/memzip.h b/shared/memzip/memzip.h index 667e2df7e13..fe27d9584a3 100644 --- a/shared/memzip/memzip.h +++ b/shared/memzip/memzip.h @@ -3,17 +3,17 @@ #define MEMZIP_FILE_HEADER_SIGNATURE 0x04034b50 typedef struct { - uint32_t signature; - uint16_t version; - uint16_t flags; - uint16_t compression_method; - uint16_t last_mod_time; - uint16_t last_mod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t filename_len; - uint16_t extra_len; + uint32_t signature; + uint16_t version; + uint16_t flags; + uint16_t compression_method; + uint16_t last_mod_time; + uint16_t last_mod_date; + uint32_t crc32; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t filename_len; + uint16_t extra_len; /* char filename[filename_len] */ /* uint8_t extra[extra_len] */ @@ -23,22 +23,22 @@ typedef struct #define MEMZIP_CENTRAL_DIRECTORY_SIGNATURE 0x02014b50 typedef struct { - uint32_t signature; - uint16_t version_made_by; - uint16_t version_read_with; - uint16_t flags; - uint16_t compression_method; - uint16_t last_mod_time; - uint16_t last_mod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t filename_len; - uint16_t extra_len; - uint16_t disk_num; - uint16_t internal_file_attributes; - uint32_t external_file_attributes; - uint32_t file_header_offset; + uint32_t signature; + uint16_t version_made_by; + uint16_t version_read_with; + uint16_t flags; + uint16_t compression_method; + uint16_t last_mod_time; + uint16_t last_mod_date; + uint32_t crc32; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t filename_len; + uint16_t extra_len; + uint16_t disk_num; + uint16_t internal_file_attributes; + uint32_t external_file_attributes; + uint32_t file_header_offset; /* char filename[filename_len] */ /* uint8_t extra[extra_len] */ @@ -48,14 +48,14 @@ typedef struct #define MEMZIP_END_OF_CENTRAL_DIRECTORY_SIGNATURE 0x06054b50 typedef struct { - uint32_t signature; - uint16_t disk_num; - uint16_t central_directory_disk; - uint16_t num_central_directories_this_disk; - uint16_t total_central_directories; - uint32_t central_directory_size; - uint32_t central_directory_offset; - uint16_t comment_len; + uint32_t signature; + uint16_t disk_num; + uint16_t central_directory_disk; + uint16_t num_central_directories_this_disk; + uint16_t total_central_directories; + uint32_t central_directory_size; + uint32_t central_directory_offset; + uint16_t comment_len; /* char comment[comment_len] */ @@ -71,10 +71,10 @@ typedef enum { } MEMZIP_RESULT; typedef struct { - uint32_t file_size; - uint16_t last_mod_date; - uint16_t last_mod_time; - uint8_t is_dir; + uint32_t file_size; + uint16_t last_mod_date; + uint16_t last_mod_time; + uint8_t is_dir; } MEMZIP_FILE_INFO; diff --git a/shared/netutils/dhcpserver.c b/shared/netutils/dhcpserver.c index 6d9cdb97d1f..038b794e864 100644 --- a/shared/netutils/dhcpserver.c +++ b/shared/netutils/dhcpserver.c @@ -69,11 +69,9 @@ #define PORT_DHCP_SERVER (67) #define PORT_DHCP_CLIENT (68) -#define DEFAULT_DNS MAKE_IP4(192, 168, 4, 1) #define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds #define MAC_LEN (6) -#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) typedef struct { uint8_t op; // message opcode @@ -287,8 +285,10 @@ static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &ip_2_ip4(&d->ip)->addr); opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &ip_2_ip4(&d->nm)->addr); - opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &ip_2_ip4(&d->ip)->addr); // aka gateway; can have multiple addresses - opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have multiple addresses + if (d->send_router) { + opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &ip_2_ip4(&d->ip)->addr); // aka gateway; can have multiple addresses + } + opt_write_n(&opt, DHCP_OPT_DNS, 4, &ip_2_ip4(&d->ip)->addr); opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S); *opt++ = DHCP_OPT_END; struct netif *netif = ip_current_input_netif(); @@ -302,6 +302,7 @@ void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) { ip_addr_copy(d->ip, *ip); ip_addr_copy(d->nm, *nm); memset(d->lease, 0, sizeof(d->lease)); + d->send_router = true; if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) { return; } diff --git a/shared/netutils/dhcpserver.h b/shared/netutils/dhcpserver.h index 2349d2ea427..24224d6aadd 100644 --- a/shared/netutils/dhcpserver.h +++ b/shared/netutils/dhcpserver.h @@ -41,6 +41,7 @@ typedef struct _dhcp_server_t { ip_addr_t nm; dhcp_server_lease_t lease[DHCPS_MAX_IP]; struct udp_pcb *udp; + bool send_router; // advertise server IP as default gateway } dhcp_server_t; void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm); diff --git a/shared/netutils/trace.c b/shared/netutils/trace.c index a6dfb42c28f..24af4d5ca31 100644 --- a/shared/netutils/trace.c +++ b/shared/netutils/trace.c @@ -56,7 +56,7 @@ static const char *ethertype_str(uint16_t type) { } void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags) { - mp_printf(print, "[% 8d] ETH%cX len=%u", mp_hal_ticks_ms(), flags & NETUTILS_TRACE_IS_TX ? 'T' : 'R', len); + mp_printf(print, "[% 8u] ETH%cX len=%u", (unsigned)mp_hal_ticks_ms(), flags & NETUTILS_TRACE_IS_TX ? 'T' : 'R', len); mp_printf(print, " dst=%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); mp_printf(print, " src=%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]); diff --git a/shared/readline/readline.c b/shared/readline/readline.c index 12acf158978..23ff6c56d29 100644 --- a/shared/readline/readline.c +++ b/shared/readline/readline.c @@ -114,6 +114,7 @@ typedef struct _readline_t { // CIRCUITPY-CHANGE uint8_t utf8_cont_chars; char escape_seq_buf[1]; + char last_nl; #if MICROPY_REPL_AUTO_INDENT uint8_t auto_indent_state; #endif @@ -151,6 +152,17 @@ static size_t cursor_count_word(int forward) { } #endif +// Function returns true if newline character shall be processed. +static bool process_nl(int c) { + if ((c == '\r' || c == '\n') && (rl.last_nl == 0 || rl.last_nl == c)) { + rl.last_nl = c; + return true; + } + + rl.last_nl = 0; + return false; +} + int readline_process_char(int c) { // CIRCUITPY-CHANGE size_t last_line_len = utf8_charlen((byte *)rl.line->buf, rl.line->len); @@ -221,7 +233,7 @@ int readline_process_char(int c) { } else if (c == CHAR_CTRL_W) { goto backward_kill_word; #endif - } else if (c == '\r') { + } else if (process_nl(c)) { // newline mp_hal_stdout_tx_str("\r\n"); readline_push_history(vstr_null_terminated_str(rl.line) + rl.orig_line_len); diff --git a/shared/runtime/buffer_helper.c b/shared/runtime/buffer_helper.c index a1f7f7bb7f6..29e486af2c9 100644 --- a/shared/runtime/buffer_helper.c +++ b/shared/runtime/buffer_helper.c @@ -14,6 +14,9 @@ void normalize_buffer_bounds(int32_t *start, int32_t end, size_t *length) { } if (*start < 0) { *start += *length; + if (*start < 0) { + *start = 0; + } } if (end < *start) { *length = 0; diff --git a/shared/runtime/gchelper.h b/shared/runtime/gchelper.h index 1e85e06f46e..9617bc7f9fe 100644 --- a/shared/runtime/gchelper.h +++ b/shared/runtime/gchelper.h @@ -43,6 +43,10 @@ typedef uintptr_t gc_helper_regs_t[10]; typedef uintptr_t gc_helper_regs_t[11]; // x19-x29 #elif defined(__riscv) && (__riscv_xlen <= 64) typedef uintptr_t gc_helper_regs_t[12]; // S0-S11 +#elif defined(__loongarch__) && defined(__loongarch64) +typedef uintptr_t gc_helper_regs_t[10]; // S0-S9 +#elif defined(__powerpc__) && defined(__powerpc64__) +typedef uintptr_t gc_helper_regs_t[18]; // r14-r31 #endif #endif diff --git a/shared/runtime/gchelper_generic.c b/shared/runtime/gchelper_generic.c index 45b2e4f7d84..dcca800d512 100644 --- a/shared/runtime/gchelper_generic.c +++ b/shared/runtime/gchelper_generic.c @@ -42,13 +42,14 @@ // stack already by the caller. #if defined(__x86_64__) +// CIRCUITPY-CHANGE: use __asm__ instead of asm static void gc_helper_get_regs(gc_helper_regs_t arr) { - register long rbx asm ("rbx"); - register long rbp asm ("rbp"); - register long r12 asm ("r12"); - register long r13 asm ("r13"); - register long r14 asm ("r14"); - register long r15 asm ("r15"); + register long rbx __asm__ ("rbx"); + register long rbp __asm__ ("rbp"); + register long r12 __asm__ ("r12"); + register long r13 __asm__ ("r13"); + register long r14 __asm__ ("r14"); + register long r15 __asm__ ("r15"); #ifdef __clang__ // TODO: // This is dirty workaround for Clang. It tries to get around @@ -56,12 +57,12 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { // Application of this patch here is random, and done only to unbreak // MacOS build. Better, cross-arch ways to deal with Clang issues should // be found. - asm ("" : "=r" (rbx)); - asm ("" : "=r" (rbp)); - asm ("" : "=r" (r12)); - asm ("" : "=r" (r13)); - asm ("" : "=r" (r14)); - asm ("" : "=r" (r15)); + __asm__ ("" : "=r" (rbx)); + __asm__ ("" : "=r" (rbp)); + __asm__ ("" : "=r" (r12)); + __asm__ ("" : "=r" (r13)); + __asm__ ("" : "=r" (r14)); + __asm__ ("" : "=r" (r15)); #endif arr[0] = rbx; arr[1] = rbp; @@ -74,10 +75,10 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { #elif defined(__i386__) static void gc_helper_get_regs(gc_helper_regs_t arr) { - register long ebx asm ("ebx"); - register long esi asm ("esi"); - register long edi asm ("edi"); - register long ebp asm ("ebp"); + register long ebx __asm__ ("ebx"); + register long esi __asm__ ("esi"); + register long edi __asm__ ("edi"); + register long ebp __asm__ ("ebp"); #ifdef __clang__ // TODO: // This is dirty workaround for Clang. It tries to get around @@ -85,10 +86,10 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { // Application of this patch here is random, and done only to unbreak // MacOS build. Better, cross-arch ways to deal with Clang issues should // be found. - asm ("" : "=r" (ebx)); - asm ("" : "=r" (esi)); - asm ("" : "=r" (edi)); - asm ("" : "=r" (ebp)); + __asm__ ("" : "=r" (ebx)); + __asm__ ("" : "=r" (esi)); + __asm__ ("" : "=r" (edi)); + __asm__ ("" : "=r" (ebp)); #endif arr[0] = ebx; arr[1] = esi; @@ -105,16 +106,16 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wuninitialized" #endif - register long r4 asm ("r4"); - register long r5 asm ("r5"); - register long r6 asm ("r6"); - register long r7 asm ("r7"); - register long r8 asm ("r8"); - register long r9 asm ("r9"); - register long r10 asm ("r10"); - register long r11 asm ("r11"); - register long r12 asm ("r12"); - register long r13 asm ("r13"); + register long r4 __asm__ ("r4"); + register long r5 __asm__ ("r5"); + register long r6 __asm__ ("r6"); + register long r7 __asm__ ("r7"); + register long r8 __asm__ ("r8"); + register long r9 __asm__ ("r9"); + register long r10 __asm__ ("r10"); + register long r11 __asm__ ("r11"); + register long r12 __asm__ ("r12"); + register long r13 __asm__ ("r13"); arr[0] = r4; arr[1] = r5; arr[2] = r6; @@ -133,17 +134,17 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { #elif defined(__aarch64__) static void gc_helper_get_regs(gc_helper_regs_t arr) { - const register long x19 asm ("x19"); - const register long x20 asm ("x20"); - const register long x21 asm ("x21"); - const register long x22 asm ("x22"); - const register long x23 asm ("x23"); - const register long x24 asm ("x24"); - const register long x25 asm ("x25"); - const register long x26 asm ("x26"); - const register long x27 asm ("x27"); - const register long x28 asm ("x28"); - const register long x29 asm ("x29"); + const register long x19 __asm__ ("x19"); + const register long x20 __asm__ ("x20"); + const register long x21 __asm__ ("x21"); + const register long x22 __asm__ ("x22"); + const register long x23 __asm__ ("x23"); + const register long x24 __asm__ ("x24"); + const register long x25 __asm__ ("x25"); + const register long x26 __asm__ ("x26"); + const register long x27 __asm__ ("x27"); + const register long x28 __asm__ ("x28"); + const register long x29 __asm__ ("x29"); arr[0] = x19; arr[1] = x20; arr[2] = x21; @@ -163,18 +164,18 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { // for RV32I targets or gchelper_rv64i.s for RV64I targets. static void gc_helper_get_regs(gc_helper_regs_t arr) { - register uintptr_t s0 asm ("x8"); - register uintptr_t s1 asm ("x9"); - register uintptr_t s2 asm ("x18"); - register uintptr_t s3 asm ("x19"); - register uintptr_t s4 asm ("x20"); - register uintptr_t s5 asm ("x21"); - register uintptr_t s6 asm ("x22"); - register uintptr_t s7 asm ("x23"); - register uintptr_t s8 asm ("x24"); - register uintptr_t s9 asm ("x25"); - register uintptr_t s10 asm ("x26"); - register uintptr_t s11 asm ("x27"); + register uintptr_t s0 __asm__ ("x8"); + register uintptr_t s1 __asm__ ("x9"); + register uintptr_t s2 __asm__ ("x18"); + register uintptr_t s3 __asm__ ("x19"); + register uintptr_t s4 __asm__ ("x20"); + register uintptr_t s5 __asm__ ("x21"); + register uintptr_t s6 __asm__ ("x22"); + register uintptr_t s7 __asm__ ("x23"); + register uintptr_t s8 __asm__ ("x24"); + register uintptr_t s9 __asm__ ("x25"); + register uintptr_t s10 __asm__ ("x26"); + register uintptr_t s11 __asm__ ("x27"); arr[0] = s0; arr[1] = s1; arr[2] = s2; @@ -189,6 +190,73 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { arr[11] = s11; } +#elif defined(__loongarch__) && defined(__loongarch64) + +// Fallback implementation for LOONG64, prefer gchelper_loong64.s. +static void gc_helper_get_regs(gc_helper_regs_t arr) { + register uintptr_t s0 asm ("r23"); + register uintptr_t s1 asm ("r24"); + register uintptr_t s2 asm ("r25"); + register uintptr_t s3 asm ("r26"); + register uintptr_t s4 asm ("r27"); + register uintptr_t s5 asm ("r28"); + register uintptr_t s6 asm ("r29"); + register uintptr_t s7 asm ("r30"); + register uintptr_t s8 asm ("r31"); + register uintptr_t s9 asm ("r22"); + arr[0] = s0; + arr[1] = s1; + arr[2] = s2; + arr[3] = s3; + arr[4] = s4; + arr[5] = s5; + arr[6] = s6; + arr[7] = s7; + arr[8] = s8; + arr[9] = s9; +} + +#elif defined(__powerpc__) && defined(__powerpc64__) + +static void gc_helper_get_regs(gc_helper_regs_t arr) { + register uintptr_t r14 __asm("r14"); + register uintptr_t r15 __asm("r15"); + register uintptr_t r16 __asm("r16"); + register uintptr_t r17 __asm("r17"); + register uintptr_t r18 __asm("r18"); + register uintptr_t r19 __asm("r19"); + register uintptr_t r20 __asm("r20"); + register uintptr_t r21 __asm("r21"); + register uintptr_t r22 __asm("r22"); + register uintptr_t r23 __asm("r23"); + register uintptr_t r24 __asm("r24"); + register uintptr_t r25 __asm("r25"); + register uintptr_t r26 __asm("r26"); + register uintptr_t r27 __asm("r27"); + register uintptr_t r28 __asm("r28"); + register uintptr_t r29 __asm("r29"); + register uintptr_t r30 __asm("r30"); + register uintptr_t r31 __asm("r31"); + arr[0] = r14; + arr[1] = r15; + arr[2] = r16; + arr[3] = r17; + arr[4] = r18; + arr[5] = r19; + arr[6] = r20; + arr[7] = r21; + arr[8] = r22; + arr[9] = r23; + arr[10] = r24; + arr[11] = r25; + arr[12] = r26; + arr[13] = r27; + arr[14] = r28; + arr[15] = r29; + arr[16] = r30; + arr[17] = r31; +} + #else #error "Architecture not supported for gc_helper_get_regs. Set MICROPY_GCREGS_SETJMP to use the fallback implementation." diff --git a/shared/runtime/gchelper_loong64.s b/shared/runtime/gchelper_loong64.s new file mode 100644 index 00000000000..5180e1e24df --- /dev/null +++ b/shared/runtime/gchelper_loong64.s @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2026 Alessandro Gatti + * + * 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. + */ + + .global gc_helper_get_regs_and_sp + .type gc_helper_get_regs_and_sp, @function + +gc_helper_get_regs_and_sp: + + /* Store registers into the given array. */ + + st.d $r23, $r4, 0 /* Save S0. */ + st.d $r24, $r4, 8 /* Save S1. */ + st.d $r25, $r4, 16 /* Save S2. */ + st.d $r26, $r4, 24 /* Save S3. */ + st.d $r27, $r4, 32 /* Save S4. */ + st.d $r28, $r4, 40 /* Save S5. */ + st.d $r29, $r4, 48 /* Save S6. */ + st.d $r30, $r4, 56 /* Save S7. */ + st.d $r31, $r4, 64 /* Save S8. */ + st.d $r22, $r4, 72 /* Save S9. */ + + /* Return the stack pointer. */ + + add.d $r4, $r0, $r3 + jirl $r0, $r1, 0 + + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp diff --git a/shared/runtime/interrupt_char.c b/shared/runtime/interrupt_char.c index 5cec1988f41..1f270201719 100644 --- a/shared/runtime/interrupt_char.c +++ b/shared/runtime/interrupt_char.c @@ -31,6 +31,7 @@ #if MICROPY_KBD_EXCEPTION +// CIRCUITPY-CHANGE #ifdef __ZEPHYR__ #include diff --git a/shared/runtime/interrupt_char.h b/shared/runtime/interrupt_char.h index c4a465456a8..44fd4b45a61 100644 --- a/shared/runtime/interrupt_char.h +++ b/shared/runtime/interrupt_char.h @@ -29,6 +29,7 @@ // CIRCUITPY-CHANGE #include +// CIRCUITPY-CHANGE #ifdef __ZEPHYR__ #include diff --git a/shared/runtime/mpirq.c b/shared/runtime/mpirq.c deleted file mode 100644 index 6111b9b10cf..00000000000 --- a/shared/runtime/mpirq.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2015 Daniel Campora - * 2018 Tobias Badertscher - * - * 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/gc.h" -#include "shared/runtime/mpirq.h" - -#if MICROPY_ENABLE_SCHEDULER - -/****************************************************************************** - DECLARE PUBLIC DATA - ******************************************************************************/ - -const mp_arg_t mp_irq_init_args[] = { - { MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_trigger, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} }, -}; - -/****************************************************************************** - DECLARE PRIVATE DATA - ******************************************************************************/ - -/****************************************************************************** - DEFINE PUBLIC FUNCTIONS - ******************************************************************************/ - -mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent) { - mp_irq_obj_t *self = m_new0(mp_irq_obj_t, 1); - mp_irq_init(self, methods, parent); - return self; -} - -void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent) { - self->base.type = &mp_irq_type; - self->methods = (mp_irq_methods_t *)methods; - self->parent = parent; - self->handler = mp_const_none; - self->ishard = false; -} - -void mp_irq_handler(mp_irq_obj_t *self) { - if (self->handler != mp_const_none) { - if (self->ishard) { - // When executing code within a handler we must lock the scheduler to - // prevent any scheduled callbacks from running, and lock the GC to - // prevent any memory allocations. - mp_sched_lock(); - gc_lock(); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_call_function_1(self->handler, self->parent); - nlr_pop(); - } else { - // Uncaught exception; disable the callback so that it doesn't run again - self->methods->trigger(self->parent, 0); - self->handler = mp_const_none; - mp_printf(MICROPY_ERROR_PRINTER, "Uncaught exception in IRQ callback handler\n"); - mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val)); - } - gc_unlock(); - mp_sched_unlock(); - } else { - // Schedule call to user function - mp_sched_schedule(self->handler, self->parent); - } - } -} - -/******************************************************************************/ -// MicroPython bindings - -static mp_obj_t mp_irq_flags(mp_obj_t self_in) { - mp_irq_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(self->methods->info(self->parent, MP_IRQ_INFO_FLAGS)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags); - -static mp_obj_t mp_irq_trigger(size_t n_args, const mp_obj_t *args) { - mp_irq_obj_t *self = MP_OBJ_TO_PTR(args[0]); - mp_obj_t ret_obj = mp_obj_new_int(self->methods->info(self->parent, MP_IRQ_INFO_TRIGGERS)); - if (n_args == 2) { - // Set trigger - self->methods->trigger(self->parent, mp_obj_get_int(args[1])); - } - return ret_obj; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_irq_trigger_obj, 1, 2, mp_irq_trigger); - -static mp_obj_t mp_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, 0, false); - mp_irq_handler(MP_OBJ_TO_PTR(self_in)); - return mp_const_none; -} - -static const mp_rom_map_elem_t mp_irq_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_flags), MP_ROM_PTR(&mp_irq_flags_obj) }, - { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&mp_irq_trigger_obj) }, -}; -static MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - mp_irq_type, - MP_QSTR_irq, - MP_TYPE_FLAG_NONE, - call, mp_irq_call, - locals_dict, &mp_irq_locals_dict - ); - -#endif // MICROPY_ENABLE_SCHEDULER diff --git a/shared/runtime/mpirq.h b/shared/runtime/mpirq.h deleted file mode 100644 index dd423c01011..00000000000 --- a/shared/runtime/mpirq.h +++ /dev/null @@ -1,82 +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_LIB_UTILS_MPIRQ_H -#define MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H - -#include "py/runtime.h" - -/****************************************************************************** - DEFINE CONSTANTS - ******************************************************************************/ - -enum { - MP_IRQ_ARG_INIT_handler = 0, - MP_IRQ_ARG_INIT_trigger, - MP_IRQ_ARG_INIT_hard, - MP_IRQ_ARG_INIT_NUM_ARGS, -}; - -/****************************************************************************** - DEFINE TYPES - ******************************************************************************/ - -typedef mp_uint_t (*mp_irq_trigger_fun_t)(mp_obj_t self, mp_uint_t trigger); -typedef mp_uint_t (*mp_irq_info_fun_t)(mp_obj_t self, mp_uint_t info_type); - -enum { - MP_IRQ_INFO_FLAGS, - MP_IRQ_INFO_TRIGGERS, -}; - -typedef struct _mp_irq_methods_t { - mp_irq_trigger_fun_t trigger; - mp_irq_info_fun_t info; -} mp_irq_methods_t; - -typedef struct _mp_irq_obj_t { - mp_obj_base_t base; - mp_irq_methods_t *methods; - mp_obj_t parent; - mp_obj_t handler; - bool ishard; -} mp_irq_obj_t; - -/****************************************************************************** - DECLARE EXPORTED DATA - ******************************************************************************/ - -extern const mp_arg_t mp_irq_init_args[]; -extern const mp_obj_type_t mp_irq_type; - -/****************************************************************************** - DECLARE PUBLIC FUNCTIONS - ******************************************************************************/ - -mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent); -void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent); -void mp_irq_handler(mp_irq_obj_t *self); - -#endif // MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 06680ff2dd1..0c10ebf0e94 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -38,15 +38,12 @@ #include "py/gc.h" #include "py/frozenmod.h" #include "py/mphal.h" -#if MICROPY_HW_ENABLE_USB -#include "irq.h" -#include "usb.h" -#endif #include "shared/readline/readline.h" #include "shared/runtime/pyexec.h" +#include "extmod/modplatform.h" #include "genhdr/mpversion.h" -// CIRCUITPY-CHANGE: atexit support +// CIRCUITPY-CHANGE: add atexit support #if CIRCUITPY_ATEXIT #include "shared-module/atexit/__init__.h" #endif @@ -87,57 +84,71 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input nlr_buf_t nlr; nlr.ret_val = NULL; if (nlr_push(&nlr) == 0) { - // CIRCUITPY-CHANGE - mp_obj_t module_fun = mp_const_none; - // CIRCUITPY-CHANGE + #if MICROPY_PYEXEC_ENABLE_VM_ABORT + nlr_set_abort(&nlr); + #endif + + // CIRCUITPY-CHANGE: move declaration for easier handling of atexit #if. + // Also make it possible to determine if module_fun was set. + mp_obj_t module_fun = NULL; + + // CIRCUITPY-CHANGE: add atexit support #if CIRCUITPY_ATEXIT - if (!(exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT)) + if (exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT) { + atexit_callback_t *callback = (atexit_callback_t *)source; + mp_call_function_n_kw(callback->func, callback->n_pos, callback->n_kw, callback->args); + } else #endif - // CIRCUITPY-CHANGE: multiple code changes - { - #if MICROPY_MODULE_FROZEN_MPY - if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) { - // source is a raw_code object, create the function - const mp_frozen_module_t *frozen = source; - mp_module_context_t *ctx = m_new_obj(mp_module_context_t); - ctx->module.globals = mp_globals_get(); - ctx->constants = frozen->constants; - module_fun = mp_make_function_from_proto_fun(frozen->proto_fun, ctx, NULL); - } else - #endif - { - #if MICROPY_ENABLE_COMPILER - mp_lexer_t *lex; - if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) { - const vstr_t *vstr = source; - lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0); - } else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER) { - lex = mp_lexer_new(MP_QSTR__lt_stdin_gt_, *(mp_reader_t *)source); - } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) { - lex = mp_lexer_new_from_file(qstr_from_str(source)); - } else { - lex = (mp_lexer_t *)source; - } - // source is a lexer, parse and compile the script - qstr source_name = lex->source_name; - // CIRCUITPY-CHANGE - #if MICROPY_PY___FILE__ - if (input_kind == MP_PARSE_FILE_INPUT) { - mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); - } - #endif - mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); - module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL); - #else - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("script compilation not supported")); - #endif + #if MICROPY_MODULE_FROZEN_MPY + if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) { + // source is a raw_code object, create the function + const mp_frozen_module_t *frozen = source; + mp_module_context_t *ctx = m_new_obj(mp_module_context_t); + ctx->module.globals = mp_globals_get(); + ctx->constants = frozen->constants; + module_fun = mp_make_function_from_proto_fun(frozen->proto_fun, ctx, NULL); + } else + #endif + { + #if MICROPY_ENABLE_COMPILER + mp_lexer_t *lex; + if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) { + const vstr_t *vstr = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0); + } else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER) { + lex = mp_lexer_new(MP_QSTR__lt_stdin_gt_, *(mp_reader_t *)source); + } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) { + lex = mp_lexer_new_from_file(qstr_from_str(source)); + } else { + lex = (mp_lexer_t *)source; } - - // If the code was loaded from a file, collect any garbage before running. + // source is a lexer, parse and compile the script + qstr source_name = lex->source_name; + #if MICROPY_MODULE___FILE__ if (input_kind == MP_PARSE_FILE_INPUT) { - gc_collect(); + mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); } + #endif + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + #if defined(MICROPY_UNIX_COVERAGE) + // allow to print the parse tree in the coverage build + if (MP_STATE_VM(mp_verbose_flag) >= 3) { + printf("----------------\n"); + mp_parse_node_print(&mp_plat_print, parse_tree.root, 0); + printf("----------------\n"); + } + #endif + module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL); + #else + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("script compilation not supported")); + #endif + } + + // CIRCUITPY-CHANGE: garbage collect after loading + // If the code was loaded from a file, collect any garbage before running. + if (input_kind == MP_PARSE_FILE_INPUT) { + gc_collect(); } // execute code @@ -147,29 +158,26 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input #if MICROPY_REPL_INFO start = mp_hal_ticks_ms(); #endif - // CIRCUITPY-CHANGE - #if CIRCUITPY_ATEXIT - if (exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT) { - atexit_callback_t *callback = (atexit_callback_t *)source; - mp_call_function_n_kw(callback->func, callback->n_pos, callback->n_kw, callback->args); - } else + #if MICROPY_PYEXEC_COMPILE_ONLY + if (!mp_compile_only) #endif - // CIRCUITPY-CHANGE - if (module_fun != mp_const_none) { - mp_call_function_0(module_fun); + { + // CIRCUITPY-CHANGE: if atexit function was called, there is nothing to call. + if (module_fun != NULL) { + mp_call_function_0(module_fun); + } } mp_hal_set_interrupt_char(-1); // disable interrupt - mp_handle_pending(true); // handle any pending exceptions (and any callbacks) + mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS); // handle any pending exceptions (and any callbacks) nlr_pop(); - // CIRCUITPY-CHANGE - ret = 0; + ret = PYEXEC_NORMAL_EXIT; if (exec_flags & EXEC_FLAG_PRINT_EOF) { mp_hal_stdout_tx_strn("\x04", 1); } } else { // uncaught exception mp_hal_set_interrupt_char(-1); // disable interrupt - mp_handle_pending(false); // clear any pending exceptions (and run any callbacks) + mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_CLEAR_EXCEPTIONS); // clear any pending exceptions (and run any callbacks) if (exec_flags & EXEC_FLAG_SOURCE_IS_READER) { const mp_reader_t *reader = source; @@ -181,36 +189,65 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input mp_hal_stdout_tx_strn("\x04", 1); } - // check for SystemExit - - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: Name and use some values. // nlr.ret_val is an exception object. mp_obj_t exception_obj = (mp_obj_t)nlr.ret_val; + const mp_obj_type_t *exception_obj_type = mp_obj_get_type(exception_obj); + + #if MICROPY_PYEXEC_ENABLE_VM_ABORT + if (nlr.ret_val == NULL) { // abort + ret = PYEXEC_ABORT; + } else + #endif - if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exception_obj)), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { - // at the moment, the value of SystemExit is unused + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exception_obj_type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // system exit + #if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING + // None is an exit value of 0; an int is its value; anything else is 1 + mp_obj_t val = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); + if (val != mp_const_none) { + if (mp_obj_is_int(val)) { + ret = (int)mp_obj_int_get_truncated(val); + } else { + mp_obj_print_helper(MICROPY_ERROR_PRINTER, val, PRINT_STR); + mp_print_str(MICROPY_ERROR_PRINTER, "\n"); + ret = PYEXEC_UNHANDLED_EXCEPTION; + } + } else { + ret = PYEXEC_NORMAL_EXIT; + } + // Set PYEXEC_FORCED_EXIT flag so REPL knows to exit + ret |= PYEXEC_FORCED_EXIT; + #else ret = PYEXEC_FORCED_EXIT; - // CIRCUITPY-CHANGE + #endif + // CIRCUITPY-CHANGE: support DeepSleepRequest #if CIRCUITPY_ALARM - } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exception_obj)), MP_OBJ_FROM_PTR(&mp_type_DeepSleepRequest))) { + } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exception_obj_type), MP_OBJ_FROM_PTR(&mp_type_DeepSleepRequest))) { ret = PYEXEC_DEEP_SLEEP; #endif + // CIRCUITPY-CHANGE: support ReloadException } else if (exception_obj == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) { ret = PYEXEC_RELOAD; - } else { - mp_obj_print_exception(&mp_plat_print, exception_obj); - ret = PYEXEC_EXCEPTION; + } else { // other exception + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + ret = PYEXEC_UNHANDLED_EXCEPTION; + #if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_KeyboardInterrupt))) { // keyboard interrupt + ret = PYEXEC_KEYBOARD_INTERRUPT; + } + #endif } - } + + // CIRCUITPY_CHANGE: Fill in result out argument. if (result != NULL) { result->return_code = ret; - #if CIRCUITPY_ALARM // Don't set the exception object if we exited for deep sleep. - if (ret != 0 && ret != PYEXEC_DEEP_SLEEP) { - #else - if (ret != 0) { + if (ret != 0 + #if CIRCUITPY_ALARM + && ret != PYEXEC_DEEP_SLEEP #endif + ) { mp_obj_t return_value = (mp_obj_t)nlr.ret_val; result->exception = return_value; result->exception_line = -1; @@ -227,6 +264,10 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input } } + #if MICROPY_PYEXEC_ENABLE_VM_ABORT + nlr_set_abort(NULL); + #endif + #if MICROPY_REPL_INFO // display debugging info if wanted if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) { @@ -484,7 +525,10 @@ static int pyexec_friendly_repl_process_char(int c) { // CIRCUITPY-CHANGE: print CircuitPython-style banner. mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO); mp_hal_stdout_tx_str("\r\n"); + #if MICROPY_PY_BUILTINS_HELP + // CIRCUITPY-CHANGE: don't print help info // mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); + #endif goto input_restart; } else if (ret == CHAR_CTRL_C) { // break @@ -501,6 +545,8 @@ static int pyexec_friendly_repl_process_char(int c) { vstr_reset(MP_STATE_VM(repl_line)); repl.paste_mode = true; return 0; + } else if (vstr_len(MP_STATE_VM(repl_line)) == 0) { + goto input_restart; } if (ret < 0) { @@ -570,10 +616,21 @@ MP_REGISTER_ROOT_POINTER(vstr_t * repl_line); #else // MICROPY_REPL_EVENT_DRIVEN +// CIRCUITPY-CHANGE: avoid warnings +#if !defined(MICROPY_HAL_HAS_STDIO_MODE_SWITCH) || !MICROPY_HAL_HAS_STDIO_MODE_SWITCH +// If the port doesn't need any stdio mode switching calls then provide trivial ones. +static inline void mp_hal_stdio_mode_raw(void) { +} +static inline void mp_hal_stdio_mode_orig(void) { +} +#endif + int pyexec_raw_repl(void) { vstr_t line; vstr_init(&line, 32); + mp_hal_stdio_mode_raw(); + raw_repl_reset: mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n"); @@ -587,6 +644,7 @@ int pyexec_raw_repl(void) { if (vstr_len(&line) == 2 && vstr_str(&line)[0] == CHAR_CTRL_E) { int ret = do_reader_stdin(vstr_str(&line)[1]); if (ret & PYEXEC_FORCED_EXIT) { + mp_hal_stdio_mode_orig(); return ret; } vstr_reset(&line); @@ -599,6 +657,7 @@ int pyexec_raw_repl(void) { mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; + mp_hal_stdio_mode_orig(); return 0; } else if (c == CHAR_CTRL_C) { // clear line @@ -619,14 +678,18 @@ int pyexec_raw_repl(void) { // exit for a soft reset mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); + mp_hal_stdio_mode_orig(); return PYEXEC_FORCED_EXIT; } + // Switch to original terminal mode to execute code, eg to support keyboard interrupt (SIGINT). + mp_hal_stdio_mode_orig(); // CIRCUITPY-CHANGE: add last arg, handle reload int ret = parse_compile_execute(&line, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR, NULL); if (ret & (PYEXEC_FORCED_EXIT | PYEXEC_RELOAD)) { return ret; } + mp_hal_stdio_mode_raw(); } } @@ -634,6 +697,8 @@ int pyexec_friendly_repl(void) { vstr_t line; vstr_init(&line, 32); + mp_hal_stdio_mode_raw(); + friendly_repl_reset: // CIRCUITPY-CHANGE: CircuitPython-style banner. mp_hal_stdout_tx_str("\r\n"); @@ -661,20 +726,6 @@ int pyexec_friendly_repl(void) { for (;;) { input_restart: - - #if MICROPY_HW_ENABLE_USB - if (usb_vcp_is_enabled()) { - // If the user gets to here and interrupts are disabled then - // they'll never see the prompt, traceback etc. The USB REPL needs - // interrupts to be enabled or no transfers occur. So we try to - // do the user a favor and re-enable interrupts. - if (query_irq() == IRQ_STATE_DISABLED) { - enable_irq(IRQ_STATE_ENABLED); - mp_hal_stdout_tx_str("MPY: enabling IRQs\r\n"); - } - } - #endif - // If the GC is locked at this point there is no way out except a reset, // so force the GC to be unlocked to help the user debug what went wrong. if (MP_STATE_THREAD(gc_lock_depth) != 0) { @@ -691,7 +742,7 @@ int pyexec_friendly_repl(void) { ret = readline(&line, mp_repl_get_ps1()); } else { // Uncaught exception - mp_handle_pending(false); // clear any pending exceptions (and run any callbacks) + mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_CLEAR_EXCEPTIONS); // clear any pending exceptions (and run any callbacks) // Print exceptions but stay in the REPL. There are very few delayed // exceptions. The WatchDogTimer can raise one though. @@ -705,6 +756,7 @@ int pyexec_friendly_repl(void) { mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; + mp_hal_stdio_mode_orig(); return 0; } else if (ret == CHAR_CTRL_B) { // reset friendly REPL @@ -718,6 +770,7 @@ int pyexec_friendly_repl(void) { // exit for a soft reset mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); + mp_hal_stdio_mode_orig(); return PYEXEC_FORCED_EXIT; } else if (ret == CHAR_CTRL_E) { // paste mode @@ -762,11 +815,14 @@ int pyexec_friendly_repl(void) { } } + // Switch to original terminal mode to execute code, eg to support keyboard interrupt (SIGINT). + mp_hal_stdio_mode_orig(); // CIRCUITPY-CHANGE: add last arg ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR, NULL); if (ret & (PYEXEC_FORCED_EXIT | PYEXEC_RELOAD)) { return ret; } + mp_hal_stdio_mode_raw(); } } diff --git a/shared/runtime/pyexec.h b/shared/runtime/pyexec.h index 55a3003791c..234b201be93 100644 --- a/shared/runtime/pyexec.h +++ b/shared/runtime/pyexec.h @@ -47,10 +47,20 @@ extern pyexec_mode_kind_t pyexec_mode_kind; #define PYEXEC_FORCED_EXIT (0x100) // CIRCUITPY-CHANGE: additional flags -#define PYEXEC_EXCEPTION (0x200) #define PYEXEC_DEEP_SLEEP (0x400) #define PYEXEC_RELOAD (0x800) +#if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING +#define PYEXEC_NORMAL_EXIT (0) +#define PYEXEC_UNHANDLED_EXCEPTION (1) +#define PYEXEC_KEYBOARD_INTERRUPT (128 + 2) // same as SIG INT exit code +#define PYEXEC_ABORT (128 + 9) // same as SIG KILL exit code +#else +#define PYEXEC_NORMAL_EXIT (1) +#define PYEXEC_UNHANDLED_EXCEPTION (0) +#define PYEXEC_ABORT PYEXEC_FORCED_EXIT +#endif + int pyexec_raw_repl(void); int pyexec_friendly_repl(void); // CIRCUITPY-CHANGE: result out argument diff --git a/shared/runtime/stdout_helpers.c b/shared/runtime/stdout_helpers.c index 5d68747b6aa..0158ae7fe1d 100644 --- a/shared/runtime/stdout_helpers.c +++ b/shared/runtime/stdout_helpers.c @@ -50,7 +50,8 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { i = 1; } // Lump all characters on the next line together. - while ((last_cr || str[i] != '\n') && i < len) { + // Check i < len first so we never read str[len]. + while (i < len && (last_cr || str[i] != '\n')) { last_cr = str[i] == '\r'; i++; } diff --git a/shared/timeutils/timeutils.c b/shared/timeutils/timeutils.c index 4282a0178dd..0c6916e06dd 100644 --- a/shared/timeutils/timeutils.c +++ b/shared/timeutils/timeutils.c @@ -29,12 +29,27 @@ #include "shared/timeutils/timeutils.h" -// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately -// after Feb 29. We calculate seconds as a signed integer relative to that. +// To maintain reasonable compatibility with CPython on embedded systems, +// and avoid breaking anytime soon, timeutils functions are required to +// work properly between 1970 and 2099 on all ports. // -// Our timebase is relative to 2000-01-01. - -#define LEAPOCH ((31 + 29) * 86400) +// During that period of time, leap years occur every 4 years without +// exception, so we can keep the code short for 32 bit machines. + +// The last leap day before the required period is Feb 29, 1968. +// This is the number of days to add to get to that date. +#define PREV_LEAP_DAY ((mp_uint_t)(365 + 366 - (31 + 29))) +#define PREV_LEAP_YEAR 1968 + +// On ports where either MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND or +// MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE is enabled, we include extra +// code to support leap years outside of the 'easy' period. +// Computation is then made based on 1600 (a mod-400 year). +// This is the number of days between 1600 and 1968. +#define QC_BASE_DAY 134409 +#define QC_LEAP_YEAR 1600 +// This is the number of leap days between 1600 and 1970 +#define QC_LEAP_DAYS 89 #define DAYS_PER_400Y (365 * 400 + 97) #define DAYS_PER_100Y (365 * 100 + 24) @@ -42,8 +57,20 @@ static const uint16_t days_since_jan1[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; +// type used internally to count small integers relative to epoch +// (using uint when possible produces smaller code on some platforms) +#if MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE +typedef mp_int_t relint_t; +#else +typedef mp_uint_t relint_t; +#endif + bool timeutils_is_leap_year(mp_uint_t year) { + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; + #else + return year % 4 == 0; + #endif } // month is one based @@ -65,67 +92,67 @@ mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) { return yday; } -void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) { - // The following algorithm was adapted from musl's __secs_to_tm and adapted - // for differences in MicroPython's timebase. - - mp_int_t seconds = t - LEAPOCH; +void timeutils_seconds_since_1970_to_struct_time(timeutils_timestamp_t seconds, timeutils_struct_time_t *tm) { + // The following algorithm was inspired from musl's __secs_to_tm + // and simplified to reduce code footprint in the simple case - mp_int_t days = seconds / 86400; + relint_t days = seconds / 86400; seconds %= 86400; + #if MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE if (seconds < 0) { seconds += 86400; days -= 1; } + #endif tm->tm_hour = seconds / 3600; tm->tm_min = seconds / 60 % 60; tm->tm_sec = seconds % 60; - mp_int_t wday = (days + 2) % 7; // Mar 1, 2000 was a Wednesday (2) + relint_t wday = (days + 3) % 7; // Jan 1, 1970 was a Thursday (3) + #if MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE if (wday < 0) { wday += 7; } + #endif tm->tm_wday = wday; - mp_int_t qc_cycles = days / DAYS_PER_400Y; + days += PREV_LEAP_DAY; + + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE + // rebase day to the oldest supported date (=> always positive) + mp_uint_t base_year = QC_LEAP_YEAR; + days += QC_BASE_DAY; + mp_uint_t qc_cycles = days / DAYS_PER_400Y; days %= DAYS_PER_400Y; - if (days < 0) { - days += DAYS_PER_400Y; - qc_cycles--; - } - mp_int_t c_cycles = days / DAYS_PER_100Y; + mp_uint_t c_cycles = days / DAYS_PER_100Y; if (c_cycles == 4) { c_cycles--; } days -= (c_cycles * DAYS_PER_100Y); - - mp_int_t q_cycles = days / DAYS_PER_4Y; + #else + mp_uint_t base_year = PREV_LEAP_YEAR; + mp_uint_t qc_cycles = 0; + mp_uint_t c_cycles = 0; + #endif + + mp_uint_t q_cycles = days / DAYS_PER_4Y; + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE if (q_cycles == 25) { q_cycles--; } + #endif days -= q_cycles * DAYS_PER_4Y; - mp_int_t years = days / 365; + relint_t years = days / 365; if (years == 4) { years--; } days -= (years * 365); - /* We will compute tm_yday at the very end - mp_int_t leap = !years && (q_cycles || !c_cycles); - - tm->tm_yday = days + 31 + 28 + leap; - if (tm->tm_yday >= 365 + leap) { - tm->tm_yday -= 365 + leap; - } - - tm->tm_yday++; // Make one based - */ - - tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles; + tm->tm_year = base_year + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles; // Note: days_in_month[0] corresponds to March - static const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29}; + static const uint8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29}; mp_int_t month; for (month = 0; days_in_month[month] <= days; month++) { @@ -144,21 +171,28 @@ void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, timeutils_struct_t } // returns the number of seconds, as an integer, since 2000-01-01 -mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, +timeutils_timestamp_t timeutils_seconds_since_1970(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { - return - second - + minute * 60 - + hour * 3600 - + (timeutils_year_day(year, month, date) - 1 - + ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001 - - ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001 - + ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001 - ) * 86400 - + (year - 2000) * 31536000; + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE + mp_uint_t ref_year = QC_LEAP_YEAR; + #else + mp_uint_t ref_year = PREV_LEAP_YEAR; + #endif + timeutils_timestamp_t res; + res = ((relint_t)year - 1970) * 365; + res += (year - (ref_year + 1)) / 4; // add a day each 4 years + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE + res -= (year - (ref_year + 1)) / 100; // subtract a day each 100 years + res += (year - (ref_year + 1)) / 400; // add a day each 400 years + res -= QC_LEAP_DAYS; + #endif + res += timeutils_year_day(year, month, date) - 1; + res *= 86400; + res += hour * 3600 + minute * 60 + second; + return res; } -mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday, +timeutils_timestamp_t timeutils_mktime_1970(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { // Normalize the tuple. This allows things like: @@ -211,12 +245,16 @@ mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday, year++; } } - return timeutils_seconds_since_2000(year, month, mday, hours, minutes, seconds); + return timeutils_seconds_since_1970(year, month, mday, hours, minutes, seconds); } // Calculate the weekday from the date. // The result is zero based with 0 = Monday. // by Michael Keith and Tom Craver, 1990. int timeutils_calc_weekday(int y, int m, int d) { - return ((d += m < 3 ? y-- : y - 2, 23 * m / 9 + d + 4 + y / 4 - y / 100 + y / 400) + 6) % 7; + return ((d += m < 3 ? y-- : y - 2, 23 * m / 9 + d + 4 + y / 4 + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE + - y / 100 + y / 400 + #endif + ) + 6) % 7; } diff --git a/shared/timeutils/timeutils.h b/shared/timeutils/timeutils.h index b41903d3b27..35356b462aa 100644 --- a/shared/timeutils/timeutils.h +++ b/shared/timeutils/timeutils.h @@ -27,12 +27,23 @@ #ifndef MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H #define MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H -// CIRCUITPY-CHANGE: MICROPY_EPOCH_IS_1970 -#include "mpconfigport.h" +#include "py/obj.h" +#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#include // required for trunc() +#endif + +// `timeutils_timestamp_t` is the type used internally by timeutils to +// represent timestamps, and is always referenced to 1970. +// It may not match the platform-specific `mp_timestamp_t`. +#if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE +typedef long long timeutils_timestamp_t; +#else +typedef mp_uint_t timeutils_timestamp_t; +#endif // The number of seconds between 1970/1/1 and 2000/1/1 is calculated using: // time.mktime((2000,1,1,0,0,0,0,0,0)) - time.mktime((1970,1,1,0,0,0,0,0,0)) -#define TIMEUTILS_SECONDS_1970_TO_2000 (946684800ULL) +#define TIMEUTILS_SECONDS_1970_TO_2000 (946684800LL) typedef struct _timeutils_struct_time_t { uint16_t tm_year; // i.e. 2014 @@ -48,66 +59,116 @@ typedef struct _timeutils_struct_time_t { bool timeutils_is_leap_year(mp_uint_t year); mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month); mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date); +int timeutils_calc_weekday(int y, int m, int d); -void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, +void timeutils_seconds_since_1970_to_struct_time(timeutils_timestamp_t t, timeutils_struct_time_t *tm); // Year is absolute, month/date are 1-based, hour/minute/second are 0-based. -mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, +timeutils_timestamp_t timeutils_seconds_since_1970(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second); // Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. -mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday, +timeutils_timestamp_t timeutils_mktime_1970(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds); +static inline mp_timestamp_t timeutils_obj_get_timestamp(mp_obj_t o_in) { + #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + mp_float_t val = mp_obj_get_float(o_in); + return (mp_timestamp_t)MICROPY_FLOAT_C_FUN(trunc)(val); + #elif MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_UINT + return mp_obj_get_uint(o_in); + #else + return mp_obj_get_ll(o_in); + #endif +} + +static inline mp_obj_t timeutils_obj_from_timestamp(mp_timestamp_t t) { + #if MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_UINT + return mp_obj_new_int_from_uint(t); + #else + return mp_obj_new_int_from_ll(t); + #endif +} + +static inline void timeutils_seconds_since_2000_to_struct_time(mp_timestamp_t t, timeutils_struct_time_t *tm) { + timeutils_seconds_since_1970_to_struct_time((timeutils_timestamp_t)(t + TIMEUTILS_SECONDS_1970_TO_2000), tm); +} + +// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. +static inline mp_timestamp_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, + mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { + return (mp_timestamp_t)timeutils_seconds_since_1970(year, month, date, hour, minute, second) - TIMEUTILS_SECONDS_1970_TO_2000; +} + +// Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. +static inline mp_timestamp_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { + return (mp_timestamp_t)timeutils_mktime_1970(year, month, mday, hours, minutes, seconds) - TIMEUTILS_SECONDS_1970_TO_2000; +} + + // Select the Epoch used by the port. #if MICROPY_EPOCH_IS_1970 -static inline void timeutils_seconds_since_epoch_to_struct_time(uint64_t t, timeutils_struct_time_t *tm) { - // TODO this will give incorrect results for dates before 2000/1/1 - timeutils_seconds_since_2000_to_struct_time((mp_uint_t)(t - TIMEUTILS_SECONDS_1970_TO_2000), tm); +static inline void timeutils_seconds_since_epoch_to_struct_time(mp_timestamp_t t, timeutils_struct_time_t *tm) { + timeutils_seconds_since_1970_to_struct_time(t, tm); +} + +// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. +static inline mp_timestamp_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date, + mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { + return timeutils_seconds_since_1970(year, month, date, hour, minute, second); } // Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. -static inline uint64_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { - return timeutils_mktime_2000(year, month, mday, hours, minutes, seconds) + TIMEUTILS_SECONDS_1970_TO_2000; +static inline mp_timestamp_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { + return timeutils_mktime_1970(year, month, mday, hours, minutes, seconds); } -// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. -static inline uint64_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, - mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { - // TODO this will give incorrect results for dates before 2000/1/1 - return timeutils_seconds_since_2000(year, month, date, hour, minute, second) + TIMEUTILS_SECONDS_1970_TO_2000; +static inline mp_timestamp_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(int64_t ns) { + return (mp_timestamp_t)(ns / 1000000000LL); } -static inline mp_uint_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(uint64_t ns) { - return (mp_uint_t)(ns / 1000000000ULL); +static inline int64_t timeutils_seconds_since_epoch_to_nanoseconds_since_1970(mp_timestamp_t s) { + return (int64_t)s * 1000000000LL; } -static inline uint64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(uint64_t ns) { +static inline int64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(int64_t ns) { return ns; } #else // Epoch is 2000 -#define timeutils_seconds_since_epoch_to_struct_time timeutils_seconds_since_2000_to_struct_time -#define timeutils_seconds_since_epoch timeutils_seconds_since_2000 -#define timeutils_mktime timeutils_mktime_2000 +static inline void timeutils_seconds_since_epoch_to_struct_time(mp_timestamp_t t, timeutils_struct_time_t *tm) { + timeutils_seconds_since_2000_to_struct_time(t, tm); +} -static inline uint64_t timeutils_seconds_since_epoch_to_nanoseconds_since_1970(mp_uint_t s) { - return ((uint64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000ULL; +// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. +static inline mp_timestamp_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date, + mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { + return timeutils_seconds_since_2000(year, month, date, hour, minute, second); } -static inline mp_uint_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(uint64_t ns) { - return ns / 1000000000ULL - TIMEUTILS_SECONDS_1970_TO_2000; +// Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. +static inline mp_timestamp_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { + return timeutils_mktime_2000(year, month, mday, hours, minutes, seconds); +} + +static inline mp_timestamp_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(int64_t ns) { + return (mp_timestamp_t)(ns / 1000000000LL - TIMEUTILS_SECONDS_1970_TO_2000); +} + +static inline int64_t timeutils_seconds_since_epoch_to_nanoseconds_since_1970(mp_timestamp_t s) { + return ((int64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000LL; } static inline int64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(int64_t ns) { - return ns + TIMEUTILS_SECONDS_1970_TO_2000 * 1000000000ULL; + return ns + TIMEUTILS_SECONDS_1970_TO_2000 * 1000000000LL; } #endif -int timeutils_calc_weekday(int y, int m, int d); - #endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H diff --git a/supervisor/port.h b/supervisor/port.h index 0bf8fd8d013..3d927318a1c 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -24,13 +24,16 @@ extern uint32_t _ebss; safe_mode_t port_init(void); // Reset the microcontroller completely. -void reset_cpu(void) NORETURN; +void reset_cpu(void) MP_NORETURN; + +// Reset port state that must be torn down before anything else is reset. +void reset_port_early(void); // Reset the microcontroller state. void reset_port(void); // Reset to the bootloader -void reset_to_bootloader(void) NORETURN; +void reset_to_bootloader(void) MP_NORETURN; // Get stack limit address uint32_t *port_stack_get_limit(void); @@ -92,9 +95,17 @@ void port_wake_main_task(void); void port_wake_main_task_from_isr(void); // Some ports may use real RTOS tasks besides the background task framework of -// CircuitPython. Calling this will yield to other tasks and then return to the -// CircuitPython task when others are done. -void port_yield(void); +// CircuitPython. Calling this will yield to other tasks at the same priority level +// (or higher priority level if pre-emption is not immediate in the RTOS) +// and then return to the CircuitPython task when others are done. +// Note that this does NOT yield to lower priority tasks. Use port_task_sleep_ms() instead. +void port_task_yield(void); + +// On ports using real RTOS tasks, yield to other tasks for at least msecs. +// This will allow lower priority tasks to run. +// On non-RTOS implementations, this just sleeps for msecs and will run CircuitPython +// background tasks. +void port_task_sleep_ms(uint32_t msecs); // Some ports want to add information to boot_out.txt. // A default weak implementation is provided that does nothing. @@ -104,6 +115,11 @@ void port_boot_info(void); // A default weak implementation is provided that does nothing. void port_gc_collect(void); +// Called once the VM heap is torn down and its finalisers have run. Ports free +// memory here that heap objects may point into. +// A default weak implementation is provided that does nothing. +void port_gc_deinit(void); + // Most ports that implement CIRCUITPY_BOOT_BUTTON use a generic version of // this function to sense the button. Ports that need to can override this // function to provide their own implementation. @@ -115,3 +131,8 @@ bool port_boot_button_pressed(void); void *mp_obj_port_malloc_helper(size_t num_bytes, const mp_obj_type_t *type); mp_obj_t mp_obj_new_port_tuple(size_t n, const mp_obj_t *items); + +// Safely free an object that may have been allocated from either the GC heap or port heap. +// If the pointer is on the GC heap, it will be freed by the GC automatically. +// If the pointer is not on the GC heap, it will be freed with port_free. +void circuitpy_free_obj(mp_obj_t obj); diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 055a5cdf1fd..e5b9c0eb290 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -28,44 +28,55 @@ #include "supervisor/shared/bluetooth/file_transfer.h" #endif -#if CIRCUITPY_SERIAL_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE #include "supervisor/shared/bluetooth/serial.h" #endif +// BLE workflow exists if either or both of these are turned on. +#define BLE_WORKFLOW (CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE) + +#if BLE_WORKFLOW +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" +#endif + #if CIRCUITPY_STATUS_BAR #include "supervisor/shared/status_bar.h" #endif -#if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" +#if (BLE_WORKFLOW || (CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI)) && CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif // This standard advertisement advertises the CircuitPython editing service and a CIRCUITPY short name. -const uint8_t public_advertising_data[] = { 0x02, 0x01, 0x06, // 0-2 Flags - 0x02, 0x0a, 0xec, // 3-5 TX power level -20 - #if CIRCUITPY_BLE_FILE_SERVICE - 0x03, 0x02, 0xbb, 0xfe, // 6 - 9 Incomplete service list (File Transfer service) - #endif - 0x0e, 0xff, 0x22, 0x08, // 10 - 13 Adafruit Manufacturer Data - 0x0a, 0x04, 0x00, // 14 - 16 Creator ID / Creation ID - CIRCUITPY_CREATOR_ID & 0xff, // 17 - 20 Creator ID - (CIRCUITPY_CREATOR_ID >> 8) & 0xff, - (CIRCUITPY_CREATOR_ID >> 16) & 0xff, - (CIRCUITPY_CREATOR_ID >> 24) & 0xff, - CIRCUITPY_CREATION_ID & 0xff, // 21 - 24 Creation ID - (CIRCUITPY_CREATION_ID >> 8) & 0xff, - (CIRCUITPY_CREATION_ID >> 16) & 0xff, - (CIRCUITPY_CREATION_ID >> 24) & 0xff, - 0x05, 0x08, 0x43, 0x49, 0x52, 0x43 // 25 - 31 - Short name +const uint8_t public_advertising_data[] = { + 0x02, 0x01, 0x06, // 0-2 Flags + 0x02, 0x0a, 0xec, // 3-5 TX power level -20 + #if CIRCUITPY_BLE_FILE_SERVICE + 0x03, 0x02, 0xbb, 0xfe, // 6 - 9 Incomplete service list (File Transfer service) + #endif + 0x0e, 0xff, 0x22, 0x08, // 10 - 13 Adafruit Manufacturer Data + 0x0a, 0x04, 0x00, // 14 - 16 Creator ID / Creation ID + CIRCUITPY_CREATOR_ID & 0xff, // 17 - 20 Creator ID + (CIRCUITPY_CREATOR_ID >> 8) & 0xff, + (CIRCUITPY_CREATOR_ID >> 16) & 0xff, + (CIRCUITPY_CREATOR_ID >> 24) & 0xff, + CIRCUITPY_CREATION_ID & 0xff, // 21 - 24 Creation ID + (CIRCUITPY_CREATION_ID >> 8) & 0xff, + (CIRCUITPY_CREATION_ID >> 16) & 0xff, + (CIRCUITPY_CREATION_ID >> 24) & 0xff, + 0x05, 0x08, 0x43, 0x49, 0x52, 0x43 // 25 - 31 - Short name }; -const uint8_t private_advertising_data[] = { 0x02, 0x01, 0x06, // 0-2 Flags - 0x02, 0x0a, 0x00 // 3-5 TX power level 0 +const uint8_t private_advertising_data[] = { + 0x02, 0x01, 0x06, // 0-2 Flags + 0x02, 0x0a, 0x00 // 3-5 TX power level 0 }; // This scan response advertises the full device name (if it fits.) uint8_t circuitpython_scan_response_data[31]; -#if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE +#if BLE_WORKFLOW static bool boot_in_discovery_mode = false; static bool advertising = false; static bool _private_advertising = false; @@ -75,6 +86,11 @@ static bool ble_started = false; #define WORKFLOW_ENABLED 1 #define WORKFLOW_DISABLED 2 +// Value of CIRCUITPY_BLE_WORKFLOW in settings.toml. Defaults to true. +static bool ble_workflow_setting = true; + +// Has BLE workflow been enabled, because it was allow and we've bonded to the workflow host? +// Also controlled by supervisor.runtime.ble_workflow. static uint8_t workflow_state = WORKFLOW_UNSET; static bool was_connected = false; @@ -173,13 +189,23 @@ static void supervisor_bluetooth_start_advertising(void) { advertising = status == 0; } -#endif // CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE +#endif // BLE_WORKFLOW #define BLE_DISCOVERY_DATA_GUARD 0xbb0000bb #define BLE_DISCOVERY_DATA_GUARD_MASK 0xff0000ff void supervisor_bluetooth_init(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if BLE_WORKFLOW + + #if CIRCUITPY_SETTINGS_TOML + // Check if the user disabled BLE workflow in settings.toml. The default is that it's enabled. + ble_workflow_setting = true; + settings_get_bool("CIRCUITPY_BLE_WORKFLOW", &ble_workflow_setting); + if (!ble_workflow_setting) { + return; + } + #endif // CIRCUITPY_SETTINGS_TOML + uint32_t reset_state = port_get_saved_word(); uint32_t ble_mode = 0; if ((reset_state & BLE_DISCOVERY_DATA_GUARD_MASK) == BLE_DISCOVERY_DATA_GUARD) { @@ -187,15 +213,17 @@ void supervisor_bluetooth_init(void) { } const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); boot_in_discovery_mode = false; - if (reset_reason != RESET_REASON_POWER_ON && - reset_reason != RESET_REASON_RESET_PIN && - reset_reason != RESET_REASON_DEEP_SLEEP_ALARM && - reset_reason != RESET_REASON_UNKNOWN && - reset_reason != RESET_REASON_SOFTWARE) { + + // These are error resets reflecting a problem and should not initiate discovery mode. + if (reset_reason == MCU_RESET_REASON_BROWNOUT || + reset_reason == MCU_RESET_REASON_WATCHDOG || + reset_reason == MCU_RESET_REASON_RESCUE_DEBUG) { return; } + // Same as what is done by `import _bleio`. common_hal_bleio_init(); + if (ble_mode == 0) { port_set_saved_word(BLE_DISCOVERY_DATA_GUARD | (0x01 << 8)); } @@ -204,47 +232,66 @@ void supervisor_bluetooth_init(void) { #if CIRCUITPY_STATUS_LED status_led_init(); #endif - uint64_t start_ticks = supervisor_ticks_ms64(); - uint64_t diff = 0; if (ble_mode != 0) { boot_in_discovery_mode = true; reset_state = 0x0; } bool bonded = common_hal_bleio_adapter_is_bonded_to_central(&common_hal_bleio_adapter_obj); - #if !CIRCUITPY_USB_DEVICE - // Boot into discovery if USB isn't available and we aren't bonded already. - // Checking here allows us to have the status LED solidly on even if no button was - // pressed. - bool wifi_workflow_active = false; - #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_OS_GETENV - char _api_password[64]; - const size_t api_password_len = sizeof(_api_password) - 1; - os_getenv_err_t result = common_hal_os_getenv_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); - wifi_workflow_active = result == GETENV_OK; - #endif - if (!bonded && !wifi_workflow_active) { - boot_in_discovery_mode = true; - } - #endif - while (diff < 1000) { - #if CIRCUITPY_STATUS_LED - // Blink on for 50 and off for 100 - bool led_on = boot_in_discovery_mode || (diff % 150) <= 50; - if (led_on) { - new_status_color(0x0000ff); - } else { - new_status_color(BLACK); - } + uint64_t start_ticks = supervisor_ticks_ms64(); + uint64_t diff = 0; + + // Don't go into discovery mode when waking from deep sleep. But if we're already bonded, + // BLE workflow can continue after deep sleep. + if (reset_reason != MCU_RESET_REASON_DEEP_SLEEP_ALARM) { + #if !CIRCUITPY_USB_DEVICE + // Boot into discovery if USB isn't available and we aren't bonded already. + // Checking here allows us to have the status LED solidly on even if no button was + // pressed. + + bool wifi_workflow_active = false; + #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML + char _api_password[64]; + const size_t api_password_len = sizeof(_api_password) - 1; + settings_err_t result = settings_get_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); + wifi_workflow_active = result == SETTINGS_OK; #endif - if (port_boot_button_pressed()) { + + if (!bonded && !wifi_workflow_active) { boot_in_discovery_mode = true; - break; } - diff = supervisor_ticks_ms64() - start_ticks; - } - if (boot_in_discovery_mode) { - common_hal_bleio_adapter_erase_bonding(&common_hal_bleio_adapter_obj); + #endif // !CIRCUITPY_USB_DEVICE + + // A press must begin inside this interval. The safe mode interval just before + // this one also uses the boot button, and a press meant for safe mode can + // still be held down when this interval starts; entering discovery mode from + // it would erase bonding unasked. Require a release first. + bool button_released = !port_boot_button_pressed(); + while (diff < 1000) { + #if CIRCUITPY_STATUS_LED + // Blink on for 50 and off for 100 + bool led_on = boot_in_discovery_mode || (diff % 150) <= 50; + if (led_on) { + new_status_color(0x0000ff); + } else { + new_status_color(BLACK); + } + #endif + if (!port_boot_button_pressed()) { + button_released = true; + } else if (button_released && !boot_in_discovery_mode) { + boot_in_discovery_mode = true; + // Restart the interval so the LED shows solid blue for the full + // 1000 ms, as feedback that the press was accepted and bonding + // will be erased. + start_ticks = supervisor_ticks_ms64(); + } + diff = supervisor_ticks_ms64() - start_ticks; + } + if (boot_in_discovery_mode) { + common_hal_bleio_adapter_erase_bonding(&common_hal_bleio_adapter_obj); + } } + if (boot_in_discovery_mode || bonded) { workflow_state = WORKFLOW_ENABLED; } else { @@ -259,7 +306,7 @@ void supervisor_bluetooth_init(void) { } void supervisor_bluetooth_background(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if BLE_WORKFLOW if (!ble_started) { return; } @@ -290,8 +337,21 @@ void supervisor_bluetooth_background(void) { #endif } +#if BLE_WORKFLOW +// adafXXXX-4369-7263-7569-74507974686e, stored little-endian. The XXXX bytes are +// filled in by common_hal_bleio_uuid_construct(). +const uint8_t circuitpython_base_uuid[16] = {0x6e, 0x68, 0x74, 0x79, 0x50, 0x74, 0x69, 0x75, 0x63, 0x72, 0x69, 0x43, 0x00, 0x00, 0xaf, 0xad }; + +static bleio_service_obj_t guard_service; +static bleio_uuid_obj_t guard_service_uuid; +static bleio_characteristic_obj_t guard_characteristic; +static bleio_uuid_obj_t guard_characteristic_uuid; +static mp_obj_list_t guard_characteristic_list; +static mp_obj_t guard_characteristic_list_items[1]; +#endif + void supervisor_start_bluetooth(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if BLE_WORKFLOW if (workflow_state != WORKFLOW_ENABLED || ble_started) { return; @@ -303,10 +363,49 @@ void supervisor_start_bluetooth(void) { supervisor_start_bluetooth_file_transfer(); #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE supervisor_start_bluetooth_serial(); #endif + // Create an unused service that will be in the GATT table immediately after + // the BLE workflow services. This protects the workflow services from being + // invalidated if user code creates services. + // + // A peripheral reports its last primary service with End Group Handle 0xffff, + // and hosts cache that literally. So a service that user code adds later lands + // inside the cached range of whichever service was last, and hosts treat the + // addition as a change to that service: Chrome invalidates the page's object + // for it (and has no event to report that to JavaScript), and BlueZ drops it + // from its cache entirely. This guard is created last so that it, + // not a workflow service, is the one affected, and file transfer and serial + // keep working. Costs three attribute handles. + guard_service_uuid.base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(&guard_service_uuid, 0x0004, circuitpython_base_uuid); + guard_characteristic_list.base.type = &mp_type_list; + guard_characteristic_list.alloc = 1; + guard_characteristic_list.len = 0; + guard_characteristic_list.items = guard_characteristic_list_items; + guard_characteristic_list_items[0] = MP_OBJ_NULL; + guard_service.base.type = &bleio_service_type; + _common_hal_bleio_service_construct(&guard_service, &guard_service_uuid, false /* is secondary */, &guard_characteristic_list); + + // One read-only characteristic: we need at least one because on espressif + // a service is not registered with NimBLE until its first characteristic is added. + guard_characteristic_uuid.base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(&guard_characteristic_uuid, 0x0005, circuitpython_base_uuid); + guard_characteristic.base.type = &bleio_characteristic_type; + common_hal_bleio_characteristic_construct(&guard_characteristic, + &guard_service, + 0, // handle (for remote only) + &guard_characteristic_uuid, + CHAR_PROP_READ, + SECURITY_MODE_ENC_NO_MITM, + SECURITY_MODE_NO_ACCESS, + 1, // max length + true, // fixed length + NULL, // no initial value + NULL); + // Mark as started so that the background call does something. ble_started = true; @@ -321,7 +420,7 @@ void supervisor_start_bluetooth(void) { } void supervisor_stop_bluetooth(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if BLE_WORKFLOW if (!ble_started && workflow_state != WORKFLOW_ENABLED) { return; @@ -333,16 +432,20 @@ void supervisor_stop_bluetooth(void) { supervisor_stop_bluetooth_file_transfer(); #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE supervisor_stop_bluetooth_serial(); #endif + // Tear down the guard service too. + common_hal_bleio_characteristic_deinit(&guard_characteristic); + common_hal_bleio_service_deinit(&guard_service); + #endif } void supervisor_bluetooth_enable_workflow(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE - if (workflow_state == WORKFLOW_DISABLED) { + #if BLE_WORKFLOW + if (!ble_workflow_setting || workflow_state == WORKFLOW_DISABLED) { return; } workflow_state = WORKFLOW_ENABLED; @@ -350,13 +453,13 @@ void supervisor_bluetooth_enable_workflow(void) { } void supervisor_bluetooth_disable_workflow(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if BLE_WORKFLOW workflow_state = WORKFLOW_DISABLED; #endif } bool supervisor_bluetooth_workflow_is_enabled(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if BLE_WORKFLOW if (workflow_state == WORKFLOW_ENABLED) { return true; } diff --git a/supervisor/shared/bluetooth/bluetooth.h b/supervisor/shared/bluetooth/bluetooth.h index 14e74a07c73..0050d702e02 100644 --- a/supervisor/shared/bluetooth/bluetooth.h +++ b/supervisor/shared/bluetooth/bluetooth.h @@ -7,6 +7,9 @@ #pragma once #include +#include + +extern const uint8_t circuitpython_base_uuid[16]; void supervisor_bluetooth_background(void); void supervisor_bluetooth_init(void); diff --git a/supervisor/shared/bluetooth/file_transfer.c b/supervisor/shared/bluetooth/file_transfer.c index 66eccf8cbf2..d8b5f68ca2d 100644 --- a/supervisor/shared/bluetooth/file_transfer.c +++ b/supervisor/shared/bluetooth/file_transfer.c @@ -38,6 +38,10 @@ static mp_obj_t characteristic_list_items[2]; // uint32_t so its aligned static uint32_t _buffer[PACKET_BUFFER_SIZE / 4 + 1]; static uint32_t _outgoing1[BLEIO_PACKET_BUFFER_MAX_PACKET_SIZE / 4]; +// TODO: _outgoing2 is unused on espressif, whose NimBLE send calls copy the data +// rather than retaining the buffer as the nordic SoftDevice does. Letting a port +// declare how many outgoing buffers it needs would drop this static allocation +// there; nordic requires both. static uint32_t _outgoing2[BLEIO_PACKET_BUFFER_MAX_PACKET_SIZE / 4]; static ble_event_handler_t static_handler_entry; static bleio_packet_buffer_obj_t _transfer_packet_buffer; diff --git a/supervisor/shared/bluetooth/serial.c b/supervisor/shared/bluetooth/serial.c index 86ff1738a2a..037e5e3c7b7 100644 --- a/supervisor/shared/bluetooth/serial.c +++ b/supervisor/shared/bluetooth/serial.c @@ -15,6 +15,7 @@ #include "shared-bindings/_bleio/Service.h" #include "shared-bindings/_bleio/UUID.h" #include "shared-module/storage/__init__.h" +#include "supervisor/shared/bluetooth/bluetooth.h" #include "supervisor/shared/bluetooth/serial.h" #include "common-hal/_bleio/__init__.h" @@ -30,9 +31,6 @@ static bleio_uuid_obj_t supervisor_ble_circuitpython_tx_uuid; static bleio_characteristic_obj_t supervisor_ble_circuitpython_version_characteristic; static bleio_uuid_obj_t supervisor_ble_circuitpython_version_uuid; -// This is the base UUID for the CircuitPython service. -const uint8_t circuitpython_base_uuid[16] = {0x6e, 0x68, 0x74, 0x79, 0x50, 0x74, 0x69, 0x75, 0x63, 0x72, 0x69, 0x43, 0x00, 0x00, 0xaf, 0xad }; - static mp_obj_list_t characteristic_list; static mp_obj_t characteristic_list_items[3]; @@ -40,6 +38,10 @@ static mp_obj_t characteristic_list_items[3]; #error "BLEIO_PACKET_BUFFER_MAX_PACKET_SIZE must be a multiple of 4" #endif static uint32_t _outgoing1[BLEIO_PACKET_BUFFER_MAX_PACKET_SIZE / 4]; +// TODO: _outgoing2 is unused on espressif, whose NimBLE send calls copy the data +// rather than retaining the buffer as the nordic SoftDevice does. Letting a port +// declare how many outgoing buffers it needs would drop this static allocation +// there; nordic requires both. static uint32_t _outgoing2[BLEIO_PACKET_BUFFER_MAX_PACKET_SIZE / 4]; static ble_event_handler_t rx_static_handler_entry; static ble_event_handler_t tx_static_handler_entry; @@ -133,7 +135,7 @@ void supervisor_start_bluetooth_serial(void) { _common_hal_bleio_characteristic_buffer_construct(&_rx_buffer, &supervisor_ble_circuitpython_rx_characteristic, 0.1f, - (uint8_t *)_incoming, sizeof(_incoming) * sizeof(uint32_t), + (uint8_t *)_incoming, sizeof(_incoming), &rx_static_handler_entry, true /* watch for interrupt character */); diff --git a/supervisor/shared/cpu_regs.S b/supervisor/shared/cpu_regs.S deleted file mode 100644 index 90e5367ed58..00000000000 --- a/supervisor/shared/cpu_regs.S +++ /dev/null @@ -1,102 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "supervisor/shared/cpu_regs.h" - -#ifdef __arm__ -.syntax unified -.thumb -.text -.align 2 - -@ uint cpu_get_regs_and_sp(r0=uint regs[SAVED_REGISTER_COUNT]) -.global cpu_get_regs_and_sp -.thumb -.thumb_func -.type cpu_get_regs_and_sp, %function -cpu_get_regs_and_sp: -#if __ARM_ARCH_ISA_THUMB == 2 -@ store registers into given array -#ifdef __arm__ -stmia r0!, {r4-r11} -#endif -#if defined(__aarch64__) && __aarch64__ == 1 -#error "aarch64 not supported" -stmia r0!, {x19-x28} -#endif -#ifdef __ARM_FP -#ifdef __arm__ -vstmia r0!, {s16-s31} -#endif -#if defined(__aarch64__) && __aarch64__ == 1 -vst1.64 {d8-d15}, [r0], #16 -#endif -#endif -#endif -// Thumb 1 can only store directly from R0-R7. This is M0 and M23 mostly. -#if __ARM_ARCH_ISA_THUMB == 1 -str r4, [r0, #0] -str r5, [r0, #4] -str r6, [r0, #8] -str r7, [r0, #12] -push {r1} -mov r1, r8 -str r1, [r0, #16] -mov r1, r9 -str r1, [r0, #20] -mov r1, r10 -str r1, [r0, #24] -mov r1, r11 -str r1, [r0, #28] -mov r1, r12 -str r1, [r0, #32] -mov r1, r13 -str r1, [r0, #36] -pop {r1} -#endif - -@ return the sp -mov r0, sp -bx lr -#endif - -#ifdef __riscv -#if __riscv_xlen == 32 -.global cpu_get_regs_and_sp -.type cpu_get_regs_and_sp, %function -cpu_get_regs_and_sp: -sw s0, 0(a0) -sw s1, 4(a0) -sw s2, 8(a0) -sw s3, 12(a0) -sw s4, 16(a0) -sw s5, 20(a0) -sw s6, 24(a0) -sw s7, 28(a0) -sw s8, 32(a0) -sw s9, 36(a0) -sw s10, 40(a0) -sw s11, 44(a0) -#ifdef __riscv_vector -sw fs0, 48(a0) -sw fs1, 52(a0) -sw fs2, 56(a0) -sw fs3, 60(a0) -sw fs4, 64(a0) -sw fs5, 68(a0) -sw fs6, 72(a0) -sw fs7, 76(a0) -sw fs8, 80(a0) -sw fs9, 84(a0) -sw fs10, 88(a0) -sw fs11, 92(a0) -#endif -move a0, sp -ret -#else -#error "Unsupported RISC-V bit length" -#endif -#endif diff --git a/supervisor/shared/cpu_regs.h b/supervisor/shared/cpu_regs.h deleted file mode 100644 index 8243c2388cd..00000000000 --- a/supervisor/shared/cpu_regs.h +++ /dev/null @@ -1,38 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#ifdef __arm__ -#define INTEGER_REGS 10 -#ifdef __ARM_FP -#define FLOATING_POINT_REGS 16 -#endif -#endif - -#ifdef __aarch64__ -#define INTEGER_REGS 10 -#ifdef __ARM_FP -#define FLOATING_POINT_REGS 8 -#endif -#endif - -#ifdef __riscv -#define INTEGER_REGS 12 -#ifdef __riscv_vector -#define FLOATING_POINT_REGS 12 -#endif -#endif - -#ifndef INTEGER_REGS -#define INTEGER_REGS 0 -#endif - -#ifndef FLOATING_POINT_REGS -#define FLOATING_POINT_REGS 0 -#endif - -#define SAVED_REGISTER_COUNT (INTEGER_REGS + FLOATING_POINT_REGS) diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 8d53b0e62be..1352c76b006 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -38,9 +38,11 @@ #if CIRCUITPY_TERMINALIO #include "supervisor/port.h" -#if CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" + +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif + #if CIRCUITPY_LVFONTIO #include "shared-bindings/lvfontio/OnDiskFont.h" #include "supervisor/filesystem.h" @@ -66,10 +68,10 @@ static bool check_for_custom_font(const char **font_path_out) { const char *default_font_path = "/fonts/terminal.lvfontbin"; const char *font_path = default_font_path; - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML // Buffer for storing custom font path static char custom_font_path[128]; - if (common_hal_os_getenv_str("CIRCUITPY_TERMINAL_FONT", custom_font_path, sizeof(custom_font_path)) == GETENV_OK) { + if (settings_get_str("CIRCUITPY_TERMINAL_FONT", custom_font_path, sizeof(custom_font_path)) == SETTINGS_OK) { // Use custom font path from environment variable font_path = custom_font_path; } @@ -125,7 +127,7 @@ static uint8_t *tilegrid_tiles = NULL; static size_t tilegrid_tiles_size = 0; #endif -#if CIRCUITPY_LVFONTIO +#if CIRCUITPY_LVFONTIO && CIRCUITPY_TERMINALIO static lvfontio_ondiskfont_t *lvfont = NULL; #endif @@ -179,8 +181,8 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) { if (width_in_tiles <= 120) { scale = 1; } - #if CIRCUITPY_OS_GETENV - (void)common_hal_os_getenv_int("CIRCUITPY_TERMINAL_SCALE", &scale); + #if CIRCUITPY_SETTINGS_TOML + (void)settings_get_int("CIRCUITPY_TERMINAL_SCALE", &scale); #endif width_in_tiles = MAX(1, width_px / (glyph_width * scale)); diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 025c9ddbd6d..4335e9afc6e 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -19,6 +19,10 @@ #include "shared-module/sdcardio/__init__.h" #endif +#if CIRCUITPY_EMMC_USB +#include "shared-module/emmcio/__init__.h" +#endif + static mp_vfs_mount_t _circuitpy_vfs; static fs_user_mount_t _circuitpy_usermount; @@ -172,7 +176,7 @@ bool filesystem_init(bool create_allowed, bool force_create) { #endif #endif - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML make_empty_file(&circuitpy->fatfs, "/settings.toml"); #endif // make a sample code.py file @@ -219,6 +223,22 @@ bool filesystem_init(bool create_allowed, bool force_create) { #if CIRCUITPY_SDCARDIO sdcardio_init(); + #if defined(DEFAULT_SD_CARD_DETECT) && CIRCUITPY_SDCARD_USB + // Mount the SD card now so it's ready when USB enumerates. + // Lazy mount from tud_msc_test_unit_ready_cb can lose races with + // macOS's probe timing. Gated on CIRCUITPY_SDCARD_USB to match the + // existing call site in usb_msc_flash.c (guarded by SDCARD_LUN). + // automount_sd_card() itself honors the runtime CIRCUITPY_SDCARD_USB + // setting and is a no-op when it is disabled. + automount_sd_card(); + #endif + #endif + + // Same reason as the SD card above, mount it before USB enumerates rather than + // lazily from tud_msc_test_unit_ready_cb(). Also the same requirement + // that settings.toml is readable. + #if CIRCUITPY_EMMC_USB + automount_emmc(); #endif return true; @@ -320,12 +340,23 @@ bool filesystem_lock(fs_user_mount_t *fs_mount) { return false; } fs_mount->lock_count += 1; + // CIRCUITPY-CHANGE: while a non-USB-MSC writer (BLE file transfer, web + // workflow, storage.remount) holds the filesystem lock, allow the + // FatFS f_open(FA_WRITE) path to bypass STA_PROTECT. Without this, the + // disk_ioctl(IOCTL_STATUS) -> filesystem_is_writable_by_python() check + // added by #10659 always sets STA_PROTECT on USB-device-capable boards, + // so even after the lock is held, f_open returns FR_WRITE_PROTECTED. + // USB MSC takes the lock via blockdev_lock() directly, NOT via + // filesystem_lock(), so this flag is never set on its behalf. + fs_mount->blockdev.flags |= MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION; return true; } void filesystem_unlock(fs_user_mount_t *fs_mount) { fs_mount->lock_count -= 1; if (fs_mount->lock_count == 0) { + // CIRCUITPY-CHANGE: clear the bypass when releasing the lock. + fs_mount->blockdev.flags &= ~MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION; blockdev_unlock(fs_mount); } } diff --git a/supervisor/shared/port.c b/supervisor/shared/port.c index aabf003fb30..4e3e12891d1 100644 --- a/supervisor/shared/port.c +++ b/supervisor/shared/port.c @@ -8,7 +8,9 @@ #include +#include "py/mphal.h" #include "py/runtime.h" +#include "py/gc.h" #include "lib/tlsf/tlsf.h" @@ -19,13 +21,20 @@ static tlsf_t heap; +MP_WEAK void reset_port_early(void) { +} + MP_WEAK void port_wake_main_task(void) { } MP_WEAK void port_wake_main_task_from_isr(void) { } -MP_WEAK void port_yield(void) { +MP_WEAK void port_task_yield(void) { +} + +MP_WEAK void port_task_sleep_ms(uint32_t msecs) { + mp_hal_delay_ms(msecs); } MP_WEAK void port_boot_info(void) { @@ -56,6 +65,22 @@ MP_WEAK void port_free(void *ptr) { tlsf_free(heap, ptr); } +// Safely free an object that may have been allocated from either the GC heap or port heap. +// If the pointer is on the GC heap, it will be freed by the GC automatically, so we do nothing. +// If the pointer is not on the GC heap (i.e., allocated with port_malloc), we free it with port_free. +// This is safe to call during shutdown when GC may not be available. +void circuitpy_free_obj(mp_obj_t obj) { + if (obj == mp_const_none) { + return; + } + void *ptr = MP_OBJ_TO_PTR(obj); + if (gc_alloc_possible() && gc_ptr_on_heap(ptr)) { + gc_free(ptr); + } else { + port_free(ptr); + } +} + MP_WEAK void *port_realloc(void *ptr, size_t size, bool dma_capable) { return tlsf_realloc(heap, ptr, size); } @@ -94,6 +119,10 @@ MP_WEAK bool port_boot_button_pressed(void) { MP_WEAK void port_gc_collect(void) { } +// Ports may provide an implementation of this function if it is needed +MP_WEAK void port_gc_deinit(void) { +} + // Allocates an object in the port heap, not the VM heap, and also sets type, for mp_obj_malloc{,_var} macros. MP_NOINLINE void *mp_obj_port_malloc_helper(size_t num_bytes, const mp_obj_type_t *type) { mp_obj_base_t *base = (mp_obj_base_t *)port_malloc_zero(num_bytes, false); diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 5f24618f7f3..fba4c0fb37f 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -18,6 +18,14 @@ #include "supervisor/shared/translate/translate.h" #include "supervisor/shared/tick.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + +#ifdef __ZEPHYR__ +#include +#endif + #define SAFE_MODE_DATA_GUARD 0xad0000af #define SAFE_MODE_DATA_GUARD_MASK 0xff0000ff @@ -46,10 +54,10 @@ safe_mode_t wait_for_safe_mode_reset(void) { } const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); - if (reset_reason != RESET_REASON_POWER_ON && - reset_reason != RESET_REASON_RESET_PIN && - reset_reason != RESET_REASON_UNKNOWN && - reset_reason != RESET_REASON_SOFTWARE) { + // Skip safe-mode wait if the reset reason was due to a problem. + if (reset_reason == MCU_RESET_REASON_BROWNOUT || + reset_reason == MCU_RESET_REASON_WATCHDOG || + reset_reason == MCU_RESET_REASON_RESCUE_DEBUG) { return SAFE_MODE_NONE; } #if CIRCUITPY_SKIP_SAFE_MODE_WAIT @@ -61,22 +69,39 @@ safe_mode_t wait_for_safe_mode_reset(void) { #if CIRCUITPY_STATUS_LED status_led_init(); #endif + + #define DEFAULT_SAFE_MODE_DELAY_MSECS (1000) + #define DEFAULT_SAFE_MODE_DELAY_SECS (((mp_float_t)DEFAULT_SAFE_MODE_DELAY_MSECS) / 1000.0f) + uint32_t safe_mode_delay_msecs = DEFAULT_SAFE_MODE_DELAY_MSECS; + + #if CIRCUITPY_SETTINGS_TOML + mp_float_t safe_mode_delay_secs = DEFAULT_SAFE_MODE_DELAY_SECS; + // Will update safe_mode_delay_secs if setting is present. + settings_get_float("CIRCUITPY_SAFE_MODE_DELAY", &safe_mode_delay_secs); + if (safe_mode_delay_secs >= 0.0f && safe_mode_delay_secs <= (mp_float_t)UINT32_MAX) { + safe_mode_delay_msecs = safe_mode_delay_secs * 1000; + } + #endif + uint64_t start_ticks = supervisor_ticks_ms64(); uint64_t diff = 0; bool boot_in_safe_mode = false; - while (diff < 1000) { + while (diff < safe_mode_delay_msecs) { #if CIRCUITPY_STATUS_LED - // Blink on for 100, off for 100 - bool led_on = (diff % 250) < 125; + // Blink on for 125, off for 125 + bool led_on = boot_in_safe_mode || (diff % 250) < 125; if (led_on) { new_status_color(SAFE_MODE); } else { new_status_color(BLACK); } #endif - if (port_boot_button_pressed()) { + if (!boot_in_safe_mode && port_boot_button_pressed()) { boot_in_safe_mode = true; - break; + // Show solid yellow as feedback that the press was accepted, for the + // default duration. + start_ticks = supervisor_ticks_ms64(); + safe_mode_delay_msecs = DEFAULT_SAFE_MODE_DELAY_MSECS; } diff = supervisor_ticks_ms64() - start_ticks; } @@ -99,10 +124,19 @@ void PLACE_IN_ITCM(safe_mode_on_next_reset)(safe_mode_t reason) { // Don't inline this so it's easy to break on it from GDB. void __attribute__((noinline, )) PLACE_IN_ITCM(reset_into_safe_mode)(safe_mode_t reason) { if (_safe_mode > SAFE_MODE_BROWNOUT && reason > SAFE_MODE_BROWNOUT) { + #ifdef __ZEPHYR__ + printk("Already in safe mode\n"); + printk("Reason: %d\n", reason); + printk("Current safe mode: %d\n", _safe_mode); + while (true) { + k_cpu_idle(); + } + #else while (true) { // This very bad because it means running in safe mode didn't save us. Only ignore brownout // because it may be due to a switch bouncing. } + #endif } safe_mode_on_next_reset(reason); diff --git a/supervisor/shared/safe_mode.h b/supervisor/shared/safe_mode.h index 8f4037cbe20..87f65d867ea 100644 --- a/supervisor/shared/safe_mode.h +++ b/supervisor/shared/safe_mode.h @@ -38,6 +38,6 @@ void set_safe_mode(safe_mode_t safe_mode); safe_mode_t wait_for_safe_mode_reset(void); void safe_mode_on_next_reset(safe_mode_t reason); -void reset_into_safe_mode(safe_mode_t reason) NORETURN; +void reset_into_safe_mode(safe_mode_t reason) MP_NORETURN; void print_safe_mode_message(safe_mode_t reason); diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c index 94b429b6ab6..1bfb8d73b3c 100644 --- a/supervisor/shared/serial.c +++ b/supervisor/shared/serial.c @@ -17,7 +17,7 @@ #include "supervisor/shared/serial.h" #include "shared-bindings/microcontroller/Pin.h" -#if CIRCUITPY_SERIAL_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE #include "supervisor/shared/bluetooth/serial.h" #endif @@ -219,7 +219,7 @@ void serial_init(void) { } bool serial_connected(void) { - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR if (tud_vendor_connected()) { return true; } @@ -229,17 +229,17 @@ bool serial_connected(void) { return true; #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE if (ble_serial_connected()) { return true; } #endif - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC if (usb_cdc_console_enabled() && tud_cdc_connected()) { return true; } - #elif CIRCUITPY_USB_DEVICE + #elif CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE if (tud_cdc_connected()) { return true; } @@ -273,7 +273,7 @@ bool serial_connected(void) { } char serial_read(void) { - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR if (tud_vendor_connected() && tud_vendor_available() > 0) { char tiny_buffer; tud_vendor_read(&tiny_buffer, 1); @@ -290,7 +290,7 @@ char serial_read(void) { } #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE if (ble_serial_available() > 0) { return ble_serial_read_char(); } @@ -327,7 +327,7 @@ char serial_read(void) { return -1; } #endif - #if CIRCUITPY_USB_DEVICE + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE return (char)tud_cdc_read_char(); #endif @@ -338,7 +338,7 @@ uint32_t serial_bytes_available(void) { // There may be multiple serial input channels, so sum the count from all. uint32_t count = 0; - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR if (tud_vendor_connected()) { count += tud_vendor_available(); } @@ -348,7 +348,7 @@ uint32_t serial_bytes_available(void) { count += common_hal_busio_uart_rx_characters_available(&console_uart); #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE count += ble_serial_available(); #endif @@ -360,7 +360,7 @@ uint32_t serial_bytes_available(void) { count += usb_keyboard_chars_available(); #endif - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC if (usb_cdc_console_enabled()) { count += tud_cdc_available(); } @@ -399,7 +399,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) { return length_sent; } - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR if (tud_vendor_connected()) { length_sent = tud_vendor_write(text, length); } @@ -409,7 +409,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) { length_sent = console_uart_write(text, length); #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE ble_serial_write(text, length); #endif @@ -423,7 +423,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) { } #endif - #if CIRCUITPY_USB_DEVICE + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE // Delay the very first write if (tud_cdc_connected() && !_first_write_done) { mp_hal_delay_ms(50); diff --git a/supervisor/shared/settings.c b/supervisor/shared/settings.c new file mode 100644 index 00000000000..1414195411e --- /dev/null +++ b/supervisor/shared/settings.c @@ -0,0 +1,525 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Scott Shawcroft for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include + +#include "py/gc.h" +#include "py/misc.h" +#include "py/mpstate.h" +#include "py/mpprint.h" +#include "py/objstr.h" +#include "py/parsenum.h" +#include "py/runtime.h" +#include "supervisor/filesystem.h" +#include "supervisor/shared/settings.h" + +#define SETTINGS_PATH "/settings.toml" + +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" + +#if CIRCUITPY_SETTINGS_TOML +typedef FIL file_arg; +static bool open_file(const char *name, file_arg *file_handle) { + #if defined(UNIX) + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t file_obj = mp_call_function_2( + MP_OBJ_FROM_PTR(&mp_builtin_open_obj), mp_obj_new_str(name, strlen(name)), MP_ROM_QSTR(MP_QSTR_rb)); + mp_arg_validate_type(file_obj, &mp_type_vfs_fat_fileio, MP_QSTR_file); + pyb_file_obj_t *file = MP_OBJ_TO_PTR(file_obj); + *file_handle = file->fp; + nlr_pop(); + return true; + } else { + return false; + } + #else + fs_user_mount_t *fs_mount = filesystem_circuitpy(); + if (fs_mount == NULL) { + return false; + } + FATFS *fatfs = &fs_mount->fatfs; + FRESULT result = f_open(fatfs, file_handle, name, FA_READ); + return result == FR_OK; + #endif +} + +static void close_file(file_arg *file_handle) { + f_close(file_handle); +} + +static bool is_eof(file_arg *file_handle) { + return f_eof(file_handle) || f_error(file_handle); +} + +// Return 0 if there is no next character (EOF). +static uint8_t get_next_byte(FIL *file_handle) { + uint8_t character = 0; + UINT quantity_read; + // If there's an error or quantity_read is 0, character will remain 0. + f_read(file_handle, &character, 1, &quantity_read); + return character; +} + +static void seek_eof(file_arg *file_handle) { + f_lseek(file_handle, f_size(file_handle)); +} + +// For a fixed buffer, record the required size rather than throwing +static void vstr_add_byte_nonstd(vstr_t *vstr, byte b) { + if (!vstr->fixed_buf || vstr->alloc > vstr->len) { + vstr_add_byte(vstr, b); + } else { + vstr->len++; + } +} + +// For a fixed buffer, record the required size rather than throwing +static void vstr_add_char_nonstd(vstr_t *vstr, unichar c) { + size_t ulen = + (c < 0x80) ? 1 : + (c < 0x800) ? 2 : + (c < 0x10000) ? 3 : 4; + if (!vstr->fixed_buf || vstr->alloc > vstr->len + ulen) { + vstr_add_char(vstr, c); + } else { + vstr->len += ulen; + } +} + +static void next_line(file_arg *file_handle) { + uint8_t character; + do { + character = get_next_byte(file_handle); + } while (character != 0 && character != '\n'); +} + +// Discard whitespace, except for newlines, returning the next character after the whitespace. +// Return 0 if there is no next character (EOF). +static uint8_t consume_whitespace(file_arg *file_handle) { + uint8_t character; + do { + character = get_next_byte(file_handle); + } while (character != '\n' && character != 0 && unichar_isspace(character)); + return character; +} + +// Starting at the start of a new line, determines if the key matches the given key. +// +// If result is true, the key matches and file pointer is pointing just after the "=". +// If the result is false, the key does NOT match and the file pointer is +// pointing at the start of the next line, if any +static bool key_matches(file_arg *file_handle, const char *key) { + uint8_t character; + character = consume_whitespace(file_handle); + // [section] isn't implemented, so skip to end of file. + if (character == '[' || character == 0) { + seek_eof(file_handle); + return false; + } + while (*key) { + if (character != *key++) { + // A character didn't match the key, so it's not a match + // If the non-matching char was not the end of the line, + // then consume the rest of the line + if (character != '\n') { + next_line(file_handle); + } + return false; + } + character = get_next_byte(file_handle); + } + // the next character could be whitespace; consume if necessary + if (unichar_isspace(character)) { + character = consume_whitespace(file_handle); + } + // If we're not looking at the "=" then the key didn't match + if (character != '=') { + // A character didn't match the key, so it's not a match + // If the non-matching char was not the end of the line, + // then consume the rest of the line + if (character != '\n') { + next_line(file_handle); + } + return false; + } + return true; +} + +static settings_err_t read_unicode_escape(file_arg *file_handle, int sz, vstr_t *vstr) { + char hex_buf[sz + 1]; + for (int i = 0; i < sz; i++) { + hex_buf[i] = get_next_byte(file_handle); + } + hex_buf[sz] = 0; + char *end; + unsigned long c = strtoul(hex_buf, &end, 16); + if (end != &hex_buf[sz]) { + return SETTINGS_ERR_BAD_VALUE; + } + if (c >= 0x110000) { + return SETTINGS_ERR_UNICODE; + } + vstr_add_char_nonstd(vstr, c); + return SETTINGS_OK; +} + +// Read a quoted string +static settings_err_t read_string_value(file_arg *file_handle, vstr_t *vstr) { + while (true) { + int character = get_next_byte(file_handle); + switch (character) { + case 0: + case '\n': + return SETTINGS_ERR_BAD_VALUE; + + case '"': + character = consume_whitespace(file_handle); + switch (character) { + case '#': + next_line(file_handle); + MP_FALLTHROUGH; + case 0: + case '\n': + return SETTINGS_OK; + default: + return SETTINGS_ERR_BAD_VALUE; + } + + case '\\': + character = get_next_byte(file_handle); + switch (character) { + case 0: + case '\n': + return SETTINGS_ERR_BAD_VALUE; + case 'b': + character = '\b'; + break; + case 'r': + character = '\r'; + break; + case 'n': + character = '\n'; + break; + case 't': + character = '\t'; + break; + case 'v': + character = '\v'; + break; + case 'f': + character = '\f'; + break; + case 'U': + case 'u': { + int sz = (character == 'u') ? 4 : 8; + settings_err_t res; + res = read_unicode_escape(file_handle, sz, vstr); + if (res != SETTINGS_OK) { + return res; + } + continue; + } + // default falls through, other escaped characters + // represent themselves + } + MP_FALLTHROUGH; + default: + vstr_add_byte_nonstd(vstr, character); + } + } +} + +// Read a bare value (non-quoted value) as a string +// Trims leading and trailing spaces/tabs, stops at # comment or newline +static settings_err_t read_bare_value(file_arg *file_handle, vstr_t *vstr, int first_character) { + int character = first_character; + size_t trailing_space_count = 0; + + while (true) { + switch (character) { + case 0: + case '\n': + // Remove trailing spaces/tabs and \r + vstr->len -= trailing_space_count; + return SETTINGS_OK; + case '#': + // Remove trailing spaces/tabs and \r before comment + vstr->len -= trailing_space_count; + next_line(file_handle); + return SETTINGS_OK; + case ' ': + case '\t': + case '\r': + // Track potential trailing whitespace + vstr_add_byte_nonstd(vstr, character); + trailing_space_count++; + break; + default: + // Non-whitespace character resets trailing space count + vstr_add_byte_nonstd(vstr, character); + trailing_space_count = 0; + } + character = get_next_byte(file_handle); + } +} + +static mp_int_t read_value(file_arg *file_handle, vstr_t *vstr, bool *quoted) { + uint8_t character; + character = consume_whitespace(file_handle); + *quoted = (character == '"'); + + if (*quoted) { + return read_string_value(file_handle, vstr); + } else if (character == '\n' || character == 0) { + // Empty value is an error + return SETTINGS_ERR_BAD_VALUE; + } else { + return read_bare_value(file_handle, vstr, character); + } +} + +static settings_err_t settings_get_vstr(const char *key, vstr_t *vstr, bool *quoted) { + file_arg file_handle; + if (!open_file(SETTINGS_PATH, &file_handle)) { + return SETTINGS_ERR_OPEN; + } + + settings_err_t result = SETTINGS_ERR_NOT_FOUND; + while (!is_eof(&file_handle)) { + if (key_matches(&file_handle, key)) { + result = read_value(&file_handle, vstr, quoted); + break; + } + } + close_file(&file_handle); + return result; +} + +static settings_err_t settings_get_buf_terminated(const char *key, char *value, size_t value_len, bool *quoted) { + vstr_t vstr; + vstr_init_fixed_buf(&vstr, value_len, value); + settings_err_t result = settings_get_vstr(key, &vstr, quoted); + + if (result == SETTINGS_OK) { + vstr_add_byte_nonstd(&vstr, 0); + memcpy(value, vstr.buf, MIN(vstr.len, value_len)); + if (vstr.len > value_len) { // this length includes trailing NUL + result = SETTINGS_ERR_LENGTH; + } + } + return result; +} + +static void print_error(const char *key, settings_err_t result) { + switch (result) { + case SETTINGS_OK: + case SETTINGS_ERR_OPEN: + case SETTINGS_ERR_NOT_FOUND: + // These errors need not be printed. + // The code asking for the value is not necessarily expecting to find one. + return; + default: + mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("An error occurred while retrieving '%s':\n"), key); + break; + } + + switch (result) { + case SETTINGS_ERR_UNICODE: + mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("Invalid unicode escape")); + break; + case SETTINGS_ERR_BAD_VALUE: + mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("Invalid format")); + break; + default: + mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("Internal error")); + break; + } + mp_printf(&mp_plat_print, "\n"); +} + + +static settings_err_t get_str(const char *key, char *value, size_t value_len) { + bool quoted; + settings_err_t result = settings_get_buf_terminated(key, value, value_len, "ed); + if (result == SETTINGS_OK && !quoted) { + result = SETTINGS_ERR_BAD_VALUE; + } + return result; +} + +settings_err_t settings_get_str(const char *key, char *value, size_t value_len) { + settings_err_t result = get_str(key, value, value_len); + print_error(key, result); + return result; +} + +static settings_err_t get_int(const char *key, mp_int_t *value) { + char buf[16]; + bool quoted; + settings_err_t result = settings_get_buf_terminated(key, buf, sizeof(buf), "ed); + if (result != SETTINGS_OK) { + return result; + } + if (quoted) { + return SETTINGS_ERR_BAD_VALUE; + } + char *end; + long num = strtol(buf, &end, 0); + while (unichar_isspace(*end)) { + end++; + } + if (end == buf || *end) { // If the whole buffer was not consumed it's an error + return SETTINGS_ERR_BAD_VALUE; + } + *value = (mp_int_t)num; + return SETTINGS_OK; +} + +settings_err_t settings_get_int(const char *key, mp_int_t *value) { + settings_err_t result = get_int(key, value); + print_error(key, result); + return result; +} + +static settings_err_t get_bool(const char *key, bool *value) { + char buf[16]; + bool quoted; + settings_err_t result = settings_get_buf_terminated(key, buf, sizeof(buf), "ed); + if (result != SETTINGS_OK) { + return result; + } + if (quoted) { + return SETTINGS_ERR_BAD_VALUE; + } + + // Check for "true" or "false" (case-sensitive) + if (strcmp(buf, "true") == 0) { + *value = true; + return SETTINGS_OK; + } else if (strcmp(buf, "false") == 0) { + *value = false; + return SETTINGS_OK; + } + + // Not a valid boolean value + return SETTINGS_ERR_BAD_VALUE; +} + +settings_err_t settings_get_bool(const char *key, bool *value) { + settings_err_t result = get_bool(key, value); + print_error(key, result); + return result; +} + +#if MICROPY_PY_BUILTINS_FLOAT +static settings_err_t get_float(const char *key, mp_float_t *value) { + char buf[48]; + bool quoted; + settings_err_t result = settings_get_buf_terminated(key, buf, sizeof(buf), "ed); + if (result != SETTINGS_OK) { + return result; + } + if (quoted) { + return SETTINGS_ERR_BAD_VALUE; + } + + const char *str = buf; + const char *end = buf + strlen(buf); + bool neg = false; + + if (str < end && (*str == '+' || *str == '-')) { + neg = (*str == '-'); + str++; + } + + mp_float_t val; + if (end - str >= 3 && str[0] == 'i' && str[1] == 'n' && str[2] == 'f') { + str += 3; + val = (mp_float_t)INFINITY; + } else if (end - str >= 3 && str[0] == 'n' && str[1] == 'a' && str[2] == 'n') { + str += 3; + val = MICROPY_FLOAT_C_FUN(nan)(""); + } else { + const char *num_start = str; + str = mp_parse_float_internal(str, end - str, &val); + if (str == NULL || str == num_start) { + return SETTINGS_ERR_BAD_VALUE; + } + } + + if (str != end) { + return SETTINGS_ERR_BAD_VALUE; + } + + *value = neg ? -val : val; + return SETTINGS_OK; +} + +settings_err_t settings_get_float(const char *key, mp_float_t *value) { + settings_err_t result = get_float(key, value); + print_error(key, result); + return result; +} +#endif + +// Get the raw value as a vstr, whether quoted or bare. Value may be an invalid TOML value. +settings_err_t settings_get_raw_vstr(const char *key, vstr_t *vstr) { + bool quoted; + return settings_get_vstr(key, vstr, "ed); +} + +settings_err_t settings_get_obj(const char *key, mp_obj_t *value) { + vstr_t vstr; + vstr_init(&vstr, 32); + bool quoted; + + settings_err_t result = settings_get_vstr(key, &vstr, "ed); + if (result != SETTINGS_OK) { + return result; + } + + if (quoted) { + // Successfully parsed a quoted string + *value = mp_obj_new_str_from_vstr(&vstr); + return SETTINGS_OK; + } + + // Not a quoted string, try boolean + bool bool_val; + result = get_bool(key, &bool_val); + if (result == SETTINGS_OK) { + *value = mp_obj_new_bool(bool_val); + return SETTINGS_OK; + } + + // Not a boolean, try integer + mp_int_t int_val; + result = get_int(key, &int_val); + if (result == SETTINGS_OK) { + *value = mp_obj_new_int(int_val); + return SETTINGS_OK; + } + + // Not an integer, try float + #if MICROPY_PY_BUILTINS_FLOAT + mp_float_t float_val; + result = get_float(key, &float_val); + if (result == SETTINGS_OK) { + *value = mp_obj_new_float(float_val); + return SETTINGS_OK; + } + #endif + + return SETTINGS_ERR_BAD_VALUE; +} + +#endif diff --git a/supervisor/shared/settings.h b/supervisor/shared/settings.h new file mode 100644 index 00000000000..6d92d45d79a --- /dev/null +++ b/supervisor/shared/settings.h @@ -0,0 +1,64 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +typedef enum { + SETTINGS_OK = 0, + // The settings file could not be opened. + SETTINGS_ERR_OPEN, + SETTINGS_ERR_UNICODE, + SETTINGS_ERR_LENGTH, + SETTINGS_ERR_NOT_FOUND, + SETTINGS_ERR_BAD_VALUE, +} settings_err_t; + +// Read a string value from the settings file. +// If it fits, the return value is 0-terminated. The passed-in buffer +// may be modified even if an error is returned. Allocation free. +// An error that is not SETTINGS_ERR_OPEN or SETTINGS_ERR_NOT_FOUND is printed on the repl. +// Returns an error if the value is not a quoted string. +settings_err_t settings_get_str(const char *key, char *value, size_t value_len); + +// Read an integer value from the settings file. +// Returns SETTINGS_OK and sets value to the read value. Returns +// SETTINGS_ERR_... if the value was not numeric. allocation-free. +// If any error code is returned, value is guaranteed not modified +// An error that is not 'open' or 'not found' is printed on the repl. +settings_err_t settings_get_int(const char *key, mp_int_t *value); + +// Read a boolean value from the settings file. +// Returns SETTINGS_OK and sets value to the read value. Returns +// SETTINGS_ERR_... if the value was not a boolean (true or false). allocation-free. +// If any error code is returned, value is guaranteed not modified +// An error that is not 'open' or 'not found' is printed on the repl. +settings_err_t settings_get_bool(const char *key, bool *value); + +#if MICROPY_PY_BUILTINS_FLOAT +// Read a float value from the settings file. +// Returns SETTINGS_OK and sets value to the read value. Returns +// SETTINGS_ERR_... if the value was not a float. allocation-free. +// If any error code is returned, value is guaranteed not modified. +// An error that is not SETTINGS_ERR_OPEN or SETTINGS_ERR_NOT_FOUND is printed on the repl. +settings_err_t settings_get_float(const char *key, mp_float_t *value); +#endif + +// Read a value from the settings file and return as parsed Python object. +// Returns SETTINGS_OK and sets value to a parsed Python object from the RHS value: +// - Quoted strings return as str +// - Bare "true" or "false" return as bool +// - Valid integers return as int +// - Valid floats (containing '.' or 'e'/'E') return as float +// Returns SETTINGS_ERR_... if the value is not parseable as one of these types. +// An error that is not SETTINGS_ERR_OPEN or SETTINGS_ERR_NOT_FOUND is printed on the repl. +settings_err_t settings_get_obj(const char *key, mp_obj_t *value); + +// Read the raw value as a string, whether quoted or bare. +// This is used by os.getenv() to always return strings. +// Does not print errors. +settings_err_t settings_get_raw_vstr(const char *key, vstr_t *vstr); diff --git a/supervisor/shared/status_bar.c b/supervisor/shared/status_bar.c index 8e32eee033e..3b6e00ef561 100644 --- a/supervisor/shared/status_bar.c +++ b/supervisor/shared/status_bar.c @@ -21,7 +21,7 @@ #include "supervisor/shared/web_workflow/web_workflow.h" #endif -#if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE +#if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE #include "supervisor/shared/bluetooth/bluetooth.h" #endif @@ -88,7 +88,7 @@ void supervisor_status_bar_update(void) { serial_write(" | "); #endif - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE supervisor_bluetooth_status(); serial_write(" | "); #endif @@ -119,7 +119,7 @@ static void status_bar_background(void *data) { dirty = dirty || supervisor_web_workflow_status_dirty(); #endif - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE dirty = dirty || supervisor_bluetooth_status_dirty(); #endif diff --git a/supervisor/shared/status_leds.c b/supervisor/shared/status_leds.c index ffe8b46b20b..ca29fd79212 100644 --- a/supervisor/shared/status_leds.c +++ b/supervisor/shared/status_leds.c @@ -133,9 +133,9 @@ void status_led_init(void) { memset(status_apa102_color + 4, 0xff, APA102_BUFFER_LENGTH - 4); #if CIRCUITPY_BITBANG_APA102 shared_module_bitbangio_spi_construct(&status_apa102, - MICROPY_HW_APA102_SCK, - MICROPY_HW_APA102_MOSI, - NULL); + MP_OBJ_FROM_PTR(MICROPY_HW_APA102_SCK), + MP_OBJ_FROM_PTR(MICROPY_HW_APA102_MOSI), + mp_const_none); #else if (!common_hal_busio_spi_deinited(&status_apa102)) { common_hal_busio_spi_deinit(&status_apa102); diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c index 346ef9a93c4..81815c0813b 100644 --- a/supervisor/shared/tick.c +++ b/supervisor/shared/tick.c @@ -27,6 +27,10 @@ #include "shared-module/keypad/__init__.h" #endif +#if CIRCUITPY_AUDIOFILEWRITER +#include "shared-module/audiofilewriter/AudioFileWriter.h" +#endif + #include "shared-bindings/microcontroller/__init__.h" #if CIRCUITPY_WATCHDOG @@ -59,6 +63,10 @@ static void supervisor_background_tick(void *unused) { filesystem_background(); + #if CIRCUITPY_AUDIOFILEWRITER + audiofilewriter_background(); + #endif + port_background_tick(); assert_heap_ok(); diff --git a/supervisor/shared/translate/compressed_string.h b/supervisor/shared/translate/compressed_string.h index 89dd75c22ae..7bfe2000b73 100644 --- a/supervisor/shared/translate/compressed_string.h +++ b/supervisor/shared/translate/compressed_string.h @@ -13,38 +13,41 @@ // The format of the compressed data is: // - the size of the uncompressed string in UTF-8 bytes, encoded as a // (compress_max_length_bits)-bit number. compress_max_length_bits is -// computed during dictionary generation time, and happens to be 8 -// for all current platforms. However, it'll probably end up being -// 9 in some translations sometime in the future. This length excludes +// computed during dictionary generation time, and is 8 for all +// current translations except ru, which needs 9. This length excludes // the trailing NUL, though notably decompress_length includes it. // -// - followed by the huffman encoding of the individual code -// points that make up the string. The trailing "\0" is not -// represented by a huffman code, but is implied by the length. -// (building the huffman encoding on UTF-16 code points gave better -// compression than building it on UTF-8 bytes) +// - followed by the huffman encoding of the symbols that make up the +// string. The trailing "\0" is not represented by a huffman code, but +// is implied by the length. // -// - If possible, the code points are represented as uint8_t values, with -// 0..127 representing themselves and 160..255 representing another range -// of Unicode, controlled by translation_offset and translation_offstart. -// If this is not possible, uint16_t values are used. At present, no translation -// requires code points not in the BMP, so this is adequate. +// - Each symbol is coded with one of TRANSLATION_CLASSES canonical Huffman +// tables, chosen by the class of the previously decoded byte: start of +// string or space, lowercase, uppercase, digit, '%', other, or >= 0x80. +// base_class() computes that seven-way class and class_map[] collapses it +// to a table index; the generator picks how many tables pay for themselves. +// The per-table code-length counts are rows of LENGTHS_ROW bytes in +// lengths[], and the symbols of table n are values[values_offset[n]..]. // -// - code points starting at 128 (word_start) and potentially extending -// to 255 (word_end) (but never interfering with the target -// language's used code points) stand for dictionary entries in a -// dictionary with size up to 256 code points. The dictionary entries -// are computed with a heuristic based on frequent substrings of 2 to -// 9 code points. These are called "words" but are not, grammatically -// speaking, words. They're just spans of code points that frequently -// occur together. They are ordered shortest to longest. +// - Symbol values 0..0x7F are ASCII (with 1, 2 and 3 reserved for the +// escapes below). Values from 0x80 up to 0x80 + alphabet_size - 1 are the +// most frequent non-ASCII characters used by the translation, renumbered +// by decreasing frequency; alphabet[] maps them back to Unicode code +// points. Most translations fit their whole non-ASCII repertoire in the +// alphabet. Those that don't (ja, ko) keep the 32 to 80 most frequent +// characters there and escape the rest: value 2 is followed by a +// rare_index_bits-bit index into rare_chars[] (characters used more than +// once), value 3 by a raw 16-bit code point (characters used once, which +// are cheaper without a table entry). All symbols are therefore 8 bits. +// At present, no translation requires code points outside the BMP, so +// this is adequate. // -// - If the translation uses a lot of code points or widely spaced code points, -// then the huffman table entries are UTF-16 code points. But if the translation -// uses only ASCII 7-bit code points plus a SMALL range of higher code points that -// still fit in 8 bits, translation_offset and translation_offstart are used to -// renumber the code points so that they still fit within 8 bits. (it's very beneficial -// for mchar_t to be 8 bits instead of 16!) +// - Symbol values from word_start to word_end stand for dictionary entries +// in a dictionary of up to 256 - word_start entries. The dictionary +// entries are computed with a heuristic based on frequent substrings of 2 +// to 11 symbols. These are called "words" but are not, grammatically +// speaking, words. They're just spans of symbols that frequently occur +// together. They are ordered shortest to longest. // // - dictionary entries are non-overlapping, and the _ending_ index of each // entry is stored in an array. A count of words of each length, from @@ -56,10 +59,11 @@ // - Value 1 ('\1') is used to indicate that a QSTR number follows. the // QSTR is encoded as a fixed number of bits (translation_qstr_bits), e.g., // 10 bits if the highest core qstr is from 512 to 1023 inclusive. -// (maketranslationdata uses a simple heuristic where any qstr >= 3 -// characters long is encoded in this way; this is simple but probably not -// optimal. In fact, the rule of >= 2 characters is better for SOME languages -// on SOME boards.) +// (maketranslationdata uses a simple heuristic where any qstr >= 4 +// characters long may be encoded in this way; whether a given occurrence +// is coded as a qstr or as characters is decided per occurrence by the +// parser, which picks the tokenization of each string that takes the +// fewest bits.) // // The "data" / "tail" construct is so that the struct's last member is a // "flexible array". However, the _only_ member is not permitted to be @@ -76,6 +80,26 @@ typedef struct compressed_string { const uint8_t tail[]; } const *mp_rom_error_text_t; +// Class of the previously decoded byte, which selects the Huffman table for +// the next symbol. Must match base_class() in py/maketranslationdata.py. +typedef enum { + CLASS_START_OR_SPACE = 0, + CLASS_LOWER = 1, + CLASS_UPPER = 2, + CLASS_DIGIT = 3, + CLASS_OTHER = 4, + CLASS_PERCENT = 5, + CLASS_NON_ASCII = 6, +} translation_class_t; + +// Symbol values with a special meaning; every other value is a character or a +// dictionary word. Must match py/maketranslationdata.py. +typedef enum { + SYMBOL_QSTR = 1, // followed by translation_qstr_bits bits of qstr index + SYMBOL_RARE_INDEX = 2, // followed by rare_index_bits bits of rare_chars[] index + SYMBOL_RARE_RAW = 3, // followed by a 16-bit code point +} translation_symbol_t; + // Return the compressed, translated version of a source string // Usually, due to LTO, this is optimized into a load of a constant // pointer. diff --git a/supervisor/shared/translate/translate.c b/supervisor/shared/translate/translate.c index 958e0a2144f..d0c05dda6e5 100644 --- a/supervisor/shared/translate/translate.c +++ b/supervisor/shared/translate/translate.c @@ -23,7 +23,7 @@ void serial_write_compressed(mp_rom_error_text_t compressed) { mp_printf(MP_PYTHON_PRINTER, "%S", compressed); } -static void get_word(int n, const mchar_t **pos, const mchar_t **end) { +static void get_word(int n, const uint8_t **pos, const uint8_t **end) { int len = minlen; int i = 0; *pos = words; @@ -37,14 +37,10 @@ static void get_word(int n, const mchar_t **pos, const mchar_t **end) { *end = *pos + len; } -static void put_utf8(vstr_t *vstr, int u) { - if (u >= translation_offstart) { - u += translation_offset; - } +static void put_utf8(vstr_t *vstr, unsigned u) { if (word_start <= u && u <= word_end) { - uint n = (u - word_start); - const mchar_t *pos, *end; - get_word(n, &pos, &end); + const uint8_t *pos, *end; + get_word(u - word_start, &pos, &end); // note that at present, entries in the words table are // guaranteed not to represent words themselves, so this adds // at most 1 level of recursive call @@ -53,9 +49,39 @@ static void put_utf8(vstr_t *vstr, int u) { } return; } + // alphabet_size is a compile-time constant; the test folds away when it is 0. + if (alphabet_size > 0 && u >= 0x80 && u < 0x80 + alphabet_size) { + u = alphabet[u - 0x80]; + } vstr_add_char(vstr, u); } +// The Huffman table used for the next symbol depends on the class of the last +// byte written. Classifying the last byte is the same as classifying the last +// code point: every byte of a multi-byte UTF-8 sequence is >= 0x80. +// This must match base_class() in py/maketranslationdata.py. +static translation_class_t base_class(uint8_t last) { + if (last == ' ') { + return CLASS_START_OR_SPACE; + } + if (last >= 'a' && last <= 'z') { + return CLASS_LOWER; + } + if (last >= 'A' && last <= 'Z') { + return CLASS_UPPER; + } + if (last >= '0' && last <= '9') { + return CLASS_DIGIT; + } + if (last == '%') { + return CLASS_PERCENT; + } + if (last >= 0x80) { + return CLASS_NON_ASCII; + } + return CLASS_OTHER; +} + uint16_t decompress_length(mp_rom_error_text_t compressed) { #ifndef NO_QSTR #if (compress_max_length_bits <= 8) @@ -99,23 +125,34 @@ static void decompress_vstr(mp_rom_error_text_t compressed, vstr_t *decompressed size_t alloc = decompressed->alloc - 1; // Stop one early because the last byte is always NULL. for (; decompressed->len < alloc;) { + // The start of a string is classed like a space. + uint8_t last = decompressed->len ? (uint8_t)decompressed->buf[decompressed->len - 1] : ' '; + uint8_t cls = class_map[base_class(last)]; + const uint8_t *len_row = lengths + cls * LENGTHS_ROW; + uint32_t bits = 0; uint8_t bit_length = 0; - uint32_t max_code = lengths[0]; - uint32_t searched_length = lengths[0]; + uint32_t max_code = len_row[0]; + uint32_t searched_length = len_row[0]; while (true) { bits = (bits << 1) | next_bit(&b); bit_length += 1; if (max_code > 0 && bits < max_code) { break; } - max_code = (max_code << 1) + lengths[bit_length]; - searched_length += lengths[bit_length]; + max_code = (max_code << 1) + len_row[bit_length]; + searched_length += len_row[bit_length]; } - int v = values[searched_length + bits - max_code]; - if (v == 1) { - qstr q = get_nbits(&b, translation_qstr_bits) + 1; // honestly no idea why "+1"... + unsigned v = values[values_offset[cls] + searched_length + bits - max_code]; + if (v == SYMBOL_QSTR) { + qstr q = get_nbits(&b, translation_qstr_bits); vstr_add_str(decompressed, qstr_str(q)); + } else if (rare_index_count > 0 && v == SYMBOL_RARE_INDEX) { + // A non-ASCII character outside the dense alphabet, by table index. + vstr_add_char(decompressed, rare_chars[get_nbits(&b, rare_index_bits)]); + } else if (rare_raw_count > 0 && v == SYMBOL_RARE_RAW) { + // A non-ASCII character used only once, as a raw code point. + vstr_add_char(decompressed, get_nbits(&b, 16)); } else { put_utf8(decompressed, v); } diff --git a/supervisor/shared/usb.c b/supervisor/shared/usb.c new file mode 100644 index 00000000000..3aa24e62675 --- /dev/null +++ b/supervisor/shared/usb.c @@ -0,0 +1,73 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/usb.h" + +#if CIRCUITPY_STORAGE +#include "shared-module/storage/__init__.h" +#endif + +#if CIRCUITPY_USB_DEVICE +#include "shared-bindings/supervisor/__init__.h" + +#if CIRCUITPY_USB_CDC +#include "shared-module/usb_cdc/__init__.h" +#endif + +#if CIRCUITPY_USB_HID +#include "shared-module/usb_hid/__init__.h" +#endif + +#if CIRCUITPY_USB_MIDI +#include "shared-module/usb_midi/__init__.h" +#endif + +#if CIRCUITPY_USB_AUDIO +#include "shared-module/usb_audio/__init__.h" +#endif + +#if CIRCUITPY_USB_VIDEO +#include "shared-module/usb_video/__init__.h" +#endif +#endif + +// Set up USB defaults before any USB changes are made in boot.py +void usb_set_defaults(void) { + #if CIRCUITPY_USB_DEVICE + #if CIRCUITPY_STORAGE && CIRCUITPY_USB_MSC + storage_usb_set_defaults(); + #endif + + #if CIRCUITPY_USB_CDC + usb_cdc_set_defaults(); + #endif + + #if CIRCUITPY_USB_HID + usb_hid_set_defaults(); + #endif + + #if CIRCUITPY_USB_MIDI + usb_midi_set_defaults(); + #endif + #endif +}; + +// Call this when ready to run code.py or a REPL, and a VM has been started. +void usb_setup_with_vm(void) { + #if CIRCUITPY_USB_DEVICE + #if CIRCUITPY_USB_HID + usb_hid_setup_devices(); + #endif + + #if CIRCUITPY_USB_MIDI + usb_midi_setup_ports(); + #endif + + #if CIRCUITPY_USB_AUDIO + usb_audio_setup_singletons(); + #endif + #endif +} diff --git a/supervisor/shared/usb/host_keyboard.c b/supervisor/shared/usb/host_keyboard.c index f99b1e5c42a..de4f719d175 100644 --- a/supervisor/shared/usb/host_keyboard.c +++ b/supervisor/shared/usb/host_keyboard.c @@ -28,6 +28,14 @@ static uint8_t _buf[16]; static uint8_t _dev_addr; static uint8_t _interface; +// A keyboard interface that is not boot-protocol, detected at mount time from +// its report descriptor. Composite HID devices (CircuitPython's usb_hid among +// them) present bInterfaceProtocol NONE and prefix each report with a report +// ID, so they fail the boot-protocol check in usb_keyboard_attach(). +static uint8_t _report_kbd_dev_addr; +static uint8_t _report_kbd_interface; +static uint8_t _report_kbd_report_id; + #define FLAG_SHIFT (1) #define FLAG_NUMLOCK (2) #define FLAG_CTRL (4) @@ -298,7 +306,12 @@ static void process_event(uint8_t dev_addr, uint8_t instance, const hid_keyboard uint8_t leds = (caps | (num << 1)); if (leds != old_report.reserved) { - tuh_hid_set_report(dev_addr, instance /*idx*/, 0 /*report_id*/, HID_REPORT_TYPE_OUTPUT /*report_type*/, &leds, sizeof(leds)); + // A report-protocol keyboard needs its report ID on the LED output report too. + uint8_t report_id = 0; + if (dev_addr == _report_kbd_dev_addr && instance == _report_kbd_interface) { + report_id = _report_kbd_report_id; + } + tuh_hid_set_report(dev_addr, instance /*idx*/, report_id, HID_REPORT_TYPE_OUTPUT /*report_type*/, &leds, sizeof(leds)); } old_report = *report; old_report.reserved = leds; @@ -326,7 +339,11 @@ void usb_keyboard_attach(uint8_t dev_addr, uint8_t interface) { return; } uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, interface); - if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) { + bool is_boot_keyboard = itf_protocol == HID_ITF_PROTOCOL_KEYBOARD; + // Detected at mount time by tuh_hid_mount_cb(). Device addresses start at + // 1, so a zeroed _report_kbd_dev_addr never matches. + bool is_report_keyboard = dev_addr == _report_kbd_dev_addr && interface == _report_kbd_interface; + if (is_boot_keyboard || is_report_keyboard) { _dev_addr = dev_addr; _interface = interface; tuh_hid_receive_report(dev_addr, interface); @@ -335,20 +352,52 @@ void usb_keyboard_attach(uint8_t dev_addr, uint8_t interface) { } void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t interface, uint8_t const *desc_report, uint16_t desc_len) { + // A non-boot interface can still be a keyboard, using report protocol. + // Find keyboard usage in its report descriptor so that we poll it too. + // Otherwise its interrupt IN endpoint is never drained, and a CircuitPython + // device plugged into us raises OSError("USB busy") on its second + // send_report() (#10721). + if (tuh_hid_interface_protocol(dev_addr, interface) == HID_ITF_PROTOCOL_NONE && + _report_kbd_dev_addr == 0) { + tuh_hid_report_info_t report_info[8]; + uint8_t report_count = + tuh_hid_parse_report_descriptor(report_info, TU_ARRAY_SIZE(report_info), desc_report, desc_len); + for (uint8_t i = 0; i < report_count; i++) { + if (report_info[i].usage_page == HID_USAGE_PAGE_DESKTOP && + report_info[i].usage == HID_USAGE_DESKTOP_KEYBOARD) { + _report_kbd_dev_addr = dev_addr; + _report_kbd_interface = interface; + _report_kbd_report_id = report_info[i].report_id; + break; + } + } + } usb_keyboard_attach(dev_addr, interface); } void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t interface) { + if (dev_addr == _report_kbd_dev_addr && interface == _report_kbd_interface) { + _report_kbd_dev_addr = 0; + _report_kbd_interface = 0; + _report_kbd_report_id = 0; + } usb_keyboard_detach(dev_addr, interface); } void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { - if (len != sizeof(hid_keyboard_report_t)) { - return; - } else { + if (len == sizeof(hid_keyboard_report_t)) { process_event(dev_addr, instance, (hid_keyboard_report_t *)report); + } else if (dev_addr == _report_kbd_dev_addr && instance == _report_kbd_interface && + _report_kbd_report_id != 0 && + len == sizeof(hid_keyboard_report_t) + 1 && + report[0] == _report_kbd_report_id) { + // Report-protocol keyboards prefix the report with its report ID. + process_event(dev_addr, instance, (const hid_keyboard_report_t *)(report + 1)); } - // continue to request to receive report + // Always request the next report, even when this one wasn't a keyboard + // report we understand (a mouse or consumer control report ID from a + // composite device, for instance), so that the device's endpoint keeps + // draining and polling doesn't stop. tuh_hid_receive_report(dev_addr, instance); } diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index ac2fd9f4f25..ac63542b8e4 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -79,18 +79,16 @@ extern "C" { #if CIRCUITPY_USB_DEVICE -#if CIRCUITPY_USB_DEVICE_INSTANCE == 0 -#if USB_HIGHSPEED -#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) +#if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 +#define _DEVICE_SPEED OPT_MODE_HIGH_SPEED #else -#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE) +#define _DEVICE_SPEED 0 #endif + +#if CIRCUITPY_USB_DEVICE_INSTANCE == 0 +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | _DEVICE_SPEED) #elif CIRCUITPY_USB_DEVICE_INSTANCE == 1 -#if USB_HIGHSPEED -#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) -#else -#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE) -#endif +#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | _DEVICE_SPEED) #endif // Use DMA with the USB peripheral. @@ -117,8 +115,33 @@ extern "C" { #define CFG_TUD_HID CIRCUITPY_USB_HID #define CFG_TUD_MIDI CIRCUITPY_USB_MIDI #define CFG_TUD_VENDOR CIRCUITPY_USB_VENDOR +#define CFG_TUD_AUDIO CIRCUITPY_USB_AUDIO #define CFG_TUD_CUSTOM_CLASS 0 +// ------------- AUDIO CLASS (UAC2 microphone) -------------// +#if CIRCUITPY_USB_AUDIO +#include "shared-module/usb_audio/usb_audio_descriptors.h" + +// EP0 buffer for class-specific control requests (sample-freq range, volume range, ...). +#define CFG_TUD_AUDIO_CTRL_BUF_SZ 64 + +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 +// wMaxPacketSize, sized for the highest supported sample rate. +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +// Deep software FIFO so the 1 ms refill keeps clear of the underrun floor. +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) + +// OUT endpoint (host -> board speaker). Compiled into the class driver +// unconditionally; whether it actually enumerates is decided by the emitted +// descriptor (still mic-only until the speaker descriptor lands). Mirrors the +// IN sizing above. +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 +// wMaxPacketSize, sized for the highest supported sample rate. +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +// Deep software FIFO so the 1 ms drain keeps clear of the overrun ceiling. +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) +#endif + /*------------------------------------------------------------------*/ /* CLASS DRIVER *------------------------------------------------------------------*/ @@ -157,18 +180,16 @@ extern "C" { #define CFG_TUH_RPI_PIO_USB 1 #endif -#if CIRCUITPY_USB_HOST_INSTANCE == 0 -#if USB_HIGHSPEED -#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) +#if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 +#define _HOST_SPEED OPT_MODE_HIGH_SPEED #else -#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST) +#define _HOST_SPEED 0 #endif + +#if CIRCUITPY_USB_HOST_INSTANCE == 0 +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | _HOST_SPEED) #elif CIRCUITPY_USB_HOST_INSTANCE == 1 -#if USB_HIGHSPEED -#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) -#else -#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST) -#endif +#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | _HOST_SPEED) #endif // Size of buffer to hold descriptors and other data used for enumeration diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index e67c15d022c..51222be0e59 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -7,6 +7,7 @@ #include "py/objstr.h" #include "supervisor/background_callback.h" #include "supervisor/linker.h" +#include "supervisor/port.h" #include "supervisor/shared/tick.h" #include "supervisor/usb.h" #include "shared/readline/readline.h" @@ -38,6 +39,10 @@ #include "shared-module/usb_video/__init__.h" #endif +#if CIRCUITPY_USB_AUDIO +#include "shared-module/usb_audio/__init__.h" +#endif + #endif #include "tusb.h" @@ -87,6 +92,14 @@ bool usb_enabled(void) { return tusb_inited(); } +bool usb_connected(void) { + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE + return tud_ready(); + #else + return false; + #endif +} + MP_WEAK void post_usb_init(void) { } @@ -144,40 +157,6 @@ void usb_init(void) { #endif } -// Set up USB defaults before any USB changes are made in boot.py -void usb_set_defaults(void) { - #if CIRCUITPY_USB_DEVICE - #if CIRCUITPY_STORAGE && CIRCUITPY_USB_MSC - storage_usb_set_defaults(); - #endif - - #if CIRCUITPY_USB_CDC - usb_cdc_set_defaults(); - #endif - - #if CIRCUITPY_USB_HID - usb_hid_set_defaults(); - #endif - - #if CIRCUITPY_USB_MIDI - usb_midi_set_defaults(); - #endif - #endif -}; - -// Call this when ready to run code.py or a REPL, and a VM has been started. -void usb_setup_with_vm(void) { - #if CIRCUITPY_USB_DEVICE - #if CIRCUITPY_USB_HID - usb_hid_setup_devices(); - #endif - - #if CIRCUITPY_USB_MIDI - usb_midi_setup_ports(); - #endif - #endif -} - void usb_background(void) { if (usb_enabled()) { #if CFG_TUSB_OS == OPT_OS_NONE || CFG_TUSB_OS == OPT_OS_PICO @@ -186,9 +165,8 @@ void usb_background(void) { tuh_task(); #endif #elif CFG_TUSB_OS == OPT_OS_FREERTOS - // Yield to FreeRTOS in case TinyUSB runs in a separate task. Don't use - // port_yield() because it has a longer delay. - vTaskDelay(0); + // TinyUSB may run in a separate task, at the same priority as CircuitPython. + port_task_yield(); #endif // No need to flush if there's no REPL. #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC @@ -200,10 +178,16 @@ void usb_background(void) { #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VIDEO usb_video_task(); #endif + #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_AUDIO + usb_audio_task(); + #endif } } -uint32_t tusb_time_millis_api(void) { +// Ports may override this with a RAM-resident version when TinyUSB code that +// calls it must not execute from flash (e.g. raspberrypi polls +// tuh_task_event_ready(), which calls this, from core1). +MP_WEAK uint32_t tusb_time_millis_api(void) { return supervisor_ticks_ms32(); } diff --git a/supervisor/shared/usb/usb_desc.c b/supervisor/shared/usb/usb_desc.c index 9427171fe9b..7a0bc4686bb 100644 --- a/supervisor/shared/usb/usb_desc.c +++ b/supervisor/shared/usb/usb_desc.c @@ -32,6 +32,10 @@ #include "shared-module/usb_video/__init__.h" #endif +#if CIRCUITPY_USB_AUDIO +#include "shared-module/usb_audio/__init__.h" +#endif + #include "shared-bindings/microcontroller/Processor.h" @@ -170,6 +174,12 @@ static bool usb_build_configuration_descriptor(void) { } #endif + #if CIRCUITPY_USB_AUDIO + if (usb_audio_enabled()) { + total_descriptor_length += usb_audio_descriptor_length(); + } + #endif + // Now we know how big the configuration descriptor will be, so we can allocate space for it. configuration_descriptor = (uint8_t *)port_malloc(total_descriptor_length, @@ -259,6 +269,13 @@ static bool usb_build_configuration_descriptor(void) { descriptor_buf_remaining, &descriptor_counts, ¤t_interface_string); } #endif + + #if CIRCUITPY_USB_AUDIO + if (usb_audio_enabled()) { + descriptor_buf_remaining += usb_audio_add_descriptor( + descriptor_buf_remaining, &descriptor_counts, ¤t_interface_string); + } + #endif // Now we know how many interfaces have been used. configuration_descriptor[CONFIG_NUM_INTERFACES_INDEX] = descriptor_counts.current_interface; diff --git a/supervisor/shared/usb/usb_device.c b/supervisor/shared/usb/usb_device.c index ec08b8bf4d7..e3f1a0d4e26 100644 --- a/supervisor/shared/usb/usb_device.c +++ b/supervisor/shared/usb/usb_device.c @@ -156,7 +156,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ // size. Setting CFG_TUD_CDC_RX_BUFSIZE to the endpoint size and then sending // any character will prevent ctrl-c from working. Require at least a 64 // character buffer. -#if CFG_TUD_CDC_RX_BUFSIZE < CFG_TUD_CDC_EP_BUFSIZE + 64 +#if CFG_TUD_CDC_RX_BUFSIZE < CFG_TUD_CDC_RX_EPSIZE + 64 #error "CFG_TUD_CDC_RX_BUFSIZE must be 64 bytes bigger than endpoint size." #endif @@ -166,6 +166,9 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ * @param wanted_char The wanted char (set previously) */ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { + // CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB on ESP. + // So, we must notify the other task when a CTRL-C is received. + port_wake_main_task(); // Workaround for using shared/runtime/interrupt_char.c // Compare mp_interrupt_char with wanted_char and ignore if not matched if (mp_interrupt_char == wanted_char) { @@ -177,7 +180,14 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) { if (usb_cdc_console_enabled() && mp_interrupt_char != -1 && itf == 0 && duration_ms > 0) { mp_sched_keyboard_interrupt(); + port_wake_main_task(); } } +void tud_cdc_rx_cb(uint8_t itf) { + (void)itf; + // Workaround for "press any key to enter REPL" response being delayed on espressif. + // Wake main task when any key is pressed. + port_wake_main_task(); +} #endif diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index febede876bb..5fcd2c8d62b 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -5,7 +5,6 @@ // SPDX-License-Identifier: MIT #include "tusb.h" -// // #include "supervisor/flash.h" // For updating fatfs's cache #include "extmod/vfs.h" @@ -14,10 +13,12 @@ #include "lib/oofatfs/ff.h" #include "py/gc.h" #include "py/mpstate.h" +#include "py/runtime.h" #include "shared-module/storage/__init__.h" #include "supervisor/filesystem.h" #include "supervisor/shared/reload.h" +#include "supervisor/shared/settings.h" #define MSC_FLASH_BLOCK_SIZE 512 @@ -28,7 +29,7 @@ #define SAVES_COUNT 0 #endif -#if CIRCUITPY_SDCARDIO +#if CIRCUITPY_SDCARD_USB #include "shared-module/sdcardio/__init__.h" #define SDCARD_COUNT 1 @@ -37,7 +38,16 @@ #define SDCARD_COUNT 0 #endif -#define LUN_COUNT (1 + SAVES_COUNT + SDCARD_COUNT) +#if CIRCUITPY_EMMC_USB +#include "shared-module/emmcio/__init__.h" + +#define EMMC_COUNT 1 +#define EMMC_LUN (1 + SAVES_COUNT + SDCARD_COUNT) +#else +#define EMMC_COUNT 0 +#endif + +#define LUN_COUNT (1 + SAVES_COUNT + SDCARD_COUNT + EMMC_COUNT) // The ellipsis range in the designated initializer of `ejected` is not standard C, // but it works in both gcc and clang. @@ -72,7 +82,7 @@ static const uint8_t usb_msc_descriptor_template[] = { 0xFF, // 11 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number] #define MSC_IN_ENDPOINT_INDEX (11) 0x02, // 12 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 13,14 wMaxPacketSize 512 #else 0x40, 0x00, // 13,14 wMaxPacketSize 64 @@ -85,7 +95,7 @@ static const uint8_t usb_msc_descriptor_template[] = { 0xFF, // 18 bEndpointAddress (OUT/H2D) [SET AT RUNTIME] #define MSC_OUT_ENDPOINT_INDEX (18) 0x02, // 19 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 20,21 wMaxPacketSize 512 #else 0x40, 0x00, // 20,21 wMaxPacketSize 64 @@ -137,7 +147,8 @@ static fs_user_mount_t *get_vfs(int lun) { if (lun == SAVES_LUN) { const char *path_under_mount; fs_user_mount_t *saves = filesystem_for_path("/saves", &path_under_mount); - if (saves != root && (saves->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0 && !gc_ptr_on_heap(saves)) { + if (saves != root && + (saves->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0 && !gc_ptr_on_heap(saves)) { return saves; } } @@ -146,8 +157,15 @@ static fs_user_mount_t *get_vfs(int lun) { if (lun == SDCARD_LUN) { const char *path_under_mount; fs_user_mount_t *sdcard = filesystem_for_path("/sd", &path_under_mount); - // If "/sd" is on the root filesystem, nothing has been mounted there. - if (sdcard != root && (sdcard->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0) { + // If sdcard ("/sd") is on the root filesystem, nothing has been mounted there, so don't + // return it as a separate filesystem. + // If the SD card was automounted at startup, then it persists across VMs and its fs_user_mount_t is + // not on the heap. + // If the SD card filesystem was mounted by the user using heap objects, + // it should not be used when the VM has stopped running. + if ((sdcard != root) && + ((sdcard->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0) && + (vm_is_running() || !gc_ptr_on_heap(sdcard))) { return sdcard; } else { // Clear any ejected state so that a re-insert causes it to reappear. @@ -156,6 +174,26 @@ static fs_user_mount_t *get_vfs(int lun) { } } #endif + #ifdef EMMC_LUN + if (lun == EMMC_LUN) { + const char *path_under_mount; + + fs_user_mount_t *emmc = filesystem_for_path(CIRCUITPY_EMMC_MOUNT_PATH, &path_under_mount); + // Unlike the SD card there is no heap-mount case to allow: the eMMC's + // drive exists only when the supervisor mounted it, and + // that mount is static. A user mount made by code.py stays a Python + // filesystem and never becomes a LUN. + if (emmc != root && + ((emmc->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0) && + !gc_ptr_on_heap(emmc)) { + return emmc; + } else { + // Clear any ejected state so that a remount causes it to reappear. + ejected[EMMC_LUN] = false; + locked[EMMC_LUN] = false; + } + } + #endif return NULL; } @@ -196,20 +234,25 @@ uint8_t tud_msc_get_maxlun_cb(void) { return LUN_COUNT; } +// PREVENT ALLOW MEDIUM REMOVAL: TinyUSB routes this to its own dedicated callback, +// NOT tud_msc_scsi_cb. Reply unsupported on all LUNs so the host keeps TUR polling +// on every LUN — eject/storage.remount() works uniformly across CIRCUITPY, SAVES, SD. +bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control) { + (void)prohibit_removal; + (void)control; + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + return false; +} + // Callback invoked when received an SCSI command not in built-in list below // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE -// - READ10 and WRITE10 have their own callbacks +// - PREVENT_ALLOW_MEDIUM_REMOVAL, READ10, WRITE10 have their own callbacks int32_t tud_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer, uint16_t bufsize) { // Note that no command uses a response right now. const void *response = NULL; int32_t resplen = 0; switch (scsi_cmd[0]) { - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - // Host is about to read/write etc ... better not to disconnect disk - resplen = 0; - break; - default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); @@ -352,6 +395,33 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16 memcpy(product_rev, CFG_TUD_MSC_PRODUCT_REV, strlen(CFG_TUD_MSC_PRODUCT_REV)); } +#ifdef SDCARD_LUN +#if CIRCUITPY_SETTINGS_TOML +typedef enum { + SDCARD_USB_SETTING_NOT_YET_READ = 0, + SDCARD_USB_SETTING_TRUE, + SDCARD_USB_SETTING_FALSE, +} sdcard_usb_setting_state_t; + +static sdcard_usb_setting_state_t _sdcard_usb_setting_state = SDCARD_USB_SETTING_NOT_YET_READ; + +// Read only once to save file access time. +static bool sdcard_usb_enabled(void) { + if (_sdcard_usb_setting_state == SDCARD_USB_SETTING_NOT_YET_READ) { + // Can be changed per board. Most boards would leave this as true (default in circuitpy_mpconfig.h). + bool setting = CIRCUITPY_SDCARD_USB_DEFAULT; + (void)settings_get_bool("CIRCUITPY_SDCARD_USB", &setting); + _sdcard_usb_setting_state = setting ? SDCARD_USB_SETTING_TRUE : SDCARD_USB_SETTING_FALSE; + } + return _sdcard_usb_setting_state == SDCARD_USB_SETTING_TRUE; +} +#else +static bool sdcard_usb_enabled(void) { + return CIRCUITPY_SDCARD_USB; +} +#endif +#endif + // Invoked when received Test Unit Ready command. // return true allowing host to read/write this LUN e.g SD card inserted bool tud_msc_test_unit_ready_cb(uint8_t lun) { @@ -359,17 +429,16 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { return false; } - #if CIRCUITPY_SDCARD_USB - if (lun == SDCARD_LUN) { - automount_sd_card(); - } - #endif - fs_user_mount_t *current_mount = get_vfs(lun); if (current_mount == NULL) { return false; } - if (ejected[lun] || eject_once[lun]) { + + if (ejected[lun] || eject_once[lun] || (lun == 0 && !storage_usb_enabled()) + #ifdef SDCARD_LUN + || (lun == SDCARD_LUN && !sdcard_usb_enabled()) + #endif + ) { eject_once[lun] = false; // Set 0x3a for media not present. tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index eea11bd5fb4..be352d6c0b3 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -8,6 +8,8 @@ #define _GNU_SOURCE #include +#include +#include #include #include "extmod/vfs.h" @@ -42,12 +44,16 @@ #include "shared-bindings/socketpool/Socket.h" #include "shared-bindings/socketpool/SocketPool.h" +#if CIRCUITPY_HOSTNETWORK +#include "bindings/hostnetwork/__init__.h" +#endif + #if CIRCUITPY_WIFI #include "shared-bindings/wifi/__init__.h" #endif -#if CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif enum request_state { @@ -84,12 +90,18 @@ typedef struct { char websocket_key[24 + 1]; } _request; +#if CIRCUITPY_WIFI static wifi_radio_error_t _wifi_status = WIFI_RADIO_ERROR_NONE; +#endif -#if CIRCUITPY_STATUS_BAR +#if CIRCUITPY_STATUS_BAR && (CIRCUITPY_WIFI || CIRCUITPY_HOSTNETWORK) // Store various last states to compute if status bar needs an update. static bool _last_enabled = false; static uint32_t _last_ip = 0; +static mp_int_t _last_web_api_port = 80; +#endif + +#if CIRCUITPY_STATUS_BAR && CIRCUITPY_WIFI static wifi_radio_error_t _last_wifi_status = WIFI_RADIO_ERROR_NONE; #endif @@ -171,11 +183,7 @@ static bool _base64_in_place(char *buf, size_t in_len, size_t out_len) { return true; } -static void _update_encoded_ip(void) { - uint32_t ipv4_address = 0; - if (common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { - ipv4_address = wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj); - } +static void _update_encoded_ip(uint32_t ipv4_address) { if (_encoded_ip != ipv4_address) { uint8_t *octets = (uint8_t *)&ipv4_address; snprintf(_our_ip_encoded, sizeof(_our_ip_encoded), "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); @@ -183,75 +191,127 @@ static void _update_encoded_ip(void) { } } +static bool _get_web_workflow_ip(uint32_t *ipv4_address) { + *ipv4_address = 0; + #if CIRCUITPY_WIFI + if (!common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { + return false; + } + *ipv4_address = wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj); + return true; + #elif CIRCUITPY_HOSTNETWORK + // hostnetwork uses the host network namespace and is reachable via localhost. + *ipv4_address = 0x0100007f; // 127.0.0.1 + return true; + #else + return false; + #endif +} + +#if CIRCUITPY_STATUS_BAR +static void _print_web_workflow_endpoint(void) { + mp_printf(&mp_plat_print, "%s", _our_ip_encoded); + if (web_api_port != 80) { + mp_printf(&mp_plat_print, ":%d", web_api_port); + } +} +#endif + mdns_server_obj_t *supervisor_web_workflow_mdns(mp_obj_t network_interface) { - #if CIRCUITPY_MDNS + #if CIRCUITPY_MDNS && CIRCUITPY_WIFI if (network_interface == &common_hal_wifi_radio_obj && mdns.base.type == &mdns_server_type) { return &mdns; } #endif + (void)network_interface; return NULL; } #if CIRCUITPY_STATUS_BAR bool supervisor_web_workflow_status_dirty(void) { - return common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj) != _last_enabled || - _encoded_ip != _last_ip || - _last_wifi_status != _wifi_status; + #if CIRCUITPY_WIFI || CIRCUITPY_HOSTNETWORK + uint32_t ipv4_address = 0; + bool enabled = _get_web_workflow_ip(&ipv4_address); + if (enabled != _last_enabled || ipv4_address != _last_ip || web_api_port != _last_web_api_port) { + return true; + } + #if CIRCUITPY_WIFI + if (_last_wifi_status != _wifi_status) { + return true; + } + #endif + return false; + #else + return false; + #endif } #endif #if CIRCUITPY_STATUS_BAR void supervisor_web_workflow_status(void) { - _last_enabled = common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj); + #if CIRCUITPY_WIFI || CIRCUITPY_HOSTNETWORK + uint32_t ipv4_address = 0; + _last_enabled = _get_web_workflow_ip(&ipv4_address); + _last_web_api_port = web_api_port; + if (_last_enabled) { - uint32_t ipv4_address = wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj); + _update_encoded_ip(ipv4_address); + _last_ip = _encoded_ip; + if (ipv4_address != 0) { - _update_encoded_ip(); - _last_ip = _encoded_ip; - mp_printf(&mp_plat_print, "%s", _our_ip_encoded); - if (web_api_port != 80) { - mp_printf(&mp_plat_print, ":%d", web_api_port); - } + _print_web_workflow_endpoint(); // TODO: Use these unicode to show signal strength: ▂▄▆█ return; } - serial_write_compressed(MP_ERROR_TEXT("Wi-Fi: ")); - _last_wifi_status = _wifi_status; - if (_wifi_status == WIFI_RADIO_ERROR_AUTH_EXPIRE || - _wifi_status == WIFI_RADIO_ERROR_AUTH_FAIL) { - serial_write_compressed(MP_ERROR_TEXT("Authentication failure")); - } else if (_wifi_status != WIFI_RADIO_ERROR_NONE) { - mp_printf(&mp_plat_print, "%d", _wifi_status); - } else if (ipv4_address == 0) { - _last_ip = 0; - serial_write_compressed(MP_ERROR_TEXT("No IP")); - } else { - } - } else { - // Keep Wi-Fi print separate so its data can be matched with the one above. - serial_write_compressed(MP_ERROR_TEXT("Wi-Fi: ")); + } + + #if CIRCUITPY_WIFI + serial_write_compressed(MP_ERROR_TEXT("Wi-Fi: ")); + _last_wifi_status = _wifi_status; + if (!_last_enabled) { serial_write_compressed(MP_ERROR_TEXT("off")); + } else if (_wifi_status == WIFI_RADIO_ERROR_AUTH_EXPIRE || + _wifi_status == WIFI_RADIO_ERROR_AUTH_FAIL) { + serial_write_compressed(MP_ERROR_TEXT("Authentication failure")); + } else if (_wifi_status != WIFI_RADIO_ERROR_NONE) { + mp_printf(&mp_plat_print, "%d", _wifi_status); + } else { + _last_ip = 0; + serial_write_compressed(MP_ERROR_TEXT("No IP")); } + #endif + #else + return; + #endif } #endif bool supervisor_start_web_workflow(void) { - #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_OS_GETENV + #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_SETTINGS_TOML && (CIRCUITPY_WIFI || CIRCUITPY_HOSTNETWORK) + + #if CIRCUITPY_WIFI + mp_obj_t socketpool_radio = MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj); + #else + mp_obj_t socketpool_radio = MP_OBJ_FROM_PTR(&common_hal_hostnetwork_obj); + #endif + + settings_err_t result; + #if CIRCUITPY_WIFI char ssid[33]; char password[64]; - os_getenv_err_t result = common_hal_os_getenv_str("CIRCUITPY_WIFI_SSID", ssid, sizeof(ssid)); - if (result != GETENV_OK || strlen(ssid) < 1) { + result = settings_get_str("CIRCUITPY_WIFI_SSID", ssid, sizeof(ssid)); + if (result != SETTINGS_OK || strlen(ssid) < 1) { return false; } - result = common_hal_os_getenv_str("CIRCUITPY_WIFI_PASSWORD", password, sizeof(password)); - if (result == GETENV_ERR_NOT_FOUND) { + result = settings_get_str("CIRCUITPY_WIFI_PASSWORD", password, sizeof(password)); + if (result == SETTINGS_ERR_NOT_FOUND) { // if password is unspecified, assume an open network password[0] = '\0'; - } else if (result != GETENV_OK) { + } else if (result != SETTINGS_OK) { return false; } @@ -275,31 +335,29 @@ bool supervisor_start_web_workflow(void) { common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, false); return false; } + #endif - // Skip starting the workflow if we're not starting from power on or reset. + // Skip starting the workflow if the reset reason reflects a problem. const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); - if (reset_reason != RESET_REASON_POWER_ON && - reset_reason != RESET_REASON_RESET_PIN && - reset_reason != RESET_REASON_DEEP_SLEEP_ALARM && - reset_reason != RESET_REASON_UNKNOWN && - reset_reason != RESET_REASON_SOFTWARE) { + if (reset_reason == MCU_RESET_REASON_BROWNOUT || + reset_reason == MCU_RESET_REASON_RESCUE_DEBUG) { return false; } bool initialized = pool.base.type == &socketpool_socketpool_type; if (!initialized) { - result = common_hal_os_getenv_str("CIRCUITPY_WEB_INSTANCE_NAME", web_instance_name, sizeof(web_instance_name)); - if (result != GETENV_OK || web_instance_name[0] == '\0') { + result = settings_get_str("CIRCUITPY_WEB_INSTANCE_NAME", web_instance_name, sizeof(web_instance_name)); + if (result != SETTINGS_OK || web_instance_name[0] == '\0') { strcpy(web_instance_name, MICROPY_HW_BOARD_NAME); } // (leaves new_port unchanged on any failure) - (void)common_hal_os_getenv_int("CIRCUITPY_WEB_API_PORT", &web_api_port); + (void)settings_get_int("CIRCUITPY_WEB_API_PORT", &web_api_port); const size_t api_password_len = sizeof(_api_password) - 1; - result = common_hal_os_getenv_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); - if (result == GETENV_OK) { + result = settings_get_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); + if (result == SETTINGS_OK) { _api_password[0] = ':'; _base64_in_place(_api_password, strlen(_api_password), sizeof(_api_password) - 1); } else { // Skip starting web-workflow when no password is passed. @@ -307,7 +365,7 @@ bool supervisor_start_web_workflow(void) { } pool.base.type = &socketpool_socketpool_type; - common_hal_socketpool_socketpool_construct(&pool, &common_hal_wifi_radio_obj); + common_hal_socketpool_socketpool_construct(&pool, socketpool_radio); socketpool_socket_reset(&listening); socketpool_socket_reset(&active); @@ -339,14 +397,33 @@ bool supervisor_start_web_workflow(void) { if (common_hal_socketpool_socket_get_closed(&listening)) { #if CIRCUITPY_SOCKETPOOL_IPV6 - socketpool_socket(&pool, SOCKETPOOL_AF_INET6, SOCKETPOOL_SOCK_STREAM, 0, &listening); + bool opened = socketpool_socket(&pool, SOCKETPOOL_AF_INET6, SOCKETPOOL_SOCK_STREAM, 0, &listening); #else - socketpool_socket(&pool, SOCKETPOOL_AF_INET, SOCKETPOOL_SOCK_STREAM, 0, &listening); + bool opened = socketpool_socket(&pool, SOCKETPOOL_AF_INET, SOCKETPOOL_SOCK_STREAM, 0, &listening); #endif + // Ports with an offloaded network stack can refuse to create a + // socket until the interface has an address (this board returns + // ENOTCONN before DHCP completes). Binding and listening on the + // unset descriptor then fails with EBADF, and reporting success + // leaves the supervisor polling a socket that was never opened. + // + // Returning false avoids that but is not a retry: the background + // callback never re-enters this function, so the next attempt is + // the next supervisor_workflow_reset(), i.e. a VM restart. A board + // that only gets an address after boot will not bring the workflow + // up on its own until then. + if (!opened) { + return false; + } common_hal_socketpool_socket_settimeout(&listening, 0); - // Bind to any ip. (Not checking for failures) - common_hal_socketpool_socket_bind(&listening, "", 0, web_api_port); - common_hal_socketpool_socket_listen(&listening, 1); + if (common_hal_socketpool_socket_bind(&listening, "", 0, web_api_port) != 0) { + common_hal_socketpool_socket_close(&listening); + return false; + } + if (!common_hal_socketpool_socket_listen(&listening, 1)) { + common_hal_socketpool_socket_close(&listening); + return false; + } } // Wake polling thread (maybe) socketpool_socket_poll_resume(); @@ -373,7 +450,7 @@ void web_workflow_send_raw(socketpool_socket_obj_t *socket, bool flush, const ui total_sent += sent; if (total_sent < len) { // Yield so that network code can run. - port_yield(); + port_task_sleep_ms(4); } } } @@ -825,7 +902,6 @@ static void _reply_with_devices_json(socketpool_socket_obj_t *socket, _request * "\"instance_name\": \"%s\", " "\"port\": %d, " "\"ip\": \"%d.%d.%d.%d\"}", hostname, instance_name, port, octets[0], octets[1], octets[2], octets[3]); - common_hal_mdns_remoteservice_deinit(&found_devices[i]); } #endif _send_chunk(socket, "]}"); @@ -847,7 +923,9 @@ static void _reply_with_version_json(socketpool_socket_obj_t *socket, _request * instance_name = common_hal_mdns_server_get_instance_name(&mdns); } #endif - _update_encoded_ip(); + uint32_t ipv4_address = 0; + (void)_get_web_workflow_ip(&ipv4_address); + _update_encoded_ip(ipv4_address); // Note: this leverages the fact that C concats consecutive string literals together. mp_printf(&_socket_print, "{\"web_api_version\": 4, " @@ -977,7 +1055,7 @@ static void _write_file_and_reply(socketpool_socket_obj_t *socket, _request *req if (result == FR_NO_FILE) { new_file = true; result = f_open(fs, &active_file, path, FA_WRITE | FA_OPEN_ALWAYS); - } else { + } else if (result == FR_OK) { old_length = f_size(&active_file); } @@ -988,6 +1066,18 @@ static void _write_file_and_reply(socketpool_socket_obj_t *socket, _request *req _reply_missing(socket, request); return; } + if (result == FR_WRITE_PROTECTED) { + // The filesystem is held by something else with write access (most + // commonly USB-MSC: the host has CIRCUITPY mounted, so CircuitPython + // can't write through FatFS). Match the mkdir/move/delete paths and + // reply 409 Conflict so clients can show an actionable message + // ("eject CIRCUITPY / disable USB MSC") instead of a generic 500. + override_fattime(0); + filesystem_unlock(fs_mount); + _discard_incoming(socket, request->content_length); + _reply_conflict(socket, request); + return; + } if (result != FR_OK) { override_fattime(0); filesystem_unlock(fs_mount); @@ -1085,6 +1175,10 @@ static void _reply_static(socketpool_socket_obj_t *socket, _request *request, co "Content-Encoding: gzip\r\n", "Content-Length: ", encoded_len, "\r\n", "Content-Type: ", content_type, "\r\n", + #if CIRCUITPY_DEBUG == 0 + "Cache-Control: max-age=31536000\r\n", // Cache for a year. + "Vary: Accept\r\n", + #endif "\r\n", NULL); web_workflow_send_raw(socket, true, response, response_len); } diff --git a/supervisor/shared/web_workflow/web_workflow.h b/supervisor/shared/web_workflow/web_workflow.h index 439964dd333..9ec15a14ddc 100644 --- a/supervisor/shared/web_workflow/web_workflow.h +++ b/supervisor/shared/web_workflow/web_workflow.h @@ -8,7 +8,12 @@ #include +#if CIRCUITPY_MDNS #include "shared-bindings/mdns/Server.h" +#else +typedef struct mdns_server_obj mdns_server_obj_t; +#endif + #include "shared-bindings/socketpool/Socket.h" // This background function should be called repeatedly. It cannot be done based diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index df2055580fc..21dd0512eb1 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -18,13 +18,15 @@ #if CIRCUITPY_BLEIO #include "shared-bindings/_bleio/__init__.h" #include "supervisor/shared/bluetooth/bluetooth.h" -#if CIRCUITPY_SERIAL_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE #include "supervisor/shared/bluetooth/serial.h" #endif #endif -#if CIRCUITPY_TINYUSB || CIRCUITPY_USB_KEYBOARD_WORKFLOW +#if CIRCUITPY_USB_DEVICE || CIRCUITPY_USB_KEYBOARD_WORKFLOW #include "supervisor/usb.h" +#endif +#if CIRCUITPY_TINYUSB #include "tusb.h" #endif @@ -43,10 +45,12 @@ void supervisor_workflow_reset(void) { #if CIRCUITPY_WEB_WORKFLOW bool result = supervisor_start_web_workflow(); - if (workflow_background_cb.fun) { - if (result) { - supervisor_workflow_request_background(); + if (result) { + if (!workflow_background_cb.fun) { + // Enable background callbacks if web_workflow startup successful. + workflow_background_cb.fun = supervisor_web_workflow_background; } + supervisor_workflow_request_background(); } #endif } @@ -68,8 +72,8 @@ void supervisor_workflow_request_background(void) { bool supervisor_workflow_active(void) { #if CIRCUITPY_USB_DEVICE // Eventually there might be other non-USB workflows, such as BLE. - // tud_ready() checks for usb mounted and not suspended. - if (tud_ready()) { + // usb_connected() checks for usb mounted and not suspended. + if (usb_connected()) { return true; } #endif @@ -78,7 +82,7 @@ bool supervisor_workflow_active(void) { return true; } #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE if (ble_serial_connected()) { return true; } @@ -89,7 +93,7 @@ bool supervisor_workflow_active(void) { void supervisor_workflow_start(void) { // Start USB after giving boot.py a chance to tweak behavior. - #if CIRCUITPY_TINYUSB + #if CIRCUITPY_USB_DEVICE // Setup USB connection after heap is available. // It needs the heap to build descriptors. usb_init(); @@ -105,9 +109,10 @@ void supervisor_workflow_start(void) { #if CIRCUITPY_WEB_WORKFLOW if (supervisor_start_web_workflow()) { - // Enable background callbacks if web_workflow startup successful - memset(&workflow_background_cb, 0, sizeof(workflow_background_cb)); + // Enable background callbacks if web_workflow startup successful. workflow_background_cb.fun = supervisor_web_workflow_background; + // Kick the first background run now that the callback is installed. + supervisor_workflow_request_background(); } #endif diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 0ecc6ea3acf..2d881dfe070 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -1,6 +1,5 @@ SRC_SUPERVISOR = \ main.c \ - lib/tlsf/tlsf.c \ supervisor/port.c \ supervisor/shared/background_callback.c \ supervisor/shared/board.c \ @@ -20,6 +19,14 @@ SRC_SUPERVISOR = \ supervisor/shared/translate/translate.c \ supervisor/shared/workflow.c \ +ifeq ($(CIRCUITPY_SETTINGS_TOML),1) +SRC_SUPERVISOR += supervisor/shared/settings.c +endif + +ifeq ($(CIRCUITPY_LIB_TLSF),1) +SRC_SUPERVISOR += lib/tlsf/tlsf.c +endif + # For tlsf CFLAGS += -D_DEBUG=0 @@ -44,7 +51,7 @@ ifeq ($(CIRCUITPY_BLEIO),1) ifeq ($(CIRCUITPY_BLE_FILE_SERVICE),1) SRC_SUPERVISOR += supervisor/shared/bluetooth/file_transfer.c endif - ifeq ($(CIRCUITPY_SERIAL_BLE),1) + ifeq ($(CIRCUITPY_BLE_SERIAL_SERVICE),1) SRC_SUPERVISOR += supervisor/shared/bluetooth/serial.c endif endif @@ -113,13 +120,13 @@ ifeq ($(CIRCUITPY_TINYUSB),1) lib/tinyusb/src/common/tusb_fifo.c \ lib/tinyusb/src/tusb.c \ supervisor/usb.c \ + supervisor/shared/usb.c \ supervisor/shared/usb/usb.c \ ifeq ($(CIRCUITPY_USB_DEVICE),1) SRC_SUPERVISOR += \ lib/tinyusb/src/class/cdc/cdc_device.c \ lib/tinyusb/src/device/usbd.c \ - lib/tinyusb/src/device/usbd_control.c \ supervisor/shared/usb/usb_desc.c \ supervisor/shared/usb/usb_device.c \ @@ -141,6 +148,7 @@ ifeq ($(CIRCUITPY_TINYUSB),1) shared-bindings/usb_hid/Device.c \ shared-module/usb_hid/__init__.c \ shared-module/usb_hid/Device.c \ + shared-module/usb_hid/report_descriptors.c \ endif @@ -174,6 +182,20 @@ ifeq ($(CIRCUITPY_TINYUSB),1) CFLAGS += -DCFG_TUD_VIDEO=1 -DCFG_TUD_VIDEO_STREAMING=1 -DCFG_TUD_VIDEO_STREAMING_EP_BUFSIZE=256 -DCFG_TUD_VIDEO_STREAMING_BULK=1 endif + ifeq ($(CIRCUITPY_USB_AUDIO), 1) + SRC_SUPERVISOR += \ + shared-bindings/usb_audio/__init__.c \ + shared-module/usb_audio/__init__.c \ + shared-bindings/usb_audio/USBMicrophone.c \ + shared-module/usb_audio/USBMicrophone.c \ + shared-bindings/usb_audio/USBSpeaker.c \ + shared-module/usb_audio/USBSpeaker.c \ + lib/tinyusb/src/class/audio/audio_device.c \ + + # The CFG_TUD_AUDIO_* class driver settings are defined in + # supervisor/shared/usb/tusb_config.h, gated on CIRCUITPY_USB_AUDIO. + endif + ifeq ($(CIRCUITPY_USB_VENDOR), 1) SRC_SUPERVISOR += \ @@ -256,9 +278,6 @@ ifeq ($(CIRCUITPY_USB_CDC),1) CFLAGS += -DCFG_TUD_CDC=2 endif -USB_HIGHSPEED ?= 0 -CFLAGS += -DUSB_HIGHSPEED=$(USB_HIGHSPEED) - $(BUILD)/supervisor/shared/translate/translate.o: $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/compressed_translations.generated.h CIRCUITPY_DISPLAY_FONT ?= "../../tools/fonts/ter-u12n.bdf" diff --git a/supervisor/usb.h b/supervisor/usb.h index 10f033a3616..d6e4236c9b4 100644 --- a/supervisor/usb.h +++ b/supervisor/usb.h @@ -48,6 +48,7 @@ typedef struct { bool usb_enabled(void); void usb_add_interface_string(uint8_t interface_string_index, const char str[]); bool usb_build_descriptors(const usb_identification_t *identification); +bool usb_connected(void); void usb_disconnect(void); void usb_init(void); void usb_set_defaults(void); diff --git a/tests/README.md b/tests/README.md index 21e14eee5e1..4edd3e1088e 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,18 @@ # MicroPython Test Suite -This directory contains tests for most parts of MicroPython. +This directory contains tests for most parts of MicroPython. To run it you will need +CPython 3.8.2 or newer, which is used to validate MicroPython's behaviour. + +The tests are organized into several categories: +- Unit and regression tests: tests for MicroPython's core functionality, including the + compiler, runtime, and built-in modules +- perf_bench: performance benchmarks +- internal_bench: internal performance benchmarks +- Serial reliability and performance test +- Test key/certificates +- CPython vs MicroPython Differences + +## Unit and regression tests To run all stable tests, run the "run-tests.py" script in this directory. By default that will run the test suite against the unix port of MicroPython. @@ -62,21 +74,19 @@ module, should go in the import/ subdirectory. The `perf_bench` directory contains some performance benchmarks that can be used to benchmark different MicroPython firmwares or host ports. -The runner utility is `run-perfbench,py`. Execute `./run-perfbench.py --help` +The runner utility is `run-perfbench.py`. Execute `./run-perfbench.py --help` for a full list of command line options. ### Benchmarking a target -To run tests on a firmware target using `pyboard.py`, run the command line like +To run tests on a firmware target using a serial port, run the command line like this: ``` -./run-perfbench.py -p -d /dev/ttyACM0 168 100 +./run-perfbench.py -t /dev/ttyACM0 168 100 ``` -* `-p` indicates running on a remote target via pyboard.py, not the host. -* `-d PORTNAME` is the serial port, `/dev/ttyACM0` is the default if not - provided. +* `-t PORTNAME` is the serial port to use (and it supports shorthand like `a0`). * `168` is value `N`, the approximate CPU frequency in MHz (in this case Pyboard V1.1 is 168MHz). It's possible to choose other values as well: lower values like `10` will run much the tests much quicker, higher values like `1000` will @@ -136,11 +146,11 @@ Usually you want to know if something is faster or slower than a reference. To do this, copy the output of each `run-perfbench.py` run to a text file. This can be done multiple ways, but one way on Linux/macOS is with the `tee` -utility: `./run-perfbench.py -p 168 100 | tee pyb-run1.txt` +utility: `./run-perfbench.py -t a0 168 100 | tee pyb-run1.txt` Once you have two files with output from two different runs (maybe with different code or configuration), compare the runtimes with `./run-perfbench.py --t pybv-run1.txt pybv-run2.txt` or compare scores with `./run-perfbench.py -s +-m pybv-run1.txt pybv-run2.txt` or compare scores with `./run-perfbench.py -s pybv-run1.txt pybv-run2.txt`: ``` @@ -204,6 +214,18 @@ internal_bench/bytebuf: 1 tests performed (3 individual testcases) ``` +## Serial reliability and performance test + +Serial port reliability and performance can be tested using the `serial_test.py` script. +Pass the name of the port to test against, for example: + + $ ./serial_test.py -t /dev/ttyACM0 + +If no port is specified then `/dev/ttyACM0` is used as the default. + +The test will send data out to the target, and receive data from the target, in various +chunk sizes. The throughput of the serial connection will be reported for each sub-test. + ## Test key/certificates SSL/TLS tests in `multi_net` and `net_inet` use self-signed key/cert pairs @@ -238,3 +260,87 @@ $ openssl ecparam -name prime256v1 -genkey -noout -out ec_key.pem $ openssl pkey -in ec_key.pem -out ec_key.der -outform DER $ openssl req -new -x509 -key ec_key.pem -out ec_cert.der -outform DER -days 3650 -nodes -subj '/CN=micropython.local/O=MicroPython/C=AU' ``` + +## CPython vs MicroPython Differences + +The `tests/cpydiff` folder contains test files that document and verify the differences +between the CPython and MicroPython implementations. + +These tests are designed to: +- Execute the same code on both CPython and MicroPython +- Document behavioral differences between the two implementations +- Generate documentation pages that help users understand these differences + +### How It Works + +1. Each test file contains Python code that demonstrates a specific difference. +2. The tests are executed on both CPython and MicroPython. +3. The output from both implementations is captured and compared. If the outputs are the + same, the generation will fail (because the outputs should be different). +4. The results, along with metadata from the file docstrings, are used to generate + documentation. + +### Documentation Generation + +The documentation is automatically generated using: +``` +tools/gen-cpydiff.py +``` + +This script: +- Parses the docstring metadata from each test file +- Runs the tests on both implementations +- Combines the results to create comprehensive documentation pages +- Outputs formatted reStructuredText documentation showing the differences + +**Note:** This script is automatically executed as part of the documentation publishing +process when building the docs. + +### Test File Format + +The test filename should match the categories of the test. For example, a test with +categories `Syntax,Operators` should be named `syntax_operators_*.py`. + +Each test file should include a docstring with the following format, and include a +minimal code snippet that reproduces the difference when run on both CPython and the +unix port of MicroPython: + +```python +""" +categories: Category,Subcategory +description: Brief description of the difference being tested +cause: Explanation of why this difference exists +workaround: How to work around this difference (or "Unknown" if none) +""" +# Minimal Python code reproducing the difference +import sys +print(sys.implementation.name) +``` + +The categories and subcategories are used to organize the documentation into sections. +Files with the same category and/or subcategory will be placed in the same section. + +Common categories include: +- Syntax +- Core (Core language) +- Types (Builtin types) +- Modules + +### Building the Documentation + +The documentation is automatically regenerated during the documentation build process. +To manually regenerate after adding or modifying tests: + +1. Set environment variables if needed: + - `MICROPY_MICROPYTHON`: Path to MicroPython executable + - `MICROPY_CPYTHON3`: Path to CPython 3.x executable (default: "python3") + +2. Run the generation script from the project root: + ``` + python tools/gen-cpydiff.py + ``` + +The generated documentation will be placed in `docs/genrst/` as reStructuredText files. + +Also see `docs/README.md` for more information on building the documentation locally +to validate the rendering of the resulting documentation page(s). diff --git a/tests/assets/Makefile b/tests/assets/Makefile new file mode 100644 index 00000000000..6048ee2a405 --- /dev/null +++ b/tests/assets/Makefile @@ -0,0 +1,29 @@ +MPY_DIR = ../.. + +PYTHON := $(command -v python3 2> /dev/null) +ifndef PYTHON +PYTHON = python +endif + +# Files created with dd if=/dev/urandom ... - the file name is the CRC32 +# of the data contained in the file itself. + +ROMFS_FILES = romfs_source/0x30d83fe5.bin \ + romfs_source/0x37bef0eb.bin \ + romfs_source/0x442f3b5f.bin \ + romfs_source/0x648793fb.bin \ + romfs_source/0x913837b6.bin \ + romfs_source/0xdb14aac7.bin \ + romfs_source/romfs_sentinel.txt + +.PHONY: romfs +romfs: all + +.PHONY: clean +clean: + rm -f random_romfs.bin + +all: random_romfs.bin + +random_romfs.bin: $(ROMFS_FILES) + $(PYTHON) $(MPY_DIR)/tools/mpremote/mpremote.py romfs --partition 0 --no-mpy --output $@ build romfs_source diff --git a/tests/assets/README.md b/tests/assets/README.md new file mode 100644 index 00000000000..a5f935ee1b9 --- /dev/null +++ b/tests/assets/README.md @@ -0,0 +1,8 @@ +This directory contains assets for other tests to use: + +- A .mpy built against the current .mpy version that can be used to test + freezing without a dependency on mpy-cross (`frozentest.py` and + `frozentest.mpy`) +- A ROMFS image containing random binary files for testing mounting and reading + from the partition without having to generate a custom image + (`random_romfs.bin`, the `romfs_source` directory, and `Makefile`) diff --git a/tests/frozen/frozentest.mpy b/tests/assets/frozentest.mpy similarity index 100% rename from tests/frozen/frozentest.mpy rename to tests/assets/frozentest.mpy diff --git a/tests/frozen/frozentest.py b/tests/assets/frozentest.py similarity index 90% rename from tests/frozen/frozentest.py rename to tests/assets/frozentest.py index 78cdd60bf04..74bdfb3b267 100644 --- a/tests/frozen/frozentest.py +++ b/tests/assets/frozentest.py @@ -1,4 +1,4 @@ -print("uPy") +print("interned") print("a long string that is not interned") print("a string that has unicode αβγ chars") print(b"bytes 1234\x01") diff --git a/tests/assets/random_romfs.bin b/tests/assets/random_romfs.bin new file mode 100644 index 00000000000..387bd7ec476 Binary files /dev/null and b/tests/assets/random_romfs.bin differ diff --git a/tests/assets/romfs_source/0x30d83fe5.bin b/tests/assets/romfs_source/0x30d83fe5.bin new file mode 100644 index 00000000000..625e51fb8ae Binary files /dev/null and b/tests/assets/romfs_source/0x30d83fe5.bin differ diff --git a/tests/assets/romfs_source/0x37bef0eb.bin b/tests/assets/romfs_source/0x37bef0eb.bin new file mode 100644 index 00000000000..11e1c67871c Binary files /dev/null and b/tests/assets/romfs_source/0x37bef0eb.bin differ diff --git a/tests/assets/romfs_source/0x442f3b5f.bin b/tests/assets/romfs_source/0x442f3b5f.bin new file mode 100644 index 00000000000..ffe9f8f0e2c Binary files /dev/null and b/tests/assets/romfs_source/0x442f3b5f.bin differ diff --git a/tests/assets/romfs_source/0x648793fb.bin b/tests/assets/romfs_source/0x648793fb.bin new file mode 100644 index 00000000000..f99b58c610a Binary files /dev/null and b/tests/assets/romfs_source/0x648793fb.bin differ diff --git a/tests/assets/romfs_source/0x913837b6.bin b/tests/assets/romfs_source/0x913837b6.bin new file mode 100644 index 00000000000..6511184346a Binary files /dev/null and b/tests/assets/romfs_source/0x913837b6.bin differ diff --git a/tests/assets/romfs_source/0xdb14aac7.bin b/tests/assets/romfs_source/0xdb14aac7.bin new file mode 100644 index 00000000000..51754d4ecd8 Binary files /dev/null and b/tests/assets/romfs_source/0xdb14aac7.bin differ diff --git a/tests/assets/romfs_source/romfs_sentinel.txt b/tests/assets/romfs_source/romfs_sentinel.txt new file mode 100644 index 00000000000..6ff9311d70e --- /dev/null +++ b/tests/assets/romfs_source/romfs_sentinel.txt @@ -0,0 +1,3 @@ +*MPY-ROMFS-TEST-PARTITION* + +This is a ROMFS partition to be used in MicroPython tests, usually for CI. diff --git a/tests/basics/annotate_var.py.exp b/tests/basics/annotate_var.py.exp deleted file mode 100644 index 9b6536e966b..00000000000 --- a/tests/basics/annotate_var.py.exp +++ /dev/null @@ -1,5 +0,0 @@ -False -1 -(1, 2) -NameError -1 diff --git a/tests/basics/array_add.py b/tests/basics/array_add.py index 76ce59f761e..e78615541c3 100644 --- a/tests/basics/array_add.py +++ b/tests/basics/array_add.py @@ -14,3 +14,9 @@ a1.extend(array.array('I', [5])) print(a1) + +a1.extend([6, 7]) +print(a1) + +a1.extend(i for i in (8, 9)) +print(a1) diff --git a/tests/basics/array_int_repr.py b/tests/basics/array_int_repr.py new file mode 100644 index 00000000000..55a2d5998eb --- /dev/null +++ b/tests/basics/array_int_repr.py @@ -0,0 +1,85 @@ +# Test array integer representations in memory +# +# This has to be a unit test because correct internal representation depends on +# native endianness +# +# These test cases should pass on both CPython and MicroPython. + +try: + from array import array + from sys import byteorder +except ImportError: + print("SKIP") + raise SystemExit + +try: + import unittest +except MemoryError: + print("SKIP-TOO-LARGE") # some small boards can't fit unittest in RAM + raise SystemExit + +# Ports without bigint support don't support typecode 'q' +try: + array("q", []) + array_has_typecode_q = True +except: + array_has_typecode_q = False + + +class TestIntReprs(unittest.TestCase): + def _test_repr(self, typecode, values): + # create an array with the specified typecode and list of values + a = array(typecode, values) + a_hex = memoryview(a).hex() + print(a, a_hex) + + self.assertEqual(len(a_hex) % len(values), 0) + # no array.itemsize in MicroPython, so calculate item size + sz = len(a_hex) // 2 // len(values) + if hasattr(a, "itemsize"): + self.assertEqual(a.itemsize, sz) + + # build alternative hex representation of the array using int.to_bytes() + # on each value + values_hex = "" + for v in values: + v_bytes = v.to_bytes(sz, byteorder=byteorder, signed=typecode.islower()) + values_hex += v_bytes.hex() + + # compare with the raw array contents + self.assertEqual(a_hex, values_hex) + + def test_smaller_ints(self): + for typecode, initialiser in ( + ("b", [1, -1, 120, -120]), + ("B", [1, 5, 220]), + ("h", [5, -1, 32_000, -32_000]), + ("H", [5, 1, 32_000, 65_535]), + ("i", [5, -1, 32_000, -32_000]), # CPython only guarantees min 2 bytes, C style! + ("I", [5, 1, 32_000, 65_535]), + ("l", [5, -1, 2_000_000, -2_000_000, 0x7FFF_FFFF]), + ("L", [5, 1, 65_536, 2_000_000, 0x7FFF_FFFF, 0xFFFF_FFFF]), + ): + self._test_repr(typecode, initialiser) + + @unittest.skipIf(not array_has_typecode_q, "port has no bigint support") + def test_bigints(self): + # Note: need to be careful not to write any literal expressions that can't be compiled on non-bigint MP + a = 0x1FFF_FFF + b = 62 + + try: + # this calculation will trigger OverflowError if bigint is set to long long + max_uint64 = [2 ** (b + 1)] + except OverflowError: + max_uint64 = [] + + for typecode, initialiser in ( + ("q", [a * 5, -a * 10, 2**b, (2**b) * -1]), + ("Q", [a * 5, a * 10, 2**b, (2**b) - 1, (2**b) + 1] + max_uint64), + ): + self._test_repr(typecode, initialiser) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/basics/array_limits_intbig.py b/tests/basics/array_limits_intbig.py new file mode 100644 index 00000000000..ec740a87bed --- /dev/null +++ b/tests/basics/array_limits_intbig.py @@ -0,0 +1,124 @@ +# Test behaviour when array module is provided out of bounds values +# +# This test is intended to also pass on CPython. + +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +try: + import unittest +except MemoryError: + print("SKIP-TOO-LARGE") # some small boards can't fit unittest in RAM + raise SystemExit + + +# MicroPython V2.0 will enforce bounds on items (same as CPython), V1.x truncates +# +# Note: once error -ValueError -enter -exit -BaseException diff --git a/tests/basics/async_with2.py b/tests/basics/async_with2.py index 5bac38236fe..b18fa6bdee1 100644 --- a/tests/basics/async_with2.py +++ b/tests/basics/async_with2.py @@ -1,7 +1,7 @@ # test waiting within async with enter/exit functions # CIRCUITPY-CHANGE -# uPy allows normal generators to be awaitables. +# MicroPython allows normal generators to be awaitables. # CircuitPython does not. # In CircuitPython you need to have an __await__ method on an awaitable like in CPython; # and like in CPython, generators do not have __await__. diff --git a/tests/basics/async_with2.py.exp b/tests/basics/async_with2.py.exp deleted file mode 100644 index 76b173b4c24..00000000000 --- a/tests/basics/async_with2.py.exp +++ /dev/null @@ -1,17 +0,0 @@ -enter -f start: 10 -coro yielded: 11 -coro yielded: 12 -f returned: 13 -body start -f start: 30 -coro yielded: 31 -coro yielded: 32 -body f returned: 33 -body end -exit None None -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -finished diff --git a/tests/basics/async_with_break.py.exp b/tests/basics/async_with_break.py.exp deleted file mode 100644 index d077a88fad0..00000000000 --- a/tests/basics/async_with_break.py.exp +++ /dev/null @@ -1,15 +0,0 @@ -enter -body -exit None None -finished -enter -body -exit None None -finally -finished -enter -body -exit None None -finally inner -finally outer -finished diff --git a/tests/basics/async_with_return.py.exp b/tests/basics/async_with_return.py.exp deleted file mode 100644 index d077a88fad0..00000000000 --- a/tests/basics/async_with_return.py.exp +++ /dev/null @@ -1,15 +0,0 @@ -enter -body -exit None None -finished -enter -body -exit None None -finally -finished -enter -body -exit None None -finally inner -finally outer -finished diff --git a/tests/basics/attrtuple2.py b/tests/basics/attrtuple2.py new file mode 100644 index 00000000000..081d24b6ae9 --- /dev/null +++ b/tests/basics/attrtuple2.py @@ -0,0 +1,25 @@ +# test os.uname() attrtuple, if available +try: + import os +except ImportError: + print("SKIP") + raise SystemExit + +try: + u = os.uname() +except AttributeError: + print("SKIP") + raise SystemExit + +# test printing of attrtuple +print(str(u).find("machine=") > 0) + +# test read attr +print(isinstance(u.machine, str)) + +# test str modulo operator for attrtuple +impl_str = ("%s " * len(u)) % u +test_str = "" +for val in u: + test_str += val + " " +print(impl_str == test_str) diff --git a/tests/basics/boundmeth1.py b/tests/basics/boundmeth1.py index fe1b454688d..9f08d9bbb25 100644 --- a/tests/basics/boundmeth1.py +++ b/tests/basics/boundmeth1.py @@ -1,6 +1,6 @@ # tests basics of bound methods -# uPy and CPython differ when printing a bound method, so just print the type +# MicroPython and CPython differ when printing a bound method, so just print the type print(type(repr([].append))) diff --git a/tests/basics/builtin_dir.py b/tests/basics/builtin_dir.py index 1eecbd044b7..2aa89dfe0a2 100644 --- a/tests/basics/builtin_dir.py +++ b/tests/basics/builtin_dir.py @@ -1,5 +1,12 @@ # test builtin dir +try: + dir +except NameError: + print("SKIP") + raise SystemExit + + # dir of locals print('__name__' in dir()) diff --git a/tests/basics/builtin_help.py b/tests/basics/builtin_help.py index 6ec39653fe9..3d4e4f26bd2 100644 --- a/tests/basics/builtin_help.py +++ b/tests/basics/builtin_help.py @@ -14,4 +14,10 @@ help(micropython) # help for a module help('modules') # list available modules +class A: + x = 1 + y = 2 + del x +help(A) + print('done') # so last bit of output is predictable diff --git a/tests/basics/builtin_pow3.py b/tests/basics/builtin_pow3.py index 4eeef85c276..3009dc0cf80 100644 --- a/tests/basics/builtin_pow3.py +++ b/tests/basics/builtin_pow3.py @@ -12,6 +12,16 @@ print(pow(0, 1, 1)) print(pow(1, 0, 1)) print(pow(1, 0, 2)) +print(pow(0, 0, 5)) +print(pow(0, 1, 5)) +print(pow(0, 0, 1)) + +# a negative modulus gives a result with the sign of the modulus +print(pow(1, 0, -1)) +print(pow(1, 0, -2)) +print(pow(3, 0, -5)) +print(pow(-3, 0, -5)) +print(pow(3, 4, -5)) # 3 arg pow is defined to only work on integers try: @@ -29,6 +39,12 @@ except TypeError: print("TypeError expected") +# pow(x, y, None) is equivalent to pow(x, y) +print(pow(0, 1, None)) +print(pow(1, 0, None)) +print(pow(-2, 3, None)) +print(pow(3, 8, None)) + # CIRCUITPY-CHANGE try: print(pow(4, 5, 0)) diff --git a/tests/basics/builtin_pow3_intbig.py b/tests/basics/builtin_pow3_intbig.py index bedc8b36b7e..c91b4d173dd 100644 --- a/tests/basics/builtin_pow3_intbig.py +++ b/tests/basics/builtin_pow3_intbig.py @@ -9,6 +9,9 @@ print(pow(555557, 1000002, 1000003)) +# a zero exponent with a large negative modulus +print(pow(3, 0, -(2**70))) + # Tests for 3 arg pow with large values # This value happens to be prime @@ -20,3 +23,8 @@ print(hex(pow(y, x-1, x))) # Should be 1, since x is prime print(hex(pow(y, y-1, x))) # Should be a 'big value' print(hex(pow(y, y-1, y))) # Should be a 'big value' + +try: + print(pow(1, 2, 0)) +except ValueError: + print("ValueError") diff --git a/tests/basics/builtin_range.py b/tests/basics/builtin_range.py index 66226bad16a..9608a816310 100644 --- a/tests/basics/builtin_range.py +++ b/tests/basics/builtin_range.py @@ -32,13 +32,29 @@ print(range(1, 4)[0:]) print(range(1, 4)[1:]) print(range(1, 4)[:-1]) +print(range(4, 1)[:]) +print(range(4, 1)[0:]) +print(range(4, 1)[1:]) +print(range(4, 1)[:-1]) print(range(7, -2, -4)[:]) print(range(1, 100, 5)[5:15:3]) print(range(1, 100, 5)[15:5:-3]) print(range(100, 1, -5)[5:15:3]) print(range(100, 1, -5)[15:5:-3]) +print(range(1, 100, 5)[5:15:-3]) +print(range(1, 100, 5)[15:5:3]) +print(range(100, 1, -5)[5:15:-3]) +print(range(100, 1, -5)[15:5:3]) +print(range(1, 100, 5)[5:15:3]) +print(range(1, 100, 5)[15:5:-3]) +print(range(1, 100, -5)[5:15:3]) +print(range(1, 100, -5)[15:5:-3]) +print(range(1, 100, 5)[5:15:-3]) +print(range(1, 100, 5)[15:5:3]) +print(range(1, 100, -5)[5:15:-3]) +print(range(1, 100, -5)[15:5:3]) -# for this case uPy gives a different stop value but the listed elements are still correct +# for this case MicroPython gives a different stop value but the listed elements are still correct print(list(range(7, -2, -4)[2:-2:])) # zero step diff --git a/tests/basics/builtin_range_maxsize.py b/tests/basics/builtin_range_maxsize.py new file mode 100644 index 00000000000..b0f3a5e5129 --- /dev/null +++ b/tests/basics/builtin_range_maxsize.py @@ -0,0 +1,38 @@ +try: + from sys import maxsize +except ImportError: + print("SKIP") + raise SystemExit + +# Test the range builtin at extreme values. (https://github.com/micropython/micropython/issues/17684) +# +# This is written using asserts instead of prints because the value of `maxsize` differs. +# +# Numbers & counts right up against the max of mp_int_t also cause overflows, such as +# objrange.c:115:14: runtime error: signed integer overflow: 9223372036854775807 + 1 cannot be represented in type 'long int' +# so just avoid them for the purposes of this test. + +r = range(-maxsize + 1, -1) +assert r.start == -maxsize + 1 +assert r.stop == -1 +assert r[0] == -maxsize + 1 +assert r[1] == -maxsize + 2 +assert r[-1] == -2 +assert r[-2] == -3 + +ir = iter(r) +assert next(ir) == -maxsize + 1 +assert next(ir) == -maxsize + 2 + +r = range(0, maxsize - 1) +assert len(r) == maxsize - 1 +assert r.stop == maxsize - 1 + +r = range(maxsize, 0, -1) +assert len(r) == maxsize +assert r.start == maxsize +assert r[0] == maxsize +assert r[1] == maxsize - 1 +ir = iter(r) +assert next(ir) == maxsize +assert next(ir) == maxsize - 1 diff --git a/tests/basics/builtin_setattr.py b/tests/basics/builtin_setattr.py index e4acb14cac3..2c9a452c327 100644 --- a/tests/basics/builtin_setattr.py +++ b/tests/basics/builtin_setattr.py @@ -21,5 +21,5 @@ def __init__(self): try: setattr(int, 'to_bytes', 1) except (AttributeError, TypeError): - # uPy raises AttributeError, CPython raises TypeError + # MicroPython raises AttributeError, CPython raises TypeError print('AttributeError/TypeError') diff --git a/tests/basics/builtin_slice.py b/tests/basics/builtin_slice.py index 3ff3c3dd04d..cbce3d14ed6 100644 --- a/tests/basics/builtin_slice.py +++ b/tests/basics/builtin_slice.py @@ -1,11 +1,44 @@ # test builtin slice +# ensures that slices passed to user types are heap-allocated and can be +# safely stored as well as not overridden by subsequent slices. + # print slice class A: def __getitem__(self, idx): - print(idx) + print("get", idx) + print("abc"[1:]) + print("get", idx) + return idx + + def __setitem__(self, idx, value): + print("set", idx) + print("abc"[1:]) + print("set", idx) + self.saved_idx = idx + return idx + + def __delitem__(self, idx): + print("del", idx) + print("abc"[1:]) + print("del", idx) return idx -s = A()[1:2:3] + + +a = A() +s = a[1:2:3] +a[4:5:6] = s +del a[7:8:9] + +print(a.saved_idx) + +# nested slicing +print(A()[1 : A()[A()[2:3:4] : 5]]) + +# tuple slicing +a[1:2, 4:5, 7:8] +a[1, 4:5, 7:8, 2] +a[1:2, a[3:4], 5:6] # check type print(type(s) is slice) diff --git a/tests/basics/builtin_str_hex.py b/tests/basics/builtin_str_hex.py index 9455883012c..f77fe7c4fa9 100644 --- a/tests/basics/builtin_str_hex.py +++ b/tests/basics/builtin_str_hex.py @@ -3,6 +3,7 @@ raise SystemExit for x in ( + b"", b"\x00\x01\x02\x03\x04\x05\x06\x07", b"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", b"\x7f\x80\xff", @@ -35,5 +36,5 @@ ): try: print(bytes.fromhex(x)) - except ValueError as e: - print("ValueError:", e) + except ValueError: + print("ValueError", x) diff --git a/tests/basics/builtin_str_hex.py.exp b/tests/basics/builtin_str_hex.py.exp deleted file mode 100644 index 0309cad02d1..00000000000 --- a/tests/basics/builtin_str_hex.py.exp +++ /dev/null @@ -1,39 +0,0 @@ -0001020304050607 -0001020304050607 -0001020304050607 -00:01:02:03:04:05:06:07 -00:01:02:03:04:05:06:07 -00:01:02:03:04:05:06:07 -08090a0b0c0d0e0f -08090a0b0c0d0e0f -08090a0b0c0d0e0f -08:09:0a:0b:0c:0d:0e:0f -08:09:0a:0b:0c:0d:0e:0f -08:09:0a:0b:0c:0d:0e:0f -7f80ff -7f80ff -7f80ff -7f:80:ff -7f:80:ff -7f:80:ff -313233344142434461626364 -313233344142434461626364 -313233344142434461626364 -31:32:33:34:41:42:43:44:61:62:63:64 -31:32:33:34:41:42:43:44:61:62:63:64 -31:32:33:34:41:42:43:44:61:62:63:64 -b'\x00\x01\x02\x03\x04\x05\x06\x07' -b'\x08\t\n\x0b\x0c\r\x0e\x0f' -b'\x7f\x80\xff' -b'1234ABCDabcd' -b'\xab\xcd\xef' -b'\xab\xcd\xef' -b'\xab\xcd\xef' -b'\xab\xcd\xef' -ValueError: non-hex digit -ValueError: non-hex digit -ValueError: non-hex digit -ValueError: non-hex digit -ValueError: non-hex digit -ValueError: non-hex digit -ValueError: non-hex digit diff --git a/tests/basics/bytearray_byte_operations.py b/tests/basics/bytearray_byte_operations.py index 48b08ab2619..794fe8cafa2 100644 --- a/tests/basics/bytearray_byte_operations.py +++ b/tests/basics/bytearray_byte_operations.py @@ -2,6 +2,7 @@ print(bytearray(b"hello world").find(b"ll")) print(bytearray(b"hello\x00world").rfind(b"l")) +print(bytearray(b"hello world").find(ord(b"l"))) print(bytearray(b"abc efg ").strip(b"g a")) print(bytearray(b" spacious ").lstrip()) @@ -14,10 +15,18 @@ print(bytearray(b"asdfasdf").replace(b"a", b"b")) -print("00\x0000".index("0", 0)) -print("00\x0000".index("0", 3)) -print("00\x0000".rindex("0", 0)) -print("00\x0000".rindex("0", 3)) +print(b"00\x0000".index(b"0", 0)) +print(b"00\x0000".index(b"0", 3)) +print(b"00\x0000".index(ord("0"), 0)) +print(b"00\x0000".index(ord("0"), 3)) +print(b"00\x0000".index(0, 0)) +try: + print(b"00\x0000".index(0, 3)) +except ValueError: + print("ValueError") +print(b"00\x0000".index(b"0", 3)) +print(b"00\x0000".rindex(b"0", 0)) +print(b"00\x0000".rindex(b"0", 3)) print(bytearray(b"foobar").endswith(b"bar")) print(bytearray(b"1foo").startswith(b"foo", 1)) diff --git a/tests/basics/bytes_find.py b/tests/basics/bytes_find.py index 75ef9796cd1..1ecbf13b0cf 100644 --- a/tests/basics/bytes_find.py +++ b/tests/basics/bytes_find.py @@ -21,6 +21,44 @@ print(b"0000".find(b'1', 3)) print(b"0000".find(b'1', 4)) print(b"0000".find(b'1', 5)) +print(b"0000".find(ord(b'0'))) +print(b"0000".find(ord(b'0'), 0)) +print(b"0000".find(ord(b'0'), 1)) +print(b"0000".find(ord(b'0'), 2)) +print(b"0000".find(ord(b'0'), 3)) +print(b"0000".find(ord(b'0'), 4)) +print(b"0000".find(ord(b'0'), 5)) +print(b"0000".find(ord(b'x'), 3)) +print(b"0000".find(ord(b'1'), 3)) +print(b"0000".find(ord(b'1'), 4)) +print(b"0000".find(ord(b'1'), 5)) # Non-ascii values (make sure not treated as unicode-like) print(b"\x80abc".find(b"a", 1)) + +# Int-like conversion. +print(b"00\x0000".find(b'0', True)) + +# Out of bounds int. +try: + print(b"0000".find(b'0', -1)) +except ValueError: + print("ValueError") +try: + print(b"0000".find(b'0', 256)) +except ValueError: + print("ValueError") +try: + print(b"0000".find(b'0', 91273611)) +except ValueError: + print("ValueError") + +# Out of bounds search argument. +try: + print(b"0000".find(-1)) +except ValueError: + print("ValueError") +try: + print(b"0000".find(256)) +except ValueError: + print("ValueError") diff --git a/tests/basics/bytes_format_modulo.py.exp b/tests/basics/bytes_format_modulo.py.exp deleted file mode 100644 index 782b7f91fcb..00000000000 --- a/tests/basics/bytes_format_modulo.py.exp +++ /dev/null @@ -1,5 +0,0 @@ -b'%' -b'=1=' -b'=1=2=' -b'=str=' -b"=b'str'=" diff --git a/tests/basics/bytes_index.py b/tests/basics/bytes_index.py new file mode 100644 index 00000000000..d99b325192e --- /dev/null +++ b/tests/basics/bytes_index.py @@ -0,0 +1,109 @@ +print(b"hello world".index(b"ll")) +print(b"hello world".index(b"ll", None)) +print(b"hello world".index(b"ll", 1)) +print(b"hello world".index(b"ll", 1, None)) +print(b"hello world".index(b"ll", None, None)) +print(b"hello world".index(b"ll", 1, -1)) +try: + print(b"hello world".index(b"ll", 1, 1)) +except ValueError: + print("ValueError") +try: + print(b"hello world".index(b"ll", 1, 2)) +except ValueError: + print("ValueError") +try: + print(b"hello world".index(b"ll", 1, 3)) +except ValueError: + print("ValueError") +print(b"hello world".index(b"ll", 1, 4)) +print(b"hello world".index(b"ll", 1, 5)) +print(b"hello world".index(b"ll", -100)) +print(b"0000".index(b'0')) +print(b"0000".index(b'0', 0)) +print(b"0000".index(b'0', 1)) +print(b"0000".index(b'0', 2)) +print(b"0000".index(b'0', 3)) +try: + print(b"0000".index(b'0', 4)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(b'0', 5)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(b'-1', 3)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(b'1', 3)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(b'1', 4)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(b'1', 5)) +except ValueError: + print("ValueError") +print(b"0000".index(ord(b'0'))) +print(b"0000".index(ord(b'0'), 0)) +print(b"0000".index(ord(b'0'), 1)) +print(b"0000".index(ord(b'0'), 2)) +print(b"0000".index(ord(b'0'), 3)) +try: + print(b"0000".index(ord(b'0'), 4)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(ord(b'0'), 5)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(ord(b'x'), 3)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(ord(b'1'), 3)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(ord(b'1'), 4)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(ord(b'1'), 5)) +except ValueError: + print("ValueError") + +# Non-ascii values (make sure not treated as unicode-like) +print(b"\x80abc".index(b"a", 1)) + +# Int-like conversion. +print(b"00\x0000".index(b'0', True)) + +# Out of bounds int. +try: + print(b"0000".index(b'0', -1)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(b'0', 256)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(b'0', 91273611)) +except ValueError: + print("ValueError") + +# Out of bounds search argument. +try: + print(b"0000".index(-1)) +except ValueError: + print("ValueError") +try: + print(b"0000".index(256)) +except ValueError: + print("ValueError") diff --git a/tests/basics/class_bind_self.py b/tests/basics/class_bind_self.py index 813f876446e..8bece902ca2 100644 --- a/tests/basics/class_bind_self.py +++ b/tests/basics/class_bind_self.py @@ -52,7 +52,7 @@ def f4(self, arg): # generator print(C.f8(13)) print(C.f9(14)) -# not working in uPy +# not working in MicroPython #class C(list): # # this acts like a method and binds self # f1 = list.extend diff --git a/tests/basics/class_descriptor.py b/tests/basics/class_descriptor.py index 83d31674301..feaed2fbb2a 100644 --- a/tests/basics/class_descriptor.py +++ b/tests/basics/class_descriptor.py @@ -1,22 +1,28 @@ class Descriptor: def __get__(self, obj, cls): - print('get') + print("get") print(type(obj) is Main) print(cls is Main) - return 'result' + return "result" def __set__(self, obj, val): - print('set') + print("set") print(type(obj) is Main) print(val) def __delete__(self, obj): - print('delete') + print("delete") print(type(obj) is Main) + def __set_name__(self, owner, name): + print("set_name", name) + print(owner.__name__ == "Main") + + class Main: Forward = Descriptor() + m = Main() try: m.__class__ @@ -26,15 +32,15 @@ class Main: raise SystemExit r = m.Forward -if 'Descriptor' in repr(r.__class__): +if "Descriptor" in repr(r.__class__): # Target doesn't support descriptors. - print('SKIP') + print("SKIP") raise SystemExit # Test assignment and deletion. print(r) -m.Forward = 'a' +m.Forward = "a" del m.Forward # Test that lookup of descriptors like __get__ are not passed into __getattr__. diff --git a/tests/basics/class_inplace_op2.py.exp b/tests/basics/class_inplace_op2.py.exp deleted file mode 100644 index 8c323b5178e..00000000000 --- a/tests/basics/class_inplace_op2.py.exp +++ /dev/null @@ -1,12 +0,0 @@ -__imul__ -__imatmul__ -__ifloordiv__ -__itruediv__ -__imod__ -__ipow__ -__ior__ -__ixor__ -__iand__ -__ilshift__ -__irshift__ -TypeError diff --git a/tests/basics/class_ordereddict.py.exp b/tests/basics/class_ordereddict.py.exp deleted file mode 100644 index b723e327515..00000000000 --- a/tests/basics/class_ordereddict.py.exp +++ /dev/null @@ -1 +0,0 @@ -['a', 'b', 'c', 'd', 'e'] diff --git a/tests/basics/class_setname_hazard.py b/tests/basics/class_setname_hazard.py new file mode 100644 index 00000000000..77c04093462 --- /dev/null +++ b/tests/basics/class_setname_hazard.py @@ -0,0 +1,182 @@ +# Test that __set_name__ can access and mutate its owner argument. + + +def skip_if_no_descriptors(): + class Descriptor: + def __get__(self, obj, cls): + return + + class TestClass: + Forward = Descriptor() + + a = TestClass() + try: + a.__class__ + except AttributeError: + # Target doesn't support __class__. + print("SKIP") + raise SystemExit + + b = a.Forward + if "Descriptor" in repr(b.__class__): + # Target doesn't support descriptors. + print("SKIP") + raise SystemExit + + +skip_if_no_descriptors() + + +# Test basic accesses and mutations. + + +class GetSibling: + def __set_name__(self, owner, name): + print(getattr(owner, name + "_sib")) + + +class GetSiblingTest: + desc = GetSibling() + desc_sib = 111 + + +t110 = GetSiblingTest() + + +class SetSibling: + def __set_name__(self, owner, name): + setattr(owner, name + "_sib", 121) + + +class SetSiblingTest: + desc = SetSibling() + + +t120 = SetSiblingTest() + +print(t120.desc_sib) + + +class DelSibling: + def __set_name__(self, owner, name): + delattr(owner, name + "_sib") + + +class DelSiblingTest: + desc = DelSibling() + desc_sib = 131 + + +t130 = DelSiblingTest() + +try: + print(t130.desc_sib) +except AttributeError: + print("AttributeError") + + +class GetSelf: + x = 211 + + def __set_name__(self, owner, name): + print(getattr(owner, name).x) + + +class GetSelfTest: + desc = GetSelf() + + +t210 = GetSelfTest() + + +class SetSelf: + def __set_name__(self, owner, name): + setattr(owner, name, 221) + + +class SetSelfTest: + desc = SetSelf() + + +t220 = SetSelfTest() + +print(t220.desc) + + +class DelSelf: + def __set_name__(self, owner, name): + delattr(owner, name) + + +class DelSelfTest: + desc = DelSelf() + + +t230 = DelSelfTest() + +try: + print(t230.desc) +except AttributeError: + print("AttributeError") + + +# Test exception behavior. + + +class Raise: + def __set_name__(self, owner, name): + raise Exception() + + +try: + + class RaiseTest: + desc = Raise() +except Exception as e: # CPython raises RuntimeError, MicroPython propagates the original exception + print("Exception") + + +# Ensure removed/overwritten class members still get __set_name__ called. + + +class SetSpecific: + def __init__(self, sib_name, sib_replace): + self.sib_name = sib_name + self.sib_replace = sib_replace + + def __set_name__(self, owner, name): + setattr(owner, self.sib_name, self.sib_replace) + + +class SetReplaceTest: + a = SetSpecific("b", 312) # one of these is changed first + b = SetSpecific("a", 311) + + +t310 = SetReplaceTest() +print(t310.a) +print(t310.b) + + +class DelSpecific: + def __init__(self, sib_name): + self.sib_name = sib_name + + def __set_name__(self, owner, name): + delattr(owner, self.sib_name) + + +class DelReplaceTest: + a = DelSpecific("b") # one of these is removed first + b = DelSpecific("a") + + +t320 = DelReplaceTest() +try: + print(t320.a) +except AttributeError: + print("AttributeError") +try: + print(t320.b) +except AttributeError: + print("AttributeError") diff --git a/tests/basics/class_setname_hazard_rand.py b/tests/basics/class_setname_hazard_rand.py new file mode 100644 index 00000000000..4c9934c3bf0 --- /dev/null +++ b/tests/basics/class_setname_hazard_rand.py @@ -0,0 +1,111 @@ +# Test to make sure there's no sequence hazard even when a __set_name__ implementation +# mutates and reorders the namespace of its owner class. +# VERY hard bug to prove out except via a stochastic test. + + +try: + from random import choice + import re +except ImportError: + print("SKIP") + raise SystemExit + + +def skip_if_no_descriptors(): + class Descriptor: + def __get__(self, obj, cls): + return + + class TestClass: + Forward = Descriptor() + + a = TestClass() + try: + a.__class__ + except AttributeError: + # Target doesn't support __class__. + print("SKIP") + raise SystemExit + + b = a.Forward + if "Descriptor" in repr(b.__class__): + # Target doesn't support descriptors. + print("SKIP") + raise SystemExit + + +skip_if_no_descriptors() + +letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +# Would be r"[A-Z]{5}", but not all ports support the {n} quantifier. +junk_re = re.compile(r"[A-Z][A-Z][A-Z][A-Z][A-Z]") + + +def junk_fill(obj, n=10): # Add randomly-generated attributes to an object. + for i in range(n): + name = "".join(choice(letters) for j in range(5)) + setattr(obj, name, object()) + + +def junk_clear(obj): # Remove attributes added by junk_fill. + to_del = [name for name in dir(obj) if junk_re.match(name)] + for name in to_del: + delattr(obj, name) + + +def junk_sequencer(): + global runs + try: + while True: + owner, name = yield + runs[name] = runs.get(name, 0) + 1 + junk_fill(owner) + finally: + junk_clear(owner) + + +class JunkMaker: + def __set_name__(self, owner, name): + global seq + seq.send((owner, name)) + + +runs = {} +seq = junk_sequencer() +next(seq) + + +class Main: + a = JunkMaker() + b = JunkMaker() + c = JunkMaker() + d = JunkMaker() + e = JunkMaker() + f = JunkMaker() + g = JunkMaker() + h = JunkMaker() + i = JunkMaker() + j = JunkMaker() + k = JunkMaker() + l = JunkMaker() + m = JunkMaker() + n = JunkMaker() + o = JunkMaker() + p = JunkMaker() + q = JunkMaker() + r = JunkMaker() + s = JunkMaker() + t = JunkMaker() + u = JunkMaker() + v = JunkMaker() + w = JunkMaker() + x = JunkMaker() + y = JunkMaker() + z = JunkMaker() + + +seq.close() + +for k in letters.lower(): + print(k, runs.get(k, 0)) diff --git a/tests/basics/del_attr.py b/tests/basics/del_attr.py index 8487b97e311..90a8a5a6f83 100644 --- a/tests/basics/del_attr.py +++ b/tests/basics/del_attr.py @@ -35,5 +35,5 @@ def f(): try: del int.to_bytes except (AttributeError, TypeError): - # uPy raises AttributeError, CPython raises TypeError + # MicroPython raises AttributeError, CPython raises TypeError print('AttributeError/TypeError') diff --git a/tests/basics/del_global.py b/tests/basics/del_global.py index d740357b033..e1aa074b97a 100644 --- a/tests/basics/del_global.py +++ b/tests/basics/del_global.py @@ -14,7 +14,7 @@ def do_del(): try: do_del() except: # NameError: - # FIXME uPy returns KeyError for this + # FIXME MicroPython returns KeyError for this print("NameError") # delete globals using a list diff --git a/tests/basics/del_name.py b/tests/basics/del_name.py index c92be54d3b6..8393b2df92a 100644 --- a/tests/basics/del_name.py +++ b/tests/basics/del_name.py @@ -10,7 +10,7 @@ try: del x except: # NameError: - # FIXME uPy returns KeyError for this + # FIXME MicroPython returns KeyError for this print("NameError") class C: diff --git a/tests/basics/deque_micropython.py b/tests/basics/deque_micropython.py index 5f32bbc496a..fb9771fefeb 100644 --- a/tests/basics/deque_micropython.py +++ b/tests/basics/deque_micropython.py @@ -45,12 +45,12 @@ try: d.popleft() except IndexError as e: - print(repr(e)) + print(str(e) or 'empty', len(d)) try: d.pop() except IndexError as e: - print(repr(e)) + print(str(e) or 'empty', len(d)) d.append(5) d.append(6) @@ -58,12 +58,12 @@ try: d.append(7) except IndexError as e: - print(repr(e)) + print(str(e) or 'full', len(d)) try: d.appendleft(8) except IndexError as e: - print(repr(e)) + print(str(e) or 'full', len(d)) print(len(d)) @@ -72,4 +72,4 @@ try: d.popleft() except IndexError as e: - print(repr(e)) + print(str(e) or 'empty', len(d)) diff --git a/tests/basics/deque_micropython.py.exp b/tests/basics/deque_micropython.py.exp index f1ff7b77ac8..7869dc8cacc 100644 --- a/tests/basics/deque_micropython.py.exp +++ b/tests/basics/deque_micropython.py.exp @@ -6,12 +6,12 @@ None 1 2 3 4 -IndexError('empty',) -IndexError('empty',) +empty 0 +empty 0 2 -IndexError('full',) -IndexError('full',) +full 2 +full 2 2 5 6 0 -IndexError('empty',) +empty 0 diff --git a/tests/basics/dict_views.py b/tests/basics/dict_views.py index a82f47b6be2..45f3238f1c6 100644 --- a/tests/basics/dict_views.py +++ b/tests/basics/dict_views.py @@ -6,6 +6,11 @@ # print a view with more than one item print({1:1, 2:1}.values()) +# `bool` and `len` unary ops +for d in ({}, {1: 2}, {1: 2, 3: 4}): + for op in (bool, len): + print(op(d.keys()), op(d.values()), op(d.items())) + # unsupported binary op on a dict values view try: {1:1}.values() + 1 diff --git a/tests/basics/exception_chain.py b/tests/basics/exception_chain.py index 579756c85fa..96c06c847ab 100644 --- a/tests/basics/exception_chain.py +++ b/tests/basics/exception_chain.py @@ -1,5 +1,12 @@ # CIRCUITPY-CHANGE: exception chaining is supported +import sys + +# The unix minimal build doesn't enable MICROPY_WARNINGS (required for this test). +if getattr(sys.implementation, "_build", None) == "minimal": + print("SKIP") + raise SystemExit + try: Exception().__cause__ except AttributeError: diff --git a/tests/basics/frozenset_set.py b/tests/basics/frozenset_set.py index 3bf456acfd7..2b3c6832609 100644 --- a/tests/basics/frozenset_set.py +++ b/tests/basics/frozenset_set.py @@ -8,5 +8,5 @@ # "Instances of set are compared to instances of frozenset based on their # members. For example:" print(set('abc') == frozenset('abc')) -# This doesn't work in uPy +# This doesn't work in MicroPython #print(set('abc') in set([frozenset('abc')])) diff --git a/tests/basics/fun_callstar_kwarg.py b/tests/basics/fun_callstar_kwarg.py new file mode 100644 index 00000000000..15bc19e216e --- /dev/null +++ b/tests/basics/fun_callstar_kwarg.py @@ -0,0 +1,8 @@ +# A CPython syntax feature not supported by MicroPython. For more information +# see `this issue `_. +# and tests/cpydiff/core_function_star.py + +try: + exec("f(y=1, *(3,))") +except SyntaxError as e: + print("SyntaxError") diff --git a/tests/basics/async_syntaxerror.py.exp b/tests/basics/fun_callstar_kwarg.py.exp similarity index 50% rename from tests/basics/async_syntaxerror.py.exp rename to tests/basics/fun_callstar_kwarg.py.exp index 5275689b413..8729fc43437 100644 --- a/tests/basics/async_syntaxerror.py.exp +++ b/tests/basics/fun_callstar_kwarg.py.exp @@ -1,2 +1 @@ SyntaxError -SyntaxError diff --git a/tests/basics/fun_code.py b/tests/basics/fun_code.py index 59e1f7ec048..841357e8aad 100644 --- a/tests/basics/fun_code.py +++ b/tests/basics/fun_code.py @@ -34,3 +34,8 @@ def f(): ftype(f.__code__, None) except TypeError: print("TypeError") + +# Test __code__ on functions with children functions. +code = (lambda: (lambda: a)).__code__ +print(ftype(code, {"a": 1})()()) +print(ftype(code, {"a": 2})()()) diff --git a/tests/basics/fun_code_colines.py b/tests/basics/fun_code_colines.py new file mode 100644 index 00000000000..a8867770edd --- /dev/null +++ b/tests/basics/fun_code_colines.py @@ -0,0 +1,81 @@ +# Check that we have sensical bytecode offsets in function.__code__.co_lines + +def f1(x, y, obj, obj2, obj3): + a = x + y # line 4: bc+4 line+4 + b = x - y # line 5: bc+4 line+1 + # line 6 + # line 7 + # line 8 + # line 9 + # line 10 + # line 11 + # line 12 + # line 13 + # line 14 + # line 15 + # line 16 + # line 17 + # line 18 + # line 19 + c = a * b # line 20: bc+4 line+15 + obj.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.fun() # line 21: bc+31 line+1; bc+27 line+0 + # line 22 + # line 23 + # line 24: bc+0 line+3 + # line 25 + # line 26 + # line 27: bc+0 line+3 + # line 28 + # line 29 + obj2.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.fun() # line 30: bc+31 line+3; bc+27 line+0 + # line 31 + # line 32 + # line 33: bc+0 line+3 + # line 34 + # line 35 + # line 36 + # line 37 + # line 38 + # line 39 + # line 40 + # line 41 + # line 42 + # line 43 + # line 44 + # line 45 + # line 46 + # line 47 + # line 48 + # line 49 + # line 50 + # line 51 + # line 52 + # line 53 + # line 54 + # line 55 + # line 56 + # line 57 + # line 58 + # line 59 + return obj3.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.fun() # line 60: bc+31 line+27; bc+27 line+0 + +def f2(x, y): + a = x + y # line 63 + b = x - y # line 64 + return a * b # line 65 + +try: + f1.__code__.co_lines +except AttributeError: + print("SKIP") + raise SystemExit + +print("f1") +for start, end, line_no in f1.__code__.co_lines(): + print("line {} start: {}".format(line_no, start)) + print("line {} end: {}".format(line_no, end)) + +print("f2") +for start, end, line_no in f2.__code__.co_lines(): + print("line {} start: {}".format(line_no, start)) + print("line {} end: {}".format(line_no, end)) diff --git a/tests/basics/fun_code_colines.py.exp b/tests/basics/fun_code_colines.py.exp new file mode 100644 index 00000000000..19bd4ef6e2a --- /dev/null +++ b/tests/basics/fun_code_colines.py.exp @@ -0,0 +1,20 @@ +f1 +line 4 start: 0 +line 4 end: 4 +line 5 start: 4 +line 5 end: 8 +line 20 start: 8 +line 20 end: 12 +line 21 start: 12 +line 21 end: 70 +line 30 start: 70 +line 30 end: 128 +line 60 start: 128 +line 60 end: 186 +f2 +line 63 start: 0 +line 63 end: 4 +line 64 start: 4 +line 64 end: 8 +line 65 start: 8 +line 65 end: 12 diff --git a/tests/basics/fun_code_full.py b/tests/basics/fun_code_full.py new file mode 100644 index 00000000000..538863631a6 --- /dev/null +++ b/tests/basics/fun_code_full.py @@ -0,0 +1,38 @@ +# Test function.__code__ attributes not available with MICROPY_PY_BUILTINS_CODE <= MICROPY_PY_BUILTINS_CODE_BASIC + +try: + (lambda: 0).__code__.co_code +except AttributeError: + print("SKIP") + raise SystemExit + +def f(x, y): + a = x + y + b = x - y + return a * b + +code = f.__code__ + +print(type(code.co_code)) # both bytes (but mpy and cpy have different instruction sets) +print(code.co_consts) # (not necessarily the same set, but in this function they are) +print(code.co_filename.rsplit('/')[-1]) # same terminal filename but might be different paths on other ports +print(type(code.co_firstlineno)) # both ints (but mpy points to first line inside, cpy points to declaration) +print(code.co_name) +print(iter(code.co_names) is not None) # both iterable (but mpy returns dict with names as keys, cpy only the names; and not necessarily the same set) + +co_lines = code.co_lines() + +l = list(co_lines) +first_start = l[0][0] +last_end = l[-1][1] +print(first_start) # co_lines should start at the start of the bytecode +print(len(code.co_code) - last_end) # and end at the end of the bytecode + +prev_end = 0 +for start, end, line_no in l: + if end != prev_end: + print("non-contiguous") + break # the offset ranges should be contiguous + prev_end = end +else: + print("contiguous") diff --git a/tests/basics/fun_code_full.py.exp b/tests/basics/fun_code_full.py.exp new file mode 100644 index 00000000000..830effadfc6 --- /dev/null +++ b/tests/basics/fun_code_full.py.exp @@ -0,0 +1,9 @@ + +(None,) +fun_code_full.py + +f +True +0 +0 +non-contiguous diff --git a/tests/basics/fun_code_lnotab.py b/tests/basics/fun_code_lnotab.py new file mode 100644 index 00000000000..9223e5730f0 --- /dev/null +++ b/tests/basics/fun_code_lnotab.py @@ -0,0 +1,34 @@ +# Test deprecation of co_lnotab + +try: + (lambda: 0).__code__.co_code +except AttributeError: + print("SKIP") + raise SystemExit + + +import unittest +import sys + + +mpy_is_v2 = getattr(sys.implementation, '_v2', False) + + +def f(): + pass + + +class Test(unittest.TestCase): + + @unittest.skipIf(mpy_is_v2, "Removed in MicroPython v2 and later.") + def test_co_lnotab_exists(self): + self.assertIsInstance(f.__code__.co_lnotab, bytes) + + @unittest.skipUnless(mpy_is_v2, "Not removed before MicroPython v2.") + def test_co_lnotab_removed(self): + with self.assertRaises(AttributeError): + f.__code__.co_lnotab + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/basics/fun_code_micropython.py b/tests/basics/fun_code_micropython.py deleted file mode 100644 index 2c319a2db8c..00000000000 --- a/tests/basics/fun_code_micropython.py +++ /dev/null @@ -1,19 +0,0 @@ -# Test MicroPython-specific restrictions of function.__code__ attribute. - -try: - (lambda: 0).__code__ -except AttributeError: - print("SKIP") - raise SystemExit - - -def f_with_children(): - def g(): - pass - - -# Can't access __code__ when function has children. -try: - f_with_children.__code__ -except AttributeError: - print("AttributeError") diff --git a/tests/basics/fun_code_micropython.py.exp b/tests/basics/fun_code_micropython.py.exp deleted file mode 100644 index d169edffb4c..00000000000 --- a/tests/basics/fun_code_micropython.py.exp +++ /dev/null @@ -1 +0,0 @@ -AttributeError diff --git a/tests/basics/fun_name.py b/tests/basics/fun_name.py index b2642280a2a..8aac35eeafa 100644 --- a/tests/basics/fun_name.py +++ b/tests/basics/fun_name.py @@ -16,7 +16,7 @@ def Fun(self): print('SKIP') raise SystemExit -# __name__ of a bound native method is not implemented in uPy +# __name__ of a bound native method is not implemented in MicroPython # the test here is to make sure it doesn't crash try: str((1).to_bytes.__name__) diff --git a/tests/basics/gc1.py b/tests/basics/gc1.py index 332bf9744c0..dff9538b14b 100644 --- a/tests/basics/gc1.py +++ b/tests/basics/gc1.py @@ -15,13 +15,13 @@ gc.collect() if hasattr(gc, 'mem_free'): - # uPy has these extra functions + # MicroPython has these extra functions # just test they execute and return an int assert type(gc.mem_free()) is int assert type(gc.mem_alloc()) is int if hasattr(gc, 'threshold'): - # uPy has this extra function + # MicroPython has this extra function # check execution and returns assert(gc.threshold(1) is None) assert(gc.threshold() == 0) diff --git a/tests/basics/gen_yield_from_close.py b/tests/basics/gen_yield_from_close.py index a493a410353..981c810564b 100644 --- a/tests/basics/gen_yield_from_close.py +++ b/tests/basics/gen_yield_from_close.py @@ -75,9 +75,9 @@ def gen6(): yield -1 try: print((yield from gen5())) - except GeneratorExit: + except GeneratorExit as e: print("delegating caught GeneratorExit") - raise + raise e yield 10 yield 11 diff --git a/tests/basics/generator_pend_throw.py b/tests/basics/generator_pend_throw.py index ae8c21189e9..6cecd418dd0 100644 --- a/tests/basics/generator_pend_throw.py +++ b/tests/basics/generator_pend_throw.py @@ -46,7 +46,7 @@ def gen_next(): try: next(g) except Exception as e: - print("raised", repr(e)) + print("raised {} {}".format(type(e), str(e) or "generator already executing")) # Verify that you can't pend_throw from within the running coroutine. @@ -59,7 +59,7 @@ def gen_pend_throw(): try: next(g) except Exception as e: - print("raised", repr(e)) + print("raised {} {}".format(type(e), str(e) or "generator already executing")) # Verify that the pend_throw exception can be ignored. diff --git a/tests/basics/generator_pend_throw.py.exp b/tests/basics/generator_pend_throw.py.exp index 8a3dadfec7a..56fa68be252 100644 --- a/tests/basics/generator_pend_throw.py.exp +++ b/tests/basics/generator_pend_throw.py.exp @@ -3,8 +3,8 @@ raised ValueError() ret was: None raised OSError() -raised ValueError('generator already executing',) -raised ValueError('generator already executing',) +raised generator already executing +raised generator already executing 0 ignore CancelledError 1 diff --git a/tests/basics/import_instance_method.py b/tests/basics/import_instance_method.py new file mode 100644 index 00000000000..d25b70ac5f0 --- /dev/null +++ b/tests/basics/import_instance_method.py @@ -0,0 +1,38 @@ +# Test importing a method from a class instance. +# This is not a common thing to do, but ensures MicroPython has the same semantics as CPython. + +import sys + +if not hasattr(sys, "modules"): + print("SKIP") + raise SystemExit + + +class A: + def __init__(self, value): + self.value = value + + def meth(self): + return self.value + + def meth_with_arg(self, a): + return [self.value, a] + + +# Register a class instance as the module "mod". +sys.modules["mod"] = A(1) + +# Try importing it as a module. +import mod + +print(mod.meth()) +print(mod.meth_with_arg(2)) + +# Change the module. +sys.modules["mod"] = A(3) + +# Try importing it using "from ... import". +from mod import meth, meth_with_arg + +print(meth()) +print(meth_with_arg(4)) diff --git a/tests/basics/import_star_nonmodule.py b/tests/basics/import_star_nonmodule.py new file mode 100644 index 00000000000..8a98ef26ce5 --- /dev/null +++ b/tests/basics/import_star_nonmodule.py @@ -0,0 +1,65 @@ +# Test "from x import *" where x is something other than a module. + +import sys + +try: + next(iter([]), 42) +except TypeError: + # Two-argument version of next() not supported. We are probably not at + # MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES which is needed for "import *". + print("SKIP") + raise SystemExit + +print("== test with a class as a module ==") + + +class M: + x = "a1" + + def __init__(self): + self.x = "a2" + + +sys.modules["mod"] = M +from mod import * + +print(x) + +sys.modules["mod"] = M() +from mod import * + +print(x) + +print("== test with a class as a module that overrides __all__ ==") + + +class M: + __all__ = ("y",) + x = "b1" + y = "b2" + + def __init__(self): + self.__all__ = ("x",) + self.x = "b3" + self.y = "b4" + + +sys.modules["mod"] = M +x = None +from mod import * + +print(x, y) + +sys.modules["mod"] = M() +from mod import * + +print(x, y) + +print("== test with objects that don't have a __dict__ ==") + +sys.modules["mod"] = 1 +try: + from mod import * + # MicroPython raises AttributeError, CPython raises ImportError. +except (AttributeError, ImportError): + print("ImportError") diff --git a/tests/basics/int_64_basics.py b/tests/basics/int_64_basics.py new file mode 100644 index 00000000000..b9d46c7d701 --- /dev/null +++ b/tests/basics/int_64_basics.py @@ -0,0 +1,161 @@ +# test support for 64-bit long integers +# (some ports don't support arbitrary precision but do support these) + +# this test is adapted from int_big1.py with numbers kept within 64-bit signed range + +# to test arbitrary precision integers + +x = 1000000000000000000 +xn = -1000000000000000000 +y = 2000000000000000000 + +# printing +print(x) +print(y) +print('%#X' % (x - x)) # print prefix +print('{:#,}'.format(x)) # print with commas + +# construction +print(int(x)) + +# addition +print(x + 1) +print(x + y) +print(x + xn == 0) +print(bool(x + xn)) + +# subtraction +print(x - 1) +print(x - y) +print(y - x) +print(x - x == 0) +print(bool(x - x)) + +# multiplication +print(x * 2) +print(1090511627776 * 1048500) + +# integer division +print(x // 2) +print(y // x) + +# bit inversion +print(~x) +print(~(-x)) + +# left shift +print("left shift positive") +x = 0x40000000 +for i in range(32): + x = x << 1 + print(x) + +# right shift +print("right shift positive") +x = 0x2000000000000000 # TODO: why can't second-tip bit be set? +for i in range(64): + x = x >> 1 + print(x) + +# left shift of a negative number +print("left shift negative") +for i in range(8): + print(-10000000000000000 << i) + print(-10000000000000001 << i) + print(-10000000000000002 << i) + print(-10000000000000003 << i) + print(-10000000000000004 << i) + + +# right shift of a negative number +print("right shift negative") +for i in range(8): + print(-1000000000000000000 >> i) + print(-1000000000000000001 >> i) + print(-1000000000000000002 >> i) + print(-1000000000000000003 >> i) + print(-1000000000000000004 >> i) + +# conversion from string +print(int("1234567890123456789")) +print(int("-1234567890123456789")) +print(int("1234567890abcdef", 16)) +print(int("1234567890ABCDEF", 16)) +print(int("-1234567890ABCDEF", 16)) +print(int("ijklmnopqrsz", 36)) + +# numbers close to 64-bit limits +print(int("-9111222333444555666")) +print(int("9111222333444555666")) + +# numbers with preceding 0s +print(int("-00000000000000000000009111222333444555666")) +print(int("0000000000000000000000009111222333444555666")) + +# invalid characters in string +try: + print(int("1234567890abcdef")) +except ValueError: + print('ValueError'); +try: + print(int("123456789\x01")) +except ValueError: + print('ValueError'); + +# test parsing ints just on threshold of small to big +# for 32 bit archs +x = 1073741823 # small +x = -1073741823 # small +x = 1073741824 # big +x = -1073741824 # big +# for 64 bit archs +x = 4611686018427387903 # small +x = -4611686018427387903 # small +x = 4611686018427387904 # big +x = -4611686018427387904 # big + +# sys.maxsize is a constant bigint, so test it's compatible with dynamic ones +import sys +if hasattr(sys, "maxsize"): + print(sys.maxsize - 1 + 1 == sys.maxsize) +else: + print(True) # No maxsize property in this config + +# test extraction of big int value via mp_obj_get_int_maybe +x = 1 << 62 +print('a' * (x + 4 - x)) + +# test overflow check in mp_obj_get_int_maybe +x = 1 << 32 +r = None +try: + r = range(0, x) +except OverflowError: + # 32-bit target, correctly handled the overflow of x + print("ok") +if r is not None: + if len(r) == x: + # 64-bit target, everything is just a small-int + print("ok") + else: + # 32-bit target that did not handle the overflow of x + print("unhandled overflow") + +# negative shifts are invalid +try: + print((1 << 48) >> -4) +except ValueError as e: + print(str(e) or "negative shift count") + +try: + print((1 << 48) << -6) +except ValueError as e: + print(str(e) or "negative shift count") + +# Test that the most extreme 64 bit integer values all parse with int() +print(int("-9223372036854775807")) +print(int("-9223372036854775808")) +print(int("9223372036854775807")) + +# Test that the most negative 64 bit integer can be formed via arithmetic +print(-9223372036854775807-1) diff --git a/tests/basics/int_big_to_small.py b/tests/basics/int_big_to_small.py index 64280d0c635..c92d263fc28 100644 --- a/tests/basics/int_big_to_small.py +++ b/tests/basics/int_big_to_small.py @@ -5,6 +5,17 @@ print("SKIP") raise SystemExit +# Skip this test on "REPR B" where (1<<29 + 1) is not a small int. +k = 1 << 29 +micropython.heap_lock() +try: + k = k + 1 +except MemoryError: + print("SKIP") + raise SystemExit +finally: + micropython.heap_unlock() + # All less than small int max. for d in (0, 27, 1<<29, -1861, -(1<<29)): i = 1<<70 diff --git a/tests/basics/int_big_to_small_int29.py b/tests/basics/int_big_to_small_int29.py new file mode 100644 index 00000000000..438a74d2bc6 --- /dev/null +++ b/tests/basics/int_big_to_small_int29.py @@ -0,0 +1,22 @@ +try: + import micropython + micropython.heap_lock +except: + print("SKIP") + raise SystemExit + +# All less than small int max. +for d in (0, 27, 1<<28, -1861, -(1<<28)): + i = 1<<70 + print(i) + j = (1<<70) + d + print(j) + # k should now be a small int. + k = j - i + print(k) + + # Now verify that working with k doesn't allocate (i.e. it's a small int). + micropython.heap_lock() + print(k + 20) + print(k // 20) + micropython.heap_unlock() diff --git a/tests/basics/int_big_to_small_int29.py.exp b/tests/basics/int_big_to_small_int29.py.exp new file mode 100644 index 00000000000..0920101924a --- /dev/null +++ b/tests/basics/int_big_to_small_int29.py.exp @@ -0,0 +1,25 @@ +1180591620717411303424 +1180591620717411303424 +0 +20 +0 +1180591620717411303424 +1180591620717411303451 +27 +47 +1 +1180591620717411303424 +1180591620717679738880 +268435456 +268435476 +13421772 +1180591620717411303424 +1180591620717411301563 +-1861 +-1841 +-94 +1180591620717411303424 +1180591620717142867968 +-268435456 +-268435436 +-13421773 diff --git a/tests/basics/int_bytes.py b/tests/basics/int_bytes.py index d1999bebb0e..7a1edc2ccec 100644 --- a/tests/basics/int_bytes.py +++ b/tests/basics/int_bytes.py @@ -1,11 +1,15 @@ -# CIRCUITPY-CHANGE: signed support +import sys + print((10).to_bytes(1, "little")) print((-10).to_bytes(1, "little", signed=True)) # Test fitting in length that's not a power of two. -print((0x10000).to_bytes(3, 'little')) +print((0x10000).to_bytes(3, "little")) print((111111).to_bytes(4, "little")) print((-111111).to_bytes(4, "little", signed=True)) print((100).to_bytes(10, "little")) +print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little")) +print(int.from_bytes(b"\x01\0\0\0\0\0\0\0", "little")) +print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little")) print((-100).to_bytes(10, "little", signed=True)) # check that extra zero bytes don't change the internal int value @@ -32,19 +36,6 @@ except OverflowError: print("OverflowError") -# CIRCUITPY-CHANGE: more tests -# too small buffer should raise an error -try: - (256).to_bytes(1, "little") -except OverflowError: - print("OverflowError") - -# negative numbers should raise an error if signed=False -try: - (-256).to_bytes(2, "little") -except OverflowError: - print("OverflowError") - # except for converting 0 to a zero-length byte array print((0).to_bytes(0, "big")) @@ -58,11 +49,54 @@ # OverFlowError if not big enough +try: + (0x123).to_bytes(1, "big") +except OverflowError: + print("OverflowError") + +try: + (0x12345).to_bytes(2, "big") +except OverflowError: + print("OverflowError") + +try: + (0x1234567).to_bytes(3, "big") +except OverflowError: + print("OverflowError") + + +# negative representations + +print((-1).to_bytes(1, "little", signed=True)) +print((-1).to_bytes(3, "little", signed=True)) +print((-1).to_bytes(1, "big", signed=True)) +print((-1).to_bytes(3, "big", signed=True)) +print((-128).to_bytes(1, "big", signed=True)) +print((-32768).to_bytes(2, "big", signed=True)) +print((-(1 << 23)).to_bytes(3, "big", signed=True)) + +# negative numbers should raise an error if signed=False, regardless of fitting or not try: (-256).to_bytes(2, "little", signed=False) except OverflowError: print("OverflowError") -# byteorder arg can be omitted; default is "big" -print(int.from_bytes(b"\x01\0")) -print((100).to_bytes(10)) +try: + (-1).to_bytes(1, "little") +except OverflowError: + print("OverflowError") + +try: + print((-129).to_bytes(1, "big")) +except OverflowError: + print("OverflowError") + +try: + print((-32769).to_bytes(2, "big")) +except OverflowError: + print("OverflowError") + +try: + print((-(1 << 23) - 1).to_bytes(2, "big")) +except OverflowError: + print("OverflowError") diff --git a/tests/basics/int_bytes_int64.py b/tests/basics/int_bytes_int64.py index 032dbccc5b1..2ca87f20dee 100644 --- a/tests/basics/int_bytes_int64.py +++ b/tests/basics/int_bytes_int64.py @@ -5,7 +5,7 @@ # long longs. try: - x = int.from_bytes(b"\x6F\xAB\xCD\x12\x34\x56\x78\xFB", "big") + x = int.from_bytes(b"\x6f\xab\xcd\x12\x34\x56\x78\xfb", "big") except OverflowError: print("SKIP") # Port can't represent this size of integer at all raise SystemExit @@ -36,17 +36,8 @@ # negative representations -# MicroPython int.to_bytes() behaves as if signed=True for negative numbers -if "micropython" in repr(sys.implementation): +x = -x - def to_bytes_compat(i, l, e): - return i.to_bytes(l, e) -else: - # Implement MicroPython compatible behaviour for CPython - def to_bytes_compat(i, l, e): - return i.to_bytes(l, e, signed=i < 0) - - -print(to_bytes_compat(-x, 8, "little")) -print(to_bytes_compat(-x, 20, "big")) -print(to_bytes_compat(-x, 20, "little")) +print(x.to_bytes(8, "little", signed=True)) +print(x.to_bytes(20, "big", signed=True)) +print(x.to_bytes(20, "little", signed=True)) diff --git a/tests/basics/int_bytes_intbig.py b/tests/basics/int_bytes_intbig.py index 073c8bf7892..6d3265ddb1d 100644 --- a/tests/basics/int_bytes_intbig.py +++ b/tests/basics/int_bytes_intbig.py @@ -4,11 +4,10 @@ import sys -# CIRCUITPY-CHANGE: signed support print((2**64).to_bytes(9, "little")) -print((-2**64).to_bytes(9, "little", signed=True)) +print((-(2**64)).to_bytes(9, "little", signed=True)) print((2**64).to_bytes(9, "big")) -print((-2**64).to_bytes(9, "big", signed=True)) +print((-(2**64)).to_bytes(9, "big", signed=True)) b = bytes(range(20)) @@ -26,50 +25,69 @@ # check that extra zero bytes don't change the internal int value print(int.from_bytes(b + bytes(10), "little") == int.from_bytes(b, "little")) -# CIRCUITPY-CHANGE: more tests -# too small buffer should raise an error +# can't write to a zero-length bytes object try: - (2**64).to_bytes(8, "little") + ib.to_bytes(0, "little") except OverflowError: print("OverflowError") -# negative numbers should raise an error if signed=False +# or one that is too short try: - (-2**64).to_bytes(9, "little") + ib.to_bytes(18, "big") except OverflowError: print("OverflowError") -# negative representations - -# MicroPython int.to_bytes() behaves as if signed=True for negative numbers -if "micropython" in repr(sys.implementation): - - def to_bytes_compat(i, l, e): - return i.to_bytes(l, e) -else: - # Implement MicroPython compatible behaviour for CPython - def to_bytes_compat(i, l, e): - return i.to_bytes(l, e, signed=i < 0) - - -print(to_bytes_compat(-ib, 20, "big")) -print(to_bytes_compat(ib * -ib, 40, "big")) - -# case where an additional byte is needed for sign bit -ib = (2**64) - 1 -print(ib.to_bytes(8, "little")) - -ib *= -1 - +# including when signed try: - (-2**64).to_bytes(9, "little", signed=False) + ib.to_bytes(18, "big", signed=True) except OverflowError: print("OverflowError") + +# negative representations + +# negative numbers should raise an error if signed=False try: - print(to_bytes_compat(ib, 8, "little")) + (-(2**64)).to_bytes(9, "little", signed=False) except OverflowError: print("OverflowError") -print(to_bytes_compat(ib, 9, "little")) -print(to_bytes_compat(ib, 9, "big")) +print((-ib).to_bytes(20, "big", signed=True)) +print((ib * -ib).to_bytes(40, "big", signed=True)) + +# cases where an additional byte is needed for sign bit + +MAX_U24 = (2**24) - 1 +MAX_U32 = (2**32) - 1 +MAX_U64 = (2**64) - 1 + +for ib, nbytes in ( + (-127, 1), + (255, 1), + (-255, 1), + (65535, 2), + (-65535, 2), + (-65534, 2), + (MAX_U24, 3), + (-MAX_U24, 3), + (1 - MAX_U24, 3), + (MAX_U32, 4), + (-MAX_U32, 4), + (1 - MAX_U32, 4), + (2 - MAX_U32, 4), + (MAX_U64, 8), + (-MAX_U64, 8), + (1 - MAX_U64, 8), + (2 - MAX_U64, 8), + (2 * MAX_U64, 8), + (-2 * MAX_U64, 8), +): + print("ib", hex(ib), "nbytes", nbytes, ":") + for signed in False, True: + for endian in "little", "big": + for nbytes_offs in (-1, 0, 1): + try: + as_bytes = ib.to_bytes(nbytes + nbytes_offs, endian, signed=signed) + except OverflowError: + as_bytes = "OverflowError" + print(as_bytes, "signed", signed, "endian", endian, "nbytes_offs", nbytes_offs) diff --git a/tests/basics/io_buffered_writer.py b/tests/basics/io_buffered_writer.py index 11df0324e24..3cfee0103f7 100644 --- a/tests/basics/io_buffered_writer.py +++ b/tests/basics/io_buffered_writer.py @@ -1,10 +1,10 @@ -import io - try: + import io + io.BytesIO io.BufferedWriter -except AttributeError: - print("SKIP") +except (AttributeError, ImportError): + print('SKIP') raise SystemExit bts = io.BytesIO() @@ -28,3 +28,27 @@ # hashing a BufferedWriter print(type(hash(buf))) + +# Test failing flush() +class MyIO(io.IOBase): + def __init__(self): + self.count = 0 + + def write(self, buf): + self.count += 1 + if self.count < 3: + return None + print("writing", buf) + return len(buf) + + +buf = io.BufferedWriter(MyIO(), 8) + +buf.write(b"foobar") + +for _ in range(4): + try: + buf.flush() + print("flushed") + except OSError: + print("OSError") diff --git a/tests/basics/io_buffered_writer.py.exp b/tests/basics/io_buffered_writer.py.exp index 2209348f5af..d61eb148b45 100644 --- a/tests/basics/io_buffered_writer.py.exp +++ b/tests/basics/io_buffered_writer.py.exp @@ -4,3 +4,8 @@ b'foobarfoobar' b'foobarfoobar' b'foo' +OSError +OSError +writing bytearray(b'foobar') +flushed +flushed diff --git a/tests/basics/io_bytesio_cow.py b/tests/basics/io_bytesio_cow.py index 2edb7136a96..543c12ad42a 100644 --- a/tests/basics/io_bytesio_cow.py +++ b/tests/basics/io_bytesio_cow.py @@ -1,6 +1,12 @@ # Make sure that write operations on io.BytesIO don't # change original object it was constructed from. -import io + +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + b = b"foobar" a = io.BytesIO(b) diff --git a/tests/basics/io_bytesio_ext.py b/tests/basics/io_bytesio_ext.py index 4d4c60c1363..92e71517811 100644 --- a/tests/basics/io_bytesio_ext.py +++ b/tests/basics/io_bytesio_ext.py @@ -1,5 +1,11 @@ # Extended stream operations on io.BytesIO -import io + +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + a = io.BytesIO(b"foobar") a.seek(10) print(a.read(10)) diff --git a/tests/basics/io_bytesio_ext2.py b/tests/basics/io_bytesio_ext2.py index 414ac90a3b0..f60a6a9a604 100644 --- a/tests/basics/io_bytesio_ext2.py +++ b/tests/basics/io_bytesio_ext2.py @@ -1,4 +1,9 @@ -import io +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + a = io.BytesIO(b"foobar") try: a.seek(-10) diff --git a/tests/basics/io_iobase.py b/tests/basics/io_iobase.py index b2ee5cd63a6..31f2616310e 100644 --- a/tests/basics/io_iobase.py +++ b/tests/basics/io_iobase.py @@ -1,15 +1,17 @@ import io try: + import io + io.IOBase -except AttributeError: +except (AttributeError, ImportError): print("SKIP") raise SystemExit class MyIO(io.IOBase): def write(self, buf): - # CPython and uPy pass in different types for buf (str vs bytearray) - print("write", len(buf)) + # CPython and MicroPython pass in different types for buf (str vs bytearray) + print('write', len(buf)) return len(buf) -print("test", file=MyIO()) +print('test', file=MyIO()) diff --git a/tests/basics/io_stringio1.py b/tests/basics/io_stringio1.py index 7d355930f5a..889e3ce6973 100644 --- a/tests/basics/io_stringio1.py +++ b/tests/basics/io_stringio1.py @@ -1,4 +1,9 @@ -import io +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + a = io.StringIO() print('io.StringIO' in repr(a)) print(a.getvalue()) diff --git a/tests/basics/io_stringio_base.py b/tests/basics/io_stringio_base.py index 0f65fb3fabc..c8890dab73a 100644 --- a/tests/basics/io_stringio_base.py +++ b/tests/basics/io_stringio_base.py @@ -1,7 +1,11 @@ # Checks that an instance type inheriting from a native base that uses # MP_TYPE_FLAG_ITER_IS_STREAM will still have a getiter. -import io +try: + import io +except ImportError: + print("SKIP") + raise SystemExit a = io.StringIO() a.write("hello\nworld\nmicro\npython\n") diff --git a/tests/basics/io_stringio_with.py b/tests/basics/io_stringio_with.py index a3aa6ec84e0..0155ad5382d 100644 --- a/tests/basics/io_stringio_with.py +++ b/tests/basics/io_stringio_with.py @@ -1,4 +1,9 @@ -import io +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + # test __enter__/__exit__ with io.StringIO() as b: b.write("foo") diff --git a/tests/basics/io_write_ext.py b/tests/basics/io_write_ext.py index 79f7450954e..5af1de7a6c3 100644 --- a/tests/basics/io_write_ext.py +++ b/tests/basics/io_write_ext.py @@ -1,11 +1,12 @@ # This tests extended (MicroPython-specific) form of write: # write(buf, len) and write(buf, offset, len) -import io try: + import io + io.BytesIO -except AttributeError: - print("SKIP") +except (AttributeError, ImportError): + print('SKIP') raise SystemExit buf = io.BytesIO() diff --git a/tests/basics/lexer.py b/tests/basics/lexer.py index addb8a13df3..dfdc0b9900d 100644 --- a/tests/basics/lexer.py +++ b/tests/basics/lexer.py @@ -91,3 +91,11 @@ def a(x): eval("01") except SyntaxError: print("SyntaxError") + +# Bytes 0-8 inclusive are not allowed in input stream. +# Earlier CPython (eg 3.10.12) raises ValueError, later CPython (eg 3.11.14) raises SyntaxError. +for invalid_byte_value in range(0, 10): + try: + print(eval(b"123" + bytes([invalid_byte_value]))) + except (ValueError, SyntaxError): + print("byte {}: SyntaxError".format(invalid_byte_value)) diff --git a/tests/basics/list_pop.py b/tests/basics/list_pop.py index 87ed456f851..58bcdd91e41 100644 --- a/tests/basics/list_pop.py +++ b/tests/basics/list_pop.py @@ -10,7 +10,7 @@ else: raise AssertionError("No IndexError raised") -# popping such that list storage shrinks (tests implementation detail of uPy) +# popping such that list storage shrinks (tests implementation detail of MicroPython) l = list(range(20)) for i in range(len(l)): l.pop() diff --git a/tests/basics/module2.py b/tests/basics/module2.py index a135601579c..d1dc18930f0 100644 --- a/tests/basics/module2.py +++ b/tests/basics/module2.py @@ -1,4 +1,4 @@ -# uPy behaviour only: builtin modules are read-only +# MicroPython behaviour only: builtin modules are read-only import sys try: sys.x = 1 diff --git a/tests/basics/namedtuple1.py b/tests/basics/namedtuple1.py index 362c60583ec..b9689b58423 100644 --- a/tests/basics/namedtuple1.py +++ b/tests/basics/namedtuple1.py @@ -21,6 +21,9 @@ print(isinstance(t, tuple)) + # a NamedTuple can be used as a tuple + print("(%d, %d)" % t) + # Check tuple can compare equal to namedtuple with same elements print(t == (t[0], t[1]), (t[0], t[1]) == t) diff --git a/tests/basics/parser.py b/tests/basics/parser.py index 626b67ad7a9..6ae5f05ba45 100644 --- a/tests/basics/parser.py +++ b/tests/basics/parser.py @@ -7,7 +7,7 @@ raise SystemExit # completely empty string -# uPy and CPy differ for this case +# MPy and CPy differ for this case #try: # compile("", "stdin", "single") #except SyntaxError: diff --git a/tests/basics/python34.py b/tests/basics/python34.py index 922234d22db..3071b55eff8 100644 --- a/tests/basics/python34.py +++ b/tests/basics/python34.py @@ -28,7 +28,7 @@ def test_syntax(code): test_syntax("del ()") # can't delete empty tuple (in 3.6 we can) # from basics/sys1.py -# uPy prints version 3.4 +# MicroPython prints version 3.4 import sys print(sys.version[:3]) print(sys.version_info[0], sys.version_info[1]) diff --git a/tests/basics/python36.py.exp b/tests/basics/python36.py.exp deleted file mode 100644 index 4b65daafa18..00000000000 --- a/tests/basics/python36.py.exp +++ /dev/null @@ -1,5 +0,0 @@ -100000 -165 -65535 -123 -83 diff --git a/tests/basics/self_type_check.py b/tests/basics/self_type_check.py index 3bd5b3eed60..5f6f6f2ca65 100644 --- a/tests/basics/self_type_check.py +++ b/tests/basics/self_type_check.py @@ -3,6 +3,14 @@ import skip_if skip_if.board_in("gemma_m0", "trinket_m0") +import sys + +# Minimal builds usually don't enable MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG, +# which is required for this test. +if getattr(sys.implementation, "_build", None) == "minimal": + print("SKIP") + raise SystemExit + list.append try: diff --git a/tests/basics/slice_optimise.py b/tests/basics/slice_optimise.py new file mode 100644 index 00000000000..f663e16b8c2 --- /dev/null +++ b/tests/basics/slice_optimise.py @@ -0,0 +1,23 @@ +# Test that the slice-on-stack optimisation does not break various uses of slice +# (see MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE type option). +# +# Note: this test has a corresponding .py.exp file because hashing slice objects +# was not allowed in CPython until 3.12. + +try: + from collections import OrderedDict +except ImportError: + print("SKIP") + raise SystemExit + +# Attempt to index with a slice, error should contain the slice (failed key). +try: + dict()[:] +except KeyError as e: + print("KeyError", e.args) + +# Put a slice and another object into an OrderedDict, and retrieve them. +x = OrderedDict() +x[:"a"] = 1 +x["b"] = 2 +print(list(x.keys()), list(x.values())) diff --git a/tests/basics/slice_optimise.py.exp b/tests/basics/slice_optimise.py.exp new file mode 100644 index 00000000000..3fa59aae15a --- /dev/null +++ b/tests/basics/slice_optimise.py.exp @@ -0,0 +1,2 @@ +KeyError (slice(None, None, None),) +[slice(None, 'a', None), 'b'] [1, 2] diff --git a/tests/basics/special_methods2.py.exp b/tests/basics/special_methods2.py.exp deleted file mode 100644 index a9ae75be55c..00000000000 --- a/tests/basics/special_methods2.py.exp +++ /dev/null @@ -1,19 +0,0 @@ -__pos__ called -__pos__ called -__neg__ called -__invert__ called -__mul__ called -__matmul__ called -__truediv__ called -__floordiv__ called -__iadd__ called -__isub__ called -__mod__ called -__pow__ called -__or__ called -__and__ called -__xor__ called -__lshift__ called -__rshift__ called -['a', 'b', 'c'] -False diff --git a/tests/basics/string_find.py b/tests/basics/string_find.py index f9fcad3e579..f37064ad291 100644 --- a/tests/basics/string_find.py +++ b/tests/basics/string_find.py @@ -24,6 +24,7 @@ print("aaaaaaaaaaa".find("bbb", 9, 2)) try: + # Only works on bytes/bytearray. 'abc'.find(1) except TypeError: print('TypeError') diff --git a/tests/basics/string_format.py b/tests/basics/string_format.py index e8600f58361..11e7836a73e 100644 --- a/tests/basics/string_format.py +++ b/tests/basics/string_format.py @@ -22,7 +22,17 @@ def test(fmt, *args): test("{:4x}", 123) test("{:4X}", 123) +test("{:4,d}", 1) +test("{:4_d}", 1) +test("{:4_o}", 1) +test("{:4_b}", 1) +test("{:4_x}", 1) + test("{:4,d}", 12345678) +test("{:4_d}", 12345678) +test("{:4_o}", 12345678) +test("{:4_b}", 12345678) +test("{:4_x}", 12345678) test("{:#4b}", 10) test("{:#4o}", 123) diff --git a/tests/basics/string_format_sep.py b/tests/basics/string_format_sep.py new file mode 100644 index 00000000000..de131fdaf33 --- /dev/null +++ b/tests/basics/string_format_sep.py @@ -0,0 +1,9 @@ +try: + "%d" % 1 +except TypeError: + print("SKIP") + raise SystemExit + +for v in (0, 0x10, 0x1000, -0x10, -0x1000): + for sz in range(1, 12): print(("{:0%d,d}" % sz).format(v)) + for sz in range(1, 12): print(("{:0%d_x}" % sz).format(v)) diff --git a/tests/basics/string_fstring.py b/tests/basics/string_fstring.py index d94cc0cd3e6..03e2d90a8f7 100644 --- a/tests/basics/string_fstring.py +++ b/tests/basics/string_fstring.py @@ -31,6 +31,8 @@ def foo(a, b): # PEP-0498 specifies that handling of double braces '{{' or '}}' should # behave like str.format. +print(f'{{') +print(f'}}') print(f'{{}}') print(f'{{{4*10}}}', '{40}') @@ -79,3 +81,7 @@ def foo(a, b): # Raw f-strings. print(rf"\r\a\w {'f'} \s\t\r\i\n\g") print(fr"\r{x}") + +# Format specifiers with nested replacement fields +radix = "x" +print(f"{314:{radix}}") diff --git a/tests/basics/string_fstring_debug.py.exp b/tests/basics/string_fstring_debug.py.exp deleted file mode 100644 index f0309e1c98a..00000000000 --- a/tests/basics/string_fstring_debug.py.exp +++ /dev/null @@ -1,9 +0,0 @@ -x=1 -x=00000001 -a x=1 b 2 c -a x=00000001 b 2 c -a f() + g("foo") + h()=15 b -a f() + g("foo") + h()=0000000f b -a 1,=(1,) b -a x,y,=(1, 2) b -a x,1=(1, 1) b diff --git a/tests/basics/string_fstring_nested.py b/tests/basics/string_fstring_nested.py new file mode 100644 index 00000000000..82de0bf6470 --- /dev/null +++ b/tests/basics/string_fstring_nested.py @@ -0,0 +1,9 @@ +# Test nesting of f-strings within f-strings. + +x = 1 + +# 2-level nesting, with padding. +print(f"a{f'b{x:2}c':>5}d") + +# 4-level nesting using the different styles of quotes. +print(f"""a{f'''b{f"c{f'd{x}e'}f"}g'''}h""") diff --git a/tests/basics/string_fstring_nested_py312.py b/tests/basics/string_fstring_nested_py312.py new file mode 100644 index 00000000000..aa731b1637d --- /dev/null +++ b/tests/basics/string_fstring_nested_py312.py @@ -0,0 +1,7 @@ +# Test nesting of f-strings within f-strings. +# These test rely on Python 3.12+ to use the same quote style for nesting. + +x = 1 + +# 8-level nesting using the same quote style. +print(f"a{f"b{f"c{f"d{f"e{f"f{f"g{f"h{x}i"}j"}k"}l"}m"}n"}o"}p") diff --git a/tests/basics/string_fstring_nested_py312.py.exp b/tests/basics/string_fstring_nested_py312.py.exp new file mode 100644 index 00000000000..1d624933dff --- /dev/null +++ b/tests/basics/string_fstring_nested_py312.py.exp @@ -0,0 +1 @@ +abcdefgh1ijklmnop diff --git a/tests/basics/string_index.py b/tests/basics/string_index.py index 31f6900e6c1..328f2dff54c 100644 --- a/tests/basics/string_index.py +++ b/tests/basics/string_index.py @@ -76,3 +76,9 @@ print("Raised ValueError") else: print("Did not raise ValueError") + +try: + # Only works on bytes/bytearray. + 'abc'.index(1) +except TypeError: + print('TypeError') diff --git a/tests/basics/string_module_tstring.py b/tests/basics/string_module_tstring.py new file mode 100644 index 00000000000..83809926926 --- /dev/null +++ b/tests/basics/string_module_tstring.py @@ -0,0 +1,6 @@ +# Test basic templatelib functionality. +# This test requires t-strings support. + +from string.templatelib import Template + +print("templatelib", isinstance(t"hi", Template)) diff --git a/tests/basics/string_module_tstring.py.exp b/tests/basics/string_module_tstring.py.exp new file mode 100644 index 00000000000..26dba98f403 --- /dev/null +++ b/tests/basics/string_module_tstring.py.exp @@ -0,0 +1 @@ +templatelib True diff --git a/tests/basics/string_tstring_basic.py b/tests/basics/string_tstring_basic.py new file mode 100644 index 00000000000..aa9de327b59 --- /dev/null +++ b/tests/basics/string_tstring_basic.py @@ -0,0 +1,339 @@ +from string.templatelib import Template, Interpolation + +print("=== Basic functionality ===") +t = t"Hello World" +print(type(t).__name__) + +name = "World" +t2 = t"Hello {name}" +print(f"Strings: {t2.strings}") +print(f"Value: {t2.interpolations[0].value}") +print(f"str(): {str(t2)}") + +t_raw = rt"Path: C:\test\{name}" +print(f"Raw: '{t_raw.strings[0]}'") + +t_tr = tr"Path: C:\test\{name}" +print(f"tr: '{t_tr.strings[0]}'") + +print("\n=== Parser tests ===") +data = {"a": {"b": [1, 2, 3]}} +t_complex = t"{data['a']['b'][0]}" +print(f"Complex: {str(t_complex)}") + +print(f"None: {str(t'{None}')}") +print(f"True: {str(t'{True}')}") +print(f"False: {str(t'{False}')}") +print(f"Ellipsis: {str(t'{...}')}") + +obj = type('Obj', (), { + '__getattr__': lambda s, n: s, + '__getitem__': lambda s, k: s, + '__call__': lambda s, *a: 42, + '__str__': lambda s: "42" +})() +print(f"Deep nest: {str(t'{obj.a.b[0].c()}')}") + +print("\n=== Conversions and formatting ===") +val = {"key": "value"} +print(f"repr: {str(t'{val!r}')}") +print(f"str: {str(t'{val!s}')}") +# print(f"ascii: {str(t'{val!a}')}") + +print(f"Width: '{str(t'{42:10d}')}'") +print(f"Precision: {str(t'{3.14159:.2f}')}") + +x = 42 +t_debug = t"{x=}" +assert t_debug.strings == ("x=", "") +assert t_debug.interpolations[0].expression == "x" +assert t_debug.interpolations[0].conversion == "r" +assert t_debug.interpolations[0].value == 42 +print(f"Debug: {str(t_debug)}") + +y = 10 +t_debug2 = t"{x + y=}" +assert t_debug2.strings == ("x + y=", "") +assert t_debug2.interpolations[0].expression == "x + y" +assert t_debug2.interpolations[0].conversion == "r" +assert t_debug2.interpolations[0].value == 52 + +pi = 3.14159 +t_debug3 = t"{pi=:.2f}" +assert t_debug3.strings == ("pi=", "") +assert t_debug3.interpolations[0].expression == "pi" +assert t_debug3.interpolations[0].conversion is None +assert t_debug3.interpolations[0].format_spec == ".2f" +assert t_debug3.interpolations[0].value == 3.14159 + +print("\n=== Constructor tests ===") +t_empty = Template() +print(f"Empty: {t_empty.strings}") + +t_single = Template("single") +print(f"Single: {t_single.strings}") + +t_multi = Template("a", "b", "c") +print(f"Multi: {t_multi.strings}") + +i1 = Interpolation(1, "x") +i2 = Interpolation(2, "y") +t_mixed = Template("start", i1, "middle", i2, "end") +print(f"Mixed: strings={t_mixed.strings}, values={t_mixed.values}") + +print("\n=== Operations ===") +t1 = t"Hello" +t2 = t" World" +t_concat = t1 + t2 +print(f"Concat: '{str(t_concat)}'") + +items = list(t"a{1}b{2}c") +print(f"Iterator: {[type(x).__name__ for x in items]}") + +t_attr = t"test{42}" +print(f"strings attr: {t_attr.strings}") +print(f"interpolations attr: {len(t_attr.interpolations)}") +print(f"values attr: {t_attr.values}") + +print(f"repr: {repr(t2)[:50]}...") + +print("\n=== Escaped braces evaluation ===") +t_escaped = Template("{", Interpolation(42, "x"), "}", Interpolation(42, "x"), "{{", Interpolation(42, "x"), "}}") +print(f"Escaped eval: '{str(t_escaped)}'") + +t_braces = Template("{{hello}}", Interpolation(1, "a"), " {", Interpolation(2, "b"), "} ", Interpolation(3, "c"), "{{world}}") +print(f"Braces in strings: '{str(t_braces)}'") + +print("\n=== Memory stress test ===") +for n in [10, 20, 30]: + args = [] + for i in range(n): + args.append("s") + args.append(Interpolation(i, f"var{i}")) + args.append("s") + t_mem = Template(*args) + result = str(t_mem) + print(f"Memory test [{n}]: {len(result)} chars") + +large_args = [] +for i in range(20): + large_args.append("") + large_args.append(Interpolation(i, f"v{i}")) +large_args.append("") +t_large = Template(*large_args) +print(f"Large values: {len(t_large.values)} values") + +print("\n=== Nested quotes and braces tests ===") +t_nested1 = t"{"{}"}" +print(f"Nested quotes 1: {str(t_nested1)}") +print(f" Value: {t_nested1.interpolations[0].value}") +print(f" Expression: {t_nested1.interpolations[0].expression}") + +t_nested2 = t"{'hello'}" +print(f"Nested quotes 2: {str(t_nested2)}") +print(f" Value: {t_nested2.interpolations[0].value}") + +t_nested3 = t'{"world"}' +print(f"Nested quotes 3: {str(t_nested3)}") +print(f" Value: {t_nested3.interpolations[0].value}") + +t_nested4 = t"{['a', 'b', 'c'][1]}" +print(f"Nested quotes 4: {str(t_nested4)}") +print(f" Value: {t_nested4.interpolations[0].value}") + +d = {"key": "value", "x": 123} +t_nested5 = t"{d['key']}" +print(f"Nested quotes 5: {str(t_nested5)}") +print(f" Value: {t_nested5.interpolations[0].value}") + +t_escaped1 = t'{{""}}' +print(f"Escaped braces 1: {str(t_escaped1)}") +print(f" Strings: {t_escaped1.strings}") + +t_escaped2 = t"{{}}}}" +print(f"Escaped braces 2: {str(t_escaped2)}") +print(f" Strings: {t_escaped2.strings}") + +x = "test" +t_mixed = t"{{before}} {x} {{after}}" +print(f"Mixed escaped: {str(t_mixed)}") +print(f" Strings: {t_mixed.strings}") +print(f" Value: {t_mixed.interpolations[0].value}") + +t_escape = t"{'\n\t'}" +print(f"Escape sequences: {str(t_escape)}") +print(f" Value repr: {repr(t_escape.interpolations[0].value)}") + +inner = "{}" +t_nested_expr = t"{inner}" +print(f"Nested expr: {str(t_nested_expr)}") +print(f" Value: {t_nested_expr.interpolations[0].value}") + +print("\n=== Interpolation attribute tests ===") +i_basic = Interpolation(42, "x") +print(f"Basic conversion: {i_basic.conversion}") +# Put in quotes to make empty string visible. +print(f"Basic format_spec: '{i_basic.format_spec}'") + +i_with_conv = Interpolation(42, "x", "s") +print(f"With conversion: {i_with_conv.conversion}") + +i_with_fmt = Interpolation(42, "x", None, ":>10") +print(f"With format_spec: {i_with_fmt.format_spec}") + +i_full = Interpolation(42, "x", "r", ":>10") +print(f"Full conversion: {i_full.conversion}") +print(f"Full format_spec: {i_full.format_spec}") + +t_conv = t"{42!s}" +print(f"Template conversion: {t_conv.interpolations[0].conversion}") + +t_fmt = t"{42:>10}" +print(f"Template format_spec: {t_fmt.interpolations[0].format_spec}") + +t_both = t"{42!r:>10}" +print(f"Both conversion: {t_both.interpolations[0].conversion}") +print(f"Both format_spec: {t_both.interpolations[0].format_spec}") + +print("\n=== Escape sequence tests ===") +print(repr(t"Line1\nLine2")) +print(repr(t"Path\\to\\file")) +print(repr(t"It\'s working")) +print(repr(t"She said \"Hello\"")) +print(repr(t"Bell\a")) +print(repr(t"Back\bspace")) +print(repr(t"Tab\there")) +print(repr(t"Vertical\vtab")) +print(repr(t"Form\ffeed")) +print(repr(t"Carriage\rreturn")) + +# Valid hex escapes +print(repr(t"\x41")) +print(repr(t"\x7F")) + +# Valid octal escapes +print(repr(t"\0")) +print(repr(t"\7")) +print(repr(t"\77")) +print(repr(t"\101")) + +print(repr(t"\1a")) +print(repr(t"\123c")) + +# Line continuation +print(repr(t"First \ +second")) +print(repr(t"One\ +Two\ +Three")) + +# Multiple escapes +print(repr(t"\n\t\r")) + +# Raw strings +print(repr(rt"\n\t\x41")) +print(repr(rt"C:\new\test")) + +# Triple quoted strings +print(repr(t"""\n\t\x41""")) +print(repr(rt"""\n\t\x41""")) + +print("\n=== Triple quote edge cases ===") +doc = '''This is a +multi-line +docstring''' +result1 = t"""Documentation: +{doc} +End of doc""" +print(f"Triple in interpolation: {str(result1)}") +print(f" Value: {repr(result1.interpolations[0].value)}") + +data = { + "users": [ + {"name": "Alice", "msg": 'Say "Hello"'}, + {"name": "Bob", "msg": "It's great!"} + ] +} +complex_nested = t"""Users: +{data['users'][0]['name']}: {data['users'][0]['msg']} +{data['users'][1]['name']}: {data['users'][1]['msg']}""" +print(f"Complex nested: {str(complex_nested)}") +print(f" Values: {complex_nested.values}") + +import os +path_sep = os.sep +raw_with_interp = rt"""Path: C:\Users\{path_sep}Documents +Raw newline: \n +Raw tab: \t""" +print(f"Raw with interpolation: {str(raw_with_interp)}") +print(f" String 0 repr: {repr(raw_with_interp.strings[0])}") + +long_line = "x" * 50 +long_triple = t"""Start +{long_line} +End""" +print(f"Long line: strings={long_triple.strings}") +print(f" Value length: {len(long_triple.values[0])}") + +inner = t"inner {42}" +outer = t"""Outer template: +{inner} +End""" +print(f"Nested templates: {str(outer)}") +print(f" Inner value: {outer.values[0]}") + +formatted = t"""Math constants: +Pi: {314:.2f} +E: {271:.1e} +Sqrt(2): {141:.0f}""" +print(f"Formatted values: {repr(formatted)}") +print(f" Interpolation count: {len(formatted.interpolations)}") +print(f" Format specs: {[i.format_spec for i in formatted.interpolations]}") + +x, y, z = 1, 2, 3 +debug_complex = t"""Debug info: +{x + y=} {x * y * z=} {x < y < z=}""" +print(f"Debug complex: {repr(debug_complex)}") +print(f" Expressions: {[i.expression for i in debug_complex.interpolations]}") + +part1 = t"""Part 1 +with newline""" +part2 = t'''Part 2 +also multiline''' +concatenated = part1 + part2 +print(f"Concatenated triple: {repr(concatenated)}") +print(f" Strings: {concatenated.strings}") + +print("\n=== PEP 701 brace compliance ===") +t_brace1 = t"{{" +print(f"Escaped {{{{: {t_brace1.strings}") +assert t_brace1.strings == ('{',) + +t_brace2 = t"}}" +print(f"Escaped }}}}: {t_brace2.strings}") +assert t_brace2.strings == ('}',) + +t_brace3 = t"test{{escape}}here" +print(f"Mixed: {t_brace3.strings}") +assert t_brace3.strings == ('test{escape}here',) + +print("\n=== Format spec scope resolution ===") +def test_format_scope(): + width = 10 + x = 42 + t_scope = t"{x:{width}}" + print(f"Local vars: width={width}, x={x}") + print(f"Format spec: {t_scope.interpolations[0].format_spec}") + return t_scope.interpolations[0].format_spec == '10' + +result = test_format_scope() +print(f"Scope test: {'PASS' if result else 'FAIL'}") +assert result, "Format spec scope resolution failed" + +precision = 2 +value = 3.14159 +t_prec = t"{value:.{precision}f}" +print(f"Precision: format_spec={t_prec.interpolations[0].format_spec}") +assert t_prec.interpolations[0].format_spec == '.2f' + +print("\nBasic tests completed!") diff --git a/tests/basics/string_tstring_basic.py.exp b/tests/basics/string_tstring_basic.py.exp new file mode 100644 index 00000000000..60affaad499 --- /dev/null +++ b/tests/basics/string_tstring_basic.py.exp @@ -0,0 +1,141 @@ +=== Basic functionality === +Template +Strings: ('Hello ', '') +Value: World +str(): Template(strings=('Hello ', ''), interpolations=(Interpolation('World', 'name', None, ''),)) +Raw: 'Path: C:\test\' +tr: 'Path: C:\test\' + +=== Parser tests === +Complex: Template(strings=('', ''), interpolations=(Interpolation(1, "data['a']['b'][0]", None, ''),)) +None: Template(strings=('', ''), interpolations=(Interpolation(None, 'None', None, ''),)) +True: Template(strings=('', ''), interpolations=(Interpolation(True, 'True', None, ''),)) +False: Template(strings=('', ''), interpolations=(Interpolation(False, 'False', None, ''),)) +Ellipsis: Template(strings=('', ''), interpolations=(Interpolation(Ellipsis, '...', None, ''),)) +Deep nest: Template(strings=('', ''), interpolations=(Interpolation(42, 'obj.a.b[0].c()', None, ''),)) + +=== Conversions and formatting === +repr: Template(strings=('', ''), interpolations=(Interpolation({'key': 'value'}, 'val', 'r', ''),)) +str: Template(strings=('', ''), interpolations=(Interpolation({'key': 'value'}, 'val', 's', ''),)) +Width: 'Template(strings=('', ''), interpolations=(Interpolation(42, '42', None, '10d'),))' +Precision: Template(strings=('', ''), interpolations=(Interpolation(3.14159, '3.14159', None, '.2f'),)) +Debug: Template(strings=('x=', ''), interpolations=(Interpolation(42, 'x', 'r', ''),)) + +=== Constructor tests === +Empty: ('',) +Single: ('single',) +Multi: ('abc',) +Mixed: strings=('start', 'middle', 'end'), values=(1, 2) + +=== Operations === +Concat: 'Template(strings=('Hello World',), interpolations=())' +Iterator: ['str', 'Interpolation', 'str', 'Interpolation', 'str'] +strings attr: ('test', '') +interpolations attr: 1 +values attr: (42,) +repr: Template(strings=(' World',), interpolations=())... + +=== Escaped braces evaluation === +Escaped eval: 'Template(strings=('{', '}', '{{', '}}'), interpolations=(Interpolation(42, 'x', None, ''), Interpolation(42, 'x', None, ''), Interpolation(42, 'x', None, '')))' +Braces in strings: 'Template(strings=('{{hello}}', ' {', '} ', '{{world}}'), interpolations=(Interpolation(1, 'a', None, ''), Interpolation(2, 'b', None, ''), Interpolation(3, 'c', None, '')))' + +=== Memory stress test === +Memory test [10]: 450 chars +Memory test [20]: 880 chars +Memory test [30]: 1310 chars +Large values: 20 values + +=== Nested quotes and braces tests === +Nested quotes 1: Template(strings=('', ''), interpolations=(Interpolation('{}', '"{}"', None, ''),)) + Value: {} + Expression: "{}" +Nested quotes 2: Template(strings=('', ''), interpolations=(Interpolation('hello', "'hello'", None, ''),)) + Value: hello +Nested quotes 3: Template(strings=('', ''), interpolations=(Interpolation('world', '"world"', None, ''),)) + Value: world +Nested quotes 4: Template(strings=('', ''), interpolations=(Interpolation('b', "['a', 'b', 'c'][1]", None, ''),)) + Value: b +Nested quotes 5: Template(strings=('', ''), interpolations=(Interpolation('value', "d['key']", None, ''),)) + Value: value +Escaped braces 1: Template(strings=('{""}',), interpolations=()) + Strings: ('{""}',) +Escaped braces 2: Template(strings=('{}}',), interpolations=()) + Strings: ('{}}',) +Mixed escaped: Template(strings=('{before} ', ' {after}'), interpolations=(Interpolation('test', 'x', None, ''),)) + Strings: ('{before} ', ' {after}') + Value: test +Escape sequences: Template(strings=('', ''), interpolations=(Interpolation('\n\t', "'\\n\\t'", None, ''),)) + Value repr: '\n\t' +Nested expr: Template(strings=('', ''), interpolations=(Interpolation('{}', 'inner', None, ''),)) + Value: {} + +=== Interpolation attribute tests === +Basic conversion: None +Basic format_spec: '' +With conversion: s +With format_spec: :>10 +Full conversion: r +Full format_spec: :>10 +Template conversion: s +Template format_spec: >10 +Both conversion: r +Both format_spec: >10 + +=== Escape sequence tests === +Template(strings=('Line1\nLine2',), interpolations=()) +Template(strings=('Path\\to\\file',), interpolations=()) +Template(strings=("It's working",), interpolations=()) +Template(strings=('She said "Hello"',), interpolations=()) +Template(strings=('Bell\x07',), interpolations=()) +Template(strings=('Back\x08space',), interpolations=()) +Template(strings=('Tab\there',), interpolations=()) +Template(strings=('Vertical\x0btab',), interpolations=()) +Template(strings=('Form\x0cfeed',), interpolations=()) +Template(strings=('Carriage\rreturn',), interpolations=()) +Template(strings=('A',), interpolations=()) +Template(strings=('\x7f',), interpolations=()) +Template(strings=('\x00',), interpolations=()) +Template(strings=('\x07',), interpolations=()) +Template(strings=('?',), interpolations=()) +Template(strings=('A',), interpolations=()) +Template(strings=('\x01a',), interpolations=()) +Template(strings=('Sc',), interpolations=()) +Template(strings=('First second',), interpolations=()) +Template(strings=('OneTwoThree',), interpolations=()) +Template(strings=('\n\t\r',), interpolations=()) +Template(strings=('\\n\\t\\x41',), interpolations=()) +Template(strings=('C:\\new\\test',), interpolations=()) +Template(strings=('\n\tA',), interpolations=()) +Template(strings=('\\n\\t\\x41',), interpolations=()) + +=== Triple quote edge cases === +Triple in interpolation: Template(strings=('Documentation:\n', '\nEnd of doc'), interpolations=(Interpolation('This is a\nmulti-line\ndocstring', 'doc', None, ''),)) + Value: 'This is a\nmulti-line\ndocstring' +Complex nested: Template(strings=('Users:\n', ': ', '\n', ': ', ''), interpolations=(Interpolation('Alice', "data['users'][0]['name']", None, ''), Interpolation('Say "Hello"', "data['users'][0]['msg']", None, ''), Interpolation('Bob', "data['users'][1]['name']", None, ''), Interpolation("It's great!", "data['users'][1]['msg']", None, ''))) + Values: ('Alice', 'Say "Hello"', 'Bob', "It's great!") +Raw with interpolation: Template(strings=('Path: C:\\Users\\', 'Documents\nRaw newline: \\n\nRaw tab: \\t'), interpolations=(Interpolation('/', 'path_sep', None, ''),)) + String 0 repr: 'Path: C:\\Users\\' +Long line: strings=('Start\n', '\nEnd') + Value length: 50 +Nested templates: Template(strings=('Outer template:\n', '\nEnd'), interpolations=(Interpolation(Template(strings=('inner ', ''), interpolations=(Interpolation(42, '42', None, ''),)), 'inner', None, ''),)) + Inner value: Template(strings=('inner ', ''), interpolations=(Interpolation(42, '42', None, ''),)) +Formatted values: Template(strings=('Math constants:\nPi: ', '\nE: ', '\nSqrt(2): ', ''), interpolations=(Interpolation(314, '314', None, '.2f'), Interpolation(271, '271', None, '.1e'), Interpolation(141, '141', None, '.0f'))) + Interpolation count: 3 + Format specs: ['.2f', '.1e', '.0f'] +Debug complex: Template(strings=('Debug info:\nx + y=', ' x * y * z=', ' x < y < z=', ''), interpolations=(Interpolation(3, 'x + y', 'r', ''), Interpolation(6, 'x * y * z', 'r', ''), Interpolation(True, 'x < y < z', 'r', ''))) + Expressions: ['x + y', 'x * y * z', 'x < y < z'] +Concatenated triple: Template(strings=('Part 1\nwith newlinePart 2\nalso multiline',), interpolations=()) + Strings: ('Part 1\nwith newlinePart 2\nalso multiline',) + +=== PEP 701 brace compliance === +Escaped {{: ('{',) +Escaped }}: ('}',) +Mixed: ('test{escape}here',) + +=== Format spec scope resolution === +Local vars: width=10, x=42 +Format spec: 10 +Scope test: PASS +Precision: format_spec=.2f + +Basic tests completed! diff --git a/tests/basics/string_tstring_basic1.py b/tests/basics/string_tstring_basic1.py new file mode 100644 index 00000000000..89ee3e0d2d4 --- /dev/null +++ b/tests/basics/string_tstring_basic1.py @@ -0,0 +1,131 @@ +print("=== Parser error tests ===") +try: + exec('t_empty = t"{}"') + print(f"Empty expr: {t_empty.interpolations[0].value}") +except SyntaxError as e: + print(f"Empty expr: SyntaxError - {e}") + +# Whitespace in expression (Python semantics are to strip trailing) +t_ws = t"{ 42 }" +print(f"Whitespace: {str(t_ws)}") + +print("\n=== Error cases ===") +try: + exec('t"{@}"') +except SyntaxError: + print("Invalid syntax: SyntaxError") + +try: + long_expr = "x" * 10001 + exec(f't"{{{long_expr}}}"') +except (ValueError, SyntaxError, RuntimeError, NameError): + print("Long expr: Error") + +try: + exec('t"hello" "world"') +except SyntaxError: + print("Mixed concat: SyntaxError") + +try: + exec('bt"test"') +except SyntaxError: + print("bt prefix: SyntaxError") + +print("\n=== Escape sequence coverage tests ===") + +def expect_invalid_escape(label, expr): + try: + eval(expr) + except SyntaxError: + print(f"{label}: SyntaxError") + else: + print(f"{label}: ERROR (expected SyntaxError)") + +# Deprecated escape sequences (CPython warns, MicroPython accepts as literal) +print(repr(t"\8")) +print(repr(t"\9")) + +# Unknown escape chars +print(repr(t"\z")) +print(repr(t"\k")) + +# Invalid escapes +expect_invalid_escape("Invalid \\x escape", 't"\\xGG"') +expect_invalid_escape("Invalid \\u escape", 't"\\uGGGG"') +expect_invalid_escape("Invalid \\U escape", 't"\\UGGGGGGGG"') + +# Unicode escapes (display format differs) +print(repr(t"\x00\x01\xFF")) +print(repr(t"\u0041")) +print(repr(t"\u03B1")) +print(repr(t"\u2764")) +print(repr(t"\U00000041")) +print(repr(t"\U0001F600")) +print(repr(t"\x41\u0042\103")) + +# Unicode in triple-quoted strings +unicode_test = t"""Unicode test: +Emoji: {'\U0001f40d'} +Special: {'\u03b1 \u03b2 \u03b3'}""" +print(f"Unicode: {str(unicode_test)}") + +print("\n=== Trailing whitespace preservation (PEP 750) ===") +x = 42 +tmpl_trail = t"{x }" +expr = tmpl_trail.interpolations[0].expression +print(f"Expression with trailing spaces: |{expr}|") +assert expr == "x", f"Expected 'x' but got '{expr}'" +assert len(expr) == 1, f"Expected length 1 but got {len(expr)}" + +tmpl_both = t"{ x }" +expr2 = tmpl_both.interpolations[0].expression +print(f"Expression with both spaces: |{expr2}|") +assert expr2 == " x", f"Expected ' x' but got '{expr2}'" +assert len(expr2) == 4, f"Expected length 4 but got {len(expr2)}" + +tmpl_lead = t"{ x}" +expr3 = tmpl_lead.interpolations[0].expression +print(f"Expression with leading spaces: |{expr3}|") +assert expr3 == " x", f"Expected ' x' but got '{expr3}'" + +# Debug specifiers: leading space preserved, trailing space stripped from expression +# PEP 750: "Whitespace is preserved in the debug specifier" (in strings part) +z = 99 +t_debug4 = t"{z =}" +assert t_debug4.strings == ("z =", "") +assert t_debug4.interpolations[0].expression == "z" # Trailing space stripped +assert t_debug4.interpolations[0].conversion == "r" + +t_debug5 = t"{ z=}" +assert t_debug5.strings == (" z=", "") +assert t_debug5.interpolations[0].expression == " z" # Leading space preserved +assert t_debug5.interpolations[0].conversion == "r" + +t_debug6 = t"{ z =}" +assert t_debug6.strings == (" z =", "") +assert t_debug6.interpolations[0].expression == " z" # Leading preserved, trailing stripped +assert t_debug6.interpolations[0].conversion == "r" + +print("Trailing whitespace: PASS") + +print("\n=== Error message tests ===") +try: + exec('t"}"') +except SyntaxError: + print("Lone }} rejected (correct)") + +try: + exec('t"{"') +except SyntaxError: + print("Unterminated {{ rejected (correct)") + +print("\n=== Triple quote empty interpolation ===") +try: + exec('''empty_interp = t"""Start +{} +End"""''') + print(f"Empty interpolation: {str(empty_interp)}") +except Exception as e: + print(f"Empty interpolation error: {type(e).__name__}: {e}") + +print("\nIncompatible tests completed!") diff --git a/tests/basics/string_tstring_basic1.py.exp b/tests/basics/string_tstring_basic1.py.exp new file mode 100644 index 00000000000..7f2b0d85b60 --- /dev/null +++ b/tests/basics/string_tstring_basic1.py.exp @@ -0,0 +1,41 @@ +=== Parser error tests === +Empty expr: SyntaxError - malformed f-string +Whitespace: Template(strings=('', ''), interpolations=(Interpolation(42, ' 42', None, ''),)) + +=== Error cases === +Invalid syntax: SyntaxError +Long expr: Error +Mixed concat: SyntaxError +bt prefix: SyntaxError + +=== Escape sequence coverage tests === +Template(strings=('\\8',), interpolations=()) +Template(strings=('\\9',), interpolations=()) +Template(strings=('\\z',), interpolations=()) +Template(strings=('\\k',), interpolations=()) +Invalid \x escape: SyntaxError +Invalid \u escape: SyntaxError +Invalid \U escape: SyntaxError +Template(strings=('\x00\x01ÿ',), interpolations=()) +Template(strings=('A',), interpolations=()) +Template(strings=('α',), interpolations=()) +Template(strings=('❤',), interpolations=()) +Template(strings=('A',), interpolations=()) +Template(strings=('😀',), interpolations=()) +Template(strings=('ABC',), interpolations=()) +Unicode: Template(strings=('Unicode test:\nEmoji: ', '\nSpecial: ', ''), interpolations=(Interpolation('🐍', "'\\U0001f40d'", None, ''), Interpolation('α β γ', "'\\u03b1 \\u03b2 \\u03b3'", None, ''))) + +=== Trailing whitespace preservation (PEP 750) === +Expression with trailing spaces: |x| +Expression with both spaces: | x| +Expression with leading spaces: | x| +Trailing whitespace: PASS + +=== Error message tests === +Lone }} rejected (correct) +Unterminated {{ rejected (correct) + +=== Triple quote empty interpolation === +Empty interpolation error: SyntaxError: malformed f-string + +Incompatible tests completed! diff --git a/tests/basics/string_tstring_constructor.py b/tests/basics/string_tstring_constructor.py new file mode 100644 index 00000000000..dc4a09a9578 --- /dev/null +++ b/tests/basics/string_tstring_constructor.py @@ -0,0 +1,112 @@ +from string.templatelib import Template, Interpolation + +print("=== Constructor basic usage ===") +t = Template("hello ", Interpolation(42, "x"), "world") +print(f"Template repr: {repr(t)}") + +t_varargs = Template("Hello ", Interpolation("World", "name"), "!") +print(f"Varargs constructor: strings={t_varargs.strings}, values={t_varargs.values}") + +t_concat = Template("A", "B", Interpolation(1, "value"), "C", "D") +print(f"Varargs merged strings: {t_concat.strings}") + +t_leading = Template(Interpolation(1, "x"), " tail") +print(f"Leading interpolation strings: {t_leading.strings}") + +t_trailing = Template("head ", Interpolation(2, "y")) +print(f"Trailing interpolation strings: {t_trailing.strings}") + +t_interps_only = Template(Interpolation(1, "x"), Interpolation(2, "y")) +print(f"Interpolation only strings: {t_interps_only.strings}") + +print("\n=== Special cases ===") + +i = Interpolation(42, "x", "s", ":>10") +try: + i.value = 100 +except AttributeError: + print("Interp read-only: AttributeError") + +t_ws_trim = Template("", Interpolation(None, " ", None, ""), "") +print(f"Whitespace trim: '{t_ws_trim}'") + +t_debug = Template("", Interpolation(42, "x=", None, ""), "") +print(f"Debug =: {t_debug}") + + +class Custom: + def __repr__(self): + return "CustomRepr" + + def __str__(self): + return "CustomStr" + + +obj = Custom() +print(f"Custom !r: {t'{obj!r}'}") +print(f"Custom !s: {t'{obj!s}'}") + +t_empty_start = Template("", Interpolation(1, "1"), "text") +print(f"Empty start iter: {[type(x).__name__ for x in t_empty_start]}") + +t_iter_edge = Template("", Interpolation(1, "1"), "", Interpolation(2, "2"), "") +iter_items = [] +for item in t_iter_edge: + iter_items.append(type(item).__name__) +print(f"Iterator edge: {iter_items}") + +print("\n=== Values property ===") +for n in range(7): + args = [] + for i in range(n): + args.append("") + args.append(Interpolation(i, str(i))) + args.append("") + t = Template(*args) + print(f"Values[{n}]: {t.values}") + +print("\n=== Multiple consecutive strings ===") +try: + t = Template("first", "second", "third", Interpolation(42, "x"), "fourth", "fifth") + if t.strings == ("firstsecondthird", "fourthfifth"): + print("Multiple strings concatenated: OK") + else: + print(f"Multiple strings: strings={t.strings}") +except Exception as e: + print(f"Multiple strings error: {e}") + +print("\n=== Template() constructor with many interpolations ===") +try: + exprs = ["a", "b", "c", "d", "e"] + interps = [Interpolation(i, exprs[i % len(exprs)]) for i in range(20)] + strings = [""] * 21 + t = Template(*strings, *interps) + print(f"Template() constructor: OK ({len(t.interpolations)} interpolations)") +except Exception as e: + print(f"Template() constructor: {type(e).__name__}") + +print("\n=== vstr string concatenation ===") +try: + t1 = Template("part1", "part2", "part3", "part4", Interpolation(1, "x"), "end") + result = str(t1) + print(f"vstr concat: '{result}'") +except Exception as e: + print(f"vstr concat error: {e}") + +print("\n=== High byte handling ===") +try: + result = t"\x7f\x80\x81\xfe\xff" + first_str = result.strings[0] + print( + f"High bytes: len={len(first_str)}, first=0x{ord(first_str[0]):02x}, last=0x{ord(first_str[-1]):02x}" + ) +except Exception as e: + print(f"High bytes error: {e}") + +try: + result = t"\200\201\377" + print(f"Octal high bytes: OK, len={len(result.strings[0])}") +except Exception as e: + print(f"Octal high bytes error: {e}") + +print("\nConstructor tests completed!") diff --git a/tests/basics/string_tstring_constructor.py.exp b/tests/basics/string_tstring_constructor.py.exp new file mode 100644 index 00000000000..e7d6ea90a9b --- /dev/null +++ b/tests/basics/string_tstring_constructor.py.exp @@ -0,0 +1,40 @@ +=== Constructor basic usage === +Template repr: Template(strings=('hello ', 'world'), interpolations=(Interpolation(42, 'x', None, ''),)) +Varargs constructor: strings=('Hello ', '!'), values=('World',) +Varargs merged strings: ('AB', 'CD') +Leading interpolation strings: ('', ' tail') +Trailing interpolation strings: ('head ', '') +Interpolation only strings: ('', '', '') + +=== Special cases === +Interp read-only: AttributeError +Whitespace trim: 'Template(strings=('', ''), interpolations=(Interpolation(None, ' ', None, ''),))' +Debug =: Template(strings=('', ''), interpolations=(Interpolation(42, 'x=', None, ''),)) +Custom !r: Template(strings=('', ''), interpolations=(Interpolation(CustomRepr, 'obj', 'r', ''),)) +Custom !s: Template(strings=('', ''), interpolations=(Interpolation(CustomRepr, 'obj', 's', ''),)) +Empty start iter: ['Interpolation', 'str'] +Iterator edge: ['Interpolation', 'Interpolation'] + +=== Values property === +Values[0]: () +Values[1]: (0,) +Values[2]: (0, 1) +Values[3]: (0, 1, 2) +Values[4]: (0, 1, 2, 3) +Values[5]: (0, 1, 2, 3, 4) +Values[6]: (0, 1, 2, 3, 4, 5) + +=== Multiple consecutive strings === +Multiple strings concatenated: OK + +=== Template() constructor with many interpolations === +Template() constructor: OK (20 interpolations) + +=== vstr string concatenation === +vstr concat: 'Template(strings=('part1part2part3part4', 'end'), interpolations=(Interpolation(1, 'x', None, ''),))' + +=== High byte handling === +High bytes: len=5, first=0x7f, last=0xff +Octal high bytes: OK, len=3 + +Constructor tests completed! diff --git a/tests/basics/string_tstring_constructor1.py b/tests/basics/string_tstring_constructor1.py new file mode 100644 index 00000000000..1593efa9d79 --- /dev/null +++ b/tests/basics/string_tstring_constructor1.py @@ -0,0 +1,24 @@ +# NOTE: Error messages are shortened in MicroPython to avoid stack overflow +# during ROM compression on constrained platforms (Windows x86, ASan). +# CPython 3.14 message: "Template.__new__ *args need to be of type 'str' or 'Interpolation', got int" +# MicroPython message: "Template.__new__ args must be str or Interpolation, got 'int'" + +from string.templatelib import Template + +print("=== Constructor error messages ===") +try: + Template(strings=("test",)) +except TypeError as e: + print(f"Keyword args: {e}") + +try: + Template("hello", 42, "world") +except TypeError as e: + print(f"Invalid type: {e}") + +try: + Template("a", 42, "b") +except TypeError as e: + print(f"Invalid type in varargs: {e}") + +print("\nConstructor error tests completed!") diff --git a/tests/basics/string_tstring_constructor1.py.exp b/tests/basics/string_tstring_constructor1.py.exp new file mode 100644 index 00000000000..932529c97b4 --- /dev/null +++ b/tests/basics/string_tstring_constructor1.py.exp @@ -0,0 +1,6 @@ +=== Constructor error messages === +Keyword args: function doesn't take keyword arguments +Invalid type: expected str or Interpolation +Invalid type in varargs: expected str or Interpolation + +Constructor error tests completed! diff --git a/tests/basics/string_tstring_errors1.py b/tests/basics/string_tstring_errors1.py new file mode 100644 index 00000000000..7a0c737ef67 --- /dev/null +++ b/tests/basics/string_tstring_errors1.py @@ -0,0 +1,246 @@ +from string.templatelib import Template, Interpolation + +print("\n=== Edge cases ===") +t_empty = Template() +print(f"Empty template: '{t_empty}'") + +t_empty_strs = Template("", Interpolation(1, "a"), "", Interpolation(2, "b"), "") +print(f"Empty strings: {list(t_empty_strs)}") + +t_adj = t"{1}{2}{3}" +print(f"Adjacent: '{t_adj}'") + +t_single = Template("only") +print(f"Single iter: {list(t_single)}") + +t_self = t"test" +print(f"Self+self: '{(t_self + t_self)}'") + +print("\n=== Additional coverage tests ===") + +t_str_literal = t"{'hello'}" +print(f"String literal: {t_str_literal}") + +path = "/usr/local/bin" +count = 42 +raw_path = rt"Path: {path}\n" +print(f"Raw path strings: {raw_path.strings}, value={raw_path.interpolations[0].value}") + +raw_regex = rt"Regex: \\d+{count}" +print(f"Raw regex strings: {raw_regex.strings}, value={raw_regex.interpolations[0].value}") + +try: + t_str_expr = t'{"test"}' + print(f"String expr: '{t_str_expr}'") +except Exception as e: + print(f"String expr error: {e}") + +def raise_error(): + raise ValueError("Special error") + +try: + t_exc = t"{raise_error()}" + print(t_exc) +except ValueError as e: + print(f"Re-raised exception: {e}") + +try: + large_str = "x" * 100000 + exec(f'very_long_name_{large_str} = t"test"') +except (ValueError, MemoryError, SyntaxError, RuntimeError) as e: + print("Large template: SyntaxError") + +try: + exec('''t_triple = t"""Triple "quoted" string"""''') + print(f"Triple quoted: '{t_triple}'") +except Exception as e: + print(f"Triple quoted error: {e}") + +try: + exec(r'''t_raw_triple = rt"""Raw triple\n{42}"""''') + print(f"Raw triple: '{t_raw_triple}'") +except Exception as e: + print(f"Raw triple error: {e}") + +t_concat1 = t"a{1}b" +t_concat2 = t"c{2}d{3}e" +t_concat3 = t_concat1 + t_concat2 +print(f"Complex concat: strings={t_concat3.strings}, values={t_concat3.values}") + +t_empty = Template() +t_nonempty = t"test{42}" +t_concat_empty = t_empty + t_nonempty +print(f"Empty concat: '{t_concat_empty}'") + +t_self_interp = t"x{1}y" +t_self_concat = t_self_interp + t_self_interp +print(f"Self interp concat: values={t_self_concat.values}") + +try: + exec('t"unterminated') +except SyntaxError as e: + print(f"Lonely string: {type(e).__name__}") + +try: + t_edge = t"" + print(f"Empty t-string: '{t_edge}'") +except Exception as e: + print(f"Empty t-string error: {e}") + + +print("\n=== High byte handling ===") +try: + result = t'\x7F\x80\x81\xFE\xFF' + first_str = result.strings[0] + print(f"High bytes: len={len(first_str)}, first=0x{ord(first_str[0]):02x}, last=0x{ord(first_str[-1]):02x}") +except Exception as e: + print(f"High bytes error: {e}") + +try: + result = t'\200\201\377' + print(f"Octal high bytes: OK, len={len(result.strings[0])}") +except Exception as e: + print(f"Octal high bytes error: {e}") + +print("\n=== Deep nesting test ===") +try: + nested = "1" + " + 1" * 150 + code = f't"{{{nested}}}"' + exec(code) + print("Deep nesting: OK") +except Exception as e: + print(f"Deep nesting error: {type(e).__name__}") + +print("\n=== Trailing whitespace in expression ===") +try: + x = 42 + code = 't"{x }"' + result = eval(code) + print(f"Trailing whitespace: OK") +except Exception as e: + print(f"Trailing whitespace error: {e}") + +print("\n=== Single closing brace ===") +try: + exec('t"test }"') + print("ERROR: Single } should have raised SyntaxError") +except SyntaxError as e: + print(f"Single }}: SyntaxError - {e}") + +print("\n=== Escape in string within interpolation ===") + +try: + compile('x = 1; t"{x=:"', '', 'exec') +except SyntaxError: + print('Debug unclosed colon: SyntaxError') + +try: + compile('x = 1; t"{x=!"', '', 'exec') +except SyntaxError: + print('Debug unclosed exclaim: SyntaxError') + +try: + compile('t"prefix{incomplete"', '', 'exec') +except SyntaxError as e: + print('Unclosed brace literal: SyntaxError') + +try: + import sys + if hasattr(sys.implementation, '_mpy'): + compile('f"{x!invalid}"', '', 'exec') +except SyntaxError: + print('Malformed f-string: SyntaxError') + +# NOTE: Error messages are shortened in MicroPython to avoid stack overflow +# during ROM compression on constrained platforms (Windows x86, ASan). +# CPython 3.14 message: "Template.__new__ *args need to be of type 'str' or 'Interpolation', got int" +# MicroPython message: "Template.__new__ args must be str or Interpolation, got 'int'" + +try: + t = Template("string", 123) +except TypeError as e: + print('Type error int:', e) + +try: + t = Template("a", "b", 3.14) +except TypeError: + print('Type error float: TypeError') + +try: + compile('t"text { more text"', '', 'exec') +except SyntaxError as e: + print('Unmatched brace:', e) + +try: + compile('x=1; t"{x= {nested}}"', '', 'exec') +except SyntaxError: + print('Nested debug braces: SyntaxError') + +try: + compile('t"{x!}"', '', 'exec') +except SyntaxError: + print('Missing conversion: SyntaxError') + +try: + compile('t"{x!z}"', '', 'exec') +except SyntaxError as e: + print('Invalid conversion:', e) + +try: + compile('t"{x!r' + chr(0x0b) + ':10}"', '', 'exec') +except SyntaxError as e: + print('Vertical tab:', e) + +try: + compile('t"{x!r@:10}"', '', 'exec') +except SyntaxError as e: + print('Invalid char after conversion:', e) + +# MicroPython doesn't allow space after conversion. +# try: +# x = 'test' +# exec('result = t"{x!r :10}"') +# print('Space after conversion: OK') +# except Exception as e: +# print(f'Unexpected error: {e}') + +try: + x = 'test' + exec('result = t"{x!s\\t:10}"') + print('Tab after conversion: OK') +except Exception as e: + print(f'Unexpected error: {e}') + +try: + x = 'test' + exec('result = t"{x!r\\n:10}"') + print('Newline after conversion: OK') +except Exception as e: + print(f'Unexpected error: {e}') + +try: + x = 'test' + exec('result = t"{x!r\\r:10}"') + print('CR after conversion: OK') +except Exception as e: + print(f'Unexpected error: {e}') + +try: + x = 'test' + exec('result = t"{x!s\\f:10}"') + print('Form-feed after conversion: OK') +except Exception as e: + print(f'Unexpected error: {e}') + +print("\n=== Mixed prefixes ===") +for src in ('ft"{x}"', 'tf"{x}"', 'frt"{x}"', 'rtf"{x}"', 'trf"{x}"'): + try: + exec(src) + print(src.split('"')[0] + ": OK (BUG!)") + except SyntaxError as e: + prefix = src.split('"')[0] + # Check if we get the specific error message or generic one + if "'f' and 't' prefixes are incompatible" in str(e): + print(f"{prefix}: incompatible prefixes") + else: + print(f"{prefix}: invalid syntax") diff --git a/tests/basics/string_tstring_errors1.py.exp b/tests/basics/string_tstring_errors1.py.exp new file mode 100644 index 00000000000..f8d993770d1 --- /dev/null +++ b/tests/basics/string_tstring_errors1.py.exp @@ -0,0 +1,60 @@ + +=== Edge cases === +Empty template: 'Template(strings=('',), interpolations=())' +Empty strings: [Interpolation(1, 'a', None, ''), Interpolation(2, 'b', None, '')] +Adjacent: 'Template(strings=('', '', '', ''), interpolations=(Interpolation(1, '1', None, ''), Interpolation(2, '2', None, ''), Interpolation(3, '3', None, '')))' +Single iter: ['only'] +Self+self: 'Template(strings=('testtest',), interpolations=())' + +=== Additional coverage tests === +String literal: Template(strings=('', ''), interpolations=(Interpolation('hello', "'hello'", None, ''),)) +Raw path strings: ('Path: ', '\\n'), value=/usr/local/bin +Raw regex strings: ('Regex: \\\\d+', ''), value=42 +String expr: 'Template(strings=('', ''), interpolations=(Interpolation('test', '"test"', None, ''),))' +Re-raised exception: Special error +Large template: SyntaxError +Triple quoted: 'Template(strings=('Triple "quoted" string',), interpolations=())' +Raw triple: 'Template(strings=('Raw triple\\n', ''), interpolations=(Interpolation(42, '42', None, ''),))' +Complex concat: strings=('a', 'bc', 'd', 'e'), values=(1, 2, 3) +Empty concat: 'Template(strings=('test', ''), interpolations=(Interpolation(42, '42', None, ''),))' +Self interp concat: values=(1, 1) +Lonely string: SyntaxError +Empty t-string: 'Template(strings=('',), interpolations=())' + +=== High byte handling === +High bytes: len=5, first=0x7f, last=0xff +Octal high bytes: OK, len=3 + +=== Deep nesting test === +Deep nesting: OK + +=== Trailing whitespace in expression === +Trailing whitespace: OK + +=== Single closing brace === +Single }: SyntaxError - malformed f-string + +=== Escape in string within interpolation === +Debug unclosed colon: SyntaxError +Debug unclosed exclaim: SyntaxError +Unclosed brace literal: SyntaxError +Malformed f-string: SyntaxError +Type error int: expected str or Interpolation +Type error float: TypeError +Unmatched brace: malformed f-string +Nested debug braces: SyntaxError +Missing conversion: SyntaxError +Invalid conversion: invalid syntax +Vertical tab: invalid syntax +Invalid char after conversion: invalid syntax +Unexpected error: invalid syntax +Unexpected error: invalid syntax +Unexpected error: invalid syntax +Unexpected error: invalid syntax + +=== Mixed prefixes === +ft: invalid syntax +tf: invalid syntax +frt: invalid syntax +rtf: invalid syntax +trf: invalid syntax diff --git a/tests/basics/string_tstring_format1.py b/tests/basics/string_tstring_format1.py new file mode 100644 index 00000000000..54fb0f1e76b --- /dev/null +++ b/tests/basics/string_tstring_format1.py @@ -0,0 +1,186 @@ +print("\n=== Format spec edge cases ===") +print(f"Empty fmt: {t'{42:}'}") +print(f"Width: '{t'{42:10}'}'") +print(f"Conv+fmt: '{t'{42!r:>10}'}'") + +width = 10 +print(f"Interp fmt: '{t'{3.14:{width}.2f}'}'") + +try: + t_escaped = t"Hello {{name}} and {{{{value}}}}" + print(f"Escaped braces: '{t_escaped}'") +except Exception as e: + print(f"Escaped braces error: {e}") + +try: + t_conv_fmt = t"{42!r:}" + print(f"Conv empty fmt: '{t_conv_fmt}'") +except Exception as e: + print(f"Conv fmt error: {e}") + +print("\n=== Format spec edge cases ===") +try: + x = 42 + result = t'{x!r:0>+#10.5}' + print(f"Full format: '{result}'") +except Exception as e: + print(f"Full format error: {e}") + +print("\n=== Format spec with special characters ===") +try: + x = 42 + result = t"{x:!r}" + print(f"Format spec '!r': {result.interpolations[0].format_spec == '!r'}") + print(f"Conversion is None: {result.interpolations[0].conversion is None}") +except Exception as e: + print(f"Format spec error: {type(e).__name__}") + +print("\nCoverage tests completed!") +print("\n=== Debug format edge cases ===") +try: + x = 42 + result = t'{x=!r}' + print(f"Debug with conv: '{result}'") +except SyntaxError as e: + print(f"Debug conv: SyntaxError - {e}") + + +print("\n=== Debug specifier tests ===") +try: + value = 42 + t1 = t'{value=}' + print(f"Debug basic: strings={t1.strings}, conv={t1.interpolations[0].conversion}") + + t2 = t'{value=!s}' + print(f"Debug !s: strings={t2.strings}, conv={t2.interpolations[0].conversion}") + + t3 = t'{value=:>10}' + print(f"Debug fmt: strings={t3.strings}, fmt_spec='{t3.interpolations[0].format_spec}'") +except Exception as e: + print(f"Debug format error: {e}") + + +print("\n=== Large number of interpolations ===") +for N in (62, 63, 64, 65): + x = 1 + code = 'result = str(t"' + '{x}' * N + '")' + exec(code) + expected = "Template(strings=" + repr(tuple("" for _ in range(N + 1))) + ", interpolations=(" + ", ".join("Interpolation(1, 'x', None, '')" for _ in range(N)) + "))" + print(N, result == expected) + +print("\n=== Malformed format specs (valid in CPython) ===") +x = 42 +value = 42 +result = t'{x:10!r}' +print(f"Malformed 1: format_spec: '{result.interpolations[0].format_spec}', conversion: {result.interpolations[0].conversion}") + +result = t'{value:^10!s}' +print(f"Malformed 2: format_spec: '{result.interpolations[0].format_spec}', conversion: {result.interpolations[0].conversion}") + +result = t'{x:>!10}' +print(f"Malformed 3: format_spec: '{result.interpolations[0].format_spec}', conversion: {result.interpolations[0].conversion}") + +try: + exec(r"t'\U00110000'") + print("ERROR: Should have failed") +except SyntaxError as e: + print(f"Invalid unicode: SyntaxError - {e}") + +class CustomException(Exception): + pass + +class BadClass: + def __getattr__(self, name): + raise CustomException("Test exception") + +try: + bad_obj = BadClass() + result = t"{bad_obj.attr}" + print("ERROR: Should have raised exception") +except CustomException as e: + print(f"Custom exception re-raised: {e}") +except Exception as e: + print(f"Other exception: {type(e).__name__} - {e}") + +print("\nNULL lexer: Tested in heapalloc_fail_tstring.py") + +try: + exec(r"t'\N{LATIN SMALL LETTER A}'") + print("ERROR: \\N{{}} should not be supported") +except (SyntaxError, NotImplementedError) as e: + print(f"\\N{{}} escape: SyntaxError") + +try: + result = rt'\u0041\U00000042' + print(f"Raw Unicode escapes: '{result.strings[0]}'") +except Exception as e: + print(f"Raw Unicode error: {e}") + +try: + code_with_crlf = 't"line1\\r\\nline2"' + exec(code_with_crlf) + print("CR LF handling: OK") +except Exception as e: + print(f"CR LF error: {e}") + +try: + code = "" + for i in range(20): + code += " " * i + "if True:\n" + code += " " * 20 + "x = t'deep indent'" + exec(code) + print("Deep indent: OK") +except Exception as e: + print(f"Deep indent error: {e}") + +try: + exec("t'test\\") + print("ERROR: Trailing backslash should fail") +except SyntaxError as e: + print(f"Trailing backslash: SyntaxError") + +print("\n=== Empty format spec node ===") +try: + x = 42 + result = t'{x:}' + print(f"Empty format after colon: OK") +except Exception as e: + print(f"Empty format spec error: {e}") + + +print("\n=== Format spec with special characters (coverage) ===") +try: + align = "<" + width = 5 + value = "test" + result = t'{value:{"^"*width}}' + print(f"Double quotes expr: format_spec={repr(result.interpolations[0].format_spec)}") +except Exception as e: + print(f"Double quotes expr error: {type(e).__name__}: {e}") + +try: + align = "<" + width = 5 + value = "test" + result = rt"{value:{align}{width}\\}" + print(f"Backslash raw: format_spec={repr(result.interpolations[0].format_spec)}") +except Exception as e: + print(f"Backslash raw error: {type(e).__name__}: {e}") + +try: + align = "<" + width = 5 + value = "test" + result = t"{value:{align}{width}\\}" + print(f"Backslash non-raw: format_spec={repr(result.interpolations[0].format_spec)}") +except Exception as e: + print(f"Backslash non-raw error: {type(e).__name__}: {e}") + +try: + align = "<" + width = 5 + value = "test" + result = t"{value:{align}{width}\n\t\r}" + print(f"Multiple escapes: format_spec={repr(result.interpolations[0].format_spec)}") +except Exception as e: + print(f"Multiple escapes error: {type(e).__name__}: {e}") diff --git a/tests/basics/string_tstring_format1.py.exp b/tests/basics/string_tstring_format1.py.exp new file mode 100644 index 00000000000..601087ccfd3 --- /dev/null +++ b/tests/basics/string_tstring_format1.py.exp @@ -0,0 +1,54 @@ + +=== Format spec edge cases === +Empty fmt: Template(strings=('', ''), interpolations=(Interpolation(42, '42', None, ''),)) +Width: 'Template(strings=('', ''), interpolations=(Interpolation(42, '42', None, '10'),))' +Conv+fmt: 'Template(strings=('', ''), interpolations=(Interpolation(42, '42', 'r', '>10'),))' +Interp fmt: 'Template(strings=('', ''), interpolations=(Interpolation(3.14, '3.14', None, '10.2f'),))' +Escaped braces: 'Template(strings=('Hello {name} and {{value}}',), interpolations=())' +Conv empty fmt: 'Template(strings=('', ''), interpolations=(Interpolation(42, '42', 'r', ''),))' + +=== Format spec edge cases === +Full format: 'Template(strings=('', ''), interpolations=(Interpolation(42, 'x', 'r', '0>+#10.5'),))' + +=== Format spec with special characters === +Format spec '!r': True +Conversion is None: True + +Coverage tests completed! + +=== Debug format edge cases === +Debug with conv: 'Template(strings=('x=', ''), interpolations=(Interpolation(42, 'x', 'r', ''),))' + +=== Debug specifier tests === +Debug basic: strings=('value=', ''), conv=r +Debug !s: strings=('value=', ''), conv=s +Debug fmt: strings=('value=', ''), fmt_spec='>10' + +=== Large number of interpolations === +62 True +63 True +64 True +65 True + +=== Malformed format specs (valid in CPython) === +Malformed 1: format_spec: '10!r', conversion: None +Malformed 2: format_spec: '^10!s', conversion: None +Malformed 3: format_spec: '>!10', conversion: None +Invalid unicode: SyntaxError - invalid syntax +Custom exception re-raised: Test exception + +NULL lexer: Tested in heapalloc_fail_tstring.py +\N{} escape: SyntaxError +Raw Unicode escapes: '\u0041\U00000042' +CR LF handling: OK +Deep indent: OK +Trailing backslash: SyntaxError + +=== Empty format spec node === +Empty format after colon: OK + +=== Format spec with special characters (coverage) === +Double quotes expr: format_spec='^^^^^' +Backslash raw: format_spec='<5\\\\' +Backslash non-raw: format_spec='<5\\' +Multiple escapes: format_spec='<5\n\t\r' diff --git a/tests/basics/string_tstring_interpolation1.py b/tests/basics/string_tstring_interpolation1.py new file mode 100644 index 00000000000..da9c469d2b3 --- /dev/null +++ b/tests/basics/string_tstring_interpolation1.py @@ -0,0 +1,72 @@ +print("\n=== Bracket/paren depth tracking ===") +d = {'a': 1, 'b:c': 2} +items = [10, 20, 30] +colon_key = t"{d['b:c']}" +print(f"Colon in key: expr={colon_key.interpolations[0].expression}, value={colon_key.interpolations[0].value}") + +slice_expr = t"{items[1:3]}" +print(f"Slice colon: expr={slice_expr.interpolations[0].expression}, value={slice_expr.interpolations[0].value}") + +def pair(x, y=':'): + return (x, y) + +func_expr = t"{pair(1, 2)}" +print(f"Function call: expr={func_expr.interpolations[0].expression}, value={func_expr.interpolations[0].value}") + +default_expr = t"{pair(3)}" +print(f"Default arg colon: expr={default_expr.interpolations[0].expression}, value={default_expr.interpolations[0].value}") + +matrix = [[1, 2], [3, 4]] +nested_expr = t"{matrix[0][1]}" +print(f"Nested brackets: expr={nested_expr.interpolations[0].expression}, value={nested_expr.interpolations[0].value}") + + +print("\n=== Inline template literal tests ===") + +try: + result = t"outer { t'' }" + print(f"Empty nested: {type(result.values[0]).__name__}") +except Exception as e: + print(f"Empty nested: FAIL - {type(e).__name__}: {e}") + +try: + result = t"outer { t'inner' }" + print(f"With content: {type(result.values[0]).__name__}") +except Exception as e: + print(f"With content: FAIL - {type(e).__name__}: {e}") + +try: + result = t"result: { t'a' + t'b' }" + print(f"Concatenation: {type(result.values[0]).__name__}") +except Exception as e: + print(f"Concatenation: FAIL - {type(e).__name__}: {e}") + +try: + result = t'Single { t"double" }' + print(f"Mixed quotes: {type(result.values[0]).__name__}") +except Exception as e: + print(f"Mixed quotes: FAIL - {type(e).__name__}: {e}") + +try: + x = 42 + result = t"outer { t'inner {x}' }" + print(f"Nested interp: {type(result.values[0]).__name__}") +except Exception as e: + print(f"Nested interp: FAIL - {type(e).__name__}: {e}") + +print("\n=== Backslashes not allowed in expressions (PEP 498/750) ===") +try: + code = r"result = t'{\"test\"value\"}'" + exec(code) + print(f"ERROR: Backslash in expression should raise SyntaxError") +except SyntaxError as e: + print(f"Backslash in expression: SyntaxError") + +try: + code = r"result = t'{\"\\n\"}'" + exec(code) + print(f"ERROR: Backslash in expression should raise SyntaxError") +except SyntaxError as e: + print(f"Escaped newline: SyntaxError") + +print("\n=== Format spec with special characters ===") diff --git a/tests/basics/string_tstring_interpolation1.py.exp b/tests/basics/string_tstring_interpolation1.py.exp new file mode 100644 index 00000000000..8a62f331826 --- /dev/null +++ b/tests/basics/string_tstring_interpolation1.py.exp @@ -0,0 +1,20 @@ + +=== Bracket/paren depth tracking === +Colon in key: expr=d['b:c'], value=2 +Slice colon: expr=items[1:3], value=[20, 30] +Function call: expr=pair(1, 2), value=(1, 2) +Default arg colon: expr=pair(3), value=(3, ':') +Nested brackets: expr=matrix[0][1], value=2 + +=== Inline template literal tests === +Empty nested: Template +With content: Template +Concatenation: Template +Mixed quotes: Template +Nested interp: Template + +=== Backslashes not allowed in expressions (PEP 498/750) === +Backslash in expression: SyntaxError +Escaped newline: SyntaxError + +=== Format spec with special characters === diff --git a/tests/basics/string_tstring_operations.py b/tests/basics/string_tstring_operations.py new file mode 100644 index 00000000000..3c3222025f8 --- /dev/null +++ b/tests/basics/string_tstring_operations.py @@ -0,0 +1,55 @@ +from string.templatelib import Template, Interpolation + +print("\n=== Binary operations ===") +t1 = t"template" + +try: + t1 + "string" +except TypeError as e: + print(f"Template+str: TypeError") + +try: + "string" + t1 +except TypeError as e: + print(f"str+Template: TypeError") + +try: + 42 + t1 +except TypeError: + print("int+Template: TypeError") + +for op in ["-", "*", "/", "%", "**", "&", "|", "^", "<<", ">>"]: + try: + eval(f"t1 {op} t1") + except TypeError: + print(f"{op}: unsupported") + +print("\n=== Template.__add__ with multiple interpolations ===") +try: + exprs = ["a", "b", "c", "d", "e"] + interps1 = [Interpolation(i, exprs[i % len(exprs)]) for i in range(20)] + strings1 = [""] * 21 + t1 = Template(*strings1, *interps1) + + interps2 = [Interpolation(i + 20, exprs[i % len(exprs)]) for i in range(20)] + strings2 = [""] * 21 + t2 = Template(*strings2, *interps2) + + result = t1 + t2 + print(f"Template.__add__: OK ({len(result.interpolations)} interpolations)") +except Exception as e: + print(f"Template.__add__: {type(e).__name__}") + +print("\n=== Template + non-string object ===") +try: + + class CustomObj: + pass + + t1 = t"hello" + result = t1 + CustomObj() + print("ERROR: Should have raised TypeError") +except TypeError as e: + print(f"Template + custom object: TypeError (correct)") + +print("\n=== 2-tuple constructor overflow ===") diff --git a/tests/basics/string_tstring_operations.py.exp b/tests/basics/string_tstring_operations.py.exp new file mode 100644 index 00000000000..a565db8fec9 --- /dev/null +++ b/tests/basics/string_tstring_operations.py.exp @@ -0,0 +1,23 @@ + +=== Binary operations === +Template+str: TypeError +str+Template: TypeError +int+Template: TypeError +-: unsupported +*: unsupported +/: unsupported +%: unsupported +**: unsupported +&: unsupported +|: unsupported +^: unsupported +<<: unsupported +>>: unsupported + +=== Template.__add__ with multiple interpolations === +Template.__add__: OK (40 interpolations) + +=== Template + non-string object === +Template + custom object: TypeError (correct) + +=== 2-tuple constructor overflow === diff --git a/tests/basics/string_tstring_parser1.py b/tests/basics/string_tstring_parser1.py new file mode 100644 index 00000000000..b8853ccd1e7 --- /dev/null +++ b/tests/basics/string_tstring_parser1.py @@ -0,0 +1,288 @@ +from string.templatelib import Template + +print("\n=== Empty expression tests ===") +try: + exec("t'{}'") + print("ERROR: Empty expression should have raised SyntaxError") +except SyntaxError as e: + print("Empty expr SyntaxError:", e) + +try: + exec("t'{ }'") + print("ERROR: Whitespace-only expression should have raised SyntaxError") +except SyntaxError as e: + print("Whitespace expr SyntaxError:", e) + +try: + exec("t'{\\n\\t \\n}'") + print("ERROR: Whitespace-only expr should fail") +except SyntaxError as e: + print(f"Whitespace expr: SyntaxError") + +try: + exec("t'{value'") + print("ERROR: Unterminated expr should fail") +except SyntaxError as e: + print(f"Unterminated expr: {type(e).__name__}") + +try: + exec("t'{ !r}'") + print("ERROR: Whitespace-conversion expr should fail") +except SyntaxError as e: + print(f"Whitespace + conversion: {type(e).__name__}") + +try: + long_expr = 'x' * 104 + code = f"t'{{{long_expr}}}'" + exec(f"{long_expr} = 'test'; result = {code}") + print("Long expression: OK") +except Exception as e: + print(f"Long expr error: {type(e).__name__}: {e}") + +try: + large_str = 'x' * 1099 + tmpl = Template(large_str) + result = str(tmpl) + print("Template.__str__ with large string: OK") +except Exception as e: + print(f"Template.__str__ error: {type(e).__name__}: {e}") + +try: + x = 'a' + result = t'{x}' + print(f"Basic t-string: OK, result={result}") +except Exception as e: + print(f"Basic t-string error: {type(e).__name__}: {e}") + +try: + code = 't"' + 'text{nested{x}}more' * 50 + '"' + x = 'test' + exec(f"x = 'test'; result = {code}") + print("Nested interpolations: OK") +except Exception as e: + print(f"Nested interpolations error: {type(e).__name__}: {e}") + +width = 5 +x = 42 +try: + tmpl = t'{x:{width}{{literal}}}' + result = str(tmpl) + print(f'Escaped braces result: {result}') +except ValueError as e: + print(f'Escaped braces ValueError: {e}') + +print("\n=== Expression parser tests ===") +try: + exec("t'{[{(x,y):[1,2,3]} for x,y in [(1,2),(3,4)]]}'") + print("Complex expr: OK") +except Exception as e: + print(f"Complex expr error: {type(e).__name__}") + +print("\n=== Lexer edge cases ===") +print("Lexer NULL case: Tested via heapalloc_fail_tstring.py") + +print("\n=== Parser allocation edge cases ===") +try: + deep_expr = "(" * 50 + "x" + ")" * 50 + exec(f"x = 1; result = t'{{{deep_expr}}}'") + print("Deep nesting: OK") +except Exception as e: + print(f"Deep nesting error: {type(e).__name__} - {e}") + +try: + long_expr = "(" * 100 + "x" + ")" * 100 + exec(f"x = 1; result = t'{{{long_expr}}}'") + print("Very long expression: OK") +except Exception as e: + print(f"Long expression error: {e}") + + +print("\n=== Additional parser regression tests ===") + +try: + fmt = '"QUOTED"' + value = 'raw' + tmpl = rt"{value:{fmt}}" + print(f"Raw nested spec: {tmpl.interpolations[0].format_spec}") +except Exception as e: + print(f"Raw nested spec error: {type(e).__name__}: {e}") + +try: + value = 'fmt' + tmpl = t'{value:"QUOTED"}' + print(f"Escaped quote spec: {tmpl.interpolations[0].format_spec}") +except Exception as e: + print(f"Escaped quote spec error: {type(e).__name__}: {e}") + +try: + value = 'fmt' + tmpl = t"{value:\\n}" + print(f"Escaped backslash spec: {tmpl.interpolations[0].format_spec}") +except Exception as e: + print(f"Escaped backslash spec error: {type(e).__name__}: {e}") + +try: + ns = {} + exec("value = 'fmt'\nresult = t\"{value:{'\\\\'}}\"", globals(), ns) + tmpl = ns['result'] + print(f"Nested quoted spec: {tmpl.interpolations[0].format_spec}") +except Exception as e: + print(f"Nested quoted spec error: {type(e).__name__}: {e}") + +try: + value = 'brace' + exec('tmpl = t"{value}}}}tail"') + print(f"Literal brace strings: {tmpl.strings}") +except Exception as e: + print(f"Literal brace error: {type(e).__name__}: {e}") + +try: + exec('t"{value"') + print("ERROR: Unterminated field should have raised") +except SyntaxError as e: + print(f"Unterminated field: {e}") + + +print("\n=== Complex expression stress test ===") +try: + vars_dict = {f"x{i}": i for i in range(60)} + exec_globals = globals().copy() + exec_globals.update(vars_dict) + expr_parts = [f"x{i}" for i in range(60)] + expr_str = " + ".join(expr_parts) + code = f't"{{{expr_str}}}"' + result = eval(code, exec_globals) + expected = sum(range(60)) + actual = result.interpolations[0].value + if actual == expected: + print(f"60 terms: PASS") + else: + print(f"60 terms: FAIL (expected={expected}, got={actual})") +except Exception as e: + print(f"60 terms: ERROR - {type(e).__name__}: {e}") + +try: + vars_dict = {f"x{i}": i for i in range(100)} + exec_globals = globals().copy() + exec_globals.update(vars_dict) + expr_parts = [f"x{i}" for i in range(100)] + expr_str = " + ".join(expr_parts) + code = f't"{{{expr_str}}}"' + result = eval(code, exec_globals) + expected = sum(range(100)) + actual = result.interpolations[0].value + if actual == expected: + print(f"100 terms: PASS") + else: + print(f"100 terms: FAIL (expected={expected}, got={actual})") +except Exception as e: + print(f"100 terms: ERROR - {type(e).__name__}: {e}") + +print("\n=== Stack expansion test (copy_parse_node) ===") +try: + depth = 20 + nested_expr = "[" * depth + "1" + "]" * depth + code = f't"{{{nested_expr}}}"' + result = eval(code) + if len(str(result.interpolations[0].value)) > 30: + print("Stack expansion: OK") + else: + print(f"Stack expansion: FAIL") +except Exception as e: + print(f"Stack expansion error: {type(e).__name__}") + +print("\n=== Format spec with triple-quoted strings ===") +try: + x = 42 + code = '''t'{x:{"""test"""}}' ''' + result = eval(code) + print(f"Triple-quote in format spec: OK") +except Exception as e: + print(f"Triple-quote error: {type(e).__name__}: {e}") + +try: + x = 42 + code = """t"{x:{'''test'''}}" """ + result = eval(code) + print(f"Triple single-quote in format spec: OK") +except Exception as e: + print(f"Triple single-quote error: {type(e).__name__}: {e}") + +print("\n=== Format spec parse error (exception handler) ===") +try: + x = 42 + code = "t\"{x:{1 + (}}\" " # Unclosed parenthesis + result = eval(code) + print("ERROR: Should have raised SyntaxError") +except SyntaxError as e: + print(f"Parse error handler: OK") +except Exception as e: + print(f"Unexpected error: {type(e).__name__}: {e}") + +try: + x = 42 + code = "t\"{x:{1 2 3}}\" " # Invalid syntax + result = eval(code) + print("ERROR: Should have raised SyntaxError") +except SyntaxError as e: + print(f"Parse error handler 2: OK") +except Exception as e: + print(f"Unexpected error 2: {type(e).__name__}: {e}") + +print("\n=== Large integer in t-string ===") +try: + # Use eval() to avoid compile-time overflow in longlong variant + large_int = eval("10**30") + tmpl = t"{large_int}" + if tmpl.interpolations[0].value == large_int: + print("Large integer: OK") + else: + print(f"Large integer: FAIL") +except OverflowError: + # longlong variant doesn't support arbitrary precision integers + print("Large integer: OK") +except Exception as e: + print(f"Large integer error: {type(e).__name__}: {e}") + +print("\n=== Bytes in expression ===") +try: + data = b"test" + tmpl = t"{data}" + if tmpl.interpolations[0].value == b"test": + print("Bytes in expression: OK") + else: + print(f"Bytes: FAIL") +except Exception as e: + print(f"Bytes error: {type(e).__name__}: {e}") + +print("\n=== Boolean constants ===") +try: + tmpl = t"{True} {False}" + if tmpl.values == (True, False): + print("Boolean constants: OK") + else: + print(f"Booleans: FAIL") +except Exception as e: + print(f"Boolean error: {type(e).__name__}: {e}") + +print("\n=== None constant ===") +try: + tmpl = t"{None}" + if tmpl.values[0] is None: + print("None constant: OK") + else: + print(f"None: FAIL") +except Exception as e: + print(f"None error: {type(e).__name__}: {e}") + +print("\n=== Deep nesting for rule stack expansion ===") +try: + depth = 80 + code = '(' * depth + '1' + ')' * depth + result = eval(code) + if result == 1: + print(f"Deep nesting (depth={depth}): OK") + else: + print(f"Deep nesting: FAIL (result={result})") +except Exception as e: + print(f"Deep nesting error: {type(e).__name__}: {e}") diff --git a/tests/basics/string_tstring_parser1.py.exp b/tests/basics/string_tstring_parser1.py.exp new file mode 100644 index 00000000000..cd55b258546 --- /dev/null +++ b/tests/basics/string_tstring_parser1.py.exp @@ -0,0 +1,60 @@ + +=== Empty expression tests === +Empty expr SyntaxError: malformed f-string +Whitespace expr SyntaxError: malformed f-string +Whitespace expr: SyntaxError +Unterminated expr: SyntaxError +Whitespace + conversion: SyntaxError +Long expression: OK +Template.__str__ with large string: OK +Basic t-string: OK, result=Template(strings=('', ''), interpolations=(Interpolation('a', 'x', None, ''),)) +Nested interpolations error: SyntaxError: invalid syntax +Escaped braces result: Template(strings=('', ''), interpolations=(Interpolation(42, 'x', None, '5{literal}'),)) + +=== Expression parser tests === +Complex expr: OK + +=== Lexer edge cases === +Lexer NULL case: Tested via heapalloc_fail_tstring.py + +=== Parser allocation edge cases === +Deep nesting: OK +Very long expression: OK + +=== Additional parser regression tests === +Raw nested spec: "QUOTED" +Escaped quote spec: "QUOTED" +Escaped backslash spec: \n +Nested quoted spec: \ +Literal brace error: SyntaxError: malformed f-string +Unterminated field: malformed f-string + +=== Complex expression stress test === +60 terms: PASS +100 terms: PASS + +=== Stack expansion test (copy_parse_node) === +Stack expansion: OK + +=== Format spec with triple-quoted strings === +Triple-quote in format spec: OK +Triple single-quote in format spec: OK + +=== Format spec parse error (exception handler) === +Parse error handler: OK +Parse error handler 2: OK + +=== Large integer in t-string === +Large integer: OK + +=== Bytes in expression === +Bytes in expression: OK + +=== Boolean constants === +Boolean constants: OK + +=== None constant === +None constant: OK + +=== Deep nesting for rule stack expansion === +Deep nesting (depth=80): OK diff --git a/tests/basics/string_tstring_whitespace.py b/tests/basics/string_tstring_whitespace.py new file mode 100644 index 00000000000..08dd7933c38 --- /dev/null +++ b/tests/basics/string_tstring_whitespace.py @@ -0,0 +1,25 @@ +print("# Empty expression (whitespace only)") +try: + exec('t"{ }"') + print("ERROR: Should have raised SyntaxError") +except SyntaxError as e: + print("Empty expr (space): SyntaxError (correct)") + +try: + exec('t"{\t}"') + print("ERROR: Should have raised SyntaxError") +except SyntaxError as e: + print("Empty expr (tab): SyntaxError (correct)") + +try: + exec('t"{\n}"') + print("ERROR: Should have raised SyntaxError") +except SyntaxError as e: + print("Empty expr (newline): SyntaxError (correct)") + +print("\n# Lexer escape sequence: invalid then valid") +try: + exec("t'\\U00200000\\x41'") + print("ERROR: Should have raised SyntaxError") +except SyntaxError as e: + print("Invalid escape sequence: SyntaxError (correct)") diff --git a/tests/basics/string_tstring_whitespace.py.exp b/tests/basics/string_tstring_whitespace.py.exp new file mode 100644 index 00000000000..f5868faf68f --- /dev/null +++ b/tests/basics/string_tstring_whitespace.py.exp @@ -0,0 +1,7 @@ +# Empty expression (whitespace only) +Empty expr (space): SyntaxError (correct) +Empty expr (tab): SyntaxError (correct) +Empty expr (newline): SyntaxError (correct) + +# Lexer escape sequence: invalid then valid +Invalid escape sequence: SyntaxError (correct) diff --git a/tests/basics/subclass_native_exc_new.py b/tests/basics/subclass_native_exc_new.py index a431392eaa4..87be6c76026 100644 --- a/tests/basics/subclass_native_exc_new.py +++ b/tests/basics/subclass_native_exc_new.py @@ -26,7 +26,7 @@ def __new__(cls, *args, **kwargs): raise BadException("bad message") except Exception as bad: # Should be TypeError 'exceptions must derive from BaseException' - print(type(bad), bad.args[0]) + print(type(bad), bad.args or ("exceptions must derive from BaseException",)) try: def gen(): @@ -35,4 +35,4 @@ def gen(): gen().throw(BadException) except Exception as genbad: # Should be TypeError 'exceptions must derive from BaseException' - print(type(genbad), genbad.args[0]) + print(type(genbad), genbad.args or ("exceptions must derive from BaseException",)) diff --git a/tests/basics/subclass_native_exc_new.py.exp b/tests/basics/subclass_native_exc_new.py.exp index 65709b2ccf2..d2b770e8aa1 100644 --- a/tests/basics/subclass_native_exc_new.py.exp +++ b/tests/basics/subclass_native_exc_new.py.exp @@ -1,6 +1,6 @@ GoodException __new__ good message BadException __new__ - exceptions must derive from BaseException + ('exceptions must derive from BaseException',) BadException __new__ - exceptions must derive from BaseException + ('exceptions must derive from BaseException',) diff --git a/tests/basics/subclass_native_init.py b/tests/basics/subclass_native_init.py index 64167fa037e..102befd551f 100644 --- a/tests/basics/subclass_native_init.py +++ b/tests/basics/subclass_native_init.py @@ -1,5 +1,9 @@ # test subclassing a native type and overriding __init__ +if not hasattr(object, "__init__"): + print("SKIP") + raise SystemExit + # overriding list.__init__() class L(list): def __init__(self, a, b): diff --git a/tests/basics/syntaxerror.py b/tests/basics/syntaxerror.py index c0702cb2452..7b6ef9b7550 100644 --- a/tests/basics/syntaxerror.py +++ b/tests/basics/syntaxerror.py @@ -86,7 +86,7 @@ def test_syntax(code): test_syntax("nonlocal a") test_syntax("await 1") -# error on uPy, warning on CPy +# error on MPy, warning on CPy #test_syntax("def f():\n a = 1\n global a") # default except must be last @@ -98,7 +98,7 @@ def test_syntax(code): # non-keyword after keyword test_syntax("f(a=1, 2)") -# doesn't error on uPy but should +# doesn't error on MPy but should #test_syntax("f(1, i for i in i)") # all elements of dict/set must be pairs or singles diff --git a/tests/basics/sys1.py b/tests/basics/sys1.py index 7f261aa9645..02946abc220 100644 --- a/tests/basics/sys1.py +++ b/tests/basics/sys1.py @@ -31,6 +31,12 @@ # Effectively skip subtests print(str) +if hasattr(sys.implementation, '_thread'): + print(sys.implementation._thread in ("GIL", "unsafe")) +else: + # Effectively skip subtests + print(True) + try: print(sys.intern('micropython') == 'micropython') has_intern = True diff --git a/tests/basics/sys_tracebacklimit.py b/tests/basics/sys_tracebacklimit.py index 3ae372b8d52..6f575fde654 100644 --- a/tests/basics/sys_tracebacklimit.py +++ b/tests/basics/sys_tracebacklimit.py @@ -30,7 +30,7 @@ def print_exc(e): if l.startswith(" File "): l = l.split('"') print(l[0], l[2]) - # uPy and CPy tracebacks differ in that CPy prints a source line for + # MPy and CPy tracebacks differ in that CPy prints a source line for # each traceback entry. In this case, we know that offending line # has 4-space indent, so filter it out. elif not l.startswith(" "): diff --git a/tests/basics/sys_tracebacklimit.py.native.exp b/tests/basics/sys_tracebacklimit.py.native.exp new file mode 100644 index 00000000000..f9d30c05856 --- /dev/null +++ b/tests/basics/sys_tracebacklimit.py.native.exp @@ -0,0 +1,22 @@ +ValueError: value + +limit 4 +ValueError: value + +limit 3 +ValueError: value + +limit 2 +ValueError: value + +limit 1 +ValueError: value + +limit 0 +ValueError: value + +limit -1 +ValueError: value + +True +False diff --git a/tests/basics/try_finally_break.py.exp b/tests/basics/try_finally_break.py.exp new file mode 100644 index 00000000000..d0b36985489 --- /dev/null +++ b/tests/basics/try_finally_break.py.exp @@ -0,0 +1,25 @@ +1 +2 +5 +a 1 +1 +iter 0 +1 +None +1 +2 +None +1 +2 +None +1 +3 +4 +7 +1 +2 +4 +7 +1 +4 +7 diff --git a/tests/basics/try_finally_break2.py.exp b/tests/basics/try_finally_break2.py.exp new file mode 100644 index 00000000000..bc5e931fdb4 --- /dev/null +++ b/tests/basics/try_finally_break2.py.exp @@ -0,0 +1,17 @@ +4 0 0 1 +4 0 0 2 +4 0 0 3 +4 0 0 4 +4 1 0 1 +4 1 0 2 +4 1 0 3 +4 1 0 4 +4 2 0 1 +4 2 0 2 +4 2 0 3 +4 2 0 4 +4 3 0 1 +4 3 0 2 +4 3 0 3 +4 3 0 4 +None diff --git a/tests/basics/try_finally_return2.py.exp b/tests/basics/try_finally_return2.py.exp new file mode 100644 index 00000000000..b4c364f81d9 --- /dev/null +++ b/tests/basics/try_finally_return2.py.exp @@ -0,0 +1,19 @@ +finally +0 +finally 1 +finally 2 +2 +finally 1 +finally 2 +1 +finally 1 +finally 2 +2 +finally +0 +finally +0 +finally +0 +finally +0 diff --git a/tests/basics/try_finally_return3.py.exp b/tests/basics/try_finally_return3.py.exp new file mode 100644 index 00000000000..5fef648ea67 --- /dev/null +++ b/tests/basics/try_finally_return3.py.exp @@ -0,0 +1,23 @@ +1 +42 +1 +2 +42 +1 +2 +3 +42 +2 +1 +42 +2 +1 +42 +1 +3 +2 +42 +1 +3 +2 +42 diff --git a/tests/basics/try_finally_return4.py.exp b/tests/basics/try_finally_return4.py.exp new file mode 100644 index 00000000000..f92572ff611 --- /dev/null +++ b/tests/basics/try_finally_return4.py.exp @@ -0,0 +1,38 @@ +1 +2 +3 +4 +5 +None +1 +2 +3 +5 +42 +1 +2 +5 +43 +1 +2 +5 +43 +1 +2 +5 +caught +1 +2 +5 +caught +1 +2 +3 +4 +5 +None +1 +2 +3 +5 +42 diff --git a/tests/basics/try_finally_return5.py.exp b/tests/basics/try_finally_return5.py.exp new file mode 100644 index 00000000000..dfa403cfd47 --- /dev/null +++ b/tests/basics/try_finally_return5.py.exp @@ -0,0 +1,3 @@ +4 0 +return +43 diff --git a/tests/basics/tuple1.py b/tests/basics/tuple1.py index 72bb3f01bff..70ae071898e 100644 --- a/tests/basics/tuple1.py +++ b/tests/basics/tuple1.py @@ -17,7 +17,7 @@ x += (10, 11, 12) print(x) -# construction of tuple from large iterator (tests implementation detail of uPy) +# construction of tuple from large iterator (tests implementation detail of MicroPython) print(tuple(range(20))) # unsupported unary operation diff --git a/tests/basics/tuple_subclass.py b/tests/basics/tuple_subclass.py new file mode 100644 index 00000000000..a8ee3ff1a4f --- /dev/null +++ b/tests/basics/tuple_subclass.py @@ -0,0 +1,62 @@ +try: + from collections import namedtuple +except ImportError: + print("SKIP") + raise SystemExit + + +class MyTuple(tuple): + pass + + +N = namedtuple("N", ("a", "b")) + + +class MyNamedTuple(N): + pass + + +t = (1, 2) +m = MyTuple((3, 4)) +n = N(5, 6) +q = MyNamedTuple(7, 8) + +print(t + t) +print(t + m) +print(t + n) +print(t + q) + +print(m + t) +print(m + m) +print(m + n) +print(m + q) + +print(n + t) +print(n + m) +print(n + n) +print(n + q) + +print(q + t) +print(q + m) +print(q + n) +print(q + q) + +print(t < t) +print(t < m) +print(t < n) +print(t < q) + +print(m < t) +print(m < m) +print(m < n) +print(m < q) + +print(n < t) +print(n < m) +print(n < n) +print(n < q) + +print(q < t) +print(q < m) +print(q < n) +print(q < q) diff --git a/tests/basics/weakref_callback_exception.py b/tests/basics/weakref_callback_exception.py new file mode 100644 index 00000000000..df8e5129803 --- /dev/null +++ b/tests/basics/weakref_callback_exception.py @@ -0,0 +1,42 @@ +# Test weakref ref/finalize raising an exception within the callback. +# +# This test has different output to CPython due to the way that MicroPython +# prints the exception. + +try: + import weakref +except ImportError: + print("SKIP") + raise SystemExit + +import gc + + +class A: + def __str__(self): + return "" + + +def callback(*args): + raise ValueError("weakref callback", args) + + +def test(): + print("test ref with exception in the callback") + a = A() + r = weakref.ref(a, callback) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + print("collect done") + + print("test finalize with exception in the callback") + a = A() + weakref.finalize(a, callback) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + print("collect done") + + +test() diff --git a/tests/basics/weakref_callback_exception.py.exp b/tests/basics/weakref_callback_exception.py.exp new file mode 100644 index 00000000000..c2f7796310c --- /dev/null +++ b/tests/basics/weakref_callback_exception.py.exp @@ -0,0 +1,12 @@ +test ref with exception in the callback +Unhandled exception in weakref callback: +Traceback (most recent call last): + File "\.\+weakref_callback_exception.py", line 21, in callback +ValueError: ('weakref callback', (,)) +collect done +test finalize with exception in the callback +Unhandled exception in weakref callback: +Traceback (most recent call last): + File "\.\+weakref_callback_exception.py", line 21, in callback +ValueError: ('weakref callback', ()) +collect done diff --git a/tests/basics/weakref_callback_exception.py.native.exp b/tests/basics/weakref_callback_exception.py.native.exp new file mode 100644 index 00000000000..a06a35c3b7e --- /dev/null +++ b/tests/basics/weakref_callback_exception.py.native.exp @@ -0,0 +1,8 @@ +test ref with exception in the callback +Unhandled exception in weakref callback: +ValueError: ('weakref callback', (,)) +collect done +test finalize with exception in the callback +Unhandled exception in weakref callback: +ValueError: ('weakref callback', ()) +collect done diff --git a/tests/basics/weakref_finalize_basic.py b/tests/basics/weakref_finalize_basic.py new file mode 100644 index 00000000000..792cffacb13 --- /dev/null +++ b/tests/basics/weakref_finalize_basic.py @@ -0,0 +1,58 @@ +# Test weakref.finalize() functionality that doesn't require gc.collect(). + +try: + import weakref +except ImportError: + print("SKIP") + raise SystemExit + +# Cannot reference non-heap objects. +for value in (None, False, True, Ellipsis, 0, "", ()): + try: + weakref.finalize(value, lambda: None) + except TypeError: + print(value, "TypeError") + + +# Convert (obj, func, args, kwargs) so CPython and MicroPython have a chance to match. +def convert_4_tuple(values): + if values is None: + return None + return (type(values[0]).__name__, type(values[1]), values[2], values[3]) + + +class A: + def __str__(self): + return "" + + +print("test alive, peek, detach") +a = A() +f = weakref.finalize(a, lambda: None, 1, 2, kwarg=3) +print("alive", f.alive) +print("peek", convert_4_tuple(f.peek())) +print("detach", convert_4_tuple(f.detach())) +print("alive", f.alive) +print("peek", convert_4_tuple(f.peek())) +print("detach", convert_4_tuple(f.detach())) +print("call", f()) +a = None + +print("test alive, peek, call") +a = A() +f = weakref.finalize(a, lambda *args, **kwargs: (args, kwargs), 1, 2, kwarg=3) +print("alive", f.alive) +print("peek", convert_4_tuple(f.peek())) +print("call", f()) +print("alive", f.alive) +print("peek", convert_4_tuple(f.peek())) +print("call", f()) +print("detach", convert_4_tuple(f.detach())) + +print("test call which raises exception") +a = A() +f = weakref.finalize(a, lambda: 1 / 0) +try: + f() +except ZeroDivisionError as er: + print("call ZeroDivisionError") diff --git a/tests/basics/weakref_finalize_collect.py b/tests/basics/weakref_finalize_collect.py new file mode 100644 index 00000000000..f6e7c14843e --- /dev/null +++ b/tests/basics/weakref_finalize_collect.py @@ -0,0 +1,76 @@ +# Test weakref.finalize() functionality requiring gc.collect(). +# Should be kept in sync with tests/ports/webassembly/weakref_finalize_collect.py. + +try: + import weakref +except ImportError: + print("SKIP") + raise SystemExit + +# gc module must be available if weakref is. +import gc + + +class A: + def __str__(self): + return "" + + +def callback(*args, **kwargs): + print("callback({}, {})".format(args, kwargs)) + return 42 + + +def test(): + print("test basic use of finalize() with a simple callback") + a = A() + f = weakref.finalize(a, callback) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + print("alive", f.alive) + print("peek", f.peek()) + print("detach", f.detach()) + print("call", f()) + + print("test that a callback is passed the correct values") + a = A() + f = weakref.finalize(a, callback, 1, 2, kwarg=3) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + print("alive", f.alive) + print("peek", f.peek()) + print("detach", f.detach()) + print("call", f()) + + print("test that calling the finalizer cancels the finalizer") + a = A() + f = weakref.finalize(a, callback) + print(f()) + print(a) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + + print("test that calling detach cancels the finalizer") + a = A() + f = weakref.finalize(a, callback) + print(len(f.detach())) + print(a) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + + print("test that finalize does not get collected before its ref does") + a = A() + weakref.finalize(a, callback) + clean_the_stack = [0, 0, 0, 0] + gc.collect() + print("free a") + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + + +test() diff --git a/tests/basics/weakref_multiple_refs.py b/tests/basics/weakref_multiple_refs.py new file mode 100644 index 00000000000..400e03a17c7 --- /dev/null +++ b/tests/basics/weakref_multiple_refs.py @@ -0,0 +1,36 @@ +# Test weakref when multiple weak references are active. +# +# This test has different output to CPython due to the order that MicroPython +# executes weak reference callbacks. + +try: + import weakref +except ImportError: + print("SKIP") + raise SystemExit + +# gc module must be available if weakref is. +import gc + + +class A: + def __str__(self): + return "" + + +def test(): + global r1, r2 # needed for webassembly port to retain references to them + + print("test having multiple ref and finalize objects referencing the same thing") + a = A() + r1 = weakref.ref(a, lambda r: print("ref1", r())) + f1 = weakref.finalize(a, lambda: print("finalize1")) + r2 = weakref.ref(a, lambda r: print("ref2", r())) + f2 = weakref.finalize(a, lambda: print("finalize2")) + print(r1(), f1.alive, r2(), f2.alive) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + + +test() diff --git a/tests/basics/weakref_multiple_refs.py.exp b/tests/basics/weakref_multiple_refs.py.exp new file mode 100644 index 00000000000..1f2d366f776 --- /dev/null +++ b/tests/basics/weakref_multiple_refs.py.exp @@ -0,0 +1,6 @@ +test having multiple ref and finalize objects referencing the same thing + True True +finalize2 +finalize1 +ref2 None +ref1 None diff --git a/tests/basics/weakref_ref_basic.py b/tests/basics/weakref_ref_basic.py new file mode 100644 index 00000000000..058045f6c33 --- /dev/null +++ b/tests/basics/weakref_ref_basic.py @@ -0,0 +1,14 @@ +# Test weakref.ref() functionality that doesn't require gc.collect(). + +try: + import weakref +except ImportError: + print("SKIP") + raise SystemExit + +# Cannot reference non-heap objects. +for value in (None, False, True, Ellipsis, 0, "", ()): + try: + weakref.ref(value) + except TypeError: + print(value, "TypeError") diff --git a/tests/basics/weakref_ref_collect.py b/tests/basics/weakref_ref_collect.py new file mode 100644 index 00000000000..0e8db977d77 --- /dev/null +++ b/tests/basics/weakref_ref_collect.py @@ -0,0 +1,69 @@ +# Test weakref.ref() functionality requiring gc.collect(). +# Should be kept in sync with tests/ports/webassembly/weakref_ref_collect.py. + +try: + import weakref +except ImportError: + print("SKIP") + raise SystemExit + +# gc module must be available if weakref is. +import gc + +# Cannot reference non-heap objects. +for value in (None, False, True, Ellipsis, 0, "", ()): + try: + weakref.ref(value) + except TypeError: + print(value, "TypeError") + + +class A: + def __str__(self): + return "" + + +def callback(r): + print("callback", r()) + + +def test(): + print("test basic use of ref() with only one argument") + a = A() + r = weakref.ref(a) + print(r()) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + print(r()) + + print("test use of ref() with a callback") + a = A() + r = weakref.ref(a, callback) + print(r()) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + print(r()) + + print("test when weakref gets collected before the object it refs") + a = A() + r = weakref.ref(a, callback) + print(r()) + r = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + a = None + + print("test a double reference") + a = A() + r1 = weakref.ref(a, callback) + r2 = weakref.ref(a, callback) + print(r1(), r2()) + a = None + clean_the_stack = [0, 0, 0, 0] + gc.collect() + print(r1(), r2()) + + +test() diff --git a/tests/circuitpython-manual/alarm/sleep_memory_persist.py b/tests/circuitpython-manual/alarm/sleep_memory_persist.py new file mode 100644 index 00000000000..39e6baafca7 --- /dev/null +++ b/tests/circuitpython-manual/alarm/sleep_memory_persist.py @@ -0,0 +1,100 @@ +"""Reproducer for https://github.com/adafruit/circuitpython/issues/10896 + +Copy to code.py. Sequences through test steps using sleep_memory to +track state. + +The test scoreboard is printed to the magtag e-ink display after every +run so the final display shows cumulative results. +""" + +import alarm +import binascii +import microcontroller +import struct +import supervisor +import time + +# Safe mode avoidance +# On boot CircuitPython writes a SAFE_MODE_USER guard to an RTC register, +# If a second boot occurs before 1000ms elapses then we enter safe mode. +# So, wait for 1000+1ms before calling microcontroller.reset(). +_SAFE_MODE_WINDOW_MS = 1000 + + +def _wait_for_safe_mode_window(): + elapsed_ms = time.monotonic() * 1000 + remaining = _SAFE_MODE_WINDOW_MS + 1 - elapsed_ms + if remaining > 0: + time.sleep(remaining / 1000) + + +# Test result enum +_UNTESTED = 0 +_PASS = 1 +_FAIL = 2 +_LABEL = {_UNTESTED: "-", _PASS: "PASS", _FAIL: "FAIL"} + +# CRC32-protected state in sleep_memory +# [magic:2][step:1][r_reset:1][r_reload:1][pad:1][crc32:4] +_MAGIC = 0xBE01 +_FMT = " board.D5 +# mic LRCL -> board.D6 +# mic DOUT -> board.D9 +# neopixel -> board.D10 +# +# The mic's 24-bit samples ride in 32-bit slots, so we use bit_depth=32 and +# an array.array("I", ...). For SPH0645 set left_justified=True. + +import array +import math +import time + +import board +import audioi2sin +import neopixel + +NUM_PIXELS = 30 +PIXEL_PIN = board.D10 + +SAMPLE_RATE = 16000 +SAMPLES_PER_FRAME = 512 # ~32 ms windows + +pixels = neopixel.NeoPixel(PIXEL_PIN, NUM_PIXELS, brightness=0.3, auto_write=False) + +mic = audioi2sin.I2SIn( + bit_clock=board.D5, + word_select=board.D6, + data=board.D9, + sample_rate=SAMPLE_RATE, + bit_depth=32, + mono=True, + left_justified=False, # set True for SPH0645LM4H +) + +buf = array.array("i", [0] * SAMPLES_PER_FRAME) + + +def wheel(pos): + pos = pos % 256 + if pos < 85: + return (pos * 3, 255 - pos * 3, 0) + if pos < 170: + pos -= 85 + return (255 - pos * 3, 0, pos * 3) + pos -= 170 + return (0, pos * 3, 255 - pos * 3) + + +# Smoothed noise floor + peak so the effect adapts to the room. +noise_floor = 2000.0 +peak = 20000.0 +hue = 0 +smoothed_level = 0.0 + +while True: + mic.record(buf, len(buf)) + + # Compute RMS of the window. + acc = 0 + for s in buf: + acc += s * s + rms = math.sqrt(acc / len(buf)) + + # Track a slow noise floor and a decaying peak for auto-gain. + noise_floor = 0.995 * noise_floor + 0.005 * rms + if rms > peak: + peak = rms + else: + peak *= 0.995 + if peak < noise_floor + 1000: + peak = noise_floor + 1000 + + level = (rms - noise_floor) / (peak - noise_floor) + if level < 0: + level = 0.0 + elif level > 1: + level = 1.0 + + # Smooth the bar so it doesn't jitter on every frame. + smoothed_level = 0.6 * smoothed_level + 0.4 * level + + lit = int(smoothed_level * NUM_PIXELS) + hue = (hue + 2) % 256 + + for i in range(NUM_PIXELS): + if i < lit: + r, g, b = wheel((hue + i * (256 // NUM_PIXELS)) % 256) + pixels[i] = (r, g, b) + else: + pixels[i] = (0, 0, 0) + pixels.show() + + time.sleep(0.005) diff --git a/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py new file mode 100644 index 00000000000..c381e272bf7 --- /dev/null +++ b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py @@ -0,0 +1,105 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# Record a longer I2S audio capture to a WAV file on an SD card. +# +# Produces /sd/recording.wav. Set left_justified=True for SPH0645LM4H mics. + +import array +import struct +import time + +import ulab.numpy as np +import board +import busio +import sdcardio +import storage +import audioi2sin + +# ---- Recording config ------------------------------------------------------ +SAMPLE_RATE = 16000 +RECORD_SECONDS = 10 +CHUNK_SAMPLES = 1024 # samples captured per record() call +OUTPUT_PATH = "/sd/talk.wav" + +# ---- Mount SD -------------------------------------------------------------- +spi = board.SPI() +sdcard = sdcardio.SDCard(spi, cs=board.D10, baudrate=24_000_000) +vfs = storage.VfsFat(sdcard) +storage.mount(vfs, "/sd") + +# ---- Mic ------------------------------------------------------------------- +# 24-bit MEMS mics ride in 32-bit slots. Downconvert each slot to a +# signed 16-bit PCM sample before writing. +mic = audioi2sin.I2SIn( + bit_clock=board.D5, + word_select=board.D6, + data=board.D9, + sample_rate=SAMPLE_RATE, + bit_depth=32, + mono=True, + left_justified=False, # True for SPH0645LM4H +) + +actual_rate = mic.sample_rate +print("Recording at", actual_rate, "Hz for", RECORD_SECONDS, "s ->", OUTPUT_PATH) + +raw = array.array("i", [0] * CHUNK_SAMPLES) +pcm16 = array.array("h", [0] * CHUNK_SAMPLES) + + +def write_wav_header(f, sample_rate, num_samples, bits_per_sample=16, channels=1): + byte_rate = sample_rate * channels * bits_per_sample // 8 + block_align = channels * bits_per_sample // 8 + data_size = num_samples * block_align + f.write(b"RIFF") + f.write(struct.pack("> 16 # take top 16 bits + pcm16[i] = s + # Write only the valid portion. + f.write(memoryview(pcm16)[:n]) + written += n + + elapsed = time.monotonic() - start + # Rewrite header now that we know the true sample count. + f.seek(0) + write_wav_header(f, actual_rate, written) + +storage.umount("/sd") + +print("Done. Wrote", written, "samples in", round(elapsed, 2), "s") diff --git a/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard_output_bit_depth.py b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard_output_bit_depth.py new file mode 100644 index 00000000000..cc2d2e78c29 --- /dev/null +++ b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard_output_bit_depth.py @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# Record a longer I2S audio capture to a WAV file on an SD card, using the +# `output_bit_depth` argument to have the driver downconvert each 32-bit slot +# to signed 16-bit PCM. Compared to `i2sin_record_sdcard.py`, this avoids the +# Python-side shift loop and writes directly from the recording buffer. +# +# Produces /sd/talk.wav. Set left_justified=True for SPH0645LM4H mics. + +import array +import struct +import time + +import board +import sdcardio +import storage +import audioi2sin + +# ---- Recording config ------------------------------------------------------ +SAMPLE_RATE = 16000 +RECORD_SECONDS = 10 +CHUNK_SAMPLES = 1024 # samples captured per record() call +OUTPUT_PATH = "/sd/talk.wav" + +# ---- Mount SD -------------------------------------------------------------- +spi = board.SPI() +sdcard = sdcardio.SDCard(spi, cs=board.D10, baudrate=24_000_000) +vfs = storage.VfsFat(sdcard) +storage.mount(vfs, "/sd") + +# ---- Mic ------------------------------------------------------------------- +# 24-bit MEMS mics ride in 32-bit slots. Ask the driver to downconvert each +# slot to a signed 16-bit PCM sample, so `record()` writes straight into a +# WAV-ready 'h' buffer. +mic = audioi2sin.I2SIn( + bit_clock=board.D5, + word_select=board.D6, + data=board.D9, + sample_rate=SAMPLE_RATE, + bit_depth=32, + output_bit_depth=16, + mono=True, + left_justified=False, # True for SPH0645LM4H +) + +actual_rate = mic.sample_rate +print("Recording at", actual_rate, "Hz for", RECORD_SECONDS, "s ->", OUTPUT_PATH) + +pcm16 = array.array("h", [0] * CHUNK_SAMPLES) + + +def write_wav_header(f, sample_rate, num_samples, bits_per_sample=16, channels=1): + byte_rate = sample_rate * channels * bits_per_sample // 8 + block_align = channels * bits_per_sample // 8 + data_size = num_samples * block_align + f.write(b"RIFF") + f.write(struct.pack(" **If using `run_serial_tests.py`** this step is done automatically — skip ahead. + +Copy the WAV test samples onto the board's `CIRCUITPY` drive root: + +``` +cp \ + tests/circuitpython-manual/audiocore/jeplayer-splash-8000-8bit-mono-unsigned.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-mono-signed.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-mono-signed.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-stereo-signed.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-stereo-signed.wav \ + /Volumes/CIRCUITPY/ +``` + +These five files cover every exercised code path: +- `8000-8bit-mono-unsigned` — 8-bit unsigned decode path, audibly lo-fi +- `8000-16bit-mono-signed` — 16-bit signed decode path at lowest sample rate +- `44100-16bit-mono-signed` — 16-bit at highest sample rate (DMA reconfiguration, audible quality difference) +- `8000-16bit-stereo-signed` — stereo decode path, left→A0, right→A1 +- `44100-16bit-stereo-signed` — stereo at 44.1 kHz + +The 16 kHz files in the audiocore test set are skipped because they exercise +no code paths beyond 8 kHz and 44.1 kHz. 24-bit WAVs are not supported by +`audiocore.WaveFile` and will raise `OSError` if loaded — they are omitted on +purpose. + +Copy the test scripts to the board as well (or paste them into the REPL): + +``` +cp tests/circuitpython-manual/audioio/wavefile_playback.py /Volumes/CIRCUITPY/ +cp tests/circuitpython-manual/audioio/wavefile_pause_resume.py /Volumes/CIRCUITPY/ +cp tests/circuitpython-manual/audioio/single_buffer_loop.py /Volumes/CIRCUITPY/ +cp tests/circuitpython-manual/audioio/stereo_playback.py /Volumes/CIRCUITPY/ +``` + +## Test 1 — WAV File Playback (`wavefile_playback.py`) *(automated)* + +Verifies that `AudioOut(board.A0)` can play WAV files at 8 kHz and 44.1 kHz +with 8-bit unsigned and 16-bit signed encodings. Stereo WAVs are played here +through the mono `AudioOut` (only the left channel is mixed to A0); the +stereo path is exercised separately in Test 5. + +**Note:** 24-bit WAV files are not supported by `audiocore.WaveFile` and will +print an `OSError` if any are present on the filesystem. That is expected. + +**Run from the REPL:** + +```python +import os +os.chdir("/") +exec(open("wavefile_playback.py").read()) +``` + +**Expected output (order may vary by filename sort):** + +``` +playing jeplayer-splash-44100-16bit-mono-signed.wav +playing jeplayer-splash-8000-16bit-mono-signed.wav +playing jeplayer-splash-8000-8bit-mono-unsigned.wav +done +``` + +**What to listen for:** + +- Each supported WAV plays the "jeplayer splash" jingle to completion before the next starts. +- No loud pops at the start or end of each file (the DAC ramp-in / ramp-out should suppress them). +- Audio pitch should match the sample rate: the 44100 Hz file sounds the most natural; the 8000 Hz file sounds lower fidelity. + +## Test 2 — Pause and Resume (`wavefile_pause_resume.py`) *(automated)* + +Verifies `AudioOut.pause()` / `AudioOut.resume()` by toggling every 100 ms during playback. The audio will sound choppy — that is intentional. + +**Run from the REPL:** + +```python +exec(open("wavefile_pause_resume.py").read()) +``` + +**Expected output (repeating for each WAV):** + +``` +playing with pause/resume: jeplayer-splash-44100-16bit-mono-signed.wav + paused + resumed + ... +playing with pause/resume: jeplayer-splash-8000-16bit-mono-signed.wav + paused + resumed + ... +playing with pause/resume: jeplayer-splash-8000-8bit-mono-unsigned.wav + paused + resumed + ... +done +``` + +**What to verify:** + +- The REPL prints alternating "paused" / "resumed" lines. +- Audio cuts in and out in sync with the prints. +- Playback eventually completes (the `while dac.playing` loop exits normally). +- No hard fault or hang. + +## Test 3 — Looping Sine Wave (`single_buffer_loop.py`) *(automated)* + +Verifies `RawSample` with `loop=True` and tests all four sample formats: +`unsigned 8-bit`, `signed 8-bit`, `unsigned 16-bit`, `signed 16-bit`. + +Each sample generates one cycle of a 440 Hz sine wave and loops for 1 second. + +**Run from the REPL:** + +```python +exec(open("single_buffer_loop.py").read()) +``` + +**Expected output:** + +``` +unsigned 8 bit + +signed 8 bit + +unsigned 16 bit + +signed 16 bit + +done +``` + +**What to listen for:** + +- A 440 Hz tone (concert A) for approximately 1 second for each format. +- All four formats use the same 8 kHz sample rate and should sound + essentially identical in pitch and volume — the test is comparing + format-conversion paths, not playback rates. +- No pops or glitches during the loop. +- Clean silence between tones (quiescent DAC value holds between `stop()` calls). + +## Test 4 — `deinit` and Re-init *(automated)* + +Verifies that `AudioOut` can be deconstructed and reconstructed without rebooting, and that pin A0 is properly released. + +```python +import audioio, analogio, board + +# Construct and immediately deinit AudioOut +dac = audioio.AudioOut(board.A0) +dac.deinit() + +# PA04 should now be free for AnalogOut +aout = analogio.AnalogOut(board.A0) +aout.value = 32768 # mid-scale +aout.deinit() + +# Re-create AudioOut on the same pin +dac2 = audioio.AudioOut(board.A0) +dac2.deinit() +print("pass") +``` + +**Expected output:** `pass` with no exceptions. + +## Test 5 — Stereo Playback (`stereo_playback.py`) *(automated)* + +Verifies that `AudioOut(board.A0, right_channel=board.A1)` drives both DAC +channels independently: left on **A0 (PA04, DAC_CH1)**, right on +**A1 (PA05, DAC_CH2)**, both clocked by TIM6. + +The script runs four phases in order: + +1. **Left-only 440 Hz tone** (~1 s) — only A0 should produce audio. +2. **Right-only 440 Hz tone** (~1 s) — only A1 should produce audio. +3. **Both-channel 440 Hz tone** (~1 s) — equal amplitude on both pins. +4. **Pan sweep L → R** (~3 s) — continuous equal-power (cos/sin) crossfade from A0 to A1 in a single non-looped buffer. +5. Then plays each stereo WAV (`44100` and `8000` Hz) in full. + +**Hardware required:** connect a stereo headphone/amp to A0 (left) and A1 +(right) with common ground, or scope-probe each pin separately. + +**Run from the REPL:** + +```python +import os +os.chdir("/") +exec(open("stereo_playback.py").read()) +``` + +**Expected output:** + +``` +channel test: left only +channel test: right only +channel test: both channels +pan sweep: left to right +playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav +playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav +done +``` + +**What to listen / look for:** + +- "left only" → tone in left ear, silence in right. +- "right only" → tone in right ear, silence in left. +- "both channels" → centered tone in both ears. +- "pan sweep" → tone smoothly travels left → right over ~3 s. +- Stereo WAVs play with proper L/R separation; no cross-contamination. +- On a scope: probing A0 and A1 simultaneously during phases 1 and 2 should + show one channel idle (mid-scale DC) while the other carries the sine. + +## Oscilloscope Checks (Optional) + +Each test script drives `board.D4` (pin D4) low at the start of each playback and high when it ends. This provides a clean trigger edge for a scope. + +- **Test 1:** Probe A0 — should show a sampled waveform at the correct sample rate. Probe D4 for a gate signal that spans the file duration. +- **Test 3:** Probe A0 — should show a 440 Hz staircase-sine at the DAC output (12-bit steps visible at 44.1 kHz; fewer at 8 kHz). A simple RC low-pass filter (1 kΩ + 100 nF) on the A0 output will smooth the staircase significantly. + +## Known Limitations + +- **Left channel must be A0 (PA04)**. Any other pin raises `ValueError: AudioOut requires pin A0 (PA04)`. +- **Right channel must be A1 (PA05)** when used. Any other pin raises `ValueError: AudioOut right channel requires pin A1 (PA05)`. +- **24-bit WAV files** are not supported by `audiocore.WaveFile` and will raise `OSError` when opened. +- Only one `AudioOut` instance can be active at a time. diff --git a/tests/circuitpython-manual/audioio/run_serial_tests.py b/tests/circuitpython-manual/audioio/run_serial_tests.py new file mode 100644 index 00000000000..9fbbe555592 --- /dev/null +++ b/tests/circuitpython-manual/audioio/run_serial_tests.py @@ -0,0 +1,582 @@ +#!/usr/bin/env python3 +""" +run_serial_tests.py — Automated REPL-based tests for STM32F405 audioio. + +Automates Tests 1–5 from README.md by: + 1. Copying WAV files and test scripts to the board via mpremote. + 2. Running each test on the device via the CircuitPython REPL. + 3. Comparing captured output to expected patterns and reporting PASS/FAIL. + +Usage: + python3 run_serial_tests.py + python3 run_serial_tests.py --port /dev/cu.usbmodemXXX + python3 run_serial_tests.py --circuitpy /Volumes/CIRCUITPY # macOS + python3 run_serial_tests.py --circuitpy /media/user/CIRCUITPY # Linux + python3 run_serial_tests.py --circuitpy D:\\ # Windows + python3 run_serial_tests.py --no-copy --tests 3,4 + +Requirements: + pip install mpremote +""" + +from __future__ import annotations + +import argparse +import os +import shutil +import subprocess +import sys +import time + +# --------------------------------------------------------------------------- +# Paths +# --------------------------------------------------------------------------- +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +REPO_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, "../../..")) +AUDIOCORE_DIR = os.path.join(REPO_ROOT, "tests", "circuitpython-manual", "audiocore") + +WAV_FILES = [ + "jeplayer-splash-8000-8bit-mono-unsigned.wav", + "jeplayer-splash-8000-16bit-mono-signed.wav", + "jeplayer-splash-44100-16bit-mono-signed.wav", + "jeplayer-splash-8000-16bit-stereo-signed.wav", + "jeplayer-splash-44100-16bit-stereo-signed.wav", +] + +TEST_SCRIPTS = [ + "wavefile_playback.py", + "wavefile_pause_resume.py", + "single_buffer_loop.py", + "stereo_playback.py", +] + +DEINIT_TEST_CODE = ( + "import audioio, analogio, board\n" + "dac = audioio.AudioOut(board.A0)\n" + "dac.deinit()\n" + "aout = analogio.AnalogOut(board.A0)\n" + "aout.value = 32768\n" + "aout.deinit()\n" + "dac2 = audioio.AudioOut(board.A0)\n" + "dac2.deinit()\n" + 'print("pass")\n' +) + +# --------------------------------------------------------------------------- +# mpremote helpers +# --------------------------------------------------------------------------- + + +def _mpremote(args: list, timeout: float = 30.0): + """Run an mpremote command, return (stdout, stderr). Raises on timeout.""" + try: + result = subprocess.run( + ["mpremote"] + args, + capture_output=True, + text=True, + timeout=timeout, + ) + return result.stdout, result.stderr + except subprocess.TimeoutExpired: + raise TimeoutError(f"mpremote timed out after {timeout}s") + except FileNotFoundError: + sys.exit("mpremote not found. Run: pip install mpremote") + + +# stderr substrings that indicate a transient host/USB issue worth retrying. +# Matched case-insensitively. CircuitPython USB-CDC briefly disappears during +# soft-reset and after some heavy DMA activity; mpremote's next invocation then +# either can't open the port or sees the kernel still holding the previous +# descriptor. +_RETRYABLE_STDERR = ( + "could not enter raw repl", + "failed to access", + "device not configured", + "errno 6", + "errno 16", + "resource busy", + "could not open", + "no such file or directory", + "serialexception", + "device disconnected", + "could not exclusively lock", +) + + +def _is_retryable(stderr: str) -> bool: + s = stderr.lower() + return any(needle in s for needle in _RETRYABLE_STDERR) + + +def _port_holders(port: str) -> list[str]: + """Return a human-readable list of processes holding *port* (Unix only). + + macOS / Linux only — uses `lsof`. Returns lines like "Code Helper (51298)". + Empty list when nothing holds the port or `lsof` is unavailable. + """ + if not port.startswith("/"): + return [] + holders: list[str] = [] + # Both /dev/cu.* (callout) and /dev/tty.* (dial-in) refer to the same UART + # on macOS — VS Code typically opens /dev/tty.* while we ask for /dev/cu.*, + # so check both. + candidates = {port} + if "/cu." in port: + candidates.add(port.replace("/cu.", "/tty.", 1)) + elif "/tty." in port: + candidates.add(port.replace("/tty.", "/cu.", 1)) + for path in candidates: + if not os.path.exists(path): + continue + try: + result = subprocess.run( + ["lsof", "-Fcp", path], + capture_output=True, + text=True, + timeout=5, + ) + except (FileNotFoundError, subprocess.TimeoutExpired): + return [] + pid = command = None + for line in result.stdout.splitlines(): + if line.startswith("p"): + pid = line[1:] + elif line.startswith("c"): + command = line[1:] + if pid: + holders.append(f"{command} (PID {pid}) on {path}") + pid = command = None + return holders + + +def _wait_for_port(port: str, timeout: float = 10.0) -> bool: + """Block until *port* exists in the filesystem, or *timeout* elapses. + + macOS / Linux expose serial ports as /dev nodes; Windows uses COMx which is + not a filesystem path, so on Windows we just sleep briefly and trust the + next mpremote call to surface the real error. + """ + if not port.startswith("/"): + time.sleep(0.5) + return True + deadline = time.time() + timeout + while time.time() < deadline: + if os.path.exists(port): + return True + time.sleep(0.1) + return False + + +def _interrupt_running_code(port: str, soft_reset: bool = False) -> None: + """Halt any code running on the device so mpremote can enter raw REPL. + + Strategy: + 1. Ctrl-C burst — usually breaks a busy print loop. + 2. Optional Ctrl-D soft reset, followed by a Ctrl-C flood through the + reboot window so code.py is interrupted *before* it gets busy again. + """ + try: + import serial # type: ignore[import-not-found] + except ImportError: + return + try: + with serial.Serial(port, 115200, timeout=0.1) as ser: + for _ in range(5): + ser.write(b"\x03") + ser.flush() + time.sleep(0.05) + if soft_reset: + ser.write(b"\x04") # Ctrl-D → soft reboot + ser.flush() + # Flood Ctrl-C while CircuitPython reboots so code.py can't + # get past its first iteration before we break in. + deadline = time.time() + 3.0 + while time.time() < deadline: + ser.write(b"\x03") + ser.flush() + time.sleep(0.05) + time.sleep(0.3) + ser.reset_input_buffer() + except (serial.SerialException, OSError): + pass + + +def find_port() -> str: + """Return the port of the first Adafruit device found by mpremote devs.""" + stdout, _ = _mpremote(["devs"]) + for line in stdout.splitlines(): + parts = line.split() + if not parts: + continue + # mpremote devs output: + # Filter for Adafruit VID (239a) + if any("239a" in p for p in parts): + return parts[0] + # Fall back to any USB serial port that isn't Bluetooth/wlan + for line in stdout.splitlines(): + parts = line.split() + if ( + parts + and parts[0].startswith("/dev/") + and "Bluetooth" not in line + and "wlan" not in line + ): + return parts[0] + raise RuntimeError( + "No board detected. Connect the board and/or pass --port.\n" + f"mpremote devs output:\n{stdout}" + ) + + +def find_circuitpy() -> str | None: + """Return the path to the mounted CIRCUITPY volume, or None if not found.""" + import platform + + system = platform.system() + + if system == "Darwin": + # Glob so a second CIRCUITPY volume (mounted as "CIRCUITPY 1") is found. + import glob + + candidates = sorted(glob.glob("/Volumes/CIRCUITPY*")) + elif system == "Windows": + # Scan all drive letters for a CIRCUITPY volume label. + import string + import ctypes + + candidates = [] + kernel32 = ctypes.windll.kernel32 # type: ignore[attr-defined] + buf = ctypes.create_unicode_buffer(256) + for letter in string.ascii_uppercase: + root = f"{letter}:\\" + if kernel32.GetVolumeInformationW(root, buf, 256, None, None, None, None, 0): + if buf.value == "CIRCUITPY": + candidates.append(root) + else: + # Linux: common udev/udisks mount points + candidates = ["/media/CIRCUITPY", "/run/media/CIRCUITPY"] + try: + import pwd + + user = pwd.getpwuid(os.getuid()).pw_name + candidates.insert(0, f"/run/media/{user}/CIRCUITPY") + candidates.insert(0, f"/media/{user}/CIRCUITPY") + except Exception: + pass + + for path in candidates: + if os.path.isdir(path): + return path + return None + + +def copy_files(port: str, circuitpy: str | None = None): + """Copy WAV samples and test scripts to the board.""" + mount = circuitpy or find_circuitpy() + if mount: + print(f"Copying files to board via {mount} ...") + else: + print("Copying files to board via mpremote ...") + files = [(os.path.join(AUDIOCORE_DIR, w), w) for w in WAV_FILES] + [ + (os.path.join(SCRIPT_DIR, s), s) for s in TEST_SCRIPTS + ] + # Check if device has enough space for test files + if mount: + needed = 0 + for src, dst in files: + if not os.path.exists(src): + continue + needed += os.path.getsize(src) + dest_path = os.path.join(mount, dst) + if os.path.exists(dest_path): + needed -= os.path.getsize(dest_path) + free = shutil.disk_usage(mount).free + if needed > free: + short = needed - free + print(f"ERROR: not enough space on {mount}.") + print(f" need: {needed / 1024:.1f} KiB") + print(f" free: {free / 1024:.1f} KiB") + print(f" short: {short / 1024:.1f} KiB") + print(f" Delete unrelated files (e.g. an old code.py or stale WAVs) and re-run.") + sys.exit(1) + missing = [] + for src, dst in files: + if not os.path.exists(src): + missing.append(src) + continue + if mount: + dest_path = os.path.join(mount, dst) + shutil.copy2(src, dest_path) + print(f" {dst} (copied)") + else: + stdout, stderr = _mpremote(["connect", port, "fs", "cp", src, f":/{dst}"], timeout=30) + if stderr and "Error" in stderr: + print(f" {dst} (FAILED: {stderr.strip()})") + else: + status = "up to date" if "Up to date" in stdout else "copied" + print(f" {dst} ({status})") + if missing: + print("WARNING: source files not found:") + for m in missing: + print(f" {m}") + print() + + +# --------------------------------------------------------------------------- +# Test runner +# --------------------------------------------------------------------------- + +PASS_TAG = "PASS" +FAIL_TAG = "FAIL" + + +def _check(condition: bool, message: str) -> bool: + print(f" [{PASS_TAG if condition else FAIL_TAG}] {message}") + return condition + + +def _run_exec(port: str, code: str, label: str, timeout: float, retries: int = 3): + """Execute *code* on the device via mpremote exec and print the output. + + Retries cover three failure modes: + * raw-REPL handshake blocked by a running code.py → Ctrl-C burst. + * Persistent handshake failure → soft-reset + Ctrl-C flood. + * Host-side serial drop ("device in use", "Errno 6", etc.) → wait for the + port node to re-appear, then retry. CircuitPython's USB-CDC can briefly + vanish after heavy DMA traffic or soft-reset. + """ + print(f"\n{'=' * 60}") + print(f" {label}") + print("=" * 60) + stdout = "" + stderr = "" + for attempt in range(retries + 1): + if not _wait_for_port(port, timeout=10.0): + print(f" [retry {attempt}/{retries}] port {port} not present — waited 10s") + continue + try: + stdout, stderr = _mpremote(["connect", port, "exec", code], timeout=timeout) + except TimeoutError as exc: + print(f" [FAIL] {exc}") + return False, "", "" + if not _is_retryable(stderr): + break + if attempt < retries: + handshake = "could not enter raw repl" in stderr.lower() + # Soft-reset only on persistent raw-REPL failures, not on host drops + # (a soft-reset there just makes the disconnect window longer). + escalate = handshake and attempt >= 1 + if handshake: + tactic = "soft-reset + Ctrl-C flood" if escalate else "Ctrl-C burst" + else: + tactic = f"port-drop recovery ({stderr.strip().splitlines()[-1] if stderr.strip() else '?'})" + print(f" [retry {attempt + 1}/{retries}] {tactic}") + _wait_for_port(port, timeout=10.0) + _interrupt_running_code(port, soft_reset=escalate) + time.sleep(0.5) + print("Output:") + for line in stdout.splitlines(): + print(f" {line}") + if stderr: + print("Stderr:") + for line in stderr.splitlines(): + print(f" {line}") + return True, stdout, stderr + + +def _settle_between_tests(port: str) -> None: + """Drain any lingering REPL output and wait for the port to be ready. + + CircuitPython occasionally re-enumerates its USB-CDC after a heavy test; + next mpremote call then races the kernel re-binding the tty. Polling for + the port node and then sending a Ctrl-C burst gives the host a clean + starting state before the next exec. + """ + _wait_for_port(port, timeout=10.0) + _interrupt_running_code(port, soft_reset=False) + time.sleep(0.3) + + +# --------------------------------------------------------------------------- +# Individual tests +# --------------------------------------------------------------------------- + + +def test1_wavefile_playback(port: str) -> bool: + code = 'exec(open("/wavefile_playback.py").read())' + ok, stdout, stderr = _run_exec( + port, code, "Test 1 — WAV File Playback (wavefile_playback.py)", timeout=180 + ) + if not ok: + return False + passed = True + for wav in sorted(WAV_FILES): + passed &= _check(f"playing {wav}" in stdout, f"played {wav}") + passed &= _check("OSError" not in stdout, "No OSError reported during playback") + passed &= _check("done" in stdout, "Script completed with 'done'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + +def test2_pause_resume(port: str) -> bool: + code = 'exec(open("/wavefile_pause_resume.py").read())' + ok, stdout, stderr = _run_exec( + port, code, "Test 2 — Pause / Resume (wavefile_pause_resume.py)", timeout=180 + ) + if not ok: + return False + passed = True + for wav in sorted(WAV_FILES): + passed &= _check( + f"playing with pause/resume: {wav}" in stdout, f"pause/resume header for {wav}" + ) + passed &= _check("paused" in stdout, "At least one 'paused' line printed") + passed &= _check("resumed" in stdout, "At least one 'resumed' line printed") + passed &= _check("TIMEOUT" not in stdout, "No pause/resume hang timeout") + passed &= _check("OSError" not in stdout, "No OSError reported during playback") + passed &= _check("done" in stdout, "Script completed with 'done'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + +def test3_single_buffer_loop(port: str) -> bool: + code = 'exec(open("/single_buffer_loop.py").read())' + ok, stdout, stderr = _run_exec( + port, code, "Test 3 — Looping Sine Wave (single_buffer_loop.py)", timeout=30 + ) + if not ok: + return False + passed = True + for label in ("unsigned 8 bit", "signed 8 bit", "unsigned 16 bit", "signed 16 bit"): + passed &= _check(label in stdout, f"'{label}' label printed") + passed &= _check("done" in stdout, "Script completed with 'done'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + +def test5_stereo_playback(port: str) -> bool: + code = 'exec(open("/stereo_playback.py").read())' + ok, stdout, stderr = _run_exec( + port, code, "Test 5 — Stereo Playback (stereo_playback.py)", timeout=180 + ) + if not ok: + return False + passed = True + passed &= _check("channel test: left only" in stdout, "Left-only channel tone played") + passed &= _check("channel test: right only" in stdout, "Right-only channel tone played") + passed &= _check("channel test: both channels" in stdout, "Both-channel tone played") + passed &= _check("pan sweep: left to right" in stdout, "Pan sweep played") + passed &= _check( + "playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav" in stdout, + "44100 Hz 16-bit stereo WAV played", + ) + passed &= _check( + "playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav" in stdout, + "8000 Hz 16-bit stereo WAV played", + ) + passed &= _check("done" in stdout, "Script completed with 'done'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + +def test4_deinit(port: str) -> bool: + ok, stdout, stderr = _run_exec( + port, DEINIT_TEST_CODE, "Test 4 — deinit and Re-init (inline)", timeout=10 + ) + if not ok: + return False + passed = True + passed &= _check("pass" in stdout, "Script printed 'pass'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + + +def main(): + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + parser.add_argument("--port", help="Serial port (auto-detected if omitted)") + parser.add_argument( + "--circuitpy", + metavar="PATH", + help="Path to mounted CIRCUITPY volume (auto-detected if omitted)", + ) + parser.add_argument( + "--no-copy", + action="store_true", + help="Skip copying files to the board (assume they are already present)", + ) + parser.add_argument( + "--tests", + default="1,2,3,4,5", + help="Comma-separated list of test numbers to run (default: 1,2,3,4,5)", + ) + args = parser.parse_args() + + selected = set(args.tests.split(",")) + + port = args.port or find_port() + print(f"Using port: {port}\n") + + # Surface the common "VS Code has the serial monitor open" pitfall up front + # — otherwise every test fails with the opaque "in use by another program". + holders = _port_holders(port) + if holders: + print("ERROR: port is held by another process:") + for h in holders: + print(f" {h}") + print( + "Close the offending app (e.g. VS Code Serial Monitor, screen, tio)\n" + "and re-run. mpremote needs exclusive access." + ) + sys.exit(2) + + if not args.no_copy: + copy_files(port, circuitpy=args.circuitpy) + + # Halt any running code.py so the first test gets a clean raw-REPL entry. + _interrupt_running_code(port) + + test_runners = [ + ("1", "Test 1 — WAV Playback", test1_wavefile_playback), + ("2", "Test 2 — Pause/Resume", test2_pause_resume), + ("3", "Test 3 — Looping Sine", test3_single_buffer_loop), + ("4", "Test 4 — deinit/Re-init", test4_deinit), + ("5", "Test 5 — Stereo Playback", test5_stereo_playback), + ] + results: dict[str, bool] = {} + first = True + for key, name, runner in test_runners: + if key not in selected: + continue + if not first: + _settle_between_tests(port) + first = False + results[name] = runner(port) + + print(f"\n{'=' * 60}") + print("SUMMARY") + print("=" * 60) + all_passed = True + for name, passed in results.items(): + print(f" [{'PASS' if passed else 'FAIL'}] {name}") + all_passed = all_passed and passed + + print() + if all_passed: + print("All automated tests passed.") + print("Remaining manual step: audio/oscilloscope verification.") + sys.exit(0) + else: + print("One or more tests FAILED — see details above.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/tests/circuitpython-manual/audioio/single_buffer_loop.py b/tests/circuitpython-manual/audioio/single_buffer_loop.py new file mode 100644 index 00000000000..4a4c4304275 --- /dev/null +++ b/tests/circuitpython-manual/audioio/single_buffer_loop.py @@ -0,0 +1,62 @@ +import audiocore +import audioio +import board +import digitalio +import array +import time +import math + +# Optional trigger pin for oscilloscope synchronisation. +try: + trigger = digitalio.DigitalInOut(board.D4) + trigger.switch_to_output(True) +except AttributeError: + trigger = None + +# Generate one period of a 440 Hz sine wave. All four samples use the same +# sample rate so each plays the same audible pitch — the test is comparing +# the four format-conversion paths, not playback rates. +sample_rate = 8000 +length = sample_rate // 440 # samples per cycle + +sample_names = ["unsigned 8 bit", "signed 8 bit", "unsigned 16 bit", "signed 16 bit"] + +# unsigned 8 bit +u8 = array.array("B", [0] * length) +for i in range(length): + u8[i] = int(math.sin(math.pi * 2 * i / length) * 127 + 128) +samples = [audiocore.RawSample(u8, sample_rate=sample_rate)] + +# signed 8 bit +s8 = array.array("b", [0] * length) +for i in range(length): + s8[i] = int(math.sin(math.pi * 2 * i / length) * 127) +samples.append(audiocore.RawSample(s8, sample_rate=sample_rate)) + +# unsigned 16 bit +u16 = array.array("H", [0] * length) +for i in range(length): + u16[i] = int(math.sin(math.pi * 2 * i / length) * 32767 + 32768) +samples.append(audiocore.RawSample(u16, sample_rate=sample_rate)) + +# signed 16 bit +s16 = array.array("h", [0] * length) +for i in range(length): + s16[i] = int(math.sin(math.pi * 2 * i / length) * 32767) +samples.append(audiocore.RawSample(s16, sample_rate=sample_rate)) + +dac = audioio.AudioOut(board.A0) +for sample, name in zip(samples, sample_names): + print(name) + if trigger: + trigger.value = False + dac.play(sample, loop=True) + time.sleep(1) + dac.stop() + time.sleep(0.1) + if trigger: + trigger.value = True + print() + +dac.deinit() +print("done") diff --git a/tests/circuitpython-manual/audioio/stereo_playback.py b/tests/circuitpython-manual/audioio/stereo_playback.py new file mode 100644 index 00000000000..cfdb4d39540 --- /dev/null +++ b/tests/circuitpython-manual/audioio/stereo_playback.py @@ -0,0 +1,128 @@ +import audiocore +import audioio +import board +import digitalio +import array +import gc +import math +import time +import os + +# Optional trigger pin for oscilloscope synchronisation. +try: + trigger = digitalio.DigitalInOut(board.D4) + trigger.switch_to_output(True) +except AttributeError: + trigger = None + +dac = audioio.AudioOut(board.A0, right_channel=board.A1) + +# --------------------------------------------------------------------------- +# Channel-isolation tones: prove each DAC channel can be driven independently. +# Listener should hear the 440 Hz tone shift between ears. +# --------------------------------------------------------------------------- +sample_rate = 8000 +freq = 440 +length = sample_rate // freq +sine = [int(math.sin(2 * math.pi * i / length) * 16000) for i in range(length)] +silence = [0] * length + + +def stereo_buffer(left, right): + buf = array.array("h", [0] * (len(left) * 2)) + for i in range(len(left)): + buf[2 * i] = left[i] + buf[2 * i + 1] = right[i] + return buf + + +channel_tests = ( + ("left only", sine, silence), + ("right only", silence, sine), + ("both channels", sine, sine), +) + +for label, left, right in channel_tests: + print("channel test:", label) + sample = audiocore.RawSample( + stereo_buffer(left, right), channel_count=2, sample_rate=sample_rate + ) + if trigger: + trigger.value = False + dac.play(sample, loop=True) + time.sleep(1.0) + dac.stop() + if trigger: + trigger.value = True + time.sleep(0.2) + del sample + print() + +del channel_tests, sine, silence + +# --------------------------------------------------------------------------- +# Pan sweep: continuous equal-power L→R over 2 s. Single non-looped buffer, +# played once for a smooth crossfade with no DMA restart clicks. +# +# Linear amplitude pan sounds like centred stereo at the midpoint because both +# channels are equally loud. Equal-power (cos/sin) pan keeps total energy +# constant so the source is perceived as moving rather than collapsing inwards. +# +# 2 s @ 4 kHz stereo 8-bit signed = 16000 bytes. Halving the sample rate keeps +# the buffer small while doubling perceived motion duration; 220 Hz at 4 kHz +# has the same samples-per-cycle as the earlier 440 Hz @ 8 kHz tones. +# --------------------------------------------------------------------------- +gc.collect() +pan_sr = sample_rate // 2 +pan_freq = freq // 2 +pan_seconds = 3 +pan_frames = pan_sr * pan_seconds +pan_buf = array.array("b", bytes(pan_frames * 2)) +two_pi_freq_over_sr = 2 * math.pi * pan_freq / pan_sr +half_pi = math.pi / 2 +for i in range(pan_frames): + s = math.sin(two_pi_freq_over_sr * i) + t = i / pan_frames # 0 → 1 + l_gain = math.cos(t * half_pi) + r_gain = math.sin(t * half_pi) + pan_buf[2 * i] = int(s * l_gain * 120) + pan_buf[2 * i + 1] = int(s * r_gain * 120) + +print("pan sweep: left to right") +pan_sample = audiocore.RawSample(pan_buf, channel_count=2, sample_rate=pan_sr) +if trigger: + trigger.value = False +dac.play(pan_sample) +while dac.playing: + time.sleep(0.05) +if trigger: + trigger.value = True +time.sleep(0.2) +print() + +# --------------------------------------------------------------------------- +# Stereo WAV files: full-content check. +# --------------------------------------------------------------------------- +sample_prefix = "jeplayer-splash" +wavs = sorted(fn for fn in os.listdir("/") if fn.startswith(sample_prefix) and "stereo" in fn) + +for filename in wavs: + print("playing stereo:", filename) + with open(filename, "rb") as sample_file: + try: + sample = audiocore.WaveFile(sample_file) + except OSError as e: + print(e) + continue + if trigger: + trigger.value = False + dac.play(sample) + while dac.playing: + time.sleep(0.1) + if trigger: + trigger.value = True + time.sleep(0.1) + print() + +dac.deinit() +print("done") diff --git a/tests/circuitpython-manual/audioio/wavefile_pause_resume.py b/tests/circuitpython-manual/audioio/wavefile_pause_resume.py new file mode 100644 index 00000000000..7661a828b26 --- /dev/null +++ b/tests/circuitpython-manual/audioio/wavefile_pause_resume.py @@ -0,0 +1,66 @@ +import audiocore +import audioio +import board +import digitalio +import time +import os + +# Optional trigger pin for oscilloscope synchronisation. +try: + trigger = digitalio.DigitalInOut(board.D4) + trigger.switch_to_output(True) +except AttributeError: + trigger = None + +sample_prefix = "jeplayer-splash" + +samples = [] +for fn in os.listdir("/"): + if fn.startswith(sample_prefix): + samples.append(fn) + +if not samples: + print( + "No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board." + ) + +dac = audioio.AudioOut(board.A0) +for filename in sorted(samples): + print("playing with pause/resume:", filename) + with open(filename, "rb") as sample_file: + try: + sample = audiocore.WaveFile(sample_file) + except OSError as e: + print(e) + continue + if trigger: + trigger.value = False + dac.play(sample) + # Deliberately toggle pause/resume every 100 ms to stress-test the + # pause/resume cycle. Audio will sound choppy — that is expected. + # The wall-clock guard makes the test fail loudly instead of hanging + # if pause() ever leaves the driver in a state where playing never + # clears. 30 s is enough for the longest 44.1 kHz mono WAV in the + # set even with pause-doubling. + deadline = time.monotonic() + 30.0 + while dac.playing: + if time.monotonic() > deadline: + print(" TIMEOUT waiting for playback to finish") + dac.stop() + break + time.sleep(0.1) + if not dac.playing: # may have finished during sleep + break + if not dac.paused: + dac.pause() + print(" paused") + else: + dac.resume() + print(" resumed") + if trigger: + trigger.value = True + time.sleep(0.1) + print() + +dac.deinit() +print("done") diff --git a/tests/circuitpython-manual/audioio/wavefile_playback.py b/tests/circuitpython-manual/audioio/wavefile_playback.py new file mode 100644 index 00000000000..a7800c54ddc --- /dev/null +++ b/tests/circuitpython-manual/audioio/wavefile_playback.py @@ -0,0 +1,49 @@ +import audiocore +import audioio +import board +import digitalio +import time +import os + +# Optional trigger pin for oscilloscope synchronisation. +try: + trigger = digitalio.DigitalInOut(board.D4) + trigger.switch_to_output(True) +except AttributeError: + trigger = None + +# List WAV files from the audiocore test samples directory on the device. +# Copy tests/circuitpython-manual/audiocore/*.wav to the board's filesystem. +sample_prefix = "jeplayer-splash" + +samples = [] +for fn in os.listdir("/"): + if fn.startswith(sample_prefix): + samples.append(fn) + +if not samples: + print( + "No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board." + ) + +dac = audioio.AudioOut(board.A0) +for filename in sorted(samples): + print("playing", filename) + with open(filename, "rb") as sample_file: + try: + sample = audiocore.WaveFile(sample_file) + except OSError as e: + print(e) + continue + if trigger: + trigger.value = False + dac.play(sample) + while dac.playing: + time.sleep(0.1) + if trigger: + trigger.value = True + time.sleep(0.1) + print() + +dac.deinit() +print("done") diff --git a/tests/circuitpython-manual/rp2pio/README.md b/tests/circuitpython-manual/rp2pio/README.md new file mode 100644 index 00000000000..de67cf203d2 --- /dev/null +++ b/tests/circuitpython-manual/rp2pio/README.md @@ -0,0 +1,44 @@ +# rp2pio + audio DMA shared-IRQ manual tests + +These programs exercise the `DMA_IRQ_0` interrupt handlers on the RP2040 / +RP2350, which are shared between `audiocore`/`audiopwmio` (audio DMA) and +`rp2pio` (PIO background read/write DMA). + +They were written to validate the change in issue #9992 (moving `audio_dma.c` +off the fixed `isr_dma_0()` linker symbol and onto `irq_add_shared_handler()`, +with `rp2pio` registering its own shared handler). **They use only public APIs +that predate that change, so each program should behave identically before and +after it** — that is the point: they are regression tests, not feature tests. + +## What each program covers + +| Program | Audio DMA | PIO write DMA | PIO read DMA | +|---|---|---|---| +| `pio_background_write.py` | | ✓ | | +| `audio_dma_shared_irq_write.py` | ✓ | ✓ | | +| `audio_dma_shared_irq_loopback.py` | ✓ | ✓ | ✓ | + +Each goes through the background-DMA path (`background_write` / +`background_read`), which is interrupt-driven. The blocking `write`/`readinto`/ +`write_readinto` calls poll instead and do **not** use the DMA IRQ, so they are +deliberately not used here. The audio sample is created with +`single_buffer=False` so audio also uses the interrupt-driven (double-buffered) +DMA path rather than the no-interrupt single-buffer chaining path. + +## Wiring (Raspberry Pi Pico / Pico 2) + +- `GP13` — PWM audio output. Connect to an amplifier/speaker, or just leave it; + the test does not require you to hear anything, only that playback keeps + running. +- `GP2` — PIO output pin. +- `GP3` — PIO input pin (loopback test only). For a meaningful loopback, + connect `GP2` to `GP3` with a jumper. Without the jumper the read still + completes (it just reads whatever the floating/pulled pin sees), so the DMA + path is still exercised. + +## Running + +Copy one file at a time to `CIRCUITPY/code.py` and watch the serial console. +A successful run ends with a `PASS:` line. A hang (no further output) or a +`RuntimeError`/crash/safe-mode indicates a regression in the shared DMA IRQ +handling. diff --git a/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_loopback.py b/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_loopback.py new file mode 100644 index 00000000000..ba8ebbb589d --- /dev/null +++ b/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_loopback.py @@ -0,0 +1,85 @@ +"""Audio + rp2pio background write AND read sharing DMA_IRQ_0. + +Exercises all three DMA_IRQ_0 dispatch arms at once: + * audio playback (double-buffered, interrupt-driven), + * a continuous PIO background_write (write-completion interrupts), and + * repeated PIO background_read one-shots (read-completion interrupts). + +The continuous background_write keeps the state machine clocking so the read +side always has data to capture. Each background_read is a one-shot whose +completion is detected by polling `StateMachine.reading`; if that never clears, +the read-completion interrupt is not being serviced (a regression). Audio must +also keep playing throughout. + +Wiring: PWM audio on GP13 (speaker optional), PIO output on GP2, PIO input on +GP3. Jumper GP2 -> GP3 for a true loopback (then the captured data reflects what +was written); without the jumper the read still completes, so the DMA path is +still exercised. +""" + +import array +import math +import time + +import audiocore +import audiopwmio +import board +import rp2pio + +# --- Audio: signed-16 sine wave, double-buffered so it uses the DMA IRQ path. +SAMPLE_RATE = 16000 +SAMPLE_COUNT = 4000 # even count (required for single_buffer=False) +PERIODS = 32 +sine = array.array("h", [0] * SAMPLE_COUNT) +for i in range(SAMPLE_COUNT): + sine[i] = int(math.sin(2 * math.pi * PERIODS * i / SAMPLE_COUNT) * (2**14)) +sample = audiocore.RawSample(sine, sample_rate=SAMPLE_RATE, single_buffer=False) + +audio = audiopwmio.PWMAudioOut(board.GP13) +audio.play(sample, loop=True) +print("audio playing:", audio.playing) + +# --- PIO loopback program (hand assembled): +# .wrap_target +# out pins, 1 ; 0x6001 shift one bit OSR -> output pin (GP2) +# in pins, 1 ; 0x4001 shift one bit input pin (GP3) -> ISR +# .wrap +# auto_pull/auto_push at 32 bits keep both FIFOs (and their DMA) moving. +PROGRAM = array.array("H", [0x6001, 0x4001]) +sm = rp2pio.StateMachine( + PROGRAM, + frequency=2_000_000, + first_out_pin=board.GP2, + first_in_pin=board.GP3, + auto_pull=True, + pull_threshold=32, + out_shift_right=True, + auto_push=True, + push_threshold=32, + in_shift_right=True, +) + +out_buf = array.array("I", [0x0F0F0F0F] * 1024) +in_buf = array.array("I", [0] * 1024) + +# Continuous background write to keep the state machine clocking. +sm.background_write(loop=out_buf) + +ITERATIONS = 100 +for n in range(ITERATIONS): + sm.background_read(once=in_buf) + deadline = time.monotonic() + 2.0 + while sm.reading and time.monotonic() < deadline: + pass + if sm.reading: + raise RuntimeError(f"background_read stuck on iteration {n} (shared DMA IRQ wedged?)") + if not audio.playing: + raise RuntimeError(f"audio stopped unexpectedly on iteration {n}") + if n % 20 == 0: + print("iteration", n, "audio.playing", audio.playing, "first read word", hex(in_buf[0])) + +sm.stop_background_write() +audio.stop() +sm.deinit() +audio.deinit() +print("PASS: audio + rp2pio background write/read shared DMA_IRQ_0 for", ITERATIONS, "iterations") diff --git a/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_write.py b/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_write.py new file mode 100644 index 00000000000..fe00df06815 --- /dev/null +++ b/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_write.py @@ -0,0 +1,67 @@ +"""Audio playback + rp2pio background_write sharing DMA_IRQ_0. + +This is the scenario from issue #9868: audio output and a PIO peripheral (e.g. a +status NeoPixel) both want DMA completion interrupts at the same time. Audio +uses the interrupt-driven double-buffered path (`single_buffer=False`) and +rp2pio uses background_write, so both subsystems are serviced by DMA_IRQ_0 +concurrently. + +The test passes if the PIO writes keep completing AND audio keeps playing for +the whole run. A hang, crash, or audio stopping early indicates a regression. + +Wiring: PWM audio on GP13 (speaker optional), PIO output on GP2 (no connection +required). +""" + +import array +import math +import time + +import audiocore +import audiopwmio +import board +import rp2pio + +# --- Audio: signed-16 sine wave, double-buffered so it uses the DMA IRQ path. +SAMPLE_RATE = 16000 +SAMPLE_COUNT = 4000 # even count (required for single_buffer=False), several periods +PERIODS = 32 +sine = array.array("h", [0] * SAMPLE_COUNT) +for i in range(SAMPLE_COUNT): + sine[i] = int(math.sin(2 * math.pi * PERIODS * i / SAMPLE_COUNT) * (2**14)) +sample = audiocore.RawSample(sine, sample_rate=SAMPLE_RATE, single_buffer=False) + +audio = audiopwmio.PWMAudioOut(board.GP13) +audio.play(sample, loop=True) +print("audio playing:", audio.playing) + +# --- PIO: drain program that clocks the TX FIFO out on GP2 (see +# pio_background_write.py for the encoding). +PROGRAM = array.array("H", [0x6001]) +sm = rp2pio.StateMachine( + PROGRAM, + frequency=2_000_000, + first_out_pin=board.GP2, + auto_pull=True, + pull_threshold=32, + out_shift_right=True, +) +data = array.array("I", [0x5555AAAA] * 4096) + +ITERATIONS = 100 +for n in range(ITERATIONS): + sm.background_write(once=data) + deadline = time.monotonic() + 2.0 + while sm.writing and time.monotonic() < deadline: + pass + if sm.writing: + raise RuntimeError(f"background_write stuck on iteration {n} (shared DMA IRQ wedged?)") + if not audio.playing: + raise RuntimeError(f"audio stopped unexpectedly on iteration {n}") + if n % 20 == 0: + print("iteration", n, "audio.playing", audio.playing) + +audio.stop() +sm.deinit() +audio.deinit() +print("PASS: audio + rp2pio background_write shared DMA_IRQ_0 for", ITERATIONS, "iterations") diff --git a/tests/circuitpython-manual/rp2pio/pio_background_write.py b/tests/circuitpython-manual/rp2pio/pio_background_write.py new file mode 100644 index 00000000000..796175da7b1 --- /dev/null +++ b/tests/circuitpython-manual/rp2pio/pio_background_write.py @@ -0,0 +1,53 @@ +"""Baseline: rp2pio background_write DMA only (no audio). + +Exercises the PIO *write* arm of the shared DMA_IRQ_0 handler, plus the +add/remove of the shared handler as the only channel comes and goes. + +Repeatedly starts a one-shot background write and waits for it to finish by +polling `StateMachine.writing`. If `writing` never clears, the DMA completion +interrupt is not being serviced (a regression). Ends with a PASS line. + +Wiring: PIO output on GP2 (no connection required). +""" + +import array +import time + +import board +import rp2pio + +# PIO program (hand assembled, no adafruit_pioasm dependency): +# .wrap_target +# out pins, 1 ; shift one bit from OSR to the output pin +# .wrap +# With auto_pull and pull_threshold=32, the OSR is refilled from the TX FIFO +# every 32 bits, so the FIFO (and therefore the DMA) drains continuously. +# Encoding of `out pins, 1`: opcode OUT=0b011, dest PINS=0b000, count 1 -> 0x6001 +PROGRAM = array.array("H", [0x6001]) + +sm = rp2pio.StateMachine( + PROGRAM, + frequency=2_000_000, + first_out_pin=board.GP2, + auto_pull=True, + pull_threshold=32, + out_shift_right=True, +) + +# 16 KB of data per transfer, enough that the DMA genuinely runs and completes +# via interrupt rather than fitting in the FIFO. +data = array.array("I", [0x5555AAAA] * 4096) + +ITERATIONS = 50 +for n in range(ITERATIONS): + sm.background_write(once=data) + deadline = time.monotonic() + 2.0 + while sm.writing and time.monotonic() < deadline: + pass + if sm.writing: + raise RuntimeError(f"background_write stuck on iteration {n} (DMA IRQ not serviced?)") + if n % 10 == 0: + print("iteration", n, "ok") + +sm.deinit() +print("PASS: rp2pio background_write completed", ITERATIONS, "times") diff --git a/tests/circuitpython-manual/settings/code.py b/tests/circuitpython-manual/settings/code.py new file mode 100644 index 00000000000..bebed3d11ae --- /dev/null +++ b/tests/circuitpython-manual/settings/code.py @@ -0,0 +1,66 @@ +# Test supervisor.get_setting() parsing of settings.toml values. +# Copy settings.toml to the root of the board, then run this script. +# All lines should print PASS. + +import math +import supervisor + + +def check(key, expected): + got = supervisor.get_setting(key) + if type(got) is not type(expected): + print( + f"FAIL {key}: expected type {type(expected).__name__}, got {type(got).__name__} ({got!r})" + ) + return + if isinstance(expected, float) and math.isnan(expected): + ok = math.isnan(got) + else: + ok = got == expected + if ok: + print(f"PASS {key}") + else: + print(f"FAIL {key}: expected {expected!r}, got {got!r}") + + +check("str_val", "hello") +check("int_val", 42) +check("neg_int_val", -7) +check("hex_int_val", 31) +check("bool_true", True) +check("bool_false", False) +check("float_val", 3.14) +check("neg_float_val", -1.5) +check("sci_float_val", 6.626e-34) +# math.nan and math.inf are not always available +check("pos_inf", float("inf")) +check("neg_inf", -float("inf")) +check("pos_nan", float("nan")) + + +def check_bad(key): + try: + got = supervisor.get_setting(key) + print(f"FAIL {key}: expected ValueError, got {got!r}") + except ValueError: + print(f"PASS {key} raises ValueError") + + +check_bad("bad_word") # unquoted non-boolean word +check_bad("bad_float_junk") # float with trailing garbage +check_bad("bad_inf_junk") # inf with trailing characters +check_bad("bad_lone_sign") # bare + with nothing after it + +# Missing key returns default +got = supervisor.get_setting("no_such_key", "default") +if got == "default": + print("PASS missing key default") +else: + print(f"FAIL missing key default: got {got!r}") + +# Invalid value raises ValueError +try: + supervisor.get_setting("str_val") # quoted string is valid + print("PASS str via get_setting") +except ValueError: + print("FAIL str via get_setting raised ValueError unexpectedly") diff --git a/tests/circuitpython-manual/settings/settings.toml b/tests/circuitpython-manual/settings/settings.toml new file mode 100644 index 00000000000..5df2d104afe --- /dev/null +++ b/tests/circuitpython-manual/settings/settings.toml @@ -0,0 +1,16 @@ +str_val = "hello" +bad_word = hello +bad_float_junk = 1.2abc +bad_inf_junk = infoo +bad_lone_sign = + +int_val = 42 +neg_int_val = -7 +hex_int_val = 0x1F +bool_true = true +bool_false = false +float_val = 3.14 +neg_float_val = -1.5 +sci_float_val = 6.626e-34 +pos_inf = inf +neg_inf = -inf +pos_nan = nan diff --git a/tests/circuitpython/audiofilter_distortion_soft_clip.py b/tests/circuitpython/audiofilter_distortion_soft_clip.py new file mode 100644 index 00000000000..cb19f85eaf8 --- /dev/null +++ b/tests/circuitpython/audiofilter_distortion_soft_clip.py @@ -0,0 +1,14 @@ +# soft_clip is declared MP_ARG_BOOL; asking for False should give back False, +# not whatever happened to be on the stack under the argument union. +from audiofilters import Distortion + +RATE = 8000 + + +def make(soft_clip): + return Distortion(soft_clip=soft_clip, sample_rate=RATE).soft_clip + + +print("default ", Distortion(sample_rate=RATE).soft_clip) +print("soft_clip=False ", make(False)) +print("soft_clip=True ", make(True)) diff --git a/tests/circuitpython/audiofilter_distortion_soft_clip.py.exp b/tests/circuitpython/audiofilter_distortion_soft_clip.py.exp new file mode 100644 index 00000000000..ce562574a19 --- /dev/null +++ b/tests/circuitpython/audiofilter_distortion_soft_clip.py.exp @@ -0,0 +1,3 @@ +default False +soft_clip=False False +soft_clip=True True diff --git a/tests/circuitpython/audiofilter_filter_reset_buffer.py b/tests/circuitpython/audiofilter_filter_reset_buffer.py new file mode 100644 index 00000000000..be66688a815 --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_reset_buffer.py @@ -0,0 +1,43 @@ +# audiofilters.Filter.reset_buffer() should leave no audio behind: a biquad +# reset should clear both its input and output history, not just the input. +import array +import math +from audiocore import get_buffer, reset_buffer, RawSample +from audiofilters import Filter +from synthio import Biquad, FilterMode + +RATE = 48000 +FRAMES = 1024 + + +def s16(data): + out = [] + for index in range(0, len(data) - 1, 2): + value = data[index] | (data[index + 1] << 8) + out.append(value - 65536 if value >= 32768 else value) + return out + + +loud = array.array( + "h", [int(30000 * math.sin(2 * math.pi * 200 * frame / RATE)) for frame in range(FRAMES)] +) +silence = array.array("h", [0] * FRAMES) + +biquad = Biquad(FilterMode.LOW_PASS, 800.0) +node = Filter( + filter=biquad, + sample_rate=RATE, + channel_count=1, + bits_per_sample=16, + samples_signed=True, + buffer_size=FRAMES * 2, +) + +node.play(RawSample(loud, sample_rate=RATE, channel_count=1), loop=True) +for _ in range(4): + get_buffer(node) # fill the filter's memory + +node.play(RawSample(silence, sample_rate=RATE, channel_count=1), loop=True) +reset_buffer(node) # what an AudioOut does on play() +first = s16(bytes(get_buffer(node)[1])) +print("peak after reset_buffer:", max(abs(value) for value in first)) diff --git a/tests/circuitpython/audiofilter_filter_reset_buffer.py.exp b/tests/circuitpython/audiofilter_filter_reset_buffer.py.exp new file mode 100644 index 00000000000..c272de65374 --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_reset_buffer.py.exp @@ -0,0 +1 @@ +peak after reset_buffer: 0 diff --git a/tests/circuitpython/audiofilter_filter_stereo.py b/tests/circuitpython/audiofilter_filter_stereo.py new file mode 100644 index 00000000000..f260286f931 --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_stereo.py @@ -0,0 +1,24 @@ +from audiofilters import Filter +from audiofilterhelper import synth_test, sine8k +from audiomixer import Mixer +from synthio import LFO + + +@synth_test +def stereo_filter(): + args = { + "bits_per_sample": 16, + "samples_signed": True, + "channel_count": 2, + } + effect = Filter(**args) + mixer = Mixer(**args) + mixer.voice[0].panning = LFO() + effect.play(mixer) + yield effect, [] + + mixer.play(sine8k, loop=True) + yield 40 + + mixer.stop_voice() + yield 20 diff --git a/tests/circuitpython/audiofilter_filter_stereo.py.exp b/tests/circuitpython/audiofilter_filter_stereo.py.exp new file mode 100644 index 00000000000..960c143a1ef --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_stereo.py.exp @@ -0,0 +1,15360 @@ +0 0.0 +1 0.0 +2 0.0 +3 0.0 +4 0.0 +5 0.0 +6 0.0 +7 0.0 +8 0.0 +9 0.0 +10 0.0 +11 0.0 +12 0.0 +13 0.0 +14 0.0 +15 0.0 +16 0.0 +17 0.0 +18 0.0 +19 0.0 +20 0.0 +21 0.0 +22 0.0 +23 0.0 +24 0.0 +25 0.0 +26 0.0 +27 0.0 +28 0.0 +29 0.0 +30 0.0 +31 0.0 +32 0.0 +33 0.0 +34 0.0 +35 0.0 +36 0.0 +37 0.0 +38 0.0 +39 0.0 +40 0.0 +41 0.0 +42 0.0 +43 0.0 +44 0.0 +45 0.0 +46 0.0 +47 0.0 +48 0.0 +49 0.0 +50 0.0 +51 0.0 +52 0.0 +53 0.0 +54 0.0 +55 0.0 +56 0.0 +57 0.0 +58 0.0 +59 0.0 +60 0.0 +61 0.0 +62 0.0 +63 0.0 +64 0.0 +65 0.0 +66 0.0 +67 0.0 +68 0.0 +69 0.0 +70 0.0 +71 0.0 +72 0.0 +73 0.0 +74 0.0 +75 0.0 +76 0.0 +77 0.0 +78 0.0 +79 0.0 +80 0.0 +81 0.0 +82 0.0 +83 0.0 +84 0.0 +85 0.0 +86 0.0 +87 0.0 +88 0.0 +89 0.0 +90 0.0 +91 0.0 +92 0.0 +93 0.0 +94 0.0 +95 0.0 +96 0.0 +97 0.0 +98 0.0 +99 0.0 +100 0.0 +101 0.0 +102 0.0 +103 0.0 +104 0.0 +105 0.0 +106 0.0 +107 0.0 +108 0.0 +109 0.0 +110 0.0 +111 0.0 +112 0.0 +113 0.0 +114 0.0 +115 0.0 +116 0.0 +117 0.0 +118 0.0 +119 0.0 +120 0.0 +121 0.0 +122 0.0 +123 0.0 +124 0.0 +125 0.0 +126 0.0 +127 0.0 +128 0.0 +129 0.0 +130 0.0 +131 0.0 +132 0.0 +133 0.0 +134 0.0 +135 0.0 +136 0.0 +137 0.0 +138 0.0 +139 0.0 +140 0.0 +141 0.0 +142 0.0 +143 0.0 +144 0.0 +145 0.0 +146 0.0 +147 0.0 +148 0.0 +149 0.0 +150 0.0 +151 0.0 +152 0.0 +153 0.0 +154 0.0 +155 0.0 +156 0.0 +157 0.0 +158 0.0 +159 0.0 +160 0.0 +161 0.0 +162 0.0 +163 0.0 +164 0.0 +165 0.0 +166 0.0 +167 0.0 +168 0.0 +169 0.0 +170 0.0 +171 0.0 +172 0.0 +173 0.0 +174 0.0 +175 0.0 +176 0.0 +177 0.0 +178 0.0 +179 0.0 +180 0.0 +181 0.0 +182 0.0 +183 0.0 +184 0.0 +185 0.0 +186 0.0 +187 0.0 +188 0.0 +189 0.0 +190 0.0 +191 0.0 +192 0.0 +193 0.0 +194 0.0 +195 0.0 +196 0.0 +197 0.0 +198 0.0 +199 0.0 +200 0.0 +201 0.0 +202 0.0 +203 0.0 +204 0.0 +205 0.0 +206 0.0 +207 0.0 +208 0.0 +209 0.0 +210 0.0 +211 0.0 +212 0.0 +213 0.0 +214 0.0 +215 0.0 +216 0.0 +217 0.0 +218 0.0 +219 0.0 +220 0.0 +221 0.0 +222 0.0 +223 0.0 +224 0.0 +225 0.0 +226 0.0 +227 0.0 +228 0.0 +229 0.0 +230 0.0 +231 0.0 +232 0.0 +233 0.0 +234 0.0 +235 0.0 +236 0.0 +237 0.0 +238 0.0 +239 0.0 +240 0.0 +241 0.0 +242 0.0 +243 0.0 +244 0.0 +245 0.0 +246 0.0 +247 0.0 +248 0.0 +249 0.0 +250 0.0 +251 0.0 +252 0.0 +253 0.0 +254 0.0 +255 0.0 +256 0.0 +257 0.0 +258 0.0101318359375 +259 0.010467529296875 +260 0.020263671875 +261 0.02093505859375 +262 0.0303955078125 +263 0.031402587890625 +264 0.04052734375 +265 0.0418701171875 +266 0.050628662109375 +267 0.05230712890625 +268 0.060760498046875 +269 0.062774658203125 +270 0.07086181640625 +271 0.073211669921875 +272 0.080963134765625 +273 0.083648681640625 +274 0.091064453125 +275 0.094085693359375 +276 0.101165771484375 +277 0.104522705078125 +278 0.111236572265625 +279 0.11492919921875 +280 0.12127685546875 +281 0.12530517578125 +282 0.131317138671875 +283 0.13568115234375 +284 0.141357421875 +285 0.14605712890625 +286 0.1513671875 +287 0.156402587890625 +288 0.161407470703125 +289 0.166748046875 +290 0.17138671875 +291 0.17706298828125 +292 0.18133544921875 +293 0.187347412109375 +294 0.1912841796875 +295 0.1976318359375 +296 0.201202392578125 +297 0.2078857421875 +298 0.21112060546875 +299 0.218109130859375 +300 0.22100830078125 +301 0.22833251953125 +302 0.230865478515625 +303 0.238525390625 +304 0.240692138671875 +305 0.2486572265625 +306 0.25048828125 +307 0.2587890625 +308 0.26025390625 +309 0.268890380859375 +310 0.27001953125 +311 0.278961181640625 +312 0.27972412109375 +313 0.28900146484375 +314 0.2894287109375 +315 0.29901123046875 +316 0.299072265625 +317 0.308990478515625 +318 0.3087158203125 +319 0.318939208984375 +320 0.31829833984375 +321 0.328826904296875 +322 0.327850341796875 +323 0.338714599609375 +324 0.337371826171875 +325 0.348541259765625 +326 0.34686279296875 +327 0.35833740234375 +328 0.356292724609375 +329 0.36810302734375 +330 0.365692138671875 +331 0.3778076171875 +332 0.37506103515625 +333 0.387481689453125 +334 0.3843994140625 +335 0.397125244140625 +336 0.3936767578125 +337 0.406707763671875 +338 0.402923583984375 +339 0.416259765625 +340 0.412109375 +341 0.425750732421875 +342 0.4212646484375 +343 0.435211181640625 +344 0.43035888671875 +345 0.444610595703125 +346 0.43939208984375 +347 0.453948974609375 +348 0.44842529296875 +349 0.4632568359375 +350 0.4573974609375 +351 0.4725341796875 +352 0.466278076171875 +353 0.481719970703125 +354 0.47515869140625 +355 0.490875244140625 +356 0.48394775390625 +357 0.499969482421875 +358 0.492706298828125 +359 0.509002685546875 +360 0.50140380859375 +361 0.51800537109375 +362 0.510040283203125 +363 0.52691650390625 +364 0.51861572265625 +365 0.535797119140625 +366 0.52716064453125 +367 0.54461669921875 +368 0.535614013671875 +369 0.5533447265625 +370 0.544036865234375 +371 0.562042236328125 +372 0.552398681640625 +373 0.5706787109375 +374 0.560699462890625 +375 0.579254150390625 +376 0.56890869140625 +377 0.587738037109375 +378 0.57708740234375 +379 0.59619140625 +380 0.585174560546875 +381 0.60455322265625 +382 0.59326171875 +383 0.612884521484375 +384 0.601226806640625 +385 0.621124267578125 +386 0.609100341796875 +387 0.6292724609375 +388 0.616973876953125 +389 0.63739013671875 +390 0.624725341796875 +391 0.645416259765625 +392 0.6324462890625 +393 0.65338134765625 +394 0.640106201171875 +395 0.661285400390625 +396 0.647674560546875 +397 0.669097900390625 +398 0.6551513671875 +399 0.676849365234375 +400 0.662567138671875 +401 0.68450927734375 +402 0.669921875 +403 0.692108154296875 +404 0.677215576171875 +405 0.699615478515625 +406 0.684417724609375 +407 0.707061767578125 +408 0.691558837890625 +409 0.714447021484375 +410 0.698577880859375 +411 0.721710205078125 +412 0.705596923828125 +413 0.72894287109375 +414 0.71246337890625 +415 0.736053466796875 +416 0.71929931640625 +417 0.74310302734375 +418 0.726043701171875 +419 0.75006103515625 +420 0.732696533203125 +421 0.7569580078125 +422 0.739288330078125 +423 0.763763427734375 +424 0.74578857421875 +425 0.770477294921875 +426 0.752197265625 +427 0.777099609375 +428 0.758544921875 +429 0.783660888671875 +430 0.76483154296875 +431 0.790130615234375 +432 0.770965576171875 +433 0.796478271484375 +434 0.77703857421875 +435 0.802764892578125 +436 0.7830810546875 +437 0.808990478515625 +438 0.788970947265625 +439 0.815093994140625 +440 0.7947998046875 +441 0.82110595703125 +442 0.800537109375 +443 0.8270263671875 +444 0.80621337890625 +445 0.8328857421875 +446 0.811767578125 +447 0.838623046875 +448 0.8172607421875 +449 0.84429931640625 +450 0.8226318359375 +451 0.849853515625 +452 0.827911376953125 +453 0.855316162109375 +454 0.8331298828125 +455 0.860687255859375 +456 0.8382568359375 +457 0.865997314453125 +458 0.843292236328125 +459 0.871185302734375 +460 0.848175048828125 +461 0.876251220703125 +462 0.85302734375 +463 0.881256103515625 +464 0.8577880859375 +465 0.88616943359375 +466 0.8624267578125 +467 0.890960693359375 +468 0.866973876953125 +469 0.895660400390625 +470 0.871429443359375 +471 0.9002685546875 +472 0.87579345703125 +473 0.90478515625 +474 0.88006591796875 +475 0.9091796875 +476 0.884246826171875 +477 0.91351318359375 +478 0.888336181640625 +479 0.917724609375 +480 0.89227294921875 +481 0.92181396484375 +482 0.89617919921875 +483 0.92584228515625 +484 0.899932861328125 +485 0.929718017578125 +486 0.90362548828125 +487 0.93353271484375 +488 0.907196044921875 +489 0.937225341796875 +490 0.91070556640625 +491 0.940826416015625 +492 0.914093017578125 +493 0.9443359375 +494 0.9173583984375 +495 0.947723388671875 +496 0.920562744140625 +497 0.951019287109375 +498 0.92364501953125 +499 0.954193115234375 +500 0.926605224609375 +501 0.957275390625 +502 0.929473876953125 +503 0.960235595703125 +504 0.9322509765625 +505 0.963104248046875 +506 0.9349365234375 +507 0.96588134765625 +508 0.9375 +509 0.968536376953125 +510 0.94000244140625 +511 0.971099853515625 +512 0.911224365234375 +513 0.973541259765625 +514 0.91339111328125 +515 0.975860595703125 +516 0.91546630859375 +517 0.97808837890625 +518 0.91748046875 +519 0.980224609375 +520 0.91937255859375 +521 0.98223876953125 +522 0.921173095703125 +523 0.984161376953125 +524 0.9228515625 +525 0.9859619140625 +526 0.924407958984375 +527 0.987640380859375 +528 0.9259033203125 +529 0.989227294921875 +530 0.927276611328125 +531 0.990692138671875 +532 0.928558349609375 +533 0.9920654296875 +534 0.929718017578125 +535 0.993316650390625 +536 0.930816650390625 +537 0.994476318359375 +538 0.931793212890625 +539 0.995513916015625 +540 0.93267822265625 +541 0.9964599609375 +542 0.933441162109375 +543 0.997283935546875 +544 0.934112548828125 +545 0.99798583984375 +546 0.934661865234375 +547 0.99859619140625 +548 0.93511962890625 +549 0.999114990234375 +550 0.93548583984375 +551 0.999481201171875 +552 0.93572998046875 +553 0.999755859375 +554 0.9359130859375 +555 0.99993896484375 +556 0.93597412109375 +557 0.999969482421875 +558 0.9359130859375 +559 0.99993896484375 +560 0.93572998046875 +561 0.999755859375 +562 0.93548583984375 +563 0.999481201171875 +564 0.93511962890625 +565 0.999114990234375 +566 0.934661865234375 +567 0.99859619140625 +568 0.934112548828125 +569 0.99798583984375 +570 0.933441162109375 +571 0.997283935546875 +572 0.93267822265625 +573 0.9964599609375 +574 0.931793212890625 +575 0.995513916015625 +576 0.930816650390625 +577 0.994476318359375 +578 0.929718017578125 +579 0.993316650390625 +580 0.928558349609375 +581 0.9920654296875 +582 0.927276611328125 +583 0.990692138671875 +584 0.9259033203125 +585 0.989227294921875 +586 0.924407958984375 +587 0.987640380859375 +588 0.9228515625 +589 0.9859619140625 +590 0.921173095703125 +591 0.984161376953125 +592 0.91937255859375 +593 0.98223876953125 +594 0.91748046875 +595 0.980224609375 +596 0.91546630859375 +597 0.97808837890625 +598 0.91339111328125 +599 0.975860595703125 +600 0.911224365234375 +601 0.973541259765625 +602 0.908935546875 +603 0.971099853515625 +604 0.906524658203125 +605 0.968536376953125 +606 0.904052734375 +607 0.96588134765625 +608 0.901458740234375 +609 0.963104248046875 +610 0.898773193359375 +611 0.960235595703125 +612 0.89599609375 +613 0.957275390625 +614 0.893096923828125 +615 0.954193115234375 +616 0.89013671875 +617 0.951019287109375 +618 0.887054443359375 +619 0.947723388671875 +620 0.883880615234375 +621 0.9443359375 +622 0.880615234375 +623 0.940826416015625 +624 0.877227783203125 +625 0.937225341796875 +626 0.873779296875 +627 0.93353271484375 +628 0.870208740234375 +629 0.929718017578125 +630 0.8665771484375 +631 0.92584228515625 +632 0.86279296875 +633 0.92181396484375 +634 0.858978271484375 +635 0.917724609375 +636 0.85504150390625 +637 0.91351318359375 +638 0.850982666015625 +639 0.9091796875 +640 0.84686279296875 +641 0.90478515625 +642 0.8426513671875 +643 0.9002685546875 +644 0.83831787109375 +645 0.895660400390625 +646 0.83392333984375 +647 0.890960693359375 +648 0.829437255859375 +649 0.88616943359375 +650 0.8248291015625 +651 0.881256103515625 +652 0.820159912109375 +653 0.876251220703125 +654 0.8154296875 +655 0.871185302734375 +656 0.810546875 +657 0.865997314453125 +658 0.80560302734375 +659 0.860687255859375 +660 0.800567626953125 +661 0.855316162109375 +662 0.795440673828125 +663 0.849853515625 +664 0.790252685546875 +665 0.84429931640625 +666 0.784942626953125 +667 0.838623046875 +668 0.779571533203125 +669 0.8328857421875 +670 0.774078369140625 +671 0.8270263671875 +672 0.7685546875 +673 0.82110595703125 +674 0.762908935546875 +675 0.815093994140625 +676 0.7572021484375 +677 0.808990478515625 +678 0.751373291015625 +679 0.802764892578125 +680 0.7454833984375 +681 0.796478271484375 +682 0.73956298828125 +683 0.790130615234375 +684 0.733489990234375 +685 0.783660888671875 +686 0.72735595703125 +687 0.777099609375 +688 0.721160888671875 +689 0.770477294921875 +690 0.714874267578125 +691 0.763763427734375 +692 0.70849609375 +693 0.7569580078125 +694 0.702056884765625 +695 0.75006103515625 +696 0.695526123046875 +697 0.74310302734375 +698 0.688934326171875 +699 0.736053466796875 +700 0.682281494140625 +701 0.72894287109375 +702 0.675506591796875 +703 0.721710205078125 +704 0.668701171875 +705 0.714447021484375 +706 0.66180419921875 +707 0.707061767578125 +708 0.654815673828125 +709 0.699615478515625 +710 0.647796630859375 +711 0.692108154296875 +712 0.64068603515625 +713 0.68450927734375 +714 0.633514404296875 +715 0.676849365234375 +716 0.626251220703125 +717 0.669097900390625 +718 0.61895751953125 +719 0.661285400390625 +720 0.611541748046875 +721 0.65338134765625 +722 0.604095458984375 +723 0.645416259765625 +724 0.596588134765625 +725 0.63739013671875 +726 0.5889892578125 +727 0.6292724609375 +728 0.58135986328125 +729 0.621124267578125 +730 0.573638916015625 +731 0.612884521484375 +732 0.56585693359375 +733 0.60455322265625 +734 0.558013916015625 +735 0.59619140625 +736 0.55010986328125 +737 0.587738037109375 +738 0.54217529296875 +739 0.579254150390625 +740 0.534149169921875 +741 0.5706787109375 +742 0.52606201171875 +743 0.562042236328125 +744 0.517913818359375 +745 0.5533447265625 +746 0.509735107421875 +747 0.54461669921875 +748 0.501495361328125 +749 0.535797119140625 +750 0.493194580078125 +751 0.52691650390625 +752 0.484832763671875 +753 0.51800537109375 +754 0.476409912109375 +755 0.509002685546875 +756 0.46795654296875 +757 0.499969482421875 +758 0.459442138671875 +759 0.490875244140625 +760 0.45086669921875 +761 0.481719970703125 +762 0.442291259765625 +763 0.4725341796875 +764 0.43359375 +765 0.4632568359375 +766 0.424896240234375 +767 0.453948974609375 +768 0.40191650390625 +769 0.444610595703125 +770 0.393402099609375 +771 0.435211181640625 +772 0.384857177734375 +773 0.425750732421875 +774 0.37628173828125 +775 0.416259765625 +776 0.367645263671875 +777 0.406707763671875 +778 0.358978271484375 +779 0.397125244140625 +780 0.350250244140625 +781 0.387481689453125 +782 0.341522216796875 +783 0.3778076171875 +784 0.332733154296875 +785 0.36810302734375 +786 0.32391357421875 +787 0.35833740234375 +788 0.3150634765625 +789 0.348541259765625 +790 0.306182861328125 +791 0.338714599609375 +792 0.2972412109375 +793 0.328826904296875 +794 0.288299560546875 +795 0.318939208984375 +796 0.279296875 +797 0.308990478515625 +798 0.270294189453125 +799 0.29901123046875 +800 0.26123046875 +801 0.28900146484375 +802 0.252166748046875 +803 0.278961181640625 +804 0.243072509765625 +805 0.268890380859375 +806 0.233917236328125 +807 0.2587890625 +808 0.224761962890625 +809 0.2486572265625 +810 0.215606689453125 +811 0.238525390625 +812 0.206390380859375 +813 0.22833251953125 +814 0.1971435546875 +815 0.218109130859375 +816 0.187896728515625 +817 0.2078857421875 +818 0.17864990234375 +819 0.1976318359375 +820 0.169342041015625 +821 0.187347412109375 +822 0.1600341796875 +823 0.17706298828125 +824 0.150726318359375 +825 0.166748046875 +826 0.141357421875 +827 0.156402587890625 +828 0.13201904296875 +829 0.14605712890625 +830 0.122650146484375 +831 0.13568115234375 +832 0.113250732421875 +833 0.12530517578125 +834 0.1038818359375 +835 0.11492919921875 +836 0.094482421875 +837 0.104522705078125 +838 0.08502197265625 +839 0.094085693359375 +840 0.075592041015625 +841 0.083648681640625 +842 0.066162109375 +843 0.073211669921875 +844 0.056732177734375 +845 0.062774658203125 +846 0.047271728515625 +847 0.05230712890625 +848 0.037841796875 +849 0.0418701171875 +850 0.02838134765625 +851 0.031402587890625 +852 0.0189208984375 +853 0.02093505859375 +854 0.00946044921875 +855 0.010467529296875 +856 0.0 +857 0.0 +858 -0.00946044921875 +859 -0.010467529296875 +860 -0.0189208984375 +861 -0.02093505859375 +862 -0.02838134765625 +863 -0.031402587890625 +864 -0.037841796875 +865 -0.0418701171875 +866 -0.047271728515625 +867 -0.05230712890625 +868 -0.056732177734375 +869 -0.062774658203125 +870 -0.066162109375 +871 -0.073211669921875 +872 -0.075592041015625 +873 -0.083648681640625 +874 -0.08502197265625 +875 -0.094085693359375 +876 -0.094482421875 +877 -0.104522705078125 +878 -0.1038818359375 +879 -0.11492919921875 +880 -0.113250732421875 +881 -0.12530517578125 +882 -0.122650146484375 +883 -0.13568115234375 +884 -0.13201904296875 +885 -0.14605712890625 +886 -0.141357421875 +887 -0.156402587890625 +888 -0.150726318359375 +889 -0.166748046875 +890 -0.1600341796875 +891 -0.17706298828125 +892 -0.169342041015625 +893 -0.187347412109375 +894 -0.17864990234375 +895 -0.1976318359375 +896 -0.187896728515625 +897 -0.2078857421875 +898 -0.1971435546875 +899 -0.218109130859375 +900 -0.206390380859375 +901 -0.22833251953125 +902 -0.215606689453125 +903 -0.238525390625 +904 -0.224761962890625 +905 -0.2486572265625 +906 -0.233917236328125 +907 -0.2587890625 +908 -0.243072509765625 +909 -0.268890380859375 +910 -0.252166748046875 +911 -0.278961181640625 +912 -0.26123046875 +913 -0.28900146484375 +914 -0.270294189453125 +915 -0.29901123046875 +916 -0.279296875 +917 -0.308990478515625 +918 -0.288299560546875 +919 -0.318939208984375 +920 -0.2972412109375 +921 -0.328826904296875 +922 -0.306182861328125 +923 -0.338714599609375 +924 -0.3150634765625 +925 -0.348541259765625 +926 -0.32391357421875 +927 -0.35833740234375 +928 -0.332733154296875 +929 -0.36810302734375 +930 -0.341522216796875 +931 -0.3778076171875 +932 -0.350250244140625 +933 -0.387481689453125 +934 -0.358978271484375 +935 -0.397125244140625 +936 -0.367645263671875 +937 -0.406707763671875 +938 -0.37628173828125 +939 -0.416259765625 +940 -0.384857177734375 +941 -0.425750732421875 +942 -0.393402099609375 +943 -0.435211181640625 +944 -0.40191650390625 +945 -0.444610595703125 +946 -0.41033935546875 +947 -0.453948974609375 +948 -0.41876220703125 +949 -0.4632568359375 +950 -0.427154541015625 +951 -0.4725341796875 +952 -0.435455322265625 +953 -0.481719970703125 +954 -0.4437255859375 +955 -0.490875244140625 +956 -0.45196533203125 +957 -0.499969482421875 +958 -0.460113525390625 +959 -0.509002685546875 +960 -0.46826171875 +961 -0.51800537109375 +962 -0.476318359375 +963 -0.52691650390625 +964 -0.484344482421875 +965 -0.535797119140625 +966 -0.4923095703125 +967 -0.54461669921875 +968 -0.500213623046875 +969 -0.5533447265625 +970 -0.508056640625 +971 -0.562042236328125 +972 -0.515869140625 +973 -0.5706787109375 +974 -0.52362060546875 +975 -0.579254150390625 +976 -0.531280517578125 +977 -0.587738037109375 +978 -0.5389404296875 +979 -0.59619140625 +980 -0.5465087890625 +981 -0.60455322265625 +982 -0.55401611328125 +983 -0.612884521484375 +984 -0.56146240234375 +985 -0.621124267578125 +986 -0.56884765625 +987 -0.6292724609375 +988 -0.576171875 +989 -0.63739013671875 +990 -0.58343505859375 +991 -0.645416259765625 +992 -0.59063720703125 +993 -0.65338134765625 +994 -0.5977783203125 +995 -0.661285400390625 +996 -0.604827880859375 +997 -0.669097900390625 +998 -0.611846923828125 +999 -0.676849365234375 +1000 -0.6187744140625 +1001 -0.68450927734375 +1002 -0.625640869140625 +1003 -0.692108154296875 +1004 -0.632415771484375 +1005 -0.699615478515625 +1006 -0.63916015625 +1007 -0.707061767578125 +1008 -0.645843505859375 +1009 -0.714447021484375 +1010 -0.65240478515625 +1011 -0.721710205078125 +1012 -0.658935546875 +1013 -0.72894287109375 +1014 -0.665374755859375 +1015 -0.736053466796875 +1016 -0.6717529296875 +1017 -0.74310302734375 +1018 -0.67803955078125 +1019 -0.75006103515625 +1020 -0.68426513671875 +1021 -0.7569580078125 +1022 -0.6904296875 +1023 -0.763763427734375 +1024 -0.671844482421875 +1025 -0.770477294921875 +1026 -0.6776123046875 +1027 -0.777099609375 +1028 -0.683349609375 +1029 -0.783660888671875 +1030 -0.688995361328125 +1031 -0.790130615234375 +1032 -0.69451904296875 +1033 -0.796478271484375 +1034 -0.70001220703125 +1035 -0.802764892578125 +1036 -0.705413818359375 +1037 -0.808990478515625 +1038 -0.71075439453125 +1039 -0.815093994140625 +1040 -0.71600341796875 +1041 -0.82110595703125 +1042 -0.721160888671875 +1043 -0.8270263671875 +1044 -0.72625732421875 +1045 -0.8328857421875 +1046 -0.73126220703125 +1047 -0.838623046875 +1048 -0.7362060546875 +1049 -0.84429931640625 +1050 -0.741058349609375 +1051 -0.849853515625 +1052 -0.745819091796875 +1053 -0.855316162109375 +1054 -0.750518798828125 +1055 -0.860687255859375 +1056 -0.755126953125 +1057 -0.865997314453125 +1058 -0.759674072265625 +1059 -0.871185302734375 +1060 -0.764068603515625 +1061 -0.876251220703125 +1062 -0.7684326171875 +1063 -0.881256103515625 +1064 -0.772735595703125 +1065 -0.88616943359375 +1066 -0.77691650390625 +1067 -0.890960693359375 +1068 -0.781005859375 +1069 -0.895660400390625 +1070 -0.7850341796875 +1071 -0.9002685546875 +1072 -0.788970947265625 +1073 -0.90478515625 +1074 -0.79278564453125 +1075 -0.9091796875 +1076 -0.79656982421875 +1077 -0.91351318359375 +1078 -0.80023193359375 +1079 -0.917724609375 +1080 -0.803802490234375 +1081 -0.92181396484375 +1082 -0.80731201171875 +1083 -0.92584228515625 +1084 -0.810699462890625 +1085 -0.929718017578125 +1086 -0.81402587890625 +1087 -0.93353271484375 +1088 -0.8172607421875 +1089 -0.937225341796875 +1090 -0.820404052734375 +1091 -0.940826416015625 +1092 -0.823455810546875 +1093 -0.9443359375 +1094 -0.826416015625 +1095 -0.947723388671875 +1096 -0.82928466796875 +1097 -0.951019287109375 +1098 -0.83203125 +1099 -0.954193115234375 +1100 -0.834747314453125 +1101 -0.957275390625 +1102 -0.837310791015625 +1103 -0.960235595703125 +1104 -0.839813232421875 +1105 -0.963104248046875 +1106 -0.84222412109375 +1107 -0.96588134765625 +1108 -0.84454345703125 +1109 -0.968536376953125 +1110 -0.8468017578125 +1111 -0.971099853515625 +1112 -0.848907470703125 +1113 -0.973541259765625 +1114 -0.8509521484375 +1115 -0.975860595703125 +1116 -0.852874755859375 +1117 -0.97808837890625 +1118 -0.854736328125 +1119 -0.980224609375 +1120 -0.85650634765625 +1121 -0.98223876953125 +1122 -0.858184814453125 +1123 -0.984161376953125 +1124 -0.8597412109375 +1125 -0.9859619140625 +1126 -0.8612060546875 +1127 -0.987640380859375 +1128 -0.86260986328125 +1129 -0.989227294921875 +1130 -0.863861083984375 +1131 -0.990692138671875 +1132 -0.865081787109375 +1133 -0.9920654296875 +1134 -0.86614990234375 +1135 -0.993316650390625 +1136 -0.8671875 +1137 -0.994476318359375 +1138 -0.868072509765625 +1139 -0.995513916015625 +1140 -0.868896484375 +1141 -0.9964599609375 +1142 -0.86962890625 +1143 -0.997283935546875 +1144 -0.8702392578125 +1145 -0.99798583984375 +1146 -0.870758056640625 +1147 -0.99859619140625 +1148 -0.871185302734375 +1149 -0.999114990234375 +1150 -0.87152099609375 +1151 -0.999481201171875 +1152 -0.87176513671875 +1153 -0.999755859375 +1154 -0.871917724609375 +1155 -0.99993896484375 +1156 -0.871978759765625 +1157 -1.0 +1158 -0.871917724609375 +1159 -0.99993896484375 +1160 -0.87176513671875 +1161 -0.999755859375 +1162 -0.87152099609375 +1163 -0.999481201171875 +1164 -0.871185302734375 +1165 -0.999114990234375 +1166 -0.870758056640625 +1167 -0.99859619140625 +1168 -0.8702392578125 +1169 -0.99798583984375 +1170 -0.86962890625 +1171 -0.997283935546875 +1172 -0.868896484375 +1173 -0.9964599609375 +1174 -0.868072509765625 +1175 -0.995513916015625 +1176 -0.8671875 +1177 -0.994476318359375 +1178 -0.86614990234375 +1179 -0.993316650390625 +1180 -0.865081787109375 +1181 -0.9920654296875 +1182 -0.863861083984375 +1183 -0.990692138671875 +1184 -0.86260986328125 +1185 -0.989227294921875 +1186 -0.8612060546875 +1187 -0.987640380859375 +1188 -0.8597412109375 +1189 -0.9859619140625 +1190 -0.858184814453125 +1191 -0.984161376953125 +1192 -0.85650634765625 +1193 -0.98223876953125 +1194 -0.854736328125 +1195 -0.980224609375 +1196 -0.852874755859375 +1197 -0.97808837890625 +1198 -0.8509521484375 +1199 -0.975860595703125 +1200 -0.848907470703125 +1201 -0.973541259765625 +1202 -0.8468017578125 +1203 -0.971099853515625 +1204 -0.84454345703125 +1205 -0.968536376953125 +1206 -0.84222412109375 +1207 -0.96588134765625 +1208 -0.839813232421875 +1209 -0.963104248046875 +1210 -0.837310791015625 +1211 -0.960235595703125 +1212 -0.834747314453125 +1213 -0.957275390625 +1214 -0.83203125 +1215 -0.954193115234375 +1216 -0.82928466796875 +1217 -0.951019287109375 +1218 -0.826416015625 +1219 -0.947723388671875 +1220 -0.823455810546875 +1221 -0.9443359375 +1222 -0.820404052734375 +1223 -0.940826416015625 +1224 -0.8172607421875 +1225 -0.937225341796875 +1226 -0.81402587890625 +1227 -0.93353271484375 +1228 -0.810699462890625 +1229 -0.929718017578125 +1230 -0.80731201171875 +1231 -0.92584228515625 +1232 -0.803802490234375 +1233 -0.92181396484375 +1234 -0.80023193359375 +1235 -0.917724609375 +1236 -0.79656982421875 +1237 -0.91351318359375 +1238 -0.79278564453125 +1239 -0.9091796875 +1240 -0.788970947265625 +1241 -0.90478515625 +1242 -0.7850341796875 +1243 -0.9002685546875 +1244 -0.781005859375 +1245 -0.895660400390625 +1246 -0.77691650390625 +1247 -0.890960693359375 +1248 -0.772735595703125 +1249 -0.88616943359375 +1250 -0.7684326171875 +1251 -0.881256103515625 +1252 -0.764068603515625 +1253 -0.876251220703125 +1254 -0.759674072265625 +1255 -0.871185302734375 +1256 -0.755126953125 +1257 -0.865997314453125 +1258 -0.750518798828125 +1259 -0.860687255859375 +1260 -0.745819091796875 +1261 -0.855316162109375 +1262 -0.741058349609375 +1263 -0.849853515625 +1264 -0.7362060546875 +1265 -0.84429931640625 +1266 -0.73126220703125 +1267 -0.838623046875 +1268 -0.72625732421875 +1269 -0.8328857421875 +1270 -0.721160888671875 +1271 -0.8270263671875 +1272 -0.71600341796875 +1273 -0.82110595703125 +1274 -0.71075439453125 +1275 -0.815093994140625 +1276 -0.705413818359375 +1277 -0.808990478515625 +1278 -0.70001220703125 +1279 -0.802764892578125 +1280 -0.677001953125 +1281 -0.796478271484375 +1282 -0.671600341796875 +1283 -0.790130615234375 +1284 -0.666107177734375 +1285 -0.783660888671875 +1286 -0.6605224609375 +1287 -0.777099609375 +1288 -0.654876708984375 +1289 -0.770477294921875 +1290 -0.649169921875 +1291 -0.763763427734375 +1292 -0.643402099609375 +1293 -0.7569580078125 +1294 -0.637542724609375 +1295 -0.75006103515625 +1296 -0.631622314453125 +1297 -0.74310302734375 +1298 -0.625640869140625 +1299 -0.736053466796875 +1300 -0.619598388671875 +1301 -0.72894287109375 +1302 -0.613433837890625 +1303 -0.721710205078125 +1304 -0.607269287109375 +1305 -0.714447021484375 +1306 -0.600982666015625 +1307 -0.707061767578125 +1308 -0.59466552734375 +1309 -0.699615478515625 +1310 -0.588287353515625 +1311 -0.692108154296875 +1312 -0.581817626953125 +1313 -0.68450927734375 +1314 -0.5753173828125 +1315 -0.676849365234375 +1316 -0.5687255859375 +1317 -0.669097900390625 +1318 -0.56207275390625 +1319 -0.661285400390625 +1320 -0.55535888671875 +1321 -0.65338134765625 +1322 -0.548583984375 +1323 -0.645416259765625 +1324 -0.541778564453125 +1325 -0.63739013671875 +1326 -0.534881591796875 +1327 -0.6292724609375 +1328 -0.5279541015625 +1329 -0.621124267578125 +1330 -0.52093505859375 +1331 -0.612884521484375 +1332 -0.51385498046875 +1333 -0.60455322265625 +1334 -0.506744384765625 +1335 -0.59619140625 +1336 -0.49957275390625 +1337 -0.587738037109375 +1338 -0.492340087890625 +1339 -0.579254150390625 +1340 -0.485076904296875 +1341 -0.5706787109375 +1342 -0.47772216796875 +1343 -0.562042236328125 +1344 -0.4703369140625 +1345 -0.5533447265625 +1346 -0.462921142578125 +1347 -0.54461669921875 +1348 -0.455413818359375 +1349 -0.535797119140625 +1350 -0.4478759765625 +1351 -0.52691650390625 +1352 -0.440277099609375 +1353 -0.51800537109375 +1354 -0.432647705078125 +1355 -0.509002685546875 +1356 -0.424957275390625 +1357 -0.499969482421875 +1358 -0.417236328125 +1359 -0.490875244140625 +1360 -0.409454345703125 +1361 -0.481719970703125 +1362 -0.401641845703125 +1363 -0.4725341796875 +1364 -0.393768310546875 +1365 -0.4632568359375 +1366 -0.385833740234375 +1367 -0.453948974609375 +1368 -0.377899169921875 +1369 -0.444610595703125 +1370 -0.369903564453125 +1371 -0.435211181640625 +1372 -0.36187744140625 +1373 -0.425750732421875 +1374 -0.35382080078125 +1375 -0.416259765625 +1376 -0.345672607421875 +1377 -0.406707763671875 +1378 -0.337554931640625 +1379 -0.397125244140625 +1380 -0.329345703125 +1381 -0.387481689453125 +1382 -0.321136474609375 +1383 -0.3778076171875 +1384 -0.3128662109375 +1385 -0.36810302734375 +1386 -0.3045654296875 +1387 -0.35833740234375 +1388 -0.296234130859375 +1389 -0.348541259765625 +1390 -0.28790283203125 +1391 -0.338714599609375 +1392 -0.27947998046875 +1393 -0.328826904296875 +1394 -0.271087646484375 +1395 -0.318939208984375 +1396 -0.26263427734375 +1397 -0.308990478515625 +1398 -0.254150390625 +1399 -0.29901123046875 +1400 -0.245635986328125 +1401 -0.28900146484375 +1402 -0.237091064453125 +1403 -0.278961181640625 +1404 -0.228546142578125 +1405 -0.268890380859375 +1406 -0.219970703125 +1407 -0.2587890625 +1408 -0.211334228515625 +1409 -0.2486572265625 +1410 -0.202728271484375 +1411 -0.238525390625 +1412 -0.194061279296875 +1413 -0.22833251953125 +1414 -0.18536376953125 +1415 -0.218109130859375 +1416 -0.17669677734375 +1417 -0.2078857421875 +1418 -0.16796875 +1419 -0.1976318359375 +1420 -0.15924072265625 +1421 -0.187347412109375 +1422 -0.150482177734375 +1423 -0.17706298828125 +1424 -0.1417236328125 +1425 -0.166748046875 +1426 -0.1329345703125 +1427 -0.156402587890625 +1428 -0.1241455078125 +1429 -0.14605712890625 +1430 -0.115325927734375 +1431 -0.13568115234375 +1432 -0.10650634765625 +1433 -0.12530517578125 +1434 -0.097686767578125 +1435 -0.11492919921875 +1436 -0.088836669921875 +1437 -0.104522705078125 +1438 -0.0799560546875 +1439 -0.094085693359375 +1440 -0.071075439453125 +1441 -0.083648681640625 +1442 -0.062225341796875 +1443 -0.073211669921875 +1444 -0.0533447265625 +1445 -0.062774658203125 +1446 -0.04443359375 +1447 -0.05230712890625 +1448 -0.03558349609375 +1449 -0.0418701171875 +1450 -0.02667236328125 +1451 -0.031402587890625 +1452 -0.017791748046875 +1453 -0.02093505859375 +1454 -0.008880615234375 +1455 -0.010467529296875 +1456 0.0 +1457 0.0 +1458 0.0087890625 +1459 0.010467529296875 +1460 0.017578125 +1461 0.02093505859375 +1462 0.0263671875 +1463 0.031402587890625 +1464 0.03515625 +1465 0.0418701171875 +1466 0.043914794921875 +1467 0.05230712890625 +1468 0.052703857421875 +1469 0.062774658203125 +1470 0.061492919921875 +1471 0.073211669921875 +1472 0.07025146484375 +1473 0.083648681640625 +1474 0.079010009765625 +1475 0.094085693359375 +1476 0.0877685546875 +1477 0.104522705078125 +1478 0.096527099609375 +1479 0.11492919921875 +1480 0.105255126953125 +1481 0.12530517578125 +1482 0.11395263671875 +1483 0.13568115234375 +1484 0.1226806640625 +1485 0.14605712890625 +1486 0.13134765625 +1487 0.156402587890625 +1488 0.140045166015625 +1489 0.166748046875 +1490 0.148712158203125 +1491 0.17706298828125 +1492 0.1573486328125 +1493 0.187347412109375 +1494 0.165985107421875 +1495 0.1976318359375 +1496 0.17462158203125 +1497 0.2078857421875 +1498 0.183197021484375 +1499 0.218109130859375 +1500 0.1917724609375 +1501 0.22833251953125 +1502 0.200347900390625 +1503 0.238525390625 +1504 0.2088623046875 +1505 0.2486572265625 +1506 0.217376708984375 +1507 0.2587890625 +1508 0.225860595703125 +1509 0.268890380859375 +1510 0.23431396484375 +1511 0.278961181640625 +1512 0.24273681640625 +1513 0.28900146484375 +1514 0.25115966796875 +1515 0.29901123046875 +1516 0.259521484375 +1517 0.308990478515625 +1518 0.26788330078125 +1519 0.318939208984375 +1520 0.27618408203125 +1521 0.328826904296875 +1522 0.284515380859375 +1523 0.338714599609375 +1524 0.292755126953125 +1525 0.348541259765625 +1526 0.300994873046875 +1527 0.35833740234375 +1528 0.309173583984375 +1529 0.36810302734375 +1530 0.317352294921875 +1531 0.3778076171875 +1532 0.325469970703125 +1533 0.387481689453125 +1534 0.33355712890625 +1535 0.397125244140625 +1536 0.32861328125 +1537 0.406707763671875 +1538 0.336334228515625 +1539 0.416259765625 +1540 0.343994140625 +1541 0.425750732421875 +1542 0.351654052734375 +1543 0.435211181640625 +1544 0.359222412109375 +1545 0.444610595703125 +1546 0.366790771484375 +1547 0.453948974609375 +1548 0.374298095703125 +1549 0.4632568359375 +1550 0.381805419921875 +1551 0.4725341796875 +1552 0.38922119140625 +1553 0.481719970703125 +1554 0.3966064453125 +1555 0.490875244140625 +1556 0.403961181640625 +1557 0.499969482421875 +1558 0.4112548828125 +1559 0.509002685546875 +1560 0.418548583984375 +1561 0.51800537109375 +1562 0.425750732421875 +1563 0.52691650390625 +1564 0.43292236328125 +1565 0.535797119140625 +1566 0.440032958984375 +1567 0.54461669921875 +1568 0.44708251953125 +1569 0.5533447265625 +1570 0.454132080078125 +1571 0.562042236328125 +1572 0.461090087890625 +1573 0.5706787109375 +1574 0.468017578125 +1575 0.579254150390625 +1576 0.474884033203125 +1577 0.587738037109375 +1578 0.481719970703125 +1579 0.59619140625 +1580 0.48846435546875 +1581 0.60455322265625 +1582 0.495208740234375 +1583 0.612884521484375 +1584 0.501861572265625 +1585 0.621124267578125 +1586 0.508453369140625 +1587 0.6292724609375 +1588 0.5150146484375 +1589 0.63739013671875 +1590 0.521484375 +1591 0.645416259765625 +1592 0.527923583984375 +1593 0.65338134765625 +1594 0.5343017578125 +1595 0.661285400390625 +1596 0.540618896484375 +1597 0.669097900390625 +1598 0.546875 +1599 0.676849365234375 +1600 0.553070068359375 +1601 0.68450927734375 +1602 0.5592041015625 +1603 0.692108154296875 +1604 0.565277099609375 +1605 0.699615478515625 +1606 0.5712890625 +1607 0.707061767578125 +1608 0.5772705078125 +1609 0.714447021484375 +1610 0.5831298828125 +1611 0.721710205078125 +1612 0.5889892578125 +1613 0.72894287109375 +1614 0.5947265625 +1615 0.736053466796875 +1616 0.60040283203125 +1617 0.74310302734375 +1618 0.606048583984375 +1619 0.75006103515625 +1620 0.611602783203125 +1621 0.7569580078125 +1622 0.61712646484375 +1623 0.763763427734375 +1624 0.622528076171875 +1625 0.770477294921875 +1626 0.627899169921875 +1627 0.777099609375 +1628 0.6331787109375 +1629 0.783660888671875 +1630 0.638427734375 +1631 0.790130615234375 +1632 0.6435546875 +1633 0.796478271484375 +1634 0.64862060546875 +1635 0.802764892578125 +1636 0.653656005859375 +1637 0.808990478515625 +1638 0.658599853515625 +1639 0.815093994140625 +1640 0.6634521484375 +1641 0.82110595703125 +1642 0.668243408203125 +1643 0.8270263671875 +1644 0.6729736328125 +1645 0.8328857421875 +1646 0.6776123046875 +1647 0.838623046875 +1648 0.68218994140625 +1649 0.84429931640625 +1650 0.686676025390625 +1651 0.849853515625 +1652 0.69110107421875 +1653 0.855316162109375 +1654 0.6954345703125 +1655 0.860687255859375 +1656 0.69970703125 +1657 0.865997314453125 +1658 0.70391845703125 +1659 0.871185302734375 +1660 0.7080078125 +1661 0.876251220703125 +1662 0.7120361328125 +1663 0.881256103515625 +1664 0.71600341796875 +1665 0.88616943359375 +1666 0.719879150390625 +1667 0.890960693359375 +1668 0.72369384765625 +1669 0.895660400390625 +1670 0.7274169921875 +1671 0.9002685546875 +1672 0.731048583984375 +1673 0.90478515625 +1674 0.734619140625 +1675 0.9091796875 +1676 0.73809814453125 +1677 0.91351318359375 +1678 0.74151611328125 +1679 0.917724609375 +1680 0.74481201171875 +1681 0.92181396484375 +1682 0.748077392578125 +1683 0.92584228515625 +1684 0.751190185546875 +1685 0.929718017578125 +1686 0.7542724609375 +1687 0.93353271484375 +1688 0.75726318359375 +1689 0.937225341796875 +1690 0.76019287109375 +1691 0.940826416015625 +1692 0.763031005859375 +1693 0.9443359375 +1694 0.7657470703125 +1695 0.947723388671875 +1696 0.768402099609375 +1697 0.951019287109375 +1698 0.770965576171875 +1699 0.954193115234375 +1700 0.773468017578125 +1701 0.957275390625 +1702 0.775848388671875 +1703 0.960235595703125 +1704 0.778167724609375 +1705 0.963104248046875 +1706 0.780426025390625 +1707 0.96588134765625 +1708 0.782562255859375 +1709 0.968536376953125 +1710 0.784637451171875 +1711 0.971099853515625 +1712 0.78662109375 +1713 0.973541259765625 +1714 0.788482666015625 +1715 0.975860595703125 +1716 0.790283203125 +1717 0.97808837890625 +1718 0.792022705078125 +1719 0.980224609375 +1720 0.79364013671875 +1721 0.98223876953125 +1722 0.795196533203125 +1723 0.984161376953125 +1724 0.796661376953125 +1725 0.9859619140625 +1726 0.798004150390625 +1727 0.987640380859375 +1728 0.799285888671875 +1729 0.989227294921875 +1730 0.80047607421875 +1731 0.990692138671875 +1732 0.80157470703125 +1733 0.9920654296875 +1734 0.802581787109375 +1735 0.993316650390625 +1736 0.80352783203125 +1737 0.994476318359375 +1738 0.80438232421875 +1739 0.995513916015625 +1740 0.805145263671875 +1741 0.9964599609375 +1742 0.8057861328125 +1743 0.997283935546875 +1744 0.806365966796875 +1745 0.99798583984375 +1746 0.806854248046875 +1747 0.99859619140625 +1748 0.8072509765625 +1749 0.999114990234375 +1750 0.80755615234375 +1751 0.999481201171875 +1752 0.807769775390625 +1753 0.999755859375 +1754 0.80792236328125 +1755 0.99993896484375 +1756 0.8079833984375 +1757 0.999969482421875 +1758 0.80792236328125 +1759 0.99993896484375 +1760 0.807769775390625 +1761 0.999755859375 +1762 0.80755615234375 +1763 0.999481201171875 +1764 0.8072509765625 +1765 0.999114990234375 +1766 0.806854248046875 +1767 0.99859619140625 +1768 0.806365966796875 +1769 0.99798583984375 +1770 0.8057861328125 +1771 0.997283935546875 +1772 0.805145263671875 +1773 0.9964599609375 +1774 0.80438232421875 +1775 0.995513916015625 +1776 0.80352783203125 +1777 0.994476318359375 +1778 0.802581787109375 +1779 0.993316650390625 +1780 0.80157470703125 +1781 0.9920654296875 +1782 0.80047607421875 +1783 0.990692138671875 +1784 0.799285888671875 +1785 0.989227294921875 +1786 0.798004150390625 +1787 0.987640380859375 +1788 0.796661376953125 +1789 0.9859619140625 +1790 0.795196533203125 +1791 0.984161376953125 +1792 0.76220703125 +1793 0.98223876953125 +1794 0.7606201171875 +1795 0.980224609375 +1796 0.75897216796875 +1797 0.97808837890625 +1798 0.757232666015625 +1799 0.975860595703125 +1800 0.75543212890625 +1801 0.973541259765625 +1802 0.7535400390625 +1803 0.971099853515625 +1804 0.751556396484375 +1805 0.968536376953125 +1806 0.74951171875 +1807 0.96588134765625 +1808 0.747344970703125 +1809 0.963104248046875 +1810 0.7451171875 +1811 0.960235595703125 +1812 0.742828369140625 +1813 0.957275390625 +1814 0.740447998046875 +1815 0.954193115234375 +1816 0.73797607421875 +1817 0.951019287109375 +1818 0.73541259765625 +1819 0.947723388671875 +1820 0.7327880859375 +1821 0.9443359375 +1822 0.730072021484375 +1823 0.940826416015625 +1824 0.727264404296875 +1825 0.937225341796875 +1826 0.724395751953125 +1827 0.93353271484375 +1828 0.721435546875 +1829 0.929718017578125 +1830 0.71844482421875 +1831 0.92584228515625 +1832 0.715301513671875 +1833 0.92181396484375 +1834 0.712127685546875 +1835 0.917724609375 +1836 0.7088623046875 +1837 0.91351318359375 +1838 0.70550537109375 +1839 0.9091796875 +1840 0.70208740234375 +1841 0.90478515625 +1842 0.698577880859375 +1843 0.9002685546875 +1844 0.69500732421875 +1845 0.895660400390625 +1846 0.691375732421875 +1847 0.890960693359375 +1848 0.687652587890625 +1849 0.88616943359375 +1850 0.683837890625 +1851 0.881256103515625 +1852 0.679962158203125 +1853 0.876251220703125 +1854 0.676025390625 +1855 0.871185302734375 +1856 0.6719970703125 +1857 0.865997314453125 +1858 0.667877197265625 +1859 0.860687255859375 +1860 0.6636962890625 +1861 0.855316162109375 +1862 0.659454345703125 +1863 0.849853515625 +1864 0.6551513671875 +1865 0.84429931640625 +1866 0.6507568359375 +1867 0.838623046875 +1868 0.64630126953125 +1869 0.8328857421875 +1870 0.641754150390625 +1871 0.8270263671875 +1872 0.63714599609375 +1873 0.82110595703125 +1874 0.63250732421875 +1875 0.815093994140625 +1876 0.62774658203125 +1877 0.808990478515625 +1878 0.6229248046875 +1879 0.802764892578125 +1880 0.6180419921875 +1881 0.796478271484375 +1882 0.613128662109375 +1883 0.790130615234375 +1884 0.60809326171875 +1885 0.783660888671875 +1886 0.602996826171875 +1887 0.777099609375 +1888 0.597869873046875 +1889 0.770477294921875 +1890 0.5926513671875 +1891 0.763763427734375 +1892 0.587371826171875 +1893 0.7569580078125 +1894 0.58203125 +1895 0.75006103515625 +1896 0.576629638671875 +1897 0.74310302734375 +1898 0.5711669921875 +1899 0.736053466796875 +1900 0.565643310546875 +1901 0.72894287109375 +1902 0.560028076171875 +1903 0.721710205078125 +1904 0.55438232421875 +1905 0.714447021484375 +1906 0.548675537109375 +1907 0.707061767578125 +1908 0.542877197265625 +1909 0.699615478515625 +1910 0.53704833984375 +1911 0.692108154296875 +1912 0.531158447265625 +1913 0.68450927734375 +1914 0.52520751953125 +1915 0.676849365234375 +1916 0.519195556640625 +1917 0.669097900390625 +1918 0.513153076171875 +1919 0.661285400390625 +1920 0.50701904296875 +1921 0.65338134765625 +1922 0.500823974609375 +1923 0.645416259765625 +1924 0.494598388671875 +1925 0.63739013671875 +1926 0.48828125 +1927 0.6292724609375 +1928 0.481964111328125 +1929 0.621124267578125 +1930 0.4755859375 +1931 0.612884521484375 +1932 0.4691162109375 +1933 0.60455322265625 +1934 0.462615966796875 +1935 0.59619140625 +1936 0.4560546875 +1937 0.587738037109375 +1938 0.449493408203125 +1939 0.579254150390625 +1940 0.442840576171875 +1941 0.5706787109375 +1942 0.436126708984375 +1943 0.562042236328125 +1944 0.42938232421875 +1945 0.5533447265625 +1946 0.422607421875 +1947 0.54461669921875 +1948 0.415771484375 +1949 0.535797119140625 +1950 0.40887451171875 +1951 0.52691650390625 +1952 0.401947021484375 +1953 0.51800537109375 +1954 0.39495849609375 +1955 0.509002685546875 +1956 0.387969970703125 +1957 0.499969482421875 +1958 0.380889892578125 +1959 0.490875244140625 +1960 0.373809814453125 +1961 0.481719970703125 +1962 0.366668701171875 +1963 0.4725341796875 +1964 0.359466552734375 +1965 0.4632568359375 +1966 0.35223388671875 +1967 0.453948974609375 +1968 0.345001220703125 +1969 0.444610595703125 +1970 0.33770751953125 +1971 0.435211181640625 +1972 0.330352783203125 +1973 0.425750732421875 +1974 0.322998046875 +1975 0.416259765625 +1976 0.315582275390625 +1977 0.406707763671875 +1978 0.30816650390625 +1979 0.397125244140625 +1980 0.3006591796875 +1981 0.387481689453125 +1982 0.29315185546875 +1983 0.3778076171875 +1984 0.28564453125 +1985 0.36810302734375 +1986 0.278045654296875 +1987 0.35833740234375 +1988 0.27044677734375 +1989 0.348541259765625 +1990 0.2628173828125 +1991 0.338714599609375 +1992 0.255157470703125 +1993 0.328826904296875 +1994 0.247467041015625 +1995 0.318939208984375 +1996 0.23974609375 +1997 0.308990478515625 +1998 0.232025146484375 +1999 0.29901123046875 +2000 0.2242431640625 +2001 0.28900146484375 +2002 0.216461181640625 +2003 0.278961181640625 +2004 0.208648681640625 +2005 0.268890380859375 +2006 0.2008056640625 +2007 0.2587890625 +2008 0.19293212890625 +2009 0.2486572265625 +2010 0.185089111328125 +2011 0.238525390625 +2012 0.177154541015625 +2013 0.22833251953125 +2014 0.16925048828125 +2015 0.218109130859375 +2016 0.16131591796875 +2017 0.2078857421875 +2018 0.153350830078125 +2019 0.1976318359375 +2020 0.145355224609375 +2021 0.187347412109375 +2022 0.13739013671875 +2023 0.17706298828125 +2024 0.12939453125 +2025 0.166748046875 +2026 0.121337890625 +2027 0.156402587890625 +2028 0.113311767578125 +2029 0.14605712890625 +2030 0.10528564453125 +2031 0.13568115234375 +2032 0.09722900390625 +2033 0.12530517578125 +2034 0.08917236328125 +2035 0.11492919921875 +2036 0.081085205078125 +2037 0.104522705078125 +2038 0.072998046875 +2039 0.094085693359375 +2040 0.064910888671875 +2041 0.083648681640625 +2042 0.056793212890625 +2043 0.073211669921875 +2044 0.0487060546875 +2045 0.062774658203125 +2046 0.04058837890625 +2047 0.05230712890625 +2048 0.0311279296875 +2049 0.0418701171875 +2050 0.023345947265625 +2051 0.031402587890625 +2052 0.01556396484375 +2053 0.02093505859375 +2054 0.007781982421875 +2055 0.010467529296875 +2056 0.0 +2057 0.0 +2058 -0.007781982421875 +2059 -0.010467529296875 +2060 -0.01556396484375 +2061 -0.02093505859375 +2062 -0.023345947265625 +2063 -0.031402587890625 +2064 -0.0311279296875 +2065 -0.0418701171875 +2066 -0.038909912109375 +2067 -0.05230712890625 +2068 -0.04669189453125 +2069 -0.062774658203125 +2070 -0.054443359375 +2071 -0.073211669921875 +2072 -0.062225341796875 +2073 -0.083648681640625 +2074 -0.069976806640625 +2075 -0.094085693359375 +2076 -0.0777587890625 +2077 -0.104522705078125 +2078 -0.085479736328125 +2079 -0.11492919921875 +2080 -0.09320068359375 +2081 -0.12530517578125 +2082 -0.100921630859375 +2083 -0.13568115234375 +2084 -0.108642578125 +2085 -0.14605712890625 +2086 -0.116363525390625 +2087 -0.156402587890625 +2088 -0.124053955078125 +2089 -0.166748046875 +2090 -0.1317138671875 +2091 -0.17706298828125 +2092 -0.139373779296875 +2093 -0.187347412109375 +2094 -0.14703369140625 +2095 -0.1976318359375 +2096 -0.1546630859375 +2097 -0.2078857421875 +2098 -0.162261962890625 +2099 -0.218109130859375 +2100 -0.16986083984375 +2101 -0.22833251953125 +2102 -0.177459716796875 +2103 -0.238525390625 +2104 -0.18499755859375 +2105 -0.2486572265625 +2106 -0.192535400390625 +2107 -0.2587890625 +2108 -0.200042724609375 +2109 -0.268890380859375 +2110 -0.207550048828125 +2111 -0.278961181640625 +2112 -0.214996337890625 +2113 -0.28900146484375 +2114 -0.222442626953125 +2115 -0.29901123046875 +2116 -0.229888916015625 +2117 -0.308990478515625 +2118 -0.237274169921875 +2119 -0.318939208984375 +2120 -0.24462890625 +2121 -0.328826904296875 +2122 -0.251983642578125 +2123 -0.338714599609375 +2124 -0.259307861328125 +2125 -0.348541259765625 +2126 -0.2666015625 +2127 -0.35833740234375 +2128 -0.27386474609375 +2129 -0.36810302734375 +2130 -0.28106689453125 +2131 -0.3778076171875 +2132 -0.28826904296875 +2133 -0.387481689453125 +2134 -0.295440673828125 +2135 -0.397125244140625 +2136 -0.302581787109375 +2137 -0.406707763671875 +2138 -0.3096923828125 +2139 -0.416259765625 +2140 -0.316741943359375 +2141 -0.425750732421875 +2142 -0.32379150390625 +2143 -0.435211181640625 +2144 -0.330780029296875 +2145 -0.444610595703125 +2146 -0.337738037109375 +2147 -0.453948974609375 +2148 -0.34466552734375 +2149 -0.4632568359375 +2150 -0.3515625 +2151 -0.4725341796875 +2152 -0.3583984375 +2153 -0.481719970703125 +2154 -0.365203857421875 +2155 -0.490875244140625 +2156 -0.371978759765625 +2157 -0.499969482421875 +2158 -0.378692626953125 +2159 -0.509002685546875 +2160 -0.3853759765625 +2161 -0.51800537109375 +2162 -0.39202880859375 +2163 -0.52691650390625 +2164 -0.39862060546875 +2165 -0.535797119140625 +2166 -0.405181884765625 +2167 -0.54461669921875 +2168 -0.41168212890625 +2169 -0.5533447265625 +2170 -0.41815185546875 +2171 -0.562042236328125 +2172 -0.424591064453125 +2173 -0.5706787109375 +2174 -0.43096923828125 +2175 -0.579254150390625 +2176 -0.437255859375 +2177 -0.587738037109375 +2178 -0.44354248046875 +2179 -0.59619140625 +2180 -0.44976806640625 +2181 -0.60455322265625 +2182 -0.455963134765625 +2183 -0.612884521484375 +2184 -0.46209716796875 +2185 -0.621124267578125 +2186 -0.468170166015625 +2187 -0.6292724609375 +2188 -0.474212646484375 +2189 -0.63739013671875 +2190 -0.480194091796875 +2191 -0.645416259765625 +2192 -0.486114501953125 +2193 -0.65338134765625 +2194 -0.491973876953125 +2195 -0.661285400390625 +2196 -0.497802734375 +2197 -0.669097900390625 +2198 -0.503570556640625 +2199 -0.676849365234375 +2200 -0.50927734375 +2201 -0.68450927734375 +2202 -0.514923095703125 +2203 -0.692108154296875 +2204 -0.5205078125 +2205 -0.699615478515625 +2206 -0.526031494140625 +2207 -0.707061767578125 +2208 -0.53155517578125 +2209 -0.714447021484375 +2210 -0.536956787109375 +2211 -0.721710205078125 +2212 -0.542327880859375 +2213 -0.72894287109375 +2214 -0.547607421875 +2215 -0.736053466796875 +2216 -0.5528564453125 +2217 -0.74310302734375 +2218 -0.55804443359375 +2219 -0.75006103515625 +2220 -0.56317138671875 +2221 -0.7569580078125 +2222 -0.5682373046875 +2223 -0.763763427734375 +2224 -0.5732421875 +2225 -0.770477294921875 +2226 -0.578155517578125 +2227 -0.777099609375 +2228 -0.583038330078125 +2229 -0.783660888671875 +2230 -0.587860107421875 +2231 -0.790130615234375 +2232 -0.592559814453125 +2233 -0.796478271484375 +2234 -0.597259521484375 +2235 -0.802764892578125 +2236 -0.60186767578125 +2237 -0.808990478515625 +2238 -0.606414794921875 +2239 -0.815093994140625 +2240 -0.61090087890625 +2241 -0.82110595703125 +2242 -0.61529541015625 +2243 -0.8270263671875 +2244 -0.619659423828125 +2245 -0.8328857421875 +2246 -0.623931884765625 +2247 -0.838623046875 +2248 -0.628143310546875 +2249 -0.84429931640625 +2250 -0.632293701171875 +2251 -0.849853515625 +2252 -0.6363525390625 +2253 -0.855316162109375 +2254 -0.640350341796875 +2255 -0.860687255859375 +2256 -0.644287109375 +2257 -0.865997314453125 +2258 -0.648162841796875 +2259 -0.871185302734375 +2260 -0.65191650390625 +2261 -0.876251220703125 +2262 -0.6556396484375 +2263 -0.881256103515625 +2264 -0.6593017578125 +2265 -0.88616943359375 +2266 -0.662872314453125 +2267 -0.890960693359375 +2268 -0.666351318359375 +2269 -0.895660400390625 +2270 -0.6697998046875 +2271 -0.9002685546875 +2272 -0.67315673828125 +2273 -0.90478515625 +2274 -0.676422119140625 +2275 -0.9091796875 +2276 -0.679656982421875 +2277 -0.91351318359375 +2278 -0.682769775390625 +2279 -0.917724609375 +2280 -0.685821533203125 +2281 -0.92181396484375 +2282 -0.688812255859375 +2283 -0.92584228515625 +2284 -0.69171142578125 +2285 -0.929718017578125 +2286 -0.694549560546875 +2287 -0.93353271484375 +2288 -0.697296142578125 +2289 -0.937225341796875 +2290 -0.699981689453125 +2291 -0.940826416015625 +2292 -0.70257568359375 +2293 -0.9443359375 +2294 -0.705108642578125 +2295 -0.947723388671875 +2296 -0.707550048828125 +2297 -0.951019287109375 +2298 -0.70989990234375 +2299 -0.954193115234375 +2300 -0.71221923828125 +2301 -0.957275390625 +2302 -0.71441650390625 +2303 -0.960235595703125 +2304 -0.685699462890625 +2305 -0.963104248046875 +2306 -0.68768310546875 +2307 -0.96588134765625 +2308 -0.6895751953125 +2309 -0.968536376953125 +2310 -0.69140625 +2311 -0.971099853515625 +2312 -0.693145751953125 +2313 -0.973541259765625 +2314 -0.694793701171875 +2315 -0.975860595703125 +2316 -0.696380615234375 +2317 -0.97808837890625 +2318 -0.697906494140625 +2319 -0.980224609375 +2320 -0.6993408203125 +2321 -0.98223876953125 +2322 -0.700714111328125 +2323 -0.984161376953125 +2324 -0.701995849609375 +2325 -0.9859619140625 +2326 -0.70318603515625 +2327 -0.987640380859375 +2328 -0.704315185546875 +2329 -0.989227294921875 +2330 -0.705352783203125 +2331 -0.990692138671875 +2332 -0.706329345703125 +2333 -0.9920654296875 +2334 -0.70721435546875 +2335 -0.993316650390625 +2336 -0.708038330078125 +2337 -0.994476318359375 +2338 -0.70880126953125 +2339 -0.995513916015625 +2340 -0.70947265625 +2341 -0.9964599609375 +2342 -0.710052490234375 +2343 -0.997283935546875 +2344 -0.710540771484375 +2345 -0.99798583984375 +2346 -0.710968017578125 +2347 -0.99859619140625 +2348 -0.711334228515625 +2349 -0.999114990234375 +2350 -0.711578369140625 +2351 -0.999481201171875 +2352 -0.7117919921875 +2353 -0.999755859375 +2354 -0.7119140625 +2355 -0.99993896484375 +2356 -0.71197509765625 +2357 -1.0 +2358 -0.7119140625 +2359 -0.99993896484375 +2360 -0.7117919921875 +2361 -0.999755859375 +2362 -0.711578369140625 +2363 -0.999481201171875 +2364 -0.711334228515625 +2365 -0.999114990234375 +2366 -0.710968017578125 +2367 -0.99859619140625 +2368 -0.710540771484375 +2369 -0.99798583984375 +2370 -0.710052490234375 +2371 -0.997283935546875 +2372 -0.70947265625 +2373 -0.9964599609375 +2374 -0.70880126953125 +2375 -0.995513916015625 +2376 -0.708038330078125 +2377 -0.994476318359375 +2378 -0.70721435546875 +2379 -0.993316650390625 +2380 -0.706329345703125 +2381 -0.9920654296875 +2382 -0.705352783203125 +2383 -0.990692138671875 +2384 -0.704315185546875 +2385 -0.989227294921875 +2386 -0.70318603515625 +2387 -0.987640380859375 +2388 -0.701995849609375 +2389 -0.9859619140625 +2390 -0.700714111328125 +2391 -0.984161376953125 +2392 -0.6993408203125 +2393 -0.98223876953125 +2394 -0.697906494140625 +2395 -0.980224609375 +2396 -0.696380615234375 +2397 -0.97808837890625 +2398 -0.694793701171875 +2399 -0.975860595703125 +2400 -0.693145751953125 +2401 -0.973541259765625 +2402 -0.69140625 +2403 -0.971099853515625 +2404 -0.6895751953125 +2405 -0.968536376953125 +2406 -0.68768310546875 +2407 -0.96588134765625 +2408 -0.685699462890625 +2409 -0.963104248046875 +2410 -0.68365478515625 +2411 -0.960235595703125 +2412 -0.681549072265625 +2413 -0.957275390625 +2414 -0.67938232421875 +2415 -0.954193115234375 +2416 -0.677093505859375 +2417 -0.951019287109375 +2418 -0.674774169921875 +2419 -0.947723388671875 +2420 -0.67236328125 +2421 -0.9443359375 +2422 -0.66986083984375 +2423 -0.940826416015625 +2424 -0.66729736328125 +2425 -0.937225341796875 +2426 -0.664642333984375 +2427 -0.93353271484375 +2428 -0.66192626953125 +2429 -0.929718017578125 +2430 -0.6591796875 +2431 -0.92584228515625 +2432 -0.65631103515625 +2433 -0.92181396484375 +2434 -0.653411865234375 +2435 -0.917724609375 +2436 -0.650390625 +2437 -0.91351318359375 +2438 -0.647308349609375 +2439 -0.9091796875 +2440 -0.644195556640625 +2441 -0.90478515625 +2442 -0.640960693359375 +2443 -0.9002685546875 +2444 -0.6376953125 +2445 -0.895660400390625 +2446 -0.63433837890625 +2447 -0.890960693359375 +2448 -0.63092041015625 +2449 -0.88616943359375 +2450 -0.62744140625 +2451 -0.881256103515625 +2452 -0.623870849609375 +2453 -0.876251220703125 +2454 -0.620269775390625 +2455 -0.871185302734375 +2456 -0.6165771484375 +2457 -0.865997314453125 +2458 -0.61279296875 +2459 -0.860687255859375 +2460 -0.608978271484375 +2461 -0.855316162109375 +2462 -0.605072021484375 +2463 -0.849853515625 +2464 -0.60113525390625 +2465 -0.84429931640625 +2466 -0.597076416015625 +2467 -0.838623046875 +2468 -0.592987060546875 +2469 -0.8328857421875 +2470 -0.588836669921875 +2471 -0.8270263671875 +2472 -0.5845947265625 +2473 -0.82110595703125 +2474 -0.580322265625 +2475 -0.815093994140625 +2476 -0.57598876953125 +2477 -0.808990478515625 +2478 -0.571563720703125 +2479 -0.802764892578125 +2480 -0.56707763671875 +2481 -0.796478271484375 +2482 -0.56256103515625 +2483 -0.790130615234375 +2484 -0.557952880859375 +2485 -0.783660888671875 +2486 -0.55328369140625 +2487 -0.777099609375 +2488 -0.548553466796875 +2489 -0.770477294921875 +2490 -0.543792724609375 +2491 -0.763763427734375 +2492 -0.5389404296875 +2493 -0.7569580078125 +2494 -0.534027099609375 +2495 -0.75006103515625 +2496 -0.529083251953125 +2497 -0.74310302734375 +2498 -0.5240478515625 +2499 -0.736053466796875 +2500 -0.51898193359375 +2501 -0.72894287109375 +2502 -0.51385498046875 +2503 -0.721710205078125 +2504 -0.5086669921875 +2505 -0.714447021484375 +2506 -0.50341796875 +2507 -0.707061767578125 +2508 -0.49810791015625 +2509 -0.699615478515625 +2510 -0.492767333984375 +2511 -0.692108154296875 +2512 -0.48736572265625 +2513 -0.68450927734375 +2514 -0.481903076171875 +2515 -0.676849365234375 +2516 -0.47637939453125 +2517 -0.669097900390625 +2518 -0.4708251953125 +2519 -0.661285400390625 +2520 -0.465179443359375 +2521 -0.65338134765625 +2522 -0.45953369140625 +2523 -0.645416259765625 +2524 -0.45379638671875 +2525 -0.63739013671875 +2526 -0.448028564453125 +2527 -0.6292724609375 +2528 -0.442230224609375 +2529 -0.621124267578125 +2530 -0.436370849609375 +2531 -0.612884521484375 +2532 -0.430419921875 +2533 -0.60455322265625 +2534 -0.424468994140625 +2535 -0.59619140625 +2536 -0.41845703125 +2537 -0.587738037109375 +2538 -0.41241455078125 +2539 -0.579254150390625 +2540 -0.40631103515625 +2541 -0.5706787109375 +2542 -0.400146484375 +2543 -0.562042236328125 +2544 -0.393951416015625 +2545 -0.5533447265625 +2546 -0.38775634765625 +2547 -0.54461669921875 +2548 -0.3814697265625 +2549 -0.535797119140625 +2550 -0.375152587890625 +2551 -0.52691650390625 +2552 -0.368804931640625 +2553 -0.51800537109375 +2554 -0.362396240234375 +2555 -0.509002685546875 +2556 -0.35595703125 +2557 -0.499969482421875 +2558 -0.3494873046875 +2559 -0.490875244140625 +2560 -0.337188720703125 +2561 -0.481719970703125 +2562 -0.33074951171875 +2563 -0.4725341796875 +2564 -0.32427978515625 +2565 -0.4632568359375 +2566 -0.3177490234375 +2567 -0.453948974609375 +2568 -0.31121826171875 +2569 -0.444610595703125 +2570 -0.30462646484375 +2571 -0.435211181640625 +2572 -0.298004150390625 +2573 -0.425750732421875 +2574 -0.2913818359375 +2575 -0.416259765625 +2576 -0.28466796875 +2577 -0.406707763671875 +2578 -0.277984619140625 +2579 -0.397125244140625 +2580 -0.271209716796875 +2581 -0.387481689453125 +2582 -0.26446533203125 +2583 -0.3778076171875 +2584 -0.257659912109375 +2585 -0.36810302734375 +2586 -0.250823974609375 +2587 -0.35833740234375 +2588 -0.24395751953125 +2589 -0.348541259765625 +2590 -0.237091064453125 +2591 -0.338714599609375 +2592 -0.23016357421875 +2593 -0.328826904296875 +2594 -0.223236083984375 +2595 -0.318939208984375 +2596 -0.216278076171875 +2597 -0.308990478515625 +2598 -0.20928955078125 +2599 -0.29901123046875 +2600 -0.202301025390625 +2601 -0.28900146484375 +2602 -0.19525146484375 +2603 -0.278961181640625 +2604 -0.188201904296875 +2605 -0.268890380859375 +2606 -0.18115234375 +2607 -0.2587890625 +2608 -0.174041748046875 +2609 -0.2486572265625 +2610 -0.166961669921875 +2611 -0.238525390625 +2612 -0.159820556640625 +2613 -0.22833251953125 +2614 -0.15264892578125 +2615 -0.218109130859375 +2616 -0.1455078125 +2617 -0.2078857421875 +2618 -0.138336181640625 +2619 -0.1976318359375 +2620 -0.131134033203125 +2621 -0.187347412109375 +2622 -0.123931884765625 +2623 -0.17706298828125 +2624 -0.11669921875 +2625 -0.166748046875 +2626 -0.109466552734375 +2627 -0.156402587890625 +2628 -0.10223388671875 +2629 -0.14605712890625 +2630 -0.094970703125 +2631 -0.13568115234375 +2632 -0.08770751953125 +2633 -0.12530517578125 +2634 -0.0804443359375 +2635 -0.11492919921875 +2636 -0.073150634765625 +2637 -0.104522705078125 +2638 -0.06585693359375 +2639 -0.094085693359375 +2640 -0.05853271484375 +2641 -0.083648681640625 +2642 -0.051239013671875 +2643 -0.073211669921875 +2644 -0.043914794921875 +2645 -0.062774658203125 +2646 -0.036590576171875 +2647 -0.05230712890625 +2648 -0.029296875 +2649 -0.0418701171875 +2650 -0.02197265625 +2651 -0.031402587890625 +2652 -0.0146484375 +2653 -0.02093505859375 +2654 -0.00732421875 +2655 -0.010467529296875 +2656 0.0 +2657 0.0 +2658 0.007110595703125 +2659 0.010467529296875 +2660 0.01422119140625 +2661 0.02093505859375 +2662 0.021331787109375 +2663 0.031402587890625 +2664 0.0284423828125 +2665 0.0418701171875 +2666 0.035552978515625 +2667 0.05230712890625 +2668 0.04266357421875 +2669 0.062774658203125 +2670 0.049774169921875 +2671 0.073211669921875 +2672 0.056854248046875 +2673 0.083648681640625 +2674 0.06396484375 +2675 0.094085693359375 +2676 0.071075439453125 +2677 0.104522705078125 +2678 0.078125 +2679 0.11492919921875 +2680 0.085205078125 +2681 0.12530517578125 +2682 0.092254638671875 +2683 0.13568115234375 +2684 0.09930419921875 +2685 0.14605712890625 +2686 0.106353759765625 +2687 0.156402587890625 +2688 0.113372802734375 +2689 0.166748046875 +2690 0.120391845703125 +2691 0.17706298828125 +2692 0.12738037109375 +2693 0.187347412109375 +2694 0.134368896484375 +2695 0.1976318359375 +2696 0.141357421875 +2697 0.2078857421875 +2698 0.1483154296875 +2699 0.218109130859375 +2700 0.155242919921875 +2701 0.22833251953125 +2702 0.16217041015625 +2703 0.238525390625 +2704 0.1690673828125 +2705 0.2486572265625 +2706 0.17596435546875 +2707 0.2587890625 +2708 0.182830810546875 +2709 0.268890380859375 +2710 0.189697265625 +2711 0.278961181640625 +2712 0.196502685546875 +2713 0.28900146484375 +2714 0.20330810546875 +2715 0.29901123046875 +2716 0.210113525390625 +2717 0.308990478515625 +2718 0.21685791015625 +2719 0.318939208984375 +2720 0.223602294921875 +2721 0.328826904296875 +2722 0.230316162109375 +2723 0.338714599609375 +2724 0.23699951171875 +2725 0.348541259765625 +2726 0.24365234375 +2727 0.35833740234375 +2728 0.25030517578125 +2729 0.36810302734375 +2730 0.25689697265625 +2731 0.3778076171875 +2732 0.26348876953125 +2733 0.387481689453125 +2734 0.270050048828125 +2735 0.397125244140625 +2736 0.27655029296875 +2737 0.406707763671875 +2738 0.283050537109375 +2739 0.416259765625 +2740 0.28948974609375 +2741 0.425750732421875 +2742 0.295928955078125 +2743 0.435211181640625 +2744 0.302337646484375 +2745 0.444610595703125 +2746 0.308685302734375 +2747 0.453948974609375 +2748 0.31500244140625 +2749 0.4632568359375 +2750 0.321319580078125 +2751 0.4725341796875 +2752 0.32757568359375 +2753 0.481719970703125 +2754 0.33380126953125 +2755 0.490875244140625 +2756 0.3399658203125 +2757 0.499969482421875 +2758 0.346099853515625 +2759 0.509002685546875 +2760 0.35223388671875 +2761 0.51800537109375 +2762 0.358306884765625 +2763 0.52691650390625 +2764 0.36431884765625 +2765 0.535797119140625 +2766 0.370330810546875 +2767 0.54461669921875 +2768 0.37628173828125 +2769 0.5533447265625 +2770 0.382171630859375 +2771 0.562042236328125 +2772 0.3880615234375 +2773 0.5706787109375 +2774 0.393890380859375 +2775 0.579254150390625 +2776 0.399658203125 +2777 0.587738037109375 +2778 0.4053955078125 +2779 0.59619140625 +2780 0.411102294921875 +2781 0.60455322265625 +2782 0.416748046875 +2783 0.612884521484375 +2784 0.42236328125 +2785 0.621124267578125 +2786 0.427886962890625 +2787 0.6292724609375 +2788 0.43341064453125 +2789 0.63739013671875 +2790 0.438873291015625 +2791 0.645416259765625 +2792 0.444305419921875 +2793 0.65338134765625 +2794 0.449676513671875 +2795 0.661285400390625 +2796 0.454986572265625 +2797 0.669097900390625 +2798 0.46026611328125 +2799 0.676849365234375 +2800 0.4654541015625 +2801 0.68450927734375 +2802 0.47064208984375 +2803 0.692108154296875 +2804 0.475738525390625 +2805 0.699615478515625 +2806 0.480804443359375 +2807 0.707061767578125 +2808 0.485809326171875 +2809 0.714447021484375 +2810 0.490753173828125 +2811 0.721710205078125 +2812 0.49566650390625 +2813 0.72894287109375 +2814 0.500518798828125 +2815 0.736053466796875 +2816 0.48150634765625 +2817 0.74310302734375 +2818 0.48602294921875 +2819 0.75006103515625 +2820 0.490478515625 +2821 0.7569580078125 +2822 0.494903564453125 +2823 0.763763427734375 +2824 0.499267578125 +2825 0.770477294921875 +2826 0.5035400390625 +2827 0.777099609375 +2828 0.507781982421875 +2829 0.783660888671875 +2830 0.511993408203125 +2831 0.790130615234375 +2832 0.51611328125 +2833 0.796478271484375 +2834 0.520172119140625 +2835 0.802764892578125 +2836 0.524200439453125 +2837 0.808990478515625 +2838 0.528167724609375 +2839 0.815093994140625 +2840 0.532073974609375 +2841 0.82110595703125 +2842 0.535888671875 +2843 0.8270263671875 +2844 0.539703369140625 +2845 0.8328857421875 +2846 0.543426513671875 +2847 0.838623046875 +2848 0.547088623046875 +2849 0.84429931640625 +2850 0.550689697265625 +2851 0.849853515625 +2852 0.554229736328125 +2853 0.855316162109375 +2854 0.557708740234375 +2855 0.860687255859375 +2856 0.5611572265625 +2857 0.865997314453125 +2858 0.56451416015625 +2859 0.871185302734375 +2860 0.56781005859375 +2861 0.876251220703125 +2862 0.571044921875 +2863 0.881256103515625 +2864 0.57421875 +2865 0.88616943359375 +2866 0.57733154296875 +2867 0.890960693359375 +2868 0.58038330078125 +2869 0.895660400390625 +2870 0.583343505859375 +2871 0.9002685546875 +2872 0.586273193359375 +2873 0.90478515625 +2874 0.589141845703125 +2875 0.9091796875 +2876 0.591949462890625 +2877 0.91351318359375 +2878 0.59466552734375 +2879 0.917724609375 +2880 0.597320556640625 +2881 0.92181396484375 +2882 0.599945068359375 +2883 0.92584228515625 +2884 0.602447509765625 +2885 0.929718017578125 +2886 0.60491943359375 +2887 0.93353271484375 +2888 0.6072998046875 +2889 0.937225341796875 +2890 0.609649658203125 +2891 0.940826416015625 +2892 0.611907958984375 +2893 0.9443359375 +2894 0.614105224609375 +2895 0.947723388671875 +2896 0.616241455078125 +2897 0.951019287109375 +2898 0.618316650390625 +2899 0.954193115234375 +2900 0.62030029296875 +2901 0.957275390625 +2902 0.622222900390625 +2903 0.960235595703125 +2904 0.62408447265625 +2905 0.963104248046875 +2906 0.625885009765625 +2907 0.96588134765625 +2908 0.627593994140625 +2909 0.968536376953125 +2910 0.629241943359375 +2911 0.971099853515625 +2912 0.630828857421875 +2913 0.973541259765625 +2914 0.632354736328125 +2915 0.975860595703125 +2916 0.6337890625 +2917 0.97808837890625 +2918 0.635162353515625 +2919 0.980224609375 +2920 0.636474609375 +2921 0.98223876953125 +2922 0.637725830078125 +2923 0.984161376953125 +2924 0.638885498046875 +2925 0.9859619140625 +2926 0.639984130859375 +2927 0.987640380859375 +2928 0.6409912109375 +2929 0.989227294921875 +2930 0.6419677734375 +2931 0.990692138671875 +2932 0.642852783203125 +2933 0.9920654296875 +2934 0.643646240234375 +2935 0.993316650390625 +2936 0.6444091796875 +2937 0.994476318359375 +2938 0.64508056640625 +2939 0.995513916015625 +2940 0.64569091796875 +2941 0.9964599609375 +2942 0.646209716796875 +2943 0.997283935546875 +2944 0.64666748046875 +2945 0.99798583984375 +2946 0.647064208984375 +2947 0.99859619140625 +2948 0.64739990234375 +2949 0.999114990234375 +2950 0.647613525390625 +2951 0.999481201171875 +2952 0.647796630859375 +2953 0.999755859375 +2954 0.647918701171875 +2955 0.99993896484375 +2956 0.647979736328125 +2957 0.999969482421875 +2958 0.647918701171875 +2959 0.99993896484375 +2960 0.647796630859375 +2961 0.999755859375 +2962 0.647613525390625 +2963 0.999481201171875 +2964 0.64739990234375 +2965 0.999114990234375 +2966 0.647064208984375 +2967 0.99859619140625 +2968 0.64666748046875 +2969 0.99798583984375 +2970 0.646209716796875 +2971 0.997283935546875 +2972 0.64569091796875 +2973 0.9964599609375 +2974 0.64508056640625 +2975 0.995513916015625 +2976 0.6444091796875 +2977 0.994476318359375 +2978 0.643646240234375 +2979 0.993316650390625 +2980 0.642852783203125 +2981 0.9920654296875 +2982 0.6419677734375 +2983 0.990692138671875 +2984 0.6409912109375 +2985 0.989227294921875 +2986 0.639984130859375 +2987 0.987640380859375 +2988 0.638885498046875 +2989 0.9859619140625 +2990 0.637725830078125 +2991 0.984161376953125 +2992 0.636474609375 +2993 0.98223876953125 +2994 0.635162353515625 +2995 0.980224609375 +2996 0.6337890625 +2997 0.97808837890625 +2998 0.632354736328125 +2999 0.975860595703125 +3000 0.630828857421875 +3001 0.973541259765625 +3002 0.629241943359375 +3003 0.971099853515625 +3004 0.627593994140625 +3005 0.968536376953125 +3006 0.625885009765625 +3007 0.96588134765625 +3008 0.62408447265625 +3009 0.963104248046875 +3010 0.622222900390625 +3011 0.960235595703125 +3012 0.62030029296875 +3013 0.957275390625 +3014 0.618316650390625 +3015 0.954193115234375 +3016 0.616241455078125 +3017 0.951019287109375 +3018 0.614105224609375 +3019 0.947723388671875 +3020 0.611907958984375 +3021 0.9443359375 +3022 0.609649658203125 +3023 0.940826416015625 +3024 0.6072998046875 +3025 0.937225341796875 +3026 0.60491943359375 +3027 0.93353271484375 +3028 0.602447509765625 +3029 0.929718017578125 +3030 0.599945068359375 +3031 0.92584228515625 +3032 0.597320556640625 +3033 0.92181396484375 +3034 0.59466552734375 +3035 0.917724609375 +3036 0.591949462890625 +3037 0.91351318359375 +3038 0.589141845703125 +3039 0.9091796875 +3040 0.586273193359375 +3041 0.90478515625 +3042 0.583343505859375 +3043 0.9002685546875 +3044 0.58038330078125 +3045 0.895660400390625 +3046 0.57733154296875 +3047 0.890960693359375 +3048 0.57421875 +3049 0.88616943359375 +3050 0.571044921875 +3051 0.881256103515625 +3052 0.56781005859375 +3053 0.876251220703125 +3054 0.56451416015625 +3055 0.871185302734375 +3056 0.5611572265625 +3057 0.865997314453125 +3058 0.557708740234375 +3059 0.860687255859375 +3060 0.554229736328125 +3061 0.855316162109375 +3062 0.550689697265625 +3063 0.849853515625 +3064 0.547088623046875 +3065 0.84429931640625 +3066 0.543426513671875 +3067 0.838623046875 +3068 0.539703369140625 +3069 0.8328857421875 +3070 0.535888671875 +3071 0.8270263671875 +3072 0.505767822265625 +3073 0.82110595703125 +3074 0.5020751953125 +3075 0.815093994140625 +3076 0.498321533203125 +3077 0.808990478515625 +3078 0.494476318359375 +3079 0.802764892578125 +3080 0.4906005859375 +3081 0.796478271484375 +3082 0.4866943359375 +3083 0.790130615234375 +3084 0.482696533203125 +3085 0.783660888671875 +3086 0.478668212890625 +3087 0.777099609375 +3088 0.474578857421875 +3089 0.770477294921875 +3090 0.470458984375 +3091 0.763763427734375 +3092 0.46624755859375 +3093 0.7569580078125 +3094 0.462005615234375 +3095 0.75006103515625 +3096 0.457733154296875 +3097 0.74310302734375 +3098 0.453369140625 +3099 0.736053466796875 +3100 0.449005126953125 +3101 0.72894287109375 +3102 0.444549560546875 +3103 0.721710205078125 +3104 0.4400634765625 +3105 0.714447021484375 +3106 0.435516357421875 +3107 0.707061767578125 +3108 0.430938720703125 +3109 0.699615478515625 +3110 0.426300048828125 +3111 0.692108154296875 +3112 0.421630859375 +3113 0.68450927734375 +3114 0.416900634765625 +3115 0.676849365234375 +3116 0.412139892578125 +3117 0.669097900390625 +3118 0.407318115234375 +3119 0.661285400390625 +3120 0.4024658203125 +3121 0.65338134765625 +3122 0.397552490234375 +3123 0.645416259765625 +3124 0.392608642578125 +3125 0.63739013671875 +3126 0.387603759765625 +3127 0.6292724609375 +3128 0.382598876953125 +3129 0.621124267578125 +3130 0.37750244140625 +3131 0.612884521484375 +3132 0.37237548828125 +3133 0.60455322265625 +3134 0.367218017578125 +3135 0.59619140625 +3136 0.362030029296875 +3137 0.587738037109375 +3138 0.3568115234375 +3139 0.579254150390625 +3140 0.35150146484375 +3141 0.5706787109375 +3142 0.34619140625 +3143 0.562042236328125 +3144 0.340850830078125 +3145 0.5533447265625 +3146 0.33544921875 +3147 0.54461669921875 +3148 0.33001708984375 +3149 0.535797119140625 +3150 0.324554443359375 +3151 0.52691650390625 +3152 0.319061279296875 +3153 0.51800537109375 +3154 0.31353759765625 +3155 0.509002685546875 +3156 0.307952880859375 +3157 0.499969482421875 +3158 0.3023681640625 +3159 0.490875244140625 +3160 0.296722412109375 +3161 0.481719970703125 +3162 0.291046142578125 +3163 0.4725341796875 +3164 0.28533935546875 +3165 0.4632568359375 +3166 0.27960205078125 +3167 0.453948974609375 +3168 0.27386474609375 +3169 0.444610595703125 +3170 0.26806640625 +3171 0.435211181640625 +3172 0.262237548828125 +3173 0.425750732421875 +3174 0.25640869140625 +3175 0.416259765625 +3176 0.250518798828125 +3177 0.406707763671875 +3178 0.244598388671875 +3179 0.397125244140625 +3180 0.238677978515625 +3181 0.387481689453125 +3182 0.232696533203125 +3183 0.3778076171875 +3184 0.22674560546875 +3185 0.36810302734375 +3186 0.220703125 +3187 0.35833740234375 +3188 0.214691162109375 +3189 0.348541259765625 +3190 0.2086181640625 +3191 0.338714599609375 +3192 0.202545166015625 +3193 0.328826904296875 +3194 0.196441650390625 +3195 0.318939208984375 +3196 0.1903076171875 +3197 0.308990478515625 +3198 0.184173583984375 +3199 0.29901123046875 +3200 0.178009033203125 +3201 0.28900146484375 +3202 0.17181396484375 +3203 0.278961181640625 +3204 0.165618896484375 +3205 0.268890380859375 +3206 0.159393310546875 +3207 0.2587890625 +3208 0.153167724609375 +3209 0.2486572265625 +3210 0.14691162109375 +3211 0.238525390625 +3212 0.140625 +3213 0.22833251953125 +3214 0.13433837890625 +3215 0.218109130859375 +3216 0.1280517578125 +3217 0.2078857421875 +3218 0.121734619140625 +3219 0.1976318359375 +3220 0.115386962890625 +3221 0.187347412109375 +3222 0.109039306640625 +3223 0.17706298828125 +3224 0.102691650390625 +3225 0.166748046875 +3226 0.0963134765625 +3227 0.156402587890625 +3228 0.0899658203125 +3229 0.14605712890625 +3230 0.08355712890625 +3231 0.13568115234375 +3232 0.077178955078125 +3233 0.12530517578125 +3234 0.070770263671875 +3235 0.11492919921875 +3236 0.064361572265625 +3237 0.104522705078125 +3238 0.057952880859375 +3239 0.094085693359375 +3240 0.051513671875 +3241 0.083648681640625 +3242 0.045074462890625 +3243 0.073211669921875 +3244 0.038665771484375 +3245 0.062774658203125 +3246 0.032196044921875 +3247 0.05230712890625 +3248 0.025787353515625 +3249 0.0418701171875 +3250 0.019317626953125 +3251 0.031402587890625 +3252 0.01287841796875 +3253 0.02093505859375 +3254 0.006439208984375 +3255 0.010467529296875 +3256 0.0 +3257 0.0 +3258 -0.006439208984375 +3259 -0.010467529296875 +3260 -0.01287841796875 +3261 -0.02093505859375 +3262 -0.019317626953125 +3263 -0.031402587890625 +3264 -0.025787353515625 +3265 -0.0418701171875 +3266 -0.032196044921875 +3267 -0.05230712890625 +3268 -0.038665771484375 +3269 -0.062774658203125 +3270 -0.045074462890625 +3271 -0.073211669921875 +3272 -0.051513671875 +3273 -0.083648681640625 +3274 -0.057952880859375 +3275 -0.094085693359375 +3276 -0.064361572265625 +3277 -0.104522705078125 +3278 -0.070770263671875 +3279 -0.11492919921875 +3280 -0.077178955078125 +3281 -0.12530517578125 +3282 -0.08355712890625 +3283 -0.13568115234375 +3284 -0.0899658203125 +3285 -0.14605712890625 +3286 -0.0963134765625 +3287 -0.156402587890625 +3288 -0.102691650390625 +3289 -0.166748046875 +3290 -0.109039306640625 +3291 -0.17706298828125 +3292 -0.115386962890625 +3293 -0.187347412109375 +3294 -0.121734619140625 +3295 -0.1976318359375 +3296 -0.1280517578125 +3297 -0.2078857421875 +3298 -0.13433837890625 +3299 -0.218109130859375 +3300 -0.140625 +3301 -0.22833251953125 +3302 -0.14691162109375 +3303 -0.238525390625 +3304 -0.153167724609375 +3305 -0.2486572265625 +3306 -0.159393310546875 +3307 -0.2587890625 +3308 -0.165618896484375 +3309 -0.268890380859375 +3310 -0.17181396484375 +3311 -0.278961181640625 +3312 -0.178009033203125 +3313 -0.28900146484375 +3314 -0.184173583984375 +3315 -0.29901123046875 +3316 -0.1903076171875 +3317 -0.308990478515625 +3318 -0.196441650390625 +3319 -0.318939208984375 +3320 -0.202545166015625 +3321 -0.328826904296875 +3322 -0.2086181640625 +3323 -0.338714599609375 +3324 -0.214691162109375 +3325 -0.348541259765625 +3326 -0.220703125 +3327 -0.35833740234375 +3328 -0.2149658203125 +3329 -0.36810302734375 +3330 -0.220611572265625 +3331 -0.3778076171875 +3332 -0.226287841796875 +3333 -0.387481689453125 +3334 -0.231903076171875 +3335 -0.397125244140625 +3336 -0.23748779296875 +3337 -0.406707763671875 +3338 -0.243072509765625 +3339 -0.416259765625 +3340 -0.248626708984375 +3341 -0.425750732421875 +3342 -0.254150390625 +3343 -0.435211181640625 +3344 -0.2596435546875 +3345 -0.444610595703125 +3346 -0.265106201171875 +3347 -0.453948974609375 +3348 -0.270538330078125 +3349 -0.4632568359375 +3350 -0.27593994140625 +3351 -0.4725341796875 +3352 -0.28131103515625 +3353 -0.481719970703125 +3354 -0.286651611328125 +3355 -0.490875244140625 +3356 -0.291961669921875 +3357 -0.499969482421875 +3358 -0.2972412109375 +3359 -0.509002685546875 +3360 -0.302490234375 +3361 -0.51800537109375 +3362 -0.307708740234375 +3363 -0.52691650390625 +3364 -0.312896728515625 +3365 -0.535797119140625 +3366 -0.31805419921875 +3367 -0.54461669921875 +3368 -0.323150634765625 +3369 -0.5533447265625 +3370 -0.328216552734375 +3371 -0.562042236328125 +3372 -0.333251953125 +3373 -0.5706787109375 +3374 -0.3382568359375 +3375 -0.579254150390625 +3376 -0.343231201171875 +3377 -0.587738037109375 +3378 -0.348175048828125 +3379 -0.59619140625 +3380 -0.353057861328125 +3381 -0.60455322265625 +3382 -0.35791015625 +3383 -0.612884521484375 +3384 -0.36273193359375 +3385 -0.621124267578125 +3386 -0.36749267578125 +3387 -0.6292724609375 +3388 -0.372222900390625 +3389 -0.63739013671875 +3390 -0.376922607421875 +3391 -0.645416259765625 +3392 -0.381561279296875 +3393 -0.65338134765625 +3394 -0.38616943359375 +3395 -0.661285400390625 +3396 -0.3907470703125 +3397 -0.669097900390625 +3398 -0.395263671875 +3399 -0.676849365234375 +3400 -0.399749755859375 +3401 -0.68450927734375 +3402 -0.4041748046875 +3403 -0.692108154296875 +3404 -0.4085693359375 +3405 -0.699615478515625 +3406 -0.41290283203125 +3407 -0.707061767578125 +3408 -0.417236328125 +3409 -0.714447021484375 +3410 -0.421478271484375 +3411 -0.721710205078125 +3412 -0.425689697265625 +3413 -0.72894287109375 +3414 -0.429840087890625 +3415 -0.736053466796875 +3416 -0.4339599609375 +3417 -0.74310302734375 +3418 -0.438018798828125 +3419 -0.75006103515625 +3420 -0.442047119140625 +3421 -0.7569580078125 +3422 -0.446014404296875 +3423 -0.763763427734375 +3424 -0.449951171875 +3425 -0.770477294921875 +3426 -0.453826904296875 +3427 -0.777099609375 +3428 -0.4576416015625 +3429 -0.783660888671875 +3430 -0.46142578125 +3431 -0.790130615234375 +3432 -0.465118408203125 +3433 -0.796478271484375 +3434 -0.46881103515625 +3435 -0.802764892578125 +3436 -0.472442626953125 +3437 -0.808990478515625 +3438 -0.47601318359375 +3439 -0.815093994140625 +3440 -0.479522705078125 +3441 -0.82110595703125 +3442 -0.48297119140625 +3443 -0.8270263671875 +3444 -0.48638916015625 +3445 -0.8328857421875 +3446 -0.48974609375 +3447 -0.838623046875 +3448 -0.493072509765625 +3449 -0.84429931640625 +3450 -0.496307373046875 +3451 -0.849853515625 +3452 -0.499481201171875 +3453 -0.855316162109375 +3454 -0.50262451171875 +3455 -0.860687255859375 +3456 -0.5057373046875 +3457 -0.865997314453125 +3458 -0.508758544921875 +3459 -0.871185302734375 +3460 -0.51171875 +3461 -0.876251220703125 +3462 -0.5146484375 +3463 -0.881256103515625 +3464 -0.51751708984375 +3465 -0.88616943359375 +3466 -0.520294189453125 +3467 -0.890960693359375 +3468 -0.523040771484375 +3469 -0.895660400390625 +3470 -0.5257568359375 +3471 -0.9002685546875 +3472 -0.52838134765625 +3473 -0.90478515625 +3474 -0.53094482421875 +3475 -0.9091796875 +3476 -0.533477783203125 +3477 -0.91351318359375 +3478 -0.53594970703125 +3479 -0.917724609375 +3480 -0.538330078125 +3481 -0.92181396484375 +3482 -0.540679931640625 +3483 -0.92584228515625 +3484 -0.542938232421875 +3485 -0.929718017578125 +3486 -0.545166015625 +3487 -0.93353271484375 +3488 -0.547332763671875 +3489 -0.937225341796875 +3490 -0.5494384765625 +3491 -0.940826416015625 +3492 -0.551483154296875 +3493 -0.9443359375 +3494 -0.553466796875 +3495 -0.947723388671875 +3496 -0.555389404296875 +3497 -0.951019287109375 +3498 -0.557220458984375 +3499 -0.954193115234375 +3500 -0.55902099609375 +3501 -0.957275390625 +3502 -0.560760498046875 +3503 -0.960235595703125 +3504 -0.56243896484375 +3505 -0.963104248046875 +3506 -0.564056396484375 +3507 -0.96588134765625 +3508 -0.56561279296875 +3509 -0.968536376953125 +3510 -0.567108154296875 +3511 -0.971099853515625 +3512 -0.56854248046875 +3513 -0.973541259765625 +3514 -0.56988525390625 +3515 -0.975860595703125 +3516 -0.571197509765625 +3517 -0.97808837890625 +3518 -0.57244873046875 +3519 -0.980224609375 +3520 -0.5736083984375 +3521 -0.98223876953125 +3522 -0.574737548828125 +3523 -0.984161376953125 +3524 -0.575775146484375 +3525 -0.9859619140625 +3526 -0.5767822265625 +3527 -0.987640380859375 +3528 -0.57769775390625 +3529 -0.989227294921875 +3530 -0.57855224609375 +3531 -0.990692138671875 +3532 -0.579345703125 +3533 -0.9920654296875 +3534 -0.580078125 +3535 -0.993316650390625 +3536 -0.58074951171875 +3537 -0.994476318359375 +3538 -0.58135986328125 +3539 -0.995513916015625 +3540 -0.5819091796875 +3541 -0.9964599609375 +3542 -0.5823974609375 +3543 -0.997283935546875 +3544 -0.58282470703125 +3545 -0.99798583984375 +3546 -0.583160400390625 +3547 -0.99859619140625 +3548 -0.583465576171875 +3549 -0.999114990234375 +3550 -0.58367919921875 +3551 -0.999481201171875 +3552 -0.583831787109375 +3553 -0.999755859375 +3554 -0.58392333984375 +3555 -0.99993896484375 +3556 -0.583984375 +3557 -1.0 +3558 -0.58392333984375 +3559 -0.99993896484375 +3560 -0.583831787109375 +3561 -0.999755859375 +3562 -0.58367919921875 +3563 -0.999481201171875 +3564 -0.583465576171875 +3565 -0.999114990234375 +3566 -0.583160400390625 +3567 -0.99859619140625 +3568 -0.58282470703125 +3569 -0.99798583984375 +3570 -0.5823974609375 +3571 -0.997283935546875 +3572 -0.5819091796875 +3573 -0.9964599609375 +3574 -0.58135986328125 +3575 -0.995513916015625 +3576 -0.58074951171875 +3577 -0.994476318359375 +3578 -0.580078125 +3579 -0.993316650390625 +3580 -0.579345703125 +3581 -0.9920654296875 +3582 -0.57855224609375 +3583 -0.990692138671875 +3584 -0.5460205078125 +3585 -0.989227294921875 +3586 -0.545135498046875 +3587 -0.987640380859375 +3588 -0.544219970703125 +3589 -0.9859619140625 +3590 -0.543243408203125 +3591 -0.984161376953125 +3592 -0.54217529296875 +3593 -0.98223876953125 +3594 -0.541046142578125 +3595 -0.980224609375 +3596 -0.539886474609375 +3597 -0.97808837890625 +3598 -0.53863525390625 +3599 -0.975860595703125 +3600 -0.537353515625 +3601 -0.973541259765625 +3602 -0.5360107421875 +3603 -0.971099853515625 +3604 -0.53460693359375 +3605 -0.968536376953125 +3606 -0.53314208984375 +3607 -0.96588134765625 +3608 -0.5316162109375 +3609 -0.963104248046875 +3610 -0.530029296875 +3611 -0.960235595703125 +3612 -0.52838134765625 +3613 -0.957275390625 +3614 -0.526702880859375 +3615 -0.954193115234375 +3616 -0.524932861328125 +3617 -0.951019287109375 +3618 -0.523101806640625 +3619 -0.947723388671875 +3620 -0.521240234375 +3621 -0.9443359375 +3622 -0.519317626953125 +3623 -0.940826416015625 +3624 -0.517333984375 +3625 -0.937225341796875 +3626 -0.515289306640625 +3627 -0.93353271484375 +3628 -0.51318359375 +3629 -0.929718017578125 +3630 -0.51104736328125 +3631 -0.92584228515625 +3632 -0.508819580078125 +3633 -0.92181396484375 +3634 -0.506561279296875 +3635 -0.917724609375 +3636 -0.504241943359375 +3637 -0.91351318359375 +3638 -0.5018310546875 +3639 -0.9091796875 +3640 -0.499420166015625 +3641 -0.90478515625 +3642 -0.496917724609375 +3643 -0.9002685546875 +3644 -0.494384765625 +3645 -0.895660400390625 +3646 -0.491790771484375 +3647 -0.890960693359375 +3648 -0.4891357421875 +3649 -0.88616943359375 +3650 -0.486419677734375 +3651 -0.881256103515625 +3652 -0.483673095703125 +3653 -0.876251220703125 +3654 -0.480865478515625 +3655 -0.871185302734375 +3656 -0.477996826171875 +3657 -0.865997314453125 +3658 -0.475067138671875 +3659 -0.860687255859375 +3660 -0.47210693359375 +3661 -0.855316162109375 +3662 -0.469085693359375 +3663 -0.849853515625 +3664 -0.466033935546875 +3665 -0.84429931640625 +3666 -0.462890625 +3667 -0.838623046875 +3668 -0.459716796875 +3669 -0.8328857421875 +3670 -0.45648193359375 +3671 -0.8270263671875 +3672 -0.453216552734375 +3673 -0.82110595703125 +3674 -0.449920654296875 +3675 -0.815093994140625 +3676 -0.446533203125 +3677 -0.808990478515625 +3678 -0.443115234375 +3679 -0.802764892578125 +3680 -0.43963623046875 +3681 -0.796478271484375 +3682 -0.436126708984375 +3683 -0.790130615234375 +3684 -0.43255615234375 +3685 -0.783660888671875 +3686 -0.428924560546875 +3687 -0.777099609375 +3688 -0.42529296875 +3689 -0.770477294921875 +3690 -0.42156982421875 +3691 -0.763763427734375 +3692 -0.417816162109375 +3693 -0.7569580078125 +3694 -0.41400146484375 +3695 -0.75006103515625 +3696 -0.41015625 +3697 -0.74310302734375 +3698 -0.406280517578125 +3699 -0.736053466796875 +3700 -0.40234375 +3701 -0.72894287109375 +3702 -0.398345947265625 +3703 -0.721710205078125 +3704 -0.39434814453125 +3705 -0.714447021484375 +3706 -0.390289306640625 +3707 -0.707061767578125 +3708 -0.38616943359375 +3709 -0.699615478515625 +3710 -0.38201904296875 +3711 -0.692108154296875 +3712 -0.377838134765625 +3713 -0.68450927734375 +3714 -0.37359619140625 +3715 -0.676849365234375 +3716 -0.36932373046875 +3717 -0.669097900390625 +3718 -0.365020751953125 +3719 -0.661285400390625 +3720 -0.36065673828125 +3721 -0.65338134765625 +3722 -0.35626220703125 +3723 -0.645416259765625 +3724 -0.351806640625 +3725 -0.63739013671875 +3726 -0.347320556640625 +3727 -0.6292724609375 +3728 -0.34283447265625 +3729 -0.621124267578125 +3730 -0.338287353515625 +3731 -0.612884521484375 +3732 -0.33367919921875 +3733 -0.60455322265625 +3734 -0.329071044921875 +3735 -0.59619140625 +3736 -0.32440185546875 +3737 -0.587738037109375 +3738 -0.319732666015625 +3739 -0.579254150390625 +3740 -0.31500244140625 +3741 -0.5706787109375 +3742 -0.310211181640625 +3743 -0.562042236328125 +3744 -0.305419921875 +3745 -0.5533447265625 +3746 -0.30059814453125 +3747 -0.54461669921875 +3748 -0.295745849609375 +3749 -0.535797119140625 +3750 -0.29083251953125 +3751 -0.52691650390625 +3752 -0.285919189453125 +3753 -0.51800537109375 +3754 -0.28094482421875 +3755 -0.509002685546875 +3756 -0.275970458984375 +3757 -0.499969482421875 +3758 -0.27093505859375 +3759 -0.490875244140625 +3760 -0.265899658203125 +3761 -0.481719970703125 +3762 -0.26080322265625 +3763 -0.4725341796875 +3764 -0.255706787109375 +3765 -0.4632568359375 +3766 -0.25054931640625 +3767 -0.453948974609375 +3768 -0.245391845703125 +3769 -0.444610595703125 +3770 -0.240203857421875 +3771 -0.435211181640625 +3772 -0.2349853515625 +3773 -0.425750732421875 +3774 -0.229766845703125 +3775 -0.416259765625 +3776 -0.2244873046875 +3777 -0.406707763671875 +3778 -0.219207763671875 +3779 -0.397125244140625 +3780 -0.2138671875 +3781 -0.387481689453125 +3782 -0.208526611328125 +3783 -0.3778076171875 +3784 -0.20318603515625 +3785 -0.36810302734375 +3786 -0.197784423828125 +3787 -0.35833740234375 +3788 -0.1923828125 +3789 -0.348541259765625 +3790 -0.18695068359375 +3791 -0.338714599609375 +3792 -0.181488037109375 +3793 -0.328826904296875 +3794 -0.176025390625 +3795 -0.318939208984375 +3796 -0.1705322265625 +3797 -0.308990478515625 +3798 -0.1650390625 +3799 -0.29901123046875 +3800 -0.159515380859375 +3801 -0.28900146484375 +3802 -0.153961181640625 +3803 -0.278961181640625 +3804 -0.148406982421875 +3805 -0.268890380859375 +3806 -0.142822265625 +3807 -0.2587890625 +3808 -0.137237548828125 +3809 -0.2486572265625 +3810 -0.13165283203125 +3811 -0.238525390625 +3812 -0.126007080078125 +3813 -0.22833251953125 +3814 -0.120391845703125 +3815 -0.218109130859375 +3816 -0.11474609375 +3817 -0.2078857421875 +3818 -0.10906982421875 +3819 -0.1976318359375 +3820 -0.1033935546875 +3821 -0.187347412109375 +3822 -0.09771728515625 +3823 -0.17706298828125 +3824 -0.092041015625 +3825 -0.166748046875 +3826 -0.0863037109375 +3827 -0.156402587890625 +3828 -0.080596923828125 +3829 -0.14605712890625 +3830 -0.07489013671875 +3831 -0.13568115234375 +3832 -0.06915283203125 +3833 -0.12530517578125 +3834 -0.06341552734375 +3835 -0.11492919921875 +3836 -0.05767822265625 +3837 -0.104522705078125 +3838 -0.051910400390625 +3839 -0.094085693359375 +3840 -0.045989990234375 +3841 -0.083648681640625 +3842 -0.040252685546875 +3843 -0.073211669921875 +3844 -0.034515380859375 +3845 -0.062774658203125 +3846 -0.02874755859375 +3847 -0.05230712890625 +3848 -0.02301025390625 +3849 -0.0418701171875 +3850 -0.017242431640625 +3851 -0.031402587890625 +3852 -0.011505126953125 +3853 -0.02093505859375 +3854 -0.0057373046875 +3855 -0.010467529296875 +3856 0.0 +3857 0.0 +3858 0.00543212890625 +3859 0.010467529296875 +3860 0.0108642578125 +3861 0.02093505859375 +3862 0.016326904296875 +3863 0.031402587890625 +3864 0.021759033203125 +3865 0.0418701171875 +3866 0.027191162109375 +3867 0.05230712890625 +3868 0.032623291015625 +3869 0.062774658203125 +3870 0.038055419921875 +3871 0.073211669921875 +3872 0.043487548828125 +3873 0.083648681640625 +3874 0.048919677734375 +3875 0.094085693359375 +3876 0.054351806640625 +3877 0.104522705078125 +3878 0.05975341796875 +3879 0.11492919921875 +3880 0.065155029296875 +3881 0.12530517578125 +3882 0.070526123046875 +3883 0.13568115234375 +3884 0.075927734375 +3885 0.14605712890625 +3886 0.081329345703125 +3887 0.156402587890625 +3888 0.086700439453125 +3889 0.166748046875 +3890 0.092071533203125 +3891 0.17706298828125 +3892 0.097412109375 +3893 0.187347412109375 +3894 0.102752685546875 +3895 0.1976318359375 +3896 0.10809326171875 +3897 0.2078857421875 +3898 0.1134033203125 +3899 0.218109130859375 +3900 0.11871337890625 +3901 0.22833251953125 +3902 0.1240234375 +3903 0.238525390625 +3904 0.1292724609375 +3905 0.2486572265625 +3906 0.134552001953125 +3907 0.2587890625 +3908 0.139801025390625 +3909 0.268890380859375 +3910 0.145050048828125 +3911 0.278961181640625 +3912 0.1502685546875 +3913 0.28900146484375 +3914 0.155487060546875 +3915 0.29901123046875 +3916 0.160675048828125 +3917 0.308990478515625 +3918 0.16583251953125 +3919 0.318939208984375 +3920 0.170989990234375 +3921 0.328826904296875 +3922 0.176116943359375 +3923 0.338714599609375 +3924 0.18121337890625 +3925 0.348541259765625 +3926 0.186309814453125 +3927 0.35833740234375 +3928 0.19140625 +3929 0.36810302734375 +3930 0.196441650390625 +3931 0.3778076171875 +3932 0.20147705078125 +3933 0.387481689453125 +3934 0.20648193359375 +3935 0.397125244140625 +3936 0.21148681640625 +3937 0.406707763671875 +3938 0.2164306640625 +3939 0.416259765625 +3940 0.22137451171875 +3941 0.425750732421875 +3942 0.226287841796875 +3943 0.435211181640625 +3944 0.231170654296875 +3945 0.444610595703125 +3946 0.236053466796875 +3947 0.453948974609375 +3948 0.240875244140625 +3949 0.4632568359375 +3950 0.245697021484375 +3951 0.4725341796875 +3952 0.25048828125 +3953 0.481719970703125 +3954 0.2552490234375 +3955 0.490875244140625 +3956 0.259979248046875 +3957 0.499969482421875 +3958 0.264678955078125 +3959 0.509002685546875 +3960 0.26934814453125 +3961 0.51800537109375 +3962 0.27398681640625 +3963 0.52691650390625 +3964 0.278594970703125 +3965 0.535797119140625 +3966 0.283203125 +3967 0.54461669921875 +3968 0.2877197265625 +3969 0.5533447265625 +3970 0.292236328125 +3971 0.562042236328125 +3972 0.2967529296875 +3973 0.5706787109375 +3974 0.30120849609375 +3975 0.579254150390625 +3976 0.30560302734375 +3977 0.587738037109375 +3978 0.30999755859375 +3979 0.59619140625 +3980 0.314361572265625 +3981 0.60455322265625 +3982 0.318695068359375 +3983 0.612884521484375 +3984 0.322967529296875 +3985 0.621124267578125 +3986 0.32720947265625 +3987 0.6292724609375 +3988 0.3314208984375 +3989 0.63739013671875 +3990 0.335601806640625 +3991 0.645416259765625 +3992 0.339752197265625 +3993 0.65338134765625 +3994 0.343841552734375 +3995 0.661285400390625 +3996 0.347930908203125 +3997 0.669097900390625 +3998 0.351959228515625 +3999 0.676849365234375 +4000 0.355926513671875 +4001 0.68450927734375 +4002 0.359893798828125 +4003 0.692108154296875 +4004 0.363800048828125 +4005 0.699615478515625 +4006 0.367645263671875 +4007 0.707061767578125 +4008 0.371490478515625 +4009 0.714447021484375 +4010 0.375274658203125 +4011 0.721710205078125 +4012 0.3790283203125 +4013 0.72894287109375 +4014 0.382720947265625 +4015 0.736053466796875 +4016 0.38641357421875 +4017 0.74310302734375 +4018 0.3900146484375 +4019 0.75006103515625 +4020 0.39361572265625 +4021 0.7569580078125 +4022 0.39715576171875 +4023 0.763763427734375 +4024 0.400634765625 +4025 0.770477294921875 +4026 0.404083251953125 +4027 0.777099609375 +4028 0.407501220703125 +4029 0.783660888671875 +4030 0.410858154296875 +4031 0.790130615234375 +4032 0.414154052734375 +4033 0.796478271484375 +4034 0.41741943359375 +4035 0.802764892578125 +4036 0.420654296875 +4037 0.808990478515625 +4038 0.423828125 +4039 0.815093994140625 +4040 0.426971435546875 +4041 0.82110595703125 +4042 0.4300537109375 +4043 0.8270263671875 +4044 0.433074951171875 +4045 0.8328857421875 +4046 0.436065673828125 +4047 0.838623046875 +4048 0.43902587890625 +4049 0.84429931640625 +4050 0.441925048828125 +4051 0.849853515625 +4052 0.44476318359375 +4053 0.855316162109375 +4054 0.447540283203125 +4055 0.860687255859375 +4056 0.4503173828125 +4057 0.865997314453125 +4058 0.4530029296875 +4059 0.871185302734375 +4060 0.45562744140625 +4061 0.876251220703125 +4062 0.458251953125 +4063 0.881256103515625 +4064 0.460784912109375 +4065 0.88616943359375 +4066 0.463287353515625 +4067 0.890960693359375 +4068 0.465728759765625 +4069 0.895660400390625 +4070 0.4681396484375 +4071 0.9002685546875 +4072 0.470489501953125 +4073 0.90478515625 +4074 0.472747802734375 +4075 0.9091796875 +4076 0.475006103515625 +4077 0.91351318359375 +4078 0.477203369140625 +4079 0.917724609375 +4080 0.479339599609375 +4081 0.92181396484375 +4082 0.481414794921875 +4083 0.92584228515625 +4084 0.483428955078125 +4085 0.929718017578125 +4086 0.48541259765625 +4087 0.93353271484375 +4088 0.487335205078125 +4089 0.937225341796875 +4090 0.489227294921875 +4091 0.940826416015625 +4092 0.491058349609375 +4093 0.9443359375 +4094 0.4927978515625 +4095 0.947723388671875 +4096 0.464080810546875 +4097 0.951019287109375 +4098 0.46563720703125 +4099 0.954193115234375 +4100 0.467132568359375 +4101 0.957275390625 +4102 0.46856689453125 +4103 0.960235595703125 +4104 0.469970703125 +4105 0.963104248046875 +4106 0.4713134765625 +4107 0.96588134765625 +4108 0.472625732421875 +4109 0.968536376953125 +4110 0.473876953125 +4111 0.971099853515625 +4112 0.475067138671875 +4113 0.973541259765625 +4114 0.4761962890625 +4115 0.975860595703125 +4116 0.477294921875 +4117 0.97808837890625 +4118 0.47833251953125 +4119 0.980224609375 +4120 0.47930908203125 +4121 0.98223876953125 +4122 0.480255126953125 +4123 0.984161376953125 +4124 0.48114013671875 +4125 0.9859619140625 +4126 0.48193359375 +4127 0.987640380859375 +4128 0.48272705078125 +4129 0.989227294921875 +4130 0.483428955078125 +4131 0.990692138671875 +4132 0.484100341796875 +4133 0.9920654296875 +4134 0.484710693359375 +4135 0.993316650390625 +4136 0.48529052734375 +4137 0.994476318359375 +4138 0.48577880859375 +4139 0.995513916015625 +4140 0.486236572265625 +4141 0.9964599609375 +4142 0.486663818359375 +4143 0.997283935546875 +4144 0.48699951171875 +4145 0.99798583984375 +4146 0.4873046875 +4147 0.99859619140625 +4148 0.487518310546875 +4149 0.999114990234375 +4150 0.487701416015625 +4151 0.999481201171875 +4152 0.48785400390625 +4153 0.999755859375 +4154 0.487945556640625 +4155 0.99993896484375 +4156 0.48797607421875 +4157 0.999969482421875 +4158 0.487945556640625 +4159 0.99993896484375 +4160 0.48785400390625 +4161 0.999755859375 +4162 0.487701416015625 +4163 0.999481201171875 +4164 0.487518310546875 +4165 0.999114990234375 +4166 0.4873046875 +4167 0.99859619140625 +4168 0.48699951171875 +4169 0.99798583984375 +4170 0.486663818359375 +4171 0.997283935546875 +4172 0.486236572265625 +4173 0.9964599609375 +4174 0.48577880859375 +4175 0.995513916015625 +4176 0.48529052734375 +4177 0.994476318359375 +4178 0.484710693359375 +4179 0.993316650390625 +4180 0.484100341796875 +4181 0.9920654296875 +4182 0.483428955078125 +4183 0.990692138671875 +4184 0.48272705078125 +4185 0.989227294921875 +4186 0.48193359375 +4187 0.987640380859375 +4188 0.48114013671875 +4189 0.9859619140625 +4190 0.480255126953125 +4191 0.984161376953125 +4192 0.47930908203125 +4193 0.98223876953125 +4194 0.47833251953125 +4195 0.980224609375 +4196 0.477294921875 +4197 0.97808837890625 +4198 0.4761962890625 +4199 0.975860595703125 +4200 0.475067138671875 +4201 0.973541259765625 +4202 0.473876953125 +4203 0.971099853515625 +4204 0.472625732421875 +4205 0.968536376953125 +4206 0.4713134765625 +4207 0.96588134765625 +4208 0.469970703125 +4209 0.963104248046875 +4210 0.46856689453125 +4211 0.960235595703125 +4212 0.467132568359375 +4213 0.957275390625 +4214 0.46563720703125 +4215 0.954193115234375 +4216 0.464080810546875 +4217 0.951019287109375 +4218 0.46246337890625 +4219 0.947723388671875 +4220 0.4608154296875 +4221 0.9443359375 +4222 0.4591064453125 +4223 0.940826416015625 +4224 0.45733642578125 +4225 0.937225341796875 +4226 0.455535888671875 +4227 0.93353271484375 +4228 0.45367431640625 +4229 0.929718017578125 +4230 0.4517822265625 +4231 0.92584228515625 +4232 0.4498291015625 +4233 0.92181396484375 +4234 0.44781494140625 +4235 0.917724609375 +4236 0.445770263671875 +4237 0.91351318359375 +4238 0.44366455078125 +4239 0.9091796875 +4240 0.441497802734375 +4241 0.90478515625 +4242 0.439300537109375 +4243 0.9002685546875 +4244 0.43707275390625 +4245 0.895660400390625 +4246 0.43475341796875 +4247 0.890960693359375 +4248 0.43243408203125 +4249 0.88616943359375 +4250 0.430023193359375 +4251 0.881256103515625 +4252 0.427581787109375 +4253 0.876251220703125 +4254 0.42510986328125 +4255 0.871185302734375 +4256 0.422576904296875 +4257 0.865997314453125 +4258 0.41998291015625 +4259 0.860687255859375 +4260 0.4173583984375 +4261 0.855316162109375 +4262 0.414703369140625 +4263 0.849853515625 +4264 0.4119873046875 +4265 0.84429931640625 +4266 0.409210205078125 +4267 0.838623046875 +4268 0.40643310546875 +4269 0.8328857421875 +4270 0.403564453125 +4271 0.8270263671875 +4272 0.400665283203125 +4273 0.82110595703125 +4274 0.397735595703125 +4275 0.815093994140625 +4276 0.394775390625 +4277 0.808990478515625 +4278 0.3917236328125 +4279 0.802764892578125 +4280 0.388671875 +4281 0.796478271484375 +4282 0.38555908203125 +4283 0.790130615234375 +4284 0.382415771484375 +4285 0.783660888671875 +4286 0.37921142578125 +4287 0.777099609375 +4288 0.3759765625 +4289 0.770477294921875 +4290 0.3726806640625 +4291 0.763763427734375 +4292 0.369384765625 +4293 0.7569580078125 +4294 0.365997314453125 +4295 0.75006103515625 +4296 0.36260986328125 +4297 0.74310302734375 +4298 0.359161376953125 +4299 0.736053466796875 +4300 0.355712890625 +4301 0.72894287109375 +4302 0.3521728515625 +4303 0.721710205078125 +4304 0.3486328125 +4305 0.714447021484375 +4306 0.34503173828125 +4307 0.707061767578125 +4308 0.341400146484375 +4309 0.699615478515625 +4310 0.337738037109375 +4311 0.692108154296875 +4312 0.334014892578125 +4313 0.68450927734375 +4314 0.330291748046875 +4315 0.676849365234375 +4316 0.326507568359375 +4317 0.669097900390625 +4318 0.32269287109375 +4319 0.661285400390625 +4320 0.318817138671875 +4321 0.65338134765625 +4322 0.31494140625 +4323 0.645416259765625 +4324 0.31103515625 +4325 0.63739013671875 +4326 0.30706787109375 +4327 0.6292724609375 +4328 0.3031005859375 +4329 0.621124267578125 +4330 0.299072265625 +4331 0.612884521484375 +4332 0.295013427734375 +4333 0.60455322265625 +4334 0.290924072265625 +4335 0.59619140625 +4336 0.28680419921875 +4337 0.587738037109375 +4338 0.28265380859375 +4339 0.579254150390625 +4340 0.278472900390625 +4341 0.5706787109375 +4342 0.274261474609375 +4343 0.562042236328125 +4344 0.27001953125 +4345 0.5533447265625 +4346 0.2657470703125 +4347 0.54461669921875 +4348 0.261444091796875 +4349 0.535797119140625 +4350 0.257110595703125 +4351 0.52691650390625 +4352 0.2362060546875 +4353 0.51800537109375 +4354 0.232086181640625 +4355 0.509002685546875 +4356 0.22796630859375 +4357 0.499969482421875 +4358 0.22381591796875 +4359 0.490875244140625 +4360 0.21966552734375 +4361 0.481719970703125 +4362 0.2154541015625 +4363 0.4725341796875 +4364 0.21124267578125 +4365 0.4632568359375 +4366 0.207000732421875 +4367 0.453948974609375 +4368 0.202728271484375 +4369 0.444610595703125 +4370 0.198455810546875 +4371 0.435211181640625 +4372 0.194122314453125 +4373 0.425750732421875 +4374 0.189788818359375 +4375 0.416259765625 +4376 0.185455322265625 +4377 0.406707763671875 +4378 0.18109130859375 +4379 0.397125244140625 +4380 0.176666259765625 +4381 0.387481689453125 +4382 0.172271728515625 +4383 0.3778076171875 +4384 0.1678466796875 +4385 0.36810302734375 +4386 0.16339111328125 +4387 0.35833740234375 +4388 0.158935546875 +4389 0.348541259765625 +4390 0.154449462890625 +4391 0.338714599609375 +4392 0.149932861328125 +4393 0.328826904296875 +4394 0.145416259765625 +4395 0.318939208984375 +4396 0.140899658203125 +4397 0.308990478515625 +4398 0.136322021484375 +4399 0.29901123046875 +4400 0.13177490234375 +4401 0.28900146484375 +4402 0.127197265625 +4403 0.278961181640625 +4404 0.122589111328125 +4405 0.268890380859375 +4406 0.11798095703125 +4407 0.2587890625 +4408 0.113372802734375 +4409 0.2486572265625 +4410 0.1087646484375 +4411 0.238525390625 +4412 0.104095458984375 +4413 0.22833251953125 +4414 0.099456787109375 +4415 0.218109130859375 +4416 0.09478759765625 +4417 0.2078857421875 +4418 0.090118408203125 +4419 0.1976318359375 +4420 0.085418701171875 +4421 0.187347412109375 +4422 0.080718994140625 +4423 0.17706298828125 +4424 0.076019287109375 +4425 0.166748046875 +4426 0.071319580078125 +4427 0.156402587890625 +4428 0.06658935546875 +4429 0.14605712890625 +4430 0.061859130859375 +4431 0.13568115234375 +4432 0.05712890625 +4433 0.12530517578125 +4434 0.052398681640625 +4435 0.11492919921875 +4436 0.047637939453125 +4437 0.104522705078125 +4438 0.042877197265625 +4439 0.094085693359375 +4440 0.038116455078125 +4441 0.083648681640625 +4442 0.033355712890625 +4443 0.073211669921875 +4444 0.02862548828125 +4445 0.062774658203125 +4446 0.023834228515625 +4447 0.05230712890625 +4448 0.019073486328125 +4449 0.0418701171875 +4450 0.014312744140625 +4451 0.031402587890625 +4452 0.009521484375 +4453 0.02093505859375 +4454 0.0047607421875 +4455 0.010467529296875 +4456 0.0 +4457 0.0 +4458 -0.0047607421875 +4459 -0.010467529296875 +4460 -0.009521484375 +4461 -0.02093505859375 +4462 -0.014312744140625 +4463 -0.031402587890625 +4464 -0.019073486328125 +4465 -0.0418701171875 +4466 -0.023834228515625 +4467 -0.05230712890625 +4468 -0.02862548828125 +4469 -0.062774658203125 +4470 -0.033355712890625 +4471 -0.073211669921875 +4472 -0.038116455078125 +4473 -0.083648681640625 +4474 -0.042877197265625 +4475 -0.094085693359375 +4476 -0.047637939453125 +4477 -0.104522705078125 +4478 -0.052398681640625 +4479 -0.11492919921875 +4480 -0.05712890625 +4481 -0.12530517578125 +4482 -0.061859130859375 +4483 -0.13568115234375 +4484 -0.06658935546875 +4485 -0.14605712890625 +4486 -0.071319580078125 +4487 -0.156402587890625 +4488 -0.076019287109375 +4489 -0.166748046875 +4490 -0.080718994140625 +4491 -0.17706298828125 +4492 -0.085418701171875 +4493 -0.187347412109375 +4494 -0.090118408203125 +4495 -0.1976318359375 +4496 -0.09478759765625 +4497 -0.2078857421875 +4498 -0.099456787109375 +4499 -0.218109130859375 +4500 -0.104095458984375 +4501 -0.22833251953125 +4502 -0.1087646484375 +4503 -0.238525390625 +4504 -0.113372802734375 +4505 -0.2486572265625 +4506 -0.11798095703125 +4507 -0.2587890625 +4508 -0.122589111328125 +4509 -0.268890380859375 +4510 -0.127197265625 +4511 -0.278961181640625 +4512 -0.13177490234375 +4513 -0.28900146484375 +4514 -0.136322021484375 +4515 -0.29901123046875 +4516 -0.140899658203125 +4517 -0.308990478515625 +4518 -0.145416259765625 +4519 -0.318939208984375 +4520 -0.149932861328125 +4521 -0.328826904296875 +4522 -0.154449462890625 +4523 -0.338714599609375 +4524 -0.158935546875 +4525 -0.348541259765625 +4526 -0.16339111328125 +4527 -0.35833740234375 +4528 -0.1678466796875 +4529 -0.36810302734375 +4530 -0.172271728515625 +4531 -0.3778076171875 +4532 -0.176666259765625 +4533 -0.387481689453125 +4534 -0.18109130859375 +4535 -0.397125244140625 +4536 -0.185455322265625 +4537 -0.406707763671875 +4538 -0.189788818359375 +4539 -0.416259765625 +4540 -0.194122314453125 +4541 -0.425750732421875 +4542 -0.198455810546875 +4543 -0.435211181640625 +4544 -0.202728271484375 +4545 -0.444610595703125 +4546 -0.207000732421875 +4547 -0.453948974609375 +4548 -0.21124267578125 +4549 -0.4632568359375 +4550 -0.2154541015625 +4551 -0.4725341796875 +4552 -0.21966552734375 +4553 -0.481719970703125 +4554 -0.22381591796875 +4555 -0.490875244140625 +4556 -0.22796630859375 +4557 -0.499969482421875 +4558 -0.232086181640625 +4559 -0.509002685546875 +4560 -0.2362060546875 +4561 -0.51800537109375 +4562 -0.240264892578125 +4563 -0.52691650390625 +4564 -0.24432373046875 +4565 -0.535797119140625 +4566 -0.248321533203125 +4567 -0.54461669921875 +4568 -0.2523193359375 +4569 -0.5533447265625 +4570 -0.25628662109375 +4571 -0.562042236328125 +4572 -0.260223388671875 +4573 -0.5706787109375 +4574 -0.264129638671875 +4575 -0.579254150390625 +4576 -0.26800537109375 +4577 -0.587738037109375 +4578 -0.2718505859375 +4579 -0.59619140625 +4580 -0.275665283203125 +4581 -0.60455322265625 +4582 -0.27947998046875 +4583 -0.612884521484375 +4584 -0.283233642578125 +4585 -0.621124267578125 +4586 -0.28692626953125 +4587 -0.6292724609375 +4588 -0.2906494140625 +4589 -0.63739013671875 +4590 -0.2943115234375 +4591 -0.645416259765625 +4592 -0.297943115234375 +4593 -0.65338134765625 +4594 -0.301544189453125 +4595 -0.661285400390625 +4596 -0.305084228515625 +4597 -0.669097900390625 +4598 -0.308624267578125 +4599 -0.676849365234375 +4600 -0.3121337890625 +4601 -0.68450927734375 +4602 -0.315582275390625 +4603 -0.692108154296875 +4604 -0.319000244140625 +4605 -0.699615478515625 +4606 -0.322418212890625 +4607 -0.707061767578125 +4608 -0.30291748046875 +4609 -0.714447021484375 +4610 -0.305999755859375 +4611 -0.721710205078125 +4612 -0.309051513671875 +4613 -0.72894287109375 +4614 -0.31207275390625 +4615 -0.736053466796875 +4616 -0.3150634765625 +4617 -0.74310302734375 +4618 -0.3179931640625 +4619 -0.75006103515625 +4620 -0.3209228515625 +4621 -0.7569580078125 +4622 -0.323822021484375 +4623 -0.763763427734375 +4624 -0.32666015625 +4625 -0.770477294921875 +4626 -0.3294677734375 +4627 -0.777099609375 +4628 -0.332244873046875 +4629 -0.783660888671875 +4630 -0.334991455078125 +4631 -0.790130615234375 +4632 -0.337677001953125 +4633 -0.796478271484375 +4634 -0.340362548828125 +4635 -0.802764892578125 +4636 -0.342987060546875 +4637 -0.808990478515625 +4638 -0.3455810546875 +4639 -0.815093994140625 +4640 -0.348114013671875 +4641 -0.82110595703125 +4642 -0.35064697265625 +4643 -0.8270263671875 +4644 -0.353118896484375 +4645 -0.8328857421875 +4646 -0.355560302734375 +4647 -0.838623046875 +4648 -0.35797119140625 +4649 -0.84429931640625 +4650 -0.360321044921875 +4651 -0.849853515625 +4652 -0.362640380859375 +4653 -0.855316162109375 +4654 -0.364898681640625 +4655 -0.860687255859375 +4656 -0.367156982421875 +4657 -0.865997314453125 +4658 -0.369354248046875 +4659 -0.871185302734375 +4660 -0.37152099609375 +4661 -0.876251220703125 +4662 -0.373626708984375 +4663 -0.881256103515625 +4664 -0.375701904296875 +4665 -0.88616943359375 +4666 -0.37774658203125 +4667 -0.890960693359375 +4668 -0.379730224609375 +4669 -0.895660400390625 +4670 -0.381683349609375 +4671 -0.9002685546875 +4672 -0.38360595703125 +4673 -0.90478515625 +4674 -0.385467529296875 +4675 -0.9091796875 +4676 -0.387298583984375 +4677 -0.91351318359375 +4678 -0.38909912109375 +4679 -0.917724609375 +4680 -0.390838623046875 +4681 -0.92181396484375 +4682 -0.392547607421875 +4683 -0.92584228515625 +4684 -0.3941650390625 +4685 -0.929718017578125 +4686 -0.395782470703125 +4687 -0.93353271484375 +4688 -0.397369384765625 +4689 -0.937225341796875 +4690 -0.398895263671875 +4691 -0.940826416015625 +4692 -0.400390625 +4693 -0.9443359375 +4694 -0.401824951171875 +4695 -0.947723388671875 +4696 -0.4031982421875 +4697 -0.951019287109375 +4698 -0.404571533203125 +4699 -0.954193115234375 +4700 -0.405853271484375 +4701 -0.957275390625 +4702 -0.4071044921875 +4703 -0.960235595703125 +4704 -0.4083251953125 +4705 -0.963104248046875 +4706 -0.409515380859375 +4707 -0.96588134765625 +4708 -0.41064453125 +4709 -0.968536376953125 +4710 -0.411712646484375 +4711 -0.971099853515625 +4712 -0.412750244140625 +4713 -0.973541259765625 +4714 -0.41375732421875 +4715 -0.975860595703125 +4716 -0.4146728515625 +4717 -0.97808837890625 +4718 -0.41558837890625 +4719 -0.980224609375 +4720 -0.41644287109375 +4721 -0.98223876953125 +4722 -0.417266845703125 +4723 -0.984161376953125 +4724 -0.41802978515625 +4725 -0.9859619140625 +4726 -0.418731689453125 +4727 -0.987640380859375 +4728 -0.419403076171875 +4729 -0.989227294921875 +4730 -0.4200439453125 +4731 -0.990692138671875 +4732 -0.420623779296875 +4733 -0.9920654296875 +4734 -0.421142578125 +4735 -0.993316650390625 +4736 -0.421630859375 +4737 -0.994476318359375 +4738 -0.422088623046875 +4739 -0.995513916015625 +4740 -0.4224853515625 +4741 -0.9964599609375 +4742 -0.422821044921875 +4743 -0.997283935546875 +4744 -0.423126220703125 +4745 -0.99798583984375 +4746 -0.423370361328125 +4747 -0.99859619140625 +4748 -0.423583984375 +4749 -0.999114990234375 +4750 -0.423736572265625 +4751 -0.999481201171875 +4752 -0.423858642578125 +4753 -0.999755859375 +4754 -0.4239501953125 +4755 -0.99993896484375 +4756 -0.423980712890625 +4757 -1.0 +4758 -0.4239501953125 +4759 -0.99993896484375 +4760 -0.423858642578125 +4761 -0.999755859375 +4762 -0.423736572265625 +4763 -0.999481201171875 +4764 -0.423583984375 +4765 -0.999114990234375 +4766 -0.423370361328125 +4767 -0.99859619140625 +4768 -0.423126220703125 +4769 -0.99798583984375 +4770 -0.422821044921875 +4771 -0.997283935546875 +4772 -0.4224853515625 +4773 -0.9964599609375 +4774 -0.422088623046875 +4775 -0.995513916015625 +4776 -0.421630859375 +4777 -0.994476318359375 +4778 -0.421142578125 +4779 -0.993316650390625 +4780 -0.420623779296875 +4781 -0.9920654296875 +4782 -0.4200439453125 +4783 -0.990692138671875 +4784 -0.419403076171875 +4785 -0.989227294921875 +4786 -0.418731689453125 +4787 -0.987640380859375 +4788 -0.41802978515625 +4789 -0.9859619140625 +4790 -0.417266845703125 +4791 -0.984161376953125 +4792 -0.41644287109375 +4793 -0.98223876953125 +4794 -0.41558837890625 +4795 -0.980224609375 +4796 -0.4146728515625 +4797 -0.97808837890625 +4798 -0.41375732421875 +4799 -0.975860595703125 +4800 -0.412750244140625 +4801 -0.973541259765625 +4802 -0.411712646484375 +4803 -0.971099853515625 +4804 -0.41064453125 +4805 -0.968536376953125 +4806 -0.409515380859375 +4807 -0.96588134765625 +4808 -0.4083251953125 +4809 -0.963104248046875 +4810 -0.4071044921875 +4811 -0.960235595703125 +4812 -0.405853271484375 +4813 -0.957275390625 +4814 -0.404571533203125 +4815 -0.954193115234375 +4816 -0.4031982421875 +4817 -0.951019287109375 +4818 -0.401824951171875 +4819 -0.947723388671875 +4820 -0.400390625 +4821 -0.9443359375 +4822 -0.398895263671875 +4823 -0.940826416015625 +4824 -0.397369384765625 +4825 -0.937225341796875 +4826 -0.395782470703125 +4827 -0.93353271484375 +4828 -0.3941650390625 +4829 -0.929718017578125 +4830 -0.392547607421875 +4831 -0.92584228515625 +4832 -0.390838623046875 +4833 -0.92181396484375 +4834 -0.38909912109375 +4835 -0.917724609375 +4836 -0.387298583984375 +4837 -0.91351318359375 +4838 -0.385467529296875 +4839 -0.9091796875 +4840 -0.38360595703125 +4841 -0.90478515625 +4842 -0.381683349609375 +4843 -0.9002685546875 +4844 -0.379730224609375 +4845 -0.895660400390625 +4846 -0.37774658203125 +4847 -0.890960693359375 +4848 -0.375701904296875 +4849 -0.88616943359375 +4850 -0.373626708984375 +4851 -0.881256103515625 +4852 -0.37152099609375 +4853 -0.876251220703125 +4854 -0.369354248046875 +4855 -0.871185302734375 +4856 -0.367156982421875 +4857 -0.865997314453125 +4858 -0.364898681640625 +4859 -0.860687255859375 +4860 -0.362640380859375 +4861 -0.855316162109375 +4862 -0.360321044921875 +4863 -0.849853515625 +4864 -0.33770751953125 +4865 -0.84429931640625 +4866 -0.33544921875 +4867 -0.838623046875 +4868 -0.3331298828125 +4869 -0.8328857421875 +4870 -0.330810546875 +4871 -0.8270263671875 +4872 -0.32843017578125 +4873 -0.82110595703125 +4874 -0.326019287109375 +4875 -0.815093994140625 +4876 -0.323577880859375 +4877 -0.808990478515625 +4878 -0.32110595703125 +4879 -0.802764892578125 +4880 -0.318572998046875 +4881 -0.796478271484375 +4882 -0.3160400390625 +4883 -0.790130615234375 +4884 -0.313446044921875 +4885 -0.783660888671875 +4886 -0.310821533203125 +4887 -0.777099609375 +4888 -0.30816650390625 +4889 -0.770477294921875 +4890 -0.30548095703125 +4891 -0.763763427734375 +4892 -0.302764892578125 +4893 -0.7569580078125 +4894 -0.300018310546875 +4895 -0.75006103515625 +4896 -0.2972412109375 +4897 -0.74310302734375 +4898 -0.294403076171875 +4899 -0.736053466796875 +4900 -0.29156494140625 +4901 -0.72894287109375 +4902 -0.288665771484375 +4903 -0.721710205078125 +4904 -0.2857666015625 +4905 -0.714447021484375 +4906 -0.282806396484375 +4907 -0.707061767578125 +4908 -0.27984619140625 +4909 -0.699615478515625 +4910 -0.276824951171875 +4911 -0.692108154296875 +4912 -0.2738037109375 +4913 -0.68450927734375 +4914 -0.270721435546875 +4915 -0.676849365234375 +4916 -0.26763916015625 +4917 -0.669097900390625 +4918 -0.264495849609375 +4919 -0.661285400390625 +4920 -0.2613525390625 +4921 -0.65338134765625 +4922 -0.258148193359375 +4923 -0.645416259765625 +4924 -0.25494384765625 +4925 -0.63739013671875 +4926 -0.251708984375 +4927 -0.6292724609375 +4928 -0.248443603515625 +4929 -0.621124267578125 +4930 -0.245147705078125 +4931 -0.612884521484375 +4932 -0.2418212890625 +4933 -0.60455322265625 +4934 -0.23846435546875 +4935 -0.59619140625 +4936 -0.235076904296875 +4937 -0.587738037109375 +4938 -0.231689453125 +4939 -0.579254150390625 +4940 -0.228271484375 +4941 -0.5706787109375 +4942 -0.22479248046875 +4943 -0.562042236328125 +4944 -0.2213134765625 +4945 -0.5533447265625 +4946 -0.21783447265625 +4947 -0.54461669921875 +4948 -0.21429443359375 +4949 -0.535797119140625 +4950 -0.21075439453125 +4951 -0.52691650390625 +4952 -0.207183837890625 +4953 -0.51800537109375 +4954 -0.203582763671875 +4955 -0.509002685546875 +4956 -0.199981689453125 +4957 -0.499969482421875 +4958 -0.19635009765625 +4959 -0.490875244140625 +4960 -0.19268798828125 +4961 -0.481719970703125 +4962 -0.188995361328125 +4963 -0.4725341796875 +4964 -0.185302734375 +4965 -0.4632568359375 +4966 -0.18157958984375 +4967 -0.453948974609375 +4968 -0.177825927734375 +4969 -0.444610595703125 +4970 -0.174072265625 +4971 -0.435211181640625 +4972 -0.1702880859375 +4973 -0.425750732421875 +4974 -0.16650390625 +4975 -0.416259765625 +4976 -0.16265869140625 +4977 -0.406707763671875 +4978 -0.158843994140625 +4979 -0.397125244140625 +4980 -0.15496826171875 +4981 -0.387481689453125 +4982 -0.151123046875 +4983 -0.3778076171875 +4984 -0.147216796875 +4985 -0.36810302734375 +4986 -0.143310546875 +4987 -0.35833740234375 +4988 -0.139404296875 +4989 -0.348541259765625 +4990 -0.135467529296875 +4991 -0.338714599609375 +4992 -0.13153076171875 +4993 -0.328826904296875 +4994 -0.1275634765625 +4995 -0.318939208984375 +4996 -0.12359619140625 +4997 -0.308990478515625 +4998 -0.119598388671875 +4999 -0.29901123046875 +5000 -0.1156005859375 +5001 -0.28900146484375 +5002 -0.111572265625 +5003 -0.278961181640625 +5004 -0.1075439453125 +5005 -0.268890380859375 +5006 -0.103515625 +5007 -0.2587890625 +5008 -0.099456787109375 +5009 -0.2486572265625 +5010 -0.09539794921875 +5011 -0.238525390625 +5012 -0.09130859375 +5013 -0.22833251953125 +5014 -0.08721923828125 +5015 -0.218109130859375 +5016 -0.0831298828125 +5017 -0.2078857421875 +5018 -0.07904052734375 +5019 -0.1976318359375 +5020 -0.074920654296875 +5021 -0.187347412109375 +5022 -0.07080078125 +5023 -0.17706298828125 +5024 -0.066680908203125 +5025 -0.166748046875 +5026 -0.06256103515625 +5027 -0.156402587890625 +5028 -0.05841064453125 +5029 -0.14605712890625 +5030 -0.05426025390625 +5031 -0.13568115234375 +5032 -0.05010986328125 +5033 -0.12530517578125 +5034 -0.04595947265625 +5035 -0.11492919921875 +5036 -0.04180908203125 +5037 -0.104522705078125 +5038 -0.037628173828125 +5039 -0.094085693359375 +5040 -0.033447265625 +5041 -0.083648681640625 +5042 -0.029266357421875 +5043 -0.073211669921875 +5044 -0.02508544921875 +5045 -0.062774658203125 +5046 -0.020904541015625 +5047 -0.05230712890625 +5048 -0.0167236328125 +5049 -0.0418701171875 +5050 -0.012542724609375 +5051 -0.031402587890625 +5052 -0.00836181640625 +5053 -0.02093505859375 +5054 -0.004180908203125 +5055 -0.010467529296875 +5056 0.0 +5057 0.0 +5058 0.00408935546875 +5059 0.010467529296875 +5060 0.0081787109375 +5061 0.02093505859375 +5062 0.012298583984375 +5063 0.031402587890625 +5064 0.016387939453125 +5065 0.0418701171875 +5066 0.020477294921875 +5067 0.05230712890625 +5068 0.02459716796875 +5069 0.062774658203125 +5070 0.0286865234375 +5071 0.073211669921875 +5072 0.03277587890625 +5073 0.083648681640625 +5074 0.036865234375 +5075 0.094085693359375 +5076 0.04095458984375 +5077 0.104522705078125 +5078 0.0450439453125 +5079 0.11492919921875 +5080 0.049102783203125 +5081 0.12530517578125 +5082 0.05316162109375 +5083 0.13568115234375 +5084 0.0572509765625 +5085 0.14605712890625 +5086 0.061309814453125 +5087 0.156402587890625 +5088 0.065338134765625 +5089 0.166748046875 +5090 0.06939697265625 +5091 0.17706298828125 +5092 0.07342529296875 +5093 0.187347412109375 +5094 0.07745361328125 +5095 0.1976318359375 +5096 0.08148193359375 +5097 0.2078857421875 +5098 0.085479736328125 +5099 0.218109130859375 +5100 0.089508056640625 +5101 0.22833251953125 +5102 0.093475341796875 +5103 0.238525390625 +5104 0.09747314453125 +5105 0.2486572265625 +5106 0.1014404296875 +5107 0.2587890625 +5108 0.10540771484375 +5109 0.268890380859375 +5110 0.109344482421875 +5111 0.278961181640625 +5112 0.11328125 +5113 0.28900146484375 +5114 0.1171875 +5115 0.29901123046875 +5116 0.121124267578125 +5117 0.308990478515625 +5118 0.125 +5119 0.318939208984375 +5120 0.11834716796875 +5121 0.328826904296875 +5122 0.121917724609375 +5123 0.338714599609375 +5124 0.125457763671875 +5125 0.348541259765625 +5126 0.128997802734375 +5127 0.35833740234375 +5128 0.13250732421875 +5129 0.36810302734375 +5130 0.135986328125 +5131 0.3778076171875 +5132 0.13946533203125 +5133 0.387481689453125 +5134 0.1429443359375 +5135 0.397125244140625 +5136 0.146392822265625 +5137 0.406707763671875 +5138 0.14984130859375 +5139 0.416259765625 +5140 0.15325927734375 +5141 0.425750732421875 +5142 0.156646728515625 +5143 0.435211181640625 +5144 0.1600341796875 +5145 0.444610595703125 +5146 0.16339111328125 +5147 0.453948974609375 +5148 0.166748046875 +5149 0.4632568359375 +5150 0.17010498046875 +5151 0.4725341796875 +5152 0.17340087890625 +5153 0.481719970703125 +5154 0.17669677734375 +5155 0.490875244140625 +5156 0.179962158203125 +5157 0.499969482421875 +5158 0.1832275390625 +5159 0.509002685546875 +5160 0.18646240234375 +5161 0.51800537109375 +5162 0.189666748046875 +5163 0.52691650390625 +5164 0.19287109375 +5165 0.535797119140625 +5166 0.196044921875 +5167 0.54461669921875 +5168 0.199188232421875 +5169 0.5533447265625 +5170 0.20233154296875 +5171 0.562042236328125 +5172 0.205413818359375 +5173 0.5706787109375 +5174 0.208526611328125 +5175 0.579254150390625 +5176 0.211578369140625 +5177 0.587738037109375 +5178 0.214599609375 +5179 0.59619140625 +5180 0.217620849609375 +5181 0.60455322265625 +5182 0.220611572265625 +5183 0.612884521484375 +5184 0.223602294921875 +5185 0.621124267578125 +5186 0.226531982421875 +5187 0.6292724609375 +5188 0.22943115234375 +5189 0.63739013671875 +5190 0.232330322265625 +5191 0.645416259765625 +5192 0.235198974609375 +5193 0.65338134765625 +5194 0.238037109375 +5195 0.661285400390625 +5196 0.2408447265625 +5197 0.669097900390625 +5198 0.24365234375 +5199 0.676849365234375 +5200 0.24639892578125 +5201 0.68450927734375 +5202 0.2491455078125 +5203 0.692108154296875 +5204 0.2518310546875 +5205 0.699615478515625 +5206 0.2545166015625 +5207 0.707061767578125 +5208 0.257171630859375 +5209 0.714447021484375 +5210 0.259796142578125 +5211 0.721710205078125 +5212 0.26239013671875 +5213 0.72894287109375 +5214 0.26495361328125 +5215 0.736053466796875 +5216 0.267486572265625 +5217 0.74310302734375 +5218 0.269989013671875 +5219 0.75006103515625 +5220 0.272491455078125 +5221 0.7569580078125 +5222 0.274932861328125 +5223 0.763763427734375 +5224 0.27734375 +5225 0.770477294921875 +5226 0.27972412109375 +5227 0.777099609375 +5228 0.2821044921875 +5229 0.783660888671875 +5230 0.284423828125 +5231 0.790130615234375 +5232 0.286712646484375 +5233 0.796478271484375 +5234 0.288970947265625 +5235 0.802764892578125 +5236 0.291229248046875 +5237 0.808990478515625 +5238 0.293426513671875 +5239 0.815093994140625 +5240 0.29559326171875 +5241 0.82110595703125 +5242 0.297698974609375 +5243 0.8270263671875 +5244 0.299835205078125 +5245 0.8328857421875 +5246 0.3018798828125 +5247 0.838623046875 +5248 0.303924560546875 +5249 0.84429931640625 +5250 0.305938720703125 +5251 0.849853515625 +5252 0.307891845703125 +5253 0.855316162109375 +5254 0.309814453125 +5255 0.860687255859375 +5256 0.311737060546875 +5257 0.865997314453125 +5258 0.3135986328125 +5259 0.871185302734375 +5260 0.3154296875 +5261 0.876251220703125 +5262 0.317230224609375 +5263 0.881256103515625 +5264 0.319000244140625 +5265 0.88616943359375 +5266 0.32073974609375 +5267 0.890960693359375 +5268 0.322418212890625 +5269 0.895660400390625 +5270 0.324066162109375 +5271 0.9002685546875 +5272 0.325714111328125 +5273 0.90478515625 +5274 0.327301025390625 +5275 0.9091796875 +5276 0.328857421875 +5277 0.91351318359375 +5278 0.330352783203125 +5279 0.917724609375 +5280 0.33184814453125 +5281 0.92181396484375 +5282 0.333282470703125 +5283 0.92584228515625 +5284 0.334686279296875 +5285 0.929718017578125 +5286 0.3360595703125 +5287 0.93353271484375 +5288 0.337371826171875 +5289 0.937225341796875 +5290 0.33868408203125 +5291 0.940826416015625 +5292 0.339935302734375 +5293 0.9443359375 +5294 0.341156005859375 +5295 0.947723388671875 +5296 0.34234619140625 +5297 0.951019287109375 +5298 0.343505859375 +5299 0.954193115234375 +5300 0.3446044921875 +5301 0.957275390625 +5302 0.345672607421875 +5303 0.960235595703125 +5304 0.346710205078125 +5305 0.963104248046875 +5306 0.347686767578125 +5307 0.96588134765625 +5308 0.348663330078125 +5309 0.968536376953125 +5310 0.349578857421875 +5311 0.971099853515625 +5312 0.3504638671875 +5313 0.973541259765625 +5314 0.351287841796875 +5315 0.975860595703125 +5316 0.352081298828125 +5317 0.97808837890625 +5318 0.352874755859375 +5319 0.980224609375 +5320 0.35357666015625 +5321 0.98223876953125 +5322 0.354278564453125 +5323 0.984161376953125 +5324 0.35491943359375 +5325 0.9859619140625 +5326 0.35552978515625 +5327 0.987640380859375 +5328 0.356109619140625 +5329 0.989227294921875 +5330 0.35662841796875 +5331 0.990692138671875 +5332 0.35711669921875 +5333 0.9920654296875 +5334 0.357574462890625 +5335 0.993316650390625 +5336 0.358001708984375 +5337 0.994476318359375 +5338 0.358367919921875 +5339 0.995513916015625 +5340 0.35870361328125 +5341 0.9964599609375 +5342 0.3590087890625 +5343 0.997283935546875 +5344 0.3592529296875 +5345 0.99798583984375 +5346 0.359466552734375 +5347 0.99859619140625 +5348 0.359649658203125 +5349 0.999114990234375 +5350 0.359771728515625 +5351 0.999481201171875 +5352 0.359893798828125 +5353 0.999755859375 +5354 0.359954833984375 +5355 0.99993896484375 +5356 0.3599853515625 +5357 0.999969482421875 +5358 0.359954833984375 +5359 0.99993896484375 +5360 0.359893798828125 +5361 0.999755859375 +5362 0.359771728515625 +5363 0.999481201171875 +5364 0.359649658203125 +5365 0.999114990234375 +5366 0.359466552734375 +5367 0.99859619140625 +5368 0.3592529296875 +5369 0.99798583984375 +5370 0.3590087890625 +5371 0.997283935546875 +5372 0.35870361328125 +5373 0.9964599609375 +5374 0.358367919921875 +5375 0.995513916015625 +5376 0.326171875 +5377 0.994476318359375 +5378 0.3258056640625 +5379 0.993316650390625 +5380 0.325408935546875 +5381 0.9920654296875 +5382 0.324951171875 +5383 0.990692138671875 +5384 0.324462890625 +5385 0.989227294921875 +5386 0.323944091796875 +5387 0.987640380859375 +5388 0.323394775390625 +5389 0.9859619140625 +5390 0.32281494140625 +5391 0.984161376953125 +5392 0.322174072265625 +5393 0.98223876953125 +5394 0.321502685546875 +5395 0.980224609375 +5396 0.32080078125 +5397 0.97808837890625 +5398 0.320068359375 +5399 0.975860595703125 +5400 0.319305419921875 +5401 0.973541259765625 +5402 0.318511962890625 +5403 0.971099853515625 +5404 0.31768798828125 +5405 0.968536376953125 +5406 0.316802978515625 +5407 0.96588134765625 +5408 0.315887451171875 +5409 0.963104248046875 +5410 0.31494140625 +5411 0.960235595703125 +5412 0.313995361328125 +5413 0.957275390625 +5414 0.312957763671875 +5415 0.954193115234375 +5416 0.311920166015625 +5417 0.951019287109375 +5418 0.31085205078125 +5419 0.947723388671875 +5420 0.30975341796875 +5421 0.9443359375 +5422 0.30859375 +5423 0.940826416015625 +5424 0.307403564453125 +5425 0.937225341796875 +5426 0.306182861328125 +5427 0.93353271484375 +5428 0.304931640625 +5429 0.929718017578125 +5430 0.303680419921875 +5431 0.92584228515625 +5432 0.302337646484375 +5433 0.92181396484375 +5434 0.301025390625 +5435 0.917724609375 +5436 0.29962158203125 +5437 0.91351318359375 +5438 0.2982177734375 +5439 0.9091796875 +5440 0.2967529296875 +5441 0.90478515625 +5442 0.2952880859375 +5443 0.9002685546875 +5444 0.29376220703125 +5445 0.895660400390625 +5446 0.292236328125 +5447 0.890960693359375 +5448 0.2906494140625 +5449 0.88616943359375 +5450 0.2890625 +5451 0.881256103515625 +5452 0.28741455078125 +5453 0.876251220703125 +5454 0.285736083984375 +5455 0.871185302734375 +5456 0.2840576171875 +5457 0.865997314453125 +5458 0.28228759765625 +5459 0.860687255859375 +5460 0.280548095703125 +5461 0.855316162109375 +5462 0.27874755859375 +5463 0.849853515625 +5464 0.27691650390625 +5465 0.84429931640625 +5466 0.275054931640625 +5467 0.838623046875 +5468 0.273193359375 +5469 0.8328857421875 +5470 0.271270751953125 +5471 0.8270263671875 +5472 0.269317626953125 +5473 0.82110595703125 +5474 0.267333984375 +5475 0.815093994140625 +5476 0.265350341796875 +5477 0.808990478515625 +5478 0.2633056640625 +5479 0.802764892578125 +5480 0.26123046875 +5481 0.796478271484375 +5482 0.2591552734375 +5483 0.790130615234375 +5484 0.257049560546875 +5485 0.783660888671875 +5486 0.2548828125 +5487 0.777099609375 +5488 0.252716064453125 +5489 0.770477294921875 +5490 0.250518798828125 +5491 0.763763427734375 +5492 0.248291015625 +5493 0.7569580078125 +5494 0.246002197265625 +5495 0.75006103515625 +5496 0.243743896484375 +5497 0.74310302734375 +5498 0.241424560546875 +5499 0.736053466796875 +5500 0.23907470703125 +5501 0.72894287109375 +5502 0.236724853515625 +5503 0.721710205078125 +5504 0.234344482421875 +5505 0.714447021484375 +5506 0.231903076171875 +5507 0.707061767578125 +5508 0.229461669921875 +5509 0.699615478515625 +5510 0.227020263671875 +5511 0.692108154296875 +5512 0.224517822265625 +5513 0.68450927734375 +5514 0.22198486328125 +5515 0.676849365234375 +5516 0.219451904296875 +5517 0.669097900390625 +5518 0.216888427734375 +5519 0.661285400390625 +5520 0.21429443359375 +5521 0.65338134765625 +5522 0.211700439453125 +5523 0.645416259765625 +5524 0.20904541015625 +5525 0.63739013671875 +5526 0.206390380859375 +5527 0.6292724609375 +5528 0.2037353515625 +5529 0.621124267578125 +5530 0.201019287109375 +5531 0.612884521484375 +5532 0.198272705078125 +5533 0.60455322265625 +5534 0.195556640625 +5535 0.59619140625 +5536 0.192779541015625 +5537 0.587738037109375 +5538 0.19000244140625 +5539 0.579254150390625 +5540 0.187164306640625 +5541 0.5706787109375 +5542 0.184356689453125 +5543 0.562042236328125 +5544 0.181488037109375 +5545 0.5533447265625 +5546 0.178619384765625 +5547 0.54461669921875 +5548 0.17572021484375 +5549 0.535797119140625 +5550 0.172821044921875 +5551 0.52691650390625 +5552 0.169891357421875 +5553 0.51800537109375 +5554 0.16693115234375 +5555 0.509002685546875 +5556 0.163970947265625 +5557 0.499969482421875 +5558 0.1610107421875 +5559 0.490875244140625 +5560 0.157989501953125 +5561 0.481719970703125 +5562 0.15496826171875 +5563 0.4725341796875 +5564 0.151947021484375 +5565 0.4632568359375 +5566 0.148895263671875 +5567 0.453948974609375 +5568 0.14581298828125 +5569 0.444610595703125 +5570 0.142730712890625 +5571 0.435211181640625 +5572 0.1396484375 +5573 0.425750732421875 +5574 0.13653564453125 +5575 0.416259765625 +5576 0.133392333984375 +5577 0.406707763671875 +5578 0.1302490234375 +5579 0.397125244140625 +5580 0.1270751953125 +5581 0.387481689453125 +5582 0.1239013671875 +5583 0.3778076171875 +5584 0.1207275390625 +5585 0.36810302734375 +5586 0.117523193359375 +5587 0.35833740234375 +5588 0.11431884765625 +5589 0.348541259765625 +5590 0.111083984375 +5591 0.338714599609375 +5592 0.10784912109375 +5593 0.328826904296875 +5594 0.1046142578125 +5595 0.318939208984375 +5596 0.101348876953125 +5597 0.308990478515625 +5598 0.098052978515625 +5599 0.29901123046875 +5600 0.09478759765625 +5601 0.28900146484375 +5602 0.09149169921875 +5603 0.278961181640625 +5604 0.08819580078125 +5605 0.268890380859375 +5606 0.084869384765625 +5607 0.2587890625 +5608 0.08154296875 +5609 0.2486572265625 +5610 0.078216552734375 +5611 0.238525390625 +5612 0.07489013671875 +5613 0.22833251953125 +5614 0.071533203125 +5615 0.218109130859375 +5616 0.06817626953125 +5617 0.2078857421875 +5618 0.0648193359375 +5619 0.1976318359375 +5620 0.061431884765625 +5621 0.187347412109375 +5622 0.058074951171875 +5623 0.17706298828125 +5624 0.0546875 +5625 0.166748046875 +5626 0.051300048828125 +5627 0.156402587890625 +5628 0.047882080078125 +5629 0.14605712890625 +5630 0.04449462890625 +5631 0.13568115234375 +5632 0.037078857421875 +5633 0.12530517578125 +5634 0.03399658203125 +5635 0.11492919921875 +5636 0.030914306640625 +5637 0.104522705078125 +5638 0.02783203125 +5639 0.094085693359375 +5640 0.024749755859375 +5641 0.083648681640625 +5642 0.02166748046875 +5643 0.073211669921875 +5644 0.0185546875 +5645 0.062774658203125 +5646 0.015472412109375 +5647 0.05230712890625 +5648 0.01239013671875 +5649 0.0418701171875 +5650 0.00927734375 +5651 0.031402587890625 +5652 0.006195068359375 +5653 0.02093505859375 +5654 0.003082275390625 +5655 0.010467529296875 +5656 0.0 +5657 0.0 +5658 -0.003082275390625 +5659 -0.010467529296875 +5660 -0.006195068359375 +5661 -0.02093505859375 +5662 -0.00927734375 +5663 -0.031402587890625 +5664 -0.01239013671875 +5665 -0.0418701171875 +5666 -0.015472412109375 +5667 -0.05230712890625 +5668 -0.0185546875 +5669 -0.062774658203125 +5670 -0.02166748046875 +5671 -0.073211669921875 +5672 -0.024749755859375 +5673 -0.083648681640625 +5674 -0.02783203125 +5675 -0.094085693359375 +5676 -0.030914306640625 +5677 -0.104522705078125 +5678 -0.03399658203125 +5679 -0.11492919921875 +5680 -0.037078857421875 +5681 -0.12530517578125 +5682 -0.0401611328125 +5683 -0.13568115234375 +5684 -0.043212890625 +5685 -0.14605712890625 +5686 -0.0462646484375 +5687 -0.156402587890625 +5688 -0.049346923828125 +5689 -0.166748046875 +5690 -0.052398681640625 +5691 -0.17706298828125 +5692 -0.055450439453125 +5693 -0.187347412109375 +5694 -0.0584716796875 +5695 -0.1976318359375 +5696 -0.0615234375 +5697 -0.2078857421875 +5698 -0.064544677734375 +5699 -0.218109130859375 +5700 -0.06756591796875 +5701 -0.22833251953125 +5702 -0.070587158203125 +5703 -0.238525390625 +5704 -0.073577880859375 +5705 -0.2486572265625 +5706 -0.07659912109375 +5707 -0.2587890625 +5708 -0.07958984375 +5709 -0.268890380859375 +5710 -0.082550048828125 +5711 -0.278961181640625 +5712 -0.085540771484375 +5713 -0.28900146484375 +5714 -0.0885009765625 +5715 -0.29901123046875 +5716 -0.0914306640625 +5717 -0.308990478515625 +5718 -0.094390869140625 +5719 -0.318939208984375 +5720 -0.097320556640625 +5721 -0.328826904296875 +5722 -0.100250244140625 +5723 -0.338714599609375 +5724 -0.1031494140625 +5725 -0.348541259765625 +5726 -0.106048583984375 +5727 -0.35833740234375 +5728 -0.10894775390625 +5729 -0.36810302734375 +5730 -0.11181640625 +5731 -0.3778076171875 +5732 -0.11468505859375 +5733 -0.387481689453125 +5734 -0.117523193359375 +5735 -0.397125244140625 +5736 -0.120361328125 +5737 -0.406707763671875 +5738 -0.123199462890625 +5739 -0.416259765625 +5740 -0.126007080078125 +5741 -0.425750732421875 +5742 -0.128814697265625 +5743 -0.435211181640625 +5744 -0.131591796875 +5745 -0.444610595703125 +5746 -0.13433837890625 +5747 -0.453948974609375 +5748 -0.137115478515625 +5749 -0.4632568359375 +5750 -0.139862060546875 +5751 -0.4725341796875 +5752 -0.142578125 +5753 -0.481719970703125 +5754 -0.145294189453125 +5755 -0.490875244140625 +5756 -0.147979736328125 +5757 -0.499969482421875 +5758 -0.150634765625 +5759 -0.509002685546875 +5760 -0.1533203125 +5761 -0.51800537109375 +5762 -0.15594482421875 +5763 -0.52691650390625 +5764 -0.1585693359375 +5765 -0.535797119140625 +5766 -0.16119384765625 +5767 -0.54461669921875 +5768 -0.163787841796875 +5769 -0.5533447265625 +5770 -0.166351318359375 +5771 -0.562042236328125 +5772 -0.168914794921875 +5773 -0.5706787109375 +5774 -0.17144775390625 +5775 -0.579254150390625 +5776 -0.1739501953125 +5777 -0.587738037109375 +5778 -0.17645263671875 +5779 -0.59619140625 +5780 -0.178924560546875 +5781 -0.60455322265625 +5782 -0.181396484375 +5783 -0.612884521484375 +5784 -0.183837890625 +5785 -0.621124267578125 +5786 -0.186248779296875 +5787 -0.6292724609375 +5788 -0.18865966796875 +5789 -0.63739013671875 +5790 -0.1910400390625 +5791 -0.645416259765625 +5792 -0.193389892578125 +5793 -0.65338134765625 +5794 -0.19573974609375 +5795 -0.661285400390625 +5796 -0.198028564453125 +5797 -0.669097900390625 +5798 -0.2003173828125 +5799 -0.676849365234375 +5800 -0.202606201171875 +5801 -0.68450927734375 +5802 -0.204833984375 +5803 -0.692108154296875 +5804 -0.207061767578125 +5805 -0.699615478515625 +5806 -0.20928955078125 +5807 -0.707061767578125 +5808 -0.211456298828125 +5809 -0.714447021484375 +5810 -0.213623046875 +5811 -0.721710205078125 +5812 -0.21575927734375 +5813 -0.72894287109375 +5814 -0.217864990234375 +5815 -0.736053466796875 +5816 -0.219940185546875 +5817 -0.74310302734375 +5818 -0.222015380859375 +5819 -0.75006103515625 +5820 -0.224029541015625 +5821 -0.7569580078125 +5822 -0.226043701171875 +5823 -0.763763427734375 +5824 -0.228057861328125 +5825 -0.770477294921875 +5826 -0.230010986328125 +5827 -0.777099609375 +5828 -0.23193359375 +5829 -0.783660888671875 +5830 -0.233856201171875 +5831 -0.790130615234375 +5832 -0.235748291015625 +5833 -0.796478271484375 +5834 -0.23760986328125 +5835 -0.802764892578125 +5836 -0.23944091796875 +5837 -0.808990478515625 +5838 -0.241241455078125 +5839 -0.815093994140625 +5840 -0.2430419921875 +5841 -0.82110595703125 +5842 -0.244781494140625 +5843 -0.8270263671875 +5844 -0.24652099609375 +5845 -0.8328857421875 +5846 -0.24822998046875 +5847 -0.838623046875 +5848 -0.249908447265625 +5849 -0.84429931640625 +5850 -0.25152587890625 +5851 -0.849853515625 +5852 -0.253143310546875 +5853 -0.855316162109375 +5854 -0.2547607421875 +5855 -0.860687255859375 +5856 -0.256317138671875 +5857 -0.865997314453125 +5858 -0.257843017578125 +5859 -0.871185302734375 +5860 -0.259368896484375 +5861 -0.876251220703125 +5862 -0.260833740234375 +5863 -0.881256103515625 +5864 -0.262298583984375 +5865 -0.88616943359375 +5866 -0.263702392578125 +5867 -0.890960693359375 +5868 -0.265106201171875 +5869 -0.895660400390625 +5870 -0.266448974609375 +5871 -0.9002685546875 +5872 -0.267791748046875 +5873 -0.90478515625 +5874 -0.26910400390625 +5875 -0.9091796875 +5876 -0.2703857421875 +5877 -0.91351318359375 +5878 -0.271636962890625 +5879 -0.917724609375 +5880 -0.2728271484375 +5881 -0.92181396484375 +5882 -0.2740478515625 +5883 -0.92584228515625 +5884 -0.275177001953125 +5885 -0.929718017578125 +5886 -0.27630615234375 +5887 -0.93353271484375 +5888 -0.247406005859375 +5889 -0.937225341796875 +5890 -0.24835205078125 +5891 -0.940826416015625 +5892 -0.249267578125 +5893 -0.9443359375 +5894 -0.25018310546875 +5895 -0.947723388671875 +5896 -0.25103759765625 +5897 -0.951019287109375 +5898 -0.25189208984375 +5899 -0.954193115234375 +5900 -0.252685546875 +5901 -0.957275390625 +5902 -0.25347900390625 +5903 -0.960235595703125 +5904 -0.254241943359375 +5905 -0.963104248046875 +5906 -0.254974365234375 +5907 -0.96588134765625 +5908 -0.25567626953125 +5909 -0.968536376953125 +5910 -0.25634765625 +5911 -0.971099853515625 +5912 -0.256988525390625 +5913 -0.973541259765625 +5914 -0.257598876953125 +5915 -0.975860595703125 +5916 -0.2581787109375 +5917 -0.97808837890625 +5918 -0.258758544921875 +5919 -0.980224609375 +5920 -0.25927734375 +5921 -0.98223876953125 +5922 -0.259796142578125 +5923 -0.984161376953125 +5924 -0.26025390625 +5925 -0.9859619140625 +5926 -0.260711669921875 +5927 -0.987640380859375 +5928 -0.261138916015625 +5929 -0.989227294921875 +5930 -0.261505126953125 +5931 -0.990692138671875 +5932 -0.261871337890625 +5933 -0.9920654296875 +5934 -0.26220703125 +5935 -0.993316650390625 +5936 -0.26251220703125 +5937 -0.994476318359375 +5938 -0.262786865234375 +5939 -0.995513916015625 +5940 -0.263031005859375 +5941 -0.9964599609375 +5942 -0.26324462890625 +5943 -0.997283935546875 +5944 -0.263427734375 +5945 -0.99798583984375 +5946 -0.26361083984375 +5947 -0.99859619140625 +5948 -0.26373291015625 +5949 -0.999114990234375 +5950 -0.263824462890625 +5951 -0.999481201171875 +5952 -0.263885498046875 +5953 -0.999755859375 +5954 -0.263946533203125 +5955 -0.99993896484375 +5956 -0.26397705078125 +5957 -1.0 +5958 -0.263946533203125 +5959 -0.99993896484375 +5960 -0.263885498046875 +5961 -0.999755859375 +5962 -0.263824462890625 +5963 -0.999481201171875 +5964 -0.26373291015625 +5965 -0.999114990234375 +5966 -0.26361083984375 +5967 -0.99859619140625 +5968 -0.263427734375 +5969 -0.99798583984375 +5970 -0.26324462890625 +5971 -0.997283935546875 +5972 -0.263031005859375 +5973 -0.9964599609375 +5974 -0.262786865234375 +5975 -0.995513916015625 +5976 -0.26251220703125 +5977 -0.994476318359375 +5978 -0.26220703125 +5979 -0.993316650390625 +5980 -0.261871337890625 +5981 -0.9920654296875 +5982 -0.261505126953125 +5983 -0.990692138671875 +5984 -0.261138916015625 +5985 -0.989227294921875 +5986 -0.260711669921875 +5987 -0.987640380859375 +5988 -0.26025390625 +5989 -0.9859619140625 +5990 -0.259796142578125 +5991 -0.984161376953125 +5992 -0.25927734375 +5993 -0.98223876953125 +5994 -0.258758544921875 +5995 -0.980224609375 +5996 -0.2581787109375 +5997 -0.97808837890625 +5998 -0.257598876953125 +5999 -0.975860595703125 +6000 -0.256988525390625 +6001 -0.973541259765625 +6002 -0.25634765625 +6003 -0.971099853515625 +6004 -0.25567626953125 +6005 -0.968536376953125 +6006 -0.254974365234375 +6007 -0.96588134765625 +6008 -0.254241943359375 +6009 -0.963104248046875 +6010 -0.25347900390625 +6011 -0.960235595703125 +6012 -0.252685546875 +6013 -0.957275390625 +6014 -0.25189208984375 +6015 -0.954193115234375 +6016 -0.25103759765625 +6017 -0.951019287109375 +6018 -0.25018310546875 +6019 -0.947723388671875 +6020 -0.249267578125 +6021 -0.9443359375 +6022 -0.24835205078125 +6023 -0.940826416015625 +6024 -0.247406005859375 +6025 -0.937225341796875 +6026 -0.246429443359375 +6027 -0.93353271484375 +6028 -0.24542236328125 +6029 -0.929718017578125 +6030 -0.244384765625 +6031 -0.92584228515625 +6032 -0.243316650390625 +6033 -0.92181396484375 +6034 -0.24224853515625 +6035 -0.917724609375 +6036 -0.24114990234375 +6037 -0.91351318359375 +6038 -0.239990234375 +6039 -0.9091796875 +6040 -0.23883056640625 +6041 -0.90478515625 +6042 -0.237640380859375 +6043 -0.9002685546875 +6044 -0.236419677734375 +6045 -0.895660400390625 +6046 -0.235198974609375 +6047 -0.890960693359375 +6048 -0.233917236328125 +6049 -0.88616943359375 +6050 -0.232635498046875 +6051 -0.881256103515625 +6052 -0.231292724609375 +6053 -0.876251220703125 +6054 -0.229949951171875 +6055 -0.871185302734375 +6056 -0.228607177734375 +6057 -0.865997314453125 +6058 -0.227203369140625 +6059 -0.860687255859375 +6060 -0.22576904296875 +6061 -0.855316162109375 +6062 -0.224334716796875 +6063 -0.849853515625 +6064 -0.222869873046875 +6065 -0.84429931640625 +6066 -0.22137451171875 +6067 -0.838623046875 +6068 -0.2198486328125 +6069 -0.8328857421875 +6070 -0.218292236328125 +6071 -0.8270263671875 +6072 -0.21673583984375 +6073 -0.82110595703125 +6074 -0.21514892578125 +6075 -0.815093994140625 +6076 -0.213531494140625 +6077 -0.808990478515625 +6078 -0.2119140625 +6079 -0.802764892578125 +6080 -0.210235595703125 +6081 -0.796478271484375 +6082 -0.20855712890625 +6083 -0.790130615234375 +6084 -0.20684814453125 +6085 -0.783660888671875 +6086 -0.20513916015625 +6087 -0.777099609375 +6088 -0.203369140625 +6089 -0.770477294921875 +6090 -0.20159912109375 +6091 -0.763763427734375 +6092 -0.199798583984375 +6093 -0.7569580078125 +6094 -0.197998046875 +6095 -0.75006103515625 +6096 -0.1961669921875 +6097 -0.74310302734375 +6098 -0.194305419921875 +6099 -0.736053466796875 +6100 -0.192413330078125 +6101 -0.72894287109375 +6102 -0.19049072265625 +6103 -0.721710205078125 +6104 -0.1885986328125 +6105 -0.714447021484375 +6106 -0.1866455078125 +6107 -0.707061767578125 +6108 -0.184661865234375 +6109 -0.699615478515625 +6110 -0.18267822265625 +6111 -0.692108154296875 +6112 -0.180694580078125 +6113 -0.68450927734375 +6114 -0.17864990234375 +6115 -0.676849365234375 +6116 -0.176605224609375 +6117 -0.669097900390625 +6118 -0.174560546875 +6119 -0.661285400390625 +6120 -0.172454833984375 +6121 -0.65338134765625 +6122 -0.170379638671875 +6123 -0.645416259765625 +6124 -0.168243408203125 +6125 -0.63739013671875 +6126 -0.166107177734375 +6127 -0.6292724609375 +6128 -0.1639404296875 +6129 -0.621124267578125 +6130 -0.161773681640625 +6131 -0.612884521484375 +6132 -0.159576416015625 +6133 -0.60455322265625 +6134 -0.157379150390625 +6135 -0.59619140625 +6136 -0.1551513671875 +6137 -0.587738037109375 +6138 -0.15289306640625 +6139 -0.579254150390625 +6140 -0.150634765625 +6141 -0.5706787109375 +6142 -0.148345947265625 +6143 -0.562042236328125 +6144 -0.138336181640625 +6145 -0.5533447265625 +6146 -0.136138916015625 +6147 -0.54461669921875 +6148 -0.133941650390625 +6149 -0.535797119140625 +6150 -0.1317138671875 +6151 -0.52691650390625 +6152 -0.129486083984375 +6153 -0.51800537109375 +6154 -0.127227783203125 +6155 -0.509002685546875 +6156 -0.124969482421875 +6157 -0.499969482421875 +6158 -0.122711181640625 +6159 -0.490875244140625 +6160 -0.12042236328125 +6161 -0.481719970703125 +6162 -0.118133544921875 +6163 -0.4725341796875 +6164 -0.115814208984375 +6165 -0.4632568359375 +6166 -0.11346435546875 +6167 -0.453948974609375 +6168 -0.11114501953125 +6169 -0.444610595703125 +6170 -0.108795166015625 +6171 -0.435211181640625 +6172 -0.106414794921875 +6173 -0.425750732421875 +6174 -0.10406494140625 +6175 -0.416259765625 +6176 -0.101654052734375 +6177 -0.406707763671875 +6178 -0.099273681640625 +6179 -0.397125244140625 +6180 -0.09686279296875 +6181 -0.387481689453125 +6182 -0.094451904296875 +6183 -0.3778076171875 +6184 -0.092010498046875 +6185 -0.36810302734375 +6186 -0.089569091796875 +6187 -0.35833740234375 +6188 -0.087127685546875 +6189 -0.348541259765625 +6190 -0.08465576171875 +6191 -0.338714599609375 +6192 -0.082183837890625 +6193 -0.328826904296875 +6194 -0.0797119140625 +6195 -0.318939208984375 +6196 -0.077239990234375 +6197 -0.308990478515625 +6198 -0.074737548828125 +6199 -0.29901123046875 +6200 -0.072235107421875 +6201 -0.28900146484375 +6202 -0.069732666015625 +6203 -0.278961181640625 +6204 -0.06719970703125 +6205 -0.268890380859375 +6206 -0.064697265625 +6207 -0.2587890625 +6208 -0.062164306640625 +6209 -0.2486572265625 +6210 -0.05963134765625 +6211 -0.238525390625 +6212 -0.05706787109375 +6213 -0.22833251953125 +6214 -0.05450439453125 +6215 -0.218109130859375 +6216 -0.051971435546875 +6217 -0.2078857421875 +6218 -0.049407958984375 +6219 -0.1976318359375 +6220 -0.04681396484375 +6221 -0.187347412109375 +6222 -0.04425048828125 +6223 -0.17706298828125 +6224 -0.04168701171875 +6225 -0.166748046875 +6226 -0.039093017578125 +6227 -0.156402587890625 +6228 -0.0364990234375 +6229 -0.14605712890625 +6230 -0.033905029296875 +6231 -0.13568115234375 +6232 -0.03131103515625 +6233 -0.12530517578125 +6234 -0.028717041015625 +6235 -0.11492919921875 +6236 -0.026123046875 +6237 -0.104522705078125 +6238 -0.02349853515625 +6239 -0.094085693359375 +6240 -0.020904541015625 +6241 -0.083648681640625 +6242 -0.018280029296875 +6243 -0.073211669921875 +6244 -0.01568603515625 +6245 -0.062774658203125 +6246 -0.0130615234375 +6247 -0.05230712890625 +6248 -0.010467529296875 +6249 -0.0418701171875 +6250 -0.007843017578125 +6251 -0.031402587890625 +6252 -0.005218505859375 +6253 -0.02093505859375 +6254 -0.002593994140625 +6255 -0.010467529296875 +6256 0.0 +6257 0.0 +6258 0.002410888671875 +6259 0.010467529296875 +6260 0.004852294921875 +6261 0.02093505859375 +6262 0.00726318359375 +6263 0.031402587890625 +6264 0.00970458984375 +6265 0.0418701171875 +6266 0.012115478515625 +6267 0.05230712890625 +6268 0.014556884765625 +6269 0.062774658203125 +6270 0.0169677734375 +6271 0.073211669921875 +6272 0.019378662109375 +6273 0.083648681640625 +6274 0.021820068359375 +6275 0.094085693359375 +6276 0.02423095703125 +6277 0.104522705078125 +6278 0.026641845703125 +6279 0.11492919921875 +6280 0.029052734375 +6281 0.12530517578125 +6282 0.031463623046875 +6283 0.13568115234375 +6284 0.03387451171875 +6285 0.14605712890625 +6286 0.036285400390625 +6287 0.156402587890625 +6288 0.038665771484375 +6289 0.166748046875 +6290 0.04107666015625 +6291 0.17706298828125 +6292 0.04345703125 +6293 0.187347412109375 +6294 0.04583740234375 +6295 0.1976318359375 +6296 0.0482177734375 +6297 0.2078857421875 +6298 0.05059814453125 +6299 0.218109130859375 +6300 0.052947998046875 +6301 0.22833251953125 +6302 0.055328369140625 +6303 0.238525390625 +6304 0.05767822265625 +6305 0.2486572265625 +6306 0.060028076171875 +6307 0.2587890625 +6308 0.0623779296875 +6309 0.268890380859375 +6310 0.064697265625 +6311 0.278961181640625 +6312 0.067047119140625 +6313 0.28900146484375 +6314 0.069366455078125 +6315 0.29901123046875 +6316 0.071685791015625 +6317 0.308990478515625 +6318 0.073974609375 +6319 0.318939208984375 +6320 0.076263427734375 +6321 0.328826904296875 +6322 0.07855224609375 +6323 0.338714599609375 +6324 0.080841064453125 +6325 0.348541259765625 +6326 0.0831298828125 +6327 0.35833740234375 +6328 0.08538818359375 +6329 0.36810302734375 +6330 0.087646484375 +6331 0.3778076171875 +6332 0.089874267578125 +6333 0.387481689453125 +6334 0.092132568359375 +6335 0.397125244140625 +6336 0.094329833984375 +6337 0.406707763671875 +6338 0.0965576171875 +6339 0.416259765625 +6340 0.0987548828125 +6341 0.425750732421875 +6342 0.1009521484375 +6343 0.435211181640625 +6344 0.1031494140625 +6345 0.444610595703125 +6346 0.105316162109375 +6347 0.453948974609375 +6348 0.107452392578125 +6349 0.4632568359375 +6350 0.109619140625 +6351 0.4725341796875 +6352 0.11175537109375 +6353 0.481719970703125 +6354 0.113861083984375 +6355 0.490875244140625 +6356 0.115966796875 +6357 0.499969482421875 +6358 0.118072509765625 +6359 0.509002685546875 +6360 0.120147705078125 +6361 0.51800537109375 +6362 0.122222900390625 +6363 0.52691650390625 +6364 0.124298095703125 +6365 0.535797119140625 +6366 0.1263427734375 +6367 0.54461669921875 +6368 0.12835693359375 +6369 0.5533447265625 +6370 0.13037109375 +6371 0.562042236328125 +6372 0.13238525390625 +6373 0.5706787109375 +6374 0.134368896484375 +6375 0.579254150390625 +6376 0.1363525390625 +6377 0.587738037109375 +6378 0.1383056640625 +6379 0.59619140625 +6380 0.140228271484375 +6381 0.60455322265625 +6382 0.142181396484375 +6383 0.612884521484375 +6384 0.144073486328125 +6385 0.621124267578125 +6386 0.145965576171875 +6387 0.6292724609375 +6388 0.147857666015625 +6389 0.63739013671875 +6390 0.14971923828125 +6391 0.645416259765625 +6392 0.151580810546875 +6393 0.65338134765625 +6394 0.153411865234375 +6395 0.661285400390625 +6396 0.15521240234375 +6397 0.669097900390625 +6398 0.157012939453125 +6399 0.676849365234375 +6400 0.136871337890625 +6401 0.68450927734375 +6402 0.138397216796875 +6403 0.692108154296875 +6404 0.139892578125 +6405 0.699615478515625 +6406 0.141387939453125 +6407 0.707061767578125 +6408 0.142852783203125 +6409 0.714447021484375 +6410 0.144317626953125 +6411 0.721710205078125 +6412 0.145751953125 +6413 0.72894287109375 +6414 0.147186279296875 +6415 0.736053466796875 +6416 0.148590087890625 +6417 0.74310302734375 +6418 0.149993896484375 +6419 0.75006103515625 +6420 0.1513671875 +6421 0.7569580078125 +6422 0.152740478515625 +6423 0.763763427734375 +6424 0.154083251953125 +6425 0.770477294921875 +6426 0.1553955078125 +6427 0.777099609375 +6428 0.156707763671875 +6429 0.783660888671875 +6430 0.157989501953125 +6431 0.790130615234375 +6432 0.159271240234375 +6433 0.796478271484375 +6434 0.1605224609375 +6435 0.802764892578125 +6436 0.161773681640625 +6437 0.808990478515625 +6438 0.162994384765625 +6439 0.815093994140625 +6440 0.1641845703125 +6441 0.82110595703125 +6442 0.165374755859375 +6443 0.8270263671875 +6444 0.16656494140625 +6445 0.8328857421875 +6446 0.167694091796875 +6447 0.838623046875 +6448 0.1688232421875 +6449 0.84429931640625 +6450 0.169952392578125 +6451 0.849853515625 +6452 0.171051025390625 +6453 0.855316162109375 +6454 0.172119140625 +6455 0.860687255859375 +6456 0.173187255859375 +6457 0.865997314453125 +6458 0.174224853515625 +6459 0.871185302734375 +6460 0.17523193359375 +6461 0.876251220703125 +6462 0.176239013671875 +6463 0.881256103515625 +6464 0.177215576171875 +6465 0.88616943359375 +6466 0.17816162109375 +6467 0.890960693359375 +6468 0.179107666015625 +6469 0.895660400390625 +6470 0.180023193359375 +6471 0.9002685546875 +6472 0.180938720703125 +6473 0.90478515625 +6474 0.18182373046875 +6475 0.9091796875 +6476 0.18267822265625 +6477 0.91351318359375 +6478 0.18353271484375 +6479 0.917724609375 +6480 0.184326171875 +6481 0.92181396484375 +6482 0.185150146484375 +6483 0.92584228515625 +6484 0.1859130859375 +6485 0.929718017578125 +6486 0.186676025390625 +6487 0.93353271484375 +6488 0.187408447265625 +6489 0.937225341796875 +6490 0.188140869140625 +6491 0.940826416015625 +6492 0.1888427734375 +6493 0.9443359375 +6494 0.18951416015625 +6495 0.947723388671875 +6496 0.190185546875 +6497 0.951019287109375 +6498 0.190826416015625 +6499 0.954193115234375 +6500 0.191436767578125 +6501 0.957275390625 +6502 0.1920166015625 +6503 0.960235595703125 +6504 0.192596435546875 +6505 0.963104248046875 +6506 0.193145751953125 +6507 0.96588134765625 +6508 0.193695068359375 +6509 0.968536376953125 +6510 0.194183349609375 +6511 0.971099853515625 +6512 0.194671630859375 +6513 0.973541259765625 +6514 0.195159912109375 +6515 0.975860595703125 +6516 0.195587158203125 +6517 0.97808837890625 +6518 0.196014404296875 +6519 0.980224609375 +6520 0.1964111328125 +6521 0.98223876953125 +6522 0.196807861328125 +6523 0.984161376953125 +6524 0.197174072265625 +6525 0.9859619140625 +6526 0.197509765625 +6527 0.987640380859375 +6528 0.19781494140625 +6529 0.989227294921875 +6530 0.1981201171875 +6531 0.990692138671875 +6532 0.198394775390625 +6533 0.9920654296875 +6534 0.198638916015625 +6535 0.993316650390625 +6536 0.198883056640625 +6537 0.994476318359375 +6538 0.199066162109375 +6539 0.995513916015625 +6540 0.19927978515625 +6541 0.9964599609375 +6542 0.199432373046875 +6543 0.997283935546875 +6544 0.1995849609375 +6545 0.99798583984375 +6546 0.19970703125 +6547 0.99859619140625 +6548 0.199798583984375 +6549 0.999114990234375 +6550 0.199859619140625 +6551 0.999481201171875 +6552 0.199920654296875 +6553 0.999755859375 +6554 0.199951171875 +6555 0.99993896484375 +6556 0.199981689453125 +6557 0.999969482421875 +6558 0.199951171875 +6559 0.99993896484375 +6560 0.199920654296875 +6561 0.999755859375 +6562 0.199859619140625 +6563 0.999481201171875 +6564 0.199798583984375 +6565 0.999114990234375 +6566 0.19970703125 +6567 0.99859619140625 +6568 0.1995849609375 +6569 0.99798583984375 +6570 0.199432373046875 +6571 0.997283935546875 +6572 0.19927978515625 +6573 0.9964599609375 +6574 0.199066162109375 +6575 0.995513916015625 +6576 0.198883056640625 +6577 0.994476318359375 +6578 0.198638916015625 +6579 0.993316650390625 +6580 0.198394775390625 +6581 0.9920654296875 +6582 0.1981201171875 +6583 0.990692138671875 +6584 0.19781494140625 +6585 0.989227294921875 +6586 0.197509765625 +6587 0.987640380859375 +6588 0.197174072265625 +6589 0.9859619140625 +6590 0.196807861328125 +6591 0.984161376953125 +6592 0.1964111328125 +6593 0.98223876953125 +6594 0.196014404296875 +6595 0.980224609375 +6596 0.195587158203125 +6597 0.97808837890625 +6598 0.195159912109375 +6599 0.975860595703125 +6600 0.194671630859375 +6601 0.973541259765625 +6602 0.194183349609375 +6603 0.971099853515625 +6604 0.193695068359375 +6605 0.968536376953125 +6606 0.193145751953125 +6607 0.96588134765625 +6608 0.192596435546875 +6609 0.963104248046875 +6610 0.1920166015625 +6611 0.960235595703125 +6612 0.191436767578125 +6613 0.957275390625 +6614 0.190826416015625 +6615 0.954193115234375 +6616 0.190185546875 +6617 0.951019287109375 +6618 0.18951416015625 +6619 0.947723388671875 +6620 0.1888427734375 +6621 0.9443359375 +6622 0.188140869140625 +6623 0.940826416015625 +6624 0.187408447265625 +6625 0.937225341796875 +6626 0.186676025390625 +6627 0.93353271484375 +6628 0.1859130859375 +6629 0.929718017578125 +6630 0.185150146484375 +6631 0.92584228515625 +6632 0.184326171875 +6633 0.92181396484375 +6634 0.18353271484375 +6635 0.917724609375 +6636 0.18267822265625 +6637 0.91351318359375 +6638 0.18182373046875 +6639 0.9091796875 +6640 0.180938720703125 +6641 0.90478515625 +6642 0.180023193359375 +6643 0.9002685546875 +6644 0.179107666015625 +6645 0.895660400390625 +6646 0.17816162109375 +6647 0.890960693359375 +6648 0.177215576171875 +6649 0.88616943359375 +6650 0.176239013671875 +6651 0.881256103515625 +6652 0.17523193359375 +6653 0.876251220703125 +6654 0.174224853515625 +6655 0.871185302734375 +6656 0.145477294921875 +6657 0.865997314453125 +6658 0.14459228515625 +6659 0.860687255859375 +6660 0.1436767578125 +6661 0.855316162109375 +6662 0.14276123046875 +6663 0.849853515625 +6664 0.141845703125 +6665 0.84429931640625 +6666 0.140869140625 +6667 0.838623046875 +6668 0.139923095703125 +6669 0.8328857421875 +6670 0.138916015625 +6671 0.8270263671875 +6672 0.137939453125 +6673 0.82110595703125 +6674 0.136932373046875 +6675 0.815093994140625 +6676 0.135894775390625 +6677 0.808990478515625 +6678 0.134857177734375 +6679 0.802764892578125 +6680 0.1337890625 +6681 0.796478271484375 +6682 0.132720947265625 +6683 0.790130615234375 +6684 0.13165283203125 +6685 0.783660888671875 +6686 0.13055419921875 +6687 0.777099609375 +6688 0.129425048828125 +6689 0.770477294921875 +6690 0.1282958984375 +6691 0.763763427734375 +6692 0.127166748046875 +6693 0.7569580078125 +6694 0.126007080078125 +6695 0.75006103515625 +6696 0.12481689453125 +6697 0.74310302734375 +6698 0.1236572265625 +6699 0.736053466796875 +6700 0.1224365234375 +6701 0.72894287109375 +6702 0.121246337890625 +6703 0.721710205078125 +6704 0.120025634765625 +6705 0.714447021484375 +6706 0.1187744140625 +6707 0.707061767578125 +6708 0.117523193359375 +6709 0.699615478515625 +6710 0.11627197265625 +6711 0.692108154296875 +6712 0.114990234375 +6713 0.68450927734375 +6714 0.11370849609375 +6715 0.676849365234375 +6716 0.112396240234375 +6717 0.669097900390625 +6718 0.111083984375 +6719 0.661285400390625 +6720 0.1097412109375 +6721 0.65338134765625 +6722 0.108428955078125 +6723 0.645416259765625 +6724 0.1070556640625 +6725 0.63739013671875 +6726 0.105712890625 +6727 0.6292724609375 +6728 0.104339599609375 +6729 0.621124267578125 +6730 0.10296630859375 +6731 0.612884521484375 +6732 0.1015625 +6733 0.60455322265625 +6734 0.10015869140625 +6735 0.59619140625 +6736 0.098724365234375 +6737 0.587738037109375 +6738 0.0972900390625 +6739 0.579254150390625 +6740 0.095855712890625 +6741 0.5706787109375 +6742 0.09442138671875 +6743 0.562042236328125 +6744 0.09295654296875 +6745 0.5533447265625 +6746 0.09149169921875 +6747 0.54461669921875 +6748 0.089996337890625 +6749 0.535797119140625 +6750 0.0885009765625 +6751 0.52691650390625 +6752 0.087005615234375 +6753 0.51800537109375 +6754 0.08551025390625 +6755 0.509002685546875 +6756 0.083984375 +6757 0.499969482421875 +6758 0.08245849609375 +6759 0.490875244140625 +6760 0.080902099609375 +6761 0.481719970703125 +6762 0.079376220703125 +6763 0.4725341796875 +6764 0.07781982421875 +6765 0.4632568359375 +6766 0.076263427734375 +6767 0.453948974609375 +6768 0.074676513671875 +6769 0.444610595703125 +6770 0.073089599609375 +6771 0.435211181640625 +6772 0.071502685546875 +6773 0.425750732421875 +6774 0.069915771484375 +6775 0.416259765625 +6776 0.06829833984375 +6777 0.406707763671875 +6778 0.06671142578125 +6779 0.397125244140625 +6780 0.065093994140625 +6781 0.387481689453125 +6782 0.063446044921875 +6783 0.3778076171875 +6784 0.06182861328125 +6785 0.36810302734375 +6786 0.0601806640625 +6787 0.35833740234375 +6788 0.05853271484375 +6789 0.348541259765625 +6790 0.056884765625 +6791 0.338714599609375 +6792 0.05523681640625 +6793 0.328826904296875 +6794 0.053558349609375 +6795 0.318939208984375 +6796 0.051910400390625 +6797 0.308990478515625 +6798 0.05023193359375 +6799 0.29901123046875 +6800 0.048553466796875 +6801 0.28900146484375 +6802 0.046844482421875 +6803 0.278961181640625 +6804 0.045166015625 +6805 0.268890380859375 +6806 0.04345703125 +6807 0.2587890625 +6808 0.041748046875 +6809 0.2486572265625 +6810 0.040069580078125 +6811 0.238525390625 +6812 0.038360595703125 +6813 0.22833251953125 +6814 0.03662109375 +6815 0.218109130859375 +6816 0.034912109375 +6817 0.2078857421875 +6818 0.033172607421875 +6819 0.1976318359375 +6820 0.031463623046875 +6821 0.187347412109375 +6822 0.02972412109375 +6823 0.17706298828125 +6824 0.027984619140625 +6825 0.166748046875 +6826 0.026275634765625 +6827 0.156402587890625 +6828 0.0245361328125 +6829 0.14605712890625 +6830 0.02276611328125 +6831 0.13568115234375 +6832 0.021026611328125 +6833 0.12530517578125 +6834 0.019287109375 +6835 0.11492919921875 +6836 0.017547607421875 +6837 0.104522705078125 +6838 0.015777587890625 +6839 0.094085693359375 +6840 0.0140380859375 +6841 0.083648681640625 +6842 0.012298583984375 +6843 0.073211669921875 +6844 0.010528564453125 +6845 0.062774658203125 +6846 0.008758544921875 +6847 0.05230712890625 +6848 0.00701904296875 +6849 0.0418701171875 +6850 0.0052490234375 +6851 0.031402587890625 +6852 0.003509521484375 +6853 0.02093505859375 +6854 0.001739501953125 +6855 0.010467529296875 +6856 0.0 +6857 0.0 +6858 -0.001739501953125 +6859 -0.010467529296875 +6860 -0.003509521484375 +6861 -0.02093505859375 +6862 -0.0052490234375 +6863 -0.031402587890625 +6864 -0.00701904296875 +6865 -0.0418701171875 +6866 -0.008758544921875 +6867 -0.05230712890625 +6868 -0.010528564453125 +6869 -0.062774658203125 +6870 -0.012298583984375 +6871 -0.073211669921875 +6872 -0.0140380859375 +6873 -0.083648681640625 +6874 -0.015777587890625 +6875 -0.094085693359375 +6876 -0.017547607421875 +6877 -0.104522705078125 +6878 -0.019287109375 +6879 -0.11492919921875 +6880 -0.021026611328125 +6881 -0.12530517578125 +6882 -0.02276611328125 +6883 -0.13568115234375 +6884 -0.0245361328125 +6885 -0.14605712890625 +6886 -0.026275634765625 +6887 -0.156402587890625 +6888 -0.027984619140625 +6889 -0.166748046875 +6890 -0.02972412109375 +6891 -0.17706298828125 +6892 -0.031463623046875 +6893 -0.187347412109375 +6894 -0.033172607421875 +6895 -0.1976318359375 +6896 -0.034912109375 +6897 -0.2078857421875 +6898 -0.03662109375 +6899 -0.218109130859375 +6900 -0.038360595703125 +6901 -0.22833251953125 +6902 -0.040069580078125 +6903 -0.238525390625 +6904 -0.041748046875 +6905 -0.2486572265625 +6906 -0.04345703125 +6907 -0.2587890625 +6908 -0.045166015625 +6909 -0.268890380859375 +6910 -0.046844482421875 +6911 -0.278961181640625 +6912 -0.039276123046875 +6913 -0.28900146484375 +6914 -0.0406494140625 +6915 -0.29901123046875 +6916 -0.0419921875 +6917 -0.308990478515625 +6918 -0.043365478515625 +6919 -0.318939208984375 +6920 -0.044708251953125 +6921 -0.328826904296875 +6922 -0.046051025390625 +6923 -0.338714599609375 +6924 -0.047393798828125 +6925 -0.348541259765625 +6926 -0.0487060546875 +6927 -0.35833740234375 +6928 -0.050048828125 +6929 -0.36810302734375 +6930 -0.051361083984375 +6931 -0.3778076171875 +6932 -0.05267333984375 +6933 -0.387481689453125 +6934 -0.053985595703125 +6935 -0.397125244140625 +6936 -0.0552978515625 +6937 -0.406707763671875 +6938 -0.05657958984375 +6939 -0.416259765625 +6940 -0.057891845703125 +6941 -0.425750732421875 +6942 -0.059173583984375 +6943 -0.435211181640625 +6944 -0.060455322265625 +6945 -0.444610595703125 +6946 -0.06170654296875 +6947 -0.453948974609375 +6948 -0.06298828125 +6949 -0.4632568359375 +6950 -0.064239501953125 +6951 -0.4725341796875 +6952 -0.06549072265625 +6953 -0.481719970703125 +6954 -0.066741943359375 +6955 -0.490875244140625 +6956 -0.067962646484375 +6957 -0.499969482421875 +6958 -0.0692138671875 +6959 -0.509002685546875 +6960 -0.0704345703125 +6961 -0.51800537109375 +6962 -0.0716552734375 +6963 -0.52691650390625 +6964 -0.072845458984375 +6965 -0.535797119140625 +6966 -0.07403564453125 +6967 -0.54461669921875 +6968 -0.075225830078125 +6969 -0.5533447265625 +6970 -0.076416015625 +6971 -0.562042236328125 +6972 -0.077606201171875 +6973 -0.5706787109375 +6974 -0.078765869140625 +6975 -0.579254150390625 +6976 -0.079925537109375 +6977 -0.587738037109375 +6978 -0.0810546875 +6979 -0.59619140625 +6980 -0.082183837890625 +6981 -0.60455322265625 +6982 -0.083343505859375 +6983 -0.612884521484375 +6984 -0.084442138671875 +6985 -0.621124267578125 +6986 -0.0855712890625 +6987 -0.6292724609375 +6988 -0.086669921875 +6989 -0.63739013671875 +6990 -0.0877685546875 +6991 -0.645416259765625 +6992 -0.088836669921875 +6993 -0.65338134765625 +6994 -0.08990478515625 +6995 -0.661285400390625 +6996 -0.090972900390625 +6997 -0.669097900390625 +6998 -0.092041015625 +6999 -0.676849365234375 +7000 -0.09307861328125 +7001 -0.68450927734375 +7002 -0.0941162109375 +7003 -0.692108154296875 +7004 -0.095123291015625 +7005 -0.699615478515625 +7006 -0.09613037109375 +7007 -0.707061767578125 +7008 -0.097137451171875 +7009 -0.714447021484375 +7010 -0.09814453125 +7011 -0.721710205078125 +7012 -0.09912109375 +7013 -0.72894287109375 +7014 -0.100067138671875 +7015 -0.736053466796875 +7016 -0.101043701171875 +7017 -0.74310302734375 +7018 -0.10198974609375 +7019 -0.75006103515625 +7020 -0.102935791015625 +7021 -0.7569580078125 +7022 -0.103851318359375 +7023 -0.763763427734375 +7024 -0.104766845703125 +7025 -0.770477294921875 +7026 -0.10565185546875 +7027 -0.777099609375 +7028 -0.1065673828125 +7029 -0.783660888671875 +7030 -0.107421875 +7031 -0.790130615234375 +7032 -0.108306884765625 +7033 -0.796478271484375 +7034 -0.109161376953125 +7035 -0.802764892578125 +7036 -0.1099853515625 +7037 -0.808990478515625 +7038 -0.11083984375 +7039 -0.815093994140625 +7040 -0.11163330078125 +7041 -0.82110595703125 +7042 -0.112457275390625 +7043 -0.8270263671875 +7044 -0.113250732421875 +7045 -0.8328857421875 +7046 -0.114044189453125 +7047 -0.838623046875 +7048 -0.11480712890625 +7049 -0.84429931640625 +7050 -0.115570068359375 +7051 -0.849853515625 +7052 -0.116302490234375 +7053 -0.855316162109375 +7054 -0.117034912109375 +7055 -0.860687255859375 +7056 -0.117767333984375 +7057 -0.865997314453125 +7058 -0.11846923828125 +7059 -0.871185302734375 +7060 -0.119140625 +7061 -0.876251220703125 +7062 -0.11981201171875 +7063 -0.881256103515625 +7064 -0.1204833984375 +7065 -0.88616943359375 +7066 -0.12115478515625 +7067 -0.890960693359375 +7068 -0.121795654296875 +7069 -0.895660400390625 +7070 -0.122406005859375 +7071 -0.9002685546875 +7072 -0.123016357421875 +7073 -0.90478515625 +7074 -0.123626708984375 +7075 -0.9091796875 +7076 -0.12420654296875 +7077 -0.91351318359375 +7078 -0.124786376953125 +7079 -0.917724609375 +7080 -0.125335693359375 +7081 -0.92181396484375 +7082 -0.125885009765625 +7083 -0.92584228515625 +7084 -0.12640380859375 +7085 -0.929718017578125 +7086 -0.126922607421875 +7087 -0.93353271484375 +7088 -0.12744140625 +7089 -0.937225341796875 +7090 -0.1279296875 +7091 -0.940826416015625 +7092 -0.12841796875 +7093 -0.9443359375 +7094 -0.128875732421875 +7095 -0.947723388671875 +7096 -0.129302978515625 +7097 -0.951019287109375 +7098 -0.1297607421875 +7099 -0.954193115234375 +7100 -0.130157470703125 +7101 -0.957275390625 +7102 -0.13055419921875 +7103 -0.960235595703125 +7104 -0.130950927734375 +7105 -0.963104248046875 +7106 -0.13134765625 +7107 -0.96588134765625 +7108 -0.131683349609375 +7109 -0.968536376953125 +7110 -0.132049560546875 +7111 -0.971099853515625 +7112 -0.13238525390625 +7113 -0.973541259765625 +7114 -0.1326904296875 +7115 -0.975860595703125 +7116 -0.13299560546875 +7117 -0.97808837890625 +7118 -0.13330078125 +7119 -0.980224609375 +7120 -0.133544921875 +7121 -0.98223876953125 +7122 -0.133819580078125 +7123 -0.984161376953125 +7124 -0.134063720703125 +7125 -0.9859619140625 +7126 -0.134307861328125 +7127 -0.987640380859375 +7128 -0.134521484375 +7129 -0.989227294921875 +7130 -0.13470458984375 +7131 -0.990692138671875 +7132 -0.1348876953125 +7133 -0.9920654296875 +7134 -0.13507080078125 +7135 -0.993316650390625 +7136 -0.135223388671875 +7137 -0.994476318359375 +7138 -0.1353759765625 +7139 -0.995513916015625 +7140 -0.135498046875 +7141 -0.9964599609375 +7142 -0.1356201171875 +7143 -0.997283935546875 +7144 -0.135711669921875 +7145 -0.99798583984375 +7146 -0.135772705078125 +7147 -0.99859619140625 +7148 -0.1358642578125 +7149 -0.999114990234375 +7150 -0.135894775390625 +7151 -0.999481201171875 +7152 -0.13592529296875 +7153 -0.999755859375 +7154 -0.135955810546875 +7155 -0.99993896484375 +7156 -0.135986328125 +7157 -1.0 +7158 -0.135955810546875 +7159 -0.99993896484375 +7160 -0.13592529296875 +7161 -0.999755859375 +7162 -0.135894775390625 +7163 -0.999481201171875 +7164 -0.1358642578125 +7165 -0.999114990234375 +7166 -0.135772705078125 +7167 -0.99859619140625 +7168 -0.103790283203125 +7169 -0.99798583984375 +7170 -0.10369873046875 +7171 -0.997283935546875 +7172 -0.1036376953125 +7173 -0.9964599609375 +7174 -0.103515625 +7175 -0.995513916015625 +7176 -0.103424072265625 +7177 -0.994476318359375 +7178 -0.103302001953125 +7179 -0.993316650390625 +7180 -0.103179931640625 +7181 -0.9920654296875 +7182 -0.10302734375 +7183 -0.990692138671875 +7184 -0.102874755859375 +7185 -0.989227294921875 +7186 -0.102691650390625 +7187 -0.987640380859375 +7188 -0.1025390625 +7189 -0.9859619140625 +7190 -0.10235595703125 +7191 -0.984161376953125 +7192 -0.102142333984375 +7193 -0.98223876953125 +7194 -0.1019287109375 +7195 -0.980224609375 +7196 -0.101715087890625 +7197 -0.97808837890625 +7198 -0.101470947265625 +7199 -0.975860595703125 +7200 -0.101226806640625 +7201 -0.973541259765625 +7202 -0.100982666015625 +7203 -0.971099853515625 +7204 -0.1007080078125 +7205 -0.968536376953125 +7206 -0.100433349609375 +7207 -0.96588134765625 +7208 -0.10015869140625 +7209 -0.963104248046875 +7210 -0.099853515625 +7211 -0.960235595703125 +7212 -0.09954833984375 +7213 -0.957275390625 +7214 -0.099212646484375 +7215 -0.954193115234375 +7216 -0.098907470703125 +7217 -0.951019287109375 +7218 -0.098541259765625 +7219 -0.947723388671875 +7220 -0.09820556640625 +7221 -0.9443359375 +7222 -0.09783935546875 +7223 -0.940826416015625 +7224 -0.09747314453125 +7225 -0.937225341796875 +7226 -0.097076416015625 +7227 -0.93353271484375 +7228 -0.0966796875 +7229 -0.929718017578125 +7230 -0.096282958984375 +7231 -0.92584228515625 +7232 -0.095855712890625 +7233 -0.92181396484375 +7234 -0.095428466796875 +7235 -0.917724609375 +7236 -0.095001220703125 +7237 -0.91351318359375 +7238 -0.09454345703125 +7239 -0.9091796875 +7240 -0.094085693359375 +7241 -0.90478515625 +7242 -0.0936279296875 +7243 -0.9002685546875 +7244 -0.0931396484375 +7245 -0.895660400390625 +7246 -0.0926513671875 +7247 -0.890960693359375 +7248 -0.0921630859375 +7249 -0.88616943359375 +7250 -0.091644287109375 +7251 -0.881256103515625 +7252 -0.09112548828125 +7253 -0.876251220703125 +7254 -0.090606689453125 +7255 -0.871185302734375 +7256 -0.090057373046875 +7257 -0.865997314453125 +7258 -0.089508056640625 +7259 -0.860687255859375 +7260 -0.088958740234375 +7261 -0.855316162109375 +7262 -0.08837890625 +7263 -0.849853515625 +7264 -0.087799072265625 +7265 -0.84429931640625 +7266 -0.08721923828125 +7267 -0.838623046875 +7268 -0.08660888671875 +7269 -0.8328857421875 +7270 -0.08599853515625 +7271 -0.8270263671875 +7272 -0.08538818359375 +7273 -0.82110595703125 +7274 -0.084747314453125 +7275 -0.815093994140625 +7276 -0.084136962890625 +7277 -0.808990478515625 +7278 -0.083465576171875 +7279 -0.802764892578125 +7280 -0.08282470703125 +7281 -0.796478271484375 +7282 -0.0821533203125 +7283 -0.790130615234375 +7284 -0.08148193359375 +7285 -0.783660888671875 +7286 -0.080810546875 +7287 -0.777099609375 +7288 -0.080108642578125 +7289 -0.770477294921875 +7290 -0.07940673828125 +7291 -0.763763427734375 +7292 -0.078704833984375 +7293 -0.7569580078125 +7294 -0.0780029296875 +7295 -0.75006103515625 +7296 -0.0772705078125 +7297 -0.74310302734375 +7298 -0.0765380859375 +7299 -0.736053466796875 +7300 -0.0758056640625 +7301 -0.72894287109375 +7302 -0.075042724609375 +7303 -0.721710205078125 +7304 -0.07427978515625 +7305 -0.714447021484375 +7306 -0.073516845703125 +7307 -0.707061767578125 +7308 -0.07275390625 +7309 -0.699615478515625 +7310 -0.07196044921875 +7311 -0.692108154296875 +7312 -0.0711669921875 +7313 -0.68450927734375 +7314 -0.07037353515625 +7315 -0.676849365234375 +7316 -0.069580078125 +7317 -0.669097900390625 +7318 -0.068756103515625 +7319 -0.661285400390625 +7320 -0.06793212890625 +7321 -0.65338134765625 +7322 -0.067108154296875 +7323 -0.645416259765625 +7324 -0.0662841796875 +7325 -0.63739013671875 +7326 -0.0654296875 +7327 -0.6292724609375 +7328 -0.0645751953125 +7329 -0.621124267578125 +7330 -0.063720703125 +7331 -0.612884521484375 +7332 -0.0628662109375 +7333 -0.60455322265625 +7334 -0.061981201171875 +7335 -0.59619140625 +7336 -0.061126708984375 +7337 -0.587738037109375 +7338 -0.06024169921875 +7339 -0.579254150390625 +7340 -0.059326171875 +7341 -0.5706787109375 +7342 -0.058441162109375 +7343 -0.562042236328125 +7344 -0.057525634765625 +7345 -0.5533447265625 +7346 -0.056640625 +7347 -0.54461669921875 +7348 -0.05572509765625 +7349 -0.535797119140625 +7350 -0.054779052734375 +7351 -0.52691650390625 +7352 -0.053863525390625 +7353 -0.51800537109375 +7354 -0.05291748046875 +7355 -0.509002685546875 +7356 -0.051971435546875 +7357 -0.499969482421875 +7358 -0.051025390625 +7359 -0.490875244140625 +7360 -0.050079345703125 +7361 -0.481719970703125 +7362 -0.04913330078125 +7363 -0.4725341796875 +7364 -0.04815673828125 +7365 -0.4632568359375 +7366 -0.047210693359375 +7367 -0.453948974609375 +7368 -0.046234130859375 +7369 -0.444610595703125 +7370 -0.045257568359375 +7371 -0.435211181640625 +7372 -0.044281005859375 +7373 -0.425750732421875 +7374 -0.04327392578125 +7375 -0.416259765625 +7376 -0.04229736328125 +7377 -0.406707763671875 +7378 -0.041290283203125 +7379 -0.397125244140625 +7380 -0.040283203125 +7381 -0.387481689453125 +7382 -0.039276123046875 +7383 -0.3778076171875 +7384 -0.03826904296875 +7385 -0.36810302734375 +7386 -0.037261962890625 +7387 -0.35833740234375 +7388 -0.036224365234375 +7389 -0.348541259765625 +7390 -0.03521728515625 +7391 -0.338714599609375 +7392 -0.0341796875 +7393 -0.328826904296875 +7394 -0.03314208984375 +7395 -0.318939208984375 +7396 -0.032135009765625 +7397 -0.308990478515625 +7398 -0.031097412109375 +7399 -0.29901123046875 +7400 -0.030029296875 +7401 -0.28900146484375 +7402 -0.02899169921875 +7403 -0.278961181640625 +7404 -0.0279541015625 +7405 -0.268890380859375 +7406 -0.026885986328125 +7407 -0.2587890625 +7408 -0.025848388671875 +7409 -0.2486572265625 +7410 -0.0247802734375 +7411 -0.238525390625 +7412 -0.02374267578125 +7413 -0.22833251953125 +7414 -0.022674560546875 +7415 -0.218109130859375 +7416 -0.0216064453125 +7417 -0.2078857421875 +7418 -0.020538330078125 +7419 -0.1976318359375 +7420 -0.01947021484375 +7421 -0.187347412109375 +7422 -0.018402099609375 +7423 -0.17706298828125 +7424 -0.01666259765625 +7425 -0.166748046875 +7426 -0.015625 +7427 -0.156402587890625 +7428 -0.01458740234375 +7429 -0.14605712890625 +7430 -0.0135498046875 +7431 -0.13568115234375 +7432 -0.01251220703125 +7433 -0.12530517578125 +7434 -0.011474609375 +7435 -0.11492919921875 +7436 -0.01043701171875 +7437 -0.104522705078125 +7438 -0.0093994140625 +7439 -0.094085693359375 +7440 -0.00836181640625 +7441 -0.083648681640625 +7442 -0.007293701171875 +7443 -0.073211669921875 +7444 -0.006256103515625 +7445 -0.062774658203125 +7446 -0.005218505859375 +7447 -0.05230712890625 +7448 -0.004180908203125 +7449 -0.0418701171875 +7450 -0.00311279296875 +7451 -0.031402587890625 +7452 -0.0020751953125 +7453 -0.02093505859375 +7454 -0.00103759765625 +7455 -0.010467529296875 +7456 0.0 +7457 0.0 +7458 0.000732421875 +7459 0.010467529296875 +7460 0.001495361328125 +7461 0.02093505859375 +7462 0.00225830078125 +7463 0.031402587890625 +7464 0.00299072265625 +7465 0.0418701171875 +7466 0.003753662109375 +7467 0.05230712890625 +7468 0.0045166015625 +7469 0.062774658203125 +7470 0.0052490234375 +7471 0.073211669921875 +7472 0.006011962890625 +7473 0.083648681640625 +7474 0.006744384765625 +7475 0.094085693359375 +7476 0.00750732421875 +7477 0.104522705078125 +7478 0.008270263671875 +7479 0.11492919921875 +7480 0.009002685546875 +7481 0.12530517578125 +7482 0.009765625 +7483 0.13568115234375 +7484 0.010498046875 +7485 0.14605712890625 +7486 0.01123046875 +7487 0.156402587890625 +7488 0.011993408203125 +7489 0.166748046875 +7490 0.012725830078125 +7491 0.17706298828125 +7492 0.013458251953125 +7493 0.187347412109375 +7494 0.01422119140625 +7495 0.1976318359375 +7496 0.01495361328125 +7497 0.2078857421875 +7498 0.01568603515625 +7499 0.218109130859375 +7500 0.01641845703125 +7501 0.22833251953125 +7502 0.01715087890625 +7503 0.238525390625 +7504 0.01788330078125 +7505 0.2486572265625 +7506 0.01861572265625 +7507 0.2587890625 +7508 0.01934814453125 +7509 0.268890380859375 +7510 0.02008056640625 +7511 0.278961181640625 +7512 0.020782470703125 +7513 0.28900146484375 +7514 0.021514892578125 +7515 0.29901123046875 +7516 0.022216796875 +7517 0.308990478515625 +7518 0.02294921875 +7519 0.318939208984375 +7520 0.023651123046875 +7521 0.328826904296875 +7522 0.024383544921875 +7523 0.338714599609375 +7524 0.02508544921875 +7525 0.348541259765625 +7526 0.025787353515625 +7527 0.35833740234375 +7528 0.0264892578125 +7529 0.36810302734375 +7530 0.027191162109375 +7531 0.3778076171875 +7532 0.02789306640625 +7533 0.387481689453125 +7534 0.028564453125 +7535 0.397125244140625 +7536 0.029266357421875 +7537 0.406707763671875 +7538 0.029937744140625 +7539 0.416259765625 +7540 0.0306396484375 +7541 0.425750732421875 +7542 0.03131103515625 +7543 0.435211181640625 +7544 0.031982421875 +7545 0.444610595703125 +7546 0.03265380859375 +7547 0.453948974609375 +7548 0.0333251953125 +7549 0.4632568359375 +7550 0.03399658203125 +7551 0.4725341796875 +7552 0.03466796875 +7553 0.481719970703125 +7554 0.03533935546875 +7555 0.490875244140625 +7556 0.035980224609375 +7557 0.499969482421875 +7558 0.03662109375 +7559 0.509002685546875 +7560 0.03729248046875 +7561 0.51800537109375 +7562 0.037933349609375 +7563 0.52691650390625 +7564 0.038543701171875 +7565 0.535797119140625 +7566 0.0391845703125 +7567 0.54461669921875 +7568 0.039825439453125 +7569 0.5533447265625 +7570 0.040435791015625 +7571 0.562042236328125 +7572 0.04107666015625 +7573 0.5706787109375 +7574 0.04168701171875 +7575 0.579254150390625 +7576 0.04229736328125 +7577 0.587738037109375 +7578 0.04290771484375 +7579 0.59619140625 +7580 0.04351806640625 +7581 0.60455322265625 +7582 0.044097900390625 +7583 0.612884521484375 +7584 0.044708251953125 +7585 0.621124267578125 +7586 0.0452880859375 +7587 0.6292724609375 +7588 0.045867919921875 +7589 0.63739013671875 +7590 0.04644775390625 +7591 0.645416259765625 +7592 0.047027587890625 +7593 0.65338134765625 +7594 0.047607421875 +7595 0.661285400390625 +7596 0.04815673828125 +7597 0.669097900390625 +7598 0.0487060546875 +7599 0.676849365234375 +7600 0.04925537109375 +7601 0.68450927734375 +7602 0.0498046875 +7603 0.692108154296875 +7604 0.05035400390625 +7605 0.699615478515625 +7606 0.0509033203125 +7607 0.707061767578125 +7608 0.051422119140625 +7609 0.714447021484375 +7610 0.05194091796875 +7611 0.721710205078125 +7612 0.052459716796875 +7613 0.72894287109375 +7614 0.052978515625 +7615 0.736053466796875 +7616 0.053497314453125 +7617 0.74310302734375 +7618 0.053985595703125 +7619 0.75006103515625 +7620 0.054473876953125 +7621 0.7569580078125 +7622 0.054962158203125 +7623 0.763763427734375 +7624 0.055450439453125 +7625 0.770477294921875 +7626 0.055938720703125 +7627 0.777099609375 +7628 0.056396484375 +7629 0.783660888671875 +7630 0.056854248046875 +7631 0.790130615234375 +7632 0.05731201171875 +7633 0.796478271484375 +7634 0.057769775390625 +7635 0.802764892578125 +7636 0.0582275390625 +7637 0.808990478515625 +7638 0.05865478515625 +7639 0.815093994140625 +7640 0.059112548828125 +7641 0.82110595703125 +7642 0.059539794921875 +7643 0.8270263671875 +7644 0.0599365234375 +7645 0.8328857421875 +7646 0.06036376953125 +7647 0.838623046875 +7648 0.060760498046875 +7649 0.84429931640625 +7650 0.0611572265625 +7651 0.849853515625 +7652 0.061553955078125 +7653 0.855316162109375 +7654 0.06195068359375 +7655 0.860687255859375 +7656 0.06231689453125 +7657 0.865997314453125 +7658 0.062713623046875 +7659 0.871185302734375 +7660 0.063079833984375 +7661 0.876251220703125 +7662 0.06341552734375 +7663 0.881256103515625 +7664 0.06378173828125 +7665 0.88616943359375 +7666 0.064117431640625 +7667 0.890960693359375 +7668 0.064453125 +7669 0.895660400390625 +7670 0.064788818359375 +7671 0.9002685546875 +7672 0.06512451171875 +7673 0.90478515625 +7674 0.0654296875 +7675 0.9091796875 +7676 0.065765380859375 +7677 0.91351318359375 +7678 0.0660400390625 +7679 0.917724609375 +7680 0.036865234375 +7681 0.92181396484375 +7682 0.037017822265625 +7683 0.92584228515625 +7684 0.03717041015625 +7685 0.929718017578125 +7686 0.037322998046875 +7687 0.93353271484375 +7688 0.0374755859375 +7689 0.937225341796875 +7690 0.037628173828125 +7691 0.940826416015625 +7692 0.03778076171875 +7693 0.9443359375 +7694 0.03790283203125 +7695 0.947723388671875 +7696 0.03802490234375 +7697 0.951019287109375 +7698 0.03814697265625 +7699 0.954193115234375 +7700 0.038299560546875 +7701 0.957275390625 +7702 0.03839111328125 +7703 0.960235595703125 +7704 0.03851318359375 +7705 0.963104248046875 +7706 0.03863525390625 +7707 0.96588134765625 +7708 0.038726806640625 +7709 0.968536376953125 +7710 0.038848876953125 +7711 0.971099853515625 +7712 0.0389404296875 +7713 0.973541259765625 +7714 0.039031982421875 +7715 0.975860595703125 +7716 0.03912353515625 +7717 0.97808837890625 +7718 0.039215087890625 +7719 0.980224609375 +7720 0.039276123046875 +7721 0.98223876953125 +7722 0.03936767578125 +7723 0.984161376953125 +7724 0.0394287109375 +7725 0.9859619140625 +7726 0.03948974609375 +7727 0.987640380859375 +7728 0.03955078125 +7729 0.989227294921875 +7730 0.03961181640625 +7731 0.990692138671875 +7732 0.0396728515625 +7733 0.9920654296875 +7734 0.03973388671875 +7735 0.993316650390625 +7736 0.039764404296875 +7737 0.994476318359375 +7738 0.039825439453125 +7739 0.995513916015625 +7740 0.03985595703125 +7741 0.9964599609375 +7742 0.039886474609375 +7743 0.997283935546875 +7744 0.0399169921875 +7745 0.99798583984375 +7746 0.039947509765625 +7747 0.99859619140625 +7748 0.039947509765625 +7749 0.999114990234375 +7750 0.03997802734375 +7751 0.999481201171875 +7752 0.03997802734375 +7753 0.999755859375 +7754 0.03997802734375 +7755 0.99993896484375 +7756 0.040008544921875 +7757 0.999969482421875 +7758 0.03997802734375 +7759 0.99993896484375 +7760 0.03997802734375 +7761 0.999755859375 +7762 0.03997802734375 +7763 0.999481201171875 +7764 0.039947509765625 +7765 0.999114990234375 +7766 0.039947509765625 +7767 0.99859619140625 +7768 0.0399169921875 +7769 0.99798583984375 +7770 0.039886474609375 +7771 0.997283935546875 +7772 0.03985595703125 +7773 0.9964599609375 +7774 0.039825439453125 +7775 0.995513916015625 +7776 0.039764404296875 +7777 0.994476318359375 +7778 0.03973388671875 +7779 0.993316650390625 +7780 0.0396728515625 +7781 0.9920654296875 +7782 0.03961181640625 +7783 0.990692138671875 +7784 0.03955078125 +7785 0.989227294921875 +7786 0.03948974609375 +7787 0.987640380859375 +7788 0.0394287109375 +7789 0.9859619140625 +7790 0.03936767578125 +7791 0.984161376953125 +7792 0.039276123046875 +7793 0.98223876953125 +7794 0.039215087890625 +7795 0.980224609375 +7796 0.03912353515625 +7797 0.97808837890625 +7798 0.039031982421875 +7799 0.975860595703125 +7800 0.0389404296875 +7801 0.973541259765625 +7802 0.038848876953125 +7803 0.971099853515625 +7804 0.038726806640625 +7805 0.968536376953125 +7806 0.03863525390625 +7807 0.96588134765625 +7808 0.03851318359375 +7809 0.963104248046875 +7810 0.03839111328125 +7811 0.960235595703125 +7812 0.038299560546875 +7813 0.957275390625 +7814 0.03814697265625 +7815 0.954193115234375 +7816 0.03802490234375 +7817 0.951019287109375 +7818 0.03790283203125 +7819 0.947723388671875 +7820 0.03778076171875 +7821 0.9443359375 +7822 0.037628173828125 +7823 0.940826416015625 +7824 0.0374755859375 +7825 0.937225341796875 +7826 0.037322998046875 +7827 0.93353271484375 +7828 0.03717041015625 +7829 0.929718017578125 +7830 0.037017822265625 +7831 0.92584228515625 +7832 0.036865234375 +7833 0.92181396484375 +7834 0.036712646484375 +7835 0.917724609375 +7836 0.036529541015625 +7837 0.91351318359375 +7838 0.036346435546875 +7839 0.9091796875 +7840 0.03619384765625 +7841 0.90478515625 +7842 0.0360107421875 +7843 0.9002685546875 +7844 0.03582763671875 +7845 0.895660400390625 +7846 0.03564453125 +7847 0.890960693359375 +7848 0.035430908203125 +7849 0.88616943359375 +7850 0.035247802734375 +7851 0.881256103515625 +7852 0.0350341796875 +7853 0.876251220703125 +7854 0.03485107421875 +7855 0.871185302734375 +7856 0.034637451171875 +7857 0.865997314453125 +7858 0.034423828125 +7859 0.860687255859375 +7860 0.034210205078125 +7861 0.855316162109375 +7862 0.03399658203125 +7863 0.849853515625 +7864 0.03375244140625 +7865 0.84429931640625 +7866 0.033538818359375 +7867 0.838623046875 +7868 0.033294677734375 +7869 0.8328857421875 +7870 0.0330810546875 +7871 0.8270263671875 +7872 0.0328369140625 +7873 0.82110595703125 +7874 0.0325927734375 +7875 0.815093994140625 +7876 0.0323486328125 +7877 0.808990478515625 +7878 0.0321044921875 +7879 0.802764892578125 +7880 0.0318603515625 +7881 0.796478271484375 +7882 0.031585693359375 +7883 0.790130615234375 +7884 0.031341552734375 +7885 0.783660888671875 +7886 0.03106689453125 +7887 0.777099609375 +7888 0.03082275390625 +7889 0.770477294921875 +7890 0.030548095703125 +7891 0.763763427734375 +7892 0.0302734375 +7893 0.7569580078125 +7894 0.029998779296875 +7895 0.75006103515625 +7896 0.02972412109375 +7897 0.74310302734375 +7898 0.0294189453125 +7899 0.736053466796875 +7900 0.029144287109375 +7901 0.72894287109375 +7902 0.02886962890625 +7903 0.721710205078125 +7904 0.028564453125 +7905 0.714447021484375 +7906 0.02825927734375 +7907 0.707061767578125 +7908 0.027984619140625 +7909 0.699615478515625 +7910 0.027679443359375 +7911 0.692108154296875 +7912 0.027374267578125 +7913 0.68450927734375 +7914 0.027069091796875 +7915 0.676849365234375 +7916 0.026763916015625 +7917 0.669097900390625 +7918 0.02642822265625 +7919 0.661285400390625 +7920 0.026123046875 +7921 0.65338134765625 +7922 0.02581787109375 +7923 0.645416259765625 +7924 0.025482177734375 +7925 0.63739013671875 +7926 0.025177001953125 +7927 0.6292724609375 +7928 0.02484130859375 +7929 0.621124267578125 +7930 0.024505615234375 +7931 0.612884521484375 +7932 0.024169921875 +7933 0.60455322265625 +7934 0.023834228515625 +7935 0.59619140625 +7936 0.004669189453125 +7937 0.587738037109375 +7938 0.004608154296875 +7939 0.579254150390625 +7940 0.004547119140625 +7941 0.5706787109375 +7942 0.004486083984375 +7943 0.562042236328125 +7944 0.00439453125 +7945 0.5533447265625 +7946 0.00433349609375 +7947 0.54461669921875 +7948 0.0042724609375 +7949 0.535797119140625 +7950 0.00421142578125 +7951 0.52691650390625 +7952 0.004119873046875 +7953 0.51800537109375 +7954 0.004058837890625 +7955 0.509002685546875 +7956 0.00396728515625 +7957 0.499969482421875 +7958 0.00390625 +7959 0.490875244140625 +7960 0.00384521484375 +7961 0.481719970703125 +7962 0.003753662109375 +7963 0.4725341796875 +7964 0.003692626953125 +7965 0.4632568359375 +7966 0.00360107421875 +7967 0.453948974609375 +7968 0.0035400390625 +7969 0.444610595703125 +7970 0.00347900390625 +7971 0.435211181640625 +7972 0.003387451171875 +7973 0.425750732421875 +7974 0.003326416015625 +7975 0.416259765625 +7976 0.00323486328125 +7977 0.406707763671875 +7978 0.003173828125 +7979 0.397125244140625 +7980 0.003082275390625 +7981 0.387481689453125 +7982 0.00299072265625 +7983 0.3778076171875 +7984 0.0029296875 +7985 0.36810302734375 +7986 0.002838134765625 +7987 0.35833740234375 +7988 0.002777099609375 +7989 0.348541259765625 +7990 0.002685546875 +7991 0.338714599609375 +7992 0.00262451171875 +7993 0.328826904296875 +7994 0.002532958984375 +7995 0.318939208984375 +7996 0.00244140625 +7997 0.308990478515625 +7998 0.00238037109375 +7999 0.29901123046875 +8000 0.002288818359375 +8001 0.28900146484375 +8002 0.002227783203125 +8003 0.278961181640625 +8004 0.00213623046875 +8005 0.268890380859375 +8006 0.002044677734375 +8007 0.2587890625 +8008 0.001983642578125 +8009 0.2486572265625 +8010 0.00189208984375 +8011 0.238525390625 +8012 0.001800537109375 +8013 0.22833251953125 +8014 0.001739501953125 +8015 0.218109130859375 +8016 0.00164794921875 +8017 0.2078857421875 +8018 0.001556396484375 +8019 0.1976318359375 +8020 0.001495361328125 +8021 0.187347412109375 +8022 0.00140380859375 +8023 0.17706298828125 +8024 0.001312255859375 +8025 0.166748046875 +8026 0.001220703125 +8027 0.156402587890625 +8028 0.00115966796875 +8029 0.14605712890625 +8030 0.001068115234375 +8031 0.13568115234375 +8032 0.0009765625 +8033 0.12530517578125 +8034 0.00091552734375 +8035 0.11492919921875 +8036 0.000823974609375 +8037 0.104522705078125 +8038 0.000732421875 +8039 0.094085693359375 +8040 0.000640869140625 +8041 0.083648681640625 +8042 0.000579833984375 +8043 0.073211669921875 +8044 0.00048828125 +8045 0.062774658203125 +8046 0.000396728515625 +8047 0.05230712890625 +8048 0.00030517578125 +8049 0.0418701171875 +8050 0.000244140625 +8051 0.031402587890625 +8052 0.000152587890625 +8053 0.02093505859375 +8054 6.103515625e-05 +8055 0.010467529296875 +8056 0.0 +8057 0.0 +8058 -6.103515625e-05 +8059 -0.010467529296875 +8060 -0.000152587890625 +8061 -0.02093505859375 +8062 -0.000244140625 +8063 -0.031402587890625 +8064 -0.00030517578125 +8065 -0.0418701171875 +8066 -0.000396728515625 +8067 -0.05230712890625 +8068 -0.00048828125 +8069 -0.062774658203125 +8070 -0.000579833984375 +8071 -0.073211669921875 +8072 -0.000640869140625 +8073 -0.083648681640625 +8074 -0.000732421875 +8075 -0.094085693359375 +8076 -0.000823974609375 +8077 -0.104522705078125 +8078 -0.00091552734375 +8079 -0.11492919921875 +8080 -0.0009765625 +8081 -0.12530517578125 +8082 -0.001068115234375 +8083 -0.13568115234375 +8084 -0.00115966796875 +8085 -0.14605712890625 +8086 -0.001220703125 +8087 -0.156402587890625 +8088 -0.001312255859375 +8089 -0.166748046875 +8090 -0.00140380859375 +8091 -0.17706298828125 +8092 -0.001495361328125 +8093 -0.187347412109375 +8094 -0.001556396484375 +8095 -0.1976318359375 +8096 -0.00164794921875 +8097 -0.2078857421875 +8098 -0.001739501953125 +8099 -0.218109130859375 +8100 -0.001800537109375 +8101 -0.22833251953125 +8102 -0.00189208984375 +8103 -0.238525390625 +8104 -0.001983642578125 +8105 -0.2486572265625 +8106 -0.002044677734375 +8107 -0.2587890625 +8108 -0.00213623046875 +8109 -0.268890380859375 +8110 -0.002227783203125 +8111 -0.278961181640625 +8112 -0.002288818359375 +8113 -0.28900146484375 +8114 -0.00238037109375 +8115 -0.29901123046875 +8116 -0.00244140625 +8117 -0.308990478515625 +8118 -0.002532958984375 +8119 -0.318939208984375 +8120 -0.00262451171875 +8121 -0.328826904296875 +8122 -0.002685546875 +8123 -0.338714599609375 +8124 -0.002777099609375 +8125 -0.348541259765625 +8126 -0.002838134765625 +8127 -0.35833740234375 +8128 -0.0029296875 +8129 -0.36810302734375 +8130 -0.00299072265625 +8131 -0.3778076171875 +8132 -0.003082275390625 +8133 -0.387481689453125 +8134 -0.003173828125 +8135 -0.397125244140625 +8136 -0.00323486328125 +8137 -0.406707763671875 +8138 -0.003326416015625 +8139 -0.416259765625 +8140 -0.003387451171875 +8141 -0.425750732421875 +8142 -0.00347900390625 +8143 -0.435211181640625 +8144 -0.0035400390625 +8145 -0.444610595703125 +8146 -0.00360107421875 +8147 -0.453948974609375 +8148 -0.003692626953125 +8149 -0.4632568359375 +8150 -0.003753662109375 +8151 -0.4725341796875 +8152 -0.00384521484375 +8153 -0.481719970703125 +8154 -0.00390625 +8155 -0.490875244140625 +8156 -0.00396728515625 +8157 -0.499969482421875 +8158 -0.004058837890625 +8159 -0.509002685546875 +8160 -0.004119873046875 +8161 -0.51800537109375 +8162 -0.00421142578125 +8163 -0.52691650390625 +8164 -0.0042724609375 +8165 -0.535797119140625 +8166 -0.00433349609375 +8167 -0.54461669921875 +8168 -0.00439453125 +8169 -0.5533447265625 +8170 -0.004486083984375 +8171 -0.562042236328125 +8172 -0.004547119140625 +8173 -0.5706787109375 +8174 -0.004608154296875 +8175 -0.579254150390625 +8176 -0.004669189453125 +8177 -0.587738037109375 +8178 -0.0047607421875 +8179 -0.59619140625 +8180 -0.00482177734375 +8181 -0.60455322265625 +8182 -0.0048828125 +8183 -0.612884521484375 +8184 -0.00494384765625 +8185 -0.621124267578125 +8186 -0.0050048828125 +8187 -0.6292724609375 +8188 -0.005096435546875 +8189 -0.63739013671875 +8190 -0.005157470703125 +8191 -0.645416259765625 +8192 -0.015655517578125 +8193 -0.65338134765625 +8194 -0.015838623046875 +8195 -0.661285400390625 +8196 -0.016021728515625 +8197 -0.669097900390625 +8198 -0.0162353515625 +8199 -0.676849365234375 +8200 -0.01641845703125 +8201 -0.68450927734375 +8202 -0.0166015625 +8203 -0.692108154296875 +8204 -0.016754150390625 +8205 -0.699615478515625 +8206 -0.016937255859375 +8207 -0.707061767578125 +8208 -0.017120361328125 +8209 -0.714447021484375 +8210 -0.017303466796875 +8211 -0.721710205078125 +8212 -0.0174560546875 +8213 -0.72894287109375 +8214 -0.01763916015625 +8215 -0.736053466796875 +8216 -0.017822265625 +8217 -0.74310302734375 +8218 -0.017974853515625 +8219 -0.75006103515625 +8220 -0.01812744140625 +8221 -0.7569580078125 +8222 -0.018310546875 +8223 -0.763763427734375 +8224 -0.018463134765625 +8225 -0.770477294921875 +8226 -0.01861572265625 +8227 -0.777099609375 +8228 -0.018768310546875 +8229 -0.783660888671875 +8230 -0.018951416015625 +8231 -0.790130615234375 +8232 -0.01910400390625 +8233 -0.796478271484375 +8234 -0.01922607421875 +8235 -0.802764892578125 +8236 -0.019378662109375 +8237 -0.808990478515625 +8238 -0.01953125 +8239 -0.815093994140625 +8240 -0.019683837890625 +8241 -0.82110595703125 +8242 -0.01983642578125 +8243 -0.8270263671875 +8244 -0.01995849609375 +8245 -0.8328857421875 +8246 -0.020111083984375 +8247 -0.838623046875 +8248 -0.020233154296875 +8249 -0.84429931640625 +8250 -0.0203857421875 +8251 -0.849853515625 +8252 -0.0205078125 +8253 -0.855316162109375 +8254 -0.0206298828125 +8255 -0.860687255859375 +8256 -0.020751953125 +8257 -0.865997314453125 +8258 -0.0208740234375 +8259 -0.871185302734375 +8260 -0.02099609375 +8261 -0.876251220703125 +8262 -0.0211181640625 +8263 -0.881256103515625 +8264 -0.021240234375 +8265 -0.88616943359375 +8266 -0.0213623046875 +8267 -0.890960693359375 +8268 -0.021484375 +8269 -0.895660400390625 +8270 -0.021575927734375 +8271 -0.9002685546875 +8272 -0.021697998046875 +8273 -0.90478515625 +8274 -0.02178955078125 +8275 -0.9091796875 +8276 -0.02191162109375 +8277 -0.91351318359375 +8278 -0.022003173828125 +8279 -0.917724609375 +8280 -0.0220947265625 +8281 -0.92181396484375 +8282 -0.022186279296875 +8283 -0.92584228515625 +8284 -0.02227783203125 +8285 -0.929718017578125 +8286 -0.022369384765625 +8287 -0.93353271484375 +8288 -0.0224609375 +8289 -0.937225341796875 +8290 -0.022552490234375 +8291 -0.940826416015625 +8292 -0.02264404296875 +8293 -0.9443359375 +8294 -0.022705078125 +8295 -0.947723388671875 +8296 -0.022796630859375 +8297 -0.951019287109375 +8298 -0.02288818359375 +8299 -0.954193115234375 +8300 -0.02294921875 +8301 -0.957275390625 +8302 -0.02301025390625 +8303 -0.960235595703125 +8304 -0.023101806640625 +8305 -0.963104248046875 +8306 -0.023162841796875 +8307 -0.96588134765625 +8308 -0.023223876953125 +8309 -0.968536376953125 +8310 -0.023284912109375 +8311 -0.971099853515625 +8312 -0.023345947265625 +8313 -0.973541259765625 +8314 -0.023406982421875 +8315 -0.975860595703125 +8316 -0.0234375 +8317 -0.97808837890625 +8318 -0.02349853515625 +8319 -0.980224609375 +8320 -0.0235595703125 +8321 -0.98223876953125 +8322 -0.023590087890625 +8323 -0.984161376953125 +8324 -0.02362060546875 +8325 -0.9859619140625 +8326 -0.023681640625 +8327 -0.987640380859375 +8328 -0.023712158203125 +8329 -0.989227294921875 +8330 -0.02374267578125 +8331 -0.990692138671875 +8332 -0.023773193359375 +8333 -0.9920654296875 +8334 -0.0238037109375 +8335 -0.993316650390625 +8336 -0.023834228515625 +8337 -0.994476318359375 +8338 -0.02386474609375 +8339 -0.995513916015625 +8340 -0.023895263671875 +8341 -0.9964599609375 +8342 -0.023895263671875 +8343 -0.997283935546875 +8344 -0.02392578125 +8345 -0.99798583984375 +8346 -0.02392578125 +8347 -0.99859619140625 +8348 -0.023956298828125 +8349 -0.999114990234375 +8350 -0.023956298828125 +8351 -0.999481201171875 +8352 -0.023956298828125 +8353 -0.999755859375 +8354 -0.023956298828125 +8355 -0.99993896484375 +8356 -0.02398681640625 +8357 -1.0 +8358 -0.023956298828125 +8359 -0.99993896484375 +8360 -0.023956298828125 +8361 -0.999755859375 +8362 -0.023956298828125 +8363 -0.999481201171875 +8364 -0.023956298828125 +8365 -0.999114990234375 +8366 -0.02392578125 +8367 -0.99859619140625 +8368 -0.02392578125 +8369 -0.99798583984375 +8370 -0.023895263671875 +8371 -0.997283935546875 +8372 -0.023895263671875 +8373 -0.9964599609375 +8374 -0.02386474609375 +8375 -0.995513916015625 +8376 -0.023834228515625 +8377 -0.994476318359375 +8378 -0.0238037109375 +8379 -0.993316650390625 +8380 -0.023773193359375 +8381 -0.9920654296875 +8382 -0.02374267578125 +8383 -0.990692138671875 +8384 -0.023712158203125 +8385 -0.989227294921875 +8386 -0.023681640625 +8387 -0.987640380859375 +8388 -0.02362060546875 +8389 -0.9859619140625 +8390 -0.023590087890625 +8391 -0.984161376953125 +8392 -0.0235595703125 +8393 -0.98223876953125 +8394 -0.02349853515625 +8395 -0.980224609375 +8396 -0.0234375 +8397 -0.97808837890625 +8398 -0.023406982421875 +8399 -0.975860595703125 +8400 -0.023345947265625 +8401 -0.973541259765625 +8402 -0.023284912109375 +8403 -0.971099853515625 +8404 -0.023223876953125 +8405 -0.968536376953125 +8406 -0.023162841796875 +8407 -0.96588134765625 +8408 -0.023101806640625 +8409 -0.963104248046875 +8410 -0.02301025390625 +8411 -0.960235595703125 +8412 -0.02294921875 +8413 -0.957275390625 +8414 -0.02288818359375 +8415 -0.954193115234375 +8416 -0.022796630859375 +8417 -0.951019287109375 +8418 -0.022705078125 +8419 -0.947723388671875 +8420 -0.02264404296875 +8421 -0.9443359375 +8422 -0.022552490234375 +8423 -0.940826416015625 +8424 -0.0224609375 +8425 -0.937225341796875 +8426 -0.022369384765625 +8427 -0.93353271484375 +8428 -0.02227783203125 +8429 -0.929718017578125 +8430 -0.022186279296875 +8431 -0.92584228515625 +8432 -0.0220947265625 +8433 -0.92181396484375 +8434 -0.022003173828125 +8435 -0.917724609375 +8436 -0.02191162109375 +8437 -0.91351318359375 +8438 -0.02178955078125 +8439 -0.9091796875 +8440 -0.021697998046875 +8441 -0.90478515625 +8442 -0.021575927734375 +8443 -0.9002685546875 +8444 -0.021484375 +8445 -0.895660400390625 +8446 -0.0213623046875 +8447 -0.890960693359375 +8448 -0.044281005859375 +8449 -0.88616943359375 +8450 -0.044036865234375 +8451 -0.881256103515625 +8452 -0.043792724609375 +8453 -0.876251220703125 +8454 -0.043548583984375 +8455 -0.871185302734375 +8456 -0.04327392578125 +8457 -0.865997314453125 +8458 -0.042999267578125 +8459 -0.860687255859375 +8460 -0.042755126953125 +8461 -0.855316162109375 +8462 -0.04248046875 +8463 -0.849853515625 +8464 -0.042205810546875 +8465 -0.84429931640625 +8466 -0.041900634765625 +8467 -0.838623046875 +8468 -0.0416259765625 +8469 -0.8328857421875 +8470 -0.04132080078125 +8471 -0.8270263671875 +8472 -0.041046142578125 +8473 -0.82110595703125 +8474 -0.040740966796875 +8475 -0.815093994140625 +8476 -0.040435791015625 +8477 -0.808990478515625 +8478 -0.04010009765625 +8479 -0.802764892578125 +8480 -0.039794921875 +8481 -0.796478271484375 +8482 -0.03948974609375 +8483 -0.790130615234375 +8484 -0.039154052734375 +8485 -0.783660888671875 +8486 -0.038818359375 +8487 -0.777099609375 +8488 -0.03851318359375 +8489 -0.770477294921875 +8490 -0.038177490234375 +8491 -0.763763427734375 +8492 -0.037811279296875 +8493 -0.7569580078125 +8494 -0.0374755859375 +8495 -0.75006103515625 +8496 -0.037139892578125 +8497 -0.74310302734375 +8498 -0.036773681640625 +8499 -0.736053466796875 +8500 -0.03643798828125 +8501 -0.72894287109375 +8502 -0.03607177734375 +8503 -0.721710205078125 +8504 -0.03570556640625 +8505 -0.714447021484375 +8506 -0.03533935546875 +8507 -0.707061767578125 +8508 -0.03497314453125 +8509 -0.699615478515625 +8510 -0.034576416015625 +8511 -0.692108154296875 +8512 -0.034210205078125 +8513 -0.68450927734375 +8514 -0.0338134765625 +8515 -0.676849365234375 +8516 -0.033447265625 +8517 -0.669097900390625 +8518 -0.033050537109375 +8519 -0.661285400390625 +8520 -0.03265380859375 +8521 -0.65338134765625 +8522 -0.032257080078125 +8523 -0.645416259765625 +8524 -0.0318603515625 +8525 -0.63739013671875 +8526 -0.03143310546875 +8527 -0.6292724609375 +8528 -0.031036376953125 +8529 -0.621124267578125 +8530 -0.030609130859375 +8531 -0.612884521484375 +8532 -0.03021240234375 +8533 -0.60455322265625 +8534 -0.02978515625 +8535 -0.59619140625 +8536 -0.02935791015625 +8537 -0.587738037109375 +8538 -0.0289306640625 +8539 -0.579254150390625 +8540 -0.02850341796875 +8541 -0.5706787109375 +8542 -0.028076171875 +8543 -0.562042236328125 +8544 -0.02764892578125 +8545 -0.5533447265625 +8546 -0.0272216796875 +8547 -0.54461669921875 +8548 -0.026763916015625 +8549 -0.535797119140625 +8550 -0.026336669921875 +8551 -0.52691650390625 +8552 -0.02587890625 +8553 -0.51800537109375 +8554 -0.025421142578125 +8555 -0.509002685546875 +8556 -0.02496337890625 +8557 -0.499969482421875 +8558 -0.0245361328125 +8559 -0.490875244140625 +8560 -0.024078369140625 +8561 -0.481719970703125 +8562 -0.02362060546875 +8563 -0.4725341796875 +8564 -0.02313232421875 +8565 -0.4632568359375 +8566 -0.022674560546875 +8567 -0.453948974609375 +8568 -0.022216796875 +8569 -0.444610595703125 +8570 -0.021728515625 +8571 -0.435211181640625 +8572 -0.021270751953125 +8573 -0.425750732421875 +8574 -0.020782470703125 +8575 -0.416259765625 +8576 -0.02032470703125 +8577 -0.406707763671875 +8578 -0.01983642578125 +8579 -0.397125244140625 +8580 -0.01934814453125 +8581 -0.387481689453125 +8582 -0.01885986328125 +8583 -0.3778076171875 +8584 -0.01837158203125 +8585 -0.36810302734375 +8586 -0.01788330078125 +8587 -0.35833740234375 +8588 -0.01739501953125 +8589 -0.348541259765625 +8590 -0.01690673828125 +8591 -0.338714599609375 +8592 -0.01641845703125 +8593 -0.328826904296875 +8594 -0.01593017578125 +8595 -0.318939208984375 +8596 -0.01544189453125 +8597 -0.308990478515625 +8598 -0.014923095703125 +8599 -0.29901123046875 +8600 -0.014434814453125 +8601 -0.28900146484375 +8602 -0.013916015625 +8603 -0.278961181640625 +8604 -0.013427734375 +8605 -0.268890380859375 +8606 -0.012908935546875 +8607 -0.2587890625 +8608 -0.012420654296875 +8609 -0.2486572265625 +8610 -0.01190185546875 +8611 -0.238525390625 +8612 -0.01141357421875 +8613 -0.22833251953125 +8614 -0.010894775390625 +8615 -0.218109130859375 +8616 -0.0103759765625 +8617 -0.2078857421875 +8618 -0.009857177734375 +8619 -0.1976318359375 +8620 -0.00933837890625 +8621 -0.187347412109375 +8622 -0.00885009765625 +8623 -0.17706298828125 +8624 -0.008331298828125 +8625 -0.166748046875 +8626 -0.0078125 +8627 -0.156402587890625 +8628 -0.007293701171875 +8629 -0.14605712890625 +8630 -0.00677490234375 +8631 -0.13568115234375 +8632 -0.006256103515625 +8633 -0.12530517578125 +8634 -0.0057373046875 +8635 -0.11492919921875 +8636 -0.005218505859375 +8637 -0.104522705078125 +8638 -0.00469970703125 +8639 -0.094085693359375 +8640 -0.004180908203125 +8641 -0.083648681640625 +8642 -0.003631591796875 +8643 -0.073211669921875 +8644 -0.00311279296875 +8645 -0.062774658203125 +8646 -0.002593994140625 +8647 -0.05230712890625 +8648 -0.0020751953125 +8649 -0.0418701171875 +8650 -0.001556396484375 +8651 -0.031402587890625 +8652 -0.00103759765625 +8653 -0.02093505859375 +8654 -0.000518798828125 +8655 -0.010467529296875 +8656 0.0 +8657 0.0 +8658 0.000579833984375 +8659 0.010467529296875 +8660 0.00115966796875 +8661 0.02093505859375 +8662 0.001739501953125 +8663 0.031402587890625 +8664 0.0023193359375 +8665 0.0418701171875 +8666 0.002899169921875 +8667 0.05230712890625 +8668 0.003509521484375 +8669 0.062774658203125 +8670 0.00408935546875 +8671 0.073211669921875 +8672 0.004669189453125 +8673 0.083648681640625 +8674 0.0052490234375 +8675 0.094085693359375 +8676 0.005828857421875 +8677 0.104522705078125 +8678 0.00640869140625 +8679 0.11492919921875 +8680 0.006988525390625 +8681 0.12530517578125 +8682 0.007568359375 +8683 0.13568115234375 +8684 0.0081787109375 +8685 0.14605712890625 +8686 0.008758544921875 +8687 0.156402587890625 +8688 0.009307861328125 +8689 0.166748046875 +8690 0.0098876953125 +8691 0.17706298828125 +8692 0.010467529296875 +8693 0.187347412109375 +8694 0.01104736328125 +8695 0.1976318359375 +8696 0.011627197265625 +8697 0.2078857421875 +8698 0.01220703125 +8699 0.218109130859375 +8700 0.012786865234375 +8701 0.22833251953125 +8702 0.013336181640625 +8703 0.238525390625 +8704 0.0218505859375 +8705 0.2486572265625 +8706 0.02276611328125 +8707 0.2587890625 +8708 0.023651123046875 +8709 0.268890380859375 +8710 0.0245361328125 +8711 0.278961181640625 +8712 0.025421142578125 +8713 0.28900146484375 +8714 0.02630615234375 +8715 0.29901123046875 +8716 0.02716064453125 +8717 0.308990478515625 +8718 0.028045654296875 +8719 0.318939208984375 +8720 0.0289306640625 +8721 0.328826904296875 +8722 0.02978515625 +8723 0.338714599609375 +8724 0.0306396484375 +8725 0.348541259765625 +8726 0.031524658203125 +8727 0.35833740234375 +8728 0.032379150390625 +8729 0.36810302734375 +8730 0.033233642578125 +8731 0.3778076171875 +8732 0.034088134765625 +8733 0.387481689453125 +8734 0.034912109375 +8735 0.397125244140625 +8736 0.0357666015625 +8737 0.406707763671875 +8738 0.03662109375 +8739 0.416259765625 +8740 0.037445068359375 +8741 0.425750732421875 +8742 0.03826904296875 +8743 0.435211181640625 +8744 0.039093017578125 +8745 0.444610595703125 +8746 0.0399169921875 +8747 0.453948974609375 +8748 0.040740966796875 +8749 0.4632568359375 +8750 0.04156494140625 +8751 0.4725341796875 +8752 0.0423583984375 +8753 0.481719970703125 +8754 0.043182373046875 +8755 0.490875244140625 +8756 0.043975830078125 +8757 0.499969482421875 +8758 0.044769287109375 +8759 0.509002685546875 +8760 0.045562744140625 +8761 0.51800537109375 +8762 0.046356201171875 +8763 0.52691650390625 +8764 0.047119140625 +8765 0.535797119140625 +8766 0.04791259765625 +8767 0.54461669921875 +8768 0.048675537109375 +8769 0.5533447265625 +8770 0.0494384765625 +8771 0.562042236328125 +8772 0.050201416015625 +8773 0.5706787109375 +8774 0.05096435546875 +8775 0.579254150390625 +8776 0.05169677734375 +8777 0.587738037109375 +8778 0.05242919921875 +8779 0.59619140625 +8780 0.05316162109375 +8781 0.60455322265625 +8782 0.053924560546875 +8783 0.612884521484375 +8784 0.05462646484375 +8785 0.621124267578125 +8786 0.05535888671875 +8787 0.6292724609375 +8788 0.056060791015625 +8789 0.63739013671875 +8790 0.0567626953125 +8791 0.645416259765625 +8792 0.057464599609375 +8793 0.65338134765625 +8794 0.05816650390625 +8795 0.661285400390625 +8796 0.058868408203125 +8797 0.669097900390625 +8798 0.059539794921875 +8799 0.676849365234375 +8800 0.060211181640625 +8801 0.68450927734375 +8802 0.060882568359375 +8803 0.692108154296875 +8804 0.061553955078125 +8805 0.699615478515625 +8806 0.06219482421875 +8807 0.707061767578125 +8808 0.062835693359375 +8809 0.714447021484375 +8810 0.0634765625 +8811 0.721710205078125 +8812 0.064117431640625 +8813 0.72894287109375 +8814 0.06475830078125 +8815 0.736053466796875 +8816 0.06536865234375 +8817 0.74310302734375 +8818 0.06597900390625 +8819 0.75006103515625 +8820 0.06658935546875 +8821 0.7569580078125 +8822 0.067169189453125 +8823 0.763763427734375 +8824 0.067779541015625 +8825 0.770477294921875 +8826 0.068359375 +8827 0.777099609375 +8828 0.068939208984375 +8829 0.783660888671875 +8830 0.06951904296875 +8831 0.790130615234375 +8832 0.070068359375 +8833 0.796478271484375 +8834 0.07061767578125 +8835 0.802764892578125 +8836 0.0711669921875 +8837 0.808990478515625 +8838 0.071685791015625 +8839 0.815093994140625 +8840 0.072235107421875 +8841 0.82110595703125 +8842 0.07275390625 +8843 0.8270263671875 +8844 0.073272705078125 +8845 0.8328857421875 +8846 0.073760986328125 +8847 0.838623046875 +8848 0.07427978515625 +8849 0.84429931640625 +8850 0.07476806640625 +8851 0.849853515625 +8852 0.075225830078125 +8853 0.855316162109375 +8854 0.075714111328125 +8855 0.860687255859375 +8856 0.076171875 +8857 0.865997314453125 +8858 0.076629638671875 +8859 0.871185302734375 +8860 0.07708740234375 +8861 0.876251220703125 +8862 0.0775146484375 +8863 0.881256103515625 +8864 0.07794189453125 +8865 0.88616943359375 +8866 0.078369140625 +8867 0.890960693359375 +8868 0.07879638671875 +8869 0.895660400390625 +8870 0.079193115234375 +8871 0.9002685546875 +8872 0.07958984375 +8873 0.90478515625 +8874 0.079986572265625 +8875 0.9091796875 +8876 0.080352783203125 +8877 0.91351318359375 +8878 0.080718994140625 +8879 0.917724609375 +8880 0.081085205078125 +8881 0.92181396484375 +8882 0.081451416015625 +8883 0.92584228515625 +8884 0.081787109375 +8885 0.929718017578125 +8886 0.082122802734375 +8887 0.93353271484375 +8888 0.08245849609375 +8889 0.937225341796875 +8890 0.082763671875 +8891 0.940826416015625 +8892 0.08306884765625 +8893 0.9443359375 +8894 0.0833740234375 +8895 0.947723388671875 +8896 0.083648681640625 +8897 0.951019287109375 +8898 0.083953857421875 +8899 0.954193115234375 +8900 0.084197998046875 +8901 0.957275390625 +8902 0.08447265625 +8903 0.960235595703125 +8904 0.084716796875 +8905 0.963104248046875 +8906 0.0849609375 +8907 0.96588134765625 +8908 0.085205078125 +8909 0.968536376953125 +8910 0.085418701171875 +8911 0.971099853515625 +8912 0.08563232421875 +8913 0.973541259765625 +8914 0.085845947265625 +8915 0.975860595703125 +8916 0.086029052734375 +8917 0.97808837890625 +8918 0.08624267578125 +8919 0.980224609375 +8920 0.086395263671875 +8921 0.98223876953125 +8922 0.086578369140625 +8923 0.984161376953125 +8924 0.08673095703125 +8925 0.9859619140625 +8926 0.086883544921875 +8927 0.987640380859375 +8928 0.0870361328125 +8929 0.989227294921875 +8930 0.087158203125 +8931 0.990692138671875 +8932 0.0872802734375 +8933 0.9920654296875 +8934 0.087371826171875 +8935 0.993316650390625 +8936 0.087493896484375 +8937 0.994476318359375 +8938 0.08758544921875 +8939 0.995513916015625 +8940 0.087646484375 +8941 0.9964599609375 +8942 0.087738037109375 +8943 0.997283935546875 +8944 0.087799072265625 +8945 0.99798583984375 +8946 0.087860107421875 +8947 0.99859619140625 +8948 0.087890625 +8949 0.999114990234375 +8950 0.087921142578125 +8951 0.999481201171875 +8952 0.08795166015625 +8953 0.999755859375 +8954 0.08795166015625 +8955 0.99993896484375 +8956 0.087982177734375 +8957 0.999969482421875 +8958 0.08795166015625 +8959 0.99993896484375 +8960 0.119964599609375 +8961 0.999755859375 +8962 0.119903564453125 +8963 0.999481201171875 +8964 0.119873046875 +8965 0.999114990234375 +8966 0.11981201171875 +8967 0.99859619140625 +8968 0.1197509765625 +8969 0.99798583984375 +8970 0.119659423828125 +8971 0.997283935546875 +8972 0.11956787109375 +8973 0.9964599609375 +8974 0.11944580078125 +8975 0.995513916015625 +8976 0.11932373046875 +8977 0.994476318359375 +8978 0.119171142578125 +8979 0.993316650390625 +8980 0.1190185546875 +8981 0.9920654296875 +8982 0.118865966796875 +8983 0.990692138671875 +8984 0.118682861328125 +8985 0.989227294921875 +8986 0.118499755859375 +8987 0.987640380859375 +8988 0.1182861328125 +8989 0.9859619140625 +8990 0.118072509765625 +8991 0.984161376953125 +8992 0.11785888671875 +8993 0.98223876953125 +8994 0.11761474609375 +8995 0.980224609375 +8996 0.117340087890625 +8997 0.97808837890625 +8998 0.117095947265625 +8999 0.975860595703125 +9000 0.1168212890625 +9001 0.973541259765625 +9002 0.11651611328125 +9003 0.971099853515625 +9004 0.1162109375 +9005 0.968536376953125 +9006 0.115875244140625 +9007 0.96588134765625 +9008 0.115570068359375 +9009 0.963104248046875 +9010 0.115203857421875 +9011 0.960235595703125 +9012 0.1148681640625 +9013 0.957275390625 +9014 0.114501953125 +9015 0.954193115234375 +9016 0.114105224609375 +9017 0.951019287109375 +9018 0.11370849609375 +9019 0.947723388671875 +9020 0.113311767578125 +9021 0.9443359375 +9022 0.112884521484375 +9023 0.940826416015625 +9024 0.112457275390625 +9025 0.937225341796875 +9026 0.11199951171875 +9027 0.93353271484375 +9028 0.111541748046875 +9029 0.929718017578125 +9030 0.111083984375 +9031 0.92584228515625 +9032 0.110595703125 +9033 0.92181396484375 +9034 0.110107421875 +9035 0.917724609375 +9036 0.109619140625 +9037 0.91351318359375 +9038 0.109100341796875 +9039 0.9091796875 +9040 0.108551025390625 +9041 0.90478515625 +9042 0.108001708984375 +9043 0.9002685546875 +9044 0.107452392578125 +9045 0.895660400390625 +9046 0.106903076171875 +9047 0.890960693359375 +9048 0.1063232421875 +9049 0.88616943359375 +9050 0.105743408203125 +9051 0.881256103515625 +9052 0.105133056640625 +9053 0.876251220703125 +9054 0.104522705078125 +9055 0.871185302734375 +9056 0.103912353515625 +9057 0.865997314453125 +9058 0.103271484375 +9059 0.860687255859375 +9060 0.102630615234375 +9061 0.855316162109375 +9062 0.101959228515625 +9063 0.849853515625 +9064 0.101287841796875 +9065 0.84429931640625 +9066 0.100616455078125 +9067 0.838623046875 +9068 0.099945068359375 +9069 0.8328857421875 +9070 0.099212646484375 +9071 0.8270263671875 +9072 0.0985107421875 +9073 0.82110595703125 +9074 0.097808837890625 +9075 0.815093994140625 +9076 0.097076416015625 +9077 0.808990478515625 +9078 0.0963134765625 +9079 0.802764892578125 +9080 0.095550537109375 +9081 0.796478271484375 +9082 0.09478759765625 +9083 0.790130615234375 +9084 0.094024658203125 +9085 0.783660888671875 +9086 0.093231201171875 +9087 0.777099609375 +9088 0.092437744140625 +9089 0.770477294921875 +9090 0.091644287109375 +9091 0.763763427734375 +9092 0.0908203125 +9093 0.7569580078125 +9094 0.089996337890625 +9095 0.75006103515625 +9096 0.089141845703125 +9097 0.74310302734375 +9098 0.08831787109375 +9099 0.736053466796875 +9100 0.08746337890625 +9101 0.72894287109375 +9102 0.086578369140625 +9103 0.721710205078125 +9104 0.085723876953125 +9105 0.714447021484375 +9106 0.0848388671875 +9107 0.707061767578125 +9108 0.08392333984375 +9109 0.699615478515625 +9110 0.083038330078125 +9111 0.692108154296875 +9112 0.082122802734375 +9113 0.68450927734375 +9114 0.081207275390625 +9115 0.676849365234375 +9116 0.08026123046875 +9117 0.669097900390625 +9118 0.079345703125 +9119 0.661285400390625 +9120 0.078399658203125 +9121 0.65338134765625 +9122 0.077423095703125 +9123 0.645416259765625 +9124 0.07647705078125 +9125 0.63739013671875 +9126 0.07550048828125 +9127 0.6292724609375 +9128 0.07452392578125 +9129 0.621124267578125 +9130 0.073516845703125 +9131 0.612884521484375 +9132 0.072540283203125 +9133 0.60455322265625 +9134 0.071533203125 +9135 0.59619140625 +9136 0.070526123046875 +9137 0.587738037109375 +9138 0.069488525390625 +9139 0.579254150390625 +9140 0.068450927734375 +9141 0.5706787109375 +9142 0.06744384765625 +9143 0.562042236328125 +9144 0.066375732421875 +9145 0.5533447265625 +9146 0.065338134765625 +9147 0.54461669921875 +9148 0.06427001953125 +9149 0.535797119140625 +9150 0.063201904296875 +9151 0.52691650390625 +9152 0.0621337890625 +9153 0.51800537109375 +9154 0.061065673828125 +9155 0.509002685546875 +9156 0.059967041015625 +9157 0.499969482421875 +9158 0.05889892578125 +9159 0.490875244140625 +9160 0.05780029296875 +9161 0.481719970703125 +9162 0.05670166015625 +9163 0.4725341796875 +9164 0.055572509765625 +9165 0.4632568359375 +9166 0.054443359375 +9167 0.453948974609375 +9168 0.0533447265625 +9169 0.444610595703125 +9170 0.052215576171875 +9171 0.435211181640625 +9172 0.05108642578125 +9173 0.425750732421875 +9174 0.0499267578125 +9175 0.416259765625 +9176 0.048797607421875 +9177 0.406707763671875 +9178 0.047637939453125 +9179 0.397125244140625 +9180 0.046478271484375 +9181 0.387481689453125 +9182 0.045318603515625 +9183 0.3778076171875 +9184 0.044158935546875 +9185 0.36810302734375 +9186 0.042999267578125 +9187 0.35833740234375 +9188 0.04180908203125 +9189 0.348541259765625 +9190 0.040618896484375 +9191 0.338714599609375 +9192 0.0394287109375 +9193 0.328826904296875 +9194 0.03826904296875 +9195 0.318939208984375 +9196 0.03704833984375 +9197 0.308990478515625 +9198 0.035858154296875 +9199 0.29901123046875 +9200 0.03466796875 +9201 0.28900146484375 +9202 0.033447265625 +9203 0.278961181640625 +9204 0.032257080078125 +9205 0.268890380859375 +9206 0.031036376953125 +9207 0.2587890625 +9208 0.029815673828125 +9209 0.2486572265625 +9210 0.028594970703125 +9211 0.238525390625 +9212 0.027374267578125 +9213 0.22833251953125 +9214 0.026153564453125 +9215 0.218109130859375 +9216 0.031585693359375 +9217 0.2078857421875 +9218 0.030029296875 +9219 0.1976318359375 +9220 0.028472900390625 +9221 0.187347412109375 +9222 0.026885986328125 +9223 0.17706298828125 +9224 0.02532958984375 +9225 0.166748046875 +9226 0.023773193359375 +9227 0.156402587890625 +9228 0.022186279296875 +9229 0.14605712890625 +9230 0.020599365234375 +9231 0.13568115234375 +9232 0.01904296875 +9233 0.12530517578125 +9234 0.0174560546875 +9235 0.11492919921875 +9236 0.015869140625 +9237 0.104522705078125 +9238 0.0142822265625 +9239 0.094085693359375 +9240 0.0126953125 +9241 0.083648681640625 +9242 0.0111083984375 +9243 0.073211669921875 +9244 0.009521484375 +9245 0.062774658203125 +9246 0.0079345703125 +9247 0.05230712890625 +9248 0.00634765625 +9249 0.0418701171875 +9250 0.0047607421875 +9251 0.031402587890625 +9252 0.003173828125 +9253 0.02093505859375 +9254 0.0015869140625 +9255 0.010467529296875 +9256 0.0 +9257 0.0 +9258 -0.0015869140625 +9259 -0.010467529296875 +9260 -0.003173828125 +9261 -0.02093505859375 +9262 -0.0047607421875 +9263 -0.031402587890625 +9264 -0.00634765625 +9265 -0.0418701171875 +9266 -0.0079345703125 +9267 -0.05230712890625 +9268 -0.009521484375 +9269 -0.062774658203125 +9270 -0.0111083984375 +9271 -0.073211669921875 +9272 -0.0126953125 +9273 -0.083648681640625 +9274 -0.0142822265625 +9275 -0.094085693359375 +9276 -0.015869140625 +9277 -0.104522705078125 +9278 -0.0174560546875 +9279 -0.11492919921875 +9280 -0.01904296875 +9281 -0.12530517578125 +9282 -0.020599365234375 +9283 -0.13568115234375 +9284 -0.022186279296875 +9285 -0.14605712890625 +9286 -0.023773193359375 +9287 -0.156402587890625 +9288 -0.02532958984375 +9289 -0.166748046875 +9290 -0.026885986328125 +9291 -0.17706298828125 +9292 -0.028472900390625 +9293 -0.187347412109375 +9294 -0.030029296875 +9295 -0.1976318359375 +9296 -0.031585693359375 +9297 -0.2078857421875 +9298 -0.03314208984375 +9299 -0.218109130859375 +9300 -0.034698486328125 +9301 -0.22833251953125 +9302 -0.0362548828125 +9303 -0.238525390625 +9304 -0.03778076171875 +9305 -0.2486572265625 +9306 -0.039337158203125 +9307 -0.2587890625 +9308 -0.040863037109375 +9309 -0.268890380859375 +9310 -0.042388916015625 +9311 -0.278961181640625 +9312 -0.043914794921875 +9313 -0.28900146484375 +9314 -0.045440673828125 +9315 -0.29901123046875 +9316 -0.046966552734375 +9317 -0.308990478515625 +9318 -0.0484619140625 +9319 -0.318939208984375 +9320 -0.049957275390625 +9321 -0.328826904296875 +9322 -0.051483154296875 +9323 -0.338714599609375 +9324 -0.052978515625 +9325 -0.348541259765625 +9326 -0.054443359375 +9327 -0.35833740234375 +9328 -0.055938720703125 +9329 -0.36810302734375 +9330 -0.057403564453125 +9331 -0.3778076171875 +9332 -0.05889892578125 +9333 -0.387481689453125 +9334 -0.06036376953125 +9335 -0.397125244140625 +9336 -0.061798095703125 +9337 -0.406707763671875 +9338 -0.063262939453125 +9339 -0.416259765625 +9340 -0.064697265625 +9341 -0.425750732421875 +9342 -0.066131591796875 +9343 -0.435211181640625 +9344 -0.06756591796875 +9345 -0.444610595703125 +9346 -0.069000244140625 +9347 -0.453948974609375 +9348 -0.070404052734375 +9349 -0.4632568359375 +9350 -0.071807861328125 +9351 -0.4725341796875 +9352 -0.073211669921875 +9353 -0.481719970703125 +9354 -0.074615478515625 +9355 -0.490875244140625 +9356 -0.07598876953125 +9357 -0.499969482421875 +9358 -0.077362060546875 +9359 -0.509002685546875 +9360 -0.0787353515625 +9361 -0.51800537109375 +9362 -0.080078125 +9363 -0.52691650390625 +9364 -0.0814208984375 +9365 -0.535797119140625 +9366 -0.082763671875 +9367 -0.54461669921875 +9368 -0.0841064453125 +9369 -0.5533447265625 +9370 -0.085418701171875 +9371 -0.562042236328125 +9372 -0.08673095703125 +9373 -0.5706787109375 +9374 -0.088043212890625 +9375 -0.579254150390625 +9376 -0.089324951171875 +9377 -0.587738037109375 +9378 -0.090606689453125 +9379 -0.59619140625 +9380 -0.091888427734375 +9381 -0.60455322265625 +9382 -0.0931396484375 +9383 -0.612884521484375 +9384 -0.094390869140625 +9385 -0.621124267578125 +9386 -0.09564208984375 +9387 -0.6292724609375 +9388 -0.09686279296875 +9389 -0.63739013671875 +9390 -0.09808349609375 +9391 -0.645416259765625 +9392 -0.09930419921875 +9393 -0.65338134765625 +9394 -0.100494384765625 +9395 -0.661285400390625 +9396 -0.1016845703125 +9397 -0.669097900390625 +9398 -0.102874755859375 +9399 -0.676849365234375 +9400 -0.104034423828125 +9401 -0.68450927734375 +9402 -0.105194091796875 +9403 -0.692108154296875 +9404 -0.1063232421875 +9405 -0.699615478515625 +9406 -0.107452392578125 +9407 -0.707061767578125 +9408 -0.10858154296875 +9409 -0.714447021484375 +9410 -0.10968017578125 +9411 -0.721710205078125 +9412 -0.11077880859375 +9413 -0.72894287109375 +9414 -0.11187744140625 +9415 -0.736053466796875 +9416 -0.112945556640625 +9417 -0.74310302734375 +9418 -0.114013671875 +9419 -0.75006103515625 +9420 -0.11505126953125 +9421 -0.7569580078125 +9422 -0.1160888671875 +9423 -0.763763427734375 +9424 -0.117095947265625 +9425 -0.770477294921875 +9426 -0.11810302734375 +9427 -0.777099609375 +9428 -0.119110107421875 +9429 -0.783660888671875 +9430 -0.120086669921875 +9431 -0.790130615234375 +9432 -0.121063232421875 +9433 -0.796478271484375 +9434 -0.12200927734375 +9435 -0.802764892578125 +9436 -0.122955322265625 +9437 -0.808990478515625 +9438 -0.1239013671875 +9439 -0.815093994140625 +9440 -0.12481689453125 +9441 -0.82110595703125 +9442 -0.125701904296875 +9443 -0.8270263671875 +9444 -0.1265869140625 +9445 -0.8328857421875 +9446 -0.127471923828125 +9447 -0.838623046875 +9448 -0.128326416015625 +9449 -0.84429931640625 +9450 -0.129180908203125 +9451 -0.849853515625 +9452 -0.1300048828125 +9453 -0.855316162109375 +9454 -0.130828857421875 +9455 -0.860687255859375 +9456 -0.131622314453125 +9457 -0.865997314453125 +9458 -0.132415771484375 +9459 -0.871185302734375 +9460 -0.1331787109375 +9461 -0.876251220703125 +9462 -0.133941650390625 +9463 -0.881256103515625 +9464 -0.13470458984375 +9465 -0.88616943359375 +9466 -0.13543701171875 +9467 -0.890960693359375 +9468 -0.136138916015625 +9469 -0.895660400390625 +9470 -0.1368408203125 +9471 -0.9002685546875 +9472 -0.166473388671875 +9473 -0.90478515625 +9474 -0.167266845703125 +9475 -0.9091796875 +9476 -0.168060302734375 +9477 -0.91351318359375 +9478 -0.168853759765625 +9479 -0.917724609375 +9480 -0.169586181640625 +9481 -0.92181396484375 +9482 -0.17034912109375 +9483 -0.92584228515625 +9484 -0.171051025390625 +9485 -0.929718017578125 +9486 -0.1717529296875 +9487 -0.93353271484375 +9488 -0.17242431640625 +9489 -0.937225341796875 +9490 -0.173095703125 +9491 -0.940826416015625 +9492 -0.173736572265625 +9493 -0.9443359375 +9494 -0.174346923828125 +9495 -0.947723388671875 +9496 -0.174957275390625 +9497 -0.951019287109375 +9498 -0.175567626953125 +9499 -0.954193115234375 +9500 -0.176116943359375 +9501 -0.957275390625 +9502 -0.176666259765625 +9503 -0.960235595703125 +9504 -0.17718505859375 +9505 -0.963104248046875 +9506 -0.177703857421875 +9507 -0.96588134765625 +9508 -0.178192138671875 +9509 -0.968536376953125 +9510 -0.17864990234375 +9511 -0.971099853515625 +9512 -0.179107666015625 +9513 -0.973541259765625 +9514 -0.179534912109375 +9515 -0.975860595703125 +9516 -0.179962158203125 +9517 -0.97808837890625 +9518 -0.180328369140625 +9519 -0.980224609375 +9520 -0.18072509765625 +9521 -0.98223876953125 +9522 -0.181060791015625 +9523 -0.984161376953125 +9524 -0.181396484375 +9525 -0.9859619140625 +9526 -0.18170166015625 +9527 -0.987640380859375 +9528 -0.1820068359375 +9529 -0.989227294921875 +9530 -0.182281494140625 +9531 -0.990692138671875 +9532 -0.182525634765625 +9533 -0.9920654296875 +9534 -0.1827392578125 +9535 -0.993316650390625 +9536 -0.182952880859375 +9537 -0.994476318359375 +9538 -0.18316650390625 +9539 -0.995513916015625 +9540 -0.183319091796875 +9541 -0.9964599609375 +9542 -0.1834716796875 +9543 -0.997283935546875 +9544 -0.183624267578125 +9545 -0.99798583984375 +9546 -0.1837158203125 +9547 -0.99859619140625 +9548 -0.183807373046875 +9549 -0.999114990234375 +9550 -0.183868408203125 +9551 -0.999481201171875 +9552 -0.183929443359375 +9553 -0.999755859375 +9554 -0.1839599609375 +9555 -0.99993896484375 +9556 -0.183990478515625 +9557 -1.0 +9558 -0.1839599609375 +9559 -0.99993896484375 +9560 -0.183929443359375 +9561 -0.999755859375 +9562 -0.183868408203125 +9563 -0.999481201171875 +9564 -0.183807373046875 +9565 -0.999114990234375 +9566 -0.1837158203125 +9567 -0.99859619140625 +9568 -0.183624267578125 +9569 -0.99798583984375 +9570 -0.1834716796875 +9571 -0.997283935546875 +9572 -0.183319091796875 +9573 -0.9964599609375 +9574 -0.18316650390625 +9575 -0.995513916015625 +9576 -0.182952880859375 +9577 -0.994476318359375 +9578 -0.1827392578125 +9579 -0.993316650390625 +9580 -0.182525634765625 +9581 -0.9920654296875 +9582 -0.182281494140625 +9583 -0.990692138671875 +9584 -0.1820068359375 +9585 -0.989227294921875 +9586 -0.18170166015625 +9587 -0.987640380859375 +9588 -0.181396484375 +9589 -0.9859619140625 +9590 -0.181060791015625 +9591 -0.984161376953125 +9592 -0.18072509765625 +9593 -0.98223876953125 +9594 -0.180328369140625 +9595 -0.980224609375 +9596 -0.179962158203125 +9597 -0.97808837890625 +9598 -0.179534912109375 +9599 -0.975860595703125 +9600 -0.179107666015625 +9601 -0.973541259765625 +9602 -0.17864990234375 +9603 -0.971099853515625 +9604 -0.178192138671875 +9605 -0.968536376953125 +9606 -0.177703857421875 +9607 -0.96588134765625 +9608 -0.17718505859375 +9609 -0.963104248046875 +9610 -0.176666259765625 +9611 -0.960235595703125 +9612 -0.176116943359375 +9613 -0.957275390625 +9614 -0.175567626953125 +9615 -0.954193115234375 +9616 -0.174957275390625 +9617 -0.951019287109375 +9618 -0.174346923828125 +9619 -0.947723388671875 +9620 -0.173736572265625 +9621 -0.9443359375 +9622 -0.173095703125 +9623 -0.940826416015625 +9624 -0.17242431640625 +9625 -0.937225341796875 +9626 -0.1717529296875 +9627 -0.93353271484375 +9628 -0.171051025390625 +9629 -0.929718017578125 +9630 -0.17034912109375 +9631 -0.92584228515625 +9632 -0.169586181640625 +9633 -0.92181396484375 +9634 -0.168853759765625 +9635 -0.917724609375 +9636 -0.168060302734375 +9637 -0.91351318359375 +9638 -0.167266845703125 +9639 -0.9091796875 +9640 -0.166473388671875 +9641 -0.90478515625 +9642 -0.165618896484375 +9643 -0.9002685546875 +9644 -0.164794921875 +9645 -0.895660400390625 +9646 -0.163909912109375 +9647 -0.890960693359375 +9648 -0.16302490234375 +9649 -0.88616943359375 +9650 -0.162139892578125 +9651 -0.881256103515625 +9652 -0.161224365234375 +9653 -0.876251220703125 +9654 -0.1602783203125 +9655 -0.871185302734375 +9656 -0.159332275390625 +9657 -0.865997314453125 +9658 -0.158355712890625 +9659 -0.860687255859375 +9660 -0.1573486328125 +9661 -0.855316162109375 +9662 -0.156341552734375 +9663 -0.849853515625 +9664 -0.15533447265625 +9665 -0.84429931640625 +9666 -0.154296875 +9667 -0.838623046875 +9668 -0.153228759765625 +9669 -0.8328857421875 +9670 -0.15216064453125 +9671 -0.8270263671875 +9672 -0.15106201171875 +9673 -0.82110595703125 +9674 -0.14996337890625 +9675 -0.815093994140625 +9676 -0.148834228515625 +9677 -0.808990478515625 +9678 -0.147705078125 +9679 -0.802764892578125 +9680 -0.14654541015625 +9681 -0.796478271484375 +9682 -0.145355224609375 +9683 -0.790130615234375 +9684 -0.1441650390625 +9685 -0.783660888671875 +9686 -0.142974853515625 +9687 -0.777099609375 +9688 -0.141754150390625 +9689 -0.770477294921875 +9690 -0.1405029296875 +9691 -0.763763427734375 +9692 -0.139251708984375 +9693 -0.7569580078125 +9694 -0.13800048828125 +9695 -0.75006103515625 +9696 -0.13671875 +9697 -0.74310302734375 +9698 -0.135406494140625 +9699 -0.736053466796875 +9700 -0.13409423828125 +9701 -0.72894287109375 +9702 -0.132781982421875 +9703 -0.721710205078125 +9704 -0.131439208984375 +9705 -0.714447021484375 +9706 -0.130096435546875 +9707 -0.707061767578125 +9708 -0.12872314453125 +9709 -0.699615478515625 +9710 -0.1273193359375 +9711 -0.692108154296875 +9712 -0.125946044921875 +9713 -0.68450927734375 +9714 -0.12451171875 +9715 -0.676849365234375 +9716 -0.12310791015625 +9717 -0.669097900390625 +9718 -0.121673583984375 +9719 -0.661285400390625 +9720 -0.120208740234375 +9721 -0.65338134765625 +9722 -0.118743896484375 +9723 -0.645416259765625 +9724 -0.11724853515625 +9725 -0.63739013671875 +9726 -0.115753173828125 +9727 -0.6292724609375 +9728 -0.12420654296875 +9729 -0.621124267578125 +9730 -0.12255859375 +9731 -0.612884521484375 +9732 -0.120880126953125 +9733 -0.60455322265625 +9734 -0.11920166015625 +9735 -0.59619140625 +9736 -0.117523193359375 +9737 -0.587738037109375 +9738 -0.115814208984375 +9739 -0.579254150390625 +9740 -0.114105224609375 +9741 -0.5706787109375 +9742 -0.112396240234375 +9743 -0.562042236328125 +9744 -0.11065673828125 +9745 -0.5533447265625 +9746 -0.10888671875 +9747 -0.54461669921875 +9748 -0.107147216796875 +9749 -0.535797119140625 +9750 -0.1053466796875 +9751 -0.52691650390625 +9752 -0.10357666015625 +9753 -0.51800537109375 +9754 -0.101776123046875 +9755 -0.509002685546875 +9756 -0.0999755859375 +9757 -0.499969482421875 +9758 -0.09814453125 +9759 -0.490875244140625 +9760 -0.0963134765625 +9761 -0.481719970703125 +9762 -0.094482421875 +9763 -0.4725341796875 +9764 -0.092620849609375 +9765 -0.4632568359375 +9766 -0.09075927734375 +9767 -0.453948974609375 +9768 -0.088897705078125 +9769 -0.444610595703125 +9770 -0.0870361328125 +9771 -0.435211181640625 +9772 -0.08514404296875 +9773 -0.425750732421875 +9774 -0.083221435546875 +9775 -0.416259765625 +9776 -0.081329345703125 +9777 -0.406707763671875 +9778 -0.07940673828125 +9779 -0.397125244140625 +9780 -0.077484130859375 +9781 -0.387481689453125 +9782 -0.075531005859375 +9783 -0.3778076171875 +9784 -0.0736083984375 +9785 -0.36810302734375 +9786 -0.0716552734375 +9787 -0.35833740234375 +9788 -0.0697021484375 +9789 -0.348541259765625 +9790 -0.067718505859375 +9791 -0.338714599609375 +9792 -0.06573486328125 +9793 -0.328826904296875 +9794 -0.06378173828125 +9795 -0.318939208984375 +9796 -0.061767578125 +9797 -0.308990478515625 +9798 -0.059783935546875 +9799 -0.29901123046875 +9800 -0.057769775390625 +9801 -0.28900146484375 +9802 -0.0557861328125 +9803 -0.278961181640625 +9804 -0.05377197265625 +9805 -0.268890380859375 +9806 -0.051727294921875 +9807 -0.2587890625 +9808 -0.049713134765625 +9809 -0.2486572265625 +9810 -0.047698974609375 +9811 -0.238525390625 +9812 -0.045654296875 +9813 -0.22833251953125 +9814 -0.043609619140625 +9815 -0.218109130859375 +9816 -0.04156494140625 +9817 -0.2078857421875 +9818 -0.039520263671875 +9819 -0.1976318359375 +9820 -0.037445068359375 +9821 -0.187347412109375 +9822 -0.035400390625 +9823 -0.17706298828125 +9824 -0.0333251953125 +9825 -0.166748046875 +9826 -0.03125 +9827 -0.156402587890625 +9828 -0.029205322265625 +9829 -0.14605712890625 +9830 -0.027130126953125 +9831 -0.13568115234375 +9832 -0.025054931640625 +9833 -0.12530517578125 +9834 -0.022979736328125 +9835 -0.11492919921875 +9836 -0.0208740234375 +9837 -0.104522705078125 +9838 -0.018798828125 +9839 -0.094085693359375 +9840 -0.0167236328125 +9841 -0.083648681640625 +9842 -0.014617919921875 +9843 -0.073211669921875 +9844 -0.012542724609375 +9845 -0.062774658203125 +9846 -0.01043701171875 +9847 -0.05230712890625 +9848 -0.00836181640625 +9849 -0.0418701171875 +9850 -0.006256103515625 +9851 -0.031402587890625 +9852 -0.004180908203125 +9853 -0.02093505859375 +9854 -0.0020751953125 +9855 -0.010467529296875 +9856 0.0 +9857 0.0 +9858 0.00225830078125 +9859 0.010467529296875 +9860 0.0045166015625 +9861 0.02093505859375 +9862 0.00677490234375 +9863 0.031402587890625 +9864 0.009033203125 +9865 0.0418701171875 +9866 0.01129150390625 +9867 0.05230712890625 +9868 0.0135498046875 +9869 0.062774658203125 +9870 0.01580810546875 +9871 0.073211669921875 +9872 0.01806640625 +9873 0.083648681640625 +9874 0.020294189453125 +9875 0.094085693359375 +9876 0.022552490234375 +9877 0.104522705078125 +9878 0.024810791015625 +9879 0.11492919921875 +9880 0.02703857421875 +9881 0.12530517578125 +9882 0.029296875 +9883 0.13568115234375 +9884 0.031524658203125 +9885 0.14605712890625 +9886 0.033782958984375 +9887 0.156402587890625 +9888 0.0360107421875 +9889 0.166748046875 +9890 0.038238525390625 +9891 0.17706298828125 +9892 0.04046630859375 +9893 0.187347412109375 +9894 0.04266357421875 +9895 0.1976318359375 +9896 0.044891357421875 +9897 0.2078857421875 +9898 0.047088623046875 +9899 0.218109130859375 +9900 0.04931640625 +9901 0.22833251953125 +9902 0.051513671875 +9903 0.238525390625 +9904 0.0537109375 +9905 0.2486572265625 +9906 0.055877685546875 +9907 0.2587890625 +9908 0.058074951171875 +9909 0.268890380859375 +9910 0.06024169921875 +9911 0.278961181640625 +9912 0.062408447265625 +9913 0.28900146484375 +9914 0.0645751953125 +9915 0.29901123046875 +9916 0.066741943359375 +9917 0.308990478515625 +9918 0.068878173828125 +9919 0.318939208984375 +9920 0.071014404296875 +9921 0.328826904296875 +9922 0.073150634765625 +9923 0.338714599609375 +9924 0.075286865234375 +9925 0.348541259765625 +9926 0.077392578125 +9927 0.35833740234375 +9928 0.079498291015625 +9929 0.36810302734375 +9930 0.08160400390625 +9931 0.3778076171875 +9932 0.08367919921875 +9933 0.387481689453125 +9934 0.08575439453125 +9935 0.397125244140625 +9936 0.08782958984375 +9937 0.406707763671875 +9938 0.08990478515625 +9939 0.416259765625 +9940 0.091949462890625 +9941 0.425750732421875 +9942 0.093994140625 +9943 0.435211181640625 +9944 0.096038818359375 +9945 0.444610595703125 +9946 0.098052978515625 +9947 0.453948974609375 +9948 0.100067138671875 +9949 0.4632568359375 +9950 0.10205078125 +9951 0.4725341796875 +9952 0.104034423828125 +9953 0.481719970703125 +9954 0.10601806640625 +9955 0.490875244140625 +9956 0.10797119140625 +9957 0.499969482421875 +9958 0.10992431640625 +9959 0.509002685546875 +9960 0.11187744140625 +9961 0.51800537109375 +9962 0.113800048828125 +9963 0.52691650390625 +9964 0.11572265625 +9965 0.535797119140625 +9966 0.11761474609375 +9967 0.54461669921875 +9968 0.1195068359375 +9969 0.5533447265625 +9970 0.12139892578125 +9971 0.562042236328125 +9972 0.123260498046875 +9973 0.5706787109375 +9974 0.1251220703125 +9975 0.579254150390625 +9976 0.126953125 +9977 0.587738037109375 +9978 0.128753662109375 +9979 0.59619140625 +9980 0.130584716796875 +9981 0.60455322265625 +9982 0.13238525390625 +9983 0.612884521484375 +9984 0.154022216796875 +9985 0.621124267578125 +9986 0.156036376953125 +9987 0.6292724609375 +9988 0.158050537109375 +9989 0.63739013671875 +9990 0.1600341796875 +9991 0.645416259765625 +9992 0.162017822265625 +9993 0.65338134765625 +9994 0.163970947265625 +9995 0.661285400390625 +9996 0.165924072265625 +9997 0.669097900390625 +9998 0.1678466796875 +9999 0.676849365234375 +10000 0.16973876953125 +10001 0.68450927734375 +10002 0.171630859375 +10003 0.692108154296875 +10004 0.173492431640625 +10005 0.699615478515625 +10006 0.175323486328125 +10007 0.707061767578125 +10008 0.177154541015625 +10009 0.714447021484375 +10010 0.178955078125 +10011 0.721710205078125 +10012 0.180755615234375 +10013 0.72894287109375 +10014 0.182525634765625 +10015 0.736053466796875 +10016 0.18426513671875 +10017 0.74310302734375 +10018 0.186004638671875 +10019 0.75006103515625 +10020 0.187713623046875 +10021 0.7569580078125 +10022 0.18939208984375 +10023 0.763763427734375 +10024 0.191070556640625 +10025 0.770477294921875 +10026 0.19268798828125 +10027 0.777099609375 +10028 0.1943359375 +10029 0.783660888671875 +10030 0.1959228515625 +10031 0.790130615234375 +10032 0.197509765625 +10033 0.796478271484375 +10034 0.199066162109375 +10035 0.802764892578125 +10036 0.20062255859375 +10037 0.808990478515625 +10038 0.202117919921875 +10039 0.815093994140625 +10040 0.20361328125 +10041 0.82110595703125 +10042 0.205078125 +10043 0.8270263671875 +10044 0.20654296875 +10045 0.8328857421875 +10046 0.20794677734375 +10047 0.838623046875 +10048 0.2093505859375 +10049 0.84429931640625 +10050 0.21075439453125 +10051 0.849853515625 +10052 0.21209716796875 +10053 0.855316162109375 +10054 0.21343994140625 +10055 0.860687255859375 +10056 0.214752197265625 +10057 0.865997314453125 +10058 0.216033935546875 +10059 0.871185302734375 +10060 0.21728515625 +10061 0.876251220703125 +10062 0.218536376953125 +10063 0.881256103515625 +10064 0.219757080078125 +10065 0.88616943359375 +10066 0.220947265625 +10067 0.890960693359375 +10068 0.22210693359375 +10069 0.895660400390625 +10070 0.223236083984375 +10071 0.9002685546875 +10072 0.224365234375 +10073 0.90478515625 +10074 0.2254638671875 +10075 0.9091796875 +10076 0.226531982421875 +10077 0.91351318359375 +10078 0.227569580078125 +10079 0.917724609375 +10080 0.22857666015625 +10081 0.92181396484375 +10082 0.229583740234375 +10083 0.92584228515625 +10084 0.230560302734375 +10085 0.929718017578125 +10086 0.23150634765625 +10087 0.93353271484375 +10088 0.232421875 +10089 0.937225341796875 +10090 0.233306884765625 +10091 0.940826416015625 +10092 0.234161376953125 +10093 0.9443359375 +10094 0.235015869140625 +10095 0.947723388671875 +10096 0.23583984375 +10097 0.951019287109375 +10098 0.23663330078125 +10099 0.954193115234375 +10100 0.237396240234375 +10101 0.957275390625 +10102 0.238128662109375 +10103 0.960235595703125 +10104 0.23883056640625 +10105 0.963104248046875 +10106 0.239501953125 +10107 0.96588134765625 +10108 0.24017333984375 +10109 0.968536376953125 +10110 0.240814208984375 +10111 0.971099853515625 +10112 0.241424560546875 +10113 0.973541259765625 +10114 0.24200439453125 +10115 0.975860595703125 +10116 0.2425537109375 +10117 0.97808837890625 +10118 0.243072509765625 +10119 0.980224609375 +10120 0.243560791015625 +10121 0.98223876953125 +10122 0.244049072265625 +10123 0.984161376953125 +10124 0.2445068359375 +10125 0.9859619140625 +10126 0.244903564453125 +10127 0.987640380859375 +10128 0.24530029296875 +10129 0.989227294921875 +10130 0.24566650390625 +10131 0.990692138671875 +10132 0.246002197265625 +10133 0.9920654296875 +10134 0.246307373046875 +10135 0.993316650390625 +10136 0.246612548828125 +10137 0.994476318359375 +10138 0.246856689453125 +10139 0.995513916015625 +10140 0.247100830078125 +10141 0.9964599609375 +10142 0.247314453125 +10143 0.997283935546875 +10144 0.247467041015625 +10145 0.99798583984375 +10146 0.24761962890625 +10147 0.99859619140625 +10148 0.24774169921875 +10149 0.999114990234375 +10150 0.247833251953125 +10151 0.999481201171875 +10152 0.2479248046875 +10153 0.999755859375 +10154 0.247955322265625 +10155 0.99993896484375 +10156 0.24798583984375 +10157 0.999969482421875 +10158 0.247955322265625 +10159 0.99993896484375 +10160 0.2479248046875 +10161 0.999755859375 +10162 0.247833251953125 +10163 0.999481201171875 +10164 0.24774169921875 +10165 0.999114990234375 +10166 0.24761962890625 +10167 0.99859619140625 +10168 0.247467041015625 +10169 0.99798583984375 +10170 0.247314453125 +10171 0.997283935546875 +10172 0.247100830078125 +10173 0.9964599609375 +10174 0.246856689453125 +10175 0.995513916015625 +10176 0.246612548828125 +10177 0.994476318359375 +10178 0.246307373046875 +10179 0.993316650390625 +10180 0.246002197265625 +10181 0.9920654296875 +10182 0.24566650390625 +10183 0.990692138671875 +10184 0.24530029296875 +10185 0.989227294921875 +10186 0.244903564453125 +10187 0.987640380859375 +10188 0.2445068359375 +10189 0.9859619140625 +10190 0.244049072265625 +10191 0.984161376953125 +10192 0.243560791015625 +10193 0.98223876953125 +10194 0.243072509765625 +10195 0.980224609375 +10196 0.2425537109375 +10197 0.97808837890625 +10198 0.24200439453125 +10199 0.975860595703125 +10200 0.241424560546875 +10201 0.973541259765625 +10202 0.240814208984375 +10203 0.971099853515625 +10204 0.24017333984375 +10205 0.968536376953125 +10206 0.239501953125 +10207 0.96588134765625 +10208 0.23883056640625 +10209 0.963104248046875 +10210 0.238128662109375 +10211 0.960235595703125 +10212 0.237396240234375 +10213 0.957275390625 +10214 0.23663330078125 +10215 0.954193115234375 +10216 0.23583984375 +10217 0.951019287109375 +10218 0.235015869140625 +10219 0.947723388671875 +10220 0.234161376953125 +10221 0.9443359375 +10222 0.233306884765625 +10223 0.940826416015625 +10224 0.232421875 +10225 0.937225341796875 +10226 0.23150634765625 +10227 0.93353271484375 +10228 0.230560302734375 +10229 0.929718017578125 +10230 0.229583740234375 +10231 0.92584228515625 +10232 0.22857666015625 +10233 0.92181396484375 +10234 0.227569580078125 +10235 0.917724609375 +10236 0.226531982421875 +10237 0.91351318359375 +10238 0.2254638671875 +10239 0.9091796875 +10240 0.0 +10241 0.0 +10242 0.0 +10243 0.0 +10244 0.0 +10245 0.0 +10246 0.0 +10247 0.0 +10248 0.0 +10249 0.0 +10250 0.0 +10251 0.0 +10252 0.0 +10253 0.0 +10254 0.0 +10255 0.0 +10256 0.0 +10257 0.0 +10258 0.0 +10259 0.0 +10260 0.0 +10261 0.0 +10262 0.0 +10263 0.0 +10264 0.0 +10265 0.0 +10266 0.0 +10267 0.0 +10268 0.0 +10269 0.0 +10270 0.0 +10271 0.0 +10272 0.0 +10273 0.0 +10274 0.0 +10275 0.0 +10276 0.0 +10277 0.0 +10278 0.0 +10279 0.0 +10280 0.0 +10281 0.0 +10282 0.0 +10283 0.0 +10284 0.0 +10285 0.0 +10286 0.0 +10287 0.0 +10288 0.0 +10289 0.0 +10290 0.0 +10291 0.0 +10292 0.0 +10293 0.0 +10294 0.0 +10295 0.0 +10296 0.0 +10297 0.0 +10298 0.0 +10299 0.0 +10300 0.0 +10301 0.0 +10302 0.0 +10303 0.0 +10304 0.0 +10305 0.0 +10306 0.0 +10307 0.0 +10308 0.0 +10309 0.0 +10310 0.0 +10311 0.0 +10312 0.0 +10313 0.0 +10314 0.0 +10315 0.0 +10316 0.0 +10317 0.0 +10318 0.0 +10319 0.0 +10320 0.0 +10321 0.0 +10322 0.0 +10323 0.0 +10324 0.0 +10325 0.0 +10326 0.0 +10327 0.0 +10328 0.0 +10329 0.0 +10330 0.0 +10331 0.0 +10332 0.0 +10333 0.0 +10334 0.0 +10335 0.0 +10336 0.0 +10337 0.0 +10338 0.0 +10339 0.0 +10340 0.0 +10341 0.0 +10342 0.0 +10343 0.0 +10344 0.0 +10345 0.0 +10346 0.0 +10347 0.0 +10348 0.0 +10349 0.0 +10350 0.0 +10351 0.0 +10352 0.0 +10353 0.0 +10354 0.0 +10355 0.0 +10356 0.0 +10357 0.0 +10358 0.0 +10359 0.0 +10360 0.0 +10361 0.0 +10362 0.0 +10363 0.0 +10364 0.0 +10365 0.0 +10366 0.0 +10367 0.0 +10368 0.0 +10369 0.0 +10370 0.0 +10371 0.0 +10372 0.0 +10373 0.0 +10374 0.0 +10375 0.0 +10376 0.0 +10377 0.0 +10378 0.0 +10379 0.0 +10380 0.0 +10381 0.0 +10382 0.0 +10383 0.0 +10384 0.0 +10385 0.0 +10386 0.0 +10387 0.0 +10388 0.0 +10389 0.0 +10390 0.0 +10391 0.0 +10392 0.0 +10393 0.0 +10394 0.0 +10395 0.0 +10396 0.0 +10397 0.0 +10398 0.0 +10399 0.0 +10400 0.0 +10401 0.0 +10402 0.0 +10403 0.0 +10404 0.0 +10405 0.0 +10406 0.0 +10407 0.0 +10408 0.0 +10409 0.0 +10410 0.0 +10411 0.0 +10412 0.0 +10413 0.0 +10414 0.0 +10415 0.0 +10416 0.0 +10417 0.0 +10418 0.0 +10419 0.0 +10420 0.0 +10421 0.0 +10422 0.0 +10423 0.0 +10424 0.0 +10425 0.0 +10426 0.0 +10427 0.0 +10428 0.0 +10429 0.0 +10430 0.0 +10431 0.0 +10432 0.0 +10433 0.0 +10434 0.0 +10435 0.0 +10436 0.0 +10437 0.0 +10438 0.0 +10439 0.0 +10440 0.0 +10441 0.0 +10442 0.0 +10443 0.0 +10444 0.0 +10445 0.0 +10446 0.0 +10447 0.0 +10448 0.0 +10449 0.0 +10450 0.0 +10451 0.0 +10452 0.0 +10453 0.0 +10454 0.0 +10455 0.0 +10456 0.0 +10457 0.0 +10458 0.0 +10459 0.0 +10460 0.0 +10461 0.0 +10462 0.0 +10463 0.0 +10464 0.0 +10465 0.0 +10466 0.0 +10467 0.0 +10468 0.0 +10469 0.0 +10470 0.0 +10471 0.0 +10472 0.0 +10473 0.0 +10474 0.0 +10475 0.0 +10476 0.0 +10477 0.0 +10478 0.0 +10479 0.0 +10480 0.0 +10481 0.0 +10482 0.0 +10483 0.0 +10484 0.0 +10485 0.0 +10486 0.0 +10487 0.0 +10488 0.0 +10489 0.0 +10490 0.0 +10491 0.0 +10492 0.0 +10493 0.0 +10494 0.0 +10495 0.0 +10496 0.0 +10497 0.0 +10498 0.0 +10499 0.0 +10500 0.0 +10501 0.0 +10502 0.0 +10503 0.0 +10504 0.0 +10505 0.0 +10506 0.0 +10507 0.0 +10508 0.0 +10509 0.0 +10510 0.0 +10511 0.0 +10512 0.0 +10513 0.0 +10514 0.0 +10515 0.0 +10516 0.0 +10517 0.0 +10518 0.0 +10519 0.0 +10520 0.0 +10521 0.0 +10522 0.0 +10523 0.0 +10524 0.0 +10525 0.0 +10526 0.0 +10527 0.0 +10528 0.0 +10529 0.0 +10530 0.0 +10531 0.0 +10532 0.0 +10533 0.0 +10534 0.0 +10535 0.0 +10536 0.0 +10537 0.0 +10538 0.0 +10539 0.0 +10540 0.0 +10541 0.0 +10542 0.0 +10543 0.0 +10544 0.0 +10545 0.0 +10546 0.0 +10547 0.0 +10548 0.0 +10549 0.0 +10550 0.0 +10551 0.0 +10552 0.0 +10553 0.0 +10554 0.0 +10555 0.0 +10556 0.0 +10557 0.0 +10558 0.0 +10559 0.0 +10560 0.0 +10561 0.0 +10562 0.0 +10563 0.0 +10564 0.0 +10565 0.0 +10566 0.0 +10567 0.0 +10568 0.0 +10569 0.0 +10570 0.0 +10571 0.0 +10572 0.0 +10573 0.0 +10574 0.0 +10575 0.0 +10576 0.0 +10577 0.0 +10578 0.0 +10579 0.0 +10580 0.0 +10581 0.0 +10582 0.0 +10583 0.0 +10584 0.0 +10585 0.0 +10586 0.0 +10587 0.0 +10588 0.0 +10589 0.0 +10590 0.0 +10591 0.0 +10592 0.0 +10593 0.0 +10594 0.0 +10595 0.0 +10596 0.0 +10597 0.0 +10598 0.0 +10599 0.0 +10600 0.0 +10601 0.0 +10602 0.0 +10603 0.0 +10604 0.0 +10605 0.0 +10606 0.0 +10607 0.0 +10608 0.0 +10609 0.0 +10610 0.0 +10611 0.0 +10612 0.0 +10613 0.0 +10614 0.0 +10615 0.0 +10616 0.0 +10617 0.0 +10618 0.0 +10619 0.0 +10620 0.0 +10621 0.0 +10622 0.0 +10623 0.0 +10624 0.0 +10625 0.0 +10626 0.0 +10627 0.0 +10628 0.0 +10629 0.0 +10630 0.0 +10631 0.0 +10632 0.0 +10633 0.0 +10634 0.0 +10635 0.0 +10636 0.0 +10637 0.0 +10638 0.0 +10639 0.0 +10640 0.0 +10641 0.0 +10642 0.0 +10643 0.0 +10644 0.0 +10645 0.0 +10646 0.0 +10647 0.0 +10648 0.0 +10649 0.0 +10650 0.0 +10651 0.0 +10652 0.0 +10653 0.0 +10654 0.0 +10655 0.0 +10656 0.0 +10657 0.0 +10658 0.0 +10659 0.0 +10660 0.0 +10661 0.0 +10662 0.0 +10663 0.0 +10664 0.0 +10665 0.0 +10666 0.0 +10667 0.0 +10668 0.0 +10669 0.0 +10670 0.0 +10671 0.0 +10672 0.0 +10673 0.0 +10674 0.0 +10675 0.0 +10676 0.0 +10677 0.0 +10678 0.0 +10679 0.0 +10680 0.0 +10681 0.0 +10682 0.0 +10683 0.0 +10684 0.0 +10685 0.0 +10686 0.0 +10687 0.0 +10688 0.0 +10689 0.0 +10690 0.0 +10691 0.0 +10692 0.0 +10693 0.0 +10694 0.0 +10695 0.0 +10696 0.0 +10697 0.0 +10698 0.0 +10699 0.0 +10700 0.0 +10701 0.0 +10702 0.0 +10703 0.0 +10704 0.0 +10705 0.0 +10706 0.0 +10707 0.0 +10708 0.0 +10709 0.0 +10710 0.0 +10711 0.0 +10712 0.0 +10713 0.0 +10714 0.0 +10715 0.0 +10716 0.0 +10717 0.0 +10718 0.0 +10719 0.0 +10720 0.0 +10721 0.0 +10722 0.0 +10723 0.0 +10724 0.0 +10725 0.0 +10726 0.0 +10727 0.0 +10728 0.0 +10729 0.0 +10730 0.0 +10731 0.0 +10732 0.0 +10733 0.0 +10734 0.0 +10735 0.0 +10736 0.0 +10737 0.0 +10738 0.0 +10739 0.0 +10740 0.0 +10741 0.0 +10742 0.0 +10743 0.0 +10744 0.0 +10745 0.0 +10746 0.0 +10747 0.0 +10748 0.0 +10749 0.0 +10750 0.0 +10751 0.0 +10752 0.0 +10753 0.0 +10754 0.0 +10755 0.0 +10756 0.0 +10757 0.0 +10758 0.0 +10759 0.0 +10760 0.0 +10761 0.0 +10762 0.0 +10763 0.0 +10764 0.0 +10765 0.0 +10766 0.0 +10767 0.0 +10768 0.0 +10769 0.0 +10770 0.0 +10771 0.0 +10772 0.0 +10773 0.0 +10774 0.0 +10775 0.0 +10776 0.0 +10777 0.0 +10778 0.0 +10779 0.0 +10780 0.0 +10781 0.0 +10782 0.0 +10783 0.0 +10784 0.0 +10785 0.0 +10786 0.0 +10787 0.0 +10788 0.0 +10789 0.0 +10790 0.0 +10791 0.0 +10792 0.0 +10793 0.0 +10794 0.0 +10795 0.0 +10796 0.0 +10797 0.0 +10798 0.0 +10799 0.0 +10800 0.0 +10801 0.0 +10802 0.0 +10803 0.0 +10804 0.0 +10805 0.0 +10806 0.0 +10807 0.0 +10808 0.0 +10809 0.0 +10810 0.0 +10811 0.0 +10812 0.0 +10813 0.0 +10814 0.0 +10815 0.0 +10816 0.0 +10817 0.0 +10818 0.0 +10819 0.0 +10820 0.0 +10821 0.0 +10822 0.0 +10823 0.0 +10824 0.0 +10825 0.0 +10826 0.0 +10827 0.0 +10828 0.0 +10829 0.0 +10830 0.0 +10831 0.0 +10832 0.0 +10833 0.0 +10834 0.0 +10835 0.0 +10836 0.0 +10837 0.0 +10838 0.0 +10839 0.0 +10840 0.0 +10841 0.0 +10842 0.0 +10843 0.0 +10844 0.0 +10845 0.0 +10846 0.0 +10847 0.0 +10848 0.0 +10849 0.0 +10850 0.0 +10851 0.0 +10852 0.0 +10853 0.0 +10854 0.0 +10855 0.0 +10856 0.0 +10857 0.0 +10858 0.0 +10859 0.0 +10860 0.0 +10861 0.0 +10862 0.0 +10863 0.0 +10864 0.0 +10865 0.0 +10866 0.0 +10867 0.0 +10868 0.0 +10869 0.0 +10870 0.0 +10871 0.0 +10872 0.0 +10873 0.0 +10874 0.0 +10875 0.0 +10876 0.0 +10877 0.0 +10878 0.0 +10879 0.0 +10880 0.0 +10881 0.0 +10882 0.0 +10883 0.0 +10884 0.0 +10885 0.0 +10886 0.0 +10887 0.0 +10888 0.0 +10889 0.0 +10890 0.0 +10891 0.0 +10892 0.0 +10893 0.0 +10894 0.0 +10895 0.0 +10896 0.0 +10897 0.0 +10898 0.0 +10899 0.0 +10900 0.0 +10901 0.0 +10902 0.0 +10903 0.0 +10904 0.0 +10905 0.0 +10906 0.0 +10907 0.0 +10908 0.0 +10909 0.0 +10910 0.0 +10911 0.0 +10912 0.0 +10913 0.0 +10914 0.0 +10915 0.0 +10916 0.0 +10917 0.0 +10918 0.0 +10919 0.0 +10920 0.0 +10921 0.0 +10922 0.0 +10923 0.0 +10924 0.0 +10925 0.0 +10926 0.0 +10927 0.0 +10928 0.0 +10929 0.0 +10930 0.0 +10931 0.0 +10932 0.0 +10933 0.0 +10934 0.0 +10935 0.0 +10936 0.0 +10937 0.0 +10938 0.0 +10939 0.0 +10940 0.0 +10941 0.0 +10942 0.0 +10943 0.0 +10944 0.0 +10945 0.0 +10946 0.0 +10947 0.0 +10948 0.0 +10949 0.0 +10950 0.0 +10951 0.0 +10952 0.0 +10953 0.0 +10954 0.0 +10955 0.0 +10956 0.0 +10957 0.0 +10958 0.0 +10959 0.0 +10960 0.0 +10961 0.0 +10962 0.0 +10963 0.0 +10964 0.0 +10965 0.0 +10966 0.0 +10967 0.0 +10968 0.0 +10969 0.0 +10970 0.0 +10971 0.0 +10972 0.0 +10973 0.0 +10974 0.0 +10975 0.0 +10976 0.0 +10977 0.0 +10978 0.0 +10979 0.0 +10980 0.0 +10981 0.0 +10982 0.0 +10983 0.0 +10984 0.0 +10985 0.0 +10986 0.0 +10987 0.0 +10988 0.0 +10989 0.0 +10990 0.0 +10991 0.0 +10992 0.0 +10993 0.0 +10994 0.0 +10995 0.0 +10996 0.0 +10997 0.0 +10998 0.0 +10999 0.0 +11000 0.0 +11001 0.0 +11002 0.0 +11003 0.0 +11004 0.0 +11005 0.0 +11006 0.0 +11007 0.0 +11008 0.0 +11009 0.0 +11010 0.0 +11011 0.0 +11012 0.0 +11013 0.0 +11014 0.0 +11015 0.0 +11016 0.0 +11017 0.0 +11018 0.0 +11019 0.0 +11020 0.0 +11021 0.0 +11022 0.0 +11023 0.0 +11024 0.0 +11025 0.0 +11026 0.0 +11027 0.0 +11028 0.0 +11029 0.0 +11030 0.0 +11031 0.0 +11032 0.0 +11033 0.0 +11034 0.0 +11035 0.0 +11036 0.0 +11037 0.0 +11038 0.0 +11039 0.0 +11040 0.0 +11041 0.0 +11042 0.0 +11043 0.0 +11044 0.0 +11045 0.0 +11046 0.0 +11047 0.0 +11048 0.0 +11049 0.0 +11050 0.0 +11051 0.0 +11052 0.0 +11053 0.0 +11054 0.0 +11055 0.0 +11056 0.0 +11057 0.0 +11058 0.0 +11059 0.0 +11060 0.0 +11061 0.0 +11062 0.0 +11063 0.0 +11064 0.0 +11065 0.0 +11066 0.0 +11067 0.0 +11068 0.0 +11069 0.0 +11070 0.0 +11071 0.0 +11072 0.0 +11073 0.0 +11074 0.0 +11075 0.0 +11076 0.0 +11077 0.0 +11078 0.0 +11079 0.0 +11080 0.0 +11081 0.0 +11082 0.0 +11083 0.0 +11084 0.0 +11085 0.0 +11086 0.0 +11087 0.0 +11088 0.0 +11089 0.0 +11090 0.0 +11091 0.0 +11092 0.0 +11093 0.0 +11094 0.0 +11095 0.0 +11096 0.0 +11097 0.0 +11098 0.0 +11099 0.0 +11100 0.0 +11101 0.0 +11102 0.0 +11103 0.0 +11104 0.0 +11105 0.0 +11106 0.0 +11107 0.0 +11108 0.0 +11109 0.0 +11110 0.0 +11111 0.0 +11112 0.0 +11113 0.0 +11114 0.0 +11115 0.0 +11116 0.0 +11117 0.0 +11118 0.0 +11119 0.0 +11120 0.0 +11121 0.0 +11122 0.0 +11123 0.0 +11124 0.0 +11125 0.0 +11126 0.0 +11127 0.0 +11128 0.0 +11129 0.0 +11130 0.0 +11131 0.0 +11132 0.0 +11133 0.0 +11134 0.0 +11135 0.0 +11136 0.0 +11137 0.0 +11138 0.0 +11139 0.0 +11140 0.0 +11141 0.0 +11142 0.0 +11143 0.0 +11144 0.0 +11145 0.0 +11146 0.0 +11147 0.0 +11148 0.0 +11149 0.0 +11150 0.0 +11151 0.0 +11152 0.0 +11153 0.0 +11154 0.0 +11155 0.0 +11156 0.0 +11157 0.0 +11158 0.0 +11159 0.0 +11160 0.0 +11161 0.0 +11162 0.0 +11163 0.0 +11164 0.0 +11165 0.0 +11166 0.0 +11167 0.0 +11168 0.0 +11169 0.0 +11170 0.0 +11171 0.0 +11172 0.0 +11173 0.0 +11174 0.0 +11175 0.0 +11176 0.0 +11177 0.0 +11178 0.0 +11179 0.0 +11180 0.0 +11181 0.0 +11182 0.0 +11183 0.0 +11184 0.0 +11185 0.0 +11186 0.0 +11187 0.0 +11188 0.0 +11189 0.0 +11190 0.0 +11191 0.0 +11192 0.0 +11193 0.0 +11194 0.0 +11195 0.0 +11196 0.0 +11197 0.0 +11198 0.0 +11199 0.0 +11200 0.0 +11201 0.0 +11202 0.0 +11203 0.0 +11204 0.0 +11205 0.0 +11206 0.0 +11207 0.0 +11208 0.0 +11209 0.0 +11210 0.0 +11211 0.0 +11212 0.0 +11213 0.0 +11214 0.0 +11215 0.0 +11216 0.0 +11217 0.0 +11218 0.0 +11219 0.0 +11220 0.0 +11221 0.0 +11222 0.0 +11223 0.0 +11224 0.0 +11225 0.0 +11226 0.0 +11227 0.0 +11228 0.0 +11229 0.0 +11230 0.0 +11231 0.0 +11232 0.0 +11233 0.0 +11234 0.0 +11235 0.0 +11236 0.0 +11237 0.0 +11238 0.0 +11239 0.0 +11240 0.0 +11241 0.0 +11242 0.0 +11243 0.0 +11244 0.0 +11245 0.0 +11246 0.0 +11247 0.0 +11248 0.0 +11249 0.0 +11250 0.0 +11251 0.0 +11252 0.0 +11253 0.0 +11254 0.0 +11255 0.0 +11256 0.0 +11257 0.0 +11258 0.0 +11259 0.0 +11260 0.0 +11261 0.0 +11262 0.0 +11263 0.0 +11264 0.0 +11265 0.0 +11266 0.0 +11267 0.0 +11268 0.0 +11269 0.0 +11270 0.0 +11271 0.0 +11272 0.0 +11273 0.0 +11274 0.0 +11275 0.0 +11276 0.0 +11277 0.0 +11278 0.0 +11279 0.0 +11280 0.0 +11281 0.0 +11282 0.0 +11283 0.0 +11284 0.0 +11285 0.0 +11286 0.0 +11287 0.0 +11288 0.0 +11289 0.0 +11290 0.0 +11291 0.0 +11292 0.0 +11293 0.0 +11294 0.0 +11295 0.0 +11296 0.0 +11297 0.0 +11298 0.0 +11299 0.0 +11300 0.0 +11301 0.0 +11302 0.0 +11303 0.0 +11304 0.0 +11305 0.0 +11306 0.0 +11307 0.0 +11308 0.0 +11309 0.0 +11310 0.0 +11311 0.0 +11312 0.0 +11313 0.0 +11314 0.0 +11315 0.0 +11316 0.0 +11317 0.0 +11318 0.0 +11319 0.0 +11320 0.0 +11321 0.0 +11322 0.0 +11323 0.0 +11324 0.0 +11325 0.0 +11326 0.0 +11327 0.0 +11328 0.0 +11329 0.0 +11330 0.0 +11331 0.0 +11332 0.0 +11333 0.0 +11334 0.0 +11335 0.0 +11336 0.0 +11337 0.0 +11338 0.0 +11339 0.0 +11340 0.0 +11341 0.0 +11342 0.0 +11343 0.0 +11344 0.0 +11345 0.0 +11346 0.0 +11347 0.0 +11348 0.0 +11349 0.0 +11350 0.0 +11351 0.0 +11352 0.0 +11353 0.0 +11354 0.0 +11355 0.0 +11356 0.0 +11357 0.0 +11358 0.0 +11359 0.0 +11360 0.0 +11361 0.0 +11362 0.0 +11363 0.0 +11364 0.0 +11365 0.0 +11366 0.0 +11367 0.0 +11368 0.0 +11369 0.0 +11370 0.0 +11371 0.0 +11372 0.0 +11373 0.0 +11374 0.0 +11375 0.0 +11376 0.0 +11377 0.0 +11378 0.0 +11379 0.0 +11380 0.0 +11381 0.0 +11382 0.0 +11383 0.0 +11384 0.0 +11385 0.0 +11386 0.0 +11387 0.0 +11388 0.0 +11389 0.0 +11390 0.0 +11391 0.0 +11392 0.0 +11393 0.0 +11394 0.0 +11395 0.0 +11396 0.0 +11397 0.0 +11398 0.0 +11399 0.0 +11400 0.0 +11401 0.0 +11402 0.0 +11403 0.0 +11404 0.0 +11405 0.0 +11406 0.0 +11407 0.0 +11408 0.0 +11409 0.0 +11410 0.0 +11411 0.0 +11412 0.0 +11413 0.0 +11414 0.0 +11415 0.0 +11416 0.0 +11417 0.0 +11418 0.0 +11419 0.0 +11420 0.0 +11421 0.0 +11422 0.0 +11423 0.0 +11424 0.0 +11425 0.0 +11426 0.0 +11427 0.0 +11428 0.0 +11429 0.0 +11430 0.0 +11431 0.0 +11432 0.0 +11433 0.0 +11434 0.0 +11435 0.0 +11436 0.0 +11437 0.0 +11438 0.0 +11439 0.0 +11440 0.0 +11441 0.0 +11442 0.0 +11443 0.0 +11444 0.0 +11445 0.0 +11446 0.0 +11447 0.0 +11448 0.0 +11449 0.0 +11450 0.0 +11451 0.0 +11452 0.0 +11453 0.0 +11454 0.0 +11455 0.0 +11456 0.0 +11457 0.0 +11458 0.0 +11459 0.0 +11460 0.0 +11461 0.0 +11462 0.0 +11463 0.0 +11464 0.0 +11465 0.0 +11466 0.0 +11467 0.0 +11468 0.0 +11469 0.0 +11470 0.0 +11471 0.0 +11472 0.0 +11473 0.0 +11474 0.0 +11475 0.0 +11476 0.0 +11477 0.0 +11478 0.0 +11479 0.0 +11480 0.0 +11481 0.0 +11482 0.0 +11483 0.0 +11484 0.0 +11485 0.0 +11486 0.0 +11487 0.0 +11488 0.0 +11489 0.0 +11490 0.0 +11491 0.0 +11492 0.0 +11493 0.0 +11494 0.0 +11495 0.0 +11496 0.0 +11497 0.0 +11498 0.0 +11499 0.0 +11500 0.0 +11501 0.0 +11502 0.0 +11503 0.0 +11504 0.0 +11505 0.0 +11506 0.0 +11507 0.0 +11508 0.0 +11509 0.0 +11510 0.0 +11511 0.0 +11512 0.0 +11513 0.0 +11514 0.0 +11515 0.0 +11516 0.0 +11517 0.0 +11518 0.0 +11519 0.0 +11520 0.0 +11521 0.0 +11522 0.0 +11523 0.0 +11524 0.0 +11525 0.0 +11526 0.0 +11527 0.0 +11528 0.0 +11529 0.0 +11530 0.0 +11531 0.0 +11532 0.0 +11533 0.0 +11534 0.0 +11535 0.0 +11536 0.0 +11537 0.0 +11538 0.0 +11539 0.0 +11540 0.0 +11541 0.0 +11542 0.0 +11543 0.0 +11544 0.0 +11545 0.0 +11546 0.0 +11547 0.0 +11548 0.0 +11549 0.0 +11550 0.0 +11551 0.0 +11552 0.0 +11553 0.0 +11554 0.0 +11555 0.0 +11556 0.0 +11557 0.0 +11558 0.0 +11559 0.0 +11560 0.0 +11561 0.0 +11562 0.0 +11563 0.0 +11564 0.0 +11565 0.0 +11566 0.0 +11567 0.0 +11568 0.0 +11569 0.0 +11570 0.0 +11571 0.0 +11572 0.0 +11573 0.0 +11574 0.0 +11575 0.0 +11576 0.0 +11577 0.0 +11578 0.0 +11579 0.0 +11580 0.0 +11581 0.0 +11582 0.0 +11583 0.0 +11584 0.0 +11585 0.0 +11586 0.0 +11587 0.0 +11588 0.0 +11589 0.0 +11590 0.0 +11591 0.0 +11592 0.0 +11593 0.0 +11594 0.0 +11595 0.0 +11596 0.0 +11597 0.0 +11598 0.0 +11599 0.0 +11600 0.0 +11601 0.0 +11602 0.0 +11603 0.0 +11604 0.0 +11605 0.0 +11606 0.0 +11607 0.0 +11608 0.0 +11609 0.0 +11610 0.0 +11611 0.0 +11612 0.0 +11613 0.0 +11614 0.0 +11615 0.0 +11616 0.0 +11617 0.0 +11618 0.0 +11619 0.0 +11620 0.0 +11621 0.0 +11622 0.0 +11623 0.0 +11624 0.0 +11625 0.0 +11626 0.0 +11627 0.0 +11628 0.0 +11629 0.0 +11630 0.0 +11631 0.0 +11632 0.0 +11633 0.0 +11634 0.0 +11635 0.0 +11636 0.0 +11637 0.0 +11638 0.0 +11639 0.0 +11640 0.0 +11641 0.0 +11642 0.0 +11643 0.0 +11644 0.0 +11645 0.0 +11646 0.0 +11647 0.0 +11648 0.0 +11649 0.0 +11650 0.0 +11651 0.0 +11652 0.0 +11653 0.0 +11654 0.0 +11655 0.0 +11656 0.0 +11657 0.0 +11658 0.0 +11659 0.0 +11660 0.0 +11661 0.0 +11662 0.0 +11663 0.0 +11664 0.0 +11665 0.0 +11666 0.0 +11667 0.0 +11668 0.0 +11669 0.0 +11670 0.0 +11671 0.0 +11672 0.0 +11673 0.0 +11674 0.0 +11675 0.0 +11676 0.0 +11677 0.0 +11678 0.0 +11679 0.0 +11680 0.0 +11681 0.0 +11682 0.0 +11683 0.0 +11684 0.0 +11685 0.0 +11686 0.0 +11687 0.0 +11688 0.0 +11689 0.0 +11690 0.0 +11691 0.0 +11692 0.0 +11693 0.0 +11694 0.0 +11695 0.0 +11696 0.0 +11697 0.0 +11698 0.0 +11699 0.0 +11700 0.0 +11701 0.0 +11702 0.0 +11703 0.0 +11704 0.0 +11705 0.0 +11706 0.0 +11707 0.0 +11708 0.0 +11709 0.0 +11710 0.0 +11711 0.0 +11712 0.0 +11713 0.0 +11714 0.0 +11715 0.0 +11716 0.0 +11717 0.0 +11718 0.0 +11719 0.0 +11720 0.0 +11721 0.0 +11722 0.0 +11723 0.0 +11724 0.0 +11725 0.0 +11726 0.0 +11727 0.0 +11728 0.0 +11729 0.0 +11730 0.0 +11731 0.0 +11732 0.0 +11733 0.0 +11734 0.0 +11735 0.0 +11736 0.0 +11737 0.0 +11738 0.0 +11739 0.0 +11740 0.0 +11741 0.0 +11742 0.0 +11743 0.0 +11744 0.0 +11745 0.0 +11746 0.0 +11747 0.0 +11748 0.0 +11749 0.0 +11750 0.0 +11751 0.0 +11752 0.0 +11753 0.0 +11754 0.0 +11755 0.0 +11756 0.0 +11757 0.0 +11758 0.0 +11759 0.0 +11760 0.0 +11761 0.0 +11762 0.0 +11763 0.0 +11764 0.0 +11765 0.0 +11766 0.0 +11767 0.0 +11768 0.0 +11769 0.0 +11770 0.0 +11771 0.0 +11772 0.0 +11773 0.0 +11774 0.0 +11775 0.0 +11776 0.0 +11777 0.0 +11778 0.0 +11779 0.0 +11780 0.0 +11781 0.0 +11782 0.0 +11783 0.0 +11784 0.0 +11785 0.0 +11786 0.0 +11787 0.0 +11788 0.0 +11789 0.0 +11790 0.0 +11791 0.0 +11792 0.0 +11793 0.0 +11794 0.0 +11795 0.0 +11796 0.0 +11797 0.0 +11798 0.0 +11799 0.0 +11800 0.0 +11801 0.0 +11802 0.0 +11803 0.0 +11804 0.0 +11805 0.0 +11806 0.0 +11807 0.0 +11808 0.0 +11809 0.0 +11810 0.0 +11811 0.0 +11812 0.0 +11813 0.0 +11814 0.0 +11815 0.0 +11816 0.0 +11817 0.0 +11818 0.0 +11819 0.0 +11820 0.0 +11821 0.0 +11822 0.0 +11823 0.0 +11824 0.0 +11825 0.0 +11826 0.0 +11827 0.0 +11828 0.0 +11829 0.0 +11830 0.0 +11831 0.0 +11832 0.0 +11833 0.0 +11834 0.0 +11835 0.0 +11836 0.0 +11837 0.0 +11838 0.0 +11839 0.0 +11840 0.0 +11841 0.0 +11842 0.0 +11843 0.0 +11844 0.0 +11845 0.0 +11846 0.0 +11847 0.0 +11848 0.0 +11849 0.0 +11850 0.0 +11851 0.0 +11852 0.0 +11853 0.0 +11854 0.0 +11855 0.0 +11856 0.0 +11857 0.0 +11858 0.0 +11859 0.0 +11860 0.0 +11861 0.0 +11862 0.0 +11863 0.0 +11864 0.0 +11865 0.0 +11866 0.0 +11867 0.0 +11868 0.0 +11869 0.0 +11870 0.0 +11871 0.0 +11872 0.0 +11873 0.0 +11874 0.0 +11875 0.0 +11876 0.0 +11877 0.0 +11878 0.0 +11879 0.0 +11880 0.0 +11881 0.0 +11882 0.0 +11883 0.0 +11884 0.0 +11885 0.0 +11886 0.0 +11887 0.0 +11888 0.0 +11889 0.0 +11890 0.0 +11891 0.0 +11892 0.0 +11893 0.0 +11894 0.0 +11895 0.0 +11896 0.0 +11897 0.0 +11898 0.0 +11899 0.0 +11900 0.0 +11901 0.0 +11902 0.0 +11903 0.0 +11904 0.0 +11905 0.0 +11906 0.0 +11907 0.0 +11908 0.0 +11909 0.0 +11910 0.0 +11911 0.0 +11912 0.0 +11913 0.0 +11914 0.0 +11915 0.0 +11916 0.0 +11917 0.0 +11918 0.0 +11919 0.0 +11920 0.0 +11921 0.0 +11922 0.0 +11923 0.0 +11924 0.0 +11925 0.0 +11926 0.0 +11927 0.0 +11928 0.0 +11929 0.0 +11930 0.0 +11931 0.0 +11932 0.0 +11933 0.0 +11934 0.0 +11935 0.0 +11936 0.0 +11937 0.0 +11938 0.0 +11939 0.0 +11940 0.0 +11941 0.0 +11942 0.0 +11943 0.0 +11944 0.0 +11945 0.0 +11946 0.0 +11947 0.0 +11948 0.0 +11949 0.0 +11950 0.0 +11951 0.0 +11952 0.0 +11953 0.0 +11954 0.0 +11955 0.0 +11956 0.0 +11957 0.0 +11958 0.0 +11959 0.0 +11960 0.0 +11961 0.0 +11962 0.0 +11963 0.0 +11964 0.0 +11965 0.0 +11966 0.0 +11967 0.0 +11968 0.0 +11969 0.0 +11970 0.0 +11971 0.0 +11972 0.0 +11973 0.0 +11974 0.0 +11975 0.0 +11976 0.0 +11977 0.0 +11978 0.0 +11979 0.0 +11980 0.0 +11981 0.0 +11982 0.0 +11983 0.0 +11984 0.0 +11985 0.0 +11986 0.0 +11987 0.0 +11988 0.0 +11989 0.0 +11990 0.0 +11991 0.0 +11992 0.0 +11993 0.0 +11994 0.0 +11995 0.0 +11996 0.0 +11997 0.0 +11998 0.0 +11999 0.0 +12000 0.0 +12001 0.0 +12002 0.0 +12003 0.0 +12004 0.0 +12005 0.0 +12006 0.0 +12007 0.0 +12008 0.0 +12009 0.0 +12010 0.0 +12011 0.0 +12012 0.0 +12013 0.0 +12014 0.0 +12015 0.0 +12016 0.0 +12017 0.0 +12018 0.0 +12019 0.0 +12020 0.0 +12021 0.0 +12022 0.0 +12023 0.0 +12024 0.0 +12025 0.0 +12026 0.0 +12027 0.0 +12028 0.0 +12029 0.0 +12030 0.0 +12031 0.0 +12032 0.0 +12033 0.0 +12034 0.0 +12035 0.0 +12036 0.0 +12037 0.0 +12038 0.0 +12039 0.0 +12040 0.0 +12041 0.0 +12042 0.0 +12043 0.0 +12044 0.0 +12045 0.0 +12046 0.0 +12047 0.0 +12048 0.0 +12049 0.0 +12050 0.0 +12051 0.0 +12052 0.0 +12053 0.0 +12054 0.0 +12055 0.0 +12056 0.0 +12057 0.0 +12058 0.0 +12059 0.0 +12060 0.0 +12061 0.0 +12062 0.0 +12063 0.0 +12064 0.0 +12065 0.0 +12066 0.0 +12067 0.0 +12068 0.0 +12069 0.0 +12070 0.0 +12071 0.0 +12072 0.0 +12073 0.0 +12074 0.0 +12075 0.0 +12076 0.0 +12077 0.0 +12078 0.0 +12079 0.0 +12080 0.0 +12081 0.0 +12082 0.0 +12083 0.0 +12084 0.0 +12085 0.0 +12086 0.0 +12087 0.0 +12088 0.0 +12089 0.0 +12090 0.0 +12091 0.0 +12092 0.0 +12093 0.0 +12094 0.0 +12095 0.0 +12096 0.0 +12097 0.0 +12098 0.0 +12099 0.0 +12100 0.0 +12101 0.0 +12102 0.0 +12103 0.0 +12104 0.0 +12105 0.0 +12106 0.0 +12107 0.0 +12108 0.0 +12109 0.0 +12110 0.0 +12111 0.0 +12112 0.0 +12113 0.0 +12114 0.0 +12115 0.0 +12116 0.0 +12117 0.0 +12118 0.0 +12119 0.0 +12120 0.0 +12121 0.0 +12122 0.0 +12123 0.0 +12124 0.0 +12125 0.0 +12126 0.0 +12127 0.0 +12128 0.0 +12129 0.0 +12130 0.0 +12131 0.0 +12132 0.0 +12133 0.0 +12134 0.0 +12135 0.0 +12136 0.0 +12137 0.0 +12138 0.0 +12139 0.0 +12140 0.0 +12141 0.0 +12142 0.0 +12143 0.0 +12144 0.0 +12145 0.0 +12146 0.0 +12147 0.0 +12148 0.0 +12149 0.0 +12150 0.0 +12151 0.0 +12152 0.0 +12153 0.0 +12154 0.0 +12155 0.0 +12156 0.0 +12157 0.0 +12158 0.0 +12159 0.0 +12160 0.0 +12161 0.0 +12162 0.0 +12163 0.0 +12164 0.0 +12165 0.0 +12166 0.0 +12167 0.0 +12168 0.0 +12169 0.0 +12170 0.0 +12171 0.0 +12172 0.0 +12173 0.0 +12174 0.0 +12175 0.0 +12176 0.0 +12177 0.0 +12178 0.0 +12179 0.0 +12180 0.0 +12181 0.0 +12182 0.0 +12183 0.0 +12184 0.0 +12185 0.0 +12186 0.0 +12187 0.0 +12188 0.0 +12189 0.0 +12190 0.0 +12191 0.0 +12192 0.0 +12193 0.0 +12194 0.0 +12195 0.0 +12196 0.0 +12197 0.0 +12198 0.0 +12199 0.0 +12200 0.0 +12201 0.0 +12202 0.0 +12203 0.0 +12204 0.0 +12205 0.0 +12206 0.0 +12207 0.0 +12208 0.0 +12209 0.0 +12210 0.0 +12211 0.0 +12212 0.0 +12213 0.0 +12214 0.0 +12215 0.0 +12216 0.0 +12217 0.0 +12218 0.0 +12219 0.0 +12220 0.0 +12221 0.0 +12222 0.0 +12223 0.0 +12224 0.0 +12225 0.0 +12226 0.0 +12227 0.0 +12228 0.0 +12229 0.0 +12230 0.0 +12231 0.0 +12232 0.0 +12233 0.0 +12234 0.0 +12235 0.0 +12236 0.0 +12237 0.0 +12238 0.0 +12239 0.0 +12240 0.0 +12241 0.0 +12242 0.0 +12243 0.0 +12244 0.0 +12245 0.0 +12246 0.0 +12247 0.0 +12248 0.0 +12249 0.0 +12250 0.0 +12251 0.0 +12252 0.0 +12253 0.0 +12254 0.0 +12255 0.0 +12256 0.0 +12257 0.0 +12258 0.0 +12259 0.0 +12260 0.0 +12261 0.0 +12262 0.0 +12263 0.0 +12264 0.0 +12265 0.0 +12266 0.0 +12267 0.0 +12268 0.0 +12269 0.0 +12270 0.0 +12271 0.0 +12272 0.0 +12273 0.0 +12274 0.0 +12275 0.0 +12276 0.0 +12277 0.0 +12278 0.0 +12279 0.0 +12280 0.0 +12281 0.0 +12282 0.0 +12283 0.0 +12284 0.0 +12285 0.0 +12286 0.0 +12287 0.0 +12288 0.0 +12289 0.0 +12290 0.0 +12291 0.0 +12292 0.0 +12293 0.0 +12294 0.0 +12295 0.0 +12296 0.0 +12297 0.0 +12298 0.0 +12299 0.0 +12300 0.0 +12301 0.0 +12302 0.0 +12303 0.0 +12304 0.0 +12305 0.0 +12306 0.0 +12307 0.0 +12308 0.0 +12309 0.0 +12310 0.0 +12311 0.0 +12312 0.0 +12313 0.0 +12314 0.0 +12315 0.0 +12316 0.0 +12317 0.0 +12318 0.0 +12319 0.0 +12320 0.0 +12321 0.0 +12322 0.0 +12323 0.0 +12324 0.0 +12325 0.0 +12326 0.0 +12327 0.0 +12328 0.0 +12329 0.0 +12330 0.0 +12331 0.0 +12332 0.0 +12333 0.0 +12334 0.0 +12335 0.0 +12336 0.0 +12337 0.0 +12338 0.0 +12339 0.0 +12340 0.0 +12341 0.0 +12342 0.0 +12343 0.0 +12344 0.0 +12345 0.0 +12346 0.0 +12347 0.0 +12348 0.0 +12349 0.0 +12350 0.0 +12351 0.0 +12352 0.0 +12353 0.0 +12354 0.0 +12355 0.0 +12356 0.0 +12357 0.0 +12358 0.0 +12359 0.0 +12360 0.0 +12361 0.0 +12362 0.0 +12363 0.0 +12364 0.0 +12365 0.0 +12366 0.0 +12367 0.0 +12368 0.0 +12369 0.0 +12370 0.0 +12371 0.0 +12372 0.0 +12373 0.0 +12374 0.0 +12375 0.0 +12376 0.0 +12377 0.0 +12378 0.0 +12379 0.0 +12380 0.0 +12381 0.0 +12382 0.0 +12383 0.0 +12384 0.0 +12385 0.0 +12386 0.0 +12387 0.0 +12388 0.0 +12389 0.0 +12390 0.0 +12391 0.0 +12392 0.0 +12393 0.0 +12394 0.0 +12395 0.0 +12396 0.0 +12397 0.0 +12398 0.0 +12399 0.0 +12400 0.0 +12401 0.0 +12402 0.0 +12403 0.0 +12404 0.0 +12405 0.0 +12406 0.0 +12407 0.0 +12408 0.0 +12409 0.0 +12410 0.0 +12411 0.0 +12412 0.0 +12413 0.0 +12414 0.0 +12415 0.0 +12416 0.0 +12417 0.0 +12418 0.0 +12419 0.0 +12420 0.0 +12421 0.0 +12422 0.0 +12423 0.0 +12424 0.0 +12425 0.0 +12426 0.0 +12427 0.0 +12428 0.0 +12429 0.0 +12430 0.0 +12431 0.0 +12432 0.0 +12433 0.0 +12434 0.0 +12435 0.0 +12436 0.0 +12437 0.0 +12438 0.0 +12439 0.0 +12440 0.0 +12441 0.0 +12442 0.0 +12443 0.0 +12444 0.0 +12445 0.0 +12446 0.0 +12447 0.0 +12448 0.0 +12449 0.0 +12450 0.0 +12451 0.0 +12452 0.0 +12453 0.0 +12454 0.0 +12455 0.0 +12456 0.0 +12457 0.0 +12458 0.0 +12459 0.0 +12460 0.0 +12461 0.0 +12462 0.0 +12463 0.0 +12464 0.0 +12465 0.0 +12466 0.0 +12467 0.0 +12468 0.0 +12469 0.0 +12470 0.0 +12471 0.0 +12472 0.0 +12473 0.0 +12474 0.0 +12475 0.0 +12476 0.0 +12477 0.0 +12478 0.0 +12479 0.0 +12480 0.0 +12481 0.0 +12482 0.0 +12483 0.0 +12484 0.0 +12485 0.0 +12486 0.0 +12487 0.0 +12488 0.0 +12489 0.0 +12490 0.0 +12491 0.0 +12492 0.0 +12493 0.0 +12494 0.0 +12495 0.0 +12496 0.0 +12497 0.0 +12498 0.0 +12499 0.0 +12500 0.0 +12501 0.0 +12502 0.0 +12503 0.0 +12504 0.0 +12505 0.0 +12506 0.0 +12507 0.0 +12508 0.0 +12509 0.0 +12510 0.0 +12511 0.0 +12512 0.0 +12513 0.0 +12514 0.0 +12515 0.0 +12516 0.0 +12517 0.0 +12518 0.0 +12519 0.0 +12520 0.0 +12521 0.0 +12522 0.0 +12523 0.0 +12524 0.0 +12525 0.0 +12526 0.0 +12527 0.0 +12528 0.0 +12529 0.0 +12530 0.0 +12531 0.0 +12532 0.0 +12533 0.0 +12534 0.0 +12535 0.0 +12536 0.0 +12537 0.0 +12538 0.0 +12539 0.0 +12540 0.0 +12541 0.0 +12542 0.0 +12543 0.0 +12544 0.0 +12545 0.0 +12546 0.0 +12547 0.0 +12548 0.0 +12549 0.0 +12550 0.0 +12551 0.0 +12552 0.0 +12553 0.0 +12554 0.0 +12555 0.0 +12556 0.0 +12557 0.0 +12558 0.0 +12559 0.0 +12560 0.0 +12561 0.0 +12562 0.0 +12563 0.0 +12564 0.0 +12565 0.0 +12566 0.0 +12567 0.0 +12568 0.0 +12569 0.0 +12570 0.0 +12571 0.0 +12572 0.0 +12573 0.0 +12574 0.0 +12575 0.0 +12576 0.0 +12577 0.0 +12578 0.0 +12579 0.0 +12580 0.0 +12581 0.0 +12582 0.0 +12583 0.0 +12584 0.0 +12585 0.0 +12586 0.0 +12587 0.0 +12588 0.0 +12589 0.0 +12590 0.0 +12591 0.0 +12592 0.0 +12593 0.0 +12594 0.0 +12595 0.0 +12596 0.0 +12597 0.0 +12598 0.0 +12599 0.0 +12600 0.0 +12601 0.0 +12602 0.0 +12603 0.0 +12604 0.0 +12605 0.0 +12606 0.0 +12607 0.0 +12608 0.0 +12609 0.0 +12610 0.0 +12611 0.0 +12612 0.0 +12613 0.0 +12614 0.0 +12615 0.0 +12616 0.0 +12617 0.0 +12618 0.0 +12619 0.0 +12620 0.0 +12621 0.0 +12622 0.0 +12623 0.0 +12624 0.0 +12625 0.0 +12626 0.0 +12627 0.0 +12628 0.0 +12629 0.0 +12630 0.0 +12631 0.0 +12632 0.0 +12633 0.0 +12634 0.0 +12635 0.0 +12636 0.0 +12637 0.0 +12638 0.0 +12639 0.0 +12640 0.0 +12641 0.0 +12642 0.0 +12643 0.0 +12644 0.0 +12645 0.0 +12646 0.0 +12647 0.0 +12648 0.0 +12649 0.0 +12650 0.0 +12651 0.0 +12652 0.0 +12653 0.0 +12654 0.0 +12655 0.0 +12656 0.0 +12657 0.0 +12658 0.0 +12659 0.0 +12660 0.0 +12661 0.0 +12662 0.0 +12663 0.0 +12664 0.0 +12665 0.0 +12666 0.0 +12667 0.0 +12668 0.0 +12669 0.0 +12670 0.0 +12671 0.0 +12672 0.0 +12673 0.0 +12674 0.0 +12675 0.0 +12676 0.0 +12677 0.0 +12678 0.0 +12679 0.0 +12680 0.0 +12681 0.0 +12682 0.0 +12683 0.0 +12684 0.0 +12685 0.0 +12686 0.0 +12687 0.0 +12688 0.0 +12689 0.0 +12690 0.0 +12691 0.0 +12692 0.0 +12693 0.0 +12694 0.0 +12695 0.0 +12696 0.0 +12697 0.0 +12698 0.0 +12699 0.0 +12700 0.0 +12701 0.0 +12702 0.0 +12703 0.0 +12704 0.0 +12705 0.0 +12706 0.0 +12707 0.0 +12708 0.0 +12709 0.0 +12710 0.0 +12711 0.0 +12712 0.0 +12713 0.0 +12714 0.0 +12715 0.0 +12716 0.0 +12717 0.0 +12718 0.0 +12719 0.0 +12720 0.0 +12721 0.0 +12722 0.0 +12723 0.0 +12724 0.0 +12725 0.0 +12726 0.0 +12727 0.0 +12728 0.0 +12729 0.0 +12730 0.0 +12731 0.0 +12732 0.0 +12733 0.0 +12734 0.0 +12735 0.0 +12736 0.0 +12737 0.0 +12738 0.0 +12739 0.0 +12740 0.0 +12741 0.0 +12742 0.0 +12743 0.0 +12744 0.0 +12745 0.0 +12746 0.0 +12747 0.0 +12748 0.0 +12749 0.0 +12750 0.0 +12751 0.0 +12752 0.0 +12753 0.0 +12754 0.0 +12755 0.0 +12756 0.0 +12757 0.0 +12758 0.0 +12759 0.0 +12760 0.0 +12761 0.0 +12762 0.0 +12763 0.0 +12764 0.0 +12765 0.0 +12766 0.0 +12767 0.0 +12768 0.0 +12769 0.0 +12770 0.0 +12771 0.0 +12772 0.0 +12773 0.0 +12774 0.0 +12775 0.0 +12776 0.0 +12777 0.0 +12778 0.0 +12779 0.0 +12780 0.0 +12781 0.0 +12782 0.0 +12783 0.0 +12784 0.0 +12785 0.0 +12786 0.0 +12787 0.0 +12788 0.0 +12789 0.0 +12790 0.0 +12791 0.0 +12792 0.0 +12793 0.0 +12794 0.0 +12795 0.0 +12796 0.0 +12797 0.0 +12798 0.0 +12799 0.0 +12800 0.0 +12801 0.0 +12802 0.0 +12803 0.0 +12804 0.0 +12805 0.0 +12806 0.0 +12807 0.0 +12808 0.0 +12809 0.0 +12810 0.0 +12811 0.0 +12812 0.0 +12813 0.0 +12814 0.0 +12815 0.0 +12816 0.0 +12817 0.0 +12818 0.0 +12819 0.0 +12820 0.0 +12821 0.0 +12822 0.0 +12823 0.0 +12824 0.0 +12825 0.0 +12826 0.0 +12827 0.0 +12828 0.0 +12829 0.0 +12830 0.0 +12831 0.0 +12832 0.0 +12833 0.0 +12834 0.0 +12835 0.0 +12836 0.0 +12837 0.0 +12838 0.0 +12839 0.0 +12840 0.0 +12841 0.0 +12842 0.0 +12843 0.0 +12844 0.0 +12845 0.0 +12846 0.0 +12847 0.0 +12848 0.0 +12849 0.0 +12850 0.0 +12851 0.0 +12852 0.0 +12853 0.0 +12854 0.0 +12855 0.0 +12856 0.0 +12857 0.0 +12858 0.0 +12859 0.0 +12860 0.0 +12861 0.0 +12862 0.0 +12863 0.0 +12864 0.0 +12865 0.0 +12866 0.0 +12867 0.0 +12868 0.0 +12869 0.0 +12870 0.0 +12871 0.0 +12872 0.0 +12873 0.0 +12874 0.0 +12875 0.0 +12876 0.0 +12877 0.0 +12878 0.0 +12879 0.0 +12880 0.0 +12881 0.0 +12882 0.0 +12883 0.0 +12884 0.0 +12885 0.0 +12886 0.0 +12887 0.0 +12888 0.0 +12889 0.0 +12890 0.0 +12891 0.0 +12892 0.0 +12893 0.0 +12894 0.0 +12895 0.0 +12896 0.0 +12897 0.0 +12898 0.0 +12899 0.0 +12900 0.0 +12901 0.0 +12902 0.0 +12903 0.0 +12904 0.0 +12905 0.0 +12906 0.0 +12907 0.0 +12908 0.0 +12909 0.0 +12910 0.0 +12911 0.0 +12912 0.0 +12913 0.0 +12914 0.0 +12915 0.0 +12916 0.0 +12917 0.0 +12918 0.0 +12919 0.0 +12920 0.0 +12921 0.0 +12922 0.0 +12923 0.0 +12924 0.0 +12925 0.0 +12926 0.0 +12927 0.0 +12928 0.0 +12929 0.0 +12930 0.0 +12931 0.0 +12932 0.0 +12933 0.0 +12934 0.0 +12935 0.0 +12936 0.0 +12937 0.0 +12938 0.0 +12939 0.0 +12940 0.0 +12941 0.0 +12942 0.0 +12943 0.0 +12944 0.0 +12945 0.0 +12946 0.0 +12947 0.0 +12948 0.0 +12949 0.0 +12950 0.0 +12951 0.0 +12952 0.0 +12953 0.0 +12954 0.0 +12955 0.0 +12956 0.0 +12957 0.0 +12958 0.0 +12959 0.0 +12960 0.0 +12961 0.0 +12962 0.0 +12963 0.0 +12964 0.0 +12965 0.0 +12966 0.0 +12967 0.0 +12968 0.0 +12969 0.0 +12970 0.0 +12971 0.0 +12972 0.0 +12973 0.0 +12974 0.0 +12975 0.0 +12976 0.0 +12977 0.0 +12978 0.0 +12979 0.0 +12980 0.0 +12981 0.0 +12982 0.0 +12983 0.0 +12984 0.0 +12985 0.0 +12986 0.0 +12987 0.0 +12988 0.0 +12989 0.0 +12990 0.0 +12991 0.0 +12992 0.0 +12993 0.0 +12994 0.0 +12995 0.0 +12996 0.0 +12997 0.0 +12998 0.0 +12999 0.0 +13000 0.0 +13001 0.0 +13002 0.0 +13003 0.0 +13004 0.0 +13005 0.0 +13006 0.0 +13007 0.0 +13008 0.0 +13009 0.0 +13010 0.0 +13011 0.0 +13012 0.0 +13013 0.0 +13014 0.0 +13015 0.0 +13016 0.0 +13017 0.0 +13018 0.0 +13019 0.0 +13020 0.0 +13021 0.0 +13022 0.0 +13023 0.0 +13024 0.0 +13025 0.0 +13026 0.0 +13027 0.0 +13028 0.0 +13029 0.0 +13030 0.0 +13031 0.0 +13032 0.0 +13033 0.0 +13034 0.0 +13035 0.0 +13036 0.0 +13037 0.0 +13038 0.0 +13039 0.0 +13040 0.0 +13041 0.0 +13042 0.0 +13043 0.0 +13044 0.0 +13045 0.0 +13046 0.0 +13047 0.0 +13048 0.0 +13049 0.0 +13050 0.0 +13051 0.0 +13052 0.0 +13053 0.0 +13054 0.0 +13055 0.0 +13056 0.0 +13057 0.0 +13058 0.0 +13059 0.0 +13060 0.0 +13061 0.0 +13062 0.0 +13063 0.0 +13064 0.0 +13065 0.0 +13066 0.0 +13067 0.0 +13068 0.0 +13069 0.0 +13070 0.0 +13071 0.0 +13072 0.0 +13073 0.0 +13074 0.0 +13075 0.0 +13076 0.0 +13077 0.0 +13078 0.0 +13079 0.0 +13080 0.0 +13081 0.0 +13082 0.0 +13083 0.0 +13084 0.0 +13085 0.0 +13086 0.0 +13087 0.0 +13088 0.0 +13089 0.0 +13090 0.0 +13091 0.0 +13092 0.0 +13093 0.0 +13094 0.0 +13095 0.0 +13096 0.0 +13097 0.0 +13098 0.0 +13099 0.0 +13100 0.0 +13101 0.0 +13102 0.0 +13103 0.0 +13104 0.0 +13105 0.0 +13106 0.0 +13107 0.0 +13108 0.0 +13109 0.0 +13110 0.0 +13111 0.0 +13112 0.0 +13113 0.0 +13114 0.0 +13115 0.0 +13116 0.0 +13117 0.0 +13118 0.0 +13119 0.0 +13120 0.0 +13121 0.0 +13122 0.0 +13123 0.0 +13124 0.0 +13125 0.0 +13126 0.0 +13127 0.0 +13128 0.0 +13129 0.0 +13130 0.0 +13131 0.0 +13132 0.0 +13133 0.0 +13134 0.0 +13135 0.0 +13136 0.0 +13137 0.0 +13138 0.0 +13139 0.0 +13140 0.0 +13141 0.0 +13142 0.0 +13143 0.0 +13144 0.0 +13145 0.0 +13146 0.0 +13147 0.0 +13148 0.0 +13149 0.0 +13150 0.0 +13151 0.0 +13152 0.0 +13153 0.0 +13154 0.0 +13155 0.0 +13156 0.0 +13157 0.0 +13158 0.0 +13159 0.0 +13160 0.0 +13161 0.0 +13162 0.0 +13163 0.0 +13164 0.0 +13165 0.0 +13166 0.0 +13167 0.0 +13168 0.0 +13169 0.0 +13170 0.0 +13171 0.0 +13172 0.0 +13173 0.0 +13174 0.0 +13175 0.0 +13176 0.0 +13177 0.0 +13178 0.0 +13179 0.0 +13180 0.0 +13181 0.0 +13182 0.0 +13183 0.0 +13184 0.0 +13185 0.0 +13186 0.0 +13187 0.0 +13188 0.0 +13189 0.0 +13190 0.0 +13191 0.0 +13192 0.0 +13193 0.0 +13194 0.0 +13195 0.0 +13196 0.0 +13197 0.0 +13198 0.0 +13199 0.0 +13200 0.0 +13201 0.0 +13202 0.0 +13203 0.0 +13204 0.0 +13205 0.0 +13206 0.0 +13207 0.0 +13208 0.0 +13209 0.0 +13210 0.0 +13211 0.0 +13212 0.0 +13213 0.0 +13214 0.0 +13215 0.0 +13216 0.0 +13217 0.0 +13218 0.0 +13219 0.0 +13220 0.0 +13221 0.0 +13222 0.0 +13223 0.0 +13224 0.0 +13225 0.0 +13226 0.0 +13227 0.0 +13228 0.0 +13229 0.0 +13230 0.0 +13231 0.0 +13232 0.0 +13233 0.0 +13234 0.0 +13235 0.0 +13236 0.0 +13237 0.0 +13238 0.0 +13239 0.0 +13240 0.0 +13241 0.0 +13242 0.0 +13243 0.0 +13244 0.0 +13245 0.0 +13246 0.0 +13247 0.0 +13248 0.0 +13249 0.0 +13250 0.0 +13251 0.0 +13252 0.0 +13253 0.0 +13254 0.0 +13255 0.0 +13256 0.0 +13257 0.0 +13258 0.0 +13259 0.0 +13260 0.0 +13261 0.0 +13262 0.0 +13263 0.0 +13264 0.0 +13265 0.0 +13266 0.0 +13267 0.0 +13268 0.0 +13269 0.0 +13270 0.0 +13271 0.0 +13272 0.0 +13273 0.0 +13274 0.0 +13275 0.0 +13276 0.0 +13277 0.0 +13278 0.0 +13279 0.0 +13280 0.0 +13281 0.0 +13282 0.0 +13283 0.0 +13284 0.0 +13285 0.0 +13286 0.0 +13287 0.0 +13288 0.0 +13289 0.0 +13290 0.0 +13291 0.0 +13292 0.0 +13293 0.0 +13294 0.0 +13295 0.0 +13296 0.0 +13297 0.0 +13298 0.0 +13299 0.0 +13300 0.0 +13301 0.0 +13302 0.0 +13303 0.0 +13304 0.0 +13305 0.0 +13306 0.0 +13307 0.0 +13308 0.0 +13309 0.0 +13310 0.0 +13311 0.0 +13312 0.0 +13313 0.0 +13314 0.0 +13315 0.0 +13316 0.0 +13317 0.0 +13318 0.0 +13319 0.0 +13320 0.0 +13321 0.0 +13322 0.0 +13323 0.0 +13324 0.0 +13325 0.0 +13326 0.0 +13327 0.0 +13328 0.0 +13329 0.0 +13330 0.0 +13331 0.0 +13332 0.0 +13333 0.0 +13334 0.0 +13335 0.0 +13336 0.0 +13337 0.0 +13338 0.0 +13339 0.0 +13340 0.0 +13341 0.0 +13342 0.0 +13343 0.0 +13344 0.0 +13345 0.0 +13346 0.0 +13347 0.0 +13348 0.0 +13349 0.0 +13350 0.0 +13351 0.0 +13352 0.0 +13353 0.0 +13354 0.0 +13355 0.0 +13356 0.0 +13357 0.0 +13358 0.0 +13359 0.0 +13360 0.0 +13361 0.0 +13362 0.0 +13363 0.0 +13364 0.0 +13365 0.0 +13366 0.0 +13367 0.0 +13368 0.0 +13369 0.0 +13370 0.0 +13371 0.0 +13372 0.0 +13373 0.0 +13374 0.0 +13375 0.0 +13376 0.0 +13377 0.0 +13378 0.0 +13379 0.0 +13380 0.0 +13381 0.0 +13382 0.0 +13383 0.0 +13384 0.0 +13385 0.0 +13386 0.0 +13387 0.0 +13388 0.0 +13389 0.0 +13390 0.0 +13391 0.0 +13392 0.0 +13393 0.0 +13394 0.0 +13395 0.0 +13396 0.0 +13397 0.0 +13398 0.0 +13399 0.0 +13400 0.0 +13401 0.0 +13402 0.0 +13403 0.0 +13404 0.0 +13405 0.0 +13406 0.0 +13407 0.0 +13408 0.0 +13409 0.0 +13410 0.0 +13411 0.0 +13412 0.0 +13413 0.0 +13414 0.0 +13415 0.0 +13416 0.0 +13417 0.0 +13418 0.0 +13419 0.0 +13420 0.0 +13421 0.0 +13422 0.0 +13423 0.0 +13424 0.0 +13425 0.0 +13426 0.0 +13427 0.0 +13428 0.0 +13429 0.0 +13430 0.0 +13431 0.0 +13432 0.0 +13433 0.0 +13434 0.0 +13435 0.0 +13436 0.0 +13437 0.0 +13438 0.0 +13439 0.0 +13440 0.0 +13441 0.0 +13442 0.0 +13443 0.0 +13444 0.0 +13445 0.0 +13446 0.0 +13447 0.0 +13448 0.0 +13449 0.0 +13450 0.0 +13451 0.0 +13452 0.0 +13453 0.0 +13454 0.0 +13455 0.0 +13456 0.0 +13457 0.0 +13458 0.0 +13459 0.0 +13460 0.0 +13461 0.0 +13462 0.0 +13463 0.0 +13464 0.0 +13465 0.0 +13466 0.0 +13467 0.0 +13468 0.0 +13469 0.0 +13470 0.0 +13471 0.0 +13472 0.0 +13473 0.0 +13474 0.0 +13475 0.0 +13476 0.0 +13477 0.0 +13478 0.0 +13479 0.0 +13480 0.0 +13481 0.0 +13482 0.0 +13483 0.0 +13484 0.0 +13485 0.0 +13486 0.0 +13487 0.0 +13488 0.0 +13489 0.0 +13490 0.0 +13491 0.0 +13492 0.0 +13493 0.0 +13494 0.0 +13495 0.0 +13496 0.0 +13497 0.0 +13498 0.0 +13499 0.0 +13500 0.0 +13501 0.0 +13502 0.0 +13503 0.0 +13504 0.0 +13505 0.0 +13506 0.0 +13507 0.0 +13508 0.0 +13509 0.0 +13510 0.0 +13511 0.0 +13512 0.0 +13513 0.0 +13514 0.0 +13515 0.0 +13516 0.0 +13517 0.0 +13518 0.0 +13519 0.0 +13520 0.0 +13521 0.0 +13522 0.0 +13523 0.0 +13524 0.0 +13525 0.0 +13526 0.0 +13527 0.0 +13528 0.0 +13529 0.0 +13530 0.0 +13531 0.0 +13532 0.0 +13533 0.0 +13534 0.0 +13535 0.0 +13536 0.0 +13537 0.0 +13538 0.0 +13539 0.0 +13540 0.0 +13541 0.0 +13542 0.0 +13543 0.0 +13544 0.0 +13545 0.0 +13546 0.0 +13547 0.0 +13548 0.0 +13549 0.0 +13550 0.0 +13551 0.0 +13552 0.0 +13553 0.0 +13554 0.0 +13555 0.0 +13556 0.0 +13557 0.0 +13558 0.0 +13559 0.0 +13560 0.0 +13561 0.0 +13562 0.0 +13563 0.0 +13564 0.0 +13565 0.0 +13566 0.0 +13567 0.0 +13568 0.0 +13569 0.0 +13570 0.0 +13571 0.0 +13572 0.0 +13573 0.0 +13574 0.0 +13575 0.0 +13576 0.0 +13577 0.0 +13578 0.0 +13579 0.0 +13580 0.0 +13581 0.0 +13582 0.0 +13583 0.0 +13584 0.0 +13585 0.0 +13586 0.0 +13587 0.0 +13588 0.0 +13589 0.0 +13590 0.0 +13591 0.0 +13592 0.0 +13593 0.0 +13594 0.0 +13595 0.0 +13596 0.0 +13597 0.0 +13598 0.0 +13599 0.0 +13600 0.0 +13601 0.0 +13602 0.0 +13603 0.0 +13604 0.0 +13605 0.0 +13606 0.0 +13607 0.0 +13608 0.0 +13609 0.0 +13610 0.0 +13611 0.0 +13612 0.0 +13613 0.0 +13614 0.0 +13615 0.0 +13616 0.0 +13617 0.0 +13618 0.0 +13619 0.0 +13620 0.0 +13621 0.0 +13622 0.0 +13623 0.0 +13624 0.0 +13625 0.0 +13626 0.0 +13627 0.0 +13628 0.0 +13629 0.0 +13630 0.0 +13631 0.0 +13632 0.0 +13633 0.0 +13634 0.0 +13635 0.0 +13636 0.0 +13637 0.0 +13638 0.0 +13639 0.0 +13640 0.0 +13641 0.0 +13642 0.0 +13643 0.0 +13644 0.0 +13645 0.0 +13646 0.0 +13647 0.0 +13648 0.0 +13649 0.0 +13650 0.0 +13651 0.0 +13652 0.0 +13653 0.0 +13654 0.0 +13655 0.0 +13656 0.0 +13657 0.0 +13658 0.0 +13659 0.0 +13660 0.0 +13661 0.0 +13662 0.0 +13663 0.0 +13664 0.0 +13665 0.0 +13666 0.0 +13667 0.0 +13668 0.0 +13669 0.0 +13670 0.0 +13671 0.0 +13672 0.0 +13673 0.0 +13674 0.0 +13675 0.0 +13676 0.0 +13677 0.0 +13678 0.0 +13679 0.0 +13680 0.0 +13681 0.0 +13682 0.0 +13683 0.0 +13684 0.0 +13685 0.0 +13686 0.0 +13687 0.0 +13688 0.0 +13689 0.0 +13690 0.0 +13691 0.0 +13692 0.0 +13693 0.0 +13694 0.0 +13695 0.0 +13696 0.0 +13697 0.0 +13698 0.0 +13699 0.0 +13700 0.0 +13701 0.0 +13702 0.0 +13703 0.0 +13704 0.0 +13705 0.0 +13706 0.0 +13707 0.0 +13708 0.0 +13709 0.0 +13710 0.0 +13711 0.0 +13712 0.0 +13713 0.0 +13714 0.0 +13715 0.0 +13716 0.0 +13717 0.0 +13718 0.0 +13719 0.0 +13720 0.0 +13721 0.0 +13722 0.0 +13723 0.0 +13724 0.0 +13725 0.0 +13726 0.0 +13727 0.0 +13728 0.0 +13729 0.0 +13730 0.0 +13731 0.0 +13732 0.0 +13733 0.0 +13734 0.0 +13735 0.0 +13736 0.0 +13737 0.0 +13738 0.0 +13739 0.0 +13740 0.0 +13741 0.0 +13742 0.0 +13743 0.0 +13744 0.0 +13745 0.0 +13746 0.0 +13747 0.0 +13748 0.0 +13749 0.0 +13750 0.0 +13751 0.0 +13752 0.0 +13753 0.0 +13754 0.0 +13755 0.0 +13756 0.0 +13757 0.0 +13758 0.0 +13759 0.0 +13760 0.0 +13761 0.0 +13762 0.0 +13763 0.0 +13764 0.0 +13765 0.0 +13766 0.0 +13767 0.0 +13768 0.0 +13769 0.0 +13770 0.0 +13771 0.0 +13772 0.0 +13773 0.0 +13774 0.0 +13775 0.0 +13776 0.0 +13777 0.0 +13778 0.0 +13779 0.0 +13780 0.0 +13781 0.0 +13782 0.0 +13783 0.0 +13784 0.0 +13785 0.0 +13786 0.0 +13787 0.0 +13788 0.0 +13789 0.0 +13790 0.0 +13791 0.0 +13792 0.0 +13793 0.0 +13794 0.0 +13795 0.0 +13796 0.0 +13797 0.0 +13798 0.0 +13799 0.0 +13800 0.0 +13801 0.0 +13802 0.0 +13803 0.0 +13804 0.0 +13805 0.0 +13806 0.0 +13807 0.0 +13808 0.0 +13809 0.0 +13810 0.0 +13811 0.0 +13812 0.0 +13813 0.0 +13814 0.0 +13815 0.0 +13816 0.0 +13817 0.0 +13818 0.0 +13819 0.0 +13820 0.0 +13821 0.0 +13822 0.0 +13823 0.0 +13824 0.0 +13825 0.0 +13826 0.0 +13827 0.0 +13828 0.0 +13829 0.0 +13830 0.0 +13831 0.0 +13832 0.0 +13833 0.0 +13834 0.0 +13835 0.0 +13836 0.0 +13837 0.0 +13838 0.0 +13839 0.0 +13840 0.0 +13841 0.0 +13842 0.0 +13843 0.0 +13844 0.0 +13845 0.0 +13846 0.0 +13847 0.0 +13848 0.0 +13849 0.0 +13850 0.0 +13851 0.0 +13852 0.0 +13853 0.0 +13854 0.0 +13855 0.0 +13856 0.0 +13857 0.0 +13858 0.0 +13859 0.0 +13860 0.0 +13861 0.0 +13862 0.0 +13863 0.0 +13864 0.0 +13865 0.0 +13866 0.0 +13867 0.0 +13868 0.0 +13869 0.0 +13870 0.0 +13871 0.0 +13872 0.0 +13873 0.0 +13874 0.0 +13875 0.0 +13876 0.0 +13877 0.0 +13878 0.0 +13879 0.0 +13880 0.0 +13881 0.0 +13882 0.0 +13883 0.0 +13884 0.0 +13885 0.0 +13886 0.0 +13887 0.0 +13888 0.0 +13889 0.0 +13890 0.0 +13891 0.0 +13892 0.0 +13893 0.0 +13894 0.0 +13895 0.0 +13896 0.0 +13897 0.0 +13898 0.0 +13899 0.0 +13900 0.0 +13901 0.0 +13902 0.0 +13903 0.0 +13904 0.0 +13905 0.0 +13906 0.0 +13907 0.0 +13908 0.0 +13909 0.0 +13910 0.0 +13911 0.0 +13912 0.0 +13913 0.0 +13914 0.0 +13915 0.0 +13916 0.0 +13917 0.0 +13918 0.0 +13919 0.0 +13920 0.0 +13921 0.0 +13922 0.0 +13923 0.0 +13924 0.0 +13925 0.0 +13926 0.0 +13927 0.0 +13928 0.0 +13929 0.0 +13930 0.0 +13931 0.0 +13932 0.0 +13933 0.0 +13934 0.0 +13935 0.0 +13936 0.0 +13937 0.0 +13938 0.0 +13939 0.0 +13940 0.0 +13941 0.0 +13942 0.0 +13943 0.0 +13944 0.0 +13945 0.0 +13946 0.0 +13947 0.0 +13948 0.0 +13949 0.0 +13950 0.0 +13951 0.0 +13952 0.0 +13953 0.0 +13954 0.0 +13955 0.0 +13956 0.0 +13957 0.0 +13958 0.0 +13959 0.0 +13960 0.0 +13961 0.0 +13962 0.0 +13963 0.0 +13964 0.0 +13965 0.0 +13966 0.0 +13967 0.0 +13968 0.0 +13969 0.0 +13970 0.0 +13971 0.0 +13972 0.0 +13973 0.0 +13974 0.0 +13975 0.0 +13976 0.0 +13977 0.0 +13978 0.0 +13979 0.0 +13980 0.0 +13981 0.0 +13982 0.0 +13983 0.0 +13984 0.0 +13985 0.0 +13986 0.0 +13987 0.0 +13988 0.0 +13989 0.0 +13990 0.0 +13991 0.0 +13992 0.0 +13993 0.0 +13994 0.0 +13995 0.0 +13996 0.0 +13997 0.0 +13998 0.0 +13999 0.0 +14000 0.0 +14001 0.0 +14002 0.0 +14003 0.0 +14004 0.0 +14005 0.0 +14006 0.0 +14007 0.0 +14008 0.0 +14009 0.0 +14010 0.0 +14011 0.0 +14012 0.0 +14013 0.0 +14014 0.0 +14015 0.0 +14016 0.0 +14017 0.0 +14018 0.0 +14019 0.0 +14020 0.0 +14021 0.0 +14022 0.0 +14023 0.0 +14024 0.0 +14025 0.0 +14026 0.0 +14027 0.0 +14028 0.0 +14029 0.0 +14030 0.0 +14031 0.0 +14032 0.0 +14033 0.0 +14034 0.0 +14035 0.0 +14036 0.0 +14037 0.0 +14038 0.0 +14039 0.0 +14040 0.0 +14041 0.0 +14042 0.0 +14043 0.0 +14044 0.0 +14045 0.0 +14046 0.0 +14047 0.0 +14048 0.0 +14049 0.0 +14050 0.0 +14051 0.0 +14052 0.0 +14053 0.0 +14054 0.0 +14055 0.0 +14056 0.0 +14057 0.0 +14058 0.0 +14059 0.0 +14060 0.0 +14061 0.0 +14062 0.0 +14063 0.0 +14064 0.0 +14065 0.0 +14066 0.0 +14067 0.0 +14068 0.0 +14069 0.0 +14070 0.0 +14071 0.0 +14072 0.0 +14073 0.0 +14074 0.0 +14075 0.0 +14076 0.0 +14077 0.0 +14078 0.0 +14079 0.0 +14080 0.0 +14081 0.0 +14082 0.0 +14083 0.0 +14084 0.0 +14085 0.0 +14086 0.0 +14087 0.0 +14088 0.0 +14089 0.0 +14090 0.0 +14091 0.0 +14092 0.0 +14093 0.0 +14094 0.0 +14095 0.0 +14096 0.0 +14097 0.0 +14098 0.0 +14099 0.0 +14100 0.0 +14101 0.0 +14102 0.0 +14103 0.0 +14104 0.0 +14105 0.0 +14106 0.0 +14107 0.0 +14108 0.0 +14109 0.0 +14110 0.0 +14111 0.0 +14112 0.0 +14113 0.0 +14114 0.0 +14115 0.0 +14116 0.0 +14117 0.0 +14118 0.0 +14119 0.0 +14120 0.0 +14121 0.0 +14122 0.0 +14123 0.0 +14124 0.0 +14125 0.0 +14126 0.0 +14127 0.0 +14128 0.0 +14129 0.0 +14130 0.0 +14131 0.0 +14132 0.0 +14133 0.0 +14134 0.0 +14135 0.0 +14136 0.0 +14137 0.0 +14138 0.0 +14139 0.0 +14140 0.0 +14141 0.0 +14142 0.0 +14143 0.0 +14144 0.0 +14145 0.0 +14146 0.0 +14147 0.0 +14148 0.0 +14149 0.0 +14150 0.0 +14151 0.0 +14152 0.0 +14153 0.0 +14154 0.0 +14155 0.0 +14156 0.0 +14157 0.0 +14158 0.0 +14159 0.0 +14160 0.0 +14161 0.0 +14162 0.0 +14163 0.0 +14164 0.0 +14165 0.0 +14166 0.0 +14167 0.0 +14168 0.0 +14169 0.0 +14170 0.0 +14171 0.0 +14172 0.0 +14173 0.0 +14174 0.0 +14175 0.0 +14176 0.0 +14177 0.0 +14178 0.0 +14179 0.0 +14180 0.0 +14181 0.0 +14182 0.0 +14183 0.0 +14184 0.0 +14185 0.0 +14186 0.0 +14187 0.0 +14188 0.0 +14189 0.0 +14190 0.0 +14191 0.0 +14192 0.0 +14193 0.0 +14194 0.0 +14195 0.0 +14196 0.0 +14197 0.0 +14198 0.0 +14199 0.0 +14200 0.0 +14201 0.0 +14202 0.0 +14203 0.0 +14204 0.0 +14205 0.0 +14206 0.0 +14207 0.0 +14208 0.0 +14209 0.0 +14210 0.0 +14211 0.0 +14212 0.0 +14213 0.0 +14214 0.0 +14215 0.0 +14216 0.0 +14217 0.0 +14218 0.0 +14219 0.0 +14220 0.0 +14221 0.0 +14222 0.0 +14223 0.0 +14224 0.0 +14225 0.0 +14226 0.0 +14227 0.0 +14228 0.0 +14229 0.0 +14230 0.0 +14231 0.0 +14232 0.0 +14233 0.0 +14234 0.0 +14235 0.0 +14236 0.0 +14237 0.0 +14238 0.0 +14239 0.0 +14240 0.0 +14241 0.0 +14242 0.0 +14243 0.0 +14244 0.0 +14245 0.0 +14246 0.0 +14247 0.0 +14248 0.0 +14249 0.0 +14250 0.0 +14251 0.0 +14252 0.0 +14253 0.0 +14254 0.0 +14255 0.0 +14256 0.0 +14257 0.0 +14258 0.0 +14259 0.0 +14260 0.0 +14261 0.0 +14262 0.0 +14263 0.0 +14264 0.0 +14265 0.0 +14266 0.0 +14267 0.0 +14268 0.0 +14269 0.0 +14270 0.0 +14271 0.0 +14272 0.0 +14273 0.0 +14274 0.0 +14275 0.0 +14276 0.0 +14277 0.0 +14278 0.0 +14279 0.0 +14280 0.0 +14281 0.0 +14282 0.0 +14283 0.0 +14284 0.0 +14285 0.0 +14286 0.0 +14287 0.0 +14288 0.0 +14289 0.0 +14290 0.0 +14291 0.0 +14292 0.0 +14293 0.0 +14294 0.0 +14295 0.0 +14296 0.0 +14297 0.0 +14298 0.0 +14299 0.0 +14300 0.0 +14301 0.0 +14302 0.0 +14303 0.0 +14304 0.0 +14305 0.0 +14306 0.0 +14307 0.0 +14308 0.0 +14309 0.0 +14310 0.0 +14311 0.0 +14312 0.0 +14313 0.0 +14314 0.0 +14315 0.0 +14316 0.0 +14317 0.0 +14318 0.0 +14319 0.0 +14320 0.0 +14321 0.0 +14322 0.0 +14323 0.0 +14324 0.0 +14325 0.0 +14326 0.0 +14327 0.0 +14328 0.0 +14329 0.0 +14330 0.0 +14331 0.0 +14332 0.0 +14333 0.0 +14334 0.0 +14335 0.0 +14336 0.0 +14337 0.0 +14338 0.0 +14339 0.0 +14340 0.0 +14341 0.0 +14342 0.0 +14343 0.0 +14344 0.0 +14345 0.0 +14346 0.0 +14347 0.0 +14348 0.0 +14349 0.0 +14350 0.0 +14351 0.0 +14352 0.0 +14353 0.0 +14354 0.0 +14355 0.0 +14356 0.0 +14357 0.0 +14358 0.0 +14359 0.0 +14360 0.0 +14361 0.0 +14362 0.0 +14363 0.0 +14364 0.0 +14365 0.0 +14366 0.0 +14367 0.0 +14368 0.0 +14369 0.0 +14370 0.0 +14371 0.0 +14372 0.0 +14373 0.0 +14374 0.0 +14375 0.0 +14376 0.0 +14377 0.0 +14378 0.0 +14379 0.0 +14380 0.0 +14381 0.0 +14382 0.0 +14383 0.0 +14384 0.0 +14385 0.0 +14386 0.0 +14387 0.0 +14388 0.0 +14389 0.0 +14390 0.0 +14391 0.0 +14392 0.0 +14393 0.0 +14394 0.0 +14395 0.0 +14396 0.0 +14397 0.0 +14398 0.0 +14399 0.0 +14400 0.0 +14401 0.0 +14402 0.0 +14403 0.0 +14404 0.0 +14405 0.0 +14406 0.0 +14407 0.0 +14408 0.0 +14409 0.0 +14410 0.0 +14411 0.0 +14412 0.0 +14413 0.0 +14414 0.0 +14415 0.0 +14416 0.0 +14417 0.0 +14418 0.0 +14419 0.0 +14420 0.0 +14421 0.0 +14422 0.0 +14423 0.0 +14424 0.0 +14425 0.0 +14426 0.0 +14427 0.0 +14428 0.0 +14429 0.0 +14430 0.0 +14431 0.0 +14432 0.0 +14433 0.0 +14434 0.0 +14435 0.0 +14436 0.0 +14437 0.0 +14438 0.0 +14439 0.0 +14440 0.0 +14441 0.0 +14442 0.0 +14443 0.0 +14444 0.0 +14445 0.0 +14446 0.0 +14447 0.0 +14448 0.0 +14449 0.0 +14450 0.0 +14451 0.0 +14452 0.0 +14453 0.0 +14454 0.0 +14455 0.0 +14456 0.0 +14457 0.0 +14458 0.0 +14459 0.0 +14460 0.0 +14461 0.0 +14462 0.0 +14463 0.0 +14464 0.0 +14465 0.0 +14466 0.0 +14467 0.0 +14468 0.0 +14469 0.0 +14470 0.0 +14471 0.0 +14472 0.0 +14473 0.0 +14474 0.0 +14475 0.0 +14476 0.0 +14477 0.0 +14478 0.0 +14479 0.0 +14480 0.0 +14481 0.0 +14482 0.0 +14483 0.0 +14484 0.0 +14485 0.0 +14486 0.0 +14487 0.0 +14488 0.0 +14489 0.0 +14490 0.0 +14491 0.0 +14492 0.0 +14493 0.0 +14494 0.0 +14495 0.0 +14496 0.0 +14497 0.0 +14498 0.0 +14499 0.0 +14500 0.0 +14501 0.0 +14502 0.0 +14503 0.0 +14504 0.0 +14505 0.0 +14506 0.0 +14507 0.0 +14508 0.0 +14509 0.0 +14510 0.0 +14511 0.0 +14512 0.0 +14513 0.0 +14514 0.0 +14515 0.0 +14516 0.0 +14517 0.0 +14518 0.0 +14519 0.0 +14520 0.0 +14521 0.0 +14522 0.0 +14523 0.0 +14524 0.0 +14525 0.0 +14526 0.0 +14527 0.0 +14528 0.0 +14529 0.0 +14530 0.0 +14531 0.0 +14532 0.0 +14533 0.0 +14534 0.0 +14535 0.0 +14536 0.0 +14537 0.0 +14538 0.0 +14539 0.0 +14540 0.0 +14541 0.0 +14542 0.0 +14543 0.0 +14544 0.0 +14545 0.0 +14546 0.0 +14547 0.0 +14548 0.0 +14549 0.0 +14550 0.0 +14551 0.0 +14552 0.0 +14553 0.0 +14554 0.0 +14555 0.0 +14556 0.0 +14557 0.0 +14558 0.0 +14559 0.0 +14560 0.0 +14561 0.0 +14562 0.0 +14563 0.0 +14564 0.0 +14565 0.0 +14566 0.0 +14567 0.0 +14568 0.0 +14569 0.0 +14570 0.0 +14571 0.0 +14572 0.0 +14573 0.0 +14574 0.0 +14575 0.0 +14576 0.0 +14577 0.0 +14578 0.0 +14579 0.0 +14580 0.0 +14581 0.0 +14582 0.0 +14583 0.0 +14584 0.0 +14585 0.0 +14586 0.0 +14587 0.0 +14588 0.0 +14589 0.0 +14590 0.0 +14591 0.0 +14592 0.0 +14593 0.0 +14594 0.0 +14595 0.0 +14596 0.0 +14597 0.0 +14598 0.0 +14599 0.0 +14600 0.0 +14601 0.0 +14602 0.0 +14603 0.0 +14604 0.0 +14605 0.0 +14606 0.0 +14607 0.0 +14608 0.0 +14609 0.0 +14610 0.0 +14611 0.0 +14612 0.0 +14613 0.0 +14614 0.0 +14615 0.0 +14616 0.0 +14617 0.0 +14618 0.0 +14619 0.0 +14620 0.0 +14621 0.0 +14622 0.0 +14623 0.0 +14624 0.0 +14625 0.0 +14626 0.0 +14627 0.0 +14628 0.0 +14629 0.0 +14630 0.0 +14631 0.0 +14632 0.0 +14633 0.0 +14634 0.0 +14635 0.0 +14636 0.0 +14637 0.0 +14638 0.0 +14639 0.0 +14640 0.0 +14641 0.0 +14642 0.0 +14643 0.0 +14644 0.0 +14645 0.0 +14646 0.0 +14647 0.0 +14648 0.0 +14649 0.0 +14650 0.0 +14651 0.0 +14652 0.0 +14653 0.0 +14654 0.0 +14655 0.0 +14656 0.0 +14657 0.0 +14658 0.0 +14659 0.0 +14660 0.0 +14661 0.0 +14662 0.0 +14663 0.0 +14664 0.0 +14665 0.0 +14666 0.0 +14667 0.0 +14668 0.0 +14669 0.0 +14670 0.0 +14671 0.0 +14672 0.0 +14673 0.0 +14674 0.0 +14675 0.0 +14676 0.0 +14677 0.0 +14678 0.0 +14679 0.0 +14680 0.0 +14681 0.0 +14682 0.0 +14683 0.0 +14684 0.0 +14685 0.0 +14686 0.0 +14687 0.0 +14688 0.0 +14689 0.0 +14690 0.0 +14691 0.0 +14692 0.0 +14693 0.0 +14694 0.0 +14695 0.0 +14696 0.0 +14697 0.0 +14698 0.0 +14699 0.0 +14700 0.0 +14701 0.0 +14702 0.0 +14703 0.0 +14704 0.0 +14705 0.0 +14706 0.0 +14707 0.0 +14708 0.0 +14709 0.0 +14710 0.0 +14711 0.0 +14712 0.0 +14713 0.0 +14714 0.0 +14715 0.0 +14716 0.0 +14717 0.0 +14718 0.0 +14719 0.0 +14720 0.0 +14721 0.0 +14722 0.0 +14723 0.0 +14724 0.0 +14725 0.0 +14726 0.0 +14727 0.0 +14728 0.0 +14729 0.0 +14730 0.0 +14731 0.0 +14732 0.0 +14733 0.0 +14734 0.0 +14735 0.0 +14736 0.0 +14737 0.0 +14738 0.0 +14739 0.0 +14740 0.0 +14741 0.0 +14742 0.0 +14743 0.0 +14744 0.0 +14745 0.0 +14746 0.0 +14747 0.0 +14748 0.0 +14749 0.0 +14750 0.0 +14751 0.0 +14752 0.0 +14753 0.0 +14754 0.0 +14755 0.0 +14756 0.0 +14757 0.0 +14758 0.0 +14759 0.0 +14760 0.0 +14761 0.0 +14762 0.0 +14763 0.0 +14764 0.0 +14765 0.0 +14766 0.0 +14767 0.0 +14768 0.0 +14769 0.0 +14770 0.0 +14771 0.0 +14772 0.0 +14773 0.0 +14774 0.0 +14775 0.0 +14776 0.0 +14777 0.0 +14778 0.0 +14779 0.0 +14780 0.0 +14781 0.0 +14782 0.0 +14783 0.0 +14784 0.0 +14785 0.0 +14786 0.0 +14787 0.0 +14788 0.0 +14789 0.0 +14790 0.0 +14791 0.0 +14792 0.0 +14793 0.0 +14794 0.0 +14795 0.0 +14796 0.0 +14797 0.0 +14798 0.0 +14799 0.0 +14800 0.0 +14801 0.0 +14802 0.0 +14803 0.0 +14804 0.0 +14805 0.0 +14806 0.0 +14807 0.0 +14808 0.0 +14809 0.0 +14810 0.0 +14811 0.0 +14812 0.0 +14813 0.0 +14814 0.0 +14815 0.0 +14816 0.0 +14817 0.0 +14818 0.0 +14819 0.0 +14820 0.0 +14821 0.0 +14822 0.0 +14823 0.0 +14824 0.0 +14825 0.0 +14826 0.0 +14827 0.0 +14828 0.0 +14829 0.0 +14830 0.0 +14831 0.0 +14832 0.0 +14833 0.0 +14834 0.0 +14835 0.0 +14836 0.0 +14837 0.0 +14838 0.0 +14839 0.0 +14840 0.0 +14841 0.0 +14842 0.0 +14843 0.0 +14844 0.0 +14845 0.0 +14846 0.0 +14847 0.0 +14848 0.0 +14849 0.0 +14850 0.0 +14851 0.0 +14852 0.0 +14853 0.0 +14854 0.0 +14855 0.0 +14856 0.0 +14857 0.0 +14858 0.0 +14859 0.0 +14860 0.0 +14861 0.0 +14862 0.0 +14863 0.0 +14864 0.0 +14865 0.0 +14866 0.0 +14867 0.0 +14868 0.0 +14869 0.0 +14870 0.0 +14871 0.0 +14872 0.0 +14873 0.0 +14874 0.0 +14875 0.0 +14876 0.0 +14877 0.0 +14878 0.0 +14879 0.0 +14880 0.0 +14881 0.0 +14882 0.0 +14883 0.0 +14884 0.0 +14885 0.0 +14886 0.0 +14887 0.0 +14888 0.0 +14889 0.0 +14890 0.0 +14891 0.0 +14892 0.0 +14893 0.0 +14894 0.0 +14895 0.0 +14896 0.0 +14897 0.0 +14898 0.0 +14899 0.0 +14900 0.0 +14901 0.0 +14902 0.0 +14903 0.0 +14904 0.0 +14905 0.0 +14906 0.0 +14907 0.0 +14908 0.0 +14909 0.0 +14910 0.0 +14911 0.0 +14912 0.0 +14913 0.0 +14914 0.0 +14915 0.0 +14916 0.0 +14917 0.0 +14918 0.0 +14919 0.0 +14920 0.0 +14921 0.0 +14922 0.0 +14923 0.0 +14924 0.0 +14925 0.0 +14926 0.0 +14927 0.0 +14928 0.0 +14929 0.0 +14930 0.0 +14931 0.0 +14932 0.0 +14933 0.0 +14934 0.0 +14935 0.0 +14936 0.0 +14937 0.0 +14938 0.0 +14939 0.0 +14940 0.0 +14941 0.0 +14942 0.0 +14943 0.0 +14944 0.0 +14945 0.0 +14946 0.0 +14947 0.0 +14948 0.0 +14949 0.0 +14950 0.0 +14951 0.0 +14952 0.0 +14953 0.0 +14954 0.0 +14955 0.0 +14956 0.0 +14957 0.0 +14958 0.0 +14959 0.0 +14960 0.0 +14961 0.0 +14962 0.0 +14963 0.0 +14964 0.0 +14965 0.0 +14966 0.0 +14967 0.0 +14968 0.0 +14969 0.0 +14970 0.0 +14971 0.0 +14972 0.0 +14973 0.0 +14974 0.0 +14975 0.0 +14976 0.0 +14977 0.0 +14978 0.0 +14979 0.0 +14980 0.0 +14981 0.0 +14982 0.0 +14983 0.0 +14984 0.0 +14985 0.0 +14986 0.0 +14987 0.0 +14988 0.0 +14989 0.0 +14990 0.0 +14991 0.0 +14992 0.0 +14993 0.0 +14994 0.0 +14995 0.0 +14996 0.0 +14997 0.0 +14998 0.0 +14999 0.0 +15000 0.0 +15001 0.0 +15002 0.0 +15003 0.0 +15004 0.0 +15005 0.0 +15006 0.0 +15007 0.0 +15008 0.0 +15009 0.0 +15010 0.0 +15011 0.0 +15012 0.0 +15013 0.0 +15014 0.0 +15015 0.0 +15016 0.0 +15017 0.0 +15018 0.0 +15019 0.0 +15020 0.0 +15021 0.0 +15022 0.0 +15023 0.0 +15024 0.0 +15025 0.0 +15026 0.0 +15027 0.0 +15028 0.0 +15029 0.0 +15030 0.0 +15031 0.0 +15032 0.0 +15033 0.0 +15034 0.0 +15035 0.0 +15036 0.0 +15037 0.0 +15038 0.0 +15039 0.0 +15040 0.0 +15041 0.0 +15042 0.0 +15043 0.0 +15044 0.0 +15045 0.0 +15046 0.0 +15047 0.0 +15048 0.0 +15049 0.0 +15050 0.0 +15051 0.0 +15052 0.0 +15053 0.0 +15054 0.0 +15055 0.0 +15056 0.0 +15057 0.0 +15058 0.0 +15059 0.0 +15060 0.0 +15061 0.0 +15062 0.0 +15063 0.0 +15064 0.0 +15065 0.0 +15066 0.0 +15067 0.0 +15068 0.0 +15069 0.0 +15070 0.0 +15071 0.0 +15072 0.0 +15073 0.0 +15074 0.0 +15075 0.0 +15076 0.0 +15077 0.0 +15078 0.0 +15079 0.0 +15080 0.0 +15081 0.0 +15082 0.0 +15083 0.0 +15084 0.0 +15085 0.0 +15086 0.0 +15087 0.0 +15088 0.0 +15089 0.0 +15090 0.0 +15091 0.0 +15092 0.0 +15093 0.0 +15094 0.0 +15095 0.0 +15096 0.0 +15097 0.0 +15098 0.0 +15099 0.0 +15100 0.0 +15101 0.0 +15102 0.0 +15103 0.0 +15104 0.0 +15105 0.0 +15106 0.0 +15107 0.0 +15108 0.0 +15109 0.0 +15110 0.0 +15111 0.0 +15112 0.0 +15113 0.0 +15114 0.0 +15115 0.0 +15116 0.0 +15117 0.0 +15118 0.0 +15119 0.0 +15120 0.0 +15121 0.0 +15122 0.0 +15123 0.0 +15124 0.0 +15125 0.0 +15126 0.0 +15127 0.0 +15128 0.0 +15129 0.0 +15130 0.0 +15131 0.0 +15132 0.0 +15133 0.0 +15134 0.0 +15135 0.0 +15136 0.0 +15137 0.0 +15138 0.0 +15139 0.0 +15140 0.0 +15141 0.0 +15142 0.0 +15143 0.0 +15144 0.0 +15145 0.0 +15146 0.0 +15147 0.0 +15148 0.0 +15149 0.0 +15150 0.0 +15151 0.0 +15152 0.0 +15153 0.0 +15154 0.0 +15155 0.0 +15156 0.0 +15157 0.0 +15158 0.0 +15159 0.0 +15160 0.0 +15161 0.0 +15162 0.0 +15163 0.0 +15164 0.0 +15165 0.0 +15166 0.0 +15167 0.0 +15168 0.0 +15169 0.0 +15170 0.0 +15171 0.0 +15172 0.0 +15173 0.0 +15174 0.0 +15175 0.0 +15176 0.0 +15177 0.0 +15178 0.0 +15179 0.0 +15180 0.0 +15181 0.0 +15182 0.0 +15183 0.0 +15184 0.0 +15185 0.0 +15186 0.0 +15187 0.0 +15188 0.0 +15189 0.0 +15190 0.0 +15191 0.0 +15192 0.0 +15193 0.0 +15194 0.0 +15195 0.0 +15196 0.0 +15197 0.0 +15198 0.0 +15199 0.0 +15200 0.0 +15201 0.0 +15202 0.0 +15203 0.0 +15204 0.0 +15205 0.0 +15206 0.0 +15207 0.0 +15208 0.0 +15209 0.0 +15210 0.0 +15211 0.0 +15212 0.0 +15213 0.0 +15214 0.0 +15215 0.0 +15216 0.0 +15217 0.0 +15218 0.0 +15219 0.0 +15220 0.0 +15221 0.0 +15222 0.0 +15223 0.0 +15224 0.0 +15225 0.0 +15226 0.0 +15227 0.0 +15228 0.0 +15229 0.0 +15230 0.0 +15231 0.0 +15232 0.0 +15233 0.0 +15234 0.0 +15235 0.0 +15236 0.0 +15237 0.0 +15238 0.0 +15239 0.0 +15240 0.0 +15241 0.0 +15242 0.0 +15243 0.0 +15244 0.0 +15245 0.0 +15246 0.0 +15247 0.0 +15248 0.0 +15249 0.0 +15250 0.0 +15251 0.0 +15252 0.0 +15253 0.0 +15254 0.0 +15255 0.0 +15256 0.0 +15257 0.0 +15258 0.0 +15259 0.0 +15260 0.0 +15261 0.0 +15262 0.0 +15263 0.0 +15264 0.0 +15265 0.0 +15266 0.0 +15267 0.0 +15268 0.0 +15269 0.0 +15270 0.0 +15271 0.0 +15272 0.0 +15273 0.0 +15274 0.0 +15275 0.0 +15276 0.0 +15277 0.0 +15278 0.0 +15279 0.0 +15280 0.0 +15281 0.0 +15282 0.0 +15283 0.0 +15284 0.0 +15285 0.0 +15286 0.0 +15287 0.0 +15288 0.0 +15289 0.0 +15290 0.0 +15291 0.0 +15292 0.0 +15293 0.0 +15294 0.0 +15295 0.0 +15296 0.0 +15297 0.0 +15298 0.0 +15299 0.0 +15300 0.0 +15301 0.0 +15302 0.0 +15303 0.0 +15304 0.0 +15305 0.0 +15306 0.0 +15307 0.0 +15308 0.0 +15309 0.0 +15310 0.0 +15311 0.0 +15312 0.0 +15313 0.0 +15314 0.0 +15315 0.0 +15316 0.0 +15317 0.0 +15318 0.0 +15319 0.0 +15320 0.0 +15321 0.0 +15322 0.0 +15323 0.0 +15324 0.0 +15325 0.0 +15326 0.0 +15327 0.0 +15328 0.0 +15329 0.0 +15330 0.0 +15331 0.0 +15332 0.0 +15333 0.0 +15334 0.0 +15335 0.0 +15336 0.0 +15337 0.0 +15338 0.0 +15339 0.0 +15340 0.0 +15341 0.0 +15342 0.0 +15343 0.0 +15344 0.0 +15345 0.0 +15346 0.0 +15347 0.0 +15348 0.0 +15349 0.0 +15350 0.0 +15351 0.0 +15352 0.0 +15353 0.0 +15354 0.0 +15355 0.0 +15356 0.0 +15357 0.0 +15358 0.0 +15359 0.0 diff --git a/tests/circuitpython/audiofilter_filter_stereo_biquads.py b/tests/circuitpython/audiofilter_filter_stereo_biquads.py new file mode 100644 index 00000000000..262f8139378 --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_stereo_biquads.py @@ -0,0 +1,27 @@ +from audiofilters import Filter +from audiofilterhelper import synth_test, white8k +from audiomixer import Mixer +from synthio import Biquad, FilterMode, LFO + + +@synth_test +def stereo_filter(): + args = { + "bits_per_sample": 16, + "samples_signed": True, + "channel_count": 2, + } + effect = Filter( + filter=[ + Biquad(FilterMode.LOW_PASS, 400), + Biquad(FilterMode.HIGH_PASS, 300, Q=8), + ], + **args, + ) + mixer = Mixer(**args) + mixer.voice[0].panning = LFO() + effect.play(mixer) + yield effect, [] + + mixer.play(white8k, loop=True) + yield 400 diff --git a/tests/circuitpython/audiofilter_filter_stereo_biquads.py.exp b/tests/circuitpython/audiofilter_filter_stereo_biquads.py.exp new file mode 100644 index 00000000000..7901d158079 --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_stereo_biquads.py.exp @@ -0,0 +1,102400 @@ +0 0.0 +1 0.0 +2 0.0 +3 0.0 +4 0.0 +5 0.0 +6 0.0 +7 0.0 +8 0.0 +9 0.0 +10 0.0 +11 0.0 +12 0.0 +13 0.0 +14 0.0 +15 0.0 +16 0.0 +17 0.0 +18 0.0 +19 0.0 +20 0.0 +21 0.0 +22 0.0 +23 0.0 +24 0.0 +25 0.0 +26 0.0 +27 0.0 +28 0.0 +29 0.0 +30 0.0 +31 0.0 +32 0.0 +33 0.0 +34 0.0 +35 0.0 +36 0.0 +37 0.0 +38 0.0 +39 0.0 +40 0.0 +41 0.0 +42 0.0 +43 0.0 +44 0.0 +45 0.0 +46 0.0 +47 0.0 +48 0.0 +49 0.0 +50 0.0 +51 0.0 +52 0.0 +53 0.0 +54 0.0 +55 0.0 +56 0.0 +57 0.0 +58 0.0 +59 0.0 +60 0.0 +61 0.0 +62 0.0 +63 0.0 +64 0.0 +65 0.0 +66 0.0 +67 0.0 +68 0.0 +69 0.0 +70 0.0 +71 0.0 +72 0.0 +73 0.0 +74 0.0 +75 0.0 +76 0.0 +77 0.0 +78 0.0 +79 0.0 +80 0.0 +81 0.0 +82 0.0 +83 0.0 +84 0.0 +85 0.0 +86 0.0 +87 0.0 +88 0.0 +89 0.0 +90 0.0 +91 0.0 +92 0.0 +93 0.0 +94 0.0 +95 0.0 +96 0.0 +97 0.0 +98 0.0 +99 0.0 +100 0.0 +101 0.0 +102 0.0 +103 0.0 +104 0.0 +105 0.0 +106 0.0 +107 0.0 +108 0.0 +109 0.0 +110 0.0 +111 0.0 +112 0.0 +113 0.0 +114 0.0 +115 0.0 +116 0.0 +117 0.0 +118 0.0 +119 0.0 +120 0.0 +121 0.0 +122 0.0 +123 0.0 +124 0.0 +125 0.0 +126 0.0 +127 0.0 +128 0.0 +129 0.0 +130 0.0 +131 0.0 +132 0.0 +133 0.0 +134 0.0 +135 0.0 +136 0.0 +137 0.0 +138 0.0 +139 0.0 +140 0.0 +141 0.0 +142 0.0 +143 0.0 +144 0.0 +145 0.0 +146 0.0 +147 0.0 +148 0.0 +149 0.0 +150 0.0 +151 0.0 +152 0.0 +153 0.0 +154 0.0 +155 0.0 +156 0.0 +157 0.0 +158 0.0 +159 0.0 +160 0.0 +161 0.0 +162 0.0 +163 0.0 +164 0.0 +165 0.0 +166 0.0 +167 0.0 +168 0.0 +169 0.0 +170 0.0 +171 0.0 +172 0.0 +173 0.0 +174 0.0 +175 0.0 +176 0.0 +177 0.0 +178 0.0 +179 0.0 +180 0.0 +181 0.0 +182 0.0 +183 0.0 +184 0.0 +185 0.0 +186 0.0 +187 0.0 +188 0.0 +189 0.0 +190 0.0 +191 0.0 +192 0.0 +193 0.0 +194 0.0 +195 0.0 +196 0.0 +197 0.0 +198 0.0 +199 0.0 +200 0.0 +201 0.0 +202 0.0 +203 0.0 +204 0.0 +205 0.0 +206 0.0 +207 0.0 +208 0.0 +209 0.0 +210 0.0 +211 0.0 +212 0.0 +213 0.0 +214 0.0 +215 0.0 +216 0.0 +217 0.0 +218 0.0 +219 0.0 +220 0.0 +221 0.0 +222 0.0 +223 0.0 +224 0.0 +225 0.0 +226 0.0 +227 0.0 +228 0.0 +229 0.0 +230 0.0 +231 0.0 +232 0.0 +233 0.0 +234 0.0 +235 0.0 +236 0.0 +237 0.0 +238 0.0 +239 0.0 +240 0.0 +241 0.0 +242 0.0 +243 0.0 +244 0.0 +245 0.0 +246 0.0 +247 0.0 +248 0.0 +249 0.0 +250 0.0 +251 0.0 +252 0.0 +253 0.0 +254 0.0 +255 0.0 +256 0.002960205078125 +257 0.0030517578125 +258 0.020904541015625 +259 0.021575927734375 +260 0.049591064453125 +261 0.05120849609375 +262 0.052093505859375 +263 0.053802490234375 +264 9.1552734375e-05 +265 9.1552734375e-05 +266 -0.089752197265625 +267 -0.09271240234375 +268 -0.1788330078125 +269 -0.1846923828125 +270 -0.229644775390625 +271 -0.237152099609375 +272 -0.205322265625 +273 -0.21197509765625 +274 -0.1357421875 +275 -0.140045166015625 +276 -0.068145751953125 +277 -0.070159912109375 +278 0.0040283203125 +279 0.004425048828125 +280 0.085601806640625 +281 0.08868408203125 +282 0.19061279296875 +283 0.1971435546875 +284 0.28875732421875 +285 0.2984619140625 +286 0.32904052734375 +287 0.34002685546875 +288 0.328033447265625 +289 0.338958740234375 +290 0.301422119140625 +291 0.311431884765625 +292 0.248870849609375 +293 0.257110595703125 +294 0.164520263671875 +295 0.169921875 +296 0.047454833984375 +297 0.048919677734375 +298 -0.07232666015625 +299 -0.074859619140625 +300 -0.189605712890625 +301 -0.196044921875 +302 -0.30810546875 +303 -0.3184814453125 +304 -0.40386962890625 +305 -0.41741943359375 +306 -0.44793701171875 +307 -0.462921142578125 +308 -0.402435302734375 +309 -0.4158935546875 +310 -0.26312255859375 +311 -0.27197265625 +312 -0.093475341796875 +313 -0.0966796875 +314 0.030303955078125 +315 0.031219482421875 +316 0.106536865234375 +317 0.110015869140625 +318 0.16162109375 +319 0.166961669921875 +320 0.20147705078125 +321 0.20819091796875 +322 0.226287841796875 +323 0.23388671875 +324 0.201416015625 +325 0.208282470703125 +326 0.1470947265625 +327 0.152252197265625 +328 0.119049072265625 +329 0.123321533203125 +330 0.090087890625 +331 0.093414306640625 +332 0.018585205078125 +333 0.019500732421875 +334 -0.070709228515625 +335 -0.07281494140625 +336 -0.11651611328125 +337 -0.1202392578125 +338 -0.0858154296875 +339 -0.088623046875 +340 -0.024078369140625 +341 -0.024932861328125 +342 -0.006011962890625 +343 -0.00634765625 +344 -0.036468505859375 +345 -0.037872314453125 +346 -0.0826416015625 +347 -0.085601806640625 +348 -0.118194580078125 +349 -0.12237548828125 +350 -0.111480712890625 +351 -0.115478515625 +352 -0.051116943359375 +353 -0.05316162109375 +354 0.021331787109375 +355 0.02166748046875 +356 0.04974365234375 +357 0.051025390625 +358 0.0406494140625 +359 0.041656494140625 +360 0.05322265625 +361 0.0546875 +362 0.12335205078125 +363 0.127197265625 +364 0.210296630859375 +365 0.21710205078125 +366 0.254425048828125 +367 0.262786865234375 +368 0.27325439453125 +369 0.282318115234375 +370 0.30120849609375 +371 0.311279296875 +372 0.312896728515625 +373 0.32342529296875 +374 0.2645263671875 +375 0.273468017578125 +376 0.1497802734375 +377 0.1549072265625 +378 0.016937255859375 +379 0.017669677734375 +380 -0.08575439453125 +381 -0.088409423828125 +382 -0.154876708984375 +383 -0.15985107421875 +384 -0.191314697265625 +385 -0.197540283203125 +386 -0.22088623046875 +387 -0.2281494140625 +388 -0.287445068359375 +389 -0.296966552734375 +390 -0.38238525390625 +391 -0.39508056640625 +392 -0.488983154296875 +393 -0.505218505859375 +394 -0.577056884765625 +395 -0.59619140625 +396 -0.609649658203125 +397 -0.62982177734375 +398 -0.57977294921875 +399 -0.59893798828125 +400 -0.464447021484375 +401 -0.47979736328125 +402 -0.276885986328125 +403 -0.286041259765625 +404 -0.0714111328125 +405 -0.07379150390625 +406 0.12152099609375 +407 0.12548828125 +408 0.269439697265625 +409 0.278289794921875 +410 0.360321044921875 +411 0.3721923828125 +412 0.43292236328125 +413 0.44720458984375 +414 0.494903564453125 +415 0.511260986328125 +416 0.50244140625 +417 0.519073486328125 +418 0.444000244140625 +419 0.458740234375 +420 0.36920166015625 +421 0.38153076171875 +422 0.32666015625 +423 0.337646484375 +424 0.322052001953125 +425 0.332916259765625 +426 0.34649658203125 +427 0.358184814453125 +428 0.367218017578125 +429 0.379608154296875 +430 0.334686279296875 +431 0.34600830078125 +432 0.232086181640625 +433 0.239990234375 +434 0.082855224609375 +435 0.085784912109375 +436 -0.079559326171875 +437 -0.082061767578125 +438 -0.231689453125 +439 -0.239288330078125 +440 -0.358489990234375 +441 -0.370361328125 +442 -0.446044921875 +443 -0.460906982421875 +444 -0.4727783203125 +445 -0.48858642578125 +446 -0.45269775390625 +447 -0.467864990234375 +448 -0.43072509765625 +449 -0.4451904296875 +450 -0.40185546875 +451 -0.4154052734375 +452 -0.359283447265625 +453 -0.371429443359375 +454 -0.339935302734375 +455 -0.3514404296875 +456 -0.320892333984375 +457 -0.331756591796875 +458 -0.229156494140625 +459 -0.236968994140625 +460 -0.062042236328125 +461 -0.064300537109375 +462 0.1336669921875 +463 0.137908935546875 +464 0.320068359375 +465 0.33056640625 +466 0.473236083984375 +467 0.488922119140625 +468 0.56414794921875 +469 0.58294677734375 +470 0.56158447265625 +471 0.580413818359375 +472 0.481597900390625 +473 0.497894287109375 +474 0.36175537109375 +475 0.374176025390625 +476 0.243743896484375 +477 0.252288818359375 +478 0.151763916015625 +479 0.157257080078125 +480 0.0540771484375 +481 0.0562744140625 +482 -0.0638427734375 +483 -0.065643310546875 +484 -0.157470703125 +485 -0.1624755859375 +486 -0.222991943359375 +487 -0.230316162109375 +488 -0.279541015625 +489 -0.288909912109375 +490 -0.291900634765625 +491 -0.30181884765625 +492 -0.25115966796875 +493 -0.25982666015625 +494 -0.20123291015625 +495 -0.20831298828125 +496 -0.181121826171875 +497 -0.18756103515625 +498 -0.17724609375 +499 -0.18359375 +500 -0.142303466796875 +501 -0.147491455078125 +502 -0.074188232421875 +503 -0.077056884765625 +504 -0.01043701171875 +505 -0.011138916015625 +506 0.04486083984375 +507 0.04608154296875 +508 0.0850830078125 +509 0.087738037109375 +510 0.088409423828125 +511 0.091278076171875 +512 0.091705322265625 +513 0.09515380859375 +514 0.11151123046875 +515 0.11663818359375 +516 0.122528076171875 +517 0.1290283203125 +518 0.110137939453125 +519 0.116546630859375 +520 0.0689697265625 +521 0.07330322265625 +522 0.02484130859375 +523 0.026763916015625 +524 -0.02301025390625 +525 -0.02392578125 +526 -0.104278564453125 +527 -0.110504150390625 +528 -0.18359375 +529 -0.195220947265625 +530 -0.223724365234375 +531 -0.23822021484375 +532 -0.232635498046875 +533 -0.248016357421875 +534 -0.18865966796875 +535 -0.201385498046875 +536 -0.101318359375 +537 -0.108489990234375 +538 -0.002288818359375 +539 -0.00311279296875 +540 0.110382080078125 +541 0.11688232421875 +542 0.20416259765625 +543 0.21673583984375 +544 0.24432373046875 +545 0.259368896484375 +546 0.24310302734375 +547 0.257904052734375 +548 0.209259033203125 +549 0.221710205078125 +550 0.163360595703125 +551 0.1727294921875 +552 0.133575439453125 +553 0.141082763671875 +554 0.101165771484375 +555 0.106689453125 +556 0.06396484375 +557 0.0672607421875 +558 0.050018310546875 +559 0.052734375 +560 0.07598876953125 +561 0.08087158203125 +562 0.126983642578125 +563 0.1357421875 +564 0.160369873046875 +565 0.171783447265625 +566 0.154541015625 +567 0.1658935546875 +568 0.101318359375 +569 0.10931396484375 +570 0.005401611328125 +571 0.007080078125 +572 -0.1109619140625 +573 -0.1170654296875 +574 -0.2427978515625 +575 -0.2578125 +576 -0.380523681640625 +577 -0.404937744140625 +578 -0.49627685546875 +579 -0.5286865234375 +580 -0.548828125 +581 -0.58502197265625 +582 -0.498046875 +583 -0.531005859375 +584 -0.366180419921875 +585 -0.390411376953125 +586 -0.21160888671875 +587 -0.225616455078125 +588 -0.058380126953125 +589 -0.062255859375 +590 0.09466552734375 +591 0.100921630859375 +592 0.23687744140625 +593 0.252532958984375 +594 0.3428955078125 +595 0.365509033203125 +596 0.396331787109375 +597 0.422332763671875 +598 0.393890380859375 +599 0.41949462890625 +600 0.334259033203125 +601 0.355621337890625 +602 0.2401123046875 +603 0.254974365234375 +604 0.144622802734375 +605 0.152984619140625 +606 0.0594482421875 +607 0.062103271484375 +608 0.01043701171875 +609 0.00994873046875 +610 -0.004119873046875 +611 -0.00531005859375 +612 -0.013671875 +613 -0.015167236328125 +614 -0.00042724609375 +615 -0.000640869140625 +616 0.0472412109375 +617 0.050628662109375 +618 0.088409423828125 +619 0.094940185546875 +620 0.074005126953125 +621 0.079833984375 +622 0.019134521484375 +623 0.021453857421875 +624 -0.04058837890625 +625 -0.04217529296875 +626 -0.096221923828125 +627 -0.10150146484375 +628 -0.1370849609375 +629 -0.1451416015625 +630 -0.17352294921875 +631 -0.18408203125 +632 -0.21112060546875 +633 -0.224334716796875 +634 -0.250518798828125 +635 -0.2666015625 +636 -0.298919677734375 +637 -0.318572998046875 +638 -0.347076416015625 +639 -0.37030029296875 +640 -0.36907958984375 +641 -0.39410400390625 +642 -0.329833984375 +643 -0.35247802734375 +644 -0.22613525390625 +645 -0.241973876953125 +646 -0.074554443359375 +647 -0.08026123046875 +648 0.09942626953125 +649 0.105438232421875 +650 0.238983154296875 +651 0.25439453125 +652 0.31884765625 +653 0.339630126953125 +654 0.356597900390625 +655 0.379913330078125 +656 0.345703125 +657 0.368316650390625 +658 0.285797119140625 +659 0.304412841796875 +660 0.224578857421875 +661 0.239166259765625 +662 0.196319580078125 +663 0.20916748046875 +664 0.176422119140625 +665 0.188140869140625 +666 0.1492919921875 +667 0.159393310546875 +668 0.14080810546875 +669 0.150543212890625 +670 0.141937255859375 +671 0.151947021484375 +672 0.114501953125 +673 0.122833251953125 +674 0.08221435546875 +675 0.088531494140625 +676 0.06683349609375 +677 0.072296142578125 +678 0.034942626953125 +679 0.038360595703125 +680 -0.02557373046875 +681 -0.026214599609375 +682 -0.1142578125 +683 -0.1209716796875 +684 -0.230499267578125 +685 -0.245208740234375 +686 -0.34661865234375 +687 -0.369354248046875 +688 -0.4248046875 +689 -0.45306396484375 +690 -0.45147705078125 +691 -0.481781005859375 +692 -0.439483642578125 +693 -0.46917724609375 +694 -0.39300537109375 +695 -0.41973876953125 +696 -0.310028076171875 +697 -0.331298828125 +698 -0.207061767578125 +699 -0.221527099609375 +700 -0.106353759765625 +701 -0.1141357421875 +702 -0.014312744140625 +703 -0.015960693359375 +704 0.0859375 +705 0.09100341796875 +706 0.2137451171875 +707 0.22747802734375 +708 0.378204345703125 +709 0.403167724609375 +710 0.559051513671875 +711 0.596435546875 +712 0.69921875 +713 0.74627685546875 +714 0.759063720703125 +715 0.81036376953125 +716 0.736114501953125 +717 0.7860107421875 +718 0.6273193359375 +719 0.66998291015625 +720 0.431915283203125 +721 0.46142578125 +722 0.18505859375 +723 0.197906494140625 +724 -0.051727294921875 +725 -0.05487060546875 +726 -0.22491455078125 +727 -0.23974609375 +728 -0.3179931640625 +729 -0.339080810546875 +730 -0.355377197265625 +731 -0.37896728515625 +732 -0.366180419921875 +733 -0.3905029296875 +734 -0.3646240234375 +735 -0.388916015625 +736 -0.3668212890625 +737 -0.391326904296875 +738 -0.37689208984375 +739 -0.4022216796875 +740 -0.369598388671875 +741 -0.39459228515625 +742 -0.32696533203125 +743 -0.3492431640625 +744 -0.269439697265625 +745 -0.287933349609375 +746 -0.237701416015625 +747 -0.254180908203125 +748 -0.248779296875 +749 -0.26617431640625 +750 -0.25311279296875 +751 -0.270904541015625 +752 -0.197998046875 +753 -0.21209716796875 +754 -0.11328125 +755 -0.121612548828125 +756 -0.055572509765625 +757 -0.059967041015625 +758 -0.031158447265625 +759 -0.03387451171875 +760 -0.013275146484375 +761 -0.01470947265625 +762 0.028900146484375 +763 0.030426025390625 +764 0.125396728515625 +765 0.133636474609375 +766 0.249176025390625 +767 0.2659912109375 +768 0.360626220703125 +769 0.385772705078125 +770 0.4522705078125 +771 0.48480224609375 +772 0.495574951171875 +773 0.531097412109375 +774 0.478851318359375 +775 0.511962890625 +776 0.426971435546875 +777 0.454986572265625 +778 0.3798828125 +779 0.404327392578125 +780 0.354766845703125 +781 0.37890625 +782 0.32635498046875 +783 0.350616455078125 +784 0.281341552734375 +785 0.3045654296875 +786 0.22198486328125 +787 0.243011474609375 +788 0.1407470703125 +789 0.157379150390625 +790 0.0196533203125 +791 0.027496337890625 +792 -0.143341064453125 +793 -0.149139404296875 +794 -0.3201904296875 +795 -0.3416748046875 +796 -0.50091552734375 +797 -0.53924560546875 +798 -0.670166015625 +799 -0.725006103515625 +800 -0.77288818359375 +801 -0.838104248046875 +802 -0.767303466796875 +803 -0.832366943359375 +804 -0.6715087890625 +805 -0.727691650390625 +806 -0.535308837890625 +807 -0.579132080078125 +808 -0.40289306640625 +809 -0.435394287109375 +810 -0.294403076171875 +811 -0.318634033203125 +812 -0.179595947265625 +813 -0.195159912109375 +814 -0.034271240234375 +815 -0.038055419921875 +816 0.10321044921875 +817 0.1104736328125 +818 0.194732666015625 +819 0.208465576171875 +820 0.252716064453125 +821 0.26983642578125 +822 0.321044921875 +823 0.34326171875 +824 0.416107177734375 +825 0.446990966796875 +826 0.507049560546875 +827 0.546905517578125 +828 0.57098388671875 +829 0.61773681640625 +830 0.600738525390625 +831 0.6514892578125 +832 0.608062744140625 +833 0.661102294921875 +834 0.59857177734375 +835 0.652679443359375 +836 0.550811767578125 +837 0.602386474609375 +838 0.4521484375 +839 0.496124267578125 +840 0.314910888671875 +841 0.347320556640625 +842 0.152801513671875 +843 0.170989990234375 +844 -0.04058837890625 +845 -0.0401611328125 +846 -0.2442626953125 +847 -0.263031005859375 +848 -0.41192626953125 +849 -0.446502685546875 +850 -0.532440185546875 +851 -0.578399658203125 +852 -0.60150146484375 +853 -0.65399169921875 +854 -0.591156005859375 +855 -0.642364501953125 +856 -0.517791748046875 +857 -0.561676025390625 +858 -0.421661376953125 +859 -0.456390380859375 +860 -0.322113037109375 +861 -0.347869873046875 +862 -0.23809814453125 +863 -0.256988525390625 +864 -0.173553466796875 +865 -0.18792724609375 +866 -0.1256103515625 +867 -0.137359619140625 +868 -0.087310791015625 +869 -0.09747314453125 +870 -0.0498046875 +871 -0.058319091796875 +872 -0.002166748046875 +873 -0.007720947265625 +874 0.066497802734375 +875 0.06646728515625 +876 0.1446533203125 +877 0.151611328125 +878 0.228668212890625 +879 0.243743896484375 +880 0.32513427734375 +881 0.35015869140625 +882 0.42181396484375 +883 0.457366943359375 +884 0.49853515625 +885 0.542999267578125 +886 0.52288818359375 +887 0.57110595703125 +888 0.460906982421875 +889 0.504058837890625 +890 0.318328857421875 +891 0.34808349609375 +892 0.13116455078125 +893 0.142974853515625 +894 -0.053192138671875 +895 -0.0589599609375 +896 -0.20050048828125 +897 -0.219940185546875 +898 -0.309173583984375 +899 -0.33837890625 +900 -0.3717041015625 +901 -0.406005859375 +902 -0.406890869140625 +903 -0.4437255859375 +904 -0.456268310546875 +905 -0.497528076171875 +906 -0.514129638671875 +907 -0.561126708984375 +908 -0.550018310546875 +909 -0.600860595703125 +910 -0.533935546875 +911 -0.58355712890625 +912 -0.4376220703125 +913 -0.4779052734375 +914 -0.255218505859375 +915 -0.27734375 +916 -0.009002685546875 +917 -0.00640869140625 +918 0.243743896484375 +919 0.271636962890625 +920 0.4388427734375 +921 0.48583984375 +922 0.549591064453125 +923 0.60675048828125 +924 0.593017578125 +925 0.6533203125 +926 0.606170654296875 +927 0.666595458984375 +928 0.586334228515625 +929 0.64361572265625 +930 0.524200439453125 +931 0.5740966796875 +932 0.456756591796875 +933 0.499053955078125 +934 0.403167724609375 +935 0.439697265625 +936 0.34454345703125 +937 0.375091552734375 +938 0.25213623046875 +939 0.2734375 +940 0.10101318359375 +941 0.107147216796875 +942 -0.088592529296875 +943 -0.101470947265625 +944 -0.287841796875 +945 -0.320648193359375 +946 -0.497772216796875 +947 -0.551544189453125 +948 -0.7022705078125 +949 -0.77642822265625 +950 -0.853424072265625 +951 -0.864105224609375 +952 -0.861785888671875 +953 -0.870391845703125 +954 -0.861785888671875 +955 -0.868682861328125 +956 -0.855743408203125 +957 -0.86053466796875 +958 -0.739044189453125 +959 -0.759246826171875 +960 -0.530792236328125 +961 -0.52203369140625 +962 -0.247528076171875 +963 -0.20556640625 +964 0.07177734375 +965 0.146942138671875 +966 0.380706787109375 +967 0.48431396484375 +968 0.64703369140625 +969 0.771270751953125 +970 0.846282958984375 +971 0.868316650390625 +972 0.8680419921875 +973 0.870361328125 +974 0.870361328125 +975 0.86395263671875 +976 0.86505126953125 +977 0.8172607421875 +978 0.854766845703125 +979 0.657073974609375 +980 0.723175048828125 +981 0.470733642578125 +982 0.567535400390625 +983 0.279388427734375 +984 0.39276123046875 +985 0.086395263671875 +986 0.170318603515625 +987 -0.140350341796875 +988 -0.106231689453125 +989 -0.40960693359375 +990 -0.39886474609375 +991 -0.6817626953125 +992 -0.654388427734375 +993 -0.859619140625 +994 -0.83514404296875 +995 -0.870391845703125 +996 -0.8634033203125 +997 -0.870391845703125 +998 -0.8685302734375 +999 -0.86444091796875 +1000 -0.870391845703125 +1001 -0.85723876953125 +1002 -0.86846923828125 +1003 -0.790008544921875 +1004 -0.857635498046875 +1005 -0.62847900390625 +1006 -0.701019287109375 +1007 -0.3956298828125 +1008 -0.466644287109375 +1009 -0.126708984375 +1010 -0.205657958984375 +1011 0.150115966796875 +1012 0.07098388671875 +1013 0.424041748046875 +1014 0.339111328125 +1015 0.670623779296875 +1016 0.56427001953125 +1017 0.854522705078125 +1018 0.731414794921875 +1019 0.866485595703125 +1020 0.827880859375 +1021 0.86920166015625 +1022 0.8563232421875 +1023 0.8653564453125 +1024 0.85687255859375 +1025 0.857147216796875 +1026 0.841522216796875 +1027 0.766845703125 +1028 0.772613525390625 +1029 0.628509521484375 +1030 0.66552734375 +1031 0.462127685546875 +1032 0.544281005859375 +1033 0.297210693359375 +1034 0.421051025390625 +1035 0.14862060546875 +1036 0.2769775390625 +1037 -0.00537109375 +1038 0.119354248046875 +1039 -0.15753173828125 +1040 -0.05450439453125 +1041 -0.31304931640625 +1042 -0.2568359375 +1043 -0.48876953125 +1044 -0.44708251953125 +1045 -0.6416015625 +1046 -0.604278564453125 +1047 -0.751373291015625 +1048 -0.749481201171875 +1049 -0.84619140625 +1050 -0.8563232421875 +1051 -0.861297607421875 +1052 -0.863983154296875 +1053 -0.863250732421875 +1054 -0.863189697265625 +1055 -0.856597900390625 +1056 -0.855255126953125 +1057 -0.7498779296875 +1058 -0.775177001953125 +1059 -0.624542236328125 +1060 -0.657257080078125 +1061 -0.47808837890625 +1062 -0.45770263671875 +1063 -0.253387451171875 +1064 -0.217071533203125 +1065 0.003692626953125 +1066 0.004547119140625 +1067 0.2257080078125 +1068 0.217926025390625 +1069 0.427154541015625 +1070 0.451385498046875 +1071 0.643218994140625 +1072 0.6968994140625 +1073 0.855926513671875 +1074 0.859954833984375 +1075 0.870361328125 +1076 0.870361328125 +1077 0.870361328125 +1078 0.870361328125 +1079 0.862762451171875 +1080 0.8629150390625 +1081 0.79669189453125 +1082 0.790863037109375 +1083 0.595794677734375 +1084 0.6055908203125 +1085 0.362152099609375 +1086 0.402740478515625 +1087 0.1270751953125 +1088 0.2022705078125 +1089 -0.086944580078125 +1090 0.006622314453125 +1091 -0.2784423828125 +1092 -0.214813232421875 +1093 -0.484832763671875 +1094 -0.4798583984375 +1095 -0.729583740234375 +1096 -0.7462158203125 +1097 -0.86688232421875 +1098 -0.86614990234375 +1099 -0.870391845703125 +1100 -0.870391845703125 +1101 -0.86859130859375 +1102 -0.870147705078125 +1103 -0.86279296875 +1104 -0.863006591796875 +1105 -0.817962646484375 +1106 -0.77215576171875 +1107 -0.6116943359375 +1108 -0.5177001953125 +1109 -0.3128662109375 +1110 -0.203094482421875 +1111 0.039398193359375 +1112 0.15142822265625 +1113 0.422821044921875 +1114 0.5162353515625 +1115 0.805145263671875 +1116 0.83343505859375 +1117 0.870361328125 +1118 0.870361328125 +1119 0.870361328125 +1120 0.870361328125 +1121 0.860015869140625 +1122 0.860992431640625 +1123 0.727935791015625 +1124 0.75042724609375 +1125 0.48114013671875 +1126 0.542449951171875 +1127 0.2059326171875 +1128 0.320953369140625 +1129 -0.06103515625 +1130 0.1038818359375 +1131 -0.29913330078125 +1132 -0.114471435546875 +1133 -0.516204833984375 +1134 -0.343231201171875 +1135 -0.7252197265625 +1136 -0.55914306640625 +1137 -0.85980224609375 +1138 -0.733428955078125 +1139 -0.870391845703125 +1140 -0.844024658203125 +1141 -0.870391845703125 +1142 -0.8544921875 +1143 -0.858062744140625 +1144 -0.769134521484375 +1145 -0.673004150390625 +1146 -0.64306640625 +1147 -0.42694091796875 +1148 -0.52520751953125 +1149 -0.2100830078125 +1150 -0.424163818359375 +1151 -0.0362548828125 +1152 -0.324798583984375 +1153 0.10943603515625 +1154 -0.219085693359375 +1155 0.23516845703125 +1156 -0.078948974609375 +1157 0.373687744140625 +1158 0.087554931640625 +1159 0.517791748046875 +1160 0.221160888671875 +1161 0.602783203125 +1162 0.32427978515625 +1163 0.635711669921875 +1164 0.42608642578125 +1165 0.655181884765625 +1166 0.5201416015625 +1167 0.65948486328125 +1168 0.603668212890625 +1169 0.651275634765625 +1170 0.661163330078125 +1171 0.61846923828125 +1172 0.667572021484375 +1173 0.53753662109375 +1174 0.615203857421875 +1175 0.404144287109375 +1176 0.5040283203125 +1177 0.22186279296875 +1178 0.343505859375 +1179 0.003997802734375 +1180 0.157379150390625 +1181 -0.22100830078125 +1182 -0.02935791015625 +1183 -0.42449951171875 +1184 -0.192413330078125 +1185 -0.579833984375 +1186 -0.2904052734375 +1187 -0.641876220703125 +1188 -0.326690673828125 +1189 -0.6177978515625 +1190 -0.357025146484375 +1191 -0.575531005859375 +1192 -0.387298583984375 +1193 -0.526336669921875 +1194 -0.37518310546875 +1195 -0.42645263671875 +1196 -0.30108642578125 +1197 -0.2581787109375 +1198 -0.202239990234375 +1199 -0.068695068359375 +1200 -0.11859130859375 +1201 0.09222412109375 +1202 -0.040740966796875 +1203 0.232147216796875 +1204 0.033233642578125 +1205 0.3509521484375 +1206 0.07086181640625 +1207 0.410064697265625 +1208 0.040618896484375 +1209 0.372955322265625 +1210 -0.044189453125 +1211 0.2554931640625 +1212 -0.14190673828125 +1213 0.10711669921875 +1214 -0.23785400390625 +1215 -0.052886962890625 +1216 -0.3013916015625 +1217 -0.186279296875 +1218 -0.283233642578125 +1219 -0.23291015625 +1220 -0.20123291015625 +1221 -0.209442138671875 +1222 -0.10968017578125 +1223 -0.174163818359375 +1224 -0.011566162109375 +1225 -0.126739501953125 +1226 0.106658935546875 +1227 -0.048126220703125 +1228 0.225921630859375 +1229 0.0426025390625 +1230 0.311187744140625 +1231 0.10748291015625 +1232 0.35638427734375 +1233 0.1409912109375 +1234 0.4080810546875 +1235 0.19708251953125 +1236 0.464691162109375 +1237 0.273651123046875 +1238 0.48089599609375 +1239 0.31768798828125 +1240 0.4686279296875 +1241 0.341094970703125 +1242 0.4510498046875 +1243 0.368011474609375 +1244 0.407989501953125 +1245 0.37249755859375 +1246 0.29522705078125 +1247 0.30072021484375 +1248 0.11474609375 +1249 0.1517333984375 +1250 -0.07855224609375 +1251 -0.01470947265625 +1252 -0.27313232421875 +1253 -0.1883544921875 +1254 -0.469879150390625 +1255 -0.372711181640625 +1256 -0.620147705078125 +1257 -0.51397705078125 +1258 -0.687469482421875 +1259 -0.57177734375 +1260 -0.66546630859375 +1261 -0.53948974609375 +1262 -0.569793701171875 +1263 -0.43511962890625 +1264 -0.433807373046875 +1265 -0.2962646484375 +1266 -0.2918701171875 +1267 -0.161102294921875 +1268 -0.15771484375 +1269 -0.0435791015625 +1270 -0.029754638671875 +1271 0.060394287109375 +1272 0.07745361328125 +1273 0.13665771484375 +1274 0.148468017578125 +1275 0.170135498046875 +1276 0.185089111328125 +1277 0.16552734375 +1278 0.21514892578125 +1279 0.15728759765625 +1280 0.241607666015625 +1281 0.150787353515625 +1282 0.241943359375 +1283 0.12200927734375 +1284 0.222625732421875 +1285 0.080108642578125 +1286 0.205413818359375 +1287 0.05126953125 +1288 0.213592529296875 +1289 0.062896728515625 +1290 0.2286376953125 +1291 0.09271240234375 +1292 0.2108154296875 +1293 0.092987060546875 +1294 0.1739501953125 +1295 0.07855224609375 +1296 0.132232666015625 +1297 0.06427001953125 +1298 0.0743408203125 +1299 0.0347900390625 +1300 0.000518798828125 +1301 -0.01171875 +1302 -0.070953369140625 +1303 -0.056060791015625 +1304 -0.10198974609375 +1305 -0.055511474609375 +1306 -0.09124755859375 +1307 -0.010467529296875 +1308 -0.083221435546875 +1309 0.02508544921875 +1310 -0.0985107421875 +1311 0.025665283203125 +1312 -0.11431884765625 +1313 0.017333984375 +1314 -0.128875732421875 +1315 0.00189208984375 +1316 -0.151702880859375 +1317 -0.03173828125 +1318 -0.17315673828125 +1319 -0.071502685546875 +1320 -0.209381103515625 +1321 -0.13543701171875 +1322 -0.25848388671875 +1323 -0.219970703125 +1324 -0.30096435546875 +1325 -0.300506591796875 +1326 -0.337677001953125 +1327 -0.376312255859375 +1328 -0.343597412109375 +1329 -0.416107177734375 +1330 -0.278778076171875 +1331 -0.371124267578125 +1332 -0.145416259765625 +1333 -0.242279052734375 +1334 0.021087646484375 +1335 -0.069732666015625 +1336 0.201995849609375 +1337 0.125640869140625 +1338 0.370208740234375 +1339 0.31268310546875 +1340 0.494476318359375 +1341 0.45501708984375 +1342 0.57659912109375 +1343 0.554779052734375 +1344 0.615753173828125 +1345 0.61065673828125 +1346 0.602630615234375 +1347 0.610931396484375 +1348 0.517578125 +1349 0.531463623046875 +1350 0.37530517578125 +1351 0.3883056640625 +1352 0.22222900390625 +1353 0.23468017578125 +1354 0.08062744140625 +1355 0.095245361328125 +1356 -0.026092529296875 +1357 -0.00396728515625 +1358 -0.08447265625 +1359 -0.04852294921875 +1360 -0.107635498046875 +1361 -0.055145263671875 +1362 -0.138916015625 +1363 -0.0758056640625 +1364 -0.20166015625 +1365 -0.138702392578125 +1366 -0.266021728515625 +1367 -0.209197998046875 +1368 -0.3333740234375 +1369 -0.289031982421875 +1370 -0.404449462890625 +1371 -0.37884521484375 +1372 -0.460662841796875 +1373 -0.456329345703125 +1374 -0.4984130859375 +1375 -0.51641845703125 +1376 -0.484649658203125 +1377 -0.519287109375 +1378 -0.4146728515625 +1379 -0.458251953125 +1380 -0.33331298828125 +1381 -0.384796142578125 +1382 -0.26263427734375 +1383 -0.323699951171875 +1384 -0.198822021484375 +1385 -0.269287109375 +1386 -0.12042236328125 +1387 -0.1951904296875 +1388 -0.027008056640625 +1389 -0.100006103515625 +1390 0.0579833984375 +1391 -0.01055908203125 +1392 0.159881591796875 +1393 0.1033935546875 +1394 0.28466796875 +1395 0.24908447265625 +1396 0.387115478515625 +1397 0.373199462890625 +1398 0.452484130859375 +1399 0.45806884765625 +1400 0.48785400390625 +1401 0.511474609375 +1402 0.52105712890625 +1403 0.565399169921875 +1404 0.545684814453125 +1405 0.61138916015625 +1406 0.511810302734375 +1407 0.5897216796875 +1408 0.411956787109375 +1409 0.4906005859375 +1410 0.2618408203125 +1411 0.33148193359375 +1412 0.09234619140625 +1413 0.147796630859375 +1414 -0.06036376953125 +1415 -0.01873779296875 +1416 -0.172088623046875 +1417 -0.140289306640625 +1418 -0.221282958984375 +1419 -0.191986083984375 +1420 -0.2166748046875 +1421 -0.184295654296875 +1422 -0.196197509765625 +1423 -0.161834716796875 +1424 -0.1956787109375 +1425 -0.166595458984375 +1426 -0.21148681640625 +1427 -0.19390869140625 +1428 -0.227691650390625 +1429 -0.22442626953125 +1430 -0.26324462890625 +1431 -0.279754638671875 +1432 -0.301055908203125 +1433 -0.3389892578125 +1434 -0.30126953125 +1435 -0.3543701171875 +1436 -0.28350830078125 +1437 -0.348175048828125 +1438 -0.253173828125 +1439 -0.32598876953125 +1440 -0.185699462890625 +1441 -0.2581787109375 +1442 -0.077362060546875 +1443 -0.139801025390625 +1444 0.05914306640625 +1445 0.014617919921875 +1446 0.171966552734375 +1447 0.144378662109375 +1448 0.236907958984375 +1449 0.221038818359375 +1450 0.276214599609375 +1451 0.27069091796875 +1452 0.290740966796875 +1453 0.294036865234375 +1454 0.298431396484375 +1455 0.311767578125 +1456 0.31268310546875 +1457 0.339141845703125 +1458 0.320404052734375 +1459 0.360260009765625 +1460 0.309783935546875 +1461 0.360504150390625 +1462 0.2550048828125 +1463 0.308380126953125 +1464 0.1380615234375 +1465 0.18170166015625 +1466 -0.019989013671875 +1467 0.0047607421875 +1468 -0.1793212890625 +1469 -0.17559814453125 +1470 -0.301727294921875 +1471 -0.3143310546875 +1472 -0.350311279296875 +1473 -0.36785888671875 +1474 -0.3470458984375 +1475 -0.36248779296875 +1476 -0.329986572265625 +1477 -0.343536376953125 +1478 -0.2916259765625 +1479 -0.3018798828125 +1480 -0.227081298828125 +1481 -0.231414794921875 +1482 -0.12451171875 +1483 -0.117645263671875 +1484 -0.011505126953125 +1485 0.007049560546875 +1486 0.06549072265625 +1487 0.087982177734375 +1488 0.117950439453125 +1489 0.13946533203125 +1490 0.156097412109375 +1491 0.17425537109375 +1492 0.175933837890625 +1493 0.188201904296875 +1494 0.1685791015625 +1495 0.171234130859375 +1496 0.12957763671875 +1497 0.118438720703125 +1498 0.081573486328125 +1499 0.05706787109375 +1500 0.026214599609375 +1501 -0.010711669921875 +1502 -0.041961669921875 +1503 -0.0914306640625 +1504 -0.103759765625 +1505 -0.162322998046875 +1506 -0.134796142578125 +1507 -0.194549560546875 +1508 -0.102203369140625 +1509 -0.1492919921875 +1510 -0.00152587890625 +1511 -0.02166748046875 +1512 0.1136474609375 +1513 0.124053955078125 +1514 0.17926025390625 +1515 0.211151123046875 +1516 0.196441650390625 +1517 0.240447998046875 +1518 0.191009521484375 +1519 0.242218017578125 +1520 0.171112060546875 +1521 0.2257080078125 +1522 0.139923095703125 +1523 0.194366455078125 +1524 0.070220947265625 +1525 0.115509033203125 +1526 -0.017913818359375 +1527 0.0128173828125 +1528 -0.074127197265625 +1529 -0.053802490234375 +1530 -0.12054443359375 +1531 -0.110626220703125 +1532 -0.192413330078125 +1533 -0.199493408203125 +1534 -0.26806640625 +1535 -0.29437255859375 +1536 -0.295135498046875 +1537 -0.33221435546875 +1538 -0.246734619140625 +1539 -0.27972412109375 +1540 -0.162811279296875 +1541 -0.185333251953125 +1542 -0.108062744140625 +1543 -0.128204345703125 +1544 -0.089111328125 +1545 -0.115692138671875 +1546 -0.081298828125 +1547 -0.116455078125 +1548 -0.06536865234375 +1549 -0.105926513671875 +1550 -0.017364501953125 +1551 -0.053955078125 +1552 0.06988525390625 +1553 0.048797607421875 +1554 0.159881591796875 +1555 0.157318115234375 +1556 0.204376220703125 +1557 0.212005615234375 +1558 0.207977294921875 +1559 0.218475341796875 +1560 0.219757080078125 +1561 0.23724365234375 +1562 0.2698974609375 +1563 0.30535888671875 +1564 0.32513427734375 +1565 0.38128662109375 +1566 0.3369140625 +1567 0.404449462890625 +1568 0.32147216796875 +1569 0.3944091796875 +1570 0.3094482421875 +1571 0.3885498046875 +1572 0.281707763671875 +1573 0.362640380859375 +1574 0.203765869140625 +1575 0.27362060546875 +1576 0.072418212890625 +1577 0.11712646484375 +1578 -0.070098876953125 +1579 -0.054901123046875 +1580 -0.181915283203125 +1581 -0.19085693359375 +1582 -0.258941650390625 +1583 -0.28570556640625 +1584 -0.30108642578125 +1585 -0.339263916015625 +1586 -0.329437255859375 +1587 -0.3775634765625 +1588 -0.380645751953125 +1589 -0.445709228515625 +1590 -0.447998046875 +1591 -0.535064697265625 +1592 -0.51837158203125 +1593 -0.629058837890625 +1594 -0.567779541015625 +1595 -0.697601318359375 +1596 -0.56683349609375 +1597 -0.70391845703125 +1598 -0.51141357421875 +1599 -0.6424560546875 +1600 -0.384063720703125 +1601 -0.491241455078125 +1602 -0.197479248046875 +1603 -0.265716552734375 +1604 0.0013427734375 +1605 -0.023712158203125 +1606 0.185577392578125 +1607 0.201751708984375 +1608 0.326995849609375 +1609 0.375823974609375 +1610 0.414764404296875 +1611 0.485076904296875 +1612 0.480712890625 +1613 0.56884765625 +1614 0.5311279296875 +1615 0.634765625 +1616 0.529693603515625 +1617 0.63763427734375 +1618 0.4674072265625 +1619 0.5660400390625 +1620 0.3865966796875 +1621 0.4720458984375 +1622 0.328948974609375 +1623 0.40692138671875 +1624 0.300537109375 +1625 0.3778076171875 +1626 0.29534912109375 +1627 0.376953125 +1628 0.287445068359375 +1629 0.371978759765625 +1630 0.236846923828125 +1631 0.313140869140625 +1632 0.1307373046875 +1633 0.184417724609375 +1634 -0.010223388671875 +1635 0.011199951171875 +1636 -0.157379150390625 +1637 -0.171051025390625 +1638 -0.290618896484375 +1639 -0.33740234375 +1640 -0.397216796875 +1641 -0.47198486328125 +1642 -0.465728759765625 +1643 -0.560394287109375 +1644 -0.478485107421875 +1645 -0.58056640625 +1646 -0.447845458984375 +1647 -0.54754638671875 +1648 -0.412200927734375 +1649 -0.508575439453125 +1650 -0.368438720703125 +1651 -0.459503173828125 +1652 -0.311981201171875 +1653 -0.394378662109375 +1654 -0.27484130859375 +1655 -0.35260009765625 +1656 -0.239044189453125 +1657 -0.31170654296875 +1658 -0.14471435546875 +1659 -0.197418212890625 +1660 0.00946044921875 +1661 -0.007965087890625 +1662 0.1837158203125 +1663 0.207489013671875 +1664 0.345977783203125 +1665 0.409210205078125 +1666 0.47601318359375 +1667 0.57208251953125 +1668 0.549560546875 +1669 0.66595458984375 +1670 0.540863037109375 +1671 0.65875244140625 +1672 0.463836669921875 +1673 0.56744384765625 +1674 0.3504638671875 +1675 0.431396484375 +1676 0.236358642578125 +1677 0.29443359375 +1678 0.14263916015625 +1679 0.182464599609375 +1680 0.04376220703125 +1681 0.06365966796875 +1682 -0.0714111328125 +1683 -0.075958251953125 +1684 -0.16485595703125 +1685 -0.189422607421875 +1686 -0.23260498046875 +1687 -0.271942138671875 +1688 -0.28997802734375 +1689 -0.342529296875 +1690 -0.307098388671875 +1691 -0.364166259765625 +1692 -0.276214599609375 +1693 -0.327239990234375 +1694 -0.233917236328125 +1695 -0.2769775390625 +1696 -0.212921142578125 +1697 -0.253692626953125 +1698 -0.20220947265625 +1699 -0.24365234375 +1700 -0.162811279296875 +1701 -0.1983642578125 +1702 -0.093597412109375 +1703 -0.116241455078125 +1704 -0.026641845703125 +1705 -0.036834716796875 +1706 0.033843994140625 +1707 0.034881591796875 +1708 0.08154296875 +1709 0.09124755859375 +1710 0.09747314453125 +1711 0.10888671875 +1712 0.112030029296875 +1713 0.125518798828125 +1714 0.1385498046875 +1715 0.15771484375 +1716 0.155029296875 +1717 0.17828369140625 +1718 0.148468017578125 +1719 0.17108154296875 +1720 0.113983154296875 +1721 0.129974365234375 +1722 0.073822021484375 +1723 0.082427978515625 +1724 0.02752685546875 +1725 0.027679443359375 +1726 -0.050140380859375 +1727 -0.065643310546875 +1728 -0.128173828125 +1729 -0.15936279296875 +1730 -0.173828125 +1731 -0.21307373046875 +1732 -0.193359375 +1733 -0.234649658203125 +1734 -0.1673583984375 +1735 -0.2001953125 +1736 -0.103363037109375 +1737 -0.119171142578125 +1738 -0.02813720703125 +1739 -0.024749755859375 +1740 0.060577392578125 +1741 0.085784912109375 +1742 0.135101318359375 +1743 0.178131103515625 +1744 0.165771484375 +1745 0.215576171875 +1746 0.163299560546875 +1747 0.211456298828125 +1748 0.13525390625 +1749 0.17523193359375 +1750 0.099212646484375 +1751 0.128753662109375 +1752 0.079254150390625 +1753 0.1019287109375 +1754 0.058807373046875 +1755 0.0743408203125 +1756 0.035552978515625 +1757 0.04327392578125 +1758 0.033203125 +1759 0.038177490234375 +1760 0.065582275390625 +1761 0.076263427734375 +1762 0.119293212890625 +1763 0.14105224609375 +1764 0.157012939453125 +1765 0.186431884765625 +1766 0.15960693359375 +1767 0.188812255859375 +1768 0.11962890625 +1769 0.1390380859375 +1770 0.040863037109375 +1771 0.041778564453125 +1772 -0.0576171875 +1773 -0.079437255859375 +1774 -0.17156982421875 +1775 -0.219390869140625 +1776 -0.29266357421875 +1777 -0.367828369140625 +1778 -0.396697998046875 +1779 -0.494873046875 +1780 -0.447784423828125 +1781 -0.556243896484375 +1782 -0.410919189453125 +1783 -0.508697509765625 +1784 -0.304901123046875 +1785 -0.3756103515625 +1786 -0.179656982421875 +1787 -0.218902587890625 +1788 -0.05548095703125 +1789 -0.063751220703125 +1790 0.06903076171875 +1791 0.091552734375 +1792 0.18499755859375 +1793 0.23602294921875 +1794 0.27093505859375 +1795 0.342987060546875 +1796 0.313232421875 +1797 0.39520263671875 +1798 0.309539794921875 +1799 0.389373779296875 +1800 0.259063720703125 +1801 0.324249267578125 +1802 0.180816650390625 +1803 0.224090576171875 +1804 0.1024169921875 +1805 0.124267578125 +1806 0.033538818359375 +1807 0.037078857421875 +1808 -0.004425048828125 +1809 -0.010101318359375 +1810 -0.013092041015625 +1811 -0.019439697265625 +1812 -0.017059326171875 +1813 -0.022796630859375 +1814 -0.0018310546875 +1815 -0.001556396484375 +1816 0.0419921875 +1817 0.056304931640625 +1818 0.080230712890625 +1819 0.106719970703125 +1820 0.07196044921875 +1821 0.096893310546875 +1822 0.029510498046875 +1823 0.042694091796875 +1824 -0.017791748046875 +1825 -0.018035888671875 +1826 -0.062591552734375 +1827 -0.07586669921875 +1828 -0.096099853515625 +1829 -0.11944580078125 +1830 -0.12689208984375 +1831 -0.15972900390625 +1832 -0.1595458984375 +1833 -0.202606201171875 +1834 -0.194488525390625 +1835 -0.24859619140625 +1836 -0.237548828125 +1837 -0.30517578125 +1838 -0.280853271484375 +1839 -0.36212158203125 +1840 -0.302734375 +1841 -0.39141845703125 +1842 -0.273895263671875 +1843 -0.35528564453125 +1844 -0.191497802734375 +1845 -0.249969482421875 +1846 -0.069091796875 +1847 -0.092864990234375 +1848 0.0723876953125 +1849 0.08905029296875 +1850 0.185943603515625 +1851 0.2352294921875 +1852 0.250732421875 +1853 0.318817138671875 +1854 0.2813720703125 +1855 0.358642578125 +1856 0.272491455078125 +1857 0.347747802734375 +1858 0.2237548828125 +1859 0.28564453125 +1860 0.174652099609375 +1861 0.223175048828125 +1862 0.1534423828125 +1863 0.196746826171875 +1864 0.139617919921875 +1865 0.179840087890625 +1866 0.120086669921875 +1867 0.155548095703125 +1868 0.116119384765625 +1869 0.151214599609375 +1870 0.12005615234375 +1871 0.156951904296875 +1872 0.10009765625 +1873 0.13177490234375 +1874 0.075775146484375 +1875 0.100799560546875 +1876 0.06500244140625 +1877 0.087127685546875 +1878 0.03997802734375 +1879 0.05487060546875 +1880 -0.009429931640625 +1881 -0.009002685546875 +1882 -0.08282470703125 +1883 -0.10400390625 +1884 -0.1796875 +1885 -0.229400634765625 +1886 -0.27703857421875 +1887 -0.35552978515625 +1888 -0.343505859375 +1889 -0.441925048828125 +1890 -0.367706298828125 +1891 -0.473846435546875 +1892 -0.360137939453125 +1893 -0.464813232421875 +1894 -0.324127197265625 +1895 -0.419097900390625 +1896 -0.25787353515625 +1897 -0.334320068359375 +1898 -0.1749267578125 +1899 -0.227935791015625 +1900 -0.093597412109375 +1901 -0.12347412109375 +1902 -0.019073486328125 +1903 -0.02764892578125 +1904 0.06268310546875 +1905 0.077667236328125 +1906 0.167816162109375 +1907 0.2132568359375 +1908 0.303863525390625 +1909 0.38885498046875 +1910 0.45404052734375 +1911 0.582794189453125 +1912 0.57098388671875 +1913 0.734039306640625 +1914 0.621795654296875 +1915 0.800140380859375 +1916 0.604339599609375 +1917 0.7783203125 +1918 0.5159912109375 +1919 0.6651611328125 +1920 0.35601806640625 +1921 0.45965576171875 +1922 0.1534423828125 +1923 0.199188232421875 +1924 -0.040802001953125 +1925 -0.050689697265625 +1926 -0.1824951171875 +1927 -0.23297119140625 +1928 -0.258056640625 +1929 -0.33013916015625 +1930 -0.287811279296875 +1931 -0.368408203125 +1932 -0.295928955078125 +1933 -0.378936767578125 +1934 -0.294281005859375 +1935 -0.376983642578125 +1936 -0.296173095703125 +1937 -0.37969970703125 +1938 -0.305023193359375 +1939 -0.391510009765625 +1940 -0.29986572265625 +1941 -0.385345458984375 +1942 -0.2657470703125 +1943 -0.3419189453125 +1944 -0.219512939453125 +1945 -0.28289794921875 +1946 -0.194793701171875 +1947 -0.251617431640625 +1948 -0.205657958984375 +1949 -0.266143798828125 +1950 -0.210906982421875 +1951 -0.273345947265625 +1952 -0.166748046875 +1953 -0.216796875 +1954 -0.09783935546875 +1955 -0.128265380859375 +1956 -0.051055908203125 +1957 -0.068145751953125 +1958 -0.031585693359375 +1959 -0.0430908203125 +1960 -0.017181396484375 +1961 -0.024444580078125 +1962 0.0177001953125 +1963 0.020721435546875 +1964 0.097991943359375 +1965 0.124481201171875 +1966 0.201202392578125 +1967 0.25787353515625 +1968 0.294921875 +1969 0.379119873046875 +1970 0.37274169921875 +1971 0.47991943359375 +1972 0.4097900390625 +1973 0.5281982421875 +1974 0.396148681640625 +1975 0.511138916015625 +1976 0.3531494140625 +1977 0.456207275390625 +1978 0.31500244140625 +1979 0.407470703125 +1980 0.296356201171875 +1981 0.383758544921875 +1982 0.27532958984375 +1983 0.35687255859375 +1984 0.240325927734375 +1985 0.31182861328125 +1986 0.19305419921875 +1987 0.250885009765625 +1988 0.1268310546875 +1989 0.1654052734375 +1990 0.026031494140625 +1991 0.035247802734375 +1992 -0.111297607421875 +1993 -0.142059326171875 +1994 -0.261199951171875 +1995 -0.33563232421875 +1996 -0.415191650390625 +1997 -0.5345458984375 +1998 -0.56011962890625 +1999 -0.72186279296875 +2000 -0.648773193359375 +2001 -0.836669921875 +2002 -0.645233154296875 +2003 -0.8326416015625 +2004 -0.56494140625 +2005 -0.7296142578125 +2006 -0.4505615234375 +2007 -0.582550048828125 +2008 -0.339813232421875 +2009 -0.440093994140625 +2010 -0.249847412109375 +2011 -0.324310302734375 +2012 -0.154510498046875 +2013 -0.20147705078125 +2014 -0.032867431640625 +2015 -0.044647216796875 +2016 0.08233642578125 +2017 0.103973388671875 +2018 0.15850830078125 +2019 0.202392578125 +2020 0.2064208984375 +2021 0.264495849609375 +2022 0.263824462890625 +2023 0.338897705078125 +2024 0.3448486328125 +2025 0.443817138671875 +2026 0.42303466796875 +2027 0.545074462890625 +2028 0.478668212890625 +2029 0.6173095703125 +2030 0.50555419921875 +2031 0.6524658203125 +2032 0.513702392578125 +2033 0.66339111328125 +2034 0.5078125 +2035 0.6561279296875 +2036 0.469329833984375 +2037 0.606781005859375 +2038 0.38726806640625 +2039 0.501190185546875 +2040 0.272064208984375 +2041 0.352783203125 +2042 0.135345458984375 +2043 0.176544189453125 +2044 -0.028533935546875 +2045 -0.034820556640625 +2046 -0.201629638671875 +2047 -0.258209228515625 +2048 -0.344451904296875 +2049 -0.44244384765625 +2050 -0.4473876953125 +2051 -0.5753173828125 +2052 -0.50689697265625 +2053 -0.65203857421875 +2054 -0.5 +2055 -0.641632080078125 +2056 -0.440277099609375 +2057 -0.562164306640625 +2058 -0.36090087890625 +2059 -0.458038330078125 +2060 -0.277923583984375 +2061 -0.350555419921875 +2062 -0.20709228515625 +2063 -0.260528564453125 +2064 -0.15179443359375 +2065 -0.192108154296875 +2066 -0.109771728515625 +2067 -0.141937255859375 +2068 -0.075469970703125 +2069 -0.1021728515625 +2070 -0.041748046875 +2071 -0.062896728515625 +2072 0.00018310546875 +2073 -0.011932373046875 +2074 0.059173583984375 +2075 0.062835693359375 +2076 0.125640869140625 +2077 0.148712158203125 +2078 0.19647216796875 +2079 0.241729736328125 +2080 0.277008056640625 +2081 0.34912109375 +2082 0.357177734375 +2083 0.457305908203125 +2084 0.42034912109375 +2085 0.54388427734375 +2086 0.439849853515625 +2087 0.5728759765625 +2088 0.387786865234375 +2089 0.506591796875 +2090 0.268951416015625 +2091 0.351226806640625 +2092 0.11309814453125 +2093 0.146514892578125 +2094 -0.040679931640625 +2095 -0.05523681640625 +2096 -0.1640625 +2097 -0.21624755859375 +2098 -0.255645751953125 +2099 -0.334930419921875 +2100 -0.30908203125 +2101 -0.402984619140625 +2102 -0.33978271484375 +2103 -0.4412841796875 +2104 -0.3818359375 +2105 -0.49578857421875 +2106 -0.43048095703125 +2107 -0.5601806640625 +2108 -0.460601806640625 +2109 -0.600738525390625 +2110 -0.447509765625 +2111 -0.584228515625 +2112 -0.367950439453125 +2113 -0.47930908203125 +2114 -0.21710205078125 +2115 -0.27935791015625 +2116 -0.01336669921875 +2117 -0.0089111328125 +2118 0.196044921875 +2119 0.268798828125 +2120 0.35821533203125 +2121 0.482818603515625 +2122 0.451080322265625 +2123 0.60369873046875 +2124 0.488555908203125 +2125 0.650421142578125 +2126 0.50103759765625 +2127 0.66400146484375 +2128 0.486175537109375 +2129 0.6414794921875 +2130 0.436248779296875 +2131 0.572540283203125 +2132 0.38165283203125 +2133 0.498138427734375 +2134 0.338104248046875 +2135 0.439453125 +2136 0.2900390625 +2137 0.375518798828125 +2138 0.21380615234375 +2139 0.274505615234375 +2140 0.08892822265625 +2141 0.1087646484375 +2142 -0.067901611328125 +2143 -0.099395751953125 +2144 -0.232940673828125 +2145 -0.3182373046875 +2146 -0.406982421875 +2147 -0.5489501953125 +2148 -0.57666015625 +2149 -0.7738037109375 +2150 -0.702423095703125 +2151 -0.86383056640625 +2152 -0.759429931640625 +2153 -0.870391845703125 +2154 -0.760772705078125 +2155 -0.86895751953125 +2156 -0.716156005859375 +2157 -0.861053466796875 +2158 -0.612640380859375 +2159 -0.765869140625 +2160 -0.441802978515625 +2161 -0.5301513671875 +2162 -0.208953857421875 +2163 -0.214691162109375 +2164 0.0538330078125 +2165 0.137359619140625 +2166 0.308349609375 +2167 0.474822998046875 +2168 0.528106689453125 +2169 0.76239013671875 +2170 0.692901611328125 +2171 0.867462158203125 +2172 0.802978515625 +2173 0.870361328125 +2174 0.849609375 +2175 0.86480712890625 +2176 0.836669921875 +2177 0.831817626953125 +2178 0.78216552734375 +2179 0.677581787109375 +2180 0.690338134765625 +2181 0.495880126953125 +2182 0.574920654296875 +2183 0.30767822265625 +2184 0.4375 +2185 0.116180419921875 +2186 0.254425048828125 +2187 -0.110748291015625 +2188 0.02056884765625 +2189 -0.381805419921875 +2190 -0.232208251953125 +2191 -0.6572265625 +2192 -0.459320068359375 +2193 -0.857421875 +2194 -0.62872314453125 +2195 -0.870391845703125 +2196 -0.73504638671875 +2197 -0.870391845703125 +2198 -0.7982177734375 +2199 -0.86444091796875 +2200 -0.84466552734375 +2201 -0.85723876953125 +2202 -0.855194091796875 +2203 -0.790008544921875 +2204 -0.80572509765625 +2205 -0.62847900390625 +2206 -0.677398681640625 +2207 -0.3956298828125 +2208 -0.50006103515625 +2209 -0.126708984375 +2210 -0.294036865234375 +2211 0.150115966796875 +2212 -0.068023681640625 +2213 0.424041748046875 +2214 0.15789794921875 +2215 0.670623779296875 +2216 0.354888916015625 +2217 0.854522705078125 +2218 0.509765625 +2219 0.866485595703125 +2220 0.610992431640625 +2221 0.86920166015625 +2222 0.6719970703125 +2223 0.8653564453125 +2224 0.702667236328125 +2225 0.857147216796875 +2226 0.700714111328125 +2227 0.766845703125 +2228 0.669891357421875 +2229 0.628509521484375 +2230 0.605072021484375 +2231 0.462127685546875 +2232 0.525390625 +2233 0.297210693359375 +2234 0.44000244140625 +2235 0.14862060546875 +2236 0.3319091796875 +2237 -0.00537109375 +2238 0.2066650390625 +2239 -0.15753173828125 +2240 0.06158447265625 +2241 -0.31304931640625 +2242 -0.11370849609375 +2243 -0.48876953125 +2244 -0.2843017578125 +2245 -0.6416015625 +2246 -0.431732177734375 +2247 -0.751373291015625 +2248 -0.573089599609375 +2249 -0.84619140625 +2250 -0.69732666015625 +2251 -0.861297607421875 +2252 -0.779693603515625 +2253 -0.863250732421875 +2254 -0.796600341796875 +2255 -0.856597900390625 +2256 -0.75701904296875 +2257 -0.7498779296875 +2258 -0.703948974609375 +2259 -0.624542236328125 +2260 -0.620941162109375 +2261 -0.47808837890625 +2262 -0.464508056640625 +2263 -0.253387451171875 +2264 -0.268585205078125 +2265 0.003692626953125 +2266 -0.08404541015625 +2267 0.2257080078125 +2268 0.098358154296875 +2269 0.427154541015625 +2270 0.30267333984375 +2271 0.643218994140625 +2272 0.5216064453125 +2273 0.855926513671875 +2274 0.71197509765625 +2275 0.870361328125 +2276 0.836761474609375 +2277 0.870361328125 +2278 0.859588623046875 +2279 0.862762451171875 +2280 0.859771728515625 +2281 0.79669189453125 +2282 0.835174560546875 +2283 0.595794677734375 +2284 0.719207763671875 +2285 0.362152099609375 +2286 0.57598876953125 +2287 0.1270751953125 +2288 0.4212646484375 +2289 -0.086944580078125 +2290 0.256622314453125 +2291 -0.2784423828125 +2292 0.056243896484375 +2293 -0.484832763671875 +2294 -0.19403076171875 +2295 -0.729583740234375 +2296 -0.45648193359375 +2297 -0.86688232421875 +2298 -0.68389892578125 +2299 -0.870391845703125 +2300 -0.856475830078125 +2301 -0.86859130859375 +2302 -0.870391845703125 +2303 -0.86279296875 +2304 -0.870391845703125 +2305 -0.817962646484375 +2306 -0.860198974609375 +2307 -0.6116943359375 +2308 -0.718719482421875 +2309 -0.3128662109375 +2310 -0.463897705078125 +2311 0.039398193359375 +2312 -0.159515380859375 +2313 0.422821044921875 +2314 0.1685791015625 +2315 0.805145263671875 +2316 0.470794677734375 +2317 0.870361328125 +2318 0.706451416015625 +2319 0.870361328125 +2320 0.85595703125 +2321 0.860015869140625 +2322 0.8651123046875 +2323 0.727935791015625 +2324 0.8656005859375 +2325 0.48114013671875 +2326 0.859619140625 +2327 0.2059326171875 +2328 0.8074951171875 +2329 -0.06103515625 +2330 0.684539794921875 +2331 -0.29913330078125 +2332 0.526153564453125 +2333 -0.516204833984375 +2334 0.324798583984375 +2335 -0.7252197265625 +2336 0.101287841796875 +2337 -0.85980224609375 +2338 -0.1173095703125 +2339 -0.870391845703125 +2340 -0.3079833984375 +2341 -0.870391845703125 +2342 -0.434814453125 +2343 -0.858062744140625 +2344 -0.494354248046875 +2345 -0.673004150390625 +2346 -0.52423095703125 +2347 -0.42694091796875 +2348 -0.5570068359375 +2349 -0.2100830078125 +2350 -0.592803955078125 +2351 -0.0362548828125 +2352 -0.613128662109375 +2353 0.10943603515625 +2354 -0.60638427734375 +2355 0.23516845703125 +2356 -0.54595947265625 +2357 0.373687744140625 +2358 -0.4361572265625 +2359 0.517791748046875 +2360 -0.324737548828125 +2361 0.602783203125 +2362 -0.210723876953125 +2363 0.635711669921875 +2364 -0.072723388671875 +2365 0.655181884765625 +2366 0.080322265625 +2367 0.65948486328125 +2368 0.241363525390625 +2369 0.651275634765625 +2370 0.3922119140625 +2371 0.61846923828125 +2372 0.50640869140625 +2373 0.53753662109375 +2374 0.571563720703125 +2375 0.404144287109375 +2376 0.581817626953125 +2377 0.22186279296875 +2378 0.53961181640625 +2379 0.003997802734375 +2380 0.459808349609375 +2381 -0.22100830078125 +2382 0.359344482421875 +2383 -0.42449951171875 +2384 0.255828857421875 +2385 -0.579833984375 +2386 0.18206787109375 +2387 -0.641876220703125 +2388 0.1356201171875 +2389 -0.6177978515625 +2390 0.07257080078125 +2391 -0.575531005859375 +2392 -0.0091552734375 +2393 -0.526336669921875 +2394 -0.071380615234375 +2395 -0.42645263671875 +2396 -0.093719482421875 +2397 -0.2581787109375 +2398 -0.101776123046875 +2399 -0.068695068359375 +2400 -0.123138427734375 +2401 0.09222412109375 +2402 -0.145233154296875 +2403 0.232147216796875 +2404 -0.161895751953125 +2405 0.3509521484375 +2406 -0.1956787109375 +2407 0.410064697265625 +2408 -0.2691650390625 +2409 0.372955322265625 +2410 -0.36932373046875 +2411 0.2554931640625 +2412 -0.4609375 +2413 0.10711669921875 +2414 -0.531951904296875 +2415 -0.052886962890625 +2416 -0.55828857421875 +2417 -0.186279296875 +2418 -0.501617431640625 +2419 -0.23291015625 +2420 -0.379302978515625 +2421 -0.209442138671875 +2422 -0.239044189453125 +2423 -0.174163818359375 +2424 -0.087188720703125 +2425 -0.126739501953125 +2426 0.083282470703125 +2427 -0.048126220703125 +2428 0.252685546875 +2429 0.0426025390625 +2430 0.3885498046875 +2431 0.10748291015625 +2432 0.48248291015625 +2433 0.1409912109375 +2434 0.56964111328125 +2435 0.19708251953125 +2436 0.646636962890625 +2437 0.273651123046875 +2438 0.675201416015625 +2439 0.31768798828125 +2440 0.6646728515625 +2441 0.341094970703125 +2442 0.634429931640625 +2443 0.368011474609375 +2444 0.569305419921875 +2445 0.37249755859375 +2446 0.435272216796875 +2447 0.30072021484375 +2448 0.236572265625 +2449 0.1517333984375 +2450 0.02105712890625 +2451 -0.01470947265625 +2452 -0.198486328125 +2453 -0.1883544921875 +2454 -0.41937255859375 +2455 -0.372711181640625 +2456 -0.598602294921875 +2457 -0.51397705078125 +2458 -0.703460693359375 +2459 -0.57177734375 +2460 -0.726165771484375 +2461 -0.53948974609375 +2462 -0.677581787109375 +2463 -0.43511962890625 +2464 -0.583648681640625 +2465 -0.2962646484375 +2466 -0.471893310546875 +2467 -0.161102294921875 +2468 -0.353668212890625 +2469 -0.0435791015625 +2470 -0.228515625 +2471 0.060394287109375 +2472 -0.1097412109375 +2473 0.13665771484375 +2474 -0.011962890625 +2475 0.170135498046875 +2476 0.0638427734375 +2477 0.16552734375 +2478 0.137725830078125 +2479 0.15728759765625 +2480 0.209136962890625 +2481 0.150787353515625 +2482 0.2569580078125 +2483 0.12200927734375 +2484 0.284210205078125 +2485 0.080108642578125 +2486 0.3067626953125 +2487 0.05126953125 +2488 0.3421630859375 +2489 0.062896728515625 +2490 0.37353515625 +2491 0.09271240234375 +2492 0.3668212890625 +2493 0.092987060546875 +2494 0.333465576171875 +2495 0.07855224609375 +2496 0.2857666015625 +2497 0.06427001953125 +2498 0.215240478515625 +2499 0.0347900390625 +2500 0.12359619140625 +2501 -0.01171875 +2502 0.0279541015625 +2503 -0.056060791015625 +2504 -0.037567138671875 +2505 -0.055511474609375 +2506 -0.069580078125 +2507 -0.010467529296875 +2508 -0.10308837890625 +2509 0.02508544921875 +2510 -0.153167724609375 +2511 0.025665283203125 +2512 -0.198760986328125 +2513 0.017333984375 +2514 -0.23675537109375 +2515 0.00189208984375 +2516 -0.27392578125 +2517 -0.03173828125 +2518 -0.3013916015625 +2519 -0.071502685546875 +2520 -0.332427978515625 +2521 -0.13543701171875 +2522 -0.36566162109375 +2523 -0.219970703125 +2524 -0.38543701171875 +2525 -0.300506591796875 +2526 -0.393585205078125 +2527 -0.376312255859375 +2528 -0.370513916015625 +2529 -0.416107177734375 +2530 -0.284515380859375 +2531 -0.371124267578125 +2532 -0.13922119140625 +2533 -0.242279052734375 +2534 0.033843994140625 +2535 -0.069732666015625 +2536 0.2171630859375 +2537 0.125640869140625 +2538 0.38629150390625 +2539 0.31268310546875 +2540 0.513641357421875 +2541 0.45501708984375 +2542 0.599578857421875 +2543 0.554779052734375 +2544 0.6427001953125 +2545 0.61065673828125 +2546 0.634796142578125 +2547 0.610931396484375 +2548 0.559478759765625 +2549 0.531463623046875 +2550 0.42950439453125 +2551 0.3883056640625 +2552 0.2845458984375 +2553 0.23468017578125 +2554 0.144317626953125 +2555 0.095245361328125 +2556 0.02972412109375 +2557 -0.00396728515625 +2558 -0.046478271484375 +2559 -0.04852294921875 +2560 -0.09393310546875 +2561 -0.055145263671875 +2562 -0.14727783203125 +2563 -0.0758056640625 +2564 -0.22430419921875 +2565 -0.138702392578125 +2566 -0.299041748046875 +2567 -0.209197998046875 +2568 -0.37139892578125 +2569 -0.289031982421875 +2570 -0.441131591796875 +2571 -0.37884521484375 +2572 -0.492462158203125 +2573 -0.456329345703125 +2574 -0.52227783203125 +2575 -0.51641845703125 +2576 -0.50360107421875 +2577 -0.519287109375 +2578 -0.43310546875 +2579 -0.458251953125 +2580 -0.348541259765625 +2581 -0.384796142578125 +2582 -0.269195556640625 +2583 -0.323699951171875 +2584 -0.19317626953125 +2585 -0.269287109375 +2586 -0.104156494140625 +2587 -0.1951904296875 +2588 -0.003173828125 +2589 -0.100006103515625 +2590 0.08917236328125 +2591 -0.01055908203125 +2592 0.192535400390625 +2593 0.1033935546875 +2594 0.310882568359375 +2595 0.24908447265625 +2596 0.406219482421875 +2597 0.373199462890625 +2598 0.4659423828125 +2599 0.45806884765625 +2600 0.495697021484375 +2601 0.511474609375 +2602 0.518524169921875 +2603 0.565399169921875 +2604 0.529541015625 +2605 0.61138916015625 +2606 0.48828125 +2607 0.5897216796875 +2608 0.389404296875 +2609 0.4906005859375 +2610 0.24688720703125 +2611 0.33148193359375 +2612 0.087249755859375 +2613 0.147796630859375 +2614 -0.05859375 +2615 -0.01873779296875 +2616 -0.16961669921875 +2617 -0.140289306640625 +2618 -0.227081298828125 +2619 -0.191986083984375 +2620 -0.2373046875 +2621 -0.184295654296875 +2622 -0.2308349609375 +2623 -0.161834716796875 +2624 -0.236724853515625 +2625 -0.166595458984375 +2626 -0.25177001953125 +2627 -0.19390869140625 +2628 -0.262847900390625 +2629 -0.22442626953125 +2630 -0.285797119140625 +2631 -0.279754638671875 +2632 -0.307037353515625 +2633 -0.3389892578125 +2634 -0.29437255859375 +2635 -0.3543701171875 +2636 -0.264739990234375 +2637 -0.348175048828125 +2638 -0.223480224609375 +2639 -0.32598876953125 +2640 -0.151275634765625 +2641 -0.2581787109375 +2642 -0.04595947265625 +2643 -0.139801025390625 +2644 0.081146240234375 +2645 0.014617919921875 +2646 0.186553955078125 +2647 0.144378662109375 +2648 0.249725341796875 +2649 0.221038818359375 +2650 0.288543701171875 +2651 0.27069091796875 +2652 0.303436279296875 +2653 0.294036865234375 +2654 0.30914306640625 +2655 0.311767578125 +2656 0.316802978515625 +2657 0.339141845703125 +2658 0.315765380859375 +2659 0.360260009765625 +2660 0.296875 +2661 0.360504150390625 +2662 0.239898681640625 +2663 0.308380126953125 +2664 0.131072998046875 +2665 0.18170166015625 +2666 -0.011688232421875 +2667 0.0047607421875 +2668 -0.155303955078125 +2669 -0.17559814453125 +2670 -0.268035888671875 +2671 -0.3143310546875 +2672 -0.319305419921875 +2673 -0.36785888671875 +2674 -0.326263427734375 +2675 -0.36248779296875 +2676 -0.319305419921875 +2677 -0.343536376953125 +2678 -0.29205322265625 +2679 -0.3018798828125 +2680 -0.24041748046875 +2681 -0.231414794921875 +2682 -0.154876708984375 +2683 -0.117645263671875 +2684 -0.058013916015625 +2685 0.007049560546875 +2686 0.012176513671875 +2687 0.087982177734375 +2688 0.06451416015625 +2689 0.13946533203125 +2690 0.106658935546875 +2691 0.17425537109375 +2692 0.134735107421875 +2693 0.188201904296875 +2694 0.140869140625 +2695 0.171234130859375 +2696 0.120819091796875 +2697 0.118438720703125 +2698 0.09228515625 +2699 0.05706787109375 +2700 0.056060791015625 +2701 -0.010711669921875 +2702 0.00726318359375 +2703 -0.0914306640625 +2704 -0.038787841796875 +2705 -0.162322998046875 +2706 -0.0625 +2707 -0.194549560546875 +2708 -0.03729248046875 +2709 -0.1492919921875 +2710 0.04058837890625 +2711 -0.02166748046875 +2712 0.128021240234375 +2713 0.124053955078125 +2714 0.173553466796875 +2715 0.211151123046875 +2716 0.17852783203125 +2717 0.240447998046875 +2718 0.16436767578125 +2719 0.242218017578125 +2720 0.13824462890625 +2721 0.2257080078125 +2722 0.103302001953125 +2723 0.194366455078125 +2724 0.03802490234375 +2725 0.115509033203125 +2726 -0.0408935546875 +2727 0.0128173828125 +2728 -0.09228515625 +2729 -0.053802490234375 +2730 -0.1337890625 +2731 -0.110626220703125 +2732 -0.19378662109375 +2733 -0.199493408203125 +2734 -0.254730224609375 +2735 -0.29437255859375 +2736 -0.27398681640625 +2737 -0.33221435546875 +2738 -0.229400634765625 +2739 -0.27972412109375 +2740 -0.154449462890625 +2741 -0.185333251953125 +2742 -0.10357666015625 +2743 -0.128204345703125 +2744 -0.08245849609375 +2745 -0.115692138671875 +2746 -0.07049560546875 +2747 -0.116455078125 +2748 -0.051666259765625 +2749 -0.105926513671875 +2750 -0.006072998046875 +2751 -0.053955078125 +2752 0.07208251953125 +2753 0.048797607421875 +2754 0.15179443359375 +2755 0.157318115234375 +2756 0.192291259765625 +2757 0.212005615234375 +2758 0.197265625 +2759 0.218475341796875 +2760 0.207916259765625 +2761 0.23724365234375 +2762 0.2496337890625 +2763 0.30535888671875 +2764 0.29449462890625 +2765 0.38128662109375 +2766 0.301727294921875 +2767 0.404449462890625 +2768 0.28515625 +2769 0.3944091796875 +2770 0.270782470703125 +2771 0.3885498046875 +2772 0.24273681640625 +2773 0.362640380859375 +2774 0.172271728515625 +2775 0.27362060546875 +2776 0.056976318359375 +2777 0.11712646484375 +2778 -0.0673828125 +2779 -0.054901123046875 +2780 -0.16534423828125 +2781 -0.19085693359375 +2782 -0.233245849609375 +2783 -0.28570556640625 +2784 -0.270843505859375 +2785 -0.339263916015625 +2786 -0.29583740234375 +2787 -0.3775634765625 +2788 -0.339019775390625 +2789 -0.445709228515625 +2790 -0.394775390625 +2791 -0.535064697265625 +2792 -0.452117919921875 +2793 -0.629058837890625 +2794 -0.490997314453125 +2795 -0.697601318359375 +2796 -0.48687744140625 +2797 -0.70391845703125 +2798 -0.43646240234375 +2799 -0.6424560546875 +2800 -0.32525634765625 +2801 -0.491241455078125 +2802 -0.164215087890625 +2803 -0.265716552734375 +2804 0.00689697265625 +2805 -0.023712158203125 +2806 0.165313720703125 +2807 0.201751708984375 +2808 0.287078857421875 +2809 0.375823974609375 +2810 0.362945556640625 +2811 0.485076904296875 +2812 0.419647216796875 +2813 0.56884765625 +2814 0.462432861328125 +2815 0.634765625 +2816 0.461212158203125 +2817 0.63763427734375 +2818 0.409210205078125 +2819 0.5660400390625 +2820 0.341064453125 +2821 0.4720458984375 +2822 0.290252685546875 +2823 0.40692138671875 +2824 0.26177978515625 +2825 0.3778076171875 +2826 0.251068115234375 +2827 0.376953125 +2828 0.237640380859375 +2829 0.371978759765625 +2830 0.18975830078125 +2831 0.313140869140625 +2832 0.0975341796875 +2833 0.184417724609375 +2834 -0.022125244140625 +2835 0.011199951171875 +2836 -0.1458740234375 +2837 -0.171051025390625 +2838 -0.257293701171875 +2839 -0.33740234375 +2840 -0.345977783203125 +2841 -0.47198486328125 +2842 -0.402557373046875 +2843 -0.560394287109375 +2844 -0.412841796875 +2845 -0.58056640625 +2846 -0.38677978515625 +2847 -0.54754638671875 +2848 -0.35528564453125 +2849 -0.508575439453125 +2850 -0.3160400390625 +2851 -0.459503173828125 +2852 -0.265625 +2853 -0.394378662109375 +2854 -0.230010986328125 +2855 -0.35260009765625 +2856 -0.195098876953125 +2857 -0.31170654296875 +2858 -0.113250732421875 +2859 -0.197418212890625 +2860 0.016265869140625 +2861 -0.007965087890625 +2862 0.1612548828125 +2863 0.207489013671875 +2864 0.29571533203125 +2865 0.409210205078125 +2866 0.403228759765625 +2867 0.57208251953125 +2868 0.4642333984375 +2869 0.66595458984375 +2870 0.45794677734375 +2871 0.65875244140625 +2872 0.3955078125 +2873 0.56744384765625 +2874 0.302642822265625 +2875 0.431396484375 +2876 0.208038330078125 +2877 0.29443359375 +2878 0.128875732421875 +2879 0.182464599609375 +2880 0.044891357421875 +2881 0.06365966796875 +2882 -0.05255126953125 +2883 -0.075958251953125 +2884 -0.132659912109375 +2885 -0.189422607421875 +2886 -0.19195556640625 +2887 -0.271942138671875 +2888 -0.242462158203125 +2889 -0.342529296875 +2890 -0.260009765625 +2891 -0.364166259765625 +2892 -0.238189697265625 +2893 -0.327239990234375 +2894 -0.20623779296875 +2895 -0.2769775390625 +2896 -0.1903076171875 +2897 -0.253692626953125 +2898 -0.181549072265625 +2899 -0.24365234375 +2900 -0.14874267578125 +2901 -0.1983642578125 +2902 -0.091064453125 +2903 -0.116241455078125 +2904 -0.034393310546875 +2905 -0.036834716796875 +2906 0.0177001953125 +2907 0.034881591796875 +2908 0.0599365234375 +2909 0.09124755859375 +2910 0.076904296875 +2911 0.10888671875 +2912 0.092681884765625 +2913 0.125518798828125 +2914 0.117767333984375 +2915 0.15771484375 +2916 0.13433837890625 +2917 0.17828369140625 +2918 0.13177490234375 +2919 0.17108154296875 +2920 0.106048583984375 +2921 0.129974365234375 +2922 0.074920654296875 +2923 0.082427978515625 +2924 0.037994384765625 +2925 0.027679443359375 +2926 -0.024932861328125 +2927 -0.065643310546875 +2928 -0.0889892578125 +2929 -0.15936279296875 +2930 -0.127777099609375 +2931 -0.21307373046875 +2932 -0.14617919921875 +2933 -0.234649658203125 +2934 -0.12847900390625 +2935 -0.2001953125 +2936 -0.08050537109375 +2937 -0.119171142578125 +2938 -0.0235595703125 +2939 -0.024749755859375 +2940 0.04437255859375 +2941 0.085784912109375 +2942 0.101226806640625 +2943 0.178131103515625 +2944 0.123382568359375 +2945 0.215576171875 +2946 0.119537353515625 +2947 0.211456298828125 +2948 0.09588623046875 +2949 0.17523193359375 +2950 0.066558837890625 +2951 0.128753662109375 +2952 0.05084228515625 +2953 0.1019287109375 +2954 0.035430908203125 +2955 0.0743408203125 +2956 0.01837158203125 +2957 0.04327392578125 +2958 0.01861572265625 +2959 0.038177490234375 +2960 0.047088623046875 +2961 0.076263427734375 +2962 0.0928955078125 +2963 0.14105224609375 +2964 0.12591552734375 +2965 0.186431884765625 +2966 0.13067626953125 +2967 0.188812255859375 +2968 0.101104736328125 +2969 0.1390380859375 +2970 0.040069580078125 +2971 0.041778564453125 +2972 -0.0372314453125 +2973 -0.079437255859375 +2974 -0.12750244140625 +2975 -0.219390869140625 +2976 -0.224029541015625 +2977 -0.367828369140625 +2978 -0.30743408203125 +2979 -0.494873046875 +2980 -0.348968505859375 +2981 -0.556243896484375 +2982 -0.32049560546875 +2983 -0.508697509765625 +2984 -0.23699951171875 +2985 -0.3756103515625 +2986 -0.13848876953125 +2987 -0.218902587890625 +2988 -0.04107666015625 +2989 -0.063751220703125 +2990 0.056488037109375 +2991 0.091552734375 +2992 0.14727783203125 +2993 0.23602294921875 +2994 0.214141845703125 +2995 0.342987060546875 +2996 0.246063232421875 +2997 0.39520263671875 +2998 0.240997314453125 +2999 0.389373779296875 +3000 0.19818115234375 +3001 0.324249267578125 +3002 0.133331298828125 +3003 0.224090576171875 +3004 0.0693359375 +3005 0.124267578125 +3006 0.01409912109375 +3007 0.037078857421875 +3008 -0.014678955078125 +3009 -0.010101318359375 +3010 -0.0185546875 +3011 -0.019439697265625 +3012 -0.018280029296875 +3013 -0.022796630859375 +3014 -0.001953125 +3015 -0.001556396484375 +3016 0.038055419921875 +3017 0.056304931640625 +3018 0.07305908203125 +3019 0.106719970703125 +3020 0.068756103515625 +3021 0.096893310546875 +3022 0.035308837890625 +3023 0.042694091796875 +3024 -0.002838134765625 +3025 -0.018035888671875 +3026 -0.03961181640625 +3027 -0.07586669921875 +3028 -0.06768798828125 +3029 -0.11944580078125 +3030 -0.094146728515625 +3031 -0.15972900390625 +3032 -0.122772216796875 +3033 -0.202606201171875 +3034 -0.15380859375 +3035 -0.24859619140625 +3036 -0.1920166015625 +3037 -0.30517578125 +3038 -0.230743408203125 +3039 -0.36212158203125 +3040 -0.251708984375 +3041 -0.39141845703125 +3042 -0.23028564453125 +3043 -0.35528564453125 +3044 -0.163970947265625 +3045 -0.249969482421875 +3046 -0.06396484375 +3047 -0.092864990234375 +3048 0.0523681640625 +3049 0.08905029296875 +3050 0.145904541015625 +3051 0.2352294921875 +3052 0.199249267578125 +3053 0.318817138671875 +3054 0.22467041015625 +3055 0.358642578125 +3056 0.2176513671875 +3057 0.347747802734375 +3058 0.1778564453125 +3059 0.28564453125 +3060 0.138214111328125 +3061 0.223175048828125 +3062 0.122222900390625 +3063 0.196746826171875 +3064 0.1126708984375 +3065 0.179840087890625 +3066 0.0985107421875 +3067 0.155548095703125 +3068 0.097381591796875 +3069 0.151214599609375 +3070 0.102783203125 +3071 0.156951904296875 +3072 0.08819580078125 +3073 0.13177490234375 +3074 0.069366455078125 +3075 0.100799560546875 +3076 0.06103515625 +3077 0.087127685546875 +3078 0.040924072265625 +3079 0.05487060546875 +3080 0.000885009765625 +3081 -0.009002685546875 +3082 -0.0587158203125 +3083 -0.10400390625 +3084 -0.137420654296875 +3085 -0.229400634765625 +3086 -0.216888427734375 +3087 -0.35552978515625 +3088 -0.272064208984375 +3089 -0.441925048828125 +3090 -0.293792724609375 +3091 -0.473846435546875 +3092 -0.29022216796875 +3093 -0.464813232421875 +3094 -0.26385498046875 +3095 -0.419097900390625 +3096 -0.213104248046875 +3097 -0.334320068359375 +3098 -0.14862060546875 +3099 -0.227935791015625 +3100 -0.084869384765625 +3101 -0.12347412109375 +3102 -0.02593994140625 +3103 -0.02764892578125 +3104 0.039337158203125 +3105 0.077667236328125 +3106 0.12371826171875 +3107 0.2132568359375 +3108 0.233154296875 +3109 0.38885498046875 +3110 0.354217529296875 +3111 0.582794189453125 +3112 0.44921875 +3113 0.734039306640625 +3114 0.49188232421875 +3115 0.800140380859375 +3116 0.480377197265625 +3117 0.7783203125 +3118 0.412506103515625 +3119 0.6651611328125 +3120 0.287567138671875 +3121 0.45965576171875 +3122 0.128509521484375 +3123 0.199188232421875 +3124 -0.024383544921875 +3125 -0.050689697265625 +3126 -0.13604736328125 +3127 -0.23297119140625 +3128 -0.195709228515625 +3129 -0.33013916015625 +3130 -0.219482421875 +3131 -0.368408203125 +3132 -0.226531982421875 +3133 -0.378936767578125 +3134 -0.22625732421875 +3135 -0.376983642578125 +3136 -0.229156494140625 +3137 -0.37969970703125 +3138 -0.237884521484375 +3139 -0.391510009765625 +3140 -0.235687255859375 +3141 -0.385345458984375 +3142 -0.2105712890625 +3143 -0.3419189453125 +3144 -0.175811767578125 +3145 -0.28289794921875 +3146 -0.15802001953125 +3147 -0.251617431640625 +3148 -0.168212890625 +3149 -0.266143798828125 +3150 -0.17364501953125 +3151 -0.273345947265625 +3152 -0.13946533203125 +3153 -0.216796875 +3154 -0.085205078125 +3155 -0.128265380859375 +3156 -0.048095703125 +3157 -0.068145751953125 +3158 -0.0322265625 +3159 -0.0430908203125 +3160 -0.02001953125 +3161 -0.024444580078125 +3162 0.0087890625 +3163 0.020721435546875 +3164 0.073883056640625 +3165 0.124481201171875 +3166 0.1573486328125 +3167 0.25787353515625 +3168 0.23333740234375 +3169 0.379119873046875 +3170 0.296722412109375 +3171 0.47991943359375 +3172 0.32763671875 +3173 0.5281982421875 +3174 0.318145751953125 +3175 0.511138916015625 +3176 0.285125732421875 +3177 0.456207275390625 +3178 0.255706787109375 +3179 0.407470703125 +3180 0.241424560546875 +3181 0.383758544921875 +3182 0.224884033203125 +3183 0.35687255859375 +3184 0.1968994140625 +3185 0.31182861328125 +3186 0.158843994140625 +3187 0.250885009765625 +3188 0.105438232421875 +3189 0.1654052734375 +3190 0.02435302734375 +3191 0.035247802734375 +3192 -0.085906982421875 +3193 -0.142059326171875 +3194 -0.20623779296875 +3195 -0.33563232421875 +3196 -0.329803466796875 +3197 -0.5345458984375 +3198 -0.446136474609375 +3199 -0.72186279296875 +3200 -0.5177001953125 +3201 -0.836669921875 +3202 -0.515899658203125 +3203 -0.8326416015625 +3204 -0.452911376953125 +3205 -0.7296142578125 +3206 -0.36260986328125 +3207 -0.582550048828125 +3208 -0.274932861328125 +3209 -0.440093994140625 +3210 -0.203460693359375 +3211 -0.324310302734375 +3212 -0.12744140625 +3213 -0.20147705078125 +3214 -0.0302734375 +3215 -0.044647216796875 +3216 0.061981201171875 +3217 0.103973388671875 +3218 0.1234130859375 +3219 0.202392578125 +3220 0.16253662109375 +3221 0.264495849609375 +3222 0.209228515625 +3223 0.338897705078125 +3224 0.274658203125 +3225 0.443817138671875 +3226 0.337738037109375 +3227 0.545074462890625 +3228 0.382781982421875 +3229 0.6173095703125 +3230 0.40484619140625 +3231 0.6524658203125 +3232 0.41180419921875 +3233 0.66339111328125 +3234 0.4073486328125 +3235 0.6561279296875 +3236 0.376800537109375 +3237 0.606781005859375 +3238 0.311431884765625 +3239 0.501190185546875 +3240 0.21954345703125 +3241 0.352783203125 +3242 0.110382080078125 +3243 0.176544189453125 +3244 -0.020477294921875 +3245 -0.034820556640625 +3246 -0.15875244140625 +3247 -0.258209228515625 +3248 -0.27288818359375 +3249 -0.44244384765625 +3250 -0.355316162109375 +3251 -0.5753173828125 +3252 -0.403076171875 +3253 -0.65203857421875 +3254 -0.397064208984375 +3255 -0.641632080078125 +3256 -0.348388671875 +3257 -0.562164306640625 +3258 -0.284393310546875 +3259 -0.458038330078125 +3260 -0.21820068359375 +3261 -0.350555419921875 +3262 -0.162628173828125 +3263 -0.260528564453125 +3264 -0.120269775390625 +3265 -0.192108154296875 +3266 -0.08905029296875 +3267 -0.141937255859375 +3268 -0.06414794921875 +3269 -0.1021728515625 +3270 -0.03948974609375 +3271 -0.062896728515625 +3272 -0.007568359375 +3273 -0.011932373046875 +3274 0.03900146484375 +3275 0.062835693359375 +3276 0.0924072265625 +3277 0.148712158203125 +3278 0.150146484375 +3279 0.241729736328125 +3280 0.2166748046875 +3281 0.34912109375 +3282 0.283599853515625 +3283 0.457305908203125 +3284 0.33709716796875 +3285 0.54388427734375 +3286 0.355010986328125 +3287 0.5728759765625 +3288 0.31414794921875 +3289 0.506591796875 +3290 0.218292236328125 +3291 0.351226806640625 +3292 0.0919189453125 +3293 0.146514892578125 +3294 -0.032684326171875 +3295 -0.05523681640625 +3296 -0.132232666015625 +3297 -0.21624755859375 +3298 -0.205718994140625 +3299 -0.334930419921875 +3300 -0.248016357421875 +3301 -0.402984619140625 +3302 -0.27197265625 +3303 -0.4412841796875 +3304 -0.305908203125 +3305 -0.49578857421875 +3306 -0.345855712890625 +3307 -0.5601806640625 +3308 -0.371063232421875 +3309 -0.600738525390625 +3310 -0.361053466796875 +3311 -0.584228515625 +3312 -0.2965087890625 +3313 -0.47930908203125 +3314 -0.173370361328125 +3315 -0.27935791015625 +3316 -0.006744384765625 +3317 -0.0089111328125 +3318 0.164398193359375 +3319 0.268798828125 +3320 0.29638671875 +3321 0.482818603515625 +3322 0.371063232421875 +3323 0.60369873046875 +3324 0.40008544921875 +3325 0.650421142578125 +3326 0.408721923828125 +3327 0.66400146484375 +3328 0.395355224609375 +3329 0.6414794921875 +3330 0.353546142578125 +3331 0.572540283203125 +3332 0.307373046875 +3333 0.498138427734375 +3334 0.26947021484375 +3335 0.439453125 +3336 0.227874755859375 +3337 0.375518798828125 +3338 0.164276123046875 +3339 0.274505615234375 +3340 0.06280517578125 +3341 0.1087646484375 +3342 -0.063201904296875 +3343 -0.099395751953125 +3344 -0.1949462890625 +3345 -0.3182373046875 +3346 -0.33294677734375 +3347 -0.5489501953125 +3348 -0.4666748046875 +3349 -0.7738037109375 +3350 -0.56512451171875 +3351 -0.86383056640625 +3352 -0.60882568359375 +3353 -0.870391845703125 +3354 -0.608154296875 +3355 -0.86895751953125 +3356 -0.570831298828125 +3357 -0.861053466796875 +3358 -0.486846923828125 +3359 -0.765869140625 +3360 -0.349761962890625 +3361 -0.5301513671875 +3362 -0.163909912109375 +3363 -0.214691162109375 +3364 0.045379638671875 +3365 0.137359619140625 +3366 0.2479248046875 +3367 0.474822998046875 +3368 0.422760009765625 +3369 0.76239013671875 +3370 0.553924560546875 +3371 0.867462158203125 +3372 0.641510009765625 +3373 0.870361328125 +3374 0.678619384765625 +3375 0.86480712890625 +3376 0.668304443359375 +3377 0.831817626953125 +3378 0.624725341796875 +3379 0.677581787109375 +3380 0.55126953125 +3381 0.495880126953125 +3382 0.458831787109375 +3383 0.30767822265625 +3384 0.3487548828125 +3385 0.116180419921875 +3386 0.20263671875 +3387 -0.110748291015625 +3388 0.01654052734375 +3389 -0.381805419921875 +3390 -0.184326171875 +3391 -0.6572265625 +3392 -0.364837646484375 +3393 -0.857421875 +3394 -0.499755859375 +3395 -0.870391845703125 +3396 -0.584747314453125 +3397 -0.870391845703125 +3398 -0.635406494140625 +3399 -0.86444091796875 +3400 -0.67242431640625 +3401 -0.85723876953125 +3402 -0.68499755859375 +3403 -0.790008544921875 +3404 -0.641387939453125 +3405 -0.62847900390625 +3406 -0.539703369140625 +3407 -0.3956298828125 +3408 -0.39910888671875 +3409 -0.126708984375 +3410 -0.23565673828125 +3411 0.150115966796875 +3412 -0.0562744140625 +3413 0.424041748046875 +3414 0.123138427734375 +3415 0.670623779296875 +3416 0.279815673828125 +3417 0.854522705078125 +3418 0.403289794921875 +3419 0.866485595703125 +3420 0.48443603515625 +3421 0.86920166015625 +3422 0.53369140625 +3423 0.8653564453125 +3424 0.558746337890625 +3425 0.857147216796875 +3426 0.55780029296875 +3427 0.766845703125 +3428 0.533721923828125 +3429 0.628509521484375 +3430 0.482513427734375 +3431 0.462127685546875 +3432 0.41925048828125 +3433 0.297210693359375 +3434 0.351165771484375 +3435 0.14862060546875 +3436 0.26495361328125 +3437 -0.00537109375 +3438 0.16510009765625 +3439 -0.15753173828125 +3440 0.049560546875 +3441 -0.31304931640625 +3442 -0.0897216796875 +3443 -0.48876953125 +3444 -0.2252197265625 +3445 -0.6416015625 +3446 -0.34234619140625 +3447 -0.751373291015625 +3448 -0.4544677734375 +3449 -0.84619140625 +3450 -0.5528564453125 +3451 -0.861297607421875 +3452 -0.6180419921875 +3453 -0.863250732421875 +3454 -0.631500244140625 +3455 -0.856597900390625 +3456 -0.60028076171875 +3457 -0.7498779296875 +3458 -0.558135986328125 +3459 -0.624542236328125 +3460 -0.492218017578125 +3461 -0.47808837890625 +3462 -0.368408203125 +3463 -0.253387451171875 +3464 -0.21343994140625 +3465 0.003692626953125 +3466 -0.06732177734375 +3467 0.2257080078125 +3468 0.077178955078125 +3469 0.427154541015625 +3470 0.23883056640625 +3471 0.643218994140625 +3472 0.411865234375 +3473 0.855926513671875 +3474 0.56231689453125 +3475 0.870361328125 +3476 0.66107177734375 +3477 0.870361328125 +3478 0.712188720703125 +3479 0.862762451171875 +3480 0.7138671875 +3481 0.79669189453125 +3482 0.6605224609375 +3483 0.595794677734375 +3484 0.5692138671875 +3485 0.362152099609375 +3486 0.456298828125 +3487 0.1270751953125 +3488 0.33416748046875 +3489 -0.086944580078125 +3490 0.2041015625 +3491 -0.2784423828125 +3492 0.04583740234375 +3493 -0.484832763671875 +3494 -0.15167236328125 +3495 -0.729583740234375 +3496 -0.358734130859375 +3497 -0.86688232421875 +3498 -0.538238525390625 +3499 -0.870391845703125 +3500 -0.687103271484375 +3501 -0.86859130859375 +3502 -0.803955078125 +3503 -0.86279296875 +3504 -0.85595703125 +3505 -0.817962646484375 +3506 -0.851593017578125 +3507 -0.6116943359375 +3508 -0.751495361328125 +3509 -0.3128662109375 +3510 -0.5870361328125 +3511 0.039398193359375 +3512 -0.369903564453125 +3513 0.422821044921875 +3514 -0.119598388671875 +3515 0.805145263671875 +3516 0.1240234375 +3517 0.870361328125 +3518 0.3275146484375 +3519 0.870361328125 +3520 0.48382568359375 +3521 0.860015869140625 +3522 0.588226318359375 +3523 0.727935791015625 +3524 0.637176513671875 +3525 0.48114013671875 +3526 0.644561767578125 +3527 0.2059326171875 +3528 0.62335205078125 +3529 -0.06103515625 +3530 0.579193115234375 +3531 -0.29913330078125 +3532 0.503448486328125 +3533 -0.516204833984375 +3534 0.3870849609375 +3535 -0.7252197265625 +3536 0.24462890625 +3537 -0.85980224609375 +3538 0.096221923828125 +3539 -0.870391845703125 +3540 -0.0406494140625 +3541 -0.870391845703125 +3542 -0.13726806640625 +3543 -0.858062744140625 +3544 -0.190826416015625 +3545 -0.673004150390625 +3546 -0.231597900390625 +3547 -0.42694091796875 +3548 -0.285125732421875 +3549 -0.2100830078125 +3550 -0.3497314453125 +3551 -0.0362548828125 +3552 -0.4080810546875 +3553 0.10943603515625 +3554 -0.448211669921875 +3555 0.23516845703125 +3556 -0.4456787109375 +3557 0.373687744140625 +3558 -0.40142822265625 +3559 0.517791748046875 +3560 -0.352142333984375 +3561 0.602783203125 +3562 -0.294830322265625 +3563 0.635711669921875 +3564 -0.21014404296875 +3565 0.655181884765625 +3566 -0.104095458984375 +3567 0.65948486328125 +3568 0.018341064453125 +3569 0.651275634765625 +3570 0.142486572265625 +3571 0.61846923828125 +3572 0.246307373046875 +3573 0.53753662109375 +3574 0.318817138671875 +3575 0.404144287109375 +3576 0.353912353515625 +3577 0.22186279296875 +3578 0.351959228515625 +3579 0.003997802734375 +3580 0.32318115234375 +3581 -0.22100830078125 +3582 0.279327392578125 +3583 -0.42449951171875 +3584 0.23236083984375 +3585 -0.579833984375 +3586 0.206451416015625 +3587 -0.641876220703125 +3588 0.19830322265625 +3589 -0.6177978515625 +3590 0.17205810546875 +3591 -0.575531005859375 +3592 0.124725341796875 +3593 -0.526336669921875 +3594 0.084991455078125 +3595 -0.42645263671875 +3596 0.068267822265625 +3597 -0.2581787109375 +3598 0.0548095703125 +3599 -0.068695068359375 +3600 0.023773193359375 +3601 0.09222412109375 +3602 -0.014068603515625 +3603 0.232147216796875 +3604 -0.052642822265625 +3605 0.3509521484375 +3606 -0.107879638671875 +3607 0.410064697265625 +3608 -0.19561767578125 +3609 0.372955322265625 +3610 -0.303955078125 +3611 0.2554931640625 +3612 -0.4039306640625 +3613 0.10711669921875 +3614 -0.484588623046875 +3615 -0.052886962890625 +3616 -0.52593994140625 +3617 -0.186279296875 +3618 -0.497314453125 +3619 -0.23291015625 +3620 -0.411468505859375 +3621 -0.209442138671875 +3622 -0.3050537109375 +3623 -0.174163818359375 +3624 -0.183013916015625 +3625 -0.126739501953125 +3626 -0.040313720703125 +3627 -0.048126220703125 +3628 0.106964111328125 +3629 0.0426025390625 +3630 0.232635498046875 +3631 0.10748291015625 +3632 0.32891845703125 +3633 0.1409912109375 +3634 0.4217529296875 +3635 0.19708251953125 +3636 0.507049560546875 +3637 0.273651123046875 +3638 0.553741455078125 +3639 0.31768798828125 +3640 0.567779541015625 +3641 0.341094970703125 +3642 0.56304931640625 +3643 0.368011474609375 +3644 0.526885986328125 +3645 0.37249755859375 +3646 0.432220458984375 +3647 0.30072021484375 +3648 0.282012939453125 +3649 0.1517333984375 +3650 0.113311767578125 +3651 -0.01470947265625 +3652 -0.063751220703125 +3653 -0.1883544921875 +3654 -0.24658203125 +3655 -0.372711181640625 +3656 -0.401092529296875 +3657 -0.51397705078125 +3658 -0.50091552734375 +3659 -0.57177734375 +3660 -0.5389404296875 +3661 -0.53948974609375 +3662 -0.52239990234375 +3663 -0.43511962890625 +3664 -0.470245361328125 +3665 -0.2962646484375 +3666 -0.4027099609375 +3667 -0.161102294921875 +3668 -0.32757568359375 +3669 -0.0435791015625 +3670 -0.24365234375 +3671 0.060394287109375 +3672 -0.16064453125 +3673 0.13665771484375 +3674 -0.089508056640625 +3675 0.170135498046875 +3676 -0.0308837890625 +3677 0.16552734375 +3678 0.0306396484375 +3679 0.15728759765625 +3680 0.09429931640625 +3681 0.150787353515625 +3682 0.14312744140625 +3683 0.12200927734375 +3684 0.1787109375 +3685 0.080108642578125 +3686 0.212493896484375 +3687 0.05126953125 +3688 0.25714111328125 +3689 0.062896728515625 +3690 0.298583984375 +3691 0.09271240234375 +3692 0.309539794921875 +3693 0.092987060546875 +3694 0.2979736328125 +3695 0.07855224609375 +3696 0.272735595703125 +3697 0.06427001953125 +3698 0.2266845703125 +3699 0.0347900390625 +3700 0.1607666015625 +3701 -0.01171875 +3702 0.08807373046875 +3703 -0.056060791015625 +3704 0.0350341796875 +3705 -0.055511474609375 +3706 0.0045166015625 +3707 -0.010467529296875 +3708 -0.030181884765625 +3709 0.02508544921875 +3710 -0.0802001953125 +3711 0.025665283203125 +3712 -0.128509521484375 +3713 0.017333984375 +3714 -0.17193603515625 +3715 0.00189208984375 +3716 -0.214935302734375 +3717 -0.03173828125 +3718 -0.249847412109375 +3719 -0.071502685546875 +3720 -0.2862548828125 +3721 -0.13543701171875 +3722 -0.322479248046875 +3723 -0.219970703125 +3724 -0.3458251953125 +3725 -0.300506591796875 +3726 -0.357330322265625 +3727 -0.376312255859375 +3728 -0.341644287109375 +3729 -0.416107177734375 +3730 -0.27410888671875 +3731 -0.371124267578125 +3732 -0.157745361328125 +3733 -0.242279052734375 +3734 -0.017242431640625 +3735 -0.069732666015625 +3736 0.133392333984375 +3737 0.125640869140625 +3738 0.274688720703125 +3739 0.31268310546875 +3740 0.3846435546875 +3741 0.45501708984375 +3742 0.462921142578125 +3743 0.554779052734375 +3744 0.507781982421875 +3745 0.61065673828125 +3746 0.512237548828125 +3747 0.610931396484375 +3748 0.4630126953125 +3749 0.531463623046875 +3750 0.36956787109375 +3751 0.3883056640625 +3752 0.262298583984375 +3753 0.23468017578125 +3754 0.15631103515625 +3755 0.095245361328125 +3756 0.06768798828125 +3757 -0.00396728515625 +3758 0.006378173828125 +3759 -0.04852294921875 +3760 -0.03472900390625 +3761 -0.055145263671875 +3762 -0.082275390625 +3763 -0.0758056640625 +3764 -0.149871826171875 +3765 -0.138702392578125 +3766 -0.216705322265625 +3767 -0.209197998046875 +3768 -0.2823486328125 +3769 -0.289031982421875 +3770 -0.346160888671875 +3771 -0.37884521484375 +3772 -0.395263671875 +3773 -0.456329345703125 +3774 -0.4267578125 +3775 -0.51641845703125 +3776 -0.418975830078125 +3777 -0.519287109375 +3778 -0.368988037109375 +3779 -0.458251953125 +3780 -0.3062744140625 +3781 -0.384796142578125 +3782 -0.245880126953125 +3783 -0.323699951171875 +3784 -0.186248779296875 +3785 -0.269287109375 +3786 -0.114532470703125 +3787 -0.1951904296875 +3788 -0.03167724609375 +3789 -0.100006103515625 +3790 0.04583740234375 +3791 -0.01055908203125 +3792 0.13323974609375 +3793 0.1033935546875 +3794 0.233306884765625 +3795 0.24908447265625 +3796 0.315673828125 +3797 0.373199462890625 +3798 0.370025634765625 +3799 0.45806884765625 +3800 0.400390625 +3801 0.511474609375 +3802 0.424591064453125 +3803 0.565399169921875 +3804 0.43841552734375 +3805 0.61138916015625 +3806 0.40972900390625 +3807 0.5897216796875 +3808 0.334136962890625 +3809 0.4906005859375 +3810 0.222564697265625 +3811 0.33148193359375 +3812 0.095947265625 +3813 0.147796630859375 +3814 -0.021240234375 +3815 -0.01873779296875 +3816 -0.112274169921875 +3817 -0.140289306640625 +3818 -0.162139892578125 +3819 -0.191986083984375 +3820 -0.175537109375 +3821 -0.184295654296875 +3822 -0.176239013671875 +3823 -0.161834716796875 +3824 -0.18682861328125 +3825 -0.166595458984375 +3826 -0.204437255859375 +3827 -0.19390869140625 +3828 -0.218414306640625 +3829 -0.22442626953125 +3830 -0.240997314453125 +3831 -0.279754638671875 +3832 -0.26123046875 +3833 -0.3389892578125 +3834 -0.253570556640625 +3835 -0.3543701171875 +3836 -0.231292724609375 +3837 -0.348175048828125 +3838 -0.198577880859375 +3839 -0.32598876953125 +3840 -0.1402587890625 +3841 -0.2581787109375 +3842 -0.054779052734375 +3843 -0.139801025390625 +3844 0.04876708984375 +3845 0.014617919921875 +3846 0.135955810546875 +3847 0.144378662109375 +3848 0.1904296875 +3849 0.221038818359375 +3850 0.225921630859375 +3851 0.27069091796875 +3852 0.24249267578125 +3853 0.294036865234375 +3854 0.25146484375 +3855 0.311767578125 +3856 0.261322021484375 +3857 0.339141845703125 +3858 0.263336181640625 +3859 0.360260009765625 +3860 0.250213623046875 +3861 0.360504150390625 +3862 0.20654296875 +3863 0.308380126953125 +3864 0.121856689453125 +3865 0.18170166015625 +3866 0.010009765625 +3867 0.0047607421875 +3868 -0.10345458984375 +3869 -0.17559814453125 +3870 -0.194000244140625 +3871 -0.3143310546875 +3872 -0.238006591796875 +3873 -0.36785888671875 +3874 -0.248321533203125 +3875 -0.36248779296875 +3876 -0.247894287109375 +3877 -0.343536376953125 +3878 -0.2315673828125 +3879 -0.3018798828125 +3880 -0.19598388671875 +3881 -0.231414794921875 +3882 -0.133697509765625 +3883 -0.117645263671875 +3884 -0.06182861328125 +3885 0.007049560546875 +3886 -0.009307861328125 +3887 0.087982177734375 +3888 0.030609130859375 +3889 0.13946533203125 +3890 0.06378173828125 +3891 0.17425537109375 +3892 0.087158203125 +3893 0.188201904296875 +3894 0.094573974609375 +3895 0.171234130859375 +3896 0.08258056640625 +3897 0.118438720703125 +3898 0.064544677734375 +3899 0.05706787109375 +3900 0.040863037109375 +3901 -0.010711669921875 +3902 0.007568359375 +3903 -0.0914306640625 +3904 -0.023834228515625 +3905 -0.162322998046875 +3906 -0.03857421875 +3907 -0.194549560546875 +3908 -0.0164794921875 +3909 -0.1492919921875 +3910 0.045135498046875 +3911 -0.02166748046875 +3912 0.11322021484375 +3913 0.124053955078125 +3914 0.14837646484375 +3915 0.211151123046875 +3916 0.151641845703125 +3917 0.240447998046875 +3918 0.13946533203125 +3919 0.242218017578125 +3920 0.117431640625 +3921 0.2257080078125 +3922 0.08807373046875 +3923 0.194366455078125 +3924 0.03509521484375 +3925 0.115509033203125 +3926 -0.028533935546875 +3927 0.0128173828125 +3928 -0.0711669921875 +3929 -0.053802490234375 +3930 -0.1060791015625 +3931 -0.110626220703125 +3932 -0.15484619140625 +3933 -0.199493408203125 +3934 -0.203887939453125 +3935 -0.29437255859375 +3936 -0.220458984375 +3937 -0.33221435546875 +3938 -0.187530517578125 +3939 -0.27972412109375 +3940 -0.13067626953125 +3941 -0.185333251953125 +3942 -0.091522216796875 +3943 -0.128204345703125 +3944 -0.074462890625 +3945 -0.115692138671875 +3946 -0.0638427734375 +3947 -0.116455078125 +3948 -0.047454833984375 +3949 -0.105926513671875 +3950 -0.01025390625 +3951 -0.053955078125 +3952 0.052093505859375 +3953 0.048797607421875 +3954 0.115753173828125 +3955 0.157318115234375 +3956 0.14935302734375 +3957 0.212005615234375 +3958 0.155609130859375 +3959 0.218475341796875 +3960 0.165863037109375 +3961 0.23724365234375 +3962 0.199432373046875 +3963 0.30535888671875 +3964 0.234893798828125 +3965 0.38128662109375 +3966 0.24102783203125 +3967 0.404449462890625 +3968 0.228363037109375 +3969 0.3944091796875 +3970 0.216827392578125 +3971 0.3885498046875 +3972 0.194305419921875 +3973 0.362640380859375 +3974 0.138916015625 +3975 0.27362060546875 +3976 0.04888916015625 +3977 0.11712646484375 +3978 -0.04827880859375 +3979 -0.054901123046875 +3980 -0.125335693359375 +3981 -0.19085693359375 +3982 -0.17938232421875 +3983 -0.28570556640625 +3984 -0.21014404296875 +3985 -0.339263916015625 +3986 -0.23101806640625 +3987 -0.3775634765625 +3988 -0.2655029296875 +3989 -0.445709228515625 +3990 -0.309173583984375 +3991 -0.535064697265625 +3992 -0.3536376953125 +3993 -0.629058837890625 +3994 -0.383514404296875 +3995 -0.697601318359375 +3996 -0.38006591796875 +3997 -0.70391845703125 +3998 -0.340789794921875 +3999 -0.6424560546875 +4000 -0.254669189453125 +4001 -0.491241455078125 +4002 -0.130157470703125 +4003 -0.265716552734375 +4004 0.00225830078125 +4005 -0.023712158203125 +4006 0.125091552734375 +4007 0.201751708984375 +4008 0.219940185546875 +4009 0.375823974609375 +4010 0.27960205078125 +4011 0.485076904296875 +4012 0.324432373046875 +4013 0.56884765625 +4014 0.3583984375 +4015 0.634765625 +4016 0.3580322265625 +4017 0.63763427734375 +4018 0.317535400390625 +4019 0.5660400390625 +4020 0.26422119140625 +4021 0.4720458984375 +4022 0.225006103515625 +4023 0.40692138671875 +4024 0.203948974609375 +4025 0.3778076171875 +4026 0.197357177734375 +4027 0.376953125 +4028 0.188720703125 +4029 0.371978759765625 +4030 0.15252685546875 +4031 0.313140869140625 +4032 0.0806884765625 +4033 0.184417724609375 +4034 -0.0133056640625 +4035 0.011199951171875 +4036 -0.110809326171875 +4037 -0.171051025390625 +4038 -0.198760986328125 +4039 -0.33740234375 +4040 -0.268829345703125 +4041 -0.47198486328125 +4042 -0.3135986328125 +4043 -0.560394287109375 +4044 -0.321685791015625 +4045 -0.58056640625 +4046 -0.30108642578125 +4047 -0.54754638671875 +4048 -0.276580810546875 +4049 -0.508575439453125 +4050 -0.24627685546875 +4051 -0.459503173828125 +4052 -0.207366943359375 +4053 -0.394378662109375 +4054 -0.18060302734375 +4055 -0.35260009765625 +4056 -0.154571533203125 +4057 -0.31170654296875 +4058 -0.090911865234375 +4059 -0.197418212890625 +4060 0.01104736328125 +4061 -0.007965087890625 +4062 0.125579833984375 +4063 0.207489013671875 +4064 0.23193359375 +4065 0.409210205078125 +4066 0.3170166015625 +4067 0.57208251953125 +4068 0.365142822265625 +4069 0.66595458984375 +4070 0.359710693359375 +4071 0.65875244140625 +4072 0.30963134765625 +4073 0.56744384765625 +4074 0.235565185546875 +4075 0.431396484375 +4076 0.1605224609375 +4077 0.29443359375 +4078 0.098175048828125 +4079 0.182464599609375 +4080 0.0322265625 +4081 0.06365966796875 +4082 -0.044342041015625 +4083 -0.075958251953125 +4084 -0.10693359375 +4085 -0.189422607421875 +4086 -0.152862548828125 +4087 -0.271942138671875 +4088 -0.19183349609375 +4089 -0.342529296875 +4090 -0.204559326171875 +4091 -0.364166259765625 +4092 -0.18597412109375 +4093 -0.327239990234375 +4094 -0.159576416015625 +4095 -0.2769775390625 +4096 -0.146087646484375 +4097 -0.253692626953125 +4098 -0.138702392578125 +4099 -0.24365234375 +4100 -0.1134033203125 +4101 -0.1983642578125 +4102 -0.069488525390625 +4103 -0.116241455078125 +4104 -0.026336669921875 +4105 -0.036834716796875 +4106 0.013427734375 +4107 0.034881591796875 +4108 0.04583740234375 +4109 0.09124755859375 +4110 0.059234619140625 +4111 0.10888671875 +4112 0.071746826171875 +4113 0.125518798828125 +4114 0.09124755859375 +4115 0.15771484375 +4116 0.104248046875 +4117 0.17828369140625 +4118 0.10272216796875 +4119 0.17108154296875 +4120 0.083587646484375 +4121 0.129974365234375 +4122 0.060211181640625 +4123 0.082427978515625 +4124 0.032257080078125 +4125 0.027679443359375 +4126 -0.015472412109375 +4127 -0.065643310546875 +4128 -0.064178466796875 +4129 -0.15936279296875 +4130 -0.093994140625 +4131 -0.21307373046875 +4132 -0.108551025390625 +4133 -0.234649658203125 +4134 -0.095947265625 +4135 -0.2001953125 +4136 -0.060577392578125 +4137 -0.119171142578125 +4138 -0.018402099609375 +4139 -0.024749755859375 +4140 0.032073974609375 +4141 0.085784912109375 +4142 0.074310302734375 +4143 0.178131103515625 +4144 0.09051513671875 +4145 0.215576171875 +4146 0.0872802734375 +4147 0.211456298828125 +4148 0.06927490234375 +4149 0.17523193359375 +4150 0.04718017578125 +4151 0.128753662109375 +4152 0.0355224609375 +4153 0.1019287109375 +4154 0.02423095703125 +4155 0.0743408203125 +4156 0.0118408203125 +4157 0.04327392578125 +4158 0.012542724609375 +4159 0.038177490234375 +4160 0.034576416015625 +4161 0.076263427734375 +4162 0.069671630859375 +4163 0.14105224609375 +4164 0.09515380859375 +4165 0.186431884765625 +4166 0.099334716796875 +4167 0.188812255859375 +4168 0.07757568359375 +4169 0.1390380859375 +4170 0.03204345703125 +4171 0.041778564453125 +4172 -0.025848388671875 +4173 -0.079437255859375 +4174 -0.093597412109375 +4175 -0.219390869140625 +4176 -0.16619873046875 +4177 -0.367828369140625 +4178 -0.229034423828125 +4179 -0.494873046875 +4180 -0.260467529296875 +4181 -0.556243896484375 +4182 -0.239288330078125 +4183 -0.508697509765625 +4184 -0.176788330078125 +4185 -0.3756103515625 +4186 -0.10302734375 +4187 -0.218902587890625 +4188 -0.030120849609375 +4189 -0.063751220703125 +4190 0.042877197265625 +4191 0.091552734375 +4192 0.110748291015625 +4193 0.23602294921875 +4194 0.160614013671875 +4195 0.342987060546875 +4196 0.1842041015625 +4197 0.39520263671875 +4198 0.17999267578125 +4199 0.389373779296875 +4200 0.147430419921875 +4201 0.324249267578125 +4202 0.098388671875 +4203 0.224090576171875 +4204 0.050140380859375 +4205 0.124267578125 +4206 0.00860595703125 +4207 0.037078857421875 +4208 -0.012908935546875 +4209 -0.010101318359375 +4210 -0.01556396484375 +4211 -0.019439697265625 +4212 -0.0150146484375 +4213 -0.022796630859375 +4214 -0.002288818359375 +4215 -0.001556396484375 +4216 0.0283203125 +4217 0.056304931640625 +4218 0.05517578125 +4219 0.106719970703125 +4220 0.05242919921875 +4221 0.096893310546875 +4222 0.027679443359375 +4223 0.042694091796875 +4224 -0.00067138671875 +4225 -0.018035888671875 +4226 -0.028076171875 +4227 -0.07586669921875 +4228 -0.04901123046875 +4229 -0.11944580078125 +4230 -0.06884765625 +4231 -0.15972900390625 +4232 -0.0904541015625 +4233 -0.202606201171875 +4234 -0.113983154296875 +4235 -0.24859619140625 +4236 -0.143035888671875 +4237 -0.30517578125 +4238 -0.17254638671875 +4239 -0.36212158203125 +4240 -0.188720703125 +4241 -0.39141845703125 +4242 -0.173004150390625 +4243 -0.35528564453125 +4244 -0.12347412109375 +4245 -0.249969482421875 +4246 -0.04852294921875 +4247 -0.092864990234375 +4248 0.03875732421875 +4249 0.08905029296875 +4250 0.10888671875 +4251 0.2352294921875 +4252 0.148834228515625 +4253 0.318817138671875 +4254 0.167816162109375 +4255 0.358642578125 +4256 0.162445068359375 +4257 0.347747802734375 +4258 0.132476806640625 +4259 0.28564453125 +4260 0.102691650390625 +4261 0.223175048828125 +4262 0.090789794921875 +4263 0.196746826171875 +4264 0.08380126953125 +4265 0.179840087890625 +4266 0.073394775390625 +4267 0.155548095703125 +4268 0.07281494140625 +4269 0.151214599609375 +4270 0.0771484375 +4271 0.156951904296875 +4272 0.066314697265625 +4273 0.13177490234375 +4274 0.052520751953125 +4275 0.100799560546875 +4276 0.04693603515625 +4277 0.087127685546875 +4278 0.032012939453125 +4279 0.05487060546875 +4280 0.0013427734375 +4281 -0.009002685546875 +4282 -0.044830322265625 +4283 -0.10400390625 +4284 -0.10614013671875 +4285 -0.229400634765625 +4286 -0.1680908203125 +4287 -0.35552978515625 +4288 -0.210906982421875 +4289 -0.441925048828125 +4290 -0.227386474609375 +4291 -0.473846435546875 +4292 -0.22406005859375 +4293 -0.464813232421875 +4294 -0.202911376953125 +4295 -0.419097900390625 +4296 -0.1627197265625 +4297 -0.334320068359375 +4298 -0.111968994140625 +4299 -0.227935791015625 +4300 -0.06207275390625 +4301 -0.12347412109375 +4302 -0.0162353515625 +4303 -0.02764892578125 +4304 0.034423828125 +4305 0.077667236328125 +4306 0.100067138671875 +4307 0.2132568359375 +4308 0.185455322265625 +4309 0.38885498046875 +4310 0.280029296875 +4311 0.582794189453125 +4312 0.35400390625 +4313 0.734039306640625 +4314 0.38665771484375 +4315 0.800140380859375 +4316 0.3765869140625 +4317 0.7783203125 +4318 0.322113037109375 +4319 0.6651611328125 +4320 0.222686767578125 +4321 0.45965576171875 +4322 0.09649658203125 +4323 0.199188232421875 +4324 -0.024505615234375 +4325 -0.050689697265625 +4326 -0.112548828125 +4327 -0.23297119140625 +4328 -0.159149169921875 +4329 -0.33013916015625 +4330 -0.177093505859375 +4331 -0.368408203125 +4332 -0.181640625 +4333 -0.378936767578125 +4334 -0.1802978515625 +4335 -0.376983642578125 +4336 -0.18145751953125 +4337 -0.37969970703125 +4338 -0.187255859375 +4339 -0.391510009765625 +4340 -0.1844482421875 +4341 -0.385345458984375 +4342 -0.16363525390625 +4343 -0.3419189453125 +4344 -0.1353759765625 +4345 -0.28289794921875 +4346 -0.12078857421875 +4347 -0.251617431640625 +4348 -0.12860107421875 +4349 -0.266143798828125 +4350 -0.13287353515625 +4351 -0.273345947265625 +4352 -0.106170654296875 +4353 -0.216796875 +4354 -0.06365966796875 +4355 -0.128265380859375 +4356 -0.0338134765625 +4357 -0.068145751953125 +4358 -0.019805908203125 +4359 -0.0430908203125 +4360 -0.008697509765625 +4361 -0.024444580078125 +4362 0.01434326171875 +4363 0.020721435546875 +4364 0.06378173828125 +4365 0.124481201171875 +4366 0.126312255859375 +4367 0.25787353515625 +4368 0.182769775390625 +4369 0.379119873046875 +4370 0.229339599609375 +4371 0.47991943359375 +4372 0.251373291015625 +4373 0.5281982421875 +4374 0.243011474609375 +4375 0.511138916015625 +4376 0.216827392578125 +4377 0.456207275390625 +4378 0.193023681640625 +4379 0.407470703125 +4380 0.1802978515625 +4381 0.383758544921875 +4382 0.1658935546875 +4383 0.35687255859375 +4384 0.143096923828125 +4385 0.31182861328125 +4386 0.113037109375 +4387 0.250885009765625 +4388 0.071929931640625 +4389 0.1654052734375 +4390 0.010711669921875 +4391 0.035247802734375 +4392 -0.071624755859375 +4393 -0.142059326171875 +4394 -0.160919189453125 +4395 -0.33563232421875 +4396 -0.252166748046875 +4397 -0.5345458984375 +4398 -0.337615966796875 +4399 -0.72186279296875 +4400 -0.389495849609375 +4401 -0.836669921875 +4402 -0.386749267578125 +4403 -0.8326416015625 +4404 -0.3385009765625 +4405 -0.7296142578125 +4406 -0.2698974609375 +4407 -0.582550048828125 +4408 -0.20318603515625 +4409 -0.440093994140625 +4410 -0.1485595703125 +4411 -0.324310302734375 +4412 -0.0906982421875 +4413 -0.20147705078125 +4414 -0.017425537109375 +4415 -0.044647216796875 +4416 0.051910400390625 +4417 0.103973388671875 +4418 0.098052978515625 +4419 0.202392578125 +4420 0.12725830078125 +4421 0.264495849609375 +4422 0.16168212890625 +4423 0.338897705078125 +4424 0.209625244140625 +4425 0.443817138671875 +4426 0.2554931640625 +4427 0.545074462890625 +4428 0.287750244140625 +4429 0.6173095703125 +4430 0.302764892578125 +4431 0.6524658203125 +4432 0.30645751953125 +4433 0.66339111328125 +4434 0.301666259765625 +4435 0.6561279296875 +4436 0.277587890625 +4437 0.606781005859375 +4438 0.22784423828125 +4439 0.501190185546875 +4440 0.158660888671875 +4441 0.352783203125 +4442 0.076934814453125 +4443 0.176544189453125 +4444 -0.020538330078125 +4445 -0.034820556640625 +4446 -0.1231689453125 +4447 -0.258209228515625 +4448 -0.20758056640625 +4449 -0.44244384765625 +4450 -0.268218994140625 +4451 -0.5753173828125 +4452 -0.30291748046875 +4453 -0.65203857421875 +4454 -0.297576904296875 +4455 -0.641632080078125 +4456 -0.260467529296875 +4457 -0.562164306640625 +4458 -0.2119140625 +4459 -0.458038330078125 +4460 -0.16168212890625 +4461 -0.350555419921875 +4462 -0.11932373046875 +4463 -0.260528564453125 +4464 -0.086822509765625 +4465 -0.192108154296875 +4466 -0.062713623046875 +4467 -0.141937255859375 +4468 -0.043487548828125 +4469 -0.1021728515625 +4470 -0.024658203125 +4471 -0.062896728515625 +4472 -0.000701904296875 +4473 -0.011932373046875 +4474 0.033843994140625 +4475 0.062835693359375 +4476 0.07318115234375 +4477 0.148712158203125 +4478 0.115478515625 +4479 0.241729736328125 +4480 0.164031982421875 +4481 0.34912109375 +4482 0.212677001953125 +4483 0.457305908203125 +4484 0.251251220703125 +4485 0.54388427734375 +4486 0.263427734375 +4487 0.5728759765625 +4488 0.232086181640625 +4489 0.506591796875 +4490 0.16009521484375 +4491 0.351226806640625 +4492 0.065643310546875 +4493 0.146514892578125 +4494 -0.02734375 +4495 -0.05523681640625 +4496 -0.101593017578125 +4497 -0.21624755859375 +4498 -0.156341552734375 +4499 -0.334930419921875 +4500 -0.187774658203125 +4501 -0.402984619140625 +4502 -0.20538330078125 +4503 -0.4412841796875 +4504 -0.230133056640625 +4505 -0.49578857421875 +4506 -0.2591552734375 +4507 -0.5601806640625 +4508 -0.277099609375 +4509 -0.600738525390625 +4510 -0.268829345703125 +4511 -0.584228515625 +4512 -0.220123291015625 +4513 -0.47930908203125 +4514 -0.128021240234375 +4515 -0.27935791015625 +4516 -0.003753662109375 +4517 -0.0089111328125 +4518 0.123748779296875 +4519 0.268798828125 +4520 0.222137451171875 +4521 0.482818603515625 +4522 0.277923583984375 +4523 0.60369873046875 +4524 0.299713134765625 +4525 0.650421142578125 +4526 0.30621337890625 +4527 0.66400146484375 +4528 0.296051025390625 +4529 0.6414794921875 +4530 0.2645263671875 +4531 0.572540283203125 +4532 0.230316162109375 +4533 0.498138427734375 +4534 0.203094482421875 +4535 0.439453125 +4536 0.173370361328125 +4537 0.375518798828125 +4538 0.12664794921875 +4539 0.274505615234375 +4540 0.05035400390625 +4541 0.1087646484375 +4542 -0.0452880859375 +4543 -0.099395751953125 +4544 -0.145782470703125 +4545 -0.3182373046875 +4546 -0.251617431640625 +4547 -0.5489501953125 +4548 -0.35467529296875 +4549 -0.7738037109375 +4550 -0.4307861328125 +4551 -0.86383056640625 +4552 -0.464752197265625 +4553 -0.870391845703125 +4554 -0.46466064453125 +4555 -0.86895751953125 +4556 -0.436492919921875 +4557 -0.861053466796875 +4558 -0.37237548828125 +4559 -0.765869140625 +4560 -0.26715087890625 +4561 -0.5301513671875 +4562 -0.124114990234375 +4563 -0.214691162109375 +4564 0.037078857421875 +4565 0.137359619140625 +4566 0.1929931640625 +4567 0.474822998046875 +4568 0.327362060546875 +4569 0.76239013671875 +4570 0.427825927734375 +4571 0.867462158203125 +4572 0.49456787109375 +4573 0.870361328125 +4574 0.522308349609375 +4575 0.86480712890625 +4576 0.513458251953125 +4577 0.831817626953125 +4578 0.4791259765625 +4579 0.677581787109375 +4580 0.42193603515625 +4581 0.495880126953125 +4582 0.35040283203125 +4583 0.30767822265625 +4584 0.2655029296875 +4585 0.116180419921875 +4586 0.152801513671875 +4587 -0.110748291015625 +4588 0.009185791015625 +4589 -0.381805419921875 +4590 -0.14581298828125 +4591 -0.6572265625 +4592 -0.28485107421875 +4593 -0.857421875 +4594 -0.388336181640625 +4595 -0.870391845703125 +4596 -0.4530029296875 +4597 -0.870391845703125 +4598 -0.4910888671875 +4599 -0.86444091796875 +4600 -0.518829345703125 +4601 -0.85723876953125 +4602 -0.52783203125 +4603 -0.790008544921875 +4604 -0.49334716796875 +4605 -0.62847900390625 +4606 -0.413909912109375 +4607 -0.3956298828125 +4608 -0.3045654296875 +4609 -0.126708984375 +4610 -0.17779541015625 +4611 0.150115966796875 +4612 -0.039276123046875 +4613 0.424041748046875 +4614 0.098876953125 +4615 0.670623779296875 +4616 0.21966552734375 +4617 0.854522705078125 +4618 0.315093994140625 +4619 0.866485595703125 +4620 0.37823486328125 +4621 0.86920166015625 +4622 0.41650390625 +4623 0.8653564453125 +4624 0.4354248046875 +4625 0.857147216796875 +4626 0.433685302734375 +4627 0.766845703125 +4628 0.413543701171875 +4629 0.628509521484375 +4630 0.372314453125 +4631 0.462127685546875 +4632 0.3211669921875 +4633 0.297210693359375 +4634 0.265716552734375 +4635 0.14862060546875 +4636 0.1966552734375 +4637 -0.00537109375 +4638 0.11761474609375 +4639 -0.15753173828125 +4640 0.027496337890625 +4641 -0.31304931640625 +4642 -0.079193115234375 +4643 -0.48876953125 +4644 -0.182220458984375 +4645 -0.6416015625 +4646 -0.270751953125 +4647 -0.751373291015625 +4648 -0.35430908203125 +4649 -0.84619140625 +4650 -0.426513671875 +4651 -0.861297607421875 +4652 -0.47320556640625 +4653 -0.863250732421875 +4654 -0.480987548828125 +4655 -0.856597900390625 +4656 -0.455108642578125 +4657 -0.7498779296875 +4658 -0.420318603515625 +4659 -0.624542236328125 +4660 -0.367523193359375 +4661 -0.47808837890625 +4662 -0.27227783203125 +4663 -0.253387451171875 +4664 -0.154266357421875 +4665 0.003692626953125 +4666 -0.042877197265625 +4667 0.2257080078125 +4668 0.066802978515625 +4669 0.427154541015625 +4670 0.188201904296875 +4671 0.643218994140625 +4672 0.31695556640625 +4673 0.855926513671875 +4674 0.42822265625 +4675 0.870361328125 +4676 0.500823974609375 +4677 0.870361328125 +4678 0.537689208984375 +4679 0.862762451171875 +4680 0.53753662109375 +4681 0.79669189453125 +4682 0.496429443359375 +4683 0.595794677734375 +4684 0.4268798828125 +4685 0.362152099609375 +4686 0.340972900390625 +4687 0.1270751953125 +4688 0.2479248046875 +4689 -0.086944580078125 +4690 0.148956298828125 +4691 -0.2784423828125 +4692 0.02960205078125 +4693 -0.484832763671875 +4694 -0.117889404296875 +4695 -0.729583740234375 +4696 -0.27178955078125 +4697 -0.86688232421875 +4698 -0.404937744140625 +4699 -0.870391845703125 +4700 -0.514984130859375 +4701 -0.86859130859375 +4702 -0.600830078125 +4703 -0.86279296875 +4704 -0.6470947265625 +4705 -0.817962646484375 +4706 -0.634490966796875 +4707 -0.6116943359375 +4708 -0.56005859375 +4709 -0.3128662109375 +4710 -0.43817138671875 +4711 0.039398193359375 +4712 -0.2774658203125 +4713 0.422821044921875 +4714 -0.092254638671875 +4715 0.805145263671875 +4716 0.0882568359375 +4717 0.870361328125 +4718 0.239593505859375 +4719 0.870361328125 +4720 0.356475830078125 +4721 0.860015869140625 +4722 0.435302734375 +4723 0.727935791015625 +4724 0.473358154296875 +4725 0.48114013671875 +4726 0.480560302734375 +4727 0.2059326171875 +4728 0.46624755859375 +4729 -0.06103515625 +4730 0.43450927734375 +4731 -0.29913330078125 +4732 0.37908935546875 +4733 -0.516204833984375 +4734 0.29345703125 +4735 -0.7252197265625 +4736 0.188262939453125 +4737 -0.85980224609375 +4738 0.0782470703125 +4739 -0.870391845703125 +4740 -0.023773193359375 +4741 -0.870391845703125 +4742 -0.0968017578125 +4743 -0.858062744140625 +4744 -0.138641357421875 +4745 -0.673004150390625 +4746 -0.171112060546875 +4747 -0.42694091796875 +4748 -0.212615966796875 +4749 -0.2100830078125 +4750 -0.26177978515625 +4751 -0.0362548828125 +4752 -0.305877685546875 +4753 0.10943603515625 +4754 -0.336151123046875 +4755 0.23516845703125 +4756 -0.334808349609375 +4757 0.373687744140625 +4758 -0.302520751953125 +4759 0.517791748046875 +4760 -0.2659912109375 +4761 0.602783203125 +4762 -0.22308349609375 +4763 0.635711669921875 +4764 -0.15985107421875 +4765 0.655181884765625 +4766 -0.080718994140625 +4767 0.65948486328125 +4768 0.010498046875 +4769 0.651275634765625 +4770 0.10302734375 +4771 0.61846923828125 +4772 0.180755615234375 +4773 0.53753662109375 +4774 0.235565185546875 +4775 0.404144287109375 +4776 0.262939453125 +4777 0.22186279296875 +4778 0.263031005859375 +4779 0.003997802734375 +4780 0.243194580078125 +4781 -0.22100830078125 +4782 0.2119140625 +4783 -0.42449951171875 +4784 0.1781005859375 +4785 -0.579833984375 +4786 0.159820556640625 +4787 -0.641876220703125 +4788 0.154266357421875 +4789 -0.6177978515625 +4790 0.134185791015625 +4791 -0.575531005859375 +4792 0.097503662109375 +4793 -0.526336669921875 +4794 0.06646728515625 +4795 -0.42645263671875 +4796 0.053009033203125 +4797 -0.2581787109375 +4798 0.0421142578125 +4799 -0.068695068359375 +4800 0.017852783203125 +4801 0.09222412109375 +4802 -0.011474609375 +4803 0.232147216796875 +4804 -0.041168212890625 +4805 0.3509521484375 +4806 -0.08349609375 +4807 0.410064697265625 +4808 -0.150604248046875 +4809 0.372955322265625 +4810 -0.23345947265625 +4811 0.2554931640625 +4812 -0.309814453125 +4813 0.10711669921875 +4814 -0.371337890625 +4815 -0.052886962890625 +4816 -0.4027099609375 +4817 -0.186279296875 +4818 -0.380340576171875 +4819 -0.23291015625 +4820 -0.3140869140625 +4821 -0.209442138671875 +4822 -0.232147216796875 +4823 -0.174163818359375 +4824 -0.138336181640625 +4825 -0.126739501953125 +4826 -0.02880859375 +4827 -0.048126220703125 +4828 0.084136962890625 +4829 0.0426025390625 +4830 0.180389404296875 +4831 0.10748291015625 +4832 0.2540283203125 +4833 0.1409912109375 +4834 0.32489013671875 +4835 0.19708251953125 +4836 0.389923095703125 +4837 0.273651123046875 +4838 0.42529296875 +4839 0.31768798828125 +4840 0.43560791015625 +4841 0.341094970703125 +4842 0.4315185546875 +4843 0.368011474609375 +4844 0.403350830078125 +4845 0.37249755859375 +4846 0.330322265625 +4847 0.30072021484375 +4848 0.2147216796875 +4849 0.1517333984375 +4850 0.08502197265625 +4851 -0.01470947265625 +4852 -0.05096435546875 +4853 -0.1883544921875 +4854 -0.191253662109375 +4855 -0.372711181640625 +4856 -0.309661865234375 +4857 -0.51397705078125 +4858 -0.385986328125 +4859 -0.57177734375 +4860 -0.414794921875 +4861 -0.53948974609375 +4862 -0.40167236328125 +4863 -0.43511962890625 +4864 -0.3614501953125 +4865 -0.2962646484375 +4866 -0.309814453125 +4867 -0.161102294921875 +4868 -0.252593994140625 +4869 -0.0435791015625 +4870 -0.188812255859375 +4871 0.060394287109375 +4872 -0.125457763671875 +4873 0.13665771484375 +4874 -0.070465087890625 +4875 0.170135498046875 +4876 -0.02435302734375 +4877 0.16552734375 +4878 0.023895263671875 +4879 0.15728759765625 +4880 0.0736083984375 +4881 0.150787353515625 +4882 0.1123046875 +4883 0.12200927734375 +4884 0.1409912109375 +4885 0.080108642578125 +4886 0.16778564453125 +4887 0.05126953125 +4888 0.201751708984375 +4889 0.062896728515625 +4890 0.23260498046875 +4891 0.09271240234375 +4892 0.240509033203125 +4893 0.092987060546875 +4894 0.231292724609375 +4895 0.07855224609375 +4896 0.21136474609375 +4897 0.06427001953125 +4898 0.1756591796875 +4899 0.0347900390625 +4900 0.125 +4901 -0.01171875 +4902 0.069061279296875 +4903 -0.056060791015625 +4904 0.027191162109375 +4905 -0.055511474609375 +4906 0.001617431640625 +4907 -0.010467529296875 +4908 -0.02679443359375 +4909 0.02508544921875 +4910 -0.06591796875 +4911 0.025665283203125 +4912 -0.103302001953125 +4913 0.017333984375 +4914 -0.13653564453125 +4915 0.00189208984375 +4916 -0.16876220703125 +4917 -0.03173828125 +4918 -0.19439697265625 +4919 -0.071502685546875 +4920 -0.220367431640625 +4921 -0.13543701171875 +4922 -0.245513916015625 +4923 -0.219970703125 +4924 -0.26068115234375 +4925 -0.300506591796875 +4926 -0.266754150390625 +4927 -0.376312255859375 +4928 -0.252777099609375 +4929 -0.416107177734375 +4930 -0.2010498046875 +4931 -0.371124267578125 +4932 -0.113861083984375 +4933 -0.242279052734375 +4934 -0.00927734375 +4935 -0.069732666015625 +4936 0.102386474609375 +4937 0.125640869140625 +4938 0.206878662109375 +4939 0.31268310546875 +4940 0.288177490234375 +4941 0.45501708984375 +4942 0.345947265625 +4943 0.554779052734375 +4944 0.37890625 +4945 0.61065673828125 +4946 0.381988525390625 +4947 0.610931396484375 +4948 0.3455810546875 +4949 0.531463623046875 +4950 0.276580810546875 +4951 0.3883056640625 +4952 0.1971435546875 +4953 0.23468017578125 +4954 0.1182861328125 +4955 0.095245361328125 +4956 0.05181884765625 +4957 -0.00396728515625 +4958 0.00506591796875 +4959 -0.04852294921875 +4960 -0.027008056640625 +4961 -0.055145263671875 +4962 -0.063568115234375 +4963 -0.0758056640625 +4964 -0.1143798828125 +4965 -0.138702392578125 +4966 -0.164276123046875 +4967 -0.209197998046875 +4968 -0.212860107421875 +4969 -0.289031982421875 +4970 -0.259674072265625 +4971 -0.37884521484375 +4972 -0.295318603515625 +4973 -0.456329345703125 +4974 -0.31768798828125 +4975 -0.51641845703125 +4976 -0.3111572265625 +4977 -0.519287109375 +4978 -0.27362060546875 +4979 -0.458251953125 +4980 -0.2265625 +4981 -0.384796142578125 +4982 -0.18096923828125 +4983 -0.323699951171875 +4984 -0.13580322265625 +4985 -0.269287109375 +4986 -0.081878662109375 +4987 -0.1951904296875 +4988 -0.019989013671875 +4989 -0.100006103515625 +4990 0.037841796875 +4991 -0.01055908203125 +4992 0.1025390625 +4993 0.1033935546875 +4994 0.176055908203125 +4995 0.24908447265625 +4996 0.236328125 +4997 0.373199462890625 +4998 0.275848388671875 +4999 0.45806884765625 +5000 0.297576904296875 +5001 0.511474609375 +5002 0.314422607421875 +5003 0.565399169921875 +5004 0.32342529296875 +5005 0.61138916015625 +5006 0.30133056640625 +5007 0.5897216796875 +5008 0.24505615234375 +5009 0.4906005859375 +5010 0.16259765625 +5011 0.33148193359375 +5012 0.0692138671875 +5013 0.147796630859375 +5014 -0.01727294921875 +5015 -0.01873779296875 +5016 -0.084625244140625 +5017 -0.140289306640625 +5018 -0.121917724609375 +5019 -0.191986083984375 +5020 -0.13250732421875 +5021 -0.184295654296875 +5022 -0.133575439453125 +5023 -0.161834716796875 +5024 -0.141448974609375 +5025 -0.166595458984375 +5026 -0.154083251953125 +5027 -0.19390869140625 +5028 -0.163726806640625 +5029 -0.22442626953125 +5030 -0.179290771484375 +5031 -0.279754638671875 +5032 -0.192901611328125 +5033 -0.3389892578125 +5034 -0.1861572265625 +5035 -0.3543701171875 +5036 -0.168731689453125 +5037 -0.348175048828125 +5038 -0.143707275390625 +5039 -0.32598876953125 +5040 -0.100189208984375 +5041 -0.2581787109375 +5042 -0.037078857421875 +5043 -0.139801025390625 +5044 0.038970947265625 +5045 0.014617919921875 +5046 0.1029052734375 +5047 0.144378662109375 +5048 0.142822265625 +5049 0.221038818359375 +5050 0.168701171875 +5051 0.27069091796875 +5052 0.18060302734375 +5053 0.294036865234375 +5054 0.186737060546875 +5055 0.311767578125 +5056 0.193328857421875 +5057 0.339141845703125 +5058 0.194305419921875 +5059 0.360260009765625 +5060 0.184295654296875 +5061 0.360504150390625 +5062 0.151611328125 +5063 0.308380126953125 +5064 0.088348388671875 +5065 0.18170166015625 +5066 0.004852294921875 +5067 0.0047607421875 +5068 -0.0797119140625 +5069 -0.17559814453125 +5070 -0.146942138671875 +5071 -0.3143310546875 +5072 -0.179107666015625 +5073 -0.36785888671875 +5074 -0.185943603515625 +5075 -0.36248779296875 +5076 -0.184783935546875 +5077 -0.343536376953125 +5078 -0.17181396484375 +5079 -0.3018798828125 +5080 -0.144500732421875 +5081 -0.231414794921875 +5082 -0.097259521484375 +5083 -0.117645263671875 +5084 -0.042999267578125 +5085 0.007049560546875 +5086 -0.0035400390625 +5087 0.087982177734375 +5088 0.026214599609375 +5089 0.13946533203125 +5090 0.05072021484375 +5091 0.17425537109375 +5092 0.06768798828125 +5093 0.188201904296875 +5094 0.072540283203125 +5095 0.171234130859375 +5096 0.062744140625 +5097 0.118438720703125 +5098 0.04840087890625 +5099 0.05706787109375 +5100 0.02984619140625 +5101 -0.010711669921875 +5102 0.004119873046875 +5103 -0.0914306640625 +5104 -0.02008056640625 +5105 -0.162322998046875 +5106 -0.031585693359375 +5107 -0.194549560546875 +5108 -0.015167236328125 +5109 -0.1492919921875 +5110 0.031219482421875 +5111 -0.02166748046875 +5112 0.0826416015625 +5113 0.124053955078125 +5114 0.109375 +5115 0.211151123046875 +5116 0.112213134765625 +5117 0.240447998046875 +5118 0.103515625 +5119 0.242218017578125 +5120 0.086944580078125 +5121 0.2257080078125 +5122 0.06463623046875 +5123 0.194366455078125 +5124 0.025970458984375 +5125 0.115509033203125 +5126 -0.019927978515625 +5127 0.0128173828125 +5128 -0.05108642578125 +5129 -0.053802490234375 +5130 -0.076629638671875 +5131 -0.110626220703125 +5132 -0.111480712890625 +5133 -0.199493408203125 +5134 -0.146148681640625 +5135 -0.29437255859375 +5136 -0.15802001953125 +5137 -0.33221435546875 +5138 -0.13531494140625 +5139 -0.27972412109375 +5140 -0.095703125 +5141 -0.185333251953125 +5142 -0.06805419921875 +5143 -0.128204345703125 +5144 -0.055450439453125 +5145 -0.115692138671875 +5146 -0.047088623046875 +5147 -0.116455078125 +5148 -0.03460693359375 +5149 -0.105926513671875 +5150 -0.00762939453125 +5151 -0.053955078125 +5152 0.0367431640625 +5153 0.048797607421875 +5154 0.081939697265625 +5155 0.157318115234375 +5156 0.106201171875 +5157 0.212005615234375 +5158 0.111328125 +5159 0.218475341796875 +5160 0.1190185546875 +5161 0.23724365234375 +5162 0.142608642578125 +5163 0.30535888671875 +5164 0.167236328125 +5165 0.38128662109375 +5166 0.1712646484375 +5167 0.404449462890625 +5168 0.16204833984375 +5169 0.3944091796875 +5170 0.153411865234375 +5171 0.3885498046875 +5172 0.13702392578125 +5173 0.362640380859375 +5174 0.0977783203125 +5175 0.27362060546875 +5176 0.034515380859375 +5177 0.11712646484375 +5178 -0.03369140625 +5179 -0.054901123046875 +5180 -0.087921142578125 +5181 -0.19085693359375 +5182 -0.126129150390625 +5183 -0.28570556640625 +5184 -0.148101806640625 +5185 -0.339263916015625 +5186 -0.163055419921875 +5187 -0.3775634765625 +5188 -0.187225341796875 +5189 -0.445709228515625 +5190 -0.217559814453125 +5191 -0.535064697265625 +5192 -0.248260498046875 +5193 -0.629058837890625 +5194 -0.2686767578125 +5195 -0.697601318359375 +5196 -0.26580810546875 +5197 -0.70391845703125 +5198 -0.23797607421875 +5199 -0.6424560546875 +5200 -0.1776123046875 +5201 -0.491241455078125 +5202 -0.090606689453125 +5203 -0.265716552734375 +5204 0.00189208984375 +5205 -0.023712158203125 +5206 0.08770751953125 +5207 0.201751708984375 +5208 0.154052734375 +5209 0.375823974609375 +5210 0.1959228515625 +5211 0.485076904296875 +5212 0.227386474609375 +5213 0.56884765625 +5214 0.25115966796875 +5215 0.634765625 +5216 0.2509765625 +5217 0.63763427734375 +5218 0.22283935546875 +5219 0.5660400390625 +5220 0.185638427734375 +5221 0.4720458984375 +5222 0.158050537109375 +5223 0.40692138671875 +5224 0.1429443359375 +5225 0.3778076171875 +5226 0.137786865234375 +5227 0.376953125 +5228 0.13116455078125 +5229 0.371978759765625 +5230 0.10540771484375 +5231 0.313140869140625 +5232 0.055023193359375 +5233 0.184417724609375 +5234 -0.0106201171875 +5235 0.011199951171875 +5236 -0.078582763671875 +5237 -0.171051025390625 +5238 -0.139801025390625 +5239 -0.33740234375 +5240 -0.18853759765625 +5241 -0.47198486328125 +5242 -0.2196044921875 +5243 -0.560394287109375 +5244 -0.225128173828125 +5245 -0.58056640625 +5246 -0.210662841796875 +5247 -0.54754638671875 +5248 -0.193389892578125 +5249 -0.508575439453125 +5250 -0.1719970703125 +5251 -0.459503173828125 +5252 -0.144561767578125 +5253 -0.394378662109375 +5254 -0.125457763671875 +5255 -0.35260009765625 +5256 -0.106842041015625 +5257 -0.31170654296875 +5258 -0.06219482421875 +5259 -0.197418212890625 +5260 0.0089111328125 +5261 -0.007965087890625 +5262 0.088653564453125 +5263 0.207489013671875 +5264 0.16259765625 +5265 0.409210205078125 +5266 0.2216796875 +5267 0.57208251953125 +5268 0.25506591796875 +5269 0.66595458984375 +5270 0.251251220703125 +5271 0.65875244140625 +5272 0.2164306640625 +5273 0.56744384765625 +5274 0.164886474609375 +5275 0.431396484375 +5276 0.112579345703125 +5277 0.29443359375 +5278 0.069000244140625 +5279 0.182464599609375 +5280 0.02288818359375 +5281 0.06365966796875 +5282 -0.03057861328125 +5283 -0.075958251953125 +5284 -0.0743408203125 +5285 -0.189422607421875 +5286 -0.10650634765625 +5287 -0.271942138671875 +5288 -0.1337890625 +5289 -0.342529296875 +5290 -0.142822265625 +5291 -0.364166259765625 +5292 -0.130096435546875 +5293 -0.327239990234375 +5294 -0.111846923828125 +5295 -0.2769775390625 +5296 -0.1026611328125 +5297 -0.253692626953125 +5298 -0.097625732421875 +5299 -0.24365234375 +5300 -0.079376220703125 +5301 -0.1983642578125 +5302 -0.0474853515625 +5303 -0.116241455078125 +5304 -0.01629638671875 +5305 -0.036834716796875 +5306 0.01220703125 +5307 0.034881591796875 +5308 0.035125732421875 +5309 0.09124755859375 +5310 0.043914794921875 +5311 0.10888671875 +5312 0.052001953125 +5313 0.125518798828125 +5314 0.065277099609375 +5315 0.15771484375 +5316 0.0738525390625 +5317 0.17828369140625 +5318 0.071868896484375 +5319 0.17108154296875 +5320 0.057098388671875 +5321 0.129974365234375 +5322 0.039459228515625 +5323 0.082427978515625 +5324 0.018707275390625 +5325 0.027679443359375 +5326 -0.016357421875 +5327 -0.065643310546875 +5328 -0.0518798828125 +5329 -0.15936279296875 +5330 -0.0732421875 +5331 -0.21307373046875 +5332 -0.0831298828125 +5333 -0.234649658203125 +5334 -0.072845458984375 +5335 -0.2001953125 +5336 -0.045684814453125 +5337 -0.119171142578125 +5338 -0.013458251953125 +5339 -0.024749755859375 +5340 0.024871826171875 +5341 0.085784912109375 +5342 0.0570068359375 +5343 0.178131103515625 +5344 0.06976318359375 +5345 0.215576171875 +5346 0.0679931640625 +5347 0.211456298828125 +5348 0.05511474609375 +5349 0.17523193359375 +5350 0.038970947265625 +5351 0.128753662109375 +5352 0.030303955078125 +5353 0.1019287109375 +5354 0.021697998046875 +5355 0.0743408203125 +5356 0.012054443359375 +5357 0.04327392578125 +5358 0.01190185546875 +5359 0.038177490234375 +5360 0.027374267578125 +5361 0.076263427734375 +5362 0.052398681640625 +5363 0.14105224609375 +5364 0.070281982421875 +5365 0.186431884765625 +5366 0.07244873046875 +5367 0.188812255859375 +5368 0.055572509765625 +5369 0.1390380859375 +5370 0.02130126953125 +5371 0.041778564453125 +5372 -0.021942138671875 +5373 -0.079437255859375 +5374 -0.072296142578125 +5375 -0.219390869140625 +5376 -0.125701904296875 +5377 -0.367828369140625 +5378 -0.170928955078125 +5379 -0.494873046875 +5380 -0.192962646484375 +5381 -0.556243896484375 +5382 -0.1778564453125 +5383 -0.508697509765625 +5384 -0.133514404296875 +5385 -0.3756103515625 +5386 -0.080535888671875 +5387 -0.218902587890625 +5388 -0.027435302734375 +5389 -0.063751220703125 +5390 0.02606201171875 +5391 0.091552734375 +5392 0.07611083984375 +5393 0.23602294921875 +5394 0.113800048828125 +5395 0.342987060546875 +5396 0.13330078125 +5397 0.39520263671875 +5398 0.133392333984375 +5399 0.389373779296875 +5400 0.11358642578125 +5401 0.324249267578125 +5402 0.081787109375 +5403 0.224090576171875 +5404 0.049560546875 +5405 0.124267578125 +5406 0.02093505859375 +5407 0.037078857421875 +5408 0.0048828125 +5409 -0.010101318359375 +5410 0.000732421875 +5411 -0.019439697265625 +5412 -0.0018310546875 +5413 -0.022796630859375 +5414 0.003387451171875 +5415 -0.001556396484375 +5416 0.02044677734375 +5417 0.056304931640625 +5418 0.035003662109375 +5419 0.106719970703125 +5420 0.02984619140625 +5421 0.096893310546875 +5422 0.01031494140625 +5423 0.042694091796875 +5424 -0.011077880859375 +5425 -0.018035888671875 +5426 -0.031158447265625 +5427 -0.07586669921875 +5428 -0.046173095703125 +5429 -0.11944580078125 +5430 -0.0596923828125 +5431 -0.15972900390625 +5432 -0.073638916015625 +5433 -0.202606201171875 +5434 -0.088165283203125 +5435 -0.24859619140625 +5436 -0.10577392578125 +5437 -0.30517578125 +5438 -0.123199462890625 +5439 -0.36212158203125 +5440 -0.131317138671875 +5441 -0.39141845703125 +5442 -0.117828369140625 +5443 -0.35528564453125 +5444 -0.08160400390625 +5445 -0.249969482421875 +5446 -0.028472900390625 +5447 -0.092864990234375 +5448 0.032623291015625 +5449 0.08905029296875 +5450 0.081756591796875 +5451 0.2352294921875 +5452 0.110076904296875 +5453 0.318817138671875 +5454 0.12371826171875 +5455 0.358642578125 +5456 0.120391845703125 +5457 0.347747802734375 +5458 0.09991455078125 +5459 0.28564453125 +5460 0.0789794921875 +5461 0.223175048828125 +5462 0.069549560546875 +5463 0.196746826171875 +5464 0.06298828125 +5465 0.179840087890625 +5466 0.053802490234375 +5467 0.155548095703125 +5468 0.051055908203125 +5469 0.151214599609375 +5470 0.05157470703125 +5471 0.156951904296875 +5472 0.041961669921875 +5473 0.13177490234375 +5474 0.030548095703125 +5475 0.100799560546875 +5476 0.02496337890625 +5477 0.087127685546875 +5478 0.013519287109375 +5479 0.05487060546875 +5480 -0.00799560546875 +5481 -0.009002685546875 +5482 -0.039398193359375 +5483 -0.10400390625 +5484 -0.0804443359375 +5485 -0.229400634765625 +5486 -0.121429443359375 +5487 -0.35552978515625 +5488 -0.14910888671875 +5489 -0.441925048828125 +5490 -0.15869140625 +5491 -0.473846435546875 +5492 -0.1546630859375 +5493 -0.464813232421875 +5494 -0.13848876953125 +5495 -0.419097900390625 +5496 -0.109466552734375 +5497 -0.334320068359375 +5498 -0.0733642578125 +5499 -0.227935791015625 +5500 -0.0379638671875 +5501 -0.12347412109375 +5502 -0.00555419921875 +5503 -0.02764892578125 +5504 0.029754638671875 +5505 0.077667236328125 +5506 0.074737548828125 +5507 0.2132568359375 +5508 0.132568359375 +5509 0.38885498046875 +5510 0.196136474609375 +5511 0.582794189453125 +5512 0.24542236328125 +5513 0.734039306640625 +5514 0.266510009765625 +5515 0.800140380859375 +5516 0.258544921875 +5517 0.7783203125 +5518 0.220458984375 +5519 0.6651611328125 +5520 0.1519775390625 +5521 0.45965576171875 +5522 0.0654296875 +5523 0.199188232421875 +5524 -0.017608642578125 +5525 -0.050689697265625 +5526 -0.078338623046875 +5527 -0.23297119140625 +5528 -0.11102294921875 +5529 -0.33013916015625 +5530 -0.12420654296875 +5531 -0.368408203125 +5532 -0.1280517578125 +5533 -0.378936767578125 +5534 -0.127593994140625 +5535 -0.376983642578125 +5536 -0.128448486328125 +5537 -0.37969970703125 +5538 -0.132080078125 +5539 -0.391510009765625 +5540 -0.129608154296875 +5541 -0.385345458984375 +5542 -0.11474609375 +5543 -0.3419189453125 +5544 -0.094635009765625 +5545 -0.28289794921875 +5546 -0.08349609375 +5547 -0.251617431640625 +5548 -0.087310791015625 +5549 -0.266143798828125 +5550 -0.0887451171875 +5551 -0.273345947265625 +5552 -0.069305419921875 +5553 -0.216796875 +5554 -0.039459228515625 +5555 -0.128265380859375 +5556 -0.01904296875 +5557 -0.068145751953125 +5558 -0.01031494140625 +5559 -0.0430908203125 +5560 -0.003875732421875 +5561 -0.024444580078125 +5562 0.01104736328125 +5563 0.020721435546875 +5564 0.044921875 +5565 0.124481201171875 +5566 0.088287353515625 +5567 0.25787353515625 +5568 0.127471923828125 +5569 0.379119873046875 +5570 0.1597900390625 +5571 0.47991943359375 +5572 0.174774169921875 +5573 0.5281982421875 +5574 0.16827392578125 +5575 0.511138916015625 +5576 0.14935302734375 +5577 0.456207275390625 +5578 0.13250732421875 +5579 0.407470703125 +5580 0.12396240234375 +5581 0.383758544921875 +5582 0.114471435546875 +5583 0.35687255859375 +5584 0.099151611328125 +5585 0.31182861328125 +5586 0.078765869140625 +5587 0.250885009765625 +5588 0.050506591796875 +5589 0.1654052734375 +5590 0.0078125 +5591 0.035247802734375 +5592 -0.05010986328125 +5593 -0.142059326171875 +5594 -0.1131591796875 +5595 -0.33563232421875 +5596 -0.17779541015625 +5597 -0.5345458984375 +5598 -0.23846435546875 +5599 -0.72186279296875 +5600 -0.275238037109375 +5601 -0.836669921875 +5602 -0.272979736328125 +5603 -0.8326416015625 +5604 -0.238250732421875 +5605 -0.7296142578125 +5606 -0.18914794921875 +5607 -0.582550048828125 +5608 -0.14166259765625 +5609 -0.440093994140625 +5610 -0.10308837890625 +5611 -0.324310302734375 +5612 -0.0623779296875 +5613 -0.20147705078125 +5614 -0.01068115234375 +5615 -0.044647216796875 +5616 0.038116455078125 +5617 0.103973388671875 +5618 0.070220947265625 +5619 0.202392578125 +5620 0.090179443359375 +5621 0.264495849609375 +5622 0.113983154296875 +5623 0.338897705078125 +5624 0.14764404296875 +5625 0.443817138671875 +5626 0.17999267578125 +5627 0.545074462890625 +5628 0.202789306640625 +5629 0.6173095703125 +5630 0.21343994140625 +5631 0.6524658203125 +5632 0.2158203125 +5633 0.66339111328125 +5634 0.211822509765625 +5635 0.6561279296875 +5636 0.194244384765625 +5637 0.606781005859375 +5638 0.15911865234375 +5639 0.501190185546875 +5640 0.11065673828125 +5641 0.352783203125 +5642 0.053619384765625 +5643 0.176544189453125 +5644 -0.013824462890625 +5645 -0.034820556640625 +5646 -0.08453369140625 +5647 -0.258209228515625 +5648 -0.14312744140625 +5649 -0.44244384765625 +5650 -0.18572998046875 +5651 -0.5753173828125 +5652 -0.210784912109375 +5653 -0.65203857421875 +5654 -0.209014892578125 +5655 -0.641632080078125 +5656 -0.18572998046875 +5657 -0.562164306640625 +5658 -0.154083251953125 +5659 -0.458038330078125 +5660 -0.12042236328125 +5661 -0.350555419921875 +5662 -0.091064453125 +5663 -0.260528564453125 +5664 -0.067413330078125 +5665 -0.192108154296875 +5666 -0.04864501953125 +5667 -0.141937255859375 +5668 -0.03265380859375 +5669 -0.1021728515625 +5670 -0.016754150390625 +5671 -0.062896728515625 +5672 0.00238037109375 +5673 -0.011932373046875 +5674 0.02813720703125 +5675 0.062835693359375 +5676 0.05657958984375 +5677 0.148712158203125 +5678 0.086334228515625 +5679 0.241729736328125 +5680 0.119476318359375 +5681 0.34912109375 +5682 0.151947021484375 +5683 0.457305908203125 +5684 0.177093505859375 +5685 0.54388427734375 +5686 0.184326171875 +5687 0.5728759765625 +5688 0.16259765625 +5689 0.506591796875 +5690 0.1138916015625 +5691 0.351226806640625 +5692 0.05010986328125 +5693 0.146514892578125 +5694 -0.013031005859375 +5695 -0.05523681640625 +5696 -0.064178466796875 +5697 -0.21624755859375 +5698 -0.102630615234375 +5699 -0.334930419921875 +5700 -0.12579345703125 +5701 -0.402984619140625 +5702 -0.1396484375 +5703 -0.4412841796875 +5704 -0.15771484375 +5705 -0.49578857421875 +5706 -0.17803955078125 +5707 -0.5601806640625 +5708 -0.190582275390625 +5709 -0.600738525390625 +5710 -0.18548583984375 +5711 -0.584228515625 +5712 -0.15350341796875 +5713 -0.47930908203125 +5714 -0.0927734375 +5715 -0.27935791015625 +5716 -0.010650634765625 +5717 -0.0089111328125 +5718 0.073974609375 +5719 0.268798828125 +5720 0.139984130859375 +5721 0.482818603515625 +5722 0.178497314453125 +5723 0.60369873046875 +5724 0.194976806640625 +5725 0.650421142578125 +5726 0.201416015625 +5727 0.66400146484375 +5728 0.19683837890625 +5729 0.6414794921875 +5730 0.178070068359375 +5731 0.572540283203125 +5732 0.15716552734375 +5733 0.498138427734375 +5734 0.140380859375 +5735 0.439453125 +5736 0.1214599609375 +5737 0.375518798828125 +5738 0.09100341796875 +5739 0.274505615234375 +5740 0.0408935546875 +5741 0.1087646484375 +5742 -0.022186279296875 +5743 -0.099395751953125 +5744 -0.0887451171875 +5745 -0.3182373046875 +5746 -0.1590576171875 +5747 -0.5489501953125 +5748 -0.22772216796875 +5749 -0.7738037109375 +5750 -0.2789306640625 +5751 -0.86383056640625 +5752 -0.302764892578125 +5753 -0.870391845703125 +5754 -0.304351806640625 +5755 -0.86895751953125 +5756 -0.287506103515625 +5757 -0.861053466796875 +5758 -0.247039794921875 +5759 -0.765869140625 +5760 -0.179595947265625 +5761 -0.5301513671875 +5762 -0.087249755859375 +5763 -0.214691162109375 +5764 0.017242431640625 +5765 0.137359619140625 +5766 0.118682861328125 +5767 0.474822998046875 +5768 0.206512451171875 +5769 0.76239013671875 +5770 0.27264404296875 +5771 0.867462158203125 +5772 0.317138671875 +5773 0.870361328125 +5774 0.33648681640625 +5775 0.86480712890625 +5776 0.3321533203125 +5777 0.831817626953125 +5778 0.311279296875 +5779 0.677581787109375 +5780 0.2755126953125 +5781 0.495880126953125 +5782 0.23028564453125 +5783 0.30767822265625 +5784 0.17620849609375 +5785 0.116180419921875 +5786 0.103851318359375 +5787 -0.110748291015625 +5788 0.0111083984375 +5789 -0.381805419921875 +5790 -0.08929443359375 +5791 -0.6572265625 +5792 -0.179595947265625 +5793 -0.857421875 +5794 -0.247100830078125 +5795 -0.870391845703125 +5796 -0.289642333984375 +5797 -0.870391845703125 +5798 -0.315155029296875 +5799 -0.86444091796875 +5800 -0.3341064453125 +5801 -0.85723876953125 +5802 -0.34100341796875 +5803 -0.790008544921875 +5804 -0.3197021484375 +5805 -0.62847900390625 +5806 -0.26922607421875 +5807 -0.3956298828125 +5808 -0.199249267578125 +5809 -0.126708984375 +5810 -0.1177978515625 +5811 0.150115966796875 +5812 -0.0283203125 +5813 0.424041748046875 +5814 0.061187744140625 +5815 0.670623779296875 +5816 0.1392822265625 +5817 0.854522705078125 +5818 0.200714111328125 +5819 0.866485595703125 +5820 0.240936279296875 +5821 0.86920166015625 +5822 0.2652587890625 +5823 0.8653564453125 +5824 0.277618408203125 +5825 0.857147216796875 +5826 0.277099609375 +5827 0.766845703125 +5828 0.265167236328125 +5829 0.628509521484375 +5830 0.239776611328125 +5831 0.462127685546875 +5832 0.208526611328125 +5833 0.297210693359375 +5834 0.175018310546875 +5835 0.14862060546875 +5836 0.1324462890625 +5837 -0.00537109375 +5838 0.0830078125 +5839 -0.15753173828125 +5840 0.025634765625 +5841 -0.31304931640625 +5842 -0.0438232421875 +5843 -0.48876953125 +5844 -0.111480712890625 +5845 -0.6416015625 +5846 -0.16998291015625 +5847 -0.751373291015625 +5848 -0.22613525390625 +5849 -0.84619140625 +5850 -0.275543212890625 +5851 -0.861297607421875 +5852 -0.308380126953125 +5853 -0.863250732421875 +5854 -0.31524658203125 +5855 -0.856597900390625 +5856 -0.2996826171875 +5857 -0.7498779296875 +5858 -0.278778076171875 +5859 -0.624542236328125 +5860 -0.246002197265625 +5861 -0.47808837890625 +5862 -0.184051513671875 +5863 -0.253387451171875 +5864 -0.106414794921875 +5865 0.003692626953125 +5866 -0.0333251953125 +5867 0.2257080078125 +5868 0.038909912109375 +5869 0.427154541015625 +5870 0.119873046875 +5871 0.643218994140625 +5872 0.206695556640625 +5873 0.855926513671875 +5874 0.282196044921875 +5875 0.870361328125 +5876 0.3316650390625 +5877 0.870361328125 +5878 0.357208251953125 +5879 0.862762451171875 +5880 0.35791015625 +5881 0.79669189453125 +5882 0.330963134765625 +5883 0.595794677734375 +5884 0.28497314453125 +5885 0.362152099609375 +5886 0.22821044921875 +5887 0.1270751953125 +5888 0.166351318359375 +5889 -0.086944580078125 +5890 0.0997314453125 +5891 -0.2784423828125 +5892 0.01947021484375 +5893 -0.484832763671875 +5894 -0.078582763671875 +5895 -0.729583740234375 +5896 -0.1802978515625 +5897 -0.86688232421875 +5898 -0.268310546875 +5899 -0.870391845703125 +5900 -0.3408203125 +5901 -0.86859130859375 +5902 -0.3968505859375 +5903 -0.86279296875 +5904 -0.426727294921875 +5905 -0.817962646484375 +5906 -0.418426513671875 +5907 -0.6116943359375 +5908 -0.37017822265625 +5909 -0.3128662109375 +5910 -0.291107177734375 +5911 0.039398193359375 +5912 -0.186798095703125 +5913 0.422821044921875 +5914 -0.066497802734375 +5915 0.805145263671875 +5916 0.051300048828125 +5917 0.870361328125 +5918 0.15106201171875 +5919 0.870361328125 +5920 0.2291259765625 +5921 0.860015869140625 +5922 0.282958984375 +5923 0.727935791015625 +5924 0.310638427734375 +5925 0.48114013671875 +5926 0.318145751953125 +5927 0.2059326171875 +5928 0.3111572265625 +5929 -0.06103515625 +5930 0.292083740234375 +5931 -0.29913330078125 +5932 0.257049560546875 +5933 -0.516204833984375 +5934 0.202056884765625 +5935 -0.7252197265625 +5936 0.13385009765625 +5937 -0.85980224609375 +5938 0.061798095703125 +5939 -0.870391845703125 +5940 -0.005889892578125 +5941 -0.870391845703125 +5942 -0.055877685546875 +5943 -0.858062744140625 +5944 -0.0865478515625 +5945 -0.673004150390625 +5946 -0.111236572265625 +5947 -0.42694091796875 +5948 -0.141143798828125 +5949 -0.2100830078125 +5950 -0.17523193359375 +5951 -0.0362548828125 +5952 -0.205413818359375 +5953 0.10943603515625 +5954 -0.226043701171875 +5955 0.23516845703125 +5956 -0.225982666015625 +5957 0.373687744140625 +5958 -0.2056884765625 +5959 0.517791748046875 +5960 -0.181793212890625 +5961 0.602783203125 +5962 -0.153076171875 +5963 0.635711669921875 +5964 -0.1109619140625 +5965 0.655181884765625 +5966 -0.05841064453125 +5967 0.65948486328125 +5968 0.00201416015625 +5969 0.651275634765625 +5970 0.06341552734375 +5971 0.61846923828125 +5972 0.115509033203125 +5973 0.53753662109375 +5974 0.153076171875 +5975 0.404144287109375 +5976 0.173095703125 +5977 0.22186279296875 +5978 0.175537109375 +5979 0.003997802734375 +5980 0.16485595703125 +5981 -0.22100830078125 +5982 0.14630126953125 +5983 -0.42449951171875 +5984 0.125335693359375 +5985 -0.579833984375 +5986 0.113250732421875 +5987 -0.641876220703125 +5988 0.108367919921875 +5989 -0.6177978515625 +5990 0.09381103515625 +5991 -0.575531005859375 +5992 0.06842041015625 +5993 -0.526336669921875 +5994 0.04620361328125 +5995 -0.42645263671875 +5996 0.03472900390625 +5997 -0.2581787109375 +5998 0.02484130859375 +5999 -0.068695068359375 +6000 0.006805419921875 +6001 0.09222412109375 +6002 -0.0140380859375 +6003 0.232147216796875 +6004 -0.034637451171875 +6005 0.3509521484375 +6006 -0.062530517578125 +6007 0.410064697265625 +6008 -0.105224609375 +6009 0.372955322265625 +6010 -0.157073974609375 +6011 0.2554931640625 +6012 -0.2042236328125 +6013 0.10711669921875 +6014 -0.241485595703125 +6015 -0.052886962890625 +6016 -0.2593994140625 +6017 -0.186279296875 +6018 -0.243438720703125 +6019 -0.23291015625 +6020 -0.1998291015625 +6021 -0.209442138671875 +6022 -0.146270751953125 +6023 -0.174163818359375 +6024 -0.085296630859375 +6025 -0.126739501953125 +6026 -0.014617919921875 +6027 -0.048126220703125 +6028 0.05792236328125 +6029 0.0426025390625 +6030 0.11968994140625 +6031 0.10748291015625 +6032 0.166900634765625 +6033 0.1409912109375 +6034 0.211883544921875 +6035 0.19708251953125 +6036 0.252685546875 +6037 0.273651123046875 +6038 0.27447509765625 +6039 0.31768798828125 +6040 0.2801513671875 +6041 0.341094970703125 +6042 0.27642822265625 +6043 0.368011474609375 +6044 0.25732421875 +6045 0.37249755859375 +6046 0.209991455078125 +6047 0.30072021484375 +6048 0.135955810546875 +6049 0.1517333984375 +6050 0.053070068359375 +6051 -0.01470947265625 +6052 -0.03369140625 +6053 -0.1883544921875 +6054 -0.122955322265625 +6055 -0.372711181640625 +6056 -0.198333740234375 +6057 -0.51397705078125 +6058 -0.24713134765625 +6059 -0.57177734375 +6060 -0.26593017578125 +6061 -0.53948974609375 +6062 -0.258148193359375 +6063 -0.43511962890625 +6064 -0.232879638671875 +6065 -0.2962646484375 +6066 -0.199798583984375 +6067 -0.161102294921875 +6068 -0.162689208984375 +6069 -0.0435791015625 +6070 -0.121063232421875 +6071 0.060394287109375 +6072 -0.079681396484375 +6073 0.13665771484375 +6074 -0.04388427734375 +6075 0.170135498046875 +6076 -0.0140380859375 +6077 0.16552734375 +6078 0.017120361328125 +6079 0.15728759765625 +6080 0.049102783203125 +6081 0.150787353515625 +6082 0.07373046875 +6083 0.12200927734375 +6084 0.091705322265625 +6085 0.080108642578125 +6086 0.108428955078125 +6087 0.05126953125 +6088 0.129974365234375 +6089 0.062896728515625 +6090 0.14959716796875 +6091 0.09271240234375 +6092 0.154266357421875 +6093 0.092987060546875 +6094 0.1478271484375 +6095 0.07855224609375 +6096 0.13458251953125 +6097 0.06427001953125 +6098 0.111175537109375 +6099 0.0347900390625 +6100 0.078125 +6101 -0.01171875 +6102 0.041839599609375 +6103 -0.056060791015625 +6104 0.0150146484375 +6105 -0.055511474609375 +6106 -0.000885009765625 +6107 -0.010467529296875 +6108 -0.0185546875 +6109 0.02508544921875 +6110 -0.04327392578125 +6111 0.025665283203125 +6112 -0.066864013671875 +6113 0.017333984375 +6114 -0.087799072265625 +6115 0.00189208984375 +6116 -0.10821533203125 +6117 -0.03173828125 +6118 -0.12445068359375 +6119 -0.071502685546875 +6120 -0.14111328125 +6121 -0.13543701171875 +6122 -0.157470703125 +6123 -0.219970703125 +6124 -0.16748046875 +6125 -0.300506591796875 +6126 -0.171722412109375 +6127 -0.376312255859375 +6128 -0.1629638671875 +6129 -0.416107177734375 +6130 -0.12945556640625 +6131 -0.371124267578125 +6132 -0.072662353515625 +6133 -0.242279052734375 +6134 -0.004486083984375 +6135 -0.069732666015625 +6136 0.06829833984375 +6137 0.125640869140625 +6138 0.136322021484375 +6139 0.31268310546875 +6140 0.189056396484375 +6141 0.45501708984375 +6142 0.226348876953125 +6143 0.554779052734375 +6144 0.247161865234375 +6145 0.61065673828125 +6146 0.24835205078125 +6147 0.610931396484375 +6148 0.224212646484375 +6149 0.531463623046875 +6150 0.179229736328125 +6151 0.3883056640625 +6152 0.12738037109375 +6153 0.23468017578125 +6154 0.07574462890625 +6155 0.095245361328125 +6156 0.0318603515625 +6157 -0.00396728515625 +6158 0.000396728515625 +6159 -0.04852294921875 +6160 -0.021636962890625 +6161 -0.055145263671875 +6162 -0.046112060546875 +6163 -0.0758056640625 +6164 -0.079071044921875 +6165 -0.138702392578125 +6166 -0.1109619140625 +6167 -0.209197998046875 +6168 -0.14154052734375 +6169 -0.289031982421875 +6170 -0.170501708984375 +6171 -0.37884521484375 +6172 -0.1920166015625 +6173 -0.456329345703125 +6174 -0.204864501953125 +6175 -0.51641845703125 +6176 -0.199310302734375 +6177 -0.519287109375 +6178 -0.174163818359375 +6179 -0.458251953125 +6180 -0.142913818359375 +6181 -0.384796142578125 +6182 -0.112548828125 +6183 -0.323699951171875 +6184 -0.082489013671875 +6185 -0.269287109375 +6186 -0.047149658203125 +6187 -0.1951904296875 +6188 -0.007080078125 +6189 -0.100006103515625 +6190 0.030120849609375 +6191 -0.01055908203125 +6192 0.07122802734375 +6193 0.1033935546875 +6194 0.117431640625 +6195 0.24908447265625 +6196 0.15496826171875 +6197 0.373199462890625 +6198 0.17913818359375 +6199 0.45806884765625 +6200 0.191802978515625 +6201 0.511474609375 +6202 0.20111083984375 +6203 0.565399169921875 +6204 0.205291748046875 +6205 0.61138916015625 +6206 0.189910888671875 +6207 0.5897216796875 +6208 0.153106689453125 +6209 0.4906005859375 +6210 0.100006103515625 +6211 0.33148193359375 +6212 0.04022216796875 +6213 0.147796630859375 +6214 -0.015045166015625 +6215 -0.01873779296875 +6216 -0.058074951171875 +6217 -0.140289306640625 +6218 -0.082000732421875 +6219 -0.191986083984375 +6220 -0.088897705078125 +6221 -0.184295654296875 +6222 -0.089508056640625 +6223 -0.161834716796875 +6224 -0.094024658203125 +6225 -0.166595458984375 +6226 -0.1011962890625 +6227 -0.19390869140625 +6228 -0.10626220703125 +6229 -0.22442626953125 +6230 -0.114837646484375 +6231 -0.279754638671875 +6232 -0.1220703125 +6233 -0.3389892578125 +6234 -0.11651611328125 +6235 -0.3543701171875 +6236 -0.10430908203125 +6237 -0.348175048828125 +6238 -0.087432861328125 +6239 -0.32598876953125 +6240 -0.059112548828125 +6241 -0.2581787109375 +6242 -0.01873779296875 +6243 -0.139801025390625 +6244 0.029449462890625 +6245 0.014617919921875 +6246 0.069793701171875 +6247 0.144378662109375 +6248 0.09478759765625 +6249 0.221038818359375 +6250 0.110687255859375 +6251 0.27069091796875 +6252 0.117584228515625 +6253 0.294036865234375 +6254 0.12066650390625 +6255 0.311767578125 +6256 0.123809814453125 +6257 0.339141845703125 +6258 0.123077392578125 +6259 0.360260009765625 +6260 0.115264892578125 +6261 0.360504150390625 +6262 0.093658447265625 +6263 0.308380126953125 +6264 0.0537109375 +6265 0.18170166015625 +6266 0.001739501953125 +6267 0.0047607421875 +6268 -0.05072021484375 +6269 -0.17559814453125 +6270 -0.0926513671875 +6271 -0.3143310546875 +6272 -0.113433837890625 +6273 -0.36785888671875 +6274 -0.118743896484375 +6275 -0.36248779296875 +6276 -0.1187744140625 +6277 -0.343536376953125 +6278 -0.111236572265625 +6279 -0.3018798828125 +6280 -0.09466552734375 +6281 -0.231414794921875 +6282 -0.0657958984375 +6283 -0.117645263671875 +6284 -0.032318115234375 +6285 0.007049560546875 +6286 -0.007232666015625 +6287 0.087982177734375 +6288 0.012359619140625 +6289 0.13946533203125 +6290 0.028961181640625 +6291 0.17425537109375 +6292 0.041107177734375 +6293 0.188201904296875 +6294 0.04595947265625 +6295 0.171234130859375 +6296 0.041900634765625 +6297 0.118438720703125 +6298 0.034881591796875 +6299 0.05706787109375 +6300 0.02496337890625 +6301 -0.010711669921875 +6302 0.0103759765625 +6303 -0.0914306640625 +6304 -0.00372314453125 +6305 -0.162322998046875 +6306 -0.0107421875 +6307 -0.194549560546875 +6308 -0.001678466796875 +6309 -0.1492919921875 +6310 0.02471923828125 +6311 -0.02166748046875 +6312 0.053802490234375 +6313 0.124053955078125 +6314 0.068023681640625 +6315 0.211151123046875 +6316 0.067962646484375 +6317 0.240447998046875 +6318 0.061065673828125 +6319 0.242218017578125 +6320 0.049896240234375 +6321 0.2257080078125 +6322 0.035614013671875 +6323 0.194366455078125 +6324 0.011016845703125 +6325 0.115509033203125 +6326 -0.01800537109375 +6327 0.0128173828125 +6328 -0.037322998046875 +6329 -0.053802490234375 +6330 -0.0528564453125 +6331 -0.110626220703125 +6332 -0.074249267578125 +6333 -0.199493408203125 +6334 -0.095458984375 +6335 -0.29437255859375 +6336 -0.101959228515625 +6337 -0.33221435546875 +6338 -0.086181640625 +6339 -0.27972412109375 +6340 -0.059600830078125 +6341 -0.185333251953125 +6342 -0.0408935546875 +6343 -0.128204345703125 +6344 -0.032073974609375 +6345 -0.115692138671875 +6346 -0.02618408203125 +6347 -0.116455078125 +6348 -0.01788330078125 +6349 -0.105926513671875 +6350 -0.00048828125 +6351 -0.053955078125 +6352 0.02789306640625 +6353 0.048797607421875 +6354 0.05657958984375 +6355 0.157318115234375 +6356 0.071563720703125 +6357 0.212005615234375 +6358 0.074066162109375 +6359 0.218475341796875 +6360 0.078125 +6361 0.23724365234375 +6362 0.092376708984375 +6363 0.30535888671875 +6364 0.1072998046875 +6365 0.38128662109375 +6366 0.1090087890625 +6367 0.404449462890625 +6368 0.102294921875 +6369 0.3944091796875 +6370 0.0960693359375 +6371 0.3885498046875 +6372 0.08502197265625 +6373 0.362640380859375 +6374 0.0594482421875 +6375 0.27362060546875 +6376 0.018585205078125 +6377 0.11712646484375 +6378 -0.0252685546875 +6379 -0.054901123046875 +6380 -0.0599365234375 +6381 -0.19085693359375 +6382 -0.084075927734375 +6383 -0.28570556640625 +6384 -0.097564697265625 +6385 -0.339263916015625 +6386 -0.106414794921875 +6387 -0.3775634765625 +6388 -0.121124267578125 +6389 -0.445709228515625 +6390 -0.139801025390625 +6391 -0.535064697265625 +6392 -0.15875244140625 +6393 -0.629058837890625 +6394 -0.171142578125 +6395 -0.697601318359375 +6396 -0.168670654296875 +6397 -0.70391845703125 +6398 -0.150238037109375 +6399 -0.6424560546875 +6400 -0.111480712890625 +6401 -0.491241455078125 +6402 -0.056365966796875 +6403 -0.265716552734375 +6404 0.002227783203125 +6405 -0.023712158203125 +6406 0.056976318359375 +6407 0.201751708984375 +6408 0.10028076171875 +6409 0.375823974609375 +6410 0.12896728515625 +6411 0.485076904296875 +6412 0.1505126953125 +6413 0.56884765625 +6414 0.166229248046875 +6415 0.634765625 +6416 0.1669921875 +6417 0.63763427734375 +6418 0.150604248046875 +6419 0.5660400390625 +6420 0.127655029296875 +6421 0.4720458984375 +6422 0.10870361328125 +6423 0.40692138671875 +6424 0.095550537109375 +6425 0.3778076171875 +6426 0.087127685546875 +6427 0.376953125 +6428 0.077423095703125 +6429 0.371978759765625 +6430 0.056976318359375 +6431 0.313140869140625 +6432 0.023101806640625 +6433 0.184417724609375 +6434 -0.0186767578125 +6435 0.011199951171875 +6436 -0.060882568359375 +6437 -0.171051025390625 +6438 -0.098236083984375 +6439 -0.33740234375 +6440 -0.127410888671875 +6441 -0.47198486328125 +6442 -0.14544677734375 +6443 -0.560394287109375 +6444 -0.147979736328125 +6445 -0.58056640625 +6446 -0.13812255859375 +6447 -0.54754638671875 +6448 -0.1256103515625 +6449 -0.508575439453125 +6450 -0.109893798828125 +6451 -0.459503173828125 +6452 -0.090118408203125 +6453 -0.394378662109375 +6454 -0.074554443359375 +6455 -0.35260009765625 +6456 -0.059112548828125 +6457 -0.31170654296875 +6458 -0.02935791015625 +6459 -0.197418212890625 +6460 0.014678955078125 +6461 -0.007965087890625 +6462 0.06280517578125 +6463 0.207489013671875 +6464 0.10687255859375 +6465 0.409210205078125 +6466 0.141693115234375 +6467 0.57208251953125 +6468 0.161163330078125 +6469 0.66595458984375 +6470 0.158843994140625 +6471 0.65875244140625 +6472 0.138275146484375 +6473 0.56744384765625 +6474 0.107452392578125 +6475 0.431396484375 +6476 0.075408935546875 +6477 0.29443359375 +6478 0.047607421875 +6479 0.182464599609375 +6480 0.01800537109375 +6481 0.06365966796875 +6482 -0.015838623046875 +6483 -0.075958251953125 +6484 -0.044219970703125 +6485 -0.189422607421875 +6486 -0.06585693359375 +6487 -0.271942138671875 +6488 -0.08428955078125 +6489 -0.342529296875 +6490 -0.091949462890625 +6491 -0.364166259765625 +6492 -0.086761474609375 +6493 -0.327239990234375 +6494 -0.077667236328125 +6495 -0.2769775390625 +6496 -0.072723388671875 +6497 -0.253692626953125 +6498 -0.0692138671875 +6499 -0.24365234375 +6500 -0.05755615234375 +6501 -0.1983642578125 +6502 -0.03759765625 +6503 -0.116241455078125 +6504 -0.0174560546875 +6505 -0.036834716796875 +6506 0.0015869140625 +6507 0.034881591796875 +6508 0.0177001953125 +6509 0.09124755859375 +6510 0.025970458984375 +6511 0.10888671875 +6512 0.03369140625 +6513 0.125518798828125 +6514 0.043914794921875 +6515 0.15771484375 +6516 0.051025390625 +6517 0.17828369140625 +6518 0.0516357421875 +6519 0.17108154296875 +6520 0.044464111328125 +6521 0.129974365234375 +6522 0.034942626953125 +6523 0.082427978515625 +6524 0.022979736328125 +6525 0.027679443359375 +6526 0.00238037109375 +6527 -0.065643310546875 +6528 -0.01904296875 +6529 -0.15936279296875 +6530 -0.033050537109375 +6531 -0.21307373046875 +6532 -0.041046142578125 +6533 -0.234649658203125 +6534 -0.03802490234375 +6535 -0.2001953125 +6536 -0.025665283203125 +6537 -0.119171142578125 +6538 -0.010406494140625 +6539 -0.024749755859375 +6540 0.008453369140625 +6541 0.085784912109375 +6542 0.024200439453125 +6543 0.178131103515625 +6544 0.0296630859375 +6545 0.215576171875 +6546 0.027587890625 +6547 0.211456298828125 +6548 0.01995849609375 +6549 0.17523193359375 +6550 0.011138916015625 +6551 0.128753662109375 +6552 0.007049560546875 +6553 0.1019287109375 +6554 0.003509521484375 +6555 0.0743408203125 +6556 -0.000152587890625 +6557 0.04327392578125 +6558 0.001800537109375 +6559 0.038177490234375 +6560 0.012603759765625 +6561 0.076263427734375 +6562 0.028778076171875 +6563 0.14105224609375 +6564 0.040924072265625 +6565 0.186431884765625 +6566 0.044158935546875 +6567 0.188812255859375 +6568 0.036529541015625 +6569 0.1390380859375 +6570 0.018890380859375 +6571 0.041778564453125 +6572 -0.004150390625 +6573 -0.079437255859375 +6574 -0.031585693359375 +6575 -0.219390869140625 +6576 -0.06134033203125 +6577 -0.367828369140625 +6578 -0.08746337890625 +6579 -0.494873046875 +6580 -0.101043701171875 +6581 -0.556243896484375 +6582 -0.09332275390625 +6583 -0.508697509765625 +6584 -0.068878173828125 +6585 -0.3756103515625 +6586 -0.039947509765625 +6587 -0.218902587890625 +6588 -0.011444091796875 +6589 -0.063751220703125 +6590 0.01702880859375 +6591 0.091552734375 +6592 0.04345703125 +6593 0.23602294921875 +6594 0.062652587890625 +6595 0.342987060546875 +6596 0.0712890625 +6597 0.39520263671875 +6598 0.06878662109375 +6599 0.389373779296875 +6600 0.054962158203125 +6601 0.324249267578125 +6602 0.034698486328125 +6603 0.224090576171875 +6604 0.01507568359375 +6605 0.124267578125 +6606 -0.001495361328125 +6607 0.037078857421875 +6608 -0.009552001953125 +6609 -0.010101318359375 +6610 -0.0096435546875 +6611 -0.019439697265625 +6612 -0.008270263671875 +6613 -0.022796630859375 +6614 -0.0018310546875 +6615 -0.001556396484375 +6616 0.011932373046875 +6617 0.056304931640625 +6618 0.024078369140625 +6619 0.106719970703125 +6620 0.02398681640625 +6621 0.096893310546875 +6622 0.01470947265625 +6623 0.042694091796875 +6624 0.003753662109375 +6625 -0.018035888671875 +6626 -0.00701904296875 +6627 -0.07586669921875 +6628 -0.015380859375 +6629 -0.11944580078125 +6630 -0.023529052734375 +6631 -0.15972900390625 +6632 -0.032623291015625 +6633 -0.202606201171875 +6634 -0.042694091796875 +6635 -0.24859619140625 +6636 -0.05517578125 +6637 -0.30517578125 +6638 -0.0679931640625 +6639 -0.36212158203125 +6640 -0.075469970703125 +6641 -0.39141845703125 +6642 -0.0699462890625 +6643 -0.35528564453125 +6644 -0.050567626953125 +6645 -0.249969482421875 +6646 -0.020751953125 +6647 -0.092864990234375 +6648 0.01416015625 +6649 0.08905029296875 +6650 0.04217529296875 +6651 0.2352294921875 +6652 0.0579833984375 +6653 0.318817138671875 +6654 0.06536865234375 +6655 0.358642578125 +6656 0.063568115234375 +6657 0.347747802734375 +6658 0.053131103515625 +6659 0.28564453125 +6660 0.042999267578125 +6661 0.223175048828125 +6662 0.039031982421875 +6663 0.196746826171875 +6664 0.03656005859375 +6665 0.179840087890625 +6666 0.0325927734375 +6667 0.155548095703125 +6668 0.0316162109375 +6669 0.151214599609375 +6670 0.031951904296875 +6671 0.156951904296875 +6672 0.026702880859375 +6673 0.13177490234375 +6674 0.0201416015625 +6675 0.100799560546875 +6676 0.0162353515625 +6677 0.087127685546875 +6678 0.009063720703125 +6679 0.05487060546875 +6680 -0.00341796875 +6681 -0.009002685546875 +6682 -0.021026611328125 +6683 -0.10400390625 +6684 -0.043548583984375 +6685 -0.229400634765625 +6686 -0.065887451171875 +6687 -0.35552978515625 +6688 -0.081207275390625 +6689 -0.441925048828125 +6690 -0.08697509765625 +6691 -0.473846435546875 +6692 -0.085418701171875 +6693 -0.464813232421875 +6694 -0.0772705078125 +6695 -0.419097900390625 +6696 -0.062164306640625 +6697 -0.334320068359375 +6698 -0.0430908203125 +6699 -0.227935791015625 +6700 -0.024078369140625 +6701 -0.12347412109375 +6702 -0.00634765625 +6703 -0.02764892578125 +6704 0.013031005859375 +6705 0.077667236328125 +6706 0.037445068359375 +6707 0.2132568359375 +6708 0.06842041015625 +6709 0.38885498046875 +6710 0.102294921875 +6711 0.582794189453125 +6712 0.12872314453125 +6713 0.734039306640625 +6714 0.1405029296875 +6715 0.800140380859375 +6716 0.13714599609375 +6717 0.7783203125 +6718 0.118072509765625 +6719 0.6651611328125 +6720 0.083160400390625 +6721 0.45965576171875 +6722 0.038726806640625 +6723 0.199188232421875 +6724 -0.004150390625 +6725 -0.050689697265625 +6726 -0.035858154296875 +6727 -0.23297119140625 +6728 -0.05340576171875 +6729 -0.33013916015625 +6730 -0.06109619140625 +6731 -0.368408203125 +6732 -0.064117431640625 +6733 -0.378936767578125 +6734 -0.064971923828125 +6735 -0.376983642578125 +6736 -0.06646728515625 +6737 -0.37969970703125 +6738 -0.069305419921875 +6739 -0.391510009765625 +6740 -0.068878173828125 +6741 -0.385345458984375 +6742 -0.061920166015625 +6743 -0.3419189453125 +6744 -0.05206298828125 +6745 -0.28289794921875 +6746 -0.046600341796875 +6747 -0.251617431640625 +6748 -0.048583984375 +6749 -0.266143798828125 +6750 -0.049102783203125 +6751 -0.273345947265625 +6752 -0.03875732421875 +6753 -0.216796875 +6754 -0.02288818359375 +6755 -0.128265380859375 +6756 -0.011688232421875 +6757 -0.068145751953125 +6758 -0.006378173828125 +6759 -0.0430908203125 +6760 -0.002166748046875 +6761 -0.024444580078125 +6762 0.006378173828125 +6763 0.020721435546875 +6764 0.024566650390625 +6765 0.124481201171875 +6766 0.047515869140625 +6767 0.25787353515625 +6768 0.06817626953125 +6769 0.379119873046875 +6770 0.08514404296875 +6771 0.47991943359375 +6772 0.093048095703125 +6773 0.5281982421875 +6774 0.0897216796875 +6775 0.511138916015625 +6776 0.079833984375 +6777 0.456207275390625 +6778 0.070831298828125 +6779 0.407470703125 +6780 0.065948486328125 +6781 0.383758544921875 +6782 0.060455322265625 +6783 0.35687255859375 +6784 0.0518798828125 +6785 0.31182861328125 +6786 0.0406494140625 +6787 0.250885009765625 +6788 0.025421142578125 +6789 0.1654052734375 +6790 0.002838134765625 +6791 0.035247802734375 +6792 -0.027435302734375 +6793 -0.142059326171875 +6794 -0.060211181640625 +6795 -0.33563232421875 +6796 -0.0936279296875 +6797 -0.5345458984375 +6798 -0.124847412109375 +6799 -0.72186279296875 +6800 -0.143646240234375 +6801 -0.836669921875 +6802 -0.142303466796875 +6803 -0.8326416015625 +6804 -0.124176025390625 +6805 -0.7296142578125 +6806 -0.09857177734375 +6807 -0.582550048828125 +6808 -0.07373046875 +6809 -0.440093994140625 +6810 -0.053375244140625 +6811 -0.324310302734375 +6812 -0.031890869140625 +6813 -0.20147705078125 +6814 -0.004791259765625 +6815 -0.044647216796875 +6816 0.020751953125 +6817 0.103973388671875 +6818 0.03765869140625 +6819 0.202392578125 +6820 0.048248291015625 +6821 0.264495849609375 +6822 0.0606689453125 +6823 0.338897705078125 +6824 0.0780029296875 +6825 0.443817138671875 +6826 0.09454345703125 +6827 0.545074462890625 +6828 0.106048583984375 +6829 0.6173095703125 +6830 0.111236572265625 +6831 0.6524658203125 +6832 0.1123046875 +6833 0.66339111328125 +6834 0.11029052734375 +6835 0.6561279296875 +6836 0.1011962890625 +6837 0.606781005859375 +6838 0.08270263671875 +6839 0.501190185546875 +6840 0.05712890625 +6841 0.352783203125 +6842 0.027008056640625 +6843 0.176544189453125 +6844 -0.008819580078125 +6845 -0.034820556640625 +6846 -0.046417236328125 +6847 -0.258209228515625 +6848 -0.077239990234375 +6849 -0.44244384765625 +6850 -0.0992431640625 +6851 -0.5753173828125 +6852 -0.11163330078125 +6853 -0.65203857421875 +6854 -0.109283447265625 +6855 -0.641632080078125 +6856 -0.095245361328125 +6857 -0.562164306640625 +6858 -0.077056884765625 +6859 -0.458038330078125 +6860 -0.058319091796875 +6861 -0.350555419921875 +6862 -0.04254150390625 +6863 -0.260528564453125 +6864 -0.03045654296875 +6865 -0.192108154296875 +6866 -0.02154541015625 +6867 -0.141937255859375 +6868 -0.01446533203125 +6869 -0.1021728515625 +6870 -0.007598876953125 +6871 -0.062896728515625 +6872 0.001068115234375 +6873 -0.011932373046875 +6874 0.013580322265625 +6875 0.062835693359375 +6876 0.027801513671875 +6877 0.148712158203125 +6878 0.043060302734375 +6879 0.241729736328125 +6880 0.06060791015625 +6881 0.34912109375 +6882 0.078216552734375 +6883 0.457305908203125 +6884 0.092132568359375 +6885 0.54388427734375 +6886 0.096343994140625 +6887 0.5728759765625 +6888 0.084564208984375 +6889 0.506591796875 +6890 0.057861328125 +6891 0.351226806640625 +6892 0.02294921875 +6893 0.146514892578125 +6894 -0.011322021484375 +6895 -0.05523681640625 +6896 -0.038604736328125 +6897 -0.21624755859375 +6898 -0.058624267578125 +6899 -0.334930419921875 +6900 -0.0699462890625 +6901 -0.402984619140625 +6902 -0.07611083984375 +6903 -0.4412841796875 +6904 -0.084869384765625 +6905 -0.49578857421875 +6906 -0.095184326171875 +6907 -0.5601806640625 +6908 -0.1014404296875 +6909 -0.600738525390625 +6910 -0.09808349609375 +6911 -0.584228515625 +6912 -0.0802001953125 +6913 -0.47930908203125 +6914 -0.04736328125 +6915 -0.27935791015625 +6916 -0.00390625 +6917 -0.0089111328125 +6918 0.04083251953125 +6919 0.268798828125 +6920 0.0765380859375 +6921 0.482818603515625 +6922 0.098724365234375 +6923 0.60369873046875 +6924 0.109588623046875 +6925 0.650421142578125 +6926 0.11444091796875 +6927 0.66400146484375 +6928 0.112762451171875 +6929 0.6414794921875 +6930 0.103118896484375 +6931 0.572540283203125 +6932 0.091156005859375 +6933 0.498138427734375 +6934 0.0799560546875 +6935 0.439453125 +6936 0.066925048828125 +6937 0.375518798828125 +6938 0.048004150390625 +6939 0.274505615234375 +6940 0.019775390625 +6941 0.1087646484375 +6942 -0.01434326171875 +6943 -0.099395751953125 +6944 -0.0496826171875 +6945 -0.3182373046875 +6946 -0.086090087890625 +6947 -0.5489501953125 +6948 -0.120880126953125 +6949 -0.7738037109375 +6950 -0.14666748046875 +6951 -0.86383056640625 +6952 -0.15875244140625 +6953 -0.870391845703125 +6954 -0.15948486328125 +6955 -0.86895751953125 +6956 -0.150665283203125 +6957 -0.861053466796875 +6958 -0.1300048828125 +6959 -0.765869140625 +6960 -0.096099853515625 +6961 -0.5301513671875 +6962 -0.050079345703125 +6963 -0.214691162109375 +6964 0.001983642578125 +6965 0.137359619140625 +6966 0.0528564453125 +6967 0.474822998046875 +6968 0.097442626953125 +6969 0.76239013671875 +6970 0.131805419921875 +6971 0.867462158203125 +6972 0.155731201171875 +6973 0.870361328125 +6974 0.16741943359375 +6975 0.86480712890625 +6976 0.167449951171875 +6977 0.831817626953125 +6978 0.159027099609375 +6979 0.677581787109375 +6980 0.142852783203125 +6981 0.495880126953125 +6982 0.121429443359375 +6983 0.30767822265625 +6984 0.0950927734375 +6985 0.116180419921875 +6986 0.05963134765625 +6987 -0.110748291015625 +6988 0.01422119140625 +6989 -0.381805419921875 +6990 -0.03509521484375 +6991 -0.6572265625 +6992 -0.0799560546875 +6993 -0.857421875 +6994 -0.114349365234375 +6995 -0.870391845703125 +6996 -0.137115478515625 +6997 -0.870391845703125 +6998 -0.1517333984375 +6999 -0.86444091796875 +7000 -0.162872314453125 +7001 -0.85723876953125 +7002 -0.167877197265625 +7003 -0.790008544921875 +7004 -0.15924072265625 +7005 -0.62847900390625 +7006 -0.136474609375 +7007 -0.3956298828125 +7008 -0.10400390625 +7009 -0.126708984375 +7010 -0.06561279296875 +7011 0.150115966796875 +7012 -0.02294921875 +7013 0.424041748046875 +7014 0.020233154296875 +7015 0.670623779296875 +7016 0.058563232421875 +7017 0.854522705078125 +7018 0.089447021484375 +7019 0.866485595703125 +7020 0.11065673828125 +7021 0.86920166015625 +7022 0.124481201171875 +7023 0.8653564453125 +7024 0.132598876953125 +7025 0.857147216796875 +7026 0.13446044921875 +7027 0.766845703125 +7028 0.130645751953125 +7029 0.628509521484375 +7030 0.1201171875 +7031 0.462127685546875 +7032 0.1063232421875 +7033 0.297210693359375 +7034 0.09088134765625 +7035 0.14862060546875 +7036 0.0706787109375 +7037 -0.00537109375 +7038 0.04681396484375 +7039 -0.15753173828125 +7040 0.01885986328125 +7041 -0.31304931640625 +7042 -0.01495361328125 +7043 -0.48876953125 +7044 -0.048126220703125 +7045 -0.6416015625 +7046 -0.077178955078125 +7047 -0.751373291015625 +7048 -0.105133056640625 +7049 -0.84619140625 +7050 -0.129852294921875 +7051 -0.861297607421875 +7052 -0.146697998046875 +7053 -0.863250732421875 +7054 -0.151275634765625 +7055 -0.856597900390625 +7056 -0.1451416015625 +7057 -0.7498779296875 +7058 -0.1361083984375 +7059 -0.624542236328125 +7060 -0.12115478515625 +7061 -0.47808837890625 +7062 -0.092315673828125 +7063 -0.253387451171875 +7064 -0.055816650390625 +7065 0.003692626953125 +7066 -0.021026611328125 +7067 0.2257080078125 +7068 0.013641357421875 +7069 0.427154541015625 +7070 0.052490234375 +7071 0.643218994140625 +7072 0.094085693359375 +7073 0.855926513671875 +7074 0.130462646484375 +7075 0.870361328125 +7076 0.154754638671875 +7077 0.870361328125 +7078 0.167877197265625 +7079 0.862762451171875 +7080 0.16937255859375 +7081 0.79669189453125 +7082 0.157867431640625 +7083 0.595794677734375 +7084 0.137298583984375 +7085 0.362152099609375 +7086 0.111419677734375 +7087 0.1270751953125 +7088 0.083099365234375 +7089 -0.086944580078125 +7090 0.052642822265625 +7091 -0.2784423828125 +7092 0.015350341796875 +7093 -0.484832763671875 +7094 -0.031280517578125 +7095 -0.729583740234375 +7096 -0.080291748046875 +7097 -0.86688232421875 +7098 -0.123016357421875 +7099 -0.870391845703125 +7100 -0.158660888671875 +7101 -0.86859130859375 +7102 -0.186859130859375 +7103 -0.86279296875 +7104 -0.20263671875 +7105 -0.817962646484375 +7106 -0.199737548828125 +7107 -0.6116943359375 +7108 -0.177154541015625 +7109 -0.3128662109375 +7110 -0.139434814453125 +7111 0.039398193359375 +7112 -0.089263916015625 +7113 0.422821044921875 +7114 -0.031158447265625 +7115 0.805145263671875 +7116 0.025543212890625 +7117 0.870361328125 +7118 0.07305908203125 +7119 0.870361328125 +7120 0.1097412109375 +7121 0.860015869140625 +7122 0.134490966796875 +7123 0.727935791015625 +7124 0.146453857421875 +7125 0.48114013671875 +7126 0.148834228515625 +7127 0.2059326171875 +7128 0.14459228515625 +7129 -0.06103515625 +7130 0.135009765625 +7131 -0.29913330078125 +7132 0.1180419921875 +7133 -0.516204833984375 +7134 0.091583251953125 +7135 -0.7252197265625 +7136 0.0589599609375 +7137 -0.85980224609375 +7138 0.02484130859375 +7139 -0.870391845703125 +7140 -0.0067138671875 +7141 -0.870391845703125 +7142 -0.029052734375 +7143 -0.858062744140625 +7144 -0.04150390625 +7145 -0.673004150390625 +7146 -0.051116943359375 +7147 -0.42694091796875 +7148 -0.0638427734375 +7149 -0.2100830078125 +7150 -0.07928466796875 +7151 -0.0362548828125 +7152 -0.093353271484375 +7153 0.10943603515625 +7154 -0.10321044921875 +7155 0.23516845703125 +7156 -0.1031494140625 +7157 0.373687744140625 +7158 -0.093353271484375 +7159 0.517791748046875 +7160 -0.08233642578125 +7161 0.602783203125 +7162 -0.06939697265625 +7163 0.635711669921875 +7164 -0.050018310546875 +7165 0.655181884765625 +7166 -0.02557373046875 +7167 0.65948486328125 +7168 0.002471923828125 +7169 0.651275634765625 +7170 0.030731201171875 +7171 0.61846923828125 +7172 0.05462646484375 +7173 0.53753662109375 +7174 0.071990966796875 +7175 0.404144287109375 +7176 0.08154296875 +7177 0.22186279296875 +7178 0.083282470703125 +7179 0.003997802734375 +7180 0.0789794921875 +7181 -0.22100830078125 +7182 0.070770263671875 +7183 -0.42449951171875 +7184 0.0609130859375 +7185 -0.579833984375 +7186 0.053955078125 +7187 -0.641876220703125 +7188 0.049346923828125 +7189 -0.6177978515625 +7190 0.0406494140625 +7191 -0.575531005859375 +7192 0.027587890625 +7193 -0.526336669921875 +7194 0.015838623046875 +7195 -0.42645263671875 +7196 0.008544921875 +7197 -0.2581787109375 +7198 0.002197265625 +7199 -0.068695068359375 +7200 -0.0068359375 +7201 0.09222412109375 +7202 -0.016387939453125 +7203 0.232147216796875 +7204 -0.025177001953125 +7205 0.3509521484375 +7206 -0.036163330078125 +7207 0.410064697265625 +7208 -0.05230712890625 +7209 0.372955322265625 +7210 -0.071441650390625 +7211 0.2554931640625 +7212 -0.08819580078125 +7213 0.10711669921875 +7214 -0.10064697265625 +7215 -0.052886962890625 +7216 -0.105194091796875 +7217 -0.186279296875 +7218 -0.096282958984375 +7219 -0.23291015625 +7220 -0.076507568359375 +7221 -0.209442138671875 +7222 -0.053009033203125 +7223 -0.174163818359375 +7224 -0.026885986328125 +7225 -0.126739501953125 +7226 0.002593994140625 +7227 -0.048126220703125 +7228 0.03228759765625 +7229 0.0426025390625 +7230 0.057159423828125 +7231 0.10748291015625 +7232 0.07574462890625 +7233 0.1409912109375 +7234 0.0928955078125 +7235 0.19708251953125 +7236 0.107879638671875 +7237 0.273651123046875 +7238 0.114959716796875 +7239 0.31768798828125 +7240 0.1153564453125 +7241 0.341094970703125 +7242 0.11181640625 +7243 0.368011474609375 +7244 0.10211181640625 +7245 0.37249755859375 +7246 0.081298828125 +7247 0.30072021484375 +7248 0.050140380859375 +7249 0.1517333984375 +7250 0.0157470703125 +7251 -0.01470947265625 +7252 -0.019805908203125 +7253 -0.1883544921875 +7254 -0.055938720703125 +7255 -0.372711181640625 +7256 -0.08612060546875 +7257 -0.51397705078125 +7258 -0.105377197265625 +7259 -0.57177734375 +7260 -0.112335205078125 +7261 -0.53948974609375 +7262 -0.1083984375 +7263 -0.43511962890625 +7264 -0.097198486328125 +7265 -0.2962646484375 +7266 -0.0826416015625 +7267 -0.161102294921875 +7268 -0.066314697265625 +7269 -0.0435791015625 +7270 -0.048126220703125 +7271 0.060394287109375 +7272 -0.030029296875 +7273 0.13665771484375 +7274 -0.01422119140625 +7275 0.170135498046875 +7276 -0.0009765625 +7277 0.16552734375 +7278 0.01251220703125 +7279 0.15728759765625 +7280 0.025970458984375 +7281 0.150787353515625 +7282 0.0361328125 +7283 0.12200927734375 +7284 0.043304443359375 +7285 0.080108642578125 +7286 0.049591064453125 +7287 0.05126953125 +7288 0.057403564453125 +7289 0.062896728515625 +7290 0.06414794921875 +7291 0.09271240234375 +7292 0.064727783203125 +7293 0.092987060546875 +7294 0.060760498046875 +7295 0.07855224609375 +7296 0.05401611328125 +7297 0.06427001953125 +7298 0.043243408203125 +7299 0.0347900390625 +7300 0.02874755859375 +7301 -0.01171875 +7302 0.01312255859375 +7303 -0.056060791015625 +7304 0.001434326171875 +7305 -0.055511474609375 +7306 -0.00567626953125 +7307 -0.010467529296875 +7308 -0.013153076171875 +7309 0.02508544921875 +7310 -0.023040771484375 +7311 0.025665283203125 +7312 -0.032135009765625 +7313 0.017333984375 +7314 -0.039825439453125 +7315 0.00189208984375 +7316 -0.047027587890625 +7317 -0.03173828125 +7318 -0.052337646484375 +7319 -0.071502685546875 +7320 -0.05767822265625 +7321 -0.13543701171875 +7322 -0.06280517578125 +7323 -0.219970703125 +7324 -0.065399169921875 +7325 -0.300506591796875 +7326 -0.06573486328125 +7327 -0.376312255859375 +7328 -0.061065673828125 +7329 -0.416107177734375 +7330 -0.04681396484375 +7331 -0.371124267578125 +7332 -0.023651123046875 +7333 -0.242279052734375 +7334 0.003692626953125 +7335 -0.069732666015625 +7336 0.03253173828125 +7337 0.125640869140625 +7338 0.059173583984375 +7339 0.31268310546875 +7340 0.0794677734375 +7341 0.45501708984375 +7342 0.0933837890625 +7343 0.554779052734375 +7344 0.100677490234375 +7345 0.61065673828125 +7346 0.10009765625 +7347 0.610931396484375 +7348 0.0892333984375 +7349 0.531463623046875 +7350 0.0699462890625 +7351 0.3883056640625 +7352 0.048095703125 +7353 0.23468017578125 +7354 0.026641845703125 +7355 0.095245361328125 +7356 0.008697509765625 +7357 -0.00396728515625 +7358 -0.00384521484375 +7359 -0.04852294921875 +7360 -0.01226806640625 +7361 -0.055145263671875 +7362 -0.02154541015625 +7363 -0.0758056640625 +7364 -0.03424072265625 +7365 -0.138702392578125 +7366 -0.046417236328125 +7367 -0.209197998046875 +7368 -0.05804443359375 +7369 -0.289031982421875 +7370 -0.069061279296875 +7371 -0.37884521484375 +7372 -0.07708740234375 +7373 -0.456329345703125 +7374 -0.0816650390625 +7375 -0.51641845703125 +7376 -0.07879638671875 +7377 -0.519287109375 +7378 -0.0679931640625 +7379 -0.458251953125 +7380 -0.054901123046875 +7381 -0.384796142578125 +7382 -0.04241943359375 +7383 -0.323699951171875 +7384 -0.0302734375 +7385 -0.269287109375 +7386 -0.01611328125 +7387 -0.1951904296875 +7388 -0.000152587890625 +7389 -0.100006103515625 +7390 0.014495849609375 +7391 -0.01055908203125 +7392 0.03070068359375 +7393 0.1033935546875 +7394 0.048980712890625 +7395 0.24908447265625 +7396 0.06365966796875 +7397 0.373199462890625 +7398 0.072845458984375 +7399 0.45806884765625 +7400 0.077392578125 +7401 0.511474609375 +7402 0.080718994140625 +7403 0.565399169921875 +7404 0.082061767578125 +7405 0.61138916015625 +7406 0.075439453125 +7407 0.5897216796875 +7408 0.06011962890625 +7409 0.4906005859375 +7410 0.0382080078125 +7411 0.33148193359375 +7412 0.013702392578125 +7413 0.147796630859375 +7414 -0.00872802734375 +7415 -0.01873779296875 +7416 -0.02593994140625 +7417 -0.140289306640625 +7418 -0.03509521484375 +7419 -0.191986083984375 +7420 -0.037109375 +7421 -0.184295654296875 +7422 -0.0364990234375 +7423 -0.161834716796875 +7424 -0.03753662109375 +7425 -0.166595458984375 +7426 -0.039764404296875 +7427 -0.19390869140625 +7428 -0.041229248046875 +7429 -0.22442626953125 +7430 -0.044189453125 +7431 -0.279754638671875 +7432 -0.046722412109375 +7433 -0.3389892578125 +7434 -0.04425048828125 +7435 -0.3543701171875 +7436 -0.039215087890625 +7437 -0.348175048828125 +7438 -0.032440185546875 +7439 -0.32598876953125 +7440 -0.021209716796875 +7441 -0.2581787109375 +7442 -0.005279541015625 +7443 -0.139801025390625 +7444 0.013641357421875 +7445 0.014617919921875 +7446 0.029327392578125 +7447 0.144378662109375 +7448 0.038818359375 +7449 0.221038818359375 +7450 0.044647216796875 +7451 0.27069091796875 +7452 0.046875 +7453 0.294036865234375 +7454 0.047607421875 +7455 0.311767578125 +7456 0.048370361328125 +7457 0.339141845703125 +7458 0.047332763671875 +7459 0.360260009765625 +7460 0.0433349609375 +7461 0.360504150390625 +7462 0.03448486328125 +7463 0.308380126953125 +7464 0.01959228515625 +7465 0.18170166015625 +7466 0.00079345703125 +7467 0.0047607421875 +7468 -0.018096923828125 +7469 -0.17559814453125 +7470 -0.033477783203125 +7471 -0.3143310546875 +7472 -0.041900634765625 +7473 -0.36785888671875 +7474 -0.0450439453125 +7475 -0.36248779296875 +7476 -0.0460205078125 +7477 -0.343536376953125 +7478 -0.0440673828125 +7479 -0.3018798828125 +7480 -0.038726806640625 +7481 -0.231414794921875 +7482 -0.029022216796875 +7483 -0.117645263671875 +7484 -0.017425537109375 +7485 0.007049560546875 +7486 -0.008026123046875 +7487 0.087982177734375 +7488 -3.0517578125e-05 +7489 0.13946533203125 +7490 0.0072021484375 +7491 0.17425537109375 +7492 0.013092041015625 +7493 0.188201904296875 +7494 0.016632080078125 +7495 0.171234130859375 +7496 0.017242431640625 +7497 0.118438720703125 +7498 0.01666259765625 +7499 0.05706787109375 +7500 0.01483154296875 +7501 -0.010711669921875 +7502 0.011138916015625 +7503 -0.0914306640625 +7504 0.007110595703125 +7505 -0.162322998046875 +7506 0.004791259765625 +7507 -0.194549560546875 +7508 0.00701904296875 +7509 -0.1492919921875 +7510 0.01422119140625 +7511 -0.02166748046875 +7512 0.02191162109375 +7513 0.124053955078125 +7514 0.02471923828125 +7515 0.211151123046875 +7516 0.022918701171875 +7517 0.240447998046875 +7518 0.018951416015625 +7519 0.242218017578125 +7520 0.013702392578125 +7521 0.2257080078125 +7522 0.007659912109375 +7523 0.194366455078125 +7524 -0.001312255859375 +7525 0.115509033203125 +7526 -0.011322021484375 +7527 0.0128173828125 +7528 -0.0179443359375 +7529 -0.053802490234375 +7530 -0.02301025390625 +7531 -0.110626220703125 +7532 -0.02947998046875 +7533 -0.199493408203125 +7534 -0.035552978515625 +7535 -0.29437255859375 +7536 -0.036712646484375 +7537 -0.33221435546875 +7538 -0.03070068359375 +7539 -0.27972412109375 +7540 -0.021148681640625 +7541 -0.185333251953125 +7542 -0.013916015625 +7543 -0.128204345703125 +7544 -0.00970458984375 +7545 -0.115692138671875 +7546 -0.006439208984375 +7547 -0.116455078125 +7548 -0.002532958984375 +7549 -0.105926513671875 +7550 0.00396728515625 +7551 -0.053955078125 +7552 0.01361083984375 +7553 0.048797607421875 +7554 0.0230712890625 +7555 0.157318115234375 +7556 0.027984619140625 +7557 0.212005615234375 +7558 0.0286865234375 +7559 0.218475341796875 +7560 0.029541015625 +7561 0.23724365234375 +7562 0.03326416015625 +7563 0.30535888671875 +7564 0.03692626953125 +7565 0.38128662109375 +7566 0.03631591796875 +7567 0.404449462890625 +7568 0.032989501953125 +7569 0.3944091796875 +7570 0.02978515625 +7571 0.3885498046875 +7572 0.025146484375 +7573 0.362640380859375 +7574 0.016082763671875 +7575 0.27362060546875 +7576 0.00244140625 +7577 0.11712646484375 +7578 -0.01190185546875 +7579 -0.054901123046875 +7580 -0.023101806640625 +7581 -0.19085693359375 +7582 -0.03076171875 +7583 -0.28570556640625 +7584 -0.034820556640625 +7585 -0.339263916015625 +7586 -0.037200927734375 +7587 -0.3775634765625 +7588 -0.041168212890625 +7589 -0.445709228515625 +7590 -0.046173095703125 +7591 -0.535064697265625 +7592 -0.05108642578125 +7593 -0.629058837890625 +7594 -0.0538330078125 +7595 -0.697601318359375 +7596 -0.05194091796875 +7597 -0.70391845703125 +7598 -0.045135498046875 +7599 -0.6424560546875 +7600 -0.031982421875 +7601 -0.491241455078125 +7602 -0.013702392578125 +7603 -0.265716552734375 +7604 0.005401611328125 +7605 -0.023712158203125 +7606 0.022857666015625 +7607 0.201751708984375 +7608 0.0361328125 +7609 0.375823974609375 +7610 0.044219970703125 +7611 0.485076904296875 +7612 0.049957275390625 +7613 0.56884765625 +7614 0.053924560546875 +7615 0.634765625 +7616 0.05291748046875 +7617 0.63763427734375 +7618 0.04620361328125 +7619 0.5660400390625 +7620 0.03759765625 +7621 0.4720458984375 +7622 0.030914306640625 +7623 0.40692138671875 +7624 0.02679443359375 +7625 0.3778076171875 +7626 0.0247802734375 +7627 0.376953125 +7628 0.022674560546875 +7629 0.371978759765625 +7630 0.016937255859375 +7631 0.313140869140625 +7632 0.006500244140625 +7633 0.184417724609375 +7634 -0.0067138671875 +7635 0.011199951171875 +7636 -0.02008056640625 +7637 -0.171051025390625 +7638 -0.031829833984375 +7639 -0.33740234375 +7640 -0.040863037109375 +7641 -0.47198486328125 +7642 -0.04620361328125 +7643 -0.560394287109375 +7644 -0.04632568359375 +7645 -0.58056640625 +7646 -0.042388916015625 +7647 -0.54754638671875 +7648 -0.037872314453125 +7649 -0.508575439453125 +7650 -0.0325927734375 +7651 -0.459503173828125 +7652 -0.026214599609375 +7653 -0.394378662109375 +7654 -0.0216064453125 +7655 -0.35260009765625 +7656 -0.017242431640625 +7657 -0.31170654296875 +7658 -0.00787353515625 +7659 -0.197418212890625 +7660 0.00653076171875 +7661 -0.007965087890625 +7662 0.022369384765625 +7663 0.207489013671875 +7664 0.036773681640625 +7665 0.409210205078125 +7666 0.0479736328125 +7667 0.57208251953125 +7668 0.053863525390625 +7669 0.66595458984375 +7670 0.052154541015625 +7671 0.65875244140625 +7672 0.044189453125 +7673 0.56744384765625 +7674 0.032867431640625 +7675 0.431396484375 +7676 0.02142333984375 +7677 0.29443359375 +7678 0.011810302734375 +7679 0.182464599609375 +7680 0.0023193359375 +7681 0.06365966796875 +7682 -0.00787353515625 +7683 -0.075958251953125 +7684 -0.0167236328125 +7685 -0.189422607421875 +7686 -0.02374267578125 +7687 -0.271942138671875 +7688 -0.029449462890625 +7689 -0.342529296875 +7690 -0.032196044921875 +7691 -0.364166259765625 +7692 -0.031494140625 +7693 -0.327239990234375 +7694 -0.029144287109375 +7695 -0.2769775390625 +7696 -0.026824951171875 +7697 -0.253692626953125 +7698 -0.024078369140625 +7699 -0.24365234375 +7700 -0.019134521484375 +7701 -0.1983642578125 +7702 -0.01214599609375 +7703 -0.116241455078125 +7704 -0.004913330078125 +7705 -0.036834716796875 +7706 0.0020751953125 +7707 0.034881591796875 +7708 0.00830078125 +7709 0.09124755859375 +7710 0.01263427734375 +7711 0.10888671875 +7712 0.016387939453125 +7713 0.125518798828125 +7714 0.020050048828125 +7715 0.15771484375 +7716 0.022430419921875 +7717 0.17828369140625 +7718 0.022796630859375 +7719 0.17108154296875 +7720 0.02093505859375 +7721 0.129974365234375 +7722 0.0179443359375 +7723 0.082427978515625 +7724 0.013885498046875 +7725 0.027679443359375 +7726 0.007659912109375 +7727 -0.065643310546875 +7728 0.000946044921875 +7729 -0.15936279296875 +7730 -0.004425048828125 +7731 -0.21307373046875 +7732 -0.008636474609375 +7733 -0.234649658203125 +7734 -0.010528564453125 +7735 -0.2001953125 +7736 -0.01031494140625 +7737 -0.119171142578125 +7738 -0.0091552734375 +7739 -0.024749755859375 +7740 -0.00677490234375 +7741 0.085784912109375 +7742 -0.0045166015625 +7743 0.178131103515625 +7744 -0.003753662109375 +7745 0.215576171875 +7746 -0.003936767578125 +7747 0.211456298828125 +7748 -0.004669189453125 +7749 0.17523193359375 +7750 -0.005157470703125 +7751 0.128753662109375 +7752 -0.004302978515625 +7753 0.1019287109375 +7754 -0.003021240234375 +7755 0.0743408203125 +7756 -0.0015869140625 +7757 0.04327392578125 +7758 0.0009765625 +7759 0.038177490234375 +7760 0.00518798828125 +7761 0.076263427734375 +7762 0.01025390625 +7763 0.14105224609375 +7764 0.014190673828125 +7765 0.186431884765625 +7766 0.0159912109375 +7767 0.188812255859375 +7768 0.01519775390625 +7769 0.1390380859375 +7770 0.011932373046875 +7771 0.041778564453125 +7772 0.00714111328125 +7773 -0.079437255859375 +7774 0.00103759765625 +7775 -0.219390869140625 +7776 -0.005859375 +7777 -0.367828369140625 +7778 -0.012298583984375 +7779 -0.494873046875 +7780 -0.01641845703125 +7781 -0.556243896484375 +7782 -0.01641845703125 +7783 -0.508697509765625 +7784 -0.01312255859375 +7785 -0.3756103515625 +7786 -0.0089111328125 +7787 -0.218902587890625 +7788 -0.004730224609375 +7789 -0.063751220703125 +7790 -0.0003662109375 +7791 0.091552734375 +7792 0.00384521484375 +7793 0.23602294921875 +7794 0.00689697265625 +7795 0.342987060546875 +7796 0.008148193359375 +7797 0.39520263671875 +7798 0.007537841796875 +7799 0.389373779296875 +7800 0.005035400390625 +7801 0.324249267578125 +7802 0.0015869140625 +7803 0.224090576171875 +7804 -0.00140380859375 +7805 0.124267578125 +7806 -0.0035400390625 +7807 0.037078857421875 +7808 -0.003814697265625 +7809 -0.010101318359375 +7810 -0.00238037109375 +7811 -0.019439697265625 +7812 -0.000640869140625 +7813 -0.022796630859375 +7814 0.00201416015625 +7815 -0.001556396484375 +7816 0.005950927734375 +7817 0.056304931640625 +7818 0.00933837890625 +7819 0.106719970703125 +7820 0.009979248046875 +7821 0.096893310546875 +7822 0.00848388671875 +7823 0.042694091796875 +7824 0.006317138671875 +7825 -0.018035888671875 +7826 0.003875732421875 +7827 -0.07586669921875 +7828 0.00164794921875 +7829 -0.11944580078125 +7830 -0.000762939453125 +7831 -0.15972900390625 +7832 -0.0035400390625 +7833 -0.202606201171875 +7834 -0.006591796875 +7835 -0.24859619140625 +7836 -0.010162353515625 +7837 -0.30517578125 +7838 -0.0137939453125 +7839 -0.36212158203125 +7840 -0.016265869140625 +7841 -0.39141845703125 +7842 -0.016021728515625 +7843 -0.35528564453125 +7844 -0.01287841796875 +7845 -0.249969482421875 +7846 -0.0074462890625 +7847 -0.092864990234375 +7848 -0.000762939453125 +7849 0.08905029296875 +7850 0.004730224609375 +7851 0.2352294921875 +7852 0.00799560546875 +7853 0.318817138671875 +7854 0.009796142578125 +7855 0.358642578125 +7856 0.009796142578125 +7857 0.347747802734375 +7858 0.007965087890625 +7859 0.28564453125 +7860 0.00628662109375 +7861 0.223175048828125 +7862 0.00616455078125 +7863 0.196746826171875 +7864 0.0064697265625 +7865 0.179840087890625 +7866 0.006500244140625 +7867 0.155548095703125 +7868 0.00726318359375 +7869 0.151214599609375 +7870 0.00836181640625 +7871 0.156951904296875 +7872 0.008087158203125 +7873 0.13177490234375 +7874 0.007415771484375 +7875 0.100799560546875 +7876 0.007232666015625 +7877 0.087127685546875 +7878 0.006103515625 +7879 0.05487060546875 +7880 0.00347900390625 +7881 -0.009002685546875 +7882 -0.00054931640625 +7883 -0.10400390625 +7884 -0.005950927734375 +7885 -0.229400634765625 +7886 -0.01153564453125 +7887 -0.35552978515625 +7888 -0.015655517578125 +7889 -0.441925048828125 +7890 -0.01763916015625 +7891 -0.473846435546875 +7892 -0.01800537109375 +7893 -0.464813232421875 +7894 -0.016876220703125 +7895 -0.419097900390625 +7896 -0.01416015625 +7897 -0.334320068359375 +7898 -0.010467529296875 +7899 -0.227935791015625 +7900 -0.0067138671875 +7901 -0.12347412109375 +7902 -0.003173828125 +7903 -0.02764892578125 +7904 0.000885009765625 +7905 0.077667236328125 +7906 0.006256103515625 +7907 0.2132568359375 +7908 0.01336669921875 +7909 0.38885498046875 +7910 0.021331787109375 +7911 0.582794189453125 +7912 0.0277099609375 +7913 0.734039306640625 +7914 0.030731201171875 +7915 0.800140380859375 +7916 0.0302734375 +7917 0.7783203125 +7918 0.02618408203125 +7919 0.6651611328125 +7920 0.018402099609375 +7921 0.45965576171875 +7922 0.008453369140625 +7923 0.199188232421875 +7924 -0.00103759765625 +7925 -0.050689697265625 +7926 -0.007843017578125 +7927 -0.23297119140625 +7928 -0.01129150390625 +7929 -0.33013916015625 +7930 -0.012481689453125 +7931 -0.368408203125 +7932 -0.012664794921875 +7933 -0.378936767578125 +7934 -0.01251220703125 +7935 -0.376983642578125 +7936 -0.012603759765625 +7937 -0.37969970703125 +7938 -0.013092041015625 +7939 -0.391510009765625 +7940 -0.013519287109375 +7941 -0.385345458984375 +7942 -0.013458251953125 +7943 -0.3419189453125 +7944 -0.012908935546875 +7945 -0.28289794921875 +7946 -0.0120849609375 +7947 -0.251617431640625 +7948 -0.011077880859375 +7949 -0.266143798828125 +7950 -0.00946044921875 +7951 -0.273345947265625 +7952 -0.006866455078125 +7953 -0.216796875 +7954 -0.003662109375 +7955 -0.128265380859375 +7956 -0.00048828125 +7957 -0.068145751953125 +7958 0.00244140625 +7959 -0.0430908203125 +7960 0.00518798828125 +7961 -0.024444580078125 +7962 0.00787353515625 +7963 0.020721435546875 +7964 0.010589599609375 +7965 0.124481201171875 +7966 0.01300048828125 +7967 0.25787353515625 +7968 0.014678955078125 +7969 0.379119873046875 +7970 0.015533447265625 +7971 0.47991943359375 +7972 0.015350341796875 +7973 0.5281982421875 +7974 0.014068603515625 +7975 0.511138916015625 +7976 0.011962890625 +7977 0.456207275390625 +7978 0.009490966796875 +7979 0.407470703125 +7980 0.00689697265625 +7981 0.383758544921875 +7982 0.00408935546875 +7983 0.35687255859375 +7984 0.001129150390625 +7985 0.31182861328125 +7986 -0.00177001953125 +7987 0.250885009765625 +7988 -0.00457763671875 +7989 0.1654052734375 +7990 -0.00732421875 +7991 0.035247802734375 +7992 -0.00994873046875 +7993 -0.142059326171875 +7994 -0.012176513671875 +7995 -0.33563232421875 +7996 -0.013885498046875 +7997 -0.5345458984375 +7998 -0.014923095703125 +7999 -0.72186279296875 +8000 -0.01483154296875 +8001 -0.836669921875 +8002 -0.0133056640625 +8003 -0.8326416015625 +8004 -0.0106201171875 +8005 -0.7296142578125 +8006 -0.00738525390625 +8007 -0.582550048828125 +8008 -0.00408935546875 +8009 -0.440093994140625 +8010 -0.001007080078125 +8011 -0.324310302734375 +8012 0.001983642578125 +8013 -0.20147705078125 +8014 0.0050048828125 +8015 -0.044647216796875 +8016 0.007598876953125 +8017 0.103973388671875 +8018 0.009368896484375 +8019 0.202392578125 +8020 0.010406494140625 +8021 0.264495849609375 +8022 0.011077880859375 +8023 0.338897705078125 +8024 0.01153564453125 +8025 0.443817138671875 +8026 0.01153564453125 +8027 0.545074462890625 +8028 0.01092529296875 +8029 0.6173095703125 +8030 0.00970458984375 +8031 0.6524658203125 +8032 0.008087158203125 +8033 0.66339111328125 +8034 0.006195068359375 +8035 0.6561279296875 +8036 0.00396728515625 +8037 0.606781005859375 +8038 0.001373291015625 +8039 0.501190185546875 +8040 -0.0013427734375 +8041 0.352783203125 +8042 -0.003997802734375 +8043 0.176544189453125 +8044 -0.006561279296875 +8045 -0.034820556640625 +8046 -0.0087890625 +8047 -0.258209228515625 +8048 -0.01025390625 +8049 -0.44244384765625 +8050 -0.010894775390625 +8051 -0.5753173828125 +8052 -0.010711669921875 +8053 -0.65203857421875 +8054 -0.009521484375 +8055 -0.641632080078125 +8056 -0.007537841796875 +8057 -0.562164306640625 +8058 -0.005218505859375 +8059 -0.458038330078125 +8060 -0.0028076171875 +8061 -0.350555419921875 +8062 -0.00054931640625 +8063 -0.260528564453125 +8064 0.00140380859375 +8065 -0.192108154296875 +8066 0.003021240234375 +8067 -0.141937255859375 +8068 0.0042724609375 +8069 -0.1021728515625 +8070 0.005218505859375 +8071 -0.062896728515625 +8072 0.005950927734375 +8073 -0.011932373046875 +8074 0.00653076171875 +8075 0.062835693359375 +8076 0.00689697265625 +8077 0.148712158203125 +8078 0.00701904296875 +8079 0.241729736328125 +8080 0.006988525390625 +8081 0.34912109375 +8082 0.006744384765625 +8083 0.457305908203125 +8084 0.006195068359375 +8085 0.54388427734375 +8086 0.005126953125 +8087 0.5728759765625 +8088 0.0032958984375 +8089 0.506591796875 +8090 0.000823974609375 +8091 0.351226806640625 +8092 -0.001861572265625 +8093 0.146514892578125 +8094 -0.004302978515625 +8095 -0.05523681640625 +8096 -0.006134033203125 +8097 -0.21624755859375 +8098 -0.007354736328125 +8099 -0.334930419921875 +8100 -0.00787353515625 +8101 -0.402984619140625 +8102 -0.00787353515625 +8103 -0.4412841796875 +8104 -0.00775146484375 +8105 -0.49578857421875 +8106 -0.007476806640625 +8107 -0.5601806640625 +8108 -0.0068359375 +8109 -0.600738525390625 +8110 -0.005645751953125 +8111 -0.584228515625 +8112 -0.003692626953125 +8113 -0.47930908203125 +8114 -0.001007080078125 +8115 -0.27935791015625 +8116 0.00213623046875 +8117 -0.0089111328125 +8118 0.005157470703125 +8119 0.268798828125 +8120 0.0074462890625 +8121 0.482818603515625 +8122 0.008758544921875 +8123 0.60369873046875 +8124 0.009246826171875 +8125 0.650421142578125 +8126 0.009246826171875 +8127 0.66400146484375 +8128 0.008758544921875 +8129 0.6414794921875 +8130 0.007720947265625 +8131 0.572540283203125 +8132 0.006500244140625 +8133 0.498138427734375 +8134 0.005279541015625 +8135 0.439453125 +8136 0.00396728515625 +8137 0.375518798828125 +8138 0.0023193359375 +8139 0.274505615234375 +8140 0.00018310546875 +8141 0.1087646484375 +8142 -0.002197265625 +8143 -0.099395751953125 +8144 -0.004547119140625 +8145 -0.3182373046875 +8146 -0.0068359375 +8147 -0.5489501953125 +8148 -0.008880615234375 +8149 -0.7738037109375 +8150 -0.01025390625 +8151 -0.86383056640625 +8152 -0.010711669921875 +8153 -0.870391845703125 +8154 -0.010406494140625 +8155 -0.86895751953125 +8156 -0.00946044921875 +8157 -0.861053466796875 +8158 -0.007781982421875 +8159 -0.765869140625 +8160 -0.00531005859375 +8161 -0.5301513671875 +8162 -0.00213623046875 +8163 -0.214691162109375 +8164 0.0013427734375 +8165 0.137359619140625 +8166 0.004669189453125 +8167 0.474822998046875 +8168 0.007537841796875 +8169 0.76239013671875 +8170 0.00970458984375 +8171 0.867462158203125 +8172 0.011138916015625 +8173 0.870361328125 +8174 0.01171875 +8175 0.86480712890625 +8176 0.011505126953125 +8177 0.831817626953125 +8178 0.010711669921875 +8179 0.677581787109375 +8180 0.009429931640625 +8181 0.495880126953125 +8182 0.007781982421875 +8183 0.30767822265625 +8184 0.005859375 +8185 0.116180419921875 +8186 0.00341796875 +8187 -0.110748291015625 +8188 0.00042724609375 +8189 -0.381805419921875 +8190 -0.00274658203125 +8191 -0.6572265625 +8192 -0.005462646484375 +8193 -0.857421875 +8194 -0.00732421875 +8195 -0.870391845703125 +8196 -0.00836181640625 +8197 -0.870391845703125 +8198 -0.00921630859375 +8199 -0.86444091796875 +8200 -0.010650634765625 +8201 -0.85723876953125 +8202 -0.012115478515625 +8203 -0.790008544921875 +8204 -0.012176513671875 +8205 -0.62847900390625 +8206 -0.01055908203125 +8207 -0.3956298828125 +8208 -0.007843017578125 +8209 -0.126708984375 +8210 -0.0045166015625 +8211 0.150115966796875 +8212 -0.000640869140625 +8213 0.424041748046875 +8214 0.0032958984375 +8215 0.670623779296875 +8216 0.00653076171875 +8217 0.854522705078125 +8218 0.008819580078125 +8219 0.866485595703125 +8220 0.009918212890625 +8221 0.86920166015625 +8222 0.01031494140625 +8223 0.8653564453125 +8224 0.010406494140625 +8225 0.857147216796875 +8226 0.010162353515625 +8227 0.766845703125 +8228 0.009674072265625 +8229 0.628509521484375 +8230 0.00872802734375 +8231 0.462127685546875 +8232 0.00787353515625 +8233 0.297210693359375 +8234 0.00726318359375 +8235 0.14862060546875 +8236 0.0062255859375 +8237 -0.00537109375 +8238 0.004791259765625 +8239 -0.15753173828125 +8240 0.00274658203125 +8241 -0.31304931640625 +8242 -0.0003662109375 +8243 -0.48876953125 +8244 -0.0035400390625 +8245 -0.6416015625 +8246 -0.006317138671875 +8247 -0.751373291015625 +8248 -0.009307861328125 +8249 -0.84619140625 +8250 -0.01226806640625 +8251 -0.861297607421875 +8252 -0.014404296875 +8253 -0.863250732421875 +8254 -0.014984130859375 +8255 -0.856597900390625 +8256 -0.0142822265625 +8257 -0.7498779296875 +8258 -0.01361083984375 +8259 -0.624542236328125 +8260 -0.012420654296875 +8261 -0.47808837890625 +8262 -0.009185791015625 +8263 -0.253387451171875 +8264 -0.004913330078125 +8265 0.003692626953125 +8266 -0.00115966796875 +8267 0.2257080078125 +8268 0.00250244140625 +8269 0.427154541015625 +8270 0.0069580078125 +8271 0.643218994140625 +8272 0.012054443359375 +8273 0.855926513671875 +8274 0.01654052734375 +8275 0.870361328125 +8276 0.019317626953125 +8277 0.870361328125 +8278 0.020599365234375 +8279 0.862762451171875 +8280 0.020355224609375 +8281 0.79669189453125 +8282 0.018341064453125 +8283 0.595794677734375 +8284 0.015228271484375 +8285 0.362152099609375 +8286 0.011627197265625 +8287 0.1270751953125 +8288 0.00799560546875 +8289 -0.086944580078125 +8290 0.00433349609375 +8291 -0.2784423828125 +8292 -0.000274658203125 +8293 -0.484832763671875 +8294 -0.00640869140625 +8295 -0.729583740234375 +8296 -0.012969970703125 +8297 -0.86688232421875 +8298 -0.018524169921875 +8299 -0.870391845703125 +8300 -0.02301025390625 +8301 -0.86859130859375 +8302 -0.026458740234375 +8303 -0.86279296875 +8304 -0.028106689453125 +8305 -0.817962646484375 +8306 -0.02685546875 +8307 -0.6116943359375 +8308 -0.022613525390625 +8309 -0.3128662109375 +8310 -0.01617431640625 +8311 0.039398193359375 +8312 -0.007965087890625 +8313 0.422821044921875 +8314 0.001220703125 +8315 0.805145263671875 +8316 0.009796142578125 +8317 0.870361328125 +8318 0.0164794921875 +8319 0.870361328125 +8320 0.021087646484375 +8321 0.860015869140625 +8322 0.0235595703125 +8323 0.727935791015625 +8324 0.023834228515625 +8325 0.48114013671875 +8326 0.022552490234375 +8327 0.2059326171875 +8328 0.020355224609375 +8329 -0.06103515625 +8330 0.017547607421875 +8331 -0.29913330078125 +8332 0.0137939453125 +8333 -0.516204833984375 +8334 0.0087890625 +8335 -0.7252197265625 +8336 0.00311279296875 +8337 -0.85980224609375 +8338 -0.00238037109375 +8339 -0.870391845703125 +8340 -0.00701904296875 +8341 -0.870391845703125 +8342 -0.00970458984375 +8343 -0.858062744140625 +8344 -0.010406494140625 +8345 -0.673004150390625 +8346 -0.010498046875 +8347 -0.42694091796875 +8348 -0.011077880859375 +8349 -0.2100830078125 +8350 -0.012176513671875 +8351 -0.0362548828125 +8352 -0.01318359375 +8353 0.10943603515625 +8354 -0.01361083984375 +8355 0.23516845703125 +8356 -0.012542724609375 +8357 0.373687744140625 +8358 -0.01007080078125 +8359 0.517791748046875 +8360 -0.007720947265625 +8361 0.602783203125 +8362 -0.00537109375 +8363 0.635711669921875 +8364 -0.002227783203125 +8365 0.655181884765625 +8366 0.00146484375 +8367 0.65948486328125 +8368 0.0054931640625 +8369 0.651275634765625 +8370 0.009307861328125 +8371 0.61846923828125 +8372 0.012115478515625 +8373 0.53753662109375 +8374 0.0135498046875 +8375 0.404144287109375 +8376 0.013458251953125 +8377 0.22186279296875 +8378 0.011993408203125 +8379 0.003997802734375 +8380 0.009613037109375 +8381 -0.22100830078125 +8382 0.006866455078125 +8383 -0.42449951171875 +8384 0.004302978515625 +8385 -0.579833984375 +8386 0.002960205078125 +8387 -0.641876220703125 +8388 0.002685546875 +8389 -0.6177978515625 +8390 0.001922607421875 +8391 -0.575531005859375 +8392 0.000518798828125 +8393 -0.526336669921875 +8394 -0.00030517578125 +8395 -0.42645263671875 +8396 3.0517578125e-05 +8397 -0.2581787109375 +8398 0.0006103515625 +8399 -0.068695068359375 +8400 0.00048828125 +8401 0.09222412109375 +8402 6.103515625e-05 +8403 0.232147216796875 +8404 -0.000457763671875 +8405 0.3509521484375 +8406 -0.001800537109375 +8407 0.410064697265625 +8408 -0.00469970703125 +8409 0.372955322265625 +8410 -0.008697509765625 +8411 0.2554931640625 +8412 -0.012542724609375 +8413 0.10711669921875 +8414 -0.015777587890625 +8415 -0.052886962890625 +8416 -0.017547607421875 +8417 -0.186279296875 +8418 -0.01654052734375 +8419 -0.23291015625 +8420 -0.0133056640625 +8421 -0.209442138671875 +8422 -0.009368896484375 +8423 -0.174163818359375 +8424 -0.004913330078125 +8425 -0.126739501953125 +8426 0.000274658203125 +8427 -0.048126220703125 +8428 0.00555419921875 +8429 0.0426025390625 +8430 0.0098876953125 +8431 0.10748291015625 +8432 0.012969970703125 +8433 0.1409912109375 +8434 0.0159912109375 +8435 0.19708251953125 +8436 0.018829345703125 +8437 0.273651123046875 +8438 0.020172119140625 +8439 0.31768798828125 +8440 0.02032470703125 +8441 0.341094970703125 +8442 0.019927978515625 +8443 0.368011474609375 +8444 0.0184326171875 +8445 0.37249755859375 +8446 0.0146484375 +8447 0.30072021484375 +8448 0.00885009765625 +8449 0.1517333984375 +8450 0.00274658203125 +8451 -0.01470947265625 +8452 -0.004058837890625 +8453 -0.1883544921875 +8454 -0.011932373046875 +8455 -0.372711181640625 +8456 -0.018310546875 +8457 -0.51397705078125 +8458 -0.021148681640625 +8459 -0.57177734375 +8460 -0.0201416015625 +8461 -0.53948974609375 +8462 -0.01611328125 +8463 -0.43511962890625 +8464 -0.010772705078125 +8465 -0.2962646484375 +8466 -0.00592041015625 +8467 -0.161102294921875 +8468 -0.002105712890625 +8469 -0.0435791015625 +8470 0.00103759765625 +8471 0.060394287109375 +8472 0.002899169921875 +8473 0.13665771484375 +8474 0.00286865234375 +8475 0.170135498046875 +8476 0.00128173828125 +8477 0.16552734375 +8478 -3.0517578125e-05 +8479 0.15728759765625 +8480 -0.000762939453125 +8481 0.150787353515625 +8482 -0.0020751953125 +8483 0.12200927734375 +8484 -0.003570556640625 +8485 0.080108642578125 +8486 -0.00396728515625 +8487 0.05126953125 +8488 -0.001983642578125 +8489 0.062896728515625 +8490 0.00115966796875 +8491 0.09271240234375 +8492 0.002960205078125 +8493 0.092987060546875 +8494 0.004058837890625 +8495 0.07855224609375 +8496 0.005126953125 +8497 0.06427001953125 +8498 0.005279541015625 +8499 0.0347900390625 +8500 0.00433349609375 +8501 -0.01171875 +8502 0.003173828125 +8503 -0.056060791015625 +8504 0.00390625 +8505 -0.055511474609375 +8506 0.0064697265625 +8507 -0.010467529296875 +8508 0.008148193359375 +8509 0.02508544921875 +8510 0.0076904296875 +8511 0.025665283203125 +8512 0.006439208984375 +8513 0.017333984375 +8514 0.004547119140625 +8515 0.00189208984375 +8516 0.001556396484375 +8517 -0.03173828125 +8518 -0.001861572265625 +8519 -0.071502685546875 +8520 -0.006500244140625 +8521 -0.13543701171875 +8522 -0.012115478515625 +8523 -0.219970703125 +8524 -0.01739501953125 +8525 -0.300506591796875 +8526 -0.022216796875 +8527 -0.376312255859375 +8528 -0.02496337890625 +8529 -0.416107177734375 +8530 -0.023193359375 +8531 -0.371124267578125 +8532 -0.016937255859375 +8533 -0.242279052734375 +8534 -0.008209228515625 +8535 -0.069732666015625 +8536 0.00189208984375 +8537 0.125640869140625 +8538 0.011810302734375 +8539 0.31268310546875 +8540 0.0196533203125 +8541 0.45501708984375 +8542 0.025482177734375 +8543 0.554779052734375 +8544 0.029205322265625 +8545 0.61065673828125 +8546 0.030181884765625 +8547 0.610931396484375 +8548 0.02716064453125 +8549 0.531463623046875 +8550 0.020904541015625 +8551 0.3883056640625 +8552 0.014007568359375 +8553 0.23468017578125 +8554 0.0076904296875 +8555 0.095245361328125 +8556 0.003204345703125 +8557 -0.00396728515625 +8558 0.001220703125 +8559 -0.04852294921875 +8560 0.00091552734375 +8561 -0.055145263671875 +8562 -0.000274658203125 +8563 -0.0758056640625 +8564 -0.00372314453125 +8565 -0.138702392578125 +8566 -0.0076904296875 +8567 -0.209197998046875 +8568 -0.01220703125 +8569 -0.289031982421875 +8570 -0.017303466796875 +8571 -0.37884521484375 +8572 -0.0218505859375 +8573 -0.456329345703125 +8574 -0.0255126953125 +8575 -0.51641845703125 +8576 -0.026275634765625 +8577 -0.519287109375 +8578 -0.023773193359375 +8579 -0.458251953125 +8580 -0.020538330078125 +8581 -0.384796142578125 +8582 -0.017822265625 +8583 -0.323699951171875 +8584 -0.015289306640625 +8585 -0.269287109375 +8586 -0.0115966796875 +8587 -0.1951904296875 +8588 -0.0067138671875 +8589 -0.100006103515625 +8590 -0.001983642578125 +8591 -0.01055908203125 +8592 0.0040283203125 +8593 0.1033935546875 +8594 0.01165771484375 +8595 0.24908447265625 +8596 0.018218994140625 +8597 0.373199462890625 +8598 0.0228271484375 +8599 0.45806884765625 +8600 0.025848388671875 +8601 0.511474609375 +8602 0.028900146484375 +8603 0.565399169921875 +8604 0.031494140625 +8605 0.61138916015625 +8606 0.0306396484375 +8607 0.5897216796875 +8608 0.025848388671875 +8609 0.4906005859375 +8610 0.017974853515625 +8611 0.33148193359375 +8612 0.0087890625 +8613 0.147796630859375 +8614 0.000396728515625 +8615 -0.01873779296875 +8616 -0.00579833984375 +8617 -0.140289306640625 +8618 -0.008544921875 +8619 -0.191986083984375 +8620 -0.00836181640625 +8621 -0.184295654296875 +8622 -0.0074462890625 +8623 -0.161834716796875 +8624 -0.007904052734375 +8625 -0.166595458984375 +8626 -0.00946044921875 +8627 -0.19390869140625 +8628 -0.01116943359375 +8629 -0.22442626953125 +8630 -0.01409912109375 +8631 -0.279754638671875 +8632 -0.017181396484375 +8633 -0.3389892578125 +8634 -0.018035888671875 +8635 -0.3543701171875 +8636 -0.01776123046875 +8637 -0.348175048828125 +8638 -0.0166015625 +8639 -0.32598876953125 +8640 -0.01312255859375 +8641 -0.2581787109375 +8642 -0.007080078125 +8643 -0.139801025390625 +8644 0.000762939453125 +8645 0.014617919921875 +8646 0.00732421875 +8647 0.144378662109375 +8648 0.011199951171875 +8649 0.221038818359375 +8650 0.013702392578125 +8651 0.27069091796875 +8652 0.014892578125 +8653 0.294036865234375 +8654 0.01580810546875 +8655 0.311767578125 +8656 0.017242431640625 +8657 0.339141845703125 +8658 0.0184326171875 +8659 0.360260009765625 +8660 0.018646240234375 +8661 0.360504150390625 +8662 0.01605224609375 +8663 0.308380126953125 +8664 0.0093994140625 +8665 0.18170166015625 +8666 3.0517578125e-05 +8667 0.0047607421875 +8668 -0.009490966796875 +8669 -0.17559814453125 +8670 -0.016693115234375 +8671 -0.3143310546875 +8672 -0.019195556640625 +8673 -0.36785888671875 +8674 -0.018463134765625 +8675 -0.36248779296875 +8676 -0.017059326171875 +8677 -0.343536376953125 +8678 -0.014495849609375 +8679 -0.3018798828125 +8680 -0.01043701171875 +8681 -0.231414794921875 +8682 -0.00408935546875 +8683 -0.117645263671875 +8684 0.002685546875 +8685 0.007049560546875 +8686 0.006866455078125 +8687 0.087982177734375 +8688 0.009307861328125 +8689 0.13946533203125 +8690 0.0107421875 +8691 0.17425537109375 +8692 0.010986328125 +8693 0.188201904296875 +8694 0.009490966796875 +8695 0.171234130859375 +8696 0.006011962890625 +8697 0.118438720703125 +8698 0.00213623046875 +8699 0.05706787109375 +8700 -0.001983642578125 +8701 -0.010711669921875 +8702 -0.0067138671875 +8703 -0.0914306640625 +8704 -0.011199951171875 +8705 -0.162322998046875 +8706 -0.013641357421875 +8707 -0.194549560546875 +8708 -0.01031494140625 +8709 -0.1492919921875 +8710 -0.000396728515625 +8711 -0.02166748046875 +8712 0.0107421875 +8713 0.124053955078125 +8714 0.016632080078125 +8715 0.211151123046875 +8716 0.017608642578125 +8717 0.240447998046875 +8718 0.016510009765625 +8719 0.242218017578125 +8720 0.014251708984375 +8721 0.2257080078125 +8722 0.011199951171875 +8723 0.194366455078125 +8724 0.00445556640625 +8725 0.115509033203125 +8726 -0.003875732421875 +8727 0.0128173828125 +8728 -0.00860595703125 +8729 -0.053802490234375 +8730 -0.012176513671875 +8731 -0.110626220703125 +8732 -0.01837158203125 +8733 -0.199493408203125 +8734 -0.0250244140625 +8735 -0.29437255859375 +8736 -0.02667236328125 +8737 -0.33221435546875 +8738 -0.0205078125 +8739 -0.27972412109375 +8740 -0.010894775390625 +8741 -0.185333251953125 +8742 -0.004852294921875 +8743 -0.128204345703125 +8744 -0.00311279296875 +8745 -0.115692138671875 +8746 -0.002899169921875 +8747 -0.116455078125 +8748 -0.0020751953125 +8749 -0.105926513671875 +8750 0.001983642578125 +8751 -0.053955078125 +8752 0.010162353515625 +8753 0.048797607421875 +8754 0.0185546875 +8755 0.157318115234375 +8756 0.02197265625 +8757 0.212005615234375 +8758 0.02099609375 +8759 0.218475341796875 +8760 0.021026611328125 +8761 0.23724365234375 +8762 0.025421142578125 +8763 0.30535888671875 +8764 0.03057861328125 +8765 0.38128662109375 +8766 0.031280517578125 +8767 0.404449462890625 +8768 0.029327392578125 +8769 0.3944091796875 +8770 0.028045654296875 +8771 0.3885498046875 +8772 0.025360107421875 +8773 0.362640380859375 +8774 0.017486572265625 +8775 0.27362060546875 +8776 0.004058837890625 +8777 0.11712646484375 +8778 -0.0103759765625 +8779 -0.054901123046875 +8780 -0.02130126953125 +8781 -0.19085693359375 +8782 -0.02838134765625 +8783 -0.28570556640625 +8784 -0.03167724609375 +8785 -0.339263916015625 +8786 -0.033538818359375 +8787 -0.3775634765625 +8788 -0.03802490234375 +8789 -0.445709228515625 +8790 -0.04443359375 +8791 -0.535064697265625 +8792 -0.051422119140625 +8793 -0.629058837890625 +8794 -0.056365966796875 +8795 -0.697601318359375 +8796 -0.056121826171875 +8797 -0.70391845703125 +8798 -0.050201416015625 +8799 -0.6424560546875 +8800 -0.0367431640625 +8801 -0.491241455078125 +8802 -0.017059326171875 +8803 -0.265716552734375 +8804 0.00372314453125 +8805 -0.023712158203125 +8806 0.022735595703125 +8807 0.201751708984375 +8808 0.036956787109375 +8809 0.375823974609375 +8810 0.0452880859375 +8811 0.485076904296875 +8812 0.05126953125 +8813 0.56884765625 +8814 0.0556640625 +8815 0.634765625 +8816 0.054595947265625 +8817 0.63763427734375 +8818 0.047088623046875 +8819 0.5660400390625 +8820 0.03778076171875 +8821 0.4720458984375 +8822 0.03125 +8823 0.40692138671875 +8824 0.028167724609375 +8825 0.3778076171875 +8826 0.027862548828125 +8827 0.376953125 +8828 0.027496337890625 +8829 0.371978759765625 +8830 0.02264404296875 +8831 0.313140869140625 +8832 0.01190185546875 +8833 0.184417724609375 +8834 -0.00250244140625 +8835 0.011199951171875 +8836 -0.017486572265625 +8837 -0.171051025390625 +8838 -0.03094482421875 +8839 -0.33740234375 +8840 -0.041534423828125 +8841 -0.47198486328125 +8842 -0.048065185546875 +8843 -0.560394287109375 +8844 -0.048675537109375 +8845 -0.58056640625 +8846 -0.04473876953125 +8847 -0.54754638671875 +8848 -0.040496826171875 +8849 -0.508575439453125 +8850 -0.035614013671875 +8851 -0.459503173828125 +8852 -0.029571533203125 +8853 -0.394378662109375 +8854 -0.02581787109375 +8855 -0.35260009765625 +8856 -0.022369384765625 +8857 -0.31170654296875 +8858 -0.0126953125 +8859 -0.197418212890625 +8860 0.00335693359375 +8861 -0.007965087890625 +8862 0.021453857421875 +8863 0.207489013671875 +8864 0.038177490234375 +8865 0.409210205078125 +8866 0.0513916015625 +8867 0.57208251953125 +8868 0.058502197265625 +8869 0.66595458984375 +8870 0.0567626953125 +8871 0.65875244140625 +8872 0.047698974609375 +8873 0.56744384765625 +8874 0.03485107421875 +8875 0.431396484375 +8876 0.022125244140625 +8877 0.29443359375 +8878 0.011810302734375 +8879 0.182464599609375 +8880 0.00115966796875 +8881 0.06365966796875 +8882 -0.01104736328125 +8883 -0.075958251953125 +8884 -0.02069091796875 +8885 -0.189422607421875 +8886 -0.027313232421875 +8887 -0.271942138671875 +8888 -0.032684326171875 +8889 -0.342529296875 +8890 -0.03363037109375 +8891 -0.364166259765625 +8892 -0.02935791015625 +8893 -0.327239990234375 +8894 -0.023895263671875 +8895 -0.2769775390625 +8896 -0.02081298828125 +8897 -0.253692626953125 +8898 -0.01898193359375 +8899 -0.24365234375 +8900 -0.014190673828125 +8901 -0.1983642578125 +8902 -0.006317138671875 +8903 -0.116241455078125 +8904 0.001068115234375 +8905 -0.036834716796875 +8906 0.007537841796875 +8907 0.034881591796875 +8908 0.01239013671875 +8909 0.09124755859375 +8910 0.013580322265625 +8911 0.10888671875 +8912 0.01446533203125 +8913 0.125518798828125 +8914 0.01654052734375 +8915 0.15771484375 +8916 0.017486572265625 +8917 0.17828369140625 +8918 0.015899658203125 +8919 0.17108154296875 +8920 0.011322021484375 +8921 0.129974365234375 +8922 0.006195068359375 +8923 0.082427978515625 +8924 0.000518798828125 +8925 0.027679443359375 +8926 -0.00836181640625 +8927 -0.065643310546875 +8928 -0.017059326171875 +8929 -0.15936279296875 +8930 -0.02203369140625 +8931 -0.21307373046875 +8932 -0.023956298828125 +8933 -0.234649658203125 +8934 -0.020751953125 +8935 -0.2001953125 +8936 -0.013275146484375 +8937 -0.119171142578125 +8938 -0.00445556640625 +8939 -0.024749755859375 +8940 0.005889892578125 +8941 0.085784912109375 +8942 0.014678955078125 +8943 0.178131103515625 +8944 0.018646240234375 +8945 0.215576171875 +8946 0.018951416015625 +8947 0.211456298828125 +8948 0.01641845703125 +8949 0.17523193359375 +8950 0.012939453125 +8951 0.128753662109375 +8952 0.011077880859375 +8953 0.1019287109375 +8954 0.009033203125 +8955 0.0743408203125 +8956 0.006561279296875 +8957 0.04327392578125 +8958 0.006195068359375 +8959 0.038177490234375 +8960 0.010009765625 +8961 0.076263427734375 +8962 0.01702880859375 +8963 0.14105224609375 +8964 0.022308349609375 +8965 0.186431884765625 +8966 0.022857666015625 +8967 0.188812255859375 +8968 0.017425537109375 +8969 0.1390380859375 +8970 0.006439208984375 +8971 0.041778564453125 +8972 -0.007354736328125 +8973 -0.079437255859375 +8974 -0.0234375 +8975 -0.219390869140625 +8976 -0.040618896484375 +8977 -0.367828369140625 +8978 -0.055419921875 +8979 -0.494873046875 +8980 -0.06256103515625 +8981 -0.556243896484375 +8982 -0.056884765625 +8983 -0.508697509765625 +8984 -0.041168212890625 +8985 -0.3756103515625 +8986 -0.022857666015625 +8987 -0.218902587890625 +8988 -0.004913330078125 +8989 -0.063751220703125 +8990 0.012847900390625 +8991 0.091552734375 +8992 0.029205322265625 +8993 0.23602294921875 +8994 0.041015625 +8995 0.342987060546875 +8996 0.0462646484375 +8997 0.39520263671875 +8998 0.04461669921875 +8999 0.389373779296875 +9000 0.0360107421875 +9001 0.324249267578125 +9002 0.023406982421875 +9003 0.224090576171875 +9004 0.011077880859375 +9005 0.124267578125 +9006 0.00048828125 +9007 0.037078857421875 +9008 -0.005035400390625 +9009 -0.010101318359375 +9010 -0.00579833984375 +9011 -0.019439697265625 +9012 -0.005615234375 +9013 -0.022796630859375 +9014 -0.0023193359375 +9015 -0.001556396484375 +9016 0.00543212890625 +9017 0.056304931640625 +9018 0.012298583984375 +9019 0.106719970703125 +9020 0.011962890625 +9021 0.096893310546875 +9022 0.006256103515625 +9023 0.042694091796875 +9024 -0.00030517578125 +9025 -0.018035888671875 +9026 -0.006591796875 +9027 -0.07586669921875 +9028 -0.01129150390625 +9029 -0.11944580078125 +9030 -0.0157470703125 +9031 -0.15972900390625 +9032 -0.020660400390625 +9033 -0.202606201171875 +9034 -0.026123046875 +9035 -0.24859619140625 +9036 -0.032989501953125 +9037 -0.30517578125 +9038 -0.0400390625 +9039 -0.36212158203125 +9040 -0.0439453125 +9041 -0.39141845703125 +9042 -0.040130615234375 +9043 -0.35528564453125 +9044 -0.02813720703125 +9045 -0.249969482421875 +9046 -0.010009765625 +9047 -0.092864990234375 +9048 0.01104736328125 +9049 0.08905029296875 +9050 0.027801513671875 +9051 0.2352294921875 +9052 0.037109375 +9053 0.318817138671875 +9054 0.041259765625 +9055 0.358642578125 +9056 0.0394287109375 +9057 0.347747802734375 +9058 0.031585693359375 +9059 0.28564453125 +9060 0.023834228515625 +9061 0.223175048828125 +9062 0.020599365234375 +9063 0.196746826171875 +9064 0.0186767578125 +9065 0.179840087890625 +9066 0.016021728515625 +9067 0.155548095703125 +9068 0.015899658203125 +9069 0.151214599609375 +9070 0.01708984375 +9071 0.156951904296875 +9072 0.0146484375 +9073 0.13177490234375 +9074 0.011566162109375 +9075 0.100799560546875 +9076 0.010589599609375 +9077 0.087127685546875 +9078 0.007354736328125 +9079 0.05487060546875 +9080 0.000244140625 +9081 -0.009002685546875 +9082 -0.010650634765625 +9083 -0.10400390625 +9084 -0.0252685546875 +9085 -0.229400634765625 +9086 -0.040069580078125 +9087 -0.35552978515625 +9088 -0.05023193359375 +9089 -0.441925048828125 +9090 -0.053985595703125 +9091 -0.473846435546875 +9092 -0.052978515625 +9093 -0.464813232421875 +9094 -0.047698974609375 +9095 -0.419097900390625 +9096 -0.037841796875 +9097 -0.334320068359375 +9098 -0.025482177734375 +9099 -0.227935791015625 +9100 -0.013427734375 +9101 -0.12347412109375 +9102 -0.00244140625 +9103 -0.02764892578125 +9104 0.009674072265625 +9105 0.077667236328125 +9106 0.025421142578125 +9107 0.2132568359375 +9108 0.045989990234375 +9109 0.38885498046875 +9110 0.06878662109375 +9111 0.582794189453125 +9112 0.086517333984375 +9113 0.734039306640625 +9114 0.094085693359375 +9115 0.800140380859375 +9116 0.091217041015625 +9117 0.7783203125 +9118 0.0775146484375 +9119 0.6651611328125 +9120 0.0528564453125 +9121 0.45965576171875 +9122 0.021759033203125 +9123 0.199188232421875 +9124 -0.007904052734375 +9125 -0.050689697265625 +9126 -0.029296875 +9127 -0.23297119140625 +9128 -0.040374755859375 +9129 -0.33013916015625 +9130 -0.044342041015625 +9131 -0.368408203125 +9132 -0.04498291015625 +9133 -0.378936767578125 +9134 -0.044158935546875 +9135 -0.376983642578125 +9136 -0.043975830078125 +9137 -0.37969970703125 +9138 -0.044952392578125 +9139 -0.391510009765625 +9140 -0.043853759765625 +9141 -0.385345458984375 +9142 -0.038421630859375 +9143 -0.3419189453125 +9144 -0.031219482421875 +9145 -0.28289794921875 +9146 -0.0274658203125 +9147 -0.251617431640625 +9148 -0.029327392578125 +9149 -0.266143798828125 +9150 -0.030426025390625 +9151 -0.273345947265625 +9152 -0.023956298828125 +9153 -0.216796875 +9154 -0.01373291015625 +9155 -0.128265380859375 +9156 -0.006927490234375 +9157 -0.068145751953125 +9158 -0.00433349609375 +9159 -0.0430908203125 +9160 -0.00250244140625 +9161 -0.024444580078125 +9162 0.00250244140625 +9163 0.020721435546875 +9164 0.014556884765625 +9165 0.124481201171875 +9166 0.030181884765625 +9167 0.25787353515625 +9168 0.044403076171875 +9169 0.379119873046875 +9170 0.05621337890625 +9171 0.47991943359375 +9172 0.061798095703125 +9173 0.5281982421875 +9174 0.059600830078125 +9175 0.511138916015625 +9176 0.052947998046875 +9177 0.456207275390625 +9178 0.047119140625 +9179 0.407470703125 +9180 0.044403076171875 +9181 0.383758544921875 +9182 0.041351318359375 +9183 0.35687255859375 +9184 0.03619384765625 +9185 0.31182861328125 +9186 0.0291748046875 +9187 0.250885009765625 +9188 0.019256591796875 +9189 0.1654052734375 +9190 0.003997802734375 +9191 0.035247802734375 +9192 -0.016876220703125 +9193 -0.142059326171875 +9194 -0.039703369140625 +9195 -0.33563232421875 +9196 -0.06317138671875 +9197 -0.5345458984375 +9198 -0.08526611328125 +9199 -0.72186279296875 +9200 -0.098663330078125 +9201 -0.836669921875 +9202 -0.097869873046875 +9203 -0.8326416015625 +9204 -0.08526611328125 +9205 -0.7296142578125 +9206 -0.0675048828125 +9207 -0.582550048828125 +9208 -0.0504150390625 +9209 -0.440093994140625 +9210 -0.036651611328125 +9211 -0.324310302734375 +9212 -0.022125244140625 +9213 -0.20147705078125 +9214 -0.003570556640625 +9215 -0.044647216796875 +9216 0.013336181640625 +9217 0.103973388671875 +9218 0.022918701171875 +9219 0.202392578125 +9220 0.02752685546875 +9221 0.264495849609375 +9222 0.034820556640625 +9223 0.338897705078125 +9224 0.04779052734375 +9225 0.443817138671875 +9226 0.061370849609375 +9227 0.545074462890625 +9228 0.07177734375 +9229 0.6173095703125 +9230 0.0777587890625 +9231 0.6524658203125 +9232 0.08123779296875 +9233 0.66339111328125 +9234 0.082977294921875 +9235 0.6561279296875 +9236 0.079132080078125 +9237 0.606781005859375 +9238 0.067352294921875 +9239 0.501190185546875 +9240 0.049407958984375 +9241 0.352783203125 +9242 0.02734375 +9243 0.176544189453125 +9244 -0.000213623046875 +9245 -0.034820556640625 +9246 -0.02996826171875 +9247 -0.258209228515625 +9248 -0.054351806640625 +9249 -0.44244384765625 +9250 -0.071685791015625 +9251 -0.5753173828125 +9252 -0.081390380859375 +9253 -0.65203857421875 +9254 -0.078857421875 +9255 -0.641632080078125 +9256 -0.066864013671875 +9257 -0.562164306640625 +9258 -0.0521240234375 +9259 -0.458038330078125 +9260 -0.037750244140625 +9261 -0.350555419921875 +9262 -0.02679443359375 +9263 -0.260528564453125 +9264 -0.01971435546875 +9265 -0.192108154296875 +9266 -0.01580810546875 +9267 -0.141937255859375 +9268 -0.013671875 +9269 -0.1021728515625 +9270 -0.011566162109375 +9271 -0.062896728515625 +9272 -0.0074462890625 +9273 -0.011932373046875 +9274 0.000701904296875 +9275 0.062835693359375 +9276 0.011138916015625 +9277 0.148712158203125 +9278 0.02337646484375 +9279 0.241729736328125 +9280 0.03857421875 +9281 0.34912109375 +9282 0.0546875 +9283 0.457305908203125 +9284 0.068328857421875 +9285 0.54388427734375 +9286 0.074005126953125 +9287 0.5728759765625 +9288 0.06585693359375 +9289 0.506591796875 +9290 0.044708251953125 +9291 0.351226806640625 +9292 0.016448974609375 +9293 0.146514892578125 +9294 -0.0111083984375 +9295 -0.05523681640625 +9296 -0.032379150390625 +9297 -0.21624755859375 +9298 -0.04730224609375 +9299 -0.334930419921875 +9300 -0.054779052734375 +9301 -0.402984619140625 +9302 -0.058135986328125 +9303 -0.4412841796875 +9304 -0.064483642578125 +9305 -0.49578857421875 +9306 -0.07293701171875 +9307 -0.5601806640625 +9308 -0.078460693359375 +9309 -0.600738525390625 +9310 -0.076019287109375 +9311 -0.584228515625 +9312 -0.060821533203125 +9313 -0.47930908203125 +9314 -0.03179931640625 +9315 -0.27935791015625 +9316 0.00738525390625 +9317 -0.0089111328125 +9318 0.047271728515625 +9319 0.268798828125 +9320 0.077178955078125 +9321 0.482818603515625 +9322 0.092803955078125 +9323 0.60369873046875 +9324 0.09716796875 +9325 0.650421142578125 +9326 0.096649169921875 +9327 0.66400146484375 +9328 0.0909423828125 +9329 0.6414794921875 +9330 0.07861328125 +9331 0.572540283203125 +9332 0.06597900390625 +9333 0.498138427734375 +9334 0.056304931640625 +9335 0.439453125 +9336 0.04644775390625 +9337 0.375518798828125 +9338 0.031524658203125 +9339 0.274505615234375 +9340 0.007293701171875 +9341 0.1087646484375 +9342 -0.022857666015625 +9343 -0.099395751953125 +9344 -0.054229736328125 +9345 -0.3182373046875 +9346 -0.087127685546875 +9347 -0.5489501953125 +9348 -0.11895751953125 +9349 -0.7738037109375 +9350 -0.14178466796875 +9351 -0.86383056640625 +9352 -0.15069580078125 +9353 -0.870391845703125 +9354 -0.148529052734375 +9355 -0.86895751953125 +9356 -0.137420654296875 +9357 -0.861053466796875 +9358 -0.11480712890625 +9359 -0.765869140625 +9360 -0.079010009765625 +9361 -0.5301513671875 +9362 -0.031158447265625 +9363 -0.214691162109375 +9364 0.02215576171875 +9365 0.137359619140625 +9366 0.07318115234375 +9367 0.474822998046875 +9368 0.1165771484375 +9369 0.76239013671875 +9370 0.1483154296875 +9371 0.867462158203125 +9372 0.1685791015625 +9373 0.870361328125 +9374 0.1756591796875 +9375 0.86480712890625 +9376 0.170501708984375 +9377 0.831817626953125 +9378 0.156951904296875 +9379 0.677581787109375 +9380 0.136016845703125 +9381 0.495880126953125 +9382 0.110626220703125 +9383 0.30767822265625 +9384 0.081146240234375 +9385 0.116180419921875 +9386 0.0428466796875 +9387 -0.110748291015625 +9388 -0.0052490234375 +9389 -0.381805419921875 +9390 -0.056671142578125 +9391 -0.6572265625 +9392 -0.102294921875 +9393 -0.857421875 +9394 -0.135650634765625 +9395 -0.870391845703125 +9396 -0.155731201171875 +9397 -0.870391845703125 +9398 -0.16668701171875 +9399 -0.86444091796875 +9400 -0.174041748046875 +9401 -0.85723876953125 +9402 -0.175140380859375 +9403 -0.790008544921875 +9404 -0.161834716796875 +9405 -0.62847900390625 +9406 -0.13372802734375 +9407 -0.3956298828125 +9408 -0.095916748046875 +9409 -0.126708984375 +9410 -0.0526123046875 +9411 0.150115966796875 +9412 -0.005645751953125 +9413 0.424041748046875 +9414 0.040802001953125 +9415 0.670623779296875 +9416 0.08087158203125 +9417 0.854522705078125 +9418 0.11187744140625 +9419 0.866485595703125 +9420 0.131500244140625 +9421 0.86920166015625 +9422 0.142547607421875 +9423 0.8653564453125 +9424 0.14715576171875 +9425 0.857147216796875 +9426 0.14495849609375 +9427 0.766845703125 +9428 0.136810302734375 +9429 0.628509521484375 +9430 0.12176513671875 +9431 0.462127685546875 +9432 0.103851318359375 +9433 0.297210693359375 +9434 0.084991455078125 +9435 0.14862060546875 +9436 0.061767578125 +9437 -0.00537109375 +9438 0.035400390625 +9439 -0.15753173828125 +9440 0.00537109375 +9441 -0.31304931640625 +9442 -0.0303955078125 +9443 -0.48876953125 +9444 -0.064788818359375 +9445 -0.6416015625 +9446 -0.09405517578125 +9447 -0.751373291015625 +9448 -0.121734619140625 +9449 -0.84619140625 +9450 -0.145660400390625 +9451 -0.861297607421875 +9452 -0.160858154296875 +9453 -0.863250732421875 +9454 -0.162567138671875 +9455 -0.856597900390625 +9456 -0.152740478515625 +9457 -0.7498779296875 +9458 -0.1402587890625 +9459 -0.624542236328125 +9460 -0.12188720703125 +9461 -0.47808837890625 +9462 -0.088836669921875 +9463 -0.253387451171875 +9464 -0.048065185546875 +9465 0.003692626953125 +9466 -0.010009765625 +9467 0.2257080078125 +9468 0.027191162109375 +9469 0.427154541015625 +9470 0.0684814453125 +9471 0.643218994140625 +9472 0.11285400390625 +9473 0.855926513671875 +9474 0.151580810546875 +9475 0.870361328125 +9476 0.176483154296875 +9477 0.870361328125 +9478 0.18890380859375 +9479 0.862762451171875 +9480 0.188232421875 +9481 0.79669189453125 +9482 0.17254638671875 +9483 0.595794677734375 +9484 0.14697265625 +9485 0.362152099609375 +9486 0.1163330078125 +9487 0.1270751953125 +9488 0.084136962890625 +9489 -0.086944580078125 +9490 0.050384521484375 +9491 -0.2784423828125 +9492 0.008270263671875 +9493 -0.484832763671875 +9494 -0.046142578125 +9495 -0.729583740234375 +9496 -0.103912353515625 +9497 -0.86688232421875 +9498 -0.153778076171875 +9499 -0.870391845703125 +9500 -0.195037841796875 +9501 -0.86859130859375 +9502 -0.227569580078125 +9503 -0.86279296875 +9504 -0.244903564453125 +9505 -0.817962646484375 +9506 -0.238739013671875 +9507 -0.6116943359375 +9508 -0.207763671875 +9509 -0.3128662109375 +9510 -0.158050537109375 +9511 0.039398193359375 +9512 -0.0931396484375 +9513 0.422821044921875 +9514 -0.0189208984375 +9515 0.805145263671875 +9516 0.052276611328125 +9517 0.870361328125 +9518 0.1102294921875 +9519 0.870361328125 +9520 0.153106689453125 +9521 0.860015869140625 +9522 0.179779052734375 +9523 0.727935791015625 +9524 0.189483642578125 +9525 0.48114013671875 +9526 0.186859130859375 +9527 0.2059326171875 +9528 0.17626953125 +9529 -0.06103515625 +9530 0.15966796875 +9531 -0.29913330078125 +9532 0.134429931640625 +9533 -0.516204833984375 +9534 0.0977783203125 +9535 -0.7252197265625 +9536 0.054229736328125 +9537 -0.85980224609375 +9538 0.010009765625 +9539 -0.870391845703125 +9540 -0.029510498046875 +9541 -0.870391845703125 +9542 -0.055511474609375 +9543 -0.858062744140625 +9544 -0.0673828125 +9545 -0.673004150390625 +9546 -0.07501220703125 +9547 -0.42694091796875 +9548 -0.086700439453125 +9549 -0.2100830078125 +9550 -0.102203369140625 +9551 -0.0362548828125 +9552 -0.11627197265625 +9553 0.10943603515625 +9554 -0.125335693359375 +9555 0.23516845703125 +9556 -0.12188720703125 +9557 0.373687744140625 +9558 -0.106353759765625 +9559 0.517791748046875 +9560 -0.090362548828125 +9561 0.602783203125 +9562 -0.07293701171875 +9563 0.635711669921875 +9564 -0.047943115234375 +9565 0.655181884765625 +9566 -0.01715087890625 +9567 0.65948486328125 +9568 0.018035888671875 +9569 0.651275634765625 +9570 0.053192138671875 +9571 0.61846923828125 +9572 0.08160400390625 +9573 0.53753662109375 +9574 0.10003662109375 +9575 0.404144287109375 +9576 0.1068115234375 +9577 0.22186279296875 +9578 0.102325439453125 +9579 0.003997802734375 +9580 0.0899658203125 +9581 -0.22100830078125 +9582 0.0736083984375 +9583 -0.42449951171875 +9584 0.0572509765625 +9585 -0.579833984375 +9586 0.04876708984375 +9587 -0.641876220703125 +9588 0.04693603515625 +9589 -0.6177978515625 +9590 0.039886474609375 +9591 -0.575531005859375 +9592 0.02655029296875 +9593 -0.526336669921875 +9594 0.016448974609375 +9595 -0.42645263671875 +9596 0.014556884765625 +9597 -0.2581787109375 +9598 0.01409912109375 +9599 -0.068695068359375 +9600 0.0079345703125 +9601 0.09222412109375 +9602 -0.000518798828125 +9603 0.232147216796875 +9604 -0.00946044921875 +9605 0.3509521484375 +9606 -0.0244140625 +9607 0.410064697265625 +9608 -0.050872802734375 +9609 0.372955322265625 +9610 -0.08502197265625 +9611 0.2554931640625 +9612 -0.11724853515625 +9613 0.10711669921875 +9614 -0.143951416015625 +9615 -0.052886962890625 +9616 -0.158477783203125 +9617 -0.186279296875 +9618 -0.150543212890625 +9619 -0.23291015625 +9620 -0.124267578125 +9621 -0.209442138671875 +9622 -0.091766357421875 +9623 -0.174163818359375 +9624 -0.054473876953125 +9625 -0.126739501953125 +9626 -0.010528564453125 +9627 -0.048126220703125 +9628 0.03485107421875 +9629 0.0426025390625 +9630 0.07318115234375 +9631 0.10748291015625 +9632 0.10205078125 +9633 0.1409912109375 +9634 0.1302490234375 +9635 0.19708251953125 +9636 0.15655517578125 +9637 0.273651123046875 +9638 0.17071533203125 +9639 0.31768798828125 +9640 0.1748046875 +9641 0.341094970703125 +9642 0.173431396484375 +9643 0.368011474609375 +9644 0.162353515625 +9645 0.37249755859375 +9646 0.132476806640625 +9647 0.30072021484375 +9648 0.08465576171875 +9649 0.1517333984375 +9650 0.0311279296875 +9651 -0.01470947265625 +9652 -0.024871826171875 +9653 -0.1883544921875 +9654 -0.0826416015625 +9655 -0.372711181640625 +9656 -0.131011962890625 +9657 -0.51397705078125 +9658 -0.161346435546875 +9659 -0.57177734375 +9660 -0.17144775390625 +9661 -0.53948974609375 +9662 -0.16387939453125 +9663 -0.43511962890625 +9664 -0.145050048828125 +9665 -0.2962646484375 +9666 -0.12176513671875 +9667 -0.161102294921875 +9668 -0.096649169921875 +9669 -0.0435791015625 +9670 -0.06927490234375 +9671 0.060394287109375 +9672 -0.042816162109375 +9673 0.13665771484375 +9674 -0.020843505859375 +9675 0.170135498046875 +9676 -0.003448486328125 +9677 0.16552734375 +9678 0.014617919921875 +9679 0.15728759765625 +9680 0.033233642578125 +9681 0.150787353515625 +9682 0.046875 +9683 0.12200927734375 +9684 0.056243896484375 +9685 0.080108642578125 +9686 0.06524658203125 +9687 0.05126953125 +9688 0.0782470703125 +9689 0.062896728515625 +9690 0.09063720703125 +9691 0.09271240234375 +9692 0.093414306640625 +9693 0.092987060546875 +9694 0.089263916015625 +9695 0.07855224609375 +9696 0.08111572265625 +9697 0.06427001953125 +9698 0.066558837890625 +9699 0.0347900390625 +9700 0.04583740234375 +9701 -0.01171875 +9702 0.02325439453125 +9703 -0.056060791015625 +9704 0.00750732421875 +9705 -0.055511474609375 +9706 -0.00054931640625 +9707 -0.010467529296875 +9708 -0.009918212890625 +9709 0.02508544921875 +9710 -0.024444580078125 +9711 0.025665283203125 +9712 -0.038543701171875 +9713 0.017333984375 +9714 -0.051300048828125 +9715 0.00189208984375 +9716 -0.06427001953125 +9717 -0.03173828125 +9718 -0.074951171875 +9719 -0.071502685546875 +9720 -0.086578369140625 +9721 -0.13543701171875 +9722 -0.098602294921875 +9723 -0.219970703125 +9724 -0.106781005859375 +9725 -0.300506591796875 +9726 -0.111419677734375 +9727 -0.376312255859375 +9728 -0.107269287109375 +9729 -0.416107177734375 +9730 -0.08587646484375 +9731 -0.371124267578125 +9732 -0.048187255859375 +9733 -0.242279052734375 +9734 -0.002593994140625 +9735 -0.069732666015625 +9736 0.046295166015625 +9737 0.125640869140625 +9738 0.0919189453125 +9739 0.31268310546875 +9740 0.126708984375 +9741 0.45501708984375 +9742 0.15087890625 +9743 0.554779052734375 +9744 0.1640625 +9745 0.61065673828125 +9746 0.16387939453125 +9747 0.610931396484375 +9748 0.145599365234375 +9749 0.531463623046875 +9750 0.11260986328125 +9751 0.3883056640625 +9752 0.07586669921875 +9753 0.23468017578125 +9754 0.040679931640625 +9755 0.095245361328125 +9756 0.012664794921875 +9757 -0.00396728515625 +9758 -0.004852294921875 +9759 -0.04852294921875 +9760 -0.014739990234375 +9761 -0.055145263671875 +9762 -0.026947021484375 +9763 -0.0758056640625 +9764 -0.046722412109375 +9765 -0.138702392578125 +9766 -0.066741943359375 +9767 -0.209197998046875 +9768 -0.08709716796875 +9769 -0.289031982421875 +9770 -0.107696533203125 +9771 -0.37884521484375 +9772 -0.123992919921875 +9773 -0.456329345703125 +9774 -0.134979248046875 +9775 -0.51641845703125 +9776 -0.1328125 +9777 -0.519287109375 +9778 -0.116363525390625 +9779 -0.458251953125 +9780 -0.09619140625 +9781 -0.384796142578125 +9782 -0.077545166015625 +9783 -0.323699951171875 +9784 -0.0596923828125 +9785 -0.269287109375 +9786 -0.0377197265625 +9787 -0.1951904296875 +9788 -0.01177978515625 +9789 -0.100006103515625 +9790 0.012359619140625 +9791 -0.01055908203125 +9792 0.0404052734375 +9793 0.1033935546875 +9794 0.073577880859375 +9795 0.24908447265625 +9796 0.10101318359375 +9797 0.373199462890625 +9798 0.11907958984375 +9799 0.45806884765625 +9800 0.129302978515625 +9801 0.511474609375 +9802 0.13818359375 +9803 0.565399169921875 +9804 0.144134521484375 +9805 0.61138916015625 +9806 0.13543701171875 +9807 0.5897216796875 +9808 0.11041259765625 +9809 0.4906005859375 +9810 0.0728759765625 +9811 0.33148193359375 +9812 0.030242919921875 +9813 0.147796630859375 +9814 -0.008819580078125 +9815 -0.01873779296875 +9816 -0.038421630859375 +9817 -0.140289306640625 +9818 -0.053314208984375 +9819 -0.191986083984375 +9820 -0.055389404296875 +9821 -0.184295654296875 +9822 -0.053375244140625 +9823 -0.161834716796875 +9824 -0.055572509765625 +9825 -0.166595458984375 +9826 -0.061004638671875 +9827 -0.19390869140625 +9828 -0.065826416015625 +9829 -0.22442626953125 +9830 -0.074493408203125 +9831 -0.279754638671875 +9832 -0.082977294921875 +9833 -0.3389892578125 +9834 -0.081939697265625 +9835 -0.3543701171875 +9836 -0.076080322265625 +9837 -0.348175048828125 +9838 -0.0667724609375 +9839 -0.32598876953125 +9840 -0.04840087890625 +9841 -0.2581787109375 +9842 -0.02020263671875 +9843 -0.139801025390625 +9844 0.014678955078125 +9845 0.014617919921875 +9846 0.043853759765625 +9847 0.144378662109375 +9848 0.061492919921875 +9849 0.221038818359375 +9850 0.072723388671875 +9851 0.27069091796875 +9852 0.07763671875 +9853 0.294036865234375 +9854 0.080413818359375 +9855 0.311767578125 +9856 0.084228515625 +9857 0.339141845703125 +9858 0.086181640625 +9859 0.360260009765625 +9860 0.083465576171875 +9861 0.360504150390625 +9862 0.069366455078125 +9863 0.308380126953125 +9864 0.0391845703125 +9865 0.18170166015625 +9866 -0.001678466796875 +9867 0.0047607421875 +9868 -0.042999267578125 +9869 -0.17559814453125 +9870 -0.074951171875 +9871 -0.3143310546875 +9872 -0.088043212890625 +9873 -0.36785888671875 +9874 -0.087890625 +9875 -0.36248779296875 +9876 -0.084259033203125 +9877 -0.343536376953125 +9878 -0.0751953125 +9879 -0.3018798828125 +9880 -0.05938720703125 +9881 -0.231414794921875 +9882 -0.033721923828125 +9883 -0.117645263671875 +9884 -0.005279541015625 +9885 0.007049560546875 +9886 0.0140380859375 +9887 0.087982177734375 +9888 0.027191162109375 +9889 0.13946533203125 +9890 0.036834716796875 +9891 0.17425537109375 +9892 0.041961669921875 +9893 0.188201904296875 +9894 0.040252685546875 +9895 0.171234130859375 +9896 0.03057861328125 +9897 0.118438720703125 +9898 0.018768310546875 +9899 0.05706787109375 +9900 0.00518798828125 +9901 -0.010711669921875 +9902 -0.0115966796875 +9903 -0.0914306640625 +9904 -0.026702880859375 +9905 -0.162322998046875 +9906 -0.033905029296875 +9907 -0.194549560546875 +9908 -0.0247802734375 +9909 -0.1492919921875 +9910 0.001739501953125 +9911 -0.02166748046875 +9912 0.0318603515625 +9913 0.124053955078125 +9914 0.049041748046875 +9915 0.211151123046875 +9916 0.0535888671875 +9917 0.240447998046875 +9918 0.052154541015625 +9919 0.242218017578125 +9920 0.04681396484375 +9921 0.2257080078125 +9922 0.038421630859375 +9923 0.194366455078125 +9924 0.019989013671875 +9925 0.115509033203125 +9926 -0.003204345703125 +9927 0.0128173828125 +9928 -0.0181884765625 +9929 -0.053802490234375 +9930 -0.0306396484375 +9931 -0.110626220703125 +9932 -0.049591064453125 +9933 -0.199493408203125 +9934 -0.069488525390625 +9935 -0.29437255859375 +9936 -0.076751708984375 +9937 -0.33221435546875 +9938 -0.06427001953125 +9939 -0.27972412109375 +9940 -0.04254150390625 +9941 -0.185333251953125 +9942 -0.028717041015625 +9943 -0.128204345703125 +9944 -0.024505615234375 +9945 -0.115692138671875 +9946 -0.023193359375 +9947 -0.116455078125 +9948 -0.01959228515625 +9949 -0.105926513671875 +9950 -0.007232666015625 +9951 -0.053955078125 +9952 0.01580810546875 +9953 0.048797607421875 +9954 0.039794921875 +9955 0.157318115234375 +9956 0.05181884765625 +9957 0.212005615234375 +9958 0.053070068359375 +9959 0.218475341796875 +9960 0.056671142578125 +9961 0.23724365234375 +9962 0.070648193359375 +9963 0.30535888671875 +9964 0.0860595703125 +9965 0.38128662109375 +9966 0.089874267578125 +9967 0.404449462890625 +9968 0.086395263671875 +9969 0.3944091796875 +9970 0.08380126953125 +9971 0.3885498046875 +9972 0.076934814453125 +9973 0.362640380859375 +9974 0.056549072265625 +9975 0.27362060546875 +9976 0.021759033203125 +9977 0.11712646484375 +9978 -0.01611328125 +9979 -0.054901123046875 +9980 -0.0458984375 +9981 -0.19085693359375 +9982 -0.066497802734375 +9983 -0.28570556640625 +9984 -0.0772705078125 +9985 -0.339263916015625 +9986 -0.0841064453125 +9987 -0.3775634765625 +9988 -0.0982666015625 +9989 -0.445709228515625 +9990 -0.118011474609375 +9991 -0.535064697265625 +9992 -0.13958740234375 +9993 -0.629058837890625 +9994 -0.15576171875 +9995 -0.697601318359375 +9996 -0.15753173828125 +9997 -0.70391845703125 +9998 -0.143524169921875 +9999 -0.6424560546875 +10000 -0.10821533203125 +10001 -0.491241455078125 +10002 -0.0552978515625 +10003 -0.265716552734375 +10004 0.001068115234375 +10005 -0.023712158203125 +10006 0.05291748046875 +10007 0.201751708984375 +10008 0.091888427734375 +10009 0.375823974609375 +10010 0.1148681640625 +10011 0.485076904296875 +10012 0.131866455078125 +10013 0.56884765625 +10014 0.144989013671875 +10015 0.634765625 +10016 0.143218994140625 +10017 0.63763427734375 +10018 0.12384033203125 +10019 0.5660400390625 +10020 0.099853515625 +10021 0.4720458984375 +10022 0.083953857421875 +10023 0.40692138671875 +10024 0.077911376953125 +10025 0.3778076171875 +10026 0.0797119140625 +10027 0.376953125 +10028 0.0811767578125 +10029 0.371978759765625 +10030 0.06982421875 +10031 0.313140869140625 +10032 0.041473388671875 +10033 0.184417724609375 +10034 0.002227783203125 +10035 0.011199951171875 +10036 -0.039276123046875 +10037 -0.171051025390625 +10038 -0.07708740234375 +10039 -0.33740234375 +10040 -0.107452392578125 +10041 -0.47198486328125 +10042 -0.126922607421875 +10043 -0.560394287109375 +10044 -0.13018798828125 +10045 -0.58056640625 +10046 -0.12103271484375 +10047 -0.54754638671875 +10048 -0.111236572265625 +10049 -0.508575439453125 +10050 -0.0997314453125 +10051 -0.459503173828125 +10052 -0.084991455078125 +10053 -0.394378662109375 +10054 -0.07666015625 +10055 -0.35260009765625 +10056 -0.06903076171875 +10057 -0.31170654296875 +10058 -0.04351806640625 +10059 -0.197418212890625 +10060 0.00042724609375 +10061 -0.007965087890625 +10062 0.050750732421875 +10063 0.207489013671875 +10064 0.0977783203125 +10065 0.409210205078125 +10066 0.135467529296875 +10067 0.57208251953125 +10068 0.156463623046875 +10069 0.66595458984375 +10070 0.152923583984375 +10071 0.65875244140625 +10072 0.129119873046875 +10073 0.56744384765625 +10074 0.09490966796875 +10075 0.431396484375 +10076 0.061126708984375 +10077 0.29443359375 +10078 0.034210205078125 +10079 0.182464599609375 +10080 0.00616455078125 +10081 0.06365966796875 +10082 -0.02655029296875 +10083 -0.075958251953125 +10084 -0.052398681640625 +10085 -0.189422607421875 +10086 -0.070281982421875 +10087 -0.271942138671875 +10088 -0.085052490234375 +10089 -0.342529296875 +10090 -0.0877685546875 +10091 -0.364166259765625 +10092 -0.076171875 +10093 -0.327239990234375 +10094 -0.06158447265625 +10095 -0.2769775390625 +10096 -0.054107666015625 +10097 -0.253692626953125 +10098 -0.0504150390625 +10099 -0.24365234375 +10100 -0.03857421875 +10101 -0.1983642578125 +10102 -0.0181884765625 +10103 -0.116241455078125 +10104 0.000946044921875 +10105 -0.036834716796875 +10106 0.01763916015625 +10107 0.034881591796875 +10108 0.030059814453125 +10109 0.09124755859375 +10110 0.032501220703125 +10111 0.10888671875 +10112 0.034423828125 +10113 0.125518798828125 +10114 0.04010009765625 +10115 0.15771484375 +10116 0.042877197265625 +10117 0.17828369140625 +10118 0.038909912109375 +10119 0.17108154296875 +10120 0.02679443359375 +10121 0.129974365234375 +10122 0.013458251953125 +10123 0.082427978515625 +10124 -0.001220703125 +10125 0.027679443359375 +10126 -0.024932861328125 +10127 -0.065643310546875 +10128 -0.0482177734375 +10129 -0.15936279296875 +10130 -0.06109619140625 +10131 -0.21307373046875 +10132 -0.0655517578125 +10133 -0.234649658203125 +10134 -0.05572509765625 +10135 -0.2001953125 +10136 -0.034027099609375 +10137 -0.119171142578125 +10138 -0.008819580078125 +10139 -0.024749755859375 +10140 0.020477294921875 +10141 0.085784912109375 +10142 0.04522705078125 +10143 0.178131103515625 +10144 0.056243896484375 +10145 0.215576171875 +10146 0.056732177734375 +10147 0.211456298828125 +10148 0.04901123046875 +10149 0.17523193359375 +10150 0.038421630859375 +10151 0.128753662109375 +10152 0.032318115234375 +10153 0.1019287109375 +10154 0.025634765625 +10155 0.0743408203125 +10156 0.0177001953125 +10157 0.04327392578125 +10158 0.01580810546875 +10159 0.038177490234375 +10160 0.0242919921875 +10161 0.076263427734375 +10162 0.039093017578125 +10163 0.14105224609375 +10164 0.04888916015625 +10165 0.186431884765625 +10166 0.04791259765625 +10167 0.188812255859375 +10168 0.03399658203125 +10169 0.1390380859375 +10170 0.008392333984375 +10171 0.041778564453125 +10172 -0.02294921875 +10173 -0.079437255859375 +10174 -0.058685302734375 +10175 -0.219390869140625 +10176 -0.096221923828125 +10177 -0.367828369140625 +10178 -0.12811279296875 +10179 -0.494873046875 +10180 -0.14337158203125 +10181 -0.556243896484375 +10182 -0.13128662109375 +10183 -0.508697509765625 +10184 -0.09771728515625 +10185 -0.3756103515625 +10186 -0.05804443359375 +10187 -0.218902587890625 +10188 -0.018585205078125 +10189 -0.063751220703125 +10190 0.02099609375 +10191 0.091552734375 +10192 0.057952880859375 +10193 0.23602294921875 +10194 0.0855712890625 +10195 0.342987060546875 +10196 0.099578857421875 +10197 0.39520263671875 +10198 0.099090576171875 +10199 0.389373779296875 +10200 0.083709716796875 +10201 0.324249267578125 +10202 0.0594482421875 +10203 0.224090576171875 +10204 0.0350341796875 +10205 0.124267578125 +10206 0.0135498046875 +10207 0.037078857421875 +10208 0.001739501953125 +10209 -0.010101318359375 +10210 -0.000885009765625 +10211 -0.019439697265625 +10212 -0.002197265625 +10213 -0.022796630859375 +10214 0.002410888671875 +10215 -0.001556396484375 +10216 0.015960693359375 +10217 0.056304931640625 +10218 0.02752685546875 +10219 0.106719970703125 +10220 0.02410888671875 +10221 0.096893310546875 +10222 0.00970458984375 +10223 0.042694091796875 +10224 -0.0062255859375 +10225 -0.018035888671875 +10226 -0.021270751953125 +10227 -0.07586669921875 +10228 -0.0325927734375 +10229 -0.11944580078125 +10230 -0.04290771484375 +10231 -0.15972900390625 +10232 -0.05364990234375 +10233 -0.202606201171875 +10234 -0.064910888671875 +10235 -0.24859619140625 +10236 -0.078582763671875 +10237 -0.30517578125 +10238 -0.0921630859375 +10239 -0.36212158203125 +10240 -0.0986328125 +10241 -0.39141845703125 +10242 -0.088531494140625 +10243 -0.35528564453125 +10244 -0.06103515625 +10245 -0.249969482421875 +10246 -0.0203857421875 +10247 -0.092864990234375 +10248 0.026458740234375 +10249 0.08905029296875 +10250 0.0631103515625 +10251 0.2352294921875 +10252 0.082489013671875 +10253 0.318817138671875 +10254 0.0902099609375 +10255 0.358642578125 +10256 0.084564208984375 +10257 0.347747802734375 +10258 0.065582275390625 +10259 0.28564453125 +10260 0.04754638671875 +10261 0.223175048828125 +10262 0.0406494140625 +10263 0.196746826171875 +10264 0.037384033203125 +10265 0.179840087890625 +10266 0.032867431640625 +10267 0.155548095703125 +10268 0.034576416015625 +10269 0.151214599609375 +10270 0.03955078125 +10271 0.156951904296875 +10272 0.03607177734375 +10273 0.13177490234375 +10274 0.030975341796875 +10275 0.100799560546875 +10276 0.030487060546875 +10277 0.087127685546875 +10278 0.024383544921875 +10279 0.05487060546875 +10280 0.00885009765625 +10281 -0.009002685546875 +10282 -0.01605224609375 +10283 -0.10400390625 +10284 -0.05023193359375 +10285 -0.229400634765625 +10286 -0.085418701171875 +10287 -0.35552978515625 +10288 -0.110260009765625 +10289 -0.441925048828125 +10290 -0.120574951171875 +10291 -0.473846435546875 +10292 -0.120025634765625 +10293 -0.464813232421875 +10294 -0.10968017578125 +10295 -0.419097900390625 +10296 -0.088714599609375 +10297 -0.334320068359375 +10298 -0.061859130859375 +10299 -0.227935791015625 +10300 -0.035552978515625 +10301 -0.12347412109375 +10302 -0.011505126953125 +10303 -0.02764892578125 +10304 0.015472412109375 +10305 0.077667236328125 +10306 0.05133056640625 +10307 0.2132568359375 +10308 0.098907470703125 +10309 0.38885498046875 +10310 0.1522216796875 +10311 0.582794189453125 +10312 0.194183349609375 +10313 0.734039306640625 +10314 0.212890625 +10315 0.800140380859375 +10316 0.207550048828125 +10317 0.7783203125 +10318 0.177154541015625 +10319 0.6651611328125 +10320 0.12139892578125 +10321 0.45965576171875 +10322 0.050628662109375 +10323 0.199188232421875 +10324 -0.01690673828125 +10325 -0.050689697265625 +10326 -0.065399169921875 +10327 -0.23297119140625 +10328 -0.090087890625 +10329 -0.33013916015625 +10330 -0.098480224609375 +10331 -0.368408203125 +10332 -0.099395751953125 +10333 -0.378936767578125 +10334 -0.09722900390625 +10335 -0.376983642578125 +10336 -0.096893310546875 +10337 -0.37969970703125 +10338 -0.099609375 +10339 -0.391510009765625 +10340 -0.097869873046875 +10341 -0.385345458984375 +10342 -0.086212158203125 +10343 -0.3419189453125 +10344 -0.0706787109375 +10345 -0.28289794921875 +10346 -0.063323974609375 +10347 -0.251617431640625 +10348 -0.069091796875 +10349 -0.266143798828125 +10350 -0.073028564453125 +10351 -0.273345947265625 +10352 -0.059234619140625 +10353 -0.216796875 +10354 -0.0364990234375 +10355 -0.128265380859375 +10356 -0.0216064453125 +10357 -0.068145751953125 +10358 -0.01629638671875 +10359 -0.0430908203125 +10360 -0.012481689453125 +10361 -0.024444580078125 +10362 -0.0008544921875 +10363 0.020721435546875 +10364 0.027587890625 +10365 0.124481201171875 +10366 0.064727783203125 +10367 0.25787353515625 +10368 0.098876953125 +10369 0.379119873046875 +10370 0.127685546875 +10371 0.47991943359375 +10372 0.142120361328125 +10373 0.5281982421875 +10374 0.1385498046875 +10375 0.511138916015625 +10376 0.124603271484375 +10377 0.456207275390625 +10378 0.112518310546875 +10379 0.407470703125 +10380 0.10748291015625 +10381 0.383758544921875 +10382 0.101470947265625 +10383 0.35687255859375 +10384 0.090240478515625 +10385 0.31182861328125 +10386 0.0743408203125 +10387 0.250885009765625 +10388 0.051300048828125 +10389 0.1654052734375 +10390 0.01544189453125 +10391 0.035247802734375 +10392 -0.033935546875 +10393 -0.142059326171875 +10394 -0.088165283203125 +10395 -0.33563232421875 +10396 -0.1441650390625 +10397 -0.5345458984375 +10398 -0.197174072265625 +10399 -0.72186279296875 +10400 -0.230072021484375 +10401 -0.836669921875 +10402 -0.229888916015625 +10403 -0.8326416015625 +10404 -0.202117919921875 +10405 -0.7296142578125 +10406 -0.162109375 +10407 -0.582550048828125 +10408 -0.1234130859375 +10409 -0.440093994140625 +10410 -0.092132568359375 +10411 -0.324310302734375 +10412 -0.058746337890625 +10413 -0.20147705078125 +10414 -0.015655517578125 +10415 -0.044647216796875 +10416 0.02532958984375 +10417 0.103973388671875 +10418 0.052490234375 +10419 0.202392578125 +10420 0.069732666015625 +10421 0.264495849609375 +10422 0.090667724609375 +10423 0.338897705078125 +10424 0.120361328125 +10425 0.443817138671875 +10426 0.14923095703125 +10427 0.545074462890625 +10428 0.170135498046875 +10429 0.6173095703125 +10430 0.1807861328125 +10431 0.6524658203125 +10432 0.18475341796875 +10433 0.66339111328125 +10434 0.18365478515625 +10435 0.6561279296875 +10436 0.170745849609375 +10437 0.606781005859375 +10438 0.141998291015625 +10439 0.501190185546875 +10440 0.10113525390625 +10441 0.352783203125 +10442 0.05230712890625 +10443 0.176544189453125 +10444 -0.0064697265625 +10445 -0.034820556640625 +10446 -0.068756103515625 +10447 -0.258209228515625 +10448 -0.1202392578125 +10449 -0.44244384765625 +10450 -0.15753173828125 +10451 -0.5753173828125 +10452 -0.17926025390625 +10453 -0.65203857421875 +10454 -0.176727294921875 +10455 -0.641632080078125 +10456 -0.154998779296875 +10457 -0.562164306640625 +10458 -0.126495361328125 +10459 -0.458038330078125 +10460 -0.09710693359375 +10461 -0.350555419921875 +10462 -0.072601318359375 +10463 -0.260528564453125 +10464 -0.05413818359375 +10465 -0.192108154296875 +10466 -0.040740966796875 +10467 -0.141937255859375 +10468 -0.030181884765625 +10469 -0.1021728515625 +10470 -0.0196533203125 +10471 -0.062896728515625 +10472 -0.00567626953125 +10473 -0.011932373046875 +10474 0.01507568359375 +10475 0.062835693359375 +10476 0.039093017578125 +10477 0.148712158203125 +10478 0.06524658203125 +10479 0.241729736328125 +10480 0.095550537109375 +10481 0.34912109375 +10482 0.126220703125 +10483 0.457305908203125 +10484 0.15093994140625 +10485 0.54388427734375 +10486 0.15960693359375 +10487 0.5728759765625 +10488 0.141632080078125 +10489 0.506591796875 +10490 0.098724365234375 +10491 0.351226806640625 +10492 0.041961669921875 +10493 0.146514892578125 +10494 -0.0140380859375 +10495 -0.05523681640625 +10496 -0.058990478515625 +10497 -0.21624755859375 +10498 -0.09228515625 +10499 -0.334930419921875 +10500 -0.11077880859375 +10501 -0.402984619140625 +10502 -0.121063232421875 +10503 -0.4412841796875 +10504 -0.13751220703125 +10505 -0.49578857421875 +10506 -0.1580810546875 +10507 -0.5601806640625 +10508 -0.17218017578125 +10509 -0.600738525390625 +10510 -0.1693115234375 +10511 -0.584228515625 +10512 -0.1395263671875 +10513 -0.47930908203125 +10514 -0.08056640625 +10515 -0.27935791015625 +10516 9.1552734375e-05 +10517 -0.0089111328125 +10518 0.082977294921875 +10519 0.268798828125 +10520 0.146148681640625 +10521 0.482818603515625 +10522 0.18060302734375 +10523 0.60369873046875 +10524 0.192413330078125 +10525 0.650421142578125 +10526 0.194549560546875 +10527 0.66400146484375 +10528 0.1861572265625 +10529 0.6414794921875 +10530 0.164093017578125 +10531 0.572540283203125 +10532 0.141143798828125 +10533 0.498138427734375 +10534 0.123870849609375 +10535 0.439453125 +10536 0.10565185546875 +10537 0.375518798828125 +10538 0.07647705078125 +10539 0.274505615234375 +10540 0.02752685546875 +10541 0.1087646484375 +10542 -0.03436279296875 +10543 -0.099395751953125 +10544 -0.099456787109375 +10545 -0.3182373046875 +10546 -0.1683349609375 +10547 -0.5489501953125 +10548 -0.235565185546875 +10549 -0.7738037109375 +10550 -0.284820556640625 +10551 -0.86383056640625 +10552 -0.30584716796875 +10553 -0.870391845703125 +10554 -0.304290771484375 +10555 -0.86895751953125 +10556 -0.2843017578125 +10557 -0.861053466796875 +10558 -0.240509033203125 +10559 -0.765869140625 +10560 -0.16937255859375 +10561 -0.5301513671875 +10562 -0.07305908203125 +10563 -0.214691162109375 +10564 0.035064697265625 +10565 0.137359619140625 +10566 0.13909912109375 +10567 0.474822998046875 +10568 0.22808837890625 +10569 0.76239013671875 +10570 0.29376220703125 +10571 0.867462158203125 +10572 0.336395263671875 +10573 0.870361328125 +10574 0.3525390625 +10575 0.86480712890625 +10576 0.343994140625 +10577 0.831817626953125 +10578 0.3184814453125 +10579 0.677581787109375 +10580 0.277923583984375 +10581 0.495880126953125 +10582 0.2281494140625 +10583 0.30767822265625 +10584 0.169891357421875 +10585 0.116180419921875 +10586 0.09326171875 +10587 -0.110748291015625 +10588 -0.00390625 +10589 -0.381805419921875 +10590 -0.10833740234375 +10591 -0.6572265625 +10592 -0.201385498046875 +10593 -0.857421875 +10594 -0.269805908203125 +10595 -0.870391845703125 +10596 -0.311492919921875 +10597 -0.870391845703125 +10598 -0.3349609375 +10599 -0.86444091796875 +10600 -0.351470947265625 +10601 -0.85723876953125 +10602 -0.35540771484375 +10603 -0.790008544921875 +10604 -0.3299560546875 +10605 -0.62847900390625 +10606 -0.27423095703125 +10607 -0.3956298828125 +10608 -0.198516845703125 +10609 -0.126708984375 +10610 -0.111419677734375 +10611 0.150115966796875 +10612 -0.0166015625 +10613 0.424041748046875 +10614 0.0775146484375 +10615 0.670623779296875 +10616 0.158905029296875 +10617 0.854522705078125 +10618 0.22210693359375 +10619 0.866485595703125 +10620 0.26239013671875 +10621 0.86920166015625 +10622 0.2855224609375 +10623 0.8653564453125 +10624 0.295806884765625 +10625 0.857147216796875 +10626 0.29241943359375 +10627 0.766845703125 +10628 0.277069091796875 +10629 0.628509521484375 +10630 0.24774169921875 +10631 0.462127685546875 +10632 0.21258544921875 +10633 0.297210693359375 +10634 0.17547607421875 +10635 0.14862060546875 +10636 0.129364013671875 +10637 -0.00537109375 +10638 0.07659912109375 +10639 -0.15753173828125 +10640 0.016082763671875 +10641 -0.31304931640625 +10642 -0.056549072265625 +10643 -0.48876953125 +10644 -0.126708984375 +10645 -0.6416015625 +10646 -0.186767578125 +10647 -0.751373291015625 +10648 -0.243988037109375 +10649 -0.84619140625 +10650 -0.293853759765625 +10651 -0.861297607421875 +10652 -0.32611083984375 +10653 -0.863250732421875 +10654 -0.33099365234375 +10655 -0.856597900390625 +10656 -0.312408447265625 +10657 -0.7498779296875 +10658 -0.288482666015625 +10659 -0.624542236328125 +10660 -0.252410888671875 +10661 -0.47808837890625 +10662 -0.186004638671875 +10663 -0.253387451171875 +10664 -0.103546142578125 +10665 0.003692626953125 +10666 -0.0263671875 +10667 0.2257080078125 +10668 0.0494384765625 +10669 0.427154541015625 +10670 0.13397216796875 +10671 0.643218994140625 +10672 0.224273681640625 +10673 0.855926513671875 +10674 0.302337646484375 +10675 0.870361328125 +10676 0.352752685546875 +10677 0.870361328125 +10678 0.3778076171875 +10679 0.862762451171875 +10680 0.37664794921875 +10681 0.79669189453125 +10682 0.346405029296875 +10683 0.595794677734375 +10684 0.2962646484375 +10685 0.362152099609375 +10686 0.23504638671875 +10687 0.1270751953125 +10688 0.169403076171875 +10689 -0.086944580078125 +10690 0.10003662109375 +10691 -0.2784423828125 +10692 0.01611328125 +10693 -0.484832763671875 +10694 -0.08831787109375 +10695 -0.729583740234375 +10696 -0.19744873046875 +10697 -0.86688232421875 +10698 -0.29156494140625 +10699 -0.870391845703125 +10700 -0.369140625 +10701 -0.86859130859375 +10702 -0.429534912109375 +10703 -0.86279296875 +10704 -0.461578369140625 +10705 -0.817962646484375 +10706 -0.451171875 +10707 -0.6116943359375 +10708 -0.3961181640625 +10709 -0.3128662109375 +10710 -0.3070068359375 +10711 0.039398193359375 +10712 -0.190155029296875 +10713 0.422821044921875 +10714 -0.055999755859375 +10715 0.805145263671875 +10716 0.074127197265625 +10717 0.870361328125 +10718 0.182373046875 +10719 0.870361328125 +10720 0.2650146484375 +10721 0.860015869140625 +10722 0.319580078125 +10723 0.727935791015625 +10724 0.344268798828125 +10725 0.48114013671875 +10726 0.34661865234375 +10727 0.2059326171875 +10728 0.3336181640625 +10729 -0.06103515625 +10730 0.308349609375 +10731 -0.29913330078125 +10732 0.266326904296875 +10733 -0.516204833984375 +10734 0.20281982421875 +10735 -0.7252197265625 +10736 0.125640869140625 +10737 -0.85980224609375 +10738 0.045623779296875 +10739 -0.870391845703125 +10740 -0.027862548828125 +10741 -0.870391845703125 +10742 -0.0794677734375 +10743 -0.858062744140625 +10744 -0.10772705078125 +10745 -0.673004150390625 +10746 -0.12884521484375 +10747 -0.42694091796875 +10748 -0.156524658203125 +10749 -0.2100830078125 +10750 -0.189910888671875 +10751 -0.0362548828125 +10752 -0.22015380859375 +10753 0.10943603515625 +10754 -0.24102783203125 +10755 0.23516845703125 +10756 -0.238311767578125 +10757 0.373687744140625 +10758 -0.212554931640625 +10759 0.517791748046875 +10760 -0.185272216796875 +10761 0.602783203125 +10762 -0.154510498046875 +10763 0.635711669921875 +10764 -0.108612060546875 +10765 0.655181884765625 +10766 -0.050872802734375 +10767 0.65948486328125 +10768 0.016082763671875 +10769 0.651275634765625 +10770 0.083892822265625 +10771 0.61846923828125 +10772 0.139892578125 +10773 0.53753662109375 +10774 0.17791748046875 +10775 0.404144287109375 +10776 0.194580078125 +10777 0.22186279296875 +10778 0.1903076171875 +10779 0.003997802734375 +10780 0.1712646484375 +10781 -0.22100830078125 +10782 0.14447021484375 +10783 -0.42449951171875 +10784 0.117156982421875 +10785 -0.579833984375 +10786 0.103912353515625 +10787 -0.641876220703125 +10788 0.10235595703125 +10789 -0.6177978515625 +10790 0.090179443359375 +10791 -0.575531005859375 +10792 0.065460205078125 +10793 -0.526336669921875 +10794 0.045928955078125 +10795 -0.42645263671875 +10796 0.04095458984375 +10797 -0.2581787109375 +10798 0.037994384765625 +10799 -0.068695068359375 +10800 0.023834228515625 +10801 0.09222412109375 +10802 0.004852294921875 +10803 0.232147216796875 +10804 -0.01531982421875 +10805 0.3509521484375 +10806 -0.046844482421875 +10807 0.410064697265625 +10808 -0.099700927734375 +10809 0.372955322265625 +10810 -0.16656494140625 +10811 0.2554931640625 +10812 -0.229400634765625 +10813 0.10711669921875 +10814 -0.281341552734375 +10815 -0.052886962890625 +10816 -0.309814453125 +10817 -0.186279296875 +10818 -0.295501708984375 +10819 -0.23291015625 +10820 -0.246185302734375 +10821 -0.209442138671875 +10822 -0.184478759765625 +10823 -0.174163818359375 +10824 -0.11322021484375 +10825 -0.126739501953125 +10826 -0.029022216796875 +10827 -0.048126220703125 +10828 0.058380126953125 +10829 0.0426025390625 +10830 0.13287353515625 +10831 0.10748291015625 +10832 0.1898193359375 +10833 0.1409912109375 +10834 0.2454833984375 +10835 0.19708251953125 +10836 0.297454833984375 +10837 0.273651123046875 +10838 0.326416015625 +10839 0.31768798828125 +10840 0.336029052734375 +10841 0.341094970703125 +10842 0.33489990234375 +10843 0.368011474609375 +10844 0.31500244140625 +10845 0.37249755859375 +10846 0.259307861328125 +10847 0.30072021484375 +10848 0.16943359375 +10849 0.1517333984375 +10850 0.0682373046875 +10851 -0.01470947265625 +10852 -0.03814697265625 +10853 -0.1883544921875 +10854 -0.148284912109375 +10855 -0.372711181640625 +10856 -0.24114990234375 +10857 -0.51397705078125 +10858 -0.300506591796875 +10859 -0.57177734375 +10860 -0.322052001953125 +10861 -0.53948974609375 +10862 -0.3104248046875 +10863 -0.43511962890625 +10864 -0.2774658203125 +10865 -0.2962646484375 +10866 -0.235748291015625 +10867 -0.161102294921875 +10868 -0.190093994140625 +10869 -0.0435791015625 +10870 -0.13970947265625 +10871 0.060394287109375 +10872 -0.090484619140625 +10873 0.13665771484375 +10874 -0.049102783203125 +10875 0.170135498046875 +10876 -0.015777587890625 +10877 0.16552734375 +10878 0.019256591796875 +10879 0.15728759765625 +10880 0.055694580078125 +10881 0.150787353515625 +10882 0.083160400390625 +10883 0.12200927734375 +10884 0.102813720703125 +10885 0.080108642578125 +10886 0.12188720703125 +10887 0.05126953125 +10888 0.14837646484375 +10889 0.062896728515625 +10890 0.173583984375 +10891 0.09271240234375 +10892 0.18048095703125 +10893 0.092987060546875 +10894 0.17401123046875 +10895 0.07855224609375 +10896 0.159637451171875 +10897 0.06427001953125 +10898 0.1328125 +10899 0.0347900390625 +10900 0.093994140625 +10901 -0.01171875 +10902 0.051239013671875 +10903 -0.056060791015625 +10904 0.0208740234375 +10905 -0.055511474609375 +10906 0.0045166015625 +10907 -0.010467529296875 +10908 -0.014617919921875 +10909 0.02508544921875 +10910 -0.0435791015625 +10911 0.025665283203125 +10912 -0.0718994140625 +10913 0.017333984375 +10914 -0.09765625 +10915 0.00189208984375 +10916 -0.123687744140625 +10917 -0.03173828125 +10918 -0.145263671875 +10919 -0.071502685546875 +10920 -0.1683349609375 +10921 -0.13543701171875 +10922 -0.191802978515625 +10923 -0.219970703125 +10924 -0.207672119140625 +10925 -0.300506591796875 +10926 -0.216552734375 +10927 -0.376312255859375 +10928 -0.208770751953125 +10929 -0.416107177734375 +10930 -0.1688232421875 +10931 -0.371124267578125 +10932 -0.09844970703125 +10933 -0.242279052734375 +10934 -0.012939453125 +10935 -0.069732666015625 +10936 0.07904052734375 +10937 0.125640869140625 +10938 0.16546630859375 +10939 0.31268310546875 +10940 0.232696533203125 +10941 0.45501708984375 +10942 0.280609130859375 +10943 0.554779052734375 +10944 0.308135986328125 +10945 0.61065673828125 +10946 0.310943603515625 +10947 0.610931396484375 +10948 0.28076171875 +10949 0.531463623046875 +10950 0.223419189453125 +10951 0.3883056640625 +10952 0.157806396484375 +10953 0.23468017578125 +10954 0.093292236328125 +10955 0.095245361328125 +10956 0.039794921875 +10957 -0.00396728515625 +10958 0.00341796875 +10959 -0.04852294921875 +10960 -0.0203857421875 +10961 -0.055145263671875 +10962 -0.04833984375 +10963 -0.0758056640625 +10964 -0.0889892578125 +10965 -0.138702392578125 +10966 -0.129425048828125 +10967 -0.209197998046875 +10968 -0.16943359375 +10969 -0.289031982421875 +10970 -0.20867919921875 +10971 -0.37884521484375 +10972 -0.239166259765625 +10973 -0.456329345703125 +10974 -0.259063720703125 +10975 -0.51641845703125 +10976 -0.25482177734375 +10977 -0.519287109375 +10978 -0.22454833984375 +10979 -0.458251953125 +10980 -0.186614990234375 +10981 -0.384796142578125 +10982 -0.150299072265625 +10983 -0.323699951171875 +10984 -0.114532470703125 +10985 -0.269287109375 +10986 -0.071258544921875 +10987 -0.1951904296875 +10988 -0.02099609375 +10989 -0.100006103515625 +10990 0.026031494140625 +10991 -0.01055908203125 +10992 0.07940673828125 +10993 0.1033935546875 +10994 0.140899658203125 +10995 0.24908447265625 +10996 0.191650390625 +10997 0.373199462890625 +10998 0.2252197265625 +10999 0.45806884765625 +11000 0.244140625 +11001 0.511474609375 +11002 0.259490966796875 +11003 0.565399169921875 +11004 0.268646240234375 +11005 0.61138916015625 +11006 0.25152587890625 +11007 0.5897216796875 +11008 0.205291748046875 +11009 0.4906005859375 +11010 0.13653564453125 +11011 0.33148193359375 +11012 0.058380126953125 +11013 0.147796630859375 +11014 -0.013763427734375 +11015 -0.01873779296875 +11016 -0.069366455078125 +11017 -0.140289306640625 +11018 -0.099029541015625 +11019 -0.191986083984375 +11020 -0.1058349609375 +11021 -0.184295654296875 +11022 -0.104888916015625 +11023 -0.161834716796875 +11024 -0.110595703125 +11025 -0.166595458984375 +11026 -0.1212158203125 +11027 -0.19390869140625 +11028 -0.1300048828125 +11029 -0.22442626953125 +11030 -0.144683837890625 +11031 -0.279754638671875 +11032 -0.158294677734375 +11033 -0.3389892578125 +11034 -0.154571533203125 +11035 -0.3543701171875 +11036 -0.141876220703125 +11037 -0.348175048828125 +11038 -0.122772216796875 +11039 -0.32598876953125 +11040 -0.0875244140625 +11041 -0.2581787109375 +11042 -0.035064697265625 +11043 -0.139801025390625 +11044 0.0289306640625 +11045 0.014617919921875 +11046 0.08270263671875 +11047 0.144378662109375 +11048 0.115875244140625 +11049 0.221038818359375 +11050 0.137298583984375 +11051 0.27069091796875 +11052 0.1470947265625 +11053 0.294036865234375 +11054 0.1524658203125 +11055 0.311767578125 +11056 0.15899658203125 +11057 0.339141845703125 +11058 0.161651611328125 +11059 0.360260009765625 +11060 0.155548095703125 +11061 0.360504150390625 +11062 0.129058837890625 +11063 0.308380126953125 +11064 0.07415771484375 +11065 0.18170166015625 +11066 0.0003662109375 +11067 0.0047607421875 +11068 -0.0743408203125 +11069 -0.17559814453125 +11070 -0.132720947265625 +11071 -0.3143310546875 +11072 -0.158111572265625 +11073 -0.36785888671875 +11074 -0.160125732421875 +11075 -0.36248779296875 +11076 -0.1556396484375 +11077 -0.343536376953125 +11078 -0.141143798828125 +11079 -0.3018798828125 +11080 -0.114288330078125 +11081 -0.231414794921875 +11082 -0.0697021484375 +11083 -0.117645263671875 +11084 -0.019683837890625 +11085 0.007049560546875 +11086 0.01495361328125 +11087 0.087982177734375 +11088 0.03936767578125 +11089 0.13946533203125 +11090 0.058074951171875 +11091 0.17425537109375 +11092 0.069183349609375 +11093 0.188201904296875 +11094 0.068572998046875 +11095 0.171234130859375 +11096 0.054107666015625 +11097 0.118438720703125 +11098 0.035736083984375 +11099 0.05706787109375 +11100 0.0140380859375 +11101 -0.010711669921875 +11102 -0.013580322265625 +11103 -0.0914306640625 +11104 -0.0386962890625 +11105 -0.162322998046875 +11106 -0.050537109375 +11107 -0.194549560546875 +11108 -0.03448486328125 +11109 -0.1492919921875 +11110 0.011383056640625 +11111 -0.02166748046875 +11112 0.06304931640625 +11113 0.124053955078125 +11114 0.09185791015625 +11115 0.211151123046875 +11116 0.098358154296875 +11117 0.240447998046875 +11118 0.09417724609375 +11119 0.242218017578125 +11120 0.083099365234375 +11121 0.2257080078125 +11122 0.066680908203125 +11123 0.194366455078125 +11124 0.03289794921875 +11125 0.115509033203125 +11126 -0.00909423828125 +11127 0.0128173828125 +11128 -0.03662109375 +11129 -0.053802490234375 +11130 -0.0594482421875 +11131 -0.110626220703125 +11132 -0.093292236328125 +11133 -0.199493408203125 +11134 -0.128387451171875 +11135 -0.29437255859375 +11136 -0.14105224609375 +11137 -0.33221435546875 +11138 -0.118896484375 +11139 -0.27972412109375 +11140 -0.080291748046875 +11141 -0.185333251953125 +11142 -0.055206298828125 +11143 -0.128204345703125 +11144 -0.04656982421875 +11145 -0.115692138671875 +11146 -0.0428466796875 +11147 -0.116455078125 +11148 -0.0350341796875 +11149 -0.105926513671875 +11150 -0.011993408203125 +11151 -0.053955078125 +11152 0.029571533203125 +11153 0.048797607421875 +11154 0.072601318359375 +11155 0.157318115234375 +11156 0.0946044921875 +11157 0.212005615234375 +11158 0.097625732421875 +11159 0.218475341796875 +11160 0.104400634765625 +11161 0.23724365234375 +11162 0.12890625 +11163 0.30535888671875 +11164 0.155609130859375 +11165 0.38128662109375 +11166 0.161865234375 +11167 0.404449462890625 +11168 0.1551513671875 +11169 0.3944091796875 +11170 0.14971923828125 +11171 0.3885498046875 +11172 0.136627197265625 +11173 0.362640380859375 +11174 0.099884033203125 +11175 0.27362060546875 +11176 0.038055419921875 +11177 0.11712646484375 +11178 -0.0291748046875 +11179 -0.054901123046875 +11180 -0.082275390625 +11181 -0.19085693359375 +11182 -0.1192626953125 +11183 -0.28570556640625 +11184 -0.1400146484375 +11185 -0.339263916015625 +11186 -0.154327392578125 +11187 -0.3775634765625 +11188 -0.179168701171875 +11189 -0.445709228515625 +11190 -0.21136474609375 +11191 -0.535064697265625 +11192 -0.2447509765625 +11193 -0.629058837890625 +11194 -0.26812744140625 +11195 -0.697601318359375 +11196 -0.267852783203125 +11197 -0.70391845703125 +11198 -0.241973876953125 +11199 -0.6424560546875 +11200 -0.182373046875 +11201 -0.491241455078125 +11202 -0.09503173828125 +11203 -0.265716552734375 +11204 -0.0018310546875 +11205 -0.023712158203125 +11206 0.084686279296875 +11207 0.201751708984375 +11208 0.151336669921875 +11209 0.375823974609375 +11210 0.193023681640625 +11211 0.485076904296875 +11212 0.22454833984375 +11213 0.56884765625 +11214 0.248779296875 +11215 0.634765625 +11216 0.248779296875 +11217 0.63763427734375 +11218 0.2203369140625 +11219 0.5660400390625 +11220 0.18310546875 +11221 0.4720458984375 +11222 0.156463623046875 +11223 0.40692138671875 +11224 0.143218994140625 +11225 0.3778076171875 +11226 0.140625 +11227 0.376953125 +11228 0.136627197265625 +11229 0.371978759765625 +11230 0.11260986328125 +11231 0.313140869140625 +11232 0.0626220703125 +11233 0.184417724609375 +11234 -0.003662109375 +11235 0.011199951171875 +11236 -0.07281494140625 +11237 -0.171051025390625 +11238 -0.135467529296875 +11239 -0.33740234375 +11240 -0.1856689453125 +11241 -0.47198486328125 +11242 -0.218048095703125 +11243 -0.560394287109375 +11244 -0.224365234375 +11245 -0.58056640625 +11246 -0.21038818359375 +11247 -0.54754638671875 +11248 -0.1939697265625 +11249 -0.508575439453125 +11250 -0.17364501953125 +11251 -0.459503173828125 +11252 -0.14727783203125 +11253 -0.394378662109375 +11254 -0.1297607421875 +11255 -0.35260009765625 +11256 -0.112762451171875 +11257 -0.31170654296875 +11258 -0.06842041015625 +11259 -0.197418212890625 +11260 0.003814697265625 +11261 -0.007965087890625 +11262 0.08538818359375 +11263 0.207489013671875 +11264 0.161407470703125 +11265 0.409210205078125 +11266 0.2230224609375 +11267 0.57208251953125 +11268 0.25848388671875 +11269 0.66595458984375 +11270 0.254425048828125 +11271 0.65875244140625 +11272 0.2174072265625 +11273 0.56744384765625 +11274 0.1632080078125 +11275 0.431396484375 +11276 0.109405517578125 +11277 0.29443359375 +11278 0.066314697265625 +11279 0.182464599609375 +11280 0.020721435546875 +11281 0.06365966796875 +11282 -0.03326416015625 +11283 -0.075958251953125 +11284 -0.07666015625 +11285 -0.189422607421875 +11286 -0.107696533203125 +11287 -0.271942138671875 +11288 -0.134246826171875 +11289 -0.342529296875 +11290 -0.141326904296875 +11291 -0.364166259765625 +11292 -0.12506103515625 +11293 -0.327239990234375 +11294 -0.10394287109375 +11295 -0.2769775390625 +11296 -0.094390869140625 +11297 -0.253692626953125 +11298 -0.09075927734375 +11299 -0.24365234375 +11300 -0.073211669921875 +11301 -0.1983642578125 +11302 -0.041015625 +11303 -0.116241455078125 +11304 -0.010223388671875 +11305 -0.036834716796875 +11306 0.0172119140625 +11307 0.034881591796875 +11308 0.03826904296875 +11309 0.09124755859375 +11310 0.043548583984375 +11311 0.10888671875 +11312 0.04852294921875 +11313 0.125518798828125 +11314 0.06005859375 +11315 0.15771484375 +11316 0.067138671875 +11317 0.17828369140625 +11318 0.063232421875 +11319 0.17108154296875 +11320 0.0458984375 +11321 0.129974365234375 +11322 0.026336669921875 +11323 0.082427978515625 +11324 0.004241943359375 +11325 0.027679443359375 +11326 -0.033172607421875 +11327 -0.065643310546875 +11328 -0.070404052734375 +11329 -0.15936279296875 +11330 -0.091033935546875 +11331 -0.21307373046875 +11332 -0.09832763671875 +11333 -0.234649658203125 +11334 -0.0826416015625 +11335 -0.2001953125 +11336 -0.047943115234375 +11337 -0.119171142578125 +11338 -0.00787353515625 +11339 -0.024749755859375 +11340 0.038604736328125 +11341 0.085784912109375 +11342 0.077392578125 +11343 0.178131103515625 +11344 0.093505859375 +11345 0.215576171875 +11346 0.09234619140625 +11347 0.211456298828125 +11348 0.0777587890625 +11349 0.17523193359375 +11350 0.05865478515625 +11351 0.128753662109375 +11352 0.0472412109375 +11353 0.1019287109375 +11354 0.035247802734375 +11355 0.0743408203125 +11356 0.021575927734375 +11357 0.04327392578125 +11358 0.018310546875 +11359 0.038177490234375 +11360 0.03253173828125 +11361 0.076263427734375 +11362 0.057586669921875 +11363 0.14105224609375 +11364 0.074737548828125 +11365 0.186431884765625 +11366 0.074432373046875 +11367 0.188812255859375 +11368 0.053009033203125 +11369 0.1390380859375 +11370 0.012451171875 +11371 0.041778564453125 +11372 -0.03759765625 +11373 -0.079437255859375 +11374 -0.095001220703125 +11375 -0.219390869140625 +11376 -0.155517578125 +11377 -0.367828369140625 +11378 -0.20697021484375 +11379 -0.494873046875 +11380 -0.2313232421875 +11381 -0.556243896484375 +11382 -0.21099853515625 +11383 -0.508697509765625 +11384 -0.15557861328125 +11385 -0.3756103515625 +11386 -0.090423583984375 +11387 -0.218902587890625 +11388 -0.025848388671875 +11389 -0.063751220703125 +11390 0.038726806640625 +11391 0.091552734375 +11392 0.0987548828125 +11393 0.23602294921875 +11394 0.143310546875 +11395 0.342987060546875 +11396 0.165313720703125 +11397 0.39520263671875 +11398 0.16339111328125 +11399 0.389373779296875 +11400 0.13702392578125 +11401 0.324249267578125 +11402 0.096099853515625 +11403 0.224090576171875 +11404 0.055084228515625 +11405 0.124267578125 +11406 0.01898193359375 +11407 0.037078857421875 +11408 -0.0009765625 +11409 -0.010101318359375 +11410 -0.005615234375 +11411 -0.019439697265625 +11412 -0.00787353515625 +11413 -0.022796630859375 +11414 -0.000152587890625 +11415 -0.001556396484375 +11416 0.022491455078125 +11417 0.056304931640625 +11418 0.042144775390625 +11419 0.106719970703125 +11420 0.037353515625 +11421 0.096893310546875 +11422 0.014617919921875 +11423 0.042694091796875 +11424 -0.010589599609375 +11425 -0.018035888671875 +11426 -0.034393310546875 +11427 -0.07586669921875 +11428 -0.052154541015625 +11429 -0.11944580078125 +11430 -0.068359375 +11431 -0.15972900390625 +11432 -0.08544921875 +11433 -0.202606201171875 +11434 -0.103607177734375 +11435 -0.24859619140625 +11436 -0.125946044921875 +11437 -0.30517578125 +11438 -0.14837646484375 +11439 -0.36212158203125 +11440 -0.159515380859375 +11441 -0.39141845703125 +11442 -0.143951416015625 +11443 -0.35528564453125 +11444 -0.1002197265625 +11445 -0.249969482421875 +11446 -0.03546142578125 +11447 -0.092864990234375 +11448 0.03924560546875 +11449 0.08905029296875 +11450 0.09918212890625 +11451 0.2352294921875 +11452 0.133392333984375 +11453 0.318817138671875 +11454 0.149566650390625 +11455 0.358642578125 +11456 0.144866943359375 +11457 0.347747802734375 +11458 0.119110107421875 +11459 0.28564453125 +11460 0.09307861328125 +11461 0.223175048828125 +11462 0.0816650390625 +11463 0.196746826171875 +11464 0.0740966796875 +11465 0.179840087890625 +11466 0.0634765625 +11467 0.155548095703125 +11468 0.06103515625 +11469 0.151214599609375 +11470 0.062744140625 +11471 0.156951904296875 +11472 0.051910400390625 +11473 0.13177490234375 +11474 0.038818359375 +11475 0.100799560546875 +11476 0.032928466796875 +11477 0.087127685546875 +11478 0.019622802734375 +11479 0.05487060546875 +11480 -0.00640869140625 +11481 -0.009002685546875 +11482 -0.044952392578125 +11483 -0.10400390625 +11484 -0.095733642578125 +11485 -0.229400634765625 +11486 -0.146728515625 +11487 -0.35552978515625 +11488 -0.181396484375 +11489 -0.441925048828125 +11490 -0.19378662109375 +11491 -0.473846435546875 +11492 -0.189453125 +11493 -0.464813232421875 +11494 -0.170166015625 +11495 -0.419097900390625 +11496 -0.134979248046875 +11497 -0.334320068359375 +11498 -0.091033935546875 +11499 -0.227935791015625 +11500 -0.0479736328125 +11501 -0.12347412109375 +11502 -0.008575439453125 +11503 -0.02764892578125 +11504 0.0345458984375 +11505 0.077667236328125 +11506 0.08984375 +11507 0.2132568359375 +11508 0.161285400390625 +11509 0.38885498046875 +11510 0.240081787109375 +11511 0.582794189453125 +11512 0.30133056640625 +11513 0.734039306640625 +11514 0.3277587890625 +11515 0.800140380859375 +11516 0.3182373046875 +11517 0.7783203125 +11518 0.27142333984375 +11519 0.6651611328125 +11520 0.186492919921875 +11521 0.45965576171875 +11522 0.078155517578125 +11523 0.199188232421875 +11524 -0.025848388671875 +11525 -0.050689697265625 +11526 -0.100555419921875 +11527 -0.23297119140625 +11528 -0.138427734375 +11529 -0.33013916015625 +11530 -0.151123046875 +11531 -0.368408203125 +11532 -0.1524658203125 +11533 -0.378936767578125 +11534 -0.149261474609375 +11535 -0.376983642578125 +11536 -0.149078369140625 +11537 -0.37969970703125 +11538 -0.153900146484375 +11539 -0.391510009765625 +11540 -0.151763916015625 +11541 -0.385345458984375 +11542 -0.134124755859375 +11543 -0.3419189453125 +11544 -0.110382080078125 +11545 -0.28289794921875 +11546 -0.099456787109375 +11547 -0.251617431640625 +11548 -0.109130859375 +11549 -0.266143798828125 +11550 -0.115875244140625 +11551 -0.273345947265625 +11552 -0.09466552734375 +11553 -0.216796875 +11554 -0.05926513671875 +11555 -0.128265380859375 +11556 -0.03607177734375 +11557 -0.068145751953125 +11558 -0.027862548828125 +11559 -0.0430908203125 +11560 -0.021881103515625 +11561 -0.024444580078125 +11562 -0.003509521484375 +11563 0.020721435546875 +11564 0.0413818359375 +11565 0.124481201171875 +11566 0.100067138671875 +11567 0.25787353515625 +11568 0.15411376953125 +11569 0.379119873046875 +11570 0.1998291015625 +11571 0.47991943359375 +11572 0.2230224609375 +11573 0.5281982421875 +11574 0.2178955078125 +11575 0.511138916015625 +11576 0.1964111328125 +11577 0.456207275390625 +11578 0.17779541015625 +11579 0.407470703125 +11580 0.170196533203125 +11581 0.383758544921875 +11582 0.161041259765625 +11583 0.35687255859375 +11584 0.143585205078125 +11585 0.31182861328125 +11586 0.11871337890625 +11587 0.250885009765625 +11588 0.082550048828125 +11589 0.1654052734375 +11590 0.026153564453125 +11591 0.035247802734375 +11592 -0.05157470703125 +11593 -0.142059326171875 +11594 -0.137054443359375 +11595 -0.33563232421875 +11596 -0.225433349609375 +11597 -0.5345458984375 +11598 -0.3092041015625 +11599 -0.72186279296875 +11600 -0.3614501953125 +11601 -0.836669921875 +11602 -0.3616943359375 +11603 -0.8326416015625 +11604 -0.31854248046875 +11605 -0.7296142578125 +11606 -0.256103515625 +11607 -0.582550048828125 +11608 -0.19561767578125 +11609 -0.440093994140625 +11610 -0.14666748046875 +11611 -0.324310302734375 +11612 -0.094329833984375 +11613 -0.20147705078125 +11614 -0.026641845703125 +11615 -0.044647216796875 +11616 0.037841796875 +11617 0.103973388671875 +11618 0.0806884765625 +11619 0.202392578125 +11620 0.1080322265625 +11621 0.264495849609375 +11622 0.1412353515625 +11623 0.338897705078125 +11624 0.188262939453125 +11625 0.443817138671875 +11626 0.234039306640625 +11627 0.545074462890625 +11628 0.267303466796875 +11629 0.6173095703125 +11630 0.284454345703125 +11631 0.6524658203125 +11632 0.291046142578125 +11633 0.66339111328125 +11634 0.28961181640625 +11635 0.6561279296875 +11636 0.269561767578125 +11637 0.606781005859375 +11638 0.224578857421875 +11639 0.501190185546875 +11640 0.16046142578125 +11641 0.352783203125 +11642 0.083770751953125 +11643 0.176544189453125 +11644 -0.00872802734375 +11645 -0.034820556640625 +11646 -0.106842041015625 +11647 -0.258209228515625 +11648 -0.188079833984375 +11649 -0.44244384765625 +11650 -0.247039794921875 +11651 -0.5753173828125 +11652 -0.281585693359375 +11653 -0.65203857421875 +11654 -0.278045654296875 +11655 -0.641632080078125 +11656 -0.24432373046875 +11657 -0.562164306640625 +11658 -0.19989013671875 +11659 -0.458038330078125 +11660 -0.154022216796875 +11661 -0.350555419921875 +11662 -0.11578369140625 +11663 -0.260528564453125 +11664 -0.086944580078125 +11665 -0.192108154296875 +11666 -0.065948486328125 +11667 -0.141937255859375 +11668 -0.049285888671875 +11669 -0.1021728515625 +11670 -0.0325927734375 +11671 -0.062896728515625 +11672 -0.01043701171875 +11673 -0.011932373046875 +11674 0.0224609375 +11675 0.062835693359375 +11676 0.060546875 +11677 0.148712158203125 +11678 0.10205078125 +11679 0.241729736328125 +11680 0.15008544921875 +11681 0.34912109375 +11682 0.198638916015625 +11683 0.457305908203125 +11684 0.237823486328125 +11685 0.54388427734375 +11686 0.251739501953125 +11687 0.5728759765625 +11688 0.223724365234375 +11689 0.506591796875 +11690 0.15643310546875 +11691 0.351226806640625 +11692 0.067291259765625 +11693 0.146514892578125 +11694 -0.02069091796875 +11695 -0.05523681640625 +11696 -0.0909423828125 +11697 -0.21624755859375 +11698 -0.142791748046875 +11699 -0.334930419921875 +11700 -0.172576904296875 +11701 -0.402984619140625 +11702 -0.18951416015625 +11703 -0.4412841796875 +11704 -0.21380615234375 +11705 -0.49578857421875 +11706 -0.242645263671875 +11707 -0.5601806640625 +11708 -0.26116943359375 +11709 -0.600738525390625 +11710 -0.254730224609375 +11711 -0.584228515625 +11712 -0.20947265625 +11713 -0.47930908203125 +11714 -0.1224365234375 +11715 -0.27935791015625 +11716 -0.00439453125 +11717 -0.0089111328125 +11718 0.11688232421875 +11719 0.268798828125 +11720 0.210235595703125 +11721 0.482818603515625 +11722 0.26275634765625 +11723 0.60369873046875 +11724 0.282806396484375 +11725 0.650421142578125 +11726 0.2884521484375 +11727 0.66400146484375 +11728 0.278411865234375 +11729 0.6414794921875 +11730 0.248138427734375 +11731 0.572540283203125 +11732 0.21563720703125 +11733 0.498138427734375 +11734 0.190277099609375 +11735 0.439453125 +11736 0.16278076171875 +11737 0.375518798828125 +11738 0.11907958984375 +11739 0.274505615234375 +11740 0.046966552734375 +11741 0.1087646484375 +11742 -0.04376220703125 +11743 -0.099395751953125 +11744 -0.139190673828125 +11745 -0.3182373046875 +11746 -0.239898681640625 +11747 -0.5489501953125 +11748 -0.338104248046875 +11749 -0.7738037109375 +11750 -0.410552978515625 +11751 -0.86383056640625 +11752 -0.442657470703125 +11753 -0.870391845703125 +11754 -0.442230224609375 +11755 -0.86895751953125 +11756 -0.4150390625 +11757 -0.861053466796875 +11758 -0.353485107421875 +11759 -0.765869140625 +11760 -0.252593994140625 +11761 -0.5301513671875 +11762 -0.115509033203125 +11763 -0.214691162109375 +11764 0.038848876953125 +11765 0.137359619140625 +11766 0.187957763671875 +11767 0.474822998046875 +11768 0.316253662109375 +11769 0.76239013671875 +11770 0.411865234375 +11771 0.867462158203125 +11772 0.47503662109375 +11773 0.870361328125 +11774 0.500701904296875 +11775 0.86480712890625 +11776 0.491455078125 +11777 0.831817626953125 +11778 0.4581298828125 +11779 0.677581787109375 +11780 0.403228759765625 +11781 0.495880126953125 +11782 0.335205078125 +11783 0.30767822265625 +11784 0.254730224609375 +11785 0.116180419921875 +11786 0.1463623046875 +11787 -0.110748291015625 +11788 0.006378173828125 +11789 -0.381805419921875 +11790 -0.145477294921875 +11791 -0.6572265625 +11792 -0.2813720703125 +11793 -0.857421875 +11794 -0.381439208984375 +11795 -0.870391845703125 +11796 -0.442657470703125 +11797 -0.870391845703125 +11798 -0.47796630859375 +11799 -0.86444091796875 +11800 -0.504364013671875 +11801 -0.85723876953125 +11802 -0.51324462890625 +11803 -0.790008544921875 +11804 -0.47894287109375 +11805 -0.62847900390625 +11806 -0.399810791015625 +11807 -0.3956298828125 +11808 -0.2911376953125 +11809 -0.126708984375 +11810 -0.16558837890625 +11811 0.150115966796875 +11812 -0.0283203125 +11813 0.424041748046875 +11814 0.1082763671875 +11815 0.670623779296875 +11816 0.22625732421875 +11817 0.854522705078125 +11818 0.317657470703125 +11819 0.866485595703125 +11820 0.375518798828125 +11821 0.86920166015625 +11822 0.40869140625 +11823 0.8653564453125 +11824 0.423736572265625 +11825 0.857147216796875 +11826 0.419403076171875 +11827 0.766845703125 +11828 0.398223876953125 +11829 0.628509521484375 +11830 0.35699462890625 +11831 0.462127685546875 +11832 0.307830810546875 +11833 0.297210693359375 +11834 0.25640869140625 +11835 0.14862060546875 +11836 0.19171142578125 +11837 -0.00537109375 +11838 0.1170654296875 +11839 -0.15753173828125 +11840 0.03045654296875 +11841 -0.31304931640625 +11842 -0.07501220703125 +11843 -0.48876953125 +11844 -0.177490234375 +11845 -0.6416015625 +11846 -0.26556396484375 +11847 -0.751373291015625 +11848 -0.35040283203125 +11849 -0.84619140625 +11850 -0.42523193359375 +11851 -0.861297607421875 +11852 -0.474517822265625 +11853 -0.863250732421875 +11854 -0.483428955078125 +11855 -0.856597900390625 +11856 -0.457733154296875 +11857 -0.7498779296875 +11858 -0.424713134765625 +11859 -0.624542236328125 +11860 -0.373870849609375 +11861 -0.47808837890625 +11862 -0.2774658203125 +11863 -0.253387451171875 +11864 -0.1568603515625 +11865 0.003692626953125 +11866 -0.044097900390625 +11867 0.2257080078125 +11868 0.066925048828125 +11869 0.427154541015625 +11870 0.19171142578125 +11871 0.643218994140625 +11872 0.325958251953125 +11873 0.855926513671875 +11874 0.4425048828125 +11875 0.870361328125 +11876 0.51806640625 +11877 0.870361328125 +11878 0.556121826171875 +11879 0.862762451171875 +11880 0.555389404296875 +11881 0.79669189453125 +11882 0.511444091796875 +11883 0.595794677734375 +11884 0.43804931640625 +11885 0.362152099609375 +11886 0.348358154296875 +11887 0.1270751953125 +11888 0.252288818359375 +11889 -0.086944580078125 +11890 0.15069580078125 +11891 -0.2784423828125 +11892 0.0269775390625 +11893 -0.484832763671875 +11894 -0.128021240234375 +11895 -0.729583740234375 +11896 -0.29058837890625 +11897 -0.86688232421875 +11898 -0.43096923828125 +11899 -0.870391845703125 +11900 -0.54693603515625 +11901 -0.86859130859375 +11902 -0.637603759765625 +11903 -0.86279296875 +11904 -0.686065673828125 +11905 -0.817962646484375 +11906 -0.67095947265625 +11907 -0.6116943359375 +11908 -0.588958740234375 +11909 -0.3128662109375 +11910 -0.455963134765625 +11911 0.039398193359375 +11912 -0.281402587890625 +11913 0.422821044921875 +11914 -0.0809326171875 +11915 0.805145263671875 +11916 0.113311767578125 +11917 0.870361328125 +11918 0.27447509765625 +11919 0.870361328125 +11920 0.3970947265625 +11921 0.860015869140625 +11922 0.4775390625 +11923 0.727935791015625 +11924 0.51318359375 +11925 0.48114013671875 +11926 0.51544189453125 +11927 0.2059326171875 +11928 0.4949951171875 +11929 -0.06103515625 +11930 0.456573486328125 +11931 -0.29913330078125 +11932 0.393341064453125 +11933 -0.516204833984375 +11934 0.298095703125 +11935 -0.7252197265625 +11936 0.1826171875 +11937 -0.85980224609375 +11938 0.06317138671875 +11939 -0.870391845703125 +11940 -0.046173095703125 +11941 -0.870391845703125 +11942 -0.122283935546875 +11943 -0.858062744140625 +11944 -0.16302490234375 +11945 -0.673004150390625 +11946 -0.193023681640625 +11947 -0.42694091796875 +11948 -0.23309326171875 +11949 -0.2100830078125 +11950 -0.282073974609375 +11951 -0.0362548828125 +11952 -0.32611083984375 +11953 0.10943603515625 +11954 -0.355712890625 +11955 0.23516845703125 +11956 -0.35125732421875 +11957 0.373687744140625 +11958 -0.3135986328125 +11959 0.517791748046875 +11960 -0.272491455078125 +11961 0.602783203125 +11962 -0.225616455078125 +11963 0.635711669921875 +11964 -0.157318115234375 +11965 0.655181884765625 +11966 -0.072418212890625 +11967 0.65948486328125 +11968 0.02508544921875 +11969 0.651275634765625 +11970 0.12347412109375 +11971 0.61846923828125 +11972 0.205047607421875 +11973 0.53753662109375 +11974 0.26104736328125 +11975 0.404144287109375 +11976 0.286712646484375 +11977 0.22186279296875 +11978 0.282470703125 +11979 0.003997802734375 +11980 0.2567138671875 +11981 -0.22100830078125 +11982 0.2191162109375 +11983 -0.42449951171875 +11984 0.179718017578125 +11985 -0.579833984375 +11986 0.158660888671875 +11987 -0.641876220703125 +11988 0.152862548828125 +11989 -0.6177978515625 +11990 0.13189697265625 +11991 -0.575531005859375 +11992 0.0933837890625 +11993 -0.526336669921875 +11994 0.0618896484375 +11995 -0.42645263671875 +11996 0.050567626953125 +11997 -0.2581787109375 +11998 0.042449951171875 +11999 -0.068695068359375 +12000 0.01959228515625 +12001 0.09222412109375 +12002 -0.009033203125 +12003 0.232147216796875 +12004 -0.03839111328125 +12005 0.3509521484375 +12006 -0.082305908203125 +12007 0.410064697265625 +12008 -0.154510498046875 +12009 0.372955322265625 +12010 -0.245025634765625 +12011 0.2554931640625 +12012 -0.32916259765625 +12013 0.10711669921875 +12014 -0.39764404296875 +12015 -0.052886962890625 +12016 -0.43341064453125 +12017 -0.186279296875 +12018 -0.410186767578125 +12019 -0.23291015625 +12020 -0.338775634765625 +12021 -0.209442138671875 +12022 -0.250457763671875 +12023 -0.174163818359375 +12024 -0.149261474609375 +12025 -0.126739501953125 +12026 -0.030731201171875 +12027 -0.048126220703125 +12028 0.09161376953125 +12029 0.0426025390625 +12030 0.195556640625 +12031 0.10748291015625 +12032 0.275177001953125 +12033 0.1409912109375 +12034 0.353485107421875 +12035 0.19708251953125 +12036 0.426361083984375 +12037 0.273651123046875 +12038 0.4659423828125 +12039 0.31768798828125 +12040 0.477813720703125 +12041 0.341094970703125 +12042 0.474609375 +12043 0.368011474609375 +12044 0.444793701171875 +12045 0.37249755859375 +12046 0.363677978515625 +12047 0.30072021484375 +12048 0.233612060546875 +12049 0.1517333984375 +12050 0.087799072265625 +12051 -0.01470947265625 +12052 -0.064971923828125 +12053 -0.1883544921875 +12054 -0.222747802734375 +12055 -0.372711181640625 +12056 -0.355072021484375 +12057 -0.51397705078125 +12058 -0.4384765625 +12059 -0.57177734375 +12060 -0.466888427734375 +12061 -0.53948974609375 +12062 -0.44720458984375 +12063 -0.43511962890625 +12064 -0.39678955078125 +12065 -0.2962646484375 +12066 -0.334075927734375 +12067 -0.161102294921875 +12068 -0.266204833984375 +12069 -0.0435791015625 +12070 -0.192047119140625 +12071 0.060394287109375 +12072 -0.1202392578125 +12073 0.13665771484375 +12074 -0.060455322265625 +12075 0.170135498046875 +12076 -0.012969970703125 +12077 0.16552734375 +12078 0.0364990234375 +12079 0.15728759765625 +12080 0.08758544921875 +12081 0.150787353515625 +12082 0.12530517578125 +12083 0.12200927734375 +12084 0.151458740234375 +12085 0.080108642578125 +12086 0.17669677734375 +12087 0.05126953125 +12088 0.21282958984375 +12089 0.062896728515625 +12090 0.247283935546875 +12091 0.09271240234375 +12092 0.255462646484375 +12093 0.092987060546875 +12094 0.244659423828125 +12095 0.07855224609375 +12096 0.22283935546875 +12097 0.06427001953125 +12098 0.183441162109375 +12099 0.0347900390625 +12100 0.127166748046875 +12101 -0.01171875 +12102 0.065673828125 +12103 -0.056060791015625 +12104 0.022613525390625 +12105 -0.055511474609375 +12106 0.00030517578125 +12107 -0.010467529296875 +12108 -0.025726318359375 +12109 0.02508544921875 +12110 -0.06585693359375 +12111 0.025665283203125 +12112 -0.104949951171875 +12113 0.017333984375 +12114 -0.140380859375 +12115 0.00189208984375 +12116 -0.176361083984375 +12117 -0.03173828125 +12118 -0.20611572265625 +12119 -0.071502685546875 +12120 -0.238372802734375 +12121 -0.13543701171875 +12122 -0.2716064453125 +12123 -0.219970703125 +12124 -0.29425048828125 +12125 -0.300506591796875 +12126 -0.307159423828125 +12127 -0.376312255859375 +12128 -0.296234130859375 +12129 -0.416107177734375 +12130 -0.238983154296875 +12131 -0.371124267578125 +12132 -0.13787841796875 +12133 -0.242279052734375 +12134 -0.015045166015625 +12135 -0.069732666015625 +12136 0.117034912109375 +12137 0.125640869140625 +12138 0.240997314453125 +12139 0.31268310546875 +12140 0.33709716796875 +12141 0.45501708984375 +12142 0.40521240234375 +12143 0.554779052734375 +12144 0.443878173828125 +12145 0.61065673828125 +12146 0.4468994140625 +12147 0.610931396484375 +12148 0.40228271484375 +12149 0.531463623046875 +12150 0.318511962890625 +12151 0.3883056640625 +12152 0.22308349609375 +12153 0.23468017578125 +12154 0.12957763671875 +12155 0.095245361328125 +12156 0.052398681640625 +12157 -0.00396728515625 +12158 0.0003662109375 +12159 -0.04852294921875 +12160 -0.033172607421875 +12161 -0.055145263671875 +12162 -0.07257080078125 +12163 -0.0758056640625 +12164 -0.130340576171875 +12165 -0.138702392578125 +12166 -0.187835693359375 +12167 -0.209197998046875 +12168 -0.24481201171875 +12169 -0.289031982421875 +12170 -0.300811767578125 +12171 -0.37884521484375 +12172 -0.34423828125 +12173 -0.456329345703125 +12174 -0.37249755859375 +12175 -0.51641845703125 +12176 -0.365966796875 +12177 -0.519287109375 +12178 -0.321868896484375 +12179 -0.458251953125 +12180 -0.26690673828125 +12181 -0.384796142578125 +12182 -0.21453857421875 +12183 -0.323699951171875 +12184 -0.163238525390625 +12185 -0.269287109375 +12186 -0.101226806640625 +12187 -0.1951904296875 +12188 -0.0291748046875 +12189 -0.100006103515625 +12190 0.03814697265625 +12191 -0.01055908203125 +12192 0.11468505859375 +12193 0.1033935546875 +12194 0.203094482421875 +12195 0.24908447265625 +12196 0.275970458984375 +12197 0.373199462890625 +12198 0.32403564453125 +12199 0.45806884765625 +12200 0.35101318359375 +12201 0.511474609375 +12202 0.373077392578125 +12203 0.565399169921875 +12204 0.386383056640625 +12205 0.61138916015625 +12206 0.36175537109375 +12207 0.5897216796875 +12208 0.295135498046875 +12209 0.4906005859375 +12210 0.196319580078125 +12211 0.33148193359375 +12212 0.0841064453125 +12213 0.147796630859375 +12214 -0.019500732421875 +12215 -0.01873779296875 +12216 -0.0994873046875 +12217 -0.140289306640625 +12218 -0.14239501953125 +12219 -0.191986083984375 +12220 -0.152587890625 +12221 -0.184295654296875 +12222 -0.15167236328125 +12223 -0.161834716796875 +12224 -0.160186767578125 +12225 -0.166595458984375 +12226 -0.17559814453125 +12227 -0.19390869140625 +12228 -0.188262939453125 +12229 -0.22442626953125 +12230 -0.209259033203125 +12231 -0.279754638671875 +12232 -0.228607177734375 +12233 -0.3389892578125 +12234 -0.223114013671875 +12235 -0.3543701171875 +12236 -0.204681396484375 +12237 -0.348175048828125 +12238 -0.176971435546875 +12239 -0.32598876953125 +12240 -0.12615966796875 +12241 -0.2581787109375 +12242 -0.050689697265625 +12243 -0.139801025390625 +12244 0.041290283203125 +12245 0.014617919921875 +12246 0.11865234375 +12247 0.144378662109375 +12248 0.16656494140625 +12249 0.221038818359375 +12250 0.1976318359375 +12251 0.27069091796875 +12252 0.21197509765625 +12253 0.294036865234375 +12254 0.21990966796875 +12255 0.311767578125 +12256 0.229217529296875 +12257 0.339141845703125 +12258 0.23236083984375 +12259 0.360260009765625 +12260 0.222503662109375 +12261 0.360504150390625 +12262 0.184326171875 +12263 0.308380126953125 +12264 0.10736083984375 +12265 0.18170166015625 +12266 0.004638671875 +12267 0.0047607421875 +12268 -0.099517822265625 +12269 -0.17559814453125 +12270 -0.18170166015625 +12271 -0.3143310546875 +12272 -0.21929931640625 +12273 -0.36785888671875 +12274 -0.225067138671875 +12275 -0.36248779296875 +12276 -0.221435546875 +12277 -0.343536376953125 +12278 -0.20355224609375 +12279 -0.3018798828125 +12280 -0.16827392578125 +12281 -0.231414794921875 +12282 -0.10833740234375 +12283 -0.117645263671875 +12284 -0.040283203125 +12285 0.007049560546875 +12286 0.007965087890625 +12287 0.087982177734375 +12288 0.0430908203125 +12289 0.13946533203125 +12290 0.071014404296875 +12291 0.17425537109375 +12292 0.089080810546875 +12293 0.188201904296875 +12294 0.091156005859375 +12295 0.171234130859375 +12296 0.073883056640625 +12297 0.118438720703125 +12298 0.051177978515625 +12299 0.05706787109375 +12300 0.02362060546875 +12301 -0.010711669921875 +12302 -0.01275634765625 +12303 -0.0914306640625 +12304 -0.04608154296875 +12305 -0.162322998046875 +12306 -0.06109619140625 +12307 -0.194549560546875 +12308 -0.037078857421875 +12309 -0.1492919921875 +12310 0.0286865234375 +12311 -0.02166748046875 +12312 0.10198974609375 +12313 0.124053955078125 +12314 0.14202880859375 +12315 0.211151123046875 +12316 0.149688720703125 +12317 0.240447998046875 +12318 0.141632080078125 +12319 0.242218017578125 +12320 0.123382568359375 +12321 0.2257080078125 +12322 0.0972900390625 +12323 0.194366455078125 +12324 0.046356201171875 +12325 0.115509033203125 +12326 -0.0162353515625 +12327 0.0128173828125 +12328 -0.0579833984375 +12329 -0.053802490234375 +12330 -0.092681884765625 +12331 -0.110626220703125 +12332 -0.142608642578125 +12333 -0.199493408203125 +12334 -0.1937255859375 +12335 -0.29437255859375 +12336 -0.2122802734375 +12337 -0.33221435546875 +12338 -0.180572509765625 +12339 -0.27972412109375 +12340 -0.124847412109375 +12341 -0.185333251953125 +12342 -0.08782958984375 +12343 -0.128204345703125 +12344 -0.0738525390625 +12345 -0.115692138671875 +12346 -0.0665283203125 +12347 -0.116455078125 +12348 -0.053131103515625 +12349 -0.105926513671875 +12350 -0.0179443359375 +12351 -0.053955078125 +12352 0.04364013671875 +12353 0.048797607421875 +12354 0.107177734375 +12355 0.157318115234375 +12356 0.140472412109375 +12357 0.212005615234375 +12358 0.1463623046875 +12359 0.218475341796875 +12360 0.157196044921875 +12361 0.23724365234375 +12362 0.19281005859375 +12363 0.30535888671875 +12364 0.231048583984375 +12365 0.38128662109375 +12366 0.23956298828125 +12367 0.404449462890625 +12368 0.2291259765625 +12369 0.3944091796875 +12370 0.2200927734375 +12371 0.3885498046875 +12372 0.199859619140625 +12373 0.362640380859375 +12374 0.14569091796875 +12375 0.27362060546875 +12376 0.05560302734375 +12377 0.11712646484375 +12378 -0.042236328125 +12379 -0.054901123046875 +12380 -0.119842529296875 +12381 -0.19085693359375 +12382 -0.17431640625 +12383 -0.28570556640625 +12384 -0.20538330078125 +12385 -0.339263916015625 +12386 -0.2269287109375 +12387 -0.3775634765625 +12388 -0.2630615234375 +12389 -0.445709228515625 +12390 -0.309234619140625 +12391 -0.535064697265625 +12392 -0.356719970703125 +12393 -0.629058837890625 +12394 -0.389556884765625 +12395 -0.697601318359375 +12396 -0.3883056640625 +12397 -0.70391845703125 +12398 -0.3502197265625 +12399 -0.6424560546875 +12400 -0.26385498046875 +12401 -0.491241455078125 +12402 -0.13775634765625 +12403 -0.265716552734375 +12404 -0.003204345703125 +12405 -0.023712158203125 +12406 0.121826171875 +12407 0.201751708984375 +12408 0.21844482421875 +12409 0.375823974609375 +12410 0.279327392578125 +12411 0.485076904296875 +12412 0.325439453125 +12413 0.56884765625 +12414 0.360809326171875 +12415 0.634765625 +12416 0.36126708984375 +12417 0.63763427734375 +12418 0.320770263671875 +12419 0.5660400390625 +12420 0.267364501953125 +12421 0.4720458984375 +12422 0.228729248046875 +12423 0.40692138671875 +12424 0.208953857421875 +12425 0.3778076171875 +12426 0.204071044921875 +12427 0.376953125 +12428 0.196990966796875 +12429 0.371978759765625 +12430 0.16131591796875 +12431 0.313140869140625 +12432 0.088653564453125 +12433 0.184417724609375 +12434 -0.007171630859375 +12435 0.011199951171875 +12436 -0.107025146484375 +12437 -0.171051025390625 +12438 -0.197418212890625 +12439 -0.33740234375 +12440 -0.26983642578125 +12441 -0.47198486328125 +12442 -0.316558837890625 +12443 -0.560394287109375 +12444 -0.325836181640625 +12445 -0.58056640625 +12446 -0.30584716796875 +12447 -0.54754638671875 +12448 -0.282073974609375 +12449 -0.508575439453125 +12450 -0.25244140625 +12451 -0.459503173828125 +12452 -0.213958740234375 +12453 -0.394378662109375 +12454 -0.187896728515625 +12455 -0.35260009765625 +12456 -0.162445068359375 +12457 -0.31170654296875 +12458 -0.097991943359375 +12459 -0.197418212890625 +12460 0.0062255859375 +12461 -0.007965087890625 +12462 0.12371826171875 +12463 0.207489013671875 +12464 0.23309326171875 +12465 0.409210205078125 +12466 0.32086181640625 +12467 0.57208251953125 +12468 0.370849609375 +12469 0.66595458984375 +12470 0.36590576171875 +12471 0.65875244140625 +12472 0.315216064453125 +12473 0.56744384765625 +12474 0.239990234375 +12475 0.431396484375 +12476 0.16387939453125 +12477 0.29443359375 +12478 0.100921630859375 +12479 0.182464599609375 +12480 0.034210205078125 +12481 0.06365966796875 +12482 -0.043548583984375 +12483 -0.075958251953125 +12484 -0.107025146484375 +12485 -0.189422607421875 +12486 -0.153533935546875 +12487 -0.271942138671875 +12488 -0.193115234375 +12489 -0.342529296875 +12490 -0.205902099609375 +12491 -0.364166259765625 +12492 -0.186676025390625 +12493 -0.327239990234375 +12494 -0.15966796875 +12495 -0.2769775390625 +12496 -0.146514892578125 +12497 -0.253692626953125 +12498 -0.139862060546875 +12499 -0.24365234375 +12500 -0.113861083984375 +12501 -0.1983642578125 +12502 -0.0677490234375 +12503 -0.116241455078125 +12504 -0.0228271484375 +12505 -0.036834716796875 +12506 0.01806640625 +12507 0.034881591796875 +12508 0.050689697265625 +12509 0.09124755859375 +12510 0.062408447265625 +12511 0.10888671875 +12512 0.07330322265625 +12513 0.125518798828125 +12514 0.0921630859375 +12515 0.15771484375 +12516 0.104339599609375 +12517 0.17828369140625 +12518 0.101104736328125 +12519 0.17108154296875 +12520 0.079193115234375 +12521 0.129974365234375 +12522 0.05328369140625 +12523 0.082427978515625 +12524 0.023040771484375 +12525 0.027679443359375 +12526 -0.02825927734375 +12527 -0.065643310546875 +12528 -0.080108642578125 +12529 -0.15936279296875 +12530 -0.110748291015625 +12531 -0.21307373046875 +12532 -0.124298095703125 +12533 -0.234649658203125 +12534 -0.107818603515625 +12535 -0.2001953125 +12536 -0.0662841796875 +12537 -0.119171142578125 +12538 -0.017364501953125 +12539 -0.024749755859375 +12540 0.04046630859375 +12541 0.085784912109375 +12542 0.088897705078125 +12543 0.178131103515625 +12544 0.1080322265625 +12545 0.215576171875 +12546 0.104949951171875 +12547 0.211456298828125 +12548 0.0845947265625 +12549 0.17523193359375 +12550 0.059326171875 +12551 0.128753662109375 +12552 0.045989990234375 +12553 0.1019287109375 +12554 0.0328369140625 +12555 0.0743408203125 +12556 0.018157958984375 +12557 0.04327392578125 +12558 0.018463134765625 +12559 0.038177490234375 +12560 0.043365478515625 +12561 0.076263427734375 +12562 0.08331298828125 +12563 0.14105224609375 +12564 0.1119384765625 +12565 0.186431884765625 +12566 0.115692138671875 +12567 0.188812255859375 +12568 0.089263916015625 +12569 0.1390380859375 +12570 0.035247802734375 +12571 0.041778564453125 +12572 -0.03302001953125 +12573 -0.079437255859375 +12574 -0.11260986328125 +12575 -0.219390869140625 +12576 -0.1976318359375 +12577 -0.367828369140625 +12578 -0.271087646484375 +12579 -0.494873046875 +12580 -0.307708740234375 +12581 -0.556243896484375 +12582 -0.282867431640625 +12583 -0.508697509765625 +12584 -0.209686279296875 +12585 -0.3756103515625 +12586 -0.12322998046875 +12587 -0.218902587890625 +12588 -0.037628173828125 +12589 -0.063751220703125 +12590 0.048187255859375 +12591 0.091552734375 +12592 0.12811279296875 +12593 0.23602294921875 +12594 0.1871337890625 +12595 0.342987060546875 +12596 0.215545654296875 +12597 0.39520263671875 +12598 0.211517333984375 +12599 0.389373779296875 +12600 0.174346923828125 +12601 0.324249267578125 +12602 0.117828369140625 +12603 0.224090576171875 +12604 0.06201171875 +12605 0.124267578125 +12606 0.0137939453125 +12607 0.037078857421875 +12608 -0.01129150390625 +12609 -0.010101318359375 +12610 -0.014617919921875 +12611 -0.019439697265625 +12612 -0.014373779296875 +12613 -0.022796630859375 +12614 -0.0001220703125 +12615 -0.001556396484375 +12616 0.0347900390625 +12617 0.056304931640625 +12618 0.06524658203125 +12619 0.106719970703125 +12620 0.0611572265625 +12621 0.096893310546875 +12622 0.031494140625 +12623 0.042694091796875 +12624 -0.002288818359375 +12625 -0.018035888671875 +12626 -0.03485107421875 +12627 -0.07586669921875 +12628 -0.05975341796875 +12629 -0.11944580078125 +12630 -0.08319091796875 +12631 -0.15972900390625 +12632 -0.108489990234375 +12633 -0.202606201171875 +12634 -0.1358642578125 +12635 -0.24859619140625 +12636 -0.16949462890625 +12637 -0.30517578125 +12638 -0.2034912109375 +12639 -0.36212158203125 +12640 -0.22186279296875 +12641 -0.39141845703125 +12642 -0.2030029296875 +12643 -0.35528564453125 +12644 -0.14471435546875 +12645 -0.249969482421875 +12646 -0.05682373046875 +12647 -0.092864990234375 +12648 0.04541015625 +12649 0.08905029296875 +12650 0.127655029296875 +12651 0.2352294921875 +12652 0.174713134765625 +12653 0.318817138671875 +12654 0.197265625 +12655 0.358642578125 +12656 0.191375732421875 +12657 0.347747802734375 +12658 0.15673828125 +12659 0.28564453125 +12660 0.1221923828125 +12661 0.223175048828125 +12662 0.10833740234375 +12663 0.196746826171875 +12664 0.10003662109375 +12665 0.179840087890625 +12666 0.087615966796875 +12667 0.155548095703125 +12668 0.0865478515625 +12669 0.151214599609375 +12670 0.09112548828125 +12671 0.156951904296875 +12672 0.0780029296875 +12673 0.13177490234375 +12674 0.061370849609375 +12675 0.100799560546875 +12676 0.054290771484375 +12677 0.087127685546875 +12678 0.036376953125 +12679 0.05487060546875 +12680 0.00018310546875 +12681 -0.009002685546875 +12682 -0.053955078125 +12683 -0.10400390625 +12684 -0.125640869140625 +12685 -0.229400634765625 +12686 -0.197967529296875 +12687 -0.35552978515625 +12688 -0.247894287109375 +12689 -0.441925048828125 +12690 -0.26702880859375 +12691 -0.473846435546875 +12692 -0.262939453125 +12693 -0.464813232421875 +12694 -0.238006591796875 +12695 -0.419097900390625 +12696 -0.19085693359375 +12697 -0.334320068359375 +12698 -0.131317138671875 +12699 -0.227935791015625 +12700 -0.072723388671875 +12701 -0.12347412109375 +12702 -0.018829345703125 +12703 -0.02764892578125 +12704 0.0406494140625 +12705 0.077667236328125 +12706 0.117523193359375 +12707 0.2132568359375 +12708 0.217315673828125 +12709 0.38885498046875 +12710 0.32769775390625 +12711 0.582794189453125 +12712 0.41400146484375 +12713 0.734039306640625 +12714 0.45208740234375 +12715 0.800140380859375 +12716 0.4403076171875 +12717 0.7783203125 +12718 0.376708984375 +12719 0.6651611328125 +12720 0.260711669921875 +12721 0.45965576171875 +12722 0.113525390625 +12723 0.199188232421875 +12724 -0.027679443359375 +12725 -0.050689697265625 +12726 -0.13055419921875 +12727 -0.23297119140625 +12728 -0.185211181640625 +12729 -0.33013916015625 +12730 -0.206512451171875 +12731 -0.368408203125 +12732 -0.21221923828125 +12733 -0.378936767578125 +12734 -0.21099853515625 +12735 -0.376983642578125 +12736 -0.212615966796875 +12737 -0.37969970703125 +12738 -0.21954345703125 +12739 -0.391510009765625 +12740 -0.216400146484375 +12741 -0.385345458984375 +12742 -0.19219970703125 +12743 -0.3419189453125 +12744 -0.15924072265625 +12745 -0.28289794921875 +12746 -0.14208984375 +12747 -0.251617431640625 +12748 -0.150970458984375 +12749 -0.266143798828125 +12750 -0.155670166015625 +12751 -0.273345947265625 +12752 -0.124114990234375 +12753 -0.216796875 +12754 -0.074310302734375 +12755 -0.128265380859375 +12756 -0.040557861328125 +12757 -0.068145751953125 +12758 -0.02655029296875 +12759 -0.0430908203125 +12760 -0.01605224609375 +12761 -0.024444580078125 +12762 0.0096435546875 +12763 0.020721435546875 +12764 0.0687255859375 +12765 0.124481201171875 +12766 0.144744873046875 +12767 0.25787353515625 +12768 0.213958740234375 +12769 0.379119873046875 +12770 0.271636962890625 +12771 0.47991943359375 +12772 0.29949951171875 +12773 0.5281982421875 +12774 0.290283203125 +12775 0.511138916015625 +12776 0.259552001953125 +12777 0.456207275390625 +12778 0.232330322265625 +12779 0.407470703125 +12780 0.21923828125 +12781 0.383758544921875 +12782 0.204254150390625 +12783 0.35687255859375 +12784 0.178863525390625 +12785 0.31182861328125 +12786 0.14434814453125 +12787 0.250885009765625 +12788 0.095794677734375 +12789 0.1654052734375 +12790 0.021759033203125 +12791 0.035247802734375 +12792 -0.079132080078125 +12793 -0.142059326171875 +12794 -0.1893310546875 +12795 -0.33563232421875 +12796 -0.3026123046875 +12797 -0.5345458984375 +12798 -0.409332275390625 +12799 -0.72186279296875 +12800 -0.474395751953125 +12801 -0.836669921875 +12802 -0.470855712890625 +12803 -0.8326416015625 +12804 -0.410552978515625 +12805 -0.7296142578125 +12806 -0.326019287109375 +12807 -0.582550048828125 +12808 -0.24591064453125 +12809 -0.440093994140625 +12810 -0.18292236328125 +12811 -0.324310302734375 +12812 -0.116241455078125 +12813 -0.20147705078125 +12814 -0.029205322265625 +12815 -0.044647216796875 +12816 0.053314208984375 +12817 0.103973388671875 +12818 0.106475830078125 +12819 0.202392578125 +12820 0.138916015625 +12821 0.264495849609375 +12822 0.180084228515625 +12823 0.338897705078125 +12824 0.24102783203125 +12825 0.443817138671875 +12826 0.301300048828125 +12827 0.545074462890625 +12828 0.34564208984375 +12829 0.6173095703125 +12830 0.369140625 +12831 0.6524658203125 +12832 0.379302978515625 +12833 0.66339111328125 +12834 0.3795166015625 +12835 0.6561279296875 +12836 0.355133056640625 +12837 0.606781005859375 +12838 0.29736328125 +12839 0.501190185546875 +12840 0.21392822265625 +12841 0.352783203125 +12842 0.113525390625 +12843 0.176544189453125 +12844 -0.008514404296875 +12845 -0.034820556640625 +12846 -0.1385498046875 +12847 -0.258209228515625 +12848 -0.24609375 +12849 -0.44244384765625 +12850 -0.323944091796875 +12851 -0.5753173828125 +12852 -0.36932373046875 +12853 -0.65203857421875 +12854 -0.3636474609375 +12855 -0.641632080078125 +12856 -0.31768798828125 +12857 -0.562164306640625 +12858 -0.257965087890625 +12859 -0.458038330078125 +12860 -0.197052001953125 +12861 -0.350555419921875 +12862 -0.147216796875 +12863 -0.260528564453125 +12864 -0.110687255859375 +12865 -0.192108154296875 +12866 -0.085235595703125 +12867 -0.141937255859375 +12868 -0.06585693359375 +12869 -0.1021728515625 +12870 -0.04638671875 +12871 -0.062896728515625 +12872 -0.019317626953125 +12873 -0.011932373046875 +12874 0.022796630859375 +12875 0.062835693359375 +12876 0.072479248046875 +12877 0.148712158203125 +12878 0.127410888671875 +12879 0.241729736328125 +12880 0.191925048828125 +12881 0.34912109375 +12882 0.25787353515625 +12883 0.457305908203125 +12884 0.311737060546875 +12885 0.54388427734375 +12886 0.331817626953125 +12887 0.5728759765625 +12888 0.295318603515625 +12889 0.506591796875 +12890 0.20574951171875 +12891 0.351226806640625 +12892 0.08673095703125 +12893 0.146514892578125 +12894 -0.030548095703125 +12895 -0.05523681640625 +12896 -0.123626708984375 +12897 -0.21624755859375 +12898 -0.19171142578125 +12899 -0.334930419921875 +12900 -0.22998046875 +12901 -0.402984619140625 +12902 -0.2510986328125 +12903 -0.4412841796875 +12904 -0.28271484375 +12905 -0.49578857421875 +12906 -0.321075439453125 +12907 -0.5601806640625 +12908 -0.345947265625 +12909 -0.600738525390625 +12910 -0.33734130859375 +12911 -0.584228515625 +12912 -0.2763671875 +12913 -0.47930908203125 +12914 -0.158905029296875 +12915 -0.27935791015625 +12916 0.00042724609375 +12917 -0.0089111328125 +12918 0.16387939453125 +12919 0.268798828125 +12920 0.2890625 +12921 0.482818603515625 +12922 0.358489990234375 +12923 0.60369873046875 +12924 0.383697509765625 +12925 0.650421142578125 +12926 0.38946533203125 +12927 0.66400146484375 +12928 0.3741455078125 +12929 0.6414794921875 +12930 0.33160400390625 +12931 0.572540283203125 +12932 0.286468505859375 +12933 0.498138427734375 +12934 0.25146484375 +12935 0.439453125 +12936 0.213958740234375 +12937 0.375518798828125 +12938 0.154815673828125 +12939 0.274505615234375 +12940 0.057342529296875 +12941 0.1087646484375 +12942 -0.065185546875 +12943 -0.099395751953125 +12944 -0.193878173828125 +12945 -0.3182373046875 +12946 -0.32958984375 +12947 -0.5489501953125 +12948 -0.461822509765625 +12949 -0.7738037109375 +12950 -0.5589599609375 +12951 -0.86383056640625 +12952 -0.601165771484375 +12953 -0.870391845703125 +12954 -0.599212646484375 +12955 -0.86895751953125 +12956 -0.56103515625 +12957 -0.861053466796875 +12958 -0.476318359375 +12959 -0.765869140625 +12960 -0.33831787109375 +12961 -0.5301513671875 +12962 -0.151275634765625 +12963 -0.214691162109375 +12964 0.05902099609375 +12965 0.137359619140625 +12966 0.2618408203125 +12967 0.474822998046875 +12968 0.43597412109375 +12969 0.76239013671875 +12970 0.565338134765625 +12971 0.867462158203125 +12972 0.65032958984375 +12973 0.870361328125 +12974 0.684112548828125 +12975 0.86480712890625 +12976 0.670013427734375 +12977 0.831817626953125 +12978 0.622772216796875 +12979 0.677581787109375 +12980 0.545928955078125 +12981 0.495880126953125 +12982 0.45074462890625 +12983 0.30767822265625 +12984 0.33856201171875 +12985 0.116180419921875 +12986 0.190399169921875 +12987 -0.110748291015625 +12988 0.002105712890625 +12989 -0.381805419921875 +12990 -0.200653076171875 +12991 -0.6572265625 +12992 -0.381988525390625 +12993 -0.857421875 +12994 -0.5162353515625 +12995 -0.870391845703125 +12996 -0.59918212890625 +12997 -0.870391845703125 +12998 -0.647064208984375 +12999 -0.86444091796875 +13000 -0.68133544921875 +13001 -0.85723876953125 +13002 -0.69110107421875 +13003 -0.790008544921875 +13004 -0.643890380859375 +13005 -0.62847900390625 +13006 -0.53790283203125 +13007 -0.3956298828125 +13008 -0.392913818359375 +13009 -0.126708984375 +13010 -0.225433349609375 +13011 0.150115966796875 +13012 -0.042510986328125 +13013 0.424041748046875 +13014 0.1396484375 +13015 0.670623779296875 +13016 0.297821044921875 +13017 0.854522705078125 +13018 0.421417236328125 +13019 0.866485595703125 +13020 0.501220703125 +13021 0.86920166015625 +13022 0.548187255859375 +13023 0.8653564453125 +13024 0.570404052734375 +13025 0.857147216796875 +13026 0.566192626953125 +13027 0.766845703125 +13028 0.5386962890625 +13029 0.628509521484375 +13030 0.483978271484375 +13031 0.462127685546875 +13032 0.417572021484375 +13033 0.297210693359375 +13034 0.346954345703125 +13035 0.14862060546875 +13036 0.258514404296875 +13037 -0.00537109375 +13038 0.156768798828125 +13039 -0.15753173828125 +13040 0.039581298828125 +13041 -0.31304931640625 +13042 -0.101409912109375 +13043 -0.48876953125 +13044 -0.238067626953125 +13045 -0.6416015625 +13046 -0.3555908203125 +13047 -0.751373291015625 +13048 -0.46783447265625 +13049 -0.84619140625 +13050 -0.566009521484375 +13051 -0.861297607421875 +13052 -0.630279541015625 +13053 -0.863250732421875 +13054 -0.6417236328125 +13055 -0.856597900390625 +13056 -0.608306884765625 +13057 -0.7498779296875 +13058 -0.565582275390625 +13059 -0.624542236328125 +13060 -0.49896240234375 +13061 -0.47808837890625 +13062 -0.371246337890625 +13063 -0.253387451171875 +13064 -0.211029052734375 +13065 0.003692626953125 +13066 -0.06121826171875 +13067 0.2257080078125 +13068 0.086456298828125 +13069 0.427154541015625 +13070 0.252777099609375 +13071 0.643218994140625 +13072 0.431976318359375 +13073 0.855926513671875 +13074 0.58770751953125 +13075 0.870361328125 +13076 0.6888427734375 +13077 0.870361328125 +13078 0.74005126953125 +13079 0.862762451171875 +13080 0.739532470703125 +13081 0.79669189453125 +13082 0.68133544921875 +13083 0.595794677734375 +13084 0.583831787109375 +13085 0.362152099609375 +13086 0.464630126953125 +13087 0.1270751953125 +13088 0.336944580078125 +13089 -0.086944580078125 +13090 0.20184326171875 +13091 -0.2784423828125 +13092 0.037109375 +13093 -0.484832763671875 +13094 -0.169586181640625 +13095 -0.729583740234375 +13096 -0.38653564453125 +13097 -0.86688232421875 +13098 -0.573944091796875 +13099 -0.870391845703125 +13100 -0.728851318359375 +13101 -0.86859130859375 +13102 -0.85009765625 +13103 -0.86279296875 +13104 -0.861114501953125 +13105 -0.817962646484375 +13106 -0.85894775390625 +13107 -0.6116943359375 +13108 -0.78582763671875 +13109 -0.3128662109375 +13110 -0.608367919921875 +13111 0.039398193359375 +13112 -0.375335693359375 +13113 0.422821044921875 +13114 -0.107696533203125 +13115 0.805145263671875 +13116 0.151580810546875 +13117 0.870361328125 +13118 0.366607666015625 +13119 0.870361328125 +13120 0.53009033203125 +13121 0.860015869140625 +13122 0.637237548828125 +13123 0.727935791015625 +13124 0.68450927734375 +13125 0.48114013671875 +13126 0.687225341796875 +13127 0.2059326171875 +13128 0.659698486328125 +13129 -0.06103515625 +13130 0.6082763671875 +13131 -0.29913330078125 +13132 0.5238037109375 +13133 -0.516204833984375 +13134 0.396575927734375 +13135 -0.7252197265625 +13136 0.24237060546875 +13137 -0.85980224609375 +13138 0.08294677734375 +13139 -0.870391845703125 +13140 -0.0628662109375 +13141 -0.870391845703125 +13142 -0.164154052734375 +13143 -0.858062744140625 +13144 -0.218109130859375 +13145 -0.673004150390625 +13146 -0.257720947265625 +13147 -0.42694091796875 +13148 -0.31085205078125 +13149 -0.2100830078125 +13150 -0.376007080078125 +13151 -0.0362548828125 +13152 -0.43463134765625 +13153 0.10943603515625 +13154 -0.474029541015625 +13155 0.23516845703125 +13156 -0.467987060546875 +13157 0.373687744140625 +13158 -0.41766357421875 +13159 0.517791748046875 +13160 -0.362884521484375 +13161 0.602783203125 +13162 -0.300445556640625 +13163 0.635711669921875 +13164 -0.209381103515625 +13165 0.655181884765625 +13166 -0.09613037109375 +13167 0.65948486328125 +13168 0.033966064453125 +13169 0.651275634765625 +13170 0.165191650390625 +13171 0.61846923828125 +13172 0.27392578125 +13173 0.53753662109375 +13174 0.3485107421875 +13175 0.404144287109375 +13176 0.382568359375 +13177 0.22186279296875 +13178 0.37664794921875 +13179 0.003997802734375 +13180 0.342010498046875 +13181 -0.22100830078125 +13182 0.291595458984375 +13183 -0.42449951171875 +13184 0.23883056640625 +13185 -0.579833984375 +13186 0.210723876953125 +13187 -0.641876220703125 +13188 0.203125 +13189 -0.6177978515625 +13190 0.17529296875 +13191 -0.575531005859375 +13192 0.123992919921875 +13193 -0.526336669921875 +13194 0.082183837890625 +13195 -0.42645263671875 +13196 0.067413330078125 +13197 -0.2581787109375 +13198 0.056915283203125 +13199 -0.068695068359375 +13200 0.026641845703125 +13201 0.09222412109375 +13202 -0.011322021484375 +13203 0.232147216796875 +13204 -0.05035400390625 +13205 0.3509521484375 +13206 -0.10894775390625 +13207 0.410064697265625 +13208 -0.20550537109375 +13209 0.372955322265625 +13210 -0.32666015625 +13211 0.2554931640625 +13212 -0.439361572265625 +13213 0.10711669921875 +13214 -0.531219482421875 +13215 -0.052886962890625 +13216 -0.579345703125 +13217 -0.186279296875 +13218 -0.548492431640625 +13219 -0.23291015625 +13220 -0.45318603515625 +13221 -0.209442138671875 +13222 -0.335235595703125 +13223 -0.174163818359375 +13224 -0.200042724609375 +13225 -0.126739501953125 +13226 -0.0416259765625 +13227 -0.048126220703125 +13228 0.121917724609375 +13229 0.0426025390625 +13230 0.260894775390625 +13231 0.10748291015625 +13232 0.36669921875 +13233 0.1409912109375 +13234 0.469207763671875 +13235 0.19708251953125 +13236 0.56396484375 +13237 0.273651123046875 +13238 0.615509033203125 +13239 0.31768798828125 +13240 0.630706787109375 +13241 0.341094970703125 +13242 0.62548828125 +13243 0.368011474609375 +13244 0.5853271484375 +13245 0.37249755859375 +13246 0.479156494140625 +13247 0.30072021484375 +13248 0.3101806640625 +13249 0.1517333984375 +13250 0.12060546875 +13251 -0.01470947265625 +13252 -0.078155517578125 +13253 -0.1883544921875 +13254 -0.283355712890625 +13255 -0.372711181640625 +13256 -0.456146240234375 +13257 -0.51397705078125 +13258 -0.56658935546875 +13259 -0.57177734375 +13260 -0.606781005859375 +13261 -0.53948974609375 +13262 -0.585174560546875 +13263 -0.43511962890625 +13264 -0.523590087890625 +13265 -0.2962646484375 +13266 -0.44525146484375 +13267 -0.161102294921875 +13268 -0.359100341796875 +13269 -0.0435791015625 +13270 -0.2637939453125 +13271 0.060394287109375 +13272 -0.17034912109375 +13273 0.13665771484375 +13274 -0.091217041015625 +13275 0.170135498046875 +13276 -0.026947021484375 +13277 0.16552734375 +13278 0.040252685546875 +13279 0.15728759765625 +13280 0.1097412109375 +13281 0.150787353515625 +13282 0.1622314453125 +13283 0.12200927734375 +13284 0.19976806640625 +13285 0.080108642578125 +13286 0.235595703125 +13287 0.05126953125 +13288 0.284393310546875 +13289 0.062896728515625 +13290 0.33013916015625 +13291 0.09271240234375 +13292 0.341644287109375 +13293 0.092987060546875 +13294 0.328094482421875 +13295 0.07855224609375 +13296 0.299591064453125 +13297 0.06427001953125 +13298 0.2479248046875 +13299 0.0347900390625 +13300 0.174072265625 +13301 -0.01171875 +13302 0.09295654296875 +13303 -0.056060791015625 +13304 0.03472900390625 +13305 -0.055511474609375 +13306 0.00250244140625 +13307 -0.010467529296875 +13308 -0.034454345703125 +13309 0.02508544921875 +13310 -0.089019775390625 +13311 0.025665283203125 +13312 -0.14166259765625 +13313 0.017333984375 +13314 -0.18902587890625 +13315 0.00189208984375 +13316 -0.236572265625 +13317 -0.03173828125 +13318 -0.2755126953125 +13319 -0.071502685546875 +13320 -0.3172607421875 +13321 -0.13543701171875 +13322 -0.359954833984375 +13323 -0.219970703125 +13324 -0.38861083984375 +13325 -0.300506591796875 +13326 -0.404388427734375 +13327 -0.376312255859375 +13328 -0.389068603515625 +13329 -0.416107177734375 +13330 -0.31341552734375 +13331 -0.371124267578125 +13332 -0.180694580078125 +13333 -0.242279052734375 +13334 -0.019744873046875 +13335 -0.069732666015625 +13336 0.153167724609375 +13337 0.125640869140625 +13338 0.315399169921875 +13339 0.31268310546875 +13340 0.4412841796875 +13341 0.45501708984375 +13342 0.53057861328125 +13343 0.554779052734375 +13344 0.581390380859375 +13345 0.61065673828125 +13346 0.5855712890625 +13347 0.610931396484375 +13348 0.527557373046875 +13349 0.531463623046875 +13350 0.41839599609375 +13351 0.3883056640625 +13352 0.293853759765625 +13353 0.23468017578125 +13354 0.17156982421875 +13355 0.095245361328125 +13356 0.070343017578125 +13357 -0.00396728515625 +13358 0.001708984375 +13359 -0.04852294921875 +13360 -0.04290771484375 +13361 -0.055145263671875 +13362 -0.095123291015625 +13363 -0.0758056640625 +13364 -0.171173095703125 +13365 -0.138702392578125 +13366 -0.2467041015625 +13367 -0.209197998046875 +13368 -0.321380615234375 +13369 -0.289031982421875 +13370 -0.394622802734375 +13371 -0.37884521484375 +13372 -0.451324462890625 +13373 -0.456329345703125 +13374 -0.48809814453125 +13375 -0.51641845703125 +13376 -0.47943115234375 +13377 -0.519287109375 +13378 -0.421783447265625 +13379 -0.458251953125 +13380 -0.34979248046875 +13381 -0.384796142578125 +13382 -0.281097412109375 +13383 -0.323699951171875 +13384 -0.21368408203125 +13385 -0.269287109375 +13386 -0.132293701171875 +13387 -0.1951904296875 +13388 -0.037841796875 +13389 -0.100006103515625 +13390 0.050445556640625 +13391 -0.01055908203125 +13392 0.150665283203125 +13393 0.1033935546875 +13394 0.2662353515625 +13395 0.24908447265625 +13396 0.361480712890625 +13397 0.373199462890625 +13398 0.42431640625 +13399 0.45806884765625 +13400 0.4595947265625 +13401 0.511474609375 +13402 0.48828125 +13403 0.565399169921875 +13404 0.505401611328125 +13405 0.61138916015625 +13406 0.473052978515625 +13407 0.5897216796875 +13408 0.385986328125 +13409 0.4906005859375 +13410 0.256927490234375 +13411 0.33148193359375 +13412 0.110382080078125 +13413 0.147796630859375 +13414 -0.0250244140625 +13415 -0.01873779296875 +13416 -0.129730224609375 +13417 -0.140289306640625 +13418 -0.1861572265625 +13419 -0.191986083984375 +13420 -0.199981689453125 +13421 -0.184295654296875 +13422 -0.19927978515625 +13423 -0.161834716796875 +13424 -0.210723876953125 +13425 -0.166595458984375 +13426 -0.230987548828125 +13427 -0.19390869140625 +13428 -0.24749755859375 +13429 -0.22442626953125 +13430 -0.274658203125 +13431 -0.279754638671875 +13432 -0.299530029296875 +13433 -0.3389892578125 +13434 -0.2919921875 +13435 -0.3543701171875 +13436 -0.267578125 +13437 -0.348175048828125 +13438 -0.2310791015625 +13439 -0.32598876953125 +13440 -0.164520263671875 +13441 -0.2581787109375 +13442 -0.065887451171875 +13443 -0.139801025390625 +13444 0.05419921875 +13445 0.014617919921875 +13446 0.155242919921875 +13447 0.144378662109375 +13448 0.217926025390625 +13449 0.221038818359375 +13450 0.258636474609375 +13451 0.27069091796875 +13452 0.27752685546875 +13453 0.294036865234375 +13454 0.2879638671875 +13455 0.311767578125 +13456 0.30010986328125 +13457 0.339141845703125 +13458 0.30419921875 +13459 0.360260009765625 +13460 0.2913818359375 +13461 0.360504150390625 +13462 0.241455078125 +13463 0.308380126953125 +13464 0.140533447265625 +13465 0.18170166015625 +13466 0.0057373046875 +13467 0.0047607421875 +13468 -0.13092041015625 +13469 -0.17559814453125 +13470 -0.238677978515625 +13471 -0.3143310546875 +13472 -0.28778076171875 +13473 -0.36785888671875 +13474 -0.295013427734375 +13475 -0.36248779296875 +13476 -0.289947509765625 +13477 -0.343536376953125 +13478 -0.266265869140625 +13479 -0.3018798828125 +13480 -0.219757080078125 +13481 -0.231414794921875 +13482 -0.140899658203125 +13483 -0.117645263671875 +13484 -0.05145263671875 +13485 0.007049560546875 +13486 0.011810302734375 +13487 0.087982177734375 +13488 0.057769775390625 +13489 0.13946533203125 +13490 0.094207763671875 +13491 0.17425537109375 +13492 0.117584228515625 +13493 0.188201904296875 +13494 0.120452880859375 +13495 0.171234130859375 +13496 0.0987548828125 +13497 0.118438720703125 +13498 0.06988525390625 +13499 0.05706787109375 +13500 0.03466796875 +13501 -0.010711669921875 +13502 -0.011688232421875 +13503 -0.0914306640625 +13504 -0.05438232421875 +13505 -0.162322998046875 +13506 -0.074432373046875 +13507 -0.194549560546875 +13508 -0.046051025390625 +13509 -0.1492919921875 +13510 0.034149169921875 +13511 -0.02166748046875 +13512 0.12384033203125 +13513 0.124053955078125 +13514 0.172515869140625 +13515 0.211151123046875 +13516 0.181304931640625 +13517 0.240447998046875 +13518 0.170928955078125 +13519 0.242218017578125 +13520 0.148223876953125 +13521 0.2257080078125 +13522 0.1160888671875 +13523 0.194366455078125 +13524 0.053436279296875 +13525 0.115509033203125 +13526 -0.0234375 +13527 0.0128173828125 +13528 -0.074371337890625 +13529 -0.053802490234375 +13530 -0.116455078125 +13531 -0.110626220703125 +13532 -0.177337646484375 +13533 -0.199493408203125 +13534 -0.239715576171875 +13535 -0.29437255859375 +13536 -0.261810302734375 +13537 -0.33221435546875 +13538 -0.221771240234375 +13539 -0.27972412109375 +13540 -0.152099609375 +13541 -0.185333251953125 +13542 -0.10577392578125 +13543 -0.128204345703125 +13544 -0.088134765625 +13545 -0.115692138671875 +13546 -0.078948974609375 +13547 -0.116455078125 +13548 -0.06243896484375 +13549 -0.105926513671875 +13550 -0.01910400390625 +13551 -0.053955078125 +13552 0.056793212890625 +13553 0.048797607421875 +13554 0.134979248046875 +13555 0.157318115234375 +13556 0.17559814453125 +13557 0.212005615234375 +13558 0.182159423828125 +13559 0.218475341796875 +13560 0.194793701171875 +13561 0.23724365234375 +13562 0.2381591796875 +13563 0.30535888671875 +13564 0.284820556640625 +13565 0.38128662109375 +13566 0.2947998046875 +13567 0.404449462890625 +13568 0.28204345703125 +13569 0.3944091796875 +13570 0.27239990234375 +13571 0.3885498046875 +13572 0.249267578125 +13573 0.362640380859375 +13574 0.18280029296875 +13575 0.27362060546875 +13576 0.070068359375 +13577 0.11712646484375 +13578 -0.052642822265625 +13579 -0.054901123046875 +13580 -0.14935302734375 +13581 -0.19085693359375 +13582 -0.216522216796875 +13583 -0.28570556640625 +13584 -0.253997802734375 +13585 -0.339263916015625 +13586 -0.279937744140625 +13587 -0.3775634765625 +13588 -0.3258056640625 +13589 -0.445709228515625 +13590 -0.38568115234375 +13591 -0.535064697265625 +13592 -0.44818115234375 +13593 -0.629058837890625 +13594 -0.49249267578125 +13595 -0.697601318359375 +13596 -0.49322509765625 +13597 -0.70391845703125 +13598 -0.446746826171875 +13599 -0.6424560546875 +13600 -0.33795166015625 +13601 -0.491241455078125 +13602 -0.177734375 +13603 -0.265716552734375 +13604 -0.00653076171875 +13605 -0.023712158203125 +13606 0.15252685546875 +13607 0.201751708984375 +13608 0.27508544921875 +13609 0.375823974609375 +13610 0.35174560546875 +13611 0.485076904296875 +13612 0.409881591796875 +13613 0.56884765625 +13614 0.454864501953125 +13615 0.634765625 +13616 0.455291748046875 +13617 0.63763427734375 +13618 0.4033203125 +13619 0.5660400390625 +13620 0.3353271484375 +13621 0.4720458984375 +13622 0.287109375 +13623 0.40692138671875 +13624 0.263824462890625 +13625 0.3778076171875 +13626 0.260223388671875 +13627 0.376953125 +13628 0.25396728515625 +13629 0.371978759765625 +13630 0.2105712890625 +13631 0.313140869140625 +13632 0.1190185546875 +13633 0.184417724609375 +13634 -0.002899169921875 +13635 0.011199951171875 +13636 -0.130462646484375 +13637 -0.171051025390625 +13638 -0.246337890625 +13639 -0.33740234375 +13640 -0.339447021484375 +13641 -0.47198486328125 +13642 -0.39984130859375 +13643 -0.560394287109375 +13644 -0.4122314453125 +13645 -0.58056640625 +13646 -0.38720703125 +13647 -0.54754638671875 +13648 -0.357757568359375 +13649 -0.508575439453125 +13650 -0.321136474609375 +13651 -0.459503173828125 +13652 -0.273345947265625 +13653 -0.394378662109375 +13654 -0.241943359375 +13655 -0.35260009765625 +13656 -0.211395263671875 +13657 -0.31170654296875 +13658 -0.130096435546875 +13659 -0.197418212890625 +13660 0.0030517578125 +13661 -0.007965087890625 +13662 0.153778076171875 +13663 0.207489013671875 +13664 0.294403076171875 +13665 0.409210205078125 +13666 0.407470703125 +13667 0.57208251953125 +13668 0.47198486328125 +13669 0.66595458984375 +13670 0.4656982421875 +13671 0.65875244140625 +13672 0.4005126953125 +13673 0.56744384765625 +13674 0.303955078125 +13675 0.431396484375 +13676 0.206634521484375 +13677 0.29443359375 +13678 0.126678466796875 +13679 0.182464599609375 +13680 0.04205322265625 +13681 0.06365966796875 +13682 -0.056884765625 +13683 -0.075958251953125 +13684 -0.137359619140625 +13685 -0.189422607421875 +13686 -0.1959228515625 +13687 -0.271942138671875 +13688 -0.245758056640625 +13689 -0.342529296875 +13690 -0.2611083984375 +13691 -0.364166259765625 +13692 -0.23529052734375 +13693 -0.327239990234375 +13694 -0.19976806640625 +13695 -0.2769775390625 +13696 -0.182647705078125 +13697 -0.253692626953125 +13698 -0.1744384765625 +13699 -0.24365234375 +13700 -0.1414794921875 +13701 -0.1983642578125 +13702 -0.082733154296875 +13703 -0.116241455078125 +13704 -0.025787353515625 +13705 -0.036834716796875 +13706 0.0257568359375 +13707 0.034881591796875 +13708 0.066497802734375 +13709 0.09124755859375 +13710 0.080078125 +13711 0.10888671875 +13712 0.0926513671875 +13713 0.125518798828125 +13714 0.115753173828125 +13715 0.15771484375 +13716 0.13043212890625 +13717 0.17828369140625 +13718 0.12542724609375 +13719 0.17108154296875 +13720 0.09649658203125 +13721 0.129974365234375 +13722 0.062744140625 +13723 0.082427978515625 +13724 0.023712158203125 +13725 0.027679443359375 +13726 -0.0423583984375 +13727 -0.065643310546875 +13728 -0.10882568359375 +13729 -0.15936279296875 +13730 -0.14752197265625 +13731 -0.21307373046875 +13732 -0.163848876953125 +13733 -0.234649658203125 +13734 -0.14111328125 +13735 -0.2001953125 +13736 -0.0858154296875 +13737 -0.119171142578125 +13738 -0.02099609375 +13739 -0.024749755859375 +13740 0.055267333984375 +13741 0.085784912109375 +13742 0.119110107421875 +13743 0.178131103515625 +13744 0.14501953125 +13745 0.215576171875 +13746 0.142242431640625 +13747 0.211456298828125 +13748 0.117401123046875 +13749 0.17523193359375 +13750 0.085662841796875 +13751 0.128753662109375 +13752 0.06781005859375 +13753 0.1019287109375 +13754 0.049591064453125 +13755 0.0743408203125 +13756 0.029052734375 +13757 0.04327392578125 +13758 0.026611328125 +13759 0.038177490234375 +13760 0.054168701171875 +13761 0.076263427734375 +13762 0.100189208984375 +13763 0.14105224609375 +13764 0.132568359375 +13765 0.186431884765625 +13766 0.13482666015625 +13767 0.188812255859375 +13768 0.100555419921875 +13769 0.1390380859375 +13770 0.033050537109375 +13771 0.041778564453125 +13772 -0.05133056640625 +13773 -0.079437255859375 +13774 -0.148956298828125 +13775 -0.219390869140625 +13776 -0.252655029296875 +13777 -0.367828369140625 +13778 -0.34161376953125 +13779 -0.494873046875 +13780 -0.385009765625 +13781 -0.556243896484375 +13782 -0.352691650390625 +13783 -0.508697509765625 +13784 -0.2608642578125 +13785 -0.3756103515625 +13786 -0.152618408203125 +13787 -0.218902587890625 +13788 -0.045379638671875 +13789 -0.063751220703125 +13790 0.06201171875 +13791 0.091552734375 +13792 0.161956787109375 +13793 0.23602294921875 +13794 0.235931396484375 +13795 0.342987060546875 +13796 0.27197265625 +13797 0.39520263671875 +13798 0.267791748046875 +13799 0.389373779296875 +13800 0.2225341796875 +13801 0.324249267578125 +13802 0.153076171875 +13803 0.224090576171875 +13804 0.084014892578125 +13805 0.124267578125 +13806 0.023834228515625 +13807 0.037078857421875 +13808 -0.008392333984375 +13809 -0.010101318359375 +13810 -0.01422119140625 +13811 -0.019439697265625 +13812 -0.015869140625 +13813 -0.022796630859375 +13814 -0.000396728515625 +13815 -0.001556396484375 +13816 0.040496826171875 +13817 0.056304931640625 +13818 0.07611083984375 +13819 0.106719970703125 +13820 0.069671630859375 +13821 0.096893310546875 +13822 0.0322265625 +13823 0.042694091796875 +13824 -0.010223388671875 +13825 -0.018035888671875 +13826 -0.0509033203125 +13827 -0.07586669921875 +13828 -0.081329345703125 +13829 -0.11944580078125 +13830 -0.109619140625 +13831 -0.15972900390625 +13832 -0.140167236328125 +13833 -0.202606201171875 +13834 -0.173370361328125 +13835 -0.24859619140625 +13836 -0.2147216796875 +13837 -0.30517578125 +13838 -0.256805419921875 +13839 -0.36212158203125 +13840 -0.279205322265625 +13841 -0.39141845703125 +13842 -0.254302978515625 +13843 -0.35528564453125 +13844 -0.17926025390625 +13845 -0.249969482421875 +13846 -0.066680908203125 +13847 -0.092864990234375 +13848 0.063934326171875 +13849 0.08905029296875 +13850 0.168609619140625 +13851 0.2352294921875 +13852 0.2279052734375 +13853 0.318817138671875 +13854 0.255615234375 +13855 0.358642578125 +13856 0.246734619140625 +13857 0.347747802734375 +13858 0.200927734375 +13859 0.28564453125 +13860 0.155242919921875 +13861 0.223175048828125 +13862 0.136199951171875 +13863 0.196746826171875 +13864 0.124481201171875 +13865 0.179840087890625 +13866 0.107757568359375 +13867 0.155548095703125 +13868 0.1058349609375 +13869 0.151214599609375 +13870 0.1114501953125 +13871 0.156951904296875 +13872 0.09466552734375 +13873 0.13177490234375 +13874 0.07366943359375 +13875 0.100799560546875 +13876 0.065185546875 +13877 0.087127685546875 +13878 0.04302978515625 +13879 0.05487060546875 +13880 -0.002349853515625 +13881 -0.009002685546875 +13882 -0.07061767578125 +13883 -0.10400390625 +13884 -0.16131591796875 +13885 -0.229400634765625 +13886 -0.252899169921875 +13887 -0.35552978515625 +13888 -0.31585693359375 +13889 -0.441925048828125 +13890 -0.3394775390625 +13891 -0.473846435546875 +13892 -0.33355712890625 +13893 -0.464813232421875 +13894 -0.3011474609375 +13895 -0.419097900390625 +13896 -0.240447998046875 +13897 -0.334320068359375 +13898 -0.16412353515625 +13899 -0.227935791015625 +13900 -0.089263916015625 +13901 -0.12347412109375 +13902 -0.020660400390625 +13903 -0.02764892578125 +13904 0.054931640625 +13905 0.077667236328125 +13906 0.152679443359375 +13907 0.2132568359375 +13908 0.279693603515625 +13909 0.38885498046875 +13910 0.420257568359375 +13911 0.582794189453125 +13912 0.52996826171875 +13913 0.734039306640625 +13914 0.57794189453125 +13915 0.800140380859375 +13916 0.5621337890625 +13917 0.7783203125 +13918 0.480072021484375 +13919 0.6651611328125 +13920 0.331024169921875 +13921 0.45965576171875 +13922 0.14215087890625 +13923 0.199188232421875 +13924 -0.038848876953125 +13925 -0.050689697265625 +13926 -0.170562744140625 +13927 -0.23297119140625 +13928 -0.24029541015625 +13929 -0.33013916015625 +13930 -0.26715087890625 +13931 -0.368408203125 +13932 -0.27386474609375 +13933 -0.378936767578125 +13934 -0.271636962890625 +13935 -0.376983642578125 +13936 -0.27301025390625 +13937 -0.37969970703125 +13938 -0.281219482421875 +13939 -0.391510009765625 +13940 -0.276580810546875 +13941 -0.385345458984375 +13942 -0.245025634765625 +13943 -0.3419189453125 +13944 -0.202301025390625 +13945 -0.28289794921875 +13946 -0.179962158203125 +13947 -0.251617431640625 +13948 -0.19110107421875 +13949 -0.266143798828125 +13950 -0.197052001953125 +13951 -0.273345947265625 +13952 -0.15667724609375 +13953 -0.216796875 +13954 -0.093017578125 +13955 -0.128265380859375 +13956 -0.050018310546875 +13957 -0.068145751953125 +13958 -0.032501220703125 +13959 -0.0430908203125 +13960 -0.019561767578125 +13961 -0.024444580078125 +13962 0.0128173828125 +13963 0.020721435546875 +13964 0.087982177734375 +13965 0.124481201171875 +13966 0.184844970703125 +13967 0.25787353515625 +13968 0.27301025390625 +13969 0.379119873046875 +13970 0.346466064453125 +13971 0.47991943359375 +13972 0.3818359375 +13973 0.5281982421875 +13974 0.369781494140625 +13975 0.511138916015625 +13976 0.330291748046875 +13977 0.456207275390625 +13978 0.29541015625 +13979 0.407470703125 +13980 0.27880859375 +13981 0.383758544921875 +13982 0.259918212890625 +13983 0.35687255859375 +13984 0.227752685546875 +13985 0.31182861328125 +13986 0.1839599609375 +13987 0.250885009765625 +13988 0.1221923828125 +13989 0.1654052734375 +13990 0.027801513671875 +13991 0.035247802734375 +13992 -0.101043701171875 +13993 -0.142059326171875 +13994 -0.241851806640625 +13995 -0.33563232421875 +13996 -0.38665771484375 +13997 -0.5345458984375 +13998 -0.52313232421875 +13999 -0.72186279296875 +14000 -0.606903076171875 +14001 -0.836669921875 +14002 -0.604278564453125 +14003 -0.8326416015625 +14004 -0.5296630859375 +14005 -0.7296142578125 +14006 -0.42303466796875 +14007 -0.582550048828125 +14008 -0.319793701171875 +14009 -0.440093994140625 +14010 -0.235992431640625 +14011 -0.324310302734375 +14012 -0.14703369140625 +14013 -0.20147705078125 +14014 -0.03326416015625 +14015 -0.044647216796875 +14016 0.0745849609375 +14017 0.103973388671875 +14018 0.145965576171875 +14019 0.202392578125 +14020 0.19097900390625 +14021 0.264495849609375 +14022 0.245025634765625 +14023 0.338897705078125 +14024 0.321380615234375 +14025 0.443817138671875 +14026 0.395172119140625 +14027 0.545074462890625 +14028 0.447906494140625 +14029 0.6173095703125 +14030 0.473724365234375 +14031 0.6524658203125 +14032 0.481964111328125 +14033 0.66339111328125 +14034 0.477020263671875 +14035 0.6561279296875 +14036 0.441436767578125 +14037 0.606781005859375 +14038 0.364898681640625 +14039 0.501190185546875 +14040 0.25714111328125 +14041 0.352783203125 +14042 0.12908935546875 +14043 0.176544189453125 +14044 -0.024566650390625 +14045 -0.034820556640625 +14046 -0.18701171875 +14047 -0.258209228515625 +14048 -0.321014404296875 +14049 -0.44244384765625 +14050 -0.417633056640625 +14051 -0.5753173828125 +14052 -0.473419189453125 +14053 -0.65203857421875 +14054 -0.4658203125 +14055 -0.641632080078125 +14056 -0.40802001953125 +14057 -0.562164306640625 +14058 -0.33233642578125 +14059 -0.458038330078125 +14060 -0.254241943359375 +14061 -0.350555419921875 +14062 -0.18890380859375 +14063 -0.260528564453125 +14064 -0.13934326171875 +14065 -0.192108154296875 +14066 -0.103118896484375 +14067 -0.141937255859375 +14068 -0.074493408203125 +14069 -0.1021728515625 +14070 -0.04620361328125 +14071 -0.062896728515625 +14072 -0.009368896484375 +14073 -0.011932373046875 +14074 0.044830322265625 +14075 0.062835693359375 +14076 0.107177734375 +14077 0.148712158203125 +14078 0.1748046875 +14079 0.241729736328125 +14080 0.253265380859375 +14081 0.34912109375 +14082 0.33343505859375 +14083 0.457305908203125 +14084 0.398895263671875 +14085 0.54388427734375 +14086 0.4219970703125 +14087 0.5728759765625 +14088 0.37371826171875 +14089 0.506591796875 +14090 0.258453369140625 +14091 0.351226806640625 +14092 0.106109619140625 +14093 0.146514892578125 +14094 -0.043853759765625 +14095 -0.05523681640625 +14096 -0.1629638671875 +14097 -0.21624755859375 +14098 -0.25018310546875 +14099 -0.334930419921875 +14100 -0.299407958984375 +14101 -0.402984619140625 +14102 -0.326568603515625 +14103 -0.4412841796875 +14104 -0.366668701171875 +14105 -0.49578857421875 +14106 -0.41497802734375 +14107 -0.5601806640625 +14108 -0.445831298828125 +14109 -0.600738525390625 +14110 -0.4339599609375 +14111 -0.584228515625 +14112 -0.355438232421875 +14113 -0.47930908203125 +14114 -0.20513916015625 +14115 -0.27935791015625 +14116 -0.001617431640625 +14117 -0.0089111328125 +14118 0.207183837890625 +14119 0.268798828125 +14120 0.36749267578125 +14121 0.482818603515625 +14122 0.457061767578125 +14123 0.60369873046875 +14124 0.490386962890625 +14125 0.650421142578125 +14126 0.498809814453125 +14127 0.66400146484375 +14128 0.48016357421875 +14129 0.6414794921875 +14130 0.42669677734375 +14131 0.572540283203125 +14132 0.36956787109375 +14133 0.498138427734375 +14134 0.32489013671875 +14135 0.439453125 +14136 0.2767333984375 +14137 0.375518798828125 +14138 0.200836181640625 +14139 0.274505615234375 +14140 0.076141357421875 +14141 0.1087646484375 +14142 -0.080474853515625 +14143 -0.099395751953125 +14144 -0.244964599609375 +14145 -0.3182373046875 +14146 -0.418365478515625 +14147 -0.5489501953125 +14148 -0.5872802734375 +14149 -0.7738037109375 +14150 -0.711578369140625 +14151 -0.86383056640625 +14152 -0.766082763671875 +14153 -0.870391845703125 +14154 -0.76434326171875 +14155 -0.86895751953125 +14156 -0.716400146484375 +14157 -0.861053466796875 +14158 -0.60919189453125 +14159 -0.765869140625 +14160 -0.434173583984375 +14161 -0.5301513671875 +14162 -0.19671630859375 +14163 -0.214691162109375 +14164 0.070465087890625 +14165 0.137359619140625 +14166 0.328399658203125 +14167 0.474822998046875 +14168 0.550140380859375 +14169 0.76239013671875 +14170 0.715240478515625 +14171 0.867462158203125 +14172 0.8240966796875 +14173 0.870361328125 +14174 0.85595703125 +14175 0.86480712890625 +14176 0.851287841796875 +14177 0.831817626953125 +14178 0.792327880859375 +14179 0.677581787109375 +14180 0.695709228515625 +14181 0.495880126953125 +14182 0.5755615234375 +14183 0.30767822265625 +14184 0.433624267578125 +14185 0.116180419921875 +14186 0.245849609375 +14187 -0.110748291015625 +14188 0.0069580078125 +14189 -0.381805419921875 +14190 -0.25048828125 +14191 -0.6572265625 +14192 -0.48101806640625 +14193 -0.857421875 +14194 -0.652008056640625 +14195 -0.870391845703125 +14196 -0.758056640625 +14197 -0.870391845703125 +14198 -0.8197021484375 +14199 -0.86444091796875 +14200 -0.855560302734375 +14201 -0.85723876953125 +14202 -0.85699462890625 +14203 -0.790008544921875 +14204 -0.818389892578125 +14205 -0.62847900390625 +14206 -0.684783935546875 +14207 -0.3956298828125 +14208 -0.5015869140625 +14209 -0.126708984375 +14210 -0.2896728515625 +14211 0.150115966796875 +14212 -0.0579833984375 +14213 0.424041748046875 +14214 0.1729736328125 +14215 0.670623779296875 +14216 0.373748779296875 +14217 0.854522705078125 +14218 0.530914306640625 +14219 0.866485595703125 +14220 0.63275146484375 +14221 0.86920166015625 +14222 0.693084716796875 +14223 0.8653564453125 +14224 0.722137451171875 +14225 0.857147216796875 +14226 0.71771240234375 +14227 0.766845703125 +14228 0.6837158203125 +14229 0.628509521484375 +14230 0.615081787109375 +14231 0.462127685546875 +14232 0.531494140625 +14233 0.297210693359375 +14234 0.442474365234375 +14235 0.14862060546875 +14236 0.3306884765625 +14237 -0.00537109375 +14238 0.201873779296875 +14239 -0.15753173828125 +14240 0.053314208984375 +14241 -0.31304931640625 +14242 -0.125579833984375 +14243 -0.48876953125 +14244 -0.299163818359375 +14245 -0.6416015625 +14246 -0.4486083984375 +14247 -0.751373291015625 +14248 -0.591461181640625 +14249 -0.84619140625 +14250 -0.716552734375 +14251 -0.861297607421875 +14252 -0.7987060546875 +14253 -0.863250732421875 +14254 -0.813934326171875 +14255 -0.856597900390625 +14256 -0.771514892578125 +14257 -0.7498779296875 +14258 -0.7154541015625 +14259 -0.624542236328125 +14260 -0.62908935546875 +14261 -0.47808837890625 +14262 -0.468017578125 +14263 -0.253387451171875 +14264 -0.26702880859375 +14265 0.003692626953125 +14266 -0.078125 +14267 0.2257080078125 +14268 0.108184814453125 +14269 0.427154541015625 +14270 0.316436767578125 +14271 0.643218994140625 +14272 0.539276123046875 +14273 0.855926513671875 +14274 0.73260498046875 +14275 0.870361328125 +14276 0.854949951171875 +14277 0.870361328125 +14278 0.8619384765625 +14279 0.862762451171875 +14280 0.861968994140625 +14281 0.79669189453125 +14282 0.852203369140625 +14283 0.595794677734375 +14284 0.732208251953125 +14285 0.362152099609375 +14286 0.5845947265625 +14287 0.1270751953125 +14288 0.425506591796875 +14289 -0.086944580078125 +14290 0.256561279296875 +14291 -0.2784423828125 +14292 0.051422119140625 +14293 -0.484832763671875 +14294 -0.204376220703125 +14295 -0.729583740234375 +14296 -0.472259521484375 +14297 -0.86688232421875 +14298 -0.704010009765625 +14299 -0.870391845703125 +14300 -0.8590087890625 +14301 -0.86859130859375 +14302 -0.870391845703125 +14303 -0.86279296875 +14304 -0.870391845703125 +14305 -0.817962646484375 +14306 -0.860076904296875 +14307 -0.6116943359375 +14308 -0.714996337890625 +14309 -0.3128662109375 +14310 -0.45672607421875 +14311 0.039398193359375 +14312 -0.14794921875 +14313 0.422821044921875 +14314 0.18505859375 +14315 0.805145263671875 +14316 0.490570068359375 +14317 0.870361328125 +14318 0.726226806640625 +14319 0.870361328125 +14320 0.857818603515625 +14321 0.860015869140625 +14322 0.866363525390625 +14323 0.727935791015625 +14324 0.8660888671875 +14325 0.48114013671875 +14326 0.85931396484375 +14327 0.2059326171875 +14328 0.79827880859375 +14329 -0.06103515625 +14330 0.67071533203125 +14331 -0.29913330078125 +14332 0.508636474609375 +14333 -0.516204833984375 +14334 0.303466796875 +14335 -0.7252197265625 +14336 0.076995849609375 +14337 -0.85980224609375 +14338 -0.14306640625 +14339 -0.870391845703125 +14340 -0.3330078125 +14341 -0.870391845703125 +14342 -0.453765869140625 +14343 -0.858062744140625 +14344 -0.502288818359375 +14345 -0.673004150390625 +14346 -0.52117919921875 +14347 -0.42694091796875 +14348 -0.547210693359375 +14349 -0.2100830078125 +14350 -0.58087158203125 +14351 -0.0362548828125 +14352 -0.60174560546875 +14353 0.10943603515625 +14354 -0.59686279296875 +14355 0.23516845703125 +14356 -0.53631591796875 +14357 0.373687744140625 +14358 -0.4244384765625 +14359 0.517791748046875 +14360 -0.313690185546875 +14361 0.602783203125 +14362 -0.202178955078125 +14363 0.635711669921875 +14364 -0.065216064453125 +14365 0.655181884765625 +14366 0.088134765625 +14367 0.65948486328125 +14368 0.2509765625 +14369 0.651275634765625 +14370 0.403900146484375 +14371 0.61846923828125 +14372 0.51824951171875 +14373 0.53753662109375 +14374 0.580902099609375 +14375 0.404144287109375 +14376 0.585784912109375 +14377 0.22186279296875 +14378 0.535858154296875 +14379 0.003997802734375 +14380 0.44769287109375 +14381 -0.22100830078125 +14382 0.339996337890625 +14383 -0.42449951171875 +14384 0.232025146484375 +14385 -0.579833984375 +14386 0.159820556640625 +14387 -0.641876220703125 +14388 0.12005615234375 +14389 -0.6177978515625 +14390 0.063140869140625 +14391 -0.575531005859375 +14392 -0.01397705078125 +14393 -0.526336669921875 +14394 -0.069610595703125 +14395 -0.42645263671875 +14396 -0.081817626953125 +14397 -0.2581787109375 +14398 -0.0797119140625 +14399 -0.068695068359375 +14400 -0.094573974609375 +14401 0.09222412109375 +14402 -0.112823486328125 +14403 0.232147216796875 +14404 -0.12786865234375 +14405 0.3509521484375 +14406 -0.164886474609375 +14407 0.410064697265625 +14408 -0.248992919921875 +14409 0.372955322265625 +14410 -0.365447998046875 +14411 0.2554931640625 +14412 -0.4747314453125 +14413 0.10711669921875 +14414 -0.562957763671875 +14415 -0.052886962890625 +14416 -0.602813720703125 +14417 -0.186279296875 +14418 -0.551025390625 +14419 -0.23291015625 +14420 -0.42626953125 +14421 -0.209442138671875 +14422 -0.281005859375 +14423 -0.174163818359375 +14424 -0.1217041015625 +14425 -0.126739501953125 +14426 0.059906005859375 +14427 -0.048126220703125 +14428 0.2423095703125 +14429 0.0426025390625 +14430 0.389678955078125 +14431 0.10748291015625 +14432 0.49285888671875 +14433 0.1409912109375 +14434 0.590911865234375 +14435 0.19708251953125 +14436 0.679962158203125 +14437 0.273651123046875 +14438 0.717193603515625 +14439 0.31768798828125 +14440 0.712646484375 +14441 0.341094970703125 +14442 0.687408447265625 +14443 0.368011474609375 +14444 0.6241455078125 +14445 0.37249755859375 +14446 0.484466552734375 +14447 0.30072021484375 +14448 0.2725830078125 +14449 0.1517333984375 +14450 0.041229248046875 +14451 -0.01470947265625 +14452 -0.195831298828125 +14453 -0.1883544921875 +14454 -0.43597412109375 +14455 -0.372711181640625 +14456 -0.631622314453125 +14457 -0.51397705078125 +14458 -0.746490478515625 +14459 -0.57177734375 +14460 -0.772003173828125 +14461 -0.53948974609375 +14462 -0.72015380859375 +14463 -0.43511962890625 +14464 -0.61962890625 +14465 -0.2962646484375 +14466 -0.500762939453125 +14467 -0.161102294921875 +14468 -0.3758544921875 +14469 -0.0435791015625 +14470 -0.24395751953125 +14471 0.060394287109375 +14472 -0.1195068359375 +14473 0.13665771484375 +14474 -0.018310546875 +14475 0.170135498046875 +14476 0.058929443359375 +14477 0.16552734375 +14478 0.1348876953125 +14479 0.15728759765625 +14480 0.209320068359375 +14481 0.150787353515625 +14482 0.2589111328125 +14483 0.12200927734375 +14484 0.28717041015625 +14485 0.080108642578125 +14486 0.311798095703125 +14487 0.05126953125 +14488 0.35235595703125 +14489 0.062896728515625 +14490 0.389923095703125 +14491 0.09271240234375 +14492 0.386444091796875 +14493 0.092987060546875 +14494 0.3543701171875 +14495 0.07855224609375 +14496 0.30706787109375 +14497 0.06427001953125 +14498 0.23480224609375 +14499 0.0347900390625 +14500 0.139129638671875 +14501 -0.01171875 +14502 0.038726806640625 +14503 -0.056060791015625 +14504 -0.028778076171875 +14505 -0.055511474609375 +14506 -0.05987548828125 +14507 -0.010467529296875 +14508 -0.09368896484375 +14509 0.02508544921875 +14510 -0.147186279296875 +14511 0.025665283203125 +14512 -0.197021484375 +14513 0.017333984375 +14514 -0.23974609375 +14515 0.00189208984375 +14516 -0.2828369140625 +14517 -0.03173828125 +14518 -0.3162841796875 +14519 -0.071502685546875 +14520 -0.35467529296875 +14521 -0.13543701171875 +14522 -0.396240234375 +14523 -0.219970703125 +14524 -0.423248291015625 +14525 -0.300506591796875 +14526 -0.437469482421875 +14527 -0.376312255859375 +14528 -0.4168701171875 +14529 -0.416107177734375 +14530 -0.325836181640625 +14531 -0.371124267578125 +14532 -0.168212890625 +14533 -0.242279052734375 +14534 0.021148681640625 +14535 -0.069732666015625 +14536 0.222869873046875 +14537 0.125640869140625 +14538 0.409912109375 +14539 0.31268310546875 +14540 0.55157470703125 +14541 0.45501708984375 +14542 0.648284912109375 +14543 0.554779052734375 +14544 0.698333740234375 +14545 0.61065673828125 +14546 0.692474365234375 +14547 0.610931396484375 +14548 0.612274169921875 +14549 0.531463623046875 +14550 0.471710205078125 +14551 0.3883056640625 +14552 0.314697265625 +14553 0.23468017578125 +14554 0.162933349609375 +14555 0.095245361328125 +14556 0.0394287109375 +14557 -0.00396728515625 +14558 -0.041839599609375 +14559 -0.04852294921875 +14560 -0.091522216796875 +14561 -0.055145263671875 +14562 -0.1484375 +14563 -0.0758056640625 +14564 -0.232818603515625 +14565 -0.138702392578125 +14566 -0.315521240234375 +14567 -0.209197998046875 +14568 -0.39666748046875 +14569 -0.289031982421875 +14570 -0.476043701171875 +14571 -0.37884521484375 +14572 -0.535797119140625 +14573 -0.456329345703125 +14574 -0.57232666015625 +14575 -0.51641845703125 +14576 -0.554962158203125 +14577 -0.519287109375 +14578 -0.479736328125 +14579 -0.458251953125 +14580 -0.389068603515625 +14581 -0.384796142578125 +14582 -0.30450439453125 +14583 -0.323699951171875 +14584 -0.2236328125 +14585 -0.269287109375 +14586 -0.127716064453125 +14587 -0.1951904296875 +14588 -0.01763916015625 +14589 -0.100006103515625 +14590 0.083526611328125 +14591 -0.01055908203125 +14592 0.1983642578125 +14593 0.1033935546875 +14594 0.331390380859375 +14595 0.24908447265625 +14596 0.439300537109375 +14597 0.373199462890625 +14598 0.507781982421875 +14599 0.45806884765625 +14600 0.543304443359375 +14601 0.511474609375 +14602 0.5721435546875 +14603 0.565399169921875 +14604 0.588531494140625 +14605 0.61138916015625 +14606 0.545989990234375 +14607 0.5897216796875 +14608 0.438201904296875 +14609 0.4906005859375 +14610 0.280792236328125 +14611 0.33148193359375 +14612 0.103759765625 +14613 0.147796630859375 +14614 -0.057861328125 +14615 -0.01873779296875 +14616 -0.180328369140625 +14617 -0.140289306640625 +14618 -0.242462158203125 +14619 -0.191986083984375 +14620 -0.251617431640625 +14621 -0.184295654296875 +14622 -0.24285888671875 +14623 -0.161834716796875 +14624 -0.249420166015625 +14625 -0.166595458984375 +14626 -0.267578125 +14627 -0.19390869140625 +14628 -0.282257080078125 +14629 -0.22442626953125 +14630 -0.311431884765625 +14631 -0.279754638671875 +14632 -0.33941650390625 +14633 -0.3389892578125 +14634 -0.32916259765625 +14635 -0.3543701171875 +14636 -0.2998046875 +14637 -0.348175048828125 +14638 -0.257171630859375 +14639 -0.32598876953125 +14640 -0.178955078125 +14641 -0.2581787109375 +14642 -0.062469482421875 +14643 -0.139801025390625 +14644 0.079559326171875 +14645 0.014617919921875 +14646 0.1976318359375 +14647 0.144378662109375 +14648 0.268341064453125 +14649 0.221038818359375 +14650 0.31219482421875 +14651 0.27069091796875 +14652 0.329681396484375 +14653 0.294036865234375 +14654 0.337554931640625 +14655 0.311767578125 +14656 0.348602294921875 +14657 0.339141845703125 +14658 0.351104736328125 +14659 0.360260009765625 +14660 0.334228515625 +14661 0.360504150390625 +14662 0.27288818359375 +14663 0.308380126953125 +14664 0.149749755859375 +14665 0.18170166015625 +14666 -0.014129638671875 +14667 0.0047607421875 +14668 -0.179290771484375 +14669 -0.17559814453125 +14670 -0.30780029296875 +14671 -0.3143310546875 +14672 -0.363067626953125 +14673 -0.36785888671875 +14674 -0.3662109375 +14675 -0.36248779296875 +14676 -0.354278564453125 +14677 -0.343536376953125 +14678 -0.3197021484375 +14679 -0.3018798828125 +14680 -0.257568359375 +14681 -0.231414794921875 +14682 -0.15625 +14683 -0.117645263671875 +14684 -0.04290771484375 +14685 0.007049560546875 +14686 0.036712646484375 +14687 0.087982177734375 +14688 0.093658447265625 +14689 0.13946533203125 +14690 0.137603759765625 +14691 0.17425537109375 +14692 0.16424560546875 +14693 0.188201904296875 +14694 0.164459228515625 +14695 0.171234130859375 +14696 0.13348388671875 +14697 0.118438720703125 +14698 0.0931396484375 +14699 0.05706787109375 +14700 0.044677734375 +14701 -0.010711669921875 +14702 -0.017578125 +14703 -0.0914306640625 +14704 -0.074981689453125 +14705 -0.162322998046875 +14706 -0.103759765625 +14707 -0.194549560546875 +14708 -0.071746826171875 +14709 -0.1492919921875 +14710 0.02545166015625 +14711 -0.02166748046875 +14712 0.13543701171875 +14713 0.124053955078125 +14714 0.19561767578125 +14715 0.211151123046875 +14716 0.20733642578125 +14717 0.240447998046875 +14718 0.196197509765625 +14719 0.242218017578125 +14720 0.170562744140625 +14721 0.2257080078125 +14722 0.1339111328125 +14723 0.194366455078125 +14724 0.059844970703125 +14725 0.115509033203125 +14726 -0.031646728515625 +14727 0.0128173828125 +14728 -0.090911865234375 +14729 -0.053802490234375 +14730 -0.139434814453125 +14731 -0.110626220703125 +14732 -0.211700439453125 +14733 -0.199493408203125 +14734 -0.286376953125 +14735 -0.29437255859375 +14736 -0.311767578125 +14737 -0.33221435546875 +14738 -0.26080322265625 +14739 -0.27972412109375 +14740 -0.17388916015625 +14741 -0.185333251953125 +14742 -0.11676025390625 +14743 -0.128204345703125 +14744 -0.096038818359375 +14745 -0.115692138671875 +14746 -0.086517333984375 +14747 -0.116455078125 +14748 -0.0684814453125 +14749 -0.105926513671875 +14750 -0.017578125 +14751 -0.053955078125 +14752 0.073455810546875 +14753 0.048797607421875 +14754 0.167236328125 +14755 0.157318115234375 +14756 0.214508056640625 +14757 0.212005615234375 +14758 0.219818115234375 +14759 0.218475341796875 +14760 0.23309326171875 +14761 0.23724365234375 +14762 0.2850341796875 +14763 0.30535888671875 +14764 0.341705322265625 +14765 0.38128662109375 +14766 0.35357666015625 +14767 0.404449462890625 +14768 0.337158203125 +14769 0.3944091796875 +14770 0.32373046875 +14771 0.3885498046875 +14772 0.29388427734375 +14773 0.362640380859375 +14774 0.2125244140625 +14775 0.27362060546875 +14776 0.076507568359375 +14777 0.11712646484375 +14778 -0.07098388671875 +14779 -0.054901123046875 +14780 -0.1871337890625 +14781 -0.19085693359375 +14782 -0.26763916015625 +14783 -0.28570556640625 +14784 -0.31231689453125 +14785 -0.339263916015625 +14786 -0.342620849609375 +14787 -0.3775634765625 +14788 -0.395843505859375 +14789 -0.445709228515625 +14790 -0.465057373046875 +14791 -0.535064697265625 +14792 -0.536895751953125 +14793 -0.629058837890625 +14794 -0.586944580078125 +14795 -0.697601318359375 +14796 -0.585235595703125 +14797 -0.70391845703125 +14798 -0.527587890625 +14799 -0.6424560546875 +14800 -0.39630126953125 +14801 -0.491241455078125 +14802 -0.20440673828125 +14803 -0.265716552734375 +14804 9.1552734375e-05 +14805 -0.023712158203125 +14806 0.189727783203125 +14807 0.201751708984375 +14808 0.33563232421875 +14809 0.375823974609375 +14810 0.4266357421875 +14811 0.485076904296875 +14812 0.495147705078125 +14813 0.56884765625 +14814 0.54754638671875 +14815 0.634765625 +14816 0.546722412109375 +14817 0.63763427734375 +14818 0.483428955078125 +14819 0.5660400390625 +14820 0.400848388671875 +14821 0.4720458984375 +14822 0.341552734375 +14823 0.40692138671875 +14824 0.311737060546875 +14825 0.3778076171875 +14826 0.30535888671875 +14827 0.376953125 +14828 0.2960205078125 +14829 0.371978759765625 +14830 0.243011474609375 +14831 0.313140869140625 +14832 0.13336181640625 +14833 0.184417724609375 +14834 -0.01177978515625 +14835 0.011199951171875 +14836 -0.16314697265625 +14837 -0.171051025390625 +14838 -0.3001708984375 +14839 -0.33740234375 +14840 -0.4097900390625 +14841 -0.47198486328125 +14842 -0.480255126953125 +14843 -0.560394287109375 +14844 -0.493560791015625 +14845 -0.58056640625 +14846 -0.462310791015625 +14847 -0.54754638671875 +14848 -0.42578125 +14849 -0.508575439453125 +14850 -0.380584716796875 +14851 -0.459503173828125 +14852 -0.32232666015625 +14853 -0.394378662109375 +14854 -0.284881591796875 +14855 -0.35260009765625 +14856 -0.24908447265625 +14857 -0.31170654296875 +14858 -0.151397705078125 +14859 -0.197418212890625 +14860 0.00970458984375 +14861 -0.007965087890625 +14862 0.19219970703125 +14863 0.207489013671875 +14864 0.3621826171875 +14865 0.409210205078125 +14866 0.498321533203125 +14867 0.57208251953125 +14868 0.574981689453125 +14869 0.66595458984375 +14870 0.56494140625 +14871 0.65875244140625 +14872 0.48291015625 +14873 0.56744384765625 +14874 0.362823486328125 +14875 0.431396484375 +14876 0.242401123046875 +14877 0.29443359375 +14878 0.14398193359375 +14879 0.182464599609375 +14880 0.04046630859375 +14881 0.06365966796875 +14882 -0.080047607421875 +14883 -0.075958251953125 +14884 -0.17730712890625 +14885 -0.189422607421875 +14886 -0.24725341796875 +14887 -0.271942138671875 +14888 -0.306182861328125 +14889 -0.342529296875 +14890 -0.322540283203125 +14891 -0.364166259765625 +14892 -0.288238525390625 +14893 -0.327239990234375 +14894 -0.242156982421875 +14895 -0.2769775390625 +14896 -0.218994140625 +14897 -0.253692626953125 +14898 -0.2071533203125 +14899 -0.24365234375 +14900 -0.165313720703125 +14901 -0.1983642578125 +14902 -0.09228515625 +14903 -0.116241455078125 +14904 -0.02203369140625 +14905 -0.036834716796875 +14906 0.041046142578125 +14907 0.034881591796875 +14908 0.090301513671875 +14909 0.09124755859375 +14910 0.105743408203125 +14911 0.10888671875 +14912 0.11962890625 +14913 0.125518798828125 +14914 0.146209716796875 +14915 0.15771484375 +14916 0.1622314453125 +14917 0.17828369140625 +14918 0.153961181640625 +14919 0.17108154296875 +14920 0.1163330078125 +14921 0.129974365234375 +14922 0.072967529296875 +14923 0.082427978515625 +14924 0.023406982421875 +14925 0.027679443359375 +14926 -0.059051513671875 +14927 -0.065643310546875 +14928 -0.141571044921875 +14929 -0.15936279296875 +14930 -0.189483642578125 +14931 -0.21307373046875 +14932 -0.209442138671875 +14933 -0.234649658203125 +14934 -0.180908203125 +14935 -0.2001953125 +14936 -0.111968994140625 +14937 -0.119171142578125 +14938 -0.031005859375 +14939 -0.024749755859375 +14940 0.06427001953125 +14941 0.085784912109375 +14942 0.14447021484375 +14943 0.178131103515625 +14944 0.1781005859375 +14945 0.215576171875 +14946 0.176422119140625 +14947 0.211456298828125 +14948 0.147430419921875 +14949 0.17523193359375 +14950 0.1097412109375 +14951 0.128753662109375 +14952 0.088836669921875 +14953 0.1019287109375 +14954 0.067169189453125 +14955 0.0743408203125 +14956 0.04229736328125 +14957 0.04327392578125 +14958 0.039337158203125 +14959 0.038177490234375 +14960 0.07293701171875 +14961 0.076263427734375 +14962 0.128936767578125 +14963 0.14105224609375 +14964 0.167877197265625 +14965 0.186431884765625 +14966 0.1695556640625 +14967 0.188812255859375 +14968 0.126129150390625 +14969 0.1390380859375 +14970 0.04168701171875 +14971 0.041778564453125 +14972 -0.06353759765625 +14973 -0.079437255859375 +14974 -0.18499755859375 +14975 -0.219390869140625 +14976 -0.31378173828125 +14977 -0.367828369140625 +14978 -0.42425537109375 +14979 -0.494873046875 +14980 -0.478424072265625 +14981 -0.556243896484375 +14982 -0.439178466796875 +14983 -0.508697509765625 +14984 -0.326446533203125 +14985 -0.3756103515625 +14986 -0.193206787109375 +14987 -0.218902587890625 +14988 -0.060943603515625 +14989 -0.063751220703125 +14990 0.07177734375 +14991 0.091552734375 +14992 0.195587158203125 +14993 0.23602294921875 +14994 0.287628173828125 +14995 0.342987060546875 +14996 0.3331298828125 +14997 0.39520263671875 +14998 0.329193115234375 +14999 0.389373779296875 +15000 0.27471923828125 +15001 0.324249267578125 +15002 0.19036865234375 +15003 0.224090576171875 +15004 0.106353759765625 +15005 0.124267578125 +15006 0.0330810546875 +15007 0.037078857421875 +15008 -0.00604248046875 +15009 -0.010101318359375 +15010 -0.012969970703125 +15011 -0.019439697265625 +15012 -0.014984130859375 +15013 -0.022796630859375 +15014 0.003753662109375 +15015 -0.001556396484375 +15016 0.053558349609375 +15017 0.056304931640625 +15018 0.096710205078125 +15019 0.106719970703125 +15020 0.087982177734375 +15021 0.096893310546875 +15022 0.041015625 +15023 0.042694091796875 +15024 -0.011749267578125 +15025 -0.018035888671875 +15026 -0.06219482421875 +15027 -0.07586669921875 +15028 -0.100555419921875 +15029 -0.11944580078125 +15030 -0.13616943359375 +15031 -0.15972900390625 +15032 -0.17401123046875 +15033 -0.202606201171875 +15034 -0.21441650390625 +15035 -0.24859619140625 +15036 -0.26373291015625 +15037 -0.30517578125 +15038 -0.31317138671875 +15039 -0.36212158203125 +15040 -0.338775634765625 +15041 -0.39141845703125 +15042 -0.308135986328125 +15043 -0.35528564453125 +15044 -0.218048095703125 +15045 -0.249969482421875 +15046 -0.083404541015625 +15047 -0.092864990234375 +15048 0.07269287109375 +15049 0.08905029296875 +15050 0.1983642578125 +15051 0.2352294921875 +15052 0.270599365234375 +15053 0.318817138671875 +15054 0.30548095703125 +15055 0.358642578125 +15056 0.2969970703125 +15057 0.347747802734375 +15058 0.24468994140625 +15059 0.28564453125 +15060 0.192047119140625 +15061 0.223175048828125 +15062 0.170166015625 +15063 0.196746826171875 +15064 0.156341552734375 +15065 0.179840087890625 +15066 0.136077880859375 +15067 0.155548095703125 +15068 0.13275146484375 +15069 0.151214599609375 +15070 0.13787841796875 +15071 0.156951904296875 +15072 0.116302490234375 +15073 0.13177490234375 +15074 0.089569091796875 +15075 0.100799560546875 +15076 0.07745361328125 +15077 0.087127685546875 +15078 0.049285888671875 +15079 0.05487060546875 +15080 -0.00604248046875 +15081 -0.009002685546875 +15082 -0.08807373046875 +15083 -0.10400390625 +15084 -0.196136474609375 +15085 -0.229400634765625 +15086 -0.3048095703125 +15087 -0.35552978515625 +15088 -0.37939453125 +15089 -0.441925048828125 +15090 -0.40728759765625 +15091 -0.473846435546875 +15092 -0.39996337890625 +15093 -0.464813232421875 +15094 -0.361114501953125 +15095 -0.419097900390625 +15096 -0.288665771484375 +15097 -0.334320068359375 +15098 -0.19757080078125 +15099 -0.227935791015625 +15100 -0.10797119140625 +15101 -0.12347412109375 +15102 -0.025634765625 +15103 -0.02764892578125 +15104 0.06488037109375 +15105 0.077667236328125 +15106 0.181610107421875 +15107 0.2132568359375 +15108 0.333648681640625 +15109 0.38885498046875 +15110 0.502349853515625 +15111 0.582794189453125 +15112 0.634002685546875 +15113 0.734039306640625 +15114 0.691253662109375 +15115 0.800140380859375 +15116 0.6717529296875 +15117 0.7783203125 +15118 0.572509765625 +15119 0.6651611328125 +15120 0.392486572265625 +15121 0.45965576171875 +15122 0.16473388671875 +15123 0.199188232421875 +15124 -0.05279541015625 +15125 -0.050689697265625 +15126 -0.20977783203125 +15127 -0.23297119140625 +15128 -0.291015625 +15129 -0.33013916015625 +15130 -0.320098876953125 +15131 -0.368408203125 +15132 -0.324951171875 +15133 -0.378936767578125 +15134 -0.319427490234375 +15135 -0.376983642578125 +15136 -0.319000244140625 +15137 -0.37969970703125 +15138 -0.32769775390625 +15139 -0.391510009765625 +15140 -0.32159423828125 +15141 -0.385345458984375 +15142 -0.283538818359375 +15143 -0.3419189453125 +15144 -0.23272705078125 +15145 -0.28289794921875 +15146 -0.207550048828125 +15147 -0.251617431640625 +15148 -0.223846435546875 +15149 -0.266143798828125 +15150 -0.2342529296875 +15151 -0.273345947265625 +15152 -0.18841552734375 +15153 -0.216796875 +15154 -0.1142578125 +15155 -0.128265380859375 +15156 -0.065185546875 +15157 -0.068145751953125 +15158 -0.046875 +15159 -0.0430908203125 +15160 -0.03369140625 +15161 -0.024444580078125 +15162 0.0037841796875 +15163 0.020721435546875 +15164 0.09417724609375 +15165 0.124481201171875 +15166 0.211822509765625 +15167 0.25787353515625 +15168 0.319610595703125 +15169 0.379119873046875 +15170 0.410186767578125 +15171 0.47991943359375 +15172 0.4549560546875 +15173 0.5281982421875 +15174 0.44244384765625 +15175 0.511138916015625 +15176 0.3968505859375 +15177 0.456207275390625 +15178 0.357147216796875 +15179 0.407470703125 +15180 0.339813232421875 +15181 0.383758544921875 +15182 0.319610595703125 +15183 0.35687255859375 +15184 0.283050537109375 +15185 0.31182861328125 +15186 0.231903076171875 +15187 0.250885009765625 +15188 0.158355712890625 +15189 0.1654052734375 +15190 0.04443359375 +15191 0.035247802734375 +15192 -0.112091064453125 +15193 -0.142059326171875 +15194 -0.283843994140625 +15195 -0.33563232421875 +15196 -0.461090087890625 +15197 -0.5345458984375 +15198 -0.628753662109375 +15199 -0.72186279296875 +15200 -0.732635498046875 +15201 -0.836669921875 +15202 -0.73150634765625 +15203 -0.8326416015625 +15204 -0.642852783203125 +15205 -0.7296142578125 +15206 -0.5152587890625 +15207 -0.582550048828125 +15208 -0.39178466796875 +15209 -0.440093994140625 +15210 -0.2918701171875 +15211 -0.324310302734375 +15212 -0.1854248046875 +15213 -0.20147705078125 +15214 -0.048309326171875 +15215 -0.044647216796875 +15216 0.08203125 +15217 0.103973388671875 +15218 0.168426513671875 +15219 0.202392578125 +15220 0.22320556640625 +15221 0.264495849609375 +15222 0.28955078125 +15223 0.338897705078125 +15224 0.38360595703125 +15225 0.443817138671875 +15226 0.4749755859375 +15227 0.545074462890625 +15228 0.541015625 +15229 0.6173095703125 +15230 0.574493408203125 +15231 0.6524658203125 +15232 0.586639404296875 +15233 0.66339111328125 +15234 0.58270263671875 +15235 0.6561279296875 +15236 0.54132080078125 +15237 0.606781005859375 +15238 0.449798583984375 +15239 0.501190185546875 +15240 0.31988525390625 +15241 0.352783203125 +15242 0.164825439453125 +15243 0.176544189453125 +15244 -0.021881103515625 +15245 -0.034820556640625 +15246 -0.219757080078125 +15247 -0.258209228515625 +15248 -0.3834228515625 +15249 -0.44244384765625 +15250 -0.501953125 +15251 -0.5753173828125 +15252 -0.571075439453125 +15253 -0.65203857421875 +15254 -0.563232421875 +15255 -0.641632080078125 +15256 -0.494384765625 +15257 -0.562164306640625 +15258 -0.40386962890625 +15259 -0.458038330078125 +15260 -0.3104248046875 +15261 -0.350555419921875 +15262 -0.23248291015625 +15263 -0.260528564453125 +15264 -0.173614501953125 +15265 -0.192108154296875 +15266 -0.1307373046875 +15267 -0.141937255859375 +15268 -0.0968017578125 +15269 -0.1021728515625 +15270 -0.06292724609375 +15271 -0.062896728515625 +15272 -0.01824951171875 +15273 -0.011932373046875 +15274 0.048004150390625 +15275 0.062835693359375 +15276 0.12457275390625 +15277 0.148712158203125 +15278 0.207855224609375 +15279 0.241729736328125 +15280 0.30426025390625 +15281 0.34912109375 +15282 0.401641845703125 +15283 0.457305908203125 +15284 0.480010986328125 +15285 0.54388427734375 +15286 0.50738525390625 +15287 0.5728759765625 +15288 0.4501953125 +15289 0.506591796875 +15290 0.3138427734375 +15291 0.351226806640625 +15292 0.133514404296875 +15293 0.146514892578125 +15294 -0.044403076171875 +15295 -0.05523681640625 +15296 -0.1864013671875 +15297 -0.21624755859375 +15298 -0.2911376953125 +15299 -0.334930419921875 +15300 -0.351287841796875 +15301 -0.402984619140625 +15302 -0.3853759765625 +15303 -0.4412841796875 +15304 -0.434173583984375 +15305 -0.49578857421875 +15306 -0.492034912109375 +15307 -0.5601806640625 +15308 -0.52899169921875 +15309 -0.600738525390625 +15310 -0.5155029296875 +15311 -0.584228515625 +15312 -0.42364501953125 +15313 -0.47930908203125 +15314 -0.24749755859375 +15315 -0.27935791015625 +15316 -0.008758544921875 +15317 -0.0089111328125 +15318 0.23651123046875 +15319 0.268798828125 +15320 0.425384521484375 +15321 0.482818603515625 +15322 0.53179931640625 +15323 0.60369873046875 +15324 0.5726318359375 +15325 0.650421142578125 +15326 0.584320068359375 +15327 0.66400146484375 +15328 0.564239501953125 +15329 0.6414794921875 +15330 0.50323486328125 +15331 0.572540283203125 +15332 0.437652587890625 +15333 0.498138427734375 +15334 0.386260986328125 +15335 0.439453125 +15336 0.33038330078125 +15337 0.375518798828125 +15338 0.241729736328125 +15339 0.274505615234375 +15340 0.095672607421875 +15341 0.1087646484375 +15342 -0.088043212890625 +15343 -0.099395751953125 +15344 -0.28125 +15345 -0.3182373046875 +15346 -0.485107421875 +15347 -0.5489501953125 +15348 -0.683929443359375 +15349 -0.7738037109375 +15350 -0.830718994140625 +15351 -0.86383056640625 +15352 -0.859039306640625 +15353 -0.870391845703125 +15354 -0.858978271484375 +15355 -0.86895751953125 +15356 -0.84075927734375 +15357 -0.861053466796875 +15358 -0.716583251953125 +15359 -0.765869140625 +15360 -0.512786865234375 +15361 -0.5301513671875 +15362 -0.23516845703125 +15363 -0.214691162109375 +15364 0.077911376953125 +15365 0.137359619140625 +15366 0.380279541015625 +15367 0.474822998046875 +15368 0.640106201171875 +15369 0.76239013671875 +15370 0.833221435546875 +15371 0.867462158203125 +15372 0.866058349609375 +15373 0.870361328125 +15374 0.870361328125 +15375 0.86480712890625 +15376 0.86700439453125 +15377 0.831817626953125 +15378 0.8585205078125 +15379 0.677581787109375 +15380 0.772491455078125 +15381 0.495880126953125 +15382 0.628936767578125 +15383 0.30767822265625 +15384 0.46282958984375 +15385 0.116180419921875 +15386 0.24456787109375 +15387 -0.110748291015625 +15388 -0.032806396484375 +15389 -0.381805419921875 +15390 -0.330718994140625 +15391 -0.6572265625 +15392 -0.59490966796875 +15393 -0.857421875 +15394 -0.786773681640625 +15395 -0.870391845703125 +15396 -0.859527587890625 +15397 -0.870391845703125 +15398 -0.866241455078125 +15399 -0.86444091796875 +15400 -0.870391845703125 +15401 -0.85723876953125 +15402 -0.870391845703125 +15403 -0.790008544921875 +15404 -0.86126708984375 +15405 -0.62847900390625 +15406 -0.746856689453125 +15407 -0.3956298828125 +15408 -0.522003173828125 +15409 -0.126708984375 +15410 -0.267120361328125 +15411 0.150115966796875 +15412 0.007171630859375 +15413 0.424041748046875 +15414 0.27655029296875 +15415 0.670623779296875 +15416 0.50604248046875 +15417 0.854522705078125 +15418 0.68017578125 +15419 0.866485595703125 +15420 0.785736083984375 +15421 0.86920166015625 +15422 0.840484619140625 +15423 0.8653564453125 +15424 0.854827880859375 +15425 0.857147216796875 +15426 0.835968017578125 +15427 0.766845703125 +15428 0.780670166015625 +15429 0.628509521484375 +15430 0.686431884765625 +15431 0.462127685546875 +15432 0.577606201171875 +15433 0.297210693359375 +15434 0.46600341796875 +15435 0.14862060546875 +15436 0.33074951171875 +15437 -0.00537109375 +15438 0.17864990234375 +15439 -0.15753173828125 +15440 0.006134033203125 +15441 -0.31304931640625 +15442 -0.20013427734375 +15443 -0.48876953125 +15444 -0.397674560546875 +15445 -0.6416015625 +15446 -0.564453125 +15447 -0.751373291015625 +15448 -0.722503662109375 +15449 -0.84619140625 +15450 -0.855010986328125 +15451 -0.861297607421875 +15452 -0.864349365234375 +15453 -0.863250732421875 +15454 -0.865020751953125 +15455 -0.856597900390625 +15456 -0.85833740234375 +15457 -0.7498779296875 +15458 -0.8143310546875 +15459 -0.624542236328125 +15460 -0.70550537109375 +15461 -0.47808837890625 +15462 -0.509429931640625 +15463 -0.253387451171875 +15464 -0.268157958984375 +15465 0.003692626953125 +15466 -0.04443359375 +15467 0.2257080078125 +15468 0.17352294921875 +15469 0.427154541015625 +15470 0.41595458984375 +15471 0.643218994140625 +15472 0.674530029296875 +15473 0.855926513671875 +15474 0.85906982421875 +15475 0.870361328125 +15476 0.870361328125 +15477 0.870361328125 +15478 0.870361328125 +15479 0.862762451171875 +15480 0.862823486328125 +15481 0.79669189453125 +15482 0.7880859375 +15483 0.595794677734375 +15484 0.6007080078125 +15485 0.362152099609375 +15486 0.396636962890625 +15487 0.1270751953125 +15488 0.196319580078125 +15489 -0.086944580078125 +15490 0.001708984375 +15491 -0.2784423828125 +15492 -0.220123291015625 +15493 -0.484832763671875 +15494 -0.4886474609375 +15495 -0.729583740234375 +15496 -0.7598876953125 +15497 -0.86688232421875 +15498 -0.8680419921875 +15499 -0.870391845703125 +15500 -0.870391845703125 +15501 -0.86859130859375 +15502 -0.868377685546875 +15503 -0.86279296875 +15504 -0.85955810546875 +15505 -0.817962646484375 +15506 -0.724853515625 +15507 -0.6116943359375 +15508 -0.45458984375 +15509 -0.3128662109375 +15510 -0.125885009765625 +15511 0.039398193359375 +15512 0.240203857421875 +15513 0.422821044921875 +15514 0.613006591796875 +15515 0.805145263671875 +15516 0.862945556640625 +15517 0.870361328125 +15518 0.870361328125 +15519 0.870361328125 +15520 0.8675537109375 +15521 0.860015869140625 +15522 0.85540771484375 +15523 0.727935791015625 +15524 0.6759033203125 +15525 0.48114013671875 +15526 0.44873046875 +15527 0.2059326171875 +15528 0.2142333984375 +15529 -0.06103515625 +15530 -0.008758544921875 +15531 -0.29913330078125 +15532 -0.226837158203125 +15533 -0.516204833984375 +15534 -0.45050048828125 +15535 -0.7252197265625 +15536 -0.656280517578125 +15537 -0.85980224609375 +15538 -0.815155029296875 +15539 -0.870391845703125 +15540 -0.86004638671875 +15541 -0.870391845703125 +15542 -0.858367919921875 +15543 -0.858062744140625 +15544 -0.77459716796875 +15545 -0.673004150390625 +15546 -0.619171142578125 +15547 -0.42694091796875 +15548 -0.47625732421875 +15549 -0.2100830078125 +15550 -0.355865478515625 +15551 -0.0362548828125 +15552 -0.242645263671875 +15553 0.10943603515625 +15554 -0.128448486328125 +15555 0.23516845703125 +15556 0.016326904296875 +15557 0.373687744140625 +15558 0.18359375 +15559 0.517791748046875 +15560 0.311431884765625 +15561 0.602783203125 +15562 0.403228759765625 +15563 0.635711669921875 +15564 0.490753173828125 +15565 0.655181884765625 +15566 0.56842041015625 +15567 0.65948486328125 +15568 0.634521484375 +15569 0.651275634765625 +15570 0.673919677734375 +15571 0.61846923828125 +15572 0.661346435546875 +15573 0.53753662109375 +15574 0.58966064453125 +15575 0.404144287109375 +15576 0.45965576171875 +15577 0.22186279296875 +15578 0.281890869140625 +15579 0.003997802734375 +15580 0.08172607421875 +15581 -0.22100830078125 +15582 -0.114410400390625 +15583 -0.42449951171875 +15584 -0.281005859375 +15585 -0.579833984375 +15586 -0.374847412109375 +15587 -0.641876220703125 +15588 -0.400177001953125 +15589 -0.6177978515625 +15590 -0.41656494140625 +15591 -0.575531005859375 +15592 -0.431121826171875 +15593 -0.526336669921875 +15594 -0.4002685546875 +15595 -0.42645263671875 +15596 -0.304290771484375 +15597 -0.2581787109375 +15598 -0.183441162109375 +15599 -0.068695068359375 +15600 -0.080718994140625 +15601 0.09222412109375 +15602 0.01300048828125 +15603 0.232147216796875 +15604 0.0992431640625 +15605 0.3509521484375 +15606 0.143402099609375 +15607 0.410064697265625 +15608 0.112091064453125 +15609 0.372955322265625 +15610 0.019378662109375 +15611 0.2554931640625 +15612 -0.0904541015625 +15613 0.10711669921875 +15614 -0.201446533203125 +15615 -0.052886962890625 +15616 -0.28021240234375 +15617 -0.186279296875 +15618 -0.273590087890625 +15619 -0.23291015625 +15620 -0.20050048828125 +15621 -0.209442138671875 +15622 -0.11865234375 +15623 -0.174163818359375 +15624 -0.0299072265625 +15625 -0.126739501953125 +15626 0.081817626953125 +15627 -0.048126220703125 +15628 0.19683837890625 +15629 0.0426025390625 +15630 0.2779541015625 +15631 0.10748291015625 +15632 0.319183349609375 +15633 0.1409912109375 +15634 0.37164306640625 +15635 0.19708251953125 +15636 0.4337158203125 +15637 0.273651123046875 +15638 0.45587158203125 +15639 0.31768798828125 +15640 0.45074462890625 +15641 0.341094970703125 +15642 0.4429931640625 +15643 0.368011474609375 +15644 0.409912109375 +15645 0.37249755859375 +15646 0.302490234375 +15647 0.30072021484375 +15648 0.121978759765625 +15649 0.1517333984375 +15650 -0.07275390625 +15651 -0.01470947265625 +15652 -0.27001953125 +15653 -0.1883544921875 +15654 -0.471588134765625 +15655 -0.372711181640625 +15656 -0.625091552734375 +15657 -0.51397705078125 +15658 -0.691253662109375 +15659 -0.57177734375 +15660 -0.663421630859375 +15661 -0.53948974609375 +15662 -0.558807373046875 +15663 -0.43511962890625 +15664 -0.413665771484375 +15665 -0.2962646484375 +15666 -0.265228271484375 +15667 -0.161102294921875 +15668 -0.12799072265625 +15669 -0.0435791015625 +15670 0.000335693359375 +15671 0.060394287109375 +15672 0.104583740234375 +15673 0.13665771484375 +15674 0.16864013671875 +15675 0.170135498046875 +15676 0.195220947265625 +15677 0.16552734375 +15678 0.21539306640625 +15679 0.15728759765625 +15680 0.232818603515625 +15681 0.150787353515625 +15682 0.2235107421875 +15683 0.12200927734375 +15684 0.195343017578125 +15685 0.080108642578125 +15686 0.172760009765625 +15687 0.05126953125 +15688 0.181732177734375 +15689 0.062896728515625 +15690 0.201385498046875 +15691 0.09271240234375 +15692 0.18707275390625 +15693 0.092987060546875 +15694 0.15380859375 +15695 0.07855224609375 +15696 0.116943359375 +15697 0.06427001953125 +15698 0.063262939453125 +15699 0.0347900390625 +15700 -0.007537841796875 +15701 -0.01171875 +15702 -0.07568359375 +15703 -0.056060791015625 +15704 -0.099212646484375 +15705 -0.055511474609375 +15706 -0.077239990234375 +15707 -0.010467529296875 +15708 -0.059967041015625 +15709 0.02508544921875 +15710 -0.070831298828125 +15711 0.025665283203125 +15712 -0.0845947265625 +15713 0.017333984375 +15714 -0.099395751953125 +15715 0.00189208984375 +15716 -0.125946044921875 +15717 -0.03173828125 +15718 -0.15325927734375 +15719 -0.071502685546875 +15720 -0.199188232421875 +15721 -0.13543701171875 +15722 -0.261260986328125 +15723 -0.219970703125 +15724 -0.317230224609375 +15725 -0.300506591796875 +15726 -0.3675537109375 +15727 -0.376312255859375 +15728 -0.38372802734375 +15729 -0.416107177734375 +15730 -0.320587158203125 +15731 -0.371124267578125 +15732 -0.180084228515625 +15733 -0.242279052734375 +15734 -0.001312255859375 +15735 -0.069732666015625 +15736 0.195159912109375 +15737 0.125640869140625 +15738 0.3792724609375 +15739 0.31268310546875 +15740 0.516265869140625 +15741 0.45501708984375 +15742 0.608184814453125 +15743 0.554779052734375 +15744 0.654083251953125 +15745 0.61065673828125 +15746 0.643341064453125 +15747 0.610931396484375 +15748 0.553741455078125 +15749 0.531463623046875 +15750 0.401397705078125 +15751 0.3883056640625 +15752 0.23779296875 +15753 0.23468017578125 +15754 0.087371826171875 +15755 0.095245361328125 +15756 -0.024139404296875 +15757 -0.00396728515625 +15758 -0.082122802734375 +15759 -0.04852294921875 +15760 -0.10162353515625 +15761 -0.055145263671875 +15762 -0.13140869140625 +15763 -0.0758056640625 +15764 -0.197784423828125 +15765 -0.138702392578125 +15766 -0.267578125 +15767 -0.209197998046875 +15768 -0.3424072265625 +15769 -0.289031982421875 +15770 -0.423065185546875 +15771 -0.37884521484375 +15772 -0.488677978515625 +15773 -0.456329345703125 +15774 -0.535003662109375 +15775 -0.51641845703125 +15776 -0.52484130859375 +15777 -0.519287109375 +15778 -0.452606201171875 +15779 -0.458251953125 +15780 -0.3680419921875 +15781 -0.384796142578125 +15782 -0.29547119140625 +15783 -0.323699951171875 +15784 -0.23028564453125 +15785 -0.269287109375 +15786 -0.148193359375 +15787 -0.1951904296875 +15788 -0.048431396484375 +15789 -0.100006103515625 +15790 0.04302978515625 +15791 -0.01055908203125 +15792 0.1546630859375 +15793 0.1033935546875 +15794 0.293243408203125 +15795 0.24908447265625 +15796 0.408233642578125 +15797 0.373199462890625 +15798 0.48309326171875 +15799 0.45806884765625 +15800 0.525604248046875 +15801 0.511474609375 +15802 0.56671142578125 +15803 0.565399169921875 +15804 0.598968505859375 +15805 0.61138916015625 +15806 0.5662841796875 +15807 0.5897216796875 +15808 0.46002197265625 +15809 0.4906005859375 +15810 0.297454833984375 +15811 0.33148193359375 +15812 0.112823486328125 +15813 0.147796630859375 +15814 -0.053741455078125 +15815 -0.01873779296875 +15816 -0.17535400390625 +15817 -0.140289306640625 +15818 -0.2281494140625 +15819 -0.191986083984375 +15820 -0.221923828125 +15821 -0.184295654296875 +15822 -0.1990966796875 +15823 -0.161834716796875 +15824 -0.199676513671875 +15825 -0.166595458984375 +15826 -0.219512939453125 +15827 -0.19390869140625 +15828 -0.240631103515625 +15829 -0.22442626953125 +15830 -0.284027099609375 +15831 -0.279754638671875 +15832 -0.330413818359375 +15833 -0.3389892578125 +15834 -0.3349609375 +15835 -0.3543701171875 +15836 -0.31939697265625 +15837 -0.348175048828125 +15838 -0.28955078125 +15839 -0.32598876953125 +15840 -0.21771240234375 +15841 -0.2581787109375 +15842 -0.09954833984375 +15843 -0.139801025390625 +15844 0.0509033203125 +15845 0.014617919921875 +15846 0.17578125 +15847 0.144378662109375 +15848 0.248077392578125 +15849 0.221038818359375 +15850 0.292633056640625 +15851 0.27069091796875 +15852 0.31036376953125 +15853 0.294036865234375 +15854 0.321197509765625 +15855 0.311767578125 +15856 0.34002685546875 +15857 0.339141845703125 +15858 0.3521728515625 +15859 0.360260009765625 +15860 0.34423828125 +15861 0.360504150390625 +15862 0.28662109375 +15863 0.308380126953125 +15864 0.15863037109375 +15865 0.18170166015625 +15866 -0.016143798828125 +15867 0.0047607421875 +15868 -0.192840576171875 +15869 -0.17559814453125 +15870 -0.328369140625 +15871 -0.3143310546875 +15872 -0.3807373046875 +15873 -0.36785888671875 +15874 -0.37530517578125 +15875 -0.36248779296875 +15876 -0.35589599609375 +15877 -0.343536376953125 +15878 -0.31341552734375 +15879 -0.3018798828125 +15880 -0.241790771484375 +15881 -0.231414794921875 +15882 -0.126800537109375 +15883 -0.117645263671875 +15884 -0.000396728515625 +15885 0.007049560546875 +15886 0.0833740234375 +15887 0.087982177734375 +15888 0.138397216796875 +15889 0.13946533203125 +15890 0.176971435546875 +15891 0.17425537109375 +15892 0.1947021484375 +15893 0.188201904296875 +15894 0.18145751953125 +15895 0.171234130859375 +15896 0.132232666015625 +15897 0.118438720703125 +15898 0.073699951171875 +15899 0.05706787109375 +15900 0.007843017578125 +15901 -0.010711669921875 +15902 -0.071746826171875 +15903 -0.0914306640625 +15904 -0.142608642578125 +15905 -0.162322998046875 +15906 -0.17633056640625 +15907 -0.194549560546875 +15908 -0.13458251953125 +15909 -0.1492919921875 +15910 -0.01239013671875 +15911 -0.02166748046875 +15912 0.127227783203125 +15913 0.124053955078125 +15914 0.208984375 +15915 0.211151123046875 +15916 0.233917236328125 +15917 0.240447998046875 +15918 0.23199462890625 +15919 0.242218017578125 +15920 0.212554931640625 +15921 0.2257080078125 +15922 0.179107666015625 +15923 0.194366455078125 +15924 0.099639892578125 +15925 0.115509033203125 +15926 -0.002471923828125 +15927 0.0128173828125 +15928 -0.0682373046875 +15929 -0.053802490234375 +15930 -0.123504638671875 +15931 -0.110626220703125 +15932 -0.20953369140625 +15933 -0.199493408203125 +15934 -0.300811767578125 +15935 -0.29437255859375 +15936 -0.335418701171875 +15937 -0.33221435546875 +15938 -0.28076171875 +15939 -0.27972412109375 +15940 -0.184661865234375 +15941 -0.185333251953125 +15942 -0.12518310546875 +15943 -0.128204345703125 +15944 -0.109710693359375 +15945 -0.115692138671875 +15946 -0.10760498046875 +15947 -0.116455078125 +15948 -0.0948486328125 +15949 -0.105926513671875 +15950 -0.04193115234375 +15951 -0.053955078125 +15952 0.060272216796875 +15953 0.048797607421875 +15954 0.16748046875 +15955 0.157318115234375 +15956 0.22100830078125 +15957 0.212005615234375 +15958 0.2264404296875 +15959 0.218475341796875 +15960 0.243377685546875 +15961 0.23724365234375 +15962 0.308380126953125 +15963 0.30535888671875 +15964 0.380706787109375 +15965 0.38128662109375 +15966 0.40087890625 +15967 0.404449462890625 +15968 0.388275146484375 +15969 0.3944091796875 +15970 0.379852294921875 +15971 0.3885498046875 +15972 0.3519287109375 +15973 0.362640380859375 +15974 0.26220703125 +15975 0.27362060546875 +15976 0.106536865234375 +15977 0.11712646484375 +15978 -0.063873291015625 +15979 -0.054901123046875 +15980 -0.198211669921875 +15981 -0.19085693359375 +15982 -0.291534423828125 +15983 -0.28570556640625 +15984 -0.343658447265625 +15985 -0.339263916015625 +15986 -0.3802490234375 +15987 -0.3775634765625 +15988 -0.445770263671875 +15989 -0.445709228515625 +15990 -0.531829833984375 +15991 -0.535064697265625 +15992 -0.6221923828125 +15993 -0.629058837890625 +15994 -0.687408447265625 +15995 -0.697601318359375 +15996 -0.69140625 +15997 -0.70391845703125 +15998 -0.628814697265625 +15999 -0.6424560546875 +16000 -0.4781494140625 +16001 -0.491241455078125 +16002 -0.25469970703125 +16003 -0.265716552734375 +16004 -0.015411376953125 +16005 -0.023712158203125 +16006 0.207122802734375 +16007 0.201751708984375 +16008 0.37860107421875 +16009 0.375823974609375 +16010 0.485809326171875 +16011 0.485076904296875 +16012 0.5675048828125 +16013 0.56884765625 +16014 0.6312255859375 +16015 0.634765625 +16016 0.632568359375 +16017 0.63763427734375 +16018 0.560394287109375 +16019 0.5660400390625 +16020 0.466033935546875 +16021 0.4720458984375 +16022 0.400054931640625 +16023 0.40692138671875 +16024 0.369598388671875 +16025 0.3778076171875 +16026 0.367095947265625 +16027 0.376953125 +16028 0.360809326171875 +16029 0.371978759765625 +16030 0.3018798828125 +16031 0.313140869140625 +16032 0.174530029296875 +16033 0.184417724609375 +16034 0.003814697265625 +16035 0.011199951171875 +16036 -0.1754150390625 +16037 -0.171051025390625 +16038 -0.338623046875 +16039 -0.33740234375 +16040 -0.470184326171875 +16041 -0.47198486328125 +16042 -0.5560302734375 +16043 -0.560394287109375 +16044 -0.574554443359375 +16045 -0.58056640625 +16046 -0.540618896484375 +16047 -0.54754638671875 +16048 -0.500762939453125 +16049 -0.508575439453125 +16050 -0.45098876953125 +16051 -0.459503173828125 +16052 -0.385528564453125 +16053 -0.394378662109375 +16054 -0.343231201171875 +16055 -0.35260009765625 +16056 -0.302032470703125 +16057 -0.31170654296875 +16058 -0.188873291015625 +16059 -0.197418212890625 +16060 -0.002044677734375 +16061 -0.007965087890625 +16062 0.21002197265625 +16063 0.207489013671875 +16064 0.40826416015625 +16065 0.409210205078125 +16066 0.567962646484375 +16067 0.57208251953125 +16068 0.659515380859375 +16069 0.66595458984375 +16070 0.6513671875 +16071 0.65875244140625 +16072 0.560302734375 +16073 0.56744384765625 +16074 0.425140380859375 +16075 0.431396484375 +16076 0.2890625 +16077 0.29443359375 +16078 0.177642822265625 +16079 0.182464599609375 +16080 0.059661865234375 +16081 0.06365966796875 +16082 -0.078582763671875 +16083 -0.075958251953125 +16084 -0.19085693359375 +16085 -0.189422607421875 +16086 -0.27239990234375 +16087 -0.271942138671875 +16088 -0.3419189453125 +16089 -0.342529296875 +16090 -0.363037109375 +16091 -0.364166259765625 +16092 -0.3262939453125 +16093 -0.327239990234375 +16094 -0.276214599609375 +16095 -0.2769775390625 +16096 -0.25250244140625 +16097 -0.253692626953125 +16098 -0.24169921875 +16099 -0.24365234375 +16100 -0.196136474609375 +16101 -0.1983642578125 +16102 -0.11431884765625 +16103 -0.116241455078125 +16104 -0.035186767578125 +16105 -0.036834716796875 +16106 0.036285400390625 +16107 0.034881591796875 +16108 0.092498779296875 +16109 0.09124755859375 +16110 0.110443115234375 +16111 0.10888671875 +16112 0.127197265625 +16113 0.125518798828125 +16114 0.159088134765625 +16115 0.15771484375 +16116 0.1793212890625 +16117 0.17828369140625 +16118 0.1719970703125 +16119 0.17108154296875 +16120 0.131134033203125 +16121 0.129974365234375 +16122 0.083770751953125 +16123 0.082427978515625 +16124 0.02923583984375 +16125 0.027679443359375 +16126 -0.0633544921875 +16127 -0.065643310546875 +16128 -0.15618896484375 +16129 -0.159515380859375 +16130 -0.209686279296875 +16131 -0.21337890625 +16132 -0.23187255859375 +16133 -0.2347412109375 +16134 -0.1986083984375 +16135 -0.200286865234375 +16136 -0.119110107421875 +16137 -0.11956787109375 +16138 -0.0263671875 +16139 -0.025421142578125 +16140 0.082550048828125 +16141 0.084686279296875 +16142 0.173492431640625 +16143 0.1768798828125 +16144 0.20989990234375 +16145 0.21490478515625 +16146 0.205108642578125 +16147 0.211761474609375 +16148 0.16864013671875 +16149 0.176727294921875 +16150 0.12237548828125 +16151 0.13128662109375 +16152 0.096160888671875 +16153 0.1048583984375 +16154 0.069580078125 +16155 0.077423095703125 +16156 0.039794921875 +16157 0.046295166015625 +16158 0.036163330078125 +16159 0.040496826171875 +16160 0.0758056640625 +16161 0.0770263671875 +16162 0.14215087890625 +16163 0.13970947265625 +16164 0.18902587890625 +16165 0.18328857421875 +16166 0.192718505859375 +16167 0.184600830078125 +16168 0.144012451171875 +16169 0.134674072265625 +16170 0.047515869140625 +16171 0.038177490234375 +16172 -0.073272705078125 +16173 -0.08172607421875 +16174 -0.213165283203125 +16175 -0.219879150390625 +16176 -0.361846923828125 +16177 -0.366119384765625 +16178 -0.489471435546875 +16179 -0.4910888671875 +16180 -0.551727294921875 +16181 -0.551239013671875 +16182 -0.505279541015625 +16183 -0.5040283203125 +16184 -0.373443603515625 +16185 -0.3724365234375 +16186 -0.218109130859375 +16187 -0.21746826171875 +16188 -0.0643310546875 +16189 -0.063934326171875 +16190 0.08966064453125 +16191 0.08978271484375 +16192 0.232940673828125 +16193 0.232818603515625 +16194 0.338897705078125 +16195 0.3388671875 +16196 0.390380859375 +16197 0.390960693359375 +16198 0.38409423828125 +16199 0.38580322265625 +16200 0.318817138671875 +16201 0.3221435546875 +16202 0.21881103515625 +16203 0.22381591796875 +16204 0.119415283203125 +16205 0.125640869140625 +16206 0.032867431640625 +16207 0.0396728515625 +16208 -0.013427734375 +16209 -0.007080078125 +16210 -0.021728515625 +16211 -0.016754150390625 +16212 -0.023956298828125 +16213 -0.0206298828125 +16214 -0.001556396484375 +16215 -0.0003662109375 +16216 0.05743408203125 +16217 0.055877685546875 +16218 0.108856201171875 +16219 0.104766845703125 +16220 0.099884033203125 +16221 0.09442138671875 +16222 0.046356201171875 +16223 0.040496826171875 +16224 -0.013916015625 +16225 -0.019744873046875 +16226 -0.071533203125 +16227 -0.076995849609375 +16228 -0.115142822265625 +16229 -0.12005615234375 +16230 -0.15570068359375 +16231 -0.159759521484375 +16232 -0.199066162109375 +16233 -0.201904296875 +16234 -0.2457275390625 +16235 -0.2469482421875 +16236 -0.3031005859375 +16237 -0.302276611328125 +16238 -0.360931396484375 +16239 -0.357879638671875 +16240 -0.39117431640625 +16241 -0.38623046875 +16242 -0.35595703125 +16243 -0.350128173828125 +16244 -0.251495361328125 +16245 -0.245941162109375 +16246 -0.09515380859375 +16247 -0.090850830078125 +16248 0.086151123046875 +16249 0.088623046875 +16250 0.231903076171875 +16251 0.232879638671875 +16252 0.315277099609375 +16253 0.31549072265625 +16254 0.355072021484375 +16255 0.35491943359375 +16256 0.3443603515625 +16257 0.344329833984375 +16258 0.282623291015625 +16259 0.283233642578125 +16260 0.220672607421875 +16261 0.221649169921875 +16262 0.19488525390625 +16263 0.195404052734375 +16264 0.1787109375 +16265 0.178436279296875 +16266 0.15521240234375 +16267 0.154144287109375 +16268 0.15167236328125 +16269 0.149444580078125 +16270 0.158172607421875 +16271 0.154632568359375 +16272 0.1336669921875 +16273 0.12939453125 +16274 0.103240966796875 +16275 0.098480224609375 +16276 0.0899658203125 +16277 0.084625244140625 +16278 0.05792236328125 +16279 0.05255126953125 +16280 -0.005889892578125 +16281 -0.01055908203125 +16282 -0.10101318359375 +16283 -0.104156494140625 +16284 -0.2266845703125 +16285 -0.227569580078125 +16286 -0.353240966796875 +16287 -0.351593017578125 +16288 -0.440155029296875 +16289 -0.4364013671875 +16290 -0.472686767578125 +16291 -0.467559814453125 +16292 -0.46429443359375 +16293 -0.45831298828125 +16294 -0.419219970703125 +16295 -0.41290283203125 +16296 -0.335052490234375 +16297 -0.32904052734375 +16298 -0.229217529296875 +16299 -0.223907470703125 +16300 -0.125213623046875 +16301 -0.120697021484375 +16302 -0.02972412109375 +16303 -0.026031494140625 +16304 0.07537841796875 +16305 0.07794189453125 +16306 0.21087646484375 +16307 0.21160888671875 +16308 0.38653564453125 +16309 0.384521484375 +16310 0.580657958984375 +16311 0.575347900390625 +16312 0.732177734375 +16313 0.72406005859375 +16314 0.79864501953125 +16315 0.788909912109375 +16316 0.777252197265625 +16317 0.76715087890625 +16318 0.664581298828125 +16319 0.65545654296875 +16320 0.459564208984375 +16321 0.452850341796875 +16322 0.1995849609375 +16323 0.196136474609375 +16324 -0.04986572265625 +16325 -0.050140380859375 +16326 -0.231781005859375 +16327 -0.229888916015625 +16328 -0.32867431640625 +16329 -0.325836181640625 +16330 -0.36676025390625 +16331 -0.36376953125 +16332 -0.377197265625 +16333 -0.37432861328125 +16334 -0.375244140625 +16335 -0.372528076171875 +16336 -0.3780517578125 +16337 -0.375244140625 +16338 -0.390045166015625 +16339 -0.386810302734375 +16340 -0.3841552734375 +16341 -0.380615234375 +16342 -0.341064453125 +16343 -0.337677001953125 +16344 -0.28240966796875 +16345 -0.27935791015625 +16346 -0.25152587890625 +16347 -0.248291015625 +16348 -0.266448974609375 +16349 -0.26226806640625 +16350 -0.274017333984375 +16351 -0.26904296875 +16352 -0.2177734375 +16353 -0.21307373046875 +16354 -0.129486083984375 +16355 -0.1256103515625 +16356 -0.069549560546875 +16357 -0.066162109375 +16358 -0.044586181640625 +16359 -0.041259765625 +16360 -0.02593994140625 +16361 -0.022735595703125 +16362 0.019317626953125 +16363 0.021820068359375 +16364 0.12322998046875 +16365 0.12396240234375 +16366 0.2568359375 +16367 0.255157470703125 +16368 0.378326416015625 +16369 0.37432861328125 +16370 0.47943115234375 +16371 0.473358154296875 +16372 0.528045654296875 +16373 0.5206298828125 +16374 0.511322021484375 +16375 0.503570556640625 +16376 0.45672607421875 +16377 0.449249267578125 +16378 0.408294677734375 +16379 0.401031494140625 +16380 0.38482666015625 +16381 0.37744140625 +16382 0.358123779296875 +16383 0.350738525390625 +16384 0.313201904296875 +16385 0.305694580078125 +16386 0.252288818359375 +16387 0.24420166015625 +16388 0.166748046875 +16389 0.158447265625 +16390 0.036468505859375 +16391 0.029754638671875 +16392 -0.141021728515625 +16393 -0.143768310546875 +16394 -0.3348388671875 +16395 -0.33233642578125 +16396 -0.534027099609375 +16397 -0.52520751953125 +16398 -0.721649169921875 +16399 -0.706024169921875 +16400 -0.836761474609375 +16401 -0.816650390625 +16402 -0.833038330078125 +16403 -0.81292724609375 +16404 -0.73028564453125 +16405 -0.713775634765625 +16406 -0.58343505859375 +16407 -0.57159423828125 +16408 -0.441131591796875 +16409 -0.432830810546875 +16410 -0.325439453125 +16411 -0.3187255859375 +16412 -0.20263671875 +16413 -0.19744873046875 +16414 -0.0457763671875 +16415 -0.043548583984375 +16416 0.102935791015625 +16417 0.102508544921875 +16418 0.201507568359375 +16419 0.200469970703125 +16420 0.263824462890625 +16421 0.263336181640625 +16422 0.338470458984375 +16423 0.337188720703125 +16424 0.443634033203125 +16425 0.439178466796875 +16426 0.545135498046875 +16427 0.536712646484375 +16428 0.61761474609375 +16429 0.605621337890625 +16430 0.652984619140625 +16431 0.63824462890625 +16432 0.664093017578125 +16433 0.646881103515625 +16434 0.656951904296875 +16435 0.637420654296875 +16436 0.607696533203125 +16437 0.587249755859375 +16438 0.50213623046875 +16439 0.48309326171875 +16440 0.35369873046875 +16441 0.33795166015625 +16442 0.1773681640625 +16443 0.16632080078125 +16444 -0.034149169921875 +16445 -0.038543701171875 +16446 -0.257720947265625 +16447 -0.25445556640625 +16448 -0.442169189453125 +16449 -0.432525634765625 +16450 -0.57525634765625 +16451 -0.56097412109375 +16452 -0.652191162109375 +16453 -0.63519287109375 +16454 -0.6419677734375 +16455 -0.625640869140625 +16456 -0.562652587890625 +16457 -0.54949951171875 +16458 -0.458648681640625 +16459 -0.449127197265625 +16460 -0.351226806640625 +16461 -0.344879150390625 +16462 -0.26123046875 +16463 -0.256683349609375 +16464 -0.19281005859375 +16465 -0.18865966796875 +16466 -0.142608642578125 +16467 -0.137786865234375 +16468 -0.102783203125 +16469 -0.096771240234375 +16470 -0.06341552734375 +16471 -0.056365966796875 +16472 -0.0123291015625 +16473 -0.005096435546875 +16474 0.062591552734375 +16475 0.06842041015625 +16476 0.148651123046875 +16477 0.1519775390625 +16478 0.241851806640625 +16479 0.24169921875 +16480 0.34942626953125 +16481 0.344451904296875 +16482 0.457794189453125 +16483 0.447296142578125 +16484 0.544525146484375 +16485 0.5289306640625 +16486 0.5736083984375 +16487 0.55517578125 +16488 0.507354736328125 +16489 0.490234375 +16490 0.35198974609375 +16491 0.340118408203125 +16492 0.147247314453125 +16493 0.14276123046875 +16494 -0.0545654296875 +16495 -0.0518798828125 +16496 -0.215667724609375 +16497 -0.20770263671875 +16498 -0.33447265625 +16499 -0.32305908203125 +16500 -0.402679443359375 +16501 -0.389923095703125 +16502 -0.441131591796875 +16503 -0.42803955078125 +16504 -0.49578857421875 +16505 -0.4810791015625 +16506 -0.560333251953125 +16507 -0.542999267578125 +16508 -0.60101318359375 +16509 -0.581695556640625 +16510 -0.584625244140625 +16511 -0.565521240234375 +16512 -0.47979736328125 +16513 -0.46466064453125 +16514 -0.2799072265625 +16515 -0.27288818359375 +16516 -0.009490966796875 +16517 -0.013671875 +16518 0.268218994140625 +16519 0.252655029296875 +16520 0.482269287109375 +16521 0.45849609375 +16522 0.60321044921875 +16523 0.575714111328125 +16524 0.649993896484375 +16525 0.6221923828125 +16526 0.663665771484375 +16527 0.63690185546875 +16528 0.6412353515625 +16529 0.616912841796875 +16530 0.5723876953125 +16531 0.5523681640625 +16532 0.498077392578125 +16533 0.482177734375 +16534 0.439483642578125 +16535 0.426483154296875 +16536 0.375640869140625 +16537 0.365325927734375 +16538 0.274688720703125 +16539 0.268463134765625 +16540 0.1090087890625 +16541 0.109619140625 +16542 -0.09912109375 +16543 -0.08990478515625 +16544 -0.31793212890625 +16545 -0.2998046875 +16546 -0.54864501953125 +16547 -0.521148681640625 +16548 -0.773529052734375 +16549 -0.7369384765625 +16550 -0.863800048828125 +16551 -0.859100341796875 +16552 -0.870391845703125 +16553 -0.866973876953125 +16554 -0.868988037109375 +16555 -0.8670654296875 +16556 -0.861114501953125 +16557 -0.86077880859375 +16558 -0.766510009765625 +16559 -0.779083251953125 +16560 -0.53094482421875 +16561 -0.560455322265625 +16562 -0.215576171875 +16563 -0.262725830078125 +16564 0.13641357421875 +16565 0.0731201171875 +16566 0.473846435546875 +16567 0.398193359375 +16568 0.761444091796875 +16569 0.6785888671875 +16570 0.86737060546875 +16571 0.858184814453125 +16572 0.870361328125 +16573 0.870361328125 +16574 0.864898681640625 +16575 0.870361328125 +16576 0.833465576171875 +16577 0.86273193359375 +16578 0.679901123046875 +16579 0.816436767578125 +16580 0.498748779296875 +16581 0.666229248046875 +16582 0.3109130859375 +16583 0.49859619140625 +16584 0.119598388671875 +16585 0.3162841796875 +16586 -0.107330322265625 +16587 0.08905029296875 +16588 -0.378570556640625 +16589 -0.190460205078125 +16590 -0.654327392578125 +16591 -0.482940673828125 +16592 -0.857147216796875 +16593 -0.733367919921875 +16594 -0.870391845703125 +16595 -0.859832763671875 +16596 -0.870391845703125 +16597 -0.869110107421875 +16598 -0.86444091796875 +16599 -0.870391845703125 +16600 -0.85723876953125 +16601 -0.869659423828125 +16602 -0.790008544921875 +16603 -0.86541748046875 +16604 -0.62847900390625 +16605 -0.834625244140625 +16606 -0.3956298828125 +16607 -0.632965087890625 +16608 -0.126708984375 +16609 -0.38238525390625 +16610 0.150115966796875 +16611 -0.109832763671875 +16612 0.424041748046875 +16613 0.173492431640625 +16614 0.670623779296875 +16615 0.44268798828125 +16616 0.854522705078125 +16617 0.662322998046875 +16618 0.866485595703125 +16619 0.817657470703125 +16620 0.86920166015625 +16621 0.85906982421875 +16622 0.8653564453125 +16623 0.861541748046875 +16624 0.857147216796875 +16625 0.859588623046875 +16626 0.766845703125 +16627 0.84326171875 +16628 0.628509521484375 +16629 0.752777099609375 +16630 0.462127685546875 +16631 0.625946044921875 +16632 0.297210693359375 +16633 0.489471435546875 +16634 0.14862060546875 +16635 0.356658935546875 +16636 -0.00537109375 +16637 0.20672607421875 +16638 -0.15753173828125 +16639 0.047088623046875 +16640 -0.31304931640625 +16641 -0.125640869140625 +16642 -0.48876953125 +16643 -0.32574462890625 +16644 -0.6416015625 +16645 -0.511383056640625 +16646 -0.751373291015625 +16647 -0.661041259765625 +16648 -0.84619140625 +16649 -0.79754638671875 +16650 -0.861297607421875 +16651 -0.860504150390625 +16652 -0.863250732421875 +16653 -0.86688232421875 +16654 -0.856597900390625 +16655 -0.86456298828125 +16656 -0.7498779296875 +16657 -0.85498046875 +16658 -0.624542236328125 +16659 -0.75927734375 +16660 -0.47808837890625 +16661 -0.629669189453125 +16662 -0.253387451171875 +16663 -0.41741943359375 +16664 0.003692626953125 +16665 -0.165313720703125 +16666 0.2257080078125 +16667 0.06341552734375 +16668 0.427154541015625 +16669 0.28045654296875 +16670 0.643218994140625 +16671 0.5162353515625 +16672 0.855926513671875 +16673 0.762908935546875 +16674 0.870361328125 +16675 0.866912841796875 +16676 0.870361328125 +16677 0.870361328125 +16678 0.862762451171875 +16679 0.866241455078125 +16680 0.79669189453125 +16681 0.85491943359375 +16682 0.595794677734375 +16683 0.68603515625 +16684 0.362152099609375 +16685 0.47540283203125 +16686 0.1270751953125 +16687 0.255584716796875 +16688 -0.086944580078125 +16689 0.047637939453125 +16690 -0.2784423828125 +16691 -0.146270751953125 +16692 -0.484832763671875 +16693 -0.359344482421875 +16694 -0.729583740234375 +16695 -0.611785888671875 +16696 -0.86688232421875 +16697 -0.855194091796875 +16698 -0.870391845703125 +16699 -0.870391845703125 +16700 -0.86859130859375 +16701 -0.870391845703125 +16702 -0.86279296875 +16703 -0.866119384765625 +16704 -0.817962646484375 +16705 -0.855224609375 +16706 -0.6116943359375 +16707 -0.6688232421875 +16708 -0.3128662109375 +16709 -0.38580322265625 +16710 0.039398193359375 +16711 -0.0484619140625 +16712 0.422821044921875 +16713 0.32177734375 +16714 0.805145263671875 +16715 0.69415283203125 +16716 0.870361328125 +16717 0.870361328125 +16718 0.870361328125 +16719 0.870361328125 +16720 0.860015869140625 +16721 0.860382080078125 +16722 0.727935791015625 +16723 0.736968994140625 +16724 0.48114013671875 +16725 0.49810791015625 +16726 0.2059326171875 +16727 0.23040771484375 +16728 -0.06103515625 +16729 -0.031494140625 +16730 -0.29913330078125 +16731 -0.267730712890625 +16732 -0.516204833984375 +16733 -0.48455810546875 +16734 -0.7252197265625 +16735 -0.69293212890625 +16736 -0.85980224609375 +16737 -0.85626220703125 +16738 -0.870391845703125 +16739 -0.869354248046875 +16740 -0.870391845703125 +16741 -0.870391845703125 +16742 -0.858062744140625 +16743 -0.85955810546875 +16744 -0.673004150390625 +16745 -0.70391845703125 +16746 -0.42694091796875 +16747 -0.472930908203125 +16748 -0.2100830078125 +16749 -0.26458740234375 +16750 -0.0362548828125 +16751 -0.092193603515625 +16752 0.10943603515625 +16753 0.05712890625 +16754 0.23516845703125 +16755 0.190032958984375 +16756 0.373687744140625 +16757 0.33563232421875 +16758 0.517791748046875 +16759 0.48626708984375 +16760 0.602783203125 +16761 0.581451416015625 +16762 0.635711669921875 +16763 0.626800537109375 +16764 0.655181884765625 +16765 0.65704345703125 +16766 0.65948486328125 +16767 0.670013427734375 +16768 0.651275634765625 +16769 0.667755126953125 +16770 0.61846923828125 +16771 0.638946533203125 +16772 0.53753662109375 +16773 0.56201171875 +16774 0.404144287109375 +16775 0.4332275390625 +16776 0.22186279296875 +16777 0.25628662109375 +16778 0.003997802734375 +16779 0.044036865234375 +16780 -0.22100830078125 +16781 -0.1766357421875 +16782 -0.42449951171875 +16783 -0.37860107421875 +16784 -0.579833984375 +16785 -0.536468505859375 +16786 -0.641876220703125 +16787 -0.60791015625 +16788 -0.6177978515625 +16789 -0.598785400390625 +16790 -0.575531005859375 +16791 -0.570892333984375 +16792 -0.526336669921875 +16793 -0.534027099609375 +16794 -0.42645263671875 +16795 -0.447601318359375 +16796 -0.2581787109375 +16797 -0.295074462890625 +16798 -0.068695068359375 +16799 -0.11981201171875 +16800 0.09222412109375 +16801 0.032257080078125 +16802 0.232147216796875 +16803 0.167755126953125 +16804 0.3509521484375 +16805 0.2861328125 +16806 0.410064697265625 +16807 0.351318359375 +16808 0.372955322265625 +16809 0.329071044921875 +16810 0.2554931640625 +16811 0.23333740234375 +16812 0.10711669921875 +16813 0.10888671875 +16814 -0.052886962890625 +16815 -0.027191162109375 +16816 -0.186279296875 +16817 -0.1402587890625 +16818 -0.23291015625 +16819 -0.17547607421875 +16820 -0.209442138671875 +16821 -0.148529052734375 +16822 -0.174163818359375 +16823 -0.11328125 +16824 -0.126739501953125 +16825 -0.069488525390625 +16826 -0.048126220703125 +16827 0.000396728515625 +16828 0.0426025390625 +16829 0.07904052734375 +16830 0.10748291015625 +16831 0.131866455078125 +16832 0.1409912109375 +16833 0.15423583984375 +16834 0.19708251953125 +16835 0.196258544921875 +16836 0.273651123046875 +16837 0.256591796875 +16838 0.31768798828125 +16839 0.287017822265625 +16840 0.341094970703125 +16841 0.299041748046875 +16842 0.368011474609375 +16843 0.315399169921875 +16844 0.37249755859375 +16845 0.312591552734375 +16846 0.30072021484375 +16847 0.241455078125 +16848 0.1517333984375 +16849 0.101318359375 +16850 -0.01470947265625 +16851 -0.052734375 +16852 -0.1883544921875 +16853 -0.21124267578125 +16854 -0.372711181640625 +16855 -0.3775634765625 +16856 -0.51397705078125 +16857 -0.50244140625 +16858 -0.57177734375 +16859 -0.549072265625 +16860 -0.53948974609375 +16861 -0.511749267578125 +16862 -0.43511962890625 +16863 -0.407501220703125 +16864 -0.2962646484375 +16865 -0.2713623046875 +16866 -0.161102294921875 +16867 -0.138916015625 +16868 -0.0435791015625 +16869 -0.02337646484375 +16870 0.060394287109375 +16871 0.07855224609375 +16872 0.13665771484375 +16873 0.153564453125 +16874 0.170135498046875 +16875 0.18756103515625 +16876 0.16552734375 +16877 0.18475341796875 +16878 0.15728759765625 +16879 0.176788330078125 +16880 0.150787353515625 +16881 0.168701171875 +16882 0.12200927734375 +16883 0.138519287109375 +16884 0.080108642578125 +16885 0.094940185546875 +16886 0.05126953125 +16887 0.062347412109375 +16888 0.062896728515625 +16889 0.06634521484375 +16890 0.09271240234375 +16891 0.086822509765625 +16892 0.092987060546875 +16893 0.08026123046875 +16894 0.07855224609375 +16895 0.060638427734375 +16896 0.06427001953125 +16897 0.0421142578125 +16898 0.0347900390625 +16899 0.010772705078125 +16900 -0.01171875 +16901 -0.03497314453125 +16902 -0.056060791015625 +16903 -0.077484130859375 +16904 -0.055511474609375 +16905 -0.078125 +16906 -0.010467529296875 +16907 -0.037139892578125 +16908 0.02508544921875 +16909 -0.00311279296875 +16910 0.025665283203125 +16911 0.0008544921875 +16912 0.017333984375 +16913 -0.001953125 +16914 0.00189208984375 +16915 -0.01025390625 +16916 -0.03173828125 +16917 -0.034332275390625 +16918 -0.071502685546875 +16919 -0.063751220703125 +16920 -0.13543701171875 +16921 -0.115081787109375 +16922 -0.219970703125 +16923 -0.18548583984375 +16924 -0.300506591796875 +16925 -0.25311279296875 +16926 -0.376312255859375 +16927 -0.317535400390625 +16928 -0.416107177734375 +16929 -0.35076904296875 +16930 -0.371124267578125 +16931 -0.309051513671875 +16932 -0.242279052734375 +16933 -0.1932373046875 +16934 -0.069732666015625 +16935 -0.0394287109375 +16936 0.125640869140625 +16937 0.1336669921875 +16938 0.31268310546875 +16939 0.2982177734375 +16940 0.45501708984375 +16941 0.421722412109375 +16942 0.554779052734375 +16943 0.506378173828125 +16944 0.61065673828125 +16945 0.551300048828125 +16946 0.610931396484375 +16947 0.546234130859375 +16948 0.531463623046875 +16949 0.46978759765625 +16950 0.3883056640625 +16951 0.33660888671875 +16952 0.23468017578125 +16953 0.19482421875 +16954 0.095245361328125 +16955 0.06683349609375 +16956 -0.00396728515625 +16957 -0.02386474609375 +16958 -0.04852294921875 +16959 -0.064239501953125 +16960 -0.055145263671875 +16961 -0.069305419921875 +16962 -0.0758056640625 +16963 -0.085968017578125 +16964 -0.138702392578125 +16965 -0.139739990234375 +16966 -0.209197998046875 +16967 -0.199615478515625 +16968 -0.289031982421875 +16969 -0.26739501953125 +16970 -0.37884521484375 +16971 -0.343902587890625 +16972 -0.456329345703125 +16973 -0.409271240234375 +16974 -0.51641845703125 +16975 -0.45916748046875 +16976 -0.519287109375 +16977 -0.457977294921875 +16978 -0.458251953125 +16979 -0.399871826171875 +16980 -0.384796142578125 +16981 -0.33135986328125 +16982 -0.323699951171875 +16983 -0.27484130859375 +16984 -0.269287109375 +16985 -0.225250244140625 +16986 -0.1951904296875 +16987 -0.158905029296875 +16988 -0.100006103515625 +16989 -0.074462890625 +16990 -0.01055908203125 +16991 0.003997802734375 +16992 0.1033935546875 +16993 0.10382080078125 +16994 0.24908447265625 +16995 0.231689453125 +16996 0.373199462890625 +16997 0.339813232421875 +16998 0.45806884765625 +16999 0.412506103515625 +17000 0.511474609375 +17001 0.456939697265625 +17002 0.565399169921875 +17003 0.50213623046875 +17004 0.61138916015625 +17005 0.540679931640625 +17006 0.5897216796875 +17007 0.5189208984375 +17008 0.4906005859375 +17009 0.42816162109375 +17010 0.33148193359375 +17011 0.284210205078125 +17012 0.147796630859375 +17013 0.118927001953125 +17014 -0.01873779296875 +17015 -0.0301513671875 +17016 -0.140289306640625 +17017 -0.1380615234375 +17018 -0.191986083984375 +17019 -0.182464599609375 +17020 -0.184295654296875 +17021 -0.172943115234375 +17022 -0.161834716796875 +17023 -0.149810791015625 +17024 -0.166595458984375 +17025 -0.151031494140625 +17026 -0.19390869140625 +17027 -0.172576904296875 +17028 -0.22442626953125 +17029 -0.197174072265625 +17030 -0.279754638671875 +17031 -0.244415283203125 +17032 -0.3389892578125 +17033 -0.295623779296875 +17034 -0.3543701171875 +17035 -0.307952880859375 +17036 -0.348175048828125 +17037 -0.301513671875 +17038 -0.32598876953125 +17039 -0.281341552734375 +17040 -0.2581787109375 +17041 -0.220794677734375 +17042 -0.139801025390625 +17043 -0.1153564453125 +17044 0.014617919921875 +17045 0.022003173828125 +17046 0.144378662109375 +17047 0.13671875 +17048 0.221038818359375 +17049 0.203338623046875 +17050 0.27069091796875 +17051 0.2454833984375 +17052 0.294036865234375 +17053 0.263916015625 +17054 0.311767578125 +17055 0.277435302734375 +17056 0.339141845703125 +17057 0.29986572265625 +17058 0.360260009765625 +17059 0.316802978515625 +17060 0.360504150390625 +17061 0.315277099609375 +17062 0.308380126953125 +17063 0.2674560546875 +17064 0.18170166015625 +17065 0.15374755859375 +17066 0.0047607421875 +17067 -0.004150390625 +17068 -0.17559814453125 +17069 -0.16461181640625 +17070 -0.3143310546875 +17071 -0.287628173828125 +17072 -0.36785888671875 +17073 -0.33453369140625 +17074 -0.36248779296875 +17075 -0.32867431640625 +17076 -0.343536376953125 +17077 -0.310394287109375 +17078 -0.3018798828125 +17079 -0.27166748046875 +17080 -0.231414794921875 +17081 -0.207183837890625 +17082 -0.117645263671875 +17083 -0.10418701171875 +17084 0.007049560546875 +17085 0.008453369140625 +17086 0.087982177734375 +17087 0.082061767578125 +17088 0.13946533203125 +17089 0.1292724609375 +17090 0.17425537109375 +17091 0.161346435546875 +17092 0.188201904296875 +17093 0.17449951171875 +17094 0.171234130859375 +17095 0.1597900390625 +17096 0.118438720703125 +17097 0.112823486328125 +17098 0.05706787109375 +17099 0.057830810546875 +17100 -0.010711669921875 +17101 -0.00323486328125 +17102 -0.0914306640625 +17103 -0.07611083984375 +17104 -0.162322998046875 +17105 -0.140472412109375 +17106 -0.194549560546875 +17107 -0.170684814453125 +17108 -0.1492919921875 +17109 -0.132171630859375 +17110 -0.02166748046875 +17111 -0.020477294921875 +17112 0.124053955078125 +17113 0.107391357421875 +17114 0.211151123046875 +17115 0.18341064453125 +17116 0.240447998046875 +17117 0.2083740234375 +17118 0.242218017578125 +17119 0.209197998046875 +17120 0.2257080078125 +17121 0.19415283203125 +17122 0.194366455078125 +17123 0.166290283203125 +17124 0.115509033203125 +17125 0.096588134765625 +17126 0.0128173828125 +17127 0.00604248046875 +17128 -0.053802490234375 +17129 -0.052215576171875 +17130 -0.110626220703125 +17131 -0.101531982421875 +17132 -0.199493408203125 +17133 -0.179168701171875 +17134 -0.29437255859375 +17135 -0.262054443359375 +17136 -0.33221435546875 +17137 -0.294281005859375 +17138 -0.27972412109375 +17139 -0.246368408203125 +17140 -0.185333251953125 +17141 -0.16143798828125 +17142 -0.128204345703125 +17143 -0.109771728515625 +17144 -0.115692138671875 +17145 -0.09796142578125 +17146 -0.116455078125 +17147 -0.09820556640625 +17148 -0.105926513671875 +17149 -0.088714599609375 +17150 -0.053955078125 +17151 -0.042724609375 +17152 0.048797607421875 +17153 0.0478515625 +17154 0.157318115234375 +17155 0.1434326171875 +17156 0.212005615234375 +17157 0.192230224609375 +17158 0.218475341796875 +17159 0.198883056640625 +17160 0.23724365234375 +17161 0.21514892578125 +17162 0.30535888671875 +17163 0.272796630859375 +17164 0.38128662109375 +17165 0.3363037109375 +17166 0.404449462890625 +17167 0.353973388671875 +17168 0.3944091796875 +17169 0.34271240234375 +17170 0.3885498046875 +17171 0.334716796875 +17172 0.362640380859375 +17173 0.309478759765625 +17174 0.27362060546875 +17175 0.230316162109375 +17176 0.11712646484375 +17177 0.09368896484375 +17178 -0.054901123046875 +17179 -0.055816650390625 +17180 -0.19085693359375 +17181 -0.173858642578125 +17182 -0.28570556640625 +17183 -0.256072998046875 +17184 -0.339263916015625 +17185 -0.302276611328125 +17186 -0.3775634765625 +17187 -0.334747314453125 +17188 -0.445709228515625 +17189 -0.392120361328125 +17190 -0.535064697265625 +17191 -0.46710205078125 +17192 -0.629058837890625 +17193 -0.54559326171875 +17194 -0.697601318359375 +17195 -0.601959228515625 +17196 -0.70391845703125 +17197 -0.6048583984375 +17198 -0.6424560546875 +17199 -0.5496826171875 +17200 -0.491241455078125 +17201 -0.417755126953125 +17202 -0.265716552734375 +17203 -0.222412109375 +17204 -0.023712158203125 +17205 -0.0133056640625 +17206 0.201751708984375 +17207 0.181182861328125 +17208 0.375823974609375 +17209 0.3311767578125 +17210 0.485076904296875 +17211 0.425140380859375 +17212 0.56884765625 +17213 0.496734619140625 +17214 0.634765625 +17215 0.552520751953125 +17216 0.63763427734375 +17217 0.553863525390625 +17218 0.5660400390625 +17219 0.491058349609375 +17220 0.4720458984375 +17221 0.40875244140625 +17222 0.40692138671875 +17223 0.3509521484375 +17224 0.3778076171875 +17225 0.323883056640625 +17226 0.376953125 +17227 0.321044921875 +17228 0.371978759765625 +17229 0.3148193359375 +17230 0.313140869140625 +17231 0.26275634765625 +17232 0.184417724609375 +17233 0.151214599609375 +17234 0.011199951171875 +17235 0.001983642578125 +17236 -0.171051025390625 +17237 -0.154510498046875 +17238 -0.33740234375 +17239 -0.29693603515625 +17240 -0.47198486328125 +17241 -0.411712646484375 +17242 -0.560394287109375 +17243 -0.486572265625 +17244 -0.58056640625 +17245 -0.502685546875 +17246 -0.54754638671875 +17247 -0.472991943359375 +17248 -0.508575439453125 +17249 -0.438018798828125 +17250 -0.459503173828125 +17251 -0.394287109375 +17252 -0.394378662109375 +17253 -0.336822509765625 +17254 -0.35260009765625 +17255 -0.2994384765625 +17256 -0.31170654296875 +17257 -0.262969970703125 +17258 -0.197418212890625 +17259 -0.1639404296875 +17260 -0.007965087890625 +17261 -0.0008544921875 +17262 0.207489013671875 +17263 0.18414306640625 +17264 0.409210205078125 +17265 0.35699462890625 +17266 0.57208251953125 +17267 0.4962158203125 +17268 0.66595458984375 +17269 0.57598876953125 +17270 0.65875244140625 +17271 0.56890869140625 +17272 0.56744384765625 +17273 0.48956298828125 +17274 0.431396484375 +17275 0.371734619140625 +17276 0.29443359375 +17277 0.2530517578125 +17278 0.182464599609375 +17279 0.15576171875 +17280 0.06365966796875 +17281 0.05267333984375 +17282 -0.075958251953125 +17283 -0.068084716796875 +17284 -0.189422607421875 +17285 -0.166229248046875 +17286 -0.271942138671875 +17287 -0.23760986328125 +17288 -0.342529296875 +17289 -0.2984619140625 +17290 -0.364166259765625 +17291 -0.317108154296875 +17292 -0.327239990234375 +17293 -0.285369873046875 +17294 -0.2769775390625 +17295 -0.241943359375 +17296 -0.253692626953125 +17297 -0.22137451171875 +17298 -0.24365234375 +17299 -0.2119140625 +17300 -0.1983642578125 +17301 -0.172119140625 +17302 -0.116241455078125 +17303 -0.1007080078125 +17304 -0.036834716796875 +17305 -0.03155517578125 +17306 0.034881591796875 +17307 0.030975341796875 +17308 0.09124755859375 +17309 0.080291748046875 +17310 0.10888671875 +17311 0.0963134765625 +17312 0.125518798828125 +17313 0.11126708984375 +17314 0.15771484375 +17315 0.13934326171875 +17316 0.17828369140625 +17317 0.157196044921875 +17318 0.17108154296875 +17319 0.150970458984375 +17320 0.129974365234375 +17321 0.115478515625 +17322 0.082427978515625 +17323 0.074249267578125 +17324 0.027679443359375 +17325 0.02667236328125 +17326 -0.065643310546875 +17327 -0.054046630859375 +17328 -0.15936279296875 +17329 -0.135162353515625 +17330 -0.21307373046875 +17331 -0.18206787109375 +17332 -0.234649658203125 +17333 -0.201446533203125 +17334 -0.2001953125 +17335 -0.17279052734375 +17336 -0.119171142578125 +17337 -0.10418701171875 +17338 -0.024749755859375 +17339 -0.02398681640625 +17340 0.085784912109375 +17341 0.070159912109375 +17342 0.178131103515625 +17343 0.14892578125 +17344 0.215576171875 +17345 0.180908203125 +17346 0.211456298828125 +17347 0.177490234375 +17348 0.17523193359375 +17349 0.146759033203125 +17350 0.128753662109375 +17351 0.107421875 +17352 0.1019287109375 +17353 0.085052490234375 +17354 0.0743408203125 +17355 0.062164306640625 +17356 0.04327392578125 +17357 0.036376953125 +17358 0.038177490234375 +17359 0.0328369140625 +17360 0.076263427734375 +17361 0.06622314453125 +17362 0.14105224609375 +17363 0.12237548828125 +17364 0.186431884765625 +17365 0.16180419921875 +17366 0.188812255859375 +17367 0.164276123046875 +17368 0.1390380859375 +17369 0.121917724609375 +17370 0.041778564453125 +17371 0.038726806640625 +17372 -0.079437255859375 +17373 -0.06512451171875 +17374 -0.219390869140625 +17375 -0.1851806640625 +17376 -0.367828369140625 +17377 -0.312591552734375 +17378 -0.494873046875 +17379 -0.421783447265625 +17380 -0.556243896484375 +17381 -0.474853515625 +17382 -0.508697509765625 +17383 -0.43475341796875 +17384 -0.3756103515625 +17385 -0.321441650390625 +17386 -0.218902587890625 +17387 -0.187896728515625 +17388 -0.063751220703125 +17389 -0.055633544921875 +17390 0.091552734375 +17391 0.076812744140625 +17392 0.23602294921875 +17393 0.2000732421875 +17394 0.342987060546875 +17395 0.29132080078125 +17396 0.39520263671875 +17397 0.335845947265625 +17398 0.389373779296875 +17399 0.330810546875 +17400 0.324249267578125 +17401 0.275177001953125 +17402 0.224090576171875 +17403 0.189666748046875 +17404 0.124267578125 +17405 0.10455322265625 +17406 0.037078857421875 +17407 0.030303955078125 +17408 -0.010101318359375 +17409 -0.01007080078125 +17410 -0.019439697265625 +17411 -0.01824951171875 +17412 -0.022796630859375 +17413 -0.020843505859375 +17414 -0.001556396484375 +17415 -0.00274658203125 +17416 0.056304931640625 +17417 0.045745849609375 +17418 0.106719970703125 +17419 0.088134765625 +17420 0.096893310546875 +17421 0.080780029296875 +17422 0.042694091796875 +17423 0.03668212890625 +17424 -0.018035888671875 +17425 -0.01300048828125 +17426 -0.07586669921875 +17427 -0.060516357421875 +17428 -0.11944580078125 +17429 -0.09649658203125 +17430 -0.15972900390625 +17431 -0.129974365234375 +17432 -0.202606201171875 +17433 -0.165771484375 +17434 -0.24859619140625 +17435 -0.2042236328125 +17436 -0.30517578125 +17437 -0.251434326171875 +17438 -0.36212158203125 +17439 -0.298980712890625 +17440 -0.39141845703125 +17441 -0.32373046875 +17442 -0.35528564453125 +17443 -0.294464111328125 +17444 -0.249969482421875 +17445 -0.208099365234375 +17446 -0.092864990234375 +17447 -0.07891845703125 +17448 0.08905029296875 +17449 0.07086181640625 +17450 0.2352294921875 +17451 0.191314697265625 +17452 0.318817138671875 +17453 0.260345458984375 +17454 0.358642578125 +17455 0.293426513671875 +17456 0.347747802734375 +17457 0.284820556640625 +17458 0.28564453125 +17459 0.234130859375 +17460 0.223175048828125 +17461 0.183197021484375 +17462 0.196746826171875 +17463 0.161956787109375 +17464 0.179840087890625 +17465 0.1485595703125 +17466 0.155548095703125 +17467 0.129058837890625 +17468 0.151214599609375 +17469 0.1259765625 +17470 0.156951904296875 +17471 0.131103515625 +17472 0.13177490234375 +17473 0.11065673828125 +17474 0.100799560546875 +17475 0.085296630859375 +17476 0.087127685546875 +17477 0.074066162109375 +17478 0.05487060546875 +17479 0.047393798828125 +17480 -0.009002685546875 +17481 -0.00543212890625 +17482 -0.10400390625 +17483 -0.083984375 +17484 -0.229400634765625 +17485 -0.18768310546875 +17486 -0.35552978515625 +17487 -0.29205322265625 +17488 -0.441925048828125 +17489 -0.36370849609375 +17490 -0.473846435546875 +17491 -0.3905029296875 +17492 -0.464813232421875 +17493 -0.383514404296875 +17494 -0.419097900390625 +17495 -0.346221923828125 +17496 -0.334320068359375 +17497 -0.27667236328125 +17498 -0.227935791015625 +17499 -0.189239501953125 +17500 -0.12347412109375 +17501 -0.103302001953125 +17502 -0.02764892578125 +17503 -0.02435302734375 +17504 0.077667236328125 +17505 0.062530517578125 +17506 0.2132568359375 +17507 0.1744384765625 +17508 0.38885498046875 +17509 0.319366455078125 +17510 0.582794189453125 +17511 0.479461669921875 +17512 0.734039306640625 +17513 0.604400634765625 +17514 0.800140380859375 +17515 0.659210205078125 +17516 0.7783203125 +17517 0.64154052734375 +17518 0.6651611328125 +17519 0.548583984375 +17520 0.45965576171875 +17521 0.3795166015625 +17522 0.199188232421875 +17523 0.16510009765625 +17524 -0.050689697265625 +17525 -0.0406494140625 +17526 -0.23297119140625 +17527 -0.190765380859375 +17528 -0.33013916015625 +17529 -0.27081298828125 +17530 -0.368408203125 +17531 -0.3023681640625 +17532 -0.378936767578125 +17533 -0.31109619140625 +17534 -0.376983642578125 +17535 -0.30963134765625 +17536 -0.37969970703125 +17537 -0.31207275390625 +17538 -0.391510009765625 +17539 -0.322052001953125 +17540 -0.385345458984375 +17541 -0.3172607421875 +17542 -0.3419189453125 +17543 -0.281768798828125 +17544 -0.28289794921875 +17545 -0.233428955078125 +17546 -0.251617431640625 +17547 -0.207916259765625 +17548 -0.266143798828125 +17549 -0.2200927734375 +17550 -0.273345947265625 +17551 -0.2261962890625 +17552 -0.216796875 +17553 -0.179718017578125 +17554 -0.128265380859375 +17555 -0.1068115234375 +17556 -0.068145751953125 +17557 -0.0572509765625 +17558 -0.0430908203125 +17559 -0.0364990234375 +17560 -0.024444580078125 +17561 -0.020965576171875 +17562 0.020721435546875 +17563 0.0164794921875 +17564 0.124481201171875 +17565 0.10223388671875 +17566 0.25787353515625 +17567 0.21240234375 +17568 0.379119873046875 +17569 0.31256103515625 +17570 0.47991943359375 +17571 0.3958740234375 +17572 0.5281982421875 +17573 0.435882568359375 +17574 0.511138916015625 +17575 0.4219970703125 +17576 0.456207275390625 +17577 0.376861572265625 +17578 0.407470703125 +17579 0.3367919921875 +17580 0.383758544921875 +17581 0.317291259765625 +17582 0.35687255859375 +17583 0.29510498046875 +17584 0.31182861328125 +17585 0.257904052734375 +17586 0.250885009765625 +17587 0.20751953125 +17588 0.1654052734375 +17589 0.136871337890625 +17590 0.035247802734375 +17591 0.029388427734375 +17592 -0.142059326171875 +17593 -0.116943359375 +17594 -0.33563232421875 +17595 -0.27667236328125 +17596 -0.5345458984375 +17597 -0.440765380859375 +17598 -0.72186279296875 +17599 -0.595245361328125 +17600 -0.836669921875 +17601 -0.68994140625 +17602 -0.8326416015625 +17603 -0.68670654296875 +17604 -0.7296142578125 +17605 -0.60186767578125 +17606 -0.582550048828125 +17607 -0.480712890625 +17608 -0.440093994140625 +17609 -0.363311767578125 +17610 -0.324310302734375 +17611 -0.267852783203125 +17612 -0.20147705078125 +17613 -0.16656494140625 +17614 -0.044647216796875 +17615 -0.0372314453125 +17616 0.103973388671875 +17617 0.085357666015625 +17618 0.202392578125 +17619 0.166595458984375 +17620 0.264495849609375 +17621 0.2178955078125 +17622 0.338897705078125 +17623 0.279327392578125 +17624 0.443817138671875 +17625 0.365875244140625 +17626 0.545074462890625 +17627 0.44940185546875 +17628 0.6173095703125 +17629 0.50897216796875 +17630 0.6524658203125 +17631 0.537994384765625 +17632 0.66339111328125 +17633 0.547027587890625 +17634 0.6561279296875 +17635 0.541046142578125 +17636 0.606781005859375 +17637 0.500335693359375 +17638 0.501190185546875 +17639 0.413238525390625 +17640 0.352783203125 +17641 0.29083251953125 +17642 0.176544189453125 +17643 0.145477294921875 +17644 -0.034820556640625 +17645 -0.02880859375 +17646 -0.258209228515625 +17647 -0.212982177734375 +17648 -0.44244384765625 +17649 -0.364898681640625 +17650 -0.5753173828125 +17651 -0.47442626953125 +17652 -0.65203857421875 +17653 -0.53765869140625 +17654 -0.641632080078125 +17655 -0.529083251953125 +17656 -0.562164306640625 +17657 -0.463592529296875 +17658 -0.458038330078125 +17659 -0.377777099609375 +17660 -0.350555419921875 +17661 -0.289154052734375 +17662 -0.260528564453125 +17663 -0.214874267578125 +17664 -0.192108154296875 +17665 -0.158233642578125 +17666 -0.141937255859375 +17667 -0.11639404296875 +17668 -0.1021728515625 +17669 -0.08319091796875 +17670 -0.062896728515625 +17671 -0.050567626953125 +17672 -0.011932373046875 +17673 -0.00872802734375 +17674 0.062835693359375 +17675 0.05194091796875 +17676 0.148712158203125 +17677 0.121368408203125 +17678 0.241729736328125 +17679 0.19635009765625 +17680 0.34912109375 +17681 0.2825927734375 +17682 0.457305908203125 +17683 0.369293212890625 +17684 0.54388427734375 +17685 0.438629150390625 +17686 0.5728759765625 +17687 0.462066650390625 +17688 0.506591796875 +17689 0.409698486328125 +17690 0.351226806640625 +17691 0.286407470703125 +17692 0.146514892578125 +17693 0.123626708984375 +17694 -0.05523681640625 +17695 -0.037139892578125 +17696 -0.21624755859375 +17697 -0.165924072265625 +17698 -0.334930419921875 +17699 -0.26141357421875 +17700 -0.402984619140625 +17701 -0.31695556640625 +17702 -0.4412841796875 +17703 -0.3489990234375 +17704 -0.49578857421875 +17705 -0.39385986328125 +17706 -0.5601806640625 +17707 -0.4464111328125 +17708 -0.600738525390625 +17709 -0.479888916015625 +17710 -0.584228515625 +17711 -0.4678955078125 +17712 -0.47930908203125 +17713 -0.38555908203125 +17714 -0.27935791015625 +17715 -0.227630615234375 +17716 -0.0089111328125 +17717 -0.013519287109375 +17718 0.268798828125 +17719 0.206695556640625 +17720 0.482818603515625 +17721 0.376800537109375 +17722 0.60369873046875 +17723 0.473419189453125 +17724 0.650421142578125 +17725 0.51153564453125 +17726 0.66400146484375 +17727 0.5235595703125 +17728 0.6414794921875 +17729 0.507080078125 +17730 0.572540283203125 +17731 0.453857421875 +17732 0.498138427734375 +17733 0.396240234375 +17734 0.439453125 +17735 0.3509521484375 +17736 0.375518798828125 +17737 0.301300048828125 +17738 0.274505615234375 +17739 0.222015380859375 +17740 0.1087646484375 +17741 0.0911865234375 +17742 -0.099395751953125 +17743 -0.073516845703125 +17744 -0.3182373046875 +17745 -0.2469482421875 +17746 -0.5489501953125 +17747 -0.4300537109375 +17748 -0.7738037109375 +17749 -0.608734130859375 +17750 -0.86383056640625 +17751 -0.74102783203125 +17752 -0.870391845703125 +17753 -0.800567626953125 +17754 -0.86895751953125 +17755 -0.801300048828125 +17756 -0.861053466796875 +17757 -0.7535400390625 +17758 -0.765869140625 +17759 -0.6435546875 +17760 -0.5301513671875 +17761 -0.462371826171875 +17762 -0.214691162109375 +17763 -0.215576171875 +17764 0.137359619140625 +17765 0.062774658203125 +17766 0.474822998046875 +17767 0.33209228515625 +17768 0.76239013671875 +17769 0.564208984375 +17770 0.867462158203125 +17771 0.737762451171875 +17772 0.870361328125 +17773 0.85308837890625 +17774 0.86480712890625 +17775 0.85955810546875 +17776 0.831817626953125 +17777 0.857879638671875 +17778 0.677581787109375 +17779 0.82666015625 +17780 0.495880126953125 +17781 0.7281494140625 +17782 0.30767822265625 +17783 0.60491943359375 +17784 0.116180419921875 +17785 0.45867919921875 +17786 -0.110748291015625 +17787 0.26422119140625 +17788 -0.381805419921875 +17789 0.016021728515625 +17790 -0.6572265625 +17791 -0.25201416015625 +17792 -0.857421875 +17793 -0.49249267578125 +17794 -0.870391845703125 +17795 -0.67138671875 +17796 -0.870391845703125 +17797 -0.783050537109375 +17798 -0.86444091796875 +17799 -0.8487548828125 +17800 -0.85723876953125 +17801 -0.859130859375 +17802 -0.790008544921875 +17803 -0.86083984375 +17804 -0.62847900390625 +17805 -0.852935791015625 +17806 -0.3956298828125 +17807 -0.715576171875 +17808 -0.126708984375 +17809 -0.5263671875 +17810 0.150115966796875 +17811 -0.30694580078125 +17812 0.424041748046875 +17813 -0.066558837890625 +17814 0.670623779296875 +17815 0.173431396484375 +17816 0.854522705078125 +17817 0.382354736328125 +17818 0.866485595703125 +17819 0.54620361328125 +17820 0.86920166015625 +17821 0.652801513671875 +17822 0.8653564453125 +17823 0.71649169921875 +17824 0.857147216796875 +17825 0.747833251953125 +17826 0.766845703125 +17827 0.7445068359375 +17828 0.628509521484375 +17829 0.710540771484375 +17830 0.462127685546875 +17831 0.64056396484375 +17832 0.297210693359375 +17833 0.555023193359375 +17834 0.14862060546875 +17835 0.46368408203125 +17836 -0.00537109375 +17837 0.348419189453125 +17838 -0.15753173828125 +17839 0.21514892578125 +17840 -0.31304931640625 +17841 0.061004638671875 +17842 -0.48876953125 +17843 -0.125091552734375 +17844 -0.6416015625 +17845 -0.30596923828125 +17846 -0.751373291015625 +17847 -0.4620361328125 +17848 -0.84619140625 +17849 -0.61151123046875 +17850 -0.861297607421875 +17851 -0.74273681640625 +17852 -0.863250732421875 +17853 -0.829376220703125 +17854 -0.856597900390625 +17855 -0.846435546875 +17856 -0.7498779296875 +17857 -0.803497314453125 +17858 -0.624542236328125 +17859 -0.746337890625 +17860 -0.47808837890625 +17861 -0.657501220703125 +17862 -0.253387451171875 +17863 -0.490692138671875 +17864 0.003692626953125 +17865 -0.282073974609375 +17866 0.2257080078125 +17867 -0.085784912109375 +17868 0.427154541015625 +17869 0.1080322265625 +17870 0.643218994140625 +17871 0.32501220703125 +17872 0.855926513671875 +17873 0.55743408203125 +17874 0.870361328125 +17875 0.759368896484375 +17876 0.870361328125 +17877 0.8585205078125 +17878 0.862762451171875 +17879 0.86590576171875 +17880 0.79669189453125 +17881 0.86602783203125 +17882 0.595794677734375 +17883 0.858062744140625 +17884 0.362152099609375 +17885 0.763336181640625 +17886 0.1270751953125 +17887 0.610443115234375 +17888 -0.086944580078125 +17889 0.44549560546875 +17890 -0.2784423828125 +17891 0.270172119140625 +17892 -0.484832763671875 +17893 0.056976318359375 +17894 -0.729583740234375 +17895 -0.209197998046875 +17896 -0.86688232421875 +17897 -0.48822021484375 +17898 -0.870391845703125 +17899 -0.729827880859375 +17900 -0.86859130859375 +17901 -0.86273193359375 +17902 -0.86279296875 +17903 -0.870391845703125 +17904 -0.817962646484375 +17905 -0.870391845703125 +17906 -0.6116943359375 +17907 -0.859893798828125 +17908 -0.3128662109375 +17909 -0.709716796875 +17910 0.039398193359375 +17911 -0.44677734375 +17912 0.422821044921875 +17913 -0.132598876953125 +17914 0.805145263671875 +17915 0.205841064453125 +17916 0.870361328125 +17917 0.515167236328125 +17918 0.870361328125 +17919 0.751739501953125 +17920 0.860015869140625 +17921 0.860382080078125 +17922 0.727935791015625 +17923 0.868499755859375 +17924 0.48114013671875 +17925 0.86761474609375 +17926 0.2059326171875 +17927 0.860137939453125 +17928 -0.06103515625 +17929 0.799102783203125 +17930 -0.29913330078125 +17931 0.664947509765625 +17932 -0.516204833984375 +17933 0.496826171875 +17934 -0.7252197265625 +17935 0.28656005859375 +17936 -0.85980224609375 +17937 0.055999755859375 +17938 -0.870391845703125 +17939 -0.166534423828125 +17940 -0.870391845703125 +17941 -0.357177734375 +17942 -0.858062744140625 +17943 -0.4783935546875 +17944 -0.673004150390625 +17945 -0.527313232421875 +17946 -0.42694091796875 +17947 -0.544921875 +17948 -0.2100830078125 +17949 -0.566802978515625 +17950 -0.0362548828125 +17951 -0.593780517578125 +17952 0.10943603515625 +17953 -0.606658935546875 +17954 0.23516845703125 +17955 -0.593505859375 +17956 0.373687744140625 +17957 -0.526123046875 +17958 0.517791748046875 +17959 -0.40924072265625 +17960 0.602783203125 +17961 -0.293701171875 +17962 0.635711669921875 +17963 -0.17816162109375 +17964 0.655181884765625 +17965 -0.03936767578125 +17966 0.65948486328125 +17967 0.113616943359375 +17968 0.651275634765625 +17969 0.273895263671875 +17970 0.61846923828125 +17971 0.422698974609375 +17972 0.53753662109375 +17973 0.532501220703125 +17974 0.404144287109375 +17975 0.59075927734375 +17976 0.22186279296875 +17977 0.591796875 +17978 0.003997802734375 +17979 0.538726806640625 +17980 -0.22100830078125 +17981 0.447784423828125 +17982 -0.42449951171875 +17983 0.337310791015625 +17984 -0.579833984375 +17985 0.226165771484375 +17986 -0.641876220703125 +17987 0.14935302734375 +17988 -0.6177978515625 +17989 0.104095458984375 +17990 -0.575531005859375 +17991 0.043182373046875 +17992 -0.526336669921875 +17993 -0.035980224609375 +17994 -0.42645263671875 +17995 -0.0931396484375 +17996 -0.2581787109375 +17997 -0.1070556640625 +17998 -0.068695068359375 +17999 -0.105621337890625 +18000 0.09222412109375 +18001 -0.118865966796875 +18002 0.232147216796875 +18003 -0.133819580078125 +18004 0.3509521484375 +18005 -0.144378662109375 +18006 0.410064697265625 +18007 -0.17498779296875 +18008 0.372955322265625 +18009 -0.25 +18010 0.2554931640625 +18011 -0.3555908203125 +18012 0.10711669921875 +18013 -0.454193115234375 +18014 -0.052886962890625 +18015 -0.5328369140625 +18016 -0.186279296875 +18017 -0.56561279296875 +18018 -0.23291015625 +18019 -0.511322021484375 +18020 -0.209442138671875 +18021 -0.38812255859375 +18022 -0.174163818359375 +18023 -0.2464599609375 +18024 -0.126739501953125 +18025 -0.0926513671875 +18026 -0.048126220703125 +18027 0.08123779296875 +18028 0.0426025390625 +18029 0.254638671875 +18030 0.10748291015625 +18031 0.393280029296875 +18032 0.1409912109375 +18033 0.488525390625 +18034 0.19708251953125 +18035 0.578094482421875 +18036 0.273651123046875 +18037 0.658538818359375 +18038 0.31768798828125 +18039 0.689056396484375 +18040 0.341094970703125 +18041 0.679595947265625 +18042 0.368011474609375 +18043 0.65069580078125 +18044 0.37249755859375 +18045 0.5859375 +18046 0.30072021484375 +18047 0.44866943359375 +18048 0.1517333984375 +18049 0.243072509765625 +18050 -0.01470947265625 +18051 0.019866943359375 +18052 -0.1883544921875 +18053 -0.20770263671875 +18054 -0.372711181640625 +18055 -0.4371337890625 +18056 -0.51397705078125 +18057 -0.62286376953125 +18058 -0.57177734375 +18059 -0.730224609375 +18060 -0.53948974609375 +18061 -0.751190185546875 +18062 -0.43511962890625 +18063 -0.697479248046875 +18064 -0.2962646484375 +18065 -0.596832275390625 +18066 -0.161102294921875 +18067 -0.478607177734375 +18068 -0.0435791015625 +18069 -0.35479736328125 +18070 0.060394287109375 +18071 -0.2247314453125 +18072 0.13665771484375 +18073 -0.102386474609375 +18074 0.170135498046875 +18075 -0.003143310546875 +18076 0.16552734375 +18077 0.072265625 +18078 0.15728759765625 +18079 0.14556884765625 +18080 0.150787353515625 +18081 0.21649169921875 +18082 0.12200927734375 +18083 0.26275634765625 +18084 0.080108642578125 +18085 0.287811279296875 +18086 0.05126953125 +18087 0.308807373046875 +18088 0.062896728515625 +18089 0.344635009765625 +18090 0.09271240234375 +18091 0.3773193359375 +18092 0.092987060546875 +18093 0.37054443359375 +18094 0.07855224609375 +18095 0.33642578125 +18096 0.06427001953125 +18097 0.287994384765625 +18098 0.0347900390625 +18099 0.216064453125 +18100 -0.01171875 +18101 0.122222900390625 +18102 -0.056060791015625 +18103 0.024566650390625 +18104 -0.055511474609375 +18105 -0.040802001953125 +18106 -0.010467529296875 +18107 -0.07049560546875 +18108 0.02508544921875 +18109 -0.10211181640625 +18110 0.025665283203125 +18111 -0.1519775390625 +18112 0.017333984375 +18113 -0.197784423828125 +18114 0.00189208984375 +18115 -0.236328125 +18116 -0.03173828125 +18117 -0.274932861328125 +18118 -0.071502685546875 +18119 -0.304168701171875 +18120 -0.13543701171875 +18121 -0.338165283203125 +18122 -0.219970703125 +18123 -0.37542724609375 +18124 -0.300506591796875 +18125 -0.399078369140625 +18126 -0.376312255859375 +18127 -0.410888671875 +18128 -0.416107177734375 +18129 -0.389801025390625 +18130 -0.371124267578125 +18131 -0.301727294921875 +18132 -0.242279052734375 +18133 -0.150360107421875 +18134 -0.069732666015625 +18135 0.030853271484375 +18136 0.125640869140625 +18137 0.223388671875 +18138 0.31268310546875 +18139 0.401336669921875 +18140 0.45501708984375 +18141 0.535369873046875 +18142 0.554779052734375 +18143 0.625946044921875 +18144 0.61065673828125 +18145 0.671600341796875 +18146 0.610931396484375 +18147 0.66357421875 +18148 0.531463623046875 +18149 0.5843505859375 +18150 0.3883056640625 +18151 0.447418212890625 +18152 0.23468017578125 +18153 0.2950439453125 +18154 0.095245361328125 +18155 0.14813232421875 +18156 -0.00396728515625 +18157 0.02880859375 +18158 -0.04852294921875 +18159 -0.0494384765625 +18160 -0.055145263671875 +18161 -0.09686279296875 +18162 -0.0758056640625 +18163 -0.1507568359375 +18164 -0.138702392578125 +18165 -0.230560302734375 +18166 -0.209197998046875 +18167 -0.308380126953125 +18168 -0.289031982421875 +18169 -0.38446044921875 +18170 -0.37884521484375 +18171 -0.458709716796875 +18172 -0.456329345703125 +18173 -0.51409912109375 +18174 -0.51641845703125 +18175 -0.5472412109375 +18176 -0.519287109375 +18177 -0.52899169921875 +18178 -0.458251953125 +18179 -0.45562744140625 +18180 -0.384796142578125 +18181 -0.3675537109375 +18182 -0.323699951171875 +18183 -0.285308837890625 +18184 -0.269287109375 +18185 -0.20672607421875 +18186 -0.1951904296875 +18187 -0.1141357421875 +18188 -0.100006103515625 +18189 -0.008514404296875 +18190 -0.01055908203125 +18191 0.08819580078125 +18192 0.1033935546875 +18193 0.19720458984375 +18194 0.24908447265625 +18195 0.32281494140625 +18196 0.373199462890625 +18197 0.42437744140625 +18198 0.45806884765625 +18199 0.488372802734375 +18200 0.511474609375 +18201 0.520843505859375 +18202 0.565399169921875 +18203 0.546417236328125 +18204 0.61138916015625 +18205 0.559814453125 +18206 0.5897216796875 +18207 0.517547607421875 +18208 0.4906005859375 +18209 0.413818359375 +18210 0.33148193359375 +18211 0.263427734375 +18212 0.147796630859375 +18213 0.09466552734375 +18214 -0.01873779296875 +18215 -0.059478759765625 +18216 -0.140289306640625 +18217 -0.176544189453125 +18218 -0.191986083984375 +18219 -0.236572265625 +18220 -0.184295654296875 +18221 -0.24639892578125 +18222 -0.161834716796875 +18223 -0.238800048828125 +18224 -0.166595458984375 +18225 -0.24493408203125 +18226 -0.19390869140625 +18227 -0.2613525390625 +18228 -0.22442626953125 +18229 -0.27392578125 +18230 -0.279754638671875 +18231 -0.29962158203125 +18232 -0.3389892578125 +18233 -0.32379150390625 +18234 -0.3543701171875 +18235 -0.3118896484375 +18236 -0.348175048828125 +18237 -0.281951904296875 +18238 -0.32598876953125 +18239 -0.239593505859375 +18240 -0.2581787109375 +18241 -0.164031982421875 +18242 -0.139801025390625 +18243 -0.0528564453125 +18244 0.014617919921875 +18245 0.081878662109375 +18246 0.144378662109375 +18247 0.193695068359375 +18248 0.221038818359375 +18249 0.2606201171875 +18250 0.27069091796875 +18251 0.301849365234375 +18252 0.294036865234375 +18253 0.317840576171875 +18254 0.311767578125 +18255 0.324371337890625 +18256 0.339141845703125 +18257 0.33331298828125 +18258 0.360260009765625 +18259 0.333251953125 +18260 0.360504150390625 +18261 0.314300537109375 +18262 0.308380126953125 +18263 0.254730224609375 +18264 0.18170166015625 +18265 0.139739990234375 +18266 0.0047607421875 +18267 -0.011627197265625 +18268 -0.17559814453125 +18269 -0.164031982421875 +18270 -0.3143310546875 +18271 -0.283538818359375 +18272 -0.36785888671875 +18273 -0.337493896484375 +18274 -0.36248779296875 +18275 -0.34429931640625 +18276 -0.343536376953125 +18277 -0.336456298828125 +18278 -0.3018798828125 +18279 -0.307159423828125 +18280 -0.231414794921875 +18281 -0.252044677734375 +18282 -0.117645263671875 +18283 -0.160919189453125 +18284 0.007049560546875 +18285 -0.057952880859375 +18286 0.087982177734375 +18287 0.016265869140625 +18288 0.13946533203125 +18289 0.07122802734375 +18290 0.17425537109375 +18291 0.115203857421875 +18292 0.188201904296875 +18293 0.14410400390625 +18294 0.171234130859375 +18295 0.1495361328125 +18296 0.118438720703125 +18297 0.12701416015625 +18298 0.05706787109375 +18299 0.0955810546875 +18300 -0.010711669921875 +18301 0.056121826171875 +18302 -0.0914306640625 +18303 0.003448486328125 +18304 -0.162322998046875 +18305 -0.0460205078125 +18306 -0.194549560546875 +18307 -0.07135009765625 +18308 -0.1492919921875 +18309 -0.0440673828125 +18310 -0.02166748046875 +18311 0.039794921875 +18312 0.124053955078125 +18313 0.134063720703125 +18314 0.211151123046875 +18315 0.183624267578125 +18316 0.240447998046875 +18317 0.18988037109375 +18318 0.242218017578125 +18319 0.175689697265625 +18320 0.2257080078125 +18321 0.148681640625 +18322 0.194366455078125 +18323 0.1121826171875 +18324 0.115509033203125 +18325 0.043060302734375 +18326 0.0128173828125 +18327 -0.040802001953125 +18328 -0.053802490234375 +18329 -0.095367431640625 +18330 -0.110626220703125 +18331 -0.139556884765625 +18332 -0.199493408203125 +18333 -0.20379638671875 +18334 -0.29437255859375 +18335 -0.26922607421875 +18336 -0.33221435546875 +18337 -0.290252685546875 +18338 -0.27972412109375 +18339 -0.243072509765625 +18340 -0.185333251953125 +18341 -0.16351318359375 +18342 -0.128204345703125 +18343 -0.10980224609375 +18344 -0.115692138671875 +18345 -0.087982177734375 +18346 -0.116455078125 +18347 -0.07598876953125 +18348 -0.105926513671875 +18349 -0.056610107421875 +18350 -0.053955078125 +18351 -0.008544921875 +18352 0.048797607421875 +18353 0.07452392578125 +18354 0.157318115234375 +18355 0.159423828125 +18356 0.212005615234375 +18357 0.2025146484375 +18358 0.218475341796875 +18359 0.207794189453125 +18360 0.23724365234375 +18361 0.219329833984375 +18362 0.30535888671875 +18363 0.264312744140625 +18364 0.38128662109375 +18365 0.31280517578125 +18366 0.404449462890625 +18367 0.321136474609375 +18368 0.3944091796875 +18369 0.3040771484375 +18370 0.3885498046875 +18371 0.289398193359375 +18372 0.362640380859375 +18373 0.26007080078125 +18374 0.27362060546875 +18375 0.185302734375 +18376 0.11712646484375 +18377 0.06243896484375 +18378 -0.054901123046875 +18379 -0.070220947265625 +18380 -0.19085693359375 +18381 -0.174713134765625 +18382 -0.28570556640625 +18383 -0.247161865234375 +18384 -0.339263916015625 +18385 -0.287322998046875 +18386 -0.3775634765625 +18387 -0.314117431640625 +18388 -0.445709228515625 +18389 -0.36053466796875 +18390 -0.535064697265625 +18391 -0.4205322265625 +18392 -0.629058837890625 +18393 -0.48236083984375 +18394 -0.697601318359375 +18395 -0.524505615234375 +18396 -0.70391845703125 +18397 -0.520660400390625 +18398 -0.6424560546875 +18399 -0.467254638671875 +18400 -0.491241455078125 +18401 -0.348785400390625 +18402 -0.265716552734375 +18403 -0.176910400390625 +18404 -0.023712158203125 +18405 0.00579833984375 +18406 0.201751708984375 +18407 0.17498779296875 +18408 0.375823974609375 +18409 0.305084228515625 +18410 0.485076904296875 +18411 0.386199951171875 +18412 0.56884765625 +18413 0.4468994140625 +18414 0.634765625 +18415 0.492828369140625 +18416 0.63763427734375 +18417 0.49127197265625 +18418 0.5660400390625 +18419 0.434112548828125 +18420 0.4720458984375 +18421 0.35955810546875 +18422 0.40692138671875 +18423 0.305328369140625 +18424 0.3778076171875 +18425 0.277008056640625 +18426 0.376953125 +18427 0.26934814453125 +18428 0.371978759765625 +18429 0.2591552734375 +18430 0.313140869140625 +18431 0.2105712890625 +18432 0.184417724609375 +18433 0.112457275390625 +18434 0.011199951171875 +18435 -0.016204833984375 +18436 -0.171051025390625 +18437 -0.14971923828125 +18438 -0.33740234375 +18439 -0.2703857421875 +18440 -0.47198486328125 +18441 -0.36688232421875 +18442 -0.560394287109375 +18443 -0.429046630859375 +18444 -0.58056640625 +18445 -0.441558837890625 +18446 -0.54754638671875 +18447 -0.415008544921875 +18448 -0.508575439453125 +18449 -0.382537841796875 +18450 -0.459503173828125 +18451 -0.34161376953125 +18452 -0.394378662109375 +18453 -0.288482666015625 +18454 -0.35260009765625 +18455 -0.25103759765625 +18456 -0.31170654296875 +18457 -0.214080810546875 +18458 -0.197418212890625 +18459 -0.12640380859375 +18460 -0.007965087890625 +18461 0.012786865234375 +18462 0.207489013671875 +18463 0.16888427734375 +18464 0.409210205078125 +18465 0.31390380859375 +18466 0.57208251953125 +18467 0.430145263671875 +18468 0.66595458984375 +18469 0.496551513671875 +18470 0.65875244140625 +18471 0.490753173828125 +18472 0.56744384765625 +18473 0.4246826171875 +18474 0.431396484375 +18475 0.325897216796875 +18476 0.29443359375 +18477 0.2252197265625 +18478 0.182464599609375 +18479 0.140960693359375 +18480 0.06365966796875 +18481 0.0513916015625 +18482 -0.075958251953125 +18483 -0.0528564453125 +18484 -0.189422607421875 +18485 -0.138671875 +18486 -0.271942138671875 +18487 -0.202362060546875 +18488 -0.342529296875 +18489 -0.2568359375 +18490 -0.364166259765625 +18491 -0.276092529296875 +18492 -0.327239990234375 +18493 -0.25323486328125 +18494 -0.2769775390625 +18495 -0.219635009765625 +18496 -0.253692626953125 +18497 -0.20330810546875 +18498 -0.24365234375 +18499 -0.194732666015625 +18500 -0.1983642578125 +18501 -0.160308837890625 +18502 -0.116241455078125 +18503 -0.09912109375 +18504 -0.036834716796875 +18505 -0.038909912109375 +18506 0.034881591796875 +18507 0.01654052734375 +18508 0.09124755859375 +18509 0.06158447265625 +18510 0.10888671875 +18511 0.079620361328125 +18512 0.125518798828125 +18513 0.0965576171875 +18514 0.15771484375 +18515 0.1236572265625 +18516 0.17828369140625 +18517 0.14178466796875 +18518 0.17108154296875 +18519 0.139495849609375 +18520 0.129974365234375 +18521 0.1124267578125 +18522 0.082427978515625 +18523 0.079620361328125 +18524 0.027679443359375 +18525 0.04058837890625 +18526 -0.065643310546875 +18527 -0.026397705078125 +18528 -0.15936279296875 +18529 -0.0946044921875 +18530 -0.21307373046875 +18531 -0.135772705078125 +18532 -0.234649658203125 +18533 -0.1551513671875 +18534 -0.2001953125 +18535 -0.135833740234375 +18536 -0.119171142578125 +18537 -0.08416748046875 +18538 -0.024749755859375 +18539 -0.02294921875 +18540 0.085784912109375 +18541 0.0499267578125 +18542 0.178131103515625 +18543 0.11077880859375 +18544 0.215576171875 +18545 0.134246826171875 +18546 0.211456298828125 +18547 0.12969970703125 +18548 0.17523193359375 +18549 0.10382080078125 +18550 0.128753662109375 +18551 0.071807861328125 +18552 0.1019287109375 +18553 0.054443359375 +18554 0.0743408203125 +18555 0.037445068359375 +18556 0.04327392578125 +18557 0.01873779296875 +18558 0.038177490234375 +18559 0.018646240234375 +18560 0.076263427734375 +18561 0.048919677734375 +18562 0.14105224609375 +18563 0.097869873046875 +18564 0.186431884765625 +18565 0.13323974609375 +18566 0.188812255859375 +18567 0.13836669921875 +18568 0.1390380859375 +18569 0.106689453125 +18570 0.041778564453125 +18571 0.041351318359375 +18572 -0.079437255859375 +18573 -0.0413818359375 +18574 -0.219390869140625 +18575 -0.137969970703125 +18576 -0.367828369140625 +18577 -0.24127197265625 +18578 -0.494873046875 +18579 -0.330474853515625 +18580 -0.556243896484375 +18581 -0.374725341796875 +18582 -0.508697509765625 +18583 -0.343780517578125 +18584 -0.3756103515625 +18585 -0.2537841796875 +18586 -0.218902587890625 +18587 -0.147705078125 +18588 -0.063751220703125 +18589 -0.0428466796875 +18590 0.091552734375 +18591 0.062103271484375 +18592 0.23602294921875 +18593 0.15966796875 +18594 0.342987060546875 +18595 0.2314453125 +18596 0.39520263671875 +18597 0.265625 +18598 0.389373779296875 +18599 0.259979248046875 +18600 0.324249267578125 +18601 0.213714599609375 +18602 0.224090576171875 +18603 0.14373779296875 +18604 0.124267578125 +18605 0.074676513671875 +18606 0.037078857421875 +18607 0.0150146484375 +18608 -0.010101318359375 +18609 -0.016204833984375 +18610 -0.019439697265625 +18611 -0.0206298828125 +18612 -0.022796630859375 +18613 -0.02056884765625 +18614 -0.001556396484375 +18615 -0.003204345703125 +18616 0.056304931640625 +18617 0.0396728515625 +18618 0.106719970703125 +18619 0.0772705078125 +18620 0.096893310546875 +18621 0.07269287109375 +18622 0.042694091796875 +18623 0.036895751953125 +18624 -0.018035888671875 +18625 -0.003875732421875 +18626 -0.07586669921875 +18627 -0.04315185546875 +18628 -0.11944580078125 +18629 -0.07305908203125 +18630 -0.15972900390625 +18631 -0.101226806640625 +18632 -0.202606201171875 +18633 -0.1317138671875 +18634 -0.24859619140625 +18635 -0.164825439453125 +18636 -0.30517578125 +18637 -0.2056884765625 +18638 -0.36212158203125 +18639 -0.24713134765625 +18640 -0.39141845703125 +18641 -0.269561767578125 +18642 -0.35528564453125 +18643 -0.246551513671875 +18644 -0.249969482421875 +18645 -0.175384521484375 +18646 -0.092864990234375 +18647 -0.06805419921875 +18648 0.08905029296875 +18649 0.056793212890625 +18650 0.2352294921875 +18651 0.1571044921875 +18652 0.318817138671875 +18653 0.214263916015625 +18654 0.358642578125 +18655 0.24139404296875 +18656 0.347747802734375 +18657 0.233673095703125 +18658 0.28564453125 +18659 0.190765380859375 +18660 0.223175048828125 +18661 0.148040771484375 +18662 0.196746826171875 +18663 0.13079833984375 +18664 0.179840087890625 +18665 0.1204833984375 +18666 0.155548095703125 +18667 0.105255126953125 +18668 0.151214599609375 +18669 0.104034423828125 +18670 0.156951904296875 +18671 0.10986328125 +18672 0.13177490234375 +18673 0.094085693359375 +18674 0.100799560546875 +18675 0.0740966796875 +18676 0.087127685546875 +18677 0.06585693359375 +18678 0.05487060546875 +18679 0.04437255859375 +18680 -0.009002685546875 +18681 0.000518798828125 +18682 -0.10400390625 +18683 -0.06536865234375 +18684 -0.229400634765625 +18685 -0.15283203125 +18686 -0.35552978515625 +18687 -0.24114990234375 +18688 -0.441925048828125 +18689 -0.301910400390625 +18690 -0.473846435546875 +18691 -0.32452392578125 +18692 -0.464813232421875 +18693 -0.318206787109375 +18694 -0.419097900390625 +18695 -0.286285400390625 +18696 -0.334320068359375 +18697 -0.227691650390625 +18698 -0.227935791015625 +18699 -0.154388427734375 +18700 -0.12347412109375 +18701 -0.082366943359375 +18702 -0.02764892578125 +18703 -0.01629638671875 +18704 0.077667236328125 +18705 0.055694580078125 +18706 0.2132568359375 +18707 0.14727783203125 +18708 0.38885498046875 +18709 0.264801025390625 +18710 0.582794189453125 +18711 0.3939208984375 +18712 0.734039306640625 +18713 0.494110107421875 +18714 0.800140380859375 +18715 0.537261962890625 +18716 0.7783203125 +18717 0.5216064453125 +18718 0.6651611328125 +18719 0.444976806640625 +18720 0.45965576171875 +18721 0.30682373046875 +18722 0.199188232421875 +18723 0.13214111328125 +18724 -0.050689697265625 +18725 -0.035430908203125 +18726 -0.23297119140625 +18727 -0.157958984375 +18728 -0.33013916015625 +18729 -0.2237548828125 +18730 -0.368408203125 +18731 -0.2501220703125 +18732 -0.378936767578125 +18733 -0.2576904296875 +18734 -0.376983642578125 +18735 -0.256591796875 +18736 -0.37969970703125 +18737 -0.25823974609375 +18738 -0.391510009765625 +18739 -0.265594482421875 +18740 -0.385345458984375 +18741 -0.260711669921875 +18742 -0.3419189453125 +18743 -0.2308349609375 +18744 -0.28289794921875 +18745 -0.1904296875 +18746 -0.251617431640625 +18747 -0.168304443359375 +18748 -0.266143798828125 +18749 -0.176544189453125 +18750 -0.273345947265625 +18751 -0.179962158203125 +18752 -0.216796875 +18753 -0.14117431640625 +18754 -0.128265380859375 +18755 -0.081298828125 +18756 -0.068145751953125 +18757 -0.04052734375 +18758 -0.0430908203125 +18759 -0.0233154296875 +18760 -0.024444580078125 +18761 -0.010650634765625 +18762 0.020721435546875 +18763 0.019317626953125 +18764 0.124481201171875 +18765 0.087890625 +18766 0.25787353515625 +18767 0.175872802734375 +18768 0.379119873046875 +18769 0.25555419921875 +18770 0.47991943359375 +18771 0.32147216796875 +18772 0.5281982421875 +18773 0.352386474609375 +18774 0.511138916015625 +18775 0.339874267578125 +18776 0.456207275390625 +18777 0.302215576171875 +18778 0.407470703125 +18779 0.26873779296875 +18780 0.383758544921875 +18781 0.25201416015625 +18782 0.35687255859375 +18783 0.233367919921875 +18784 0.31182861328125 +18785 0.202880859375 +18786 0.250885009765625 +18787 0.16204833984375 +18788 0.1654052734375 +18789 0.10516357421875 +18790 0.035247802734375 +18791 0.01885986328125 +18792 -0.142059326171875 +18793 -0.0985107421875 +18794 -0.33563232421875 +18795 -0.2264404296875 +18796 -0.5345458984375 +18797 -0.357696533203125 +18798 -0.72186279296875 +18799 -0.481109619140625 +18800 -0.836669921875 +18801 -0.5562744140625 +18802 -0.8326416015625 +18803 -0.552520751953125 +18804 -0.7296142578125 +18805 -0.483062744140625 +18806 -0.582550048828125 +18807 -0.38446044921875 +18808 -0.440093994140625 +18809 -0.2890625 +18810 -0.324310302734375 +18811 -0.2115478515625 +18812 -0.20147705078125 +18813 -0.12957763671875 +18814 -0.044647216796875 +18815 -0.025238037109375 +18816 0.103973388671875 +18817 0.07342529296875 +18818 0.202392578125 +18819 0.13848876953125 +18820 0.264495849609375 +18821 0.179229736328125 +18822 0.338897705078125 +18823 0.22796630859375 +18824 0.443817138671875 +18825 0.29681396484375 +18826 0.545074462890625 +18827 0.363128662109375 +18828 0.6173095703125 +18829 0.410125732421875 +18830 0.6524658203125 +18831 0.432525634765625 +18832 0.66339111328125 +18833 0.43890380859375 +18834 0.6561279296875 +18835 0.433319091796875 +18836 0.606781005859375 +18837 0.399932861328125 +18838 0.501190185546875 +18839 0.329376220703125 +18840 0.352783203125 +18841 0.2305908203125 +18842 0.176544189453125 +18843 0.113525390625 +18844 -0.034820556640625 +18845 -0.026641845703125 +18846 -0.258209228515625 +18847 -0.174591064453125 +18848 -0.44244384765625 +18849 -0.296356201171875 +18850 -0.5753173828125 +18851 -0.383880615234375 +18852 -0.65203857421875 +18853 -0.43402099609375 +18854 -0.641632080078125 +18855 -0.42626953125 +18856 -0.562164306640625 +18857 -0.3726806640625 +18858 -0.458038330078125 +18859 -0.30279541015625 +18860 -0.350555419921875 +18861 -0.230743408203125 +18862 -0.260528564453125 +18863 -0.17041015625 +18864 -0.192108154296875 +18865 -0.12457275390625 +18866 -0.141937255859375 +18867 -0.091033935546875 +18868 -0.1021728515625 +18869 -0.0645751953125 +18870 -0.062896728515625 +18871 -0.038604736328125 +18872 -0.011932373046875 +18873 -0.005035400390625 +18874 0.062835693359375 +18875 0.044189453125 +18876 0.148712158203125 +18877 0.100677490234375 +18878 0.241729736328125 +18879 0.16180419921875 +18880 0.34912109375 +18881 0.232421875 +18882 0.457305908203125 +18883 0.303558349609375 +18884 0.54388427734375 +18885 0.360382080078125 +18886 0.5728759765625 +18887 0.379058837890625 +18888 0.506591796875 +18889 0.334564208984375 +18890 0.351226806640625 +18891 0.231048583984375 +18892 0.146514892578125 +18893 0.094879150390625 +18894 -0.05523681640625 +18895 -0.039154052734375 +18896 -0.21624755859375 +18897 -0.14599609375 +18898 -0.334930419921875 +18899 -0.224578857421875 +18900 -0.402984619140625 +18901 -0.269439697265625 +18902 -0.4412841796875 +18903 -0.29443359375 +18904 -0.49578857421875 +18905 -0.330108642578125 +18906 -0.5601806640625 +18907 -0.372314453125 +18908 -0.600738525390625 +18909 -0.398681640625 +18910 -0.584228515625 +18911 -0.38714599609375 +18912 -0.47930908203125 +18913 -0.31695556640625 +18914 -0.27935791015625 +18915 -0.183746337890625 +18916 -0.0089111328125 +18917 -0.003814697265625 +18918 0.268798828125 +18919 0.1807861328125 +18920 0.482818603515625 +18921 0.322967529296875 +18922 0.60369873046875 +18923 0.403167724609375 +18924 0.650421142578125 +18925 0.433990478515625 +18926 0.66400146484375 +18927 0.442718505859375 +18928 0.6414794921875 +18929 0.427398681640625 +18930 0.572540283203125 +18931 0.381195068359375 +18932 0.498138427734375 +18933 0.331329345703125 +18934 0.439453125 +18935 0.291900634765625 +18936 0.375518798828125 +18937 0.248992919921875 +18938 0.274505615234375 +18939 0.181488037109375 +18940 0.1087646484375 +18941 0.071044921875 +18942 -0.099395751953125 +18943 -0.0675048828125 +18944 -0.3182373046875 +18945 -0.2125244140625 +18946 -0.5489501953125 +18947 -0.364013671875 +18948 -0.7738037109375 +18949 -0.5103759765625 +18950 -0.86383056640625 +18951 -0.61798095703125 +18952 -0.870391845703125 +18953 -0.665740966796875 +18954 -0.86895751953125 +18955 -0.664886474609375 +18956 -0.861053466796875 +18957 -0.62384033203125 +18958 -0.765869140625 +18959 -0.5318603515625 +18960 -0.5301513671875 +18961 -0.382110595703125 +18962 -0.214691162109375 +18963 -0.17938232421875 +18964 0.137359619140625 +18965 0.04876708984375 +18966 0.474822998046875 +18967 0.26959228515625 +18968 0.76239013671875 +18969 0.4603271484375 +18970 0.867462158203125 +18971 0.603607177734375 +18972 0.870361328125 +18973 0.699462890625 +18974 0.86480712890625 +18975 0.74041748046875 +18976 0.831817626953125 +18977 0.729705810546875 +18978 0.677581787109375 +18979 0.682647705078125 +18980 0.495880126953125 +18981 0.602874755859375 +18982 0.30767822265625 +18983 0.502197265625 +18984 0.116180419921875 +18985 0.38214111328125 +18986 -0.110748291015625 +18987 0.22283935546875 +18988 -0.381805419921875 +18989 0.020111083984375 +18990 -0.6572265625 +18991 -0.198699951171875 +18992 -0.857421875 +18993 -0.3955078125 +18994 -0.870391845703125 +18995 -0.542877197265625 +18996 -0.870391845703125 +18997 -0.636077880859375 +18998 -0.86444091796875 +18999 -0.69189453125 +19000 -0.85723876953125 +19001 -0.732696533203125 +19002 -0.790008544921875 +19003 -0.746734619140625 +19004 -0.62847900390625 +19005 -0.69964599609375 +19006 -0.3956298828125 +19007 -0.58941650390625 +19008 -0.126708984375 +19009 -0.43682861328125 +19010 0.150115966796875 +19011 -0.25927734375 +19012 0.424041748046875 +19013 -0.064300537109375 +19014 0.670623779296875 +19015 0.130859375 +19016 0.854522705078125 +19017 0.301544189453125 +19018 0.866485595703125 +19019 0.43634033203125 +19020 0.86920166015625 +19021 0.525299072265625 +19022 0.8653564453125 +19023 0.57965087890625 +19024 0.857147216796875 +19025 0.607666015625 +19026 0.766845703125 +19027 0.607330322265625 +19028 0.628509521484375 +19029 0.581756591796875 +19030 0.462127685546875 +19031 0.526611328125 +19032 0.297210693359375 +19033 0.458160400390625 +19034 0.14862060546875 +19035 0.384246826171875 +19036 -0.00537109375 +19037 0.290496826171875 +19038 -0.15753173828125 +19039 0.1817626953125 +19040 -0.31304931640625 +19041 0.055908203125 +19042 -0.48876953125 +19043 -0.095733642578125 +19044 -0.6416015625 +19045 -0.24334716796875 +19046 -0.751373291015625 +19047 -0.371124267578125 +19048 -0.84619140625 +19049 -0.493438720703125 +19050 -0.861297607421875 +19051 -0.60076904296875 +19052 -0.863250732421875 +19053 -0.672027587890625 +19054 -0.856597900390625 +19055 -0.687103271484375 +19056 -0.7498779296875 +19057 -0.653594970703125 +19058 -0.624542236328125 +19059 -0.6080322265625 +19060 -0.47808837890625 +19061 -0.5364990234375 +19062 -0.253387451171875 +19063 -0.402130126953125 +19064 0.003692626953125 +19065 -0.233856201171875 +19066 0.2257080078125 +19067 -0.07501220703125 +19068 0.427154541015625 +19069 0.082183837890625 +19070 0.643218994140625 +19071 0.25799560546875 +19072 0.855926513671875 +19073 0.446136474609375 +19074 0.870361328125 +19075 0.609771728515625 +19076 0.870361328125 +19077 0.717376708984375 +19078 0.862762451171875 +19079 0.7733154296875 +19080 0.79669189453125 +19081 0.775604248046875 +19082 0.595794677734375 +19083 0.718170166015625 +19084 0.362152099609375 +19085 0.61944580078125 +19086 0.1270751953125 +19087 0.49713134765625 +19088 -0.086944580078125 +19089 0.364654541015625 +19090 -0.2784423828125 +19091 0.223419189453125 +19092 -0.484832763671875 +19093 0.05157470703125 +19094 -0.729583740234375 +19095 -0.162841796875 +19096 -0.86688232421875 +19097 -0.38763427734375 +19098 -0.870391845703125 +19099 -0.582611083984375 +19100 -0.86859130859375 +19101 -0.744415283203125 +19102 -0.86279296875 +19103 -0.856353759765625 +19104 -0.817962646484375 +19105 -0.86395263671875 +19106 -0.6116943359375 +19107 -0.862091064453125 +19108 -0.3128662109375 +19109 -0.816009521484375 +19110 0.039398193359375 +19111 -0.638153076171875 +19112 0.422821044921875 +19113 -0.40313720703125 +19114 0.805145263671875 +19115 -0.132049560546875 +19116 0.870361328125 +19117 0.131927490234375 +19118 0.870361328125 +19119 0.35260009765625 +19120 0.860015869140625 +19121 0.522308349609375 +19122 0.727935791015625 +19123 0.63592529296875 +19124 0.48114013671875 +19125 0.689544677734375 +19126 0.2059326171875 +19127 0.698150634765625 +19128 -0.06103515625 +19129 0.675750732421875 +19130 -0.29913330078125 +19131 0.628448486328125 +19132 -0.516204833984375 +19133 0.546875 +19134 -0.7252197265625 +19135 0.42120361328125 +19136 -0.85980224609375 +19137 0.267181396484375 +19138 -0.870391845703125 +19139 0.106597900390625 +19140 -0.870391845703125 +19141 -0.0416259765625 +19142 -0.858062744140625 +19143 -0.14642333984375 +19144 -0.673004150390625 +19145 -0.204742431640625 +19146 -0.42694091796875 +19147 -0.24932861328125 +19148 -0.2100830078125 +19149 -0.307769775390625 +19150 -0.0362548828125 +19151 -0.37823486328125 +19152 0.10943603515625 +19153 -0.441925048828125 +19154 0.23516845703125 +19155 -0.48583984375 +19156 0.373687744140625 +19157 -0.4835205078125 +19158 0.517791748046875 +19159 -0.435943603515625 +19160 0.602783203125 +19161 -0.382843017578125 +19162 0.635711669921875 +19163 -0.320953369140625 +19164 0.655181884765625 +19165 -0.22930908203125 +19166 0.65948486328125 +19167 -0.114410400390625 +19168 0.651275634765625 +19169 0.018280029296875 +19170 0.61846923828125 +19171 0.15289306640625 +19172 0.53753662109375 +19173 0.26556396484375 +19174 0.404144287109375 +19175 0.34442138671875 +19176 0.22186279296875 +19177 0.382843017578125 +19178 0.003997802734375 +19179 0.381134033203125 +19180 -0.22100830078125 +19181 0.350341796875 +19182 -0.42449951171875 +19183 0.30322265625 +19184 -0.579833984375 +19185 0.2530517578125 +19186 -0.641876220703125 +19187 0.2266845703125 +19188 -0.6177978515625 +19189 0.21990966796875 +19190 -0.575531005859375 +19191 0.191986083984375 +19192 -0.526336669921875 +19193 0.139678955078125 +19194 -0.42645263671875 +19195 0.096038818359375 +19196 -0.2581787109375 +19197 0.0787353515625 +19198 -0.068695068359375 +19199 0.065185546875 +19200 0.09222412109375 +19201 0.031005859375 +19202 0.232147216796875 +19203 -0.01214599609375 +19204 0.3509521484375 +19205 -0.056854248046875 +19206 0.410064697265625 +19207 -0.11993408203125 +19208 0.372955322265625 +19209 -0.21820068359375 +19210 0.2554931640625 +19211 -0.33843994140625 +19212 0.10711669921875 +19213 -0.44891357421875 +19214 -0.052886962890625 +19215 -0.53765869140625 +19216 -0.186279296875 +19217 -0.5828857421875 +19218 -0.23291015625 +19219 -0.55120849609375 +19220 -0.209442138671875 +19221 -0.45660400390625 +19222 -0.174163818359375 +19223 -0.339019775390625 +19224 -0.126739501953125 +19225 -0.2039794921875 +19226 -0.048126220703125 +19227 -0.04620361328125 +19228 0.0426025390625 +19229 0.116668701171875 +19230 0.10748291015625 +19231 0.2559814453125 +19232 0.1409912109375 +19233 0.3631591796875 +19234 0.19708251953125 +19235 0.466217041015625 +19236 0.273651123046875 +19237 0.560638427734375 +19238 0.31768798828125 +19239 0.612518310546875 +19240 0.341094970703125 +19241 0.6282958984375 +19242 0.368011474609375 +19243 0.623046875 +19244 0.37249755859375 +19245 0.5830078125 +19246 0.30072021484375 +19247 0.478851318359375 +19248 0.1517333984375 +19249 0.3138427734375 +19250 -0.01470947265625 +19251 0.128326416015625 +19252 -0.1883544921875 +19253 -0.066497802734375 +19254 -0.372711181640625 +19255 -0.267669677734375 +19256 -0.51397705078125 +19257 -0.437957763671875 +19258 -0.57177734375 +19259 -0.54864501953125 +19260 -0.53948974609375 +19261 -0.591888427734375 +19262 -0.43511962890625 +19263 -0.575469970703125 +19264 -0.2962646484375 +19265 -0.5198974609375 +19266 -0.161102294921875 +19267 -0.44708251953125 +19268 -0.0435791015625 +19269 -0.365478515625 +19270 0.060394287109375 +19271 -0.2738037109375 +19272 0.13665771484375 +19273 -0.182647705078125 +19274 0.170135498046875 +19275 -0.10400390625 +19276 0.16552734375 +19277 -0.03863525390625 +19278 0.15728759765625 +19279 0.03009033203125 +19280 0.150787353515625 +19281 0.101287841796875 +19282 0.12200927734375 +19283 0.1563720703125 +19284 0.080108642578125 +19285 0.19696044921875 +19286 0.05126953125 +19287 0.235382080078125 +19288 0.062896728515625 +19289 0.28533935546875 +19290 0.09271240234375 +19291 0.33148193359375 +19292 0.092987060546875 +19293 0.34405517578125 +19294 0.07855224609375 +19295 0.33172607421875 +19296 0.06427001953125 +19297 0.304107666015625 +19298 0.0347900390625 +19299 0.253448486328125 +19300 -0.01171875 +19301 0.180816650390625 +19302 -0.056060791015625 +19303 0.100494384765625 +19304 -0.055511474609375 +19305 0.04132080078125 +19306 -0.010467529296875 +19307 0.0064697265625 +19308 0.02508544921875 +19309 -0.032958984375 +19310 0.025665283203125 +19311 -0.088958740234375 +19312 0.017333984375 +19313 -0.1429443359375 +19314 0.00189208984375 +19315 -0.19140625 +19316 -0.03173828125 +19317 -0.2391357421875 +19318 -0.071502685546875 +19319 -0.27777099609375 +19320 -0.13543701171875 +19321 -0.31768798828125 +19322 -0.219970703125 +19323 -0.357025146484375 +19324 -0.300506591796875 +19325 -0.381988525390625 +19326 -0.376312255859375 +19327 -0.393768310546875 +19328 -0.416107177734375 +19329 -0.375701904296875 +19330 -0.371124267578125 +19331 -0.30108642578125 +19332 -0.242279052734375 +19333 -0.1732177734375 +19334 -0.069732666015625 +19335 -0.01904296875 +19336 0.125640869140625 +19337 0.1461181640625 +19338 0.31268310546875 +19339 0.301025390625 +19340 0.45501708984375 +19341 0.42169189453125 +19342 0.554779052734375 +19343 0.5076904296875 +19344 0.61065673828125 +19345 0.55706787109375 +19346 0.610931396484375 +19347 0.562225341796875 +19348 0.531463623046875 +19349 0.50872802734375 +19350 0.3883056640625 +19351 0.4068603515625 +19352 0.23468017578125 +19353 0.289703369140625 +19354 0.095245361328125 +19355 0.1737060546875 +19356 -0.00396728515625 +19357 0.076416015625 +19358 -0.04852294921875 +19359 0.0086669921875 +19360 -0.055145263671875 +19361 -0.03717041015625 +19362 -0.0758056640625 +19363 -0.09002685546875 +19364 -0.138702392578125 +19365 -0.164642333984375 +19366 -0.209197998046875 +19367 -0.23828125 +19368 -0.289031982421875 +19369 -0.310455322265625 +19370 -0.37884521484375 +19371 -0.380462646484375 +19372 -0.456329345703125 +19373 -0.434234619140625 +19374 -0.51641845703125 +19375 -0.468597412109375 +19376 -0.519287109375 +19377 -0.46002197265625 +19378 -0.458251953125 +19379 -0.405303955078125 +19380 -0.384796142578125 +19381 -0.3365478515625 +19382 -0.323699951171875 +19383 -0.2701416015625 +19384 -0.269287109375 +19385 -0.20440673828125 +19386 -0.1951904296875 +19387 -0.12548828125 +19388 -0.100006103515625 +19389 -0.034423828125 +19390 -0.01055908203125 +19391 0.05084228515625 +19392 0.1033935546875 +19393 0.146759033203125 +19394 0.24908447265625 +19395 0.256317138671875 +19396 0.373199462890625 +19397 0.346466064453125 +19398 0.45806884765625 +19399 0.405914306640625 +19400 0.511474609375 +19401 0.4390869140625 +19402 0.565399169921875 +19403 0.46533203125 +19404 0.61138916015625 +19405 0.4801025390625 +19406 0.5897216796875 +19407 0.448455810546875 +19408 0.4906005859375 +19409 0.36572265625 +19410 0.33148193359375 +19411 0.2437744140625 +19412 0.147796630859375 +19413 0.105377197265625 +19414 -0.01873779296875 +19415 -0.0228271484375 +19416 -0.140289306640625 +19417 -0.12255859375 +19418 -0.191986083984375 +19419 -0.177490234375 +19420 -0.184295654296875 +19421 -0.19268798828125 +19422 -0.161834716796875 +19423 -0.1939697265625 +19424 -0.166595458984375 +19425 -0.20587158203125 +19426 -0.19390869140625 +19427 -0.225250244140625 +19428 -0.22442626953125 +19429 -0.240509033203125 +19430 -0.279754638671875 +19431 -0.26495361328125 +19432 -0.3389892578125 +19433 -0.28668212890625 +19434 -0.3543701171875 +19435 -0.2779541015625 +19436 -0.348175048828125 +19437 -0.25323486328125 +19438 -0.32598876953125 +19439 -0.217071533203125 +19440 -0.2581787109375 +19441 -0.15301513671875 +19442 -0.139801025390625 +19443 -0.05938720703125 +19444 0.014617919921875 +19445 0.05389404296875 +19446 0.144378662109375 +19447 0.1492919921875 +19448 0.221038818359375 +19449 0.208892822265625 +19450 0.27069091796875 +19451 0.24774169921875 +19452 0.294036865234375 +19453 0.26593017578125 +19454 0.311767578125 +19455 0.2757568359375 +19456 0.339141845703125 +19457 0.286468505859375 +19458 0.360260009765625 +19459 0.288543701171875 +19460 0.360504150390625 +19461 0.2740478515625 +19462 0.308380126953125 +19463 0.226165771484375 +19464 0.18170166015625 +19465 0.13348388671875 +19466 0.0047607421875 +19467 0.011138916015625 +19468 -0.17559814453125 +19469 -0.11297607421875 +19470 -0.3143310546875 +19471 -0.21209716796875 +19472 -0.36785888671875 +19473 -0.2603759765625 +19474 -0.36248779296875 +19475 -0.271820068359375 +19476 -0.343536376953125 +19477 -0.271453857421875 +19478 -0.3018798828125 +19479 -0.253692626953125 +19480 -0.231414794921875 +19481 -0.214874267578125 +19482 -0.117645263671875 +19483 -0.14678955078125 +19484 0.007049560546875 +19485 -0.068206787109375 +19486 0.087982177734375 +19487 -0.010711669921875 +19488 0.13946533203125 +19489 0.033050537109375 +19490 0.17425537109375 +19491 0.0694580078125 +19492 0.188201904296875 +19493 0.09515380859375 +19494 0.171234130859375 +19495 0.103424072265625 +19496 0.118438720703125 +19497 0.09051513671875 +19498 0.05706787109375 +19499 0.07098388671875 +19500 -0.010711669921875 +19501 0.04522705078125 +19502 -0.0914306640625 +19503 0.008941650390625 +19504 -0.162322998046875 +19505 -0.02532958984375 +19506 -0.194549560546875 +19507 -0.04144287109375 +19508 -0.1492919921875 +19509 -0.017364501953125 +19510 -0.02166748046875 +19511 0.049835205078125 +19512 0.124053955078125 +19513 0.12408447265625 +19514 0.211151123046875 +19515 0.162353515625 +19516 0.240447998046875 +19517 0.165802001953125 +19518 0.242218017578125 +19519 0.152374267578125 +19520 0.2257080078125 +19521 0.128173828125 +19522 0.194366455078125 +19523 0.095977783203125 +19524 0.115509033203125 +19525 0.0379638671875 +19526 0.0128173828125 +19527 -0.03167724609375 +19528 -0.053802490234375 +19529 -0.078369140625 +19530 -0.110626220703125 +19531 -0.116607666015625 +19532 -0.199493408203125 +19533 -0.169921875 +19534 -0.29437255859375 +19535 -0.223480224609375 +19536 -0.33221435546875 +19537 -0.2415771484375 +19538 -0.27972412109375 +19539 -0.205596923828125 +19540 -0.185333251953125 +19541 -0.143463134765625 +19542 -0.128204345703125 +19543 -0.100616455078125 +19544 -0.115692138671875 +19545 -0.081878662109375 +19546 -0.116455078125 +19547 -0.070098876953125 +19548 -0.105926513671875 +19549 -0.052001953125 +19550 -0.053955078125 +19551 -0.011138916015625 +19552 0.048797607421875 +19553 0.057159423828125 +19554 0.157318115234375 +19555 0.126861572265625 +19556 0.212005615234375 +19557 0.1636962890625 +19558 0.218475341796875 +19559 0.170623779296875 +19560 0.23724365234375 +19561 0.181915283203125 +19562 0.30535888671875 +19563 0.218658447265625 +19564 0.38128662109375 +19565 0.257415771484375 +19566 0.404449462890625 +19567 0.264068603515625 +19568 0.3944091796875 +19569 0.25018310546875 +19570 0.3885498046875 +19571 0.23748779296875 +19572 0.362640380859375 +19573 0.2127685546875 +19574 0.27362060546875 +19575 0.152130126953125 +19576 0.11712646484375 +19577 0.05364990234375 +19578 -0.054901123046875 +19579 -0.05267333984375 +19580 -0.19085693359375 +19581 -0.137054443359375 +19582 -0.28570556640625 +19583 -0.1962890625 +19584 -0.339263916015625 +19585 -0.230072021484375 +19586 -0.3775634765625 +19587 -0.2530517578125 +19588 -0.445709228515625 +19589 -0.29083251953125 +19590 -0.535064697265625 +19591 -0.338623046875 +19592 -0.629058837890625 +19593 -0.387237548828125 +19594 -0.697601318359375 +19595 -0.41986083984375 +19596 -0.70391845703125 +19597 -0.415985107421875 +19598 -0.6424560546875 +19599 -0.3729248046875 +19600 -0.491241455078125 +19601 -0.2786865234375 +19602 -0.265716552734375 +19603 -0.142486572265625 +19604 -0.023712158203125 +19605 0.00238037109375 +19606 0.201751708984375 +19607 0.136749267578125 +19608 0.375823974609375 +19609 0.240509033203125 +19610 0.485076904296875 +19611 0.30584716796875 +19612 0.56884765625 +19613 0.35498046875 +19614 0.634765625 +19615 0.392181396484375 +19616 0.63763427734375 +19617 0.391876220703125 +19618 0.5660400390625 +19619 0.34771728515625 +19620 0.4720458984375 +19621 0.28948974609375 +19622 0.40692138671875 +19623 0.246612548828125 +19624 0.3778076171875 +19625 0.2235107421875 +19626 0.376953125 +19627 0.216156005859375 +19628 0.371978759765625 +19629 0.20654296875 +19630 0.313140869140625 +19631 0.166778564453125 +19632 0.184417724609375 +19633 0.088104248046875 +19634 0.011199951171875 +19635 -0.0147705078125 +19636 -0.171051025390625 +19637 -0.121490478515625 +19638 -0.33740234375 +19639 -0.217742919921875 +19640 -0.47198486328125 +19641 -0.294464111328125 +19642 -0.560394287109375 +19643 -0.343505859375 +19644 -0.58056640625 +19645 -0.352447509765625 +19646 -0.54754638671875 +19647 -0.329986572265625 +19648 -0.508575439453125 +19649 -0.303192138671875 +19650 -0.459503173828125 +19651 -0.269989013671875 +19652 -0.394378662109375 +19653 -0.227325439453125 +19654 -0.35260009765625 +19655 -0.1978759765625 +19656 -0.31170654296875 +19657 -0.169189453125 +19658 -0.197418212890625 +19659 -0.099395751953125 +19660 -0.007965087890625 +19661 0.01226806640625 +19662 0.207489013671875 +19663 0.13763427734375 +19664 0.409210205078125 +19665 0.2540283203125 +19666 0.57208251953125 +19667 0.34710693359375 +19668 0.66595458984375 +19669 0.399749755859375 +19670 0.65875244140625 +19671 0.393829345703125 +19672 0.56744384765625 +19673 0.339111328125 +19674 0.431396484375 +19675 0.258148193359375 +19676 0.29443359375 +19677 0.176055908203125 +19678 0.182464599609375 +19679 0.107818603515625 +19680 0.06365966796875 +19681 0.035614013671875 +19682 -0.075958251953125 +19683 -0.0482177734375 +19684 -0.189422607421875 +19685 -0.116790771484375 +19686 -0.271942138671875 +19687 -0.1671142578125 +19688 -0.342529296875 +19689 -0.2098388671875 +19690 -0.364166259765625 +19691 -0.223846435546875 +19692 -0.327239990234375 +19693 -0.20361328125 +19694 -0.2769775390625 +19695 -0.174835205078125 +19696 -0.253692626953125 +19697 -0.160430908203125 +19698 -0.24365234375 +19699 -0.152679443359375 +19700 -0.1983642578125 +19701 -0.124176025390625 +19702 -0.116241455078125 +19703 -0.074188232421875 +19704 -0.036834716796875 +19705 -0.025360107421875 +19706 0.034881591796875 +19707 0.01922607421875 +19708 0.09124755859375 +19709 0.055023193359375 +19710 0.10888671875 +19711 0.06854248046875 +19712 0.125518798828125 +19713 0.08062744140625 +19714 0.15771484375 +19715 0.100433349609375 +19716 0.17828369140625 +19717 0.112884521484375 +19718 0.17108154296875 +19719 0.109405517578125 +19720 0.129974365234375 +19721 0.086822509765625 +19722 0.082427978515625 +19723 0.059967041015625 +19724 0.027679443359375 +19725 0.028564453125 +19726 -0.065643310546875 +19727 -0.0240478515625 +19728 -0.15936279296875 +19729 -0.077239990234375 +19730 -0.21307373046875 +19731 -0.109222412109375 +19732 -0.234649658203125 +19733 -0.124053955078125 +19734 -0.2001953125 +19735 -0.1087646484375 +19736 -0.119171142578125 +19737 -0.068267822265625 +19738 -0.024749755859375 +19739 -0.020233154296875 +19740 0.085784912109375 +19741 0.036895751953125 +19742 0.178131103515625 +19743 0.0848388671875 +19744 0.215576171875 +19745 0.10400390625 +19746 0.211456298828125 +19747 0.101531982421875 +19748 0.17523193359375 +19749 0.082489013671875 +19750 0.128753662109375 +19751 0.058563232421875 +19752 0.1019287109375 +19753 0.04571533203125 +19754 0.0743408203125 +19755 0.03289794921875 +19756 0.04327392578125 +19757 0.018524169921875 +19758 0.038177490234375 +19759 0.01824951171875 +19760 0.076263427734375 +19761 0.041168212890625 +19762 0.14105224609375 +19763 0.07830810546875 +19764 0.186431884765625 +19765 0.104827880859375 +19766 0.188812255859375 +19767 0.10797119140625 +19768 0.1390380859375 +19769 0.082733154296875 +19770 0.041778564453125 +19771 0.03155517578125 +19772 -0.079437255859375 +19773 -0.032958984375 +19774 -0.219390869140625 +19775 -0.108062744140625 +19776 -0.367828369140625 +19777 -0.188201904296875 +19778 -0.494873046875 +19779 -0.25732421875 +19780 -0.556243896484375 +19781 -0.2916259765625 +19782 -0.508697509765625 +19783 -0.26788330078125 +19784 -0.3756103515625 +19785 -0.198486328125 +19786 -0.218902587890625 +19787 -0.11651611328125 +19788 -0.063751220703125 +19789 -0.035369873046875 +19790 0.091552734375 +19791 0.04595947265625 +19792 0.23602294921875 +19793 0.1217041015625 +19794 0.342987060546875 +19795 0.177642822265625 +19796 0.39520263671875 +19797 0.204620361328125 +19798 0.389373779296875 +19799 0.200927734375 +19800 0.324249267578125 +19801 0.1658935546875 +19802 0.224090576171875 +19803 0.112518310546875 +19804 0.124267578125 +19805 0.059722900390625 +19806 0.037078857421875 +19807 0.014068603515625 +19808 -0.010101318359375 +19809 -0.00982666015625 +19810 -0.019439697265625 +19811 -0.01324462890625 +19812 -0.022796630859375 +19813 -0.013336181640625 +19814 -0.001556396484375 +19815 -0.000213623046875 +19816 0.056304931640625 +19817 0.032440185546875 +19818 0.106719970703125 +19819 0.0609130859375 +19820 0.096893310546875 +19821 0.056854248046875 +19822 0.042694091796875 +19823 0.028717041015625 +19824 -0.018035888671875 +19825 -0.003265380859375 +19826 -0.07586669921875 +19827 -0.034027099609375 +19828 -0.11944580078125 +19829 -0.057525634765625 +19830 -0.15972900390625 +19831 -0.079620361328125 +19832 -0.202606201171875 +19833 -0.103424072265625 +19834 -0.24859619140625 +19835 -0.129119873046875 +19836 -0.30517578125 +19837 -0.160614013671875 +19838 -0.36212158203125 +19839 -0.192413330078125 +19840 -0.39141845703125 +19841 -0.209442138671875 +19842 -0.35528564453125 +19843 -0.191375732421875 +19844 -0.249969482421875 +19845 -0.136138916015625 +19846 -0.092864990234375 +19847 -0.053009033203125 +19848 0.08905029296875 +19849 0.04364013671875 +19850 0.2352294921875 +19851 0.121368408203125 +19852 0.318817138671875 +19853 0.16583251953125 +19854 0.358642578125 +19855 0.187103271484375 +19856 0.347747802734375 +19857 0.181488037109375 +19858 0.28564453125 +19859 0.148681640625 +19860 0.223175048828125 +19861 0.11590576171875 +19862 0.196746826171875 +19863 0.102630615234375 +19864 0.179840087890625 +19865 0.0946044921875 +19866 0.155548095703125 +19867 0.08270263671875 +19868 0.151214599609375 +19869 0.081512451171875 +19870 0.156951904296875 +19871 0.085662841796875 +19872 0.13177490234375 +19873 0.073089599609375 +19874 0.100799560546875 +19875 0.0572509765625 +19876 0.087127685546875 +19877 0.05047607421875 +19878 0.05487060546875 +19879 0.033538818359375 +19880 -0.009002685546875 +19881 -0.000579833984375 +19882 -0.10400390625 +19883 -0.051605224609375 +19884 -0.229400634765625 +19885 -0.119110107421875 +19886 -0.35552978515625 +19887 -0.18719482421875 +19888 -0.441925048828125 +19889 -0.234130859375 +19890 -0.473846435546875 +19891 -0.25201416015625 +19892 -0.464813232421875 +19893 -0.248016357421875 +19894 -0.419097900390625 +19895 -0.224365234375 +19896 -0.334320068359375 +19897 -0.17974853515625 +19898 -0.227935791015625 +19899 -0.12347412109375 +19900 -0.12347412109375 +19901 -0.068145751953125 +19902 -0.02764892578125 +19903 -0.017303466796875 +19904 0.077667236328125 +19905 0.038787841796875 +19906 0.2132568359375 +19907 0.11126708984375 +19908 0.38885498046875 +19909 0.205352783203125 +19910 0.582794189453125 +19911 0.3094482421875 +19912 0.734039306640625 +19913 0.39080810546875 +19914 0.800140380859375 +19915 0.426666259765625 +19916 0.7783203125 +19917 0.415496826171875 +19918 0.6651611328125 +19919 0.355438232421875 +19920 0.45965576171875 +19921 0.245941162109375 +19922 0.199188232421875 +19923 0.10699462890625 +19924 -0.050689697265625 +19925 -0.026275634765625 +19926 -0.23297119140625 +19927 -0.123382568359375 +19928 -0.33013916015625 +19929 -0.174957275390625 +19930 -0.368408203125 +19931 -0.195068359375 +19932 -0.378936767578125 +19933 -0.200439453125 +19934 -0.376983642578125 +19935 -0.19927978515625 +19936 -0.37969970703125 +19937 -0.200775146484375 +19938 -0.391510009765625 +19939 -0.207275390625 +19940 -0.385345458984375 +19941 -0.20428466796875 +19942 -0.3419189453125 +19943 -0.181427001953125 +19944 -0.28289794921875 +19945 -0.150299072265625 +19946 -0.251617431640625 +19947 -0.134063720703125 +19948 -0.266143798828125 +19949 -0.142364501953125 +19950 -0.273345947265625 +19951 -0.146728515625 +19952 -0.216796875 +19953 -0.11688232421875 +19954 -0.128265380859375 +19955 -0.069793701171875 +19956 -0.068145751953125 +19957 -0.037841796875 +19958 -0.0430908203125 +19959 -0.02459716796875 +19960 -0.024444580078125 +19961 -0.014678955078125 +19962 0.020721435546875 +19963 0.009552001953125 +19964 0.124481201171875 +19965 0.065277099609375 +19966 0.25787353515625 +19967 0.136962890625 +19968 0.379119873046875 +19969 0.201629638671875 +19970 0.47991943359375 +19971 0.255035400390625 +19972 0.5281982421875 +19973 0.28131103515625 +19974 0.511138916015625 +19975 0.2738037109375 +19976 0.456207275390625 +19977 0.246246337890625 +19978 0.407470703125 +19979 0.2208251953125 +19980 0.383758544921875 +19981 0.20709228515625 +19982 0.35687255859375 +19983 0.190948486328125 +19984 0.31182861328125 +19985 0.165008544921875 +19986 0.250885009765625 +19987 0.130615234375 +19988 0.1654052734375 +19989 0.0836181640625 +19990 0.035247802734375 +19991 0.014129638671875 +19992 -0.142059326171875 +19993 -0.078857421875 +19994 -0.33563232421875 +19995 -0.1795654296875 +19996 -0.5345458984375 +19997 -0.282318115234375 +19998 -0.72186279296875 +19999 -0.378448486328125 +20000 -0.836669921875 +20001 -0.437164306640625 +20002 -0.8326416015625 +20003 -0.435089111328125 +20004 -0.7296142578125 +20005 -0.382232666015625 +20006 -0.582550048828125 +20007 -0.306427001953125 +20008 -0.440093994140625 +20009 -0.232269287109375 +20010 -0.324310302734375 +20011 -0.171051025390625 +20012 -0.20147705078125 +20013 -0.105926513671875 +20014 -0.044647216796875 +20015 -0.02349853515625 +20016 0.103973388671875 +20017 0.05474853515625 +20018 0.202392578125 +20019 0.10748291015625 +20020 0.264495849609375 +20021 0.141510009765625 +20022 0.338897705078125 +20023 0.18121337890625 +20024 0.443817138671875 +20025 0.23565673828125 +20026 0.545074462890625 +20027 0.287567138671875 +20028 0.6173095703125 +20029 0.324127197265625 +20030 0.6524658203125 +20031 0.341278076171875 +20032 0.66339111328125 +20033 0.3455810546875 +20034 0.6561279296875 +20035 0.340118408203125 +20036 0.606781005859375 +20037 0.31298828125 +20038 0.501190185546875 +20039 0.257171630859375 +20040 0.352783203125 +20041 0.1795654296875 +20042 0.176544189453125 +20043 0.087921142578125 +20044 -0.034820556640625 +20045 -0.021270751953125 +20046 -0.258209228515625 +20047 -0.136199951171875 +20048 -0.44244384765625 +20049 -0.23095703125 +20050 -0.5753173828125 +20051 -0.29931640625 +20052 -0.65203857421875 +20053 -0.33880615234375 +20054 -0.641632080078125 +20055 -0.33380126953125 +20056 -0.562164306640625 +20057 -0.293426513671875 +20058 -0.458038330078125 +20059 -0.240081787109375 +20060 -0.350555419921875 +20061 -0.184539794921875 +20062 -0.260528564453125 +20063 -0.13739013671875 +20064 -0.192108154296875 +20065 -0.100830078125 +20066 -0.141937255859375 +20067 -0.07330322265625 +20068 -0.1021728515625 +20069 -0.05096435546875 +20070 -0.062896728515625 +20071 -0.028961181640625 +20072 -0.011932373046875 +20073 -0.00128173828125 +20074 0.062835693359375 +20075 0.0380859375 +20076 0.148712158203125 +20077 0.082672119140625 +20078 0.241729736328125 +20079 0.130401611328125 +20080 0.34912109375 +20081 0.18487548828125 +20082 0.457305908203125 +20083 0.2392578125 +20084 0.54388427734375 +20085 0.282257080078125 +20086 0.5728759765625 +20087 0.295806884765625 +20088 0.506591796875 +20089 0.260986328125 +20090 0.351226806640625 +20091 0.1810302734375 +20092 0.146514892578125 +20093 0.076019287109375 +20094 -0.05523681640625 +20095 -0.02752685546875 +20096 -0.21624755859375 +20097 -0.110504150390625 +20098 -0.334930419921875 +20099 -0.1719970703125 +20100 -0.402984619140625 +20101 -0.207733154296875 +20102 -0.4412841796875 +20103 -0.2281494140625 +20104 -0.49578857421875 +20105 -0.256378173828125 +20106 -0.5601806640625 +20107 -0.2891845703125 +20108 -0.600738525390625 +20109 -0.3095703125 +20110 -0.584228515625 +20111 -0.300811767578125 +20112 -0.47930908203125 +20113 -0.24713134765625 +20114 -0.27935791015625 +20115 -0.145263671875 +20116 -0.0089111328125 +20117 -0.00762939453125 +20118 0.268798828125 +20119 0.1337890625 +20120 0.482818603515625 +20121 0.243133544921875 +20122 0.60369873046875 +20123 0.305511474609375 +20124 0.650421142578125 +20125 0.330413818359375 +20126 0.66400146484375 +20127 0.33843994140625 +20128 0.6414794921875 +20129 0.328033447265625 +20130 0.572540283203125 +20131 0.2939453125 +20132 0.498138427734375 +20133 0.256805419921875 +20134 0.439453125 +20135 0.227264404296875 +20136 0.375518798828125 +20137 0.19476318359375 +20138 0.274505615234375 +20139 0.14324951171875 +20140 0.1087646484375 +20141 0.058868408203125 +20142 -0.099395751953125 +20143 -0.04705810546875 +20144 -0.3182373046875 +20145 -0.158477783203125 +20146 -0.5489501953125 +20147 -0.27593994140625 +20148 -0.7738037109375 +20149 -0.390411376953125 +20150 -0.86383056640625 +20151 -0.475189208984375 +20152 -0.870391845703125 +20153 -0.513427734375 +20154 -0.86895751953125 +20155 -0.514007568359375 +20156 -0.861053466796875 +20157 -0.4835205078125 +20158 -0.765869140625 +20159 -0.4132080078125 +20160 -0.5301513671875 +20161 -0.297393798828125 +20162 -0.214691162109375 +20163 -0.1396484375 +20164 0.137359619140625 +20165 0.038299560546875 +20166 0.474822998046875 +20167 0.2105712890625 +20168 0.76239013671875 +20169 0.35919189453125 +20170 0.867462158203125 +20171 0.470489501953125 +20172 0.870361328125 +20173 0.544677734375 +20174 0.86480712890625 +20175 0.57586669921875 +20176 0.831817626953125 +20177 0.566680908203125 +20178 0.677581787109375 +20179 0.52935791015625 +20180 0.495880126953125 +20181 0.466766357421875 +20182 0.30767822265625 +20183 0.38824462890625 +20184 0.116180419921875 +20185 0.294921875 +20186 -0.110748291015625 +20187 0.1707763671875 +20188 -0.381805419921875 +20189 0.0123291015625 +20190 -0.6572265625 +20191 -0.158843994140625 +20192 -0.857421875 +20193 -0.312530517578125 +20194 -0.870391845703125 +20195 -0.42706298828125 +20196 -0.870391845703125 +20197 -0.498809814453125 +20198 -0.86444091796875 +20199 -0.541259765625 +20200 -0.85723876953125 +20201 -0.572357177734375 +20202 -0.790008544921875 +20203 -0.58282470703125 +20204 -0.62847900390625 +20205 -0.545257568359375 +20206 -0.3956298828125 +20207 -0.4580078125 +20208 -0.126708984375 +20209 -0.33758544921875 +20210 0.150115966796875 +20211 -0.19781494140625 +20212 0.424041748046875 +20213 -0.044586181640625 +20214 0.670623779296875 +20215 0.1085205078125 +20216 0.854522705078125 +20217 0.241943359375 +20218 0.866485595703125 +20219 0.34674072265625 +20220 0.86920166015625 +20221 0.415130615234375 +20222 0.8653564453125 +20223 0.456207275390625 +20224 0.857147216796875 +20225 0.4769287109375 +20226 0.766845703125 +20227 0.47552490234375 +20228 0.628509521484375 +20229 0.454193115234375 +20230 0.462127685546875 +20231 0.4097900390625 +20232 0.297210693359375 +20233 0.354644775390625 +20234 0.14862060546875 +20235 0.2947998046875 +20236 -0.00537109375 +20237 0.219818115234375 +20238 -0.15753173828125 +20239 0.133575439453125 +20240 -0.31304931640625 +20241 0.0347900390625 +20242 -0.48876953125 +20243 -0.082794189453125 +20244 -0.6416015625 +20245 -0.1966552734375 +20246 -0.751373291015625 +20247 -0.294769287109375 +20248 -0.84619140625 +20249 -0.387786865234375 +20250 -0.861297607421875 +20251 -0.468536376953125 +20252 -0.863250732421875 +20253 -0.521240234375 +20254 -0.856597900390625 +20255 -0.53094482421875 +20256 -0.7498779296875 +20257 -0.503448486328125 +20258 -0.624542236328125 +20259 -0.4661865234375 +20260 -0.47808837890625 +20261 -0.408966064453125 +20262 -0.253387451171875 +20263 -0.304473876953125 +20264 0.003692626953125 +20265 -0.174530029296875 +20266 0.2257080078125 +20267 -0.051727294921875 +20268 0.427154541015625 +20269 0.069488525390625 +20270 0.643218994140625 +20271 0.20404052734375 +20272 0.855926513671875 +20273 0.34710693359375 +20274 0.870361328125 +20275 0.4710693359375 +20276 0.870361328125 +20277 0.552276611328125 +20278 0.862762451171875 +20279 0.593963623046875 +20280 0.79669189453125 +20281 0.594696044921875 +20282 0.595794677734375 +20283 0.550018310546875 +20284 0.362152099609375 +20285 0.473785400390625 +20286 0.1270751953125 +20287 0.37939453125 +20288 -0.086944580078125 +20289 0.277069091796875 +20290 -0.2784423828125 +20291 0.16802978515625 +20292 -0.484832763671875 +20293 0.0361328125 +20294 -0.729583740234375 +20295 -0.1273193359375 +20296 -0.86688232421875 +20297 -0.298126220703125 +20298 -0.870391845703125 +20299 -0.446075439453125 +20300 -0.86859130859375 +20301 -0.568572998046875 +20302 -0.86279296875 +20303 -0.664398193359375 +20304 -0.817962646484375 +20305 -0.7164306640625 +20306 -0.6116943359375 +20307 -0.703155517578125 +20308 -0.3128662109375 +20309 -0.621185302734375 +20310 0.039398193359375 +20311 -0.486480712890625 +20312 0.422821044921875 +20313 -0.30859375 +20314 0.805145263671875 +20315 -0.103424072265625 +20316 0.870361328125 +20317 0.09661865234375 +20318 0.870361328125 +20319 0.264312744140625 +20320 0.860015869140625 +20321 0.393829345703125 +20322 0.727935791015625 +20323 0.481170654296875 +20324 0.48114013671875 +20325 0.5233154296875 +20326 0.2059326171875 +20327 0.531341552734375 +20328 -0.06103515625 +20329 0.515625 +20330 -0.29913330078125 +20331 0.480682373046875 +20332 -0.516204833984375 +20333 0.41949462890625 +20334 -0.7252197265625 +20335 0.324798583984375 +20336 -0.85980224609375 +20337 0.2083740234375 +20338 -0.870391845703125 +20339 0.08660888671875 +20340 -0.870391845703125 +20341 -0.0262451171875 +20342 -0.858062744140625 +20343 -0.10687255859375 +20344 -0.673004150390625 +20345 -0.15283203125 +20346 -0.42694091796875 +20347 -0.188446044921875 +20348 -0.2100830078125 +20349 -0.234222412109375 +20350 -0.0362548828125 +20351 -0.2886962890625 +20352 0.10943603515625 +20353 -0.33770751953125 +20354 0.23516845703125 +20355 -0.371490478515625 +20356 0.373687744140625 +20357 -0.3702392578125 +20358 0.517791748046875 +20359 -0.33465576171875 +20360 0.602783203125 +20361 -0.29443359375 +20362 0.635711669921875 +20363 -0.247222900390625 +20364 0.655181884765625 +20365 -0.17742919921875 +20366 0.65948486328125 +20367 -0.0899658203125 +20368 0.651275634765625 +20369 0.010986328125 +20370 0.61846923828125 +20371 0.113494873046875 +20372 0.53753662109375 +20373 0.199615478515625 +20374 0.404144287109375 +20375 0.260345458984375 +20376 0.22186279296875 +20377 0.290618896484375 +20378 0.003997802734375 +20379 0.290618896484375 +20380 -0.22100830078125 +20381 0.2685546875 +20382 -0.42449951171875 +20383 0.233917236328125 +20384 -0.579833984375 +20385 0.196563720703125 +20386 -0.641876220703125 +20387 0.17657470703125 +20388 -0.6177978515625 +20389 0.17083740234375 +20390 -0.575531005859375 +20391 0.148956298828125 +20392 -0.526336669921875 +20393 0.108612060546875 +20394 -0.42645263671875 +20395 0.07452392578125 +20396 -0.2581787109375 +20397 0.05999755859375 +20398 -0.068695068359375 +20399 0.048248291015625 +20400 0.09222412109375 +20401 0.02154541015625 +20402 0.232147216796875 +20403 -0.010894775390625 +20404 0.3509521484375 +20405 -0.043853759765625 +20406 0.410064697265625 +20407 -0.090972900390625 +20408 0.372955322265625 +20409 -0.165802001953125 +20410 0.2554931640625 +20411 -0.25823974609375 +20412 0.10711669921875 +20413 -0.343536376953125 +20414 -0.052886962890625 +20415 -0.412384033203125 +20416 -0.186279296875 +20417 -0.44769287109375 +20418 -0.23291015625 +20419 -0.423248291015625 +20420 -0.209442138671875 +20421 -0.349945068359375 +20422 -0.174163818359375 +20423 -0.2591552734375 +20424 -0.126739501953125 +20425 -0.15509033203125 +20426 -0.048126220703125 +20427 -0.033447265625 +20428 0.0426025390625 +20429 0.092071533203125 +20430 0.10748291015625 +20431 0.1990966796875 +20432 0.1409912109375 +20433 0.281036376953125 +20434 0.19708251953125 +20435 0.360015869140625 +20436 0.273651123046875 +20437 0.4326171875 +20438 0.31768798828125 +20439 0.4722900390625 +20440 0.341094970703125 +20441 0.484100341796875 +20442 0.368011474609375 +20443 0.47991943359375 +20444 0.37249755859375 +20445 0.448944091796875 +20446 0.30072021484375 +20447 0.3680419921875 +20448 0.1517333984375 +20449 0.239715576171875 +20450 -0.01470947265625 +20451 0.09564208984375 +20452 -0.1883544921875 +20453 -0.0555419921875 +20454 -0.372711181640625 +20455 -0.211578369140625 +20456 -0.51397705078125 +20457 -0.343353271484375 +20458 -0.57177734375 +20459 -0.4283447265625 +20460 -0.53948974609375 +20461 -0.460479736328125 +20462 -0.43511962890625 +20463 -0.446014404296875 +20464 -0.2962646484375 +20465 -0.401123046875 +20466 -0.161102294921875 +20467 -0.3431396484375 +20468 -0.0435791015625 +20469 -0.27874755859375 +20470 0.060394287109375 +20471 -0.2069091796875 +20472 0.13665771484375 +20473 -0.135955810546875 +20474 0.170135498046875 +20475 -0.075225830078125 +20476 0.16552734375 +20477 -0.025238037109375 +20478 0.15728759765625 +20479 0.02716064453125 +20480 0.150787353515625 +20481 0.081512451171875 +20482 0.12200927734375 +20483 0.12335205078125 +20484 0.080108642578125 +20485 0.15374755859375 +20486 0.05126953125 +20487 0.182098388671875 +20488 0.062896728515625 +20489 0.218841552734375 +20490 0.09271240234375 +20491 0.2525634765625 +20492 0.092987060546875 +20493 0.26104736328125 +20494 0.07855224609375 +20495 0.2508544921875 +20496 0.06427001953125 +20497 0.229217529296875 +20498 0.0347900390625 +20499 0.19036865234375 +20500 -0.01171875 +20501 0.1351318359375 +20502 -0.056060791015625 +20503 0.074249267578125 +20504 -0.055511474609375 +20505 0.02935791015625 +20506 -0.010467529296875 +20507 0.00286865234375 +20508 0.02508544921875 +20509 -0.02691650390625 +20510 0.025665283203125 +20511 -0.0689697265625 +20512 0.017333984375 +20513 -0.109375 +20514 0.00189208984375 +20515 -0.1455078125 +20516 -0.03173828125 +20517 -0.18096923828125 +20518 -0.071502685546875 +20519 -0.20953369140625 +20520 -0.13543701171875 +20521 -0.239013671875 +20522 -0.219970703125 +20523 -0.268035888671875 +20524 -0.300506591796875 +20525 -0.28631591796875 +20526 -0.376312255859375 +20527 -0.294708251953125 +20528 -0.416107177734375 +20529 -0.28076171875 +20530 -0.371124267578125 +20531 -0.224456787109375 +20532 -0.242279052734375 +20533 -0.128326416015625 +20534 -0.069732666015625 +20535 -0.0125732421875 +20536 0.125640869140625 +20537 0.111297607421875 +20538 0.31268310546875 +20539 0.2274169921875 +20540 0.45501708984375 +20541 0.317779541015625 +20542 0.554779052734375 +20543 0.382049560546875 +20544 0.61065673828125 +20545 0.418792724609375 +20546 0.610931396484375 +20547 0.422332763671875 +20548 0.531463623046875 +20549 0.381866455078125 +20550 0.3883056640625 +20551 0.30511474609375 +20552 0.23468017578125 +20553 0.2169189453125 +20554 0.095245361328125 +20555 0.129608154296875 +20556 -0.00396728515625 +20557 0.056365966796875 +20558 -0.04852294921875 +20559 0.005340576171875 +20560 -0.055145263671875 +20561 -0.029205322265625 +20562 -0.0758056640625 +20563 -0.06890869140625 +20564 -0.138702392578125 +20565 -0.124847412109375 +20566 -0.209197998046875 +20567 -0.17999267578125 +20568 -0.289031982421875 +20569 -0.23394775390625 +20570 -0.37884521484375 +20571 -0.286224365234375 +20572 -0.456329345703125 +20573 -0.326263427734375 +20574 -0.51641845703125 +20575 -0.35174560546875 +20576 -0.519287109375 +20577 -0.345001220703125 +20578 -0.458251953125 +20579 -0.303619384765625 +20580 -0.384796142578125 +20581 -0.251708984375 +20582 -0.323699951171875 +20583 -0.20159912109375 +20584 -0.269287109375 +20585 -0.152069091796875 +20586 -0.1951904296875 +20587 -0.09271240234375 +20588 -0.100006103515625 +20589 -0.024322509765625 +20590 -0.01055908203125 +20591 0.03961181640625 +20592 0.1033935546875 +20593 0.1114501953125 +20594 0.24908447265625 +20595 0.19342041015625 +20596 0.373199462890625 +20597 0.260772705078125 +20598 0.45806884765625 +20599 0.305084228515625 +20600 0.511474609375 +20601 0.32965087890625 +20602 0.565399169921875 +20603 0.3489990234375 +20604 0.61138916015625 +20605 0.359771728515625 +20606 0.5897216796875 +20607 0.33575439453125 +20608 0.4906005859375 +20609 0.273468017578125 +20610 0.33148193359375 +20611 0.18182373046875 +20612 0.147796630859375 +20613 0.077911376953125 +20614 -0.01873779296875 +20615 -0.018310546875 +20616 -0.140289306640625 +20617 -0.093109130859375 +20618 -0.191986083984375 +20619 -0.134246826171875 +20620 -0.184295654296875 +20621 -0.1455078125 +20622 -0.161834716796875 +20623 -0.146270751953125 +20624 -0.166595458984375 +20625 -0.154937744140625 +20626 -0.19390869140625 +20627 -0.169219970703125 +20628 -0.22442626953125 +20629 -0.180389404296875 +20630 -0.279754638671875 +20631 -0.19842529296875 +20632 -0.3389892578125 +20633 -0.214447021484375 +20634 -0.3543701171875 +20635 -0.207672119140625 +20636 -0.348175048828125 +20637 -0.188934326171875 +20638 -0.32598876953125 +20639 -0.16168212890625 +20640 -0.2581787109375 +20641 -0.11358642578125 +20642 -0.139801025390625 +20643 -0.043365478515625 +20644 0.014617919921875 +20645 0.041534423828125 +20646 0.144378662109375 +20647 0.11297607421875 +20648 0.221038818359375 +20649 0.15753173828125 +20650 0.27069091796875 +20651 0.18646240234375 +20652 0.294036865234375 +20653 0.199859619140625 +20654 0.311767578125 +20655 0.207000732421875 +20656 0.339141845703125 +20657 0.21484375 +20658 0.360260009765625 +20659 0.2164306640625 +20660 0.360504150390625 +20661 0.205780029296875 +20662 0.308380126953125 +20663 0.169708251953125 +20664 0.18170166015625 +20665 0.099273681640625 +20666 0.0047607421875 +20667 0.006072998046875 +20668 -0.17559814453125 +20669 -0.08837890625 +20670 -0.3143310546875 +20671 -0.1634521484375 +20672 -0.36785888671875 +20673 -0.199249267578125 +20674 -0.36248779296875 +20675 -0.206695556640625 +20676 -0.343536376953125 +20677 -0.20526123046875 +20678 -0.3018798828125 +20679 -0.190704345703125 +20680 -0.231414794921875 +20681 -0.160186767578125 +20682 -0.117645263671875 +20683 -0.107391357421875 +20684 0.007049560546875 +20685 -0.04681396484375 +20686 0.087982177734375 +20687 -0.002899169921875 +20688 0.13946533203125 +20689 0.03009033203125 +20690 0.17425537109375 +20691 0.057159423828125 +20692 0.188201904296875 +20693 0.075775146484375 +20694 0.171234130859375 +20695 0.080810546875 +20696 0.118438720703125 +20697 0.069427490234375 +20698 0.05706787109375 +20699 0.053009033203125 +20700 -0.010711669921875 +20701 0.031951904296875 +20702 -0.0914306640625 +20703 0.0029296875 +20704 -0.162322998046875 +20705 -0.0242919921875 +20706 -0.194549560546875 +20707 -0.03717041015625 +20708 -0.1492919921875 +20709 -0.018646240234375 +20710 -0.02166748046875 +20711 0.033599853515625 +20712 0.124053955078125 +20713 0.091552734375 +20714 0.211151123046875 +20715 0.121856689453125 +20716 0.240447998046875 +20717 0.125396728515625 +20718 0.242218017578125 +20719 0.115997314453125 +20720 0.2257080078125 +20721 0.098358154296875 +20722 0.194366455078125 +20723 0.074554443359375 +20724 0.115509033203125 +20725 0.030731201171875 +20726 0.0128173828125 +20727 -0.022186279296875 +20728 -0.053802490234375 +20729 -0.057464599609375 +20730 -0.110626220703125 +20731 -0.086395263671875 +20732 -0.199493408203125 +20733 -0.12725830078125 +20734 -0.29437255859375 +20735 -0.168548583984375 +20736 -0.33221435546875 +20737 -0.1829833984375 +20738 -0.27972412109375 +20739 -0.156829833984375 +20740 -0.185333251953125 +20741 -0.11065673828125 +20742 -0.128204345703125 +20743 -0.077545166015625 +20744 -0.115692138671875 +20745 -0.061309814453125 +20746 -0.116455078125 +20747 -0.049957275390625 +20748 -0.105926513671875 +20749 -0.03424072265625 +20750 -0.053955078125 +20751 -0.002532958984375 +20752 0.048797607421875 +20753 0.048370361328125 +20754 0.157318115234375 +20755 0.09967041015625 +20756 0.212005615234375 +20757 0.126708984375 +20758 0.218475341796875 +20759 0.131622314453125 +20760 0.23724365234375 +20761 0.139068603515625 +20762 0.30535888671875 +20763 0.164276123046875 +20764 0.38128662109375 +20765 0.190521240234375 +20766 0.404449462890625 +20767 0.19342041015625 +20768 0.3944091796875 +20769 0.181365966796875 +20770 0.3885498046875 +20771 0.17010498046875 +20772 0.362640380859375 +20773 0.1502685546875 +20774 0.27362060546875 +20775 0.104827880859375 +20776 0.11712646484375 +20777 0.032501220703125 +20778 -0.054901123046875 +20779 -0.0450439453125 +20780 -0.19085693359375 +20781 -0.10638427734375 +20782 -0.28570556640625 +20783 -0.149200439453125 +20784 -0.339263916015625 +20785 -0.173248291015625 +20786 -0.3775634765625 +20787 -0.1890869140625 +20788 -0.445709228515625 +20789 -0.215179443359375 +20790 -0.535064697265625 +20791 -0.248138427734375 +20792 -0.629058837890625 +20793 -0.28143310546875 +20794 -0.697601318359375 +20795 -0.3031005859375 +20796 -0.70391845703125 +20797 -0.29852294921875 +20798 -0.6424560546875 +20799 -0.265869140625 +20800 -0.491241455078125 +20801 -0.19659423828125 +20802 -0.265716552734375 +20803 -0.097412109375 +20804 -0.023712158203125 +20805 0.007659912109375 +20806 0.201751708984375 +20807 0.1048583984375 +20808 0.375823974609375 +20809 0.1796875 +20810 0.485076904296875 +20811 0.226531982421875 +20812 0.56884765625 +20813 0.2613525390625 +20814 0.634765625 +20815 0.287261962890625 +20816 0.63763427734375 +20817 0.28594970703125 +20818 0.5660400390625 +20819 0.2529296875 +20820 0.4720458984375 +20821 0.209686279296875 +20822 0.40692138671875 +20823 0.177398681640625 +20824 0.3778076171875 +20825 0.159332275390625 +20826 0.376953125 +20827 0.152679443359375 +20828 0.371978759765625 +20829 0.14459228515625 +20830 0.313140869140625 +20831 0.115081787109375 +20832 0.184417724609375 +20833 0.057891845703125 +20834 0.011199951171875 +20835 -0.016357421875 +20836 -0.171051025390625 +20837 -0.093017578125 +20838 -0.33740234375 +20839 -0.161834716796875 +20840 -0.47198486328125 +20841 -0.21630859375 +20842 -0.560394287109375 +20843 -0.250640869140625 +20844 -0.58056640625 +20845 -0.2559814453125 +20846 -0.54754638671875 +20847 -0.2386474609375 +20848 -0.508575439453125 +20849 -0.218170166015625 +20850 -0.459503173828125 +20851 -0.193115234375 +20852 -0.394378662109375 +20853 -0.161346435546875 +20854 -0.35260009765625 +20855 -0.139190673828125 +20856 -0.31170654296875 +20857 -0.117767333984375 +20858 -0.197418212890625 +20859 -0.0670166015625 +20860 -0.007965087890625 +20861 0.0135498046875 +20862 0.207489013671875 +20863 0.10369873046875 +20864 0.409210205078125 +20865 0.187103271484375 +20866 0.57208251953125 +20867 0.253509521484375 +20868 0.66595458984375 +20869 0.2906494140625 +20870 0.65875244140625 +20871 0.285552978515625 +20872 0.56744384765625 +20873 0.24530029296875 +20874 0.431396484375 +20875 0.186126708984375 +20876 0.29443359375 +20877 0.126129150390625 +20878 0.182464599609375 +20879 0.07611083984375 +20880 0.06365966796875 +20881 0.023345947265625 +20882 -0.075958251953125 +20883 -0.037628173828125 +20884 -0.189422607421875 +20885 -0.087432861328125 +20886 -0.271942138671875 +20887 -0.123931884765625 +20888 -0.342529296875 +20889 -0.15472412109375 +20890 -0.364166259765625 +20891 -0.1646728515625 +20892 -0.327239990234375 +20893 -0.149810791015625 +20894 -0.2769775390625 +20895 -0.12860107421875 +20896 -0.253692626953125 +20897 -0.1175537109375 +20898 -0.24365234375 +20899 -0.111175537109375 +20900 -0.1983642578125 +20901 -0.089813232421875 +20902 -0.116241455078125 +20903 -0.053009033203125 +20904 -0.036834716796875 +20905 -0.017059326171875 +20906 0.034881591796875 +20907 0.0157470703125 +20908 0.09124755859375 +20909 0.042083740234375 +20910 0.10888671875 +20911 0.05224609375 +20912 0.125518798828125 +20913 0.061492919921875 +20914 0.15771484375 +20915 0.07647705078125 +20916 0.17828369140625 +20917 0.08599853515625 +20918 0.17108154296875 +20919 0.08343505859375 +20920 0.129974365234375 +20921 0.0662841796875 +20922 0.082427978515625 +20923 0.0457763671875 +20924 0.027679443359375 +20925 0.021697998046875 +20926 -0.065643310546875 +20927 -0.018585205078125 +20928 -0.15936279296875 +20929 -0.059356689453125 +20930 -0.21307373046875 +20931 -0.084014892578125 +20932 -0.234649658203125 +20933 -0.09564208984375 +20934 -0.2001953125 +20935 -0.084320068359375 +20936 -0.119171142578125 +20937 -0.05377197265625 +20938 -0.024749755859375 +20939 -0.01739501953125 +20940 0.085784912109375 +20941 0.0260009765625 +20942 0.178131103515625 +20943 0.0625 +20944 0.215576171875 +20945 0.077178955078125 +20946 0.211456298828125 +20947 0.07550048828125 +20948 0.17523193359375 +20949 0.06134033203125 +20950 0.128753662109375 +20951 0.04351806640625 +20952 0.1019287109375 +20953 0.0341796875 +20954 0.0743408203125 +20955 0.02490234375 +20956 0.04327392578125 +20957 0.014434814453125 +20958 0.038177490234375 +20959 0.014678955078125 +20960 0.076263427734375 +20961 0.032501220703125 +20962 0.14105224609375 +20963 0.061065673828125 +20964 0.186431884765625 +20965 0.081451416015625 +20966 0.188812255859375 +20967 0.08392333984375 +20968 0.1390380859375 +20969 0.064697265625 +20970 0.041778564453125 +20971 0.025634765625 +20972 -0.079437255859375 +20973 -0.023681640625 +20974 -0.219390869140625 +20975 -0.08111572265625 +20976 -0.367828369140625 +20977 -0.142425537109375 +20978 -0.494873046875 +20979 -0.19537353515625 +20980 -0.556243896484375 +20981 -0.221832275390625 +20982 -0.508697509765625 +20983 -0.204071044921875 +20984 -0.3756103515625 +20985 -0.151519775390625 +20986 -0.218902587890625 +20987 -0.08935546875 +20988 -0.063751220703125 +20989 -0.027740478515625 +20990 0.091552734375 +20991 0.0340576171875 +20992 0.23602294921875 +20993 0.091583251953125 +20994 0.342987060546875 +20995 0.134033203125 +20996 0.39520263671875 +20997 0.15472412109375 +20998 0.389373779296875 +20999 0.152679443359375 +21000 0.324249267578125 +21001 0.127655029296875 +21002 0.224090576171875 +21003 0.0889892578125 +21004 0.124267578125 +21005 0.0501708984375 +21006 0.037078857421875 +21007 0.0159912109375 +21008 -0.010101318359375 +21009 -0.00311279296875 +21010 -0.019439697265625 +21011 -0.007843017578125 +21012 -0.022796630859375 +21013 -0.0101318359375 +21014 -0.001556396484375 +21015 -0.0029296875 +21016 0.056304931640625 +21017 0.018280029296875 +21018 0.106719970703125 +21019 0.03692626953125 +21020 0.096893310546875 +21021 0.03314208984375 +21022 0.042694091796875 +21023 0.012908935546875 +21024 -0.018035888671875 +21025 -0.009552001953125 +21026 -0.07586669921875 +21027 -0.030731201171875 +21028 -0.11944580078125 +21029 -0.046417236328125 +21030 -0.15972900390625 +21031 -0.060791015625 +21032 -0.202606201171875 +21033 -0.076080322265625 +21034 -0.24859619140625 +21035 -0.092529296875 +21036 -0.30517578125 +21037 -0.113006591796875 +21038 -0.36212158203125 +21039 -0.133697509765625 +21040 -0.39141845703125 +21041 -0.144134521484375 +21042 -0.35528564453125 +21043 -0.130157470703125 +21044 -0.249969482421875 +21045 -0.090362548828125 +21046 -0.092864990234375 +21047 -0.03131103515625 +21048 0.08905029296875 +21049 0.036865234375 +21050 0.2352294921875 +21051 0.0914306640625 +21052 0.318817138671875 +21053 0.122314453125 +21054 0.358642578125 +21055 0.136627197265625 +21056 0.347747802734375 +21057 0.13177490234375 +21058 0.28564453125 +21059 0.107635498046875 +21060 0.223175048828125 +21061 0.0833740234375 +21062 0.196746826171875 +21063 0.072723388671875 +21064 0.179840087890625 +21065 0.06573486328125 +21066 0.155548095703125 +21067 0.056121826171875 +21068 0.151214599609375 +21069 0.054168701171875 +21070 0.156951904296875 +21071 0.056182861328125 +21072 0.13177490234375 +21073 0.046722412109375 +21074 0.100799560546875 +21075 0.03521728515625 +21076 0.087127685546875 +21077 0.03033447265625 +21078 0.05487060546875 +21079 0.01861572265625 +21080 -0.009002685546875 +21081 -0.0048828125 +21082 -0.10400390625 +21083 -0.03997802734375 +21084 -0.229400634765625 +21085 -0.086456298828125 +21086 -0.35552978515625 +21087 -0.133209228515625 +21088 -0.441925048828125 +21089 -0.1650390625 +21090 -0.473846435546875 +21091 -0.176483154296875 +21092 -0.464813232421875 +21093 -0.172607421875 +21094 -0.419097900390625 +21095 -0.155029296875 +21096 -0.334320068359375 +21097 -0.1229248046875 +21098 -0.227935791015625 +21099 -0.082855224609375 +21100 -0.12347412109375 +21101 -0.043670654296875 +21102 -0.02764892578125 +21103 -0.007843017578125 +21104 0.077667236328125 +21105 0.031463623046875 +21106 0.2132568359375 +21107 0.082061767578125 +21108 0.38885498046875 +21109 0.1475830078125 +21110 0.582794189453125 +21111 0.219940185546875 +21112 0.734039306640625 +21113 0.276214599609375 +21114 0.800140380859375 +21115 0.30047607421875 +21116 0.7783203125 +21117 0.291717529296875 +21118 0.6651611328125 +21119 0.248687744140625 +21120 0.45965576171875 +21121 0.1710205078125 +21122 0.199188232421875 +21123 0.072784423828125 +21124 -0.050689697265625 +21125 -0.02130126953125 +21126 -0.23297119140625 +21127 -0.08984375 +21128 -0.33013916015625 +21129 -0.126251220703125 +21130 -0.368408203125 +21131 -0.140380859375 +21132 -0.378936767578125 +21133 -0.143951416015625 +21134 -0.376983642578125 +21135 -0.14276123046875 +21136 -0.37969970703125 +21137 -0.143280029296875 +21138 -0.391510009765625 +21139 -0.147186279296875 +21140 -0.385345458984375 +21141 -0.14434814453125 +21142 -0.3419189453125 +21143 -0.127532958984375 +21144 -0.28289794921875 +21145 -0.104888916015625 +21146 -0.251617431640625 +21147 -0.092742919921875 +21148 -0.266143798828125 +21149 -0.097900390625 +21150 -0.273345947265625 +21151 -0.100433349609375 +21152 -0.216796875 +21153 -0.0791015625 +21154 -0.128265380859375 +21155 -0.045867919921875 +21156 -0.068145751953125 +21157 -0.023406982421875 +21158 -0.0430908203125 +21159 -0.014190673828125 +21160 -0.024444580078125 +21161 -0.0074462890625 +21162 0.020721435546875 +21163 0.009185791015625 +21164 0.124481201171875 +21165 0.047760009765625 +21166 0.25787353515625 +21167 0.097412109375 +21168 0.379119873046875 +21169 0.1424560546875 +21170 0.47991943359375 +21171 0.179840087890625 +21172 0.5281982421875 +21173 0.197509765625 +21174 0.511138916015625 +21175 0.190673828125 +21176 0.456207275390625 +21177 0.169708251953125 +21178 0.407470703125 +21179 0.15118408203125 +21180 0.383758544921875 +21181 0.142181396484375 +21182 0.35687255859375 +21183 0.132110595703125 +21184 0.31182861328125 +21185 0.11529541015625 +21186 0.250885009765625 +21187 0.09259033203125 +21188 0.1654052734375 +21189 0.06072998046875 +21190 0.035247802734375 +21191 0.01214599609375 +21192 -0.142059326171875 +21193 -0.054107666015625 +21194 -0.33563232421875 +21195 -0.126434326171875 +21196 -0.5345458984375 +21197 -0.20074462890625 +21198 -0.72186279296875 +21199 -0.27069091796875 +21200 -0.836669921875 +21201 -0.313385009765625 +21202 -0.8326416015625 +21203 -0.31146240234375 +21204 -0.7296142578125 +21205 -0.27239990234375 +21206 -0.582550048828125 +21207 -0.216888427734375 +21208 -0.440093994140625 +21209 -0.163238525390625 +21210 -0.324310302734375 +21211 -0.119720458984375 +21212 -0.20147705078125 +21213 -0.07366943359375 +21214 -0.044647216796875 +21215 -0.014892578125 +21216 0.103973388671875 +21217 0.040679931640625 +21218 0.202392578125 +21219 0.077301025390625 +21220 0.264495849609375 +21221 0.100189208984375 +21222 0.338897705078125 +21223 0.127655029296875 +21224 0.443817138671875 +21225 0.166595458984375 +21226 0.545074462890625 +21227 0.204193115234375 +21228 0.6173095703125 +21229 0.230926513671875 +21230 0.6524658203125 +21231 0.243804931640625 +21232 0.66339111328125 +21233 0.247650146484375 +21234 0.6561279296875 +21235 0.244781494140625 +21236 0.606781005859375 +21237 0.2261962890625 +21238 0.501190185546875 +21239 0.186553955078125 +21240 0.352783203125 +21241 0.130889892578125 +21242 0.176544189453125 +21243 0.064849853515625 +21244 -0.034820556640625 +21245 -0.014312744140625 +21246 -0.258209228515625 +21247 -0.097900390625 +21248 -0.44244384765625 +21249 -0.1668701171875 +21250 -0.5753173828125 +21251 -0.216522216796875 +21252 -0.65203857421875 +21253 -0.2452392578125 +21254 -0.641632080078125 +21255 -0.242431640625 +21256 -0.562164306640625 +21257 -0.2144775390625 +21258 -0.458038330078125 +21259 -0.176788330078125 +21260 -0.350555419921875 +21261 -0.13690185546875 +21262 -0.260528564453125 +21263 -0.102203369140625 +21264 -0.192108154296875 +21265 -0.07440185546875 +21266 -0.141937255859375 +21267 -0.0526123046875 +21268 -0.1021728515625 +21269 -0.03436279296875 +21270 -0.062896728515625 +21271 -0.0164794921875 +21272 -0.011932373046875 +21273 0.004974365234375 +21274 0.062835693359375 +21275 0.033966064453125 +21276 0.148712158203125 +21277 0.06597900390625 +21278 0.241729736328125 +21279 0.099517822265625 +21280 0.34912109375 +21281 0.137054443359375 +21282 0.457305908203125 +21283 0.17388916015625 +21284 0.54388427734375 +21285 0.202392578125 +21286 0.5728759765625 +21287 0.210296630859375 +21288 0.506591796875 +21289 0.18475341796875 +21290 0.351226806640625 +21291 0.12811279296875 +21292 0.146514892578125 +21293 0.05419921875 +21294 -0.05523681640625 +21295 -0.018768310546875 +21296 -0.21624755859375 +21297 -0.077606201171875 +21298 -0.334930419921875 +21299 -0.121551513671875 +21300 -0.402984619140625 +21301 -0.147613525390625 +21302 -0.4412841796875 +21303 -0.162841796875 +21304 -0.49578857421875 +21305 -0.182952880859375 +21306 -0.5601806640625 +21307 -0.205718994140625 +21308 -0.600738525390625 +21309 -0.21954345703125 +21310 -0.584228515625 +21311 -0.2130126953125 +21312 -0.47930908203125 +21313 -0.1754150390625 +21314 -0.27935791015625 +21315 -0.104583740234375 +21316 -0.0089111328125 +21317 -0.00909423828125 +21318 0.268798828125 +21319 0.089141845703125 +21320 0.482818603515625 +21321 0.16558837890625 +21322 0.60369873046875 +21323 0.209930419921875 +21324 0.650421142578125 +21325 0.22857666015625 +21326 0.66400146484375 +21327 0.2354736328125 +21328 0.6414794921875 +21329 0.229522705078125 +21330 0.572540283203125 +21331 0.20709228515625 +21332 0.498138427734375 +21333 0.18218994140625 +21334 0.439453125 +21335 0.162078857421875 +21336 0.375518798828125 +21337 0.13958740234375 +21338 0.274505615234375 +21339 0.103790283203125 +21340 0.1087646484375 +21341 0.04522705078125 +21342 -0.099395751953125 +21343 -0.028289794921875 +21344 -0.3182373046875 +21345 -0.105712890625 +21346 -0.5489501953125 +21347 -0.187347412109375 +21348 -0.7738037109375 +21349 -0.266937255859375 +21350 -0.86383056640625 +21351 -0.326171875 +21352 -0.870391845703125 +21353 -0.353485107421875 +21354 -0.86895751953125 +21355 -0.354888916015625 +21356 -0.861053466796875 +21357 -0.3348388671875 +21358 -0.765869140625 +21359 -0.287322998046875 +21360 -0.5301513671875 +21361 -0.20843505859375 +21362 -0.214691162109375 +21363 -0.10064697265625 +21364 0.137359619140625 +21365 0.021209716796875 +21366 0.474822998046875 +21367 0.139404296875 +21368 0.76239013671875 +21369 0.241668701171875 +21370 0.867462158203125 +21371 0.318634033203125 +21372 0.870361328125 +21373 0.370361328125 +21374 0.86480712890625 +21375 0.39276123046875 +21376 0.831817626953125 +21377 0.387603759765625 +21378 0.677581787109375 +21379 0.3631591796875 +21380 0.495880126953125 +21381 0.32135009765625 +21382 0.30767822265625 +21383 0.26849365234375 +21384 0.116180419921875 +21385 0.205322265625 +21386 -0.110748291015625 +21387 0.120880126953125 +21388 -0.381805419921875 +21389 0.01275634765625 +21390 -0.6572265625 +21391 -0.104248046875 +21392 -0.857421875 +21393 -0.209503173828125 +21394 -0.870391845703125 +21395 -0.2882080078125 +21396 -0.870391845703125 +21397 -0.337860107421875 +21398 -0.86444091796875 +21399 -0.367645263671875 +21400 -0.85723876953125 +21401 -0.389739990234375 +21402 -0.790008544921875 +21403 -0.39776611328125 +21404 -0.62847900390625 +21405 -0.37298583984375 +21406 -0.3956298828125 +21407 -0.314239501953125 +21408 -0.126708984375 +21409 -0.232757568359375 +21410 0.150115966796875 +21411 -0.137908935546875 +21412 0.424041748046875 +21413 -0.033660888671875 +21414 0.670623779296875 +21415 0.0706787109375 +21416 0.854522705078125 +21417 0.16180419921875 +21418 0.866485595703125 +21419 0.23358154296875 +21420 0.86920166015625 +21421 0.280670166015625 +21422 0.8653564453125 +21423 0.30926513671875 +21424 0.857147216796875 +21425 0.323883056640625 +21426 0.766845703125 +21427 0.323455810546875 +21428 0.628509521484375 +21429 0.3096923828125 +21430 0.462127685546875 +21431 0.28021240234375 +21432 0.297210693359375 +21433 0.24383544921875 +21434 0.14862060546875 +21435 0.204742431640625 +21436 -0.00537109375 +21437 0.155059814453125 +21438 -0.15753173828125 +21439 0.09735107421875 +21440 -0.31304931640625 +21441 0.0303955078125 +21442 -0.48876953125 +21443 -0.050628662109375 +21444 -0.6416015625 +21445 -0.129547119140625 +21446 -0.751373291015625 +21447 -0.197845458984375 +21448 -0.84619140625 +21449 -0.263427734375 +21450 -0.861297607421875 +21451 -0.3211669921875 +21452 -0.863250732421875 +21453 -0.359588623046875 +21454 -0.856597900390625 +21455 -0.367767333984375 +21456 -0.7498779296875 +21457 -0.349822998046875 +21458 -0.624542236328125 +21459 -0.325592041015625 +21460 -0.47808837890625 +21461 -0.287506103515625 +21462 -0.253387451171875 +21463 -0.215423583984375 +21464 0.003692626953125 +21465 -0.125030517578125 +21466 0.2257080078125 +21467 -0.03985595703125 +21468 0.427154541015625 +21469 0.044403076171875 +21470 0.643218994140625 +21471 0.13885498046875 +21472 0.855926513671875 +21473 0.240142822265625 +21474 0.870361328125 +21475 0.3282470703125 +21476 0.870361328125 +21477 0.386077880859375 +21478 0.862762451171875 +21479 0.416046142578125 +21480 0.79669189453125 +21481 0.4171142578125 +21482 0.595794677734375 +21483 0.385955810546875 +21484 0.362152099609375 +21485 0.33258056640625 +21486 0.1270751953125 +21487 0.2666015625 +21488 -0.086944580078125 +21489 0.195281982421875 +21490 -0.2784423828125 +21491 0.119354248046875 +21492 -0.484832763671875 +21493 0.026885986328125 +21494 -0.729583740234375 +21495 -0.08868408203125 +21496 -0.86688232421875 +21497 -0.209930419921875 +21498 -0.870391845703125 +21499 -0.315032958984375 +21500 -0.86859130859375 +21501 -0.402191162109375 +21502 -0.86279296875 +21503 -0.47064208984375 +21504 -0.817962646484375 +21505 -0.50787353515625 +21506 -0.6116943359375 +21507 -0.49853515625 +21508 -0.3128662109375 +21509 -0.4404296875 +21510 0.039398193359375 +21511 -0.344879150390625 +21512 0.422821044921875 +21513 -0.21905517578125 +21514 0.805145263671875 +21515 -0.07427978515625 +21516 0.870361328125 +21517 0.06719970703125 +21518 0.870361328125 +21519 0.186767578125 +21520 0.860015869140625 +21521 0.280029296875 +21522 0.727935791015625 +21523 0.343902587890625 +21524 0.48114013671875 +21525 0.3760986328125 +21526 0.2059326171875 +21527 0.3837890625 +21528 -0.06103515625 +21529 0.373748779296875 +21530 -0.29913330078125 +21531 0.349029541015625 +21532 -0.516204833984375 +21533 0.305206298828125 +21534 -0.7252197265625 +21535 0.23773193359375 +21536 -0.85980224609375 +21537 0.15472412109375 +21538 -0.870391845703125 +21539 0.0673828125 +21540 -0.870391845703125 +21541 -0.014434814453125 +21542 -0.858062744140625 +21543 -0.07489013671875 +21544 -0.673004150390625 +21545 -0.11199951171875 +21546 -0.42694091796875 +21547 -0.1414794921875 +21548 -0.2100830078125 +21549 -0.176544189453125 +21550 -0.0362548828125 +21551 -0.21600341796875 +21552 0.10943603515625 +21553 -0.2503662109375 +21554 0.23516845703125 +21555 -0.273101806640625 +21556 0.373687744140625 +21557 -0.2711181640625 +21558 0.517791748046875 +21559 -0.245025634765625 +21560 0.602783203125 +21561 -0.214630126953125 +21562 0.635711669921875 +21563 -0.1785888671875 +21564 0.655181884765625 +21565 -0.12689208984375 +21566 0.65948486328125 +21567 -0.063140869140625 +21568 0.651275634765625 +21569 0.009552001953125 +21570 0.61846923828125 +21571 0.08294677734375 +21572 0.53753662109375 +21573 0.1448974609375 +21574 0.404144287109375 +21575 0.189178466796875 +21576 0.22186279296875 +21577 0.2122802734375 +21578 0.003997802734375 +21579 0.214202880859375 +21580 -0.22100830078125 +21581 0.2003173828125 +21582 -0.42449951171875 +21583 0.17681884765625 +21584 -0.579833984375 +21585 0.15032958984375 +21586 -0.641876220703125 +21587 0.13427734375 +21588 -0.6177978515625 +21589 0.12677001953125 +21590 -0.575531005859375 +21591 0.107940673828125 +21592 -0.526336669921875 +21593 0.076507568359375 +21594 -0.42645263671875 +21595 0.049102783203125 +21596 -0.2581787109375 +21597 0.034759521484375 +21598 -0.068695068359375 +21599 0.02264404296875 +21600 0.09222412109375 +21601 0.00128173828125 +21602 0.232147216796875 +21603 -0.023040771484375 +21604 0.3509521484375 +21605 -0.046783447265625 +21606 0.410064697265625 +21607 -0.078857421875 +21608 0.372955322265625 +21609 -0.128204345703125 +21610 0.2554931640625 +21611 -0.18817138671875 +21612 0.10711669921875 +21613 -0.24249267578125 +21614 -0.052886962890625 +21615 -0.285125732421875 +21616 -0.186279296875 +21617 -0.304962158203125 +21618 -0.23291015625 +21619 -0.284881591796875 +21620 -0.209442138671875 +21621 -0.232330322265625 +21622 -0.174163818359375 +21623 -0.16827392578125 +21624 -0.126739501953125 +21625 -0.095733642578125 +21626 -0.048126220703125 +21627 -0.012054443359375 +21628 0.0426025390625 +21629 0.073516845703125 +21630 0.10748291015625 +21631 0.146087646484375 +21632 0.1409912109375 +21633 0.20123291015625 +21634 0.19708251953125 +21635 0.253509521484375 +21636 0.273651123046875 +21637 0.300689697265625 +21638 0.31768798828125 +21639 0.3253173828125 +21640 0.341094970703125 +21641 0.330841064453125 +21642 0.368011474609375 +21643 0.325286865234375 +21644 0.37249755859375 +21645 0.301666259765625 +21646 0.30072021484375 +21647 0.244873046875 +21648 0.1517333984375 +21649 0.156768798828125 +21650 -0.01470947265625 +21651 0.058441162109375 +21652 -0.1883544921875 +21653 -0.044189453125 +21654 -0.372711181640625 +21655 -0.1495361328125 +21656 -0.51397705078125 +21657 -0.238250732421875 +21658 -0.57177734375 +21659 -0.295379638671875 +21660 -0.53948974609375 +21661 -0.31689453125 +21662 -0.43511962890625 +21663 -0.306915283203125 +21664 -0.2962646484375 +21665 -0.276153564453125 +21666 -0.161102294921875 +21667 -0.23614501953125 +21668 -0.0435791015625 +21669 -0.19140625 +21670 0.060394287109375 +21671 -0.14141845703125 +21672 0.13665771484375 +21673 -0.091796875 +21674 0.170135498046875 +21675 -0.04888916015625 +21676 0.16552734375 +21677 -0.013214111328125 +21678 0.15728759765625 +21679 0.023773193359375 +21680 0.150787353515625 +21681 0.061553955078125 +21682 0.12200927734375 +21683 0.0904541015625 +21684 0.080108642578125 +21685 0.111297607421875 +21686 0.05126953125 +21687 0.13055419921875 +21688 0.062896728515625 +21689 0.1553955078125 +21690 0.09271240234375 +21691 0.17791748046875 +21692 0.092987060546875 +21693 0.1827392578125 +21694 0.07855224609375 +21695 0.174468994140625 +21696 0.06427001953125 +21697 0.158172607421875 +21698 0.0347900390625 +21699 0.129913330078125 +21700 -0.01171875 +21701 0.09039306640625 +21702 -0.056060791015625 +21703 0.047149658203125 +21704 -0.055511474609375 +21705 0.015228271484375 +21706 -0.010467529296875 +21707 -0.003631591796875 +21708 0.02508544921875 +21709 -0.024444580078125 +21710 0.025665283203125 +21711 -0.053466796875 +21712 0.017333984375 +21713 -0.0810546875 +21714 0.00189208984375 +21715 -0.105377197265625 +21716 -0.03173828125 +21717 -0.128997802734375 +21718 -0.071502685546875 +21719 -0.14764404296875 +21720 -0.13543701171875 +21721 -0.166778564453125 +21722 -0.219970703125 +21723 -0.185546875 +21724 -0.300506591796875 +21725 -0.196868896484375 +21726 -0.376312255859375 +21727 -0.20147705078125 +21728 -0.416107177734375 +21729 -0.1907958984375 +21730 -0.371124267578125 +21731 -0.150970458984375 +21732 -0.242279052734375 +21733 -0.08380126953125 +21734 -0.069732666015625 +21735 -0.003326416015625 +21736 0.125640869140625 +21737 0.082489013671875 +21738 0.31268310546875 +21739 0.162628173828125 +21740 0.45501708984375 +21741 0.224639892578125 +21742 0.554779052734375 +21743 0.268310546875 +21744 0.61065673828125 +21745 0.292755126953125 +21746 0.610931396484375 +21747 0.2940673828125 +21748 0.531463623046875 +21749 0.26483154296875 +21750 0.3883056640625 +21751 0.21044921875 +21752 0.23468017578125 +21753 0.148193359375 +21754 0.095245361328125 +21755 0.086700439453125 +21756 -0.00396728515625 +21757 0.035186767578125 +21758 -0.04852294921875 +21759 -0.000640869140625 +21760 -0.055145263671875 +21761 -0.024993896484375 +21762 -0.0758056640625 +21763 -0.052734375 +21764 -0.138702392578125 +21765 -0.09124755859375 +21766 -0.209197998046875 +21767 -0.1290283203125 +21768 -0.289031982421875 +21769 -0.1656494140625 +21770 -0.37884521484375 +21771 -0.20068359375 +21772 -0.456329345703125 +21773 -0.22705078125 +21774 -0.51641845703125 +21775 -0.2431640625 +21776 -0.519287109375 +21777 -0.2373046875 +21778 -0.458251953125 +21779 -0.207977294921875 +21780 -0.384796142578125 +21781 -0.17132568359375 +21782 -0.323699951171875 +21783 -0.13568115234375 +21784 -0.269287109375 +21785 -0.100341796875 +21786 -0.1951904296875 +21787 -0.05853271484375 +21788 -0.100006103515625 +21789 -0.010894775390625 +21790 -0.01055908203125 +21791 0.033447265625 +21792 0.1033935546875 +21793 0.0826416015625 +21794 0.24908447265625 +21795 0.13812255859375 +21796 0.373199462890625 +21797 0.183349609375 +21798 0.45806884765625 +21799 0.212677001953125 +21800 0.511474609375 +21801 0.228363037109375 +21802 0.565399169921875 +21803 0.240142822265625 +21804 0.61138916015625 +21805 0.245819091796875 +21806 0.5897216796875 +21807 0.22802734375 +21808 0.4906005859375 +21809 0.184539794921875 +21810 0.33148193359375 +21811 0.12139892578125 +21812 0.147796630859375 +21813 0.050140380859375 +21814 -0.01873779296875 +21815 -0.01580810546875 +21816 -0.140289306640625 +21817 -0.0672607421875 +21818 -0.191986083984375 +21819 -0.095947265625 +21820 -0.184295654296875 +21821 -0.104339599609375 +21822 -0.161834716796875 +21823 -0.10528564453125 +21824 -0.166595458984375 +21825 -0.111053466796875 +21826 -0.19390869140625 +21827 -0.120086669921875 +21828 -0.22442626953125 +21829 -0.12664794921875 +21830 -0.279754638671875 +21831 -0.137481689453125 +21832 -0.3389892578125 +21833 -0.146697998046875 +21834 -0.3543701171875 +21835 -0.140533447265625 +21836 -0.348175048828125 +21837 -0.126312255859375 +21838 -0.32598876953125 +21839 -0.1064453125 +21840 -0.2581787109375 +21841 -0.072784423828125 +21842 -0.139801025390625 +21843 -0.02459716796875 +21844 0.014617919921875 +21845 0.033111572265625 +21846 0.144378662109375 +21847 0.081512451171875 +21848 0.221038818359375 +21849 0.11163330078125 +21850 0.27069091796875 +21851 0.1309814453125 +21852 0.294036865234375 +21853 0.139617919921875 +21854 0.311767578125 +21855 0.143707275390625 +21856 0.339141845703125 +21857 0.14794921875 +21858 0.360260009765625 +21859 0.1475830078125 +21860 0.360504150390625 +21861 0.13873291015625 +21862 0.308380126953125 +21863 0.11322021484375 +21864 0.18170166015625 +21865 0.065582275390625 +21866 0.0047607421875 +21867 0.00335693359375 +21868 -0.17559814453125 +21869 -0.059539794921875 +21870 -0.3143310546875 +21871 -0.109832763671875 +21872 -0.36785888671875 +21873 -0.13470458984375 +21874 -0.36248779296875 +21875 -0.141021728515625 +21876 -0.343536376953125 +21877 -0.14111328125 +21878 -0.3018798828125 +21879 -0.1322021484375 +21880 -0.231414794921875 +21881 -0.11248779296875 +21882 -0.117645263671875 +21883 -0.0780029296875 +21884 0.007049560546875 +21885 -0.038055419921875 +21886 0.087982177734375 +21887 -0.008270263671875 +21888 0.13946533203125 +21889 0.014892578125 +21890 0.17425537109375 +21891 0.034454345703125 +21892 0.188201904296875 +21893 0.0487060546875 +21894 0.171234130859375 +21895 0.054229736328125 +21896 0.118438720703125 +21897 0.049072265625 +21898 0.05706787109375 +21899 0.040374755859375 +21900 -0.010711669921875 +21901 0.028289794921875 +21902 -0.0914306640625 +21903 0.01068115234375 +21904 -0.162322998046875 +21905 -0.006256103515625 +21906 -0.194549560546875 +21907 -0.014556884765625 +21908 -0.1492919921875 +21909 -0.00335693359375 +21910 -0.02166748046875 +21911 0.028839111328125 +21912 0.124053955078125 +21913 0.064300537109375 +21914 0.211151123046875 +21915 0.08184814453125 +21916 0.240447998046875 +21917 0.082183837890625 +21918 0.242218017578125 +21919 0.07421875 +21920 0.2257080078125 +21921 0.06103515625 +21922 0.194366455078125 +21923 0.0440673828125 +21924 0.115509033203125 +21925 0.01458740234375 +21926 0.0128173828125 +21927 -0.020355224609375 +21928 -0.053802490234375 +21929 -0.043701171875 +21930 -0.110626220703125 +21931 -0.06256103515625 +21932 -0.199493408203125 +21933 -0.08856201171875 +21934 -0.29437255859375 +21935 -0.114410400390625 +21936 -0.33221435546875 +21937 -0.122528076171875 +21938 -0.27972412109375 +21939 -0.103790283203125 +21940 -0.185333251953125 +21941 -0.072021484375 +21942 -0.128204345703125 +21943 -0.049713134765625 +21944 -0.115692138671875 +21945 -0.039306640625 +21946 -0.116455078125 +21947 -0.032379150390625 +21948 -0.105926513671875 +21949 -0.022491455078125 +21950 -0.053955078125 +21951 -0.0015869140625 +21952 0.048797607421875 +21953 0.0325927734375 +21954 0.157318115234375 +21955 0.06719970703125 +21956 0.212005615234375 +21957 0.085357666015625 +21958 0.218475341796875 +21959 0.088531494140625 +21960 0.23724365234375 +21961 0.093597412109375 +21962 0.30535888671875 +21963 0.110992431640625 +21964 0.38128662109375 +21965 0.12921142578125 +21966 0.404449462890625 +21967 0.131500244140625 +21968 0.3944091796875 +21969 0.123626708984375 +21970 0.3885498046875 +21971 0.116363525390625 +21972 0.362640380859375 +21973 0.103240966796875 +21974 0.27362060546875 +21975 0.072540283203125 +21976 0.11712646484375 +21977 0.023345947265625 +21978 -0.054901123046875 +21979 -0.029510498046875 +21980 -0.19085693359375 +21981 -0.071319580078125 +21982 -0.28570556640625 +21983 -0.100494384765625 +21984 -0.339263916015625 +21985 -0.11688232421875 +21986 -0.3775634765625 +21987 -0.12774658203125 +21988 -0.445709228515625 +21989 -0.145751953125 +21990 -0.535064697265625 +21991 -0.1685791015625 +21992 -0.629058837890625 +21993 -0.19171142578125 +21994 -0.697601318359375 +21995 -0.206939697265625 +21996 -0.70391845703125 +21997 -0.204193115234375 +21998 -0.6424560546875 +21999 -0.18218994140625 +22000 -0.491241455078125 +22001 -0.135040283203125 +22002 -0.265716552734375 +22003 -0.067352294921875 +22004 -0.023712158203125 +22005 0.004425048828125 +22006 0.201751708984375 +22007 0.070831298828125 +22008 0.375823974609375 +22009 0.121978759765625 +22010 0.485076904296875 +22011 0.15399169921875 +22012 0.56884765625 +22013 0.177825927734375 +22014 0.634765625 +22015 0.195648193359375 +22016 0.63763427734375 +22017 0.195343017578125 +22018 0.5660400390625 +22019 0.174591064453125 +22020 0.4720458984375 +22021 0.14703369140625 +22022 0.40692138671875 +22023 0.125457763671875 +22024 0.3778076171875 +22025 0.11181640625 +22026 0.376953125 +22027 0.104461669921875 +22028 0.371978759765625 +22029 0.095733642578125 +22030 0.313140869140625 +22031 0.0736083984375 +22032 0.184417724609375 +22033 0.034515380859375 +22034 0.011199951171875 +22035 -0.01483154296875 +22036 -0.171051025390625 +22037 -0.0653076171875 +22038 -0.33740234375 +22039 -0.1104736328125 +22040 -0.47198486328125 +22041 -0.146209716796875 +22042 -0.560394287109375 +22043 -0.168853759765625 +22044 -0.58056640625 +22045 -0.172943115234375 +22046 -0.54754638671875 +22047 -0.16229248046875 +22048 -0.508575439453125 +22049 -0.148834228515625 +22050 -0.459503173828125 +22051 -0.131744384765625 +22052 -0.394378662109375 +22053 -0.10986328125 +22054 -0.35260009765625 +22055 -0.093231201171875 +22056 -0.31170654296875 +22057 -0.07666015625 +22058 -0.197418212890625 +22059 -0.04205322265625 +22060 -0.007965087890625 +22061 0.010650634765625 +22062 0.207489013671875 +22063 0.06890869140625 +22064 0.409210205078125 +22065 0.122650146484375 +22066 0.57208251953125 +22067 0.165496826171875 +22068 0.66595458984375 +22069 0.18988037109375 +22070 0.65875244140625 +22071 0.18780517578125 +22072 0.56744384765625 +22073 0.16357421875 +22074 0.431396484375 +22075 0.127044677734375 +22076 0.29443359375 +22077 0.08929443359375 +22078 0.182464599609375 +22079 0.05694580078125 +22080 0.06365966796875 +22081 0.02239990234375 +22082 -0.075958251953125 +22083 -0.01751708984375 +22084 -0.189422607421875 +22085 -0.05084228515625 +22086 -0.271942138671875 +22087 -0.076080322265625 +22088 -0.342529296875 +22089 -0.097686767578125 +22090 -0.364166259765625 +22091 -0.106353759765625 +22092 -0.327239990234375 +22093 -0.099517822265625 +22094 -0.2769775390625 +22095 -0.088287353515625 +22096 -0.253692626953125 +22097 -0.082611083984375 +22098 -0.24365234375 +22099 -0.079132080078125 +22100 -0.1983642578125 +22101 -0.06591796875 +22102 -0.116241455078125 +22103 -0.042694091796875 +22104 -0.036834716796875 +22105 -0.019439697265625 +22106 0.034881591796875 +22107 0.00238037109375 +22108 0.09124755859375 +22109 0.0206298828125 +22110 0.10888671875 +22111 0.02923583984375 +22112 0.125518798828125 +22113 0.037322998046875 +22114 0.15771484375 +22115 0.048828125 +22116 0.17828369140625 +22117 0.056793212890625 +22118 0.17108154296875 +22119 0.057098388671875 +22120 0.129974365234375 +22121 0.048126220703125 +22122 0.082427978515625 +22123 0.03668212890625 +22124 0.027679443359375 +22125 0.022552490234375 +22126 -0.065643310546875 +22127 -0.001922607421875 +22128 -0.15936279296875 +22129 -0.027191162109375 +22130 -0.21307373046875 +22131 -0.043121337890625 +22132 -0.234649658203125 +22133 -0.051513671875 +22134 -0.2001953125 +22135 -0.0462646484375 +22136 -0.119171142578125 +22137 -0.029541015625 +22138 -0.024749755859375 +22139 -0.0093994140625 +22140 0.085784912109375 +22141 0.0150146484375 +22142 0.178131103515625 +22143 0.03533935546875 +22144 0.215576171875 +22145 0.0426025390625 +22146 0.211456298828125 +22147 0.040191650390625 +22148 0.17523193359375 +22149 0.030548095703125 +22150 0.128753662109375 +22151 0.01910400390625 +22152 0.1019287109375 +22153 0.01324462890625 +22154 0.0743408203125 +22155 0.007843017578125 +22156 0.04327392578125 +22157 0.002105712890625 +22158 0.038177490234375 +22159 0.003204345703125 +22160 0.076263427734375 +22161 0.015289306640625 +22162 0.14105224609375 +22163 0.034088134765625 +22164 0.186431884765625 +22165 0.04803466796875 +22166 0.188812255859375 +22167 0.051116943359375 +22168 0.1390380859375 +22169 0.040985107421875 +22170 0.041778564453125 +22171 0.0186767578125 +22172 -0.079437255859375 +22173 -0.010040283203125 +22174 -0.219390869140625 +22175 -0.0439453125 +22176 -0.367828369140625 +22177 -0.08050537109375 +22178 -0.494873046875 +22179 -0.1123046875 +22180 -0.556243896484375 +22181 -0.12835693359375 +22182 -0.508697509765625 +22183 -0.117889404296875 +22184 -0.3756103515625 +22185 -0.08660888671875 +22186 -0.218902587890625 +22187 -0.04974365234375 +22188 -0.063751220703125 +22189 -0.013458251953125 +22190 0.091552734375 +22191 0.02276611328125 +22192 0.23602294921875 +22193 0.056365966796875 +22194 0.342987060546875 +22195 0.080810546875 +22196 0.39520263671875 +22197 0.09197998046875 +22198 0.389373779296875 +22199 0.089141845703125 +22200 0.324249267578125 +22201 0.072021484375 +22202 0.224090576171875 +22203 0.046722412109375 +22204 0.124267578125 +22205 0.022003173828125 +22206 0.037078857421875 +22207 0.00091552734375 +22208 -0.010101318359375 +22209 -0.009796142578125 +22210 -0.019439697265625 +22211 -0.0107421875 +22212 -0.022796630859375 +22213 -0.0098876953125 +22214 -0.001556396484375 +22215 -0.00274658203125 +22216 0.056304931640625 +22217 0.0135498046875 +22218 0.106719970703125 +22219 0.027923583984375 +22220 0.096893310546875 +22221 0.0272216796875 +22222 0.042694091796875 +22223 0.015289306640625 +22224 -0.018035888671875 +22225 0.00140380859375 +22226 -0.07586669921875 +22227 -0.0120849609375 +22228 -0.11944580078125 +22229 -0.02239990234375 +22230 -0.15972900390625 +22231 -0.03228759765625 +22232 -0.202606201171875 +22233 -0.043182373046875 +22234 -0.24859619140625 +22235 -0.05517578125 +22236 -0.30517578125 +22237 -0.070098876953125 +22238 -0.36212158203125 +22239 -0.085357666015625 +22240 -0.39141845703125 +22241 -0.093963623046875 +22242 -0.35528564453125 +22243 -0.086456298828125 +22244 -0.249969482421875 +22245 -0.061798095703125 +22246 -0.092864990234375 +22247 -0.02423095703125 +22248 0.08905029296875 +22249 0.01959228515625 +22250 0.2352294921875 +22251 0.054718017578125 +22252 0.318817138671875 +22253 0.074554443359375 +22254 0.358642578125 +22255 0.08380126953125 +22256 0.347747802734375 +22257 0.080780029296875 +22258 0.28564453125 +22259 0.06536865234375 +22260 0.223175048828125 +22261 0.0501708984375 +22262 0.196746826171875 +22263 0.044189453125 +22264 0.179840087890625 +22265 0.040802001953125 +22266 0.155548095703125 +22267 0.0357666015625 +22268 0.151214599609375 +22269 0.035797119140625 +22270 0.156951904296875 +22271 0.03839111328125 +22272 0.13177490234375 +22273 0.033447265625 +22274 0.100799560546875 +22275 0.026702880859375 +22276 0.087127685546875 +22277 0.023681640625 +22278 0.05487060546875 +22279 0.016448974609375 +22280 -0.009002685546875 +22281 0.00213623046875 +22282 -0.10400390625 +22283 -0.0191650390625 +22284 -0.229400634765625 +22285 -0.047332763671875 +22286 -0.35552978515625 +22287 -0.07586669921875 +22288 -0.441925048828125 +22289 -0.095947265625 +22290 -0.473846435546875 +22291 -0.10430908203125 +22292 -0.464813232421875 +22293 -0.103790283203125 +22294 -0.419097900390625 +22295 -0.095184326171875 +22296 -0.334320068359375 +22297 -0.077911376953125 +22298 -0.227935791015625 +22299 -0.055633544921875 +22300 -0.12347412109375 +22301 -0.033416748046875 +22302 -0.02764892578125 +22303 -0.0126953125 +22304 0.077667236328125 +22305 0.01043701171875 +22306 0.2132568359375 +22307 0.040435791015625 +22308 0.38885498046875 +22309 0.079345703125 +22310 0.582794189453125 +22311 0.122467041015625 +22312 0.734039306640625 +22313 0.156524658203125 +22314 0.800140380859375 +22315 0.172271728515625 +22316 0.7783203125 +22317 0.16900634765625 +22318 0.6651611328125 +22319 0.145904541015625 +22320 0.45965576171875 +22321 0.10272216796875 +22322 0.199188232421875 +22323 0.0474853515625 +22324 -0.050689697265625 +22325 -0.005706787109375 +22326 -0.23297119140625 +22327 -0.0445556640625 +22328 -0.33013916015625 +22329 -0.0653076171875 +22330 -0.368408203125 +22331 -0.07366943359375 +22332 -0.378936767578125 +22333 -0.076324462890625 +22334 -0.376983642578125 +22335 -0.076568603515625 +22336 -0.37969970703125 +22337 -0.07806396484375 +22338 -0.391510009765625 +22339 -0.081695556640625 +22340 -0.385345458984375 +22341 -0.081573486328125 +22342 -0.3419189453125 +22343 -0.073455810546875 +22344 -0.28289794921875 +22345 -0.061920166015625 +22346 -0.251617431640625 +22347 -0.0562744140625 +22348 -0.266143798828125 +22349 -0.06036376953125 +22350 -0.273345947265625 +22351 -0.062652587890625 +22352 -0.216796875 +22353 -0.050933837890625 +22354 -0.128265380859375 +22355 -0.03204345703125 +22356 -0.068145751953125 +22357 -0.01898193359375 +22358 -0.0430908203125 +22359 -0.013214111328125 +22360 -0.024444580078125 +22361 -0.00860595703125 +22362 0.020721435546875 +22363 0.00189208984375 +22364 0.124481201171875 +22365 0.025146484375 +22366 0.25787353515625 +22367 0.05487060546875 +22368 0.379119873046875 +22369 0.08197021484375 +22370 0.47991943359375 +22371 0.1046142578125 +22372 0.5281982421875 +22373 0.1158447265625 +22374 0.511138916015625 +22375 0.11285400390625 +22376 0.456207275390625 +22377 0.10150146484375 +22378 0.407470703125 +22379 0.09130859375 +22380 0.383758544921875 +22381 0.086334228515625 +22382 0.35687255859375 +22383 0.0804443359375 +22384 0.31182861328125 +22385 0.0704345703125 +22386 0.250885009765625 +22387 0.05682373046875 +22388 0.1654052734375 +22389 0.03778076171875 +22390 0.035247802734375 +22391 0.009002685546875 +22392 -0.142059326171875 +22393 -0.02996826171875 +22394 -0.33563232421875 +22395 -0.07244873046875 +22396 -0.5345458984375 +22397 -0.11602783203125 +22398 -0.72186279296875 +22399 -0.157012939453125 +22400 -0.836669921875 +22401 -0.182220458984375 +22402 -0.8326416015625 +22403 -0.181640625 +22404 -0.7296142578125 +22405 -0.1595458984375 +22406 -0.582550048828125 +22407 -0.1278076171875 +22408 -0.440093994140625 +22409 -0.096954345703125 +22410 -0.324310302734375 +22411 -0.071746826171875 +22412 -0.20147705078125 +22413 -0.044891357421875 +22414 -0.044647216796875 +22415 -0.010589599609375 +22416 0.103973388671875 +22417 0.02197265625 +22418 0.202392578125 +22419 0.043701171875 +22420 0.264495849609375 +22421 0.05755615234375 +22422 0.338897705078125 +22423 0.07403564453125 +22424 0.443817138671875 +22425 0.0970458984375 +22426 0.545074462890625 +22427 0.119171142578125 +22428 0.6173095703125 +22429 0.13494873046875 +22430 0.6524658203125 +22431 0.142608642578125 +22432 0.66339111328125 +22433 0.14495849609375 +22434 0.6561279296875 +22435 0.143280029296875 +22436 0.606781005859375 +22437 0.132415771484375 +22438 0.501190185546875 +22439 0.10931396484375 +22440 0.352783203125 +22441 0.076904296875 +22442 0.176544189453125 +22443 0.0384521484375 +22444 -0.034820556640625 +22445 -0.007568359375 +22446 -0.258209228515625 +22447 -0.056121826171875 +22448 -0.44244384765625 +22449 -0.09613037109375 +22450 -0.5753173828125 +22451 -0.124969482421875 +22452 -0.65203857421875 +22453 -0.1416015625 +22454 -0.641632080078125 +22455 -0.13934326171875 +22456 -0.562164306640625 +22457 -0.12213134765625 +22458 -0.458038330078125 +22459 -0.099517822265625 +22460 -0.350555419921875 +22461 -0.076141357421875 +22462 -0.260528564453125 +22463 -0.056488037109375 +22464 -0.192108154296875 +22465 -0.041473388671875 +22466 -0.141937255859375 +22467 -0.0303955078125 +22468 -0.1021728515625 +22469 -0.021575927734375 +22470 -0.062896728515625 +22471 -0.01287841796875 +22472 -0.011932373046875 +22473 -0.001678466796875 +22474 0.062835693359375 +22475 0.014617919921875 +22476 0.148712158203125 +22477 0.03326416015625 +22478 0.241729736328125 +22479 0.053375244140625 +22480 0.34912109375 +22481 0.0765380859375 +22482 0.457305908203125 +22483 0.099822998046875 +22484 0.54388427734375 +22485 0.118377685546875 +22486 0.5728759765625 +22487 0.12445068359375 +22488 0.506591796875 +22489 0.109893798828125 +22490 0.351226806640625 +22491 0.076080322265625 +22492 0.146514892578125 +22493 0.031585693359375 +22494 -0.05523681640625 +22495 -0.012237548828125 +22496 -0.21624755859375 +22497 -0.047210693359375 +22498 -0.334930419921875 +22499 -0.072967529296875 +22500 -0.402984619140625 +22501 -0.08770751953125 +22502 -0.4412841796875 +22503 -0.095947265625 +22504 -0.49578857421875 +22505 -0.10760498046875 +22506 -0.5601806640625 +22507 -0.121337890625 +22508 -0.600738525390625 +22509 -0.129913330078125 +22510 -0.584228515625 +22511 -0.12615966796875 +22512 -0.47930908203125 +22513 -0.103302001953125 +22514 -0.27935791015625 +22515 -0.0599365234375 +22516 -0.0089111328125 +22517 -0.0013427734375 +22518 0.268798828125 +22519 0.05877685546875 +22520 0.482818603515625 +22521 0.105072021484375 +22522 0.60369873046875 +22523 0.131195068359375 +22524 0.650421142578125 +22525 0.141265869140625 +22526 0.66400146484375 +22527 0.144134521484375 +22528 0.6414794921875 +22529 0.139404296875 +22530 0.572540283203125 +22531 0.124786376953125 +22532 0.498138427734375 +22533 0.10797119140625 +22534 0.439453125 +22535 0.093170166015625 +22536 0.375518798828125 +22537 0.07684326171875 +22538 0.274505615234375 +22539 0.05340576171875 +22540 0.1087646484375 +22541 0.018096923828125 +22542 -0.099395751953125 +22543 -0.02471923828125 +22544 -0.3182373046875 +22545 -0.068939208984375 +22546 -0.5489501953125 +22547 -0.114593505859375 +22548 -0.7738037109375 +22549 -0.158233642578125 +22550 -0.86383056640625 +22551 -0.190032958984375 +22552 -0.870391845703125 +22553 -0.203857421875 +22554 -0.86895751953125 +22555 -0.2030029296875 +22556 -0.861053466796875 +22557 -0.18994140625 +22558 -0.765869140625 +22559 -0.161651611328125 +22560 -0.5301513671875 +22561 -0.1162109375 +22562 -0.214691162109375 +22563 -0.05511474609375 +22564 0.137359619140625 +22565 0.013458251953125 +22566 0.474822998046875 +22567 0.079864501953125 +22568 0.76239013671875 +22569 0.137359619140625 +22570 0.867462158203125 +22571 0.180816650390625 +22572 0.870361328125 +22573 0.21014404296875 +22574 0.86480712890625 +22575 0.223052978515625 +22576 0.831817626953125 +22577 0.220458984375 +22578 0.677581787109375 +22579 0.20684814453125 +22580 0.495880126953125 +22581 0.18328857421875 +22582 0.30767822265625 +22583 0.153228759765625 +22584 0.116180419921875 +22585 0.117156982421875 +22586 -0.110748291015625 +22587 0.06939697265625 +22588 -0.381805419921875 +22589 0.0087890625 +22590 -0.6572265625 +22591 -0.05657958984375 +22592 -0.857421875 +22593 -0.115509033203125 +22594 -0.870391845703125 +22595 -0.159942626953125 +22596 -0.870391845703125 +22597 -0.188446044921875 +22598 -0.86444091796875 +22599 -0.205841064453125 +22600 -0.85723876953125 +22601 -0.21856689453125 +22602 -0.790008544921875 +22603 -0.223175048828125 +22604 -0.62847900390625 +22605 -0.20965576171875 +22606 -0.3956298828125 +22607 -0.177398681640625 +22608 -0.126708984375 +22609 -0.132476806640625 +22610 0.150115966796875 +22611 -0.079986572265625 +22612 0.424041748046875 +22613 -0.022186279296875 +22614 0.670623779296875 +22615 0.035858154296875 +22616 0.854522705078125 +22617 0.086883544921875 +22618 0.866485595703125 +22619 0.127471923828125 +22620 0.86920166015625 +22621 0.1546630859375 +22622 0.8653564453125 +22623 0.171630859375 +22624 0.857147216796875 +22625 0.180755615234375 +22626 0.766845703125 +22627 0.181396484375 +22628 0.628509521484375 +22629 0.174407958984375 +22630 0.462127685546875 +22631 0.15850830078125 +22632 0.297210693359375 +22633 0.138458251953125 +22634 0.14862060546875 +22635 0.11651611328125 +22636 -0.00537109375 +22637 0.08856201171875 +22638 -0.15753173828125 +22639 0.056060791015625 +22640 -0.31304931640625 +22641 0.0184326171875 +22642 -0.48876953125 +22643 -0.026763916015625 +22644 -0.6416015625 +22645 -0.07080078125 +22646 -0.751373291015625 +22647 -0.1090087890625 +22648 -0.84619140625 +22649 -0.1455078125 +22650 -0.861297607421875 +22651 -0.177520751953125 +22652 -0.863250732421875 +22653 -0.198822021484375 +22654 -0.856597900390625 +22655 -0.20355224609375 +22656 -0.7498779296875 +22657 -0.19390869140625 +22658 -0.624542236328125 +22659 -0.1805419921875 +22660 -0.47808837890625 +22661 -0.159423828125 +22662 -0.253387451171875 +22663 -0.11981201171875 +22664 0.003692626953125 +22665 -0.0701904296875 +22666 0.2257080078125 +22667 -0.023193359375 +22668 0.427154541015625 +22669 0.02337646484375 +22670 0.643218994140625 +22671 0.07537841796875 +22672 0.855926513671875 +22673 0.13092041015625 +22674 0.870361328125 +22675 0.17919921875 +22676 0.870361328125 +22677 0.211029052734375 +22678 0.862762451171875 +22679 0.227691650390625 +22680 0.79669189453125 +22681 0.22857666015625 +22682 0.595794677734375 +22683 0.2119140625 +22684 0.362152099609375 +22685 0.183074951171875 +22686 0.1270751953125 +22687 0.147216796875 +22688 -0.086944580078125 +22689 0.1082763671875 +22690 -0.2784423828125 +22691 0.066680908203125 +22692 -0.484832763671875 +22693 0.01611328125 +22694 -0.729583740234375 +22695 -0.046875 +22696 -0.86688232421875 +22697 -0.112884521484375 +22698 -0.870391845703125 +22699 -0.170166015625 +22700 -0.86859130859375 +22701 -0.21771240234375 +22702 -0.86279296875 +22703 -0.255035400390625 +22704 -0.817962646484375 +22705 -0.275482177734375 +22706 -0.6116943359375 +22707 -0.2706298828125 +22708 -0.3128662109375 +22709 -0.2391357421875 +22710 0.039398193359375 +22711 -0.18719482421875 +22712 0.422821044921875 +22713 -0.1185302734375 +22714 0.805145263671875 +22715 -0.039306640625 +22716 0.870361328125 +22717 0.037841796875 +22718 0.870361328125 +22719 0.102386474609375 +22720 0.860015869140625 +22721 0.152069091796875 +22722 0.727935791015625 +22723 0.1854248046875 +22724 0.48114013671875 +22725 0.2012939453125 +22726 0.2059326171875 +22727 0.204010009765625 +22728 -0.06103515625 +22729 0.197662353515625 +22730 -0.29913330078125 +22731 0.18402099609375 +22732 -0.516204833984375 +22733 0.16033935546875 +22734 -0.7252197265625 +22735 0.123779296875 +22736 -0.85980224609375 +22737 0.07891845703125 +22738 -0.870391845703125 +22739 0.032073974609375 +22740 -0.870391845703125 +22741 -0.011199951171875 +22742 -0.858062744140625 +22743 -0.041839599609375 +22744 -0.673004150390625 +22745 -0.0589599609375 +22746 -0.42694091796875 +22747 -0.0721435546875 +22748 -0.2100830078125 +22749 -0.089385986328125 +22750 -0.0362548828125 +22751 -0.110137939453125 +22752 0.10943603515625 +22753 -0.128875732421875 +22754 0.23516845703125 +22755 -0.14178466796875 +22756 0.373687744140625 +22757 -0.14117431640625 +22758 0.517791748046875 +22759 -0.127349853515625 +22760 0.602783203125 +22761 -0.11187744140625 +22762 0.635711669921875 +22763 -0.093780517578125 +22764 0.655181884765625 +22765 -0.066986083984375 +22766 0.65948486328125 +22767 -0.03338623046875 +22768 0.651275634765625 +22769 0.005401611328125 +22770 0.61846923828125 +22771 0.04473876953125 +22772 0.53753662109375 +22773 0.077667236328125 +22774 0.404144287109375 +22775 0.1007080078125 +22776 0.22186279296875 +22777 0.1119384765625 +22778 0.003997802734375 +22779 0.111480712890625 +22780 -0.22100830078125 +22781 0.1025390625 +22782 -0.42449951171875 +22783 0.088836669921875 +22784 -0.579833984375 +22785 0.073883056640625 +22786 -0.641876220703125 +22787 0.0648193359375 +22788 -0.6177978515625 +22789 0.06103515625 +22790 -0.575531005859375 +22791 0.05242919921875 +22792 -0.526336669921875 +22793 0.03802490234375 +22794 -0.42645263671875 +22795 0.025634765625 +22796 -0.2581787109375 +22797 0.01947021484375 +22798 -0.068695068359375 +22799 0.01409912109375 +22800 0.09222412109375 +22801 0.003875732421875 +22802 0.232147216796875 +22803 -0.008148193359375 +22804 0.3509521484375 +22805 -0.020172119140625 +22806 0.410064697265625 +22807 -0.036529541015625 +22808 0.372955322265625 +22809 -0.061492919921875 +22810 0.2554931640625 +22811 -0.091766357421875 +22812 0.10711669921875 +22813 -0.11932373046875 +22814 -0.052886962890625 +22815 -0.14111328125 +22816 -0.186279296875 +22817 -0.15167236328125 +22818 -0.23291015625 +22819 -0.142608642578125 +22820 -0.209442138671875 +22821 -0.11749267578125 +22822 -0.174163818359375 +22823 -0.086517333984375 +22824 -0.126739501953125 +22825 -0.051116943359375 +22826 -0.048126220703125 +22827 -0.010040283203125 +22828 0.0426025390625 +22829 0.032196044921875 +22830 0.10748291015625 +22831 0.06829833984375 +22832 0.1409912109375 +22833 0.096038818359375 +22834 0.19708251953125 +22835 0.122467041015625 +22836 0.273651123046875 +22837 0.146453857421875 +22838 0.31768798828125 +22839 0.159423828125 +22840 0.341094970703125 +22841 0.162994384765625 +22842 0.368011474609375 +22843 0.161041259765625 +22844 0.37249755859375 +22845 0.150115966796875 +22846 0.30072021484375 +22847 0.122833251953125 +22848 0.1517333984375 +22849 0.080078125 +22850 -0.01470947265625 +22851 0.032135009765625 +22852 -0.1883544921875 +22853 -0.01806640625 +22854 -0.372711181640625 +22855 -0.06976318359375 +22856 -0.51397705078125 +22857 -0.11346435546875 +22858 -0.57177734375 +22859 -0.14190673828125 +22860 -0.53948974609375 +22861 -0.153076171875 +22862 -0.43511962890625 +22863 -0.14892578125 +22864 -0.2962646484375 +22865 -0.1346435546875 +22866 -0.161102294921875 +22867 -0.115814208984375 +22868 -0.0435791015625 +22869 -0.094635009765625 +22870 0.060394287109375 +22871 -0.070770263671875 +22872 0.13665771484375 +22873 -0.046966552734375 +22874 0.170135498046875 +22875 -0.02630615234375 +22876 0.16552734375 +22877 -0.009033203125 +22878 0.15728759765625 +22879 0.009033203125 +22880 0.150787353515625 +22881 0.027618408203125 +22882 0.12200927734375 +22883 0.0419921875 +22884 0.080108642578125 +22885 0.05255126953125 +22886 0.05126953125 +22887 0.062408447265625 +22888 0.062896728515625 +22889 0.075042724609375 +22890 0.09271240234375 +22891 0.0865478515625 +22892 0.092987060546875 +22893 0.08941650390625 +22894 0.07855224609375 +22895 0.08587646484375 +22896 0.06427001953125 +22897 0.078338623046875 +22898 0.0347900390625 +22899 0.064910888671875 +22900 -0.01171875 +22901 0.0458984375 +22902 -0.056060791015625 +22903 0.02496337890625 +22904 -0.055511474609375 +22905 0.009429931640625 +22906 -0.010467529296875 +22907 0.0001220703125 +22908 0.02508544921875 +22909 -0.010223388671875 +22910 0.025665283203125 +22911 -0.024627685546875 +22912 0.017333984375 +22913 -0.038360595703125 +22914 0.00189208984375 +22915 -0.050567626953125 +22916 -0.03173828125 +22917 -0.062469482421875 +22918 -0.071502685546875 +22919 -0.071929931640625 +22920 -0.13543701171875 +22921 -0.08160400390625 +22922 -0.219970703125 +22923 -0.091064453125 +22924 -0.300506591796875 +22925 -0.096832275390625 +22926 -0.376312255859375 +22927 -0.0992431640625 +22928 -0.416107177734375 +22929 -0.094085693359375 +22930 -0.371124267578125 +22931 -0.074676513671875 +22932 -0.242279052734375 +22933 -0.0418701171875 +22934 -0.069732666015625 +22935 -0.00250244140625 +22936 0.125640869140625 +22937 0.039520263671875 +22938 0.31268310546875 +22939 0.07879638671875 +22940 0.45501708984375 +22941 0.109222412109375 +22942 0.554779052734375 +22943 0.130706787109375 +22944 0.61065673828125 +22945 0.142791748046875 +22946 0.610931396484375 +22947 0.14361572265625 +22948 0.531463623046875 +22949 0.1295166015625 +22950 0.3883056640625 +22951 0.103118896484375 +22952 0.23468017578125 +22953 0.0728759765625 +22954 0.095245361328125 +22955 0.042999267578125 +22956 -0.00396728515625 +22957 0.0179443359375 +22958 -0.04852294921875 +22959 0.000457763671875 +22960 -0.055145263671875 +22961 -0.0113525390625 +22962 -0.0758056640625 +22963 -0.024810791015625 +22964 -0.138702392578125 +22965 -0.04364013671875 +22966 -0.209197998046875 +22967 -0.062103271484375 +22968 -0.289031982421875 +22969 -0.080078125 +22970 -0.37884521484375 +22971 -0.097412109375 +22972 -0.456329345703125 +22973 -0.110565185546875 +22974 -0.51641845703125 +22975 -0.1187744140625 +22976 -0.519287109375 +22977 -0.1160888671875 +22978 -0.458251953125 +22979 -0.101715087890625 +22980 -0.384796142578125 +22981 -0.08380126953125 +22982 -0.323699951171875 +22983 -0.066558837890625 +22984 -0.269287109375 +22985 -0.049560546875 +22986 -0.1951904296875 +22987 -0.029296875 +22988 -0.100006103515625 +22989 -0.006072998046875 +22990 -0.01055908203125 +22991 0.0155029296875 +22992 0.1033935546875 +22993 0.039642333984375 +22994 0.24908447265625 +22995 0.067108154296875 +22996 0.373199462890625 +22997 0.08953857421875 +22998 0.45806884765625 +22999 0.104095458984375 +23000 0.511474609375 +23001 0.1119384765625 +23002 0.565399169921875 +23003 0.11798095703125 +23004 0.61138916015625 +23005 0.121124267578125 +23006 0.5897216796875 +23007 0.112548828125 +23008 0.4906005859375 +23009 0.091094970703125 +23010 0.33148193359375 +23011 0.059814453125 +23012 0.147796630859375 +23013 0.02447509765625 +23014 -0.01873779296875 +23015 -0.00811767578125 +23016 -0.140289306640625 +23017 -0.0333251953125 +23018 -0.191986083984375 +23019 -0.047027587890625 +23020 -0.184295654296875 +23021 -0.050537109375 +23022 -0.161834716796875 +23023 -0.0504150390625 +23024 -0.166595458984375 +23025 -0.05291748046875 +23026 -0.19390869140625 +23027 -0.057281494140625 +23028 -0.22442626953125 +23029 -0.060577392578125 +23030 -0.279754638671875 +23031 -0.066192626953125 +23032 -0.3389892578125 +23033 -0.0711669921875 +23034 -0.3543701171875 +23035 -0.068511962890625 +23036 -0.348175048828125 +23037 -0.0618896484375 +23038 -0.32598876953125 +23039 -0.052459716796875 +23040 -0.2581787109375 +23041 -0.036102294921875 +23042 -0.139801025390625 +23043 -0.01239013671875 +23044 0.014617919921875 +23045 0.016082763671875 +23046 0.144378662109375 +23047 0.0399169921875 +23048 0.221038818359375 +23049 0.05462646484375 +23050 0.27069091796875 +23051 0.063995361328125 +23052 0.294036865234375 +23053 0.068084716796875 +23054 0.311767578125 +23055 0.07000732421875 +23056 0.339141845703125 +23057 0.072021484375 +23058 0.360260009765625 +23059 0.071533203125 +23060 0.360504150390625 +23061 0.066680908203125 +23062 0.308380126953125 +23063 0.054107666015625 +23064 0.18170166015625 +23065 0.03167724609375 +23066 0.0047607421875 +23067 0.0028076171875 +23068 -0.17559814453125 +23069 -0.0263671875 +23070 -0.3143310546875 +23071 -0.04998779296875 +23072 -0.36785888671875 +23073 -0.062469482421875 +23074 -0.36248779296875 +23075 -0.066650390625 +23076 -0.343536376953125 +23077 -0.067718505859375 +23078 -0.3018798828125 +23079 -0.064453125 +23080 -0.231414794921875 +23081 -0.05609130859375 +23082 -0.117645263671875 +23083 -0.040924072265625 +23084 0.007049560546875 +23085 -0.02301025390625 +23086 0.087982177734375 +23087 -0.009063720703125 +23088 0.13946533203125 +23089 0.0023193359375 +23090 0.17425537109375 +23091 0.012359619140625 +23092 0.188201904296875 +23093 0.02020263671875 +23094 0.171234130859375 +23095 0.0242919921875 +23096 0.118438720703125 +23097 0.023712158203125 +23098 0.05706787109375 +23099 0.021453857421875 +23100 -0.010711669921875 +23101 0.017486572265625 +23102 -0.0914306640625 +23103 0.010833740234375 +23104 -0.162322998046875 +23105 0.00408935546875 +23106 -0.194549560546875 +23107 0.000640869140625 +23108 -0.1492919921875 +23109 0.00518798828125 +23110 -0.02166748046875 +23111 0.01837158203125 +23112 0.124053955078125 +23113 0.032623291015625 +23114 0.211151123046875 +23115 0.0389404296875 +23116 0.240447998046875 +23117 0.03765869140625 +23118 0.242218017578125 +23119 0.03271484375 +23120 0.2257080078125 +23121 0.025543212890625 +23122 0.194366455078125 +23123 0.016815185546875 +23124 0.115509033203125 +23125 0.00286865234375 +23126 0.0128173828125 +23127 -0.013153076171875 +23128 -0.053802490234375 +23129 -0.023895263671875 +23130 -0.110626220703125 +23131 -0.03240966796875 +23132 -0.199493408203125 +23133 -0.043670654296875 +23134 -0.29437255859375 +23135 -0.054534912109375 +23136 -0.33221435546875 +23137 -0.0574951171875 +23138 -0.27972412109375 +23139 -0.048675537109375 +23140 -0.185333251953125 +23141 -0.034088134765625 +23142 -0.128204345703125 +23143 -0.023406982421875 +23144 -0.115692138671875 +23145 -0.017730712890625 +23146 -0.116455078125 +23147 -0.013519287109375 +23148 -0.105926513671875 +23149 -0.008056640625 +23150 -0.053955078125 +23151 0.001983642578125 +23152 0.048797607421875 +23153 0.017547607421875 +23154 0.157318115234375 +23155 0.0330810546875 +23156 0.212005615234375 +23157 0.041290283203125 +23158 0.218475341796875 +23159 0.042816162109375 +23160 0.23724365234375 +23161 0.044891357421875 +23162 0.30535888671875 +23163 0.052001953125 +23164 0.38128662109375 +23165 0.059234619140625 +23166 0.404449462890625 +23167 0.059417724609375 +23168 0.3944091796875 +23169 0.055084228515625 +23170 0.3885498046875 +23171 0.050933837890625 +23172 0.362640380859375 +23173 0.04425048828125 +23174 0.27362060546875 +23175 0.030059814453125 +23176 0.11712646484375 +23177 0.008026123046875 +23178 -0.054901123046875 +23179 -0.015411376953125 +23180 -0.19085693359375 +23181 -0.033935546875 +23182 -0.28570556640625 +23183 -0.046844482421875 +23184 -0.339263916015625 +23185 -0.054046630859375 +23186 -0.3775634765625 +23187 -0.058624267578125 +23188 -0.445709228515625 +23189 -0.066009521484375 +23190 -0.535064697265625 +23191 -0.07525634765625 +23192 -0.629058837890625 +23193 -0.08447265625 +23194 -0.697601318359375 +23195 -0.09014892578125 +23196 -0.70391845703125 +23197 -0.088043212890625 +23198 -0.6424560546875 +23199 -0.077667236328125 +23200 -0.491241455078125 +23201 -0.056549072265625 +23202 -0.265716552734375 +23203 -0.026702880859375 +23204 -0.023712158203125 +23205 0.0047607421875 +23206 0.201751708984375 +23207 0.03375244140625 +23208 0.375823974609375 +23209 0.05596923828125 +23210 0.485076904296875 +23211 0.069793701171875 +23212 0.56884765625 +23213 0.07989501953125 +23214 0.634765625 +23215 0.08721923828125 +23216 0.63763427734375 +23217 0.086395263671875 +23218 0.5660400390625 +23219 0.07611083984375 +23220 0.4720458984375 +23221 0.062744140625 +23222 0.40692138671875 +23223 0.052581787109375 +23224 0.3778076171875 +23225 0.046600341796875 +23226 0.376953125 +23227 0.04400634765625 +23228 0.371978759765625 +23229 0.041046142578125 +23230 0.313140869140625 +23231 0.0318603515625 +23232 0.184417724609375 +23233 0.0146484375 +23234 0.011199951171875 +23235 -0.0074462890625 +23236 -0.171051025390625 +23237 -0.030029296875 +23238 -0.33740234375 +23239 -0.05010986328125 +23240 -0.47198486328125 +23241 -0.065826416015625 +23242 -0.560394287109375 +23243 -0.075469970703125 +23244 -0.58056640625 +23245 -0.07647705078125 +23246 -0.54754638671875 +23247 -0.07073974609375 +23248 -0.508575439453125 +23249 -0.064056396484375 +23250 -0.459503173828125 +23251 -0.0560302734375 +23252 -0.394378662109375 +23253 -0.04608154296875 +23254 -0.35260009765625 +23255 -0.03900146484375 +23256 -0.31170654296875 +23257 -0.0322265625 +23258 -0.197418212890625 +23259 -0.016937255859375 +23260 -0.007965087890625 +23261 0.006927490234375 +23262 0.207489013671875 +23263 0.033416748046875 +23264 0.409210205078125 +23265 0.057769775390625 +23266 0.57208251953125 +23267 0.07696533203125 +23268 0.66595458984375 +23269 0.087432861328125 +23270 0.65875244140625 +23271 0.08538818359375 +23272 0.56744384765625 +23273 0.072967529296875 +23274 0.431396484375 +23275 0.054962158203125 +23276 0.29443359375 +23277 0.0367431640625 +23278 0.182464599609375 +23279 0.021484375 +23280 0.06365966796875 +23281 0.005462646484375 +23282 -0.075958251953125 +23283 -0.012847900390625 +23284 -0.189422607421875 +23285 -0.027740478515625 +23286 -0.271942138671875 +23287 -0.038543701171875 +23288 -0.342529296875 +23289 -0.047515869140625 +23290 -0.364166259765625 +23291 -0.05023193359375 +23292 -0.327239990234375 +23293 -0.045562744140625 +23294 -0.2769775390625 +23295 -0.0389404296875 +23296 -0.253692626953125 +23297 -0.03497314453125 +23298 -0.24365234375 +23299 -0.03228759765625 +23300 -0.1983642578125 +23301 -0.0262451171875 +23302 -0.116241455078125 +23303 -0.016693115234375 +23304 -0.036834716796875 +23305 -0.00714111328125 +23306 0.034881591796875 +23307 0.00189208984375 +23308 0.09124755859375 +23309 0.009613037109375 +23310 0.10888671875 +23311 0.01385498046875 +23312 0.125518798828125 +23313 0.017791748046875 +23314 0.15771484375 +23315 0.02276611328125 +23316 0.17828369140625 +23317 0.026275634765625 +23318 0.17108154296875 +23319 0.02679443359375 +23320 0.129974365234375 +23321 0.023712158203125 +23322 0.082427978515625 +23323 0.019439697265625 +23324 0.027679443359375 +23325 0.013916015625 +23326 -0.065643310546875 +23327 0.00445556640625 +23328 -0.15936279296875 +23329 -0.005523681640625 +23330 -0.21307373046875 +23331 -0.012359619140625 +23332 -0.234649658203125 +23333 -0.016632080078125 +23334 -0.2001953125 +23335 -0.016082763671875 +23336 -0.119171142578125 +23337 -0.011444091796875 +23338 -0.024749755859375 +23339 -0.0054931640625 +23340 0.085784912109375 +23341 0.00213623046875 +23342 0.178131103515625 +23343 0.00848388671875 +23344 0.215576171875 +23345 0.010406494140625 +23346 0.211456298828125 +23347 0.0091552734375 +23348 0.17523193359375 +23349 0.005645751953125 +23350 0.128753662109375 +23351 0.00177001953125 +23352 0.1019287109375 +23353 0.000152587890625 +23354 0.0743408203125 +23355 -0.00103759765625 +23356 0.04327392578125 +23357 -0.00213623046875 +23358 0.038177490234375 +23359 -0.000640869140625 +23360 0.076263427734375 +23361 0.00482177734375 +23362 0.14105224609375 +23363 0.012664794921875 +23364 0.186431884765625 +23365 0.018707275390625 +23366 0.188812255859375 +23367 0.020782470703125 +23368 0.1390380859375 +23369 0.017974853515625 +23370 0.041778564453125 +23371 0.010650634765625 +23372 -0.079437255859375 +23373 0.00079345703125 +23374 -0.219390869140625 +23375 -0.011138916015625 +23376 -0.367828369140625 +23377 -0.024200439453125 +23378 -0.494873046875 +23379 -0.0357666015625 +23380 -0.556243896484375 +23381 -0.04193115234375 +23382 -0.508697509765625 +23383 -0.038848876953125 +23384 -0.3756103515625 +23385 -0.02850341796875 +23386 -0.218902587890625 +23387 -0.016265869140625 +23388 -0.063751220703125 +23389 -0.0042724609375 +23390 0.091552734375 +23391 0.007659912109375 +23392 0.23602294921875 +23393 0.018707275390625 +23394 0.342987060546875 +23395 0.026611328125 +23396 0.39520263671875 +23397 0.029937744140625 +23398 0.389373779296875 +23399 0.0284423828125 +23400 0.324249267578125 +23401 0.0220947265625 +23402 0.224090576171875 +23403 0.0130615234375 +23404 0.124267578125 +23405 0.004425048828125 +23406 0.037078857421875 +23407 -0.002716064453125 +23408 -0.010101318359375 +23409 -0.0059814453125 +23410 -0.019439697265625 +23411 -0.005645751953125 +23412 -0.022796630859375 +23413 -0.00457763671875 +23414 -0.001556396484375 +23415 -0.001220703125 +23416 0.056304931640625 +23417 0.005340576171875 +23418 0.106719970703125 +23419 0.01116943359375 +23420 0.096893310546875 +23421 0.011566162109375 +23422 0.042694091796875 +23423 0.007843017578125 +23424 -0.018035888671875 +23425 0.0032958984375 +23426 -0.07586669921875 +23427 -0.00128173828125 +23428 -0.11944580078125 +23429 -0.0048828125 +23430 -0.15972900390625 +23431 -0.00848388671875 +23432 -0.202606201171875 +23433 -0.0125732421875 +23434 -0.24859619140625 +23435 -0.01715087890625 +23436 -0.30517578125 +23437 -0.022857666015625 +23438 -0.36212158203125 +23439 -0.02874755859375 +23440 -0.39141845703125 +23441 -0.032318115234375 +23442 -0.35528564453125 +23443 -0.030181884765625 +23444 -0.249969482421875 +23445 -0.021942138671875 +23446 -0.092864990234375 +23447 -0.00909423828125 +23448 0.08905029296875 +23449 0.006011962890625 +23450 0.2352294921875 +23451 0.01806640625 +23452 0.318817138671875 +23453 0.0247802734375 +23454 0.358642578125 +23455 0.02783203125 +23456 0.347747802734375 +23457 0.026641845703125 +23458 0.28564453125 +23459 0.021148681640625 +23460 0.223175048828125 +23461 0.01580810546875 +23462 0.196746826171875 +23463 0.013824462890625 +23464 0.179840087890625 +23465 0.01287841796875 +23466 0.155548095703125 +23467 0.011444091796875 +23468 0.151214599609375 +23469 0.011871337890625 +23470 0.156951904296875 +23471 0.01324462890625 +23472 0.13177490234375 +23473 0.01190185546875 +23474 0.100799560546875 +23475 0.010009765625 +23476 0.087127685546875 +23477 0.009552001953125 +23478 0.05487060546875 +23479 0.007354736328125 +23480 -0.009002685546875 +23481 0.002227783203125 +23482 -0.10400390625 +23483 -0.005767822265625 +23484 -0.229400634765625 +23485 -0.0166015625 +23486 -0.35552978515625 +23487 -0.027679443359375 +23488 -0.441925048828125 +23489 -0.035430908203125 +23490 -0.473846435546875 +23491 -0.03857421875 +23492 -0.464813232421875 +23493 -0.038238525390625 +23494 -0.419097900390625 +23495 -0.0347900390625 +23496 -0.334320068359375 +23497 -0.027984619140625 +23498 -0.227935791015625 +23499 -0.019317626953125 +23500 -0.12347412109375 +23501 -0.01080322265625 +23502 -0.02764892578125 +23503 -0.003021240234375 +23504 0.077667236328125 +23505 0.005645751953125 +23506 0.2132568359375 +23507 0.017059326171875 +23508 0.38885498046875 +23509 0.0321044921875 +23510 0.582794189453125 +23511 0.04888916015625 +23512 0.734039306640625 +23513 0.062042236328125 +23514 0.800140380859375 +23515 0.06781005859375 +23516 0.7783203125 +23517 0.06597900390625 +23518 0.6651611328125 +23519 0.056243896484375 +23520 0.45965576171875 +23521 0.03851318359375 +23522 0.199188232421875 +23523 0.016082763671875 +23524 -0.050689697265625 +23525 -0.00531005859375 +23526 -0.23297119140625 +23527 -0.02069091796875 +23528 -0.33013916015625 +23529 -0.028564453125 +23530 -0.368408203125 +23531 -0.031280517578125 +23532 -0.378936767578125 +23533 -0.031585693359375 +23534 -0.376983642578125 +23535 -0.030914306640625 +23536 -0.37969970703125 +23537 -0.03076171875 +23538 -0.391510009765625 +23539 -0.03155517578125 +23540 -0.385345458984375 +23541 -0.030914306640625 +23542 -0.3419189453125 +23543 -0.02716064453125 +23544 -0.28289794921875 +23545 -0.02215576171875 +23546 -0.251617431640625 +23547 -0.01971435546875 +23548 -0.266143798828125 +23549 -0.021392822265625 +23550 -0.273345947265625 +23551 -0.02252197265625 +23552 -0.216796875 +23553 -0.018218994140625 +23554 -0.128265380859375 +23555 -0.010986328125 +23556 -0.068145751953125 +23557 -0.005096435546875 +23558 -0.0430908203125 +23559 -0.0010986328125 +23560 -0.024444580078125 +23561 0.002471923828125 +23562 0.020721435546875 +23563 0.007293701171875 +23564 0.124481201171875 +23565 0.0150146484375 +23566 0.25787353515625 +23567 0.023895263671875 +23568 0.379119873046875 +23569 0.03155517578125 +23570 0.47991943359375 +23571 0.0374755859375 +23572 0.5281982421875 +23573 0.039886474609375 +23574 0.511138916015625 +23575 0.0380859375 +23576 0.456207275390625 +23577 0.033660888671875 +23578 0.407470703125 +23579 0.0291748046875 +23580 0.383758544921875 +23581 0.025787353515625 +23582 0.35687255859375 +23583 0.022003173828125 +23584 0.31182861328125 +23585 0.01715087890625 +23586 0.250885009765625 +23587 0.011474609375 +23588 0.1654052734375 +23589 0.004638671875 +23590 0.035247802734375 +23591 -0.004364013671875 +23592 -0.142059326171875 +23593 -0.01556396484375 +23594 -0.33563232421875 +23595 -0.027191162109375 +23596 -0.5345458984375 +23597 -0.038604736328125 +23598 -0.72186279296875 +23599 -0.048828125 +23600 -0.836669921875 +23601 -0.054473876953125 +23602 -0.8326416015625 +23603 -0.05303955078125 +23604 -0.7296142578125 +23605 -0.045684814453125 +23606 -0.582550048828125 +23607 -0.03564453125 +23608 -0.440093994140625 +23609 -0.025726318359375 +23610 -0.324310302734375 +23611 -0.017303466796875 +23612 -0.20147705078125 +23613 -0.008544921875 +23614 -0.044647216796875 +23615 0.001922607421875 +23616 0.103973388671875 +23617 0.01165771484375 +23618 0.202392578125 +23619 0.018218994140625 +23620 0.264495849609375 +23621 0.022308349609375 +23622 0.338897705078125 +23623 0.02667236328125 +23624 0.443817138671875 +23625 0.032318115234375 +23626 0.545074462890625 +23627 0.037353515625 +23628 0.6173095703125 +23629 0.0404052734375 +23630 0.6524658203125 +23631 0.04107666015625 +23632 0.66339111328125 +23633 0.0401611328125 +23634 0.6561279296875 +23635 0.038116455078125 +23636 0.606781005859375 +23637 0.033660888671875 +23638 0.501190185546875 +23639 0.026092529296875 +23640 0.352783203125 +23641 0.01629638671875 +23642 0.176544189453125 +23643 0.005157470703125 +23644 -0.034820556640625 +23645 -0.00762939453125 +23646 -0.258209228515625 +23647 -0.020660400390625 +23648 -0.44244384765625 +23649 -0.031097412109375 +23650 -0.5753173828125 +23651 -0.03826904296875 +23652 -0.65203857421875 +23653 -0.04193115234375 +23654 -0.641632080078125 +23655 -0.0404052734375 +23656 -0.562164306640625 +23657 -0.0347900390625 +23658 -0.458038330078125 +23659 -0.02764892578125 +23660 -0.350555419921875 +23661 -0.020233154296875 +23662 -0.260528564453125 +23663 -0.013763427734375 +23664 -0.192108154296875 +23665 -0.008575439453125 +23666 -0.141937255859375 +23667 -0.0045166015625 +23668 -0.1021728515625 +23669 -0.001251220703125 +23670 -0.062896728515625 +23671 0.001708984375 +23672 -0.011932373046875 +23673 0.005035400390625 +23674 0.062835693359375 +23675 0.0093994140625 +23676 0.148712158203125 +23677 0.0140380859375 +23678 0.241729736328125 +23679 0.018768310546875 +23680 0.34912109375 +23681 0.024017333984375 +23682 0.457305908203125 +23683 0.02911376953125 +23684 0.54388427734375 +23685 0.0328369140625 +23686 0.5728759765625 +23687 0.033233642578125 +23688 0.506591796875 +23689 0.028289794921875 +23690 0.351226806640625 +23691 0.018402099609375 +23692 0.146514892578125 +23693 0.005859375 +23694 -0.05523681640625 +23695 -0.00634765625 +23696 -0.21624755859375 +23697 -0.01605224609375 +23698 -0.334930419921875 +23699 -0.02313232421875 +23700 -0.402984619140625 +23701 -0.027099609375 +23702 -0.4412841796875 +23703 -0.029083251953125 +23704 -0.49578857421875 +23705 -0.031707763671875 +23706 -0.5601806640625 +23707 -0.03466796875 +23708 -0.600738525390625 +23709 -0.036102294921875 +23710 -0.584228515625 +23711 -0.034210205078125 +23712 -0.47930908203125 +23713 -0.027313232421875 +23714 -0.27935791015625 +23715 -0.01507568359375 +23716 -0.0089111328125 +23717 0.00103759765625 +23718 0.268798828125 +23719 0.017425537109375 +23720 0.482818603515625 +23721 0.03009033203125 +23722 0.60369873046875 +23723 0.037353515625 +23724 0.650421142578125 +23725 0.04022216796875 +23726 0.66400146484375 +23727 0.041015625 +23728 0.6414794921875 +23729 0.039581298828125 +23730 0.572540283203125 +23731 0.03533935546875 +23732 0.498138427734375 +23733 0.0306396484375 +23734 0.439453125 +23735 0.026702880859375 +23736 0.375518798828125 +23737 0.022369384765625 +23738 0.274505615234375 +23739 0.01593017578125 +23740 0.1087646484375 +23741 0.005859375 +23742 -0.099395751953125 +23743 -0.00653076171875 +23744 -0.3182373046875 +23745 -0.0194091796875 +23746 -0.5489501953125 +23747 -0.032806396484375 +23748 -0.7738037109375 +23749 -0.045684814453125 +23750 -0.86383056640625 +23751 -0.055084228515625 +23752 -0.870391845703125 +23753 -0.059173583984375 +23754 -0.86895751953125 +23755 -0.058929443359375 +23756 -0.861053466796875 +23757 -0.05511474609375 +23758 -0.765869140625 +23759 -0.046783447265625 +23760 -0.5301513671875 +23761 -0.033355712890625 +23762 -0.214691162109375 +23763 -0.0152587890625 +23764 0.137359619140625 +23765 0.005035400390625 +23766 0.474822998046875 +23767 0.024658203125 +23768 0.76239013671875 +23769 0.04156494140625 +23770 0.867462158203125 +23771 0.05419921875 +23772 0.870361328125 +23773 0.062591552734375 +23774 0.86480712890625 +23775 0.066070556640625 +23776 0.831817626953125 +23777 0.06494140625 +23778 0.677581787109375 +23779 0.060577392578125 +23780 0.495880126953125 +23781 0.053314208984375 +23782 0.30767822265625 +23783 0.044219970703125 +23784 0.116180419921875 +23785 0.033447265625 +23786 -0.110748291015625 +23787 0.01922607421875 +23788 -0.381805419921875 +23789 0.001190185546875 +23790 -0.6572265625 +23791 -0.0181884765625 +23792 -0.857421875 +23793 -0.0355224609375 +23794 -0.870391845703125 +23795 -0.04840087890625 +23796 -0.870391845703125 +23797 -0.056427001953125 +23798 -0.86444091796875 +23799 -0.061126708984375 +23800 -0.85723876953125 +23801 -0.064483642578125 +23802 -0.790008544921875 +23803 -0.065460205078125 +23804 -0.62847900390625 +23805 -0.061065673828125 +23806 -0.3956298828125 +23807 -0.05108642578125 +23808 -0.126708984375 +23809 -0.037445068359375 +23810 0.150115966796875 +23811 -0.02166748046875 +23812 0.424041748046875 +23813 -0.0047607421875 +23814 0.670623779296875 +23815 0.011962890625 +23816 0.854522705078125 +23817 0.0269775390625 +23818 0.866485595703125 +23819 0.03936767578125 +23820 0.86920166015625 +23821 0.04840087890625 +23822 0.8653564453125 +23823 0.054229736328125 +23824 0.857147216796875 +23825 0.05706787109375 +23826 0.766845703125 +23827 0.056793212890625 +23828 0.628509521484375 +23829 0.05364990234375 +23830 0.462127685546875 +23831 0.047637939453125 +23832 0.297210693359375 +23833 0.039642333984375 +23834 0.14862060546875 +23835 0.03033447265625 +23836 -0.00537109375 +23837 0.01959228515625 +23838 -0.15753173828125 +23839 0.00799560546875 +23840 -0.31304931640625 +23841 -0.004058837890625 +23842 -0.48876953125 +23843 -0.016510009765625 +23844 -0.6416015625 +23845 -0.02789306640625 +23846 -0.751373291015625 +23847 -0.03729248046875 +23848 -0.84619140625 +23849 -0.0450439453125 +23850 -0.861297607421875 +23851 -0.0506591796875 +23852 -0.863250732421875 +23853 -0.053314208984375 +23854 -0.856597900390625 +23855 -0.052276611328125 +23856 -0.7498779296875 +23857 -0.047943115234375 +23858 -0.624542236328125 +23859 -0.04193115234375 +23860 -0.47808837890625 +23861 -0.034027099609375 +23862 -0.253387451171875 +23863 -0.023101806640625 +23864 0.003692626953125 +23865 -0.0106201171875 +23866 0.2257080078125 +23867 0.00140380859375 +23868 0.427154541015625 +23869 0.012939453125 +23870 0.643218994140625 +23871 0.02447509765625 +23872 0.855926513671875 +23873 0.035491943359375 +23874 0.870361328125 +23875 0.04443359375 +23876 0.870361328125 +23877 0.050018310546875 +23878 0.862762451171875 +23879 0.0523681640625 +23880 0.79669189453125 +23881 0.05145263671875 +23882 0.595794677734375 +23883 0.047119140625 +23884 0.362152099609375 +23885 0.040191650390625 +23886 0.1270751953125 +23887 0.031524658203125 +23888 -0.086944580078125 +23889 0.021881103515625 +23890 -0.2784423828125 +23891 0.011627197265625 +23892 -0.484832763671875 +23893 0.000213623046875 +23894 -0.729583740234375 +23895 -0.012542724609375 +23896 -0.86688232421875 +23897 -0.02520751953125 +23898 -0.870391845703125 +23899 -0.0360107421875 +23900 -0.86859130859375 +23901 -0.04461669921875 +23902 -0.86279296875 +23903 -0.0509033203125 +23904 -0.817962646484375 +23905 -0.053955078125 +23906 -0.6116943359375 +23907 -0.05267333984375 +23908 -0.3128662109375 +23909 -0.0469970703125 +23910 0.039398193359375 +23911 -0.037811279296875 +23912 0.422821044921875 +23913 -0.0257568359375 +23914 0.805145263671875 +23915 -0.0118408203125 +23916 0.870361328125 +23917 0.002044677734375 +23918 0.870361328125 +23919 0.014312744140625 +23920 0.860015869140625 +23921 0.02447509765625 +23922 0.727935791015625 +23923 0.03216552734375 +23924 0.48114013671875 +23925 0.03704833984375 +23926 0.2059326171875 +23927 0.039520263671875 +23928 -0.06103515625 +23929 0.0400390625 +23930 -0.29913330078125 +23931 0.038818359375 +23932 -0.516204833984375 +23933 0.03546142578125 +23934 -0.7252197265625 +23935 0.0296630859375 +23936 -0.85980224609375 +23937 0.0220947265625 +23938 -0.870391845703125 +23939 0.013702392578125 +23940 -0.870391845703125 +23941 0.005340576171875 +23942 -0.858062744140625 +23943 -0.00164794921875 +23944 -0.673004150390625 +23945 -0.006988525390625 +23946 -0.42694091796875 +23947 -0.011749267578125 +23948 -0.2100830078125 +23949 -0.01678466796875 +23950 -0.0362548828125 +23951 -0.021881103515625 +23952 0.10943603515625 +23953 -0.0262451171875 +23954 0.23516845703125 +23955 -0.02923583984375 +23956 0.373687744140625 +23957 -0.029815673828125 +23958 0.517791748046875 +23959 -0.02801513671875 +23960 0.602783203125 +23961 -0.02532958984375 +23962 0.635711669921875 +23963 -0.021697998046875 +23964 0.655181884765625 +23965 -0.01641845703125 +23966 0.65948486328125 +23967 -0.009857177734375 +23968 0.651275634765625 +23969 -0.00238037109375 +23970 0.61846923828125 +23971 0.005218505859375 +23972 0.53753662109375 +23973 0.011932373046875 +23974 0.404144287109375 +23975 0.017181396484375 +23976 0.22186279296875 +23977 0.020599365234375 +23978 0.003997802734375 +23979 0.02215576171875 +23980 -0.22100830078125 +23981 0.02215576171875 +23982 -0.42449951171875 +23983 0.021026611328125 +23984 -0.579833984375 +23985 0.019256591796875 +23986 -0.641876220703125 +23987 0.01788330078125 +23988 -0.6177978515625 +23989 0.016754150390625 +23990 -0.575531005859375 +23991 0.014373779296875 +23992 -0.526336669921875 +23993 0.010711669921875 +23994 -0.42645263671875 +23995 0.007110595703125 +23996 -0.2581787109375 +23997 0.004364013671875 +23998 -0.068695068359375 +23999 0.001739501953125 +24000 0.09222412109375 +24001 -0.00152587890625 +24002 0.232147216796875 +24003 -0.004852294921875 +24004 0.3509521484375 +24005 -0.007904052734375 +24006 0.410064697265625 +24007 -0.01129150390625 +24008 0.372955322265625 +24009 -0.015655517578125 +24010 0.2554931640625 +24011 -0.020477294921875 +24012 0.10711669921875 +24013 -0.02447509765625 +24014 -0.052886962890625 +24015 -0.027191162109375 +24016 -0.186279296875 +24017 -0.02783203125 +24018 -0.23291015625 +24019 -0.025146484375 +24020 -0.209442138671875 +24021 -0.019805908203125 +24022 -0.174163818359375 +24023 -0.01348876953125 +24024 -0.126739501953125 +24025 -0.006500244140625 +24026 -0.048126220703125 +24027 0.001220703125 +24028 0.0426025390625 +24029 0.0089111328125 +24030 0.10748291015625 +24031 0.015380859375 +24032 0.1409912109375 +24033 0.020233154296875 +24034 0.19708251953125 +24035 0.02459716796875 +24036 0.273651123046875 +24037 0.02825927734375 +24038 0.31768798828125 +24039 0.029876708984375 +24040 0.341094970703125 +24041 0.029754638671875 +24042 0.368011474609375 +24043 0.028564453125 +24044 0.37249755859375 +24045 0.02581787109375 +24046 0.30072021484375 +24047 0.020416259765625 +24048 0.1517333984375 +24049 0.0125732421875 +24050 -0.01470947265625 +24051 0.003936767578125 +24052 -0.1883544921875 +24053 -0.00494384765625 +24054 -0.372711181640625 +24055 -0.013885498046875 +24056 -0.51397705078125 +24057 -0.0213623046875 +24058 -0.57177734375 +24059 -0.02618408203125 +24060 -0.53948974609375 +24061 -0.028045654296875 +24062 -0.43511962890625 +24063 -0.027252197265625 +24064 -0.2962646484375 +24065 -0.024932861328125 +24066 -0.161102294921875 +24067 -0.0220947265625 +24068 -0.0435791015625 +24069 -0.0189208984375 +24070 0.060394287109375 +24071 -0.01531982421875 +24072 0.13665771484375 +24073 -0.01129150390625 +24074 0.170135498046875 +24075 -0.006866455078125 +24076 0.16552734375 +24077 -0.002197265625 +24078 0.15728759765625 +24079 0.002471923828125 +24080 0.150787353515625 +24081 0.0069580078125 +24082 0.12200927734375 +24083 0.01104736328125 +24084 0.080108642578125 +24085 0.014556884765625 +24086 0.05126953125 +24087 0.017303466796875 +24088 0.062896728515625 +24089 0.019134521484375 +24090 0.09271240234375 +24091 0.019989013671875 +24092 0.092987060546875 +24093 0.019805908203125 +24094 0.07855224609375 +24095 0.01861572265625 +24096 0.06427001953125 +24097 0.0164794921875 +24098 0.0347900390625 +24099 0.01348876953125 +24100 -0.01171875 +24101 0.009857177734375 +24102 -0.056060791015625 +24103 0.00579833984375 +24104 -0.055511474609375 +24105 0.001495361328125 +24106 -0.010467529296875 +24107 -0.00274658203125 +24108 0.02508544921875 +24109 -0.006683349609375 +24110 0.025665283203125 +24111 -0.010101318359375 +24112 0.017333984375 +24113 -0.012847900390625 +24114 0.00189208984375 +24115 -0.0147705078125 +24116 -0.03173828125 +24117 -0.01580810546875 +24118 -0.071502685546875 +24119 -0.01593017578125 +24120 -0.13543701171875 +24121 -0.01513671875 +24122 -0.219970703125 +24123 -0.013519287109375 +24124 -0.300506591796875 +24125 -0.01116943359375 +24126 -0.376312255859375 +24127 -0.00823974609375 +24128 -0.416107177734375 +24129 -0.004913330078125 +24130 -0.371124267578125 +24131 -0.001373291015625 +24132 -0.242279052734375 +24133 0.00213623046875 +24134 -0.069732666015625 +24135 0.00543212890625 +24136 0.125640869140625 +24137 0.008331298828125 +24138 0.31268310546875 +24139 0.01068115234375 +24140 0.45501708984375 +24141 0.01239013671875 +24142 0.554779052734375 +24143 0.01336669921875 +24144 0.61065673828125 +24145 0.013580322265625 +24146 0.610931396484375 +24147 0.0130615234375 +24148 0.531463623046875 +24149 0.0118408203125 +24150 0.3883056640625 +24151 0.010009765625 +24152 0.23468017578125 +24153 0.0076904296875 +24154 0.095245361328125 +24155 0.0050048828125 +24156 -0.00396728515625 +24157 0.00213623046875 +24158 -0.04852294921875 +24159 -0.000732421875 +24160 -0.055145263671875 +24161 -0.003448486328125 +24162 -0.0758056640625 +24163 -0.005859375 +24164 -0.138702392578125 +24165 -0.007843017578125 +24166 -0.209197998046875 +24167 -0.009307861328125 +24168 -0.289031982421875 +24169 -0.01019287109375 +24170 -0.37884521484375 +24171 -0.010467529296875 +24172 -0.456329345703125 +24173 -0.0101318359375 +24174 -0.51641845703125 +24175 -0.00921630859375 +24176 -0.519287109375 +24177 -0.007781982421875 +24178 -0.458251953125 +24179 -0.00592041015625 +24180 -0.384796142578125 +24181 -0.003753662109375 +24182 -0.323699951171875 +24183 -0.00140380859375 +24184 -0.269287109375 +24185 0.000946044921875 +24186 -0.1951904296875 +24187 0.003173828125 +24188 -0.100006103515625 +24189 0.005157470703125 +24190 -0.01055908203125 +24191 0.006805419921875 +24192 0.1033935546875 +24193 0.008026123046875 +24194 0.24908447265625 +24195 0.0087890625 +24196 0.373199462890625 +24197 0.009063720703125 +24198 0.45806884765625 +24199 0.00885009765625 +24200 0.511474609375 +24201 0.008148193359375 +24202 0.565399169921875 +24203 0.00701904296875 +24204 0.61138916015625 +24205 0.00555419921875 +24206 0.5897216796875 +24207 0.003814697265625 +24208 0.4906005859375 +24209 0.001922607421875 +24210 0.33148193359375 +24211 0.0 +24212 0.147796630859375 +24213 -0.0018310546875 +24214 -0.01873779296875 +24215 -0.00347900390625 +24216 -0.140289306640625 +24217 -0.004852294921875 +24218 -0.191986083984375 +24219 -0.005889892578125 +24220 -0.184295654296875 +24221 -0.006561279296875 +24222 -0.161834716796875 +24223 -0.0068359375 +24224 -0.166595458984375 +24225 -0.0067138671875 +24226 -0.19390869140625 +24227 -0.006195068359375 +24228 -0.22442626953125 +24229 -0.00531005859375 +24230 -0.279754638671875 +24231 -0.004119873046875 +24232 -0.3389892578125 +24233 -0.002716064453125 +24234 -0.3543701171875 +24235 -0.00115966796875 +24236 -0.348175048828125 +24237 0.00042724609375 +24238 -0.32598876953125 +24239 0.001953125 +24240 -0.2581787109375 +24241 0.003326416015625 +24242 -0.139801025390625 +24243 0.004486083984375 +24244 0.014617919921875 +24245 0.00537109375 +24246 0.144378662109375 +24247 0.005950927734375 +24248 0.221038818359375 +24249 0.006195068359375 +24250 0.27069091796875 +24251 0.006103515625 +24252 0.294036865234375 +24253 0.00567626953125 +24254 0.311767578125 +24255 0.00494384765625 +24256 0.339141845703125 +24257 0.003997802734375 +24258 0.360260009765625 +24259 0.00299072265625 +24260 0.360504150390625 +24261 0.001953125 +24262 0.308380126953125 +24263 0.00067138671875 +24264 0.18170166015625 +24265 -0.001007080078125 +24266 0.0047607421875 +24267 -0.002838134765625 +24268 -0.17559814453125 +24269 -0.00445556640625 +24270 -0.3143310546875 +24271 -0.00555419921875 +24272 -0.36785888671875 +24273 -0.00579833984375 +24274 -0.36248779296875 +24275 -0.00543212890625 +24276 -0.343536376953125 +24277 -0.00482177734375 +24278 -0.3018798828125 +24279 -0.00390625 +24280 -0.231414794921875 +24281 -0.002685546875 +24282 -0.117645263671875 +24283 -0.001129150390625 +24284 0.007049560546875 +24285 0.00048828125 +24286 0.087982177734375 +24287 0.001708984375 +24288 0.13946533203125 +24289 0.002593994140625 +24290 0.17425537109375 +24291 0.003265380859375 +24292 0.188201904296875 +24293 0.003662109375 +24294 0.171234130859375 +24295 0.003692626953125 +24296 0.118438720703125 +24297 0.003326416015625 +24298 0.05706787109375 +24299 0.002777099609375 +24300 -0.010711669921875 +24301 0.002105712890625 +24302 -0.0914306640625 +24303 0.001220703125 +24304 -0.162322998046875 +24305 0.000335693359375 +24306 -0.194549560546875 +24307 -0.000274658203125 +24308 -0.1492919921875 +24309 -0.00030517578125 +24310 -0.02166748046875 +24311 0.000274658203125 +24312 0.124053955078125 +24313 0.0009765625 +24314 0.211151123046875 +24315 0.001190185546875 +24316 0.240447998046875 +24317 0.0009765625 +24318 0.242218017578125 +24319 0.0006103515625 +24320 0.2257080078125 +24321 0.000732421875 +24322 0.194366455078125 +24323 0.001068115234375 +24324 0.115509033203125 +24325 -0.00030517578125 +24326 0.0128173828125 +24327 -0.00250244140625 +24328 -0.053802490234375 +24329 -0.00323486328125 +24330 -0.110626220703125 +24331 -0.003631591796875 +24332 -0.199493408203125 +24333 -0.005462646484375 +24334 -0.29437255859375 +24335 -0.00775146484375 +24336 -0.33221435546875 +24337 -0.008026123046875 +24338 -0.27972412109375 +24339 -0.0050048828125 +24340 -0.185333251953125 +24341 -0.00067138671875 +24342 -0.128204345703125 +24343 0.00177001953125 +24344 -0.115692138671875 +24345 0.002044677734375 +24346 -0.116455078125 +24347 0.001434326171875 +24348 -0.105926513671875 +24349 0.0009765625 +24350 -0.053955078125 +24351 0.001922607421875 +24352 0.048797607421875 +24353 0.00469970703125 +24354 0.157318115234375 +24355 0.00762939453125 +24356 0.212005615234375 +24357 0.00836181640625 +24358 0.218475341796875 +24359 0.007232666015625 +24360 0.23724365234375 +24361 0.0067138671875 +24362 0.30535888671875 +24363 0.00836181640625 +24364 0.38128662109375 +24365 0.010528564453125 +24366 0.404449462890625 +24367 0.010833740234375 +24368 0.3944091796875 +24369 0.0101318359375 +24370 0.3885498046875 +24371 0.009918212890625 +24372 0.362640380859375 +24373 0.00921630859375 +24374 0.27362060546875 +24375 0.00628662109375 +24376 0.11712646484375 +24377 0.00091552734375 +24378 -0.054901123046875 +24379 -0.004852294921875 +24380 -0.19085693359375 +24381 -0.009033203125 +24382 -0.28570556640625 +24383 -0.011505126953125 +24384 -0.339263916015625 +24385 -0.0123291015625 +24386 -0.3775634765625 +24387 -0.01263427734375 +24388 -0.445709228515625 +24389 -0.014251708984375 +24390 -0.535064697265625 +24391 -0.01690673828125 +24392 -0.629058837890625 +24393 -0.019989013671875 +24394 -0.697601318359375 +24395 -0.022308349609375 +24396 -0.70391845703125 +24397 -0.02239990234375 +24398 -0.6424560546875 +24399 -0.020050048828125 +24400 -0.491241455078125 +24401 -0.014404296875 +24402 -0.265716552734375 +24403 -0.00604248046875 +24404 -0.023712158203125 +24405 0.00274658203125 +24406 0.201751708984375 +24407 0.01068115234375 +24408 0.375823974609375 +24409 0.01641845703125 +24410 0.485076904296875 +24411 0.01953125 +24412 0.56884765625 +24413 0.021636962890625 +24414 0.634765625 +24415 0.02313232421875 +24416 0.63763427734375 +24417 0.022247314453125 +24418 0.5660400390625 +24419 0.01861572265625 +24420 0.4720458984375 +24421 0.01434326171875 +24422 0.40692138671875 +24423 0.011474609375 +24424 0.3778076171875 +24425 0.01031494140625 +24426 0.376953125 +24427 0.01055908203125 +24428 0.371978759765625 +24429 0.0108642578125 +24430 0.313140869140625 +24431 0.009185791015625 +24432 0.184417724609375 +24433 0.004852294921875 +24434 0.011199951171875 +24435 -0.001129150390625 +24436 -0.171051025390625 +24437 -0.007354736328125 +24438 -0.33740234375 +24439 -0.012908935546875 +24440 -0.47198486328125 +24441 -0.0172119140625 +24442 -0.560394287109375 +24443 -0.019744873046875 +24444 -0.58056640625 +24445 -0.01971435546875 +24446 -0.54754638671875 +24447 -0.01776123046875 +24448 -0.508575439453125 +24449 -0.01580810546875 +24450 -0.459503173828125 +24451 -0.013671875 +24452 -0.394378662109375 +24453 -0.0111083984375 +24454 -0.35260009765625 +24455 -0.009674072265625 +24456 -0.31170654296875 +24457 -0.008453369140625 +24458 -0.197418212890625 +24459 -0.00445556640625 +24460 -0.007965087890625 +24461 0.00238037109375 +24462 0.207489013671875 +24463 0.010101318359375 +24464 0.409210205078125 +24465 0.017181396484375 +24466 0.57208251953125 +24467 0.022674560546875 +24468 0.66595458984375 +24469 0.02545166015625 +24470 0.65875244140625 +24471 0.024261474609375 +24472 0.56744384765625 +24473 0.019866943359375 +24474 0.431396484375 +24475 0.01385498046875 +24476 0.29443359375 +24477 0.008026123046875 +24478 0.182464599609375 +24479 0.00341796875 +24480 0.06365966796875 +24481 -0.001220703125 +24482 -0.075958251953125 +24483 -0.0064697265625 +24484 -0.189422607421875 +24485 -0.01043701171875 +24486 -0.271942138671875 +24487 -0.012969970703125 +24488 -0.342529296875 +24489 -0.014862060546875 +24490 -0.364166259765625 +24491 -0.0147705078125 +24492 -0.327239990234375 +24493 -0.0123291015625 +24494 -0.2769775390625 +24495 -0.0093994140625 +24496 -0.253692626953125 +24497 -0.00762939453125 +24498 -0.24365234375 +24499 -0.00653076171875 +24500 -0.1983642578125 +24501 -0.004180908203125 +24502 -0.116241455078125 +24503 -0.00054931640625 +24504 -0.036834716796875 +24505 0.00274658203125 +24506 0.034881591796875 +24507 0.0054931640625 +24508 0.09124755859375 +24509 0.00738525390625 +24510 0.10888671875 +24511 0.007537841796875 +24512 0.125518798828125 +24513 0.007476806640625 +24514 0.15771484375 +24515 0.0079345703125 +24516 0.17828369140625 +24517 0.007843017578125 +24518 0.17108154296875 +24519 0.006622314453125 +24520 0.129974365234375 +24521 0.00408935546875 +24522 0.082427978515625 +24523 0.001373291015625 +24524 0.027679443359375 +24525 -0.00146484375 +24526 -0.065643310546875 +24527 -0.005615234375 +24528 -0.15936279296875 +24529 -0.009552001953125 +24530 -0.21307373046875 +24531 -0.01165771484375 +24532 -0.234649658203125 +24533 -0.012298583984375 +24534 -0.2001953125 +24535 -0.010528564453125 +24536 -0.119171142578125 +24537 -0.006744384765625 +24538 -0.024749755859375 +24539 -0.0023193359375 +24540 0.085784912109375 +24541 0.0028076171875 +24542 0.178131103515625 +24543 0.0072021484375 +24544 0.215576171875 +24545 0.009368896484375 +24546 0.211456298828125 +24547 0.009796142578125 +24548 0.17523193359375 +24549 0.008880615234375 +24550 0.128753662109375 +24551 0.0074462890625 +24552 0.1019287109375 +24553 0.00665283203125 +24554 0.0743408203125 +24555 0.005706787109375 +24556 0.04327392578125 +24557 0.004486083984375 +24558 0.038177490234375 +24559 0.004150390625 +24560 0.076263427734375 +24561 0.00537109375 +24562 0.14105224609375 +24563 0.00750732421875 +24564 0.186431884765625 +24565 0.008758544921875 +24566 0.188812255859375 +24567 0.00823974609375 +24568 0.1390380859375 +24569 0.005615234375 +24570 0.041778564453125 +24571 0.0010986328125 +24572 -0.079437255859375 +24573 -0.004302978515625 +24574 -0.219390869140625 +24575 -0.010345458984375 +24576 -0.367828369140625 +24577 -0.01690673828125 +24578 -0.494873046875 +24579 -0.023223876953125 +24580 -0.556243896484375 +24581 -0.026580810546875 +24582 -0.508697509765625 +24583 -0.023590087890625 +24584 -0.3756103515625 +24585 -0.015655517578125 +24586 -0.218902587890625 +24587 -0.006927490234375 +24588 -0.063751220703125 +24589 0.001068115234375 +24590 0.091552734375 +24591 0.0087890625 +24592 0.23602294921875 +24593 0.01568603515625 +24594 0.342987060546875 +24595 0.020111083984375 +24596 0.39520263671875 +24597 0.021026611328125 +24598 0.389373779296875 +24599 0.018341064453125 +24600 0.324249267578125 +24601 0.0120849609375 +24602 0.224090576171875 +24603 0.00408935546875 +24604 0.124267578125 +24605 -0.003082275390625 +24606 0.037078857421875 +24607 -0.00860595703125 +24608 -0.010101318359375 +24609 -0.010589599609375 +24610 -0.019439697265625 +24611 -0.009307861328125 +24612 -0.022796630859375 +24613 -0.007171630859375 +24614 -0.001556396484375 +24615 -0.00299072265625 +24616 0.056304931640625 +24617 0.003875732421875 +24618 0.106719970703125 +24619 0.0101318359375 +24620 0.096893310546875 +24621 0.0118408203125 +24622 0.042694091796875 +24623 0.010040283203125 +24624 -0.018035888671875 +24625 0.00732421875 +24626 -0.07586669921875 +24627 0.0042724609375 +24628 -0.11944580078125 +24629 0.001708984375 +24630 -0.15972900390625 +24631 -0.00115966796875 +24632 -0.202606201171875 +24633 -0.004730224609375 +24634 -0.24859619140625 +24635 -0.009002685546875 +24636 -0.30517578125 +24637 -0.014434814453125 +24638 -0.36212158203125 +24639 -0.020233154296875 +24640 -0.39141845703125 +24641 -0.0242919921875 +24642 -0.35528564453125 +24643 -0.023773193359375 +24644 -0.249969482421875 +24645 -0.018280029296875 +24646 -0.092864990234375 +24647 -0.00897216796875 +24648 0.08905029296875 +24649 0.002288818359375 +24650 0.2352294921875 +24651 0.011260986328125 +24652 0.318817138671875 +24653 0.016082763671875 +24654 0.358642578125 +24655 0.018157958984375 +24656 0.347747802734375 +24657 0.01702880859375 +24658 0.28564453125 +24659 0.012664794921875 +24660 0.223175048828125 +24661 0.00872802734375 +24662 0.196746826171875 +24663 0.00775146484375 +24664 0.179840087890625 +24665 0.007781982421875 +24666 0.155548095703125 +24667 0.007537841796875 +24668 0.151214599609375 +24669 0.008880615234375 +24670 0.156951904296875 +24671 0.011016845703125 +24672 0.13177490234375 +24673 0.010894775390625 +24674 0.100799560546875 +24675 0.01025390625 +24676 0.087127685546875 +24677 0.010650634765625 +24678 0.05487060546875 +24679 0.00946044921875 +24680 -0.009002685546875 +24681 0.005645751953125 +24682 -0.10400390625 +24683 -0.000732421875 +24684 -0.229400634765625 +24685 -0.0096435546875 +24686 -0.35552978515625 +24687 -0.018951416015625 +24688 -0.441925048828125 +24689 -0.025726318359375 +24690 -0.473846435546875 +24691 -0.028900146484375 +24692 -0.464813232421875 +24693 -0.02935791015625 +24694 -0.419097900390625 +24695 -0.02734375 +24696 -0.334320068359375 +24697 -0.0225830078125 +24698 -0.227935791015625 +24699 -0.01629638671875 +24700 -0.12347412109375 +24701 -0.010101318359375 +24702 -0.02764892578125 +24703 -0.00439453125 +24704 0.077667236328125 +24705 0.002166748046875 +24706 0.2132568359375 +24707 0.0111083984375 +24708 0.38885498046875 +24709 0.023193359375 +24710 0.582794189453125 +24711 0.036865234375 +24712 0.734039306640625 +24713 0.047760009765625 +24714 0.800140380859375 +24715 0.052764892578125 +24716 0.7783203125 +24717 0.05169677734375 +24718 0.6651611328125 +24719 0.044281005859375 +24720 0.45965576171875 +24721 0.0303955078125 +24722 0.199188232421875 +24723 0.0126953125 +24724 -0.050689697265625 +24725 -0.004150390625 +24726 -0.23297119140625 +24727 -0.01611328125 +24728 -0.33013916015625 +24729 -0.022003173828125 +24730 -0.368408203125 +24731 -0.02374267578125 +24732 -0.378936767578125 +24733 -0.02362060546875 +24734 -0.376983642578125 +24735 -0.0228271484375 +24736 -0.37969970703125 +24737 -0.022613525390625 +24738 -0.391510009765625 +24739 -0.0233154296875 +24740 -0.385345458984375 +24741 -0.02294921875 +24742 -0.3419189453125 +24743 -0.020111083984375 +24744 -0.28289794921875 +24745 -0.016357421875 +24746 -0.251617431640625 +24747 -0.014801025390625 +24748 -0.266143798828125 +24749 -0.01666259765625 +24750 -0.273345947265625 +24751 -0.01806640625 +24752 -0.216796875 +24753 -0.014923095703125 +24754 -0.128265380859375 +24755 -0.00946044921875 +24756 -0.068145751953125 +24757 -0.005950927734375 +24758 -0.0430908203125 +24759 -0.00482177734375 +24760 -0.024444580078125 +24761 -0.003997802734375 +24762 0.020721435546875 +24763 -0.0010986328125 +24764 0.124481201171875 +24765 0.00616455078125 +24766 0.25787353515625 +24767 0.015716552734375 +24768 0.379119873046875 +24769 0.024566650390625 +24770 0.47991943359375 +24771 0.0321044921875 +24772 0.5281982421875 +24773 0.035980224609375 +24774 0.511138916015625 +24775 0.035247802734375 +24776 0.456207275390625 +24777 0.031829833984375 +24778 0.407470703125 +24779 0.02886962890625 +24780 0.383758544921875 +24781 0.0277099609375 +24782 0.35687255859375 +24783 0.026275634765625 +24784 0.31182861328125 +24785 0.023468017578125 +24786 0.250885009765625 +24787 0.019439697265625 +24788 0.1654052734375 +24789 0.0135498046875 +24790 0.035247802734375 +24791 0.004364013671875 +24792 -0.142059326171875 +24793 -0.008270263671875 +24794 -0.33563232421875 +24795 -0.022125244140625 +24796 -0.5345458984375 +24797 -0.03643798828125 +24798 -0.72186279296875 +24799 -0.04998779296875 +24800 -0.836669921875 +24801 -0.058380126953125 +24802 -0.8326416015625 +24803 -0.05828857421875 +24804 -0.7296142578125 +24805 -0.051116943359375 +24806 -0.582550048828125 +24807 -0.040863037109375 +24808 -0.440093994140625 +24809 -0.030975341796875 +24810 -0.324310302734375 +24811 -0.02301025390625 +24812 -0.20147705078125 +24813 -0.014495849609375 +24814 -0.044647216796875 +24815 -0.00347900390625 +24816 0.103973388671875 +24817 0.0069580078125 +24818 0.202392578125 +24819 0.0137939453125 +24820 0.264495849609375 +24821 0.01806640625 +24822 0.338897705078125 +24823 0.023284912109375 +24824 0.443817138671875 +24825 0.03076171875 +24826 0.545074462890625 +24827 0.03802490234375 +24828 0.6173095703125 +24829 0.04327392578125 +24830 0.6524658203125 +24831 0.0458984375 +24832 0.66339111328125 +24833 0.04718017578125 +24834 0.6561279296875 +24835 0.047698974609375 +24836 0.606781005859375 +24837 0.045074462890625 +24838 0.501190185546875 +24839 0.03765869140625 +24840 0.352783203125 +24841 0.026611328125 +24842 0.176544189453125 +24843 0.01324462890625 +24844 -0.034820556640625 +24845 -0.00347900390625 +24846 -0.258209228515625 +24847 -0.021453857421875 +24848 -0.44244384765625 +24849 -0.035675048828125 +24850 -0.5753173828125 +24851 -0.045166015625 +24852 -0.65203857421875 +24853 -0.049652099609375 +24854 -0.641632080078125 +24855 -0.046112060546875 +24856 -0.562164306640625 +24857 -0.03656005859375 +24858 -0.458038330078125 +24859 -0.025665283203125 +24860 -0.350555419921875 +24861 -0.015625 +24862 -0.260528564453125 +24863 -0.00848388671875 +24864 -0.192108154296875 +24865 -0.0045166015625 +24866 -0.141937255859375 +24867 -0.003173828125 +24868 -0.1021728515625 +24869 -0.00341796875 +24870 -0.062896728515625 +24871 -0.003936767578125 +24872 -0.011932373046875 +24873 -0.003204345703125 +24874 0.062835693359375 +24875 0.000244140625 +24876 0.148712158203125 +24877 0.005340576171875 +24878 0.241729736328125 +24879 0.0118408203125 +24880 0.34912109375 +24881 0.020660400390625 +24882 0.457305908203125 +24883 0.030487060546875 +24884 0.54388427734375 +24885 0.0390625 +24886 0.5728759765625 +24887 0.042633056640625 +24888 0.506591796875 +24889 0.037200927734375 +24890 0.351226806640625 +24891 0.0233154296875 +24892 0.146514892578125 +24893 0.00494384765625 +24894 -0.05523681640625 +24895 -0.012603759765625 +24896 -0.21624755859375 +24897 -0.025604248046875 +24898 -0.334930419921875 +24899 -0.03411865234375 +24900 -0.402984619140625 +24901 -0.0374755859375 +24902 -0.4412841796875 +24903 -0.03802490234375 +24904 -0.49578857421875 +24905 -0.040771484375 +24906 -0.5601806640625 +24907 -0.045196533203125 +24908 -0.600738525390625 +24909 -0.047882080078125 +24910 -0.584228515625 +24911 -0.045440673828125 +24912 -0.47930908203125 +24913 -0.03466796875 +24914 -0.27935791015625 +24915 -0.014801025390625 +24916 -0.0089111328125 +24917 0.011627197265625 +24918 0.268798828125 +24919 0.038177490234375 +24920 0.482818603515625 +24921 0.057586669921875 +24922 0.60369873046875 +24923 0.066986083984375 +24924 0.650421142578125 +24925 0.068511962890625 +24926 0.66400146484375 +24927 0.066650390625 +24928 0.6414794921875 +24929 0.061279296875 +24930 0.572540283203125 +24931 0.051483154296875 +24932 0.498138427734375 +24933 0.0416259765625 +24934 0.439453125 +24935 0.034027099609375 +24936 0.375518798828125 +24937 0.026580810546875 +24938 0.274505615234375 +24939 0.0159912109375 +24940 0.1087646484375 +24941 -0.0006103515625 +24942 -0.099395751953125 +24943 -0.020965576171875 +24944 -0.3182373046875 +24945 -0.041839599609375 +24946 -0.5489501953125 +24947 -0.0634765625 +24948 -0.7738037109375 +24949 -0.08416748046875 +24950 -0.86383056640625 +24951 -0.09857177734375 +24952 -0.870391845703125 +24953 -0.1033935546875 +24954 -0.86895751953125 +24955 -0.10064697265625 +24956 -0.861053466796875 +24957 -0.091827392578125 +24958 -0.765869140625 +24959 -0.075286865234375 +24960 -0.5301513671875 +24961 -0.049957275390625 +24962 -0.214691162109375 +24963 -0.0166015625 +24964 0.137359619140625 +24965 0.020233154296875 +24966 0.474822998046875 +24967 0.055206298828125 +24968 0.76239013671875 +24969 0.084686279296875 +24970 0.867462158203125 +24971 0.105926513671875 +24972 0.870361328125 +24973 0.119049072265625 +24974 0.86480712890625 +24975 0.122955322265625 +24976 0.831817626953125 +24977 0.11834716796875 +24978 0.677581787109375 +24979 0.10791015625 +24980 0.495880126953125 +24981 0.092437744140625 +24982 0.30767822265625 +24983 0.073974609375 +24984 0.116180419921875 +24985 0.0528564453125 +24986 -0.110748291015625 +24987 0.02587890625 +24988 -0.381805419921875 +24989 -0.007598876953125 +24990 -0.6572265625 +24991 -0.0430908203125 +24992 -0.857421875 +24993 -0.0743408203125 +24994 -0.870391845703125 +24995 -0.096954345703125 +24996 -0.870391845703125 +24997 -0.110260009765625 +24998 -0.86444091796875 +24999 -0.117156982421875 +25000 -0.85723876953125 +25001 -0.121429443359375 +25002 -0.790008544921875 +25003 -0.121307373046875 +25004 -0.62847900390625 +25005 -0.11126708984375 +25006 -0.3956298828125 +25007 -0.091094970703125 +25008 -0.126708984375 +25009 -0.064300537109375 +25010 0.150115966796875 +25011 -0.0338134765625 +25012 0.424041748046875 +25013 -0.0009765625 +25014 0.670623779296875 +25015 0.031341552734375 +25016 0.854522705078125 +25017 0.059051513671875 +25018 0.866485595703125 +25019 0.080352783203125 +25020 0.86920166015625 +25021 0.093658447265625 +25022 0.8653564453125 +25023 0.100921630859375 +25024 0.857147216796875 +25025 0.103607177734375 +25026 0.766845703125 +25027 0.10150146484375 +25028 0.628509521484375 +25029 0.09521484375 +25030 0.462127685546875 +25031 0.08416748046875 +25032 0.297210693359375 +25033 0.071136474609375 +25034 0.14862060546875 +25035 0.057464599609375 +25036 -0.00537109375 +25037 0.040863037109375 +25038 -0.15753173828125 +25039 0.022186279296875 +25040 -0.31304931640625 +25041 0.00115966796875 +25042 -0.48876953125 +25043 -0.02362060546875 +25044 -0.6416015625 +25045 -0.04730224609375 +25046 -0.751373291015625 +25047 -0.06732177734375 +25048 -0.84619140625 +25049 -0.086090087890625 +25050 -0.861297607421875 +25051 -0.102142333984375 +25052 -0.863250732421875 +25053 -0.112091064453125 +25054 -0.856597900390625 +25055 -0.112701416015625 +25056 -0.7498779296875 +25057 -0.1053466796875 +25058 -0.624542236328125 +25059 -0.09613037109375 +25060 -0.47808837890625 +25061 -0.0828857421875 +25062 -0.253387451171875 +25063 -0.059600830078125 +25064 0.003692626953125 +25065 -0.031097412109375 +25066 0.2257080078125 +25067 -0.00457763671875 +25068 0.427154541015625 +25069 0.021209716796875 +25070 0.643218994140625 +25071 0.049652099609375 +25072 0.855926513671875 +25073 0.0797119140625 +25074 0.870361328125 +25075 0.105438232421875 +25076 0.870361328125 +25077 0.121673583984375 +25078 0.862762451171875 +25079 0.1292724609375 +25080 0.79669189453125 +25081 0.127960205078125 +25082 0.595794677734375 +25083 0.116851806640625 +25084 0.362152099609375 +25085 0.09906005859375 +25086 0.1270751953125 +25087 0.077606201171875 +25088 -0.086944580078125 +25089 0.0552978515625 +25090 -0.2784423828125 +25091 0.03271484375 +25092 -0.484832763671875 +25093 0.0048828125 +25094 -0.729583740234375 +25095 -0.0316162109375 +25096 -0.86688232421875 +25097 -0.07061767578125 +25098 -0.870391845703125 +25099 -0.104156494140625 +25100 -0.86859130859375 +25101 -0.131988525390625 +25102 -0.86279296875 +25103 -0.154205322265625 +25104 -0.817962646484375 +25105 -0.1661376953125 +25106 -0.6116943359375 +25107 -0.161712646484375 +25108 -0.3128662109375 +25109 -0.139892578125 +25110 0.039398193359375 +25111 -0.105072021484375 +25112 0.422821044921875 +25113 -0.059722900390625 +25114 0.805145263671875 +25115 -0.008026123046875 +25116 0.870361328125 +25117 0.041107177734375 +25118 0.870361328125 +25119 0.08038330078125 +25120 0.860015869140625 +25121 0.108673095703125 +25122 0.727935791015625 +25123 0.12530517578125 +25124 0.48114013671875 +25125 0.1298828125 +25126 0.2059326171875 +25127 0.126007080078125 +25128 -0.06103515625 +25129 0.116943359375 +25130 -0.29913330078125 +25131 0.10418701171875 +25132 -0.516204833984375 +25133 0.0858154296875 +25134 -0.7252197265625 +25135 0.05975341796875 +25136 -0.85980224609375 +25137 0.029266357421875 +25138 -0.870391845703125 +25139 -0.0010986328125 +25140 -0.870391845703125 +25141 -0.027587890625 +25142 -0.858062744140625 +25143 -0.0438232421875 +25144 -0.673004150390625 +25145 -0.049560546875 +25146 -0.42694091796875 +25147 -0.05224609375 +25148 -0.2100830078125 +25149 -0.05816650390625 +25150 -0.0362548828125 +25151 -0.067291259765625 +25152 0.10943603515625 +25153 -0.07586669921875 +25154 0.23516845703125 +25155 -0.081329345703125 +25156 0.373687744140625 +25157 -0.07818603515625 +25158 0.517791748046875 +25159 -0.066741943359375 +25160 0.602783203125 +25161 -0.055572509765625 +25162 0.635711669921875 +25163 -0.0439453125 +25164 0.655181884765625 +25165 -0.0272216796875 +25166 0.65948486328125 +25167 -0.006591796875 +25168 0.651275634765625 +25169 0.016998291015625 +25170 0.61846923828125 +25171 0.0404052734375 +25172 0.53753662109375 +25173 0.058837890625 +25174 0.404144287109375 +25175 0.070037841796875 +25176 0.22186279296875 +25177 0.072906494140625 +25178 0.003997802734375 +25179 0.067840576171875 +25180 -0.22100830078125 +25181 0.05743408203125 +25182 -0.42449951171875 +25183 0.04461669921875 +25184 -0.579833984375 +25185 0.0323486328125 +25186 -0.641876220703125 +25187 0.026458740234375 +25188 -0.6177978515625 +25189 0.0260009765625 +25190 -0.575531005859375 +25191 0.022125244140625 +25192 -0.526336669921875 +25193 0.01397705078125 +25194 -0.42645263671875 +25195 0.00848388671875 +25196 -0.2581787109375 +25197 0.009185791015625 +25198 -0.068695068359375 +25199 0.010955810546875 +25200 0.09222412109375 +25201 0.0084228515625 +25202 0.232147216796875 +25203 0.00396728515625 +25204 0.3509521484375 +25205 -0.001129150390625 +25206 0.410064697265625 +25207 -0.011016845703125 +25208 0.372955322265625 +25209 -0.029815673828125 +25210 0.2554931640625 +25211 -0.054718017578125 +25212 0.10711669921875 +25213 -0.078643798828125 +25214 -0.052886962890625 +25215 -0.098907470703125 +25216 -0.186279296875 +25217 -0.110565185546875 +25218 -0.23291015625 +25219 -0.105926513671875 +25220 -0.209442138671875 +25221 -0.087982177734375 +25222 -0.174163818359375 +25223 -0.065582275390625 +25224 -0.126739501953125 +25225 -0.03973388671875 +25226 -0.048126220703125 +25227 -0.00897216796875 +25228 0.0426025390625 +25229 0.02301025390625 +25230 0.10748291015625 +25231 0.049957275390625 +25232 0.1409912109375 +25233 0.070159912109375 +25234 0.19708251953125 +25235 0.090179443359375 +25236 0.273651123046875 +25237 0.109161376953125 +25238 0.31768798828125 +25239 0.119537353515625 +25240 0.341094970703125 +25241 0.122833251953125 +25242 0.368011474609375 +25243 0.1224365234375 +25244 0.37249755859375 +25245 0.11517333984375 +25246 0.30072021484375 +25247 0.09423828125 +25248 0.1517333984375 +25249 0.060211181640625 +25250 -0.01470947265625 +25251 0.02203369140625 +25252 -0.1883544921875 +25253 -0.0179443359375 +25254 -0.372711181640625 +25255 -0.059295654296875 +25256 -0.51397705078125 +25257 -0.09381103515625 +25258 -0.57177734375 +25259 -0.115203857421875 +25260 -0.53948974609375 +25261 -0.12188720703125 +25262 -0.43511962890625 +25263 -0.11578369140625 +25264 -0.2962646484375 +25265 -0.101654052734375 +25266 -0.161102294921875 +25267 -0.08453369140625 +25268 -0.0435791015625 +25269 -0.066314697265625 +25270 0.060394287109375 +25271 -0.046661376953125 +25272 0.13665771484375 +25273 -0.02789306640625 +25274 0.170135498046875 +25275 -0.01263427734375 +25276 0.16552734375 +25277 -0.000885009765625 +25278 0.15728759765625 +25279 0.01129150390625 +25280 0.150787353515625 +25281 0.02386474609375 +25282 0.12200927734375 +25283 0.0328369140625 +25284 0.080108642578125 +25285 0.03875732421875 +25286 0.05126953125 +25287 0.04461669921875 +25288 0.062896728515625 +25289 0.05364990234375 +25290 0.09271240234375 +25291 0.062469482421875 +25292 0.092987060546875 +25293 0.064422607421875 +25294 0.07855224609375 +25295 0.061492919921875 +25296 0.06427001953125 +25297 0.055816650390625 +25298 0.0347900390625 +25299 0.04559326171875 +25300 -0.01171875 +25301 0.031005859375 +25302 -0.056060791015625 +25303 0.015167236328125 +25304 -0.055511474609375 +25305 0.004486083984375 +25306 -0.010467529296875 +25307 -0.000457763671875 +25308 0.02508544921875 +25309 -0.006378173828125 +25310 0.025665283203125 +25311 -0.01617431640625 +25312 0.017333984375 +25313 -0.02581787109375 +25314 0.00189208984375 +25315 -0.03460693359375 +25316 -0.03173828125 +25317 -0.04376220703125 +25318 -0.071502685546875 +25319 -0.05145263671875 +25320 -0.13543701171875 +25321 -0.06005859375 +25322 -0.219970703125 +25323 -0.069183349609375 +25324 -0.300506591796875 +25325 -0.075653076171875 +25326 -0.376312255859375 +25327 -0.079681396484375 +25328 -0.416107177734375 +25329 -0.077423095703125 +25330 -0.371124267578125 +25331 -0.06268310546875 +25332 -0.242279052734375 +25333 -0.036102294921875 +25334 -0.069732666015625 +25335 -0.003631591796875 +25336 0.125640869140625 +25337 0.0313720703125 +25338 0.31268310546875 +25339 0.064208984375 +25340 0.45501708984375 +25341 0.08953857421875 +25342 0.554779052734375 +25343 0.107391357421875 +25344 0.61065673828125 +25345 0.11761474609375 +25346 0.610931396484375 +25347 0.118408203125 +25348 0.531463623046875 +25349 0.105865478515625 +25350 0.3883056640625 +25351 0.08245849609375 +25352 0.23468017578125 +25353 0.0562744140625 +25354 0.095245361328125 +25355 0.03118896484375 +25356 -0.00396728515625 +25357 0.011322021484375 +25358 -0.04852294921875 +25359 -0.000885009765625 +25360 -0.055145263671875 +25361 -0.007598876953125 +25362 -0.0758056640625 +25363 -0.016326904296875 +25364 -0.138702392578125 +25365 -0.030975341796875 +25366 -0.209197998046875 +25367 -0.046051025390625 +25368 -0.289031982421875 +25369 -0.06158447265625 +25370 -0.37884521484375 +25371 -0.077484130859375 +25372 -0.456329345703125 +25373 -0.090301513671875 +25374 -0.51641845703125 +25375 -0.0992431640625 +25376 -0.519287109375 +25377 -0.098388671875 +25378 -0.458251953125 +25379 -0.08685302734375 +25380 -0.384796142578125 +25381 -0.072509765625 +25382 -0.323699951171875 +25383 -0.059295654296875 +25384 -0.269287109375 +25385 -0.046539306640625 +25386 -0.1951904296875 +25387 -0.03057861328125 +25388 -0.100006103515625 +25389 -0.011474609375 +25390 -0.01055908203125 +25391 0.006439208984375 +25392 0.1033935546875 +25393 0.027435302734375 +25394 0.24908447265625 +25395 0.05242919921875 +25396 0.373199462890625 +25397 0.073272705078125 +25398 0.45806884765625 +25399 0.08721923828125 +25400 0.511474609375 +25401 0.09539794921875 +25402 0.565399169921875 +25403 0.102630615234375 +25404 0.61138916015625 +25405 0.10772705078125 +25406 0.5897216796875 +25407 0.101837158203125 +25408 0.4906005859375 +25409 0.08367919921875 +25410 0.33148193359375 +25411 0.056060791015625 +25412 0.147796630859375 +25413 0.024505615234375 +25414 -0.01873779296875 +25415 -0.004486083984375 +25416 -0.140289306640625 +25417 -0.0264892578125 +25418 -0.191986083984375 +25419 -0.037567138671875 +25420 -0.184295654296875 +25421 -0.03912353515625 +25422 -0.161834716796875 +25423 -0.0377197265625 +25424 -0.166595458984375 +25425 -0.039581298828125 +25426 -0.19390869140625 +25427 -0.043975830078125 +25428 -0.22442626953125 +25429 -0.048004150390625 +25430 -0.279754638671875 +25431 -0.054962158203125 +25432 -0.3389892578125 +25433 -0.061798095703125 +25434 -0.3543701171875 +25435 -0.0615234375 +25436 -0.348175048828125 +25437 -0.0576171875 +25438 -0.32598876953125 +25439 -0.051055908203125 +25440 -0.2581787109375 +25441 -0.03759765625 +25442 -0.139801025390625 +25443 -0.016693115234375 +25444 0.014617919921875 +25445 0.009307861328125 +25446 0.144378662109375 +25447 0.0311279296875 +25448 0.221038818359375 +25449 0.044403076171875 +25450 0.27069091796875 +25451 0.052947998046875 +25452 0.294036865234375 +25453 0.056854248046875 +25454 0.311767578125 +25455 0.0592041015625 +25456 0.339141845703125 +25457 0.0623779296875 +25458 0.360260009765625 +25459 0.064300537109375 +25460 0.360504150390625 +25461 0.06280517578125 +25462 0.308380126953125 +25463 0.052581787109375 +25464 0.18170166015625 +25465 0.029937744140625 +25466 0.0047607421875 +25467 -0.000946044921875 +25468 -0.17559814453125 +25469 -0.032196044921875 +25470 -0.3143310546875 +25471 -0.056243896484375 +25472 -0.36785888671875 +25473 -0.065765380859375 +25474 -0.36248779296875 +25475 -0.06512451171875 +25476 -0.343536376953125 +25477 -0.06195068359375 +25478 -0.3018798828125 +25479 -0.05474853515625 +25480 -0.231414794921875 +25481 -0.042510986328125 +25482 -0.117645263671875 +25483 -0.0228271484375 +25484 0.007049560546875 +25485 -0.001190185546875 +25486 0.087982177734375 +25487 0.01318359375 +25488 0.13946533203125 +25489 0.02264404296875 +25490 0.17425537109375 +25491 0.029327392578125 +25492 0.188201904296875 +25493 0.032470703125 +25494 0.171234130859375 +25495 0.03033447265625 +25496 0.118438720703125 +25497 0.0220947265625 +25498 0.05706787109375 +25499 0.012298583984375 +25500 -0.010711669921875 +25501 0.00128173828125 +25502 -0.0914306640625 +25503 -0.01202392578125 +25504 -0.162322998046875 +25505 -0.023834228515625 +25506 -0.194549560546875 +25507 -0.029327392578125 +25508 -0.1492919921875 +25509 -0.02197265625 +25510 -0.02166748046875 +25511 -0.000946044921875 +25512 0.124053955078125 +25513 0.02301025390625 +25514 0.211151123046875 +25515 0.0369873046875 +25516 0.240447998046875 +25517 0.041168212890625 +25518 0.242218017578125 +25519 0.04071044921875 +25520 0.2257080078125 +25521 0.037200927734375 +25522 0.194366455078125 +25523 0.03125 +25524 0.115509033203125 +25525 0.017425537109375 +25526 0.0128173828125 +25527 -0.000244140625 +25528 -0.053802490234375 +25529 -0.01165771484375 +25530 -0.110626220703125 +25531 -0.021240234375 +25532 -0.199493408203125 +25533 -0.036041259765625 +25534 -0.29437255859375 +25535 -0.05169677734375 +25536 -0.33221435546875 +25537 -0.0576171875 +25538 -0.27972412109375 +25539 -0.04827880859375 +25540 -0.185333251953125 +25541 -0.031829833984375 +25542 -0.128204345703125 +25543 -0.0216064453125 +25544 -0.115692138671875 +25545 -0.01885986328125 +25546 -0.116455078125 +25547 -0.01837158203125 +25548 -0.105926513671875 +25549 -0.016021728515625 +25550 -0.053955078125 +25551 -0.006805419921875 +25552 0.048797607421875 +25553 0.01080322265625 +25554 0.157318115234375 +25555 0.02923583984375 +25556 0.212005615234375 +25557 0.0384521484375 +25558 0.218475341796875 +25559 0.039398193359375 +25560 0.23724365234375 +25561 0.042266845703125 +25562 0.30535888671875 +25563 0.053314208984375 +25564 0.38128662109375 +25565 0.065582275390625 +25566 0.404449462890625 +25567 0.068878173828125 +25568 0.3944091796875 +25569 0.066558837890625 +25570 0.3885498046875 +25571 0.06494140625 +25572 0.362640380859375 +25573 0.059967041015625 +25574 0.27362060546875 +25575 0.044464111328125 +25576 0.11712646484375 +25577 0.017730712890625 +25578 -0.054901123046875 +25579 -0.011444091796875 +25580 -0.19085693359375 +25581 -0.034393310546875 +25582 -0.28570556640625 +25583 -0.050262451171875 +25584 -0.339263916015625 +25585 -0.059051513671875 +25586 -0.3775634765625 +25587 -0.065155029296875 +25588 -0.445709228515625 +25589 -0.076171875 +25590 -0.535064697265625 +25591 -0.090667724609375 +25592 -0.629058837890625 +25593 -0.10589599609375 +25594 -0.697601318359375 +25595 -0.1168212890625 +25596 -0.70391845703125 +25597 -0.117279052734375 +25598 -0.6424560546875 +25599 -0.10638427734375 +25600 -0.491241455078125 +25601 -0.080047607421875 +25602 -0.265716552734375 +25603 -0.04071044921875 +25604 -0.023712158203125 +25605 0.0010986328125 +25606 0.201751708984375 +25607 0.039276123046875 +25608 0.375823974609375 +25609 0.0673828125 +25610 0.485076904296875 +25611 0.083221435546875 +25612 0.56884765625 +25613 0.095001220703125 +25614 0.634765625 +25615 0.1044921875 +25616 0.63763427734375 +25617 0.102813720703125 +25618 0.5660400390625 +25619 0.0877685546875 +25620 0.4720458984375 +25621 0.069732666015625 +25622 0.40692138671875 +25623 0.058868408203125 +25624 0.3778076171875 +25625 0.056427001953125 +25626 0.376953125 +25627 0.06060791015625 +25628 0.371978759765625 +25629 0.064697265625 +25630 0.313140869140625 +25631 0.05841064453125 +25632 0.184417724609375 +25633 0.0382080078125 +25634 0.011199951171875 +25635 0.008880615234375 +25636 -0.171051025390625 +25637 -0.022735595703125 +25638 -0.33740234375 +25639 -0.051910400390625 +25640 -0.47198486328125 +25641 -0.075653076171875 +25642 -0.560394287109375 +25643 -0.09124755859375 +25644 -0.58056640625 +25645 -0.0943603515625 +25646 -0.54754638671875 +25647 -0.0880126953125 +25648 -0.508575439453125 +25649 -0.081634521484375 +25650 -0.459503173828125 +25651 -0.07427978515625 +25652 -0.394378662109375 +25653 -0.064605712890625 +25654 -0.35260009765625 +25655 -0.06024169921875 +25656 -0.31170654296875 +25657 -0.05645751953125 +25658 -0.197418212890625 +25659 -0.038177490234375 +25660 -0.007965087890625 +25661 -0.004791259765625 +25662 0.207489013671875 +25663 0.0340576171875 +25664 0.409210205078125 +25665 0.0706787109375 +25666 0.57208251953125 +25667 0.1002197265625 +25668 0.66595458984375 +25669 0.1168212890625 +25670 0.65875244140625 +25671 0.1141357421875 +25672 0.56744384765625 +25673 0.09564208984375 +25674 0.431396484375 +25675 0.069183349609375 +25676 0.29443359375 +25677 0.04345703125 +25678 0.182464599609375 +25679 0.023529052734375 +25680 0.06365966796875 +25681 0.002899169921875 +25682 -0.075958251953125 +25683 -0.02142333984375 +25684 -0.189422607421875 +25685 -0.040252685546875 +25686 -0.271942138671875 +25687 -0.052825927734375 +25688 -0.342529296875 +25689 -0.06317138671875 +25690 -0.364166259765625 +25691 -0.064117431640625 +25692 -0.327239990234375 +25693 -0.053924560546875 +25694 -0.2769775390625 +25695 -0.041778564453125 +25696 -0.253692626953125 +25697 -0.035797119140625 +25698 -0.24365234375 +25699 -0.033294677734375 +25700 -0.1983642578125 +25701 -0.024566650390625 +25702 -0.116241455078125 +25703 -0.00927734375 +25704 -0.036834716796875 +25705 0.004730224609375 +25706 0.034881591796875 +25707 0.0166015625 +25708 0.09124755859375 +25709 0.024932861328125 +25710 0.10888671875 +25711 0.025238037109375 +25712 0.125518798828125 +25713 0.025238037109375 +25714 0.15771484375 +25715 0.0284423828125 +25716 0.17828369140625 +25717 0.02960205078125 +25718 0.17108154296875 +25719 0.025604248046875 +25720 0.129974365234375 +25721 0.015380859375 +25722 0.082427978515625 +25723 0.0045166015625 +25724 0.027679443359375 +25725 -0.007049560546875 +25726 -0.065643310546875 +25727 -0.02557373046875 +25728 -0.15936279296875 +25729 -0.04345703125 +25730 -0.21307373046875 +25731 -0.052703857421875 +25732 -0.234649658203125 +25733 -0.05499267578125 +25734 -0.2001953125 +25735 -0.045684814453125 +25736 -0.119171142578125 +25737 -0.026824951171875 +25738 -0.024749755859375 +25739 -0.00518798828125 +25740 0.085784912109375 +25741 0.01959228515625 +25742 0.178131103515625 +25743 0.040496826171875 +25744 0.215576171875 +25745 0.050079345703125 +25746 0.211456298828125 +25747 0.0509033203125 +25748 0.17523193359375 +25749 0.0447998046875 +25750 0.128753662109375 +25751 0.036102294921875 +25752 0.1019287109375 +25753 0.03076171875 +25754 0.0743408203125 +25755 0.02471923828125 +25756 0.04327392578125 +25757 0.0174560546875 +25758 0.038177490234375 +25759 0.01495361328125 +25760 0.076263427734375 +25761 0.020721435546875 +25762 0.14105224609375 +25763 0.031585693359375 +25764 0.186431884765625 +25765 0.038421630859375 +25766 0.188812255859375 +25767 0.036651611328125 +25768 0.1390380859375 +25769 0.024566650390625 +25770 0.041778564453125 +25771 0.00323486328125 +25772 -0.079437255859375 +25773 -0.02252197265625 +25774 -0.219390869140625 +25775 -0.051605224609375 +25776 -0.367828369140625 +25777 -0.081878662109375 +25778 -0.494873046875 +25779 -0.107391357421875 +25780 -0.556243896484375 +25781 -0.119293212890625 +25782 -0.508697509765625 +25783 -0.10894775390625 +25784 -0.3756103515625 +25785 -0.081085205078125 +25786 -0.218902587890625 +25787 -0.048187255859375 +25788 -0.063751220703125 +25789 -0.015380859375 +25790 0.091552734375 +25791 0.017486572265625 +25792 0.23602294921875 +25793 0.04815673828125 +25794 0.342987060546875 +25795 0.07122802734375 +25796 0.39520263671875 +25797 0.083160400390625 +25798 0.389373779296875 +25799 0.083221435546875 +25800 0.324249267578125 +25801 0.07110595703125 +25802 0.224090576171875 +25803 0.0516357421875 +25804 0.124267578125 +25805 0.0318603515625 +25806 0.037078857421875 +25807 0.01422119140625 +25808 -0.010101318359375 +25809 0.004241943359375 +25810 -0.019439697265625 +25811 0.001495361328125 +25812 -0.022796630859375 +25813 -0.00030517578125 +25814 -0.001556396484375 +25815 0.002593994140625 +25816 0.056304931640625 +25817 0.0126953125 +25818 0.106719970703125 +25819 0.021240234375 +25820 0.096893310546875 +25821 0.017791748046875 +25822 0.042694091796875 +25823 0.005584716796875 +25824 -0.018035888671875 +25825 -0.0076904296875 +25826 -0.07586669921875 +25827 -0.020111083984375 +25828 -0.11944580078125 +25829 -0.02935791015625 +25830 -0.15972900390625 +25831 -0.03759765625 +25832 -0.202606201171875 +25833 -0.0460205078125 +25834 -0.24859619140625 +25835 -0.054718017578125 +25836 -0.30517578125 +25837 -0.065216064453125 +25838 -0.36212158203125 +25839 -0.0755615234375 +25840 -0.39141845703125 +25841 -0.0802001953125 +25842 -0.35528564453125 +25843 -0.0716552734375 +25844 -0.249969482421875 +25845 -0.04925537109375 +25846 -0.092864990234375 +25847 -0.016571044921875 +25848 0.08905029296875 +25849 0.020904541015625 +25850 0.2352294921875 +25851 0.051025390625 +25852 0.318817138671875 +25853 0.068389892578125 +25854 0.358642578125 +25855 0.07672119140625 +25856 0.347747802734375 +25857 0.07403564453125 +25858 0.28564453125 +25859 0.0595703125 +25860 0.223175048828125 +25861 0.04473876953125 +25862 0.196746826171875 +25863 0.0382080078125 +25864 0.179840087890625 +25865 0.034088134765625 +25866 0.155548095703125 +25867 0.028594970703125 +25868 0.151214599609375 +25869 0.02813720703125 +25870 0.156951904296875 +25871 0.030426025390625 +25872 0.13177490234375 +25873 0.025909423828125 +25874 0.100799560546875 +25875 0.0203857421875 +25876 0.087127685546875 +25877 0.01910400390625 +25878 0.05487060546875 +25879 0.01361083984375 +25880 -0.009002685546875 +25881 0.000762939453125 +25882 -0.10400390625 +25883 -0.0194091796875 +25884 -0.229400634765625 +25885 -0.046875 +25886 -0.35552978515625 +25887 -0.074859619140625 +25888 -0.441925048828125 +25889 -0.094024658203125 +25890 -0.473846435546875 +25891 -0.10101318359375 +25892 -0.464813232421875 +25893 -0.098968505859375 +25894 -0.419097900390625 +25895 -0.0888671875 +25896 -0.334320068359375 +25897 -0.07012939453125 +25898 -0.227935791015625 +25899 -0.0467529296875 +25900 -0.12347412109375 +25901 -0.02410888671875 +25902 -0.02764892578125 +25903 -0.003631591796875 +25904 0.077667236328125 +25905 0.018951416015625 +25906 0.2132568359375 +25907 0.048553466796875 +25908 0.38885498046875 +25909 0.0875244140625 +25910 0.582794189453125 +25911 0.130950927734375 +25912 0.734039306640625 +25913 0.16473388671875 +25914 0.800140380859375 +25915 0.1790771484375 +25916 0.7783203125 +25917 0.17340087890625 +25918 0.6651611328125 +25919 0.146942138671875 +25920 0.45965576171875 +25921 0.0994873046875 +25922 0.199188232421875 +25923 0.039703369140625 +25924 -0.050689697265625 +25925 -0.01727294921875 +25926 -0.23297119140625 +25927 -0.058258056640625 +25928 -0.33013916015625 +25929 -0.07928466796875 +25930 -0.368408203125 +25931 -0.086517333984375 +25932 -0.378936767578125 +25933 -0.0872802734375 +25934 -0.376983642578125 +25935 -0.085235595703125 +25936 -0.37969970703125 +25937 -0.084442138671875 +25938 -0.391510009765625 +25939 -0.085968017578125 +25940 -0.385345458984375 +25941 -0.083587646484375 +25942 -0.3419189453125 +25943 -0.072906494140625 +25944 -0.28289794921875 +25945 -0.0589599609375 +25946 -0.251617431640625 +25947 -0.051788330078125 +25948 -0.266143798828125 +25949 -0.0555419921875 +25950 -0.273345947265625 +25951 -0.05792236328125 +25952 -0.216796875 +25953 -0.0457763671875 +25954 -0.128265380859375 +25955 -0.0263671875 +25956 -0.068145751953125 +25957 -0.013671875 +25958 -0.0430908203125 +25959 -0.009124755859375 +25960 -0.024444580078125 +25961 -0.00604248046875 +25962 0.020721435546875 +25963 0.00323486328125 +25964 0.124481201171875 +25965 0.026214599609375 +25966 0.25787353515625 +25967 0.056243896484375 +25968 0.379119873046875 +25969 0.08367919921875 +25970 0.47991943359375 +25971 0.10662841796875 +25972 0.5281982421875 +25973 0.117645263671875 +25974 0.511138916015625 +25975 0.11376953125 +25976 0.456207275390625 +25977 0.101348876953125 +25978 0.407470703125 +25979 0.090606689453125 +25980 0.383758544921875 +25981 0.085845947265625 +25982 0.35687255859375 +25983 0.080474853515625 +25984 0.31182861328125 +25985 0.07098388671875 +25986 0.250885009765625 +25987 0.057830810546875 +25988 0.1654052734375 +25989 0.038970947265625 +25990 0.035247802734375 +25991 0.009674072265625 +25992 -0.142059326171875 +25993 -0.0306396484375 +25994 -0.33563232421875 +25995 -0.074859619140625 +25996 -0.5345458984375 +25997 -0.120452880859375 +25998 -0.72186279296875 +25999 -0.163543701171875 +26000 -0.836669921875 +26001 -0.189971923828125 +26002 -0.8326416015625 +26003 -0.18902587890625 +26004 -0.7296142578125 +26005 -0.165313720703125 +26006 -0.582550048828125 +26007 -0.131591796875 +26008 -0.440093994140625 +26009 -0.09912109375 +26010 -0.324310302734375 +26011 -0.07293701171875 +26012 -0.20147705078125 +26013 -0.045196533203125 +26014 -0.044647216796875 +26015 -0.00958251953125 +26016 0.103973388671875 +26017 0.02410888671875 +26018 0.202392578125 +26019 0.046173095703125 +26020 0.264495849609375 +26021 0.05987548828125 +26022 0.338897705078125 +26023 0.0765380859375 +26024 0.443817138671875 +26025 0.10040283203125 +26026 0.545074462890625 +26027 0.123565673828125 +26028 0.6173095703125 +26029 0.140167236328125 +26030 0.6524658203125 +26031 0.1483154296875 +26032 0.66339111328125 +26033 0.1510009765625 +26034 0.6561279296875 +26035 0.149627685546875 +26036 0.606781005859375 +26037 0.13861083984375 +26038 0.501190185546875 +26039 0.1146240234375 +26040 0.352783203125 +26041 0.080780029296875 +26042 0.176544189453125 +26043 0.040496826171875 +26044 -0.034820556640625 +26045 -0.007904052734375 +26046 -0.258209228515625 +26047 -0.059051513671875 +26048 -0.44244384765625 +26049 -0.10113525390625 +26050 -0.5753173828125 +26051 -0.131378173828125 +26052 -0.65203857421875 +26053 -0.148681640625 +26054 -0.641632080078125 +26055 -0.145904541015625 +26056 -0.562164306640625 +26057 -0.127288818359375 +26058 -0.458038330078125 +26059 -0.103118896484375 +26060 -0.350555419921875 +26061 -0.078338623046875 +26062 -0.260528564453125 +26063 -0.0577392578125 +26064 -0.192108154296875 +26065 -0.042266845703125 +26066 -0.141937255859375 +26067 -0.031097412109375 +26068 -0.1021728515625 +26069 -0.02239990234375 +26070 -0.062896728515625 +26071 -0.01385498046875 +26072 -0.011932373046875 +26073 -0.0025634765625 +26074 0.062835693359375 +26075 0.0142822265625 +26076 0.148712158203125 +26077 0.033721923828125 +26078 0.241729736328125 +26079 0.05487060546875 +26080 0.34912109375 +26081 0.079437255859375 +26082 0.457305908203125 +26083 0.104278564453125 +26084 0.54388427734375 +26085 0.12420654296875 +26086 0.5728759765625 +26087 0.130889892578125 +26088 0.506591796875 +26089 0.1156005859375 +26090 0.351226806640625 +26091 0.07977294921875 +26092 0.146514892578125 +26093 0.0325927734375 +26094 -0.05523681640625 +26095 -0.0137939453125 +26096 -0.21624755859375 +26097 -0.050689697265625 +26098 -0.334930419921875 +26099 -0.07769775390625 +26100 -0.402984619140625 +26101 -0.092926025390625 +26102 -0.4412841796875 +26103 -0.10125732421875 +26104 -0.49578857421875 +26105 -0.1134033203125 +26106 -0.5601806640625 +26107 -0.1279296875 +26108 -0.600738525390625 +26109 -0.13702392578125 +26110 -0.584228515625 +26111 -0.133026123046875 +26112 -0.47930908203125 +26113 -0.10833740234375 +26114 -0.27935791015625 +26115 -0.06072998046875 +26116 -0.0089111328125 +26117 0.004241943359375 +26118 0.268798828125 +26119 0.070587158203125 +26120 0.482818603515625 +26121 0.1202392578125 +26122 0.60369873046875 +26123 0.145965576171875 +26124 0.650421142578125 +26125 0.153167724609375 +26126 0.66400146484375 +26127 0.15301513671875 +26128 0.6414794921875 +26129 0.144866943359375 +26130 0.572540283203125 +26131 0.1260986328125 +26132 0.498138427734375 +26133 0.107452392578125 +26134 0.439453125 +26135 0.09442138671875 +26136 0.375518798828125 +26137 0.08123779296875 +26138 0.274505615234375 +26139 0.059234619140625 +26140 0.1087646484375 +26141 0.02081298828125 +26142 -0.099395751953125 +26143 -0.028472900390625 +26144 -0.3182373046875 +26145 -0.080535888671875 +26146 -0.5489501953125 +26147 -0.13604736328125 +26148 -0.7738037109375 +26149 -0.190582275390625 +26150 -0.86383056640625 +26151 -0.23046875 +26152 -0.870391845703125 +26153 -0.247100830078125 +26154 -0.86895751953125 +26155 -0.24530029296875 +26156 -0.861053466796875 +26157 -0.22857666015625 +26158 -0.765869140625 +26159 -0.192352294921875 +26160 -0.5301513671875 +26161 -0.13360595703125 +26162 -0.214691162109375 +26163 -0.054046630859375 +26164 0.137359619140625 +26165 0.03509521484375 +26166 0.474822998046875 +26167 0.12054443359375 +26168 0.76239013671875 +26169 0.19317626953125 +26170 0.867462158203125 +26171 0.24615478515625 +26172 0.870361328125 +26173 0.279876708984375 +26174 0.86480712890625 +26175 0.29150390625 +26176 0.831817626953125 +26177 0.28265380859375 +26178 0.677581787109375 +26179 0.259918212890625 +26180 0.495880126953125 +26181 0.225006103515625 +26182 0.30767822265625 +26183 0.182861328125 +26184 0.116180419921875 +26185 0.13409423828125 +26186 -0.110748291015625 +26187 0.070281982421875 +26188 -0.381805419921875 +26189 -0.01043701171875 +26190 -0.6572265625 +26191 -0.096923828125 +26192 -0.857421875 +26193 -0.173553466796875 +26194 -0.870391845703125 +26195 -0.229217529296875 +26196 -0.870391845703125 +26197 -0.26226806640625 +26198 -0.86444091796875 +26199 -0.280029296875 +26200 -0.85723876953125 +26201 -0.29217529296875 +26202 -0.790008544921875 +26203 -0.29400634765625 +26204 -0.62847900390625 +26205 -0.271392822265625 +26206 -0.3956298828125 +26207 -0.223602294921875 +26208 -0.126708984375 +26209 -0.159393310546875 +26210 0.150115966796875 +26211 -0.08599853515625 +26212 0.424041748046875 +26213 -0.006500244140625 +26214 0.670623779296875 +26215 0.072021484375 +26216 0.854522705078125 +26217 0.139434814453125 +26218 0.866485595703125 +26219 0.19122314453125 +26220 0.86920166015625 +26221 0.2235107421875 +26222 0.8653564453125 +26223 0.24127197265625 +26224 0.857147216796875 +26225 0.24822998046875 +26226 0.766845703125 +26227 0.243804931640625 +26228 0.628509521484375 +26229 0.229522705078125 +26230 0.462127685546875 +26231 0.203704833984375 +26232 0.297210693359375 +26233 0.173309326171875 +26234 0.14862060546875 +26235 0.141632080078125 +26236 -0.00537109375 +26237 0.102691650390625 +26238 -0.15753173828125 +26239 0.058502197265625 +26240 -0.31304931640625 +26241 0.008087158203125 +26242 -0.48876953125 +26243 -0.05230712890625 +26244 -0.6416015625 +26245 -0.11041259765625 +26246 -0.751373291015625 +26247 -0.159820556640625 +26248 -0.84619140625 +26249 -0.206787109375 +26250 -0.861297607421875 +26251 -0.24755859375 +26252 -0.863250732421875 +26253 -0.2735595703125 +26254 -0.856597900390625 +26255 -0.276580810546875 +26256 -0.7498779296875 +26257 -0.259918212890625 +26258 -0.624542236328125 +26259 -0.239013671875 +26260 -0.47808837890625 +26261 -0.208099365234375 +26262 -0.253387451171875 +26263 -0.15179443359375 +26264 0.003692626953125 +26265 -0.082183837890625 +26266 0.2257080078125 +26267 -0.017333984375 +26268 0.427154541015625 +26269 0.04608154296875 +26270 0.643218994140625 +26271 0.11669921875 +26272 0.855926513671875 +26273 0.192047119140625 +26274 0.870361328125 +26275 0.256927490234375 +26276 0.870361328125 +26277 0.298370361328125 +26278 0.862762451171875 +26279 0.31842041015625 +26280 0.79669189453125 +26281 0.31640625 +26282 0.595794677734375 +26283 0.289947509765625 +26284 0.362152099609375 +26285 0.246856689453125 +26286 0.1270751953125 +26287 0.194610595703125 +26288 -0.086944580078125 +26289 0.13885498046875 +26290 -0.2784423828125 +26291 0.0802001953125 +26292 -0.484832763671875 +26293 0.009490966796875 +26294 -0.729583740234375 +26295 -0.078338623046875 +26296 -0.86688232421875 +26297 -0.169952392578125 +26298 -0.870391845703125 +26299 -0.24871826171875 +26300 -0.86859130859375 +26301 -0.313385009765625 +26302 -0.86279296875 +26303 -0.36346435546875 +26304 -0.817962646484375 +26305 -0.38958740234375 +26306 -0.6116943359375 +26307 -0.379852294921875 +26308 -0.3128662109375 +26309 -0.332489013671875 +26310 0.039398193359375 +26311 -0.2564697265625 +26312 0.422821044921875 +26313 -0.15716552734375 +26314 0.805145263671875 +26315 -0.043426513671875 +26316 0.870361328125 +26317 0.066680908203125 +26318 0.870361328125 +26319 0.158050537109375 +26320 0.860015869140625 +26321 0.227569580078125 +26322 0.727935791015625 +26323 0.273162841796875 +26324 0.48114013671875 +26325 0.293365478515625 +26326 0.2059326171875 +26327 0.294525146484375 +26328 -0.06103515625 +26329 0.28265380859375 +26330 -0.29913330078125 +26331 0.26043701171875 +26332 -0.516204833984375 +26333 0.224090576171875 +26334 -0.7252197265625 +26335 0.169647216796875 +26336 -0.85980224609375 +26337 0.103759765625 +26338 -0.870391845703125 +26339 0.035614013671875 +26340 -0.870391845703125 +26341 -0.02685546875 +26342 -0.858062744140625 +26343 -0.070648193359375 +26344 -0.673004150390625 +26345 -0.094512939453125 +26346 -0.42694091796875 +26347 -0.112152099609375 +26348 -0.2100830078125 +26349 -0.135162353515625 +26350 -0.0362548828125 +26351 -0.162872314453125 +26352 0.10943603515625 +26353 -0.187530517578125 +26354 0.23516845703125 +26355 -0.203765869140625 +26356 0.373687744140625 +26357 -0.20068359375 +26358 0.517791748046875 +26359 -0.178802490234375 +26360 0.602783203125 +26361 -0.15484619140625 +26362 0.635711669921875 +26363 -0.127532958984375 +26364 0.655181884765625 +26365 -0.088165283203125 +26366 0.65948486328125 +26367 -0.039520263671875 +26368 0.651275634765625 +26369 0.016387939453125 +26370 0.61846923828125 +26371 0.0728759765625 +26372 0.53753662109375 +26373 0.11944580078125 +26374 0.404144287109375 +26375 0.15081787109375 +26376 0.22186279296875 +26377 0.164154052734375 +26378 0.003997802734375 +26379 0.1597900390625 +26380 -0.22100830078125 +26381 0.143035888671875 +26382 -0.42449951171875 +26383 0.119903564453125 +26384 -0.579833984375 +26385 0.09661865234375 +26386 -0.641876220703125 +26387 0.085662841796875 +26388 -0.6177978515625 +26389 0.084991455078125 +26390 -0.575531005859375 +26391 0.0753173828125 +26392 -0.526336669921875 +26393 0.054901123046875 +26394 -0.42645263671875 +26395 0.03900146484375 +26396 -0.2581787109375 +26397 0.035614013671875 +26398 -0.068695068359375 +26399 0.03387451171875 +26400 0.09222412109375 +26401 0.02239990234375 +26402 0.232147216796875 +26403 0.00665283203125 +26404 0.3509521484375 +26405 -0.010284423828125 +26406 0.410064697265625 +26407 -0.037139892578125 +26408 0.372955322265625 +26409 -0.08251953125 +26410 0.2554931640625 +26411 -0.14013671875 +26412 0.10711669921875 +26413 -0.1944580078125 +26414 -0.052886962890625 +26415 -0.23956298828125 +26416 -0.186279296875 +26417 -0.264617919921875 +26418 -0.23291015625 +26419 -0.252960205078125 +26420 -0.209442138671875 +26421 -0.21124267578125 +26422 -0.174163818359375 +26423 -0.158843994140625 +26424 -0.126739501953125 +26425 -0.09820556640625 +26426 -0.048126220703125 +26427 -0.0263671875 +26428 0.0426025390625 +26429 0.048309326171875 +26430 0.10748291015625 +26431 0.11199951171875 +26432 0.1409912109375 +26433 0.1607666015625 +26434 0.19708251953125 +26435 0.208587646484375 +26436 0.273651123046875 +26437 0.253387451171875 +26438 0.31768798828125 +26439 0.278533935546875 +26440 0.341094970703125 +26441 0.287139892578125 +26442 0.368011474609375 +26443 0.28662109375 +26444 0.37249755859375 +26445 0.27001953125 +26446 0.30072021484375 +26447 0.22265625 +26448 0.1517333984375 +26449 0.1458740234375 +26450 -0.01470947265625 +26451 0.059326171875 +26452 -0.1883544921875 +26453 -0.031707763671875 +26454 -0.372711181640625 +26455 -0.12603759765625 +26456 -0.51397705078125 +26457 -0.205596923828125 +26458 -0.57177734375 +26459 -0.25640869140625 +26460 -0.53948974609375 +26461 -0.274810791015625 +26462 -0.43511962890625 +26463 -0.2647705078125 +26464 -0.2962646484375 +26465 -0.236480712890625 +26466 -0.161102294921875 +26467 -0.2008056640625 +26468 -0.0435791015625 +26469 -0.161865234375 +26470 0.060394287109375 +26471 -0.118896484375 +26472 0.13665771484375 +26473 -0.076995849609375 +26474 0.170135498046875 +26475 -0.041900634765625 +26476 0.16552734375 +26477 -0.01373291015625 +26478 0.15728759765625 +26479 0.015899658203125 +26480 0.150787353515625 +26481 0.04681396484375 +26482 0.12200927734375 +26483 0.070068359375 +26484 0.080108642578125 +26485 0.086669921875 +26486 0.05126953125 +26487 0.102874755859375 +26488 0.062896728515625 +26489 0.125579833984375 +26490 0.09271240234375 +26491 0.14727783203125 +26492 0.092987060546875 +26493 0.1533203125 +26494 0.07855224609375 +26495 0.147979736328125 +26496 0.06427001953125 +26497 0.13592529296875 +26498 0.0347900390625 +26499 0.11322021484375 +26500 -0.01171875 +26501 0.08026123046875 +26502 -0.056060791015625 +26503 0.0439453125 +26504 -0.055511474609375 +26505 0.018280029296875 +26506 -0.010467529296875 +26507 0.004638671875 +26508 0.02508544921875 +26509 -0.01141357421875 +26510 0.025665283203125 +26511 -0.035980224609375 +26512 0.017333984375 +26513 -0.060089111328125 +26514 0.00189208984375 +26515 -0.08209228515625 +26516 -0.03173828125 +26517 -0.104461669921875 +26518 -0.071502685546875 +26519 -0.12310791015625 +26520 -0.13543701171875 +26521 -0.14312744140625 +26522 -0.219970703125 +26523 -0.16357421875 +26524 -0.300506591796875 +26525 -0.17755126953125 +26526 -0.376312255859375 +26527 -0.185546875 +26528 -0.416107177734375 +26529 -0.179229736328125 +26530 -0.371124267578125 +26531 -0.145263671875 +26532 -0.242279052734375 +26533 -0.085113525390625 +26534 -0.069732666015625 +26535 -0.01190185546875 +26536 0.125640869140625 +26537 0.06695556640625 +26538 0.31268310546875 +26539 0.141082763671875 +26540 0.45501708984375 +26541 0.198760986328125 +26542 0.554779052734375 +26543 0.239898681640625 +26544 0.61065673828125 +26545 0.263580322265625 +26546 0.610931396484375 +26547 0.266082763671875 +26548 0.531463623046875 +26549 0.240264892578125 +26550 0.3883056640625 +26551 0.191162109375 +26552 0.23468017578125 +26553 0.135009765625 +26554 0.095245361328125 +26555 0.079803466796875 +26556 -0.00396728515625 +26557 0.034088134765625 +26558 -0.04852294921875 +26559 0.003082275390625 +26560 -0.055145263671875 +26561 -0.017120361328125 +26562 -0.0758056640625 +26563 -0.0408935546875 +26564 -0.138702392578125 +26565 -0.07562255859375 +26566 -0.209197998046875 +26567 -0.110260009765625 +26568 -0.289031982421875 +26569 -0.14459228515625 +26570 -0.37884521484375 +26571 -0.1783447265625 +26572 -0.456329345703125 +26573 -0.204620361328125 +26574 -0.51641845703125 +26575 -0.221832275390625 +26576 -0.519287109375 +26577 -0.21832275390625 +26578 -0.458251953125 +26579 -0.192474365234375 +26580 -0.384796142578125 +26581 -0.160064697265625 +26582 -0.323699951171875 +26583 -0.12908935546875 +26584 -0.269287109375 +26585 -0.098602294921875 +26586 -0.1951904296875 +26587 -0.061614990234375 +26588 -0.100006103515625 +26589 -0.018585205078125 +26590 -0.01055908203125 +26591 0.021728515625 +26592 0.1033935546875 +26593 0.067535400390625 +26594 0.24908447265625 +26595 0.120361328125 +26596 0.373199462890625 +26597 0.163970947265625 +26598 0.45806884765625 +26599 0.192840576171875 +26600 0.511474609375 +26601 0.20916748046875 +26602 0.565399169921875 +26603 0.222503662109375 +26604 0.61138916015625 +26605 0.230560302734375 +26606 0.5897216796875 +26607 0.216033935546875 +26608 0.4906005859375 +26609 0.176544189453125 +26610 0.33148193359375 +26611 0.117889404296875 +26612 0.147796630859375 +26613 0.05120849609375 +26614 -0.01873779296875 +26615 -0.01043701171875 +26616 -0.140289306640625 +26617 -0.05810546875 +26618 -0.191986083984375 +26619 -0.0838623046875 +26620 -0.184295654296875 +26621 -0.090240478515625 +26622 -0.161834716796875 +26623 -0.09002685546875 +26624 -0.166595458984375 +26625 -0.095367431640625 +26626 -0.19390869140625 +26627 -0.104766845703125 +26628 -0.22442626953125 +26629 -0.11248779296875 +26630 -0.279754638671875 +26631 -0.125152587890625 +26632 -0.3389892578125 +26633 -0.136810302734375 +26634 -0.3543701171875 +26635 -0.133514404296875 +26636 -0.348175048828125 +26637 -0.122467041015625 +26638 -0.32598876953125 +26639 -0.105865478515625 +26640 -0.2581787109375 +26641 -0.075408935546875 +26642 -0.139801025390625 +26643 -0.030181884765625 +26644 0.014617919921875 +26645 0.024932861328125 +26646 0.144378662109375 +26647 0.071258544921875 +26648 0.221038818359375 +26649 0.09991455078125 +26650 0.27069091796875 +26651 0.118438720703125 +26652 0.294036865234375 +26653 0.126953125 +26654 0.311767578125 +26655 0.131622314453125 +26656 0.339141845703125 +26657 0.137237548828125 +26658 0.360260009765625 +26659 0.1395263671875 +26660 0.360504150390625 +26661 0.134307861328125 +26662 0.308380126953125 +26663 0.1114501953125 +26664 0.18170166015625 +26665 0.063934326171875 +26666 0.0047607421875 +26667 0.0 +26668 -0.17559814453125 +26669 -0.064727783203125 +26670 -0.3143310546875 +26671 -0.115234375 +26672 -0.36785888671875 +26673 -0.136993408203125 +26674 -0.36248779296875 +26675 -0.138427734375 +26676 -0.343536376953125 +26677 -0.13427734375 +26678 -0.3018798828125 +26679 -0.1214599609375 +26680 -0.231414794921875 +26681 -0.09796142578125 +26682 -0.117645263671875 +26683 -0.05908203125 +26684 0.007049560546875 +26685 -0.01556396484375 +26686 0.087982177734375 +26687 0.01446533203125 +26688 0.13946533203125 +26689 0.0355224609375 +26690 0.17425537109375 +26691 0.051544189453125 +26692 0.188201904296875 +26693 0.060882568359375 +26694 0.171234130859375 +26695 0.05999755859375 +26696 0.118438720703125 +26697 0.0469970703125 +26698 0.05706787109375 +26699 0.0306396484375 +26700 -0.010711669921875 +26701 0.01141357421875 +26702 -0.0914306640625 +26703 -0.012908935546875 +26704 -0.162322998046875 +26705 -0.03497314453125 +26706 -0.194549560546875 +26707 -0.045379638671875 +26708 -0.1492919921875 +26709 -0.0313720703125 +26710 -0.02166748046875 +26711 0.00872802734375 +26712 0.124053955078125 +26713 0.053955078125 +26714 0.211151123046875 +26715 0.07928466796875 +26716 0.240447998046875 +26717 0.085205078125 +26718 0.242218017578125 +26719 0.081817626953125 +26720 0.2257080078125 +26721 0.07244873046875 +26722 0.194366455078125 +26723 0.05841064453125 +26724 0.115509033203125 +26725 0.0291748046875 +26726 0.0128173828125 +26727 -0.007232666015625 +26728 -0.053802490234375 +26729 -0.03106689453125 +26730 -0.110626220703125 +26731 -0.050872802734375 +26732 -0.199493408203125 +26733 -0.080352783203125 +26734 -0.29437255859375 +26735 -0.1109619140625 +26736 -0.33221435546875 +26737 -0.1220703125 +26738 -0.27972412109375 +26739 -0.10284423828125 +26740 -0.185333251953125 +26741 -0.069305419921875 +26742 -0.128204345703125 +26743 -0.047576904296875 +26744 -0.115692138671875 +26745 -0.040252685546875 +26746 -0.116455078125 +26747 -0.0372314453125 +26748 -0.105926513671875 +26749 -0.0306396484375 +26750 -0.053955078125 +26751 -0.010772705078125 +26752 0.048797607421875 +26753 0.0252685546875 +26754 0.157318115234375 +26755 0.0626220703125 +26756 0.212005615234375 +26757 0.0816650390625 +26758 0.218475341796875 +26759 0.084197998046875 +26760 0.23724365234375 +26761 0.090087890625 +26762 0.30535888671875 +26763 0.11151123046875 +26764 0.38128662109375 +26765 0.134918212890625 +26766 0.404449462890625 +26767 0.140472412109375 +26768 0.3944091796875 +26769 0.134765625 +26770 0.3885498046875 +26771 0.13018798828125 +26772 0.362640380859375 +26773 0.11895751953125 +26774 0.27362060546875 +26775 0.087127685546875 +26776 0.11712646484375 +26777 0.03338623046875 +26778 -0.054901123046875 +26779 -0.02508544921875 +26780 -0.19085693359375 +26781 -0.071258544921875 +26782 -0.28570556640625 +26783 -0.103424072265625 +26784 -0.339263916015625 +26785 -0.1214599609375 +26786 -0.3775634765625 +26787 -0.1339111328125 +26788 -0.445709228515625 +26789 -0.15557861328125 +26790 -0.535064697265625 +26791 -0.183685302734375 +26792 -0.629058837890625 +26793 -0.212860107421875 +26794 -0.697601318359375 +26795 -0.233367919921875 +26796 -0.70391845703125 +26797 -0.233245849609375 +26798 -0.6424560546875 +26799 -0.2108154296875 +26800 -0.491241455078125 +26801 -0.15899658203125 +26802 -0.265716552734375 +26803 -0.08294677734375 +26804 -0.023712158203125 +26805 -0.00177001953125 +26806 0.201751708984375 +26807 0.073577880859375 +26808 0.375823974609375 +26809 0.131622314453125 +26810 0.485076904296875 +26811 0.16790771484375 +26812 0.56884765625 +26813 0.195343017578125 +26814 0.634765625 +26815 0.2164306640625 +26816 0.63763427734375 +26817 0.2164306640625 +26818 0.5660400390625 +26819 0.191650390625 +26820 0.4720458984375 +26821 0.159210205078125 +26822 0.40692138671875 +26823 0.13604736328125 +26824 0.3778076171875 +26825 0.124603271484375 +26826 0.376953125 +26827 0.1224365234375 +26828 0.371978759765625 +26829 0.1190185546875 +26830 0.313140869140625 +26831 0.098114013671875 +26832 0.184417724609375 +26833 0.0545654296875 +26834 0.011199951171875 +26835 -0.003204345703125 +26836 -0.171051025390625 +26837 -0.063507080078125 +26838 -0.33740234375 +26839 -0.118133544921875 +26840 -0.47198486328125 +26841 -0.161895751953125 +26842 -0.560394287109375 +26843 -0.19012451171875 +26844 -0.58056640625 +26845 -0.195648193359375 +26846 -0.54754638671875 +26847 -0.1834716796875 +26848 -0.508575439453125 +26849 -0.169189453125 +26850 -0.459503173828125 +26851 -0.1514892578125 +26852 -0.394378662109375 +26853 -0.128509521484375 +26854 -0.35260009765625 +26855 -0.113250732421875 +26856 -0.31170654296875 +26857 -0.098419189453125 +26858 -0.197418212890625 +26859 -0.059722900390625 +26860 -0.007965087890625 +26861 0.0032958984375 +26862 0.207489013671875 +26863 0.074462890625 +26864 0.409210205078125 +26865 0.1407470703125 +26866 0.57208251953125 +26867 0.19390869140625 +26868 0.66595458984375 +26869 0.22412109375 +26870 0.65875244140625 +26871 0.22088623046875 +26872 0.56744384765625 +26873 0.1898193359375 +26874 0.431396484375 +26875 0.143890380859375 +26876 0.29443359375 +26877 0.097564697265625 +26878 0.182464599609375 +26879 0.059417724609375 +26880 0.06365966796875 +26881 0.018585205078125 +26882 -0.075958251953125 +26883 -0.029449462890625 +26884 -0.189422607421875 +26885 -0.067840576171875 +26886 -0.271942138671875 +26887 -0.0950927734375 +26888 -0.342529296875 +26889 -0.118255615234375 +26890 -0.364166259765625 +26891 -0.124176025390625 +26892 -0.327239990234375 +26893 -0.1094970703125 +26894 -0.2769775390625 +26895 -0.090545654296875 +26896 -0.253692626953125 +26897 -0.081878662109375 +26898 -0.24365234375 +26899 -0.078521728515625 +26900 -0.1983642578125 +26901 -0.06298828125 +26902 -0.116241455078125 +26903 -0.034637451171875 +26904 -0.036834716796875 +26905 -0.00762939453125 +26906 0.034881591796875 +26907 0.016326904296875 +26908 0.09124755859375 +26909 0.034576416015625 +26910 0.10888671875 +26911 0.038848876953125 +26912 0.125518798828125 +26913 0.0428466796875 +26914 0.15771484375 +26915 0.052642822265625 +26916 0.17828369140625 +26917 0.058502197265625 +26918 0.17108154296875 +26919 0.054718017578125 +26920 0.129974365234375 +26921 0.039154052734375 +26922 0.082427978515625 +26923 0.021728515625 +26924 0.027679443359375 +26925 0.002166748046875 +26926 -0.065643310546875 +26927 -0.03082275390625 +26928 -0.15936279296875 +26929 -0.063568115234375 +26930 -0.21307373046875 +26931 -0.081573486328125 +26932 -0.234649658203125 +26933 -0.0877685546875 +26934 -0.2001953125 +26935 -0.073638916015625 +26936 -0.119171142578125 +26937 -0.042694091796875 +26938 -0.024749755859375 +26939 -0.0069580078125 +26940 0.085784912109375 +26941 0.034423828125 +26942 0.178131103515625 +26943 0.069000244140625 +26944 0.215576171875 +26945 0.08349609375 +26946 0.211456298828125 +26947 0.082672119140625 +26948 0.17523193359375 +26949 0.069915771484375 +26950 0.128753662109375 +26951 0.0531005859375 +26952 0.1019287109375 +26953 0.042999267578125 +26954 0.0743408203125 +26955 0.03228759765625 +26956 0.04327392578125 +26957 0.02008056640625 +26958 0.038177490234375 +26959 0.016998291015625 +26960 0.076263427734375 +26961 0.029296875 +26962 0.14105224609375 +26963 0.051116943359375 +26964 0.186431884765625 +26965 0.065948486328125 +26966 0.188812255859375 +26967 0.065399169921875 +26968 0.1390380859375 +26969 0.0462646484375 +26970 0.041778564453125 +26971 0.010284423828125 +26972 -0.079437255859375 +26973 -0.03399658203125 +26974 -0.219390869140625 +26975 -0.084716796875 +26976 -0.367828369140625 +26977 -0.138153076171875 +26978 -0.494873046875 +26979 -0.18353271484375 +26980 -0.556243896484375 +26981 -0.2049560546875 +26982 -0.508697509765625 +26983 -0.186920166015625 +26984 -0.3756103515625 +26985 -0.13787841796875 +26986 -0.218902587890625 +26987 -0.0802001953125 +26988 -0.063751220703125 +26989 -0.023040771484375 +26990 0.091552734375 +26991 0.03411865234375 +26992 0.23602294921875 +26993 0.0872802734375 +26994 0.342987060546875 +26995 0.12677001953125 +26996 0.39520263671875 +26997 0.1463623046875 +26998 0.389373779296875 +26999 0.144805908203125 +27000 0.324249267578125 +27001 0.12164306640625 +27002 0.224090576171875 +27003 0.085601806640625 +27004 0.124267578125 +27005 0.0494384765625 +27006 0.037078857421875 +27007 0.017578125 +27008 -0.010101318359375 +27009 -9.1552734375e-05 +27010 -0.019439697265625 +27011 -0.0042724609375 +27012 -0.022796630859375 +27013 -0.00640869140625 +27014 -0.001556396484375 +27015 0.000244140625 +27016 0.056304931640625 +27017 0.020050048828125 +27018 0.106719970703125 +27019 0.03717041015625 +27020 0.096893310546875 +27021 0.032684326171875 +27022 0.042694091796875 +27023 0.012359619140625 +27024 -0.018035888671875 +27025 -0.010101318359375 +27026 -0.07586669921875 +27027 -0.031280517578125 +27028 -0.11944580078125 +27029 -0.047088623046875 +27030 -0.15972900390625 +27031 -0.06146240234375 +27032 -0.202606201171875 +27033 -0.076507568359375 +27034 -0.24859619140625 +27035 -0.092437744140625 +27036 -0.30517578125 +27037 -0.111968994140625 +27038 -0.36212158203125 +27039 -0.131500244140625 +27040 -0.39141845703125 +27041 -0.14105224609375 +27042 -0.35528564453125 +27043 -0.1270751953125 +27044 -0.249969482421875 +27045 -0.088226318359375 +27046 -0.092864990234375 +27047 -0.030853271484375 +27048 0.08905029296875 +27049 0.0352783203125 +27050 0.2352294921875 +27051 0.08831787109375 +27052 0.318817138671875 +27053 0.118621826171875 +27054 0.358642578125 +27055 0.132965087890625 +27056 0.347747802734375 +27057 0.128814697265625 +27058 0.28564453125 +27059 0.106048583984375 +27060 0.223175048828125 +27061 0.0830078125 +27062 0.196746826171875 +27063 0.07281494140625 +27064 0.179840087890625 +27065 0.06597900390625 +27066 0.155548095703125 +27067 0.056427001953125 +27068 0.151214599609375 +27069 0.0540771484375 +27070 0.156951904296875 +27071 0.055419921875 +27072 0.13177490234375 +27073 0.045684814453125 +27074 0.100799560546875 +27075 0.033966064453125 +27076 0.087127685546875 +27077 0.028594970703125 +27078 0.05487060546875 +27079 0.016693115234375 +27080 -0.009002685546875 +27081 -0.00640869140625 +27082 -0.10400390625 +27083 -0.040496826171875 +27084 -0.229400634765625 +27085 -0.0853271484375 +27086 -0.35552978515625 +27087 -0.130279541015625 +27088 -0.441925048828125 +27089 -0.160797119140625 +27090 -0.473846435546875 +27091 -0.171600341796875 +27092 -0.464813232421875 +27093 -0.1676025390625 +27094 -0.419097900390625 +27095 -0.150390625 +27096 -0.334320068359375 +27097 -0.119140625 +27098 -0.227935791015625 +27099 -0.080169677734375 +27100 -0.12347412109375 +27101 -0.0419921875 +27102 -0.02764892578125 +27103 -0.007049560546875 +27104 0.077667236328125 +27105 0.0311279296875 +27106 0.2132568359375 +27107 0.08001708984375 +27108 0.38885498046875 +27109 0.14312744140625 +27110 0.582794189453125 +27111 0.212677001953125 +27112 0.734039306640625 +27113 0.2667236328125 +27114 0.800140380859375 +27115 0.28997802734375 +27116 0.7783203125 +27117 0.281494140625 +27118 0.6651611328125 +27119 0.240081787109375 +27120 0.45965576171875 +27121 0.165435791015625 +27122 0.199188232421875 +27123 0.071044921875 +27124 -0.050689697265625 +27125 -0.01947021484375 +27126 -0.23297119140625 +27127 -0.085540771484375 +27128 -0.33013916015625 +27129 -0.120880126953125 +27130 -0.368408203125 +27131 -0.1348876953125 +27132 -0.378936767578125 +27133 -0.13873291015625 +27134 -0.376983642578125 +27135 -0.137969970703125 +27136 -0.37969970703125 +27137 -0.13885498046875 +27138 -0.391510009765625 +27139 -0.1429443359375 +27140 -0.385345458984375 +27141 -0.139923095703125 +27142 -0.3419189453125 +27143 -0.122467041015625 +27144 -0.28289794921875 +27145 -0.099273681640625 +27146 -0.251617431640625 +27147 -0.087432861328125 +27148 -0.266143798828125 +27149 -0.094085693359375 +27150 -0.273345947265625 +27151 -0.098419189453125 +27152 -0.216796875 +27153 -0.0782470703125 +27154 -0.128265380859375 +27155 -0.0458984375 +27156 -0.068145751953125 +27157 -0.02490234375 +27158 -0.0430908203125 +27159 -0.017730712890625 +27160 -0.024444580078125 +27161 -0.01300048828125 +27162 0.020721435546875 +27163 0.0023193359375 +27164 0.124481201171875 +27165 0.040924072265625 +27166 0.25787353515625 +27167 0.091583251953125 +27168 0.379119873046875 +27169 0.138031005859375 +27170 0.47991943359375 +27171 0.177032470703125 +27172 0.5281982421875 +27173 0.196044921875 +27174 0.511138916015625 +27175 0.190032958984375 +27176 0.456207275390625 +27177 0.169708251953125 +27178 0.407470703125 +27179 0.15228271484375 +27180 0.383758544921875 +27181 0.14501953125 +27182 0.35687255859375 +27183 0.136749267578125 +27184 0.31182861328125 +27185 0.1214599609375 +27186 0.250885009765625 +27187 0.09991455078125 +27188 0.1654052734375 +27189 0.068572998046875 +27190 0.035247802734375 +27191 0.01947021484375 +27192 -0.142059326171875 +27193 -0.0484619140625 +27194 -0.33563232421875 +27195 -0.123199462890625 +27196 -0.5345458984375 +27197 -0.20050048828125 +27198 -0.72186279296875 +27199 -0.27374267578125 +27200 -0.836669921875 +27201 -0.31903076171875 +27202 -0.8326416015625 +27203 -0.31817626953125 +27204 -0.7296142578125 +27205 -0.278900146484375 +27206 -0.582550048828125 +27207 -0.22271728515625 +27208 -0.440093994140625 +27209 -0.1685791015625 +27210 -0.324310302734375 +27211 -0.12506103515625 +27212 -0.20147705078125 +27213 -0.078826904296875 +27214 -0.044647216796875 +27215 -0.019195556640625 +27216 0.103973388671875 +27217 0.037353515625 +27218 0.202392578125 +27219 0.074462890625 +27220 0.264495849609375 +27221 0.097625732421875 +27222 0.338897705078125 +27223 0.125946044921875 +27224 0.443817138671875 +27225 0.1666259765625 +27226 0.545074462890625 +27227 0.206268310546875 +27228 0.6173095703125 +27229 0.23492431640625 +27230 0.6524658203125 +27231 0.249420166015625 +27232 0.66339111328125 +27233 0.254730224609375 +27234 0.6561279296875 +27235 0.253173828125 +27236 0.606781005859375 +27237 0.23529052734375 +27238 0.501190185546875 +27239 0.195465087890625 +27240 0.352783203125 +27241 0.13885498046875 +27242 0.176544189453125 +27243 0.071258544921875 +27244 -0.034820556640625 +27245 -0.01025390625 +27246 -0.258209228515625 +27247 -0.0966796875 +27248 -0.44244384765625 +27249 -0.16802978515625 +27250 -0.5753173828125 +27251 -0.21954345703125 +27252 -0.65203857421875 +27253 -0.249359130859375 +27254 -0.641632080078125 +27255 -0.245330810546875 +27256 -0.562164306640625 +27257 -0.21453857421875 +27258 -0.458038330078125 +27259 -0.17437744140625 +27260 -0.350555419921875 +27261 -0.133148193359375 +27262 -0.260528564453125 +27263 -0.098968505859375 +27264 -0.192108154296875 +27265 -0.073394775390625 +27266 -0.141937255859375 +27267 -0.055023193359375 +27268 -0.1021728515625 +27269 -0.04071044921875 +27270 -0.062896728515625 +27271 -0.0264892578125 +27272 -0.011932373046875 +27273 -0.007537841796875 +27274 0.062835693359375 +27275 0.02093505859375 +27276 0.148712158203125 +27277 0.05401611328125 +27278 0.241729736328125 +27279 0.09014892578125 +27280 0.34912109375 +27281 0.132171630859375 +27282 0.457305908203125 +27283 0.174774169921875 +27284 0.54388427734375 +27285 0.209136962890625 +27286 0.5728759765625 +27287 0.22113037109375 +27288 0.506591796875 +27289 0.195953369140625 +27290 0.351226806640625 +27291 0.135955810546875 +27292 0.146514892578125 +27293 0.056671142578125 +27294 -0.05523681640625 +27295 -0.021392822265625 +27296 -0.21624755859375 +27297 -0.083526611328125 +27298 -0.334930419921875 +27299 -0.129150390625 +27300 -0.402984619140625 +27301 -0.155029296875 +27302 -0.4412841796875 +27303 -0.16937255859375 +27304 -0.49578857421875 +27305 -0.190277099609375 +27306 -0.5601806640625 +27307 -0.21527099609375 +27308 -0.600738525390625 +27309 -0.23114013671875 +27310 -0.584228515625 +27311 -0.224884033203125 +27312 -0.47930908203125 +27313 -0.18414306640625 +27314 -0.27935791015625 +27315 -0.1063232421875 +27316 -0.0089111328125 +27317 -0.00103759765625 +27318 0.268798828125 +27319 0.106964111328125 +27320 0.482818603515625 +27321 0.189910888671875 +27322 0.60369873046875 +27323 0.236328125 +27324 0.650421142578125 +27325 0.253692626953125 +27326 0.66400146484375 +27327 0.258148193359375 +27328 0.6414794921875 +27329 0.24859619140625 +27330 0.572540283203125 +27331 0.221038818359375 +27332 0.498138427734375 +27333 0.1915283203125 +27334 0.439453125 +27335 0.16839599609375 +27336 0.375518798828125 +27337 0.1434326171875 +27338 0.274505615234375 +27339 0.104156494140625 +27340 0.1087646484375 +27341 0.0396728515625 +27342 -0.099395751953125 +27343 -0.041290283203125 +27344 -0.3182373046875 +27345 -0.126312255859375 +27346 -0.5489501953125 +27347 -0.21588134765625 +27348 -0.7738037109375 +27349 -0.3031005859375 +27350 -0.86383056640625 +27351 -0.367279052734375 +27352 -0.870391845703125 +27353 -0.39544677734375 +27354 -0.86895751953125 +27355 -0.394561767578125 +27356 -0.861053466796875 +27357 -0.36981201171875 +27358 -0.765869140625 +27359 -0.314453125 +27360 -0.5301513671875 +27361 -0.22412109375 +27362 -0.214691162109375 +27363 -0.101593017578125 +27364 0.137359619140625 +27365 0.036285400390625 +27366 0.474822998046875 +27367 0.16937255859375 +27368 0.76239013671875 +27369 0.2838134765625 +27370 0.867462158203125 +27371 0.3690185546875 +27372 0.870361328125 +27373 0.42523193359375 +27374 0.86480712890625 +27375 0.44793701171875 +27376 0.831817626953125 +27377 0.439300537109375 +27378 0.677581787109375 +27379 0.408905029296875 +27380 0.495880126953125 +27381 0.359039306640625 +27382 0.30767822265625 +27383 0.297027587890625 +27384 0.116180419921875 +27385 0.223785400390625 +27386 -0.110748291015625 +27387 0.12689208984375 +27388 -0.381805419921875 +27389 0.003662109375 +27390 -0.6572265625 +27391 -0.129119873046875 +27392 -0.857421875 +27393 -0.247833251953125 +27394 -0.870391845703125 +27395 -0.335540771484375 +27396 -0.870391845703125 +27397 -0.389617919921875 +27398 -0.86444091796875 +27399 -0.4215087890625 +27400 -0.85723876953125 +27401 -0.446197509765625 +27402 -0.790008544921875 +27403 -0.4556884765625 +27404 -0.62847900390625 +27405 -0.4267578125 +27406 -0.3956298828125 +27407 -0.35772705078125 +27408 -0.126708984375 +27409 -0.262176513671875 +27410 0.150115966796875 +27411 -0.151275634765625 +27412 0.424041748046875 +27413 -0.02960205078125 +27414 0.670623779296875 +27415 0.091827392578125 +27416 0.854522705078125 +27417 0.19696044921875 +27418 0.866485595703125 +27419 0.278656005859375 +27420 0.86920166015625 +27421 0.3306884765625 +27422 0.8653564453125 +27423 0.3609619140625 +27424 0.857147216796875 +27425 0.37530517578125 +27426 0.766845703125 +27427 0.37255859375 +27428 0.628509521484375 +27429 0.3548583984375 +27430 0.462127685546875 +27431 0.31927490234375 +27432 0.297210693359375 +27433 0.276580810546875 +27434 0.14862060546875 +27435 0.231781005859375 +27436 -0.00537109375 +27437 0.174957275390625 +27438 -0.15753173828125 +27439 0.108978271484375 +27440 -0.31304931640625 +27441 0.032012939453125 +27442 -0.48876953125 +27443 -0.062164306640625 +27444 -0.6416015625 +27445 -0.153961181640625 +27446 -0.751373291015625 +27447 -0.233123779296875 +27448 -0.84619140625 +27449 -0.30963134765625 +27450 -0.861297607421875 +27451 -0.377410888671875 +27452 -0.863250732421875 +27453 -0.4224853515625 +27454 -0.856597900390625 +27455 -0.43145751953125 +27456 -0.7498779296875 +27457 -0.40948486328125 +27458 -0.624542236328125 +27459 -0.3809814453125 +27460 -0.47808837890625 +27461 -0.336456298828125 +27462 -0.253387451171875 +27463 -0.250946044921875 +27464 0.003692626953125 +27465 -0.1435546875 +27466 0.2257080078125 +27467 -0.043060302734375 +27468 0.427154541015625 +27469 0.05609130859375 +27470 0.643218994140625 +27471 0.1678466796875 +27472 0.855926513671875 +27473 0.288330078125 +27474 0.870361328125 +27475 0.39312744140625 +27476 0.870361328125 +27477 0.461334228515625 +27478 0.862762451171875 +27479 0.49609375 +27480 0.79669189453125 +27481 0.49615478515625 +27482 0.595794677734375 +27483 0.45751953125 +27484 0.362152099609375 +27485 0.39251708984375 +27486 0.1270751953125 +27487 0.312896728515625 +27488 -0.086944580078125 +27489 0.227508544921875 +27490 -0.2784423828125 +27491 0.1370849609375 +27492 -0.484832763671875 +27493 0.02667236328125 +27494 -0.729583740234375 +27495 -0.111968994140625 +27496 -0.86688232421875 +27497 -0.257568359375 +27498 -0.870391845703125 +27499 -0.3834228515625 +27500 -0.86859130859375 +27501 -0.487548828125 +27502 -0.86279296875 +27503 -0.569122314453125 +27504 -0.817962646484375 +27505 -0.613006591796875 +27506 -0.6116943359375 +27507 -0.599945068359375 +27508 -0.3128662109375 +27509 -0.526947021484375 +27510 0.039398193359375 +27511 -0.408233642578125 +27512 0.422821044921875 +27513 -0.252227783203125 +27514 0.805145263671875 +27515 -0.072967529296875 +27516 0.870361328125 +27517 0.100738525390625 +27518 0.870361328125 +27519 0.24481201171875 +27520 0.860015869140625 +27521 0.354339599609375 +27522 0.727935791015625 +27523 0.426116943359375 +27524 0.48114013671875 +27525 0.45782470703125 +27526 0.2059326171875 +27527 0.459716796875 +27528 -0.06103515625 +27529 0.441375732421875 +27530 -0.29913330078125 +27531 0.407073974609375 +27532 -0.516204833984375 +27533 0.35064697265625 +27534 -0.7252197265625 +27535 0.26556396484375 +27536 -0.85980224609375 +27537 0.162445068359375 +27538 -0.870391845703125 +27539 0.05584716796875 +27540 -0.870391845703125 +27541 -0.0416259765625 +27542 -0.858062744140625 +27543 -0.1092529296875 +27544 -0.673004150390625 +27545 -0.145172119140625 +27546 -0.42694091796875 +27547 -0.171539306640625 +27548 -0.2100830078125 +27549 -0.20709228515625 +27550 -0.0362548828125 +27551 -0.250762939453125 +27552 0.10943603515625 +27553 -0.290130615234375 +27554 0.23516845703125 +27555 -0.316680908203125 +27556 0.373687744140625 +27557 -0.312774658203125 +27558 0.517791748046875 +27559 -0.279205322265625 +27560 0.602783203125 +27561 -0.242706298828125 +27562 0.635711669921875 +27563 -0.201080322265625 +27564 0.655181884765625 +27565 -0.140289306640625 +27566 0.65948486328125 +27567 -0.064605712890625 +27568 0.651275634765625 +27569 0.02239990234375 +27570 0.61846923828125 +27571 0.110198974609375 +27572 0.53753662109375 +27573 0.182952880859375 +27574 0.404144287109375 +27575 0.232818603515625 +27576 0.22186279296875 +27577 0.255523681640625 +27578 0.003997802734375 +27579 0.251495361328125 +27580 -0.22100830078125 +27581 0.228302001953125 +27582 -0.42449951171875 +27583 0.194580078125 +27584 -0.579833984375 +27585 0.15936279296875 +27586 -0.641876220703125 +27587 0.1407470703125 +27588 -0.6177978515625 +27589 0.13592529296875 +27590 -0.575531005859375 +27591 0.1175537109375 +27592 -0.526336669921875 +27593 0.08343505859375 +27594 -0.42645263671875 +27595 0.0556640625 +27596 -0.2581787109375 +27597 0.045989990234375 +27598 -0.068695068359375 +27599 0.039154052734375 +27600 0.09222412109375 +27601 0.01898193359375 +27602 0.232147216796875 +27603 -0.00640869140625 +27604 0.3509521484375 +27605 -0.032562255859375 +27606 0.410064697265625 +27607 -0.0718994140625 +27608 0.372955322265625 +27609 -0.136749267578125 +27610 0.2554931640625 +27611 -0.2181396484375 +27612 0.10711669921875 +27613 -0.293914794921875 +27614 -0.052886962890625 +27615 -0.355743408203125 +27616 -0.186279296875 +27617 -0.38824462890625 +27618 -0.23291015625 +27619 -0.367767333984375 +27620 -0.209442138671875 +27621 -0.304046630859375 +27622 -0.174163818359375 +27623 -0.22509765625 +27624 -0.126739501953125 +27625 -0.13458251953125 +27626 -0.048126220703125 +27627 -0.028472900390625 +27628 0.0426025390625 +27629 0.08111572265625 +27630 0.10748291015625 +27631 0.17425537109375 +27632 0.1409912109375 +27633 0.245208740234375 +27634 0.19708251953125 +27635 0.31396484375 +27636 0.273651123046875 +27637 0.377532958984375 +27638 0.31768798828125 +27639 0.41217041015625 +27640 0.341094970703125 +27641 0.4224853515625 +27642 0.368011474609375 +27643 0.41912841796875 +27644 0.37249755859375 +27645 0.392333984375 +27646 0.30072021484375 +27647 0.321258544921875 +27648 0.1517333984375 +27649 0.208221435546875 +27650 -0.01470947265625 +27651 0.081695556640625 +27652 -0.1883544921875 +27653 -0.051513671875 +27654 -0.372711181640625 +27655 -0.189971923828125 +27656 -0.51397705078125 +27657 -0.306488037109375 +27658 -0.57177734375 +27659 -0.38006591796875 +27660 -0.53948974609375 +27661 -0.4052734375 +27662 -0.43511962890625 +27663 -0.388275146484375 +27664 -0.2962646484375 +27665 -0.344573974609375 +27666 -0.161102294921875 +27667 -0.290618896484375 +27668 -0.0435791015625 +27669 -0.232574462890625 +27670 0.060394287109375 +27671 -0.169219970703125 +27672 0.13665771484375 +27673 -0.10809326171875 +27674 0.170135498046875 +27675 -0.0577392578125 +27676 0.16552734375 +27677 -0.018218994140625 +27678 0.15728759765625 +27679 0.023529052734375 +27680 0.150787353515625 +27681 0.06732177734375 +27682 0.12200927734375 +27683 0.099761962890625 +27684 0.080108642578125 +27685 0.12255859375 +27686 0.05126953125 +27687 0.14532470703125 +27688 0.062896728515625 +27689 0.17864990234375 +27690 0.09271240234375 +27691 0.211151123046875 +27692 0.092987060546875 +27693 0.2205810546875 +27694 0.07855224609375 +27695 0.21337890625 +27696 0.06427001953125 +27697 0.196563720703125 +27698 0.0347900390625 +27699 0.164093017578125 +27700 -0.01171875 +27701 0.11639404296875 +27702 -0.056060791015625 +27703 0.063812255859375 +27704 -0.055511474609375 +27705 0.027496337890625 +27706 -0.010467529296875 +27707 0.009368896484375 +27708 0.02508544921875 +27709 -0.012664794921875 +27710 0.025665283203125 +27711 -0.048004150390625 +27712 0.017333984375 +27713 -0.08306884765625 +27714 0.00189208984375 +27715 -0.115447998046875 +27716 -0.03173828125 +27717 -0.14892578125 +27718 -0.071502685546875 +27719 -0.17730712890625 +27720 -0.13543701171875 +27721 -0.208343505859375 +27722 -0.219970703125 +27723 -0.24053955078125 +27724 -0.300506591796875 +27725 -0.26336669921875 +27726 -0.376312255859375 +27727 -0.277435302734375 +27728 -0.416107177734375 +27729 -0.269927978515625 +27730 -0.371124267578125 +27731 -0.220489501953125 +27732 -0.242279052734375 +27733 -0.131195068359375 +27734 -0.069732666015625 +27735 -0.02191162109375 +27736 0.125640869140625 +27737 0.09619140625 +27738 0.31268310546875 +27739 0.207489013671875 +27740 0.45501708984375 +27741 0.29425048828125 +27742 0.554779052734375 +27743 0.3563232421875 +27744 0.61065673828125 +27745 0.392364501953125 +27746 0.610931396484375 +27747 0.39666748046875 +27748 0.531463623046875 +27749 0.35833740234375 +27750 0.3883056640625 +27751 0.284912109375 +27752 0.23468017578125 +27753 0.201019287109375 +27754 0.095245361328125 +27755 0.118743896484375 +27756 -0.00396728515625 +27757 0.050994873046875 +27758 -0.04852294921875 +27759 0.005615234375 +27760 -0.055145263671875 +27761 -0.023468017578125 +27762 -0.0758056640625 +27763 -0.05816650390625 +27764 -0.138702392578125 +27765 -0.109832763671875 +27766 -0.209197998046875 +27767 -0.161651611328125 +27768 -0.289031982421875 +27769 -0.213409423828125 +27770 -0.37884521484375 +27771 -0.264617919921875 +27772 -0.456329345703125 +27773 -0.3048095703125 +27774 -0.51641845703125 +27775 -0.33160400390625 +27776 -0.519287109375 +27777 -0.327239990234375 +27778 -0.458251953125 +27779 -0.289154052734375 +27780 -0.384796142578125 +27781 -0.241241455078125 +27782 -0.323699951171875 +27783 -0.195587158203125 +27784 -0.269287109375 +27785 -0.15069580078125 +27786 -0.1951904296875 +27787 -0.095916748046875 +27788 -0.100006103515625 +27789 -0.03179931640625 +27790 -0.01055908203125 +27791 0.02838134765625 +27792 0.1033935546875 +27793 0.09716796875 +27794 0.24908447265625 +27795 0.17694091796875 +27796 0.373199462890625 +27797 0.243072509765625 +27798 0.45806884765625 +27799 0.28717041015625 +27800 0.511474609375 +27801 0.3125 +27802 0.565399169921875 +27803 0.333526611328125 +27804 0.61138916015625 +27805 0.346771240234375 +27806 0.5897216796875 +27807 0.32586669921875 +27808 0.4906005859375 +27809 0.267120361328125 +27810 0.33148193359375 +27811 0.17926025390625 +27812 0.147796630859375 +27813 0.07916259765625 +27814 -0.01873779296875 +27815 -0.013397216796875 +27816 -0.140289306640625 +27817 -0.08489990234375 +27818 -0.191986083984375 +27819 -0.123291015625 +27820 -0.184295654296875 +27821 -0.13250732421875 +27822 -0.161834716796875 +27823 -0.13201904296875 +27824 -0.166595458984375 +27825 -0.1402587890625 +27826 -0.19390869140625 +27827 -0.1549072265625 +27828 -0.22442626953125 +27829 -0.167205810546875 +27830 -0.279754638671875 +27831 -0.18707275390625 +27832 -0.3389892578125 +27833 -0.205474853515625 +27834 -0.3543701171875 +27835 -0.201507568359375 +27836 -0.348175048828125 +27837 -0.18585205078125 +27838 -0.32598876953125 +27839 -0.161773681640625 +27840 -0.2581787109375 +27841 -0.11676025390625 +27842 -0.139801025390625 +27843 -0.049346923828125 +27844 0.014617919921875 +27845 0.03314208984375 +27846 0.144378662109375 +27847 0.102691650390625 +27848 0.221038818359375 +27849 0.145965576171875 +27850 0.27069091796875 +27851 0.174285888671875 +27852 0.294036865234375 +27853 0.187744140625 +27854 0.311767578125 +27855 0.195587158203125 +27856 0.339141845703125 +27857 0.204803466796875 +27858 0.360260009765625 +27859 0.20855712890625 +27860 0.360504150390625 +27861 0.20062255859375 +27862 0.308380126953125 +27863 0.1671142578125 +27864 0.18170166015625 +27865 0.098480224609375 +27866 0.0047607421875 +27867 0.006439208984375 +27868 -0.17559814453125 +27869 -0.087005615234375 +27870 -0.3143310546875 +27871 -0.1607666015625 +27872 -0.36785888671875 +27873 -0.194427490234375 +27874 -0.36248779296875 +27875 -0.199493408203125 +27876 -0.343536376953125 +27877 -0.196258544921875 +27878 -0.3018798828125 +27879 -0.18035888671875 +27880 -0.231414794921875 +27881 -0.148895263671875 +27882 -0.117645263671875 +27883 -0.095306396484375 +27884 0.007049560546875 +27885 -0.034515380859375 +27886 0.087982177734375 +27887 0.008270263671875 +27888 0.13946533203125 +27889 0.0391845703125 +27890 0.17425537109375 +27891 0.0635986328125 +27892 0.188201904296875 +27893 0.079132080078125 +27894 0.171234130859375 +27895 0.080657958984375 +27896 0.118438720703125 +27897 0.065460205078125 +27898 0.05706787109375 +27899 0.045501708984375 +27900 -0.010711669921875 +27901 0.021331787109375 +27902 -0.0914306640625 +27903 -0.0103759765625 +27904 -0.162322998046875 +27905 -0.03985595703125 +27906 -0.194549560546875 +27907 -0.053924560546875 +27908 -0.1492919921875 +27909 -0.033355712890625 +27910 -0.02166748046875 +27911 0.02471923828125 +27912 0.124053955078125 +27913 0.08953857421875 +27914 0.211151123046875 +27915 0.124237060546875 +27916 0.240447998046875 +27917 0.12982177734375 +27918 0.242218017578125 +27919 0.121612548828125 +27920 0.2257080078125 +27921 0.104736328125 +27922 0.194366455078125 +27923 0.081329345703125 +27924 0.115509033203125 +27925 0.035858154296875 +27926 0.0128173828125 +27927 -0.01971435546875 +27928 -0.053802490234375 +27929 -0.05596923828125 +27930 -0.110626220703125 +27931 -0.0855712890625 +27932 -0.199493408203125 +27933 -0.128936767578125 +27934 -0.29437255859375 +27935 -0.1734619140625 +27936 -0.33221435546875 +27937 -0.18853759765625 +27938 -0.27972412109375 +27939 -0.158172607421875 +27940 -0.185333251953125 +27941 -0.106292724609375 +27942 -0.128204345703125 +27943 -0.071868896484375 +27944 -0.115692138671875 +27945 -0.058868408203125 +27946 -0.116455078125 +27947 -0.0523681640625 +27948 -0.105926513671875 +27949 -0.040802001953125 +27950 -0.053955078125 +27951 -0.009765625 +27952 0.048797607421875 +27953 0.04498291015625 +27954 0.157318115234375 +27955 0.10125732421875 +27956 0.212005615234375 +27957 0.129852294921875 +27958 0.218475341796875 +27959 0.133392333984375 +27960 0.23724365234375 +27961 0.141448974609375 +27962 0.30535888671875 +27963 0.172210693359375 +27964 0.38128662109375 +27965 0.20556640625 +27966 0.404449462890625 +27967 0.212188720703125 +27968 0.3944091796875 +27969 0.201934814453125 +27970 0.3885498046875 +27971 0.193359375 +27972 0.362640380859375 +27973 0.174957275390625 +27974 0.27362060546875 +27975 0.12603759765625 +27976 0.11712646484375 +27977 0.04473876953125 +27978 -0.054901123046875 +27979 -0.04327392578125 +27980 -0.19085693359375 +27981 -0.112640380859375 +27982 -0.28570556640625 +27983 -0.1607666015625 +27984 -0.339263916015625 +27985 -0.187530517578125 +27986 -0.3775634765625 +27987 -0.20562744140625 +27988 -0.445709228515625 +27989 -0.23712158203125 +27990 -0.535064697265625 +27991 -0.277923583984375 +27992 -0.629058837890625 +27993 -0.320159912109375 +27994 -0.697601318359375 +27995 -0.349334716796875 +27996 -0.70391845703125 +27997 -0.347747802734375 +27998 -0.6424560546875 +27999 -0.31298828125 +28000 -0.491241455078125 +28001 -0.234588623046875 +28002 -0.265716552734375 +28003 -0.120330810546875 +28004 -0.023712158203125 +28005 0.001312255859375 +28006 0.201751708984375 +28007 0.11407470703125 +28008 0.375823974609375 +28009 0.200836181640625 +28010 0.485076904296875 +28011 0.254974365234375 +28012 0.56884765625 +28013 0.295654296875 +28014 0.634765625 +28015 0.326629638671875 +28016 0.63763427734375 +28017 0.325958251953125 +28018 0.5660400390625 +28019 0.2882080078125 +28020 0.4720458984375 +28021 0.23895263671875 +28022 0.40692138671875 +28023 0.203399658203125 +28024 0.3778076171875 +28025 0.18524169921875 +28026 0.376953125 +28027 0.180938720703125 +28028 0.371978759765625 +28029 0.174896240234375 +28030 0.313140869140625 +28031 0.143035888671875 +28032 0.184417724609375 +28033 0.07769775390625 +28034 0.011199951171875 +28035 -0.00860595703125 +28036 -0.171051025390625 +28037 -0.09844970703125 +28038 -0.33740234375 +28039 -0.179656982421875 +28040 -0.47198486328125 +28041 -0.244537353515625 +28042 -0.560394287109375 +28043 -0.2861328125 +28044 -0.58056640625 +28045 -0.293792724609375 +28046 -0.54754638671875 +28047 -0.27496337890625 +28048 -0.508575439453125 +28049 -0.252899169921875 +28050 -0.459503173828125 +28051 -0.2257080078125 +28052 -0.394378662109375 +28053 -0.190704345703125 +28054 -0.35260009765625 +28055 -0.167266845703125 +28056 -0.31170654296875 +28057 -0.14459228515625 +28058 -0.197418212890625 +28059 -0.086578369140625 +28060 -0.007965087890625 +28061 0.007537841796875 +28062 0.207489013671875 +28063 0.113677978515625 +28064 0.409210205078125 +28065 0.212371826171875 +28066 0.57208251953125 +28067 0.291412353515625 +28068 0.66595458984375 +28069 0.33612060546875 +28070 0.65875244140625 +28071 0.3309326171875 +28072 0.56744384765625 +28073 0.284210205078125 +28074 0.431396484375 +28075 0.21533203125 +28076 0.29443359375 +28077 0.145843505859375 +28078 0.182464599609375 +28079 0.0885009765625 +28080 0.06365966796875 +28081 0.027923583984375 +28082 -0.075958251953125 +28083 -0.04254150390625 +28084 -0.189422607421875 +28085 -0.099853515625 +28086 -0.271942138671875 +28087 -0.141571044921875 +28088 -0.342529296875 +28089 -0.176910400390625 +28090 -0.364166259765625 +28091 -0.18780517578125 +28092 -0.327239990234375 +28093 -0.169586181640625 +28094 -0.2769775390625 +28095 -0.144317626953125 +28096 -0.253692626953125 +28097 -0.1317138671875 +28098 -0.24365234375 +28099 -0.12518310546875 +28100 -0.1983642578125 +28101 -0.101165771484375 +28102 -0.116241455078125 +28103 -0.058990478515625 +28104 -0.036834716796875 +28105 -0.018035888671875 +28106 0.034881591796875 +28107 0.01910400390625 +28108 0.09124755859375 +28109 0.048583984375 +28110 0.10888671875 +28111 0.05889892578125 +28112 0.125518798828125 +28113 0.068328857421875 +28114 0.15771484375 +28115 0.084930419921875 +28116 0.17828369140625 +28117 0.09539794921875 +28118 0.17108154296875 +28119 0.09185791015625 +28120 0.129974365234375 +28121 0.071319580078125 +28122 0.082427978515625 +28123 0.047210693359375 +28124 0.027679443359375 +28125 0.01922607421875 +28126 -0.065643310546875 +28127 -0.027801513671875 +28128 -0.15936279296875 +28129 -0.075164794921875 +28130 -0.21307373046875 +28131 -0.10308837890625 +28132 -0.234649658203125 +28133 -0.11529541015625 +28134 -0.2001953125 +28135 -0.10003662109375 +28136 -0.119171142578125 +28137 -0.061859130859375 +28138 -0.024749755859375 +28139 -0.01690673828125 +28140 0.085784912109375 +28141 0.03619384765625 +28142 0.178131103515625 +28143 0.080718994140625 +28144 0.215576171875 +28145 0.098785400390625 +28146 0.211456298828125 +28147 0.096923828125 +28148 0.17523193359375 +28149 0.079742431640625 +28150 0.128753662109375 +28151 0.057861328125 +28152 0.1019287109375 +28153 0.04583740234375 +28154 0.0743408203125 +28155 0.033660888671875 +28156 0.04327392578125 +28157 0.0198974609375 +28158 0.038177490234375 +28159 0.018829345703125 +28160 0.076263427734375 +28161 0.039337158203125 +28162 0.14105224609375 +28163 0.073760986328125 +28164 0.186431884765625 +28165 0.0986328125 +28166 0.188812255859375 +28167 0.1014404296875 +28168 0.1390380859375 +28169 0.07720947265625 +28170 0.041778564453125 +28171 0.0281982421875 +28172 -0.079437255859375 +28173 -0.03350830078125 +28174 -0.219390869140625 +28175 -0.1053466796875 +28176 -0.367828369140625 +28177 -0.182037353515625 +28178 -0.494873046875 +28179 -0.24810791015625 +28180 -0.556243896484375 +28181 -0.280548095703125 +28182 -0.508697509765625 +28183 -0.256866455078125 +28184 -0.3756103515625 +28185 -0.189117431640625 +28186 -0.218902587890625 +28187 -0.109405517578125 +28188 -0.063751220703125 +28189 -0.03070068359375 +28190 0.091552734375 +28191 0.047943115234375 +28192 0.23602294921875 +28193 0.1209716796875 +28194 0.342987060546875 +28195 0.17462158203125 +28196 0.39520263671875 +28197 0.200042724609375 +28198 0.389373779296875 +28199 0.19561767578125 +28200 0.324249267578125 +28201 0.1607666015625 +28202 0.224090576171875 +28203 0.108154296875 +28204 0.124267578125 +28205 0.05621337890625 +28206 0.037078857421875 +28207 0.01129150390625 +28208 -0.010101318359375 +28209 -0.01239013671875 +28210 -0.019439697265625 +28211 -0.016021728515625 +28212 -0.022796630859375 +28213 -0.0162353515625 +28214 -0.001556396484375 +28215 -0.00341796875 +28216 0.056304931640625 +28217 0.028533935546875 +28218 0.106719970703125 +28219 0.05657958984375 +28220 0.096893310546875 +28221 0.053192138671875 +28222 0.042694091796875 +28223 0.026519775390625 +28224 -0.018035888671875 +28225 -0.003814697265625 +28226 -0.07586669921875 +28227 -0.032958984375 +28228 -0.11944580078125 +28229 -0.0550537109375 +28230 -0.15972900390625 +28231 -0.075836181640625 +28232 -0.202606201171875 +28233 -0.098358154296875 +28234 -0.24859619140625 +28235 -0.12286376953125 +28236 -0.30517578125 +28237 -0.153167724609375 +28238 -0.36212158203125 +28239 -0.183929443359375 +28240 -0.39141845703125 +28241 -0.20050048828125 +28242 -0.35528564453125 +28243 -0.183135986328125 +28244 -0.249969482421875 +28245 -0.129852294921875 +28246 -0.092864990234375 +28247 -0.049591064453125 +28248 0.08905029296875 +28249 0.043670654296875 +28250 0.2352294921875 +28251 0.1185302734375 +28252 0.318817138671875 +28253 0.16107177734375 +28254 0.358642578125 +28255 0.181121826171875 +28256 0.347747802734375 +28257 0.17510986328125 +28258 0.28564453125 +28259 0.142791748046875 +28260 0.223175048828125 +28261 0.110595703125 +28262 0.196746826171875 +28263 0.097442626953125 +28264 0.179840087890625 +28265 0.089508056640625 +28266 0.155548095703125 +28267 0.07794189453125 +28268 0.151214599609375 +28269 0.076873779296875 +28270 0.156951904296875 +28271 0.08111572265625 +28272 0.13177490234375 +28273 0.069244384765625 +28274 0.100799560546875 +28275 0.05426025390625 +28276 0.087127685546875 +28277 0.04815673828125 +28278 0.05487060546875 +28279 0.0322265625 +28280 -0.009002685546875 +28281 -0.0003662109375 +28282 -0.10400390625 +28283 -0.04937744140625 +28284 -0.229400634765625 +28285 -0.11444091796875 +28286 -0.35552978515625 +28287 -0.180145263671875 +28288 -0.441925048828125 +28289 -0.22540283203125 +28290 -0.473846435546875 +28291 -0.2425537109375 +28292 -0.464813232421875 +28293 -0.238555908203125 +28294 -0.419097900390625 +28295 -0.215606689453125 +28296 -0.334320068359375 +28297 -0.17242431640625 +28298 -0.227935791015625 +28299 -0.118011474609375 +28300 -0.12347412109375 +28301 -0.064605712890625 +28302 -0.02764892578125 +28303 -0.015655517578125 +28304 0.077667236328125 +28305 0.038330078125 +28306 0.2132568359375 +28307 0.108184814453125 +28308 0.38885498046875 +28309 0.199005126953125 +28310 0.582794189453125 +28311 0.299560546875 +28312 0.734039306640625 +28313 0.37811279296875 +28314 0.800140380859375 +28315 0.41259765625 +28316 0.7783203125 +28317 0.401519775390625 +28318 0.6651611328125 +28319 0.343109130859375 +28320 0.45965576171875 +28321 0.23681640625 +28322 0.199188232421875 +28323 0.10205078125 +28324 -0.050689697265625 +28325 -0.027099609375 +28326 -0.23297119140625 +28327 -0.121063232421875 +28328 -0.33013916015625 +28329 -0.1707763671875 +28330 -0.368408203125 +28331 -0.18994140625 +28332 -0.378936767578125 +28333 -0.19476318359375 +28334 -0.376983642578125 +28335 -0.1932373046875 +28336 -0.37969970703125 +28337 -0.194305419921875 +28338 -0.391510009765625 +28339 -0.20025634765625 +28340 -0.385345458984375 +28341 -0.197052001953125 +28342 -0.3419189453125 +28343 -0.17462158203125 +28344 -0.28289794921875 +28345 -0.14422607421875 +28346 -0.251617431640625 +28347 -0.128387451171875 +28348 -0.266143798828125 +28349 -0.136474609375 +28350 -0.273345947265625 +28351 -0.140838623046875 +28352 -0.216796875 +28353 -0.112091064453125 +28354 -0.128265380859375 +28355 -0.06671142578125 +28356 -0.068145751953125 +28357 -0.036041259765625 +28358 -0.0430908203125 +28359 -0.02349853515625 +28360 -0.024444580078125 +28361 -0.014190673828125 +28362 0.020721435546875 +28363 0.009002685546875 +28364 0.124481201171875 +28365 0.062744140625 +28366 0.25787353515625 +28367 0.131988525390625 +28368 0.379119873046875 +28369 0.19500732421875 +28370 0.47991943359375 +28371 0.247528076171875 +28372 0.5281982421875 +28373 0.272857666015625 +28374 0.511138916015625 +28375 0.2642822265625 +28376 0.456207275390625 +28377 0.236083984375 +28378 0.407470703125 +28379 0.211151123046875 +28380 0.383758544921875 +28381 0.19927978515625 +28382 0.35687255859375 +28383 0.185760498046875 +28384 0.31182861328125 +28385 0.16278076171875 +28386 0.250885009765625 +28387 0.1314697265625 +28388 0.1654052734375 +28389 0.087310791015625 +28390 0.035247802734375 +28391 0.01983642578125 +28392 -0.142059326171875 +28393 -0.072235107421875 +28394 -0.33563232421875 +28395 -0.1728515625 +28396 -0.5345458984375 +28397 -0.27630615234375 +28398 -0.72186279296875 +28399 -0.373779296875 +28400 -0.836669921875 +28401 -0.43359375 +28402 -0.8326416015625 +28403 -0.431671142578125 +28404 -0.7296142578125 +28405 -0.378326416015625 +28406 -0.582550048828125 +28407 -0.3021240234375 +28408 -0.440093994140625 +28409 -0.22833251953125 +28410 -0.324310302734375 +28411 -0.168426513671875 +28412 -0.20147705078125 +28413 -0.1048583984375 +28414 -0.044647216796875 +28415 -0.023590087890625 +28416 0.103973388671875 +28417 0.052886962890625 +28418 0.202392578125 +28419 0.102081298828125 +28420 0.264495849609375 +28421 0.131866455078125 +28422 0.338897705078125 +28423 0.169342041015625 +28424 0.443817138671875 +28425 0.2247314453125 +28426 0.545074462890625 +28427 0.279296875 +28428 0.6173095703125 +28429 0.319061279296875 +28430 0.6524658203125 +28431 0.33953857421875 +28432 0.66339111328125 +28433 0.347747802734375 +28434 0.6561279296875 +28435 0.346893310546875 +28436 0.606781005859375 +28437 0.32354736328125 +28438 0.501190185546875 +28439 0.2696533203125 +28440 0.352783203125 +28441 0.1923828125 +28442 0.176544189453125 +28443 0.099761962890625 +28444 -0.034820556640625 +28445 -0.012481689453125 +28446 -0.258209228515625 +28447 -0.1318359375 +28448 -0.44244384765625 +28449 -0.230255126953125 +28450 -0.5753173828125 +28451 -0.301116943359375 +28452 -0.65203857421875 +28453 -0.3419189453125 +28454 -0.641632080078125 +28455 -0.335662841796875 +28456 -0.562164306640625 +28457 -0.29229736328125 +28458 -0.458038330078125 +28459 -0.236297607421875 +28460 -0.350555419921875 +28461 -0.179290771484375 +28462 -0.260528564453125 +28463 -0.132598876953125 +28464 -0.192108154296875 +28465 -0.098358154296875 +28466 -0.141937255859375 +28467 -0.07452392578125 +28468 -0.1021728515625 +28469 -0.0565185546875 +28470 -0.062896728515625 +28471 -0.038665771484375 +28472 -0.011932373046875 +28473 -0.0140380859375 +28474 0.062835693359375 +28475 0.02423095703125 +28476 0.148712158203125 +28477 0.069305419921875 +28478 0.241729736328125 +28479 0.11907958984375 +28480 0.34912109375 +28481 0.177642822265625 +28482 0.457305908203125 +28483 0.23748779296875 +28484 0.54388427734375 +28485 0.28619384765625 +28486 0.5728759765625 +28487 0.303863525390625 +28488 0.506591796875 +28489 0.269561767578125 +28490 0.351226806640625 +28491 0.18658447265625 +28492 0.146514892578125 +28493 0.076690673828125 +28494 -0.05523681640625 +28495 -0.031402587890625 +28496 -0.21624755859375 +28497 -0.1170654296875 +28498 -0.334930419921875 +28499 -0.1795654296875 +28500 -0.402984619140625 +28501 -0.2144775390625 +28502 -0.4412841796875 +28503 -0.23345947265625 +28504 -0.49578857421875 +28505 -0.261993408203125 +28506 -0.5601806640625 +28507 -0.296630859375 +28508 -0.600738525390625 +28509 -0.318817138671875 +28510 -0.584228515625 +28511 -0.310211181640625 +28512 -0.47930908203125 +28513 -0.253448486328125 +28514 -0.27935791015625 +28515 -0.144775390625 +28516 -0.0089111328125 +28517 0.002349853515625 +28518 0.268798828125 +28519 0.15313720703125 +28520 0.482818603515625 +28521 0.268585205078125 +28522 0.60369873046875 +28523 0.33258056640625 +28524 0.650421142578125 +28525 0.355712890625 +28526 0.66400146484375 +28527 0.360809326171875 +28528 0.6414794921875 +28529 0.346343994140625 +28530 0.572540283203125 +28531 0.306732177734375 +28532 0.498138427734375 +28533 0.2646484375 +28534 0.439453125 +28535 0.231842041015625 +28536 0.375518798828125 +28537 0.19671630859375 +28538 0.274505615234375 +28539 0.141693115234375 +28540 0.1087646484375 +28541 0.05145263671875 +28542 -0.099395751953125 +28543 -0.061767578125 +28544 -0.3182373046875 +28545 -0.1805419921875 +28546 -0.5489501953125 +28547 -0.3056640625 +28548 -0.7738037109375 +28549 -0.42742919921875 +28550 -0.86383056640625 +28551 -0.516754150390625 +28552 -0.870391845703125 +28553 -0.555419921875 +28554 -0.86895751953125 +28555 -0.553314208984375 +28556 -0.861053466796875 +28557 -0.517791748046875 +28558 -0.765869140625 +28559 -0.439361572265625 +28560 -0.5301513671875 +28561 -0.311859130859375 +28562 -0.214691162109375 +28563 -0.13922119140625 +28564 0.137359619140625 +28565 0.054779052734375 +28566 0.474822998046875 +28567 0.24188232421875 +28568 0.76239013671875 +28569 0.402496337890625 +28570 0.867462158203125 +28571 0.521820068359375 +28572 0.870361328125 +28573 0.600189208984375 +28574 0.86480712890625 +28575 0.63134765625 +28576 0.831817626953125 +28577 0.618316650390625 +28578 0.677581787109375 +28579 0.574676513671875 +28580 0.495880126953125 +28581 0.503753662109375 +28582 0.30767822265625 +28583 0.415863037109375 +28584 0.116180419921875 +28585 0.312286376953125 +28586 -0.110748291015625 +28587 0.175567626953125 +28588 -0.381805419921875 +28589 0.001922607421875 +28590 -0.6572265625 +28591 -0.185028076171875 +28592 -0.857421875 +28593 -0.352203369140625 +28594 -0.870391845703125 +28595 -0.475982666015625 +28596 -0.870391845703125 +28597 -0.552490234375 +28598 -0.86444091796875 +28599 -0.596649169921875 +28600 -0.85723876953125 +28601 -0.62823486328125 +28602 -0.790008544921875 +28603 -0.63720703125 +28604 -0.62847900390625 +28605 -0.59368896484375 +28606 -0.3956298828125 +28607 -0.496002197265625 +28608 -0.126708984375 +28609 -0.36236572265625 +28610 0.150115966796875 +28611 -0.207977294921875 +28612 0.424041748046875 +28613 -0.03936767578125 +28614 0.670623779296875 +28615 0.128570556640625 +28616 0.854522705078125 +28617 0.2744140625 +28618 0.866485595703125 +28619 0.388427734375 +28620 0.86920166015625 +28621 0.46209716796875 +28622 0.8653564453125 +28623 0.505462646484375 +28624 0.857147216796875 +28625 0.5260009765625 +28626 0.766845703125 +28627 0.522186279296875 +28628 0.628509521484375 +28629 0.49688720703125 +28630 0.462127685546875 +28631 0.446441650390625 +28632 0.297210693359375 +28633 0.38519287109375 +28634 0.14862060546875 +28635 0.32000732421875 +28636 -0.00537109375 +28637 0.238372802734375 +28638 -0.15753173828125 +28639 0.144500732421875 +28640 -0.31304931640625 +28641 0.03643798828125 +28642 -0.48876953125 +28643 -0.093536376953125 +28644 -0.6416015625 +28645 -0.219512939453125 +28646 -0.751373291015625 +28647 -0.32781982421875 +28648 -0.84619140625 +28649 -0.43121337890625 +28650 -0.861297607421875 +28651 -0.521636962890625 +28652 -0.863250732421875 +28653 -0.580780029296875 +28654 -0.856597900390625 +28655 -0.591278076171875 +28656 -0.7498779296875 +28657 -0.559906005859375 +28658 -0.624542236328125 +28659 -0.5186767578125 +28660 -0.47808837890625 +28661 -0.45550537109375 +28662 -0.253387451171875 +28663 -0.338165283203125 +28664 0.003692626953125 +28665 -0.191925048828125 +28666 0.2257080078125 +28667 -0.0545654296875 +28668 0.427154541015625 +28669 0.080780029296875 +28670 0.643218994140625 +28671 0.231964111328125 +28672 0.855926513671875 +28673 0.39410400390625 +28674 0.870361328125 +28675 0.53521728515625 +28676 0.870361328125 +28677 0.627197265625 +28678 0.862762451171875 +28679 0.674224853515625 +28680 0.79669189453125 +28681 0.674468994140625 +28682 0.595794677734375 +28683 0.622161865234375 +28684 0.362152099609375 +28685 0.534088134765625 +28686 0.1270751953125 +28687 0.42626953125 +28688 -0.086944580078125 +28689 0.310699462890625 +28690 -0.2784423828125 +28691 0.188232421875 +28692 -0.484832763671875 +28693 0.0382080078125 +28694 -0.729583740234375 +28695 -0.15093994140625 +28696 -0.86688232421875 +28697 -0.3499755859375 +28698 -0.870391845703125 +28699 -0.522186279296875 +28700 -0.86859130859375 +28701 -0.664886474609375 +28702 -0.86279296875 +28703 -0.777008056640625 +28704 -0.817962646484375 +28705 -0.837615966796875 +28706 -0.6116943359375 +28707 -0.820220947265625 +28708 -0.3128662109375 +28709 -0.7205810546875 +28710 0.039398193359375 +28711 -0.558258056640625 +28712 0.422821044921875 +28713 -0.34478759765625 +28714 0.805145263671875 +28715 -0.099395751953125 +28716 0.870361328125 +28717 0.138336181640625 +28718 0.870361328125 +28719 0.3353271484375 +28720 0.860015869140625 +28721 0.48492431640625 +28722 0.727935791015625 +28723 0.582763671875 +28724 0.48114013671875 +28725 0.625640869140625 +28726 0.2059326171875 +28727 0.62774658203125 +28728 -0.06103515625 +28729 0.602294921875 +28730 -0.29913330078125 +28731 0.555145263671875 +28732 -0.516204833984375 +28733 0.477813720703125 +28734 -0.7252197265625 +28735 0.361297607421875 +28736 -0.85980224609375 +28737 0.2200927734375 +28738 -0.870391845703125 +28739 0.07427978515625 +28740 -0.870391845703125 +28741 -0.058837890625 +28742 -0.858062744140625 +28743 -0.15081787109375 +28744 -0.673004150390625 +28745 -0.19915771484375 +28746 -0.42694091796875 +28747 -0.234405517578125 +28748 -0.2100830078125 +28749 -0.28240966796875 +28750 -0.0362548828125 +28751 -0.341796875 +28752 0.10943603515625 +28753 -0.3955078125 +28754 0.23516845703125 +28755 -0.43182373046875 +28756 0.373687744140625 +28757 -0.426483154296875 +28758 0.517791748046875 +28759 -0.38055419921875 +28760 0.602783203125 +28761 -0.330780029296875 +28762 0.635711669921875 +28763 -0.274169921875 +28764 0.655181884765625 +28765 -0.1912841796875 +28766 0.65948486328125 +28767 -0.0880126953125 +28768 0.651275634765625 +28769 0.030853271484375 +28770 0.61846923828125 +28771 0.15081787109375 +28772 0.53753662109375 +28773 0.2501220703125 +28774 0.404144287109375 +28775 0.31805419921875 +28776 0.22186279296875 +28777 0.348785400390625 +28778 0.003997802734375 +28779 0.342864990234375 +28780 -0.22100830078125 +28781 0.31072998046875 +28782 -0.42449951171875 +28783 0.264312744140625 +28784 -0.579833984375 +28785 0.21600341796875 +28786 -0.641876220703125 +28787 0.190704345703125 +28788 -0.6177978515625 +28789 0.184539794921875 +28790 -0.575531005859375 +28791 0.159820556640625 +28792 -0.526336669921875 +28793 0.113525390625 +28794 -0.42645263671875 +28795 0.076019287109375 +28796 -0.2581787109375 +28797 0.063446044921875 +28798 -0.068695068359375 +28799 0.05474853515625 +28800 0.09222412109375 +28801 0.02764892578125 +28802 0.232147216796875 +28803 -0.00677490234375 +28804 0.3509521484375 +28805 -0.042388916015625 +28806 0.410064697265625 +28807 -0.0963134765625 +28808 0.372955322265625 +28809 -0.185577392578125 +28810 0.2554931640625 +28811 -0.29779052734375 +28812 0.10711669921875 +28813 -0.40240478515625 +28814 -0.052886962890625 +28815 -0.4879150390625 +28816 -0.186279296875 +28817 -0.533172607421875 +28818 -0.23291015625 +28819 -0.50555419921875 +28820 -0.209442138671875 +28821 -0.418426513671875 +28822 -0.174163818359375 +28823 -0.31036376953125 +28824 -0.126739501953125 +28825 -0.18634033203125 +28826 -0.048126220703125 +28827 -0.040740966796875 +28828 0.0426025390625 +28829 0.1097412109375 +28830 0.10748291015625 +28831 0.237701416015625 +28832 0.1409912109375 +28833 0.335205078125 +28834 0.19708251953125 +28835 0.42987060546875 +28836 0.273651123046875 +28837 0.517547607421875 +28838 0.31768798828125 +28839 0.56549072265625 +28840 0.341094970703125 +28841 0.580047607421875 +28842 0.368011474609375 +28843 0.575897216796875 +28844 0.37249755859375 +28845 0.539520263671875 +28846 0.30072021484375 +28847 0.442169189453125 +28848 0.1517333984375 +28849 0.286773681640625 +28850 -0.01470947265625 +28851 0.1123046875 +28852 -0.1883544921875 +28853 -0.070709228515625 +28854 -0.372711181640625 +28855 -0.259765625 +28856 -0.51397705078125 +28857 -0.419036865234375 +28858 -0.57177734375 +28859 -0.520843505859375 +28860 -0.53948974609375 +28861 -0.557861328125 +28862 -0.43511962890625 +28863 -0.537933349609375 +28864 -0.2962646484375 +28865 -0.481231689453125 +28866 -0.161102294921875 +28867 -0.4091796875 +28868 -0.0435791015625 +28869 -0.33001708984375 +28870 0.060394287109375 +28871 -0.242431640625 +28872 0.13665771484375 +28873 -0.156646728515625 +28874 0.170135498046875 +28875 -0.0841064453125 +28876 0.16552734375 +28877 -0.025299072265625 +28878 0.15728759765625 +28879 0.036285400390625 +28880 0.150787353515625 +28881 0.100006103515625 +28882 0.12200927734375 +28883 0.148101806640625 +28884 0.080108642578125 +28885 0.182464599609375 +28886 0.05126953125 +28887 0.21539306640625 +28888 0.062896728515625 +28889 0.26043701171875 +28890 0.09271240234375 +28891 0.30279541015625 +28892 0.092987060546875 +28893 0.313629150390625 +28894 0.07855224609375 +28895 0.301422119140625 +28896 0.06427001953125 +28897 0.2755126953125 +28898 0.0347900390625 +28899 0.228240966796875 +28900 -0.01171875 +28901 0.160552978515625 +28902 -0.056060791015625 +28903 0.086151123046875 +28904 -0.055511474609375 +28905 0.032867431640625 +28906 -0.010467529296875 +28907 0.003570556640625 +28908 0.02508544921875 +28909 -0.0301513671875 +28910 0.025665283203125 +28911 -0.08026123046875 +28912 0.017333984375 +28913 -0.12890625 +28914 0.00189208984375 +28915 -0.1728515625 +28916 -0.03173828125 +28917 -0.2169189453125 +28918 -0.071502685546875 +28919 -0.2530517578125 +28920 -0.13543701171875 +28921 -0.291412353515625 +28922 -0.219970703125 +28923 -0.3302001953125 +28924 -0.300506591796875 +28925 -0.355926513671875 +28926 -0.376312255859375 +28927 -0.36962890625 +28928 -0.416107177734375 +28929 -0.354888916015625 +28930 -0.371124267578125 +28931 -0.28533935546875 +28932 -0.242279052734375 +28933 -0.164031982421875 +28934 -0.069732666015625 +28935 -0.017242431640625 +28936 0.125640869140625 +28937 0.14031982421875 +28938 0.31268310546875 +28939 0.28802490234375 +28940 0.45501708984375 +28941 0.402374267578125 +28942 0.554779052734375 +28943 0.48333740234375 +28944 0.61065673828125 +28945 0.52923583984375 +28946 0.610931396484375 +28947 0.53265380859375 +28948 0.531463623046875 +28949 0.479217529296875 +28950 0.3883056640625 +28951 0.37908935546875 +28952 0.23468017578125 +28953 0.26519775390625 +28954 0.095245361328125 +28955 0.153778076171875 +28956 -0.00396728515625 +28957 0.06207275390625 +28958 -0.04852294921875 +28959 0.000579833984375 +28960 -0.055145263671875 +28961 -0.0386962890625 +28962 -0.0758056640625 +28963 -0.085052490234375 +28964 -0.138702392578125 +28965 -0.153594970703125 +28966 -0.209197998046875 +28967 -0.221954345703125 +28968 -0.289031982421875 +28969 -0.289886474609375 +28970 -0.37884521484375 +28971 -0.356903076171875 +28972 -0.456329345703125 +28973 -0.409027099609375 +28974 -0.51641845703125 +28975 -0.44317626953125 +28976 -0.519287109375 +28977 -0.435791015625 +28978 -0.458251953125 +28979 -0.383544921875 +28980 -0.384796142578125 +28981 -0.318359375 +28982 -0.323699951171875 +28983 -0.25640869140625 +28984 -0.269287109375 +28985 -0.19580078125 +28986 -0.1951904296875 +28987 -0.122314453125 +28988 -0.100006103515625 +28989 -0.036712646484375 +28990 -0.01055908203125 +28991 0.0433349609375 +28992 0.1033935546875 +28993 0.134613037109375 +28994 0.24908447265625 +28995 0.240325927734375 +28996 0.373199462890625 +28997 0.327606201171875 +28998 0.45806884765625 +28999 0.385284423828125 +29000 0.511474609375 +29001 0.4178466796875 +29002 0.565399169921875 +29003 0.444671630859375 +29004 0.61138916015625 +29005 0.461151123046875 +29006 0.5897216796875 +29007 0.432220458984375 +29008 0.4906005859375 +29009 0.352996826171875 +29010 0.33148193359375 +29011 0.23516845703125 +29012 0.147796630859375 +29013 0.101226806640625 +29014 -0.01873779296875 +29015 -0.022430419921875 +29016 -0.140289306640625 +29017 -0.117767333984375 +29018 -0.191986083984375 +29019 -0.168701171875 +29020 -0.184295654296875 +29021 -0.18048095703125 +29022 -0.161834716796875 +29023 -0.179107666015625 +29024 -0.166595458984375 +29025 -0.189239501953125 +29026 -0.19390869140625 +29027 -0.207794189453125 +29028 -0.22442626953125 +29029 -0.22320556640625 +29030 -0.279754638671875 +29031 -0.24871826171875 +29032 -0.3389892578125 +29033 -0.272369384765625 +29034 -0.3543701171875 +29035 -0.26629638671875 +29036 -0.348175048828125 +29037 -0.244781494140625 +29038 -0.32598876953125 +29039 -0.212188720703125 +29040 -0.2581787109375 +29041 -0.151885986328125 +29042 -0.139801025390625 +29043 -0.06195068359375 +29044 0.014617919921875 +29045 0.047882080078125 +29046 0.144378662109375 +29047 0.1402587890625 +29048 0.221038818359375 +29049 0.197418212890625 +29050 0.27069091796875 +29051 0.234527587890625 +29052 0.294036865234375 +29053 0.251739501953125 +29054 0.311767578125 +29055 0.261383056640625 +29056 0.339141845703125 +29057 0.272857666015625 +29058 0.360260009765625 +29059 0.277191162109375 +29060 0.360504150390625 +29061 0.266143798828125 +29062 0.308380126953125 +29063 0.22088623046875 +29064 0.18170166015625 +29065 0.12847900390625 +29066 0.0047607421875 +29067 0.00469970703125 +29068 -0.17559814453125 +29069 -0.120819091796875 +29070 -0.3143310546875 +29071 -0.2196044921875 +29072 -0.36785888671875 +29073 -0.26409912109375 +29074 -0.36248779296875 +29075 -0.269927978515625 +29076 -0.343536376953125 +29077 -0.264617919921875 +29078 -0.3018798828125 +29079 -0.242279052734375 +29080 -0.231414794921875 +29081 -0.19903564453125 +29082 -0.117645263671875 +29083 -0.12603759765625 +29084 0.007049560546875 +29085 -0.043487548828125 +29086 0.087982177734375 +29087 0.0145263671875 +29088 0.13946533203125 +29089 0.056304931640625 +29090 0.17425537109375 +29091 0.089141845703125 +29092 0.188201904296875 +29093 0.10980224609375 +29094 0.171234130859375 +29095 0.11138916015625 +29096 0.118438720703125 +29097 0.090240478515625 +29098 0.05706787109375 +29099 0.06256103515625 +29100 -0.010711669921875 +29101 0.02911376953125 +29102 -0.0914306640625 +29103 -0.01446533203125 +29104 -0.162322998046875 +29105 -0.054412841796875 +29106 -0.194549560546875 +29107 -0.073150634765625 +29108 -0.1492919921875 +29109 -0.0467529296875 +29110 -0.02166748046875 +29111 0.0279541015625 +29112 0.124053955078125 +29113 0.1116943359375 +29114 0.211151123046875 +29115 0.157562255859375 +29116 0.240447998046875 +29117 0.16656494140625 +29118 0.242218017578125 +29119 0.1578369140625 +29120 0.2257080078125 +29121 0.137664794921875 +29122 0.194366455078125 +29123 0.108734130859375 +29124 0.115509033203125 +29125 0.0513916015625 +29126 0.0128173828125 +29127 -0.019256591796875 +29128 -0.053802490234375 +29129 -0.06597900390625 +29130 -0.110626220703125 +29131 -0.104705810546875 +29132 -0.199493408203125 +29133 -0.161041259765625 +29134 -0.29437255859375 +29135 -0.218963623046875 +29136 -0.33221435546875 +29137 -0.239715576171875 +29138 -0.27972412109375 +29139 -0.2030029296875 +29140 -0.185333251953125 +29141 -0.138916015625 +29142 -0.128204345703125 +29143 -0.0965576171875 +29144 -0.115692138671875 +29145 -0.08087158203125 +29146 -0.116455078125 +29147 -0.07305908203125 +29148 -0.105926513671875 +29149 -0.0584716796875 +29150 -0.053955078125 +29151 -0.018951416015625 +29152 0.048797607421875 +29153 0.05084228515625 +29154 0.157318115234375 +29155 0.122894287109375 +29156 0.212005615234375 +29157 0.16021728515625 +29158 0.218475341796875 +29159 0.166107177734375 +29160 0.23724365234375 +29161 0.17779541015625 +29162 0.30535888671875 +29163 0.218170166015625 +29164 0.38128662109375 +29165 0.261749267578125 +29166 0.404449462890625 +29167 0.27142333984375 +29168 0.3944091796875 +29169 0.259552001953125 +29170 0.3885498046875 +29171 0.24951171875 +29172 0.362640380859375 +29173 0.22674560546875 +29174 0.27362060546875 +29175 0.165130615234375 +29176 0.11712646484375 +29177 0.06231689453125 +29178 -0.054901123046875 +29179 -0.04931640625 +29180 -0.19085693359375 +29181 -0.1376953125 +29182 -0.28570556640625 +29183 -0.19952392578125 +29184 -0.339263916015625 +29185 -0.233917236328125 +29186 -0.3775634765625 +29187 -0.257110595703125 +29188 -0.445709228515625 +29189 -0.29833984375 +29190 -0.535064697265625 +29191 -0.352508544921875 +29192 -0.629058837890625 +29193 -0.409271240234375 +29194 -0.697601318359375 +29195 -0.449554443359375 +29196 -0.70391845703125 +29197 -0.4498291015625 +29198 -0.6424560546875 +29199 -0.406768798828125 +29200 -0.491241455078125 +29201 -0.306304931640625 +29202 -0.265716552734375 +29203 -0.1585693359375 +29204 -0.023712158203125 +29205 -0.001068115234375 +29206 0.201751708984375 +29207 0.144775390625 +29208 0.375823974609375 +29209 0.256439208984375 +29210 0.485076904296875 +29211 0.325347900390625 +29212 0.56884765625 +29213 0.37713623046875 +29214 0.634765625 +29215 0.416900634765625 +29216 0.63763427734375 +29217 0.415557861328125 +29218 0.5660400390625 +29219 0.36590576171875 +29220 0.4720458984375 +29221 0.301849365234375 +29222 0.40692138671875 +29223 0.256805419921875 +29224 0.3778076171875 +29225 0.23553466796875 +29226 0.376953125 +29227 0.233154296875 +29228 0.371978759765625 +29229 0.228790283203125 +29230 0.313140869140625 +29231 0.190216064453125 +29232 0.184417724609375 +29233 0.1070556640625 +29234 0.011199951171875 +29235 -0.004241943359375 +29236 -0.171051025390625 +29237 -0.120758056640625 +29238 -0.33740234375 +29239 -0.2264404296875 +29240 -0.47198486328125 +29241 -0.311126708984375 +29242 -0.560394287109375 +29243 -0.365692138671875 +29244 -0.58056640625 +29245 -0.3759765625 +29246 -0.54754638671875 +29247 -0.351898193359375 +29248 -0.508575439453125 +29249 -0.324188232421875 +29250 -0.459503173828125 +29251 -0.290283203125 +29252 -0.394378662109375 +29253 -0.2464599609375 +29254 -0.35260009765625 +29255 -0.218292236328125 +29256 -0.31170654296875 +29257 -0.191253662109375 +29258 -0.197418212890625 +29259 -0.11724853515625 +29260 -0.007965087890625 +29261 0.004852294921875 +29262 0.207489013671875 +29263 0.14324951171875 +29264 0.409210205078125 +29265 0.27227783203125 +29266 0.57208251953125 +29267 0.37579345703125 +29268 0.66595458984375 +29269 0.434356689453125 +29270 0.65875244140625 +29271 0.427337646484375 +29272 0.56744384765625 +29273 0.3658447265625 +29274 0.431396484375 +29275 0.2755126953125 +29276 0.29443359375 +29277 0.18487548828125 +29278 0.182464599609375 +29279 0.11077880859375 +29280 0.06365966796875 +29281 0.03271484375 +29282 -0.075958251953125 +29283 -0.058319091796875 +29284 -0.189422607421875 +29285 -0.131866455078125 +29286 -0.271942138671875 +29287 -0.184844970703125 +29288 -0.342529296875 +29289 -0.2296142578125 +29290 -0.364166259765625 +29291 -0.242279052734375 +29292 -0.327239990234375 +29293 -0.216705322265625 +29294 -0.2769775390625 +29295 -0.182281494140625 +29296 -0.253692626953125 +29297 -0.165252685546875 +29298 -0.24365234375 +29299 -0.15679931640625 +29300 -0.1983642578125 +29301 -0.125640869140625 +29302 -0.116241455078125 +29303 -0.070831298828125 +29304 -0.036834716796875 +29305 -0.018035888671875 +29306 0.034881591796875 +29307 0.0294189453125 +29308 0.09124755859375 +29309 0.0665283203125 +29310 0.10888671875 +29311 0.078155517578125 +29312 0.125518798828125 +29313 0.08868408203125 +29314 0.15771484375 +29315 0.108917236328125 +29316 0.17828369140625 +29317 0.12127685546875 +29318 0.17108154296875 +29319 0.115325927734375 +29320 0.129974365234375 +29321 0.08721923828125 +29322 0.082427978515625 +29323 0.0548095703125 +29324 0.027679443359375 +29325 0.017730712890625 +29326 -0.065643310546875 +29327 -0.04425048828125 +29328 -0.15936279296875 +29329 -0.1063232421875 +29330 -0.21307373046875 +29331 -0.142242431640625 +29332 -0.234649658203125 +29333 -0.1571044921875 +29334 -0.2001953125 +29335 -0.135345458984375 +29336 -0.119171142578125 +29337 -0.08306884765625 +29338 -0.024749755859375 +29339 -0.02178955078125 +29340 0.085784912109375 +29341 0.050262451171875 +29342 0.178131103515625 +29343 0.110809326171875 +29344 0.215576171875 +29345 0.136016845703125 +29346 0.211456298828125 +29347 0.13446044921875 +29348 0.17523193359375 +29349 0.112213134765625 +29350 0.128753662109375 +29351 0.0833740234375 +29352 0.1019287109375 +29353 0.067230224609375 +29354 0.0743408203125 +29355 0.050506591796875 +29356 0.04327392578125 +29357 0.0313720703125 +29358 0.038177490234375 +29359 0.028839111328125 +29360 0.076263427734375 +29361 0.054046630859375 +29362 0.14105224609375 +29363 0.096282958984375 +29364 0.186431884765625 +29365 0.12567138671875 +29366 0.188812255859375 +29367 0.126922607421875 +29368 0.1390380859375 +29369 0.094146728515625 +29370 0.041778564453125 +29371 0.0303955078125 +29372 -0.079437255859375 +29373 -0.04901123046875 +29374 -0.219390869140625 +29375 -0.140655517578125 +29376 -0.367828369140625 +29377 -0.237823486328125 +29378 -0.494873046875 +29379 -0.32110595703125 +29380 -0.556243896484375 +29381 -0.36175537109375 +29382 -0.508697509765625 +29383 -0.33172607421875 +29384 -0.3756103515625 +29385 -0.246124267578125 +29386 -0.218902587890625 +29387 -0.145050048828125 +29388 -0.063751220703125 +29389 -0.0447998046875 +29390 0.091552734375 +29391 0.05572509765625 +29392 0.23602294921875 +29393 0.149444580078125 +29394 0.342987060546875 +29395 0.219024658203125 +29396 0.39520263671875 +29397 0.2532958984375 +29398 0.389373779296875 +29399 0.2501220703125 +29400 0.324249267578125 +29401 0.208648681640625 +29402 0.224090576171875 +29403 0.14453125 +29404 0.124267578125 +29405 0.08062744140625 +29406 0.037078857421875 +29407 0.024871826171875 +29408 -0.010101318359375 +29409 -0.0050048828125 +29410 -0.019439697265625 +29411 -0.010467529296875 +29412 -0.022796630859375 +29413 -0.012176513671875 +29414 -0.001556396484375 +29415 0.001861572265625 +29416 0.056304931640625 +29417 0.039459228515625 +29418 0.106719970703125 +29419 0.072052001953125 +29420 0.096893310546875 +29421 0.065460205078125 +29422 0.042694091796875 +29423 0.02996826171875 +29424 -0.018035888671875 +29425 -0.0098876953125 +29426 -0.07586669921875 +29427 -0.047943115234375 +29428 -0.11944580078125 +29429 -0.0767822265625 +29430 -0.15972900390625 +29431 -0.103515625 +29432 -0.202606201171875 +29433 -0.13189697265625 +29434 -0.24859619140625 +29435 -0.162200927734375 +29436 -0.30517578125 +29437 -0.199249267578125 +29438 -0.36212158203125 +29439 -0.236419677734375 +29440 -0.39141845703125 +29441 -0.255462646484375 +29442 -0.35528564453125 +29443 -0.231719970703125 +29444 -0.249969482421875 +29445 -0.162872314453125 +29446 -0.092864990234375 +29447 -0.060028076171875 +29448 0.08905029296875 +29449 0.05908203125 +29450 0.2352294921875 +29451 0.15386962890625 +29452 0.318817138671875 +29453 0.206512451171875 +29454 0.358642578125 +29455 0.23016357421875 +29456 0.347747802734375 +29457 0.220367431640625 +29458 0.28564453125 +29459 0.176910400390625 +29460 0.223175048828125 +29461 0.1343994140625 +29462 0.196746826171875 +29463 0.1175537109375 +29464 0.179840087890625 +29465 0.10821533203125 +29466 0.155548095703125 +29467 0.094696044921875 +29468 0.151214599609375 +29469 0.09539794921875 +29470 0.156951904296875 +29471 0.10333251953125 +29472 0.13177490234375 +29473 0.090362548828125 +29474 0.100799560546875 +29475 0.073333740234375 +29476 0.087127685546875 +29477 0.06768798828125 +29478 0.05487060546875 +29479 0.048858642578125 +29480 -0.009002685546875 +29481 0.0078125 +29482 -0.10400390625 +29483 -0.05523681640625 +29484 -0.229400634765625 +29485 -0.139862060546875 +29486 -0.35552978515625 +29487 -0.22589111328125 +29488 -0.441925048828125 +29489 -0.285736083984375 +29490 -0.473846435546875 +29491 -0.309326171875 +29492 -0.464813232421875 +29493 -0.305694580078125 +29494 -0.419097900390625 +29495 -0.277618408203125 +29496 -0.334320068359375 +29497 -0.223297119140625 +29498 -0.227935791015625 +29499 -0.154388427734375 +29500 -0.12347412109375 +29501 -0.08673095703125 +29502 -0.02764892578125 +29503 -0.024688720703125 +29504 0.077667236328125 +29505 0.044219970703125 +29506 0.2132568359375 +29507 0.134246826171875 +29508 0.38885498046875 +29509 0.252105712890625 +29510 0.582794189453125 +29511 0.383148193359375 +29512 0.734039306640625 +29513 0.48590087890625 +29514 0.800140380859375 +29515 0.531494140625 +29516 0.7783203125 +29517 0.5179443359375 +29518 0.6651611328125 +29519 0.442840576171875 +29520 0.45965576171875 +29521 0.305419921875 +29522 0.199188232421875 +29523 0.1309814453125 +29524 -0.050689697265625 +29525 -0.03607177734375 +29526 -0.23297119140625 +29527 -0.157135009765625 +29528 -0.33013916015625 +29529 -0.220458984375 +29530 -0.368408203125 +29531 -0.2440185546875 +29532 -0.378936767578125 +29533 -0.249114990234375 +29534 -0.376983642578125 +29535 -0.246246337890625 +29536 -0.37969970703125 +29537 -0.247161865234375 +29538 -0.391510009765625 +29539 -0.254913330078125 +29540 -0.385345458984375 +29541 -0.251068115234375 +29542 -0.3419189453125 +29543 -0.22247314453125 +29544 -0.28289794921875 +29545 -0.183807373046875 +29546 -0.251617431640625 +29547 -0.1644287109375 +29548 -0.266143798828125 +29549 -0.176483154296875 +29550 -0.273345947265625 +29551 -0.183746337890625 +29552 -0.216796875 +29553 -0.147674560546875 +29554 -0.128265380859375 +29555 -0.0897216796875 +29556 -0.068145751953125 +29557 -0.050872802734375 +29558 -0.0430908203125 +29559 -0.035552978515625 +29560 -0.024444580078125 +29561 -0.024200439453125 +29562 0.020721435546875 +29563 0.005645751953125 +29564 0.124481201171875 +29565 0.075836181640625 +29566 0.25787353515625 +29567 0.1666259765625 +29568 0.379119873046875 +29569 0.249603271484375 +29570 0.47991943359375 +29571 0.319122314453125 +29572 0.5281982421875 +29573 0.353302001953125 +29574 0.511138916015625 +29575 0.34332275390625 +29576 0.456207275390625 +29577 0.307769775390625 +29578 0.407470703125 +29579 0.276519775390625 +29580 0.383758544921875 +29581 0.26226806640625 +29582 0.35687255859375 +29583 0.2457275390625 +29584 0.31182861328125 +29585 0.21661376953125 +29586 0.250885009765625 +29587 0.1763916015625 +29588 0.1654052734375 +29589 0.119140625 +29590 0.035247802734375 +29591 0.031097412109375 +29592 -0.142059326171875 +29593 -0.089385986328125 +29594 -0.33563232421875 +29595 -0.2213134765625 +29596 -0.5345458984375 +29597 -0.357208251953125 +29598 -0.72186279296875 +29599 -0.48553466796875 +29600 -0.836669921875 +29601 -0.564788818359375 +29602 -0.8326416015625 +29603 -0.56341552734375 +29604 -0.7296142578125 +29605 -0.49481201171875 +29606 -0.582550048828125 +29607 -0.396270751953125 +29608 -0.440093994140625 +29609 -0.30078125 +29610 -0.324310302734375 +29611 -0.22332763671875 +29612 -0.20147705078125 +29613 -0.140869140625 +29614 -0.044647216796875 +29615 -0.0350341796875 +29616 0.103973388671875 +29617 0.065521240234375 +29618 0.202392578125 +29619 0.132232666015625 +29620 0.264495849609375 +29621 0.174530029296875 +29622 0.338897705078125 +29623 0.2254638671875 +29624 0.443817138671875 +29625 0.29742431640625 +29626 0.545074462890625 +29627 0.36712646484375 +29628 0.6173095703125 +29629 0.417236328125 +29630 0.6524658203125 +29631 0.4422607421875 +29632 0.66339111328125 +29633 0.45086669921875 +29634 0.6561279296875 +29635 0.44708251953125 +29636 0.606781005859375 +29637 0.41455078125 +29638 0.501190185546875 +29639 0.3436279296875 +29640 0.352783203125 +29641 0.243377685546875 +29642 0.176544189453125 +29643 0.123992919921875 +29644 -0.034820556640625 +29645 -0.01947021484375 +29646 -0.258209228515625 +29647 -0.17132568359375 +29648 -0.44244384765625 +29649 -0.296783447265625 +29650 -0.5753173828125 +29651 -0.38751220703125 +29652 -0.65203857421875 +29653 -0.440216064453125 +29654 -0.641632080078125 +29655 -0.433807373046875 +29656 -0.562164306640625 +29657 -0.38055419921875 +29658 -0.458038330078125 +29659 -0.31060791015625 +29660 -0.350555419921875 +29661 -0.238372802734375 +29662 -0.260528564453125 +29663 -0.177978515625 +29664 -0.192108154296875 +29665 -0.1322021484375 +29666 -0.141937255859375 +29667 -0.098724365234375 +29668 -0.1021728515625 +29669 -0.07220458984375 +29670 -0.062896728515625 +29671 -0.04583740234375 +29672 -0.011932373046875 +29673 -0.011322021484375 +29674 0.062835693359375 +29675 0.03955078125 +29676 0.148712158203125 +29677 0.098175048828125 +29678 0.241729736328125 +29679 0.16180419921875 +29680 0.34912109375 +29681 0.2353515625 +29682 0.457305908203125 +29683 0.309539794921875 +29684 0.54388427734375 +29685 0.369110107421875 +29686 0.5728759765625 +29687 0.389556884765625 +29688 0.506591796875 +29689 0.345184326171875 +29690 0.351226806640625 +29691 0.240203857421875 +29692 0.146514892578125 +29693 0.1015625 +29694 -0.05523681640625 +29695 -0.03515625 +29696 -0.21624755859375 +29697 -0.144622802734375 +29698 -0.334930419921875 +29699 -0.225555419921875 +29700 -0.402984619140625 +29701 -0.271484375 +29702 -0.4412841796875 +29703 -0.297332763671875 +29704 -0.49578857421875 +29705 -0.335845947265625 +29706 -0.5601806640625 +29707 -0.382476806640625 +29708 -0.600738525390625 +29709 -0.4130859375 +29710 -0.584228515625 +29711 -0.40386962890625 +29712 -0.47930908203125 +29713 -0.332305908203125 +29714 -0.27935791015625 +29715 -0.193511962890625 +29716 -0.0089111328125 +29717 -0.00469970703125 +29718 0.268798828125 +29719 0.189300537109375 +29720 0.482818603515625 +29721 0.33819580078125 +29722 0.60369873046875 +29723 0.421173095703125 +29724 0.650421142578125 +29725 0.451904296875 +29726 0.66400146484375 +29727 0.459716796875 +29728 0.6414794921875 +29729 0.442596435546875 +29730 0.572540283203125 +29731 0.39324951171875 +29732 0.498138427734375 +29733 0.340789794921875 +29734 0.439453125 +29735 0.300262451171875 +29736 0.375518798828125 +29737 0.25665283203125 +29738 0.274505615234375 +29739 0.187164306640625 +29740 0.1087646484375 +29741 0.07196044921875 +29742 -0.099395751953125 +29743 -0.073211669921875 +29744 -0.3182373046875 +29745 -0.225921630859375 +29746 -0.5489501953125 +29747 -0.38720703125 +29748 -0.7738037109375 +29749 -0.544586181640625 +29750 -0.86383056640625 +29751 -0.6605224609375 +29752 -0.870391845703125 +29753 -0.71142578125 +29754 -0.86895751953125 +29755 -0.71002197265625 +29756 -0.861053466796875 +29757 -0.665679931640625 +29758 -0.765869140625 +29759 -0.56610107421875 +29760 -0.5301513671875 +29761 -0.403228759765625 +29762 -0.214691162109375 +29763 -0.182037353515625 +29764 0.137359619140625 +29765 0.06689453125 +29766 0.474822998046875 +29767 0.30712890625 +29768 0.76239013671875 +29769 0.513519287109375 +29770 0.867462158203125 +29771 0.666961669921875 +29772 0.870361328125 +29773 0.767913818359375 +29774 0.86480712890625 +29775 0.808319091796875 +29776 0.831817626953125 +29777 0.792083740234375 +29778 0.677581787109375 +29779 0.736663818359375 +29780 0.495880126953125 +29781 0.646270751953125 +29782 0.30767822265625 +29783 0.534149169921875 +29784 0.116180419921875 +29785 0.401885986328125 +29786 -0.110748291015625 +29787 0.226898193359375 +29788 -0.381805419921875 +29789 0.00421142578125 +29790 -0.6572265625 +29791 -0.23577880859375 +29792 -0.857421875 +29793 -0.450531005859375 +29794 -0.870391845703125 +29795 -0.60955810546875 +29796 -0.870391845703125 +29797 -0.707855224609375 +29798 -0.86444091796875 +29799 -0.76470947265625 +29800 -0.85723876953125 +29801 -0.805633544921875 +29802 -0.790008544921875 +29803 -0.817626953125 +29804 -0.62847900390625 +29805 -0.762176513671875 +29806 -0.3956298828125 +29807 -0.6370849609375 +29808 -0.126708984375 +29809 -0.46575927734375 +29810 0.150115966796875 +29811 -0.2677001953125 +29812 0.424041748046875 +29813 -0.05126953125 +29814 0.670623779296875 +29815 0.164306640625 +29816 0.854522705078125 +29817 0.35150146484375 +29818 0.866485595703125 +29819 0.497772216796875 +29820 0.86920166015625 +29821 0.59222412109375 +29822 0.8653564453125 +29823 0.6478271484375 +29824 0.857147216796875 +29825 0.6741943359375 +29826 0.766845703125 +29827 0.669342041015625 +29828 0.628509521484375 +29829 0.63702392578125 +29830 0.462127685546875 +29831 0.572479248046875 +29832 0.297210693359375 +29833 0.494171142578125 +29834 0.14862060546875 +29835 0.41094970703125 +29836 -0.00537109375 +29837 0.30657958984375 +29838 -0.15753173828125 +29839 0.186431884765625 +29840 -0.31304931640625 +29841 0.04791259765625 +29842 -0.48876953125 +29843 -0.118927001953125 +29844 -0.6416015625 +29845 -0.28076171875 +29846 -0.751373291015625 +29847 -0.41998291015625 +29848 -0.84619140625 +29849 -0.553070068359375 +29850 -0.861297607421875 +29851 -0.669586181640625 +29852 -0.863250732421875 +29853 -0.746002197265625 +29854 -0.856597900390625 +29855 -0.759857177734375 +29856 -0.7498779296875 +29857 -0.7198486328125 +29858 -0.624542236328125 +29859 -0.667205810546875 +29860 -0.47808837890625 +29861 -0.586334228515625 +29862 -0.253387451171875 +29863 -0.4356689453125 +29864 0.003692626953125 +29865 -0.24774169921875 +29866 0.2257080078125 +29867 -0.071258544921875 +29868 0.427154541015625 +29869 0.102691650390625 +29870 0.643218994140625 +29871 0.297119140625 +29872 0.855926513671875 +29873 0.50518798828125 +29874 0.870361328125 +29875 0.685638427734375 +29876 0.870361328125 +29877 0.80316162109375 +29878 0.862762451171875 +29879 0.85540771484375 +29880 0.79669189453125 +29881 0.855377197265625 +29882 0.595794677734375 +29883 0.795928955078125 +29884 0.362152099609375 +29885 0.683380126953125 +29886 0.1270751953125 +29887 0.54510498046875 +29888 -0.086944580078125 +29889 0.396209716796875 +29890 -0.2784423828125 +29891 0.238250732421875 +29892 -0.484832763671875 +29893 0.0465087890625 +29894 -0.729583740234375 +29895 -0.192626953125 +29896 -0.86688232421875 +29897 -0.44305419921875 +29898 -0.870391845703125 +29899 -0.65960693359375 +29900 -0.86859130859375 +29901 -0.8387451171875 +29902 -0.86279296875 +29903 -0.868072509765625 +29904 -0.817962646484375 +29905 -0.870391845703125 +29906 -0.6116943359375 +29907 -0.86260986328125 +29908 -0.3128662109375 +29909 -0.76226806640625 +29910 0.039398193359375 +29911 -0.527099609375 +29912 0.422821044921875 +29913 -0.238983154296875 +29914 0.805145263671875 +29915 0.07733154296875 +29916 0.870361328125 +29917 0.373016357421875 +29918 0.870361328125 +29919 0.60772705078125 +29920 0.860015869140625 +29921 0.77392578125 +29922 0.727935791015625 +29923 0.85589599609375 +29924 0.48114013671875 +29925 0.857940673828125 +29926 0.2059326171875 +29927 0.849639892578125 +29928 -0.06103515625 +29929 0.775909423828125 +29930 -0.29913330078125 +29931 0.6746826171875 +29932 -0.516204833984375 +29933 0.538055419921875 +29934 -0.7252197265625 +29935 0.357269287109375 +29936 -0.85980224609375 +29937 0.15203857421875 +29938 -0.870391845703125 +29939 -0.051513671875 +29940 -0.870391845703125 +29941 -0.231170654296875 +29942 -0.858062744140625 +29943 -0.351470947265625 +29944 -0.673004150390625 +29945 -0.409210205078125 +29946 -0.42694091796875 +29947 -0.441986083984375 +29948 -0.2100830078125 +29949 -0.4820556640625 +29950 -0.0362548828125 +29951 -0.529052734375 +29952 0.10943603515625 +29953 -0.564056396484375 +29954 0.23516845703125 +29955 -0.57476806640625 +29956 0.373687744140625 +29957 -0.5323486328125 +29958 0.517791748046875 +29959 -0.440032958984375 +29960 0.602783203125 +29961 -0.346405029296875 +29962 0.635711669921875 +29963 -0.249114990234375 +29964 0.655181884765625 +29965 -0.124603271484375 +29966 0.65948486328125 +29967 0.018798828125 +29968 0.651275634765625 +29969 0.174560546875 +29970 0.61846923828125 +29971 0.324249267578125 +29972 0.53753662109375 +29973 0.4405517578125 +29974 0.404144287109375 +29975 0.510528564453125 +29976 0.22186279296875 +29977 0.527862548828125 +29978 0.003997802734375 +29979 0.49456787109375 +29980 -0.22100830078125 +29981 0.425445556640625 +29982 -0.42449951171875 +29983 0.33734130859375 +29984 -0.579833984375 +29985 0.24761962890625 +29986 -0.641876220703125 +29987 0.189544677734375 +29988 -0.6177978515625 +29989 0.159515380859375 +29990 -0.575531005859375 +29991 0.110626220703125 +29992 -0.526336669921875 +29993 0.039825439453125 +29994 -0.42645263671875 +29995 -0.013702392578125 +29996 -0.2581787109375 +29997 -0.029205322265625 +29998 -0.068695068359375 +29999 -0.03375244140625 +30000 0.09222412109375 +30001 -0.056304931640625 +30002 0.232147216796875 +30003 -0.083526611328125 +30004 0.3509521484375 +30005 -0.108673095703125 +30006 0.410064697265625 +30007 -0.15478515625 +30008 0.372955322265625 +30009 -0.24481201171875 +30010 0.2554931640625 +30011 -0.36431884765625 +30012 0.10711669921875 +30013 -0.47564697265625 +30014 -0.052886962890625 +30015 -0.565338134765625 +30016 -0.186279296875 +30017 -0.60736083984375 +30018 -0.23291015625 +30019 -0.560943603515625 +30020 -0.209442138671875 +30021 -0.443572998046875 +30022 -0.174163818359375 +30023 -0.304595947265625 +30024 -0.126739501953125 +30025 -0.1502685546875 +30026 -0.048126220703125 +30027 0.02685546875 +30028 0.0426025390625 +30029 0.2061767578125 +30030 0.10748291015625 +30031 0.353546142578125 +30032 0.1409912109375 +30033 0.459808349609375 +30034 0.19708251953125 +30035 0.561187744140625 +30036 0.273651123046875 +30037 0.65350341796875 +30038 0.31768798828125 +30039 0.69610595703125 +30040 0.341094970703125 +30041 0.697998046875 +30042 0.368011474609375 +30043 0.678741455078125 +30044 0.37249755859375 +30045 0.621856689453125 +30046 0.30072021484375 +30047 0.49114990234375 +30048 0.1517333984375 +30049 0.290618896484375 +30050 -0.01470947265625 +30051 0.0699462890625 +30052 -0.1883544921875 +30053 -0.157684326171875 +30054 -0.372711181640625 +30055 -0.389495849609375 +30056 -0.51397705078125 +30057 -0.58038330078125 +30058 -0.57177734375 +30059 -0.695892333984375 +30060 -0.53948974609375 +30061 -0.727569580078125 +30062 -0.43511962890625 +30063 -0.68621826171875 +30064 -0.2962646484375 +30065 -0.598388671875 +30066 -0.161102294921875 +30067 -0.49224853515625 +30068 -0.0435791015625 +30069 -0.379058837890625 +30070 0.060394287109375 +30071 -0.257781982421875 +30072 0.13665771484375 +30073 -0.141876220703125 +30074 0.170135498046875 +30075 -0.04620361328125 +30076 0.16552734375 +30077 0.028533935546875 +30078 0.15728759765625 +30079 0.103485107421875 +30080 0.150787353515625 +30081 0.17816162109375 +30082 0.12200927734375 +30083 0.230377197265625 +30084 0.080108642578125 +30085 0.263092041015625 +30086 0.05126953125 +30087 0.2926025390625 +30088 0.062896728515625 +30089 0.3369140625 +30090 0.09271240234375 +30091 0.377899169921875 +30092 0.092987060546875 +30093 0.379547119140625 +30094 0.07855224609375 +30095 0.353271484375 +30096 0.06427001953125 +30097 0.311492919921875 +30098 0.0347900390625 +30099 0.244903564453125 +30100 -0.01171875 +30101 0.154937744140625 +30102 -0.056060791015625 +30103 0.059234619140625 +30104 -0.055511474609375 +30105 -0.006744384765625 +30106 -0.010467529296875 +30107 -0.039581298828125 +30108 0.02508544921875 +30109 -0.075775146484375 +30110 0.025665283203125 +30111 -0.1309814453125 +30112 0.017333984375 +30113 -0.183013916015625 +30114 0.00189208984375 +30115 -0.22833251953125 +30116 -0.03173828125 +30117 -0.273681640625 +30118 -0.071502685546875 +30119 -0.30938720703125 +30120 -0.13543701171875 +30121 -0.348907470703125 +30122 -0.219970703125 +30123 -0.390472412109375 +30124 -0.300506591796875 +30125 -0.41729736328125 +30126 -0.376312255859375 +30127 -0.430999755859375 +30128 -0.416107177734375 +30129 -0.410888671875 +30130 -0.371124267578125 +30131 -0.3236083984375 +30132 -0.242279052734375 +30133 -0.172882080078125 +30134 -0.069732666015625 +30135 0.008392333984375 +30136 0.125640869140625 +30137 0.20184326171875 +30138 0.31268310546875 +30139 0.38177490234375 +30140 0.45501708984375 +30141 0.519134521484375 +30142 0.554779052734375 +30143 0.61407470703125 +30144 0.61065673828125 +30145 0.664794921875 +30146 0.610931396484375 +30147 0.662384033203125 +30148 0.531463623046875 +30149 0.58941650390625 +30150 0.3883056640625 +30151 0.458892822265625 +30152 0.23468017578125 +30153 0.31201171875 +30154 0.095245361328125 +30155 0.16912841796875 +30156 -0.00396728515625 +30157 0.051910400390625 +30158 -0.04852294921875 +30159 -0.026397705078125 +30160 -0.055145263671875 +30161 -0.075714111328125 +30162 -0.0758056640625 +30163 -0.132293701171875 +30164 -0.138702392578125 +30165 -0.214996337890625 +30166 -0.209197998046875 +30167 -0.29620361328125 +30168 -0.289031982421875 +30169 -0.375885009765625 +30170 -0.37884521484375 +30171 -0.453643798828125 +30172 -0.456329345703125 +30173 -0.51251220703125 +30174 -0.51641845703125 +30175 -0.5489501953125 +30176 -0.519287109375 +30177 -0.534088134765625 +30178 -0.458251953125 +30179 -0.464111328125 +30180 -0.384796142578125 +30181 -0.37884521484375 +30182 -0.323699951171875 +30183 -0.298614501953125 +30184 -0.269287109375 +30185 -0.221160888671875 +30186 -0.1951904296875 +30187 -0.128997802734375 +30188 -0.100006103515625 +30189 -0.0230712890625 +30190 -0.01055908203125 +30191 0.074737548828125 +30192 0.1033935546875 +30193 0.18536376953125 +30194 0.24908447265625 +30195 0.31292724609375 +30196 0.373199462890625 +30197 0.416961669921875 +30198 0.45806884765625 +30199 0.483856201171875 +30200 0.511474609375 +30201 0.519439697265625 +30202 0.565399169921875 +30203 0.5479736328125 +30204 0.61138916015625 +30205 0.563995361328125 +30206 0.5897216796875 +30207 0.524261474609375 +30208 0.4906005859375 +30209 0.42279052734375 +30210 0.33148193359375 +30211 0.274078369140625 +30212 0.147796630859375 +30213 0.1063232421875 +30214 -0.01873779296875 +30215 -0.047515869140625 +30216 -0.140289306640625 +30217 -0.16497802734375 +30218 -0.191986083984375 +30219 -0.22601318359375 +30220 -0.184295654296875 +30221 -0.237396240234375 +30222 -0.161834716796875 +30223 -0.2318115234375 +30224 -0.166595458984375 +30225 -0.240264892578125 +30226 -0.19390869140625 +30227 -0.2591552734375 +30228 -0.22442626953125 +30229 -0.274261474609375 +30230 -0.279754638671875 +30231 -0.302398681640625 +30232 -0.3389892578125 +30233 -0.32879638671875 +30234 -0.3543701171875 +30235 -0.318756103515625 +30236 -0.348175048828125 +30237 -0.290252685546875 +30238 -0.32598876953125 +30239 -0.248809814453125 +30240 -0.2581787109375 +30241 -0.17364501953125 +30242 -0.139801025390625 +30243 -0.062347412109375 +30244 0.014617919921875 +30245 0.073028564453125 +30246 0.144378662109375 +30247 0.185943603515625 +30248 0.221038818359375 +30249 0.254364013671875 +30250 0.27069091796875 +30251 0.29736328125 +30252 0.294036865234375 +30253 0.31536865234375 +30254 0.311767578125 +30255 0.323974609375 +30256 0.339141845703125 +30257 0.335113525390625 +30258 0.360260009765625 +30259 0.33782958984375 +30260 0.360504150390625 +30261 0.321929931640625 +30262 0.308380126953125 +30263 0.2637939453125 +30264 0.18170166015625 +30265 0.147125244140625 +30266 0.0047607421875 +30267 -0.008209228515625 +30268 -0.17559814453125 +30269 -0.16497802734375 +30270 -0.3143310546875 +30271 -0.287384033203125 +30272 -0.36785888671875 +30273 -0.34088134765625 +30274 -0.36248779296875 +30275 -0.3453369140625 +30276 -0.343536376953125 +30277 -0.335540771484375 +30278 -0.3018798828125 +30279 -0.30426025390625 +30280 -0.231414794921875 +30281 -0.246826171875 +30282 -0.117645263671875 +30283 -0.1522216796875 +30284 0.007049560546875 +30285 -0.0460205078125 +30286 0.087982177734375 +30287 0.02874755859375 +30288 0.13946533203125 +30289 0.082489013671875 +30290 0.17425537109375 +30291 0.124298095703125 +30292 0.188201904296875 +30293 0.15008544921875 +30294 0.171234130859375 +30295 0.15118408203125 +30296 0.118438720703125 +30297 0.123077392578125 +30298 0.05706787109375 +30299 0.08624267578125 +30300 -0.010711669921875 +30301 0.04180908203125 +30302 -0.0914306640625 +30303 -0.015625 +30304 -0.162322998046875 +30305 -0.068603515625 +30306 -0.194549560546875 +30307 -0.09478759765625 +30308 -0.1492919921875 +30309 -0.063873291015625 +30310 -0.02166748046875 +30311 0.028228759765625 +30312 0.124053955078125 +30313 0.13214111328125 +30314 0.211151123046875 +30315 0.188873291015625 +30316 0.240447998046875 +30317 0.19970703125 +30318 0.242218017578125 +30319 0.18878173828125 +30320 0.2257080078125 +30321 0.16400146484375 +30322 0.194366455078125 +30323 0.128692626953125 +30324 0.115509033203125 +30325 0.058013916015625 +30326 0.0128173828125 +30327 -0.029144287109375 +30328 -0.053802490234375 +30329 -0.085968017578125 +30330 -0.110626220703125 +30331 -0.13262939453125 +30332 -0.199493408203125 +30333 -0.2015380859375 +30334 -0.29437255859375 +30335 -0.2725830078125 +30336 -0.33221435546875 +30337 -0.2969970703125 +30338 -0.27972412109375 +30339 -0.24932861328125 +30340 -0.185333251953125 +30341 -0.167572021484375 +30342 -0.128204345703125 +30343 -0.113677978515625 +30344 -0.115692138671875 +30345 -0.0938720703125 +30346 -0.116455078125 +30347 -0.08441162109375 +30348 -0.105926513671875 +30349 -0.066802978515625 +30350 -0.053955078125 +30351 -0.01812744140625 +30352 0.048797607421875 +30353 0.06842041015625 +30354 0.157318115234375 +30355 0.1575927734375 +30356 0.212005615234375 +30357 0.202911376953125 +30358 0.218475341796875 +30359 0.208648681640625 +30360 0.23724365234375 +30361 0.221771240234375 +30362 0.30535888671875 +30363 0.27117919921875 +30364 0.38128662109375 +30365 0.324859619140625 +30366 0.404449462890625 +30367 0.336151123046875 +30368 0.3944091796875 +30369 0.320648193359375 +30370 0.3885498046875 +30371 0.30780029296875 +30372 0.362640380859375 +30373 0.279327392578125 +30374 0.27362060546875 +30375 0.202239990234375 +30376 0.11712646484375 +30377 0.073577880859375 +30378 -0.054901123046875 +30379 -0.065948486328125 +30380 -0.19085693359375 +30381 -0.176025390625 +30382 -0.28570556640625 +30383 -0.252532958984375 +30384 -0.339263916015625 +30385 -0.295257568359375 +30386 -0.3775634765625 +30387 -0.3243408203125 +30388 -0.445709228515625 +30389 -0.3748779296875 +30390 -0.535064697265625 +30391 -0.44036865234375 +30392 -0.629058837890625 +30393 -0.5081787109375 +30394 -0.697601318359375 +30395 -0.5552978515625 +30396 -0.70391845703125 +30397 -0.55352783203125 +30398 -0.6424560546875 +30399 -0.498931884765625 +30400 -0.491241455078125 +30401 -0.3748779296875 +30402 -0.265716552734375 +30403 -0.19366455078125 +30404 -0.023712158203125 +30405 -0.000518798828125 +30406 0.201751708984375 +30407 0.17864990234375 +30408 0.375823974609375 +30409 0.316619873046875 +30410 0.485076904296875 +30411 0.40283203125 +30412 0.56884765625 +30413 0.4677734375 +30414 0.634765625 +30415 0.517425537109375 +30416 0.63763427734375 +30417 0.516845703125 +30418 0.5660400390625 +30419 0.457366943359375 +30420 0.4720458984375 +30421 0.379638671875 +30422 0.40692138671875 +30423 0.323699951171875 +30424 0.3778076171875 +30425 0.295440673828125 +30426 0.376953125 +30427 0.289154052734375 +30428 0.371978759765625 +30429 0.280029296875 +30430 0.313140869140625 +30431 0.229736328125 +30432 0.184417724609375 +30433 0.126068115234375 +30434 0.011199951171875 +30435 -0.011077880859375 +30436 -0.171051025390625 +30437 -0.154083251953125 +30438 -0.33740234375 +30439 -0.283538818359375 +30440 -0.47198486328125 +30441 -0.387115478515625 +30442 -0.560394287109375 +30443 -0.4537353515625 +30444 -0.58056640625 +30445 -0.466461181640625 +30446 -0.54754638671875 +30447 -0.437103271484375 +30448 -0.508575439453125 +30449 -0.402587890625 +30450 -0.459503173828125 +30451 -0.359893798828125 +30452 -0.394378662109375 +30453 -0.304718017578125 +30454 -0.35260009765625 +30455 -0.267852783203125 +30456 -0.31170654296875 +30457 -0.232086181640625 +30458 -0.197418212890625 +30459 -0.139984130859375 +30460 -0.007965087890625 +30461 0.009613037109375 +30462 0.207489013671875 +30463 0.178436279296875 +30464 0.409210205078125 +30465 0.33563232421875 +30466 0.57208251953125 +30467 0.462310791015625 +30468 0.66595458984375 +30469 0.534698486328125 +30470 0.65875244140625 +30471 0.526580810546875 +30472 0.56744384765625 +30473 0.451416015625 +30474 0.431396484375 +30475 0.340850830078125 +30476 0.29443359375 +30477 0.2301025390625 +30478 0.182464599609375 +30479 0.13995361328125 +30480 0.06365966796875 +30481 0.044586181640625 +30482 -0.075958251953125 +30483 -0.0673828125 +30484 -0.189422607421875 +30485 -0.158050537109375 +30486 -0.271942138671875 +30487 -0.223602294921875 +30488 -0.342529296875 +30489 -0.27947998046875 +30490 -0.364166259765625 +30491 -0.29583740234375 +30492 -0.327239990234375 +30493 -0.264923095703125 +30494 -0.2769775390625 +30495 -0.22332763671875 +30496 -0.253692626953125 +30497 -0.203643798828125 +30498 -0.24365234375 +30499 -0.194793701171875 +30500 -0.1983642578125 +30501 -0.157623291015625 +30502 -0.116241455078125 +30503 -0.090850830078125 +30504 -0.036834716796875 +30505 -0.02642822265625 +30506 0.034881591796875 +30507 0.031585693359375 +30508 0.09124755859375 +30509 0.076995849609375 +30510 0.10888671875 +30511 0.090972900390625 +30512 0.125518798828125 +30513 0.103973388671875 +30514 0.15771484375 +30515 0.129425048828125 +30516 0.17828369140625 +30517 0.145355224609375 +30518 0.17108154296875 +30519 0.1387939453125 +30520 0.129974365234375 +30521 0.104827880859375 +30522 0.082427978515625 +30523 0.065673828125 +30524 0.027679443359375 +30525 0.02081298828125 +30526 -0.065643310546875 +30527 -0.055084228515625 +30528 -0.15936279296875 +30529 -0.131134033203125 +30530 -0.21307373046875 +30531 -0.174713134765625 +30532 -0.234649658203125 +30533 -0.192169189453125 +30534 -0.2001953125 +30535 -0.164215087890625 +30536 -0.119171142578125 +30537 -0.0985107421875 +30538 -0.024749755859375 +30539 -0.021881103515625 +30540 0.085784912109375 +30541 0.06787109375 +30542 0.178131103515625 +30543 0.14300537109375 +30544 0.215576171875 +30545 0.173828125 +30546 0.211456298828125 +30547 0.171051025390625 +30548 0.17523193359375 +30549 0.142303466796875 +30550 0.128753662109375 +30551 0.105194091796875 +30552 0.1019287109375 +30553 0.083892822265625 +30554 0.0743408203125 +30555 0.0618896484375 +30556 0.04327392578125 +30557 0.036956787109375 +30558 0.038177490234375 +30559 0.03289794921875 +30560 0.076263427734375 +30561 0.063629150390625 +30562 0.14105224609375 +30563 0.1158447265625 +30564 0.186431884765625 +30565 0.15228271484375 +30566 0.188812255859375 +30567 0.153900146484375 +30568 0.1390380859375 +30569 0.11328125 +30570 0.041778564453125 +30571 0.03424072265625 +30572 -0.079437255859375 +30573 -0.06414794921875 +30574 -0.219390869140625 +30575 -0.17767333984375 +30576 -0.367828369140625 +30577 -0.298004150390625 +30578 -0.494873046875 +30579 -0.4010009765625 +30580 -0.556243896484375 +30581 -0.450836181640625 +30582 -0.508697509765625 +30583 -0.412567138671875 +30584 -0.3756103515625 +30585 -0.305084228515625 +30586 -0.218902587890625 +30587 -0.178436279296875 +30588 -0.063751220703125 +30589 -0.052978515625 +30590 0.091552734375 +30591 0.072662353515625 +30592 0.23602294921875 +30593 0.189605712890625 +30594 0.342987060546875 +30595 0.27630615234375 +30596 0.39520263671875 +30597 0.318817138671875 +30598 0.389373779296875 +30599 0.314453125 +30600 0.324249267578125 +30601 0.26220703125 +30602 0.224090576171875 +30603 0.181640625 +30604 0.124267578125 +30605 0.101287841796875 +30606 0.037078857421875 +30607 0.03106689453125 +30608 -0.010101318359375 +30609 -0.006866455078125 +30610 -0.019439697265625 +30611 -0.014312744140625 +30612 -0.022796630859375 +30613 -0.016998291015625 +30614 -0.001556396484375 +30615 9.1552734375e-05 +30616 0.056304931640625 +30617 0.04669189453125 +30618 0.106719970703125 +30619 0.08721923828125 +30620 0.096893310546875 +30621 0.079010009765625 +30622 0.042694091796875 +30623 0.034942626953125 +30624 -0.018035888671875 +30625 -0.014434814453125 +30626 -0.07586669921875 +30627 -0.06146240234375 +30628 -0.11944580078125 +30629 -0.096954345703125 +30630 -0.15972900390625 +30631 -0.1297607421875 +30632 -0.202606201171875 +30633 -0.16461181640625 +30634 -0.24859619140625 +30635 -0.201904296875 +30636 -0.30517578125 +30637 -0.2476806640625 +30638 -0.36212158203125 +30639 -0.293670654296875 +30640 -0.39141845703125 +30641 -0.317291259765625 +30642 -0.35528564453125 +30643 -0.2879638671875 +30644 -0.249969482421875 +30645 -0.20269775390625 +30646 -0.092864990234375 +30647 -0.0755615234375 +30648 0.08905029296875 +30649 0.0716552734375 +30650 0.2352294921875 +30651 0.19000244140625 +30652 0.318817138671875 +30653 0.257781982421875 +30654 0.358642578125 +30655 0.290191650390625 +30656 0.347747802734375 +30657 0.281585693359375 +30658 0.28564453125 +30659 0.2315673828125 +30660 0.223175048828125 +30661 0.18121337890625 +30662 0.196746826171875 +30663 0.159942626953125 +30664 0.179840087890625 +30665 0.146331787109375 +30666 0.155548095703125 +30667 0.126678466796875 +30668 0.151214599609375 +30669 0.12310791015625 +30670 0.156951904296875 +30671 0.12762451171875 +30672 0.13177490234375 +30673 0.10711669921875 +30674 0.100799560546875 +30675 0.0819091796875 +30676 0.087127685546875 +30677 0.070648193359375 +30678 0.05487060546875 +30679 0.044342041015625 +30680 -0.009002685546875 +30681 -0.00750732421875 +30682 -0.10400390625 +30683 -0.08447265625 +30684 -0.229400634765625 +30685 -0.18597412109375 +30686 -0.35552978515625 +30687 -0.28802490234375 +30688 -0.441925048828125 +30689 -0.357879638671875 +30690 -0.473846435546875 +30691 -0.383697509765625 +30692 -0.464813232421875 +30693 -0.3763427734375 +30694 -0.419097900390625 +30695 -0.33929443359375 +30696 -0.334320068359375 +30697 -0.2706298828125 +30698 -0.227935791015625 +30699 -0.1844482421875 +30700 -0.12347412109375 +30701 -0.099822998046875 +30702 -0.02764892578125 +30703 -0.022186279296875 +30704 0.077667236328125 +30705 0.063140869140625 +30706 0.2132568359375 +30707 0.17291259765625 +30708 0.38885498046875 +30709 0.314971923828125 +30710 0.582794189453125 +30711 0.4718017578125 +30712 0.734039306640625 +30713 0.594085693359375 +30714 0.800140380859375 +30715 0.64752197265625 +30716 0.7783203125 +30717 0.629852294921875 +30718 0.6651611328125 +30719 0.538299560546875 +30720 0.45965576171875 +30721 0.371612548828125 +30722 0.199188232421875 +30723 0.159454345703125 +30724 -0.050689697265625 +30725 -0.044219970703125 +30726 -0.23297119140625 +30727 -0.19171142578125 +30728 -0.33013916015625 +30729 -0.2684326171875 +30730 -0.368408203125 +30731 -0.2965087890625 +30732 -0.378936767578125 +30733 -0.302215576171875 +30734 -0.376983642578125 +30735 -0.2984619140625 +30736 -0.37969970703125 +30737 -0.29974365234375 +30738 -0.391510009765625 +30739 -0.309722900390625 +30740 -0.385345458984375 +30741 -0.30560302734375 +30742 -0.3419189453125 +30743 -0.271087646484375 +30744 -0.28289794921875 +30745 -0.2242431640625 +30746 -0.251617431640625 +30747 -0.2012939453125 +30748 -0.266143798828125 +30749 -0.21722412109375 +30750 -0.273345947265625 +30751 -0.227203369140625 +30752 -0.216796875 +30753 -0.18359375 +30754 -0.128265380859375 +30755 -0.112884521484375 +30756 -0.068145751953125 +30757 -0.065643310546875 +30758 -0.0430908203125 +30759 -0.04730224609375 +30760 -0.024444580078125 +30761 -0.03363037109375 +30762 0.020721435546875 +30763 0.00311279296875 +30764 0.124481201171875 +30765 0.08990478515625 +30766 0.25787353515625 +30767 0.202392578125 +30768 0.379119873046875 +30769 0.305389404296875 +30770 0.47991943359375 +30771 0.39190673828125 +30772 0.5281982421875 +30773 0.434844970703125 +30774 0.511138916015625 +30775 0.423309326171875 +30776 0.456207275390625 +30777 0.380218505859375 +30778 0.407470703125 +30779 0.3424072265625 +30780 0.383758544921875 +30781 0.325531005859375 +30782 0.35687255859375 +30783 0.30572509765625 +30784 0.31182861328125 +30785 0.270263671875 +30786 0.250885009765625 +30787 0.220916748046875 +30788 0.1654052734375 +30789 0.150360107421875 +30790 0.035247802734375 +30791 0.0416259765625 +30792 -0.142059326171875 +30793 -0.10736083984375 +30794 -0.33563232421875 +30795 -0.270660400390625 +30796 -0.5345458984375 +30797 -0.43902587890625 +30798 -0.72186279296875 +30799 -0.59814453125 +30800 -0.836669921875 +30801 -0.696746826171875 +30802 -0.8326416015625 +30803 -0.69580078125 +30804 -0.7296142578125 +30805 -0.611846923828125 +30806 -0.582550048828125 +30807 -0.490875244140625 +30808 -0.440093994140625 +30809 -0.37359619140625 +30810 -0.324310302734375 +30811 -0.2784423828125 +30812 -0.20147705078125 +30813 -0.177001953125 +30814 -0.044647216796875 +30815 -0.0465087890625 +30816 0.103973388671875 +30817 0.07763671875 +30818 0.202392578125 +30819 0.16015625 +30820 0.264495849609375 +30821 0.21270751953125 +30822 0.338897705078125 +30823 0.276092529296875 +30824 0.443817138671875 +30825 0.36553955078125 +30826 0.545074462890625 +30827 0.452239990234375 +30828 0.6173095703125 +30829 0.514801025390625 +30830 0.6524658203125 +30831 0.54638671875 +30832 0.66339111328125 +30833 0.557647705078125 +30834 0.6561279296875 +30835 0.553558349609375 +30836 0.606781005859375 +30837 0.513916015625 +30838 0.501190185546875 +30839 0.426727294921875 +30840 0.352783203125 +30841 0.30322265625 +30842 0.176544189453125 +30843 0.155914306640625 +30844 -0.034820556640625 +30845 -0.02130126953125 +30846 -0.258209228515625 +30847 -0.20904541015625 +30848 -0.44244384765625 +30849 -0.36431884765625 +30850 -0.5753173828125 +30851 -0.476806640625 +30852 -0.65203857421875 +30853 -0.542449951171875 +30854 -0.641632080078125 +30855 -0.535125732421875 +30856 -0.562164306640625 +30857 -0.469940185546875 +30858 -0.458038330078125 +30859 -0.384124755859375 +30860 -0.350555419921875 +30861 -0.29547119140625 +30862 -0.260528564453125 +30863 -0.221343994140625 +30864 -0.192108154296875 +30865 -0.165191650390625 +30866 -0.141937255859375 +30867 -0.1241455078125 +30868 -0.1021728515625 +30869 -0.091552734375 +30870 -0.062896728515625 +30871 -0.05902099609375 +30872 -0.011932373046875 +30873 -0.01629638671875 +30874 0.062835693359375 +30875 0.046783447265625 +30876 0.148712158203125 +30877 0.119537353515625 +30878 0.241729736328125 +30879 0.19854736328125 +30880 0.34912109375 +30881 0.28985595703125 +30882 0.457305908203125 +30883 0.381988525390625 +30884 0.54388427734375 +30885 0.4560546875 +30886 0.5728759765625 +30887 0.481781005859375 +30888 0.506591796875 +30889 0.427398681640625 +30890 0.351226806640625 +30891 0.298065185546875 +30892 0.146514892578125 +30893 0.127105712890625 +30894 -0.05523681640625 +30895 -0.041595458984375 +30896 -0.21624755859375 +30897 -0.176361083984375 +30898 -0.334930419921875 +30899 -0.27587890625 +30900 -0.402984619140625 +30901 -0.333160400390625 +30902 -0.4412841796875 +30903 -0.36572265625 +30904 -0.49578857421875 +30905 -0.412139892578125 +30906 -0.5601806640625 +30907 -0.467071533203125 +30908 -0.600738525390625 +30909 -0.50213623046875 +30910 -0.584228515625 +30911 -0.489349365234375 +30912 -0.47930908203125 +30913 -0.402313232421875 +30914 -0.27935791015625 +30915 -0.235443115234375 +30916 -0.0089111328125 +30917 -0.00927734375 +30918 0.268798828125 +30919 0.22308349609375 +30920 0.482818603515625 +30921 0.402130126953125 +30922 0.60369873046875 +30923 0.503143310546875 +30924 0.650421142578125 +30925 0.542083740234375 +30926 0.66400146484375 +30927 0.553436279296875 +30928 0.6414794921875 +30929 0.53466796875 +30930 0.572540283203125 +30931 0.47711181640625 +30932 0.498138427734375 +30933 0.4151611328125 +30934 0.439453125 +30935 0.3665771484375 +30936 0.375518798828125 +30937 0.313690185546875 +30938 0.274505615234375 +30939 0.229705810546875 +30940 0.1087646484375 +30941 0.09136962890625 +30942 -0.099395751953125 +30943 -0.0826416015625 +30944 -0.3182373046875 +30945 -0.265655517578125 +30946 -0.5489501953125 +30947 -0.458770751953125 +30948 -0.7738037109375 +30949 -0.647064208984375 +30950 -0.86383056640625 +30951 -0.7861328125 +30952 -0.870391845703125 +30953 -0.848052978515625 +30954 -0.86895751953125 +30955 -0.847686767578125 +30956 -0.861053466796875 +30957 -0.79608154296875 +30958 -0.765869140625 +30959 -0.678680419921875 +30960 -0.5301513671875 +30961 -0.485992431640625 +30962 -0.214691162109375 +30963 -0.223968505859375 +30964 0.137359619140625 +30965 0.071258544921875 +30966 0.474822998046875 +30967 0.35662841796875 +30968 0.76239013671875 +30969 0.602325439453125 +30970 0.867462158203125 +30971 0.78570556640625 +30972 0.870361328125 +30973 0.8602294921875 +30974 0.86480712890625 +30975 0.86566162109375 +30976 0.831817626953125 +30977 0.863800048828125 +30978 0.677581787109375 +30979 0.856903076171875 +30980 0.495880126953125 +30981 0.77191162109375 +30982 0.30767822265625 +30983 0.64141845703125 +30984 0.116180419921875 +30985 0.48681640625 +30986 -0.110748291015625 +30987 0.27996826171875 +30988 -0.381805419921875 +30989 0.014312744140625 +30990 -0.6572265625 +30991 -0.273223876953125 +30992 -0.857421875 +30993 -0.5308837890625 +30994 -0.870391845703125 +30995 -0.72161865234375 +30996 -0.870391845703125 +30997 -0.8394775390625 +30998 -0.86444091796875 +30999 -0.8603515625 +31000 -0.85723876953125 +31001 -0.86590576171875 +31002 -0.790008544921875 +31003 -0.86773681640625 +31004 -0.62847900390625 +31005 -0.8607177734375 +31006 -0.3956298828125 +31007 -0.762725830078125 +31008 -0.126708984375 +31009 -0.558319091796875 +31010 0.150115966796875 +31011 -0.321685791015625 +31012 0.424041748046875 +31013 -0.062744140625 +31014 0.670623779296875 +31015 0.195343017578125 +31016 0.854522705078125 +31017 0.419158935546875 +31018 0.866485595703125 +31019 0.5936279296875 +31020 0.86920166015625 +31021 0.70562744140625 +31022 0.8653564453125 +31023 0.771270751953125 +31024 0.857147216796875 +31025 0.80242919921875 +31026 0.766845703125 +31027 0.796661376953125 +31028 0.628509521484375 +31029 0.758453369140625 +31030 0.462127685546875 +31031 0.68194580078125 +31032 0.297210693359375 +31033 0.58953857421875 +31034 0.14862060546875 +31035 0.491851806640625 +31036 -0.00537109375 +31037 0.3687744140625 +31038 -0.15753173828125 +31039 0.226593017578125 +31040 -0.31304931640625 +31041 0.0618896484375 +31042 -0.48876953125 +31043 -0.137847900390625 +31044 -0.6416015625 +31045 -0.332000732421875 +31046 -0.751373291015625 +31047 -0.499237060546875 +31048 -0.84619140625 +31049 -0.659881591796875 +31050 -0.861297607421875 +31051 -0.80126953125 +31052 -0.863250732421875 +31053 -0.85888671875 +31054 -0.856597900390625 +31055 -0.860809326171875 +31056 -0.7498779296875 +31057 -0.855682373046875 +31058 -0.624542236328125 +31059 -0.8033447265625 +31060 -0.47808837890625 +31061 -0.7076416015625 +31062 -0.253387451171875 +31063 -0.526947021484375 +31064 0.003692626953125 +31065 -0.300872802734375 +31066 0.2257080078125 +31067 -0.08880615234375 +31068 0.427154541015625 +31069 0.120361328125 +31070 0.643218994140625 +31071 0.35504150390625 +31072 0.855926513671875 +31073 0.607025146484375 +31074 0.870361328125 +31075 0.825927734375 +31076 0.870361328125 +31077 0.866912841796875 +31078 0.862762451171875 +31079 0.870361328125 +31080 0.79669189453125 +31081 0.866241455078125 +31082 0.595794677734375 +31083 0.849365234375 +31084 0.362152099609375 +31085 0.688079833984375 +31086 0.1270751953125 +31087 0.5040283203125 +31088 -0.086944580078125 +31089 0.316253662109375 +31090 -0.2784423828125 +31091 0.126708984375 +31092 -0.484832763671875 +31093 -0.095306396484375 +31094 -0.729583740234375 +31095 -0.367431640625 +31096 -0.86688232421875 +31097 -0.646820068359375 +31098 -0.870391845703125 +31099 -0.857269287109375 +31100 -0.86859130859375 +31101 -0.870391845703125 +31102 -0.86279296875 +31103 -0.870391845703125 +31104 -0.817962646484375 +31105 -0.86346435546875 +31106 -0.6116943359375 +31107 -0.778167724609375 +31108 -0.3128662109375 +31109 -0.52508544921875 +31110 0.039398193359375 +31111 -0.211395263671875 +31112 0.422821044921875 +31113 0.142669677734375 +31114 0.805145263671875 +31115 0.50750732421875 +31116 0.870361328125 +31117 0.8251953125 +31118 0.870361328125 +31119 0.870361328125 +31120 0.860015869140625 +31121 0.870361328125 +31122 0.727935791015625 +31123 0.860992431640625 +31124 0.48114013671875 +31125 0.75042724609375 +31126 0.2059326171875 +31127 0.542449951171875 +31128 -0.06103515625 +31129 0.320953369140625 +31130 -0.29913330078125 +31131 0.1038818359375 +31132 -0.516204833984375 +31133 -0.114471435546875 +31134 -0.7252197265625 +31135 -0.343231201171875 +31136 -0.85980224609375 +31137 -0.55914306640625 +31138 -0.870391845703125 +31139 -0.733428955078125 +31140 -0.870391845703125 +31141 -0.844024658203125 +31142 -0.858062744140625 +31143 -0.8544921875 +31144 -0.673004150390625 +31145 -0.769134521484375 +31146 -0.42694091796875 +31147 -0.64306640625 +31148 -0.2100830078125 +31149 -0.525177001953125 +31150 -0.0362548828125 +31151 -0.424102783203125 +31152 0.10943603515625 +31153 -0.32470703125 +31154 0.23516845703125 +31155 -0.219024658203125 +31156 0.373687744140625 +31157 -0.07891845703125 +31158 0.517791748046875 +31159 0.0875244140625 +31160 0.602783203125 +31161 0.221099853515625 +31162 0.635711669921875 +31163 0.324188232421875 +31164 0.655181884765625 +31165 0.425933837890625 +31166 0.65948486328125 +31167 0.519927978515625 +31168 0.651275634765625 +31169 0.603424072265625 +31170 0.61846923828125 +31171 0.660919189453125 +31172 0.53753662109375 +31173 0.667327880859375 +31174 0.404144287109375 +31175 0.614959716796875 +31176 0.22186279296875 +31177 0.503814697265625 +31178 0.003997802734375 +31179 0.3433837890625 +31180 -0.22100830078125 +31181 0.1573486328125 +31182 -0.42449951171875 +31183 -0.029296875 +31184 -0.579833984375 +31185 -0.1922607421875 +31186 -0.641876220703125 +31187 -0.2901611328125 +31188 -0.6177978515625 +31189 -0.326385498046875 +31190 -0.575531005859375 +31191 -0.356689453125 +31192 -0.526336669921875 +31193 -0.386932373046875 +31194 -0.42645263671875 +31195 -0.374847412109375 +31196 -0.2581787109375 +31197 -0.30078125 +31198 -0.068695068359375 +31199 -0.20196533203125 +31200 0.09222412109375 +31201 -0.11834716796875 +31202 0.232147216796875 +31203 -0.04052734375 +31204 0.3509521484375 +31205 0.03338623046875 +31206 0.410064697265625 +31207 0.070953369140625 +31208 0.372955322265625 +31209 0.0406494140625 +31210 0.2554931640625 +31211 -0.044219970703125 +31212 0.10711669921875 +31213 -0.141998291015625 +31214 -0.052886962890625 +31215 -0.238006591796875 +31216 -0.186279296875 +31217 -0.30157470703125 +31218 -0.23291015625 +31219 -0.283416748046875 +31220 -0.209442138671875 +31221 -0.201446533203125 +31222 -0.174163818359375 +31223 -0.109893798828125 +31224 -0.126739501953125 +31225 -0.01177978515625 +31226 -0.048126220703125 +31227 0.106475830078125 +31228 0.0426025390625 +31229 0.22576904296875 +31230 0.10748291015625 +31231 0.31109619140625 +31232 0.1409912109375 +31233 0.35687255859375 +31234 0.19708251953125 +31235 0.410369873046875 +31236 0.273651123046875 +31237 0.469207763671875 +31238 0.31768798828125 +31239 0.4866943359375 +31240 0.341094970703125 +31241 0.47515869140625 +31242 0.368011474609375 +31243 0.458465576171875 +31244 0.37249755859375 +31245 0.415771484375 +31246 0.30072021484375 +31247 0.3013916015625 +31248 0.1517333984375 +31249 0.117279052734375 +31250 -0.01470947265625 +31251 -0.080047607421875 +31252 -0.1883544921875 +31253 -0.278839111328125 +31254 -0.372711181640625 +31255 -0.480072021484375 +31256 -0.51397705078125 +31257 -0.63360595703125 +31258 -0.57177734375 +31259 -0.701873779296875 +31260 -0.53948974609375 +31261 -0.678375244140625 +31262 -0.43511962890625 +31263 -0.579315185546875 +31264 -0.2962646484375 +31265 -0.439117431640625 +31266 -0.161102294921875 +31267 -0.29327392578125 +31268 -0.0435791015625 +31269 -0.1558837890625 +31270 0.060394287109375 +31271 -0.025238037109375 +31272 0.13665771484375 +31273 0.083740234375 +31274 0.170135498046875 +31275 0.15521240234375 +31276 0.16552734375 +31277 0.191131591796875 +31278 0.15728759765625 +31279 0.2203369140625 +31280 0.150787353515625 +31281 0.24578857421875 +31282 0.12200927734375 +31283 0.244293212890625 +31284 0.080108642578125 +31285 0.222930908203125 +31286 0.05126953125 +31287 0.204620361328125 +31288 0.062896728515625 +31289 0.213897705078125 +31290 0.09271240234375 +31291 0.230987548828125 +31292 0.092987060546875 +31293 0.2137451171875 +31294 0.07855224609375 +31295 0.176666259765625 +31296 0.06427001953125 +31297 0.1346435546875 +31298 0.0347900390625 +31299 0.075592041015625 +31300 -0.01171875 +31301 -0.000274658203125 +31302 -0.056060791015625 +31303 -0.073760986328125 +31304 -0.055511474609375 +31305 -0.1046142578125 +31306 -0.010467529296875 +31307 -0.091522216796875 +31308 0.02508544921875 +31309 -0.081695556640625 +31310 0.025665283203125 +31311 -0.09698486328125 +31312 0.017333984375 +31313 -0.113250732421875 +31314 0.00189208984375 +31315 -0.12860107421875 +31316 -0.03173828125 +31317 -0.15313720703125 +31318 -0.071502685546875 +31319 -0.176605224609375 +31320 -0.13543701171875 +31321 -0.216064453125 +31322 -0.219970703125 +31323 -0.26947021484375 +31324 -0.300506591796875 +31325 -0.3160400390625 +31326 -0.376312255859375 +31327 -0.356597900390625 +31328 -0.416107177734375 +31329 -0.364532470703125 +31330 -0.371124267578125 +31331 -0.2974853515625 +31332 -0.242279052734375 +31333 -0.15771484375 +31334 -0.069732666015625 +31335 0.01739501953125 +31336 0.125640869140625 +31337 0.208099365234375 +31338 0.31268310546875 +31339 0.385650634765625 +31340 0.45501708984375 +31341 0.51702880859375 +31342 0.554779052734375 +31343 0.6041259765625 +31344 0.61065673828125 +31345 0.646087646484375 +31346 0.610931396484375 +31347 0.63299560546875 +31348 0.531463623046875 +31349 0.54400634765625 +31350 0.3883056640625 +31351 0.394622802734375 +31352 0.23468017578125 +31353 0.23394775390625 +31354 0.095245361328125 +31355 0.08544921875 +31356 -0.00396728515625 +31357 -0.02618408203125 +31358 -0.04852294921875 +31359 -0.086761474609375 +31360 -0.055145263671875 +31361 -0.1102294921875 +31362 -0.0758056640625 +31363 -0.14251708984375 +31364 -0.138702392578125 +31365 -0.2083740234375 +31366 -0.209197998046875 +31367 -0.2762451171875 +31368 -0.289031982421875 +31369 -0.347625732421875 +31370 -0.37884521484375 +31371 -0.423248291015625 +31372 -0.456329345703125 +31373 -0.483428955078125 +31374 -0.51641845703125 +31375 -0.524261474609375 +31376 -0.519287109375 +31377 -0.5107421875 +31378 -0.458251953125 +31379 -0.43780517578125 +31380 -0.384796142578125 +31381 -0.35284423828125 +31382 -0.323699951171875 +31383 -0.2791748046875 +31384 -0.269287109375 +31385 -0.21270751953125 +31386 -0.1951904296875 +31387 -0.130645751953125 +31388 -0.100006103515625 +31389 -0.032501220703125 +31390 -0.01055908203125 +31391 0.056976318359375 +31392 0.1033935546875 +31393 0.16461181640625 +31394 0.24908447265625 +31395 0.2967529296875 +31396 0.373199462890625 +31397 0.405487060546875 +31398 0.45806884765625 +31399 0.4752197265625 +31400 0.511474609375 +31401 0.51336669921875 +31402 0.565399169921875 +31403 0.54937744140625 +31404 0.61138916015625 +31405 0.576416015625 +31406 0.5897216796875 +31407 0.541534423828125 +31408 0.4906005859375 +31409 0.436798095703125 +31410 0.33148193359375 +31411 0.278778076171875 +31412 0.147796630859375 +31413 0.100128173828125 +31414 -0.01873779296875 +31415 -0.0609130859375 +31416 -0.140289306640625 +31417 -0.178741455078125 +31418 -0.191986083984375 +31419 -0.230560302734375 +31420 -0.184295654296875 +31421 -0.225616455078125 +31422 -0.161834716796875 +31423 -0.204071044921875 +31424 -0.166595458984375 +31425 -0.203887939453125 +31426 -0.19390869140625 +31427 -0.22119140625 +31428 -0.22442626953125 +31429 -0.239013671875 +31430 -0.279754638671875 +31431 -0.27740478515625 +31432 -0.3389892578125 +31433 -0.3182373046875 +31434 -0.3543701171875 +31435 -0.319244384765625 +31436 -0.348175048828125 +31437 -0.301177978515625 +31438 -0.32598876953125 +31439 -0.269744873046875 +31440 -0.2581787109375 +31441 -0.198883056640625 +31442 -0.139801025390625 +31443 -0.084625244140625 +31444 0.014617919921875 +31445 0.05963134765625 +31446 0.144378662109375 +31447 0.178985595703125 +31448 0.221038818359375 +31449 0.247802734375 +31450 0.27069091796875 +31451 0.289642333984375 +31452 0.294036865234375 +31453 0.305389404296875 +31454 0.311767578125 +31455 0.31402587890625 +31456 0.339141845703125 +31457 0.329742431640625 +31458 0.360260009765625 +31459 0.33880615234375 +31460 0.360504150390625 +31461 0.328643798828125 +31462 0.308380126953125 +31463 0.27130126953125 +31464 0.18170166015625 +31465 0.14727783203125 +31466 0.0047607421875 +31467 -0.02093505859375 +31468 -0.17559814453125 +31469 -0.190582275390625 +31470 -0.3143310546875 +31471 -0.3206787109375 +31472 -0.36785888671875 +31473 -0.37164306640625 +31474 -0.36248779296875 +31475 -0.367156982421875 +31476 -0.343536376953125 +31477 -0.348236083984375 +31478 -0.3018798828125 +31479 -0.30682373046875 +31480 -0.231414794921875 +31481 -0.23760986328125 +31482 -0.117645263671875 +31483 -0.127838134765625 +31484 0.007049560546875 +31485 -0.0072021484375 +31486 0.087982177734375 +31487 0.074371337890625 +31488 0.13946533203125 +31489 0.12933349609375 +31490 0.17425537109375 +31491 0.168792724609375 +31492 0.188201904296875 +31493 0.1885986328125 +31494 0.171234130859375 +31495 0.178802490234375 +31496 0.118438720703125 +31497 0.134429931640625 +31498 0.05706787109375 +31499 0.08062744140625 +31500 -0.010711669921875 +31501 0.0191650390625 +31502 -0.0914306640625 +31503 -0.05609130859375 +31504 -0.162322998046875 +31505 -0.123809814453125 +31506 -0.194549560546875 +31507 -0.15692138671875 +31508 -0.1492919921875 +31509 -0.118865966796875 +31510 -0.02166748046875 +31511 -0.004791259765625 +31512 0.124053955078125 +31513 0.12548828125 +31514 0.211151123046875 +31515 0.20050048828125 +31516 0.240447998046875 +31517 0.221435546875 +31518 0.242218017578125 +31519 0.216949462890625 +31520 0.2257080078125 +31521 0.196075439453125 +31522 0.194366455078125 +31523 0.16229248046875 +31524 0.115509033203125 +31525 0.085205078125 +31526 0.0128173828125 +31527 -0.0128173828125 +31528 -0.053802490234375 +31529 -0.07568359375 +31530 -0.110626220703125 +31531 -0.127960205078125 +31532 -0.199493408203125 +31533 -0.20892333984375 +31534 -0.29437255859375 +31535 -0.29437255859375 +31536 -0.33221435546875 +31537 -0.325469970703125 +31538 -0.27972412109375 +31539 -0.2713623046875 +31540 -0.185333251953125 +31541 -0.17767333984375 +31542 -0.128204345703125 +31543 -0.1187744140625 +31544 -0.115692138671875 +31545 -0.101806640625 +31546 -0.116455078125 +31547 -0.097747802734375 +31548 -0.105926513671875 +31549 -0.0838623046875 +31550 -0.053955078125 +31551 -0.032135009765625 +31552 0.048797607421875 +31553 0.066009521484375 +31554 0.157318115234375 +31555 0.16839599609375 +31556 0.212005615234375 +31557 0.219207763671875 +31558 0.218475341796875 +31559 0.223785400390625 +31560 0.23724365234375 +31561 0.2388916015625 +31562 0.30535888671875 +31563 0.299346923828125 +31564 0.38128662109375 +31565 0.366455078125 +31566 0.404449462890625 +31567 0.383758544921875 +31568 0.3944091796875 +31569 0.36981201171875 +31570 0.3885498046875 +31571 0.35986328125 +31572 0.362640380859375 +31573 0.331512451171875 +31574 0.27362060546875 +31575 0.24462890625 +31576 0.11712646484375 +31577 0.095306396484375 +31578 -0.054901123046875 +31579 -0.06768798828125 +31580 -0.19085693359375 +31581 -0.195953369140625 +31582 -0.28570556640625 +31583 -0.284759521484375 +31584 -0.339263916015625 +31585 -0.333984375 +31586 -0.3775634765625 +31587 -0.3680419921875 +31588 -0.445709228515625 +31589 -0.429290771484375 +31590 -0.535064697265625 +31591 -0.50982666015625 +31592 -0.629058837890625 +31593 -0.59429931640625 +31594 -0.697601318359375 +31595 -0.654754638671875 +31596 -0.70391845703125 +31597 -0.656951904296875 +31598 -0.6424560546875 +31599 -0.595916748046875 +31600 -0.491241455078125 +31601 -0.451263427734375 +31602 -0.265716552734375 +31603 -0.23760986328125 +31604 -0.023712158203125 +31605 -0.009185791015625 +31606 0.201751708984375 +31607 0.202972412109375 +31608 0.375823974609375 +31609 0.366241455078125 +31610 0.485076904296875 +31611 0.468048095703125 +31612 0.56884765625 +31613 0.545257568359375 +31614 0.634765625 +31615 0.6051025390625 +31616 0.63763427734375 +31617 0.60540771484375 +31618 0.5660400390625 +31619 0.535614013671875 +31620 0.4720458984375 +31621 0.444610595703125 +31622 0.40692138671875 +31623 0.38055419921875 +31624 0.3778076171875 +31625 0.350311279296875 +31626 0.376953125 +31627 0.3468017578125 +31628 0.371978759765625 +31629 0.33984375 +31630 0.313140869140625 +31631 0.282989501953125 +31632 0.184417724609375 +31633 0.16131591796875 +31634 0.011199951171875 +31635 -0.0013427734375 +31636 -0.171051025390625 +31637 -0.17181396484375 +31638 -0.33740234375 +31639 -0.3267822265625 +31640 -0.47198486328125 +31641 -0.451416015625 +31642 -0.560394287109375 +31643 -0.5323486328125 +31644 -0.58056640625 +31645 -0.549072265625 +31646 -0.54754638671875 +31647 -0.5157470703125 +31648 -0.508575439453125 +31649 -0.47674560546875 +31650 -0.459503173828125 +31651 -0.4283447265625 +31652 -0.394378662109375 +31653 -0.3651123046875 +31654 -0.35260009765625 +31655 -0.324005126953125 +31656 -0.31170654296875 +31657 -0.284088134765625 +31658 -0.197418212890625 +31659 -0.175933837890625 +31660 -0.007965087890625 +31661 0.0020751953125 +31662 0.207489013671875 +31663 0.203857421875 +31664 0.409210205078125 +31665 0.392242431640625 +31666 0.57208251953125 +31667 0.54376220703125 +31668 0.66595458984375 +31669 0.6302490234375 +31670 0.65875244140625 +31671 0.621795654296875 +31672 0.56744384765625 +31673 0.53436279296875 +31674 0.431396484375 +31675 0.404937744140625 +31676 0.29443359375 +31677 0.274658203125 +31678 0.182464599609375 +31679 0.167877197265625 +31680 0.06365966796875 +31681 0.054931640625 +31682 -0.075958251953125 +31683 -0.077178955078125 +31684 -0.189422607421875 +31685 -0.1844482421875 +31686 -0.271942138671875 +31687 -0.2623291015625 +31688 -0.342529296875 +31689 -0.328582763671875 +31690 -0.364166259765625 +31691 -0.348602294921875 +31692 -0.327239990234375 +31693 -0.31341552734375 +31694 -0.2769775390625 +31695 -0.265380859375 +31696 -0.253692626953125 +31697 -0.242279052734375 +31698 -0.24365234375 +31699 -0.231353759765625 +31700 -0.1983642578125 +31701 -0.18731689453125 +31702 -0.116241455078125 +31703 -0.1087646484375 +31704 -0.036834716796875 +31705 -0.03277587890625 +31706 0.034881591796875 +31707 0.035858154296875 +31708 0.09124755859375 +31709 0.08990478515625 +31710 0.10888671875 +31711 0.107452392578125 +31712 0.125518798828125 +31713 0.12371826171875 +31714 0.15771484375 +31715 0.1541748046875 +31716 0.17828369140625 +31717 0.173370361328125 +31718 0.17108154296875 +31719 0.166229248046875 +31720 0.129974365234375 +31721 0.127044677734375 +31722 0.082427978515625 +31723 0.08154296875 +31724 0.027679443359375 +31725 0.02911376953125 +31726 -0.065643310546875 +31727 -0.059539794921875 +31728 -0.15936279296875 +31729 -0.148590087890625 +31730 -0.21307373046875 +31731 -0.200164794921875 +31732 -0.234649658203125 +31733 -0.221588134765625 +31734 -0.2001953125 +31735 -0.1904296875 +31736 -0.119171142578125 +31737 -0.115478515625 +31738 -0.024749755859375 +31739 -0.027740478515625 +31740 0.085784912109375 +31741 0.07537841796875 +31742 0.178131103515625 +31743 0.1617431640625 +31744 0.215576171875 +31745 0.196807861328125 +31746 0.211456298828125 +31747 0.192840576171875 +31748 0.17523193359375 +31749 0.1585693359375 +31750 0.128753662109375 +31751 0.115020751953125 +31752 0.1019287109375 +31753 0.09100341796875 +31754 0.0743408203125 +31755 0.066650390625 +31756 0.04327392578125 +31757 0.039154052734375 +31758 0.038177490234375 +31759 0.036834716796875 +31760 0.076263427734375 +31761 0.07623291015625 +31762 0.14105224609375 +31763 0.141265869140625 +31764 0.186431884765625 +31765 0.1871337890625 +31766 0.188812255859375 +31767 0.19091796875 +31768 0.1390380859375 +31769 0.1436767578125 +31770 0.041778564453125 +31771 0.0499267578125 +31772 -0.079437255859375 +31773 -0.067535400390625 +31774 -0.219390869140625 +31775 -0.20367431640625 +31776 -0.367828369140625 +31777 -0.348480224609375 +31778 -0.494873046875 +31779 -0.47296142578125 +31780 -0.556243896484375 +31781 -0.5341796875 +31782 -0.508697509765625 +31783 -0.490142822265625 +31784 -0.3756103515625 +31785 -0.363372802734375 +31786 -0.218902587890625 +31787 -0.213714599609375 +31788 -0.063751220703125 +31789 -0.065399169921875 +31790 0.091552734375 +31791 0.08331298828125 +31792 0.23602294921875 +31793 0.22186279296875 +31794 0.342987060546875 +31795 0.32452392578125 +31796 0.39520263671875 +31797 0.3746337890625 +31798 0.389373779296875 +31799 0.3690185546875 +31800 0.324249267578125 +31801 0.306427001953125 +31802 0.224090576171875 +31803 0.210296630859375 +31804 0.124267578125 +31805 0.114837646484375 +31806 0.037078857421875 +31807 0.0318603515625 +31808 -0.010101318359375 +31809 -0.01220703125 +31810 -0.019439697265625 +31811 -0.019561767578125 +31812 -0.022796630859375 +31813 -0.0211181640625 +31814 -0.001556396484375 +31815 0.001007080078125 +31816 0.056304931640625 +31817 0.058380126953125 +31818 0.106719970703125 +31819 0.1082763671875 +31820 0.096893310546875 +31821 0.09954833984375 +31822 0.042694091796875 +31823 0.04754638671875 +31824 -0.018035888671875 +31825 -0.01116943359375 +31826 -0.07586669921875 +31827 -0.067413330078125 +31828 -0.11944580078125 +31829 -0.11016845703125 +31830 -0.15972900390625 +31831 -0.150054931640625 +31832 -0.202606201171875 +31833 -0.19268798828125 +31834 -0.24859619140625 +31835 -0.23846435546875 +31836 -0.30517578125 +31837 -0.2945556640625 +31838 -0.36212158203125 +31839 -0.35101318359375 +31840 -0.39141845703125 +31841 -0.380645751953125 +31842 -0.35528564453125 +31843 -0.3468017578125 +31844 -0.249969482421875 +31845 -0.245819091796875 +31846 -0.092864990234375 +31847 -0.094482421875 +31848 0.08905029296875 +31849 0.081146240234375 +31850 0.2352294921875 +31851 0.22247314453125 +31852 0.318817138671875 +31853 0.303497314453125 +31854 0.358642578125 +31855 0.342437744140625 +31856 0.347747802734375 +31857 0.33251953125 +31858 0.28564453125 +31859 0.273223876953125 +31860 0.223175048828125 +31861 0.2137451171875 +31862 0.196746826171875 +31863 0.189239501953125 +31864 0.179840087890625 +31865 0.17401123046875 +31866 0.155548095703125 +31867 0.151611328125 +31868 0.151214599609375 +31869 0.1484375 +31870 0.156951904296875 +31871 0.154876708984375 +31872 0.13177490234375 +31873 0.131195068359375 +31874 0.100799560546875 +31875 0.1016845703125 +31876 0.087127685546875 +31877 0.088653564453125 +31878 0.05487060546875 +31879 0.057403564453125 +31880 -0.009002685546875 +31881 -0.004669189453125 +31882 -0.10400390625 +31883 -0.0970458984375 +31884 -0.229400634765625 +31885 -0.21905517578125 +31886 -0.35552978515625 +31887 -0.3419189453125 +31888 -0.441925048828125 +31889 -0.4263916015625 +31890 -0.473846435546875 +31891 -0.458221435546875 +31892 -0.464813232421875 +31893 -0.45037841796875 +31894 -0.419097900390625 +31895 -0.406951904296875 +31896 -0.334320068359375 +31897 -0.32562255859375 +31898 -0.227935791015625 +31899 -0.223236083984375 +31900 -0.12347412109375 +31901 -0.12255859375 +31902 -0.02764892578125 +31903 -0.030059814453125 +31904 0.077667236328125 +31905 0.07183837890625 +31906 0.2132568359375 +31907 0.203216552734375 +31908 0.38885498046875 +31909 0.37347412109375 +31910 0.582794189453125 +31911 0.5616455078125 +31912 0.734039306640625 +31913 0.7086181640625 +31914 0.800140380859375 +31915 0.77325439453125 +31916 0.7783203125 +31917 0.752838134765625 +31918 0.6651611328125 +31919 0.644012451171875 +31920 0.45965576171875 +31921 0.445770263671875 +31922 0.199188232421875 +31923 0.194244384765625 +31924 -0.050689697265625 +31925 -0.047149658203125 +31926 -0.23297119140625 +31927 -0.223236083984375 +31928 -0.33013916015625 +31929 -0.31707763671875 +31930 -0.368408203125 +31931 -0.354034423828125 +31932 -0.378936767578125 +31933 -0.3642578125 +31934 -0.376983642578125 +31935 -0.362548828125 +31936 -0.37969970703125 +31937 -0.365509033203125 +31938 -0.391510009765625 +31939 -0.377349853515625 +31940 -0.385345458984375 +31941 -0.37188720703125 +31942 -0.3419189453125 +31943 -0.330413818359375 +31944 -0.28289794921875 +31945 -0.27386474609375 +31946 -0.251617431640625 +31947 -0.244140625 +31948 -0.266143798828125 +31949 -0.258697509765625 +31950 -0.273345947265625 +31951 -0.266082763671875 +31952 -0.216796875 +31953 -0.211669921875 +31954 -0.128265380859375 +31955 -0.12615966796875 +31956 -0.068145751953125 +31957 -0.06805419921875 +31958 -0.0430908203125 +31959 -0.04376220703125 +31960 -0.024444580078125 +31961 -0.025543212890625 +31962 0.020721435546875 +31963 0.018463134765625 +31964 0.124481201171875 +31965 0.1192626953125 +31966 0.25787353515625 +31967 0.248779296875 +31968 0.379119873046875 +31969 0.3665771484375 +31970 0.47991943359375 +31971 0.464599609375 +31972 0.5281982421875 +31973 0.511749267578125 +31974 0.511138916015625 +31975 0.495635986328125 +31976 0.456207275390625 +31977 0.44281005859375 +31978 0.407470703125 +31979 0.39593505859375 +31980 0.383758544921875 +31981 0.373199462890625 +31982 0.35687255859375 +31983 0.3472900390625 +31984 0.31182861328125 +31985 0.3037109375 +31986 0.250885009765625 +31987 0.24462890625 +31988 0.1654052734375 +31989 0.16168212890625 +31990 0.035247802734375 +31991 0.035400390625 +31992 -0.142059326171875 +31993 -0.1365966796875 +31994 -0.33563232421875 +31995 -0.32440185546875 +31996 -0.5345458984375 +31997 -0.517364501953125 +31998 -0.72186279296875 +31999 -0.699066162109375 +32000 -0.836669921875 +32001 -0.81005859375 +32002 -0.8326416015625 +32003 -0.804901123046875 +32004 -0.7296142578125 +32005 -0.703369140625 +32006 -0.582550048828125 +32007 -0.5599365234375 +32008 -0.440093994140625 +32009 -0.422698974609375 +32010 -0.324310302734375 +32011 -0.313232421875 +32012 -0.20147705078125 +32013 -0.197296142578125 +32014 -0.044647216796875 +32015 -0.047393798828125 +32016 0.103973388671875 +32017 0.094696044921875 +32018 0.202392578125 +32019 0.1873779296875 +32020 0.264495849609375 +32021 0.24481201171875 +32022 0.338897705078125 +32023 0.315887451171875 +32024 0.443817138671875 +32025 0.4189453125 +32026 0.545074462890625 +32027 0.519866943359375 +32028 0.6173095703125 +32029 0.59320068359375 +32030 0.6524658203125 +32031 0.63079833984375 +32032 0.66339111328125 +32033 0.64532470703125 +32034 0.6561279296875 +32035 0.642578125 +32036 0.606781005859375 +32037 0.598358154296875 +32038 0.501190185546875 +32039 0.498199462890625 +32040 0.352783203125 +32041 0.355224609375 +32042 0.176544189453125 +32043 0.184112548828125 +32044 -0.034820556640625 +32045 -0.022674560546875 +32046 -0.258209228515625 +32047 -0.242279052734375 +32048 -0.44244384765625 +32049 -0.4237060546875 +32050 -0.5753173828125 +32051 -0.55487060546875 +32052 -0.65203857421875 +32053 -0.63104248046875 +32054 -0.641632080078125 +32055 -0.621246337890625 +32056 -0.562164306640625 +32057 -0.543487548828125 +32058 -0.458038330078125 +32059 -0.442047119140625 +32060 -0.350555419921875 +32061 -0.338043212890625 +32062 -0.260528564453125 +32063 -0.2520751953125 +32064 -0.192108154296875 +32065 -0.188079833984375 +32066 -0.141937255859375 +32067 -0.1424560546875 +32068 -0.1021728515625 +32069 -0.107086181640625 +32070 -0.062896728515625 +32071 -0.07183837890625 +32072 -0.011932373046875 +32073 -0.0242919921875 +32074 0.062835693359375 +32075 0.047821044921875 +32076 0.148712158203125 +32077 0.131988525390625 +32078 0.241729736328125 +32079 0.2242431640625 +32080 0.34912109375 +32081 0.33184814453125 +32082 0.457305908203125 +32083 0.441192626953125 +32084 0.54388427734375 +32085 0.52978515625 +32086 0.5728759765625 +32087 0.561492919921875 +32088 0.506591796875 +32089 0.49847412109375 +32090 0.351226806640625 +32091 0.34674072265625 +32092 0.146514892578125 +32093 0.145782470703125 +32094 -0.05523681640625 +32095 -0.052276611328125 +32096 -0.21624755859375 +32097 -0.2098388671875 +32098 -0.334930419921875 +32099 -0.325469970703125 +32100 -0.402984619140625 +32101 -0.391082763671875 +32102 -0.4412841796875 +32103 -0.427642822265625 +32104 -0.49578857421875 +32105 -0.481201171875 +32106 -0.5601806640625 +32107 -0.54547119140625 +32108 -0.600738525390625 +32109 -0.586700439453125 +32110 -0.584228515625 +32111 -0.571624755859375 +32112 -0.47930908203125 +32113 -0.468780517578125 +32114 -0.27935791015625 +32115 -0.27142333984375 +32116 -0.0089111328125 +32117 -0.00390625 +32118 0.268798828125 +32119 0.270660400390625 +32120 0.482818603515625 +32121 0.4815673828125 +32122 0.60369873046875 +32123 0.5994873046875 +32124 0.650421142578125 +32125 0.6435546875 +32126 0.66400146484375 +32127 0.654937744140625 +32128 0.6414794921875 +32129 0.630767822265625 +32130 0.572540283203125 +32131 0.560821533203125 +32132 0.498138427734375 +32133 0.486053466796875 +32134 0.439453125 +32135 0.42767333984375 +32136 0.375518798828125 +32137 0.36468505859375 +32138 0.274505615234375 +32139 0.265167236328125 +32140 0.1087646484375 +32141 0.10137939453125 +32142 -0.099395751953125 +32143 -0.1044921875 +32144 -0.3182373046875 +32145 -0.320831298828125 +32146 -0.5489501953125 +32147 -0.548980712890625 +32148 -0.7738037109375 +32149 -0.771331787109375 +32150 -0.86383056640625 +32151 -0.863311767578125 +32152 -0.870391845703125 +32153 -0.870391845703125 +32154 -0.86895751953125 +32155 -0.869476318359375 +32156 -0.861053466796875 +32157 -0.862030029296875 +32158 -0.765869140625 +32159 -0.77838134765625 +32160 -0.5301513671875 +32161 -0.5455322265625 +32162 -0.214691162109375 +32163 -0.232025146484375 +32164 0.137359619140625 +32165 0.119049072265625 +32166 0.474822998046875 +32167 0.45654296875 +32168 0.76239013671875 +32169 0.7451171875 +32170 0.867462158203125 +32171 0.86578369140625 +32172 0.870361328125 +32173 0.870361328125 +32174 0.86480712890625 +32175 0.866424560546875 +32176 0.831817626953125 +32177 0.855133056640625 +32178 0.677581787109375 +32179 0.7178955078125 +32180 0.495880126953125 +32181 0.545379638671875 +32182 0.30767822265625 +32183 0.3634033203125 +32184 0.116180419921875 +32185 0.1749267578125 +32186 -0.110748291015625 +32187 -0.05224609375 +32188 -0.381805419921875 +32189 -0.32672119140625 +32190 -0.6572265625 +32191 -0.60845947265625 +32192 -0.857421875 +32193 -0.841217041015625 +32194 -0.870391845703125 +32195 -0.868896484375 +32196 -0.870391845703125 +32197 -0.870391845703125 +32198 -0.86444091796875 +32199 -0.865875244140625 +32200 -0.85723876953125 +32201 -0.860015869140625 +32202 -0.790008544921875 +32203 -0.825897216796875 +32204 -0.62847900390625 +32205 -0.67254638671875 +32206 -0.3956298828125 +32207 -0.445220947265625 +32208 -0.126708984375 +32209 -0.178955078125 +32210 0.150115966796875 +32211 0.09814453125 +32212 0.424041748046875 +32213 0.375152587890625 +32214 0.670623779296875 +32215 0.627410888671875 +32216 0.854522705078125 +32217 0.819610595703125 +32218 0.866485595703125 +32219 0.8636474609375 +32220 0.86920166015625 +32221 0.8675537109375 +32222 0.8653564453125 +32223 0.86492919921875 +32224 0.857147216796875 +32225 0.857940673828125 +32226 0.766845703125 +32227 0.784393310546875 +32228 0.628509521484375 +32229 0.655181884765625 +32230 0.462127685546875 +32231 0.4962158203125 +32232 0.297210693359375 +32233 0.336639404296875 +32234 0.14862060546875 +32235 0.19110107421875 +32236 -0.00537109375 +32237 0.0377197265625 +32238 -0.15753173828125 +32239 -0.116180419921875 +32240 -0.31304931640625 +32241 -0.275634765625 +32242 -0.48876953125 +32243 -0.45721435546875 +32244 -0.6416015625 +32245 -0.617462158203125 +32246 -0.751373291015625 +32247 -0.735748291015625 +32248 -0.84619140625 +32249 -0.839691162109375 +32250 -0.861297607421875 +32251 -0.861572265625 +32252 -0.863250732421875 +32253 -0.864501953125 +32254 -0.856597900390625 +32255 -0.85870361328125 +32256 -0.749298095703125 +32257 -0.775909423828125 +32258 -0.62200927734375 +32259 -0.655609130859375 +32260 -0.473663330078125 +32261 -0.512359619140625 +32262 -0.249298095703125 +32263 -0.288909912109375 +32264 0.00634765625 +32265 -0.03106689453125 +32266 0.227630615234375 +32267 0.193603515625 +32268 0.42828369140625 +32269 0.39935302734375 +32270 0.642120361328125 +32271 0.621124267578125 +32272 0.85540771484375 +32273 0.8524169921875 +32274 0.870361328125 +32275 0.870361328125 +32276 0.870361328125 +32277 0.870361328125 +32278 0.862823486328125 +32279 0.862762451171875 +32280 0.798126220703125 +32281 0.79669189453125 +32282 0.598968505859375 +32283 0.595794677734375 +32284 0.3670654296875 +32285 0.362152099609375 +32286 0.133056640625 +32287 0.1270751953125 +32288 -0.080902099609375 +32289 -0.086944580078125 +32290 -0.2730712890625 +32291 -0.2784423828125 +32292 -0.479248046875 +32293 -0.484832763671875 +32294 -0.72186279296875 +32295 -0.729583740234375 +32296 -0.86572265625 +32297 -0.86688232421875 +32298 -0.870391845703125 +32299 -0.870391845703125 +32300 -0.86968994140625 +32301 -0.86859130859375 +32302 -0.8648681640625 +32303 -0.86279296875 +32304 -0.8447265625 +32305 -0.817962646484375 +32306 -0.64630126953125 +32307 -0.6116943359375 +32308 -0.35528564453125 +32309 -0.3128662109375 +32310 -0.00970458984375 +32311 0.039398193359375 +32312 0.3685302734375 +32313 0.422821044921875 +32314 0.747711181640625 +32315 0.805145263671875 +32316 0.870361328125 +32317 0.870361328125 +32318 0.870361328125 +32319 0.870361328125 +32320 0.86016845703125 +32321 0.860015869140625 +32322 0.7315673828125 +32323 0.727935791015625 +32324 0.48797607421875 +32325 0.48114013671875 +32326 0.215789794921875 +32327 0.2059326171875 +32328 -0.049163818359375 +32329 -0.06103515625 +32330 -0.28656005859375 +32331 -0.29913330078125 +32332 -0.50360107421875 +32333 -0.516204833984375 +32334 -0.71240234375 +32335 -0.7252197265625 +32336 -0.8583984375 +32337 -0.85980224609375 +32338 -0.870391845703125 +32339 -0.870391845703125 +32340 -0.870391845703125 +32341 -0.870391845703125 +32342 -0.8582763671875 +32343 -0.858062744140625 +32344 -0.6783447265625 +32345 -0.673004150390625 +32346 -0.435394287109375 +32347 -0.42694091796875 +32348 -0.219696044921875 +32349 -0.2100830078125 +32350 -0.044921875 +32351 -0.0362548828125 +32352 0.10296630859375 +32353 0.10943603515625 +32354 0.23150634765625 +32355 0.23516845703125 +32356 0.37200927734375 +32357 0.373687744140625 +32358 0.51715087890625 +32359 0.517791748046875 +32360 0.604034423828125 +32361 0.602783203125 +32362 0.639312744140625 +32363 0.635711669921875 +32364 0.66015625 +32365 0.655181884765625 +32366 0.66485595703125 +32367 0.65948486328125 +32368 0.655975341796875 +32369 0.651275634765625 +32370 0.62188720703125 +32371 0.61846923828125 +32372 0.540008544921875 +32373 0.53753662109375 +32374 0.4063720703125 +32375 0.404144287109375 +32376 0.224700927734375 +32377 0.22186279296875 +32378 0.008209228515625 +32379 0.003997802734375 +32380 -0.21527099609375 +32381 -0.22100830078125 +32382 -0.417724609375 +32383 -0.42449951171875 +32384 -0.573028564453125 +32385 -0.579833984375 +32386 -0.637237548828125 +32387 -0.641876220703125 +32388 -0.617095947265625 +32389 -0.6177978515625 +32390 -0.578216552734375 +32391 -0.575531005859375 +32392 -0.53143310546875 +32393 -0.526336669921875 +32394 -0.43438720703125 +32395 -0.42645263671875 +32396 -0.269927978515625 +32397 -0.2581787109375 +32398 -0.083892822265625 +32399 -0.068695068359375 +32400 0.07537841796875 +32401 0.09222412109375 +32402 0.2149658203125 +32403 0.232147216796875 +32404 0.33453369140625 +32405 0.3509521484375 +32406 0.396453857421875 +32407 0.410064697265625 +32408 0.3651123046875 +32409 0.372955322265625 +32410 0.255645751953125 +32411 0.2554931640625 +32412 0.115692138671875 +32413 0.10711669921875 +32414 -0.036285400390625 +32415 -0.052886962890625 +32416 -0.163360595703125 +32417 -0.186279296875 +32418 -0.20745849609375 +32419 -0.23291015625 +32420 -0.1846923828125 +32421 -0.209442138671875 +32422 -0.151458740234375 +32423 -0.174163818359375 +32424 -0.107391357421875 +32425 -0.126739501953125 +32426 -0.033935546875 +32427 -0.048126220703125 +32428 0.050628662109375 +32429 0.0426025390625 +32430 0.109771728515625 +32431 0.10748291015625 +32432 0.138336181640625 +32433 0.1409912109375 +32434 0.188751220703125 +32435 0.19708251953125 +32436 0.25921630859375 +32437 0.273651123046875 +32438 0.298614501953125 +32439 0.31768798828125 +32440 0.318603515625 +32441 0.341094970703125 +32442 0.34271240234375 +32443 0.368011474609375 +32444 0.34588623046875 +32445 0.37249755859375 +32446 0.27606201171875 +32447 0.30072021484375 +32448 0.132293701171875 +32449 0.1517333984375 +32450 -0.027618408203125 +32451 -0.01470947265625 +32452 -0.193817138671875 +32453 -0.1883544921875 +32454 -0.36981201171875 +32455 -0.372711181640625 +32456 -0.503692626953125 +32457 -0.51397705078125 +32458 -0.556488037109375 +32459 -0.57177734375 +32460 -0.522003173828125 +32461 -0.53948974609375 +32462 -0.4178466796875 +32463 -0.43511962890625 +32464 -0.280609130859375 +32465 -0.2962646484375 +32466 -0.147369384765625 +32467 -0.161102294921875 +32468 -0.031707763671875 +32469 -0.0435791015625 +32470 0.0701904296875 +32471 0.060394287109375 +32472 0.144561767578125 +32473 0.13665771484375 +32474 0.176849365234375 +32475 0.170135498046875 +32476 0.171630859375 +32477 0.16552734375 +32478 0.16229248046875 +32479 0.15728759765625 +32480 0.154144287109375 +32481 0.150787353515625 +32482 0.1240234375 +32483 0.12200927734375 +32484 0.0809326171875 +32485 0.080108642578125 +32486 0.05035400390625 +32487 0.05126953125 +32488 0.05902099609375 +32489 0.062896728515625 +32490 0.08544921875 +32491 0.09271240234375 +32492 0.0836181640625 +32493 0.092987060546875 +32494 0.067962646484375 +32495 0.07855224609375 +32496 0.052947998046875 +32497 0.06427001953125 +32498 0.02374267578125 +32499 0.0347900390625 +32500 -0.021392822265625 +32501 -0.01171875 +32502 -0.06390380859375 +32503 -0.056060791015625 +32504 -0.06243896484375 +32505 -0.055511474609375 +32506 -0.0174560546875 +32507 -0.010467529296875 +32508 0.01873779296875 +32509 0.02508544921875 +32510 0.0213623046875 +32511 0.025665283203125 +32512 0.015289306640625 +32513 0.017333984375 +32514 0.00225830078125 +32515 0.00189208984375 +32516 -0.028289794921875 +32517 -0.03173828125 +32518 -0.06494140625 +32519 -0.071502685546875 +32520 -0.124755859375 +32521 -0.13543701171875 +32522 -0.204345703125 +32523 -0.219970703125 +32524 -0.28033447265625 +32525 -0.300506591796875 +32526 -0.352020263671875 +32527 -0.376312255859375 +32528 -0.38970947265625 +32529 -0.416107177734375 +32530 -0.347076416015625 +32531 -0.371124267578125 +32532 -0.2249755859375 +32533 -0.242279052734375 +32534 -0.061553955078125 +32535 -0.069732666015625 +32536 0.12335205078125 +32537 0.125640869140625 +32538 0.3001708984375 +32539 0.31268310546875 +32540 0.43438720703125 +32541 0.45501708984375 +32542 0.528076171875 +32543 0.554779052734375 +32544 0.580047607421875 +32545 0.61065673828125 +32546 0.579254150390625 +32547 0.610931396484375 +32548 0.502838134765625 +32549 0.531463623046875 +32550 0.366058349609375 +32551 0.3883056640625 +32552 0.219482421875 +32553 0.23468017578125 +32554 0.08660888671875 +32555 0.095245361328125 +32556 -0.007843017578125 +32557 -0.00396728515625 +32558 -0.050140380859375 +32559 -0.04852294921875 +32560 -0.05615234375 +32561 -0.055145263671875 +32562 -0.075347900390625 +32563 -0.0758056640625 +32564 -0.134490966796875 +32565 -0.138702392578125 +32566 -0.200714111328125 +32567 -0.209197998046875 +32568 -0.275726318359375 +32569 -0.289031982421875 +32570 -0.360198974609375 +32571 -0.37884521484375 +32572 -0.432952880859375 +32573 -0.456329345703125 +32574 -0.4892578125 +32575 -0.51641845703125 +32576 -0.491302490234375 +32577 -0.519287109375 +32578 -0.432769775390625 +32579 -0.458251953125 +32580 -0.36260986328125 +32581 -0.384796142578125 +32582 -0.304351806640625 +32583 -0.323699951171875 +32584 -0.252593994140625 +32585 -0.269287109375 +32586 -0.18231201171875 +32587 -0.1951904296875 +32588 -0.0921630859375 +32589 -0.100006103515625 +32590 -0.00762939453125 +32591 -0.01055908203125 +32592 0.10003662109375 +32593 0.1033935546875 +32594 0.237762451171875 +32595 0.24908447265625 +32596 0.354949951171875 +32597 0.373199462890625 +32598 0.43487548828125 +32599 0.45806884765625 +32600 0.48492431640625 +32601 0.511474609375 +32602 0.535552978515625 +32603 0.565399169921875 +32604 0.5787353515625 +32605 0.61138916015625 +32606 0.557769775390625 +32607 0.5897216796875 +32608 0.463348388671875 +32609 0.4906005859375 +32610 0.312103271484375 +32611 0.33148193359375 +32612 0.137664794921875 +32613 0.147796630859375 +32614 -0.020355224609375 +32615 -0.01873779296875 +32616 -0.135498046875 +32617 -0.140289306640625 +32618 -0.184173583984375 +32619 -0.191986083984375 +32620 -0.17633056640625 +32621 -0.184295654296875 +32622 -0.1544189453125 +32623 -0.161834716796875 +32624 -0.1583251953125 +32625 -0.166595458984375 +32626 -0.18365478515625 +32627 -0.19390869140625 +32628 -0.212066650390625 +32629 -0.22442626953125 +32630 -0.26409912109375 +32631 -0.279754638671875 +32632 -0.319976806640625 +32633 -0.3389892578125 +32634 -0.334320068359375 +32635 -0.3543701171875 +32636 -0.32830810546875 +32637 -0.348175048828125 +32638 -0.3072509765625 +32639 -0.32598876953125 +32640 -0.24298095703125 +32641 -0.2581787109375 +32642 -0.13079833984375 +32643 -0.139801025390625 +32644 0.015533447265625 +32645 0.014617919921875 +32646 0.138336181640625 +32647 0.144378662109375 +32648 0.21063232421875 +32649 0.221038818359375 +32650 0.257232666015625 +32651 0.27069091796875 +32652 0.278900146484375 +32653 0.294036865234375 +32654 0.2952880859375 +32655 0.311767578125 +32656 0.320892333984375 +32657 0.339141845703125 +32658 0.34039306640625 +32659 0.360260009765625 +32660 0.339996337890625 +32661 0.360504150390625 +32662 0.290313720703125 +32663 0.308380126953125 +32664 0.17071533203125 +32665 0.18170166015625 +32666 0.004058837890625 +32667 0.0047607421875 +32668 -0.165740966796875 +32669 -0.17559814453125 +32670 -0.2965087890625 +32671 -0.3143310546875 +32672 -0.347381591796875 +32673 -0.36785888671875 +32674 -0.3428955078125 +32675 -0.36248779296875 +32676 -0.325439453125 +32677 -0.343536376953125 +32678 -0.2864990234375 +32679 -0.3018798828125 +32680 -0.220367431640625 +32681 -0.231414794921875 +32682 -0.11346435546875 +32683 -0.117645263671875 +32684 0.00384521484375 +32685 0.007049560546875 +32686 0.080352783203125 +32687 0.087982177734375 +32688 0.12939453125 +32689 0.13946533203125 +32690 0.162872314453125 +32691 0.17425537109375 +32692 0.17681884765625 +32693 0.188201904296875 +32694 0.1617431640625 +32695 0.171234130859375 +32696 0.113006591796875 +32697 0.118438720703125 +32698 0.05609130859375 +32699 0.05706787109375 +32700 -0.006988525390625 +32701 -0.010711669921875 +32702 -0.082366943359375 +32703 -0.0914306640625 +32704 -0.148712158203125 +32705 -0.162322998046875 +32706 -0.179046630859375 +32707 -0.194549560546875 +32708 -0.137054443359375 +32709 -0.1492919921875 +32710 -0.01806640625 +32711 -0.02166748046875 +32712 0.117767333984375 +32713 0.124053955078125 +32714 0.19866943359375 +32715 0.211151123046875 +32716 0.2254638671875 +32717 0.240447998046875 +32718 0.226470947265625 +32719 0.242218017578125 +32720 0.210418701171875 +32721 0.2257080078125 +32722 0.1805419921875 +32723 0.194366455078125 +32724 0.10626220703125 +32725 0.115509033203125 +32726 0.009765625 +32727 0.0128173828125 +32728 -0.052825927734375 +32729 -0.053802490234375 +32730 -0.1060791015625 +32731 -0.110626220703125 +32732 -0.189208984375 +32733 -0.199493408203125 +32734 -0.277801513671875 +32735 -0.29437255859375 +32736 -0.3128662109375 +32737 -0.33221435546875 +32738 -0.2633056640625 +32739 -0.27972412109375 +32740 -0.174468994140625 +32741 -0.185333251953125 +32742 -0.120452880859375 +32743 -0.128204345703125 +32744 -0.108154296875 +32745 -0.115692138671875 +32746 -0.1082763671875 +32747 -0.116455078125 +32748 -0.097900390625 +32749 -0.105926513671875 +32750 -0.048797607421875 +32751 -0.053955078125 +32752 0.0477294921875 +32753 0.048797607421875 +32754 0.1495361328125 +32755 0.157318115234375 +32756 0.2008056640625 +32757 0.212005615234375 +32758 0.206817626953125 +32759 0.218475341796875 +32760 0.2242431640625 +32761 0.23724365234375 +32762 0.287750244140625 +32763 0.30535888671875 +32764 0.35845947265625 +32765 0.38128662109375 +32766 0.37969970703125 +32767 0.404449462890625 +32768 0.36920166015625 +32769 0.3944091796875 +32770 0.361358642578125 +32771 0.3885498046875 +32772 0.334503173828125 +32773 0.362640380859375 +32774 0.25006103515625 +32775 0.27362060546875 +32776 0.10443115234375 +32777 0.11712646484375 +32778 -0.055084228515625 +32779 -0.054901123046875 +32780 -0.181549072265625 +32781 -0.19085693359375 +32782 -0.270233154296875 +32783 -0.28570556640625 +32784 -0.320831298828125 +32785 -0.339263916015625 +32786 -0.35675048828125 +32787 -0.3775634765625 +32788 -0.418701171875 +32789 -0.445709228515625 +32790 -0.4989013671875 +32791 -0.535064697265625 +32792 -0.582427978515625 +32793 -0.629058837890625 +32794 -0.642181396484375 +32795 -0.697601318359375 +32796 -0.64508056640625 +32797 -0.70391845703125 +32798 -0.5863037109375 +32799 -0.6424560546875 +32800 -0.4461669921875 +32801 -0.491241455078125 +32802 -0.238800048828125 +32803 -0.265716552734375 +32804 -0.016693115234375 +32805 -0.023712158203125 +32806 0.190093994140625 +32807 0.201751708984375 +32808 0.34991455078125 +32809 0.375823974609375 +32810 0.45050048828125 +32811 0.485076904296875 +32812 0.52734375 +32813 0.56884765625 +32814 0.58734130859375 +32815 0.634765625 +32816 0.589599609375 +32817 0.63763427734375 +32818 0.523834228515625 +32819 0.5660400390625 +32820 0.437164306640625 +32821 0.4720458984375 +32822 0.376068115234375 +32823 0.40692138671875 +32824 0.347137451171875 +32825 0.3778076171875 +32826 0.343505859375 +32827 0.376953125 +32828 0.3360595703125 +32829 0.371978759765625 +32830 0.280029296875 +32831 0.313140869140625 +32832 0.16107177734375 +32833 0.184417724609375 +32834 0.002288818359375 +32835 0.011199951171875 +32836 -0.1641845703125 +32837 -0.171051025390625 +32838 -0.315704345703125 +32839 -0.33740234375 +32840 -0.437896728515625 +32841 -0.47198486328125 +32842 -0.517730712890625 +32843 -0.560394287109375 +32844 -0.5352783203125 +32845 -0.58056640625 +32846 -0.504180908203125 +32847 -0.54754638671875 +32848 -0.46722412109375 +32849 -0.508575439453125 +32850 -0.4207763671875 +32851 -0.459503173828125 +32852 -0.359588623046875 +32853 -0.394378662109375 +32854 -0.319427490234375 +32855 -0.35260009765625 +32856 -0.28009033203125 +32857 -0.31170654296875 +32858 -0.174560546875 +32859 -0.197418212890625 +32860 -0.001312255859375 +32861 -0.007965087890625 +32862 0.195068359375 +32863 0.207489013671875 +32864 0.3785400390625 +32865 0.409210205078125 +32866 0.5263671875 +32867 0.57208251953125 +32868 0.611297607421875 +32869 0.66595458984375 +32870 0.604339599609375 +32871 0.65875244140625 +32872 0.5208740234375 +32873 0.56744384765625 +32874 0.39654541015625 +32875 0.431396484375 +32876 0.271087646484375 +32877 0.29443359375 +32878 0.167999267578125 +32879 0.182464599609375 +32880 0.058624267578125 +32881 0.06365966796875 +32882 -0.069549560546875 +32883 -0.075958251953125 +32884 -0.1739501953125 +32885 -0.189422607421875 +32886 -0.25018310546875 +32887 -0.271942138671875 +32888 -0.315338134765625 +32889 -0.342529296875 +32890 -0.335906982421875 +32891 -0.364166259765625 +32892 -0.30316162109375 +32893 -0.327239990234375 +32894 -0.2579345703125 +32895 -0.2769775390625 +32896 -0.236663818359375 +32897 -0.253692626953125 +32898 -0.226959228515625 +32899 -0.24365234375 +32900 -0.18505859375 +32901 -0.1983642578125 +32902 -0.10955810546875 +32903 -0.116241455078125 +32904 -0.036285400390625 +32905 -0.036834716796875 +32906 0.0301513671875 +32907 0.034881591796875 +32908 0.082733154296875 +32909 0.09124755859375 +32910 0.100250244140625 +32911 0.10888671875 +32912 0.11669921875 +32913 0.125518798828125 +32914 0.147003173828125 +32915 0.15771484375 +32916 0.16650390625 +32917 0.17828369140625 +32918 0.160552978515625 +32919 0.17108154296875 +32920 0.123626708984375 +32921 0.129974365234375 +32922 0.080535888671875 +32923 0.082427978515625 +32924 0.0306396484375 +32925 0.027679443359375 +32926 -0.054412841796875 +32927 -0.065643310546875 +32928 -0.140045166015625 +32929 -0.15936279296875 +32930 -0.189727783203125 +32931 -0.21307373046875 +32932 -0.210479736328125 +32933 -0.234649658203125 +32934 -0.180633544921875 +32935 -0.2001953125 +32936 -0.108673095703125 +32937 -0.119171142578125 +32938 -0.024505615234375 +32939 -0.024749755859375 +32940 0.074371337890625 +32941 0.085784912109375 +32942 0.157012939453125 +32943 0.178131103515625 +32944 0.190277099609375 +32945 0.215576171875 +32946 0.18621826171875 +32947 0.211456298828125 +32948 0.153411865234375 +32949 0.17523193359375 +32950 0.111602783203125 +32951 0.128753662109375 +32952 0.087799072265625 +32953 0.1019287109375 +32954 0.06353759765625 +32955 0.0743408203125 +32956 0.03631591796875 +32957 0.04327392578125 +32958 0.032684326171875 +32959 0.038177490234375 +32960 0.06817626953125 +32961 0.076263427734375 +32962 0.127838134765625 +32963 0.14105224609375 +32964 0.169921875 +32965 0.186431884765625 +32966 0.17303466796875 +32967 0.188812255859375 +32968 0.12884521484375 +32969 0.1390380859375 +32970 0.04156494140625 +32971 0.041778564453125 +32972 -0.06756591796875 +32973 -0.079437255859375 +32974 -0.19390869140625 +32975 -0.219390869140625 +32976 -0.328155517578125 +32977 -0.367828369140625 +32978 -0.44329833984375 +32979 -0.494873046875 +32980 -0.499298095703125 +32981 -0.556243896484375 +32982 -0.45703125 +32983 -0.508697509765625 +32984 -0.337554931640625 +32985 -0.3756103515625 +32986 -0.196807861328125 +32987 -0.218902587890625 +32988 -0.0574951171875 +32989 -0.063751220703125 +32990 0.08197021484375 +32991 0.091552734375 +32992 0.211700439453125 +32993 0.23602294921875 +32994 0.3076171875 +32995 0.342987060546875 +32996 0.354217529296875 +32997 0.39520263671875 +32998 0.348541259765625 +32999 0.389373779296875 +33000 0.289459228515625 +33001 0.324249267578125 +33002 0.198883056640625 +33003 0.224090576171875 +33004 0.10882568359375 +33005 0.124267578125 +33006 0.03033447265625 +33007 0.037078857421875 +33008 -0.0118408203125 +33009 -0.010101318359375 +33010 -0.019683837890625 +33011 -0.019439697265625 +33012 -0.022003173828125 +33013 -0.022796630859375 +33014 -0.00201416015625 +33015 -0.001556396484375 +33016 0.05108642578125 +33017 0.056304931640625 +33018 0.097412109375 +33019 0.106719970703125 +33020 0.089202880859375 +33021 0.096893310546875 +33022 0.040802001953125 +33023 0.042694091796875 +33024 -0.01336669921875 +33025 -0.018035888671875 +33026 -0.06494140625 +33027 -0.07586669921875 +33028 -0.104248046875 +33029 -0.11944580078125 +33030 -0.140716552734375 +33031 -0.15972900390625 +33032 -0.179351806640625 +33033 -0.202606201171875 +33034 -0.220489501953125 +33035 -0.24859619140625 +33036 -0.270538330078125 +33037 -0.30517578125 +33038 -0.320587158203125 +33039 -0.36212158203125 +33040 -0.34619140625 +33041 -0.39141845703125 +33042 -0.31439208984375 +33043 -0.35528564453125 +33044 -0.22198486328125 +33045 -0.249969482421875 +33046 -0.084197998046875 +33047 -0.092864990234375 +33048 0.075408935546875 +33049 0.08905029296875 +33050 0.2039794921875 +33051 0.2352294921875 +33052 0.27801513671875 +33053 0.318817138671875 +33054 0.313873291015625 +33055 0.358642578125 +33056 0.305419921875 +33057 0.347747802734375 +33058 0.252166748046875 +33059 0.28564453125 +33060 0.198394775390625 +33061 0.223175048828125 +33062 0.175811767578125 +33063 0.196746826171875 +33064 0.16131591796875 +33065 0.179840087890625 +33066 0.14013671875 +33067 0.155548095703125 +33068 0.1361083984375 +33069 0.151214599609375 +33070 0.140625 +33071 0.156951904296875 +33072 0.11798095703125 +33073 0.13177490234375 +33074 0.090118408203125 +33075 0.100799560546875 +33076 0.07720947265625 +33077 0.087127685546875 +33078 0.048065185546875 +33079 0.05487060546875 +33080 -0.008636474609375 +33081 -0.009002685546875 +33082 -0.092376708984375 +33083 -0.10400390625 +33084 -0.2025146484375 +33085 -0.229400634765625 +33086 -0.3131103515625 +33087 -0.35552978515625 +33088 -0.38885498046875 +33089 -0.441925048828125 +33090 -0.41693115234375 +33091 -0.473846435546875 +33092 -0.4090576171875 +33093 -0.464813232421875 +33094 -0.36895751953125 +33095 -0.419097900390625 +33096 -0.29461669921875 +33097 -0.334320068359375 +33098 -0.20123291015625 +33099 -0.227935791015625 +33100 -0.109405517578125 +33101 -0.12347412109375 +33102 -0.0250244140625 +33103 -0.02764892578125 +33104 0.06768798828125 +33105 0.077667236328125 +33106 0.186767578125 +33107 0.2132568359375 +33108 0.340667724609375 +33109 0.38885498046875 +33110 0.51043701171875 +33111 0.582794189453125 +33112 0.642822265625 +33113 0.734039306640625 +33114 0.7008056640625 +33115 0.800140380859375 +33116 0.68194580078125 +33117 0.7783203125 +33118 0.583282470703125 +33119 0.6651611328125 +33120 0.4039306640625 +33121 0.45965576171875 +33122 0.176483154296875 +33123 0.199188232421875 +33124 -0.0418701171875 +33125 -0.050689697265625 +33126 -0.201385498046875 +33127 -0.23297119140625 +33128 -0.286773681640625 +33129 -0.33013916015625 +33130 -0.32086181640625 +33131 -0.368408203125 +33132 -0.33074951171875 +33133 -0.378936767578125 +33134 -0.3297119140625 +33135 -0.376983642578125 +33136 -0.332672119140625 +33137 -0.37969970703125 +33138 -0.34344482421875 +33139 -0.391510009765625 +33140 -0.338409423828125 +33141 -0.385345458984375 +33142 -0.300750732421875 +33143 -0.3419189453125 +33144 -0.249359130859375 +33145 -0.28289794921875 +33146 -0.22198486328125 +33147 -0.251617431640625 +33148 -0.234405517578125 +33149 -0.266143798828125 +33150 -0.24029541015625 +33151 -0.273345947265625 +33152 -0.19049072265625 +33153 -0.216796875 +33154 -0.112701416015625 +33155 -0.128265380859375 +33156 -0.0596923828125 +33157 -0.068145751953125 +33158 -0.037261962890625 +33159 -0.0430908203125 +33160 -0.02044677734375 +33161 -0.024444580078125 +33162 0.01947021484375 +33163 0.020721435546875 +33164 0.11041259765625 +33165 0.124481201171875 +33166 0.22705078125 +33167 0.25787353515625 +33168 0.33294677734375 +33169 0.379119873046875 +33170 0.4208984375 +33171 0.47991943359375 +33172 0.462921142578125 +33173 0.5281982421875 +33174 0.447845458984375 +33175 0.511138916015625 +33176 0.399627685546875 +33177 0.456207275390625 +33178 0.356719970703125 +33179 0.407470703125 +33180 0.335601806640625 +33181 0.383758544921875 +33182 0.311676025390625 +33183 0.35687255859375 +33184 0.271881103515625 +33185 0.31182861328125 +33186 0.218231201171875 +33187 0.250885009765625 +33188 0.143218994140625 +33189 0.1654052734375 +33190 0.029327392578125 +33191 0.035247802734375 +33192 -0.125579833984375 +33193 -0.142059326171875 +33194 -0.294586181640625 +33195 -0.33563232421875 +33196 -0.4681396484375 +33197 -0.5345458984375 +33198 -0.631439208984375 +33199 -0.72186279296875 +33200 -0.73138427734375 +33201 -0.836669921875 +33202 -0.72760009765625 +33203 -0.8326416015625 +33204 -0.637420654296875 +33205 -0.7296142578125 +33206 -0.508758544921875 +33207 -0.582550048828125 +33208 -0.384063720703125 +33209 -0.440093994140625 +33210 -0.282623291015625 +33211 -0.324310302734375 +33212 -0.175079345703125 +33213 -0.20147705078125 +33214 -0.03790283203125 +33215 -0.044647216796875 +33216 0.092071533203125 +33217 0.103973388671875 +33218 0.17816162109375 +33219 0.202392578125 +33220 0.23248291015625 +33221 0.264495849609375 +33222 0.29742431640625 +33223 0.338897705078125 +33224 0.38885498046875 +33225 0.443817138671875 +33226 0.47698974609375 +33227 0.545074462890625 +33228 0.539703369140625 +33229 0.6173095703125 +33230 0.57000732421875 +33231 0.6524658203125 +33232 0.579132080078125 +33233 0.66339111328125 +33234 0.572357177734375 +33235 0.6561279296875 +33236 0.528900146484375 +33237 0.606781005859375 +33238 0.436431884765625 +33239 0.501190185546875 +33240 0.306671142578125 +33241 0.352783203125 +33242 0.152679443359375 +33243 0.176544189453125 +33244 -0.031829833984375 +33245 -0.034820556640625 +33246 -0.22674560546875 +33247 -0.258209228515625 +33248 -0.387451171875 +33249 -0.44244384765625 +33250 -0.503265380859375 +33251 -0.5753173828125 +33252 -0.57000732421875 +33253 -0.65203857421875 +33254 -0.560699462890625 +33255 -0.641632080078125 +33256 -0.491119384765625 +33257 -0.562164306640625 +33258 -0.399993896484375 +33259 -0.458038330078125 +33260 -0.305877685546875 +33261 -0.350555419921875 +33262 -0.22698974609375 +33263 -0.260528564453125 +33264 -0.166961669921875 +33265 -0.192108154296875 +33266 -0.1229248046875 +33267 -0.141937255859375 +33268 -0.0880126953125 +33269 -0.1021728515625 +33270 -0.0535888671875 +33271 -0.062896728515625 +33272 -0.009033203125 +33273 -0.011932373046875 +33274 0.05621337890625 +33275 0.062835693359375 +33276 0.131072998046875 +33277 0.148712158203125 +33278 0.212066650390625 +33279 0.241729736328125 +33280 0.305206298828125 +33281 0.34912109375 +33282 0.397918701171875 +33283 0.457305908203125 +33284 0.47076416015625 +33285 0.54388427734375 +33286 0.493896484375 +33287 0.5728759765625 +33288 0.436004638671875 +33289 0.506591796875 +33290 0.302642822265625 +33291 0.351226806640625 +33292 0.127471923828125 +33293 0.146514892578125 +33294 -0.0452880859375 +33295 -0.05523681640625 +33296 -0.183685302734375 +33297 -0.21624755859375 +33298 -0.286163330078125 +33299 -0.334930419921875 +33300 -0.345611572265625 +33301 -0.402984619140625 +33302 -0.37945556640625 +33303 -0.4412841796875 +33304 -0.42626953125 +33305 -0.49578857421875 +33306 -0.480712890625 +33307 -0.5601806640625 +33308 -0.51446533203125 +33309 -0.600738525390625 +33310 -0.49969482421875 +33311 -0.584228515625 +33312 -0.410125732421875 +33313 -0.47930908203125 +33314 -0.2403564453125 +33315 -0.27935791015625 +33316 -0.0111083984375 +33317 -0.0089111328125 +33318 0.224365234375 +33319 0.268798828125 +33320 0.4063720703125 +33321 0.482818603515625 +33322 0.510040283203125 +33323 0.60369873046875 +33324 0.551177978515625 +33325 0.650421142578125 +33326 0.56414794921875 +33327 0.66400146484375 +33328 0.54638671875 +33329 0.6414794921875 +33330 0.489166259765625 +33331 0.572540283203125 +33332 0.4268798828125 +33333 0.498138427734375 +33334 0.3773193359375 +33335 0.439453125 +33336 0.322906494140625 +33337 0.375518798828125 +33338 0.2369384765625 +33339 0.274505615234375 +33340 0.096282958984375 +33341 0.1087646484375 +33342 -0.080230712890625 +33343 -0.099395751953125 +33344 -0.265838623046875 +33345 -0.3182373046875 +33346 -0.461456298828125 +33347 -0.5489501953125 +33348 -0.65203857421875 +33349 -0.7738037109375 +33350 -0.793060302734375 +33351 -0.86383056640625 +33352 -0.854736328125 +33353 -0.870391845703125 +33354 -0.85479736328125 +33355 -0.86895751953125 +33356 -0.806060791015625 +33357 -0.861053466796875 +33358 -0.6885986328125 +33359 -0.765869140625 +33360 -0.495330810546875 +33361 -0.5301513671875 +33362 -0.23223876953125 +33363 -0.214691162109375 +33364 0.064453125 +33365 0.137359619140625 +33366 0.351593017578125 +33367 0.474822998046875 +33368 0.599273681640625 +33369 0.76239013671875 +33370 0.784759521484375 +33371 0.867462158203125 +33372 0.8603515625 +33373 0.870361328125 +33374 0.865997314453125 +33375 0.86480712890625 +33376 0.86431884765625 +33377 0.831817626953125 +33378 0.8575439453125 +33379 0.677581787109375 +33380 0.778106689453125 +33381 0.495880126953125 +33382 0.647186279296875 +33383 0.30767822265625 +33384 0.491546630859375 +33385 0.116180419921875 +33386 0.284515380859375 +33387 -0.110748291015625 +33388 0.020294189453125 +33389 -0.381805419921875 +33390 -0.26513671875 +33391 -0.6572265625 +33392 -0.52142333984375 +33393 -0.857421875 +33394 -0.712432861328125 +33395 -0.870391845703125 +33396 -0.83209228515625 +33397 -0.870391845703125 +33398 -0.85980224609375 +33399 -0.86444091796875 +33400 -0.865447998046875 +33401 -0.85723876953125 +33402 -0.867340087890625 +33403 -0.790008544921875 +33404 -0.860504150390625 +33405 -0.62847900390625 +33406 -0.76409912109375 +33407 -0.3956298828125 +33408 -0.563323974609375 +33409 -0.126708984375 +33410 -0.33026123046875 +33411 0.150115966796875 +33412 -0.074737548828125 +33413 0.424041748046875 +33414 0.180572509765625 +33415 0.670623779296875 +33416 0.403106689453125 +33417 0.854522705078125 +33418 0.577972412109375 +33419 0.866485595703125 +33420 0.692138671875 +33421 0.86920166015625 +33422 0.760772705078125 +33423 0.8653564453125 +33424 0.7950439453125 +33425 0.857147216796875 +33426 0.79241943359375 +33427 0.766845703125 +33428 0.757110595703125 +33429 0.628509521484375 +33430 0.683380126953125 +33431 0.462127685546875 +33432 0.5928955078125 +33433 0.297210693359375 +33434 0.49603271484375 +33435 0.14862060546875 +33436 0.37359619140625 +33437 -0.00537109375 +33438 0.231842041015625 +33439 -0.15753173828125 +33440 0.067779541015625 +33441 -0.31304931640625 +33442 -0.13031005859375 +33443 -0.48876953125 +33444 -0.322998046875 +33445 -0.6416015625 +33446 -0.48944091796875 +33447 -0.751373291015625 +33448 -0.64892578125 +33449 -0.84619140625 +33450 -0.788970947265625 +33451 -0.861297607421875 +33452 -0.85748291015625 +33453 -0.863250732421875 +33454 -0.859527587890625 +33455 -0.856597900390625 +33456 -0.854583740234375 +33457 -0.7498779296875 +33458 -0.794952392578125 +33459 -0.624542236328125 +33460 -0.700836181640625 +33461 -0.47808837890625 +33462 -0.52386474609375 +33463 -0.253387451171875 +33464 -0.3023681640625 +33465 0.003692626953125 +33466 -0.09381103515625 +33467 0.2257080078125 +33468 0.112274169921875 +33469 0.427154541015625 +33470 0.343017578125 +33471 0.643218994140625 +33472 0.590240478515625 +33473 0.855926513671875 +33474 0.805145263671875 +33475 0.870361328125 +33476 0.86444091796875 +33477 0.870361328125 +33478 0.870361328125 +33479 0.862762451171875 +33480 0.868682861328125 +33481 0.79669189453125 +33482 0.85870361328125 +33483 0.595794677734375 +33484 0.75067138671875 +33485 0.362152099609375 +33486 0.580963134765625 +33487 0.1270751953125 +33488 0.40228271484375 +33489 -0.086944580078125 +33490 0.216522216796875 +33491 -0.2784423828125 +33492 -0.005584716796875 +33493 -0.484832763671875 +33494 -0.280426025390625 +33495 -0.729583740234375 +33496 -0.56591796875 +33497 -0.86688232421875 +33498 -0.80938720703125 +33499 -0.870391845703125 +33500 -0.870391845703125 +33501 -0.86859130859375 +33502 -0.870391845703125 +33503 -0.86279296875 +33504 -0.863494873046875 +33505 -0.817962646484375 +33506 -0.780487060546875 +33507 -0.6116943359375 +33508 -0.531280517578125 +33509 -0.3128662109375 +33510 -0.22247314453125 +33511 0.039398193359375 +33512 0.126068115234375 +33513 0.422821044921875 +33514 0.48541259765625 +33515 0.805145263671875 +33516 0.79931640625 +33517 0.870361328125 +33518 0.870361328125 +33519 0.870361328125 +33520 0.870361328125 +33521 0.860015869140625 +33522 0.861114501953125 +33523 0.727935791015625 +33524 0.75372314453125 +33525 0.48114013671875 +33526 0.5479736328125 +33527 0.2059326171875 +33528 0.327972412109375 +33529 -0.06103515625 +33530 0.111358642578125 +33531 -0.29913330078125 +33532 -0.10687255859375 +33533 -0.516204833984375 +33534 -0.335113525390625 +33535 -0.7252197265625 +33536 -0.550689697265625 +33537 -0.85980224609375 +33538 -0.72503662109375 +33539 -0.870391845703125 +33540 -0.836578369140625 +33541 -0.870391845703125 +33542 -0.8514404296875 +33543 -0.858062744140625 +33544 -0.773651123046875 +33545 -0.673004150390625 +33546 -0.654541015625 +33547 -0.42694091796875 +33548 -0.539764404296875 +33549 -0.2100830078125 +33550 -0.43780517578125 +33551 -0.0362548828125 +33552 -0.33526611328125 +33553 0.10943603515625 +33554 -0.225372314453125 +33555 0.23516845703125 +33556 -0.08282470703125 +33557 0.373687744140625 +33558 0.084197998046875 +33559 0.517791748046875 +33560 0.220123291015625 +33561 0.602783203125 +33562 0.3265380859375 +33563 0.635711669921875 +33564 0.429931640625 +33565 0.655181884765625 +33566 0.52392578125 +33567 0.65948486328125 +33568 0.60565185546875 +33569 0.651275634765625 +33570 0.66058349609375 +33571 0.61846923828125 +33572 0.66546630859375 +33573 0.53753662109375 +33574 0.613311767578125 +33575 0.404144287109375 +33576 0.504425048828125 +33577 0.22186279296875 +33578 0.347991943359375 +33579 0.003997802734375 +33580 0.166412353515625 +33581 -0.22100830078125 +33582 -0.0166015625 +33583 -0.42449951171875 +33584 -0.17791748046875 +33585 -0.579833984375 +33586 -0.278656005859375 +33587 -0.641876220703125 +33588 -0.321441650390625 +33589 -0.6177978515625 +33590 -0.357421875 +33591 -0.575531005859375 +33592 -0.391632080078125 +33593 -0.526336669921875 +33594 -0.384613037109375 +33595 -0.42645263671875 +33596 -0.3179931640625 +33597 -0.2581787109375 +33598 -0.22625732421875 +33599 -0.068695068359375 +33600 -0.146484375 +33601 0.09222412109375 +33602 -0.070159912109375 +33603 0.232147216796875 +33604 0.00421142578125 +33605 0.3509521484375 +33606 0.046173095703125 +33607 0.410064697265625 +33608 0.026123046875 +33609 0.372955322265625 +33610 -0.0440673828125 +33611 0.2554931640625 +33612 -0.12628173828125 +33613 0.10711669921875 +33614 -0.207366943359375 +33615 -0.052886962890625 +33616 -0.25933837890625 +33617 -0.186279296875 +33618 -0.23687744140625 +33619 -0.23291015625 +33620 -0.1568603515625 +33621 -0.209442138671875 +33622 -0.069732666015625 +33623 -0.174163818359375 +33624 0.021636962890625 +33625 -0.126739501953125 +33626 0.129913330078125 +33627 -0.048126220703125 +33628 0.23748779296875 +33629 0.0426025390625 +33630 0.3121337890625 +33631 0.10748291015625 +33632 0.3485107421875 +33633 0.1409912109375 +33634 0.390045166015625 +33635 0.19708251953125 +33636 0.4356689453125 +33637 0.273651123046875 +33638 0.44378662109375 +33639 0.31768798828125 +33640 0.425811767578125 +33641 0.341094970703125 +33642 0.403564453125 +33643 0.368011474609375 +33644 0.358673095703125 +33645 0.37249755859375 +33646 0.250396728515625 +33647 0.30072021484375 +33648 0.08074951171875 +33649 0.1517333984375 +33650 -0.09930419921875 +33651 -0.01470947265625 +33652 -0.279083251953125 +33653 -0.1883544921875 +33654 -0.45947265625 +33655 -0.372711181640625 +33656 -0.59552001953125 +33657 -0.51397705078125 +33658 -0.653656005859375 +33659 -0.57177734375 +33660 -0.62823486328125 +33661 -0.53948974609375 +33662 -0.5340576171875 +33663 -0.43511962890625 +33664 -0.40234375 +33665 -0.2962646484375 +33666 -0.265289306640625 +33667 -0.161102294921875 +33668 -0.135894775390625 +33669 -0.0435791015625 +33670 -0.012939453125 +33671 0.060394287109375 +33672 0.08984375 +33673 0.13665771484375 +33674 0.15802001953125 +33675 0.170135498046875 +33676 0.193115234375 +33677 0.16552734375 +33678 0.220916748046875 +33679 0.15728759765625 +33680 0.244049072265625 +33681 0.150787353515625 +33682 0.24169921875 +33683 0.12200927734375 +33684 0.2203369140625 +33685 0.080108642578125 +33686 0.20068359375 +33687 0.05126953125 +33688 0.204986572265625 +33689 0.062896728515625 +33690 0.215728759765625 +33691 0.09271240234375 +33692 0.1953125 +33693 0.092987060546875 +33694 0.15704345703125 +33695 0.07855224609375 +33696 0.11456298828125 +33697 0.06427001953125 +33698 0.057281494140625 +33699 0.0347900390625 +33700 -0.014404296875 +33701 -0.01171875 +33702 -0.083099365234375 +33703 -0.056060791015625 +33704 -0.112518310546875 +33705 -0.055511474609375 +33706 -0.101409912109375 +33707 -0.010467529296875 +33708 -0.092132568359375 +33709 0.02508544921875 +33710 -0.104400634765625 +33711 0.025665283203125 +33712 -0.116607666015625 +33713 0.017333984375 +33714 -0.127288818359375 +33715 0.00189208984375 +33716 -0.14569091796875 +33717 -0.03173828125 +33718 -0.16278076171875 +33719 -0.071502685546875 +33720 -0.194091796875 +33721 -0.13543701171875 +33722 -0.238006591796875 +33723 -0.219970703125 +33724 -0.276123046875 +33725 -0.300506591796875 +33726 -0.309356689453125 +33727 -0.376312255859375 +33728 -0.31396484375 +33729 -0.416107177734375 +33730 -0.252044677734375 +33731 -0.371124267578125 +33732 -0.12567138671875 +33733 -0.242279052734375 +33734 0.03155517578125 +33735 -0.069732666015625 +33736 0.201873779296875 +33737 0.125640869140625 +33738 0.359619140625 +33739 0.31268310546875 +33740 0.4752197265625 +33741 0.45501708984375 +33742 0.550537109375 +33743 0.554779052734375 +33744 0.5849609375 +33745 0.61065673828125 +33746 0.569793701171875 +33747 0.610931396484375 +33748 0.48651123046875 +33749 0.531463623046875 +33750 0.349212646484375 +33751 0.3883056640625 +33752 0.2021484375 +33753 0.23468017578125 +33754 0.0665283203125 +33755 0.095245361328125 +33756 -0.035369873046875 +33757 -0.00396728515625 +33758 -0.090728759765625 +33759 -0.04852294921875 +33760 -0.112060546875 +33761 -0.055145263671875 +33762 -0.140594482421875 +33763 -0.0758056640625 +33764 -0.198577880859375 +33765 -0.138702392578125 +33766 -0.25775146484375 +33767 -0.209197998046875 +33768 -0.319580078125 +33769 -0.289031982421875 +33770 -0.3848876953125 +33771 -0.37884521484375 +33772 -0.436126708984375 +33773 -0.456329345703125 +33774 -0.469970703125 +33775 -0.51641845703125 +33776 -0.45513916015625 +33777 -0.519287109375 +33778 -0.38720703125 +33779 -0.458251953125 +33780 -0.308837890625 +33781 -0.384796142578125 +33782 -0.2410888671875 +33783 -0.323699951171875 +33784 -0.18035888671875 +33785 -0.269287109375 +33786 -0.106231689453125 +33787 -0.1951904296875 +33788 -0.018280029296875 +33789 -0.100006103515625 +33790 0.061279296875 +33791 -0.01055908203125 +33792 0.156463623046875 +33793 0.1033935546875 +33794 0.27313232421875 +33795 0.24908447265625 +33796 0.368682861328125 +33797 0.373199462890625 +33798 0.429229736328125 +33799 0.45806884765625 +33800 0.461456298828125 +33801 0.511474609375 +33802 0.4915771484375 +33803 0.565399169921875 +33804 0.5135498046875 +33805 0.61138916015625 +33806 0.48046875 +33807 0.5897216796875 +33808 0.385345458984375 +33809 0.4906005859375 +33810 0.2430419921875 +33811 0.33148193359375 +33812 0.08270263671875 +33813 0.147796630859375 +33814 -0.061614990234375 +33815 -0.01873779296875 +33816 -0.1671142578125 +33817 -0.140289306640625 +33818 -0.2135009765625 +33819 -0.191986083984375 +33820 -0.208984375 +33821 -0.184295654296875 +33822 -0.18927001953125 +33823 -0.161834716796875 +33824 -0.188140869140625 +33825 -0.166595458984375 +33826 -0.20220947265625 +33827 -0.19390869140625 +33828 -0.21649169921875 +33829 -0.22442626953125 +33830 -0.248870849609375 +33831 -0.279754638671875 +33832 -0.2833251953125 +33833 -0.3389892578125 +33834 -0.28240966796875 +33835 -0.3543701171875 +33836 -0.264678955078125 +33837 -0.348175048828125 +33838 -0.235260009765625 +33839 -0.32598876953125 +33840 -0.17108154296875 +33841 -0.2581787109375 +33842 -0.06866455078125 +33843 -0.139801025390625 +33844 0.060028076171875 +33845 0.014617919921875 +33846 0.166168212890625 +33847 0.144378662109375 +33848 0.227020263671875 +33849 0.221038818359375 +33850 0.2635498046875 +33851 0.27069091796875 +33852 0.276580810546875 +33853 0.294036865234375 +33854 0.28302001953125 +33855 0.311767578125 +33856 0.295501708984375 +33857 0.339141845703125 +33858 0.30157470703125 +33859 0.360260009765625 +33860 0.29022216796875 +33861 0.360504150390625 +33862 0.237762451171875 +33863 0.308380126953125 +33864 0.127716064453125 +33865 0.18170166015625 +33866 -0.020294189453125 +33867 0.0047607421875 +33868 -0.169342041015625 +33869 -0.17559814453125 +33870 -0.284027099609375 +33871 -0.3143310546875 +33872 -0.330169677734375 +33873 -0.36785888671875 +33874 -0.3280029296875 +33875 -0.36248779296875 +33876 -0.312652587890625 +33877 -0.343536376953125 +33878 -0.27716064453125 +33879 -0.3018798828125 +33880 -0.217010498046875 +33881 -0.231414794921875 +33882 -0.121337890625 +33883 -0.117645263671875 +33884 -0.015716552734375 +33885 0.007049560546875 +33886 0.056884765625 +33887 0.087982177734375 +33888 0.10699462890625 +33889 0.13946533203125 +33890 0.143951416015625 +33891 0.17425537109375 +33892 0.163970947265625 +33893 0.188201904296875 +33894 0.15875244140625 +33895 0.171234130859375 +33896 0.12408447265625 +33897 0.118438720703125 +33898 0.080841064453125 +33899 0.05706787109375 +33900 0.03045654296875 +33901 -0.010711669921875 +33902 -0.032135009765625 +33903 -0.0914306640625 +33904 -0.08917236328125 +33905 -0.162322998046875 +33906 -0.1181640625 +33907 -0.194549560546875 +33908 -0.088714599609375 +33909 -0.1492919921875 +33910 0.003326416015625 +33911 -0.02166748046875 +33912 0.108489990234375 +33913 0.124053955078125 +33914 0.167724609375 +33915 0.211151123046875 +33916 0.182159423828125 +33917 0.240447998046875 +33918 0.175689697265625 +33919 0.242218017578125 +33920 0.15594482421875 +33921 0.2257080078125 +33922 0.125946044921875 +33923 0.194366455078125 +33924 0.060577392578125 +33925 0.115509033203125 +33926 -0.02154541015625 +33927 0.0128173828125 +33928 -0.073883056640625 +33929 -0.053802490234375 +33930 -0.1168212890625 +33931 -0.110626220703125 +33932 -0.1829833984375 +33933 -0.199493408203125 +33934 -0.25238037109375 +33935 -0.29437255859375 +33936 -0.27630615234375 +33937 -0.33221435546875 +33938 -0.22930908203125 +33939 -0.27972412109375 +33940 -0.149322509765625 +33941 -0.185333251953125 +33942 -0.098114013671875 +33943 -0.128204345703125 +33944 -0.081756591796875 +33945 -0.115692138671875 +33946 -0.0762939453125 +33947 -0.116455078125 +33948 -0.06298828125 +33949 -0.105926513671875 +33950 -0.018707275390625 +33951 -0.053955078125 +33952 0.0635986328125 +33953 0.048797607421875 +33954 0.14892578125 +33955 0.157318115234375 +33956 0.19097900390625 +33957 0.212005615234375 +33958 0.194183349609375 +33959 0.218475341796875 +33960 0.20562744140625 +33961 0.23724365234375 +33962 0.2542724609375 +33963 0.30535888671875 +33964 0.308135986328125 +33965 0.38128662109375 +33966 0.320526123046875 +33967 0.404449462890625 +33968 0.30694580078125 +33969 0.3944091796875 +33970 0.296722412109375 +33971 0.3885498046875 +33972 0.271392822265625 +33973 0.362640380859375 +33974 0.197784423828125 +33975 0.27362060546875 +33976 0.072723388671875 +33977 0.11712646484375 +33978 -0.063262939453125 +33979 -0.054901123046875 +33980 -0.1700439453125 +33981 -0.19085693359375 +33982 -0.243682861328125 +33983 -0.28570556640625 +33984 -0.284088134765625 +33985 -0.339263916015625 +33986 -0.3115234375 +33987 -0.3775634765625 +33988 -0.36114501953125 +33989 -0.445709228515625 +33990 -0.426513671875 +33991 -0.535064697265625 +33992 -0.494964599609375 +33993 -0.629058837890625 +33994 -0.543426513671875 +33995 -0.697601318359375 +33996 -0.543609619140625 +33997 -0.70391845703125 +33998 -0.491455078125 +33999 -0.6424560546875 +34000 -0.37017822265625 +34001 -0.491241455078125 +34002 -0.191925048828125 +34003 -0.265716552734375 +34004 -0.001739501953125 +34005 -0.023712158203125 +34006 0.17462158203125 +34007 0.201751708984375 +34008 0.310089111328125 +34009 0.375823974609375 +34010 0.39422607421875 +34011 0.485076904296875 +34012 0.4576416015625 +34013 0.56884765625 +34014 0.506378173828125 +34015 0.634765625 +34016 0.5054931640625 +34017 0.63763427734375 +34018 0.446319580078125 +34019 0.5660400390625 +34020 0.369476318359375 +34021 0.4720458984375 +34022 0.314971923828125 +34023 0.40692138671875 +34024 0.28857421875 +34025 0.3778076171875 +34026 0.284454345703125 +34027 0.376953125 +34028 0.277679443359375 +34029 0.371978759765625 +34030 0.22979736328125 +34031 0.313140869140625 +34032 0.12847900390625 +34033 0.184417724609375 +34034 -0.006500244140625 +34035 0.011199951171875 +34036 -0.14764404296875 +34037 -0.171051025390625 +34038 -0.275634765625 +34039 -0.33740234375 +34040 -0.378204345703125 +34041 -0.47198486328125 +34042 -0.4443359375 +34043 -0.560394287109375 +34044 -0.45709228515625 +34045 -0.58056640625 +34046 -0.42828369140625 +34047 -0.54754638671875 +34048 -0.3946533203125 +34049 -0.508575439453125 +34050 -0.353363037109375 +34051 -0.459503173828125 +34052 -0.299774169921875 +34053 -0.394378662109375 +34054 -0.263458251953125 +34055 -0.35260009765625 +34056 -0.227935791015625 +34057 -0.31170654296875 +34058 -0.13818359375 +34059 -0.197418212890625 +34060 0.006866455078125 +34061 -0.007965087890625 +34062 0.17041015625 +34063 0.207489013671875 +34064 0.32275390625 +34065 0.409210205078125 +34066 0.44512939453125 +34067 0.57208251953125 +34068 0.515106201171875 +34069 0.66595458984375 +34070 0.5087890625 +34071 0.65875244140625 +34072 0.43890380859375 +34073 0.56744384765625 +34074 0.334869384765625 +34075 0.431396484375 +34076 0.229522705078125 +34077 0.29443359375 +34078 0.142303466796875 +34079 0.182464599609375 +34080 0.049774169921875 +34081 0.06365966796875 +34082 -0.0582275390625 +34083 -0.075958251953125 +34084 -0.14654541015625 +34085 -0.189422607421875 +34086 -0.211395263671875 +34087 -0.271942138671875 +34088 -0.26678466796875 +34089 -0.342529296875 +34090 -0.2850341796875 +34091 -0.364166259765625 +34092 -0.258880615234375 +34093 -0.327239990234375 +34094 -0.221923828125 +34095 -0.2769775390625 +34096 -0.20416259765625 +34097 -0.253692626953125 +34098 -0.1954345703125 +34099 -0.24365234375 +34100 -0.159759521484375 +34101 -0.1983642578125 +34102 -0.096099853515625 +34103 -0.116241455078125 +34104 -0.03399658203125 +34105 -0.036834716796875 +34106 0.02264404296875 +34107 0.034881591796875 +34108 0.067962646484375 +34109 0.09124755859375 +34110 0.084381103515625 +34111 0.10888671875 +34112 0.099761962890625 +34113 0.125518798828125 +34114 0.12628173828125 +34115 0.15771484375 +34116 0.143585205078125 +34117 0.17828369140625 +34118 0.139556884765625 +34119 0.17108154296875 +34120 0.109619140625 +34121 0.129974365234375 +34122 0.07415771484375 +34123 0.082427978515625 +34124 0.03265380859375 +34125 0.027679443359375 +34126 -0.03814697265625 +34127 -0.065643310546875 +34128 -0.1097412109375 +34129 -0.15936279296875 +34130 -0.152008056640625 +34131 -0.21307373046875 +34132 -0.170654296875 +34133 -0.234649658203125 +34134 -0.147735595703125 +34135 -0.2001953125 +34136 -0.09014892578125 +34137 -0.119171142578125 +34138 -0.0224609375 +34139 -0.024749755859375 +34140 0.057525634765625 +34141 0.085784912109375 +34142 0.1243896484375 +34143 0.178131103515625 +34144 0.150909423828125 +34145 0.215576171875 +34146 0.14703369140625 +34147 0.211456298828125 +34148 0.119873046875 +34149 0.17523193359375 +34150 0.085662841796875 +34151 0.128753662109375 +34152 0.066619873046875 +34153 0.1019287109375 +34154 0.047515869140625 +34155 0.0743408203125 +34156 0.026214599609375 +34157 0.04327392578125 +34158 0.024505615234375 +34159 0.038177490234375 +34160 0.0550537109375 +34161 0.076263427734375 +34162 0.10546875 +34163 0.14105224609375 +34164 0.141357421875 +34165 0.186431884765625 +34166 0.145050048828125 +34167 0.188812255859375 +34168 0.109619140625 +34169 0.1390380859375 +34170 0.038482666015625 +34171 0.041778564453125 +34172 -0.0509033203125 +34173 -0.079437255859375 +34174 -0.154693603515625 +34175 -0.219390869140625 +34176 -0.2652587890625 +34177 -0.367828369140625 +34178 -0.3603515625 +34179 -0.494873046875 +34180 -0.406982421875 +34181 -0.556243896484375 +34182 -0.3729248046875 +34183 -0.508697509765625 +34184 -0.27545166015625 +34185 -0.3756103515625 +34186 -0.16058349609375 +34187 -0.218902587890625 +34188 -0.04693603515625 +34189 -0.063751220703125 +34190 0.066802978515625 +34191 0.091552734375 +34192 0.172576904296875 +34193 0.23602294921875 +34194 0.250640869140625 +34195 0.342987060546875 +34196 0.28826904296875 +34197 0.39520263671875 +34198 0.2830810546875 +34199 0.389373779296875 +34200 0.234161376953125 +34201 0.324249267578125 +34202 0.159576416015625 +34203 0.224090576171875 +34204 0.085601806640625 +34205 0.124267578125 +34206 0.0213623046875 +34207 0.037078857421875 +34208 -0.01275634765625 +34209 -0.010101318359375 +34210 -0.018463134765625 +34211 -0.019439697265625 +34212 -0.01953125 +34213 -0.022796630859375 +34214 -0.002166748046875 +34215 -0.001556396484375 +34216 0.04241943359375 +34217 0.056304931640625 +34218 0.081390380859375 +34219 0.106719970703125 +34220 0.07537841796875 +34221 0.096893310546875 +34222 0.036163330078125 +34223 0.042694091796875 +34224 -0.008209228515625 +34225 -0.018035888671875 +34226 -0.05072021484375 +34227 -0.07586669921875 +34228 -0.08294677734375 +34229 -0.11944580078125 +34230 -0.113037109375 +34231 -0.15972900390625 +34232 -0.145355224609375 +34233 -0.202606201171875 +34234 -0.18023681640625 +34235 -0.24859619140625 +34236 -0.22320556640625 +34237 -0.30517578125 +34238 -0.266632080078125 +34239 -0.36212158203125 +34240 -0.28961181640625 +34241 -0.39141845703125 +34242 -0.263946533203125 +34243 -0.35528564453125 +34244 -0.186767578125 +34245 -0.249969482421875 +34246 -0.071014404296875 +34247 -0.092864990234375 +34248 0.063323974609375 +34249 0.08905029296875 +34250 0.1712646484375 +34251 0.2352294921875 +34252 0.232879638671875 +34253 0.318817138671875 +34254 0.262176513671875 +34255 0.358642578125 +34256 0.253997802734375 +34257 0.347747802734375 +34258 0.207977294921875 +34259 0.28564453125 +34260 0.161956787109375 +34261 0.223175048828125 +34262 0.1429443359375 +34263 0.196746826171875 +34264 0.131195068359375 +34265 0.179840087890625 +34266 0.114105224609375 +34267 0.155548095703125 +34268 0.1119384765625 +34269 0.151214599609375 +34270 0.117279052734375 +34271 0.156951904296875 +34272 0.099517822265625 +34273 0.13177490234375 +34274 0.07733154296875 +34275 0.100799560546875 +34276 0.06787109375 +34277 0.087127685546875 +34278 0.044403076171875 +34279 0.05487060546875 +34280 -0.002777099609375 +34281 -0.009002685546875 +34282 -0.07330322265625 +34283 -0.10400390625 +34284 -0.166656494140625 +34285 -0.229400634765625 +34286 -0.260772705078125 +34287 -0.35552978515625 +34288 -0.32550048828125 +34289 -0.441925048828125 +34290 -0.349884033203125 +34291 -0.473846435546875 +34292 -0.343902587890625 +34293 -0.464813232421875 +34294 -0.3106689453125 +34295 -0.419097900390625 +34296 -0.248382568359375 +34297 -0.334320068359375 +34298 -0.170013427734375 +34299 -0.227935791015625 +34300 -0.093017578125 +34301 -0.12347412109375 +34302 -0.0223388671875 +34303 -0.02764892578125 +34304 0.055572509765625 +34305 0.077667236328125 +34306 0.15594482421875 +34307 0.2132568359375 +34308 0.28521728515625 +34309 0.38885498046875 +34310 0.42730712890625 +34311 0.582794189453125 +34312 0.53826904296875 +34313 0.734039306640625 +34314 0.587554931640625 +34315 0.800140380859375 +34316 0.572967529296875 +34317 0.7783203125 +34318 0.49200439453125 +34319 0.6651611328125 +34320 0.344024658203125 +34321 0.45965576171875 +34322 0.15576171875 +34323 0.199188232421875 +34324 -0.02587890625 +34325 -0.050689697265625 +34326 -0.1600341796875 +34327 -0.23297119140625 +34328 -0.233978271484375 +34329 -0.33013916015625 +34330 -0.266021728515625 +34331 -0.368408203125 +34332 -0.278045654296875 +34333 -0.378936767578125 +34334 -0.2806396484375 +34335 -0.376983642578125 +34336 -0.285797119140625 +34337 -0.37969970703125 +34338 -0.2965087890625 +34339 -0.391510009765625 +34340 -0.29339599609375 +34341 -0.385345458984375 +34342 -0.262664794921875 +34343 -0.3419189453125 +34344 -0.21978759765625 +34345 -0.28289794921875 +34346 -0.1956787109375 +34347 -0.251617431640625 +34348 -0.20330810546875 +34349 -0.266143798828125 +34350 -0.205047607421875 +34351 -0.273345947265625 +34352 -0.160888671875 +34353 -0.216796875 +34354 -0.093658447265625 +34355 -0.128265380859375 +34356 -0.046630859375 +34357 -0.068145751953125 +34358 -0.0247802734375 +34359 -0.0430908203125 +34360 -0.007904052734375 +34361 -0.024444580078125 +34362 0.027252197265625 +34363 0.020721435546875 +34364 0.10333251953125 +34365 0.124481201171875 +34366 0.199615478515625 +34367 0.25787353515625 +34368 0.28631591796875 +34369 0.379119873046875 +34370 0.357574462890625 +34371 0.47991943359375 +34372 0.390594482421875 +34373 0.5281982421875 +34374 0.3763427734375 +34375 0.511138916015625 +34376 0.334503173828125 +34377 0.456207275390625 +34378 0.296630859375 +34379 0.407470703125 +34380 0.27630615234375 +34381 0.383758544921875 +34382 0.253631591796875 +34383 0.35687255859375 +34384 0.2181396484375 +34385 0.31182861328125 +34386 0.171630859375 +34387 0.250885009765625 +34388 0.108123779296875 +34389 0.1654052734375 +34390 0.013397216796875 +34391 0.035247802734375 +34392 -0.11419677734375 +34393 -0.142059326171875 +34394 -0.252593994140625 +34395 -0.33563232421875 +34396 -0.394012451171875 +34397 -0.5345458984375 +34398 -0.52642822265625 +34399 -0.72186279296875 +34400 -0.606536865234375 +34401 -0.836669921875 +34402 -0.601470947265625 +34403 -0.8326416015625 +34404 -0.5255126953125 +34405 -0.7296142578125 +34406 -0.41796875 +34407 -0.582550048828125 +34408 -0.3135986328125 +34409 -0.440093994140625 +34410 -0.228302001953125 +34411 -0.324310302734375 +34412 -0.138214111328125 +34413 -0.20147705078125 +34414 -0.024261474609375 +34415 -0.044647216796875 +34416 0.0833740234375 +34417 0.103973388671875 +34418 0.15472412109375 +34419 0.202392578125 +34420 0.199615478515625 +34421 0.264495849609375 +34422 0.25262451171875 +34423 0.338897705078125 +34424 0.32672119140625 +34425 0.443817138671875 +34426 0.39764404296875 +34427 0.545074462890625 +34428 0.447418212890625 +34429 0.6173095703125 +34430 0.47039794921875 +34431 0.6524658203125 +34432 0.475860595703125 +34433 0.66339111328125 +34434 0.46826171875 +34435 0.6561279296875 +34436 0.430694580078125 +34437 0.606781005859375 +34438 0.353240966796875 +34439 0.501190185546875 +34440 0.245574951171875 +34441 0.352783203125 +34442 0.118438720703125 +34443 0.176544189453125 +34444 -0.03326416015625 +34445 -0.034820556640625 +34446 -0.1929931640625 +34447 -0.258209228515625 +34448 -0.324310302734375 +34449 -0.44244384765625 +34450 -0.41851806640625 +34451 -0.5753173828125 +34452 -0.4722900390625 +34453 -0.65203857421875 +34454 -0.463592529296875 +34455 -0.641632080078125 +34456 -0.4053955078125 +34457 -0.562164306640625 +34458 -0.32940673828125 +34459 -0.458038330078125 +34460 -0.250885009765625 +34461 -0.350555419921875 +34462 -0.184783935546875 +34463 -0.260528564453125 +34464 -0.1341552734375 +34465 -0.192108154296875 +34466 -0.096710205078125 +34467 -0.141937255859375 +34468 -0.06695556640625 +34469 -0.1021728515625 +34470 -0.037872314453125 +34471 -0.062896728515625 +34472 -0.0008544921875 +34473 -0.011932373046875 +34474 0.05267333984375 +34475 0.062835693359375 +34476 0.113677978515625 +34477 0.148712158203125 +34478 0.179351806640625 +34479 0.241729736328125 +34480 0.254852294921875 +34481 0.34912109375 +34482 0.330596923828125 +34483 0.457305908203125 +34484 0.3907470703125 +34485 0.54388427734375 +34486 0.409759521484375 +34487 0.5728759765625 +34488 0.360870361328125 +34489 0.506591796875 +34490 0.24859619140625 +34491 0.351226806640625 +34492 0.101318359375 +34493 0.146514892578125 +34494 -0.04364013671875 +34495 -0.05523681640625 +34496 -0.1593017578125 +34497 -0.21624755859375 +34498 -0.244476318359375 +34499 -0.334930419921875 +34500 -0.29327392578125 +34501 -0.402984619140625 +34502 -0.32049560546875 +34503 -0.4412841796875 +34504 -0.35888671875 +34505 -0.49578857421875 +34506 -0.40399169921875 +34507 -0.5601806640625 +34508 -0.431854248046875 +34509 -0.600738525390625 +34510 -0.41888427734375 +34511 -0.584228515625 +34512 -0.34283447265625 +34513 -0.47930908203125 +34514 -0.199066162109375 +34515 -0.27935791015625 +34516 -0.005126953125 +34517 -0.0089111328125 +34518 0.19384765625 +34519 0.268798828125 +34520 0.347320556640625 +34521 0.482818603515625 +34522 0.43426513671875 +34523 0.60369873046875 +34524 0.4681396484375 +34525 0.650421142578125 +34526 0.478118896484375 +34527 0.66400146484375 +34528 0.462066650390625 +34529 0.6414794921875 +34530 0.41265869140625 +34531 0.572540283203125 +34532 0.359100341796875 +34533 0.498138427734375 +34534 0.3165283203125 +34535 0.439453125 +34536 0.270050048828125 +34537 0.375518798828125 +34538 0.197052001953125 +34539 0.274505615234375 +34540 0.077911376953125 +34541 0.1087646484375 +34542 -0.0714111328125 +34543 -0.099395751953125 +34544 -0.228240966796875 +34545 -0.3182373046875 +34546 -0.3934326171875 +34547 -0.5489501953125 +34548 -0.55426025390625 +34549 -0.7738037109375 +34550 -0.673004150390625 +34551 -0.86383056640625 +34552 -0.7259521484375 +34553 -0.870391845703125 +34554 -0.7257080078125 +34555 -0.86895751953125 +34556 -0.681640625 +34557 -0.861053466796875 +34558 -0.581451416015625 +34559 -0.765869140625 +34560 -0.417205810546875 +34561 -0.5301513671875 +34562 -0.19451904296875 +34563 -0.214691162109375 +34564 0.05609130859375 +34565 0.137359619140625 +34566 0.2987060546875 +34567 0.474822998046875 +34568 0.508270263671875 +34569 0.76239013671875 +34570 0.665740966796875 +34571 0.867462158203125 +34572 0.770904541015625 +34573 0.870361328125 +34574 0.81561279296875 +34575 0.86480712890625 +34576 0.8033447265625 +34577 0.831817626953125 +34578 0.750701904296875 +34579 0.677581787109375 +34580 0.66180419921875 +34581 0.495880126953125 +34582 0.549591064453125 +34583 0.30767822265625 +34584 0.415985107421875 +34585 0.116180419921875 +34586 0.2398681640625 +34587 -0.110748291015625 +34588 0.01708984375 +34589 -0.381805419921875 +34590 -0.222686767578125 +34591 -0.6572265625 +34592 -0.43817138671875 +34593 -0.857421875 +34594 -0.599700927734375 +34595 -0.870391845703125 +34596 -0.701995849609375 +34597 -0.870391845703125 +34598 -0.763031005859375 +34599 -0.86444091796875 +34600 -0.806854248046875 +34601 -0.85723876953125 +34602 -0.82086181640625 +34603 -0.790008544921875 +34604 -0.7681884765625 +34605 -0.62847900390625 +34606 -0.646759033203125 +34607 -0.3956298828125 +34608 -0.4791259765625 +34609 -0.126708984375 +34610 -0.28424072265625 +34611 0.150115966796875 +34612 -0.0704345703125 +34613 0.424041748046875 +34614 0.1435546875 +34615 0.670623779296875 +34616 0.3309326171875 +34617 0.854522705078125 +34618 0.479217529296875 +34619 0.866485595703125 +34620 0.577545166015625 +34621 0.86920166015625 +34622 0.637908935546875 +34623 0.8653564453125 +34624 0.66912841796875 +34625 0.857147216796875 +34626 0.668975830078125 +34627 0.766845703125 +34628 0.64080810546875 +34629 0.628509521484375 +34630 0.580047607421875 +34631 0.462127685546875 +34632 0.5042724609375 +34633 0.297210693359375 +34634 0.42205810546875 +34635 0.14862060546875 +34636 0.318145751953125 +34637 -0.00537109375 +34638 0.1978759765625 +34639 -0.15753173828125 +34640 0.05914306640625 +34641 -0.31304931640625 +34642 -0.107177734375 +34643 -0.48876953125 +34644 -0.268829345703125 +34645 -0.6416015625 +34646 -0.408660888671875 +34647 -0.751373291015625 +34648 -0.542022705078125 +34649 -0.84619140625 +34650 -0.65863037109375 +34651 -0.861297607421875 +34652 -0.7357177734375 +34653 -0.863250732421875 +34654 -0.751678466796875 +34655 -0.856597900390625 +34656 -0.714691162109375 +34657 -0.7498779296875 +34658 -0.66412353515625 +34659 -0.624542236328125 +34660 -0.58514404296875 +34661 -0.47808837890625 +34662 -0.43817138671875 +34663 -0.253387451171875 +34664 -0.254486083984375 +34665 0.003692626953125 +34666 -0.08087158203125 +34667 0.2257080078125 +34668 0.09088134765625 +34669 0.427154541015625 +34670 0.282470703125 +34671 0.643218994140625 +34672 0.486968994140625 +34673 0.855926513671875 +34674 0.6646728515625 +34675 0.870361328125 +34676 0.781585693359375 +34677 0.870361328125 +34678 0.84234619140625 +34679 0.862762451171875 +34680 0.84478759765625 +34681 0.79669189453125 +34682 0.78240966796875 +34683 0.595794677734375 +34684 0.675079345703125 +34685 0.362152099609375 +34686 0.54193115234375 +34687 0.1270751953125 +34688 0.397491455078125 +34689 -0.086944580078125 +34690 0.243408203125 +34691 -0.2784423828125 +34692 0.0562744140625 +34693 -0.484832763671875 +34694 -0.1766357421875 +34695 -0.729583740234375 +34696 -0.420562744140625 +34697 -0.86688232421875 +34698 -0.63214111328125 +34699 -0.870391845703125 +34700 -0.80767822265625 +34701 -0.86859130859375 +34702 -0.86444091796875 +34703 -0.86279296875 +34704 -0.870391845703125 +34705 -0.817962646484375 +34706 -0.8663330078125 +34707 -0.6116943359375 +34708 -0.829803466796875 +34709 -0.3128662109375 +34710 -0.62481689453125 +34711 0.039398193359375 +34712 -0.362091064453125 +34713 0.422821044921875 +34714 -0.06475830078125 +34715 0.805145263671875 +34716 0.220550537109375 +34717 0.870361328125 +34718 0.454925537109375 +34719 0.870361328125 +34720 0.630401611328125 +34721 0.860015869140625 +34722 0.741973876953125 +34723 0.727935791015625 +34724 0.786163330078125 +34725 0.48114013671875 +34726 0.7799072265625 +34727 0.2059326171875 +34728 0.739166259765625 +34729 -0.06103515625 +34730 0.67144775390625 +34731 -0.29913330078125 +34732 0.567596435546875 +34733 -0.516204833984375 +34734 0.41790771484375 +34735 -0.7252197265625 +34736 0.24005126953125 +34737 -0.85980224609375 +34738 0.05804443359375 +34739 -0.870391845703125 +34740 -0.107330322265625 +34741 -0.870391845703125 +34742 -0.222381591796875 +34743 -0.858062744140625 +34744 -0.2838134765625 +34745 -0.673004150390625 +34746 -0.3270263671875 +34747 -0.42694091796875 +34748 -0.382080078125 +34749 -0.2100830078125 +34750 -0.447540283203125 +34751 -0.0362548828125 +34752 -0.5037841796875 +34753 0.10943603515625 +34754 -0.537567138671875 +34755 0.23516845703125 +34756 -0.52117919921875 +34757 0.373687744140625 +34758 -0.45648193359375 +34759 0.517791748046875 +34760 -0.38690185546875 +34761 0.602783203125 +34762 -0.309600830078125 +34763 0.635711669921875 +34764 -0.20257568359375 +34765 0.655181884765625 +34766 -0.073211669921875 +34767 0.65948486328125 +34768 0.072418212890625 +34769 0.651275634765625 +34770 0.2171630859375 +34771 0.61846923828125 +34772 0.335479736328125 +34773 0.53753662109375 +34774 0.414794921875 +34775 0.404144287109375 +34776 0.448333740234375 +34777 0.22186279296875 +34778 0.43695068359375 +34779 0.003997802734375 +34780 0.393096923828125 +34781 -0.22100830078125 +34782 0.331085205078125 +34783 -0.42449951171875 +34784 0.265838623046875 +34785 -0.579833984375 +34786 0.22686767578125 +34787 -0.641876220703125 +34788 0.210205078125 +34789 -0.6177978515625 +34790 0.1724853515625 +34791 -0.575531005859375 +34792 0.110626220703125 +34793 -0.526336669921875 +34794 0.060394287109375 +34795 -0.42645263671875 +34796 0.04095458984375 +34797 -0.2581787109375 +34798 0.0279541015625 +34799 -0.068695068359375 +34800 -0.004425048828125 +34801 0.09222412109375 +34802 -0.043304443359375 +34803 0.232147216796875 +34804 -0.0816650390625 +34805 0.3509521484375 +34806 -0.139678955078125 +34807 0.410064697265625 +34808 -0.237457275390625 +34809 0.372955322265625 +34810 -0.360992431640625 +34811 0.2554931640625 +34812 -0.475128173828125 +34813 0.10711669921875 +34814 -0.566925048828125 +34815 -0.052886962890625 +34816 -0.612579345703125 +34817 -0.186279296875 +34818 -0.574951171875 +34819 -0.23291015625 +34820 -0.46905517578125 +34821 -0.209442138671875 +34822 -0.3388671875 +34823 -0.174163818359375 +34824 -0.19085693359375 +34825 -0.126739501953125 +34826 -0.0196533203125 +34827 -0.048126220703125 +34828 0.155517578125 +34829 0.0426025390625 +34830 0.3035888671875 +34831 0.10748291015625 +34832 0.4154052734375 +34833 0.1409912109375 +34834 0.521514892578125 +34835 0.19708251953125 +34836 0.617340087890625 +34837 0.273651123046875 +34838 0.66656494140625 +34839 0.31768798828125 +34840 0.676544189453125 +34841 0.341094970703125 +34842 0.66400146484375 +34843 0.368011474609375 +34844 0.614471435546875 +34845 0.37249755859375 +34846 0.496490478515625 +34847 0.30072021484375 +34848 0.313873291015625 +34849 0.1517333984375 +34850 0.110595703125 +34851 -0.01470947265625 +34852 -0.1011962890625 +34853 -0.1883544921875 +34854 -0.318267822265625 +34855 -0.372711181640625 +34856 -0.500396728515625 +34857 -0.51397705078125 +34858 -0.6165771484375 +34859 -0.57177734375 +34860 -0.6585693359375 +34861 -0.53948974609375 +34862 -0.635101318359375 +34863 -0.43511962890625 +34864 -0.5687255859375 +34865 -0.2962646484375 +34866 -0.4835205078125 +34867 -0.161102294921875 +34868 -0.389007568359375 +34869 -0.0435791015625 +34870 -0.284149169921875 +34871 0.060394287109375 +34872 -0.180694580078125 +34873 0.13665771484375 +34874 -0.091888427734375 +34875 0.170135498046875 +34876 -0.018707275390625 +34877 0.16552734375 +34878 0.056793212890625 +34879 0.15728759765625 +34880 0.133575439453125 +34881 0.150787353515625 +34882 0.191619873046875 +34883 0.12200927734375 +34884 0.2327880859375 +34885 0.080108642578125 +34886 0.2706298828125 +34887 0.05126953125 +34888 0.32025146484375 +34889 0.062896728515625 +34890 0.365264892578125 +34891 0.09271240234375 +34892 0.373748779296875 +34893 0.092987060546875 +34894 0.3553466796875 +34895 0.07855224609375 +34896 0.320709228515625 +34897 0.06427001953125 +34898 0.261688232421875 +34899 0.0347900390625 +34900 0.1796875 +34901 -0.01171875 +34902 0.09033203125 +34903 -0.056060791015625 +34904 0.02496337890625 +34905 -0.055511474609375 +34906 -0.012908935546875 +34907 -0.010467529296875 +34908 -0.054656982421875 +34909 0.02508544921875 +34910 -0.11334228515625 +34911 0.025665283203125 +34912 -0.16900634765625 +34913 0.017333984375 +34914 -0.217987060546875 +34915 0.00189208984375 +34916 -0.26568603515625 +34917 -0.03173828125 +34918 -0.30328369140625 +34919 -0.071502685546875 +34920 -0.342254638671875 +34921 -0.13543701171875 +34922 -0.380828857421875 +34923 -0.219970703125 +34924 -0.404266357421875 +34925 -0.300506591796875 +34926 -0.4140625 +34927 -0.376312255859375 +34928 -0.392303466796875 +34929 -0.416107177734375 +34930 -0.310150146484375 +34931 -0.371124267578125 +34932 -0.171234130859375 +34933 -0.242279052734375 +34934 -0.004730224609375 +34935 -0.069732666015625 +34936 0.172821044921875 +34937 0.125640869140625 +34938 0.338531494140625 +34939 0.31268310546875 +34940 0.466552734375 +34941 0.45501708984375 +34942 0.55657958984375 +34943 0.554779052734375 +34944 0.606689453125 +34945 0.61065673828125 +34946 0.60882568359375 +34947 0.610931396484375 +34948 0.54754638671875 +34949 0.531463623046875 +34950 0.434112548828125 +34951 0.3883056640625 +34952 0.304534912109375 +34953 0.23468017578125 +34954 0.1767578125 +34955 0.095245361328125 +34956 0.069915771484375 +34957 -0.00396728515625 +34958 -0.004150390625 +34959 -0.04852294921875 +34960 -0.053741455078125 +34961 -0.055145263671875 +34962 -0.110198974609375 +34963 -0.0758056640625 +34964 -0.189544677734375 +34965 -0.138702392578125 +34966 -0.26727294921875 +34967 -0.209197998046875 +34968 -0.342987060546875 +34969 -0.289031982421875 +34970 -0.416046142578125 +34971 -0.37884521484375 +34972 -0.471405029296875 +34973 -0.456329345703125 +34974 -0.505767822265625 +34975 -0.51641845703125 +34976 -0.493804931640625 +34977 -0.519287109375 +34978 -0.432159423828125 +34979 -0.458251953125 +34980 -0.355743408203125 +34981 -0.384796142578125 +34982 -0.28240966796875 +34983 -0.323699951171875 +34984 -0.210418701171875 +34985 -0.269287109375 +34986 -0.124755859375 +34987 -0.1951904296875 +34988 -0.026580810546875 +34989 -0.100006103515625 +34990 0.064697265625 +34991 -0.01055908203125 +34992 0.167022705078125 +34993 0.1033935546875 +34994 0.283721923828125 +34995 0.24908447265625 +34996 0.379119873046875 +34997 0.373199462890625 +34998 0.441162109375 +34999 0.45806884765625 +35000 0.4747314453125 +35001 0.511474609375 +35002 0.50091552734375 +35003 0.565399169921875 +35004 0.514923095703125 +35005 0.61138916015625 +35006 0.47900390625 +35007 0.5897216796875 +35008 0.388153076171875 +35009 0.4906005859375 +35010 0.25531005859375 +35011 0.33148193359375 +35012 0.10516357421875 +35013 0.147796630859375 +35014 -0.033447265625 +35015 -0.01873779296875 +35016 -0.140777587890625 +35017 -0.140289306640625 +35018 -0.19915771484375 +35019 -0.191986083984375 +35020 -0.21417236328125 +35021 -0.184295654296875 +35022 -0.213836669921875 +35023 -0.161834716796875 +35024 -0.224853515625 +35025 -0.166595458984375 +35026 -0.243927001953125 +35027 -0.19390869140625 +35028 -0.258575439453125 +35029 -0.22442626953125 +35030 -0.2833251953125 +35031 -0.279754638671875 +35032 -0.305389404296875 +35033 -0.3389892578125 +35034 -0.2947998046875 +35035 -0.3543701171875 +35036 -0.267242431640625 +35037 -0.348175048828125 +35038 -0.22772216796875 +35039 -0.32598876953125 +35040 -0.158416748046875 +35041 -0.2581787109375 +35042 -0.057464599609375 +35043 -0.139801025390625 +35044 0.064422607421875 +35045 0.014617919921875 +35046 0.166656494140625 +35047 0.144378662109375 +35048 0.229888916015625 +35049 0.221038818359375 +35050 0.270477294921875 +35051 0.27069091796875 +35052 0.288604736328125 +35053 0.294036865234375 +35054 0.297698974609375 +35055 0.311767578125 +35056 0.307952880859375 +35057 0.339141845703125 +35058 0.309539794921875 +35059 0.360260009765625 +35060 0.293792724609375 +35061 0.360504150390625 +35062 0.241241455078125 +35063 0.308380126953125 +35064 0.138641357421875 +35065 0.18170166015625 +35066 0.002960205078125 +35067 0.0047607421875 +35068 -0.13427734375 +35069 -0.17559814453125 +35070 -0.242828369140625 +35071 -0.3143310546875 +35072 -0.29388427734375 +35073 -0.36785888671875 +35074 -0.30328369140625 +35075 -0.36248779296875 +35076 -0.2991943359375 +35077 -0.343536376953125 +35078 -0.27593994140625 +35079 -0.3018798828125 +35080 -0.229888916015625 +35081 -0.231414794921875 +35082 -0.15252685546875 +35083 -0.117645263671875 +35084 -0.06439208984375 +35085 0.007049560546875 +35086 6.103515625e-05 +35087 0.087982177734375 +35088 0.04876708984375 +35089 0.13946533203125 +35090 0.088592529296875 +35091 0.17425537109375 +35092 0.115936279296875 +35093 0.188201904296875 +35094 0.12359619140625 +35095 0.171234130859375 +35096 0.10760498046875 +35097 0.118438720703125 +35098 0.08392333984375 +35099 0.05706787109375 +35100 0.05316162109375 +35101 -0.010711669921875 +35102 0.01080322265625 +35103 -0.0914306640625 +35104 -0.029388427734375 +35105 -0.162322998046875 +35106 -0.04974365234375 +35107 -0.194549560546875 +35108 -0.02618408203125 +35109 -0.1492919921875 +35110 0.044647216796875 +35111 -0.02166748046875 +35112 0.123687744140625 +35113 0.124053955078125 +35114 0.164337158203125 +35115 0.211151123046875 +35116 0.16790771484375 +35117 0.240447998046875 +35118 0.15386962890625 +35119 0.242218017578125 +35120 0.128753662109375 +35121 0.2257080078125 +35122 0.095489501953125 +35123 0.194366455078125 +35124 0.034698486328125 +35125 0.115509033203125 +35126 -0.03839111328125 +35127 0.0128173828125 +35128 -0.08642578125 +35129 -0.053802490234375 +35130 -0.125274658203125 +35131 -0.110626220703125 +35132 -0.180633544921875 +35133 -0.199493408203125 +35134 -0.23651123046875 +35135 -0.29437255859375 +35136 -0.254302978515625 +35137 -0.33221435546875 +35138 -0.213897705078125 +35139 -0.27972412109375 +35140 -0.1456298828125 +35141 -0.185333251953125 +35142 -0.098876953125 +35143 -0.128204345703125 +35144 -0.078826904296875 +35145 -0.115692138671875 +35146 -0.066864013671875 +35147 -0.116455078125 +35148 -0.048583984375 +35149 -0.105926513671875 +35150 -0.006011962890625 +35151 -0.053955078125 +35152 0.0660400390625 +35153 0.048797607421875 +35154 0.13946533203125 +35155 0.157318115234375 +35156 0.177215576171875 +35157 0.212005615234375 +35158 0.182586669921875 +35159 0.218475341796875 +35160 0.19287109375 +35161 0.23724365234375 +35162 0.231048583984375 +35163 0.30535888671875 +35164 0.27178955078125 +35165 0.38128662109375 +35166 0.278167724609375 +35167 0.404449462890625 +35168 0.262725830078125 +35169 0.3944091796875 +35170 0.2490234375 +35171 0.3885498046875 +35172 0.22271728515625 +35173 0.362640380859375 +35174 0.157867431640625 +35175 0.27362060546875 +35176 0.052337646484375 +35177 0.11712646484375 +35178 -0.061370849609375 +35179 -0.054901123046875 +35180 -0.151123046875 +35181 -0.19085693359375 +35182 -0.213531494140625 +35183 -0.28570556640625 +35184 -0.248321533203125 +35185 -0.339263916015625 +35186 -0.271484375 +35187 -0.3775634765625 +35188 -0.3109130859375 +35189 -0.445709228515625 +35190 -0.361480712890625 +35191 -0.535064697265625 +35192 -0.413299560546875 +35193 -0.629058837890625 +35194 -0.44818115234375 +35195 -0.697601318359375 +35196 -0.443939208984375 +35197 -0.70391845703125 +35198 -0.3975830078125 +35199 -0.6424560546875 +35200 -0.296051025390625 +35201 -0.491241455078125 +35202 -0.149322509765625 +35203 -0.265716552734375 +35204 0.00653076171875 +35205 -0.023712158203125 +35206 0.150848388671875 +35207 0.201751708984375 +35208 0.261871337890625 +35209 0.375823974609375 +35210 0.331207275390625 +35211 0.485076904296875 +35212 0.383026123046875 +35213 0.56884765625 +35214 0.42205810546875 +35215 0.634765625 +35216 0.420623779296875 +35217 0.63763427734375 +35218 0.37188720703125 +35219 0.5660400390625 +35220 0.308197021484375 +35221 0.4720458984375 +35222 0.261505126953125 +35223 0.40692138671875 +35224 0.236602783203125 +35225 0.3778076171875 +35226 0.229095458984375 +35227 0.376953125 +35228 0.219390869140625 +35229 0.371978759765625 +35230 0.17724609375 +35231 0.313140869140625 +35232 0.09307861328125 +35233 0.184417724609375 +35234 -0.0172119140625 +35235 0.011199951171875 +35236 -0.13165283203125 +35237 -0.171051025390625 +35238 -0.23480224609375 +35239 -0.33740234375 +35240 -0.316864013671875 +35241 -0.47198486328125 +35242 -0.369049072265625 +35243 -0.560394287109375 +35244 -0.377960205078125 +35245 -0.58056640625 +35246 -0.353118896484375 +35247 -0.54754638671875 +35248 -0.3238525390625 +35249 -0.508575439453125 +35250 -0.2879638671875 +35251 -0.459503173828125 +35252 -0.2420654296875 +35253 -0.394378662109375 +35254 -0.21075439453125 +35255 -0.35260009765625 +35256 -0.18048095703125 +35257 -0.31170654296875 +35258 -0.10577392578125 +35259 -0.197418212890625 +35260 0.014251708984375 +35261 -0.007965087890625 +35262 0.149139404296875 +35263 0.207489013671875 +35264 0.274322509765625 +35265 0.409210205078125 +35266 0.374298095703125 +35267 0.57208251953125 +35268 0.430572509765625 +35269 0.66595458984375 +35270 0.42352294921875 +35271 0.65875244140625 +35272 0.36376953125 +35273 0.56744384765625 +35274 0.2757568359375 +35275 0.431396484375 +35276 0.186737060546875 +35277 0.29443359375 +35278 0.11297607421875 +35279 0.182464599609375 +35280 0.035125732421875 +35281 0.06365966796875 +35282 -0.05517578125 +35283 -0.075958251953125 +35284 -0.1287841796875 +35285 -0.189422607421875 +35286 -0.182525634765625 +35287 -0.271942138671875 +35288 -0.22796630859375 +35289 -0.342529296875 +35290 -0.242279052734375 +35291 -0.364166259765625 +35292 -0.219512939453125 +35293 -0.327239990234375 +35294 -0.187530517578125 +35295 -0.2769775390625 +35296 -0.171295166015625 +35297 -0.253692626953125 +35298 -0.162445068359375 +35299 -0.24365234375 +35300 -0.13128662109375 +35301 -0.1983642578125 +35302 -0.0770263671875 +35303 -0.116241455078125 +35304 -0.02423095703125 +35305 -0.036834716796875 +35306 0.0238037109375 +35307 0.034881591796875 +35308 0.0621337890625 +35309 0.09124755859375 +35310 0.076171875 +35311 0.10888671875 +35312 0.0889892578125 +35313 0.125518798828125 +35314 0.1107177734375 +35315 0.15771484375 +35316 0.124481201171875 +35317 0.17828369140625 +35318 0.12030029296875 +35319 0.17108154296875 +35320 0.09442138671875 +35321 0.129974365234375 +35322 0.063812255859375 +35323 0.082427978515625 +35324 0.028106689453125 +35325 0.027679443359375 +35326 -0.031890869140625 +35327 -0.065643310546875 +35328 -0.092864990234375 +35329 -0.15936279296875 +35330 -0.129364013671875 +35331 -0.21307373046875 +35332 -0.145416259765625 +35333 -0.234649658203125 +35334 -0.12725830078125 +35335 -0.2001953125 +35336 -0.0806884765625 +35337 -0.119171142578125 +35338 -0.02532958984375 +35339 -0.024749755859375 +35340 0.0401611328125 +35341 0.085784912109375 +35342 0.095550537109375 +35343 0.178131103515625 +35344 0.119232177734375 +35345 0.215576171875 +35346 0.11883544921875 +35347 0.211456298828125 +35348 0.099761962890625 +35349 0.17523193359375 +35350 0.07464599609375 +35351 0.128753662109375 +35352 0.06085205078125 +35353 0.1019287109375 +35354 0.04638671875 +35355 0.0743408203125 +35356 0.02960205078125 +35357 0.04327392578125 +35358 0.027618408203125 +35359 0.038177490234375 +35360 0.05047607421875 +35361 0.076263427734375 +35362 0.08856201171875 +35363 0.14105224609375 +35364 0.11492919921875 +35365 0.186431884765625 +35366 0.115814208984375 +35367 0.188812255859375 +35368 0.0859375 +35369 0.1390380859375 +35370 0.028106689453125 +35371 0.041778564453125 +35372 -0.043853759765625 +35373 -0.079437255859375 +35374 -0.1268310546875 +35375 -0.219390869140625 +35376 -0.21478271484375 +35377 -0.367828369140625 +35378 -0.290191650390625 +35379 -0.494873046875 +35380 -0.327117919921875 +35381 -0.556243896484375 +35382 -0.300262451171875 +35383 -0.508697509765625 +35384 -0.223236083984375 +35385 -0.3756103515625 +35386 -0.1322021484375 +35387 -0.218902587890625 +35388 -0.04180908203125 +35389 -0.063751220703125 +35390 0.04888916015625 +35391 0.091552734375 +35392 0.133514404296875 +35393 0.23602294921875 +35394 0.196441650390625 +35395 0.342987060546875 +35396 0.22760009765625 +35397 0.39520263671875 +35398 0.225006103515625 +35399 0.389373779296875 +35400 0.187896728515625 +35401 0.324249267578125 +35402 0.130401611328125 +35403 0.224090576171875 +35404 0.0731201171875 +35405 0.124267578125 +35406 0.02313232421875 +35407 0.037078857421875 +35408 -0.003570556640625 +35409 -0.010101318359375 +35410 -0.008331298828125 +35411 -0.019439697265625 +35412 -0.009765625 +35413 -0.022796630859375 +35414 0.0029296875 +35415 -0.001556396484375 +35416 0.036773681640625 +35417 0.056304931640625 +35418 0.0660400390625 +35419 0.106719970703125 +35420 0.0599365234375 +35421 0.096893310546875 +35422 0.027740478515625 +35423 0.042694091796875 +35424 -0.008392333984375 +35425 -0.018035888671875 +35426 -0.04290771484375 +35427 -0.07586669921875 +35428 -0.06915283203125 +35429 -0.11944580078125 +35430 -0.093475341796875 +35431 -0.15972900390625 +35432 -0.1192626953125 +35433 -0.202606201171875 +35434 -0.146728515625 +35435 -0.24859619140625 +35436 -0.18023681640625 +35437 -0.30517578125 +35438 -0.21380615234375 +35439 -0.36212158203125 +35440 -0.231109619140625 +35441 -0.39141845703125 +35442 -0.210052490234375 +35443 -0.35528564453125 +35444 -0.148468017578125 +35445 -0.249969482421875 +35446 -0.056488037109375 +35447 -0.092864990234375 +35448 0.050079345703125 +35449 0.08905029296875 +35450 0.1358642578125 +35451 0.2352294921875 +35452 0.1851806640625 +35453 0.318817138671875 +35454 0.208953857421875 +35455 0.358642578125 +35456 0.203125 +35457 0.347747802734375 +35458 0.167388916015625 +35459 0.28564453125 +35460 0.131378173828125 +35461 0.223175048828125 +35462 0.1163330078125 +35463 0.196746826171875 +35464 0.106781005859375 +35465 0.179840087890625 +35466 0.092803955078125 +35467 0.155548095703125 +35468 0.090362548828125 +35469 0.151214599609375 +35470 0.09368896484375 +35471 0.156951904296875 +35472 0.078857421875 +35473 0.13177490234375 +35474 0.060546875 +35475 0.100799560546875 +35476 0.05224609375 +35477 0.087127685546875 +35478 0.03302001953125 +35479 0.05487060546875 +35480 -0.00469970703125 +35481 -0.009002685546875 +35482 -0.06060791015625 +35483 -0.10400390625 +35484 -0.13427734375 +35485 -0.229400634765625 +35486 -0.20831298828125 +35487 -0.35552978515625 +35488 -0.259063720703125 +35489 -0.441925048828125 +35490 -0.2779541015625 +35491 -0.473846435546875 +35492 -0.2728271484375 +35493 -0.464813232421875 +35494 -0.246185302734375 +35495 -0.419097900390625 +35496 -0.1966552734375 +35497 -0.334320068359375 +35498 -0.1343994140625 +35499 -0.227935791015625 +35500 -0.07318115234375 +35501 -0.12347412109375 +35502 -0.016937255859375 +35503 -0.02764892578125 +35504 0.044921875 +35505 0.077667236328125 +35506 0.124481201171875 +35507 0.2132568359375 +35508 0.227386474609375 +35509 0.38885498046875 +35510 0.340972900390625 +35511 0.582794189453125 +35512 0.4295654296875 +35513 0.734039306640625 +35514 0.4683837890625 +35515 0.800140380859375 +35516 0.455780029296875 +35517 0.7783203125 +35518 0.389739990234375 +35519 0.6651611328125 +35520 0.26971435546875 +35521 0.45965576171875 +35522 0.117523193359375 +35523 0.199188232421875 +35524 -0.02850341796875 +35525 -0.050689697265625 +35526 -0.135101318359375 +35527 -0.23297119140625 +35528 -0.1920166015625 +35529 -0.33013916015625 +35530 -0.21453857421875 +35531 -0.368408203125 +35532 -0.220855712890625 +35533 -0.378936767578125 +35534 -0.21990966796875 +35535 -0.376983642578125 +35536 -0.221710205078125 +35537 -0.37969970703125 +35538 -0.22882080078125 +35539 -0.391510009765625 +35540 -0.225433349609375 +35541 -0.385345458984375 +35542 -0.20025634765625 +35543 -0.3419189453125 +35544 -0.165924072265625 +35545 -0.28289794921875 +35546 -0.147735595703125 +35547 -0.251617431640625 +35548 -0.156219482421875 +35549 -0.266143798828125 +35550 -0.160369873046875 +35551 -0.273345947265625 +35552 -0.12725830078125 +35553 -0.216796875 +35554 -0.075408935546875 +35555 -0.128265380859375 +35556 -0.04010009765625 +35557 -0.068145751953125 +35558 -0.02520751953125 +35559 -0.0430908203125 +35560 -0.0140380859375 +35561 -0.024444580078125 +35562 0.012603759765625 +35563 0.020721435546875 +35564 0.07342529296875 +35565 0.124481201171875 +35566 0.1514892578125 +35567 0.25787353515625 +35568 0.222381591796875 +35569 0.379119873046875 +35570 0.281280517578125 +35571 0.47991943359375 +35572 0.3094482421875 +35573 0.5281982421875 +35574 0.299407958984375 +35575 0.511138916015625 +35576 0.2672119140625 +35577 0.456207275390625 +35578 0.238616943359375 +35579 0.407470703125 +35580 0.224609375 +35581 0.383758544921875 +35582 0.208740234375 +35583 0.35687255859375 +35584 0.181732177734375 +35585 0.31182861328125 +35586 0.14459228515625 +35587 0.250885009765625 +35588 0.09295654296875 +35589 0.1654052734375 +35590 0.0162353515625 +35591 0.035247802734375 +35592 -0.08648681640625 +35593 -0.142059326171875 +35594 -0.19775390625 +35595 -0.33563232421875 +35596 -0.311187744140625 +35597 -0.5345458984375 +35598 -0.41717529296875 +35599 -0.72186279296875 +35600 -0.481964111328125 +35601 -0.836669921875 +35602 -0.47991943359375 +35603 -0.8326416015625 +35604 -0.4219970703125 +35605 -0.7296142578125 +35606 -0.338653564453125 +35607 -0.582550048828125 +35608 -0.25689697265625 +35609 -0.440093994140625 +35610 -0.189117431640625 +35611 -0.324310302734375 +35612 -0.116912841796875 +35613 -0.20147705078125 +35614 -0.02569580078125 +35615 -0.044647216796875 +35616 0.060943603515625 +35617 0.103973388671875 +35618 0.11956787109375 +35619 0.202392578125 +35620 0.1575927734375 +35621 0.264495849609375 +35622 0.201690673828125 +35623 0.338897705078125 +35624 0.261749267578125 +35625 0.443817138671875 +35626 0.318817138671875 +35627 0.545074462890625 +35628 0.358856201171875 +35629 0.6173095703125 +35630 0.37744140625 +35631 0.6524658203125 +35632 0.3817138671875 +35633 0.66339111328125 +35634 0.375152587890625 +35635 0.6561279296875 +35636 0.3447265625 +35637 0.606781005859375 +35638 0.282806396484375 +35639 0.501190185546875 +35640 0.196990966796875 +35641 0.352783203125 +35642 0.095794677734375 +35643 0.176544189453125 +35644 -0.024566650390625 +35645 -0.034820556640625 +35646 -0.151123046875 +35647 -0.258209228515625 +35648 -0.2554931640625 +35649 -0.44244384765625 +35650 -0.330810546875 +35651 -0.5753173828125 +35652 -0.37432861328125 +35653 -0.65203857421875 +35654 -0.368927001953125 +35655 -0.641632080078125 +35656 -0.3245849609375 +35657 -0.562164306640625 +35658 -0.265869140625 +35659 -0.458038330078125 +35660 -0.204620361328125 +35661 -0.350555419921875 +35662 -0.152435302734375 +35663 -0.260528564453125 +35664 -0.111785888671875 +35665 -0.192108154296875 +35666 -0.080963134765625 +35667 -0.141937255859375 +35668 -0.055816650390625 +35669 -0.1021728515625 +35670 -0.03106689453125 +35671 -0.062896728515625 +35672 -0.0001220703125 +35673 -0.011932373046875 +35674 0.04351806640625 +35675 0.062835693359375 +35676 0.092742919921875 +35677 0.148712158203125 +35678 0.145263671875 +35679 0.241729736328125 +35680 0.205047607421875 +35681 0.34912109375 +35682 0.26458740234375 +35683 0.457305908203125 +35684 0.3115234375 +35685 0.54388427734375 +35686 0.326080322265625 +35687 0.5728759765625 +35688 0.287567138671875 +35689 0.506591796875 +35690 0.199493408203125 +35691 0.351226806640625 +35692 0.083953857421875 +35693 0.146514892578125 +35694 -0.030029296875 +35695 -0.05523681640625 +35696 -0.121490478515625 +35697 -0.21624755859375 +35698 -0.189361572265625 +35699 -0.334930419921875 +35700 -0.22894287109375 +35701 -0.402984619140625 +35702 -0.251678466796875 +35703 -0.4412841796875 +35704 -0.282867431640625 +35705 -0.49578857421875 +35706 -0.318939208984375 +35707 -0.5601806640625 +35708 -0.34130859375 +35709 -0.600738525390625 +35710 -0.331634521484375 +35711 -0.584228515625 +35712 -0.27264404296875 +35713 -0.47930908203125 +35714 -0.1607666015625 +35715 -0.27935791015625 +35716 -0.0096435546875 +35717 -0.0089111328125 +35718 0.145660400390625 +35719 0.268798828125 +35720 0.265899658203125 +35721 0.482818603515625 +35722 0.334686279296875 +35723 0.60369873046875 +35724 0.36236572265625 +35725 0.650421142578125 +35726 0.37152099609375 +35727 0.66400146484375 +35728 0.360443115234375 +35729 0.6414794921875 +35730 0.3233642578125 +35731 0.572540283203125 +35732 0.2828369140625 +35733 0.498138427734375 +35734 0.25054931640625 +35735 0.439453125 +35736 0.21490478515625 +35737 0.375518798828125 +35738 0.15838623046875 +35739 0.274505615234375 +35740 0.0657958984375 +35741 0.1087646484375 +35742 -0.05047607421875 +35743 -0.099395751953125 +35744 -0.172821044921875 +35745 -0.3182373046875 +35746 -0.301849365234375 +35747 -0.5489501953125 +35748 -0.4276123046875 +35749 -0.7738037109375 +35750 -0.52081298828125 +35751 -0.86383056640625 +35752 -0.563018798828125 +35753 -0.870391845703125 +35754 -0.563934326171875 +35755 -0.86895751953125 +35756 -0.53076171875 +35757 -0.861053466796875 +35758 -0.45391845703125 +35759 -0.765869140625 +35760 -0.3271484375 +35761 -0.5301513671875 +35762 -0.154388427734375 +35763 -0.214691162109375 +35764 0.040557861328125 +35765 0.137359619140625 +35766 0.2293701171875 +35767 0.474822998046875 +35768 0.392333984375 +35769 0.76239013671875 +35770 0.514495849609375 +35771 0.867462158203125 +35772 0.596038818359375 +35773 0.870361328125 +35774 0.6304931640625 +35775 0.86480712890625 +35776 0.6207275390625 +35777 0.831817626953125 +35778 0.58013916015625 +35779 0.677581787109375 +35780 0.511871337890625 +35781 0.495880126953125 +35782 0.426116943359375 +35783 0.30767822265625 +35784 0.32403564453125 +35785 0.116180419921875 +35786 0.1881103515625 +35787 -0.110748291015625 +35788 0.014556884765625 +35789 -0.381805419921875 +35790 -0.1729736328125 +35791 -0.6572265625 +35792 -0.34136962890625 +35793 -0.857421875 +35794 -0.4669189453125 +35795 -0.870391845703125 +35796 -0.545654296875 +35797 -0.870391845703125 +35798 -0.59234619140625 +35799 -0.86444091796875 +35800 -0.626617431640625 +35801 -0.85723876953125 +35802 -0.6383056640625 +35803 -0.790008544921875 +35804 -0.59735107421875 +35805 -0.62847900390625 +35806 -0.501953125 +35807 -0.3956298828125 +35808 -0.370208740234375 +35809 -0.126708984375 +35810 -0.21722412109375 +35811 0.150115966796875 +35812 -0.049468994140625 +35813 0.424041748046875 +35814 0.1181640625 +35815 0.670623779296875 +35816 0.2642822265625 +35817 0.854522705078125 +35818 0.37908935546875 +35819 0.866485595703125 +35820 0.45404052734375 +35821 0.86920166015625 +35822 0.49908447265625 +35823 0.8653564453125 +35824 0.5216064453125 +35825 0.857147216796875 +35826 0.51995849609375 +35827 0.766845703125 +35828 0.496856689453125 +35829 0.628509521484375 +35830 0.44854736328125 +35831 0.462127685546875 +35832 0.389251708984375 +35833 0.297210693359375 +35834 0.32574462890625 +35835 0.14862060546875 +35836 0.24542236328125 +35837 -0.00537109375 +35838 0.152435302734375 +35839 -0.15753173828125 +35840 0.04522705078125 +35841 -0.31304931640625 +35842 -0.083831787109375 +35843 -0.48876953125 +35844 -0.210174560546875 +35845 -0.6416015625 +35846 -0.320098876953125 +35847 -0.751373291015625 +35848 -0.4249267578125 +35849 -0.84619140625 +35850 -0.51641845703125 +35851 -0.861297607421875 +35852 -0.576934814453125 +35853 -0.863250732421875 +35854 -0.58978271484375 +35855 -0.856597900390625 +35856 -0.5611572265625 +35857 -0.7498779296875 +35858 -0.52117919921875 +35859 -0.624542236328125 +35860 -0.458587646484375 +35861 -0.47808837890625 +35862 -0.34332275390625 +35863 -0.253387451171875 +35864 -0.199493408203125 +35865 0.003692626953125 +35866 -0.063079833984375 +35867 0.2257080078125 +35868 0.07196044921875 +35869 0.427154541015625 +35870 0.22198486328125 +35871 0.643218994140625 +35872 0.381500244140625 +35873 0.855926513671875 +35874 0.51995849609375 +35875 0.870361328125 +35876 0.611236572265625 +35877 0.870361328125 +35878 0.6588134765625 +35879 0.862762451171875 +35880 0.66094970703125 +35881 0.79669189453125 +35882 0.612701416015625 +35883 0.595794677734375 +35884 0.529296875 +35885 0.362152099609375 +35886 0.425445556640625 +35887 0.1270751953125 +35888 0.312408447265625 +35889 -0.086944580078125 +35890 0.191619873046875 +35891 -0.2784423828125 +35892 0.04534912109375 +35893 -0.484832763671875 +35894 -0.135955810546875 +35895 -0.729583740234375 +35896 -0.325592041015625 +35897 -0.86688232421875 +35898 -0.490203857421875 +35899 -0.870391845703125 +35900 -0.626800537109375 +35901 -0.86859130859375 +35902 -0.733978271484375 +35903 -0.86279296875 +35904 -0.792724609375 +35905 -0.817962646484375 +35906 -0.779266357421875 +35907 -0.6116943359375 +35908 -0.689849853515625 +35909 -0.3128662109375 +35910 -0.5419921875 +35911 0.039398193359375 +35912 -0.346221923828125 +35913 0.422821044921875 +35914 -0.120025634765625 +35915 0.805145263671875 +35916 0.100830078125 +35917 0.870361328125 +35918 0.286346435546875 +35919 0.870361328125 +35920 0.42999267578125 +35921 0.860015869140625 +35922 0.52734375 +35923 0.727935791015625 +35924 0.57501220703125 +35925 0.48114013671875 +35926 0.58514404296875 +35927 0.2059326171875 +35928 0.569091796875 +35929 -0.06103515625 +35930 0.531768798828125 +35931 -0.29913330078125 +35932 0.46539306640625 +35933 -0.516204833984375 +35934 0.36187744140625 +35935 -0.7252197265625 +35936 0.23419189453125 +35937 -0.85980224609375 +35938 0.100341796875 +35939 -0.870391845703125 +35940 -0.02398681640625 +35941 -0.870391845703125 +35942 -0.11309814453125 +35943 -0.858062744140625 +35944 -0.164306640625 +35945 -0.673004150390625 +35946 -0.204345703125 +35947 -0.42694091796875 +35948 -0.255706787109375 +35949 -0.2100830078125 +35950 -0.31671142578125 +35951 -0.0362548828125 +35952 -0.37176513671875 +35953 0.10943603515625 +35954 -0.4100341796875 +35955 0.23516845703125 +35956 -0.409637451171875 +35957 0.373687744140625 +35958 -0.371307373046875 +35959 0.517791748046875 +35960 -0.327728271484375 +35961 0.602783203125 +35962 -0.27618408203125 +35963 0.635711669921875 +35964 -0.19952392578125 +35965 0.655181884765625 +35966 -0.103179931640625 +35967 0.65948486328125 +35968 0.008270263671875 +35969 0.651275634765625 +35970 0.12158203125 +35971 0.61846923828125 +35972 0.217010498046875 +35973 0.53753662109375 +35974 0.28460693359375 +35975 0.404144287109375 +35976 0.31878662109375 +35977 0.22186279296875 +35978 0.3197021484375 +35979 0.003997802734375 +35980 0.29632568359375 +35981 -0.22100830078125 +35982 0.259002685546875 +35983 -0.42449951171875 +35984 0.21856689453125 +35985 -0.579833984375 +35986 0.1971435546875 +35987 -0.641876220703125 +35988 0.19122314453125 +35989 -0.6177978515625 +35990 0.167327880859375 +35991 -0.575531005859375 +35992 0.122894287109375 +35993 -0.526336669921875 +35994 0.085174560546875 +35995 -0.42645263671875 +35996 0.06884765625 +35997 -0.2581787109375 +35998 0.05548095703125 +35999 -0.068695068359375 +36000 0.0255126953125 +36001 0.09222412109375 +36002 -0.0108642578125 +36003 0.232147216796875 +36004 -0.0478515625 +36005 0.3509521484375 +36006 -0.1004638671875 +36007 0.410064697265625 +36008 -0.18359375 +36009 0.372955322265625 +36010 -0.286041259765625 +36011 0.2554931640625 +36012 -0.380523681640625 +36013 0.10711669921875 +36014 -0.456756591796875 +36015 -0.052886962890625 +36016 -0.49591064453125 +36017 -0.186279296875 +36018 -0.46905517578125 +36019 -0.23291015625 +36020 -0.38824462890625 +36021 -0.209442138671875 +36022 -0.28802490234375 +36023 -0.174163818359375 +36024 -0.173065185546875 +36025 -0.126739501953125 +36026 -0.038665771484375 +36027 -0.048126220703125 +36028 0.10009765625 +36029 0.0426025390625 +36030 0.218536376953125 +36031 0.10748291015625 +36032 0.309356689453125 +36033 0.1409912109375 +36034 0.396942138671875 +36035 0.19708251953125 +36036 0.4774169921875 +36037 0.273651123046875 +36038 0.52154541015625 +36039 0.31768798828125 +36040 0.534912109375 +36041 0.341094970703125 +36042 0.530609130859375 +36043 0.368011474609375 +36044 0.496673583984375 +36045 0.37249755859375 +36046 0.4075927734375 +36047 0.30072021484375 +36048 0.26617431640625 +36049 0.1517333984375 +36050 0.107269287109375 +36051 -0.01470947265625 +36052 -0.059539794921875 +36053 -0.1883544921875 +36054 -0.2318115234375 +36055 -0.372711181640625 +36056 -0.37738037109375 +36057 -0.51397705078125 +36058 -0.471435546875 +36059 -0.57177734375 +36060 -0.50732421875 +36061 -0.53948974609375 +36062 -0.491851806640625 +36063 -0.43511962890625 +36064 -0.442840576171875 +36065 -0.2962646484375 +36066 -0.379364013671875 +36067 -0.161102294921875 +36068 -0.3087158203125 +36069 -0.0435791015625 +36070 -0.229766845703125 +36071 0.060394287109375 +36072 -0.151702880859375 +36073 0.13665771484375 +36074 -0.084808349609375 +36075 0.170135498046875 +36076 -0.0296630859375 +36077 0.16552734375 +36078 0.028228759765625 +36079 0.15728759765625 +36080 0.088165283203125 +36081 0.150787353515625 +36082 0.134185791015625 +36083 0.12200927734375 +36084 0.167755126953125 +36085 0.080108642578125 +36086 0.19964599609375 +36087 0.05126953125 +36088 0.2418212890625 +36089 0.062896728515625 +36090 0.281036376953125 +36091 0.09271240234375 +36092 0.291534423828125 +36093 0.092987060546875 +36094 0.28082275390625 +36095 0.07855224609375 +36096 0.25732421875 +36097 0.06427001953125 +36098 0.21429443359375 +36099 0.0347900390625 +36100 0.15252685546875 +36101 -0.01171875 +36102 0.084136962890625 +36103 -0.056060791015625 +36104 0.0333251953125 +36105 -0.055511474609375 +36106 0.002899169921875 +36107 -0.010467529296875 +36108 -0.0311279296875 +36109 0.02508544921875 +36110 -0.07867431640625 +36111 0.025665283203125 +36112 -0.124176025390625 +36113 0.017333984375 +36114 -0.16473388671875 +36115 0.00189208984375 +36116 -0.204315185546875 +36117 -0.03173828125 +36118 -0.235992431640625 +36119 -0.071502685546875 +36120 -0.2684326171875 +36121 -0.13543701171875 +36122 -0.3001708984375 +36123 -0.219970703125 +36124 -0.31976318359375 +36125 -0.300506591796875 +36126 -0.32830810546875 +36127 -0.376312255859375 +36128 -0.31201171875 +36129 -0.416107177734375 +36130 -0.248687744140625 +36131 -0.371124267578125 +36132 -0.141143798828125 +36133 -0.242279052734375 +36134 -0.011871337890625 +36135 -0.069732666015625 +36136 0.126312255859375 +36137 0.125640869140625 +36138 0.25567626953125 +36139 0.31268310546875 +36140 0.356231689453125 +36141 0.45501708984375 +36142 0.427642822265625 +36143 0.554779052734375 +36144 0.468292236328125 +36145 0.61065673828125 +36146 0.471893310546875 +36147 0.610931396484375 +36148 0.426483154296875 +36149 0.531463623046875 +36150 0.340606689453125 +36151 0.3883056640625 +36152 0.241912841796875 +36153 0.23468017578125 +36154 0.1441650390625 +36155 0.095245361328125 +36156 0.06207275390625 +36157 -0.00396728515625 +36158 0.00469970703125 +36159 -0.04852294921875 +36160 -0.03424072265625 +36161 -0.055145263671875 +36162 -0.07879638671875 +36163 -0.0758056640625 +36164 -0.1412353515625 +36165 -0.138702392578125 +36166 -0.202667236328125 +36167 -0.209197998046875 +36168 -0.262664794921875 +36169 -0.289031982421875 +36170 -0.32061767578125 +36171 -0.37884521484375 +36172 -0.3648681640625 +36173 -0.456329345703125 +36174 -0.392791748046875 +36175 -0.51641845703125 +36176 -0.38482666015625 +36177 -0.519287109375 +36178 -0.33831787109375 +36179 -0.458251953125 +36180 -0.28009033203125 +36181 -0.384796142578125 +36182 -0.223846435546875 +36183 -0.323699951171875 +36184 -0.16827392578125 +36185 -0.269287109375 +36186 -0.101837158203125 +36187 -0.1951904296875 +36188 -0.02545166015625 +36189 -0.100006103515625 +36190 0.0458984375 +36191 -0.01055908203125 +36192 0.12591552734375 +36193 0.1033935546875 +36194 0.21710205078125 +36195 0.24908447265625 +36196 0.291900634765625 +36197 0.373199462890625 +36198 0.340972900390625 +36199 0.45806884765625 +36200 0.368011474609375 +36201 0.511474609375 +36202 0.389190673828125 +36203 0.565399169921875 +36204 0.4007568359375 +36205 0.61138916015625 +36206 0.3736572265625 +36207 0.5897216796875 +36208 0.303985595703125 +36209 0.4906005859375 +36210 0.20172119140625 +36211 0.33148193359375 +36212 0.085845947265625 +36213 0.147796630859375 +36214 -0.021392822265625 +36215 -0.01873779296875 +36216 -0.10479736328125 +36217 -0.140289306640625 +36218 -0.150726318359375 +36219 -0.191986083984375 +36220 -0.16339111328125 +36221 -0.184295654296875 +36222 -0.164276123046875 +36223 -0.161834716796875 +36224 -0.173858642578125 +36225 -0.166595458984375 +36226 -0.189544677734375 +36227 -0.19390869140625 +36228 -0.20172119140625 +36229 -0.22442626953125 +36230 -0.22149658203125 +36231 -0.279754638671875 +36232 -0.238983154296875 +36233 -0.3389892578125 +36234 -0.231109619140625 +36235 -0.3543701171875 +36236 -0.209930419921875 +36237 -0.348175048828125 +36238 -0.179290771484375 +36239 -0.32598876953125 +36240 -0.125518798828125 +36241 -0.2581787109375 +36242 -0.047210693359375 +36243 -0.139801025390625 +36244 0.04736328125 +36245 0.014617919921875 +36246 0.126922607421875 +36247 0.144378662109375 +36248 0.176513671875 +36249 0.221038818359375 +36250 0.20867919921875 +36251 0.27069091796875 +36252 0.223480224609375 +36253 0.294036865234375 +36254 0.231231689453125 +36255 0.311767578125 +36256 0.239715576171875 +36257 0.339141845703125 +36258 0.2412109375 +36259 0.360260009765625 +36260 0.22906494140625 +36261 0.360504150390625 +36262 0.188690185546875 +36263 0.308380126953125 +36264 0.110198974609375 +36265 0.18170166015625 +36266 0.006439208984375 +36267 0.0047607421875 +36268 -0.09869384765625 +36269 -0.17559814453125 +36270 -0.18231201171875 +36271 -0.3143310546875 +36272 -0.2222900390625 +36273 -0.36785888671875 +36274 -0.230743408203125 +36275 -0.36248779296875 +36276 -0.229278564453125 +36277 -0.343536376953125 +36278 -0.213134765625 +36279 -0.3018798828125 +36280 -0.17919921875 +36281 -0.231414794921875 +36282 -0.120452880859375 +36283 -0.117645263671875 +36284 -0.053009033203125 +36285 0.007049560546875 +36286 -0.0040283203125 +36287 0.087982177734375 +36288 0.032867431640625 +36289 0.13946533203125 +36290 0.063201904296875 +36291 0.17425537109375 +36292 0.08416748046875 +36293 0.188201904296875 +36294 0.09002685546875 +36295 0.171234130859375 +36296 0.07763671875 +36297 0.118438720703125 +36298 0.05963134765625 +36299 0.05706787109375 +36300 0.03643798828125 +36301 -0.010711669921875 +36302 0.004364013671875 +36303 -0.0914306640625 +36304 -0.025787353515625 +36305 -0.162322998046875 +36306 -0.04010009765625 +36307 -0.194549560546875 +36308 -0.019622802734375 +36309 -0.1492919921875 +36310 0.038177490234375 +36311 -0.02166748046875 +36312 0.102264404296875 +36313 0.124053955078125 +36314 0.135650634765625 +36315 0.211151123046875 +36316 0.139312744140625 +36317 0.240447998046875 +36318 0.128631591796875 +36319 0.242218017578125 +36320 0.10882568359375 +36321 0.2257080078125 +36322 0.08221435546875 +36323 0.194366455078125 +36324 0.033447265625 +36325 0.115509033203125 +36326 -0.025390625 +36327 0.0128173828125 +36328 -0.06463623046875 +36329 -0.053802490234375 +36330 -0.0968017578125 +36331 -0.110626220703125 +36332 -0.142120361328125 +36333 -0.199493408203125 +36334 -0.187835693359375 +36335 -0.29437255859375 +36336 -0.20330810546875 +36337 -0.33221435546875 +36338 -0.17254638671875 +36339 -0.27972412109375 +36340 -0.1195068359375 +36341 -0.185333251953125 +36342 -0.083251953125 +36343 -0.128204345703125 +36344 -0.067840576171875 +36345 -0.115692138671875 +36346 -0.058502197265625 +36347 -0.116455078125 +36348 -0.0438232421875 +36349 -0.105926513671875 +36350 -0.009613037109375 +36351 -0.053955078125 +36352 0.048004150390625 +36353 0.048797607421875 +36354 0.10699462890625 +36355 0.157318115234375 +36356 0.139068603515625 +36357 0.212005615234375 +36358 0.14642333984375 +36359 0.218475341796875 +36360 0.156463623046875 +36361 0.23724365234375 +36362 0.186126708984375 +36363 0.30535888671875 +36364 0.216644287109375 +36365 0.38128662109375 +36366 0.220703125 +36367 0.404449462890625 +36368 0.20770263671875 +36369 0.3944091796875 +36370 0.195220947265625 +36371 0.3885498046875 +36372 0.172821044921875 +36373 0.362640380859375 +36374 0.121490478515625 +36375 0.27362060546875 +36376 0.03985595703125 +36377 0.11712646484375 +36378 -0.047821044921875 +36379 -0.054901123046875 +36380 -0.117523193359375 +36381 -0.19085693359375 +36382 -0.16656494140625 +36383 -0.28570556640625 +36384 -0.194610595703125 +36385 -0.339263916015625 +36386 -0.21337890625 +36387 -0.3775634765625 +36388 -0.243438720703125 +36389 -0.445709228515625 +36390 -0.281005859375 +36391 -0.535064697265625 +36392 -0.3187255859375 +36393 -0.629058837890625 +36394 -0.34320068359375 +36395 -0.697601318359375 +36396 -0.338104248046875 +36397 -0.70391845703125 +36398 -0.301361083984375 +36399 -0.6424560546875 +36400 -0.223480224609375 +36401 -0.491241455078125 +36402 -0.111968994140625 +36403 -0.265716552734375 +36404 0.00628662109375 +36405 -0.023712158203125 +36406 0.115814208984375 +36407 0.201751708984375 +36408 0.200408935546875 +36409 0.375823974609375 +36410 0.253692626953125 +36411 0.485076904296875 +36412 0.293487548828125 +36413 0.56884765625 +36414 0.323272705078125 +36415 0.634765625 +36416 0.322479248046875 +36417 0.63763427734375 +36418 0.28607177734375 +36419 0.5660400390625 +36420 0.238037109375 +36421 0.4720458984375 +36422 0.202056884765625 +36423 0.40692138671875 +36424 0.181793212890625 +36425 0.3778076171875 +36426 0.174102783203125 +36427 0.376953125 +36428 0.16461181640625 +36429 0.371978759765625 +36430 0.13104248046875 +36431 0.313140869140625 +36432 0.06640625 +36433 0.184417724609375 +36434 -0.017364501953125 +36435 0.011199951171875 +36436 -0.103851318359375 +36437 -0.171051025390625 +36438 -0.181549072265625 +36439 -0.33740234375 +36440 -0.2431640625 +36441 -0.47198486328125 +36442 -0.28216552734375 +36443 -0.560394287109375 +36444 -0.28863525390625 +36445 -0.58056640625 +36446 -0.26959228515625 +36447 -0.54754638671875 +36448 -0.24688720703125 +36449 -0.508575439453125 +36450 -0.2188720703125 +36451 -0.459503173828125 +36452 -0.18316650390625 +36453 -0.394378662109375 +36454 -0.1580810546875 +36455 -0.35260009765625 +36456 -0.133697509765625 +36457 -0.31170654296875 +36458 -0.076446533203125 +36459 -0.197418212890625 +36460 0.014190673828125 +36461 -0.007965087890625 +36462 0.115570068359375 +36463 0.207489013671875 +36464 0.20941162109375 +36465 0.409210205078125 +36466 0.28424072265625 +36467 0.57208251953125 +36468 0.326324462890625 +36469 0.66595458984375 +36470 0.321075439453125 +36471 0.65875244140625 +36472 0.276397705078125 +36473 0.56744384765625 +36474 0.210418701171875 +36475 0.431396484375 +36476 0.143402099609375 +36477 0.29443359375 +36478 0.08740234375 +36479 0.182464599609375 +36480 0.028228759765625 +36481 0.06365966796875 +36482 -0.040252685546875 +36483 -0.075958251953125 +36484 -0.096343994140625 +36485 -0.189422607421875 +36486 -0.13763427734375 +36487 -0.271942138671875 +36488 -0.172607421875 +36489 -0.342529296875 +36490 -0.18426513671875 +36491 -0.364166259765625 +36492 -0.16815185546875 +36493 -0.327239990234375 +36494 -0.1448974609375 +36495 -0.2769775390625 +36496 -0.1329345703125 +36497 -0.253692626953125 +36498 -0.1260986328125 +36499 -0.24365234375 +36500 -0.102447509765625 +36501 -0.1983642578125 +36502 -0.061431884765625 +36503 -0.116241455078125 +36504 -0.021270751953125 +36505 -0.036834716796875 +36506 0.0155029296875 +36507 0.034881591796875 +36508 0.045166015625 +36509 0.09124755859375 +36510 0.056884765625 +36511 0.10888671875 +36512 0.067657470703125 +36513 0.125518798828125 +36514 0.084869384765625 +36515 0.15771484375 +36516 0.095977783203125 +36517 0.17828369140625 +36518 0.09356689453125 +36519 0.17108154296875 +36520 0.0748291015625 +36521 0.129974365234375 +36522 0.05230712890625 +36523 0.082427978515625 +36524 0.025726318359375 +36525 0.027679443359375 +36526 -0.019073486328125 +36527 -0.065643310546875 +36528 -0.064544677734375 +36529 -0.15936279296875 +36530 -0.09210205078125 +36531 -0.21307373046875 +36532 -0.105194091796875 +36533 -0.234649658203125 +36534 -0.092742919921875 +36535 -0.2001953125 +36536 -0.058868408203125 +36537 -0.119171142578125 +36538 -0.0185546875 +36539 -0.024749755859375 +36540 0.029571533203125 +36541 0.085784912109375 +36542 0.069976806640625 +36543 0.178131103515625 +36544 0.08599853515625 +36545 0.215576171875 +36546 0.083770751953125 +36547 0.211456298828125 +36548 0.067596435546875 +36549 0.17523193359375 +36550 0.047393798828125 +36551 0.128753662109375 +36552 0.0367431640625 +36553 0.1019287109375 +36554 0.0262451171875 +36555 0.0743408203125 +36556 0.0145263671875 +36557 0.04327392578125 +36558 0.014862060546875 +36559 0.038177490234375 +36560 0.034942626953125 +36561 0.076263427734375 +36562 0.067108154296875 +36563 0.14105224609375 +36564 0.090179443359375 +36565 0.186431884765625 +36566 0.093292236328125 +36567 0.188812255859375 +36568 0.0721435546875 +36569 0.1390380859375 +36570 0.028839111328125 +36571 0.041778564453125 +36572 -0.025909423828125 +36573 -0.079437255859375 +36574 -0.08978271484375 +36575 -0.219390869140625 +36576 -0.158050537109375 +36577 -0.367828369140625 +36578 -0.217041015625 +36579 -0.494873046875 +36580 -0.246490478515625 +36581 -0.556243896484375 +36582 -0.226593017578125 +36583 -0.508697509765625 +36584 -0.16790771484375 +36585 -0.3756103515625 +36586 -0.09857177734375 +36587 -0.218902587890625 +36588 -0.029937744140625 +36589 -0.063751220703125 +36590 0.038848876953125 +36591 0.091552734375 +36592 0.102874755859375 +36593 0.23602294921875 +36594 0.150115966796875 +36595 0.342987060546875 +36596 0.17279052734375 +36597 0.39520263671875 +36598 0.16943359375 +36599 0.389373779296875 +36600 0.1395263671875 +36601 0.324249267578125 +36602 0.0941162109375 +36603 0.224090576171875 +36604 0.04931640625 +36605 0.124267578125 +36606 0.010650634765625 +36607 0.037078857421875 +36608 -0.0098876953125 +36609 -0.010101318359375 +36610 -0.013153076171875 +36611 -0.019439697265625 +36612 -0.01312255859375 +36613 -0.022796630859375 +36614 -0.002197265625 +36615 -0.001556396484375 +36616 0.024444580078125 +36617 0.056304931640625 +36618 0.047821044921875 +36619 0.106719970703125 +36620 0.04541015625 +36621 0.096893310546875 +36622 0.0238037109375 +36623 0.042694091796875 +36624 -0.00103759765625 +36625 -0.018035888671875 +36626 -0.025146484375 +36627 -0.07586669921875 +36628 -0.043701171875 +36629 -0.11944580078125 +36630 -0.06134033203125 +36631 -0.15972900390625 +36632 -0.080474853515625 +36633 -0.202606201171875 +36634 -0.1011962890625 +36635 -0.24859619140625 +36636 -0.126617431640625 +36637 -0.30517578125 +36638 -0.152313232421875 +36639 -0.36212158203125 +36640 -0.16632080078125 +36641 -0.39141845703125 +36642 -0.15252685546875 +36643 -0.35528564453125 +36644 -0.1092529296875 +36645 -0.249969482421875 +36646 -0.043792724609375 +36647 -0.092864990234375 +36648 0.032470703125 +36649 0.08905029296875 +36650 0.093902587890625 +36651 0.2352294921875 +36652 0.129150390625 +36653 0.318817138671875 +36654 0.14617919921875 +36655 0.358642578125 +36656 0.14202880859375 +36657 0.347747802734375 +36658 0.116424560546875 +36659 0.28564453125 +36660 0.090911865234375 +36661 0.223175048828125 +36662 0.080841064453125 +36663 0.196746826171875 +36664 0.074920654296875 +36665 0.179840087890625 +36666 0.06591796875 +36667 0.155548095703125 +36668 0.065338134765625 +36669 0.151214599609375 +36670 0.068939208984375 +36671 0.156951904296875 +36672 0.05926513671875 +36673 0.13177490234375 +36674 0.046905517578125 +36675 0.100799560546875 +36676 0.0416259765625 +36677 0.087127685546875 +36678 0.0281982421875 +36679 0.05487060546875 +36680 0.001068115234375 +36681 -0.009002685546875 +36682 -0.03948974609375 +36683 -0.10400390625 +36684 -0.093170166015625 +36685 -0.229400634765625 +36686 -0.1473388671875 +36687 -0.35552978515625 +36688 -0.184783935546875 +36689 -0.441925048828125 +36690 -0.199249267578125 +36691 -0.473846435546875 +36692 -0.1964111328125 +36693 -0.464813232421875 +36694 -0.178009033203125 +36695 -0.419097900390625 +36696 -0.142974853515625 +36697 -0.334320068359375 +36698 -0.098663330078125 +36699 -0.227935791015625 +36700 -0.055023193359375 +36701 -0.12347412109375 +36702 -0.014862060546875 +36703 -0.02764892578125 +36704 0.029541015625 +36705 0.077667236328125 +36706 0.08697509765625 +36707 0.2132568359375 +36708 0.16156005859375 +36709 0.38885498046875 +36710 0.24407958984375 +36711 0.582794189453125 +36712 0.30865478515625 +36713 0.734039306640625 +36714 0.337249755859375 +36715 0.800140380859375 +36716 0.328643798828125 +36717 0.7783203125 +36718 0.2813720703125 +36719 0.6651611328125 +36720 0.194976806640625 +36721 0.45965576171875 +36722 0.08526611328125 +36723 0.199188232421875 +36724 -0.019989013671875 +36725 -0.050689697265625 +36726 -0.096649169921875 +36727 -0.23297119140625 +36728 -0.1373291015625 +36729 -0.33013916015625 +36730 -0.1531982421875 +36731 -0.368408203125 +36732 -0.157440185546875 +36733 -0.378936767578125 +36734 -0.15655517578125 +36735 -0.376983642578125 +36736 -0.1578369140625 +36737 -0.37969970703125 +36738 -0.16314697265625 +36739 -0.391510009765625 +36740 -0.160980224609375 +36741 -0.385345458984375 +36742 -0.143096923828125 +36743 -0.3419189453125 +36744 -0.118682861328125 +36745 -0.28289794921875 +36746 -0.1060791015625 +36747 -0.251617431640625 +36748 -0.112884521484375 +36749 -0.266143798828125 +36750 -0.116546630859375 +36751 -0.273345947265625 +36752 -0.093109130859375 +36753 -0.216796875 +36754 -0.055999755859375 +36755 -0.128265380859375 +36756 -0.03082275390625 +36757 -0.068145751953125 +36758 -0.0203857421875 +36759 -0.0430908203125 +36760 -0.01251220703125 +36761 -0.024444580078125 +36762 0.006744384765625 +36763 0.020721435546875 +36764 0.050933837890625 +36765 0.124481201171875 +36766 0.1077880859375 +36767 0.25787353515625 +36768 0.159576416015625 +36769 0.379119873046875 +36770 0.2027587890625 +36771 0.47991943359375 +36772 0.22369384765625 +36773 0.5281982421875 +36774 0.2169189453125 +36775 0.511138916015625 +36776 0.194061279296875 +36777 0.456207275390625 +36778 0.17376708984375 +36779 0.407470703125 +36780 0.16400146484375 +36781 0.383758544921875 +36782 0.152801513671875 +36783 0.35687255859375 +36784 0.1337890625 +36785 0.31182861328125 +36786 0.107940673828125 +36787 0.250885009765625 +36788 0.071624755859375 +36789 0.1654052734375 +36790 0.016265869140625 +36791 0.035247802734375 +36792 -0.059112548828125 +36793 -0.142059326171875 +36794 -0.141448974609375 +36795 -0.33563232421875 +36796 -0.226043701171875 +36797 -0.5345458984375 +36798 -0.30572509765625 +36799 -0.72186279296875 +36800 -0.3546142578125 +36801 -0.836669921875 +36802 -0.353118896484375 +36803 -0.8326416015625 +36804 -0.309600830078125 +36805 -0.7296142578125 +36806 -0.247406005859375 +36807 -0.582550048828125 +36808 -0.1871337890625 +36809 -0.440093994140625 +36810 -0.13812255859375 +36811 -0.324310302734375 +36812 -0.0860595703125 +36813 -0.20147705078125 +36814 -0.01953125 +36815 -0.044647216796875 +36816 0.0435791015625 +36817 0.103973388671875 +36818 0.085418701171875 +36819 0.202392578125 +36820 0.11187744140625 +36821 0.264495849609375 +36822 0.1435546875 +36823 0.338897705078125 +36824 0.18817138671875 +36825 0.443817138671875 +36826 0.231231689453125 +36827 0.545074462890625 +36828 0.261962890625 +36829 0.6173095703125 +36830 0.2769775390625 +36831 0.6524658203125 +36832 0.28167724609375 +36833 0.66339111328125 +36834 0.27862548828125 +36835 0.6561279296875 +36836 0.2576904296875 +36837 0.606781005859375 +36838 0.212860107421875 +36839 0.501190185546875 +36840 0.14984130859375 +36841 0.352783203125 +36842 0.07501220703125 +36843 0.176544189453125 +36844 -0.014678955078125 +36845 -0.034820556640625 +36846 -0.10943603515625 +36847 -0.258209228515625 +36848 -0.18756103515625 +36849 -0.44244384765625 +36850 -0.243865966796875 +36851 -0.5753173828125 +36852 -0.2763671875 +36853 -0.65203857421875 +36854 -0.271942138671875 +36855 -0.641632080078125 +36856 -0.23822021484375 +36857 -0.562164306640625 +36858 -0.194061279296875 +36859 -0.458038330078125 +36860 -0.148468017578125 +36861 -0.350555419921875 +36862 -0.110260009765625 +36863 -0.260528564453125 +36864 -0.081024169921875 +36865 -0.192108154296875 +36866 -0.059295654296875 +36867 -0.141937255859375 +36868 -0.042022705078125 +36869 -0.1021728515625 +36870 -0.025115966796875 +36871 -0.062896728515625 +36872 -0.00372314453125 +36873 -0.011932373046875 +36874 0.026947021484375 +36875 0.062835693359375 +36876 0.06195068359375 +36877 0.148712158203125 +36878 0.099700927734375 +36879 0.241729736328125 +36880 0.1429443359375 +36881 0.34912109375 +36882 0.186309814453125 +36883 0.457305908203125 +36884 0.220947265625 +36885 0.54388427734375 +36886 0.23272705078125 +36887 0.5728759765625 +36888 0.206787109375 +36889 0.506591796875 +36890 0.14556884765625 +36891 0.351226806640625 +36892 0.06463623046875 +36893 0.146514892578125 +36894 -0.01544189453125 +36895 -0.05523681640625 +36896 -0.079833984375 +36897 -0.21624755859375 +36898 -0.1278076171875 +36899 -0.334930419921875 +36900 -0.156036376953125 +36901 -0.402984619140625 +36902 -0.172637939453125 +36903 -0.4412841796875 +36904 -0.195556640625 +36905 -0.49578857421875 +36906 -0.22222900390625 +36907 -0.5601806640625 +36908 -0.2393798828125 +36909 -0.600738525390625 +36910 -0.233917236328125 +36911 -0.584228515625 +36912 -0.1934814453125 +36913 -0.47930908203125 +36914 -0.115478515625 +36915 -0.27935791015625 +36916 -0.009490966796875 +36917 -0.0089111328125 +36918 0.09967041015625 +36919 0.268798828125 +36920 0.18414306640625 +36921 0.482818603515625 +36922 0.23236083984375 +36923 0.60369873046875 +36924 0.251708984375 +36925 0.650421142578125 +36926 0.258209228515625 +36927 0.66400146484375 +36928 0.250640869140625 +36929 0.6414794921875 +36930 0.224884033203125 +36931 0.572540283203125 +36932 0.196929931640625 +36933 0.498138427734375 +36934 0.175018310546875 +36935 0.439453125 +36936 0.15087890625 +36937 0.375518798828125 +36938 0.11199951171875 +36939 0.274505615234375 +36940 0.0474853515625 +36941 0.1087646484375 +36942 -0.033935546875 +36943 -0.099395751953125 +36944 -0.11981201171875 +36945 -0.3182373046875 +36946 -0.210601806640625 +36947 -0.5489501953125 +36948 -0.299285888671875 +36949 -0.7738037109375 +36950 -0.365081787109375 +36951 -0.86383056640625 +36952 -0.394927978515625 +36953 -0.870391845703125 +36954 -0.395721435546875 +36955 -0.86895751953125 +36956 -0.37255859375 +36957 -0.861053466796875 +36958 -0.318603515625 +36959 -0.765869140625 +36960 -0.229400634765625 +36961 -0.5301513671875 +36962 -0.107666015625 +36963 -0.214691162109375 +36964 0.029754638671875 +36965 0.137359619140625 +36966 0.162750244140625 +36967 0.474822998046875 +36968 0.277435302734375 +36969 0.76239013671875 +36970 0.36322021484375 +36971 0.867462158203125 +36972 0.420318603515625 +36973 0.870361328125 +36974 0.44415283203125 +36975 0.86480712890625 +36976 0.436798095703125 +36977 0.831817626953125 +36978 0.40777587890625 +36979 0.677581787109375 +36980 0.35931396484375 +36981 0.495880126953125 +36982 0.29864501953125 +36983 0.30767822265625 +36984 0.22662353515625 +36985 0.116180419921875 +36986 0.130767822265625 +36987 -0.110748291015625 +36988 0.008331298828125 +36989 -0.381805419921875 +36990 -0.123931884765625 +36991 -0.6572265625 +36992 -0.242584228515625 +36993 -0.857421875 +36994 -0.330810546875 +36995 -0.870391845703125 +36996 -0.385833740234375 +36997 -0.870391845703125 +36998 -0.418182373046875 +36999 -0.86444091796875 +37000 -0.441864013671875 +37001 -0.85723876953125 +37002 -0.449676513671875 +37003 -0.790008544921875 +37004 -0.420318603515625 +37005 -0.62847900390625 +37006 -0.352508544921875 +37007 -0.3956298828125 +37008 -0.25909423828125 +37009 -0.126708984375 +37010 -0.150787353515625 +37011 0.150115966796875 +37012 -0.03216552734375 +37013 0.424041748046875 +37014 0.086212158203125 +37015 0.670623779296875 +37016 0.189178466796875 +37017 0.854522705078125 +37018 0.26983642578125 +37019 0.866485595703125 +37020 0.32220458984375 +37021 0.86920166015625 +37022 0.3533935546875 +37023 0.8653564453125 +37024 0.36865234375 +37025 0.857147216796875 +37026 0.366851806640625 +37027 0.766845703125 +37028 0.3499755859375 +37029 0.628509521484375 +37030 0.31536865234375 +37031 0.462127685546875 +37032 0.27313232421875 +37033 0.297210693359375 +37034 0.228118896484375 +37035 0.14862060546875 +37036 0.171356201171875 +37037 -0.00537109375 +37038 0.105712890625 +37039 -0.15753173828125 +37040 0.02978515625 +37041 -0.31304931640625 +37042 -0.061920166015625 +37043 -0.48876953125 +37044 -0.151031494140625 +37045 -0.6416015625 +37046 -0.227874755859375 +37047 -0.751373291015625 +37048 -0.301513671875 +37049 -0.84619140625 +37050 -0.366180419921875 +37051 -0.861297607421875 +37052 -0.408843994140625 +37053 -0.863250732421875 +37054 -0.4171142578125 +37055 -0.856597900390625 +37056 -0.395751953125 +37057 -0.7498779296875 +37058 -0.367431640625 +37059 -0.624542236328125 +37060 -0.32354736328125 +37061 -0.47808837890625 +37062 -0.24114990234375 +37063 -0.253387451171875 +37064 -0.13812255859375 +37065 0.003692626953125 +37066 -0.041259765625 +37067 0.2257080078125 +37068 0.0543212890625 +37069 0.427154541015625 +37070 0.16131591796875 +37071 0.643218994140625 +37072 0.27593994140625 +37073 0.855926513671875 +37074 0.375457763671875 +37075 0.870361328125 +37076 0.440399169921875 +37077 0.870361328125 +37078 0.473602294921875 +37079 0.862762451171875 +37080 0.473907470703125 +37081 0.79669189453125 +37082 0.437591552734375 +37083 0.595794677734375 +37084 0.376129150390625 +37085 0.362152099609375 +37086 0.300506591796875 +37087 0.1270751953125 +37088 0.218994140625 +37089 -0.086944580078125 +37090 0.132415771484375 +37091 -0.2784423828125 +37092 0.02716064453125 +37093 -0.484832763671875 +37094 -0.104248046875 +37095 -0.729583740234375 +37096 -0.241943359375 +37097 -0.86688232421875 +37098 -0.361114501953125 +37099 -0.870391845703125 +37100 -0.459747314453125 +37101 -0.86859130859375 +37102 -0.537017822265625 +37103 -0.86279296875 +37104 -0.578765869140625 +37105 -0.817962646484375 +37106 -0.567169189453125 +37107 -0.6116943359375 +37108 -0.49945068359375 +37109 -0.3128662109375 +37110 -0.3887939453125 +37111 0.039398193359375 +37112 -0.243072509765625 +37113 0.422821044921875 +37114 -0.075347900390625 +37115 0.805145263671875 +37116 0.087615966796875 +37117 0.870361328125 +37118 0.223419189453125 +37119 0.870361328125 +37120 0.327178955078125 +37121 0.860015869140625 +37122 0.396270751953125 +37123 0.727935791015625 +37124 0.428741455078125 +37125 0.48114013671875 +37126 0.43328857421875 +37127 0.2059326171875 +37128 0.41815185546875 +37129 -0.06103515625 +37130 0.387054443359375 +37131 -0.29913330078125 +37132 0.335052490234375 +37133 -0.516204833984375 +37134 0.256927490234375 +37135 -0.7252197265625 +37136 0.16204833984375 +37137 -0.85980224609375 +37138 0.063232421875 +37139 -0.870391845703125 +37140 -0.0283203125 +37141 -0.870391845703125 +37142 -0.094573974609375 +37143 -0.858062744140625 +37144 -0.13348388671875 +37145 -0.673004150390625 +37146 -0.163421630859375 +37147 -0.42694091796875 +37148 -0.19989013671875 +37149 -0.2100830078125 +37150 -0.241729736328125 +37151 -0.0362548828125 +37152 -0.278167724609375 +37153 0.10943603515625 +37154 -0.3018798828125 +37155 0.23516845703125 +37156 -0.297882080078125 +37157 0.373687744140625 +37158 -0.2669677734375 +37159 0.517791748046875 +37160 -0.23199462890625 +37161 0.602783203125 +37162 -0.191375732421875 +37163 0.635711669921875 +37164 -0.133514404296875 +37165 0.655181884765625 +37166 -0.062408447265625 +37167 0.65948486328125 +37168 0.018524169921875 +37169 0.651275634765625 +37170 0.099945068359375 +37171 0.61846923828125 +37172 0.16802978515625 +37173 0.53753662109375 +37174 0.2158203125 +37175 0.404144287109375 +37176 0.239410400390625 +37177 0.22186279296875 +37178 0.23895263671875 +37179 0.003997802734375 +37180 0.220733642578125 +37181 -0.22100830078125 +37182 0.19207763671875 +37183 -0.42449951171875 +37184 0.160675048828125 +37185 -0.579833984375 +37186 0.141998291015625 +37187 -0.641876220703125 +37188 0.133880615234375 +37189 -0.6177978515625 +37190 0.113372802734375 +37191 -0.575531005859375 +37192 0.078887939453125 +37193 -0.526336669921875 +37194 0.049530029296875 +37195 -0.42645263671875 +37196 0.03558349609375 +37197 -0.2581787109375 +37198 0.0244140625 +37199 -0.068695068359375 +37200 0.0025634765625 +37201 0.09222412109375 +37202 -0.022857666015625 +37203 0.232147216796875 +37204 -0.047882080078125 +37205 0.3509521484375 +37206 -0.082916259765625 +37207 0.410064697265625 +37208 -0.138397216796875 +37209 0.372955322265625 +37210 -0.206695556640625 +37211 0.2554931640625 +37212 -0.269073486328125 +37213 0.10711669921875 +37214 -0.31854248046875 +37215 -0.052886962890625 +37216 -0.34228515625 +37217 -0.186279296875 +37218 -0.320465087890625 +37219 -0.23291015625 +37220 -0.2615966796875 +37221 -0.209442138671875 +37222 -0.18975830078125 +37223 -0.174163818359375 +37224 -0.108306884765625 +37225 -0.126739501953125 +37226 -0.014068603515625 +37227 -0.048126220703125 +37228 0.082427978515625 +37229 0.0426025390625 +37230 0.16412353515625 +37231 0.10748291015625 +37232 0.22601318359375 +37233 0.1409912109375 +37234 0.285003662109375 +37235 0.19708251953125 +37236 0.33856201171875 +37237 0.273651123046875 +37238 0.3665771484375 +37239 0.31768798828125 +37240 0.373077392578125 +37241 0.341094970703125 +37242 0.367279052734375 +37243 0.368011474609375 +37244 0.341064453125 +37245 0.37249755859375 +37246 0.276885986328125 +37247 0.30072021484375 +37248 0.17681884765625 +37249 0.1517333984375 +37250 0.06512451171875 +37251 -0.01470947265625 +37252 -0.051483154296875 +37253 -0.1883544921875 +37254 -0.171234130859375 +37255 -0.372711181640625 +37256 -0.27191162109375 +37257 -0.51397705078125 +37258 -0.336334228515625 +37259 -0.57177734375 +37260 -0.35992431640625 +37261 -0.53948974609375 +37262 -0.347503662109375 +37263 -0.43511962890625 +37264 -0.311553955078125 +37265 -0.2962646484375 +37266 -0.265350341796875 +37267 -0.161102294921875 +37268 -0.214080810546875 +37269 -0.0435791015625 +37270 -0.1571044921875 +37271 0.060394287109375 +37272 -0.10089111328125 +37273 0.13665771484375 +37274 -0.052703857421875 +37275 0.170135498046875 +37276 -0.013031005859375 +37277 0.16552734375 +37278 0.028106689453125 +37279 0.15728759765625 +37280 0.070159912109375 +37281 0.150787353515625 +37282 0.10205078125 +37283 0.12200927734375 +37284 0.124847412109375 +37285 0.080108642578125 +37286 0.146026611328125 +37287 0.05126953125 +37288 0.173919677734375 +37289 0.062896728515625 +37290 0.199432373046875 +37291 0.09271240234375 +37292 0.204864501953125 +37293 0.092987060546875 +37294 0.19549560546875 +37295 0.07855224609375 +37296 0.17718505859375 +37297 0.06427001953125 +37298 0.1453857421875 +37299 0.0347900390625 +37300 0.100799560546875 +37301 -0.01171875 +37302 0.05206298828125 +37303 -0.056060791015625 +37304 0.0164794921875 +37305 -0.055511474609375 +37306 -0.003997802734375 +37307 -0.010467529296875 +37308 -0.02679443359375 +37309 0.02508544921875 +37310 -0.059173583984375 +37311 0.025665283203125 +37312 -0.090057373046875 +37313 0.017333984375 +37314 -0.117431640625 +37315 0.00189208984375 +37316 -0.144256591796875 +37317 -0.03173828125 +37318 -0.165618896484375 +37319 -0.071502685546875 +37320 -0.187835693359375 +37321 -0.13543701171875 +37322 -0.20989990234375 +37323 -0.219970703125 +37324 -0.223602294921875 +37325 -0.300506591796875 +37326 -0.229736328125 +37327 -0.376312255859375 +37328 -0.21832275390625 +37329 -0.416107177734375 +37330 -0.173370361328125 +37331 -0.371124267578125 +37332 -0.09686279296875 +37333 -0.242279052734375 +37334 -0.00494384765625 +37335 -0.069732666015625 +37336 0.09320068359375 +37337 0.125640869140625 +37338 0.1849365234375 +37339 0.31268310546875 +37340 0.25592041015625 +37341 0.45501708984375 +37342 0.30596923828125 +37343 0.554779052734375 +37344 0.334014892578125 +37345 0.61065673828125 +37346 0.335601806640625 +37347 0.610931396484375 +37348 0.302154541015625 +37349 0.531463623046875 +37350 0.2398681640625 +37351 0.3883056640625 +37352 0.168670654296875 +37353 0.23468017578125 +37354 0.098480224609375 +37355 0.095245361328125 +37356 0.039825439453125 +37357 -0.00396728515625 +37358 -0.000732421875 +37359 -0.04852294921875 +37360 -0.027801513671875 +37361 -0.055145263671875 +37362 -0.05877685546875 +37363 -0.0758056640625 +37364 -0.1025390625 +37365 -0.138702392578125 +37366 -0.145538330078125 +37367 -0.209197998046875 +37368 -0.18756103515625 +37369 -0.289031982421875 +37370 -0.228240966796875 +37371 -0.37884521484375 +37372 -0.259185791015625 +37373 -0.456329345703125 +37374 -0.278594970703125 +37375 -0.51641845703125 +37376 -0.272552490234375 +37377 -0.519287109375 +37378 -0.23919677734375 +37379 -0.458251953125 +37380 -0.19744873046875 +37381 -0.384796142578125 +37382 -0.156951904296875 +37383 -0.323699951171875 +37384 -0.116851806640625 +37385 -0.269287109375 +37386 -0.06915283203125 +37387 -0.1951904296875 +37388 -0.014617919921875 +37389 -0.100006103515625 +37390 0.03619384765625 +37391 -0.01055908203125 +37392 0.092864990234375 +37393 0.1033935546875 +37394 0.15704345703125 +37395 0.24908447265625 +37396 0.20947265625 +37397 0.373199462890625 +37398 0.243621826171875 +37399 0.45806884765625 +37400 0.2620849609375 +37401 0.511474609375 +37402 0.276214599609375 +37403 0.565399169921875 +37404 0.283416748046875 +37405 0.61138916015625 +37406 0.263397216796875 +37407 0.5897216796875 +37408 0.213531494140625 +37409 0.4906005859375 +37410 0.140838623046875 +37411 0.33148193359375 +37412 0.058685302734375 +37413 0.147796630859375 +37414 -0.017333984375 +37415 -0.01873779296875 +37416 -0.07647705078125 +37417 -0.140289306640625 +37418 -0.10919189453125 +37419 -0.191986083984375 +37420 -0.118408203125 +37421 -0.184295654296875 +37422 -0.119140625 +37423 -0.161834716796875 +37424 -0.125732421875 +37425 -0.166595458984375 +37426 -0.136383056640625 +37427 -0.19390869140625 +37428 -0.144378662109375 +37429 -0.22442626953125 +37430 -0.15753173828125 +37431 -0.279754638671875 +37432 -0.1689453125 +37433 -0.3389892578125 +37434 -0.162506103515625 +37435 -0.3543701171875 +37436 -0.146728515625 +37437 -0.348175048828125 +37438 -0.124359130859375 +37439 -0.32598876953125 +37440 -0.085845947265625 +37441 -0.2581787109375 +37442 -0.030303955078125 +37443 -0.139801025390625 +37444 0.03643798828125 +37445 0.014617919921875 +37446 0.09246826171875 +37447 0.144378662109375 +37448 0.1273193359375 +37449 0.221038818359375 +37450 0.149749755859375 +37451 0.27069091796875 +37452 0.159820556640625 +37453 0.294036865234375 +37454 0.164764404296875 +37455 0.311767578125 +37456 0.170013427734375 +37457 0.339141845703125 +37458 0.1700439453125 +37459 0.360260009765625 +37460 0.16033935546875 +37461 0.360504150390625 +37462 0.131256103515625 +37463 0.308380126953125 +37464 0.076263427734375 +37465 0.18170166015625 +37466 0.00421142578125 +37467 0.0047607421875 +37468 -0.068695068359375 +37469 -0.17559814453125 +37470 -0.126922607421875 +37471 -0.3143310546875 +37472 -0.155487060546875 +37473 -0.36785888671875 +37474 -0.1624755859375 +37475 -0.36248779296875 +37476 -0.162322998046875 +37477 -0.343536376953125 +37478 -0.15179443359375 +37479 -0.3018798828125 +37480 -0.1287841796875 +37481 -0.231414794921875 +37482 -0.088653564453125 +37483 -0.117645263671875 +37484 -0.042266845703125 +37485 0.007049560546875 +37486 -0.0079345703125 +37487 0.087982177734375 +37488 0.018524169921875 +37489 0.13946533203125 +37490 0.04071044921875 +37491 0.17425537109375 +37492 0.056671142578125 +37493 0.188201904296875 +37494 0.06243896484375 +37495 0.171234130859375 +37496 0.0557861328125 +37497 0.118438720703125 +37498 0.045135498046875 +37499 0.05706787109375 +37500 0.030670166015625 +37501 -0.010711669921875 +37502 0.0098876953125 +37503 -0.0914306640625 +37504 -0.010009765625 +37505 -0.162322998046875 +37506 -0.019683837890625 +37507 -0.194549560546875 +37508 -0.00634765625 +37509 -0.1492919921875 +37510 0.031707763671875 +37511 -0.02166748046875 +37512 0.07366943359375 +37513 0.124053955078125 +37514 0.094757080078125 +37515 0.211151123046875 +37516 0.095703125 +37517 0.240447998046875 +37518 0.0869140625 +37519 0.242218017578125 +37520 0.072021484375 +37521 0.2257080078125 +37522 0.052642822265625 +37523 0.194366455078125 +37524 0.0185546875 +37525 0.115509033203125 +37526 -0.02203369140625 +37527 0.0128173828125 +37528 -0.04913330078125 +37529 -0.053802490234375 +37530 -0.07110595703125 +37531 -0.110626220703125 +37532 -0.101593017578125 +37533 -0.199493408203125 +37534 -0.13201904296875 +37535 -0.29437255859375 +37536 -0.14178466796875 +37537 -0.33221435546875 +37538 -0.120208740234375 +37539 -0.27972412109375 +37540 -0.08343505859375 +37541 -0.185333251953125 +37542 -0.05780029296875 +37543 -0.128204345703125 +37544 -0.046112060546875 +37545 -0.115692138671875 +37546 -0.038543701171875 +37547 -0.116455078125 +37548 -0.0274658203125 +37549 -0.105926513671875 +37550 -0.003387451171875 +37551 -0.053955078125 +37552 0.036346435546875 +37553 0.048797607421875 +37554 0.076690673828125 +37555 0.157318115234375 +37556 0.097869873046875 +37557 0.212005615234375 +37558 0.101593017578125 +37559 0.218475341796875 +37560 0.107696533203125 +37561 0.23724365234375 +37562 0.12835693359375 +37563 0.30535888671875 +37564 0.15008544921875 +37565 0.38128662109375 +37566 0.1531982421875 +37567 0.404449462890625 +37568 0.144439697265625 +37569 0.3944091796875 +37570 0.1363525390625 +37571 0.3885498046875 +37572 0.12139892578125 +37573 0.362640380859375 +37574 0.0858154296875 +37575 0.27362060546875 +37576 0.02850341796875 +37577 0.11712646484375 +37578 -0.033172607421875 +37579 -0.054901123046875 +37580 -0.082000732421875 +37581 -0.19085693359375 +37582 -0.11614990234375 +37583 -0.28570556640625 +37584 -0.13543701171875 +37585 -0.339263916015625 +37586 -0.148345947265625 +37587 -0.3775634765625 +37588 -0.169677734375 +37589 -0.445709228515625 +37590 -0.196685791015625 +37591 -0.535064697265625 +37592 -0.224090576171875 +37593 -0.629058837890625 +37594 -0.24224853515625 +37595 -0.697601318359375 +37596 -0.239349365234375 +37597 -0.70391845703125 +37598 -0.2138671875 +37599 -0.6424560546875 +37600 -0.158905029296875 +37601 -0.491241455078125 +37602 -0.079803466796875 +37603 -0.265716552734375 +37604 0.004119873046875 +37605 -0.023712158203125 +37606 0.081817626953125 +37607 0.201751708984375 +37608 0.141693115234375 +37609 0.375823974609375 +37610 0.179229736328125 +37611 0.485076904296875 +37612 0.207244873046875 +37613 0.56884765625 +37614 0.228271484375 +37615 0.634765625 +37616 0.227569580078125 +37617 0.63763427734375 +37618 0.201507568359375 +37619 0.5660400390625 +37620 0.16729736328125 +37621 0.4720458984375 +37622 0.1419677734375 +37623 0.40692138671875 +37624 0.12811279296875 +37625 0.3778076171875 +37626 0.1234130859375 +37627 0.376953125 +37628 0.11749267578125 +37629 0.371978759765625 +37630 0.09423828125 +37631 0.313140869140625 +37632 0.048828125 +37633 0.184417724609375 +37634 -0.009918212890625 +37635 0.011199951171875 +37636 -0.07049560546875 +37637 -0.171051025390625 +37638 -0.1251220703125 +37639 -0.33740234375 +37640 -0.168792724609375 +37641 -0.47198486328125 +37642 -0.19708251953125 +37643 -0.560394287109375 +37644 -0.203369140625 +37645 -0.58056640625 +37646 -0.192138671875 +37647 -0.54754638671875 +37648 -0.177490234375 +37649 -0.508575439453125 +37650 -0.158416748046875 +37651 -0.459503173828125 +37652 -0.133453369140625 +37653 -0.394378662109375 +37654 -0.114593505859375 +37655 -0.35260009765625 +37656 -0.0955810546875 +37657 -0.31170654296875 +37658 -0.0548095703125 +37659 -0.197418212890625 +37660 0.007843017578125 +37661 -0.007965087890625 +37662 0.077423095703125 +37663 0.207489013671875 +37664 0.141876220703125 +37665 0.409210205078125 +37666 0.193572998046875 +37667 0.57208251953125 +37668 0.223419189453125 +37669 0.66595458984375 +37670 0.22186279296875 +37671 0.65875244140625 +37672 0.193939208984375 +37673 0.56744384765625 +37674 0.1513671875 +37675 0.431396484375 +37676 0.1072998046875 +37677 0.29443359375 +37678 0.069610595703125 +37679 0.182464599609375 +37680 0.0291748046875 +37681 0.06365966796875 +37682 -0.017791748046875 +37683 -0.075958251953125 +37684 -0.057098388671875 +37685 -0.189422607421875 +37686 -0.087005615234375 +37687 -0.271942138671875 +37688 -0.112823486328125 +37689 -0.342529296875 +37690 -0.123382568359375 +37691 -0.364166259765625 +37692 -0.115631103515625 +37693 -0.327239990234375 +37694 -0.102813720703125 +37695 -0.2769775390625 +37696 -0.096771240234375 +37697 -0.253692626953125 +37698 -0.09344482421875 +37699 -0.24365234375 +37700 -0.0784912109375 +37701 -0.1983642578125 +37702 -0.051605224609375 +37703 -0.116241455078125 +37704 -0.02459716796875 +37705 -0.036834716796875 +37706 0.00079345703125 +37707 0.034881591796875 +37708 0.02203369140625 +37709 0.09124755859375 +37710 0.031982421875 +37711 0.10888671875 +37712 0.04150390625 +37713 0.125518798828125 +37714 0.055267333984375 +37715 0.15771484375 +37716 0.06500244140625 +37717 0.17828369140625 +37718 0.06573486328125 +37719 0.17108154296875 +37720 0.0555419921875 +37721 0.129974365234375 +37722 0.042449951171875 +37723 0.082427978515625 +37724 0.026214599609375 +37725 0.027679443359375 +37726 -0.00238037109375 +37727 -0.065643310546875 +37728 -0.031951904296875 +37729 -0.15936279296875 +37730 -0.0504150390625 +37731 -0.21307373046875 +37732 -0.059967041015625 +37733 -0.234649658203125 +37734 -0.0533447265625 +37735 -0.2001953125 +37736 -0.03314208984375 +37737 -0.119171142578125 +37738 -0.00897216796875 +37739 -0.024749755859375 +37740 0.0201416015625 +37741 0.085784912109375 +37742 0.04425048828125 +37743 0.178131103515625 +37744 0.052642822265625 +37745 0.215576171875 +37746 0.049407958984375 +37747 0.211456298828125 +37748 0.0374755859375 +37749 0.17523193359375 +37750 0.023345947265625 +37751 0.128753662109375 +37752 0.015869140625 +37753 0.1019287109375 +37754 0.00897216796875 +37755 0.0743408203125 +37756 0.001739501953125 +37757 0.04327392578125 +37758 0.002716064453125 +37759 0.038177490234375 +37760 0.016876220703125 +37761 0.076263427734375 +37762 0.039154052734375 +37763 0.14105224609375 +37764 0.05572509765625 +37765 0.186431884765625 +37766 0.0594482421875 +37767 0.188812255859375 +37768 0.047454833984375 +37769 0.1390380859375 +37770 0.02099609375 +37771 0.041778564453125 +37772 -0.0130615234375 +37773 -0.079437255859375 +37774 -0.053253173828125 +37775 -0.219390869140625 +37776 -0.0965576171875 +37777 -0.367828369140625 +37778 -0.134185791015625 +37779 -0.494873046875 +37780 -0.15301513671875 +37781 -0.556243896484375 +37782 -0.14019775390625 +37783 -0.508697509765625 +37784 -0.102569580078125 +37785 -0.3756103515625 +37786 -0.058349609375 +37787 -0.218902587890625 +37788 -0.014862060546875 +37789 -0.063751220703125 +37790 0.028472900390625 +37791 0.091552734375 +37792 0.068603515625 +37793 0.23602294921875 +37794 0.097747802734375 +37795 0.342987060546875 +37796 0.1109619140625 +37797 0.39520263671875 +37798 0.107391357421875 +37799 0.389373779296875 +37800 0.08673095703125 +37801 0.324249267578125 +37802 0.0562744140625 +37803 0.224090576171875 +37804 0.0264892578125 +37805 0.124267578125 +37806 0.001007080078125 +37807 0.037078857421875 +37808 -0.0120849609375 +37809 -0.010101318359375 +37810 -0.01348876953125 +37811 -0.019439697265625 +37812 -0.012725830078125 +37813 -0.022796630859375 +37814 -0.004364013671875 +37815 -0.001556396484375 +37816 0.014984130859375 +37817 0.056304931640625 +37818 0.032135009765625 +37819 0.106719970703125 +37820 0.031341552734375 +37821 0.096893310546875 +37822 0.017242431640625 +37823 0.042694091796875 +37824 0.000885009765625 +37825 -0.018035888671875 +37826 -0.01495361328125 +37827 -0.07586669921875 +37828 -0.027008056640625 +37829 -0.11944580078125 +37830 -0.038543701171875 +37831 -0.15972900390625 +37832 -0.05133056640625 +37833 -0.202606201171875 +37834 -0.065460205078125 +37835 -0.24859619140625 +37836 -0.083099365234375 +37837 -0.30517578125 +37838 -0.1011962890625 +37839 -0.36212158203125 +37840 -0.11138916015625 +37841 -0.39141845703125 +37842 -0.102386474609375 +37843 -0.35528564453125 +37844 -0.072998046875 +37845 -0.249969482421875 +37846 -0.028289794921875 +37847 -0.092864990234375 +37848 0.02386474609375 +37849 0.08905029296875 +37850 0.06561279296875 +37851 0.2352294921875 +37852 0.089080810546875 +37853 0.318817138671875 +37854 0.099945068359375 +37855 0.358642578125 +37856 0.096160888671875 +37857 0.347747802734375 +37858 0.077606201171875 +37859 0.28564453125 +37860 0.059326171875 +37861 0.223175048828125 +37862 0.05206298828125 +37863 0.196746826171875 +37864 0.047943115234375 +37865 0.179840087890625 +37866 0.041900634765625 +37867 0.155548095703125 +37868 0.041961669921875 +37869 0.151214599609375 +37870 0.045135498046875 +37871 0.156951904296875 +37872 0.0391845703125 +37873 0.13177490234375 +37874 0.031463623046875 +37875 0.100799560546875 +37876 0.028717041015625 +37877 0.087127685546875 +37878 0.020263671875 +37879 0.05487060546875 +37880 0.002197265625 +37881 -0.009002685546875 +37882 -0.025360107421875 +37883 -0.10400390625 +37884 -0.06219482421875 +37885 -0.229400634765625 +37886 -0.099517822265625 +37887 -0.35552978515625 +37888 -0.12518310546875 +37889 -0.441925048828125 +37890 -0.13446044921875 +37891 -0.473846435546875 +37892 -0.1312255859375 +37893 -0.464813232421875 +37894 -0.117156982421875 +37895 -0.419097900390625 +37896 -0.092132568359375 +37897 -0.334320068359375 +37898 -0.061126708984375 +37899 -0.227935791015625 +37900 -0.030731201171875 +37901 -0.12347412109375 +37902 -0.0029296875 +37903 -0.02764892578125 +37904 0.02685546875 +37905 0.077667236328125 +37906 0.06396484375 +37907 0.2132568359375 +37908 0.110931396484375 +37909 0.38885498046875 +37910 0.16204833984375 +37911 0.582794189453125 +37912 0.201263427734375 +37913 0.734039306640625 +37914 0.21746826171875 +37915 0.800140380859375 +37916 0.210052490234375 +37917 0.7783203125 +37918 0.17822265625 +37919 0.6651611328125 +37920 0.12188720703125 +37921 0.45965576171875 +37922 0.051055908203125 +37923 0.199188232421875 +37924 -0.016815185546875 +37925 -0.050689697265625 +37926 -0.066558837890625 +37927 -0.23297119140625 +37928 -0.093475341796875 +37929 -0.33013916015625 +37930 -0.10443115234375 +37931 -0.368408203125 +37932 -0.10760498046875 +37933 -0.378936767578125 +37934 -0.1070556640625 +37935 -0.376983642578125 +37936 -0.1072998046875 +37937 -0.37969970703125 +37938 -0.10955810546875 +37939 -0.391510009765625 +37940 -0.106719970703125 +37941 -0.385345458984375 +37942 -0.093780517578125 +37943 -0.3419189453125 +37944 -0.0765380859375 +37945 -0.28289794921875 +37946 -0.0665283203125 +37947 -0.251617431640625 +37948 -0.068634033203125 +37949 -0.266143798828125 +37950 -0.068939208984375 +37951 -0.273345947265625 +37952 -0.0526123046875 +37953 -0.216796875 +37954 -0.028106689453125 +37955 -0.128265380859375 +37956 -0.01141357421875 +37957 -0.068145751953125 +37958 -0.00433349609375 +37959 -0.0430908203125 +37960 0.000640869140625 +37961 -0.024444580078125 +37962 0.012237548828125 +37963 0.020721435546875 +37964 0.0389404296875 +37965 0.124481201171875 +37966 0.073150634765625 +37967 0.25787353515625 +37968 0.103912353515625 +37969 0.379119873046875 +37970 0.129119873046875 +37971 0.47991943359375 +37972 0.140380859375 +37973 0.5281982421875 +37974 0.134368896484375 +37975 0.511138916015625 +37976 0.118438720703125 +37977 0.456207275390625 +37978 0.10430908203125 +37979 0.407470703125 +37980 0.097015380859375 +37981 0.383758544921875 +37982 0.089111328125 +37983 0.35687255859375 +37984 0.076690673828125 +37985 0.31182861328125 +37986 0.060394287109375 +37987 0.250885009765625 +37988 0.037933349609375 +37989 0.1654052734375 +37990 0.003997802734375 +37991 0.035247802734375 +37992 -0.042083740234375 +37993 -0.142059326171875 +37994 -0.092193603515625 +37995 -0.33563232421875 +37996 -0.143524169921875 +37997 -0.5345458984375 +37998 -0.191680908203125 +37999 -0.72186279296875 +38000 -0.220611572265625 +38001 -0.836669921875 +38002 -0.218170166015625 +38003 -0.8326416015625 +38004 -0.189697265625 +38005 -0.7296142578125 +38006 -0.149810791015625 +38007 -0.582550048828125 +38008 -0.11138916015625 +38009 -0.440093994140625 +38010 -0.080291748046875 +38011 -0.324310302734375 +38012 -0.047607421875 +38013 -0.20147705078125 +38014 -0.006195068359375 +38015 -0.044647216796875 +38016 0.03277587890625 +38017 0.103973388671875 +38018 0.0582275390625 +38019 0.202392578125 +38020 0.0738525390625 +38021 0.264495849609375 +38022 0.092498779296875 +38023 0.338897705078125 +38024 0.11907958984375 +38025 0.443817138671875 +38026 0.14459228515625 +38027 0.545074462890625 +38028 0.162445068359375 +38029 0.6173095703125 +38030 0.170562744140625 +38031 0.6524658203125 +38032 0.17242431640625 +38033 0.66339111328125 +38034 0.169677734375 +38035 0.6561279296875 +38036 0.156005859375 +38037 0.606781005859375 +38038 0.127685546875 +38039 0.501190185546875 +38040 0.08831787109375 +38041 0.352783203125 +38042 0.0418701171875 +38043 0.176544189453125 +38044 -0.0135498046875 +38045 -0.034820556640625 +38046 -0.071868896484375 +38047 -0.258209228515625 +38048 -0.11962890625 +38049 -0.44244384765625 +38050 -0.1536865234375 +38051 -0.5753173828125 +38052 -0.1728515625 +38053 -0.65203857421875 +38054 -0.16900634765625 +38055 -0.641632080078125 +38056 -0.14697265625 +38057 -0.562164306640625 +38058 -0.118499755859375 +38059 -0.458038330078125 +38060 -0.08929443359375 +38061 -0.350555419921875 +38062 -0.06488037109375 +38063 -0.260528564453125 +38064 -0.04638671875 +38065 -0.192108154296875 +38066 -0.032928466796875 +38067 -0.141937255859375 +38068 -0.0224609375 +38069 -0.1021728515625 +38070 -0.012359619140625 +38071 -0.062896728515625 +38072 0.0006103515625 +38073 -0.011932373046875 +38074 0.019683837890625 +38075 0.062835693359375 +38076 0.04156494140625 +38077 0.148712158203125 +38078 0.06524658203125 +38079 0.241729736328125 +38080 0.092681884765625 +38081 0.34912109375 +38082 0.120330810546875 +38083 0.457305908203125 +38084 0.142303466796875 +38085 0.54388427734375 +38086 0.149169921875 +38087 0.5728759765625 +38088 0.131011962890625 +38089 0.506591796875 +38090 0.089508056640625 +38091 0.351226806640625 +38092 0.035186767578125 +38093 0.146514892578125 +38094 -0.01812744140625 +38095 -0.05523681640625 +38096 -0.060455322265625 +38097 -0.21624755859375 +38098 -0.0914306640625 +38099 -0.334930419921875 +38100 -0.108856201171875 +38101 -0.402984619140625 +38102 -0.1182861328125 +38103 -0.4412841796875 +38104 -0.13189697265625 +38105 -0.49578857421875 +38106 -0.148040771484375 +38107 -0.5601806640625 +38108 -0.157867431640625 +38109 -0.600738525390625 +38110 -0.152679443359375 +38111 -0.584228515625 +38112 -0.124237060546875 +38113 -0.47930908203125 +38114 -0.070831298828125 +38115 -0.27935791015625 +38116 0.0009765625 +38117 -0.0089111328125 +38118 0.074493408203125 +38119 0.268798828125 +38120 0.1309814453125 +38121 0.482818603515625 +38122 0.162689208984375 +38123 0.60369873046875 +38124 0.17462158203125 +38125 0.650421142578125 +38126 0.17767333984375 +38127 0.66400146484375 +38128 0.17108154296875 +38129 0.6414794921875 +38130 0.15216064453125 +38131 0.572540283203125 +38132 0.13177490234375 +38133 0.498138427734375 +38134 0.115570068359375 +38135 0.439453125 +38136 0.098052978515625 +38137 0.375518798828125 +38138 0.070831298828125 +38139 0.274505615234375 +38140 0.026611328125 +38141 0.1087646484375 +38142 -0.0286865234375 +38143 -0.099395751953125 +38144 -0.08612060546875 +38145 -0.3182373046875 +38146 -0.14520263671875 +38147 -0.5489501953125 +38148 -0.201446533203125 +38149 -0.7738037109375 +38150 -0.242431640625 +38151 -0.86383056640625 +38152 -0.2603759765625 +38153 -0.870391845703125 +38154 -0.25946044921875 +38155 -0.86895751953125 +38156 -0.24285888671875 +38157 -0.861053466796875 +38158 -0.206756591796875 +38159 -0.765869140625 +38160 -0.1488037109375 +38161 -0.5301513671875 +38162 -0.070953369140625 +38163 -0.214691162109375 +38164 0.01641845703125 +38165 0.137359619140625 +38166 0.101104736328125 +38167 0.474822998046875 +38168 0.174530029296875 +38169 0.76239013671875 +38170 0.230133056640625 +38171 0.867462158203125 +38172 0.26776123046875 +38173 0.870361328125 +38174 0.284515380859375 +38175 0.86480712890625 +38176 0.28155517578125 +38177 0.831817626953125 +38178 0.26446533203125 +38179 0.677581787109375 +38180 0.234619140625 +38181 0.495880126953125 +38182 0.196380615234375 +38183 0.30767822265625 +38184 0.150390625 +38185 0.116180419921875 +38186 0.0894775390625 +38187 -0.110748291015625 +38188 0.01226806640625 +38189 -0.381805419921875 +38190 -0.071014404296875 +38191 -0.6572265625 +38192 -0.14617919921875 +38193 -0.857421875 +38194 -0.203033447265625 +38195 -0.870391845703125 +38196 -0.23968505859375 +38197 -0.870391845703125 +38198 -0.26214599609375 +38199 -0.86444091796875 +38200 -0.278564453125 +38201 -0.85723876953125 +38202 -0.284576416015625 +38203 -0.790008544921875 +38204 -0.267547607421875 +38205 -0.62847900390625 +38206 -0.226715087890625 +38207 -0.3956298828125 +38208 -0.169769287109375 +38209 -0.126708984375 +38210 -0.1031494140625 +38211 0.150115966796875 +38212 -0.02972412109375 +38213 0.424041748046875 +38214 0.0440673828125 +38215 0.670623779296875 +38216 0.1090087890625 +38217 0.854522705078125 +38218 0.160797119140625 +38219 0.866485595703125 +38220 0.195648193359375 +38221 0.86920166015625 +38222 0.21759033203125 +38223 0.8653564453125 +38224 0.22955322265625 +38225 0.857147216796875 +38226 0.230712890625 +38227 0.766845703125 +38228 0.222137451171875 +38229 0.628509521484375 +38230 0.20220947265625 +38231 0.462127685546875 +38232 0.176910400390625 +38233 0.297210693359375 +38234 0.14910888671875 +38235 0.14862060546875 +38236 0.11358642578125 +38237 -0.00537109375 +38238 0.07220458984375 +38239 -0.15753173828125 +38240 0.024322509765625 +38241 -0.31304931640625 +38242 -0.03314208984375 +38243 -0.48876953125 +38244 -0.08917236328125 +38245 -0.6416015625 +38246 -0.137847900390625 +38247 -0.751373291015625 +38248 -0.184356689453125 +38249 -0.84619140625 +38250 -0.22515869140625 +38251 -0.861297607421875 +38252 -0.252410888671875 +38253 -0.863250732421875 +38254 -0.2586669921875 +38255 -0.856597900390625 +38256 -0.2467041015625 +38257 -0.7498779296875 +38258 -0.22991943359375 +38259 -0.624542236328125 +38260 -0.203216552734375 +38261 -0.47808837890625 +38262 -0.153106689453125 +38263 -0.253387451171875 +38264 -0.090240478515625 +38265 0.003692626953125 +38266 -0.030609130859375 +38267 0.2257080078125 +38268 0.028533935546875 +38269 0.427154541015625 +38270 0.09454345703125 +38271 0.643218994140625 +38272 0.1650390625 +38273 0.855926513671875 +38274 0.226409912109375 +38275 0.870361328125 +38276 0.26702880859375 +38277 0.870361328125 +38278 0.288421630859375 +38279 0.862762451171875 +38280 0.28985595703125 +38281 0.79669189453125 +38282 0.269073486328125 +38283 0.595794677734375 +38284 0.232818603515625 +38285 0.362152099609375 +38286 0.1876220703125 +38287 0.1270751953125 +38288 0.138427734375 +38289 -0.086944580078125 +38290 0.085784912109375 +38291 -0.2784423828125 +38292 0.021728515625 +38293 -0.484832763671875 +38294 -0.05804443359375 +38295 -0.729583740234375 +38296 -0.14166259765625 +38297 -0.86688232421875 +38298 -0.214324951171875 +38299 -0.870391845703125 +38300 -0.27471923828125 +38301 -0.86859130859375 +38302 -0.322235107421875 +38303 -0.86279296875 +38304 -0.34844970703125 +38305 -0.817962646484375 +38306 -0.34271240234375 +38307 -0.6116943359375 +38308 -0.3033447265625 +38309 -0.3128662109375 +38310 -0.23809814453125 +38311 0.039398193359375 +38312 -0.151641845703125 +38313 0.422821044921875 +38314 -0.0517578125 +38315 0.805145263671875 +38316 0.045684814453125 +38317 0.870361328125 +38318 0.127349853515625 +38319 0.870361328125 +38320 0.190399169921875 +38321 0.860015869140625 +38322 0.232879638671875 +38323 0.727935791015625 +38324 0.25335693359375 +38325 0.48114013671875 +38326 0.257293701171875 +38327 0.2059326171875 +38328 0.249755859375 +38329 -0.06103515625 +38330 0.23297119140625 +38331 -0.29913330078125 +38332 0.203460693359375 +38333 -0.516204833984375 +38334 0.157623291015625 +38335 -0.7252197265625 +38336 0.101226806640625 +38337 -0.85980224609375 +38338 0.042236328125 +38339 -0.870391845703125 +38340 -0.01239013671875 +38341 -0.870391845703125 +38342 -0.051177978515625 +38343 -0.858062744140625 +38344 -0.072998046875 +38345 -0.673004150390625 +38346 -0.089874267578125 +38347 -0.42694091796875 +38348 -0.111907958984375 +38349 -0.2100830078125 +38350 -0.138397216796875 +38351 -0.0362548828125 +38352 -0.162384033203125 +38353 0.10943603515625 +38354 -0.179046630859375 +38355 0.23516845703125 +38356 -0.17864990234375 +38357 0.373687744140625 +38358 -0.16156005859375 +38359 0.517791748046875 +38360 -0.142333984375 +38361 0.602783203125 +38362 -0.1197509765625 +38363 0.635711669921875 +38364 -0.08612060546875 +38365 0.655181884765625 +38366 -0.0438232421875 +38367 0.65948486328125 +38368 0.00506591796875 +38369 0.651275634765625 +38370 0.05474853515625 +38371 0.61846923828125 +38372 0.096435546875 +38373 0.53753662109375 +38374 0.125732421875 +38375 0.404144287109375 +38376 0.140228271484375 +38377 0.22186279296875 +38378 0.1400146484375 +38379 0.003997802734375 +38380 0.129119873046875 +38381 -0.22100830078125 +38382 0.112213134765625 +38383 -0.42449951171875 +38384 0.0941162109375 +38385 -0.579833984375 +38386 0.084686279296875 +38387 -0.641876220703125 +38388 0.082366943359375 +38389 -0.6177978515625 +38390 0.072174072265625 +38391 -0.575531005859375 +38392 0.052947998046875 +38393 -0.526336669921875 +38394 0.036773681640625 +38395 -0.42645263671875 +38396 0.0301513671875 +38397 -0.2581787109375 +38398 0.02484130859375 +38399 -0.068695068359375 +38400 0.0115966796875 +38401 0.09222412109375 +38402 -0.005615234375 +38403 0.232147216796875 +38404 -0.023712158203125 +38405 0.3509521484375 +38406 -0.047882080078125 +38407 0.410064697265625 +38408 -0.083404541015625 +38409 0.372955322265625 +38410 -0.125640869140625 +38411 0.2554931640625 +38412 -0.163818359375 +38413 0.10711669921875 +38414 -0.193817138671875 +38415 -0.052886962890625 +38416 -0.208343505859375 +38417 -0.186279296875 +38418 -0.19635009765625 +38419 -0.23291015625 +38420 -0.16259765625 +38421 -0.209442138671875 +38422 -0.120574951171875 +38423 -0.174163818359375 +38424 -0.07232666015625 +38425 -0.126739501953125 +38426 -0.016265869140625 +38427 -0.048126220703125 +38428 0.041473388671875 +38429 0.0426025390625 +38430 0.091156005859375 +38431 0.10748291015625 +38432 0.129730224609375 +38433 0.1409912109375 +38434 0.166351318359375 +38435 0.19708251953125 +38436 0.19940185546875 +38437 0.273651123046875 +38438 0.217559814453125 +38439 0.31768798828125 +38440 0.222930908203125 +38441 0.341094970703125 +38442 0.220550537109375 +38443 0.368011474609375 +38444 0.205902099609375 +38445 0.37249755859375 +38446 0.1693115234375 +38447 0.30072021484375 +38448 0.111968994140625 +38449 0.1517333984375 +38450 0.0474853515625 +38451 -0.01470947265625 +38452 -0.020263671875 +38453 -0.1883544921875 +38454 -0.090118408203125 +38455 -0.372711181640625 +38456 -0.149566650390625 +38457 -0.51397705078125 +38458 -0.188873291015625 +38459 -0.57177734375 +38460 -0.20526123046875 +38461 -0.53948974609375 +38462 -0.20123291015625 +38463 -0.43511962890625 +38464 -0.183563232421875 +38465 -0.2962646484375 +38466 -0.1595458984375 +38467 -0.161102294921875 +38468 -0.131988525390625 +38469 -0.0435791015625 +38470 -0.10052490234375 +38471 0.060394287109375 +38472 -0.0687255859375 +38473 0.13665771484375 +38474 -0.040679931640625 +38475 0.170135498046875 +38476 -0.01678466796875 +38477 0.16552734375 +38478 0.00836181640625 +38479 0.15728759765625 +38480 0.034332275390625 +38481 0.150787353515625 +38482 0.054840087890625 +38483 0.12200927734375 +38484 0.0703125 +38485 0.080108642578125 +38486 0.084747314453125 +38487 0.05126953125 +38488 0.102630615234375 +38489 0.062896728515625 +38490 0.118804931640625 +38491 0.09271240234375 +38492 0.123321533203125 +38493 0.092987060546875 +38494 0.119049072265625 +38495 0.07855224609375 +38496 0.109222412109375 +38497 0.06427001953125 +38498 0.09130859375 +38499 0.0347900390625 +38500 0.06573486328125 +38501 -0.01171875 +38502 0.037353515625 +38503 -0.056060791015625 +38504 0.015869140625 +38505 -0.055511474609375 +38506 0.00244140625 +38507 -0.010467529296875 +38508 -0.012451171875 +38509 0.02508544921875 +38510 -0.032745361328125 +38511 0.025665283203125 +38512 -0.052154541015625 +38513 0.017333984375 +38514 -0.06939697265625 +38515 0.00189208984375 +38516 -0.086029052734375 +38517 -0.03173828125 +38518 -0.0992431640625 +38519 -0.071502685546875 +38520 -0.11248779296875 +38521 -0.13543701171875 +38522 -0.125152587890625 +38523 -0.219970703125 +38524 -0.1326904296875 +38525 -0.300506591796875 +38526 -0.135528564453125 +38527 -0.376312255859375 +38528 -0.128204345703125 +38529 -0.416107177734375 +38530 -0.10186767578125 +38531 -0.371124267578125 +38532 -0.0577392578125 +38533 -0.242279052734375 +38534 -0.0048828125 +38535 -0.069732666015625 +38536 0.051483154296875 +38537 0.125640869140625 +38538 0.104248046875 +38539 0.31268310546875 +38540 0.14532470703125 +38541 0.45501708984375 +38542 0.174530029296875 +38543 0.554779052734375 +38544 0.19122314453125 +38545 0.61065673828125 +38546 0.19287109375 +38547 0.610931396484375 +38548 0.1746826171875 +38549 0.531463623046875 +38550 0.140106201171875 +38551 0.3883056640625 +38552 0.1002197265625 +38553 0.23468017578125 +38554 0.060546875 +38555 0.095245361328125 +38556 0.027008056640625 +38557 -0.00396728515625 +38558 0.003265380859375 +38559 -0.04852294921875 +38560 -0.013153076171875 +38561 -0.055145263671875 +38562 -0.031829833984375 +38563 -0.0758056640625 +38564 -0.0576171875 +38565 -0.138702392578125 +38566 -0.0828857421875 +38567 -0.209197998046875 +38568 -0.107452392578125 +38569 -0.289031982421875 +38570 -0.13104248046875 +38571 -0.37884521484375 +38572 -0.148956298828125 +38573 -0.456329345703125 +38574 -0.16015625 +38575 -0.51641845703125 +38576 -0.156829833984375 +38577 -0.519287109375 +38578 -0.137939453125 +38579 -0.458251953125 +38580 -0.11419677734375 +38581 -0.384796142578125 +38582 -0.09112548828125 +38583 -0.323699951171875 +38584 -0.0682373046875 +38585 -0.269287109375 +38586 -0.040924072265625 +38587 -0.1951904296875 +38588 -0.009613037109375 +38589 -0.100006103515625 +38590 0.019622802734375 +38591 -0.01055908203125 +38592 0.052215576171875 +38593 0.1033935546875 +38594 0.089141845703125 +38595 0.24908447265625 +38596 0.119384765625 +38597 0.373199462890625 +38598 0.13916015625 +38599 0.45806884765625 +38600 0.14996337890625 +38601 0.511474609375 +38602 0.15826416015625 +38603 0.565399169921875 +38604 0.162567138671875 +38605 0.61138916015625 +38606 0.151275634765625 +38607 0.5897216796875 +38608 0.12286376953125 +38609 0.4906005859375 +38610 0.08135986328125 +38611 0.33148193359375 +38612 0.034423828125 +38613 0.147796630859375 +38614 -0.009033203125 +38615 -0.01873779296875 +38616 -0.042877197265625 +38617 -0.140289306640625 +38618 -0.0616455078125 +38619 -0.191986083984375 +38620 -0.0670166015625 +38621 -0.184295654296875 +38622 -0.06756591796875 +38623 -0.161834716796875 +38624 -0.07147216796875 +38625 -0.166595458984375 +38626 -0.07769775390625 +38627 -0.19390869140625 +38628 -0.0823974609375 +38629 -0.22442626953125 +38630 -0.09002685546875 +38631 -0.279754638671875 +38632 -0.096649169921875 +38633 -0.3389892578125 +38634 -0.09307861328125 +38635 -0.3543701171875 +38636 -0.084136962890625 +38637 -0.348175048828125 +38638 -0.0714111328125 +38639 -0.32598876953125 +38640 -0.049468994140625 +38641 -0.2581787109375 +38642 -0.01776123046875 +38643 -0.139801025390625 +38644 0.0203857421875 +38645 0.014617919921875 +38646 0.052398681640625 +38647 0.144378662109375 +38648 0.07232666015625 +38649 0.221038818359375 +38650 0.085174560546875 +38651 0.27069091796875 +38652 0.09100341796875 +38653 0.294036865234375 +38654 0.09393310546875 +38655 0.311767578125 +38656 0.09698486328125 +38657 0.339141845703125 +38658 0.096771240234375 +38659 0.360260009765625 +38660 0.09075927734375 +38661 0.360504150390625 +38662 0.074188232421875 +38663 0.308380126953125 +38664 0.043914794921875 +38665 0.18170166015625 +38666 0.004608154296875 +38667 0.0047607421875 +38668 -0.035186767578125 +38669 -0.17559814453125 +38670 -0.0673828125 +38671 -0.3143310546875 +38672 -0.084136962890625 +38673 -0.36785888671875 +38674 -0.0894775390625 +38675 -0.36248779296875 +38676 -0.090728759765625 +38677 -0.343536376953125 +38678 -0.086181640625 +38679 -0.3018798828125 +38680 -0.074737548828125 +38681 -0.231414794921875 +38682 -0.053985595703125 +38683 -0.117645263671875 +38684 -0.029541015625 +38685 0.007049560546875 +38686 -0.010833740234375 +38687 0.087982177734375 +38688 0.004180908203125 +38689 0.13946533203125 +38690 0.01727294921875 +38691 0.17425537109375 +38692 0.027313232421875 +38693 0.188201904296875 +38694 0.03216552734375 +38695 0.171234130859375 +38696 0.03057861328125 +38697 0.118438720703125 +38698 0.02679443359375 +38699 0.05706787109375 +38700 0.02081298828125 +38701 -0.010711669921875 +38702 0.011260986328125 +38703 -0.0914306640625 +38704 0.001800537109375 +38705 -0.162322998046875 +38706 -0.0028076171875 +38707 -0.194549560546875 +38708 0.003936767578125 +38709 -0.1492919921875 +38710 0.02294921875 +38711 -0.02166748046875 +38712 0.04364013671875 +38713 0.124053955078125 +38714 0.053314208984375 +38715 0.211151123046875 +38716 0.05242919921875 +38717 0.240447998046875 +38718 0.046417236328125 +38719 0.242218017578125 +38720 0.0372314453125 +38721 0.2257080078125 +38722 0.025787353515625 +38723 0.194366455078125 +38724 0.006927490234375 +38725 0.115509033203125 +38726 -0.015045166015625 +38727 0.0128173828125 +38728 -0.02984619140625 +38729 -0.053802490234375 +38730 -0.041748046875 +38731 -0.110626220703125 +38732 -0.05767822265625 +38733 -0.199493408203125 +38734 -0.0732421875 +38735 -0.29437255859375 +38736 -0.077911376953125 +38737 -0.33221435546875 +38738 -0.066253662109375 +38739 -0.27972412109375 +38740 -0.04656982421875 +38741 -0.185333251953125 +38742 -0.032379150390625 +38743 -0.128204345703125 +38744 -0.02520751953125 +38745 -0.115692138671875 +38746 -0.02008056640625 +38747 -0.116455078125 +38748 -0.013153076171875 +38749 -0.105926513671875 +38750 0.00030517578125 +38751 -0.053955078125 +38752 0.021636962890625 +38753 0.048797607421875 +38754 0.0430908203125 +38755 0.157318115234375 +38756 0.05450439453125 +38757 0.212005615234375 +38758 0.05670166015625 +38759 0.218475341796875 +38760 0.059844970703125 +38761 0.23724365234375 +38762 0.0701904296875 +38763 0.30535888671875 +38764 0.08087158203125 +38765 0.38128662109375 +38766 0.081787109375 +38767 0.404449462890625 +38768 0.076446533203125 +38769 0.3944091796875 +38770 0.07135009765625 +38771 0.3885498046875 +38772 0.062652587890625 +38773 0.362640380859375 +38774 0.043365478515625 +38775 0.27362060546875 +38776 0.01300048828125 +38777 0.11712646484375 +38778 -0.01947021484375 +38779 -0.054901123046875 +38780 -0.045166015625 +38781 -0.19085693359375 +38782 -0.0631103515625 +38783 -0.28570556640625 +38784 -0.073211669921875 +38785 -0.339263916015625 +38786 -0.079803466796875 +38787 -0.3775634765625 +38788 -0.090484619140625 +38789 -0.445709228515625 +38790 -0.1038818359375 +38791 -0.535064697265625 +38792 -0.1173095703125 +38793 -0.629058837890625 +38794 -0.1258544921875 +38795 -0.697601318359375 +38796 -0.123504638671875 +38797 -0.70391845703125 +38798 -0.109527587890625 +38799 -0.6424560546875 +38800 -0.0804443359375 +38801 -0.491241455078125 +38802 -0.039093017578125 +38803 -0.265716552734375 +38804 0.004608154296875 +38805 -0.023712158203125 +38806 0.044952392578125 +38807 0.201751708984375 +38808 0.07598876953125 +38809 0.375823974609375 +38810 0.095367431640625 +38811 0.485076904296875 +38812 0.10968017578125 +38813 0.56884765625 +38814 0.120208740234375 +38815 0.634765625 +38816 0.11944580078125 +38817 0.63763427734375 +38818 0.10552978515625 +38819 0.5660400390625 +38820 0.08734130859375 +38821 0.4720458984375 +38822 0.073638916015625 +38823 0.40692138671875 +38824 0.065765380859375 +38825 0.3778076171875 +38826 0.062591552734375 +38827 0.376953125 +38828 0.058868408203125 +38829 0.371978759765625 +38830 0.046356201171875 +38831 0.313140869140625 +38832 0.02252197265625 +38833 0.184417724609375 +38834 -0.00823974609375 +38835 0.011199951171875 +38836 -0.039886474609375 +38837 -0.171051025390625 +38838 -0.06817626953125 +38839 -0.33740234375 +38840 -0.0904541015625 +38841 -0.47198486328125 +38842 -0.104339599609375 +38843 -0.560394287109375 +38844 -0.106201171875 +38845 -0.58056640625 +38846 -0.09869384765625 +38847 -0.54754638671875 +38848 -0.089874267578125 +38849 -0.508575439453125 +38850 -0.07916259765625 +38851 -0.459503173828125 +38852 -0.065704345703125 +38853 -0.394378662109375 +38854 -0.056243896484375 +38855 -0.35260009765625 +38856 -0.047088623046875 +38857 -0.31170654296875 +38858 -0.02593994140625 +38859 -0.197418212890625 +38860 0.007415771484375 +38861 -0.007965087890625 +38862 0.044586181640625 +38863 0.207489013671875 +38864 0.078887939453125 +38865 0.409210205078125 +38866 0.1060791015625 +38867 0.57208251953125 +38868 0.121124267578125 +38869 0.66595458984375 +38870 0.118682861328125 +38871 0.65875244140625 +38872 0.101715087890625 +38873 0.56744384765625 +38874 0.076934814453125 +38875 0.431396484375 +38876 0.05181884765625 +38877 0.29443359375 +38878 0.03082275390625 +38879 0.182464599609375 +38880 0.008758544921875 +38881 0.06365966796875 +38882 -0.016632080078125 +38883 -0.075958251953125 +38884 -0.037322998046875 +38885 -0.189422607421875 +38886 -0.05242919921875 +38887 -0.271942138671875 +38888 -0.0650634765625 +38889 -0.342529296875 +38890 -0.06903076171875 +38891 -0.364166259765625 +38892 -0.062713623046875 +38893 -0.327239990234375 +38894 -0.0537109375 +38895 -0.2769775390625 +38896 -0.048828125 +38897 -0.253692626953125 +38898 -0.04583740234375 +38899 -0.24365234375 +38900 -0.03668212890625 +38901 -0.1983642578125 +38902 -0.02117919921875 +38903 -0.116241455078125 +38904 -0.006072998046875 +38905 -0.036834716796875 +38906 0.0076904296875 +38907 0.034881591796875 +38908 0.01873779296875 +38909 0.09124755859375 +38910 0.023040771484375 +38911 0.10888671875 +38912 0.0264892578125 +38913 0.125518798828125 +38914 0.031707763671875 +38915 0.15771484375 +38916 0.03460693359375 +38917 0.17828369140625 +38918 0.03314208984375 +38919 0.17108154296875 +38920 0.026580810546875 +38921 0.129974365234375 +38922 0.018798828125 +38923 0.082427978515625 +38924 0.009765625 +38925 0.027679443359375 +38926 -0.004608154296875 +38927 -0.065643310546875 +38928 -0.019073486328125 +38929 -0.15936279296875 +38930 -0.028045654296875 +38931 -0.21307373046875 +38932 -0.03253173828125 +38933 -0.234649658203125 +38934 -0.02923583984375 +38935 -0.2001953125 +38936 -0.0194091796875 +38937 -0.119171142578125 +38938 -0.00750732421875 +38939 -0.024749755859375 +38940 0.006866455078125 +38941 0.085784912109375 +38942 0.01904296875 +38943 0.178131103515625 +38944 0.0240478515625 +38945 0.215576171875 +38946 0.023681640625 +38947 0.211456298828125 +38948 0.019256591796875 +38949 0.17523193359375 +38950 0.013671875 +38951 0.128753662109375 +38952 0.010955810546875 +38953 0.1019287109375 +38954 0.008270263671875 +38955 0.0743408203125 +38956 0.00518798828125 +38957 0.04327392578125 +38958 0.005615234375 +38959 0.038177490234375 +38960 0.011871337890625 +38961 0.076263427734375 +38962 0.0216064453125 +38963 0.14105224609375 +38964 0.028533935546875 +38965 0.186431884765625 +38966 0.0294189453125 +38967 0.188812255859375 +38968 0.02301025390625 +38969 0.1390380859375 +38970 0.009918212890625 +38971 0.041778564453125 +38972 -0.006622314453125 +38973 -0.079437255859375 +38974 -0.025909423828125 +38975 -0.219390869140625 +38976 -0.046478271484375 +38977 -0.367828369140625 +38978 -0.06427001953125 +38979 -0.494873046875 +38980 -0.0732421875 +38981 -0.556243896484375 +38982 -0.0675048828125 +38983 -0.508697509765625 +38984 -0.0501708984375 +38985 -0.3756103515625 +38986 -0.0296630859375 +38987 -0.218902587890625 +38988 -0.009307861328125 +38989 -0.063751220703125 +38990 0.011077880859375 +38991 0.091552734375 +38992 0.030059814453125 +38993 0.23602294921875 +38994 0.0440673828125 +38995 0.342987060546875 +38996 0.05078125 +38997 0.39520263671875 +38998 0.04974365234375 +38999 0.389373779296875 +39000 0.04083251953125 +39001 0.324249267578125 +39002 0.027374267578125 +39003 0.224090576171875 +39004 0.01416015625 +39005 0.124267578125 +39006 0.0028076171875 +39007 0.037078857421875 +39008 -0.002960205078125 +39009 -0.010101318359375 +39010 -0.003509521484375 +39011 -0.019439697265625 +39012 -0.003204345703125 +39013 -0.022796630859375 +39014 0.00042724609375 +39015 -0.001556396484375 +39016 0.008941650390625 +39017 0.056304931640625 +39018 0.016326904296875 +39019 0.106719970703125 +39020 0.015411376953125 +39021 0.096893310546875 +39022 0.00830078125 +39023 0.042694091796875 +39024 0.00018310546875 +39025 -0.018035888671875 +39026 -0.007659912109375 +39027 -0.07586669921875 +39028 -0.013671875 +39029 -0.11944580078125 +39030 -0.01934814453125 +39031 -0.15972900390625 +39032 -0.025482177734375 +39033 -0.202606201171875 +39034 -0.0321044921875 +39035 -0.24859619140625 +39036 -0.040191650390625 +39037 -0.30517578125 +39038 -0.04833984375 +39039 -0.36212158203125 +39040 -0.052764892578125 +39041 -0.39141845703125 +39042 -0.04827880859375 +39043 -0.35528564453125 +39044 -0.034332275390625 +39045 -0.249969482421875 +39046 -0.0133056640625 +39047 -0.092864990234375 +39048 0.011138916015625 +39049 0.08905029296875 +39050 0.030792236328125 +39051 0.2352294921875 +39052 0.0419921875 +39053 0.318817138671875 +39054 0.047332763671875 +39055 0.358642578125 +39056 0.04583740234375 +39057 0.347747802734375 +39058 0.0374755859375 +39059 0.28564453125 +39060 0.02911376953125 +39061 0.223175048828125 +39062 0.025726318359375 +39063 0.196746826171875 +39064 0.023681640625 +39065 0.179840087890625 +39066 0.020660400390625 +39067 0.155548095703125 +39068 0.020355224609375 +39069 0.151214599609375 +39070 0.02142333984375 +39071 0.156951904296875 +39072 0.018280029296875 +39073 0.13177490234375 +39074 0.014312744140625 +39075 0.100799560546875 +39076 0.01263427734375 +39077 0.087127685546875 +39078 0.008392333984375 +39079 0.05487060546875 +39080 -0.000152587890625 +39081 -0.009002685546875 +39082 -0.012939453125 +39083 -0.10400390625 +39084 -0.0299072265625 +39085 -0.229400634765625 +39086 -0.047027587890625 +39087 -0.35552978515625 +39088 -0.05877685546875 +39089 -0.441925048828125 +39090 -0.063140869140625 +39091 -0.473846435546875 +39092 -0.061981201171875 +39093 -0.464813232421875 +39094 -0.055877685546875 +39095 -0.419097900390625 +39096 -0.04449462890625 +39097 -0.334320068359375 +39098 -0.03021240234375 +39099 -0.227935791015625 +39100 -0.016204833984375 +39101 -0.12347412109375 +39102 -0.003387451171875 +39103 -0.02764892578125 +39104 0.010711669921875 +39105 0.077667236328125 +39106 0.0289306640625 +39107 0.2132568359375 +39108 0.0526123046875 +39109 0.38885498046875 +39110 0.07879638671875 +39111 0.582794189453125 +39112 0.099212646484375 +39113 0.734039306640625 +39114 0.108062744140625 +39115 0.800140380859375 +39116 0.10498046875 +39117 0.7783203125 +39118 0.08953857421875 +39119 0.6651611328125 +39120 0.06158447265625 +39121 0.45965576171875 +39122 0.0262451171875 +39123 0.199188232421875 +39124 -0.007568359375 +39125 -0.050689697265625 +39126 -0.032135009765625 +39127 -0.23297119140625 +39128 -0.045074462890625 +39129 -0.33013916015625 +39130 -0.049957275390625 +39131 -0.368408203125 +39132 -0.051055908203125 +39133 -0.378936767578125 +39134 -0.050506591796875 +39135 -0.376983642578125 +39136 -0.050628662109375 +39137 -0.37969970703125 +39138 -0.052032470703125 +39139 -0.391510009765625 +39140 -0.051025390625 +39141 -0.385345458984375 +39142 -0.045013427734375 +39143 -0.3419189453125 +39144 -0.036956787109375 +39145 -0.28289794921875 +39146 -0.03271484375 +39147 -0.251617431640625 +39148 -0.034759521484375 +39149 -0.266143798828125 +39150 -0.035858154296875 +39151 -0.273345947265625 +39152 -0.0283203125 +39153 -0.216796875 +39154 -0.016448974609375 +39155 -0.128265380859375 +39156 -0.0084228515625 +39157 -0.068145751953125 +39158 -0.005157470703125 +39159 -0.0430908203125 +39160 -0.002777099609375 +39161 -0.024444580078125 +39162 0.003173828125 +39163 0.020721435546875 +39164 0.01708984375 +39165 0.124481201171875 +39166 0.035003662109375 +39167 0.25787353515625 +39168 0.050689697265625 +39169 0.379119873046875 +39170 0.063262939453125 +39171 0.47991943359375 +39172 0.0697021484375 +39173 0.5281982421875 +39174 0.06854248046875 +39175 0.511138916015625 +39176 0.062530517578125 +39177 0.456207275390625 +39178 0.056243896484375 +39179 0.407470703125 +39180 0.051727294921875 +39181 0.383758544921875 +39182 0.046142578125 +39183 0.35687255859375 +39184 0.038116455078125 +39185 0.31182861328125 +39186 0.02813720703125 +39187 0.250885009765625 +39188 0.0155029296875 +39189 0.1654052734375 +39190 -0.001617431640625 +39191 0.035247802734375 +39192 -0.02325439453125 +39193 -0.142059326171875 +39194 -0.0460205078125 +39195 -0.33563232421875 +39196 -0.068634033203125 +39197 -0.5345458984375 +39198 -0.089263916015625 +39199 -0.72186279296875 +39200 -0.10150146484375 +39201 -0.836669921875 +39202 -0.10052490234375 +39203 -0.8326416015625 +39204 -0.0885009765625 +39205 -0.7296142578125 +39206 -0.07122802734375 +39207 -0.582550048828125 +39208 -0.05389404296875 +39209 -0.440093994140625 +39210 -0.0389404296875 +39211 -0.324310302734375 +39212 -0.02301025390625 +39213 -0.20147705078125 +39214 -0.00347900390625 +39215 -0.044647216796875 +39216 0.015045166015625 +39217 0.103973388671875 +39218 0.028045654296875 +39219 0.202392578125 +39220 0.03680419921875 +39221 0.264495849609375 +39222 0.0462646484375 +39223 0.338897705078125 +39224 0.0582275390625 +39225 0.443817138671875 +39226 0.069091796875 +39227 0.545074462890625 +39228 0.076263427734375 +39229 0.6173095703125 +39230 0.07891845703125 +39231 0.6524658203125 +39232 0.078460693359375 +39233 0.66339111328125 +39234 0.075653076171875 +39235 0.6561279296875 +39236 0.068084716796875 +39237 0.606781005859375 +39238 0.054443359375 +39239 0.501190185546875 +39240 0.036285400390625 +39241 0.352783203125 +39242 0.015350341796875 +39243 0.176544189453125 +39244 -0.00897216796875 +39245 -0.034820556640625 +39246 -0.03411865234375 +39247 -0.258209228515625 +39248 -0.0546875 +39249 -0.44244384765625 +39250 -0.069366455078125 +39251 -0.5753173828125 +39252 -0.077606201171875 +39253 -0.65203857421875 +39254 -0.076202392578125 +39255 -0.641632080078125 +39256 -0.067108154296875 +39257 -0.562164306640625 +39258 -0.05499267578125 +39259 -0.458038330078125 +39260 -0.042144775390625 +39261 -0.350555419921875 +39262 -0.03082275390625 +39263 -0.260528564453125 +39264 -0.021575927734375 +39265 -0.192108154296875 +39266 -0.014190673828125 +39267 -0.141937255859375 +39268 -0.007965087890625 +39269 -0.1021728515625 +39270 -0.001953125 +39271 -0.062896728515625 +39272 0.004974365234375 +39273 -0.011932373046875 +39274 0.014007568359375 +39275 0.062835693359375 +39276 0.023773193359375 +39277 0.148712158203125 +39278 0.0338134765625 +39279 0.241729736328125 +39280 0.04486083984375 +39281 0.34912109375 +39282 0.055511474609375 +39283 0.457305908203125 +39284 0.063507080078125 +39285 0.54388427734375 +39286 0.065185546875 +39287 0.5728759765625 +39288 0.056671142578125 +39289 0.506591796875 +39290 0.038726806640625 +39291 0.351226806640625 +39292 0.01556396484375 +39293 0.146514892578125 +39294 -0.007232666015625 +39295 -0.05523681640625 +39296 -0.025634765625 +39297 -0.21624755859375 +39298 -0.03936767578125 +39299 -0.334930419921875 +39300 -0.047515869140625 +39301 -0.402984619140625 +39302 -0.05218505859375 +39303 -0.4412841796875 +39304 -0.058135986328125 +39305 -0.49578857421875 +39306 -0.064727783203125 +39307 -0.5601806640625 +39308 -0.068450927734375 +39309 -0.600738525390625 +39310 -0.065887451171875 +39311 -0.584228515625 +39312 -0.0538330078125 +39313 -0.47930908203125 +39314 -0.031707763671875 +39315 -0.27935791015625 +39316 -0.002105712890625 +39317 -0.0089111328125 +39318 0.02825927734375 +39319 0.268798828125 +39320 0.051910400390625 +39321 0.482818603515625 +39322 0.065704345703125 +39323 0.60369873046875 +39324 0.071563720703125 +39325 0.650421142578125 +39326 0.07373046875 +39327 0.66400146484375 +39328 0.071868896484375 +39329 0.6414794921875 +39330 0.064910888671875 +39331 0.572540283203125 +39332 0.05706787109375 +39333 0.498138427734375 +39334 0.050567626953125 +39335 0.439453125 +39336 0.04327392578125 +39337 0.375518798828125 +39338 0.031890869140625 +39339 0.274505615234375 +39340 0.013641357421875 +39341 0.1087646484375 +39342 -0.00909423828125 +39343 -0.099395751953125 +39344 -0.032928466796875 +39345 -0.3182373046875 +39346 -0.05792236328125 +39347 -0.5489501953125 +39348 -0.082183837890625 +39349 -0.7738037109375 +39350 -0.10015869140625 +39351 -0.86383056640625 +39352 -0.1083984375 +39353 -0.870391845703125 +39354 -0.108673095703125 +39355 -0.86895751953125 +39356 -0.10235595703125 +39357 -0.861053466796875 +39358 -0.087677001953125 +39359 -0.765869140625 +39360 -0.0634765625 +39361 -0.5301513671875 +39362 -0.030487060546875 +39363 -0.214691162109375 +39364 0.006744384765625 +39365 0.137359619140625 +39366 0.0428466796875 +39367 0.474822998046875 +39368 0.0740966796875 +39369 0.76239013671875 +39370 0.097625732421875 +39371 0.867462158203125 +39372 0.113433837890625 +39373 0.870361328125 +39374 0.120269775390625 +39375 0.86480712890625 +39376 0.11865234375 +39377 0.831817626953125 +39378 0.111114501953125 +39379 0.677581787109375 +39380 0.0982666015625 +39381 0.495880126953125 +39382 0.08203125 +39383 0.30767822265625 +39384 0.062652587890625 +39385 0.116180419921875 +39386 0.036834716796875 +39387 -0.110748291015625 +39388 0.00384521484375 +39389 -0.381805419921875 +39390 -0.03179931640625 +39391 -0.6572265625 +39392 -0.063812255859375 +39393 -0.857421875 +39394 -0.087738037109375 +39395 -0.870391845703125 +39396 -0.102813720703125 +39397 -0.870391845703125 +39398 -0.11181640625 +39399 -0.86444091796875 +39400 -0.118438720703125 +39401 -0.85723876953125 +39402 -0.120758056640625 +39403 -0.790008544921875 +39404 -0.11309814453125 +39405 -0.62847900390625 +39406 -0.095123291015625 +39407 -0.3956298828125 +39408 -0.07025146484375 +39409 -0.126708984375 +39410 -0.04132080078125 +39411 0.150115966796875 +39412 -0.00958251953125 +39413 0.424041748046875 +39414 0.02215576171875 +39415 0.670623779296875 +39416 0.0498046875 +39417 0.854522705078125 +39418 0.071533203125 +39419 0.866485595703125 +39420 0.08575439453125 +39421 0.86920166015625 +39422 0.094329833984375 +39423 0.8653564453125 +39424 0.098907470703125 +39425 0.857147216796875 +39426 0.098907470703125 +39427 0.766845703125 +39428 0.094482421875 +39429 0.628509521484375 +39430 0.085205078125 +39431 0.462127685546875 +39432 0.0731201171875 +39433 0.297210693359375 +39434 0.059326171875 +39435 0.14862060546875 +39436 0.042510986328125 +39437 -0.00537109375 +39438 0.023590087890625 +39439 -0.15753173828125 +39440 0.002716064453125 +39441 -0.31304931640625 +39442 -0.02069091796875 +39443 -0.48876953125 +39444 -0.04290771484375 +39445 -0.6416015625 +39446 -0.0618896484375 +39447 -0.751373291015625 +39448 -0.07904052734375 +39449 -0.84619140625 +39450 -0.0931396484375 +39451 -0.861297607421875 +39452 -0.1016845703125 +39453 -0.863250732421875 +39454 -0.102386474609375 +39455 -0.856597900390625 +39456 -0.09625244140625 +39457 -0.7498779296875 +39458 -0.08758544921875 +39459 -0.624542236328125 +39460 -0.07501220703125 +39461 -0.47808837890625 +39462 -0.05462646484375 +39463 -0.253387451171875 +39464 -0.030029296875 +39465 0.003692626953125 +39466 -0.0064697265625 +39467 0.2257080078125 +39468 0.016632080078125 +39469 0.427154541015625 +39470 0.04132080078125 +39471 0.643218994140625 +39472 0.066619873046875 +39473 0.855926513671875 +39474 0.088165283203125 +39475 0.870361328125 +39476 0.102203369140625 +39477 0.870361328125 +39478 0.109161376953125 +39479 0.862762451171875 +39480 0.108856201171875 +39481 0.79669189453125 +39482 0.100677490234375 +39483 0.595794677734375 +39484 0.0867919921875 +39485 0.362152099609375 +39486 0.069427490234375 +39487 0.1270751953125 +39488 0.050323486328125 +39489 -0.086944580078125 +39490 0.02984619140625 +39491 -0.2784423828125 +39492 0.005767822265625 +39493 -0.484832763671875 +39494 -0.02301025390625 +39495 -0.729583740234375 +39496 -0.052581787109375 +39497 -0.86688232421875 +39498 -0.078125 +39499 -0.870391845703125 +39500 -0.099090576171875 +39501 -0.86859130859375 +39502 -0.115203857421875 +39503 -0.86279296875 +39504 -0.123809814453125 +39505 -0.817962646484375 +39506 -0.121612548828125 +39507 -0.6116943359375 +39508 -0.108123779296875 +39509 -0.3128662109375 +39510 -0.08587646484375 +39511 0.039398193359375 +39512 -0.05645751953125 +39513 0.422821044921875 +39514 -0.022430419921875 +39515 0.805145263671875 +39516 0.011077880859375 +39517 0.870361328125 +39518 0.039764404296875 +39519 0.870361328125 +39520 0.06256103515625 +39521 0.860015869140625 +39522 0.07867431640625 +39523 0.727935791015625 +39524 0.0875244140625 +39525 0.48114013671875 +39526 0.0906982421875 +39527 0.2059326171875 +39528 0.08966064453125 +39529 -0.06103515625 +39530 0.0850830078125 +39531 -0.29913330078125 +39532 0.075836181640625 +39533 -0.516204833984375 +39534 0.06085205078125 +39535 -0.7252197265625 +39536 0.041961669921875 +39537 -0.85980224609375 +39538 0.021728515625 +39539 -0.870391845703125 +39540 0.00244140625 +39541 -0.870391845703125 +39542 -0.012176513671875 +39543 -0.858062744140625 +39544 -0.021636962890625 +39545 -0.673004150390625 +39546 -0.029541015625 +39547 -0.42694091796875 +39548 -0.03887939453125 +39549 -0.2100830078125 +39550 -0.04925537109375 +39551 -0.0362548828125 +39552 -0.058441162109375 +39553 0.10943603515625 +39554 -0.0648193359375 +39555 0.23516845703125 +39556 -0.065338134765625 +39557 0.373687744140625 +39558 -0.060089111328125 +39559 0.517791748046875 +39560 -0.053619384765625 +39561 0.602783203125 +39562 -0.045562744140625 +39563 0.635711669921875 +39564 -0.03363037109375 +39565 0.655181884765625 +39566 -0.0186767578125 +39567 0.65948486328125 +39568 -0.00140380859375 +39569 0.651275634765625 +39570 0.016204833984375 +39571 0.61846923828125 +39572 0.03131103515625 +39573 0.53753662109375 +39574 0.04241943359375 +39575 0.404144287109375 +39576 0.048675537109375 +39577 0.22186279296875 +39578 0.050048828125 +39579 0.003997802734375 +39580 0.0477294921875 +39581 -0.22100830078125 +39582 0.043121337890625 +39583 -0.42449951171875 +39584 0.03765869140625 +39585 -0.579833984375 +39586 0.034423828125 +39587 -0.641876220703125 +39588 0.032958984375 +39589 -0.6177978515625 +39590 0.0286865234375 +39591 -0.575531005859375 +39592 0.021270751953125 +39593 -0.526336669921875 +39594 0.01458740234375 +39595 -0.42645263671875 +39596 0.010711669921875 +39597 -0.2581787109375 +39598 0.007232666015625 +39599 -0.068695068359375 +39600 0.001495361328125 +39601 0.09222412109375 +39602 -0.00494384765625 +39603 0.232147216796875 +39604 -0.01123046875 +39605 0.3509521484375 +39606 -0.019378662109375 +39607 0.410064697265625 +39608 -0.031402587890625 +39609 0.372955322265625 +39610 -0.04571533203125 +39611 0.2554931640625 +39612 -0.058563232421875 +39613 0.10711669921875 +39614 -0.068511962890625 +39615 -0.052886962890625 +39616 -0.073028564453125 +39617 -0.186279296875 +39618 -0.068145751953125 +39619 -0.23291015625 +39620 -0.055633544921875 +39621 -0.209442138671875 +39622 -0.04034423828125 +39623 -0.174163818359375 +39624 -0.02301025390625 +39625 -0.126739501953125 +39626 -0.0030517578125 +39627 -0.048126220703125 +39628 0.017333984375 +39629 0.0426025390625 +39630 0.03466796875 +39631 0.10748291015625 +39632 0.047882080078125 +39633 0.1409912109375 +39634 0.060333251953125 +39635 0.19708251953125 +39636 0.07147216796875 +39637 0.273651123046875 +39638 0.0772705078125 +39639 0.31768798828125 +39640 0.07855224609375 +39641 0.341094970703125 +39642 0.077178955078125 +39643 0.368011474609375 +39644 0.071533203125 +39645 0.37249755859375 +39646 0.058135986328125 +39647 0.30072021484375 +39648 0.037445068359375 +39649 0.1517333984375 +39650 0.01434326171875 +39651 -0.01470947265625 +39652 -0.009765625 +39653 -0.1883544921875 +39654 -0.03448486328125 +39655 -0.372711181640625 +39656 -0.0552978515625 +39657 -0.51397705078125 +39658 -0.068756103515625 +39659 -0.57177734375 +39660 -0.07391357421875 +39661 -0.53948974609375 +39662 -0.071746826171875 +39663 -0.43511962890625 +39664 -0.064727783203125 +39665 -0.2962646484375 +39666 -0.05548095703125 +39667 -0.161102294921875 +39668 -0.045074462890625 +39669 -0.0435791015625 +39670 -0.033355712890625 +39671 0.060394287109375 +39672 -0.02166748046875 +39673 0.13665771484375 +39674 -0.011505126953125 +39675 0.170135498046875 +39676 -0.002960205078125 +39677 0.16552734375 +39678 0.005889892578125 +39679 0.15728759765625 +39680 0.015045166015625 +39681 0.150787353515625 +39682 0.022308349609375 +39683 0.12200927734375 +39684 0.027557373046875 +39685 0.080108642578125 +39686 0.0318603515625 +39687 0.05126953125 +39688 0.03643798828125 +39689 0.062896728515625 +39690 0.040069580078125 +39691 0.09271240234375 +39692 0.04034423828125 +39693 0.092987060546875 +39694 0.038055419921875 +39695 0.07855224609375 +39696 0.034088134765625 +39697 0.06427001953125 +39698 0.02789306640625 +39699 0.0347900390625 +39700 0.0196533203125 +39701 -0.01171875 +39702 0.01068115234375 +39703 -0.056060791015625 +39704 0.003448486328125 +39705 -0.055511474609375 +39706 -0.0015869140625 +39707 -0.010467529296875 +39708 -0.00677490234375 +39709 0.02508544921875 +39710 -0.013031005859375 +39711 0.025665283203125 +39712 -0.01873779296875 +39713 0.017333984375 +39714 -0.0235595703125 +39715 0.00189208984375 +39716 -0.027862548828125 +39717 -0.03173828125 +39718 -0.03094482421875 +39719 -0.071502685546875 +39720 -0.03369140625 +39721 -0.13543701171875 +39722 -0.035980224609375 +39723 -0.219970703125 +39724 -0.036712646484375 +39725 -0.300506591796875 +39726 -0.03607177734375 +39727 -0.376312255859375 +39728 -0.032806396484375 +39729 -0.416107177734375 +39730 -0.0247802734375 +39731 -0.371124267578125 +39732 -0.012359619140625 +39733 -0.242279052734375 +39734 0.0020751953125 +39735 -0.069732666015625 +39736 0.017181396484375 +39737 0.125640869140625 +39738 0.0311279296875 +39739 0.31268310546875 +39740 0.041839599609375 +39741 0.45501708984375 +39742 0.04925537109375 +39743 0.554779052734375 +39744 0.053253173828125 +39745 0.61065673828125 +39746 0.053192138671875 +39747 0.610931396484375 +39748 0.04791259765625 +39749 0.531463623046875 +39750 0.038330078125 +39751 0.3883056640625 +39752 0.027252197265625 +39753 0.23468017578125 +39754 0.01617431640625 +39755 0.095245361328125 +39756 0.006622314453125 +39757 -0.00396728515625 +39758 -0.00042724609375 +39759 -0.04852294921875 +39760 -0.005523681640625 +39761 -0.055145263671875 +39762 -0.011016845703125 +39763 -0.0758056640625 +39764 -0.01806640625 +39765 -0.138702392578125 +39766 -0.024749755859375 +39767 -0.209197998046875 +39768 -0.030975341796875 +39769 -0.289031982421875 +39770 -0.036712646484375 +39771 -0.37884521484375 +39772 -0.040802001953125 +39773 -0.456329345703125 +39774 -0.04302978515625 +39775 -0.51641845703125 +39776 -0.04144287109375 +39777 -0.519287109375 +39778 -0.03582763671875 +39779 -0.458251953125 +39780 -0.0289306640625 +39781 -0.384796142578125 +39782 -0.022186279296875 +39783 -0.323699951171875 +39784 -0.0155029296875 +39785 -0.269287109375 +39786 -0.007781982421875 +39787 -0.1951904296875 +39788 0.000762939453125 +39789 -0.100006103515625 +39790 0.00860595703125 +39791 -0.01055908203125 +39792 0.017059326171875 +39793 0.1033935546875 +39794 0.0263671875 +39795 0.24908447265625 +39796 0.033782958984375 +39797 0.373199462890625 +39798 0.038360595703125 +39799 0.45806884765625 +39800 0.040496826171875 +39801 0.511474609375 +39802 0.041839599609375 +39803 0.565399169921875 +39804 0.042083740234375 +39805 0.61138916015625 +39806 0.038360595703125 +39807 0.5897216796875 +39808 0.03033447265625 +39809 0.4906005859375 +39810 0.019073486328125 +39811 0.33148193359375 +39812 0.006561279296875 +39813 0.147796630859375 +39814 -0.004913330078125 +39815 -0.01873779296875 +39816 -0.0137939453125 +39817 -0.140289306640625 +39818 -0.018707275390625 +39819 -0.191986083984375 +39820 -0.02008056640625 +39821 -0.184295654296875 +39822 -0.020050048828125 +39823 -0.161834716796875 +39824 -0.02069091796875 +39825 -0.166595458984375 +39826 -0.021728515625 +39827 -0.19390869140625 +39828 -0.02227783203125 +39829 -0.22442626953125 +39830 -0.023468017578125 +39831 -0.279754638671875 +39832 -0.02435302734375 +39833 -0.3389892578125 +39834 -0.022674560546875 +39835 -0.3543701171875 +39836 -0.019683837890625 +39837 -0.348175048828125 +39838 -0.01580810546875 +39839 -0.32598876953125 +39840 -0.009735107421875 +39841 -0.2581787109375 +39842 -0.0013427734375 +39843 -0.139801025390625 +39844 0.00848388671875 +39845 0.014617919921875 +39846 0.016571044921875 +39847 0.144378662109375 +39848 0.02142333984375 +39849 0.221038818359375 +39850 0.024322509765625 +39851 0.27069091796875 +39852 0.025299072265625 +39853 0.294036865234375 +39854 0.025421142578125 +39855 0.311767578125 +39856 0.025482177734375 +39857 0.339141845703125 +39858 0.024658203125 +39859 0.360260009765625 +39860 0.022369384765625 +39861 0.360504150390625 +39862 0.017547607421875 +39863 0.308380126953125 +39864 0.00946044921875 +39865 0.18170166015625 +39866 -0.00067138671875 +39867 0.0047607421875 +39868 -0.010772705078125 +39869 -0.17559814453125 +39870 -0.01885986328125 +39871 -0.3143310546875 +39872 -0.0230712890625 +39873 -0.36785888671875 +39874 -0.02435302734375 +39875 -0.36248779296875 +39876 -0.02447509765625 +39877 -0.343536376953125 +39878 -0.023040771484375 +39879 -0.3018798828125 +39880 -0.01983642578125 +39881 -0.231414794921875 +39882 -0.014312744140625 +39883 -0.117645263671875 +39884 -0.007843017578125 +39885 0.007049560546875 +39886 -0.002716064453125 +39887 0.087982177734375 +39888 0.00152587890625 +39889 0.13946533203125 +39890 0.005279541015625 +39891 0.17425537109375 +39892 0.008209228515625 +39893 0.188201904296875 +39894 0.009796142578125 +39895 0.171234130859375 +39896 0.009735107421875 +39897 0.118438720703125 +39898 0.009033203125 +39899 0.05706787109375 +39900 0.0076904296875 +39901 -0.010711669921875 +39902 0.00537109375 +39903 -0.0914306640625 +39904 0.0029296875 +39905 -0.162322998046875 +39906 0.00152587890625 +39907 -0.194549560546875 +39908 0.002716064453125 +39909 -0.1492919921875 +39910 0.0067138671875 +39911 -0.02166748046875 +39912 0.011016845703125 +39913 0.124053955078125 +39914 0.012664794921875 +39915 0.211151123046875 +39916 0.011810302734375 +39917 0.240447998046875 +39918 0.009765625 +39919 0.242218017578125 +39920 0.007049560546875 +39921 0.2257080078125 +39922 0.00390625 +39923 0.194366455078125 +39924 -0.0008544921875 +39925 0.115509033203125 +39926 -0.006134033203125 +39927 0.0128173828125 +39928 -0.009521484375 +39929 -0.053802490234375 +39930 -0.012054443359375 +39931 -0.110626220703125 +39932 -0.015411376953125 +39933 -0.199493408203125 +39934 -0.018585205078125 +39935 -0.29437255859375 +39936 -0.01947021484375 +39937 -0.33221435546875 +39938 -0.01751708984375 +39939 -0.27972412109375 +39940 -0.013671875 +39941 -0.185333251953125 +39942 -0.00909423828125 +39943 -0.128204345703125 +39944 -0.004302978515625 +39945 -0.115692138671875 +39946 0.000457763671875 +39947 -0.116455078125 +39948 0.005035400390625 +39949 -0.105926513671875 +39950 0.0093994140625 +39951 -0.053955078125 +39952 0.01336669921875 +39953 0.048797607421875 +39954 0.01641845703125 +39955 0.157318115234375 +39956 0.01800537109375 +39957 0.212005615234375 +39958 0.018157958984375 +39959 0.218475341796875 +39960 0.01739501953125 +39961 0.23724365234375 +39962 0.01611328125 +39963 0.30535888671875 +39964 0.01409912109375 +39965 0.38128662109375 +39966 0.011077880859375 +39967 0.404449462890625 +39968 0.007415771484375 +39969 0.3944091796875 +39970 0.003631591796875 +39971 0.3885498046875 +39972 -0.000213623046875 +39973 0.362640380859375 +39974 -0.0042724609375 +39975 0.27362060546875 +39976 -0.008392333984375 +39977 0.11712646484375 +39978 -0.011993408203125 +39979 -0.054901123046875 +39980 -0.014556884765625 +39981 -0.19085693359375 +39982 -0.0159912109375 +39983 -0.28570556640625 +39984 -0.01629638671875 +39985 -0.339263916015625 +39986 -0.015716552734375 +39987 -0.3775634765625 +39988 -0.014678955078125 +39989 -0.445709228515625 +39990 -0.01318359375 +39991 -0.535064697265625 +39992 -0.01129150390625 +39993 -0.629058837890625 +39994 -0.008880615234375 +39995 -0.697601318359375 +39996 -0.005828857421875 +39997 -0.70391845703125 +39998 -0.002288818359375 +39999 -0.6424560546875 +40000 0.001708984375 +40001 -0.491241455078125 +40002 0.00592041015625 +40003 -0.265716552734375 +40004 0.009735107421875 +40005 -0.023712158203125 +40006 0.012786865234375 +40007 0.201751708984375 +40008 0.0147705078125 +40009 0.375823974609375 +40010 0.015594482421875 +40011 0.485076904296875 +40012 0.015594482421875 +40013 0.56884765625 +40014 0.014862060546875 +40015 0.634765625 +40016 0.01312255859375 +40017 0.63763427734375 +40018 0.010406494140625 +40019 0.5660400390625 +40020 0.00726318359375 +40021 0.4720458984375 +40022 0.004241943359375 +40023 0.40692138671875 +40024 0.00152587890625 +40025 0.3778076171875 +40026 -0.000823974609375 +40027 0.376953125 +40028 -0.0029296875 +40029 0.371978759765625 +40030 -0.005096435546875 +40031 0.313140869140625 +40032 -0.00732421875 +40033 0.184417724609375 +40034 -0.009368896484375 +40035 0.011199951171875 +40036 -0.010894775390625 +40037 -0.171051025390625 +40038 -0.01171875 +40039 -0.33740234375 +40040 -0.011749267578125 +40041 -0.47198486328125 +40042 -0.010955810546875 +40043 -0.560394287109375 +40044 -0.009246826171875 +40045 -0.58056640625 +40046 -0.00689697265625 +40047 -0.54754638671875 +40048 -0.004425048828125 +40049 -0.508575439453125 +40050 -0.00189208984375 +40051 -0.459503173828125 +40052 0.0006103515625 +40053 -0.394378662109375 +40054 0.002685546875 +40055 -0.35260009765625 +40056 0.00439453125 +40057 -0.31170654296875 +40058 0.00628662109375 +40059 -0.197418212890625 +40060 0.00830078125 +40061 -0.007965087890625 +40062 0.010040283203125 +40063 0.207489013671875 +40064 0.01116943359375 +40065 0.409210205078125 +40066 0.011566162109375 +40067 0.57208251953125 +40068 0.01104736328125 +40069 0.66595458984375 +40070 0.00946044921875 +40071 0.65875244140625 +40072 0.00701904296875 +40073 0.56744384765625 +40074 0.004150390625 +40075 0.431396484375 +40076 0.00128173828125 +40077 0.29443359375 +40078 -0.001251220703125 +40079 0.182464599609375 +40080 -0.00360107421875 +40081 0.06365966796875 +40082 -0.005828857421875 +40083 -0.075958251953125 +40084 -0.00750732421875 +40085 -0.189422607421875 +40086 -0.008544921875 +40087 -0.271942138671875 +40088 -0.009063720703125 +40089 -0.342529296875 +40090 -0.00885009765625 +40091 -0.364166259765625 +40092 -0.007843017578125 +40093 -0.327239990234375 +40094 -0.006439208984375 +40095 -0.2769775390625 +40096 -0.005035400390625 +40097 -0.253692626953125 +40098 -0.00360107421875 +40099 -0.24365234375 +40100 -0.001800537109375 +40101 -0.1983642578125 +40102 0.000244140625 +40103 -0.116241455078125 +40104 0.002166748046875 +40105 -0.036834716796875 +40106 0.00384521484375 +40107 0.034881591796875 +40108 0.00518798828125 +40109 0.09124755859375 +40110 0.0059814453125 +40111 0.10888671875 +40112 0.006500244140625 +40113 0.125518798828125 +40114 0.0068359375 +40115 0.15771484375 +40116 0.00677490234375 +40117 0.17828369140625 +40118 0.006195068359375 +40119 0.17108154296875 +40120 0.005126953125 +40121 0.129974365234375 +40122 0.003814697265625 +40123 0.082427978515625 +40124 0.002288818359375 +40125 0.027679443359375 +40126 0.000396728515625 +40127 -0.065643310546875 +40128 -0.00146484375 +40129 -0.15936279296875 +40130 -0.0029296875 +40131 -0.21307373046875 +40132 -0.0040283203125 +40133 -0.234649658203125 +40134 -0.0045166015625 +40135 -0.2001953125 +40136 -0.004425048828125 +40137 -0.119171142578125 +40138 -0.003997802734375 +40139 -0.024749755859375 +40140 -0.003173828125 +40141 0.085784912109375 +40142 -0.002288818359375 +40143 0.178131103515625 +40144 -0.001617431640625 +40145 0.215576171875 +40146 -0.0010986328125 +40147 0.211456298828125 +40148 -0.00067138671875 +40149 0.17523193359375 +40150 -0.00018310546875 +40151 0.128753662109375 +40152 0.00054931640625 +40153 0.1019287109375 +40154 0.001251220703125 +40155 0.0743408203125 +40156 0.001861572265625 +40157 0.04327392578125 +40158 0.002593994140625 +40159 0.038177490234375 +40160 0.00347900390625 +40161 0.076263427734375 +40162 0.00439453125 +40163 0.14105224609375 +40164 0.00494384765625 +40165 0.186431884765625 +40166 0.00494384765625 +40167 0.188812255859375 +40168 0.00433349609375 +40169 0.1390380859375 +40170 0.003173828125 +40171 0.041778564453125 +40172 0.001708984375 +40173 -0.079437255859375 +40174 0.0 +40175 -0.219390869140625 +40176 -0.001800537109375 +40177 -0.367828369140625 +40178 -0.00341796875 +40179 -0.494873046875 +40180 -0.004486083984375 +40181 -0.556243896484375 +40182 -0.004638671875 +40183 -0.508697509765625 +40184 -0.0040283203125 +40185 -0.3756103515625 +40186 -0.00311279296875 +40187 -0.218902587890625 +40188 -0.00213623046875 +40189 -0.063751220703125 +40190 -0.001068115234375 +40191 0.091552734375 +40192 3.0517578125e-05 +40193 0.23602294921875 +40194 0.000946044921875 +40195 0.342987060546875 +40196 0.00140380859375 +40197 0.39520263671875 +40198 0.001251220703125 +40199 0.389373779296875 +40200 0.000335693359375 +40201 0.324249267578125 +40202 -0.000885009765625 +40203 0.224090576171875 +40204 -0.001739501953125 +40205 0.124267578125 +40206 -0.002044677734375 +40207 0.037078857421875 +40208 -0.00128173828125 +40209 -0.010101318359375 +40210 0.000335693359375 +40211 -0.019439697265625 +40212 0.001953125 +40213 -0.022796630859375 +40214 0.003936767578125 +40215 -0.001556396484375 +40216 0.006439208984375 +40217 0.056304931640625 +40218 0.008392333984375 +40219 0.106719970703125 +40220 0.008514404296875 +40221 0.096893310546875 +40222 0.0072021484375 +40223 0.042694091796875 +40224 0.005401611328125 +40225 -0.018035888671875 +40226 0.00335693359375 +40227 -0.07586669921875 +40228 0.00140380859375 +40229 -0.11944580078125 +40230 -0.00067138671875 +40231 -0.15972900390625 +40232 -0.0029296875 +40233 -0.202606201171875 +40234 -0.0052490234375 +40235 -0.24859619140625 +40236 -0.007781982421875 +40237 -0.30517578125 +40238 -0.010223388671875 +40239 -0.36212158203125 +40240 -0.011871337890625 +40241 -0.39141845703125 +40242 -0.011749267578125 +40243 -0.35528564453125 +40244 -0.009735107421875 +40245 -0.249969482421875 +40246 -0.0062255859375 +40247 -0.092864990234375 +40248 -0.00189208984375 +40249 0.08905029296875 +40250 0.001800537109375 +40251 0.2352294921875 +40252 0.004180908203125 +40253 0.318817138671875 +40254 0.005706787109375 +40255 0.358642578125 +40256 0.00616455078125 +40257 0.347747802734375 +40258 0.005462646484375 +40259 0.28564453125 +40260 0.00482177734375 +40261 0.223175048828125 +40262 0.005035400390625 +40263 0.196746826171875 +40264 0.00543212890625 +40265 0.179840087890625 +40266 0.005584716796875 +40267 0.155548095703125 +40268 0.006072998046875 +40269 0.151214599609375 +40270 0.00665283203125 +40271 0.156951904296875 +40272 0.006317138671875 +40273 0.13177490234375 +40274 0.005645751953125 +40275 0.100799560546875 +40276 0.005218505859375 +40277 0.087127685546875 +40278 0.004180908203125 +40279 0.05487060546875 +40280 0.002227783203125 +40281 -0.009002685546875 +40282 -0.00054931640625 +40283 -0.10400390625 +40284 -0.004150390625 +40285 -0.229400634765625 +40286 -0.0078125 +40287 -0.35552978515625 +40288 -0.010498046875 +40289 -0.441925048828125 +40290 -0.011810302734375 +40291 -0.473846435546875 +40292 -0.0120849609375 +40293 -0.464813232421875 +40294 -0.011383056640625 +40295 -0.419097900390625 +40296 -0.0096435546875 +40297 -0.334320068359375 +40298 -0.00726318359375 +40299 -0.227935791015625 +40300 -0.004791259765625 +40301 -0.12347412109375 +40302 -0.00238037109375 +40303 -0.02764892578125 +40304 0.0003662109375 +40305 0.077667236328125 +40306 0.00390625 +40307 0.2132568359375 +40308 0.008453369140625 +40309 0.38885498046875 +40310 0.01348876953125 +40311 0.582794189453125 +40312 0.01751708984375 +40313 0.734039306640625 +40314 0.01947021484375 +40315 0.800140380859375 +40316 0.019256591796875 +40317 0.7783203125 +40318 0.016815185546875 +40319 0.6651611328125 +40320 0.012115478515625 +40321 0.45965576171875 +40322 0.006072998046875 +40323 0.199188232421875 +40324 0.000244140625 +40325 -0.050689697265625 +40326 -0.003997802734375 +40327 -0.23297119140625 +40328 -0.006256103515625 +40329 -0.33013916015625 +40330 -0.007171630859375 +40331 -0.368408203125 +40332 -0.007476806640625 +40333 -0.378936767578125 +40334 -0.007568359375 +40335 -0.376983642578125 +40336 -0.007843017578125 +40337 -0.37969970703125 +40338 -0.00836181640625 +40339 -0.391510009765625 +40340 -0.008453369140625 +40341 -0.385345458984375 +40342 -0.007659912109375 +40343 -0.3419189453125 +40344 -0.0064697265625 +40345 -0.28289794921875 +40346 -0.00592041015625 +40347 -0.251617431640625 +40348 -0.006439208984375 +40349 -0.266143798828125 +40350 -0.006744384765625 +40351 -0.273345947265625 +40352 -0.0054931640625 +40353 -0.216796875 +40354 -0.003448486328125 +40355 -0.128265380859375 +40356 -0.00201416015625 +40357 -0.068145751953125 +40358 -0.0013427734375 +40359 -0.0430908203125 +40360 -0.000762939453125 +40361 -0.024444580078125 +40362 0.000457763671875 +40363 0.020721435546875 +40364 0.003082275390625 +40365 0.124481201171875 +40366 0.00640869140625 +40367 0.25787353515625 +40368 0.0093994140625 +40369 0.379119873046875 +40370 0.011871337890625 +40371 0.47991943359375 +40372 0.0130615234375 +40373 0.5281982421875 +40374 0.01263427734375 +40375 0.511138916015625 +40376 0.01129150390625 +40377 0.456207275390625 +40378 0.01007080078125 +40379 0.407470703125 +40380 0.009429931640625 +40381 0.383758544921875 +40382 0.008636474609375 +40383 0.35687255859375 +40384 0.00738525390625 +40385 0.31182861328125 +40386 0.0057373046875 +40387 0.250885009765625 +40388 0.0035400390625 +40389 0.1654052734375 +40390 0.00030517578125 +40391 0.035247802734375 +40392 -0.00396728515625 +40393 -0.142059326171875 +40394 -0.008544921875 +40395 -0.33563232421875 +40396 -0.01318359375 +40397 -0.5345458984375 +40398 -0.01751708984375 +40399 -0.72186279296875 +40400 -0.02001953125 +40401 -0.836669921875 +40402 -0.019622802734375 +40403 -0.8326416015625 +40404 -0.016845703125 +40405 -0.7296142578125 +40406 -0.0130615234375 +40407 -0.582550048828125 +40408 -0.009429931640625 +40409 -0.440093994140625 +40410 -0.006500244140625 +40411 -0.324310302734375 +40412 -0.00341796875 +40413 -0.20147705078125 +40414 0.00042724609375 +40415 -0.044647216796875 +40416 0.003997802734375 +40417 0.103973388671875 +40418 0.006256103515625 +40419 0.202392578125 +40420 0.007568359375 +40421 0.264495849609375 +40422 0.009124755859375 +40423 0.338897705078125 +40424 0.0113525390625 +40425 0.443817138671875 +40426 0.013458251953125 +40427 0.545074462890625 +40428 0.014862060546875 +40429 0.6173095703125 +40430 0.015380859375 +40431 0.6524658203125 +40432 0.01531982421875 +40433 0.66339111328125 +40434 0.014862060546875 +40435 0.6561279296875 +40436 0.013427734375 +40437 0.606781005859375 +40438 0.01068115234375 +40439 0.501190185546875 +40440 0.006988525390625 +40441 0.352783203125 +40442 0.002685546875 +40443 0.176544189453125 +40444 -0.0023193359375 +40445 -0.034820556640625 +40446 -0.007476806640625 +40447 -0.258209228515625 +40448 -0.011383056640625 +40449 -0.44244384765625 +40450 -0.013946533203125 +40451 -0.5753173828125 +40452 -0.01495361328125 +40453 -0.65203857421875 +40454 -0.0126953125 +40455 -0.641632080078125 +40456 -0.008056640625 +40457 -0.562164306640625 +40458 -0.00341796875 +40459 -0.458038330078125 +40460 0.000213623046875 +40461 -0.350555419921875 +40462 0.00189208984375 +40463 -0.260528564453125 +40464 0.001617431640625 +40465 -0.192108154296875 +40466 -0.0001220703125 +40467 -0.141937255859375 +40468 -0.00262451171875 +40469 -0.1021728515625 +40470 -0.005096435546875 +40471 -0.062896728515625 +40472 -0.006591796875 +40473 -0.011932373046875 +40474 -0.0062255859375 +40475 0.062835693359375 +40476 -0.0045166015625 +40477 0.148712158203125 +40478 -0.0015869140625 +40479 0.241729736328125 +40480 0.0030517578125 +40481 0.34912109375 +40482 0.0086669921875 +40483 0.457305908203125 +40484 0.014007568359375 +40485 0.54388427734375 +40486 0.016998291015625 +40487 0.5728759765625 +40488 0.01544189453125 +40489 0.506591796875 +40490 0.009552001953125 +40491 0.351226806640625 +40492 0.001373291015625 +40493 0.146514892578125 +40494 -0.00634765625 +40495 -0.05523681640625 +40496 -0.011688232421875 +40497 -0.21624755859375 +40498 -0.014739990234375 +40499 -0.334930419921875 +40500 -0.01519775390625 +40501 -0.402984619140625 +40502 -0.01446533203125 +40503 -0.4412841796875 +40504 -0.0152587890625 +40505 -0.49578857421875 +40506 -0.017333984375 +40507 -0.5601806640625 +40508 -0.01885986328125 +40509 -0.600738525390625 +40510 -0.01800537109375 +40511 -0.584228515625 +40512 -0.012969970703125 +40513 -0.47930908203125 +40514 -0.003326416015625 +40515 -0.27935791015625 +40516 0.0096435546875 +40517 -0.0089111328125 +40518 0.02252197265625 +40519 0.268798828125 +40520 0.031494140625 +40521 0.482818603515625 +40522 0.03509521484375 +40523 0.60369873046875 +40524 0.0345458984375 +40525 0.650421142578125 +40526 0.0323486328125 +40527 0.66400146484375 +40528 0.028472900390625 +40529 0.6414794921875 +40530 0.0224609375 +40531 0.572540283203125 +40532 0.0167236328125 +40533 0.498138427734375 +40534 0.01251220703125 +40535 0.439453125 +40536 0.008697509765625 +40537 0.375518798828125 +40538 0.003509521484375 +40539 0.274505615234375 +40540 -0.004638671875 +40541 0.1087646484375 +40542 -0.01458740234375 +40543 -0.099395751953125 +40544 -0.024658203125 +40545 -0.3182373046875 +40546 -0.035064697265625 +40547 -0.5489501953125 +40548 -0.044921875 +40549 -0.7738037109375 +40550 -0.051422119140625 +40551 -0.86383056640625 +40552 -0.052886962890625 +40553 -0.870391845703125 +40554 -0.050445556640625 +40555 -0.86895751953125 +40556 -0.044952392578125 +40557 -0.861053466796875 +40558 -0.0355224609375 +40559 -0.765869140625 +40560 -0.021636962890625 +40561 -0.5301513671875 +40562 -0.00372314453125 +40563 -0.214691162109375 +40564 0.015777587890625 +40565 0.137359619140625 +40566 0.034027099609375 +40567 0.474822998046875 +40568 0.049102783203125 +40569 0.76239013671875 +40570 0.0595703125 +40571 0.867462158203125 +40572 0.065582275390625 +40573 0.870361328125 +40574 0.066558837890625 +40575 0.86480712890625 +40576 0.062957763671875 +40577 0.831817626953125 +40578 0.056304931640625 +40579 0.677581787109375 +40580 0.047027587890625 +40581 0.495880126953125 +40582 0.03631591796875 +40583 0.30767822265625 +40584 0.0244140625 +40585 0.116180419921875 +40586 0.00958251953125 +40587 -0.110748291015625 +40588 -0.00848388671875 +40589 -0.381805419921875 +40590 -0.027374267578125 +40591 -0.6572265625 +40592 -0.043731689453125 +40593 -0.857421875 +40594 -0.055206298828125 +40595 -0.870391845703125 +40596 -0.061492919921875 +40597 -0.870391845703125 +40598 -0.064208984375 +40599 -0.86444091796875 +40600 -0.06549072265625 +40601 -0.85723876953125 +40602 -0.064422607421875 +40603 -0.790008544921875 +40604 -0.05810546875 +40605 -0.62847900390625 +40606 -0.046417236328125 +40607 -0.3956298828125 +40608 -0.03131103515625 +40609 -0.126708984375 +40610 -0.014434814453125 +40611 0.150115966796875 +40612 0.00347900390625 +40613 0.424041748046875 +40614 0.020904541015625 +40615 0.670623779296875 +40616 0.03564453125 +40617 0.854522705078125 +40618 0.046722412109375 +40619 0.866485595703125 +40620 0.053314208984375 +40621 0.86920166015625 +40622 0.0565185546875 +40623 0.8653564453125 +40624 0.05712890625 +40625 0.857147216796875 +40626 0.05511474609375 +40627 0.766845703125 +40628 0.050872802734375 +40629 0.628509521484375 +40630 0.044097900390625 +40631 0.462127685546875 +40632 0.03631591796875 +40633 0.297210693359375 +40634 0.028289794921875 +40635 0.14862060546875 +40636 0.01885986328125 +40637 -0.00537109375 +40638 0.00848388671875 +40639 -0.15753173828125 +40640 -0.002960205078125 +40641 -0.31304931640625 +40642 -0.016204833984375 +40643 -0.48876953125 +40644 -0.02862548828125 +40645 -0.6416015625 +40646 -0.03887939453125 +40647 -0.751373291015625 +40648 -0.048309326171875 +40649 -0.84619140625 +40650 -0.056182861328125 +40651 -0.861297607421875 +40652 -0.060699462890625 +40653 -0.863250732421875 +40654 -0.0601806640625 +40655 -0.856597900390625 +40656 -0.055419921875 +40657 -0.7498779296875 +40658 -0.04974365234375 +40659 -0.624542236328125 +40660 -0.042022705078125 +40661 -0.47808837890625 +40662 -0.029052734375 +40663 -0.253387451171875 +40664 -0.013458251953125 +40665 0.003692626953125 +40666 0.000885009765625 +40667 0.2257080078125 +40668 0.014678955078125 +40669 0.427154541015625 +40670 0.029693603515625 +40671 0.643218994140625 +40672 0.04541015625 +40673 0.855926513671875 +40674 0.05865478515625 +40675 0.870361328125 +40676 0.06671142578125 +40677 0.870361328125 +40678 0.070068359375 +40679 0.862762451171875 +40680 0.068634033203125 +40681 0.79669189453125 +40682 0.06195068359375 +40683 0.595794677734375 +40684 0.0517578125 +40685 0.362152099609375 +40686 0.039703369140625 +40687 0.1270751953125 +40688 0.027008056640625 +40689 -0.086944580078125 +40690 0.01385498046875 +40691 -0.2784423828125 +40692 -0.001617431640625 +40693 -0.484832763671875 +40694 -0.020477294921875 +40695 -0.729583740234375 +40696 -0.0399169921875 +40697 -0.86688232421875 +40698 -0.056396484375 +40699 -0.870391845703125 +40700 -0.06964111328125 +40701 -0.86859130859375 +40702 -0.07958984375 +40703 -0.86279296875 +40704 -0.084381103515625 +40705 -0.817962646484375 +40706 -0.081207275390625 +40707 -0.6116943359375 +40708 -0.069488525390625 +40709 -0.3128662109375 +40710 -0.051361083984375 +40711 0.039398193359375 +40712 -0.0277099609375 +40713 0.422821044921875 +40714 -0.000640869140625 +40715 0.805145263671875 +40716 0.024688720703125 +40717 0.870361328125 +40718 0.044036865234375 +40719 0.870361328125 +40720 0.057037353515625 +40721 0.860015869140625 +40722 0.0635986328125 +40723 0.727935791015625 +40724 0.06365966796875 +40725 0.48114013671875 +40726 0.05963134765625 +40727 0.2059326171875 +40728 0.053680419921875 +40729 -0.06103515625 +40730 0.04669189453125 +40731 -0.29913330078125 +40732 0.03729248046875 +40733 -0.516204833984375 +40734 0.02392578125 +40735 -0.7252197265625 +40736 0.00848388671875 +40737 -0.85980224609375 +40738 -0.00640869140625 +40739 -0.870391845703125 +40740 -0.0185546875 +40741 -0.870391845703125 +40742 -0.024169921875 +40743 -0.858062744140625 +40744 -0.023345947265625 +40745 -0.673004150390625 +40746 -0.021148681640625 +40747 -0.42694091796875 +40748 -0.0218505859375 +40749 -0.2100830078125 +40750 -0.02557373046875 +40751 -0.0362548828125 +40752 -0.029998779296875 +40753 0.10943603515625 +40754 -0.033447265625 +40755 0.23516845703125 +40756 -0.0323486328125 +40757 0.373687744140625 +40758 -0.02685546875 +40759 0.517791748046875 +40760 -0.022369384765625 +40761 0.602783203125 +40762 -0.01824951171875 +40763 0.635711669921875 +40764 -0.01129150390625 +40765 0.655181884765625 +40766 -0.00201416015625 +40767 0.65948486328125 +40768 0.009185791015625 +40769 0.651275634765625 +40770 0.020477294921875 +40771 0.61846923828125 +40772 0.0289306640625 +40773 0.53753662109375 +40774 0.033294677734375 +40775 0.404144287109375 +40776 0.03302001953125 +40777 0.22186279296875 +40778 0.0284423828125 +40779 0.003997802734375 +40780 0.021331787109375 +40781 -0.22100830078125 +40782 0.013519287109375 +40783 -0.42449951171875 +40784 0.00689697265625 +40785 -0.579833984375 +40786 0.005126953125 +40787 -0.641876220703125 +40788 0.0074462890625 +40789 -0.6177978515625 +40790 0.00799560546875 +40791 -0.575531005859375 +40792 0.00604248046875 +40793 -0.526336669921875 +40794 0.005859375 +40795 -0.42645263671875 +40796 0.009552001953125 +40797 -0.2581787109375 +40798 0.013641357421875 +40799 -0.068695068359375 +40800 0.014495849609375 +40801 0.09222412109375 +40802 0.013519287109375 +40803 0.232147216796875 +40804 0.011444091796875 +40805 0.3509521484375 +40806 0.00555419921875 +40807 0.410064697265625 +40808 -0.00677490234375 +40809 0.372955322265625 +40810 -0.023712158203125 +40811 0.2554931640625 +40812 -0.040618896484375 +40813 0.10711669921875 +40814 -0.055633544921875 +40815 -0.052886962890625 +40816 -0.065460205078125 +40817 -0.186279296875 +40818 -0.06500244140625 +40819 -0.23291015625 +40820 -0.0560302734375 +40821 -0.209442138671875 +40822 -0.04412841796875 +40823 -0.174163818359375 +40824 -0.029815673828125 +40825 -0.126739501953125 +40826 -0.01202392578125 +40827 -0.048126220703125 +40828 0.0069580078125 +40829 0.0426025390625 +40830 0.023162841796875 +40831 0.10748291015625 +40832 0.0355224609375 +40833 0.1409912109375 +40834 0.04827880859375 +40835 0.19708251953125 +40836 0.0609130859375 +40837 0.273651123046875 +40838 0.068511962890625 +40839 0.31768798828125 +40840 0.071990966796875 +40841 0.341094970703125 +40842 0.073455810546875 +40843 0.368011474609375 +40844 0.07073974609375 +40845 0.37249755859375 +40846 0.059356689453125 +40847 0.30072021484375 +40848 0.039520263671875 +40849 0.1517333984375 +40850 0.01690673828125 +40851 -0.01470947265625 +40852 -0.007080078125 +40853 -0.1883544921875 +40854 -0.032257080078125 +40855 -0.372711181640625 +40856 -0.053375244140625 +40857 -0.51397705078125 +40858 -0.06640625 +40859 -0.57177734375 +40860 -0.07037353515625 +40861 -0.53948974609375 +40862 -0.0665283203125 +40863 -0.43511962890625 +40864 -0.05792236328125 +40865 -0.2962646484375 +40866 -0.047760009765625 +40867 -0.161102294921875 +40868 -0.0372314453125 +40869 -0.0435791015625 +40870 -0.026031494140625 +40871 0.060394287109375 +40872 -0.01556396484375 +40873 0.13665771484375 +40874 -0.007415771484375 +40875 0.170135498046875 +40876 -0.00152587890625 +40877 0.16552734375 +40878 0.0047607421875 +40879 0.15728759765625 +40880 0.011505126953125 +40881 0.150787353515625 +40882 0.016143798828125 +40883 0.12200927734375 +40884 0.01910400390625 +40885 0.080108642578125 +40886 0.022369384765625 +40887 0.05126953125 +40888 0.028045654296875 +40889 0.062896728515625 +40890 0.033966064453125 +40891 0.09271240234375 +40892 0.035797119140625 +40893 0.092987060546875 +40894 0.0347900390625 +40895 0.07855224609375 +40896 0.032257080078125 +40897 0.06427001953125 +40898 0.0269775390625 +40899 0.0347900390625 +40900 0.018951416015625 +40901 -0.01171875 +40902 0.010162353515625 +40903 -0.056060791015625 +40904 0.004638671875 +40905 -0.055511474609375 +40906 0.002655029296875 +40907 -0.010467529296875 +40908 -0.000152587890625 +40909 0.02508544921875 +40910 -0.005706787109375 +40911 0.025665283203125 +40912 -0.01141357421875 +40913 0.017333984375 +40914 -0.016876220703125 +40915 0.00189208984375 +40916 -0.022857666015625 +40917 -0.03173828125 +40918 -0.028167724609375 +40919 -0.071502685546875 +40920 -0.034332275390625 +40921 -0.13543701171875 +40922 -0.041015625 +40923 -0.219970703125 +40924 -0.046142578125 +40925 -0.300506591796875 +40926 -0.0498046875 +40927 -0.376312255859375 +40928 -0.0494384765625 +40929 -0.416107177734375 +40930 -0.041015625 +40931 -0.371124267578125 +40932 -0.024871826171875 +40933 -0.242279052734375 +40934 -0.00482177734375 +40935 -0.069732666015625 +40936 0.01702880859375 +40937 0.125640869140625 +40938 0.037689208984375 +40939 0.31268310546875 +40940 0.0537109375 +40941 0.45501708984375 +40942 0.06512451171875 +40943 0.554779052734375 +40944 0.07171630859375 +40945 0.61065673828125 +40946 0.072357177734375 +40947 0.610931396484375 +40948 0.06494140625 +40949 0.531463623046875 +40950 0.05096435546875 +40951 0.3883056640625 +40952 0.03521728515625 +40953 0.23468017578125 +40954 0.02001953125 +40955 0.095245361328125 +40956 0.0078125 +40957 -0.00396728515625 +40958 3.0517578125e-05 +40959 -0.04852294921875 +40960 -0.004302978515625 +40961 -0.055145263671875 +40962 -0.009674072265625 +40963 -0.0758056640625 +40964 -0.018646240234375 +40965 -0.138702392578125 +40966 -0.027740478515625 +40967 -0.209197998046875 +40968 -0.037139892578125 +40969 -0.289031982421875 +40970 -0.04693603515625 +40971 -0.37884521484375 +40972 -0.054931640625 +40973 -0.456329345703125 +40974 -0.060638427734375 +40975 -0.51641845703125 +40976 -0.060150146484375 +40977 -0.519287109375 +40978 -0.0528564453125 +40979 -0.458251953125 +40980 -0.043975830078125 +40981 -0.384796142578125 +40982 -0.036102294921875 +40983 -0.323699951171875 +40984 -0.028717041015625 +40985 -0.269287109375 +40986 -0.019317626953125 +40987 -0.1951904296875 +40988 -0.00787353515625 +40989 -0.100006103515625 +40990 0.0028076171875 +40991 -0.01055908203125 +40992 0.015625 +40993 0.1033935546875 +40994 0.03125 +40995 0.24908447265625 +40996 0.044342041015625 +40997 0.373199462890625 +40998 0.0531005859375 +40999 0.45806884765625 +41000 0.05828857421875 +41001 0.511474609375 +41002 0.063140869140625 +41003 0.565399169921875 +41004 0.06683349609375 +41005 0.61138916015625 +41006 0.0634765625 +41007 0.5897216796875 +41008 0.052154541015625 +41009 0.4906005859375 +41010 0.034698486328125 +41011 0.33148193359375 +41012 0.0147705078125 +41013 0.147796630859375 +41014 -0.00335693359375 +41015 -0.01873779296875 +41016 -0.016845703125 +41017 -0.140289306640625 +41018 -0.02313232421875 +41019 -0.191986083984375 +41020 -0.023223876953125 +41021 -0.184295654296875 +41022 -0.021514892578125 +41023 -0.161834716796875 +41024 -0.022216796875 +41025 -0.166595458984375 +41026 -0.02484130859375 +41027 -0.19390869140625 +41028 -0.0274658203125 +41029 -0.22442626953125 +41030 -0.03228759765625 +41031 -0.279754638671875 +41032 -0.037261962890625 +41033 -0.3389892578125 +41034 -0.03765869140625 +41035 -0.3543701171875 +41036 -0.035797119140625 +41037 -0.348175048828125 +41038 -0.032318115234375 +41039 -0.32598876953125 +41040 -0.0242919921875 +41041 -0.2581787109375 +41042 -0.01129150390625 +41043 -0.139801025390625 +41044 0.005126953125 +41045 0.014617919921875 +41046 0.018829345703125 +41047 0.144378662109375 +41048 0.026947021484375 +41049 0.221038818359375 +41050 0.032073974609375 +41051 0.27069091796875 +41052 0.034271240234375 +41053 0.294036865234375 +41054 0.03564453125 +41055 0.311767578125 +41056 0.037811279296875 +41057 0.339141845703125 +41058 0.03948974609375 +41059 0.360260009765625 +41060 0.0391845703125 +41061 0.360504150390625 +41062 0.03302001953125 +41063 0.308380126953125 +41064 0.018218994140625 +41065 0.18170166015625 +41066 -0.002288818359375 +41067 0.0047607421875 +41068 -0.02301025390625 +41069 -0.17559814453125 +41070 -0.038604736328125 +41071 -0.3143310546875 +41072 -0.043975830078125 +41073 -0.36785888671875 +41074 -0.042327880859375 +41075 -0.36248779296875 +41076 -0.039154052734375 +41077 -0.343536376953125 +41078 -0.033416748046875 +41079 -0.3018798828125 +41080 -0.0244140625 +41081 -0.231414794921875 +41082 -0.01043701171875 +41083 -0.117645263671875 +41084 0.004608154296875 +41085 0.007049560546875 +41086 0.01416015625 +41087 0.087982177734375 +41088 0.01995849609375 +41089 0.13946533203125 +41090 0.023590087890625 +41091 0.17425537109375 +41092 0.02459716796875 +41093 0.188201904296875 +41094 0.02178955078125 +41095 0.171234130859375 +41096 0.0146484375 +41097 0.118438720703125 +41098 0.00653076171875 +41099 0.05706787109375 +41100 -0.00225830078125 +41101 -0.010711669921875 +41102 -0.012481689453125 +41103 -0.0914306640625 +41104 -0.021392822265625 +41105 -0.162322998046875 +41106 -0.025543212890625 +41107 -0.194549560546875 +41108 -0.020233154296875 +41109 -0.1492919921875 +41110 -0.0048828125 +41111 -0.02166748046875 +41112 0.01275634765625 +41113 0.124053955078125 +41114 0.0234375 +41115 0.211151123046875 +41116 0.027252197265625 +41117 0.240447998046875 +41118 0.02783203125 +41119 0.242218017578125 +41120 0.026275634765625 +41121 0.2257080078125 +41122 0.022979736328125 +41123 0.194366455078125 +41124 0.01397705078125 +41125 0.115509033203125 +41126 0.00213623046875 +41127 0.0128173828125 +41128 -0.00537109375 +41129 -0.053802490234375 +41130 -0.011749267578125 +41131 -0.110626220703125 +41132 -0.02203369140625 +41133 -0.199493408203125 +41134 -0.03314208984375 +41135 -0.29437255859375 +41136 -0.037506103515625 +41137 -0.33221435546875 +41138 -0.031158447265625 +41139 -0.27972412109375 +41140 -0.0198974609375 +41141 -0.185333251953125 +41142 -0.013214111328125 +41143 -0.128204345703125 +41144 -0.011962890625 +41145 -0.115692138671875 +41146 -0.01239013671875 +41147 -0.116455078125 +41148 -0.011505126953125 +41149 -0.105926513671875 +41150 -0.00567626953125 +41151 -0.053955078125 +41152 0.0062255859375 +41153 0.048797607421875 +41154 0.018798828125 +41155 0.157318115234375 +41156 0.02490234375 +41157 0.212005615234375 +41158 0.0252685546875 +41159 0.218475341796875 +41160 0.027191162109375 +41161 0.23724365234375 +41162 0.035125732421875 +41163 0.30535888671875 +41164 0.044097900390625 +41165 0.38128662109375 +41166 0.046783447265625 +41167 0.404449462890625 +41168 0.045562744140625 +41169 0.3944091796875 +41170 0.044952392578125 +41171 0.3885498046875 +41172 0.042022705078125 +41173 0.362640380859375 +41174 0.0316162109375 +41175 0.27362060546875 +41176 0.01318359375 +41177 0.11712646484375 +41178 -0.007049560546875 +41179 -0.054901123046875 +41180 -0.022918701171875 +41181 -0.19085693359375 +41182 -0.033843994140625 +41183 -0.28570556640625 +41184 -0.039825439453125 +41185 -0.339263916015625 +41186 -0.04400634765625 +41187 -0.3775634765625 +41188 -0.05181884765625 +41189 -0.445709228515625 +41190 -0.062255859375 +41191 -0.535064697265625 +41192 -0.073333740234375 +41193 -0.629058837890625 +41194 -0.0814208984375 +41195 -0.697601318359375 +41196 -0.082122802734375 +41197 -0.70391845703125 +41198 -0.074798583984375 +41199 -0.6424560546875 +41200 -0.05682373046875 +41201 -0.491241455078125 +41202 -0.029998779296875 +41203 -0.265716552734375 +41204 -0.00128173828125 +41205 -0.023712158203125 +41206 0.025360107421875 +41207 0.201751708984375 +41208 0.045745849609375 +41209 0.375823974609375 +41210 0.058349609375 +41211 0.485076904296875 +41212 0.06787109375 +41213 0.56884765625 +41214 0.075286865234375 +41215 0.634765625 +41216 0.07470703125 +41217 0.63763427734375 +41218 0.064056396484375 +41219 0.5660400390625 +41220 0.0506591796875 +41221 0.4720458984375 +41222 0.04241943359375 +41223 0.40692138671875 +41224 0.04046630859375 +41225 0.3778076171875 +41226 0.043548583984375 +41227 0.376953125 +41228 0.046630859375 +41229 0.371978759765625 +41230 0.0419921875 +41231 0.313140869140625 +41232 0.026947021484375 +41233 0.184417724609375 +41234 0.005126953125 +41235 0.011199951171875 +41236 -0.01824951171875 +41237 -0.171051025390625 +41238 -0.039642333984375 +41239 -0.33740234375 +41240 -0.056854248046875 +41241 -0.47198486328125 +41242 -0.06787109375 +41243 -0.560394287109375 +41244 -0.0694580078125 +41245 -0.58056640625 +41246 -0.06396484375 +41247 -0.54754638671875 +41248 -0.058624267578125 +41249 -0.508575439453125 +41250 -0.052703857421875 +41251 -0.459503173828125 +41252 -0.045196533203125 +41253 -0.394378662109375 +41254 -0.041900634765625 +41255 -0.35260009765625 +41256 -0.039276123046875 +41257 -0.31170654296875 +41258 -0.02581787109375 +41259 -0.197418212890625 +41260 -0.001007080078125 +41261 -0.007965087890625 +41262 0.02783203125 +41263 0.207489013671875 +41264 0.054901123046875 +41265 0.409210205078125 +41266 0.0765380859375 +41267 0.57208251953125 +41268 0.088348388671875 +41269 0.66595458984375 +41270 0.0855712890625 +41271 0.65875244140625 +41272 0.07086181640625 +41273 0.56744384765625 +41274 0.05023193359375 +41275 0.431396484375 +41276 0.030303955078125 +41277 0.29443359375 +41278 0.014923095703125 +41279 0.182464599609375 +41280 -0.00079345703125 +41281 0.06365966796875 +41282 -0.019134521484375 +41283 -0.075958251953125 +41284 -0.03314208984375 +41285 -0.189422607421875 +41286 -0.042266845703125 +41287 -0.271942138671875 +41288 -0.049591064453125 +41289 -0.342529296875 +41290 -0.049713134765625 +41291 -0.364166259765625 +41292 -0.04132080078125 +41293 -0.327239990234375 +41294 -0.03143310546875 +41295 -0.2769775390625 +41296 -0.026275634765625 +41297 -0.253692626953125 +41298 -0.0238037109375 +41299 -0.24365234375 +41300 -0.016693115234375 +41301 -0.1983642578125 +41302 -0.00469970703125 +41303 -0.116241455078125 +41304 0.00616455078125 +41305 -0.036834716796875 +41306 0.0152587890625 +41307 0.034881591796875 +41308 0.02154541015625 +41309 0.09124755859375 +41310 0.021575927734375 +41311 0.10888671875 +41312 0.021270751953125 +41313 0.125518798828125 +41314 0.0233154296875 +41315 0.15771484375 +41316 0.023712158203125 +41317 0.17828369140625 +41318 0.0201416015625 +41319 0.17108154296875 +41320 0.011810302734375 +41321 0.129974365234375 +41322 0.00299072265625 +41323 0.082427978515625 +41324 -0.00628662109375 +41325 0.027679443359375 +41326 -0.020782470703125 +41327 -0.065643310546875 +41328 -0.034698486328125 +41329 -0.15936279296875 +41330 -0.04193115234375 +41331 -0.21307373046875 +41332 -0.04376220703125 +41333 -0.234649658203125 +41334 -0.036651611328125 +41335 -0.2001953125 +41336 -0.02215576171875 +41337 -0.119171142578125 +41338 -0.00543212890625 +41339 -0.024749755859375 +41340 0.01373291015625 +41341 0.085784912109375 +41342 0.029998779296875 +41343 0.178131103515625 +41344 0.037689208984375 +41345 0.215576171875 +41346 0.038726806640625 +41347 0.211456298828125 +41348 0.034515380859375 +41349 0.17523193359375 +41350 0.0283203125 +41351 0.128753662109375 +41352 0.024627685546875 +41353 0.1019287109375 +41354 0.02032470703125 +41355 0.0743408203125 +41356 0.0150146484375 +41357 0.04327392578125 +41358 0.01318359375 +41359 0.038177490234375 +41360 0.017547607421875 +41361 0.076263427734375 +41362 0.025665283203125 +41363 0.14105224609375 +41364 0.0306396484375 +41365 0.186431884765625 +41366 0.02899169921875 +41367 0.188812255859375 +41368 0.01947021484375 +41369 0.1390380859375 +41370 0.00286865234375 +41371 0.041778564453125 +41372 -0.01708984375 +41373 -0.079437255859375 +41374 -0.03955078125 +41375 -0.219390869140625 +41376 -0.062896728515625 +41377 -0.367828369140625 +41378 -0.08251953125 +41379 -0.494873046875 +41380 -0.091705322265625 +41381 -0.556243896484375 +41382 -0.083953857421875 +41383 -0.508697509765625 +41384 -0.062835693359375 +41385 -0.3756103515625 +41386 -0.037841796875 +41387 -0.218902587890625 +41388 -0.012847900390625 +41389 -0.063751220703125 +41390 0.01226806640625 +41391 0.091552734375 +41392 0.0357666015625 +41393 0.23602294921875 +41394 0.05352783203125 +41395 0.342987060546875 +41396 0.062835693359375 +41397 0.39520263671875 +41398 0.063140869140625 +41399 0.389373779296875 +41400 0.054168701171875 +41401 0.324249267578125 +41402 0.039581298828125 +41403 0.224090576171875 +41404 0.024749755859375 +41405 0.124267578125 +41406 0.011505126953125 +41407 0.037078857421875 +41408 0.0040283203125 +41409 -0.010101318359375 +41410 0.00201416015625 +41411 -0.019439697265625 +41412 0.000640869140625 +41413 -0.022796630859375 +41414 0.0028076171875 +41415 -0.001556396484375 +41416 0.0103759765625 +41417 0.056304931640625 +41418 0.016754150390625 +41419 0.106719970703125 +41420 0.01397705078125 +41421 0.096893310546875 +41422 0.0045166015625 +41423 0.042694091796875 +41424 -0.005767822265625 +41425 -0.018035888671875 +41426 -0.015380859375 +41427 -0.07586669921875 +41428 -0.022552490234375 +41429 -0.11944580078125 +41430 -0.0289306640625 +41431 -0.15972900390625 +41432 -0.035430908203125 +41433 -0.202606201171875 +41434 -0.042083740234375 +41435 -0.24859619140625 +41436 -0.050079345703125 +41437 -0.30517578125 +41438 -0.057891845703125 +41439 -0.36212158203125 +41440 -0.06134033203125 +41441 -0.39141845703125 +41442 -0.05474853515625 +41443 -0.35528564453125 +41444 -0.037628173828125 +41445 -0.249969482421875 +41446 -0.012664794921875 +41447 -0.092864990234375 +41448 0.015960693359375 +41449 0.08905029296875 +41450 0.03900146484375 +41451 0.2352294921875 +41452 0.05230712890625 +41453 0.318817138671875 +41454 0.058746337890625 +41455 0.358642578125 +41456 0.057220458984375 +41457 0.347747802734375 +41458 0.04766845703125 +41459 0.28564453125 +41460 0.037841796875 +41461 0.223175048828125 +41462 0.033294677734375 +41463 0.196746826171875 +41464 0.030029296875 +41465 0.179840087890625 +41466 0.025482177734375 +41467 0.155548095703125 +41468 0.023895263671875 +41469 0.151214599609375 +41470 0.0238037109375 +41471 0.156951904296875 +41472 0.018890380859375 +41473 0.13177490234375 +41474 0.013458251953125 +41475 0.100799560546875 +41476 0.011260986328125 +41477 0.087127685546875 +41478 0.005828857421875 +41479 0.05487060546875 +41480 -0.005126953125 +41481 -0.009002685546875 +41482 -0.021514892578125 +41483 -0.10400390625 +41484 -0.043243408203125 +41485 -0.229400634765625 +41486 -0.064910888671875 +41487 -0.35552978515625 +41488 -0.07916259765625 +41489 -0.441925048828125 +41490 -0.083404541015625 +41491 -0.473846435546875 +41492 -0.080230712890625 +41493 -0.464813232421875 +41494 -0.070526123046875 +41495 -0.419097900390625 +41496 -0.053924560546875 +41497 -0.334320068359375 +41498 -0.033721923828125 +41499 -0.227935791015625 +41500 -0.0142822265625 +41501 -0.12347412109375 +41502 0.00311279296875 +41503 -0.02764892578125 +41504 0.021820068359375 +41505 0.077667236328125 +41506 0.045684814453125 +41507 0.2132568359375 +41508 0.076568603515625 +41509 0.38885498046875 +41510 0.110565185546875 +41511 0.582794189453125 +41512 0.136566162109375 +41513 0.734039306640625 +41514 0.1468505859375 +41515 0.800140380859375 +41516 0.1409912109375 +41517 0.7783203125 +41518 0.118499755859375 +41519 0.6651611328125 +41520 0.07928466796875 +41521 0.45965576171875 +41522 0.03033447265625 +41523 0.199188232421875 +41524 -0.0162353515625 +41525 -0.050689697265625 +41526 -0.049957275390625 +41527 -0.23297119140625 +41528 -0.067626953125 +41529 -0.33013916015625 +41530 -0.074066162109375 +41531 -0.368408203125 +41532 -0.075042724609375 +41533 -0.378936767578125 +41534 -0.073486328125 +41535 -0.376983642578125 +41536 -0.072601318359375 +41537 -0.37969970703125 +41538 -0.0732421875 +41539 -0.391510009765625 +41540 -0.070526123046875 +41541 -0.385345458984375 +41542 -0.06097412109375 +41543 -0.3419189453125 +41544 -0.048675537109375 +41545 -0.28289794921875 +41546 -0.04168701171875 +41547 -0.251617431640625 +41548 -0.04339599609375 +41549 -0.266143798828125 +41550 -0.0440673828125 +41551 -0.273345947265625 +41552 -0.0333251953125 +41553 -0.216796875 +41554 -0.01702880859375 +41555 -0.128265380859375 +41556 -0.006256103515625 +41557 -0.068145751953125 +41558 -0.002227783203125 +41559 -0.0430908203125 +41560 0.000335693359375 +41561 -0.024444580078125 +41562 0.007568359375 +41563 0.020721435546875 +41564 0.025390625 +41565 0.124481201171875 +41566 0.048553466796875 +41567 0.25787353515625 +41568 0.0694580078125 +41569 0.379119873046875 +41570 0.086669921875 +41571 0.47991943359375 +41572 0.094329833984375 +41573 0.5281982421875 +41574 0.09014892578125 +41575 0.511138916015625 +41576 0.079254150390625 +41577 0.456207275390625 +41578 0.069793701171875 +41579 0.407470703125 +41580 0.065216064453125 +41581 0.383758544921875 +41582 0.060333251953125 +41583 0.35687255859375 +41584 0.052398681640625 +41585 0.31182861328125 +41586 0.041778564453125 +41587 0.250885009765625 +41588 0.026885986328125 +41589 0.1654052734375 +41590 0.00396728515625 +41591 0.035247802734375 +41592 -0.027496337890625 +41593 -0.142059326171875 +41594 -0.0618896484375 +41595 -0.33563232421875 +41596 -0.097259521484375 +41597 -0.5345458984375 +41598 -0.13055419921875 +41599 -0.72186279296875 +41600 -0.150604248046875 +41601 -0.836669921875 +41602 -0.148956298828125 +41603 -0.8326416015625 +41604 -0.12933349609375 +41605 -0.7296142578125 +41606 -0.101898193359375 +41607 -0.582550048828125 +41608 -0.075592041015625 +41609 -0.440093994140625 +41610 -0.054473876953125 +41611 -0.324310302734375 +41612 -0.03228759765625 +41613 -0.20147705078125 +41614 -0.004058837890625 +41615 -0.044647216796875 +41616 0.022491455078125 +41617 0.103973388671875 +41618 0.039642333984375 +41619 0.202392578125 +41620 0.050018310546875 +41621 0.264495849609375 +41622 0.0626220703125 +41623 0.338897705078125 +41624 0.080841064453125 +41625 0.443817138671875 +41626 0.09844970703125 +41627 0.545074462890625 +41628 0.11083984375 +41629 0.6173095703125 +41630 0.1165771484375 +41631 0.6524658203125 +41632 0.1180419921875 +41633 0.66339111328125 +41634 0.11639404296875 +41635 0.6561279296875 +41636 0.107208251953125 +41637 0.606781005859375 +41638 0.087890625 +41639 0.501190185546875 +41640 0.0609130859375 +41641 0.352783203125 +41642 0.029022216796875 +41643 0.176544189453125 +41644 -0.009124755859375 +41645 -0.034820556640625 +41646 -0.049285888671875 +41647 -0.258209228515625 +41648 -0.082122802734375 +41649 -0.44244384765625 +41650 -0.105438232421875 +41651 -0.5753173828125 +41652 -0.118438720703125 +41653 -0.65203857421875 +41654 -0.115478515625 +41655 -0.641632080078125 +41656 -0.0999755859375 +41657 -0.562164306640625 +41658 -0.08013916015625 +41659 -0.458038330078125 +41660 -0.059906005859375 +41661 -0.350555419921875 +41662 -0.043121337890625 +41663 -0.260528564453125 +41664 -0.030548095703125 +41665 -0.192108154296875 +41666 -0.021575927734375 +41667 -0.141937255859375 +41668 -0.01470947265625 +41669 -0.1021728515625 +41670 -0.00811767578125 +41671 -0.062896728515625 +41672 0.000457763671875 +41673 -0.011932373046875 +41674 0.0133056640625 +41675 0.062835693359375 +41676 0.02813720703125 +41677 0.148712158203125 +41678 0.044281005859375 +41679 0.241729736328125 +41680 0.063079833984375 +41681 0.34912109375 +41682 0.082122802734375 +41683 0.457305908203125 +41684 0.097320556640625 +41685 0.54388427734375 +41686 0.10211181640625 +41687 0.5728759765625 +41688 0.089569091796875 +41689 0.506591796875 +41690 0.06085205078125 +41691 0.351226806640625 +41692 0.02325439453125 +41693 0.146514892578125 +41694 -0.013580322265625 +41695 -0.05523681640625 +41696 -0.042724609375 +41697 -0.21624755859375 +41698 -0.06390380859375 +41699 -0.334930419921875 +41700 -0.07562255859375 +41701 -0.402984619140625 +41702 -0.081787109375 +41703 -0.4412841796875 +41704 -0.09088134765625 +41705 -0.49578857421875 +41706 -0.101806640625 +41707 -0.5601806640625 +41708 -0.1083984375 +41709 -0.600738525390625 +41710 -0.1046142578125 +41711 -0.584228515625 +41712 -0.084747314453125 +41713 -0.47930908203125 +41714 -0.047576904296875 +41715 -0.27935791015625 +41716 0.0023193359375 +41717 -0.0089111328125 +41718 0.053314208984375 +41719 0.268798828125 +41720 0.09234619140625 +41721 0.482818603515625 +41722 0.114044189453125 +41723 0.60369873046875 +41724 0.121917724609375 +41725 0.650421142578125 +41726 0.12359619140625 +41727 0.66400146484375 +41728 0.11834716796875 +41729 0.6414794921875 +41730 0.104400634765625 +41731 0.572540283203125 +41732 0.09051513671875 +41733 0.498138427734375 +41734 0.08099365234375 +41735 0.439453125 +41736 0.071044921875 +41737 0.375518798828125 +41738 0.05352783203125 +41739 0.274505615234375 +41740 0.022186279296875 +41741 0.1087646484375 +41742 -0.018402099609375 +41743 -0.099395751953125 +41744 -0.061614990234375 +41745 -0.3182373046875 +41746 -0.107940673828125 +41747 -0.5489501953125 +41748 -0.1536865234375 +41749 -0.7738037109375 +41750 -0.187530517578125 +41751 -0.86383056640625 +41752 -0.202362060546875 +41753 -0.870391845703125 +41754 -0.20208740234375 +41755 -0.86895751953125 +41756 -0.189483642578125 +41757 -0.861053466796875 +41758 -0.1607666015625 +41759 -0.765869140625 +41760 -0.1134033203125 +41761 -0.5301513671875 +41762 -0.04876708984375 +41763 -0.214691162109375 +41764 0.02398681640625 +41765 0.137359619140625 +41766 0.093994140625 +41767 0.474822998046875 +41768 0.15374755859375 +41769 0.76239013671875 +41770 0.197662353515625 +41771 0.867462158203125 +41772 0.225982666015625 +41773 0.870361328125 +41774 0.236358642578125 +41775 0.86480712890625 +41776 0.230072021484375 +41777 0.831817626953125 +41778 0.212493896484375 +41779 0.677581787109375 +41780 0.184906005859375 +41781 0.495880126953125 +41782 0.1513671875 +41783 0.30767822265625 +41784 0.1123046875 +41785 0.116180419921875 +41786 0.060760498046875 +41787 -0.110748291015625 +41788 -0.00482177734375 +41789 -0.381805419921875 +41790 -0.075347900390625 +41791 -0.6572265625 +41792 -0.138031005859375 +41793 -0.857421875 +41794 -0.18377685546875 +41795 -0.870391845703125 +41796 -0.211212158203125 +41797 -0.870391845703125 +41798 -0.226318359375 +41799 -0.86444091796875 +41800 -0.2369384765625 +41801 -0.85723876953125 +41802 -0.239227294921875 +41803 -0.790008544921875 +41804 -0.2215576171875 +41805 -0.62847900390625 +41806 -0.183258056640625 +41807 -0.3956298828125 +41808 -0.1314697265625 +41809 -0.126708984375 +41810 -0.072113037109375 +41811 0.150115966796875 +41812 -0.00762939453125 +41813 0.424041748046875 +41814 0.056182861328125 +41815 0.670623779296875 +41816 0.111083984375 +41817 0.854522705078125 +41818 0.15338134765625 +41819 0.866485595703125 +41820 0.17987060546875 +41821 0.86920166015625 +41822 0.19464111328125 +41823 0.8653564453125 +41824 0.200714111328125 +41825 0.857147216796875 +41826 0.19757080078125 +41827 0.766845703125 +41828 0.18646240234375 +41829 0.628509521484375 +41830 0.165985107421875 +41831 0.462127685546875 +41832 0.141754150390625 +41833 0.297210693359375 +41834 0.116455078125 +41835 0.14862060546875 +41836 0.085174560546875 +41837 -0.00537109375 +41838 0.049530029296875 +41839 -0.15753173828125 +41840 0.0086669921875 +41841 -0.31304931640625 +41842 -0.040496826171875 +41843 -0.48876953125 +41844 -0.087921142578125 +41845 -0.6416015625 +41846 -0.12835693359375 +41847 -0.751373291015625 +41848 -0.16693115234375 +41849 -0.84619140625 +41850 -0.2005615234375 +41851 -0.861297607421875 +41852 -0.22216796875 +41853 -0.863250732421875 +41854 -0.22503662109375 +41855 -0.856597900390625 +41856 -0.211883544921875 +41857 -0.7498779296875 +41858 -0.195281982421875 +41859 -0.624542236328125 +41860 -0.170501708984375 +41861 -0.47808837890625 +41862 -0.124908447265625 +41863 -0.253387451171875 +41864 -0.068389892578125 +41865 0.003692626953125 +41866 -0.015655517578125 +41867 0.2257080078125 +41868 0.0360107421875 +41869 0.427154541015625 +41870 0.093658447265625 +41871 0.643218994140625 +41872 0.1552734375 +41873 0.855926513671875 +41874 0.20843505859375 +41875 0.870361328125 +41876 0.24249267578125 +41877 0.870361328125 +41878 0.25909423828125 +41879 0.862762451171875 +41880 0.257720947265625 +41881 0.79669189453125 +41882 0.236419677734375 +41883 0.595794677734375 +41884 0.2015380859375 +41885 0.362152099609375 +41886 0.1591796875 +41887 0.1270751953125 +41888 0.11395263671875 +41889 -0.086944580078125 +41890 0.066314697265625 +41891 -0.2784423828125 +41892 0.008758544921875 +41893 -0.484832763671875 +41894 -0.0628662109375 +41895 -0.729583740234375 +41896 -0.137664794921875 +41897 -0.86688232421875 +41898 -0.201995849609375 +41899 -0.870391845703125 +41900 -0.254852294921875 +41901 -0.86859130859375 +41902 -0.295867919921875 +41903 -0.86279296875 +41904 -0.317352294921875 +41905 -0.817962646484375 +41906 -0.3095703125 +41907 -0.6116943359375 +41908 -0.27105712890625 +41909 -0.3128662109375 +41910 -0.209136962890625 +41911 0.039398193359375 +41912 -0.128204345703125 +41913 0.422821044921875 +41914 -0.035491943359375 +41915 0.805145263671875 +41916 0.054229736328125 +41917 0.870361328125 +41918 0.128662109375 +41919 0.870361328125 +41920 0.18524169921875 +41921 0.860015869140625 +41922 0.222320556640625 +41923 0.727935791015625 +41924 0.238677978515625 +41925 0.48114013671875 +41926 0.239532470703125 +41927 0.2059326171875 +41928 0.22979736328125 +41929 -0.06103515625 +41930 0.211669921875 +41931 -0.29913330078125 +41932 0.18206787109375 +41933 -0.516204833984375 +41934 0.137725830078125 +41935 -0.7252197265625 +41936 0.0841064453125 +41937 -0.85980224609375 +41938 0.028656005859375 +41939 -0.870391845703125 +41940 -0.0220947265625 +41941 -0.870391845703125 +41942 -0.05755615234375 +41943 -0.858062744140625 +41944 -0.07672119140625 +41945 -0.673004150390625 +41946 -0.090850830078125 +41947 -0.42694091796875 +41948 -0.109405517578125 +41949 -0.2100830078125 +41950 -0.131866455078125 +41951 -0.0362548828125 +41952 -0.151885986328125 +41953 0.10943603515625 +41954 -0.165130615234375 +41955 0.23516845703125 +41956 -0.16265869140625 +41957 0.373687744140625 +41958 -0.1448974609375 +41959 0.517791748046875 +41960 -0.125457763671875 +41961 0.602783203125 +41962 -0.10333251953125 +41963 0.635711669921875 +41964 -0.0714111328125 +41965 0.655181884765625 +41966 -0.031951904296875 +41967 0.65948486328125 +41968 0.01318359375 +41969 0.651275634765625 +41970 0.058624267578125 +41971 0.61846923828125 +41972 0.096221923828125 +41973 0.53753662109375 +41974 0.121978759765625 +41975 0.404144287109375 +41976 0.133697509765625 +41977 0.22186279296875 +41978 0.131622314453125 +41979 0.003997802734375 +41980 0.119598388671875 +41981 -0.22100830078125 +41982 0.10205078125 +41983 -0.42449951171875 +41984 0.08392333984375 +41985 -0.579833984375 +41986 0.07513427734375 +41987 -0.641876220703125 +41988 0.073699951171875 +41989 -0.6177978515625 +41990 0.06396484375 +41991 -0.575531005859375 +41992 0.044891357421875 +41993 -0.526336669921875 +41994 0.029541015625 +41995 -0.42645263671875 +41996 0.02490234375 +41997 -0.2581787109375 +41998 0.0220947265625 +41999 -0.068695068359375 +42000 0.01165771484375 +42001 0.09222412109375 +42002 -0.001739501953125 +42003 0.232147216796875 +42004 -0.015533447265625 +42005 0.3509521484375 +42006 -0.037109375 +42007 0.410064697265625 +42008 -0.073760986328125 +42009 0.372955322265625 +42010 -0.120361328125 +42011 0.2554931640625 +42012 -0.16400146484375 +42013 0.10711669921875 +42014 -0.1998291015625 +42015 -0.052886962890625 +42016 -0.218902587890625 +42017 -0.186279296875 +42018 -0.2073974609375 +42019 -0.23291015625 +42020 -0.170989990234375 +42021 -0.209442138671875 +42022 -0.126007080078125 +42023 -0.174163818359375 +42024 -0.07452392578125 +42025 -0.126739501953125 +42026 -0.014068603515625 +42027 -0.048126220703125 +42028 0.048309326171875 +42029 0.0426025390625 +42030 0.101043701171875 +42031 0.10748291015625 +42032 0.140869140625 +42033 0.1409912109375 +42034 0.179595947265625 +42035 0.19708251953125 +42036 0.215545654296875 +42037 0.273651123046875 +42038 0.23486328125 +42039 0.31768798828125 +42040 0.240325927734375 +42041 0.341094970703125 +42042 0.2381591796875 +42043 0.368011474609375 +42044 0.222686767578125 +42045 0.37249755859375 +42046 0.181671142578125 +42047 0.30072021484375 +42048 0.116363525390625 +42049 0.1517333984375 +42050 0.043243408203125 +42051 -0.01470947265625 +42052 -0.03326416015625 +42053 -0.1883544921875 +42054 -0.112152099609375 +42055 -0.372711181640625 +42056 -0.178314208984375 +42057 -0.51397705078125 +42058 -0.220062255859375 +42059 -0.57177734375 +42060 -0.234375 +42061 -0.53948974609375 +42062 -0.22467041015625 +42063 -0.43511962890625 +42064 -0.199554443359375 +42065 -0.2962646484375 +42066 -0.168212890625 +42067 -0.161102294921875 +42068 -0.1341552734375 +42069 -0.0435791015625 +42070 -0.09686279296875 +42071 0.060394287109375 +42072 -0.060638427734375 +42073 0.13665771484375 +42074 -0.03033447265625 +42075 0.170135498046875 +42076 -0.006134033203125 +42077 0.16552734375 +42078 0.019012451171875 +42079 0.15728759765625 +42080 0.044891357421875 +42081 0.150787353515625 +42082 0.064056396484375 +42083 0.12200927734375 +42084 0.077362060546875 +42085 0.080108642578125 +42086 0.090087890625 +42087 0.05126953125 +42088 0.108062744140625 +42089 0.062896728515625 +42090 0.12506103515625 +42091 0.09271240234375 +42092 0.12890625 +42093 0.092987060546875 +42094 0.123199462890625 +42095 0.07855224609375 +42096 0.1119384765625 +42097 0.06427001953125 +42098 0.091888427734375 +42099 0.0347900390625 +42100 0.06341552734375 +42101 -0.01171875 +42102 0.0323486328125 +42103 -0.056060791015625 +42104 0.010467529296875 +42105 -0.055511474609375 +42106 -0.00103759765625 +42107 -0.010467529296875 +42108 -0.0142822265625 +42109 0.02508544921875 +42110 -0.034423828125 +42111 0.025665283203125 +42112 -0.053955078125 +42113 0.017333984375 +42114 -0.071533203125 +42115 0.00189208984375 +42116 -0.089263916015625 +42117 -0.03173828125 +42118 -0.103790283203125 +42119 -0.071502685546875 +42120 -0.11944580078125 +42121 -0.13543701171875 +42122 -0.135528564453125 +42123 -0.219970703125 +42124 -0.14630126953125 +42125 -0.300506591796875 +42126 -0.152191162109375 +42127 -0.376312255859375 +42128 -0.14630126953125 +42129 -0.416107177734375 +42130 -0.117462158203125 +42131 -0.371124267578125 +42132 -0.066925048828125 +42133 -0.242279052734375 +42134 -0.00567626953125 +42135 -0.069732666015625 +42136 0.06005859375 +42137 0.125640869140625 +42138 0.12164306640625 +42139 0.31268310546875 +42140 0.169281005859375 +42141 0.45501708984375 +42142 0.202911376953125 +42143 0.554779052734375 +42144 0.221832275390625 +42145 0.61065673828125 +42146 0.222991943359375 +42147 0.610931396484375 +42148 0.200439453125 +42149 0.531463623046875 +42150 0.158447265625 +42151 0.3883056640625 +42152 0.11065673828125 +42153 0.23468017578125 +42154 0.063812255859375 +42155 0.095245361328125 +42156 0.02508544921875 +42157 -0.00396728515625 +42158 -0.001068115234375 +42159 -0.04852294921875 +42160 -0.0179443359375 +42161 -0.055145263671875 +42162 -0.037628173828125 +42163 -0.0758056640625 +42164 -0.066314697265625 +42165 -0.138702392578125 +42166 -0.094757080078125 +42167 -0.209197998046875 +42168 -0.122833251953125 +42169 -0.289031982421875 +42170 -0.150360107421875 +42171 -0.37884521484375 +42172 -0.17156982421875 +42173 -0.456329345703125 +42174 -0.1851806640625 +42175 -0.51641845703125 +42176 -0.1815185546875 +42177 -0.519287109375 +42178 -0.15924072265625 +42179 -0.458251953125 +42180 -0.131561279296875 +42181 -0.384796142578125 +42182 -0.105224609375 +42183 -0.323699951171875 +42184 -0.0794677734375 +42185 -0.269287109375 +42186 -0.0484619140625 +42187 -0.1951904296875 +42188 -0.0125732421875 +42189 -0.100006103515625 +42190 0.0208740234375 +42191 -0.01055908203125 +42192 0.05877685546875 +42193 0.1033935546875 +42194 0.102447509765625 +42195 0.24908447265625 +42196 0.138336181640625 +42197 0.373199462890625 +42198 0.161865234375 +42199 0.45806884765625 +42200 0.17486572265625 +42201 0.511474609375 +42202 0.18536376953125 +42203 0.565399169921875 +42204 0.191497802734375 +42205 0.61138916015625 +42206 0.1788330078125 +42207 0.5897216796875 +42208 0.1453857421875 +42209 0.4906005859375 +42210 0.096038818359375 +42211 0.33148193359375 +42212 0.040130615234375 +42213 0.147796630859375 +42214 -0.01141357421875 +42215 -0.01873779296875 +42216 -0.051116943359375 +42217 -0.140289306640625 +42218 -0.072296142578125 +42219 -0.191986083984375 +42220 -0.0771484375 +42221 -0.184295654296875 +42222 -0.076416015625 +42223 -0.161834716796875 +42224 -0.080291748046875 +42225 -0.166595458984375 +42226 -0.0875244140625 +42227 -0.19390869140625 +42228 -0.093353271484375 +42229 -0.22442626953125 +42230 -0.103302001953125 +42231 -0.279754638671875 +42232 -0.112457275390625 +42233 -0.3389892578125 +42234 -0.10931396484375 +42235 -0.3543701171875 +42236 -0.099822998046875 +42237 -0.348175048828125 +42238 -0.085845947265625 +42239 -0.32598876953125 +42240 -0.06048583984375 +42241 -0.2581787109375 +42242 -0.02294921875 +42243 -0.139801025390625 +42244 0.022705078125 +42245 0.014617919921875 +42246 0.0609130859375 +42247 0.144378662109375 +42248 0.084320068359375 +42249 0.221038818359375 +42250 0.099273681640625 +42251 0.27069091796875 +42252 0.105865478515625 +42253 0.294036865234375 +42254 0.109283447265625 +42255 0.311767578125 +42256 0.113525390625 +42257 0.339141845703125 +42258 0.115203857421875 +42259 0.360260009765625 +42260 0.11077880859375 +42261 0.360504150390625 +42262 0.091583251953125 +42263 0.308380126953125 +42264 0.051544189453125 +42265 0.18170166015625 +42266 -0.0023193359375 +42267 0.0047607421875 +42268 -0.056732177734375 +42269 -0.17559814453125 +42270 -0.09893798828125 +42271 -0.3143310546875 +42272 -0.1165771484375 +42273 -0.36785888671875 +42274 -0.116943359375 +42275 -0.36248779296875 +42276 -0.112640380859375 +42277 -0.343536376953125 +42278 -0.101104736328125 +42279 -0.3018798828125 +42280 -0.08062744140625 +42281 -0.231414794921875 +42282 -0.047210693359375 +42283 -0.117645263671875 +42284 -0.010009765625 +42285 0.007049560546875 +42286 0.015472412109375 +42287 0.087982177734375 +42288 0.033111572265625 +42289 0.13946533203125 +42290 0.046295166015625 +42291 0.17425537109375 +42292 0.053680419921875 +42293 0.188201904296875 +42294 0.05224609375 +42295 0.171234130859375 +42296 0.040435791015625 +42297 0.118438720703125 +42298 0.025787353515625 +42299 0.05706787109375 +42300 0.00872802734375 +42301 -0.010711669921875 +42302 -0.012603759765625 +42303 -0.0914306640625 +42304 -0.031890869140625 +42305 -0.162322998046875 +42306 -0.04107666015625 +42307 -0.194549560546875 +42308 -0.029266357421875 +42309 -0.1492919921875 +42310 0.004913330078125 +42311 -0.02166748046875 +42312 0.043609619140625 +42313 0.124053955078125 +42314 0.0654296875 +42315 0.211151123046875 +42316 0.070770263671875 +42317 0.240447998046875 +42318 0.068267822265625 +42319 0.242218017578125 +42320 0.06072998046875 +42321 0.2257080078125 +42322 0.04925537109375 +42323 0.194366455078125 +42324 0.02484130859375 +42325 0.115509033203125 +42326 -0.005706787109375 +42327 0.0128173828125 +42328 -0.025543212890625 +42329 -0.053802490234375 +42330 -0.0419921875 +42331 -0.110626220703125 +42332 -0.0667724609375 +42333 -0.199493408203125 +42334 -0.092620849609375 +42335 -0.29437255859375 +42336 -0.1019287109375 +42337 -0.33221435546875 +42338 -0.085479736328125 +42339 -0.27972412109375 +42340 -0.05694580078125 +42341 -0.185333251953125 +42342 -0.038604736328125 +42343 -0.128204345703125 +42344 -0.03265380859375 +42345 -0.115692138671875 +42346 -0.03045654296875 +42347 -0.116455078125 +42348 -0.0252685546875 +42349 -0.105926513671875 +42350 -0.008758544921875 +42351 -0.053955078125 +42352 0.021575927734375 +42353 0.048797607421875 +42354 0.05303955078125 +42355 0.157318115234375 +42356 0.06890869140625 +42357 0.212005615234375 +42358 0.07073974609375 +42359 0.218475341796875 +42360 0.07550048828125 +42361 0.23724365234375 +42362 0.093597412109375 +42363 0.30535888671875 +42364 0.11346435546875 +42365 0.38128662109375 +42366 0.11822509765625 +42367 0.404449462890625 +42368 0.11346435546875 +42369 0.3944091796875 +42370 0.109771728515625 +42371 0.3885498046875 +42372 0.1004638671875 +42373 0.362640380859375 +42374 0.0736083984375 +42375 0.27362060546875 +42376 0.028076171875 +42377 0.11712646484375 +42378 -0.021484375 +42379 -0.054901123046875 +42380 -0.060516357421875 +42381 -0.19085693359375 +42382 -0.08758544921875 +42383 -0.28570556640625 +42384 -0.1026611328125 +42385 -0.339263916015625 +42386 -0.113006591796875 +42387 -0.3775634765625 +42388 -0.131317138671875 +42389 -0.445709228515625 +42390 -0.15521240234375 +42391 -0.535064697265625 +42392 -0.18011474609375 +42393 -0.629058837890625 +42394 -0.197662353515625 +42395 -0.697601318359375 +42396 -0.197662353515625 +42397 -0.70391845703125 +42398 -0.1787109375 +42399 -0.6424560546875 +42400 -0.134735107421875 +42401 -0.491241455078125 +42402 -0.07012939453125 +42403 -0.265716552734375 +42404 -0.00115966796875 +42405 -0.023712158203125 +42406 0.062835693359375 +42407 0.201751708984375 +42408 0.112060546875 +42409 0.375823974609375 +42410 0.14276123046875 +42411 0.485076904296875 +42412 0.165924072265625 +42413 0.56884765625 +42414 0.183746337890625 +42415 0.634765625 +42416 0.18359375 +42417 0.63763427734375 +42418 0.162353515625 +42419 0.5660400390625 +42420 0.1346435546875 +42421 0.4720458984375 +42422 0.114898681640625 +42423 0.40692138671875 +42424 0.105255126953125 +42425 0.3778076171875 +42426 0.10357666015625 +42427 0.376953125 +42428 0.10089111328125 +42429 0.371978759765625 +42430 0.08331298828125 +42431 0.313140869140625 +42432 0.046417236328125 +42433 0.184417724609375 +42434 -0.002593994140625 +42435 0.011199951171875 +42436 -0.05377197265625 +42437 -0.171051025390625 +42438 -0.100128173828125 +42439 -0.33740234375 +42440 -0.13726806640625 +42441 -0.47198486328125 +42442 -0.16119384765625 +42443 -0.560394287109375 +42444 -0.165802001953125 +42445 -0.58056640625 +42446 -0.15533447265625 +42447 -0.54754638671875 +42448 -0.14312744140625 +42449 -0.508575439453125 +42450 -0.128082275390625 +42451 -0.459503173828125 +42452 -0.10858154296875 +42453 -0.394378662109375 +42454 -0.095703125 +42455 -0.35260009765625 +42456 -0.083221435546875 +42457 -0.31170654296875 +42458 -0.0504150390625 +42459 -0.197418212890625 +42460 0.003143310546875 +42461 -0.007965087890625 +42462 0.06365966796875 +42463 0.207489013671875 +42464 0.1199951171875 +42465 0.409210205078125 +42466 0.165130615234375 +42467 0.57208251953125 +42468 0.190673828125 +42469 0.66595458984375 +42470 0.187713623046875 +42471 0.65875244140625 +42472 0.161041259765625 +42473 0.56744384765625 +42474 0.12176513671875 +42475 0.431396484375 +42476 0.082244873046875 +42477 0.29443359375 +42478 0.049774169921875 +42479 0.182464599609375 +42480 0.0155029296875 +42481 0.06365966796875 +42482 -0.0244140625 +42483 -0.075958251953125 +42484 -0.056793212890625 +42485 -0.189422607421875 +42486 -0.08026123046875 +42487 -0.271942138671875 +42488 -0.10009765625 +42489 -0.342529296875 +42490 -0.105987548828125 +42491 -0.364166259765625 +42492 -0.095245361328125 +42493 -0.327239990234375 +42494 -0.08056640625 +42495 -0.2769775390625 +42496 -0.07354736328125 +42497 -0.253692626953125 +42498 -0.070159912109375 +42499 -0.24365234375 +42500 -0.0557861328125 +42501 -0.1983642578125 +42502 -0.030059814453125 +42503 -0.116241455078125 +42504 -0.00543212890625 +42505 -0.036834716796875 +42506 0.016448974609375 +42507 0.034881591796875 +42508 0.033172607421875 +42509 0.09124755859375 +42510 0.037506103515625 +42511 0.10888671875 +42512 0.041259765625 +42513 0.125518798828125 +42514 0.049713134765625 +42515 0.15771484375 +42516 0.054473876953125 +42517 0.17828369140625 +42518 0.050567626953125 +42519 0.17108154296875 +42520 0.0362548828125 +42521 0.129974365234375 +42522 0.020172119140625 +42523 0.082427978515625 +42524 0.00213623046875 +42525 0.027679443359375 +42526 -0.02752685546875 +42527 -0.065643310546875 +42528 -0.056884765625 +42529 -0.15936279296875 +42530 -0.073333740234375 +42531 -0.21307373046875 +42532 -0.079376220703125 +42533 -0.234649658203125 +42534 -0.067596435546875 +42535 -0.2001953125 +42536 -0.041015625 +42537 -0.119171142578125 +42538 -0.01007080078125 +42539 -0.024749755859375 +42540 0.0260009765625 +42541 0.085784912109375 +42542 0.056396484375 +42543 0.178131103515625 +42544 0.069549560546875 +42545 0.215576171875 +42546 0.069549560546875 +42547 0.211456298828125 +42548 0.059326171875 +42549 0.17523193359375 +42550 0.045623779296875 +42551 0.128753662109375 +42552 0.037750244140625 +42553 0.1019287109375 +42554 0.029327392578125 +42555 0.0743408203125 +42556 0.019500732421875 +42557 0.04327392578125 +42558 0.017425537109375 +42559 0.038177490234375 +42560 0.028564453125 +42561 0.076263427734375 +42562 0.047760009765625 +42563 0.14105224609375 +42564 0.06072998046875 +42565 0.186431884765625 +42566 0.0601806640625 +42567 0.188812255859375 +42568 0.043304443359375 +42569 0.1390380859375 +42570 0.011688232421875 +42571 0.041778564453125 +42572 -0.027252197265625 +42573 -0.079437255859375 +42574 -0.071868896484375 +42575 -0.219390869140625 +42576 -0.118865966796875 +42577 -0.367828369140625 +42578 -0.158905029296875 +42579 -0.494873046875 +42580 -0.178192138671875 +42581 -0.556243896484375 +42582 -0.1632080078125 +42583 -0.508697509765625 +42584 -0.12127685546875 +42585 -0.3756103515625 +42586 -0.071746826171875 +42587 -0.218902587890625 +42588 -0.02252197265625 +42589 -0.063751220703125 +42590 0.02685546875 +42591 0.091552734375 +42592 0.072906494140625 +42593 0.23602294921875 +42594 0.10723876953125 +42595 0.342987060546875 +42596 0.12445068359375 +42597 0.39520263671875 +42598 0.12347412109375 +42599 0.389373779296875 +42600 0.1038818359375 +42601 0.324249267578125 +42602 0.073211669921875 +42603 0.224090576171875 +42604 0.042449951171875 +42605 0.124267578125 +42606 0.015411376953125 +42607 0.037078857421875 +42608 0.000640869140625 +42609 -0.010101318359375 +42610 -0.00250244140625 +42611 -0.019439697265625 +42612 -0.003936767578125 +42613 -0.022796630859375 +42614 0.00213623046875 +42615 -0.001556396484375 +42616 0.019500732421875 +42617 0.056304931640625 +42618 0.034454345703125 +42619 0.106719970703125 +42620 0.030548095703125 +42621 0.096893310546875 +42622 0.0128173828125 +42623 0.042694091796875 +42624 -0.00689697265625 +42625 -0.018035888671875 +42626 -0.025604248046875 +42627 -0.07586669921875 +42628 -0.039703369140625 +42629 -0.11944580078125 +42630 -0.0526123046875 +42631 -0.15972900390625 +42632 -0.066131591796875 +42633 -0.202606201171875 +42634 -0.080413818359375 +42635 -0.24859619140625 +42636 -0.0977783203125 +42637 -0.30517578125 +42638 -0.115081787109375 +42639 -0.36212158203125 +42640 -0.1236572265625 +42641 -0.39141845703125 +42642 -0.111724853515625 +42643 -0.35528564453125 +42644 -0.07818603515625 +42645 -0.249969482421875 +42646 -0.02850341796875 +42647 -0.092864990234375 +42648 0.02886962890625 +42649 0.08905029296875 +42650 0.07501220703125 +42651 0.2352294921875 +42652 0.101531982421875 +42653 0.318817138671875 +42654 0.114288330078125 +42655 0.358642578125 +42656 0.111083984375 +42657 0.347747802734375 +42658 0.09173583984375 +42659 0.28564453125 +42660 0.0721435546875 +42661 0.223175048828125 +42662 0.06365966796875 +42663 0.196746826171875 +42664 0.05804443359375 +42665 0.179840087890625 +42666 0.050048828125 +42667 0.155548095703125 +42668 0.0482177734375 +42669 0.151214599609375 +42670 0.049468994140625 +42671 0.156951904296875 +42672 0.041046142578125 +42673 0.13177490234375 +42674 0.030853271484375 +42675 0.100799560546875 +42676 0.026092529296875 +42677 0.087127685546875 +42678 0.015594482421875 +42679 0.05487060546875 +42680 -0.004638671875 +42681 -0.009002685546875 +42682 -0.034454345703125 +42683 -0.10400390625 +42684 -0.073638916015625 +42685 -0.229400634765625 +42686 -0.1129150390625 +42687 -0.35552978515625 +42688 -0.1396484375 +42689 -0.441925048828125 +42690 -0.149261474609375 +42691 -0.473846435546875 +42692 -0.14599609375 +42693 -0.464813232421875 +42694 -0.1312255859375 +42695 -0.419097900390625 +42696 -0.104248046875 +42697 -0.334320068359375 +42698 -0.070526123046875 +42699 -0.227935791015625 +42700 -0.037445068359375 +42701 -0.12347412109375 +42702 -0.007110595703125 +42703 -0.02764892578125 +42704 0.026092529296875 +42705 0.077667236328125 +42706 0.068634033203125 +42707 0.2132568359375 +42708 0.12353515625 +42709 0.38885498046875 +42710 0.184051513671875 +42711 0.582794189453125 +42712 0.231109619140625 +42713 0.734039306640625 +42714 0.25146484375 +42715 0.800140380859375 +42716 0.244293212890625 +42717 0.7783203125 +42718 0.20855712890625 +42719 0.6651611328125 +42720 0.144012451171875 +42721 0.45965576171875 +42722 0.06231689453125 +42723 0.199188232421875 +42724 -0.016021728515625 +42725 -0.050689697265625 +42726 -0.0732421875 +42727 -0.23297119140625 +42728 -0.103851318359375 +42729 -0.33013916015625 +42730 -0.11602783203125 +42731 -0.368408203125 +42732 -0.11944580078125 +42733 -0.378936767578125 +42734 -0.118927001953125 +42735 -0.376983642578125 +42736 -0.11981201171875 +42737 -0.37969970703125 +42738 -0.1234130859375 +42739 -0.391510009765625 +42740 -0.121307373046875 +42741 -0.385345458984375 +42742 -0.107513427734375 +42743 -0.3419189453125 +42744 -0.08880615234375 +42745 -0.28289794921875 +42746 -0.078704833984375 +42747 -0.251617431640625 +42748 -0.082855224609375 +42749 -0.266143798828125 +42750 -0.084716796875 +42751 -0.273345947265625 +42752 -0.066558837890625 +42753 -0.216796875 +42754 -0.038604736328125 +42755 -0.128265380859375 +42756 -0.02069091796875 +42757 -0.068145751953125 +42758 -0.014923095703125 +42759 -0.0430908203125 +42760 -0.01129150390625 +42761 -0.024444580078125 +42762 0.001678466796875 +42763 0.020721435546875 +42764 0.03515625 +42765 0.124481201171875 +42766 0.07928466796875 +42767 0.25787353515625 +42768 0.1197509765625 +42769 0.379119873046875 +42770 0.15380859375 +42771 0.47991943359375 +42772 0.17041015625 +42773 0.5281982421875 +42774 0.165130615234375 +42775 0.511138916015625 +42776 0.147369384765625 +42777 0.456207275390625 +42778 0.132232666015625 +42779 0.407470703125 +42780 0.1260986328125 +42781 0.383758544921875 +42782 0.119110107421875 +42783 0.35687255859375 +42784 0.10601806640625 +42785 0.31182861328125 +42786 0.087432861328125 +42787 0.250885009765625 +42788 0.060272216796875 +42789 0.1654052734375 +42790 0.017486572265625 +42791 0.035247802734375 +42792 -0.041839599609375 +42793 -0.142059326171875 +42794 -0.107147216796875 +42795 -0.33563232421875 +42796 -0.174774169921875 +42797 -0.5345458984375 +42798 -0.2388916015625 +42799 -0.72186279296875 +42800 -0.278564453125 +42801 -0.836669921875 +42802 -0.27783203125 +42803 -0.8326416015625 +42804 -0.24346923828125 +42805 -0.7296142578125 +42806 -0.1943359375 +42807 -0.582550048828125 +42808 -0.147064208984375 +42809 -0.440093994140625 +42810 -0.109161376953125 +42811 -0.324310302734375 +42812 -0.068878173828125 +42813 -0.20147705078125 +42814 -0.016845703125 +42815 -0.044647216796875 +42816 0.032501220703125 +42817 0.103973388671875 +42818 0.0648193359375 +42819 0.202392578125 +42820 0.0849609375 +42821 0.264495849609375 +42822 0.10968017578125 +42823 0.338897705078125 +42824 0.145294189453125 +42825 0.443817138671875 +42826 0.1800537109375 +42827 0.545074462890625 +42828 0.205230712890625 +42829 0.6173095703125 +42830 0.218017578125 +42831 0.6524658203125 +42832 0.222808837890625 +42833 0.66339111328125 +42834 0.22161865234375 +42835 0.6561279296875 +42836 0.20611572265625 +42837 0.606781005859375 +42838 0.17132568359375 +42839 0.501190185546875 +42840 0.121826171875 +42841 0.352783203125 +42842 0.06268310546875 +42843 0.176544189453125 +42844 -0.0086669921875 +42845 -0.034820556640625 +42846 -0.084320068359375 +42847 -0.258209228515625 +42848 -0.146759033203125 +42849 -0.44244384765625 +42850 -0.191802978515625 +42851 -0.5753173828125 +42852 -0.217864990234375 +42853 -0.65203857421875 +42854 -0.21429443359375 +42855 -0.641632080078125 +42856 -0.18731689453125 +42857 -0.562164306640625 +42858 -0.152191162109375 +42859 -0.458038330078125 +42860 -0.11614990234375 +42861 -0.350555419921875 +42862 -0.086334228515625 +42863 -0.260528564453125 +42864 -0.0640869140625 +42865 -0.192108154296875 +42866 -0.048187255859375 +42867 -0.141937255859375 +42868 -0.035858154296875 +42869 -0.1021728515625 +42870 -0.023590087890625 +42871 -0.062896728515625 +42872 -0.00714111328125 +42873 -0.011932373046875 +42874 0.0177001953125 +42875 0.062835693359375 +42876 0.046630859375 +42877 0.148712158203125 +42878 0.078277587890625 +42879 0.241729736328125 +42880 0.11517333984375 +42881 0.34912109375 +42882 0.152618408203125 +42883 0.457305908203125 +42884 0.182891845703125 +42885 0.54388427734375 +42886 0.193572998046875 +42887 0.5728759765625 +42888 0.171661376953125 +42889 0.506591796875 +42890 0.119232177734375 +42891 0.351226806640625 +42892 0.049896240234375 +42893 0.146514892578125 +42894 -0.018402099609375 +42895 -0.05523681640625 +42896 -0.072723388671875 +42897 -0.21624755859375 +42898 -0.112579345703125 +42899 -0.334930419921875 +42900 -0.135162353515625 +42901 -0.402984619140625 +42902 -0.147674560546875 +42903 -0.4412841796875 +42904 -0.165985107421875 +42905 -0.49578857421875 +42906 -0.187957763671875 +42907 -0.5601806640625 +42908 -0.20196533203125 +42909 -0.600738525390625 +42910 -0.19659423828125 +42911 -0.584228515625 +42912 -0.1610107421875 +42913 -0.47930908203125 +42914 -0.092926025390625 +42915 -0.27935791015625 +42916 -0.000732421875 +42917 -0.0089111328125 +42918 0.093841552734375 +42919 0.268798828125 +42920 0.166473388671875 +42921 0.482818603515625 +42922 0.207061767578125 +42923 0.60369873046875 +42924 0.222198486328125 +42925 0.650421142578125 +42926 0.226043701171875 +42927 0.66400146484375 +42928 0.21759033203125 +42929 0.6414794921875 +42930 0.193359375 +42931 0.572540283203125 +42932 0.16748046875 +42933 0.498138427734375 +42934 0.147216796875 +42935 0.439453125 +42936 0.125396728515625 +42937 0.375518798828125 +42938 0.091033935546875 +42939 0.274505615234375 +42940 0.034576416015625 +42941 0.1087646484375 +42942 -0.03631591796875 +42943 -0.099395751953125 +42944 -0.110748291015625 +42945 -0.3182373046875 +42946 -0.189208984375 +42947 -0.5489501953125 +42948 -0.265594482421875 +42949 -0.7738037109375 +42950 -0.32177734375 +42951 -0.86383056640625 +42952 -0.34637451171875 +42953 -0.870391845703125 +42954 -0.345550537109375 +42955 -0.86895751953125 +42956 -0.323822021484375 +42957 -0.861053466796875 +42958 -0.2752685546875 +42959 -0.765869140625 +42960 -0.196014404296875 +42961 -0.5301513671875 +42962 -0.088531494140625 +42963 -0.214691162109375 +42964 0.032379150390625 +42965 0.137359619140625 +42966 0.1490478515625 +42967 0.474822998046875 +42968 0.24932861328125 +42969 0.76239013671875 +42970 0.323944091796875 +42971 0.867462158203125 +42972 0.37310791015625 +42973 0.870361328125 +42974 0.39288330078125 +42975 0.86480712890625 +42976 0.385162353515625 +42977 0.831817626953125 +42978 0.358367919921875 +42979 0.677581787109375 +42980 0.314544677734375 +42981 0.495880126953125 +42982 0.260101318359375 +42983 0.30767822265625 +42984 0.195831298828125 +42985 0.116180419921875 +42986 0.11083984375 +42987 -0.110748291015625 +42988 0.002716064453125 +42989 -0.381805419921875 +42990 -0.113739013671875 +42991 -0.6572265625 +42992 -0.21795654296875 +42993 -0.857421875 +42994 -0.295196533203125 +42995 -0.870391845703125 +42996 -0.343017578125 +42997 -0.870391845703125 +42998 -0.3707275390625 +42999 -0.86444091796875 +43000 -0.390625 +43001 -0.85723876953125 +43002 -0.396453857421875 +43003 -0.790008544921875 +43004 -0.36962890625 +43005 -0.62847900390625 +43006 -0.30908203125 +43007 -0.3956298828125 +43008 -0.22607421875 +43009 -0.126708984375 +43010 -0.130035400390625 +43011 0.150115966796875 +43012 -0.024749755859375 +43013 0.424041748046875 +43014 0.080291748046875 +43015 0.670623779296875 +43016 0.171051025390625 +43017 0.854522705078125 +43018 0.24139404296875 +43019 0.866485595703125 +43020 0.285919189453125 +43021 0.86920166015625 +43022 0.31170654296875 +43023 0.8653564453125 +43024 0.323974609375 +43025 0.857147216796875 +43026 0.321685791015625 +43027 0.766845703125 +43028 0.30670166015625 +43029 0.628509521484375 +43030 0.276336669921875 +43031 0.462127685546875 +43032 0.24005126953125 +43033 0.297210693359375 +43034 0.202178955078125 +43035 0.14862060546875 +43036 0.153778076171875 +43037 -0.00537109375 +43038 0.0972900390625 +43039 -0.15753173828125 +43040 0.030975341796875 +43041 -0.31304931640625 +43042 -0.05078125 +43043 -0.48876953125 +43044 -0.130706787109375 +43045 -0.6416015625 +43046 -0.199798583984375 +43047 -0.751373291015625 +43048 -0.2669677734375 +43049 -0.84619140625 +43050 -0.32684326171875 +43051 -0.861297607421875 +43052 -0.367034912109375 +43053 -0.863250732421875 +43054 -0.3756103515625 +43055 -0.856597900390625 +43056 -0.357086181640625 +43057 -0.7498779296875 +43058 -0.33306884765625 +43059 -0.624542236328125 +43060 -0.2950439453125 +43061 -0.47808837890625 +43062 -0.220794677734375 +43063 -0.253387451171875 +43064 -0.127197265625 +43065 0.003692626953125 +43066 -0.0396728515625 +43067 0.2257080078125 +43068 0.046783447265625 +43069 0.427154541015625 +43070 0.1446533203125 +43071 0.643218994140625 +43072 0.250518798828125 +43073 0.855926513671875 +43074 0.342803955078125 +43075 0.870361328125 +43076 0.402984619140625 +43077 0.870361328125 +43078 0.433837890625 +43079 0.862762451171875 +43080 0.43426513671875 +43081 0.79669189453125 +43082 0.400665283203125 +43083 0.595794677734375 +43084 0.34393310546875 +43085 0.362152099609375 +43086 0.274444580078125 +43087 0.1270751953125 +43088 0.199981689453125 +43089 -0.086944580078125 +43090 0.121124267578125 +43091 -0.2784423828125 +43092 0.0245361328125 +43093 -0.484832763671875 +43094 -0.097198486328125 +43095 -0.729583740234375 +43096 -0.225250244140625 +43097 -0.86688232421875 +43098 -0.335968017578125 +43099 -0.870391845703125 +43100 -0.427642822265625 +43101 -0.86859130859375 +43102 -0.4996337890625 +43103 -0.86279296875 +43104 -0.5384521484375 +43105 -0.817962646484375 +43106 -0.52703857421875 +43107 -0.6116943359375 +43108 -0.46270751953125 +43109 -0.3128662109375 +43110 -0.358062744140625 +43111 0.039398193359375 +43112 -0.220550537109375 +43113 0.422821044921875 +43114 -0.06256103515625 +43115 0.805145263671875 +43116 0.090423583984375 +43117 0.870361328125 +43118 0.217071533203125 +43119 0.870361328125 +43120 0.313140869140625 +43121 0.860015869140625 +43122 0.3758544921875 +43123 0.727935791015625 +43124 0.403167724609375 +43125 0.48114013671875 +43126 0.404205322265625 +43127 0.2059326171875 +43128 0.38751220703125 +43129 -0.06103515625 +43130 0.35687255859375 +43131 -0.29913330078125 +43132 0.306854248046875 +43133 -0.516204833984375 +43134 0.231658935546875 +43135 -0.7252197265625 +43136 0.140625 +43137 -0.85980224609375 +43138 0.04669189453125 +43139 -0.870391845703125 +43140 -0.03900146484375 +43141 -0.870391845703125 +43142 -0.09814453125 +43143 -0.858062744140625 +43144 -0.129119873046875 +43145 -0.673004150390625 +43146 -0.151641845703125 +43147 -0.42694091796875 +43148 -0.182342529296875 +43149 -0.2100830078125 +43150 -0.2203369140625 +43151 -0.0362548828125 +43152 -0.254638671875 +43153 0.10943603515625 +43154 -0.2777099609375 +43155 0.23516845703125 +43156 -0.273956298828125 +43157 0.373687744140625 +43158 -0.244110107421875 +43159 0.517791748046875 +43160 -0.21185302734375 +43161 0.602783203125 +43162 -0.17523193359375 +43163 0.635711669921875 +43164 -0.121734619140625 +43165 0.655181884765625 +43166 -0.05517578125 +43167 0.65948486328125 +43168 0.021331787109375 +43169 0.651275634765625 +43170 0.098480224609375 +43171 0.61846923828125 +43172 0.162261962890625 +43173 0.53753662109375 +43174 0.20574951171875 +43175 0.404144287109375 +43176 0.2252197265625 +43177 0.22186279296875 +43178 0.2210693359375 +43179 0.003997802734375 +43180 0.200042724609375 +43181 -0.22100830078125 +43182 0.16986083984375 +43183 -0.42449951171875 +43184 0.13848876953125 +43185 -0.579833984375 +43186 0.121978759765625 +43187 -0.641876220703125 +43188 0.117828369140625 +43189 -0.6177978515625 +43190 0.101806640625 +43191 -0.575531005859375 +43192 0.07196044921875 +43193 -0.526336669921875 +43194 0.047821044921875 +43195 -0.42645263671875 +43196 0.039794921875 +43197 -0.2581787109375 +43198 0.0343017578125 +43199 -0.068695068359375 +43200 0.0169677734375 +43201 0.09222412109375 +43202 -0.005035400390625 +43203 0.232147216796875 +43204 -0.02777099609375 +43205 0.3509521484375 +43206 -0.062286376953125 +43207 0.410064697265625 +43208 -0.1195068359375 +43209 0.372955322265625 +43210 -0.191497802734375 +43211 0.2554931640625 +43212 -0.25860595703125 +43213 0.10711669921875 +43214 -0.31341552734375 +43215 -0.052886962890625 +43216 -0.342315673828125 +43217 -0.186279296875 +43218 -0.3243408203125 +43219 -0.23291015625 +43220 -0.268096923828125 +43221 -0.209442138671875 +43222 -0.19842529296875 +43223 -0.174163818359375 +43224 -0.1185302734375 +43225 -0.126739501953125 +43226 -0.02484130859375 +43227 -0.048126220703125 +43228 0.071929931640625 +43229 0.0426025390625 +43230 0.154144287109375 +43231 0.10748291015625 +43232 0.216705322265625 +43233 0.1409912109375 +43234 0.277374267578125 +43235 0.19708251953125 +43236 0.333526611328125 +43237 0.273651123046875 +43238 0.36407470703125 +43239 0.31768798828125 +43240 0.373138427734375 +43241 0.341094970703125 +43242 0.37017822265625 +43243 0.368011474609375 +43244 0.346527099609375 +43245 0.37249755859375 +43246 0.283660888671875 +43247 0.30072021484375 +43248 0.183502197265625 +43249 0.1517333984375 +43250 0.071136474609375 +43251 -0.01470947265625 +43252 -0.046661376953125 +43253 -0.1883544921875 +43254 -0.168304443359375 +43255 -0.372711181640625 +43256 -0.27069091796875 +43257 -0.51397705078125 +43258 -0.336029052734375 +43259 -0.57177734375 +43260 -0.359619140625 +43261 -0.53948974609375 +43262 -0.346527099609375 +43263 -0.43511962890625 +43264 -0.3094482421875 +43265 -0.2962646484375 +43266 -0.2620849609375 +43267 -0.161102294921875 +43268 -0.209930419921875 +43269 -0.0435791015625 +43270 -0.15228271484375 +43271 0.060394287109375 +43272 -0.096221923828125 +43273 0.13665771484375 +43274 -0.049591064453125 +43275 0.170135498046875 +43276 -0.012664794921875 +43277 0.16552734375 +43278 0.02593994140625 +43279 0.15728759765625 +43280 0.065948486328125 +43281 0.150787353515625 +43282 0.09539794921875 +43283 0.12200927734375 +43284 0.115753173828125 +43285 0.080108642578125 +43286 0.135589599609375 +43287 0.05126953125 +43288 0.164337158203125 +43289 0.062896728515625 +43290 0.191986083984375 +43291 0.09271240234375 +43292 0.1988525390625 +43293 0.092987060546875 +43294 0.190765380859375 +43295 0.07855224609375 +43296 0.174072265625 +43297 0.06427001953125 +43298 0.14349365234375 +43299 0.0347900390625 +43300 0.099578857421875 +43301 -0.01171875 +43302 0.051544189453125 +43303 -0.056060791015625 +43304 0.018310546875 +43305 -0.055511474609375 +43306 0.001617431640625 +43307 -0.010467529296875 +43308 -0.018157958984375 +43309 0.02508544921875 +43310 -0.04937744140625 +43311 0.025665283203125 +43312 -0.0799560546875 +43313 0.017333984375 +43314 -0.107818603515625 +43315 0.00189208984375 +43316 -0.136383056640625 +43317 -0.03173828125 +43318 -0.16021728515625 +43319 -0.071502685546875 +43320 -0.186279296875 +43321 -0.13543701171875 +43322 -0.21337890625 +43323 -0.219970703125 +43324 -0.232177734375 +43325 -0.300506591796875 +43326 -0.243316650390625 +43327 -0.376312255859375 +43328 -0.23553466796875 +43329 -0.416107177734375 +43330 -0.190765380859375 +43331 -0.371124267578125 +43332 -0.11090087890625 +43333 -0.242279052734375 +43334 -0.013580322265625 +43335 -0.069732666015625 +43336 0.091278076171875 +43337 0.125640869140625 +43338 0.189788818359375 +43339 0.31268310546875 +43340 0.266204833984375 +43341 0.45501708984375 +43342 0.3204345703125 +43343 0.554779052734375 +43344 0.351348876953125 +43345 0.61065673828125 +43346 0.35394287109375 +43347 0.610931396484375 +43348 0.318603515625 +43349 0.531463623046875 +43350 0.252105712890625 +43351 0.3883056640625 +43352 0.176422119140625 +43353 0.23468017578125 +43354 0.10235595703125 +43355 0.095245361328125 +43356 0.041412353515625 +43357 -0.00396728515625 +43358 0.000579833984375 +43359 -0.04852294921875 +43360 -0.025482177734375 +43361 -0.055145263671875 +43362 -0.0562744140625 +43363 -0.0758056640625 +43364 -0.101898193359375 +43365 -0.138702392578125 +43366 -0.147430419921875 +43367 -0.209197998046875 +43368 -0.19268798828125 +43369 -0.289031982421875 +43370 -0.23736572265625 +43371 -0.37884521484375 +43372 -0.27215576171875 +43373 -0.456329345703125 +43374 -0.29498291015625 +43375 -0.51641845703125 +43376 -0.290130615234375 +43377 -0.519287109375 +43378 -0.25537109375 +43379 -0.458251953125 +43380 -0.212005615234375 +43381 -0.384796142578125 +43382 -0.1707763671875 +43383 -0.323699951171875 +43384 -0.130401611328125 +43385 -0.269287109375 +43386 -0.081451416015625 +43387 -0.1951904296875 +43388 -0.0244140625 +43389 -0.100006103515625 +43390 0.0289306640625 +43391 -0.01055908203125 +43392 0.089752197265625 +43393 0.1033935546875 +43394 0.160186767578125 +43395 0.24908447265625 +43396 0.21832275390625 +43397 0.373199462890625 +43398 0.256744384765625 +43399 0.45806884765625 +43400 0.2784423828125 +43401 0.511474609375 +43402 0.296295166015625 +43403 0.565399169921875 +43404 0.307281494140625 +43405 0.61138916015625 +43406 0.287994384765625 +43407 0.5897216796875 +43408 0.23516845703125 +43409 0.4906005859375 +43410 0.156585693359375 +43411 0.33148193359375 +43412 0.067291259765625 +43413 0.147796630859375 +43414 -0.015106201171875 +43415 -0.01873779296875 +43416 -0.07861328125 +43417 -0.140289306640625 +43418 -0.112518310546875 +43419 -0.191986083984375 +43420 -0.120330810546875 +43421 -0.184295654296875 +43422 -0.119354248046875 +43423 -0.161834716796875 +43424 -0.126007080078125 +43425 -0.166595458984375 +43426 -0.1383056640625 +43427 -0.19390869140625 +43428 -0.14849853515625 +43429 -0.22442626953125 +43430 -0.165435791015625 +43431 -0.279754638671875 +43432 -0.18115234375 +43433 -0.3389892578125 +43434 -0.177093505859375 +43435 -0.3543701171875 +43436 -0.162750244140625 +43437 -0.348175048828125 +43438 -0.14105224609375 +43439 -0.32598876953125 +43440 -0.10089111328125 +43441 -0.2581787109375 +43442 -0.040985107421875 +43443 -0.139801025390625 +43444 0.03216552734375 +43445 0.014617919921875 +43446 0.093658447265625 +43447 0.144378662109375 +43448 0.131683349609375 +43449 0.221038818359375 +43450 0.156341552734375 +43451 0.27069091796875 +43452 0.167724609375 +43453 0.294036865234375 +43454 0.174072265625 +43455 0.311767578125 +43456 0.181640625 +43457 0.339141845703125 +43458 0.184417724609375 +43459 0.360260009765625 +43460 0.176910400390625 +43461 0.360504150390625 +43462 0.146728515625 +43463 0.308380126953125 +43464 0.085296630859375 +43465 0.18170166015625 +43466 0.003082275390625 +43467 0.0047607421875 +43468 -0.08026123046875 +43469 -0.17559814453125 +43470 -0.145843505859375 +43471 -0.3143310546875 +43472 -0.175445556640625 +43473 -0.36785888671875 +43474 -0.179412841796875 +43475 -0.36248779296875 +43476 -0.175933837890625 +43477 -0.343536376953125 +43478 -0.1611328125 +43479 -0.3018798828125 +43480 -0.132415771484375 +43481 -0.231414794921875 +43482 -0.083953857421875 +43483 -0.117645263671875 +43484 -0.029144287109375 +43485 0.007049560546875 +43486 0.009429931640625 +43487 0.087982177734375 +43488 0.037261962890625 +43489 0.13946533203125 +43490 0.059173583984375 +43491 0.17425537109375 +43492 0.073028564453125 +43493 0.188201904296875 +43494 0.07421875 +43495 0.171234130859375 +43496 0.060333251953125 +43497 0.118438720703125 +43498 0.0421142578125 +43499 0.05706787109375 +43500 0.020050048828125 +43501 -0.010711669921875 +43502 -0.0087890625 +43503 -0.0914306640625 +43504 -0.035247802734375 +43505 -0.162322998046875 +43506 -0.047698974609375 +43507 -0.194549560546875 +43508 -0.0302734375 +43509 -0.1492919921875 +43510 0.01910400390625 +43511 -0.02166748046875 +43512 0.074432373046875 +43513 0.124053955078125 +43514 0.104644775390625 +43515 0.211151123046875 +43516 0.11041259765625 +43517 0.240447998046875 +43518 0.104461669921875 +43519 0.242218017578125 +43520 0.091461181640625 +43521 0.2257080078125 +43522 0.07293701171875 +43523 0.194366455078125 +43524 0.034149169921875 +43525 0.115509033203125 +43526 -0.014190673828125 +43527 0.0128173828125 +43528 -0.04559326171875 +43529 -0.053802490234375 +43530 -0.071502685546875 +43531 -0.110626220703125 +43532 -0.11029052734375 +43533 -0.199493408203125 +43534 -0.150543212890625 +43535 -0.29437255859375 +43536 -0.16461181640625 +43537 -0.33221435546875 +43538 -0.13800048828125 +43539 -0.27972412109375 +43540 -0.092254638671875 +43541 -0.185333251953125 +43542 -0.06243896484375 +43543 -0.128204345703125 +43544 -0.052032470703125 +43545 -0.115692138671875 +43546 -0.047515869140625 +43547 -0.116455078125 +43548 -0.038330078125 +43549 -0.105926513671875 +43550 -0.011474609375 +43551 -0.053955078125 +43552 0.036956787109375 +43553 0.048797607421875 +43554 0.087005615234375 +43555 0.157318115234375 +43556 0.112335205078125 +43557 0.212005615234375 +43558 0.115386962890625 +43559 0.218475341796875 +43560 0.122802734375 +43561 0.23724365234375 +43562 0.150970458984375 +43563 0.30535888671875 +43564 0.18170166015625 +43565 0.38128662109375 +43566 0.188507080078125 +43567 0.404449462890625 +43568 0.180206298828125 +43569 0.3944091796875 +43570 0.1734619140625 +43571 0.3885498046875 +43572 0.157867431640625 +43573 0.362640380859375 +43574 0.114715576171875 +43575 0.27362060546875 +43576 0.042327880859375 +43577 0.11712646484375 +43578 -0.0362548828125 +43579 -0.054901123046875 +43580 -0.09820556640625 +43581 -0.19085693359375 +43582 -0.141204833984375 +43583 -0.28570556640625 +43584 -0.165130615234375 +43585 -0.339263916015625 +43586 -0.18145751953125 +43587 -0.3775634765625 +43588 -0.210052490234375 +43589 -0.445709228515625 +43590 -0.24725341796875 +43591 -0.535064697265625 +43592 -0.285888671875 +43593 -0.629058837890625 +43594 -0.3128662109375 +43595 -0.697601318359375 +43596 -0.31219482421875 +43597 -0.70391845703125 +43598 -0.281646728515625 +43599 -0.6424560546875 +43600 -0.21173095703125 +43601 -0.491241455078125 +43602 -0.10943603515625 +43603 -0.265716552734375 +43604 -0.0003662109375 +43605 -0.023712158203125 +43606 0.10076904296875 +43607 0.201751708984375 +43608 0.1785888671875 +43609 0.375823974609375 +43610 0.227142333984375 +43611 0.485076904296875 +43612 0.26373291015625 +43613 0.56884765625 +43614 0.291748046875 +43615 0.634765625 +43616 0.2913818359375 +43617 0.63763427734375 +43618 0.2576904296875 +43619 0.5660400390625 +43620 0.213714599609375 +43621 0.4720458984375 +43622 0.182159423828125 +43623 0.40692138671875 +43624 0.166351318359375 +43625 0.3778076171875 +43626 0.163055419921875 +43627 0.376953125 +43628 0.158172607421875 +43629 0.371978759765625 +43630 0.129974365234375 +43631 0.313140869140625 +43632 0.071502685546875 +43633 0.184417724609375 +43634 -0.005950927734375 +43635 0.011199951171875 +43636 -0.08673095703125 +43637 -0.171051025390625 +43638 -0.15985107421875 +43639 -0.33740234375 +43640 -0.21832275390625 +43641 -0.47198486328125 +43642 -0.25592041015625 +43643 -0.560394287109375 +43644 -0.26300048828125 +43645 -0.58056640625 +43646 -0.24627685546875 +43647 -0.54754638671875 +43648 -0.226715087890625 +43649 -0.508575439453125 +43650 -0.20263671875 +43651 -0.459503173828125 +43652 -0.171539306640625 +43653 -0.394378662109375 +43654 -0.150848388671875 +43655 -0.35260009765625 +43656 -0.13079833984375 +43657 -0.31170654296875 +43658 -0.078826904296875 +43659 -0.197418212890625 +43660 0.0057373046875 +43661 -0.007965087890625 +43662 0.101165771484375 +43663 0.207489013671875 +43664 0.189971923828125 +43665 0.409210205078125 +43666 0.2611083984375 +43667 0.57208251953125 +43668 0.301361083984375 +43669 0.66595458984375 +43670 0.296722412109375 +43671 0.65875244140625 +43672 0.254730224609375 +43673 0.56744384765625 +43674 0.192840576171875 +43675 0.431396484375 +43676 0.130462646484375 +43677 0.29443359375 +43678 0.079071044921875 +43679 0.182464599609375 +43680 0.024810791015625 +43681 0.06365966796875 +43682 -0.038360595703125 +43683 -0.075958251953125 +43684 -0.089691162109375 +43685 -0.189422607421875 +43686 -0.126983642578125 +43687 -0.271942138671875 +43688 -0.1585693359375 +43689 -0.342529296875 +43690 -0.168182373046875 +43691 -0.364166259765625 +43692 -0.151580810546875 +43693 -0.327239990234375 +43694 -0.128692626953125 +43695 -0.2769775390625 +43696 -0.117340087890625 +43697 -0.253692626953125 +43698 -0.11151123046875 +43699 -0.24365234375 +43700 -0.089996337890625 +43701 -0.1983642578125 +43702 -0.052154541015625 +43703 -0.116241455078125 +43704 -0.015472412109375 +43705 -0.036834716796875 +43706 0.017730712890625 +43707 0.034881591796875 +43708 0.04400634765625 +43709 0.09124755859375 +43710 0.053009033203125 +43711 0.10888671875 +43712 0.061248779296875 +43713 0.125518798828125 +43714 0.07598876953125 +43715 0.15771484375 +43716 0.085235595703125 +43717 0.17828369140625 +43718 0.08184814453125 +43719 0.17108154296875 +43720 0.063201904296875 +43721 0.129974365234375 +43722 0.041412353515625 +43723 0.082427978515625 +43724 0.016204833984375 +43725 0.027679443359375 +43726 -0.026123046875 +43727 -0.065643310546875 +43728 -0.0687255859375 +43729 -0.15936279296875 +43730 -0.09375 +43731 -0.21307373046875 +43732 -0.104583740234375 +43733 -0.234649658203125 +43734 -0.09063720703125 +43735 -0.2001953125 +43736 -0.055999755859375 +43737 -0.119171142578125 +43738 -0.015228271484375 +43739 -0.024749755859375 +43740 0.03289794921875 +43741 0.085784912109375 +43742 0.073272705078125 +43743 0.178131103515625 +43744 0.08978271484375 +43745 0.215576171875 +43746 0.0882568359375 +43747 0.211456298828125 +43748 0.072845458984375 +43749 0.17523193359375 +43750 0.053131103515625 +43751 0.128753662109375 +43752 0.042236328125 +43753 0.1019287109375 +43754 0.0311279296875 +43755 0.0743408203125 +43756 0.0185546875 +43757 0.04327392578125 +43758 0.01739501953125 +43759 0.038177490234375 +43760 0.03515625 +43761 0.076263427734375 +43762 0.064544677734375 +43763 0.14105224609375 +43764 0.085235595703125 +43765 0.186431884765625 +43766 0.0867919921875 +43767 0.188812255859375 +43768 0.065185546875 +43769 0.1390380859375 +43770 0.0224609375 +43771 0.041778564453125 +43772 -0.031005859375 +43773 -0.079437255859375 +43774 -0.0928955078125 +43775 -0.219390869140625 +43776 -0.15899658203125 +43777 -0.367828369140625 +43778 -0.21661376953125 +43779 -0.494873046875 +43780 -0.2452392578125 +43781 -0.556243896484375 +43782 -0.224151611328125 +43783 -0.508697509765625 +43784 -0.164031982421875 +43785 -0.3756103515625 +43786 -0.093719482421875 +43787 -0.218902587890625 +43788 -0.0247802734375 +43789 -0.063751220703125 +43790 0.043975830078125 +43791 0.091552734375 +43792 0.107696533203125 +43793 0.23602294921875 +43794 0.15411376953125 +43795 0.342987060546875 +43796 0.17535400390625 +43797 0.39520263671875 +43798 0.16998291015625 +43799 0.389373779296875 +43800 0.137542724609375 +43801 0.324249267578125 +43802 0.08953857421875 +43803 0.224090576171875 +43804 0.042694091796875 +43805 0.124267578125 +43806 0.002716064453125 +43807 0.037078857421875 +43808 -0.017547607421875 +43809 -0.010101318359375 +43810 -0.019287109375 +43811 -0.019439697265625 +43812 -0.0177001953125 +43813 -0.022796630859375 +43814 -0.004180908203125 +43815 -0.001556396484375 +43816 0.026702880859375 +43817 0.056304931640625 +43818 0.053924560546875 +43819 0.106719970703125 +43820 0.05242919921875 +43821 0.096893310546875 +43822 0.029541015625 +43823 0.042694091796875 +43824 0.002960205078125 +43825 -0.018035888671875 +43826 -0.022918701171875 +43827 -0.07586669921875 +43828 -0.04278564453125 +43829 -0.11944580078125 +43830 -0.061859130859375 +43831 -0.15972900390625 +43832 -0.0828857421875 +43833 -0.202606201171875 +43834 -0.10601806640625 +43835 -0.24859619140625 +43836 -0.134674072265625 +43837 -0.30517578125 +43838 -0.1639404296875 +43839 -0.36212158203125 +43840 -0.180450439453125 +43841 -0.39141845703125 +43842 -0.16619873046875 +43843 -0.35528564453125 +43844 -0.1192626953125 +43845 -0.249969482421875 +43846 -0.0477294921875 +43847 -0.092864990234375 +43848 0.035797119140625 +43849 0.08905029296875 +43850 0.102874755859375 +43851 0.2352294921875 +43852 0.140899658203125 +43853 0.318817138671875 +43854 0.1588134765625 +43855 0.358642578125 +43856 0.15338134765625 +43857 0.347747802734375 +43858 0.1243896484375 +43859 0.28564453125 +43860 0.09576416015625 +43861 0.223175048828125 +43862 0.084625244140625 +43863 0.196746826171875 +43864 0.078399658203125 +43865 0.179840087890625 +43866 0.069000244140625 +43867 0.155548095703125 +43868 0.069183349609375 +43869 0.151214599609375 +43870 0.074188232421875 +43871 0.156951904296875 +43872 0.06451416015625 +43873 0.13177490234375 +43874 0.051910400390625 +43875 0.100799560546875 +43876 0.04718017578125 +43877 0.087127685546875 +43878 0.0333251953125 +43879 0.05487060546875 +43880 0.004119873046875 +43881 -0.009002685546875 +43882 -0.040252685546875 +43883 -0.10400390625 +43884 -0.099456787109375 +43885 -0.229400634765625 +43886 -0.159454345703125 +43887 -0.35552978515625 +43888 -0.20111083984375 +43889 -0.441925048828125 +43890 -0.217437744140625 +43891 -0.473846435546875 +43892 -0.2147216796875 +43893 -0.464813232421875 +43894 -0.19488525390625 +43895 -0.419097900390625 +43896 -0.156707763671875 +43897 -0.334320068359375 +43898 -0.1082763671875 +43899 -0.227935791015625 +43900 -0.060638427734375 +43901 -0.12347412109375 +43902 -0.01690673828125 +43903 -0.02764892578125 +43904 0.03155517578125 +43905 0.077667236328125 +43906 0.0946044921875 +43907 0.2132568359375 +43908 0.1768798828125 +43909 0.38885498046875 +43910 0.2681884765625 +43911 0.582794189453125 +43912 0.3397216796875 +43913 0.734039306640625 +43914 0.371429443359375 +43915 0.800140380859375 +43916 0.361968994140625 +43917 0.7783203125 +43918 0.309661865234375 +43919 0.6651611328125 +43920 0.2139892578125 +43921 0.45965576171875 +43922 0.092529296875 +43923 0.199188232421875 +43924 -0.02386474609375 +43925 -0.050689697265625 +43926 -0.108367919921875 +43927 -0.23297119140625 +43928 -0.15283203125 +43929 -0.33013916015625 +43930 -0.169677734375 +43931 -0.368408203125 +43932 -0.173675537109375 +43933 -0.378936767578125 +43934 -0.172088623046875 +43935 -0.376983642578125 +43936 -0.173065185546875 +43937 -0.37969970703125 +43938 -0.178680419921875 +43939 -0.391510009765625 +43940 -0.176116943359375 +43941 -0.385345458984375 +43942 -0.15625 +43943 -0.3419189453125 +43944 -0.1292724609375 +43945 -0.28289794921875 +43946 -0.115570068359375 +43947 -0.251617431640625 +43948 -0.12359619140625 +43949 -0.266143798828125 +43950 -0.12823486328125 +43951 -0.273345947265625 +43952 -0.102752685546875 +43953 -0.216796875 +43954 -0.06207275390625 +43955 -0.128265380859375 +43956 -0.03466796875 +43957 -0.068145751953125 +43958 -0.02362060546875 +43959 -0.0430908203125 +43960 -0.015380859375 +43961 -0.024444580078125 +43962 0.005615234375 +43963 0.020721435546875 +43964 0.05450439453125 +43965 0.124481201171875 +43966 0.117584228515625 +43967 0.25787353515625 +43968 0.175140380859375 +43969 0.379119873046875 +43970 0.223236083984375 +43971 0.47991943359375 +43972 0.2467041015625 +43973 0.5281982421875 +43974 0.239471435546875 +43975 0.511138916015625 +43976 0.214447021484375 +43977 0.456207275390625 +43978 0.192352294921875 +43979 0.407470703125 +43980 0.182037353515625 +43981 0.383758544921875 +43982 0.170135498046875 +43983 0.35687255859375 +43984 0.1495361328125 +43985 0.31182861328125 +43986 0.121246337890625 +43987 0.250885009765625 +43988 0.081207275390625 +43989 0.1654052734375 +43990 0.019927978515625 +43991 0.035247802734375 +43992 -0.063751220703125 +43993 -0.142059326171875 +43994 -0.155242919921875 +43995 -0.33563232421875 +43996 -0.249420166015625 +43997 -0.5345458984375 +43998 -0.3382568359375 +43999 -0.72186279296875 +44000 -0.392974853515625 +44001 -0.836669921875 +44002 -0.391693115234375 +44003 -0.8326416015625 +44004 -0.343719482421875 +44005 -0.7296142578125 +44006 -0.27496337890625 +44007 -0.582550048828125 +44008 -0.208343505859375 +44009 -0.440093994140625 +44010 -0.154266357421875 +44011 -0.324310302734375 +44012 -0.09674072265625 +44013 -0.20147705078125 +44014 -0.02301025390625 +44015 -0.044647216796875 +44016 0.04693603515625 +44017 0.103973388671875 +44018 0.093292236328125 +44019 0.202392578125 +44020 0.122650146484375 +44021 0.264495849609375 +44022 0.157928466796875 +44023 0.338897705078125 +44024 0.20770263671875 +44025 0.443817138671875 +44026 0.255859375 +44027 0.545074462890625 +44028 0.290374755859375 +44029 0.6173095703125 +44030 0.30743408203125 +44031 0.6524658203125 +44032 0.31341552734375 +44033 0.66339111328125 +44034 0.311309814453125 +44035 0.6561279296875 +44036 0.289154052734375 +44037 0.606781005859375 +44038 0.239654541015625 +44039 0.501190185546875 +44040 0.169342041015625 +44041 0.352783203125 +44042 0.085479736328125 +44043 0.176544189453125 +44044 -0.015899658203125 +44045 -0.034820556640625 +44046 -0.123443603515625 +44047 -0.258209228515625 +44048 -0.211669921875 +44049 -0.44244384765625 +44050 -0.274658203125 +44051 -0.5753173828125 +44052 -0.31024169921875 +44053 -0.65203857421875 +44054 -0.302978515625 +44055 -0.641632080078125 +44056 -0.262054443359375 +44057 -0.562164306640625 +44058 -0.20989990234375 +44059 -0.458038330078125 +44060 -0.15716552734375 +44061 -0.350555419921875 +44062 -0.114227294921875 +44063 -0.260528564453125 +44064 -0.083038330078125 +44065 -0.192108154296875 +44066 -0.06170654296875 +44067 -0.141937255859375 +44068 -0.046051025390625 +44069 -0.1021728515625 +44070 -0.030792236328125 +44071 -0.062896728515625 +44072 -0.009552001953125 +44073 -0.011932373046875 +44074 0.02398681640625 +44075 0.062835693359375 +44076 0.063690185546875 +44077 0.148712158203125 +44078 0.107696533203125 +44079 0.241729736328125 +44080 0.159820556640625 +44081 0.34912109375 +44082 0.2132568359375 +44083 0.457305908203125 +44084 0.25677490234375 +44085 0.54388427734375 +44086 0.272216796875 +44087 0.5728759765625 +44088 0.240509033203125 +44089 0.506591796875 +44090 0.1646728515625 +44091 0.351226806640625 +44092 0.0645751953125 +44093 0.146514892578125 +44094 -0.033599853515625 +44095 -0.05523681640625 +44096 -0.11102294921875 +44097 -0.21624755859375 +44098 -0.167083740234375 +44099 -0.334930419921875 +44100 -0.19781494140625 +44101 -0.402984619140625 +44102 -0.21392822265625 +44103 -0.4412841796875 +44104 -0.238739013671875 +44105 -0.49578857421875 +44106 -0.269195556640625 +44107 -0.5601806640625 +44108 -0.288360595703125 +44109 -0.600738525390625 +44110 -0.279571533203125 +44111 -0.584228515625 +44112 -0.227020263671875 +44113 -0.47930908203125 +44114 -0.127349853515625 +44115 -0.27935791015625 +44116 0.007110595703125 +44117 -0.0089111328125 +44118 0.1446533203125 +44119 0.268798828125 +44120 0.249664306640625 +44121 0.482818603515625 +44122 0.307464599609375 +44123 0.60369873046875 +44124 0.3277587890625 +44125 0.650421142578125 +44126 0.331451416015625 +44127 0.66400146484375 +44128 0.31719970703125 +44129 0.6414794921875 +44130 0.279998779296875 +44131 0.572540283203125 +44132 0.2406005859375 +44133 0.498138427734375 +44134 0.209747314453125 +44135 0.439453125 +44136 0.176910400390625 +44137 0.375518798828125 +44138 0.126068115234375 +44139 0.274505615234375 +44140 0.04327392578125 +44141 0.1087646484375 +44142 -0.060272216796875 +44143 -0.099395751953125 +44144 -0.16864013671875 +44145 -0.3182373046875 +44146 -0.2825927734375 +44147 -0.5489501953125 +44148 -0.393280029296875 +44149 -0.7738037109375 +44150 -0.474212646484375 +44151 -0.86383056640625 +44152 -0.5087890625 +44153 -0.870391845703125 +44154 -0.506072998046875 +44155 -0.86895751953125 +44156 -0.472808837890625 +44157 -0.861053466796875 +44158 -0.400390625 +44159 -0.765869140625 +44160 -0.283203125 +44161 -0.5301513671875 +44162 -0.124908447265625 +44163 -0.214691162109375 +44164 0.052764892578125 +44165 0.137359619140625 +44166 0.223968505859375 +44167 0.474822998046875 +44168 0.370819091796875 +44169 0.76239013671875 +44170 0.479766845703125 +44171 0.867462158203125 +44172 0.5511474609375 +44173 0.870361328125 +44174 0.579254150390625 +44175 0.86480712890625 +44176 0.56689453125 +44177 0.831817626953125 +44178 0.5264892578125 +44179 0.677581787109375 +44180 0.4610595703125 +44181 0.495880126953125 +44182 0.380096435546875 +44183 0.30767822265625 +44184 0.28485107421875 +44185 0.116180419921875 +44186 0.15936279296875 +44187 -0.110748291015625 +44188 0.000213623046875 +44189 -0.381805419921875 +44190 -0.170989990234375 +44191 -0.6572265625 +44192 -0.32403564453125 +44193 -0.857421875 +44194 -0.43731689453125 +44195 -0.870391845703125 +44196 -0.50726318359375 +44197 -0.870391845703125 +44198 -0.5474853515625 +44199 -0.86444091796875 +44200 -0.576080322265625 +44201 -0.85723876953125 +44202 -0.583892822265625 +44203 -0.790008544921875 +44204 -0.543701171875 +44205 -0.62847900390625 +44206 -0.454010009765625 +44207 -0.3956298828125 +44208 -0.331451416015625 +44209 -0.126708984375 +44210 -0.18994140625 +44211 0.150115966796875 +44212 -0.035430908203125 +44213 0.424041748046875 +44214 0.118408203125 +44215 0.670623779296875 +44216 0.251983642578125 +44217 0.854522705078125 +44218 0.35638427734375 +44219 0.866485595703125 +44220 0.423858642578125 +44221 0.86920166015625 +44222 0.46356201171875 +44223 0.8653564453125 +44224 0.482330322265625 +44225 0.857147216796875 +44226 0.478729248046875 +44227 0.766845703125 +44228 0.455413818359375 +44229 0.628509521484375 +44230 0.409088134765625 +44231 0.462127685546875 +44232 0.352813720703125 +44233 0.297210693359375 +44234 0.292938232421875 +44235 0.14862060546875 +44236 0.218017578125 +44237 -0.00537109375 +44238 0.13189697265625 +44239 -0.15753173828125 +44240 0.032806396484375 +44241 -0.31304931640625 +44242 -0.08624267578125 +44243 -0.48876953125 +44244 -0.20159912109375 +44245 -0.6416015625 +44246 -0.300750732421875 +44247 -0.751373291015625 +44248 -0.395355224609375 +44249 -0.84619140625 +44250 -0.477996826171875 +44251 -0.861297607421875 +44252 -0.532012939453125 +44253 -0.863250732421875 +44254 -0.54150390625 +44255 -0.856597900390625 +44256 -0.512664794921875 +44257 -0.7498779296875 +44258 -0.4747314453125 +44259 -0.624542236328125 +44260 -0.41668701171875 +44261 -0.47808837890625 +44262 -0.30914306640625 +44263 -0.253387451171875 +44264 -0.175201416015625 +44265 0.003692626953125 +44266 -0.04937744140625 +44267 0.2257080078125 +44268 0.074554443359375 +44269 0.427154541015625 +44270 0.212860107421875 +44271 0.643218994140625 +44272 0.36065673828125 +44273 0.855926513671875 +44274 0.488739013671875 +44275 0.870361328125 +44276 0.57208251953125 +44277 0.870361328125 +44278 0.614288330078125 +44279 0.862762451171875 +44280 0.6138916015625 +44281 0.79669189453125 +44282 0.566192626953125 +44283 0.595794677734375 +44284 0.4859619140625 +44285 0.362152099609375 +44286 0.38739013671875 +44287 0.1270751953125 +44288 0.281768798828125 +44289 -0.086944580078125 +44290 0.17059326171875 +44291 -0.2784423828125 +44292 0.034942626953125 +44293 -0.484832763671875 +44294 -0.136199951171875 +44295 -0.729583740234375 +44296 -0.316375732421875 +44297 -0.86688232421875 +44298 -0.47222900390625 +44299 -0.870391845703125 +44300 -0.60150146484375 +44301 -0.86859130859375 +44302 -0.703338623046875 +44303 -0.86279296875 +44304 -0.75860595703125 +44305 -0.817962646484375 +44306 -0.74298095703125 +44307 -0.6116943359375 +44308 -0.65252685546875 +44309 -0.3128662109375 +44310 -0.505126953125 +44311 0.039398193359375 +44312 -0.31121826171875 +44313 0.422821044921875 +44314 -0.08831787109375 +44315 0.805145263671875 +44316 0.12738037109375 +44317 0.870361328125 +44318 0.3056640625 +44319 0.870361328125 +44320 0.440582275390625 +44321 0.860015869140625 +44322 0.528289794921875 +44323 0.727935791015625 +44324 0.565948486328125 +44325 0.48114013671875 +44326 0.566680908203125 +44327 0.2059326171875 +44328 0.542694091796875 +44329 -0.06103515625 +44330 0.499359130859375 +44331 -0.29913330078125 +44332 0.42889404296875 +44333 -0.516204833984375 +44334 0.322998046875 +44335 -0.7252197265625 +44336 0.19488525390625 +44337 -0.85980224609375 +44338 0.0628662109375 +44339 -0.870391845703125 +44340 -0.057281494140625 +44341 -0.870391845703125 +44342 -0.1395263671875 +44343 -0.858062744140625 +44344 -0.18170166015625 +44345 -0.673004150390625 +44346 -0.21197509765625 +44347 -0.42694091796875 +44348 -0.254180908203125 +44349 -0.2100830078125 +44350 -0.30718994140625 +44351 -0.0362548828125 +44352 -0.355377197265625 +44353 0.10943603515625 +44354 -0.388031005859375 +44355 0.23516845703125 +44356 -0.382904052734375 +44357 0.373687744140625 +44358 -0.340972900390625 +44359 0.517791748046875 +44360 -0.29595947265625 +44361 0.602783203125 +44362 -0.24505615234375 +44363 0.635711669921875 +44364 -0.17034912109375 +44365 0.655181884765625 +44366 -0.077178955078125 +44367 0.65948486328125 +44368 0.030120849609375 +44369 0.651275634765625 +44370 0.138427734375 +44371 0.61846923828125 +44372 0.22784423828125 +44373 0.53753662109375 +44374 0.288604736328125 +44375 0.404144287109375 +44376 0.3154296875 +44377 0.22186279296875 +44378 0.30889892578125 +44379 0.003997802734375 +44380 0.278656005859375 +44381 -0.22100830078125 +44382 0.235687255859375 +44383 -0.42449951171875 +44384 0.191375732421875 +44385 -0.579833984375 +44386 0.168548583984375 +44387 -0.641876220703125 +44388 0.16363525390625 +44389 -0.6177978515625 +44390 0.141998291015625 +44391 -0.575531005859375 +44392 0.100799560546875 +44393 -0.526336669921875 +44394 0.06781005859375 +44395 -0.42645263671875 +44396 0.05780029296875 +44397 -0.2581787109375 +44398 0.05133056640625 +44399 -0.068695068359375 +44400 0.027862548828125 +44401 0.09222412109375 +44402 -0.00250244140625 +44403 0.232147216796875 +44404 -0.034210205078125 +44405 0.3509521484375 +44406 -0.083038330078125 +44407 0.410064697265625 +44408 -0.164581298828125 +44409 0.372955322265625 +44410 -0.26751708984375 +44411 0.2554931640625 +44412 -0.363800048828125 +44413 0.10711669921875 +44414 -0.44287109375 +44415 -0.052886962890625 +44416 -0.4852294921875 +44417 -0.186279296875 +44418 -0.46087646484375 +44419 -0.23291015625 +44420 -0.382049560546875 +44421 -0.209442138671875 +44422 -0.2840576171875 +44423 -0.174163818359375 +44424 -0.171417236328125 +44425 -0.126739501953125 +44426 -0.0389404296875 +44427 -0.048126220703125 +44428 0.09814453125 +44429 0.0426025390625 +44430 0.2147216796875 +44431 0.10748291015625 +44432 0.303558349609375 +44433 0.1409912109375 +44434 0.3900146484375 +44435 0.19708251953125 +44436 0.470306396484375 +44437 0.273651123046875 +44438 0.514404296875 +44439 0.31768798828125 +44440 0.528106689453125 +44441 0.341094970703125 +44442 0.52484130859375 +44443 0.368011474609375 +44444 0.4921875 +44445 0.37249755859375 +44446 0.403717041015625 +44447 0.30072021484375 +44448 0.2620849609375 +44449 0.1517333984375 +44450 0.102996826171875 +44451 -0.01470947265625 +44452 -0.06396484375 +44453 -0.1883544921875 +44454 -0.236541748046875 +44455 -0.372711181640625 +44456 -0.38189697265625 +44457 -0.51397705078125 +44458 -0.474700927734375 +44459 -0.57177734375 +44460 -0.508270263671875 +44461 -0.53948974609375 +44462 -0.489776611328125 +44463 -0.43511962890625 +44464 -0.437744140625 +44465 -0.2962646484375 +44466 -0.371826171875 +44467 -0.161102294921875 +44468 -0.299591064453125 +44469 -0.0435791015625 +44470 -0.219818115234375 +44471 0.060394287109375 +44472 -0.141815185546875 +44473 0.13665771484375 +44474 -0.0760498046875 +44475 0.170135498046875 +44476 -0.022918701171875 +44477 0.16552734375 +44478 0.032745361328125 +44479 0.15728759765625 +44480 0.0904541015625 +44481 0.150787353515625 +44482 0.133941650390625 +44483 0.12200927734375 +44484 0.164947509765625 +44485 0.080108642578125 +44486 0.19476318359375 +44487 0.05126953125 +44488 0.235870361328125 +44489 0.062896728515625 +44490 0.274688720703125 +44491 0.09271240234375 +44492 0.284759521484375 +44493 0.092987060546875 +44494 0.27386474609375 +44495 0.07855224609375 +44496 0.250518798828125 +44497 0.06427001953125 +44498 0.20770263671875 +44499 0.0347900390625 +44500 0.146209716796875 +44501 -0.01171875 +44502 0.07861328125 +44503 -0.056060791015625 +44504 0.030426025390625 +44505 -0.055511474609375 +44506 0.004180908203125 +44507 -0.010467529296875 +44508 -0.02618408203125 +44509 0.02508544921875 +44510 -0.0716552734375 +44511 0.025665283203125 +44512 -0.11590576171875 +44513 0.017333984375 +44514 -0.155975341796875 +44515 0.00189208984375 +44516 -0.1962890625 +44517 -0.03173828125 +44518 -0.2294921875 +44519 -0.071502685546875 +44520 -0.264862060546875 +44521 -0.13543701171875 +44522 -0.30078125 +44523 -0.219970703125 +44524 -0.3248291015625 +44525 -0.300506591796875 +44526 -0.33795166015625 +44527 -0.376312255859375 +44528 -0.325103759765625 +44529 -0.416107177734375 +44530 -0.26220703125 +44531 -0.371124267578125 +44532 -0.15203857421875 +44533 -0.242279052734375 +44534 -0.01837158203125 +44535 -0.069732666015625 +44536 0.12530517578125 +44537 0.125640869140625 +44538 0.260223388671875 +44539 0.31268310546875 +44540 0.3651123046875 +44541 0.45501708984375 +44542 0.439727783203125 +44543 0.554779052734375 +44544 0.482666015625 +44545 0.61065673828125 +44546 0.487060546875 +44547 0.610931396484375 +44548 0.43939208984375 +44549 0.531463623046875 +44550 0.348846435546875 +44551 0.3883056640625 +44552 0.24554443359375 +44553 0.23468017578125 +44554 0.144287109375 +44555 0.095245361328125 +44556 0.060821533203125 +44557 -0.00396728515625 +44558 0.0047607421875 +44559 -0.04852294921875 +44560 -0.03125 +44561 -0.055145263671875 +44562 -0.07403564453125 +44563 -0.0758056640625 +44564 -0.13739013671875 +44565 -0.138702392578125 +44566 -0.200775146484375 +44567 -0.209197998046875 +44568 -0.263916015625 +44569 -0.289031982421875 +44570 -0.3262939453125 +44571 -0.37884521484375 +44572 -0.375091552734375 +44573 -0.456329345703125 +44574 -0.407379150390625 +44575 -0.51641845703125 +44576 -0.4014892578125 +44577 -0.519287109375 +44578 -0.354339599609375 +44579 -0.458251953125 +44580 -0.295166015625 +44581 -0.384796142578125 +44582 -0.238739013671875 +44583 -0.323699951171875 +44584 -0.18328857421875 +44585 -0.269287109375 +44586 -0.11578369140625 +44587 -0.1951904296875 +44588 -0.036956787109375 +44589 -0.100006103515625 +44590 0.036956787109375 +44591 -0.01055908203125 +44592 0.121307373046875 +44593 0.1033935546875 +44594 0.218963623046875 +44595 0.24908447265625 +44596 0.299774169921875 +44597 0.373199462890625 +44598 0.353515625 +44599 0.45806884765625 +44600 0.384185791015625 +44601 0.511474609375 +44602 0.40948486328125 +44603 0.565399169921875 +44604 0.4251708984375 +44605 0.61138916015625 +44606 0.399078369140625 +44607 0.5897216796875 +44608 0.32672119140625 +44609 0.4906005859375 +44610 0.21875 +44611 0.33148193359375 +44612 0.095855712890625 +44613 0.147796630859375 +44614 -0.01776123046875 +44615 -0.01873779296875 +44616 -0.1055908203125 +44617 -0.140289306640625 +44618 -0.15283203125 +44619 -0.191986083984375 +44620 -0.164276123046875 +44621 -0.184295654296875 +44622 -0.1636962890625 +44623 -0.161834716796875 +44624 -0.173675537109375 +44625 -0.166595458984375 +44626 -0.19134521484375 +44627 -0.19390869140625 +44628 -0.2060546875 +44629 -0.22442626953125 +44630 -0.22991943359375 +44631 -0.279754638671875 +44632 -0.251983642578125 +44633 -0.3389892578125 +44634 -0.24664306640625 +44635 -0.3543701171875 +44636 -0.22698974609375 +44637 -0.348175048828125 +44638 -0.197052001953125 +44639 -0.32598876953125 +44640 -0.141571044921875 +44641 -0.2581787109375 +44642 -0.058807373046875 +44643 -0.139801025390625 +44644 0.04229736328125 +44645 0.014617919921875 +44646 0.127471923828125 +44647 0.144378662109375 +44648 0.180450439453125 +44649 0.221038818359375 +44650 0.21502685546875 +44651 0.27069091796875 +44652 0.231353759765625 +44653 0.294036865234375 +44654 0.24072265625 +44655 0.311767578125 +44656 0.251708984375 +44657 0.339141845703125 +44658 0.256103515625 +44659 0.360260009765625 +44660 0.246307373046875 +44661 0.360504150390625 +44662 0.2049560546875 +44663 0.308380126953125 +44664 0.120086669921875 +44665 0.18170166015625 +44666 0.006195068359375 +44667 0.0047607421875 +44668 -0.109375 +44669 -0.17559814453125 +44670 -0.20037841796875 +44671 -0.3143310546875 +44672 -0.241455078125 +44673 -0.36785888671875 +44674 -0.24700927734375 +44675 -0.36248779296875 +44676 -0.24237060546875 +44677 -0.343536376953125 +44678 -0.222137451171875 +44679 -0.3018798828125 +44680 -0.18267822265625 +44681 -0.231414794921875 +44682 -0.115814208984375 +44683 -0.117645263671875 +44684 -0.040130615234375 +44685 0.007049560546875 +44686 0.012969970703125 +44687 0.087982177734375 +44688 0.0511474609375 +44689 0.13946533203125 +44690 0.08111572265625 +44691 0.17425537109375 +44692 0.09991455078125 +44693 0.188201904296875 +44694 0.101226806640625 +44695 0.171234130859375 +44696 0.081634521484375 +44697 0.118438720703125 +44698 0.056121826171875 +44699 0.05706787109375 +44700 0.025421142578125 +44701 -0.010711669921875 +44702 -0.014556884765625 +44703 -0.0914306640625 +44704 -0.0511474609375 +44705 -0.162322998046875 +44706 -0.068115234375 +44707 -0.194549560546875 +44708 -0.04345703125 +44709 -0.1492919921875 +44710 0.0257568359375 +44711 -0.02166748046875 +44712 0.103271484375 +44713 0.124053955078125 +44714 0.145843505859375 +44715 0.211151123046875 +44716 0.15435791015625 +44717 0.240447998046875 +44718 0.146484375 +44719 0.242218017578125 +44720 0.12799072265625 +44721 0.2257080078125 +44722 0.101348876953125 +44723 0.194366455078125 +44724 0.0484619140625 +44725 0.115509033203125 +44726 -0.016754150390625 +44727 0.0128173828125 +44728 -0.059967041015625 +44729 -0.053802490234375 +44730 -0.0958251953125 +44731 -0.110626220703125 +44732 -0.147979736328125 +44733 -0.199493408203125 +44734 -0.20159912109375 +44735 -0.29437255859375 +44736 -0.220947265625 +44737 -0.33221435546875 +44738 -0.187286376953125 +44739 -0.27972412109375 +44740 -0.128387451171875 +44741 -0.185333251953125 +44742 -0.089508056640625 +44743 -0.128204345703125 +44744 -0.075225830078125 +44745 -0.115692138671875 +44746 -0.068145751953125 +44747 -0.116455078125 +44748 -0.054718017578125 +44749 -0.105926513671875 +44750 -0.01824951171875 +44751 -0.053955078125 +44752 0.046173095703125 +44753 0.048797607421875 +44754 0.112701416015625 +44755 0.157318115234375 +44756 0.147247314453125 +44757 0.212005615234375 +44758 0.15283203125 +44759 0.218475341796875 +44760 0.163787841796875 +44761 0.23724365234375 +44762 0.201202392578125 +44763 0.30535888671875 +44764 0.241546630859375 +44765 0.38128662109375 +44766 0.2506103515625 +44767 0.404449462890625 +44768 0.239776611328125 +44769 0.3944091796875 +44770 0.2305908203125 +44771 0.3885498046875 +44772 0.20965576171875 +44773 0.362640380859375 +44774 0.152862548828125 +44775 0.27362060546875 +44776 0.058074951171875 +44777 0.11712646484375 +44778 -0.044891357421875 +44779 -0.054901123046875 +44780 -0.126434326171875 +44781 -0.19085693359375 +44782 -0.183502197265625 +44783 -0.28570556640625 +44784 -0.21588134765625 +44785 -0.339263916015625 +44786 -0.23828125 +44787 -0.3775634765625 +44788 -0.27630615234375 +44789 -0.445709228515625 +44790 -0.325103759765625 +44791 -0.535064697265625 +44792 -0.37542724609375 +44793 -0.629058837890625 +44794 -0.410369873046875 +44795 -0.697601318359375 +44796 -0.409271240234375 +44797 -0.70391845703125 +44798 -0.369293212890625 +44799 -0.6424560546875 +44800 -0.27777099609375 +44801 -0.491241455078125 +44802 -0.143585205078125 +44803 -0.265716552734375 +44804 -0.0006103515625 +44805 -0.023712158203125 +44806 0.131622314453125 +44807 0.201751708984375 +44808 0.232513427734375 +44809 0.375823974609375 +44810 0.294281005859375 +44811 0.485076904296875 +44812 0.340789794921875 +44813 0.56884765625 +44814 0.376861572265625 +44815 0.634765625 +44816 0.37554931640625 +44817 0.63763427734375 +44818 0.33013916015625 +44819 0.5660400390625 +44820 0.27197265625 +44821 0.4720458984375 +44822 0.23187255859375 +44823 0.40692138671875 +44824 0.214141845703125 +44825 0.3778076171875 +44826 0.214080810546875 +44827 0.376953125 +44828 0.21221923828125 +44829 0.371978759765625 +44830 0.178619384765625 +44831 0.313140869140625 +44832 0.103546142578125 +44833 0.184417724609375 +44834 0.002105712890625 +44835 0.011199951171875 +44836 -0.10455322265625 +44837 -0.171051025390625 +44838 -0.20166015625 +44839 -0.33740234375 +44840 -0.279815673828125 +44841 -0.47198486328125 +44842 -0.33050537109375 +44843 -0.560394287109375 +44844 -0.34063720703125 +44845 -0.58056640625 +44846 -0.3193359375 +44847 -0.54754638671875 +44848 -0.295013427734375 +44849 -0.508575439453125 +44850 -0.265228271484375 +44851 -0.459503173828125 +44852 -0.226409912109375 +44853 -0.394378662109375 +44854 -0.202117919921875 +44855 -0.35260009765625 +44856 -0.1788330078125 +44857 -0.31170654296875 +44858 -0.111907958984375 +44859 -0.197418212890625 +44860 -0.000152587890625 +44861 -0.007965087890625 +44862 0.126983642578125 +44863 0.207489013671875 +44864 0.24578857421875 +44865 0.409210205078125 +44866 0.34130859375 +44867 0.57208251953125 +44868 0.395599365234375 +44869 0.66595458984375 +44870 0.389495849609375 +44871 0.65875244140625 +44872 0.333282470703125 +44873 0.56744384765625 +44874 0.25067138671875 +44875 0.431396484375 +44876 0.16796875 +44877 0.29443359375 +44878 0.10076904296875 +44879 0.182464599609375 +44880 0.029937744140625 +44881 0.06365966796875 +44882 -0.05291748046875 +44883 -0.075958251953125 +44884 -0.119720458984375 +44885 -0.189422607421875 +44886 -0.167633056640625 +44887 -0.271942138671875 +44888 -0.208160400390625 +44889 -0.342529296875 +44890 -0.21923828125 +44891 -0.364166259765625 +44892 -0.1951904296875 +44893 -0.327239990234375 +44894 -0.163238525390625 +44895 -0.2769775390625 +44896 -0.147705078125 +44897 -0.253692626953125 +44898 -0.140380859375 +44899 -0.24365234375 +44900 -0.112274169921875 +44901 -0.1983642578125 +44902 -0.06243896484375 +44903 -0.116241455078125 +44904 -0.0146484375 +44905 -0.036834716796875 +44906 0.028106689453125 +44907 0.034881591796875 +44908 0.061279296875 +44909 0.09124755859375 +44910 0.07086181640625 +44911 0.10888671875 +44912 0.079559326171875 +44913 0.125518798828125 +44914 0.097412109375 +44915 0.15771484375 +44916 0.108154296875 +44917 0.17828369140625 +44918 0.102203369140625 +44919 0.17108154296875 +44920 0.07598876953125 +44921 0.129974365234375 +44922 0.046051025390625 +44923 0.082427978515625 +44924 0.01202392578125 +44925 0.027679443359375 +44926 -0.04486083984375 +44927 -0.065643310546875 +44928 -0.101654052734375 +44929 -0.15936279296875 +44930 -0.134063720703125 +44931 -0.21307373046875 +44932 -0.1468505859375 +44933 -0.234649658203125 +44934 -0.12567138671875 +44935 -0.2001953125 +44936 -0.076263427734375 +44937 -0.119171142578125 +44938 -0.0185546875 +44939 -0.024749755859375 +44940 0.048980712890625 +44941 0.085784912109375 +44942 0.105712890625 +44943 0.178131103515625 +44944 0.129547119140625 +44945 0.215576171875 +44946 0.12835693359375 +44947 0.211456298828125 +44948 0.1077880859375 +44949 0.17523193359375 +44950 0.080902099609375 +44951 0.128753662109375 +44952 0.065582275390625 +44953 0.1019287109375 +44954 0.049560546875 +44955 0.0743408203125 +44956 0.03118896484375 +44957 0.04327392578125 +44958 0.028106689453125 +44959 0.038177490234375 +44960 0.0506591796875 +44961 0.076263427734375 +44962 0.088958740234375 +44963 0.14105224609375 +44964 0.115386962890625 +44965 0.186431884765625 +44966 0.1158447265625 +44967 0.188812255859375 +44968 0.084869384765625 +44969 0.1390380859375 +44970 0.025360107421875 +44971 0.041778564453125 +44972 -0.0484619140625 +44973 -0.079437255859375 +44974 -0.133453369140625 +44975 -0.219390869140625 +44976 -0.223358154296875 +44977 -0.367828369140625 +44978 -0.300262451171875 +44979 -0.494873046875 +44980 -0.337554931640625 +44981 -0.556243896484375 +44982 -0.309234619140625 +44983 -0.508697509765625 +44984 -0.229339599609375 +44985 -0.3756103515625 +44986 -0.135040283203125 +44987 -0.218902587890625 +44988 -0.041473388671875 +44989 -0.063751220703125 +44990 0.05230712890625 +44991 0.091552734375 +44992 0.13970947265625 +44993 0.23602294921875 +44994 0.204681396484375 +44995 0.342987060546875 +44996 0.236846923828125 +44997 0.39520263671875 +44998 0.234161376953125 +44999 0.389373779296875 +45000 0.19586181640625 +45001 0.324249267578125 +45002 0.136444091796875 +45003 0.224090576171875 +45004 0.077117919921875 +45005 0.124267578125 +45006 0.02520751953125 +45007 0.037078857421875 +45008 -0.002838134765625 +45009 -0.010101318359375 +45010 -0.00836181640625 +45011 -0.019439697265625 +45012 -0.01043701171875 +45013 -0.022796630859375 +45014 0.0020751953125 +45015 -0.001556396484375 +45016 0.036407470703125 +45017 0.056304931640625 +45018 0.066131591796875 +45019 0.106719970703125 +45020 0.059600830078125 +45021 0.096893310546875 +45022 0.026397705078125 +45023 0.042694091796875 +45024 -0.010772705078125 +45025 -0.018035888671875 +45026 -0.046173095703125 +45027 -0.07586669921875 +45028 -0.07293701171875 +45029 -0.11944580078125 +45030 -0.09765625 +45031 -0.15972900390625 +45032 -0.123809814453125 +45033 -0.202606201171875 +45034 -0.15167236328125 +45035 -0.24859619140625 +45036 -0.185699462890625 +45037 -0.30517578125 +45038 -0.21978759765625 +45039 -0.36212158203125 +45040 -0.237152099609375 +45041 -0.39141845703125 +45042 -0.215087890625 +45043 -0.35528564453125 +45044 -0.151397705078125 +45045 -0.249969482421875 +45046 -0.05657958984375 +45047 -0.092864990234375 +45048 0.053131103515625 +45049 0.08905029296875 +45050 0.141387939453125 +45051 0.2352294921875 +45052 0.192047119140625 +45053 0.318817138671875 +45054 0.21636962890625 +45055 0.358642578125 +45056 0.2095947265625 +45057 0.347747802734375 +45058 0.170745849609375 +45059 0.28564453125 +45060 0.13153076171875 +45061 0.223175048828125 +45062 0.11517333984375 +45063 0.196746826171875 +45064 0.1051025390625 +45065 0.179840087890625 +45066 0.090728759765625 +45067 0.155548095703125 +45068 0.08935546875 +45069 0.151214599609375 +45070 0.0947265625 +45071 0.156951904296875 +45072 0.080841064453125 +45073 0.13177490234375 +45074 0.0634765625 +45075 0.100799560546875 +45076 0.057098388671875 +45077 0.087127685546875 +45078 0.038909912109375 +45079 0.05487060546875 +45080 0.000518798828125 +45081 -0.009002685546875 +45082 -0.057861328125 +45083 -0.10400390625 +45084 -0.1358642578125 +45085 -0.229400634765625 +45086 -0.214813232421875 +45087 -0.35552978515625 +45088 -0.2691650390625 +45089 -0.441925048828125 +45090 -0.28961181640625 +45091 -0.473846435546875 +45092 -0.284698486328125 +45093 -0.464813232421875 +45094 -0.257049560546875 +45095 -0.419097900390625 +45096 -0.205078125 +45097 -0.334320068359375 +45098 -0.139739990234375 +45099 -0.227935791015625 +45100 -0.0758056640625 +45101 -0.12347412109375 +45102 -0.017364501953125 +45103 -0.02764892578125 +45104 0.047149658203125 +45105 0.077667236328125 +45106 0.130950927734375 +45107 0.2132568359375 +45108 0.24029541015625 +45109 0.38885498046875 +45110 0.361541748046875 +45111 0.582794189453125 +45112 0.456207275390625 +45113 0.734039306640625 +45114 0.49749755859375 +45115 0.800140380859375 +45116 0.483673095703125 +45117 0.7783203125 +45118 0.412567138671875 +45119 0.6651611328125 +45120 0.283538818359375 +45121 0.45965576171875 +45122 0.120147705078125 +45123 0.199188232421875 +45124 -0.0362548828125 +45125 -0.050689697265625 +45126 -0.149749755859375 +45127 -0.23297119140625 +45128 -0.209381103515625 +45129 -0.33013916015625 +45130 -0.231781005859375 +45131 -0.368408203125 +45132 -0.23675537109375 +45133 -0.378936767578125 +45134 -0.2340087890625 +45135 -0.376983642578125 +45136 -0.2344970703125 +45137 -0.37969970703125 +45138 -0.241058349609375 +45139 -0.391510009765625 +45140 -0.23663330078125 +45141 -0.385345458984375 +45142 -0.20904541015625 +45143 -0.3419189453125 +45144 -0.1719970703125 +45145 -0.28289794921875 +45146 -0.15283203125 +45147 -0.251617431640625 +45148 -0.16290283203125 +45149 -0.266143798828125 +45150 -0.1685791015625 +45151 -0.273345947265625 +45152 -0.1341552734375 +45153 -0.216796875 +45154 -0.079620361328125 +45155 -0.128265380859375 +45156 -0.0430908203125 +45157 -0.068145751953125 +45158 -0.02862548828125 +45159 -0.0430908203125 +45160 -0.018096923828125 +45161 -0.024444580078125 +45162 0.009368896484375 +45163 0.020721435546875 +45164 0.0740966796875 +45165 0.124481201171875 +45166 0.157806396484375 +45167 0.25787353515625 +45168 0.234130859375 +45169 0.379119873046875 +45170 0.2978515625 +45171 0.47991943359375 +45172 0.32867431640625 +45173 0.5281982421875 +45174 0.3184814453125 +45175 0.511138916015625 +45176 0.284576416015625 +45177 0.456207275390625 +45178 0.2547607421875 +45179 0.407470703125 +45180 0.240875244140625 +45181 0.383758544921875 +45182 0.22503662109375 +45183 0.35687255859375 +45184 0.197723388671875 +45185 0.31182861328125 +45186 0.160308837890625 +45187 0.250885009765625 +45188 0.10723876953125 +45189 0.1654052734375 +45190 0.0257568359375 +45191 0.035247802734375 +45192 -0.085723876953125 +45193 -0.142059326171875 +45194 -0.20770263671875 +45195 -0.33563232421875 +45196 -0.333282470703125 +45197 -0.5345458984375 +45198 -0.4517822265625 +45199 -0.72186279296875 +45200 -0.524658203125 +45201 -0.836669921875 +45202 -0.52264404296875 +45203 -0.8326416015625 +45204 -0.458221435546875 +45205 -0.7296142578125 +45206 -0.366119384765625 +45207 -0.582550048828125 +45208 -0.277008056640625 +45209 -0.440093994140625 +45210 -0.20477294921875 +45211 -0.324310302734375 +45212 -0.1280517578125 +45213 -0.20147705078125 +45214 -0.029754638671875 +45215 -0.044647216796875 +45216 0.0634765625 +45217 0.103973388671875 +45218 0.1251220703125 +45219 0.202392578125 +45220 0.163970947265625 +45221 0.264495849609375 +45222 0.210784912109375 +45223 0.338897705078125 +45224 0.277069091796875 +45225 0.443817138671875 +45226 0.34124755859375 +45227 0.545074462890625 +45228 0.387237548828125 +45229 0.6173095703125 +45230 0.409942626953125 +45231 0.6524658203125 +45232 0.417449951171875 +45233 0.66339111328125 +45234 0.413543701171875 +45235 0.6561279296875 +45236 0.383056640625 +45237 0.606781005859375 +45238 0.3170166015625 +45239 0.501190185546875 +45240 0.223846435546875 +45241 0.352783203125 +45242 0.113037109375 +45243 0.176544189453125 +45244 -0.020050048828125 +45245 -0.034820556640625 +45246 -0.16082763671875 +45247 -0.258209228515625 +45248 -0.2769775390625 +45249 -0.44244384765625 +45250 -0.360809326171875 +45251 -0.5753173828125 +45252 -0.4093017578125 +45253 -0.65203857421875 +45254 -0.402862548828125 +45255 -0.641632080078125 +45256 -0.3529052734375 +45257 -0.562164306640625 +45258 -0.287506103515625 +45259 -0.458038330078125 +45260 -0.220062255859375 +45261 -0.350555419921875 +45262 -0.163726806640625 +45263 -0.260528564453125 +45264 -0.121063232421875 +45265 -0.192108154296875 +45266 -0.089935302734375 +45267 -0.141937255859375 +45268 -0.065338134765625 +45269 -0.1021728515625 +45270 -0.040985107421875 +45271 -0.062896728515625 +45272 -0.009124755859375 +45273 -0.011932373046875 +45274 0.037872314453125 +45275 0.062835693359375 +45276 0.092010498046875 +45277 0.148712158203125 +45278 0.1507568359375 +45279 0.241729736328125 +45280 0.21868896484375 +45281 0.34912109375 +45282 0.2872314453125 +45283 0.457305908203125 +45284 0.342193603515625 +45285 0.54388427734375 +45286 0.36083984375 +45287 0.5728759765625 +45288 0.3193359375 +45289 0.506591796875 +45290 0.2215576171875 +45291 0.351226806640625 +45292 0.092620849609375 +45293 0.146514892578125 +45294 -0.034454345703125 +45295 -0.05523681640625 +45296 -0.13580322265625 +45297 -0.21624755859375 +45298 -0.210418701171875 +45299 -0.334930419921875 +45300 -0.253082275390625 +45301 -0.402984619140625 +45302 -0.277008056640625 +45303 -0.4412841796875 +45304 -0.311279296875 +45305 -0.49578857421875 +45306 -0.351898193359375 +45307 -0.5601806640625 +45308 -0.3775634765625 +45309 -0.600738525390625 +45310 -0.36724853515625 +45311 -0.584228515625 +45312 -0.30084228515625 +45313 -0.47930908203125 +45314 -0.173492431640625 +45315 -0.27935791015625 +45316 -0.000518798828125 +45317 -0.0089111328125 +45318 0.17681884765625 +45319 0.268798828125 +45320 0.31207275390625 +45321 0.482818603515625 +45322 0.386199951171875 +45323 0.60369873046875 +45324 0.412200927734375 +45325 0.650421142578125 +45326 0.417633056640625 +45327 0.66400146484375 +45328 0.400665283203125 +45329 0.6414794921875 +45330 0.35455322265625 +45331 0.572540283203125 +45332 0.306427001953125 +45333 0.498138427734375 +45334 0.270172119140625 +45335 0.439453125 +45336 0.231689453125 +45337 0.375518798828125 +45338 0.169525146484375 +45339 0.274505615234375 +45340 0.065032958984375 +45341 0.1087646484375 +45342 -0.067352294921875 +45343 -0.099395751953125 +45344 -0.206878662109375 +45345 -0.3182373046875 +45346 -0.35467529296875 +45347 -0.5489501953125 +45348 -0.499237060546875 +45349 -0.7738037109375 +45350 -0.60565185546875 +45351 -0.86383056640625 +45352 -0.65203857421875 +45353 -0.870391845703125 +45354 -0.6502685546875 +45355 -0.86895751953125 +45356 -0.609130859375 +45357 -0.861053466796875 +45358 -0.51708984375 +45359 -0.765869140625 +45360 -0.3665771484375 +45361 -0.5301513671875 +45362 -0.16217041015625 +45363 -0.214691162109375 +45364 0.0677490234375 +45365 0.137359619140625 +45366 0.28936767578125 +45367 0.474822998046875 +45368 0.479339599609375 +45369 0.76239013671875 +45370 0.6199951171875 +45371 0.867462158203125 +45372 0.7119140625 +45373 0.870361328125 +45374 0.747650146484375 +45375 0.86480712890625 +45376 0.73095703125 +45377 0.831817626953125 +45378 0.67816162109375 +45379 0.677581787109375 +45380 0.593231201171875 +45381 0.495880126953125 +45382 0.48858642578125 +45383 0.30767822265625 +45384 0.365692138671875 +45385 0.116180419921875 +45386 0.20343017578125 +45387 -0.110748291015625 +45388 -0.002899169921875 +45389 -0.381805419921875 +45390 -0.225006103515625 +45391 -0.6572265625 +45392 -0.42333984375 +45393 -0.857421875 +45394 -0.569580078125 +45395 -0.870391845703125 +45396 -0.6591796875 +45397 -0.870391845703125 +45398 -0.710205078125 +45399 -0.86444091796875 +45400 -0.74658203125 +45401 -0.85723876953125 +45402 -0.75628662109375 +45403 -0.790008544921875 +45404 -0.703460693359375 +45405 -0.62847900390625 +45406 -0.586090087890625 +45407 -0.3956298828125 +45408 -0.426055908203125 +45409 -0.126708984375 +45410 -0.2415771484375 +45411 0.150115966796875 +45412 -0.0404052734375 +45413 0.424041748046875 +45414 0.159576416015625 +45415 0.670623779296875 +45416 0.332763671875 +45417 0.854522705078125 +45418 0.467559814453125 +45419 0.866485595703125 +45420 0.55389404296875 +45421 0.86920166015625 +45422 0.603973388671875 +45423 0.8653564453125 +45424 0.626861572265625 +45425 0.857147216796875 +45426 0.620758056640625 +45427 0.766845703125 +45428 0.5892333984375 +45429 0.628509521484375 +45430 0.5279541015625 +45431 0.462127685546875 +45432 0.454193115234375 +45433 0.297210693359375 +45434 0.376251220703125 +45435 0.14862060546875 +45436 0.278961181640625 +45437 -0.00537109375 +45438 0.167327880859375 +45439 -0.15753173828125 +45440 0.038909912109375 +45441 -0.31304931640625 +45442 -0.115631103515625 +45443 -0.48876953125 +45444 -0.2652587890625 +45445 -0.6416015625 +45446 -0.3936767578125 +45447 -0.751373291015625 +45448 -0.51629638671875 +45449 -0.84619140625 +45450 -0.62347412109375 +45451 -0.861297607421875 +45452 -0.693328857421875 +45453 -0.863250732421875 +45454 -0.70501708984375 +45455 -0.856597900390625 +45456 -0.66668701171875 +45457 -0.7498779296875 +45458 -0.61688232421875 +45459 -0.624542236328125 +45460 -0.541046142578125 +45461 -0.47808837890625 +45462 -0.400421142578125 +45463 -0.253387451171875 +45464 -0.225372314453125 +45465 0.003692626953125 +45466 -0.061279296875 +45467 0.2257080078125 +45468 0.10015869140625 +45469 0.427154541015625 +45470 0.280517578125 +45471 0.643218994140625 +45472 0.47344970703125 +45473 0.855926513671875 +45474 0.6405029296875 +45475 0.870361328125 +45476 0.74884033203125 +45477 0.870361328125 +45478 0.803314208984375 +45479 0.862762451171875 +45480 0.80206298828125 +45481 0.79669189453125 +45482 0.7388916015625 +45483 0.595794677734375 +45484 0.63323974609375 +45485 0.362152099609375 +45486 0.503814697265625 +45487 0.1270751953125 +45488 0.36474609375 +45489 -0.086944580078125 +45490 0.21746826171875 +45491 -0.2784423828125 +45492 0.038909912109375 +45493 -0.484832763671875 +45494 -0.18359375 +45495 -0.729583740234375 +45496 -0.416412353515625 +45497 -0.86688232421875 +45498 -0.617462158203125 +45499 -0.870391845703125 +45500 -0.78350830078125 +45501 -0.86859130859375 +45502 -0.86090087890625 +45503 -0.86279296875 +45504 -0.86846923828125 +45505 -0.817962646484375 +45506 -0.866180419921875 +45507 -0.6116943359375 +45508 -0.845306396484375 +45509 -0.3128662109375 +45510 -0.65655517578125 +45511 0.039398193359375 +45512 -0.408538818359375 +45513 0.422821044921875 +45514 -0.123504638671875 +45515 0.805145263671875 +45516 0.153228759765625 +45517 0.870361328125 +45518 0.3836669921875 +45519 0.870361328125 +45520 0.55987548828125 +45521 0.860015869140625 +45522 0.676605224609375 +45523 0.727935791015625 +45524 0.72991943359375 +45525 0.48114013671875 +45526 0.73577880859375 +45527 0.2059326171875 +45528 0.70904541015625 +45529 -0.06103515625 +45530 0.656280517578125 +45531 -0.29913330078125 +45532 0.56781005859375 +45533 -0.516204833984375 +45534 0.4334716796875 +45535 -0.7252197265625 +45536 0.269866943359375 +45537 -0.85980224609375 +45538 0.100006103515625 +45539 -0.870391845703125 +45540 -0.056182861328125 +45541 -0.870391845703125 +45542 -0.166046142578125 +45543 -0.858062744140625 +45544 -0.226409912109375 +45545 -0.673004150390625 +45546 -0.271759033203125 +45547 -0.42694091796875 +45548 -0.331146240234375 +45549 -0.2100830078125 +45550 -0.402801513671875 +45551 -0.0362548828125 +45552 -0.46710205078125 +45553 0.10943603515625 +45554 -0.51055908203125 +45555 0.23516845703125 +45556 -0.505523681640625 +45557 0.373687744140625 +45558 -0.45318603515625 +45559 0.517791748046875 +45560 -0.3953857421875 +45561 0.602783203125 +45562 -0.32879638671875 +45563 0.635711669921875 +45564 -0.231475830078125 +45565 0.655181884765625 +45566 -0.11029052734375 +45567 0.65948486328125 +45568 0.02935791015625 +45569 0.651275634765625 +45570 0.170745849609375 +45571 0.61846923828125 +45572 0.288299560546875 +45573 0.53753662109375 +45574 0.369232177734375 +45575 0.404144287109375 +45576 0.406524658203125 +45577 0.22186279296875 +45578 0.4007568359375 +45579 0.003997802734375 +45580 0.36419677734375 +45581 -0.22100830078125 +45582 0.31097412109375 +45583 -0.42449951171875 +45584 0.25567626953125 +45585 -0.579833984375 +45586 0.227874755859375 +45587 -0.641876220703125 +45588 0.2227783203125 +45589 -0.6177978515625 +45590 0.19537353515625 +45591 -0.575531005859375 +45592 0.14190673828125 +45593 -0.526336669921875 +45594 0.0985107421875 +45595 -0.42645263671875 +45596 0.084381103515625 +45597 -0.2581787109375 +45598 0.074371337890625 +45599 -0.068695068359375 +45600 0.0418701171875 +45601 0.09222412109375 +45602 0.0001220703125 +45603 0.232147216796875 +45604 -0.043487548828125 +45605 0.3509521484375 +45606 -0.10931396484375 +45607 0.410064697265625 +45608 -0.217498779296875 +45609 0.372955322265625 +45610 -0.35321044921875 +45611 0.2554931640625 +45612 -0.47991943359375 +45613 0.10711669921875 +45614 -0.58380126953125 +45615 -0.052886962890625 +45616 -0.6395263671875 +45617 -0.186279296875 +45618 -0.608154296875 +45619 -0.23291015625 +45620 -0.5054931640625 +45621 -0.209442138671875 +45622 -0.377471923828125 +45623 -0.174163818359375 +45624 -0.230010986328125 +45625 -0.126739501953125 +45626 -0.056396484375 +45627 -0.048126220703125 +45628 0.123504638671875 +45629 0.0426025390625 +45630 0.276947021484375 +45631 0.10748291015625 +45632 0.3944091796875 +45633 0.1409912109375 +45634 0.508697509765625 +45635 0.19708251953125 +45636 0.614837646484375 +45637 0.273651123046875 +45638 0.673675537109375 +45639 0.31768798828125 +45640 0.69268798828125 +45641 0.341094970703125 +45642 0.68927001953125 +45643 0.368011474609375 +45644 0.647247314453125 +45645 0.37249755859375 +45646 0.53228759765625 +45647 0.30072021484375 +45648 0.34783935546875 +45649 0.1517333984375 +45650 0.14031982421875 +45651 -0.01470947265625 +45652 -0.0777587890625 +45653 -0.1883544921875 +45654 -0.30340576171875 +45655 -0.372711181640625 +45656 -0.493865966796875 +45657 -0.51397705078125 +45658 -0.616119384765625 +45659 -0.57177734375 +45660 -0.661407470703125 +45661 -0.53948974609375 +45662 -0.639007568359375 +45663 -0.43511962890625 +45664 -0.57281494140625 +45665 -0.2962646484375 +45666 -0.488311767578125 +45667 -0.161102294921875 +45668 -0.395294189453125 +45669 -0.0435791015625 +45670 -0.292144775390625 +45671 0.060394287109375 +45672 -0.190948486328125 +45673 0.13665771484375 +45674 -0.10528564453125 +45675 0.170135498046875 +45676 -0.03570556640625 +45677 0.16552734375 +45678 0.037506103515625 +45679 0.15728759765625 +45680 0.11358642578125 +45681 0.150787353515625 +45682 0.17138671875 +45683 0.12200927734375 +45684 0.213104248046875 +45685 0.080108642578125 +45686 0.253265380859375 +45687 0.05126953125 +45688 0.308013916015625 +45689 0.062896728515625 +45690 0.35968017578125 +45691 0.09271240234375 +45692 0.373809814453125 +45693 0.092987060546875 +45694 0.360443115234375 +45695 0.07855224609375 +45696 0.33062744140625 +45697 0.06427001953125 +45698 0.27520751953125 +45699 0.0347900390625 +45700 0.195220947265625 +45701 -0.01171875 +45702 0.10699462890625 +45703 -0.056060791015625 +45704 0.043670654296875 +45705 -0.055511474609375 +45706 0.008636474609375 +45707 -0.010467529296875 +45708 -0.031951904296875 +45709 0.02508544921875 +45710 -0.092254638671875 +45711 0.025665283203125 +45712 -0.150970458984375 +45713 0.017333984375 +45714 -0.2042236328125 +45715 0.00189208984375 +45716 -0.2576904296875 +45717 -0.03173828125 +45718 -0.301727294921875 +45719 -0.071502685546875 +45720 -0.348388671875 +45721 -0.13543701171875 +45722 -0.39544677734375 +45723 -0.219970703125 +45724 -0.426849365234375 +45725 -0.300506591796875 +45726 -0.44378662109375 +45727 -0.376312255859375 +45728 -0.4267578125 +45729 -0.416107177734375 +45730 -0.34454345703125 +45731 -0.371124267578125 +45732 -0.200714111328125 +45733 -0.242279052734375 +45734 -0.0262451171875 +45735 -0.069732666015625 +45736 0.16131591796875 +45737 0.125640869140625 +45738 0.337554931640625 +45739 0.31268310546875 +45740 0.474822998046875 +45741 0.45501708984375 +45742 0.57275390625 +45743 0.554779052734375 +45744 0.629180908203125 +45745 0.61065673828125 +45746 0.635284423828125 +45747 0.610931396484375 +45748 0.57427978515625 +45749 0.531463623046875 +45750 0.457977294921875 +45751 0.3883056640625 +45752 0.324615478515625 +45753 0.23468017578125 +45754 0.193115234375 +45755 0.095245361328125 +45756 0.08367919921875 +45757 -0.00396728515625 +45758 0.00872802734375 +45759 -0.04852294921875 +45760 -0.040863037109375 +45761 -0.055145263671875 +45762 -0.098785400390625 +45763 -0.0758056640625 +45764 -0.182342529296875 +45765 -0.138702392578125 +45766 -0.265350341796875 +45767 -0.209197998046875 +45768 -0.34735107421875 +45769 -0.289031982421875 +45770 -0.427581787109375 +45771 -0.37884521484375 +45772 -0.489776611328125 +45773 -0.456329345703125 +45774 -0.53021240234375 +45775 -0.51641845703125 +45776 -0.52154541015625 +45777 -0.519287109375 +45778 -0.4599609375 +45779 -0.458251953125 +45780 -0.382568359375 +45781 -0.384796142578125 +45782 -0.308258056640625 +45783 -0.323699951171875 +45784 -0.2349853515625 +45785 -0.269287109375 +45786 -0.146453857421875 +45787 -0.1951904296875 +45788 -0.043701171875 +45789 -0.100006103515625 +45790 0.052581787109375 +45791 -0.01055908203125 +45792 0.161651611328125 +45793 0.1033935546875 +45794 0.28704833984375 +45795 0.24908447265625 +45796 0.39056396484375 +45797 0.373199462890625 +45798 0.459136962890625 +45799 0.45806884765625 +45800 0.49786376953125 +45801 0.511474609375 +45802 0.5291748046875 +45803 0.565399169921875 +45804 0.547760009765625 +45805 0.61138916015625 +45806 0.512969970703125 +45807 0.5897216796875 +45808 0.41925048828125 +45809 0.4906005859375 +45810 0.280242919921875 +45811 0.33148193359375 +45812 0.12225341796875 +45813 0.147796630859375 +45814 -0.02398681640625 +45815 -0.01873779296875 +45816 -0.137451171875 +45817 -0.140289306640625 +45818 -0.19927978515625 +45819 -0.191986083984375 +45820 -0.2154541015625 +45821 -0.184295654296875 +45822 -0.215972900390625 +45823 -0.161834716796875 +45824 -0.229339599609375 +45825 -0.166595458984375 +45826 -0.251953125 +45827 -0.19390869140625 +45828 -0.270294189453125 +45829 -0.22442626953125 +45830 -0.29986572265625 +45831 -0.279754638671875 +45832 -0.32672119140625 +45833 -0.3389892578125 +45834 -0.318389892578125 +45835 -0.3543701171875 +45836 -0.2916259765625 +45837 -0.348175048828125 +45838 -0.251678466796875 +45839 -0.32598876953125 +45840 -0.179229736328125 +45841 -0.2581787109375 +45842 -0.072174072265625 +45843 -0.139801025390625 +45844 0.058013916015625 +45845 0.014617919921875 +45846 0.167694091796875 +45847 0.144378662109375 +45848 0.236053466796875 +45849 0.221038818359375 +45850 0.2806396484375 +45851 0.27069091796875 +45852 0.301544189453125 +45853 0.294036865234375 +45854 0.31317138671875 +45855 0.311767578125 +45856 0.326507568359375 +45857 0.339141845703125 +45858 0.331207275390625 +45859 0.360260009765625 +45860 0.317626953125 +45861 0.360504150390625 +45862 0.263580322265625 +45863 0.308380126953125 +45864 0.15374755859375 +45865 0.18170166015625 +45866 0.00677490234375 +45867 0.0047607421875 +45868 -0.14227294921875 +45869 -0.17559814453125 +45870 -0.259735107421875 +45871 -0.3143310546875 +45872 -0.313018798828125 +45873 -0.36785888671875 +45874 -0.320556640625 +45875 -0.36248779296875 +45876 -0.3148193359375 +45877 -0.343536376953125 +45878 -0.288848876953125 +45879 -0.3018798828125 +45880 -0.238067626953125 +45881 -0.231414794921875 +45882 -0.1519775390625 +45883 -0.117645263671875 +45884 -0.054412841796875 +45885 0.007049560546875 +45886 0.01434326171875 +45887 0.087982177734375 +45888 0.0640869140625 +45889 0.13946533203125 +45890 0.103363037109375 +45891 0.17425537109375 +45892 0.128326416015625 +45893 0.188201904296875 +45894 0.13079833984375 +45895 0.171234130859375 +45896 0.1064453125 +45897 0.118438720703125 +45898 0.0743408203125 +45899 0.05706787109375 +45900 0.035400390625 +45901 -0.010711669921875 +45902 -0.015625 +45903 -0.0914306640625 +45904 -0.0625 +45905 -0.162322998046875 +45906 -0.084381103515625 +45907 -0.194549560546875 +45908 -0.05303955078125 +45909 -0.1492919921875 +45910 0.035247802734375 +45911 -0.02166748046875 +45912 0.134063720703125 +45913 0.124053955078125 +45914 0.188018798828125 +45915 0.211151123046875 +45916 0.19830322265625 +45917 0.240447998046875 +45918 0.18756103515625 +45919 0.242218017578125 +45920 0.16326904296875 +45921 0.2257080078125 +45922 0.128570556640625 +45923 0.194366455078125 +45924 0.060333251953125 +45925 0.115509033203125 +45926 -0.02362060546875 +45927 0.0128173828125 +45928 -0.079254150390625 +45929 -0.053802490234375 +45930 -0.125335693359375 +45931 -0.110626220703125 +45932 -0.192169189453125 +45933 -0.199493408203125 +45934 -0.2607421875 +45935 -0.29437255859375 +45936 -0.285247802734375 +45937 -0.33221435546875 +45938 -0.24169921875 +45939 -0.27972412109375 +45940 -0.165740966796875 +45941 -0.185333251953125 +45942 -0.11541748046875 +45943 -0.128204345703125 +45944 -0.096588134765625 +45945 -0.115692138671875 +45946 -0.087005615234375 +45947 -0.116455078125 +45948 -0.069366455078125 +45949 -0.105926513671875 +45950 -0.02227783203125 +45951 -0.053955078125 +45952 0.060577392578125 +45953 0.048797607421875 +45954 0.146026611328125 +45955 0.157318115234375 +45956 0.190399169921875 +45957 0.212005615234375 +45958 0.19757080078125 +45959 0.218475341796875 +45960 0.211517333984375 +45961 0.23724365234375 +45962 0.25927734375 +45963 0.30535888671875 +45964 0.310760498046875 +45965 0.38128662109375 +45966 0.322113037109375 +45967 0.404449462890625 +45968 0.30792236328125 +45969 0.3944091796875 +45970 0.29583740234375 +45971 0.3885498046875 +45972 0.2686767578125 +45973 0.362640380859375 +45974 0.195556640625 +45975 0.27362060546875 +45976 0.07373046875 +45977 0.11712646484375 +45978 -0.05853271484375 +45979 -0.054901123046875 +45980 -0.16326904296875 +45981 -0.19085693359375 +45982 -0.236572265625 +45983 -0.28570556640625 +45984 -0.27813720703125 +45985 -0.339263916015625 +45986 -0.306793212890625 +45987 -0.3775634765625 +45988 -0.35540771484375 +45989 -0.445709228515625 +45990 -0.417816162109375 +45991 -0.535064697265625 +45992 -0.48211669921875 +45993 -0.629058837890625 +45994 -0.52667236328125 +45995 -0.697601318359375 +45996 -0.525054931640625 +45997 -0.70391845703125 +45998 -0.47357177734375 +45999 -0.6424560546875 +46000 -0.356597900390625 +46001 -0.491241455078125 +46002 -0.185791015625 +46003 -0.265716552734375 +46004 -0.003570556640625 +46005 -0.023712158203125 +46006 0.1656494140625 +46007 0.201751708984375 +46008 0.296295166015625 +46009 0.375823974609375 +46010 0.37841796875 +46011 0.485076904296875 +46012 0.440521240234375 +46013 0.56884765625 +46014 0.4881591796875 +46015 0.634765625 +46016 0.488494873046875 +46017 0.63763427734375 +46018 0.433349609375 +46019 0.5660400390625 +46020 0.36083984375 +46021 0.4720458984375 +46022 0.308502197265625 +46023 0.40692138671875 +46024 0.2818603515625 +46025 0.3778076171875 +46026 0.27557373046875 +46027 0.376953125 +46028 0.266387939453125 +46029 0.371978759765625 +46030 0.218414306640625 +46031 0.313140869140625 +46032 0.1202392578125 +46033 0.184417724609375 +46034 -0.0093994140625 +46035 0.011199951171875 +46036 -0.144561767578125 +46037 -0.171051025390625 +46038 -0.2669677734375 +46039 -0.33740234375 +46040 -0.365020751953125 +46041 -0.47198486328125 +46042 -0.42828369140625 +46043 -0.560394287109375 +46044 -0.440826416015625 +46045 -0.58056640625 +46046 -0.4136962890625 +46047 -0.54754638671875 +46048 -0.381500244140625 +46049 -0.508575439453125 +46050 -0.341461181640625 +46051 -0.459503173828125 +46052 -0.28948974609375 +46053 -0.394378662109375 +46054 -0.254486083984375 +46055 -0.35260009765625 +46056 -0.2203369140625 +46057 -0.31170654296875 +46058 -0.13323974609375 +46059 -0.197418212890625 +46060 0.00787353515625 +46061 -0.007965087890625 +46062 0.167083740234375 +46063 0.207489013671875 +46064 0.315338134765625 +46065 0.409210205078125 +46066 0.434295654296875 +46067 0.57208251953125 +46068 0.502044677734375 +46069 0.66595458984375 +46070 0.495269775390625 +46071 0.65875244140625 +46072 0.42645263671875 +46073 0.56744384765625 +46074 0.324371337890625 +46075 0.431396484375 +46076 0.221160888671875 +46077 0.29443359375 +46078 0.135894775390625 +46079 0.182464599609375 +46080 0.04510498046875 +46081 0.06365966796875 +46082 -0.06121826171875 +46083 -0.075958251953125 +46084 -0.1473388671875 +46085 -0.189422607421875 +46086 -0.209686279296875 +46087 -0.271942138671875 +46088 -0.262786865234375 +46089 -0.342529296875 +46090 -0.278594970703125 +46091 -0.364166259765625 +46092 -0.2498779296875 +46093 -0.327239990234375 +46094 -0.211029052734375 +46095 -0.2769775390625 +46096 -0.1927490234375 +46097 -0.253692626953125 +46098 -0.184600830078125 +46099 -0.24365234375 +46100 -0.149749755859375 +46101 -0.1983642578125 +46102 -0.087005615234375 +46103 -0.116241455078125 +46104 -0.026397705078125 +46105 -0.036834716796875 +46106 0.028228759765625 +46107 0.034881591796875 +46108 0.071075439453125 +46109 0.09124755859375 +46110 0.08441162109375 +46111 0.10888671875 +46112 0.096893310546875 +46113 0.125518798828125 +46114 0.121124267578125 +46115 0.15771484375 +46116 0.136444091796875 +46117 0.17828369140625 +46118 0.130584716796875 +46119 0.17108154296875 +46120 0.098968505859375 +46121 0.129974365234375 +46122 0.06243896484375 +46123 0.082427978515625 +46124 0.020477294921875 +46125 0.027679443359375 +46126 -0.05072021484375 +46127 -0.065643310546875 +46128 -0.122161865234375 +46129 -0.15936279296875 +46130 -0.163116455078125 +46131 -0.21307373046875 +46132 -0.179595947265625 +46133 -0.234649658203125 +46134 -0.153411865234375 +46135 -0.2001953125 +46136 -0.091766357421875 +46137 -0.119171142578125 +46138 -0.019866943359375 +46139 -0.024749755859375 +46140 0.0643310546875 +46141 0.085784912109375 +46142 0.134735107421875 +46143 0.178131103515625 +46144 0.1634521484375 +46145 0.215576171875 +46146 0.16058349609375 +46147 0.211456298828125 +46148 0.133331298828125 +46149 0.17523193359375 +46150 0.0982666015625 +46151 0.128753662109375 +46152 0.078094482421875 +46153 0.1019287109375 +46154 0.057342529296875 +46155 0.0743408203125 +46156 0.033905029296875 +46157 0.04327392578125 +46158 0.0301513671875 +46159 0.038177490234375 +46160 0.05914306640625 +46161 0.076263427734375 +46162 0.10833740234375 +46163 0.14105224609375 +46164 0.1427001953125 +46165 0.186431884765625 +46166 0.144317626953125 +46167 0.188812255859375 +46168 0.10626220703125 +46169 0.1390380859375 +46170 0.0321044921875 +46171 0.041778564453125 +46172 -0.06024169921875 +46173 -0.079437255859375 +46174 -0.16680908203125 +46175 -0.219390869140625 +46176 -0.27978515625 +46177 -0.367828369140625 +46178 -0.376495361328125 +46179 -0.494873046875 +46180 -0.42327880859375 +46181 -0.556243896484375 +46182 -0.38726806640625 +46183 -0.508697509765625 +46184 -0.28619384765625 +46185 -0.3756103515625 +46186 -0.1671142578125 +46187 -0.218902587890625 +46188 -0.049163818359375 +46189 -0.063751220703125 +46190 0.06890869140625 +46191 0.091552734375 +46192 0.178802490234375 +46193 0.23602294921875 +46194 0.260223388671875 +46195 0.342987060546875 +46196 0.300048828125 +46197 0.39520263671875 +46198 0.2957763671875 +46199 0.389373779296875 +46200 0.246429443359375 +46201 0.324249267578125 +46202 0.170440673828125 +46203 0.224090576171875 +46204 0.094696044921875 +46205 0.124267578125 +46206 0.02850341796875 +46207 0.037078857421875 +46208 -0.007293701171875 +46209 -0.010101318359375 +46210 -0.01434326171875 +46211 -0.019439697265625 +46212 -0.016845703125 +46213 -0.022796630859375 +46214 -0.00067138671875 +46215 -0.001556396484375 +46216 0.04327392578125 +46217 0.056304931640625 +46218 0.081512451171875 +46219 0.106719970703125 +46220 0.073944091796875 +46221 0.096893310546875 +46222 0.03265380859375 +46223 0.042694091796875 +46224 -0.01361083984375 +46225 -0.018035888671875 +46226 -0.057647705078125 +46227 -0.07586669921875 +46228 -0.090850830078125 +46229 -0.11944580078125 +46230 -0.121551513671875 +46231 -0.15972900390625 +46232 -0.154205322265625 +46233 -0.202606201171875 +46234 -0.189178466796875 +46235 -0.24859619140625 +46236 -0.232147216796875 +46237 -0.30517578125 +46238 -0.275360107421875 +46239 -0.36212158203125 +46240 -0.297576904296875 +46241 -0.39141845703125 +46242 -0.270050048828125 +46243 -0.35528564453125 +46244 -0.18994140625 +46245 -0.249969482421875 +46246 -0.07049560546875 +46247 -0.092864990234375 +46248 0.067779541015625 +46249 0.08905029296875 +46250 0.17889404296875 +46251 0.2352294921875 +46252 0.242462158203125 +46253 0.318817138671875 +46254 0.272735595703125 +46255 0.358642578125 +46256 0.26446533203125 +46257 0.347747802734375 +46258 0.21728515625 +46259 0.28564453125 +46260 0.169830322265625 +46261 0.223175048828125 +46262 0.14971923828125 +46263 0.196746826171875 +46264 0.1368408203125 +46265 0.179840087890625 +46266 0.118377685546875 +46267 0.155548095703125 +46268 0.115081787109375 +46269 0.151214599609375 +46270 0.11944580078125 +46271 0.156951904296875 +46272 0.10028076171875 +46273 0.13177490234375 +46274 0.07672119140625 +46275 0.100799560546875 +46276 0.0662841796875 +46277 0.087127685546875 +46278 0.041717529296875 +46279 0.05487060546875 +46280 -0.006866455078125 +46281 -0.009002685546875 +46282 -0.079071044921875 +46283 -0.10400390625 +46284 -0.17437744140625 +46285 -0.229400634765625 +46286 -0.270233154296875 +46287 -0.35552978515625 +46288 -0.33587646484375 +46289 -0.441925048828125 +46290 -0.360137939453125 +46291 -0.473846435546875 +46292 -0.353240966796875 +46293 -0.464813232421875 +46294 -0.318450927734375 +46295 -0.419097900390625 +46296 -0.25396728515625 +46297 -0.334320068359375 +46298 -0.173065185546875 +46299 -0.227935791015625 +46300 -0.093658447265625 +46301 -0.12347412109375 +46302 -0.02081298828125 +46303 -0.02764892578125 +46304 0.05926513671875 +46305 0.077667236328125 +46306 0.162322998046875 +46307 0.2132568359375 +46308 0.295745849609375 +46309 0.38885498046875 +46310 0.443084716796875 +46311 0.582794189453125 +46312 0.5579833984375 +46313 0.734039306640625 +46314 0.608184814453125 +46315 0.800140380859375 +46316 0.591552734375 +46317 0.7783203125 +46318 0.505523681640625 +46319 0.6651611328125 +46320 0.349334716796875 +46321 0.45965576171875 +46322 0.1513671875 +46323 0.199188232421875 +46324 -0.038543701171875 +46325 -0.050689697265625 +46326 -0.17706298828125 +46327 -0.23297119140625 +46328 -0.250885009765625 +46329 -0.33013916015625 +46330 -0.279937744140625 +46331 -0.368408203125 +46332 -0.28790283203125 +46333 -0.378936767578125 +46334 -0.286376953125 +46335 -0.376983642578125 +46336 -0.28851318359375 +46337 -0.37969970703125 +46338 -0.297607421875 +46339 -0.391510009765625 +46340 -0.292510986328125 +46341 -0.385345458984375 +46342 -0.2581787109375 +46343 -0.3419189453125 +46344 -0.2119140625 +46345 -0.28289794921875 +46346 -0.188140869140625 +46347 -0.251617431640625 +46348 -0.201202392578125 +46349 -0.266143798828125 +46350 -0.208984375 +46351 -0.273345947265625 +46352 -0.166717529296875 +46353 -0.216796875 +46354 -0.099365234375 +46355 -0.128265380859375 +46356 -0.054656982421875 +46357 -0.068145751953125 +46358 -0.037689208984375 +46359 -0.0430908203125 +46360 -0.02557373046875 +46361 -0.024444580078125 +46362 0.007904052734375 +46363 0.020721435546875 +46364 0.088287353515625 +46365 0.124481201171875 +46366 0.19268798828125 +46367 0.25787353515625 +46368 0.2880859375 +46369 0.379119873046875 +46370 0.36798095703125 +46371 0.47991943359375 +46372 0.40692138671875 +46373 0.5281982421875 +46374 0.39471435546875 +46375 0.511138916015625 +46376 0.352996826171875 +46377 0.456207275390625 +46378 0.31658935546875 +46379 0.407470703125 +46380 0.30029296875 +46381 0.383758544921875 +46382 0.2816162109375 +46383 0.35687255859375 +46384 0.24853515625 +46385 0.31182861328125 +46386 0.202667236328125 +46387 0.250885009765625 +46388 0.1370849609375 +46389 0.1654052734375 +46390 0.035736083984375 +46391 0.035247802734375 +46392 -0.103424072265625 +46393 -0.142059326171875 +46394 -0.256011962890625 +46395 -0.33563232421875 +46396 -0.413360595703125 +46397 -0.5345458984375 +46398 -0.562042236328125 +46399 -0.72186279296875 +46400 -0.65380859375 +46401 -0.836669921875 +46402 -0.65191650390625 +46403 -0.8326416015625 +46404 -0.571990966796875 +46405 -0.7296142578125 +46406 -0.45745849609375 +46407 -0.582550048828125 +46408 -0.346710205078125 +46409 -0.440093994140625 +46410 -0.257110595703125 +46411 -0.324310302734375 +46412 -0.161865234375 +46413 -0.20147705078125 +46414 -0.03948974609375 +46415 -0.044647216796875 +46416 0.076690673828125 +46417 0.103973388671875 +46418 0.153472900390625 +46419 0.202392578125 +46420 0.201873779296875 +46421 0.264495849609375 +46422 0.260467529296875 +46423 0.338897705078125 +46424 0.343658447265625 +46425 0.443817138671875 +46426 0.424346923828125 +46427 0.545074462890625 +46428 0.482452392578125 +46429 0.6173095703125 +46430 0.51153564453125 +46431 0.6524658203125 +46432 0.52166748046875 +46433 0.66339111328125 +46434 0.517547607421875 +46435 0.6561279296875 +46436 0.480133056640625 +46437 0.606781005859375 +46438 0.39813232421875 +46439 0.501190185546875 +46440 0.2821044921875 +46441 0.352783203125 +46442 0.143829345703125 +46443 0.176544189453125 +46444 -0.022491455078125 +46445 -0.034820556640625 +46446 -0.1986083984375 +46447 -0.258209228515625 +46448 -0.34405517578125 +46449 -0.44244384765625 +46450 -0.44915771484375 +46451 -0.5753173828125 +46452 -0.5101318359375 +46453 -0.65203857421875 +46454 -0.502410888671875 +46455 -0.641632080078125 +46456 -0.4403076171875 +46457 -0.562164306640625 +46458 -0.358917236328125 +46459 -0.458038330078125 +46460 -0.275054931640625 +46461 -0.350555419921875 +46462 -0.205108642578125 +46463 -0.260528564453125 +46464 -0.152313232421875 +46465 -0.192108154296875 +46466 -0.113922119140625 +46467 -0.141937255859375 +46468 -0.083648681640625 +46469 -0.1021728515625 +46470 -0.0535888671875 +46471 -0.062896728515625 +46472 -0.014007568359375 +46473 -0.011932373046875 +46474 0.044708251953125 +46475 0.062835693359375 +46476 0.112518310546875 +46477 0.148712158203125 +46478 0.186248779296875 +46479 0.241729736328125 +46480 0.271636962890625 +46481 0.34912109375 +46482 0.35791015625 +46483 0.457305908203125 +46484 0.427276611328125 +46485 0.54388427734375 +46486 0.451202392578125 +46487 0.5728759765625 +46488 0.3997802734375 +46489 0.506591796875 +46490 0.277862548828125 +46491 0.351226806640625 +46492 0.1168212890625 +46493 0.146514892578125 +46494 -0.04193115234375 +46495 -0.05523681640625 +46496 -0.168548583984375 +46497 -0.21624755859375 +46498 -0.261810302734375 +46499 -0.334930419921875 +46500 -0.315185546875 +46501 -0.402984619140625 +46502 -0.345184326171875 +46503 -0.4412841796875 +46504 -0.38824462890625 +46505 -0.49578857421875 +46506 -0.439361572265625 +46507 -0.5601806640625 +46508 -0.471832275390625 +46509 -0.600738525390625 +46510 -0.45928955078125 +46511 -0.584228515625 +46512 -0.37689208984375 +46513 -0.47930908203125 +46514 -0.2193603515625 +46515 -0.27935791015625 +46516 -0.006072998046875 +46517 -0.0089111328125 +46518 0.212921142578125 +46519 0.268798828125 +46520 0.381500244140625 +46521 0.482818603515625 +46522 0.47637939453125 +46523 0.60369873046875 +46524 0.51263427734375 +46525 0.650421142578125 +46526 0.522796630859375 +46527 0.66400146484375 +46528 0.5045166015625 +46529 0.6414794921875 +46530 0.449676513671875 +46531 0.572540283203125 +46532 0.390716552734375 +46533 0.498138427734375 +46534 0.34442138671875 +46535 0.439453125 +46536 0.294158935546875 +46537 0.375518798828125 +46538 0.2147216796875 +46539 0.274505615234375 +46540 0.08416748046875 +46541 0.1087646484375 +46542 -0.079925537109375 +46543 -0.099395751953125 +46544 -0.252410888671875 +46545 -0.3182373046875 +46546 -0.434295654296875 +46547 -0.5489501953125 +46548 -0.611572265625 +46549 -0.7738037109375 +46550 -0.742340087890625 +46551 -0.86383056640625 +46552 -0.800323486328125 +46553 -0.870391845703125 +46554 -0.799560546875 +46555 -0.86895751953125 +46556 -0.75048828125 +46557 -0.861053466796875 +46558 -0.639404296875 +46559 -0.765869140625 +46560 -0.457366943359375 +46561 -0.5301513671875 +46562 -0.209991455078125 +46563 -0.214691162109375 +46564 0.068603515625 +46565 0.137359619140625 +46566 0.33782958984375 +46567 0.474822998046875 +46568 0.569549560546875 +46569 0.76239013671875 +46570 0.742431640625 +46571 0.867462158203125 +46572 0.854736328125 +46573 0.870361328125 +46574 0.85986328125 +46575 0.86480712890625 +46576 0.858062744140625 +46577 0.831817626953125 +46578 0.826934814453125 +46579 0.677581787109375 +46580 0.7271728515625 +46581 0.495880126953125 +46582 0.602783203125 +46583 0.30767822265625 +46584 0.45550537109375 +46585 0.116180419921875 +46586 0.260223388671875 +46587 -0.110748291015625 +46588 0.011444091796875 +46589 -0.381805419921875 +46590 -0.25689697265625 +46591 -0.6572265625 +46592 -0.49725341796875 +46593 -0.857421875 +46594 -0.67547607421875 +46595 -0.870391845703125 +46596 -0.7861328125 +46597 -0.870391845703125 +46598 -0.851348876953125 +46599 -0.86444091796875 +46600 -0.859527587890625 +46601 -0.85723876953125 +46602 -0.861419677734375 +46603 -0.790008544921875 +46604 -0.85498046875 +46605 -0.62847900390625 +46606 -0.72039794921875 +46607 -0.3956298828125 +46608 -0.52911376953125 +46609 -0.126708984375 +46610 -0.30718994140625 +46611 0.150115966796875 +46612 -0.063873291015625 +46613 0.424041748046875 +46614 0.17901611328125 +46615 0.670623779296875 +46616 0.389923095703125 +46617 0.854522705078125 +46618 0.55462646484375 +46619 0.866485595703125 +46620 0.660736083984375 +46621 0.86920166015625 +46622 0.723388671875 +46623 0.8653564453125 +46624 0.7537841796875 +46625 0.857147216796875 +46626 0.74951171875 +46627 0.766845703125 +46628 0.71478271484375 +46629 0.628509521484375 +46630 0.643890380859375 +46631 0.462127685546875 +46632 0.5579833984375 +46633 0.297210693359375 +46634 0.467010498046875 +46635 0.14862060546875 +46636 0.351898193359375 +46637 -0.00537109375 +46638 0.218505859375 +46639 -0.15753173828125 +46640 0.063568115234375 +46641 -0.31304931640625 +46642 -0.124755859375 +46643 -0.48876953125 +46644 -0.30810546875 +46645 -0.6416015625 +46646 -0.466339111328125 +46647 -0.751373291015625 +46648 -0.618621826171875 +46649 -0.84619140625 +46650 -0.75299072265625 +46651 -0.861297607421875 +46652 -0.842132568359375 +46653 -0.863250732421875 +46654 -0.8551025390625 +46655 -0.856597900390625 +46656 -0.81658935546875 +46657 -0.7498779296875 +46658 -0.7593994140625 +46659 -0.624542236328125 +46660 -0.670135498046875 +46661 -0.47808837890625 +46662 -0.50042724609375 +46663 -0.253387451171875 +46664 -0.287628173828125 +46665 0.003692626953125 +46666 -0.087860107421875 +46667 0.2257080078125 +46668 0.109405517578125 +46669 0.427154541015625 +46670 0.3310546875 +46671 0.643218994140625 +46672 0.56927490234375 +46673 0.855926513671875 +46674 0.77642822265625 +46675 0.870361328125 +46676 0.8607177734375 +46677 0.870361328125 +46678 0.8682861328125 +46679 0.862762451171875 +46680 0.868408203125 +46681 0.79669189453125 +46682 0.860198974609375 +46683 0.595794677734375 +46684 0.779296875 +46685 0.362152099609375 +46686 0.62255859375 +46687 0.1270751953125 +46688 0.453857421875 +46689 -0.086944580078125 +46690 0.274810791015625 +46691 -0.2784423828125 +46692 0.05657958984375 +46693 -0.484832763671875 +46694 -0.21673583984375 +46695 -0.729583740234375 +46696 -0.5035400390625 +46697 -0.86688232421875 +46698 -0.751739501953125 +46699 -0.870391845703125 +46700 -0.86572265625 +46701 -0.86859130859375 +46702 -0.870391845703125 +46703 -0.86279296875 +46704 -0.8680419921875 +46705 -0.817962646484375 +46706 -0.855224609375 +46707 -0.6116943359375 +46708 -0.646514892578125 +46709 -0.3128662109375 +46710 -0.365692138671875 +46711 0.039398193359375 +46712 -0.03717041015625 +46713 0.422821044921875 +46714 0.311065673828125 +46715 0.805145263671875 +46716 0.62384033203125 +46717 0.870361328125 +46718 0.85467529296875 +46719 0.870361328125 +46720 0.870361328125 +46721 0.860015869140625 +46722 0.870361328125 +46723 0.727935791015625 +46724 0.86126708984375 +46725 0.48114013671875 +46726 0.778228759765625 +46727 0.2059326171875 +46728 0.610809326171875 +46729 -0.06103515625 +46730 0.429595947265625 +46731 -0.29913330078125 +46732 0.228363037109375 +46733 -0.516204833984375 +46734 -0.001220703125 +46735 -0.7252197265625 +46736 -0.235870361328125 +46737 -0.85980224609375 +46738 -0.44622802734375 +46739 -0.870391845703125 +46740 -0.608551025390625 +46741 -0.870391845703125 +46742 -0.684906005859375 +46743 -0.858062744140625 +46744 -0.675445556640625 +46745 -0.673004150390625 +46746 -0.628265380859375 +46747 -0.42694091796875 +46748 -0.58563232421875 +46749 -0.2100830078125 +46750 -0.55206298828125 +46751 -0.0362548828125 +46752 -0.510040283203125 +46753 0.10943603515625 +46754 -0.449493408203125 +46755 0.23516845703125 +46756 -0.34210205078125 +46757 0.373687744140625 +46758 -0.1944580078125 +46759 0.517791748046875 +46760 -0.062469482421875 +46761 0.602783203125 +46762 0.055328369140625 +46763 0.635711669921875 +46764 0.184967041015625 +46765 0.655181884765625 +46766 0.31817626953125 +46767 0.65948486328125 +46768 0.449615478515625 +46769 0.651275634765625 +46770 0.561553955078125 +46771 0.61846923828125 +46772 0.62701416015625 +46773 0.53753662109375 +46774 0.635406494140625 +46775 0.404144287109375 +46776 0.583648681640625 +46777 0.22186279296875 +46778 0.4779052734375 +46779 0.003997802734375 +46780 0.3382568359375 +46781 -0.22100830078125 +46782 0.186614990234375 +46783 -0.42449951171875 +46784 0.044952392578125 +46785 -0.579833984375 +46786 -0.047943115234375 +46787 -0.641876220703125 +46788 -0.094879150390625 +46789 -0.6177978515625 +46790 -0.147491455078125 +46791 -0.575531005859375 +46792 -0.209686279296875 +46793 -0.526336669921875 +46794 -0.2393798828125 +46795 -0.42645263671875 +46796 -0.215606689453125 +46797 -0.2581787109375 +46798 -0.1708984375 +46799 -0.068695068359375 +46800 -0.1402587890625 +46801 0.09222412109375 +46802 -0.1121826171875 +46803 0.232147216796875 +46804 -0.082427978515625 +46805 0.3509521484375 +46806 -0.079620361328125 +46807 0.410064697265625 +46808 -0.131988525390625 +46809 0.372955322265625 +46810 -0.2259521484375 +46811 0.2554931640625 +46812 -0.321624755859375 +46813 0.10711669921875 +46814 -0.405303955078125 +46815 -0.052886962890625 +46816 -0.448699951171875 +46817 -0.186279296875 +46818 -0.40643310546875 +46819 -0.23291015625 +46820 -0.297027587890625 +46821 -0.209442138671875 +46822 -0.173675537109375 +46823 -0.174163818359375 +46824 -0.0413818359375 +46825 -0.126739501953125 +46826 0.110443115234375 +46827 -0.048126220703125 +46828 0.261566162109375 +46829 0.0426025390625 +46830 0.376861572265625 +46831 0.10748291015625 +46832 0.448822021484375 +46833 0.1409912109375 +46834 0.51995849609375 +46835 0.19708251953125 +46836 0.587799072265625 +46837 0.273651123046875 +46838 0.60894775390625 +46839 0.31768798828125 +46840 0.5946044921875 +46841 0.341094970703125 +46842 0.567047119140625 +46843 0.368011474609375 +46844 0.508056640625 +46845 0.37249755859375 +46846 0.377044677734375 +46847 0.30072021484375 +46848 0.17755126953125 +46849 0.1517333984375 +46850 -0.03668212890625 +46851 -0.01470947265625 +46852 -0.2537841796875 +46853 -0.1883544921875 +46854 -0.473114013671875 +46855 -0.372711181640625 +46856 -0.645751953125 +46857 -0.51397705078125 +46858 -0.73480224609375 +46859 -0.57177734375 +46860 -0.732818603515625 +46861 -0.53948974609375 +46862 -0.65411376953125 +46863 -0.43511962890625 +46864 -0.530517578125 +46865 -0.2962646484375 +46866 -0.395172119140625 +46867 -0.161102294921875 +46868 -0.26141357421875 +46869 -0.0435791015625 +46870 -0.127960205078125 +46871 0.060394287109375 +46872 -0.00958251953125 +46873 0.13665771484375 +46874 0.077728271484375 +46875 0.170135498046875 +46876 0.134613037109375 +46877 0.16552734375 +46878 0.186981201171875 +46879 0.15728759765625 +46880 0.236236572265625 +46881 0.150787353515625 +46882 0.25909423828125 +46883 0.12200927734375 +46884 0.260955810546875 +46885 0.080108642578125 +46886 0.2623291015625 +46887 0.05126953125 +46888 0.28546142578125 +46889 0.062896728515625 +46890 0.31103515625 +46891 0.09271240234375 +46892 0.298858642578125 +46893 0.092987060546875 +46894 0.262542724609375 +46895 0.07855224609375 +46896 0.216400146484375 +46897 0.06427001953125 +46898 0.149505615234375 +46899 0.0347900390625 +46900 0.062774658203125 +46901 -0.01171875 +46902 -0.02471923828125 +46903 -0.056060791015625 +46904 -0.073883056640625 +46905 -0.055511474609375 +46906 -0.08233642578125 +46907 -0.010467529296875 +46908 -0.093475341796875 +46909 0.02508544921875 +46910 -0.126861572265625 +46911 0.025665283203125 +46912 -0.15869140625 +46913 0.017333984375 +46914 -0.186370849609375 +46915 0.00189208984375 +46916 -0.21881103515625 +46917 -0.03173828125 +46918 -0.245941162109375 +46919 -0.071502685546875 +46920 -0.283721923828125 +46921 -0.13543701171875 +46922 -0.330291748046875 +46923 -0.219970703125 +46924 -0.366363525390625 +46925 -0.300506591796875 +46926 -0.393280029296875 +46927 -0.376312255859375 +46928 -0.38665771484375 +46929 -0.416107177734375 +46930 -0.30731201171875 +46931 -0.371124267578125 +46932 -0.158294677734375 +46933 -0.242279052734375 +46934 0.02410888671875 +46935 -0.069732666015625 +46936 0.220306396484375 +46937 0.125640869140625 +46938 0.402374267578125 +46939 0.31268310546875 +46940 0.538360595703125 +46941 0.45501708984375 +46942 0.62945556640625 +46943 0.554779052734375 +46944 0.674468994140625 +46945 0.61065673828125 +46946 0.663848876953125 +46947 0.610931396484375 +46948 0.577911376953125 +46949 0.531463623046875 +46950 0.431488037109375 +46951 0.3883056640625 +46952 0.271331787109375 +46953 0.23468017578125 +46954 0.12017822265625 +46955 0.095245361328125 +46956 0.00201416015625 +46957 -0.00396728515625 +46958 -0.06903076171875 +46959 -0.04852294921875 +46960 -0.1053466796875 +46961 -0.055145263671875 +46962 -0.1495361328125 +46963 -0.0758056640625 +46964 -0.2242431640625 +46965 -0.138702392578125 +46966 -0.29901123046875 +46967 -0.209197998046875 +46968 -0.374664306640625 +46969 -0.289031982421875 +46970 -0.4515380859375 +46971 -0.37884521484375 +46972 -0.510833740234375 +46973 -0.456329345703125 +46974 -0.548828125 +46975 -0.51641845703125 +46976 -0.532562255859375 +46977 -0.519287109375 +46978 -0.457550048828125 +46979 -0.458251953125 +46980 -0.36895751953125 +46981 -0.384796142578125 +46982 -0.289306640625 +46983 -0.323699951171875 +46984 -0.21533203125 +46985 -0.269287109375 +46986 -0.12615966796875 +46987 -0.1951904296875 +46988 -0.02197265625 +46989 -0.100006103515625 +46990 0.073211669921875 +46991 -0.01055908203125 +46992 0.184173583984375 +46993 0.1033935546875 +46994 0.316436767578125 +46995 0.24908447265625 +46996 0.424407958984375 +46997 0.373199462890625 +46998 0.49310302734375 +46999 0.45806884765625 +47000 0.52947998046875 +47001 0.511474609375 +47002 0.5614013671875 +47003 0.565399169921875 +47004 0.58258056640625 +47005 0.61138916015625 +47006 0.5433349609375 +47007 0.5897216796875 +47008 0.436553955078125 +47009 0.4906005859375 +47010 0.27838134765625 +47011 0.33148193359375 +47012 0.10015869140625 +47013 0.147796630859375 +47014 -0.06146240234375 +47015 -0.01873779296875 +47016 -0.181793212890625 +47017 -0.140289306640625 +47018 -0.23883056640625 +47019 -0.191986083984375 +47020 -0.24090576171875 +47021 -0.184295654296875 +47022 -0.225616455078125 +47023 -0.161834716796875 +47024 -0.228546142578125 +47025 -0.166595458984375 +47026 -0.24591064453125 +47027 -0.19390869140625 +47028 -0.261749267578125 +47029 -0.22442626953125 +47030 -0.295074462890625 +47031 -0.279754638671875 +47032 -0.3289794921875 +47033 -0.3389892578125 +47034 -0.3238525390625 +47035 -0.3543701171875 +47036 -0.2996826171875 +47037 -0.348175048828125 +47038 -0.262237548828125 +47039 -0.32598876953125 +47040 -0.1873779296875 +47041 -0.2581787109375 +47042 -0.07177734375 +47043 -0.139801025390625 +47044 0.07147216796875 +47045 0.014617919921875 +47046 0.190185546875 +47047 0.144378662109375 +47048 0.259857177734375 +47049 0.221038818359375 +47050 0.302490234375 +47051 0.27069091796875 +47052 0.318817138671875 +47053 0.294036865234375 +47054 0.32672119140625 +47055 0.311767578125 +47056 0.339691162109375 +47057 0.339141845703125 +47058 0.344940185546875 +47059 0.360260009765625 +47060 0.330780029296875 +47061 0.360504150390625 +47062 0.27105712890625 +47063 0.308380126953125 +47064 0.1475830078125 +47065 0.18170166015625 +47066 -0.017974853515625 +47067 0.0047607421875 +47068 -0.184814453125 +47069 -0.17559814453125 +47070 -0.31378173828125 +47071 -0.3143310546875 +47072 -0.367095947265625 +47073 -0.36785888671875 +47074 -0.366912841796875 +47075 -0.36248779296875 +47076 -0.351898193359375 +47077 -0.343536376953125 +47078 -0.314300537109375 +47079 -0.3018798828125 +47080 -0.249053955078125 +47081 -0.231414794921875 +47082 -0.14410400390625 +47083 -0.117645263671875 +47084 -0.02764892578125 +47085 0.007049560546875 +47086 0.05291748046875 +47087 0.087982177734375 +47088 0.10919189453125 +47089 0.13946533203125 +47090 0.151397705078125 +47091 0.17425537109375 +47092 0.175262451171875 +47093 0.188201904296875 +47094 0.171539306640625 +47095 0.171234130859375 +47096 0.135467529296875 +47097 0.118438720703125 +47098 0.089935302734375 +47099 0.05706787109375 +47100 0.03643798828125 +47101 -0.010711669921875 +47102 -0.03076171875 +47103 -0.0914306640625 +47104 -0.09259033203125 +47105 -0.162322998046875 +47106 -0.12408447265625 +47107 -0.194549560546875 +47108 -0.090240478515625 +47109 -0.1492919921875 +47110 0.0140380859375 +47111 -0.02166748046875 +47112 0.132537841796875 +47113 0.124053955078125 +47114 0.197967529296875 +47115 0.211151123046875 +47116 0.211883544921875 +47117 0.240447998046875 +47118 0.201873779296875 +47119 0.242218017578125 +47120 0.176849365234375 +47121 0.2257080078125 +47122 0.140411376953125 +47123 0.194366455078125 +47124 0.063934326171875 +47125 0.115509033203125 +47126 -0.03125 +47127 0.0128173828125 +47128 -0.091827392578125 +47129 -0.053802490234375 +47130 -0.141143798828125 +47131 -0.110626220703125 +47132 -0.216552734375 +47133 -0.199493408203125 +47134 -0.295196533203125 +47135 -0.29437255859375 +47136 -0.32147216796875 +47137 -0.33221435546875 +47138 -0.26629638671875 +47139 -0.27972412109375 +47140 -0.173187255859375 +47141 -0.185333251953125 +47142 -0.112945556640625 +47143 -0.128204345703125 +47144 -0.092620849609375 +47145 -0.115692138671875 +47146 -0.084869384765625 +47147 -0.116455078125 +47148 -0.068359375 +47149 -0.105926513671875 +47150 -0.01666259765625 +47151 -0.053955078125 +47152 0.0782470703125 +47153 0.048797607421875 +47154 0.17626953125 +47155 0.157318115234375 +47156 0.22442626953125 +47157 0.212005615234375 +47158 0.227783203125 +47159 0.218475341796875 +47160 0.24029541015625 +47161 0.23724365234375 +47162 0.295135498046875 +47163 0.30535888671875 +47164 0.355743408203125 +47165 0.38128662109375 +47166 0.368743896484375 +47167 0.404449462890625 +47168 0.3519287109375 +47169 0.3944091796875 +47170 0.338958740234375 +47171 0.3885498046875 +47172 0.308746337890625 +47173 0.362640380859375 +47174 0.223419189453125 +47175 0.27362060546875 +47176 0.07940673828125 +47177 0.11712646484375 +47178 -0.076873779296875 +47179 -0.054901123046875 +47180 -0.199432373046875 +47181 -0.19085693359375 +47182 -0.283782958984375 +47183 -0.28570556640625 +47184 -0.329833984375 +47185 -0.339263916015625 +47186 -0.36083984375 +47187 -0.3775634765625 +47188 -0.417022705078125 +47189 -0.445709228515625 +47190 -0.49102783203125 +47191 -0.535064697265625 +47192 -0.568450927734375 +47193 -0.629058837890625 +47194 -0.622894287109375 +47195 -0.697601318359375 +47196 -0.6220703125 +47197 -0.70391845703125 +47198 -0.5614013671875 +47199 -0.6424560546875 +47200 -0.421722412109375 +47201 -0.491241455078125 +47202 -0.21697998046875 +47203 -0.265716552734375 +47204 0.001220703125 +47205 -0.023712158203125 +47206 0.203399658203125 +47207 0.201751708984375 +47208 0.358551025390625 +47209 0.375823974609375 +47210 0.45477294921875 +47211 0.485076904296875 +47212 0.527099609375 +47213 0.56884765625 +47214 0.582427978515625 +47215 0.634765625 +47216 0.580841064453125 +47217 0.63763427734375 +47218 0.512420654296875 +47219 0.5660400390625 +47220 0.4237060546875 +47221 0.4720458984375 +47222 0.360504150390625 +47223 0.40692138671875 +47224 0.329498291015625 +47225 0.3778076171875 +47226 0.324066162109375 +47227 0.376953125 +47228 0.315704345703125 +47229 0.371978759765625 +47230 0.26043701171875 +47231 0.313140869140625 +47232 0.1441650390625 +47233 0.184417724609375 +47234 -0.010467529296875 +47235 0.011199951171875 +47236 -0.171966552734375 +47237 -0.171051025390625 +47238 -0.318267822265625 +47239 -0.33740234375 +47240 -0.43536376953125 +47241 -0.47198486328125 +47242 -0.510650634765625 +47243 -0.560394287109375 +47244 -0.52471923828125 +47245 -0.58056640625 +47246 -0.491180419921875 +47247 -0.54754638671875 +47248 -0.45220947265625 +47249 -0.508575439453125 +47250 -0.40435791015625 +47251 -0.459503173828125 +47252 -0.34259033203125 +47253 -0.394378662109375 +47254 -0.30206298828125 +47255 -0.35260009765625 +47256 -0.26300048828125 +47257 -0.31170654296875 +47258 -0.159576416015625 +47259 -0.197418212890625 +47260 0.009674072265625 +47261 -0.007965087890625 +47262 0.2010498046875 +47263 0.207489013671875 +47264 0.3792724609375 +47265 0.409210205078125 +47266 0.52215576171875 +47267 0.57208251953125 +47268 0.60302734375 +47269 0.66595458984375 +47270 0.59356689453125 +47271 0.65875244140625 +47272 0.509033203125 +47273 0.56744384765625 +47274 0.38458251953125 +47275 0.431396484375 +47276 0.259368896484375 +47277 0.29443359375 +47278 0.156585693359375 +47279 0.182464599609375 +47280 0.048126220703125 +47281 0.06365966796875 +47282 -0.0782470703125 +47283 -0.075958251953125 +47284 -0.180755615234375 +47285 -0.189422607421875 +47286 -0.255035400390625 +47287 -0.271942138671875 +47288 -0.31793212890625 +47289 -0.342529296875 +47290 -0.336639404296875 +47291 -0.364166259765625 +47292 -0.302642822265625 +47293 -0.327239990234375 +47294 -0.256195068359375 +47295 -0.2769775390625 +47296 -0.233184814453125 +47297 -0.253692626953125 +47298 -0.2215576171875 +47299 -0.24365234375 +47300 -0.178436279296875 +47301 -0.1983642578125 +47302 -0.102569580078125 +47303 -0.116241455078125 +47304 -0.029205322265625 +47305 -0.036834716796875 +47306 0.03704833984375 +47307 0.034881591796875 +47308 0.089263916015625 +47309 0.09124755859375 +47310 0.1065673828125 +47311 0.10888671875 +47312 0.12237548828125 +47313 0.125518798828125 +47314 0.1513671875 +47315 0.15771484375 +47316 0.169403076171875 +47317 0.17828369140625 +47318 0.16217041015625 +47319 0.17108154296875 +47320 0.12432861328125 +47321 0.129974365234375 +47322 0.080322265625 +47323 0.082427978515625 +47324 0.02960205078125 +47325 0.027679443359375 +47326 -0.05560302734375 +47327 -0.065643310546875 +47328 -0.1412353515625 +47329 -0.15936279296875 +47330 -0.1912841796875 +47331 -0.21307373046875 +47332 -0.212615966796875 +47333 -0.234649658203125 +47334 -0.18389892578125 +47335 -0.2001953125 +47336 -0.113433837890625 +47337 -0.119171142578125 +47338 -0.030609130859375 +47339 -0.024749755859375 +47340 0.0670166015625 +47341 0.085784912109375 +47342 0.149017333984375 +47343 0.178131103515625 +47344 0.182769775390625 +47345 0.215576171875 +47346 0.1800537109375 +47347 0.211456298828125 +47348 0.149200439453125 +47349 0.17523193359375 +47350 0.10955810546875 +47351 0.128753662109375 +47352 0.08758544921875 +47353 0.1019287109375 +47354 0.0650634765625 +47355 0.0743408203125 +47356 0.039459228515625 +47357 0.04327392578125 +47358 0.03680419921875 +47359 0.038177490234375 +47360 0.072845458984375 +47361 0.076263427734375 +47362 0.13330078125 +47363 0.14105224609375 +47364 0.17626953125 +47365 0.186431884765625 +47366 0.1798095703125 +47367 0.188812255859375 +47368 0.135284423828125 +47369 0.1390380859375 +47370 0.046875 +47371 0.041778564453125 +47372 -0.06390380859375 +47373 -0.079437255859375 +47374 -0.192413330078125 +47375 -0.219390869140625 +47376 -0.3292236328125 +47377 -0.367828369140625 +47378 -0.446868896484375 +47379 -0.494873046875 +47380 -0.504547119140625 +47381 -0.556243896484375 +47382 -0.462432861328125 +47383 -0.508697509765625 +47384 -0.3419189453125 +47385 -0.3756103515625 +47386 -0.19989013671875 +47387 -0.218902587890625 +47388 -0.059356689453125 +47389 -0.063751220703125 +47390 0.08135986328125 +47391 0.091552734375 +47392 0.212310791015625 +47393 0.23602294921875 +47394 0.309051513671875 +47395 0.342987060546875 +47396 0.355804443359375 +47397 0.39520263671875 +47398 0.349609375 +47399 0.389373779296875 +47400 0.28936767578125 +47401 0.324249267578125 +47402 0.1973876953125 +47403 0.224090576171875 +47404 0.106201171875 +47405 0.124267578125 +47406 0.02703857421875 +47407 0.037078857421875 +47408 -0.01495361328125 +47409 -0.010101318359375 +47410 -0.0218505859375 +47411 -0.019439697265625 +47412 -0.023040771484375 +47413 -0.022796630859375 +47414 -0.00152587890625 +47415 -0.001556396484375 +47416 0.053619384765625 +47417 0.056304931640625 +47418 0.10174560546875 +47419 0.106719970703125 +47420 0.094207763671875 +47421 0.096893310546875 +47422 0.0455322265625 +47423 0.042694091796875 +47424 -0.009552001953125 +47425 -0.018035888671875 +47426 -0.062347412109375 +47427 -0.07586669921875 +47428 -0.102447509765625 +47429 -0.11944580078125 +47430 -0.139923095703125 +47431 -0.15972900390625 +47432 -0.18017578125 +47433 -0.202606201171875 +47434 -0.223602294921875 +47435 -0.24859619140625 +47436 -0.277008056640625 +47437 -0.30517578125 +47438 -0.3309326171875 +47439 -0.36212158203125 +47440 -0.3594970703125 +47441 -0.39141845703125 +47442 -0.32781982421875 +47443 -0.35528564453125 +47444 -0.23236083984375 +47445 -0.249969482421875 +47446 -0.089111328125 +47447 -0.092864990234375 +47448 0.077178955078125 +47449 0.08905029296875 +47450 0.210906982421875 +47451 0.2352294921875 +47452 0.287384033203125 +47453 0.318817138671875 +47454 0.323944091796875 +47455 0.358642578125 +47456 0.314178466796875 +47457 0.347747802734375 +47458 0.25762939453125 +47459 0.28564453125 +47460 0.201019287109375 +47461 0.223175048828125 +47462 0.177734375 +47463 0.196746826171875 +47464 0.163360595703125 +47465 0.179840087890625 +47466 0.14227294921875 +47467 0.155548095703125 +47468 0.139556884765625 +47469 0.151214599609375 +47470 0.14605712890625 +47471 0.156951904296875 +47472 0.123992919921875 +47473 0.13177490234375 +47474 0.096405029296875 +47475 0.100799560546875 +47476 0.084503173828125 +47477 0.087127685546875 +47478 0.055267333984375 +47479 0.05487060546875 +47480 -0.0032958984375 +47481 -0.009002685546875 +47482 -0.09075927734375 +47483 -0.10400390625 +47484 -0.20648193359375 +47485 -0.229400634765625 +47486 -0.3231201171875 +47487 -0.35552978515625 +47488 -0.40338134765625 +47489 -0.441925048828125 +47490 -0.433685302734375 +47491 -0.473846435546875 +47492 -0.4263916015625 +47493 -0.464813232421875 +47494 -0.3853759765625 +47495 -0.419097900390625 +47496 -0.308380126953125 +47497 -0.334320068359375 +47498 -0.211395263671875 +47499 -0.227935791015625 +47500 -0.1160888671875 +47501 -0.12347412109375 +47502 -0.028564453125 +47503 -0.02764892578125 +47504 0.067901611328125 +47505 0.077667236328125 +47506 0.19244384765625 +47507 0.2132568359375 +47508 0.35400390625 +47509 0.38885498046875 +47510 0.532623291015625 +47511 0.582794189453125 +47512 0.672149658203125 +47513 0.734039306640625 +47514 0.7335205078125 +47515 0.800140380859375 +47516 0.714111328125 +47517 0.7783203125 +47518 0.610748291015625 +47519 0.6651611328125 +47520 0.4224853515625 +47521 0.45965576171875 +47522 0.18365478515625 +47523 0.199188232421875 +47524 -0.04547119140625 +47525 -0.050689697265625 +47526 -0.212493896484375 +47527 -0.23297119140625 +47528 -0.30133056640625 +47529 -0.33013916015625 +47530 -0.33612060546875 +47531 -0.368408203125 +47532 -0.345550537109375 +47533 -0.378936767578125 +47534 -0.34368896484375 +47535 -0.376983642578125 +47536 -0.3463134765625 +47537 -0.37969970703125 +47538 -0.357452392578125 +47539 -0.391510009765625 +47540 -0.352203369140625 +47541 -0.385345458984375 +47542 -0.312774658203125 +47543 -0.3419189453125 +47544 -0.25909423828125 +47545 -0.28289794921875 +47546 -0.230987548828125 +47547 -0.251617431640625 +47548 -0.2449951171875 +47549 -0.266143798828125 +47550 -0.25225830078125 +47551 -0.273345947265625 +47552 -0.2008056640625 +47553 -0.216796875 +47554 -0.11981201171875 +47555 -0.128265380859375 +47556 -0.06488037109375 +47557 -0.068145751953125 +47558 -0.042083740234375 +47559 -0.0430908203125 +47560 -0.0250244140625 +47561 -0.024444580078125 +47562 0.016571044921875 +47563 0.020721435546875 +47564 0.112213134765625 +47565 0.124481201171875 +47566 0.2352294921875 +47567 0.25787353515625 +47568 0.34716796875 +47569 0.379119873046875 +47570 0.44036865234375 +47571 0.47991943359375 +47572 0.48529052734375 +47573 0.5281982421875 +47574 0.470123291015625 +47575 0.511138916015625 +47576 0.42010498046875 +47577 0.456207275390625 +47578 0.375762939453125 +47579 0.407470703125 +47580 0.354400634765625 +47581 0.383758544921875 +47582 0.33001708984375 +47583 0.35687255859375 +47584 0.288818359375 +47585 0.31182861328125 +47586 0.23284912109375 +47587 0.250885009765625 +47588 0.154205322265625 +47589 0.1654052734375 +47590 0.03436279296875 +47591 0.035247802734375 +47592 -0.128936767578125 +47593 -0.142059326171875 +47594 -0.30731201171875 +47595 -0.33563232421875 +47596 -0.49066162109375 +47597 -0.5345458984375 +47598 -0.663360595703125 +47599 -0.72186279296875 +47600 -0.769378662109375 +47601 -0.836669921875 +47602 -0.766082763671875 +47603 -0.8326416015625 +47604 -0.67169189453125 +47605 -0.7296142578125 +47606 -0.5367431640625 +47607 -0.582550048828125 +47608 -0.405975341796875 +47609 -0.440093994140625 +47610 -0.299713134765625 +47611 -0.324310302734375 +47612 -0.1868896484375 +47613 -0.20147705078125 +47614 -0.042694091796875 +47615 -0.044647216796875 +47616 0.093475341796875 +47617 0.103973388671875 +47618 0.18231201171875 +47619 0.202392578125 +47620 0.23724365234375 +47621 0.264495849609375 +47622 0.3048095703125 +47623 0.338897705078125 +47624 0.402496337890625 +47625 0.443817138671875 +47626 0.49786376953125 +47627 0.545074462890625 +47628 0.5667724609375 +47629 0.6173095703125 +47630 0.601531982421875 +47631 0.6524658203125 +47632 0.614288330078125 +47633 0.66339111328125 +47634 0.610626220703125 +47635 0.6561279296875 +47636 0.567596435546875 +47637 0.606781005859375 +47638 0.471466064453125 +47639 0.501190185546875 +47640 0.334747314453125 +47641 0.352783203125 +47642 0.17144775390625 +47643 0.176544189453125 +47644 -0.025604248046875 +47645 -0.034820556640625 +47646 -0.234649658203125 +47647 -0.258209228515625 +47648 -0.407135009765625 +47649 -0.44244384765625 +47650 -0.53155517578125 +47651 -0.5753173828125 +47652 -0.60345458984375 +47653 -0.65203857421875 +47654 -0.5933837890625 +47655 -0.641632080078125 +47656 -0.518524169921875 +47657 -0.562164306640625 +47658 -0.42108154296875 +47659 -0.458038330078125 +47660 -0.321197509765625 +47661 -0.350555419921875 +47662 -0.238555908203125 +47663 -0.260528564453125 +47664 -0.176910400390625 +47665 -0.192108154296875 +47666 -0.13287353515625 +47667 -0.141937255859375 +47668 -0.0987548828125 +47669 -0.1021728515625 +47670 -0.06494140625 +47671 -0.062896728515625 +47672 -0.01959228515625 +47673 -0.011932373046875 +47674 0.0489501953125 +47675 0.062835693359375 +47676 0.128753662109375 +47677 0.148712158203125 +47678 0.216094970703125 +47679 0.241729736328125 +47680 0.317901611328125 +47681 0.34912109375 +47682 0.421295166015625 +47683 0.457305908203125 +47684 0.5048828125 +47685 0.54388427734375 +47686 0.534332275390625 +47687 0.5728759765625 +47688 0.4736328125 +47689 0.506591796875 +47690 0.32855224609375 +47691 0.351226806640625 +47692 0.13671875 +47693 0.146514892578125 +47694 -0.052215576171875 +47695 -0.05523681640625 +47696 -0.202484130859375 +47697 -0.21624755859375 +47698 -0.312713623046875 +47699 -0.334930419921875 +47700 -0.37518310546875 +47701 -0.402984619140625 +47702 -0.409820556640625 +47703 -0.4412841796875 +47704 -0.460479736328125 +47705 -0.49578857421875 +47706 -0.521209716796875 +47707 -0.5601806640625 +47708 -0.5599365234375 +47709 -0.600738525390625 +47710 -0.54498291015625 +47711 -0.584228515625 +47712 -0.446441650390625 +47713 -0.47930908203125 +47714 -0.2579345703125 +47715 -0.27935791015625 +47716 -0.002685546875 +47717 -0.0089111328125 +47718 0.259185791015625 +47719 0.268798828125 +47720 0.4603271484375 +47721 0.482818603515625 +47722 0.5728759765625 +47723 0.60369873046875 +47724 0.614990234375 +47725 0.650421142578125 +47726 0.6258544921875 +47727 0.66400146484375 +47728 0.60272216796875 +47729 0.6414794921875 +47730 0.535888671875 +47731 0.572540283203125 +47732 0.46435546875 +47733 0.498138427734375 +47734 0.4083251953125 +47735 0.439453125 +47736 0.34783935546875 +47737 0.375518798828125 +47738 0.2525634765625 +47739 0.274505615234375 +47740 0.09613037109375 +47741 0.1087646484375 +47742 -0.100311279296875 +47743 -0.099395751953125 +47744 -0.306640625 +47745 -0.3182373046875 +47746 -0.524139404296875 +47747 -0.5489501953125 +47748 -0.73602294921875 +47749 -0.7738037109375 +47750 -0.858612060546875 +47751 -0.86383056640625 +47752 -0.8660888671875 +47753 -0.870391845703125 +47754 -0.865875244140625 +47755 -0.86895751953125 +47756 -0.859344482421875 +47757 -0.861053466796875 +47758 -0.764617919921875 +47759 -0.765869140625 +47760 -0.54541015625 +47761 -0.5301513671875 +47762 -0.247955322265625 +47763 -0.214691162109375 +47764 0.086822509765625 +47765 0.137359619140625 +47766 0.41009521484375 +47767 0.474822998046875 +47768 0.688079833984375 +47769 0.76239013671875 +47770 0.858917236328125 +47771 0.867462158203125 +47772 0.870361328125 +47773 0.870361328125 +47774 0.870361328125 +47775 0.86480712890625 +47776 0.86273193359375 +47777 0.831817626953125 +47778 0.816436767578125 +47779 0.677581787109375 +47780 0.666229248046875 +47781 0.495880126953125 +47782 0.49859619140625 +47783 0.30767822265625 +47784 0.3162841796875 +47785 0.116180419921875 +47786 0.08905029296875 +47787 -0.110748291015625 +47788 -0.190460205078125 +47789 -0.381805419921875 +47790 -0.482940673828125 +47791 -0.6572265625 +47792 -0.733367919921875 +47793 -0.857421875 +47794 -0.859832763671875 +47795 -0.870391845703125 +47796 -0.869110107421875 +47797 -0.870391845703125 +47798 -0.870391845703125 +47799 -0.86444091796875 +47800 -0.869659423828125 +47801 -0.85723876953125 +47802 -0.86541748046875 +47803 -0.790008544921875 +47804 -0.834625244140625 +47805 -0.62847900390625 +47806 -0.632965087890625 +47807 -0.3956298828125 +47808 -0.38238525390625 +47809 -0.126708984375 +47810 -0.109832763671875 +47811 0.150115966796875 +47812 0.173492431640625 +47813 0.424041748046875 +47814 0.44268798828125 +47815 0.670623779296875 +47816 0.662322998046875 +47817 0.854522705078125 +47818 0.817657470703125 +47819 0.866485595703125 +47820 0.85906982421875 +47821 0.86920166015625 +47822 0.861541748046875 +47823 0.8653564453125 +47824 0.859588623046875 +47825 0.857147216796875 +47826 0.84326171875 +47827 0.766845703125 +47828 0.752777099609375 +47829 0.628509521484375 +47830 0.625946044921875 +47831 0.462127685546875 +47832 0.489471435546875 +47833 0.297210693359375 +47834 0.356658935546875 +47835 0.14862060546875 +47836 0.20672607421875 +47837 -0.00537109375 +47838 0.047088623046875 +47839 -0.15753173828125 +47840 -0.126068115234375 +47841 -0.31304931640625 +47842 -0.32708740234375 +47843 -0.48876953125 +47844 -0.51287841796875 +47845 -0.6416015625 +47846 -0.661834716796875 +47847 -0.751373291015625 +47848 -0.7982177734375 +47849 -0.84619140625 +47850 -0.860626220703125 +47851 -0.861297607421875 +47852 -0.8670654296875 +47853 -0.863250732421875 +47854 -0.86468505859375 +47855 -0.856597900390625 +47856 -0.85498046875 +47857 -0.7498779296875 +47858 -0.759735107421875 +47859 -0.624542236328125 +47860 -0.630950927734375 +47861 -0.47808837890625 +47862 -0.41778564453125 +47863 -0.253387451171875 +47864 -0.164093017578125 +47865 0.003692626953125 +47866 0.065093994140625 +47867 0.2257080078125 +47868 0.2823486328125 +47869 0.427154541015625 +47870 0.519561767578125 +47871 0.643218994140625 +47872 0.769500732421875 +47873 0.855926513671875 +47874 0.8680419921875 +47875 0.870361328125 +47876 0.870361328125 +47877 0.870361328125 +47878 0.8651123046875 +47879 0.862762451171875 +47880 0.83843994140625 +47881 0.79669189453125 +47882 0.655731201171875 +47883 0.595794677734375 +47884 0.436767578125 +47885 0.362152099609375 +47886 0.2117919921875 +47887 0.1270751953125 +47888 0.00262451171875 +47889 -0.086944580078125 +47890 -0.189300537109375 +47891 -0.2784423828125 +47892 -0.400421142578125 +47893 -0.484832763671875 +47894 -0.6533203125 +47895 -0.729583740234375 +47896 -0.85980224609375 +47897 -0.86688232421875 +47898 -0.870391845703125 +47899 -0.870391845703125 +47900 -0.870391845703125 +47901 -0.86859130859375 +47902 -0.866241455078125 +47903 -0.86279296875 +47904 -0.855377197265625 +47905 -0.817962646484375 +47906 -0.667388916015625 +47907 -0.6116943359375 +47908 -0.37738037109375 +47909 -0.3128662109375 +47910 -0.0308837890625 +47911 0.039398193359375 +47912 0.35009765625 +47913 0.422821044921875 +47914 0.73345947265625 +47915 0.805145263671875 +47916 0.870361328125 +47917 0.870361328125 +47918 0.870361328125 +47919 0.870361328125 +47920 0.860076904296875 +47921 0.860015869140625 +47922 0.729766845703125 +47923 0.727935791015625 +47924 0.48455810546875 +47925 0.48114013671875 +47926 0.210845947265625 +47927 0.2059326171875 +47928 -0.05511474609375 +47929 -0.06103515625 +47930 -0.292877197265625 +47931 -0.29913330078125 +47932 -0.50994873046875 +47933 -0.516204833984375 +47934 -0.7188720703125 +47935 -0.7252197265625 +47936 -0.859100341796875 +47937 -0.85980224609375 +47938 -0.870391845703125 +47939 -0.870391845703125 +47940 -0.870391845703125 +47941 -0.870391845703125 +47942 -0.858184814453125 +47943 -0.858062744140625 +47944 -0.675689697265625 +47945 -0.673004150390625 +47946 -0.43121337890625 +47947 -0.42694091796875 +47948 -0.2149658203125 +47949 -0.2100830078125 +47950 -0.040679931640625 +47951 -0.0362548828125 +47952 0.1060791015625 +47953 0.10943603515625 +47954 0.233184814453125 +47955 0.23516845703125 +47956 0.3726806640625 +47957 0.373687744140625 +47958 0.517303466796875 +47959 0.517791748046875 +47960 0.603271484375 +47961 0.602783203125 +47962 0.63739013671875 +47963 0.635711669921875 +47964 0.657562255859375 +47965 0.655181884765625 +47966 0.662078857421875 +47967 0.65948486328125 +47968 0.653533935546875 +47969 0.651275634765625 +47970 0.620086669921875 +47971 0.61846923828125 +47972 0.538665771484375 +47973 0.53753662109375 +47974 0.4051513671875 +47975 0.404144287109375 +47976 0.22320556640625 +47977 0.22186279296875 +47978 0.00604248046875 +47979 0.003997802734375 +47980 -0.21820068359375 +47981 -0.22100830078125 +47982 -0.421173095703125 +47983 -0.42449951171875 +47984 -0.57647705078125 +47985 -0.579833984375 +47986 -0.63958740234375 +47987 -0.641876220703125 +47988 -0.617462158203125 +47989 -0.6177978515625 +47990 -0.576873779296875 +47991 -0.575531005859375 +47992 -0.52886962890625 +47993 -0.526336669921875 +47994 -0.430389404296875 +47995 -0.42645263671875 +47996 -0.264007568359375 +47997 -0.2581787109375 +47998 -0.076202392578125 +47999 -0.068695068359375 +48000 0.083953857421875 +48001 0.09222412109375 +48002 0.2237548828125 +48003 0.232147216796875 +48004 0.34295654296875 +48005 0.3509521484375 +48006 0.403472900390625 +48007 0.410064697265625 +48008 0.369232177734375 +48009 0.372955322265625 +48010 0.2557373046875 +48011 0.2554931640625 +48012 0.11151123046875 +48013 0.10711669921875 +48014 -0.0445556640625 +48015 -0.052886962890625 +48016 -0.17486572265625 +48017 -0.186279296875 +48018 -0.22027587890625 +48019 -0.23291015625 +48020 -0.19720458984375 +48021 -0.209442138671875 +48022 -0.162994384765625 +48023 -0.174163818359375 +48024 -0.11724853515625 +48025 -0.126739501953125 +48026 -0.04119873046875 +48027 -0.048126220703125 +48028 0.046478271484375 +48029 0.0426025390625 +48030 0.1085205078125 +48031 0.10748291015625 +48032 0.13958740234375 +48033 0.1409912109375 +48034 0.19287109375 +48035 0.19708251953125 +48036 0.266448974609375 +48037 0.273651123046875 +48038 0.3082275390625 +48039 0.31768798828125 +48040 0.329986572265625 +48041 0.341094970703125 +48042 0.355560302734375 +48043 0.368011474609375 +48044 0.35943603515625 +48045 0.37249755859375 +48046 0.288665771484375 +48047 0.30072021484375 +48048 0.14227294921875 +48049 0.1517333984375 +48050 -0.02093505859375 +48051 -0.01470947265625 +48052 -0.190887451171875 +48053 -0.1883544921875 +48054 -0.37109375 +48055 -0.372711181640625 +48056 -0.50872802734375 +48057 -0.51397705078125 +48058 -0.564117431640625 +48059 -0.57177734375 +48060 -0.53082275390625 +48061 -0.53948974609375 +48062 -0.426666259765625 +48063 -0.43511962890625 +48064 -0.2886962890625 +48065 -0.2962646484375 +48066 -0.154541015625 +48067 -0.161102294921875 +48068 -0.0379638671875 +48069 -0.0435791015625 +48070 0.06494140625 +48071 0.060394287109375 +48072 0.1402587890625 +48073 0.13665771484375 +48074 0.17315673828125 +48075 0.170135498046875 +48076 0.16827392578125 +48077 0.16552734375 +48078 0.1595458984375 +48079 0.15728759765625 +48080 0.152313232421875 +48081 0.150787353515625 +48082 0.12298583984375 +48083 0.12200927734375 +48084 0.08062744140625 +48085 0.080108642578125 +48086 0.051055908203125 +48087 0.05126953125 +48088 0.06134033203125 +48089 0.062896728515625 +48090 0.089569091796875 +48091 0.09271240234375 +48092 0.088836669921875 +48093 0.092987060546875 +48094 0.07379150390625 +48095 0.07855224609375 +48096 0.059112548828125 +48097 0.06427001953125 +48098 0.029693603515625 +48099 0.0347900390625 +48100 -0.016265869140625 +48101 -0.01171875 +48102 -0.059814453125 +48103 -0.056060791015625 +48104 -0.058929443359375 +48105 -0.055511474609375 +48106 -0.014007568359375 +48107 -0.010467529296875 +48108 0.02178955078125 +48109 0.02508544921875 +48110 0.0233154296875 +48111 0.025665283203125 +48112 0.01617431640625 +48113 0.017333984375 +48114 0.002044677734375 +48115 0.00189208984375 +48116 -0.029998779296875 +48117 -0.03173828125 +48118 -0.068206787109375 +48119 -0.071502685546875 +48120 -0.130340576171875 +48121 -0.13543701171875 +48122 -0.212921142578125 +48123 -0.219970703125 +48124 -0.291778564453125 +48125 -0.300506591796875 +48126 -0.3662109375 +48127 -0.376312255859375 +48128 -0.40533447265625 +48129 -0.416107177734375 +48130 -0.360992431640625 +48131 -0.371124267578125 +48132 -0.23406982421875 +48133 -0.242279052734375 +48134 -0.0643310546875 +48135 -0.069732666015625 +48136 0.127716064453125 +48137 0.125640869140625 +48138 0.311248779296875 +48139 0.31268310546875 +48140 0.450225830078125 +48141 0.45501708984375 +48142 0.547027587890625 +48143 0.554779052734375 +48144 0.600555419921875 +48145 0.61065673828125 +48146 0.599212646484375 +48147 0.610931396484375 +48148 0.518951416015625 +48149 0.531463623046875 +48150 0.37579345703125 +48151 0.3883056640625 +48152 0.222930908203125 +48153 0.23468017578125 +48154 0.0849609375 +48155 0.095245361328125 +48156 -0.01220703125 +48157 -0.00396728515625 +48158 -0.05426025390625 +48159 -0.04852294921875 +48160 -0.05810546875 +48161 -0.055145263671875 +48162 -0.075897216796875 +48163 -0.0758056640625 +48164 -0.136016845703125 +48165 -0.138702392578125 +48166 -0.203948974609375 +48167 -0.209197998046875 +48168 -0.281585693359375 +48169 -0.289031982421875 +48170 -0.36968994140625 +48171 -0.37884521484375 +48172 -0.446014404296875 +48173 -0.456329345703125 +48174 -0.505523681640625 +48175 -0.51641845703125 +48176 -0.5084228515625 +48177 -0.519287109375 +48178 -0.448028564453125 +48179 -0.458251953125 +48180 -0.37579345703125 +48181 -0.384796142578125 +48182 -0.31634521484375 +48183 -0.323699951171875 +48184 -0.263946533203125 +48185 -0.269287109375 +48186 -0.192108154296875 +48187 -0.1951904296875 +48188 -0.099273681640625 +48189 -0.100006103515625 +48190 -0.012115478515625 +48191 -0.01055908203125 +48192 0.09967041015625 +48193 0.1033935546875 +48194 0.24346923828125 +48195 0.24908447265625 +48196 0.366058349609375 +48197 0.373199462890625 +48198 0.4498291015625 +48199 0.45806884765625 +48200 0.502593994140625 +48201 0.511474609375 +48202 0.556396484375 +48203 0.565399169921875 +48204 0.602783203125 +48205 0.61138916015625 +48206 0.58197021484375 +48207 0.5897216796875 +48208 0.484100341796875 +48209 0.4906005859375 +48210 0.326568603515625 +48211 0.33148193359375 +48212 0.144683837890625 +48213 0.147796630859375 +48214 -0.01995849609375 +48215 -0.01873779296875 +48216 -0.139617919921875 +48217 -0.140289306640625 +48218 -0.18951416015625 +48219 -0.191986083984375 +48220 -0.180206298828125 +48221 -0.184295654296875 +48222 -0.1563720703125 +48223 -0.161834716796875 +48224 -0.16009521484375 +48225 -0.166595458984375 +48226 -0.186737060546875 +48227 -0.19390869140625 +48228 -0.217010498046875 +48229 -0.22442626953125 +48230 -0.272491455078125 +48231 -0.279754638671875 +48232 -0.332244873046875 +48233 -0.3389892578125 +48234 -0.348541259765625 +48235 -0.3543701171875 +48236 -0.34356689453125 +48237 -0.348175048828125 +48238 -0.322784423828125 +48239 -0.32598876953125 +48240 -0.25653076171875 +48241 -0.2581787109375 +48242 -0.139739990234375 +48243 -0.139801025390625 +48244 0.013153076171875 +48245 0.014617919921875 +48246 0.141510009765625 +48247 0.144378662109375 +48248 0.21697998046875 +48249 0.221038818359375 +48250 0.26568603515625 +48251 0.27069091796875 +48252 0.28839111328125 +48253 0.294036865234375 +48254 0.305816650390625 +48255 0.311767578125 +48256 0.333251953125 +48257 0.339111328125 +48258 0.354766845703125 +48259 0.35992431640625 +48260 0.355712890625 +48261 0.35968017578125 +48262 0.30450439453125 +48263 0.3074951171875 +48264 0.17889404296875 +48265 0.181640625 +48266 0.003173828125 +48267 0.00616455078125 +48268 -0.1759033203125 +48269 -0.1727294921875 +48270 -0.3133544921875 +48271 -0.310638427734375 +48272 -0.365692138671875 +48273 -0.364593505859375 +48274 -0.359283447265625 +48275 -0.3603515625 +48276 -0.3394775390625 +48277 -0.342498779296875 +48278 -0.297210693359375 +48279 -0.302032470703125 +48280 -0.226409912109375 +48281 -0.232879638671875 +48282 -0.112579345703125 +48283 -0.120819091796875 +48284 0.01190185546875 +48285 0.00225830078125 +48286 0.092376708984375 +48287 0.082550048828125 +48288 0.143157958984375 +48289 0.13409423828125 +48290 0.177093505859375 +48291 0.169403076171875 +48292 0.190032958984375 +48293 0.184295654296875 +48294 0.17193603515625 +48295 0.16876220703125 +48296 0.118011474609375 +48297 0.117919921875 +48298 0.0555419921875 +48299 0.05853271484375 +48300 -0.01324462890625 +48301 -0.00732421875 +48302 -0.094818115234375 +48303 -0.08612060546875 +48304 -0.166351318359375 +48305 -0.15545654296875 +48306 -0.198974609375 +48307 -0.18701171875 +48308 -0.15386962890625 +48309 -0.142608642578125 +48310 -0.026153564453125 +48311 -0.01739501953125 +48312 0.119903564453125 +48313 0.12542724609375 +48314 0.207550048828125 +48315 0.210418701171875 +48316 0.237579345703125 +48317 0.238433837890625 +48318 0.240203857421875 +48319 0.2392578125 +48320 0.224639892578125 +48321 0.222076416015625 +48322 0.19427490234375 +48323 0.190338134765625 +48324 0.116363525390625 +48325 0.111907958984375 +48326 0.0145263671875 +48327 0.010101318359375 +48328 -0.051361083984375 +48329 -0.056060791015625 +48330 -0.10760498046875 +48331 -0.11236572265625 +48332 -0.196075439453125 +48333 -0.20001220703125 +48334 -0.290771484375 +48335 -0.293365478515625 +48336 -0.32861328125 +48337 -0.330352783203125 +48338 -0.27630615234375 +48339 -0.278289794921875 +48340 -0.182281494140625 +48341 -0.18487548828125 +48342 -0.12567138671875 +48343 -0.12799072265625 +48344 -0.113800048828125 +48345 -0.1148681640625 +48346 -0.11529541015625 +48347 -0.11474609375 +48348 -0.10552978515625 +48349 -0.103546142578125 +48350 -0.0543212890625 +48351 -0.051666259765625 +48352 0.047698974609375 +48353 0.050079345703125 +48354 0.15557861328125 +48355 0.157379150390625 +48356 0.209716796875 +48357 0.2115478515625 +48358 0.215789794921875 +48359 0.218109130859375 +48360 0.23431396484375 +48361 0.236602783203125 +48362 0.3023681640625 +48363 0.303497314453125 +48364 0.378387451171875 +48365 0.377899169921875 +48366 0.40179443359375 +48367 0.400238037109375 +48368 0.392120361328125 +48369 0.3897705078125 +48370 0.386749267578125 +48371 0.383331298828125 +48372 0.361419677734375 +48373 0.357147216796875 +48374 0.273040771484375 +48375 0.26885986328125 +48376 0.1171875 +48377 0.114227294921875 +48378 -0.054229736328125 +48379 -0.05560302734375 +48380 -0.189605712890625 +48381 -0.189788818359375 +48382 -0.283935546875 +48383 -0.283416748046875 +48384 -0.33709716796875 +48385 -0.3369140625 +48386 -0.375152587890625 +48387 -0.375579833984375 +48388 -0.443206787109375 +48389 -0.4423828125 +48390 -0.532623291015625 +48391 -0.528717041015625 +48392 -0.626800537109375 +48393 -0.618560791015625 +48394 -0.695648193359375 +48395 -0.68310546875 +48396 -0.702392578125 +48397 -0.68731689453125 +48398 -0.641448974609375 +48399 -0.6259765625 +48400 -0.49078369140625 +48401 -0.478363037109375 +48402 -0.26580810546875 +48403 -0.25933837890625 +48404 -0.024322509765625 +48405 -0.02423095703125 +48406 0.200653076171875 +48407 0.195220947265625 +48408 0.37432861328125 +48409 0.36553955078125 +48410 0.4832763671875 +48411 0.47369384765625 +48412 0.56683349609375 +48413 0.556884765625 +48414 0.632659912109375 +48415 0.6221923828125 +48416 0.63555908203125 +48417 0.62646484375 +48418 0.564117431640625 +48419 0.558746337890625 +48420 0.470367431640625 +48421 0.468597412109375 +48422 0.405548095703125 +48423 0.404876708984375 +48424 0.376800537109375 +48425 0.374542236328125 +48426 0.3763427734375 +48427 0.370361328125 +48428 0.371795654296875 +48429 0.361724853515625 +48430 0.313385009765625 +48431 0.301513671875 +48432 0.18505859375 +48433 0.1746826171875 +48434 0.012176513671875 +48435 0.00567626953125 +48436 -0.1697998046875 +48437 -0.171539306640625 +48438 -0.335968017578125 +48439 -0.333038330078125 +48440 -0.470428466796875 +48441 -0.46356201171875 +48442 -0.558807373046875 +48443 -0.54931640625 +48444 -0.57904052734375 +48445 -0.569244384765625 +48446 -0.546142578125 +48447 -0.53759765625 +48448 -0.50738525390625 +48449 -0.4993896484375 +48450 -0.458587646484375 +48451 -0.45074462890625 +48452 -0.393798828125 +48453 -0.38616943359375 +48454 -0.352386474609375 +48455 -0.343292236328125 +48456 -0.311859130859375 +48457 -0.3009033203125 +48458 -0.197906494140625 +48459 -0.188507080078125 +48460 -0.008758544921875 +48461 -0.004608154296875 +48462 0.2064208984375 +48463 0.203765869140625 +48464 0.407928466796875 +48465 0.398590087890625 +48466 0.5706787109375 +48467 0.55584716796875 +48468 0.664520263671875 +48469 0.646728515625 +48470 0.6573486328125 +48471 0.640625 +48472 0.566131591796875 +48473 0.5537109375 +48474 0.43023681640625 +48475 0.4234619140625 +48476 0.293487548828125 +48477 0.291656494140625 +48478 0.181793212890625 +48479 0.183074951171875 +48480 0.06329345703125 +48481 0.067535400390625 +48482 -0.076019287109375 +48483 -0.068115234375 +48484 -0.189178466796875 +48485 -0.179046630859375 +48486 -0.27142333984375 +48487 -0.260498046875 +48488 -0.341766357421875 +48489 -0.33038330078125 +48490 -0.36322021484375 +48491 -0.353363037109375 +48492 -0.326171875 +48493 -0.320159912109375 +48494 -0.275848388671875 +48495 -0.27374267578125 +48496 -0.2525634765625 +48497 -0.252410888671875 +48498 -0.242584228515625 +48499 -0.243072509765625 +48500 -0.197418212890625 +48501 -0.1995849609375 +48502 -0.115478515625 +48503 -0.120452880859375 +48504 -0.036285400390625 +48505 -0.04339599609375 +48506 0.035186767578125 +48507 0.0267333984375 +48508 0.091278076171875 +48509 0.08251953125 +48510 0.108642578125 +48511 0.101654052734375 +48512 0.125 +48513 0.119842529296875 +48514 0.156982421875 +48515 0.15277099609375 +48516 0.1773681640625 +48517 0.174407958984375 +48518 0.170013427734375 +48519 0.169281005859375 +48520 0.128814697265625 +48521 0.131500244140625 +48522 0.08123779296875 +48523 0.087127685546875 +48524 0.026519775390625 +48525 0.035430908203125 +48526 -0.06671142578125 +48527 -0.053497314453125 +48528 -0.1602783203125 +48529 -0.143280029296875 +48530 -0.21380615234375 +48531 -0.195404052734375 +48532 -0.235137939453125 +48533 -0.217315673828125 +48534 -0.200408935546875 +48535 -0.1861572265625 +48536 -0.119110107421875 +48537 -0.110870361328125 +48538 -0.0244140625 +48539 -0.02294921875 +48540 0.08636474609375 +48541 0.080352783203125 +48542 0.178924560546875 +48543 0.166473388671875 +48544 0.216522216796875 +48545 0.200592041015625 +48546 0.212493896484375 +48547 0.195404052734375 +48548 0.176300048828125 +48549 0.160003662109375 +48550 0.129791259765625 +48551 0.115234375 +48552 0.102874755859375 +48553 0.089599609375 +48554 0.075164794921875 +48555 0.063690185546875 +48556 0.0439453125 +48557 0.03485107421875 +48558 0.038665771484375 +48559 0.03106689453125 +48560 0.0765380859375 +48561 0.06866455078125 +48562 0.141082763671875 +48563 0.131866455078125 +48564 0.18621826171875 +48565 0.17669677734375 +48566 0.1883544921875 +48567 0.180572509765625 +48568 0.13836669921875 +48569 0.134674072265625 +48570 0.04095458984375 +48571 0.043426513671875 +48572 -0.080352783203125 +48573 -0.07086181640625 +48574 -0.2203369140625 +48575 -0.20330810546875 +48576 -0.3687744140625 +48577 -0.344146728515625 +48578 -0.49578857421875 +48579 -0.4649658203125 +48580 -0.557098388671875 +48581 -0.52362060546875 +48582 -0.50946044921875 +48583 -0.4788818359375 +48584 -0.376251220703125 +48585 -0.352996826171875 +48586 -0.219390869140625 +48587 -0.204864501953125 +48588 -0.064056396484375 +48589 -0.058349609375 +48590 0.0914306640625 +48591 0.08819580078125 +48592 0.236083984375 +48593 0.22442626953125 +48594 0.34320068359375 +48595 0.32501220703125 +48596 0.395538330078125 +48597 0.37359619140625 +48598 0.389801025390625 +48599 0.367095947265625 +48600 0.324737548828125 +48601 0.30438232421875 +48602 0.224609375 +48603 0.20855712890625 +48604 0.124786376953125 +48605 0.113311767578125 +48606 0.037567138671875 +48607 0.030364990234375 +48608 -0.009674072265625 +48609 -0.01422119140625 +48610 -0.01910400390625 +48611 -0.022552490234375 +48612 -0.022552490234375 +48613 -0.02496337890625 +48614 -0.00140380859375 +48615 -0.003814697265625 +48616 0.056365966796875 +48617 0.05230712890625 +48618 0.106658935546875 +48619 0.10137939453125 +48620 0.096710205078125 +48621 0.09307861328125 +48622 0.04241943359375 +48623 0.04248046875 +48624 -0.01837158203125 +48625 -0.01446533203125 +48626 -0.07623291015625 +48627 -0.068817138671875 +48628 -0.11981201171875 +48629 -0.109832763671875 +48630 -0.16009521484375 +48631 -0.14794921875 +48632 -0.20294189453125 +48633 -0.18878173828125 +48634 -0.2489013671875 +48635 -0.232818603515625 +48636 -0.305419921875 +48637 -0.287109375 +48638 -0.3623046875 +48639 -0.3419189453125 +48640 -0.39154052734375 +48641 -0.370697021484375 +48642 -0.3553466796875 +48643 -0.337493896484375 +48644 -0.249969482421875 +48645 -0.2386474609375 +48646 -0.092803955078125 +48647 -0.090850830078125 +48648 0.08917236328125 +48649 0.08050537109375 +48650 0.23541259765625 +48651 0.21917724609375 +48652 0.319061279296875 +48653 0.300048828125 +48654 0.358917236328125 +48655 0.340057373046875 +48656 0.348052978515625 +48657 0.33258056640625 +48658 0.285980224609375 +48659 0.27703857421875 +48660 0.2235107421875 +48661 0.220123291015625 +48662 0.197052001953125 +48663 0.195343017578125 +48664 0.18011474609375 +48665 0.178375244140625 +48666 0.155792236328125 +48667 0.15380859375 +48668 0.15142822265625 +48669 0.14697265625 +48670 0.157135009765625 +48671 0.14898681640625 +48672 0.13189697265625 +48673 0.122344970703125 +48674 0.100860595703125 +48675 0.09033203125 +48676 0.087127685546875 +48677 0.074432373046875 +48678 0.0548095703125 +48679 0.041839599609375 +48680 -0.00909423828125 +48681 -0.019256591796875 +48682 -0.1041259765625 +48683 -0.108306884765625 +48684 -0.22955322265625 +48685 -0.224578857421875 +48686 -0.355712890625 +48687 -0.34075927734375 +48688 -0.442108154296875 +48689 -0.41961669921875 +48690 -0.474029541015625 +48691 -0.447662353515625 +48692 -0.4649658203125 +48693 -0.437408447265625 +48694 -0.419219970703125 +48695 -0.392913818359375 +48696 -0.334381103515625 +48697 -0.3121337890625 +48698 -0.227935791015625 +48699 -0.211273193359375 +48700 -0.1234130859375 +48701 -0.112152099609375 +48702 -0.02752685546875 +48703 -0.021148681640625 +48704 0.077850341796875 +48705 0.078277587890625 +48706 0.2135009765625 +48707 0.205108642578125 +48708 0.38916015625 +48709 0.368194580078125 +48710 0.583160400390625 +48711 0.547515869140625 +48712 0.73443603515625 +48713 0.686920166015625 +48714 0.800537109375 +48715 0.747344970703125 +48716 0.7786865234375 +48717 0.72625732421875 +48718 0.665496826171875 +48719 0.62060546875 +48720 0.459930419921875 +48721 0.429595947265625 +48722 0.19940185546875 +48723 0.187713623046875 +48724 -0.050567626953125 +48725 -0.044586181640625 +48726 -0.232940673828125 +48727 -0.2147216796875 +48728 -0.3302001953125 +48729 -0.30645751953125 +48730 -0.3685302734375 +48731 -0.343780517578125 +48732 -0.379119873046875 +48733 -0.355224609375 +48734 -0.377227783203125 +48735 -0.354766845703125 +48736 -0.379974365234375 +48737 -0.358154296875 +48738 -0.391815185546875 +48739 -0.369384765625 +48740 -0.38568115234375 +48741 -0.36358642578125 +48742 -0.34228515625 +48743 -0.322998046875 +48744 -0.28326416015625 +48745 -0.267608642578125 +48746 -0.251983642578125 +48747 -0.23736572265625 +48748 -0.2664794921875 +48749 -0.248992919921875 +48750 -0.27362060546875 +48751 -0.25372314453125 +48752 -0.217010498046875 +48753 -0.199737548828125 +48754 -0.128387451171875 +48755 -0.1163330078125 +48756 -0.06817626953125 +48757 -0.059234619140625 +48758 -0.04302978515625 +48759 -0.034637451171875 +48760 -0.0242919921875 +48761 -0.0162353515625 +48762 0.020965576171875 +48763 0.02618408203125 +48764 0.12481689453125 +48765 0.122100830078125 +48766 0.258270263671875 +48767 0.244842529296875 +48768 0.379547119140625 +48769 0.355987548828125 +48770 0.480377197265625 +48771 0.44793701171875 +48772 0.528656005859375 +48773 0.491241455078125 +48774 0.5115966796875 +48775 0.474151611328125 +48776 0.456634521484375 +48777 0.422027587890625 +48778 0.4078369140625 +48779 0.37554931640625 +48780 0.384033203125 +48781 0.35211181640625 +48782 0.357025146484375 +48783 0.325836181640625 +48784 0.311859130859375 +48785 0.28302001953125 +48786 0.25079345703125 +48787 0.225799560546875 +48788 0.165191650390625 +48789 0.14630126953125 +48790 0.034912109375 +48791 0.026031494140625 +48792 -0.14251708984375 +48793 -0.137237548828125 +48794 -0.336181640625 +48795 -0.31512451171875 +48796 -0.53515625 +48797 -0.49755859375 +48798 -0.722503662109375 +48799 -0.668975830078125 +48800 -0.8372802734375 +48801 -0.7734375 +48802 -0.83319091796875 +48803 -0.768402099609375 +48804 -0.730072021484375 +48805 -0.672210693359375 +48806 -0.5828857421875 +48807 -0.535491943359375 +48808 -0.440277099609375 +48809 -0.403045654296875 +48810 -0.3243408203125 +48811 -0.2952880859375 +48812 -0.20135498046875 +48813 -0.1812744140625 +48814 -0.04437255859375 +48815 -0.036224365234375 +48816 0.1043701171875 +48817 0.100982666015625 +48818 0.202911376953125 +48819 0.191680908203125 +48820 0.265106201171875 +48821 0.2486572265625 +48822 0.339569091796875 +48823 0.316680908203125 +48824 0.444488525390625 +48825 0.412506103515625 +48826 0.545684814453125 +48827 0.504791259765625 +48828 0.617828369140625 +48829 0.570220947265625 +48830 0.652862548828125 +48831 0.6014404296875 +48832 0.66363525390625 +48833 0.6103515625 +48834 0.65618896484375 +48835 0.602569580078125 +48836 0.606658935546875 +48837 0.55615234375 +48838 0.500885009765625 +48839 0.4581298828125 +48840 0.352325439453125 +48841 0.32086181640625 +48842 0.17596435546875 +48843 0.158203125 +48844 -0.035491943359375 +48845 -0.036529541015625 +48846 -0.258941650390625 +48847 -0.2420654296875 +48848 -0.443206787109375 +48849 -0.41131591796875 +48850 -0.5760498046875 +48851 -0.5330810546875 +48852 -0.6527099609375 +48853 -0.602996826171875 +48854 -0.6422119140625 +48855 -0.59259033203125 +48856 -0.5626220703125 +48857 -0.518524169921875 +48858 -0.4583740234375 +48859 -0.4217529296875 +48860 -0.350738525390625 +48861 -0.3218994140625 +48862 -0.26055908203125 +48863 -0.2381591796875 +48864 -0.191986083984375 +48865 -0.174407958984375 +48866 -0.141693115234375 +48867 -0.12762451171875 +48868 -0.101837158203125 +48869 -0.090606689453125 +48870 -0.062469482421875 +48871 -0.054229736328125 +48872 -0.011444091796875 +48873 -0.007293701171875 +48874 0.0633544921875 +48875 0.06134033203125 +48876 0.149261474609375 +48877 0.1400146484375 +48878 0.242279052734375 +48879 0.225067138671875 +48880 0.349639892578125 +48881 0.323211669921875 +48882 0.457794189453125 +48883 0.4219970703125 +48884 0.5443115234375 +48885 0.5008544921875 +48886 0.573211669921875 +48887 0.5267333984375 +48888 0.506805419921875 +48889 0.464996337890625 +48890 0.351318359375 +48891 0.321380615234375 +48892 0.146484375 +48893 0.132476806640625 +48894 -0.055389404296875 +48895 -0.053558349609375 +48896 -0.21649169921875 +48897 -0.201629638671875 +48898 -0.335235595703125 +48899 -0.310455322265625 +48900 -0.403350830078125 +48901 -0.373291015625 +48902 -0.441680908203125 +48903 -0.408538818359375 +48904 -0.496185302734375 +48905 -0.457061767578125 +48906 -0.560546875 +48907 -0.5133056640625 +48908 -0.601043701171875 +48909 -0.547454833984375 +48910 -0.58447265625 +48911 -0.5301513671875 +48912 -0.479461669921875 +48913 -0.433746337890625 +48914 -0.2794189453125 +48915 -0.252593994140625 +48916 -0.008880615234375 +48917 -0.0086669921875 +48918 0.268890380859375 +48919 0.24163818359375 +48920 0.48297119140625 +48921 0.43511962890625 +48922 0.603912353515625 +48923 0.545440673828125 +48924 0.650665283203125 +48925 0.58929443359375 +48926 0.66424560546875 +48927 0.602996826171875 +48928 0.641693115234375 +48929 0.5838623046875 +48930 0.572723388671875 +48931 0.522705078125 +48932 0.498291015625 +48933 0.455902099609375 +48934 0.4395751953125 +48935 0.402313232421875 +48936 0.3756103515625 +48937 0.34344482421875 +48938 0.274566650390625 +48939 0.251129150390625 +48940 0.108795166015625 +48941 0.100982666015625 +48942 -0.099395751953125 +48943 -0.08697509765625 +48944 -0.318267822265625 +48945 -0.28436279296875 +48946 -0.54901123046875 +48947 -0.492095947265625 +48948 -0.773895263671875 +48949 -0.694305419921875 +48950 -0.86383056640625 +48951 -0.843841552734375 +48952 -0.870391845703125 +48953 -0.860687255859375 +48954 -0.86895751953125 +48955 -0.860748291015625 +48956 -0.86102294921875 +48957 -0.85479736328125 +48958 -0.765625 +48959 -0.732086181640625 +48960 -0.529876708984375 +48961 -0.52679443359375 +48962 -0.21441650390625 +48963 -0.247528076171875 +48964 0.137603759765625 +48965 0.067352294921875 +48966 0.475006103515625 +48967 0.372161865234375 +48968 0.76251220703125 +48969 0.63519287109375 +48970 0.867462158203125 +48971 0.83233642578125 +48972 0.870361328125 +48973 0.866424560546875 +48974 0.864776611328125 +48975 0.870361328125 +48976 0.831695556640625 +48977 0.866668701171875 +48978 0.677398681640625 +48979 0.85784912109375 +48980 0.49566650390625 +48981 0.762847900390625 +48982 0.30743408203125 +48983 0.615936279296875 +48984 0.115936279296875 +48985 0.44683837890625 +48986 -0.1109619140625 +48987 0.227508544921875 +48988 -0.381988525390625 +48989 -0.048248291015625 +48990 -0.6573486328125 +48991 -0.34271240234375 +48992 -0.857421875 +48993 -0.603179931640625 +48994 -0.870391845703125 +48995 -0.7921142578125 +48996 -0.870391845703125 +48997 -0.859893798828125 +48998 -0.86444091796875 +48999 -0.866363525390625 +49000 -0.85723876953125 +49001 -0.870391845703125 +49002 -0.790008544921875 +49003 -0.870391845703125 +49004 -0.62847900390625 +49005 -0.861358642578125 +49006 -0.3956298828125 +49007 -0.75006103515625 +49008 -0.126708984375 +49009 -0.527862548828125 +49010 0.150115966796875 +49011 -0.2755126953125 +49012 0.424041748046875 +49013 -0.003631591796875 +49014 0.670623779296875 +49015 0.26385498046875 +49016 0.854522705078125 +49017 0.492767333984375 +49018 0.866485595703125 +49019 0.667816162109375 +49020 0.86920166015625 +49021 0.775909423828125 +49022 0.8653564453125 +49023 0.83380126953125 +49024 0.857147216796875 +49025 0.854156494140625 +49026 0.766845703125 +49027 0.835235595703125 +49028 0.628509521484375 +49029 0.782379150390625 +49030 0.462127685546875 +49031 0.69036865234375 +49032 0.297210693359375 +49033 0.582794189453125 +49034 0.14862060546875 +49035 0.47119140625 +49036 -0.00537109375 +49037 0.335693359375 +49038 -0.15753173828125 +49039 0.183197021484375 +49040 -0.31304931640625 +49041 0.010589599609375 +49042 -0.48876953125 +49043 -0.194671630859375 +49044 -0.6416015625 +49045 -0.3912353515625 +49046 -0.751373291015625 +49047 -0.557525634765625 +49048 -0.84619140625 +49049 -0.71453857421875 +49050 -0.861297607421875 +49051 -0.849822998046875 +49052 -0.863250732421875 +49053 -0.863250732421875 +49054 -0.856597900390625 +49055 -0.863983154296875 +49056 -0.7498779296875 +49057 -0.85748291015625 +49058 -0.624542236328125 +49059 -0.80743408203125 +49060 -0.47808837890625 +49061 -0.699554443359375 +49062 -0.253387451171875 +49063 -0.50653076171875 +49064 0.003692626953125 +49065 -0.269195556640625 +49066 0.2257080078125 +49067 -0.048370361328125 +49068 0.427154541015625 +49069 0.16705322265625 +49070 0.643218994140625 +49071 0.405975341796875 +49072 0.855926513671875 +49073 0.660064697265625 +49074 0.870361328125 +49075 0.857086181640625 +49076 0.870361328125 +49077 0.870361328125 +49078 0.862762451171875 +49079 0.870361328125 +49080 0.79669189453125 +49081 0.862884521484375 +49082 0.595794677734375 +49083 0.789947509765625 +49084 0.362152099609375 +49085 0.60394287109375 +49086 0.1270751953125 +49087 0.400665283203125 +49088 -0.086944580078125 +49089 0.200225830078125 +49090 -0.2784423828125 +49091 0.004913330078125 +49092 -0.484832763671875 +49093 -0.21661376953125 +49094 -0.729583740234375 +49095 -0.482757568359375 +49096 -0.86688232421875 +49097 -0.750701904296875 +49098 -0.870391845703125 +49099 -0.86676025390625 +49100 -0.86859130859375 +49101 -0.870391845703125 +49102 -0.86279296875 +49103 -0.86956787109375 +49104 -0.817962646484375 +49105 -0.86187744140625 +49106 -0.6116943359375 +49107 -0.756622314453125 +49108 -0.3128662109375 +49109 -0.496978759765625 +49110 0.039398193359375 +49111 -0.177703857421875 +49112 0.422821044921875 +49113 0.1806640625 +49114 0.805145263671875 +49115 0.548126220703125 +49116 0.870361328125 +49117 0.855743408203125 +49118 0.870361328125 +49119 0.870361328125 +49120 0.860015869140625 +49121 0.870361328125 +49122 0.727935791015625 +49123 0.86090087890625 +49124 0.48114013671875 +49125 0.74871826171875 +49126 0.2059326171875 +49127 0.539642333984375 +49128 -0.06103515625 +49129 0.317413330078125 +49130 -0.29913330078125 +49131 0.100067138671875 +49132 -0.516204833984375 +49133 -0.118377685546875 +49134 -0.7252197265625 +49135 -0.34747314453125 +49136 -0.85980224609375 +49137 -0.563720703125 +49138 -0.870391845703125 +49139 -0.73797607421875 +49140 -0.870391845703125 +49141 -0.84796142578125 +49142 -0.858062744140625 +49143 -0.854736328125 +49144 -0.673004150390625 +49145 -0.768707275390625 +49146 -0.42694091796875 +49147 -0.640045166015625 +49148 -0.2100830078125 +49149 -0.520538330078125 +49150 -0.0362548828125 +49151 -0.418914794921875 +49152 0.10943603515625 +49153 -0.319366455078125 +49154 0.23516845703125 +49155 -0.213470458984375 +49156 0.373687744140625 +49157 -0.073699951171875 +49158 0.517791748046875 +49159 0.091888427734375 +49160 0.602783203125 +49161 0.224945068359375 +49162 0.635711669921875 +49163 0.32769775390625 +49164 0.655181884765625 +49165 0.42864990234375 +49166 0.65948486328125 +49167 0.52142333984375 +49168 0.651275634765625 +49169 0.603271484375 +49170 0.61846923828125 +49171 0.65899658203125 +49172 0.53753662109375 +49173 0.664031982421875 +49174 0.404144287109375 +49175 0.61090087890625 +49176 0.22186279296875 +49177 0.49969482421875 +49178 0.003997802734375 +49179 0.339874267578125 +49180 -0.22100830078125 +49181 0.15478515625 +49182 -0.42449951171875 +49183 -0.030853271484375 +49184 -0.579833984375 +49185 -0.19305419921875 +49186 -0.641876220703125 +49187 -0.29107666015625 +49188 -0.6177978515625 +49189 -0.328155517578125 +49190 -0.575531005859375 +49191 -0.35894775390625 +49192 -0.526336669921875 +49193 -0.389190673828125 +49194 -0.42645263671875 +49195 -0.3773193359375 +49196 -0.2581787109375 +49197 -0.304107666015625 +49198 -0.068695068359375 +49199 -0.2061767578125 +49200 0.09222412109375 +49201 -0.12274169921875 +49202 0.232147216796875 +49203 -0.044677734375 +49204 0.3509521484375 +49205 0.02978515625 +49206 0.410064697265625 +49207 0.06866455078125 +49208 0.372955322265625 +49209 0.040924072265625 +49210 0.2554931640625 +49211 -0.040496826171875 +49212 0.10711669921875 +49213 -0.134796142578125 +49214 -0.052886962890625 +49215 -0.227630615234375 +49216 -0.186279296875 +49217 -0.288970947265625 +49218 -0.23291015625 +49219 -0.2705078125 +49220 -0.209442138671875 +49221 -0.1898193359375 +49222 -0.174163818359375 +49223 -0.100189208984375 +49224 -0.126739501953125 +49225 -0.0045166015625 +49226 -0.048126220703125 +49227 0.110565185546875 +49228 0.0426025390625 +49229 0.22637939453125 +49230 0.10748291015625 +49231 0.308624267578125 +49232 0.1409912109375 +49233 0.351409912109375 +49234 0.19708251953125 +49235 0.400543212890625 +49236 0.273651123046875 +49237 0.454559326171875 +49238 0.31768798828125 +49239 0.46905517578125 +49240 0.341094970703125 +49241 0.455810546875 +49242 0.368011474609375 +49243 0.4376220703125 +49244 0.37249755859375 +49245 0.394744873046875 +49246 0.30072021484375 +49247 0.28375244140625 +49248 0.1517333984375 +49249 0.10662841796875 +49250 -0.01470947265625 +49251 -0.082763671875 +49252 -0.1883544921875 +49253 -0.27313232421875 +49254 -0.372711181640625 +49255 -0.465362548828125 +49256 -0.51397705078125 +49257 -0.61175537109375 +49258 -0.57177734375 +49259 -0.67657470703125 +49260 -0.53948974609375 +49261 -0.653656005859375 +49262 -0.43511962890625 +49263 -0.558441162109375 +49264 -0.2962646484375 +49265 -0.423736572265625 +49266 -0.161102294921875 +49267 -0.283355712890625 +49268 -0.0435791015625 +49269 -0.15081787109375 +49270 0.060394287109375 +49271 -0.024627685546875 +49272 0.13665771484375 +49273 0.0809326171875 +49274 0.170135498046875 +49275 0.150665283203125 +49276 0.16552734375 +49277 0.18634033203125 +49278 0.15728759765625 +49279 0.21533203125 +49280 0.150787353515625 +49281 0.24041748046875 +49282 0.12200927734375 +49283 0.239471435546875 +49284 0.080108642578125 +49285 0.21923828125 +49286 0.05126953125 +49287 0.201507568359375 +49288 0.062896728515625 +49289 0.20965576171875 +49290 0.09271240234375 +49291 0.22491455078125 +49292 0.092987060546875 +49293 0.207275390625 +49294 0.07855224609375 +49295 0.17059326171875 +49296 0.06427001953125 +49297 0.12908935546875 +49298 0.0347900390625 +49299 0.071380615234375 +49300 -0.01171875 +49301 -0.00225830078125 +49302 -0.056060791015625 +49303 -0.073486328125 +49304 -0.055511474609375 +49305 -0.10394287109375 +49306 -0.010467529296875 +49307 -0.092315673828125 +49308 0.02508544921875 +49309 -0.083465576171875 +49310 0.025665283203125 +49311 -0.098175048828125 +49312 0.017333984375 +49313 -0.113494873046875 +49314 0.00189208984375 +49315 -0.127655029296875 +49316 -0.03173828125 +49317 -0.1502685546875 +49318 -0.071502685546875 +49319 -0.171600341796875 +49320 -0.13543701171875 +49321 -0.207977294921875 +49322 -0.219970703125 +49323 -0.25750732421875 +49324 -0.300506591796875 +49325 -0.30047607421875 +49326 -0.376312255859375 +49327 -0.337799072265625 +49328 -0.416107177734375 +49329 -0.344207763671875 +49330 -0.371124267578125 +49331 -0.27947998046875 +49332 -0.242279052734375 +49333 -0.145782470703125 +49334 -0.069732666015625 +49335 0.021270751953125 +49336 0.125640869140625 +49337 0.202850341796875 +49338 0.31268310546875 +49339 0.371673583984375 +49340 0.45501708984375 +49341 0.496307373046875 +49342 0.554779052734375 +49343 0.57861328125 +49344 0.61065673828125 +49345 0.6177978515625 +49346 0.610931396484375 +49347 0.60443115234375 +49348 0.531463623046875 +49349 0.518768310546875 +49350 0.3883056640625 +49351 0.3756103515625 +49352 0.23468017578125 +49353 0.22174072265625 +49354 0.095245361328125 +49355 0.079559326171875 +49356 -0.00396728515625 +49357 -0.027435302734375 +49358 -0.04852294921875 +49359 -0.085693359375 +49360 -0.055145263671875 +49361 -0.108489990234375 +49362 -0.0758056640625 +49363 -0.139495849609375 +49364 -0.138702392578125 +49365 -0.20220947265625 +49366 -0.209197998046875 +49367 -0.2666015625 +49368 -0.289031982421875 +49369 -0.3341064453125 +49370 -0.37884521484375 +49371 -0.40545654296875 +49372 -0.456329345703125 +49373 -0.46197509765625 +49374 -0.51641845703125 +49375 -0.5 +49376 -0.519287109375 +49377 -0.48626708984375 +49378 -0.458251953125 +49379 -0.416015625 +49380 -0.384796142578125 +49381 -0.3343505859375 +49382 -0.323699951171875 +49383 -0.2635498046875 +49384 -0.269287109375 +49385 -0.19970703125 +49386 -0.1951904296875 +49387 -0.1212158203125 +49388 -0.100006103515625 +49389 -0.027587890625 +49390 -0.01055908203125 +49391 0.057586669921875 +49392 0.1033935546875 +49393 0.15985107421875 +49394 0.24908447265625 +49395 0.285247802734375 +49396 0.373199462890625 +49397 0.38824462890625 +49398 0.45806884765625 +49399 0.4539794921875 +49400 0.511474609375 +49401 0.489593505859375 +49402 0.565399169921875 +49403 0.52313232421875 +49404 0.61138916015625 +49405 0.548095703125 +49406 0.5897216796875 +49407 0.514190673828125 +49408 0.4906005859375 +49409 0.41400146484375 +49410 0.33148193359375 +49411 0.26348876953125 +49412 0.147796630859375 +49413 0.09356689453125 +49414 -0.01873779296875 +49415 -0.059600830078125 +49416 -0.140289306640625 +49417 -0.171783447265625 +49418 -0.191986083984375 +49419 -0.221435546875 +49420 -0.184295654296875 +49421 -0.21728515625 +49422 -0.161834716796875 +49423 -0.19720458984375 +49424 -0.166595458984375 +49425 -0.197021484375 +49426 -0.19390869140625 +49427 -0.213134765625 +49428 -0.22442626953125 +49429 -0.229522705078125 +49430 -0.279754638671875 +49431 -0.26513671875 +49432 -0.3389892578125 +49433 -0.30291748046875 +49434 -0.3543701171875 +49435 -0.302978515625 +49436 -0.348175048828125 +49437 -0.28497314453125 +49438 -0.32598876953125 +49439 -0.254364013671875 +49440 -0.2581787109375 +49441 -0.186553955078125 +49442 -0.139801025390625 +49443 -0.077850341796875 +49444 0.014617919921875 +49445 0.05902099609375 +49446 0.144378662109375 +49447 0.172210693359375 +49448 0.221038818359375 +49449 0.23748779296875 +49450 0.27069091796875 +49451 0.277130126953125 +49452 0.294036865234375 +49453 0.29193115234375 +49454 0.311767578125 +49455 0.299835205078125 +49456 0.339141845703125 +49457 0.314178466796875 +49458 0.360260009765625 +49459 0.321624755859375 +49460 0.360504150390625 +49461 0.310455322265625 +49462 0.308380126953125 +49463 0.2554931640625 +49464 0.18170166015625 +49465 0.13922119140625 +49466 0.0047607421875 +49467 -0.017578125 +49468 -0.17559814453125 +49469 -0.17572021484375 +49470 -0.3143310546875 +49471 -0.297607421875 +49472 -0.36785888671875 +49473 -0.346923828125 +49474 -0.36248779296875 +49475 -0.345123291015625 +49476 -0.343536376953125 +49477 -0.3294677734375 +49478 -0.3018798828125 +49479 -0.29254150390625 +49480 -0.231414794921875 +49481 -0.229522705078125 +49482 -0.117645263671875 +49483 -0.128814697265625 +49484 0.007049560546875 +49485 -0.017547607421875 +49486 0.087982177734375 +49487 0.0587158203125 +49488 0.13946533203125 +49489 0.111236572265625 +49490 0.17425537109375 +49491 0.149932861328125 +49492 0.188201904296875 +49493 0.17083740234375 +49494 0.171234130859375 +49495 0.165130615234375 +49496 0.118438720703125 +49497 0.128326416015625 +49498 0.05706787109375 +49499 0.08258056640625 +49500 -0.010711669921875 +49501 0.029449462890625 +49502 -0.0914306640625 +49503 -0.0364990234375 +49504 -0.162322998046875 +49505 -0.096466064453125 +49506 -0.194549560546875 +49507 -0.1265869140625 +49508 -0.1492919921875 +49509 -0.094635009765625 +49510 -0.02166748046875 +49511 0.003753662109375 +49512 0.124053955078125 +49513 0.1160888671875 +49514 0.211151123046875 +49515 0.179595947265625 +49516 0.240447998046875 +49517 0.195404052734375 +49518 0.242218017578125 +49519 0.18890380859375 +49520 0.2257080078125 +49521 0.168182373046875 +49522 0.194366455078125 +49523 0.13641357421875 +49524 0.115509033203125 +49525 0.06695556640625 +49526 0.0128173828125 +49527 -0.02044677734375 +49528 -0.053802490234375 +49529 -0.076324462890625 +49530 -0.110626220703125 +49531 -0.122344970703125 +49532 -0.199493408203125 +49533 -0.193115234375 +49534 -0.29437255859375 +49535 -0.267333984375 +49536 -0.33221435546875 +49537 -0.293304443359375 +49538 -0.27972412109375 +49539 -0.243927001953125 +49540 -0.185333251953125 +49541 -0.15948486328125 +49542 -0.128204345703125 +49543 -0.105560302734375 +49544 -0.115692138671875 +49545 -0.08856201171875 +49546 -0.116455078125 +49547 -0.08306884765625 +49548 -0.105926513671875 +49549 -0.069122314453125 +49550 -0.053955078125 +49551 -0.02215576171875 +49552 0.048797607421875 +49553 0.0653076171875 +49554 0.157318115234375 +49555 0.15606689453125 +49556 0.212005615234375 +49557 0.201019287109375 +49558 0.218475341796875 +49559 0.204803466796875 +49560 0.23724365234375 +49561 0.2174072265625 +49562 0.30535888671875 +49563 0.269561767578125 +49564 0.38128662109375 +49565 0.3272705078125 +49566 0.404449462890625 +49567 0.340911865234375 +49568 0.3944091796875 +49569 0.326904296875 +49570 0.3885498046875 +49571 0.31640625 +49572 0.362640380859375 +49573 0.289794921875 +49574 0.27362060546875 +49575 0.211822509765625 +49576 0.11712646484375 +49577 0.079132080078125 +49578 -0.054901123046875 +49579 -0.065277099609375 +49580 -0.19085693359375 +49581 -0.178741455078125 +49582 -0.28570556640625 +49583 -0.257110595703125 +49584 -0.339263916015625 +49585 -0.30029296875 +49586 -0.3775634765625 +49587 -0.32977294921875 +49588 -0.445709228515625 +49589 -0.38287353515625 +49590 -0.535064697265625 +49591 -0.452667236328125 +49592 -0.629058837890625 +49593 -0.5257568359375 +49594 -0.697601318359375 +49595 -0.577606201171875 +49596 -0.70391845703125 +49597 -0.578155517578125 +49598 -0.6424560546875 +49599 -0.523101806640625 +49600 -0.491241455078125 +49601 -0.394561767578125 +49602 -0.265716552734375 +49603 -0.2054443359375 +49604 -0.023712158203125 +49605 -0.003570556640625 +49606 0.201751708984375 +49607 0.1837158203125 +49608 0.375823974609375 +49609 0.327667236328125 +49610 0.485076904296875 +49611 0.417205810546875 +49612 0.56884765625 +49613 0.48480224609375 +49614 0.634765625 +49615 0.536865234375 +49616 0.63763427734375 +49617 0.53631591796875 +49618 0.5660400390625 +49619 0.473876953125 +49620 0.4720458984375 +49621 0.392669677734375 +49622 0.40692138671875 +49623 0.33514404296875 +49624 0.3778076171875 +49625 0.307403564453125 +49626 0.376953125 +49627 0.30328369140625 +49628 0.371978759765625 +49629 0.2962646484375 +49630 0.313140869140625 +49631 0.245513916015625 +49632 0.184417724609375 +49633 0.137939453125 +49634 0.011199951171875 +49635 -0.00543212890625 +49636 -0.171051025390625 +49637 -0.155426025390625 +49638 -0.33740234375 +49639 -0.291534423828125 +49640 -0.47198486328125 +49641 -0.4007568359375 +49642 -0.560394287109375 +49643 -0.4713134765625 +49644 -0.58056640625 +49645 -0.485198974609375 +49646 -0.54754638671875 +49647 -0.454986572265625 +49648 -0.508575439453125 +49649 -0.41973876953125 +49650 -0.459503173828125 +49651 -0.376220703125 +49652 -0.394378662109375 +49653 -0.3197021484375 +49654 -0.35260009765625 +49655 -0.282806396484375 +49656 -0.31170654296875 +49657 -0.24713134765625 +49658 -0.197418212890625 +49659 -0.15155029296875 +49660 -0.007965087890625 +49661 0.00531005859375 +49662 0.207489013671875 +49663 0.18292236328125 +49664 0.409210205078125 +49665 0.348480224609375 +49666 0.57208251953125 +49667 0.48077392578125 +49668 0.66595458984375 +49669 0.5555419921875 +49670 0.65875244140625 +49671 0.54779052734375 +49672 0.56744384765625 +49673 0.47149658203125 +49674 0.431396484375 +49675 0.358367919921875 +49676 0.29443359375 +49677 0.24365234375 +49678 0.182464599609375 +49679 0.148345947265625 +49680 0.06365966796875 +49681 0.0477294921875 +49682 -0.075958251953125 +49683 -0.068878173828125 +49684 -0.189422607421875 +49685 -0.163970947265625 +49686 -0.271942138671875 +49687 -0.233489990234375 +49688 -0.342529296875 +49689 -0.29229736328125 +49690 -0.364166259765625 +49691 -0.311004638671875 +49692 -0.327239990234375 +49693 -0.281951904296875 +49694 -0.2769775390625 +49695 -0.240997314453125 +49696 -0.253692626953125 +49697 -0.22021484375 +49698 -0.24365234375 +49699 -0.208892822265625 +49700 -0.1983642578125 +49701 -0.168853759765625 +49702 -0.116241455078125 +49703 -0.09912109375 +49704 -0.036834716796875 +49705 -0.031280517578125 +49706 0.034881591796875 +49707 0.030426025390625 +49708 0.09124755859375 +49709 0.079681396484375 +49710 0.10888671875 +49711 0.097747802734375 +49712 0.125518798828125 +49713 0.114227294921875 +49714 0.15771484375 +49715 0.142120361328125 +49716 0.17828369140625 +49717 0.159759521484375 +49718 0.17108154296875 +49719 0.154327392578125 +49720 0.129974365234375 +49721 0.12103271484375 +49722 0.082427978515625 +49723 0.0816650390625 +49724 0.027679443359375 +49725 0.0357666015625 +49726 -0.065643310546875 +49727 -0.041351318359375 +49728 -0.15936279296875 +49729 -0.1192626953125 +49730 -0.21307373046875 +49731 -0.165771484375 +49732 -0.234649658203125 +49733 -0.1868896484375 +49734 -0.2001953125 +49735 -0.1634521484375 +49736 -0.119171142578125 +49737 -0.10272216796875 +49738 -0.024749755859375 +49739 -0.03082275390625 +49740 0.085784912109375 +49741 0.054534912109375 +49742 0.178131103515625 +49743 0.12628173828125 +49744 0.215576171875 +49745 0.1553955078125 +49746 0.211456298828125 +49747 0.152435302734375 +49748 0.17523193359375 +49749 0.124847412109375 +49750 0.128753662109375 +49751 0.089874267578125 +49752 0.1019287109375 +49753 0.07110595703125 +49754 0.0743408203125 +49755 0.052215576171875 +49756 0.04327392578125 +49757 0.030853271484375 +49758 0.038177490234375 +49759 0.0301513671875 +49760 0.076263427734375 +49761 0.063568115234375 +49762 0.14105224609375 +49763 0.11785888671875 +49764 0.186431884765625 +49765 0.1563720703125 +49766 0.188812255859375 +49767 0.1602783203125 +49768 0.1390380859375 +49769 0.122222900390625 +49770 0.041778564453125 +49771 0.045867919921875 +49772 -0.079437255859375 +49773 -0.0501708984375 +49774 -0.219390869140625 +49775 -0.1617431640625 +49776 -0.367828369140625 +49777 -0.280670166015625 +49778 -0.494873046875 +49779 -0.3831787109375 +49780 -0.556243896484375 +49781 -0.43408203125 +49782 -0.508697509765625 +49783 -0.399017333984375 +49784 -0.3756103515625 +49785 -0.29632568359375 +49786 -0.218902587890625 +49787 -0.1749267578125 +49788 -0.063751220703125 +49789 -0.0545654296875 +49790 0.091552734375 +49791 0.066192626953125 +49792 0.23602294921875 +49793 0.17877197265625 +49794 0.342987060546875 +49795 0.26214599609375 +49796 0.39520263671875 +49797 0.302703857421875 +49798 0.389373779296875 +49799 0.297882080078125 +49800 0.324249267578125 +49801 0.246673583984375 +49802 0.224090576171875 +49803 0.168243408203125 +49804 0.124267578125 +49805 0.090545654296875 +49806 0.037078857421875 +49807 0.023223876953125 +49808 -0.010101318359375 +49809 -0.012115478515625 +49810 -0.019439697265625 +49811 -0.017333984375 +49812 -0.022796630859375 +49813 -0.017730712890625 +49814 -0.001556396484375 +49815 0.001251220703125 +49816 0.056304931640625 +49817 0.049041748046875 +49818 0.106719970703125 +49819 0.090606689453125 +49820 0.096893310546875 +49821 0.0841064453125 +49822 0.042694091796875 +49823 0.042022705078125 +49824 -0.018035888671875 +49825 -0.005706787109375 +49826 -0.07586669921875 +49827 -0.051605224609375 +49828 -0.11944580078125 +49829 -0.086669921875 +49830 -0.15972900390625 +49831 -0.11956787109375 +49832 -0.202606201171875 +49833 -0.154876708984375 +49834 -0.24859619140625 +49835 -0.192901611328125 +49836 -0.30517578125 +49837 -0.239471435546875 +49838 -0.36212158203125 +49839 -0.286376953125 +49840 -0.39141845703125 +49841 -0.311370849609375 +49842 -0.35528564453125 +49843 -0.284393310546875 +49844 -0.249969482421875 +49845 -0.202392578125 +49846 -0.092864990234375 +49847 -0.0791015625 +49848 0.08905029296875 +49849 0.064178466796875 +49850 0.2352294921875 +49851 0.179534912109375 +49852 0.318817138671875 +49853 0.2457275390625 +49854 0.358642578125 +49855 0.277618408203125 +49856 0.347747802734375 +49857 0.269683837890625 +49858 0.28564453125 +49859 0.221466064453125 +49860 0.223175048828125 +49861 0.173187255859375 +49862 0.196746826171875 +49863 0.15362548828125 +49864 0.179840087890625 +49865 0.141693115234375 +49866 0.155548095703125 +49867 0.123931884765625 +49868 0.151214599609375 +49869 0.121917724609375 +49870 0.156951904296875 +49871 0.12774658203125 +49872 0.13177490234375 +49873 0.10882568359375 +49874 0.100799560546875 +49875 0.08502197265625 +49876 0.087127685546875 +49877 0.0745849609375 +49878 0.05487060546875 +49879 0.049102783203125 +49880 -0.009002685546875 +49881 -0.001708984375 +49882 -0.10400390625 +49883 -0.077423095703125 +49884 -0.229400634765625 +49885 -0.177459716796875 +49886 -0.35552978515625 +49887 -0.278289794921875 +49888 -0.441925048828125 +49889 -0.347747802734375 +49890 -0.473846435546875 +49891 -0.374176025390625 +49892 -0.464813232421875 +49893 -0.3681640625 +49894 -0.419097900390625 +49895 -0.333038330078125 +49896 -0.334320068359375 +49897 -0.266876220703125 +49898 -0.227935791015625 +49899 -0.183441162109375 +49900 -0.12347412109375 +49901 -0.101348876953125 +49902 -0.02764892578125 +49903 -0.02587890625 +49904 0.077667236328125 +49905 0.057342529296875 +49906 0.2132568359375 +49907 0.164764404296875 +49908 0.38885498046875 +49909 0.3040771484375 +49910 0.582794189453125 +49911 0.4581298828125 +49912 0.734039306640625 +49913 0.578521728515625 +49914 0.800140380859375 +49915 0.631622314453125 +49916 0.7783203125 +49917 0.61517333984375 +49918 0.6651611328125 +49919 0.52642822265625 +49920 0.45965576171875 +49921 0.36505126953125 +49922 0.199188232421875 +49923 0.161163330078125 +49924 -0.050689697265625 +49925 -0.03436279296875 +49926 -0.23297119140625 +49927 -0.178070068359375 +49928 -0.33013916015625 +49929 -0.25653076171875 +49930 -0.368408203125 +49931 -0.289520263671875 +49932 -0.378936767578125 +49933 -0.3006591796875 +49934 -0.376983642578125 +49935 -0.30145263671875 +49936 -0.37969970703125 +49937 -0.304901123046875 +49938 -0.391510009765625 +49939 -0.314361572265625 +49940 -0.385345458984375 +49941 -0.30926513671875 +49942 -0.3419189453125 +49943 -0.274993896484375 +49944 -0.28289794921875 +49945 -0.2281494140625 +49946 -0.251617431640625 +49947 -0.2017822265625 +49948 -0.266143798828125 +49949 -0.209747314453125 +49950 -0.273345947265625 +49951 -0.21185302734375 +49952 -0.216796875 +49953 -0.1654052734375 +49954 -0.128265380859375 +49955 -0.094696044921875 +49956 -0.068145751953125 +49957 -0.045867919921875 +49958 -0.0430908203125 +49959 -0.024078369140625 +49960 -0.024444580078125 +49961 -0.007720947265625 +49962 0.020721435546875 +49963 0.02813720703125 +49964 0.124481201171875 +49965 0.1077880859375 +49966 0.25787353515625 +49967 0.209197998046875 +49968 0.379119873046875 +49969 0.3006591796875 +49970 0.47991943359375 +49971 0.37591552734375 +49972 0.5281982421875 +49973 0.41070556640625 +49974 0.511138916015625 +49975 0.3953857421875 +49976 0.456207275390625 +49977 0.350982666015625 +49978 0.407470703125 +49979 0.3111572265625 +49980 0.383758544921875 +49981 0.290374755859375 +49982 0.35687255859375 +49983 0.267333984375 +49984 0.31182861328125 +49985 0.23077392578125 +49986 0.250885009765625 +49987 0.1824951171875 +49988 0.1654052734375 +49989 0.116058349609375 +49990 0.035247802734375 +49991 0.0162353515625 +49992 -0.142059326171875 +49993 -0.11883544921875 +49994 -0.33563232421875 +49995 -0.265655517578125 +49996 -0.5345458984375 +49997 -0.415924072265625 +49998 -0.72186279296875 +49999 -0.556854248046875 +50000 -0.836669921875 +50001 -0.64227294921875 +50002 -0.8326416015625 +50003 -0.6370849609375 +50004 -0.7296142578125 +50005 -0.5565185546875 +50006 -0.582550048828125 +50007 -0.44244384765625 +50008 -0.440093994140625 +50009 -0.331939697265625 +50010 -0.324310302734375 +50011 -0.241912841796875 +50012 -0.20147705078125 +50013 -0.146820068359375 +50014 -0.044647216796875 +50015 -0.0262451171875 +50016 0.103973388671875 +50017 0.087646484375 +50018 0.202392578125 +50019 0.16290283203125 +50020 0.264495849609375 +50021 0.21002197265625 +50022 0.338897705078125 +50023 0.2659912109375 +50024 0.443817138671875 +50025 0.3447265625 +50026 0.545074462890625 +50027 0.4202880859375 +50028 0.6173095703125 +50029 0.4735107421875 +50030 0.6524658203125 +50031 0.49835205078125 +50032 0.66339111328125 +50033 0.50469970703125 +50034 0.6561279296875 +50035 0.49725341796875 +50036 0.606781005859375 +50037 0.457977294921875 +50038 0.501190185546875 +50039 0.376190185546875 +50040 0.352783203125 +50041 0.262115478515625 +50042 0.176544189453125 +50043 0.12725830078125 +50044 -0.034820556640625 +50045 -0.03387451171875 +50046 -0.258209228515625 +50047 -0.203704833984375 +50048 -0.44244384765625 +50049 -0.3433837890625 +50050 -0.5753173828125 +50051 -0.443603515625 +50052 -0.65203857421875 +50053 -0.50079345703125 +50054 -0.641632080078125 +50055 -0.49151611328125 +50056 -0.562164306640625 +50057 -0.429595947265625 +50058 -0.458038330078125 +50059 -0.348846435546875 +50060 -0.350555419921875 +50061 -0.265533447265625 +50062 -0.260528564453125 +50063 -0.195556640625 +50064 -0.192108154296875 +50065 -0.142181396484375 +50066 -0.141937255859375 +50067 -0.1029052734375 +50068 -0.1021728515625 +50069 -0.07183837890625 +50070 -0.062896728515625 +50071 -0.04150390625 +50072 -0.011932373046875 +50073 -0.00262451171875 +50074 0.062835693359375 +50075 0.053985595703125 +50076 0.148712158203125 +50077 0.11871337890625 +50078 0.241729736328125 +50079 0.188568115234375 +50080 0.34912109375 +50081 0.26910400390625 +50082 0.457305908203125 +50083 0.35009765625 +50084 0.54388427734375 +50085 0.414581298828125 +50086 0.5728759765625 +50087 0.435272216796875 +50088 0.506591796875 +50089 0.38360595703125 +50090 0.351226806640625 +50091 0.264373779296875 +50092 0.146514892578125 +50093 0.107818603515625 +50094 -0.05523681640625 +50095 -0.0462646484375 +50096 -0.21624755859375 +50097 -0.16912841796875 +50098 -0.334930419921875 +50099 -0.259521484375 +50100 -0.402984619140625 +50101 -0.3111572265625 +50102 -0.4412841796875 +50103 -0.33990478515625 +50104 -0.49578857421875 +50105 -0.380706787109375 +50106 -0.5601806640625 +50107 -0.4288330078125 +50108 -0.600738525390625 +50109 -0.45867919921875 +50110 -0.584228515625 +50111 -0.445037841796875 +50112 -0.47930908203125 +50113 -0.364166259765625 +50114 -0.27935791015625 +50115 -0.21112060546875 +50116 -0.0089111328125 +50117 -0.004608154296875 +50118 0.268798828125 +50119 0.207244873046875 +50120 0.482818603515625 +50121 0.37054443359375 +50122 0.60369873046875 +50123 0.462860107421875 +50124 0.650421142578125 +50125 0.498565673828125 +50126 0.66400146484375 +50127 0.508819580078125 +50128 0.6414794921875 +50129 0.49139404296875 +50130 0.572540283203125 +50131 0.4384765625 +50132 0.498138427734375 +50133 0.381256103515625 +50134 0.439453125 +50135 0.335845947265625 +50136 0.375518798828125 +50137 0.286376953125 +50138 0.274505615234375 +50139 0.20867919921875 +50140 0.1087646484375 +50141 0.081817626953125 +50142 -0.099395751953125 +50143 -0.07720947265625 +50144 -0.3182373046875 +50145 -0.244232177734375 +50146 -0.5489501953125 +50147 -0.42010498046875 +50148 -0.7738037109375 +50149 -0.591339111328125 +50150 -0.86383056640625 +50151 -0.717681884765625 +50152 -0.870391845703125 +50153 -0.77386474609375 +50154 -0.86895751953125 +50155 -0.773345947265625 +50156 -0.861053466796875 +50157 -0.726104736328125 +50158 -0.765869140625 +50159 -0.619049072265625 +50160 -0.5301513671875 +50161 -0.443634033203125 +50162 -0.214691162109375 +50163 -0.205291748046875 +50164 0.137359619140625 +50165 0.063201904296875 +50166 0.474822998046875 +50167 0.322784423828125 +50168 0.76239013671875 +50169 0.546417236328125 +50170 0.867462158203125 +50171 0.71356201171875 +50172 0.870361328125 +50173 0.824493408203125 +50174 0.86480712890625 +50175 0.856231689453125 +50176 0.831817626953125 +50177 0.85455322265625 +50178 0.677581787109375 +50179 0.797454833984375 +50180 0.495880126953125 +50181 0.701385498046875 +50182 0.30767822265625 +50183 0.5809326171875 +50184 0.116180419921875 +50185 0.438140869140625 +50186 -0.110748291015625 +50187 0.2503662109375 +50188 -0.381805419921875 +50189 0.0130615234375 +50190 -0.6572265625 +50191 -0.24212646484375 +50192 -0.857421875 +50193 -0.47113037109375 +50194 -0.870391845703125 +50195 -0.64227294921875 +50196 -0.870391845703125 +50197 -0.75006103515625 +50198 -0.86444091796875 +50199 -0.813812255859375 +50200 -0.85723876953125 +50201 -0.85504150390625 +50202 -0.790008544921875 +50203 -0.8565673828125 +50204 -0.62847900390625 +50205 -0.816131591796875 +50206 -0.3956298828125 +50207 -0.685791015625 +50208 -0.126708984375 +50209 -0.50634765625 +50210 0.150115966796875 +50211 -0.298095703125 +50212 0.424041748046875 +50213 -0.069915771484375 +50214 0.670623779296875 +50215 0.158172607421875 +50216 0.854522705078125 +50217 0.3575439453125 +50218 0.866485595703125 +50219 0.514923095703125 +50220 0.86920166015625 +50221 0.6187744140625 +50222 0.8653564453125 +50223 0.6820068359375 +50224 0.857147216796875 +50225 0.714111328125 +50226 0.766845703125 +50227 0.7127685546875 +50228 0.628509521484375 +50229 0.681671142578125 +50230 0.462127685546875 +50231 0.61590576171875 +50232 0.297210693359375 +50233 0.534393310546875 +50234 0.14862060546875 +50235 0.4462890625 +50236 -0.00537109375 +50237 0.335235595703125 +50238 -0.15753173828125 +50239 0.20697021484375 +50240 -0.31304931640625 +50241 0.0592041015625 +50242 -0.48876953125 +50243 -0.117919921875 +50244 -0.6416015625 +50245 -0.2899169921875 +50246 -0.751373291015625 +50247 -0.438446044921875 +50248 -0.84619140625 +50249 -0.580047607421875 +50250 -0.861297607421875 +50251 -0.703765869140625 +50252 -0.863250732421875 +50253 -0.7852783203125 +50254 -0.856597900390625 +50255 -0.801513671875 +50256 -0.7498779296875 +50257 -0.76129150390625 +50258 -0.624542236328125 +50259 -0.706787109375 +50260 -0.47808837890625 +50261 -0.62213134765625 +50262 -0.253387451171875 +50263 -0.46490478515625 +50264 0.003692626953125 +50265 -0.26861572265625 +50266 0.2257080078125 +50267 -0.083282470703125 +50268 0.427154541015625 +50269 0.099884033203125 +50270 0.643218994140625 +50271 0.30413818359375 +50272 0.855926513671875 +50273 0.52215576171875 +50274 0.870361328125 +50275 0.71148681640625 +50276 0.870361328125 +50277 0.83575439453125 +50278 0.862762451171875 +50279 0.85943603515625 +50280 0.79669189453125 +50281 0.859649658203125 +50282 0.595794677734375 +50283 0.83465576171875 +50284 0.362152099609375 +50285 0.71942138671875 +50286 0.1270751953125 +50287 0.57672119140625 +50288 -0.086944580078125 +50289 0.422149658203125 +50290 -0.2784423828125 +50291 0.257415771484375 +50292 -0.484832763671875 +50293 0.0574951171875 +50294 -0.729583740234375 +50295 -0.191314697265625 +50296 -0.86688232421875 +50297 -0.45184326171875 +50298 -0.870391845703125 +50299 -0.67767333984375 +50300 -0.86859130859375 +50301 -0.85565185546875 +50302 -0.86279296875 +50303 -0.870391845703125 +50304 -0.817962646484375 +50305 -0.870391845703125 +50306 -0.6116943359375 +50307 -0.860260009765625 +50308 -0.3128662109375 +50309 -0.7203369140625 +50310 0.039398193359375 +50311 -0.46673583984375 +50312 0.422821044921875 +50313 -0.163330078125 +50314 0.805145263671875 +50315 0.16424560546875 +50316 0.870361328125 +50317 0.4659423828125 +50318 0.870361328125 +50319 0.700714111328125 +50320 0.860015869140625 +50321 0.855224609375 +50322 0.727935791015625 +50323 0.8642578125 +50324 0.48114013671875 +50325 0.8646240234375 +50326 0.2059326171875 +50327 0.858642578125 +50328 -0.06103515625 +50329 0.79901123046875 +50330 -0.29913330078125 +50331 0.677520751953125 +50332 -0.516204833984375 +50333 0.521026611328125 +50334 -0.7252197265625 +50335 0.32147216796875 +50336 -0.85980224609375 +50337 0.099761962890625 +50338 -0.870391845703125 +50339 -0.11688232421875 +50340 -0.870391845703125 +50341 -0.305328369140625 +50342 -0.858062744140625 +50343 -0.42919921875 +50344 -0.673004150390625 +50345 -0.4852294921875 +50346 -0.42694091796875 +50347 -0.512176513671875 +50348 -0.2100830078125 +50349 -0.54351806640625 +50350 -0.0362548828125 +50351 -0.5794677734375 +50352 0.10943603515625 +50353 -0.60107421875 +50354 0.23516845703125 +50355 -0.596405029296875 +50356 0.373687744140625 +50357 -0.538055419921875 +50358 0.517791748046875 +50359 -0.430267333984375 +50360 0.602783203125 +50361 -0.321563720703125 +50362 0.635711669921875 +50363 -0.21063232421875 +50364 0.655181884765625 +50365 -0.07525634765625 +50366 0.65948486328125 +50367 0.07568359375 +50368 0.651275634765625 +50369 0.235321044921875 +50370 0.61846923828125 +50371 0.385284423828125 +50372 0.53753662109375 +50373 0.498748779296875 +50374 0.404144287109375 +50375 0.563232421875 +50376 0.22186279296875 +50377 0.57281494140625 +50378 0.003997802734375 +50379 0.529998779296875 +50380 -0.22100830078125 +50381 0.449920654296875 +50382 -0.42449951171875 +50383 0.349761962890625 +50384 -0.579833984375 +50385 0.247344970703125 +50386 -0.641876220703125 +50387 0.176055908203125 +50388 -0.6177978515625 +50389 0.13311767578125 +50390 -0.575531005859375 +50391 0.0733642578125 +50392 -0.526336669921875 +50393 -0.005584716796875 +50394 -0.42645263671875 +50395 -0.06494140625 +50396 -0.2581787109375 +50397 -0.084075927734375 +50398 -0.068695068359375 +50399 -0.08935546875 +50400 0.09222412109375 +50401 -0.109100341796875 +50402 0.232147216796875 +50403 -0.13055419921875 +50404 0.3509521484375 +50405 -0.147491455078125 +50406 0.410064697265625 +50407 -0.182891845703125 +50408 0.372955322265625 +50409 -0.25982666015625 +50410 0.2554931640625 +50411 -0.364837646484375 +50412 0.10711669921875 +50413 -0.461761474609375 +50414 -0.052886962890625 +50415 -0.53802490234375 +50416 -0.186279296875 +50417 -0.56878662109375 +50418 -0.23291015625 +50419 -0.514678955078125 +50420 -0.209442138671875 +50421 -0.39324951171875 +50422 -0.174163818359375 +50423 -0.25311279296875 +50424 -0.126739501953125 +50425 -0.10052490234375 +50426 -0.048126220703125 +50427 0.07177734375 +50428 0.0426025390625 +50429 0.2437744140625 +50430 0.10748291015625 +50431 0.38232421875 +50432 0.1409912109375 +50433 0.478363037109375 +50434 0.19708251953125 +50435 0.567047119140625 +50436 0.273651123046875 +50437 0.645599365234375 +50438 0.31768798828125 +50439 0.6761474609375 +50440 0.341094970703125 +50441 0.667694091796875 +50442 0.368011474609375 +50443 0.639129638671875 +50444 0.37249755859375 +50445 0.575469970703125 +50446 0.30072021484375 +50447 0.44317626953125 +50448 0.1517333984375 +50449 0.2464599609375 +50450 -0.01470947265625 +50451 0.032470703125 +50452 -0.1883544921875 +50453 -0.18609619140625 +50454 -0.372711181640625 +50455 -0.40643310546875 +50456 -0.51397705078125 +50457 -0.586090087890625 +50458 -0.57177734375 +50459 -0.692657470703125 +50460 -0.53948974609375 +50461 -0.71832275390625 +50462 -0.43511962890625 +50463 -0.673614501953125 +50464 -0.2962646484375 +50465 -0.583831787109375 +50466 -0.161102294921875 +50467 -0.475921630859375 +50468 -0.0435791015625 +50469 -0.360931396484375 +50470 0.060394287109375 +50471 -0.238372802734375 +50472 0.13665771484375 +50473 -0.121307373046875 +50474 0.170135498046875 +50475 -0.024169921875 +50476 0.16552734375 +50477 0.052032470703125 +50478 0.15728759765625 +50479 0.12689208984375 +50480 0.150787353515625 +50481 0.19976806640625 +50482 0.12200927734375 +50483 0.24969482421875 +50484 0.080108642578125 +50485 0.27947998046875 +50486 0.05126953125 +50487 0.304534912109375 +50488 0.062896728515625 +50489 0.34197998046875 +50490 0.09271240234375 +50491 0.37506103515625 +50492 0.092987060546875 +50493 0.37017822265625 +50494 0.07855224609375 +50495 0.3385009765625 +50496 0.06427001953125 +50497 0.292083740234375 +50498 0.0347900390625 +50499 0.22259521484375 +50500 -0.01171875 +50501 0.131744384765625 +50502 -0.056060791015625 +50503 0.03643798828125 +50504 -0.055511474609375 +50505 -0.029693603515625 +50506 -0.010467529296875 +50507 -0.063232421875 +50508 0.02508544921875 +50509 -0.09844970703125 +50510 0.025665283203125 +50511 -0.150054931640625 +50512 0.017333984375 +50513 -0.197235107421875 +50514 0.00189208984375 +50515 -0.23675537109375 +50516 -0.03173828125 +50517 -0.27520751953125 +50518 -0.071502685546875 +50519 -0.30377197265625 +50520 -0.13543701171875 +50521 -0.33538818359375 +50522 -0.219970703125 +50523 -0.368682861328125 +50524 -0.300506591796875 +50525 -0.38818359375 +50526 -0.376312255859375 +50527 -0.395721435546875 +50528 -0.416107177734375 +50529 -0.37213134765625 +50530 -0.371124267578125 +50531 -0.2862548828125 +50532 -0.242279052734375 +50533 -0.14178466796875 +50534 -0.069732666015625 +50535 0.030181884765625 +50536 0.125640869140625 +50537 0.212310791015625 +50538 0.31268310546875 +50539 0.380523681640625 +50540 0.45501708984375 +50541 0.507568359375 +50542 0.554779052734375 +50543 0.593719482421875 +50544 0.61065673828125 +50545 0.63751220703125 +50546 0.610931396484375 +50547 0.630828857421875 +50548 0.531463623046875 +50549 0.557464599609375 +50550 0.3883056640625 +50551 0.429931640625 +50552 0.23468017578125 +50553 0.2872314453125 +50554 0.095245361328125 +50555 0.148773193359375 +50556 -0.00396728515625 +50557 0.03515625 +50558 -0.04852294921875 +50559 -0.041015625 +50560 -0.055145263671875 +50561 -0.08892822265625 +50562 -0.0758056640625 +50563 -0.1427001953125 +50564 -0.138702392578125 +50565 -0.22003173828125 +50566 -0.209197998046875 +50567 -0.295013427734375 +50568 -0.289031982421875 +50569 -0.367706298828125 +50570 -0.37884521484375 +50571 -0.4378662109375 +50572 -0.456329345703125 +50573 -0.48974609375 +50574 -0.51641845703125 +50575 -0.520233154296875 +50576 -0.519287109375 +50577 -0.5023193359375 +50578 -0.458251953125 +50579 -0.432647705078125 +50580 -0.384796142578125 +50581 -0.348968505859375 +50582 -0.323699951171875 +50583 -0.2705078125 +50584 -0.269287109375 +50585 -0.195343017578125 +50586 -0.1951904296875 +50587 -0.107086181640625 +50588 -0.100006103515625 +50589 -0.0067138671875 +50590 -0.01055908203125 +50591 0.085205078125 +50592 0.1033935546875 +50593 0.188385009765625 +50594 0.24908447265625 +50595 0.306793212890625 +50596 0.373199462890625 +50597 0.40240478515625 +50598 0.45806884765625 +50599 0.46258544921875 +50600 0.511474609375 +50601 0.49298095703125 +50602 0.565399169921875 +50603 0.516571044921875 +50604 0.61138916015625 +50605 0.528411865234375 +50606 0.5897216796875 +50607 0.488006591796875 +50608 0.4906005859375 +50609 0.389984130859375 +50610 0.33148193359375 +50611 0.248291015625 +50612 0.147796630859375 +50613 0.08935546875 +50614 -0.01873779296875 +50615 -0.055938720703125 +50616 -0.140289306640625 +50617 -0.16656494140625 +50618 -0.191986083984375 +50619 -0.22381591796875 +50620 -0.184295654296875 +50621 -0.2340087890625 +50622 -0.161834716796875 +50623 -0.227691650390625 +50624 -0.166595458984375 +50625 -0.233917236328125 +50626 -0.19390869140625 +50627 -0.249420166015625 +50628 -0.22442626953125 +50629 -0.26104736328125 +50630 -0.279754638671875 +50631 -0.28466796875 +50632 -0.3389892578125 +50633 -0.306610107421875 +50634 -0.3543701171875 +50635 -0.294647216796875 +50636 -0.348175048828125 +50637 -0.26568603515625 +50638 -0.32598876953125 +50639 -0.22503662109375 +50640 -0.2581787109375 +50641 -0.153350830078125 +50642 -0.139801025390625 +50643 -0.048431396484375 +50644 0.014617919921875 +50645 0.07843017578125 +50646 0.144378662109375 +50647 0.183746337890625 +50648 0.221038818359375 +50649 0.246978759765625 +50650 0.27069091796875 +50651 0.2860107421875 +50652 0.294036865234375 +50653 0.301239013671875 +50654 0.311767578125 +50655 0.307373046875 +50656 0.339141845703125 +50657 0.3155517578125 +50658 0.360260009765625 +50659 0.315338134765625 +50660 0.360504150390625 +50661 0.297454833984375 +50662 0.308380126953125 +50663 0.241058349609375 +50664 0.18170166015625 +50665 0.131866455078125 +50666 0.0047607421875 +50667 -0.011962890625 +50668 -0.17559814453125 +50669 -0.15673828125 +50670 -0.3143310546875 +50671 -0.270111083984375 +50672 -0.36785888671875 +50673 -0.320892333984375 +50674 -0.36248779296875 +50675 -0.32672119140625 +50676 -0.343536376953125 +50677 -0.318756103515625 +50678 -0.3018798828125 +50679 -0.290496826171875 +50680 -0.231414794921875 +50681 -0.237762451171875 +50682 -0.117645263671875 +50683 -0.150787353515625 +50684 0.007049560546875 +50685 -0.05267333984375 +50686 0.087982177734375 +50687 0.017822265625 +50688 0.13946533203125 +50689 0.069793701171875 +50690 0.17425537109375 +50691 0.1112060546875 +50692 0.188201904296875 +50693 0.13812255859375 +50694 0.171234130859375 +50695 0.143035888671875 +50696 0.118438720703125 +50697 0.121978759765625 +50698 0.05706787109375 +50699 0.092437744140625 +50700 -0.010711669921875 +50701 0.055328369140625 +50702 -0.0914306640625 +50703 0.006011962890625 +50704 -0.162322998046875 +50705 -0.04046630859375 +50706 -0.194549560546875 +50707 -0.06488037109375 +50708 -0.1492919921875 +50709 -0.04119873046875 +50710 -0.02166748046875 +50711 0.03424072265625 +50712 0.124053955078125 +50713 0.119384765625 +50714 0.211151123046875 +50715 0.1639404296875 +50716 0.240447998046875 +50717 0.16925048828125 +50718 0.242218017578125 +50719 0.15618896484375 +50720 0.2257080078125 +50721 0.131683349609375 +50722 0.194366455078125 +50723 0.098724365234375 +50724 0.115509033203125 +50725 0.03619384765625 +50726 0.0128173828125 +50727 -0.03961181640625 +50728 -0.053802490234375 +50729 -0.088623046875 +50730 -0.110626220703125 +50731 -0.128082275390625 +50732 -0.199493408203125 +50733 -0.185791015625 +50734 -0.29437255859375 +50735 -0.24462890625 +50736 -0.33221435546875 +50737 -0.263031005859375 +50738 -0.27972412109375 +50739 -0.219329833984375 +50740 -0.185333251953125 +50741 -0.146240234375 +50742 -0.128204345703125 +50743 -0.096923828125 +50744 -0.115692138671875 +50745 -0.076904296875 +50746 -0.116455078125 +50747 -0.066009521484375 +50748 -0.105926513671875 +50749 -0.04852294921875 +50750 -0.053955078125 +50751 -0.0050048828125 +50752 0.048797607421875 +50753 0.070281982421875 +50754 0.157318115234375 +50755 0.14715576171875 +50756 0.212005615234375 +50757 0.185791015625 +50758 0.218475341796875 +50759 0.18988037109375 +50760 0.23724365234375 +50761 0.19970703125 +50762 0.30535888671875 +50763 0.2401123046875 +50764 0.38128662109375 +50765 0.2838134765625 +50766 0.404449462890625 +50767 0.290985107421875 +50768 0.3944091796875 +50769 0.275115966796875 +50770 0.3885498046875 +50771 0.261566162109375 +50772 0.362640380859375 +50773 0.23480224609375 +50774 0.27362060546875 +50775 0.166717529296875 +50776 0.11712646484375 +50777 0.054901123046875 +50778 -0.054901123046875 +50779 -0.06573486328125 +50780 -0.19085693359375 +50781 -0.160614013671875 +50782 -0.28570556640625 +50783 -0.2261962890625 +50784 -0.339263916015625 +50785 -0.262298583984375 +50786 -0.3775634765625 +50787 -0.286224365234375 +50788 -0.445709228515625 +50789 -0.32806396484375 +50790 -0.535064697265625 +50791 -0.38232421875 +50792 -0.629058837890625 +50793 -0.438323974609375 +50794 -0.697601318359375 +50795 -0.476470947265625 +50796 -0.70391845703125 +50797 -0.4727783203125 +50798 -0.6424560546875 +50799 -0.423980712890625 +50800 -0.491241455078125 +50801 -0.315948486328125 +50802 -0.265716552734375 +50803 -0.159332275390625 +50804 -0.023712158203125 +50805 0.007080078125 +50806 0.201751708984375 +50807 0.16107177734375 +50808 0.375823974609375 +50809 0.27935791015625 +50810 0.485076904296875 +50811 0.352874755859375 +50812 0.56884765625 +50813 0.40777587890625 +50814 0.634765625 +50815 0.449188232421875 +50816 0.63763427734375 +50817 0.447296142578125 +50818 0.5660400390625 +50819 0.394775390625 +50820 0.4720458984375 +50821 0.326507568359375 +50822 0.40692138671875 +50823 0.27685546875 +50824 0.3778076171875 +50825 0.25091552734375 +50826 0.376953125 +50827 0.243896484375 +50828 0.371978759765625 +50829 0.23468017578125 +50830 0.313140869140625 +50831 0.1905517578125 +50832 0.184417724609375 +50833 0.101104736328125 +50834 0.011199951171875 +50835 -0.016571044921875 +50836 -0.171051025390625 +50837 -0.138824462890625 +50838 -0.33740234375 +50839 -0.249114990234375 +50840 -0.47198486328125 +50841 -0.336944580078125 +50842 -0.560394287109375 +50843 -0.39288330078125 +50844 -0.58056640625 +50845 -0.4024658203125 +50846 -0.54754638671875 +50847 -0.375885009765625 +50848 -0.508575439453125 +50849 -0.344818115234375 +50850 -0.459503173828125 +50851 -0.306793212890625 +50852 -0.394378662109375 +50853 -0.2581787109375 +50854 -0.35260009765625 +50855 -0.22540283203125 +50856 -0.31170654296875 +50857 -0.19378662109375 +50858 -0.197418212890625 +50859 -0.114288330078125 +50860 -0.007965087890625 +50861 0.01409912109375 +50862 0.207489013671875 +50863 0.158599853515625 +50864 0.409210205078125 +50865 0.292755126953125 +50866 0.57208251953125 +50867 0.399932861328125 +50868 0.66595458984375 +50869 0.460205078125 +50870 0.65875244140625 +50871 0.45245361328125 +50872 0.56744384765625 +50873 0.388092041015625 +50874 0.431396484375 +50875 0.29351806640625 +50876 0.29443359375 +50877 0.198089599609375 +50878 0.182464599609375 +50879 0.1192626953125 +50880 0.06365966796875 +50881 0.0361328125 +50882 -0.075958251953125 +50883 -0.060333251953125 +50884 -0.189422607421875 +50885 -0.1387939453125 +50886 -0.271942138671875 +50887 -0.195892333984375 +50888 -0.342529296875 +50889 -0.244140625 +50890 -0.364166259765625 +50891 -0.258941650390625 +50892 -0.327239990234375 +50893 -0.233917236328125 +50894 -0.2769775390625 +50895 -0.19915771484375 +50896 -0.253692626953125 +50897 -0.1815185546875 +50898 -0.24365234375 +50899 -0.1719970703125 +50900 -0.1983642578125 +50901 -0.13861083984375 +50902 -0.116241455078125 +50903 -0.080474853515625 +50904 -0.036834716796875 +50905 -0.0240478515625 +50906 0.034881591796875 +50907 0.027130126953125 +50908 0.09124755859375 +50909 0.067779541015625 +50910 0.10888671875 +50911 0.082244873046875 +50912 0.125518798828125 +50913 0.095428466796875 +50914 0.15771484375 +50915 0.118255615234375 +50916 0.17828369140625 +50917 0.132568359375 +50918 0.17108154296875 +50919 0.127655029296875 +50920 0.129974365234375 +50921 0.099456787109375 +50922 0.082427978515625 +50923 0.0662841796875 +50924 0.027679443359375 +50925 0.027740478515625 +50926 -0.065643310546875 +50927 -0.036834716796875 +50928 -0.15936279296875 +50929 -0.1019287109375 +50930 -0.21307373046875 +50931 -0.140594482421875 +50932 -0.234649658203125 +50933 -0.157867431640625 +50934 -0.2001953125 +50935 -0.1376953125 +50936 -0.119171142578125 +50937 -0.086273193359375 +50938 -0.024749755859375 +50939 -0.025482177734375 +50940 0.085784912109375 +50941 0.046539306640625 +50942 0.178131103515625 +50943 0.107086181640625 +50944 0.215576171875 +50945 0.13201904296875 +50946 0.211456298828125 +50947 0.13031005859375 +50948 0.17523193359375 +50949 0.108306884765625 +50950 0.128753662109375 +50951 0.079833984375 +50952 0.1019287109375 +50953 0.063812255859375 +50954 0.0743408203125 +50955 0.047332763671875 +50956 0.04327392578125 +50957 0.02862548828125 +50958 0.038177490234375 +50959 0.0262451171875 +50960 0.076263427734375 +50961 0.051025390625 +50962 0.14105224609375 +50963 0.092498779296875 +50964 0.186431884765625 +50965 0.121551513671875 +50966 0.188812255859375 +50967 0.12322998046875 +50968 0.1390380859375 +50969 0.09173583984375 +50970 0.041778564453125 +50971 0.030029296875 +50972 -0.079437255859375 +50973 -0.046966552734375 +50974 -0.219390869140625 +50975 -0.135986328125 +50976 -0.367828369140625 +50977 -0.23046875 +50978 -0.494873046875 +50979 -0.3115234375 +50980 -0.556243896484375 +50981 -0.351104736328125 +50982 -0.508697509765625 +50983 -0.32183837890625 +50984 -0.3756103515625 +50985 -0.238433837890625 +50986 -0.218902587890625 +50987 -0.1400146484375 +50988 -0.063751220703125 +50989 -0.042449951171875 +50990 0.091552734375 +50991 0.0552978515625 +50992 0.23602294921875 +50993 0.146331787109375 +50994 0.342987060546875 +50995 0.21380615234375 +50996 0.39520263671875 +50997 0.246856689453125 +50998 0.389373779296875 +50999 0.243377685546875 +51000 0.324249267578125 +51001 0.20257568359375 +51002 0.224090576171875 +51003 0.139739990234375 +51004 0.124267578125 +51005 0.07720947265625 +51006 0.037078857421875 +51007 0.022705078125 +51008 -0.010101318359375 +51009 -0.0064697265625 +51010 -0.019439697265625 +51011 -0.01171875 +51012 -0.022796630859375 +51013 -0.01324462890625 +51014 -0.001556396484375 +51015 0.00067138671875 +51016 0.056304931640625 +51017 0.037628173828125 +51018 0.106719970703125 +51019 0.06976318359375 +51020 0.096893310546875 +51021 0.063690185546875 +51022 0.042694091796875 +51023 0.0294189453125 +51024 -0.018035888671875 +51025 -0.009124755859375 +51026 -0.07586669921875 +51027 -0.04595947265625 +51028 -0.11944580078125 +51029 -0.0738525390625 +51030 -0.15972900390625 +51031 -0.0997314453125 +51032 -0.202606201171875 +51033 -0.127288818359375 +51034 -0.24859619140625 +51035 -0.156829833984375 +51036 -0.30517578125 +51037 -0.193023681640625 +51038 -0.36212158203125 +51039 -0.229400634765625 +51040 -0.39141845703125 +51041 -0.248291015625 +51042 -0.35528564453125 +51043 -0.225738525390625 +51044 -0.249969482421875 +51045 -0.15936279296875 +51046 -0.092864990234375 +51047 -0.0601806640625 +51048 0.08905029296875 +51049 0.054779052734375 +51050 0.2352294921875 +51051 0.147216796875 +51052 0.318817138671875 +51053 0.200164794921875 +51054 0.358642578125 +51055 0.22552490234375 +51056 0.347747802734375 +51057 0.2188720703125 +51058 0.28564453125 +51059 0.179901123046875 +51060 0.223175048828125 +51061 0.1407470703125 +51062 0.196746826171875 +51063 0.124359130859375 +51064 0.179840087890625 +51065 0.113983154296875 +51066 0.155548095703125 +51067 0.098907470703125 +51068 0.151214599609375 +51069 0.096405029296875 +51070 0.156951904296875 +51071 0.100250244140625 +51072 0.13177490234375 +51073 0.084503173828125 +51074 0.100799560546875 +51075 0.065032958984375 +51076 0.087127685546875 +51077 0.056396484375 +51078 0.05487060546875 +51079 0.03594970703125 +51080 -0.009002685546875 +51081 -0.004547119140625 +51082 -0.10400390625 +51083 -0.06475830078125 +51084 -0.229400634765625 +51085 -0.14422607421875 +51086 -0.35552978515625 +51087 -0.22418212890625 +51088 -0.441925048828125 +51089 -0.279022216796875 +51090 -0.473846435546875 +51091 -0.299407958984375 +51092 -0.464813232421875 +51093 -0.29388427734375 +51094 -0.419097900390625 +51095 -0.26513671875 +51096 -0.334320068359375 +51097 -0.211669921875 +51098 -0.227935791015625 +51099 -0.144500732421875 +51100 -0.12347412109375 +51101 -0.0784912109375 +51102 -0.02764892578125 +51103 -0.01788330078125 +51104 0.077667236328125 +51105 0.04876708984375 +51106 0.2132568359375 +51107 0.134552001953125 +51108 0.38885498046875 +51109 0.245635986328125 +51110 0.582794189453125 +51111 0.3682861328125 +51112 0.734039306640625 +51113 0.463958740234375 +51114 0.800140380859375 +51115 0.505828857421875 +51116 0.7783203125 +51117 0.492095947265625 +51118 0.6651611328125 +51119 0.420623779296875 +51120 0.45965576171875 +51121 0.290771484375 +51122 0.199188232421875 +51123 0.12615966796875 +51124 -0.050689697265625 +51125 -0.031768798828125 +51126 -0.23297119140625 +51127 -0.147003173828125 +51128 -0.33013916015625 +51129 -0.208465576171875 +51130 -0.368408203125 +51131 -0.232666015625 +51132 -0.378936767578125 +51133 -0.23931884765625 +51134 -0.376983642578125 +51135 -0.23809814453125 +51136 -0.37969970703125 +51137 -0.239837646484375 +51138 -0.391510009765625 +51139 -0.247314453125 +51140 -0.385345458984375 +51141 -0.243408203125 +51142 -0.3419189453125 +51143 -0.2159423828125 +51144 -0.28289794921875 +51145 -0.178619384765625 +51146 -0.251617431640625 +51147 -0.158843994140625 +51148 -0.266143798828125 +51149 -0.167999267578125 +51150 -0.273345947265625 +51151 -0.17254638671875 +51152 -0.216796875 +51153 -0.136810302734375 +51154 -0.128265380859375 +51155 -0.080841064453125 +51156 -0.068145751953125 +51157 -0.0428466796875 +51158 -0.0430908203125 +51159 -0.027008056640625 +51160 -0.024444580078125 +51161 -0.015228271484375 +51162 0.020721435546875 +51163 0.013336181640625 +51164 0.124481201171875 +51165 0.07891845703125 +51166 0.25787353515625 +51167 0.1632080078125 +51168 0.379119873046875 +51169 0.23980712890625 +51170 0.47991943359375 +51171 0.303466796875 +51172 0.5281982421875 +51173 0.33392333984375 +51174 0.511138916015625 +51175 0.323089599609375 +51176 0.456207275390625 +51177 0.288299560546875 +51178 0.407470703125 +51179 0.257415771484375 +51180 0.383758544921875 +51181 0.242340087890625 +51182 0.35687255859375 +51183 0.225250244140625 +51184 0.31182861328125 +51185 0.196685791015625 +51186 0.250885009765625 +51187 0.158111572265625 +51188 0.1654052734375 +51189 0.104034423828125 +51190 0.035247802734375 +51191 0.021759033203125 +51192 -0.142059326171875 +51193 -0.09027099609375 +51194 -0.33563232421875 +51195 -0.2125244140625 +51196 -0.5345458984375 +51197 -0.338104248046875 +51198 -0.72186279296875 +51199 -0.456329345703125 +51200 -0.836669921875 +51201 -0.5291748046875 +51202 -0.8326416015625 +51203 -0.528045654296875 +51204 -0.7296142578125 +51205 -0.46484375 +51206 -0.582550048828125 +51207 -0.373016357421875 +51208 -0.440093994140625 +51209 -0.28228759765625 +51210 -0.324310302734375 +51211 -0.206451416015625 +51212 -0.20147705078125 +51213 -0.12579345703125 +51214 -0.044647216796875 +51215 -0.02459716796875 +51216 0.103973388671875 +51217 0.0712890625 +51218 0.202392578125 +51219 0.136260986328125 +51220 0.264495849609375 +51221 0.1783447265625 +51222 0.338897705078125 +51223 0.22650146484375 +51224 0.443817138671875 +51225 0.291473388671875 +51226 0.545074462890625 +51227 0.35272216796875 +51228 0.6173095703125 +51229 0.39508056640625 +51230 0.6524658203125 +51231 0.413787841796875 +51232 0.66339111328125 +51233 0.416748046875 +51234 0.6561279296875 +51235 0.4078369140625 +51236 0.606781005859375 +51237 0.373016357421875 +51238 0.501190185546875 +51239 0.304107666015625 +51240 0.352783203125 +51241 0.209442138671875 +51242 0.176544189453125 +51243 0.098358154296875 +51244 -0.034820556640625 +51245 -0.033233642578125 +51246 -0.258209228515625 +51247 -0.171173095703125 +51248 -0.44244384765625 +51249 -0.28460693359375 +51250 -0.5753173828125 +51251 -0.366058349609375 +51252 -0.65203857421875 +51253 -0.41259765625 +51254 -0.641632080078125 +51255 -0.405670166015625 +51256 -0.562164306640625 +51257 -0.356170654296875 +51258 -0.458038330078125 +51259 -0.2908935546875 +51260 -0.350555419921875 +51261 -0.2227783203125 +51262 -0.260528564453125 +51263 -0.164520263671875 +51264 -0.192108154296875 +51265 -0.118865966796875 +51266 -0.141937255859375 +51267 -0.0841064453125 +51268 -0.1021728515625 +51269 -0.055755615234375 +51270 -0.062896728515625 +51271 -0.028106689453125 +51272 -0.011932373046875 +51273 0.005889892578125 +51274 0.062835693359375 +51275 0.0533447265625 +51276 0.148712158203125 +51277 0.106536865234375 +51278 0.241729736328125 +51279 0.16302490234375 +51280 0.34912109375 +51281 0.22711181640625 +51282 0.457305908203125 +51283 0.290740966796875 +51284 0.54388427734375 +51285 0.340545654296875 +51286 0.5728759765625 +51287 0.3551025390625 +51288 0.506591796875 +51289 0.311981201171875 +51290 0.351226806640625 +51291 0.215057373046875 +51292 0.146514892578125 +51293 0.088409423828125 +51294 -0.05523681640625 +51295 -0.036376953125 +51296 -0.21624755859375 +51297 -0.136444091796875 +51298 -0.334930419921875 +51299 -0.21063232421875 +51300 -0.402984619140625 +51301 -0.2537841796875 +51302 -0.4412841796875 +51303 -0.2783203125 +51304 -0.49578857421875 +51305 -0.311767578125 +51306 -0.5601806640625 +51307 -0.350341796875 +51308 -0.600738525390625 +51309 -0.37384033203125 +51310 -0.584228515625 +51311 -0.36236572265625 +51312 -0.47930908203125 +51313 -0.2972412109375 +51314 -0.27935791015625 +51315 -0.17462158203125 +51316 -0.0089111328125 +51317 -0.0093994140625 +51318 0.268798828125 +51319 0.160308837890625 +51320 0.482818603515625 +51321 0.291748046875 +51322 0.60369873046875 +51323 0.367095947265625 +51324 0.650421142578125 +51325 0.3975830078125 +51326 0.66400146484375 +51327 0.40771484375 +51328 0.6414794921875 +51329 0.3956298828125 +51330 0.572540283203125 +51331 0.355072021484375 +51332 0.498138427734375 +51333 0.31060791015625 +51334 0.439453125 +51335 0.274932861328125 +51336 0.375518798828125 +51337 0.235504150390625 +51338 0.274505615234375 +51339 0.173309326171875 +51340 0.1087646484375 +51341 0.071868896484375 +51342 -0.099395751953125 +51343 -0.055328369140625 +51344 -0.3182373046875 +51345 -0.1890869140625 +51346 -0.5489501953125 +51347 -0.329986572265625 +51348 -0.7738037109375 +51349 -0.467254638671875 +51350 -0.86383056640625 +51351 -0.569000244140625 +51352 -0.870391845703125 +51353 -0.615142822265625 +51354 -0.86895751953125 +51355 -0.616241455078125 +51356 -0.861053466796875 +51357 -0.580078125 +51358 -0.765869140625 +51359 -0.49627685546875 +51360 -0.5301513671875 +51361 -0.358062744140625 +51362 -0.214691162109375 +51363 -0.16973876953125 +51364 0.137359619140625 +51365 0.042816162109375 +51366 0.474822998046875 +51367 0.24871826171875 +51368 0.76239013671875 +51369 0.426544189453125 +51370 0.867462158203125 +51371 0.55999755859375 +51372 0.870361328125 +51373 0.64923095703125 +51374 0.86480712890625 +51375 0.68719482421875 +51376 0.831817626953125 +51377 0.677001953125 +51378 0.677581787109375 +51379 0.6331787109375 +51380 0.495880126953125 +51381 0.559112548828125 +51382 0.30767822265625 +51383 0.46588134765625 +51384 0.116180419921875 +51385 0.354766845703125 +51386 -0.110748291015625 +51387 0.206756591796875 +51388 -0.381805419921875 +51389 0.0177001953125 +51390 -0.6572265625 +51391 -0.1866455078125 +51392 -0.857421875 +51393 -0.37030029296875 +51394 -0.870391845703125 +51395 -0.507415771484375 +51396 -0.870391845703125 +51397 -0.5936279296875 +51398 -0.86444091796875 +51399 -0.644989013671875 +51400 -0.85723876953125 +51401 -0.682769775390625 +51402 -0.790008544921875 +51403 -0.69586181640625 +51404 -0.62847900390625 +51405 -0.651641845703125 +51406 -0.3956298828125 +51407 -0.548126220703125 +51408 -0.126708984375 +51409 -0.40496826171875 +51410 0.150115966796875 +51411 -0.23858642578125 +51412 0.424041748046875 +51413 -0.055999755859375 +51414 0.670623779296875 +51415 0.126556396484375 +51416 0.854522705078125 +51417 0.28582763671875 +51418 0.866485595703125 +51419 0.411163330078125 +51420 0.86920166015625 +51421 0.49322509765625 +51422 0.8653564453125 +51423 0.542816162109375 +51424 0.857147216796875 +51425 0.56787109375 +51426 0.766845703125 +51427 0.566558837890625 +51428 0.628509521484375 +51429 0.541839599609375 +51430 0.462127685546875 +51431 0.4896240234375 +51432 0.297210693359375 +51433 0.425323486328125 +51434 0.14862060546875 +51435 0.3563232421875 +51436 -0.00537109375 +51437 0.2689208984375 +51438 -0.15753173828125 +51439 0.167633056640625 +51440 -0.31304931640625 +51441 0.05029296875 +51442 -0.48876953125 +51443 -0.0914306640625 +51444 -0.6416015625 +51445 -0.229339599609375 +51446 -0.751373291015625 +51447 -0.34857177734375 +51448 -0.84619140625 +51449 -0.462860107421875 +51450 -0.861297607421875 +51451 -0.56329345703125 +51452 -0.863250732421875 +51453 -0.629913330078125 +51454 -0.856597900390625 +51455 -0.6436767578125 +51456 -0.7498779296875 +51457 -0.611236572265625 +51458 -0.624542236328125 +51459 -0.566436767578125 +51460 -0.47808837890625 +51461 -0.497528076171875 +51462 -0.253387451171875 +51463 -0.371551513671875 +51464 0.003692626953125 +51465 -0.21478271484375 +51466 0.2257080078125 +51467 -0.066436767578125 +51468 0.427154541015625 +51469 0.080169677734375 +51470 0.643218994140625 +51471 0.24298095703125 +51472 0.855926513671875 +51473 0.416107177734375 +51474 0.870361328125 +51475 0.5662841796875 +51476 0.870361328125 +51477 0.665008544921875 +51478 0.862762451171875 +51479 0.716156005859375 +51480 0.79669189453125 +51481 0.717926025390625 +51482 0.595794677734375 +51483 0.6649169921875 +51484 0.362152099609375 +51485 0.573760986328125 +51486 0.1270751953125 +51487 0.4605712890625 +51488 -0.086944580078125 +51489 0.33758544921875 +51490 -0.2784423828125 +51491 0.206329345703125 +51492 -0.484832763671875 +51493 0.047393798828125 +51494 -0.729583740234375 +51495 -0.14971923828125 +51496 -0.86688232421875 +51497 -0.3558349609375 +51498 -0.870391845703125 +51499 -0.53460693359375 +51500 -0.86859130859375 +51501 -0.682861328125 +51502 -0.86279296875 +51503 -0.799102783203125 +51504 -0.817962646484375 +51505 -0.85540771484375 +51506 -0.6116943359375 +51507 -0.847564697265625 +51508 -0.3128662109375 +51509 -0.749664306640625 +51510 0.039398193359375 +51511 -0.588134765625 +51512 0.422821044921875 +51513 -0.374481201171875 +51514 0.805145263671875 +51515 -0.1278076171875 +51516 0.870361328125 +51517 0.11285400390625 +51518 0.870361328125 +51519 0.314788818359375 +51520 0.860015869140625 +51521 0.470916748046875 +51522 0.727935791015625 +51523 0.576446533203125 +51524 0.48114013671875 +51525 0.627716064453125 +51526 0.2059326171875 +51527 0.63800048828125 +51528 -0.06103515625 +51529 0.619781494140625 +51530 -0.29913330078125 +51531 0.57843017578125 +51532 -0.516204833984375 +51533 0.505523681640625 +51534 -0.7252197265625 +51535 0.3922119140625 +51536 -0.85980224609375 +51537 0.252685546875 +51538 -0.870391845703125 +51539 0.106597900390625 +51540 -0.870391845703125 +51541 -0.028900146484375 +51542 -0.858062744140625 +51543 -0.125762939453125 +51544 -0.673004150390625 +51545 -0.18109130859375 +51546 -0.42694091796875 +51547 -0.22412109375 +51548 -0.2100830078125 +51549 -0.279510498046875 +51550 -0.0362548828125 +51551 -0.345458984375 +51552 0.10943603515625 +51553 -0.4049072265625 +51554 0.23516845703125 +51555 -0.446136474609375 +51556 0.373687744140625 +51557 -0.44525146484375 +51558 0.517791748046875 +51559 -0.403106689453125 +51560 0.602783203125 +51561 -0.3553466796875 +51562 0.635711669921875 +51563 -0.299072265625 +51564 0.655181884765625 +51565 -0.21551513671875 +51566 0.65948486328125 +51567 -0.110595703125 +51568 0.651275634765625 +51569 0.010711669921875 +51570 0.61846923828125 +51571 0.134002685546875 +51572 0.53753662109375 +51573 0.237701416015625 +51574 0.404144287109375 +51575 0.31097412109375 +51576 0.22186279296875 +51577 0.347747802734375 +51578 0.003997802734375 +51579 0.34820556640625 +51580 -0.22100830078125 +51581 0.322174072265625 +51582 -0.42449951171875 +51583 0.281036376953125 +51584 -0.579833984375 +51585 0.23663330078125 +51586 -0.641876220703125 +51587 0.213104248046875 +51588 -0.6177978515625 +51589 0.206634521484375 +51590 -0.575531005859375 +51591 0.1806640625 +51592 -0.526336669921875 +51593 0.13238525390625 +51594 -0.42645263671875 +51595 0.091552734375 +51596 -0.2581787109375 +51597 0.07415771484375 +51598 -0.068695068359375 +51599 0.05999755859375 +51600 0.09222412109375 +51601 0.0277099609375 +51602 0.232147216796875 +51603 -0.011566162109375 +51604 0.3509521484375 +51605 -0.05157470703125 +51606 0.410064697265625 +51607 -0.108673095703125 +51608 0.372955322265625 +51609 -0.19915771484375 +51610 0.2554931640625 +51611 -0.31085205078125 +51612 0.10711669921875 +51613 -0.4139404296875 +51614 -0.052886962890625 +51615 -0.4971923828125 +51616 -0.186279296875 +51617 -0.540069580078125 +51618 -0.23291015625 +51619 -0.51092529296875 +51620 -0.209442138671875 +51621 -0.42291259765625 +51622 -0.174163818359375 +51623 -0.313751220703125 +51624 -0.126739501953125 +51625 -0.18853759765625 +51626 -0.048126220703125 +51627 -0.042083740234375 +51628 0.0426025390625 +51629 0.109130859375 +51630 0.10748291015625 +51631 0.2381591796875 +51632 0.1409912109375 +51633 0.337066650390625 +51634 0.19708251953125 +51635 0.4324951171875 +51636 0.273651123046875 +51637 0.520263671875 +51638 0.31768798828125 +51639 0.568389892578125 +51640 0.341094970703125 +51641 0.5830078125 +51642 0.368011474609375 +51643 0.578369140625 +51644 0.37249755859375 +51645 0.541412353515625 +51646 0.30072021484375 +51647 0.444305419921875 +51648 0.1517333984375 +51649 0.2900390625 +51650 -0.01470947265625 +51651 0.11669921875 +51652 -0.1883544921875 +51653 -0.06524658203125 +51654 -0.372711181640625 +51655 -0.253143310546875 +51656 -0.51397705078125 +51657 -0.411895751953125 +51658 -0.57177734375 +51659 -0.514404296875 +51660 -0.53948974609375 +51661 -0.553375244140625 +51662 -0.43511962890625 +51663 -0.536285400390625 +51664 -0.2962646484375 +51665 -0.482635498046875 +51666 -0.161102294921875 +51667 -0.4132080078125 +51668 -0.0435791015625 +51669 -0.336029052734375 +51670 0.060394287109375 +51671 -0.249847412109375 +51672 0.13665771484375 +51673 -0.1646728515625 +51674 0.170135498046875 +51675 -0.091766357421875 +51676 0.16552734375 +51677 -0.03173828125 +51678 0.15728759765625 +51679 0.03125 +51680 0.150787353515625 +51681 0.096435546875 +51682 0.12200927734375 +51683 0.146392822265625 +51684 0.080108642578125 +51685 0.18280029296875 +51686 0.05126953125 +51687 0.2174072265625 +51688 0.062896728515625 +51689 0.263275146484375 +51690 0.09271240234375 +51691 0.305938720703125 +51692 0.092987060546875 +51693 0.317291259765625 +51694 0.07855224609375 +51695 0.3055419921875 +51696 0.06427001953125 +51697 0.279754638671875 +51698 0.0347900390625 +51699 0.232574462890625 +51700 -0.01171875 +51701 0.16497802734375 +51702 -0.056060791015625 +51703 0.0904541015625 +51704 -0.055511474609375 +51705 0.036163330078125 +51706 -0.010467529296875 +51707 0.005035400390625 +51708 0.02508544921875 +51709 -0.0303955078125 +51710 0.025665283203125 +51711 -0.081634521484375 +51712 0.017333984375 +51713 -0.131378173828125 +51714 0.00189208984375 +51715 -0.176239013671875 +51716 -0.03173828125 +51717 -0.220550537109375 +51718 -0.071502685546875 +51719 -0.25653076171875 +51720 -0.13543701171875 +51721 -0.293548583984375 +51722 -0.219970703125 +51723 -0.329833984375 +51724 -0.300506591796875 +51725 -0.35272216796875 +51726 -0.376312255859375 +51727 -0.36328125 +51728 -0.416107177734375 +51729 -0.346282958984375 +51730 -0.371124267578125 +51731 -0.27728271484375 +51732 -0.242279052734375 +51733 -0.15936279296875 +51734 -0.069732666015625 +51735 -0.01727294921875 +51736 0.125640869140625 +51737 0.134918212890625 +51738 0.31268310546875 +51739 0.277679443359375 +51740 0.45501708984375 +51741 0.388946533203125 +51742 0.554779052734375 +51743 0.46832275390625 +51744 0.61065673828125 +51745 0.51397705078125 +51746 0.610931396484375 +51747 0.5189208984375 +51748 0.531463623046875 +51749 0.46990966796875 +51750 0.3883056640625 +51751 0.3763427734375 +51752 0.23468017578125 +51753 0.268585205078125 +51754 0.095245361328125 +51755 0.161712646484375 +51756 -0.00396728515625 +51757 0.07183837890625 +51758 -0.04852294921875 +51759 0.009002685546875 +51760 -0.055145263671875 +51761 -0.0338134765625 +51762 -0.0758056640625 +51763 -0.083038330078125 +51764 -0.138702392578125 +51765 -0.152130126953125 +51766 -0.209197998046875 +51767 -0.22027587890625 +51768 -0.289031982421875 +51769 -0.286956787109375 +51770 -0.37884521484375 +51771 -0.351470947265625 +51772 -0.456329345703125 +51773 -0.40093994140625 +51774 -0.51641845703125 +51775 -0.432464599609375 +51776 -0.519287109375 +51777 -0.424468994140625 +51778 -0.458251953125 +51779 -0.3740234375 +51780 -0.384796142578125 +51781 -0.310577392578125 +51782 -0.323699951171875 +51783 -0.249176025390625 +51784 -0.269287109375 +51785 -0.188323974609375 +51786 -0.1951904296875 +51787 -0.115325927734375 +51788 -0.100006103515625 +51789 -0.03118896484375 +51790 -0.01055908203125 +51791 0.047576904296875 +51792 0.1033935546875 +51793 0.136016845703125 +51794 0.24908447265625 +51795 0.236846923828125 +51796 0.373199462890625 +51797 0.31976318359375 +51798 0.45806884765625 +51799 0.37445068359375 +51800 0.511474609375 +51801 0.4049072265625 +51802 0.565399169921875 +51803 0.42889404296875 +51804 0.61138916015625 +51805 0.4422607421875 +51806 0.5897216796875 +51807 0.412994384765625 +51808 0.4906005859375 +51809 0.3367919921875 +51810 0.33148193359375 +51811 0.224578857421875 +51812 0.147796630859375 +51813 0.097259521484375 +51814 -0.01873779296875 +51815 -0.020751953125 +51816 -0.140289306640625 +51817 -0.1126708984375 +51818 -0.191986083984375 +51819 -0.163482666015625 +51820 -0.184295654296875 +51821 -0.177825927734375 +51822 -0.161834716796875 +51823 -0.1793212890625 +51824 -0.166595458984375 +51825 -0.190460205078125 +51826 -0.19390869140625 +51827 -0.2083740234375 +51828 -0.22442626953125 +51829 -0.222381591796875 +51830 -0.279754638671875 +51831 -0.244720458984375 +51832 -0.3389892578125 +51833 -0.26446533203125 +51834 -0.3543701171875 +51835 -0.256195068359375 +51836 -0.348175048828125 +51837 -0.233184814453125 +51838 -0.32598876953125 +51839 -0.19964599609375 +51840 -0.2581787109375 +51841 -0.140533447265625 +51842 -0.139801025390625 +51843 -0.0543212890625 +51844 0.014617919921875 +51845 0.04986572265625 +51846 0.144378662109375 +51847 0.13763427734375 +51848 0.221038818359375 +51849 0.19256591796875 +51850 0.27069091796875 +51851 0.2283935546875 +51852 0.294036865234375 +51853 0.245208740234375 +51854 0.311767578125 +51855 0.2542724609375 +51856 0.339141845703125 +51857 0.26409912109375 +51858 0.360260009765625 +51859 0.26617431640625 +51860 0.360504150390625 +51861 0.253173828125 +51862 0.308380126953125 +51863 0.209075927734375 +51864 0.18170166015625 +51865 0.123016357421875 +51866 0.0047607421875 +51867 0.009124755859375 +51868 -0.17559814453125 +51869 -0.106414794921875 +51870 -0.3143310546875 +51871 -0.19842529296875 +51872 -0.36785888671875 +51873 -0.242584228515625 +51874 -0.36248779296875 +51875 -0.252227783203125 +51876 -0.343536376953125 +51877 -0.25103759765625 +51878 -0.3018798828125 +51879 -0.233734130859375 +51880 -0.231414794921875 +51881 -0.1968994140625 +51882 -0.117645263671875 +51883 -0.132843017578125 +51884 0.007049560546875 +51885 -0.059173583984375 +51886 0.087982177734375 +51887 -0.005706787109375 +51888 0.13946533203125 +51889 0.034576416015625 +51890 0.17425537109375 +51891 0.0677490234375 +51892 0.188201904296875 +51893 0.090728759765625 +51894 0.171234130859375 +51895 0.097259521484375 +51896 0.118438720703125 +51897 0.083831787109375 +51898 0.05706787109375 +51899 0.064300537109375 +51900 -0.010711669921875 +51901 0.039093017578125 +51902 -0.0914306640625 +51903 0.004180908203125 +51904 -0.162322998046875 +51905 -0.028594970703125 +51906 -0.194549560546875 +51907 -0.043975830078125 +51908 -0.1492919921875 +51909 -0.02117919921875 +51910 -0.02166748046875 +51911 0.042572021484375 +51912 0.124053955078125 +51913 0.11322021484375 +51914 0.211151123046875 +51915 0.15008544921875 +51916 0.240447998046875 +51917 0.15423583984375 +51918 0.242218017578125 +51919 0.142547607421875 +51920 0.2257080078125 +51921 0.120758056640625 +51922 0.194366455078125 +51923 0.091400146484375 +51924 0.115509033203125 +51925 0.037628173828125 +51926 0.0128173828125 +51927 -0.027252197265625 +51928 -0.053802490234375 +51929 -0.07061767578125 +51930 -0.110626220703125 +51931 -0.106201171875 +51932 -0.199493408203125 +51933 -0.15625 +51934 -0.29437255859375 +51935 -0.206756591796875 +51936 -0.33221435546875 +51937 -0.2239990234375 +51938 -0.27972412109375 +51939 -0.1904296875 +51940 -0.185333251953125 +51941 -0.132354736328125 +51942 -0.128204345703125 +51943 -0.0926513671875 +51944 -0.115692138671875 +51945 -0.0758056640625 +51946 -0.116455078125 +51947 -0.06561279296875 +51948 -0.105926513671875 +51949 -0.04949951171875 +51950 -0.053955078125 +51951 -0.011871337890625 +51952 0.048797607421875 +51953 0.0517578125 +51954 0.157318115234375 +51955 0.116851806640625 +51956 0.212005615234375 +51957 0.151123046875 +51958 0.218475341796875 +51959 0.157379150390625 +51960 0.23724365234375 +51961 0.167938232421875 +51962 0.30535888671875 +51963 0.20269775390625 +51964 0.38128662109375 +51965 0.23956298828125 +51966 0.404449462890625 +51967 0.246337890625 +51968 0.3944091796875 +51969 0.2332763671875 +51970 0.3885498046875 +51971 0.220184326171875 +51972 0.362640380859375 +51973 0.195556640625 +51974 0.27362060546875 +51975 0.13848876953125 +51976 0.11712646484375 +51977 0.047607421875 +51978 -0.054901123046875 +51979 -0.0501708984375 +51980 -0.19085693359375 +51981 -0.128204345703125 +51982 -0.28570556640625 +51983 -0.183441162109375 +51984 -0.339263916015625 +51985 -0.215423583984375 +51986 -0.3775634765625 +51987 -0.237091064453125 +51988 -0.445709228515625 +51989 -0.2711181640625 +51990 -0.535064697265625 +51991 -0.313232421875 +51992 -0.629058837890625 +51993 -0.355316162109375 +51994 -0.697601318359375 +51995 -0.382537841796875 +51996 -0.70391845703125 +51997 -0.376861572265625 +51998 -0.6424560546875 +51999 -0.336029052734375 +52000 -0.491241455078125 +52001 -0.249542236328125 +52002 -0.265716552734375 +52003 -0.125762939453125 +52004 -0.023712158203125 +52005 0.005584716796875 +52006 0.201751708984375 +52007 0.12738037109375 +52008 0.375823974609375 +52009 0.22161865234375 +52010 0.485076904296875 +52011 0.281219482421875 +52012 0.56884765625 +52013 0.32586669921875 +52014 0.634765625 +52015 0.35931396484375 +52016 0.63763427734375 +52017 0.35882568359375 +52018 0.5660400390625 +52019 0.318817138671875 +52020 0.4720458984375 +52021 0.265777587890625 +52022 0.40692138671875 +52023 0.225921630859375 +52024 0.3778076171875 +52025 0.203277587890625 +52026 0.376953125 +52027 0.194427490234375 +52028 0.371978759765625 +52029 0.183502197265625 +52030 0.313140869140625 +52031 0.145904541015625 +52032 0.184417724609375 +52033 0.073944091796875 +52034 0.011199951171875 +52035 -0.0191650390625 +52036 -0.171051025390625 +52037 -0.11529541015625 +52038 -0.33740234375 +52039 -0.20166015625 +52040 -0.47198486328125 +52041 -0.27020263671875 +52042 -0.560394287109375 +52043 -0.313690185546875 +52044 -0.58056640625 +52045 -0.32110595703125 +52046 -0.54754638671875 +52047 -0.300201416015625 +52048 -0.508575439453125 +52049 -0.275115966796875 +52050 -0.459503173828125 +52051 -0.244049072265625 +52052 -0.394378662109375 +52053 -0.20440673828125 +52054 -0.35260009765625 +52055 -0.176422119140625 +52056 -0.31170654296875 +52057 -0.14910888671875 +52058 -0.197418212890625 +52059 -0.085418701171875 +52060 -0.007965087890625 +52061 0.01519775390625 +52062 0.207489013671875 +52063 0.127685546875 +52064 0.409210205078125 +52065 0.23187255859375 +52066 0.57208251953125 +52067 0.31500244140625 +52068 0.66595458984375 +52069 0.36187744140625 +52070 0.65875244140625 +52071 0.35638427734375 +52072 0.56744384765625 +52073 0.3072509765625 +52074 0.431396484375 +52075 0.2344970703125 +52076 0.29443359375 +52077 0.160491943359375 +52078 0.182464599609375 +52079 0.098541259765625 +52080 0.06365966796875 +52081 0.032928466796875 +52082 -0.075958251953125 +52083 -0.04302978515625 +52084 -0.189422607421875 +52085 -0.1053466796875 +52086 -0.271942138671875 +52087 -0.151336669921875 +52088 -0.342529296875 +52089 -0.19036865234375 +52090 -0.364166259765625 +52091 -0.20367431640625 +52092 -0.327239990234375 +52093 -0.186309814453125 +52094 -0.2769775390625 +52095 -0.161041259765625 +52096 -0.253692626953125 +52097 -0.148193359375 +52098 -0.24365234375 +52099 -0.14093017578125 +52100 -0.1983642578125 +52101 -0.114990234375 +52102 -0.116241455078125 +52103 -0.069732666015625 +52104 -0.036834716796875 +52105 -0.02532958984375 +52106 0.034881591796875 +52107 0.01544189453125 +52108 0.09124755859375 +52109 0.0484619140625 +52110 0.10888671875 +52111 0.06170654296875 +52112 0.125518798828125 +52113 0.073944091796875 +52114 0.15771484375 +52115 0.09332275390625 +52116 0.17828369140625 +52117 0.105987548828125 +52118 0.17108154296875 +52119 0.10369873046875 +52120 0.129974365234375 +52121 0.0833740234375 +52122 0.082427978515625 +52123 0.058807373046875 +52124 0.027679443359375 +52125 0.029693603515625 +52126 -0.065643310546875 +52127 -0.019622802734375 +52128 -0.15936279296875 +52129 -0.06976318359375 +52130 -0.21307373046875 +52131 -0.1002197265625 +52132 -0.234649658203125 +52133 -0.114776611328125 +52134 -0.2001953125 +52135 -0.10113525390625 +52136 -0.119171142578125 +52137 -0.06390380859375 +52138 -0.024749755859375 +52139 -0.01959228515625 +52140 0.085784912109375 +52141 0.0333251953125 +52142 0.178131103515625 +52143 0.077667236328125 +52144 0.215576171875 +52145 0.095062255859375 +52146 0.211456298828125 +52147 0.09228515625 +52148 0.17523193359375 +52149 0.07415771484375 +52150 0.128753662109375 +52151 0.0516357421875 +52152 0.1019287109375 +52153 0.03973388671875 +52154 0.0743408203125 +52155 0.028045654296875 +52156 0.04327392578125 +52157 0.015045166015625 +52158 0.038177490234375 +52159 0.015411376953125 +52160 0.076263427734375 +52161 0.03765869140625 +52162 0.14105224609375 +52163 0.07330322265625 +52164 0.186431884765625 +52165 0.09893798828125 +52166 0.188812255859375 +52167 0.1025390625 +52168 0.1390380859375 +52169 0.079376220703125 +52170 0.041778564453125 +52171 0.03173828125 +52172 -0.079437255859375 +52173 -0.028533935546875 +52174 -0.219390869140625 +52175 -0.098907470703125 +52176 -0.367828369140625 +52177 -0.17413330078125 +52178 -0.494873046875 +52179 -0.239166259765625 +52180 -0.556243896484375 +52181 -0.2716064453125 +52182 -0.508697509765625 +52183 -0.24957275390625 +52184 -0.3756103515625 +52185 -0.184722900390625 +52186 -0.218902587890625 +52187 -0.108154296875 +52188 -0.063751220703125 +52189 -0.03240966796875 +52190 0.091552734375 +52191 0.04345703125 +52192 0.23602294921875 +52193 0.11407470703125 +52194 0.342987060546875 +52195 0.166107177734375 +52196 0.39520263671875 +52197 0.19097900390625 +52198 0.389373779296875 +52199 0.187103271484375 +52200 0.324249267578125 +52201 0.15386962890625 +52202 0.224090576171875 +52203 0.103546142578125 +52204 0.124267578125 +52205 0.05389404296875 +52206 0.037078857421875 +52207 0.011077880859375 +52208 -0.010101318359375 +52209 -0.01116943359375 +52210 -0.019439697265625 +52211 -0.0140380859375 +52212 -0.022796630859375 +52213 -0.013702392578125 +52214 -0.001556396484375 +52215 -0.000885009765625 +52216 0.056304931640625 +52217 0.030303955078125 +52218 0.106719970703125 +52219 0.057586669921875 +52220 0.096893310546875 +52221 0.05426025390625 +52222 0.042694091796875 +52223 0.028228759765625 +52224 -0.018035888671875 +52225 -0.00115966796875 +52226 -0.07586669921875 +52227 -0.029388427734375 +52228 -0.11944580078125 +52229 -0.051361083984375 +52230 -0.15972900390625 +52231 -0.07208251953125 +52232 -0.202606201171875 +52233 -0.094146728515625 +52234 -0.24859619140625 +52235 -0.117645263671875 +52236 -0.30517578125 +52237 -0.145965576171875 +52238 -0.36212158203125 +52239 -0.174224853515625 +52240 -0.39141845703125 +52241 -0.18914794921875 +52242 -0.35528564453125 +52243 -0.172821044921875 +52244 -0.249969482421875 +52245 -0.12347412109375 +52246 -0.092864990234375 +52247 -0.049346923828125 +52248 0.08905029296875 +52249 0.036834716796875 +52250 0.2352294921875 +52251 0.106475830078125 +52252 0.318817138671875 +52253 0.1468505859375 +52254 0.358642578125 +52255 0.166717529296875 +52256 0.347747802734375 +52257 0.162750244140625 +52258 0.28564453125 +52259 0.134674072265625 +52260 0.223175048828125 +52261 0.10638427734375 +52262 0.196746826171875 +52263 0.095001220703125 +52264 0.179840087890625 +52265 0.087982177734375 +52266 0.155548095703125 +52267 0.077301025390625 +52268 0.151214599609375 +52269 0.075836181640625 +52270 0.156951904296875 +52271 0.078857421875 +52272 0.13177490234375 +52273 0.0670166015625 +52274 0.100799560546875 +52275 0.052154541015625 +52276 0.087127685546875 +52277 0.045196533203125 +52278 0.05487060546875 +52279 0.029266357421875 +52280 -0.009002685546875 +52281 -0.001739501953125 +52282 -0.10400390625 +52283 -0.04754638671875 +52284 -0.229400634765625 +52285 -0.107757568359375 +52286 -0.35552978515625 +52287 -0.168304443359375 +52288 -0.441925048828125 +52289 -0.21002197265625 +52290 -0.473846435546875 +52291 -0.225921630859375 +52292 -0.464813232421875 +52293 -0.222320556640625 +52294 -0.419097900390625 +52295 -0.201202392578125 +52296 -0.334320068359375 +52297 -0.16143798828125 +52298 -0.227935791015625 +52299 -0.111236572265625 +52300 -0.12347412109375 +52301 -0.06170654296875 +52302 -0.02764892578125 +52303 -0.016082763671875 +52304 0.077667236328125 +52305 0.0341796875 +52306 0.2132568359375 +52307 0.098846435546875 +52308 0.38885498046875 +52309 0.182464599609375 +52310 0.582794189453125 +52311 0.2747802734375 +52312 0.734039306640625 +52313 0.346954345703125 +52314 0.800140380859375 +52315 0.37890625 +52316 0.7783203125 +52317 0.3692626953125 +52318 0.6651611328125 +52319 0.316375732421875 +52320 0.45965576171875 +52321 0.219757080078125 +52322 0.199188232421875 +52323 0.0970458984375 +52324 -0.050689697265625 +52325 -0.02081298828125 +52326 -0.23297119140625 +52327 -0.106903076171875 +52328 -0.33013916015625 +52329 -0.152984619140625 +52330 -0.368408203125 +52331 -0.17138671875 +52332 -0.378936767578125 +52333 -0.176788330078125 +52334 -0.376983642578125 +52335 -0.1763916015625 +52336 -0.37969970703125 +52337 -0.17828369140625 +52338 -0.391510009765625 +52339 -0.18450927734375 +52340 -0.385345458984375 +52341 -0.182220458984375 +52342 -0.3419189453125 +52343 -0.16229248046875 +52344 -0.28289794921875 +52345 -0.134918212890625 +52346 -0.251617431640625 +52347 -0.120513916015625 +52348 -0.266143798828125 +52349 -0.127593994140625 +52350 -0.273345947265625 +52351 -0.131103515625 +52352 -0.216796875 +52353 -0.1043701171875 +52354 -0.128265380859375 +52355 -0.062408447265625 +52356 -0.068145751953125 +52357 -0.033721923828125 +52358 -0.0430908203125 +52359 -0.021484375 +52360 -0.024444580078125 +52361 -0.01220703125 +52362 0.020721435546875 +52363 0.0096435546875 +52364 0.124481201171875 +52365 0.05914306640625 +52366 0.25787353515625 +52367 0.12255859375 +52368 0.379119873046875 +52369 0.18017578125 +52370 0.47991943359375 +52371 0.228057861328125 +52372 0.5281982421875 +52373 0.25103759765625 +52374 0.511138916015625 +52375 0.24310302734375 +52376 0.456207275390625 +52377 0.217193603515625 +52378 0.407470703125 +52379 0.194091796875 +52380 0.383758544921875 +52381 0.182708740234375 +52382 0.35687255859375 +52383 0.16973876953125 +52384 0.31182861328125 +52385 0.14813232421875 +52386 0.250885009765625 +52387 0.11895751953125 +52388 0.1654052734375 +52389 0.07818603515625 +52390 0.035247802734375 +52391 0.016357421875 +52392 -0.142059326171875 +52393 -0.067657470703125 +52394 -0.33563232421875 +52395 -0.159271240234375 +52396 -0.5345458984375 +52397 -0.253326416015625 +52398 -0.72186279296875 +52399 -0.341827392578125 +52400 -0.836669921875 +52401 -0.396026611328125 +52402 -0.8326416015625 +52403 -0.394073486328125 +52404 -0.7296142578125 +52405 -0.345306396484375 +52406 -0.582550048828125 +52407 -0.27569580078125 +52408 -0.440093994140625 +52409 -0.208221435546875 +52410 -0.324310302734375 +52411 -0.1533203125 +52412 -0.20147705078125 +52413 -0.095062255859375 +52414 -0.044647216796875 +52415 -0.020721435546875 +52416 0.103973388671875 +52417 0.049713134765625 +52418 0.202392578125 +52419 0.096405029296875 +52420 0.264495849609375 +52421 0.12591552734375 +52422 0.338897705078125 +52423 0.161163330078125 +52424 0.443817138671875 +52425 0.210723876953125 +52426 0.545074462890625 +52427 0.258514404296875 +52428 0.6173095703125 +52429 0.29254150390625 +52430 0.6524658203125 +52431 0.308990478515625 +52432 0.66339111328125 +52433 0.313934326171875 +52434 0.6561279296875 +52435 0.310272216796875 +52436 0.606781005859375 +52437 0.286712646484375 +52438 0.501190185546875 +52439 0.236572265625 +52440 0.352783203125 +52441 0.166229248046875 +52442 0.176544189453125 +52443 0.082763671875 +52444 -0.034820556640625 +52445 -0.017242431640625 +52446 -0.258209228515625 +52447 -0.122833251953125 +52448 -0.44244384765625 +52449 -0.2098388671875 +52450 -0.5753173828125 +52451 -0.27252197265625 +52452 -0.65203857421875 +52453 -0.30865478515625 +52454 -0.641632080078125 +52455 -0.3035888671875 +52456 -0.562164306640625 +52457 -0.265899658203125 +52458 -0.458038330078125 +52459 -0.216552734375 +52460 -0.350555419921875 +52461 -0.16558837890625 +52462 -0.260528564453125 +52463 -0.122833251953125 +52464 -0.192108154296875 +52465 -0.09027099609375 +52466 -0.141937255859375 +52467 -0.06634521484375 +52468 -0.1021728515625 +52469 -0.04736328125 +52470 -0.062896728515625 +52471 -0.028656005859375 +52472 -0.011932373046875 +52473 -0.004486083984375 +52474 0.062835693359375 +52475 0.030853271484375 +52476 0.148712158203125 +52477 0.071380615234375 +52478 0.241729736328125 +52479 0.11517333984375 +52480 0.34912109375 +52481 0.165374755859375 +52482 0.457305908203125 +52483 0.21484375 +52484 0.54388427734375 +52485 0.25311279296875 +52486 0.5728759765625 +52487 0.264739990234375 +52488 0.506591796875 +52489 0.23345947265625 +52490 0.351226806640625 +52491 0.162322998046875 +52492 0.146514892578125 +52493 0.069091796875 +52494 -0.05523681640625 +52495 -0.022918701171875 +52496 -0.21624755859375 +52497 -0.096832275390625 +52498 -0.334930419921875 +52499 -0.151763916015625 +52500 -0.402984619140625 +52501 -0.183929443359375 +52502 -0.4412841796875 +52503 -0.202423095703125 +52504 -0.49578857421875 +52505 -0.2274169921875 +52506 -0.5601806640625 +52507 -0.256072998046875 +52508 -0.600738525390625 +52509 -0.27362060546875 +52510 -0.584228515625 +52511 -0.265472412109375 +52512 -0.47930908203125 +52513 -0.217926025390625 +52514 -0.27935791015625 +52515 -0.128173828125 +52516 -0.0089111328125 +52517 -0.007171630859375 +52518 0.268798828125 +52519 0.11712646484375 +52520 0.482818603515625 +52521 0.213409423828125 +52522 0.60369873046875 +52523 0.268585205078125 +52524 0.650421142578125 +52525 0.2908935546875 +52526 0.66400146484375 +52527 0.298309326171875 +52528 0.6414794921875 +52529 0.289459228515625 +52530 0.572540283203125 +52531 0.259735107421875 +52532 0.498138427734375 +52533 0.227142333984375 +52534 0.439453125 +52535 0.201019287109375 +52536 0.375518798828125 +52537 0.17218017578125 +52538 0.274505615234375 +52539 0.12664794921875 +52540 0.1087646484375 +52541 0.052337646484375 +52542 -0.099395751953125 +52543 -0.040802001953125 +52544 -0.3182373046875 +52545 -0.13873291015625 +52546 -0.5489501953125 +52547 -0.24188232421875 +52548 -0.7738037109375 +52549 -0.34234619140625 +52550 -0.86383056640625 +52551 -0.416748046875 +52552 -0.870391845703125 +52553 -0.45037841796875 +52554 -0.86895751953125 +52555 -0.451019287109375 +52556 -0.861053466796875 +52557 -0.424407958984375 +52558 -0.765869140625 +52559 -0.3629150390625 +52560 -0.5301513671875 +52561 -0.261566162109375 +52562 -0.214691162109375 +52563 -0.12353515625 +52564 0.137359619140625 +52565 0.032196044921875 +52566 0.474822998046875 +52567 0.183013916015625 +52568 0.76239013671875 +52569 0.313232421875 +52570 0.867462158203125 +52571 0.410888671875 +52572 0.870361328125 +52573 0.476104736328125 +52574 0.86480712890625 +52575 0.503692626953125 +52576 0.831817626953125 +52577 0.4959716796875 +52578 0.677581787109375 +52579 0.463592529296875 +52580 0.495880126953125 +52581 0.409088134765625 +52582 0.30767822265625 +52583 0.340576171875 +52584 0.116180419921875 +52585 0.259033203125 +52586 -0.110748291015625 +52587 0.150482177734375 +52588 -0.381805419921875 +52589 0.01190185546875 +52590 -0.6572265625 +52591 -0.1378173828125 +52592 -0.857421875 +52593 -0.27227783203125 +52594 -0.870391845703125 +52595 -0.372589111328125 +52596 -0.870391845703125 +52597 -0.435516357421875 +52598 -0.86444091796875 +52599 -0.472869873046875 +52600 -0.85723876953125 +52601 -0.500274658203125 +52602 -0.790008544921875 +52603 -0.509613037109375 +52604 -0.62847900390625 +52605 -0.476959228515625 +52606 -0.3956298828125 +52607 -0.40087890625 +52608 -0.126708984375 +52609 -0.2957763671875 +52610 0.150115966796875 +52611 -0.173675537109375 +52612 0.424041748046875 +52613 -0.039764404296875 +52614 0.670623779296875 +52615 0.09405517578125 +52616 0.854522705078125 +52617 0.210723876953125 +52618 0.866485595703125 +52619 0.30242919921875 +52620 0.86920166015625 +52621 0.362335205078125 +52622 0.8653564453125 +52623 0.398406982421875 +52624 0.857147216796875 +52625 0.416473388671875 +52626 0.766845703125 +52627 0.41522216796875 +52628 0.628509521484375 +52629 0.3968505859375 +52630 0.462127685546875 +52631 0.358367919921875 +52632 0.297210693359375 +52633 0.311065673828125 +52634 0.14862060546875 +52635 0.260345458984375 +52636 -0.00537109375 +52637 0.1961669921875 +52638 -0.15753173828125 +52639 0.121856689453125 +52640 -0.31304931640625 +52641 0.035858154296875 +52642 -0.48876953125 +52643 -0.0679931640625 +52644 -0.6416015625 +52645 -0.16900634765625 +52646 -0.751373291015625 +52647 -0.256256103515625 +52648 -0.84619140625 +52649 -0.33984375 +52650 -0.861297607421875 +52651 -0.413238525390625 +52652 -0.863250732421875 +52653 -0.461822509765625 +52654 -0.856597900390625 +52655 -0.471649169921875 +52656 -0.7498779296875 +52657 -0.447998046875 +52658 -0.624542236328125 +52659 -0.41632080078125 +52660 -0.47808837890625 +52661 -0.366943359375 +52662 -0.253387451171875 +52663 -0.274169921875 +52664 0.003692626953125 +52665 -0.158050537109375 +52666 0.2257080078125 +52667 -0.048736572265625 +52668 0.427154541015625 +52669 0.05926513671875 +52670 0.643218994140625 +52671 0.180145263671875 +52672 0.855926513671875 +52673 0.30963134765625 +52674 0.870361328125 +52675 0.422149658203125 +52676 0.870361328125 +52677 0.495819091796875 +52678 0.862762451171875 +52679 0.53375244140625 +52680 0.79669189453125 +52681 0.53460693359375 +52682 0.595794677734375 +52683 0.49420166015625 +52684 0.362152099609375 +52685 0.425384521484375 +52686 0.1270751953125 +52687 0.3404541015625 +52688 -0.086944580078125 +52689 0.248748779296875 +52690 -0.2784423828125 +52691 0.151214599609375 +52692 -0.484832763671875 +52693 0.032562255859375 +52694 -0.729583740234375 +52695 -0.115570068359375 +52696 -0.86688232421875 +52697 -0.27081298828125 +52698 -0.870391845703125 +52699 -0.4052734375 +52700 -0.86859130859375 +52701 -0.516693115234375 +52702 -0.86279296875 +52703 -0.60406494140625 +52704 -0.817962646484375 +52705 -0.6514892578125 +52706 -0.6116943359375 +52707 -0.638916015625 +52708 -0.3128662109375 +52709 -0.563201904296875 +52710 0.039398193359375 +52711 -0.43914794921875 +52712 0.422821044921875 +52713 -0.27557373046875 +52714 0.805145263671875 +52715 -0.087188720703125 +52716 0.870361328125 +52717 0.09600830078125 +52718 0.870361328125 +52719 0.24884033203125 +52720 0.860015869140625 +52721 0.36602783203125 +52722 0.727935791015625 +52723 0.444061279296875 +52724 0.48114013671875 +52725 0.48028564453125 +52726 0.2059326171875 +52727 0.485198974609375 +52728 -0.06103515625 +52729 0.4686279296875 +52730 -0.29913330078125 +52731 0.434814453125 +52732 -0.516204833984375 +52733 0.3773193359375 +52734 -0.7252197265625 +52735 0.289337158203125 +52736 -0.85980224609375 +52737 0.181640625 +52738 -0.870391845703125 +52739 0.069854736328125 +52740 -0.870391845703125 +52741 -0.032806396484375 +52742 -0.858062744140625 +52743 -0.106201171875 +52744 -0.673004150390625 +52745 -0.148345947265625 +52746 -0.42694091796875 +52747 -0.18035888671875 +52748 -0.2100830078125 +52749 -0.22003173828125 +52750 -0.0362548828125 +52751 -0.2662353515625 +52752 0.10943603515625 +52753 -0.306854248046875 +52754 0.23516845703125 +52755 -0.3336181640625 +52756 0.373687744140625 +52757 -0.329559326171875 +52758 0.517791748046875 +52759 -0.2955322265625 +52760 0.602783203125 +52761 -0.257354736328125 +52762 0.635711669921875 +52763 -0.213165283203125 +52764 0.655181884765625 +52765 -0.149627685546875 +52766 0.65948486328125 +52767 -0.071197509765625 +52768 0.651275634765625 +52769 0.018402099609375 +52770 0.61846923828125 +52771 0.108734130859375 +52772 0.53753662109375 +52773 0.18426513671875 +52774 0.404144287109375 +52775 0.2371826171875 +52776 0.22186279296875 +52777 0.263092041015625 +52778 0.003997802734375 +52779 0.26220703125 +52780 -0.22100830078125 +52781 0.24169921875 +52782 -0.42449951171875 +52783 0.2098388671875 +52784 -0.579833984375 +52785 0.17529296875 +52786 -0.641876220703125 +52787 0.155548095703125 +52788 -0.6177978515625 +52789 0.14801025390625 +52790 -0.575531005859375 +52791 0.1265869140625 +52792 -0.526336669921875 +52793 0.089385986328125 +52794 -0.42645263671875 +52795 0.057891845703125 +52796 -0.2581787109375 +52797 0.043731689453125 +52798 -0.068695068359375 +52799 0.032470703125 +52800 0.09222412109375 +52801 0.008819580078125 +52802 0.232147216796875 +52803 -0.01922607421875 +52804 0.3509521484375 +52805 -0.047210693359375 +52806 0.410064697265625 +52807 -0.0869140625 +52808 0.372955322265625 +52809 -0.150146484375 +52810 0.2554931640625 +52811 -0.228271484375 +52812 0.10711669921875 +52813 -0.29998779296875 +52814 -0.052886962890625 +52815 -0.35736083984375 +52816 -0.186279296875 +52817 -0.385772705078125 +52818 -0.23291015625 +52819 -0.362640380859375 +52820 -0.209442138671875 +52821 -0.297515869140625 +52822 -0.174163818359375 +52823 -0.21759033203125 +52824 -0.126739501953125 +52825 -0.1265869140625 +52826 -0.048126220703125 +52827 -0.02081298828125 +52828 0.0426025390625 +52829 0.087860107421875 +52830 0.10748291015625 +52831 0.180084228515625 +52832 0.1409912109375 +52833 0.25018310546875 +52834 0.19708251953125 +52835 0.317352294921875 +52836 0.273651123046875 +52837 0.378662109375 +52838 0.31768798828125 +52839 0.411285400390625 +52840 0.341094970703125 +52841 0.419708251953125 +52842 0.368011474609375 +52843 0.414337158203125 +52844 0.37249755859375 +52845 0.385894775390625 +52846 0.30072021484375 +52847 0.314453125 +52848 0.1517333984375 +52849 0.2022705078125 +52850 -0.01470947265625 +52851 0.076751708984375 +52852 -0.1883544921875 +52853 -0.054534912109375 +52854 -0.372711181640625 +52855 -0.18963623046875 +52856 -0.51397705078125 +52857 -0.303375244140625 +52858 -0.57177734375 +52859 -0.376312255859375 +52860 -0.53948974609375 +52861 -0.40325927734375 +52862 -0.43511962890625 +52863 -0.3896484375 +52864 -0.2962646484375 +52865 -0.34954833984375 +52866 -0.161102294921875 +52867 -0.2979736328125 +52868 -0.0435791015625 +52869 -0.240814208984375 +52870 0.060394287109375 +52871 -0.177276611328125 +52872 0.13665771484375 +52873 -0.1146240234375 +52874 0.170135498046875 +52875 -0.061004638671875 +52876 0.16552734375 +52877 -0.016937255859375 +52878 0.15728759765625 +52879 0.0289306640625 +52880 0.150787353515625 +52881 0.076019287109375 +52882 0.12200927734375 +52883 0.111785888671875 +52884 0.080108642578125 +52885 0.137451171875 +52886 0.05126953125 +52887 0.1614990234375 +52888 0.062896728515625 +52889 0.193359375 +52890 0.09271240234375 +52891 0.22271728515625 +52892 0.092987060546875 +52893 0.229461669921875 +52894 0.07855224609375 +52895 0.219573974609375 +52896 0.06427001953125 +52897 0.199676513671875 +52898 0.0347900390625 +52899 0.164520263671875 +52900 -0.01171875 +52901 0.1148681640625 +52902 -0.056060791015625 +52903 0.060455322265625 +52904 -0.055511474609375 +52905 0.020843505859375 +52906 -0.010467529296875 +52907 -0.001800537109375 +52908 0.02508544921875 +52909 -0.0272216796875 +52910 0.025665283203125 +52911 -0.063690185546875 +52912 0.017333984375 +52913 -0.098663330078125 +52914 0.00189208984375 +52915 -0.12982177734375 +52916 -0.03173828125 +52917 -0.160552978515625 +52918 -0.071502685546875 +52919 -0.185272216796875 +52920 -0.13543701171875 +52921 -0.211090087890625 +52922 -0.219970703125 +52923 -0.23681640625 +52924 -0.300506591796875 +52925 -0.25311279296875 +52926 -0.376312255859375 +52927 -0.26080322265625 +52928 -0.416107177734375 +52929 -0.24859619140625 +52930 -0.371124267578125 +52931 -0.19830322265625 +52932 -0.242279052734375 +52933 -0.11212158203125 +52934 -0.069732666015625 +52935 -0.008331298828125 +52936 0.125640869140625 +52937 0.102691650390625 +52938 0.31268310546875 +52939 0.20660400390625 +52940 0.45501708984375 +52941 0.28717041015625 +52942 0.554779052734375 +52943 0.34417724609375 +52944 0.61065673828125 +52945 0.37640380859375 +52946 0.610931396484375 +52947 0.37872314453125 +52948 0.531463623046875 +52949 0.341400146484375 +52950 0.3883056640625 +52951 0.271453857421875 +52952 0.23468017578125 +52953 0.19140625 +52954 0.095245361328125 +52955 0.112457275390625 +52956 -0.00396728515625 +52957 0.04656982421875 +52958 -0.04852294921875 +52959 0.001068115234375 +52960 -0.055145263671875 +52961 -0.029296875 +52962 -0.0758056640625 +52963 -0.064208984375 +52964 -0.138702392578125 +52965 -0.113739013671875 +52966 -0.209197998046875 +52967 -0.162567138671875 +52968 -0.289031982421875 +52969 -0.21038818359375 +52970 -0.37884521484375 +52971 -0.25677490234375 +52972 -0.456329345703125 +52973 -0.292266845703125 +52974 -0.51641845703125 +52975 -0.31475830078125 +52976 -0.519287109375 +52977 -0.308258056640625 +52978 -0.458251953125 +52979 -0.2706298828125 +52980 -0.384796142578125 +52981 -0.223724365234375 +52982 -0.323699951171875 +52983 -0.1787109375 +52984 -0.269287109375 +52985 -0.134429931640625 +52986 -0.1951904296875 +52987 -0.081390380859375 +52988 -0.100006103515625 +52989 -0.020263671875 +52990 -0.01055908203125 +52991 0.036773681640625 +52992 0.1033935546875 +52993 0.100830078125 +52994 0.24908447265625 +52995 0.17401123046875 +52996 0.373199462890625 +52997 0.234283447265625 +52998 0.45806884765625 +52999 0.2740478515625 +53000 0.511474609375 +53001 0.296142578125 +53002 0.565399169921875 +53003 0.313446044921875 +53004 0.61138916015625 +53005 0.32293701171875 +53006 0.5897216796875 +53007 0.30133056640625 +53008 0.4906005859375 +53009 0.245513916015625 +53010 0.33148193359375 +53011 0.1634521484375 +53012 0.147796630859375 +53013 0.07037353515625 +53014 -0.01873779296875 +53015 -0.015899658203125 +53016 -0.140289306640625 +53017 -0.083160400390625 +53018 -0.191986083984375 +53019 -0.120452880859375 +53020 -0.184295654296875 +53021 -0.131134033203125 +53022 -0.161834716796875 +53023 -0.13238525390625 +53024 -0.166595458984375 +53025 -0.140533447265625 +53026 -0.19390869140625 +53027 -0.153472900390625 +53028 -0.22442626953125 +53029 -0.163482666015625 +53030 -0.279754638671875 +53031 -0.179412841796875 +53032 -0.3389892578125 +53033 -0.193389892578125 +53034 -0.3543701171875 +53035 -0.186920166015625 +53036 -0.348175048828125 +53037 -0.169708251953125 +53038 -0.32598876953125 +53039 -0.14483642578125 +53040 -0.2581787109375 +53041 -0.10137939453125 +53042 -0.139801025390625 +53043 -0.038238525390625 +53044 0.014617919921875 +53045 0.03790283203125 +53046 0.144378662109375 +53047 0.10198974609375 +53048 0.221038818359375 +53049 0.14208984375 +53050 0.27069091796875 +53051 0.168182373046875 +53052 0.294036865234375 +53053 0.180328369140625 +53054 0.311767578125 +53055 0.18670654296875 +53056 0.339141845703125 +53057 0.193511962890625 +53058 0.360260009765625 +53059 0.19439697265625 +53060 0.360504150390625 +53061 0.18408203125 +53062 0.308380126953125 +53063 0.151519775390625 +53064 0.18170166015625 +53065 0.089202880859375 +53066 0.0047607421875 +53067 0.007232666015625 +53068 -0.17559814453125 +53069 -0.07586669921875 +53070 -0.3143310546875 +53071 -0.142333984375 +53072 -0.36785888671875 +53073 -0.175018310546875 +53074 -0.36248779296875 +53075 -0.183135986328125 +53076 -0.343536376953125 +53077 -0.183258056640625 +53078 -0.3018798828125 +53079 -0.171630859375 +53080 -0.231414794921875 +53081 -0.14581298828125 +53082 -0.117645263671875 +53083 -0.100433349609375 +53084 0.007049560546875 +53085 -0.04791259765625 +53086 0.087982177734375 +53087 -0.00921630859375 +53088 0.13946533203125 +53089 0.020477294921875 +53090 0.17425537109375 +53091 0.04534912109375 +53092 0.188201904296875 +53093 0.063140869140625 +53094 0.171234130859375 +53095 0.069366455078125 +53096 0.118438720703125 +53097 0.061492919921875 +53098 0.05706787109375 +53099 0.049163818359375 +53100 -0.010711669921875 +53101 0.032623291015625 +53102 -0.0914306640625 +53103 0.008941650390625 +53104 -0.162322998046875 +53105 -0.0135498046875 +53106 -0.194549560546875 +53107 -0.024200439453125 +53108 -0.1492919921875 +53109 -0.0084228515625 +53110 -0.02166748046875 +53111 0.035736083984375 +53112 0.124053955078125 +53113 0.08441162109375 +53114 0.211151123046875 +53115 0.109130859375 +53116 0.240447998046875 +53117 0.1107177734375 +53118 0.242218017578125 +53119 0.101104736328125 +53120 0.2257080078125 +53121 0.084381103515625 +53122 0.194366455078125 +53123 0.062408447265625 +53124 0.115509033203125 +53125 0.023468017578125 +53126 0.0128173828125 +53127 -0.023040771484375 +53128 -0.053802490234375 +53129 -0.05419921875 +53130 -0.110626220703125 +53131 -0.079620361328125 +53132 -0.199493408203125 +53133 -0.114898681640625 +53134 -0.29437255859375 +53135 -0.15020751953125 +53136 -0.33221435546875 +53137 -0.161895751953125 +53138 -0.27972412109375 +53139 -0.137664794921875 +53140 -0.185333251953125 +53141 -0.096038818359375 +53142 -0.128204345703125 +53143 -0.067169189453125 +53144 -0.115692138671875 +53145 -0.05419921875 +53146 -0.116455078125 +53147 -0.045867919921875 +53148 -0.105926513671875 +53149 -0.033416748046875 +53150 -0.053955078125 +53151 -0.0059814453125 +53152 0.048797607421875 +53153 0.039520263671875 +53154 0.157318115234375 +53155 0.085845947265625 +53156 0.212005615234375 +53157 0.110321044921875 +53158 0.218475341796875 +53159 0.1148681640625 +53160 0.23724365234375 +53161 0.1221923828125 +53162 0.30535888671875 +53163 0.146270751953125 +53164 0.38128662109375 +53165 0.171630859375 +53166 0.404449462890625 +53167 0.175689697265625 +53168 0.3944091796875 +53169 0.16607666015625 +53170 0.3885498046875 +53171 0.1572265625 +53172 0.362640380859375 +53173 0.140411376953125 +53174 0.27362060546875 +53175 0.099853515625 +53176 0.11712646484375 +53177 0.0343017578125 +53178 -0.054901123046875 +53179 -0.036346435546875 +53180 -0.19085693359375 +53181 -0.092376708984375 +53182 -0.28570556640625 +53183 -0.13165283203125 +53184 -0.339263916015625 +53185 -0.153961181640625 +53186 -0.3775634765625 +53187 -0.16900634765625 +53188 -0.445709228515625 +53189 -0.193756103515625 +53190 -0.535064697265625 +53191 -0.225067138671875 +53192 -0.629058837890625 +53193 -0.256866455078125 +53194 -0.697601318359375 +53195 -0.278045654296875 +53196 -0.70391845703125 +53197 -0.27508544921875 +53198 -0.6424560546875 +53199 -0.2462158203125 +53200 -0.491241455078125 +53201 -0.1834716796875 +53202 -0.265716552734375 +53203 -0.093017578125 +53204 -0.023712158203125 +53205 0.003082275390625 +53206 0.201751708984375 +53207 0.0921630859375 +53208 0.375823974609375 +53209 0.160919189453125 +53210 0.485076904296875 +53211 0.204132080078125 +53212 0.56884765625 +53213 0.23651123046875 +53214 0.634765625 +53215 0.26092529296875 +53216 0.63763427734375 +53217 0.26043701171875 +53218 0.5660400390625 +53219 0.230865478515625 +53220 0.4720458984375 +53221 0.19195556640625 +53222 0.40692138671875 +53223 0.1632080078125 +53224 0.3778076171875 +53225 0.147552490234375 +53226 0.376953125 +53227 0.142364501953125 +53228 0.371978759765625 +53229 0.1357421875 +53230 0.313140869140625 +53231 0.109222412109375 +53232 0.184417724609375 +53233 0.056976318359375 +53234 0.011199951171875 +53235 -0.011199951171875 +53236 -0.171051025390625 +53237 -0.081787109375 +53238 -0.33740234375 +53239 -0.145355224609375 +53240 -0.47198486328125 +53241 -0.1959228515625 +53242 -0.560394287109375 +53243 -0.22808837890625 +53244 -0.58056640625 +53245 -0.233673095703125 +53246 -0.54754638671875 +53247 -0.218475341796875 +53248 -0.508575439453125 +53249 -0.2003173828125 +53250 -0.459503173828125 +53251 -0.17803955078125 +53252 -0.394378662109375 +53253 -0.1494140625 +53254 -0.35260009765625 +53255 -0.1282958984375 +53256 -0.31170654296875 +53257 -0.107330322265625 +53258 -0.197418212890625 +53259 -0.06134033203125 +53260 -0.007965087890625 +53261 0.009918212890625 +53262 0.207489013671875 +53263 0.0892333984375 +53264 0.409210205078125 +53265 0.162689208984375 +53266 0.57208251953125 +53267 0.22149658203125 +53268 0.66595458984375 +53269 0.255157470703125 +53270 0.65875244140625 +53271 0.25262451171875 +53272 0.56744384765625 +53273 0.219757080078125 +53274 0.431396484375 +53275 0.17022705078125 +53276 0.29443359375 +53277 0.1192626953125 +53278 0.182464599609375 +53279 0.0760498046875 +53280 0.06365966796875 +53281 0.0299072265625 +53282 -0.075958251953125 +53283 -0.023651123046875 +53284 -0.189422607421875 +53285 -0.068145751953125 +53286 -0.271942138671875 +53287 -0.10162353515625 +53288 -0.342529296875 +53289 -0.13037109375 +53290 -0.364166259765625 +53291 -0.141448974609375 +53292 -0.327239990234375 +53293 -0.131378173828125 +53294 -0.2769775390625 +53295 -0.115631103515625 +53296 -0.253692626953125 +53297 -0.108001708984375 +53298 -0.24365234375 +53299 -0.103790283203125 +53300 -0.1983642578125 +53301 -0.08636474609375 +53302 -0.116241455078125 +53303 -0.055328369140625 +53304 -0.036834716796875 +53305 -0.0244140625 +53306 0.034881591796875 +53307 0.00439453125 +53308 0.09124755859375 +53309 0.028228759765625 +53310 0.10888671875 +53311 0.038787841796875 +53312 0.125518798828125 +53313 0.048797607421875 +53314 0.15771484375 +53315 0.063720703125 +53316 0.17828369140625 +53317 0.074005126953125 +53318 0.17108154296875 +53319 0.073944091796875 +53320 0.129974365234375 +53321 0.06134033203125 +53322 0.082427978515625 +53323 0.045562744140625 +53324 0.027679443359375 +53325 0.0263671875 +53326 -0.065643310546875 +53327 -0.0069580078125 +53328 -0.15936279296875 +53329 -0.04119873046875 +53330 -0.21307373046875 +53331 -0.06231689453125 +53332 -0.234649658203125 +53333 -0.0728759765625 +53334 -0.2001953125 +53335 -0.064483642578125 +53336 -0.119171142578125 +53337 -0.04022216796875 +53338 -0.024749755859375 +53339 -0.01129150390625 +53340 0.085784912109375 +53341 0.0234375 +53342 0.178131103515625 +53343 0.05230712890625 +53344 0.215576171875 +53345 0.0628662109375 +53346 0.211456298828125 +53347 0.059783935546875 +53348 0.17523193359375 +53349 0.04644775390625 +53350 0.128753662109375 +53351 0.030364990234375 +53352 0.1019287109375 +53353 0.021820068359375 +53354 0.0743408203125 +53355 0.01373291015625 +53356 0.04327392578125 +53357 0.005035400390625 +53358 0.038177490234375 +53359 0.0057373046875 +53360 0.076263427734375 +53361 0.0216064453125 +53362 0.14105224609375 +53363 0.04681396484375 +53364 0.186431884765625 +53365 0.06536865234375 +53366 0.188812255859375 +53367 0.0689697265625 +53368 0.1390380859375 +53369 0.0543212890625 +53370 0.041778564453125 +53371 0.022918701171875 +53372 -0.079437255859375 +53373 -0.0172119140625 +53374 -0.219390869140625 +53375 -0.064361572265625 +53376 -0.367828369140625 +53377 -0.115020751953125 +53378 -0.494873046875 +53379 -0.158935546875 +53380 -0.556243896484375 +53381 -0.18084716796875 +53382 -0.508697509765625 +53383 -0.165802001953125 +53384 -0.3756103515625 +53385 -0.12176513671875 +53386 -0.218902587890625 +53387 -0.0699462890625 +53388 -0.063751220703125 +53389 -0.018890380859375 +53390 0.091552734375 +53391 0.032073974609375 +53392 0.23602294921875 +53393 0.079345703125 +53394 0.342987060546875 +53395 0.113861083984375 +53396 0.39520263671875 +53397 0.129852294921875 +53398 0.389373779296875 +53399 0.126251220703125 +53400 0.324249267578125 +53401 0.10272216796875 +53402 0.224090576171875 +53403 0.067657470703125 +53404 0.124267578125 +53405 0.03326416015625 +53406 0.037078857421875 +53407 0.003753662109375 +53408 -0.010101318359375 +53409 -0.011505126953125 +53410 -0.019439697265625 +53411 -0.013336181640625 +53412 -0.022796630859375 +53413 -0.012786865234375 +53414 -0.001556396484375 +53415 -0.0035400390625 +53416 0.056304931640625 +53417 0.018402099609375 +53418 0.106719970703125 +53419 0.037750244140625 +53420 0.096893310546875 +53421 0.036285400390625 +53422 0.042694091796875 +53423 0.01934814453125 +53424 -0.018035888671875 +53425 -0.0001220703125 +53426 -0.07586669921875 +53427 -0.018951416015625 +53428 -0.11944580078125 +53429 -0.03326416015625 +53430 -0.15972900390625 +53431 -0.046875 +53432 -0.202606201171875 +53433 -0.061798095703125 +53434 -0.24859619140625 +53435 -0.07818603515625 +53436 -0.30517578125 +53437 -0.09857177734375 +53438 -0.36212158203125 +53439 -0.119384765625 +53440 -0.39141845703125 +53441 -0.13092041015625 +53442 -0.35528564453125 +53443 -0.120086669921875 +53444 -0.249969482421875 +53445 -0.08551025390625 +53446 -0.092864990234375 +53447 -0.0330810546875 +53448 0.08905029296875 +53449 0.027984619140625 +53450 0.2352294921875 +53451 0.07696533203125 +53452 0.318817138671875 +53453 0.10467529296875 +53454 0.358642578125 +53455 0.11761474609375 +53456 0.347747802734375 +53457 0.11346435546875 +53458 0.28564453125 +53459 0.092041015625 +53460 0.223175048828125 +53461 0.070831298828125 +53462 0.196746826171875 +53463 0.062347412109375 +53464 0.179840087890625 +53465 0.057403564453125 +53466 0.155548095703125 +53467 0.0501708984375 +53468 0.151214599609375 +53469 0.049957275390625 +53470 0.156951904296875 +53471 0.05328369140625 +53472 0.13177490234375 +53473 0.04595947265625 +53474 0.100799560546875 +53475 0.03656005859375 +53476 0.087127685546875 +53477 0.032989501953125 +53478 0.05487060546875 +53479 0.0228271484375 +53480 -0.009002685546875 +53481 0.00152587890625 +53482 -0.10400390625 +53483 -0.030731201171875 +53484 -0.229400634765625 +53485 -0.07373046875 +53486 -0.35552978515625 +53487 -0.11724853515625 +53488 -0.441925048828125 +53489 -0.1473388671875 +53490 -0.473846435546875 +53491 -0.158905029296875 +53492 -0.464813232421875 +53493 -0.15655517578125 +53494 -0.419097900390625 +53495 -0.1417236328125 +53496 -0.334320068359375 +53497 -0.113525390625 +53498 -0.227935791015625 +53499 -0.07794189453125 +53500 -0.12347412109375 +53501 -0.04296875 +53502 -0.02764892578125 +53503 -0.010894775390625 +53504 0.077667236328125 +53505 0.02459716796875 +53506 0.2132568359375 +53507 0.0704345703125 +53508 0.38885498046875 +53509 0.129180908203125 +53510 0.582794189453125 +53511 0.1934814453125 +53512 0.734039306640625 +53513 0.243743896484375 +53514 0.800140380859375 +53515 0.26641845703125 +53516 0.7783203125 +53517 0.260467529296875 +53518 0.6651611328125 +53519 0.2247314453125 +53520 0.45965576171875 +53521 0.158966064453125 +53522 0.199188232421875 +53523 0.074981689453125 +53524 -0.050689697265625 +53525 -0.00653076171875 +53526 -0.23297119140625 +53527 -0.067535400390625 +53528 -0.33013916015625 +53529 -0.102264404296875 +53530 -0.368408203125 +53531 -0.11865234375 +53532 -0.378936767578125 +53533 -0.1260986328125 +53534 -0.376983642578125 +53535 -0.129150390625 +53536 -0.37969970703125 +53537 -0.132965087890625 +53538 -0.391510009765625 +53539 -0.13873291015625 +53540 -0.385345458984375 +53541 -0.137908935546875 +53542 -0.3419189453125 +53543 -0.124420166015625 +53544 -0.28289794921875 +53545 -0.105072021484375 +53546 -0.251617431640625 +53547 -0.09344482421875 +53548 -0.266143798828125 +53549 -0.095306396484375 +53550 -0.273345947265625 +53551 -0.094268798828125 +53552 -0.216796875 +53553 -0.072906494140625 +53554 -0.128265380859375 +53555 -0.04132080078125 +53556 -0.068145751953125 +53557 -0.018585205078125 +53558 -0.0430908203125 +53559 -0.006988525390625 +53560 -0.024444580078125 +53561 0.00213623046875 +53562 0.020721435546875 +53563 0.0189208984375 +53564 0.124481201171875 +53565 0.05322265625 +53566 0.25787353515625 +53567 0.095916748046875 +53568 0.379119873046875 +53569 0.133941650390625 +53570 0.47991943359375 +53571 0.16473388671875 +53572 0.5281982421875 +53573 0.1783447265625 +53574 0.511138916015625 +53575 0.170867919921875 +53576 0.456207275390625 +53577 0.1510009765625 +53578 0.407470703125 +53579 0.132659912109375 +53580 0.383758544921875 +53581 0.121917724609375 +53582 0.35687255859375 +53583 0.110137939453125 +53584 0.31182861328125 +53585 0.09283447265625 +53586 0.250885009765625 +53587 0.0709228515625 +53588 0.1654052734375 +53589 0.0418701171875 +53590 0.035247802734375 +53591 -0.00048828125 +53592 -0.142059326171875 +53593 -0.056854248046875 +53594 -0.33563232421875 +53595 -0.1175537109375 +53596 -0.5345458984375 +53597 -0.179168701171875 +53598 -0.72186279296875 +53599 -0.236480712890625 +53600 -0.836669921875 +53601 -0.27056884765625 +53602 -0.8326416015625 +53603 -0.267059326171875 +53604 -0.7296142578125 +53605 -0.2322998046875 +53606 -0.582550048828125 +53607 -0.183624267578125 +53608 -0.440093994140625 +53609 -0.1363525390625 +53610 -0.324310302734375 +53611 -0.097503662109375 +53612 -0.20147705078125 +53613 -0.05670166015625 +53614 -0.044647216796875 +53615 -0.00567626953125 +53616 0.103973388671875 +53617 0.04229736328125 +53618 0.202392578125 +53619 0.07403564453125 +53620 0.264495849609375 +53621 0.093841552734375 +53622 0.338897705078125 +53623 0.116851806640625 +53624 0.443817138671875 +53625 0.148773193359375 +53626 0.545074462890625 +53627 0.178985595703125 +53628 0.6173095703125 +53629 0.199676513671875 +53630 0.6524658203125 +53631 0.208465576171875 +53632 0.66339111328125 +53633 0.209503173828125 +53634 0.6561279296875 +53635 0.204803466796875 +53636 0.606781005859375 +53637 0.187042236328125 +53638 0.501190185546875 +53639 0.15191650390625 +53640 0.352783203125 +53641 0.10369873046875 +53642 0.176544189453125 +53643 0.047210693359375 +53644 -0.034820556640625 +53645 -0.019744873046875 +53646 -0.258209228515625 +53647 -0.08990478515625 +53648 -0.44244384765625 +53649 -0.14727783203125 +53650 -0.5753173828125 +53651 -0.188079833984375 +53652 -0.65203857421875 +53653 -0.210906982421875 +53654 -0.641632080078125 +53655 -0.206146240234375 +53656 -0.562164306640625 +53657 -0.179534912109375 +53658 -0.458038330078125 +53659 -0.145050048828125 +53660 -0.350555419921875 +53661 -0.10943603515625 +53662 -0.260528564453125 +53663 -0.07928466796875 +53664 -0.192108154296875 +53665 -0.0560302734375 +53666 -0.141937255859375 +53667 -0.038726806640625 +53668 -0.1021728515625 +53669 -0.024993896484375 +53670 -0.062896728515625 +53671 -0.011810302734375 +53672 -0.011932373046875 +53673 0.00457763671875 +53674 0.062835693359375 +53675 0.027923583984375 +53676 0.148712158203125 +53677 0.054290771484375 +53678 0.241729736328125 +53679 0.082489013671875 +53680 0.34912109375 +53681 0.11480712890625 +53682 0.457305908203125 +53683 0.1470947265625 +53684 0.54388427734375 +53685 0.172454833984375 +53686 0.5728759765625 +53687 0.17974853515625 +53688 0.506591796875 +53689 0.157318115234375 +53690 0.351226806640625 +53691 0.107208251953125 +53692 0.146514892578125 +53693 0.0418701171875 +53694 -0.05523681640625 +53695 -0.02227783203125 +53696 -0.21624755859375 +53697 -0.0733642578125 +53698 -0.334930419921875 +53699 -0.110870361328125 +53700 -0.402984619140625 +53701 -0.132171630859375 +53702 -0.4412841796875 +53703 -0.143798828125 +53704 -0.49578857421875 +53705 -0.160125732421875 +53706 -0.5601806640625 +53707 -0.179229736328125 +53708 -0.600738525390625 +53709 -0.190673828125 +53710 -0.584228515625 +53711 -0.18414306640625 +53712 -0.47930908203125 +53713 -0.149932861328125 +53714 -0.27935791015625 +53715 -0.086090087890625 +53716 -0.0089111328125 +53717 -0.000335693359375 +53718 0.268798828125 +53719 0.087493896484375 +53720 0.482818603515625 +53721 0.15521240234375 +53722 0.60369873046875 +53723 0.193603515625 +53724 0.650421142578125 +53725 0.208526611328125 +53726 0.66400146484375 +53727 0.2127685546875 +53728 0.6414794921875 +53729 0.2054443359375 +53730 0.572540283203125 +53731 0.183380126953125 +53732 0.498138427734375 +53733 0.15936279296875 +53734 0.439453125 +53735 0.14007568359375 +53736 0.375518798828125 +53737 0.1190185546875 +53738 0.274505615234375 +53739 0.086334228515625 +53740 0.1087646484375 +53741 0.033447265625 +53742 -0.099395751953125 +53743 -0.0325927734375 +53744 -0.3182373046875 +53745 -0.101806640625 +53746 -0.5489501953125 +53747 -0.174560546875 +53748 -0.7738037109375 +53749 -0.245269775390625 +53750 -0.86383056640625 +53751 -0.29736328125 +53752 -0.870391845703125 +53753 -0.320465087890625 +53754 -0.86895751953125 +53755 -0.32012939453125 +53756 -0.861053466796875 +53757 -0.300445556640625 +53758 -0.765869140625 +53759 -0.25604248046875 +53760 -0.5301513671875 +53761 -0.183563232421875 +53762 -0.214691162109375 +53763 -0.085784912109375 +53764 0.137359619140625 +53765 0.02398681640625 +53766 0.474822998046875 +53767 0.13037109375 +53768 0.76239013671875 +53769 0.2225341796875 +53770 0.867462158203125 +53771 0.292205810546875 +53772 0.870361328125 +53773 0.339019775390625 +53774 0.86480712890625 +53775 0.35943603515625 +53776 0.831817626953125 +53777 0.354827880859375 +53778 0.677581787109375 +53779 0.33209228515625 +53780 0.495880126953125 +53781 0.293060302734375 +53782 0.30767822265625 +53783 0.243255615234375 +53784 0.116180419921875 +53785 0.1837158203125 +53786 -0.110748291015625 +53787 0.106048583984375 +53788 -0.381805419921875 +53789 0.008880615234375 +53790 -0.6572265625 +53791 -0.095245361328125 +53792 -0.857421875 +53793 -0.188995361328125 +53794 -0.870391845703125 +53795 -0.2598876953125 +53796 -0.870391845703125 +53797 -0.3055419921875 +53798 -0.86444091796875 +53799 -0.33319091796875 +53800 -0.85723876953125 +53801 -0.352630615234375 +53802 -0.790008544921875 +53803 -0.358612060546875 +53804 -0.62847900390625 +53805 -0.335968017578125 +53806 -0.3956298828125 +53807 -0.283935546875 +53808 -0.126708984375 +53809 -0.211944580078125 +53810 0.150115966796875 +53811 -0.128021240234375 +53812 0.424041748046875 +53813 -0.035797119140625 +53814 0.670623779296875 +53815 0.056732177734375 +53816 0.854522705078125 +53817 0.1383056640625 +53818 0.866485595703125 +53819 0.20355224609375 +53820 0.86920166015625 +53821 0.247772216796875 +53822 0.8653564453125 +53823 0.27569580078125 +53824 0.857147216796875 +53825 0.290802001953125 +53826 0.766845703125 +53827 0.2921142578125 +53828 0.628509521484375 +53829 0.28094482421875 +53830 0.462127685546875 +53831 0.255401611328125 +53832 0.297210693359375 +53833 0.2227783203125 +53834 0.14862060546875 +53835 0.186737060546875 +53836 -0.00537109375 +53837 0.141082763671875 +53838 -0.15753173828125 +53839 0.088226318359375 +53840 -0.31304931640625 +53841 0.027496337890625 +53842 -0.48876953125 +53843 -0.044647216796875 +53844 -0.6416015625 +53845 -0.114715576171875 +53846 -0.751373291015625 +53847 -0.175445556640625 +53848 -0.84619140625 +53849 -0.233001708984375 +53850 -0.861297607421875 +53851 -0.28302001953125 +53852 -0.863250732421875 +53853 -0.316070556640625 +53854 -0.856597900390625 +53855 -0.32318115234375 +53856 -0.7498779296875 +53857 -0.307708740234375 +53858 -0.624542236328125 +53859 -0.285919189453125 +53860 -0.47808837890625 +53861 -0.251739501953125 +53862 -0.253387451171875 +53863 -0.188995361328125 +53864 0.003692626953125 +53865 -0.1107177734375 +53866 0.2257080078125 +53867 -0.03631591796875 +53868 0.427154541015625 +53869 0.037384033203125 +53870 0.643218994140625 +53871 0.119140625 +53872 0.855926513671875 +53873 0.205963134765625 +53874 0.870361328125 +53875 0.2813720703125 +53876 0.870361328125 +53877 0.33123779296875 +53878 0.862762451171875 +53879 0.357421875 +53880 0.79669189453125 +53881 0.358978271484375 +53882 0.595794677734375 +53883 0.333251953125 +53884 0.362152099609375 +53885 0.288421630859375 +53886 0.1270751953125 +53887 0.232421875 +53888 -0.086944580078125 +53889 0.171295166015625 +53890 -0.2784423828125 +53891 0.1058349609375 +53892 -0.484832763671875 +53893 0.026519775390625 +53894 -0.729583740234375 +53895 -0.07171630859375 +53896 -0.86688232421875 +53897 -0.174468994140625 +53898 -0.870391845703125 +53899 -0.263763427734375 +53900 -0.86859130859375 +53901 -0.33795166015625 +53902 -0.86279296875 +53903 -0.396209716796875 +53904 -0.817962646484375 +53905 -0.428314208984375 +53906 -0.6116943359375 +53907 -0.42144775390625 +53908 -0.3128662109375 +53909 -0.37353515625 +53910 0.039398193359375 +53911 -0.294036865234375 +53912 0.422821044921875 +53913 -0.1885986328125 +53914 0.805145263671875 +53915 -0.066650390625 +53916 0.870361328125 +53917 0.052520751953125 +53918 0.870361328125 +53919 0.152740478515625 +53920 0.860015869140625 +53921 0.23046875 +53922 0.727935791015625 +53923 0.2833251953125 +53924 0.48114013671875 +53925 0.3094482421875 +53926 0.2059326171875 +53927 0.315338134765625 +53928 -0.06103515625 +53929 0.307098388671875 +53930 -0.29913330078125 +53931 0.287384033203125 +53932 -0.516204833984375 +53933 0.251983642578125 +53934 -0.7252197265625 +53935 0.196502685546875 +53936 -0.85980224609375 +53937 0.1279296875 +53938 -0.870391845703125 +53939 0.055938720703125 +53940 -0.870391845703125 +53941 -0.011016845703125 +53942 -0.858062744140625 +53943 -0.05908203125 +53944 -0.673004150390625 +53945 -0.086822509765625 +53946 -0.42694091796875 +53947 -0.108642578125 +53948 -0.2100830078125 +53949 -0.136627197265625 +53950 -0.0362548828125 +53951 -0.16986083984375 +53952 0.10943603515625 +53953 -0.19989013671875 +53954 0.23516845703125 +53955 -0.220855712890625 +53956 0.373687744140625 +53957 -0.220977783203125 +53958 0.517791748046875 +53959 -0.20062255859375 +53960 0.602783203125 +53961 -0.1773681640625 +53962 0.635711669921875 +53963 -0.1497802734375 +53964 0.655181884765625 +53965 -0.10858154296875 +53966 0.65948486328125 +53967 -0.05670166015625 +53968 0.651275634765625 +53969 0.00335693359375 +53970 0.61846923828125 +53971 0.064483642578125 +53972 0.53753662109375 +53973 0.115997314453125 +53974 0.404144287109375 +53975 0.152557373046875 +53976 0.22186279296875 +53977 0.171142578125 +53978 0.003997802734375 +53979 0.171844482421875 +53980 -0.22100830078125 +53981 0.15948486328125 +53982 -0.42449951171875 +53983 0.139617919921875 +53984 -0.579833984375 +53985 0.118072509765625 +53986 -0.641876220703125 +53987 0.106719970703125 +53988 -0.6177978515625 +53989 0.103668212890625 +53990 -0.575531005859375 +53991 0.090911865234375 +53992 -0.526336669921875 +53993 0.067047119140625 +53994 -0.42645263671875 +53995 0.046783447265625 +53996 -0.2581787109375 +53997 0.0379638671875 +53998 -0.068695068359375 +53999 0.030670166015625 +54000 0.09222412109375 +54001 0.014373779296875 +54002 0.232147216796875 +54003 -0.00537109375 +54004 0.3509521484375 +54005 -0.025482177734375 +54006 0.410064697265625 +54007 -0.053985595703125 +54008 0.372955322265625 +54009 -0.098907470703125 +54010 0.2554931640625 +54011 -0.154205322265625 +54012 0.10711669921875 +54013 -0.205169677734375 +54014 -0.052886962890625 +54015 -0.24627685546875 +54016 -0.186279296875 +54017 -0.267791748046875 +54018 -0.23291015625 +54019 -0.254608154296875 +54020 -0.209442138671875 +54021 -0.21234130859375 +54022 -0.174163818359375 +54023 -0.158355712890625 +54024 -0.126739501953125 +54025 -0.09564208984375 +54026 -0.048126220703125 +54027 -0.022705078125 +54028 0.0426025390625 +54029 0.052490234375 +54030 0.10748291015625 +54031 0.117431640625 +54032 0.1409912109375 +54033 0.1680908203125 +54034 0.19708251953125 +54035 0.215789794921875 +54036 0.273651123046875 +54037 0.25836181640625 +54038 0.31768798828125 +54039 0.281585693359375 +54040 0.341094970703125 +54041 0.288116455078125 +54042 0.368011474609375 +54043 0.284332275390625 +54044 0.37249755859375 +54045 0.2646484375 +54046 0.30072021484375 +54047 0.217041015625 +54048 0.1517333984375 +54049 0.1431884765625 +54050 -0.01470947265625 +54051 0.06024169921875 +54052 -0.1883544921875 +54053 -0.02679443359375 +54054 -0.372711181640625 +54055 -0.116363525390625 +54056 -0.51397705078125 +54057 -0.192626953125 +54058 -0.57177734375 +54059 -0.243316650390625 +54060 -0.53948974609375 +54061 -0.264923095703125 +54062 -0.43511962890625 +54063 -0.26055908203125 +54064 -0.2962646484375 +54065 -0.2386474609375 +54066 -0.161102294921875 +54067 -0.208282470703125 +54068 -0.0435791015625 +54069 -0.17303466796875 +54070 0.060394287109375 +54071 -0.132476806640625 +54072 0.13665771484375 +54073 -0.0911865234375 +54074 0.170135498046875 +54075 -0.054351806640625 +54076 0.16552734375 +54077 -0.02252197265625 +54078 0.15728759765625 +54079 0.01092529296875 +54080 0.150787353515625 +54081 0.04534912109375 +54082 0.12200927734375 +54083 0.07275390625 +54084 0.080108642578125 +54085 0.093597412109375 +54086 0.05126953125 +54087 0.11279296875 +54088 0.062896728515625 +54089 0.135894775390625 +54090 0.09271240234375 +54091 0.156402587890625 +54092 0.092987060546875 +54093 0.161895751953125 +54094 0.07855224609375 +54095 0.156005859375 +54096 0.06427001953125 +54097 0.142791748046875 +54098 0.0347900390625 +54099 0.119110107421875 +54100 -0.01171875 +54101 0.085601806640625 +54102 -0.056060791015625 +54103 0.048431396484375 +54104 -0.055511474609375 +54105 0.01983642578125 +54106 -0.010467529296875 +54107 0.0013427734375 +54108 0.02508544921875 +54109 -0.01885986328125 +54110 0.025665283203125 +54111 -0.045562744140625 +54112 0.017333984375 +54113 -0.07086181640625 +54114 0.00189208984375 +54115 -0.0931396484375 +54116 -0.03173828125 +54117 -0.114288330078125 +54118 -0.071502685546875 +54119 -0.13079833984375 +54120 -0.13543701171875 +54121 -0.14697265625 +54122 -0.219970703125 +54123 -0.162109375 +54124 -0.300506591796875 +54125 -0.1705322265625 +54126 -0.376312255859375 +54127 -0.1728515625 +54128 -0.416107177734375 +54129 -0.162322998046875 +54130 -0.371124267578125 +54131 -0.12799072265625 +54132 -0.242279052734375 +54133 -0.0714111328125 +54134 -0.069732666015625 +54135 -0.003997802734375 +54136 0.125640869140625 +54137 0.06768798828125 +54138 0.31268310546875 +54139 0.1346435546875 +54140 0.45501708984375 +54141 0.186737060546875 +54142 0.554779052734375 +54143 0.223724365234375 +54144 0.61065673828125 +54145 0.2447509765625 +54146 0.610931396484375 +54147 0.246673583984375 +54148 0.531463623046875 +54149 0.2235107421875 +54150 0.3883056640625 +54151 0.1795654296875 +54152 0.23468017578125 +54153 0.128753662109375 +54154 0.095245361328125 +54155 0.07806396484375 +54156 -0.00396728515625 +54157 0.034942626953125 +54158 -0.04852294921875 +54159 0.0040283203125 +54160 -0.055145263671875 +54161 -0.0177001953125 +54162 -0.0758056640625 +54163 -0.042144775390625 +54164 -0.138702392578125 +54165 -0.0753173828125 +54166 -0.209197998046875 +54167 -0.107635498046875 +54168 -0.289031982421875 +54169 -0.138824462890625 +54170 -0.37884521484375 +54171 -0.16851806640625 +54172 -0.456329345703125 +54173 -0.190887451171875 +54174 -0.51641845703125 +54175 -0.204620361328125 +54176 -0.519287109375 +54177 -0.199951171875 +54178 -0.458251953125 +54179 -0.17559814453125 +54180 -0.384796142578125 +54181 -0.145050048828125 +54182 -0.323699951171875 +54183 -0.115234375 +54184 -0.269287109375 +54185 -0.085601806640625 +54186 -0.1951904296875 +54187 -0.050506591796875 +54188 -0.100006103515625 +54189 -0.010498046875 +54190 -0.01055908203125 +54191 0.02679443359375 +54192 0.1033935546875 +54193 0.06817626953125 +54194 0.24908447265625 +54195 0.11480712890625 +54196 0.373199462890625 +54197 0.15289306640625 +54198 0.45806884765625 +54199 0.177734375 +54200 0.511474609375 +54201 0.191131591796875 +54202 0.565399169921875 +54203 0.201202392578125 +54204 0.61138916015625 +54205 0.20611572265625 +54206 0.5897216796875 +54207 0.19140625 +54208 0.4906005859375 +54209 0.15521240234375 +54210 0.33148193359375 +54211 0.102569580078125 +54212 0.147796630859375 +54213 0.043060302734375 +54214 -0.01873779296875 +54215 -0.0120849609375 +54216 -0.140289306640625 +54217 -0.05517578125 +54218 -0.191986083984375 +54219 -0.079315185546875 +54220 -0.184295654296875 +54221 -0.086578369140625 +54222 -0.161834716796875 +54223 -0.087677001953125 +54224 -0.166595458984375 +54225 -0.0927734375 +54226 -0.19390869140625 +54227 -0.1005859375 +54228 -0.22442626953125 +54229 -0.1063232421875 +54230 -0.279754638671875 +54231 -0.115570068359375 +54232 -0.3389892578125 +54233 -0.1234130859375 +54234 -0.3543701171875 +54235 -0.118377685546875 +54236 -0.348175048828125 +54237 -0.1065673828125 +54238 -0.32598876953125 +54239 -0.0899658203125 +54240 -0.2581787109375 +54241 -0.061798095703125 +54242 -0.139801025390625 +54243 -0.02142333984375 +54244 0.014617919921875 +54245 0.02691650390625 +54246 0.144378662109375 +54247 0.067535400390625 +54248 0.221038818359375 +54249 0.092926025390625 +54250 0.27069091796875 +54251 0.10931396484375 +54252 0.294036865234375 +54253 0.11676025390625 +54254 0.311767578125 +54255 0.12042236328125 +54256 0.339141845703125 +54257 0.12420654296875 +54258 0.360260009765625 +54259 0.12432861328125 +54260 0.360504150390625 +54261 0.11749267578125 +54262 0.308380126953125 +54263 0.0963134765625 +54264 0.18170166015625 +54265 0.0557861328125 +54266 0.0047607421875 +54267 0.00250244140625 +54268 -0.17559814453125 +54269 -0.0513916015625 +54270 -0.3143310546875 +54271 -0.09423828125 +54272 -0.36785888671875 +54273 -0.11517333984375 +54274 -0.36248779296875 +54275 -0.119964599609375 +54276 -0.343536376953125 +54277 -0.11895751953125 +54278 -0.3018798828125 +54279 -0.110321044921875 +54280 -0.231414794921875 +54281 -0.092926025390625 +54282 -0.117645263671875 +54283 -0.063934326171875 +54284 0.007049560546875 +54285 -0.030731201171875 +54286 0.087982177734375 +54287 -0.005523681640625 +54288 0.13946533203125 +54289 0.0142822265625 +54290 0.17425537109375 +54291 0.03094482421875 +54292 0.188201904296875 +54293 0.0430908203125 +54294 0.171234130859375 +54295 0.048065185546875 +54296 0.118438720703125 +54297 0.04437255859375 +54298 0.05706787109375 +54299 0.037567138671875 +54300 -0.010711669921875 +54301 0.02777099609375 +54302 -0.0914306640625 +54303 0.01336669921875 +54304 -0.162322998046875 +54305 -0.00079345703125 +54306 -0.194549560546875 +54307 -0.008514404296875 +54308 -0.1492919921875 +54309 -0.00128173828125 +54310 -0.02166748046875 +54311 0.022125244140625 +54312 0.124053955078125 +54313 0.048095703125 +54314 0.211151123046875 +54315 0.06036376953125 +54316 0.240447998046875 +54317 0.059539794921875 +54318 0.242218017578125 +54319 0.05255126953125 +54320 0.2257080078125 +54321 0.04180908203125 +54322 0.194366455078125 +54323 0.0284423828125 +54324 0.115509033203125 +54325 0.0057373046875 +54326 0.0128173828125 +54327 -0.020843505859375 +54328 -0.053802490234375 +54329 -0.038177490234375 +54330 -0.110626220703125 +54331 -0.05181884765625 +54332 -0.199493408203125 +54333 -0.070770263671875 +54334 -0.29437255859375 +54335 -0.089508056640625 +54336 -0.33221435546875 +54337 -0.09454345703125 +54338 -0.27972412109375 +54339 -0.07891845703125 +54340 -0.185333251953125 +54341 -0.053314208984375 +54342 -0.128204345703125 +54343 -0.03515625 +54344 -0.115692138671875 +54345 -0.0263671875 +54346 -0.116455078125 +54347 -0.0205078125 +54348 -0.105926513671875 +54349 -0.01263427734375 +54350 -0.053955078125 +54351 0.003448486328125 +54352 0.048797607421875 +54353 0.029541015625 +54354 0.157318115234375 +54355 0.05572509765625 +54356 0.212005615234375 +54357 0.069000244140625 +54358 0.218475341796875 +54359 0.070556640625 +54360 0.23724365234375 +54361 0.073516845703125 +54362 0.30535888671875 +54363 0.085968017578125 +54364 0.38128662109375 +54365 0.09906005859375 +54366 0.404449462890625 +54367 0.09991455078125 +54368 0.3944091796875 +54369 0.093017578125 +54370 0.3885498046875 +54371 0.086700439453125 +54372 0.362640380859375 +54373 0.0760498046875 +54374 0.27362060546875 +54375 0.052032470703125 +54376 0.11712646484375 +54377 0.01397705078125 +54378 -0.054901123046875 +54379 -0.026641845703125 +54380 -0.19085693359375 +54381 -0.05853271484375 +54382 -0.28570556640625 +54383 -0.08050537109375 +54384 -0.339263916015625 +54385 -0.092437744140625 +54386 -0.3775634765625 +54387 -0.100006103515625 +54388 -0.445709228515625 +54389 -0.113006591796875 +54390 -0.535064697265625 +54391 -0.12969970703125 +54392 -0.629058837890625 +54393 -0.14666748046875 +54394 -0.697601318359375 +54395 -0.1575927734375 +54396 -0.70391845703125 +54397 -0.15478515625 +54398 -0.6424560546875 +54399 -0.13726806640625 +54400 -0.491241455078125 +54401 -0.100555419921875 +54402 -0.265716552734375 +54403 -0.0482177734375 +54404 -0.023712158203125 +54405 0.007049560546875 +54406 0.201751708984375 +54407 0.058013916015625 +54408 0.375823974609375 +54409 0.097015380859375 +54410 0.485076904296875 +54411 0.12109375 +54412 0.56884765625 +54413 0.138763427734375 +54414 0.634765625 +54415 0.151702880859375 +54416 0.63763427734375 +54417 0.1502685546875 +54418 0.5660400390625 +54419 0.132110595703125 +54420 0.4720458984375 +54421 0.108642578125 +54422 0.40692138671875 +54423 0.091156005859375 +54424 0.3778076171875 +54425 0.08135986328125 +54426 0.376953125 +54427 0.0777587890625 +54428 0.371978759765625 +54429 0.07354736328125 +54430 0.313140869140625 +54431 0.05816650390625 +54432 0.184417724609375 +54433 0.028289794921875 +54434 0.011199951171875 +54435 -0.010498046875 +54436 -0.171051025390625 +54437 -0.050445556640625 +54438 -0.33740234375 +54439 -0.086181640625 +54440 -0.47198486328125 +54441 -0.114288330078125 +54442 -0.560394287109375 +54443 -0.131744384765625 +54444 -0.58056640625 +54445 -0.133880615234375 +54446 -0.54754638671875 +54447 -0.124114990234375 +54448 -0.508575439453125 +54449 -0.112823486328125 +54450 -0.459503173828125 +54451 -0.099273681640625 +54452 -0.394378662109375 +54453 -0.08233642578125 +54454 -0.35260009765625 +54455 -0.07061767578125 +54456 -0.31170654296875 +54457 -0.0594482421875 +54458 -0.197418212890625 +54459 -0.03289794921875 +54460 -0.007965087890625 +54461 0.009307861328125 +54462 0.207489013671875 +54463 0.05645751953125 +54464 0.409210205078125 +54465 0.0999755859375 +54466 0.57208251953125 +54467 0.134490966796875 +54468 0.66595458984375 +54469 0.153533935546875 +54470 0.65875244140625 +54471 0.150238037109375 +54472 0.56744384765625 +54473 0.12841796875 +54474 0.431396484375 +54475 0.0966796875 +54476 0.29443359375 +54477 0.064605712890625 +54478 0.182464599609375 +54479 0.037933349609375 +54480 0.06365966796875 +54481 0.009918212890625 +54482 -0.075958251953125 +54483 -0.02227783203125 +54484 -0.189422607421875 +54485 -0.048431396484375 +54486 -0.271942138671875 +54487 -0.0673828125 +54488 -0.342529296875 +54489 -0.083221435546875 +54490 -0.364166259765625 +54491 -0.08795166015625 +54492 -0.327239990234375 +54493 -0.079498291015625 +54494 -0.2769775390625 +54495 -0.06768798828125 +54496 -0.253692626953125 +54497 -0.061279296875 +54498 -0.24365234375 +54499 -0.057373046875 +54500 -0.1983642578125 +54501 -0.045654296875 +54502 -0.116241455078125 +54503 -0.025848388671875 +54504 -0.036834716796875 +54505 -0.006622314453125 +54506 0.034881591796875 +54507 0.01080322265625 +54508 0.09124755859375 +54509 0.024688720703125 +54510 0.10888671875 +54511 0.029876708984375 +54512 0.125518798828125 +54513 0.03448486328125 +54514 0.15771484375 +54515 0.042022705078125 +54516 0.17828369140625 +54517 0.046600341796875 +54518 0.17108154296875 +54519 0.04473876953125 +54520 0.129974365234375 +54521 0.035125732421875 +54522 0.082427978515625 +54523 0.02374267578125 +54524 0.027679443359375 +54525 0.010498046875 +54526 -0.065643310546875 +54527 -0.01123046875 +54528 -0.15936279296875 +54529 -0.033477783203125 +54530 -0.21307373046875 +54531 -0.047027587890625 +54532 -0.234649658203125 +54533 -0.0528564453125 +54534 -0.2001953125 +54535 -0.046875 +54536 -0.119171142578125 +54537 -0.03118896484375 +54538 -0.024749755859375 +54539 -0.01220703125 +54540 0.085784912109375 +54541 0.01025390625 +54542 0.178131103515625 +54543 0.029571533203125 +54544 0.215576171875 +54545 0.038818359375 +54546 0.211456298828125 +54547 0.040252685546875 +54548 0.17523193359375 +54549 0.0355224609375 +54550 0.128753662109375 +54551 0.028533935546875 +54552 0.1019287109375 +54553 0.02471923828125 +54554 0.0743408203125 +54555 0.020294189453125 +54556 0.04327392578125 +54557 0.0147705078125 +54558 0.038177490234375 +54559 0.0135498046875 +54560 0.076263427734375 +54561 0.019866943359375 +54562 0.14105224609375 +54563 0.030731201171875 +54564 0.186431884765625 +54565 0.03778076171875 +54566 0.188812255859375 +54567 0.0367431640625 +54568 0.1390380859375 +54569 0.026031494140625 +54570 0.041778564453125 +54571 0.006622314453125 +54572 -0.079437255859375 +54573 -0.017059326171875 +54574 -0.219390869140625 +54575 -0.04400634765625 +54576 -0.367828369140625 +54577 -0.072235107421875 +54578 -0.494873046875 +54579 -0.09619140625 +54580 -0.556243896484375 +54581 -0.10772705078125 +54582 -0.508697509765625 +54583 -0.098876953125 +54584 -0.3756103515625 +54585 -0.073974609375 +54586 -0.218902587890625 +54587 -0.044464111328125 +54588 -0.063751220703125 +54589 -0.0150146484375 +54590 0.091552734375 +54591 0.01458740234375 +54592 0.23602294921875 +54593 0.042236328125 +54594 0.342987060546875 +54595 0.06298828125 +54596 0.39520263671875 +54597 0.07366943359375 +54598 0.389373779296875 +54599 0.073577880859375 +54600 0.324249267578125 +54601 0.06243896484375 +54602 0.224090576171875 +54603 0.044708251953125 +54604 0.124267578125 +54605 0.026824951171875 +54606 0.037078857421875 +54607 0.01104736328125 +54608 -0.010101318359375 +54609 0.00238037109375 +54610 -0.019439697265625 +54611 0.000457763671875 +54612 -0.022796630859375 +54613 -0.00054931640625 +54614 -0.001556396484375 +54615 0.002777099609375 +54616 0.056304931640625 +54617 0.012664794921875 +54618 0.106719970703125 +54619 0.02105712890625 +54620 0.096893310546875 +54621 0.018310546875 +54622 0.042694091796875 +54623 0.007415771484375 +54624 -0.018035888671875 +54625 -0.004608154296875 +54626 -0.07586669921875 +54627 -0.015960693359375 +54628 -0.11944580078125 +54629 -0.024505615234375 +54630 -0.15972900390625 +54631 -0.032257080078125 +54632 -0.202606201171875 +54633 -0.040283203125 +54634 -0.24859619140625 +54635 -0.048675537109375 +54636 -0.30517578125 +54637 -0.058807373046875 +54638 -0.36212158203125 +54639 -0.06884765625 +54640 -0.39141845703125 +54641 -0.07366943359375 +54642 -0.35528564453125 +54643 -0.06634521484375 +54644 -0.249969482421875 +54645 -0.046234130859375 +54646 -0.092864990234375 +54647 -0.016571044921875 +54648 0.08905029296875 +54649 0.017578125 +54650 0.2352294921875 +54651 0.045074462890625 +54652 0.318817138671875 +54653 0.060943603515625 +54654 0.358642578125 +54655 0.068603515625 +54656 0.347747802734375 +54657 0.0667724609375 +54658 0.28564453125 +54659 0.05535888671875 +54660 0.223175048828125 +54661 0.043731689453125 +54662 0.196746826171875 +54663 0.038604736328125 +54664 0.179840087890625 +54665 0.035125732421875 +54666 0.155548095703125 +54667 0.030181884765625 +54668 0.151214599609375 +54669 0.028839111328125 +54670 0.156951904296875 +54671 0.029327392578125 +54672 0.13177490234375 +54673 0.02410888671875 +54674 0.100799560546875 +54675 0.017852783203125 +54676 0.087127685546875 +54677 0.01483154296875 +54678 0.05487060546875 +54679 0.00848388671875 +54680 -0.009002685546875 +54681 -0.003570556640625 +54682 -0.10400390625 +54683 -0.02117919921875 +54684 -0.229400634765625 +54685 -0.04425048828125 +54686 -0.35552978515625 +54687 -0.06732177734375 +54688 -0.441925048828125 +54689 -0.08294677734375 +54690 -0.473846435546875 +54691 -0.08843994140625 +54692 -0.464813232421875 +54693 -0.0863037109375 +54694 -0.419097900390625 +54695 -0.077362060546875 +54696 -0.334320068359375 +54697 -0.06121826171875 +54698 -0.227935791015625 +54699 -0.041107177734375 +54700 -0.12347412109375 +54701 -0.021392822265625 +54702 -0.02764892578125 +54703 -0.003326416015625 +54704 0.077667236328125 +54705 0.016387939453125 +54706 0.2132568359375 +54707 0.04156494140625 +54708 0.38885498046875 +54709 0.073944091796875 +54710 0.582794189453125 +54711 0.10955810546875 +54712 0.734039306640625 +54713 0.13720703125 +54714 0.800140380859375 +54715 0.1490478515625 +54716 0.7783203125 +54717 0.144622802734375 +54718 0.6651611328125 +54719 0.123291015625 +54720 0.45965576171875 +54721 0.084930419921875 +54722 0.199188232421875 +54723 0.0364990234375 +54724 -0.050689697265625 +54725 -0.009918212890625 +54726 -0.23297119140625 +54727 -0.0438232421875 +54728 -0.33013916015625 +54729 -0.06195068359375 +54730 -0.368408203125 +54731 -0.06915283203125 +54732 -0.378936767578125 +54733 -0.0711669921875 +54734 -0.376983642578125 +54735 -0.07080078125 +54736 -0.37969970703125 +54737 -0.07122802734375 +54738 -0.391510009765625 +54739 -0.073211669921875 +54740 -0.385345458984375 +54741 -0.071807861328125 +54742 -0.3419189453125 +54743 -0.0634765625 +54744 -0.28289794921875 +54745 -0.052215576171875 +54746 -0.251617431640625 +54747 -0.0460205078125 +54748 -0.266143798828125 +54749 -0.048248291015625 +54750 -0.273345947265625 +54751 -0.04913330078125 +54752 -0.216796875 +54753 -0.038360595703125 +54754 -0.128265380859375 +54755 -0.021759033203125 +54756 -0.068145751953125 +54757 -0.01043701171875 +54758 -0.0430908203125 +54759 -0.005645751953125 +54760 -0.024444580078125 +54761 -0.00213623046875 +54762 0.020721435546875 +54763 0.006103515625 +54764 0.124481201171875 +54765 0.024993896484375 +54766 0.25787353515625 +54767 0.049224853515625 +54768 0.379119873046875 +54769 0.071136474609375 +54770 0.47991943359375 +54771 0.0892333984375 +54772 0.5281982421875 +54773 0.097625732421875 +54774 0.511138916015625 +54775 0.093994140625 +54776 0.456207275390625 +54777 0.083404541015625 +54778 0.407470703125 +54779 0.074005126953125 +54780 0.383758544921875 +54781 0.06927490234375 +54782 0.35687255859375 +54783 0.06402587890625 +54784 0.31182861328125 +54785 0.05499267578125 +54786 0.250885009765625 +54787 0.042327880859375 +54788 0.1654052734375 +54789 0.02508544921875 +54790 0.035247802734375 +54791 0.000701904296875 +54792 -0.142059326171875 +54793 -0.030731201171875 +54794 -0.33563232421875 +54795 -0.064117431640625 +54796 -0.5345458984375 +54797 -0.097503662109375 +54798 -0.72186279296875 +54799 -0.128082275390625 +54800 -0.836669921875 +54801 -0.146484375 +54802 -0.8326416015625 +54803 -0.145599365234375 +54804 -0.7296142578125 +54805 -0.1285400390625 +54806 -0.582550048828125 +54807 -0.103790283203125 +54808 -0.440093994140625 +54809 -0.078857421875 +54810 -0.324310302734375 +54811 -0.057342529296875 +54812 -0.20147705078125 +54813 -0.034332275390625 +54814 -0.044647216796875 +54815 -0.0059814453125 +54816 0.103973388671875 +54817 0.02099609375 +54818 0.202392578125 +54819 0.03997802734375 +54820 0.264495849609375 +54821 0.052825927734375 +54822 0.338897705078125 +54823 0.066741943359375 +54824 0.443817138671875 +54825 0.084381103515625 +54826 0.545074462890625 +54827 0.100494384765625 +54828 0.6173095703125 +54829 0.1112060546875 +54830 0.6524658203125 +54831 0.1153564453125 +54832 0.66339111328125 +54833 0.114959716796875 +54834 0.6561279296875 +54835 0.111053466796875 +54836 0.606781005859375 +54837 0.10015869140625 +54838 0.501190185546875 +54839 0.080352783203125 +54840 0.352783203125 +54841 0.053924560546875 +54842 0.176544189453125 +54843 0.023345947265625 +54844 -0.034820556640625 +54845 -0.01226806640625 +54846 -0.258209228515625 +54847 -0.0491943359375 +54848 -0.44244384765625 +54849 -0.079498291015625 +54850 -0.5753173828125 +54851 -0.101226806640625 +54852 -0.65203857421875 +54853 -0.11358642578125 +54854 -0.641632080078125 +54855 -0.11187744140625 +54856 -0.562164306640625 +54857 -0.098907470703125 +54858 -0.458038330078125 +54859 -0.08148193359375 +54860 -0.350555419921875 +54861 -0.062896728515625 +54862 -0.260528564453125 +54863 -0.046478271484375 +54864 -0.192108154296875 +54865 -0.03302001953125 +54866 -0.141937255859375 +54867 -0.022186279296875 +54868 -0.1021728515625 +54869 -0.012969970703125 +54870 -0.062896728515625 +54871 -0.0040283203125 +54872 -0.011932373046875 +54873 0.00628662109375 +54874 0.062835693359375 +54875 0.01971435546875 +54876 0.148712158203125 +54877 0.03424072265625 +54878 0.241729736328125 +54879 0.0491943359375 +54880 0.34912109375 +54881 0.065643310546875 +54882 0.457305908203125 +54883 0.081512451171875 +54884 0.54388427734375 +54885 0.093475341796875 +54886 0.5728759765625 +54887 0.09613037109375 +54888 0.506591796875 +54889 0.0838623046875 +54890 0.351226806640625 +54891 0.0577392578125 +54892 0.146514892578125 +54893 0.02392578125 +54894 -0.05523681640625 +54895 -0.009429931640625 +54896 -0.21624755859375 +54897 -0.036407470703125 +54898 -0.334930419921875 +54899 -0.056640625 +54900 -0.402984619140625 +54901 -0.068756103515625 +54902 -0.4412841796875 +54903 -0.07586669921875 +54904 -0.49578857421875 +54905 -0.08489990234375 +54906 -0.5601806640625 +54907 -0.0948486328125 +54908 -0.600738525390625 +54909 -0.100616455078125 +54910 -0.584228515625 +54911 -0.097198486328125 +54912 -0.47930908203125 +54913 -0.07989501953125 +54914 -0.27935791015625 +54915 -0.04779052734375 +54916 -0.0089111328125 +54917 -0.004730224609375 +54918 0.268798828125 +54919 0.039581298828125 +54920 0.482818603515625 +54921 0.074188232421875 +54922 0.60369873046875 +54923 0.09454345703125 +54924 0.650421142578125 +54925 0.1033935546875 +54926 0.66400146484375 +54927 0.10687255859375 +54928 0.6414794921875 +54929 0.1044921875 +54930 0.572540283203125 +54931 0.094635009765625 +54932 0.498138427734375 +54933 0.083526611328125 +54934 0.439453125 +54935 0.074371337890625 +54936 0.375518798828125 +54937 0.06402587890625 +54938 0.274505615234375 +54939 0.04766845703125 +54940 0.1087646484375 +54941 0.02117919921875 +54942 -0.099395751953125 +54943 -0.011932373046875 +54944 -0.3182373046875 +54945 -0.0467529296875 +54946 -0.5489501953125 +54947 -0.083404541015625 +54948 -0.7738037109375 +54949 -0.11907958984375 +54950 -0.86383056640625 +54951 -0.1456298828125 +54952 -0.870391845703125 +54953 -0.157958984375 +54954 -0.86895751953125 +54955 -0.158721923828125 +54956 -0.861053466796875 +54957 -0.14990234375 +54958 -0.765869140625 +54959 -0.12884521484375 +54960 -0.5301513671875 +54961 -0.09381103515625 +54962 -0.214691162109375 +54963 -0.0458984375 +54964 0.137359619140625 +54965 0.008270263671875 +54966 0.474822998046875 +54967 0.060882568359375 +54968 0.76239013671875 +54969 0.10650634765625 +54970 0.867462158203125 +54971 0.140960693359375 +54972 0.870361328125 +54973 0.16424560546875 +54974 0.86480712890625 +54975 0.17449951171875 +54976 0.831817626953125 +54977 0.1724853515625 +54978 0.677581787109375 +54979 0.161865234375 +54980 0.495880126953125 +54981 0.14349365234375 +54982 0.30767822265625 +54983 0.12017822265625 +54984 0.116180419921875 +54985 0.092193603515625 +54986 -0.110748291015625 +54987 0.05474853515625 +54988 -0.381805419921875 +54989 0.006805419921875 +54990 -0.6572265625 +54991 -0.04510498046875 +54992 -0.857421875 +54993 -0.09185791015625 +54994 -0.870391845703125 +54995 -0.12689208984375 +54996 -0.870391845703125 +54997 -0.149078369140625 +54998 -0.86444091796875 +54999 -0.162445068359375 +55000 -0.85723876953125 +55001 -0.172393798828125 +55002 -0.790008544921875 +55003 -0.17608642578125 +55004 -0.62847900390625 +55005 -0.165252685546875 +55006 -0.3956298828125 +55007 -0.139373779296875 +55008 -0.126708984375 +55009 -0.1033935546875 +55010 0.150115966796875 +55011 -0.061431884765625 +55012 0.424041748046875 +55013 -0.015289306640625 +55014 0.670623779296875 +55015 0.0308837890625 +55016 0.854522705078125 +55017 0.07122802734375 +55018 0.866485595703125 +55019 0.10302734375 +55020 0.86920166015625 +55021 0.1239013671875 +55022 0.8653564453125 +55023 0.1365966796875 +55024 0.857147216796875 +55025 0.143157958984375 +55026 0.766845703125 +55027 0.14306640625 +55028 0.628509521484375 +55029 0.1370849609375 +55030 0.462127685546875 +55031 0.1241455078125 +55032 0.297210693359375 +55033 0.108123779296875 +55034 0.14862060546875 +55035 0.09088134765625 +55036 -0.00537109375 +55037 0.06890869140625 +55038 -0.15753173828125 +55039 0.043365478515625 +55040 -0.31304931640625 +55041 0.01416015625 +55042 -0.48876953125 +55043 -0.020721435546875 +55044 -0.6416015625 +55045 -0.05548095703125 +55046 -0.751373291015625 +55047 -0.08636474609375 +55048 -0.84619140625 +55049 -0.115478515625 +55050 -0.861297607421875 +55051 -0.1405029296875 +55052 -0.863250732421875 +55053 -0.1571044921875 +55054 -0.856597900390625 +55055 -0.161224365234375 +55056 -0.7498779296875 +55057 -0.15423583984375 +55058 -0.624542236328125 +55059 -0.143096923828125 +55060 -0.47808837890625 +55061 -0.125396728515625 +55062 -0.253387451171875 +55063 -0.094390869140625 +55064 0.003692626953125 +55065 -0.05596923828125 +55066 0.2257080078125 +55067 -0.018768310546875 +55068 0.427154541015625 +55069 0.01824951171875 +55070 0.643218994140625 +55071 0.058502197265625 +55072 0.855926513671875 +55073 0.100433349609375 +55074 0.870361328125 +55075 0.13665771484375 +55076 0.870361328125 +55077 0.16094970703125 +55078 0.862762451171875 +55079 0.1739501953125 +55080 0.79669189453125 +55081 0.17523193359375 +55082 0.595794677734375 +55083 0.16363525390625 +55084 0.362152099609375 +55085 0.1427001953125 +55086 0.1270751953125 +55087 0.115997314453125 +55088 -0.086944580078125 +55089 0.0863037109375 +55090 -0.2784423828125 +55091 0.05413818359375 +55092 -0.484832763671875 +55093 0.01568603515625 +55094 -0.729583740234375 +55095 -0.030975341796875 +55096 -0.86688232421875 +55097 -0.07940673828125 +55098 -0.870391845703125 +55099 -0.121673583984375 +55100 -0.86859130859375 +55101 -0.156829833984375 +55102 -0.86279296875 +55103 -0.18438720703125 +55104 -0.817962646484375 +55105 -0.199859619140625 +55106 -0.6116943359375 +55107 -0.197662353515625 +55108 -0.3128662109375 +55109 -0.176910400390625 +55110 0.039398193359375 +55111 -0.141693115234375 +55112 0.422821044921875 +55113 -0.09454345703125 +55114 0.805145263671875 +55115 -0.03961181640625 +55116 0.870361328125 +55117 0.014617919921875 +55118 0.870361328125 +55119 0.061065673828125 +55120 0.860015869140625 +55121 0.0980224609375 +55122 0.727935791015625 +55123 0.124267578125 +55124 0.48114013671875 +55125 0.1387939453125 +55126 0.2059326171875 +55127 0.144195556640625 +55128 -0.06103515625 +55129 0.142974853515625 +55130 -0.29913330078125 +55131 0.136138916015625 +55132 -0.516204833984375 +55133 0.121856689453125 +55134 -0.7252197265625 +55135 0.098236083984375 +55136 -0.85980224609375 +55137 0.0682373046875 +55138 -0.870391845703125 +55139 0.03607177734375 +55140 -0.870391845703125 +55141 0.005401611328125 +55142 -0.858062744140625 +55143 -0.01763916015625 +55144 -0.673004150390625 +55145 -0.03228759765625 +55146 -0.42694091796875 +55147 -0.04461669921875 +55148 -0.2100830078125 +55149 -0.05963134765625 +55150 -0.0362548828125 +55151 -0.07672119140625 +55152 0.10943603515625 +55153 -0.092132568359375 +55154 0.23516845703125 +55155 -0.10321044921875 +55156 0.373687744140625 +55157 -0.10479736328125 +55158 0.517791748046875 +55159 -0.097015380859375 +55160 0.602783203125 +55161 -0.08734130859375 +55162 0.635711669921875 +55163 -0.075164794921875 +55164 0.655181884765625 +55165 -0.056549072265625 +55166 0.65948486328125 +55167 -0.0328369140625 +55168 0.651275634765625 +55169 -0.005157470703125 +55170 0.61846923828125 +55171 0.023284912109375 +55172 0.53753662109375 +55173 0.047760009765625 +55174 0.404144287109375 +55175 0.065887451171875 +55176 0.22186279296875 +55177 0.07623291015625 +55178 0.003997802734375 +55179 0.07867431640625 +55180 -0.22100830078125 +55181 0.0751953125 +55182 -0.42449951171875 +55183 0.068084716796875 +55184 -0.579833984375 +55185 0.059783935546875 +55186 -0.641876220703125 +55187 0.055328369140625 +55188 -0.6177978515625 +55189 0.053924560546875 +55190 -0.575531005859375 +55191 0.0478515625 +55192 -0.526336669921875 +55193 0.03656005859375 +55194 -0.42645263671875 +55195 0.026397705078125 +55196 -0.2581787109375 +55197 0.02081298828125 +55198 -0.068695068359375 +55199 0.01568603515625 +55200 0.09222412109375 +55201 0.006622314453125 +55202 0.232147216796875 +55203 -0.003875732421875 +55204 0.3509521484375 +55205 -0.014373779296875 +55206 0.410064697265625 +55207 -0.0281982421875 +55208 0.372955322265625 +55209 -0.0487060546875 +55210 0.2554931640625 +55211 -0.073272705078125 +55212 0.10711669921875 +55213 -0.095550537109375 +55214 -0.052886962890625 +55215 -0.11309814453125 +55216 -0.186279296875 +55217 -0.12164306640625 +55218 -0.23291015625 +55219 -0.114532470703125 +55220 -0.209442138671875 +55221 -0.0946044921875 +55222 -0.174163818359375 +55223 -0.0699462890625 +55224 -0.126739501953125 +55225 -0.041748046875 +55226 -0.048126220703125 +55227 -0.009002685546875 +55228 0.0426025390625 +55229 0.024688720703125 +55230 0.10748291015625 +55231 0.053558349609375 +55232 0.1409912109375 +55233 0.075836181640625 +55234 0.19708251953125 +55235 0.097076416015625 +55236 0.273651123046875 +55237 0.1163330078125 +55238 0.31768798828125 +55239 0.126861572265625 +55240 0.341094970703125 +55241 0.12994384765625 +55242 0.368011474609375 +55243 0.128570556640625 +55244 0.37249755859375 +55245 0.120025634765625 +55246 0.30072021484375 +55247 0.098480224609375 +55248 0.1517333984375 +55249 0.06463623046875 +55250 -0.01470947265625 +55251 0.026641845703125 +55252 -0.1883544921875 +55253 -0.013214111328125 +55254 -0.372711181640625 +55255 -0.054290771484375 +55256 -0.51397705078125 +55257 -0.089080810546875 +55258 -0.57177734375 +55259 -0.11181640625 +55260 -0.53948974609375 +55261 -0.120880126953125 +55262 -0.43511962890625 +55263 -0.11785888671875 +55264 -0.2962646484375 +55265 -0.106842041015625 +55266 -0.161102294921875 +55267 -0.092193603515625 +55268 -0.0435791015625 +55269 -0.07562255859375 +55270 0.060394287109375 +55271 -0.056884765625 +55272 0.13665771484375 +55273 -0.03814697265625 +55274 0.170135498046875 +55275 -0.021820068359375 +55276 0.16552734375 +55277 -0.008056640625 +55278 0.15728759765625 +55279 0.006378173828125 +55280 0.150787353515625 +55281 0.021270751953125 +55282 0.12200927734375 +55283 0.03289794921875 +55284 0.080108642578125 +55285 0.04150390625 +55286 0.05126953125 +55287 0.049560546875 +55288 0.062896728515625 +55289 0.059783935546875 +55290 0.09271240234375 +55291 0.069091796875 +55292 0.092987060546875 +55293 0.071533203125 +55294 0.07855224609375 +55295 0.06884765625 +55296 0.06427001953125 +55297 0.0631103515625 +55298 0.0347900390625 +55299 0.052764892578125 +55300 -0.01171875 +55301 0.037933349609375 +55302 -0.056060791015625 +55303 0.02130126953125 +55304 -0.055511474609375 +55305 0.007965087890625 +55306 -0.010467529296875 +55307 -0.001251220703125 +55308 0.02508544921875 +55309 -0.01092529296875 +55310 0.025665283203125 +55311 -0.02288818359375 +55312 0.017333984375 +55313 -0.033905029296875 +55314 0.00189208984375 +55315 -0.043304443359375 +55316 -0.03173828125 +55317 -0.05181884765625 +55318 -0.071502685546875 +55319 -0.058074951171875 +55320 -0.13543701171875 +55321 -0.0638427734375 +55322 -0.219970703125 +55323 -0.06890869140625 +55324 -0.300506591796875 +55325 -0.071014404296875 +55326 -0.376312255859375 +55327 -0.070526123046875 +55328 -0.416107177734375 +55329 -0.064849853515625 +55330 -0.371124267578125 +55331 -0.049652099609375 +55332 -0.242279052734375 +55333 -0.025665283203125 +55334 -0.069732666015625 +55335 0.00244140625 +55336 0.125640869140625 +55337 0.031982421875 +55338 0.31268310546875 +55339 0.059356689453125 +55340 0.45501708984375 +55341 0.0804443359375 +55342 0.554779052734375 +55343 0.09515380859375 +55344 0.61065673828125 +55345 0.1031494140625 +55346 0.610931396484375 +55347 0.10321044921875 +55348 0.531463623046875 +55349 0.093017578125 +55350 0.3883056640625 +55351 0.0743408203125 +55352 0.23468017578125 +55353 0.05279541015625 +55354 0.095245361328125 +55355 0.031280517578125 +55356 -0.00396728515625 +55357 0.012847900390625 +55358 -0.04852294921875 +55359 -0.000579833984375 +55360 -0.055145263671875 +55361 -0.01019287109375 +55362 -0.0758056640625 +55363 -0.020660400390625 +55364 -0.138702392578125 +55365 -0.03436279296875 +55366 -0.209197998046875 +55367 -0.047454833984375 +55368 -0.289031982421875 +55369 -0.059844970703125 +55370 -0.37884521484375 +55371 -0.0714111328125 +55372 -0.456329345703125 +55373 -0.079833984375 +55374 -0.51641845703125 +55375 -0.084625244140625 +55376 -0.519287109375 +55377 -0.0819091796875 +55378 -0.458251953125 +55379 -0.07122802734375 +55380 -0.384796142578125 +55381 -0.05804443359375 +55382 -0.323699951171875 +55383 -0.045166015625 +55384 -0.269287109375 +55385 -0.032379150390625 +55386 -0.1951904296875 +55387 -0.017486572265625 +55388 -0.100006103515625 +55389 -0.00079345703125 +55390 -0.01055908203125 +55391 0.014617919921875 +55392 0.1033935546875 +55393 0.03143310546875 +55394 0.24908447265625 +55395 0.05010986328125 +55396 0.373199462890625 +55397 0.06512451171875 +55398 0.45806884765625 +55399 0.074615478515625 +55400 0.511474609375 +55401 0.079345703125 +55402 0.565399169921875 +55403 0.08258056640625 +55404 0.61138916015625 +55405 0.083648681640625 +55406 0.5897216796875 +55407 0.07684326171875 +55408 0.4906005859375 +55409 0.06146240234375 +55410 0.33148193359375 +55411 0.03955078125 +55412 0.147796630859375 +55413 0.0150146484375 +55414 -0.01873779296875 +55415 -0.00762939453125 +55416 -0.140289306640625 +55417 -0.0252685546875 +55418 -0.191986083984375 +55419 -0.035125732421875 +55420 -0.184295654296875 +55421 -0.03802490234375 +55422 -0.161834716796875 +55423 -0.03826904296875 +55424 -0.166595458984375 +55425 -0.0399169921875 +55426 -0.19390869140625 +55427 -0.04248046875 +55428 -0.22442626953125 +55429 -0.0440673828125 +55430 -0.279754638671875 +55431 -0.046966552734375 +55432 -0.3389892578125 +55433 -0.04925537109375 +55434 -0.3543701171875 +55435 -0.04638671875 +55436 -0.348175048828125 +55437 -0.040863037109375 +55438 -0.32598876953125 +55439 -0.033538818359375 +55440 -0.2581787109375 +55441 -0.021728515625 +55442 -0.139801025390625 +55443 -0.00518798828125 +55444 0.014617919921875 +55445 0.01434326171875 +55446 0.144378662109375 +55447 0.03057861328125 +55448 0.221038818359375 +55449 0.04052734375 +55450 0.27069091796875 +55451 0.04669189453125 +55452 0.294036865234375 +55453 0.049102783203125 +55454 0.311767578125 +55455 0.04986572265625 +55456 0.339141845703125 +55457 0.05059814453125 +55458 0.360260009765625 +55459 0.0496826171875 +55460 0.360504150390625 +55461 0.045867919921875 +55462 0.308380126953125 +55463 0.036651611328125 +55464 0.18170166015625 +55465 0.020416259765625 +55466 0.0047607421875 +55467 -0.000335693359375 +55468 -0.17559814453125 +55469 -0.021148681640625 +55470 -0.3143310546875 +55471 -0.037811279296875 +55472 -0.36785888671875 +55473 -0.0462646484375 +55474 -0.36248779296875 +55475 -0.04864501953125 +55476 -0.343536376953125 +55477 -0.04876708984375 +55478 -0.3018798828125 +55479 -0.0457763671875 +55480 -0.231414794921875 +55481 -0.039154052734375 +55482 -0.117645263671875 +55483 -0.027679443359375 +55484 0.007049560546875 +55485 -0.01434326171875 +55486 0.087982177734375 +55487 -0.00408935546875 +55488 0.13946533203125 +55489 0.004119873046875 +55490 0.17425537109375 +55491 0.01123046875 +55492 0.188201904296875 +55493 0.0166015625 +55494 0.171234130859375 +55495 0.019134521484375 +55496 0.118438720703125 +55497 0.0181884765625 +55498 0.05706787109375 +55499 0.0159912109375 +55500 -0.010711669921875 +55501 0.0125732421875 +55502 -0.0914306640625 +55503 0.0072021484375 +55504 -0.162322998046875 +55505 0.0018310546875 +55506 -0.194549560546875 +55507 -0.001007080078125 +55508 -0.1492919921875 +55509 0.002105712890625 +55510 -0.02166748046875 +55511 0.01165771484375 +55512 0.124053955078125 +55513 0.0220947265625 +55514 0.211151123046875 +55515 0.02679443359375 +55516 0.240447998046875 +55517 0.0260009765625 +55518 0.242218017578125 +55519 0.0225830078125 +55520 0.2257080078125 +55521 0.017578125 +55522 0.194366455078125 +55523 0.011505126953125 +55524 0.115509033203125 +55525 0.00164794921875 +55526 0.0128173828125 +55527 -0.009674072265625 +55528 -0.053802490234375 +55529 -0.017120361328125 +55530 -0.110626220703125 +55531 -0.02294921875 +55532 -0.199493408203125 +55533 -0.03082275390625 +55534 -0.29437255859375 +55535 -0.038482666015625 +55536 -0.33221435546875 +55537 -0.0404052734375 +55538 -0.27972412109375 +55539 -0.033782958984375 +55540 -0.185333251953125 +55541 -0.02301025390625 +55542 -0.128204345703125 +55543 -0.01519775390625 +55544 -0.115692138671875 +55545 -0.011138916015625 +55546 -0.116455078125 +55547 -0.00823974609375 +55548 -0.105926513671875 +55549 -0.0045166015625 +55550 -0.053955078125 +55551 0.00250244140625 +55552 0.048797607421875 +55553 0.0133056640625 +55554 0.157318115234375 +55555 0.024169921875 +55556 0.212005615234375 +55557 0.0308837890625 +55558 0.218475341796875 +55559 0.033538818359375 +55560 0.23724365234375 +55561 0.035430908203125 +55562 0.30535888671875 +55563 0.03863525390625 +55564 0.38128662109375 +55565 0.0408935546875 +55566 0.404449462890625 +55567 0.039031982421875 +55568 0.3944091796875 +55569 0.034393310546875 +55570 0.3885498046875 +55571 0.02935791015625 +55572 0.362640380859375 +55573 0.022857666015625 +55574 0.27362060546875 +55575 0.012786865234375 +55576 0.11712646484375 +55577 -0.000762939453125 +55578 -0.054901123046875 +55579 -0.014617919921875 +55580 -0.19085693359375 +55581 -0.025665283203125 +55582 -0.28570556640625 +55583 -0.033447265625 +55584 -0.339263916015625 +55585 -0.037841796875 +55586 -0.3775634765625 +55587 -0.040283203125 +55588 -0.445709228515625 +55589 -0.043304443359375 +55590 -0.535064697265625 +55591 -0.046478271484375 +55592 -0.629058837890625 +55593 -0.04901123046875 +55594 -0.697601318359375 +55595 -0.04937744140625 +55596 -0.70391845703125 +55597 -0.045745849609375 +55598 -0.6424560546875 +55599 -0.038055419921875 +55600 -0.491241455078125 +55601 -0.025299072265625 +55602 -0.265716552734375 +55603 -0.00860595703125 +55604 -0.023712158203125 +55605 0.008544921875 +55606 0.201751708984375 +55607 0.02410888671875 +55608 0.375823974609375 +55609 0.0360107421875 +55610 0.485076904296875 +55611 0.04339599609375 +55612 0.56884765625 +55613 0.04840087890625 +55614 0.634765625 +55615 0.051483154296875 +55616 0.63763427734375 +55617 0.050201416015625 +55618 0.5660400390625 +55619 0.04400634765625 +55620 0.4720458984375 +55621 0.03594970703125 +55622 0.40692138671875 +55623 0.029083251953125 +55624 0.3778076171875 +55625 0.02398681640625 +55626 0.376953125 +55627 0.020416259765625 +55628 0.371978759765625 +55629 0.016754150390625 +55630 0.313140869140625 +55631 0.0103759765625 +55632 0.184417724609375 +55633 0.00054931640625 +55634 0.011199951171875 +55635 -0.011138916015625 +55636 -0.171051025390625 +55637 -0.0225830078125 +55638 -0.33740234375 +55639 -0.0323486328125 +55640 -0.47198486328125 +55641 -0.03955078125 +55642 -0.560394287109375 +55643 -0.043426513671875 +55644 -0.58056640625 +55645 -0.042816162109375 +55646 -0.54754638671875 +55647 -0.038665771484375 +55648 -0.508575439453125 +55649 -0.033843994140625 +55650 -0.459503173828125 +55651 -0.028228759765625 +55652 -0.394378662109375 +55653 -0.021636962890625 +55654 -0.35260009765625 +55655 -0.016387939453125 +55656 -0.31170654296875 +55657 -0.01141357421875 +55658 -0.197418212890625 +55659 -0.002685546875 +55660 -0.007965087890625 +55661 0.009735107421875 +55662 0.207489013671875 +55663 0.022979736328125 +55664 0.409210205078125 +55665 0.0347900390625 +55666 0.57208251953125 +55667 0.043731689453125 +55668 0.66595458984375 +55669 0.04815673828125 +55670 0.65875244140625 +55671 0.046356201171875 +55672 0.56744384765625 +55673 0.03936767578125 +55674 0.431396484375 +55675 0.029510498046875 +55676 0.29443359375 +55677 0.019378662109375 +55678 0.182464599609375 +55679 0.01055908203125 +55680 0.06365966796875 +55681 0.00140380859375 +55682 -0.075958251953125 +55683 -0.008697509765625 +55684 -0.189422607421875 +55685 -0.016998291015625 +55686 -0.271942138671875 +55687 -0.023101806640625 +55688 -0.342529296875 +55689 -0.02801513671875 +55690 -0.364166259765625 +55691 -0.0296630859375 +55692 -0.327239990234375 +55693 -0.027496337890625 +55694 -0.2769775390625 +55695 -0.024078369140625 +55696 -0.253692626953125 +55697 -0.021697998046875 +55698 -0.24365234375 +55699 -0.0196533203125 +55700 -0.1983642578125 +55701 -0.01531982421875 +55702 -0.116241455078125 +55703 -0.00872802734375 +55704 -0.036834716796875 +55705 -0.002197265625 +55706 0.034881591796875 +55707 0.00384521484375 +55708 0.09124755859375 +55709 0.008880615234375 +55710 0.10888671875 +55711 0.011474609375 +55712 0.125518798828125 +55713 0.013671875 +55714 0.15771484375 +55715 0.016357421875 +55716 0.17828369140625 +55717 0.0179443359375 +55718 0.17108154296875 +55719 0.01751708984375 +55720 0.129974365234375 +55721 0.014739990234375 +55722 0.082427978515625 +55723 0.011199951171875 +55724 0.027679443359375 +55725 0.0069580078125 +55726 -0.065643310546875 +55727 0.000335693359375 +55728 -0.15936279296875 +55729 -0.006439208984375 +55730 -0.21307373046875 +55731 -0.01104736328125 +55732 -0.234649658203125 +55733 -0.013824462890625 +55734 -0.2001953125 +55735 -0.01336669921875 +55736 -0.119171142578125 +55737 -0.010101318359375 +55738 -0.024749755859375 +55739 -0.005859375 +55740 0.085784912109375 +55741 -0.000396728515625 +55742 0.178131103515625 +55743 0.004302978515625 +55744 0.215576171875 +55745 0.0062255859375 +55746 0.211456298828125 +55747 0.006134033203125 +55748 0.17523193359375 +55749 0.00457763671875 +55750 0.128753662109375 +55751 0.002716064453125 +55752 0.1019287109375 +55753 0.002197265625 +55754 0.0743408203125 +55755 0.001800537109375 +55756 0.04327392578125 +55757 0.001312255859375 +55758 0.038177490234375 +55759 0.0023193359375 +55760 0.076263427734375 +55761 0.005706787109375 +55762 0.14105224609375 +55763 0.01043701171875 +55764 0.186431884765625 +55765 0.013885498046875 +55766 0.188812255859375 +55767 0.01470947265625 +55768 0.1390380859375 +55769 0.012359619140625 +55770 0.041778564453125 +55771 0.007080078125 +55772 -0.079437255859375 +55773 0.000213623046875 +55774 -0.219390869140625 +55775 -0.0079345703125 +55776 -0.367828369140625 +55777 -0.0167236328125 +55778 -0.494873046875 +55779 -0.02447509765625 +55780 -0.556243896484375 +55781 -0.028656005859375 +55782 -0.508697509765625 +55783 -0.026824951171875 +55784 -0.3756103515625 +55785 -0.020233154296875 +55786 -0.218902587890625 +55787 -0.012298583984375 +55788 -0.063751220703125 +55789 -0.004425048828125 +55790 0.091552734375 +55791 0.00347900390625 +55792 0.23602294921875 +55793 0.0108642578125 +55794 0.342987060546875 +55795 0.01629638671875 +55796 0.39520263671875 +55797 0.01885986328125 +55798 0.389373779296875 +55799 0.01837158203125 +55800 0.324249267578125 +55801 0.0147705078125 +55802 0.224090576171875 +55803 0.0093994140625 +55804 0.124267578125 +55805 0.004241943359375 +55806 0.037078857421875 +55807 -6.103515625e-05 +55808 -0.010101318359375 +55809 -0.00244140625 +55810 -0.019439697265625 +55811 -0.002838134765625 +55812 -0.022796630859375 +55813 -0.002410888671875 +55814 -0.001556396484375 +55815 -0.0009765625 +55816 0.056304931640625 +55817 0.001495361328125 +55818 0.106719970703125 +55819 0.0037841796875 +55820 0.096893310546875 +55821 0.004425048828125 +55822 0.042694091796875 +55823 0.003753662109375 +55824 -0.018035888671875 +55825 0.00262451171875 +55826 -0.07586669921875 +55827 0.001251220703125 +55828 -0.11944580078125 +55829 -3.0517578125e-05 +55830 -0.15972900390625 +55831 -0.001434326171875 +55832 -0.202606201171875 +55833 -0.003082275390625 +55834 -0.24859619140625 +55835 -0.0048828125 +55836 -0.30517578125 +55837 -0.006988525390625 +55838 -0.36212158203125 +55839 -0.00909423828125 +55840 -0.39141845703125 +55841 -0.010467529296875 +55842 -0.35528564453125 +55843 -0.01019287109375 +55844 -0.249969482421875 +55845 -0.00811767578125 +55846 -0.092864990234375 +55847 -0.004638671875 +55848 0.08905029296875 +55849 -0.000396728515625 +55850 0.2352294921875 +55851 0.00311279296875 +55852 0.318817138671875 +55853 0.0052490234375 +55854 0.358642578125 +55855 0.0064697265625 +55856 0.347747802734375 +55857 0.006561279296875 +55858 0.28564453125 +55859 0.005523681640625 +55860 0.223175048828125 +55861 0.004547119140625 +55862 0.196746826171875 +55863 0.00445556640625 +55864 0.179840087890625 +55865 0.004608154296875 +55866 0.155548095703125 +55867 0.00457763671875 +55868 0.151214599609375 +55869 0.00494384765625 +55870 0.156951904296875 +55871 0.005462646484375 +55872 0.13177490234375 +55873 0.005126953125 +55874 0.100799560546875 +55875 0.0045166015625 +55876 0.087127685546875 +55877 0.00421142578125 +55878 0.05487060546875 +55879 0.00335693359375 +55880 -0.009002685546875 +55881 0.001617431640625 +55882 -0.10400390625 +55883 -0.00091552734375 +55884 -0.229400634765625 +55885 -0.004241943359375 +55886 -0.35552978515625 +55887 -0.00762939453125 +55888 -0.441925048828125 +55889 -0.01007080078125 +55890 -0.473846435546875 +55891 -0.01116943359375 +55892 -0.464813232421875 +55893 -0.011260986328125 +55894 -0.419097900390625 +55895 -0.01043701171875 +55896 -0.334320068359375 +55897 -0.008636474609375 +55898 -0.227935791015625 +55899 -0.0062255859375 +55900 -0.12347412109375 +55901 -0.0037841796875 +55902 -0.02764892578125 +55903 -0.00146484375 +55904 0.077667236328125 +55905 0.001129150390625 +55906 0.2132568359375 +55907 0.004486083984375 +55908 0.38885498046875 +55909 0.00885009765625 +55910 0.582794189453125 +55911 0.013671875 +55912 0.734039306640625 +55913 0.017486572265625 +55914 0.800140380859375 +55915 0.01922607421875 +55916 0.7783203125 +55917 0.018829345703125 +55918 0.6651611328125 +55919 0.0162353515625 +55920 0.45965576171875 +55921 0.01141357421875 +55922 0.199188232421875 +55923 0.005279541015625 +55924 -0.050689697265625 +55925 -0.000579833984375 +55926 -0.23297119140625 +55927 -0.00482177734375 +55928 -0.33013916015625 +55929 -0.007049560546875 +55930 -0.368408203125 +55931 -0.00787353515625 +55932 -0.378936767578125 +55933 -0.008056640625 +55934 -0.376983642578125 +55935 -0.00799560546875 +55936 -0.37969970703125 +55937 -0.008087158203125 +55938 -0.391510009765625 +55939 -0.0084228515625 +55940 -0.385345458984375 +55941 -0.00836181640625 +55942 -0.3419189453125 +55943 -0.007415771484375 +55944 -0.28289794921875 +55945 -0.006103515625 +55946 -0.251617431640625 +55947 -0.00543212890625 +55948 -0.266143798828125 +55949 -0.005859375 +55950 -0.273345947265625 +55951 -0.006103515625 +55952 -0.216796875 +55953 -0.00482177734375 +55954 -0.128265380859375 +55955 -0.002777099609375 +55956 -0.068145751953125 +55957 -0.001373291015625 +55958 -0.0430908203125 +55959 -0.000762939453125 +55960 -0.024444580078125 +55961 -0.000274658203125 +55962 0.020721435546875 +55963 0.000823974609375 +55964 0.124481201171875 +55965 0.0032958984375 +55966 0.25787353515625 +55967 0.0064697265625 +55968 0.379119873046875 +55969 0.009307861328125 +55970 0.47991943359375 +55971 0.01165771484375 +55972 0.5281982421875 +55973 0.01275634765625 +55974 0.511138916015625 +55975 0.01226806640625 +55976 0.456207275390625 +55977 0.010894775390625 +55978 0.407470703125 +55979 0.009674072265625 +55980 0.383758544921875 +55981 0.009063720703125 +55982 0.35687255859375 +55983 0.008331298828125 +55984 0.31182861328125 +55985 0.007171630859375 +55986 0.250885009765625 +55987 0.005615234375 +55988 0.1654052734375 +55989 0.003509521484375 +55990 0.035247802734375 +55991 0.0003662109375 +55992 -0.142059326171875 +55993 -0.00384521484375 +55994 -0.33563232421875 +55995 -0.008392333984375 +55996 -0.5345458984375 +55997 -0.01300048828125 +55998 -0.72186279296875 +55999 -0.017303466796875 +56000 -0.836669921875 +56001 -0.019805908203125 +56002 -0.8326416015625 +56003 -0.019439697265625 +56004 -0.7296142578125 +56005 -0.016693115234375 +56006 -0.582550048828125 +56007 -0.012939453125 +56008 -0.440093994140625 +56009 -0.009368896484375 +56010 -0.324310302734375 +56011 -0.006500244140625 +56012 -0.20147705078125 +56013 -0.00347900390625 +56014 -0.044647216796875 +56015 0.00030517578125 +56016 0.103973388671875 +56017 0.003814697265625 +56018 0.202392578125 +56019 0.00604248046875 +56020 0.264495849609375 +56021 0.007354736328125 +56022 0.338897705078125 +56023 0.0089111328125 +56024 0.443817138671875 +56025 0.011138916015625 +56026 0.545074462890625 +56027 0.01324462890625 +56028 0.6173095703125 +56029 0.0146484375 +56030 0.6524658203125 +56031 0.01519775390625 +56032 0.66339111328125 +56033 0.015167236328125 +56034 0.6561279296875 +56035 0.0147705078125 +56036 0.606781005859375 +56037 0.013397216796875 +56038 0.501190185546875 +56039 0.010711669921875 +56040 0.352783203125 +56041 0.007080078125 +56042 0.176544189453125 +56043 0.002838134765625 +56044 -0.034820556640625 +56045 -0.002105712890625 +56046 -0.258209228515625 +56047 -0.0072021484375 +56048 -0.44244384765625 +56049 -0.011260986328125 +56050 -0.5753173828125 +56051 -0.0140380859375 +56052 -0.65203857421875 +56053 -0.01544189453125 +56054 -0.641632080078125 +56055 -0.014739990234375 +56056 -0.562164306640625 +56057 -0.012420654296875 +56058 -0.458038330078125 +56059 -0.00958251953125 +56060 -0.350555419921875 +56061 -0.0067138671875 +56062 -0.260528564453125 +56063 -0.00433349609375 +56064 -0.192108154296875 +56065 -0.002471923828125 +56066 -0.141937255859375 +56067 -0.00103759765625 +56068 -0.1021728515625 +56069 3.0517578125e-05 +56070 -0.062896728515625 +56071 0.000885009765625 +56072 -0.011932373046875 +56073 0.001708984375 +56074 0.062835693359375 +56075 0.002655029296875 +56076 0.148712158203125 +56077 0.003631591796875 +56078 0.241729736328125 +56079 0.00457763671875 +56080 0.34912109375 +56081 0.005584716796875 +56082 0.457305908203125 +56083 0.00653076171875 +56084 0.54388427734375 +56085 0.007232666015625 +56086 0.5728759765625 +56087 0.007415771484375 +56088 0.506591796875 +56089 0.006744384765625 +56090 0.351226806640625 +56091 0.0052490234375 +56092 0.146514892578125 +56093 0.003265380859375 +56094 -0.05523681640625 +56095 0.001220703125 +56096 -0.21624755859375 +56097 -0.00054931640625 +56098 -0.334930419921875 +56099 -0.001983642578125 +56100 -0.402984619140625 +56101 -0.00299072265625 +56102 -0.4412841796875 +56103 -0.00372314453125 +56104 -0.49578857421875 +56105 -0.0045166015625 +56106 -0.5601806640625 +56107 -0.005340576171875 +56108 -0.600738525390625 +56109 -0.00592041015625 +56110 -0.584228515625 +56111 -0.005950927734375 +56112 -0.47930908203125 +56113 -0.00518798828125 +56114 -0.27935791015625 +56115 -0.003570556640625 +56116 -0.0089111328125 +56117 -0.001312255859375 +56118 0.268798828125 +56119 0.00103759765625 +56120 0.482818603515625 +56121 0.002899169921875 +56122 0.60369873046875 +56123 0.004058837890625 +56124 0.650421142578125 +56125 0.004669189453125 +56126 0.66400146484375 +56127 0.005035400390625 +56128 0.6414794921875 +56129 0.005126953125 +56130 0.572540283203125 +56131 0.004852294921875 +56132 0.498138427734375 +56133 0.0045166015625 +56134 0.439453125 +56135 0.0042724609375 +56136 0.375518798828125 +56137 0.003936767578125 +56138 0.274505615234375 +56139 0.00323486328125 +56140 0.1087646484375 +56141 0.001953125 +56142 -0.099395751953125 +56143 0.000274658203125 +56144 -0.3182373046875 +56145 -0.00152587890625 +56146 -0.5489501953125 +56147 -0.00341796875 +56148 -0.7738037109375 +56149 -0.0052490234375 +56150 -0.86383056640625 +56151 -0.006622314453125 +56152 -0.870391845703125 +56153 -0.00726318359375 +56154 -0.86895751953125 +56155 -0.00732421875 +56156 -0.861053466796875 +56157 -0.006927490234375 +56158 -0.765869140625 +56159 -0.00592041015625 +56160 -0.5301513671875 +56161 -0.00421142578125 +56162 -0.214691162109375 +56163 -0.001861572265625 +56164 0.137359619140625 +56165 0.00079345703125 +56166 0.474822998046875 +56167 0.00335693359375 +56168 0.76239013671875 +56169 0.00555419921875 +56170 0.867462158203125 +56171 0.007171630859375 +56172 0.870361328125 +56173 0.008209228515625 +56174 0.86480712890625 +56175 0.008575439453125 +56176 0.831817626953125 +56177 0.00830078125 +56178 0.677581787109375 +56179 0.007598876953125 +56180 0.495880126953125 +56181 0.006561279296875 +56182 0.30767822265625 +56183 0.00531005859375 +56184 0.116180419921875 +56185 0.00390625 +56186 -0.110748291015625 +56187 0.0020751953125 +56188 -0.381805419921875 +56189 -0.000244140625 +56190 -0.6572265625 +56191 -0.002716064453125 +56192 -0.857421875 +56193 -0.004852294921875 +56194 -0.870391845703125 +56195 -0.00634765625 +56196 -0.870391845703125 +56197 -0.007171630859375 +56198 -0.86444091796875 +56199 -0.007537841796875 +56200 -0.85723876953125 +56201 -0.00775146484375 +56202 -0.790008544921875 +56203 -0.0076904296875 +56204 -0.62847900390625 +56205 -0.0069580078125 +56206 -0.3956298828125 +56207 -0.005523681640625 +56208 -0.126708984375 +56209 -0.003631591796875 +56210 0.150115966796875 +56211 -0.001495361328125 +56212 0.424041748046875 +56213 0.000762939453125 +56214 0.670623779296875 +56215 0.0029296875 +56216 0.854522705078125 +56217 0.00469970703125 +56218 0.866485595703125 +56219 0.005950927734375 +56220 0.86920166015625 +56221 0.006622314453125 +56222 0.8653564453125 +56223 0.00689697265625 +56224 0.857147216796875 +56225 0.006866455078125 +56226 0.766845703125 +56227 0.006561279296875 +56228 0.628509521484375 +56229 0.0059814453125 +56230 0.462127685546875 +56231 0.005126953125 +56232 0.297210693359375 +56233 0.004180908203125 +56234 0.14862060546875 +56235 0.00323486328125 +56236 -0.00537109375 +56237 0.002105712890625 +56238 -0.15753173828125 +56239 0.0008544921875 +56240 -0.31304931640625 +56241 -0.000518798828125 +56242 -0.48876953125 +56243 -0.002105712890625 +56244 -0.6416015625 +56245 -0.003570556640625 +56246 -0.751373291015625 +56247 -0.004730224609375 +56248 -0.84619140625 +56249 -0.00579833984375 +56250 -0.861297607421875 +56251 -0.00665283203125 +56252 -0.863250732421875 +56253 -0.007080078125 +56254 -0.856597900390625 +56255 -0.006805419921875 +56256 -0.7498779296875 +56257 -0.0059814453125 +56258 -0.624542236328125 +56259 -0.005096435546875 +56260 -0.47808837890625 +56261 -0.003997802734375 +56262 -0.253387451171875 +56263 -0.002227783203125 +56264 0.003692626953125 +56265 -0.000152587890625 +56266 0.2257080078125 +56267 0.00164794921875 +56268 0.427154541015625 +56269 0.003265380859375 +56270 0.643218994140625 +56271 0.004974365234375 +56272 0.855926513671875 +56273 0.0067138671875 +56274 0.870361328125 +56275 0.008087158203125 +56276 0.870361328125 +56277 0.00872802734375 +56278 0.862762451171875 +56279 0.008758544921875 +56280 0.79669189453125 +56281 0.0081787109375 +56282 0.595794677734375 +56283 0.0069580078125 +56284 0.362152099609375 +56285 0.005340576171875 +56286 0.1270751953125 +56287 0.003570556640625 +56288 -0.086944580078125 +56289 0.0018310546875 +56290 -0.2784423828125 +56291 0.0001220703125 +56292 -0.484832763671875 +56293 -0.00177001953125 +56294 -0.729583740234375 +56295 -0.004058837890625 +56296 -0.86688232421875 +56297 -0.006317138671875 +56298 -0.870391845703125 +56299 -0.00811767578125 +56300 -0.86859130859375 +56301 -0.009429931640625 +56302 -0.86279296875 +56303 -0.010284423828125 +56304 -0.817962646484375 +56305 -0.01043701171875 +56306 -0.6116943359375 +56307 -0.00958251953125 +56308 -0.3128662109375 +56309 -0.007659912109375 +56310 0.039398193359375 +56311 -0.004974365234375 +56312 0.422821044921875 +56313 -0.001739501953125 +56314 0.805145263671875 +56315 0.001708984375 +56316 0.870361328125 +56317 0.0048828125 +56318 0.870361328125 +56319 0.00732421875 +56320 0.860015869140625 +56321 0.0091552734375 +56322 0.727935791015625 +56323 0.0098876953125 +56324 0.48114013671875 +56325 0.0091552734375 +56326 0.2059326171875 +56327 0.00787353515625 +56328 -0.06103515625 +56329 0.006805419921875 +56330 -0.29913330078125 +56331 0.006103515625 +56332 -0.516204833984375 +56333 0.00494384765625 +56334 -0.7252197265625 +56335 0.00238037109375 +56336 -0.85980224609375 +56337 -0.00091552734375 +56338 -0.870391845703125 +56339 -0.003936767578125 +56340 -0.870391845703125 +56341 -0.005889892578125 +56342 -0.858062744140625 +56343 -0.005218505859375 +56344 -0.673004150390625 +56345 -0.0020751953125 +56346 -0.42694091796875 +56347 0.00103759765625 +56348 -0.2100830078125 +56349 0.00213623046875 +56350 -0.0362548828125 +56351 0.0010986328125 +56352 0.10943603515625 +56353 -0.0009765625 +56354 0.23516845703125 +56355 -0.003265380859375 +56356 0.373687744140625 +56357 -0.00408935546875 +56358 0.517791748046875 +56359 -0.00341796875 +56360 0.602783203125 +56361 -0.003631591796875 +56362 0.635711669921875 +56363 -0.004302978515625 +56364 0.655181884765625 +56365 -0.003814697265625 +56366 0.65948486328125 +56367 -0.002227783203125 +56368 0.651275634765625 +56369 0.000396728515625 +56370 0.61846923828125 +56371 0.0032958984375 +56372 0.53753662109375 +56373 0.00531005859375 +56374 0.404144287109375 +56375 0.005950927734375 +56376 0.22186279296875 +56377 0.005035400390625 +56378 0.003997802734375 +56379 0.00274658203125 +56380 -0.22100830078125 +56381 -9.1552734375e-05 +56382 -0.42449951171875 +56383 -0.002655029296875 +56384 -0.579833984375 +56385 -0.00421142578125 +56386 -0.641876220703125 +56387 -0.003173828125 +56388 -0.6177978515625 +56389 0.0 +56390 -0.575531005859375 +56391 0.00250244140625 +56392 -0.526336669921875 +56393 0.003875732421875 +56394 -0.42645263671875 +56395 0.00592041015625 +56396 -0.2581787109375 +56397 0.009490966796875 +56398 -0.068695068359375 +56399 0.01287841796875 +56400 0.09222412109375 +56401 0.014404296875 +56402 0.232147216796875 +56403 0.014617919921875 +56404 0.3509521484375 +56405 0.01385498046875 +56406 0.410064697265625 +56407 0.0108642578125 +56408 0.372955322265625 +56409 0.004486083984375 +56410 0.2554931640625 +56411 -0.004364013671875 +56412 0.10711669921875 +56413 -0.01348876953125 +56414 -0.052886962890625 +56415 -0.021942138671875 +56416 -0.186279296875 +56417 -0.028167724609375 +56418 -0.23291015625 +56419 -0.02972412109375 +56420 -0.209442138671875 +56421 -0.027374267578125 +56422 -0.174163818359375 +56423 -0.023529052734375 +56424 -0.126739501953125 +56425 -0.018341064453125 +56426 -0.048126220703125 +56427 -0.011260986328125 +56428 0.0426025390625 +56429 -0.003265380859375 +56430 0.10748291015625 +56431 0.00384521484375 +56432 0.1409912109375 +56433 0.00958251953125 +56434 0.19708251953125 +56435 0.015838623046875 +56436 0.273651123046875 +56437 0.0223388671875 +56438 0.31768798828125 +56439 0.026824951171875 +56440 0.341094970703125 +56441 0.029632568359375 +56442 0.368011474609375 +56443 0.03167724609375 +56444 0.37249755859375 +56445 0.031890869140625 +56446 0.30072021484375 +56447 0.02813720703125 +56448 0.1517333984375 +56449 0.020477294921875 +56450 -0.01470947265625 +56451 0.011383056640625 +56452 -0.1883544921875 +56453 0.001434326171875 +56454 -0.372711181640625 +56455 -0.009307861328125 +56456 -0.51397705078125 +56457 -0.018524169921875 +56458 -0.57177734375 +56459 -0.024383544921875 +56460 -0.53948974609375 +56461 -0.02642822265625 +56462 -0.43511962890625 +56463 -0.02520751953125 +56464 -0.2962646484375 +56465 -0.022064208984375 +56466 -0.161102294921875 +56467 -0.018402099609375 +56468 -0.0435791015625 +56469 -0.01470947265625 +56470 0.060394287109375 +56471 -0.01080322265625 +56472 0.13665771484375 +56473 -0.00726318359375 +56474 0.170135498046875 +56475 -0.004730224609375 +56476 0.16552734375 +56477 -0.00311279296875 +56478 0.15728759765625 +56479 -0.001129150390625 +56480 0.150787353515625 +56481 0.00128173828125 +56482 0.12200927734375 +56483 0.00299072265625 +56484 0.080108642578125 +56485 0.004180908203125 +56486 0.05126953125 +56487 0.005767822265625 +56488 0.062896728515625 +56489 0.008697509765625 +56490 0.09271240234375 +56491 0.011962890625 +56492 0.092987060546875 +56493 0.013519287109375 +56494 0.07855224609375 +56495 0.013916015625 +56496 0.06427001953125 +56497 0.013702392578125 +56498 0.0347900390625 +56499 0.01226806640625 +56500 -0.01171875 +56501 0.009552001953125 +56502 -0.056060791015625 +56503 0.006378173828125 +56504 -0.055511474609375 +56505 0.00457763671875 +56506 -0.010467529296875 +56507 0.004241943359375 +56508 0.02508544921875 +56509 0.003326416015625 +56510 0.025665283203125 +56511 0.000946044921875 +56512 0.017333984375 +56513 -0.001678466796875 +56514 0.00189208984375 +56515 -0.00433349609375 +56516 -0.03173828125 +56517 -0.00738525390625 +56518 -0.071502685546875 +56519 -0.010284423828125 +56520 -0.13543701171875 +56521 -0.013671875 +56522 -0.219970703125 +56523 -0.017364501953125 +56524 -0.300506591796875 +56525 -0.020355224609375 +56526 -0.376312255859375 +56527 -0.022674560546875 +56528 -0.416107177734375 +56529 -0.02313232421875 +56530 -0.371124267578125 +56531 -0.019866943359375 +56532 -0.242279052734375 +56533 -0.01300048828125 +56534 -0.069732666015625 +56535 -0.004241943359375 +56536 0.125640869140625 +56537 0.00543212890625 +56538 0.31268310546875 +56539 0.014678955078125 +56540 0.45501708984375 +56541 0.021942138671875 +56542 0.554779052734375 +56543 0.027252197265625 +56544 0.61065673828125 +56545 0.030487060546875 +56546 0.610931396484375 +56547 0.0311279296875 +56548 0.531463623046875 +56549 0.028228759765625 +56550 0.3883056640625 +56551 0.02239990234375 +56552 0.23468017578125 +56553 0.015777587890625 +56554 0.095245361328125 +56555 0.009429931640625 +56556 -0.00396728515625 +56557 0.004425048828125 +56558 -0.04852294921875 +56559 0.001373291015625 +56560 -0.055145263671875 +56561 -0.000274658203125 +56562 -0.0758056640625 +56563 -0.002532958984375 +56564 -0.138702392578125 +56565 -0.006439208984375 +56566 -0.209197998046875 +56567 -0.010528564453125 +56568 -0.289031982421875 +56569 -0.014801025390625 +56570 -0.37884521484375 +56571 -0.01922607421875 +56572 -0.456329345703125 +56573 -0.02288818359375 +56574 -0.51641845703125 +56575 -0.025543212890625 +56576 -0.519287109375 +56577 -0.025421142578125 +56578 -0.458251953125 +56579 -0.02227783203125 +56580 -0.384796142578125 +56581 -0.01861572265625 +56582 -0.323699951171875 +56583 -0.015655517578125 +56584 -0.269287109375 +56585 -0.0130615234375 +56586 -0.1951904296875 +56587 -0.009490966796875 +56588 -0.100006103515625 +56589 -0.0048828125 +56590 -0.01055908203125 +56591 -0.00054931640625 +56592 0.1033935546875 +56593 0.0050048828125 +56594 0.24908447265625 +56595 0.01214599609375 +56596 0.373199462890625 +56597 0.01824951171875 +56598 0.45806884765625 +56599 0.02239990234375 +56600 0.511474609375 +56601 0.024993896484375 +56602 0.565399169921875 +56603 0.02764892578125 +56604 0.61138916015625 +56605 0.029937744140625 +56606 0.5897216796875 +56607 0.028900146484375 +56608 0.4906005859375 +56609 0.0240478515625 +56610 0.33148193359375 +56611 0.016204833984375 +56612 0.147796630859375 +56613 0.00714111328125 +56614 -0.01873779296875 +56615 -0.001007080078125 +56616 -0.140289306640625 +56617 -0.006866455078125 +56618 -0.191986083984375 +56619 -0.00921630859375 +56620 -0.184295654296875 +56621 -0.008636474609375 +56622 -0.161834716796875 +56623 -0.00732421875 +56624 -0.166595458984375 +56625 -0.00738525390625 +56626 -0.19390869140625 +56627 -0.008575439453125 +56628 -0.22442626953125 +56629 -0.009979248046875 +56630 -0.279754638671875 +56631 -0.012664794921875 +56632 -0.3389892578125 +56633 -0.015594482421875 +56634 -0.3543701171875 +56635 -0.016387939453125 +56636 -0.348175048828125 +56637 -0.016143798828125 +56638 -0.32598876953125 +56639 -0.015106201171875 +56640 -0.2581787109375 +56641 -0.011810302734375 +56642 -0.139801025390625 +56643 -0.006011962890625 +56644 0.014617919921875 +56645 0.001556396484375 +56646 0.144378662109375 +56647 0.0078125 +56648 0.221038818359375 +56649 0.0113525390625 +56650 0.27069091796875 +56651 0.013519287109375 +56652 0.294036865234375 +56653 0.014373779296875 +56654 0.311767578125 +56655 0.014984130859375 +56656 0.339141845703125 +56657 0.01617431640625 +56658 0.360260009765625 +56659 0.0174560546875 +56660 0.360504150390625 +56661 0.01800537109375 +56662 0.308380126953125 +56663 0.015411376953125 +56664 0.18170166015625 +56665 0.0079345703125 +56666 0.0047607421875 +56667 -0.0028076171875 +56668 -0.17559814453125 +56669 -0.01361083984375 +56670 -0.3143310546875 +56671 -0.0213623046875 +56672 -0.36785888671875 +56673 -0.023101806640625 +56674 -0.36248779296875 +56675 -0.0208740234375 +56676 -0.343536376953125 +56677 -0.01800537109375 +56678 -0.3018798828125 +56679 -0.013946533203125 +56680 -0.231414794921875 +56681 -0.008270263671875 +56682 -0.117645263671875 +56683 0.0 +56684 0.007049560546875 +56685 0.008544921875 +56686 0.087982177734375 +56687 0.013458251953125 +56688 0.13946533203125 +56689 0.015869140625 +56690 0.17425537109375 +56691 0.01678466796875 +56692 0.188201904296875 +56693 0.016021728515625 +56694 0.171234130859375 +56695 0.012939453125 +56696 0.118438720703125 +56697 0.00732421875 +56698 0.05706787109375 +56699 0.001251220703125 +56700 -0.010711669921875 +56701 -0.005035400390625 +56702 -0.0914306640625 +56703 -0.011932373046875 +56704 -0.162322998046875 +56705 -0.01776123046875 +56706 -0.194549560546875 +56707 -0.02044677734375 +56708 -0.1492919921875 +56709 -0.01715087890625 +56710 -0.02166748046875 +56711 -0.007568359375 +56712 0.124053955078125 +56713 0.003631591796875 +56714 0.211151123046875 +56715 0.010833740234375 +56716 0.240447998046875 +56717 0.014068603515625 +56718 0.242218017578125 +56719 0.015472412109375 +56720 0.2257080078125 +56721 0.015625 +56722 0.194366455078125 +56723 0.01470947265625 +56724 0.115509033203125 +56725 0.010284423828125 +56726 0.0128173828125 +56727 0.0040283203125 +56728 -0.053802490234375 +56729 0.000152587890625 +56730 -0.110626220703125 +56731 -0.00323486328125 +56732 -0.199493408203125 +56733 -0.0091552734375 +56734 -0.29437255859375 +56735 -0.015777587890625 +56736 -0.33221435546875 +56737 -0.0185546875 +56738 -0.27972412109375 +56739 -0.015106201171875 +56740 -0.185333251953125 +56741 -0.008880615234375 +56742 -0.128204345703125 +56743 -0.005523681640625 +56744 -0.115692138671875 +56745 -0.005523681640625 +56746 -0.116455078125 +56747 -0.006591796875 +56748 -0.105926513671875 +56749 -0.00689697265625 +56750 -0.053955078125 +56751 -0.00421142578125 +56752 0.048797607421875 +56753 0.002166748046875 +56754 0.157318115234375 +56755 0.009033203125 +56756 0.212005615234375 +56757 0.012176513671875 +56758 0.218475341796875 +56759 0.012054443359375 +56760 0.23724365234375 +56761 0.013031005859375 +56762 0.30535888671875 +56763 0.017791748046875 +56764 0.38128662109375 +56765 0.0233154296875 +56766 0.404449462890625 +56767 0.025238037109375 +56768 0.3944091796875 +56769 0.024993896484375 +56770 0.3885498046875 +56771 0.025238037109375 +56772 0.362640380859375 +56773 0.024200439453125 +56774 0.27362060546875 +56775 0.018707275390625 +56776 0.11712646484375 +56777 0.00836181640625 +56778 -0.054901123046875 +56779 -0.003082275390625 +56780 -0.19085693359375 +56781 -0.011962890625 +56782 -0.28570556640625 +56783 -0.017974853515625 +56784 -0.339263916015625 +56785 -0.021148681640625 +56786 -0.3775634765625 +56787 -0.023406982421875 +56788 -0.445709228515625 +56789 -0.02801513671875 +56790 -0.535064697265625 +56791 -0.034332275390625 +56792 -0.629058837890625 +56793 -0.041168212890625 +56794 -0.697601318359375 +56795 -0.04632568359375 +56796 -0.70391845703125 +56797 -0.04718017578125 +56798 -0.6424560546875 +56799 -0.043304443359375 +56800 -0.491241455078125 +56801 -0.0330810546875 +56802 -0.265716552734375 +56803 -0.017578125 +56804 -0.023712158203125 +56805 -0.000946044921875 +56806 0.201751708984375 +56807 0.01446533203125 +56808 0.375823974609375 +56809 0.026214599609375 +56810 0.485076904296875 +56811 0.033355712890625 +56812 0.56884765625 +56813 0.03875732421875 +56814 0.634765625 +56815 0.04302978515625 +56816 0.63763427734375 +56817 0.04290771484375 +56818 0.5660400390625 +56819 0.03759765625 +56820 0.4720458984375 +56821 0.03082275390625 +56822 0.40692138671875 +56823 0.02630615234375 +56824 0.3778076171875 +56825 0.0245361328125 +56826 0.376953125 +56827 0.024932861328125 +56828 0.371978759765625 +56829 0.025146484375 +56830 0.313140869140625 +56831 0.021514892578125 +56832 0.184417724609375 +56833 0.01263427734375 +56834 0.011199951171875 +56835 6.103515625e-05 +56836 -0.171051025390625 +56837 -0.013336181640625 +56838 -0.33740234375 +56839 -0.025360107421875 +56840 -0.47198486328125 +56841 -0.03466796875 +56842 -0.560394287109375 +56843 -0.040069580078125 +56844 -0.58056640625 +56845 -0.03948974609375 +56846 -0.54754638671875 +56847 -0.03460693359375 +56848 -0.508575439453125 +56849 -0.030364990234375 +56850 -0.459503173828125 +56851 -0.026336669921875 +56852 -0.394378662109375 +56853 -0.02178955078125 +56854 -0.35260009765625 +56855 -0.0206298828125 +56856 -0.31170654296875 +56857 -0.02032470703125 +56858 -0.197418212890625 +56859 -0.012908935546875 +56860 -0.007965087890625 +56861 0.00201416015625 +56862 0.207489013671875 +56863 0.01959228515625 +56864 0.409210205078125 +56865 0.03594970703125 +56866 0.57208251953125 +56867 0.048736572265625 +56868 0.66595458984375 +56869 0.0550537109375 +56870 0.65875244140625 +56871 0.051727294921875 +56872 0.56744384765625 +56873 0.040618896484375 +56874 0.431396484375 +56875 0.025909423828125 +56876 0.29443359375 +56877 0.012176513671875 +56878 0.182464599609375 +56879 0.002044677734375 +56880 0.06365966796875 +56881 -0.00787353515625 +56882 -0.075958251953125 +56883 -0.01922607421875 +56884 -0.189422607421875 +56885 -0.027313232421875 +56886 -0.271942138671875 +56887 -0.03179931640625 +56888 -0.342529296875 +56889 -0.034912109375 +56890 -0.364166259765625 +56891 -0.0330810546875 +56892 -0.327239990234375 +56893 -0.0255126953125 +56894 -0.2769775390625 +56895 -0.01708984375 +56896 -0.253692626953125 +56897 -0.012176513671875 +56898 -0.24365234375 +56899 -0.00946044921875 +56900 -0.1983642578125 +56901 -0.00396728515625 +56902 -0.116241455078125 +56903 0.004425048828125 +56904 -0.036834716796875 +56905 0.01165771484375 +56906 0.034881591796875 +56907 0.01727294921875 +56908 0.09124755859375 +56909 0.020599365234375 +56910 0.10888671875 +56911 0.01934814453125 +56912 0.125518798828125 +56913 0.01763916015625 +56914 0.15771484375 +56915 0.01739501953125 +56916 0.17828369140625 +56917 0.0159912109375 +56918 0.17108154296875 +56919 0.011932373046875 +56920 0.129974365234375 +56921 0.0047607421875 +56922 0.082427978515625 +56923 -0.00250244140625 +56924 0.027679443359375 +56925 -0.009796142578125 +56926 -0.065643310546875 +56927 -0.02032470703125 +56928 -0.15936279296875 +56929 -0.03009033203125 +56930 -0.21307373046875 +56931 -0.034912109375 +56932 -0.234649658203125 +56933 -0.03570556640625 +56934 -0.2001953125 +56935 -0.03009033203125 +56936 -0.119171142578125 +56937 -0.0191650390625 +56938 -0.024749755859375 +56939 -0.00653076171875 +56940 0.085784912109375 +56941 0.007904052734375 +56942 0.178131103515625 +56943 0.0203857421875 +56944 0.215576171875 +56945 0.026947021484375 +56946 0.211456298828125 +56947 0.02886962890625 +56948 0.17523193359375 +56949 0.02703857421875 +56950 0.128753662109375 +56951 0.023651123046875 +56952 0.1019287109375 +56953 0.021697998046875 +56954 0.0743408203125 +56955 0.019073486328125 +56956 0.04327392578125 +56957 0.01544189453125 +56958 0.038177490234375 +56959 0.013916015625 +56960 0.076263427734375 +56961 0.016357421875 +56962 0.14105224609375 +56963 0.0211181640625 +56964 0.186431884765625 +56965 0.0235595703125 +56966 0.188812255859375 +56967 0.0213623046875 +56968 0.1390380859375 +56969 0.01373291015625 +56970 0.041778564453125 +56971 0.00128173828125 +56972 -0.079437255859375 +56973 -0.013397216796875 +56974 -0.219390869140625 +56975 -0.0296630859375 +56976 -0.367828369140625 +56977 -0.04632568359375 +56978 -0.494873046875 +56979 -0.06024169921875 +56980 -0.556243896484375 +56981 -0.066802978515625 +56982 -0.508697509765625 +56983 -0.061492919921875 +56984 -0.3756103515625 +56985 -0.046783447265625 +56986 -0.218902587890625 +56987 -0.029205322265625 +56988 -0.063751220703125 +56989 -0.011444091796875 +56990 0.091552734375 +56991 0.00653076171875 +56992 0.23602294921875 +56993 0.023468017578125 +56994 0.342987060546875 +56995 0.0364990234375 +56996 0.39520263671875 +56997 0.043731689453125 +56998 0.389373779296875 +56999 0.04473876953125 +57000 0.324249267578125 +57001 0.039306640625 +57002 0.224090576171875 +57003 0.029937744140625 +57004 0.124267578125 +57005 0.020233154296875 +57006 0.037078857421875 +57007 0.01141357421875 +57008 -0.010101318359375 +57009 0.00634765625 +57010 -0.019439697265625 +57011 0.00482177734375 +57012 -0.022796630859375 +57013 0.0035400390625 +57014 -0.001556396484375 +57015 0.0045166015625 +57016 0.056304931640625 +57017 0.009033203125 +57018 0.106719970703125 +57019 0.01263427734375 +57020 0.096893310546875 +57021 0.009918212890625 +57022 0.042694091796875 +57023 0.002655029296875 +57024 -0.018035888671875 +57025 -0.005126953125 +57026 -0.07586669921875 +57027 -0.012359619140625 +57028 -0.11944580078125 +57029 -0.017791748046875 +57030 -0.15972900390625 +57031 -0.022552490234375 +57032 -0.202606201171875 +57033 -0.0272216796875 +57034 -0.24859619140625 +57035 -0.03179931640625 +57036 -0.30517578125 +57037 -0.037109375 +57038 -0.36212158203125 +57039 -0.042144775390625 +57040 -0.39141845703125 +57041 -0.0440673828125 +57042 -0.35528564453125 +57043 -0.03900146484375 +57044 -0.249969482421875 +57045 -0.026641845703125 +57046 -0.092864990234375 +57047 -0.008880615234375 +57048 0.08905029296875 +57049 0.011383056640625 +57050 0.2352294921875 +57051 0.02777099609375 +57052 0.318817138671875 +57053 0.03741455078125 +57054 0.358642578125 +57055 0.042236328125 +57056 0.347747802734375 +57057 0.041473388671875 +57058 0.28564453125 +57059 0.03509521484375 +57060 0.223175048828125 +57061 0.02838134765625 +57062 0.196746826171875 +57063 0.025115966796875 +57064 0.179840087890625 +57065 0.0225830078125 +57066 0.155548095703125 +57067 0.01910400390625 +57068 0.151214599609375 +57069 0.017547607421875 +57070 0.156951904296875 +57071 0.0169677734375 +57072 0.13177490234375 +57073 0.013153076171875 +57074 0.100799560546875 +57075 0.008819580078125 +57076 0.087127685546875 +57077 0.00640869140625 +57078 0.05487060546875 +57079 0.002227783203125 +57080 -0.009002685546875 +57081 -0.0050048828125 +57082 -0.10400390625 +57083 -0.01519775390625 +57084 -0.229400634765625 +57085 -0.02825927734375 +57086 -0.35552978515625 +57087 -0.0411376953125 +57088 -0.441925048828125 +57089 -0.049835205078125 +57090 -0.473846435546875 +57091 -0.05316162109375 +57092 -0.464813232421875 +57093 -0.052703857421875 +57094 -0.419097900390625 +57095 -0.048492431640625 +57096 -0.334320068359375 +57097 -0.039703369140625 +57098 -0.227935791015625 +57099 -0.02825927734375 +57100 -0.12347412109375 +57101 -0.01702880859375 +57102 -0.02764892578125 +57103 -0.006683349609375 +57104 0.077667236328125 +57105 0.00543212890625 +57106 0.2132568359375 +57107 0.022247314453125 +57108 0.38885498046875 +57109 0.045166015625 +57110 0.582794189453125 +57111 0.071258544921875 +57112 0.734039306640625 +57113 0.0921630859375 +57114 0.800140380859375 +57115 0.102020263671875 +57116 0.7783203125 +57117 0.100372314453125 +57118 0.6651611328125 +57119 0.086639404296875 +57120 0.45965576171875 +57121 0.06060791015625 +57122 0.199188232421875 +57123 0.027191162109375 +57124 -0.050689697265625 +57125 -0.004791259765625 +57126 -0.23297119140625 +57127 -0.027740478515625 +57128 -0.33013916015625 +57129 -0.039337158203125 +57130 -0.368408203125 +57131 -0.04327392578125 +57132 -0.378936767578125 +57133 -0.0438232421875 +57134 -0.376983642578125 +57135 -0.04315185546875 +57136 -0.37969970703125 +57137 -0.043548583984375 +57138 -0.391510009765625 +57139 -0.045623779296875 +57140 -0.385345458984375 +57141 -0.045623779296875 +57142 -0.3419189453125 +57143 -0.0408935546875 +57144 -0.28289794921875 +57145 -0.0343017578125 +57146 -0.251617431640625 +57147 -0.031646728515625 +57148 -0.266143798828125 +57149 -0.0352783203125 +57150 -0.273345947265625 +57151 -0.03790283203125 +57152 -0.216796875 +57153 -0.03173828125 +57154 -0.128265380859375 +57155 -0.021026611328125 +57156 -0.068145751953125 +57157 -0.01385498046875 +57158 -0.0430908203125 +57159 -0.0111083984375 +57160 -0.024444580078125 +57161 -0.0089111328125 +57162 0.020721435546875 +57163 -0.00274658203125 +57164 0.124481201171875 +57165 0.011688232421875 +57166 0.25787353515625 +57167 0.030426025390625 +57168 0.379119873046875 +57169 0.0477294921875 +57170 0.47991943359375 +57171 0.06243896484375 +57172 0.5281982421875 +57173 0.07012939453125 +57174 0.511138916015625 +57175 0.069000244140625 +57176 0.456207275390625 +57177 0.06268310546875 +57178 0.407470703125 +57179 0.05712890625 +57180 0.383758544921875 +57181 0.054840087890625 +57182 0.35687255859375 +57183 0.051910400390625 +57184 0.31182861328125 +57185 0.046295166015625 +57186 0.250885009765625 +57187 0.038299560546875 +57188 0.1654052734375 +57189 0.0267333984375 +57190 0.035247802734375 +57191 0.008880615234375 +57192 -0.142059326171875 +57193 -0.01556396484375 +57194 -0.33563232421875 +57195 -0.042388916015625 +57196 -0.5345458984375 +57197 -0.070068359375 +57198 -0.72186279296875 +57199 -0.09625244140625 +57200 -0.836669921875 +57201 -0.11260986328125 +57202 -0.8326416015625 +57203 -0.11279296875 +57204 -0.7296142578125 +57205 -0.099456787109375 +57206 -0.582550048828125 +57207 -0.080108642578125 +57208 -0.440093994140625 +57209 -0.061309814453125 +57210 -0.324310302734375 +57211 -0.0460205078125 +57212 -0.20147705078125 +57213 -0.02960205078125 +57214 -0.044647216796875 +57215 -0.008392333984375 +57216 0.103973388671875 +57217 0.0118408203125 +57218 0.202392578125 +57219 0.025390625 +57220 0.264495849609375 +57221 0.03411865234375 +57222 0.338897705078125 +57223 0.044586181640625 +57224 0.443817138671875 +57225 0.05926513671875 +57226 0.545074462890625 +57227 0.073486328125 +57228 0.6173095703125 +57229 0.083770751953125 +57230 0.6524658203125 +57231 0.089019775390625 +57232 0.66339111328125 +57233 0.0909423828125 +57234 0.6561279296875 +57235 0.09033203125 +57236 0.606781005859375 +57237 0.083892822265625 +57238 0.501190185546875 +57239 0.0697021484375 +57240 0.352783203125 +57241 0.049591064453125 +57242 0.176544189453125 +57243 0.025604248046875 +57244 -0.034820556640625 +57245 -0.003204345703125 +57246 -0.258209228515625 +57247 -0.03369140625 +57248 -0.44244384765625 +57249 -0.05889892578125 +57250 -0.5753173828125 +57251 -0.0771484375 +57252 -0.65203857421875 +57253 -0.087799072265625 +57254 -0.641632080078125 +57255 -0.08660888671875 +57256 -0.562164306640625 +57257 -0.0760498046875 +57258 -0.458038330078125 +57259 -0.062164306640625 +57260 -0.350555419921875 +57261 -0.047821044921875 +57262 -0.260528564453125 +57263 -0.035797119140625 +57264 -0.192108154296875 +57265 -0.026641845703125 +57266 -0.141937255859375 +57267 -0.019927978515625 +57268 -0.1021728515625 +57269 -0.01458740234375 +57270 -0.062896728515625 +57271 -0.00921630859375 +57272 -0.011932373046875 +57273 -0.002197265625 +57274 0.062835693359375 +57275 0.008087158203125 +57276 0.148712158203125 +57277 0.0198974609375 +57278 0.241729736328125 +57279 0.032684326171875 +57280 0.34912109375 +57281 0.047454833984375 +57282 0.457305908203125 +57283 0.06231689453125 +57284 0.54388427734375 +57285 0.074249267578125 +57286 0.5728759765625 +57287 0.07830810546875 +57288 0.506591796875 +57289 0.06939697265625 +57290 0.351226806640625 +57291 0.048370361328125 +57292 0.146514892578125 +57293 0.020599365234375 +57294 -0.05523681640625 +57295 -0.00677490234375 +57296 -0.21624755859375 +57297 -0.02862548828125 +57298 -0.334930419921875 +57299 -0.04473876953125 +57300 -0.402984619140625 +57301 -0.053985595703125 +57302 -0.4412841796875 +57303 -0.0592041015625 +57304 -0.49578857421875 +57305 -0.066650390625 +57306 -0.5601806640625 +57307 -0.075439453125 +57308 -0.600738525390625 +57309 -0.081024169921875 +57310 -0.584228515625 +57311 -0.078857421875 +57312 -0.47930908203125 +57313 -0.064666748046875 +57314 -0.27935791015625 +57315 -0.037567138671875 +57316 -0.0089111328125 +57317 -0.0008544921875 +57318 0.268798828125 +57319 0.036834716796875 +57320 0.482818603515625 +57321 0.065826416015625 +57322 0.60369873046875 +57323 0.082122802734375 +57324 0.650421142578125 +57325 0.08831787109375 +57326 0.66400146484375 +57327 0.09002685546875 +57328 0.6414794921875 +57329 0.08685302734375 +57330 0.572540283203125 +57331 0.077392578125 +57332 0.498138427734375 +57333 0.067230224609375 +57334 0.439453125 +57335 0.059234619140625 +57336 0.375518798828125 +57337 0.050567626953125 +57338 0.274505615234375 +57339 0.036895751953125 +57340 0.1087646484375 +57341 0.01446533203125 +57342 -0.099395751953125 +57343 -0.013671875 +57344 -0.3182373046875 +57345 -0.04376220703125 +57346 -0.5489501953125 +57347 -0.0767822265625 +57348 -0.7738037109375 +57349 -0.110107421875 +57350 -0.86383056640625 +57351 -0.135009765625 +57352 -0.870391845703125 +57353 -0.14599609375 +57354 -0.86895751953125 +57355 -0.146026611328125 +57356 -0.861053466796875 +57357 -0.137237548828125 +57358 -0.765869140625 +57359 -0.116546630859375 +57360 -0.5301513671875 +57361 -0.08184814453125 +57362 -0.214691162109375 +57363 -0.034027099609375 +57364 0.137359619140625 +57365 0.019927978515625 +57366 0.474822998046875 +57367 0.07171630859375 +57368 0.76239013671875 +57369 0.115692138671875 +57370 0.867462158203125 +57371 0.147613525390625 +57372 0.870361328125 +57373 0.167816162109375 +57374 0.86480712890625 +57375 0.174560546875 +57376 0.831817626953125 +57377 0.16888427734375 +57378 0.677581787109375 +57379 0.154998779296875 +57380 0.495880126953125 +57381 0.1339111328125 +57382 0.30767822265625 +57383 0.108734130859375 +57384 0.116180419921875 +57385 0.0797119140625 +57386 -0.110748291015625 +57387 0.0413818359375 +57388 -0.381805419921875 +57389 -0.007598876953125 +57390 -0.6572265625 +57391 -0.060272216796875 +57392 -0.857421875 +57393 -0.106781005859375 +57394 -0.870391845703125 +57395 -0.14019775390625 +57396 -0.870391845703125 +57397 -0.159576416015625 +57398 -0.86444091796875 +57399 -0.169677734375 +57400 -0.85723876953125 +57401 -0.176666259765625 +57402 -0.790008544921875 +57403 -0.1776123046875 +57404 -0.62847900390625 +57405 -0.16351318359375 +57406 -0.3956298828125 +57407 -0.133880615234375 +57408 -0.126708984375 +57409 -0.094207763671875 +57410 0.150115966796875 +57411 -0.049041748046875 +57412 0.424041748046875 +57413 -0.000244140625 +57414 0.670623779296875 +57415 0.047760009765625 +57416 0.854522705078125 +57417 0.088653564453125 +57418 0.866485595703125 +57419 0.119659423828125 +57420 0.86920166015625 +57421 0.138427734375 +57422 0.8653564453125 +57423 0.148193359375 +57424 0.857147216796875 +57425 0.151397705078125 +57426 0.766845703125 +57427 0.147735595703125 +57428 0.628509521484375 +57429 0.13824462890625 +57430 0.462127685546875 +57431 0.12188720703125 +57432 0.297210693359375 +57433 0.10302734375 +57434 0.14862060546875 +57435 0.083709716796875 +57436 -0.00537109375 +57437 0.06011962890625 +57438 -0.15753173828125 +57439 0.033416748046875 +57440 -0.31304931640625 +57441 0.0029296875 +57442 -0.48876953125 +57443 -0.033843994140625 +57444 -0.6416015625 +57445 -0.069183349609375 +57446 -0.751373291015625 +57447 -0.099090576171875 +57448 -0.84619140625 +57449 -0.127593994140625 +57450 -0.861297607421875 +57451 -0.152374267578125 +57452 -0.863250732421875 +57453 -0.168060302734375 +57454 -0.856597900390625 +57455 -0.16943359375 +57456 -0.7498779296875 +57457 -0.158660888671875 +57458 -0.624542236328125 +57459 -0.1455078125 +57460 -0.47808837890625 +57461 -0.1263427734375 +57462 -0.253387451171875 +57463 -0.091339111328125 +57464 0.003692626953125 +57465 -0.048126220703125 +57466 0.2257080078125 +57467 -0.00811767578125 +57468 0.427154541015625 +57469 0.030853271484375 +57470 0.643218994140625 +57471 0.0743408203125 +57472 0.855926513671875 +57473 0.120849609375 +57474 0.870361328125 +57475 0.160797119140625 +57476 0.870361328125 +57477 0.18603515625 +57478 0.862762451171875 +57479 0.1978759765625 +57480 0.79669189453125 +57481 0.195953369140625 +57482 0.595794677734375 +57483 0.178802490234375 +57484 0.362152099609375 +57485 0.151397705078125 +57486 0.1270751953125 +57487 0.118499755859375 +57488 -0.086944580078125 +57489 0.083648681640625 +57490 -0.2784423828125 +57491 0.047210693359375 +57492 -0.484832763671875 +57493 0.003265380859375 +57494 -0.729583740234375 +57495 -0.051422119140625 +57496 -0.86688232421875 +57497 -0.10845947265625 +57498 -0.870391845703125 +57499 -0.157318115234375 +57500 -0.86859130859375 +57501 -0.197265625 +57502 -0.86279296875 +57503 -0.228057861328125 +57504 -0.817962646484375 +57505 -0.243804931640625 +57506 -0.6116943359375 +57507 -0.236968994140625 +57508 -0.3128662109375 +57509 -0.2064208984375 +57510 0.039398193359375 +57511 -0.157928466796875 +57512 0.422821044921875 +57513 -0.094879150390625 +57514 0.805145263671875 +57515 -0.022918701171875 +57516 0.870361328125 +57517 0.046478271484375 +57518 0.870361328125 +57519 0.103759765625 +57520 0.860015869140625 +57521 0.14697265625 +57522 0.727935791015625 +57523 0.17486572265625 +57524 0.48114013671875 +57525 0.186553955078125 +57526 0.2059326171875 +57527 0.186187744140625 +57528 -0.06103515625 +57529 0.1776123046875 +57530 -0.29913330078125 +57531 0.16259765625 +57532 -0.516204833984375 +57533 0.1387939453125 +57534 -0.7252197265625 +57535 0.103729248046875 +57536 -0.85980224609375 +57537 0.0616455078125 +57538 -0.870391845703125 +57539 0.01837158203125 +57540 -0.870391845703125 +57541 -0.021026611328125 +57542 -0.858062744140625 +57543 -0.048309326171875 +57544 -0.673004150390625 +57545 -0.062713623046875 +57546 -0.42694091796875 +57547 -0.07305908203125 +57548 -0.2100830078125 +57549 -0.086761474609375 +57550 -0.0362548828125 +57551 -0.103424072265625 +57552 0.10943603515625 +57553 -0.118194580078125 +57554 0.23516845703125 +57555 -0.127685546875 +57556 0.373687744140625 +57557 -0.125 +57558 0.517791748046875 +57559 -0.110504150390625 +57560 0.602783203125 +57561 -0.0948486328125 +57562 0.635711669921875 +57563 -0.0772705078125 +57564 0.655181884765625 +57565 -0.05224609375 +57566 0.65948486328125 +57567 -0.02154541015625 +57568 0.651275634765625 +57569 0.013397216796875 +57570 0.61846923828125 +57571 0.048370361328125 +57572 0.53753662109375 +57573 0.07708740234375 +57574 0.404144287109375 +57575 0.096466064453125 +57576 0.22186279296875 +57577 0.1048583984375 +57578 0.003997802734375 +57579 0.102508544921875 +57580 -0.22100830078125 +57581 0.092437744140625 +57582 -0.42449951171875 +57583 0.078125 +57584 -0.579833984375 +57585 0.063201904296875 +57586 -0.641876220703125 +57587 0.05487060546875 +57588 -0.6177978515625 +57589 0.05206298828125 +57590 -0.575531005859375 +57591 0.04400634765625 +57592 -0.526336669921875 +57593 0.029876708984375 +57594 -0.42645263671875 +57595 0.0184326171875 +57596 -0.2581787109375 +57597 0.01434326171875 +57598 -0.068695068359375 +57599 0.011566162109375 +57600 0.09222412109375 +57601 0.00421142578125 +57602 0.232147216796875 +57603 -0.003936767578125 +57604 0.3509521484375 +57605 -0.01165771484375 +57606 0.410064697265625 +57607 -0.025390625 +57608 0.372955322265625 +57609 -0.05145263671875 +57610 0.2554931640625 +57611 -0.086029052734375 +57612 0.10711669921875 +57613 -0.118988037109375 +57614 -0.052886962890625 +57615 -0.146575927734375 +57616 -0.186279296875 +57617 -0.161651611328125 +57618 -0.23291015625 +57619 -0.153076171875 +57620 -0.209442138671875 +57621 -0.125335693359375 +57622 -0.174163818359375 +57623 -0.091461181640625 +57624 -0.126739501953125 +57625 -0.05291748046875 +57626 -0.048126220703125 +57627 -0.007568359375 +57628 0.0426025390625 +57629 0.039154052734375 +57630 0.10748291015625 +57631 0.078155517578125 +57632 0.1409912109375 +57633 0.10699462890625 +57634 0.19708251953125 +57635 0.1353759765625 +57636 0.273651123046875 +57637 0.162109375 +57638 0.31768798828125 +57639 0.1761474609375 +57640 0.341094970703125 +57641 0.179779052734375 +57642 0.368011474609375 +57643 0.178070068359375 +57644 0.37249755859375 +57645 0.1663818359375 +57646 0.30072021484375 +57647 0.134796142578125 +57648 0.1517333984375 +57649 0.084197998046875 +57650 -0.01470947265625 +57651 0.027801513671875 +57652 -0.1883544921875 +57653 -0.031005859375 +57654 -0.372711181640625 +57655 -0.091583251953125 +57656 -0.51397705078125 +57657 -0.14190673828125 +57658 -0.57177734375 +57659 -0.172760009765625 +57660 -0.53948974609375 +57661 -0.18182373046875 +57662 -0.43511962890625 +57663 -0.171966552734375 +57664 -0.2962646484375 +57665 -0.150238037109375 +57666 -0.161102294921875 +57667 -0.12408447265625 +57668 -0.0435791015625 +57669 -0.096405029296875 +57670 0.060394287109375 +57671 -0.0667724609375 +57672 0.13665771484375 +57673 -0.038604736328125 +57674 0.170135498046875 +57675 -0.0157470703125 +57676 0.16552734375 +57677 0.001739501953125 +57678 0.15728759765625 +57679 0.019683837890625 +57680 0.150787353515625 +57681 0.038055419921875 +57682 0.12200927734375 +57683 0.05096435546875 +57684 0.080108642578125 +57685 0.05926513671875 +57686 0.05126953125 +57687 0.06732177734375 +57688 0.062896728515625 +57689 0.0799560546875 +57690 0.09271240234375 +57691 0.092254638671875 +57692 0.092987060546875 +57693 0.094451904296875 +57694 0.07855224609375 +57695 0.089508056640625 +57696 0.06427001953125 +57697 0.080657958984375 +57698 0.0347900390625 +57699 0.06524658203125 +57700 -0.01171875 +57701 0.04351806640625 +57702 -0.056060791015625 +57703 0.02008056640625 +57704 -0.055511474609375 +57705 0.004364013671875 +57706 -0.010467529296875 +57707 -0.0028076171875 +57708 0.02508544921875 +57709 -0.0113525390625 +57710 0.025665283203125 +57711 -0.025543212890625 +57712 0.017333984375 +57713 -0.0394287109375 +57714 0.00189208984375 +57715 -0.052001953125 +57716 -0.03173828125 +57717 -0.0650634765625 +57718 -0.071502685546875 +57719 -0.075958251953125 +57720 -0.13543701171875 +57721 -0.088226318359375 +57722 -0.219970703125 +57723 -0.10125732421875 +57724 -0.300506591796875 +57725 -0.110443115234375 +57726 -0.376312255859375 +57727 -0.1160888671875 +57728 -0.416107177734375 +57729 -0.112548828125 +57730 -0.371124267578125 +57731 -0.09075927734375 +57732 -0.242279052734375 +57733 -0.051666259765625 +57734 -0.069732666015625 +57735 -0.0040283203125 +57736 0.125640869140625 +57737 0.0472412109375 +57738 0.31268310546875 +57739 0.095306396484375 +57740 0.45501708984375 +57741 0.13232421875 +57742 0.554779052734375 +57743 0.158294677734375 +57744 0.61065673828125 +57745 0.1727294921875 +57746 0.610931396484375 +57747 0.173187255859375 +57748 0.531463623046875 +57749 0.1549072265625 +57750 0.3883056640625 +57751 0.121337890625 +57752 0.23468017578125 +57753 0.083465576171875 +57754 0.095245361328125 +57755 0.046661376953125 +57756 -0.00396728515625 +57757 0.01666259765625 +57758 -0.04852294921875 +57759 -0.0030517578125 +57760 -0.055145263671875 +57761 -0.01519775390625 +57762 -0.0758056640625 +57763 -0.02960205078125 +57764 -0.138702392578125 +57765 -0.051361083984375 +57766 -0.209197998046875 +57767 -0.07305908203125 +57768 -0.289031982421875 +57769 -0.094696044921875 +57770 -0.37884521484375 +57771 -0.116119384765625 +57772 -0.456329345703125 +57773 -0.132720947265625 +57774 -0.51641845703125 +57775 -0.1435546875 +57776 -0.519287109375 +57777 -0.140777587890625 +57778 -0.458251953125 +57779 -0.123291015625 +57780 -0.384796142578125 +57781 -0.101715087890625 +57782 -0.323699951171875 +57783 -0.0814208984375 +57784 -0.269287109375 +57785 -0.061737060546875 +57786 -0.1951904296875 +57787 -0.03790283203125 +57788 -0.100006103515625 +57789 -0.0101318359375 +57790 -0.01055908203125 +57791 0.015716552734375 +57792 0.1033935546875 +57793 0.045257568359375 +57794 0.24908447265625 +57795 0.079620361328125 +57796 0.373199462890625 +57797 0.107879638671875 +57798 0.45806884765625 +57799 0.126373291015625 +57800 0.511474609375 +57801 0.136627197265625 +57802 0.565399169921875 +57803 0.1451416015625 +57804 0.61138916015625 +57805 0.150360107421875 +57806 0.5897216796875 +57807 0.140625 +57808 0.4906005859375 +57809 0.11431884765625 +57810 0.33148193359375 +57811 0.0753173828125 +57812 0.147796630859375 +57813 0.0311279296875 +57814 -0.01873779296875 +57815 -0.009490966796875 +57816 -0.140289306640625 +57817 -0.040557861328125 +57818 -0.191986083984375 +57819 -0.056732177734375 +57820 -0.184295654296875 +57821 -0.059844970703125 +57822 -0.161834716796875 +57823 -0.05859375 +57824 -0.166595458984375 +57825 -0.061248779296875 +57826 -0.19390869140625 +57827 -0.066802978515625 +57828 -0.22442626953125 +57829 -0.071441650390625 +57830 -0.279754638671875 +57831 -0.079620361328125 +57832 -0.3389892578125 +57833 -0.08734130859375 +57834 -0.3543701171875 +57835 -0.0853271484375 +57836 -0.348175048828125 +57837 -0.078338623046875 +57838 -0.32598876953125 +57839 -0.06781005859375 +57840 -0.2581787109375 +57841 -0.048187255859375 +57842 -0.139801025390625 +57843 -0.018798828125 +57844 0.014617919921875 +57845 0.01715087890625 +57846 0.144378662109375 +57847 0.047210693359375 +57848 0.221038818359375 +57849 0.065521240234375 +57850 0.27069091796875 +57851 0.077178955078125 +57852 0.294036865234375 +57853 0.082275390625 +57854 0.311767578125 +57855 0.0849609375 +57856 0.339141845703125 +57857 0.088470458984375 +57858 0.360260009765625 +57859 0.090179443359375 +57860 0.360504150390625 +57861 0.08721923828125 +57862 0.308380126953125 +57863 0.072296142578125 +57864 0.18170166015625 +57865 0.040313720703125 +57866 0.0047607421875 +57867 -0.002960205078125 +57868 -0.17559814453125 +57869 -0.046661376953125 +57870 -0.3143310546875 +57871 -0.080291748046875 +57872 -0.36785888671875 +57873 -0.093719482421875 +57874 -0.36248779296875 +57875 -0.093017578125 +57876 -0.343536376953125 +57877 -0.08868408203125 +57878 -0.3018798828125 +57879 -0.078643798828125 +57880 -0.231414794921875 +57881 -0.061492919921875 +57882 -0.117645263671875 +57883 -0.033905029296875 +57884 0.007049560546875 +57885 -0.00347900390625 +57886 0.087982177734375 +57887 0.016998291015625 +57888 0.13946533203125 +57889 0.03076171875 +57890 0.17425537109375 +57891 0.040679931640625 +57892 0.188201904296875 +57893 0.045684814453125 +57894 0.171234130859375 +57895 0.0433349609375 +57896 0.118438720703125 +57897 0.032440185546875 +57898 0.05706787109375 +57899 0.019256591796875 +57900 -0.010711669921875 +57901 0.004241943359375 +57902 -0.0914306640625 +57903 -0.014129638671875 +57904 -0.162322998046875 +57905 -0.03057861328125 +57906 -0.194549560546875 +57907 -0.038421630859375 +57908 -0.1492919921875 +57909 -0.02862548828125 +57910 -0.02166748046875 +57911 -3.0517578125e-05 +57912 0.124053955078125 +57913 0.03253173828125 +57914 0.211151123046875 +57915 0.051300048828125 +57916 0.240447998046875 +57917 0.056549072265625 +57918 0.242218017578125 +57919 0.055389404296875 +57920 0.2257080078125 +57921 0.050079345703125 +57922 0.194366455078125 +57923 0.04150390625 +57924 0.115509033203125 +57925 0.022125244140625 +57926 0.0128173828125 +57927 -0.00244140625 +57928 -0.053802490234375 +57929 -0.018280029296875 +57930 -0.110626220703125 +57931 -0.031494140625 +57932 -0.199493408203125 +57933 -0.05181884765625 +57934 -0.29437255859375 +57935 -0.073211669921875 +57936 -0.33221435546875 +57937 -0.081085205078125 +57938 -0.27972412109375 +57939 -0.067779541015625 +57940 -0.185333251953125 +57941 -0.04461669921875 +57942 -0.128204345703125 +57943 -0.030029296875 +57944 -0.115692138671875 +57945 -0.025787353515625 +57946 -0.116455078125 +57947 -0.024688720703125 +57948 -0.105926513671875 +57949 -0.0211181640625 +57950 -0.053955078125 +57951 -0.00811767578125 +57952 0.048797607421875 +57953 0.016387939453125 +57954 0.157318115234375 +57955 0.04193115234375 +57956 0.212005615234375 +57957 0.054656982421875 +57958 0.218475341796875 +57959 0.055877685546875 +57960 0.23724365234375 +57961 0.0596923828125 +57962 0.30535888671875 +57963 0.07470703125 +57964 0.38128662109375 +57965 0.091339111328125 +57966 0.404449462890625 +57967 0.0955810546875 +57968 0.3944091796875 +57969 0.092071533203125 +57970 0.3885498046875 +57971 0.089508056640625 +57972 0.362640380859375 +57973 0.082366943359375 +57974 0.27362060546875 +57975 0.060699462890625 +57976 0.11712646484375 +57977 0.0235595703125 +57978 -0.054901123046875 +57979 -0.01690673828125 +57980 -0.19085693359375 +57981 -0.0487060546875 +57982 -0.28570556640625 +57983 -0.070709228515625 +57984 -0.339263916015625 +57985 -0.082855224609375 +57986 -0.3775634765625 +57987 -0.091217041015625 +57988 -0.445709228515625 +57989 -0.106292724609375 +57990 -0.535064697265625 +57991 -0.12615966796875 +57992 -0.629058837890625 +57993 -0.147003173828125 +57994 -0.697601318359375 +57995 -0.161865234375 +57996 -0.70391845703125 +57997 -0.16229248046875 +57998 -0.6424560546875 +57999 -0.14703369140625 +58000 -0.491241455078125 +58001 -0.111053466796875 +58002 -0.265716552734375 +58003 -0.058013916015625 +58004 -0.023712158203125 +58005 -0.0013427734375 +58006 0.201751708984375 +58007 0.051239013671875 +58008 0.375823974609375 +58009 0.09161376953125 +58010 0.485076904296875 +58011 0.11669921875 +58012 0.56884765625 +58013 0.135650634765625 +58014 0.634765625 +58015 0.1502685546875 +58016 0.63763427734375 +58017 0.150115966796875 +58018 0.5660400390625 +58019 0.132598876953125 +58020 0.4720458984375 +58021 0.109832763671875 +58022 0.40692138671875 +58023 0.093780517578125 +58024 0.3778076171875 +58025 0.08612060546875 +58026 0.376953125 +58027 0.085113525390625 +58028 0.371978759765625 +58029 0.083282470703125 +58030 0.313140869140625 +58031 0.069122314453125 +58032 0.184417724609375 +58033 0.0389404296875 +58034 0.011199951171875 +58035 -0.001312255859375 +58036 -0.171051025390625 +58037 -0.04339599609375 +58038 -0.33740234375 +58039 -0.08154296875 +58040 -0.47198486328125 +58041 -0.11212158203125 +58042 -0.560394287109375 +58043 -0.1318359375 +58044 -0.58056640625 +58045 -0.135650634765625 +58046 -0.54754638671875 +58047 -0.1270751953125 +58048 -0.508575439453125 +58049 -0.117156982421875 +58050 -0.459503173828125 +58051 -0.104949951171875 +58052 -0.394378662109375 +58053 -0.089111328125 +58054 -0.35260009765625 +58055 -0.078765869140625 +58056 -0.31170654296875 +58057 -0.06878662109375 +58058 -0.197418212890625 +58059 -0.04193115234375 +58060 -0.007965087890625 +58061 0.00213623046875 +58062 0.207489013671875 +58063 0.052001953125 +58064 0.409210205078125 +58065 0.09844970703125 +58066 0.57208251953125 +58067 0.135711669921875 +58068 0.66595458984375 +58069 0.156829833984375 +58070 0.65875244140625 +58071 0.154388427734375 +58072 0.56744384765625 +58073 0.132354736328125 +58074 0.431396484375 +58075 0.099945068359375 +58076 0.29443359375 +58077 0.067352294921875 +58078 0.182464599609375 +58079 0.040618896484375 +58080 0.06365966796875 +58081 0.012420654296875 +58082 -0.075958251953125 +58083 -0.020416259765625 +58084 -0.189422607421875 +58085 -0.0469970703125 +58086 -0.271942138671875 +58087 -0.066192626953125 +58088 -0.342529296875 +58089 -0.082427978515625 +58090 -0.364166259765625 +58091 -0.087158203125 +58092 -0.327239990234375 +58093 -0.078155517578125 +58094 -0.2769775390625 +58095 -0.06591796875 +58096 -0.253692626953125 +58097 -0.059844970703125 +58098 -0.24365234375 +58099 -0.056793212890625 +58100 -0.1983642578125 +58101 -0.0455322265625 +58102 -0.116241455078125 +58103 -0.025726318359375 +58104 -0.036834716796875 +58105 -0.006591796875 +58106 0.034881591796875 +58107 0.0106201171875 +58108 0.09124755859375 +58109 0.02410888671875 +58110 0.10888671875 +58111 0.028411865234375 +58112 0.125518798828125 +58113 0.032684326171875 +58114 0.15771484375 +58115 0.0408935546875 +58116 0.17828369140625 +58117 0.046234130859375 +58118 0.17108154296875 +58119 0.044342041015625 +58120 0.129974365234375 +58121 0.03350830078125 +58122 0.082427978515625 +58123 0.02093505859375 +58124 0.027679443359375 +58125 0.00640869140625 +58126 -0.065643310546875 +58127 -0.018341064453125 +58128 -0.15936279296875 +58129 -0.043212890625 +58130 -0.21307373046875 +58131 -0.057525634765625 +58132 -0.234649658203125 +58133 -0.063323974609375 +58134 -0.2001953125 +58135 -0.054290771484375 +58136 -0.119171142578125 +58137 -0.032928466796875 +58138 -0.024749755859375 +58139 -0.00799560546875 +58140 0.085784912109375 +58141 0.021240234375 +58142 0.178131103515625 +58143 0.04571533203125 +58144 0.215576171875 +58145 0.055755615234375 +58146 0.211456298828125 +58147 0.05487060546875 +58148 0.17523193359375 +58149 0.045562744140625 +58150 0.128753662109375 +58151 0.033599853515625 +58152 0.1019287109375 +58153 0.02685546875 +58154 0.0743408203125 +58155 0.0198974609375 +58156 0.04327392578125 +58157 0.011993408203125 +58158 0.038177490234375 +58159 0.010894775390625 +58160 0.076263427734375 +58161 0.021148681640625 +58162 0.14105224609375 +58163 0.03839111328125 +58164 0.186431884765625 +58165 0.050445556640625 +58166 0.188812255859375 +58167 0.051055908203125 +58168 0.1390380859375 +58169 0.037841796875 +58170 0.041778564453125 +58171 0.012054443359375 +58172 -0.079437255859375 +58173 -0.02008056640625 +58174 -0.219390869140625 +58175 -0.05718994140625 +58176 -0.367828369140625 +58177 -0.096527099609375 +58178 -0.494873046875 +58179 -0.130218505859375 +58180 -0.556243896484375 +58181 -0.14654541015625 +58182 -0.508697509765625 +58183 -0.13409423828125 +58184 -0.3756103515625 +58185 -0.09906005859375 +58186 -0.218902587890625 +58187 -0.057769775390625 +58188 -0.063751220703125 +58189 -0.016845703125 +58190 0.091552734375 +58191 0.024078369140625 +58192 0.23602294921875 +58193 0.0621337890625 +58194 0.342987060546875 +58195 0.09027099609375 +58196 0.39520263671875 +58197 0.103973388671875 +58198 0.389373779296875 +58199 0.10235595703125 +58200 0.324249267578125 +58201 0.085113525390625 +58202 0.224090576171875 +58203 0.05865478515625 +58204 0.124267578125 +58205 0.0323486328125 +58206 0.037078857421875 +58207 0.0093994140625 +58208 -0.010101318359375 +58209 -0.0029296875 +58210 -0.019439697265625 +58211 -0.0052490234375 +58212 -0.022796630859375 +58213 -0.0059814453125 +58214 -0.001556396484375 +58215 -0.00018310546875 +58216 0.056304931640625 +58217 0.0152587890625 +58218 0.106719970703125 +58219 0.0286865234375 +58220 0.096893310546875 +58221 0.026153564453125 +58222 0.042694091796875 +58223 0.011871337890625 +58224 -0.018035888671875 +58225 -0.004150390625 +58226 -0.07586669921875 +58227 -0.0194091796875 +58228 -0.11944580078125 +58229 -0.030914306640625 +58230 -0.15972900390625 +58231 -0.04156494140625 +58232 -0.202606201171875 +58233 -0.05291748046875 +58234 -0.24859619140625 +58235 -0.0650634765625 +58236 -0.30517578125 +58237 -0.079986572265625 +58238 -0.36212158203125 +58239 -0.095001220703125 +58240 -0.39141845703125 +58241 -0.102752685546875 +58242 -0.35528564453125 +58243 -0.093231201171875 +58244 -0.249969482421875 +58245 -0.065460205078125 +58246 -0.092864990234375 +58247 -0.024017333984375 +58248 0.08905029296875 +58249 0.02392578125 +58250 0.2352294921875 +58251 0.062408447265625 +58252 0.318817138671875 +58253 0.084381103515625 +58254 0.358642578125 +58255 0.09478759765625 +58256 0.347747802734375 +58257 0.091796875 +58258 0.28564453125 +58259 0.075286865234375 +58260 0.223175048828125 +58261 0.058685302734375 +58262 0.196746826171875 +58263 0.051605224609375 +58264 0.179840087890625 +58265 0.047088623046875 +58266 0.155548095703125 +58267 0.0406494140625 +58268 0.151214599609375 +58269 0.039520263671875 +58270 0.156951904296875 +58271 0.04107666015625 +58272 0.13177490234375 +58273 0.03448486328125 +58274 0.100799560546875 +58275 0.026397705078125 +58276 0.087127685546875 +58277 0.02288818359375 +58278 0.05487060546875 +58279 0.01446533203125 +58280 -0.009002685546875 +58281 -0.002288818359375 +58282 -0.10400390625 +58283 -0.027252197265625 +58284 -0.229400634765625 +58285 -0.06024169921875 +58286 -0.35552978515625 +58287 -0.093414306640625 +58288 -0.441925048828125 +58289 -0.1160888671875 +58290 -0.473846435546875 +58291 -0.124420166015625 +58292 -0.464813232421875 +58293 -0.1219482421875 +58294 -0.419097900390625 +58295 -0.10980224609375 +58296 -0.334320068359375 +58297 -0.087371826171875 +58298 -0.227935791015625 +58299 -0.059234619140625 +58300 -0.12347412109375 +58301 -0.031646728515625 +58302 -0.02764892578125 +58303 -0.00634765625 +58304 0.077667236328125 +58305 0.021392822265625 +58306 0.2132568359375 +58307 0.05706787109375 +58308 0.38885498046875 +58309 0.103271484375 +58310 0.582794189453125 +58311 0.154296875 +58312 0.734039306640625 +58313 0.19403076171875 +58314 0.800140380859375 +58315 0.21124267578125 +58316 0.7783203125 +58317 0.205230712890625 +58318 0.6651611328125 +58319 0.17510986328125 +58320 0.45965576171875 +58321 0.12066650390625 +58322 0.199188232421875 +58323 0.051788330078125 +58324 -0.050689697265625 +58325 -0.01422119140625 +58326 -0.23297119140625 +58327 -0.06231689453125 +58328 -0.33013916015625 +58329 -0.087890625 +58330 -0.368408203125 +58331 -0.09783935546875 +58332 -0.378936767578125 +58333 -0.10040283203125 +58334 -0.376983642578125 +58335 -0.099639892578125 +58336 -0.37969970703125 +58337 -0.10009765625 +58338 -0.391510009765625 +58339 -0.102935791015625 +58340 -0.385345458984375 +58341 -0.101043701171875 +58342 -0.3419189453125 +58343 -0.089324951171875 +58344 -0.28289794921875 +58345 -0.073516845703125 +58346 -0.251617431640625 +58347 -0.0650634765625 +58348 -0.266143798828125 +58349 -0.068756103515625 +58350 -0.273345947265625 +58351 -0.070587158203125 +58352 -0.216796875 +58353 -0.055633544921875 +58354 -0.128265380859375 +58355 -0.03228759765625 +58356 -0.068145751953125 +58357 -0.0164794921875 +58358 -0.0430908203125 +58359 -0.009979248046875 +58360 -0.024444580078125 +58361 -0.005218505859375 +58362 0.020721435546875 +58363 0.0064697265625 +58364 0.124481201171875 +58365 0.0335693359375 +58366 0.25787353515625 +58367 0.068450927734375 +58368 0.379119873046875 +58369 0.100677490234375 +58370 0.47991943359375 +58371 0.127899169921875 +58372 0.5281982421875 +58373 0.140289306640625 +58374 0.511138916015625 +58375 0.134246826171875 +58376 0.456207275390625 +58377 0.118011474609375 +58378 0.407470703125 +58379 0.104644775390625 +58380 0.383758544921875 +58381 0.099639892578125 +58382 0.35687255859375 +58383 0.094482421875 +58384 0.31182861328125 +58385 0.0845947265625 +58386 0.250885009765625 +58387 0.070404052734375 +58388 0.1654052734375 +58389 0.04913330078125 +58390 0.035247802734375 +58391 0.01458740234375 +58392 -0.142059326171875 +58393 -0.0341796875 +58394 -0.33563232421875 +58395 -0.0882568359375 +58396 -0.5345458984375 +58397 -0.14453125 +58398 -0.72186279296875 +58399 -0.198150634765625 +58400 -0.836669921875 +58401 -0.23114013671875 +58402 -0.8326416015625 +58403 -0.2298583984375 +58404 -0.7296142578125 +58405 -0.200164794921875 +58406 -0.582550048828125 +58407 -0.15826416015625 +58408 -0.440093994140625 +58409 -0.118438720703125 +58410 -0.324310302734375 +58411 -0.08709716796875 +58412 -0.20147705078125 +58413 -0.054046630859375 +58414 -0.044647216796875 +58415 -0.0111083984375 +58416 0.103973388671875 +58417 0.029388427734375 +58418 0.202392578125 +58419 0.055206298828125 +58420 0.264495849609375 +58421 0.07061767578125 +58422 0.338897705078125 +58423 0.09014892578125 +58424 0.443817138671875 +58425 0.11932373046875 +58426 0.545074462890625 +58427 0.14813232421875 +58428 0.6173095703125 +58429 0.169097900390625 +58430 0.6524658203125 +58431 0.179840087890625 +58432 0.66339111328125 +58433 0.184112548828125 +58434 0.6561279296875 +58435 0.183624267578125 +58436 0.606781005859375 +58437 0.171173095703125 +58438 0.501190185546875 +58439 0.1424560546875 +58440 0.352783203125 +58441 0.101318359375 +58442 0.176544189453125 +58443 0.052001953125 +58444 -0.034820556640625 +58445 -0.00775146484375 +58446 -0.258209228515625 +58447 -0.07122802734375 +58448 -0.44244384765625 +58449 -0.1234130859375 +58450 -0.5753173828125 +58451 -0.160858154296875 +58452 -0.65203857421875 +58453 -0.182220458984375 +58454 -0.641632080078125 +58455 -0.178375244140625 +58456 -0.562164306640625 +58457 -0.154754638671875 +58458 -0.458038330078125 +58459 -0.124481201171875 +58460 -0.350555419921875 +58461 -0.093780517578125 +58462 -0.260528564453125 +58463 -0.0687255859375 +58464 -0.192108154296875 +58465 -0.05047607421875 +58466 -0.141937255859375 +58467 -0.03790283203125 +58468 -0.1021728515625 +58469 -0.028564453125 +58470 -0.062896728515625 +58471 -0.01934814453125 +58472 -0.011932373046875 +58473 -0.006561279296875 +58474 0.062835693359375 +58475 0.013519287109375 +58476 0.148712158203125 +58477 0.0372314453125 +58478 0.241729736328125 +58479 0.0634765625 +58480 0.34912109375 +58481 0.09442138671875 +58482 0.457305908203125 +58483 0.126129150390625 +58484 0.54388427734375 +58485 0.151947021484375 +58486 0.5728759765625 +58487 0.16119384765625 +58488 0.506591796875 +58489 0.142669677734375 +58490 0.351226806640625 +58491 0.09814453125 +58492 0.146514892578125 +58493 0.039276123046875 +58494 -0.05523681640625 +58495 -0.01849365234375 +58496 -0.21624755859375 +58497 -0.064117431640625 +58498 -0.334930419921875 +58499 -0.09722900390625 +58500 -0.402984619140625 +58501 -0.115478515625 +58502 -0.4412841796875 +58503 -0.1251220703125 +58504 -0.49578857421875 +58505 -0.139892578125 +58506 -0.5601806640625 +58507 -0.157958984375 +58508 -0.600738525390625 +58509 -0.169403076171875 +58510 -0.584228515625 +58511 -0.164398193359375 +58512 -0.47930908203125 +58513 -0.1336669921875 +58514 -0.27935791015625 +58515 -0.075225830078125 +58516 -0.0089111328125 +58517 0.003662109375 +58518 0.268798828125 +58519 0.0843505859375 +58520 0.482818603515625 +58521 0.145965576171875 +58522 0.60369873046875 +58523 0.17987060546875 +58524 0.650421142578125 +58525 0.191802978515625 +58526 0.66400146484375 +58527 0.194000244140625 +58528 0.6414794921875 +58529 0.185699462890625 +58530 0.572540283203125 +58531 0.1639404296875 +58532 0.498138427734375 +58533 0.140899658203125 +58534 0.439453125 +58535 0.1229248046875 +58536 0.375518798828125 +58537 0.10382080078125 +58538 0.274505615234375 +58539 0.07415771484375 +58540 0.1087646484375 +58541 0.025726318359375 +58542 -0.099395751953125 +58543 -0.034912109375 +58544 -0.3182373046875 +58545 -0.098388671875 +58546 -0.5489501953125 +58547 -0.165191650390625 +58548 -0.7738037109375 +58549 -0.2301025390625 +58550 -0.86383056640625 +58551 -0.277557373046875 +58552 -0.870391845703125 +58553 -0.297821044921875 +58554 -0.86895751953125 +58555 -0.296234130859375 +58556 -0.861053466796875 +58557 -0.276763916015625 +58558 -0.765869140625 +58559 -0.234344482421875 +58560 -0.5301513671875 +58561 -0.165679931640625 +58562 -0.214691162109375 +58563 -0.072906494140625 +58564 0.137359619140625 +58565 0.031219482421875 +58566 0.474822998046875 +58567 0.13153076171875 +58568 0.76239013671875 +58569 0.217559814453125 +58570 0.867462158203125 +58571 0.281341552734375 +58572 0.870361328125 +58573 0.323089599609375 +58574 0.86480712890625 +58575 0.339447021484375 +58576 0.831817626953125 +58577 0.332061767578125 +58578 0.677581787109375 +58579 0.308258056640625 +58580 0.495880126953125 +58581 0.269805908203125 +58582 0.30767822265625 +58583 0.2222900390625 +58584 0.116180419921875 +58585 0.166412353515625 +58586 -0.110748291015625 +58587 0.09283447265625 +58588 -0.381805419921875 +58589 -0.000457763671875 +58590 -0.6572265625 +58591 -0.10076904296875 +58592 -0.857421875 +58593 -0.19036865234375 +58594 -0.870391845703125 +58595 -0.256591796875 +58596 -0.870391845703125 +58597 -0.29736328125 +58598 -0.86444091796875 +58599 -0.320709228515625 +58600 -0.85723876953125 +58601 -0.337249755859375 +58602 -0.790008544921875 +58603 -0.341644287109375 +58604 -0.62847900390625 +58605 -0.31787109375 +58606 -0.3956298828125 +58607 -0.26507568359375 +58608 -0.126708984375 +58609 -0.19305419921875 +58610 0.150115966796875 +58611 -0.109954833984375 +58612 0.424041748046875 +58613 -0.019317626953125 +58614 0.670623779296875 +58615 0.070831298828125 +58616 0.854522705078125 +58617 0.149017333984375 +58618 0.866485595703125 +58619 0.21002197265625 +58620 0.86920166015625 +58621 0.249298095703125 +58622 0.8653564453125 +58623 0.272247314453125 +58624 0.857147216796875 +58625 0.282623291015625 +58626 0.766845703125 +58627 0.2799072265625 +58628 0.628509521484375 +58629 0.266021728515625 +58630 0.462127685546875 +58631 0.23870849609375 +58632 0.297210693359375 +58633 0.20635986328125 +58634 0.14862060546875 +58635 0.17279052734375 +58636 -0.00537109375 +58637 0.130279541015625 +58638 -0.15753173828125 +58639 0.080963134765625 +58640 -0.31304931640625 +58641 0.023345947265625 +58642 -0.48876953125 +58643 -0.04754638671875 +58644 -0.6416015625 +58645 -0.11663818359375 +58646 -0.751373291015625 +58647 -0.176116943359375 +58648 -0.84619140625 +58649 -0.233795166015625 +58650 -0.861297607421875 +58651 -0.285064697265625 +58652 -0.863250732421875 +58653 -0.319183349609375 +58654 -0.856597900390625 +58655 -0.3258056640625 +58656 -0.7498779296875 +58657 -0.30889892578125 +58658 -0.624542236328125 +58659 -0.287353515625 +58660 -0.47808837890625 +58661 -0.2537841796875 +58662 -0.253387451171875 +58663 -0.1888427734375 +58664 0.003692626953125 +58665 -0.10723876953125 +58666 0.2257080078125 +58667 -0.0311279296875 +58668 0.427154541015625 +58669 0.04388427734375 +58670 0.643218994140625 +58671 0.128662109375 +58672 0.855926513671875 +58673 0.220306396484375 +58674 0.870361328125 +58675 0.300018310546875 +58676 0.870361328125 +58677 0.3516845703125 +58678 0.862762451171875 +58679 0.377777099609375 +58680 0.79669189453125 +58681 0.37738037109375 +58682 0.595794677734375 +58683 0.347412109375 +58684 0.362152099609375 +58685 0.29742431640625 +58686 0.1270751953125 +58687 0.2364501953125 +58688 -0.086944580078125 +58689 0.171295166015625 +58690 -0.2784423828125 +58691 0.10247802734375 +58692 -0.484832763671875 +58693 0.018402099609375 +58694 -0.729583740234375 +58695 -0.087432861328125 +58696 -0.86688232421875 +58697 -0.19866943359375 +58698 -0.870391845703125 +58699 -0.294708251953125 +58700 -0.86859130859375 +58701 -0.37408447265625 +58702 -0.86279296875 +58703 -0.43621826171875 +58704 -0.817962646484375 +58705 -0.46942138671875 +58706 -0.6116943359375 +58707 -0.4588623046875 +58708 -0.3128662109375 +58709 -0.402191162109375 +58710 0.039398193359375 +58711 -0.310455322265625 +58712 0.422821044921875 +58713 -0.190155029296875 +58714 0.805145263671875 +58715 -0.0521240234375 +58716 0.870361328125 +58717 0.081390380859375 +58718 0.870361328125 +58719 0.191802978515625 +58720 0.860015869140625 +58721 0.275421142578125 +58722 0.727935791015625 +58723 0.329803466796875 +58724 0.48114013671875 +58725 0.353179931640625 +58726 0.2059326171875 +58727 0.35357666015625 +58728 -0.06103515625 +58729 0.3385009765625 +58730 -0.29913330078125 +58731 0.311248779296875 +58732 -0.516204833984375 +58733 0.26708984375 +58734 -0.7252197265625 +58735 0.2010498046875 +58736 -0.85980224609375 +58737 0.12127685546875 +58738 -0.870391845703125 +58739 0.0390625 +58740 -0.870391845703125 +58741 -0.035858154296875 +58742 -0.858062744140625 +58743 -0.087493896484375 +58744 -0.673004150390625 +58745 -0.11444091796875 +58746 -0.42694091796875 +58747 -0.133941650390625 +58748 -0.2100830078125 +58749 -0.16046142578125 +58750 -0.0362548828125 +58751 -0.193267822265625 +58752 0.10943603515625 +58753 -0.222808837890625 +58754 0.23516845703125 +58755 -0.242523193359375 +58756 0.373687744140625 +58757 -0.23883056640625 +58758 0.517791748046875 +58759 -0.212371826171875 +58760 0.602783203125 +58761 -0.183807373046875 +58762 0.635711669921875 +58763 -0.1514892578125 +58764 0.655181884765625 +58765 -0.10455322265625 +58766 0.65948486328125 +58767 -0.04632568359375 +58768 0.651275634765625 +58769 0.020477294921875 +58770 0.61846923828125 +58771 0.087738037109375 +58772 0.53753662109375 +58773 0.143218994140625 +58774 0.404144287109375 +58775 0.180938720703125 +58776 0.22186279296875 +58777 0.1976318359375 +58778 0.003997802734375 +58779 0.19366455078125 +58780 -0.22100830078125 +58781 0.1749267578125 +58782 -0.42449951171875 +58783 0.148162841796875 +58784 -0.579833984375 +58785 0.120391845703125 +58786 -0.641876220703125 +58787 0.105621337890625 +58788 -0.6177978515625 +58789 0.1016845703125 +58790 -0.575531005859375 +58791 0.08746337890625 +58792 -0.526336669921875 +58793 0.061248779296875 +58794 -0.42645263671875 +58795 0.04010009765625 +58796 -0.2581787109375 +58797 0.0330810546875 +58798 -0.068695068359375 +58799 0.02838134765625 +58800 0.09222412109375 +58801 0.013458251953125 +58802 0.232147216796875 +58803 -0.0054931640625 +58804 0.3509521484375 +58805 -0.0250244140625 +58806 0.410064697265625 +58807 -0.0548095703125 +58808 0.372955322265625 +58809 -0.1043701171875 +58810 0.2554931640625 +58811 -0.16680908203125 +58812 0.10711669921875 +58813 -0.225006103515625 +58814 -0.052886962890625 +58815 -0.27252197265625 +58816 -0.186279296875 +58817 -0.2974853515625 +58818 -0.23291015625 +58819 -0.2816162109375 +58820 -0.209442138671875 +58821 -0.232452392578125 +58822 -0.174163818359375 +58823 -0.171630859375 +58824 -0.126739501953125 +58825 -0.10198974609375 +58826 -0.048126220703125 +58827 -0.020355224609375 +58828 0.0426025390625 +58829 0.063873291015625 +58830 0.10748291015625 +58831 0.135345458984375 +58832 0.1409912109375 +58833 0.189605712890625 +58834 0.19708251953125 +58835 0.2421875 +58836 0.273651123046875 +58837 0.29083251953125 +58838 0.31768798828125 +58839 0.317169189453125 +58840 0.341094970703125 +58841 0.32476806640625 +58842 0.368011474609375 +58843 0.321929931640625 +58844 0.37249755859375 +58845 0.301116943359375 +58846 0.30072021484375 +58847 0.246185302734375 +58848 0.1517333984375 +58849 0.15875244140625 +58850 -0.01470947265625 +58851 0.060760498046875 +58852 -0.1883544921875 +58853 -0.041900634765625 +58854 -0.372711181640625 +58855 -0.147796630859375 +58856 -0.51397705078125 +58857 -0.236846923828125 +58858 -0.57177734375 +58859 -0.293548583984375 +58860 -0.53948974609375 +58861 -0.313812255859375 +58862 -0.43511962890625 +58863 -0.30206298828125 +58864 -0.2962646484375 +58865 -0.2696533203125 +58866 -0.161102294921875 +58867 -0.228668212890625 +58868 -0.0435791015625 +58869 -0.183746337890625 +58870 0.060394287109375 +58871 -0.134185791015625 +58872 0.13665771484375 +58873 -0.08575439453125 +58874 0.170135498046875 +58875 -0.04486083984375 +58876 0.16552734375 +58877 -0.01177978515625 +58878 0.15728759765625 +58879 0.022705078125 +58880 0.150787353515625 +58881 0.058074951171875 +58882 0.12200927734375 +58883 0.0843505859375 +58884 0.080108642578125 +58885 0.10296630859375 +58886 0.05126953125 +58887 0.121185302734375 +58888 0.062896728515625 +58889 0.147125244140625 +58890 0.09271240234375 +58891 0.171905517578125 +58892 0.092987060546875 +58893 0.17822265625 +58894 0.07855224609375 +58895 0.171142578125 +58896 0.06427001953125 +58897 0.15625 +58898 0.0347900390625 +58899 0.12890625 +58900 -0.01171875 +58901 0.089630126953125 +58902 -0.056060791015625 +58903 0.04656982421875 +58904 -0.055511474609375 +58905 0.016326904296875 +58906 -0.010467529296875 +58907 0.00054931640625 +58908 0.02508544921875 +58909 -0.017852783203125 +58910 0.025665283203125 +58911 -0.046142578125 +58912 0.017333984375 +58913 -0.073699951171875 +58914 0.00189208984375 +58915 -0.098663330078125 +58916 -0.03173828125 +58917 -0.123992919921875 +58918 -0.071502685546875 +58919 -0.144927978515625 +58920 -0.13543701171875 +58921 -0.16754150390625 +58922 -0.219970703125 +58923 -0.1907958984375 +58924 -0.300506591796875 +58925 -0.20660400390625 +58926 -0.376312255859375 +58927 -0.21551513671875 +58928 -0.416107177734375 +58929 -0.207733154296875 +58930 -0.371124267578125 +58931 -0.16748046875 +58932 -0.242279052734375 +58933 -0.09649658203125 +58934 -0.069732666015625 +58935 -0.01031494140625 +58936 0.125640869140625 +58937 0.082305908203125 +58938 0.31268310546875 +58939 0.169219970703125 +58940 0.45501708984375 +58941 0.236572265625 +58942 0.554779052734375 +58943 0.2843017578125 +58944 0.61065673828125 +58945 0.3114013671875 +58946 0.610931396484375 +58947 0.313507080078125 +58948 0.531463623046875 +58949 0.282196044921875 +58950 0.3883056640625 +58951 0.223480224609375 +58952 0.23468017578125 +58953 0.15655517578125 +58954 0.095245361328125 +58955 0.0909423828125 +58956 -0.00396728515625 +58957 0.036773681640625 +58958 -0.04852294921875 +58959 0.00018310546875 +58960 -0.055145263671875 +58961 -0.0234375 +58962 -0.0758056640625 +58963 -0.051116943359375 +58964 -0.138702392578125 +58965 -0.091644287109375 +58966 -0.209197998046875 +58967 -0.131927490234375 +58968 -0.289031982421875 +58969 -0.17181396484375 +58970 -0.37884521484375 +58971 -0.210968017578125 +58972 -0.456329345703125 +58973 -0.241302490234375 +58974 -0.51641845703125 +58975 -0.260986328125 +58976 -0.519287109375 +58977 -0.256256103515625 +58978 -0.458251953125 +58979 -0.225250244140625 +58980 -0.384796142578125 +58981 -0.186614990234375 +58982 -0.323699951171875 +58983 -0.14984130859375 +58984 -0.269287109375 +58985 -0.11383056640625 +58986 -0.1951904296875 +58987 -0.0703125 +58988 -0.100006103515625 +58989 -0.019805908203125 +58990 -0.01055908203125 +58991 0.027374267578125 +58992 0.1033935546875 +58993 0.080963134765625 +58994 0.24908447265625 +58995 0.142852783203125 +58996 0.373199462890625 +58997 0.19384765625 +58998 0.45806884765625 +58999 0.227447509765625 +59000 0.511474609375 +59001 0.24627685546875 +59002 0.565399169921875 +59003 0.261627197265625 +59004 0.61138916015625 +59005 0.27081298828125 +59006 0.5897216796875 +59007 0.25341796875 +59008 0.4906005859375 +59009 0.20660400390625 +59010 0.33148193359375 +59011 0.137237548828125 +59012 0.147796630859375 +59013 0.058502197265625 +59014 -0.01873779296875 +59015 -0.01416015625 +59016 -0.140289306640625 +59017 -0.070220947265625 +59018 -0.191986083984375 +59019 -0.10028076171875 +59020 -0.184295654296875 +59021 -0.107391357421875 +59022 -0.161834716796875 +59023 -0.106689453125 +59024 -0.166595458984375 +59025 -0.112548828125 +59026 -0.19390869140625 +59027 -0.123199462890625 +59028 -0.22442626953125 +59029 -0.13189697265625 +59030 -0.279754638671875 +59031 -0.146392822265625 +59032 -0.3389892578125 +59033 -0.15972900390625 +59034 -0.3543701171875 +59035 -0.155670166015625 +59036 -0.348175048828125 +59037 -0.142578125 +59038 -0.32598876953125 +59039 -0.123077392578125 +59040 -0.2581787109375 +59041 -0.08746337890625 +59042 -0.139801025390625 +59043 -0.034637451171875 +59044 0.014617919921875 +59045 0.02972412109375 +59046 0.144378662109375 +59047 0.08380126953125 +59048 0.221038818359375 +59049 0.117218017578125 +59050 0.27069091796875 +59051 0.1387939453125 +59052 0.294036865234375 +59053 0.148651123046875 +59054 0.311767578125 +59055 0.154022216796875 +59056 0.339141845703125 +59057 0.160400390625 +59058 0.360260009765625 +59059 0.162567138671875 +59060 0.360504150390625 +59061 0.155731201171875 +59062 0.308380126953125 +59063 0.128936767578125 +59064 0.18170166015625 +59065 0.074615478515625 +59066 0.0047607421875 +59067 0.00201416015625 +59068 -0.17559814453125 +59069 -0.071502685546875 +59070 -0.3143310546875 +59071 -0.129302978515625 +59072 -0.36785888671875 +59073 -0.155303955078125 +59074 -0.36248779296875 +59075 -0.15869140625 +59076 -0.343536376953125 +59077 -0.155487060546875 +59078 -0.3018798828125 +59079 -0.142303466796875 +59080 -0.231414794921875 +59081 -0.11688232421875 +59082 -0.117645263671875 +59083 -0.07403564453125 +59084 0.007049560546875 +59085 -0.02557373046875 +59086 0.087982177734375 +59087 0.008575439453125 +59088 0.13946533203125 +59089 0.033233642578125 +59090 0.17425537109375 +59091 0.052642822265625 +59092 0.188201904296875 +59093 0.06488037109375 +59094 0.171234130859375 +59095 0.06591796875 +59096 0.118438720703125 +59097 0.0535888671875 +59098 0.05706787109375 +59099 0.03741455078125 +59100 -0.010711669921875 +59101 0.017822265625 +59102 -0.0914306640625 +59103 -0.007720947265625 +59104 -0.162322998046875 +59105 -0.03118896484375 +59106 -0.194549560546875 +59107 -0.042266845703125 +59108 -0.1492919921875 +59109 -0.026947021484375 +59110 -0.02166748046875 +59111 0.016571044921875 +59112 0.124053955078125 +59113 0.065338134765625 +59114 0.211151123046875 +59115 0.091949462890625 +59116 0.240447998046875 +59117 0.097015380859375 +59118 0.242218017578125 +59119 0.091766357421875 +59120 0.2257080078125 +59121 0.079864501953125 +59122 0.194366455078125 +59123 0.062896728515625 +59124 0.115509033203125 +59125 0.02935791015625 +59126 0.0128173828125 +59127 -0.01190185546875 +59128 -0.053802490234375 +59129 -0.039093017578125 +59130 -0.110626220703125 +59131 -0.061553955078125 +59132 -0.199493408203125 +59133 -0.094268798828125 +59134 -0.29437255859375 +59135 -0.12786865234375 +59136 -0.33221435546875 +59137 -0.139373779296875 +59138 -0.27972412109375 +59139 -0.116180419921875 +59140 -0.185333251953125 +59141 -0.076995849609375 +59142 -0.128204345703125 +59143 -0.052642822265625 +59144 -0.115692138671875 +59145 -0.0458984375 +59146 -0.116455078125 +59147 -0.044403076171875 +59148 -0.105926513671875 +59149 -0.038543701171875 +59150 -0.053955078125 +59151 -0.016510009765625 +59152 0.048797607421875 +59153 0.025238037109375 +59154 0.157318115234375 +59155 0.06903076171875 +59156 0.212005615234375 +59157 0.0914306640625 +59158 0.218475341796875 +59159 0.0946044921875 +59160 0.23724365234375 +59161 0.102203369140625 +59162 0.30535888671875 +59163 0.12872314453125 +59164 0.38128662109375 +59165 0.157867431640625 +59166 0.404449462890625 +59167 0.165924072265625 +59168 0.3944091796875 +59169 0.160614013671875 +59170 0.3885498046875 +59171 0.15667724609375 +59172 0.362640380859375 +59173 0.144683837890625 +59174 0.27362060546875 +59175 0.10784912109375 +59176 0.11712646484375 +59177 0.044586181640625 +59178 -0.054901123046875 +59179 -0.024627685546875 +59180 -0.19085693359375 +59181 -0.079437255859375 +59182 -0.28570556640625 +59183 -0.1177978515625 +59184 -0.339263916015625 +59185 -0.139617919921875 +59186 -0.3775634765625 +59187 -0.155029296875 +59188 -0.445709228515625 +59189 -0.1817626953125 +59190 -0.535064697265625 +59191 -0.2164306640625 +59192 -0.629058837890625 +59193 -0.252532958984375 +59194 -0.697601318359375 +59195 -0.2783203125 +59196 -0.70391845703125 +59197 -0.279449462890625 +59198 -0.6424560546875 +59199 -0.25384521484375 +59200 -0.491241455078125 +59201 -0.1929931640625 +59202 -0.265716552734375 +59203 -0.10302734375 +59204 -0.023712158203125 +59205 -0.006683349609375 +59206 0.201751708984375 +59207 0.082977294921875 +59208 0.375823974609375 +59209 0.152252197265625 +59210 0.485076904296875 +59211 0.19580078125 +59212 0.56884765625 +59213 0.229034423828125 +59214 0.634765625 +59215 0.25494384765625 +59216 0.63763427734375 +59217 0.25579833984375 +59218 0.5660400390625 +59219 0.227142333984375 +59220 0.4720458984375 +59221 0.189422607421875 +59222 0.40692138671875 +59223 0.16278076171875 +59224 0.3778076171875 +59225 0.150115966796875 +59226 0.376953125 +59227 0.1484375 +59228 0.371978759765625 +59229 0.1451416015625 +59230 0.313140869140625 +59231 0.12078857421875 +59232 0.184417724609375 +59233 0.06915283203125 +59234 0.011199951171875 +59235 0.000274658203125 +59236 -0.171051025390625 +59237 -0.071868896484375 +59238 -0.33740234375 +59239 -0.137451171875 +59240 -0.47198486328125 +59241 -0.19024658203125 +59242 -0.560394287109375 +59243 -0.224639892578125 +59244 -0.58056640625 +59245 -0.23199462890625 +59246 -0.54754638671875 +59247 -0.21826171875 +59248 -0.508575439453125 +59249 -0.2020263671875 +59250 -0.459503173828125 +59251 -0.18170166015625 +59252 -0.394378662109375 +59253 -0.155029296875 +59254 -0.35260009765625 +59255 -0.137481689453125 +59256 -0.31170654296875 +59257 -0.120330810546875 +59258 -0.197418212890625 +59259 -0.07452392578125 +59260 -0.007965087890625 +59261 0.00054931640625 +59262 0.207489013671875 +59263 0.0855712890625 +59264 0.409210205078125 +59265 0.164947509765625 +59266 0.57208251953125 +59267 0.228851318359375 +59268 0.66595458984375 +59269 0.26544189453125 +59270 0.65875244140625 +59271 0.262176513671875 +59272 0.56744384765625 +59273 0.22576904296875 +59274 0.431396484375 +59275 0.171661376953125 +59276 0.29443359375 +59277 0.1170654296875 +59278 0.182464599609375 +59279 0.07220458984375 +59280 0.06365966796875 +59281 0.024658203125 +59282 -0.075958251953125 +59283 -0.030975341796875 +59284 -0.189422607421875 +59285 -0.076263427734375 +59286 -0.271942138671875 +59287 -0.1092529296875 +59288 -0.342529296875 +59289 -0.13739013671875 +59290 -0.364166259765625 +59291 -0.14617919921875 +59292 -0.327239990234375 +59293 -0.131805419921875 +59294 -0.2769775390625 +59295 -0.11199951171875 +59296 -0.253692626953125 +59297 -0.10260009765625 +59298 -0.24365234375 +59299 -0.09820556640625 +59300 -0.1983642578125 +59301 -0.079833984375 +59302 -0.116241455078125 +59303 -0.04693603515625 +59304 -0.036834716796875 +59305 -0.0150146484375 +59306 0.034881591796875 +59307 0.013885498046875 +59308 0.09124755859375 +59309 0.036712646484375 +59310 0.10888671875 +59311 0.0443115234375 +59312 0.125518798828125 +59313 0.051422119140625 +59314 0.15771484375 +59315 0.064483642578125 +59316 0.17828369140625 +59317 0.07281494140625 +59318 0.17108154296875 +59319 0.070068359375 +59320 0.129974365234375 +59321 0.05389404296875 +59322 0.082427978515625 +59323 0.0350341796875 +59324 0.027679443359375 +59325 0.013214111328125 +59326 -0.065643310546875 +59327 -0.0238037109375 +59328 -0.15936279296875 +59329 -0.06103515625 +59330 -0.21307373046875 +59331 -0.082611083984375 +59332 -0.234649658203125 +59333 -0.09161376953125 +59334 -0.2001953125 +59335 -0.078643798828125 +59336 -0.119171142578125 +59337 -0.04736328125 +59338 -0.024749755859375 +59339 -0.010772705078125 +59340 0.085784912109375 +59341 0.032196044921875 +59342 0.178131103515625 +59343 0.068115234375 +59344 0.215576171875 +59345 0.082611083984375 +59346 0.211456298828125 +59347 0.08087158203125 +59348 0.17523193359375 +59349 0.066680908203125 +59350 0.128753662109375 +59351 0.048583984375 +59352 0.1019287109375 +59353 0.038299560546875 +59354 0.0743408203125 +59355 0.02783203125 +59356 0.04327392578125 +59357 0.01605224609375 +59358 0.038177490234375 +59359 0.01446533203125 +59360 0.076263427734375 +59361 0.029815673828125 +59362 0.14105224609375 +59363 0.05560302734375 +59364 0.186431884765625 +59365 0.073760986328125 +59366 0.188812255859375 +59367 0.07501220703125 +59368 0.1390380859375 +59369 0.055755615234375 +59370 0.041778564453125 +59371 0.017822265625 +59372 -0.079437255859375 +59373 -0.029571533203125 +59374 -0.219390869140625 +59375 -0.084381103515625 +59376 -0.367828369140625 +59377 -0.142578125 +59378 -0.494873046875 +59379 -0.19244384765625 +59380 -0.556243896484375 +59381 -0.21661376953125 +59382 -0.508697509765625 +59383 -0.198150634765625 +59384 -0.3756103515625 +59385 -0.14617919921875 +59386 -0.218902587890625 +59387 -0.084991455078125 +59388 -0.063751220703125 +59389 -0.0244140625 +59390 0.091552734375 +59391 0.036163330078125 +59392 0.23602294921875 +59393 0.092529296875 +59394 0.342987060546875 +59395 0.13421630859375 +59396 0.39520263671875 +59397 0.15423583984375 +59398 0.389373779296875 +59399 0.1510009765625 +59400 0.324249267578125 +59401 0.123748779296875 +59402 0.224090576171875 +59403 0.08258056640625 +59404 0.124267578125 +59405 0.042236328125 +59406 0.037078857421875 +59407 0.007720947265625 +59408 -0.010101318359375 +59409 -0.009521484375 +59410 -0.019439697265625 +59411 -0.010589599609375 +59412 -0.022796630859375 +59413 -0.0091552734375 +59414 -0.001556396484375 +59415 0.002471923828125 +59416 0.056304931640625 +59417 0.029266357421875 +59418 0.106719970703125 +59419 0.052459716796875 +59420 0.096893310546875 +59421 0.049591064453125 +59422 0.042694091796875 +59423 0.027374267578125 +59424 -0.018035888671875 +59425 0.001800537109375 +59426 -0.07586669921875 +59427 -0.0230712890625 +59428 -0.11944580078125 +59429 -0.042388916015625 +59430 -0.15972900390625 +59431 -0.06072998046875 +59432 -0.202606201171875 +59433 -0.080474853515625 +59434 -0.24859619140625 +59435 -0.10174560546875 +59436 -0.30517578125 +59437 -0.12762451171875 +59438 -0.36212158203125 +59439 -0.153656005859375 +59440 -0.39141845703125 +59441 -0.167877197265625 +59442 -0.35528564453125 +59443 -0.1541748046875 +59444 -0.249969482421875 +59445 -0.11090087890625 +59446 -0.092864990234375 +59447 -0.04534912109375 +59448 0.08905029296875 +59449 0.03106689453125 +59450 0.2352294921875 +59451 0.09271240234375 +59452 0.318817138671875 +59453 0.12823486328125 +59454 0.358642578125 +59455 0.14556884765625 +59456 0.347747802734375 +59457 0.141754150390625 +59458 0.28564453125 +59459 0.116546630859375 +59460 0.223175048828125 +59461 0.091400146484375 +59462 0.196746826171875 +59463 0.0816650390625 +59464 0.179840087890625 +59465 0.076019287109375 +59466 0.155548095703125 +59467 0.067230224609375 +59468 0.151214599609375 +59469 0.0667724609375 +59470 0.156951904296875 +59471 0.070404052734375 +59472 0.13177490234375 +59473 0.0606689453125 +59474 0.100799560546875 +59475 0.048187255859375 +59476 0.087127685546875 +59477 0.042724609375 +59478 0.05487060546875 +59479 0.029083251953125 +59480 -0.009002685546875 +59481 0.001708984375 +59482 -0.10400390625 +59483 -0.03912353515625 +59484 -0.229400634765625 +59485 -0.09307861328125 +59486 -0.35552978515625 +59487 -0.14752197265625 +59488 -0.441925048828125 +59489 -0.18524169921875 +59490 -0.473846435546875 +59491 -0.199951171875 +59492 -0.464813232421875 +59493 -0.19732666015625 +59494 -0.419097900390625 +59495 -0.1790771484375 +59496 -0.334320068359375 +59497 -0.144134521484375 +59498 -0.227935791015625 +59499 -0.099853515625 +59500 -0.12347412109375 +59501 -0.056182861328125 +59502 -0.02764892578125 +59503 -0.01593017578125 +59504 0.077667236328125 +59505 0.028594970703125 +59506 0.2132568359375 +59507 0.086181640625 +59508 0.38885498046875 +59509 0.16094970703125 +59510 0.582794189453125 +59511 0.243682861328125 +59512 0.734039306640625 +59513 0.3084716796875 +59514 0.800140380859375 +59515 0.3372802734375 +59516 0.7783203125 +59517 0.328857421875 +59518 0.6651611328125 +59519 0.28173828125 +59520 0.45965576171875 +59521 0.195465087890625 +59522 0.199188232421875 +59523 0.085845947265625 +59524 -0.050689697265625 +59525 -0.019378662109375 +59526 -0.23297119140625 +59527 -0.096038818359375 +59528 -0.33013916015625 +59529 -0.136749267578125 +59530 -0.368408203125 +59531 -0.152679443359375 +59532 -0.378936767578125 +59533 -0.157012939453125 +59534 -0.376983642578125 +59535 -0.15625 +59536 -0.37969970703125 +59537 -0.157684326171875 +59538 -0.391510009765625 +59539 -0.16314697265625 +59540 -0.385345458984375 +59541 -0.1611328125 +59542 -0.3419189453125 +59543 -0.143402099609375 +59544 -0.28289794921875 +59545 -0.119110107421875 +59546 -0.251617431640625 +59547 -0.106597900390625 +59548 -0.266143798828125 +59549 -0.11346435546875 +59550 -0.273345947265625 +59551 -0.117156982421875 +59552 -0.216796875 +59553 -0.093719482421875 +59554 -0.128265380859375 +59555 -0.056549072265625 +59556 -0.068145751953125 +59557 -0.031280517578125 +59558 -0.0430908203125 +59559 -0.020721435546875 +59560 -0.024444580078125 +59561 -0.012725830078125 +59562 0.020721435546875 +59563 0.00665283203125 +59564 0.124481201171875 +59565 0.050994873046875 +59566 0.25787353515625 +59567 0.10797119140625 +59568 0.379119873046875 +59569 0.15985107421875 +59570 0.47991943359375 +59571 0.203094482421875 +59572 0.5281982421875 +59573 0.22406005859375 +59574 0.511138916015625 +59575 0.21728515625 +59576 0.456207275390625 +59577 0.194427490234375 +59578 0.407470703125 +59579 0.17413330078125 +59580 0.383758544921875 +59581 0.16436767578125 +59582 0.35687255859375 +59583 0.153167724609375 +59584 0.31182861328125 +59585 0.1341552734375 +59586 0.250885009765625 +59587 0.1082763671875 +59588 0.1654052734375 +59589 0.0718994140625 +59590 0.035247802734375 +59591 0.0164794921875 +59592 -0.142059326171875 +59593 -0.058990478515625 +59594 -0.33563232421875 +59595 -0.14141845703125 +59596 -0.5345458984375 +59597 -0.226104736328125 +59598 -0.72186279296875 +59599 -0.305877685546875 +59600 -0.836669921875 +59601 -0.3548583984375 +59602 -0.8326416015625 +59603 -0.353424072265625 +59604 -0.7296142578125 +59605 -0.309967041015625 +59606 -0.582550048828125 +59607 -0.247802734375 +59608 -0.440093994140625 +59609 -0.187530517578125 +59610 -0.324310302734375 +59611 -0.13848876953125 +59612 -0.20147705078125 +59613 -0.08636474609375 +59614 -0.044647216796875 +59615 -0.019744873046875 +59616 0.103973388671875 +59617 0.04345703125 +59618 0.202392578125 +59619 0.08538818359375 +59620 0.264495849609375 +59621 0.1119384765625 +59622 0.338897705078125 +59623 0.143707275390625 +59624 0.443817138671875 +59625 0.18841552734375 +59626 0.545074462890625 +59627 0.231536865234375 +59628 0.6173095703125 +59629 0.2623291015625 +59630 0.6524658203125 +59631 0.277374267578125 +59632 0.66339111328125 +59633 0.2821044921875 +59634 0.6561279296875 +59635 0.279052734375 +59636 0.606781005859375 +59637 0.258087158203125 +59638 0.501190185546875 +59639 0.213226318359375 +59640 0.352783203125 +59641 0.150177001953125 +59642 0.176544189453125 +59643 0.075286865234375 +59644 -0.034820556640625 +59645 -0.014495849609375 +59646 -0.258209228515625 +59647 -0.109375 +59648 -0.44244384765625 +59649 -0.18743896484375 +59650 -0.5753173828125 +59651 -0.24365234375 +59652 -0.65203857421875 +59653 -0.275848388671875 +59654 -0.641632080078125 +59655 -0.269866943359375 +59656 -0.562164306640625 +59657 -0.233856201171875 +59658 -0.458038330078125 +59659 -0.18792724609375 +59660 -0.350555419921875 +59661 -0.141571044921875 +59662 -0.260528564453125 +59663 -0.10406494140625 +59664 -0.192108154296875 +59665 -0.077056884765625 +59666 -0.141937255859375 +59667 -0.058746337890625 +59668 -0.1021728515625 +59669 -0.0452880859375 +59670 -0.062896728515625 +59671 -0.03192138671875 +59672 -0.011932373046875 +59673 -0.012847900390625 +59674 0.062835693359375 +59675 0.017669677734375 +59676 0.148712158203125 +59677 0.053985595703125 +59678 0.241729736328125 +59679 0.09442138671875 +59680 0.34912109375 +59681 0.142364501953125 +59682 0.457305908203125 +59683 0.191650390625 +59684 0.54388427734375 +59685 0.23199462890625 +59686 0.5728759765625 +59687 0.246917724609375 +59688 0.506591796875 +59689 0.2191162109375 +59690 0.351226806640625 +59691 0.151275634765625 +59692 0.146514892578125 +59693 0.06134033203125 +59694 -0.05523681640625 +59695 -0.027008056640625 +59696 -0.21624755859375 +59697 -0.09674072265625 +59698 -0.334930419921875 +59699 -0.147369384765625 +59700 -0.402984619140625 +59701 -0.17529296875 +59702 -0.4412841796875 +59703 -0.190155029296875 +59704 -0.49578857421875 +59705 -0.21307373046875 +59706 -0.5601806640625 +59707 -0.241241455078125 +59708 -0.600738525390625 +59709 -0.25933837890625 +59710 -0.584228515625 +59711 -0.252227783203125 +59712 -0.47930908203125 +59713 -0.20556640625 +59714 -0.27935791015625 +59715 -0.11627197265625 +59716 -0.0089111328125 +59717 0.00457763671875 +59718 0.268798828125 +59719 0.128326416015625 +59720 0.482818603515625 +59721 0.222808837890625 +59722 0.60369873046875 +59723 0.2747802734375 +59724 0.650421142578125 +59725 0.293060302734375 +59726 0.66400146484375 +59727 0.2965087890625 +59728 0.6414794921875 +59729 0.283905029296875 +59730 0.572540283203125 +59731 0.25067138671875 +59732 0.498138427734375 +59733 0.215545654296875 +59734 0.439453125 +59735 0.188262939453125 +59736 0.375518798828125 +59737 0.159271240234375 +59738 0.274505615234375 +59739 0.114044189453125 +59740 0.1087646484375 +59741 0.039886474609375 +59742 -0.099395751953125 +59743 -0.053131103515625 +59744 -0.3182373046875 +59745 -0.150634765625 +59746 -0.5489501953125 +59747 -0.2532958984375 +59748 -0.7738037109375 +59749 -0.353179931640625 +59750 -0.86383056640625 +59751 -0.42626953125 +59752 -0.870391845703125 +59753 -0.457550048828125 +59754 -0.86895751953125 +59755 -0.455230712890625 +59756 -0.861053466796875 +59757 -0.4254150390625 +59758 -0.765869140625 +59759 -0.36029052734375 +59760 -0.5301513671875 +59761 -0.2547607421875 +59762 -0.214691162109375 +59763 -0.112091064453125 +59764 0.137359619140625 +59765 0.048065185546875 +59766 0.474822998046875 +59767 0.202362060546875 +59768 0.76239013671875 +59769 0.33465576171875 +59770 0.867462158203125 +59771 0.432708740234375 +59772 0.870361328125 +59773 0.496856689453125 +59774 0.86480712890625 +59775 0.52197265625 +59776 0.831817626953125 +59777 0.510589599609375 +59778 0.677581787109375 +59779 0.473968505859375 +59780 0.495880126953125 +59781 0.41485595703125 +59782 0.30767822265625 +59783 0.341827392578125 +59784 0.116180419921875 +59785 0.255950927734375 +59786 -0.110748291015625 +59787 0.142822265625 +59788 -0.381805419921875 +59789 -0.000640869140625 +59790 -0.6572265625 +59791 -0.15496826171875 +59792 -0.857421875 +59793 -0.2928466796875 +59794 -0.870391845703125 +59795 -0.394775390625 +59796 -0.870391845703125 +59797 -0.45758056640625 +59798 -0.86444091796875 +59799 -0.493621826171875 +59800 -0.85723876953125 +59801 -0.519256591796875 +59802 -0.790008544921875 +59803 -0.526214599609375 +59804 -0.62847900390625 +59805 -0.489837646484375 +59806 -0.3956298828125 +59807 -0.40875244140625 +59808 -0.126708984375 +59809 -0.298004150390625 +59810 0.150115966796875 +59811 -0.170196533203125 +59812 0.424041748046875 +59813 -0.030731201171875 +59814 0.670623779296875 +59815 0.108062744140625 +59816 0.854522705078125 +59817 0.228485107421875 +59818 0.866485595703125 +59819 0.322479248046875 +59820 0.86920166015625 +59821 0.383087158203125 +59822 0.8653564453125 +59823 0.418609619140625 +59824 0.857147216796875 +59825 0.435211181640625 +59826 0.766845703125 +59827 0.431640625 +59828 0.628509521484375 +59829 0.410308837890625 +59830 0.462127685546875 +59831 0.36822509765625 +59832 0.297210693359375 +59833 0.3172607421875 +59834 0.14862060546875 +59835 0.26312255859375 +59836 -0.00537109375 +59837 0.195465087890625 +59838 -0.15753173828125 +59839 0.117767333984375 +59840 -0.31304931640625 +59841 0.0284423828125 +59842 -0.48876953125 +59843 -0.078887939453125 +59844 -0.6416015625 +59845 -0.182830810546875 +59846 -0.751373291015625 +59847 -0.2720947265625 +59848 -0.84619140625 +59849 -0.35723876953125 +59850 -0.861297607421875 +59851 -0.43157958984375 +59852 -0.863250732421875 +59853 -0.480072021484375 +59854 -0.856597900390625 +59855 -0.488372802734375 +59856 -0.7498779296875 +59857 -0.462066650390625 +59858 -0.624542236328125 +59859 -0.427642822265625 +59860 -0.47808837890625 +59861 -0.375152587890625 +59862 -0.253387451171875 +59863 -0.277984619140625 +59864 0.003692626953125 +59865 -0.157012939453125 +59866 0.2257080078125 +59867 -0.04345703125 +59868 0.427154541015625 +59869 0.068359375 +59870 0.643218994140625 +59871 0.193145751953125 +59872 0.855926513671875 +59873 0.326507568359375 +59874 0.870361328125 +59875 0.4420166015625 +59876 0.870361328125 +59877 0.51702880859375 +59878 0.862762451171875 +59879 0.55487060546875 +59880 0.79669189453125 +59881 0.554229736328125 +59882 0.595794677734375 +59883 0.5108642578125 +59884 0.362152099609375 +59885 0.438140869140625 +59886 0.1270751953125 +59887 0.34893798828125 +59888 -0.086944580078125 +59889 0.252960205078125 +59890 -0.2784423828125 +59891 0.151214599609375 +59892 -0.484832763671875 +59893 0.027923583984375 +59894 -0.729583740234375 +59895 -0.125579833984375 +59896 -0.86688232421875 +59897 -0.286163330078125 +59898 -0.870391845703125 +59899 -0.424896240234375 +59900 -0.86859130859375 +59901 -0.53948974609375 +59902 -0.86279296875 +59903 -0.62896728515625 +59904 -0.817962646484375 +59905 -0.677001953125 +59906 -0.6116943359375 +59907 -0.66253662109375 +59908 -0.3128662109375 +59909 -0.58209228515625 +59910 0.039398193359375 +59911 -0.4512939453125 +59912 0.422821044921875 +59913 -0.279052734375 +59914 0.805145263671875 +59915 -0.080780029296875 +59916 0.870361328125 +59917 0.111053466796875 +59918 0.870361328125 +59919 0.26934814453125 +59920 0.860015869140625 +59921 0.388946533203125 +59922 0.727935791015625 +59923 0.466552734375 +59924 0.48114013671875 +59925 0.499664306640625 +59926 0.2059326171875 +59927 0.500244140625 +59928 -0.06103515625 +59929 0.479339599609375 +59930 -0.29913330078125 +59931 0.4417724609375 +59932 -0.516204833984375 +59933 0.380279541015625 +59934 -0.7252197265625 +59935 0.287109375 +59936 -0.85980224609375 +59937 0.174072265625 +59938 -0.870391845703125 +59939 0.0576171875 +59940 -0.870391845703125 +59941 -0.048126220703125 +59942 -0.858062744140625 +59943 -0.11968994140625 +59944 -0.673004150390625 +59945 -0.1552734375 +59946 -0.42694091796875 +59947 -0.180694580078125 +59948 -0.2100830078125 +59949 -0.21771240234375 +59950 -0.0362548828125 +59951 -0.265350341796875 +59952 0.10943603515625 +59953 -0.309417724609375 +59954 0.23516845703125 +59955 -0.340087890625 +59956 0.373687744140625 +59957 -0.3370361328125 +59958 0.517791748046875 +59959 -0.30108642578125 +59960 0.602783203125 +59961 -0.262786865234375 +59962 0.635711669921875 +59963 -0.21942138671875 +59964 0.655181884765625 +59965 -0.154510498046875 +59966 0.65948486328125 +59967 -0.072723388671875 +59968 0.651275634765625 +59969 0.02215576171875 +59970 0.61846923828125 +59971 0.1182861328125 +59972 0.53753662109375 +59973 0.19769287109375 +59974 0.404144287109375 +59975 0.251617431640625 +59976 0.22186279296875 +59977 0.275299072265625 +59978 0.003997802734375 +59979 0.269287109375 +59980 -0.22100830078125 +59981 0.242340087890625 +59982 -0.42449951171875 +59983 0.204376220703125 +59984 -0.579833984375 +59985 0.16571044921875 +59986 -0.641876220703125 +59987 0.14703369140625 +59988 -0.6177978515625 +59989 0.144927978515625 +59990 -0.575531005859375 +59991 0.12774658203125 +59992 -0.526336669921875 +59993 0.092742919921875 +59994 -0.42645263671875 +59995 0.065093994140625 +59996 -0.2581787109375 +59997 0.05810546875 +59998 -0.068695068359375 +59999 0.053985595703125 +60000 0.09222412109375 +60001 0.033935546875 +60002 0.232147216796875 +60003 0.007080078125 +60004 0.3509521484375 +60005 -0.021514892578125 +60006 0.410064697265625 +60007 -0.06622314453125 +60008 0.372955322265625 +60009 -0.1412353515625 +60010 0.2554931640625 +60011 -0.23614501953125 +60012 0.10711669921875 +60013 -0.32537841796875 +60014 -0.052886962890625 +60015 -0.399169921875 +60016 -0.186279296875 +60017 -0.439697265625 +60018 -0.23291015625 +60019 -0.4195556640625 +60020 -0.209442138671875 +60021 -0.349761962890625 +60022 -0.174163818359375 +60023 -0.262359619140625 +60024 -0.126739501953125 +60025 -0.161346435546875 +60026 -0.048126220703125 +60027 -0.04193115234375 +60028 0.0426025390625 +60029 0.082061767578125 +60030 0.10748291015625 +60031 0.18780517578125 +60032 0.1409912109375 +60033 0.268707275390625 +60034 0.19708251953125 +60035 0.347869873046875 +60036 0.273651123046875 +60037 0.42181396484375 +60038 0.31768798828125 +60039 0.463104248046875 +60040 0.341094970703125 +60041 0.47698974609375 +60042 0.368011474609375 +60043 0.4755859375 +60044 0.37249755859375 +60045 0.447540283203125 +60046 0.30072021484375 +60047 0.368682861328125 +60048 0.1517333984375 +60049 0.241302490234375 +60050 -0.01470947265625 +60051 0.09783935546875 +60052 -0.1883544921875 +60053 -0.053070068359375 +60054 -0.372711181640625 +60055 -0.20941162109375 +60056 -0.51397705078125 +60057 -0.34130859375 +60058 -0.57177734375 +60059 -0.425689697265625 +60060 -0.53948974609375 +60061 -0.456512451171875 +60062 -0.43511962890625 +60063 -0.440277099609375 +60064 -0.2962646484375 +60065 -0.393768310546875 +60066 -0.161102294921875 +60067 -0.3348388671875 +60068 -0.0435791015625 +60069 -0.270294189453125 +60070 0.060394287109375 +60071 -0.198974609375 +60072 0.13665771484375 +60073 -0.1292724609375 +60074 0.170135498046875 +60075 -0.0706787109375 +60076 0.16552734375 +60077 -0.023468017578125 +60078 0.15728759765625 +60079 0.026214599609375 +60080 0.150787353515625 +60081 0.077972412109375 +60082 0.12200927734375 +60083 0.117034912109375 +60084 0.080108642578125 +60085 0.14501953125 +60086 0.05126953125 +60087 0.172210693359375 +60088 0.062896728515625 +60089 0.2099609375 +60090 0.09271240234375 +60091 0.245880126953125 +60092 0.092987060546875 +60093 0.255828857421875 +60094 0.07855224609375 +60095 0.246856689453125 +60096 0.06427001953125 +60097 0.226654052734375 +60098 0.0347900390625 +60099 0.18878173828125 +60100 -0.01171875 +60101 0.133880615234375 +60102 -0.056060791015625 +60103 0.073333740234375 +60104 -0.055511474609375 +60105 0.030303955078125 +60106 -0.010467529296875 +60107 0.007080078125 +60108 0.02508544921875 +60109 -0.020111083984375 +60110 0.025665283203125 +60111 -0.061309814453125 +60112 0.017333984375 +60113 -0.101593017578125 +60114 0.00189208984375 +60115 -0.138275146484375 +60116 -0.03173828125 +60117 -0.175384521484375 +60118 -0.071502685546875 +60119 -0.2061767578125 +60120 -0.13543701171875 +60121 -0.23907470703125 +60122 -0.219970703125 +60123 -0.27252197265625 +60124 -0.300506591796875 +60125 -0.295196533203125 +60126 -0.376312255859375 +60127 -0.30792236328125 +60128 -0.416107177734375 +60129 -0.296966552734375 +60130 -0.371124267578125 +60131 -0.240386962890625 +60132 -0.242279052734375 +60133 -0.140655517578125 +60134 -0.069732666015625 +60135 -0.0194091796875 +60136 0.125640869140625 +60137 0.111114501953125 +60138 0.31268310546875 +60139 0.233856201171875 +60140 0.45501708984375 +60141 0.329437255859375 +60142 0.554779052734375 +60143 0.39764404296875 +60144 0.61065673828125 +60145 0.43695068359375 +60146 0.610931396484375 +60147 0.441192626953125 +60148 0.531463623046875 +60149 0.398590087890625 +60150 0.3883056640625 +60151 0.317413330078125 +60152 0.23468017578125 +60153 0.2244873046875 +60154 0.095245361328125 +60155 0.133026123046875 +60156 -0.00396728515625 +60157 0.057159423828125 +60158 -0.04852294921875 +60159 0.005523681640625 +60160 -0.055145263671875 +60161 -0.028106689453125 +60162 -0.0758056640625 +60163 -0.067535400390625 +60164 -0.138702392578125 +60165 -0.125244140625 +60166 -0.209197998046875 +60167 -0.182647705078125 +60168 -0.289031982421875 +60169 -0.2396240234375 +60170 -0.37884521484375 +60171 -0.295806884765625 +60172 -0.456329345703125 +60173 -0.339630126953125 +60174 -0.51641845703125 +60175 -0.3685302734375 +60176 -0.519287109375 +60177 -0.36285400390625 +60178 -0.458251953125 +60179 -0.31982421875 +60180 -0.384796142578125 +60181 -0.266021728515625 +60182 -0.323699951171875 +60183 -0.21490478515625 +60184 -0.269287109375 +60185 -0.16485595703125 +60186 -0.1951904296875 +60187 -0.10400390625 +60188 -0.100006103515625 +60189 -0.032928466796875 +60190 -0.01055908203125 +60191 0.03363037109375 +60192 0.1033935546875 +60193 0.109649658203125 +60194 0.24908447265625 +60195 0.197784423828125 +60196 0.373199462890625 +60197 0.27069091796875 +60198 0.45806884765625 +60199 0.319091796875 +60200 0.511474609375 +60201 0.3466796875 +60202 0.565399169921875 +60203 0.36956787109375 +60204 0.61138916015625 +60205 0.383880615234375 +60206 0.5897216796875 +60207 0.3603515625 +60208 0.4906005859375 +60209 0.29486083984375 +60210 0.33148193359375 +60211 0.1971435546875 +60212 0.147796630859375 +60213 0.0859375 +60214 -0.01873779296875 +60215 -0.01678466796875 +60216 -0.140289306640625 +60217 -0.096038818359375 +60218 -0.191986083984375 +60219 -0.138397216796875 +60220 -0.184295654296875 +60221 -0.14825439453125 +60222 -0.161834716796875 +60223 -0.147247314453125 +60224 -0.166595458984375 +60225 -0.155914306640625 +60226 -0.19390869140625 +60227 -0.17169189453125 +60228 -0.22442626953125 +60229 -0.1849365234375 +60230 -0.279754638671875 +60231 -0.206634521484375 +60232 -0.3389892578125 +60233 -0.226806640625 +60234 -0.3543701171875 +60235 -0.222198486328125 +60236 -0.348175048828125 +60237 -0.204681396484375 +60238 -0.32598876953125 +60239 -0.17791748046875 +60240 -0.2581787109375 +60241 -0.12799072265625 +60242 -0.139801025390625 +60243 -0.05328369140625 +60244 0.014617919921875 +60245 0.038116455078125 +60246 0.144378662109375 +60247 0.115081787109375 +60248 0.221038818359375 +60249 0.162811279296875 +60250 0.27069091796875 +60251 0.19390869140625 +60252 0.294036865234375 +60253 0.208465576171875 +60254 0.311767578125 +60255 0.216796875 +60256 0.339141845703125 +60257 0.226715087890625 +60258 0.360260009765625 +60259 0.230804443359375 +60260 0.360504150390625 +60261 0.222137451171875 +60262 0.308380126953125 +60263 0.184783935546875 +60264 0.18170166015625 +60265 0.107757568359375 +60266 0.0047607421875 +60267 0.004302978515625 +60268 -0.17559814453125 +60269 -0.10064697265625 +60270 -0.3143310546875 +60271 -0.18310546875 +60272 -0.36785888671875 +60273 -0.21990966796875 +60274 -0.36248779296875 +60275 -0.224273681640625 +60276 -0.343536376953125 +60277 -0.21942138671875 +60278 -0.3018798828125 +60279 -0.200439453125 +60280 -0.231414794921875 +60281 -0.164031982421875 +60282 -0.117645263671875 +60283 -0.10272216796875 +60284 0.007049560546875 +60285 -0.033538818359375 +60286 0.087982177734375 +60287 0.0147705078125 +60288 0.13946533203125 +60289 0.04925537109375 +60290 0.17425537109375 +60291 0.07611083984375 +60292 0.188201904296875 +60293 0.0926513671875 +60294 0.171234130859375 +60295 0.093109130859375 +60296 0.118438720703125 +60297 0.074432373046875 +60298 0.05706787109375 +60299 0.05035400390625 +60300 -0.010711669921875 +60301 0.021575927734375 +60302 -0.0914306640625 +60303 -0.015594482421875 +60304 -0.162322998046875 +60305 -0.04949951171875 +60306 -0.194549560546875 +60307 -0.065277099609375 +60308 -0.1492919921875 +60309 -0.042755126953125 +60310 -0.02166748046875 +60311 0.020721435546875 +60312 0.124053955078125 +60313 0.091949462890625 +60314 0.211151123046875 +60315 0.131317138671875 +60316 0.240447998046875 +60317 0.1396484375 +60318 0.242218017578125 +60319 0.133026123046875 +60320 0.2257080078125 +60321 0.116729736328125 +60322 0.194366455078125 +60323 0.092987060546875 +60324 0.115509033203125 +60325 0.045196533203125 +60326 0.0128173828125 +60327 -0.013946533203125 +60328 -0.053802490234375 +60329 -0.05303955078125 +60330 -0.110626220703125 +60331 -0.08551025390625 +60332 -0.199493408203125 +60333 -0.133026123046875 +60334 -0.29437255859375 +60335 -0.182037353515625 +60336 -0.33221435546875 +60337 -0.199798583984375 +60338 -0.27972412109375 +60339 -0.169158935546875 +60340 -0.185333251953125 +60341 -0.115509033203125 +60342 -0.128204345703125 +60343 -0.080291748046875 +60344 -0.115692138671875 +60345 -0.067657470703125 +60346 -0.116455078125 +60347 -0.061676025390625 +60348 -0.105926513671875 +60349 -0.0499267578125 +60350 -0.053955078125 +60351 -0.017059326171875 +60352 0.048797607421875 +60353 0.04144287109375 +60354 0.157318115234375 +60355 0.101898193359375 +60356 0.212005615234375 +60357 0.133148193359375 +60358 0.218475341796875 +60359 0.13800048828125 +60360 0.23724365234375 +60361 0.147857666015625 +60362 0.30535888671875 +60363 0.182037353515625 +60364 0.38128662109375 +60365 0.21905517578125 +60366 0.404449462890625 +60367 0.227569580078125 +60368 0.3944091796875 +60369 0.217987060546875 +60370 0.3885498046875 +60371 0.209991455078125 +60372 0.362640380859375 +60373 0.1912841796875 +60374 0.27362060546875 +60375 0.1397705078125 +60376 0.11712646484375 +60377 0.053466796875 +60378 -0.054901123046875 +60379 -0.04034423828125 +60380 -0.19085693359375 +60381 -0.1146240234375 +60382 -0.28570556640625 +60383 -0.166595458984375 +60384 -0.339263916015625 +60385 -0.196044921875 +60386 -0.3775634765625 +60387 -0.2164306640625 +60388 -0.445709228515625 +60389 -0.251190185546875 +60390 -0.535064697265625 +60391 -0.295928955078125 +60392 -0.629058837890625 +60393 -0.3421630859375 +60394 -0.697601318359375 +60395 -0.3743896484375 +60396 -0.70391845703125 +60397 -0.373687744140625 +60398 -0.6424560546875 +60399 -0.337432861328125 +60400 -0.491241455078125 +60401 -0.254425048828125 +60402 -0.265716552734375 +60403 -0.1329345703125 +60404 -0.023712158203125 +60405 -0.003265380859375 +60406 0.201751708984375 +60407 0.1171875 +60408 0.375823974609375 +60409 0.21014404296875 +60410 0.485076904296875 +60411 0.26849365234375 +60412 0.56884765625 +60413 0.31268310546875 +60414 0.634765625 +60415 0.346649169921875 +60416 0.63763427734375 +60417 0.346435546875 +60418 0.5660400390625 +60419 0.305450439453125 +60420 0.4720458984375 +60421 0.251983642578125 +60422 0.40692138671875 +60423 0.214599609375 +60424 0.3778076171875 +60425 0.197479248046875 +60426 0.376953125 +60427 0.196502685546875 +60428 0.371978759765625 +60429 0.19390869140625 +60430 0.313140869140625 +60431 0.1622314453125 +60432 0.184417724609375 +60433 0.092559814453125 +60434 0.011199951171875 +60435 -0.0010986328125 +60436 -0.171051025390625 +60437 -0.09930419921875 +60438 -0.33740234375 +60439 -0.188446044921875 +60440 -0.47198486328125 +60441 -0.259918212890625 +60442 -0.560394287109375 +60443 -0.305938720703125 +60444 -0.58056640625 +60445 -0.31451416015625 +60446 -0.54754638671875 +60447 -0.2940673828125 +60448 -0.508575439453125 +60449 -0.270843505859375 +60450 -0.459503173828125 +60451 -0.24261474609375 +60452 -0.394378662109375 +60453 -0.206146240234375 +60454 -0.35260009765625 +60455 -0.183197021484375 +60456 -0.31170654296875 +60457 -0.161346435546875 +60458 -0.197418212890625 +60459 -0.099517822265625 +60460 -0.007965087890625 +60461 0.0032958984375 +60462 0.207489013671875 +60463 0.120086669921875 +60464 0.409210205078125 +60465 0.229034423828125 +60466 0.57208251953125 +60467 0.316436767578125 +60468 0.66595458984375 +60469 0.36578369140625 +60470 0.65875244140625 +60471 0.3594970703125 +60472 0.56744384765625 +60473 0.30706787109375 +60474 0.431396484375 +60475 0.230316162109375 +60476 0.29443359375 +60477 0.153533935546875 +60478 0.182464599609375 +60479 0.091094970703125 +60480 0.06365966796875 +60481 0.025421142578125 +60482 -0.075958251953125 +60483 -0.051177978515625 +60484 -0.189422607421875 +60485 -0.11285400390625 +60486 -0.271942138671875 +60487 -0.156982421875 +60488 -0.342529296875 +60489 -0.19415283203125 +60490 -0.364166259765625 +60491 -0.204071044921875 +60492 -0.327239990234375 +60493 -0.181549072265625 +60494 -0.2769775390625 +60495 -0.15167236328125 +60496 -0.253692626953125 +60497 -0.136810302734375 +60498 -0.24365234375 +60499 -0.129486083984375 +60500 -0.1983642578125 +60501 -0.10302734375 +60502 -0.116241455078125 +60503 -0.056610107421875 +60504 -0.036834716796875 +60505 -0.012115478515625 +60506 0.034881591796875 +60507 0.02764892578125 +60508 0.09124755859375 +60509 0.0584716796875 +60510 0.10888671875 +60511 0.0675048828125 +60512 0.125518798828125 +60513 0.075592041015625 +60514 0.15771484375 +60515 0.091949462890625 +60516 0.17828369140625 +60517 0.10162353515625 +60518 0.17108154296875 +60519 0.0958251953125 +60520 0.129974365234375 +60521 0.0712890625 +60522 0.082427978515625 +60523 0.04327392578125 +60524 0.027679443359375 +60525 0.011474609375 +60526 -0.065643310546875 +60527 -0.04132080078125 +60528 -0.15936279296875 +60529 -0.093994140625 +60530 -0.21307373046875 +60531 -0.12420654296875 +60532 -0.234649658203125 +60533 -0.13629150390625 +60534 -0.2001953125 +60535 -0.117034912109375 +60536 -0.119171142578125 +60537 -0.07171630859375 +60538 -0.024749755859375 +60539 -0.0186767578125 +60540 0.085784912109375 +60541 0.043487548828125 +60542 0.178131103515625 +60543 0.09576416015625 +60544 0.215576171875 +60545 0.11785888671875 +60546 0.211456298828125 +60547 0.117034912109375 +60548 0.17523193359375 +60549 0.09844970703125 +60550 0.128753662109375 +60551 0.0740966796875 +60552 0.1019287109375 +60553 0.06036376953125 +60554 0.0743408203125 +60555 0.04595947265625 +60556 0.04327392578125 +60557 0.02935791015625 +60558 0.038177490234375 +60559 0.02679443359375 +60560 0.076263427734375 +60561 0.047760009765625 +60562 0.14105224609375 +60563 0.0831298828125 +60564 0.186431884765625 +60565 0.10748291015625 +60566 0.188812255859375 +60567 0.10784912109375 +60568 0.1390380859375 +60569 0.079254150390625 +60570 0.041778564453125 +60571 0.02435302734375 +60572 -0.079437255859375 +60573 -0.04376220703125 +60574 -0.219390869140625 +60575 -0.1221923828125 +60576 -0.367828369140625 +60577 -0.205169677734375 +60578 -0.494873046875 +60579 -0.27618408203125 +60580 -0.556243896484375 +60581 -0.31072998046875 +60582 -0.508697509765625 +60583 -0.284912109375 +60584 -0.3756103515625 +60585 -0.211639404296875 +60586 -0.218902587890625 +60587 -0.125091552734375 +60588 -0.063751220703125 +60589 -0.039154052734375 +60590 0.091552734375 +60591 0.047027587890625 +60592 0.23602294921875 +60593 0.127410888671875 +60594 0.342987060546875 +60595 0.187225341796875 +60596 0.39520263671875 +60597 0.2169189453125 +60598 0.389373779296875 +60599 0.214630126953125 +60600 0.324249267578125 +60601 0.179595947265625 +60602 0.224090576171875 +60603 0.125152587890625 +60604 0.124267578125 +60605 0.07080078125 +60606 0.037078857421875 +60607 0.023284912109375 +60608 -0.010101318359375 +60609 -0.002288818359375 +60610 -0.019439697265625 +60611 -0.00714111328125 +60612 -0.022796630859375 +60613 -0.008880615234375 +60614 -0.001556396484375 +60615 0.002716064453125 +60616 0.056304931640625 +60617 0.034332275390625 +60618 0.106719970703125 +60619 0.0616455078125 +60620 0.096893310546875 +60621 0.055572509765625 +60622 0.042694091796875 +60623 0.024932861328125 +60624 -0.018035888671875 +60625 -0.009368896484375 +60626 -0.07586669921875 +60627 -0.04205322265625 +60628 -0.11944580078125 +60629 -0.06683349609375 +60630 -0.15972900390625 +60631 -0.0897216796875 +60632 -0.202606201171875 +60633 -0.11395263671875 +60634 -0.24859619140625 +60635 -0.139739990234375 +60636 -0.30517578125 +60637 -0.17120361328125 +60638 -0.36212158203125 +60639 -0.20269775390625 +60640 -0.39141845703125 +60641 -0.21875 +60642 -0.35528564453125 +60643 -0.19854736328125 +60644 -0.249969482421875 +60645 -0.1400146484375 +60646 -0.092864990234375 +60647 -0.05279541015625 +60648 0.08905029296875 +60649 0.048187255859375 +60650 0.2352294921875 +60651 0.12945556640625 +60652 0.318817138671875 +60653 0.176177978515625 +60654 0.358642578125 +60655 0.19873046875 +60656 0.347747802734375 +60657 0.1932373046875 +60658 0.28564453125 +60659 0.159393310546875 +60660 0.223175048828125 +60661 0.125244140625 +60662 0.196746826171875 +60663 0.11083984375 +60664 0.179840087890625 +60665 0.101593017578125 +60666 0.155548095703125 +60667 0.088134765625 +60668 0.151214599609375 +60669 0.0855712890625 +60670 0.156951904296875 +60671 0.088470458984375 +60672 0.13177490234375 +60673 0.07403564453125 +60674 0.100799560546875 +60675 0.056610107421875 +60676 0.087127685546875 +60677 0.04913330078125 +60678 0.05487060546875 +60679 0.030792236328125 +60680 -0.009002685546875 +60681 -0.005889892578125 +60682 -0.10400390625 +60683 -0.06060791015625 +60684 -0.229400634765625 +60685 -0.132965087890625 +60686 -0.35552978515625 +60687 -0.205657958984375 +60688 -0.441925048828125 +60689 -0.255096435546875 +60690 -0.473846435546875 +60691 -0.27276611328125 +60692 -0.464813232421875 +60693 -0.266632080078125 +60694 -0.419097900390625 +60695 -0.2392578125 +60696 -0.334320068359375 +60697 -0.1893310546875 +60698 -0.227935791015625 +60699 -0.127044677734375 +60700 -0.12347412109375 +60701 -0.066162109375 +60702 -0.02764892578125 +60703 -0.010589599609375 +60704 0.077667236328125 +60705 0.050262451171875 +60706 0.2132568359375 +60707 0.1285400390625 +60708 0.38885498046875 +60709 0.22998046875 +60710 0.582794189453125 +60711 0.34197998046875 +60712 0.734039306640625 +60713 0.428985595703125 +60714 0.800140380859375 +60715 0.466278076171875 +60716 0.7783203125 +60717 0.452301025390625 +60718 0.6651611328125 +60719 0.3851318359375 +60720 0.45965576171875 +60721 0.264251708984375 +60722 0.199188232421875 +60723 0.111541748046875 +60724 -0.050689697265625 +60725 -0.03466796875 +60726 -0.23297119140625 +60727 -0.14111328125 +60728 -0.33013916015625 +60729 -0.19757080078125 +60730 -0.368408203125 +60731 -0.2193603515625 +60732 -0.378936767578125 +60733 -0.224700927734375 +60734 -0.376983642578125 +60735 -0.22259521484375 +60736 -0.37969970703125 +60737 -0.22314453125 +60738 -0.391510009765625 +60739 -0.228973388671875 +60740 -0.385345458984375 +60741 -0.224334716796875 +60742 -0.3419189453125 +60743 -0.197998046875 +60744 -0.28289794921875 +60745 -0.16265869140625 +60746 -0.251617431640625 +60747 -0.1436767578125 +60748 -0.266143798828125 +60749 -0.151611328125 +60750 -0.273345947265625 +60751 -0.155487060546875 +60752 -0.216796875 +60753 -0.122344970703125 +60754 -0.128265380859375 +60755 -0.07073974609375 +60756 -0.068145751953125 +60757 -0.035919189453125 +60758 -0.0430908203125 +60759 -0.021728515625 +60760 -0.024444580078125 +60761 -0.011444091796875 +60762 0.020721435546875 +60763 0.01422119140625 +60764 0.124481201171875 +60765 0.074005126953125 +60766 0.25787353515625 +60767 0.151031494140625 +60768 0.379119873046875 +60769 0.220947265625 +60770 0.47991943359375 +60771 0.27899169921875 +60772 0.5281982421875 +60773 0.30645751953125 +60774 0.511138916015625 +60775 0.2958984375 +60776 0.456207275390625 +60777 0.26336669921875 +60778 0.407470703125 +60779 0.234649658203125 +60780 0.383758544921875 +60781 0.220733642578125 +60782 0.35687255859375 +60783 0.20513916015625 +60784 0.31182861328125 +60785 0.179107666015625 +60786 0.250885009765625 +60787 0.1439208984375 +60788 0.1654052734375 +60789 0.09454345703125 +60790 0.035247802734375 +60791 0.019195556640625 +60792 -0.142059326171875 +60793 -0.0836181640625 +60794 -0.33563232421875 +60795 -0.195892333984375 +60796 -0.5345458984375 +60797 -0.311279296875 +60798 -0.72186279296875 +60799 -0.419952392578125 +60800 -0.836669921875 +60801 -0.486358642578125 +60802 -0.8326416015625 +60803 -0.483489990234375 +60804 -0.7296142578125 +60805 -0.4229736328125 +60806 -0.582550048828125 +60807 -0.336944580078125 +60808 -0.440093994140625 +60809 -0.2537841796875 +60810 -0.324310302734375 +60811 -0.186370849609375 +60812 -0.20147705078125 +60813 -0.114990234375 +60814 -0.044647216796875 +60815 -0.02386474609375 +60816 0.103973388671875 +60817 0.062347412109375 +60818 0.202392578125 +60819 0.119171142578125 +60820 0.264495849609375 +60821 0.154754638671875 +60822 0.338897705078125 +60823 0.197509765625 +60824 0.443817138671875 +60825 0.25811767578125 +60826 0.545074462890625 +60827 0.316680908203125 +60828 0.6173095703125 +60829 0.3583984375 +60830 0.6524658203125 +60831 0.378570556640625 +60832 0.66339111328125 +60833 0.384735107421875 +60834 0.6561279296875 +60835 0.38043212890625 +60836 0.606781005859375 +60837 0.3516845703125 +60838 0.501190185546875 +60839 0.29022216796875 +60840 0.352783203125 +60841 0.203857421875 +60842 0.176544189453125 +60843 0.101318359375 +60844 -0.034820556640625 +60845 -0.021636962890625 +60846 -0.258209228515625 +60847 -0.151519775390625 +60848 -0.44244384765625 +60849 -0.25848388671875 +60850 -0.5753173828125 +60851 -0.33544921875 +60852 -0.65203857421875 +60853 -0.379669189453125 +60854 -0.641632080078125 +60855 -0.373046875 +60856 -0.562164306640625 +60857 -0.326202392578125 +60858 -0.458038330078125 +60859 -0.265106201171875 +60860 -0.350555419921875 +60861 -0.202178955078125 +60862 -0.260528564453125 +60863 -0.149566650390625 +60864 -0.192108154296875 +60865 -0.109710693359375 +60866 -0.141937255859375 +60867 -0.08062744140625 +60868 -0.1021728515625 +60869 -0.057708740234375 +60870 -0.062896728515625 +60871 -0.03515625 +60872 -0.011932373046875 +60873 -0.005859375 +60874 0.062835693359375 +60875 0.03729248046875 +60876 0.148712158203125 +60877 0.0869140625 +60878 0.241729736328125 +60879 0.14068603515625 +60880 0.34912109375 +60881 0.202880859375 +60882 0.457305908203125 +60883 0.265594482421875 +60884 0.54388427734375 +60885 0.3157958984375 +60886 0.5728759765625 +60887 0.332489013671875 +60888 0.506591796875 +60889 0.293670654296875 +60890 0.351226806640625 +60891 0.202972412109375 +60892 0.146514892578125 +60893 0.08355712890625 +60894 -0.05523681640625 +60895 -0.034027099609375 +60896 -0.21624755859375 +60897 -0.127716064453125 +60898 -0.334930419921875 +60899 -0.19659423828125 +60900 -0.402984619140625 +60901 -0.23583984375 +60902 -0.4412841796875 +60903 -0.257659912109375 +60904 -0.49578857421875 +60905 -0.288909912109375 +60906 -0.5601806640625 +60907 -0.325958251953125 +60908 -0.600738525390625 +60909 -0.349151611328125 +60910 -0.584228515625 +60911 -0.339111328125 +60912 -0.47930908203125 +60913 -0.27752685546875 +60914 -0.27935791015625 +60915 -0.16058349609375 +60916 -0.0089111328125 +60917 -0.00262451171875 +60918 0.268798828125 +60919 0.159423828125 +60920 0.482818603515625 +60921 0.284149169921875 +60922 0.60369873046875 +60923 0.3543701171875 +60924 0.650421142578125 +60925 0.38116455078125 +60926 0.66400146484375 +60927 0.3885498046875 +60928 0.6414794921875 +60929 0.37457275390625 +60930 0.572540283203125 +60931 0.333343505859375 +60932 0.498138427734375 +60933 0.2899169921875 +60934 0.439453125 +60935 0.257110595703125 +60936 0.375518798828125 +60937 0.221771240234375 +60938 0.274505615234375 +60939 0.163970947265625 +60940 0.1087646484375 +60941 0.06640625 +60942 -0.099395751953125 +60943 -0.05743408203125 +60944 -0.3182373046875 +60945 -0.188201904296875 +60946 -0.5489501953125 +60947 -0.326873779296875 +60948 -0.7738037109375 +60949 -0.462677001953125 +60950 -0.86383056640625 +60951 -0.563140869140625 +60952 -0.870391845703125 +60953 -0.607818603515625 +60954 -0.86895751953125 +60955 -0.607635498046875 +60956 -0.861053466796875 +60957 -0.570648193359375 +60958 -0.765869140625 +60959 -0.486114501953125 +60960 -0.5301513671875 +60961 -0.34698486328125 +60962 -0.214691162109375 +60963 -0.157470703125 +60964 0.137359619140625 +60965 0.05609130859375 +60966 0.474822998046875 +60967 0.262298583984375 +60968 0.76239013671875 +60969 0.439453125 +60970 0.867462158203125 +60971 0.571136474609375 +60972 0.870361328125 +60973 0.65777587890625 +60974 0.86480712890625 +60975 0.692413330078125 +60976 0.831817626953125 +60977 0.678436279296875 +60978 0.677581787109375 +60979 0.630950927734375 +60980 0.495880126953125 +60981 0.55352783203125 +60982 0.30767822265625 +60983 0.45758056640625 +60984 0.116180419921875 +60985 0.34442138671875 +60986 -0.110748291015625 +60987 0.194427490234375 +60988 -0.381805419921875 +60989 0.003204345703125 +60990 -0.6572265625 +60991 -0.202972412109375 +60992 -0.857421875 +60993 -0.38739013671875 +60994 -0.870391845703125 +60995 -0.52374267578125 +60996 -0.870391845703125 +60997 -0.6077880859375 +60998 -0.86444091796875 +60999 -0.65625 +61000 -0.85723876953125 +61001 -0.69122314453125 +61002 -0.790008544921875 +61003 -0.701507568359375 +61004 -0.62847900390625 +61005 -0.65374755859375 +61006 -0.3956298828125 +61007 -0.5460205078125 +61008 -0.126708984375 +61009 -0.398529052734375 +61010 0.150115966796875 +61011 -0.2281494140625 +61012 0.424041748046875 +61013 -0.04205322265625 +61014 0.670623779296875 +61015 0.143218994140625 +61016 0.854522705078125 +61017 0.303924560546875 +61018 0.866485595703125 +61019 0.42926025390625 +61020 0.86920166015625 +61021 0.5098876953125 +61022 0.8653564453125 +61023 0.557098388671875 +61024 0.857147216796875 +61025 0.5792236328125 +61026 0.766845703125 +61027 0.574615478515625 +61028 0.628509521484375 +61029 0.546478271484375 +61030 0.462127685546875 +61031 0.49072265625 +61032 0.297210693359375 +61033 0.42327880859375 +61034 0.14862060546875 +61035 0.351776123046875 +61036 -0.00537109375 +61037 0.262176513671875 +61038 -0.15753173828125 +61039 0.1590576171875 +61040 -0.31304931640625 +61041 0.0401611328125 +61042 -0.48876953125 +61043 -0.10321044921875 +61044 -0.6416015625 +61045 -0.24224853515625 +61046 -0.751373291015625 +61047 -0.36181640625 +61048 -0.84619140625 +61049 -0.476165771484375 +61050 -0.861297607421875 +61051 -0.57635498046875 +61052 -0.863250732421875 +61053 -0.64202880859375 +61054 -0.856597900390625 +61055 -0.653778076171875 +61056 -0.7498779296875 +61057 -0.619140625 +61058 -0.624542236328125 +61059 -0.57379150390625 +61060 -0.47808837890625 +61061 -0.504180908203125 +61062 -0.253387451171875 +61063 -0.37432861328125 +61064 0.003692626953125 +61065 -0.21234130859375 +61066 0.2257080078125 +61067 -0.060302734375 +61068 0.427154541015625 +61069 0.089508056640625 +61070 0.643218994140625 +61071 0.257049560546875 +61072 0.855926513671875 +61073 0.4364013671875 +61074 0.870361328125 +61075 0.5919189453125 +61076 0.870361328125 +61077 0.69305419921875 +61078 0.862762451171875 +61079 0.744293212890625 +61080 0.79669189453125 +61081 0.74383544921875 +61082 0.595794677734375 +61083 0.6859130859375 +61084 0.362152099609375 +61085 0.58856201171875 +61086 0.1270751953125 +61087 0.469085693359375 +61088 -0.086944580078125 +61089 0.340545654296875 +61090 -0.2784423828125 +61091 0.204254150390625 +61092 -0.484832763671875 +61093 0.038818359375 +61094 -0.729583740234375 +61095 -0.16754150390625 +61096 -0.86688232421875 +61097 -0.38360595703125 +61098 -0.870391845703125 +61099 -0.57037353515625 +61100 -0.86859130859375 +61101 -0.72479248046875 +61102 -0.86279296875 +61103 -0.84552001953125 +61104 -0.817962646484375 +61105 -0.860595703125 +61106 -0.6116943359375 +61107 -0.8585205078125 +61108 -0.3128662109375 +61109 -0.78424072265625 +61110 0.039398193359375 +61111 -0.60968017578125 +61112 0.422821044921875 +61113 -0.380126953125 +61114 0.805145263671875 +61115 -0.116119384765625 +61116 0.870361328125 +61117 0.140289306640625 +61118 0.870361328125 +61119 0.353851318359375 +61120 0.860015869140625 +61121 0.5172119140625 +61122 0.727935791015625 +61123 0.62548828125 +61124 0.48114013671875 +61125 0.675079345703125 +61126 0.2059326171875 +61127 0.68072509765625 +61128 -0.06103515625 +61129 0.656219482421875 +61130 -0.29913330078125 +61131 0.607635498046875 +61132 -0.516204833984375 +61133 0.5260009765625 +61134 -0.7252197265625 +61135 0.401824951171875 +61136 -0.85980224609375 +61137 0.25054931640625 +61138 -0.870391845703125 +61139 0.09344482421875 +61140 -0.870391845703125 +61141 -0.051025390625 +61142 -0.858062744140625 +61143 -0.152587890625 +61144 -0.673004150390625 +61145 -0.20831298828125 +61146 -0.42694091796875 +61147 -0.250213623046875 +61148 -0.2100830078125 +61149 -0.30523681640625 +61150 -0.0362548828125 +61151 -0.37176513671875 +61152 0.10943603515625 +61153 -0.43157958984375 +61154 0.23516845703125 +61155 -0.472137451171875 +61156 0.373687744140625 +61157 -0.4677734375 +61158 0.517791748046875 +61159 -0.4195556640625 +61160 0.602783203125 +61161 -0.366302490234375 +61162 0.635711669921875 +61163 -0.304901123046875 +61164 0.655181884765625 +61165 -0.2149658203125 +61166 0.65948486328125 +61167 -0.102874755859375 +61168 0.651275634765625 +61169 0.026123046875 +61170 0.61846923828125 +61171 0.15655517578125 +61172 0.53753662109375 +61173 0.26519775390625 +61174 0.404144287109375 +61175 0.340576171875 +61176 0.22186279296875 +61177 0.3763427734375 +61178 0.003997802734375 +61179 0.372894287109375 +61180 -0.22100830078125 +61181 0.341064453125 +61182 -0.42449951171875 +61183 0.293365478515625 +61184 -0.579833984375 +61185 0.2431640625 +61186 -0.641876220703125 +61187 0.217437744140625 +61188 -0.6177978515625 +61189 0.211517333984375 +61190 -0.575531005859375 +61191 0.183990478515625 +61192 -0.526336669921875 +61193 0.131805419921875 +61194 -0.42645263671875 +61195 0.08892822265625 +61196 -0.2581787109375 +61197 0.073516845703125 +61198 -0.068695068359375 +61199 0.062408447265625 +61200 0.09222412109375 +61201 0.030975341796875 +61202 0.232147216796875 +61203 -0.008392333984375 +61204 0.3509521484375 +61205 -0.048858642578125 +61206 0.410064697265625 +61207 -0.109375 +61208 0.372955322265625 +61209 -0.208770751953125 +61210 0.2554931640625 +61211 -0.333343505859375 +61212 0.10711669921875 +61213 -0.449249267578125 +61214 -0.052886962890625 +61215 -0.54376220703125 +61216 -0.186279296875 +61217 -0.59344482421875 +61218 -0.23291015625 +61219 -0.562164306640625 +61220 -0.209442138671875 +61221 -0.46478271484375 +61222 -0.174163818359375 +61223 -0.344146728515625 +61224 -0.126739501953125 +61225 -0.205841064453125 +61226 -0.048126220703125 +61227 -0.043670654296875 +61228 0.0426025390625 +61229 0.123809814453125 +61230 0.10748291015625 +61231 0.26617431640625 +61232 0.1409912109375 +61233 0.374603271484375 +61234 0.19708251953125 +61235 0.479705810546875 +61236 0.273651123046875 +61237 0.576904296875 +61238 0.31768798828125 +61239 0.629852294921875 +61240 0.341094970703125 +61241 0.645599365234375 +61242 0.368011474609375 +61243 0.640472412109375 +61244 0.37249755859375 +61245 0.59954833984375 +61246 0.30072021484375 +61247 0.490936279296875 +61248 0.1517333984375 +61249 0.31793212890625 +61250 -0.01470947265625 +61251 0.123809814453125 +61252 -0.1883544921875 +61253 -0.079742431640625 +61254 -0.372711181640625 +61255 -0.2899169921875 +61256 -0.51397705078125 +61257 -0.4669189453125 +61258 -0.57177734375 +61259 -0.580047607421875 +61260 -0.53948974609375 +61261 -0.6212158203125 +61262 -0.43511962890625 +61263 -0.59906005859375 +61264 -0.2962646484375 +61265 -0.53594970703125 +61266 -0.161102294921875 +61267 -0.455718994140625 +61268 -0.0435791015625 +61269 -0.367523193359375 +61270 0.060394287109375 +61271 -0.26995849609375 +61272 0.13665771484375 +61273 -0.174346923828125 +61274 0.170135498046875 +61275 -0.093414306640625 +61276 0.16552734375 +61277 -0.027740478515625 +61278 0.15728759765625 +61279 0.04095458984375 +61280 0.150787353515625 +61281 0.11199951171875 +61282 0.12200927734375 +61283 0.165679931640625 +61284 0.080108642578125 +61285 0.20404052734375 +61286 0.05126953125 +61287 0.24066162109375 +61288 0.062896728515625 +61289 0.2906494140625 +61290 0.09271240234375 +61291 0.337554931640625 +61292 0.092987060546875 +61293 0.349395751953125 +61294 0.07855224609375 +61295 0.33563232421875 +61296 0.06427001953125 +61297 0.30657958984375 +61298 0.0347900390625 +61299 0.253814697265625 +61300 -0.01171875 +61301 0.1783447265625 +61302 -0.056060791015625 +61303 0.095428466796875 +61304 -0.055511474609375 +61305 0.03594970703125 +61306 -0.010467529296875 +61307 0.003082275390625 +61308 0.02508544921875 +61309 -0.034637451171875 +61310 0.025665283203125 +61311 -0.0904541015625 +61312 0.017333984375 +61313 -0.144561767578125 +61314 0.00189208984375 +61315 -0.193359375 +61316 -0.03173828125 +61317 -0.242218017578125 +61318 -0.071502685546875 +61319 -0.282196044921875 +61320 -0.13543701171875 +61321 -0.3245849609375 +61322 -0.219970703125 +61323 -0.36737060546875 +61324 -0.300506591796875 +61325 -0.3956298828125 +61326 -0.376312255859375 +61327 -0.4105224609375 +61328 -0.416107177734375 +61329 -0.393951416015625 +61330 -0.371124267578125 +61331 -0.316864013671875 +61332 -0.242279052734375 +61333 -0.1826171875 +61334 -0.069732666015625 +61335 -0.020111083984375 +61336 0.125640869140625 +61337 0.154327392578125 +61338 0.31268310546875 +61339 0.318023681640625 +61340 0.45501708984375 +61341 0.445220947265625 +61342 0.554779052734375 +61343 0.535614013671875 +61344 0.61065673828125 +61345 0.58721923828125 +61346 0.610931396484375 +61347 0.5919189453125 +61348 0.531463623046875 +61349 0.534149169921875 +61350 0.3883056640625 +61351 0.424957275390625 +61352 0.23468017578125 +61353 0.29998779296875 +61354 0.095245361328125 +61355 0.176910400390625 +61356 -0.00396728515625 +61357 0.074554443359375 +61358 -0.04852294921875 +61359 0.004486083984375 +61360 -0.055145263671875 +61361 -0.041748046875 +61362 -0.0758056640625 +61363 -0.095550537109375 +61364 -0.138702392578125 +61365 -0.17303466796875 +61366 -0.209197998046875 +61367 -0.249847412109375 +61368 -0.289031982421875 +61369 -0.325592041015625 +61370 -0.37884521484375 +61371 -0.399566650390625 +61372 -0.456329345703125 +61373 -0.4566650390625 +61374 -0.51641845703125 +61375 -0.493499755859375 +61376 -0.519287109375 +61377 -0.484649658203125 +61378 -0.458251953125 +61379 -0.4266357421875 +61380 -0.384796142578125 +61381 -0.354034423828125 +61382 -0.323699951171875 +61383 -0.284423828125 +61384 -0.269287109375 +61385 -0.215911865234375 +61386 -0.1951904296875 +61387 -0.133331298828125 +61388 -0.100006103515625 +61389 -0.037689208984375 +61390 -0.01055908203125 +61391 0.0517578125 +61392 0.1033935546875 +61393 0.1529541015625 +61394 0.24908447265625 +61395 0.269256591796875 +61396 0.373199462890625 +61397 0.365081787109375 +61398 0.45806884765625 +61399 0.428314208984375 +61400 0.511474609375 +61401 0.463714599609375 +61402 0.565399169921875 +61403 0.492218017578125 +61404 0.61138916015625 +61405 0.5089111328125 +61406 0.5897216796875 +61407 0.475982666015625 +61408 0.4906005859375 +61409 0.388275146484375 +61410 0.33148193359375 +61411 0.258544921875 +61412 0.147796630859375 +61413 0.11126708984375 +61414 -0.01873779296875 +61415 -0.024932861328125 +61416 -0.140289306640625 +61417 -0.130462646484375 +61418 -0.191986083984375 +61419 -0.187774658203125 +61420 -0.184295654296875 +61421 -0.20245361328125 +61422 -0.161834716796875 +61423 -0.20245361328125 +61424 -0.166595458984375 +61425 -0.21435546875 +61426 -0.19390869140625 +61427 -0.23480224609375 +61428 -0.22442626953125 +61429 -0.251251220703125 +61430 -0.279754638671875 +61431 -0.278106689453125 +61432 -0.3389892578125 +61433 -0.302459716796875 +61434 -0.3543701171875 +61435 -0.294281005859375 +61436 -0.348175048828125 +61437 -0.26910400390625 +61438 -0.32598876953125 +61439 -0.231781005859375 +61440 -0.2581787109375 +61441 -0.1644287109375 +61442 -0.139801025390625 +61443 -0.065093994140625 +61444 0.014617919921875 +61445 0.055633544921875 +61446 0.144378662109375 +61447 0.1572265625 +61448 0.221038818359375 +61449 0.220367431640625 +61450 0.27069091796875 +61451 0.261383056640625 +61452 0.294036865234375 +61453 0.280426025390625 +61454 0.311767578125 +61455 0.29083251953125 +61456 0.339141845703125 +61457 0.3028564453125 +61458 0.360260009765625 +61459 0.30694580078125 +61460 0.360504150390625 +61461 0.294189453125 +61462 0.308380126953125 +61463 0.2437744140625 +61464 0.18170166015625 +61465 0.14141845703125 +61466 0.0047607421875 +61467 0.0045166015625 +61468 -0.17559814453125 +61469 -0.134246826171875 +61470 -0.3143310546875 +61471 -0.243438720703125 +61472 -0.36785888671875 +61473 -0.29266357421875 +61474 -0.36248779296875 +61475 -0.2991943359375 +61476 -0.343536376953125 +61477 -0.2933349609375 +61478 -0.3018798828125 +61479 -0.26861572265625 +61480 -0.231414794921875 +61481 -0.220794677734375 +61482 -0.117645263671875 +61483 -0.140106201171875 +61484 0.007049560546875 +61485 -0.048828125 +61486 0.087982177734375 +61487 0.015411376953125 +61488 0.13946533203125 +61489 0.061767578125 +61490 0.17425537109375 +61491 0.0982666015625 +61492 0.188201904296875 +61493 0.121307373046875 +61494 0.171234130859375 +61495 0.123291015625 +61496 0.118438720703125 +61497 0.100128173828125 +61498 0.05706787109375 +61499 0.0697021484375 +61500 -0.010711669921875 +61501 0.032867431640625 +61502 -0.0914306640625 +61503 -0.015228271484375 +61504 -0.162322998046875 +61505 -0.059356689453125 +61506 -0.194549560546875 +61507 -0.080078125 +61508 -0.1492919921875 +61509 -0.050994873046875 +61510 -0.02166748046875 +61511 0.031341552734375 +61512 0.124053955078125 +61513 0.12359619140625 +61514 0.211151123046875 +61515 0.174041748046875 +61516 0.240447998046875 +61517 0.183807373046875 +61518 0.242218017578125 +61519 0.17401123046875 +61520 0.2257080078125 +61521 0.151611328125 +61522 0.194366455078125 +61523 0.119537353515625 +61524 0.115509033203125 +61525 0.05615234375 +61526 0.0128173828125 +61527 -0.02191162109375 +61528 -0.053802490234375 +61529 -0.073516845703125 +61530 -0.110626220703125 +61531 -0.116241455078125 +61532 -0.199493408203125 +61533 -0.17840576171875 +61534 -0.29437255859375 +61535 -0.242279052734375 +61536 -0.33221435546875 +61537 -0.26507568359375 +61538 -0.27972412109375 +61539 -0.22442626953125 +61540 -0.185333251953125 +61541 -0.153533935546875 +61542 -0.128204345703125 +61543 -0.106658935546875 +61544 -0.115692138671875 +61545 -0.089263916015625 +61546 -0.116455078125 +61547 -0.08056640625 +61548 -0.105926513671875 +61549 -0.064361572265625 +61550 -0.053955078125 +61551 -0.020660400390625 +61552 0.048797607421875 +61553 0.056427001953125 +61554 0.157318115234375 +61555 0.135955810546875 +61556 0.212005615234375 +61557 0.1771240234375 +61558 0.218475341796875 +61559 0.18359375 +61560 0.23724365234375 +61561 0.196441650390625 +61562 0.30535888671875 +61563 0.240966796875 +61564 0.38128662109375 +61565 0.289031982421875 +61566 0.404449462890625 +61567 0.2996826171875 +61568 0.3944091796875 +61569 0.286529541015625 +61570 0.3885498046875 +61571 0.275390625 +61572 0.362640380859375 +61573 0.250244140625 +61574 0.27362060546875 +61575 0.18218994140625 +61576 0.11712646484375 +61577 0.068695068359375 +61578 -0.054901123046875 +61579 -0.054534912109375 +61580 -0.19085693359375 +61581 -0.152099609375 +61582 -0.28570556640625 +61583 -0.2203369140625 +61584 -0.339263916015625 +61585 -0.25897216796875 +61586 -0.3775634765625 +61587 -0.285614013671875 +61588 -0.445709228515625 +61589 -0.330963134765625 +61590 -0.535064697265625 +61591 -0.389251708984375 +61592 -0.629058837890625 +61593 -0.449371337890625 +61594 -0.697601318359375 +61595 -0.4910888671875 +61596 -0.70391845703125 +61597 -0.489715576171875 +61598 -0.6424560546875 +61599 -0.441802978515625 +61600 -0.491241455078125 +61601 -0.332733154296875 +61602 -0.265716552734375 +61603 -0.173370361328125 +61604 -0.023712158203125 +61605 -0.00335693359375 +61606 0.201751708984375 +61607 0.154541015625 +61608 0.375823974609375 +61609 0.276397705078125 +61610 0.485076904296875 +61611 0.352935791015625 +61612 0.56884765625 +61613 0.41082763671875 +61614 0.634765625 +61615 0.45526123046875 +61616 0.63763427734375 +61617 0.45556640625 +61618 0.5660400390625 +61619 0.404083251953125 +61620 0.4720458984375 +61621 0.336395263671875 +61622 0.40692138671875 +61623 0.28759765625 +61624 0.3778076171875 +61625 0.2628173828125 +61626 0.376953125 +61627 0.257080078125 +61628 0.371978759765625 +61629 0.2486572265625 +61630 0.313140869140625 +61631 0.204010009765625 +61632 0.184417724609375 +61633 0.112457275390625 +61634 0.011199951171875 +61635 -0.008514404296875 +61636 -0.171051025390625 +61637 -0.1346435546875 +61638 -0.33740234375 +61639 -0.2489013671875 +61640 -0.47198486328125 +61641 -0.340423583984375 +61642 -0.560394287109375 +61643 -0.39947509765625 +61644 -0.58056640625 +61645 -0.411163330078125 +61646 -0.54754638671875 +61647 -0.385833740234375 +61648 -0.508575439453125 +61649 -0.355804443359375 +61650 -0.459503173828125 +61651 -0.318450927734375 +61652 -0.394378662109375 +61653 -0.269989013671875 +61654 -0.35260009765625 +61655 -0.237396240234375 +61656 -0.31170654296875 +61657 -0.20562744140625 +61658 -0.197418212890625 +61659 -0.124420166015625 +61660 -0.007965087890625 +61661 0.007232666015625 +61662 0.207489013671875 +61663 0.155792236328125 +61664 0.409210205078125 +61665 0.29412841796875 +61666 0.57208251953125 +61667 0.405120849609375 +61668 0.66595458984375 +61669 0.468292236328125 +61670 0.65875244140625 +61671 0.4619140625 +61672 0.56744384765625 +61673 0.397613525390625 +61674 0.431396484375 +61675 0.302337646484375 +61676 0.29443359375 +61677 0.2060546875 +61678 0.182464599609375 +61679 0.126556396484375 +61680 0.06365966796875 +61681 0.0423583984375 +61682 -0.075958251953125 +61683 -0.055816650390625 +61684 -0.189422607421875 +61685 -0.1358642578125 +61686 -0.271942138671875 +61687 -0.19439697265625 +61688 -0.342529296875 +61689 -0.24420166015625 +61690 -0.364166259765625 +61691 -0.26007080078125 +61692 -0.327239990234375 +61693 -0.23541259765625 +61694 -0.2769775390625 +61695 -0.20098876953125 +61696 -0.253692626953125 +61697 -0.184478759765625 +61698 -0.24365234375 +61699 -0.176361083984375 +61700 -0.1983642578125 +61701 -0.1427001953125 +61702 -0.116241455078125 +61703 -0.08258056640625 +61704 -0.036834716796875 +61705 -0.024383544921875 +61706 0.034881591796875 +61707 0.028167724609375 +61708 0.09124755859375 +61709 0.06951904296875 +61710 0.10888671875 +61711 0.082916259765625 +61712 0.125518798828125 +61713 0.095184326171875 +61714 0.15771484375 +61715 0.118133544921875 +61716 0.17828369140625 +61717 0.13238525390625 +61718 0.17108154296875 +61719 0.126495361328125 +61720 0.129974365234375 +61721 0.09619140625 +61722 0.082427978515625 +61723 0.06109619140625 +61724 0.027679443359375 +61725 0.020751953125 +61726 -0.065643310546875 +61727 -0.047088623046875 +61728 -0.15936279296875 +61729 -0.115142822265625 +61730 -0.21307373046875 +61731 -0.154571533203125 +61732 -0.234649658203125 +61733 -0.1708984375 +61734 -0.2001953125 +61735 -0.1470947265625 +61736 -0.119171142578125 +61737 -0.08984375 +61738 -0.024749755859375 +61739 -0.02276611328125 +61740 0.085784912109375 +61741 0.056060791015625 +61742 0.178131103515625 +61743 0.122222900390625 +61744 0.215576171875 +61745 0.1495361328125 +61746 0.211456298828125 +61747 0.1474609375 +61748 0.17523193359375 +61749 0.1226806640625 +61750 0.128753662109375 +61751 0.090667724609375 +61752 0.1019287109375 +61753 0.072662353515625 +61754 0.0743408203125 +61755 0.054107666015625 +61756 0.04327392578125 +61757 0.032989501953125 +61758 0.038177490234375 +61759 0.03021240234375 +61760 0.076263427734375 +61761 0.0579833984375 +61762 0.14105224609375 +61763 0.10455322265625 +61764 0.186431884765625 +61765 0.137054443359375 +61766 0.188812255859375 +61767 0.138702392578125 +61768 0.1390380859375 +61769 0.102996826171875 +61770 0.041778564453125 +61771 0.03326416015625 +61772 -0.079437255859375 +61773 -0.05364990234375 +61774 -0.219390869140625 +61775 -0.154052734375 +61776 -0.367828369140625 +61777 -0.260589599609375 +61778 -0.494873046875 +61779 -0.3519287109375 +61780 -0.556243896484375 +61781 -0.396514892578125 +61782 -0.508697509765625 +61783 -0.363494873046875 +61784 -0.3756103515625 +61785 -0.26947021484375 +61786 -0.218902587890625 +61787 -0.15850830078125 +61788 -0.063751220703125 +61789 -0.0484619140625 +61790 0.091552734375 +61791 0.061859130859375 +61792 0.23602294921875 +61793 0.164642333984375 +61794 0.342987060546875 +61795 0.24090576171875 +61796 0.39520263671875 +61797 0.278350830078125 +61798 0.389373779296875 +61799 0.274627685546875 +61800 0.324249267578125 +61801 0.22882080078125 +61802 0.224090576171875 +61803 0.158172607421875 +61804 0.124267578125 +61805 0.08782958984375 +61806 0.037078857421875 +61807 0.026458740234375 +61808 -0.010101318359375 +61809 -0.006439208984375 +61810 -0.019439697265625 +61811 -0.012451171875 +61812 -0.022796630859375 +61813 -0.0142822265625 +61814 -0.001556396484375 +61815 0.00128173828125 +61816 0.056304931640625 +61817 0.042755126953125 +61818 0.106719970703125 +61819 0.0787353515625 +61820 0.096893310546875 +61821 0.071685791015625 +61822 0.042694091796875 +61823 0.03289794921875 +61824 -0.018035888671875 +61825 -0.010650634765625 +61826 -0.07586669921875 +61827 -0.05224609375 +61828 -0.11944580078125 +61829 -0.083740234375 +61830 -0.15972900390625 +61831 -0.11297607421875 +61832 -0.202606201171875 +61833 -0.144073486328125 +61834 -0.24859619140625 +61835 -0.177337646484375 +61836 -0.30517578125 +61837 -0.21807861328125 +61838 -0.36212158203125 +61839 -0.259033203125 +61840 -0.39141845703125 +61841 -0.280242919921875 +61842 -0.35528564453125 +61843 -0.254730224609375 +61844 -0.249969482421875 +61845 -0.179840087890625 +61846 -0.092864990234375 +61847 -0.0679931640625 +61848 0.08905029296875 +61849 0.061614990234375 +61850 0.2352294921875 +61851 0.165863037109375 +61852 0.318817138671875 +61853 0.225616455078125 +61854 0.358642578125 +61855 0.2542724609375 +61856 0.347747802734375 +61857 0.246856689453125 +61858 0.28564453125 +61859 0.2030029296875 +61860 0.223175048828125 +61861 0.158905029296875 +61862 0.196746826171875 +61863 0.140472412109375 +61864 0.179840087890625 +61865 0.128814697265625 +61866 0.155548095703125 +61867 0.111846923828125 +61868 0.151214599609375 +61869 0.109039306640625 +61870 0.156951904296875 +61871 0.11334228515625 +61872 0.13177490234375 +61873 0.09552001953125 +61874 0.100799560546875 +61875 0.073486328125 +61876 0.087127685546875 +61877 0.06365966796875 +61878 0.05487060546875 +61879 0.040496826171875 +61880 -0.009002685546875 +61881 -0.0052490234375 +61882 -0.10400390625 +61883 -0.07318115234375 +61884 -0.229400634765625 +61885 -0.16278076171875 +61886 -0.35552978515625 +61887 -0.252899169921875 +61888 -0.441925048828125 +61889 -0.314697265625 +61890 -0.473846435546875 +61891 -0.33770751953125 +61892 -0.464813232421875 +61893 -0.331512451171875 +61894 -0.419097900390625 +61895 -0.29913330078125 +61896 -0.334320068359375 +61897 -0.2388916015625 +61898 -0.227935791015625 +61899 -0.1632080078125 +61900 -0.12347412109375 +61901 -0.088836669921875 +61902 -0.02764892578125 +61903 -0.020538330078125 +61904 0.077667236328125 +61905 0.0545654296875 +61906 0.2132568359375 +61907 0.151275634765625 +61908 0.38885498046875 +61909 0.2764892578125 +61910 0.582794189453125 +61911 0.414794921875 +61912 0.734039306640625 +61913 0.522705078125 +61914 0.800140380859375 +61915 0.569976806640625 +61916 0.7783203125 +61917 0.554595947265625 +61918 0.6651611328125 +61919 0.474151611328125 +61920 0.45965576171875 +61921 0.32794189453125 +61922 0.199188232421875 +61923 0.142547607421875 +61924 -0.050689697265625 +61925 -0.03533935546875 +61926 -0.23297119140625 +61927 -0.165130615234375 +61928 -0.33013916015625 +61929 -0.234375 +61930 -0.368408203125 +61931 -0.26171875 +61932 -0.378936767578125 +61933 -0.269317626953125 +61934 -0.376983642578125 +61935 -0.268035888671875 +61936 -0.37969970703125 +61937 -0.270111083984375 +61938 -0.391510009765625 +61939 -0.278656005859375 +61940 -0.385345458984375 +61941 -0.2744140625 +61942 -0.3419189453125 +61943 -0.243621826171875 +61944 -0.28289794921875 +61945 -0.20172119140625 +61946 -0.251617431640625 +61947 -0.179534912109375 +61948 -0.266143798828125 +61949 -0.189910888671875 +61950 -0.273345947265625 +61951 -0.195037841796875 +61952 -0.216796875 +61953 -0.154632568359375 +61954 -0.128265380859375 +61955 -0.091522216796875 +61956 -0.068145751953125 +61957 -0.04974365234375 +61958 -0.0430908203125 +61959 -0.034027099609375 +61960 -0.024444580078125 +61961 -0.022918701171875 +61962 0.020721435546875 +61963 0.008270263671875 +61964 0.124481201171875 +61965 0.083465576171875 +61966 0.25787353515625 +61967 0.181243896484375 +61968 0.379119873046875 +61969 0.27056884765625 +61970 0.47991943359375 +61971 0.3453369140625 +61972 0.5281982421875 +61973 0.38165283203125 +61974 0.511138916015625 +61975 0.369964599609375 +61976 0.456207275390625 +61977 0.330657958984375 +61978 0.407470703125 +61979 0.296417236328125 +61980 0.383758544921875 +61981 0.281097412109375 +61982 0.35687255859375 +61983 0.263580322265625 +61984 0.31182861328125 +61985 0.232574462890625 +61986 0.250885009765625 +61987 0.18963623046875 +61988 0.1654052734375 +61989 0.128173828125 +61990 0.035247802734375 +61991 0.03314208984375 +61992 -0.142059326171875 +61993 -0.097381591796875 +61994 -0.33563232421875 +61995 -0.240478515625 +61996 -0.5345458984375 +61997 -0.388031005859375 +61998 -0.72186279296875 +61999 -0.527496337890625 +62000 -0.836669921875 +62001 -0.613525390625 +62002 -0.8326416015625 +62003 -0.611602783203125 +62004 -0.7296142578125 +62005 -0.536407470703125 +62006 -0.582550048828125 +62007 -0.428741455078125 +62008 -0.440093994140625 +62009 -0.32470703125 +62010 -0.324310302734375 +62011 -0.2406005859375 +62012 -0.20147705078125 +62013 -0.151214599609375 +62014 -0.044647216796875 +62015 -0.036376953125 +62016 0.103973388671875 +62017 0.07257080078125 +62018 0.202392578125 +62019 0.14447021484375 +62020 0.264495849609375 +62021 0.189727783203125 +62022 0.338897705078125 +62023 0.24456787109375 +62024 0.443817138671875 +62025 0.322540283203125 +62026 0.545074462890625 +62027 0.398193359375 +62028 0.6173095703125 +62029 0.45263671875 +62030 0.6524658203125 +62031 0.479827880859375 +62032 0.66339111328125 +62033 0.4892578125 +62034 0.6561279296875 +62035 0.4853515625 +62036 0.606781005859375 +62037 0.450225830078125 +62038 0.501190185546875 +62039 0.373260498046875 +62040 0.352783203125 +62041 0.264373779296875 +62042 0.176544189453125 +62043 0.134613037109375 +62044 -0.034820556640625 +62045 -0.021484375 +62046 -0.258209228515625 +62047 -0.186798095703125 +62048 -0.44244384765625 +62049 -0.32330322265625 +62050 -0.5753173828125 +62051 -0.421905517578125 +62052 -0.65203857421875 +62053 -0.47906494140625 +62054 -0.641632080078125 +62055 -0.471710205078125 +62056 -0.562164306640625 +62057 -0.413299560546875 +62058 -0.458038330078125 +62059 -0.3367919921875 +62060 -0.350555419921875 +62061 -0.257965087890625 +62062 -0.260528564453125 +62063 -0.192230224609375 +62064 -0.192108154296875 +62065 -0.142608642578125 +62066 -0.141937255859375 +62067 -0.106536865234375 +62068 -0.1021728515625 +62069 -0.078094482421875 +62070 -0.062896728515625 +62071 -0.04986572265625 +62072 -0.011932373046875 +62073 -0.012725830078125 +62074 0.062835693359375 +62075 0.0423583984375 +62076 0.148712158203125 +62077 0.105987548828125 +62078 0.241729736328125 +62079 0.1751708984375 +62080 0.34912109375 +62081 0.25531005859375 +62082 0.457305908203125 +62083 0.336273193359375 +62084 0.54388427734375 +62085 0.4013671875 +62086 0.5728759765625 +62087 0.42376708984375 +62088 0.506591796875 +62089 0.375396728515625 +62090 0.351226806640625 +62091 0.26080322265625 +62092 0.146514892578125 +62093 0.109466552734375 +62094 -0.05523681640625 +62095 -0.03973388671875 +62096 -0.21624755859375 +62097 -0.158721923828125 +62098 -0.334930419921875 +62099 -0.246337890625 +62100 -0.402984619140625 +62101 -0.29644775390625 +62102 -0.4412841796875 +62103 -0.3245849609375 +62104 -0.49578857421875 +62105 -0.364990234375 +62106 -0.5601806640625 +62107 -0.412933349609375 +62108 -0.600738525390625 +62109 -0.443328857421875 +62110 -0.584228515625 +62111 -0.43145751953125 +62112 -0.47930908203125 +62113 -0.35394287109375 +62114 -0.27935791015625 +62115 -0.20587158203125 +62116 -0.0089111328125 +62117 -0.00543212890625 +62118 0.268798828125 +62119 0.200347900390625 +62120 0.482818603515625 +62121 0.3587646484375 +62122 0.60369873046875 +62123 0.447967529296875 +62124 0.650421142578125 +62125 0.4820556640625 +62126 0.66400146484375 +62127 0.4915771484375 +62128 0.6414794921875 +62129 0.474395751953125 +62130 0.572540283203125 +62131 0.422821044921875 +62132 0.498138427734375 +62133 0.36737060546875 +62134 0.439453125 +62135 0.32379150390625 +62136 0.375518798828125 +62137 0.2764892578125 +62138 0.274505615234375 +62139 0.201751708984375 +62140 0.1087646484375 +62141 0.0789794921875 +62142 -0.099395751953125 +62143 -0.075286865234375 +62144 -0.3182373046875 +62145 -0.2374267578125 +62146 -0.5489501953125 +62147 -0.408355712890625 +62148 -0.7738037109375 +62149 -0.574920654296875 +62150 -0.86383056640625 +62151 -0.697784423828125 +62152 -0.870391845703125 +62153 -0.752227783203125 +62154 -0.86895751953125 +62155 -0.751495361328125 +62156 -0.861053466796875 +62157 -0.705322265625 +62158 -0.765869140625 +62159 -0.600860595703125 +62160 -0.5301513671875 +62161 -0.42974853515625 +62162 -0.214691162109375 +62163 -0.197296142578125 +62164 0.137359619140625 +62165 0.064483642578125 +62166 0.474822998046875 +62167 0.31744384765625 +62168 0.76239013671875 +62169 0.535186767578125 +62170 0.867462158203125 +62171 0.6976318359375 +62172 0.870361328125 +62173 0.80517578125 +62174 0.86480712890625 +62175 0.849212646484375 +62176 0.831817626953125 +62177 0.833770751953125 +62178 0.677581787109375 +62179 0.777008056640625 +62180 0.495880126953125 +62181 0.683258056640625 +62182 0.30767822265625 +62183 0.56634521484375 +62184 0.116180419921875 +62185 0.427947998046875 +62186 -0.110748291015625 +62187 0.24444580078125 +62188 -0.381805419921875 +62189 0.010711669921875 +62190 -0.6572265625 +62191 -0.241424560546875 +62192 -0.857421875 +62193 -0.4674072265625 +62194 -0.870391845703125 +62195 -0.635284423828125 +62196 -0.870391845703125 +62197 -0.739776611328125 +62198 -0.86444091796875 +62199 -0.8009033203125 +62200 -0.85723876953125 +62201 -0.84521484375 +62202 -0.790008544921875 +62203 -0.855010986328125 +62204 -0.62847900390625 +62205 -0.802215576171875 +62206 -0.3956298828125 +62207 -0.67218017578125 +62208 -0.126708984375 +62209 -0.493408203125 +62210 0.150115966796875 +62211 -0.28631591796875 +62212 0.424041748046875 +62213 -0.059326171875 +62214 0.670623779296875 +62215 0.167266845703125 +62216 0.854522705078125 +62217 0.3638916015625 +62218 0.866485595703125 +62219 0.517333984375 +62220 0.86920166015625 +62221 0.615997314453125 +62222 0.8653564453125 +62223 0.674224853515625 +62224 0.857147216796875 +62225 0.70257568359375 +62226 0.766845703125 +62227 0.69879150390625 +62228 0.628509521484375 +62229 0.666778564453125 +62230 0.462127685546875 +62231 0.60113525390625 +62232 0.297210693359375 +62233 0.521636962890625 +62234 0.14862060546875 +62235 0.43756103515625 +62236 -0.00537109375 +62237 0.330841064453125 +62238 -0.15753173828125 +62239 0.2069091796875 +62240 -0.31304931640625 +62241 0.06256103515625 +62242 -0.48876953125 +62243 -0.1134033203125 +62244 -0.6416015625 +62245 -0.284942626953125 +62246 -0.751373291015625 +62247 -0.433135986328125 +62248 -0.84619140625 +62249 -0.57611083984375 +62250 -0.861297607421875 +62251 -0.70257568359375 +62252 -0.863250732421875 +62253 -0.78680419921875 +62254 -0.856597900390625 +62255 -0.80426025390625 +62256 -0.7498779296875 +62257 -0.7642822265625 +62258 -0.624542236328125 +62259 -0.7115478515625 +62260 -0.47808837890625 +62261 -0.6287841796875 +62262 -0.253387451171875 +62263 -0.4703369140625 +62264 0.003692626953125 +62265 -0.271331787109375 +62266 0.2257080078125 +62267 -0.084564208984375 +62268 0.427154541015625 +62269 0.0999755859375 +62270 0.643218994140625 +62271 0.30767822265625 +62272 0.855926513671875 +62273 0.531219482421875 +62274 0.870361328125 +62275 0.725830078125 +62276 0.870361328125 +62277 0.853057861328125 +62278 0.862762451171875 +62279 0.8614501953125 +62280 0.79669189453125 +62281 0.861602783203125 +62282 0.595794677734375 +62283 0.849761962890625 +62284 0.362152099609375 +62285 0.73065185546875 +62286 0.1270751953125 +62287 0.58416748046875 +62288 -0.086944580078125 +62289 0.426513671875 +62290 -0.2784423828125 +62291 0.259124755859375 +62292 -0.484832763671875 +62293 0.0548095703125 +62294 -0.729583740234375 +62295 -0.201507568359375 +62296 -0.86688232421875 +62297 -0.470703125 +62298 -0.870391845703125 +62299 -0.703765869140625 +62300 -0.86859130859375 +62301 -0.859130859375 +62302 -0.86279296875 +62303 -0.870391845703125 +62304 -0.817962646484375 +62305 -0.870391845703125 +62306 -0.6116943359375 +62307 -0.8599853515625 +62308 -0.3128662109375 +62309 -0.712371826171875 +62310 0.039398193359375 +62311 -0.4517822265625 +62312 0.422821044921875 +62313 -0.140289306640625 +62314 0.805145263671875 +62315 0.195465087890625 +62316 0.870361328125 +62317 0.5029296875 +62318 0.870361328125 +62319 0.739105224609375 +62320 0.860015869140625 +62321 0.859100341796875 +62322 0.727935791015625 +62323 0.867462158203125 +62324 0.48114013671875 +62325 0.8668212890625 +62326 0.2059326171875 +62327 0.85968017578125 +62328 -0.06103515625 +62329 0.798126220703125 +62330 -0.29913330078125 +62331 0.66748046875 +62332 -0.516204833984375 +62333 0.502532958984375 +62334 -0.7252197265625 +62335 0.29449462890625 +62336 -0.85980224609375 +62337 0.0653076171875 +62338 -0.870391845703125 +62339 -0.15643310546875 +62340 -0.870391845703125 +62341 -0.34661865234375 +62342 -0.858062744140625 +62343 -0.467132568359375 +62344 -0.673004150390625 +62345 -0.515167236328125 +62346 -0.42694091796875 +62347 -0.53265380859375 +62348 -0.2100830078125 +62349 -0.55584716796875 +62350 -0.0362548828125 +62351 -0.58551025390625 +62352 0.10943603515625 +62353 -0.60186767578125 +62354 0.23516845703125 +62355 -0.592529296875 +62356 0.373687744140625 +62357 -0.528472900390625 +62358 0.517791748046875 +62359 -0.4141845703125 +62360 0.602783203125 +62361 -0.30133056640625 +62362 0.635711669921875 +62363 -0.188262939453125 +62364 0.655181884765625 +62365 -0.05096435546875 +62366 0.65948486328125 +62367 0.101531982421875 +62368 0.651275634765625 +62369 0.26239013671875 +62370 0.61846923828125 +62371 0.41259765625 +62372 0.53753662109375 +62373 0.524078369140625 +62374 0.404144287109375 +62375 0.584014892578125 +62376 0.22186279296875 +62377 0.586578369140625 +62378 0.003997802734375 +62379 0.534820556640625 +62380 -0.22100830078125 +62381 0.44512939453125 +62382 -0.42449951171875 +62383 0.336029052734375 +62384 -0.579833984375 +62385 0.22662353515625 +62386 -0.641876220703125 +62387 0.15240478515625 +62388 -0.6177978515625 +62389 0.11029052734375 +62390 -0.575531005859375 +62391 0.0518798828125 +62392 -0.526336669921875 +62393 -0.02569580078125 +62394 -0.42645263671875 +62395 -0.08148193359375 +62396 -0.2581787109375 +62397 -0.093963623046875 +62398 -0.068695068359375 +62399 -0.091644287109375 +62400 0.09222412109375 +62401 -0.105194091796875 +62402 0.232147216796875 +62403 -0.12139892578125 +62404 0.3509521484375 +62405 -0.133941650390625 +62406 0.410064697265625 +62407 -0.167633056640625 +62408 0.372955322265625 +62409 -0.247161865234375 +62410 0.2554931640625 +62411 -0.3582763671875 +62412 0.10711669921875 +62413 -0.46246337890625 +62414 -0.052886962890625 +62415 -0.5462646484375 +62416 -0.186279296875 +62417 -0.5830078125 +62418 -0.23291015625 +62419 -0.530426025390625 +62420 -0.209442138671875 +62421 -0.40692138671875 +62422 -0.174163818359375 +62423 -0.263946533203125 +62424 -0.126739501953125 +62425 -0.10784912109375 +62426 -0.048126220703125 +62427 0.06951904296875 +62428 0.0426025390625 +62429 0.247100830078125 +62430 0.10748291015625 +62431 0.389892578125 +62432 0.1409912109375 +62433 0.48895263671875 +62434 0.19708251953125 +62435 0.582733154296875 +62436 0.273651123046875 +62437 0.66754150390625 +62438 0.31768798828125 +62439 0.701568603515625 +62440 0.341094970703125 +62441 0.694793701171875 +62442 0.368011474609375 +62443 0.66802978515625 +62444 0.37249755859375 +62445 0.6043701171875 +62446 0.30072021484375 +62447 0.466278076171875 +62448 0.1517333984375 +62449 0.2579345703125 +62450 -0.01470947265625 +62451 0.031036376953125 +62452 -0.1883544921875 +62453 -0.200958251953125 +62454 -0.372711181640625 +62455 -0.43548583984375 +62456 -0.51397705078125 +62457 -0.6259765625 +62458 -0.57177734375 +62459 -0.736968994140625 +62460 -0.53948974609375 +62461 -0.760162353515625 +62462 -0.43511962890625 +62463 -0.707427978515625 +62464 -0.2962646484375 +62465 -0.606689453125 +62466 -0.161102294921875 +62467 -0.487640380859375 +62468 -0.0435791015625 +62469 -0.362579345703125 +62470 0.060394287109375 +62471 -0.2308349609375 +62472 0.13665771484375 +62473 -0.107086181640625 +62474 0.170135498046875 +62475 -0.00738525390625 +62476 0.16552734375 +62477 0.067626953125 +62478 0.15728759765625 +62479 0.14093017578125 +62480 0.150787353515625 +62481 0.21240234375 +62482 0.12200927734375 +62483 0.25872802734375 +62484 0.080108642578125 +62485 0.283660888671875 +62486 0.05126953125 +62487 0.3052978515625 +62488 0.062896728515625 +62489 0.343536376953125 +62490 0.09271240234375 +62491 0.379425048828125 +62492 0.092987060546875 +62493 0.3746337890625 +62494 0.07855224609375 +62495 0.341796875 +62496 0.06427001953125 +62497 0.29443359375 +62498 0.0347900390625 +62499 0.22265625 +62500 -0.01171875 +62501 0.127960205078125 +62502 -0.056060791015625 +62503 0.029144287109375 +62504 -0.055511474609375 +62505 -0.035980224609375 +62506 -0.010467529296875 +62507 -0.064056396484375 +62508 0.02508544921875 +62509 -0.094818115234375 +62510 0.025665283203125 +62511 -0.145538330078125 +62512 0.017333984375 +62513 -0.19281005859375 +62514 0.00189208984375 +62515 -0.233306884765625 +62516 -0.03173828125 +62517 -0.27471923828125 +62518 -0.071502685546875 +62519 -0.30706787109375 +62520 -0.13543701171875 +62521 -0.3450927734375 +62522 -0.219970703125 +62523 -0.387054443359375 +62524 -0.300506591796875 +62525 -0.4150390625 +62526 -0.376312255859375 +62527 -0.430755615234375 +62528 -0.416107177734375 +62529 -0.411865234375 +62530 -0.371124267578125 +62531 -0.322296142578125 +62532 -0.242279052734375 +62533 -0.165771484375 +62534 -0.069732666015625 +62535 0.02264404296875 +62536 0.125640869140625 +62537 0.22357177734375 +62538 0.31268310546875 +62539 0.409820556640625 +62540 0.45501708984375 +62541 0.550537109375 +62542 0.554779052734375 +62543 0.646270751953125 +62544 0.61065673828125 +62545 0.695404052734375 +62546 0.610931396484375 +62547 0.688629150390625 +62548 0.531463623046875 +62549 0.60736083984375 +62550 0.3883056640625 +62551 0.465728759765625 +62552 0.23468017578125 +62553 0.308074951171875 +62554 0.095245361328125 +62555 0.156219482421875 +62556 -0.00396728515625 +62557 0.0333251953125 +62558 -0.04852294921875 +62559 -0.046600341796875 +62560 -0.055145263671875 +62561 -0.094451904296875 +62562 -0.0758056640625 +62563 -0.149566650390625 +62564 -0.138702392578125 +62565 -0.232513427734375 +62566 -0.209197998046875 +62567 -0.31396484375 +62568 -0.289031982421875 +62569 -0.394195556640625 +62570 -0.37884521484375 +62571 -0.473052978515625 +62572 -0.456329345703125 +62573 -0.532562255859375 +62574 -0.51641845703125 +62575 -0.569091796875 +62576 -0.519287109375 +62577 -0.551666259765625 +62578 -0.458251953125 +62579 -0.47625732421875 +62580 -0.384796142578125 +62581 -0.38568115234375 +62582 -0.323699951171875 +62583 -0.301666259765625 +62584 -0.269287109375 +62585 -0.221649169921875 +62586 -0.1951904296875 +62587 -0.1265869140625 +62588 -0.100006103515625 +62589 -0.01727294921875 +62590 -0.01055908203125 +62591 0.083038330078125 +62592 0.1033935546875 +62593 0.197113037109375 +62594 0.24908447265625 +62595 0.329681396484375 +62596 0.373199462890625 +62597 0.437408447265625 +62598 0.45806884765625 +62599 0.50592041015625 +62600 0.511474609375 +62601 0.5416259765625 +62602 0.565399169921875 +62603 0.570770263671875 +62604 0.61138916015625 +62605 0.5875244140625 +62606 0.5897216796875 +62607 0.545379638671875 +62608 0.4906005859375 +62609 0.43792724609375 +62610 0.33148193359375 +62611 0.280792236328125 +62612 0.147796630859375 +62613 0.10400390625 +62614 -0.01873779296875 +62615 -0.05743408203125 +62616 -0.140289306640625 +62617 -0.17974853515625 +62618 -0.191986083984375 +62619 -0.241790771484375 +62620 -0.184295654296875 +62621 -0.25091552734375 +62622 -0.161834716796875 +62623 -0.242156982421875 +62624 -0.166595458984375 +62625 -0.248748779296875 +62626 -0.19390869140625 +62627 -0.2669677734375 +62628 -0.22442626953125 +62629 -0.28173828125 +62630 -0.279754638671875 +62631 -0.31103515625 +62632 -0.3389892578125 +62633 -0.339111328125 +62634 -0.3543701171875 +62635 -0.3289794921875 +62636 -0.348175048828125 +62637 -0.29974365234375 +62638 -0.32598876953125 +62639 -0.257232666015625 +62640 -0.2581787109375 +62641 -0.17913818359375 +62642 -0.139801025390625 +62643 -0.062774658203125 +62644 0.014617919921875 +62645 0.07916259765625 +62646 0.144378662109375 +62647 0.1971435546875 +62648 0.221038818359375 +62649 0.267791748046875 +62650 0.27069091796875 +62651 0.311614990234375 +62652 0.294036865234375 +62653 0.3291015625 +62654 0.311767578125 +62655 0.337005615234375 +62656 0.339141845703125 +62657 0.34808349609375 +62658 0.360260009765625 +62659 0.35040283203125 +62660 0.360504150390625 +62661 0.333160400390625 +62662 0.308380126953125 +62663 0.271881103515625 +62664 0.18170166015625 +62665 0.14971923828125 +62666 0.0047607421875 +62667 -0.0125732421875 +62668 -0.17559814453125 +62669 -0.1761474609375 +62670 -0.3143310546875 +62671 -0.3037109375 +62672 -0.36785888671875 +62673 -0.359283447265625 +62674 -0.36248779296875 +62675 -0.363494873046875 +62676 -0.343536376953125 +62677 -0.352630615234375 +62678 -0.3018798828125 +62679 -0.319244384765625 +62680 -0.231414794921875 +62681 -0.258453369140625 +62682 -0.117645263671875 +62683 -0.158905029296875 +62684 0.007049560546875 +62685 -0.047271728515625 +62686 0.087982177734375 +62687 0.031585693359375 +62688 0.13946533203125 +62689 0.088409423828125 +62690 0.17425537109375 +62691 0.13262939453125 +62692 0.188201904296875 +62693 0.15997314453125 +62694 0.171234130859375 +62695 0.16143798828125 +62696 0.118438720703125 +62697 0.13226318359375 +62698 0.05706787109375 +62699 0.093780517578125 +62700 -0.010711669921875 +62701 0.04718017578125 +62702 -0.0914306640625 +62703 -0.013153076171875 +62704 -0.162322998046875 +62705 -0.0689697265625 +62706 -0.194549560546875 +62707 -0.09698486328125 +62708 -0.1492919921875 +62709 -0.06561279296875 +62710 -0.02166748046875 +62711 0.029449462890625 +62712 0.124053955078125 +62713 0.136810302734375 +62714 0.211151123046875 +62715 0.195098876953125 +62716 0.240447998046875 +62717 0.205718994140625 +62718 0.242218017578125 +62719 0.19384765625 +62720 0.2257080078125 +62721 0.168243408203125 +62722 0.194366455078125 +62723 0.132080078125 +62724 0.115509033203125 +62725 0.05780029296875 +62726 0.0128173828125 +62727 -0.03424072265625 +62728 -0.053802490234375 +62729 -0.093475341796875 +62730 -0.110626220703125 +62731 -0.141845703125 +62732 -0.199493408203125 +62733 -0.21453857421875 +62734 -0.29437255859375 +62735 -0.289825439453125 +62736 -0.33221435546875 +62737 -0.315032958984375 +62738 -0.27972412109375 +62739 -0.26263427734375 +62740 -0.185333251953125 +62741 -0.17376708984375 +62742 -0.128204345703125 +62743 -0.115478515625 +62744 -0.115692138671875 +62745 -0.094512939453125 +62746 -0.116455078125 +62747 -0.08514404296875 +62748 -0.105926513671875 +62749 -0.0672607421875 +62750 -0.053955078125 +62751 -0.016021728515625 +62752 0.048797607421875 +62753 0.0760498046875 +62754 0.157318115234375 +62755 0.1708984375 +62756 0.212005615234375 +62757 0.21832275390625 +62758 0.218475341796875 +62759 0.222991943359375 +62760 0.23724365234375 +62761 0.235870361328125 +62762 0.30535888671875 +62763 0.288299560546875 +62764 0.38128662109375 +62765 0.345703125 +62766 0.404449462890625 +62767 0.3575439453125 +62768 0.3944091796875 +62769 0.34075927734375 +62770 0.3885498046875 +62771 0.32720947265625 +62772 0.362640380859375 +62773 0.297027587890625 +62774 0.27362060546875 +62775 0.2144775390625 +62776 0.11712646484375 +62777 0.0762939453125 +62778 -0.054901123046875 +62779 -0.073486328125 +62780 -0.19085693359375 +62781 -0.1912841796875 +62782 -0.28570556640625 +62783 -0.27276611328125 +62784 -0.339263916015625 +62785 -0.317718505859375 +62786 -0.3775634765625 +62787 -0.34808349609375 +62788 -0.445709228515625 +62789 -0.401885986328125 +62790 -0.535064697265625 +62791 -0.47210693359375 +62792 -0.629058837890625 +62793 -0.54510498046875 +62794 -0.697601318359375 +62795 -0.59600830078125 +62796 -0.70391845703125 +62797 -0.594268798828125 +62798 -0.6424560546875 +62799 -0.535614013671875 +62800 -0.491241455078125 +62801 -0.4019775390625 +62802 -0.265716552734375 +62803 -0.206695556640625 +62804 -0.023712158203125 +62805 0.001373291015625 +62806 0.201751708984375 +62807 0.1942138671875 +62808 0.375823974609375 +62809 0.3424072265625 +62810 0.485076904296875 +62811 0.43463134765625 +62812 0.56884765625 +62813 0.503997802734375 +62814 0.634765625 +62815 0.556976318359375 +62816 0.63763427734375 +62817 0.555755615234375 +62818 0.5660400390625 +62819 0.490966796875 +62820 0.4720458984375 +62821 0.406646728515625 +62822 0.40692138671875 +62823 0.346160888671875 +62824 0.3778076171875 +62825 0.31585693359375 +62826 0.376953125 +62827 0.309539794921875 +62828 0.371978759765625 +62829 0.30029296875 +62830 0.313140869140625 +62831 0.246612548828125 +62832 0.184417724609375 +62833 0.135223388671875 +62834 0.011199951171875 +62835 -0.0123291015625 +62836 -0.171051025390625 +62837 -0.16619873046875 +62838 -0.33740234375 +62839 -0.305450439453125 +62840 -0.47198486328125 +62841 -0.41680908203125 +62842 -0.560394287109375 +62843 -0.48834228515625 +62844 -0.58056640625 +62845 -0.501678466796875 +62846 -0.54754638671875 +62847 -0.46966552734375 +62848 -0.508575439453125 +62849 -0.4322509765625 +62850 -0.459503173828125 +62851 -0.386199951171875 +62852 -0.394378662109375 +62853 -0.326812744140625 +62854 -0.35260009765625 +62855 -0.28741455078125 +62856 -0.31170654296875 +62857 -0.249359130859375 +62858 -0.197418212890625 +62859 -0.150421142578125 +62860 -0.007965087890625 +62861 0.0107421875 +62862 0.207489013671875 +62863 0.192718505859375 +62864 0.409210205078125 +62865 0.362091064453125 +62866 0.57208251953125 +62867 0.497802734375 +62868 0.66595458984375 +62869 0.57464599609375 +62870 0.65875244140625 +62871 0.5657958984375 +62872 0.56744384765625 +62873 0.485687255859375 +62874 0.431396484375 +62875 0.36761474609375 +62876 0.29443359375 +62877 0.24859619140625 +62878 0.182464599609375 +62879 0.150634765625 +62880 0.06365966796875 +62881 0.04718017578125 +62882 -0.075958251953125 +62883 -0.07330322265625 +62884 -0.189422607421875 +62885 -0.17120361328125 +62886 -0.271942138671875 +62887 -0.24237060546875 +62888 -0.342529296875 +62889 -0.30267333984375 +62890 -0.364166259765625 +62891 -0.321014404296875 +62892 -0.327239990234375 +62893 -0.28936767578125 +62894 -0.2769775390625 +62895 -0.245758056640625 +62896 -0.253692626953125 +62897 -0.224151611328125 +62898 -0.24365234375 +62899 -0.213104248046875 +62900 -0.1983642578125 +62901 -0.172088623046875 +62902 -0.116241455078125 +62903 -0.09991455078125 +62904 -0.036834716796875 +62905 -0.029937744140625 +62906 0.034881591796875 +62907 0.033416748046875 +62908 0.09124755859375 +62909 0.083526611328125 +62910 0.10888671875 +62911 0.100677490234375 +62912 0.125518798828125 +62913 0.116424560546875 +62914 0.15771484375 +62915 0.14459228515625 +62916 0.17828369140625 +62917 0.16229248046875 +62918 0.17108154296875 +62919 0.15594482421875 +62920 0.129974365234375 +62921 0.120452880859375 +62922 0.082427978515625 +62923 0.0789794921875 +62924 0.027679443359375 +62925 0.030975341796875 +62926 -0.065643310546875 +62927 -0.049774169921875 +62928 -0.15936279296875 +62929 -0.131072998046875 +62930 -0.21307373046875 +62931 -0.1788330078125 +62932 -0.234649658203125 +62933 -0.19952392578125 +62934 -0.2001953125 +62935 -0.172943115234375 +62936 -0.119171142578125 +62937 -0.106903076171875 +62938 -0.024749755859375 +62939 -0.0291748046875 +62940 0.085784912109375 +62941 0.062591552734375 +62942 0.178131103515625 +62943 0.139617919921875 +62944 0.215576171875 +62945 0.171112060546875 +62946 0.211456298828125 +62947 0.168212890625 +62948 0.17523193359375 +62949 0.13885498046875 +62950 0.128753662109375 +62951 0.101318359375 +62952 0.1019287109375 +62953 0.080596923828125 +62954 0.0743408203125 +62955 0.059478759765625 +62956 0.04327392578125 +62957 0.035552978515625 +62958 0.038177490234375 +62959 0.033416748046875 +62960 0.076263427734375 +62961 0.067413330078125 +62962 0.14105224609375 +62963 0.12359619140625 +62964 0.186431884765625 +62965 0.16314697265625 +62966 0.188812255859375 +62967 0.166168212890625 +62968 0.1390380859375 +62969 0.124908447265625 +62970 0.041778564453125 +62971 0.043304443359375 +62972 -0.079437255859375 +62973 -0.058837890625 +62974 -0.219390869140625 +62975 -0.177154541015625 +62976 -0.367828369140625 +62977 -0.303253173828125 +62978 -0.494873046875 +62979 -0.412445068359375 +62980 -0.556243896484375 +62981 -0.466522216796875 +62982 -0.508697509765625 +62983 -0.427398681640625 +62984 -0.3756103515625 +62985 -0.315032958984375 +62986 -0.218902587890625 +62987 -0.1829833984375 +62988 -0.063751220703125 +62989 -0.05279541015625 +62990 0.091552734375 +62991 0.07745361328125 +62992 0.23602294921875 +62993 0.19854736328125 +62994 0.342987060546875 +62995 0.28753662109375 +62996 0.39520263671875 +62997 0.329620361328125 +62998 0.389373779296875 +62999 0.322113037109375 +63000 0.324249267578125 +63001 0.264007568359375 +63002 0.224090576171875 +63003 0.176483154296875 +63004 0.124267578125 +63005 0.090362548828125 +63006 0.037078857421875 +63007 0.0162353515625 +63008 -0.010101318359375 +63009 -0.022125244140625 +63010 -0.019439697265625 +63011 -0.026824951171875 +63012 -0.022796630859375 +63013 -0.02581787109375 +63014 -0.001556396484375 +63015 -0.003143310546875 +63016 0.056304931640625 +63017 0.05145263671875 +63018 0.106719970703125 +63019 0.09930419921875 +63020 0.096893310546875 +63021 0.09417724609375 +63022 0.042694091796875 +63023 0.04974365234375 +63024 -0.018035888671875 +63025 -0.00115966796875 +63026 -0.07586669921875 +63027 -0.05035400390625 +63028 -0.11944580078125 +63029 -0.0880126953125 +63030 -0.15972900390625 +63031 -0.12371826171875 +63032 -0.202606201171875 +63033 -0.16253662109375 +63034 -0.24859619140625 +63035 -0.20477294921875 +63036 -0.30517578125 +63037 -0.256805419921875 +63038 -0.36212158203125 +63039 -0.3095703125 +63040 -0.39141845703125 +63041 -0.338470458984375 +63042 -0.35528564453125 +63043 -0.31036376953125 +63044 -0.249969482421875 +63045 -0.2218017578125 +63046 -0.092864990234375 +63047 -0.08782958984375 +63048 0.08905029296875 +63049 0.0682373046875 +63050 0.2352294921875 +63051 0.1937255859375 +63052 0.318817138671875 +63053 0.26531982421875 +63054 0.358642578125 +63055 0.299468994140625 +63056 0.347747802734375 +63057 0.290130615234375 +63058 0.28564453125 +63059 0.23687744140625 +63060 0.223175048828125 +63061 0.183929443359375 +63062 0.196746826171875 +63063 0.162933349609375 +63064 0.179840087890625 +63065 0.150665283203125 +63066 0.155548095703125 +63067 0.132232666015625 +63068 0.151214599609375 +63069 0.131317138671875 +63070 0.156951904296875 +63071 0.13916015625 +63072 0.13177490234375 +63073 0.119842529296875 +63074 0.100799560546875 +63075 0.095123291015625 +63076 0.087127685546875 +63077 0.08502197265625 +63078 0.05487060546875 +63079 0.05816650390625 +63080 -0.009002685546875 +63081 0.00311279296875 +63082 -0.10400390625 +63083 -0.079681396484375 +63084 -0.229400634765625 +63085 -0.1895751953125 +63086 -0.35552978515625 +63087 -0.3006591796875 +63088 -0.441925048828125 +63089 -0.3775634765625 +63090 -0.473846435546875 +63091 -0.4073486328125 +63092 -0.464813232421875 +63093 -0.40167236328125 +63094 -0.419097900390625 +63095 -0.3641357421875 +63096 -0.334320068359375 +63097 -0.29254150390625 +63098 -0.227935791015625 +63099 -0.201934814453125 +63100 -0.12347412109375 +63101 -0.112762451171875 +63102 -0.02764892578125 +63103 -0.030792236328125 +63104 0.077667236328125 +63105 0.05987548828125 +63106 0.2132568359375 +63107 0.177398681640625 +63108 0.38885498046875 +63109 0.330291748046875 +63110 0.582794189453125 +63111 0.499664306640625 +63112 0.734039306640625 +63113 0.63226318359375 +63114 0.800140380859375 +63115 0.6910400390625 +63116 0.7783203125 +63117 0.6734619140625 +63118 0.6651611328125 +63119 0.57647705078125 +63120 0.45965576171875 +63121 0.399139404296875 +63122 0.199188232421875 +63123 0.173919677734375 +63124 -0.050689697265625 +63125 -0.042144775390625 +63126 -0.23297119140625 +63127 -0.19940185546875 +63128 -0.33013916015625 +63129 -0.28271484375 +63130 -0.368408203125 +63131 -0.31500244140625 +63132 -0.378936767578125 +63133 -0.323455810546875 +63134 -0.376983642578125 +63135 -0.3214111328125 +63136 -0.37969970703125 +63137 -0.3238525390625 +63138 -0.391510009765625 +63139 -0.3345947265625 +63140 -0.385345458984375 +63141 -0.33001708984375 +63142 -0.3419189453125 +63143 -0.29327392578125 +63144 -0.28289794921875 +63145 -0.2431640625 +63146 -0.251617431640625 +63147 -0.217376708984375 +63148 -0.266143798828125 +63149 -0.231597900390625 +63150 -0.273345947265625 +63151 -0.239410400390625 +63152 -0.216796875 +63153 -0.1915283203125 +63154 -0.128265380859375 +63155 -0.11553955078125 +63156 -0.068145751953125 +63157 -0.064117431640625 +63158 -0.0430908203125 +63159 -0.04296875 +63160 -0.024444580078125 +63161 -0.027069091796875 +63162 0.020721435546875 +63163 0.012298583984375 +63164 0.124481201171875 +63165 0.10308837890625 +63166 0.25787353515625 +63167 0.219970703125 +63168 0.379119873046875 +63169 0.32647705078125 +63170 0.47991943359375 +63171 0.415374755859375 +63172 0.5281982421875 +63173 0.4586181640625 +63174 0.511138916015625 +63175 0.4449462890625 +63176 0.456207275390625 +63177 0.39825439453125 +63178 0.407470703125 +63179 0.356903076171875 +63180 0.383758544921875 +63181 0.3372802734375 +63182 0.35687255859375 +63183 0.314727783203125 +63184 0.31182861328125 +63185 0.276123046875 +63186 0.250885009765625 +63187 0.223388671875 +63188 0.1654052734375 +63189 0.14898681640625 +63190 0.035247802734375 +63191 0.035369873046875 +63192 -0.142059326171875 +63193 -0.119598388671875 +63194 -0.33563232421875 +63195 -0.28900146484375 +63196 -0.5345458984375 +63197 -0.463226318359375 +63198 -0.72186279296875 +63199 -0.627471923828125 +63200 -0.836669921875 +63201 -0.728546142578125 +63202 -0.8326416015625 +63203 -0.72601318359375 +63204 -0.7296142578125 +63205 -0.63714599609375 +63206 -0.582550048828125 +63207 -0.509796142578125 +63208 -0.440093994140625 +63209 -0.386322021484375 +63210 -0.324310302734375 +63211 -0.28594970703125 +63212 -0.20147705078125 +63213 -0.17926025390625 +63214 -0.044647216796875 +63215 -0.042694091796875 +63216 0.103973388671875 +63217 0.086944580078125 +63218 0.202392578125 +63219 0.173004150390625 +63220 0.264495849609375 +63221 0.22760009765625 +63222 0.338897705078125 +63223 0.2930908203125 +63224 0.443817138671875 +63225 0.385284423828125 +63226 0.545074462890625 +63227 0.474365234375 +63228 0.6173095703125 +63229 0.53814697265625 +63230 0.6524658203125 +63231 0.569580078125 +63232 0.66339111328125 +63233 0.5802001953125 +63234 0.6561279296875 +63235 0.57537841796875 +63236 0.606781005859375 +63237 0.5335693359375 +63238 0.501190185546875 +63239 0.441802978515625 +63240 0.352783203125 +63241 0.311981201171875 +63242 0.176544189453125 +63243 0.15740966796875 +63244 -0.034820556640625 +63245 -0.02880859375 +63246 -0.258209228515625 +63247 -0.22607421875 +63248 -0.44244384765625 +63249 -0.388397216796875 +63250 -0.5753173828125 +63251 -0.504974365234375 +63252 -0.65203857421875 +63253 -0.571685791015625 +63254 -0.641632080078125 +63255 -0.560638427734375 +63256 -0.562164306640625 +63257 -0.488250732421875 +63258 -0.458038330078125 +63259 -0.394683837890625 +63260 -0.350555419921875 +63261 -0.299102783203125 +63262 -0.260528564453125 +63263 -0.22021484375 +63264 -0.192108154296875 +63265 -0.16162109375 +63266 -0.141937255859375 +63267 -0.1201171875 +63268 -0.1021728515625 +63269 -0.08837890625 +63270 -0.062896728515625 +63271 -0.057159423828125 +63272 -0.011932373046875 +63273 -0.01519775390625 +63274 0.062835693359375 +63275 0.048614501953125 +63276 0.148712158203125 +63277 0.123046875 +63278 0.241729736328125 +63279 0.204620361328125 +63280 0.34912109375 +63281 0.300018310546875 +63282 0.457305908203125 +63283 0.397064208984375 +63284 0.54388427734375 +63285 0.475494384765625 +63286 0.5728759765625 +63287 0.50274658203125 +63288 0.506591796875 +63289 0.444671630859375 +63290 0.351226806640625 +63291 0.306732177734375 +63292 0.146514892578125 +63293 0.124664306640625 +63294 -0.05523681640625 +63295 -0.05438232421875 +63296 -0.21624755859375 +63297 -0.19647216796875 +63298 -0.334930419921875 +63299 -0.300323486328125 +63300 -0.402984619140625 +63301 -0.358642578125 +63302 -0.4412841796875 +63303 -0.39044189453125 +63304 -0.49578857421875 +63305 -0.437408447265625 +63306 -0.5601806640625 +63307 -0.49395751953125 +63308 -0.600738525390625 +63309 -0.5296630859375 +63310 -0.584228515625 +63311 -0.5145263671875 +63312 -0.47930908203125 +63313 -0.42022705078125 +63314 -0.27935791015625 +63315 -0.24072265625 +63316 -0.0089111328125 +63317 0.001861572265625 +63318 0.268798828125 +63319 0.250518798828125 +63320 0.482818603515625 +63321 0.441253662109375 +63322 0.60369873046875 +63323 0.547637939453125 +63324 0.650421142578125 +63325 0.586944580078125 +63326 0.66400146484375 +63327 0.596435546875 +63328 0.6414794921875 +63329 0.57354736328125 +63330 0.572540283203125 +63331 0.50909423828125 +63332 0.498138427734375 +63333 0.440216064453125 +63334 0.439453125 +63335 0.386138916015625 +63336 0.375518798828125 +63337 0.327972412109375 +63338 0.274505615234375 +63339 0.2369384765625 +63340 0.1087646484375 +63341 0.087982177734375 +63342 -0.099395751953125 +63343 -0.09881591796875 +63344 -0.3182373046875 +63345 -0.2947998046875 +63346 -0.5489501953125 +63347 -0.501190185546875 +63348 -0.7738037109375 +63349 -0.702056884765625 +63350 -0.86383056640625 +63351 -0.84967041015625 +63352 -0.870391845703125 +63353 -0.86102294921875 +63354 -0.86895751953125 +63355 -0.860748291015625 +63356 -0.861053466796875 +63357 -0.85394287109375 +63358 -0.765869140625 +63359 -0.725738525390625 +63360 -0.5301513671875 +63361 -0.516815185546875 +63362 -0.214691162109375 +63363 -0.233642578125 +63364 0.137359619140625 +63365 0.084808349609375 +63366 0.474822998046875 +63367 0.392181396484375 +63368 0.76239013671875 +63369 0.6563720703125 +63370 0.867462158203125 +63371 0.853057861328125 +63372 0.870361328125 +63373 0.86846923828125 +63374 0.86480712890625 +63375 0.870361328125 +63376 0.831817626953125 +63377 0.864654541015625 +63378 0.677581787109375 +63379 0.849761962890625 +63380 0.495880126953125 +63381 0.71282958984375 +63382 0.30767822265625 +63383 0.554840087890625 +63384 0.116180419921875 +63385 0.37847900390625 +63386 -0.110748291015625 +63387 0.1552734375 +63388 -0.381805419921875 +63389 -0.1212158203125 +63390 -0.6572265625 +63391 -0.4129638671875 +63392 -0.857421875 +63393 -0.666839599609375 +63394 -0.870391845703125 +63395 -0.8453369140625 +63396 -0.870391845703125 +63397 -0.864227294921875 +63398 -0.86444091796875 +63399 -0.8690185546875 +63400 -0.85723876953125 +63401 -0.870391845703125 +63402 -0.790008544921875 +63403 -0.868011474609375 +63404 -0.62847900390625 +63405 -0.856781005859375 +63406 -0.3956298828125 +63407 -0.689697265625 +63408 -0.126708984375 +63409 -0.4527587890625 +63410 0.150115966796875 +63411 -0.190032958984375 +63412 0.424041748046875 +63413 0.08746337890625 +63414 0.670623779296875 +63415 0.355499267578125 +63416 0.854522705078125 +63417 0.579681396484375 +63418 0.866485595703125 +63419 0.745025634765625 +63420 0.86920166015625 +63421 0.8389892578125 +63422 0.8653564453125 +63423 0.857208251953125 +63424 0.857147216796875 +63425 0.85736083984375 +63426 0.766845703125 +63427 0.842193603515625 +63428 0.628509521484375 +63429 0.7698974609375 +63430 0.462127685546875 +63431 0.659698486328125 +63432 0.297210693359375 +63433 0.5364990234375 +63434 0.14862060546875 +63435 0.412689208984375 +63436 -0.00537109375 +63437 0.268524169921875 +63438 -0.15753173828125 +63439 0.111236572265625 +63440 -0.31304931640625 +63441 -0.062347412109375 +63442 -0.48876953125 +63443 -0.265289306640625 +63444 -0.6416015625 +63445 -0.455902099609375 +63446 -0.751373291015625 +63447 -0.61285400390625 +63448 -0.84619140625 +63449 -0.758270263671875 +63450 -0.861297607421875 +63451 -0.857330322265625 +63452 -0.863250732421875 +63453 -0.864990234375 +63454 -0.856597900390625 +63455 -0.864044189453125 +63456 -0.7498779296875 +63457 -0.8558349609375 +63458 -0.624542236328125 +63459 -0.779022216796875 +63460 -0.47808837890625 +63461 -0.659759521484375 +63462 -0.253387451171875 +63463 -0.45697021484375 +63464 0.003692626953125 +63465 -0.212432861328125 +63466 0.2257080078125 +63467 0.0118408203125 +63468 0.427154541015625 +63469 0.227294921875 +63470 0.643218994140625 +63471 0.463653564453125 +63472 0.855926513671875 +63473 0.712921142578125 +63474 0.870361328125 +63475 0.862030029296875 +63476 0.870361328125 +63477 0.870361328125 +63478 0.862762451171875 +63479 0.870361328125 +63480 0.79669189453125 +63481 0.86285400390625 +63482 0.595794677734375 +63483 0.78900146484375 +63484 0.362152099609375 +63485 0.602325439453125 +63486 0.1270751953125 +63487 0.398681640625 +63488 -0.086944580078125 +63489 0.19891357421875 +63490 -0.2784423828125 +63491 0.00543212890625 +63492 -0.484832763671875 +63493 -0.215362548828125 +63494 -0.729583740234375 +63495 -0.48388671875 +63496 -0.86688232421875 +63497 -0.755859375 +63498 -0.870391845703125 +63499 -0.867706298828125 +63500 -0.86859130859375 +63501 -0.870391845703125 +63502 -0.86279296875 +63503 -0.868743896484375 +63504 -0.817962646484375 +63505 -0.86029052734375 +63506 -0.6116943359375 +63507 -0.73370361328125 +63508 -0.3128662109375 +63509 -0.464111328125 +63510 0.039398193359375 +63511 -0.134979248046875 +63512 0.422821044921875 +63513 0.23260498046875 +63514 0.805145263671875 +63515 0.607666015625 +63516 0.870361328125 +63517 0.86260986328125 +63518 0.870361328125 +63519 0.870361328125 +63520 0.860015869140625 +63521 0.8677978515625 +63522 0.727935791015625 +63523 0.8558349609375 +63524 0.48114013671875 +63525 0.680572509765625 +63526 0.2059326171875 +63527 0.4537353515625 +63528 -0.06103515625 +63529 0.219512939453125 +63530 -0.29913330078125 +63531 -0.00323486328125 +63532 -0.516204833984375 +63533 -0.221405029296875 +63534 -0.7252197265625 +63535 -0.44586181640625 +63536 -0.85980224609375 +63537 -0.652923583984375 +63538 -0.870391845703125 +63539 -0.8131103515625 +63540 -0.870391845703125 +63541 -0.859954833984375 +63542 -0.858062744140625 +63543 -0.8582763671875 +63544 -0.673004150390625 +63545 -0.7730712890625 +63546 -0.42694091796875 +63547 -0.617034912109375 +63548 -0.2100830078125 +63549 -0.474365234375 +63550 -0.0362548828125 +63551 -0.3551025390625 +63552 0.10943603515625 +63553 -0.243408203125 +63554 0.23516845703125 +63555 -0.13079833984375 +63556 0.373687744140625 +63557 0.0130615234375 +63558 0.517791748046875 +63559 0.180084228515625 +63560 0.602783203125 +63561 0.307464599609375 +63562 0.635711669921875 +63563 0.39874267578125 +63564 0.655181884765625 +63565 0.486358642578125 +63566 0.65948486328125 +63567 0.564697265625 +63568 0.651275634765625 +63569 0.632049560546875 +63570 0.61846923828125 +63571 0.6729736328125 +63572 0.53753662109375 +63573 0.661651611328125 +63574 0.404144287109375 +63575 0.590728759765625 +63576 0.22186279296875 +63577 0.460906982421875 +63578 0.003997802734375 +63579 0.282806396484375 +63580 -0.22100830078125 +63581 0.08203125 +63582 -0.42449951171875 +63583 -0.114654541015625 +63584 -0.579833984375 +63585 -0.281494140625 +63586 -0.641876220703125 +63587 -0.374603271484375 +63588 -0.6177978515625 +63589 -0.3984375 +63590 -0.575531005859375 +63591 -0.413726806640625 +63592 -0.526336669921875 +63593 -0.427764892578125 +63594 -0.42645263671875 +63595 -0.39617919921875 +63596 -0.2581787109375 +63597 -0.2989501953125 +63598 -0.068695068359375 +63599 -0.176971435546875 +63600 0.09222412109375 +63601 -0.073944091796875 +63602 0.232147216796875 +63603 0.01953125 +63604 0.3509521484375 +63605 0.1051025390625 +63606 0.410064697265625 +63607 0.147705078125 +63608 0.372955322265625 +63609 0.11346435546875 +63610 0.2554931640625 +63611 0.016845703125 +63612 0.10711669921875 +63613 -0.096923828125 +63614 -0.052886962890625 +63615 -0.2115478515625 +63616 -0.186279296875 +63617 -0.293426513671875 +63618 -0.23291015625 +63619 -0.288848876953125 +63620 -0.209442138671875 +63621 -0.2161865234375 +63622 -0.174163818359375 +63623 -0.1328125 +63624 -0.126739501953125 +63625 -0.0411376953125 +63626 -0.048126220703125 +63627 0.0740966796875 +63628 0.0426025390625 +63629 0.192962646484375 +63630 0.10748291015625 +63631 0.2783203125 +63632 0.1409912109375 +63633 0.32391357421875 +63634 0.19708251953125 +63635 0.3797607421875 +63636 0.273651123046875 +63637 0.444061279296875 +63638 0.31768798828125 +63639 0.4678955078125 +63640 0.341094970703125 +63641 0.463623046875 +63642 0.368011474609375 +63643 0.455535888671875 +63644 0.37249755859375 +63645 0.421356201171875 +63646 0.30072021484375 +63647 0.31292724609375 +63648 0.1517333984375 +63649 0.13165283203125 +63650 -0.01470947265625 +63651 -0.064208984375 +63652 -0.1883544921875 +63653 -0.262908935546875 +63654 -0.372711181640625 +63655 -0.46588134765625 +63656 -0.51397705078125 +63657 -0.62127685546875 +63658 -0.57177734375 +63659 -0.690216064453125 +63660 -0.53948974609375 +63661 -0.66595458984375 +63662 -0.43511962890625 +63663 -0.565277099609375 +63664 -0.2962646484375 +63665 -0.423828125 +63666 -0.161102294921875 +63667 -0.278167724609375 +63668 -0.0435791015625 +63669 -0.142608642578125 +63670 0.060394287109375 +63671 -0.014892578125 +63672 0.13665771484375 +63673 0.08990478515625 +63674 0.170135498046875 +63675 0.155792236328125 +63676 0.16552734375 +63677 0.18524169921875 +63678 0.15728759765625 +63679 0.208648681640625 +63680 0.150787353515625 +63681 0.229461669921875 +63682 0.12200927734375 +63683 0.223846435546875 +63684 0.080108642578125 +63685 0.199371337890625 +63686 0.05126953125 +63687 0.179901123046875 +63688 0.062896728515625 +63689 0.19091796875 +63690 0.09271240234375 +63691 0.21173095703125 +63692 0.092987060546875 +63693 0.19830322265625 +63694 0.07855224609375 +63695 0.165435791015625 +63696 0.06427001953125 +63697 0.128265380859375 +63698 0.0347900390625 +63699 0.07379150390625 +63700 -0.01171875 +63701 0.001861572265625 +63702 -0.056060791015625 +63703 -0.06793212890625 +63704 -0.055511474609375 +63705 -0.09405517578125 +63706 -0.010467529296875 +63707 -0.075439453125 +63708 0.02508544921875 +63709 -0.0614013671875 +63710 0.025665283203125 +63711 -0.074859619140625 +63712 0.017333984375 +63713 -0.0908203125 +63714 0.00189208984375 +63715 -0.107330322265625 +63716 -0.03173828125 +63717 -0.134857177734375 +63718 -0.071502685546875 +63719 -0.16253662109375 +63720 -0.13543701171875 +63721 -0.2078857421875 +63722 -0.219970703125 +63723 -0.268524169921875 +63724 -0.300506591796875 +63725 -0.322540283203125 +63726 -0.376312255859375 +63727 -0.370513916015625 +63728 -0.416107177734375 +63729 -0.384429931640625 +63730 -0.371124267578125 +63731 -0.319915771484375 +63732 -0.242279052734375 +63733 -0.17901611328125 +63734 -0.069732666015625 +63735 -0.000396728515625 +63736 0.125640869140625 +63737 0.195526123046875 +63738 0.31268310546875 +63739 0.3790283203125 +63740 0.45501708984375 +63741 0.5157470703125 +63742 0.554779052734375 +63743 0.60760498046875 +63744 0.61065673828125 +63745 0.653839111328125 +63746 0.610931396484375 +63747 0.643829345703125 +63748 0.531463623046875 +63749 0.5550537109375 +63750 0.3883056640625 +63751 0.403472900390625 +63752 0.23468017578125 +63753 0.24053955078125 +63754 0.095245361328125 +63755 0.09063720703125 +63756 -0.00396728515625 +63757 -0.02056884765625 +63758 -0.04852294921875 +63759 -0.0784912109375 +63760 -0.055145263671875 +63761 -0.098175048828125 +63762 -0.0758056640625 +63763 -0.128387451171875 +63764 -0.138702392578125 +63765 -0.19537353515625 +63766 -0.209197998046875 +63767 -0.26593017578125 +63768 -0.289031982421875 +63769 -0.34161376953125 +63770 -0.37884521484375 +63771 -0.42315673828125 +63772 -0.456329345703125 +63773 -0.489654541015625 +63774 -0.51641845703125 +63775 -0.536773681640625 +63776 -0.519287109375 +63777 -0.527313232421875 +63778 -0.458251953125 +63779 -0.45562744140625 +63780 -0.384796142578125 +63781 -0.371429443359375 +63782 -0.323699951171875 +63783 -0.299072265625 +63784 -0.269287109375 +63785 -0.233917236328125 +63786 -0.1951904296875 +63787 -0.151641845703125 +63788 -0.100006103515625 +63789 -0.051513671875 +63790 -0.01055908203125 +63791 0.040496826171875 +63792 0.1033935546875 +63793 0.152801513671875 +63794 0.24908447265625 +63795 0.292144775390625 +63796 0.373199462890625 +63797 0.407958984375 +63798 0.45806884765625 +63799 0.483642578125 +63800 0.511474609375 +63801 0.52691650390625 +63802 0.565399169921875 +63803 0.56866455078125 +63804 0.61138916015625 +63805 0.601409912109375 +63806 0.5897216796875 +63807 0.569091796875 +63808 0.4906005859375 +63809 0.4630126953125 +63810 0.33148193359375 +63811 0.300445556640625 +63812 0.147796630859375 +63813 0.11566162109375 +63814 -0.01873779296875 +63815 -0.05120849609375 +63816 -0.140289306640625 +63817 -0.173248291015625 +63818 -0.191986083984375 +63819 -0.2265625 +63820 -0.184295654296875 +63821 -0.220916748046875 +63822 -0.161834716796875 +63823 -0.198699951171875 +63824 -0.166595458984375 +63825 -0.19989013671875 +63826 -0.19390869140625 +63827 -0.220306396484375 +63828 -0.22442626953125 +63829 -0.241943359375 +63830 -0.279754638671875 +63831 -0.2857666015625 +63832 -0.3389892578125 +63833 -0.332489013671875 +63834 -0.3543701171875 +63835 -0.337249755859375 +63836 -0.348175048828125 +63837 -0.32177734375 +63838 -0.32598876953125 +63839 -0.2918701171875 +63840 -0.2581787109375 +63841 -0.2198486328125 +63842 -0.139801025390625 +63843 -0.101409912109375 +63844 0.014617919921875 +63845 0.049407958984375 +63846 0.144378662109375 +63847 0.174713134765625 +63848 0.221038818359375 +63849 0.247467041015625 +63850 0.27069091796875 +63851 0.292510986328125 +63852 0.294036865234375 +63853 0.31072998046875 +63854 0.311767578125 +63855 0.322021484375 +63856 0.339141845703125 +63857 0.34130859375 +63858 0.360260009765625 +63859 0.35406494140625 +63860 0.360504150390625 +63861 0.3468017578125 +63862 0.308380126953125 +63863 0.289337158203125 +63864 0.18170166015625 +63865 0.160491943359375 +63866 0.0047607421875 +63867 -0.015869140625 +63868 -0.17559814453125 +63869 -0.194244384765625 +63870 -0.3143310546875 +63871 -0.33087158203125 +63872 -0.36785888671875 +63873 -0.383544921875 +63874 -0.36248779296875 +63875 -0.377685546875 +63876 -0.343536376953125 +63877 -0.35723876953125 +63878 -0.3018798828125 +63879 -0.313568115234375 +63880 -0.231414794921875 +63881 -0.240966796875 +63882 -0.117645263671875 +63883 -0.12567138671875 +63884 0.007049560546875 +63885 0.00067138671875 +63886 0.087982177734375 +63887 0.084808349609375 +63888 0.13946533203125 +63889 0.14031982421875 +63890 0.17425537109375 +63891 0.179229736328125 +63892 0.188201904296875 +63893 0.197235107421875 +63894 0.171234130859375 +63895 0.184326171875 +63896 0.118438720703125 +63897 0.135650634765625 +63898 0.05706787109375 +63899 0.07745361328125 +63900 -0.010711669921875 +63901 0.011749267578125 +63902 -0.0914306640625 +63903 -0.067718505859375 +63904 -0.162322998046875 +63905 -0.13873291015625 +63906 -0.194549560546875 +63907 -0.173248291015625 +63908 -0.1492919921875 +63909 -0.133514404296875 +63910 -0.02166748046875 +63911 -0.0145263671875 +63912 0.124053955078125 +63913 0.12176513671875 +63914 0.211151123046875 +63915 0.201385498046875 +63916 0.240447998046875 +63917 0.225372314453125 +63918 0.242218017578125 +63919 0.22320556640625 +63920 0.2257080078125 +63921 0.2041015625 +63922 0.194366455078125 +63923 0.1715087890625 +63924 0.115509033203125 +63925 0.0938720703125 +63926 0.0128173828125 +63927 -0.00579833984375 +63928 -0.053802490234375 +63929 -0.069580078125 +63930 -0.110626220703125 +63931 -0.1229248046875 +63932 -0.199493408203125 +63933 -0.20648193359375 +63934 -0.29437255859375 +63935 -0.29522705078125 +63936 -0.33221435546875 +63937 -0.328277587890625 +63938 -0.27972412109375 +63939 -0.27362060546875 +63940 -0.185333251953125 +63941 -0.1783447265625 +63942 -0.128204345703125 +63943 -0.119293212890625 +63944 -0.115692138671875 +63945 -0.103759765625 +63946 -0.116455078125 +63947 -0.10162353515625 +63948 -0.105926513671875 +63949 -0.0892333984375 +63950 -0.053955078125 +63951 -0.03753662109375 +63952 0.048797607421875 +63953 0.06243896484375 +63954 0.157318115234375 +63955 0.16717529296875 +63956 0.212005615234375 +63957 0.218994140625 +63958 0.218475341796875 +63959 0.223388671875 +63960 0.23724365234375 +63961 0.239105224609375 +63962 0.30535888671875 +63963 0.302154541015625 +63964 0.38128662109375 +63965 0.372467041015625 +63966 0.404449462890625 +63967 0.3916015625 +63968 0.3944091796875 +63969 0.378662109375 +63970 0.3885498046875 +63971 0.370025634765625 +63972 0.362640380859375 +63973 0.3424072265625 +63974 0.27362060546875 +63975 0.2542724609375 +63976 0.11712646484375 +63977 0.101470947265625 +63978 -0.054901123046875 +63979 -0.065673828125 +63980 -0.19085693359375 +63981 -0.197174072265625 +63982 -0.28570556640625 +63983 -0.2882080078125 +63984 -0.339263916015625 +63985 -0.33868408203125 +63986 -0.3775634765625 +63987 -0.37384033203125 +63988 -0.445709228515625 +63989 -0.437469482421875 +63990 -0.535064697265625 +63991 -0.521392822265625 +63992 -0.629058837890625 +63993 -0.609710693359375 +63994 -0.697601318359375 +63995 -0.673431396484375 +63996 -0.70391845703125 +63997 -0.6771240234375 +63998 -0.6424560546875 +63999 -0.615509033203125 +64000 -0.491241455078125 +64001 -0.466949462890625 +64002 -0.265716552734375 +64003 -0.246307373046875 +64004 -0.023712158203125 +64005 -0.010406494140625 +64006 0.201751708984375 +64007 0.208251953125 +64008 0.375823974609375 +64009 0.37530517578125 +64010 0.485076904296875 +64011 0.477813720703125 +64012 0.56884765625 +64013 0.555511474609375 +64014 0.634765625 +64015 0.61639404296875 +64016 0.63763427734375 +64017 0.615509033203125 +64018 0.5660400390625 +64019 0.54156494140625 +64020 0.4720458984375 +64021 0.44671630859375 +64022 0.40692138671875 +64023 0.382232666015625 +64024 0.3778076171875 +64025 0.35516357421875 +64026 0.376953125 +64027 0.357574462890625 +64028 0.371978759765625 +64029 0.35687255859375 +64030 0.313140869140625 +64031 0.30303955078125 +64032 0.184417724609375 +64033 0.17974853515625 +64034 0.011199951171875 +64035 0.012054443359375 +64036 -0.171051025390625 +64037 -0.164886474609375 +64038 -0.33740234375 +64039 -0.326416015625 +64040 -0.47198486328125 +64041 -0.456939697265625 +64042 -0.560394287109375 +64043 -0.542236328125 +64044 -0.58056640625 +64045 -0.560394287109375 +64046 -0.54754638671875 +64047 -0.526519775390625 +64048 -0.508575439453125 +64049 -0.48785400390625 +64050 -0.459503173828125 +64051 -0.440216064453125 +64052 -0.394378662109375 +64053 -0.377532958984375 +64054 -0.35260009765625 +64055 -0.33905029296875 +64056 -0.31170654296875 +64057 -0.302093505859375 +64058 -0.197418212890625 +64059 -0.192169189453125 +64060 -0.007965087890625 +64061 -0.007232666015625 +64062 0.207489013671875 +64063 0.203765869140625 +64064 0.409210205078125 +64065 0.4013671875 +64066 0.57208251953125 +64067 0.560638427734375 +64068 0.66595458984375 +64069 0.651641845703125 +64070 0.65875244140625 +64071 0.642425537109375 +64072 0.56744384765625 +64073 0.550048828125 +64074 0.431396484375 +64075 0.413909912109375 +64076 0.29443359375 +64077 0.27783203125 +64078 0.182464599609375 +64079 0.167633056640625 +64080 0.06365966796875 +64081 0.051361083984375 +64082 -0.075958251953125 +64083 -0.08514404296875 +64084 -0.189422607421875 +64085 -0.195068359375 +64086 -0.271942138671875 +64087 -0.273834228515625 +64088 -0.342529296875 +64089 -0.340667724609375 +64090 -0.364166259765625 +64091 -0.3587646484375 +64092 -0.327239990234375 +64093 -0.3187255859375 +64094 -0.2769775390625 +64095 -0.265899658203125 +64096 -0.253692626953125 +64097 -0.240753173828125 +64098 -0.24365234375 +64099 -0.2296142578125 +64100 -0.1983642578125 +64101 -0.184051513671875 +64102 -0.116241455078125 +64103 -0.102447509765625 +64104 -0.036834716796875 +64105 -0.0242919921875 +64106 0.034881591796875 +64107 0.0455322265625 +64108 0.09124755859375 +64109 0.099456787109375 +64110 0.10888671875 +64111 0.114288330078125 +64112 0.125518798828125 +64113 0.127899169921875 +64114 0.15771484375 +64115 0.15704345703125 +64116 0.17828369140625 +64117 0.1746826171875 +64118 0.17108154296875 +64119 0.164825439453125 +64120 0.129974365234375 +64121 0.121490478515625 +64122 0.082427978515625 +64123 0.07220458984375 +64124 0.027679443359375 +64125 0.016326904296875 +64126 -0.065643310546875 +64127 -0.07745361328125 +64128 -0.15936279296875 +64129 -0.17095947265625 +64130 -0.21307373046875 +64131 -0.22381591796875 +64132 -0.234649658203125 +64133 -0.24395751953125 +64134 -0.2001953125 +64135 -0.20758056640625 +64136 -0.119171142578125 +64137 -0.124298095703125 +64138 -0.024749755859375 +64139 -0.02740478515625 +64140 0.085784912109375 +64141 0.085662841796875 +64142 0.178131103515625 +64143 0.18048095703125 +64144 0.215576171875 +64145 0.220184326171875 +64146 0.211456298828125 +64147 0.217987060546875 +64148 0.17523193359375 +64149 0.183258056640625 +64150 0.128753662109375 +64151 0.137786865234375 +64152 0.1019287109375 +64153 0.1114501953125 +64154 0.0743408203125 +64155 0.083831787109375 +64156 0.04327392578125 +64157 0.05224609375 +64158 0.038177490234375 +64159 0.046173095703125 +64160 0.076263427734375 +64161 0.0828857421875 +64162 0.14105224609375 +64163 0.145965576171875 +64164 0.186431884765625 +64165 0.189422607421875 +64166 0.188812255859375 +64167 0.18975830078125 +64168 0.1390380859375 +64169 0.137939453125 +64170 0.041778564453125 +64171 0.03875732421875 +64172 -0.079437255859375 +64173 -0.08416748046875 +64174 -0.219390869140625 +64175 -0.22552490234375 +64176 -0.367828369140625 +64177 -0.375 +64178 -0.494873046875 +64179 -0.502685546875 +64180 -0.556243896484375 +64181 -0.56427001953125 +64182 -0.508697509765625 +64183 -0.516510009765625 +64184 -0.3756103515625 +64185 -0.382781982421875 +64186 -0.218902587890625 +64187 -0.225067138671875 +64188 -0.063751220703125 +64189 -0.068603515625 +64190 0.091552734375 +64191 0.088226318359375 +64192 0.23602294921875 +64193 0.234375 +64194 0.342987060546875 +64195 0.343048095703125 +64196 0.39520263671875 +64197 0.39691162109375 +64198 0.389373779296875 +64199 0.392578125 +64200 0.324249267578125 +64201 0.3287353515625 +64202 0.224090576171875 +64203 0.229583740234375 +64204 0.124267578125 +64205 0.13043212890625 +64206 0.037078857421875 +64207 0.043548583984375 +64208 -0.010101318359375 +64209 -0.003692626953125 +64210 -0.019439697265625 +64211 -0.013458251953125 +64212 -0.022796630859375 +64213 -0.017547607421875 +64214 -0.001556396484375 +64215 0.002655029296875 +64216 0.056304931640625 +64217 0.05926513671875 +64218 0.106719970703125 +64219 0.1082763671875 +64220 0.096893310546875 +64221 0.09698486328125 +64222 0.042694091796875 +64223 0.041351318359375 +64224 -0.018035888671875 +64225 -0.02069091796875 +64226 -0.07586669921875 +64227 -0.07965087890625 +64228 -0.11944580078125 +64229 -0.124114990234375 +64230 -0.15972900390625 +64231 -0.165008544921875 +64232 -0.202606201171875 +64233 -0.20819091796875 +64234 -0.24859619140625 +64235 -0.254180908203125 +64236 -0.30517578125 +64237 -0.310455322265625 +64238 -0.36212158203125 +64239 -0.3668212890625 +64240 -0.39141845703125 +64241 -0.395294189453125 +64242 -0.35528564453125 +64243 -0.358154296875 +64244 -0.249969482421875 +64245 -0.251708984375 +64246 -0.092864990234375 +64247 -0.093414306640625 +64248 0.08905029296875 +64249 0.089691162109375 +64250 0.2352294921875 +64251 0.23699951171875 +64252 0.318817138671875 +64253 0.32159423828125 +64254 0.358642578125 +64255 0.36224365234375 +64256 0.348358154296875 +64257 0.351959228515625 +64258 0.288116455078125 +64259 0.29022216796875 +64260 0.227569580078125 +64261 0.22784423828125 +64262 0.201690673828125 +64263 0.20123291015625 +64264 0.184661865234375 +64265 0.183929443359375 +64266 0.1600341796875 +64267 0.159027099609375 +64268 0.15423583984375 +64269 0.1539306640625 +64270 0.157745361328125 +64271 0.158782958984375 +64272 0.1309814453125 +64273 0.13262939453125 +64274 0.098358154296875 +64275 0.10064697265625 +64276 0.082366943359375 +64277 0.08599853515625 +64278 0.0484619140625 +64279 0.0528564453125 +64280 -0.015777587890625 +64281 -0.011749267578125 +64282 -0.1097412109375 +64283 -0.1072998046875 +64284 -0.232635498046875 +64285 -0.233062744140625 +64286 -0.355682373046875 +64287 -0.359344482421875 +64288 -0.439605712890625 +64289 -0.4456787109375 +64290 -0.470184326171875 +64291 -0.47735595703125 +64292 -0.46051025390625 +64293 -0.4678955078125 +64294 -0.414764404296875 +64295 -0.421600341796875 +64296 -0.33074951171875 +64297 -0.33612060546875 +64298 -0.2254638671875 +64299 -0.22894287109375 +64300 -0.121856689453125 +64301 -0.1236572265625 +64302 -0.02655029296875 +64303 -0.027008056640625 +64304 0.077880859375 +64305 0.0791015625 +64306 0.21142578125 +64307 0.21539306640625 +64308 0.383331298828125 +64309 0.391571044921875 +64310 0.57257080078125 +64311 0.5859375 +64312 0.719970703125 +64313 0.7374267578125 +64314 0.784423828125 +64315 0.8035888671875 +64316 0.763214111328125 +64317 0.781646728515625 +64318 0.653045654296875 +64319 0.668182373046875 +64320 0.453033447265625 +64321 0.46221923828125 +64322 0.19940185546875 +64323 0.201171875 +64324 -0.0443115234375 +64325 -0.04937744140625 +64326 -0.222808837890625 +64327 -0.232391357421875 +64328 -0.319000244140625 +64329 -0.330322265625 +64330 -0.358123779296875 +64331 -0.36932373046875 +64332 -0.3702392578125 +64333 -0.380523681640625 +64334 -0.370025634765625 +64335 -0.379150390625 +64336 -0.3740234375 +64337 -0.382293701171875 +64338 -0.38641357421875 +64339 -0.394378662109375 +64340 -0.3809814453125 +64341 -0.388336181640625 +64342 -0.33905029296875 +64343 -0.344879150390625 +64344 -0.281585693359375 +64345 -0.28564453125 +64346 -0.25054931640625 +64347 -0.2540283203125 +64348 -0.263458251953125 +64349 -0.268096923828125 +64350 -0.26898193359375 +64351 -0.274749755859375 +64352 -0.212615966796875 +64353 -0.21759033203125 +64354 -0.125152587890625 +64355 -0.12841796875 +64356 -0.065216064453125 +64357 -0.06768798828125 +64358 -0.039306640625 +64359 -0.04205322265625 +64360 -0.019775390625 +64361 -0.02288818359375 +64362 0.02520751953125 +64363 0.022705078125 +64364 0.1265869140625 +64365 0.12677001953125 +64366 0.25628662109375 +64367 0.260345458984375 +64368 0.37384033203125 +64369 0.381622314453125 +64370 0.471221923828125 +64371 0.482330322265625 +64372 0.51739501953125 +64373 0.5303955078125 +64374 0.500030517578125 +64375 0.513031005859375 +64376 0.44573974609375 +64377 0.45770263671875 +64378 0.39727783203125 +64379 0.40850830078125 +64380 0.3729248046875 +64381 0.384307861328125 +64382 0.345458984375 +64383 0.356903076171875 +64384 0.300445556640625 +64385 0.311370849609375 +64386 0.240142822265625 +64387 0.249969482421875 +64388 0.15625 +64389 0.164093017578125 +64390 0.02935791015625 +64391 0.03363037109375 +64392 -0.14288330078125 +64393 -0.143890380859375 +64394 -0.33056640625 +64395 -0.33758544921875 +64396 -0.5230712890625 +64397 -0.5364990234375 +64398 -0.704010009765625 +64399 -0.723724365234375 +64400 -0.81451416015625 +64401 -0.83831787109375 +64402 -0.80975341796875 +64403 -0.834014892578125 +64404 -0.708984375 +64405 -0.73065185546875 +64406 -0.565460205078125 +64407 -0.58319091796875 +64408 -0.42633056640625 +64409 -0.4403076171875 +64410 -0.31304931640625 +64411 -0.3240966796875 +64412 -0.19305419921875 +64413 -0.20086669921875 +64414 -0.040252685546875 +64415 -0.043670654296875 +64416 0.10443115234375 +64417 0.105255126953125 +64418 0.200286865234375 +64419 0.20391845703125 +64420 0.2607421875 +64421 0.26617431640625 +64422 0.332855224609375 +64423 0.34063720703125 +64424 0.434234619140625 +64425 0.44549560546875 +64426 0.531829833984375 +64427 0.546600341796875 +64428 0.601104736328125 +64429 0.61859130859375 +64430 0.63433837890625 +64431 0.6534423828125 +64432 0.64398193359375 +64433 0.664031982421875 +64434 0.635955810546875 +64435 0.656402587890625 +64436 0.587158203125 +64437 0.606689453125 +64438 0.48394775390625 +64439 0.500732421875 +64440 0.339385986328125 +64441 0.35198974609375 +64442 0.16802978515625 +64443 0.17547607421875 +64444 -0.037139892578125 +64445 -0.036102294921875 +64446 -0.253753662109375 +64447 -0.259613037109375 +64448 -0.4322509765625 +64449 -0.443878173828125 +64450 -0.560791015625 +64451 -0.576690673828125 +64452 -0.634765625 +64453 -0.653289794921875 +64454 -0.624237060546875 +64455 -0.6427001953125 +64456 -0.54669189453125 +64457 -0.563018798828125 +64458 -0.445159912109375 +64459 -0.458648681640625 +64460 -0.34027099609375 +64461 -0.35089111328125 +64462 -0.25225830078125 +64463 -0.26055908203125 +64464 -0.1851806640625 +64465 -0.191864013671875 +64466 -0.135833740234375 +64467 -0.141448974609375 +64468 -0.0966796875 +64469 -0.101470947265625 +64470 -0.058135986328125 +64471 -0.06201171875 +64472 -0.0084228515625 +64473 -0.010894775390625 +64474 0.06414794921875 +64475 0.06396484375 +64476 0.147308349609375 +64477 0.149871826171875 +64478 0.2371826171875 +64479 0.24285888671875 +64480 0.340789794921875 +64481 0.35015869140625 +64482 0.445037841796875 +64483 0.458221435546875 +64484 0.52825927734375 +64485 0.54461669921875 +64486 0.5556640625 +64487 0.573394775390625 +64488 0.49078369140625 +64489 0.506866455078125 +64490 0.339691162109375 +64491 0.35125732421875 +64492 0.140869140625 +64493 0.146331787109375 +64494 -0.05499267578125 +64495 -0.05560302734375 +64496 -0.211334228515625 +64497 -0.216766357421875 +64498 -0.326568603515625 +64499 -0.3355712890625 +64500 -0.392669677734375 +64501 -0.403717041015625 +64502 -0.4298095703125 +64503 -0.442047119140625 +64504 -0.482513427734375 +64505 -0.49652099609375 +64506 -0.54461669921875 +64507 -0.560821533203125 +64508 -0.583526611328125 +64509 -0.60125732421875 +64510 -0.56707763671875 +64511 -0.584625244140625 +64512 -0.46527099609375 +64513 -0.47955322265625 +64514 -0.272430419921875 +64515 -0.279449462890625 +64516 -0.012481689453125 +64517 -0.00885009765625 +64518 0.254608154296875 +64519 0.26898193359375 +64520 0.461822509765625 +64521 0.483123779296875 +64522 0.581085205078125 +64523 0.6041259765625 +64524 0.62969970703125 +64525 0.65093994140625 +64526 0.645782470703125 +64527 0.664581298828125 +64528 0.62640380859375 +64529 0.64208984375 +64530 0.5618896484375 +64531 0.573150634765625 +64532 0.490631103515625 +64533 0.49871826171875 +64534 0.4326171875 +64535 0.439971923828125 +64536 0.36846923828125 +64537 0.375946044921875 +64538 0.268707275390625 +64539 0.274810791015625 +64540 0.1077880859375 +64541 0.10894775390625 +64542 -0.09307861328125 +64543 -0.099365234375 +64544 -0.30377197265625 +64545 -0.318359375 +64546 -0.525115966796875 +64547 -0.549224853515625 +64548 -0.74017333984375 +64549 -0.77423095703125 +64550 -0.859375 +64551 -0.8638916015625 +64552 -0.8671875 +64553 -0.870391845703125 +64554 -0.867279052734375 +64555 -0.868896484375 +64556 -0.8609619140625 +64557 -0.860931396484375 +64558 -0.780975341796875 +64559 -0.764373779296875 +64560 -0.563140869140625 +64561 -0.528350830078125 +64562 -0.2669677734375 +64563 -0.21270751953125 +64564 0.0670166015625 +64565 0.139404296875 +64566 0.39056396484375 +64567 0.476806640625 +64568 0.670135498046875 +64569 0.764190673828125 +64570 0.857269287109375 +64571 0.86761474609375 +64572 0.870361328125 +64573 0.870361328125 +64574 0.870361328125 +64575 0.8646240234375 +64576 0.862762451171875 +64577 0.828948974609375 +64578 0.81683349609375 +64579 0.673553466796875 +64580 0.66668701171875 +64581 0.490966796875 +64582 0.49884033203125 +64583 0.30218505859375 +64584 0.316192626953125 +64585 0.11041259765625 +64586 0.08917236328125 +64587 -0.116455078125 +64588 -0.189239501953125 +64589 -0.38714599609375 +64590 -0.480194091796875 +64591 -0.66192626953125 +64592 -0.729400634765625 +64593 -0.85784912109375 +64594 -0.859344482421875 +64595 -0.870391845703125 +64596 -0.868682861328125 +64597 -0.870391845703125 +64598 -0.870391845703125 +64599 -0.86444091796875 +64600 -0.870025634765625 +64601 -0.85723876953125 +64602 -0.8660888671875 +64603 -0.790008544921875 +64604 -0.84332275390625 +64605 -0.62847900390625 +64606 -0.644500732421875 +64607 -0.3956298828125 +64608 -0.39642333984375 +64609 -0.126708984375 +64610 -0.12567138671875 +64611 0.150115966796875 +64612 0.15655517578125 +64613 0.424041748046875 +64614 0.425537109375 +64615 0.670623779296875 +64616 0.64617919921875 +64617 0.854522705078125 +64618 0.8037109375 +64619 0.866485595703125 +64620 0.85791015625 +64621 0.86920166015625 +64622 0.860809326171875 +64623 0.8653564453125 +64624 0.85931396484375 +64625 0.857147216796875 +64626 0.84466552734375 +64627 0.766845703125 +64628 0.7576904296875 +64629 0.628509521484375 +64630 0.634002685546875 +64631 0.462127685546875 +64632 0.499786376953125 +64633 0.297210693359375 +64634 0.3681640625 +64635 0.14862060546875 +64636 0.218780517578125 +64637 -0.00537109375 +64638 0.05902099609375 +64639 -0.15753173828125 +64640 -0.114654541015625 +64641 -0.31304931640625 +64642 -0.316162109375 +64643 -0.48876953125 +64644 -0.50286865234375 +64645 -0.6416015625 +64646 -0.6533203125 +64647 -0.751373291015625 +64648 -0.7911376953125 +64649 -0.84619140625 +64650 -0.8599853515625 +64651 -0.861297607421875 +64652 -0.866607666015625 +64653 -0.863250732421875 +64654 -0.864501953125 +64655 -0.856597900390625 +64656 -0.855072021484375 +64657 -0.7498779296875 +64658 -0.76239013671875 +64659 -0.624542236328125 +64660 -0.6351318359375 +64661 -0.47808837890625 +64662 -0.424102783203125 +64663 -0.253387451171875 +64664 -0.17254638671875 +64665 0.003692626953125 +64666 0.05548095703125 +64667 0.2257080078125 +64668 0.27215576171875 +64669 0.427154541015625 +64670 0.5086669921875 +64671 0.643218994140625 +64672 0.757232666015625 +64673 0.855926513671875 +64674 0.866546630859375 +64675 0.870361328125 +64676 0.870361328125 +64677 0.870361328125 +64678 0.8665771484375 +64679 0.862762451171875 +64680 0.855560302734375 +64681 0.79669189453125 +64682 0.693359375 +64683 0.595794677734375 +64684 0.483917236328125 +64685 0.362152099609375 +64686 0.264984130859375 +64687 0.1270751953125 +64688 0.0577392578125 +64689 -0.086944580078125 +64690 -0.13580322265625 +64691 -0.2784423828125 +64692 -0.34967041015625 +64693 -0.484832763671875 +64694 -0.60455322265625 +64695 -0.729583740234375 +64696 -0.854766845703125 +64697 -0.86688232421875 +64698 -0.870391845703125 +64699 -0.870391845703125 +64700 -0.870391845703125 +64701 -0.86859130859375 +64702 -0.86614990234375 +64703 -0.86279296875 +64704 -0.855255126953125 +64705 -0.817962646484375 +64706 -0.668487548828125 +64707 -0.6116943359375 +64708 -0.38372802734375 +64709 -0.3128662109375 +64710 -0.044097900390625 +64711 0.039398193359375 +64712 0.328857421875 +64713 0.422821044921875 +64714 0.704010009765625 +64715 0.805145263671875 +64716 0.870361328125 +64717 0.870361328125 +64718 0.870361328125 +64719 0.870361328125 +64720 0.86029052734375 +64721 0.860015869140625 +64722 0.73516845703125 +64723 0.727935791015625 +64724 0.494720458984375 +64725 0.48114013671875 +64726 0.22552490234375 +64727 0.2059326171875 +64728 -0.037384033203125 +64729 -0.06103515625 +64730 -0.27398681640625 +64731 -0.29913330078125 +64732 -0.490875244140625 +64733 -0.516204833984375 +64734 -0.69940185546875 +64735 -0.7252197265625 +64736 -0.85699462890625 +64737 -0.85980224609375 +64738 -0.870025634765625 +64739 -0.870391845703125 +64740 -0.870391845703125 +64741 -0.870391845703125 +64742 -0.85882568359375 +64743 -0.858062744140625 +64744 -0.6898193359375 +64745 -0.673004150390625 +64746 -0.45257568359375 +64747 -0.42694091796875 +64748 -0.240020751953125 +64749 -0.2100830078125 +64750 -0.065643310546875 +64751 -0.0362548828125 +64752 0.083770751953125 +64753 0.10943603515625 +64754 0.21514892578125 +64755 0.23516845703125 +64756 0.358367919921875 +64757 0.373687744140625 +64758 0.505950927734375 +64759 0.517791748046875 +64760 0.5966796875 +64761 0.602783203125 +64762 0.6365966796875 +64763 0.635711669921875 +64764 0.661376953125 +64765 0.655181884765625 +64766 0.669158935546875 +64767 0.65948486328125 +64768 0.6619873046875 +64769 0.651275634765625 +64770 0.628631591796875 +64771 0.61846923828125 +64772 0.547821044921875 +64773 0.53753662109375 +64774 0.416229248046875 +64775 0.404144287109375 +64776 0.237823486328125 +64777 0.22186279296875 +64778 0.025482177734375 +64779 0.003997802734375 +64780 -0.19415283203125 +64781 -0.22100830078125 +64782 -0.394256591796875 +64783 -0.42449951171875 +64784 -0.5498046875 +64785 -0.579833984375 +64786 -0.61920166015625 +64787 -0.641876220703125 +64788 -0.608245849609375 +64789 -0.6177978515625 +64790 -0.57781982421875 +64791 -0.575531005859375 +64792 -0.53778076171875 +64793 -0.526336669921875 +64794 -0.44842529296875 +64795 -0.42645263671875 +64796 -0.29376220703125 +64797 -0.2581787109375 +64798 -0.116668701171875 +64799 -0.068695068359375 +64800 0.03741455078125 +64801 0.09222412109375 +64802 0.174774169921875 +64803 0.232147216796875 +64804 0.294677734375 +64805 0.3509521484375 +64806 0.361480712890625 +64807 0.410064697265625 +64808 0.3414306640625 +64809 0.372955322265625 +64810 0.248138427734375 +64811 0.2554931640625 +64812 0.1256103515625 +64813 0.10711669921875 +64814 -0.009307861328125 +64815 -0.052886962890625 +64816 -0.122528076171875 +64817 -0.186279296875 +64818 -0.1600341796875 +64819 -0.23291015625 +64820 -0.137054443359375 +64821 -0.209442138671875 +64822 -0.1063232421875 +64823 -0.174163818359375 +64824 -0.067352294921875 +64825 -0.126739501953125 +64826 -0.002655029296875 +64827 -0.048126220703125 +64828 0.070953369140625 +64829 0.0426025390625 +64830 0.119659423828125 +64831 0.10748291015625 +64832 0.139068603515625 +64833 0.1409912109375 +64834 0.178558349609375 +64835 0.19708251953125 +64836 0.23687744140625 +64837 0.273651123046875 +64838 0.266693115234375 +64839 0.31768798828125 +64840 0.279266357421875 +64841 0.341094970703125 +64842 0.296844482421875 +64843 0.368011474609375 +64844 0.2962646484375 +64845 0.37249755859375 +64846 0.229095458984375 +64847 0.30072021484375 +64848 0.094482421875 +64849 0.1517333984375 +64850 -0.0535888671875 +64851 -0.01470947265625 +64852 -0.206024169921875 +64853 -0.1883544921875 +64854 -0.366302490234375 +64855 -0.372711181640625 +64856 -0.486236572265625 +64857 -0.51397705078125 +64858 -0.529754638671875 +64859 -0.57177734375 +64860 -0.49139404296875 +64861 -0.53948974609375 +64862 -0.387969970703125 +64863 -0.43511962890625 +64864 -0.25390625 +64865 -0.2962646484375 +64866 -0.124176025390625 +64867 -0.161102294921875 +64868 -0.011749267578125 +64869 -0.0435791015625 +64870 0.086700439453125 +64871 0.060394287109375 +64872 0.158203125 +64873 0.13665771484375 +64874 0.1890869140625 +64875 0.170135498046875 +64876 0.18365478515625 +64877 0.16552734375 +64878 0.173095703125 +64879 0.15728759765625 +64880 0.16253662109375 +64881 0.150787353515625 +64882 0.13055419921875 +64883 0.12200927734375 +64884 0.085784912109375 +64885 0.080108642578125 +64886 0.052276611328125 +64887 0.05126953125 +64888 0.055267333984375 +64889 0.062896728515625 +64890 0.07501220703125 +64891 0.09271240234375 +64892 0.068756103515625 +64893 0.092987060546875 +64894 0.050201416015625 +64895 0.07855224609375 +64896 0.0330810546875 +64897 0.06427001953125 +64898 0.003692626953125 +64899 0.0347900390625 +64900 -0.039520263671875 +64901 -0.01171875 +64902 -0.07916259765625 +64903 -0.056060791015625 +64904 -0.076690673828125 +64905 -0.055511474609375 +64906 -0.0325927734375 +64907 -0.010467529296875 +64908 0.00408935546875 +64909 0.02508544921875 +64910 0.01007080078125 +64911 0.025665283203125 +64912 0.008575439453125 +64913 0.017333984375 +64914 0.0008544921875 +64915 0.00189208984375 +64916 -0.0234375 +64917 -0.03173828125 +64918 -0.05377197265625 +64919 -0.071502685546875 +64920 -0.106719970703125 +64921 -0.13543701171875 +64922 -0.17926025390625 +64923 -0.219970703125 +64924 -0.249359130859375 +64925 -0.300506591796875 +64926 -0.316497802734375 +64927 -0.376312255859375 +64928 -0.352386474609375 +64929 -0.416107177734375 +64930 -0.31292724609375 +64931 -0.371124267578125 +64932 -0.198822021484375 +64933 -0.242279052734375 +64934 -0.046234130859375 +64935 -0.069732666015625 +64936 0.12615966796875 +64937 0.125640869140625 +64938 0.290435791015625 +64939 0.31268310546875 +64940 0.414031982421875 +64941 0.45501708984375 +64942 0.4991455078125 +64943 0.554779052734375 +64944 0.54486083984375 +64945 0.61065673828125 +64946 0.54083251953125 +64947 0.610931396484375 +64948 0.465484619140625 +64949 0.531463623046875 +64950 0.333465576171875 +64951 0.3883056640625 +64952 0.1929931640625 +64953 0.23468017578125 +64954 0.066436767578125 +64955 0.095245361328125 +64956 -0.022674560546875 +64957 -0.00396728515625 +64958 -0.061370849609375 +64959 -0.04852294921875 +64960 -0.064849853515625 +64961 -0.055145263671875 +64962 -0.08026123046875 +64963 -0.0758056640625 +64964 -0.13330078125 +64965 -0.138702392578125 +64966 -0.192901611328125 +64967 -0.209197998046875 +64968 -0.260833740234375 +64969 -0.289031982421875 +64970 -0.337921142578125 +64971 -0.37884521484375 +64972 -0.404205322265625 +64973 -0.456329345703125 +64974 -0.455322265625 +64975 -0.51641845703125 +64976 -0.4554443359375 +64977 -0.519287109375 +64978 -0.39862060546875 +64979 -0.458251953125 +64980 -0.331451416015625 +64981 -0.384796142578125 +64982 -0.276397705078125 +64983 -0.323699951171875 +64984 -0.228240966796875 +64985 -0.269287109375 +64986 -0.1630859375 +64987 -0.1951904296875 +64988 -0.07952880859375 +64989 -0.100006103515625 +64990 -0.001678466796875 +64991 -0.01055908203125 +64992 0.09796142578125 +64993 0.1033935546875 +64994 0.22613525390625 +64995 0.24908447265625 +64996 0.334869384765625 +64997 0.373199462890625 +64998 0.40838623046875 +64999 0.45806884765625 +65000 0.453826904296875 +65001 0.511474609375 +65002 0.500274658203125 +65003 0.565399169921875 +65004 0.54022216796875 +65005 0.61138916015625 +65006 0.519744873046875 +65007 0.5897216796875 +65008 0.429962158203125 +65009 0.4906005859375 +65010 0.286712646484375 +65011 0.33148193359375 +65012 0.1219482421875 +65013 0.147796630859375 +65014 -0.026702880859375 +65015 -0.01873779296875 +65016 -0.134185791015625 +65017 -0.140289306640625 +65018 -0.178192138671875 +65019 -0.191986083984375 +65020 -0.1683349609375 +65021 -0.184295654296875 +65022 -0.145111083984375 +65023 -0.161834716796875 +65024 -0.1466064453125 +65025 -0.166595458984375 +65026 -0.16876220703125 +65027 -0.19390869140625 +65028 -0.1942138671875 +65029 -0.22442626953125 +65030 -0.242523193359375 +65031 -0.279754638671875 +65032 -0.294952392578125 +65033 -0.3389892578125 +65034 -0.30853271484375 +65035 -0.3543701171875 +65036 -0.30328369140625 +65037 -0.348175048828125 +65038 -0.2841796875 +65039 -0.32598876953125 +65040 -0.2244873046875 +65041 -0.2581787109375 +65042 -0.11968994140625 +65043 -0.139801025390625 +65044 0.01727294921875 +65045 0.014617919921875 +65046 0.131866455078125 +65047 0.144378662109375 +65048 0.19866943359375 +65049 0.221038818359375 +65050 0.241241455078125 +65051 0.27069091796875 +65052 0.260345458984375 +65053 0.294036865234375 +65054 0.27471923828125 +65055 0.311767578125 +65056 0.298065185546875 +65057 0.339141845703125 +65058 0.315765380859375 +65059 0.360260009765625 +65060 0.3148193359375 +65061 0.360504150390625 +65062 0.2679443359375 +65063 0.308380126953125 +65064 0.155975341796875 +65065 0.18170166015625 +65066 0.000274658203125 +65067 0.0047607421875 +65068 -0.158172607421875 +65069 -0.17559814453125 +65070 -0.279998779296875 +65071 -0.3143310546875 +65072 -0.327178955078125 +65073 -0.36785888671875 +65074 -0.32257080078125 +65075 -0.36248779296875 +65076 -0.30572509765625 +65077 -0.343536376953125 +65078 -0.268707275390625 +65079 -0.3018798828125 +65080 -0.20623779296875 +65081 -0.231414794921875 +65082 -0.105743408203125 +65083 -0.117645263671875 +65084 0.004425048828125 +65085 0.007049560546875 +65086 0.0765380859375 +65087 0.087982177734375 +65088 0.12298583984375 +65089 0.13946533203125 +65090 0.15478515625 +65091 0.17425537109375 +65092 0.168212890625 +65093 0.188201904296875 +65094 0.1544189453125 +65095 0.171234130859375 +65096 0.10906982421875 +65097 0.118438720703125 +65098 0.055908203125 +65099 0.05706787109375 +65100 -0.003204345703125 +65101 -0.010711669921875 +65102 -0.073974609375 +65103 -0.0914306640625 +65104 -0.136474609375 +65105 -0.162322998046875 +65106 -0.16552734375 +65107 -0.194549560546875 +65108 -0.127227783203125 +65109 -0.1492919921875 +65110 -0.0172119140625 +65111 -0.02166748046875 +65112 0.1085205078125 +65113 0.124053955078125 +65114 0.18316650390625 +65115 0.211151123046875 +65116 0.20751953125 +65117 0.240447998046875 +65118 0.2080078125 +65119 0.242218017578125 +65120 0.192779541015625 +65121 0.2257080078125 +65122 0.16485595703125 +65123 0.194366455078125 +65124 0.09576416015625 +65125 0.115509033203125 +65126 0.00616455078125 +65127 0.0128173828125 +65128 -0.05169677734375 +65129 -0.053802490234375 +65130 -0.100738525390625 +65131 -0.110626220703125 +65132 -0.177520751953125 +65133 -0.199493408203125 +65134 -0.259368896484375 +65135 -0.29437255859375 +65136 -0.291351318359375 +65137 -0.33221435546875 +65138 -0.2445068359375 +65139 -0.27972412109375 +65140 -0.161102294921875 +65141 -0.185333251953125 +65142 -0.1102294921875 +65143 -0.128204345703125 +65144 -0.098358154296875 +65145 -0.115692138671875 +65146 -0.09820556640625 +65147 -0.116455078125 +65148 -0.088409423828125 +65149 -0.105926513671875 +65150 -0.042724609375 +65151 -0.053955078125 +65152 0.046966552734375 +65153 0.048797607421875 +65154 0.141448974609375 +65155 0.157318115234375 +65156 0.188751220703125 +65157 0.212005615234375 +65158 0.19378662109375 +65159 0.218475341796875 +65160 0.209381103515625 +65161 0.23724365234375 +65162 0.267913818359375 +65163 0.30535888671875 +65164 0.333160400390625 +65165 0.38128662109375 +65166 0.35235595703125 +65167 0.404449462890625 +65168 0.342620849609375 +65169 0.3944091796875 +65170 0.33660888671875 +65171 0.3885498046875 +65172 0.31329345703125 +65173 0.362640380859375 +65174 0.235137939453125 +65175 0.27362060546875 +65176 0.098358154296875 +65177 0.11712646484375 +65178 -0.051727294921875 +65179 -0.054901123046875 +65180 -0.170135498046875 +65181 -0.19085693359375 +65182 -0.25250244140625 +65183 -0.28570556640625 +65184 -0.2987060546875 +65185 -0.339263916015625 +65186 -0.331451416015625 +65187 -0.3775634765625 +65188 -0.390106201171875 +65189 -0.445709228515625 +65190 -0.46722412109375 +65191 -0.535064697265625 +65192 -0.548370361328125 +65193 -0.629058837890625 +65194 -0.60736083984375 +65195 -0.697601318359375 +65196 -0.612152099609375 +65197 -0.70391845703125 +65198 -0.557952880859375 +65199 -0.6424560546875 +65200 -0.425628662109375 +65201 -0.491241455078125 +65202 -0.2286376953125 +65203 -0.265716552734375 +65204 -0.0174560546875 +65205 -0.023712158203125 +65206 0.179107666015625 +65207 0.201751708984375 +65208 0.3306884765625 +65209 0.375823974609375 +65210 0.42559814453125 +65211 0.485076904296875 +65212 0.498138427734375 +65213 0.56884765625 +65214 0.55499267578125 +65215 0.634765625 +65216 0.55682373046875 +65217 0.63763427734375 +65218 0.49371337890625 +65219 0.5660400390625 +65220 0.41107177734375 +65221 0.4720458984375 +65222 0.3536376953125 +65223 0.40692138671875 +65224 0.327667236328125 +65225 0.3778076171875 +65226 0.326446533203125 +65227 0.376953125 +65228 0.32177734375 +65229 0.371978759765625 +65230 0.27032470703125 +65231 0.313140869140625 +65232 0.158111572265625 +65233 0.184417724609375 +65234 0.00726318359375 +65235 0.011199951171875 +65236 -0.151336669921875 +65237 -0.171051025390625 +65238 -0.29595947265625 +65239 -0.33740234375 +65240 -0.41278076171875 +65241 -0.47198486328125 +65242 -0.489288330078125 +65243 -0.560394287109375 +65244 -0.50628662109375 +65245 -0.58056640625 +65246 -0.476898193359375 +65247 -0.54754638671875 +65248 -0.4423828125 +65249 -0.508575439453125 +65250 -0.399139404296875 +65251 -0.459503173828125 +65252 -0.342010498046875 +65253 -0.394378662109375 +65254 -0.30535888671875 +65255 -0.35260009765625 +65256 -0.26959228515625 +65257 -0.31170654296875 +65258 -0.169952392578125 +65259 -0.197418212890625 +65260 -0.0048828125 +65261 -0.007965087890625 +65262 0.1827392578125 +65263 0.207489013671875 +65264 0.3582763671875 +65265 0.409210205078125 +65266 0.499847412109375 +65267 0.57208251953125 +65268 0.581207275390625 +65269 0.66595458984375 +65270 0.57440185546875 +65271 0.65875244140625 +65272 0.4942626953125 +65273 0.56744384765625 +65274 0.375152587890625 +65275 0.431396484375 +65276 0.255340576171875 +65277 0.29443359375 +65278 0.15740966796875 +65279 0.182464599609375 +65280 0.05413818359375 +65281 0.06365966796875 +65282 -0.066650390625 +65283 -0.075958251953125 +65284 -0.16534423828125 +65285 -0.189422607421875 +65286 -0.237640380859375 +65287 -0.271942138671875 +65288 -0.29931640625 +65289 -0.342529296875 +65290 -0.31915283203125 +65291 -0.364166259765625 +65292 -0.28900146484375 +65293 -0.327239990234375 +65294 -0.246826171875 +65295 -0.2769775390625 +65296 -0.22650146484375 +65297 -0.253692626953125 +65298 -0.216522216796875 +65299 -0.24365234375 +65300 -0.176300048828125 +65301 -0.1983642578125 +65302 -0.104644775390625 +65303 -0.116241455078125 +65304 -0.034912109375 +65305 -0.036834716796875 +65306 0.02850341796875 +65307 0.034881591796875 +65308 0.0789794921875 +65309 0.09124755859375 +65310 0.09674072265625 +65311 0.10888671875 +65312 0.11328125 +65313 0.125518798828125 +65314 0.14239501953125 +65315 0.15771484375 +65316 0.1611328125 +65317 0.17828369140625 +65318 0.155853271484375 +65319 0.17108154296875 +65320 0.121429443359375 +65321 0.129974365234375 +65322 0.0809326171875 +65323 0.082427978515625 +65324 0.033782958984375 +65325 0.027679443359375 +65326 -0.046295166015625 +65327 -0.065643310546875 +65328 -0.12713623046875 +65329 -0.15936279296875 +65330 -0.174652099609375 +65331 -0.21307373046875 +65332 -0.195343017578125 +65333 -0.234649658203125 +65334 -0.168975830078125 +65335 -0.2001953125 +65336 -0.103363037109375 +65337 -0.119171142578125 +65338 -0.0262451171875 +65339 -0.024749755859375 +65340 0.06475830078125 +65341 0.085784912109375 +65342 0.14093017578125 +65343 0.178131103515625 +65344 0.1715087890625 +65345 0.215576171875 +65346 0.167694091796875 +65347 0.211456298828125 +65348 0.137451171875 +65349 0.17523193359375 +65350 0.099090576171875 +65351 0.128753662109375 +65352 0.077728271484375 +65353 0.1019287109375 +65354 0.05615234375 +65355 0.0743408203125 +65356 0.031951904296875 +65357 0.04327392578125 +65358 0.029754638671875 +65359 0.038177490234375 +65360 0.063873291015625 +65361 0.076263427734375 +65362 0.120361328125 +65363 0.14105224609375 +65364 0.160400390625 +65365 0.186431884765625 +65366 0.1640625 +65367 0.188812255859375 +65368 0.123565673828125 +65369 0.1390380859375 +65370 0.04278564453125 +65371 0.041778564453125 +65372 -0.058563232421875 +65373 -0.079437255859375 +65374 -0.176116943359375 +65375 -0.219390869140625 +65376 -0.30120849609375 +65377 -0.367828369140625 +65378 -0.40875244140625 +65379 -0.494873046875 +65380 -0.461456298828125 +65381 -0.556243896484375 +65382 -0.422943115234375 +65383 -0.508697509765625 +65384 -0.312774658203125 +65385 -0.3756103515625 +65386 -0.182891845703125 +65387 -0.218902587890625 +65388 -0.0543212890625 +65389 -0.063751220703125 +65390 0.074432373046875 +65391 0.091552734375 +65392 0.19427490234375 +65393 0.23602294921875 +65394 0.282867431640625 +65395 0.342987060546875 +65396 0.3258056640625 +65397 0.39520263671875 +65398 0.320343017578125 +65399 0.389373779296875 +65400 0.26544189453125 +65401 0.324249267578125 +65402 0.181488037109375 +65403 0.224090576171875 +65404 0.098175048828125 +65405 0.124267578125 +65406 0.025787353515625 +65407 0.037078857421875 +65408 -0.012725830078125 +65409 -0.010101318359375 +65410 -0.019256591796875 +65411 -0.019439697265625 +65412 -0.0206298828125 +65413 -0.022796630859375 +65414 -0.00128173828125 +65415 -0.001556396484375 +65416 0.048797607421875 +65417 0.056304931640625 +65418 0.092498779296875 +65419 0.106719970703125 +65420 0.085418701171875 +65421 0.096893310546875 +65422 0.04083251953125 +65423 0.042694091796875 +65424 -0.009521484375 +65425 -0.018035888671875 +65426 -0.057769775390625 +65427 -0.07586669921875 +65428 -0.0943603515625 +65429 -0.11944580078125 +65430 -0.128509521484375 +65431 -0.15972900390625 +65432 -0.165130615234375 +65433 -0.202606201171875 +65434 -0.204620361328125 +65435 -0.24859619140625 +65436 -0.253173828125 +65437 -0.30517578125 +65438 -0.30218505859375 +65439 -0.36212158203125 +65440 -0.32806396484375 +65441 -0.39141845703125 +65442 -0.298980712890625 +65443 -0.35528564453125 +65444 -0.211700439453125 +65445 -0.249969482421875 +65446 -0.080810546875 +65447 -0.092864990234375 +65448 0.07110595703125 +65449 0.08905029296875 +65450 0.1932373046875 +65451 0.2352294921875 +65452 0.2630615234375 +65453 0.318817138671875 +65454 0.29638671875 +65455 0.358642578125 +65456 0.287384033203125 +65457 0.347747802734375 +65458 0.235626220703125 +65459 0.28564453125 +65460 0.18377685546875 +65461 0.223175048828125 +65462 0.162353515625 +65463 0.196746826171875 +65464 0.149078369140625 +65465 0.179840087890625 +65466 0.129669189453125 +65467 0.155548095703125 +65468 0.1270751953125 +65469 0.151214599609375 +65470 0.132904052734375 +65471 0.156951904296875 +65472 0.1126708984375 +65473 0.13177490234375 +65474 0.087432861328125 +65475 0.100799560546875 +65476 0.076507568359375 +65477 0.087127685546875 +65478 0.049774169921875 +65479 0.05487060546875 +65480 -0.003692626953125 +65481 -0.009002685546875 +65482 -0.08349609375 +65483 -0.10400390625 +65484 -0.189056396484375 +65485 -0.229400634765625 +65486 -0.29541015625 +65487 -0.35552978515625 +65488 -0.368499755859375 +65489 -0.441925048828125 +65490 -0.39599609375 +65491 -0.473846435546875 +65492 -0.38916015625 +65493 -0.464813232421875 +65494 -0.351531982421875 +65495 -0.419097900390625 +65496 -0.281097412109375 +65497 -0.334320068359375 +65498 -0.192474365234375 +65499 -0.227935791015625 +65500 -0.105377197265625 +65501 -0.12347412109375 +65502 -0.025421142578125 +65503 -0.02764892578125 +65504 0.062652587890625 +65505 0.077667236328125 +65506 0.17633056640625 +65507 0.2132568359375 +65508 0.323760986328125 +65509 0.38885498046875 +65510 0.48675537109375 +65511 0.582794189453125 +65512 0.614044189453125 +65513 0.734039306640625 +65514 0.669952392578125 +65515 0.800140380859375 +65516 0.652099609375 +65517 0.7783203125 +65518 0.557586669921875 +65519 0.6651611328125 +65520 0.385528564453125 +65521 0.45965576171875 +65522 0.167327880859375 +65523 0.199188232421875 +65524 -0.0419921875 +65525 -0.050689697265625 +65526 -0.194549560546875 +65527 -0.23297119140625 +65528 -0.27569580078125 +65529 -0.33013916015625 +65530 -0.307464599609375 +65531 -0.368408203125 +65532 -0.3160400390625 +65533 -0.378936767578125 +65534 -0.31427001953125 +65535 -0.376983642578125 +65536 -0.316497802734375 +65537 -0.37969970703125 +65538 -0.326416015625 +65539 -0.391510009765625 +65540 -0.321868896484375 +65541 -0.385345458984375 +65542 -0.28704833984375 +65543 -0.3419189453125 +65544 -0.239288330078125 +65545 -0.28289794921875 +65546 -0.213470458984375 +65547 -0.251617431640625 +65548 -0.22412109375 +65549 -0.266143798828125 +65550 -0.228363037109375 +65551 -0.273345947265625 +65552 -0.1806640625 +65553 -0.216796875 +65554 -0.10675048828125 +65555 -0.128265380859375 +65556 -0.05560302734375 +65557 -0.068145751953125 +65558 -0.032745361328125 +65559 -0.0430908203125 +65560 -0.015167236328125 +65561 -0.024444580078125 +65562 0.023590087890625 +65563 0.020721435546875 +65564 0.10931396484375 +65565 0.124481201171875 +65566 0.218475341796875 +65567 0.25787353515625 +65568 0.3172607421875 +65569 0.379119873046875 +65570 0.398956298828125 +65571 0.47991943359375 +65572 0.437591552734375 +65573 0.5281982421875 +65574 0.4228515625 +65575 0.511138916015625 +65576 0.37701416015625 +65577 0.456207275390625 +65578 0.33575439453125 +65579 0.407470703125 +65580 0.31439208984375 +65581 0.383758544921875 +65582 0.290313720703125 +65583 0.35687255859375 +65584 0.25152587890625 +65585 0.31182861328125 +65586 0.199951171875 +65587 0.250885009765625 +65588 0.128753662109375 +65589 0.1654052734375 +65590 0.02178955078125 +65591 0.035247802734375 +65592 -0.12286376953125 +65593 -0.142059326171875 +65594 -0.2801513671875 +65595 -0.33563232421875 +65596 -0.441192626953125 +65597 -0.5345458984375 +65598 -0.59234619140625 +65599 -0.72186279296875 +65600 -0.684417724609375 +65601 -0.836669921875 +65602 -0.680023193359375 +65603 -0.8326416015625 +65604 -0.595306396484375 +65605 -0.7296142578125 +65606 -0.4747314453125 +65607 -0.582550048828125 +65608 -0.357696533203125 +65609 -0.440093994140625 +65610 -0.26214599609375 +65611 -0.324310302734375 +65612 -0.16094970703125 +65613 -0.20147705078125 +65614 -0.03240966796875 +65615 -0.044647216796875 +65616 0.089263916015625 +65617 0.103973388671875 +65618 0.1700439453125 +65619 0.202392578125 +65620 0.2210693359375 +65621 0.264495849609375 +65622 0.2816162109375 +65623 0.338897705078125 +65624 0.366363525390625 +65625 0.443817138671875 +65626 0.44775390625 +65627 0.545074462890625 +65628 0.50531005859375 +65629 0.6173095703125 +65630 0.532562255859375 +65631 0.6524658203125 +65632 0.53997802734375 +65633 0.66339111328125 +65634 0.53253173828125 +65635 0.6561279296875 +65636 0.490997314453125 +65637 0.606781005859375 +65638 0.40399169921875 +65639 0.501190185546875 +65640 0.282470703125 +65641 0.352783203125 +65642 0.138641357421875 +65643 0.176544189453125 +65644 -0.033294677734375 +65645 -0.034820556640625 +65646 -0.214599609375 +65647 -0.258209228515625 +65648 -0.363922119140625 +65649 -0.44244384765625 +65650 -0.471343994140625 +65651 -0.5753173828125 +65652 -0.53302001953125 +65653 -0.65203857421875 +65654 -0.52398681640625 +65655 -0.641632080078125 +65656 -0.4588623046875 +65657 -0.562164306640625 +65658 -0.37359619140625 +65659 -0.458038330078125 +65660 -0.285430908203125 +65661 -0.350555419921875 +65662 -0.211273193359375 +65663 -0.260528564453125 +65664 -0.154571533203125 +65665 -0.192108154296875 +65666 -0.112701416015625 +65667 -0.141937255859375 +65668 -0.07940673828125 +65669 -0.1021728515625 +65670 -0.04669189453125 +65671 -0.062896728515625 +65672 -0.004791259765625 +65673 -0.011932373046875 +65674 0.056060791015625 +65675 0.062835693359375 +65676 0.1256103515625 +65677 0.148712158203125 +65678 0.20062255859375 +65679 0.241729736328125 +65680 0.286956787109375 +65681 0.34912109375 +65682 0.373687744140625 +65683 0.457305908203125 +65684 0.4427490234375 +65685 0.54388427734375 +65686 0.46514892578125 +65687 0.5728759765625 +65688 0.41046142578125 +65689 0.506591796875 +65690 0.283782958984375 +65691 0.351226806640625 +65692 0.117279052734375 +65693 0.146514892578125 +65694 -0.0467529296875 +65695 -0.05523681640625 +65696 -0.177703857421875 +65697 -0.21624755859375 +65698 -0.27423095703125 +65699 -0.334930419921875 +65700 -0.329620361328125 +65701 -0.402984619140625 +65702 -0.3607177734375 +65703 -0.4412841796875 +65704 -0.404693603515625 +65705 -0.49578857421875 +65706 -0.4564208984375 +65707 -0.5601806640625 +65708 -0.488677978515625 +65709 -0.600738525390625 +65710 -0.474639892578125 +65711 -0.584228515625 +65712 -0.3890380859375 +65713 -0.47930908203125 +65714 -0.2265625 +65715 -0.27935791015625 +65716 -0.007110595703125 +65717 -0.0089111328125 +65718 0.218170166015625 +65719 0.268798828125 +65720 0.39190673828125 +65721 0.482818603515625 +65722 0.49029541015625 +65723 0.60369873046875 +65724 0.528564453125 +65725 0.650421142578125 +65726 0.539886474609375 +65727 0.66400146484375 +65728 0.5218505859375 +65729 0.6414794921875 +65730 0.466094970703125 +65731 0.572540283203125 +65732 0.405731201171875 +65733 0.498138427734375 +65734 0.357879638671875 +65735 0.439453125 +65736 0.3056640625 +65737 0.375518798828125 +65738 0.223358154296875 +65739 0.274505615234375 +65740 0.088714599609375 +65741 0.1087646484375 +65742 -0.080230712890625 +65743 -0.099395751953125 +65744 -0.257781982421875 +65745 -0.3182373046875 +65746 -0.444854736328125 +65747 -0.5489501953125 +65748 -0.627105712890625 +65749 -0.7738037109375 +65750 -0.76171875 +65751 -0.86383056640625 +65752 -0.82177734375 +65753 -0.870391845703125 +65754 -0.82159423828125 +65755 -0.86895751953125 +65756 -0.771759033203125 +65757 -0.861053466796875 +65758 -0.6583251953125 +65759 -0.765869140625 +65760 -0.47216796875 +65761 -0.5301513671875 +65762 -0.219085693359375 +65763 -0.214691162109375 +65764 0.066070556640625 +65765 0.137359619140625 +65766 0.341827392578125 +65767 0.474822998046875 +65768 0.5794677734375 +65769 0.76239013671875 +65770 0.75714111328125 +65771 0.867462158203125 +65772 0.856719970703125 +65773 0.870361328125 +65774 0.862091064453125 +65775 0.86480712890625 +65776 0.8603515625 +65777 0.831817626953125 +65778 0.84765625 +65779 0.677581787109375 +65780 0.7464599609375 +65781 0.495880126953125 +65782 0.619842529296875 +65783 0.30767822265625 +65784 0.4696044921875 +65785 0.116180419921875 +65786 0.2701416015625 +65787 -0.110748291015625 +65788 0.015869140625 +65789 -0.381805419921875 +65790 -0.25860595703125 +65791 -0.6572265625 +65792 -0.504974365234375 +65793 -0.857421875 +65794 -0.68865966796875 +65795 -0.870391845703125 +65796 -0.803680419921875 +65797 -0.870391845703125 +65798 -0.856292724609375 +65799 -0.86444091796875 +65800 -0.8614501953125 +65801 -0.85723876953125 +65802 -0.8629150390625 +65803 -0.790008544921875 +65804 -0.8560791015625 +65805 -0.62847900390625 +65806 -0.72833251953125 +65807 -0.3956298828125 +65808 -0.53570556640625 +65809 -0.126708984375 +65810 -0.31268310546875 +65811 0.150115966796875 +65812 -0.06878662109375 +65813 0.424041748046875 +65814 0.174591064453125 +65815 0.670623779296875 +65816 0.386962890625 +65817 0.854522705078125 +65818 0.55419921875 +65819 0.866485595703125 +65820 0.664031982421875 +65821 0.86920166015625 +65822 0.73028564453125 +65823 0.8653564453125 +65824 0.763153076171875 +65825 0.857147216796875 +65826 0.76031494140625 +65827 0.766845703125 +65828 0.72576904296875 +65829 0.628509521484375 +65830 0.65435791015625 +65831 0.462127685546875 +65832 0.566314697265625 +65833 0.297210693359375 +65834 0.47149658203125 +65835 0.14862060546875 +65836 0.352447509765625 +65837 -0.00537109375 +65838 0.215362548828125 +65839 -0.15753173828125 +65840 0.057769775390625 +65841 -0.31304931640625 +65842 -0.13079833984375 +65843 -0.48876953125 +65844 -0.313629150390625 +65845 -0.6416015625 +65846 -0.471221923828125 +65847 -0.751373291015625 +65848 -0.621246337890625 +65849 -0.84619140625 +65850 -0.752044677734375 +65851 -0.861297607421875 +65852 -0.837799072265625 +65853 -0.863250732421875 +65854 -0.853973388671875 +65855 -0.856597900390625 +65856 -0.810028076171875 +65857 -0.7498779296875 +65858 -0.750946044921875 +65859 -0.624542236328125 +65860 -0.65985107421875 +65861 -0.47808837890625 +65862 -0.49163818359375 +65863 -0.253387451171875 +65864 -0.282012939453125 +65865 0.003692626953125 +65866 -0.0843505859375 +65867 0.2257080078125 +65868 0.110748291015625 +65869 0.427154541015625 +65870 0.328094482421875 +65871 0.643218994140625 +65872 0.5599365234375 +65873 0.855926513671875 +65874 0.761016845703125 +65875 0.870361328125 +65876 0.858642578125 +65877 0.870361328125 +65878 0.865997314453125 +65879 0.862762451171875 +65880 0.866119384765625 +65881 0.79669189453125 +65882 0.85821533203125 +65883 0.595794677734375 +65884 0.764984130859375 +65885 0.362152099609375 +65886 0.612213134765625 +65887 0.1270751953125 +65888 0.446929931640625 +65889 -0.086944580078125 +65890 0.271026611328125 +65891 -0.2784423828125 +65892 0.057769775390625 +65893 -0.484832763671875 +65894 -0.2073974609375 +65895 -0.729583740234375 +65896 -0.484893798828125 +65897 -0.86688232421875 +65898 -0.725250244140625 +65899 -0.870391845703125 +65900 -0.86212158203125 +65901 -0.86859130859375 +65902 -0.870391845703125 +65903 -0.86279296875 +65904 -0.870391845703125 +65905 -0.817962646484375 +65906 -0.8599853515625 +65907 -0.6116943359375 +65908 -0.712371826171875 +65909 -0.3128662109375 +65910 -0.4517822265625 +65911 0.039398193359375 +65912 -0.140289306640625 +65913 0.422821044921875 +65914 0.195465087890625 +65915 0.805145263671875 +65916 0.502899169921875 +65917 0.870361328125 +65918 0.739044189453125 +65919 0.870361328125 +65920 0.859100341796875 +65921 0.860015869140625 +65922 0.867462158203125 +65923 0.727935791015625 +65924 0.8668212890625 +65925 0.48114013671875 +65926 0.85968017578125 +65927 0.2059326171875 +65928 0.798187255859375 +65929 -0.06103515625 +65930 0.667572021484375 +65931 -0.29913330078125 +65932 0.50262451171875 +65933 -0.516204833984375 +65934 0.294586181640625 +65935 -0.7252197265625 +65936 0.065399169921875 +65937 -0.85980224609375 +65938 -0.156341552734375 +65939 -0.870391845703125 +65940 -0.346527099609375 +65941 -0.870391845703125 +65942 -0.467071533203125 +65943 -0.858062744140625 +65944 -0.51513671875 +65945 -0.673004150390625 +65946 -0.53265380859375 +65947 -0.42694091796875 +65948 -0.555877685546875 +65949 -0.2100830078125 +65950 -0.5855712890625 +65951 -0.0362548828125 +65952 -0.601959228515625 +65953 0.10943603515625 +65954 -0.5926513671875 +65955 0.23516845703125 +65956 -0.52862548828125 +65957 0.373687744140625 +65958 -0.41436767578125 +65959 0.517791748046875 +65960 -0.301544189453125 +65961 0.602783203125 +65962 -0.1884765625 +65963 0.635711669921875 +65964 -0.051177978515625 +65965 0.655181884765625 +65966 0.101348876953125 +65967 0.65948486328125 +65968 0.262237548828125 +65969 0.651275634765625 +65970 0.4124755859375 +65971 0.61846923828125 +65972 0.52398681640625 +65973 0.53753662109375 +65974 0.583953857421875 +65975 0.404144287109375 +65976 0.5865478515625 +65977 0.22186279296875 +65978 0.534820556640625 +65979 0.003997802734375 +65980 0.445159912109375 +65981 -0.22100830078125 +65982 0.336090087890625 +65983 -0.42449951171875 +65984 0.226715087890625 +65985 -0.579833984375 +65986 0.152496337890625 +65987 -0.641876220703125 +65988 0.110382080078125 +65989 -0.6177978515625 +65990 0.051971435546875 +65991 -0.575531005859375 +65992 -0.025604248046875 +65993 -0.526336669921875 +65994 -0.081390380859375 +65995 -0.42645263671875 +65996 -0.0938720703125 +65997 -0.2581787109375 +65998 -0.091552734375 +65999 -0.068695068359375 +66000 -0.1051025390625 +66001 0.09222412109375 +66002 -0.121307373046875 +66003 0.232147216796875 +66004 -0.13385009765625 +66005 0.3509521484375 +66006 -0.16754150390625 +66007 0.410064697265625 +66008 -0.2470703125 +66009 0.372955322265625 +66010 -0.358184814453125 +66011 0.2554931640625 +66012 -0.462371826171875 +66013 0.10711669921875 +66014 -0.546173095703125 +66015 -0.052886962890625 +66016 -0.58294677734375 +66017 -0.186279296875 +66018 -0.5303955078125 +66019 -0.23291015625 +66020 -0.40692138671875 +66021 -0.209442138671875 +66022 -0.26397705078125 +66023 -0.174163818359375 +66024 -0.10791015625 +66025 -0.126739501953125 +66026 0.069427490234375 +66027 -0.048126220703125 +66028 0.246978759765625 +66029 0.0426025390625 +66030 0.389739990234375 +66031 0.10748291015625 +66032 0.488800048828125 +66033 0.1409912109375 +66034 0.58258056640625 +66035 0.19708251953125 +66036 0.667388916015625 +66037 0.273651123046875 +66038 0.701416015625 +66039 0.31768798828125 +66040 0.694671630859375 +66041 0.341094970703125 +66042 0.667938232421875 +66043 0.368011474609375 +66044 0.60430908203125 +66045 0.37249755859375 +66046 0.46624755859375 +66047 0.30072021484375 +66048 0.25775146484375 +66049 0.1517333984375 +66050 0.0303955078125 +66051 -0.01470947265625 +66052 -0.201507568359375 +66053 -0.1883544921875 +66054 -0.43499755859375 +66055 -0.372711181640625 +66056 -0.62469482421875 +66057 -0.51397705078125 +66058 -0.73602294921875 +66059 -0.57177734375 +66060 -0.76080322265625 +66061 -0.53948974609375 +66062 -0.710479736328125 +66063 -0.43511962890625 +66064 -0.61236572265625 +66065 -0.2962646484375 +66066 -0.49542236328125 +66067 -0.161102294921875 +66068 -0.371612548828125 +66069 -0.0435791015625 +66070 -0.24041748046875 +66071 0.060394287109375 +66072 -0.115875244140625 +66073 0.13665771484375 +66074 -0.013397216796875 +66075 0.170135498046875 +66076 0.066009521484375 +66077 0.16552734375 +66078 0.143463134765625 +66079 0.15728759765625 +66080 0.218414306640625 +66081 0.150787353515625 +66082 0.26861572265625 +66083 0.12200927734375 +66084 0.2972412109375 +66085 0.080108642578125 +66086 0.321014404296875 +66087 0.05126953125 +66088 0.358428955078125 +66089 0.062896728515625 +66090 0.391693115234375 +66091 0.09271240234375 +66092 0.38494873046875 +66093 0.092987060546875 +66094 0.350189208984375 +66095 0.07855224609375 +66096 0.30035400390625 +66097 0.06427001953125 +66098 0.226470947265625 +66099 0.0347900390625 +66100 0.13031005859375 +66101 -0.01171875 +66102 0.029937744140625 +66103 -0.056060791015625 +66104 -0.03875732421875 +66105 -0.055511474609375 +66106 -0.072235107421875 +66107 -0.010467529296875 +66108 -0.107330322265625 +66109 0.02508544921875 +66110 -0.159942626953125 +66111 0.025665283203125 +66112 -0.207916259765625 +66113 0.017333984375 +66114 -0.247955322265625 +66115 0.00189208984375 +66116 -0.287200927734375 +66117 -0.03173828125 +66118 -0.3162841796875 +66119 -0.071502685546875 +66120 -0.34918212890625 +66121 -0.13543701171875 +66122 -0.38446044921875 +66123 -0.219970703125 +66124 -0.40557861328125 +66125 -0.300506591796875 +66126 -0.414459228515625 +66127 -0.376312255859375 +66128 -0.3905029296875 +66129 -0.416107177734375 +66130 -0.300201416015625 +66131 -0.371124267578125 +66132 -0.147430419921875 +66133 -0.242279052734375 +66134 0.03460693359375 +66135 -0.069732666015625 +66136 0.227508544921875 +66137 0.125640869140625 +66138 0.405548095703125 +66139 0.31268310546875 +66140 0.539642333984375 +66141 0.45501708984375 +66142 0.630218505859375 +66143 0.554779052734375 +66144 0.67578125 +66145 0.61065673828125 +66146 0.66766357421875 +66147 0.610931396484375 +66148 0.588592529296875 +66149 0.531463623046875 +66150 0.451934814453125 +66151 0.3883056640625 +66152 0.29949951171875 +66153 0.23468017578125 +66154 0.152069091796875 +66155 0.095245361328125 +66156 0.031646728515625 +66157 -0.00396728515625 +66158 -0.048370361328125 +66159 -0.04852294921875 +66160 -0.097930908203125 +66161 -0.055145263671875 +66162 -0.153656005859375 +66163 -0.0758056640625 +66164 -0.234619140625 +66165 -0.138702392578125 +66166 -0.31317138671875 +66167 -0.209197998046875 +66168 -0.38946533203125 +66169 -0.289031982421875 +66170 -0.46337890625 +66171 -0.37884521484375 +66172 -0.518035888671875 +66173 -0.456329345703125 +66174 -0.5501708984375 +66175 -0.51641845703125 +66176 -0.530914306640625 +66177 -0.519287109375 +66178 -0.45660400390625 +66179 -0.458251953125 +66180 -0.367645263671875 +66181 -0.384796142578125 +66182 -0.28460693359375 +66183 -0.323699951171875 +66184 -0.205352783203125 +66185 -0.269287109375 +66186 -0.112274169921875 +66187 -0.1951904296875 +66188 -0.00628662109375 +66189 -0.100006103515625 +66190 0.09063720703125 +66191 -0.01055908203125 +66192 0.199676513671875 +66193 0.1033935546875 +66194 0.3251953125 +66195 0.24908447265625 +66196 0.426513671875 +66197 0.373199462890625 +66198 0.49017333984375 +66199 0.45806884765625 +66200 0.522247314453125 +66201 0.511474609375 +66202 0.547393798828125 +66203 0.565399169921875 +66204 0.560302734375 +66205 0.61138916015625 +66206 0.517547607421875 +66207 0.5897216796875 +66208 0.413360595703125 +66209 0.4906005859375 +66210 0.262603759765625 +66211 0.33148193359375 +66212 0.09356689453125 +66213 0.147796630859375 +66214 -0.060791015625 +66215 -0.01873779296875 +66216 -0.178009033203125 +66217 -0.140289306640625 +66218 -0.23809814453125 +66219 -0.191986083984375 +66220 -0.247894287109375 +66221 -0.184295654296875 +66222 -0.24017333984375 +66223 -0.161834716796875 +66224 -0.24609375 +66225 -0.166595458984375 +66226 -0.262237548828125 +66227 -0.19390869140625 +66228 -0.2745361328125 +66229 -0.22442626953125 +66230 -0.2999267578125 +66231 -0.279754638671875 +66232 -0.32379150390625 +66233 -0.3389892578125 +66234 -0.31158447265625 +66235 -0.3543701171875 +66236 -0.2813720703125 +66237 -0.348175048828125 +66238 -0.23876953125 +66239 -0.32598876953125 +66240 -0.16302490234375 +66241 -0.2581787109375 +66242 -0.051727294921875 +66243 -0.139801025390625 +66244 0.08306884765625 +66245 0.014617919921875 +66246 0.194854736328125 +66247 0.144378662109375 +66248 0.261688232421875 +66249 0.221038818359375 +66250 0.302764892578125 +66251 0.27069091796875 +66252 0.318572998046875 +66253 0.294036865234375 +66254 0.32489013671875 +66255 0.311767578125 +66256 0.33367919921875 +66257 0.339141845703125 +66258 0.333709716796875 +66259 0.360260009765625 +66260 0.31500244140625 +66261 0.360504150390625 +66262 0.2552490234375 +66263 0.308380126953125 +66264 0.139190673828125 +66265 0.18170166015625 +66266 -0.0137939453125 +66267 0.0047607421875 +66268 -0.167755126953125 +66269 -0.17559814453125 +66270 -0.28814697265625 +66271 -0.3143310546875 +66272 -0.3416748046875 +66273 -0.36785888671875 +66274 -0.347259521484375 +66275 -0.36248779296875 +66276 -0.338226318359375 +66277 -0.343536376953125 +66278 -0.3076171875 +66279 -0.3018798828125 +66280 -0.25103759765625 +66281 -0.231414794921875 +66282 -0.15802001953125 +66283 -0.117645263671875 +66284 -0.053253173828125 +66285 0.007049560546875 +66286 0.02178955078125 +66287 0.087982177734375 +66288 0.076873779296875 +66289 0.13946533203125 +66290 0.12054443359375 +66291 0.17425537109375 +66292 0.148681640625 +66293 0.188201904296875 +66294 0.15283203125 +66295 0.171234130859375 +66296 0.128448486328125 +66297 0.118438720703125 +66298 0.095062255859375 +66299 0.05706787109375 +66300 0.05364990234375 +66301 -0.010711669921875 +66302 -0.001007080078125 +66303 -0.0914306640625 +66304 -0.051727294921875 +66305 -0.162322998046875 +66306 -0.07720947265625 +66307 -0.194549560546875 +66308 -0.0499267578125 +66309 -0.1492919921875 +66310 0.033599853515625 +66311 -0.02166748046875 +66312 0.127838134765625 +66313 0.124053955078125 +66314 0.178558349609375 +66315 0.211151123046875 +66316 0.186920166015625 +66317 0.240447998046875 +66318 0.175048828125 +66319 0.242218017578125 +66320 0.1502685546875 +66321 0.2257080078125 +66322 0.11572265625 +66323 0.194366455078125 +66324 0.048736572265625 +66325 0.115509033203125 +66326 -0.033203125 +66327 0.0128173828125 +66328 -0.087005615234375 +66329 -0.053802490234375 +66330 -0.131072998046875 +66331 -0.110626220703125 +66332 -0.195098876953125 +66333 -0.199493408203125 +66334 -0.26055908203125 +66335 -0.29437255859375 +66336 -0.28271484375 +66337 -0.33221435546875 +66338 -0.23822021484375 +66339 -0.27972412109375 +66340 -0.161956787109375 +66341 -0.185333251953125 +66342 -0.110809326171875 +66343 -0.128204345703125 +66344 -0.09063720703125 +66345 -0.115692138671875 +66346 -0.07977294921875 +66347 -0.116455078125 +66348 -0.061370849609375 +66349 -0.105926513671875 +66350 -0.014556884765625 +66351 -0.053955078125 +66352 0.06683349609375 +66353 0.048797607421875 +66354 0.150360107421875 +66355 0.157318115234375 +66356 0.19329833984375 +66357 0.212005615234375 +66358 0.199493408203125 +66359 0.218475341796875 +66360 0.212005615234375 +66361 0.23724365234375 +66362 0.25732421875 +66363 0.30535888671875 +66364 0.306121826171875 +66365 0.38128662109375 +66366 0.315582275390625 +66367 0.404449462890625 +66368 0.300079345703125 +66369 0.3944091796875 +66370 0.2867431640625 +66371 0.3885498046875 +66372 0.25885009765625 +66373 0.362640380859375 +66374 0.186248779296875 +66375 0.27362060546875 +66376 0.06634521484375 +66377 0.11712646484375 +66378 -0.063446044921875 +66379 -0.054901123046875 +66380 -0.165985107421875 +66381 -0.19085693359375 +66382 -0.2374267578125 +66383 -0.28570556640625 +66384 -0.277496337890625 +66385 -0.339263916015625 +66386 -0.3046875 +66387 -0.3775634765625 +66388 -0.3511962890625 +66389 -0.445709228515625 +66390 -0.4110107421875 +66391 -0.535064697265625 +66392 -0.47259521484375 +66393 -0.629058837890625 +66394 -0.51483154296875 +66395 -0.697601318359375 +66396 -0.511962890625 +66397 -0.70391845703125 +66398 -0.46044921875 +66399 -0.6424560546875 +66400 -0.3450927734375 +66401 -0.491241455078125 +66402 -0.177276611328125 +66403 -0.265716552734375 +66404 0.00140380859375 +66405 -0.023712158203125 +66406 0.167144775390625 +66407 0.201751708984375 +66408 0.29486083984375 +66409 0.375823974609375 +66410 0.374847412109375 +66411 0.485076904296875 +66412 0.43499755859375 +66413 0.56884765625 +66414 0.48077392578125 +66415 0.634765625 +66416 0.480133056640625 +66417 0.63763427734375 +66418 0.42510986328125 +66419 0.5660400390625 +66420 0.35302734375 +66421 0.4720458984375 +66422 0.30072021484375 +66423 0.40692138671875 +66424 0.273651123046875 +66425 0.3778076171875 +66426 0.266632080078125 +66427 0.376953125 +66428 0.2569580078125 +66429 0.371978759765625 +66430 0.20953369140625 +66431 0.313140869140625 +66432 0.11322021484375 +66433 0.184417724609375 +66434 -0.01361083984375 +66435 0.011199951171875 +66436 -0.14556884765625 +66437 -0.171051025390625 +66438 -0.264862060546875 +66439 -0.33740234375 +66440 -0.360137939453125 +66441 -0.47198486328125 +66442 -0.421234130859375 +66443 -0.560394287109375 +66444 -0.432586669921875 +66445 -0.58056640625 +66446 -0.40509033203125 +66447 -0.54754638671875 +66448 -0.372650146484375 +66449 -0.508575439453125 +66450 -0.33258056640625 +66451 -0.459503173828125 +66452 -0.28094482421875 +66453 -0.394378662109375 +66454 -0.246063232421875 +66455 -0.35260009765625 +66456 -0.21221923828125 +66457 -0.31170654296875 +66458 -0.12677001953125 +66459 -0.197418212890625 +66460 0.01129150390625 +66461 -0.007965087890625 +66462 0.166839599609375 +66463 0.207489013671875 +66464 0.311492919921875 +66465 0.409210205078125 +66466 0.4273681640625 +66467 0.57208251953125 +66468 0.4930419921875 +66469 0.66595458984375 +66470 0.485748291015625 +66471 0.65875244140625 +66472 0.417724609375 +66473 0.56744384765625 +66474 0.317169189453125 +66475 0.431396484375 +66476 0.215545654296875 +66477 0.29443359375 +66478 0.131500244140625 +66479 0.182464599609375 +66480 0.042633056640625 +66481 0.06365966796875 +66482 -0.060760498046875 +66483 -0.075958251953125 +66484 -0.145050048828125 +66485 -0.189422607421875 +66486 -0.20660400390625 +66487 -0.271942138671875 +66488 -0.25885009765625 +66489 -0.342529296875 +66490 -0.275360107421875 +66491 -0.364166259765625 +66492 -0.249267578125 +66493 -0.327239990234375 +66494 -0.2127685546875 +66495 -0.2769775390625 +66496 -0.19464111328125 +66497 -0.253692626953125 +66498 -0.185211181640625 +66499 -0.24365234375 +66500 -0.150115966796875 +66501 -0.1983642578125 +66502 -0.08837890625 +66503 -0.116241455078125 +66504 -0.028350830078125 +66505 -0.036834716796875 +66506 0.026214599609375 +66507 0.034881591796875 +66508 0.06964111328125 +66509 0.09124755859375 +66510 0.08514404296875 +66511 0.10888671875 +66512 0.099456787109375 +66513 0.125518798828125 +66514 0.124237060546875 +66515 0.15771484375 +66516 0.1400146484375 +66517 0.17828369140625 +66518 0.13525390625 +66519 0.17108154296875 +66520 0.105621337890625 +66521 0.129974365234375 +66522 0.070709228515625 +66523 0.082427978515625 +66524 0.030059814453125 +66525 0.027679443359375 +66526 -0.038543701171875 +66527 -0.065643310546875 +66528 -0.1077880859375 +66529 -0.15936279296875 +66530 -0.148773193359375 +66531 -0.21307373046875 +66532 -0.166961669921875 +66533 -0.234649658203125 +66534 -0.1451416015625 +66535 -0.2001953125 +66536 -0.089935302734375 +66537 -0.119171142578125 +66538 -0.02484130859375 +66539 -0.024749755859375 +66540 0.052154541015625 +66541 0.085784912109375 +66542 0.116729736328125 +66543 0.178131103515625 +66544 0.142791748046875 +66545 0.215576171875 +66546 0.139862060546875 +66547 0.211456298828125 +66548 0.114654541015625 +66549 0.17523193359375 +66550 0.082672119140625 +66551 0.128753662109375 +66552 0.06512451171875 +66553 0.1019287109375 +66554 0.047454833984375 +66555 0.0743408203125 +66556 0.027557373046875 +66557 0.04327392578125 +66558 0.0262451171875 +66559 0.038177490234375 +66560 0.05511474609375 +66561 0.076263427734375 +66562 0.10186767578125 +66563 0.14105224609375 +66564 0.13446044921875 +66565 0.186431884765625 +66566 0.13690185546875 +66567 0.188812255859375 +66568 0.103057861328125 +66569 0.1390380859375 +66570 0.036224365234375 +66571 0.041778564453125 +66572 -0.04742431640625 +66573 -0.079437255859375 +66574 -0.144195556640625 +66575 -0.219390869140625 +66576 -0.2469482421875 +66577 -0.367828369140625 +66578 -0.335235595703125 +66579 -0.494873046875 +66580 -0.37884521484375 +66581 -0.556243896484375 +66582 -0.3482666015625 +66583 -0.508697509765625 +66584 -0.259307861328125 +66585 -0.3756103515625 +66586 -0.15399169921875 +66587 -0.218902587890625 +66588 -0.04937744140625 +66589 -0.063751220703125 +66590 0.055694580078125 +66591 0.091552734375 +66592 0.153778076171875 +66593 0.23602294921875 +66594 0.22674560546875 +66595 0.342987060546875 +66596 0.262847900390625 +66597 0.39520263671875 +66598 0.259796142578125 +66599 0.389373779296875 +66600 0.2166748046875 +66601 0.324249267578125 +66602 0.149932861328125 +66603 0.224090576171875 +66604 0.083526611328125 +66605 0.124267578125 +66606 0.02569580078125 +66607 0.037078857421875 +66608 -0.004974365234375 +66609 -0.010101318359375 +66610 -0.01007080078125 +66611 -0.019439697265625 +66612 -0.01129150390625 +66613 -0.022796630859375 +66614 0.003936767578125 +66615 -0.001556396484375 +66616 0.04376220703125 +66617 0.056304931640625 +66618 0.07818603515625 +66619 0.106719970703125 +66620 0.071319580078125 +66621 0.096893310546875 +66622 0.03399658203125 +66623 0.042694091796875 +66624 -0.008026123046875 +66625 -0.018035888671875 +66626 -0.04827880859375 +66627 -0.07586669921875 +66628 -0.078948974609375 +66629 -0.11944580078125 +66630 -0.10748291015625 +66631 -0.15972900390625 +66632 -0.137786865234375 +66633 -0.202606201171875 +66634 -0.170135498046875 +66635 -0.24859619140625 +66636 -0.209564208984375 +66637 -0.30517578125 +66638 -0.249114990234375 +66639 -0.36212158203125 +66640 -0.269683837890625 +66641 -0.39141845703125 +66642 -0.24554443359375 +66643 -0.35528564453125 +66644 -0.17413330078125 +66645 -0.249969482421875 +66646 -0.0672607421875 +66647 -0.092864990234375 +66648 0.05670166015625 +66649 0.08905029296875 +66650 0.156585693359375 +66651 0.2352294921875 +66652 0.214080810546875 +66653 0.318817138671875 +66654 0.241943359375 +66655 0.358642578125 +66656 0.23541259765625 +66657 0.347747802734375 +66658 0.194091796875 +66659 0.28564453125 +66660 0.152496337890625 +66661 0.223175048828125 +66662 0.135345458984375 +66663 0.196746826171875 +66664 0.12457275390625 +66665 0.179840087890625 +66666 0.108642578125 +66667 0.155548095703125 +66668 0.106109619140625 +66669 0.151214599609375 +66670 0.1102294921875 +66671 0.156951904296875 +66672 0.0931396484375 +66673 0.13177490234375 +66674 0.0718994140625 +66675 0.100799560546875 +66676 0.062225341796875 +66677 0.087127685546875 +66678 0.039764404296875 +66679 0.05487060546875 +66680 -0.004302978515625 +66681 -0.009002685546875 +66682 -0.069610595703125 +66683 -0.10400390625 +66684 -0.155609130859375 +66685 -0.229400634765625 +66686 -0.242095947265625 +66687 -0.35552978515625 +66688 -0.301513671875 +66689 -0.441925048828125 +66690 -0.323822021484375 +66691 -0.473846435546875 +66692 -0.318145751953125 +66693 -0.464813232421875 +66694 -0.287353515625 +66695 -0.419097900390625 +66696 -0.2298583984375 +66697 -0.334320068359375 +66698 -0.157501220703125 +66699 -0.227935791015625 +66700 -0.0863037109375 +66701 -0.12347412109375 +66702 -0.0208740234375 +66703 -0.02764892578125 +66704 0.051116943359375 +66705 0.077667236328125 +66706 0.143768310546875 +66707 0.2132568359375 +66708 0.263702392578125 +66709 0.38885498046875 +66710 0.396148681640625 +66711 0.582794189453125 +66712 0.499542236328125 +66713 0.734039306640625 +66714 0.545013427734375 +66715 0.800140380859375 +66716 0.5306396484375 +66717 0.7783203125 +66718 0.454071044921875 +66719 0.6651611328125 +66720 0.314605712890625 +66721 0.45965576171875 +66722 0.13763427734375 +66723 0.199188232421875 +66724 -0.032257080078125 +66725 -0.050689697265625 +66726 -0.156280517578125 +66727 -0.23297119140625 +66728 -0.2225341796875 +66729 -0.33013916015625 +66730 -0.248809814453125 +66731 -0.368408203125 +66732 -0.25628662109375 +66733 -0.378936767578125 +66734 -0.25537109375 +66735 -0.376983642578125 +66736 -0.2576904296875 +66737 -0.37969970703125 +66738 -0.26617431640625 +66739 -0.391510009765625 +66740 -0.262420654296875 +66741 -0.385345458984375 +66742 -0.2332763671875 +66743 -0.3419189453125 +66744 -0.1934814453125 +66745 -0.28289794921875 +66746 -0.172454833984375 +66747 -0.251617431640625 +66748 -0.182464599609375 +66749 -0.266143798828125 +66750 -0.187408447265625 +66751 -0.273345947265625 +66752 -0.148895263671875 +66753 -0.216796875 +66754 -0.0885009765625 +66755 -0.128265380859375 +66756 -0.04736328125 +66757 -0.068145751953125 +66758 -0.029998779296875 +66759 -0.0430908203125 +66760 -0.0169677734375 +66761 -0.024444580078125 +66762 0.014129638671875 +66763 0.020721435546875 +66764 0.085052490234375 +66765 0.124481201171875 +66766 0.176055908203125 +66767 0.25787353515625 +66768 0.25872802734375 +66769 0.379119873046875 +66770 0.32745361328125 +66771 0.47991943359375 +66772 0.36041259765625 +66773 0.5281982421875 +66774 0.348876953125 +66775 0.511138916015625 +66776 0.3115234375 +66777 0.456207275390625 +66778 0.2783203125 +66779 0.407470703125 +66780 0.2620849609375 +66781 0.383758544921875 +66782 0.243621826171875 +66783 0.35687255859375 +66784 0.2127685546875 +66785 0.31182861328125 +66786 0.171051025390625 +66787 0.250885009765625 +66788 0.112640380859375 +66789 0.1654052734375 +66790 0.023834228515625 +66791 0.035247802734375 +66792 -0.097015380859375 +66793 -0.142059326171875 +66794 -0.2288818359375 +66795 -0.33563232421875 +66796 -0.364288330078125 +66797 -0.5345458984375 +66798 -0.491729736328125 +66799 -0.72186279296875 +66800 -0.56982421875 +66801 -0.836669921875 +66802 -0.56707763671875 +66803 -0.8326416015625 +66804 -0.4969482421875 +66805 -0.7296142578125 +66806 -0.396820068359375 +66807 -0.582550048828125 +66808 -0.299774169921875 +66809 -0.440093994140625 +66810 -0.220855712890625 +66811 -0.324310302734375 +66812 -0.137115478515625 +66813 -0.20147705078125 +66814 -0.030242919921875 +66815 -0.044647216796875 +66816 0.071624755859375 +66817 0.103973388671875 +66818 0.14056396484375 +66819 0.202392578125 +66820 0.185333251953125 +66821 0.264495849609375 +66822 0.2371826171875 +66823 0.338897705078125 +66824 0.307708740234375 +66825 0.443817138671875 +66826 0.37469482421875 +66827 0.545074462890625 +66828 0.421630859375 +66829 0.6173095703125 +66830 0.443359375 +66831 0.6524658203125 +66832 0.448272705078125 +66833 0.66339111328125 +66834 0.440460205078125 +66835 0.6561279296875 +66836 0.40460205078125 +66837 0.606781005859375 +66838 0.331756591796875 +66839 0.501190185546875 +66840 0.230865478515625 +66841 0.352783203125 +66842 0.111968994140625 +66843 0.176544189453125 +66844 -0.029388427734375 +66845 -0.034820556640625 +66846 -0.178009033203125 +66847 -0.258209228515625 +66848 -0.300537109375 +66849 -0.44244384765625 +66850 -0.388916015625 +66851 -0.5753173828125 +66852 -0.439971923828125 +66853 -0.65203857421875 +66854 -0.433563232421875 +66855 -0.641632080078125 +66856 -0.381439208984375 +66857 -0.562164306640625 +66858 -0.31243896484375 +66859 -0.458038330078125 +66860 -0.24041748046875 +66861 -0.350555419921875 +66862 -0.17901611328125 +66863 -0.260528564453125 +66864 -0.131134033203125 +66865 -0.192108154296875 +66866 -0.0948486328125 +66867 -0.141937255859375 +66868 -0.06524658203125 +66869 -0.1021728515625 +66870 -0.036102294921875 +66871 -0.062896728515625 +66872 0.000244140625 +66873 -0.011932373046875 +66874 0.051483154296875 +66875 0.062835693359375 +66876 0.1092529296875 +66877 0.148712158203125 +66878 0.170867919921875 +66879 0.241729736328125 +66880 0.240966796875 +66881 0.34912109375 +66882 0.310760498046875 +66883 0.457305908203125 +66884 0.365753173828125 +66885 0.54388427734375 +66886 0.38275146484375 +66887 0.5728759765625 +66888 0.337432861328125 +66889 0.506591796875 +66890 0.233978271484375 +66891 0.351226806640625 +66892 0.098297119140625 +66893 0.146514892578125 +66894 -0.035552978515625 +66895 -0.05523681640625 +66896 -0.142913818359375 +66897 -0.21624755859375 +66898 -0.22259521484375 +66899 -0.334930419921875 +66900 -0.269073486328125 +66901 -0.402984619140625 +66902 -0.29571533203125 +66903 -0.4412841796875 +66904 -0.332244873046875 +66905 -0.49578857421875 +66906 -0.374542236328125 +66907 -0.5601806640625 +66908 -0.400726318359375 +66909 -0.600738525390625 +66910 -0.389312744140625 +66911 -0.584228515625 +66912 -0.320037841796875 +66913 -0.47930908203125 +66914 -0.188690185546875 +66915 -0.27935791015625 +66916 -0.01129150390625 +66917 -0.0089111328125 +66918 0.1710205078125 +66919 0.268798828125 +66920 0.312164306640625 +66921 0.482818603515625 +66922 0.3929443359375 +66923 0.60369873046875 +66924 0.42547607421875 +66925 0.650421142578125 +66926 0.436248779296875 +66927 0.66400146484375 +66928 0.4232177734375 +66929 0.6414794921875 +66930 0.379669189453125 +66931 0.572540283203125 +66932 0.332061767578125 +66933 0.498138427734375 +66934 0.29412841796875 +66935 0.439453125 +66936 0.252288818359375 +66937 0.375518798828125 +66938 0.185943603515625 +66939 0.274505615234375 +66940 0.07720947265625 +66941 0.1087646484375 +66942 -0.059326171875 +66943 -0.099395751953125 +66944 -0.202972412109375 +66945 -0.3182373046875 +66946 -0.35443115234375 +66947 -0.5489501953125 +66948 -0.502105712890625 +66949 -0.7738037109375 +66950 -0.611541748046875 +66951 -0.86383056640625 +66952 -0.6611328125 +66953 -0.870391845703125 +66954 -0.662261962890625 +66955 -0.86895751953125 +66956 -0.623382568359375 +66957 -0.861053466796875 +66958 -0.533203125 +66959 -0.765869140625 +66960 -0.3843994140625 +66961 -0.5301513671875 +66962 -0.181610107421875 +66963 -0.214691162109375 +66964 0.047271728515625 +66965 0.137359619140625 +66966 0.2689208984375 +66967 0.474822998046875 +66968 0.46026611328125 +66969 0.76239013671875 +66970 0.603729248046875 +66971 0.867462158203125 +66972 0.699493408203125 +66973 0.870361328125 +66974 0.739990234375 +66975 0.86480712890625 +66976 0.728607177734375 +66977 0.831817626953125 +66978 0.6810302734375 +66979 0.677581787109375 +66980 0.6009521484375 +66981 0.495880126953125 +66982 0.500335693359375 +66983 0.30767822265625 +66984 0.380584716796875 +66985 0.116180419921875 +66986 0.221099853515625 +66987 -0.110748291015625 +66988 0.01739501953125 +66989 -0.381805419921875 +66990 -0.2027587890625 +66991 -0.6572265625 +66992 -0.4005126953125 +66993 -0.857421875 +66994 -0.548004150390625 +66995 -0.870391845703125 +66996 -0.6405029296875 +66997 -0.870391845703125 +66998 -0.695404052734375 +66999 -0.86444091796875 +67000 -0.735748291015625 +67001 -0.85723876953125 +67002 -0.749542236328125 +67003 -0.790008544921875 +67004 -0.701568603515625 +67005 -0.62847900390625 +67006 -0.589691162109375 +67007 -0.3956298828125 +67008 -0.435150146484375 +67009 -0.126708984375 +67010 -0.255645751953125 +67011 0.150115966796875 +67012 -0.058746337890625 +67013 0.424041748046875 +67014 0.138031005859375 +67015 0.670623779296875 +67016 0.309600830078125 +67017 0.854522705078125 +67018 0.4444580078125 +67019 0.866485595703125 +67020 0.5325927734375 +67021 0.86920166015625 +67022 0.585662841796875 +67023 0.8653564453125 +67024 0.612274169921875 +67025 0.857147216796875 +67026 0.6104736328125 +67027 0.766845703125 +67028 0.583526611328125 +67029 0.628509521484375 +67030 0.5269775390625 +67031 0.462127685546875 +67032 0.457489013671875 +67033 0.297210693359375 +67034 0.383026123046875 +67035 0.14862060546875 +67036 0.288787841796875 +67037 -0.00537109375 +67038 0.179656982421875 +67039 -0.15753173828125 +67040 0.05328369140625 +67041 -0.31304931640625 +67042 -0.099395751953125 +67043 -0.48876953125 +67044 -0.247955322265625 +67045 -0.6416015625 +67046 -0.376312255859375 +67047 -0.751373291015625 +67048 -0.499359130859375 +67049 -0.84619140625 +67050 -0.60748291015625 +67051 -0.861297607421875 +67052 -0.679107666015625 +67053 -0.863250732421875 +67054 -0.693756103515625 +67055 -0.856597900390625 +67056 -0.659210205078125 +67057 -0.7498779296875 +67058 -0.612884521484375 +67059 -0.624542236328125 +67060 -0.540496826171875 +67061 -0.47808837890625 +67062 -0.404144287109375 +67063 -0.253387451171875 +67064 -0.233428955078125 +67065 0.003692626953125 +67066 -0.072662353515625 +67067 0.2257080078125 +67068 0.086212158203125 +67069 0.427154541015625 +67070 0.264129638671875 +67071 0.643218994140625 +67072 0.45428466796875 +67073 0.855926513671875 +67074 0.619049072265625 +67075 0.870361328125 +67076 0.726898193359375 +67077 0.870361328125 +67078 0.78216552734375 +67079 0.862762451171875 +67080 0.783111572265625 +67081 0.79669189453125 +67082 0.72412109375 +67083 0.595794677734375 +67084 0.62347412109375 +67085 0.362152099609375 +67086 0.498809814453125 +67087 0.1270751953125 +67088 0.36358642578125 +67089 -0.086944580078125 +67090 0.2196044921875 +67091 -0.2784423828125 +67092 0.045928955078125 +67093 -0.484832763671875 +67094 -0.16876220703125 +67095 -0.729583740234375 +67096 -0.392822265625 +67097 -0.86688232421875 +67098 -0.5867919921875 +67099 -0.870391845703125 +67100 -0.747222900390625 +67101 -0.86859130859375 +67102 -0.856475830078125 +67103 -0.86279296875 +67104 -0.863861083984375 +67105 -0.817962646484375 +67106 -0.8619384765625 +67107 -0.6116943359375 +67108 -0.81488037109375 +67109 -0.3128662109375 +67110 -0.63812255859375 +67111 0.039398193359375 +67112 -0.404876708984375 +67113 0.422821044921875 +67114 -0.135955810546875 +67115 0.805145263671875 +67116 0.126312255859375 +67117 0.870361328125 +67118 0.346343994140625 +67119 0.870361328125 +67120 0.516387939453125 +67121 0.860015869140625 +67122 0.631195068359375 +67123 0.727935791015625 +67124 0.68682861328125 +67125 0.48114013671875 +67126 0.69769287109375 +67127 0.2059326171875 +67128 0.677337646484375 +67129 -0.06103515625 +67130 0.631622314453125 +67131 -0.29913330078125 +67132 0.55145263671875 +67133 -0.516204833984375 +67134 0.42730712890625 +67135 -0.7252197265625 +67136 0.274658203125 +67137 -0.85980224609375 +67138 0.114898681640625 +67139 -0.870391845703125 +67140 -0.0333251953125 +67141 -0.870391845703125 +67142 -0.139495849609375 +67143 -0.858062744140625 +67144 -0.200408935546875 +67145 -0.673004150390625 +67146 -0.24774169921875 +67147 -0.42694091796875 +67148 -0.308197021484375 +67149 -0.2100830078125 +67150 -0.37982177734375 +67151 -0.0362548828125 +67152 -0.44415283203125 +67153 0.10943603515625 +67154 -0.4884033203125 +67155 0.23516845703125 +67156 -0.48675537109375 +67157 0.373687744140625 +67158 -0.440185546875 +67159 0.517791748046875 +67160 -0.38739013671875 +67161 0.602783203125 +67162 -0.325286865234375 +67163 0.635711669921875 +67164 -0.233551025390625 +67165 0.655181884765625 +67166 -0.11871337890625 +67167 0.65948486328125 +67168 0.0137939453125 +67169 0.651275634765625 +67170 0.148284912109375 +67171 0.61846923828125 +67172 0.261322021484375 +67173 0.53753662109375 +67174 0.3411865234375 +67175 0.404144287109375 +67176 0.3812255859375 +67177 0.22186279296875 +67178 0.38165283203125 +67179 0.003997802734375 +67180 0.3531494140625 +67181 -0.22100830078125 +67182 0.308013916015625 +67183 -0.42449951171875 +67184 0.259185791015625 +67185 -0.579833984375 +67186 0.232879638671875 +67187 -0.641876220703125 +67188 0.225006103515625 +67189 -0.6177978515625 +67190 0.195953369140625 +67191 -0.575531005859375 +67192 0.142730712890625 +67193 -0.526336669921875 +67194 0.09765625 +67195 -0.42645263671875 +67196 0.078094482421875 +67197 -0.2581787109375 +67198 0.06219482421875 +67199 -0.068695068359375 +67200 0.02679443359375 +67201 0.09222412109375 +67202 -0.0159912109375 +67203 0.232147216796875 +67204 -0.05938720703125 +67205 0.3509521484375 +67206 -0.12115478515625 +67207 0.410064697265625 +67208 -0.218963623046875 +67209 0.372955322265625 +67210 -0.339599609375 +67211 0.2554931640625 +67212 -0.450775146484375 +67213 0.10711669921875 +67214 -0.54034423828125 +67215 -0.052886962890625 +67216 -0.586090087890625 +67217 -0.186279296875 +67218 -0.553741455078125 +67219 -0.23291015625 +67220 -0.45758056640625 +67221 -0.209442138671875 +67222 -0.33856201171875 +67223 -0.174163818359375 +67224 -0.202239990234375 +67225 -0.126739501953125 +67226 -0.042999267578125 +67227 -0.048126220703125 +67228 0.121246337890625 +67229 0.0426025390625 +67230 0.261260986328125 +67231 0.10748291015625 +67232 0.368438720703125 +67233 0.1409912109375 +67234 0.4716796875 +67235 0.19708251953125 +67236 0.56646728515625 +67237 0.273651123046875 +67238 0.6181640625 +67239 0.31768798828125 +67240 0.633392333984375 +67241 0.341094970703125 +67242 0.627685546875 +67243 0.368011474609375 +67244 0.586944580078125 +67245 0.37249755859375 +67246 0.48095703125 +67247 0.30072021484375 +67248 0.31304931640625 +67249 0.1517333984375 +67250 0.124603271484375 +67251 -0.01470947265625 +67252 -0.073089599609375 +67253 -0.1883544921875 +67254 -0.277099609375 +67255 -0.372711181640625 +67256 -0.449371337890625 +67257 -0.51397705078125 +67258 -0.560516357421875 +67259 -0.57177734375 +67260 -0.602630615234375 +67261 -0.53948974609375 +67262 -0.58380126953125 +67263 -0.43511962890625 +67264 -0.52520751953125 +67265 -0.2962646484375 +67266 -0.44940185546875 +67267 -0.161102294921875 +67268 -0.365142822265625 +67269 -0.0435791015625 +67270 -0.2711181640625 +67271 0.060394287109375 +67272 -0.178192138671875 +67273 0.13665771484375 +67274 -0.098602294921875 +67275 0.170135498046875 +67276 -0.03302001953125 +67277 0.16552734375 +67278 0.03570556640625 +67279 0.15728759765625 +67280 0.106719970703125 +67281 0.150787353515625 +67282 0.161102294921875 +67283 0.12200927734375 +67284 0.200653076171875 +67285 0.080108642578125 +67286 0.238128662109375 +67287 0.05126953125 +67288 0.2877197265625 +67289 0.062896728515625 +67290 0.333709716796875 +67291 0.09271240234375 +67292 0.34564208984375 +67293 0.092987060546875 +67294 0.33245849609375 +67295 0.07855224609375 +67296 0.303985595703125 +67297 0.06427001953125 +67298 0.252288818359375 +67299 0.0347900390625 +67300 0.178436279296875 +67301 -0.01171875 +67302 0.09710693359375 +67303 -0.056060791015625 +67304 0.037811279296875 +67305 -0.055511474609375 +67306 0.003692626953125 +67307 -0.010467529296875 +67308 -0.035003662109375 +67309 0.02508544921875 +67310 -0.0906982421875 +67311 0.025665283203125 +67312 -0.1444091796875 +67313 0.017333984375 +67314 -0.192626953125 +67315 0.00189208984375 +67316 -0.2403564453125 +67317 -0.03173828125 +67318 -0.279052734375 +67319 -0.071502685546875 +67320 -0.31939697265625 +67321 -0.13543701171875 +67322 -0.359527587890625 +67323 -0.219970703125 +67324 -0.38531494140625 +67325 -0.300506591796875 +67326 -0.397918701171875 +67327 -0.376312255859375 +67328 -0.380340576171875 +67329 -0.416107177734375 +67330 -0.30523681640625 +67331 -0.371124267578125 +67332 -0.1759033203125 +67333 -0.242279052734375 +67334 -0.0196533203125 +67335 -0.069732666015625 +67336 0.147857666015625 +67337 0.125640869140625 +67338 0.30511474609375 +67339 0.31268310546875 +67340 0.427886962890625 +67341 0.45501708984375 +67342 0.515533447265625 +67343 0.554779052734375 +67344 0.566009521484375 +67345 0.61065673828125 +67346 0.5716552734375 +67347 0.610931396484375 +67348 0.51800537109375 +67349 0.531463623046875 +67350 0.41534423828125 +67351 0.3883056640625 +67352 0.296844482421875 +67353 0.23468017578125 +67354 0.1790771484375 +67355 0.095245361328125 +67356 0.0797119140625 +67357 -0.00396728515625 +67358 0.009735107421875 +67359 -0.04852294921875 +67360 -0.03839111328125 +67361 -0.055145263671875 +67362 -0.093414306640625 +67363 -0.0758056640625 +67364 -0.169952392578125 +67365 -0.138702392578125 +67366 -0.245208740234375 +67367 -0.209197998046875 +67368 -0.318572998046875 +67369 -0.289031982421875 +67370 -0.389251708984375 +67371 -0.37884521484375 +67372 -0.44317626953125 +67373 -0.456329345703125 +67374 -0.477203369140625 +67375 -0.51641845703125 +67376 -0.467803955078125 +67377 -0.519287109375 +67378 -0.411865234375 +67379 -0.458251953125 +67380 -0.341552734375 +67381 -0.384796142578125 +67382 -0.27337646484375 +67383 -0.323699951171875 +67384 -0.20574951171875 +67385 -0.269287109375 +67386 -0.124908447265625 +67387 -0.1951904296875 +67388 -0.032012939453125 +67389 -0.100006103515625 +67390 0.05487060546875 +67391 -0.01055908203125 +67392 0.15216064453125 +67393 0.1033935546875 +67394 0.26275634765625 +67395 0.24908447265625 +67396 0.35357666015625 +67397 0.373199462890625 +67398 0.413299560546875 +67399 0.45806884765625 +67400 0.446319580078125 +67401 0.511474609375 +67402 0.4720458984375 +67403 0.565399169921875 +67404 0.4859619140625 +67405 0.61138916015625 +67406 0.45318603515625 +67407 0.5897216796875 +67408 0.369110107421875 +67409 0.4906005859375 +67410 0.24566650390625 +67411 0.33148193359375 +67412 0.105712890625 +67413 0.147796630859375 +67414 -0.024017333984375 +67415 -0.01873779296875 +67416 -0.12518310546875 +67417 -0.140289306640625 +67418 -0.181365966796875 +67419 -0.191986083984375 +67420 -0.19757080078125 +67421 -0.184295654296875 +67422 -0.1995849609375 +67423 -0.161834716796875 +67424 -0.211883544921875 +67425 -0.166595458984375 +67426 -0.2313232421875 +67427 -0.19390869140625 +67428 -0.246307373046875 +67429 -0.22442626953125 +67430 -0.2701416015625 +67431 -0.279754638671875 +67432 -0.290985107421875 +67433 -0.3389892578125 +67434 -0.281158447265625 +67435 -0.3543701171875 +67436 -0.25518798828125 +67437 -0.348175048828125 +67438 -0.21771240234375 +67439 -0.32598876953125 +67440 -0.15234375 +67441 -0.2581787109375 +67442 -0.057464599609375 +67443 -0.139801025390625 +67444 0.056915283203125 +67445 0.014617919921875 +67446 0.153228759765625 +67447 0.144378662109375 +67448 0.2135009765625 +67449 0.221038818359375 +67450 0.25274658203125 +67451 0.27069091796875 +67452 0.271026611328125 +67453 0.294036865234375 +67454 0.2806396484375 +67455 0.311767578125 +67456 0.290924072265625 +67457 0.339141845703125 +67458 0.292633056640625 +67459 0.360260009765625 +67460 0.27777099609375 +67461 0.360504150390625 +67462 0.22894287109375 +67463 0.308380126953125 +67464 0.13433837890625 +67465 0.18170166015625 +67466 0.0093994140625 +67467 0.0047607421875 +67468 -0.117279052734375 +67469 -0.17559814453125 +67470 -0.218231201171875 +67471 -0.3143310546875 +67472 -0.26690673828125 +67473 -0.36785888671875 +67474 -0.277801513671875 +67475 -0.36248779296875 +67476 -0.2767333984375 +67477 -0.343536376953125 +67478 -0.2579345703125 +67479 -0.3018798828125 +67480 -0.2176513671875 +67481 -0.231414794921875 +67482 -0.14752197265625 +67483 -0.117645263671875 +67484 -0.066802978515625 +67485 0.007049560546875 +67486 -0.007965087890625 +67487 0.087982177734375 +67488 0.036590576171875 +67489 0.13946533203125 +67490 0.073455810546875 +67491 0.17425537109375 +67492 0.0992431640625 +67493 0.188201904296875 +67494 0.1070556640625 +67495 0.171234130859375 +67496 0.093048095703125 +67497 0.118438720703125 +67498 0.072265625 +67499 0.05706787109375 +67500 0.045135498046875 +67501 -0.010711669921875 +67502 0.007293701171875 +67503 -0.0914306640625 +67504 -0.02838134765625 +67505 -0.162322998046875 +67506 -0.045257568359375 +67507 -0.194549560546875 +67508 -0.020660400390625 +67509 -0.1492919921875 +67510 0.048431396484375 +67511 -0.02166748046875 +67512 0.124908447265625 +67513 0.124053955078125 +67514 0.164520263671875 +67515 0.211151123046875 +67516 0.16845703125 +67517 0.240447998046875 +67518 0.1551513671875 +67519 0.242218017578125 +67520 0.130859375 +67521 0.2257080078125 +67522 0.098388671875 +67523 0.194366455078125 +67524 0.039398193359375 +67525 0.115509033203125 +67526 -0.031585693359375 +67527 0.0128173828125 +67528 -0.079010009765625 +67529 -0.053802490234375 +67530 -0.11785888671875 +67531 -0.110626220703125 +67532 -0.172332763671875 +67533 -0.199493408203125 +67534 -0.227203369140625 +67535 -0.29437255859375 +67536 -0.245758056640625 +67537 -0.33221435546875 +67538 -0.208831787109375 +67539 -0.27972412109375 +67540 -0.1451416015625 +67541 -0.185333251953125 +67542 -0.1014404296875 +67543 -0.128204345703125 +67544 -0.08258056640625 +67545 -0.115692138671875 +67546 -0.07098388671875 +67547 -0.116455078125 +67548 -0.052978515625 +67549 -0.105926513671875 +67550 -0.0115966796875 +67551 -0.053955078125 +67552 0.05804443359375 +67553 0.048797607421875 +67554 0.129180908203125 +67555 0.157318115234375 +67556 0.166656494140625 +67557 0.212005615234375 +67558 0.1734619140625 +67559 0.218475341796875 +67560 0.184844970703125 +67561 0.23724365234375 +67562 0.2225341796875 +67563 0.30535888671875 +67564 0.262420654296875 +67565 0.38128662109375 +67566 0.269439697265625 +67567 0.404449462890625 +67568 0.25543212890625 +67569 0.3944091796875 +67570 0.242706298828125 +67571 0.3885498046875 +67572 0.21771240234375 +67573 0.362640380859375 +67574 0.15582275390625 +67575 0.27362060546875 +67576 0.055023193359375 +67577 0.11712646484375 +67578 -0.0538330078125 +67579 -0.054901123046875 +67580 -0.140167236328125 +67581 -0.19085693359375 +67582 -0.200714111328125 +67583 -0.28570556640625 +67584 -0.235748291015625 +67585 -0.339263916015625 +67586 -0.26007080078125 +67587 -0.3775634765625 +67588 -0.298583984375 +67589 -0.445709228515625 +67590 -0.346282958984375 +67591 -0.535064697265625 +67592 -0.39398193359375 +67593 -0.629058837890625 +67594 -0.425201416015625 +67595 -0.697601318359375 +67596 -0.41998291015625 +67597 -0.70391845703125 +67598 -0.375732421875 +67599 -0.6424560546875 +67600 -0.280914306640625 +67601 -0.491241455078125 +67602 -0.144683837890625 +67603 -0.265716552734375 +67604 0.0003662109375 +67605 -0.023712158203125 +67606 0.135345458984375 +67607 0.201751708984375 +67608 0.240447998046875 +67609 0.375823974609375 +67610 0.30780029296875 +67611 0.485076904296875 +67612 0.3587646484375 +67613 0.56884765625 +67614 0.3973388671875 +67615 0.634765625 +67616 0.398529052734375 +67617 0.63763427734375 +67618 0.3560791015625 +67619 0.5660400390625 +67620 0.298980712890625 +67621 0.4720458984375 +67622 0.255859375 +67623 0.40692138671875 +67624 0.231109619140625 +67625 0.3778076171875 +67626 0.220977783203125 +67627 0.376953125 +67628 0.2081298828125 +67629 0.371978759765625 +67630 0.165679931640625 +67631 0.313140869140625 +67632 0.0853271484375 +67633 0.184417724609375 +67634 -0.018402099609375 +67635 0.011199951171875 +67636 -0.125518798828125 +67637 -0.171051025390625 +67638 -0.221954345703125 +67639 -0.33740234375 +67640 -0.298736572265625 +67641 -0.47198486328125 +67642 -0.347869873046875 +67643 -0.560394287109375 +67644 -0.35723876953125 +67645 -0.58056640625 +67646 -0.335296630859375 +67647 -0.54754638671875 +67648 -0.308380126953125 +67649 -0.508575439453125 +67650 -0.2745361328125 +67651 -0.459503173828125 +67652 -0.23089599609375 +67653 -0.394378662109375 +67654 -0.199615478515625 +67655 -0.35260009765625 +67656 -0.16876220703125 +67657 -0.31170654296875 +67658 -0.097808837890625 +67659 -0.197418212890625 +67660 0.013824462890625 +67661 -0.007965087890625 +67662 0.13861083984375 +67663 0.207489013671875 +67664 0.254302978515625 +67665 0.409210205078125 +67666 0.34686279296875 +67667 0.57208251953125 +67668 0.3995361328125 +67669 0.66595458984375 +67670 0.3946533203125 +67671 0.65875244140625 +67672 0.3416748046875 +67673 0.56744384765625 +67674 0.26251220703125 +67675 0.431396484375 +67676 0.181640625 +67677 0.29443359375 +67678 0.113677978515625 +67679 0.182464599609375 +67680 0.041412353515625 +67681 0.06365966796875 +67682 -0.04248046875 +67683 -0.075958251953125 +67684 -0.1116943359375 +67685 -0.189422607421875 +67686 -0.1632080078125 +67687 -0.271942138671875 +67688 -0.20721435546875 +67689 -0.342529296875 +67690 -0.223052978515625 +67691 -0.364166259765625 +67692 -0.205291748046875 +67693 -0.327239990234375 +67694 -0.178741455078125 +67695 -0.2769775390625 +67696 -0.1656494140625 +67697 -0.253692626953125 +67698 -0.158447265625 +67699 -0.24365234375 +67700 -0.130523681640625 +67701 -0.1983642578125 +67702 -0.0811767578125 +67703 -0.116241455078125 +67704 -0.032501220703125 +67705 -0.036834716796875 +67706 0.012451171875 +67707 0.034881591796875 +67708 0.04913330078125 +67709 0.09124755859375 +67710 0.064361572265625 +67711 0.10888671875 +67712 0.078643798828125 +67713 0.125518798828125 +67714 0.100860595703125 +67715 0.15771484375 +67716 0.11578369140625 +67717 0.17828369140625 +67718 0.11431884765625 +67719 0.17108154296875 +67720 0.092987060546875 +67721 0.129974365234375 +67722 0.06689453125 +67723 0.082427978515625 +67724 0.03564453125 +67725 0.027679443359375 +67726 -0.0179443359375 +67727 -0.065643310546875 +67728 -0.072662353515625 +67729 -0.15936279296875 +67730 -0.106048583984375 +67731 -0.21307373046875 +67732 -0.122222900390625 +67733 -0.234649658203125 +67734 -0.10772705078125 +67735 -0.2001953125 +67736 -0.067535400390625 +67737 -0.119171142578125 +67738 -0.01971435546875 +67739 -0.024749755859375 +67740 0.037445068359375 +67741 0.085784912109375 +67742 0.085205078125 +67743 0.178131103515625 +67744 0.103485107421875 +67745 0.215576171875 +67746 0.0997314453125 +67747 0.211456298828125 +67748 0.0792236328125 +67749 0.17523193359375 +67750 0.05401611328125 +67751 0.128753662109375 +67752 0.04058837890625 +67753 0.1019287109375 +67754 0.027557373046875 +67755 0.0743408203125 +67756 0.013275146484375 +67757 0.04327392578125 +67758 0.013824462890625 +67759 0.038177490234375 +67760 0.03851318359375 +67761 0.076263427734375 +67762 0.0780029296875 +67763 0.14105224609375 +67764 0.106658935546875 +67765 0.186431884765625 +67766 0.11126708984375 +67767 0.188812255859375 +67768 0.08660888671875 +67769 0.1390380859375 +67770 0.035125732421875 +67771 0.041778564453125 +67772 -0.030303955078125 +67773 -0.079437255859375 +67774 -0.106842041015625 +67775 -0.219390869140625 +67776 -0.188812255859375 +67777 -0.367828369140625 +67778 -0.25970458984375 +67779 -0.494873046875 +67780 -0.2950439453125 +67781 -0.556243896484375 +67782 -0.2708740234375 +67783 -0.508697509765625 +67784 -0.199951171875 +67785 -0.3756103515625 +67786 -0.116302490234375 +67787 -0.218902587890625 +67788 -0.033660888671875 +67789 -0.063751220703125 +67790 0.049041748046875 +67791 0.091552734375 +67792 0.12591552734375 +67793 0.23602294921875 +67794 0.182373046875 +67795 0.342987060546875 +67796 0.20904541015625 +67797 0.39520263671875 +67798 0.204254150390625 +67799 0.389373779296875 +67800 0.167388916015625 +67801 0.324249267578125 +67802 0.111846923828125 +67803 0.224090576171875 +67804 0.057159423828125 +67805 0.124267578125 +67806 0.01007080078125 +67807 0.037078857421875 +67808 -0.014373779296875 +67809 -0.010101318359375 +67810 -0.017486572265625 +67811 -0.019439697265625 +67812 -0.0169677734375 +67813 -0.022796630859375 +67814 -0.002685546875 +67815 -0.001556396484375 +67816 0.031829833984375 +67817 0.056304931640625 +67818 0.062103271484375 +67819 0.106719970703125 +67820 0.058868408203125 +67821 0.096893310546875 +67822 0.030792236328125 +67823 0.042694091796875 +67824 -0.0013427734375 +67825 -0.018035888671875 +67826 -0.0323486328125 +67827 -0.07586669921875 +67828 -0.055999755859375 +67829 -0.11944580078125 +67830 -0.078369140625 +67831 -0.15972900390625 +67832 -0.102691650390625 +67833 -0.202606201171875 +67834 -0.129180908203125 +67835 -0.24859619140625 +67836 -0.161895751953125 +67837 -0.30517578125 +67838 -0.195098876953125 +67839 -0.36212158203125 +67840 -0.21337890625 +67841 -0.39141845703125 +67842 -0.19586181640625 +67843 -0.35528564453125 +67844 -0.14031982421875 +67845 -0.249969482421875 +67846 -0.056396484375 +67847 -0.092864990234375 +67848 0.04132080078125 +67849 0.08905029296875 +67850 0.120880126953125 +67851 0.2352294921875 +67852 0.16790771484375 +67853 0.318817138671875 +67854 0.191864013671875 +67855 0.358642578125 +67856 0.18890380859375 +67857 0.347747802734375 +67858 0.158599853515625 +67859 0.28564453125 +67860 0.12725830078125 +67861 0.223175048828125 +67862 0.113800048828125 +67863 0.196746826171875 +67864 0.1044921875 +67865 0.179840087890625 +67866 0.09063720703125 +67867 0.155548095703125 +67868 0.0865478515625 +67869 0.151214599609375 +67870 0.087249755859375 +67871 0.156951904296875 +67872 0.071563720703125 +67873 0.13177490234375 +67874 0.052734375 +67875 0.100799560546875 +67876 0.042938232421875 +67877 0.087127685546875 +67878 0.023681640625 +67879 0.05487060546875 +67880 -0.011688232421875 +67881 -0.009002685546875 +67882 -0.062744140625 +67883 -0.10400390625 +67884 -0.12908935546875 +67885 -0.229400634765625 +67886 -0.195220947265625 +67887 -0.35552978515625 +67888 -0.240081787109375 +67889 -0.441925048828125 +67890 -0.25604248046875 +67891 -0.473846435546875 +67892 -0.250152587890625 +67893 -0.464813232421875 +67894 -0.2247314453125 +67895 -0.419097900390625 +67896 -0.17864990234375 +67897 -0.334320068359375 +67898 -0.12109375 +67899 -0.227935791015625 +67900 -0.064422607421875 +67901 -0.12347412109375 +67902 -0.01226806640625 +67903 -0.02764892578125 +67904 0.044647216796875 +67905 0.077667236328125 +67906 0.11700439453125 +67907 0.2132568359375 +67908 0.20977783203125 +67909 0.38885498046875 +67910 0.311614990234375 +67911 0.582794189453125 +67912 0.3907470703125 +67913 0.734039306640625 +67914 0.425079345703125 +67915 0.800140380859375 +67916 0.413177490234375 +67917 0.7783203125 +67918 0.353363037109375 +67919 0.6651611328125 +67920 0.245147705078125 +67921 0.45965576171875 +67922 0.10809326171875 +67923 0.199188232421875 +67924 -0.023651123046875 +67925 -0.050689697265625 +67926 -0.120330810546875 +67927 -0.23297119140625 +67928 -0.1727294921875 +67929 -0.33013916015625 +67930 -0.19439697265625 +67931 -0.368408203125 +67932 -0.201416015625 +67933 -0.378936767578125 +67934 -0.20166015625 +67935 -0.376983642578125 +67936 -0.2039794921875 +67937 -0.37969970703125 +67938 -0.21063232421875 +67939 -0.391510009765625 +67940 -0.207550048828125 +67941 -0.385345458984375 +67942 -0.184661865234375 +67943 -0.3419189453125 +67944 -0.153289794921875 +67945 -0.28289794921875 +67946 -0.136016845703125 +67947 -0.251617431640625 +67948 -0.142303466796875 +67949 -0.266143798828125 +67950 -0.14459228515625 +67951 -0.273345947265625 +67952 -0.113616943359375 +67953 -0.216796875 +67954 -0.06597900390625 +67955 -0.128265380859375 +67956 -0.033172607421875 +67957 -0.068145751953125 +67958 -0.018707275390625 +67959 -0.0430908203125 +67960 -0.007781982421875 +67961 -0.024444580078125 +67962 0.016632080078125 +67963 0.020721435546875 +67964 0.071136474609375 +67965 0.124481201171875 +67966 0.140655517578125 +67967 0.25787353515625 +67968 0.2034912109375 +67969 0.379119873046875 +67970 0.25537109375 +67971 0.47991943359375 +67972 0.2796630859375 +67973 0.5281982421875 +67974 0.26971435546875 +67975 0.511138916015625 +67976 0.239898681640625 +67977 0.456207275390625 +67978 0.21319580078125 +67979 0.407470703125 +67980 0.199493408203125 +67981 0.383758544921875 +67982 0.184173583984375 +67983 0.35687255859375 +67984 0.159515380859375 +67985 0.31182861328125 +67986 0.126739501953125 +67987 0.250885009765625 +67988 0.0814208984375 +67989 0.1654052734375 +67990 0.013153076171875 +67991 0.035247802734375 +67992 -0.079315185546875 +67993 -0.142059326171875 +67994 -0.179931640625 +67995 -0.33563232421875 +67996 -0.28302001953125 +67997 -0.5345458984375 +67998 -0.3797607421875 +67999 -0.72186279296875 +68000 -0.43853759765625 +68001 -0.836669921875 +68002 -0.435333251953125 +68003 -0.8326416015625 +68004 -0.38055419921875 +68005 -0.7296142578125 +68006 -0.302825927734375 +68007 -0.582550048828125 +68008 -0.2275390625 +68009 -0.440093994140625 +68010 -0.166229248046875 +68011 -0.324310302734375 +68012 -0.101409912109375 +68013 -0.20147705078125 +68014 -0.01910400390625 +68015 -0.044647216796875 +68016 0.0587158203125 +68017 0.103973388671875 +68018 0.11016845703125 +68019 0.202392578125 +68020 0.1424560546875 +68021 0.264495849609375 +68022 0.180877685546875 +68023 0.338897705078125 +68024 0.23492431640625 +68025 0.443817138671875 +68026 0.286865234375 +68027 0.545074462890625 +68028 0.32354736328125 +68029 0.6173095703125 +68030 0.3408203125 +68031 0.6524658203125 +68032 0.345428466796875 +68033 0.66339111328125 +68034 0.340576171875 +68035 0.6561279296875 +68036 0.31390380859375 +68037 0.606781005859375 +68038 0.25811767578125 +68039 0.501190185546875 +68040 0.18023681640625 +68041 0.352783203125 +68042 0.08807373046875 +68043 0.176544189453125 +68044 -0.0220947265625 +68045 -0.034820556640625 +68046 -0.138275146484375 +68047 -0.258209228515625 +68048 -0.233856201171875 +68049 -0.44244384765625 +68050 -0.302490234375 +68051 -0.5753173828125 +68052 -0.34173583984375 +68053 -0.65203857421875 +68054 -0.335540771484375 +68055 -0.641632080078125 +68056 -0.2933349609375 +68057 -0.562164306640625 +68058 -0.23828125 +68059 -0.458038330078125 +68060 -0.181488037109375 +68061 -0.350555419921875 +68062 -0.133819580078125 +68063 -0.260528564453125 +68064 -0.097503662109375 +68065 -0.192108154296875 +68066 -0.070831298828125 +68067 -0.141937255859375 +68068 -0.04974365234375 +68069 -0.1021728515625 +68070 -0.029083251953125 +68071 -0.062896728515625 +68072 -0.002532958984375 +68073 -0.011932373046875 +68074 0.03619384765625 +68075 0.062835693359375 +68076 0.080535888671875 +68077 0.148712158203125 +68078 0.12841796875 +68079 0.241729736328125 +68080 0.18365478515625 +68081 0.34912109375 +68082 0.239227294921875 +68083 0.457305908203125 +68084 0.28350830078125 +68085 0.54388427734375 +68086 0.297821044921875 +68087 0.5728759765625 +68088 0.262603759765625 +68089 0.506591796875 +68090 0.18115234375 +68091 0.351226806640625 +68092 0.074127197265625 +68093 0.146514892578125 +68094 -0.031219482421875 +68095 -0.05523681640625 +68096 -0.114898681640625 +68097 -0.21624755859375 +68098 -0.17626953125 +68099 -0.334930419921875 +68100 -0.211883544921875 +68101 -0.402984619140625 +68102 -0.231842041015625 +68103 -0.4412841796875 +68104 -0.258575439453125 +68105 -0.49578857421875 +68106 -0.2890625 +68107 -0.5601806640625 +68108 -0.306976318359375 +68109 -0.600738525390625 +68110 -0.296234130859375 +68111 -0.584228515625 +68112 -0.24176025390625 +68113 -0.47930908203125 +68114 -0.14056396484375 +68115 -0.27935791015625 +68116 -0.00482177734375 +68117 -0.0089111328125 +68118 0.134368896484375 +68119 0.268798828125 +68120 0.2421875 +68121 0.482818603515625 +68122 0.304107666015625 +68123 0.60369873046875 +68124 0.3292236328125 +68125 0.650421142578125 +68126 0.337432861328125 +68127 0.66400146484375 +68128 0.32720947265625 +68129 0.6414794921875 +68130 0.293548583984375 +68131 0.572540283203125 +68132 0.256439208984375 +68133 0.498138427734375 +68134 0.226287841796875 +68135 0.439453125 +68136 0.192962646484375 +68137 0.375518798828125 +68138 0.14105224609375 +68139 0.274505615234375 +68140 0.0572509765625 +68141 0.1087646484375 +68142 -0.047393798828125 +68143 -0.099395751953125 +68144 -0.157196044921875 +68145 -0.3182373046875 +68146 -0.2725830078125 +68147 -0.5489501953125 +68148 -0.384735107421875 +68149 -0.7738037109375 +68150 -0.46771240234375 +68151 -0.86383056640625 +68152 -0.50518798828125 +68153 -0.870391845703125 +68154 -0.5057373046875 +68155 -0.86895751953125 +68156 -0.47576904296875 +68157 -0.861053466796875 +68158 -0.406829833984375 +68159 -0.765869140625 +68160 -0.293487548828125 +68161 -0.5301513671875 +68162 -0.1392822265625 +68163 -0.214691162109375 +68164 0.034637451171875 +68165 0.137359619140625 +68166 0.203125 +68167 0.474822998046875 +68168 0.34869384765625 +68169 0.76239013671875 +68170 0.458038330078125 +68171 0.867462158203125 +68172 0.53125 +68173 0.870361328125 +68174 0.56256103515625 +68175 0.86480712890625 +68176 0.554473876953125 +68177 0.831817626953125 +68178 0.518798828125 +68179 0.677581787109375 +68180 0.458343505859375 +68181 0.495880126953125 +68182 0.382110595703125 +68183 0.30767822265625 +68184 0.29119873046875 +68185 0.116180419921875 +68186 0.170135498046875 +68187 -0.110748291015625 +68188 0.015594482421875 +68189 -0.381805419921875 +68190 -0.15142822265625 +68191 -0.6572265625 +68192 -0.301605224609375 +68193 -0.857421875 +68194 -0.41387939453125 +68195 -0.870391845703125 +68196 -0.484649658203125 +68197 -0.870391845703125 +68198 -0.526947021484375 +68199 -0.86444091796875 +68200 -0.55804443359375 +68201 -0.85723876953125 +68202 -0.568878173828125 +68203 -0.790008544921875 +68204 -0.532928466796875 +68205 -0.62847900390625 +68206 -0.448577880859375 +68207 -0.3956298828125 +68208 -0.33184814453125 +68209 -0.126708984375 +68210 -0.19610595703125 +68211 0.150115966796875 +68212 -0.047088623046875 +68213 0.424041748046875 +68214 0.10198974609375 +68215 0.670623779296875 +68216 0.232147216796875 +68217 0.854522705078125 +68218 0.33465576171875 +68219 0.866485595703125 +68220 0.401947021484375 +68221 0.86920166015625 +68222 0.4427490234375 +68223 0.8653564453125 +68224 0.463531494140625 +68225 0.857147216796875 +68226 0.4627685546875 +68227 0.766845703125 +68228 0.442901611328125 +68229 0.628509521484375 +68230 0.400543212890625 +68231 0.462127685546875 +68232 0.348236083984375 +68233 0.297210693359375 +68234 0.2919921875 +68235 0.14862060546875 +68236 0.220672607421875 +68237 -0.00537109375 +68238 0.137939453125 +68239 -0.15753173828125 +68240 0.042083740234375 +68241 -0.31304931640625 +68242 -0.07366943359375 +68243 -0.48876953125 +68244 -0.18634033203125 +68245 -0.6416015625 +68246 -0.2838134765625 +68247 -0.751373291015625 +68248 -0.377227783203125 +68249 -0.84619140625 +68250 -0.459320068359375 +68251 -0.861297607421875 +68252 -0.513824462890625 +68253 -0.863250732421875 +68254 -0.525238037109375 +68255 -0.856597900390625 +68256 -0.499420166015625 +68257 -0.7498779296875 +68258 -0.464569091796875 +68259 -0.624542236328125 +68260 -0.409942626953125 +68261 -0.47808837890625 +68262 -0.3070068359375 +68263 -0.253387451171875 +68264 -0.17803955078125 +68265 0.003692626953125 +68266 -0.05645751953125 +68267 0.2257080078125 +68268 0.06378173828125 +68269 0.427154541015625 +68270 0.19842529296875 +68271 0.643218994140625 +68272 0.3426513671875 +68273 0.855926513671875 +68274 0.46807861328125 +68275 0.870361328125 +68276 0.5504150390625 +68277 0.870361328125 +68278 0.593048095703125 +68279 0.862762451171875 +68280 0.594512939453125 +68281 0.79669189453125 +68282 0.55010986328125 +68283 0.595794677734375 +68284 0.474029541015625 +68285 0.362152099609375 +68286 0.379974365234375 +68287 0.1270751953125 +68288 0.27825927734375 +68289 -0.086944580078125 +68290 0.169952392578125 +68291 -0.2784423828125 +68292 0.03814697265625 +68293 -0.484832763671875 +68294 -0.12646484375 +68295 -0.729583740234375 +68296 -0.299102783203125 +68297 -0.86688232421875 +68298 -0.44873046875 +68299 -0.870391845703125 +68300 -0.572845458984375 +68301 -0.86859130859375 +68302 -0.6702880859375 +68303 -0.86279296875 +68304 -0.723419189453125 +68305 -0.817962646484375 +68306 -0.7099609375 +68307 -0.6116943359375 +68308 -0.62640380859375 +68309 -0.3128662109375 +68310 -0.4891357421875 +68311 0.039398193359375 +68312 -0.30792236328125 +68313 0.422821044921875 +68314 -0.099029541015625 +68315 0.805145263671875 +68316 0.104217529296875 +68317 0.870361328125 +68318 0.273895263671875 +68319 0.870361328125 +68320 0.404144287109375 +68321 0.860015869140625 +68322 0.49102783203125 +68323 0.727935791015625 +68324 0.5316162109375 +68325 0.48114013671875 +68326 0.53753662109375 +68327 0.2059326171875 +68328 0.519622802734375 +68329 -0.06103515625 +68330 0.48260498046875 +68331 -0.29913330078125 +68332 0.4193115234375 +68333 -0.516204833984375 +68334 0.3221435546875 +68335 -0.7252197265625 +68336 0.2032470703125 +68337 -0.85980224609375 +68338 0.079437255859375 +68339 -0.870391845703125 +68340 -0.03466796875 +68341 -0.870391845703125 +68342 -0.115081787109375 +68343 -0.858062744140625 +68344 -0.159515380859375 +68345 -0.673004150390625 +68346 -0.193267822265625 +68347 -0.42694091796875 +68348 -0.2376708984375 +68349 -0.2100830078125 +68350 -0.2913818359375 +68351 -0.0362548828125 +68352 -0.339599609375 +68353 0.10943603515625 +68354 -0.372161865234375 +68355 0.23516845703125 +68356 -0.369873046875 +68357 0.373687744140625 +68358 -0.3336181640625 +68359 0.517791748046875 +68360 -0.292236328125 +68361 0.602783203125 +68362 -0.243621826171875 +68363 0.635711669921875 +68364 -0.172943115234375 +68365 0.655181884765625 +68366 -0.085205078125 +68367 0.65948486328125 +68368 0.015380859375 +68369 0.651275634765625 +68370 0.117095947265625 +68371 0.61846923828125 +68372 0.202484130859375 +68373 0.53753662109375 +68374 0.262725830078125 +68375 0.404144287109375 +68376 0.292877197265625 +68377 0.22186279296875 +68378 0.2930908203125 +68379 0.003997802734375 +68380 0.27130126953125 +68381 -0.22100830078125 +68382 0.2366943359375 +68383 -0.42449951171875 +68384 0.19891357421875 +68385 -0.579833984375 +68386 0.177459716796875 +68387 -0.641876220703125 +68388 0.16943359375 +68389 -0.6177978515625 +68390 0.1456298828125 +68391 -0.575531005859375 +68392 0.103973388671875 +68393 -0.526336669921875 +68394 0.068511962890625 +68395 -0.42645263671875 +68396 0.05218505859375 +68397 -0.2581787109375 +68398 0.0389404296875 +68399 -0.068695068359375 +68400 0.011688232421875 +68401 0.09222412109375 +68402 -0.020538330078125 +68403 0.232147216796875 +68404 -0.052703857421875 +68405 0.3509521484375 +68406 -0.097991943359375 +68407 0.410064697265625 +68408 -0.16949462890625 +68409 0.372955322265625 +68410 -0.257537841796875 +68411 0.2554931640625 +68412 -0.3382568359375 +68413 0.10711669921875 +68414 -0.402801513671875 +68415 -0.052886962890625 +68416 -0.434783935546875 +68417 -0.186279296875 +68418 -0.408935546875 +68419 -0.23291015625 +68420 -0.335968017578125 +68421 -0.209442138671875 +68422 -0.24627685546875 +68423 -0.174163818359375 +68424 -0.14404296875 +68425 -0.126739501953125 +68426 -0.02520751953125 +68427 -0.048126220703125 +68428 0.096954345703125 +68429 0.0426025390625 +68430 0.200775146484375 +68431 0.10748291015625 +68432 0.279876708984375 +68433 0.1409912109375 +68434 0.355682373046875 +68435 0.19708251953125 +68436 0.424896240234375 +68437 0.273651123046875 +68438 0.461944580078125 +68439 0.31768798828125 +68440 0.4718017578125 +68441 0.341094970703125 +68442 0.466033935546875 +68443 0.368011474609375 +68444 0.434326171875 +68445 0.37249755859375 +68446 0.354400634765625 +68447 0.30072021484375 +68448 0.228759765625 +68449 0.1517333984375 +68450 0.08807373046875 +68451 -0.01470947265625 +68452 -0.059173583984375 +68453 -0.1883544921875 +68454 -0.210784912109375 +68455 -0.372711181640625 +68456 -0.33856201171875 +68457 -0.51397705078125 +68458 -0.420745849609375 +68459 -0.57177734375 +68460 -0.451507568359375 +68461 -0.53948974609375 +68462 -0.436859130859375 +68463 -0.43511962890625 +68464 -0.392547607421875 +68465 -0.2962646484375 +68466 -0.3353271484375 +68467 -0.161102294921875 +68468 -0.271697998046875 +68469 -0.0435791015625 +68470 -0.200775146484375 +68471 0.060394287109375 +68472 -0.130706787109375 +68473 0.13665771484375 +68474 -0.070587158203125 +68475 0.170135498046875 +68476 -0.021026611328125 +68477 0.16552734375 +68478 0.0306396484375 +68479 0.15728759765625 +68480 0.083740234375 +68481 0.150787353515625 +68482 0.124237060546875 +68483 0.12200927734375 +68484 0.153472900390625 +68485 0.080108642578125 +68486 0.180908203125 +68487 0.05126953125 +68488 0.217071533203125 +68489 0.062896728515625 +68490 0.2503662109375 +68491 0.09271240234375 +68492 0.25830078125 +68493 0.092987060546875 +68494 0.247528076171875 +68495 0.07855224609375 +68496 0.22540283203125 +68497 0.06427001953125 +68498 0.18609619140625 +68499 0.0347900390625 +68500 0.130462646484375 +68501 -0.01171875 +68502 0.06939697265625 +68503 -0.056060791015625 +68504 0.0247802734375 +68505 -0.055511474609375 +68506 -0.000946044921875 +68507 -0.010467529296875 +68508 -0.02984619140625 +68509 0.02508544921875 +68510 -0.071136474609375 +68511 0.025665283203125 +68512 -0.110748291015625 +68513 0.017333984375 +68514 -0.14605712890625 +68515 0.00189208984375 +68516 -0.180816650390625 +68517 -0.03173828125 +68518 -0.208770751953125 +68519 -0.071502685546875 +68520 -0.237823486328125 +68521 -0.13543701171875 +68522 -0.26666259765625 +68523 -0.219970703125 +68524 -0.28485107421875 +68525 -0.300506591796875 +68526 -0.2933349609375 +68527 -0.376312255859375 +68528 -0.27947998046875 +68529 -0.416107177734375 +68530 -0.22296142578125 +68531 -0.371124267578125 +68532 -0.126312255859375 +68533 -0.242279052734375 +68534 -0.00994873046875 +68535 -0.069732666015625 +68536 0.114532470703125 +68537 0.125640869140625 +68538 0.231048583984375 +68539 0.31268310546875 +68540 0.321441650390625 +68541 0.45501708984375 +68542 0.385498046875 +68543 0.554779052734375 +68544 0.421783447265625 +68545 0.61065673828125 +68546 0.424591064453125 +68547 0.610931396484375 +68548 0.383026123046875 +68549 0.531463623046875 +68550 0.304901123046875 +68551 0.3883056640625 +68552 0.21539306640625 +68553 0.23468017578125 +68554 0.127044677734375 +68555 0.095245361328125 +68556 0.053192138671875 +68557 -0.00396728515625 +68558 0.002044677734375 +68559 -0.04852294921875 +68560 -0.0322265625 +68561 -0.055145263671875 +68562 -0.071624755859375 +68563 -0.0758056640625 +68564 -0.12738037109375 +68565 -0.138702392578125 +68566 -0.18231201171875 +68567 -0.209197998046875 +68568 -0.236083984375 +68569 -0.289031982421875 +68570 -0.2882080078125 +68571 -0.37884521484375 +68572 -0.328094482421875 +68573 -0.456329345703125 +68574 -0.353363037109375 +68575 -0.51641845703125 +68576 -0.346160888671875 +68577 -0.519287109375 +68578 -0.3040771484375 +68579 -0.458251953125 +68580 -0.251556396484375 +68581 -0.384796142578125 +68582 -0.2010498046875 +68583 -0.323699951171875 +68584 -0.15130615234375 +68585 -0.269287109375 +68586 -0.091705322265625 +68587 -0.1951904296875 +68588 -0.0230712890625 +68589 -0.100006103515625 +68590 0.040985107421875 +68591 -0.01055908203125 +68592 0.113037109375 +68593 0.1033935546875 +68594 0.195404052734375 +68595 0.24908447265625 +68596 0.26300048828125 +68597 0.373199462890625 +68598 0.30731201171875 +68599 0.45806884765625 +68600 0.33172607421875 +68601 0.511474609375 +68602 0.35101318359375 +68603 0.565399169921875 +68604 0.36175537109375 +68605 0.61138916015625 +68606 0.33740234375 +68607 0.5897216796875 +68608 0.274505615234375 +68609 0.4906005859375 +68610 0.182220458984375 +68611 0.33148193359375 +68612 0.077728271484375 +68613 0.147796630859375 +68614 -0.01898193359375 +68615 -0.01873779296875 +68616 -0.094207763671875 +68617 -0.140289306640625 +68618 -0.135711669921875 +68619 -0.191986083984375 +68620 -0.14727783203125 +68621 -0.184295654296875 +68622 -0.14825439453125 +68623 -0.161834716796875 +68624 -0.157012939453125 +68625 -0.166595458984375 +68626 -0.1712646484375 +68627 -0.19390869140625 +68628 -0.182281494140625 +68629 -0.22442626953125 +68630 -0.200103759765625 +68631 -0.279754638671875 +68632 -0.2158203125 +68633 -0.3389892578125 +68634 -0.20867919921875 +68635 -0.3543701171875 +68636 -0.189544677734375 +68637 -0.348175048828125 +68638 -0.161865234375 +68639 -0.32598876953125 +68640 -0.11334228515625 +68641 -0.2581787109375 +68642 -0.042755126953125 +68643 -0.139801025390625 +68644 0.042449951171875 +68645 0.014617919921875 +68646 0.1141357421875 +68647 0.144378662109375 +68648 0.158843994140625 +68649 0.221038818359375 +68650 0.1878662109375 +68651 0.27069091796875 +68652 0.201263427734375 +68653 0.294036865234375 +68654 0.208282470703125 +68655 0.311767578125 +68656 0.215911865234375 +68657 0.339141845703125 +68658 0.217010498046875 +68659 0.360260009765625 +68660 0.205657958984375 +68661 0.360504150390625 +68662 0.1693115234375 +68663 0.308380126953125 +68664 0.099517822265625 +68665 0.18170166015625 +68666 0.007598876953125 +68667 0.0047607421875 +68668 -0.085601806640625 +68669 -0.17559814453125 +68670 -0.160064697265625 +68671 -0.3143310546875 +68672 -0.19647216796875 +68673 -0.36785888671875 +68674 -0.20526123046875 +68675 -0.36248779296875 +68676 -0.205108642578125 +68677 -0.343536376953125 +68678 -0.19183349609375 +68679 -0.3018798828125 +68680 -0.16265869140625 +68681 -0.231414794921875 +68682 -0.11151123046875 +68683 -0.117645263671875 +68684 -0.05242919921875 +68685 0.007049560546875 +68686 -0.009002685546875 +68687 0.087982177734375 +68688 0.024200439453125 +68689 0.13946533203125 +68690 0.051910400390625 +68691 0.17425537109375 +68692 0.07159423828125 +68693 0.188201904296875 +68694 0.078216552734375 +68695 0.171234130859375 +68696 0.0689697265625 +68697 0.118438720703125 +68698 0.054718017578125 +68699 0.05706787109375 +68700 0.035736083984375 +68701 -0.010711669921875 +68702 0.008758544921875 +68703 -0.0914306640625 +68704 -0.016815185546875 +68705 -0.162322998046875 +68706 -0.028961181640625 +68707 -0.194549560546875 +68708 -0.011199951171875 +68709 -0.1492919921875 +68710 0.038665771484375 +68711 -0.02166748046875 +68712 0.093719482421875 +68713 0.124053955078125 +68714 0.121856689453125 +68715 0.211151123046875 +68716 0.12396240234375 +68717 0.240447998046875 +68718 0.11346435546875 +68719 0.242218017578125 +68720 0.094970703125 +68721 0.2257080078125 +68722 0.070556640625 +68723 0.194366455078125 +68724 0.026947021484375 +68725 0.115509033203125 +68726 -0.02520751953125 +68727 0.0128173828125 +68728 -0.06011962890625 +68729 -0.053802490234375 +68730 -0.088623046875 +68731 -0.110626220703125 +68732 -0.1282958984375 +68733 -0.199493408203125 +68734 -0.1680908203125 +68735 -0.29437255859375 +68736 -0.18133544921875 +68737 -0.33221435546875 +68738 -0.154144287109375 +68739 -0.27972412109375 +68740 -0.10736083984375 +68741 -0.185333251953125 +68742 -0.074981689453125 +68743 -0.128204345703125 +68744 -0.06060791015625 +68745 -0.115692138671875 +68746 -0.051483154296875 +68747 -0.116455078125 +68748 -0.0377197265625 +68749 -0.105926513671875 +68750 -0.007049560546875 +68751 -0.053955078125 +68752 0.044036865234375 +68753 0.048797607421875 +68754 0.0960693359375 +68755 0.157318115234375 +68756 0.123504638671875 +68757 0.212005615234375 +68758 0.1285400390625 +68759 0.218475341796875 +68760 0.13677978515625 +68761 0.23724365234375 +68762 0.163970947265625 +68763 0.30535888671875 +68764 0.192626953125 +68765 0.38128662109375 +68766 0.197296142578125 +68767 0.404449462890625 +68768 0.186614990234375 +68769 0.3944091796875 +68770 0.176849365234375 +68771 0.3885498046875 +68772 0.15814208984375 +68773 0.362640380859375 +68774 0.1126708984375 +68775 0.27362060546875 +68776 0.03900146484375 +68777 0.11712646484375 +68778 -0.040435791015625 +68779 -0.054901123046875 +68780 -0.103424072265625 +68781 -0.19085693359375 +68782 -0.1475830078125 +68783 -0.28570556640625 +68784 -0.17266845703125 +68785 -0.339263916015625 +68786 -0.189605712890625 +68787 -0.3775634765625 +68788 -0.217559814453125 +68789 -0.445709228515625 +68790 -0.252960205078125 +68791 -0.535064697265625 +68792 -0.2889404296875 +68793 -0.629058837890625 +68794 -0.31298828125 +68795 -0.697601318359375 +68796 -0.309814453125 +68797 -0.70391845703125 +68798 -0.27740478515625 +68799 -0.6424560546875 +68800 -0.20684814453125 +68801 -0.491241455078125 +68802 -0.10504150390625 +68803 -0.265716552734375 +68804 0.003143310546875 +68805 -0.023712158203125 +68806 0.103424072265625 +68807 0.201751708984375 +68808 0.1807861328125 +68809 0.375823974609375 +68810 0.2293701171875 +68811 0.485076904296875 +68812 0.26580810546875 +68813 0.56884765625 +68814 0.293304443359375 +68815 0.634765625 +68816 0.292755126953125 +68817 0.63763427734375 +68818 0.259490966796875 +68819 0.5660400390625 +68820 0.215728759765625 +68821 0.4720458984375 +68822 0.183441162109375 +68823 0.40692138671875 +68824 0.16595458984375 +68825 0.3778076171875 +68826 0.1602783203125 +68827 0.376953125 +68828 0.15301513671875 +68829 0.371978759765625 +68830 0.123321533203125 +68831 0.313140869140625 +68832 0.06463623046875 +68833 0.184417724609375 +68834 -0.01202392578125 +68835 0.011199951171875 +68836 -0.09149169921875 +68837 -0.171051025390625 +68838 -0.1630859375 +68839 -0.33740234375 +68840 -0.220062255859375 +68841 -0.47198486328125 +68842 -0.25634765625 +68843 -0.560394287109375 +68844 -0.2626953125 +68845 -0.58056640625 +68846 -0.245635986328125 +68847 -0.54754638671875 +68848 -0.22540283203125 +68849 -0.508575439453125 +68850 -0.200469970703125 +68851 -0.459503173828125 +68852 -0.16851806640625 +68853 -0.394378662109375 +68854 -0.146514892578125 +68855 -0.35260009765625 +68856 -0.1251220703125 +68857 -0.31170654296875 +68858 -0.073089599609375 +68859 -0.197418212890625 +68860 0.010101318359375 +68861 -0.007965087890625 +68862 0.103485107421875 +68863 0.207489013671875 +68864 0.1900634765625 +68865 0.409210205078125 +68866 0.25860595703125 +68867 0.57208251953125 +68868 0.296783447265625 +68869 0.66595458984375 +68870 0.29248046875 +68871 0.65875244140625 +68872 0.252838134765625 +68873 0.56744384765625 +68874 0.19378662109375 +68875 0.431396484375 +68876 0.133087158203125 +68877 0.29443359375 +68878 0.081451416015625 +68879 0.182464599609375 +68880 0.02691650390625 +68881 0.06365966796875 +68882 -0.035491943359375 +68883 -0.075958251953125 +68884 -0.086944580078125 +68885 -0.189422607421875 +68886 -0.12518310546875 +68887 -0.271942138671875 +68888 -0.157379150390625 +68889 -0.342529296875 +68890 -0.168853759765625 +68891 -0.364166259765625 +68892 -0.15576171875 +68893 -0.327239990234375 +68894 -0.135833740234375 +68895 -0.2769775390625 +68896 -0.12493896484375 +68897 -0.253692626953125 +68898 -0.117828369140625 +68899 -0.24365234375 +68900 -0.095733642578125 +68901 -0.1983642578125 +68902 -0.058319091796875 +68903 -0.116241455078125 +68904 -0.021392822265625 +68905 -0.036834716796875 +68906 0.012725830078125 +68907 0.034881591796875 +68908 0.040679931640625 +68909 0.09124755859375 +68910 0.053009033203125 +68911 0.10888671875 +68912 0.064239501953125 +68913 0.125518798828125 +68914 0.080596923828125 +68915 0.15771484375 +68916 0.09124755859375 +68917 0.17828369140625 +68918 0.089752197265625 +68919 0.17108154296875 +68920 0.07366943359375 +68921 0.129974365234375 +68922 0.0538330078125 +68923 0.082427978515625 +68924 0.030029296875 +68925 0.027679443359375 +68926 -0.00982666015625 +68927 -0.065643310546875 +68928 -0.050567626953125 +68929 -0.15936279296875 +68930 -0.076141357421875 +68931 -0.21307373046875 +68932 -0.089385986328125 +68933 -0.234649658203125 +68934 -0.080657958984375 +68935 -0.2001953125 +68936 -0.05340576171875 +68937 -0.119171142578125 +68938 -0.020416259765625 +68939 -0.024749755859375 +68940 0.01959228515625 +68941 0.085784912109375 +68942 0.053314208984375 +68943 0.178131103515625 +68944 0.06646728515625 +68945 0.215576171875 +68946 0.064361572265625 +68947 0.211456298828125 +68948 0.05072021484375 +68949 0.17523193359375 +68950 0.034027099609375 +68951 0.128753662109375 +68952 0.025909423828125 +68953 0.1019287109375 +68954 0.018218994140625 +68955 0.0743408203125 +68956 0.009674072265625 +68957 0.04327392578125 +68958 0.0115966796875 +68959 0.038177490234375 +68960 0.030517578125 +68961 0.076263427734375 +68962 0.05975341796875 +68963 0.14105224609375 +68964 0.081024169921875 +68965 0.186431884765625 +68966 0.08489990234375 +68967 0.188812255859375 +68968 0.067657470703125 +68969 0.1390380859375 +68970 0.031036376953125 +68971 0.041778564453125 +68972 -0.01580810546875 +68973 -0.079437255859375 +68974 -0.070831298828125 +68975 -0.219390869140625 +68976 -0.129974365234375 +68977 -0.367828369140625 +68978 -0.18145751953125 +68979 -0.494873046875 +68980 -0.207794189453125 +68981 -0.556243896484375 +68982 -0.19189453125 +68983 -0.508697509765625 +68984 -0.14276123046875 +68985 -0.3756103515625 +68986 -0.08453369140625 +68987 -0.218902587890625 +68988 -0.026885986328125 +68989 -0.063751220703125 +68990 0.030975341796875 +68991 0.091552734375 +68992 0.084930419921875 +68993 0.23602294921875 +68994 0.124664306640625 +68995 0.342987060546875 +68996 0.143524169921875 +68997 0.39520263671875 +68998 0.14031982421875 +68999 0.389373779296875 +69000 0.11456298828125 +69001 0.324249267578125 +69002 0.075775146484375 +69003 0.224090576171875 +69004 0.03778076171875 +69005 0.124267578125 +69006 0.005279541015625 +69007 0.037078857421875 +69008 -0.01104736328125 +69009 -0.010101318359375 +69010 -0.01220703125 +69011 -0.019439697265625 +69012 -0.01080322265625 +69013 -0.022796630859375 +69014 0.000244140625 +69015 -0.001556396484375 +69016 0.025482177734375 +69017 0.056304931640625 +69018 0.04754638671875 +69019 0.106719970703125 +69020 0.045623779296875 +69021 0.096893310546875 +69022 0.025848388671875 +69023 0.042694091796875 +69024 0.002960205078125 +69025 -0.018035888671875 +69026 -0.01934814453125 +69027 -0.07586669921875 +69028 -0.036651611328125 +69029 -0.11944580078125 +69030 -0.05322265625 +69031 -0.15972900390625 +69032 -0.0712890625 +69033 -0.202606201171875 +69034 -0.0909423828125 +69035 -0.24859619140625 +69036 -0.115020751953125 +69037 -0.30517578125 +69038 -0.139404296875 +69039 -0.36212158203125 +69040 -0.15301513671875 +69041 -0.39141845703125 +69042 -0.140899658203125 +69043 -0.35528564453125 +69044 -0.10150146484375 +69045 -0.249969482421875 +69046 -0.04156494140625 +69047 -0.092864990234375 +69048 0.0284423828125 +69049 0.08905029296875 +69050 0.0848388671875 +69051 0.2352294921875 +69052 0.11712646484375 +69053 0.318817138671875 +69054 0.1326904296875 +69055 0.358642578125 +69056 0.128814697265625 +69057 0.347747802734375 +69058 0.105255126953125 +69059 0.28564453125 +69060 0.081878662109375 +69061 0.223175048828125 +69062 0.072906494140625 +69063 0.196746826171875 +69064 0.06787109375 +69065 0.179840087890625 +69066 0.060028076171875 +69067 0.155548095703125 +69068 0.060028076171875 +69069 0.151214599609375 +69070 0.063873291015625 +69071 0.156951904296875 +69072 0.055419921875 +69073 0.13177490234375 +69074 0.044464111328125 +69075 0.100799560546875 +69076 0.03997802734375 +69077 0.087127685546875 +69078 0.027862548828125 +69079 0.05487060546875 +69080 0.00299072265625 +69081 -0.009002685546875 +69082 -0.034393310546875 +69083 -0.10400390625 +69084 -0.084014892578125 +69085 -0.229400634765625 +69086 -0.13421630859375 +69087 -0.35552978515625 +69088 -0.1690673828125 +69089 -0.441925048828125 +69090 -0.1827392578125 +69091 -0.473846435546875 +69092 -0.18048095703125 +69093 -0.464813232421875 +69094 -0.16387939453125 +69095 -0.419097900390625 +69096 -0.131927490234375 +69097 -0.334320068359375 +69098 -0.091400146484375 +69099 -0.227935791015625 +69100 -0.051483154296875 +69101 -0.12347412109375 +69102 -0.014739990234375 +69103 -0.02764892578125 +69104 0.025970458984375 +69105 0.077667236328125 +69106 0.078826904296875 +69107 0.2132568359375 +69108 0.14764404296875 +69109 0.38885498046875 +69110 0.223907470703125 +69111 0.582794189453125 +69112 0.283660888671875 +69113 0.734039306640625 +69114 0.31024169921875 +69115 0.800140380859375 +69116 0.302520751953125 +69117 0.7783203125 +69118 0.25909423828125 +69119 0.6651611328125 +69120 0.180023193359375 +69121 0.45965576171875 +69122 0.080474853515625 +69123 0.199188232421875 +69124 -0.01483154296875 +69125 -0.050689697265625 +69126 -0.085296630859375 +69127 -0.23297119140625 +69128 -0.12451171875 +69129 -0.33013916015625 +69130 -0.141845703125 +69131 -0.368408203125 +69132 -0.1484375 +69133 -0.378936767578125 +69134 -0.149749755859375 +69135 -0.376983642578125 +69136 -0.15191650390625 +69137 -0.37969970703125 +69138 -0.156494140625 +69139 -0.391510009765625 +69140 -0.153778076171875 +69141 -0.385345458984375 +69142 -0.136871337890625 +69143 -0.3419189453125 +69144 -0.113677978515625 +69145 -0.28289794921875 +69146 -0.09991455078125 +69147 -0.251617431640625 +69148 -0.10223388671875 +69149 -0.266143798828125 +69150 -0.1016845703125 +69151 -0.273345947265625 +69152 -0.078094482421875 +69153 -0.216796875 +69154 -0.043060302734375 +69155 -0.128265380859375 +69156 -0.01849365234375 +69157 -0.068145751953125 +69158 -0.006927490234375 +69159 -0.0430908203125 +69160 0.00177001953125 +69161 -0.024444580078125 +69162 0.0194091796875 +69163 0.020721435546875 +69164 0.05743408203125 +69165 0.124481201171875 +69166 0.10540771484375 +69167 0.25787353515625 +69168 0.1483154296875 +69169 0.379119873046875 +69170 0.1832275390625 +69171 0.47991943359375 +69172 0.198699951171875 +69173 0.5281982421875 +69174 0.19024658203125 +69175 0.511138916015625 +69176 0.16790771484375 +69177 0.456207275390625 +69178 0.147674560546875 +69179 0.407470703125 +69180 0.136474609375 +69181 0.383758544921875 +69182 0.124298095703125 +69183 0.35687255859375 +69184 0.105865478515625 +69185 0.31182861328125 +69186 0.08209228515625 +69187 0.250885009765625 +69188 0.04998779296875 +69189 0.1654052734375 +69190 0.002349853515625 +69191 0.035247802734375 +69192 -0.0616455078125 +69193 -0.142059326171875 +69194 -0.130889892578125 +69195 -0.33563232421875 +69196 -0.201507568359375 +69197 -0.5345458984375 +69198 -0.2674560546875 +69199 -0.72186279296875 +69200 -0.306915283203125 +69201 -0.836669921875 +69202 -0.30328369140625 +69203 -0.8326416015625 +69204 -0.26385498046875 +69205 -0.7296142578125 +69206 -0.20855712890625 +69207 -0.582550048828125 +69208 -0.155059814453125 +69209 -0.440093994140625 +69210 -0.111419677734375 +69211 -0.324310302734375 +69212 -0.0655517578125 +69213 -0.20147705078125 +69214 -0.007843017578125 +69215 -0.044647216796875 +69216 0.04644775390625 +69217 0.103973388671875 +69218 0.0821533203125 +69219 0.202392578125 +69220 0.104248046875 +69221 0.264495849609375 +69222 0.130279541015625 +69223 0.338897705078125 +69224 0.1668701171875 +69225 0.443817138671875 +69226 0.201812744140625 +69227 0.545074462890625 +69228 0.226043701171875 +69229 0.6173095703125 +69230 0.236785888671875 +69231 0.6524658203125 +69232 0.23876953125 +69233 0.66339111328125 +69234 0.234283447265625 +69235 0.6561279296875 +69236 0.21478271484375 +69237 0.606781005859375 +69238 0.175262451171875 +69239 0.501190185546875 +69240 0.120635986328125 +69241 0.352783203125 +69242 0.056365966796875 +69243 0.176544189453125 +69244 -0.020111083984375 +69245 -0.034820556640625 +69246 -0.1004638671875 +69247 -0.258209228515625 +69248 -0.166290283203125 +69249 -0.44244384765625 +69250 -0.21319580078125 +69251 -0.5753173828125 +69252 -0.23956298828125 +69253 -0.65203857421875 +69254 -0.23431396484375 +69255 -0.641632080078125 +69256 -0.204071044921875 +69257 -0.562164306640625 +69258 -0.164886474609375 +69259 -0.458038330078125 +69260 -0.12451171875 +69261 -0.350555419921875 +69262 -0.090545654296875 +69263 -0.260528564453125 +69264 -0.064544677734375 +69265 -0.192108154296875 +69266 -0.045379638671875 +69267 -0.141937255859375 +69268 -0.0302734375 +69269 -0.1021728515625 +69270 -0.015716552734375 +69271 -0.062896728515625 +69272 0.002655029296875 +69273 -0.011932373046875 +69274 0.02923583984375 +69275 0.062835693359375 +69276 0.059478759765625 +69277 0.148712158203125 +69278 0.09197998046875 +69279 0.241729736328125 +69280 0.12939453125 +69281 0.34912109375 +69282 0.16693115234375 +69283 0.457305908203125 +69284 0.19659423828125 +69285 0.54388427734375 +69286 0.205535888671875 +69287 0.5728759765625 +69288 0.180267333984375 +69289 0.506591796875 +69290 0.123077392578125 +69291 0.351226806640625 +69292 0.04833984375 +69293 0.146514892578125 +69294 -0.025054931640625 +69295 -0.05523681640625 +69296 -0.08343505859375 +69297 -0.21624755859375 +69298 -0.126251220703125 +69299 -0.334930419921875 +69300 -0.150482177734375 +69301 -0.402984619140625 +69302 -0.163665771484375 +69303 -0.4412841796875 +69304 -0.182403564453125 +69305 -0.49578857421875 +69306 -0.2044677734375 +69307 -0.5601806640625 +69308 -0.217803955078125 +69309 -0.600738525390625 +69310 -0.210540771484375 +69311 -0.584228515625 +69312 -0.17144775390625 +69313 -0.47930908203125 +69314 -0.098236083984375 +69315 -0.27935791015625 +69316 0.00018310546875 +69317 -0.0089111328125 +69318 0.100982666015625 +69319 0.268798828125 +69320 0.1785888671875 +69321 0.482818603515625 +69322 0.222381591796875 +69323 0.60369873046875 +69324 0.239166259765625 +69325 0.650421142578125 +69326 0.243743896484375 +69327 0.66400146484375 +69328 0.235076904296875 +69329 0.6414794921875 +69330 0.20947265625 +69331 0.572540283203125 +69332 0.1817626953125 +69333 0.498138427734375 +69334 0.159637451171875 +69335 0.439453125 +69336 0.135589599609375 +69337 0.375518798828125 +69338 0.09820556640625 +69339 0.274505615234375 +69340 0.03759765625 +69341 0.1087646484375 +69342 -0.03814697265625 +69343 -0.099395751953125 +69344 -0.1175537109375 +69345 -0.3182373046875 +69346 -0.2010498046875 +69347 -0.5489501953125 +69348 -0.282196044921875 +69349 -0.7738037109375 +69350 -0.341949462890625 +69351 -0.86383056640625 +69352 -0.36834716796875 +69353 -0.870391845703125 +69354 -0.367767333984375 +69355 -0.86895751953125 +69356 -0.345001220703125 +69357 -0.861053466796875 +69358 -0.293853759765625 +69359 -0.765869140625 +69360 -0.210296630859375 +69361 -0.5301513671875 +69362 -0.096923828125 +69363 -0.214691162109375 +69364 0.03070068359375 +69365 0.137359619140625 +69366 0.154052734375 +69367 0.474822998046875 +69368 0.26031494140625 +69369 0.76239013671875 +69370 0.3397216796875 +69371 0.867462158203125 +69372 0.392425537109375 +69373 0.870361328125 +69374 0.414215087890625 +69375 0.86480712890625 +69376 0.4068603515625 +69377 0.831817626953125 +69378 0.3790283203125 +69379 0.677581787109375 +69380 0.332916259765625 +69381 0.495880126953125 +69382 0.27496337890625 +69383 0.30767822265625 +69384 0.206329345703125 +69385 0.116180419921875 +69386 0.1170654296875 +69387 -0.110748291015625 +69388 0.005401611328125 +69389 -0.381805419921875 +69390 -0.114105224609375 +69391 -0.6572265625 +69392 -0.22137451171875 +69393 -0.857421875 +69394 -0.301910400390625 +69395 -0.870391845703125 +69396 -0.35308837890625 +69397 -0.870391845703125 +69398 -0.383514404296875 +69399 -0.86444091796875 +69400 -0.40472412109375 +69401 -0.85723876953125 +69402 -0.41070556640625 +69403 -0.790008544921875 +69404 -0.38372802734375 +69405 -0.62847900390625 +69406 -0.322906494140625 +69407 -0.3956298828125 +69408 -0.2392578125 +69409 -0.126708984375 +69410 -0.14208984375 +69411 0.150115966796875 +69412 -0.035614013671875 +69413 0.424041748046875 +69414 0.0709228515625 +69415 0.670623779296875 +69416 0.1644287109375 +69417 0.854522705078125 +69418 0.238739013671875 +69419 0.866485595703125 +69420 0.288482666015625 +69421 0.86920166015625 +69422 0.319305419921875 +69423 0.8653564453125 +69424 0.33538818359375 +69425 0.857147216796875 +69426 0.33563232421875 +69427 0.766845703125 +69428 0.3216552734375 +69429 0.628509521484375 +69430 0.291259765625 +69431 0.462127685546875 +69432 0.2530517578125 +69433 0.297210693359375 +69434 0.21124267578125 +69435 0.14862060546875 +69436 0.158599853515625 +69437 -0.00537109375 +69438 0.097869873046875 +69439 -0.15753173828125 +69440 0.028167724609375 +69441 -0.31304931640625 +69442 -0.05474853515625 +69443 -0.48876953125 +69444 -0.135162353515625 +69445 -0.6416015625 +69446 -0.20465087890625 +69447 -0.751373291015625 +69448 -0.270538330078125 +69449 -0.84619140625 +69450 -0.3277587890625 +69451 -0.861297607421875 +69452 -0.365325927734375 +69453 -0.863250732421875 +69454 -0.372802734375 +69455 -0.856597900390625 +69456 -0.354156494140625 +69457 -0.7498779296875 +69458 -0.328460693359375 +69459 -0.624542236328125 +69460 -0.28863525390625 +69461 -0.47808837890625 +69462 -0.2156982421875 +69463 -0.253387451171875 +69464 -0.124847412109375 +69465 0.003692626953125 +69466 -0.038787841796875 +69467 0.2257080078125 +69468 0.046295166015625 +69469 0.427154541015625 +69470 0.1407470703125 +69471 0.643218994140625 +69472 0.241119384765625 +69473 0.855926513671875 +69474 0.328155517578125 +69475 0.870361328125 +69476 0.385406494140625 +69477 0.870361328125 +69478 0.415069580078125 +69479 0.862762451171875 +69480 0.4161376953125 +69481 0.79669189453125 +69482 0.385467529296875 +69483 0.595794677734375 +69484 0.332672119140625 +69485 0.362152099609375 +69486 0.26708984375 +69487 0.1270751953125 +69488 0.19580078125 +69489 -0.086944580078125 +69490 0.11968994140625 +69491 -0.2784423828125 +69492 0.027587890625 +69493 -0.484832763671875 +69494 -0.0865478515625 +69495 -0.729583740234375 +69496 -0.205902099609375 +69497 -0.86688232421875 +69498 -0.309417724609375 +69499 -0.870391845703125 +69500 -0.395263671875 +69501 -0.86859130859375 +69502 -0.4625244140625 +69503 -0.86279296875 +69504 -0.499298095703125 +69505 -0.817962646484375 +69506 -0.490570068359375 +69507 -0.6116943359375 +69508 -0.4339599609375 +69509 -0.3128662109375 +69510 -0.340545654296875 +69511 0.039398193359375 +69512 -0.21697998046875 +69513 0.422821044921875 +69514 -0.074310302734375 +69515 0.805145263671875 +69516 0.06494140625 +69517 0.870361328125 +69518 0.18182373046875 +69519 0.870361328125 +69520 0.27227783203125 +69521 0.860015869140625 +69522 0.33349609375 +69523 0.727935791015625 +69524 0.363311767578125 +69525 0.48114013671875 +69526 0.369415283203125 +69527 0.2059326171875 +69528 0.3590087890625 +69529 -0.06103515625 +69530 0.335174560546875 +69531 -0.29913330078125 +69532 0.29302978515625 +69533 -0.516204833984375 +69534 0.227508544921875 +69535 -0.7252197265625 +69536 0.14678955078125 +69537 -0.85980224609375 +69538 0.062255859375 +69539 -0.870391845703125 +69540 -0.01617431640625 +69541 -0.870391845703125 +69542 -0.072296142578125 +69543 -0.858062744140625 +69544 -0.10443115234375 +69545 -0.673004150390625 +69546 -0.1295166015625 +69547 -0.42694091796875 +69548 -0.161712646484375 +69549 -0.2100830078125 +69550 -0.199981689453125 +69551 -0.0362548828125 +69552 -0.234466552734375 +69553 0.10943603515625 +69554 -0.25836181640625 +69555 0.23516845703125 +69556 -0.25787353515625 +69557 0.373687744140625 +69558 -0.233489990234375 +69559 0.517791748046875 +69560 -0.205810546875 +69561 0.602783203125 +69562 -0.17315673828125 +69563 0.635711669921875 +69564 -0.12469482421875 +69565 0.655181884765625 +69566 -0.063873291015625 +69567 0.65948486328125 +69568 0.00640869140625 +69569 0.651275634765625 +69570 0.07781982421875 +69571 0.61846923828125 +69572 0.13787841796875 +69573 0.53753662109375 +69574 0.180328369140625 +69575 0.404144287109375 +69576 0.201629638671875 +69577 0.22186279296875 +69578 0.201934814453125 +69579 0.003997802734375 +69580 0.1868896484375 +69581 -0.22100830078125 +69582 0.1630859375 +69583 -0.42449951171875 +69584 0.137359619140625 +69585 -0.579833984375 +69586 0.123626708984375 +69587 -0.641876220703125 +69588 0.1197509765625 +69589 -0.6177978515625 +69590 0.104583740234375 +69591 -0.575531005859375 +69592 0.0765380859375 +69593 -0.526336669921875 +69594 0.05279541015625 +69595 -0.42645263671875 +69596 0.042572021484375 +69597 -0.2581787109375 +69598 0.03424072265625 +69599 -0.068695068359375 +69600 0.015472412109375 +69601 0.09222412109375 +69602 -0.00732421875 +69603 0.232147216796875 +69604 -0.030487060546875 +69605 0.3509521484375 +69606 -0.0634765625 +69607 0.410064697265625 +69608 -0.11566162109375 +69609 0.372955322265625 +69610 -0.180023193359375 +69611 0.2554931640625 +69612 -0.2393798828125 +69613 0.10711669921875 +69614 -0.2872314453125 +69615 -0.052886962890625 +69616 -0.311737060546875 +69617 -0.186279296875 +69618 -0.294647216796875 +69619 -0.23291015625 +69620 -0.24359130859375 +69621 -0.209442138671875 +69622 -0.180328369140625 +69623 -0.174163818359375 +69624 -0.10784912109375 +69625 -0.126739501953125 +69626 -0.023162841796875 +69627 -0.048126220703125 +69628 0.064178466796875 +69629 0.0426025390625 +69630 0.138671875 +69631 0.10748291015625 +69632 0.195220947265625 +69633 0.1409912109375 +69634 0.24847412109375 +69635 0.19708251953125 +69636 0.29681396484375 +69637 0.273651123046875 +69638 0.32318115234375 +69639 0.31768798828125 +69640 0.330718994140625 +69641 0.341094970703125 +69642 0.326934814453125 +69643 0.368011474609375 +69644 0.30499267578125 +69645 0.37249755859375 +69646 0.250335693359375 +69647 0.30072021484375 +69648 0.16473388671875 +69649 0.1517333984375 +69650 0.06854248046875 +69651 -0.01470947265625 +69652 -0.032470703125 +69653 -0.1883544921875 +69654 -0.136627197265625 +69655 -0.372711181640625 +69656 -0.225128173828125 +69657 -0.51397705078125 +69658 -0.28338623046875 +69659 -0.57177734375 +69660 -0.307342529296875 +69661 -0.53948974609375 +69662 -0.30078125 +69663 -0.43511962890625 +69664 -0.27386474609375 +69665 -0.2962646484375 +69666 -0.237548828125 +69667 -0.161102294921875 +69668 -0.196075439453125 +69669 -0.0435791015625 +69670 -0.148834228515625 +69671 0.060394287109375 +69672 -0.10125732421875 +69673 0.13665771484375 +69674 -0.0594482421875 +69675 0.170135498046875 +69676 -0.023895263671875 +69677 0.16552734375 +69678 0.013519287109375 +69679 0.15728759765625 +69680 0.052154541015625 +69681 0.150787353515625 +69682 0.082550048828125 +69683 0.12200927734375 +69684 0.105377197265625 +69685 0.080108642578125 +69686 0.126678466796875 +69687 0.05126953125 +69688 0.153228759765625 +69689 0.062896728515625 +69690 0.17724609375 +69691 0.09271240234375 +69692 0.183807373046875 +69693 0.092987060546875 +69694 0.177276611328125 +69695 0.07855224609375 +69696 0.1624755859375 +69697 0.06427001953125 +69698 0.135589599609375 +69699 0.0347900390625 +69700 0.0972900390625 +69701 -0.01171875 +69702 0.054840087890625 +69703 -0.056060791015625 +69704 0.022796630859375 +69705 -0.055511474609375 +69706 0.00286865234375 +69707 -0.010467529296875 +69708 -0.01922607421875 +69709 0.02508544921875 +69710 -0.04937744140625 +69711 0.025665283203125 +69712 -0.07818603515625 +69713 0.017333984375 +69714 -0.103790283203125 +69715 0.00189208984375 +69716 -0.1285400390625 +69717 -0.03173828125 +69718 -0.148223876953125 +69719 -0.071502685546875 +69720 -0.167999267578125 +69721 -0.13543701171875 +69722 -0.186981201171875 +69723 -0.219970703125 +69724 -0.19830322265625 +69725 -0.300506591796875 +69726 -0.20263671875 +69727 -0.376312255859375 +69728 -0.1917724609375 +69729 -0.416107177734375 +69730 -0.152435302734375 +69731 -0.371124267578125 +69732 -0.08642578125 +69733 -0.242279052734375 +69734 -0.007293701171875 +69735 -0.069732666015625 +69736 0.0771484375 +69737 0.125640869140625 +69738 0.15618896484375 +69739 0.31268310546875 +69740 0.217742919921875 +69741 0.45501708984375 +69742 0.26153564453125 +69743 0.554779052734375 +69744 0.286590576171875 +69745 0.61065673828125 +69746 0.2890625 +69747 0.610931396484375 +69748 0.261810302734375 +69749 0.531463623046875 +69750 0.209991455078125 +69751 0.3883056640625 +69752 0.15020751953125 +69753 0.23468017578125 +69754 0.09075927734375 +69755 0.095245361328125 +69756 0.040496826171875 +69757 -0.00396728515625 +69758 0.004913330078125 +69759 -0.04852294921875 +69760 -0.01971435546875 +69761 -0.055145263671875 +69762 -0.0477294921875 +69763 -0.0758056640625 +69764 -0.086395263671875 +69765 -0.138702392578125 +69766 -0.12432861328125 +69767 -0.209197998046875 +69768 -0.16119384765625 +69769 -0.289031982421875 +69770 -0.196624755859375 +69771 -0.37884521484375 +69772 -0.223541259765625 +69773 -0.456329345703125 +69774 -0.24041748046875 +69775 -0.51641845703125 +69776 -0.2354736328125 +69777 -0.519287109375 +69778 -0.2071533203125 +69779 -0.458251953125 +69780 -0.17156982421875 +69781 -0.384796142578125 +69782 -0.136993408203125 +69783 -0.323699951171875 +69784 -0.102691650390625 +69785 -0.269287109375 +69786 -0.061767578125 +69787 -0.1951904296875 +69788 -0.014862060546875 +69789 -0.100006103515625 +69790 0.028961181640625 +69791 -0.01055908203125 +69792 0.077911376953125 +69793 0.1033935546875 +69794 0.133392333984375 +69795 0.24908447265625 +69796 0.178863525390625 +69797 0.373199462890625 +69798 0.20867919921875 +69799 0.45806884765625 +69800 0.225006103515625 +69801 0.511474609375 +69802 0.237579345703125 +69803 0.565399169921875 +69804 0.244171142578125 +69805 0.61138916015625 +69806 0.22735595703125 +69807 0.5897216796875 +69808 0.184844970703125 +69809 0.4906005859375 +69810 0.122650146484375 +69811 0.33148193359375 +69812 0.05224609375 +69813 0.147796630859375 +69814 -0.01300048828125 +69815 -0.01873779296875 +69816 -0.063873291015625 +69817 -0.140289306640625 +69818 -0.092193603515625 +69819 -0.191986083984375 +69820 -0.100433349609375 +69821 -0.184295654296875 +69822 -0.101470947265625 +69823 -0.161834716796875 +69824 -0.1075439453125 +69825 -0.166595458984375 +69826 -0.1170654296875 +69827 -0.19390869140625 +69828 -0.124298095703125 +69829 -0.22442626953125 +69830 -0.1358642578125 +69831 -0.279754638671875 +69832 -0.145904541015625 +69833 -0.3389892578125 +69834 -0.140594482421875 +69835 -0.3543701171875 +69836 -0.127197265625 +69837 -0.348175048828125 +69838 -0.10809326171875 +69839 -0.32598876953125 +69840 -0.0750732421875 +69841 -0.2581787109375 +69842 -0.027374267578125 +69843 -0.139801025390625 +69844 0.029998779296875 +69845 0.014617919921875 +69846 0.0782470703125 +69847 0.144378662109375 +69848 0.1083984375 +69849 0.221038818359375 +69850 0.127960205078125 +69851 0.27069091796875 +69852 0.136962890625 +69853 0.294036865234375 +69854 0.141571044921875 +69855 0.311767578125 +69856 0.146453857421875 +69857 0.339141845703125 +69858 0.147064208984375 +69859 0.360260009765625 +69860 0.139404296875 +69861 0.360504150390625 +69862 0.1146240234375 +69863 0.308380126953125 +69864 0.066741943359375 +69865 0.18170166015625 +69866 0.00360107421875 +69867 0.0047607421875 +69868 -0.060333251953125 +69869 -0.17559814453125 +69870 -0.11114501953125 +69871 -0.3143310546875 +69872 -0.13543701171875 +69873 -0.36785888671875 +69874 -0.140594482421875 +69875 -0.36248779296875 +69876 -0.139678955078125 +69877 -0.343536376953125 +69878 -0.12982177734375 +69879 -0.3018798828125 +69880 -0.109130859375 +69881 -0.231414794921875 +69882 -0.073394775390625 +69883 -0.117645263671875 +69884 -0.032379150390625 +69885 0.007049560546875 +69886 -0.0025634765625 +69887 0.087982177734375 +69888 0.01995849609375 +69889 0.13946533203125 +69890 0.03851318359375 +69891 0.17425537109375 +69892 0.051361083984375 +69893 0.188201904296875 +69894 0.055450439453125 +69895 0.171234130859375 +69896 0.049163818359375 +69897 0.118438720703125 +69898 0.039398193359375 +69899 0.05706787109375 +69900 0.02642822265625 +69901 -0.010711669921875 +69902 0.00836181640625 +69903 -0.0914306640625 +69904 -0.008880615234375 +69905 -0.162322998046875 +69906 -0.017730712890625 +69907 -0.194549560546875 +69908 -0.00787353515625 +69909 -0.1492919921875 +69910 0.022125244140625 +69911 -0.02166748046875 +69912 0.0555419921875 +69913 0.124053955078125 +69914 0.0723876953125 +69915 0.211151123046875 +69916 0.073272705078125 +69917 0.240447998046875 +69918 0.06658935546875 +69919 0.242218017578125 +69920 0.05517578125 +69921 0.2257080078125 +69922 0.040313720703125 +69923 0.194366455078125 +69924 0.013671875 +69925 0.115509033203125 +69926 -0.018096923828125 +69927 0.0128173828125 +69928 -0.03900146484375 +69929 -0.053802490234375 +69930 -0.05584716796875 +69931 -0.110626220703125 +69932 -0.079620361328125 +69933 -0.199493408203125 +69934 -0.103485107421875 +69935 -0.29437255859375 +69936 -0.11090087890625 +69937 -0.33221435546875 +69938 -0.093292236328125 +69939 -0.27972412109375 +69940 -0.06365966796875 +69941 -0.185333251953125 +69942 -0.043182373046875 +69943 -0.128204345703125 +69944 -0.034088134765625 +69945 -0.115692138671875 +69946 -0.0284423828125 +69947 -0.116455078125 +69948 -0.020111083984375 +69949 -0.105926513671875 +69950 -0.00140380859375 +69951 -0.053955078125 +69952 0.029876708984375 +69953 0.048797607421875 +69954 0.061614990234375 +69955 0.157318115234375 +69956 0.077972412109375 +69957 0.212005615234375 +69958 0.080322265625 +69959 0.218475341796875 +69960 0.08465576171875 +69961 0.23724365234375 +69962 0.100830078125 +69963 0.30535888671875 +69964 0.118011474609375 +69965 0.38128662109375 +69966 0.120361328125 +69967 0.404449462890625 +69968 0.11328125 +69969 0.3944091796875 +69970 0.10693359375 +69971 0.3885498046875 +69972 0.09521484375 +69973 0.362640380859375 +69974 0.0670166015625 +69975 0.27362060546875 +69976 0.021453857421875 +69977 0.11712646484375 +69978 -0.027557373046875 +69979 -0.054901123046875 +69980 -0.06622314453125 +69981 -0.19085693359375 +69982 -0.093048095703125 +69983 -0.28570556640625 +69984 -0.107940673828125 +69985 -0.339263916015625 +69986 -0.11773681640625 +69987 -0.3775634765625 +69988 -0.134429931640625 +69989 -0.445709228515625 +69990 -0.15582275390625 +69991 -0.535064697265625 +69992 -0.177703857421875 +69993 -0.629058837890625 +69994 -0.1922607421875 +69995 -0.697601318359375 +69996 -0.19000244140625 +69997 -0.70391845703125 +69998 -0.169708251953125 +69999 -0.6424560546875 +70000 -0.12579345703125 +70001 -0.491241455078125 +70002 -0.06256103515625 +70003 -0.265716552734375 +70004 0.004486083984375 +70005 -0.023712158203125 +70006 0.066497802734375 +70007 0.201751708984375 +70008 0.1141357421875 +70009 0.375823974609375 +70010 0.143798828125 +70011 0.485076904296875 +70012 0.16583251953125 +70013 0.56884765625 +70014 0.182281494140625 +70015 0.634765625 +70016 0.181304931640625 +70017 0.63763427734375 +70018 0.160003662109375 +70019 0.5660400390625 +70020 0.132293701171875 +70021 0.4720458984375 +70022 0.11187744140625 +70023 0.40692138671875 +70024 0.100799560546875 +70025 0.3778076171875 +70026 0.09722900390625 +70027 0.376953125 +70028 0.092803955078125 +70029 0.371978759765625 +70030 0.07452392578125 +70031 0.313140869140625 +70032 0.038330078125 +70033 0.184417724609375 +70034 -0.00897216796875 +70035 0.011199951171875 +70036 -0.05792236328125 +70037 -0.171051025390625 +70038 -0.1019287109375 +70039 -0.33740234375 +70040 -0.136810302734375 +70041 -0.47198486328125 +70042 -0.1588134765625 +70043 -0.560394287109375 +70044 -0.1622314453125 +70045 -0.58056640625 +70046 -0.151153564453125 +70047 -0.54754638671875 +70048 -0.138214111328125 +70049 -0.508575439453125 +70050 -0.1224365234375 +70051 -0.459503173828125 +70052 -0.1024169921875 +70053 -0.394378662109375 +70054 -0.08868408203125 +70055 -0.35260009765625 +70056 -0.075469970703125 +70057 -0.31170654296875 +70058 -0.043304443359375 +70059 -0.197418212890625 +70060 0.008148193359375 +70061 -0.007965087890625 +70062 0.065826416015625 +70063 0.207489013671875 +70064 0.119232177734375 +70065 0.409210205078125 +70066 0.1617431640625 +70067 0.57208251953125 +70068 0.185455322265625 +70069 0.66595458984375 +70070 0.1820068359375 +70071 0.65875244140625 +70072 0.15594482421875 +70073 0.56744384765625 +70074 0.1177978515625 +70075 0.431396484375 +70076 0.07928466796875 +70077 0.29443359375 +70078 0.047332763671875 +70079 0.182464599609375 +70080 0.013702392578125 +70081 0.06365966796875 +70082 -0.025177001953125 +70083 -0.075958251953125 +70084 -0.056793212890625 +70085 -0.189422607421875 +70086 -0.07977294921875 +70087 -0.271942138671875 +70088 -0.099090576171875 +70089 -0.342529296875 +70090 -0.105010986328125 +70091 -0.364166259765625 +70092 -0.094970703125 +70093 -0.327239990234375 +70094 -0.0809326171875 +70095 -0.2769775390625 +70096 -0.0736083984375 +70097 -0.253692626953125 +70098 -0.069427490234375 +70099 -0.24365234375 +70100 -0.055694580078125 +70101 -0.1983642578125 +70102 -0.032073974609375 +70103 -0.116241455078125 +70104 -0.009124755859375 +70105 -0.036834716796875 +70106 0.011688232421875 +70107 0.034881591796875 +70108 0.02825927734375 +70109 0.09124755859375 +70110 0.034332275390625 +70111 0.10888671875 +70112 0.039794921875 +70113 0.125518798828125 +70114 0.048980712890625 +70115 0.15771484375 +70116 0.054656982421875 +70117 0.17828369140625 +70118 0.052581787109375 +70119 0.17108154296875 +70120 0.041168212890625 +70121 0.129974365234375 +70122 0.027679443359375 +70123 0.082427978515625 +70124 0.011993408203125 +70125 0.027679443359375 +70126 -0.014068603515625 +70127 -0.065643310546875 +70128 -0.04034423828125 +70129 -0.15936279296875 +70130 -0.056060791015625 +70131 -0.21307373046875 +70132 -0.063262939453125 +70133 -0.234649658203125 +70134 -0.0555419921875 +70135 -0.2001953125 +70136 -0.035308837890625 +70137 -0.119171142578125 +70138 -0.01129150390625 +70139 -0.024749755859375 +70140 0.01727294921875 +70141 0.085784912109375 +70142 0.04132080078125 +70143 0.178131103515625 +70144 0.0513916015625 +70145 0.215576171875 +70146 0.0511474609375 +70147 0.211456298828125 +70148 0.043212890625 +70149 0.17523193359375 +70150 0.032684326171875 +70151 0.128753662109375 +70152 0.026519775390625 +70153 0.1019287109375 +70154 0.020050048828125 +70155 0.0743408203125 +70156 0.01263427734375 +70157 0.04327392578125 +70158 0.0111083984375 +70159 0.038177490234375 +70160 0.01953125 +70161 0.076263427734375 +70162 0.0340576171875 +70163 0.14105224609375 +70164 0.044036865234375 +70165 0.186431884765625 +70166 0.044036865234375 +70167 0.188812255859375 +70168 0.03192138671875 +70169 0.1390380859375 +70170 0.00885009765625 +70171 0.041778564453125 +70172 -0.019683837890625 +70173 -0.079437255859375 +70174 -0.052459716796875 +70175 -0.219390869140625 +70176 -0.0870361328125 +70177 -0.367828369140625 +70178 -0.116485595703125 +70179 -0.494873046875 +70180 -0.130584716796875 +70181 -0.556243896484375 +70182 -0.11932373046875 +70183 -0.508697509765625 +70184 -0.088104248046875 +70185 -0.3756103515625 +70186 -0.051361083984375 +70187 -0.218902587890625 +70188 -0.01495361328125 +70189 -0.063751220703125 +70190 0.021453857421875 +70191 0.091552734375 +70192 0.055328369140625 +70193 0.23602294921875 +70194 0.0804443359375 +70195 0.342987060546875 +70196 0.092803955078125 +70197 0.39520263671875 +70198 0.09161376953125 +70199 0.389373779296875 +70200 0.07659912109375 +70201 0.324249267578125 +70202 0.05340576171875 +70203 0.224090576171875 +70204 0.03021240234375 +70205 0.124267578125 +70206 0.0098876953125 +70207 0.037078857421875 +70208 -0.001190185546875 +70209 -0.010101318359375 +70210 -0.003509521484375 +70211 -0.019439697265625 +70212 -0.004486083984375 +70213 -0.022796630859375 +70214 0.000213623046875 +70215 -0.001556396484375 +70216 0.01336669921875 +70217 0.056304931640625 +70218 0.024749755859375 +70219 0.106719970703125 +70220 0.02215576171875 +70221 0.096893310546875 +70222 0.00927734375 +70223 0.042694091796875 +70224 -0.005035400390625 +70225 -0.018035888671875 +70226 -0.01861572265625 +70227 -0.07586669921875 +70228 -0.02880859375 +70229 -0.11944580078125 +70230 -0.03814697265625 +70231 -0.15972900390625 +70232 -0.048004150390625 +70233 -0.202606201171875 +70234 -0.0584716796875 +70235 -0.24859619140625 +70236 -0.071319580078125 +70237 -0.30517578125 +70238 -0.084197998046875 +70239 -0.36212158203125 +70240 -0.09063720703125 +70241 -0.39141845703125 +70242 -0.081878662109375 +70243 -0.35528564453125 +70244 -0.057098388671875 +70245 -0.249969482421875 +70246 -0.02032470703125 +70247 -0.092864990234375 +70248 0.0220947265625 +70249 0.08905029296875 +70250 0.056121826171875 +70251 0.2352294921875 +70252 0.0755615234375 +70253 0.318817138671875 +70254 0.084747314453125 +70255 0.358642578125 +70256 0.08209228515625 +70257 0.347747802734375 +70258 0.0675048828125 +70259 0.28564453125 +70260 0.052764892578125 +70261 0.223175048828125 +70262 0.046356201171875 +70263 0.196746826171875 +70264 0.0421142578125 +70265 0.179840087890625 +70266 0.0361328125 +70267 0.155548095703125 +70268 0.0347900390625 +70269 0.151214599609375 +70270 0.035797119140625 +70271 0.156951904296875 +70272 0.0296630859375 +70273 0.13177490234375 +70274 0.022247314453125 +70275 0.100799560546875 +70276 0.0189208984375 +70277 0.087127685546875 +70278 0.0113525390625 +70279 0.05487060546875 +70280 -0.003448486328125 +70281 -0.009002685546875 +70282 -0.025390625 +70283 -0.10400390625 +70284 -0.054290771484375 +70285 -0.229400634765625 +70286 -0.083282470703125 +70287 -0.35552978515625 +70288 -0.102996826171875 +70289 -0.441925048828125 +70290 -0.110015869140625 +70291 -0.473846435546875 +70292 -0.107513427734375 +70293 -0.464813232421875 +70294 -0.096527099609375 +70295 -0.419097900390625 +70296 -0.076507568359375 +70297 -0.334320068359375 +70298 -0.051513671875 +70299 -0.227935791015625 +70300 -0.02703857421875 +70301 -0.12347412109375 +70302 -0.004638671875 +70303 -0.02764892578125 +70304 0.019866943359375 +70305 0.077667236328125 +70306 0.051300048828125 +70307 0.2132568359375 +70308 0.0919189453125 +70309 0.38885498046875 +70310 0.13671875 +70311 0.582794189453125 +70312 0.171539306640625 +70313 0.734039306640625 +70314 0.1865234375 +70315 0.800140380859375 +70316 0.181060791015625 +70317 0.7783203125 +70318 0.154388427734375 +70319 0.6651611328125 +70320 0.1063232421875 +70321 0.45965576171875 +70322 0.0455322265625 +70323 0.199188232421875 +70324 -0.012725830078125 +70325 -0.050689697265625 +70326 -0.055206298828125 +70327 -0.23297119140625 +70328 -0.077850341796875 +70329 -0.33013916015625 +70330 -0.08673095703125 +70331 -0.368408203125 +70332 -0.089080810546875 +70333 -0.378936767578125 +70334 -0.088470458984375 +70335 -0.376983642578125 +70336 -0.0888671875 +70337 -0.37969970703125 +70338 -0.09130859375 +70339 -0.391510009765625 +70340 -0.089569091796875 +70341 -0.385345458984375 +70342 -0.07916259765625 +70343 -0.3419189453125 +70344 -0.06512451171875 +70345 -0.28289794921875 +70346 -0.057525634765625 +70347 -0.251617431640625 +70348 -0.060577392578125 +70349 -0.266143798828125 +70350 -0.061981201171875 +70351 -0.273345947265625 +70352 -0.048675537109375 +70353 -0.216796875 +70354 -0.027984619140625 +70355 -0.128265380859375 +70356 -0.013946533203125 +70357 -0.068145751953125 +70358 -0.008087158203125 +70359 -0.0430908203125 +70360 -0.0037841796875 +70361 -0.024444580078125 +70362 0.006561279296875 +70363 0.020721435546875 +70364 0.0303955078125 +70365 0.124481201171875 +70366 0.06103515625 +70367 0.25787353515625 +70368 0.08880615234375 +70369 0.379119873046875 +70370 0.111785888671875 +70371 0.47991943359375 +70372 0.12255859375 +70373 0.5281982421875 +70374 0.118194580078125 +70375 0.511138916015625 +70376 0.105072021484375 +70377 0.456207275390625 +70378 0.093414306640625 +70379 0.407470703125 +70380 0.087615966796875 +70381 0.383758544921875 +70382 0.081146240234375 +70383 0.35687255859375 +70384 0.070556640625 +70385 0.31182861328125 +70386 0.056365966796875 +70387 0.250885009765625 +70388 0.03656005859375 +70389 0.1654052734375 +70390 0.006500244140625 +70391 0.035247802734375 +70392 -0.034393310546875 +70393 -0.142059326171875 +70394 -0.0789794921875 +70395 -0.33563232421875 +70396 -0.124725341796875 +70397 -0.5345458984375 +70398 -0.167724609375 +70399 -0.72186279296875 +70400 -0.1943359375 +70401 -0.836669921875 +70402 -0.194488525390625 +70403 -0.8326416015625 +70404 -0.172210693359375 +70405 -0.7296142578125 +70406 -0.138946533203125 +70407 -0.582550048828125 +70408 -0.105010986328125 +70409 -0.440093994140625 +70410 -0.0753173828125 +70411 -0.324310302734375 +70412 -0.043670654296875 +70413 -0.20147705078125 +70414 -0.00518798828125 +70415 -0.044647216796875 +70416 0.03118896484375 +70417 0.103973388671875 +70418 0.056671142578125 +70419 0.202392578125 +70420 0.073699951171875 +70421 0.264495849609375 +70422 0.091796875 +70423 0.338897705078125 +70424 0.114471435546875 +70425 0.443817138671875 +70426 0.134857177734375 +70427 0.545074462890625 +70428 0.14794921875 +70429 0.6173095703125 +70430 0.15228271484375 +70431 0.6524658203125 +70432 0.150604248046875 +70433 0.66339111328125 +70434 0.144378662109375 +70435 0.6561279296875 +70436 0.12908935546875 +70437 0.606781005859375 +70438 0.102264404296875 +70439 0.501190185546875 +70440 0.066925048828125 +70441 0.352783203125 +70442 0.0263671875 +70443 0.176544189453125 +70444 -0.020538330078125 +70445 -0.034820556640625 +70446 -0.06890869140625 +70447 -0.258209228515625 +70448 -0.108367919921875 +70449 -0.44244384765625 +70450 -0.1363525390625 +70451 -0.5753173828125 +70452 -0.15185546875 +70453 -0.65203857421875 +70454 -0.148712158203125 +70455 -0.641632080078125 +70456 -0.13067626953125 +70457 -0.562164306640625 +70458 -0.106781005859375 +70459 -0.458038330078125 +70460 -0.081451416015625 +70461 -0.350555419921875 +70462 -0.05908203125 +70463 -0.260528564453125 +70464 -0.040740966796875 +70465 -0.192108154296875 +70466 -0.026031494140625 +70467 -0.141937255859375 +70468 -0.013641357421875 +70469 -0.1021728515625 +70470 -0.001800537109375 +70471 -0.062896728515625 +70472 0.01165771484375 +70473 -0.011932373046875 +70474 0.029022216796875 +70475 0.062835693359375 +70476 0.04766845703125 +70477 0.148712158203125 +70478 0.066741943359375 +70479 0.241729736328125 +70480 0.087677001953125 +70481 0.34912109375 +70482 0.1077880859375 +70483 0.457305908203125 +70484 0.122711181640625 +70485 0.54388427734375 +70486 0.125457763671875 +70487 0.5728759765625 +70488 0.108642578125 +70489 0.506591796875 +70490 0.07373046875 +70491 0.351226806640625 +70492 0.02886962890625 +70493 0.146514892578125 +70494 -0.015228271484375 +70495 -0.05523681640625 +70496 -0.050811767578125 +70497 -0.21624755859375 +70498 -0.077392578125 +70499 -0.334930419921875 +70500 -0.0931396484375 +70501 -0.402984619140625 +70502 -0.102142333984375 +70503 -0.4412841796875 +70504 -0.113555908203125 +70505 -0.49578857421875 +70506 -0.126129150390625 +70507 -0.5601806640625 +70508 -0.133148193359375 +70509 -0.600738525390625 +70510 -0.1280517578125 +70511 -0.584228515625 +70512 -0.104705810546875 +70513 -0.47930908203125 +70514 -0.061920166015625 +70515 -0.27935791015625 +70516 -0.0047607421875 +70517 -0.0089111328125 +70518 0.053924560546875 +70519 0.268798828125 +70520 0.0997314453125 +70521 0.482818603515625 +70522 0.12664794921875 +70523 0.60369873046875 +70524 0.138336181640625 +70525 0.650421142578125 +70526 0.142852783203125 +70527 0.66400146484375 +70528 0.139556884765625 +70529 0.6414794921875 +70530 0.1263427734375 +70531 0.572540283203125 +70532 0.111358642578125 +70533 0.498138427734375 +70534 0.098907470703125 +70535 0.439453125 +70536 0.0848388671875 +70537 0.375518798828125 +70538 0.0628662109375 +70539 0.274505615234375 +70540 0.027557373046875 +70541 0.1087646484375 +70542 -0.016448974609375 +70543 -0.099395751953125 +70544 -0.06268310546875 +70545 -0.3182373046875 +70546 -0.11126708984375 +70547 -0.5489501953125 +70548 -0.158477783203125 +70549 -0.7738037109375 +70550 -0.193603515625 +70551 -0.86383056640625 +70552 -0.209930419921875 +70553 -0.870391845703125 +70554 -0.2109375 +70555 -0.86895751953125 +70556 -0.199188232421875 +70557 -0.861053466796875 +70558 -0.171234130859375 +70559 -0.765869140625 +70560 -0.12481689453125 +70561 -0.5301513671875 +70562 -0.0614013671875 +70563 -0.214691162109375 +70564 0.010345458984375 +70565 0.137359619140625 +70566 0.080047607421875 +70567 0.474822998046875 +70568 0.1405029296875 +70569 0.76239013671875 +70570 0.18621826171875 +70571 0.867462158203125 +70572 0.2171630859375 +70573 0.870361328125 +70574 0.230926513671875 +70575 0.86480712890625 +70576 0.228485107421875 +70577 0.831817626953125 +70578 0.214630126953125 +70579 0.677581787109375 +70580 0.19049072265625 +70581 0.495880126953125 +70582 0.15972900390625 +70583 0.30767822265625 +70584 0.122772216796875 +70585 0.116180419921875 +70586 0.073272705078125 +70587 -0.110748291015625 +70588 0.009857177734375 +70589 -0.381805419921875 +70590 -0.058837890625 +70591 -0.6572265625 +70592 -0.120758056640625 +70593 -0.857421875 +70594 -0.167266845703125 +70595 -0.870391845703125 +70596 -0.196868896484375 +70597 -0.870391845703125 +70598 -0.21484375 +70599 -0.86444091796875 +70600 -0.228271484375 +70601 -0.85723876953125 +70602 -0.2333984375 +70603 -0.790008544921875 +70604 -0.21929931640625 +70605 -0.62847900390625 +70606 -0.185272216796875 +70607 -0.3956298828125 +70608 -0.13787841796875 +70609 -0.126708984375 +70610 -0.082550048828125 +70611 0.150115966796875 +70612 -0.021636962890625 +70613 0.424041748046875 +70614 0.039459228515625 +70615 0.670623779296875 +70616 0.092926025390625 +70617 0.854522705078125 +70618 0.13519287109375 +70619 0.866485595703125 +70620 0.163116455078125 +70621 0.86920166015625 +70622 0.180267333984375 +70623 0.8653564453125 +70624 0.18927001953125 +70625 0.857147216796875 +70626 0.189453125 +70627 0.766845703125 +70628 0.181793212890625 +70629 0.628509521484375 +70630 0.164886474609375 +70631 0.462127685546875 +70632 0.143829345703125 +70633 0.297210693359375 +70634 0.12109375 +70635 0.14862060546875 +70636 0.092071533203125 +70637 -0.00537109375 +70638 0.058258056640625 +70639 -0.15753173828125 +70640 0.01898193359375 +70641 -0.31304931640625 +70642 -0.028533935546875 +70643 -0.48876953125 +70644 -0.074859619140625 +70645 -0.6416015625 +70646 -0.114990234375 +70647 -0.751373291015625 +70648 -0.15350341796875 +70649 -0.84619140625 +70650 -0.187408447265625 +70651 -0.861297607421875 +70652 -0.209991455078125 +70653 -0.863250732421875 +70654 -0.21490478515625 +70655 -0.856597900390625 +70656 -0.203948974609375 +70657 -0.7498779296875 +70658 -0.187896728515625 +70659 -0.624542236328125 +70660 -0.163787841796875 +70661 -0.47808837890625 +70662 -0.1220703125 +70663 -0.253387451171875 +70664 -0.070770263671875 +70665 0.003692626953125 +70666 -0.021728515625 +70667 0.2257080078125 +70668 0.0267333984375 +70669 0.427154541015625 +70670 0.079681396484375 +70671 0.643218994140625 +70672 0.135101318359375 +70673 0.855926513671875 +70674 0.182952880859375 +70675 0.870361328125 +70676 0.21466064453125 +70677 0.870361328125 +70678 0.23126220703125 +70679 0.862762451171875 +70680 0.232177734375 +70681 0.79669189453125 +70682 0.2158203125 +70683 0.595794677734375 +70684 0.187164306640625 +70685 0.362152099609375 +70686 0.151092529296875 +70687 0.1270751953125 +70688 0.111419677734375 +70689 -0.086944580078125 +70690 0.068756103515625 +70691 -0.2784423828125 +70692 0.017608642578125 +70693 -0.484832763671875 +70694 -0.044891357421875 +70695 -0.729583740234375 +70696 -0.109893798828125 +70697 -0.86688232421875 +70698 -0.166412353515625 +70699 -0.870391845703125 +70700 -0.21331787109375 +70701 -0.86859130859375 +70702 -0.25 +70703 -0.86279296875 +70704 -0.270294189453125 +70705 -0.817962646484375 +70706 -0.26641845703125 +70707 -0.6116943359375 +70708 -0.237152099609375 +70709 -0.3128662109375 +70710 -0.188232421875 +70711 0.039398193359375 +70712 -0.123138427734375 +70713 0.422821044921875 +70714 -0.04766845703125 +70715 0.805145263671875 +70716 0.0264892578125 +70717 0.870361328125 +70718 0.0894775390625 +70719 0.870361328125 +70720 0.139007568359375 +70721 0.860015869140625 +70722 0.173492431640625 +70723 0.727935791015625 +70724 0.191650390625 +70725 0.48114013671875 +70726 0.197296142578125 +70727 0.2059326171875 +70728 0.193939208984375 +70729 -0.06103515625 +70730 0.18310546875 +70731 -0.29913330078125 +70732 0.162261962890625 +70733 -0.516204833984375 +70734 0.1287841796875 +70735 -0.7252197265625 +70736 0.086883544921875 +70737 -0.85980224609375 +70738 0.042388916015625 +70739 -0.870391845703125 +70740 0.000457763671875 +70741 -0.870391845703125 +70742 -0.03045654296875 +70743 -0.858062744140625 +70744 -0.049346923828125 +70745 -0.673004150390625 +70746 -0.06475830078125 +70747 -0.42694091796875 +70748 -0.083831787109375 +70749 -0.2100830078125 +70750 -0.10589599609375 +70751 -0.0362548828125 +70752 -0.125762939453125 +70753 0.10943603515625 +70754 -0.139801025390625 +70755 0.23516845703125 +70756 -0.140869140625 +70757 0.373687744140625 +70758 -0.129150390625 +70759 0.517791748046875 +70760 -0.11517333984375 +70761 0.602783203125 +70762 -0.098114013671875 +70763 0.635711669921875 +70764 -0.07244873046875 +70765 0.655181884765625 +70766 -0.040008544921875 +70767 0.65948486328125 +70768 -0.002349853515625 +70769 0.651275634765625 +70770 0.0361328125 +70771 0.61846923828125 +70772 0.068939208984375 +70773 0.53753662109375 +70774 0.092742919921875 +70775 0.404144287109375 +70776 0.10565185546875 +70777 0.22186279296875 +70778 0.107666015625 +70779 0.003997802734375 +70780 0.1015625 +70781 -0.22100830078125 +70782 0.090606689453125 +70783 -0.42449951171875 +70784 0.0782470703125 +70785 -0.579833984375 +70786 0.07159423828125 +70787 -0.641876220703125 +70788 0.06951904296875 +70789 -0.6177978515625 +70790 0.06121826171875 +70791 -0.575531005859375 +70792 0.0458984375 +70793 -0.526336669921875 +70794 0.032440185546875 +70795 -0.42645263671875 +70796 0.025634765625 +70797 -0.2581787109375 +70798 0.019622802734375 +70799 -0.068695068359375 +70800 0.008209228515625 +70801 0.09222412109375 +70802 -0.005218505859375 +70803 0.232147216796875 +70804 -0.0186767578125 +70805 0.3509521484375 +70806 -0.03692626953125 +70807 0.410064697265625 +70808 -0.064697265625 +70809 0.372955322265625 +70810 -0.098388671875 +70811 0.2554931640625 +70812 -0.129119873046875 +70813 0.10711669921875 +70814 -0.153564453125 +70815 -0.052886962890625 +70816 -0.165679931640625 +70817 -0.186279296875 +70818 -0.156158447265625 +70819 -0.23291015625 +70820 -0.12896728515625 +70821 -0.209442138671875 +70822 -0.095306396484375 +70823 -0.174163818359375 +70824 -0.056793212890625 +70825 -0.126739501953125 +70826 -0.011962890625 +70827 -0.048126220703125 +70828 0.034210205078125 +70829 0.0426025390625 +70830 0.07366943359375 +70831 0.10748291015625 +70832 0.10400390625 +70833 0.1409912109375 +70834 0.133026123046875 +70835 0.19708251953125 +70836 0.159454345703125 +70837 0.273651123046875 +70838 0.173858642578125 +70839 0.31768798828125 +70840 0.178009033203125 +70841 0.341094970703125 +70842 0.176177978515625 +70843 0.368011474609375 +70844 0.164520263671875 +70845 0.37249755859375 +70846 0.134857177734375 +70847 0.30072021484375 +70848 0.088134765625 +70849 0.1517333984375 +70850 0.03570556640625 +70851 -0.01470947265625 +70852 -0.019256591796875 +70853 -0.1883544921875 +70854 -0.075927734375 +70855 -0.372711181640625 +70856 -0.123870849609375 +70857 -0.51397705078125 +70858 -0.155029296875 +70859 -0.57177734375 +70860 -0.167205810546875 +70861 -0.53948974609375 +70862 -0.162567138671875 +70863 -0.43511962890625 +70864 -0.1468505859375 +70865 -0.2962646484375 +70866 -0.126220703125 +70867 -0.161102294921875 +70868 -0.103057861328125 +70869 -0.0435791015625 +70870 -0.0770263671875 +70871 0.060394287109375 +70872 -0.0511474609375 +70873 0.13665771484375 +70874 -0.028778076171875 +70875 0.170135498046875 +70876 -0.010101318359375 +70877 0.16552734375 +70878 0.009490966796875 +70879 0.15728759765625 +70880 0.029693603515625 +70881 0.150787353515625 +70882 0.0452880859375 +70883 0.12200927734375 +70884 0.0567626953125 +70885 0.080108642578125 +70886 0.067535400390625 +70887 0.05126953125 +70888 0.0814208984375 +70889 0.062896728515625 +70890 0.094146728515625 +70891 0.09271240234375 +70892 0.097442626953125 +70893 0.092987060546875 +70894 0.093719482421875 +70895 0.07855224609375 +70896 0.085662841796875 +70897 0.06427001953125 +70898 0.07110595703125 +70899 0.0347900390625 +70900 0.050384521484375 +70901 -0.01171875 +70902 0.02752685546875 +70903 -0.056060791015625 +70904 0.0106201171875 +70905 -0.055511474609375 +70906 0.000579833984375 +70907 -0.010467529296875 +70908 -0.0106201171875 +70909 0.02508544921875 +70910 -0.026336669921875 +70911 0.025665283203125 +70912 -0.041595458984375 +70913 0.017333984375 +70914 -0.055267333984375 +70915 0.00189208984375 +70916 -0.068511962890625 +70917 -0.03173828125 +70918 -0.07904052734375 +70919 -0.071502685546875 +70920 -0.089324951171875 +70921 -0.13543701171875 +70922 -0.098846435546875 +70923 -0.219970703125 +70924 -0.104156494140625 +70925 -0.300506591796875 +70926 -0.1055908203125 +70927 -0.376312255859375 +70928 -0.09912109375 +70929 -0.416107177734375 +70930 -0.07818603515625 +70931 -0.371124267578125 +70932 -0.04376220703125 +70933 -0.242279052734375 +70934 -0.00274658203125 +70935 -0.069732666015625 +70936 0.040863037109375 +70937 0.125640869140625 +70938 0.081634521484375 +70939 0.31268310546875 +70940 0.113433837890625 +70941 0.45501708984375 +70942 0.136077880859375 +70943 0.554779052734375 +70944 0.1490478515625 +70945 0.61065673828125 +70946 0.150421142578125 +70947 0.610931396484375 +70948 0.136627197265625 +70949 0.531463623046875 +70950 0.1102294921875 +70951 0.3883056640625 +70952 0.079559326171875 +70953 0.23468017578125 +70954 0.048858642578125 +70955 0.095245361328125 +70956 0.022613525390625 +70957 -0.00396728515625 +70958 0.00360107421875 +70959 -0.04852294921875 +70960 -0.00994873046875 +70961 -0.055145263671875 +70962 -0.025146484375 +70963 -0.0758056640625 +70964 -0.0455322265625 +70965 -0.138702392578125 +70966 -0.06536865234375 +70967 -0.209197998046875 +70968 -0.084442138671875 +70969 -0.289031982421875 +70970 -0.1025390625 +70971 -0.37884521484375 +70972 -0.116119384765625 +70973 -0.456329345703125 +70974 -0.1243896484375 +70975 -0.51641845703125 +70976 -0.12152099609375 +70977 -0.519287109375 +70978 -0.106781005859375 +70979 -0.458251953125 +70980 -0.0882568359375 +70981 -0.384796142578125 +70982 -0.070098876953125 +70983 -0.323699951171875 +70984 -0.051971435546875 +70985 -0.269287109375 +70986 -0.030487060546875 +70987 -0.1951904296875 +70988 -0.00604248046875 +70989 -0.100006103515625 +70990 0.016754150390625 +70991 -0.01055908203125 +70992 0.04193115234375 +70993 0.1033935546875 +70994 0.0701904296875 +70995 0.24908447265625 +70996 0.09326171875 +70997 0.373199462890625 +70998 0.1082763671875 +70999 0.45806884765625 +71000 0.1163330078125 +71001 0.511474609375 +71002 0.122283935546875 +71003 0.565399169921875 +71004 0.125091552734375 +71005 0.61138916015625 +71006 0.116058349609375 +71007 0.5897216796875 +71008 0.094085693359375 +71009 0.4906005859375 +71010 0.06219482421875 +71011 0.33148193359375 +71012 0.02618408203125 +71013 0.147796630859375 +71014 -0.007232666015625 +71015 -0.01873779296875 +71016 -0.03338623046875 +71017 -0.140289306640625 +71018 -0.048126220703125 +71019 -0.191986083984375 +71020 -0.05267333984375 +71021 -0.184295654296875 +71022 -0.053436279296875 +71023 -0.161834716796875 +71024 -0.056549072265625 +71025 -0.166595458984375 +71026 -0.061248779296875 +71027 -0.19390869140625 +71028 -0.06463623046875 +71029 -0.22442626953125 +71030 -0.070068359375 +71031 -0.279754638671875 +71032 -0.074615478515625 +71033 -0.3389892578125 +71034 -0.0714111328125 +71035 -0.3543701171875 +71036 -0.064117431640625 +71037 -0.348175048828125 +71038 -0.053924560546875 +71039 -0.32598876953125 +71040 -0.036773681640625 +71041 -0.2581787109375 +71042 -0.0123291015625 +71043 -0.139801025390625 +71044 0.016845703125 +71045 0.014617919921875 +71046 0.04132080078125 +71047 0.144378662109375 +71048 0.056610107421875 +71049 0.221038818359375 +71050 0.066436767578125 +71051 0.27069091796875 +71052 0.07086181640625 +71053 0.294036865234375 +71054 0.072967529296875 +71055 0.311767578125 +71056 0.0750732421875 +71057 0.339141845703125 +71058 0.07476806640625 +71059 0.360260009765625 +71060 0.07012939453125 +71061 0.360504150390625 +71062 0.057220458984375 +71063 0.308380126953125 +71064 0.033416748046875 +71065 0.18170166015625 +71066 0.002471923828125 +71067 0.0047607421875 +71068 -0.02880859375 +71069 -0.17559814453125 +71070 -0.053955078125 +71071 -0.3143310546875 +71072 -0.066680908203125 +71073 -0.36785888671875 +71074 -0.070281982421875 +71075 -0.36248779296875 +71076 -0.070709228515625 +71077 -0.343536376953125 +71078 -0.066619873046875 +71079 -0.3018798828125 +71080 -0.057159423828125 +71081 -0.231414794921875 +71082 -0.040374755859375 +71083 -0.117645263671875 +71084 -0.02081298828125 +71085 0.007049560546875 +71086 -0.00604248046875 +71087 0.087982177734375 +71088 0.005615234375 +71089 0.13946533203125 +71090 0.015594482421875 +71091 0.17425537109375 +71092 0.023040771484375 +71093 0.188201904296875 +71094 0.0262451171875 +71095 0.171234130859375 +71096 0.0242919921875 +71097 0.118438720703125 +71098 0.020599365234375 +71099 0.05706787109375 +71100 0.01519775390625 +71101 -0.010711669921875 +71102 0.00701904296875 +71103 -0.0914306640625 +71104 -0.00091552734375 +71105 -0.162322998046875 +71106 -0.0047607421875 +71107 -0.194549560546875 +71108 0.000732421875 +71109 -0.1492919921875 +71110 0.01629638671875 +71111 -0.02166748046875 +71112 0.0333251953125 +71113 0.124053955078125 +71114 0.04156494140625 +71115 0.211151123046875 +71116 0.041351318359375 +71117 0.240447998046875 +71118 0.037017822265625 +71119 0.242218017578125 +71120 0.030120849609375 +71121 0.2257080078125 +71122 0.0213623046875 +71123 0.194366455078125 +71124 0.006561279296875 +71125 0.115509033203125 +71126 -0.01080322265625 +71127 0.0128173828125 +71128 -0.0224609375 +71129 -0.053802490234375 +71130 -0.0318603515625 +71131 -0.110626220703125 +71132 -0.04461669921875 +71133 -0.199493408203125 +71134 -0.05718994140625 +71135 -0.29437255859375 +71136 -0.061065673828125 +71137 -0.33221435546875 +71138 -0.051788330078125 +71139 -0.27972412109375 +71140 -0.036102294921875 +71141 -0.185333251953125 +71142 -0.02496337890625 +71143 -0.128204345703125 +71144 -0.01953125 +71145 -0.115692138671875 +71146 -0.01580810546875 +71147 -0.116455078125 +71148 -0.010650634765625 +71149 -0.105926513671875 +71150 -0.0001220703125 +71151 -0.053955078125 +71152 0.016815185546875 +71153 0.048797607421875 +71154 0.033905029296875 +71155 0.157318115234375 +71156 0.042938232421875 +71157 0.212005615234375 +71158 0.044586181640625 +71159 0.218475341796875 +71160 0.047088623046875 +71161 0.23724365234375 +71162 0.05548095703125 +71163 0.30535888671875 +71164 0.064208984375 +71165 0.38128662109375 +71166 0.065093994140625 +71167 0.404449462890625 +71168 0.06036376953125 +71169 0.3944091796875 +71170 0.054656982421875 +71171 0.3885498046875 +71172 0.04583740234375 +71173 0.362640380859375 +71174 0.029937744140625 +71175 0.27362060546875 +71176 0.006988525390625 +71177 0.11712646484375 +71178 -0.017120361328125 +71179 -0.054901123046875 +71180 -0.036651611328125 +71181 -0.19085693359375 +71182 -0.05078125 +71183 -0.28570556640625 +71184 -0.05926513671875 +71185 -0.339263916015625 +71186 -0.064697265625 +71187 -0.3775634765625 +71188 -0.071685791015625 +71189 -0.445709228515625 +71190 -0.07940673828125 +71191 -0.535064697265625 +71192 -0.086273193359375 +71193 -0.629058837890625 +71194 -0.089324951171875 +71195 -0.697601318359375 +71196 -0.085052490234375 +71197 -0.70391845703125 +71198 -0.073150634765625 +71199 -0.6424560546875 +71200 -0.05169677734375 +71201 -0.491241455078125 +71202 -0.022613525390625 +71203 -0.265716552734375 +71204 0.00775146484375 +71205 -0.023712158203125 +71206 0.03570556640625 +71207 0.201751708984375 +71208 0.057373046875 +71209 0.375823974609375 +71210 0.071197509765625 +71211 0.485076904296875 +71212 0.081146240234375 +71213 0.56884765625 +71214 0.087982177734375 +71215 0.634765625 +71216 0.087066650390625 +71217 0.63763427734375 +71218 0.077301025390625 +71219 0.5660400390625 +71220 0.06427001953125 +71221 0.4720458984375 +71222 0.053466796875 +71223 0.40692138671875 +71224 0.0458984375 +71225 0.3778076171875 +71226 0.041015625 +71227 0.376953125 +71228 0.0357666015625 +71229 0.371978759765625 +71230 0.025177001953125 +71231 0.313140869140625 +71232 0.007843017578125 +71233 0.184417724609375 +71234 -0.01336669921875 +71235 0.011199951171875 +71236 -0.034576416015625 +71237 -0.171051025390625 +71238 -0.0531005859375 +71239 -0.33740234375 +71240 -0.067291259765625 +71241 -0.47198486328125 +71242 -0.075653076171875 +71243 -0.560394287109375 +71244 -0.075958251953125 +71245 -0.58056640625 +71246 -0.06988525390625 +71247 -0.54754638671875 +71248 -0.06256103515625 +71249 -0.508575439453125 +71250 -0.05377197265625 +71251 -0.459503173828125 +71252 -0.043060302734375 +71253 -0.394378662109375 +71254 -0.03472900390625 +71255 -0.35260009765625 +71256 -0.02667236328125 +71257 -0.31170654296875 +71258 -0.011383056640625 +71259 -0.197418212890625 +71260 0.011138916015625 +71261 -0.007965087890625 +71262 0.035614013671875 +71263 0.207489013671875 +71264 0.057830810546875 +71265 0.409210205078125 +71266 0.07513427734375 +71267 0.57208251953125 +71268 0.084381103515625 +71269 0.66595458984375 +71270 0.082305908203125 +71271 0.65875244140625 +71272 0.07080078125 +71273 0.56744384765625 +71274 0.054046630859375 +71275 0.431396484375 +71276 0.036773681640625 +71277 0.29443359375 +71278 0.0218505859375 +71279 0.182464599609375 +71280 0.00616455078125 +71281 0.06365966796875 +71282 -0.01153564453125 +71283 -0.075958251953125 +71284 -0.02618408203125 +71285 -0.189422607421875 +71286 -0.037109375 +71287 -0.271942138671875 +71288 -0.04620361328125 +71289 -0.342529296875 +71290 -0.049591064453125 +71291 -0.364166259765625 +71292 -0.04620361328125 +71293 -0.327239990234375 +71294 -0.04071044921875 +71295 -0.2769775390625 +71296 -0.037353515625 +71297 -0.253692626953125 +71298 -0.0347900390625 +71299 -0.24365234375 +71300 -0.028045654296875 +71301 -0.1983642578125 +71302 -0.01708984375 +71303 -0.116241455078125 +71304 -0.00616455078125 +71305 -0.036834716796875 +71306 0.003997802734375 +71307 0.034881591796875 +71308 0.012451171875 +71309 0.09124755859375 +71310 0.016632080078125 +71311 0.10888671875 +71312 0.020355224609375 +71313 0.125518798828125 +71314 0.025238037109375 +71315 0.15771484375 +71316 0.028411865234375 +71317 0.17828369140625 +71318 0.02813720703125 +71319 0.17108154296875 +71320 0.02374267578125 +71321 0.129974365234375 +71322 0.01812744140625 +71323 0.082427978515625 +71324 0.011260986328125 +71325 0.027679443359375 +71326 0.0 +71327 -0.065643310546875 +71328 -0.0115966796875 +71329 -0.15936279296875 +71330 -0.019195556640625 +71331 -0.21307373046875 +71332 -0.023529052734375 +71333 -0.234649658203125 +71334 -0.022003173828125 +71335 -0.2001953125 +71336 -0.0155029296875 +71337 -0.119171142578125 +71338 -0.007354736328125 +71339 -0.024749755859375 +71340 0.002777099609375 +71341 0.085784912109375 +71342 0.011383056640625 +71343 0.178131103515625 +71344 0.014678955078125 +71345 0.215576171875 +71346 0.01409912109375 +71347 0.211456298828125 +71348 0.0106201171875 +71349 0.17523193359375 +71350 0.006500244140625 +71351 0.128753662109375 +71352 0.004791259765625 +71353 0.1019287109375 +71354 0.003326416015625 +71355 0.0743408203125 +71356 0.001678466796875 +71357 0.04327392578125 +71358 0.002838134765625 +71359 0.038177490234375 +71360 0.00848388671875 +71361 0.076263427734375 +71362 0.01678466796875 +71363 0.14105224609375 +71364 0.02288818359375 +71365 0.186431884765625 +71366 0.024261474609375 +71367 0.188812255859375 +71368 0.019927978515625 +71369 0.1390380859375 +71370 0.010345458984375 +71371 0.041778564453125 +71372 -0.002044677734375 +71373 -0.079437255859375 +71374 -0.016693115234375 +71375 -0.219390869140625 +71376 -0.032501220703125 +71377 -0.367828369140625 +71378 -0.046356201171875 +71379 -0.494873046875 +71380 -0.053619384765625 +71381 -0.556243896484375 +71382 -0.049713134765625 +71383 -0.508697509765625 +71384 -0.037017822265625 +71385 -0.3756103515625 +71386 -0.021942138671875 +71387 -0.218902587890625 +71388 -0.00701904296875 +71389 -0.063751220703125 +71390 0.0079345703125 +71391 0.091552734375 +71392 0.0218505859375 +71393 0.23602294921875 +71394 0.03204345703125 +71395 0.342987060546875 +71396 0.0367431640625 +71397 0.39520263671875 +71398 0.03564453125 +71399 0.389373779296875 +71400 0.028656005859375 +71401 0.324249267578125 +71402 0.018341064453125 +71403 0.224090576171875 +71404 0.00836181640625 +71405 0.124267578125 +71406 -3.0517578125e-05 +71407 0.037078857421875 +71408 -0.0040283203125 +71409 -0.010101318359375 +71410 -0.003936767578125 +71411 -0.019439697265625 +71412 -0.00311279296875 +71413 -0.022796630859375 +71414 0.000274658203125 +71415 -0.001556396484375 +71416 0.00738525390625 +71417 0.056304931640625 +71418 0.013580322265625 +71419 0.106719970703125 +71420 0.013336181640625 +71421 0.096893310546875 +71422 0.008270263671875 +71423 0.042694091796875 +71424 0.002593994140625 +71425 -0.018035888671875 +71426 -0.00286865234375 +71427 -0.07586669921875 +71428 -0.007537841796875 +71429 -0.11944580078125 +71430 -0.01202392578125 +71431 -0.15972900390625 +71432 -0.0166015625 +71433 -0.202606201171875 +71434 -0.02117919921875 +71435 -0.24859619140625 +71436 -0.02618408203125 +71437 -0.30517578125 +71438 -0.030853271484375 +71439 -0.36212158203125 +71440 -0.033172607421875 +71441 -0.39141845703125 +71442 -0.030426025390625 +71443 -0.35528564453125 +71444 -0.022369384765625 +71445 -0.249969482421875 +71446 -0.010284423828125 +71447 -0.092864990234375 +71448 0.0037841796875 +71449 0.08905029296875 +71450 0.015411376953125 +71451 0.2352294921875 +71452 0.022613525390625 +71453 0.318817138671875 +71454 0.026641845703125 +71455 0.358642578125 +71456 0.026947021484375 +71457 0.347747802734375 +71458 0.0234375 +71459 0.28564453125 +71460 0.01971435546875 +71461 0.223175048828125 +71462 0.018341064453125 +71463 0.196746826171875 +71464 0.01739501953125 +71465 0.179840087890625 +71466 0.01568603515625 +71467 0.155548095703125 +71468 0.015167236328125 +71469 0.151214599609375 +71470 0.01513671875 +71471 0.156951904296875 +71472 0.0126953125 +71473 0.13177490234375 +71474 0.00970458984375 +71475 0.100799560546875 +71476 0.007843017578125 +71477 0.087127685546875 +71478 0.004608154296875 +71479 0.05487060546875 +71480 -0.000885009765625 +71481 -0.009002685546875 +71482 -0.008544921875 +71483 -0.10400390625 +71484 -0.018280029296875 +71485 -0.229400634765625 +71486 -0.027923583984375 +71487 -0.35552978515625 +71488 -0.034515380859375 +71489 -0.441925048828125 +71490 -0.037017822265625 +71491 -0.473846435546875 +71492 -0.036376953125 +71493 -0.464813232421875 +71494 -0.03289794921875 +71495 -0.419097900390625 +71496 -0.02642822265625 +71497 -0.334320068359375 +71498 -0.01824951171875 +71499 -0.227935791015625 +71500 -0.010101318359375 +71501 -0.12347412109375 +71502 -0.00250244140625 +71503 -0.02764892578125 +71504 0.00579833984375 +71505 0.077667236328125 +71506 0.0162353515625 +71507 0.2132568359375 +71508 0.02947998046875 +71509 0.38885498046875 +71510 0.0439453125 +71511 0.582794189453125 +71512 0.055206298828125 +71513 0.734039306640625 +71514 0.0601806640625 +71515 0.800140380859375 +71516 0.058685302734375 +71517 0.7783203125 +71518 0.05047607421875 +71519 0.6651611328125 +71520 0.035491943359375 +71521 0.45965576171875 +71522 0.016448974609375 +71523 0.199188232421875 +71524 -0.00189208984375 +71525 -0.050689697265625 +71526 -0.015411376953125 +71527 -0.23297119140625 +71528 -0.0228271484375 +71529 -0.33013916015625 +71530 -0.0260009765625 +71531 -0.368408203125 +71532 -0.02716064453125 +71533 -0.378936767578125 +71534 -0.027435302734375 +71535 -0.376983642578125 +71536 -0.02801513671875 +71537 -0.37969970703125 +71538 -0.0291748046875 +71539 -0.391510009765625 +71540 -0.028961181640625 +71541 -0.385345458984375 +71542 -0.025970458984375 +71543 -0.3419189453125 +71544 -0.021728515625 +71545 -0.28289794921875 +71546 -0.019378662109375 +71547 -0.251617431640625 +71548 -0.020233154296875 +71549 -0.266143798828125 +71550 -0.020477294921875 +71551 -0.273345947265625 +71552 -0.016082763671875 +71553 -0.216796875 +71554 -0.00933837890625 +71555 -0.128265380859375 +71556 -0.00457763671875 +71557 -0.068145751953125 +71558 -0.0023193359375 +71559 -0.0430908203125 +71560 -0.000518798828125 +71561 -0.024444580078125 +71562 0.00311279296875 +71563 0.020721435546875 +71564 0.0108642578125 +71565 0.124481201171875 +71566 0.0206298828125 +71567 0.25787353515625 +71568 0.0294189453125 +71569 0.379119873046875 +71570 0.03662109375 +71571 0.47991943359375 +71572 0.0399169921875 +71573 0.5281982421875 +71574 0.03839111328125 +71575 0.511138916015625 +71576 0.0340576171875 +71577 0.456207275390625 +71578 0.03009033203125 +71579 0.407470703125 +71580 0.02789306640625 +71581 0.383758544921875 +71582 0.02545166015625 +71583 0.35687255859375 +71584 0.021728515625 +71585 0.31182861328125 +71586 0.01690673828125 +71587 0.250885009765625 +71588 0.0103759765625 +71589 0.1654052734375 +71590 0.000732421875 +71591 0.035247802734375 +71592 -0.01214599609375 +71593 -0.142059326171875 +71594 -0.026031494140625 +71595 -0.33563232421875 +71596 -0.0401611328125 +71597 -0.5345458984375 +71598 -0.053314208984375 +71599 -0.72186279296875 +71600 -0.061126708984375 +71601 -0.836669921875 +71602 -0.060302734375 +71603 -0.8326416015625 +71604 -0.05230712890625 +71605 -0.7296142578125 +71606 -0.04119873046875 +71607 -0.582550048828125 +71608 -0.030487060546875 +71609 -0.440093994140625 +71610 -0.021728515625 +71611 -0.324310302734375 +71612 -0.01251220703125 +71613 -0.20147705078125 +71614 -0.00091552734375 +71615 -0.044647216796875 +71616 0.00994873046875 +71617 0.103973388671875 +71618 0.017059326171875 +71619 0.202392578125 +71620 0.02142333984375 +71621 0.264495849609375 +71622 0.02655029296875 +71623 0.338897705078125 +71624 0.03375244140625 +71625 0.443817138671875 +71626 0.04058837890625 +71627 0.545074462890625 +71628 0.0452880859375 +71629 0.6173095703125 +71630 0.047271728515625 +71631 0.6524658203125 +71632 0.047515869140625 +71633 0.66339111328125 +71634 0.046478271484375 +71635 0.6561279296875 +71636 0.04241943359375 +71637 0.606781005859375 +71638 0.034393310546875 +71639 0.501190185546875 +71640 0.02337646484375 +71641 0.352783203125 +71642 0.010467529296875 +71643 0.176544189453125 +71644 -0.004791259765625 +71645 -0.034820556640625 +71646 -0.020751953125 +71647 -0.258209228515625 +71648 -0.033721923828125 +71649 -0.44244384765625 +71650 -0.0428466796875 +71651 -0.5753173828125 +71652 -0.047821044921875 +71653 -0.65203857421875 +71654 -0.04644775390625 +71655 -0.641632080078125 +71656 -0.040130615234375 +71657 -0.562164306640625 +71658 -0.032073974609375 +71659 -0.458038330078125 +71660 -0.023834228515625 +71661 -0.350555419921875 +71662 -0.01690673828125 +71663 -0.260528564453125 +71664 -0.011627197265625 +71665 -0.192108154296875 +71666 -0.00775146484375 +71667 -0.141937255859375 +71668 -0.004730224609375 +71669 -0.1021728515625 +71670 -0.001861572265625 +71671 -0.062896728515625 +71672 0.001708984375 +71673 -0.011932373046875 +71674 0.006866455078125 +71675 0.062835693359375 +71676 0.012725830078125 +71677 0.148712158203125 +71678 0.019012451171875 +71679 0.241729736328125 +71680 0.02593994140625 +71681 0.34912109375 +71682 0.031829833984375 +71683 0.457305908203125 +71684 0.03515625 +71685 0.54388427734375 +71686 0.034881591796875 +71687 0.5728759765625 +71688 0.02984619140625 +71689 0.506591796875 +71690 0.020660400390625 +71691 0.351226806640625 +71692 0.00921630859375 +71693 0.146514892578125 +71694 -0.002105712890625 +71695 -0.05523681640625 +71696 -0.011566162109375 +71697 -0.21624755859375 +71698 -0.018951416015625 +71699 -0.334930419921875 +71700 -0.02374267578125 +71701 -0.402984619140625 +71702 -0.02667236328125 +71703 -0.4412841796875 +71704 -0.029541015625 +71705 -0.49578857421875 +71706 -0.032135009765625 +71707 -0.5601806640625 +71708 -0.03314208984375 +71709 -0.600738525390625 +71710 -0.03131103515625 +71711 -0.584228515625 +71712 -0.025482177734375 +71713 -0.47930908203125 +71714 -0.0155029296875 +71715 -0.27935791015625 +71716 -0.00250244140625 +71717 -0.0089111328125 +71718 0.0108642578125 +71719 0.268798828125 +71720 0.021575927734375 +71721 0.482818603515625 +71722 0.02838134765625 +71723 0.60369873046875 +71724 0.031890869140625 +71725 0.650421142578125 +71726 0.033721923828125 +71727 0.66400146484375 +71728 0.033660888671875 +71729 0.6414794921875 +71730 0.031280517578125 +71731 0.572540283203125 +71732 0.0281982421875 +71733 0.498138427734375 +71734 0.025299072265625 +71735 0.439453125 +71736 0.02178955078125 +71737 0.375518798828125 +71738 0.016448974609375 +71739 0.274505615234375 +71740 0.008270263671875 +71741 0.1087646484375 +71742 -0.001739501953125 +71743 -0.099395751953125 +71744 -0.012237548828125 +71745 -0.3182373046875 +71746 -0.023162841796875 +71747 -0.5489501953125 +71748 -0.033660888671875 +71749 -0.7738037109375 +71750 -0.04156494140625 +71751 -0.86383056640625 +71752 -0.045501708984375 +71753 -0.870391845703125 +71754 -0.046142578125 +71755 -0.86895751953125 +71756 -0.043975830078125 +71757 -0.861053466796875 +71758 -0.038330078125 +71759 -0.765869140625 +71760 -0.02874755859375 +71761 -0.5301513671875 +71762 -0.01556396484375 +71763 -0.214691162109375 +71764 -0.000518798828125 +71765 0.137359619140625 +71766 0.014251708984375 +71767 0.474822998046875 +71768 0.0272216796875 +71769 0.76239013671875 +71770 0.037261962890625 +71771 0.867462158203125 +71772 0.0443115234375 +71773 0.870361328125 +71774 0.047821044921875 +71775 0.86480712890625 +71776 0.0479736328125 +71777 0.831817626953125 +71778 0.045684814453125 +71779 0.677581787109375 +71780 0.041168212890625 +71781 0.495880126953125 +71782 0.03515625 +71783 0.30767822265625 +71784 0.027740478515625 +71785 0.116180419921875 +71786 0.017669677734375 +71787 -0.110748291015625 +71788 0.004669189453125 +71789 -0.381805419921875 +71790 -0.009490966796875 +71791 -0.6572265625 +71792 -0.022369384765625 +71793 -0.857421875 +71794 -0.032196044921875 +71795 -0.870391845703125 +71796 -0.03863525390625 +71797 -0.870391845703125 +71798 -0.042755126953125 +71799 -0.86444091796875 +71800 -0.045928955078125 +71801 -0.85723876953125 +71802 -0.047393798828125 +71803 -0.790008544921875 +71804 -0.044952392578125 +71805 -0.62847900390625 +71806 -0.0384521484375 +71807 -0.3956298828125 +71808 -0.0291748046875 +71809 -0.126708984375 +71810 -0.0181884765625 +71811 0.150115966796875 +71812 -0.005950927734375 +71813 0.424041748046875 +71814 0.00640869140625 +71815 0.670623779296875 +71816 0.017303466796875 +71817 0.854522705078125 +71818 0.026031494140625 +71819 0.866485595703125 +71820 0.03192138671875 +71821 0.86920166015625 +71822 0.03570556640625 +71823 0.8653564453125 +71824 0.037872314453125 +71825 0.857147216796875 +71826 0.03826904296875 +71827 0.766845703125 +71828 0.037078857421875 +71829 0.628509521484375 +71830 0.03399658203125 +71831 0.462127685546875 +71832 0.029998779296875 +71833 0.297210693359375 +71834 0.025543212890625 +71835 0.14862060546875 +71836 0.019744873046875 +71837 -0.00537109375 +71838 0.012908935546875 +71839 -0.15753173828125 +71840 0.004913330078125 +71841 -0.31304931640625 +71842 -0.0047607421875 +71843 -0.48876953125 +71844 -0.01422119140625 +71845 -0.6416015625 +71846 -0.0224609375 +71847 -0.751373291015625 +71848 -0.030364990234375 +71849 -0.84619140625 +71850 -0.03729248046875 +71851 -0.861297607421875 +71852 -0.04193115234375 +71853 -0.863250732421875 +71854 -0.042999267578125 +71855 -0.856597900390625 +71856 -0.040985107421875 +71857 -0.7498779296875 +71858 -0.038177490234375 +71859 -0.624542236328125 +71860 -0.03369140625 +71861 -0.47808837890625 +71862 -0.02520751953125 +71863 -0.253387451171875 +71864 -0.014556884765625 +71865 0.003692626953125 +71866 -0.004486083984375 +71867 0.2257080078125 +71868 0.005462646484375 +71869 0.427154541015625 +71870 0.01654052734375 +71871 0.643218994140625 +71872 0.028350830078125 +71873 0.855926513671875 +71874 0.03857421875 +71875 0.870361328125 +71876 0.045257568359375 +71877 0.870361328125 +71878 0.048675537109375 +71879 0.862762451171875 +71880 0.0487060546875 +71881 0.79669189453125 +71882 0.04498291015625 +71883 0.595794677734375 +71884 0.038665771484375 +71885 0.362152099609375 +71886 0.0308837890625 +71887 0.1270751953125 +71888 0.022491455078125 +71889 -0.086944580078125 +71890 0.013580322265625 +71891 -0.2784423828125 +71892 0.00274658203125 +71893 -0.484832763671875 +71894 -0.010711669921875 +71895 -0.729583740234375 +71896 -0.0247802734375 +71897 -0.86688232421875 +71898 -0.036956787109375 +71899 -0.870391845703125 +71900 -0.046966552734375 +71901 -0.86859130859375 +71902 -0.05474853515625 +71903 -0.86279296875 +71904 -0.058868408203125 +71905 -0.817962646484375 +71906 -0.057525634765625 +71907 -0.6116943359375 +71908 -0.050445556640625 +71909 -0.3128662109375 +71910 -0.03900146484375 +71911 0.039398193359375 +71912 -0.024017333984375 +71913 0.422821044921875 +71914 -0.006805419921875 +71915 0.805145263671875 +71916 0.00982666015625 +71917 0.870361328125 +71918 0.02362060546875 +71919 0.870361328125 +71920 0.034088134765625 +71921 0.860015869140625 +71922 0.04095458984375 +71923 0.727935791015625 +71924 0.04400634765625 +71925 0.48114013671875 +71926 0.044219970703125 +71927 0.2059326171875 +71928 0.04248046875 +71929 -0.06103515625 +71930 0.0391845703125 +71931 -0.29913330078125 +71932 0.03375244140625 +71933 -0.516204833984375 +71934 0.025634765625 +71935 -0.7252197265625 +71936 0.015625 +71937 -0.85980224609375 +71938 0.005523681640625 +71939 -0.870391845703125 +71940 -0.003387451171875 +71941 -0.870391845703125 +71942 -0.010711669921875 +71943 -0.858062744140625 +71944 -0.016326904296875 +71945 -0.673004150390625 +71946 -0.020599365234375 +71947 -0.42694091796875 +71948 -0.02386474609375 +71949 -0.2100830078125 +71950 -0.026092529296875 +71951 -0.0362548828125 +71952 -0.02703857421875 +71953 0.10943603515625 +71954 -0.026641845703125 +71955 0.23516845703125 +71956 -0.024658203125 +71957 0.373687744140625 +71958 -0.021209716796875 +71959 0.517791748046875 +71960 -0.016998291015625 +71961 0.602783203125 +71962 -0.01214599609375 +71963 0.635711669921875 +71964 -0.00665283203125 +71965 0.655181884765625 +71966 -0.00079345703125 +71967 0.65948486328125 +71968 0.00506591796875 +71969 0.651275634765625 +71970 0.010498046875 +71971 0.61846923828125 +71972 0.015045166015625 +71973 0.53753662109375 +71974 0.0184326171875 +71975 0.404144287109375 +71976 0.02044677734375 +71977 0.22186279296875 +71978 0.0211181640625 +71979 0.003997802734375 +71980 0.020538330078125 +71981 -0.22100830078125 +71982 0.018890380859375 +71983 -0.42449951171875 +71984 0.016448974609375 +71985 -0.579833984375 +71986 0.013641357421875 +71987 -0.641876220703125 +71988 0.01055908203125 +71989 -0.6177978515625 +71990 0.006866455078125 +71991 -0.575531005859375 +71992 0.002716064453125 +71993 -0.526336669921875 +71994 -0.00128173828125 +71995 -0.42645263671875 +71996 -0.00469970703125 +71997 -0.2581787109375 +71998 -0.00762939453125 +71999 -0.068695068359375 +72000 -0.010223388671875 +72001 0.09222412109375 +72002 -0.012237548828125 +72003 0.232147216796875 +72004 -0.013519287109375 +72005 0.3509521484375 +72006 -0.0142822265625 +72007 0.410064697265625 +72008 -0.0147705078125 +72009 0.372955322265625 +72010 -0.014892578125 +72011 0.2554931640625 +72012 -0.014312744140625 +72013 0.10711669921875 +72014 -0.01300048828125 +72015 -0.052886962890625 +72016 -0.01080322265625 +72017 -0.186279296875 +72018 -0.0074462890625 +72019 -0.23291015625 +72020 -0.0032958984375 +72021 -0.209442138671875 +72022 0.00091552734375 +72023 -0.174163818359375 +72024 0.004974365234375 +72025 -0.126739501953125 +72026 0.008819580078125 +72027 -0.048126220703125 +72028 0.01214599609375 +72029 0.0426025390625 +72030 0.014495849609375 +72031 0.10748291015625 +72032 0.015777587890625 +72033 0.1409912109375 +72034 0.016387939453125 +72035 0.19708251953125 +72036 0.016357421875 +72037 0.273651123046875 +72038 0.01531982421875 +72039 0.31768798828125 +72040 0.01348876953125 +72041 0.341094970703125 +72042 0.01116943359375 +72043 0.368011474609375 +72044 0.00830078125 +72045 0.37249755859375 +72046 0.004608154296875 +72047 0.30072021484375 +72048 0.000274658203125 +72049 0.1517333984375 +72050 -0.003997802734375 +72051 -0.01470947265625 +72052 -0.00799560546875 +72053 -0.1883544921875 +72054 -0.011627197265625 +72055 -0.372711181640625 +72056 -0.01434326171875 +72057 -0.51397705078125 +72058 -0.015777587890625 +72059 -0.57177734375 +72060 -0.015838623046875 +72061 -0.53948974609375 +72062 -0.0146484375 +72063 -0.43511962890625 +72064 -0.012542724609375 +72065 -0.2962646484375 +72066 -0.0098876953125 +72067 -0.161102294921875 +72068 -0.006927490234375 +72069 -0.0435791015625 +72070 -0.003753662109375 +72071 0.060394287109375 +72072 -0.0006103515625 +72073 0.13665771484375 +72074 0.002197265625 +72075 0.170135498046875 +72076 0.004608154296875 +72077 0.16552734375 +72078 0.0067138671875 +72079 0.15728759765625 +72080 0.00848388671875 +72081 0.150787353515625 +72082 0.009613037109375 +72083 0.12200927734375 +72084 0.0101318359375 +72085 0.080108642578125 +72086 0.010223388671875 +72087 0.05126953125 +72088 0.01007080078125 +72089 0.062896728515625 +72090 0.009552001953125 +72091 0.09271240234375 +72092 0.00836181640625 +72093 0.092987060546875 +72094 0.00665283203125 +72095 0.07855224609375 +72096 0.004669189453125 +72097 0.06427001953125 +72098 0.002410888671875 +72099 0.0347900390625 +72100 0.0 +72101 -0.01171875 +72102 -0.0023193359375 +72103 -0.056060791015625 +72104 -0.00408935546875 +72105 -0.055511474609375 +72106 -0.005218505859375 +72107 -0.010467529296875 +72108 -0.006103515625 +72109 0.02508544921875 +72110 -0.006866455078125 +72111 0.025665283203125 +72112 -0.00726318359375 +72113 0.017333984375 +72114 -0.007293701171875 +72115 0.00189208984375 +72116 -0.007049560546875 +72117 -0.03173828125 +72118 -0.0064697265625 +72119 -0.071502685546875 +72120 -0.005767822265625 +72121 -0.13543701171875 +72122 -0.004974365234375 +72123 -0.219970703125 +72124 -0.00396728515625 +72125 -0.300506591796875 +72126 -0.002838134765625 +72127 -0.376312255859375 +72128 -0.001434326171875 +72129 -0.416107177734375 +72130 0.000518798828125 +72131 -0.371124267578125 +72132 0.002899169921875 +72133 -0.242279052734375 +72134 0.00531005859375 +72135 -0.069732666015625 +72136 0.007537841796875 +72137 0.125640869140625 +72138 0.009307861328125 +72139 0.31268310546875 +72140 0.01031494140625 +72141 0.45501708984375 +72142 0.0106201171875 +72143 0.554779052734375 +72144 0.01025390625 +72145 0.61065673828125 +72146 0.0091552734375 +72147 0.610931396484375 +72148 0.0072021484375 +72149 0.531463623046875 +72150 0.004608154296875 +72151 0.3883056640625 +72152 0.00189208984375 +72153 0.23468017578125 +72154 -0.0006103515625 +72155 0.095245361328125 +72156 -0.00262451171875 +72157 -0.00396728515625 +72158 -0.0040283203125 +72159 -0.04852294921875 +72160 -0.0048828125 +72161 -0.055145263671875 +72162 -0.00555419921875 +72163 -0.0758056640625 +72164 -0.0062255859375 +72165 -0.138702392578125 +72166 -0.00665283203125 +72167 -0.209197998046875 +72168 -0.006866455078125 +72169 -0.289031982421875 +72170 -0.006866455078125 +72171 -0.37884521484375 +72172 -0.006561279296875 +72173 -0.456329345703125 +72174 -0.005950927734375 +72175 -0.51641845703125 +72176 -0.0047607421875 +72177 -0.519287109375 +72178 -0.003021240234375 +72179 -0.458251953125 +72180 -0.001220703125 +72181 -0.384796142578125 +72182 0.000335693359375 +72183 -0.323699951171875 +72184 0.001678466796875 +72185 -0.269287109375 +72186 0.002960205078125 +72187 -0.1951904296875 +72188 0.004150390625 +72189 -0.100006103515625 +72190 0.005035400390625 +72191 -0.01055908203125 +72192 0.00567626953125 +72193 0.1033935546875 +72194 0.006195068359375 +72195 0.24908447265625 +72196 0.00653076171875 +72197 0.373199462890625 +72198 0.006591796875 +72199 0.45806884765625 +72200 0.00634765625 +72201 0.511474609375 +72202 0.005767822265625 +72203 0.565399169921875 +72204 0.004852294921875 +72205 0.61138916015625 +72206 0.003662109375 +72207 0.5897216796875 +72208 0.00225830078125 +72209 0.4906005859375 +72210 0.000701904296875 +72211 0.33148193359375 +72212 -0.0008544921875 +72213 0.147796630859375 +72214 -0.0023193359375 +72215 -0.01873779296875 +72216 -0.00360107421875 +72217 -0.140289306640625 +72218 -0.004608154296875 +72219 -0.191986083984375 +72220 -0.00531005859375 +72221 -0.184295654296875 +72222 -0.00567626953125 +72223 -0.161834716796875 +72224 -0.005706787109375 +72225 -0.166595458984375 +72226 -0.005401611328125 +72227 -0.19390869140625 +72228 -0.004791259765625 +72229 -0.22442626953125 +72230 -0.00390625 +72231 -0.279754638671875 +72232 -0.0028076171875 +72233 -0.3389892578125 +72234 -0.001556396484375 +72235 -0.3543701171875 +72236 -0.000213623046875 +72237 -0.348175048828125 +72238 0.0010986328125 +72239 -0.32598876953125 +72240 0.0023193359375 +72241 -0.2581787109375 +72242 0.003387451171875 +72243 -0.139801025390625 +72244 0.004241943359375 +72245 0.014617919921875 +72246 0.004852294921875 +72247 0.144378662109375 +72248 0.00518798828125 +72249 0.221038818359375 +72250 0.005218505859375 +72251 0.27069091796875 +72252 0.004974365234375 +72253 0.294036865234375 +72254 0.00445556640625 +72255 0.311767578125 +72256 0.003753662109375 +72257 0.339141845703125 +72258 0.00323486328125 +72259 0.360260009765625 +72260 0.002838134765625 +72261 0.360504150390625 +72262 0.001739501953125 +72263 0.308380126953125 +72264 -0.00067138671875 +72265 0.18170166015625 +72266 -0.003875732421875 +72267 0.0047607421875 +72268 -0.00689697265625 +72269 -0.17559814453125 +72270 -0.008758544921875 +72271 -0.3143310546875 +72272 -0.008544921875 +72273 -0.36785888671875 +72274 -0.006988525390625 +72275 -0.36248779296875 +72276 -0.0052490234375 +72277 -0.343536376953125 +72278 -0.003173828125 +72279 -0.3018798828125 +72280 -0.00067138671875 +72281 -0.231414794921875 +72282 0.002532958984375 +72283 -0.117645263671875 +72284 0.005615234375 +72285 0.007049560546875 +72286 0.00732421875 +72287 0.087982177734375 +72288 0.008026123046875 +72289 0.13946533203125 +72290 0.008056640625 +72291 0.17425537109375 +72292 0.007415771484375 +72293 0.188201904296875 +72294 0.00592041015625 +72295 0.171234130859375 +72296 0.00347900390625 +72297 0.118438720703125 +72298 0.0008544921875 +72299 0.05706787109375 +72300 -0.001800537109375 +72301 -0.010711669921875 +72302 -0.004608154296875 +72303 -0.0914306640625 +72304 -0.006988525390625 +72305 -0.162322998046875 +72306 -0.00823974609375 +72307 -0.194549560546875 +72308 -0.007415771484375 +72309 -0.1492919921875 +72310 -0.004364013671875 +72311 -0.02166748046875 +72312 -0.00067138671875 +72313 0.124053955078125 +72314 0.001800537109375 +72315 0.211151123046875 +72316 0.003021240234375 +72317 0.240447998046875 +72318 0.00372314453125 +72319 0.242218017578125 +72320 0.00408935546875 +72321 0.2257080078125 +72322 0.004119873046875 +72323 0.194366455078125 +72324 0.003021240234375 +72325 0.115509033203125 +72326 0.0013427734375 +72327 0.0128173828125 +72328 0.000457763671875 +72329 -0.053802490234375 +72330 -0.000274658203125 +72331 -0.110626220703125 +72332 -0.00189208984375 +72333 -0.199493408203125 +72334 -0.003814697265625 +72335 -0.29437255859375 +72336 -0.0045166015625 +72337 -0.33221435546875 +72338 -0.00323486328125 +72339 -0.27972412109375 +72340 -0.0010986328125 +72341 -0.185333251953125 +72342 0.0 +72343 -0.128204345703125 +72344 -9.1552734375e-05 +72345 -0.115692138671875 +72346 -0.0006103515625 +72347 -0.116455078125 +72348 -0.000946044921875 +72349 -0.105926513671875 +72350 -0.000335693359375 +72351 -0.053955078125 +72352 0.00146484375 +72353 0.048797607421875 +72354 0.003387451171875 +72355 0.157318115234375 +72356 0.004058837890625 +72357 0.212005615234375 +72358 0.003631591796875 +72359 0.218475341796875 +72360 0.003570556640625 +72361 0.23724365234375 +72362 0.00482177734375 +72363 0.30535888671875 +72364 0.006378173828125 +72365 0.38128662109375 +72366 0.0068359375 +72367 0.404449462890625 +72368 0.00665283203125 +72369 0.3944091796875 +72370 0.006744384765625 +72371 0.3885498046875 +72372 0.006500244140625 +72373 0.362640380859375 +72374 0.0048828125 +72375 0.27362060546875 +72376 0.001739501953125 +72377 0.11712646484375 +72378 -0.001708984375 +72379 -0.054901123046875 +72380 -0.004241943359375 +72381 -0.19085693359375 +72382 -0.005828857421875 +72383 -0.28570556640625 +72384 -0.0064697265625 +72385 -0.339263916015625 +72386 -0.0068359375 +72387 -0.3775634765625 +72388 -0.008026123046875 +72389 -0.445709228515625 +72390 -0.00982666015625 +72391 -0.535064697265625 +72392 -0.011871337890625 +72393 -0.629058837890625 +72394 -0.013427734375 +72395 -0.697601318359375 +72396 -0.013641357421875 +72397 -0.70391845703125 +72398 -0.012359619140625 +72399 -0.6424560546875 +72400 -0.009033203125 +72401 -0.491241455078125 +72402 -0.0040283203125 +72403 -0.265716552734375 +72404 0.001220703125 +72405 -0.023712158203125 +72406 0.0059814453125 +72407 0.201751708984375 +72408 0.009429931640625 +72409 0.375823974609375 +72410 0.011322021484375 +72411 0.485076904296875 +72412 0.012664794921875 +72413 0.56884765625 +72414 0.013671875 +72415 0.634765625 +72416 0.01324462890625 +72417 0.63763427734375 +72418 0.01116943359375 +72419 0.5660400390625 +72420 0.008697509765625 +72421 0.4720458984375 +72422 0.007080078125 +72423 0.40692138671875 +72424 0.006500244140625 +72425 0.3778076171875 +72426 0.006744384765625 +72427 0.376953125 +72428 0.006988525390625 +72429 0.371978759765625 +72430 0.006011962890625 +72431 0.313140869140625 +72432 0.003387451171875 +72433 0.184417724609375 +72434 -0.000244140625 +72435 0.011199951171875 +72436 -0.0040283203125 +72437 -0.171051025390625 +72438 -0.00738525390625 +72439 -0.33740234375 +72440 -0.010009765625 +72441 -0.47198486328125 +72442 -0.0115966796875 +72443 -0.560394287109375 +72444 -0.01165771484375 +72445 -0.58056640625 +72446 -0.01055908203125 +72447 -0.54754638671875 +72448 -0.00958251953125 +72449 -0.508575439453125 +72450 -0.008392333984375 +72451 -0.459503173828125 +72452 -0.007049560546875 +72453 -0.394378662109375 +72454 -0.00762939453125 +72455 -0.35260009765625 +72456 -0.00872802734375 +72457 -0.31170654296875 +72458 -0.006011962890625 +72459 -0.197418212890625 +72460 0.00079345703125 +72461 -0.007965087890625 +72462 0.00909423828125 +72463 0.207489013671875 +72464 0.016845703125 +72465 0.409210205078125 +72466 0.0228271484375 +72467 0.57208251953125 +72468 0.0255126953125 +72469 0.66595458984375 +72470 0.023223876953125 +72471 0.65875244140625 +72472 0.016998291015625 +72473 0.56744384765625 +72474 0.00909423828125 +72475 0.431396484375 +72476 0.001953125 +72477 0.29443359375 +72478 -0.00299072265625 +72479 0.182464599609375 +72480 -0.00762939453125 +72481 0.06365966796875 +72482 -0.012847900390625 +72483 -0.075958251953125 +72484 -0.01617431640625 +72485 -0.189422607421875 +72486 -0.017486572265625 +72487 -0.271942138671875 +72488 -0.01806640625 +72489 -0.342529296875 +72490 -0.01605224609375 +72491 -0.364166259765625 +72492 -0.011077880859375 +72493 -0.327239990234375 +72494 -0.005828857421875 +72495 -0.2769775390625 +72496 -0.002655029296875 +72497 -0.253692626953125 +72498 -0.000885009765625 +72499 -0.24365234375 +72500 0.00213623046875 +72501 -0.1983642578125 +72502 0.006500244140625 +72503 -0.116241455078125 +72504 0.010009765625 +72505 -0.036834716796875 +72506 0.012451171875 +72507 0.034881591796875 +72508 0.013519287109375 +72509 0.09124755859375 +72510 0.012054443359375 +72511 0.10888671875 +72512 0.010284423828125 +72513 0.125518798828125 +72514 0.00927734375 +72515 0.15771484375 +72516 0.007659912109375 +72517 0.17828369140625 +72518 0.00469970703125 +72519 0.17108154296875 +72520 0.00018310546875 +72521 0.129974365234375 +72522 -0.00421142578125 +72523 0.082427978515625 +72524 -0.0084228515625 +72525 0.027679443359375 +72526 -0.01416015625 +72527 -0.065643310546875 +72528 -0.019287109375 +72529 -0.15936279296875 +72530 -0.021575927734375 +72531 -0.21307373046875 +72532 -0.021514892578125 +72533 -0.234649658203125 +72534 -0.01788330078125 +72535 -0.2001953125 +72536 -0.01129150390625 +72537 -0.119171142578125 +72538 -0.003753662109375 +72539 -0.024749755859375 +72540 0.0047607421875 +72541 0.085784912109375 +72542 0.01214599609375 +72543 0.178131103515625 +72544 0.016265869140625 +72545 0.215576171875 +72546 0.01776123046875 +72547 0.211456298828125 +72548 0.017120361328125 +72549 0.17523193359375 +72550 0.015472412109375 +72551 0.128753662109375 +72552 0.01446533203125 +72553 0.1019287109375 +72554 0.012939453125 +72555 0.0743408203125 +72556 0.0107421875 +72557 0.04327392578125 +72558 0.009552001953125 +72559 0.038177490234375 +72560 0.010406494140625 +72561 0.076263427734375 +72562 0.012420654296875 +72563 0.14105224609375 +72564 0.01312255859375 +72565 0.186431884765625 +72566 0.011322021484375 +72567 0.188812255859375 +72568 0.006622314453125 +72569 0.1390380859375 +72570 -0.000579833984375 +72571 0.041778564453125 +72572 -0.008880615234375 +72573 -0.079437255859375 +72574 -0.017913818359375 +72575 -0.219390869140625 +72576 -0.027008056640625 +72577 -0.367828369140625 +72578 -0.03448486328125 +72579 -0.494873046875 +72580 -0.037841796875 +72581 -0.556243896484375 +72582 -0.034698486328125 +72583 -0.508697509765625 +72584 -0.026397705078125 +72585 -0.3756103515625 +72586 -0.0164794921875 +72587 -0.218902587890625 +72588 -0.006439208984375 +72589 -0.063751220703125 +72590 0.003692626953125 +72591 0.091552734375 +72592 0.01324462890625 +72593 0.23602294921875 +72594 0.0206298828125 +72595 0.342987060546875 +72596 0.02484130859375 +72597 0.39520263671875 +72598 0.025634765625 +72599 0.389373779296875 +72600 0.022857666015625 +72601 0.324249267578125 +72602 0.017852783203125 +72603 0.224090576171875 +72604 0.0125732421875 +72605 0.124267578125 +72606 0.007720947265625 +72607 0.037078857421875 +72608 0.004791259765625 +72609 -0.010101318359375 +72610 0.003692626953125 +72611 -0.019439697265625 +72612 0.002685546875 +72613 -0.022796630859375 +72614 0.00286865234375 +72615 -0.001556396484375 +72616 0.00494384765625 +72617 0.056304931640625 +72618 0.006500244140625 +72619 0.106719970703125 +72620 0.004669189453125 +72621 0.096893310546875 +72622 0.00042724609375 +72623 0.042694091796875 +72624 -0.003997802734375 +72625 -0.018035888671875 +72626 -0.008056640625 +72627 -0.07586669921875 +72628 -0.01104736328125 +72629 -0.11944580078125 +72630 -0.0135498046875 +72631 -0.15972900390625 +72632 -0.015899658203125 +72633 -0.202606201171875 +72634 -0.01812744140625 +72635 -0.24859619140625 +72636 -0.02069091796875 +72637 -0.30517578125 +72638 -0.0230712890625 +72639 -0.36212158203125 +72640 -0.02374267578125 +72641 -0.39141845703125 +72642 -0.020660400390625 +72643 -0.35528564453125 +72644 -0.013671875 +72645 -0.249969482421875 +72646 -0.0037841796875 +72647 -0.092864990234375 +72648 0.007354736328125 +72649 0.08905029296875 +72650 0.016357421875 +72651 0.2352294921875 +72652 0.02166748046875 +72653 0.318817138671875 +72654 0.0242919921875 +72655 0.358642578125 +72656 0.023834228515625 +72657 0.347747802734375 +72658 0.020294189453125 +72659 0.28564453125 +72660 0.0164794921875 +72661 0.223175048828125 +72662 0.014495849609375 +72663 0.196746826171875 +72664 0.01287841796875 +72665 0.179840087890625 +72666 0.01068115234375 +72667 0.155548095703125 +72668 0.009521484375 +72669 0.151214599609375 +72670 0.008880615234375 +72671 0.156951904296875 +72672 0.00653076171875 +72673 0.13177490234375 +72674 0.00396728515625 +72675 0.100799560546875 +72676 0.002471923828125 +72677 0.087127685546875 +72678 9.1552734375e-05 +72679 0.05487060546875 +72680 -0.00384521484375 +72681 -0.009002685546875 +72682 -0.009307861328125 +72683 -0.10400390625 +72684 -0.0162353515625 +72685 -0.229400634765625 +72686 -0.02301025390625 +72687 -0.35552978515625 +72688 -0.02734375 +72689 -0.441925048828125 +72690 -0.028472900390625 +72691 -0.473846435546875 +72692 -0.027191162109375 +72693 -0.464813232421875 +72694 -0.023773193359375 +72695 -0.419097900390625 +72696 -0.018157958984375 +72697 -0.334320068359375 +72698 -0.0113525390625 +72699 -0.227935791015625 +72700 -0.004730224609375 +72701 -0.12347412109375 +72702 0.001251220703125 +72703 -0.02764892578125 +72704 0.007537841796875 +72705 0.077667236328125 +72706 0.015533447265625 +72707 0.2132568359375 +72708 0.026580810546875 +72709 0.38885498046875 +72710 0.039459228515625 +72711 0.582794189453125 +72712 0.04925537109375 +72713 0.734039306640625 +72714 0.0526123046875 +72715 0.800140380859375 +72716 0.04949951171875 +72717 0.7783203125 +72718 0.039703369140625 +72719 0.6651611328125 +72720 0.023101806640625 +72721 0.45965576171875 +72722 0.002899169921875 +72723 0.199188232421875 +72724 -0.015380859375 +72725 -0.050689697265625 +72726 -0.0269775390625 +72727 -0.23297119140625 +72728 -0.030670166015625 +72729 -0.33013916015625 +72730 -0.029083251953125 +72731 -0.368408203125 +72732 -0.025238037109375 +72733 -0.378936767578125 +72734 -0.02081298828125 +72735 -0.376983642578125 +72736 -0.017547607421875 +72737 -0.37969970703125 +72738 -0.016021728515625 +72739 -0.391510009765625 +72740 -0.01397705078125 +72741 -0.385345458984375 +72742 -0.009765625 +72743 -0.3419189453125 +72744 -0.005279541015625 +72745 -0.28289794921875 +72746 -0.004241943359375 +72747 -0.251617431640625 +72748 -0.008148193359375 +72749 -0.266143798828125 +72750 -0.01214599609375 +72751 -0.273345947265625 +72752 -0.011077880859375 +72753 -0.216796875 +72754 -0.00750732421875 +72755 -0.128265380859375 +72756 -0.0064697265625 +72757 -0.068145751953125 +72758 -0.008331298828125 +72759 -0.0430908203125 +72760 -0.0103759765625 +72761 -0.024444580078125 +72762 -0.009521484375 +72763 0.020721435546875 +72764 -0.002777099609375 +72765 0.124481201171875 +72766 0.00738525390625 +72767 0.25787353515625 +72768 0.017364501953125 +72769 0.379119873046875 +72770 0.02642822265625 +72771 0.47991943359375 +72772 0.031707763671875 +72773 0.5281982421875 +72774 0.032012939453125 +72775 0.511138916015625 +72776 0.029632568359375 +72777 0.456207275390625 +72778 0.028289794921875 +72779 0.407470703125 +72780 0.02947998046875 +72781 0.383758544921875 +72782 0.030517578125 +72783 0.35687255859375 +72784 0.029876708984375 +72785 0.31182861328125 +72786 0.027587890625 +72787 0.250885009765625 +72788 0.022735595703125 +72789 0.1654052734375 +72790 0.013427734375 +72791 0.035247802734375 +72792 -0.0006103515625 +72793 -0.142059326171875 +72794 -0.0167236328125 +72795 -0.33563232421875 +72796 -0.034027099609375 +72797 -0.5345458984375 +72798 -0.050994873046875 +72799 -0.72186279296875 +72800 -0.062164306640625 +72801 -0.836669921875 +72802 -0.06341552734375 +72803 -0.8326416015625 +72804 -0.056396484375 +72805 -0.7296142578125 +72806 -0.045867919921875 +72807 -0.582550048828125 +72808 -0.03594970703125 +72809 -0.440093994140625 +72810 -0.0284423828125 +72811 -0.324310302734375 +72812 -0.02020263671875 +72813 -0.20147705078125 +72814 -0.00872802734375 +72815 -0.044647216796875 +72816 0.002349853515625 +72817 0.103973388671875 +72818 0.00946044921875 +72819 0.202392578125 +72820 0.013885498046875 +72821 0.264495849609375 +72822 0.019927978515625 +72823 0.338897705078125 +72824 0.029205322265625 +72825 0.443817138671875 +72826 0.0386962890625 +72827 0.545074462890625 +72828 0.046112060546875 +72829 0.6173095703125 +72830 0.050689697265625 +72831 0.6524658203125 +72832 0.053436279296875 +72833 0.66339111328125 +72834 0.054779052734375 +72835 0.6561279296875 +72836 0.052490234375 +72837 0.606781005859375 +72838 0.045196533203125 +72839 0.501190185546875 +72840 0.034027099609375 +72841 0.352783203125 +72842 0.02020263671875 +72843 0.176544189453125 +72844 0.002960205078125 +72845 -0.034820556640625 +72846 -0.015625 +72847 -0.258209228515625 +72848 -0.0311279296875 +72849 -0.44244384765625 +72850 -0.04254150390625 +72851 -0.5753173828125 +72852 -0.0494384765625 +72853 -0.65203857421875 +72854 -0.049041748046875 +72855 -0.641632080078125 +72856 -0.04296875 +72857 -0.562164306640625 +72858 -0.035064697265625 +72859 -0.458038330078125 +72860 -0.027069091796875 +72861 -0.350555419921875 +72862 -0.020721435546875 +72863 -0.260528564453125 +72864 -0.016326904296875 +72865 -0.192108154296875 +72866 -0.013519287109375 +72867 -0.141937255859375 +72868 -0.011474609375 +72869 -0.1021728515625 +72870 -0.00927734375 +72871 -0.062896728515625 +72872 -0.005767822265625 +72873 -0.011932373046875 +72874 0.0001220703125 +72875 0.062835693359375 +72876 0.00732421875 +72877 0.148712158203125 +72878 0.0155029296875 +72879 0.241729736328125 +72880 0.0252685546875 +72881 0.34912109375 +72882 0.035400390625 +72883 0.457305908203125 +72884 0.04388427734375 +72885 0.54388427734375 +72886 0.0474853515625 +72887 0.5728759765625 +72888 0.0428466796875 +72889 0.506591796875 +72890 0.030426025390625 +72891 0.351226806640625 +72892 0.013641357421875 +72893 0.146514892578125 +72894 -0.0029296875 +72895 -0.05523681640625 +72896 -0.016021728515625 +72897 -0.21624755859375 +72898 -0.025543212890625 +72899 -0.334930419921875 +72900 -0.03082275390625 +72901 -0.402984619140625 +72902 -0.03369140625 +72903 -0.4412841796875 +72904 -0.03826904296875 +72905 -0.49578857421875 +72906 -0.043975830078125 +72907 -0.5601806640625 +72908 -0.0478515625 +72909 -0.600738525390625 +72910 -0.04693603515625 +72911 -0.584228515625 +72912 -0.0384521484375 +72913 -0.47930908203125 +72914 -0.021759033203125 +72915 -0.27935791015625 +72916 0.0009765625 +72917 -0.0089111328125 +72918 0.0242919921875 +72919 0.268798828125 +72920 0.041961669921875 +72921 0.482818603515625 +72922 0.051483154296875 +72923 0.60369873046875 +72924 0.054595947265625 +72925 0.650421142578125 +72926 0.054962158203125 +72927 0.66400146484375 +72928 0.052337646484375 +72929 0.6414794921875 +72930 0.045867919921875 +72931 0.572540283203125 +72932 0.0391845703125 +72933 0.498138427734375 +72934 0.034149169921875 +72935 0.439453125 +72936 0.028900146484375 +72937 0.375518798828125 +72938 0.020599365234375 +72939 0.274505615234375 +72940 0.00677490234375 +72941 0.1087646484375 +72942 -0.0106201171875 +72943 -0.099395751953125 +72944 -0.02886962890625 +72945 -0.3182373046875 +72946 -0.048095703125 +72947 -0.5489501953125 +72948 -0.0667724609375 +72949 -0.7738037109375 +72950 -0.080352783203125 +72951 -0.86383056640625 +72952 -0.085968017578125 +72953 -0.870391845703125 +72954 -0.085235595703125 +72955 -0.86895751953125 +72956 -0.079315185546875 +72957 -0.861053466796875 +72958 -0.06671142578125 +72959 -0.765869140625 +72960 -0.04638671875 +72961 -0.5301513671875 +72962 -0.0184326171875 +72963 -0.214691162109375 +72964 0.013153076171875 +72965 0.137359619140625 +72966 0.043243408203125 +72967 0.474822998046875 +72968 0.068450927734375 +72969 0.76239013671875 +72970 0.086212158203125 +72971 0.867462158203125 +72972 0.097076416015625 +72973 0.870361328125 +72974 0.10003662109375 +72975 0.86480712890625 +72976 0.095855712890625 +72977 0.831817626953125 +72978 0.087493896484375 +72979 0.677581787109375 +72980 0.075469970703125 +72981 0.495880126953125 +72982 0.061737060546875 +72983 0.30767822265625 +72984 0.04620361328125 +72985 0.116180419921875 +72986 0.024566650390625 +72987 -0.110748291015625 +72988 -0.00445556640625 +72989 -0.381805419921875 +72990 -0.036285400390625 +72991 -0.6572265625 +72992 -0.064208984375 +72993 -0.857421875 +72994 -0.08355712890625 +72995 -0.870391845703125 +72996 -0.093902587890625 +72997 -0.870391845703125 +72998 -0.09881591796875 +72999 -0.86444091796875 +73000 -0.102813720703125 +73001 -0.85723876953125 +73002 -0.10382080078125 +73003 -0.790008544921875 +73004 -0.0953369140625 +73005 -0.62847900390625 +73006 -0.076873779296875 +73007 -0.3956298828125 +73008 -0.05218505859375 +73009 -0.126708984375 +73010 -0.0242919921875 +73011 0.150115966796875 +73012 0.005706787109375 +73013 0.424041748046875 +73014 0.034942626953125 +73015 0.670623779296875 +73016 0.0592041015625 +73017 0.854522705078125 +73018 0.0767822265625 +73019 0.866485595703125 +73020 0.086212158203125 +73021 0.86920166015625 +73022 0.09002685546875 +73023 0.8653564453125 +73024 0.090118408203125 +73025 0.857147216796875 +73026 0.08636474609375 +73027 0.766845703125 +73028 0.079498291015625 +73029 0.628509521484375 +73030 0.068756103515625 +73031 0.462127685546875 +73032 0.05718994140625 +73033 0.297210693359375 +73034 0.046173095703125 +73035 0.14862060546875 +73036 0.032745361328125 +73037 -0.00537109375 +73038 0.017547607421875 +73039 -0.15753173828125 +73040 -9.1552734375e-05 +73041 -0.31304931640625 +73042 -0.022216796875 +73043 -0.48876953125 +73044 -0.04351806640625 +73045 -0.6416015625 +73046 -0.061370849609375 +73047 -0.751373291015625 +73048 -0.078826904296875 +73049 -0.84619140625 +73050 -0.094390869140625 +73051 -0.861297607421875 +73052 -0.104278564453125 +73053 -0.863250732421875 +73054 -0.104827880859375 +73055 -0.856597900390625 +73056 -0.097564697265625 +73057 -0.7498779296875 +73058 -0.0894775390625 +73059 -0.624542236328125 +73060 -0.077850341796875 +73061 -0.47808837890625 +73062 -0.055511474609375 +73063 -0.253387451171875 +73064 -0.02777099609375 +73065 0.003692626953125 +73066 -0.0025634765625 +73067 0.2257080078125 +73068 0.021820068359375 +73069 0.427154541015625 +73070 0.049530029296875 +73071 0.643218994140625 +73072 0.079681396484375 +73073 0.855926513671875 +73074 0.1055908203125 +73075 0.870361328125 +73076 0.121551513671875 +73077 0.870361328125 +73078 0.128631591796875 +73079 0.862762451171875 +73080 0.126617431640625 +73081 0.79669189453125 +73082 0.114471435546875 +73083 0.595794677734375 +73084 0.095733642578125 +73085 0.362152099609375 +73086 0.073699951171875 +73087 0.1270751953125 +73088 0.05084228515625 +73089 -0.086944580078125 +73090 0.027252197265625 +73091 -0.2784423828125 +73092 -0.001373291015625 +73093 -0.484832763671875 +73094 -0.037567138671875 +73095 -0.729583740234375 +73096 -0.075439453125 +73097 -0.86688232421875 +73098 -0.107666015625 +73099 -0.870391845703125 +73100 -0.13385009765625 +73101 -0.86859130859375 +73102 -0.1539306640625 +73103 -0.86279296875 +73104 -0.163787841796875 +73105 -0.817962646484375 +73106 -0.158111572265625 +73107 -0.6116943359375 +73108 -0.136138916015625 +73109 -0.3128662109375 +73110 -0.101959228515625 +73111 0.039398193359375 +73112 -0.057952880859375 +73113 0.422821044921875 +73114 -0.008087158203125 +73115 0.805145263671875 +73116 0.039520263671875 +73117 0.870361328125 +73118 0.07818603515625 +73119 0.870361328125 +73120 0.10662841796875 +73121 0.860015869140625 +73122 0.124114990234375 +73123 0.727935791015625 +73124 0.130157470703125 +73125 0.48114013671875 +73126 0.1278076171875 +73127 0.2059326171875 +73128 0.119964599609375 +73129 -0.06103515625 +73130 0.107940673828125 +73131 -0.29913330078125 +73132 0.090118408203125 +73133 -0.516204833984375 +73134 0.064788818359375 +73135 -0.7252197265625 +73136 0.03497314453125 +73137 -0.85980224609375 +73138 0.004791259765625 +73139 -0.870391845703125 +73140 -0.022186279296875 +73141 -0.870391845703125 +73142 -0.0401611328125 +73143 -0.858062744140625 +73144 -0.048675537109375 +73145 -0.673004150390625 +73146 -0.05413818359375 +73147 -0.42694091796875 +73148 -0.06195068359375 +73149 -0.2100830078125 +73150 -0.071929931640625 +73151 -0.0362548828125 +73152 -0.0806884765625 +73153 0.10943603515625 +73154 -0.0859375 +73155 0.23516845703125 +73156 -0.082794189453125 +73157 0.373687744140625 +73158 -0.07159423828125 +73159 0.517791748046875 +73160 -0.05999755859375 +73161 0.602783203125 +73162 -0.04742431640625 +73163 0.635711669921875 +73164 -0.02996826171875 +73165 0.655181884765625 +73166 -0.008819580078125 +73167 0.65948486328125 +73168 0.0150146484375 +73169 0.651275634765625 +73170 0.03863525390625 +73171 0.61846923828125 +73172 0.0576171875 +73173 0.53753662109375 +73174 0.069854736328125 +73175 0.404144287109375 +73176 0.074249267578125 +73177 0.22186279296875 +73178 0.071044921875 +73179 0.003997802734375 +73180 0.0625 +73181 -0.22100830078125 +73182 0.0511474609375 +73183 -0.42449951171875 +73184 0.039642333984375 +73185 -0.579833984375 +73186 0.033172607421875 +73187 -0.641876220703125 +73188 0.031005859375 +73189 -0.6177978515625 +73190 0.025421142578125 +73191 -0.575531005859375 +73192 0.015838623046875 +73193 -0.526336669921875 +73194 0.008453369140625 +73195 -0.42645263671875 +73196 0.00653076171875 +73197 -0.2581787109375 +73198 0.0057373046875 +73199 -0.068695068359375 +73200 0.001434326171875 +73201 0.09222412109375 +73202 -0.004150390625 +73203 0.232147216796875 +73204 -0.009857177734375 +73205 0.3509521484375 +73206 -0.019287109375 +73207 0.410064697265625 +73208 -0.036041259765625 +73209 0.372955322265625 +73210 -0.0576171875 +73211 0.2554931640625 +73212 -0.077850341796875 +73213 0.10711669921875 +73214 -0.09442138671875 +73215 -0.052886962890625 +73216 -0.10260009765625 +73217 -0.186279296875 +73218 -0.09527587890625 +73219 -0.23291015625 +73220 -0.0760498046875 +73221 -0.209442138671875 +73222 -0.054107666015625 +73223 -0.174163818359375 +73224 -0.02996826171875 +73225 -0.126739501953125 +73226 -0.00140380859375 +73227 -0.048126220703125 +73228 0.027984619140625 +73229 0.0426025390625 +73230 0.051788330078125 +73231 0.10748291015625 +73232 0.068572998046875 +73233 0.1409912109375 +73234 0.085968017578125 +73235 0.19708251953125 +73236 0.103271484375 +73237 0.273651123046875 +73238 0.1123046875 +73239 0.31768798828125 +73240 0.11480712890625 +73241 0.341094970703125 +73242 0.114532470703125 +73243 0.368011474609375 +73244 0.10791015625 +73245 0.37249755859375 +73246 0.087310791015625 +73247 0.30072021484375 +73248 0.053192138671875 +73249 0.1517333984375 +73250 0.015167236328125 +73251 -0.01470947265625 +73252 -0.024444580078125 +73253 -0.1883544921875 +73254 -0.0654296875 +73255 -0.372711181640625 +73256 -0.0989990234375 +73257 -0.51397705078125 +73258 -0.11846923828125 +73259 -0.57177734375 +73260 -0.122314453125 +73261 -0.53948974609375 +73262 -0.112823486328125 +73263 -0.43511962890625 +73264 -0.095367431640625 +73265 -0.2962646484375 +73266 -0.075592041015625 +73267 -0.161102294921875 +73268 -0.05560302734375 +73269 -0.0435791015625 +73270 -0.0350341796875 +73271 0.060394287109375 +73272 -0.016326904296875 +73273 0.13665771484375 +73274 -0.002227783203125 +73275 0.170135498046875 +73276 0.007415771484375 +73277 0.16552734375 +73278 0.017181396484375 +73279 0.15728759765625 +73280 0.027252197265625 +73281 0.150787353515625 +73282 0.033416748046875 +73283 0.12200927734375 +73284 0.0364990234375 +73285 0.080108642578125 +73286 0.039947509765625 +73287 0.05126953125 +73288 0.0474853515625 +73289 0.062896728515625 +73290 0.055511474609375 +73291 0.09271240234375 +73292 0.0567626953125 +73293 0.092987060546875 +73294 0.053436279296875 +73295 0.07855224609375 +73296 0.047882080078125 +73297 0.06427001953125 +73298 0.038055419921875 +73299 0.0347900390625 +73300 0.0240478515625 +73301 -0.01171875 +73302 0.0091552734375 +73303 -0.056060791015625 +73304 0.000274658203125 +73305 -0.055511474609375 +73306 -0.002105712890625 +73307 -0.010467529296875 +73308 -0.005584716796875 +73309 0.02508544921875 +73310 -0.013519287109375 +73311 0.025665283203125 +73312 -0.021575927734375 +73313 0.017333984375 +73314 -0.0291748046875 +73315 0.00189208984375 +73316 -0.0377197265625 +73317 -0.03173828125 +73318 -0.045257568359375 +73319 -0.071502685546875 +73320 -0.054473876953125 +73321 -0.13543701171875 +73322 -0.06488037109375 +73323 -0.219970703125 +73324 -0.072967529296875 +73325 -0.300506591796875 +73326 -0.078887939453125 +73327 -0.376312255859375 +73328 -0.07830810546875 +73329 -0.416107177734375 +73330 -0.064300537109375 +73331 -0.371124267578125 +73332 -0.03741455078125 +73333 -0.242279052734375 +73334 -0.00408935546875 +73335 -0.069732666015625 +73336 0.0321044921875 +73337 0.125640869140625 +73338 0.066131591796875 +73339 0.31268310546875 +73340 0.092193603515625 +73341 0.45501708984375 +73342 0.11041259765625 +73343 0.554779052734375 +73344 0.120452880859375 +73345 0.61065673828125 +73346 0.120513916015625 +73347 0.610931396484375 +73348 0.1070556640625 +73349 0.531463623046875 +73350 0.082611083984375 +73351 0.3883056640625 +73352 0.05535888671875 +73353 0.23468017578125 +73354 0.029296875 +73355 0.095245361328125 +73356 0.00860595703125 +73357 -0.00396728515625 +73358 -0.00421142578125 +73359 -0.04852294921875 +73360 -0.01129150390625 +73361 -0.055145263671875 +73362 -0.020111083984375 +73363 -0.0758056640625 +73364 -0.03460693359375 +73365 -0.138702392578125 +73366 -0.04931640625 +73367 -0.209197998046875 +73368 -0.064300537109375 +73369 -0.289031982421875 +73370 -0.07952880859375 +73371 -0.37884521484375 +73372 -0.091583251953125 +73373 -0.456329345703125 +73374 -0.0997314453125 +73375 -0.51641845703125 +73376 -0.09808349609375 +73377 -0.519287109375 +73378 -0.085784912109375 +73379 -0.458251953125 +73380 -0.070770263671875 +73381 -0.384796142578125 +73382 -0.056976318359375 +73383 -0.323699951171875 +73384 -0.043792724609375 +73385 -0.269287109375 +73386 -0.027557373046875 +73387 -0.1951904296875 +73388 -0.00836181640625 +73389 -0.100006103515625 +73390 0.00946044921875 +73391 -0.01055908203125 +73392 0.03021240234375 +73393 0.1033935546875 +73394 0.0548095703125 +73395 0.24908447265625 +73396 0.07513427734375 +73397 0.373199462890625 +73398 0.088470458984375 +73399 0.45806884765625 +73400 0.095977783203125 +73401 0.511474609375 +73402 0.102508544921875 +73403 0.565399169921875 +73404 0.10693359375 +73405 0.61138916015625 +73406 0.1004638671875 +73407 0.5897216796875 +73408 0.081817626953125 +73409 0.4906005859375 +73410 0.0538330078125 +73411 0.33148193359375 +73412 0.022064208984375 +73413 0.147796630859375 +73414 -0.006988525390625 +73415 -0.01873779296875 +73416 -0.0289306640625 +73417 -0.140289306640625 +73418 -0.039825439453125 +73419 -0.191986083984375 +73420 -0.04107666015625 +73421 -0.184295654296875 +73422 -0.039276123046875 +73423 -0.161834716796875 +73424 -0.040679931640625 +73425 -0.166595458984375 +73426 -0.044586181640625 +73427 -0.19390869140625 +73428 -0.048126220703125 +73429 -0.22442626953125 +73430 -0.054595947265625 +73431 -0.279754638671875 +73432 -0.06097412109375 +73433 -0.3389892578125 +73434 -0.060272216796875 +73435 -0.3543701171875 +73436 -0.055999755859375 +73437 -0.348175048828125 +73438 -0.0491943359375 +73439 -0.32598876953125 +73440 -0.035614013671875 +73441 -0.2581787109375 +73442 -0.01470947265625 +73443 -0.139801025390625 +73444 0.01116943359375 +73445 0.014617919921875 +73446 0.032745361328125 +73447 0.144378662109375 +73448 0.045684814453125 +73449 0.221038818359375 +73450 0.0538330078125 +73451 0.27069091796875 +73452 0.05731201171875 +73453 0.294036865234375 +73454 0.059234619140625 +73455 0.311767578125 +73456 0.061981201171875 +73457 0.339141845703125 +73458 0.063262939453125 +73459 0.360260009765625 +73460 0.061004638671875 +73461 0.360504150390625 +73462 0.050537109375 +73463 0.308380126953125 +73464 0.02862548828125 +73465 0.18170166015625 +73466 -0.000823974609375 +73467 0.0047607421875 +73468 -0.030609130859375 +73469 -0.17559814453125 +73470 -0.053741455078125 +73471 -0.3143310546875 +73472 -0.063140869140625 +73473 -0.36785888671875 +73474 -0.063140869140625 +73475 -0.36248779296875 +73476 -0.061187744140625 +73477 -0.343536376953125 +73478 -0.0552978515625 +73479 -0.3018798828125 +73480 -0.044097900390625 +73481 -0.231414794921875 +73482 -0.02471923828125 +73483 -0.117645263671875 +73484 -0.003021240234375 +73485 0.007049560546875 +73486 0.011016845703125 +73487 0.087982177734375 +73488 0.02008056640625 +73489 0.13946533203125 +73490 0.02655029296875 +73491 0.17425537109375 +73492 0.02960205078125 +73493 0.188201904296875 +73494 0.02734375 +73495 0.171234130859375 +73496 0.018768310546875 +73497 0.118438720703125 +73498 0.008819580078125 +73499 0.05706787109375 +73500 -0.002166748046875 +73501 -0.010711669921875 +73502 -0.0155029296875 +73503 -0.0914306640625 +73504 -0.027099609375 +73505 -0.162322998046875 +73506 -0.03173828125 +73507 -0.194549560546875 +73508 -0.0223388671875 +73509 -0.1492919921875 +73510 0.00189208984375 +73511 -0.02166748046875 +73512 0.029083251953125 +73513 0.124053955078125 +73514 0.04510498046875 +73515 0.211151123046875 +73516 0.050140380859375 +73517 0.240447998046875 +73518 0.049774169921875 +73519 0.242218017578125 +73520 0.0457763671875 +73521 0.2257080078125 +73522 0.038848876953125 +73523 0.194366455078125 +73524 0.0230712890625 +73525 0.115509033203125 +73526 0.00286865234375 +73527 0.0128173828125 +73528 -0.010650634765625 +73529 -0.053802490234375 +73530 -0.022247314453125 +73531 -0.110626220703125 +73532 -0.039581298828125 +73533 -0.199493408203125 +73534 -0.057830810546875 +73535 -0.29437255859375 +73536 -0.065338134765625 +73537 -0.33221435546875 +73538 -0.05596923828125 +73539 -0.27972412109375 +73540 -0.03863525390625 +73541 -0.185333251953125 +73542 -0.02789306640625 +73543 -0.128204345703125 +73544 -0.025115966796875 +73545 -0.115692138671875 +73546 -0.0245361328125 +73547 -0.116455078125 +73548 -0.021728515625 +73549 -0.105926513671875 +73550 -0.01116943359375 +73551 -0.053955078125 +73552 0.008758544921875 +73553 0.048797607421875 +73554 0.029754638671875 +73555 0.157318115234375 +73556 0.040740966796875 +73557 0.212005615234375 +73558 0.042724609375 +73559 0.218475341796875 +73560 0.04681396484375 +73561 0.23724365234375 +73562 0.059814453125 +73563 0.30535888671875 +73564 0.07403564453125 +73565 0.38128662109375 +73566 0.07830810546875 +73567 0.404449462890625 +73568 0.076263427734375 +73569 0.3944091796875 +73570 0.07476806640625 +73571 0.3885498046875 +73572 0.069427490234375 +73573 0.362640380859375 +73574 0.0523681640625 +73575 0.27362060546875 +73576 0.022796630859375 +73577 0.11712646484375 +73578 -0.009674072265625 +73579 -0.054901123046875 +73580 -0.03546142578125 +73581 -0.19085693359375 +73582 -0.053619384765625 +73583 -0.28570556640625 +73584 -0.064056396484375 +73585 -0.339263916015625 +73586 -0.071563720703125 +73587 -0.3775634765625 +73588 -0.084381103515625 +73589 -0.445709228515625 +73590 -0.1009521484375 +73591 -0.535064697265625 +73592 -0.11822509765625 +73593 -0.629058837890625 +73594 -0.130645751953125 +73595 -0.697601318359375 +73596 -0.131439208984375 +73597 -0.70391845703125 +73598 -0.119659423828125 +73599 -0.6424560546875 +73600 -0.091278076171875 +73601 -0.491241455078125 +73602 -0.049163818359375 +73603 -0.265716552734375 +73604 -0.003997802734375 +73605 -0.023712158203125 +73606 0.0380859375 +73607 0.201751708984375 +73608 0.070648193359375 +73609 0.375823974609375 +73610 0.0911865234375 +73611 0.485076904296875 +73612 0.106903076171875 +73613 0.56884765625 +73614 0.11920166015625 +73615 0.634765625 +73616 0.1197509765625 +73617 0.63763427734375 +73618 0.106475830078125 +73619 0.5660400390625 +73620 0.088958740234375 +73621 0.4720458984375 +73622 0.07666015625 +73623 0.40692138671875 +73624 0.070892333984375 +73625 0.3778076171875 +73626 0.070281982421875 +73627 0.376953125 +73628 0.068878173828125 +73629 0.371978759765625 +73630 0.057525634765625 +73631 0.313140869140625 +73632 0.033294677734375 +73633 0.184417724609375 +73634 0.00091552734375 +73635 0.011199951171875 +73636 -0.03302001953125 +73637 -0.171051025390625 +73638 -0.063873291015625 +73639 -0.33740234375 +73640 -0.088714599609375 +73641 -0.47198486328125 +73642 -0.10491943359375 +73643 -0.560394287109375 +73644 -0.10845947265625 +73645 -0.58056640625 +73646 -0.10211181640625 +73647 -0.54754638671875 +73648 -0.0946044921875 +73649 -0.508575439453125 +73650 -0.085174560546875 +73651 -0.459503173828125 +73652 -0.07275390625 +73653 -0.394378662109375 +73654 -0.0645751953125 +73655 -0.35260009765625 +73656 -0.056549072265625 +73657 -0.31170654296875 +73658 -0.035064697265625 +73659 -0.197418212890625 +73660 0.00018310546875 +73661 -0.007965087890625 +73662 0.04010009765625 +73663 0.207489013671875 +73664 0.077362060546875 +73665 0.409210205078125 +73666 0.10736083984375 +73667 0.57208251953125 +73668 0.124542236328125 +73669 0.66595458984375 +73670 0.123016357421875 +73671 0.65875244140625 +73672 0.105926513671875 +73673 0.56744384765625 +73674 0.080535888671875 +73675 0.431396484375 +73676 0.054931640625 +73677 0.29443359375 +73678 0.033905029296875 +73679 0.182464599609375 +73680 0.011627197265625 +73681 0.06365966796875 +73682 -0.014434814453125 +73683 -0.075958251953125 +73684 -0.035614013671875 +73685 -0.189422607421875 +73686 -0.05096435546875 +73687 -0.271942138671875 +73688 -0.06402587890625 +73689 -0.342529296875 +73690 -0.068023681640625 +73691 -0.364166259765625 +73692 -0.061187744140625 +73693 -0.327239990234375 +73694 -0.051849365234375 +73695 -0.2769775390625 +73696 -0.047393798828125 +73697 -0.253692626953125 +73698 -0.045318603515625 +73699 -0.24365234375 +73700 -0.0367431640625 +73701 -0.1983642578125 +73702 -0.0213623046875 +73703 -0.116241455078125 +73704 -0.006439208984375 +73705 -0.036834716796875 +73706 0.007049560546875 +73707 0.034881591796875 +73708 0.017669677734375 +73709 0.09124755859375 +73710 0.0211181640625 +73711 0.10888671875 +73712 0.024322509765625 +73713 0.125518798828125 +73714 0.03033447265625 +73715 0.15771484375 +73716 0.03411865234375 +73717 0.17828369140625 +73718 0.03271484375 +73719 0.17108154296875 +73720 0.024993896484375 +73721 0.129974365234375 +73722 0.01605224609375 +73723 0.082427978515625 +73724 0.0057373046875 +73725 0.027679443359375 +73726 -0.01165771484375 +73727 -0.065643310546875 +73728 -0.02874755859375 +73729 -0.15936279296875 +73730 -0.038482666015625 +73731 -0.21307373046875 +73732 -0.04296875 +73733 -0.234649658203125 +73734 -0.036651611328125 +73735 -0.2001953125 +73736 -0.021148681640625 +73737 -0.119171142578125 +73738 -0.00323486328125 +73739 -0.024749755859375 +73740 0.017974853515625 +73741 0.085784912109375 +73742 0.035308837890625 +73743 0.178131103515625 +73744 0.04107666015625 +73745 0.215576171875 +73746 0.038330078125 +73747 0.211456298828125 +73748 0.029266357421875 +73749 0.17523193359375 +73750 0.01861572265625 +73751 0.128753662109375 +73752 0.01287841796875 +73753 0.1019287109375 +73754 0.007598876953125 +73755 0.0743408203125 +73756 0.002105712890625 +73757 0.04327392578125 +73758 0.002655029296875 +73759 0.038177490234375 +73760 0.012847900390625 +73761 0.076263427734375 +73762 0.028961181640625 +73763 0.14105224609375 +73764 0.040924072265625 +73765 0.186431884765625 +73766 0.04351806640625 +73767 0.188812255859375 +73768 0.034637451171875 +73769 0.1390380859375 +73770 0.01519775390625 +73771 0.041778564453125 +73772 -0.009796142578125 +73773 -0.079437255859375 +73774 -0.039276123046875 +73775 -0.219390869140625 +73776 -0.07098388671875 +73777 -0.367828369140625 +73778 -0.0985107421875 +73779 -0.494873046875 +73780 -0.112274169921875 +73781 -0.556243896484375 +73782 -0.1029052734375 +73783 -0.508697509765625 +73784 -0.075408935546875 +73785 -0.3756103515625 +73786 -0.0430908203125 +73787 -0.218902587890625 +73788 -0.01129150390625 +73789 -0.063751220703125 +73790 0.02044677734375 +73791 0.091552734375 +73792 0.049835205078125 +73793 0.23602294921875 +73794 0.07122802734375 +73795 0.342987060546875 +73796 0.08099365234375 +73797 0.39520263671875 +73798 0.0784912109375 +73799 0.389373779296875 +73800 0.06353759765625 +73801 0.324249267578125 +73802 0.041412353515625 +73803 0.224090576171875 +73804 0.019775390625 +73805 0.124267578125 +73806 0.001251220703125 +73807 0.037078857421875 +73808 -0.00823974609375 +73809 -0.010101318359375 +73810 -0.009246826171875 +73811 -0.019439697265625 +73812 -0.0086669921875 +73813 -0.022796630859375 +73814 -0.002593994140625 +73815 -0.001556396484375 +73816 0.01141357421875 +73817 0.056304931640625 +73818 0.0238037109375 +73819 0.106719970703125 +73820 0.023101806640625 +73821 0.096893310546875 +73822 0.01263427734375 +73823 0.042694091796875 +73824 0.000518798828125 +73825 -0.018035888671875 +73826 -0.01123046875 +73827 -0.07586669921875 +73828 -0.02020263671875 +73829 -0.11944580078125 +73830 -0.028778076171875 +73831 -0.15972900390625 +73832 -0.0382080078125 +73833 -0.202606201171875 +73834 -0.048553466796875 +73835 -0.24859619140625 +73836 -0.0614013671875 +73837 -0.30517578125 +73838 -0.074493408203125 +73839 -0.36212158203125 +73840 -0.081756591796875 +73841 -0.39141845703125 +73842 -0.074981689453125 +73843 -0.35528564453125 +73844 -0.053314208984375 +73845 -0.249969482421875 +73846 -0.020477294921875 +73847 -0.092864990234375 +73848 0.01776123046875 +73849 0.08905029296875 +73850 0.04840087890625 +73851 0.2352294921875 +73852 0.065673828125 +73853 0.318817138671875 +73854 0.07366943359375 +73855 0.358642578125 +73856 0.0709228515625 +73857 0.347747802734375 +73858 0.057373046875 +73859 0.28564453125 +73860 0.04400634765625 +73861 0.223175048828125 +73862 0.038665771484375 +73863 0.196746826171875 +73864 0.03558349609375 +73865 0.179840087890625 +73866 0.03106689453125 +73867 0.155548095703125 +73868 0.030975341796875 +73869 0.151214599609375 +73870 0.033111572265625 +73871 0.156951904296875 +73872 0.028564453125 +73873 0.13177490234375 +73874 0.022735595703125 +73875 0.100799560546875 +73876 0.020538330078125 +73877 0.087127685546875 +73878 0.014190673828125 +73879 0.05487060546875 +73880 0.000885009765625 +73881 -0.009002685546875 +73882 -0.019287109375 +73883 -0.10400390625 +73884 -0.04620361328125 +73885 -0.229400634765625 +73886 -0.073455810546875 +73887 -0.35552978515625 +73888 -0.092254638671875 +73889 -0.441925048828125 +73890 -0.09942626953125 +73891 -0.473846435546875 +73892 -0.09783935546875 +73893 -0.464813232421875 +73894 -0.08843994140625 +73895 -0.419097900390625 +73896 -0.0706787109375 +73897 -0.334320068359375 +73898 -0.048309326171875 +73899 -0.227935791015625 +73900 -0.026336669921875 +73901 -0.12347412109375 +73902 -0.006195068359375 +73903 -0.02764892578125 +73904 0.016021728515625 +73905 0.077667236328125 +73906 0.044830322265625 +73907 0.2132568359375 +73908 0.082366943359375 +73909 0.38885498046875 +73910 0.123992919921875 +73911 0.582794189453125 +73912 0.156494140625 +73913 0.734039306640625 +73914 0.170684814453125 +73915 0.800140380859375 +73916 0.165985107421875 +73917 0.7783203125 +73918 0.14166259765625 +73919 0.6651611328125 +73920 0.09747314453125 +73921 0.45965576171875 +73922 0.041534423828125 +73923 0.199188232421875 +73924 -0.011993408203125 +73925 -0.050689697265625 +73926 -0.05084228515625 +73927 -0.23297119140625 +73928 -0.071258544921875 +73929 -0.33013916015625 +73930 -0.07891845703125 +73931 -0.368408203125 +73932 -0.080596923828125 +73933 -0.378936767578125 +73934 -0.079681396484375 +73935 -0.376983642578125 +73936 -0.079864501953125 +73937 -0.37969970703125 +73938 -0.082122802734375 +73939 -0.391510009765625 +73940 -0.080596923828125 +73941 -0.385345458984375 +73942 -0.0711669921875 +73943 -0.3419189453125 +73944 -0.0584716796875 +73945 -0.28289794921875 +73946 -0.0518798828125 +73947 -0.251617431640625 +73948 -0.0552978515625 +73949 -0.266143798828125 +73950 -0.057220458984375 +73951 -0.273345947265625 +73952 -0.045440673828125 +73953 -0.216796875 +73954 -0.026763916015625 +73955 -0.128265380859375 +73956 -0.01422119140625 +73957 -0.068145751953125 +73958 -0.00921630859375 +73959 -0.0430908203125 +73960 -0.00555419921875 +73961 -0.024444580078125 +73962 0.00384521484375 +73963 0.020721435546875 +73964 0.02593994140625 +73965 0.124481201171875 +73966 0.05450439453125 +73967 0.25787353515625 +73968 0.08050537109375 +73969 0.379119873046875 +73970 0.1021728515625 +73971 0.47991943359375 +73972 0.112579345703125 +73973 0.5281982421875 +73974 0.10894775390625 +73975 0.511138916015625 +73976 0.097198486328125 +73977 0.456207275390625 +73978 0.08685302734375 +73979 0.407470703125 +73980 0.08197021484375 +73981 0.383758544921875 +73982 0.076416015625 +73983 0.35687255859375 +73984 0.067474365234375 +73985 0.31182861328125 +73986 0.055908203125 +73987 0.250885009765625 +73988 0.0391845703125 +73989 0.1654052734375 +73990 0.0118408203125 +73991 0.035247802734375 +73992 -0.027191162109375 +73993 -0.142059326171875 +73994 -0.070648193359375 +73995 -0.33563232421875 +73996 -0.11614990234375 +73997 -0.5345458984375 +73998 -0.159759521484375 +73999 -0.72186279296875 +74000 -0.186553955078125 +74001 -0.836669921875 +74002 -0.18511962890625 +74003 -0.8326416015625 +74004 -0.160369873046875 +74005 -0.7296142578125 +74006 -0.125885009765625 +74007 -0.582550048828125 +74008 -0.09356689453125 +74009 -0.440093994140625 +74010 -0.06866455078125 +74011 -0.324310302734375 +74012 -0.042572021484375 +74013 -0.20147705078125 +74014 -0.008331298828125 +74015 -0.044647216796875 +74016 0.023834228515625 +74017 0.103973388671875 +74018 0.043792724609375 +74019 0.202392578125 +74020 0.055206298828125 +74021 0.264495849609375 +74022 0.070343017578125 +74023 0.338897705078125 +74024 0.0938720703125 +74025 0.443817138671875 +74026 0.117431640625 +74027 0.545074462890625 +74028 0.134796142578125 +74029 0.6173095703125 +74030 0.143951416015625 +74031 0.6524658203125 +74032 0.148040771484375 +74033 0.66339111328125 +74034 0.148468017578125 +74035 0.6561279296875 +74036 0.13916015625 +74037 0.606781005859375 +74038 0.116424560546875 +74039 0.501190185546875 +74040 0.083404541015625 +74041 0.352783203125 +74042 0.0435791015625 +74043 0.176544189453125 +74044 -0.0050048828125 +74045 -0.034820556640625 +74046 -0.05682373046875 +74047 -0.258209228515625 +74048 -0.099395751953125 +74049 -0.44244384765625 +74050 -0.129852294921875 +74051 -0.5753173828125 +74052 -0.147125244140625 +74053 -0.65203857421875 +74054 -0.14361572265625 +74055 -0.641632080078125 +74056 -0.123870849609375 +74057 -0.562164306640625 +74058 -0.098846435546875 +74059 -0.458038330078125 +74060 -0.073760986328125 +74061 -0.350555419921875 +74062 -0.05364990234375 +74063 -0.260528564453125 +74064 -0.039398193359375 +74065 -0.192108154296875 +74066 -0.030029296875 +74067 -0.141937255859375 +74068 -0.023406982421875 +74069 -0.1021728515625 +74070 -0.016876220703125 +74071 -0.062896728515625 +74072 -0.007232666015625 +74073 -0.011932373046875 +74074 0.008636474609375 +74075 0.062835693359375 +74076 0.027740478515625 +74077 0.148712158203125 +74078 0.049163818359375 +74079 0.241729736328125 +74080 0.07476806640625 +74081 0.34912109375 +74082 0.10125732421875 +74083 0.457305908203125 +74084 0.123077392578125 +74085 0.54388427734375 +74086 0.131256103515625 +74087 0.5728759765625 +74088 0.11639404296875 +74089 0.506591796875 +74090 0.07989501953125 +74091 0.351226806640625 +74092 0.031494140625 +74093 0.146514892578125 +74094 -0.015960693359375 +74095 -0.05523681640625 +74096 -0.05322265625 +74097 -0.21624755859375 +74098 -0.080047607421875 +74099 -0.334930419921875 +74100 -0.094512939453125 +74101 -0.402984619140625 +74102 -0.1019287109375 +74103 -0.4412841796875 +74104 -0.113800048828125 +74105 -0.49578857421875 +74106 -0.128662109375 +74107 -0.5601806640625 +74108 -0.13818359375 +74109 -0.600738525390625 +74110 -0.1341552734375 +74111 -0.584228515625 +74112 -0.1087646484375 +74113 -0.47930908203125 +74114 -0.060302734375 +74115 -0.27935791015625 +74116 0.00518798828125 +74117 -0.0089111328125 +74118 0.072113037109375 +74119 0.268798828125 +74120 0.12298583984375 +74121 0.482818603515625 +74122 0.150665283203125 +74123 0.60369873046875 +74124 0.15997314453125 +74125 0.650421142578125 +74126 0.16119384765625 +74127 0.66400146484375 +74128 0.153717041015625 +74129 0.6414794921875 +74130 0.13507080078125 +74131 0.572540283203125 +74132 0.115509033203125 +74133 0.498138427734375 +74134 0.100311279296875 +74135 0.439453125 +74136 0.08428955078125 +74137 0.375518798828125 +74138 0.0595703125 +74139 0.274505615234375 +74140 0.019256591796875 +74141 0.1087646484375 +74142 -0.031158447265625 +74143 -0.099395751953125 +74144 -0.0838623046875 +74145 -0.3182373046875 +74146 -0.139251708984375 +74147 -0.5489501953125 +74148 -0.193023681640625 +74149 -0.7738037109375 +74150 -0.232177734375 +74151 -0.86383056640625 +74152 -0.24859619140625 +74153 -0.870391845703125 +74154 -0.246734619140625 +74155 -0.86895751953125 +74156 -0.229949951171875 +74157 -0.861053466796875 +74158 -0.194061279296875 +74159 -0.765869140625 +74160 -0.136322021484375 +74161 -0.5301513671875 +74162 -0.058502197265625 +74163 -0.214691162109375 +74164 0.028656005859375 +74165 0.137359619140625 +74166 0.11248779296875 +74167 0.474822998046875 +74168 0.184234619140625 +74169 0.76239013671875 +74170 0.237274169921875 +74171 0.867462158203125 +74172 0.271759033203125 +74173 0.870361328125 +74174 0.284912109375 +74175 0.86480712890625 +74176 0.278167724609375 +74177 0.831817626953125 +74178 0.257659912109375 +74179 0.677581787109375 +74180 0.224945068359375 +74181 0.495880126953125 +74182 0.1846923828125 +74183 0.30767822265625 +74184 0.137542724609375 +74185 0.116180419921875 +74186 0.07568359375 +74187 -0.110748291015625 +74188 -0.0025634765625 +74189 -0.381805419921875 +74190 -0.0865478515625 +74191 -0.6572265625 +74192 -0.16143798828125 +74193 -0.857421875 +74194 -0.21661376953125 +74195 -0.870391845703125 +74196 -0.250396728515625 +74197 -0.870391845703125 +74198 -0.26953125 +74199 -0.86444091796875 +74200 -0.282958984375 +74201 -0.85723876953125 +74202 -0.28619384765625 +74203 -0.790008544921875 +74204 -0.265869140625 +74205 -0.62847900390625 +74206 -0.221282958984375 +74207 -0.3956298828125 +74208 -0.16064453125 +74209 -0.126708984375 +74210 -0.090789794921875 +74211 0.150115966796875 +74212 -0.014678955078125 +74213 0.424041748046875 +74214 0.060943603515625 +74215 0.670623779296875 +74216 0.12646484375 +74217 0.854522705078125 +74218 0.177490234375 +74219 0.866485595703125 +74220 0.210235595703125 +74221 0.86920166015625 +74222 0.229248046875 +74223 0.8653564453125 +74224 0.237884521484375 +74225 0.857147216796875 +74226 0.235504150390625 +74227 0.766845703125 +74228 0.22344970703125 +74229 0.628509521484375 +74230 0.20013427734375 +74231 0.462127685546875 +74232 0.1719970703125 +74233 0.297210693359375 +74234 0.14215087890625 +74235 0.14862060546875 +74236 0.105010986328125 +74237 -0.00537109375 +74238 0.0625 +74239 -0.15753173828125 +74240 0.0133056640625 +74241 -0.31304931640625 +74242 -0.04608154296875 +74243 -0.48876953125 +74244 -0.102691650390625 +74245 -0.6416015625 +74246 -0.150390625 +74247 -0.751373291015625 +74248 -0.1962890625 +74249 -0.84619140625 +74250 -0.236846923828125 +74251 -0.861297607421875 +74252 -0.263214111328125 +74253 -0.863250732421875 +74254 -0.266754150390625 +74255 -0.856597900390625 +74256 -0.25103759765625 +74257 -0.7498779296875 +74258 -0.232269287109375 +74259 -0.624542236328125 +74260 -0.204132080078125 +74261 -0.47808837890625 +74262 -0.1500244140625 +74263 -0.253387451171875 +74264 -0.082366943359375 +74265 0.003692626953125 +74266 -0.019927978515625 +74267 0.2257080078125 +74268 0.041168212890625 +74269 0.427154541015625 +74270 0.11041259765625 +74271 0.643218994140625 +74272 0.185516357421875 +74273 0.855926513671875 +74274 0.250640869140625 +74275 0.870361328125 +74276 0.292205810546875 +74277 0.870361328125 +74278 0.312469482421875 +74279 0.862762451171875 +74280 0.310760498046875 +74281 0.79669189453125 +74282 0.28448486328125 +74283 0.595794677734375 +74284 0.24176025390625 +74285 0.362152099609375 +74286 0.190338134765625 +74287 0.1270751953125 +74288 0.135986328125 +74289 -0.086944580078125 +74290 0.079010009765625 +74291 -0.2784423828125 +74292 0.0093994140625 +74293 -0.484832763671875 +74294 -0.0784912109375 +74295 -0.729583740234375 +74296 -0.170806884765625 +74297 -0.86688232421875 +74298 -0.250152587890625 +74299 -0.870391845703125 +74300 -0.3154296875 +74301 -0.86859130859375 +74302 -0.36627197265625 +74303 -0.86279296875 +74304 -0.392822265625 +74305 -0.817962646484375 +74306 -0.382476806640625 +74307 -0.6116943359375 +74308 -0.33331298828125 +74309 -0.3128662109375 +74310 -0.254791259765625 +74311 0.039398193359375 +74312 -0.152435302734375 +74313 0.422821044921875 +74314 -0.03546142578125 +74315 0.805145263671875 +74316 0.077178955078125 +74317 0.870361328125 +74318 0.169708251953125 +74319 0.870361328125 +74320 0.239044189453125 +74321 0.860015869140625 +74322 0.28326416015625 +74323 0.727935791015625 +74324 0.301025390625 +74325 0.48114013671875 +74326 0.29925537109375 +74327 0.2059326171875 +74328 0.284454345703125 +74329 -0.06103515625 +74330 0.25958251953125 +74331 -0.29913330078125 +74332 0.220672607421875 +74333 -0.516204833984375 +74334 0.163482666015625 +74335 -0.7252197265625 +74336 0.095062255859375 +74337 -0.85980224609375 +74338 0.024993896484375 +74339 -0.870391845703125 +74340 -0.03839111328125 +74341 -0.870391845703125 +74342 -0.08148193359375 +74343 -0.858062744140625 +74344 -0.103179931640625 +74345 -0.673004150390625 +74346 -0.118255615234375 +74347 -0.42694091796875 +74348 -0.139190673828125 +74349 -0.2100830078125 +74350 -0.165435791015625 +74351 -0.0362548828125 +74352 -0.18890380859375 +74353 0.10943603515625 +74354 -0.2041015625 +74355 0.23516845703125 +74356 -0.19952392578125 +74357 0.373687744140625 +74358 -0.17578125 +74359 0.517791748046875 +74360 -0.15057373046875 +74361 0.602783203125 +74362 -0.122528076171875 +74363 0.635711669921875 +74364 -0.082366943359375 +74365 0.655181884765625 +74366 -0.032928466796875 +74367 0.65948486328125 +74368 0.023468017578125 +74369 0.651275634765625 +74370 0.079925537109375 +74371 0.61846923828125 +74372 0.126068115234375 +74373 0.53753662109375 +74374 0.1568603515625 +74375 0.404144287109375 +74376 0.16961669921875 +74377 0.22186279296875 +74378 0.164764404296875 +74379 0.003997802734375 +74380 0.14739990234375 +74381 -0.22100830078125 +74382 0.123321533203125 +74383 -0.42449951171875 +74384 0.09857177734375 +74385 -0.579833984375 +74386 0.085174560546875 +74387 -0.641876220703125 +74388 0.081329345703125 +74389 -0.6177978515625 +74390 0.069000244140625 +74391 -0.575531005859375 +74392 0.0467529296875 +74393 -0.526336669921875 +74394 0.029144287109375 +74395 -0.42645263671875 +74396 0.02386474609375 +74397 -0.2581787109375 +74398 0.020782470703125 +74399 -0.068695068359375 +74400 0.009124755859375 +74401 0.09222412109375 +74402 -0.005828857421875 +74403 0.232147216796875 +74404 -0.021240234375 +74405 0.3509521484375 +74406 -0.04541015625 +74407 0.410064697265625 +74408 -0.086578369140625 +74409 0.372955322265625 +74410 -0.138916015625 +74411 0.2554931640625 +74412 -0.187835693359375 +74413 0.10711669921875 +74414 -0.2279052734375 +74415 -0.052886962890625 +74416 -0.248992919921875 +74417 -0.186279296875 +74418 -0.235504150390625 +74419 -0.23291015625 +74420 -0.19384765625 +74421 -0.209442138671875 +74422 -0.142486572265625 +74423 -0.174163818359375 +74424 -0.08380126953125 +74425 -0.126739501953125 +74426 -0.015045166015625 +74427 -0.048126220703125 +74428 0.05584716796875 +74429 0.0426025390625 +74430 0.11578369140625 +74431 0.10748291015625 +74432 0.16107177734375 +74433 0.1409912109375 +74434 0.204986572265625 +74435 0.19708251953125 +74436 0.245635986328125 +74437 0.273651123046875 +74438 0.26739501953125 +74439 0.31768798828125 +74440 0.27337646484375 +74441 0.341094970703125 +74442 0.270660400390625 +74443 0.368011474609375 +74444 0.2528076171875 +74445 0.37249755859375 +74446 0.2060546875 +74447 0.30072021484375 +74448 0.1318359375 +74449 0.1517333984375 +74450 0.048797607421875 +74451 -0.01470947265625 +74452 -0.0380859375 +74453 -0.1883544921875 +74454 -0.12762451171875 +74455 -0.372711181640625 +74456 -0.20269775390625 +74457 -0.51397705078125 +74458 -0.250152587890625 +74459 -0.57177734375 +74460 -0.266571044921875 +74461 -0.53948974609375 +74462 -0.255767822265625 +74463 -0.43511962890625 +74464 -0.227447509765625 +74465 -0.2962646484375 +74466 -0.19195556640625 +74467 -0.161102294921875 +74468 -0.1533203125 +74469 -0.0435791015625 +74470 -0.11090087890625 +74471 0.060394287109375 +74472 -0.069610595703125 +74473 0.13665771484375 +74474 -0.03497314453125 +74475 0.170135498046875 +74476 -0.0072021484375 +74477 0.16552734375 +74478 0.021636962890625 +74479 0.15728759765625 +74480 0.05126953125 +74481 0.150787353515625 +74482 0.073272705078125 +74483 0.12200927734375 +74484 0.088592529296875 +74485 0.080108642578125 +74486 0.103179931640625 +74487 0.05126953125 +74488 0.123626708984375 +74489 0.062896728515625 +74490 0.14288330078125 +74491 0.09271240234375 +74492 0.147186279296875 +74493 0.092987060546875 +74494 0.140655517578125 +74495 0.07855224609375 +74496 0.12762451171875 +74497 0.06427001953125 +74498 0.104522705078125 +74499 0.0347900390625 +74500 0.071868896484375 +74501 -0.01171875 +74502 0.03643798828125 +74503 -0.056060791015625 +74504 0.012298583984375 +74505 -0.055511474609375 +74506 0.000640869140625 +74507 -0.010467529296875 +74508 -0.01336669921875 +74509 0.02508544921875 +74510 -0.036041259765625 +74511 0.025665283203125 +74512 -0.058380126953125 +74513 0.017333984375 +74514 -0.078887939453125 +74515 0.00189208984375 +74516 -0.100128173828125 +74517 -0.03173828125 +74518 -0.118011474609375 +74519 -0.071502685546875 +74520 -0.137725830078125 +74521 -0.13543701171875 +74522 -0.1583251953125 +74523 -0.219970703125 +74524 -0.172821044921875 +74525 -0.300506591796875 +74526 -0.181671142578125 +74527 -0.376312255859375 +74528 -0.176361083984375 +74529 -0.416107177734375 +74530 -0.143280029296875 +74531 -0.371124267578125 +74532 -0.0838623046875 +74533 -0.242279052734375 +74534 -0.011322021484375 +74535 -0.069732666015625 +74536 0.066925048828125 +74537 0.125640869140625 +74538 0.140533447265625 +74539 0.31268310546875 +74540 0.197662353515625 +74541 0.45501708984375 +74542 0.238250732421875 +74543 0.554779052734375 +74544 0.261444091796875 +74545 0.61065673828125 +74546 0.263519287109375 +74547 0.610931396484375 +74548 0.23724365234375 +74549 0.531463623046875 +74550 0.18768310546875 +74551 0.3883056640625 +74552 0.131317138671875 +74553 0.23468017578125 +74554 0.076202392578125 +74555 0.095245361328125 +74556 0.03094482421875 +74557 -0.00396728515625 +74558 0.000762939453125 +74559 -0.04852294921875 +74560 -0.018402099609375 +74561 -0.055145263671875 +74562 -0.041168212890625 +74563 -0.0758056640625 +74564 -0.075103759765625 +74565 -0.138702392578125 +74566 -0.109039306640625 +74567 -0.209197998046875 +74568 -0.14288330078125 +74569 -0.289031982421875 +74570 -0.176361083984375 +74571 -0.37884521484375 +74572 -0.202484130859375 +74573 -0.456329345703125 +74574 -0.219696044921875 +74575 -0.51641845703125 +74576 -0.216217041015625 +74577 -0.519287109375 +74578 -0.19036865234375 +74579 -0.458251953125 +74580 -0.1580810546875 +74581 -0.384796142578125 +74582 -0.12744140625 +74583 -0.323699951171875 +74584 -0.097442626953125 +74585 -0.269287109375 +74586 -0.061004638671875 +74587 -0.1951904296875 +74588 -0.01849365234375 +74589 -0.100006103515625 +74590 0.021240234375 +74591 -0.01055908203125 +74592 0.066619873046875 +74593 0.1033935546875 +74594 0.1192626953125 +74595 0.24908447265625 +74596 0.162750244140625 +74597 0.373199462890625 +74598 0.1915283203125 +74599 0.45806884765625 +74600 0.20782470703125 +74601 0.511474609375 +74602 0.221282958984375 +74603 0.565399169921875 +74604 0.2296142578125 +74605 0.61138916015625 +74606 0.21527099609375 +74607 0.5897216796875 +74608 0.175811767578125 +74609 0.4906005859375 +74610 0.1170654296875 +74611 0.33148193359375 +74612 0.05029296875 +74613 0.147796630859375 +74614 -0.01129150390625 +74615 -0.01873779296875 +74616 -0.0587158203125 +74617 -0.140289306640625 +74618 -0.083953857421875 +74619 -0.191986083984375 +74620 -0.08966064453125 +74621 -0.184295654296875 +74622 -0.088836669921875 +74623 -0.161834716796875 +74624 -0.093780517578125 +74625 -0.166595458984375 +74626 -0.10296630859375 +74627 -0.19390869140625 +74628 -0.110626220703125 +74629 -0.22442626953125 +74630 -0.12335205078125 +74631 -0.279754638671875 +74632 -0.13519287109375 +74633 -0.3389892578125 +74634 -0.1322021484375 +74635 -0.3543701171875 +74636 -0.12152099609375 +74637 -0.348175048828125 +74638 -0.1053466796875 +74639 -0.32598876953125 +74640 -0.0753173828125 +74641 -0.2581787109375 +74642 -0.030517578125 +74643 -0.139801025390625 +74644 0.024200439453125 +74645 0.014617919921875 +74646 0.0701904296875 +74647 0.144378662109375 +74648 0.09857177734375 +74649 0.221038818359375 +74650 0.116943359375 +74651 0.27069091796875 +74652 0.125396728515625 +74653 0.294036865234375 +74654 0.130096435546875 +74655 0.311767578125 +74656 0.1357421875 +74657 0.339141845703125 +74658 0.137908935546875 +74659 0.360260009765625 +74660 0.132476806640625 +74661 0.360504150390625 +74662 0.109893798828125 +74663 0.308380126953125 +74664 0.06353759765625 +74665 0.18170166015625 +74666 0.00140380859375 +74667 0.0047607421875 +74668 -0.061553955078125 +74669 -0.17559814453125 +74670 -0.1109619140625 +74671 -0.3143310546875 +74672 -0.132904052734375 +74673 -0.36785888671875 +74674 -0.13531494140625 +74675 -0.36248779296875 +74676 -0.13214111328125 +74677 -0.343536376953125 +74678 -0.120452880859375 +74679 -0.3018798828125 +74680 -0.09832763671875 +74681 -0.231414794921875 +74682 -0.061279296875 +74683 -0.117645263671875 +74684 -0.01953125 +74685 0.007049560546875 +74686 0.0096435546875 +74687 0.087982177734375 +74688 0.030487060546875 +74689 0.13946533203125 +74690 0.04669189453125 +74691 0.17425537109375 +74692 0.056640625 +74693 0.188201904296875 +74694 0.056884765625 +74695 0.171234130859375 +74696 0.04559326171875 +74697 0.118438720703125 +74698 0.031005859375 +74699 0.05706787109375 +74700 0.013580322265625 +74701 -0.010711669921875 +74702 -0.008880615234375 +74703 -0.0914306640625 +74704 -0.029388427734375 +74705 -0.162322998046875 +74706 -0.039031982421875 +74707 -0.194549560546875 +74708 -0.02569580078125 +74709 -0.1492919921875 +74710 0.01220703125 +74711 -0.02166748046875 +74712 0.05474853515625 +74713 0.124053955078125 +74714 0.07818603515625 +74715 0.211151123046875 +74716 0.0830078125 +74717 0.240447998046875 +74718 0.07891845703125 +74719 0.242218017578125 +74720 0.069091796875 +74721 0.2257080078125 +74722 0.05487060546875 +74723 0.194366455078125 +74724 0.026275634765625 +74725 0.115509033203125 +74726 -0.009063720703125 +74727 0.0128173828125 +74728 -0.03228759765625 +74729 -0.053802490234375 +74730 -0.051513671875 +74731 -0.110626220703125 +74732 -0.079742431640625 +74733 -0.199493408203125 +74734 -0.108856201171875 +74735 -0.29437255859375 +74736 -0.119232177734375 +74737 -0.33221435546875 +74738 -0.1005859375 +74739 -0.27972412109375 +74740 -0.068206787109375 +74741 -0.185333251953125 +74742 -0.04693603515625 +74743 -0.128204345703125 +74744 -0.03924560546875 +74745 -0.115692138671875 +74746 -0.035614013671875 +74747 -0.116455078125 +74748 -0.028594970703125 +74749 -0.105926513671875 +74750 -0.00897216796875 +74751 -0.053955078125 +74752 0.02618408203125 +74753 0.048797607421875 +74754 0.0623779296875 +74755 0.157318115234375 +74756 0.079803466796875 +74757 0.212005615234375 +74758 0.08050537109375 +74759 0.218475341796875 +74760 0.085418701171875 +74761 0.23724365234375 +74762 0.10736083984375 +74763 0.30535888671875 +74764 0.132110595703125 +74765 0.38128662109375 +74766 0.138824462890625 +74767 0.404449462890625 +74768 0.13427734375 +74769 0.3944091796875 +74770 0.131378173828125 +74771 0.3885498046875 +74772 0.121826171875 +74773 0.362640380859375 +74774 0.090789794921875 +74775 0.27362060546875 +74776 0.036773681640625 +74777 0.11712646484375 +74778 -0.0223388671875 +74779 -0.054901123046875 +74780 -0.06884765625 +74781 -0.19085693359375 +74782 -0.101043701171875 +74783 -0.28570556640625 +74784 -0.118896484375 +74785 -0.339263916015625 +74786 -0.131378173828125 +74787 -0.3775634765625 +74788 -0.154052734375 +74789 -0.445709228515625 +74790 -0.183990478515625 +74791 -0.535064697265625 +74792 -0.21551513671875 +74793 -0.629058837890625 +74794 -0.238311767578125 +74795 -0.697601318359375 +74796 -0.239776611328125 +74797 -0.70391845703125 +74798 -0.218048095703125 +74799 -0.6424560546875 +74800 -0.16558837890625 +74801 -0.491241455078125 +74802 -0.087738037109375 +74803 -0.265716552734375 +74804 -0.00439453125 +74805 -0.023712158203125 +74806 0.073028564453125 +74807 0.201751708984375 +74808 0.132568359375 +74809 0.375823974609375 +74810 0.169647216796875 +74811 0.485076904296875 +74812 0.19781494140625 +74813 0.56884765625 +74814 0.2197265625 +74815 0.634765625 +74816 0.21990966796875 +74817 0.63763427734375 +74818 0.1944580078125 +74819 0.5660400390625 +74820 0.161346435546875 +74821 0.4720458984375 +74822 0.13824462890625 +74823 0.40692138671875 +74824 0.127655029296875 +74825 0.3778076171875 +74826 0.126922607421875 +74827 0.376953125 +74828 0.12493896484375 +74829 0.371978759765625 +74830 0.104583740234375 +74831 0.313140869140625 +74832 0.06036376953125 +74833 0.184417724609375 +74834 0.001007080078125 +74835 0.011199951171875 +74836 -0.061279296875 +74837 -0.171051025390625 +74838 -0.117950439453125 +74839 -0.33740234375 +74840 -0.16357421875 +74841 -0.47198486328125 +74842 -0.1932373046875 +74843 -0.560394287109375 +74844 -0.19940185546875 +74845 -0.58056640625 +74846 -0.18731689453125 +74847 -0.54754638671875 +74848 -0.173248291015625 +74849 -0.508575439453125 +74850 -0.155792236328125 +74851 -0.459503173828125 +74852 -0.132965087890625 +74853 -0.394378662109375 +74854 -0.1182861328125 +74855 -0.35260009765625 +74856 -0.104034423828125 +74857 -0.31170654296875 +74858 -0.064666748046875 +74859 -0.197418212890625 +74860 0.0003662109375 +74861 -0.007965087890625 +74862 0.07415771484375 +74863 0.207489013671875 +74864 0.14306640625 +74865 0.409210205078125 +74866 0.198486328125 +74867 0.57208251953125 +74868 0.2301025390625 +74869 0.66595458984375 +74870 0.226898193359375 +74871 0.65875244140625 +74872 0.19476318359375 +74873 0.56744384765625 +74874 0.14727783203125 +74875 0.431396484375 +74876 0.099578857421875 +74877 0.29443359375 +74878 0.060577392578125 +74879 0.182464599609375 +74880 0.019378662109375 +74881 0.06365966796875 +74882 -0.02880859375 +74883 -0.075958251953125 +74884 -0.06781005859375 +74885 -0.189422607421875 +74886 -0.095977783203125 +74887 -0.271942138671875 +74888 -0.119873046875 +74889 -0.342529296875 +74890 -0.126861572265625 +74891 -0.364166259765625 +74892 -0.113616943359375 +74893 -0.327239990234375 +74894 -0.095733642578125 +74895 -0.2769775390625 +74896 -0.087127685546875 +74897 -0.253692626953125 +74898 -0.08306884765625 +74899 -0.24365234375 +74900 -0.066925048828125 +74901 -0.1983642578125 +74902 -0.0382080078125 +74903 -0.116241455078125 +74904 -0.010498046875 +74905 -0.036834716796875 +74906 0.014434814453125 +74907 0.034881591796875 +74908 0.033935546875 +74909 0.09124755859375 +74910 0.03997802734375 +74911 0.10888671875 +74912 0.0455322265625 +74913 0.125518798828125 +74914 0.056304931640625 +74915 0.15771484375 +74916 0.062957763671875 +74917 0.17828369140625 +74918 0.059967041015625 +74919 0.17108154296875 +74920 0.0452880859375 +74921 0.129974365234375 +74922 0.02838134765625 +74923 0.082427978515625 +74924 0.009033203125 +74925 0.027679443359375 +74926 -0.02349853515625 +74927 -0.065643310546875 +74928 -0.056060791015625 +74929 -0.15936279296875 +74930 -0.074737548828125 +74931 -0.21307373046875 +74932 -0.082244873046875 +74933 -0.234649658203125 +74934 -0.07037353515625 +74935 -0.2001953125 +74936 -0.042388916015625 +74937 -0.119171142578125 +74938 -0.00970458984375 +74939 -0.024749755859375 +74940 0.028564453125 +74941 0.085784912109375 +74942 0.060577392578125 +74943 0.178131103515625 +74944 0.07373046875 +74945 0.215576171875 +74946 0.07257080078125 +74947 0.211456298828125 +74948 0.060394287109375 +74949 0.17523193359375 +74950 0.044677734375 +74951 0.128753662109375 +74952 0.03570556640625 +74953 0.1019287109375 +74954 0.02642822265625 +74955 0.0743408203125 +74956 0.015899658203125 +74957 0.04327392578125 +74958 0.014251708984375 +74959 0.038177490234375 +74960 0.027374267578125 +74961 0.076263427734375 +74962 0.049591064453125 +74963 0.14105224609375 +74964 0.065093994140625 +74965 0.186431884765625 +74966 0.06573486328125 +74967 0.188812255859375 +74968 0.048370361328125 +74969 0.1390380859375 +74970 0.0146484375 +74971 0.041778564453125 +74972 -0.027313232421875 +74973 -0.079437255859375 +74974 -0.07568359375 +74975 -0.219390869140625 +74976 -0.12689208984375 +74977 -0.367828369140625 +74978 -0.170684814453125 +74979 -0.494873046875 +74980 -0.19183349609375 +74981 -0.556243896484375 +74982 -0.175445556640625 +74983 -0.508697509765625 +74984 -0.12957763671875 +74985 -0.3756103515625 +74986 -0.0755615234375 +74987 -0.218902587890625 +74988 -0.022064208984375 +74989 -0.063751220703125 +74990 0.031463623046875 +74991 0.091552734375 +74992 0.081268310546875 +74993 0.23602294921875 +74994 0.1181640625 +74995 0.342987060546875 +74996 0.13623046875 +74997 0.39520263671875 +74998 0.134307861328125 +74999 0.389373779296875 +75000 0.111968994140625 +75001 0.324249267578125 +75002 0.077545166015625 +75003 0.224090576171875 +75004 0.043243408203125 +75005 0.124267578125 +75006 0.013275146484375 +75007 0.037078857421875 +75008 -0.00250244140625 +75009 -0.010101318359375 +75010 -0.00506591796875 +75011 -0.019439697265625 +75012 -0.00604248046875 +75013 -0.022796630859375 +75014 0.00177001953125 +75015 -0.001556396484375 +75016 0.023040771484375 +75017 0.056304931640625 +75018 0.0413818359375 +75019 0.106719970703125 +75020 0.037078857421875 +75021 0.096893310546875 +75022 0.016204833984375 +75023 0.042694091796875 +75024 -0.0069580078125 +75025 -0.018035888671875 +75026 -0.02886962890625 +75027 -0.07586669921875 +75028 -0.045257568359375 +75029 -0.11944580078125 +75030 -0.060272216796875 +75031 -0.15972900390625 +75032 -0.076171875 +75033 -0.202606201171875 +75034 -0.0931396484375 +75035 -0.24859619140625 +75036 -0.114044189453125 +75037 -0.30517578125 +75038 -0.13507080078125 +75039 -0.36212158203125 +75040 -0.145721435546875 +75041 -0.39141845703125 +75042 -0.1318359375 +75043 -0.35528564453125 +75044 -0.092041015625 +75045 -0.249969482421875 +75046 -0.03289794921875 +75047 -0.092864990234375 +75048 0.03546142578125 +75049 0.08905029296875 +75050 0.09027099609375 +75051 0.2352294921875 +75052 0.121429443359375 +75053 0.318817138671875 +75054 0.13604736328125 +75055 0.358642578125 +75056 0.13153076171875 +75057 0.347747802734375 +75058 0.10772705078125 +75059 0.28564453125 +75060 0.083770751953125 +75061 0.223175048828125 +75062 0.073394775390625 +75063 0.196746826171875 +75064 0.066650390625 +75065 0.179840087890625 +75066 0.05718994140625 +75067 0.155548095703125 +75068 0.055328369140625 +75069 0.151214599609375 +75070 0.057342529296875 +75071 0.156951904296875 +75072 0.047821044921875 +75073 0.13177490234375 +75074 0.03619384765625 +75075 0.100799560546875 +75076 0.03118896484375 +75077 0.087127685546875 +75078 0.019287109375 +75079 0.05487060546875 +75080 -0.004425048828125 +75081 -0.009002685546875 +75082 -0.039764404296875 +75083 -0.10400390625 +75084 -0.08648681640625 +75085 -0.229400634765625 +75086 -0.133453369140625 +75087 -0.35552978515625 +75088 -0.16546630859375 +75089 -0.441925048828125 +75090 -0.17706298828125 +75091 -0.473846435546875 +75092 -0.173309326171875 +75093 -0.464813232421875 +75094 -0.15582275390625 +75095 -0.419097900390625 +75096 -0.123748779296875 +75097 -0.334320068359375 +75098 -0.083648681640625 +75099 -0.227935791015625 +75100 -0.04437255859375 +75101 -0.12347412109375 +75102 -0.0084228515625 +75103 -0.02764892578125 +75104 0.031036376953125 +75105 0.077667236328125 +75106 0.081787109375 +75107 0.2132568359375 +75108 0.147491455078125 +75109 0.38885498046875 +75110 0.22003173828125 +75111 0.582794189453125 +75112 0.2764892578125 +75113 0.734039306640625 +75114 0.300933837890625 +75115 0.800140380859375 +75116 0.292327880859375 +75117 0.7783203125 +75118 0.249420166015625 +75119 0.6651611328125 +75120 0.171844482421875 +75121 0.45965576171875 +75122 0.07366943359375 +75123 0.199188232421875 +75124 -0.020416259765625 +75125 -0.050689697265625 +75126 -0.0889892578125 +75127 -0.23297119140625 +75128 -0.125457763671875 +75129 -0.33013916015625 +75130 -0.139678955078125 +75131 -0.368408203125 +75132 -0.14337158203125 +75133 -0.378936767578125 +75134 -0.142303466796875 +75135 -0.376983642578125 +75136 -0.142974853515625 +75137 -0.37969970703125 +75138 -0.14703369140625 +75139 -0.391510009765625 +75140 -0.14434814453125 +75141 -0.385345458984375 +75142 -0.127685546875 +75143 -0.3419189453125 +75144 -0.105194091796875 +75145 -0.28289794921875 +75146 -0.09320068359375 +75147 -0.251617431640625 +75148 -0.098480224609375 +75149 -0.266143798828125 +75150 -0.10107421875 +75151 -0.273345947265625 +75152 -0.079742431640625 +75153 -0.216796875 +75154 -0.04644775390625 +75155 -0.128265380859375 +75156 -0.023895263671875 +75157 -0.068145751953125 +75158 -0.014556884765625 +75159 -0.0430908203125 +75160 -0.0076904296875 +75161 -0.024444580078125 +75162 0.009063720703125 +75163 0.020721435546875 +75164 0.047760009765625 +75165 0.124481201171875 +75166 0.0975341796875 +75167 0.25787353515625 +75168 0.1427001953125 +75169 0.379119873046875 +75170 0.18017578125 +75171 0.47991943359375 +75172 0.197906494140625 +75173 0.5281982421875 +75174 0.19110107421875 +75175 0.511138916015625 +75176 0.170135498046875 +75177 0.456207275390625 +75178 0.151580810546875 +75179 0.407470703125 +75180 0.142547607421875 +75181 0.383758544921875 +75182 0.132415771484375 +75183 0.35687255859375 +75184 0.11553955078125 +75185 0.31182861328125 +75186 0.0927734375 +75187 0.250885009765625 +75188 0.06085205078125 +75189 0.1654052734375 +75190 0.01220703125 +75191 0.035247802734375 +75192 -0.054107666015625 +75193 -0.142059326171875 +75194 -0.126495361328125 +75195 -0.33563232421875 +75196 -0.20086669921875 +75197 -0.5345458984375 +75198 -0.2708740234375 +75199 -0.72186279296875 +75200 -0.3135986328125 +75201 -0.836669921875 +75202 -0.311676025390625 +75203 -0.8326416015625 +75204 -0.2725830078125 +75205 -0.7296142578125 +75206 -0.217041015625 +75207 -0.582550048828125 +75208 -0.163330078125 +75209 -0.440093994140625 +75210 -0.1197509765625 +75211 -0.324310302734375 +75212 -0.073638916015625 +75213 -0.20147705078125 +75214 -0.014801025390625 +75215 -0.044647216796875 +75216 0.04083251953125 +75217 0.103973388671875 +75218 0.0775146484375 +75219 0.202392578125 +75220 0.1004638671875 +75221 0.264495849609375 +75222 0.12799072265625 +75223 0.338897705078125 +75224 0.166961669921875 +75225 0.443817138671875 +75226 0.204559326171875 +75227 0.545074462890625 +75228 0.23126220703125 +75229 0.6173095703125 +75230 0.24407958984375 +75231 0.6524658203125 +75232 0.24786376953125 +75233 0.66339111328125 +75234 0.244903564453125 +75235 0.6561279296875 +75236 0.226226806640625 +75237 0.606781005859375 +75238 0.186492919921875 +75239 0.501190185546875 +75240 0.1307373046875 +75241 0.352783203125 +75242 0.06463623046875 +75243 0.176544189453125 +75244 -0.014556884765625 +75245 -0.034820556640625 +75246 -0.09814453125 +75247 -0.258209228515625 +75248 -0.16693115234375 +75249 -0.44244384765625 +75250 -0.21636962890625 +75251 -0.5753173828125 +75252 -0.244659423828125 +75253 -0.65203857421875 +75254 -0.240203857421875 +75255 -0.641632080078125 +75256 -0.2098388671875 +75257 -0.562164306640625 +75258 -0.170318603515625 +75259 -0.458038330078125 +75260 -0.129638671875 +75261 -0.350555419921875 +75262 -0.09564208984375 +75263 -0.260528564453125 +75264 -0.070037841796875 +75265 -0.192108154296875 +75266 -0.0516357421875 +75267 -0.141937255859375 +75268 -0.037200927734375 +75269 -0.1021728515625 +75270 -0.022857666015625 +75271 -0.062896728515625 +75272 -0.00372314453125 +75273 -0.011932373046875 +75274 0.025054931640625 +75275 0.062835693359375 +75276 0.058319091796875 +75277 0.148712158203125 +75278 0.094512939453125 +75279 0.241729736328125 +75280 0.136688232421875 +75281 0.34912109375 +75282 0.179351806640625 +75283 0.457305908203125 +75284 0.213470458984375 +75285 0.54388427734375 +75286 0.224456787109375 +75287 0.5728759765625 +75288 0.196990966796875 +75289 0.506591796875 +75290 0.133636474609375 +75291 0.351226806640625 +75292 0.05059814453125 +75293 0.146514892578125 +75294 -0.03076171875 +75295 -0.05523681640625 +75296 -0.0950927734375 +75297 -0.21624755859375 +75298 -0.141815185546875 +75299 -0.334930419921875 +75300 -0.1676025390625 +75301 -0.402984619140625 +75302 -0.181121826171875 +75303 -0.4412841796875 +75304 -0.20123291015625 +75305 -0.49578857421875 +75306 -0.2254638671875 +75307 -0.5601806640625 +75308 -0.24017333984375 +75309 -0.600738525390625 +75310 -0.231903076171875 +75311 -0.584228515625 +75312 -0.187896728515625 +75313 -0.47930908203125 +75314 -0.10552978515625 +75315 -0.27935791015625 +75316 0.005096435546875 +75317 -0.0089111328125 +75318 0.1181640625 +75319 0.268798828125 +75320 0.20477294921875 +75321 0.482818603515625 +75322 0.252960205078125 +75323 0.60369873046875 +75324 0.270538330078125 +75325 0.650421142578125 +75326 0.27435302734375 +75327 0.66400146484375 +75328 0.2633056640625 +75329 0.6414794921875 +75330 0.233306884765625 +75331 0.572540283203125 +75332 0.201141357421875 +75333 0.498138427734375 +75334 0.175537109375 +75335 0.439453125 +75336 0.148040771484375 +75337 0.375518798828125 +75338 0.105743408203125 +75339 0.274505615234375 +75340 0.03741455078125 +75341 0.1087646484375 +75342 -0.047821044921875 +75343 -0.099395751953125 +75344 -0.136993408203125 +75345 -0.3182373046875 +75346 -0.230621337890625 +75347 -0.5489501953125 +75348 -0.32147216796875 +75349 -0.7738037109375 +75350 -0.38800048828125 +75351 -0.86383056640625 +75352 -0.416717529296875 +75353 -0.870391845703125 +75354 -0.414947509765625 +75355 -0.86895751953125 +75356 -0.388153076171875 +75357 -0.861053466796875 +75358 -0.329376220703125 +75359 -0.765869140625 +75360 -0.234100341796875 +75361 -0.5301513671875 +75362 -0.10528564453125 +75363 -0.214691162109375 +75364 0.0394287109375 +75365 0.137359619140625 +75366 0.179046630859375 +75367 0.474822998046875 +75368 0.299041748046875 +75369 0.76239013671875 +75370 0.388397216796875 +75371 0.867462158203125 +75372 0.447296142578125 +75373 0.870361328125 +75374 0.471038818359375 +75375 0.86480712890625 +75376 0.461883544921875 +75377 0.831817626953125 +75378 0.429840087890625 +75379 0.677581787109375 +75380 0.377349853515625 +75381 0.495880126953125 +75382 0.31207275390625 +75383 0.30767822265625 +75384 0.2349853515625 +75385 0.116180419921875 +75386 0.1331787109375 +75387 -0.110748291015625 +75388 0.00390625 +75389 -0.381805419921875 +75390 -0.13531494140625 +75391 -0.6572265625 +75392 -0.259979248046875 +75393 -0.857421875 +75394 -0.3525390625 +75395 -0.870391845703125 +75396 -0.41009521484375 +75397 -0.870391845703125 +75398 -0.443572998046875 +75399 -0.86444091796875 +75400 -0.467559814453125 +75401 -0.85723876953125 +75402 -0.474639892578125 +75403 -0.790008544921875 +75404 -0.442718505859375 +75405 -0.62847900390625 +75406 -0.37054443359375 +75407 -0.3956298828125 +75408 -0.271575927734375 +75409 -0.126708984375 +75410 -0.157073974609375 +75411 0.150115966796875 +75412 -0.0318603515625 +75413 0.424041748046875 +75414 0.092987060546875 +75415 0.670623779296875 +75416 0.20159912109375 +75417 0.854522705078125 +75418 0.286712646484375 +75419 0.866485595703125 +75420 0.342010498046875 +75421 0.86920166015625 +75422 0.3748779296875 +75423 0.8653564453125 +75424 0.390777587890625 +75425 0.857147216796875 +75426 0.3885498046875 +75427 0.766845703125 +75428 0.370269775390625 +75429 0.628509521484375 +75430 0.333221435546875 +75431 0.462127685546875 +75432 0.287994384765625 +75433 0.297210693359375 +75434 0.239715576171875 +75435 0.14862060546875 +75436 0.179107666015625 +75437 -0.00537109375 +75438 0.1092529296875 +75439 -0.15753173828125 +75440 0.028778076171875 +75441 -0.31304931640625 +75442 -0.067962646484375 +75443 -0.48876953125 +75444 -0.161773681640625 +75445 -0.6416015625 +75446 -0.242523193359375 +75447 -0.751373291015625 +75448 -0.31964111328125 +75449 -0.84619140625 +75450 -0.3870849609375 +75451 -0.861297607421875 +75452 -0.431304931640625 +75453 -0.863250732421875 +75454 -0.439453125 +75455 -0.856597900390625 +75456 -0.416473388671875 +75457 -0.7498779296875 +75458 -0.386016845703125 +75459 -0.624542236328125 +75460 -0.339202880859375 +75461 -0.47808837890625 +75462 -0.252227783203125 +75463 -0.253387451171875 +75464 -0.143768310546875 +75465 0.003692626953125 +75466 -0.041778564453125 +75467 0.2257080078125 +75468 0.05877685546875 +75469 0.427154541015625 +75470 0.17108154296875 +75471 0.643218994140625 +75472 0.2911376953125 +75473 0.855926513671875 +75474 0.395263671875 +75475 0.870361328125 +75476 0.463165283203125 +75477 0.870361328125 +75478 0.497772216796875 +75479 0.862762451171875 +75480 0.49786376953125 +75481 0.79669189453125 +75482 0.4595947265625 +75483 0.595794677734375 +75484 0.3948974609375 +75485 0.362152099609375 +75486 0.315277099609375 +75487 0.1270751953125 +75488 0.229400634765625 +75489 -0.086944580078125 +75490 0.138214111328125 +75491 -0.2784423828125 +75492 0.027618408203125 +75493 -0.484832763671875 +75494 -0.110137939453125 +75495 -0.729583740234375 +75496 -0.25433349609375 +75497 -0.86688232421875 +75498 -0.379058837890625 +75499 -0.870391845703125 +75500 -0.48223876953125 +75501 -0.86859130859375 +75502 -0.56292724609375 +75503 -0.86279296875 +75504 -0.606414794921875 +75505 -0.817962646484375 +75506 -0.59417724609375 +75507 -0.6116943359375 +75508 -0.523284912109375 +75509 -0.3128662109375 +75510 -0.40753173828125 +75511 0.039398193359375 +75512 -0.255126953125 +75513 0.422821044921875 +75514 -0.079742431640625 +75515 0.805145263671875 +75516 0.090728759765625 +75517 0.870361328125 +75518 0.23291015625 +75519 0.870361328125 +75520 0.342071533203125 +75521 0.860015869140625 +75522 0.41448974609375 +75523 0.727935791015625 +75524 0.447357177734375 +75525 0.48114013671875 +75526 0.451080322265625 +75527 0.2059326171875 +75528 0.435302734375 +75529 -0.06103515625 +75530 0.404083251953125 +75531 -0.29913330078125 +75532 0.350738525390625 +75533 -0.516204833984375 +75534 0.26812744140625 +75535 -0.7252197265625 +75536 0.1668701171875 +75537 -0.85980224609375 +75538 0.061798095703125 +75539 -0.870391845703125 +75540 -0.0343017578125 +75541 -0.870391845703125 +75542 -0.10015869140625 +75543 -0.858062744140625 +75544 -0.134033203125 +75545 -0.673004150390625 +75546 -0.1590576171875 +75547 -0.42694091796875 +75548 -0.1947021484375 +75549 -0.2100830078125 +75550 -0.239990234375 +75551 -0.0362548828125 +75552 -0.281951904296875 +75553 0.10943603515625 +75554 -0.311614990234375 +75555 0.23516845703125 +75556 -0.310546875 +75557 0.373687744140625 +75558 -0.279388427734375 +75559 0.517791748046875 +75560 -0.245635986328125 +75561 0.602783203125 +75562 -0.206787109375 +75563 0.635711669921875 +75564 -0.14801025390625 +75565 0.655181884765625 +75566 -0.07354736328125 +75567 0.65948486328125 +75568 0.013153076171875 +75569 0.651275634765625 +75570 0.101318359375 +75571 0.61846923828125 +75572 0.174652099609375 +75573 0.53753662109375 +75574 0.22515869140625 +75575 0.404144287109375 +75576 0.2484130859375 +75577 0.22186279296875 +75578 0.24481201171875 +75579 0.003997802734375 +75580 0.22216796875 +75581 -0.22100830078125 +75582 0.189361572265625 +75583 -0.42449951171875 +75584 0.155609130859375 +75585 -0.579833984375 +75586 0.1395263671875 +75587 -0.641876220703125 +75588 0.138031005859375 +75589 -0.6177978515625 +75590 0.122528076171875 +75591 -0.575531005859375 +75592 0.090545654296875 +75593 -0.526336669921875 +75594 0.0648193359375 +75595 -0.42645263671875 +75596 0.057403564453125 +75597 -0.2581787109375 +75598 0.05230712890625 +75599 -0.068695068359375 +75600 0.032684326171875 +75601 0.09222412109375 +75602 0.006866455078125 +75603 0.232147216796875 +75604 -0.0205078125 +75605 0.3509521484375 +75606 -0.062286376953125 +75607 0.410064697265625 +75608 -0.131195068359375 +75609 0.372955322265625 +75610 -0.21783447265625 +75611 0.2554931640625 +75612 -0.299041748046875 +75613 0.10711669921875 +75614 -0.365997314453125 +75615 -0.052886962890625 +75616 -0.402618408203125 +75617 -0.186279296875 +75618 -0.38421630859375 +75619 -0.23291015625 +75620 -0.320709228515625 +75621 -0.209442138671875 +75622 -0.24102783203125 +75623 -0.174163818359375 +75624 -0.14886474609375 +75625 -0.126739501953125 +75626 -0.039947509765625 +75627 -0.048126220703125 +75628 0.07318115234375 +75629 0.0426025390625 +75630 0.169830322265625 +75631 0.10748291015625 +75632 0.2440185546875 +75633 0.1409912109375 +75634 0.316497802734375 +75635 0.19708251953125 +75636 0.38409423828125 +75637 0.273651123046875 +75638 0.422027587890625 +75639 0.31768798828125 +75640 0.4349365234375 +75641 0.341094970703125 +75642 0.43377685546875 +75643 0.368011474609375 +75644 0.4083251953125 +75645 0.37249755859375 +75646 0.3367919921875 +75647 0.30072021484375 +75648 0.221282958984375 +75649 0.1517333984375 +75650 0.091094970703125 +75651 -0.01470947265625 +75652 -0.045928955078125 +75653 -0.1883544921875 +75654 -0.18792724609375 +75655 -0.372711181640625 +75656 -0.307891845703125 +75657 -0.51397705078125 +75658 -0.384979248046875 +75659 -0.57177734375 +75660 -0.413665771484375 +75661 -0.53948974609375 +75662 -0.3997802734375 +75663 -0.43511962890625 +75664 -0.358428955078125 +75665 -0.2962646484375 +75666 -0.3056640625 +75667 -0.161102294921875 +75668 -0.247650146484375 +75669 -0.0435791015625 +75670 -0.18328857421875 +75671 0.060394287109375 +75672 -0.120208740234375 +75673 0.13665771484375 +75674 -0.066925048828125 +75675 0.170135498046875 +75676 -0.02374267578125 +75677 0.16552734375 +75678 0.02178955078125 +75679 0.15728759765625 +75680 0.06927490234375 +75681 0.150787353515625 +75682 0.105316162109375 +75683 0.12200927734375 +75684 0.131378173828125 +75685 0.080108642578125 +75686 0.156646728515625 +75687 0.05126953125 +75688 0.19134521484375 +75689 0.062896728515625 +75690 0.224273681640625 +75691 0.09271240234375 +75692 0.233642578125 +75693 0.092987060546875 +75694 0.22576904296875 +75695 0.07855224609375 +75696 0.20758056640625 +75697 0.06427001953125 +75698 0.173248291015625 +75699 0.0347900390625 +75700 0.1234130859375 +75701 -0.01171875 +75702 0.068328857421875 +75703 -0.056060791015625 +75704 0.0289306640625 +75705 -0.055511474609375 +75706 0.007354736328125 +75707 -0.010467529296875 +75708 -0.017822265625 +75709 0.02508544921875 +75710 -0.05560302734375 +75711 0.025665283203125 +75712 -0.092529296875 +75713 0.017333984375 +75714 -0.126129150390625 +75715 0.00189208984375 +75716 -0.160003662109375 +75717 -0.03173828125 +75718 -0.18804931640625 +75719 -0.071502685546875 +75720 -0.2178955078125 +75721 -0.13543701171875 +75722 -0.24810791015625 +75723 -0.219970703125 +75724 -0.268463134765625 +75725 -0.300506591796875 +75726 -0.27972412109375 +75727 -0.376312255859375 +75728 -0.269500732421875 +75729 -0.416107177734375 +75730 -0.218048095703125 +75731 -0.371124267578125 +75732 -0.127593994140625 +75733 -0.242279052734375 +75734 -0.0177001953125 +75735 -0.069732666015625 +75736 0.10052490234375 +75737 0.125640869140625 +75738 0.211639404296875 +75739 0.31268310546875 +75740 0.2982177734375 +75741 0.45501708984375 +75742 0.36004638671875 +75743 0.554779052734375 +75744 0.395721435546875 +75745 0.61065673828125 +75746 0.399688720703125 +75747 0.610931396484375 +75748 0.361328125 +75749 0.531463623046875 +75750 0.2880859375 +75751 0.3883056640625 +75752 0.20416259765625 +75753 0.23468017578125 +75754 0.121490478515625 +75755 0.095245361328125 +75756 0.05279541015625 +75757 -0.00396728515625 +75758 0.005859375 +75759 -0.04852294921875 +75760 -0.025054931640625 +75761 -0.055145263671875 +75762 -0.061279296875 +75763 -0.0758056640625 +75764 -0.11376953125 +75765 -0.138702392578125 +75766 -0.165985107421875 +75767 -0.209197998046875 +75768 -0.2176513671875 +75769 -0.289031982421875 +75770 -0.268280029296875 +75771 -0.37884521484375 +75772 -0.3076171875 +75773 -0.456329345703125 +75774 -0.33331298828125 +75775 -0.51641845703125 +75776 -0.327911376953125 +75777 -0.519287109375 +75778 -0.2889404296875 +75779 -0.458251953125 +75780 -0.240264892578125 +75781 -0.384796142578125 +75782 -0.194000244140625 +75783 -0.323699951171875 +75784 -0.148651123046875 +75785 -0.269287109375 +75786 -0.09356689453125 +75787 -0.1951904296875 +75788 -0.029296875 +75789 -0.100006103515625 +75790 0.0308837890625 +75791 -0.01055908203125 +75792 0.09954833984375 +75793 0.1033935546875 +75794 0.1790771484375 +75795 0.24908447265625 +75796 0.244842529296875 +75797 0.373199462890625 +75798 0.2884521484375 +75799 0.45806884765625 +75800 0.313262939453125 +75801 0.511474609375 +75802 0.333740234375 +75803 0.565399169921875 +75804 0.346435546875 +75805 0.61138916015625 +75806 0.32501220703125 +75807 0.5897216796875 +75808 0.26580810546875 +75809 0.4906005859375 +75810 0.17755126953125 +75811 0.33148193359375 +75812 0.077178955078125 +75813 0.147796630859375 +75814 -0.015533447265625 +75815 -0.01873779296875 +75816 -0.087066650390625 +75817 -0.140289306640625 +75818 -0.1253662109375 +75819 -0.191986083984375 +75820 -0.134368896484375 +75821 -0.184295654296875 +75822 -0.133575439453125 +75823 -0.161834716796875 +75824 -0.14141845703125 +75825 -0.166595458984375 +75826 -0.155609130859375 +75827 -0.19390869140625 +75828 -0.167449951171875 +75829 -0.22442626953125 +75830 -0.1868896484375 +75831 -0.279754638671875 +75832 -0.20489501953125 +75833 -0.3389892578125 +75834 -0.2005615234375 +75835 -0.3543701171875 +75836 -0.184600830078125 +75837 -0.348175048828125 +75838 -0.1602783203125 +75839 -0.32598876953125 +75840 -0.1151123046875 +75841 -0.2581787109375 +75842 -0.047637939453125 +75843 -0.139801025390625 +75844 0.034820556640625 +75845 0.014617919921875 +75846 0.104248046875 +75847 0.144378662109375 +75848 0.147308349609375 +75849 0.221038818359375 +75850 0.17535400390625 +75851 0.27069091796875 +75852 0.188507080078125 +75853 0.294036865234375 +75854 0.196014404296875 +75855 0.311767578125 +75856 0.20489501953125 +75857 0.339141845703125 +75858 0.20855712890625 +75859 0.360260009765625 +75860 0.200775146484375 +75861 0.360504150390625 +75862 0.167022705078125 +75863 0.308380126953125 +75864 0.097320556640625 +75865 0.18170166015625 +75866 0.003631591796875 +75867 0.0047607421875 +75868 -0.091400146484375 +75869 -0.17559814453125 +75870 -0.166015625 +75871 -0.3143310546875 +75872 -0.19921875 +75873 -0.36785888671875 +75874 -0.2030029296875 +75875 -0.36248779296875 +75876 -0.198486328125 +75877 -0.343536376953125 +75878 -0.181182861328125 +75879 -0.3018798828125 +75880 -0.14813232421875 +75881 -0.231414794921875 +75882 -0.092529296875 +75883 -0.117645263671875 +75884 -0.029815673828125 +75885 0.007049560546875 +75886 0.013916015625 +75887 0.087982177734375 +75888 0.045074462890625 +75889 0.13946533203125 +75890 0.06927490234375 +75891 0.17425537109375 +75892 0.0841064453125 +75893 0.188201904296875 +75894 0.084381103515625 +75895 0.171234130859375 +75896 0.06732177734375 +75897 0.118438720703125 +75898 0.045379638671875 +75899 0.05706787109375 +75900 0.019195556640625 +75901 -0.010711669921875 +75902 -0.01458740234375 +75903 -0.0914306640625 +75904 -0.045379638671875 +75905 -0.162322998046875 +75906 -0.0596923828125 +75907 -0.194549560546875 +75908 -0.039215087890625 +75909 -0.1492919921875 +75910 0.0184326171875 +75911 -0.02166748046875 +75912 0.083160400390625 +75913 0.124053955078125 +75914 0.118988037109375 +75915 0.211151123046875 +75916 0.126617431640625 +75917 0.240447998046875 +75918 0.120697021484375 +75919 0.242218017578125 +75920 0.105987548828125 +75921 0.2257080078125 +75922 0.08453369140625 +75923 0.194366455078125 +75924 0.041229248046875 +75925 0.115509033203125 +75926 -0.01239013671875 +75927 0.0128173828125 +75928 -0.04779052734375 +75929 -0.053802490234375 +75930 -0.077178955078125 +75931 -0.110626220703125 +75932 -0.1202392578125 +75933 -0.199493408203125 +75934 -0.1646728515625 +75935 -0.29437255859375 +75936 -0.1807861328125 +75937 -0.33221435546875 +75938 -0.15301513671875 +75939 -0.27972412109375 +75940 -0.1043701171875 +75941 -0.185333251953125 +75942 -0.072479248046875 +75943 -0.128204345703125 +75944 -0.06109619140625 +75945 -0.115692138671875 +75946 -0.055755615234375 +75947 -0.116455078125 +75948 -0.045196533203125 +75949 -0.105926513671875 +75950 -0.0155029296875 +75951 -0.053955078125 +75952 0.0374755859375 +75953 0.048797607421875 +75954 0.092254638671875 +75955 0.157318115234375 +75956 0.120513916015625 +75957 0.212005615234375 +75958 0.12481689453125 +75959 0.218475341796875 +75960 0.133697509765625 +75961 0.23724365234375 +75962 0.164703369140625 +75963 0.30535888671875 +75964 0.19830322265625 +75965 0.38128662109375 +75966 0.206024169921875 +75967 0.404449462890625 +75968 0.19732666015625 +75969 0.3944091796875 +75970 0.190093994140625 +75971 0.3885498046875 +75972 0.17315673828125 +75973 0.362640380859375 +75974 0.12646484375 +75975 0.27362060546875 +75976 0.0482177734375 +75977 0.11712646484375 +75978 -0.03680419921875 +75979 -0.054901123046875 +75980 -0.10406494140625 +75981 -0.19085693359375 +75982 -0.15106201171875 +75983 -0.28570556640625 +75984 -0.1776123046875 +75985 -0.339263916015625 +75986 -0.195953369140625 +75987 -0.3775634765625 +75988 -0.227386474609375 +75989 -0.445709228515625 +75990 -0.267913818359375 +75991 -0.535064697265625 +75992 -0.309814453125 +75993 -0.629058837890625 +75994 -0.33905029296875 +75995 -0.697601318359375 +75996 -0.338470458984375 +75997 -0.70391845703125 +75998 -0.305633544921875 +75999 -0.6424560546875 +76000 -0.230377197265625 +76001 -0.491241455078125 +76002 -0.120208740234375 +76003 -0.265716552734375 +76004 -0.002655029296875 +76005 -0.023712158203125 +76006 0.106536865234375 +76007 0.201751708984375 +76008 0.190765380859375 +76009 0.375823974609375 +76010 0.24359130859375 +76011 0.485076904296875 +76012 0.283538818359375 +76013 0.56884765625 +76014 0.314239501953125 +76015 0.634765625 +76016 0.314422607421875 +76017 0.63763427734375 +76018 0.27874755859375 +76019 0.5660400390625 +76020 0.231903076171875 +76021 0.4720458984375 +76022 0.1982421875 +76023 0.40692138671875 +76024 0.18133544921875 +76025 0.3778076171875 +76026 0.177703857421875 +76027 0.376953125 +76028 0.1722412109375 +76029 0.371978759765625 +76030 0.141632080078125 +76031 0.313140869140625 +76032 0.078216552734375 +76033 0.184417724609375 +76034 -0.006103515625 +76035 0.011199951171875 +76036 -0.09423828125 +76037 -0.171051025390625 +76038 -0.173919677734375 +76039 -0.33740234375 +76040 -0.2374267578125 +76041 -0.47198486328125 +76042 -0.277801513671875 +76043 -0.560394287109375 +76044 -0.284149169921875 +76045 -0.58056640625 +76046 -0.2642822265625 +76047 -0.54754638671875 +76048 -0.2421875 +76049 -0.508575439453125 +76050 -0.215850830078125 +76051 -0.459503173828125 +76052 -0.182373046875 +76053 -0.394378662109375 +76054 -0.16156005859375 +76055 -0.35260009765625 +76056 -0.142059326171875 +76057 -0.31170654296875 +76058 -0.08636474609375 +76059 -0.197418212890625 +76060 0.00653076171875 +76061 -0.007965087890625 +76062 0.11199951171875 +76063 0.207489013671875 +76064 0.210235595703125 +76065 0.409210205078125 +76066 0.28875732421875 +76067 0.57208251953125 +76068 0.33258056640625 +76069 0.66595458984375 +76070 0.325714111328125 +76071 0.65875244140625 +76072 0.27691650390625 +76073 0.56744384765625 +76074 0.206146240234375 +76075 0.431396484375 +76076 0.1356201171875 +76077 0.29443359375 +76078 0.07843017578125 +76079 0.182464599609375 +76080 0.0185546875 +76081 0.06365966796875 +76082 -0.051055908203125 +76083 -0.075958251953125 +76084 -0.1068115234375 +76085 -0.189422607421875 +76086 -0.1463623046875 +76087 -0.271942138671875 +76088 -0.179412841796875 +76089 -0.342529296875 +76090 -0.1875 +76091 -0.364166259765625 +76092 -0.16595458984375 +76093 -0.327239990234375 +76094 -0.1376953125 +76095 -0.2769775390625 +76096 -0.123199462890625 +76097 -0.253692626953125 +76098 -0.115692138671875 +76099 -0.24365234375 +76100 -0.090850830078125 +76101 -0.1983642578125 +76102 -0.048004150390625 +76103 -0.116241455078125 +76104 -0.00714111328125 +76105 -0.036834716796875 +76106 0.029205322265625 +76107 0.034881591796875 +76108 0.05718994140625 +76109 0.09124755859375 +76110 0.065093994140625 +76111 0.10888671875 +76112 0.07196044921875 +76113 0.125518798828125 +76114 0.08624267578125 +76115 0.15771484375 +76116 0.094329833984375 +76117 0.17828369140625 +76118 0.088226318359375 +76119 0.17108154296875 +76120 0.06500244140625 +76121 0.129974365234375 +76122 0.03863525390625 +76123 0.082427978515625 +76124 0.008880615234375 +76125 0.027679443359375 +76126 -0.039947509765625 +76127 -0.065643310546875 +76128 -0.0885009765625 +76129 -0.15936279296875 +76130 -0.11639404296875 +76131 -0.21307373046875 +76132 -0.1275634765625 +76133 -0.234649658203125 +76134 -0.109954833984375 +76135 -0.2001953125 +76136 -0.068389892578125 +76137 -0.119171142578125 +76138 -0.019622802734375 +76139 -0.024749755859375 +76140 0.037628173828125 +76141 0.085784912109375 +76142 0.0859375 +76143 0.178131103515625 +76144 0.106719970703125 +76145 0.215576171875 +76146 0.106597900390625 +76147 0.211456298828125 +76148 0.09027099609375 +76149 0.17523193359375 +76150 0.068634033203125 +76151 0.128753662109375 +76152 0.056671142578125 +76153 0.1019287109375 +76154 0.04400634765625 +76155 0.0743408203125 +76156 0.0291748046875 +76157 0.04327392578125 +76158 0.027008056640625 +76159 0.038177490234375 +76160 0.046142578125 +76161 0.076263427734375 +76162 0.078277587890625 +76163 0.14105224609375 +76164 0.100250244140625 +76165 0.186431884765625 +76166 0.1002197265625 +76167 0.188812255859375 +76168 0.07366943359375 +76169 0.1390380859375 +76170 0.023040771484375 +76171 0.041778564453125 +76172 -0.0396728515625 +76173 -0.079437255859375 +76174 -0.111785888671875 +76175 -0.219390869140625 +76176 -0.188018798828125 +76177 -0.367828369140625 +76178 -0.253265380859375 +76179 -0.494873046875 +76180 -0.28515625 +76181 -0.556243896484375 +76182 -0.2618408203125 +76183 -0.508697509765625 +76184 -0.195068359375 +76185 -0.3756103515625 +76186 -0.1160888671875 +76187 -0.218902587890625 +76188 -0.037567138671875 +76189 -0.063751220703125 +76190 0.041290283203125 +76191 0.091552734375 +76192 0.11492919921875 +76193 0.23602294921875 +76194 0.16986083984375 +76195 0.342987060546875 +76196 0.19732666015625 +76197 0.39520263671875 +76198 0.19561767578125 +76199 0.389373779296875 +76200 0.16400146484375 +76201 0.324249267578125 +76202 0.11468505859375 +76203 0.224090576171875 +76204 0.065399169921875 +76205 0.124267578125 +76206 0.022308349609375 +76207 0.037078857421875 +76208 -0.000823974609375 +76209 -0.010101318359375 +76210 -0.005126953125 +76211 -0.019439697265625 +76212 -0.006683349609375 +76213 -0.022796630859375 +76214 0.003875732421875 +76215 -0.001556396484375 +76216 0.032623291015625 +76217 0.056304931640625 +76218 0.057403564453125 +76219 0.106719970703125 +76220 0.0516357421875 +76221 0.096893310546875 +76222 0.02337646484375 +76223 0.042694091796875 +76224 -0.00823974609375 +76225 -0.018035888671875 +76226 -0.03839111328125 +76227 -0.07586669921875 +76228 -0.061309814453125 +76229 -0.11944580078125 +76230 -0.082489013671875 +76231 -0.15972900390625 +76232 -0.104827880859375 +76233 -0.202606201171875 +76234 -0.128509521484375 +76235 -0.24859619140625 +76236 -0.15728759765625 +76237 -0.30517578125 +76238 -0.18603515625 +76239 -0.36212158203125 +76240 -0.20068359375 +76241 -0.39141845703125 +76242 -0.18212890625 +76243 -0.35528564453125 +76244 -0.1285400390625 +76245 -0.249969482421875 +76246 -0.0487060546875 +76247 -0.092864990234375 +76248 0.043701171875 +76249 0.08905029296875 +76250 0.118133544921875 +76251 0.2352294921875 +76252 0.161041259765625 +76253 0.318817138671875 +76254 0.18182373046875 +76255 0.358642578125 +76256 0.176971435546875 +76257 0.347747802734375 +76258 0.14617919921875 +76259 0.28564453125 +76260 0.115081787109375 +76261 0.223175048828125 +76262 0.10198974609375 +76263 0.196746826171875 +76264 0.093536376953125 +76265 0.179840087890625 +76266 0.081207275390625 +76267 0.155548095703125 +76268 0.07879638671875 +76269 0.151214599609375 +76270 0.081329345703125 +76271 0.156951904296875 +76272 0.06817626953125 +76273 0.13177490234375 +76274 0.052001953125 +76275 0.100799560546875 +76276 0.04449462890625 +76277 0.087127685546875 +76278 0.027587890625 +76279 0.05487060546875 +76280 -0.005218505859375 +76281 -0.009002685546875 +76282 -0.053619384765625 +76283 -0.10400390625 +76284 -0.11724853515625 +76285 -0.229400634765625 +76286 -0.18115234375 +76287 -0.35552978515625 +76288 -0.225067138671875 +76289 -0.441925048828125 +76290 -0.241912841796875 +76291 -0.473846435546875 +76292 -0.238616943359375 +76293 -0.464813232421875 +76294 -0.21685791015625 +76295 -0.419097900390625 +76296 -0.174835205078125 +76297 -0.334320068359375 +76298 -0.121429443359375 +76299 -0.227935791015625 +76300 -0.06890869140625 +76301 -0.12347412109375 +76302 -0.02056884765625 +76303 -0.02764892578125 +76304 0.03350830078125 +76305 0.077667236328125 +76306 0.10455322265625 +76307 0.2132568359375 +76308 0.197845458984375 +76309 0.38885498046875 +76310 0.3017578125 +76311 0.582794189453125 +76312 0.383544921875 +76313 0.734039306640625 +76314 0.42034912109375 +76315 0.800140380859375 +76316 0.410552978515625 +76317 0.7783203125 +76318 0.3521728515625 +76319 0.6651611328125 +76320 0.244537353515625 +76321 0.45965576171875 +76322 0.107513427734375 +76323 0.199188232421875 +76324 -0.023895263671875 +76325 -0.050689697265625 +76326 -0.11932373046875 +76327 -0.23297119140625 +76328 -0.16949462890625 +76329 -0.33013916015625 +76330 -0.18853759765625 +76331 -0.368408203125 +76332 -0.1932373046875 +76333 -0.378936767578125 +76334 -0.19183349609375 +76335 -0.376983642578125 +76336 -0.193511962890625 +76337 -0.37969970703125 +76338 -0.200592041015625 +76339 -0.391510009765625 +76340 -0.198516845703125 +76341 -0.385345458984375 +76342 -0.1768798828125 +76343 -0.3419189453125 +76344 -0.147186279296875 +76345 -0.28289794921875 +76346 -0.132537841796875 +76347 -0.251617431640625 +76348 -0.14251708984375 +76349 -0.266143798828125 +76350 -0.14849853515625 +76351 -0.273345947265625 +76352 -0.1201171875 +76353 -0.216796875 +76354 -0.07427978515625 +76355 -0.128265380859375 +76356 -0.043304443359375 +76357 -0.068145751953125 +76358 -0.03070068359375 +76359 -0.0430908203125 +76360 -0.021087646484375 +76361 -0.024444580078125 +76362 0.003204345703125 +76363 0.020721435546875 +76364 0.059356689453125 +76365 0.124481201171875 +76366 0.13177490234375 +76367 0.25787353515625 +76368 0.197998046875 +76369 0.379119873046875 +76370 0.253509521484375 +76371 0.47991943359375 +76372 0.281036376953125 +76373 0.5281982421875 +76374 0.273590087890625 +76375 0.511138916015625 +76376 0.245819091796875 +76377 0.456207275390625 +76378 0.22125244140625 +76379 0.407470703125 +76380 0.20989990234375 +76381 0.383758544921875 +76382 0.196563720703125 +76383 0.35687255859375 +76384 0.17315673828125 +76385 0.31182861328125 +76386 0.140869140625 +76387 0.250885009765625 +76388 0.095062255859375 +76389 0.1654052734375 +76390 0.024993896484375 +76391 0.035247802734375 +76392 -0.070648193359375 +76393 -0.142059326171875 +76394 -0.175262451171875 +76395 -0.33563232421875 +76396 -0.282958984375 +76397 -0.5345458984375 +76398 -0.384552001953125 +76399 -0.72186279296875 +76400 -0.447357177734375 +76401 -0.836669921875 +76402 -0.44647216796875 +76403 -0.8326416015625 +76404 -0.392486572265625 +76405 -0.7296142578125 +76406 -0.31475830078125 +76407 -0.582550048828125 +76408 -0.23931884765625 +76409 -0.440093994140625 +76410 -0.177947998046875 +76411 -0.324310302734375 +76412 -0.112548828125 +76413 -0.20147705078125 +76414 -0.02862548828125 +76415 -0.044647216796875 +76416 0.0511474609375 +76417 0.103973388671875 +76418 0.104248046875 +76419 0.202392578125 +76420 0.138092041015625 +76421 0.264495849609375 +76422 0.1787109375 +76423 0.338897705078125 +76424 0.23583984375 +76425 0.443817138671875 +76426 0.29107666015625 +76427 0.545074462890625 +76428 0.330780029296875 +76429 0.6173095703125 +76430 0.3505859375 +76431 0.6524658203125 +76432 0.357330322265625 +76433 0.66339111328125 +76434 0.35418701171875 +76435 0.6561279296875 +76436 0.32830810546875 +76437 0.606781005859375 +76438 0.2720947265625 +76439 0.501190185546875 +76440 0.192718505859375 +76441 0.352783203125 +76442 0.09820556640625 +76443 0.176544189453125 +76444 -0.01531982421875 +76445 -0.034820556640625 +76446 -0.13543701171875 +76447 -0.258209228515625 +76448 -0.23468017578125 +76449 -0.44244384765625 +76450 -0.30645751953125 +76451 -0.5753173828125 +76452 -0.348236083984375 +76453 -0.65203857421875 +76454 -0.343353271484375 +76455 -0.641632080078125 +76456 -0.301483154296875 +76457 -0.562164306640625 +76458 -0.246368408203125 +76459 -0.458038330078125 +76460 -0.18939208984375 +76461 -0.350555419921875 +76462 -0.14166259765625 +76463 -0.260528564453125 +76464 -0.105377197265625 +76465 -0.192108154296875 +76466 -0.0787353515625 +76467 -0.141937255859375 +76468 -0.0574951171875 +76469 -0.1021728515625 +76470 -0.036346435546875 +76471 -0.062896728515625 +76472 -0.008758544921875 +76473 -0.011932373046875 +76474 0.031707763671875 +76475 0.062835693359375 +76476 0.0782470703125 +76477 0.148712158203125 +76478 0.128662109375 +76479 0.241729736328125 +76480 0.186798095703125 +76481 0.34912109375 +76482 0.245361328125 +76483 0.457305908203125 +76484 0.29229736328125 +76485 0.54388427734375 +76486 0.30828857421875 +76487 0.5728759765625 +76488 0.27313232421875 +76489 0.506591796875 +76490 0.19012451171875 +76491 0.351226806640625 +76492 0.08056640625 +76493 0.146514892578125 +76494 -0.027496337890625 +76495 -0.05523681640625 +76496 -0.113800048828125 +76497 -0.21624755859375 +76498 -0.177520751953125 +76499 -0.334930419921875 +76500 -0.214202880859375 +76501 -0.402984619140625 +76502 -0.235015869140625 +76503 -0.4412841796875 +76504 -0.26458740234375 +76505 -0.49578857421875 +76506 -0.299468994140625 +76507 -0.5601806640625 +76508 -0.32159423828125 +76509 -0.600738525390625 +76510 -0.3131103515625 +76511 -0.584228515625 +76512 -0.2572021484375 +76513 -0.47930908203125 +76514 -0.15032958984375 +76515 -0.27935791015625 +76516 -0.005615234375 +76517 -0.0089111328125 +76518 0.14300537109375 +76519 0.268798828125 +76520 0.257537841796875 +76521 0.482818603515625 +76522 0.322235107421875 +76523 0.60369873046875 +76524 0.347259521484375 +76525 0.650421142578125 +76526 0.354583740234375 +76527 0.66400146484375 +76528 0.3426513671875 +76529 0.6414794921875 +76530 0.305877685546875 +76531 0.572540283203125 +76532 0.266204833984375 +76533 0.498138427734375 +76534 0.2349853515625 +76535 0.439453125 +76536 0.20098876953125 +76537 0.375518798828125 +76538 0.147125244140625 +76539 0.274505615234375 +76540 0.058563232421875 +76541 0.1087646484375 +76542 -0.052734375 +76543 -0.099395751953125 +76544 -0.170257568359375 +76545 -0.3182373046875 +76546 -0.2955322265625 +76547 -0.5489501953125 +76548 -0.418792724609375 +76549 -0.7738037109375 +76550 -0.510162353515625 +76551 -0.86383056640625 +76552 -0.550872802734375 +76553 -0.870391845703125 +76554 -0.550933837890625 +76555 -0.86895751953125 +76556 -0.5177001953125 +76557 -0.861053466796875 +76558 -0.441192626953125 +76559 -0.765869140625 +76560 -0.314727783203125 +76561 -0.5301513671875 +76562 -0.14208984375 +76563 -0.214691162109375 +76564 0.052581787109375 +76565 0.137359619140625 +76566 0.240447998046875 +76567 0.474822998046875 +76568 0.40167236328125 +76569 0.76239013671875 +76570 0.521209716796875 +76571 0.867462158203125 +76572 0.59954833984375 +76573 0.870361328125 +76574 0.630340576171875 +76575 0.86480712890625 +76576 0.616790771484375 +76577 0.831817626953125 +76578 0.572845458984375 +76579 0.677581787109375 +76580 0.5018310546875 +76581 0.495880126953125 +76582 0.414215087890625 +76583 0.30767822265625 +76584 0.311126708984375 +76585 0.116180419921875 +76586 0.174407958984375 +76587 -0.110748291015625 +76588 -6.103515625e-05 +76589 -0.381805419921875 +76590 -0.188232421875 +76591 -0.6572265625 +76592 -0.3563232421875 +76593 -0.857421875 +76594 -0.480194091796875 +76595 -0.870391845703125 +76596 -0.5560302734375 +76597 -0.870391845703125 +76598 -0.599334716796875 +76599 -0.86444091796875 +76600 -0.63055419921875 +76601 -0.85723876953125 +76602 -0.639404296875 +76603 -0.790008544921875 +76604 -0.595184326171875 +76605 -0.62847900390625 +76606 -0.49609375 +76607 -0.3956298828125 +76608 -0.36077880859375 +76609 -0.126708984375 +76610 -0.2047119140625 +76611 0.150115966796875 +76612 -0.034393310546875 +76613 0.424041748046875 +76614 0.134979248046875 +76615 0.670623779296875 +76616 0.28155517578125 +76617 0.854522705078125 +76618 0.395477294921875 +76619 0.866485595703125 +76620 0.468231201171875 +76621 0.86920166015625 +76622 0.51031494140625 +76623 0.8653564453125 +76624 0.529510498046875 +76625 0.857147216796875 +76626 0.524322509765625 +76627 0.766845703125 +76628 0.497772216796875 +76629 0.628509521484375 +76630 0.44610595703125 +76631 0.462127685546875 +76632 0.384002685546875 +76633 0.297210693359375 +76634 0.318511962890625 +76635 0.14862060546875 +76636 0.23663330078125 +76637 -0.00537109375 +76638 0.142547607421875 +76639 -0.15753173828125 +76640 0.03411865234375 +76641 -0.31304931640625 +76642 -0.09674072265625 +76643 -0.48876953125 +76644 -0.2235107421875 +76645 -0.6416015625 +76646 -0.332305908203125 +76647 -0.751373291015625 +76648 -0.4364013671875 +76649 -0.84619140625 +76650 -0.527587890625 +76651 -0.861297607421875 +76652 -0.587158203125 +76653 -0.863250732421875 +76654 -0.5972900390625 +76655 -0.856597900390625 +76656 -0.564971923828125 +76657 -0.7498779296875 +76658 -0.523101806640625 +76659 -0.624542236328125 +76660 -0.459197998046875 +76661 -0.47808837890625 +76662 -0.340057373046875 +76663 -0.253387451171875 +76664 -0.1915283203125 +76665 0.003692626953125 +76666 -0.052398681640625 +76667 0.2257080078125 +76668 0.084503173828125 +76669 0.427154541015625 +76670 0.237701416015625 +76671 0.643218994140625 +76672 0.40179443359375 +76673 0.855926513671875 +76674 0.543975830078125 +76675 0.870361328125 +76676 0.63616943359375 +76677 0.870361328125 +76678 0.682525634765625 +76679 0.862762451171875 +76680 0.68145751953125 +76681 0.79669189453125 +76682 0.627685546875 +76683 0.595794677734375 +76684 0.537811279296875 +76685 0.362152099609375 +76686 0.42779541015625 +76687 0.1270751953125 +76688 0.3096923828125 +76689 -0.086944580078125 +76690 0.1846923828125 +76691 -0.2784423828125 +76692 0.032989501953125 +76693 -0.484832763671875 +76694 -0.15631103515625 +76695 -0.729583740234375 +76696 -0.3544921875 +76697 -0.86688232421875 +76698 -0.525634765625 +76699 -0.870391845703125 +76700 -0.666961669921875 +76701 -0.86859130859375 +76702 -0.77734375 +76703 -0.86279296875 +76704 -0.83636474609375 +76705 -0.817962646484375 +76706 -0.818267822265625 +76707 -0.6116943359375 +76708 -0.71905517578125 +76709 -0.3128662109375 +76710 -0.55792236328125 +76711 0.039398193359375 +76712 -0.3463134765625 +76713 0.422821044921875 +76714 -0.103179931640625 +76715 0.805145263671875 +76716 0.132720947265625 +76717 0.870361328125 +76718 0.328948974609375 +76719 0.870361328125 +76720 0.478759765625 +76721 0.860015869140625 +76722 0.577728271484375 +76723 0.727935791015625 +76724 0.62255859375 +76725 0.48114013671875 +76726 0.62689208984375 +76727 0.2059326171875 +76728 0.603485107421875 +76729 -0.06103515625 +76730 0.5579833984375 +76731 -0.29913330078125 +76732 0.482147216796875 +76733 -0.516204833984375 +76734 0.36724853515625 +76735 -0.7252197265625 +76736 0.2275390625 +76737 -0.85980224609375 +76738 0.0826416015625 +76739 -0.870391845703125 +76740 -0.0504150390625 +76741 -0.870391845703125 +76742 -0.14373779296875 +76743 -0.858062744140625 +76744 -0.19464111328125 +76745 -0.673004150390625 +76746 -0.232635498046875 +76747 -0.42694091796875 +76748 -0.28265380859375 +76749 -0.2100830078125 +76750 -0.343231201171875 +76751 -0.0362548828125 +76752 -0.3975830078125 +76753 0.10943603515625 +76754 -0.4342041015625 +76755 0.23516845703125 +76756 -0.42950439453125 +76757 0.373687744140625 +76758 -0.384490966796875 +76759 0.517791748046875 +76760 -0.3349609375 +76761 0.602783203125 +76762 -0.278076171875 +76763 0.635711669921875 +76764 -0.195068359375 +76765 0.655181884765625 +76766 -0.091796875 +76767 0.65948486328125 +76768 0.026885986328125 +76769 0.651275634765625 +76770 0.146728515625 +76771 0.61846923828125 +76772 0.246368408203125 +76773 0.53753662109375 +76774 0.31524658203125 +76775 0.404144287109375 +76776 0.3475341796875 +76777 0.22186279296875 +76778 0.3436279296875 +76779 0.003997802734375 +76780 0.3135986328125 +76781 -0.22100830078125 +76782 0.26904296875 +76783 -0.42449951171875 +76784 0.221954345703125 +76785 -0.579833984375 +76786 0.19659423828125 +76787 -0.641876220703125 +76788 0.18927001953125 +76789 -0.6177978515625 +76790 0.163421630859375 +76791 -0.575531005859375 +76792 0.116180419921875 +76793 -0.526336669921875 +76794 0.077239990234375 +76795 -0.42645263671875 +76796 0.062469482421875 +76797 -0.2581787109375 +76798 0.051513671875 +76799 -0.068695068359375 +76800 0.0233154296875 +76801 0.09222412109375 +76802 -0.010650634765625 +76803 0.232147216796875 +76804 -0.044830322265625 +76805 0.3509521484375 +76806 -0.097320556640625 +76807 0.410064697265625 +76808 -0.186004638671875 +76809 0.372955322265625 +76810 -0.29852294921875 +76811 0.2554931640625 +76812 -0.40374755859375 +76813 0.10711669921875 +76814 -0.49005126953125 +76815 -0.052886962890625 +76816 -0.535797119140625 +76817 -0.186279296875 +76818 -0.50750732421875 +76819 -0.23291015625 +76820 -0.41888427734375 +76821 -0.209442138671875 +76822 -0.309478759765625 +76823 -0.174163818359375 +76824 -0.18426513671875 +76825 -0.126739501953125 +76826 -0.037322998046875 +76827 -0.048126220703125 +76828 0.114410400390625 +76829 0.0426025390625 +76830 0.242950439453125 +76831 0.10748291015625 +76832 0.340301513671875 +76833 0.1409912109375 +76834 0.435028076171875 +76835 0.19708251953125 +76836 0.52301025390625 +76837 0.273651123046875 +76838 0.570709228515625 +76839 0.31768798828125 +76840 0.584716796875 +76841 0.341094970703125 +76842 0.580108642578125 +76843 0.368011474609375 +76844 0.543060302734375 +76845 0.37249755859375 +76846 0.4439697265625 +76847 0.30072021484375 +76848 0.285797119140625 +76849 0.1517333984375 +76850 0.108489990234375 +76851 -0.01470947265625 +76852 -0.077301025390625 +76853 -0.1883544921875 +76854 -0.269073486328125 +76855 -0.372711181640625 +76856 -0.43017578125 +76857 -0.51397705078125 +76858 -0.5323486328125 +76859 -0.57177734375 +76860 -0.56817626953125 +76861 -0.53948974609375 +76862 -0.54583740234375 +76863 -0.43511962890625 +76864 -0.486114501953125 +76865 -0.2962646484375 +76866 -0.411102294921875 +76867 -0.161102294921875 +76868 -0.329345703125 +76869 -0.0435791015625 +76870 -0.239501953125 +76871 0.060394287109375 +76872 -0.152008056640625 +76873 0.13665771484375 +76874 -0.078582763671875 +76875 0.170135498046875 +76876 -0.0196533203125 +76877 0.16552734375 +76878 0.041778564453125 +76879 0.15728759765625 +76880 0.105224609375 +76881 0.150787353515625 +76882 0.152557373046875 +76883 0.12200927734375 +76884 0.18585205078125 +76885 0.080108642578125 +76886 0.2177734375 +76887 0.05126953125 +76888 0.26239013671875 +76889 0.062896728515625 +76890 0.304595947265625 +76891 0.09271240234375 +76892 0.3148193359375 +76893 0.092987060546875 +76894 0.301788330078125 +76895 0.07855224609375 +76896 0.275115966796875 +76897 0.06427001953125 +76898 0.226959228515625 +76899 0.0347900390625 +76900 0.158203125 +76901 -0.01171875 +76902 0.0828857421875 +76903 -0.056060791015625 +76904 0.029541015625 +76905 -0.055511474609375 +76906 0.001007080078125 +76907 -0.010467529296875 +76908 -0.031982421875 +76909 0.02508544921875 +76910 -0.081787109375 +76911 0.025665283203125 +76912 -0.130157470703125 +76913 0.017333984375 +76914 -0.173858642578125 +76915 0.00189208984375 +76916 -0.217926025390625 +76917 -0.03173828125 +76918 -0.254150390625 +76919 -0.071502685546875 +76920 -0.292999267578125 +76921 -0.13543701171875 +76922 -0.3326416015625 +76923 -0.219970703125 +76924 -0.3592529296875 +76925 -0.300506591796875 +76926 -0.373870849609375 +76927 -0.376312255859375 +76928 -0.35968017578125 +76929 -0.416107177734375 +76930 -0.289703369140625 +76931 -0.371124267578125 +76932 -0.166961669921875 +76933 -0.242279052734375 +76934 -0.01812744140625 +76935 -0.069732666015625 +76936 0.141815185546875 +76937 0.125640869140625 +76938 0.291900634765625 +76939 0.31268310546875 +76940 0.40838623046875 +76941 0.45501708984375 +76942 0.491058349609375 +76943 0.554779052734375 +76944 0.538116455078125 +76945 0.61065673828125 +76946 0.54205322265625 +76947 0.610931396484375 +76948 0.48846435546875 +76949 0.531463623046875 +76950 0.387603759765625 +76951 0.3883056640625 +76952 0.2724609375 +76953 0.23468017578125 +76954 0.159332275390625 +76955 0.095245361328125 +76956 0.06561279296875 +76957 -0.00396728515625 +76958 0.001953125 +76959 -0.04852294921875 +76960 -0.039581298828125 +76961 -0.055145263671875 +76962 -0.08807373046875 +76963 -0.0758056640625 +76964 -0.1585693359375 +76965 -0.138702392578125 +76966 -0.228546142578125 +76967 -0.209197998046875 +76968 -0.297698974609375 +76969 -0.289031982421875 +76970 -0.365447998046875 +76971 -0.37884521484375 +76972 -0.417816162109375 +76973 -0.456329345703125 +76974 -0.45172119140625 +76975 -0.51641845703125 +76976 -0.443634033203125 +76977 -0.519287109375 +76978 -0.3902587890625 +76979 -0.458251953125 +76980 -0.3236083984375 +76981 -0.384796142578125 +76982 -0.25994873046875 +76983 -0.323699951171875 +76984 -0.19744873046875 +76985 -0.269287109375 +76986 -0.122039794921875 +76987 -0.1951904296875 +76988 -0.034576416015625 +76989 -0.100006103515625 +76990 0.04718017578125 +76991 -0.01055908203125 +76992 0.139892578125 +76993 0.1033935546875 +76994 0.2467041015625 +76995 0.24908447265625 +76996 0.334716796875 +76997 0.373199462890625 +76998 0.392730712890625 +76999 0.45806884765625 +77000 0.42523193359375 +77001 0.511474609375 +77002 0.451568603515625 +77003 0.565399169921875 +77004 0.467193603515625 +77005 0.61138916015625 +77006 0.437103271484375 +77007 0.5897216796875 +77008 0.35650634765625 +77009 0.4906005859375 +77010 0.237152099609375 +77011 0.33148193359375 +77012 0.10162353515625 +77013 0.147796630859375 +77014 -0.023590087890625 +77015 -0.01873779296875 +77016 -0.120391845703125 +77017 -0.140289306640625 +77018 -0.172607421875 +77019 -0.191986083984375 +77020 -0.1854248046875 +77021 -0.184295654296875 +77022 -0.184783935546875 +77023 -0.161834716796875 +77024 -0.1953125 +77025 -0.166595458984375 +77026 -0.21392822265625 +77027 -0.19390869140625 +77028 -0.22906494140625 +77029 -0.22442626953125 +77030 -0.253997802734375 +77031 -0.279754638671875 +77032 -0.27679443359375 +77033 -0.3389892578125 +77034 -0.2696533203125 +77035 -0.3543701171875 +77036 -0.246917724609375 +77037 -0.348175048828125 +77038 -0.213043212890625 +77039 -0.32598876953125 +77040 -0.15142822265625 +77041 -0.2581787109375 +77042 -0.06024169921875 +77043 -0.139801025390625 +77044 0.05072021484375 +77045 0.014617919921875 +77046 0.14404296875 +77047 0.144378662109375 +77048 0.201904296875 +77049 0.221038818359375 +77050 0.23944091796875 +77051 0.27069091796875 +77052 0.256805419921875 +77053 0.294036865234375 +77054 0.266326904296875 +77055 0.311767578125 +77056 0.2774658203125 +77057 0.339141845703125 +77058 0.281463623046875 +77059 0.360260009765625 +77060 0.270050048828125 +77061 0.360504150390625 +77062 0.223876953125 +77063 0.308380126953125 +77064 0.12957763671875 +77065 0.18170166015625 +77066 0.00323486328125 +77067 0.0047607421875 +77068 -0.12481689453125 +77069 -0.17559814453125 +77070 -0.225372314453125 +77071 -0.3143310546875 +77072 -0.270294189453125 +77073 -0.36785888671875 +77074 -0.275634765625 +77075 -0.36248779296875 +77076 -0.2696533203125 +77077 -0.343536376953125 +77078 -0.246337890625 +77079 -0.3018798828125 +77080 -0.201751708984375 +77081 -0.231414794921875 +77082 -0.12677001953125 +77083 -0.117645263671875 +77084 -0.042144775390625 +77085 0.007049560546875 +77086 0.01715087890625 +77087 0.087982177734375 +77088 0.0596923828125 +77089 0.13946533203125 +77090 0.09295654296875 +77091 0.17425537109375 +77092 0.1136474609375 +77093 0.188201904296875 +77094 0.11474609375 +77095 0.171234130859375 +77096 0.092498779296875 +77097 0.118438720703125 +77098 0.063568115234375 +77099 0.05706787109375 +77100 0.028778076171875 +77101 -0.010711669921875 +77102 -0.016326904296875 +77103 -0.0914306640625 +77104 -0.057647705078125 +77105 -0.162322998046875 +77106 -0.07708740234375 +77107 -0.194549560546875 +77108 -0.050079345703125 +77109 -0.1492919921875 +77110 0.026611328125 +77111 -0.02166748046875 +77112 0.112640380859375 +77113 0.124053955078125 +77114 0.159912109375 +77115 0.211151123046875 +77116 0.16943359375 +77117 0.240447998046875 +77118 0.160858154296875 +77119 0.242218017578125 +77120 0.140625 +77121 0.2257080078125 +77122 0.111419677734375 +77123 0.194366455078125 +77124 0.053070068359375 +77125 0.115509033203125 +77126 -0.01898193359375 +77127 0.0128173828125 +77128 -0.0665283203125 +77129 -0.053802490234375 +77130 -0.10589599609375 +77131 -0.110626220703125 +77132 -0.1634521484375 +77133 -0.199493408203125 +77134 -0.22271728515625 +77135 -0.29437255859375 +77136 -0.243927001953125 +77137 -0.33221435546875 +77138 -0.206298828125 +77139 -0.27972412109375 +77140 -0.140716552734375 +77141 -0.185333251953125 +77142 -0.097564697265625 +77143 -0.128204345703125 +77144 -0.081878662109375 +77145 -0.115692138671875 +77146 -0.074310302734375 +77147 -0.116455078125 +77148 -0.059783935546875 +77149 -0.105926513671875 +77150 -0.019683837890625 +77151 -0.053955078125 +77152 0.051513671875 +77153 0.048797607421875 +77154 0.125030517578125 +77155 0.157318115234375 +77156 0.162994384765625 +77157 0.212005615234375 +77158 0.168792724609375 +77159 0.218475341796875 +77160 0.1806640625 +77161 0.23724365234375 +77162 0.222076416015625 +77163 0.30535888671875 +77164 0.266876220703125 +77165 0.38128662109375 +77166 0.2769775390625 +77167 0.404449462890625 +77168 0.265045166015625 +77169 0.3944091796875 +77170 0.25506591796875 +77171 0.3885498046875 +77172 0.232086181640625 +77173 0.362640380859375 +77174 0.16925048828125 +77175 0.27362060546875 +77176 0.064178466796875 +77177 0.11712646484375 +77178 -0.04998779296875 +77179 -0.054901123046875 +77180 -0.14031982421875 +77181 -0.19085693359375 +77182 -0.20343017578125 +77183 -0.28570556640625 +77184 -0.239105224609375 +77185 -0.339263916015625 +77186 -0.26373291015625 +77187 -0.3775634765625 +77188 -0.30584716796875 +77189 -0.445709228515625 +77190 -0.360076904296875 +77191 -0.535064697265625 +77192 -0.416107177734375 +77193 -0.629058837890625 +77194 -0.455108642578125 +77195 -0.697601318359375 +77196 -0.454132080078125 +77197 -0.70391845703125 +77198 -0.409942626953125 +77199 -0.6424560546875 +77200 -0.3089599609375 +77201 -0.491241455078125 +77202 -0.161224365234375 +77203 -0.265716552734375 +77204 -0.003570556640625 +77205 -0.023712158203125 +77206 0.142852783203125 +77207 0.201751708984375 +77208 0.255828857421875 +77209 0.375823974609375 +77210 0.326751708984375 +77211 0.485076904296875 +77212 0.38043212890625 +77213 0.56884765625 +77214 0.42169189453125 +77215 0.634765625 +77216 0.4219970703125 +77217 0.63763427734375 +77218 0.374237060546875 +77219 0.5660400390625 +77220 0.311492919921875 +77221 0.4720458984375 +77222 0.266357421875 +77223 0.40692138671875 +77224 0.24359130859375 +77225 0.3778076171875 +77226 0.238555908203125 +77227 0.376953125 +77228 0.23101806640625 +77229 0.371978759765625 +77230 0.189788818359375 +77231 0.313140869140625 +77232 0.104949951171875 +77233 0.184417724609375 +77234 -0.00726318359375 +77235 0.011199951171875 +77236 -0.124298095703125 +77237 -0.171051025390625 +77238 -0.2303466796875 +77239 -0.33740234375 +77240 -0.315338134765625 +77241 -0.47198486328125 +77242 -0.370208740234375 +77243 -0.560394287109375 +77244 -0.381103515625 +77245 -0.58056640625 +77246 -0.357666015625 +77247 -0.54754638671875 +77248 -0.329925537109375 +77249 -0.508575439453125 +77250 -0.295440673828125 +77251 -0.459503173828125 +77252 -0.250640869140625 +77253 -0.394378662109375 +77254 -0.220611572265625 +77255 -0.35260009765625 +77256 -0.19134521484375 +77257 -0.31170654296875 +77258 -0.116058349609375 +77259 -0.197418212890625 +77260 0.00616455078125 +77261 -0.007965087890625 +77262 0.14410400390625 +77263 0.207489013671875 +77264 0.2725830078125 +77265 0.409210205078125 +77266 0.375701904296875 +77267 0.57208251953125 +77268 0.434417724609375 +77269 0.66595458984375 +77270 0.42852783203125 +77271 0.65875244140625 +77272 0.36883544921875 +77273 0.56744384765625 +77274 0.280364990234375 +77275 0.431396484375 +77276 0.190948486328125 +77277 0.29443359375 +77278 0.117156982421875 +77279 0.182464599609375 +77280 0.039031982421875 +77281 0.06365966796875 +77282 -0.052093505859375 +77283 -0.075958251953125 +77284 -0.126373291015625 +77285 -0.189422607421875 +77286 -0.180633544921875 +77287 -0.271942138671875 +77288 -0.226776123046875 +77289 -0.342529296875 +77290 -0.241363525390625 +77291 -0.364166259765625 +77292 -0.21832275390625 +77293 -0.327239990234375 +77294 -0.18621826171875 +77295 -0.2769775390625 +77296 -0.170562744140625 +77297 -0.253692626953125 +77298 -0.1627197265625 +77299 -0.24365234375 +77300 -0.132171630859375 +77301 -0.1983642578125 +77302 -0.078033447265625 +77303 -0.116241455078125 +77304 -0.025390625 +77305 -0.036834716796875 +77306 0.022430419921875 +77307 0.034881591796875 +77308 0.060455322265625 +77309 0.09124755859375 +77310 0.07379150390625 +77311 0.10888671875 +77312 0.086517333984375 +77313 0.125518798828125 +77314 0.109161376953125 +77315 0.15771484375 +77316 0.12396240234375 +77317 0.17828369140625 +77318 0.1199951171875 +77319 0.17108154296875 +77320 0.093109130859375 +77321 0.129974365234375 +77322 0.06146240234375 +77323 0.082427978515625 +77324 0.024566650390625 +77325 0.027679443359375 +77326 -0.03839111328125 +77327 -0.065643310546875 +77328 -0.101959228515625 +77329 -0.15936279296875 +77330 -0.13922119140625 +77331 -0.21307373046875 +77332 -0.155303955078125 +77333 -0.234649658203125 +77334 -0.13421630859375 +77335 -0.2001953125 +77336 -0.082122802734375 +77337 -0.119171142578125 +77338 -0.020965576171875 +77339 -0.024749755859375 +77340 0.0511474609375 +77341 0.085784912109375 +77342 0.11151123046875 +77343 0.178131103515625 +77344 0.135833740234375 +77345 0.215576171875 +77346 0.132965087890625 +77347 0.211456298828125 +77348 0.10919189453125 +77349 0.17523193359375 +77350 0.0789794921875 +77351 0.128753662109375 +77352 0.062164306640625 +77353 0.1019287109375 +77354 0.045135498046875 +77355 0.0743408203125 +77356 0.0260009765625 +77357 0.04327392578125 +77358 0.024200439453125 +77359 0.038177490234375 +77360 0.05108642578125 +77361 0.076263427734375 +77362 0.095611572265625 +77363 0.14105224609375 +77364 0.127105712890625 +77365 0.186431884765625 +77366 0.12982177734375 +77367 0.188812255859375 +77368 0.09765625 +77369 0.1390380859375 +77370 0.033660888671875 +77371 0.041778564453125 +77372 -0.04656982421875 +77373 -0.079437255859375 +77374 -0.13958740234375 +77375 -0.219390869140625 +77376 -0.238555908203125 +77377 -0.367828369140625 +77378 -0.3236083984375 +77379 -0.494873046875 +77380 -0.36529541015625 +77381 -0.556243896484375 +77382 -0.3348388671875 +77383 -0.508697509765625 +77384 -0.247711181640625 +77385 -0.3756103515625 +77386 -0.14495849609375 +77387 -0.218902587890625 +77388 -0.043212890625 +77389 -0.063751220703125 +77390 0.058685302734375 +77391 0.091552734375 +77392 0.153533935546875 +77393 0.23602294921875 +77394 0.223663330078125 +77395 0.342987060546875 +77396 0.2576904296875 +77397 0.39520263671875 +77398 0.25347900390625 +77399 0.389373779296875 +77400 0.210174560546875 +77401 0.324249267578125 +77402 0.143890380859375 +77403 0.224090576171875 +77404 0.078094482421875 +77405 0.124267578125 +77406 0.0208740234375 +77407 0.037078857421875 +77408 -0.00958251953125 +77409 -0.010101318359375 +77410 -0.014801025390625 +77411 -0.019439697265625 +77412 -0.01593017578125 +77413 -0.022796630859375 +77414 -0.000701904296875 +77415 -0.001556396484375 +77416 0.038787841796875 +77417 0.056304931640625 +77418 0.073211669921875 +77419 0.106719970703125 +77420 0.067474365234375 +77421 0.096893310546875 +77422 0.0321044921875 +77423 0.042694091796875 +77424 -0.0078125 +77425 -0.018035888671875 +77426 -0.046051025390625 +77427 -0.07586669921875 +77428 -0.075042724609375 +77429 -0.11944580078125 +77430 -0.102081298828125 +77431 -0.15972900390625 +77432 -0.13104248046875 +77433 -0.202606201171875 +77434 -0.162200927734375 +77435 -0.24859619140625 +77436 -0.20050048828125 +77437 -0.30517578125 +77438 -0.239105224609375 +77439 -0.36212158203125 +77440 -0.2593994140625 +77441 -0.39141845703125 +77442 -0.236236572265625 +77443 -0.35528564453125 +77444 -0.1671142578125 +77445 -0.249969482421875 +77446 -0.06353759765625 +77447 -0.092864990234375 +77448 0.056640625 +77449 0.08905029296875 +77450 0.15325927734375 +77451 0.2352294921875 +77452 0.20849609375 +77453 0.318817138671875 +77454 0.23486328125 +77455 0.358642578125 +77456 0.227752685546875 +77457 0.347747802734375 +77458 0.186798095703125 +77459 0.28564453125 +77460 0.145751953125 +77461 0.223175048828125 +77462 0.12872314453125 +77463 0.196746826171875 +77464 0.11810302734375 +77465 0.179840087890625 +77466 0.102630615234375 +77467 0.155548095703125 +77468 0.100433349609375 +77469 0.151214599609375 +77470 0.10491943359375 +77471 0.156951904296875 +77472 0.08880615234375 +77473 0.13177490234375 +77474 0.0687255859375 +77475 0.100799560546875 +77476 0.060028076171875 +77477 0.087127685546875 +77478 0.038848876953125 +77479 0.05487060546875 +77480 -0.003448486328125 +77481 -0.009002685546875 +77482 -0.0665283203125 +77483 -0.10400390625 +77484 -0.14990234375 +77485 -0.229400634765625 +77486 -0.23388671875 +77487 -0.35552978515625 +77488 -0.29156494140625 +77489 -0.441925048828125 +77490 -0.31317138671875 +77491 -0.473846435546875 +77492 -0.307647705078125 +77493 -0.464813232421875 +77494 -0.277801513671875 +77495 -0.419097900390625 +77496 -0.222015380859375 +77497 -0.334320068359375 +77498 -0.151824951171875 +77499 -0.227935791015625 +77500 -0.0828857421875 +77501 -0.12347412109375 +77502 -0.01959228515625 +77503 -0.02764892578125 +77504 0.050079345703125 +77505 0.077667236328125 +77506 0.13995361328125 +77507 0.2132568359375 +77508 0.256500244140625 +77509 0.38885498046875 +77510 0.38531494140625 +77511 0.582794189453125 +77512 0.485870361328125 +77513 0.734039306640625 +77514 0.529937744140625 +77515 0.800140380859375 +77516 0.51568603515625 +77517 0.7783203125 +77518 0.440826416015625 +77519 0.6651611328125 +77520 0.3046875 +77521 0.45965576171875 +77522 0.132080078125 +77523 0.199188232421875 +77524 -0.033477783203125 +77525 -0.050689697265625 +77526 -0.154144287109375 +77527 -0.23297119140625 +77528 -0.218353271484375 +77529 -0.33013916015625 +77530 -0.24346923828125 +77531 -0.368408203125 +77532 -0.250213623046875 +77533 -0.378936767578125 +77534 -0.248748779296875 +77535 -0.376983642578125 +77536 -0.250457763671875 +77537 -0.37969970703125 +77538 -0.258270263671875 +77539 -0.391510009765625 +77540 -0.254241943359375 +77541 -0.385345458984375 +77542 -0.225555419921875 +77543 -0.3419189453125 +77544 -0.18658447265625 +77545 -0.28289794921875 +77546 -0.166107177734375 +77547 -0.251617431640625 +77548 -0.176055908203125 +77549 -0.266143798828125 +77550 -0.18115234375 +77551 -0.273345947265625 +77552 -0.1439208984375 +77553 -0.216796875 +77554 -0.085418701171875 +77555 -0.128265380859375 +77556 -0.0457763671875 +77557 -0.068145751953125 +77558 -0.029327392578125 +77559 -0.0430908203125 +77560 -0.01708984375 +77561 -0.024444580078125 +77562 0.0128173828125 +77563 0.020721435546875 +77564 0.081695556640625 +77565 0.124481201171875 +77566 0.1702880859375 +77567 0.25787353515625 +77568 0.25140380859375 +77569 0.379119873046875 +77570 0.31939697265625 +77571 0.47991943359375 +77572 0.351531982421875 +77573 0.5281982421875 +77574 0.339080810546875 +77575 0.511138916015625 +77576 0.301239013671875 +77577 0.456207275390625 +77578 0.2686767578125 +77579 0.407470703125 +77580 0.25445556640625 +77581 0.383758544921875 +77582 0.23876953125 +77583 0.35687255859375 +77584 0.21099853515625 +77585 0.31182861328125 +77586 0.172454833984375 +77587 0.250885009765625 +77588 0.116912841796875 +77589 0.1654052734375 +77590 0.030120849609375 +77591 0.035247802734375 +77592 -0.08984375 +77593 -0.142059326171875 +77594 -0.2216796875 +77595 -0.33563232421875 +77596 -0.357940673828125 +77597 -0.5345458984375 +77598 -0.486907958984375 +77599 -0.72186279296875 +77600 -0.566253662109375 +77601 -0.836669921875 +77602 -0.56378173828125 +77603 -0.8326416015625 +77604 -0.4932861328125 +77605 -0.7296142578125 +77606 -0.39288330078125 +77607 -0.582550048828125 +77608 -0.29632568359375 +77609 -0.440093994140625 +77610 -0.21881103515625 +77611 -0.324310302734375 +77612 -0.13665771484375 +77613 -0.20147705078125 +77614 -0.030914306640625 +77615 -0.044647216796875 +77616 0.0692138671875 +77617 0.103973388671875 +77618 0.134674072265625 +77619 0.202392578125 +77620 0.17529296875 +77621 0.264495849609375 +77622 0.22503662109375 +77623 0.338897705078125 +77624 0.296661376953125 +77625 0.443817138671875 +77626 0.366424560546875 +77627 0.545074462890625 +77628 0.416717529296875 +77629 0.6173095703125 +77630 0.44189453125 +77631 0.6524658203125 +77632 0.450836181640625 +77633 0.66339111328125 +77634 0.447662353515625 +77635 0.6561279296875 +77636 0.415618896484375 +77637 0.606781005859375 +77638 0.3447265625 +77639 0.501190185546875 +77640 0.244171142578125 +77641 0.352783203125 +77642 0.124237060546875 +77643 0.176544189453125 +77644 -0.020294189453125 +77645 -0.034820556640625 +77646 -0.173431396484375 +77647 -0.258209228515625 +77648 -0.299713134765625 +77649 -0.44244384765625 +77650 -0.390716552734375 +77651 -0.5753173828125 +77652 -0.443206787109375 +77653 -0.65203857421875 +77654 -0.435638427734375 +77655 -0.641632080078125 +77656 -0.380615234375 +77657 -0.562164306640625 +77658 -0.30902099609375 +77659 -0.458038330078125 +77660 -0.235565185546875 +77661 -0.350555419921875 +77662 -0.1746826171875 +77663 -0.260528564453125 +77664 -0.129150390625 +77665 -0.192108154296875 +77666 -0.096527099609375 +77667 -0.141937255859375 +77668 -0.071197509765625 +77669 -0.1021728515625 +77670 -0.046142578125 +77671 -0.062896728515625 +77672 -0.012725830078125 +77673 -0.011932373046875 +77674 0.037567138671875 +77675 0.062835693359375 +77676 0.095977783203125 +77677 0.148712158203125 +77678 0.159820556640625 +77679 0.241729736328125 +77680 0.234130859375 +77681 0.34912109375 +77682 0.30950927734375 +77683 0.457305908203125 +77684 0.370330810546875 +77685 0.54388427734375 +77686 0.39154052734375 +77687 0.5728759765625 +77688 0.3468017578125 +77689 0.506591796875 +77690 0.240325927734375 +77691 0.351226806640625 +77692 0.099700927734375 +77693 0.146514892578125 +77694 -0.038787841796875 +77695 -0.05523681640625 +77696 -0.14892578125 +77697 -0.21624755859375 +77698 -0.229705810546875 +77699 -0.334930419921875 +77700 -0.275482177734375 +77701 -0.402984619140625 +77702 -0.300872802734375 +77703 -0.4412841796875 +77704 -0.337921142578125 +77705 -0.49578857421875 +77706 -0.382232666015625 +77707 -0.5601806640625 +77708 -0.410400390625 +77709 -0.600738525390625 +77710 -0.3992919921875 +77711 -0.584228515625 +77712 -0.3270263671875 +77713 -0.47930908203125 +77714 -0.18896484375 +77715 -0.27935791015625 +77716 -0.0020751953125 +77717 -0.0089111328125 +77718 0.189666748046875 +77719 0.268798828125 +77720 0.337005615234375 +77721 0.482818603515625 +77722 0.419525146484375 +77723 0.60369873046875 +77724 0.45050048828125 +77725 0.650421142578125 +77726 0.458587646484375 +77727 0.66400146484375 +77728 0.4417724609375 +77729 0.6414794921875 +77730 0.3929443359375 +77731 0.572540283203125 +77732 0.34063720703125 +77733 0.498138427734375 +77734 0.29962158203125 +77735 0.439453125 +77736 0.255279541015625 +77737 0.375518798828125 +77738 0.185455322265625 +77739 0.274505615234375 +77740 0.070892333984375 +77741 0.1087646484375 +77742 -0.072967529296875 +77743 -0.099395751953125 +77744 -0.22406005859375 +77745 -0.3182373046875 +77746 -0.38330078125 +77747 -0.5489501953125 +77748 -0.538421630859375 +77749 -0.7738037109375 +77750 -0.65264892578125 +77751 -0.86383056640625 +77752 -0.702911376953125 +77753 -0.870391845703125 +77754 -0.70159912109375 +77755 -0.86895751953125 +77756 -0.65789794921875 +77757 -0.861053466796875 +77758 -0.559783935546875 +77759 -0.765869140625 +77760 -0.399444580078125 +77761 -0.5301513671875 +77762 -0.18182373046875 +77763 -0.214691162109375 +77764 0.063079833984375 +77765 0.137359619140625 +77766 0.299591064453125 +77767 0.474822998046875 +77768 0.503021240234375 +77769 0.76239013671875 +77770 0.654632568359375 +77771 0.867462158203125 +77772 0.7547607421875 +77773 0.870361328125 +77774 0.79541015625 +77775 0.86480712890625 +77776 0.7803955078125 +77777 0.831817626953125 +77778 0.726715087890625 +77779 0.677581787109375 +77780 0.638458251953125 +77781 0.495880126953125 +77782 0.528594970703125 +77783 0.30767822265625 +77784 0.398681640625 +77785 0.116180419921875 +77786 0.2266845703125 +77787 -0.110748291015625 +77788 0.007781982421875 +77789 -0.381805419921875 +77790 -0.228179931640625 +77791 -0.6572265625 +77792 -0.43951416015625 +77793 -0.857421875 +77794 -0.59637451171875 +77795 -0.870391845703125 +77796 -0.693817138671875 +77797 -0.870391845703125 +77798 -0.750579833984375 +77799 -0.86444091796875 +77800 -0.79156494140625 +77801 -0.85723876953125 +77802 -0.804046630859375 +77803 -0.790008544921875 +77804 -0.75030517578125 +77805 -0.62847900390625 +77806 -0.628173828125 +77807 -0.3956298828125 +77808 -0.460540771484375 +77809 -0.126708984375 +77810 -0.26654052734375 +77811 0.150115966796875 +77812 -0.0543212890625 +77813 0.424041748046875 +77814 0.15728759765625 +77815 0.670623779296875 +77816 0.34130859375 +77817 0.854522705078125 +77818 0.48541259765625 +77819 0.866485595703125 +77820 0.578887939453125 +77821 0.86920166015625 +77822 0.634368896484375 +77823 0.8653564453125 +77824 0.66094970703125 +77825 0.857147216796875 +77826 0.656890869140625 +77827 0.766845703125 +77828 0.6260986328125 +77829 0.628509521484375 +77830 0.563629150390625 +77831 0.462127685546875 +77832 0.4881591796875 +77833 0.297210693359375 +77834 0.408477783203125 +77835 0.14862060546875 +77836 0.307708740234375 +77837 -0.00537109375 +77838 0.19097900390625 +77839 -0.15753173828125 +77840 0.055328369140625 +77841 -0.31304931640625 +77842 -0.109771728515625 +77843 -0.48876953125 +77844 -0.2705078125 +77845 -0.6416015625 +77846 -0.409149169921875 +77847 -0.751373291015625 +77848 -0.542724609375 +77849 -0.84619140625 +77850 -0.66064453125 +77851 -0.861297607421875 +77852 -0.738861083984375 +77853 -0.863250732421875 +77854 -0.754425048828125 +77855 -0.856597900390625 +77856 -0.71612548828125 +77857 -0.7498779296875 +77858 -0.665924072265625 +77859 -0.624542236328125 +77860 -0.587646484375 +77861 -0.47808837890625 +77862 -0.438507080078125 +77863 -0.253387451171875 +77864 -0.251495361328125 +77865 0.003692626953125 +77866 -0.07611083984375 +77867 0.2257080078125 +77868 0.09698486328125 +77869 0.427154541015625 +77870 0.2916259765625 +77871 0.643218994140625 +77872 0.501007080078125 +77873 0.855926513671875 +77874 0.68310546875 +77875 0.870361328125 +77876 0.8018798828125 +77877 0.870361328125 +77878 0.855377197265625 +77879 0.862762451171875 +77880 0.855438232421875 +77881 0.79669189453125 +77882 0.7967529296875 +77883 0.595794677734375 +77884 0.684356689453125 +77885 0.362152099609375 +77886 0.54632568359375 +77887 0.1270751953125 +77888 0.397918701171875 +77889 -0.086944580078125 +77890 0.240509033203125 +77891 -0.2784423828125 +77892 0.048614501953125 +77893 -0.484832763671875 +77894 -0.191925048828125 +77895 -0.729583740234375 +77896 -0.44439697265625 +77897 -0.86688232421875 +77898 -0.662811279296875 +77899 -0.870391845703125 +77900 -0.843658447265625 +77901 -0.86859130859375 +77902 -0.868804931640625 +77903 -0.86279296875 +77904 -0.870391845703125 +77905 -0.817962646484375 +77906 -0.86181640625 +77907 -0.6116943359375 +77908 -0.7474365234375 +77909 -0.3128662109375 +77910 -0.504974365234375 +77911 0.039398193359375 +77912 -0.210296630859375 +77913 0.422821044921875 +77914 0.111358642578125 +77915 0.805145263671875 +77916 0.410186767578125 +77917 0.870361328125 +77918 0.64520263671875 +77919 0.870361328125 +77920 0.809051513671875 +77921 0.860015869140625 +77922 0.859222412109375 +77923 0.727935791015625 +77924 0.860504150390625 +77925 0.48114013671875 +77926 0.855621337890625 +77927 0.2059326171875 +77928 0.78277587890625 +77929 -0.06103515625 +77930 0.673187255859375 +77931 -0.29913330078125 +77932 0.528472900390625 +77933 -0.516204833984375 +77934 0.3399658203125 +77935 -0.7252197265625 +77936 0.1279296875 +77937 -0.85980224609375 +77938 -0.080841064453125 +77939 -0.870391845703125 +77940 -0.26361083984375 +77941 -0.870391845703125 +77942 -0.384246826171875 +77943 -0.858062744140625 +77944 -0.439605712890625 +77945 -0.673004150390625 +77946 -0.4683837890625 +77947 -0.42694091796875 +77948 -0.503875732421875 +77949 -0.2100830078125 +77950 -0.545989990234375 +77951 -0.0362548828125 +77952 -0.575408935546875 +77953 0.10943603515625 +77954 -0.579742431640625 +77955 0.23516845703125 +77956 -0.53106689453125 +77957 0.373687744140625 +77958 -0.43304443359375 +77959 0.517791748046875 +77960 -0.33367919921875 +77961 0.602783203125 +77962 -0.23114013671875 +77963 0.635711669921875 +77964 -0.102813720703125 +77965 0.655181884765625 +77966 0.04278564453125 +77967 0.65948486328125 +77968 0.199005126953125 +77969 0.651275634765625 +77970 0.347625732421875 +77971 0.61846923828125 +77972 0.46185302734375 +77973 0.53753662109375 +77974 0.529083251953125 +77975 0.404144287109375 +77976 0.543182373046875 +77977 0.22186279296875 +77978 0.50634765625 +77979 0.003997802734375 +77980 0.433349609375 +77981 -0.22100830078125 +77982 0.34100341796875 +77983 -0.42449951171875 +77984 0.246673583984375 +77985 -0.579833984375 +77986 0.1832275390625 +77987 -0.641876220703125 +77988 0.14752197265625 +77989 -0.6177978515625 +77990 0.093994140625 +77991 -0.575531005859375 +77992 0.01995849609375 +77993 -0.526336669921875 +77994 -0.0360107421875 +77995 -0.42645263671875 +77996 -0.053436279296875 +77997 -0.2581787109375 +77998 -0.0587158203125 +77999 -0.068695068359375 +78000 -0.08013916015625 +78001 0.09222412109375 +78002 -0.10479736328125 +78003 0.232147216796875 +78004 -0.126251220703125 +78005 0.3509521484375 +78006 -0.167205810546875 +78007 0.410064697265625 +78008 -0.2503662109375 +78009 0.372955322265625 +78010 -0.3619384765625 +78011 0.2554931640625 +78012 -0.46539306640625 +78013 0.10711669921875 +78014 -0.547821044921875 +78015 -0.052886962890625 +78016 -0.58404541015625 +78017 -0.186279296875 +78018 -0.534423828125 +78019 -0.23291015625 +78020 -0.416290283203125 +78021 -0.209442138671875 +78022 -0.278076171875 +78023 -0.174163818359375 +78024 -0.126007080078125 +78025 -0.126739501953125 +78026 0.04718017578125 +78027 -0.048126220703125 +78028 0.22137451171875 +78029 0.0426025390625 +78030 0.36328125 +78031 0.10748291015625 +78032 0.464080810546875 +78033 0.1409912109375 +78034 0.559417724609375 +78035 0.19708251953125 +78036 0.645416259765625 +78037 0.273651123046875 +78038 0.68255615234375 +78039 0.31768798828125 +78040 0.679931640625 +78041 0.341094970703125 +78042 0.65692138671875 +78043 0.368011474609375 +78044 0.59759521484375 +78045 0.37249755859375 +78046 0.466766357421875 +78047 0.30072021484375 +78048 0.268463134765625 +78049 0.1517333984375 +78050 0.051361083984375 +78051 -0.01470947265625 +78052 -0.171600341796875 +78053 -0.1883544921875 +78054 -0.397705078125 +78055 -0.372711181640625 +78056 -0.582916259765625 +78057 -0.51397705078125 +78058 -0.693603515625 +78059 -0.57177734375 +78060 -0.72161865234375 +78061 -0.53948974609375 +78062 -0.677764892578125 +78063 -0.43511962890625 +78064 -0.588165283203125 +78065 -0.2962646484375 +78066 -0.480621337890625 +78067 -0.161102294921875 +78068 -0.366363525390625 +78069 -0.0435791015625 +78070 -0.244537353515625 +78071 0.060394287109375 +78072 -0.12847900390625 +78073 0.13665771484375 +78074 -0.0328369140625 +78075 0.170135498046875 +78076 0.041595458984375 +78077 0.16552734375 +78078 0.115447998046875 +78079 0.15728759765625 +78080 0.18804931640625 +78081 0.150787353515625 +78082 0.23773193359375 +78083 0.12200927734375 +78084 0.26776123046875 +78085 0.080108642578125 +78086 0.294586181640625 +78087 0.05126953125 +78088 0.336395263671875 +78089 0.062896728515625 +78090 0.375030517578125 +78091 0.09271240234375 +78092 0.374298095703125 +78093 0.092987060546875 +78094 0.3458251953125 +78095 0.07855224609375 +78096 0.302215576171875 +78097 0.06427001953125 +78098 0.23419189453125 +78099 0.0347900390625 +78100 0.14324951171875 +78101 -0.01171875 +78102 0.04718017578125 +78103 -0.056060791015625 +78104 -0.018341064453125 +78105 -0.055511474609375 +78106 -0.049896240234375 +78107 -0.010467529296875 +78108 -0.08441162109375 +78109 0.02508544921875 +78110 -0.13775634765625 +78111 0.025665283203125 +78112 -0.187652587890625 +78113 0.017333984375 +78114 -0.23065185546875 +78115 0.00189208984375 +78116 -0.27374267578125 +78117 -0.03173828125 +78118 -0.30731201171875 +78119 -0.071502685546875 +78120 -0.345062255859375 +78121 -0.13543701171875 +78122 -0.385284423828125 +78123 -0.219970703125 +78124 -0.411163330078125 +78125 -0.300506591796875 +78126 -0.42431640625 +78127 -0.376312255859375 +78128 -0.4039306640625 +78129 -0.416107177734375 +78130 -0.316375732421875 +78131 -0.371124267578125 +78132 -0.165374755859375 +78133 -0.242279052734375 +78134 0.01593017578125 +78135 -0.069732666015625 +78136 0.209136962890625 +78137 0.125640869140625 +78138 0.38848876953125 +78139 0.31268310546875 +78140 0.5247802734375 +78141 0.45501708984375 +78142 0.6182861328125 +78143 0.554779052734375 +78144 0.667327880859375 +78145 0.61065673828125 +78146 0.663055419921875 +78147 0.610931396484375 +78148 0.587982177734375 +78149 0.531463623046875 +78150 0.45526123046875 +78151 0.3883056640625 +78152 0.30645751953125 +78153 0.23468017578125 +78154 0.16217041015625 +78155 0.095245361328125 +78156 0.04425048828125 +78157 -0.00396728515625 +78158 -0.03399658203125 +78159 -0.04852294921875 +78160 -0.082611083984375 +78161 -0.055145263671875 +78162 -0.138275146484375 +78163 -0.0758056640625 +78164 -0.220001220703125 +78165 -0.138702392578125 +78166 -0.30010986328125 +78167 -0.209197998046875 +78168 -0.378631591796875 +78169 -0.289031982421875 +78170 -0.455291748046875 +78171 -0.37884521484375 +78172 -0.513092041015625 +78173 -0.456329345703125 +78174 -0.54852294921875 +78175 -0.51641845703125 +78176 -0.532501220703125 +78177 -0.519287109375 +78178 -0.46124267578125 +78179 -0.458251953125 +78180 -0.375 +78181 -0.384796142578125 +78182 -0.294189453125 +78183 -0.323699951171875 +78184 -0.216583251953125 +78185 -0.269287109375 +78186 -0.124481201171875 +78187 -0.1951904296875 +78188 -0.018768310546875 +78189 -0.100006103515625 +78190 0.078582763671875 +78191 -0.01055908203125 +78192 0.188690185546875 +78193 0.1033935546875 +78194 0.315826416015625 +78195 0.24908447265625 +78196 0.419219970703125 +78197 0.373199462890625 +78198 0.48529052734375 +78199 0.45806884765625 +78200 0.51995849609375 +78201 0.511474609375 +78202 0.547760009765625 +78203 0.565399169921875 +78204 0.563232421875 +78205 0.61138916015625 +78206 0.522796630859375 +78207 0.5897216796875 +78208 0.420562744140625 +78209 0.4906005859375 +78210 0.27130126953125 +78211 0.33148193359375 +78212 0.10321044921875 +78213 0.147796630859375 +78214 -0.05072021484375 +78215 -0.01873779296875 +78216 -0.1680908203125 +78217 -0.140289306640625 +78218 -0.2288818359375 +78219 -0.191986083984375 +78220 -0.2398681640625 +78221 -0.184295654296875 +78222 -0.2337646484375 +78223 -0.161834716796875 +78224 -0.241607666015625 +78225 -0.166595458984375 +78226 -0.2598876953125 +78227 -0.19390869140625 +78228 -0.274383544921875 +78229 -0.22442626953125 +78230 -0.301910400390625 +78231 -0.279754638671875 +78232 -0.327728271484375 +78233 -0.3389892578125 +78234 -0.31719970703125 +78235 -0.3543701171875 +78236 -0.288330078125 +78237 -0.348175048828125 +78238 -0.24664306640625 +78239 -0.32598876953125 +78240 -0.171356201171875 +78241 -0.2581787109375 +78242 -0.06005859375 +78243 -0.139801025390625 +78244 0.0751953125 +78245 0.014617919921875 +78246 0.1878662109375 +78247 0.144378662109375 +78248 0.255950927734375 +78249 0.221038818359375 +78250 0.298553466796875 +78251 0.27069091796875 +78252 0.316070556640625 +78253 0.294036865234375 +78254 0.324188232421875 +78255 0.311767578125 +78256 0.334808349609375 +78257 0.339141845703125 +78258 0.3367919921875 +78259 0.360260009765625 +78260 0.320037841796875 +78261 0.360504150390625 +78262 0.26153564453125 +78263 0.308380126953125 +78264 0.145477294921875 +78265 0.18170166015625 +78266 -0.008544921875 +78267 0.0047607421875 +78268 -0.163909912109375 +78269 -0.17559814453125 +78270 -0.28546142578125 +78271 -0.3143310546875 +78272 -0.3392333984375 +78273 -0.36785888671875 +78274 -0.3446044921875 +78275 -0.36248779296875 +78276 -0.33563232421875 +78277 -0.343536376953125 +78278 -0.305206298828125 +78279 -0.3018798828125 +78280 -0.24871826171875 +78281 -0.231414794921875 +78282 -0.155426025390625 +78283 -0.117645263671875 +78284 -0.0504150390625 +78285 0.007049560546875 +78286 0.024078369140625 +78287 0.087982177734375 +78288 0.078155517578125 +78289 0.13946533203125 +78290 0.12066650390625 +78291 0.17425537109375 +78292 0.14752197265625 +78293 0.188201904296875 +78294 0.150146484375 +78295 0.171234130859375 +78296 0.1240234375 +78297 0.118438720703125 +78298 0.089141845703125 +78299 0.05706787109375 +78300 0.0465087890625 +78301 -0.010711669921875 +78302 -0.00921630859375 +78303 -0.0914306640625 +78304 -0.0609130859375 +78305 -0.162322998046875 +78306 -0.086669921875 +78307 -0.194549560546875 +78308 -0.056854248046875 +78309 -0.1492919921875 +78310 0.032562255859375 +78311 -0.02166748046875 +78312 0.13330078125 +78313 0.124053955078125 +78314 0.1876220703125 +78315 0.211151123046875 +78316 0.1968994140625 +78317 0.240447998046875 +78318 0.184814453125 +78319 0.242218017578125 +78320 0.159210205078125 +78321 0.2257080078125 +78322 0.123382568359375 +78323 0.194366455078125 +78324 0.0531005859375 +78325 0.115509033203125 +78326 -0.033050537109375 +78327 0.0128173828125 +78328 -0.089202880859375 +78329 -0.053802490234375 +78330 -0.135101318359375 +78331 -0.110626220703125 +78332 -0.2025146484375 +78333 -0.199493408203125 +78334 -0.271728515625 +78335 -0.29437255859375 +78336 -0.294677734375 +78337 -0.33221435546875 +78338 -0.2457275390625 +78339 -0.27972412109375 +78340 -0.163177490234375 +78341 -0.185333251953125 +78342 -0.10986328125 +78343 -0.128204345703125 +78344 -0.091827392578125 +78345 -0.115692138671875 +78346 -0.084564208984375 +78347 -0.116455078125 +78348 -0.068939208984375 +78349 -0.105926513671875 +78350 -0.021392822265625 +78351 -0.053955078125 +78352 0.065185546875 +78353 0.048797607421875 +78354 0.1549072265625 +78355 0.157318115234375 +78356 0.20037841796875 +78357 0.212005615234375 +78358 0.205963134765625 +78359 0.218475341796875 +78360 0.2196044921875 +78361 0.23724365234375 +78362 0.270721435546875 +78363 0.30535888671875 +78364 0.32659912109375 +78365 0.38128662109375 +78366 0.3394775390625 +78367 0.404449462890625 +78368 0.3251953125 +78369 0.3944091796875 +78370 0.313720703125 +78371 0.3885498046875 +78372 0.286285400390625 +78373 0.362640380859375 +78374 0.2091064453125 +78375 0.27362060546875 +78376 0.079071044921875 +78377 0.11712646484375 +78378 -0.062347412109375 +78379 -0.054901123046875 +78380 -0.17401123046875 +78381 -0.19085693359375 +78382 -0.251739501953125 +78383 -0.28570556640625 +78384 -0.295318603515625 +78385 -0.339263916015625 +78386 -0.3253173828125 +78387 -0.3775634765625 +78388 -0.377532958984375 +78389 -0.445709228515625 +78390 -0.44525146484375 +78391 -0.535064697265625 +78392 -0.51556396484375 +78393 -0.629058837890625 +78394 -0.56488037109375 +78395 -0.697601318359375 +78396 -0.564361572265625 +78397 -0.70391845703125 +78398 -0.50994873046875 +78399 -0.6424560546875 +78400 -0.384552001953125 +78401 -0.491241455078125 +78402 -0.20068359375 +78403 -0.265716552734375 +78404 -0.004425048828125 +78405 -0.023712158203125 +78406 0.17779541015625 +78407 0.201751708984375 +78408 0.318206787109375 +78409 0.375823974609375 +78410 0.406097412109375 +78411 0.485076904296875 +78412 0.472564697265625 +78413 0.56884765625 +78414 0.523712158203125 +78415 0.634765625 +78416 0.5238037109375 +78417 0.63763427734375 +78418 0.46392822265625 +78419 0.5660400390625 +78420 0.385528564453125 +78421 0.4720458984375 +78422 0.3294677734375 +78423 0.40692138671875 +78424 0.301666259765625 +78425 0.3778076171875 +78426 0.2962646484375 +78427 0.376953125 +78428 0.287872314453125 +78429 0.371978759765625 +78430 0.237335205078125 +78431 0.313140869140625 +78432 0.132110595703125 +78433 0.184417724609375 +78434 -0.007476806640625 +78435 0.011199951171875 +78436 -0.153228759765625 +78437 -0.171051025390625 +78438 -0.285369873046875 +78439 -0.33740234375 +78440 -0.391326904296875 +78441 -0.47198486328125 +78442 -0.459808349609375 +78443 -0.560394287109375 +78444 -0.473419189453125 +78445 -0.58056640625 +78446 -0.4442138671875 +78447 -0.54754638671875 +78448 -0.409820556640625 +78449 -0.508575439453125 +78450 -0.36712646484375 +78451 -0.459503173828125 +78452 -0.311676025390625 +78453 -0.394378662109375 +78454 -0.27484130859375 +78455 -0.35260009765625 +78456 -0.239044189453125 +78457 -0.31170654296875 +78458 -0.1456298828125 +78459 -0.197418212890625 +78460 0.00665283203125 +78461 -0.007965087890625 +78462 0.17877197265625 +78463 0.207489013671875 +78464 0.33917236328125 +78465 0.409210205078125 +78466 0.46795654296875 +78467 0.57208251953125 +78468 0.541290283203125 +78469 0.66595458984375 +78470 0.533843994140625 +78471 0.65875244140625 +78472 0.45916748046875 +78473 0.56744384765625 +78474 0.34857177734375 +78475 0.431396484375 +78476 0.236968994140625 +78477 0.29443359375 +78478 0.145050048828125 +78479 0.182464599609375 +78480 0.04779052734375 +78481 0.06365966796875 +78482 -0.065704345703125 +78483 -0.075958251953125 +78484 -0.1580810546875 +78485 -0.189422607421875 +78486 -0.225433349609375 +78487 -0.271942138671875 +78488 -0.28271484375 +78489 -0.342529296875 +78490 -0.300567626953125 +78491 -0.364166259765625 +78492 -0.2713623046875 +78493 -0.327239990234375 +78494 -0.230926513671875 +78495 -0.2769775390625 +78496 -0.21124267578125 +78497 -0.253692626953125 +78498 -0.201507568359375 +78499 -0.24365234375 +78500 -0.1634521484375 +78501 -0.1983642578125 +78502 -0.095916748046875 +78503 -0.116241455078125 +78504 -0.030364990234375 +78505 -0.036834716796875 +78506 0.029083251953125 +78507 0.034881591796875 +78508 0.076202392578125 +78509 0.09124755859375 +78510 0.092376708984375 +78511 0.10888671875 +78512 0.10736083984375 +78513 0.125518798828125 +78514 0.134185791015625 +78515 0.15771484375 +78516 0.1512451171875 +78517 0.17828369140625 +78518 0.145721435546875 +78519 0.17108154296875 +78520 0.11279296875 +78521 0.129974365234375 +78522 0.07421875 +78523 0.082427978515625 +78524 0.029510498046875 +78525 0.027679443359375 +78526 -0.046112060546875 +78527 -0.065643310546875 +78528 -0.122283935546875 +78529 -0.15936279296875 +78530 -0.166900634765625 +78531 -0.21307373046875 +78532 -0.18609619140625 +78533 -0.234649658203125 +78534 -0.16082763671875 +78535 -0.2001953125 +78536 -0.0985107421875 +78537 -0.119171142578125 +78538 -0.02532958984375 +78539 -0.024749755859375 +78540 0.06097412109375 +78541 0.085784912109375 +78542 0.13330078125 +78543 0.178131103515625 +78544 0.16259765625 +78545 0.215576171875 +78546 0.159393310546875 +78547 0.211456298828125 +78548 0.131195068359375 +78549 0.17523193359375 +78550 0.095306396484375 +78551 0.128753662109375 +78552 0.075347900390625 +78553 0.1019287109375 +78554 0.0550537109375 +78555 0.0743408203125 +78556 0.03216552734375 +78557 0.04327392578125 +78558 0.0299072265625 +78559 0.038177490234375 +78560 0.06182861328125 +78561 0.076263427734375 +78562 0.114776611328125 +78563 0.14105224609375 +78564 0.152130126953125 +78565 0.186431884765625 +78566 0.1551513671875 +78567 0.188812255859375 +78568 0.11651611328125 +78569 0.1390380859375 +78570 0.0399169921875 +78571 0.041778564453125 +78572 -0.0560302734375 +78573 -0.079437255859375 +78574 -0.167205810546875 +78575 -0.219390869140625 +78576 -0.285430908203125 +78577 -0.367828369140625 +78578 -0.38702392578125 +78579 -0.494873046875 +78580 -0.43682861328125 +78581 -0.556243896484375 +78582 -0.400543212890625 +78583 -0.508697509765625 +78584 -0.296600341796875 +78585 -0.3756103515625 +78586 -0.1739501953125 +78587 -0.218902587890625 +78588 -0.05242919921875 +78589 -0.063751220703125 +78590 0.0693359375 +78591 0.091552734375 +78592 0.182769775390625 +78593 0.23602294921875 +78594 0.26678466796875 +78595 0.342987060546875 +78596 0.3074951171875 +78597 0.39520263671875 +78598 0.302001953125 +78599 0.389373779296875 +78600 0.249053955078125 +78601 0.324249267578125 +78602 0.168365478515625 +78603 0.224090576171875 +78604 0.0888671875 +78605 0.124267578125 +78606 0.0203857421875 +78607 0.037078857421875 +78608 -0.014739990234375 +78609 -0.010101318359375 +78610 -0.0185546875 +78611 -0.019439697265625 +78612 -0.01751708984375 +78613 -0.022796630859375 +78614 0.00347900390625 +78615 -0.001556396484375 +78616 0.054168701171875 +78617 0.056304931640625 +78618 0.09814453125 +78619 0.106719970703125 +78620 0.091796875 +78621 0.096893310546875 +78622 0.04815673828125 +78623 0.042694091796875 +78624 -0.001617431640625 +78625 -0.018035888671875 +78626 -0.04974365234375 +78627 -0.07586669921875 +78628 -0.0867919921875 +78629 -0.11944580078125 +78630 -0.12176513671875 +78631 -0.15972900390625 +78632 -0.15936279296875 +78633 -0.202606201171875 +78634 -0.199859619140625 +78635 -0.24859619140625 +78636 -0.249237060546875 +78637 -0.30517578125 +78638 -0.2989501953125 +78639 -0.36212158203125 +78640 -0.3258056640625 +78641 -0.39141845703125 +78642 -0.2984619140625 +78643 -0.35528564453125 +78644 -0.213714599609375 +78645 -0.249969482421875 +78646 -0.0858154296875 +78647 -0.092864990234375 +78648 0.063079833984375 +78649 0.08905029296875 +78650 0.18310546875 +78651 0.2352294921875 +78652 0.25213623046875 +78653 0.318817138671875 +78654 0.28564453125 +78655 0.358642578125 +78656 0.27789306640625 +78657 0.347747802734375 +78658 0.2283935546875 +78659 0.28564453125 +78660 0.178924560546875 +78661 0.223175048828125 +78662 0.15936279296875 +78663 0.196746826171875 +78664 0.147735595703125 +78665 0.179840087890625 +78666 0.1300048828125 +78667 0.155548095703125 +78668 0.1285400390625 +78669 0.151214599609375 +78670 0.135101318359375 +78671 0.156951904296875 +78672 0.115814208984375 +78673 0.13177490234375 +78674 0.09130859375 +78675 0.100799560546875 +78676 0.08056640625 +78677 0.087127685546875 +78678 0.05401611328125 +78679 0.05487060546875 +78680 0.00091552734375 +78681 -0.009002685546875 +78682 -0.0782470703125 +78683 -0.10400390625 +78684 -0.182830810546875 +78685 -0.229400634765625 +78686 -0.288330078125 +78687 -0.35552978515625 +78688 -0.36126708984375 +78689 -0.441925048828125 +78690 -0.389434814453125 +78691 -0.473846435546875 +78692 -0.38385009765625 +78693 -0.464813232421875 +78694 -0.347900390625 +78695 -0.419097900390625 +78696 -0.279571533203125 +78697 -0.334320068359375 +78698 -0.193145751953125 +78699 -0.227935791015625 +78700 -0.10797119140625 +78701 -0.12347412109375 +78702 -0.029510498046875 +78703 -0.02764892578125 +78704 0.05718994140625 +78705 0.077667236328125 +78706 0.169189453125 +78707 0.2132568359375 +78708 0.314483642578125 +78709 0.38885498046875 +78710 0.475189208984375 +78711 0.582794189453125 +78712 0.6009521484375 +78713 0.734039306640625 +78714 0.65673828125 +78715 0.800140380859375 +78716 0.640167236328125 +78717 0.7783203125 +78718 0.548370361328125 +78719 0.6651611328125 +78720 0.38043212890625 +78721 0.45965576171875 +78722 0.167083740234375 +78723 0.199188232421875 +78724 -0.0377197265625 +78725 -0.050689697265625 +78726 -0.18707275390625 +78727 -0.23297119140625 +78728 -0.2666015625 +78729 -0.33013916015625 +78730 -0.297882080078125 +78731 -0.368408203125 +78732 -0.306610107421875 +78733 -0.378936767578125 +78734 -0.30535888671875 +78735 -0.376983642578125 +78736 -0.3082275390625 +78737 -0.37969970703125 +78738 -0.318817138671875 +78739 -0.391510009765625 +78740 -0.314788818359375 +78741 -0.385345458984375 +78742 -0.280181884765625 +78743 -0.3419189453125 +78744 -0.2327880859375 +78745 -0.28289794921875 +78746 -0.208221435546875 +78747 -0.251617431640625 +78748 -0.2213134765625 +78749 -0.266143798828125 +78750 -0.228240966796875 +78751 -0.273345947265625 +78752 -0.182464599609375 +78753 -0.216796875 +78754 -0.110076904296875 +78755 -0.128265380859375 +78756 -0.06085205078125 +78757 -0.068145751953125 +78758 -0.04022216796875 +78759 -0.0430908203125 +78760 -0.02459716796875 +78761 -0.024444580078125 +78762 0.01312255859375 +78763 0.020721435546875 +78764 0.099334716796875 +78765 0.124481201171875 +78766 0.210113525390625 +78767 0.25787353515625 +78768 0.31097412109375 +78769 0.379119873046875 +78770 0.395050048828125 +78771 0.47991943359375 +78772 0.43585205078125 +78773 0.5281982421875 +78774 0.422760009765625 +78775 0.511138916015625 +78776 0.37835693359375 +78777 0.456207275390625 +78778 0.338897705078125 +78779 0.407470703125 +78780 0.319854736328125 +78781 0.383758544921875 +78782 0.2979736328125 +78783 0.35687255859375 +78784 0.26092529296875 +78785 0.31182861328125 +78786 0.210540771484375 +78787 0.250885009765625 +78788 0.139739990234375 +78789 0.1654052734375 +78790 0.031951904296875 +78791 0.035247802734375 +78792 -0.114837646484375 +78793 -0.142059326171875 +78794 -0.275115966796875 +78795 -0.33563232421875 +78796 -0.4398193359375 +78797 -0.5345458984375 +78798 -0.594940185546875 +78799 -0.72186279296875 +78800 -0.690277099609375 +78801 -0.836669921875 +78802 -0.687652587890625 +78803 -0.8326416015625 +78804 -0.603363037109375 +78805 -0.7296142578125 +78806 -0.482635498046875 +78807 -0.582550048828125 +78808 -0.36553955078125 +78809 -0.440093994140625 +78810 -0.270263671875 +78811 -0.324310302734375 +78812 -0.16900634765625 +78813 -0.20147705078125 +78814 -0.03955078125 +78815 -0.044647216796875 +78816 0.083282470703125 +78817 0.103973388671875 +78818 0.164886474609375 +78819 0.202392578125 +78820 0.216644287109375 +78821 0.264495849609375 +78822 0.278594970703125 +78823 0.338897705078125 +78824 0.365692138671875 +78825 0.443817138671875 +78826 0.44976806640625 +78827 0.545074462890625 +78828 0.509857177734375 +78829 0.6173095703125 +78830 0.539337158203125 +78831 0.6524658203125 +78832 0.548736572265625 +78833 0.66339111328125 +78834 0.54302978515625 +78835 0.6561279296875 +78836 0.50250244140625 +78837 0.606781005859375 +78838 0.41546630859375 +78839 0.501190185546875 +78840 0.292999267578125 +78841 0.352783203125 +78842 0.1474609375 +78843 0.176544189453125 +78844 -0.027130126953125 +78845 -0.034820556640625 +78846 -0.211700439453125 +78847 -0.258209228515625 +78848 -0.3638916015625 +78849 -0.44244384765625 +78850 -0.47369384765625 +78851 -0.5753173828125 +78852 -0.53704833984375 +78853 -0.65203857421875 +78854 -0.527374267578125 +78855 -0.641632080078125 +78856 -0.459991455078125 +78857 -0.562164306640625 +78858 -0.37274169921875 +78859 -0.458038330078125 +78860 -0.28363037109375 +78861 -0.350555419921875 +78862 -0.21026611328125 +78863 -0.260528564453125 +78864 -0.15594482421875 +78865 -0.192108154296875 +78866 -0.117523193359375 +78867 -0.141937255859375 +78868 -0.088043212890625 +78869 -0.1021728515625 +78870 -0.058746337890625 +78871 -0.062896728515625 +78872 -0.018951416015625 +78873 -0.011932373046875 +78874 0.041839599609375 +78875 0.062835693359375 +78876 0.1129150390625 +78877 0.148712158203125 +78878 0.19097900390625 +78879 0.241729736328125 +78880 0.28228759765625 +78881 0.34912109375 +78882 0.375213623046875 +78883 0.457305908203125 +78884 0.450531005859375 +78885 0.54388427734375 +78886 0.47735595703125 +78887 0.5728759765625 +78888 0.42327880859375 +78889 0.506591796875 +78890 0.29345703125 +78891 0.351226806640625 +78892 0.121673583984375 +78893 0.146514892578125 +78894 -0.047454833984375 +78895 -0.05523681640625 +78896 -0.181793212890625 +78897 -0.21624755859375 +78898 -0.280181884765625 +78899 -0.334930419921875 +78900 -0.335662841796875 +78901 -0.402984619140625 +78902 -0.366241455078125 +78903 -0.4412841796875 +78904 -0.411407470703125 +78905 -0.49578857421875 +78906 -0.465789794921875 +78907 -0.5601806640625 +78908 -0.50054931640625 +78909 -0.600738525390625 +78910 -0.487213134765625 +78911 -0.584228515625 +78912 -0.398834228515625 +78913 -0.47930908203125 +78914 -0.229705810546875 +78915 -0.27935791015625 +78916 -0.00067138671875 +78917 -0.0089111328125 +78918 0.2342529296875 +78919 0.268798828125 +78920 0.41455078125 +78921 0.482818603515625 +78922 0.515167236328125 +78923 0.60369873046875 +78924 0.552459716796875 +78925 0.650421142578125 +78926 0.561676025390625 +78927 0.66400146484375 +78928 0.5404052734375 +78929 0.6414794921875 +78930 0.479949951171875 +78931 0.572540283203125 +78932 0.4154052734375 +78933 0.498138427734375 +78934 0.36492919921875 +78935 0.439453125 +78936 0.310577392578125 +78937 0.375518798828125 +78938 0.225067138671875 +78939 0.274505615234375 +78940 0.08465576171875 +78941 0.1087646484375 +78942 -0.0916748046875 +78943 -0.099395751953125 +78944 -0.27679443359375 +78945 -0.3182373046875 +78946 -0.471923828125 +78947 -0.5489501953125 +78948 -0.6619873046875 +78949 -0.7738037109375 +78950 -0.801788330078125 +78951 -0.86383056640625 +78952 -0.855438232421875 +78953 -0.870391845703125 +78954 -0.855194091796875 +78955 -0.86895751953125 +78956 -0.80670166015625 +78957 -0.861053466796875 +78958 -0.685821533203125 +78959 -0.765869140625 +78960 -0.48858642578125 +78961 -0.5301513671875 +78962 -0.2210693359375 +78963 -0.214691162109375 +78964 0.07989501953125 +78965 0.137359619140625 +78966 0.37042236328125 +78967 0.474822998046875 +78968 0.620147705078125 +78969 0.76239013671875 +78970 0.806060791015625 +78971 0.867462158203125 +78972 0.862579345703125 +78973 0.870361328125 +78974 0.867950439453125 +78975 0.86480712890625 +78976 0.865875244140625 +78977 0.831817626953125 +78978 0.858642578125 +78979 0.677581787109375 +78980 0.783599853515625 +78981 0.495880126953125 +78982 0.648193359375 +78983 0.30767822265625 +78984 0.488250732421875 +78985 0.116180419921875 +78986 0.27667236328125 +78987 -0.110748291015625 +78988 0.007568359375 +78989 -0.381805419921875 +78990 -0.28240966796875 +78991 -0.6572265625 +78992 -0.54205322265625 +78993 -0.857421875 +78994 -0.734649658203125 +78995 -0.870391845703125 +78996 -0.854095458984375 +78997 -0.870391845703125 +78998 -0.862030029296875 +78999 -0.86444091796875 +79000 -0.86749267578125 +79001 -0.85723876953125 +79002 -0.869140625 +79003 -0.790008544921875 +79004 -0.86187744140625 +79005 -0.62847900390625 +79006 -0.771575927734375 +79007 -0.3956298828125 +79008 -0.565185546875 +79009 -0.126708984375 +79010 -0.326446533203125 +79011 0.150115966796875 +79012 -0.065399169921875 +79013 0.424041748046875 +79014 0.19482421875 +79015 0.670623779296875 +79016 0.421051025390625 +79017 0.854522705078125 +79018 0.59814453125 +79019 0.866485595703125 +79020 0.712890625 +79021 0.86920166015625 +79022 0.7808837890625 +79023 0.8653564453125 +79024 0.813629150390625 +79025 0.857147216796875 +79026 0.80865478515625 +79027 0.766845703125 +79028 0.7703857421875 +79029 0.628509521484375 +79030 0.693084716796875 +79031 0.462127685546875 +79032 0.59893798828125 +79033 0.297210693359375 +79034 0.498626708984375 +79035 0.14862060546875 +79036 0.372650146484375 +79037 -0.00537109375 +79038 0.22747802734375 +79039 -0.15753173828125 +79040 0.060089111328125 +79041 -0.31304931640625 +79042 -0.1414794921875 +79043 -0.48876953125 +79044 -0.337066650390625 +79045 -0.6416015625 +79046 -0.505462646484375 +79047 -0.751373291015625 +79048 -0.66644287109375 +79049 -0.84619140625 +79050 -0.807373046875 +79051 -0.861297607421875 +79052 -0.859466552734375 +79053 -0.863250732421875 +79054 -0.861328125 +79055 -0.856597900390625 +79056 -0.85614013671875 +79057 -0.7498779296875 +79058 -0.80621337890625 +79059 -0.624542236328125 +79060 -0.70892333984375 +79061 -0.47808837890625 +79062 -0.527496337890625 +79063 -0.253387451171875 +79064 -0.301055908203125 +79065 0.003692626953125 +79066 -0.08819580078125 +79067 0.2257080078125 +79068 0.12176513671875 +79069 0.427154541015625 +79070 0.356475830078125 +79071 0.643218994140625 +79072 0.60760498046875 +79073 0.855926513671875 +79074 0.82550048828125 +79075 0.870361328125 +79076 0.8668212890625 +79077 0.870361328125 +79078 0.870361328125 +79079 0.862762451171875 +79080 0.866363525390625 +79081 0.79669189453125 +79082 0.852020263671875 +79083 0.595794677734375 +79084 0.692138671875 +79085 0.362152099609375 +79086 0.509063720703125 +79087 0.1270751953125 +79088 0.3216552734375 +79089 -0.086944580078125 +79090 0.131988525390625 +79091 -0.2784423828125 +79092 -0.089874267578125 +79093 -0.484832763671875 +79094 -0.36102294921875 +79095 -0.729583740234375 +79096 -0.639129638671875 +79097 -0.86688232421875 +79098 -0.856353759765625 +79099 -0.870391845703125 +79100 -0.870391845703125 +79101 -0.86859130859375 +79102 -0.870391845703125 +79103 -0.86279296875 +79104 -0.863494873046875 +79105 -0.817962646484375 +79106 -0.77923583984375 +79107 -0.6116943359375 +79108 -0.52740478515625 +79109 -0.3128662109375 +79110 -0.21514892578125 +79111 0.039398193359375 +79112 0.1378173828125 +79113 0.422821044921875 +79114 0.5020751953125 +79115 0.805145263671875 +79116 0.81927490234375 +79117 0.870361328125 +79118 0.870361328125 +79119 0.870361328125 +79120 0.870361328125 +79121 0.860015869140625 +79122 0.860931396484375 +79123 0.727935791015625 +79124 0.74932861328125 +79125 0.48114013671875 +79126 0.540802001953125 +79127 0.2059326171875 +79128 0.319244384765625 +79129 -0.06103515625 +79130 0.10260009765625 +79131 -0.29913330078125 +79132 -0.115203857421875 +79133 -0.516204833984375 +79134 -0.343719482421875 +79135 -0.7252197265625 +79136 -0.55950927734375 +79137 -0.85980224609375 +79138 -0.7335205078125 +79139 -0.870391845703125 +79140 -0.843505859375 +79141 -0.870391845703125 +79142 -0.852508544921875 +79143 -0.858062744140625 +79144 -0.764923095703125 +79145 -0.673004150390625 +79146 -0.636871337890625 +79147 -0.42694091796875 +79148 -0.51812744140625 +79149 -0.2100830078125 +79150 -0.41741943359375 +79151 -0.0362548828125 +79152 -0.31915283203125 +79153 0.10943603515625 +79154 -0.214996337890625 +79155 0.23516845703125 +79156 -0.076141357421875 +79157 0.373687744140625 +79158 0.08941650390625 +79159 0.517791748046875 +79160 0.221588134765625 +79161 0.602783203125 +79162 0.323028564453125 +79163 0.635711669921875 +79164 0.423614501953125 +79165 0.655181884765625 +79166 0.516937255859375 +79167 0.65948486328125 +79168 0.600311279296875 +79169 0.651275634765625 +79170 0.657989501953125 +79171 0.61846923828125 +79172 0.66448974609375 +79173 0.53753662109375 +79174 0.6119384765625 +79175 0.404144287109375 +79176 0.500274658203125 +79177 0.22186279296875 +79178 0.33905029296875 +79179 0.003997802734375 +79180 0.152252197265625 +79181 -0.22100830078125 +79182 -0.034820556640625 +79183 -0.42449951171875 +79184 -0.19757080078125 +79185 -0.579833984375 +79186 -0.2940673828125 +79187 -0.641876220703125 +79188 -0.327911376953125 +79189 -0.6177978515625 +79190 -0.356048583984375 +79191 -0.575531005859375 +79192 -0.38458251953125 +79193 -0.526336669921875 +79194 -0.370574951171875 +79195 -0.42645263671875 +79196 -0.29412841796875 +79197 -0.2581787109375 +79198 -0.193206787109375 +79199 -0.068695068359375 +79200 -0.108489990234375 +79201 0.09222412109375 +79202 -0.030364990234375 +79203 0.232147216796875 +79204 0.043243408203125 +79205 0.3509521484375 +79206 0.079376220703125 +79207 0.410064697265625 +79208 0.046051025390625 +79209 0.372955322265625 +79210 -0.04302978515625 +79211 0.2554931640625 +79212 -0.145263671875 +79213 0.10711669921875 +79214 -0.245574951171875 +79215 -0.052886962890625 +79216 -0.312591552734375 +79217 -0.186279296875 +79218 -0.2960205078125 +79219 -0.23291015625 +79220 -0.214019775390625 +79221 -0.209442138671875 +79222 -0.12176513671875 +79223 -0.174163818359375 +79224 -0.022247314453125 +79225 -0.126739501953125 +79226 0.098358154296875 +79227 -0.048126220703125 +79228 0.2205810546875 +79229 0.0426025390625 +79230 0.308685302734375 +79231 0.10748291015625 +79232 0.3564453125 +79233 0.1409912109375 +79234 0.4111328125 +79235 0.19708251953125 +79236 0.47100830078125 +79237 0.273651123046875 +79238 0.48980712890625 +79239 0.31768798828125 +79240 0.479522705078125 +79241 0.341094970703125 +79242 0.463623046875 +79243 0.368011474609375 +79244 0.421478271484375 +79245 0.37249755859375 +79246 0.3079833984375 +79247 0.30072021484375 +79248 0.125091552734375 +79249 0.1517333984375 +79250 -0.071319580078125 +79251 -0.01470947265625 +79252 -0.26953125 +79253 -0.1883544921875 +79254 -0.47039794921875 +79255 -0.372711181640625 +79256 -0.62432861328125 +79257 -0.51397705078125 +79258 -0.69415283203125 +79259 -0.57177734375 +79260 -0.67327880859375 +79261 -0.53948974609375 +79262 -0.577606201171875 +79263 -0.43511962890625 +79264 -0.44097900390625 +79265 -0.2962646484375 +79266 -0.298309326171875 +79267 -0.161102294921875 +79268 -0.1634521484375 +79269 -0.0435791015625 +79270 -0.034698486328125 +79271 0.060394287109375 +79272 0.07318115234375 +79273 0.13665771484375 +79274 0.144561767578125 +79275 0.170135498046875 +79276 0.181304931640625 +79277 0.16552734375 +79278 0.211761474609375 +79279 0.15728759765625 +79280 0.23876953125 +79281 0.150787353515625 +79282 0.239349365234375 +79283 0.12200927734375 +79284 0.220367431640625 +79285 0.080108642578125 +79286 0.204345703125 +79287 0.05126953125 +79288 0.21533203125 +79289 0.062896728515625 +79290 0.2337646484375 +79291 0.09271240234375 +79292 0.21795654296875 +79293 0.092987060546875 +79294 0.182159423828125 +79295 0.07855224609375 +79296 0.14105224609375 +79297 0.06427001953125 +79298 0.082672119140625 +79299 0.0347900390625 +79300 0.007232666015625 +79301 -0.01171875 +79302 -0.066253662109375 +79303 -0.056060791015625 +79304 -0.097991943359375 +79305 -0.055511474609375 +79306 -0.08660888671875 +79307 -0.010467529296875 +79308 -0.078582763671875 +79309 0.02508544921875 +79310 -0.095367431640625 +79311 0.025665283203125 +79312 -0.11309814453125 +79313 0.017333984375 +79314 -0.12982177734375 +79315 0.00189208984375 +79316 -0.155426025390625 +79317 -0.03173828125 +79318 -0.1796875 +79319 -0.071502685546875 +79320 -0.219390869140625 +79321 -0.13543701171875 +79322 -0.272491455078125 +79323 -0.219970703125 +79324 -0.3184814453125 +79325 -0.300506591796875 +79326 -0.358184814453125 +79327 -0.376312255859375 +79328 -0.3653564453125 +79329 -0.416107177734375 +79330 -0.29827880859375 +79331 -0.371124267578125 +79332 -0.159210205078125 +79333 -0.242279052734375 +79334 0.014892578125 +79335 -0.069732666015625 +79336 0.2044677734375 +79337 0.125640869140625 +79338 0.381103515625 +79339 0.31268310546875 +79340 0.512115478515625 +79341 0.45501708984375 +79342 0.599273681640625 +79343 0.554779052734375 +79344 0.6417236328125 +79345 0.61065673828125 +79346 0.62957763671875 +79347 0.610931396484375 +79348 0.542266845703125 +79349 0.531463623046875 +79350 0.395050048828125 +79351 0.3883056640625 +79352 0.23638916015625 +79353 0.23468017578125 +79354 0.089447021484375 +79355 0.095245361328125 +79356 -0.0213623046875 +79357 -0.00396728515625 +79358 -0.08203125 +79359 -0.04852294921875 +79360 -0.1060791015625 +79361 -0.055145263671875 +79362 -0.138885498046875 +79363 -0.0758056640625 +79364 -0.205078125 +79365 -0.138702392578125 +79366 -0.273162841796875 +79367 -0.209197998046875 +79368 -0.3447265625 +79369 -0.289031982421875 +79370 -0.420562744140625 +79371 -0.37884521484375 +79372 -0.48101806640625 +79373 -0.456329345703125 +79374 -0.52227783203125 +79375 -0.51641845703125 +79376 -0.509307861328125 +79377 -0.519287109375 +79378 -0.43701171875 +79379 -0.458251953125 +79380 -0.35272216796875 +79381 -0.384796142578125 +79382 -0.27978515625 +79383 -0.323699951171875 +79384 -0.21405029296875 +79385 -0.269287109375 +79386 -0.132659912109375 +79387 -0.1951904296875 +79388 -0.035064697265625 +79389 -0.100006103515625 +79390 0.053985595703125 +79391 -0.01055908203125 +79392 0.16131591796875 +79393 0.1033935546875 +79394 0.2933349609375 +79395 0.24908447265625 +79396 0.402130126953125 +79397 0.373199462890625 +79398 0.472076416015625 +79399 0.45806884765625 +79400 0.5106201171875 +79401 0.511474609375 +79402 0.54718017578125 +79403 0.565399169921875 +79404 0.57489013671875 +79405 0.61138916015625 +79406 0.540740966796875 +79407 0.5897216796875 +79408 0.436737060546875 +79409 0.4906005859375 +79410 0.279449462890625 +79411 0.33148193359375 +79412 0.10150146484375 +79413 0.147796630859375 +79414 -0.058929443359375 +79415 -0.01873779296875 +79416 -0.176300048828125 +79417 -0.140289306640625 +79418 -0.227813720703125 +79419 -0.191986083984375 +79420 -0.222747802734375 +79421 -0.184295654296875 +79422 -0.20123291015625 +79423 -0.161834716796875 +79424 -0.20123291015625 +79425 -0.166595458984375 +79426 -0.2188720703125 +79427 -0.19390869140625 +79428 -0.237152099609375 +79429 -0.22442626953125 +79430 -0.276092529296875 +79431 -0.279754638671875 +79432 -0.317535400390625 +79433 -0.3389892578125 +79434 -0.319183349609375 +79435 -0.3543701171875 +79436 -0.3017578125 +79437 -0.348175048828125 +79438 -0.270904541015625 +79439 -0.32598876953125 +79440 -0.2005615234375 +79441 -0.2581787109375 +79442 -0.08673095703125 +79443 -0.139801025390625 +79444 0.057220458984375 +79445 0.014617919921875 +79446 0.176422119140625 +79447 0.144378662109375 +79448 0.245269775390625 +79449 0.221038818359375 +79450 0.28729248046875 +79451 0.27069091796875 +79452 0.3033447265625 +79453 0.294036865234375 +79454 0.312408447265625 +79455 0.311767578125 +79456 0.32867431640625 +79457 0.339141845703125 +79458 0.338592529296875 +79459 0.360260009765625 +79460 0.3294677734375 +79461 0.360504150390625 +79462 0.272705078125 +79463 0.308380126953125 +79464 0.1483154296875 +79465 0.18170166015625 +79466 -0.020965576171875 +79467 0.0047607421875 +79468 -0.1917724609375 +79469 -0.17559814453125 +79470 -0.322509765625 +79471 -0.3143310546875 +79472 -0.372955322265625 +79473 -0.36785888671875 +79474 -0.367340087890625 +79475 -0.36248779296875 +79476 -0.347442626953125 +79477 -0.343536376953125 +79478 -0.3050537109375 +79479 -0.3018798828125 +79480 -0.234832763671875 +79481 -0.231414794921875 +79482 -0.123748779296875 +79483 -0.117645263671875 +79484 -0.001922607421875 +79485 0.007049560546875 +79486 0.079864501953125 +79487 0.087982177734375 +79488 0.134429931640625 +79489 0.13946533203125 +79490 0.173095703125 +79491 0.17425537109375 +79492 0.191680908203125 +79493 0.188201904296875 +79494 0.180633544921875 +79495 0.171234130859375 +79496 0.135223388671875 +79497 0.118438720703125 +79498 0.08038330078125 +79499 0.05706787109375 +79500 0.01806640625 +79501 -0.010711669921875 +79502 -0.05767822265625 +79503 -0.0914306640625 +79504 -0.125762939453125 +79505 -0.162322998046875 +79506 -0.15948486328125 +79507 -0.194549560546875 +79508 -0.122894287109375 +79509 -0.1492919921875 +79510 -0.01116943359375 +79511 -0.02166748046875 +79512 0.116912841796875 +79513 0.124053955078125 +79514 0.19110107421875 +79515 0.211151123046875 +79516 0.21246337890625 +79517 0.240447998046875 +79518 0.2091064453125 +79519 0.242218017578125 +79520 0.189849853515625 +79521 0.2257080078125 +79522 0.158050537109375 +79523 0.194366455078125 +79524 0.083740234375 +79525 0.115509033203125 +79526 -0.011199951171875 +79527 0.0128173828125 +79528 -0.071685791015625 +79529 -0.053802490234375 +79530 -0.1219482421875 +79531 -0.110626220703125 +79532 -0.200653076171875 +79533 -0.199493408203125 +79534 -0.284027099609375 +79535 -0.29437255859375 +79536 -0.314300537109375 +79537 -0.33221435546875 +79538 -0.261138916015625 +79539 -0.27972412109375 +79540 -0.16937255859375 +79541 -0.185333251953125 +79542 -0.112091064453125 +79543 -0.128204345703125 +79544 -0.09625244140625 +79545 -0.115692138671875 +79546 -0.093292236328125 +79547 -0.116455078125 +79548 -0.080780029296875 +79549 -0.105926513671875 +79550 -0.031158447265625 +79551 -0.053955078125 +79552 0.064117431640625 +79553 0.048797607421875 +79554 0.16363525390625 +79555 0.157318115234375 +79556 0.212615966796875 +79557 0.212005615234375 +79558 0.21630859375 +79559 0.218475341796875 +79560 0.23052978515625 +79561 0.23724365234375 +79562 0.289581298828125 +79563 0.30535888671875 +79564 0.35540771484375 +79565 0.38128662109375 +79566 0.372528076171875 +79567 0.404449462890625 +79568 0.35919189453125 +79569 0.3944091796875 +79570 0.35003662109375 +79571 0.3885498046875 +79572 0.322967529296875 +79573 0.362640380859375 +79574 0.238525390625 +79575 0.27362060546875 +79576 0.0927734375 +79577 0.11712646484375 +79578 -0.06640625 +79579 -0.054901123046875 +79580 -0.19146728515625 +79581 -0.19085693359375 +79582 -0.27783203125 +79583 -0.28570556640625 +79584 -0.325439453125 +79585 -0.339263916015625 +79586 -0.35833740234375 +79587 -0.3775634765625 +79588 -0.41815185546875 +79589 -0.445709228515625 +79590 -0.49713134765625 +79591 -0.535064697265625 +79592 -0.5802001953125 +79593 -0.629058837890625 +79594 -0.639892578125 +79595 -0.697601318359375 +79596 -0.642547607421875 +79597 -0.70391845703125 +79598 -0.58319091796875 +79599 -0.6424560546875 +79600 -0.4417724609375 +79601 -0.491241455078125 +79602 -0.232574462890625 +79603 -0.265716552734375 +79604 -0.0089111328125 +79605 -0.023712158203125 +79606 0.19879150390625 +79607 0.201751708984375 +79608 0.358489990234375 +79609 0.375823974609375 +79610 0.457855224609375 +79611 0.485076904296875 +79612 0.533172607421875 +79613 0.56884765625 +79614 0.591583251953125 +79615 0.634765625 +79616 0.591156005859375 +79617 0.63763427734375 +79618 0.520782470703125 +79619 0.5660400390625 +79620 0.429595947265625 +79621 0.4720458984375 +79622 0.366668701171875 +79623 0.40692138671875 +79624 0.3389892578125 +79625 0.3778076171875 +79626 0.3392333984375 +79627 0.376953125 +79628 0.336578369140625 +79629 0.371978759765625 +79630 0.283599853515625 +79631 0.313140869140625 +79632 0.164825439453125 +79633 0.184417724609375 +79634 0.004241943359375 +79635 0.011199951171875 +79636 -0.164642333984375 +79637 -0.171051025390625 +79638 -0.318359375 +79639 -0.33740234375 +79640 -0.4420166015625 +79641 -0.47198486328125 +79642 -0.522186279296875 +79643 -0.560394287109375 +79644 -0.5380859375 +79645 -0.58056640625 +79646 -0.50421142578125 +79647 -0.54754638671875 +79648 -0.465667724609375 +79649 -0.508575439453125 +79650 -0.418548583984375 +79651 -0.459503173828125 +79652 -0.357177734375 +79653 -0.394378662109375 +79654 -0.319000244140625 +79655 -0.35260009765625 +79656 -0.282501220703125 +79657 -0.31170654296875 +79658 -0.17681884765625 +79659 -0.197418212890625 +79660 -9.1552734375e-05 +79661 -0.007965087890625 +79662 0.201080322265625 +79663 0.207489013671875 +79664 0.389068603515625 +79665 0.409210205078125 +79666 0.54022216796875 +79667 0.57208251953125 +79668 0.62603759765625 +79669 0.66595458984375 +79670 0.61614990234375 +79671 0.65875244140625 +79672 0.52685546875 +79673 0.56744384765625 +79674 0.395782470703125 +79675 0.431396484375 +79676 0.26470947265625 +79677 0.29443359375 +79678 0.158294677734375 +79679 0.182464599609375 +79680 0.046234130859375 +79681 0.06365966796875 +79682 -0.084869384765625 +79683 -0.075958251953125 +79684 -0.190460205078125 +79685 -0.189422607421875 +79686 -0.26611328125 +79687 -0.271942138671875 +79688 -0.330078125 +79689 -0.342529296875 +79690 -0.34735107421875 +79691 -0.364166259765625 +79692 -0.3089599609375 +79693 -0.327239990234375 +79694 -0.258087158203125 +79695 -0.2769775390625 +79696 -0.233306884765625 +79697 -0.253692626953125 +79698 -0.221649169921875 +79699 -0.24365234375 +79700 -0.177093505859375 +79701 -0.1983642578125 +79702 -0.09814453125 +79703 -0.116241455078125 +79704 -0.0224609375 +79705 -0.036834716796875 +79706 0.045196533203125 +79707 0.034881591796875 +79708 0.09759521484375 +79709 0.09124755859375 +79710 0.11260986328125 +79711 0.10888671875 +79712 0.126220703125 +79713 0.125518798828125 +79714 0.15435791015625 +79715 0.15771484375 +79716 0.1712646484375 +79717 0.17828369140625 +79718 0.161712646484375 +79719 0.17108154296875 +79720 0.120025634765625 +79721 0.129974365234375 +79722 0.072479248046875 +79723 0.082427978515625 +79724 0.01849365234375 +79725 0.027679443359375 +79726 -0.07171630859375 +79727 -0.065643310546875 +79728 -0.1617431640625 +79729 -0.15936279296875 +79730 -0.213104248046875 +79731 -0.21307373046875 +79732 -0.233306884765625 +79733 -0.234649658203125 +79734 -0.199615478515625 +79735 -0.2001953125 +79736 -0.121124267578125 +79737 -0.119171142578125 +79738 -0.029541015625 +79739 -0.024749755859375 +79740 0.077667236328125 +79741 0.085784912109375 +79742 0.167724609375 +79743 0.178131103515625 +79744 0.20556640625 +79745 0.215576171875 +79746 0.2037353515625 +79747 0.211456298828125 +79748 0.171142578125 +79749 0.17523193359375 +79750 0.128509521484375 +79751 0.128753662109375 +79752 0.104217529296875 +79753 0.1019287109375 +79754 0.07879638671875 +79755 0.0743408203125 +79756 0.049591064453125 +79757 0.04327392578125 +79758 0.044647216796875 +79759 0.038177490234375 +79760 0.080352783203125 +79761 0.076263427734375 +79762 0.141082763671875 +79763 0.14105224609375 +79764 0.183013916015625 +79765 0.186431884765625 +79766 0.183746337890625 +79767 0.188812255859375 +79768 0.1346435546875 +79769 0.1390380859375 +79770 0.040283203125 +79771 0.041778564453125 +79772 -0.07684326171875 +79773 -0.079437255859375 +79774 -0.21173095703125 +79775 -0.219390869140625 +79776 -0.3544921875 +79777 -0.367828369140625 +79778 -0.47662353515625 +79779 -0.494873046875 +79780 -0.535919189453125 +79781 -0.556243896484375 +79782 -0.49114990234375 +79783 -0.508697509765625 +79784 -0.36456298828125 +79785 -0.3756103515625 +79786 -0.215118408203125 +79787 -0.218902587890625 +79788 -0.0667724609375 +79789 -0.063751220703125 +79790 0.08203125 +79791 0.091552734375 +79792 0.22076416015625 +79793 0.23602294921875 +79794 0.323974609375 +79795 0.342987060546875 +79796 0.37518310546875 +79797 0.39520263671875 +79798 0.37115478515625 +79799 0.389373779296875 +79800 0.31060791015625 +79801 0.324249267578125 +79802 0.216552734375 +79803 0.224090576171875 +79804 0.122589111328125 +79805 0.124267578125 +79806 0.040374755859375 +79807 0.037078857421875 +79808 -0.004058837890625 +79809 -0.010101318359375 +79810 -0.012786865234375 +79811 -0.019439697265625 +79812 -0.01611328125 +79813 -0.022796630859375 +79814 0.003631591796875 +79815 -0.001556396484375 +79816 0.0579833984375 +79817 0.056304931640625 +79818 0.10504150390625 +79819 0.106719970703125 +79820 0.0946044921875 +79821 0.096893310546875 +79822 0.041839599609375 +79823 0.042694091796875 +79824 -0.017181396484375 +79825 -0.018035888671875 +79826 -0.073394775390625 +79827 -0.07586669921875 +79828 -0.115966796875 +79829 -0.11944580078125 +79830 -0.1552734375 +79831 -0.15972900390625 +79832 -0.19683837890625 +79833 -0.202606201171875 +79834 -0.241119384765625 +79835 -0.24859619140625 +79836 -0.295196533203125 +79837 -0.30517578125 +79838 -0.349365234375 +79839 -0.36212158203125 +79840 -0.376983642578125 +79841 -0.39141845703125 +79842 -0.342041015625 +79843 -0.35528564453125 +79844 -0.24102783203125 +79845 -0.249969482421875 +79846 -0.090576171875 +79847 -0.092864990234375 +79848 0.08355712890625 +79849 0.08905029296875 +79850 0.223724365234375 +79851 0.2352294921875 +79852 0.304290771484375 +79853 0.318817138671875 +79854 0.343109130859375 +79855 0.358642578125 +79856 0.333526611328125 +79857 0.347747802734375 +79858 0.275054931640625 +79859 0.28564453125 +79860 0.216033935546875 +79861 0.223175048828125 +79862 0.19110107421875 +79863 0.196746826171875 +79864 0.175018310546875 +79865 0.179840087890625 +79866 0.151702880859375 +79867 0.155548095703125 +79868 0.147186279296875 +79869 0.151214599609375 +79870 0.152099609375 +79871 0.156951904296875 +79872 0.127288818359375 +79873 0.13177490234375 +79874 0.097137451171875 +79875 0.100799560546875 +79876 0.0838623046875 +79877 0.087127685546875 +79878 0.05230712890625 +79879 0.05487060546875 +79880 -0.010223388671875 +79881 -0.009002685546875 +79882 -0.10321044921875 +79883 -0.10400390625 +79884 -0.2259521484375 +79885 -0.229400634765625 +79886 -0.349273681640625 +79887 -0.35552978515625 +79888 -0.433349609375 +79889 -0.441925048828125 +79890 -0.46380615234375 +79891 -0.473846435546875 +79892 -0.454010009765625 +79893 -0.464813232421875 +79894 -0.408233642578125 +79895 -0.419097900390625 +79896 -0.324188232421875 +79897 -0.334320068359375 +79898 -0.219085693359375 +79899 -0.227935791015625 +79900 -0.11614990234375 +79901 -0.12347412109375 +79902 -0.02197265625 +79903 -0.02764892578125 +79904 0.081298828125 +79905 0.077667236328125 +79906 0.214111328125 +79907 0.2132568359375 +79908 0.38604736328125 +79909 0.38885498046875 +79910 0.575836181640625 +79911 0.582794189453125 +79912 0.7235107421875 +79913 0.734039306640625 +79914 0.787384033203125 +79915 0.800140380859375 +79916 0.764739990234375 +79917 0.7783203125 +79918 0.65228271484375 +79919 0.6651611328125 +79920 0.4490966796875 +79921 0.45965576171875 +79922 0.192047119140625 +79923 0.199188232421875 +79924 -0.054351806640625 +79925 -0.050689697265625 +79926 -0.233978271484375 +79927 -0.23297119140625 +79928 -0.32958984375 +79929 -0.33013916015625 +79930 -0.366973876953125 +79931 -0.368408203125 +79932 -0.376800537109375 +79933 -0.378936767578125 +79934 -0.3741455078125 +79935 -0.376983642578125 +79936 -0.375946044921875 +79937 -0.37969970703125 +79938 -0.386566162109375 +79939 -0.391510009765625 +79940 -0.37945556640625 +79941 -0.385345458984375 +79942 -0.335693359375 +79943 -0.3419189453125 +79944 -0.27667236328125 +79945 -0.28289794921875 +79946 -0.24505615234375 +79947 -0.251617431640625 +79948 -0.2586669921875 +79949 -0.266143798828125 +79950 -0.265289306640625 +79951 -0.273345947265625 +79952 -0.20941162109375 +79953 -0.216796875 +79954 -0.12225341796875 +79955 -0.128265380859375 +79956 -0.06329345703125 +79957 -0.068145751953125 +79958 -0.03900146484375 +79959 -0.0430908203125 +79960 -0.021209716796875 +79961 -0.024444580078125 +79962 0.022552490234375 +79963 0.020721435546875 +79964 0.123870849609375 +79965 0.124481201171875 +79966 0.2542724609375 +79967 0.25787353515625 +79968 0.372711181640625 +79969 0.379119873046875 +79970 0.471099853515625 +79971 0.47991943359375 +79972 0.51788330078125 +79973 0.5281982421875 +79974 0.500518798828125 +79975 0.511138916015625 +79976 0.446044921875 +79977 0.456207275390625 +79978 0.3978271484375 +79979 0.407470703125 +79980 0.3743896484375 +79981 0.383758544921875 +79982 0.3480224609375 +79983 0.35687255859375 +79984 0.303985595703125 +79985 0.31182861328125 +79986 0.24444580078125 +79987 0.250885009765625 +79988 0.160858154296875 +79989 0.1654052734375 +79990 0.033416748046875 +79991 0.035247802734375 +79992 -0.140350341796875 +79993 -0.142059326171875 +79994 -0.33013916015625 +79995 -0.33563232421875 +79996 -0.52520751953125 +79997 -0.5345458984375 +79998 -0.70892333984375 +79999 -0.72186279296875 +80000 -0.821380615234375 +80001 -0.836669921875 +80002 -0.817047119140625 +80003 -0.8326416015625 +80004 -0.7154541015625 +80005 -0.7296142578125 +80006 -0.5706787109375 +80007 -0.582550048828125 +80008 -0.4305419921875 +80009 -0.440093994140625 +80010 -0.316802978515625 +80011 -0.324310302734375 +80012 -0.1962890625 +80013 -0.20147705078125 +80014 -0.04241943359375 +80015 -0.044647216796875 +80016 0.10333251953125 +80017 0.103973388671875 +80018 0.19964599609375 +80019 0.202392578125 +80020 0.260223388671875 +80021 0.264495849609375 +80022 0.33294677734375 +80023 0.338897705078125 +80024 0.43572998046875 +80025 0.443817138671875 +80026 0.53497314453125 +80027 0.545074462890625 +80028 0.605743408203125 +80029 0.6173095703125 +80030 0.64013671875 +80031 0.6524658203125 +80032 0.650787353515625 +80033 0.66339111328125 +80034 0.6436767578125 +80035 0.6561279296875 +80036 0.595245361328125 +80037 0.606781005859375 +80038 0.491546630859375 +80039 0.501190185546875 +80040 0.34576416015625 +80041 0.352783203125 +80042 0.17266845703125 +80043 0.176544189453125 +80044 -0.034942626953125 +80045 -0.034820556640625 +80046 -0.25433349609375 +80047 -0.258209228515625 +80048 -0.4351806640625 +80049 -0.44244384765625 +80050 -0.56549072265625 +80051 -0.5753173828125 +80052 -0.640625 +80053 -0.65203857421875 +80054 -0.630096435546875 +80055 -0.641632080078125 +80056 -0.551666259765625 +80057 -0.562164306640625 +80058 -0.449066162109375 +80059 -0.458038330078125 +80060 -0.343231201171875 +80061 -0.350555419921875 +80062 -0.254669189453125 +80063 -0.260528564453125 +80064 -0.187469482421875 +80065 -0.192108154296875 +80066 -0.138336181640625 +80067 -0.141937255859375 +80068 -0.099517822265625 +80069 -0.1021728515625 +80070 -0.06121826171875 +80071 -0.062896728515625 +80072 -0.011444091796875 +80073 -0.011932373046875 +80074 0.061767578125 +80075 0.062835693359375 +80076 0.145965576171875 +80077 0.148712158203125 +80078 0.2371826171875 +80079 0.241729736328125 +80080 0.34259033203125 +80081 0.34912109375 +80082 0.448822021484375 +80083 0.457305908203125 +80084 0.533843994140625 +80085 0.54388427734375 +80086 0.56231689453125 +80087 0.5728759765625 +80088 0.497100830078125 +80089 0.506591796875 +80090 0.344329833984375 +80091 0.351226806640625 +80092 0.14306640625 +80093 0.146514892578125 +80094 -0.05523681640625 +80095 -0.05523681640625 +80096 -0.213409423828125 +80097 -0.21624755859375 +80098 -0.32989501953125 +80099 -0.334930419921875 +80100 -0.39654541015625 +80101 -0.402984619140625 +80102 -0.43389892578125 +80103 -0.4412841796875 +80104 -0.487213134765625 +80105 -0.49578857421875 +80106 -0.55029296875 +80107 -0.5601806640625 +80108 -0.589996337890625 +80109 -0.600738525390625 +80110 -0.5736083984375 +80111 -0.584228515625 +80112 -0.47027587890625 +80113 -0.47930908203125 +80114 -0.273529052734375 +80115 -0.27935791015625 +80116 -0.007476806640625 +80117 -0.0089111328125 +80118 0.265625 +80119 0.268798828125 +80120 0.47601318359375 +80121 0.482818603515625 +80122 0.5947265625 +80123 0.60369873046875 +80124 0.640411376953125 +80125 0.650421142578125 +80126 0.653472900390625 +80127 0.66400146484375 +80128 0.630859375 +80129 0.6416015625 +80130 0.562530517578125 +80131 0.5728759765625 +80132 0.489349365234375 +80133 0.498199462890625 +80134 0.432342529296875 +80135 0.43853759765625 +80136 0.37042236328125 +80137 0.3734130859375 +80138 0.271636962890625 +80139 0.271636962890625 +80140 0.108184814453125 +80141 0.106170654296875 +80142 -0.097747802734375 +80143 -0.100921630859375 +80144 -0.314544677734375 +80145 -0.3182373046875 +80146 -0.54351806640625 +80147 -0.546875 +80148 -0.766998291015625 +80149 -0.769287109375 +80150 -0.86297607421875 +80151 -0.863128662109375 +80152 -0.870391845703125 +80153 -0.870391845703125 +80154 -0.869781494140625 +80155 -0.86968994140625 +80156 -0.862640380859375 +80157 -0.8624267578125 +80158 -0.786224365234375 +80159 -0.784149169921875 +80160 -0.55517578125 +80161 -0.553741455078125 +80162 -0.242889404296875 +80163 -0.24310302734375 +80164 0.10760498046875 +80165 0.105255126953125 +80166 0.445159912109375 +80167 0.4407958984375 +80168 0.73443603515625 +80169 0.72857666015625 +80170 0.86474609375 +80171 0.864044189453125 +80172 0.870361328125 +80173 0.870361328125 +80174 0.867431640625 +80175 0.8681640625 +80176 0.857025146484375 +80177 0.85845947265625 +80178 0.742645263671875 +80179 0.7611083984375 +80180 0.575775146484375 +80181 0.598388671875 +80182 0.397613525390625 +80183 0.42279052734375 +80184 0.210968017578125 +80185 0.237152099609375 +80186 -0.016387939453125 +80187 0.009857177734375 +80188 -0.292999267578125 +80189 -0.2672119140625 +80190 -0.578643798828125 +80191 -0.554168701171875 +80192 -0.81683349609375 +80193 -0.795074462890625 +80194 -0.866943359375 +80195 -0.86505126953125 +80196 -0.870391845703125 +80197 -0.870391845703125 +80198 -0.867767333984375 +80199 -0.869598388671875 +80200 -0.863616943359375 +80201 -0.8670654296875 +80202 -0.856475830078125 +80203 -0.861297607421875 +80204 -0.729736328125 +80205 -0.7840576171875 +80206 -0.509613037109375 +80207 -0.57147216796875 +80208 -0.246826171875 +80209 -0.312957763671875 +80210 0.03057861328125 +80211 -0.03619384765625 +80212 0.31158447265625 +80213 0.24761962890625 +80214 0.5711669921875 +80215 0.51336669921875 +80216 0.7735595703125 +80217 0.725189208984375 +80218 0.8599853515625 +80219 0.856048583984375 +80220 0.865386962890625 +80221 0.863006591796875 +80222 0.8643798828125 +80223 0.8636474609375 +80224 0.85894775390625 +80225 0.859832763671875 +80226 0.807159423828125 +80227 0.82916259765625 +80228 0.689849853515625 +80229 0.72393798828125 +80230 0.54052734375 +80231 0.584442138671875 +80232 0.387908935546875 +80233 0.438629150390625 +80234 0.246337890625 +80235 0.3004150390625 +80236 0.09381103515625 +80237 0.148223876953125 +80238 -0.06231689453125 +80239 -0.010498046875 +80240 -0.22686767578125 +80241 -0.180145263671875 +80242 -0.41607666015625 +80243 -0.376190185546875 +80244 -0.58599853515625 +80245 -0.55474853515625 +80246 -0.71539306640625 +80247 -0.694305419921875 +80248 -0.83123779296875 +80249 -0.820709228515625 +80250 -0.861968994140625 +80251 -0.861968994140625 +80252 -0.86614990234375 +80253 -0.86724853515625 +80254 -0.861480712890625 +80255 -0.8636474609375 +80256 -0.80999755859375 +80257 -0.8385009765625 +80258 -0.696258544921875 +80259 -0.731048583984375 +80260 -0.557159423828125 +80261 -0.59600830078125 +80262 -0.335296630859375 +80263 -0.376861572265625 +80264 -0.07647705078125 +80265 -0.118804931640625 +80266 0.151611328125 +80267 0.11126708984375 +80268 0.36297607421875 +80269 0.3267822265625 +80270 0.5921630859375 +80271 0.561309814453125 +80272 0.832244873046875 +80273 0.80743408203125 +80274 0.870361328125 +80275 0.870361328125 +80276 0.870361328125 +80277 0.870361328125 +80278 0.862762451171875 +80279 0.86279296875 +80280 0.79669189453125 +80281 0.797332763671875 +80282 0.595794677734375 +80283 0.597259521484375 +80284 0.362152099609375 +80285 0.36444091796875 +80286 0.1270751953125 +80287 0.1298828125 +80288 -0.086944580078125 +80289 -0.0841064453125 +80290 -0.2784423828125 +80291 -0.27593994140625 +80292 -0.484832763671875 +80293 -0.48223876953125 +80294 -0.729583740234375 +80295 -0.725921630859375 +80296 -0.86688232421875 +80297 -0.866302490234375 +80298 -0.870391845703125 +80299 -0.870391845703125 +80300 -0.86859130859375 +80301 -0.869110107421875 +80302 -0.86279296875 +80303 -0.86376953125 +80304 -0.817962646484375 +80305 -0.83087158203125 +80306 -0.6116943359375 +80307 -0.62841796875 +80308 -0.3128662109375 +80309 -0.33343505859375 +80310 0.039398193359375 +80311 0.0155029296875 +80312 0.422821044921875 +80313 0.39630126953125 +80314 0.805145263671875 +80315 0.7769775390625 +80316 0.870361328125 +80317 0.870361328125 +80318 0.870361328125 +80319 0.870361328125 +80320 0.860015869140625 +80321 0.860076904296875 +80322 0.727935791015625 +80323 0.729766845703125 +80324 0.48114013671875 +80325 0.484588623046875 +80326 0.2059326171875 +80327 0.21087646484375 +80328 -0.06103515625 +80329 -0.055084228515625 +80330 -0.29913330078125 +80331 -0.2928466796875 +80332 -0.516204833984375 +80333 -0.509918212890625 +80334 -0.7252197265625 +80335 -0.718841552734375 +80336 -0.85980224609375 +80337 -0.859100341796875 +80338 -0.870391845703125 +80339 -0.870391845703125 +80340 -0.870391845703125 +80341 -0.870391845703125 +80342 -0.858062744140625 +80343 -0.858184814453125 +80344 -0.673004150390625 +80345 -0.675689697265625 +80346 -0.42694091796875 +80347 -0.43121337890625 +80348 -0.2100830078125 +80349 -0.2149658203125 +80350 -0.0362548828125 +80351 -0.040679931640625 +80352 0.10943603515625 +80353 0.1060791015625 +80354 0.23516845703125 +80355 0.233184814453125 +80356 0.373687744140625 +80357 0.3726806640625 +80358 0.517791748046875 +80359 0.517303466796875 +80360 0.602783203125 +80361 0.603271484375 +80362 0.635711669921875 +80363 0.63739013671875 +80364 0.655181884765625 +80365 0.657562255859375 +80366 0.65948486328125 +80367 0.662078857421875 +80368 0.651275634765625 +80369 0.653533935546875 +80370 0.61846923828125 +80371 0.620086669921875 +80372 0.53753662109375 +80373 0.538665771484375 +80374 0.404144287109375 +80375 0.4051513671875 +80376 0.22186279296875 +80377 0.22320556640625 +80378 0.003997802734375 +80379 0.00604248046875 +80380 -0.22100830078125 +80381 -0.21820068359375 +80382 -0.42449951171875 +80383 -0.421173095703125 +80384 -0.579833984375 +80385 -0.576812744140625 +80386 -0.641876220703125 +80387 -0.641265869140625 +80388 -0.6177978515625 +80389 -0.620880126953125 +80390 -0.575531005859375 +80391 -0.58062744140625 +80392 -0.526336669921875 +80393 -0.5316162109375 +80394 -0.42645263671875 +80395 -0.432647705078125 +80396 -0.2581787109375 +80397 -0.2672119140625 +80398 -0.068695068359375 +80399 -0.080657958984375 +80400 0.09222412109375 +80401 0.079193115234375 +80402 0.232147216796875 +80403 0.219146728515625 +80404 0.3509521484375 +80405 0.3387451171875 +80406 0.410064697265625 +80407 0.40093994140625 +80408 0.372955322265625 +80409 0.370635986328125 +80410 0.2554931640625 +80411 0.262725830078125 +80412 0.10711669921875 +80413 0.1241455078125 +80414 -0.052886962890625 +80415 -0.02685546875 +80416 -0.186279296875 +80417 -0.15386962890625 +80418 -0.23291015625 +80419 -0.199615478515625 +80420 -0.209442138671875 +80421 -0.1798095703125 +80422 -0.174163818359375 +80423 -0.149749755859375 +80424 -0.126739501953125 +80425 -0.10888671875 +80426 -0.048126220703125 +80427 -0.038848876953125 +80428 0.0426025390625 +80429 0.04248046875 +80430 0.10748291015625 +80431 0.0992431640625 +80432 0.1409912109375 +80433 0.12646484375 +80434 0.19708251953125 +80435 0.17572021484375 +80436 0.273651123046875 +80437 0.2452392578125 +80438 0.31768798828125 +80439 0.28472900390625 +80440 0.341094970703125 +80441 0.30560302734375 +80442 0.368011474609375 +80443 0.3309326171875 +80444 0.37249755859375 +80445 0.335968017578125 +80446 0.30072021484375 +80447 0.269378662109375 +80448 0.1517333984375 +80449 0.130126953125 +80450 -0.01470947265625 +80451 -0.0250244140625 +80452 -0.1883544921875 +80453 -0.1865234375 +80454 -0.372711181640625 +80455 -0.35797119140625 +80456 -0.51397705078125 +80457 -0.48834228515625 +80458 -0.57177734375 +80459 -0.539398193359375 +80460 -0.53948974609375 +80461 -0.50506591796875 +80462 -0.43511962890625 +80463 -0.4027099609375 +80464 -0.2962646484375 +80465 -0.26824951171875 +80466 -0.161102294921875 +80467 -0.13812255859375 +80468 -0.0435791015625 +80469 -0.025634765625 +80470 0.060394287109375 +80471 0.07305908203125 +80472 0.13665771484375 +80473 0.14453125 +80474 0.170135498046875 +80475 0.174530029296875 +80476 0.16552734375 +80477 0.16766357421875 +80478 0.15728759765625 +80479 0.1568603515625 +80480 0.150787353515625 +80481 0.147430419921875 +80482 0.12200927734375 +80483 0.116668701171875 +80484 0.080108642578125 +80485 0.073486328125 +80486 0.05126953125 +80487 0.04296875 +80488 0.062896728515625 +80489 0.051422119140625 +80490 0.09271240234375 +80491 0.07769775390625 +80492 0.092987060546875 +80493 0.076507568359375 +80494 0.07855224609375 +80495 0.06201171875 +80496 0.06427001953125 +80497 0.04840087890625 +80498 0.0347900390625 +80499 0.02099609375 +80500 -0.01171875 +80501 -0.02197265625 +80502 -0.056060791015625 +80503 -0.062347412109375 +80504 -0.055511474609375 +80505 -0.059539794921875 +80506 -0.010467529296875 +80507 -0.014068603515625 +80508 0.02508544921875 +80509 0.02252197265625 +80510 0.025665283203125 +80511 0.02581787109375 +80512 0.017333984375 +80513 0.020477294921875 +80514 0.00189208984375 +80515 0.008087158203125 +80516 -0.03173828125 +80517 -0.022003173828125 +80518 -0.071502685546875 +80519 -0.0584716796875 +80520 -0.13543701171875 +80521 -0.118499755859375 +80522 -0.219970703125 +80523 -0.19873046875 +80524 -0.300506591796875 +80525 -0.2757568359375 +80526 -0.376312255859375 +80527 -0.34881591796875 +80528 -0.416107177734375 +80529 -0.3880615234375 +80530 -0.371124267578125 +80531 -0.34698486328125 +80532 -0.242279052734375 +80533 -0.226348876953125 +80534 -0.069732666015625 +80535 -0.06427001953125 +80536 0.125640869140625 +80537 0.119476318359375 +80538 0.31268310546875 +80539 0.29534912109375 +80540 0.45501708984375 +80541 0.428863525390625 +80542 0.554779052734375 +80543 0.52215576171875 +80544 0.61065673828125 +80545 0.574066162109375 +80546 0.610931396484375 +80547 0.573455810546875 +80548 0.531463623046875 +80549 0.497406005859375 +80550 0.3883056640625 +80551 0.3612060546875 +80552 0.23468017578125 +80553 0.215484619140625 +80554 0.095245361328125 +80555 0.083709716796875 +80556 -0.00396728515625 +80557 -0.009429931640625 +80558 -0.04852294921875 +80559 -0.05029296875 +80560 -0.055145263671875 +80561 -0.054840087890625 +80562 -0.0758056640625 +80563 -0.07269287109375 +80564 -0.138702392578125 +80565 -0.130767822265625 +80566 -0.209197998046875 +80567 -0.196197509765625 +80568 -0.289031982421875 +80569 -0.270751953125 +80570 -0.37884521484375 +80571 -0.3551025390625 +80572 -0.456329345703125 +80573 -0.42803955078125 +80574 -0.51641845703125 +80575 -0.484771728515625 +80576 -0.519287109375 +80577 -0.487396240234375 +80578 -0.458251953125 +80579 -0.4295654296875 +80580 -0.384796142578125 +80581 -0.360260009765625 +80582 -0.323699951171875 +80583 -0.30303955078125 +80584 -0.269287109375 +80585 -0.252410888671875 +80586 -0.1951904296875 +80587 -0.1832275390625 +80588 -0.100006103515625 +80589 -0.09405517578125 +80590 -0.01055908203125 +80591 -0.010345458984375 +80592 0.1033935546875 +80593 0.09674072265625 +80594 0.24908447265625 +80595 0.234161376953125 +80596 0.373199462890625 +80597 0.351226806640625 +80598 0.45806884765625 +80599 0.431182861328125 +80600 0.511474609375 +80601 0.4814453125 +80602 0.565399169921875 +80603 0.53253173828125 +80604 0.61138916015625 +80605 0.576385498046875 +80606 0.5897216796875 +80607 0.556121826171875 +80608 0.4906005859375 +80609 0.462371826171875 +80610 0.33148193359375 +80611 0.311767578125 +80612 0.147796630859375 +80613 0.137939453125 +80614 -0.01873779296875 +80615 -0.019439697265625 +80616 -0.140289306640625 +80617 -0.133941650390625 +80618 -0.191986083984375 +80619 -0.18194580078125 +80620 -0.184295654296875 +80621 -0.173492431640625 +80622 -0.161834716796875 +80623 -0.151123046875 +80624 -0.166595458984375 +80625 -0.15484619140625 +80626 -0.19390869140625 +80627 -0.18023681640625 +80628 -0.22442626953125 +80629 -0.20892333984375 +80630 -0.279754638671875 +80631 -0.261505126953125 +80632 -0.3389892578125 +80633 -0.318084716796875 +80634 -0.3543701171875 +80635 -0.333160400390625 +80636 -0.348175048828125 +80637 -0.327911376953125 +80638 -0.32598876953125 +80639 -0.3076171875 +80640 -0.2581787109375 +80641 -0.2440185546875 +80642 -0.139801025390625 +80643 -0.132354736328125 +80644 0.014617919921875 +80645 0.013580322265625 +80646 0.144378662109375 +80647 0.1361083984375 +80648 0.221038818359375 +80649 0.208282470703125 +80650 0.27069091796875 +80651 0.2548828125 +80652 0.294036865234375 +80653 0.276641845703125 +80654 0.311767578125 +80655 0.293212890625 +80656 0.339141845703125 +80657 0.31903076171875 +80658 0.360260009765625 +80659 0.338623046875 +80660 0.360504150390625 +80661 0.338226318359375 +80662 0.308380126953125 +80663 0.28900146484375 +80664 0.18170166015625 +80665 0.170745849609375 +80666 0.0047607421875 +80667 0.00604248046875 +80668 -0.17559814453125 +80669 -0.161865234375 +80670 -0.3143310546875 +80671 -0.291412353515625 +80672 -0.36785888671875 +80673 -0.342376708984375 +80674 -0.36248779296875 +80675 -0.338836669921875 +80676 -0.343536376953125 +80677 -0.322418212890625 +80678 -0.3018798828125 +80679 -0.284698486328125 +80680 -0.231414794921875 +80681 -0.22003173828125 +80682 -0.117645263671875 +80683 -0.11505126953125 +80684 0.007049560546875 +80685 0.0003662109375 +80686 0.087982177734375 +80687 0.07586669921875 +80688 0.13946533203125 +80689 0.12457275390625 +80690 0.17425537109375 +80691 0.158111572265625 +80692 0.188201904296875 +80693 0.17254638671875 +80694 0.171234130859375 +80695 0.15850830078125 +80696 0.118438720703125 +80697 0.111419677734375 +80698 0.05706787109375 +80699 0.0562744140625 +80700 -0.010711669921875 +80701 -0.0050048828125 +80702 -0.0914306640625 +80703 -0.078521728515625 +80704 -0.162322998046875 +80705 -0.143310546875 +80706 -0.194549560546875 +80707 -0.172882080078125 +80708 -0.1492919921875 +80709 -0.13153076171875 +80710 -0.02166748046875 +80711 -0.014678955078125 +80712 0.124053955078125 +80713 0.1185302734375 +80714 0.211151123046875 +80715 0.197601318359375 +80716 0.240447998046875 +80717 0.223358154296875 +80718 0.242218017578125 +80719 0.22369384765625 +80720 0.2257080078125 +80721 0.20721435546875 +80722 0.194366455078125 +80723 0.177154541015625 +80724 0.115509033203125 +80725 0.103515625 +80726 0.0128173828125 +80727 0.00811767578125 +80728 -0.053802490234375 +80729 -0.053863525390625 +80730 -0.110626220703125 +80731 -0.1065673828125 +80732 -0.199493408203125 +80733 -0.1884765625 +80734 -0.29437255859375 +80735 -0.275634765625 +80736 -0.33221435546875 +80737 -0.31005859375 +80738 -0.27972412109375 +80739 -0.261138916015625 +80740 -0.185333251953125 +80741 -0.173492431640625 +80742 -0.128204345703125 +80743 -0.1199951171875 +80744 -0.115692138671875 +80745 -0.107421875 +80746 -0.116455078125 +80747 -0.107025146484375 +80748 -0.105926513671875 +80749 -0.09625244140625 +80750 -0.053955078125 +80751 -0.047454833984375 +80752 0.048797607421875 +80753 0.04791259765625 +80754 0.157318115234375 +80755 0.148406982421875 +80756 0.212005615234375 +80757 0.19915771484375 +80758 0.218475341796875 +80759 0.205291748046875 +80760 0.23724365234375 +80761 0.222503662109375 +80762 0.30535888671875 +80763 0.284912109375 +80764 0.38128662109375 +80765 0.354278564453125 +80766 0.404449462890625 +80767 0.374908447265625 +80768 0.3944091796875 +80769 0.364837646484375 +80770 0.3885498046875 +80771 0.358551025390625 +80772 0.362640380859375 +80773 0.333831787109375 +80774 0.27362060546875 +80775 0.251068115234375 +80776 0.11712646484375 +80777 0.10626220703125 +80778 -0.054901123046875 +80779 -0.052734375 +80780 -0.19085693359375 +80781 -0.178375244140625 +80782 -0.28570556640625 +80783 -0.266021728515625 +80784 -0.339263916015625 +80785 -0.31549072265625 +80786 -0.3775634765625 +80787 -0.350738525390625 +80788 -0.445709228515625 +80789 -0.41326904296875 +80790 -0.535064697265625 +80791 -0.495147705078125 +80792 -0.629058837890625 +80793 -0.581146240234375 +80794 -0.697601318359375 +80795 -0.64361572265625 +80796 -0.70391845703125 +80797 -0.648773193359375 +80798 -0.6424560546875 +80799 -0.591522216796875 +80800 -0.491241455078125 +80801 -0.451690673828125 +80802 -0.265716552734375 +80803 -0.243499755859375 +80804 -0.023712158203125 +80805 -0.02020263671875 +80806 0.201751708984375 +80807 0.187744140625 +80808 0.375823974609375 +80809 0.3482666015625 +80810 0.485076904296875 +80811 0.449005126953125 +80812 0.56884765625 +80813 0.526153564453125 +80814 0.634765625 +80815 0.58673095703125 +80816 0.63763427734375 +80817 0.58917236328125 +80818 0.5660400390625 +80819 0.522979736328125 +80820 0.4720458984375 +80821 0.436065673828125 +80822 0.40692138671875 +80823 0.375579833984375 +80824 0.3778076171875 +80825 0.34820556640625 +80826 0.376953125 +80827 0.3468017578125 +80828 0.371978759765625 +80829 0.34161376953125 +80830 0.313140869140625 +80831 0.28692626953125 +80832 0.184417724609375 +80833 0.167999267578125 +80834 0.011199951171875 +80835 0.00823974609375 +80836 -0.171051025390625 +80837 -0.15972900390625 +80838 -0.33740234375 +80839 -0.31292724609375 +80840 -0.47198486328125 +80841 -0.436737060546875 +80842 -0.560394287109375 +80843 -0.5179443359375 +80844 -0.58056640625 +80845 -0.5362548828125 +80846 -0.54754638671875 +80847 -0.505523681640625 +80848 -0.508575439453125 +80849 -0.46923828125 +80850 -0.459503173828125 +80851 -0.423583984375 +80852 -0.394378662109375 +80853 -0.3631591796875 +80854 -0.35260009765625 +80855 -0.32421875 +80856 -0.31170654296875 +80857 -0.286102294921875 +80858 -0.197418212890625 +80859 -0.180511474609375 +80860 -0.007965087890625 +80861 -0.005828857421875 +80862 0.207489013671875 +80863 0.19268798828125 +80864 0.409210205078125 +80865 0.37847900390625 +80866 0.57208251953125 +80867 0.52838134765625 +80868 0.66595458984375 +80869 0.61468505859375 +80870 0.65875244140625 +80871 0.60791015625 +80872 0.56744384765625 +80873 0.523651123046875 +80874 0.431396484375 +80875 0.39813232421875 +80876 0.29443359375 +80877 0.271728515625 +80878 0.182464599609375 +80879 0.16827392578125 +80880 0.06365966796875 +80881 0.05853271484375 +80882 -0.075958251953125 +80883 -0.070343017578125 +80884 -0.189422607421875 +80885 -0.175140380859375 +80886 -0.271942138671875 +80887 -0.25140380859375 +80888 -0.342529296875 +80889 -0.316619873046875 +80890 -0.364166259765625 +80891 -0.336761474609375 +80892 -0.327239990234375 +80893 -0.302947998046875 +80894 -0.2769775390625 +80895 -0.25677490234375 +80896 -0.253692626953125 +80897 -0.235076904296875 +80898 -0.24365234375 +80899 -0.22540283203125 +80900 -0.1983642578125 +80901 -0.184295654296875 +80902 -0.116241455078125 +80903 -0.1102294921875 +80904 -0.036834716796875 +80905 -0.038238525390625 +80906 0.034881591796875 +80907 0.027191162109375 +80908 0.09124755859375 +80909 0.079193115234375 +80910 0.10888671875 +80911 0.096954345703125 +80912 0.125518798828125 +80913 0.11383056640625 +80914 0.15771484375 +80915 0.1444091796875 +80916 0.17828369140625 +80917 0.1644287109375 +80918 0.17108154296875 +80919 0.159454345703125 +80920 0.129974365234375 +80921 0.123992919921875 +80922 0.082427978515625 +80923 0.08233642578125 +80924 0.027679443359375 +80925 0.0338134765625 +80926 -0.065643310546875 +80927 -0.0494384765625 +80928 -0.15936279296875 +80929 -0.13348388671875 +80930 -0.21307373046875 +80931 -0.182373046875 +80932 -0.234649658203125 +80933 -0.20306396484375 +80934 -0.2001953125 +80935 -0.174224853515625 +80936 -0.119171142578125 +80937 -0.10418701171875 +80938 -0.024749755859375 +80939 -0.022308349609375 +80940 0.085784912109375 +80941 0.073944091796875 +80942 0.178131103515625 +80943 0.154205322265625 +80944 0.215576171875 +80945 0.186004638671875 +80946 0.211456298828125 +80947 0.18121337890625 +80948 0.17523193359375 +80949 0.148284912109375 +80950 0.128753662109375 +80951 0.106689453125 +80952 0.1019287109375 +80953 0.082977294921875 +80954 0.0743408203125 +80955 0.05902099609375 +80956 0.04327392578125 +80957 0.0323486328125 +80958 0.038177490234375 +80959 0.029022216796875 +80960 0.076263427734375 +80961 0.064300537109375 +80962 0.14105224609375 +80963 0.1234130859375 +80964 0.186431884765625 +80965 0.16534423828125 +80966 0.188812255859375 +80967 0.169036865234375 +80968 0.1390380859375 +80969 0.126251220703125 +80970 0.041778564453125 +80971 0.041107177734375 +80972 -0.079437255859375 +80973 -0.0655517578125 +80974 -0.219390869140625 +80975 -0.18914794921875 +80976 -0.367828369140625 +80977 -0.320587158203125 +80978 -0.494873046875 +80979 -0.433349609375 +80980 -0.556243896484375 +80981 -0.488128662109375 +80982 -0.508697509765625 +80983 -0.446502685546875 +80984 -0.3756103515625 +80985 -0.32916259765625 +80986 -0.218902587890625 +80987 -0.191070556640625 +80988 -0.063751220703125 +80989 -0.05450439453125 +80990 0.091552734375 +80991 0.08209228515625 +80992 0.23602294921875 +80993 0.209075927734375 +80994 0.342987060546875 +80995 0.30279541015625 +80996 0.39520263671875 +80997 0.3480224609375 +80998 0.389373779296875 +80999 0.3419189453125 +81000 0.324249267578125 +81001 0.28338623046875 +81002 0.224090576171875 +81003 0.194000244140625 +81004 0.124267578125 +81005 0.105224609375 +81006 0.037078857421875 +81007 0.027923583984375 +81008 -0.010101318359375 +81009 -0.013580322265625 +81010 -0.019439697265625 +81011 -0.021270751953125 +81012 -0.022796630859375 +81013 -0.0234375 +81014 -0.001556396484375 +81015 -0.003570556640625 +81016 0.056304931640625 +81017 0.048919677734375 +81018 0.106719970703125 +81019 0.09478759765625 +81020 0.096893310546875 +81021 0.087127685546875 +81022 0.042694091796875 +81023 0.040008544921875 +81024 -0.018035888671875 +81025 -0.0130615234375 +81026 -0.07586669921875 +81027 -0.063720703125 +81028 -0.11944580078125 +81029 -0.1019287109375 +81030 -0.15972900390625 +81031 -0.137451171875 +81032 -0.202606201171875 +81033 -0.175537109375 +81034 -0.24859619140625 +81035 -0.216644287109375 +81036 -0.30517578125 +81037 -0.267333984375 +81038 -0.36212158203125 +81039 -0.31854248046875 +81040 -0.39141845703125 +81041 -0.345367431640625 +81042 -0.35528564453125 +81043 -0.314178466796875 +81044 -0.249969482421875 +81045 -0.22161865234375 +81046 -0.092864990234375 +81047 -0.083099365234375 +81048 0.08905029296875 +81049 0.0775146484375 +81050 0.2352294921875 +81051 0.206512451171875 +81052 0.318817138671875 +81053 0.28009033203125 +81054 0.358642578125 +81055 0.31500244140625 +81056 0.347747802734375 +81057 0.305084228515625 +81058 0.28564453125 +81059 0.249908447265625 +81060 0.223175048828125 +81061 0.19464111328125 +81062 0.196746826171875 +81063 0.17156982421875 +81064 0.179840087890625 +81065 0.1571044921875 +81066 0.155548095703125 +81067 0.13623046875 +81068 0.151214599609375 +81069 0.133148193359375 +81070 0.156951904296875 +81071 0.139068603515625 +81072 0.13177490234375 +81073 0.117523193359375 +81074 0.100799560546875 +81075 0.09075927734375 +81076 0.087127685546875 +81077 0.079254150390625 +81078 0.05487060546875 +81079 0.051116943359375 +81080 -0.009002685546875 +81081 -0.0052490234375 +81082 -0.10400390625 +81083 -0.089385986328125 +81084 -0.229400634765625 +81085 -0.200653076171875 +81086 -0.35552978515625 +81087 -0.312713623046875 +81088 -0.441925048828125 +81089 -0.3896484375 +81090 -0.473846435546875 +81091 -0.41839599609375 +81092 -0.464813232421875 +81093 -0.410858154296875 +81094 -0.419097900390625 +81095 -0.370819091796875 +81096 -0.334320068359375 +81097 -0.296173095703125 +81098 -0.227935791015625 +81099 -0.20233154296875 +81100 -0.12347412109375 +81101 -0.11016845703125 +81102 -0.02764892578125 +81103 -0.025604248046875 +81104 0.077667236328125 +81105 0.06744384765625 +81106 0.2132568359375 +81107 0.187469482421875 +81108 0.38885498046875 +81109 0.3431396484375 +81110 0.582794189453125 +81111 0.51519775390625 +81112 0.734039306640625 +81113 0.649444580078125 +81114 0.800140380859375 +81115 0.708221435546875 +81116 0.7783203125 +81117 0.68902587890625 +81118 0.6651611328125 +81119 0.588836669921875 +81120 0.45965576171875 +81121 0.40673828125 +81122 0.199188232421875 +81123 0.1759033203125 +81124 -0.050689697265625 +81125 -0.04547119140625 +81126 -0.23297119140625 +81127 -0.206817626953125 +81128 -0.33013916015625 +81129 -0.292633056640625 +81130 -0.368408203125 +81131 -0.326171875 +81132 -0.378936767578125 +81133 -0.335113525390625 +81134 -0.376983642578125 +81135 -0.333038330078125 +81136 -0.37969970703125 +81137 -0.335205078125 +81138 -0.391510009765625 +81139 -0.345550537109375 +81140 -0.385345458984375 +81141 -0.340057373046875 +81142 -0.3419189453125 +81143 -0.301605224609375 +81144 -0.28289794921875 +81145 -0.249420166015625 +81146 -0.251617431640625 +81147 -0.221954345703125 +81148 -0.266143798828125 +81149 -0.235198974609375 +81150 -0.273345947265625 +81151 -0.24200439453125 +81152 -0.216796875 +81153 -0.192352294921875 +81154 -0.128265380859375 +81155 -0.114166259765625 +81156 -0.068145751953125 +81157 -0.060089111328125 +81158 -0.0430908203125 +81159 -0.03594970703125 +81160 -0.024444580078125 +81161 -0.01739501953125 +81162 0.020721435546875 +81163 0.023651123046875 +81164 0.124481201171875 +81165 0.114501953125 +81166 0.25787353515625 +81167 0.230224609375 +81168 0.379119873046875 +81169 0.334991455078125 +81170 0.47991943359375 +81171 0.421661376953125 +81172 0.5281982421875 +81173 0.4627685546875 +81174 0.511138916015625 +81175 0.447357177734375 +81176 0.456207275390625 +81177 0.399017333984375 +81178 0.407470703125 +81179 0.355560302734375 +81180 0.383758544921875 +81181 0.333221435546875 +81182 0.35687255859375 +81183 0.307952880859375 +81184 0.31182861328125 +81185 0.267059326171875 +81186 0.250885009765625 +81187 0.212615966796875 +81188 0.1654052734375 +81189 0.137359619140625 +81190 0.035247802734375 +81191 0.024139404296875 +81192 -0.142059326171875 +81193 -0.129058837890625 +81194 -0.33563232421875 +81195 -0.295745849609375 +81196 -0.5345458984375 +81197 -0.46649169921875 +81198 -0.72186279296875 +81199 -0.62677001953125 +81200 -0.836669921875 +81201 -0.7244873046875 +81202 -0.8326416015625 +81203 -0.72003173828125 +81204 -0.7296142578125 +81205 -0.6304931640625 +81206 -0.582550048828125 +81207 -0.502960205078125 +81208 -0.440093994140625 +81209 -0.379180908203125 +81210 -0.324310302734375 +81211 -0.278167724609375 +81212 -0.20147705078125 +81213 -0.171142578125 +81214 -0.044647216796875 +81215 -0.035125732421875 +81216 0.103973388671875 +81217 0.093658447265625 +81218 0.202392578125 +81219 0.179168701171875 +81220 0.264495849609375 +81221 0.233245849609375 +81222 0.338897705078125 +81223 0.2974853515625 +81224 0.443817138671875 +81225 0.387420654296875 +81226 0.545074462890625 +81227 0.47381591796875 +81228 0.6173095703125 +81229 0.53497314453125 +81230 0.6524658203125 +81231 0.564056396484375 +81232 0.66339111328125 +81233 0.572113037109375 +81234 0.6561279296875 +81235 0.56439208984375 +81236 0.606781005859375 +81237 0.520538330078125 +81238 0.501190185546875 +81239 0.42852783203125 +81240 0.352783203125 +81241 0.2999267578125 +81242 0.176544189453125 +81243 0.147674560546875 +81244 -0.034820556640625 +81245 -0.034423828125 +81246 -0.258209228515625 +81247 -0.226531982421875 +81248 -0.44244384765625 +81249 -0.384765625 +81250 -0.5753173828125 +81251 -0.4986572265625 +81252 -0.65203857421875 +81253 -0.56414794921875 +81254 -0.641632080078125 +81255 -0.55474853515625 +81256 -0.562164306640625 +81257 -0.485931396484375 +81258 -0.458038330078125 +81259 -0.395782470703125 +81260 -0.350555419921875 +81261 -0.302581787109375 +81262 -0.260528564453125 +81263 -0.224212646484375 +81264 -0.192108154296875 +81265 -0.164306640625 +81266 -0.141937255859375 +81267 -0.120086669921875 +81268 -0.1021728515625 +81269 -0.08489990234375 +81270 -0.062896728515625 +81271 -0.050323486328125 +81272 -0.011932373046875 +81273 -0.005950927734375 +81274 0.062835693359375 +81275 0.058563232421875 +81276 0.148712158203125 +81277 0.13232421875 +81278 0.241729736328125 +81279 0.2119140625 +81280 0.34912109375 +81281 0.30352783203125 +81282 0.457305908203125 +81283 0.395599365234375 +81284 0.54388427734375 +81285 0.46893310546875 +81286 0.5728759765625 +81287 0.492828369140625 +81288 0.506591796875 +81289 0.43505859375 +81290 0.351226806640625 +81291 0.300994873046875 +81292 0.146514892578125 +81293 0.12469482421875 +81294 -0.05523681640625 +81295 -0.048980712890625 +81296 -0.21624755859375 +81297 -0.18768310546875 +81298 -0.334930419921875 +81299 -0.289947509765625 +81300 -0.402984619140625 +81301 -0.348663330078125 +81302 -0.4412841796875 +81303 -0.381683349609375 +81304 -0.49578857421875 +81305 -0.428375244140625 +81306 -0.5601806640625 +81307 -0.483306884765625 +81308 -0.600738525390625 +81309 -0.51763916015625 +81310 -0.584228515625 +81311 -0.502960205078125 +81312 -0.47930908203125 +81313 -0.41241455078125 +81314 -0.27935791015625 +81315 -0.240447998046875 +81316 -0.0089111328125 +81317 -0.008087158203125 +81318 0.268798828125 +81319 0.23046875 +81320 0.482818603515625 +81321 0.41448974609375 +81322 0.60369873046875 +81323 0.518707275390625 +81324 0.650421142578125 +81325 0.559295654296875 +81326 0.66400146484375 +81327 0.57135009765625 +81328 0.6414794921875 +81329 0.55230712890625 +81330 0.572540283203125 +81331 0.49334716796875 +81332 0.498138427734375 +81333 0.429534912109375 +81334 0.439453125 +81335 0.378997802734375 +81336 0.375518798828125 +81337 0.323822021484375 +81338 0.274505615234375 +81339 0.236785888671875 +81340 0.1087646484375 +81341 0.09423828125 +81342 -0.099395751953125 +81343 -0.084686279296875 +81344 -0.3182373046875 +81345 -0.272735595703125 +81346 -0.5489501953125 +81347 -0.470916748046875 +81348 -0.7738037109375 +81349 -0.663970947265625 +81350 -0.86383056640625 +81351 -0.806549072265625 +81352 -0.870391845703125 +81353 -0.856231689453125 +81354 -0.86895751953125 +81355 -0.856201171875 +81356 -0.861053466796875 +81357 -0.81732177734375 +81358 -0.765869140625 +81359 -0.697235107421875 +81360 -0.5301513671875 +81361 -0.5001220703125 +81362 -0.214691162109375 +81363 -0.23211669921875 +81364 0.137359619140625 +81365 0.069915771484375 +81366 0.474822998046875 +81367 0.36199951171875 +81368 0.76239013671875 +81369 0.613677978515625 +81370 0.867462158203125 +81371 0.801849365234375 +81372 0.870361328125 +81373 0.86236572265625 +81374 0.86480712890625 +81375 0.8680419921875 +81376 0.831817626953125 +81377 0.8662109375 +81378 0.677581787109375 +81379 0.85919189453125 +81380 0.495880126953125 +81381 0.790435791015625 +81382 0.30767822265625 +81383 0.6563720703125 +81384 0.116180419921875 +81385 0.497283935546875 +81386 -0.110748291015625 +81387 0.286041259765625 +81388 -0.381805419921875 +81389 0.016754150390625 +81390 -0.6572265625 +81391 -0.27392578125 +81392 -0.857421875 +81393 -0.534698486328125 +81394 -0.870391845703125 +81395 -0.728790283203125 +81396 -0.870391845703125 +81397 -0.850006103515625 +81398 -0.86444091796875 +81399 -0.86181640625 +81400 -0.85723876953125 +81401 -0.86749267578125 +81402 -0.790008544921875 +81403 -0.86932373046875 +81404 -0.62847900390625 +81405 -0.862274169921875 +81406 -0.3956298828125 +81407 -0.776763916015625 +81408 -0.126708984375 +81409 -0.5716552734375 +81410 0.150115966796875 +81411 -0.333831787109375 +81412 0.424041748046875 +81413 -0.073638916015625 +81414 0.670623779296875 +81415 0.186065673828125 +81416 0.854522705078125 +81417 0.4127197265625 +81418 0.866485595703125 +81419 0.59124755859375 +81420 0.86920166015625 +81421 0.708526611328125 +81422 0.8653564453125 +81423 0.779205322265625 +81424 0.857147216796875 +81425 0.81414794921875 +81426 0.766845703125 +81427 0.81085205078125 +81428 0.628509521484375 +81429 0.773590087890625 +81430 0.462127685546875 +81431 0.696990966796875 +81432 0.297210693359375 +81433 0.602569580078125 +81434 0.14862060546875 +81435 0.5008544921875 +81436 -0.00537109375 +81437 0.373443603515625 +81438 -0.15753173828125 +81439 0.2269287109375 +81440 -0.31304931640625 +81441 0.05877685546875 +81442 -0.48876953125 +81443 -0.142120361328125 +81444 -0.6416015625 +81445 -0.33673095703125 +81446 -0.751373291015625 +81447 -0.50433349609375 +81448 -0.84619140625 +81449 -0.663665771484375 +81450 -0.861297607421875 +81451 -0.802398681640625 +81452 -0.863250732421875 +81453 -0.858734130859375 +81454 -0.856597900390625 +81455 -0.86053466796875 +81456 -0.7498779296875 +81457 -0.855377197265625 +81458 -0.624542236328125 +81459 -0.798858642578125 +81460 -0.47808837890625 +81461 -0.701324462890625 +81462 -0.253387451171875 +81463 -0.521881103515625 +81464 0.003692626953125 +81465 -0.2984619140625 +81466 0.2257080078125 +81467 -0.087799072265625 +81468 0.427154541015625 +81469 0.12005615234375 +81470 0.643218994140625 +81471 0.351409912109375 +81472 0.855926513671875 +81473 0.59796142578125 +81474 0.870361328125 +81475 0.8116455078125 +81476 0.870361328125 +81477 0.86505126953125 +81478 0.862762451171875 +81479 0.870361328125 +81480 0.79669189453125 +81481 0.868133544921875 +81482 0.595794677734375 +81483 0.857696533203125 +81484 0.362152099609375 +81485 0.737945556640625 +81486 0.1270751953125 +81487 0.56536865234375 +81488 -0.086944580078125 +81489 0.3843994140625 +81490 -0.2784423828125 +81491 0.197235107421875 +81492 -0.484832763671875 +81493 -0.024627685546875 +81494 -0.729583740234375 +81495 -0.297027587890625 +81496 -0.86688232421875 +81497 -0.578582763671875 +81498 -0.870391845703125 +81499 -0.817596435546875 +81500 -0.86859130859375 +81501 -0.870391845703125 +81502 -0.86279296875 +81503 -0.870391845703125 +81504 -0.817962646484375 +81505 -0.863525390625 +81506 -0.6116943359375 +81507 -0.78167724609375 +81508 -0.3128662109375 +81509 -0.534423828125 +81510 0.039398193359375 +81511 -0.228057861328125 +81512 0.422821044921875 +81513 0.11773681640625 +81514 0.805145263671875 +81515 0.47430419921875 +81516 0.870361328125 +81517 0.786285400390625 +81518 0.870361328125 +81519 0.870361328125 +81520 0.860015869140625 +81521 0.870361328125 +81522 0.727935791015625 +81523 0.861175537109375 +81524 0.48114013671875 +81525 0.755401611328125 +81526 0.2059326171875 +81527 0.55078125 +81528 -0.06103515625 +81529 0.33154296875 +81530 -0.29913330078125 +81531 0.115203857421875 +81532 -0.516204833984375 +81533 -0.10296630859375 +81534 -0.7252197265625 +81535 -0.3309326171875 +81536 -0.85980224609375 +81537 -0.546051025390625 +81538 -0.870391845703125 +81539 -0.72052001953125 +81540 -0.870391845703125 +81541 -0.833038330078125 +81542 -0.858062744140625 +81543 -0.848785400390625 +81544 -0.673004150390625 +81545 -0.77154541015625 +81546 -0.42694091796875 +81547 -0.653289794921875 +81548 -0.2100830078125 +81549 -0.540252685546875 +81550 -0.0362548828125 +81551 -0.440765380859375 +81552 0.10943603515625 +81553 -0.340789794921875 +81554 0.23516845703125 +81555 -0.233184814453125 +81556 0.373687744140625 +81557 -0.091888427734375 +81558 0.517791748046875 +81559 0.07501220703125 +81560 0.602783203125 +81561 0.21099853515625 +81562 0.635711669921875 +81563 0.317779541015625 +81564 0.655181884765625 +81565 0.42242431640625 +81566 0.65948486328125 +81567 0.5184326171875 +81568 0.651275634765625 +81569 0.602813720703125 +81570 0.61846923828125 +81571 0.66070556640625 +81572 0.53753662109375 +81573 0.668243408203125 +81574 0.404144287109375 +81575 0.618133544921875 +81576 0.22186279296875 +81577 0.510498046875 +81578 0.003997802734375 +81579 0.354461669921875 +81580 -0.22100830078125 +81581 0.172698974609375 +81582 -0.42449951171875 +81583 -0.010772705078125 +81584 -0.579833984375 +81585 -0.172576904296875 +81586 -0.641876220703125 +81587 -0.273193359375 +81588 -0.6177978515625 +81589 -0.315338134765625 +81590 -0.575531005859375 +81591 -0.35125732421875 +81592 -0.526336669921875 +81593 -0.386138916015625 +81594 -0.42645263671875 +81595 -0.37969970703125 +81596 -0.2581787109375 +81597 -0.31317138671875 +81598 -0.068695068359375 +81599 -0.22161865234375 +81600 0.09222412109375 +81601 -0.142730712890625 +81602 0.232147216796875 +81603 -0.067657470703125 +81604 0.3509521484375 +81605 0.005279541015625 +81606 0.410064697265625 +81607 0.045196533203125 +81608 0.372955322265625 +81609 0.02203369140625 +81610 0.2554931640625 +81611 -0.05194091796875 +81612 0.10711669921875 +81613 -0.1376953125 +81614 -0.052886962890625 +81615 -0.221771240234375 +81616 -0.186279296875 +81617 -0.27557373046875 +81618 -0.23291015625 +81619 -0.25286865234375 +81620 -0.209442138671875 +81621 -0.17083740234375 +81622 -0.174163818359375 +81623 -0.080963134765625 +81624 -0.126739501953125 +81625 0.01373291015625 +81626 -0.048126220703125 +81627 0.12603759765625 +81628 0.0426025390625 +81629 0.2379150390625 +81630 0.10748291015625 +81631 0.316375732421875 +81632 0.1409912109375 +81633 0.3558349609375 +81634 0.19708251953125 +81635 0.400482177734375 +81636 0.273651123046875 +81637 0.4490966796875 +81638 0.31768798828125 +81639 0.459136962890625 +81640 0.341094970703125 +81641 0.442169189453125 +81642 0.368011474609375 +81643 0.42034912109375 +81644 0.37249755859375 +81645 0.37493896484375 +81646 0.30072021484375 +81647 0.264373779296875 +81648 0.1517333984375 +81649 0.09075927734375 +81650 -0.01470947265625 +81651 -0.09393310546875 +81652 -0.1883544921875 +81653 -0.27874755859375 +81654 -0.372711181640625 +81655 -0.464447021484375 +81656 -0.51397705078125 +81657 -0.6051025390625 +81658 -0.57177734375 +81659 -0.666351318359375 +81660 -0.53948974609375 +81661 -0.642333984375 +81662 -0.43511962890625 +81663 -0.548065185546875 +81664 -0.2962646484375 +81665 -0.415557861328125 +81666 -0.161102294921875 +81667 -0.277679443359375 +81668 -0.0435791015625 +81669 -0.1474609375 +81670 0.060394287109375 +81671 -0.0235595703125 +81672 0.13665771484375 +81673 0.080596923828125 +81674 0.170135498046875 +81675 0.150726318359375 +81676 0.16552734375 +81677 0.188323974609375 +81678 0.15728759765625 +81679 0.218841552734375 +81680 0.150787353515625 +81681 0.244720458984375 +81682 0.12200927734375 +81683 0.2452392578125 +81684 0.080108642578125 +81685 0.226654052734375 +81686 0.05126953125 +81687 0.209320068359375 +81688 0.062896728515625 +81689 0.21514892578125 +81690 0.09271240234375 +81691 0.226715087890625 +81692 0.092987060546875 +81693 0.206756591796875 +81694 0.07855224609375 +81695 0.16845703125 +81696 0.06427001953125 +81697 0.125335693359375 +81698 0.0347900390625 +81699 0.06695556640625 +81700 -0.01171875 +81701 -0.006195068359375 +81702 -0.056060791015625 +81703 -0.07672119140625 +81704 -0.055511474609375 +81705 -0.108551025390625 +81706 -0.010467529296875 +81707 -0.100341796875 +81708 0.02508544921875 +81709 -0.0938720703125 +81710 0.025665283203125 +81711 -0.1085205078125 +81712 0.017333984375 +81713 -0.122802734375 +81714 0.00189208984375 +81715 -0.135101318359375 +81716 -0.03173828125 +81717 -0.15447998046875 +81718 -0.071502685546875 +81719 -0.171966552734375 +81720 -0.13543701171875 +81721 -0.20294189453125 +81722 -0.219970703125 +81723 -0.245819091796875 +81724 -0.300506591796875 +81725 -0.28240966796875 +81726 -0.376312255859375 +81727 -0.313720703125 +81728 -0.416107177734375 +81729 -0.31634521484375 +81730 -0.371124267578125 +81731 -0.25286865234375 +81732 -0.242279052734375 +81733 -0.125457763671875 +81734 -0.069732666015625 +81735 0.032470703125 +81736 0.125640869140625 +81737 0.2032470703125 +81738 0.31268310546875 +81739 0.361328125 +81740 0.45501708984375 +81741 0.47735595703125 +81742 0.554779052734375 +81743 0.553070068359375 +81744 0.61065673828125 +81745 0.58782958984375 +81746 0.610931396484375 +81747 0.572967529296875 +81748 0.531463623046875 +81749 0.49017333984375 +81750 0.3883056640625 +81751 0.353424072265625 +81752 0.23468017578125 +81753 0.206634521484375 +81754 0.095245361328125 +81755 0.07086181640625 +81756 -0.00396728515625 +81757 -0.03173828125 +81758 -0.04852294921875 +81759 -0.088409423828125 +81760 -0.055145263671875 +81761 -0.11138916015625 +81762 -0.0758056640625 +81763 -0.14141845703125 +81764 -0.138702392578125 +81765 -0.200439453125 +81766 -0.209197998046875 +81767 -0.260406494140625 +81768 -0.289031982421875 +81769 -0.322662353515625 +81770 -0.37884521484375 +81771 -0.387969970703125 +81772 -0.456329345703125 +81773 -0.43896484375 +81774 -0.51641845703125 +81775 -0.472320556640625 +81776 -0.519287109375 +81777 -0.45709228515625 +81778 -0.458251953125 +81779 -0.38897705078125 +81780 -0.384796142578125 +81781 -0.31024169921875 +81782 -0.323699951171875 +81783 -0.241851806640625 +81784 -0.269287109375 +81785 -0.180267333984375 +81786 -0.1951904296875 +81787 -0.105377197265625 +81788 -0.100006103515625 +81789 -0.016815185546875 +81790 -0.01055908203125 +81791 0.063323974609375 +81792 0.1033935546875 +81793 0.158905029296875 +81794 0.24908447265625 +81795 0.275604248046875 +81796 0.373199462890625 +81797 0.370880126953125 +81798 0.45806884765625 +81799 0.430938720703125 +81800 0.511474609375 +81801 0.4625244140625 +81802 0.565399169921875 +81803 0.491973876953125 +81804 0.61138916015625 +81805 0.5133056640625 +81806 0.5897216796875 +81807 0.479644775390625 +81808 0.4906005859375 +81809 0.384033203125 +81810 0.33148193359375 +81811 0.241363525390625 +81812 0.147796630859375 +81813 0.080780029296875 +81814 -0.01873779296875 +81815 -0.06365966796875 +81816 -0.140289306640625 +81817 -0.169158935546875 +81818 -0.191986083984375 +81819 -0.215423583984375 +81820 -0.184295654296875 +81821 -0.210662841796875 +81822 -0.161834716796875 +81823 -0.19061279296875 +81824 -0.166595458984375 +81825 -0.189056396484375 +81826 -0.19390869140625 +81827 -0.20263671875 +81828 -0.22442626953125 +81829 -0.216400146484375 +81830 -0.279754638671875 +81831 -0.248291015625 +81832 -0.3389892578125 +81833 -0.282318115234375 +81834 -0.3543701171875 +81835 -0.28106689453125 +81836 -0.348175048828125 +81837 -0.2630615234375 +81838 -0.32598876953125 +81839 -0.23345947265625 +81840 -0.2581787109375 +81841 -0.169189453125 +81842 -0.139801025390625 +81843 -0.066802978515625 +81844 0.014617919921875 +81845 0.061767578125 +81846 0.144378662109375 +81847 0.167694091796875 +81848 0.221038818359375 +81849 0.228240966796875 +81850 0.27069091796875 +81851 0.264404296875 +81852 0.294036865234375 +81853 0.277008056640625 +81854 0.311767578125 +81855 0.28302001953125 +81856 0.339141845703125 +81857 0.295135498046875 +81858 0.360260009765625 +81859 0.301116943359375 +81860 0.360504150390625 +81861 0.2899169921875 +81862 0.308380126953125 +81863 0.23724365234375 +81864 0.18170166015625 +81865 0.12615966796875 +81866 0.0047607421875 +81867 -0.0234375 +81868 -0.17559814453125 +81869 -0.173980712890625 +81870 -0.3143310546875 +81871 -0.289398193359375 +81872 -0.36785888671875 +81873 -0.3349609375 +81874 -0.36248779296875 +81875 -0.331390380859375 +81876 -0.343536376953125 +81877 -0.314605712890625 +81878 -0.3018798828125 +81879 -0.277557373046875 +81880 -0.231414794921875 +81881 -0.2156982421875 +81882 -0.117645263671875 +81883 -0.117919921875 +81884 0.007049560546875 +81885 -0.01031494140625 +81886 0.087982177734375 +81887 0.063262939453125 +81888 0.13946533203125 +81889 0.11358642578125 +81890 0.17425537109375 +81891 0.150238037109375 +81892 0.188201904296875 +81893 0.169464111328125 +81894 0.171234130859375 +81895 0.162841796875 +81896 0.118438720703125 +81897 0.126190185546875 +81898 0.05706787109375 +81899 0.080841064453125 +81900 -0.010711669921875 +81901 0.0283203125 +81902 -0.0914306640625 +81903 -0.036468505859375 +81904 -0.162322998046875 +81905 -0.09539794921875 +81906 -0.194549560546875 +81907 -0.125457763671875 +81908 -0.1492919921875 +81909 -0.095611572265625 +81910 -0.02166748046875 +81911 -0.0015869140625 +81912 0.124053955078125 +81913 0.106109619140625 +81914 0.211151123046875 +81915 0.16717529296875 +81916 0.240447998046875 +81917 0.182708740234375 +81918 0.242218017578125 +81919 0.17706298828125 +81920 0.2257080078125 +81921 0.157440185546875 +81922 0.194366455078125 +81923 0.12713623046875 +81924 0.115509033203125 +81925 0.062164306640625 +81926 0.0128173828125 +81927 -0.01922607421875 +81928 -0.053802490234375 +81929 -0.071380615234375 +81930 -0.110626220703125 +81931 -0.1142578125 +81932 -0.199493408203125 +81933 -0.179779052734375 +81934 -0.29437255859375 +81935 -0.248321533203125 +81936 -0.33221435546875 +81937 -0.272216796875 +81938 -0.27972412109375 +81939 -0.22650146484375 +81940 -0.185333251953125 +81941 -0.148345947265625 +81942 -0.128204345703125 +81943 -0.0982666015625 +81944 -0.115692138671875 +81945 -0.08221435546875 +81946 -0.116455078125 +81947 -0.07672119140625 +81948 -0.105926513671875 +81949 -0.0634765625 +81950 -0.053955078125 +81951 -0.01983642578125 +81952 0.048797607421875 +81953 0.06109619140625 +81954 0.157318115234375 +81955 0.145050048828125 +81956 0.212005615234375 +81957 0.1866455078125 +81958 0.218475341796875 +81959 0.190185546875 +81960 0.23724365234375 +81961 0.201812744140625 +81962 0.30535888671875 +81963 0.2498779296875 +81964 0.38128662109375 +81965 0.303009033203125 +81966 0.404449462890625 +81967 0.315399169921875 +81968 0.3944091796875 +81969 0.302276611328125 +81970 0.3885498046875 +81971 0.292327880859375 +81972 0.362640380859375 +81973 0.2674560546875 +81974 0.27362060546875 +81975 0.195220947265625 +81976 0.11712646484375 +81977 0.072540283203125 +81978 -0.054901123046875 +81979 -0.0609130859375 +81980 -0.19085693359375 +81981 -0.165802001953125 +81982 -0.28570556640625 +81983 -0.238250732421875 +81984 -0.339263916015625 +81985 -0.278167724609375 +81986 -0.3775634765625 +81987 -0.305389404296875 +81988 -0.445709228515625 +81989 -0.354339599609375 +81990 -0.535064697265625 +81991 -0.41864013671875 +81992 -0.629058837890625 +81993 -0.48590087890625 +81994 -0.697601318359375 +81995 -0.53350830078125 +81996 -0.70391845703125 +81997 -0.53375244140625 +81998 -0.6424560546875 +81999 -0.482666015625 +82000 -0.491241455078125 +82001 -0.36376953125 +82002 -0.265716552734375 +82003 -0.188995361328125 +82004 -0.023712158203125 +82005 -0.002471923828125 +82006 0.201751708984375 +82007 0.170562744140625 +82008 0.375823974609375 +82009 0.303558349609375 +82010 0.485076904296875 +82011 0.38629150390625 +82012 0.56884765625 +82013 0.448699951171875 +82014 0.634765625 +82015 0.496673583984375 +82016 0.63763427734375 +82017 0.49603271484375 +82018 0.5660400390625 +82019 0.438232421875 +82020 0.4720458984375 +82021 0.363037109375 +82022 0.40692138671875 +82023 0.30963134765625 +82024 0.3778076171875 +82025 0.28369140625 +82026 0.376953125 +82027 0.279510498046875 +82028 0.371978759765625 +82029 0.272674560546875 +82030 0.313140869140625 +82031 0.225555419921875 +82032 0.184417724609375 +82033 0.126068115234375 +82034 0.011199951171875 +82035 -0.006378173828125 +82036 -0.171051025390625 +82037 -0.14483642578125 +82038 -0.33740234375 +82039 -0.2703857421875 +82040 -0.47198486328125 +82041 -0.37103271484375 +82042 -0.560394287109375 +82043 -0.43597412109375 +82044 -0.58056640625 +82045 -0.448577880859375 +82046 -0.54754638671875 +82047 -0.420440673828125 +82048 -0.508575439453125 +82049 -0.38763427734375 +82050 -0.459503173828125 +82051 -0.34716796875 +82052 -0.394378662109375 +82053 -0.294708251953125 +82054 -0.35260009765625 +82055 -0.260345458984375 +82056 -0.31170654296875 +82057 -0.227142333984375 +82058 -0.197418212890625 +82059 -0.13873291015625 +82060 -0.007965087890625 +82061 0.006134033203125 +82062 0.207489013671875 +82063 0.1700439453125 +82064 0.409210205078125 +82065 0.32281494140625 +82066 0.57208251953125 +82067 0.4454345703125 +82068 0.66595458984375 +82069 0.51507568359375 +82070 0.65875244140625 +82071 0.5074462890625 +82072 0.56744384765625 +82073 0.435577392578125 +82074 0.431396484375 +82075 0.32952880859375 +82076 0.29443359375 +82077 0.2227783203125 +82078 0.182464599609375 +82079 0.135162353515625 +82080 0.06365966796875 +82081 0.0426025390625 +82082 -0.075958251953125 +82083 -0.06536865234375 +82084 -0.189422607421875 +82085 -0.152984619140625 +82086 -0.271942138671875 +82087 -0.216552734375 +82088 -0.342529296875 +82089 -0.270477294921875 +82090 -0.364166259765625 +82091 -0.286651611328125 +82092 -0.327239990234375 +82093 -0.257781982421875 +82094 -0.2769775390625 +82095 -0.218292236328125 +82096 -0.253692626953125 +82097 -0.19891357421875 +82098 -0.24365234375 +82099 -0.189300537109375 +82100 -0.1983642578125 +82101 -0.152740478515625 +82102 -0.116241455078125 +82103 -0.088134765625 +82104 -0.036834716796875 +82105 -0.025634765625 +82106 0.034881591796875 +82107 0.03082275390625 +82108 0.09124755859375 +82109 0.0753173828125 +82110 0.10888671875 +82111 0.089996337890625 +82112 0.125518798828125 +82113 0.10345458984375 +82114 0.15771484375 +82115 0.1282958984375 +82116 0.17828369140625 +82117 0.143829345703125 +82118 0.17108154296875 +82119 0.137786865234375 +82120 0.129974365234375 +82121 0.105560302734375 +82122 0.082427978515625 +82123 0.068084716796875 +82124 0.027679443359375 +82125 0.02490234375 +82126 -0.065643310546875 +82127 -0.0477294921875 +82128 -0.15936279296875 +82129 -0.1207275390625 +82130 -0.21307373046875 +82131 -0.16326904296875 +82132 -0.234649658203125 +82133 -0.1812744140625 +82134 -0.2001953125 +82135 -0.156463623046875 +82136 -0.119171142578125 +82137 -0.095977783203125 +82138 -0.024749755859375 +82139 -0.024993896484375 +82140 0.085784912109375 +82141 0.05859375 +82142 0.178131103515625 +82143 0.12872314453125 +82144 0.215576171875 +82145 0.157501220703125 +82146 0.211456298828125 +82147 0.154998779296875 +82148 0.17523193359375 +82149 0.128387451171875 +82150 0.128753662109375 +82151 0.094207763671875 +82152 0.1019287109375 +82153 0.07513427734375 +82154 0.0743408203125 +82155 0.05560302734375 +82156 0.04327392578125 +82157 0.033416748046875 +82158 0.038177490234375 +82159 0.030914306640625 +82160 0.076263427734375 +82161 0.06109619140625 +82162 0.14105224609375 +82163 0.11138916015625 +82164 0.186431884765625 +82165 0.14666748046875 +82166 0.188812255859375 +82167 0.148956298828125 +82168 0.1390380859375 +82169 0.111297607421875 +82170 0.041778564453125 +82171 0.0372314453125 +82172 -0.079437255859375 +82173 -0.0552978515625 +82174 -0.219390869140625 +82175 -0.162322998046875 +82176 -0.367828369140625 +82177 -0.275665283203125 +82178 -0.494873046875 +82179 -0.372161865234375 +82180 -0.556243896484375 +82181 -0.41900634765625 +82182 -0.508697509765625 +82183 -0.38494873046875 +82184 -0.3756103515625 +82185 -0.287261962890625 +82186 -0.218902587890625 +82187 -0.17132568359375 +82188 -0.063751220703125 +82189 -0.05572509765625 +82190 0.091552734375 +82191 0.060455322265625 +82192 0.23602294921875 +82193 0.168975830078125 +82194 0.342987060546875 +82195 0.25018310546875 +82196 0.39520263671875 +82197 0.29132080078125 +82198 0.389373779296875 +82199 0.289825439453125 +82200 0.324249267578125 +82201 0.244659423828125 +82202 0.224090576171875 +82203 0.173370361328125 +82204 0.124267578125 +82205 0.101654052734375 +82206 0.037078857421875 +82207 0.038421630859375 +82208 -0.010101318359375 +82209 0.003631591796875 +82210 -0.019439697265625 +82211 -0.00421142578125 +82212 -0.022796630859375 +82213 -0.008209228515625 +82214 -0.001556396484375 +82215 0.0052490234375 +82216 0.056304931640625 +82217 0.0450439453125 +82218 0.106719970703125 +82219 0.079254150390625 +82220 0.096893310546875 +82221 0.069610595703125 +82222 0.042694091796875 +82223 0.027801513671875 +82224 -0.018035888671875 +82225 -0.01849365234375 +82226 -0.07586669921875 +82227 -0.06231689453125 +82228 -0.11944580078125 +82229 -0.095306396484375 +82230 -0.15972900390625 +82231 -0.12542724609375 +82232 -0.202606201171875 +82233 -0.15692138671875 +82234 -0.24859619140625 +82235 -0.19012451171875 +82236 -0.30517578125 +82237 -0.23052978515625 +82238 -0.36212158203125 +82239 -0.270751953125 +82240 -0.39141845703125 +82241 -0.290496826171875 +82242 -0.35528564453125 +82243 -0.2623291015625 +82244 -0.249969482421875 +82245 -0.18365478515625 +82246 -0.092864990234375 +82247 -0.067230224609375 +82248 0.08905029296875 +82249 0.067169189453125 +82250 0.2352294921875 +82251 0.175384521484375 +82252 0.318817138671875 +82253 0.237762451171875 +82254 0.358642578125 +82255 0.267913818359375 +82256 0.347747802734375 +82257 0.2607421875 +82258 0.28564453125 +82259 0.215850830078125 +82260 0.223175048828125 +82261 0.170257568359375 +82262 0.196746826171875 +82263 0.15045166015625 +82264 0.179840087890625 +82265 0.137237548828125 +82266 0.155548095703125 +82267 0.118316650390625 +82268 0.151214599609375 +82269 0.11370849609375 +82270 0.156951904296875 +82271 0.116302490234375 +82272 0.13177490234375 +82273 0.0963134765625 +82274 0.100799560546875 +82275 0.0721435546875 +82276 0.087127685546875 +82277 0.060638427734375 +82278 0.05487060546875 +82279 0.035797119140625 +82280 -0.009002685546875 +82281 -0.01177978515625 +82282 -0.10400390625 +82283 -0.081695556640625 +82284 -0.229400634765625 +82285 -0.173370361328125 +82286 -0.35552978515625 +82287 -0.26519775390625 +82288 -0.441925048828125 +82289 -0.327728271484375 +82290 -0.473846435546875 +82291 -0.350311279296875 +82292 -0.464813232421875 +82293 -0.342803955078125 +82294 -0.419097900390625 +82295 -0.308349609375 +82296 -0.334320068359375 +82297 -0.245269775390625 +82298 -0.227935791015625 +82299 -0.1663818359375 +82300 -0.12347412109375 +82301 -0.088897705078125 +82302 -0.02764892578125 +82303 -0.01776123046875 +82304 0.077667236328125 +82305 0.060150146484375 +82306 0.2132568359375 +82307 0.159881591796875 +82308 0.38885498046875 +82309 0.2884521484375 +82310 0.582794189453125 +82311 0.4300537109375 +82312 0.734039306640625 +82313 0.54022216796875 +82314 0.800140380859375 +82315 0.58807373046875 +82316 0.7783203125 +82317 0.57159423828125 +82318 0.6651611328125 +82319 0.488372802734375 +82320 0.45965576171875 +82321 0.337738037109375 +82322 0.199188232421875 +82323 0.146942138671875 +82324 -0.050689697265625 +82325 -0.03619384765625 +82326 -0.23297119140625 +82327 -0.17010498046875 +82328 -0.33013916015625 +82329 -0.24200439453125 +82330 -0.368408203125 +82331 -0.2708740234375 +82332 -0.378936767578125 +82333 -0.279327392578125 +82334 -0.376983642578125 +82335 -0.278472900390625 +82336 -0.37969970703125 +82337 -0.280792236328125 +82338 -0.391510009765625 +82339 -0.28948974609375 +82340 -0.385345458984375 +82341 -0.28485107421875 +82342 -0.3419189453125 +82343 -0.252838134765625 +82344 -0.28289794921875 +82345 -0.209228515625 +82346 -0.251617431640625 +82347 -0.185638427734375 +82348 -0.266143798828125 +82349 -0.195281982421875 +82350 -0.273345947265625 +82351 -0.199554443359375 +82352 -0.216796875 +82353 -0.15740966796875 +82354 -0.128265380859375 +82355 -0.092010498046875 +82356 -0.068145751953125 +82357 -0.047393798828125 +82358 -0.0430908203125 +82359 -0.0284423828125 +82360 -0.024444580078125 +82361 -0.014312744140625 +82362 0.020721435546875 +82363 0.018951416015625 +82364 0.124481201171875 +82365 0.094635009765625 +82366 0.25787353515625 +82367 0.191650390625 +82368 0.379119873046875 +82369 0.27960205078125 +82370 0.47991943359375 +82371 0.35247802734375 +82372 0.5281982421875 +82373 0.386962890625 +82374 0.511138916015625 +82375 0.373779296875 +82376 0.456207275390625 +82377 0.332977294921875 +82378 0.407470703125 +82379 0.29669189453125 +82380 0.383758544921875 +82381 0.278656005859375 +82382 0.35687255859375 +82383 0.258392333984375 +82384 0.31182861328125 +82385 0.2249755859375 +82386 0.250885009765625 +82387 0.18011474609375 +82388 0.1654052734375 +82389 0.117523193359375 +82390 0.035247802734375 +82391 0.0225830078125 +82392 -0.142059326171875 +82393 -0.10650634765625 +82394 -0.33563232421875 +82395 -0.24725341796875 +82396 -0.5345458984375 +82397 -0.3917236328125 +82398 -0.72186279296875 +82399 -0.527587890625 +82400 -0.836669921875 +82401 -0.61053466796875 +82402 -0.8326416015625 +82403 -0.606903076171875 +82404 -0.7296142578125 +82405 -0.531158447265625 +82406 -0.582550048828125 +82407 -0.423370361328125 +82408 -0.440093994140625 +82409 -0.3189697265625 +82410 -0.324310302734375 +82411 -0.234100341796875 +82412 -0.20147705078125 +82413 -0.14422607421875 +82414 -0.044647216796875 +82415 -0.02972412109375 +82416 0.103973388671875 +82417 0.078643798828125 +82418 0.202392578125 +82419 0.150299072265625 +82420 0.264495849609375 +82421 0.195343017578125 +82422 0.338897705078125 +82423 0.249176025390625 +82424 0.443817138671875 +82425 0.3250732421875 +82426 0.545074462890625 +82427 0.398223876953125 +82428 0.6173095703125 +82429 0.4501953125 +82430 0.6524658203125 +82431 0.47515869140625 +82432 0.66339111328125 +82433 0.482147216796875 +82434 0.6561279296875 +82435 0.47540283203125 +82436 0.606781005859375 +82437 0.438232421875 +82438 0.501190185546875 +82439 0.3609619140625 +82440 0.352783203125 +82441 0.253143310546875 +82442 0.176544189453125 +82443 0.125518798828125 +82444 -0.034820556640625 +82445 -0.02667236328125 +82446 -0.258209228515625 +82447 -0.187042236328125 +82448 -0.44244384765625 +82449 -0.3197021484375 +82450 -0.5753173828125 +82451 -0.415863037109375 +82452 -0.65203857421875 +82453 -0.47198486328125 +82454 -0.641632080078125 +82455 -0.4664306640625 +82456 -0.562164306640625 +82457 -0.41168212890625 +82458 -0.458038330078125 +82459 -0.338653564453125 +82460 -0.350555419921875 +82461 -0.26220703125 +82462 -0.260528564453125 +82463 -0.19696044921875 +82464 -0.192108154296875 +82465 -0.145965576171875 +82466 -0.141937255859375 +82467 -0.107086181640625 +82468 -0.1021728515625 +82469 -0.075103759765625 +82470 -0.062896728515625 +82471 -0.0433349609375 +82472 -0.011932373046875 +82473 -0.003570556640625 +82474 0.062835693359375 +82475 0.052398681640625 +82476 0.148712158203125 +82477 0.11553955078125 +82478 0.241729736328125 +82479 0.182861328125 +82480 0.34912109375 +82481 0.259307861328125 +82482 0.457305908203125 +82483 0.33538818359375 +82484 0.54388427734375 +82485 0.395477294921875 +82486 0.5728759765625 +82487 0.41461181640625 +82488 0.506591796875 +82489 0.366607666015625 +82490 0.351226806640625 +82491 0.255889892578125 +82492 0.146514892578125 +82493 0.11029052734375 +82494 -0.05523681640625 +82495 -0.033599853515625 +82496 -0.21624755859375 +82497 -0.1492919921875 +82498 -0.334930419921875 +82499 -0.235443115234375 +82500 -0.402984619140625 +82501 -0.286102294921875 +82502 -0.4412841796875 +82503 -0.315643310546875 +82504 -0.49578857421875 +82505 -0.35589599609375 +82506 -0.5601806640625 +82507 -0.402374267578125 +82508 -0.600738525390625 +82509 -0.4315185546875 +82510 -0.584228515625 +82511 -0.420196533203125 +82512 -0.47930908203125 +82513 -0.3465576171875 +82514 -0.27935791015625 +82515 -0.206085205078125 +82516 -0.0089111328125 +82517 -0.01593017578125 +82518 0.268798828125 +82519 0.17974853515625 +82520 0.482818603515625 +82521 0.331451416015625 +82522 0.60369873046875 +82523 0.41851806640625 +82524 0.650421142578125 +82525 0.453948974609375 +82526 0.66400146484375 +82527 0.466156005859375 +82528 0.6414794921875 +82529 0.45294189453125 +82530 0.572540283203125 +82531 0.406982421875 +82532 0.498138427734375 +82533 0.356689453125 +82534 0.439453125 +82535 0.316741943359375 +82536 0.375518798828125 +82537 0.27252197265625 +82538 0.274505615234375 +82539 0.201873779296875 +82540 0.1087646484375 +82541 0.085601806640625 +82542 -0.099395751953125 +82543 -0.060699462890625 +82544 -0.3182373046875 +82545 -0.214813232421875 +82546 -0.5489501953125 +82547 -0.37750244140625 +82548 -0.7738037109375 +82549 -0.536285400390625 +82550 -0.86383056640625 +82551 -0.6541748046875 +82552 -0.870391845703125 +82553 -0.707916259765625 +82554 -0.86895751953125 +82555 -0.709716796875 +82556 -0.861053466796875 +82557 -0.6685791015625 +82558 -0.765869140625 +82559 -0.5723876953125 +82560 -0.5301513671875 +82561 -0.413238525390625 +82562 -0.214691162109375 +82563 -0.196014404296875 +82564 0.137359619140625 +82565 0.04925537109375 +82566 0.474822998046875 +82567 0.286865234375 +82568 0.76239013671875 +82569 0.492034912109375 +82570 0.867462158203125 +82571 0.64593505859375 +82572 0.870361328125 +82573 0.748748779296875 +82574 0.86480712890625 +82575 0.792327880859375 +82576 0.831817626953125 +82577 0.780303955078125 +82578 0.677581787109375 +82579 0.729522705078125 +82580 0.495880126953125 +82581 0.643951416015625 +82582 0.30767822265625 +82583 0.536376953125 +82584 0.116180419921875 +82585 0.40826416015625 +82586 -0.110748291015625 +82587 0.23748779296875 +82588 -0.381805419921875 +82589 0.019195556640625 +82590 -0.6572265625 +82591 -0.216796875 +82592 -0.857421875 +82593 -0.428802490234375 +82594 -0.870391845703125 +82595 -0.586883544921875 +82596 -0.870391845703125 +82597 -0.68603515625 +82598 -0.86444091796875 +82599 -0.744873046875 +82600 -0.85723876953125 +82601 -0.788177490234375 +82602 -0.790008544921875 +82603 -0.803070068359375 +82604 -0.62847900390625 +82605 -0.751708984375 +82606 -0.3956298828125 +82607 -0.631805419921875 +82608 -0.126708984375 +82609 -0.46612548828125 +82610 0.150115966796875 +82611 -0.273712158203125 +82612 0.424041748046875 +82613 -0.062652587890625 +82614 0.670623779296875 +82615 0.148284912109375 +82616 0.854522705078125 +82617 0.3321533203125 +82618 0.866485595703125 +82619 0.47662353515625 +82620 0.86920166015625 +82621 0.570953369140625 +82622 0.8653564453125 +82623 0.627685546875 +82624 0.857147216796875 +82625 0.65606689453125 +82626 0.766845703125 +82627 0.654022216796875 +82628 0.628509521484375 +82629 0.62506103515625 +82630 0.462127685546875 +82631 0.564422607421875 +82632 0.297210693359375 +82633 0.489990234375 +82634 0.14862060546875 +82635 0.41033935546875 +82636 -0.00537109375 +82637 0.309478759765625 +82638 -0.15753173828125 +82639 0.192626953125 +82640 -0.31304931640625 +82641 0.0572509765625 +82642 -0.48876953125 +82643 -0.10638427734375 +82644 -0.6416015625 +82645 -0.265625 +82646 -0.751373291015625 +82647 -0.4031982421875 +82648 -0.84619140625 +82649 -0.535125732421875 +82650 -0.861297607421875 +82651 -0.651092529296875 +82652 -0.863250732421875 +82653 -0.72796630859375 +82654 -0.856597900390625 +82655 -0.74371337890625 +82656 -0.7498779296875 +82657 -0.706695556640625 +82658 -0.624542236328125 +82659 -0.6571044921875 +82660 -0.47808837890625 +82661 -0.579620361328125 +82662 -0.253387451171875 +82663 -0.433502197265625 +82664 0.003692626953125 +82665 -0.250518798828125 +82666 0.2257080078125 +82667 -0.0782470703125 +82668 0.427154541015625 +82669 0.092041015625 +82670 0.643218994140625 +82671 0.2828369140625 +82672 0.855926513671875 +82673 0.487335205078125 +82674 0.870361328125 +82675 0.665191650390625 +82676 0.870361328125 +82677 0.78173828125 +82678 0.862762451171875 +82679 0.8419189453125 +82680 0.79669189453125 +82681 0.843597412109375 +82682 0.595794677734375 +82683 0.780120849609375 +82684 0.362152099609375 +82685 0.671722412109375 +82686 0.1270751953125 +82687 0.53790283203125 +82688 -0.086944580078125 +82689 0.392822265625 +82690 -0.2784423828125 +82691 0.237640380859375 +82692 -0.484832763671875 +82693 0.04962158203125 +82694 -0.729583740234375 +82695 -0.18304443359375 +82696 -0.86688232421875 +82697 -0.425933837890625 +82698 -0.870391845703125 +82699 -0.63629150390625 +82700 -0.86859130859375 +82701 -0.810211181640625 +82702 -0.86279296875 +82703 -0.864471435546875 +82704 -0.817962646484375 +82705 -0.870391845703125 +82706 -0.6116943359375 +82707 -0.866363525390625 +82708 -0.3128662109375 +82709 -0.83123779296875 +82710 0.039398193359375 +82711 -0.62786865234375 +82712 0.422821044921875 +82713 -0.367095947265625 +82714 0.805145263671875 +82715 -0.07183837890625 +82716 0.870361328125 +82717 0.21209716796875 +82718 0.870361328125 +82719 0.446380615234375 +82720 0.860015869140625 +82721 0.6229248046875 +82722 0.727935791015625 +82723 0.736541748046875 +82724 0.48114013671875 +82725 0.7835693359375 +82726 0.2059326171875 +82727 0.780364990234375 +82728 -0.06103515625 +82729 0.74237060546875 +82730 -0.29913330078125 +82731 0.676849365234375 +82732 -0.516204833984375 +82733 0.574859619140625 +82734 -0.7252197265625 +82735 0.427001953125 +82736 -0.85980224609375 +82737 0.250640869140625 +82738 -0.870391845703125 +82739 0.0694580078125 +82740 -0.870391845703125 +82741 -0.0960693359375 +82742 -0.858062744140625 +82743 -0.21282958984375 +82744 -0.673004150390625 +82745 -0.277374267578125 +82746 -0.42694091796875 +82747 -0.324005126953125 +82748 -0.2100830078125 +82749 -0.381805419921875 +82750 -0.0362548828125 +82751 -0.44915771484375 +82752 0.10943603515625 +82753 -0.50677490234375 +82754 0.23516845703125 +82755 -0.54156494140625 +82756 0.373687744140625 +82757 -0.526397705078125 +82758 0.517791748046875 +82759 -0.46307373046875 +82760 0.602783203125 +82761 -0.394073486328125 +82762 0.635711669921875 +82763 -0.316680908203125 +82764 0.655181884765625 +82765 -0.20953369140625 +82766 0.65948486328125 +82767 -0.079986572265625 +82768 0.651275634765625 +82769 0.065826416015625 +82770 0.61846923828125 +82771 0.210906982421875 +82772 0.53753662109375 +82773 0.330108642578125 +82774 0.404144287109375 +82775 0.41094970703125 +82776 0.22186279296875 +82777 0.446685791015625 +82778 0.003997802734375 +82779 0.43798828125 +82780 -0.22100830078125 +82781 0.39691162109375 +82782 -0.42449951171875 +82783 0.33734130859375 +82784 -0.579833984375 +82785 0.2738037109375 +82786 -0.641876220703125 +82787 0.235137939453125 +82788 -0.6177978515625 +82789 0.217529296875 +82790 -0.575531005859375 +82791 0.1787109375 +82792 -0.526336669921875 +82793 0.1158447265625 +82794 -0.42645263671875 +82795 0.063995361328125 +82796 -0.2581787109375 +82797 0.0419921875 +82798 -0.068695068359375 +82799 0.0262451171875 +82800 0.09222412109375 +82801 -0.008270263671875 +82802 0.232147216796875 +82803 -0.048858642578125 +82804 0.3509521484375 +82805 -0.088531494140625 +82806 0.410064697265625 +82807 -0.1468505859375 +82808 0.372955322265625 +82809 -0.243377685546875 +82810 0.2554931640625 +82811 -0.3643798828125 +82812 0.10711669921875 +82813 -0.47552490234375 +82814 -0.052886962890625 +82815 -0.564239501953125 +82816 -0.186279296875 +82817 -0.60693359375 +82818 -0.23291015625 +82819 -0.566986083984375 +82820 -0.209442138671875 +82821 -0.46002197265625 +82822 -0.174163818359375 +82823 -0.330352783203125 +82824 -0.126739501953125 +82825 -0.1839599609375 +82826 -0.048126220703125 +82827 -0.01470947265625 +82828 0.0426025390625 +82829 0.158294677734375 +82830 0.10748291015625 +82831 0.303802490234375 +82832 0.1409912109375 +82833 0.412841796875 +82834 0.19708251953125 +82835 0.5169677734375 +82836 0.273651123046875 +82837 0.611724853515625 +82838 0.31768798828125 +82839 0.660186767578125 +82840 0.341094970703125 +82841 0.669891357421875 +82842 0.368011474609375 +82843 0.657928466796875 +82844 0.37249755859375 +82845 0.609375 +82846 0.30072021484375 +82847 0.491912841796875 +82848 0.1517333984375 +82849 0.309234619140625 +82850 -0.01470947265625 +82851 0.105987548828125 +82852 -0.1883544921875 +82853 -0.10565185546875 +82854 -0.372711181640625 +82855 -0.32269287109375 +82856 -0.51397705078125 +82857 -0.504302978515625 +82858 -0.57177734375 +82859 -0.619049072265625 +82860 -0.53948974609375 +82861 -0.658721923828125 +82862 -0.43511962890625 +82863 -0.63238525390625 +82864 -0.2962646484375 +82865 -0.56317138671875 +82866 -0.161102294921875 +82867 -0.475799560546875 +82868 -0.0435791015625 +82869 -0.37994384765625 +82870 0.060394287109375 +82871 -0.274444580078125 +82872 0.13665771484375 +82873 -0.171234130859375 +82874 0.170135498046875 +82875 -0.0836181640625 +82876 0.16552734375 +82877 -0.012420654296875 +82878 0.15728759765625 +82879 0.0609130859375 +82880 0.150787353515625 +82881 0.135528564453125 +82882 0.12200927734375 +82883 0.191131591796875 +82884 0.080108642578125 +82885 0.2298583984375 +82886 0.05126953125 +82887 0.265716552734375 +82888 0.062896728515625 +82889 0.31427001953125 +82890 0.09271240234375 +82891 0.358856201171875 +82892 0.092987060546875 +82893 0.366943359375 +82894 0.07855224609375 +82895 0.348388671875 +82896 0.06427001953125 +82897 0.314056396484375 +82898 0.0347900390625 +82899 0.25555419921875 +82900 -0.01171875 +82901 0.174163818359375 +82902 -0.056060791015625 +82903 0.085723876953125 +82904 -0.055511474609375 +82905 0.0220947265625 +82906 -0.010467529296875 +82907 -0.01336669921875 +82908 0.02508544921875 +82909 -0.0528564453125 +82910 0.025665283203125 +82911 -0.109893798828125 +82912 0.017333984375 +82913 -0.164215087890625 +82914 0.00189208984375 +82915 -0.2122802734375 +82916 -0.03173828125 +82917 -0.259674072265625 +82918 -0.071502685546875 +82919 -0.29742431640625 +82920 -0.13543701171875 +82921 -0.3372802734375 +82922 -0.219970703125 +82923 -0.37738037109375 +82924 -0.300506591796875 +82925 -0.402679443359375 +82926 -0.376312255859375 +82927 -0.41455078125 +82928 -0.416107177734375 +82929 -0.394622802734375 +82930 -0.371124267578125 +82931 -0.313262939453125 +82932 -0.242279052734375 +82933 -0.174041748046875 +82934 -0.069732666015625 +82935 -0.006622314453125 +82936 0.125640869140625 +82937 0.1722412109375 +82938 0.31268310546875 +82939 0.33929443359375 +82940 0.45501708984375 +82941 0.46826171875 +82942 0.554779052734375 +82943 0.558929443359375 +82944 0.61065673828125 +82945 0.609161376953125 +82946 0.610931396484375 +82947 0.61090087890625 +82948 0.531463623046875 +82949 0.54901123046875 +82950 0.3883056640625 +82951 0.434844970703125 +82952 0.23468017578125 +82953 0.30450439453125 +82954 0.095245361328125 +82955 0.175994873046875 +82956 -0.00396728515625 +82957 0.0684814453125 +82958 -0.04852294921875 +82959 -0.006134033203125 +82960 -0.055145263671875 +82961 -0.056121826171875 +82962 -0.0758056640625 +82963 -0.11279296875 +82964 -0.138702392578125 +82965 -0.192169189453125 +82966 -0.209197998046875 +82967 -0.269775390625 +82968 -0.289031982421875 +82969 -0.345184326171875 +82970 -0.37884521484375 +82971 -0.41778564453125 +82972 -0.456329345703125 +82973 -0.47259521484375 +82974 -0.51641845703125 +82975 -0.50634765625 +82976 -0.519287109375 +82977 -0.493743896484375 +82978 -0.458251953125 +82979 -0.431488037109375 +82980 -0.384796142578125 +82981 -0.3544921875 +82982 -0.323699951171875 +82983 -0.280670166015625 +82984 -0.269287109375 +82985 -0.20831298828125 +82986 -0.1951904296875 +82987 -0.122406005859375 +82988 -0.100006103515625 +82989 -0.02410888671875 +82990 -0.01055908203125 +82991 0.067169189453125 +82992 0.1033935546875 +82993 0.16937255859375 +82994 0.24908447265625 +82995 0.28582763671875 +82996 0.373199462890625 +82997 0.380859375 +82998 0.45806884765625 +82999 0.44244384765625 +83000 0.511474609375 +83001 0.475494384765625 +83002 0.565399169921875 +83003 0.501129150390625 +83004 0.61138916015625 +83005 0.51458740234375 +83006 0.5897216796875 +83007 0.478179931640625 +83008 0.4906005859375 +83009 0.38690185546875 +83010 0.33148193359375 +83011 0.253692626953125 +83012 0.147796630859375 +83013 0.103271484375 +83014 -0.01873779296875 +83015 -0.0355224609375 +83016 -0.140289306640625 +83017 -0.1429443359375 +83018 -0.191986083984375 +83019 -0.2012939453125 +83020 -0.184295654296875 +83021 -0.216156005859375 +83022 -0.161834716796875 +83023 -0.215576171875 +83024 -0.166595458984375 +83025 -0.22625732421875 +83026 -0.19390869140625 +83027 -0.24493408203125 +83028 -0.22442626953125 +83029 -0.2591552734375 +83030 -0.279754638671875 +83031 -0.283447265625 +83032 -0.3389892578125 +83033 -0.3050537109375 +83034 -0.3543701171875 +83035 -0.294036865234375 +83036 -0.348175048828125 +83037 -0.26611328125 +83038 -0.32598876953125 +83039 -0.226287841796875 +83040 -0.2581787109375 +83041 -0.156768798828125 +83042 -0.139801025390625 +83043 -0.055694580078125 +83044 0.014617919921875 +83045 0.06622314453125 +83046 0.144378662109375 +83047 0.16839599609375 +83048 0.221038818359375 +83049 0.2314453125 +83050 0.27069091796875 +83051 0.271759033203125 +83052 0.294036865234375 +83053 0.28955078125 +83054 0.311767578125 +83055 0.298248291015625 +83056 0.339141845703125 +83057 0.30804443359375 +83058 0.360260009765625 +83059 0.3089599609375 +83060 0.360504150390625 +83061 0.292388916015625 +83062 0.308380126953125 +83063 0.239501953125 +83064 0.18170166015625 +83065 0.13751220703125 +83066 0.0047607421875 +83067 0.00311279296875 +83068 -0.17559814453125 +83069 -0.1328125 +83070 -0.3143310546875 +83071 -0.2406005859375 +83072 -0.36785888671875 +83073 -0.291656494140625 +83074 -0.36248779296875 +83075 -0.30169677734375 +83076 -0.343536376953125 +83077 -0.29876708984375 +83078 -0.3018798828125 +83079 -0.276763916015625 +83080 -0.231414794921875 +83081 -0.231689453125 +83082 -0.117645263671875 +83083 -0.154571533203125 +83084 0.007049560546875 +83085 -0.0662841796875 +83086 0.087982177734375 +83087 -0.00201416015625 +83088 0.13946533203125 +83089 0.046417236328125 +83090 0.17425537109375 +83091 0.08612060546875 +83092 0.188201904296875 +83093 0.113433837890625 +83094 0.171234130859375 +83095 0.1209716796875 +83096 0.118438720703125 +83097 0.104644775390625 +83098 0.05706787109375 +83099 0.080810546875 +83100 -0.010711669921875 +83101 0.050048828125 +83102 -0.0914306640625 +83103 0.00762939453125 +83104 -0.162322998046875 +83105 -0.0323486328125 +83106 -0.194549560546875 +83107 -0.051849365234375 +83108 -0.1492919921875 +83109 -0.026275634765625 +83110 -0.02166748046875 +83111 0.047698974609375 +83112 0.124053955078125 +83113 0.12994384765625 +83114 0.211151123046875 +83115 0.172607421875 +83116 0.240447998046875 +83117 0.176971435546875 +83118 0.242218017578125 +83119 0.1629638671875 +83120 0.2257080078125 +83121 0.1373291015625 +83122 0.194366455078125 +83123 0.103057861328125 +83124 0.115509033203125 +83125 0.040252685546875 +83126 0.0128173828125 +83127 -0.035430908203125 +83128 -0.053802490234375 +83129 -0.08563232421875 +83130 -0.110626220703125 +83131 -0.126556396484375 +83132 -0.199493408203125 +83133 -0.18450927734375 +83134 -0.29437255859375 +83135 -0.243011474609375 +83136 -0.33221435546875 +83137 -0.26239013671875 +83138 -0.27972412109375 +83139 -0.221954345703125 +83140 -0.185333251953125 +83141 -0.15277099609375 +83142 -0.128204345703125 +83143 -0.10546875 +83144 -0.115692138671875 +83145 -0.085296630859375 +83146 -0.116455078125 +83147 -0.07318115234375 +83148 -0.105926513671875 +83149 -0.0543212890625 +83150 -0.053955078125 +83151 -0.01031494140625 +83152 0.048797607421875 +83153 0.064178466796875 +83154 0.157318115234375 +83155 0.140228271484375 +83156 0.212005615234375 +83157 0.1798095703125 +83158 0.218475341796875 +83159 0.186279296875 +83160 0.23724365234375 +83161 0.197845458984375 +83162 0.30535888671875 +83163 0.238006591796875 +83164 0.38128662109375 +83165 0.28070068359375 +83166 0.404449462890625 +83167 0.287994384765625 +83168 0.3944091796875 +83169 0.272735595703125 +83170 0.3885498046875 +83171 0.25909423828125 +83172 0.362640380859375 +83173 0.232330322265625 +83174 0.27362060546875 +83175 0.165802001953125 +83176 0.11712646484375 +83177 0.05731201171875 +83178 -0.054901123046875 +83179 -0.059783935546875 +83180 -0.19085693359375 +83181 -0.152435302734375 +83182 -0.28570556640625 +83183 -0.2171630859375 +83184 -0.339263916015625 +83185 -0.253662109375 +83186 -0.3775634765625 +83187 -0.278289794921875 +83188 -0.445709228515625 +83189 -0.319610595703125 +83190 -0.535064697265625 +83191 -0.372314453125 +83192 -0.629058837890625 +83193 -0.42620849609375 +83194 -0.697601318359375 +83195 -0.46258544921875 +83196 -0.70391845703125 +83197 -0.458648681640625 +83198 -0.6424560546875 +83199 -0.411346435546875 +83200 -0.491241455078125 +83201 -0.3077392578125 +83202 -0.265716552734375 +83203 -0.158172607421875 +83204 -0.023712158203125 +83205 0.0010986328125 +83206 0.201751708984375 +83207 0.14935302734375 +83208 0.375823974609375 +83209 0.264892578125 +83210 0.485076904296875 +83211 0.339019775390625 +83212 0.56884765625 +83213 0.394866943359375 +83214 0.634765625 +83215 0.436798095703125 +83216 0.63763427734375 +83217 0.43768310546875 +83218 0.5660400390625 +83219 0.390777587890625 +83220 0.4720458984375 +83221 0.327667236328125 +83222 0.40692138671875 +83223 0.279541015625 +83224 0.3778076171875 +83225 0.25128173828125 +83226 0.376953125 +83227 0.2388916015625 +83228 0.371978759765625 +83229 0.2236328125 +83230 0.313140869140625 +83231 0.176361083984375 +83232 0.184417724609375 +83233 0.088104248046875 +83234 0.011199951171875 +83235 -0.025299072265625 +83236 -0.171051025390625 +83237 -0.142059326171875 +83238 -0.33740234375 +83239 -0.24688720703125 +83240 -0.47198486328125 +83241 -0.330047607421875 +83242 -0.560394287109375 +83243 -0.38287353515625 +83244 -0.58056640625 +83245 -0.3922119140625 +83246 -0.54754638671875 +83247 -0.367340087890625 +83248 -0.508575439453125 +83249 -0.3369140625 +83250 -0.459503173828125 +83251 -0.298919677734375 +83252 -0.394378662109375 +83253 -0.250274658203125 +83254 -0.35260009765625 +83255 -0.215118408203125 +83256 -0.31170654296875 +83257 -0.180572509765625 +83258 -0.197418212890625 +83259 -0.102630615234375 +83260 -0.007965087890625 +83261 0.019287109375 +83262 0.207489013671875 +83263 0.155242919921875 +83264 0.409210205078125 +83265 0.281097412109375 +83266 0.57208251953125 +83267 0.38153076171875 +83268 0.66595458984375 +83269 0.43841552734375 +83270 0.65875244140625 +83271 0.4324951171875 +83272 0.56744384765625 +83273 0.374114990234375 +83274 0.431396484375 +83275 0.28717041015625 +83276 0.29443359375 +83277 0.198272705078125 +83278 0.182464599609375 +83279 0.1234130859375 +83280 0.06365966796875 +83281 0.043914794921875 +83282 -0.075958251953125 +83283 -0.048126220703125 +83284 -0.189422607421875 +83285 -0.124114990234375 +83286 -0.271942138671875 +83287 -0.18072509765625 +83288 -0.342529296875 +83289 -0.22900390625 +83290 -0.364166259765625 +83291 -0.2464599609375 +83292 -0.327239990234375 +83293 -0.22711181640625 +83294 -0.2769775390625 +83295 -0.197998046875 +83296 -0.253692626953125 +83297 -0.183319091796875 +83298 -0.24365234375 +83299 -0.174896240234375 +83300 -0.1983642578125 +83301 -0.143829345703125 +83302 -0.116241455078125 +83303 -0.08941650390625 +83304 -0.036834716796875 +83305 -0.03570556640625 +83306 0.034881591796875 +83307 0.013946533203125 +83308 0.09124755859375 +83309 0.054595947265625 +83310 0.10888671875 +83311 0.071807861328125 +83312 0.125518798828125 +83313 0.087860107421875 +83314 0.15771484375 +83315 0.112396240234375 +83316 0.17828369140625 +83317 0.128814697265625 +83318 0.17108154296875 +83319 0.12725830078125 +83320 0.129974365234375 +83321 0.10394287109375 +83322 0.082427978515625 +83323 0.0753173828125 +83324 0.027679443359375 +83325 0.040985107421875 +83326 -0.065643310546875 +83327 -0.01776123046875 +83328 -0.15936279296875 +83329 -0.07781982421875 +83330 -0.21307373046875 +83331 -0.114715576171875 +83332 -0.234649658203125 +83333 -0.132904052734375 +83334 -0.2001953125 +83335 -0.11773681640625 +83336 -0.119171142578125 +83337 -0.074615478515625 +83338 -0.024749755859375 +83339 -0.023101806640625 +83340 0.085784912109375 +83341 0.038665771484375 +83342 0.178131103515625 +83343 0.090362548828125 +83344 0.215576171875 +83345 0.110137939453125 +83346 0.211456298828125 +83347 0.1060791015625 +83348 0.17523193359375 +83349 0.08392333984375 +83350 0.128753662109375 +83351 0.056793212890625 +83352 0.1019287109375 +83353 0.04254150390625 +83354 0.0743408203125 +83355 0.02880859375 +83356 0.04327392578125 +83357 0.0137939453125 +83358 0.038177490234375 +83359 0.014923095703125 +83360 0.076263427734375 +83361 0.04229736328125 +83362 0.14105224609375 +83363 0.08575439453125 +83364 0.186431884765625 +83365 0.117340087890625 +83366 0.188812255859375 +83367 0.1226806640625 +83368 0.1390380859375 +83369 0.0960693359375 +83370 0.041778564453125 +83371 0.040191650390625 +83372 -0.079437255859375 +83373 -0.030914306640625 +83374 -0.219390869140625 +83375 -0.114227294921875 +83376 -0.367828369140625 +83377 -0.20355224609375 +83378 -0.494873046875 +83379 -0.280975341796875 +83380 -0.556243896484375 +83381 -0.31982421875 +83382 -0.508697509765625 +83383 -0.29400634765625 +83384 -0.3756103515625 +83385 -0.217376708984375 +83386 -0.218902587890625 +83387 -0.126922607421875 +83388 -0.063751220703125 +83389 -0.03753662109375 +83390 0.091552734375 +83391 0.051971435546875 +83392 0.23602294921875 +83393 0.13525390625 +83394 0.342987060546875 +83395 0.19647216796875 +83396 0.39520263671875 +83397 0.225433349609375 +83398 0.389373779296875 +83399 0.22027587890625 +83400 0.324249267578125 +83401 0.180328369140625 +83402 0.224090576171875 +83403 0.120147705078125 +83404 0.124267578125 +83405 0.06097412109375 +83406 0.037078857421875 +83407 0.010101318359375 +83408 -0.010101318359375 +83409 -0.01611328125 +83410 -0.019439697265625 +83411 -0.019134521484375 +83412 -0.022796630859375 +83413 -0.018218994140625 +83414 -0.001556396484375 +83415 -0.002349853515625 +83416 0.056304931640625 +83417 0.03546142578125 +83418 0.106719970703125 +83419 0.068634033203125 +83420 0.096893310546875 +83421 0.0653076171875 +83422 0.042694091796875 +83423 0.034912109375 +83424 -0.018035888671875 +83425 0.0 +83426 -0.07586669921875 +83427 -0.033782958984375 +83428 -0.11944580078125 +83429 -0.059661865234375 +83430 -0.15972900390625 +83431 -0.084259033203125 +83432 -0.202606201171875 +83433 -0.11102294921875 +83434 -0.24859619140625 +83435 -0.140167236328125 +83436 -0.30517578125 +83437 -0.17608642578125 +83438 -0.36212158203125 +83439 -0.2125244140625 +83440 -0.39141845703125 +83441 -0.232574462890625 +83442 -0.35528564453125 +83443 -0.21337890625 +83444 -0.249969482421875 +83445 -0.152587890625 +83446 -0.092864990234375 +83447 -0.060516357421875 +83448 0.08905029296875 +83449 0.0467529296875 +83450 0.2352294921875 +83451 0.13299560546875 +83452 0.318817138671875 +83453 0.182159423828125 +83454 0.358642578125 +83455 0.20556640625 +83456 0.347747802734375 +83457 0.199676513671875 +83458 0.28564453125 +83459 0.164825439453125 +83460 0.223175048828125 +83461 0.130279541015625 +83462 0.196746826171875 +83463 0.116424560546875 +83464 0.179840087890625 +83465 0.107940673828125 +83466 0.155548095703125 +83467 0.095001220703125 +83468 0.151214599609375 +83469 0.093017578125 +83470 0.156951904296875 +83471 0.096282958984375 +83472 0.13177490234375 +83473 0.08148193359375 +83474 0.100799560546875 +83475 0.06292724609375 +83476 0.087127685546875 +83477 0.053802490234375 +83478 0.05487060546875 +83479 0.0338134765625 +83480 -0.009002685546875 +83481 -0.004302978515625 +83482 -0.10400390625 +83483 -0.06011962890625 +83484 -0.229400634765625 +83485 -0.133148193359375 +83486 -0.35552978515625 +83487 -0.2064208984375 +83488 -0.441925048828125 +83489 -0.2568359375 +83490 -0.473846435546875 +83491 -0.275970458984375 +83492 -0.464813232421875 +83493 -0.27142333984375 +83494 -0.419097900390625 +83495 -0.245574951171875 +83496 -0.334320068359375 +83497 -0.197113037109375 +83498 -0.227935791015625 +83499 -0.135955810546875 +83500 -0.12347412109375 +83501 -0.075531005859375 +83502 -0.02764892578125 +83503 -0.01971435546875 +83504 0.077667236328125 +83505 0.04168701171875 +83506 0.2132568359375 +83507 0.120361328125 +83508 0.38885498046875 +83509 0.22174072265625 +83510 0.582794189453125 +83511 0.333465576171875 +83512 0.734039306640625 +83513 0.420745849609375 +83514 0.800140380859375 +83515 0.45941162109375 +83516 0.7783203125 +83517 0.44781494140625 +83518 0.6651611328125 +83519 0.384002685546875 +83520 0.45965576171875 +83521 0.26739501953125 +83522 0.199188232421875 +83523 0.119232177734375 +83524 -0.050689697265625 +83525 -0.023223876953125 +83526 -0.23297119140625 +83527 -0.1275634765625 +83528 -0.33013916015625 +83529 -0.183807373046875 +83530 -0.368408203125 +83531 -0.20672607421875 +83532 -0.378936767578125 +83533 -0.2139892578125 +83534 -0.376983642578125 +83535 -0.21417236328125 +83536 -0.37969970703125 +83537 -0.21697998046875 +83538 -0.391510009765625 +83539 -0.224822998046875 +83540 -0.385345458984375 +83541 -0.2222900390625 +83542 -0.3419189453125 +83543 -0.1983642578125 +83544 -0.28289794921875 +83545 -0.165313720703125 +83546 -0.251617431640625 +83547 -0.147735595703125 +83548 -0.266143798828125 +83549 -0.1558837890625 +83550 -0.273345947265625 +83551 -0.15960693359375 +83552 -0.216796875 +83553 -0.12689208984375 +83554 -0.128265380859375 +83555 -0.0758056640625 +83556 -0.068145751953125 +83557 -0.04071044921875 +83558 -0.0430908203125 +83559 -0.025390625 +83560 -0.024444580078125 +83561 -0.013702392578125 +83562 0.020721435546875 +83563 0.013031005859375 +83564 0.124481201171875 +83565 0.07293701171875 +83566 0.25787353515625 +83567 0.149505615234375 +83568 0.379119873046875 +83569 0.218994140625 +83570 0.47991943359375 +83571 0.27667236328125 +83572 0.5281982421875 +83573 0.30426025390625 +83574 0.511138916015625 +83575 0.29449462890625 +83576 0.456207275390625 +83577 0.26300048828125 +83578 0.407470703125 +83579 0.234832763671875 +83580 0.383758544921875 +83581 0.220703125 +83582 0.35687255859375 +83583 0.204620361328125 +83584 0.31182861328125 +83585 0.178131103515625 +83586 0.250885009765625 +83587 0.142578125 +83588 0.1654052734375 +83589 0.093109130859375 +83590 0.035247802734375 +83591 0.018341064453125 +83592 -0.142059326171875 +83593 -0.08306884765625 +83594 -0.33563232421875 +83595 -0.193572998046875 +83596 -0.5345458984375 +83597 -0.306915283203125 +83598 -0.72186279296875 +83599 -0.413482666015625 +83600 -0.836669921875 +83601 -0.4786376953125 +83602 -0.8326416015625 +83603 -0.47607421875 +83604 -0.7296142578125 +83605 -0.4171142578125 +83606 -0.582550048828125 +83607 -0.332977294921875 +83608 -0.440093994140625 +83609 -0.2513427734375 +83610 -0.324310302734375 +83611 -0.184814453125 +83612 -0.20147705078125 +83613 -0.1142578125 +83614 -0.044647216796875 +83615 -0.0244140625 +83616 0.103973388671875 +83617 0.060699462890625 +83618 0.202392578125 +83619 0.1171875 +83620 0.264495849609375 +83621 0.152923583984375 +83622 0.338897705078125 +83623 0.195465087890625 +83624 0.443817138671875 +83625 0.25518798828125 +83626 0.545074462890625 +83627 0.312652587890625 +83628 0.6173095703125 +83629 0.35345458984375 +83630 0.6524658203125 +83631 0.373046875 +83632 0.66339111328125 +83633 0.378753662109375 +83634 0.6561279296875 +83635 0.3740234375 +83636 0.606781005859375 +83637 0.345306396484375 +83638 0.501190185546875 +83639 0.284637451171875 +83640 0.352783203125 +83641 0.199676513671875 +83642 0.176544189453125 +83643 0.09893798828125 +83644 -0.034820556640625 +83645 -0.0216064453125 +83646 -0.258209228515625 +83647 -0.148834228515625 +83648 -0.44244384765625 +83649 -0.253662109375 +83650 -0.5753173828125 +83651 -0.32916259765625 +83652 -0.65203857421875 +83653 -0.37261962890625 +83654 -0.641632080078125 +83655 -0.366455078125 +83656 -0.562164306640625 +83657 -0.320953369140625 +83658 -0.458038330078125 +83659 -0.261383056640625 +83660 -0.350555419921875 +83661 -0.1998291015625 +83662 -0.260528564453125 +83663 -0.14813232421875 +83664 -0.192108154296875 +83665 -0.10870361328125 +83666 -0.141937255859375 +83667 -0.079681396484375 +83668 -0.1021728515625 +83669 -0.056610107421875 +83670 -0.062896728515625 +83671 -0.033905029296875 +83672 -0.011932373046875 +83673 -0.004638671875 +83674 0.062835693359375 +83675 0.037994384765625 +83676 0.148712158203125 +83677 0.086822509765625 +83678 0.241729736328125 +83679 0.139556884765625 +83680 0.34912109375 +83681 0.200347900390625 +83682 0.457305908203125 +83683 0.261505126953125 +83684 0.54388427734375 +83685 0.310302734375 +83686 0.5728759765625 +83687 0.326324462890625 +83688 0.506591796875 +83689 0.2882080078125 +83690 0.351226806640625 +83691 0.199493408203125 +83692 0.146514892578125 +83693 0.082763671875 +83694 -0.05523681640625 +83695 -0.0322265625 +83696 -0.21624755859375 +83697 -0.123992919921875 +83698 -0.334930419921875 +83699 -0.191619873046875 +83700 -0.402984619140625 +83701 -0.23040771484375 +83702 -0.4412841796875 +83703 -0.252197265625 +83704 -0.49578857421875 +83705 -0.2830810546875 +83706 -0.5601806640625 +83707 -0.319488525390625 +83708 -0.600738525390625 +83709 -0.342254638671875 +83710 -0.584228515625 +83711 -0.33258056640625 +83712 -0.47930908203125 +83713 -0.27294921875 +83714 -0.27935791015625 +83715 -0.160308837890625 +83716 -0.0089111328125 +83717 -0.008758544921875 +83718 0.268798828125 +83719 0.14703369140625 +83720 0.482818603515625 +83721 0.268402099609375 +83722 0.60369873046875 +83723 0.339080810546875 +83724 0.650421142578125 +83725 0.368804931640625 +83726 0.66400146484375 +83727 0.37933349609375 +83728 0.6414794921875 +83729 0.368896484375 +83730 0.572540283203125 +83731 0.331939697265625 +83732 0.498138427734375 +83733 0.290496826171875 +83734 0.439453125 +83735 0.256072998046875 +83736 0.375518798828125 +83737 0.217681884765625 +83738 0.274505615234375 +83739 0.1585693359375 +83740 0.1087646484375 +83741 0.064208984375 +83742 -0.099395751953125 +83743 -0.0531005859375 +83744 -0.3182373046875 +83745 -0.175994873046875 +83746 -0.5489501953125 +83747 -0.3048095703125 +83748 -0.7738037109375 +83749 -0.429718017578125 +83750 -0.86383056640625 +83751 -0.52215576171875 +83752 -0.870391845703125 +83753 -0.5640869140625 +83754 -0.86895751953125 +83755 -0.56494140625 +83756 -0.861053466796875 +83757 -0.53173828125 +83758 -0.765869140625 +83759 -0.45526123046875 +83760 -0.5301513671875 +83761 -0.329559326171875 +83762 -0.214691162109375 +83763 -0.15863037109375 +83764 0.137359619140625 +83765 0.034210205078125 +83766 0.474822998046875 +83767 0.22125244140625 +83768 0.76239013671875 +83769 0.3831787109375 +83770 0.867462158203125 +83771 0.505279541015625 +83772 0.870361328125 +83773 0.5875244140625 +83774 0.86480712890625 +83775 0.62347412109375 +83776 0.831817626953125 +83777 0.615814208984375 +83778 0.677581787109375 +83779 0.57745361328125 +83780 0.495880126953125 +83781 0.51141357421875 +83782 0.30767822265625 +83783 0.4276123046875 +83784 0.116180419921875 +83785 0.327239990234375 +83786 -0.110748291015625 +83787 0.193389892578125 +83788 -0.381805419921875 +83789 0.022430419921875 +83790 -0.6572265625 +83791 -0.1624755859375 +83792 -0.857421875 +83793 -0.329071044921875 +83794 -0.870391845703125 +83795 -0.4541015625 +83796 -0.870391845703125 +83797 -0.53350830078125 +83798 -0.86444091796875 +83799 -0.581512451171875 +83800 -0.85723876953125 +83801 -0.6170654296875 +83802 -0.790008544921875 +83803 -0.630126953125 +83804 -0.62847900390625 +83805 -0.59149169921875 +83806 -0.3956298828125 +83807 -0.499359130859375 +83808 -0.126708984375 +83809 -0.37127685546875 +83810 0.150115966796875 +83811 -0.221923828125 +83812 0.424041748046875 +83813 -0.057647705078125 +83814 0.670623779296875 +83815 0.10699462890625 +83816 0.854522705078125 +83817 0.2510986328125 +83818 0.866485595703125 +83819 0.365020751953125 +83820 0.86920166015625 +83821 0.440338134765625 +83822 0.8653564453125 +83823 0.486572265625 +83824 0.857147216796875 +83825 0.5107421875 +83826 0.766845703125 +83827 0.511138916015625 +83828 0.628509521484375 +83829 0.490325927734375 +83830 0.462127685546875 +83831 0.444580078125 +83832 0.297210693359375 +83833 0.38763427734375 +83834 0.14862060546875 +83835 0.3260498046875 +83836 -0.00537109375 +83837 0.247589111328125 +83838 -0.15753173828125 +83839 0.15631103515625 +83840 -0.31304931640625 +83841 0.050384521484375 +83842 -0.48876953125 +83843 -0.077606201171875 +83844 -0.6416015625 +83845 -0.202362060546875 +83846 -0.751373291015625 +83847 -0.31048583984375 +83848 -0.84619140625 +83849 -0.4141845703125 +83850 -0.861297607421875 +83851 -0.50543212890625 +83852 -0.863250732421875 +83853 -0.566314697265625 +83854 -0.856597900390625 +83855 -0.5797119140625 +83856 -0.7498779296875 +83857 -0.55206298828125 +83858 -0.624542236328125 +83859 -0.5142822265625 +83860 -0.47808837890625 +83861 -0.45452880859375 +83862 -0.253387451171875 +83863 -0.341461181640625 +83864 0.003692626953125 +83865 -0.1995849609375 +83866 0.2257080078125 +83867 -0.06561279296875 +83868 0.427154541015625 +83869 0.06707763671875 +83870 0.643218994140625 +83871 0.2156982421875 +83872 0.855926513671875 +83873 0.374969482421875 +83874 0.870361328125 +83875 0.513641357421875 +83876 0.870361328125 +83877 0.60498046875 +83878 0.862762451171875 +83879 0.652679443359375 +83880 0.79669189453125 +83881 0.655029296875 +83882 0.595794677734375 +83883 0.606903076171875 +83884 0.362152099609375 +83885 0.523834228515625 +83886 0.1270751953125 +83887 0.42083740234375 +83888 -0.086944580078125 +83889 0.30926513671875 +83890 -0.2784423828125 +83891 0.19024658203125 +83892 -0.484832763671875 +83893 0.045196533203125 +83894 -0.729583740234375 +83895 -0.13604736328125 +83896 -0.86688232421875 +83897 -0.32623291015625 +83898 -0.870391845703125 +83899 -0.49127197265625 +83900 -0.86859130859375 +83901 -0.628326416015625 +83902 -0.86279296875 +83903 -0.736114501953125 +83904 -0.817962646484375 +83905 -0.795196533203125 +83906 -0.6116943359375 +83907 -0.781097412109375 +83908 -0.3128662109375 +83909 -0.689910888671875 +83910 0.039398193359375 +83911 -0.539581298828125 +83912 0.422821044921875 +83913 -0.340850830078125 +83914 0.805145263671875 +83915 -0.111572265625 +83916 0.870361328125 +83917 0.111663818359375 +83918 0.870361328125 +83919 0.298187255859375 +83920 0.860015869140625 +83921 0.441558837890625 +83922 0.727935791015625 +83923 0.53741455078125 +83924 0.48114013671875 +83925 0.58251953125 +83926 0.2059326171875 +83927 0.589599609375 +83928 -0.06103515625 +83929 0.570526123046875 +83930 -0.29913330078125 +83931 0.53045654296875 +83932 -0.516204833984375 +83933 0.461456298828125 +83934 -0.7252197265625 +83935 0.35516357421875 +83936 -0.85980224609375 +83937 0.22491455078125 +83938 -0.870391845703125 +83939 0.08917236328125 +83940 -0.870391845703125 +83941 -0.0360107421875 +83942 -0.858062744140625 +83943 -0.12432861328125 +83944 -0.673004150390625 +83945 -0.1732177734375 +83946 -0.42694091796875 +83947 -0.21051025390625 +83948 -0.2100830078125 +83949 -0.259613037109375 +83950 -0.0362548828125 +83951 -0.319000244140625 +83952 0.10943603515625 +83953 -0.37274169921875 +83954 0.23516845703125 +83955 -0.40985107421875 +83956 0.373687744140625 +83957 -0.407867431640625 +83958 0.517791748046875 +83959 -0.367645263671875 +83960 0.602783203125 +83961 -0.322845458984375 +83962 0.635711669921875 +83963 -0.27069091796875 +83964 0.655181884765625 +83965 -0.193389892578125 +83966 0.65948486328125 +83967 -0.096435546875 +83968 0.651275634765625 +83969 0.01531982421875 +83970 0.61846923828125 +83971 0.128448486328125 +83972 0.53753662109375 +83973 0.22332763671875 +83974 0.404144287109375 +83975 0.290252685546875 +83976 0.22186279296875 +83977 0.32379150390625 +83978 0.003997802734375 +83979 0.324127197265625 +83980 -0.22100830078125 +83981 0.300018310546875 +83982 -0.42449951171875 +83983 0.261688232421875 +83984 -0.579833984375 +83985 0.219818115234375 +83986 -0.641876220703125 +83987 0.19598388671875 +83988 -0.6177978515625 +83989 0.186981201171875 +83990 -0.575531005859375 +83991 0.16058349609375 +83992 -0.526336669921875 +83993 0.114471435546875 +83994 -0.42645263671875 +83995 0.075225830078125 +83996 -0.2581787109375 +83997 0.057220458984375 +83998 -0.068695068359375 +83999 0.042633056640625 +84000 0.09222412109375 +84001 0.012603759765625 +84002 0.232147216796875 +84003 -0.022918701171875 +84004 0.3509521484375 +84005 -0.058380126953125 +84006 0.410064697265625 +84007 -0.10833740234375 +84008 0.372955322265625 +84009 -0.187286376953125 +84010 0.2554931640625 +84011 -0.28448486328125 +84012 0.10711669921875 +84013 -0.37359619140625 +84014 -0.052886962890625 +84015 -0.44482421875 +84016 -0.186279296875 +84017 -0.4801025390625 +84018 -0.23291015625 +84019 -0.451507568359375 +84020 -0.209442138671875 +84021 -0.370849609375 +84022 -0.174163818359375 +84023 -0.271728515625 +84024 -0.126739501953125 +84025 -0.1588134765625 +84026 -0.048126220703125 +84027 -0.027557373046875 +84028 0.0426025390625 +84029 0.107330322265625 +84030 0.10748291015625 +84031 0.221954345703125 +84032 0.1409912109375 +84033 0.30926513671875 +84034 0.19708251953125 +84035 0.3929443359375 +84036 0.273651123046875 +84037 0.4693603515625 +84038 0.31768798828125 +84039 0.510223388671875 +84040 0.341094970703125 +84041 0.52105712890625 +84042 0.368011474609375 +84043 0.5146484375 +84044 0.37249755859375 +84045 0.47955322265625 +84046 0.30072021484375 +84047 0.39117431640625 +84048 0.1517333984375 +84049 0.252288818359375 +84050 -0.01470947265625 +84051 0.096832275390625 +84052 -0.1883544921875 +84053 -0.06585693359375 +84054 -0.372711181640625 +84055 -0.233367919921875 +84056 -0.51397705078125 +84057 -0.374542236328125 +84058 -0.57177734375 +84059 -0.46533203125 +84060 -0.53948974609375 +84061 -0.499267578125 +84062 -0.43511962890625 +84063 -0.483001708984375 +84064 -0.2962646484375 +84065 -0.433929443359375 +84066 -0.161102294921875 +84067 -0.37060546875 +84068 -0.0435791015625 +84069 -0.30023193359375 +84070 0.060394287109375 +84071 -0.2218017578125 +84072 0.13665771484375 +84073 -0.144317626953125 +84074 0.170135498046875 +84075 -0.077880859375 +84076 0.16552734375 +84077 -0.0230712890625 +84078 0.15728759765625 +84079 0.0340576171875 +84080 0.150787353515625 +84081 0.0927734375 +84082 0.12200927734375 +84083 0.1375732421875 +84084 0.080108642578125 +84085 0.169891357421875 +84086 0.05126953125 +84087 0.200164794921875 +84088 0.062896728515625 +84089 0.240081787109375 +84090 0.09271240234375 +84091 0.276824951171875 +84092 0.092987060546875 +84093 0.2855224609375 +84094 0.07855224609375 +84095 0.273529052734375 +84096 0.06427001953125 +84097 0.248992919921875 +84098 0.0347900390625 +84099 0.205474853515625 +84100 -0.01171875 +84101 0.143951416015625 +84102 -0.056060791015625 +84103 0.076446533203125 +84104 -0.055511474609375 +84105 0.02716064453125 +84106 -0.010467529296875 +84107 -0.00128173828125 +84108 0.02508544921875 +84109 -0.033233642578125 +84110 0.025665283203125 +84111 -0.078826904296875 +84112 0.017333984375 +84113 -0.12255859375 +84114 0.00189208984375 +84115 -0.16156005859375 +84116 -0.03173828125 +84117 -0.199951171875 +84118 -0.071502685546875 +84119 -0.230804443359375 +84120 -0.13543701171875 +84121 -0.26287841796875 +84122 -0.219970703125 +84123 -0.294708251953125 +84124 -0.300506591796875 +84125 -0.314788818359375 +84126 -0.376312255859375 +84127 -0.32415771484375 +84128 -0.416107177734375 +84129 -0.308837890625 +84130 -0.371124267578125 +84131 -0.24639892578125 +84132 -0.242279052734375 +84133 -0.139556884765625 +84134 -0.069732666015625 +84135 -0.01092529296875 +84136 0.125640869140625 +84137 0.126678466796875 +84138 0.31268310546875 +84139 0.2554931640625 +84140 0.45501708984375 +84141 0.355438232421875 +84142 0.554779052734375 +84143 0.426239013671875 +84144 0.61065673828125 +84145 0.466339111328125 +84146 0.610931396484375 +84147 0.46942138671875 +84148 0.531463623046875 +84149 0.423431396484375 +84150 0.3883056640625 +84151 0.3370361328125 +84152 0.23468017578125 +84153 0.238067626953125 +84154 0.095245361328125 +84155 0.140350341796875 +84156 -0.00396728515625 +84157 0.058685302734375 +84158 -0.04852294921875 +84159 0.00213623046875 +84160 -0.055145263671875 +84161 -0.035736083984375 +84162 -0.0758056640625 +84163 -0.079254150390625 +84164 -0.138702392578125 +84165 -0.140869140625 +84166 -0.209197998046875 +84167 -0.2015380859375 +84168 -0.289031982421875 +84169 -0.26092529296875 +84170 -0.37884521484375 +84171 -0.318511962890625 +84172 -0.456329345703125 +84173 -0.362548828125 +84174 -0.51641845703125 +84175 -0.39044189453125 +84176 -0.519287109375 +84177 -0.3824462890625 +84178 -0.458251953125 +84179 -0.335906982421875 +84180 -0.384796142578125 +84181 -0.27783203125 +84182 -0.323699951171875 +84183 -0.22198486328125 +84184 -0.269287109375 +84185 -0.166961669921875 +84186 -0.1951904296875 +84187 -0.101104736328125 +84188 -0.100006103515625 +84189 -0.0252685546875 +84190 -0.01055908203125 +84191 0.045501708984375 +84192 0.1033935546875 +84193 0.1251220703125 +84194 0.24908447265625 +84195 0.216094970703125 +84196 0.373199462890625 +84197 0.290740966796875 +84198 0.45806884765625 +84199 0.33966064453125 +84200 0.511474609375 +84201 0.366607666015625 +84202 0.565399169921875 +84203 0.387908935546875 +84204 0.61138916015625 +84205 0.3997802734375 +84206 0.5897216796875 +84207 0.372894287109375 +84208 0.4906005859375 +84209 0.30328369140625 +84210 0.33148193359375 +84211 0.200958251953125 +84212 0.147796630859375 +84213 0.08502197265625 +84214 -0.01873779296875 +84215 -0.02215576171875 +84216 -0.140289306640625 +84217 -0.10528564453125 +84218 -0.191986083984375 +84219 -0.150665283203125 +84220 -0.184295654296875 +84221 -0.162628173828125 +84222 -0.161834716796875 +84223 -0.16290283203125 +84224 -0.166595458984375 +84225 -0.172088623046875 +84226 -0.19390869140625 +84227 -0.187591552734375 +84228 -0.22442626953125 +84229 -0.199737548828125 +84230 -0.279754638671875 +84231 -0.219635009765625 +84232 -0.3389892578125 +84233 -0.23736572265625 +84234 -0.3543701171875 +84235 -0.22979736328125 +84236 -0.348175048828125 +84237 -0.208984375 +84238 -0.32598876953125 +84239 -0.17877197265625 +84240 -0.2581787109375 +84241 -0.125457763671875 +84242 -0.139801025390625 +84243 -0.047607421875 +84244 0.014617919921875 +84245 0.046539306640625 +84246 0.144378662109375 +84247 0.125701904296875 +84248 0.221038818359375 +84249 0.17498779296875 +84250 0.27069091796875 +84251 0.206939697265625 +84252 0.294036865234375 +84253 0.221649169921875 +84254 0.311767578125 +84255 0.229400634765625 +84256 0.339141845703125 +84257 0.2379150390625 +84258 0.360260009765625 +84259 0.239288330078125 +84260 0.360504150390625 +84261 0.226898193359375 +84262 0.308380126953125 +84263 0.186798095703125 +84264 0.18170166015625 +84265 0.10955810546875 +84266 0.0047607421875 +84267 0.00775146484375 +84268 -0.17559814453125 +84269 -0.095458984375 +84270 -0.3143310546875 +84271 -0.17779541015625 +84272 -0.36785888671875 +84273 -0.2177734375 +84274 -0.36248779296875 +84275 -0.227081298828125 +84276 -0.343536376953125 +84277 -0.226531982421875 +84278 -0.3018798828125 +84279 -0.211456298828125 +84280 -0.231414794921875 +84281 -0.178863525390625 +84282 -0.117645263671875 +84283 -0.1219482421875 +84284 0.007049560546875 +84285 -0.056304931640625 +84286 0.087982177734375 +84287 -0.00823974609375 +84288 0.13946533203125 +84289 0.028350830078125 +84290 0.17425537109375 +84291 0.05877685546875 +84292 0.188201904296875 +84293 0.08026123046875 +84294 0.171234130859375 +84295 0.087188720703125 +84296 0.118438720703125 +84297 0.076446533203125 +84298 0.05706787109375 +84299 0.06011962890625 +84300 -0.010711669921875 +84301 0.03857421875 +84302 -0.0914306640625 +84303 0.008209228515625 +84304 -0.162322998046875 +84305 -0.0205078125 +84306 -0.194549560546875 +84307 -0.0341796875 +84308 -0.1492919921875 +84309 -0.01446533203125 +84310 -0.02166748046875 +84311 0.041107177734375 +84312 0.124053955078125 +84313 0.102569580078125 +84314 0.211151123046875 +84315 0.1341552734375 +84316 0.240447998046875 +84317 0.1368408203125 +84318 0.242218017578125 +84319 0.12554931640625 +84320 0.2257080078125 +84321 0.10540771484375 +84322 0.194366455078125 +84323 0.07867431640625 +84324 0.115509033203125 +84325 0.030548095703125 +84326 0.0128173828125 +84327 -0.02716064453125 +84328 -0.053802490234375 +84329 -0.06573486328125 +84330 -0.110626220703125 +84331 -0.09722900390625 +84332 -0.199493408203125 +84333 -0.1412353515625 +84334 -0.29437255859375 +84335 -0.185455322265625 +84336 -0.33221435546875 +84337 -0.2001953125 +84338 -0.27972412109375 +84339 -0.170013427734375 +84340 -0.185333251953125 +84341 -0.118133544921875 +84342 -0.128204345703125 +84343 -0.082366943359375 +84344 -0.115692138671875 +84345 -0.066680908203125 +84346 -0.116455078125 +84347 -0.056854248046875 +84348 -0.105926513671875 +84349 -0.0418701171875 +84350 -0.053955078125 +84351 -0.008056640625 +84352 0.048797607421875 +84353 0.048492431640625 +84354 0.157318115234375 +84355 0.10614013671875 +84356 0.212005615234375 +84357 0.136474609375 +84358 0.218475341796875 +84359 0.14190673828125 +84360 0.23724365234375 +84361 0.150970458984375 +84362 0.30535888671875 +84363 0.18121337890625 +84364 0.38128662109375 +84365 0.213165283203125 +84366 0.404449462890625 +84367 0.218475341796875 +84368 0.3944091796875 +84369 0.206756591796875 +84370 0.3885498046875 +84371 0.196075439453125 +84372 0.362640380859375 +84373 0.175445556640625 +84374 0.27362060546875 +84375 0.12506103515625 +84376 0.11712646484375 +84377 0.043304443359375 +84378 -0.054901123046875 +84379 -0.04486083984375 +84380 -0.19085693359375 +84381 -0.114715576171875 +84382 -0.28570556640625 +84383 -0.16363525390625 +84384 -0.339263916015625 +84385 -0.191375732421875 +84386 -0.3775634765625 +84387 -0.210113525390625 +84388 -0.445709228515625 +84389 -0.24114990234375 +84390 -0.535064697265625 +84391 -0.280548095703125 +84392 -0.629058837890625 +84393 -0.3206787109375 +84394 -0.697601318359375 +84395 -0.34759521484375 +84396 -0.70391845703125 +84397 -0.344268798828125 +84398 -0.6424560546875 +84399 -0.3084716796875 +84400 -0.491241455078125 +84401 -0.230194091796875 +84402 -0.265716552734375 +84403 -0.11712646484375 +84404 -0.023712158203125 +84405 0.0030517578125 +84406 0.201751708984375 +84407 0.114471435546875 +84408 0.375823974609375 +84409 0.200439453125 +84410 0.485076904296875 +84411 0.25445556640625 +84412 0.56884765625 +84413 0.29498291015625 +84414 0.634765625 +84415 0.32562255859375 +84416 0.63763427734375 +84417 0.325103759765625 +84418 0.5660400390625 +84419 0.288177490234375 +84420 0.4720458984375 +84421 0.239593505859375 +84422 0.40692138671875 +84423 0.203826904296875 +84424 0.3778076171875 +84425 0.1845703125 +84426 0.376953125 +84427 0.178466796875 +84428 0.371978759765625 +84429 0.170562744140625 +84430 0.313140869140625 +84431 0.137664794921875 +84432 0.184417724609375 +84433 0.072479248046875 +84434 0.011199951171875 +84435 -0.01275634765625 +84436 -0.171051025390625 +84437 -0.10113525390625 +84438 -0.33740234375 +84439 -0.180816650390625 +84440 -0.47198486328125 +84441 -0.244293212890625 +84442 -0.560394287109375 +84443 -0.2847900390625 +84444 -0.58056640625 +84445 -0.2919921875 +84446 -0.54754638671875 +84447 -0.273162841796875 +84448 -0.508575439453125 +84449 -0.250823974609375 +84450 -0.459503173828125 +84451 -0.223236083984375 +84452 -0.394378662109375 +84453 -0.1878662109375 +84454 -0.35260009765625 +84455 -0.163543701171875 +84456 -0.31170654296875 +84457 -0.139892578125 +84458 -0.197418212890625 +84459 -0.08209228515625 +84460 -0.007965087890625 +84461 0.010467529296875 +84462 0.207489013671875 +84463 0.114410400390625 +84464 0.409210205078125 +84465 0.21087646484375 +84466 0.57208251953125 +84467 0.287994384765625 +84468 0.66595458984375 +84469 0.331573486328125 +84470 0.65875244140625 +84471 0.326507568359375 +84472 0.56744384765625 +84473 0.28094482421875 +84474 0.431396484375 +84475 0.213623046875 +84476 0.29443359375 +84477 0.1453857421875 +84478 0.182464599609375 +84479 0.088714599609375 +84480 0.06365966796875 +84481 0.029266357421875 +84482 -0.075958251953125 +84483 -0.039276123046875 +84484 -0.189422607421875 +84485 -0.095916748046875 +84486 -0.271942138671875 +84487 -0.138092041015625 +84488 -0.342529296875 +84489 -0.173797607421875 +84490 -0.364166259765625 +84491 -0.186553955078125 +84492 -0.327239990234375 +84493 -0.171966552734375 +84494 -0.2769775390625 +84495 -0.149871826171875 +84496 -0.253692626953125 +84497 -0.1380615234375 +84498 -0.24365234375 +84499 -0.130615234375 +84500 -0.1983642578125 +84501 -0.106414794921875 +84502 -0.116241455078125 +84503 -0.065032958984375 +84504 -0.036834716796875 +84505 -0.024169921875 +84506 0.034881591796875 +84507 0.013580322265625 +84508 0.09124755859375 +84509 0.044525146484375 +84510 0.10888671875 +84511 0.05804443359375 +84512 0.125518798828125 +84513 0.070404052734375 +84514 0.15771484375 +84515 0.088623046875 +84516 0.17828369140625 +84517 0.100555419921875 +84518 0.17108154296875 +84519 0.09893798828125 +84520 0.129974365234375 +84521 0.081085205078125 +84522 0.082427978515625 +84523 0.05908203125 +84524 0.027679443359375 +84525 0.03271484375 +84526 -0.065643310546875 +84527 -0.01165771484375 +84528 -0.15936279296875 +84529 -0.057037353515625 +84530 -0.21307373046875 +84531 -0.08538818359375 +84532 -0.234649658203125 +84533 -0.09991455078125 +84534 -0.2001953125 +84535 -0.08978271484375 +84536 -0.119171142578125 +84537 -0.05889892578125 +84538 -0.024749755859375 +84539 -0.021636962890625 +84540 0.085784912109375 +84541 0.023406982421875 +84542 0.178131103515625 +84543 0.061309814453125 +84544 0.215576171875 +84545 0.0760498046875 +84546 0.211456298828125 +84547 0.07354736328125 +84548 0.17523193359375 +84549 0.058013916015625 +84550 0.128753662109375 +84551 0.03900146484375 +84552 0.1019287109375 +84553 0.029571533203125 +84554 0.0743408203125 +84555 0.02056884765625 +84556 0.04327392578125 +84557 0.0106201171875 +84558 0.038177490234375 +84559 0.012451171875 +84560 0.076263427734375 +84561 0.03338623046875 +84562 0.14105224609375 +84563 0.065948486328125 +84564 0.186431884765625 +84565 0.08966064453125 +84566 0.188812255859375 +84567 0.09393310546875 +84568 0.1390380859375 +84569 0.074554443359375 +84570 0.041778564453125 +84571 0.033477783203125 +84572 -0.079437255859375 +84573 -0.01898193359375 +84574 -0.219390869140625 +84575 -0.08056640625 +84576 -0.367828369140625 +84577 -0.146728515625 +84578 -0.494873046875 +84579 -0.204254150390625 +84580 -0.556243896484375 +84581 -0.233551025390625 +84582 -0.508697509765625 +84583 -0.2154541015625 +84584 -0.3756103515625 +84585 -0.16009521484375 +84586 -0.218902587890625 +84587 -0.094512939453125 +84588 -0.063751220703125 +84589 -0.02960205078125 +84590 0.091552734375 +84591 0.0355224609375 +84592 0.23602294921875 +84593 0.096221923828125 +84594 0.342987060546875 +84595 0.140899658203125 +84596 0.39520263671875 +84597 0.162109375 +84598 0.389373779296875 +84599 0.158477783203125 +84600 0.324249267578125 +84601 0.129486083984375 +84602 0.224090576171875 +84603 0.0858154296875 +84604 0.124267578125 +84605 0.042999267578125 +84606 0.037078857421875 +84607 0.00634765625 +84608 -0.010101318359375 +84609 -0.012176513671875 +84610 -0.019439697265625 +84611 -0.013702392578125 +84612 -0.022796630859375 +84613 -0.012359619140625 +84614 -0.001556396484375 +84615 -0.0001220703125 +84616 0.056304931640625 +84617 0.028076171875 +84618 0.106719970703125 +84619 0.052703857421875 +84620 0.096893310546875 +84621 0.050445556640625 +84622 0.042694091796875 +84623 0.028167724609375 +84624 -0.018035888671875 +84625 0.00244140625 +84626 -0.07586669921875 +84627 -0.0225830078125 +84628 -0.11944580078125 +84629 -0.04193115234375 +84630 -0.15972900390625 +84631 -0.060394287109375 +84632 -0.202606201171875 +84633 -0.08050537109375 +84634 -0.24859619140625 +84635 -0.102386474609375 +84636 -0.30517578125 +84637 -0.12921142578125 +84638 -0.36212158203125 +84639 -0.1563720703125 +84640 -0.39141845703125 +84641 -0.171478271484375 +84642 -0.35528564453125 +84643 -0.157745361328125 +84644 -0.249969482421875 +84645 -0.1134033203125 +84646 -0.092864990234375 +84647 -0.0460205078125 +84648 0.08905029296875 +84649 0.0325927734375 +84650 0.2352294921875 +84651 0.095855712890625 +84652 0.318817138671875 +84653 0.13201904296875 +84654 0.358642578125 +84655 0.149383544921875 +84656 0.347747802734375 +84657 0.1448974609375 +84658 0.28564453125 +84659 0.118316650390625 +84660 0.223175048828125 +84661 0.091949462890625 +84662 0.196746826171875 +84663 0.08172607421875 +84664 0.179840087890625 +84665 0.075927734375 +84666 0.155548095703125 +84667 0.0670166015625 +84668 0.151214599609375 +84669 0.06689453125 +84670 0.156951904296875 +84671 0.071136474609375 +84672 0.13177490234375 +84673 0.06158447265625 +84674 0.100799560546875 +84675 0.04925537109375 +84676 0.087127685546875 +84677 0.04425048828125 +84678 0.05487060546875 +84679 0.030731201171875 +84680 -0.009002685546875 +84681 0.002899169921875 +84682 -0.10400390625 +84683 -0.03900146484375 +84684 -0.229400634765625 +84685 -0.094635009765625 +84686 -0.35552978515625 +84687 -0.15087890625 +84688 -0.441925048828125 +84689 -0.18988037109375 +84690 -0.473846435546875 +84691 -0.20513916015625 +84692 -0.464813232421875 +84693 -0.2025146484375 +84694 -0.419097900390625 +84695 -0.18377685546875 +84696 -0.334320068359375 +84697 -0.1478271484375 +84698 -0.227935791015625 +84699 -0.102264404296875 +84700 -0.12347412109375 +84701 -0.057373046875 +84702 -0.02764892578125 +84703 -0.01605224609375 +84704 0.077667236328125 +84705 0.0296630859375 +84706 0.2132568359375 +84707 0.0889892578125 +84708 0.38885498046875 +84709 0.166168212890625 +84710 0.582794189453125 +84711 0.251678466796875 +84712 0.734039306640625 +84713 0.31866455078125 +84714 0.800140380859375 +84715 0.348388671875 +84716 0.7783203125 +84717 0.339599609375 +84718 0.6651611328125 +84719 0.290740966796875 +84720 0.45965576171875 +84721 0.201324462890625 +84722 0.199188232421875 +84723 0.0877685546875 +84724 -0.050689697265625 +84725 -0.021148681640625 +84726 -0.23297119140625 +84727 -0.100372314453125 +84728 -0.33013916015625 +84729 -0.14227294921875 +84730 -0.368408203125 +84731 -0.158416748046875 +84732 -0.378936767578125 +84733 -0.162567138671875 +84734 -0.376983642578125 +84735 -0.161468505859375 +84736 -0.37969970703125 +84737 -0.16259765625 +84738 -0.391510009765625 +84739 -0.167877197265625 +84740 -0.385345458984375 +84741 -0.165985107421875 +84742 -0.3419189453125 +84743 -0.1488037109375 +84744 -0.28289794921875 +84745 -0.124969482421875 +84746 -0.251617431640625 +84747 -0.112030029296875 +84748 -0.266143798828125 +84749 -0.117279052734375 +84750 -0.273345947265625 +84751 -0.119049072265625 +84752 -0.216796875 +84753 -0.0943603515625 +84754 -0.128265380859375 +84755 -0.05621337890625 +84756 -0.068145751953125 +84757 -0.02935791015625 +84758 -0.0430908203125 +84759 -0.01666259765625 +84760 -0.024444580078125 +84761 -0.006591796875 +84762 0.020721435546875 +84763 0.01409912109375 +84764 0.124481201171875 +84765 0.058380126953125 +84766 0.25787353515625 +84767 0.11431884765625 +84768 0.379119873046875 +84769 0.164764404296875 +84770 0.47991943359375 +84771 0.206329345703125 +84772 0.5281982421875 +84773 0.225860595703125 +84774 0.511138916015625 +84775 0.218170166015625 +84776 0.456207275390625 +84777 0.19451904296875 +84778 0.407470703125 +84779 0.173004150390625 +84780 0.383758544921875 +84781 0.161376953125 +84782 0.35687255859375 +84783 0.148223876953125 +84784 0.31182861328125 +84785 0.1275634765625 +84786 0.250885009765625 +84787 0.1004638671875 +84788 0.1654052734375 +84789 0.063507080078125 +84790 0.035247802734375 +84791 0.00860595703125 +84792 -0.142059326171875 +84793 -0.065155029296875 +84794 -0.33563232421875 +84795 -0.14508056640625 +84796 -0.5345458984375 +84797 -0.2266845703125 +84798 -0.72186279296875 +84799 -0.30303955078125 +84800 -0.836669921875 +84801 -0.34930419921875 +84802 -0.8326416015625 +84803 -0.34661865234375 +84804 -0.7296142578125 +84805 -0.303192138671875 +84806 -0.582550048828125 +84807 -0.241546630859375 +84808 -0.440093994140625 +84809 -0.18157958984375 +84810 -0.324310302734375 +84811 -0.132415771484375 +84812 -0.20147705078125 +84813 -0.080413818359375 +84814 -0.044647216796875 +84815 -0.014678955078125 +84816 0.103973388671875 +84817 0.0474853515625 +84818 0.202392578125 +84819 0.088836669921875 +84820 0.264495849609375 +84821 0.114990234375 +84822 0.338897705078125 +84823 0.145751953125 +84824 0.443817138671875 +84825 0.18853759765625 +84826 0.545074462890625 +84827 0.22943115234375 +84828 0.6173095703125 +84829 0.258087158203125 +84830 0.6524658203125 +84831 0.27130126953125 +84832 0.66339111328125 +84833 0.274383544921875 +84834 0.6561279296875 +84835 0.269866943359375 +84836 0.606781005859375 +84837 0.24810791015625 +84838 0.501190185546875 +84839 0.203399658203125 +84840 0.352783203125 +84841 0.141326904296875 +84842 0.176544189453125 +84843 0.068084716796875 +84844 -0.034820556640625 +84845 -0.01922607421875 +84846 -0.258209228515625 +84847 -0.111114501953125 +84848 -0.44244384765625 +84849 -0.1866455078125 +84850 -0.5753173828125 +84851 -0.2408447265625 +84852 -0.65203857421875 +84853 -0.27178955078125 +84854 -0.641632080078125 +84855 -0.266845703125 +84856 -0.562164306640625 +84857 -0.23345947265625 +84858 -0.458038330078125 +84859 -0.1898193359375 +84860 -0.350555419921875 +84861 -0.1446533203125 +84862 -0.260528564453125 +84863 -0.106536865234375 +84864 -0.192108154296875 +84865 -0.0772705078125 +84866 -0.141937255859375 +84867 -0.055511474609375 +84868 -0.1021728515625 +84869 -0.03814697265625 +84870 -0.062896728515625 +84871 -0.02117919921875 +84872 -0.011932373046875 +84873 0.000274658203125 +84874 0.062835693359375 +84875 0.031158447265625 +84876 0.148712158203125 +84877 0.0662841796875 +84878 0.241729736328125 +84879 0.10400390625 +84880 0.34912109375 +84881 0.147308349609375 +84882 0.457305908203125 +84883 0.190673828125 +84884 0.54388427734375 +84885 0.22503662109375 +84886 0.5728759765625 +84887 0.235748291015625 +84888 0.506591796875 +84889 0.20751953125 +84890 0.351226806640625 +84891 0.1429443359375 +84892 0.146514892578125 +84893 0.05828857421875 +84894 -0.05523681640625 +84895 -0.0250244140625 +84896 -0.21624755859375 +84897 -0.091522216796875 +84898 -0.334930419921875 +84899 -0.140533447265625 +84900 -0.402984619140625 +84901 -0.16864013671875 +84902 -0.4412841796875 +84903 -0.184326171875 +84904 -0.49578857421875 +84905 -0.20635986328125 +84906 -0.5601806640625 +84907 -0.232208251953125 +84908 -0.600738525390625 +84909 -0.248138427734375 +84910 -0.584228515625 +84911 -0.240631103515625 +84912 -0.47930908203125 +84913 -0.196929931640625 +84914 -0.27935791015625 +84915 -0.1143798828125 +84916 -0.0089111328125 +84917 -0.0030517578125 +84918 0.268798828125 +84919 0.11114501953125 +84920 0.482818603515625 +84921 0.199249267578125 +84922 0.60369873046875 +84923 0.24920654296875 +84924 0.650421142578125 +84925 0.268707275390625 +84926 0.66400146484375 +84927 0.27447509765625 +84928 0.6414794921875 +84929 0.26531982421875 +84930 0.572540283203125 +84931 0.237030029296875 +84932 0.498138427734375 +84933 0.206329345703125 +84934 0.439453125 +84935 0.181884765625 +84936 0.375518798828125 +84937 0.155181884765625 +84938 0.274505615234375 +84939 0.113250732421875 +84940 0.1087646484375 +84941 0.04486083984375 +84942 -0.099395751953125 +84943 -0.04083251953125 +84944 -0.3182373046875 +84945 -0.130828857421875 +84946 -0.5489501953125 +84947 -0.2255859375 +84948 -0.7738037109375 +84949 -0.31781005859375 +84950 -0.86383056640625 +84951 -0.3858642578125 +84952 -0.870391845703125 +84953 -0.41619873046875 +84954 -0.86895751953125 +84955 -0.416015625 +84956 -0.861053466796875 +84957 -0.39068603515625 +84958 -0.765869140625 +84959 -0.33319091796875 +84960 -0.5301513671875 +84961 -0.23895263671875 +84962 -0.214691162109375 +84963 -0.110870361328125 +84964 0.137359619140625 +84965 0.033416748046875 +84966 0.474822998046875 +84967 0.172943115234375 +84968 0.76239013671875 +84969 0.293182373046875 +84970 0.867462158203125 +84971 0.383087158203125 +84972 0.870361328125 +84973 0.44281005859375 +84974 0.86480712890625 +84975 0.46759033203125 +84976 0.831817626953125 +84977 0.459625244140625 +84978 0.677581787109375 +84979 0.428863525390625 +84980 0.495880126953125 +84981 0.377655029296875 +84982 0.30767822265625 +84983 0.3135986328125 +84984 0.116180419921875 +84985 0.237579345703125 +84986 -0.110748291015625 +84987 0.136688232421875 +84988 -0.381805419921875 +84989 0.00811767578125 +84990 -0.6572265625 +84991 -0.130615234375 +84992 -0.857421875 +84993 -0.25518798828125 +84994 -0.870391845703125 +84995 -0.34820556640625 +84996 -0.870391845703125 +84997 -0.406585693359375 +84998 -0.86444091796875 +84999 -0.440460205078125 +85000 -0.85723876953125 +85001 -0.46337890625 +85002 -0.790008544921875 +85003 -0.46868896484375 +85004 -0.62847900390625 +85005 -0.436279296875 +85006 -0.3956298828125 +85007 -0.36529541015625 +85008 -0.126708984375 +85009 -0.26849365234375 +85010 0.150115966796875 +85011 -0.1566162109375 +85012 0.424041748046875 +85013 -0.03448486328125 +85014 0.670623779296875 +85015 0.0872802734375 +85016 0.854522705078125 +85017 0.193695068359375 +85018 0.866485595703125 +85019 0.27777099609375 +85020 0.86920166015625 +85021 0.333404541015625 +85022 0.8653564453125 +85023 0.3671875 +85024 0.857147216796875 +85025 0.384033203125 +85026 0.766845703125 +85027 0.38275146484375 +85028 0.628509521484375 +85029 0.36529541015625 +85030 0.462127685546875 +85031 0.3292236328125 +85032 0.297210693359375 +85033 0.284454345703125 +85034 0.14862060546875 +85035 0.23590087890625 +85036 -0.00537109375 +85037 0.175262451171875 +85038 -0.15753173828125 +85039 0.105712890625 +85040 -0.31304931640625 +85041 0.0262451171875 +85042 -0.48876953125 +85043 -0.068023681640625 +85044 -0.6416015625 +85045 -0.159149169921875 +85046 -0.751373291015625 +85047 -0.237548828125 +85048 -0.84619140625 +85049 -0.31170654296875 +85050 -0.861297607421875 +85051 -0.37591552734375 +85052 -0.863250732421875 +85053 -0.417633056640625 +85054 -0.856597900390625 +85055 -0.424957275390625 +85056 -0.7498779296875 +85057 -0.40252685546875 +85058 -0.624542236328125 +85059 -0.372222900390625 +85060 -0.47808837890625 +85061 -0.325958251953125 +85062 -0.253387451171875 +85063 -0.242034912109375 +85064 0.003692626953125 +85065 -0.137908935546875 +85066 0.2257080078125 +85067 -0.03955078125 +85068 0.427154541015625 +85069 0.05743408203125 +85070 0.643218994140625 +85071 0.164947509765625 +85072 0.855926513671875 +85073 0.279083251953125 +85074 0.870361328125 +85075 0.377838134765625 +85076 0.870361328125 +85077 0.4423828125 +85078 0.862762451171875 +85079 0.475311279296875 +85080 0.79669189453125 +85081 0.475494384765625 +85082 0.595794677734375 +85083 0.43939208984375 +85084 0.362152099609375 +85085 0.37811279296875 +85086 0.1270751953125 +85087 0.302337646484375 +85088 -0.086944580078125 +85089 0.220245361328125 +85090 -0.2784423828125 +85091 0.13287353515625 +85092 -0.484832763671875 +85093 0.027374267578125 +85094 -0.729583740234375 +85095 -0.103179931640625 +85096 -0.86688232421875 +85097 -0.239471435546875 +85098 -0.870391845703125 +85099 -0.357421875 +85100 -0.86859130859375 +85101 -0.4549560546875 +85102 -0.86279296875 +85103 -0.531158447265625 +85104 -0.817962646484375 +85105 -0.572357177734375 +85106 -0.6116943359375 +85107 -0.5614013671875 +85108 -0.3128662109375 +85109 -0.49566650390625 +85110 0.039398193359375 +85111 -0.38787841796875 +85112 0.422821044921875 +85113 -0.245697021484375 +85114 0.805145263671875 +85115 -0.081817626953125 +85116 0.870361328125 +85117 0.077911376953125 +85118 0.870361328125 +85119 0.2117919921875 +85120 0.860015869140625 +85121 0.315185546875 +85122 0.727935791015625 +85123 0.3848876953125 +85124 0.48114013671875 +85125 0.418487548828125 +85126 0.2059326171875 +85127 0.4248046875 +85128 -0.06103515625 +85129 0.412109375 +85130 -0.29913330078125 +85131 0.384033203125 +85132 -0.516204833984375 +85133 0.33502197265625 +85134 -0.7252197265625 +85135 0.25927734375 +85136 -0.85980224609375 +85137 0.16619873046875 +85138 -0.870391845703125 +85139 0.068878173828125 +85140 -0.870391845703125 +85141 -0.021331787109375 +85142 -0.858062744140625 +85143 -0.085845947265625 +85144 -0.673004150390625 +85145 -0.122711181640625 +85146 -0.42694091796875 +85147 -0.15130615234375 +85148 -0.2100830078125 +85149 -0.18792724609375 +85150 -0.0362548828125 +85151 -0.23138427734375 +85152 0.10943603515625 +85153 -0.2703857421875 +85154 0.23516845703125 +85155 -0.29718017578125 +85156 0.373687744140625 +85157 -0.29595947265625 +85158 0.517791748046875 +85159 -0.267364501953125 +85160 0.602783203125 +85161 -0.23504638671875 +85162 0.635711669921875 +85163 -0.197113037109375 +85164 0.655181884765625 +85165 -0.14117431640625 +85166 0.65948486328125 +85167 -0.071197509765625 +85168 0.651275634765625 +85169 0.009490966796875 +85170 0.61846923828125 +85171 0.091339111328125 +85172 0.53753662109375 +85173 0.160064697265625 +85174 0.404144287109375 +85175 0.208465576171875 +85176 0.22186279296875 +85177 0.232574462890625 +85178 0.003997802734375 +85179 0.232513427734375 +85180 -0.22100830078125 +85181 0.214813232421875 +85182 -0.42449951171875 +85183 0.187042236328125 +85184 -0.579833984375 +85185 0.157073974609375 +85186 -0.641876220703125 +85187 0.140899658203125 +85188 -0.6177978515625 +85189 0.13604736328125 +85190 -0.575531005859375 +85191 0.11834716796875 +85192 -0.526336669921875 +85193 0.085968017578125 +85194 -0.42645263671875 +85195 0.058624267578125 +85196 -0.2581787109375 +85197 0.046905517578125 +85198 -0.068695068359375 +85199 0.037445068359375 +85200 0.09222412109375 +85201 0.01611328125 +85202 0.232147216796875 +85203 -0.009735107421875 +85204 0.3509521484375 +85205 -0.03594970703125 +85206 0.410064697265625 +85207 -0.073394775390625 +85208 0.372955322265625 +85209 -0.132843017578125 +85210 0.2554931640625 +85211 -0.206268310546875 +85212 0.10711669921875 +85213 -0.273956298828125 +85214 -0.052886962890625 +85215 -0.3284912109375 +85216 -0.186279296875 +85217 -0.3563232421875 +85218 -0.23291015625 +85219 -0.3365478515625 +85220 -0.209442138671875 +85221 -0.277862548828125 +85222 -0.174163818359375 +85223 -0.205291748046875 +85224 -0.126739501953125 +85225 -0.122222900390625 +85226 -0.048126220703125 +85227 -0.025238037109375 +85228 0.0426025390625 +85229 0.07476806640625 +85230 0.10748291015625 +85231 0.15997314453125 +85232 0.1409912109375 +85233 0.22509765625 +85234 0.19708251953125 +85235 0.287811279296875 +85236 0.273651123046875 +85237 0.345367431640625 +85238 0.31768798828125 +85239 0.376617431640625 +85240 0.341094970703125 +85241 0.38568115234375 +85242 0.368011474609375 +85243 0.38201904296875 +85244 0.37249755859375 +85245 0.3570556640625 +85246 0.30072021484375 +85247 0.2923583984375 +85248 0.1517333984375 +85249 0.18975830078125 +85250 -0.01470947265625 +85251 0.074371337890625 +85252 -0.1883544921875 +85253 -0.046051025390625 +85254 -0.372711181640625 +85255 -0.169342041015625 +85256 -0.51397705078125 +85257 -0.2734375 +85258 -0.57177734375 +85259 -0.341339111328125 +85260 -0.53948974609375 +85261 -0.368377685546875 +85262 -0.43511962890625 +85263 -0.359039306640625 +85264 -0.2962646484375 +85265 -0.325347900390625 +85266 -0.161102294921875 +85267 -0.2802734375 +85268 -0.0435791015625 +85269 -0.228973388671875 +85270 0.060394287109375 +85271 -0.17095947265625 +85272 0.13665771484375 +85273 -0.112701416015625 +85274 0.170135498046875 +85275 -0.0615234375 +85276 0.16552734375 +85277 -0.018157958984375 +85278 0.15728759765625 +85279 0.02679443359375 +85280 0.150787353515625 +85281 0.072509765625 +85282 0.12200927734375 +85283 0.10797119140625 +85284 0.080108642578125 +85285 0.13397216796875 +85286 0.05126953125 +85287 0.1575927734375 +85288 0.062896728515625 +85289 0.186767578125 +85290 0.09271240234375 +85291 0.212615966796875 +85292 0.092987060546875 +85293 0.217864990234375 +85294 0.07855224609375 +85295 0.20770263671875 +85296 0.06427001953125 +85297 0.187896728515625 +85298 0.0347900390625 +85299 0.1541748046875 +85300 -0.01171875 +85301 0.107421875 +85302 -0.056060791015625 +85303 0.05621337890625 +85304 -0.055511474609375 +85305 0.017578125 +85306 -0.010467529296875 +85307 -0.006378173828125 +85308 0.02508544921875 +85309 -0.032318115234375 +85310 0.025665283203125 +85311 -0.067108154296875 +85312 0.017333984375 +85313 -0.099822998046875 +85314 0.00189208984375 +85315 -0.128387451171875 +85316 -0.03173828125 +85317 -0.155609130859375 +85318 -0.071502685546875 +85319 -0.176666259765625 +85320 -0.13543701171875 +85321 -0.19769287109375 +85322 -0.219970703125 +85323 -0.217742919921875 +85324 -0.300506591796875 +85325 -0.22894287109375 +85326 -0.376312255859375 +85327 -0.232208251953125 +85328 -0.416107177734375 +85329 -0.218048095703125 +85330 -0.371124267578125 +85331 -0.171051025390625 +85332 -0.242279052734375 +85333 -0.09332275390625 +85334 -0.069732666015625 +85335 -0.000762939453125 +85336 0.125640869140625 +85337 0.097564697265625 +85338 0.31268310546875 +85339 0.189178466796875 +85340 0.45501708984375 +85341 0.260009765625 +85342 0.554779052734375 +85343 0.309814453125 +85344 0.61065673828125 +85345 0.3375244140625 +85346 0.610931396484375 +85347 0.33880615234375 +85348 0.531463623046875 +85349 0.305328369140625 +85350 0.3883056640625 +85351 0.24322509765625 +85352 0.23468017578125 +85353 0.17193603515625 +85354 0.095245361328125 +85355 0.10125732421875 +85356 -0.00396728515625 +85357 0.041595458984375 +85358 -0.04852294921875 +85359 -0.00054931640625 +85360 -0.055145263671875 +85361 -0.029541015625 +85362 -0.0758056640625 +85363 -0.062103271484375 +85364 -0.138702392578125 +85365 -0.106781005859375 +85366 -0.209197998046875 +85367 -0.1502685546875 +85368 -0.289031982421875 +85369 -0.1922607421875 +85370 -0.37884521484375 +85371 -0.23236083984375 +85372 -0.456329345703125 +85373 -0.262451171875 +85374 -0.51641845703125 +85375 -0.28076171875 +85376 -0.519287109375 +85377 -0.27362060546875 +85378 -0.458251953125 +85379 -0.23931884765625 +85380 -0.384796142578125 +85381 -0.19671630859375 +85382 -0.323699951171875 +85383 -0.155517578125 +85384 -0.269287109375 +85385 -0.114898681640625 +85386 -0.1951904296875 +85387 -0.06683349609375 +85388 -0.100006103515625 +85389 -0.0120849609375 +85390 -0.01055908203125 +85391 0.038787841796875 +85392 0.1033935546875 +85393 0.0953369140625 +85394 0.24908447265625 +85395 0.1593017578125 +85396 0.373199462890625 +85397 0.21142578125 +85398 0.45806884765625 +85399 0.245147705078125 +85400 0.511474609375 +85401 0.26312255859375 +85402 0.565399169921875 +85403 0.276702880859375 +85404 0.61138916015625 +85405 0.283355712890625 +85406 0.5897216796875 +85407 0.2628173828125 +85408 0.4906005859375 +85409 0.212432861328125 +85410 0.33148193359375 +85411 0.1392822265625 +85412 0.147796630859375 +85413 0.0567626953125 +85414 -0.01873779296875 +85415 -0.01947021484375 +85416 -0.140289306640625 +85417 -0.078704833984375 +85418 -0.191986083984375 +85419 -0.11138916015625 +85420 -0.184295654296875 +85421 -0.120452880859375 +85422 -0.161834716796875 +85423 -0.120941162109375 +85424 -0.166595458984375 +85425 -0.127197265625 +85426 -0.19390869140625 +85427 -0.137420654296875 +85428 -0.22442626953125 +85429 -0.144927978515625 +85430 -0.279754638671875 +85431 -0.157562255859375 +85432 -0.3389892578125 +85433 -0.168487548828125 +85434 -0.3543701171875 +85435 -0.16162109375 +85436 -0.348175048828125 +85437 -0.145477294921875 +85438 -0.32598876953125 +85439 -0.122833251953125 +85440 -0.2581787109375 +85441 -0.08416748046875 +85442 -0.139801025390625 +85443 -0.028564453125 +85444 0.014617919921875 +85445 0.03814697265625 +85446 0.144378662109375 +85447 0.094024658203125 +85448 0.221038818359375 +85449 0.128631591796875 +85450 0.27069091796875 +85451 0.1507568359375 +85452 0.294036865234375 +85453 0.160491943359375 +85454 0.311767578125 +85455 0.16510009765625 +85456 0.339141845703125 +85457 0.170074462890625 +85458 0.360260009765625 +85459 0.17010498046875 +85460 0.360504150390625 +85461 0.16058349609375 +85462 0.308380126953125 +85463 0.13128662109375 +85464 0.18170166015625 +85465 0.07525634765625 +85466 0.0047607421875 +85467 0.001617431640625 +85468 -0.17559814453125 +85469 -0.07281494140625 +85470 -0.3143310546875 +85471 -0.13189697265625 +85472 -0.36785888671875 +85473 -0.1600341796875 +85474 -0.36248779296875 +85475 -0.165802001953125 +85476 -0.343536376953125 +85477 -0.164398193359375 +85478 -0.3018798828125 +85479 -0.152496337890625 +85480 -0.231414794921875 +85481 -0.1279296875 +85482 -0.117645263671875 +85483 -0.0858154296875 +85484 0.007049560546875 +85485 -0.037567138671875 +85486 0.087982177734375 +85487 -0.002288818359375 +85488 0.13946533203125 +85489 0.0244140625 +85490 0.17425537109375 +85491 0.046417236328125 +85492 0.188201904296875 +85493 0.06170654296875 +85494 0.171234130859375 +85495 0.06622314453125 +85496 0.118438720703125 +85497 0.057708740234375 +85498 0.05706787109375 +85499 0.045074462890625 +85500 -0.010711669921875 +85501 0.028594970703125 +85502 -0.0914306640625 +85503 0.005706787109375 +85504 -0.162322998046875 +85505 -0.0155029296875 +85506 -0.194549560546875 +85507 -0.025421142578125 +85508 -0.1492919921875 +85509 -0.012176513671875 +85510 -0.02166748046875 +85511 0.025482177734375 +85512 0.124053955078125 +85513 0.0673828125 +85514 0.211151123046875 +85515 0.089630126953125 +85516 0.240447998046875 +85517 0.0926513671875 +85518 0.242218017578125 +85519 0.086181640625 +85520 0.2257080078125 +85521 0.073516845703125 +85522 0.194366455078125 +85523 0.056121826171875 +85524 0.115509033203125 +85525 0.024200439453125 +85526 0.0128173828125 +85527 -0.014404296875 +85528 -0.053802490234375 +85529 -0.0406494140625 +85530 -0.110626220703125 +85531 -0.06243896484375 +85532 -0.199493408203125 +85533 -0.0926513671875 +85534 -0.29437255859375 +85535 -0.123046875 +85536 -0.33221435546875 +85537 -0.133941650390625 +85538 -0.27972412109375 +85539 -0.11505126953125 +85540 -0.185333251953125 +85541 -0.0816650390625 +85542 -0.128204345703125 +85543 -0.058685302734375 +85544 -0.115692138671875 +85545 -0.0487060546875 +85546 -0.116455078125 +85547 -0.042327880859375 +85548 -0.105926513671875 +85549 -0.032257080078125 +85550 -0.053955078125 +85551 -0.00946044921875 +85552 0.048797607421875 +85553 0.028564453125 +85554 0.157318115234375 +85555 0.0675048828125 +85556 0.212005615234375 +85557 0.0885009765625 +85558 0.218475341796875 +85559 0.0931396484375 +85560 0.23724365234375 +85561 0.100189208984375 +85562 0.30535888671875 +85563 0.121185302734375 +85564 0.38128662109375 +85565 0.1431884765625 +85566 0.404449462890625 +85567 0.147430419921875 +85568 0.3944091796875 +85569 0.140228271484375 +85570 0.3885498046875 +85571 0.133514404296875 +85572 0.362640380859375 +85573 0.120025634765625 +85574 0.27362060546875 +85575 0.08660888671875 +85576 0.11712646484375 +85577 0.032257080078125 +85578 -0.054901123046875 +85579 -0.0264892578125 +85580 -0.19085693359375 +85581 -0.07330322265625 +85582 -0.28570556640625 +85583 -0.10638427734375 +85584 -0.339263916015625 +85585 -0.12554931640625 +85586 -0.3775634765625 +85587 -0.138763427734375 +85588 -0.445709228515625 +85589 -0.16009521484375 +85590 -0.535064697265625 +85591 -0.1868896484375 +85592 -0.629058837890625 +85593 -0.21405029296875 +85594 -0.697601318359375 +85595 -0.232330322265625 +85596 -0.70391845703125 +85597 -0.230438232421875 +85598 -0.6424560546875 +85599 -0.2069091796875 +85600 -0.491241455078125 +85601 -0.155120849609375 +85602 -0.265716552734375 +85603 -0.08013916015625 +85604 -0.023712158203125 +85605 -0.000274658203125 +85606 0.201751708984375 +85607 0.073883056640625 +85608 0.375823974609375 +85609 0.13128662109375 +85610 0.485076904296875 +85611 0.1676025390625 +85612 0.56884765625 +85613 0.19500732421875 +85614 0.634765625 +85615 0.215850830078125 +85616 0.63763427734375 +85617 0.216064453125 +85618 0.5660400390625 +85619 0.192138671875 +85620 0.4720458984375 +85621 0.160430908203125 +85622 0.40692138671875 +85623 0.137054443359375 +85624 0.3778076171875 +85625 0.12445068359375 +85626 0.376953125 +85627 0.12042236328125 +85628 0.371978759765625 +85629 0.11505126953125 +85630 0.313140869140625 +85631 0.093048095703125 +85632 0.184417724609375 +85633 0.049591064453125 +85634 0.011199951171875 +85635 -0.007171630859375 +85636 -0.171051025390625 +85637 -0.066070556640625 +85638 -0.33740234375 +85639 -0.119232177734375 +85640 -0.47198486328125 +85641 -0.161651611328125 +85642 -0.560394287109375 +85643 -0.1888427734375 +85644 -0.58056640625 +85645 -0.1939697265625 +85646 -0.54754638671875 +85647 -0.18182373046875 +85648 -0.508575439453125 +85649 -0.167266845703125 +85650 -0.459503173828125 +85651 -0.149139404296875 +85652 -0.394378662109375 +85653 -0.125732421875 +85654 -0.35260009765625 +85655 -0.109527587890625 +85656 -0.31170654296875 +85657 -0.09368896484375 +85658 -0.197418212890625 +85659 -0.055206298828125 +85660 -0.007965087890625 +85661 0.00628662109375 +85662 0.207489013671875 +85663 0.075347900390625 +85664 0.409210205078125 +85665 0.13946533203125 +85666 0.57208251953125 +85667 0.190765380859375 +85668 0.66595458984375 +85669 0.2198486328125 +85670 0.65875244140625 +85671 0.21673583984375 +85672 0.56744384765625 +85673 0.186798095703125 +85674 0.431396484375 +85675 0.142425537109375 +85676 0.29443359375 +85677 0.097412109375 +85678 0.182464599609375 +85679 0.0599365234375 +85680 0.06365966796875 +85681 0.020233154296875 +85682 -0.075958251953125 +85683 -0.025909423828125 +85684 -0.189422607421875 +85685 -0.063690185546875 +85686 -0.271942138671875 +85687 -0.091461181640625 +85688 -0.342529296875 +85689 -0.11505126953125 +85690 -0.364166259765625 +85691 -0.122894287109375 +85692 -0.327239990234375 +85693 -0.111907958984375 +85694 -0.2769775390625 +85695 -0.09619140625 +85696 -0.253692626953125 +85697 -0.088348388671875 +85698 -0.24365234375 +85699 -0.0841064453125 +85700 -0.1983642578125 +85701 -0.06842041015625 +85702 -0.116241455078125 +85703 -0.040924072265625 +85704 -0.036834716796875 +85705 -0.014068603515625 +85706 0.034881591796875 +85707 0.010467529296875 +85708 0.09124755859375 +85709 0.0301513671875 +85710 0.10888671875 +85711 0.03759765625 +85712 0.125518798828125 +85713 0.044464111328125 +85714 0.15771484375 +85715 0.05584716796875 +85716 0.17828369140625 +85717 0.063201904296875 +85718 0.17108154296875 +85719 0.061431884765625 +85720 0.129974365234375 +85721 0.04864501953125 +85722 0.082427978515625 +85723 0.03338623046875 +85724 0.027679443359375 +85725 0.0155029296875 +85726 -0.065643310546875 +85727 -0.01470947265625 +85728 -0.15936279296875 +85729 -0.0452880859375 +85730 -0.21307373046875 +85731 -0.063568115234375 +85732 -0.234649658203125 +85733 -0.071929931640625 +85734 -0.2001953125 +85735 -0.06280517578125 +85736 -0.119171142578125 +85737 -0.0390625 +85738 -0.024749755859375 +85739 -0.010986328125 +85740 0.085784912109375 +85741 0.0223388671875 +85742 0.178131103515625 +85743 0.05023193359375 +85744 0.215576171875 +85745 0.061309814453125 +85746 0.211456298828125 +85747 0.059783935546875 +85748 0.17523193359375 +85749 0.048614501953125 +85750 0.128753662109375 +85751 0.034576416015625 +85752 0.1019287109375 +85753 0.0269775390625 +85754 0.0743408203125 +85755 0.019378662109375 +85756 0.04327392578125 +85757 0.010894775390625 +85758 0.038177490234375 +85759 0.010589599609375 +85760 0.076263427734375 +85761 0.02325439453125 +85762 0.14105224609375 +85763 0.043182373046875 +85764 0.186431884765625 +85765 0.05682373046875 +85766 0.188812255859375 +85767 0.05767822265625 +85768 0.1390380859375 +85769 0.0433349609375 +85770 0.041778564453125 +85771 0.0152587890625 +85772 -0.079437255859375 +85773 -0.019775390625 +85774 -0.219390869140625 +85775 -0.060211181640625 +85776 -0.367828369140625 +85777 -0.10302734375 +85778 -0.494873046875 +85779 -0.1397705078125 +85780 -0.556243896484375 +85781 -0.157989501953125 +85782 -0.508697509765625 +85783 -0.1455078125 +85784 -0.3756103515625 +85785 -0.10882568359375 +85786 -0.218902587890625 +85787 -0.06524658203125 +85788 -0.063751220703125 +85789 -0.021820068359375 +85790 0.091552734375 +85791 0.021881103515625 +85792 0.23602294921875 +85793 0.062744140625 +85794 0.342987060546875 +85795 0.093292236328125 +85796 0.39520263671875 +85797 0.108642578125 +85798 0.389373779296875 +85799 0.10784912109375 +85800 0.324249267578125 +85801 0.09051513671875 +85802 0.224090576171875 +85803 0.063385009765625 +85804 0.124267578125 +85805 0.03631591796875 +85806 0.037078857421875 +85807 0.012664794921875 +85808 -0.010101318359375 +85809 6.103515625e-05 +85810 -0.019439697265625 +85811 -0.002105712890625 +85812 -0.022796630859375 +85813 -0.00274658203125 +85814 -0.001556396484375 +85815 0.003265380859375 +85816 0.056304931640625 +85817 0.019287109375 +85818 0.106719970703125 +85819 0.03302001953125 +85820 0.096893310546875 +85821 0.02972412109375 +85822 0.042694091796875 +85823 0.01385498046875 +85824 -0.018035888671875 +85825 -0.00390625 +85826 -0.07586669921875 +85827 -0.0208740234375 +85828 -0.11944580078125 +85829 -0.0338134765625 +85830 -0.15972900390625 +85831 -0.045745849609375 +85832 -0.202606201171875 +85833 -0.058319091796875 +85834 -0.24859619140625 +85835 -0.071624755859375 +85836 -0.30517578125 +85837 -0.087738037109375 +85838 -0.36212158203125 +85839 -0.103790283203125 +85840 -0.39141845703125 +85841 -0.1119384765625 +85842 -0.35528564453125 +85843 -0.10162353515625 +85844 -0.249969482421875 +85845 -0.071807861328125 +85846 -0.092864990234375 +85847 -0.02740478515625 +85848 0.08905029296875 +85849 0.024017333984375 +85850 0.2352294921875 +85851 0.065460205078125 +85852 0.318817138671875 +85853 0.089385986328125 +85854 0.358642578125 +85855 0.10101318359375 +85856 0.347747802734375 +85857 0.098388671875 +85858 0.28564453125 +85859 0.08135986328125 +85860 0.223175048828125 +85861 0.064117431640625 +85862 0.196746826171875 +85863 0.056884765625 +85864 0.179840087890625 +85865 0.052215576171875 +85866 0.155548095703125 +85867 0.045379638671875 +85868 0.151214599609375 +85869 0.044036865234375 +85870 0.156951904296875 +85871 0.045440673828125 +85872 0.13177490234375 +85873 0.0380859375 +85874 0.100799560546875 +85875 0.029052734375 +85876 0.087127685546875 +85877 0.024810791015625 +85878 0.05487060546875 +85879 0.015350341796875 +85880 -0.009002685546875 +85881 -0.0029296875 +85882 -0.10400390625 +85883 -0.029876708984375 +85884 -0.229400634765625 +85885 -0.065277099609375 +85886 -0.35552978515625 +85887 -0.100799560546875 +85888 -0.441925048828125 +85889 -0.125091552734375 +85890 -0.473846435546875 +85891 -0.134033203125 +85892 -0.464813232421875 +85893 -0.13140869140625 +85894 -0.419097900390625 +85895 -0.118438720703125 +85896 -0.334320068359375 +85897 -0.094451904296875 +85898 -0.227935791015625 +85899 -0.0643310546875 +85900 -0.12347412109375 +85901 -0.034698486328125 +85902 -0.02764892578125 +85903 -0.007476806640625 +85904 0.077667236328125 +85905 0.022369384765625 +85906 0.2132568359375 +85907 0.060638427734375 +85908 0.38885498046875 +85909 0.11004638671875 +85910 0.582794189453125 +85911 0.164520263671875 +85912 0.734039306640625 +85913 0.206939697265625 +85914 0.800140380859375 +85915 0.22540283203125 +85916 0.7783203125 +85917 0.219146728515625 +85918 0.6651611328125 +85919 0.187286376953125 +85920 0.45965576171875 +85921 0.129547119140625 +85922 0.199188232421875 +85923 0.056365966796875 +85924 -0.050689697265625 +85925 -0.013824462890625 +85926 -0.23297119140625 +85927 -0.0650634765625 +85928 -0.33013916015625 +85929 -0.092437744140625 +85930 -0.368408203125 +85931 -0.103302001953125 +85932 -0.378936767578125 +85933 -0.106353759765625 +85934 -0.376983642578125 +85935 -0.10589599609375 +85936 -0.37969970703125 +85937 -0.10675048828125 +85938 -0.391510009765625 +85939 -0.110107421875 +85940 -0.385345458984375 +85941 -0.1083984375 +85942 -0.3419189453125 +85943 -0.09619140625 +85944 -0.28289794921875 +85945 -0.079559326171875 +85946 -0.251617431640625 +85947 -0.0706787109375 +85948 -0.266143798828125 +85949 -0.0745849609375 +85950 -0.273345947265625 +85951 -0.076416015625 +85952 -0.216796875 +85953 -0.060394287109375 +85954 -0.128265380859375 +85955 -0.035400390625 +85956 -0.068145751953125 +85957 -0.01837158203125 +85958 -0.0430908203125 +85959 -0.011138916015625 +85960 -0.024444580078125 +85961 -0.0057373046875 +85962 0.020721435546875 +85963 0.00701904296875 +85964 0.124481201171875 +85965 0.036102294921875 +85966 0.25787353515625 +85967 0.07342529296875 +85968 0.379119873046875 +85969 0.107269287109375 +85970 0.47991943359375 +85971 0.135345458984375 +85972 0.5281982421875 +85973 0.148651123046875 +85974 0.511138916015625 +85975 0.14361572265625 +85976 0.456207275390625 +85977 0.1279296875 +85978 0.407470703125 +85979 0.113983154296875 +85980 0.383758544921875 +85981 0.107025146484375 +85982 0.35687255859375 +85983 0.099212646484375 +85984 0.31182861328125 +85985 0.08636474609375 +85986 0.250885009765625 +85987 0.069122314453125 +85988 0.1654052734375 +85989 0.045074462890625 +85990 0.035247802734375 +85991 0.008575439453125 +85992 -0.142059326171875 +85993 -0.041046142578125 +85994 -0.33563232421875 +85995 -0.095123291015625 +85996 -0.5345458984375 +85997 -0.150604248046875 +85998 -0.72186279296875 +85999 -0.202789306640625 +86000 -0.836669921875 +86001 -0.234588623046875 +86002 -0.8326416015625 +86003 -0.23309326171875 +86004 -0.7296142578125 +86005 -0.203857421875 +86006 -0.582550048828125 +86007 -0.16229248046875 +86008 -0.440093994140625 +86009 -0.1220703125 +86010 -0.324310302734375 +86011 -0.089385986328125 +86012 -0.20147705078125 +86013 -0.054779052734375 +86014 -0.044647216796875 +86015 -0.010711669921875 +86016 0.103973388671875 +86017 0.03155517578125 +86018 0.202392578125 +86019 0.060882568359375 +86020 0.264495849609375 +86021 0.08050537109375 +86022 0.338897705078125 +86023 0.10223388671875 +86024 0.443817138671875 +86025 0.13043212890625 +86026 0.545074462890625 +86027 0.156524658203125 +86028 0.6173095703125 +86029 0.1741943359375 +86030 0.6524658203125 +86031 0.1815185546875 +86032 0.66339111328125 +86033 0.1817626953125 +86034 0.6561279296875 +86035 0.176605224609375 +86036 0.606781005859375 +86037 0.160308837890625 +86038 0.501190185546875 +86039 0.129638671875 +86040 0.352783203125 +86041 0.088165283203125 +86042 0.176544189453125 +86043 0.039886474609375 +86044 -0.034820556640625 +86045 -0.0167236328125 +86046 -0.258209228515625 +86047 -0.07568359375 +86048 -0.44244384765625 +86049 -0.124176025390625 +86050 -0.5753173828125 +86051 -0.159027099609375 +86052 -0.65203857421875 +86053 -0.178985595703125 +86054 -0.641632080078125 +86055 -0.176361083984375 +86056 -0.562164306640625 +86057 -0.155670166015625 +86058 -0.458038330078125 +86059 -0.128021240234375 +86060 -0.350555419921875 +86061 -0.098785400390625 +86062 -0.260528564453125 +86063 -0.073272705078125 +86064 -0.192108154296875 +86065 -0.052703857421875 +86066 -0.141937255859375 +86067 -0.036468505859375 +86068 -0.1021728515625 +86069 -0.0228271484375 +86070 -0.062896728515625 +86071 -0.009521484375 +86072 -0.011932373046875 +86073 0.006256103515625 +86074 0.062835693359375 +86075 0.02734375 +86076 0.148712158203125 +86077 0.05047607421875 +86078 0.241729736328125 +86079 0.0745849609375 +86080 0.34912109375 +86081 0.101409912109375 +86082 0.457305908203125 +86083 0.12762451171875 +86084 0.54388427734375 +86085 0.147735595703125 +86086 0.5728759765625 +86087 0.15289306640625 +86088 0.506591796875 +86089 0.1339111328125 +86090 0.351226806640625 +86091 0.092437744140625 +86092 0.146514892578125 +86093 0.03851318359375 +86094 -0.05523681640625 +86095 -0.014678955078125 +86096 -0.21624755859375 +86097 -0.057586669921875 +86098 -0.334930419921875 +86099 -0.08966064453125 +86100 -0.402984619140625 +86101 -0.10870361328125 +86102 -0.4412841796875 +86103 -0.119781494140625 +86104 -0.49578857421875 +86105 -0.134246826171875 +86106 -0.5601806640625 +86107 -0.1505126953125 +86108 -0.600738525390625 +86109 -0.160186767578125 +86110 -0.584228515625 +86111 -0.15509033203125 +86112 -0.47930908203125 +86113 -0.12750244140625 +86114 -0.27935791015625 +86115 -0.075897216796875 +86116 -0.0089111328125 +86117 -0.006500244140625 +86118 0.268798828125 +86119 0.064849853515625 +86120 0.482818603515625 +86121 0.12042236328125 +86122 0.60369873046875 +86123 0.152801513671875 +86124 0.650421142578125 +86125 0.166534423828125 +86126 0.66400146484375 +86127 0.17169189453125 +86128 0.6414794921875 +86129 0.167449951171875 +86130 0.572540283203125 +86131 0.151214599609375 +86132 0.498138427734375 +86133 0.13311767578125 +86134 0.439453125 +86135 0.118377685546875 +86136 0.375518798828125 +86137 0.101806640625 +86138 0.274505615234375 +86139 0.075592041015625 +86140 0.1087646484375 +86141 0.032958984375 +86142 -0.099395751953125 +86143 -0.02044677734375 +86144 -0.3182373046875 +86145 -0.076629638671875 +86146 -0.5489501953125 +86147 -0.13580322265625 +86148 -0.7738037109375 +86149 -0.193450927734375 +86150 -0.86383056640625 +86151 -0.236358642578125 +86152 -0.870391845703125 +86153 -0.256195068359375 +86154 -0.86895751953125 +86155 -0.25726318359375 +86156 -0.861053466796875 +86157 -0.242767333984375 +86158 -0.765869140625 +86159 -0.208404541015625 +86160 -0.5301513671875 +86161 -0.1513671875 +86162 -0.214691162109375 +86163 -0.07342529296875 +86164 0.137359619140625 +86165 0.014678955078125 +86166 0.474822998046875 +86167 0.100189208984375 +86168 0.76239013671875 +86169 0.174224853515625 +86170 0.867462158203125 +86171 0.230010986328125 +86172 0.870361328125 +86173 0.267578125 +86174 0.86480712890625 +86175 0.283966064453125 +86176 0.831817626953125 +86177 0.280426025390625 +86178 0.677581787109375 +86179 0.262908935546875 +86180 0.495880126953125 +86181 0.232818603515625 +86182 0.30767822265625 +86183 0.1947021484375 +86184 0.116180419921875 +86185 0.149078369140625 +86186 -0.110748291015625 +86187 0.08807373046875 +86188 -0.381805419921875 +86189 0.00994873046875 +86190 -0.6572265625 +86191 -0.074615478515625 +86192 -0.857421875 +86193 -0.150726318359375 +86194 -0.870391845703125 +86195 -0.207672119140625 +86196 -0.870391845703125 +86197 -0.24365234375 +86198 -0.86444091796875 +86199 -0.265289306640625 +86200 -0.85723876953125 +86201 -0.2813720703125 +86202 -0.790008544921875 +86203 -0.28729248046875 +86204 -0.62847900390625 +86205 -0.26953125 +86206 -0.3956298828125 +86207 -0.227203369140625 +86208 -0.126708984375 +86209 -0.168426513671875 +86210 0.150115966796875 +86211 -0.0999755859375 +86212 0.424041748046875 +86213 -0.024749755859375 +86214 0.670623779296875 +86215 0.050567626953125 +86216 0.854522705078125 +86217 0.116363525390625 +86218 0.866485595703125 +86219 0.168243408203125 +86220 0.86920166015625 +86221 0.202301025390625 +86222 0.8653564453125 +86223 0.2230224609375 +86224 0.857147216796875 +86225 0.233673095703125 +86226 0.766845703125 +86227 0.233489990234375 +86228 0.628509521484375 +86229 0.223663330078125 +86230 0.462127685546875 +86231 0.202484130859375 +86232 0.297210693359375 +86233 0.176300048828125 +86234 0.14862060546875 +86235 0.148101806640625 +86236 -0.00537109375 +86237 0.112213134765625 +86238 -0.15753173828125 +86239 0.070526123046875 +86240 -0.31304931640625 +86241 0.022125244140625 +86242 -0.48876953125 +86243 -0.036407470703125 +86244 -0.6416015625 +86245 -0.09344482421875 +86246 -0.751373291015625 +86247 -0.142791748046875 +86248 -0.84619140625 +86249 -0.190155029296875 +86250 -0.861297607421875 +86251 -0.2318115234375 +86252 -0.863250732421875 +86253 -0.259521484375 +86254 -0.856597900390625 +86255 -0.265380859375 +86256 -0.7498779296875 +86257 -0.25238037109375 +86258 -0.624542236328125 +86259 -0.234832763671875 +86260 -0.47808837890625 +86261 -0.207275390625 +86262 -0.253387451171875 +86263 -0.15521240234375 +86264 0.003692626953125 +86265 -0.0899658203125 +86266 0.2257080078125 +86267 -0.028472900390625 +86268 0.427154541015625 +86269 0.032318115234375 +86270 0.643218994140625 +86271 0.100433349609375 +86272 0.855926513671875 +86273 0.1729736328125 +86274 0.870361328125 +86275 0.2354736328125 +86276 0.870361328125 +86277 0.27630615234375 +86278 0.862762451171875 +86279 0.29705810546875 +86280 0.79669189453125 +86281 0.29718017578125 +86282 0.595794677734375 +86283 0.274871826171875 +86284 0.362152099609375 +86285 0.23675537109375 +86286 0.1270751953125 +86287 0.18927001953125 +86288 -0.086944580078125 +86289 0.13739013671875 +86290 -0.2784423828125 +86291 0.082061767578125 +86292 -0.484832763671875 +86293 0.0162353515625 +86294 -0.729583740234375 +86295 -0.06378173828125 +86296 -0.86688232421875 +86297 -0.146636962890625 +86298 -0.870391845703125 +86299 -0.21826171875 +86300 -0.86859130859375 +86301 -0.277252197265625 +86302 -0.86279296875 +86303 -0.322967529296875 +86304 -0.817962646484375 +86305 -0.347503662109375 +86306 -0.6116943359375 +86307 -0.34100341796875 +86308 -0.3128662109375 +86309 -0.302001953125 +86310 0.039398193359375 +86311 -0.237884521484375 +86312 0.422821044921875 +86313 -0.153228759765625 +86314 0.805145263671875 +86315 -0.055511474609375 +86316 0.870361328125 +86317 0.0401611328125 +86318 0.870361328125 +86319 0.121124267578125 +86320 0.860015869140625 +86321 0.184478759765625 +86322 0.727935791015625 +86323 0.228179931640625 +86324 0.48114013671875 +86325 0.250640869140625 +86326 0.2059326171875 +86327 0.25677490234375 +86328 -0.06103515625 +86329 0.251220703125 +86330 -0.29913330078125 +86331 0.235992431640625 +86332 -0.516204833984375 +86333 0.207855224609375 +86334 -0.7252197265625 +86335 0.163543701171875 +86336 -0.85980224609375 +86337 0.1085205078125 +86338 -0.870391845703125 +86339 0.0504150390625 +86340 -0.870391845703125 +86341 -0.004119873046875 +86342 -0.858062744140625 +86343 -0.044219970703125 +86344 -0.673004150390625 +86345 -0.068634033203125 +86346 -0.42694091796875 +86347 -0.08831787109375 +86348 -0.2100830078125 +86349 -0.1124267578125 +86350 -0.0362548828125 +86351 -0.14013671875 +86352 0.10943603515625 +86353 -0.164794921875 +86354 0.23516845703125 +86355 -0.181793212890625 +86356 0.373687744140625 +86357 -0.182037353515625 +86358 0.517791748046875 +86359 -0.165863037109375 +86360 0.602783203125 +86361 -0.1468505859375 +86362 0.635711669921875 +86363 -0.12396240234375 +86364 0.655181884765625 +86365 -0.090179443359375 +86366 0.65948486328125 +86367 -0.0478515625 +86368 0.651275634765625 +86369 0.000946044921875 +86370 0.61846923828125 +86371 0.050567626953125 +86372 0.53753662109375 +86373 0.0926513671875 +86374 0.404144287109375 +86375 0.122955322265625 +86376 0.22186279296875 +86377 0.1390380859375 +86378 0.003997802734375 +86379 0.140899658203125 +86380 -0.22100830078125 +86381 0.132171630859375 +86382 -0.42449951171875 +86383 0.117156982421875 +86384 -0.579833984375 +86385 0.100341796875 +86386 -0.641876220703125 +86387 0.090911865234375 +86388 -0.6177978515625 +86389 0.08746337890625 +86390 -0.575531005859375 +86391 0.076141357421875 +86392 -0.526336669921875 +86393 0.055938720703125 +86394 -0.42645263671875 +86395 0.038299560546875 +86396 -0.2581787109375 +86397 0.0294189453125 +86398 -0.068695068359375 +86399 0.021728515625 +86400 0.09222412109375 +86401 0.00726318359375 +86402 0.232147216796875 +86403 -0.009613037109375 +86404 0.3509521484375 +86405 -0.026397705078125 +86406 0.410064697265625 +86407 -0.04925537109375 +86408 0.372955322265625 +86409 -0.084320068359375 +86410 0.2554931640625 +86411 -0.126922607421875 +86412 0.10711669921875 +86413 -0.165740966796875 +86414 -0.052886962890625 +86415 -0.196533203125 +86416 -0.186279296875 +86417 -0.2115478515625 +86418 -0.23291015625 +86419 -0.1988525390625 +86420 -0.209442138671875 +86421 -0.163543701171875 +86422 -0.174163818359375 +86423 -0.120086669921875 +86424 -0.126739501953125 +86425 -0.070526123046875 +86426 -0.048126220703125 +86427 -0.01300048828125 +86428 0.0426025390625 +86429 0.046142578125 +86430 0.10748291015625 +86431 0.0965576171875 +86432 0.1409912109375 +86433 0.1351318359375 +86434 0.19708251953125 +86435 0.171966552734375 +86436 0.273651123046875 +86437 0.2054443359375 +86438 0.31768798828125 +86439 0.223419189453125 +86440 0.341094970703125 +86441 0.228240966796875 +86442 0.368011474609375 +86443 0.22540283203125 +86444 0.37249755859375 +86445 0.209991455078125 +86446 0.30072021484375 +86447 0.171539306640625 +86448 0.1517333984375 +86449 0.11126708984375 +86450 -0.01470947265625 +86451 0.04376220703125 +86452 -0.1883544921875 +86453 -0.02691650390625 +86454 -0.372711181640625 +86455 -0.09967041015625 +86456 -0.51397705078125 +86457 -0.161102294921875 +86458 -0.57177734375 +86459 -0.20086669921875 +86460 -0.53948974609375 +86461 -0.21612548828125 +86462 -0.43511962890625 +86463 -0.209747314453125 +86464 -0.2962646484375 +86465 -0.189117431640625 +86466 -0.161102294921875 +86467 -0.162139892578125 +86468 -0.0435791015625 +86469 -0.131927490234375 +86470 0.060394287109375 +86471 -0.09808349609375 +86472 0.13665771484375 +86473 -0.064453125 +86474 0.170135498046875 +86475 -0.035400390625 +86476 0.16552734375 +86477 -0.011260986328125 +86478 0.15728759765625 +86479 0.013916015625 +86480 0.150787353515625 +86481 0.039794921875 +86482 0.12200927734375 +86483 0.059661865234375 +86484 0.080108642578125 +86485 0.074127197265625 +86486 0.05126953125 +86487 0.087646484375 +86488 0.062896728515625 +86489 0.105194091796875 +86490 0.09271240234375 +86491 0.121246337890625 +86492 0.092987060546875 +86493 0.1251220703125 +86494 0.07855224609375 +86495 0.1199951171875 +86496 0.06427001953125 +86497 0.109344482421875 +86498 0.0347900390625 +86499 0.090423583984375 +86500 -0.01171875 +86501 0.06365966796875 +86502 -0.056060791015625 +86503 0.034210205078125 +86504 -0.055511474609375 +86505 0.012481689453125 +86506 -0.010467529296875 +86507 -0.00030517578125 +86508 0.02508544921875 +86509 -0.01458740234375 +86510 0.025665283203125 +86511 -0.03466796875 +86512 0.017333984375 +86513 -0.053863525390625 +86514 0.00189208984375 +86515 -0.0709228515625 +86516 -0.03173828125 +86517 -0.087615966796875 +86518 -0.071502685546875 +86519 -0.100921630859375 +86520 -0.13543701171875 +86521 -0.1146240234375 +86522 -0.219970703125 +86523 -0.128082275390625 +86524 -0.300506591796875 +86525 -0.1363525390625 +86526 -0.376312255859375 +86527 -0.13995361328125 +86528 -0.416107177734375 +86529 -0.13299560546875 +86530 -0.371124267578125 +86531 -0.106048583984375 +86532 -0.242279052734375 +86533 -0.060333251953125 +86534 -0.069732666015625 +86535 -0.005279541015625 +86536 0.125640869140625 +86537 0.0535888671875 +86538 0.31268310546875 +86539 0.108795166015625 +86540 0.45501708984375 +86541 0.15203857421875 +86542 0.554779052734375 +86543 0.182952880859375 +86544 0.61065673828125 +86545 0.20074462890625 +86546 0.610931396484375 +86547 0.20281982421875 +86548 0.531463623046875 +86549 0.18438720703125 +86550 0.3883056640625 +86551 0.14892578125 +86552 0.23468017578125 +86553 0.107574462890625 +86554 0.095245361328125 +86555 0.0660400390625 +86556 -0.00396728515625 +86557 0.03033447265625 +86558 -0.04852294921875 +86559 0.004241943359375 +86560 -0.055145263671875 +86561 -0.0145263671875 +86562 -0.0758056640625 +86563 -0.035400390625 +86564 -0.138702392578125 +86565 -0.063140869140625 +86566 -0.209197998046875 +86567 -0.09002685546875 +86568 -0.289031982421875 +86569 -0.115753173828125 +86570 -0.37884521484375 +86571 -0.1400146484375 +86572 -0.456329345703125 +86573 -0.1580810546875 +86574 -0.51641845703125 +86575 -0.1689453125 +86576 -0.519287109375 +86577 -0.164794921875 +86578 -0.458251953125 +86579 -0.144622802734375 +86580 -0.384796142578125 +86581 -0.119293212890625 +86582 -0.323699951171875 +86583 -0.09442138671875 +86584 -0.269287109375 +86585 -0.069580078125 +86586 -0.1951904296875 +86587 -0.040283203125 +86588 -0.100006103515625 +86589 -0.007080078125 +86590 -0.01055908203125 +86591 0.02386474609375 +86592 0.1033935546875 +86593 0.057891845703125 +86594 0.24908447265625 +86595 0.095916748046875 +86596 0.373199462890625 +86597 0.126861572265625 +86598 0.45806884765625 +86599 0.14691162109375 +86600 0.511474609375 +86601 0.157562255859375 +86602 0.565399169921875 +86603 0.165313720703125 +86604 0.61138916015625 +86605 0.168701171875 +86606 0.5897216796875 +86607 0.15618896484375 +86608 0.4906005859375 +86609 0.1263427734375 +86610 0.33148193359375 +86611 0.083251953125 +86612 0.147796630859375 +86613 0.03466796875 +86614 -0.01873779296875 +86615 -0.010406494140625 +86616 -0.140289306640625 +86617 -0.045745849609375 +86618 -0.191986083984375 +86619 -0.0657958984375 +86620 -0.184295654296875 +86621 -0.072174072265625 +86622 -0.161834716796875 +86623 -0.07342529296875 +86624 -0.166595458984375 +86625 -0.07769775390625 +86626 -0.19390869140625 +86627 -0.08392333984375 +86628 -0.22442626953125 +86629 -0.0882568359375 +86630 -0.279754638671875 +86631 -0.09521484375 +86632 -0.3389892578125 +86633 -0.10089111328125 +86634 -0.3543701171875 +86635 -0.096160888671875 +86636 -0.348175048828125 +86637 -0.0859375 +86638 -0.32598876953125 +86639 -0.071868896484375 +86640 -0.2581787109375 +86641 -0.048583984375 +86642 -0.139801025390625 +86643 -0.015594482421875 +86644 0.014617919921875 +86645 0.023681640625 +86646 0.144378662109375 +86647 0.056610107421875 +86648 0.221038818359375 +86649 0.07720947265625 +86650 0.27069091796875 +86651 0.0904541015625 +86652 0.294036865234375 +86653 0.09637451171875 +86654 0.311767578125 +86655 0.099090576171875 +86656 0.339141845703125 +86657 0.1016845703125 +86658 0.360260009765625 +86659 0.10101318359375 +86660 0.360504150390625 +86661 0.09454345703125 +86662 0.308380126953125 +86663 0.07696533203125 +86664 0.18170166015625 +86665 0.044708251953125 +86666 0.0047607421875 +86667 0.0028076171875 +86668 -0.17559814453125 +86669 -0.039520263671875 +86670 -0.3143310546875 +86671 -0.073516845703125 +86672 -0.36785888671875 +86673 -0.0906982421875 +86674 -0.36248779296875 +86675 -0.09552001953125 +86676 -0.343536376953125 +86677 -0.0960693359375 +86678 -0.3018798828125 +86679 -0.09051513671875 +86680 -0.231414794921875 +86681 -0.07763671875 +86682 -0.117645263671875 +86683 -0.054840087890625 +86684 0.007049560546875 +86685 -0.02825927734375 +86686 0.087982177734375 +86687 -0.008209228515625 +86688 0.13946533203125 +86689 0.00762939453125 +86690 0.17425537109375 +86691 0.021209716796875 +86692 0.188201904296875 +86693 0.031341552734375 +86694 0.171234130859375 +86695 0.035736083984375 +86696 0.118438720703125 +86697 0.033111572265625 +86698 0.05706787109375 +86699 0.028106689453125 +86700 -0.010711669921875 +86701 0.020782470703125 +86702 -0.0914306640625 +86703 0.009674072265625 +86704 -0.162322998046875 +86705 -0.001129150390625 +86706 -0.194549560546875 +86707 -0.006439208984375 +86708 -0.1492919921875 +86709 0.000885009765625 +86710 -0.02166748046875 +86711 0.021820068359375 +86712 0.124053955078125 +86713 0.04473876953125 +86714 0.211151123046875 +86715 0.055755615234375 +86716 0.240447998046875 +86717 0.05535888671875 +86718 0.242218017578125 +86719 0.049468994140625 +86720 0.2257080078125 +86721 0.040130615234375 +86722 0.194366455078125 +86723 0.0283203125 +86724 0.115509033203125 +86725 0.008331298828125 +86726 0.0128173828125 +86727 -0.01513671875 +86728 -0.053802490234375 +86729 -0.030853271484375 +86730 -0.110626220703125 +86731 -0.043487548828125 +86732 -0.199493408203125 +86733 -0.0606689453125 +86734 -0.29437255859375 +86735 -0.07757568359375 +86736 -0.33221435546875 +86737 -0.08270263671875 +86738 -0.27972412109375 +86739 -0.070068359375 +86740 -0.185333251953125 +86741 -0.048797607421875 +86742 -0.128204345703125 +86743 -0.033660888671875 +86744 -0.115692138671875 +86745 -0.026275634765625 +86746 -0.116455078125 +86747 -0.021209716796875 +86748 -0.105926513671875 +86749 -0.01422119140625 +86750 -0.053955078125 +86751 0.0 +86752 0.048797607421875 +86753 0.02288818359375 +86754 0.157318115234375 +86755 0.04595947265625 +86756 0.212005615234375 +86757 0.058135986328125 +86758 0.218475341796875 +86759 0.060333251953125 +86760 0.23724365234375 +86761 0.06365966796875 +86762 0.30535888671875 +86763 0.074981689453125 +86764 0.38128662109375 +86765 0.086761474609375 +86766 0.404449462890625 +86767 0.08795166015625 +86768 0.3944091796875 +86769 0.082366943359375 +86770 0.3885498046875 +86771 0.077117919921875 +86772 0.362640380859375 +86773 0.0679931640625 +86774 0.27362060546875 +86775 0.047332763671875 +86776 0.11712646484375 +86777 0.014556884765625 +86778 -0.054901123046875 +86779 -0.020538330078125 +86780 -0.19085693359375 +86781 -0.04827880859375 +86782 -0.28570556640625 +86783 -0.067626953125 +86784 -0.339263916015625 +86785 -0.079071044921875 +86786 -0.3775634765625 +86787 -0.087127685546875 +86788 -0.445709228515625 +86789 -0.098663330078125 +86790 -0.535064697265625 +86791 -0.112060546875 +86792 -0.629058837890625 +86793 -0.1246337890625 +86794 -0.697601318359375 +86795 -0.131805419921875 +86796 -0.70391845703125 +86797 -0.128082275390625 +86798 -0.6424560546875 +86799 -0.11285400390625 +86800 -0.491241455078125 +86801 -0.0831298828125 +86802 -0.265716552734375 +86803 -0.041656494140625 +86804 -0.023712158203125 +86805 0.0023193359375 +86806 0.201751708984375 +86807 0.043365478515625 +86808 0.375823974609375 +86809 0.075836181640625 +86810 0.485076904296875 +86811 0.09735107421875 +86812 0.56884765625 +86813 0.113616943359375 +86814 0.634765625 +86815 0.1256103515625 +86816 0.63763427734375 +86817 0.12640380859375 +86818 0.5660400390625 +86819 0.1142578125 +86820 0.4720458984375 +86821 0.097198486328125 +86822 0.40692138671875 +86823 0.083221435546875 +86824 0.3778076171875 +86825 0.07366943359375 +86826 0.376953125 +86827 0.06768798828125 +86828 0.371978759765625 +86829 0.060638427734375 +86830 0.313140869140625 +86831 0.045318603515625 +86832 0.184417724609375 +86833 0.0196533203125 +86834 0.011199951171875 +86835 -0.012115478515625 +86836 -0.171051025390625 +86837 -0.0443115234375 +86838 -0.33740234375 +86839 -0.07293701171875 +86840 -0.47198486328125 +86841 -0.095428466796875 +86842 -0.560394287109375 +86843 -0.109527587890625 +86844 -0.58056640625 +86845 -0.11187744140625 +86846 -0.54754638671875 +86847 -0.1048583984375 +86848 -0.508575439453125 +86849 -0.095794677734375 +86850 -0.459503173828125 +86851 -0.084259033203125 +86852 -0.394378662109375 +86853 -0.069580078125 +86854 -0.35260009765625 +86855 -0.058013916015625 +86856 -0.31170654296875 +86857 -0.046478271484375 +86858 -0.197418212890625 +86859 -0.023956298828125 +86860 -0.007965087890625 +86861 0.009521484375 +86862 0.207489013671875 +86863 0.04620361328125 +86864 0.409210205078125 +86865 0.079864501953125 +86866 0.57208251953125 +86867 0.1065673828125 +86868 0.66595458984375 +86869 0.12164306640625 +86870 0.65875244140625 +86871 0.120208740234375 +86872 0.56744384765625 +86873 0.10491943359375 +86874 0.431396484375 +86875 0.08184814453125 +86876 0.29443359375 +86877 0.057830810546875 +86878 0.182464599609375 +86879 0.0369873046875 +86880 0.06365966796875 +86881 0.014739990234375 +86882 -0.075958251953125 +86883 -0.010772705078125 +86884 -0.189422607421875 +86885 -0.032196044921875 +86886 -0.271942138671875 +86887 -0.048553466796875 +86888 -0.342529296875 +86889 -0.06256103515625 +86890 -0.364166259765625 +86891 -0.068450927734375 +86892 -0.327239990234375 +86893 -0.064666748046875 +86894 -0.2769775390625 +86895 -0.0579833984375 +86896 -0.253692626953125 +86897 -0.05450439453125 +86898 -0.24365234375 +86899 -0.0521240234375 +86900 -0.1983642578125 +86901 -0.043548583984375 +86902 -0.116241455078125 +86903 -0.028656005859375 +86904 -0.036834716796875 +86905 -0.013641357421875 +86906 0.034881591796875 +86907 0.00054931640625 +86908 0.09124755859375 +86909 0.0125732421875 +86910 0.10888671875 +86911 0.0186767578125 +86912 0.125518798828125 +86913 0.0244140625 +86914 0.15771484375 +86915 0.032135009765625 +86916 0.17828369140625 +86917 0.037567138671875 +86918 0.17108154296875 +86919 0.03814697265625 +86920 0.129974365234375 +86921 0.032867431640625 +86922 0.082427978515625 +86923 0.025848388671875 +86924 0.027679443359375 +86925 0.01702880859375 +86926 -0.065643310546875 +86927 0.001678466796875 +86928 -0.15936279296875 +86929 -0.014312744140625 +86930 -0.21307373046875 +86931 -0.024658203125 +86932 -0.234649658203125 +86933 -0.03045654296875 +86934 -0.2001953125 +86935 -0.027923583984375 +86936 -0.119171142578125 +86937 -0.01837158203125 +86938 -0.024749755859375 +86939 -0.00665283203125 +86940 0.085784912109375 +86941 0.007720947265625 +86942 0.178131103515625 +86943 0.0196533203125 +86944 0.215576171875 +86945 0.023712158203125 +86946 0.211456298828125 +86947 0.02197265625 +86948 0.17523193359375 +86949 0.015960693359375 +86950 0.128753662109375 +86951 0.009002685546875 +86952 0.1019287109375 +86953 0.005615234375 +86954 0.0743408203125 +86955 0.002655029296875 +86956 0.04327392578125 +86957 -0.0003662109375 +86958 0.038177490234375 +86959 0.000885009765625 +86960 0.076263427734375 +86961 0.0089111328125 +86962 0.14105224609375 +86963 0.02105712890625 +86964 0.186431884765625 +86965 0.030181884765625 +86966 0.188812255859375 +86967 0.0325927734375 +86968 0.1390380859375 +86969 0.02679443359375 +86970 0.041778564453125 +86971 0.013427734375 +86972 -0.079437255859375 +86973 -0.00396728515625 +86974 -0.219390869140625 +86975 -0.024658203125 +86976 -0.367828369140625 +86977 -0.047088623046875 +86978 -0.494873046875 +86979 -0.066680908203125 +86980 -0.556243896484375 +86981 -0.076690673828125 +86982 -0.508697509765625 +86983 -0.070556640625 +86984 -0.3756103515625 +86985 -0.051727294921875 +86986 -0.218902587890625 +86987 -0.029541015625 +86988 -0.063751220703125 +86989 -0.007720947265625 +86990 0.091552734375 +86991 0.0140380859375 +86992 0.23602294921875 +86993 0.0341796875 +86994 0.342987060546875 +86995 0.04876708984375 +86996 0.39520263671875 +86997 0.055267333984375 +86998 0.389373779296875 +86999 0.053253173828125 +87000 0.324249267578125 +87001 0.042572021484375 +87002 0.224090576171875 +87003 0.0269775390625 +87004 0.124267578125 +87005 0.0118408203125 +87006 0.037078857421875 +87007 -0.000946044921875 +87008 -0.010101318359375 +87009 -0.00726318359375 +87010 -0.019439697265625 +87011 -0.00750732421875 +87012 -0.022796630859375 +87013 -0.006622314453125 +87014 -0.001556396484375 +87015 -0.0018310546875 +87016 0.056304931640625 +87017 0.008514404296875 +87018 0.106719970703125 +87019 0.017669677734375 +87020 0.096893310546875 +87021 0.01751708984375 +87022 0.042694091796875 +87023 0.010406494140625 +87024 -0.018035888671875 +87025 0.002044677734375 +87026 -0.07586669921875 +87027 -0.006134033203125 +87028 -0.11944580078125 +87029 -0.012420654296875 +87030 -0.15972900390625 +87031 -0.01849365234375 +87032 -0.202606201171875 +87033 -0.025238037109375 +87034 -0.24859619140625 +87035 -0.032684326171875 +87036 -0.30517578125 +87037 -0.041961669921875 +87038 -0.36212158203125 +87039 -0.051483154296875 +87040 -0.39141845703125 +87041 -0.05706787109375 +87042 -0.35528564453125 +87043 -0.053070068359375 +87044 -0.249969482421875 +87045 -0.03875732421875 +87046 -0.092864990234375 +87047 -0.016876220703125 +87048 0.08905029296875 +87049 0.00872802734375 +87050 0.2352294921875 +87051 0.0302734375 +87052 0.318817138671875 +87053 0.04412841796875 +87054 0.358642578125 +87055 0.05218505859375 +87056 0.347747802734375 +87057 0.053375244140625 +87058 0.28564453125 +87059 0.0474853515625 +87060 0.223175048828125 +87061 0.040557861328125 +87062 0.196746826171875 +87063 0.0369873046875 +87064 0.179840087890625 +87065 0.033660888671875 +87066 0.155548095703125 +87067 0.028656005859375 +87068 0.151214599609375 +87069 0.02545166015625 +87070 0.156951904296875 +87071 0.0230712890625 +87072 0.13177490234375 +87073 0.01678466796875 +87074 0.100799560546875 +87075 0.009796142578125 +87076 0.087127685546875 +87077 0.005096435546875 +87078 0.05487060546875 +87079 -0.001434326171875 +87080 -0.009002685546875 +87081 -0.01123046875 +87082 -0.10400390625 +87083 -0.02410888671875 +87084 -0.229400634765625 +87085 -0.0399169921875 +87086 -0.35552978515625 +87087 -0.055084228515625 +87088 -0.441925048828125 +87089 -0.06475830078125 +87090 -0.473846435546875 +87091 -0.067230224609375 +87092 -0.464813232421875 +87093 -0.064239501953125 +87094 -0.419097900390625 +87095 -0.056396484375 +87096 -0.334320068359375 +87097 -0.0435791015625 +87098 -0.227935791015625 +87099 -0.02801513671875 +87100 -0.12347412109375 +87101 -0.0126953125 +87102 -0.02764892578125 +87103 0.00140380859375 +87104 0.077667236328125 +87105 0.016326904296875 +87106 0.2132568359375 +87107 0.034454345703125 +87108 0.38885498046875 +87109 0.05682373046875 +87110 0.582794189453125 +87111 0.080780029296875 +87112 0.734039306640625 +87113 0.0989990234375 +87114 0.800140380859375 +87115 0.106414794921875 +87116 0.7783203125 +87117 0.10272216796875 +87118 0.6651611328125 +87119 0.08758544921875 +87120 0.45965576171875 +87121 0.061004638671875 +87122 0.199188232421875 +87123 0.027587890625 +87124 -0.050689697265625 +87125 -0.004638671875 +87126 -0.23297119140625 +87127 -0.028717041015625 +87128 -0.33013916015625 +87129 -0.042449951171875 +87130 -0.368408203125 +87131 -0.04888916015625 +87132 -0.378936767578125 +87133 -0.051666259765625 +87134 -0.376983642578125 +87135 -0.05255126953125 +87136 -0.37969970703125 +87137 -0.053558349609375 +87138 -0.391510009765625 +87139 -0.05517578125 +87140 -0.385345458984375 +87141 -0.054168701171875 +87142 -0.3419189453125 +87143 -0.048248291015625 +87144 -0.28289794921875 +87145 -0.0400390625 +87146 -0.251617431640625 +87147 -0.03485107421875 +87148 -0.266143798828125 +87149 -0.034912109375 +87150 -0.273345947265625 +87151 -0.033966064453125 +87152 -0.216796875 +87153 -0.02532958984375 +87154 -0.128265380859375 +87155 -0.012908935546875 +87156 -0.068145751953125 +87157 -0.0040283203125 +87158 -0.0430908203125 +87159 0.000396728515625 +87160 -0.024444580078125 +87161 0.00372314453125 +87162 0.020721435546875 +87163 0.00982666015625 +87164 0.124481201171875 +87165 0.022552490234375 +87166 0.25787353515625 +87167 0.03839111328125 +87168 0.379119873046875 +87169 0.0523681640625 +87170 0.47991943359375 +87171 0.063507080078125 +87172 0.5281982421875 +87173 0.06805419921875 +87174 0.511138916015625 +87175 0.06451416015625 +87176 0.456207275390625 +87177 0.0562744140625 +87178 0.407470703125 +87179 0.048736572265625 +87180 0.383758544921875 +87181 0.044281005859375 +87182 0.35687255859375 +87183 0.03955078125 +87184 0.31182861328125 +87185 0.032867431640625 +87186 0.250885009765625 +87187 0.024566650390625 +87188 0.1654052734375 +87189 0.013641357421875 +87190 0.035247802734375 +87191 -0.00225830078125 +87192 -0.142059326171875 +87193 -0.023406982421875 +87194 -0.33563232421875 +87195 -0.046142578125 +87196 -0.5345458984375 +87197 -0.069183349609375 +87198 -0.72186279296875 +87199 -0.090545654296875 +87200 -0.836669921875 +87201 -0.102935791015625 +87202 -0.8326416015625 +87203 -0.100921630859375 +87204 -0.7296142578125 +87205 -0.08697509765625 +87206 -0.582550048828125 +87207 -0.067840576171875 +87208 -0.440093994140625 +87209 -0.04937744140625 +87210 -0.324310302734375 +87211 -0.034332275390625 +87212 -0.20147705078125 +87213 -0.0186767578125 +87214 -0.044647216796875 +87215 0.000762939453125 +87216 0.103973388671875 +87217 0.01885986328125 +87218 0.202392578125 +87219 0.03057861328125 +87220 0.264495849609375 +87221 0.03759765625 +87222 0.338897705078125 +87223 0.0457763671875 +87224 0.443817138671875 +87225 0.057373046875 +87226 0.545074462890625 +87227 0.068328857421875 +87228 0.6173095703125 +87229 0.075653076171875 +87230 0.6524658203125 +87231 0.078460693359375 +87232 0.66339111328125 +87233 0.078399658203125 +87234 0.6561279296875 +87235 0.076263427734375 +87236 0.606781005859375 +87237 0.069244384765625 +87238 0.501190185546875 +87239 0.055694580078125 +87240 0.352783203125 +87241 0.037261962890625 +87242 0.176544189453125 +87243 0.015777587890625 +87244 -0.034820556640625 +87245 -0.00958251953125 +87246 -0.258209228515625 +87247 -0.036041259765625 +87248 -0.44244384765625 +87249 -0.0574951171875 +87250 -0.5753173828125 +87251 -0.072540283203125 +87252 -0.65203857421875 +87253 -0.080657958984375 +87254 -0.641632080078125 +87255 -0.078216552734375 +87256 -0.562164306640625 +87257 -0.06744384765625 +87258 -0.458038330078125 +87259 -0.053741455078125 +87260 -0.350555419921875 +87261 -0.039703369140625 +87262 -0.260528564453125 +87263 -0.027923583984375 +87264 -0.192108154296875 +87265 -0.0189208984375 +87266 -0.141937255859375 +87267 -0.0123291015625 +87268 -0.1021728515625 +87269 -0.007232666015625 +87270 -0.062896728515625 +87271 -0.00244140625 +87272 -0.011932373046875 +87273 0.00347900390625 +87274 0.062835693359375 +87275 0.011993408203125 +87276 0.148712158203125 +87277 0.021636962890625 +87278 0.241729736328125 +87279 0.031951904296875 +87280 0.34912109375 +87281 0.043853759765625 +87282 0.457305908203125 +87283 0.0557861328125 +87284 0.54388427734375 +87285 0.065093994140625 +87286 0.5728759765625 +87287 0.067535400390625 +87288 0.506591796875 +87289 0.058624267578125 +87290 0.351226806640625 +87291 0.0391845703125 +87292 0.146514892578125 +87293 0.014007568359375 +87294 -0.05523681640625 +87295 -0.010589599609375 +87296 -0.21624755859375 +87297 -0.02972412109375 +87298 -0.334930419921875 +87299 -0.043426513671875 +87300 -0.402984619140625 +87301 -0.051513671875 +87302 -0.4412841796875 +87303 -0.0557861328125 +87304 -0.49578857421875 +87305 -0.060333251953125 +87306 -0.5601806640625 +87307 -0.064697265625 +87308 -0.600738525390625 +87309 -0.0660400390625 +87310 -0.584228515625 +87311 -0.061614990234375 +87312 -0.47930908203125 +87313 -0.04888916015625 +87314 -0.27935791015625 +87315 -0.027496337890625 +87316 -0.0089111328125 +87317 0.000152587890625 +87318 0.268798828125 +87319 0.02825927734375 +87320 0.482818603515625 +87321 0.050384521484375 +87322 0.60369873046875 +87323 0.063751220703125 +87324 0.650421142578125 +87325 0.069915771484375 +87326 0.66400146484375 +87327 0.0723876953125 +87328 0.6414794921875 +87329 0.07086181640625 +87330 0.572540283203125 +87331 0.064453125 +87332 0.498138427734375 +87333 0.05682373046875 +87334 0.439453125 +87335 0.049896240234375 +87336 0.375518798828125 +87337 0.041961669921875 +87338 0.274505615234375 +87339 0.03033447265625 +87340 0.1087646484375 +87341 0.01275634765625 +87342 -0.099395751953125 +87343 -0.00860595703125 +87344 -0.3182373046875 +87345 -0.030792236328125 +87346 -0.5489501953125 +87347 -0.05377197265625 +87348 -0.7738037109375 +87349 -0.0758056640625 +87350 -0.86383056640625 +87351 -0.0921630859375 +87352 -0.870391845703125 +87353 -0.099822998046875 +87354 -0.86895751953125 +87355 -0.100311279296875 +87356 -0.861053466796875 +87357 -0.094757080078125 +87358 -0.765869140625 +87359 -0.0816650390625 +87360 -0.5301513671875 +87361 -0.06011962890625 +87362 -0.214691162109375 +87363 -0.030853271484375 +87364 0.137359619140625 +87365 0.00225830078125 +87366 0.474822998046875 +87367 0.034576416015625 +87368 0.76239013671875 +87369 0.06280517578125 +87370 0.867462158203125 +87371 0.084442138671875 +87372 0.870361328125 +87373 0.099395751953125 +87374 0.86480712890625 +87375 0.10650634765625 +87376 0.831817626953125 +87377 0.106170654296875 +87378 0.677581787109375 +87379 0.1004638671875 +87380 0.495880126953125 +87381 0.08990478515625 +87382 0.30767822265625 +87383 0.076080322265625 +87384 0.116180419921875 +87385 0.0592041015625 +87386 -0.110748291015625 +87387 0.03656005859375 +87388 -0.381805419921875 +87389 0.007598876953125 +87390 -0.6572265625 +87391 -0.0238037109375 +87392 -0.857421875 +87393 -0.052276611328125 +87394 -0.870391845703125 +87395 -0.073944091796875 +87396 -0.870391845703125 +87397 -0.088104248046875 +87398 -0.86444091796875 +87399 -0.097015380859375 +87400 -0.85723876953125 +87401 -0.103729248046875 +87402 -0.790008544921875 +87403 -0.1065673828125 +87404 -0.62847900390625 +87405 -0.1007080078125 +87406 -0.3956298828125 +87407 -0.085845947265625 +87408 -0.126708984375 +87409 -0.0648193359375 +87410 0.150115966796875 +87411 -0.040069580078125 +87412 0.424041748046875 +87413 -0.012664794921875 +87414 0.670623779296875 +87415 0.014984130859375 +87416 0.854522705078125 +87417 0.039398193359375 +87418 0.866485595703125 +87419 0.058929443359375 +87420 0.86920166015625 +87421 0.0721435546875 +87422 0.8653564453125 +87423 0.08056640625 +87424 0.857147216796875 +87425 0.085296630859375 +87426 0.766845703125 +87427 0.08599853515625 +87428 0.628509521484375 +87429 0.083099365234375 +87430 0.462127685546875 +87431 0.075958251953125 +87432 0.297210693359375 +87433 0.066802978515625 +87434 0.14862060546875 +87435 0.056671142578125 +87436 -0.00537109375 +87437 0.0435791015625 +87438 -0.15753173828125 +87439 0.028228759765625 +87440 -0.31304931640625 +87441 0.010345458984375 +87442 -0.48876953125 +87443 -0.01123046875 +87444 -0.6416015625 +87445 -0.032318115234375 +87446 -0.751373291015625 +87447 -0.050689697265625 +87448 -0.84619140625 +87449 -0.06829833984375 +87450 -0.861297607421875 +87451 -0.083770751953125 +87452 -0.863250732421875 +87453 -0.09417724609375 +87454 -0.856597900390625 +87455 -0.096649169921875 +87456 -0.7498779296875 +87457 -0.09222412109375 +87458 -0.624542236328125 +87459 -0.08599853515625 +87460 -0.47808837890625 +87461 -0.0760498046875 +87462 -0.253387451171875 +87463 -0.0572509765625 +87464 0.003692626953125 +87465 -0.033660888671875 +87466 0.2257080078125 +87467 -0.011322021484375 +87468 0.427154541015625 +87469 0.01080322265625 +87470 0.643218994140625 +87471 0.0355224609375 +87472 0.855926513671875 +87473 0.06195068359375 +87474 0.870361328125 +87475 0.0849609375 +87476 0.870361328125 +87477 0.10015869140625 +87478 0.862762451171875 +87479 0.108123779296875 +87480 0.79669189453125 +87481 0.108612060546875 +87482 0.595794677734375 +87483 0.10076904296875 +87484 0.362152099609375 +87485 0.087127685546875 +87486 0.1270751953125 +87487 0.070159912109375 +87488 -0.086944580078125 +87489 0.051727294921875 +87490 -0.2784423828125 +87491 0.032012939453125 +87492 -0.484832763671875 +87493 0.00799560546875 +87494 -0.729583740234375 +87495 -0.02197265625 +87496 -0.86688232421875 +87497 -0.053375244140625 +87498 -0.870391845703125 +87499 -0.08062744140625 +87500 -0.86859130859375 +87501 -0.103240966796875 +87502 -0.86279296875 +87503 -0.121002197265625 +87504 -0.817962646484375 +87505 -0.130706787109375 +87506 -0.6116943359375 +87507 -0.128387451171875 +87508 -0.3128662109375 +87509 -0.113372802734375 +87510 0.039398193359375 +87511 -0.088623046875 +87512 0.422821044921875 +87513 -0.055908203125 +87514 0.805145263671875 +87515 -0.0181884765625 +87516 0.870361328125 +87517 0.018524169921875 +87518 0.870361328125 +87519 0.049163818359375 +87520 0.860015869140625 +87521 0.072723388671875 +87522 0.727935791015625 +87523 0.088470458984375 +87524 0.48114013671875 +87525 0.095855712890625 +87526 0.2059326171875 +87527 0.097015380859375 +87528 -0.06103515625 +87529 0.0938720703125 +87530 -0.29913330078125 +87531 0.0872802734375 +87532 -0.516204833984375 +87533 0.075927734375 +87534 -0.7252197265625 +87535 0.0584716796875 +87536 -0.85980224609375 +87537 0.037078857421875 +87538 -0.870391845703125 +87539 0.0147705078125 +87540 -0.870391845703125 +87541 -0.005767822265625 +87542 -0.858062744140625 +87543 -0.020233154296875 +87544 -0.673004150390625 +87545 -0.028228759765625 +87546 -0.42694091796875 +87547 -0.034332275390625 +87548 -0.2100830078125 +87549 -0.0423583984375 +87550 -0.0362548828125 +87551 -0.052093505859375 +87552 0.10943603515625 +87553 -0.060577392578125 +87554 0.23516845703125 +87555 -0.065826416015625 +87556 0.373687744140625 +87557 -0.065399169921875 +87558 0.517791748046875 +87559 -0.05950927734375 +87560 0.602783203125 +87561 -0.051849365234375 +87562 0.635711669921875 +87563 -0.042388916015625 +87564 0.655181884765625 +87565 -0.029541015625 +87566 0.65948486328125 +87567 -0.014190673828125 +87568 0.651275634765625 +87569 0.002838134765625 +87570 0.61846923828125 +87571 0.019805908203125 +87572 0.53753662109375 +87573 0.0343017578125 +87574 0.404144287109375 +87575 0.0450439453125 +87576 0.22186279296875 +87577 0.05126953125 +87578 0.003997802734375 +87579 0.05291748046875 +87580 -0.22100830078125 +87581 0.0509033203125 +87582 -0.42449951171875 +87583 0.04632568359375 +87584 -0.579833984375 +87585 0.040435791015625 +87586 -0.641876220703125 +87587 0.03570556640625 +87588 -0.6177978515625 +87589 0.03192138671875 +87590 -0.575531005859375 +87591 0.025665283203125 +87592 -0.526336669921875 +87593 0.016876220703125 +87594 -0.42645263671875 +87595 0.00872802734375 +87596 -0.2581787109375 +87597 0.00299072265625 +87598 -0.068695068359375 +87599 -0.0020751953125 +87600 0.09222412109375 +87601 -0.00836181640625 +87602 0.232147216796875 +87603 -0.014617919921875 +87604 0.3509521484375 +87605 -0.020111083984375 +87606 0.410064697265625 +87607 -0.026397705078125 +87608 0.372955322265625 +87609 -0.035064697265625 +87610 0.2554931640625 +87611 -0.044952392578125 +87612 0.10711669921875 +87613 -0.053192138671875 +87614 -0.052886962890625 +87615 -0.058807373046875 +87616 -0.186279296875 +87617 -0.059967041015625 +87618 -0.23291015625 +87619 -0.0537109375 +87620 -0.209442138671875 +87621 -0.041534423828125 +87622 -0.174163818359375 +87623 -0.02734375 +87624 -0.126739501953125 +87625 -0.011871337890625 +87626 -0.048126220703125 +87627 0.005218505859375 +87628 0.0426025390625 +87629 0.022186279296875 +87630 0.10748291015625 +87631 0.036285400390625 +87632 0.1409912109375 +87633 0.046661376953125 +87634 0.19708251953125 +87635 0.055908203125 +87636 0.273651123046875 +87637 0.063690185546875 +87638 0.31768798828125 +87639 0.066925048828125 +87640 0.341094970703125 +87641 0.066314697265625 +87642 0.368011474609375 +87643 0.063385009765625 +87644 0.37249755859375 +87645 0.0570068359375 +87646 0.30072021484375 +87647 0.044586181640625 +87648 0.1517333984375 +87649 0.026580810546875 +87650 -0.01470947265625 +87651 0.00689697265625 +87652 -0.1883544921875 +87653 -0.013275146484375 +87654 -0.372711181640625 +87655 -0.0335693359375 +87656 -0.51397705078125 +87657 -0.050445556640625 +87658 -0.57177734375 +87659 -0.061187744140625 +87660 -0.53948974609375 +87661 -0.0650634765625 +87662 -0.43511962890625 +87663 -0.06280517578125 +87664 -0.2962646484375 +87665 -0.056396484375 +87666 -0.161102294921875 +87667 -0.047943115234375 +87668 -0.0435791015625 +87669 -0.038360595703125 +87670 0.060394287109375 +87671 -0.02764892578125 +87672 0.13665771484375 +87673 -0.01690673828125 +87674 0.170135498046875 +87675 -0.00738525390625 +87676 0.16552734375 +87677 0.000732421875 +87678 0.15728759765625 +87679 0.008880615234375 +87680 0.150787353515625 +87681 0.016876220703125 +87682 0.12200927734375 +87683 0.022918701171875 +87684 0.080108642578125 +87685 0.027130126953125 +87686 0.05126953125 +87687 0.030670166015625 +87688 0.062896728515625 +87689 0.034820556640625 +87690 0.09271240234375 +87691 0.038177490234375 +87692 0.092987060546875 +87693 0.038055419921875 +87694 0.07855224609375 +87695 0.03533935546875 +87696 0.06427001953125 +87697 0.031005859375 +87698 0.0347900390625 +87699 0.0244140625 +87700 -0.01171875 +87701 0.015777587890625 +87702 -0.056060791015625 +87703 0.00653076171875 +87704 -0.055511474609375 +87705 -0.000518798828125 +87706 -0.010467529296875 +87707 -0.0050048828125 +87708 0.02508544921875 +87709 -0.009521484375 +87710 0.025665283203125 +87711 -0.01519775390625 +87712 0.017333984375 +87713 -0.020263671875 +87714 0.00189208984375 +87715 -0.0244140625 +87716 -0.03173828125 +87717 -0.02813720703125 +87718 -0.071502685546875 +87719 -0.03070068359375 +87720 -0.13543701171875 +87721 -0.033111572265625 +87722 -0.219970703125 +87723 -0.0352783203125 +87724 -0.300506591796875 +87725 -0.035980224609375 +87726 -0.376312255859375 +87727 -0.035430908203125 +87728 -0.416107177734375 +87729 -0.03216552734375 +87730 -0.371124267578125 +87731 -0.0238037109375 +87732 -0.242279052734375 +87733 -0.0107421875 +87734 -0.069732666015625 +87735 0.004425048828125 +87736 0.125640869140625 +87737 0.020263671875 +87738 0.31268310546875 +87739 0.0347900390625 +87740 0.45501708984375 +87741 0.04571533203125 +87742 0.554779052734375 +87743 0.05303955078125 +87744 0.61065673828125 +87745 0.056640625 +87746 0.610931396484375 +87747 0.055908203125 +87748 0.531463623046875 +87749 0.049560546875 +87750 0.3883056640625 +87751 0.038604736328125 +87752 0.23468017578125 +87753 0.0262451171875 +87754 0.095245361328125 +87755 0.014129638671875 +87756 -0.00396728515625 +87757 0.003936767578125 +87758 -0.04852294921875 +87759 -0.0032958984375 +87760 -0.055145263671875 +87761 -0.008209228515625 +87762 -0.0758056640625 +87763 -0.01348876953125 +87764 -0.138702392578125 +87765 -0.020477294921875 +87766 -0.209197998046875 +87767 -0.027069091796875 +87768 -0.289031982421875 +87769 -0.033233642578125 +87770 -0.37884521484375 +87771 -0.0389404296875 +87772 -0.456329345703125 +87773 -0.04296875 +87774 -0.51641845703125 +87775 -0.0450439453125 +87776 -0.519287109375 +87777 -0.04302978515625 +87778 -0.458251953125 +87779 -0.036712646484375 +87780 -0.384796142578125 +87781 -0.029144287109375 +87782 -0.323699951171875 +87783 -0.02191162109375 +87784 -0.269287109375 +87785 -0.014923095703125 +87786 -0.1951904296875 +87787 -0.00689697265625 +87788 -0.100006103515625 +87789 0.001983642578125 +87790 -0.01055908203125 +87791 0.010040283203125 +87792 0.1033935546875 +87793 0.018798828125 +87794 0.24908447265625 +87795 0.028533935546875 +87796 0.373199462890625 +87797 0.03619384765625 +87798 0.45806884765625 +87799 0.040802001953125 +87800 0.511474609375 +87801 0.042816162109375 +87802 0.565399169921875 +87803 0.044097900390625 +87804 0.61138916015625 +87805 0.0443115234375 +87806 0.5897216796875 +87807 0.040252685546875 +87808 0.4906005859375 +87809 0.031646728515625 +87810 0.33148193359375 +87811 0.019775390625 +87812 0.147796630859375 +87813 0.006683349609375 +87814 -0.01873779296875 +87815 -0.005340576171875 +87816 -0.140289306640625 +87817 -0.014739990234375 +87818 -0.191986083984375 +87819 -0.020111083984375 +87820 -0.184295654296875 +87821 -0.021820068359375 +87822 -0.161834716796875 +87823 -0.02203369140625 +87824 -0.166595458984375 +87825 -0.022796630859375 +87826 -0.19390869140625 +87827 -0.02386474609375 +87828 -0.22442626953125 +87829 -0.024322509765625 +87830 -0.279754638671875 +87831 -0.025299072265625 +87832 -0.3389892578125 +87833 -0.025909423828125 +87834 -0.3543701171875 +87835 -0.02386474609375 +87836 -0.348175048828125 +87837 -0.02044677734375 +87838 -0.32598876953125 +87839 -0.016143798828125 +87840 -0.2581787109375 +87841 -0.0096435546875 +87842 -0.139801025390625 +87843 -0.000885009765625 +87844 0.014617919921875 +87845 0.00927734375 +87846 0.144378662109375 +87847 0.01763916015625 +87848 0.221038818359375 +87849 0.022735595703125 +87850 0.27069091796875 +87851 0.025787353515625 +87852 0.294036865234375 +87853 0.02685546875 +87854 0.311767578125 +87855 0.0269775390625 +87856 0.339141845703125 +87857 0.026885986328125 +87858 0.360260009765625 +87859 0.02557373046875 +87860 0.360504150390625 +87861 0.022552490234375 +87862 0.308380126953125 +87863 0.01739501953125 +87864 0.18170166015625 +87865 0.009857177734375 +87866 0.0047607421875 +87867 0.000885009765625 +87868 -0.17559814453125 +87869 -0.008056640625 +87870 -0.3143310546875 +87871 -0.015625 +87872 -0.36785888671875 +87873 -0.0205078125 +87874 -0.36248779296875 +87875 -0.023162841796875 +87876 -0.343536376953125 +87877 -0.024566650390625 +87878 -0.3018798828125 +87879 -0.0244140625 +87880 -0.231414794921875 +87881 -0.022552490234375 +87882 -0.117645263671875 +87883 -0.0186767578125 +87884 0.007049560546875 +87885 -0.013671875 +87886 0.087982177734375 +87887 -0.00897216796875 +87888 0.13946533203125 +87889 -0.004425048828125 +87890 0.17425537109375 +87891 6.103515625e-05 +87892 0.188201904296875 +87893 0.004180908203125 +87894 0.171234130859375 +87895 0.007476806640625 +87896 0.118438720703125 +87897 0.0096435546875 +87898 0.05706787109375 +87899 0.01116943359375 +87900 -0.010711669921875 +87901 0.011962890625 +87902 -0.0914306640625 +87903 0.01171875 +87904 -0.162322998046875 +87905 0.010894775390625 +87906 -0.194549560546875 +87907 0.010162353515625 +87908 -0.1492919921875 +87909 0.010467529296875 +87910 -0.02166748046875 +87911 0.011993408203125 +87912 0.124053955078125 +87913 0.0133056640625 +87914 0.211151123046875 +87915 0.012664794921875 +87916 0.240447998046875 +87917 0.010284423828125 +87918 0.242218017578125 +87919 0.007049560546875 +87920 0.2257080078125 +87921 0.00341796875 +87922 0.194366455078125 +87923 -0.000335693359375 +87924 0.115509033203125 +87925 -0.00482177734375 +87926 0.0128173828125 +87927 -0.00933837890625 +87928 -0.053802490234375 +87929 -0.012359619140625 +87930 -0.110626220703125 +87931 -0.01446533203125 +87932 -0.199493408203125 +87933 -0.016632080078125 +87934 -0.29437255859375 +87935 -0.018280029296875 +87936 -0.33221435546875 +87937 -0.0179443359375 +87938 -0.27972412109375 +87939 -0.014923095703125 +87940 -0.185333251953125 +87941 -0.010467529296875 +87942 -0.128204345703125 +87943 -0.006591796875 +87944 -0.115692138671875 +87945 -0.003631591796875 +87946 -0.116455078125 +87947 -0.001007080078125 +87948 -0.105926513671875 +87949 0.001708984375 +87950 -0.053955078125 +87951 0.005126953125 +87952 0.048797607421875 +87953 0.009368896484375 +87954 0.157318115234375 +87955 0.01324462890625 +87956 0.212005615234375 +87957 0.015289306640625 +87958 0.218475341796875 +87959 0.015594482421875 +87960 0.23724365234375 +87961 0.015594482421875 +87962 0.30535888671875 +87963 0.016265869140625 +87964 0.38128662109375 +87965 0.016632080078125 +87966 0.404449462890625 +87967 0.015380859375 +87968 0.3944091796875 +87969 0.0130615234375 +87970 0.3885498046875 +87971 0.010711669921875 +87972 0.362640380859375 +87973 0.00787353515625 +87974 0.27362060546875 +87975 0.003662109375 +87976 0.11712646484375 +87977 -0.00189208984375 +87978 -0.054901123046875 +87979 -0.007476806640625 +87980 -0.19085693359375 +87981 -0.01177978515625 +87982 -0.28570556640625 +87983 -0.014678955078125 +87984 -0.339263916015625 +87985 -0.01611328125 +87986 -0.3775634765625 +87987 -0.0167236328125 +87988 -0.445709228515625 +87989 -0.017608642578125 +87990 -0.535064697265625 +87991 -0.01861572265625 +87992 -0.629058837890625 +87993 -0.0194091796875 +87994 -0.697601318359375 +87995 -0.019317626953125 +87996 -0.70391845703125 +87997 -0.017608642578125 +87998 -0.6424560546875 +87999 -0.014251708984375 +88000 -0.491241455078125 +88001 -0.008819580078125 +88002 -0.265716552734375 +88003 -0.001800537109375 +88004 -0.023712158203125 +88005 0.005279541015625 +88006 0.201751708984375 +88007 0.0115966796875 +88008 0.375823974609375 +88009 0.0162353515625 +88010 0.485076904296875 +88011 0.0189208984375 +88012 0.56884765625 +88013 0.0206298828125 +88014 0.634765625 +88015 0.02154541015625 +88016 0.63763427734375 +88017 0.020599365234375 +88018 0.5660400390625 +88019 0.017608642578125 +88020 0.4720458984375 +88021 0.013885498046875 +88022 0.40692138671875 +88023 0.010772705078125 +88024 0.3778076171875 +88025 0.008514404296875 +88026 0.376953125 +88027 0.00701904296875 +88028 0.371978759765625 +88029 0.005584716796875 +88030 0.313140869140625 +88031 0.0030517578125 +88032 0.184417724609375 +88033 -0.000885009765625 +88034 0.011199951171875 +88035 -0.00555419921875 +88036 -0.171051025390625 +88037 -0.010040283203125 +88038 -0.33740234375 +88039 -0.013763427734375 +88040 -0.47198486328125 +88041 -0.016387939453125 +88042 -0.560394287109375 +88043 -0.01763916015625 +88044 -0.58056640625 +88045 -0.01702880859375 +88046 -0.54754638671875 +88047 -0.014984130859375 +88048 -0.508575439453125 +88049 -0.012725830078125 +88050 -0.459503173828125 +88051 -0.010223388671875 +88052 -0.394378662109375 +88053 -0.00738525390625 +88054 -0.35260009765625 +88055 -0.005218505859375 +88056 -0.31170654296875 +88057 -0.00323486328125 +88058 -0.197418212890625 +88059 0.000274658203125 +88060 -0.007965087890625 +88061 0.00531005859375 +88062 0.207489013671875 +88063 0.0106201171875 +88064 0.409210205078125 +88065 0.0152587890625 +88066 0.57208251953125 +88067 0.018341064453125 +88068 0.66595458984375 +88069 0.0194091796875 +88070 0.65875244140625 +88071 0.0184326171875 +88072 0.56744384765625 +88073 0.015838623046875 +88074 0.431396484375 +88075 0.012176513671875 +88076 0.29443359375 +88077 0.008056640625 +88078 0.182464599609375 +88079 0.00390625 +88080 0.06365966796875 +88081 -0.000244140625 +88082 -0.075958251953125 +88083 -0.00433349609375 +88084 -0.189422607421875 +88085 -0.0078125 +88086 -0.271942138671875 +88087 -0.010528564453125 +88088 -0.342529296875 +88089 -0.012542724609375 +88090 -0.364166259765625 +88091 -0.01348876953125 +88092 -0.327239990234375 +88093 -0.013275146484375 +88094 -0.2769775390625 +88095 -0.012298583984375 +88096 -0.253692626953125 +88097 -0.010955810546875 +88098 -0.24365234375 +88099 -0.009246826171875 +88100 -0.1983642578125 +88101 -0.0068359375 +88102 -0.116241455078125 +88103 -0.003875732421875 +88104 -0.036834716796875 +88105 -0.000823974609375 +88106 0.034881591796875 +88107 0.00213623046875 +88108 0.09124755859375 +88109 0.004791259765625 +88110 0.10888671875 +88111 0.006866455078125 +88112 0.125518798828125 +88113 0.008544921875 +88114 0.15771484375 +88115 0.0098876953125 +88116 0.17828369140625 +88117 0.010650634765625 +88118 0.17108154296875 +88119 0.010650634765625 +88120 0.129974365234375 +88121 0.009857177734375 +88122 0.082427978515625 +88123 0.008544921875 +88124 0.027679443359375 +88125 0.00677490234375 +88126 -0.065643310546875 +88127 0.004425048828125 +88128 -0.15936279296875 +88129 0.001861572265625 +88130 -0.21307373046875 +88131 -0.000457763671875 +88132 -0.234649658203125 +88133 -0.00250244140625 +88134 -0.2001953125 +88135 -0.003997802734375 +88136 -0.119171142578125 +88137 -0.00494384765625 +88138 -0.024749755859375 +88139 -0.0054931640625 +88140 0.085784912109375 +88141 -0.005615234375 +88142 0.178131103515625 +88143 -0.0054931640625 +88144 0.215576171875 +88145 -0.005401611328125 +88146 0.211456298828125 +88147 -0.005218505859375 +88148 0.17523193359375 +88149 -0.004913330078125 +88150 0.128753662109375 +88151 -0.004302978515625 +88152 0.1019287109375 +88153 -0.003204345703125 +88154 0.0743408203125 +88155 -0.001861572265625 +88156 0.04327392578125 +88157 -0.00042724609375 +88158 0.038177490234375 +88159 0.001190185546875 +88160 0.076263427734375 +88161 0.003021240234375 +88162 0.14105224609375 +88163 0.0048828125 +88164 0.186431884765625 +88165 0.00634765625 +88166 0.188812255859375 +88167 0.007171630859375 +88168 0.1390380859375 +88169 0.00726318359375 +88170 0.041778564453125 +88171 0.006622314453125 +88172 -0.079437255859375 +88173 0.005462646484375 +88174 -0.219390869140625 +88175 0.00384521484375 +88176 -0.367828369140625 +88177 0.00189208984375 +88178 -0.494873046875 +88179 -9.1552734375e-05 +88180 -0.556243896484375 +88181 -0.001678466796875 +88182 -0.508697509765625 +88183 -0.002471923828125 +88184 -0.3756103515625 +88185 -0.002593994140625 +88186 -0.218902587890625 +88187 -0.002471923828125 +88188 -0.063751220703125 +88189 -0.0023193359375 +88190 0.091552734375 +88191 -0.002044677734375 +88192 0.23602294921875 +88193 -0.001678466796875 +88194 0.342987060546875 +88195 -0.001373291015625 +88196 0.39520263671875 +88197 -0.001251220703125 +88198 0.389373779296875 +88199 -0.001312255859375 +88200 0.324249267578125 +88201 -0.001556396484375 +88202 0.224090576171875 +88203 -0.001800537109375 +88204 0.124267578125 +88205 -0.001800537109375 +88206 0.037078857421875 +88207 -0.00152587890625 +88208 -0.010101318359375 +88209 -0.000823974609375 +88210 -0.019439697265625 +88211 0.00018310546875 +88212 -0.022796630859375 +88213 0.001190185546875 +88214 -0.001556396484375 +88215 0.002288818359375 +88216 0.056304931640625 +88217 0.003509521484375 +88218 0.106719970703125 +88219 0.004486083984375 +88220 0.096893310546875 +88221 0.004730224609375 +88222 0.042694091796875 +88223 0.00439453125 +88224 -0.018035888671875 +88225 0.0037841796875 +88226 -0.07586669921875 +88227 0.00299072265625 +88228 -0.11944580078125 +88229 0.002105712890625 +88230 -0.15972900390625 +88231 0.0010986328125 +88232 -0.202606201171875 +88233 0.0 +88234 -0.24859619140625 +88235 -0.001129150390625 +88236 -0.30517578125 +88237 -0.0023193359375 +88238 -0.36212158203125 +88239 -0.00347900390625 +88240 -0.39141845703125 +88241 -0.00433349609375 +88242 -0.35528564453125 +88243 -0.00457763671875 +88244 -0.249969482421875 +88245 -0.004119873046875 +88246 -0.092864990234375 +88247 -0.003082275390625 +88248 0.08905029296875 +88249 -0.001708984375 +88250 0.2352294921875 +88251 -0.000457763671875 +88252 0.318817138671875 +88253 0.00042724609375 +88254 0.358642578125 +88255 0.001068115234375 +88256 0.347747802734375 +88257 0.00140380859375 +88258 0.28564453125 +88259 0.001373291015625 +88260 0.223175048828125 +88261 0.0013427734375 +88262 0.196746826171875 +88263 0.0015869140625 +88264 0.179840087890625 +88265 0.001922607421875 +88266 0.155548095703125 +88267 0.002166748046875 +88268 0.151214599609375 +88269 0.00250244140625 +88270 0.156951904296875 +88271 0.002838134765625 +88272 0.13177490234375 +88273 0.002838134765625 +88274 0.100799560546875 +88275 0.002685546875 +88276 0.087127685546875 +88277 0.0025634765625 +88278 0.05487060546875 +88279 0.002197265625 +88280 -0.009002685546875 +88281 0.001495361328125 +88282 -0.10400390625 +88283 0.000457763671875 +88284 -0.229400634765625 +88285 -0.0008544921875 +88286 -0.35552978515625 +88287 -0.002197265625 +88288 -0.441925048828125 +88289 -0.003204345703125 +88290 -0.473846435546875 +88291 -0.0037841796875 +88292 -0.464813232421875 +88293 -0.003997802734375 +88294 -0.419097900390625 +88295 -0.003875732421875 +88296 -0.334320068359375 +88297 -0.00335693359375 +88298 -0.227935791015625 +88299 -0.002593994140625 +88300 -0.12347412109375 +88301 -0.00177001953125 +88302 -0.02764892578125 +88303 -0.000946044921875 +88304 0.077667236328125 +88305 0.0 +88306 0.2132568359375 +88307 0.001220703125 +88308 0.38885498046875 +88309 0.002777099609375 +88310 0.582794189453125 +88311 0.004486083984375 +88312 0.734039306640625 +88313 0.005828857421875 +88314 0.800140380859375 +88315 0.0064697265625 +88316 0.7783203125 +88317 0.006378173828125 +88318 0.6651611328125 +88319 0.00555419921875 +88320 0.45965576171875 +88321 0.003509521484375 +88322 0.199188232421875 +88323 0.0 +88324 -0.050689697265625 +88325 -0.00347900390625 +88326 -0.23297119140625 +88327 -0.00482177734375 +88328 -0.33013916015625 +88329 -0.003509521484375 +88330 -0.368408203125 +88331 -0.000732421875 +88332 -0.378936767578125 +88333 0.002105712890625 +88334 -0.376983642578125 +88335 0.00433349609375 +88336 -0.37969970703125 +88337 0.005218505859375 +88338 -0.391510009765625 +88339 0.004608154296875 +88340 -0.385345458984375 +88341 0.003662109375 +88342 -0.3419189453125 +88343 0.003265380859375 +88344 -0.28289794921875 +88345 0.002716064453125 +88346 -0.251617431640625 +88347 0.00042724609375 +88348 -0.266143798828125 +88349 -0.004058837890625 +88350 -0.273345947265625 +88351 -0.0084228515625 +88352 -0.216796875 +88353 -0.010223388671875 +88354 -0.128265380859375 +88355 -0.010498046875 +88356 -0.068145751953125 +88357 -0.011444091796875 +88358 -0.0430908203125 +88359 -0.013153076171875 +88360 -0.024444580078125 +88361 -0.014373779296875 +88362 0.020721435546875 +88363 -0.013702392578125 +88364 0.124481201171875 +88365 -0.00982666015625 +88366 0.25787353515625 +88367 -0.003936767578125 +88368 0.379119873046875 +88369 0.002197265625 +88370 0.47991943359375 +88371 0.0081787109375 +88372 0.5281982421875 +88373 0.012603759765625 +88374 0.511138916015625 +88375 0.01483154296875 +88376 0.456207275390625 +88377 0.0157470703125 +88378 0.407470703125 +88379 0.0169677734375 +88380 0.383758544921875 +88381 0.019073486328125 +88382 0.35687255859375 +88383 0.020721435546875 +88384 0.31182861328125 +88385 0.02117919921875 +88386 0.250885009765625 +88387 0.02044677734375 +88388 0.1654052734375 +88389 0.01812744140625 +88390 0.035247802734375 +88391 0.013336181640625 +88392 -0.142059326171875 +88393 0.006011962890625 +88394 -0.33563232421875 +88395 -0.0025634765625 +88396 -0.5345458984375 +88397 -0.011871337890625 +88398 -0.72186279296875 +88399 -0.021148681640625 +88400 -0.836669921875 +88401 -0.02783203125 +88402 -0.8326416015625 +88403 -0.02996826171875 +88404 -0.7296142578125 +88405 -0.028228759765625 +88406 -0.582550048828125 +88407 -0.024688720703125 +88408 -0.440093994140625 +88409 -0.02117919921875 +88410 -0.324310302734375 +88411 -0.018463134765625 +88412 -0.20147705078125 +88413 -0.01507568359375 +88414 -0.044647216796875 +88415 -0.009857177734375 +88416 0.103973388671875 +88417 -0.00445556640625 +88418 0.202392578125 +88419 -0.00054931640625 +88420 0.264495849609375 +88421 0.00238037109375 +88422 0.338897705078125 +88423 0.0062255859375 +88424 0.443817138671875 +88425 0.01165771484375 +88426 0.545074462890625 +88427 0.0172119140625 +88428 0.6173095703125 +88429 0.021820068359375 +88430 0.6524658203125 +88431 0.025054931640625 +88432 0.66339111328125 +88433 0.027313232421875 +88434 0.6561279296875 +88435 0.02874755859375 +88436 0.606781005859375 +88437 0.028289794921875 +88438 0.501190185546875 +88439 0.025299072265625 +88440 0.352783203125 +88441 0.020263671875 +88442 0.176544189453125 +88443 0.013763427734375 +88444 -0.034820556640625 +88445 0.0054931640625 +88446 -0.258209228515625 +88447 -0.003570556640625 +88448 -0.44244384765625 +88449 -0.011383056640625 +88450 -0.5753173828125 +88451 -0.017425537109375 +88452 -0.65203857421875 +88453 -0.021484375 +88454 -0.641632080078125 +88455 -0.022247314453125 +88456 -0.562164306640625 +88457 -0.020416259765625 +88458 -0.458038330078125 +88459 -0.017669677734375 +88460 -0.350555419921875 +88461 -0.014739990234375 +88462 -0.260528564453125 +88463 -0.01239013671875 +88464 -0.192108154296875 +88465 -0.0107421875 +88466 -0.141937255859375 +88467 -0.00958251953125 +88468 -0.1021728515625 +88469 -0.008544921875 +88470 -0.062896728515625 +88471 -0.00726318359375 +88472 -0.011932373046875 +88473 -0.005218505859375 +88474 0.062835693359375 +88475 -0.001953125 +88476 0.148712158203125 +88477 0.00201416015625 +88478 0.241729736328125 +88479 0.0064697265625 +88480 0.34912109375 +88481 0.01165771484375 +88482 0.457305908203125 +88483 0.0169677734375 +88484 0.54388427734375 +88485 0.02142333984375 +88486 0.5728759765625 +88487 0.0235595703125 +88488 0.506591796875 +88489 0.021820068359375 +88490 0.351226806640625 +88491 0.016387939453125 +88492 0.146514892578125 +88493 0.008819580078125 +88494 -0.05523681640625 +88495 0.001190185546875 +88496 -0.21624755859375 +88497 -0.004974365234375 +88498 -0.334930419921875 +88499 -0.009613037109375 +88500 -0.402984619140625 +88501 -0.01239013671875 +88502 -0.4412841796875 +88503 -0.014129638671875 +88504 -0.49578857421875 +88505 -0.016693115234375 +88506 -0.5601806640625 +88507 -0.019775390625 +88508 -0.600738525390625 +88509 -0.02197265625 +88510 -0.584228515625 +88511 -0.02197265625 +88512 -0.47930908203125 +88513 -0.018463134765625 +88514 -0.27935791015625 +88515 -0.01116943359375 +88516 -0.0089111328125 +88517 -0.001007080078125 +88518 0.268798828125 +88519 0.009490966796875 +88520 0.482818603515625 +88521 0.01751708984375 +88522 0.60369873046875 +88523 0.021881103515625 +88524 0.650421142578125 +88525 0.023406982421875 +88526 0.66400146484375 +88527 0.023773193359375 +88528 0.6414794921875 +88529 0.022857666015625 +88530 0.572540283203125 +88531 0.020233154296875 +88532 0.498138427734375 +88533 0.01751708984375 +88534 0.439453125 +88535 0.01556396484375 +88536 0.375518798828125 +88537 0.01348876953125 +88538 0.274505615234375 +88539 0.010009765625 +88540 0.1087646484375 +88541 0.00396728515625 +88542 -0.099395751953125 +88543 -0.00372314453125 +88544 -0.3182373046875 +88545 -0.0118408203125 +88546 -0.5489501953125 +88547 -0.020477294921875 +88548 -0.7738037109375 +88549 -0.028900146484375 +88550 -0.86383056640625 +88551 -0.035064697265625 +88552 -0.870391845703125 +88553 -0.03765869140625 +88554 -0.86895751953125 +88555 -0.03741455078125 +88556 -0.861053466796875 +88557 -0.034881591796875 +88558 -0.765869140625 +88559 -0.02935791015625 +88560 -0.5301513671875 +88561 -0.020416259765625 +88562 -0.214691162109375 +88563 -0.00830078125 +88564 0.137359619140625 +88565 0.005279541015625 +88566 0.474822998046875 +88567 0.018310546875 +88568 0.76239013671875 +88569 0.0294189453125 +88570 0.867462158203125 +88571 0.03753662109375 +88572 0.870361328125 +88573 0.042724609375 +88574 0.86480712890625 +88575 0.044525146484375 +88576 0.831817626953125 +88577 0.0433349609375 +88578 0.677581787109375 +88579 0.040252685546875 +88580 0.495880126953125 +88581 0.035491943359375 +88582 0.30767822265625 +88583 0.03009033203125 +88584 0.116180419921875 +88585 0.023834228515625 +88586 -0.110748291015625 +88587 0.014007568359375 +88588 -0.381805419921875 +88589 -0.000335693359375 +88590 -0.6572265625 +88591 -0.0166015625 +88592 -0.857421875 +88593 -0.030914306640625 +88594 -0.870391845703125 +88595 -0.04058837890625 +88596 -0.870391845703125 +88597 -0.045440673828125 +88598 -0.86444091796875 +88599 -0.047637939453125 +88600 -0.85723876953125 +88601 -0.0499267578125 +88602 -0.790008544921875 +88603 -0.051055908203125 +88604 -0.62847900390625 +88605 -0.04705810546875 +88606 -0.3956298828125 +88607 -0.03759765625 +88608 -0.126708984375 +88609 -0.024810791015625 +88610 0.150115966796875 +88611 -0.0103759765625 +88612 0.424041748046875 +88613 0.005157470703125 +88614 0.670623779296875 +88615 0.02020263671875 +88616 0.854522705078125 +88617 0.032379150390625 +88618 0.866485595703125 +88619 0.040771484375 +88620 0.86920166015625 +88621 0.04461669921875 +88622 0.8653564453125 +88623 0.0455322265625 +88624 0.857147216796875 +88625 0.044708251953125 +88626 0.766845703125 +88627 0.0421142578125 +88628 0.628509521484375 +88629 0.038177490234375 +88630 0.462127685546875 +88631 0.03240966796875 +88632 0.297210693359375 +88633 0.026611328125 +88634 0.14862060546875 +88635 0.021514892578125 +88636 -0.00537109375 +88637 0.0152587890625 +88638 -0.15753173828125 +88639 0.008148193359375 +88640 -0.31304931640625 +88641 -0.0003662109375 +88642 -0.48876953125 +88643 -0.0115966796875 +88644 -0.6416015625 +88645 -0.0224609375 +88646 -0.751373291015625 +88647 -0.031494140625 +88648 -0.84619140625 +88649 -0.040618896484375 +88650 -0.861297607421875 +88651 -0.048980712890625 +88652 -0.863250732421875 +88653 -0.05438232421875 +88654 -0.856597900390625 +88655 -0.05462646484375 +88656 -0.7498779296875 +88657 -0.050628662109375 +88658 -0.624542236328125 +88659 -0.046539306640625 +88660 -0.47808837890625 +88661 -0.0406494140625 +88662 -0.253387451171875 +88663 -0.02862548828125 +88664 0.003692626953125 +88665 -0.013580322265625 +88666 0.2257080078125 +88667 -0.00018310546875 +88668 0.427154541015625 +88669 0.0126953125 +88670 0.643218994140625 +88671 0.02764892578125 +88672 0.855926513671875 +88673 0.044219970703125 +88674 0.870361328125 +88675 0.058502197265625 +88676 0.870361328125 +88677 0.067108154296875 +88678 0.862762451171875 +88679 0.070709228515625 +88680 0.79669189453125 +88681 0.0692138671875 +88682 0.595794677734375 +88683 0.062042236328125 +88684 0.362152099609375 +88685 0.051239013671875 +88686 0.1270751953125 +88687 0.038818359375 +88688 -0.086944580078125 +88689 0.02618408203125 +88690 -0.2784423828125 +88691 0.0133056640625 +88692 -0.484832763671875 +88693 -0.00244140625 +88694 -0.729583740234375 +88695 -0.022674560546875 +88696 -0.86688232421875 +88697 -0.043975830078125 +88698 -0.870391845703125 +88699 -0.061981201171875 +88700 -0.86859130859375 +88701 -0.076507568359375 +88702 -0.86279296875 +88703 -0.087615966796875 +88704 -0.817962646484375 +88705 -0.092864990234375 +88706 -0.6116943359375 +88707 -0.089111328125 +88708 -0.3128662109375 +88709 -0.075897216796875 +88710 0.039398193359375 +88711 -0.0556640625 +88712 0.422821044921875 +88713 -0.02984619140625 +88714 0.805145263671875 +88715 -0.000762939453125 +88716 0.870361328125 +88717 0.026763916015625 +88718 0.870361328125 +88719 0.04876708984375 +88720 0.860015869140625 +88721 0.0645751953125 +88722 0.727935791015625 +88723 0.07379150390625 +88724 0.48114013671875 +88725 0.076202392578125 +88726 0.2059326171875 +88727 0.07373046875 +88728 -0.06103515625 +88729 0.068145751953125 +88730 -0.29913330078125 +88731 0.060302734375 +88732 -0.516204833984375 +88733 0.04925537109375 +88734 -0.7252197265625 +88735 0.033966064453125 +88736 -0.85980224609375 +88737 0.016265869140625 +88738 -0.870391845703125 +88739 -0.001373291015625 +88740 -0.870391845703125 +88741 -0.016845703125 +88742 -0.858062744140625 +88743 -0.026702880859375 +88744 -0.673004150390625 +88745 -0.03076171875 +88746 -0.42694091796875 +88747 -0.032928466796875 +88748 -0.2100830078125 +88749 -0.0364990234375 +88750 -0.0362548828125 +88751 -0.041412353515625 +88752 0.10943603515625 +88753 -0.04571533203125 +88754 0.23516845703125 +88755 -0.048065185546875 +88756 0.373687744140625 +88757 -0.04559326171875 +88758 0.517791748046875 +88759 -0.03851318359375 +88760 0.602783203125 +88761 -0.03143310546875 +88762 0.635711669921875 +88763 -0.02398681640625 +88764 0.655181884765625 +88765 -0.013824462890625 +88766 0.65948486328125 +88767 -0.00164794921875 +88768 0.651275634765625 +88769 0.011962890625 +88770 0.61846923828125 +88771 0.0252685546875 +88772 0.53753662109375 +88773 0.035675048828125 +88774 0.404144287109375 +88775 0.041961669921875 +88776 0.22186279296875 +88777 0.043548583984375 +88778 0.003997802734375 +88779 0.040679931640625 +88780 -0.22100830078125 +88781 0.034759521484375 +88782 -0.42449951171875 +88783 0.02734375 +88784 -0.579833984375 +88785 0.02001953125 +88786 -0.641876220703125 +88787 0.01593017578125 +88788 -0.6177978515625 +88789 0.0146484375 +88790 -0.575531005859375 +88791 0.01153564453125 +88792 -0.526336669921875 +88793 0.006195068359375 +88794 -0.42645263671875 +88795 0.002349853515625 +88796 -0.2581787109375 +88797 0.00189208984375 +88798 -0.068695068359375 +88799 0.002197265625 +88800 0.09222412109375 +88801 0.00042724609375 +88802 0.232147216796875 +88803 -0.0020751953125 +88804 0.3509521484375 +88805 -0.00469970703125 +88806 0.410064697265625 +88807 -0.0096435546875 +88808 0.372955322265625 +88809 -0.019073486328125 +88810 0.2554931640625 +88811 -0.03155517578125 +88812 0.10711669921875 +88813 -0.04339599609375 +88814 -0.052886962890625 +88815 -0.053192138671875 +88816 -0.186279296875 +88817 -0.058380126953125 +88818 -0.23291015625 +88819 -0.054962158203125 +88820 -0.209442138671875 +88821 -0.044586181640625 +88822 -0.174163818359375 +88823 -0.031982421875 +88824 -0.126739501953125 +88825 -0.0177001953125 +88826 -0.048126220703125 +88827 -0.001007080078125 +88828 0.0426025390625 +88829 0.016082763671875 +88830 0.10748291015625 +88831 0.030303955078125 +88832 0.1409912109375 +88833 0.04119873046875 +88834 0.19708251953125 +88835 0.05303955078125 +88836 0.273651123046875 +88837 0.0645751953125 +88838 0.31768798828125 +88839 0.070465087890625 +88840 0.341094970703125 +88841 0.071990966796875 +88842 0.368011474609375 +88843 0.071746826171875 +88844 0.37249755859375 +88845 0.0673828125 +88846 0.30072021484375 +88847 0.05389404296875 +88848 0.1517333984375 +88849 0.031585693359375 +88850 -0.01470947265625 +88851 0.006866455078125 +88852 -0.1883544921875 +88853 -0.01873779296875 +88854 -0.372711181640625 +88855 -0.04510498046875 +88856 -0.51397705078125 +88857 -0.066436767578125 +88858 -0.57177734375 +88859 -0.078338623046875 +88860 -0.53948974609375 +88861 -0.079833984375 +88862 -0.43511962890625 +88863 -0.072509765625 +88864 -0.2962646484375 +88865 -0.060028076171875 +88866 -0.161102294921875 +88867 -0.046173095703125 +88868 -0.0435791015625 +88869 -0.03240966796875 +88870 0.060394287109375 +88871 -0.01849365234375 +88872 0.13665771484375 +88873 -0.006103515625 +88874 0.170135498046875 +88875 0.0029296875 +88876 0.16552734375 +88877 0.008758544921875 +88878 0.15728759765625 +88879 0.01446533203125 +88880 0.150787353515625 +88881 0.020233154296875 +88882 0.12200927734375 +88883 0.0233154296875 +88884 0.080108642578125 +88885 0.0242919921875 +88886 0.05126953125 +88887 0.025543212890625 +88888 0.062896728515625 +88889 0.02960205078125 +88890 0.09271240234375 +88891 0.03411865234375 +88892 0.092987060546875 +88893 0.0343017578125 +88894 0.07855224609375 +88895 0.031646728515625 +88896 0.06427001953125 +88897 0.027740478515625 +88898 0.0347900390625 +88899 0.021209716796875 +88900 -0.01171875 +88901 0.012115478515625 +88902 -0.056060791015625 +88903 0.002655029296875 +88904 -0.055511474609375 +88905 -0.002593994140625 +88906 -0.010467529296875 +88907 -0.003387451171875 +88908 0.02508544921875 +88909 -0.00482177734375 +88910 0.025665283203125 +88911 -0.009185791015625 +88912 0.017333984375 +88913 -0.013641357421875 +88914 0.00189208984375 +88915 -0.017822265625 +88916 -0.03173828125 +88917 -0.022735595703125 +88918 -0.071502685546875 +88919 -0.027130126953125 +88920 -0.13543701171875 +88921 -0.0328369140625 +88922 -0.219970703125 +88923 -0.03955078125 +88924 -0.300506591796875 +88925 -0.044891357421875 +88926 -0.376312255859375 +88927 -0.048980712890625 +88928 -0.416107177734375 +88929 -0.048919677734375 +88930 -0.371124267578125 +88931 -0.0400390625 +88932 -0.242279052734375 +88933 -0.022705078125 +88934 -0.069732666015625 +88935 -0.001190185546875 +88936 0.125640869140625 +88937 0.02215576171875 +88938 0.31268310546875 +88939 0.044036865234375 +88940 0.45501708984375 +88941 0.060638427734375 +88942 0.554779052734375 +88943 0.072052001953125 +88944 0.61065673828125 +88945 0.078125 +88946 0.610931396484375 +88947 0.07769775390625 +88948 0.531463623046875 +88949 0.068389892578125 +88950 0.3883056640625 +88951 0.051910400390625 +88952 0.23468017578125 +88953 0.03375244140625 +88954 0.095245361328125 +88955 0.016571044921875 +88956 -0.00396728515625 +88957 0.003143310546875 +88958 -0.04852294921875 +88959 -0.0048828125 +88960 -0.055145263671875 +88961 -0.009002685546875 +88962 -0.0758056640625 +88963 -0.014190673828125 +88964 -0.138702392578125 +88965 -0.023101806640625 +88966 -0.209197998046875 +88967 -0.03216552734375 +88968 -0.289031982421875 +88969 -0.041473388671875 +88970 -0.37884521484375 +88971 -0.051055908203125 +88972 -0.456329345703125 +88973 -0.05865478515625 +88974 -0.51641845703125 +88975 -0.06378173828125 +88976 -0.519287109375 +88977 -0.062530517578125 +88978 -0.458251953125 +88979 -0.0543212890625 +88980 -0.384796142578125 +88981 -0.044464111328125 +88982 -0.323699951171875 +88983 -0.035552978515625 +88984 -0.269287109375 +88985 -0.02716064453125 +88986 -0.1951904296875 +88987 -0.016815185546875 +88988 -0.100006103515625 +88989 -0.00457763671875 +88990 -0.01055908203125 +88991 0.0067138671875 +88992 0.1033935546875 +88993 0.01995849609375 +88994 0.24908447265625 +88995 0.035797119140625 +88996 0.373199462890625 +88997 0.048858642578125 +88998 0.45806884765625 +88999 0.057342529296875 +89000 0.511474609375 +89001 0.062042236328125 +89002 0.565399169921875 +89003 0.066192626953125 +89004 0.61138916015625 +89005 0.069061279296875 +89006 0.5897216796875 +89007 0.064788818359375 +89008 0.4906005859375 +89009 0.052520751953125 +89010 0.33148193359375 +89011 0.03411865234375 +89012 0.147796630859375 +89013 0.013275146484375 +89014 -0.01873779296875 +89015 -0.00567626953125 +89016 -0.140289306640625 +89017 -0.01983642578125 +89018 -0.191986083984375 +89019 -0.026611328125 +89020 -0.184295654296875 +89021 -0.027008056640625 +89022 -0.161834716796875 +89023 -0.025421142578125 +89024 -0.166595458984375 +89025 -0.0260009765625 +89026 -0.19390869140625 +89027 -0.028289794921875 +89028 -0.22442626953125 +89029 -0.0303955078125 +89030 -0.279754638671875 +89031 -0.0345458984375 +89032 -0.3389892578125 +89033 -0.038726806640625 +89034 -0.3543701171875 +89035 -0.03826904296875 +89036 -0.348175048828125 +89037 -0.0355224609375 +89038 -0.32598876953125 +89039 -0.03118896484375 +89040 -0.2581787109375 +89041 -0.02239990234375 +89042 -0.139801025390625 +89043 -0.008758544921875 +89044 0.014617919921875 +89045 0.008148193359375 +89046 0.144378662109375 +89047 0.02215576171875 +89048 0.221038818359375 +89049 0.0303955078125 +89050 0.27069091796875 +89051 0.03546142578125 +89052 0.294036865234375 +89053 0.03741455078125 +89054 0.311767578125 +89055 0.038360595703125 +89056 0.339141845703125 +89057 0.0399169921875 +89058 0.360260009765625 +89059 0.040618896484375 +89060 0.360504150390625 +89061 0.039093017578125 +89062 0.308380126953125 +89063 0.032135009765625 +89064 0.18170166015625 +89065 0.01751708984375 +89066 0.0047607421875 +89067 -0.00213623046875 +89068 -0.17559814453125 +89069 -0.02191162109375 +89070 -0.3143310546875 +89071 -0.037109375 +89072 -0.36785888671875 +89073 -0.04315185546875 +89074 -0.36248779296875 +89075 -0.042755126953125 +89076 -0.343536376953125 +89077 -0.0406494140625 +89078 -0.3018798828125 +89079 -0.035919189453125 +89080 -0.231414794921875 +89081 -0.0279541015625 +89082 -0.117645263671875 +89083 -0.015289306640625 +89084 0.007049560546875 +89085 -0.0013427734375 +89086 0.087982177734375 +89087 0.00811767578125 +89088 0.13946533203125 +89089 0.014495849609375 +89090 0.17425537109375 +89091 0.01910400390625 +89092 0.188201904296875 +89093 0.021514892578125 +89094 0.171234130859375 +89095 0.020172119140625 +89096 0.118438720703125 +89097 0.014251708984375 +89098 0.05706787109375 +89099 0.00732421875 +89100 -0.010711669921875 +89101 -0.00048828125 +89102 -0.0914306640625 +89103 -0.010162353515625 +89104 -0.162322998046875 +89105 -0.018707275390625 +89106 -0.194549560546875 +89107 -0.022247314453125 +89108 -0.1492919921875 +89109 -0.01556396484375 +89110 -0.02166748046875 +89111 0.001983642578125 +89112 0.124053955078125 +89113 0.021636962890625 +89114 0.211151123046875 +89115 0.032989501953125 +89116 0.240447998046875 +89117 0.036224365234375 +89118 0.242218017578125 +89119 0.0355224609375 +89120 0.2257080078125 +89121 0.032196044921875 +89122 0.194366455078125 +89123 0.02679443359375 +89124 0.115509033203125 +89125 0.01495361328125 +89126 0.0128173828125 +89127 0.0 +89128 -0.053802490234375 +89129 -0.009857177734375 +89130 -0.110626220703125 +89131 -0.0181884765625 +89132 -0.199493408203125 +89133 -0.030670166015625 +89134 -0.29437255859375 +89135 -0.043731689453125 +89136 -0.33221435546875 +89137 -0.048797607421875 +89138 -0.27972412109375 +89139 -0.041351318359375 +89140 -0.185333251953125 +89141 -0.02801513671875 +89142 -0.128204345703125 +89143 -0.01959228515625 +89144 -0.115692138671875 +89145 -0.017120361328125 +89146 -0.116455078125 +89147 -0.016387939453125 +89148 -0.105926513671875 +89149 -0.01409912109375 +89150 -0.053955078125 +89151 -0.006195068359375 +89152 0.048797607421875 +89153 0.008514404296875 +89154 0.157318115234375 +89155 0.023895263671875 +89156 0.212005615234375 +89157 0.03179931640625 +89158 0.218475341796875 +89159 0.032958984375 +89160 0.23724365234375 +89161 0.035614013671875 +89162 0.30535888671875 +89163 0.0447998046875 +89164 0.38128662109375 +89165 0.05487060546875 +89166 0.404449462890625 +89167 0.05755615234375 +89168 0.3944091796875 +89169 0.055572509765625 +89170 0.3885498046875 +89171 0.054046630859375 +89172 0.362640380859375 +89173 0.049774169921875 +89174 0.27362060546875 +89175 0.03692626953125 +89176 0.11712646484375 +89177 0.01495361328125 +89178 -0.054901123046875 +89179 -0.009002685546875 +89180 -0.19085693359375 +89181 -0.027923583984375 +89182 -0.28570556640625 +89183 -0.041107177734375 +89184 -0.339263916015625 +89185 -0.04852294921875 +89186 -0.3775634765625 +89187 -0.0537109375 +89188 -0.445709228515625 +89189 -0.06280517578125 +89190 -0.535064697265625 +89191 -0.074615478515625 +89192 -0.629058837890625 +89193 -0.086944580078125 +89194 -0.697601318359375 +89195 -0.095703125 +89196 -0.70391845703125 +89197 -0.095947265625 +89198 -0.6424560546875 +89199 -0.086944580078125 +89200 -0.491241455078125 +89201 -0.06573486328125 +89202 -0.265716552734375 +89203 -0.03448486328125 +89204 -0.023712158203125 +89205 -0.001068115234375 +89206 0.201751708984375 +89207 0.02996826171875 +89208 0.375823974609375 +89209 0.053863525390625 +89210 0.485076904296875 +89211 0.06878662109375 +89212 0.56884765625 +89213 0.080078125 +89214 0.634765625 +89215 0.088775634765625 +89216 0.63763427734375 +89217 0.088775634765625 +89218 0.5660400390625 +89219 0.07855224609375 +89220 0.4720458984375 +89221 0.06524658203125 +89222 0.40692138671875 +89223 0.055816650390625 +89224 0.3778076171875 +89225 0.05126953125 +89226 0.376953125 +89227 0.05059814453125 +89228 0.371978759765625 +89229 0.049407958984375 +89230 0.313140869140625 +89231 0.04095458984375 +89232 0.184417724609375 +89233 0.0230712890625 +89234 0.011199951171875 +89235 -0.000701904296875 +89236 -0.171051025390625 +89237 -0.025543212890625 +89238 -0.33740234375 +89239 -0.04803466796875 +89240 -0.47198486328125 +89241 -0.0660400390625 +89242 -0.560394287109375 +89243 -0.07763671875 +89244 -0.58056640625 +89245 -0.079864501953125 +89246 -0.54754638671875 +89247 -0.074798583984375 +89248 -0.508575439453125 +89249 -0.06890869140625 +89250 -0.459503173828125 +89251 -0.061676025390625 +89252 -0.394378662109375 +89253 -0.05230712890625 +89254 -0.35260009765625 +89255 -0.046173095703125 +89256 -0.31170654296875 +89257 -0.04022216796875 +89258 -0.197418212890625 +89259 -0.024383544921875 +89260 -0.007965087890625 +89261 0.00152587890625 +89262 0.207489013671875 +89263 0.03082275390625 +89264 0.409210205078125 +89265 0.05810546875 +89266 0.57208251953125 +89267 0.0799560546875 +89268 0.66595458984375 +89269 0.092315673828125 +89270 0.65875244140625 +89271 0.090850830078125 +89272 0.56744384765625 +89273 0.077880859375 +89274 0.431396484375 +89275 0.058807373046875 +89276 0.29443359375 +89277 0.039642333984375 +89278 0.182464599609375 +89279 0.023895263671875 +89280 0.06365966796875 +89281 0.007293701171875 +89282 -0.075958251953125 +89283 -0.01202392578125 +89284 -0.189422607421875 +89285 -0.027679443359375 +89286 -0.271942138671875 +89287 -0.038970947265625 +89288 -0.342529296875 +89289 -0.048492431640625 +89290 -0.364166259765625 +89291 -0.051239013671875 +89292 -0.327239990234375 +89293 -0.045928955078125 +89294 -0.2769775390625 +89295 -0.038726806640625 +89296 -0.253692626953125 +89297 -0.035125732421875 +89298 -0.24365234375 +89299 -0.03326416015625 +89300 -0.1983642578125 +89301 -0.026580810546875 +89302 -0.116241455078125 +89303 -0.014892578125 +89304 -0.036834716796875 +89305 -0.003631591796875 +89306 0.034881591796875 +89307 0.006500244140625 +89308 0.09124755859375 +89309 0.014434814453125 +89310 0.10888671875 +89311 0.016998291015625 +89312 0.125518798828125 +89313 0.019287109375 +89314 0.15771484375 +89315 0.0235595703125 +89316 0.17828369140625 +89317 0.026123046875 +89318 0.17108154296875 +89319 0.024810791015625 +89320 0.129974365234375 +89321 0.018798828125 +89322 0.082427978515625 +89323 0.011871337890625 +89324 0.027679443359375 +89325 0.003936767578125 +89326 -0.065643310546875 +89327 -0.009185791015625 +89328 -0.15936279296875 +89329 -0.02227783203125 +89330 -0.21307373046875 +89331 -0.029876708984375 +89332 -0.234649658203125 +89333 -0.03302001953125 +89334 -0.2001953125 +89335 -0.028472900390625 +89336 -0.119171142578125 +89337 -0.017486572265625 +89338 -0.024749755859375 +89339 -0.00457763671875 +89340 0.085784912109375 +89341 0.010589599609375 +89342 0.178131103515625 +89343 0.0233154296875 +89344 0.215576171875 +89345 0.02838134765625 +89346 0.211456298828125 +89347 0.0274658203125 +89348 0.17523193359375 +89349 0.021759033203125 +89350 0.128753662109375 +89351 0.01483154296875 +89352 0.1019287109375 +89353 0.0115966796875 +89354 0.0743408203125 +89355 0.008544921875 +89356 0.04327392578125 +89357 0.005096435546875 +89358 0.038177490234375 +89359 0.006072998046875 +89360 0.076263427734375 +89361 0.014251708984375 +89362 0.14105224609375 +89363 0.0267333984375 +89364 0.186431884765625 +89365 0.035675048828125 +89366 0.188812255859375 +89367 0.037078857421875 +89368 0.1390380859375 +89369 0.029388427734375 +89370 0.041778564453125 +89371 0.013336181640625 +89372 -0.079437255859375 +89373 -0.007080078125 +89374 -0.219390869140625 +89375 -0.030975341796875 +89376 -0.367828369140625 +89377 -0.0565185546875 +89378 -0.494873046875 +89379 -0.078704833984375 +89380 -0.556243896484375 +89381 -0.090057373046875 +89382 -0.508697509765625 +89383 -0.083251953125 +89384 -0.3756103515625 +89385 -0.0621337890625 +89386 -0.218902587890625 +89387 -0.03704833984375 +89388 -0.063751220703125 +89389 -0.01214599609375 +89390 0.091552734375 +89391 0.01287841796875 +89392 0.23602294921875 +89393 0.0362548828125 +89394 0.342987060546875 +89395 0.053497314453125 +89396 0.39520263671875 +89397 0.061767578125 +89398 0.389373779296875 +89399 0.060546875 +89400 0.324249267578125 +89401 0.049652099609375 +89402 0.224090576171875 +89403 0.033172607421875 +89404 0.124267578125 +89405 0.016998291015625 +89406 0.037078857421875 +89407 0.003143310546875 +89408 -0.010101318359375 +89409 -0.003814697265625 +89410 -0.019439697265625 +89411 -0.004302978515625 +89412 -0.022796630859375 +89413 -0.003753662109375 +89414 -0.001556396484375 +89415 0.000885009765625 +89416 0.056304931640625 +89417 0.01153564453125 +89418 0.106719970703125 +89419 0.020782470703125 +89420 0.096893310546875 +89421 0.019744873046875 +89422 0.042694091796875 +89423 0.01104736328125 +89424 -0.018035888671875 +89425 0.001007080078125 +89426 -0.07586669921875 +89427 -0.00872802734375 +89428 -0.11944580078125 +89429 -0.016265869140625 +89430 -0.15972900390625 +89431 -0.023406982421875 +89432 -0.202606201171875 +89433 -0.0311279296875 +89434 -0.24859619140625 +89435 -0.039459228515625 +89436 -0.30517578125 +89437 -0.049652099609375 +89438 -0.36212158203125 +89439 -0.0599365234375 +89440 -0.39141845703125 +89441 -0.065582275390625 +89442 -0.35528564453125 +89443 -0.0601806640625 +89444 -0.249969482421875 +89445 -0.0430908203125 +89446 -0.092864990234375 +89447 -0.0172119140625 +89448 0.08905029296875 +89449 0.012939453125 +89450 0.2352294921875 +89451 0.037200927734375 +89452 0.318817138671875 +89453 0.05108642578125 +89454 0.358642578125 +89455 0.057769775390625 +89456 0.347747802734375 +89457 0.056060791015625 +89458 0.28564453125 +89459 0.045867919921875 +89460 0.223175048828125 +89461 0.035736083984375 +89462 0.196746826171875 +89463 0.03173828125 +89464 0.179840087890625 +89465 0.029388427734375 +89466 0.155548095703125 +89467 0.02581787109375 +89468 0.151214599609375 +89469 0.025604248046875 +89470 0.156951904296875 +89471 0.027069091796875 +89472 0.13177490234375 +89473 0.023284912109375 +89474 0.100799560546875 +89475 0.018463134765625 +89476 0.087127685546875 +89477 0.016448974609375 +89478 0.05487060546875 +89479 0.011199951171875 +89480 -0.009002685546875 +89481 0.00054931640625 +89482 -0.10400390625 +89483 -0.01544189453125 +89484 -0.229400634765625 +89485 -0.03662109375 +89486 -0.35552978515625 +89487 -0.0579833984375 +89488 -0.441925048828125 +89489 -0.072723388671875 +89490 -0.473846435546875 +89491 -0.078369140625 +89492 -0.464813232421875 +89493 -0.077178955078125 +89494 -0.419097900390625 +89495 -0.069854736328125 +89496 -0.334320068359375 +89497 -0.05596923828125 +89498 -0.227935791015625 +89499 -0.038421630859375 +89500 -0.12347412109375 +89501 -0.021148681640625 +89502 -0.02764892578125 +89503 -0.0052490234375 +89504 0.077667236328125 +89505 0.01226806640625 +89506 0.2132568359375 +89507 0.034912109375 +89508 0.38885498046875 +89509 0.0643310546875 +89510 0.582794189453125 +89511 0.096893310546875 +89512 0.734039306640625 +89513 0.122344970703125 +89514 0.800140380859375 +89515 0.133514404296875 +89516 0.7783203125 +89517 0.129974365234375 +89518 0.6651611328125 +89519 0.111114501953125 +89520 0.45965576171875 +89521 0.0767822265625 +89522 0.199188232421875 +89523 0.03326416015625 +89524 -0.050689697265625 +89525 -0.008453369140625 +89526 -0.23297119140625 +89527 -0.038787841796875 +89528 -0.33013916015625 +89529 -0.054840087890625 +89530 -0.368408203125 +89531 -0.061004638671875 +89532 -0.378936767578125 +89533 -0.062530517578125 +89534 -0.376983642578125 +89535 -0.062042236328125 +89536 -0.37969970703125 +89537 -0.062408447265625 +89538 -0.391510009765625 +89539 -0.064361572265625 +89540 -0.385345458984375 +89541 -0.0633544921875 +89542 -0.3419189453125 +89543 -0.056121826171875 +89544 -0.28289794921875 +89545 -0.046295166015625 +89546 -0.251617431640625 +89547 -0.041168212890625 +89548 -0.266143798828125 +89549 -0.04376220703125 +89550 -0.273345947265625 +89551 -0.045135498046875 +89552 -0.216796875 +89553 -0.03582763671875 +89554 -0.128265380859375 +89555 -0.0211181640625 +89556 -0.068145751953125 +89557 -0.011138916015625 +89558 -0.0430908203125 +89559 -0.007049560546875 +89560 -0.024444580078125 +89561 -0.003997802734375 +89562 0.020721435546875 +89563 0.003509521484375 +89564 0.124481201171875 +89565 0.020843505859375 +89566 0.25787353515625 +89567 0.04315185546875 +89568 0.379119873046875 +89569 0.06341552734375 +89570 0.47991943359375 +89571 0.08026123046875 +89572 0.5281982421875 +89573 0.08831787109375 +89574 0.511138916015625 +89575 0.08538818359375 +89576 0.456207275390625 +89577 0.07611083984375 +89578 0.407470703125 +89579 0.067901611328125 +89580 0.383758544921875 +89581 0.063934326171875 +89582 0.35687255859375 +89583 0.0594482421875 +89584 0.31182861328125 +89585 0.051910400390625 +89586 0.250885009765625 +89587 0.04168701171875 +89588 0.1654052734375 +89589 0.027374267578125 +89590 0.035247802734375 +89591 0.005584716796875 +89592 -0.142059326171875 +89593 -0.024078369140625 +89594 -0.33563232421875 +89595 -0.056427001953125 +89596 -0.5345458984375 +89597 -0.089630126953125 +89598 -0.72186279296875 +89599 -0.120849609375 +89600 -0.836669921875 +89601 -0.139404296875 +89602 -0.8326416015625 +89603 -0.13690185546875 +89604 -0.7296142578125 +89605 -0.117279052734375 +89606 -0.582550048828125 +89607 -0.09112548828125 +89608 -0.440093994140625 +89609 -0.067657470703125 +89610 -0.324310302734375 +89611 -0.050750732421875 +89612 -0.20147705078125 +89613 -0.033111572265625 +89614 -0.044647216796875 +89615 -0.00885009765625 +89616 0.103973388671875 +89617 0.0140380859375 +89618 0.202392578125 +89619 0.027557373046875 +89620 0.264495849609375 +89621 0.0347900390625 +89622 0.338897705078125 +89623 0.045745849609375 +89624 0.443817138671875 +89625 0.064208984375 +89626 0.545074462890625 +89627 0.08343505859375 +89628 0.6173095703125 +89629 0.09832763671875 +89630 0.6524658203125 +89631 0.10723876953125 +89632 0.66339111328125 +89633 0.112548828125 +89634 0.6561279296875 +89635 0.115264892578125 +89636 0.606781005859375 +89637 0.110321044921875 +89638 0.501190185546875 +89639 0.094573974609375 +89640 0.352783203125 +89641 0.070404052734375 +89642 0.176544189453125 +89643 0.04052734375 +89644 -0.034820556640625 +89645 0.003204345703125 +89646 -0.258209228515625 +89647 -0.03717041015625 +89648 -0.44244384765625 +89649 -0.070587158203125 +89650 -0.5753173828125 +89651 -0.09478759765625 +89652 -0.65203857421875 +89653 -0.108917236328125 +89654 -0.641632080078125 +89655 -0.106781005859375 +89656 -0.562164306640625 +89657 -0.092010498046875 +89658 -0.458038330078125 +89659 -0.073394775390625 +89660 -0.350555419921875 +89661 -0.055023193359375 +89662 -0.260528564453125 +89663 -0.040863037109375 +89664 -0.192108154296875 +89665 -0.031524658203125 +89666 -0.141937255859375 +89667 -0.02606201171875 +89668 -0.1021728515625 +89669 -0.02264404296875 +89670 -0.062896728515625 +89671 -0.01904296875 +89672 -0.011932373046875 +89673 -0.012603759765625 +89674 0.062835693359375 +89675 -0.000701904296875 +89676 0.148712158203125 +89677 0.014251708984375 +89678 0.241729736328125 +89679 0.031524658203125 +89680 0.34912109375 +89681 0.052642822265625 +89682 0.457305908203125 +89683 0.07489013671875 +89684 0.54388427734375 +89685 0.09368896484375 +89686 0.5728759765625 +89687 0.101776123046875 +89688 0.506591796875 +89689 0.0914306640625 +89690 0.351226806640625 +89691 0.063720703125 +89692 0.146514892578125 +89693 0.026397705078125 +89694 -0.05523681640625 +89695 -0.01025390625 +89696 -0.21624755859375 +89697 -0.03887939453125 +89698 -0.334930419921875 +89699 -0.059356689453125 +89700 -0.402984619140625 +89701 -0.070159912109375 +89702 -0.4412841796875 +89703 -0.07562255859375 +89704 -0.49578857421875 +89705 -0.085052490234375 +89706 -0.5601806640625 +89707 -0.097259521484375 +89708 -0.600738525390625 +89709 -0.105499267578125 +89710 -0.584228515625 +89711 -0.10308837890625 +89712 -0.47930908203125 +89713 -0.083709716796875 +89714 -0.27935791015625 +89715 -0.045928955078125 +89716 -0.0089111328125 +89717 0.005462646484375 +89718 0.268798828125 +89719 0.0579833984375 +89720 0.482818603515625 +89721 0.09759521484375 +89722 0.60369873046875 +89723 0.118621826171875 +89724 0.650421142578125 +89725 0.125 +89726 0.66400146484375 +89727 0.125091552734375 +89728 0.6414794921875 +89729 0.118438720703125 +89730 0.572540283203125 +89731 0.103118896484375 +89732 0.498138427734375 +89733 0.087371826171875 +89734 0.439453125 +89735 0.075469970703125 +89736 0.375518798828125 +89737 0.063201904296875 +89738 0.274505615234375 +89739 0.044158935546875 +89740 0.1087646484375 +89741 0.012725830078125 +89742 -0.099395751953125 +89743 -0.026702880859375 +89744 -0.3182373046875 +89745 -0.06793212890625 +89746 -0.5489501953125 +89747 -0.111358642578125 +89748 -0.7738037109375 +89749 -0.153533935546875 +89750 -0.86383056640625 +89751 -0.184051513671875 +89752 -0.870391845703125 +89753 -0.1964111328125 +89754 -0.86895751953125 +89755 -0.194305419921875 +89756 -0.861053466796875 +89757 -0.180450439453125 +89758 -0.765869140625 +89759 -0.151458740234375 +89760 -0.5301513671875 +89761 -0.1051025390625 +89762 -0.214691162109375 +89763 -0.042816162109375 +89764 0.137359619140625 +89765 0.02679443359375 +89766 0.474822998046875 +89767 0.093536376953125 +89768 0.76239013671875 +89769 0.150390625 +89770 0.867462158203125 +89771 0.19207763671875 +89772 0.870361328125 +89773 0.21881103515625 +89774 0.86480712890625 +89775 0.2283935546875 +89776 0.831817626953125 +89777 0.222015380859375 +89778 0.677581787109375 +89779 0.2047119140625 +89780 0.495880126953125 +89781 0.177764892578125 +89782 0.30767822265625 +89783 0.14495849609375 +89784 0.116180419921875 +89785 0.1068115234375 +89786 -0.110748291015625 +89787 0.057037353515625 +89788 -0.381805419921875 +89789 -0.005706787109375 +89790 -0.6572265625 +89791 -0.072906494140625 +89792 -0.857421875 +89793 -0.132598876953125 +89794 -0.870391845703125 +89795 -0.176300048828125 +89796 -0.870391845703125 +89797 -0.202667236328125 +89798 -0.86444091796875 +89799 -0.217193603515625 +89800 -0.85723876953125 +89801 -0.227142333984375 +89802 -0.790008544921875 +89803 -0.228973388671875 +89804 -0.62847900390625 +89805 -0.2119140625 +89806 -0.3956298828125 +89807 -0.1754150390625 +89808 -0.126708984375 +89809 -0.12615966796875 +89810 0.150115966796875 +89811 -0.069671630859375 +89812 0.424041748046875 +89813 -0.008331298828125 +89814 0.670623779296875 +89815 0.05242919921875 +89816 0.854522705078125 +89817 0.1048583984375 +89818 0.866485595703125 +89819 0.145477294921875 +89820 0.86920166015625 +89821 0.171234130859375 +89822 0.8653564453125 +89823 0.18585205078125 +89824 0.857147216796875 +89825 0.19207763671875 +89826 0.766845703125 +89827 0.18939208984375 +89828 0.628509521484375 +89829 0.178955078125 +89830 0.462127685546875 +89831 0.159515380859375 +89832 0.297210693359375 +89833 0.13629150390625 +89834 0.14862060546875 +89835 0.111846923828125 +89836 -0.00537109375 +89837 0.081695556640625 +89838 -0.15753173828125 +89839 0.04736328125 +89840 -0.31304931640625 +89841 0.0081787109375 +89842 -0.48876953125 +89843 -0.038665771484375 +89844 -0.6416015625 +89845 -0.083770751953125 +89846 -0.751373291015625 +89847 -0.12225341796875 +89848 -0.84619140625 +89849 -0.158782958984375 +89850 -0.861297607421875 +89851 -0.190460205078125 +89852 -0.863250732421875 +89853 -0.210723876953125 +89854 -0.856597900390625 +89855 -0.213348388671875 +89856 -0.7498779296875 +89857 -0.201446533203125 +89858 -0.624542236328125 +89859 -0.187469482421875 +89860 -0.47808837890625 +89861 -0.165618896484375 +89862 -0.253387451171875 +89863 -0.122100830078125 +89864 0.003692626953125 +89865 -0.067230224609375 +89866 0.2257080078125 +89867 -0.016571044921875 +89868 0.427154541015625 +89869 0.033111572265625 +89870 0.643218994140625 +89871 0.0897216796875 +89872 0.855926513671875 +89873 0.1513671875 +89874 0.870361328125 +89875 0.20489501953125 +89876 0.870361328125 +89877 0.239044189453125 +89878 0.862762451171875 +89879 0.25567626953125 +89880 0.79669189453125 +89881 0.254241943359375 +89882 0.595794677734375 +89883 0.232574462890625 +89884 0.362152099609375 +89885 0.19744873046875 +89886 0.1270751953125 +89887 0.1552734375 +89888 -0.086944580078125 +89889 0.11077880859375 +89890 -0.2784423828125 +89891 0.064178466796875 +89892 -0.484832763671875 +89893 0.007171630859375 +89894 -0.729583740234375 +89895 -0.06500244140625 +89896 -0.86688232421875 +89897 -0.140869140625 +89898 -0.870391845703125 +89899 -0.2060546875 +89900 -0.86859130859375 +89901 -0.259613037109375 +89902 -0.86279296875 +89903 -0.301300048828125 +89904 -0.817962646484375 +89905 -0.322967529296875 +89906 -0.6116943359375 +89907 -0.314208984375 +89908 -0.3128662109375 +89909 -0.2734375 +89910 0.039398193359375 +89911 -0.20849609375 +89912 0.422821044921875 +89913 -0.123931884765625 +89914 0.805145263671875 +89915 -0.027374267578125 +89916 0.870361328125 +89917 0.06549072265625 +89918 0.870361328125 +89919 0.1416015625 +89920 0.860015869140625 +89921 0.198486328125 +89922 0.727935791015625 +89923 0.23455810546875 +89924 0.48114013671875 +89925 0.24871826171875 +89926 0.2059326171875 +89927 0.24676513671875 +89928 -0.06103515625 +89929 0.234100341796875 +89930 -0.29913330078125 +89931 0.21319580078125 +89932 -0.516204833984375 +89933 0.180755615234375 +89934 -0.7252197265625 +89935 0.13330078125 +89936 -0.85980224609375 +89937 0.07666015625 +89938 -0.870391845703125 +89939 0.018768310546875 +89940 -0.870391845703125 +89941 -0.03350830078125 +89942 -0.858062744140625 +89943 -0.06890869140625 +89944 -0.673004150390625 +89945 -0.08648681640625 +89946 -0.42694091796875 +89947 -0.0985107421875 +89948 -0.2100830078125 +89949 -0.1153564453125 +89950 -0.0362548828125 +89951 -0.136627197265625 +89952 0.10943603515625 +89953 -0.155609130859375 +89954 0.23516845703125 +89955 -0.16778564453125 +89956 0.373687744140625 +89957 -0.16363525390625 +89958 0.517791748046875 +89959 -0.143707275390625 +89960 0.602783203125 +89961 -0.1226806640625 +89962 0.635711669921875 +89963 -0.09942626953125 +89964 0.655181884765625 +89965 -0.066253662109375 +89966 0.65948486328125 +89967 -0.0255126953125 +89968 0.651275634765625 +89969 0.020904541015625 +89970 0.61846923828125 +89971 0.06732177734375 +89972 0.53753662109375 +89973 0.105133056640625 +89974 0.404144287109375 +89975 0.13018798828125 +89976 0.22186279296875 +89977 0.14031982421875 +89978 0.003997802734375 +89979 0.1358642578125 +89980 -0.22100830078125 +89981 0.121063232421875 +89982 -0.42449951171875 +89983 0.10076904296875 +89984 -0.579833984375 +89985 0.08001708984375 +89986 -0.641876220703125 +89987 0.068756103515625 +89988 -0.6177978515625 +89989 0.065521240234375 +89990 -0.575531005859375 +89991 0.05535888671875 +89992 -0.526336669921875 +89993 0.037078857421875 +89994 -0.42645263671875 +89995 0.022735595703125 +89996 -0.2581787109375 +89997 0.0186767578125 +89998 -0.068695068359375 +89999 0.0164794921875 +90000 0.09222412109375 +90001 0.0072021484375 +90002 0.232147216796875 +90003 -0.00482177734375 +90004 0.3509521484375 +90005 -0.017242431640625 +90006 0.410064697265625 +90007 -0.036956787109375 +90008 0.372955322265625 +90009 -0.07080078125 +90010 0.2554931640625 +90011 -0.113922119140625 +90012 0.10711669921875 +90013 -0.154296875 +90014 -0.052886962890625 +90015 -0.1873779296875 +90016 -0.186279296875 +90017 -0.204803466796875 +90018 -0.23291015625 +90019 -0.19366455078125 +90020 -0.209442138671875 +90021 -0.159271240234375 +90022 -0.174163818359375 +90023 -0.116912841796875 +90024 -0.126739501953125 +90025 -0.068511962890625 +90026 -0.048126220703125 +90027 -0.011810302734375 +90028 0.0426025390625 +90029 0.046630859375 +90030 0.10748291015625 +90031 0.095977783203125 +90032 0.1409912109375 +90033 0.1331787109375 +90034 0.19708251953125 +90035 0.16925048828125 +90036 0.273651123046875 +90037 0.202667236328125 +90038 0.31768798828125 +90039 0.220489501953125 +90040 0.341094970703125 +90041 0.225311279296875 +90042 0.368011474609375 +90043 0.222991943359375 +90044 0.37249755859375 +90045 0.208221435546875 +90046 0.30072021484375 +90047 0.169586181640625 +90048 0.1517333984375 +90049 0.10821533203125 +90050 -0.01470947265625 +90051 0.039581298828125 +90052 -0.1883544921875 +90053 -0.03216552734375 +90054 -0.372711181640625 +90055 -0.1060791015625 +90056 -0.51397705078125 +90057 -0.16802978515625 +90058 -0.57177734375 +90059 -0.20709228515625 +90060 -0.53948974609375 +90061 -0.220428466796875 +90062 -0.43511962890625 +90063 -0.211212158203125 +90064 -0.2962646484375 +90065 -0.187530517578125 +90066 -0.161102294921875 +90067 -0.157958984375 +90068 -0.0435791015625 +90069 -0.125823974609375 +90070 0.060394287109375 +90071 -0.09063720703125 +90072 0.13665771484375 +90073 -0.056488037109375 +90074 0.170135498046875 +90075 -0.02789306640625 +90076 0.16552734375 +90077 -0.005035400390625 +90078 0.15728759765625 +90079 0.018646240234375 +90080 0.150787353515625 +90081 0.04296875 +90082 0.12200927734375 +90083 0.060943603515625 +90084 0.080108642578125 +90085 0.073394775390625 +90086 0.05126953125 +90087 0.08526611328125 +90088 0.062896728515625 +90089 0.10198974609375 +90090 0.09271240234375 +90091 0.11773681640625 +90092 0.092987060546875 +90093 0.121124267578125 +90094 0.07855224609375 +90095 0.1156005859375 +90096 0.06427001953125 +90097 0.104888916015625 +90098 0.0347900390625 +90099 0.0859375 +90100 -0.01171875 +90101 0.05914306640625 +90102 -0.056060791015625 +90103 0.029937744140625 +90104 -0.055511474609375 +90105 0.00933837890625 +90106 -0.010467529296875 +90107 -0.00152587890625 +90108 0.02508544921875 +90109 -0.01397705078125 +90110 0.025665283203125 +90111 -0.0328369140625 +90112 0.017333984375 +90113 -0.050872802734375 +90114 0.00189208984375 +90115 -0.066986083984375 +90116 -0.03173828125 +90117 -0.083404541015625 +90118 -0.071502685546875 +90119 -0.096923828125 +90120 -0.13543701171875 +90121 -0.112030029296875 +90122 -0.219970703125 +90123 -0.128082275390625 +90124 -0.300506591796875 +90125 -0.139312744140625 +90126 -0.376312255859375 +90127 -0.146148681640625 +90128 -0.416107177734375 +90129 -0.141571044921875 +90130 -0.371124267578125 +90131 -0.114227294921875 +90132 -0.242279052734375 +90133 -0.06524658203125 +90134 -0.069732666015625 +90135 -0.005615234375 +90136 0.125640869140625 +90137 0.05853271484375 +90138 0.31268310546875 +90139 0.118621826171875 +90140 0.45501708984375 +90141 0.1649169921875 +90142 0.554779052734375 +90143 0.197418212890625 +90144 0.61065673828125 +90145 0.21551513671875 +90146 0.610931396484375 +90147 0.216156005859375 +90148 0.531463623046875 +90149 0.193389892578125 +90150 0.3883056640625 +90151 0.1514892578125 +90152 0.23468017578125 +90153 0.10418701171875 +90154 0.095245361328125 +90155 0.0582275390625 +90156 -0.00396728515625 +90157 0.02081298828125 +90158 -0.04852294921875 +90159 -0.003753662109375 +90160 -0.055145263671875 +90161 -0.018890380859375 +90162 -0.0758056640625 +90163 -0.036865234375 +90164 -0.138702392578125 +90165 -0.06402587890625 +90166 -0.209197998046875 +90167 -0.09112548828125 +90168 -0.289031982421875 +90169 -0.118133544921875 +90170 -0.37884521484375 +90171 -0.1448974609375 +90172 -0.456329345703125 +90173 -0.165679931640625 +90174 -0.51641845703125 +90175 -0.179229736328125 +90176 -0.519287109375 +90177 -0.17578125 +90178 -0.458251953125 +90179 -0.153961181640625 +90180 -0.384796142578125 +90181 -0.127044677734375 +90182 -0.323699951171875 +90183 -0.10174560546875 +90184 -0.269287109375 +90185 -0.07720947265625 +90186 -0.1951904296875 +90187 -0.047515869140625 +90188 -0.100006103515625 +90189 -0.012908935546875 +90190 -0.01055908203125 +90191 0.019287109375 +90192 0.1033935546875 +90193 0.056121826171875 +90194 0.24908447265625 +90195 0.0989990234375 +90196 0.373199462890625 +90197 0.13427734375 +90198 0.45806884765625 +90199 0.15740966796875 +90200 0.511474609375 +90201 0.170257568359375 +90202 0.565399169921875 +90203 0.180938720703125 +90204 0.61138916015625 +90205 0.18756103515625 +90206 0.5897216796875 +90207 0.175537109375 +90208 0.4906005859375 +90209 0.142791748046875 +90210 0.33148193359375 +90211 0.09417724609375 +90212 0.147796630859375 +90213 0.0390625 +90214 -0.01873779296875 +90215 -0.0115966796875 +90216 -0.140289306640625 +90217 -0.05035400390625 +90218 -0.191986083984375 +90219 -0.070526123046875 +90220 -0.184295654296875 +90221 -0.07440185546875 +90222 -0.161834716796875 +90223 -0.0728759765625 +90224 -0.166595458984375 +90225 -0.07623291015625 +90226 -0.19390869140625 +90227 -0.083251953125 +90228 -0.22442626953125 +90229 -0.089141845703125 +90230 -0.279754638671875 +90231 -0.099456787109375 +90232 -0.3389892578125 +90233 -0.109222412109375 +90234 -0.3543701171875 +90235 -0.1068115234375 +90236 -0.348175048828125 +90237 -0.098175048828125 +90238 -0.32598876953125 +90239 -0.085113525390625 +90240 -0.2581787109375 +90241 -0.060638427734375 +90242 -0.139801025390625 +90243 -0.02392578125 +90244 0.014617919921875 +90245 0.02099609375 +90246 0.144378662109375 +90247 0.058624267578125 +90248 0.221038818359375 +90249 0.08160400390625 +90250 0.27069091796875 +90251 0.096282958984375 +90252 0.294036865234375 +90253 0.102783203125 +90254 0.311767578125 +90255 0.106292724609375 +90256 0.339141845703125 +90257 0.1107177734375 +90258 0.360260009765625 +90259 0.112457275390625 +90260 0.360504150390625 +90261 0.1080322265625 +90262 0.308380126953125 +90263 0.089324951171875 +90264 0.18170166015625 +90265 0.050750732421875 +90266 0.0047607421875 +90267 -0.0009765625 +90268 -0.17559814453125 +90269 -0.05328369140625 +90270 -0.3143310546875 +90271 -0.09405517578125 +90272 -0.36785888671875 +90273 -0.111602783203125 +90274 -0.36248779296875 +90275 -0.112701416015625 +90276 -0.343536376953125 +90277 -0.109222412109375 +90278 -0.3018798828125 +90279 -0.09869384765625 +90280 -0.231414794921875 +90281 -0.079498291015625 +90282 -0.117645263671875 +90283 -0.047882080078125 +90284 0.007049560546875 +90285 -0.01251220703125 +90286 0.087982177734375 +90287 0.011993408203125 +90288 0.13946533203125 +90289 0.02923583984375 +90290 0.17425537109375 +90291 0.0423583984375 +90292 0.188201904296875 +90293 0.050079345703125 +90294 0.171234130859375 +90295 0.04949951171875 +90296 0.118438720703125 +90297 0.03912353515625 +90298 0.05706787109375 +90299 0.025970458984375 +90300 -0.010711669921875 +90301 0.01043701171875 +90302 -0.0914306640625 +90303 -0.00927734375 +90304 -0.162322998046875 +90305 -0.0272216796875 +90306 -0.194549560546875 +90307 -0.035797119140625 +90308 -0.1492919921875 +90309 -0.02471923828125 +90310 -0.02166748046875 +90311 0.00732421875 +90312 0.124053955078125 +90313 0.043487548828125 +90314 0.211151123046875 +90315 0.063629150390625 +90316 0.240447998046875 +90317 0.068145751953125 +90318 0.242218017578125 +90319 0.065185546875 +90320 0.2257080078125 +90321 0.05743408203125 +90322 0.194366455078125 +90323 0.045989990234375 +90324 0.115509033203125 +90325 0.022369384765625 +90326 0.0128173828125 +90327 -0.0069580078125 +90328 -0.053802490234375 +90329 -0.026092529296875 +90330 -0.110626220703125 +90331 -0.04193115234375 +90332 -0.199493408203125 +90333 -0.065460205078125 +90334 -0.29437255859375 +90335 -0.08984375 +90336 -0.33221435546875 +90337 -0.0985107421875 +90338 -0.27972412109375 +90339 -0.082794189453125 +90340 -0.185333251953125 +90341 -0.055572509765625 +90342 -0.128204345703125 +90343 -0.037872314453125 +90344 -0.115692138671875 +90345 -0.031768798828125 +90346 -0.116455078125 +90347 -0.029144287109375 +90348 -0.105926513671875 +90349 -0.023712158203125 +90350 -0.053955078125 +90351 -0.00762939453125 +90352 0.048797607421875 +90353 0.02142333984375 +90354 0.157318115234375 +90355 0.051483154296875 +90356 0.212005615234375 +90357 0.066741943359375 +90358 0.218475341796875 +90359 0.068634033203125 +90360 0.23724365234375 +90361 0.07318115234375 +90362 0.30535888671875 +90363 0.090179443359375 +90364 0.38128662109375 +90365 0.108734130859375 +90366 0.404449462890625 +90367 0.112945556640625 +90368 0.3944091796875 +90369 0.10870361328125 +90370 0.3885498046875 +90371 0.10662841796875 +90372 0.362640380859375 +90373 0.0994873046875 +90374 0.27362060546875 +90375 0.0743408203125 +90376 0.11712646484375 +90377 0.029693603515625 +90378 -0.054901123046875 +90379 -0.01922607421875 +90380 -0.19085693359375 +90381 -0.05731201171875 +90382 -0.28570556640625 +90383 -0.083251953125 +90384 -0.339263916015625 +90385 -0.097137451171875 +90386 -0.3775634765625 +90387 -0.106781005859375 +90388 -0.445709228515625 +90389 -0.1256103515625 +90390 -0.535064697265625 +90391 -0.151153564453125 +90392 -0.629058837890625 +90393 -0.17852783203125 +90394 -0.697601318359375 +90395 -0.19879150390625 +90396 -0.70391845703125 +90397 -0.2010498046875 +90398 -0.6424560546875 +90399 -0.183624267578125 +90400 -0.491241455078125 +90401 -0.13995361328125 +90402 -0.265716552734375 +90403 -0.074554443359375 +90404 -0.023712158203125 +90405 -0.00445556640625 +90406 0.201751708984375 +90407 0.060638427734375 +90408 0.375823974609375 +90409 0.110504150390625 +90410 0.485076904296875 +90411 0.141265869140625 +90412 0.56884765625 +90413 0.1646728515625 +90414 0.634765625 +90415 0.18304443359375 +90416 0.63763427734375 +90417 0.18304443359375 +90418 0.5660400390625 +90419 0.161346435546875 +90420 0.4720458984375 +90421 0.133392333984375 +90422 0.40692138671875 +90423 0.11431884765625 +90424 0.3778076171875 +90425 0.106231689453125 +90426 0.376953125 +90427 0.1068115234375 +90428 0.371978759765625 +90429 0.106414794921875 +90430 0.313140869140625 +90431 0.090240478515625 +90432 0.184417724609375 +90433 0.053436279296875 +90434 0.011199951171875 +90435 0.00347900390625 +90436 -0.171051025390625 +90437 -0.04913330078125 +90438 -0.33740234375 +90439 -0.09710693359375 +90440 -0.47198486328125 +90441 -0.135833740234375 +90442 -0.560394287109375 +90443 -0.1611328125 +90444 -0.58056640625 +90445 -0.16650390625 +90446 -0.54754638671875 +90447 -0.156402587890625 +90448 -0.508575439453125 +90449 -0.144866943359375 +90450 -0.459503173828125 +90451 -0.130645751953125 +90452 -0.394378662109375 +90453 -0.1119384765625 +90454 -0.35260009765625 +90455 -0.100341796875 +90456 -0.31170654296875 +90457 -0.08917236328125 +90458 -0.197418212890625 +90459 -0.056365966796875 +90460 -0.007965087890625 +90461 -0.001373291015625 +90462 0.207489013671875 +90463 0.061279296875 +90464 0.409210205078125 +90465 0.119873046875 +90466 0.57208251953125 +90467 0.16705322265625 +90468 0.66595458984375 +90469 0.193939208984375 +90470 0.65875244140625 +90471 0.191131591796875 +90472 0.56744384765625 +90473 0.163665771484375 +90474 0.431396484375 +90475 0.123199462890625 +90476 0.29443359375 +90477 0.082733154296875 +90478 0.182464599609375 +90479 0.0499267578125 +90480 0.06365966796875 +90481 0.01531982421875 +90482 -0.075958251953125 +90483 -0.025238037109375 +90484 -0.189422607421875 +90485 -0.05792236328125 +90486 -0.271942138671875 +90487 -0.081329345703125 +90488 -0.342529296875 +90489 -0.101165771484375 +90490 -0.364166259765625 +90491 -0.1065673828125 +90492 -0.327239990234375 +90493 -0.0947265625 +90494 -0.2769775390625 +90495 -0.079071044921875 +90496 -0.253692626953125 +90497 -0.071563720703125 +90498 -0.24365234375 +90499 -0.068145751953125 +90500 -0.1983642578125 +90501 -0.05450439453125 +90502 -0.116241455078125 +90503 -0.030181884765625 +90504 -0.036834716796875 +90505 -0.006866455078125 +90506 0.034881591796875 +90507 0.013946533203125 +90508 0.09124755859375 +90509 0.030029296875 +90510 0.10888671875 +90511 0.034515380859375 +90512 0.125518798828125 +90513 0.038604736328125 +90514 0.15771484375 +90515 0.047271728515625 +90516 0.17828369140625 +90517 0.052490234375 +90518 0.17108154296875 +90519 0.04949951171875 +90520 0.129974365234375 +90521 0.03656005859375 +90522 0.082427978515625 +90523 0.021820068359375 +90524 0.027679443359375 +90525 0.005126953125 +90526 -0.065643310546875 +90527 -0.02276611328125 +90528 -0.15936279296875 +90529 -0.050537109375 +90530 -0.21307373046875 +90531 -0.0662841796875 +90532 -0.234649658203125 +90533 -0.07232666015625 +90534 -0.2001953125 +90535 -0.061614990234375 +90536 -0.119171142578125 +90537 -0.0369873046875 +90538 -0.024749755859375 +90539 -0.00830078125 +90540 0.085784912109375 +90541 0.025177001953125 +90542 0.178131103515625 +90543 0.05322265625 +90544 0.215576171875 +90545 0.06494140625 +90546 0.211456298828125 +90547 0.06427001953125 +90548 0.17523193359375 +90549 0.05401611328125 +90550 0.128753662109375 +90551 0.040618896484375 +90552 0.1019287109375 +90553 0.03289794921875 +90554 0.0743408203125 +90555 0.024810791015625 +90556 0.04327392578125 +90557 0.015533447265625 +90558 0.038177490234375 +90559 0.0137939453125 +90560 0.076263427734375 +90561 0.024688720703125 +90562 0.14105224609375 +90563 0.043365478515625 +90564 0.186431884765625 +90565 0.05621337890625 +90566 0.188812255859375 +90567 0.0562744140625 +90568 0.1390380859375 +90569 0.0408935546875 +90570 0.041778564453125 +90571 0.011505126953125 +90572 -0.079437255859375 +90573 -0.02490234375 +90574 -0.219390869140625 +90575 -0.066741943359375 +90576 -0.367828369140625 +90577 -0.1109619140625 +90578 -0.494873046875 +90579 -0.148681640625 +90580 -0.556243896484375 +90581 -0.16680908203125 +90582 -0.508697509765625 +90583 -0.152557373046875 +90584 -0.3756103515625 +90585 -0.11285400390625 +90586 -0.218902587890625 +90587 -0.066070556640625 +90588 -0.063751220703125 +90589 -0.019683837890625 +90590 0.091552734375 +90591 0.026763916015625 +90592 0.23602294921875 +90593 0.07000732421875 +90594 0.342987060546875 +90595 0.10211181640625 +90596 0.39520263671875 +90597 0.11798095703125 +90598 0.389373779296875 +90599 0.116607666015625 +90600 0.324249267578125 +90601 0.097625732421875 +90602 0.224090576171875 +90603 0.068206787109375 +90604 0.124267578125 +90605 0.038787841796875 +90606 0.037078857421875 +90607 0.01300048828125 +90608 -0.010101318359375 +90609 -0.00103759765625 +90610 -0.019439697265625 +90611 -0.00396728515625 +90612 -0.022796630859375 +90613 -0.00518798828125 +90614 -0.001556396484375 +90615 0.000762939453125 +90616 0.056304931640625 +90617 0.017486572265625 +90618 0.106719970703125 +90619 0.031951904296875 +90620 0.096893310546875 +90621 0.028564453125 +90622 0.042694091796875 +90623 0.012054443359375 +90624 -0.018035888671875 +90625 -0.006622314453125 +90626 -0.07586669921875 +90627 -0.02447509765625 +90628 -0.11944580078125 +90629 -0.037506103515625 +90630 -0.15972900390625 +90631 -0.049468994140625 +90632 -0.202606201171875 +90633 -0.062469482421875 +90634 -0.24859619140625 +90635 -0.076690673828125 +90636 -0.30517578125 +90637 -0.094696044921875 +90638 -0.36212158203125 +90639 -0.1131591796875 +90640 -0.39141845703125 +90641 -0.122894287109375 +90642 -0.35528564453125 +90643 -0.11151123046875 +90644 -0.249969482421875 +90645 -0.077728271484375 +90646 -0.092864990234375 +90647 -0.0272216796875 +90648 0.08905029296875 +90649 0.03125 +90650 0.2352294921875 +90651 0.077911376953125 +90652 0.318817138671875 +90653 0.104034423828125 +90654 0.358642578125 +90655 0.1158447265625 +90656 0.347747802734375 +90657 0.11114501953125 +90658 0.28564453125 +90659 0.08984375 +90660 0.223175048828125 +90661 0.06866455078125 +90662 0.196746826171875 +90663 0.0595703125 +90664 0.179840087890625 +90665 0.053863525390625 +90666 0.155548095703125 +90667 0.0460205078125 +90668 0.151214599609375 +90669 0.045013427734375 +90670 0.156951904296875 +90671 0.04754638671875 +90672 0.13177490234375 +90673 0.040130615234375 +90674 0.100799560546875 +90675 0.03094482421875 +90676 0.087127685546875 +90677 0.02752685546875 +90678 0.05487060546875 +90679 0.01806640625 +90680 -0.009002685546875 +90681 -0.00177001953125 +90682 -0.10400390625 +90683 -0.031890869140625 +90684 -0.229400634765625 +90685 -0.072113037109375 +90686 -0.35552978515625 +90687 -0.112762451171875 +90688 -0.441925048828125 +90689 -0.14056396484375 +90690 -0.473846435546875 +90691 -0.150726318359375 +90692 -0.464813232421875 +90693 -0.147674560546875 +90694 -0.419097900390625 +90695 -0.132843017578125 +90696 -0.334320068359375 +90697 -0.105438232421875 +90698 -0.227935791015625 +90699 -0.071136474609375 +90700 -0.12347412109375 +90701 -0.037628173828125 +90702 -0.02764892578125 +90703 -0.007049560546875 +90704 0.077667236328125 +90705 0.026580810546875 +90706 0.2132568359375 +90707 0.070098876953125 +90708 0.38885498046875 +90709 0.12677001953125 +90710 0.582794189453125 +90711 0.18951416015625 +90712 0.734039306640625 +90713 0.238372802734375 +90714 0.800140380859375 +90715 0.259429931640625 +90716 0.7783203125 +90717 0.2518310546875 +90718 0.6651611328125 +90719 0.2144775390625 +90720 0.45965576171875 +90721 0.14703369140625 +90722 0.199188232421875 +90723 0.061767578125 +90724 -0.050689697265625 +90725 -0.019805908203125 +90726 -0.23297119140625 +90727 -0.079010009765625 +90728 -0.33013916015625 +90729 -0.11016845703125 +90730 -0.368408203125 +90731 -0.121917724609375 +90732 -0.378936767578125 +90733 -0.124481201171875 +90734 -0.376983642578125 +90735 -0.12298583984375 +90736 -0.37969970703125 +90737 -0.123077392578125 +90738 -0.391510009765625 +90739 -0.126251220703125 +90740 -0.385345458984375 +90741 -0.123626708984375 +90742 -0.3419189453125 +90743 -0.10894775390625 +90744 -0.28289794921875 +90745 -0.089324951171875 +90746 -0.251617431640625 +90747 -0.078948974609375 +90748 -0.266143798828125 +90749 -0.083770751953125 +90750 -0.273345947265625 +90751 -0.086395263671875 +90752 -0.216796875 +90753 -0.0682373046875 +90754 -0.128265380859375 +90755 -0.039703369140625 +90756 -0.068145751953125 +90757 -0.02056884765625 +90758 -0.0430908203125 +90759 -0.01300048828125 +90760 -0.024444580078125 +90761 -0.007537841796875 +90762 0.020721435546875 +90763 0.006622314453125 +90764 0.124481201171875 +90765 0.040008544921875 +90766 0.25787353515625 +90767 0.083160400390625 +90768 0.379119873046875 +90769 0.122406005859375 +90770 0.47991943359375 +90771 0.155059814453125 +90772 0.5281982421875 +90773 0.170654296875 +90774 0.511138916015625 +90775 0.164947509765625 +90776 0.456207275390625 +90777 0.14697265625 +90778 0.407470703125 +90779 0.13116455078125 +90780 0.383758544921875 +90781 0.123687744140625 +90782 0.35687255859375 +90783 0.115264892578125 +90784 0.31182861328125 +90785 0.1009521484375 +90786 0.250885009765625 +90787 0.081451416015625 +90788 0.1654052734375 +90789 0.053924560546875 +90790 0.035247802734375 +90791 0.011749267578125 +90792 -0.142059326171875 +90793 -0.045867919921875 +90794 -0.33563232421875 +90795 -0.108856201171875 +90796 -0.5345458984375 +90797 -0.17364501953125 +90798 -0.72186279296875 +90799 -0.234710693359375 +90800 -0.836669921875 +90801 -0.272064208984375 +90802 -0.8326416015625 +90803 -0.27056884765625 +90804 -0.7296142578125 +90805 -0.236724853515625 +90806 -0.582550048828125 +90807 -0.188568115234375 +90808 -0.440093994140625 +90809 -0.142059326171875 +90810 -0.324310302734375 +90811 -0.10443115234375 +90812 -0.20147705078125 +90813 -0.0645751953125 +90814 -0.044647216796875 +90815 -0.013580322265625 +90816 0.103973388671875 +90817 0.034698486328125 +90818 0.202392578125 +90819 0.066497802734375 +90820 0.264495849609375 +90821 0.08636474609375 +90822 0.338897705078125 +90823 0.11029052734375 +90824 0.443817138671875 +90825 0.144287109375 +90826 0.545074462890625 +90827 0.177154541015625 +90828 0.6173095703125 +90829 0.20062255859375 +90830 0.6524658203125 +90831 0.2120361328125 +90832 0.66339111328125 +90833 0.215606689453125 +90834 0.6561279296875 +90835 0.21331787109375 +90836 0.606781005859375 +90837 0.197296142578125 +90838 0.501190185546875 +90839 0.16290283203125 +90840 0.352783203125 +90841 0.114532470703125 +90842 0.176544189453125 +90843 0.05706787109375 +90844 -0.034820556640625 +90845 -0.0118408203125 +90846 -0.258209228515625 +90847 -0.08465576171875 +90848 -0.44244384765625 +90849 -0.14459228515625 +90850 -0.5753173828125 +90851 -0.18768310546875 +90852 -0.65203857421875 +90853 -0.21240234375 +90854 -0.641632080078125 +90855 -0.2086181640625 +90856 -0.562164306640625 +90857 -0.18231201171875 +90858 -0.458038330078125 +90859 -0.148040771484375 +90860 -0.350555419921875 +90861 -0.112762451171875 +90862 -0.260528564453125 +90863 -0.083343505859375 +90864 -0.192108154296875 +90865 -0.061126708984375 +90866 -0.141937255859375 +90867 -0.04498291015625 +90868 -0.1021728515625 +90869 -0.032318115234375 +90870 -0.062896728515625 +90871 -0.019866943359375 +90872 -0.011932373046875 +90873 -0.003570556640625 +90874 0.062835693359375 +90875 0.020538330078125 +90876 0.148712158203125 +90877 0.048309326171875 +90878 0.241729736328125 +90879 0.078460693359375 +90880 0.34912109375 +90881 0.113677978515625 +90882 0.457305908203125 +90883 0.150299072265625 +90884 0.54388427734375 +90885 0.180877685546875 +90886 0.5728759765625 +90887 0.192138671875 +90888 0.506591796875 +90889 0.170196533203125 +90890 0.351226806640625 +90891 0.116943359375 +90892 0.146514892578125 +90893 0.04638671875 +90894 -0.05523681640625 +90895 -0.02288818359375 +90896 -0.21624755859375 +90897 -0.0775146484375 +90898 -0.334930419921875 +90899 -0.11712646484375 +90900 -0.402984619140625 +90901 -0.138885498046875 +90902 -0.4412841796875 +90903 -0.15045166015625 +90904 -0.49578857421875 +90905 -0.16845703125 +90906 -0.5601806640625 +90907 -0.190704345703125 +90908 -0.600738525390625 +90909 -0.205047607421875 +90910 -0.584228515625 +90911 -0.199493408203125 +90912 -0.47930908203125 +90913 -0.162689208984375 +90914 -0.27935791015625 +90915 -0.092193603515625 +90916 -0.0089111328125 +90917 0.00323486328125 +90918 0.268798828125 +90919 0.1009521484375 +90920 0.482818603515625 +90921 0.175567626953125 +90922 0.60369873046875 +90923 0.216644287109375 +90924 0.650421142578125 +90925 0.231109619140625 +90926 0.66400146484375 +90927 0.23388671875 +90928 0.6414794921875 +90929 0.2239990234375 +90930 0.572540283203125 +90931 0.19781494140625 +90932 0.498138427734375 +90933 0.170166015625 +90934 0.439453125 +90935 0.148712158203125 +90936 0.375518798828125 +90937 0.12591552734375 +90938 0.274505615234375 +90939 0.09027099609375 +90940 0.1087646484375 +90941 0.031768798828125 +90942 -0.099395751953125 +90943 -0.0416259765625 +90944 -0.3182373046875 +90945 -0.118560791015625 +90946 -0.5489501953125 +90947 -0.199615478515625 +90948 -0.7738037109375 +90949 -0.278472900390625 +90950 -0.86383056640625 +90951 -0.336212158203125 +90952 -0.870391845703125 +90953 -0.3609619140625 +90954 -0.86895751953125 +90955 -0.35919189453125 +90956 -0.861053466796875 +90957 -0.335723876953125 +90958 -0.765869140625 +90959 -0.284393310546875 +90960 -0.5301513671875 +90961 -0.201171875 +90962 -0.214691162109375 +90963 -0.088592529296875 +90964 0.137359619140625 +90965 0.037811279296875 +90966 0.474822998046875 +90967 0.15960693359375 +90968 0.76239013671875 +90969 0.2640380859375 +90970 0.867462158203125 +90971 0.341461181640625 +90972 0.870361328125 +90973 0.39215087890625 +90974 0.86480712890625 +90975 0.4119873046875 +90976 0.831817626953125 +90977 0.40301513671875 +90978 0.677581787109375 +90979 0.374114990234375 +90980 0.495880126953125 +90981 0.32745361328125 +90982 0.30767822265625 +90983 0.269805908203125 +90984 0.116180419921875 +90985 0.2020263671875 +90986 -0.110748291015625 +90987 0.11273193359375 +90988 -0.381805419921875 +90989 -0.000518798828125 +90990 -0.6572265625 +90991 -0.122314453125 +90992 -0.857421875 +90993 -0.231109619140625 +90994 -0.870391845703125 +90995 -0.3115234375 +90996 -0.870391845703125 +90997 -0.361053466796875 +90998 -0.86444091796875 +90999 -0.389434814453125 +91000 -0.85723876953125 +91001 -0.40960693359375 +91002 -0.790008544921875 +91003 -0.4150390625 +91004 -0.62847900390625 +91005 -0.38629150390625 +91006 -0.3956298828125 +91007 -0.322265625 +91008 -0.126708984375 +91009 -0.23486328125 +91010 0.150115966796875 +91011 -0.134002685546875 +91012 0.424041748046875 +91013 -0.023956298828125 +91014 0.670623779296875 +91015 0.085540771484375 +91016 0.854522705078125 +91017 0.180511474609375 +91018 0.866485595703125 +91019 0.254638671875 +91020 0.86920166015625 +91021 0.302398681640625 +91022 0.8653564453125 +91023 0.33038330078125 +91024 0.857147216796875 +91025 0.34344482421875 +91026 0.766845703125 +91027 0.340576171875 +91028 0.628509521484375 +91029 0.323699951171875 +91030 0.462127685546875 +91031 0.29046630859375 +91032 0.297210693359375 +91033 0.250213623046875 +91034 0.14862060546875 +91035 0.20745849609375 +91036 -0.00537109375 +91037 0.154022216796875 +91038 -0.15753173828125 +91039 0.092681884765625 +91040 -0.31304931640625 +91041 0.022186279296875 +91042 -0.48876953125 +91043 -0.0625 +91044 -0.6416015625 +91045 -0.144500732421875 +91046 -0.751373291015625 +91047 -0.21490478515625 +91048 -0.84619140625 +91049 -0.28204345703125 +91050 -0.861297607421875 +91051 -0.340667724609375 +91052 -0.863250732421875 +91053 -0.378875732421875 +91054 -0.856597900390625 +91055 -0.385345458984375 +91056 -0.7498779296875 +91057 -0.364501953125 +91058 -0.624542236328125 +91059 -0.33721923828125 +91060 -0.47808837890625 +91061 -0.295684814453125 +91062 -0.253387451171875 +91063 -0.218902587890625 +91064 0.003692626953125 +91065 -0.12335205078125 +91066 0.2257080078125 +91067 -0.03369140625 +91068 0.427154541015625 +91069 0.054534912109375 +91070 0.643218994140625 +91071 0.152984619140625 +91072 0.855926513671875 +91073 0.2581787109375 +91074 0.870361328125 +91075 0.3492431640625 +91076 0.870361328125 +91077 0.4083251953125 +91078 0.862762451171875 +91079 0.43804931640625 +91080 0.79669189453125 +91081 0.437408447265625 +91082 0.595794677734375 +91083 0.403076171875 +91084 0.362152099609375 +91085 0.3455810546875 +91086 0.1270751953125 +91087 0.27508544921875 +91088 -0.086944580078125 +91089 0.19927978515625 +91090 -0.2784423828125 +91091 0.118927001953125 +91092 -0.484832763671875 +91093 0.021575927734375 +91094 -0.729583740234375 +91095 -0.099609375 +91096 -0.86688232421875 +91097 -0.226348876953125 +91098 -0.870391845703125 +91099 -0.3358154296875 +91100 -0.86859130859375 +91101 -0.426177978515625 +91102 -0.86279296875 +91103 -0.496673583984375 +91104 -0.817962646484375 +91105 -0.534393310546875 +91106 -0.6116943359375 +91107 -0.52301025390625 +91108 -0.3128662109375 +91109 -0.459991455078125 +91110 0.039398193359375 +91111 -0.35748291015625 +91112 0.422821044921875 +91113 -0.2227783203125 +91114 0.805145263671875 +91115 -0.067901611328125 +91116 0.870361328125 +91117 0.082489013671875 +91118 0.870361328125 +91119 0.207794189453125 +91120 0.860015869140625 +91121 0.303680419921875 +91122 0.727935791015625 +91123 0.367279052734375 +91124 0.48114013671875 +91125 0.396453857421875 +91126 0.2059326171875 +91127 0.39984130859375 +91128 -0.06103515625 +91129 0.385498046875 +91130 -0.29913330078125 +91131 0.35699462890625 +91132 -0.516204833984375 +91133 0.30908203125 +91134 -0.7252197265625 +91135 0.236236572265625 +91136 -0.85980224609375 +91137 0.147674560546875 +91138 -0.870391845703125 +91139 0.055419921875 +91140 -0.870391845703125 +91141 -0.029754638671875 +91142 -0.858062744140625 +91143 -0.088653564453125 +91144 -0.673004150390625 +91145 -0.11944580078125 +91146 -0.42694091796875 +91147 -0.142547607421875 +91148 -0.2100830078125 +91149 -0.175140380859375 +91150 -0.0362548828125 +91151 -0.2161865234375 +91152 0.10943603515625 +91153 -0.254058837890625 +91154 0.23516845703125 +91155 -0.28070068359375 +91156 0.373687744140625 +91157 -0.2796630859375 +91158 0.517791748046875 +91159 -0.251556396484375 +91160 0.602783203125 +91161 -0.22088623046875 +91162 0.635711669921875 +91163 -0.18548583984375 +91164 0.655181884765625 +91165 -0.1322021484375 +91166 0.65948486328125 +91167 -0.06488037109375 +91168 0.651275634765625 +91169 0.0133056640625 +91170 0.61846923828125 +91171 0.092742919921875 +91172 0.53753662109375 +91173 0.1588134765625 +91174 0.404144287109375 +91175 0.204345703125 +91176 0.22186279296875 +91177 0.22540283203125 +91178 0.003997802734375 +91179 0.222320556640625 +91180 -0.22100830078125 +91181 0.202056884765625 +91182 -0.42449951171875 +91183 0.172515869140625 +91184 -0.579833984375 +91185 0.141937255859375 +91186 -0.641876220703125 +91187 0.12689208984375 +91188 -0.6177978515625 +91189 0.12469482421875 +91190 -0.575531005859375 +91191 0.109954833984375 +91192 -0.526336669921875 +91193 0.08050537109375 +91194 -0.42645263671875 +91195 0.056640625 +91196 -0.2581787109375 +91197 0.0491943359375 +91198 -0.068695068359375 +91199 0.043975830078125 +91200 0.09222412109375 +91201 0.025970458984375 +91202 0.232147216796875 +91203 0.00262451171875 +91204 0.3509521484375 +91205 -0.021881103515625 +91206 0.410064697265625 +91207 -0.05902099609375 +91208 0.372955322265625 +91209 -0.1201171875 +91210 0.2554931640625 +91211 -0.196807861328125 +91212 0.10711669921875 +91213 -0.268524169921875 +91214 -0.052886962890625 +91215 -0.32745361328125 +91216 -0.186279296875 +91217 -0.35931396484375 +91218 -0.23291015625 +91219 -0.34210205078125 +91220 -0.209442138671875 +91221 -0.284759521484375 +91222 -0.174163818359375 +91223 -0.213104248046875 +91224 -0.126739501953125 +91225 -0.13043212890625 +91226 -0.048126220703125 +91227 -0.032958984375 +91228 0.0426025390625 +91229 0.068115234375 +91230 0.10748291015625 +91231 0.15435791015625 +91232 0.1409912109375 +91233 0.220428466796875 +91234 0.19708251953125 +91235 0.284820556640625 +91236 0.273651123046875 +91237 0.344696044921875 +91238 0.31768798828125 +91239 0.3780517578125 +91240 0.341094970703125 +91241 0.3890380859375 +91242 0.368011474609375 +91243 0.387420654296875 +91244 0.37249755859375 +91245 0.364105224609375 +91246 0.30072021484375 +91247 0.299713134765625 +91248 0.1517333984375 +91249 0.1961669921875 +91250 -0.01470947265625 +91251 0.079620361328125 +91252 -0.1883544921875 +91253 -0.04290771484375 +91254 -0.372711181640625 +91255 -0.16973876953125 +91256 -0.51397705078125 +91257 -0.276824951171875 +91258 -0.57177734375 +91259 -0.3455810546875 +91260 -0.53948974609375 +91261 -0.37103271484375 +91262 -0.43511962890625 +91263 -0.358428955078125 +91264 -0.2962646484375 +91265 -0.32122802734375 +91266 -0.161102294921875 +91267 -0.2738037109375 +91268 -0.0435791015625 +91269 -0.22161865234375 +91270 0.060394287109375 +91271 -0.16375732421875 +91272 0.13665771484375 +91273 -0.10699462890625 +91274 0.170135498046875 +91275 -0.058990478515625 +91276 0.16552734375 +91277 -0.020050048828125 +91278 0.15728759765625 +91279 0.02093505859375 +91280 0.150787353515625 +91281 0.063568115234375 +91282 0.12200927734375 +91283 0.095916748046875 +91284 0.080108642578125 +91285 0.119232177734375 +91286 0.05126953125 +91287 0.1417236328125 +91288 0.062896728515625 +91289 0.1724853515625 +91290 0.09271240234375 +91291 0.201568603515625 +91292 0.092987060546875 +91293 0.209564208984375 +91294 0.07855224609375 +91295 0.2021484375 +91296 0.06427001953125 +91297 0.18548583984375 +91298 0.0347900390625 +91299 0.154449462890625 +91300 -0.01171875 +91301 0.109588623046875 +91302 -0.056060791015625 +91303 0.060089111328125 +91304 -0.055511474609375 +91305 0.024627685546875 +91306 -0.010467529296875 +91307 0.005096435546875 +91308 0.02508544921875 +91309 -0.017547607421875 +91310 0.025665283203125 +91311 -0.051300048828125 +91312 0.017333984375 +91313 -0.084197998046875 +91314 0.00189208984375 +91315 -0.114044189453125 +91316 -0.03173828125 +91317 -0.14404296875 +91318 -0.071502685546875 +91319 -0.16876220703125 +91320 -0.13543701171875 +91321 -0.195037841796875 +91322 -0.219970703125 +91323 -0.221588134765625 +91324 -0.300506591796875 +91325 -0.239349365234375 +91326 -0.376312255859375 +91327 -0.2490234375 +91328 -0.416107177734375 +91329 -0.239593505859375 +91330 -0.371124267578125 +91331 -0.193450927734375 +91332 -0.242279052734375 +91333 -0.11260986328125 +91334 -0.069732666015625 +91335 -0.0145263671875 +91336 0.125640869140625 +91337 0.0909423828125 +91338 0.31268310546875 +91339 0.190032958984375 +91340 0.45501708984375 +91341 0.267181396484375 +91342 0.554779052734375 +91343 0.322174072265625 +91344 0.61065673828125 +91345 0.353790283203125 +91346 0.610931396484375 +91347 0.357086181640625 +91348 0.531463623046875 +91349 0.3226318359375 +91350 0.3883056640625 +91351 0.257080078125 +91352 0.23468017578125 +91353 0.181976318359375 +91354 0.095245361328125 +91355 0.10797119140625 +91356 -0.00396728515625 +91357 0.04644775390625 +91358 -0.04852294921875 +91359 0.004364013671875 +91360 -0.055145263671875 +91361 -0.023406982421875 +91362 -0.0758056640625 +91363 -0.055877685546875 +91364 -0.138702392578125 +91365 -0.102752685546875 +91366 -0.209197998046875 +91367 -0.1492919921875 +91368 -0.289031982421875 +91369 -0.19525146484375 +91370 -0.37884521484375 +91371 -0.240234375 +91372 -0.456329345703125 +91373 -0.27508544921875 +91374 -0.51641845703125 +91375 -0.2977294921875 +91376 -0.519287109375 +91377 -0.292755126953125 +91378 -0.458251953125 +91379 -0.258026123046875 +91380 -0.384796142578125 +91381 -0.214447021484375 +91382 -0.323699951171875 +91383 -0.17266845703125 +91384 -0.269287109375 +91385 -0.131500244140625 +91386 -0.1951904296875 +91387 -0.08172607421875 +91388 -0.100006103515625 +91389 -0.02398681640625 +91390 -0.01055908203125 +91391 0.03009033203125 +91392 0.1033935546875 +91393 0.09149169921875 +91394 0.24908447265625 +91395 0.162200927734375 +91396 0.373199462890625 +91397 0.220306396484375 +91398 0.45806884765625 +91399 0.25848388671875 +91400 0.511474609375 +91401 0.27978515625 +91402 0.565399169921875 +91403 0.29718017578125 +91404 0.61138916015625 +91405 0.30767822265625 +91406 0.5897216796875 +91407 0.287933349609375 +91408 0.4906005859375 +91409 0.234710693359375 +91410 0.33148193359375 +91411 0.15582275390625 +91412 0.147796630859375 +91413 0.066314697265625 +91414 -0.01873779296875 +91415 -0.0162353515625 +91416 -0.140289306640625 +91417 -0.079833984375 +91418 -0.191986083984375 +91419 -0.113739013671875 +91420 -0.184295654296875 +91421 -0.1214599609375 +91422 -0.161834716796875 +91423 -0.120330810546875 +91424 -0.166595458984375 +91425 -0.126800537109375 +91426 -0.19390869140625 +91427 -0.13885498046875 +91428 -0.22442626953125 +91429 -0.1488037109375 +91430 -0.279754638671875 +91431 -0.16552734375 +91432 -0.3389892578125 +91433 -0.1810302734375 +91434 -0.3543701171875 +91435 -0.176727294921875 +91436 -0.348175048828125 +91437 -0.16217041015625 +91438 -0.32598876953125 +91439 -0.140289306640625 +91440 -0.2581787109375 +91441 -0.100006103515625 +91442 -0.139801025390625 +91443 -0.0400390625 +91444 0.014617919921875 +91445 0.033111572265625 +91446 0.144378662109375 +91447 0.09454345703125 +91448 0.221038818359375 +91449 0.132476806640625 +91450 0.27069091796875 +91451 0.156982421875 +91452 0.294036865234375 +91453 0.168182373046875 +91454 0.311767578125 +91455 0.17431640625 +91456 0.339141845703125 +91457 0.181732177734375 +91458 0.360260009765625 +91459 0.184600830078125 +91460 0.360504150390625 +91461 0.177398681640625 +91462 0.308380126953125 +91463 0.1470947265625 +91464 0.18170166015625 +91465 0.08465576171875 +91466 0.0047607421875 +91467 0.0008544921875 +91468 -0.17559814453125 +91469 -0.084014892578125 +91470 -0.3143310546875 +91471 -0.15045166015625 +91472 -0.36785888671875 +91473 -0.179595947265625 +91474 -0.36248779296875 +91475 -0.18231201171875 +91476 -0.343536376953125 +91477 -0.177581787109375 +91478 -0.3018798828125 +91479 -0.16143798828125 +91480 -0.231414794921875 +91481 -0.1312255859375 +91482 -0.117645263671875 +91483 -0.08087158203125 +91484 0.007049560546875 +91485 -0.024261474609375 +91486 0.087982177734375 +91487 0.01513671875 +91488 0.13946533203125 +91489 0.0430908203125 +91490 0.17425537109375 +91491 0.064666748046875 +91492 0.188201904296875 +91493 0.07769775390625 +91494 0.171234130859375 +91495 0.0775146484375 +91496 0.118438720703125 +91497 0.061676025390625 +91498 0.05706787109375 +91499 0.041412353515625 +91500 -0.010711669921875 +91501 0.017333984375 +91502 -0.0914306640625 +91503 -0.0135498046875 +91504 -0.162322998046875 +91505 -0.041717529296875 +91506 -0.194549560546875 +91507 -0.055023193359375 +91508 -0.1492919921875 +91509 -0.036956787109375 +91510 -0.02166748046875 +91511 0.014617919921875 +91512 0.124053955078125 +91513 0.0726318359375 +91514 0.211151123046875 +91515 0.10479736328125 +91516 0.240447998046875 +91517 0.11175537109375 +91518 0.242218017578125 +91519 0.10662841796875 +91520 0.2257080078125 +91521 0.093719482421875 +91522 0.194366455078125 +91523 0.074798583984375 +91524 0.115509033203125 +91525 0.036285400390625 +91526 0.0128173828125 +91527 -0.011444091796875 +91528 -0.053802490234375 +91529 -0.042816162109375 +91530 -0.110626220703125 +91531 -0.068817138671875 +91532 -0.199493408203125 +91533 -0.107147216796875 +91534 -0.29437255859375 +91535 -0.14678955078125 +91536 -0.33221435546875 +91537 -0.161041259765625 +91538 -0.27972412109375 +91539 -0.13592529296875 +91540 -0.185333251953125 +91541 -0.0921630859375 +91542 -0.128204345703125 +91543 -0.063568115234375 +91544 -0.115692138671875 +91545 -0.053466796875 +91546 -0.116455078125 +91547 -0.048858642578125 +91548 -0.105926513671875 +91549 -0.03961181640625 +91550 -0.053955078125 +91551 -0.013214111328125 +91552 0.048797607421875 +91553 0.0340576171875 +91554 0.157318115234375 +91555 0.082916259765625 +91556 0.212005615234375 +91557 0.108001708984375 +91558 0.218475341796875 +91559 0.111602783203125 +91560 0.23724365234375 +91561 0.119384765625 +91562 0.30535888671875 +91563 0.147064208984375 +91564 0.38128662109375 +91565 0.1771240234375 +91566 0.404449462890625 +91567 0.183990478515625 +91568 0.3944091796875 +91569 0.176177978515625 +91570 0.3885498046875 +91571 0.16973876953125 +91572 0.362640380859375 +91573 0.154632568359375 +91574 0.27362060546875 +91575 0.11285400390625 +91576 0.11712646484375 +91577 0.042755126953125 +91578 -0.054901123046875 +91579 -0.033416748046875 +91580 -0.19085693359375 +91581 -0.0936279296875 +91582 -0.28570556640625 +91583 -0.1356201171875 +91584 -0.339263916015625 +91585 -0.159271240234375 +91586 -0.3775634765625 +91587 -0.175537109375 +91588 -0.445709228515625 +91589 -0.20361328125 +91590 -0.535064697265625 +91591 -0.239898681640625 +91592 -0.629058837890625 +91593 -0.2774658203125 +91594 -0.697601318359375 +91595 -0.303680419921875 +91596 -0.70391845703125 +91597 -0.303131103515625 +91598 -0.6424560546875 +91599 -0.273651123046875 +91600 -0.491241455078125 +91601 -0.206146240234375 +91602 -0.265716552734375 +91603 -0.107330322265625 +91604 -0.023712158203125 +91605 -0.00189208984375 +91606 0.201751708984375 +91607 0.095977783203125 +91608 0.375823974609375 +91609 0.171417236328125 +91610 0.485076904296875 +91611 0.218658447265625 +91612 0.56884765625 +91613 0.254364013671875 +91614 0.634765625 +91615 0.281768798828125 +91616 0.63763427734375 +91617 0.281768798828125 +91618 0.5660400390625 +91619 0.2496337890625 +91620 0.4720458984375 +91621 0.20751953125 +91622 0.40692138671875 +91623 0.177276611328125 +91624 0.3778076171875 +91625 0.162109375 +91626 0.376953125 +91627 0.158905029296875 +91628 0.371978759765625 +91629 0.15411376953125 +91630 0.313140869140625 +91631 0.12677001953125 +91632 0.184417724609375 +91633 0.070159912109375 +91634 0.011199951171875 +91635 -0.004791259765625 +91636 -0.171051025390625 +91637 -0.082977294921875 +91638 -0.33740234375 +91639 -0.15380859375 +91640 -0.47198486328125 +91641 -0.210540771484375 +91642 -0.560394287109375 +91643 -0.247100830078125 +91644 -0.58056640625 +91645 -0.25421142578125 +91646 -0.54754638671875 +91647 -0.238372802734375 +91648 -0.508575439453125 +91649 -0.2198486328125 +91650 -0.459503173828125 +91651 -0.19677734375 +91652 -0.394378662109375 +91653 -0.166961669921875 +91654 -0.35260009765625 +91655 -0.14837646484375 +91656 -0.31170654296875 +91657 -0.1307373046875 +91658 -0.197418212890625 +91659 -0.080169677734375 +91660 -0.007965087890625 +91661 0.004180908203125 +91662 0.207489013671875 +91663 0.100006103515625 +91664 0.409210205078125 +91665 0.189300537109375 +91666 0.57208251953125 +91667 0.260772705078125 +91668 0.66595458984375 +91669 0.30084228515625 +91670 0.65875244140625 +91671 0.2950439453125 +91672 0.56744384765625 +91673 0.251251220703125 +91674 0.431396484375 +91675 0.1875 +91676 0.29443359375 +91677 0.123870849609375 +91678 0.182464599609375 +91679 0.072265625 +91680 0.06365966796875 +91681 0.018157958984375 +91682 -0.075958251953125 +91683 -0.044830322265625 +91684 -0.189422607421875 +91685 -0.0953369140625 +91686 -0.271942138671875 +91687 -0.131256103515625 +91688 -0.342529296875 +91689 -0.161346435546875 +91690 -0.364166259765625 +91691 -0.168914794921875 +91692 -0.327239990234375 +91693 -0.149688720703125 +91694 -0.2769775390625 +91695 -0.124420166015625 +91696 -0.253692626953125 +91697 -0.111602783203125 +91698 -0.24365234375 +91699 -0.105072021484375 +91700 -0.1983642578125 +91701 -0.082855224609375 +91702 -0.116241455078125 +91703 -0.0443115234375 +91704 -0.036834716796875 +91705 -0.007476806640625 +91706 0.034881591796875 +91707 0.02532958984375 +91708 0.09124755859375 +91709 0.050628662109375 +91710 0.10888671875 +91711 0.05780029296875 +91712 0.125518798828125 +91713 0.0640869140625 +91714 0.15771484375 +91715 0.0771484375 +91716 0.17828369140625 +91717 0.084686279296875 +91718 0.17108154296875 +91719 0.07940673828125 +91720 0.129974365234375 +91721 0.05865478515625 +91722 0.082427978515625 +91723 0.035064697265625 +91724 0.027679443359375 +91725 0.008392333984375 +91726 -0.065643310546875 +91727 -0.035552978515625 +91728 -0.15936279296875 +91729 -0.07928466796875 +91730 -0.21307373046875 +91731 -0.104339599609375 +91732 -0.234649658203125 +91733 -0.11431884765625 +91734 -0.2001953125 +91735 -0.098358154296875 +91736 -0.119171142578125 +91737 -0.060760498046875 +91738 -0.024749755859375 +91739 -0.0167236328125 +91740 0.085784912109375 +91741 0.034912109375 +91742 0.178131103515625 +91743 0.07843017578125 +91744 0.215576171875 +91745 0.097015380859375 +91746 0.211456298828125 +91747 0.0966796875 +91748 0.17523193359375 +91749 0.0816650390625 +91750 0.128753662109375 +91751 0.06182861328125 +91752 0.1019287109375 +91753 0.050750732421875 +91754 0.0743408203125 +91755 0.0390625 +91756 0.04327392578125 +91757 0.025482177734375 +91758 0.038177490234375 +91759 0.0234375 +91760 0.076263427734375 +91761 0.040740966796875 +91762 0.14105224609375 +91763 0.06988525390625 +91764 0.186431884765625 +91765 0.089874267578125 +91766 0.188812255859375 +91767 0.089996337890625 +91768 0.1390380859375 +91769 0.066131591796875 +91770 0.041778564453125 +91771 0.0205078125 +91772 -0.079437255859375 +91773 -0.036041259765625 +91774 -0.219390869140625 +91775 -0.101104736328125 +91776 -0.367828369140625 +91777 -0.169921875 +91778 -0.494873046875 +91779 -0.228790283203125 +91780 -0.556243896484375 +91781 -0.257476806640625 +91782 -0.508697509765625 +91783 -0.236236572265625 +91784 -0.3756103515625 +91785 -0.17572021484375 +91786 -0.218902587890625 +91787 -0.10418701171875 +91788 -0.063751220703125 +91789 -0.033111572265625 +91790 0.091552734375 +91791 0.038238525390625 +91792 0.23602294921875 +91793 0.10479736328125 +91794 0.342987060546875 +91795 0.154388427734375 +91796 0.39520263671875 +91797 0.179107666015625 +91798 0.389373779296875 +91799 0.177398681640625 +91800 0.324249267578125 +91801 0.148651123046875 +91802 0.224090576171875 +91803 0.1038818359375 +91804 0.124267578125 +91805 0.05914306640625 +91806 0.037078857421875 +91807 0.019989013671875 +91808 -0.010101318359375 +91809 -0.0010986328125 +91810 -0.019439697265625 +91811 -0.005157470703125 +91812 -0.022796630859375 +91813 -0.006683349609375 +91814 -0.001556396484375 +91815 0.002777099609375 +91816 0.056304931640625 +91817 0.02874755859375 +91818 0.106719970703125 +91819 0.0511474609375 +91820 0.096893310546875 +91821 0.045928955078125 +91822 0.042694091796875 +91823 0.020416259765625 +91824 -0.018035888671875 +91825 -0.008087158203125 +91826 -0.07586669921875 +91827 -0.035247802734375 +91828 -0.11944580078125 +91829 -0.055816650390625 +91830 -0.15972900390625 +91831 -0.07476806640625 +91832 -0.202606201171875 +91833 -0.094757080078125 +91834 -0.24859619140625 +91835 -0.115966796875 +91836 -0.30517578125 +91837 -0.141815185546875 +91838 -0.36212158203125 +91839 -0.16766357421875 +91840 -0.39141845703125 +91841 -0.1807861328125 +91842 -0.35528564453125 +91843 -0.1639404296875 +91844 -0.249969482421875 +91845 -0.115447998046875 +91846 -0.092864990234375 +91847 -0.04327392578125 +91848 0.08905029296875 +91849 0.040252685546875 +91850 0.2352294921875 +91851 0.107513427734375 +91852 0.318817138671875 +91853 0.146209716796875 +91854 0.358642578125 +91855 0.164886474609375 +91856 0.347747802734375 +91857 0.16033935546875 +91858 0.28564453125 +91859 0.13232421875 +91860 0.223175048828125 +91861 0.10400390625 +91862 0.196746826171875 +91863 0.09197998046875 +91864 0.179840087890625 +91865 0.084197998046875 +91866 0.155548095703125 +91867 0.07293701171875 +91868 0.151214599609375 +91869 0.0706787109375 +91870 0.156951904296875 +91871 0.07293701171875 +91872 0.13177490234375 +91873 0.061004638671875 +91874 0.100799560546875 +91875 0.04638671875 +91876 0.087127685546875 +91877 0.039642333984375 +91878 0.05487060546875 +91879 0.02447509765625 +91880 -0.009002685546875 +91881 -0.00506591796875 +91882 -0.10400390625 +91883 -0.0487060546875 +91884 -0.229400634765625 +91885 -0.106109619140625 +91886 -0.35552978515625 +91887 -0.16375732421875 +91888 -0.441925048828125 +91889 -0.203155517578125 +91890 -0.473846435546875 +91891 -0.217620849609375 +91892 -0.464813232421875 +91893 -0.21331787109375 +91894 -0.419097900390625 +91895 -0.19219970703125 +91896 -0.334320068359375 +91897 -0.1531982421875 +91898 -0.227935791015625 +91899 -0.104278564453125 +91900 -0.12347412109375 +91901 -0.05621337890625 +91902 -0.02764892578125 +91903 -0.0120849609375 +91904 0.077667236328125 +91905 0.036285400390625 +91906 0.2132568359375 +91907 0.098602294921875 +91908 0.38885498046875 +91909 0.18011474609375 +91910 0.582794189453125 +91911 0.2708740234375 +91912 0.734039306640625 +91913 0.341583251953125 +91914 0.800140380859375 +91915 0.371856689453125 +91916 0.7783203125 +91917 0.36053466796875 +91918 0.6651611328125 +91919 0.30596923828125 +91920 0.45965576171875 +91921 0.207611083984375 +91922 0.199188232421875 +91923 0.083587646484375 +91924 -0.050689697265625 +91925 -0.034332275390625 +91926 -0.23297119140625 +91927 -0.118621826171875 +91928 -0.33013916015625 +91929 -0.16107177734375 +91930 -0.368408203125 +91931 -0.174774169921875 +91932 -0.378936767578125 +91933 -0.17523193359375 +91934 -0.376983642578125 +91935 -0.17022705078125 +91936 -0.37969970703125 +91937 -0.1683349609375 +91938 -0.391510009765625 +91939 -0.171844482421875 +91940 -0.385345458984375 +91941 -0.167694091796875 +91942 -0.3419189453125 +91943 -0.146484375 +91944 -0.28289794921875 +91945 -0.118804931640625 +91946 -0.251617431640625 +91947 -0.105682373046875 +91948 -0.266143798828125 +91949 -0.11578369140625 +91950 -0.273345947265625 +91951 -0.12298583984375 +91952 -0.216796875 +91953 -0.099517822265625 +91954 -0.128265380859375 +91955 -0.060638427734375 +91956 -0.068145751953125 +91957 -0.03558349609375 +91958 -0.0430908203125 +91959 -0.027374267578125 +91960 -0.024444580078125 +91961 -0.021820068359375 +91962 0.020721435546875 +91963 -0.00262451171875 +91964 0.124481201171875 +91965 0.04595947265625 +91966 0.25787353515625 +91967 0.10986328125 +91968 0.379119873046875 +91969 0.168731689453125 +91970 0.47991943359375 +91971 0.218536376953125 +91972 0.5281982421875 +91973 0.2435302734375 +91974 0.511138916015625 +91975 0.23736572265625 +91976 0.456207275390625 +91977 0.21331787109375 +91978 0.407470703125 +91979 0.192718505859375 +91980 0.383758544921875 +91981 0.1845703125 +91982 0.35687255859375 +91983 0.1749267578125 +91984 0.31182861328125 +91985 0.156280517578125 +91986 0.250885009765625 +91987 0.1295166015625 +91988 0.1654052734375 +91989 0.090301513671875 +91990 0.035247802734375 +91991 0.0286865234375 +91992 -0.142059326171875 +91993 -0.056610107421875 +91994 -0.33563232421875 +91995 -0.150543212890625 +91996 -0.5345458984375 +91997 -0.247772216796875 +91998 -0.72186279296875 +91999 -0.34002685546875 +92000 -0.836669921875 +92001 -0.39752197265625 +92002 -0.8326416015625 +92003 -0.397552490234375 +92004 -0.7296142578125 +92005 -0.34967041015625 +92006 -0.582550048828125 +92007 -0.28057861328125 +92008 -0.440093994140625 +92009 -0.213836669921875 +92010 -0.324310302734375 +92011 -0.160064697265625 +92012 -0.20147705078125 +92013 -0.102630615234375 +92014 -0.044647216796875 +92015 -0.02825927734375 +92016 0.103973388671875 +92017 0.042510986328125 +92018 0.202392578125 +92019 0.089263916015625 +92020 0.264495849609375 +92021 0.118865966796875 +92022 0.338897705078125 +92023 0.155059814453125 +92024 0.443817138671875 +92025 0.206695556640625 +92026 0.545074462890625 +92027 0.257049560546875 +92028 0.6173095703125 +92029 0.293701171875 +92030 0.6524658203125 +92031 0.312652587890625 +92032 0.66339111328125 +92033 0.320037841796875 +92034 0.6561279296875 +92035 0.31866455078125 +92036 0.606781005859375 +92037 0.2967529296875 +92038 0.501190185546875 +92039 0.247283935546875 +92040 0.352783203125 +92041 0.17669677734375 +92042 0.176544189453125 +92043 0.09222412109375 +92044 -0.034820556640625 +92045 -0.009735107421875 +92046 -0.258209228515625 +92047 -0.117950439453125 +92048 -0.44244384765625 +92049 -0.207489013671875 +92050 -0.5753173828125 +92051 -0.27239990234375 +92052 -0.65203857421875 +92053 -0.310333251953125 +92054 -0.641632080078125 +92055 -0.30615234375 +92056 -0.562164306640625 +92057 -0.268646240234375 +92058 -0.458038330078125 +92059 -0.219390869140625 +92060 -0.350555419921875 +92061 -0.168670654296875 +92062 -0.260528564453125 +92063 -0.12652587890625 +92064 -0.192108154296875 +92065 -0.09490966796875 +92066 -0.141937255859375 +92067 -0.072052001953125 +92068 -0.1021728515625 +92069 -0.054046630859375 +92070 -0.062896728515625 +92071 -0.035980224609375 +92072 -0.011932373046875 +92073 -0.011871337890625 +92074 0.062835693359375 +92075 0.024200439453125 +92076 0.148712158203125 +92077 0.066070556640625 +92078 0.241729736328125 +92079 0.11175537109375 +92080 0.34912109375 +92081 0.164764404296875 +92082 0.457305908203125 +92083 0.21844482421875 +92084 0.54388427734375 +92085 0.261810302734375 +92086 0.5728759765625 +92087 0.277252197265625 +92088 0.506591796875 +92089 0.246307373046875 +92090 0.351226806640625 +92091 0.171905517578125 +92092 0.146514892578125 +92093 0.0733642578125 +92094 -0.05523681640625 +92095 -0.02386474609375 +92096 -0.21624755859375 +92097 -0.1014404296875 +92098 -0.334930419921875 +92099 -0.158599853515625 +92100 -0.402984619140625 +92101 -0.191314697265625 +92102 -0.4412841796875 +92103 -0.20977783203125 +92104 -0.49578857421875 +92105 -0.2364501953125 +92106 -0.5601806640625 +92107 -0.268218994140625 +92108 -0.600738525390625 +92109 -0.288604736328125 +92110 -0.584228515625 +92111 -0.2813720703125 +92112 -0.47930908203125 +92113 -0.23114013671875 +92114 -0.27935791015625 +92115 -0.1346435546875 +92116 -0.0089111328125 +92117 -0.0037841796875 +92118 0.268798828125 +92119 0.130615234375 +92120 0.482818603515625 +92121 0.2340087890625 +92122 0.60369873046875 +92123 0.292083740234375 +92124 0.650421142578125 +92125 0.314117431640625 +92126 0.66400146484375 +92127 0.3201904296875 +92128 0.6414794921875 +92129 0.308868408203125 +92130 0.572540283203125 +92131 0.275146484375 +92132 0.498138427734375 +92133 0.23895263671875 +92134 0.439453125 +92135 0.210662841796875 +92136 0.375518798828125 +92137 0.180023193359375 +92138 0.274505615234375 +92139 0.1314697265625 +92140 0.1087646484375 +92141 0.05145263671875 +92142 -0.099395751953125 +92143 -0.049224853515625 +92144 -0.3182373046875 +92145 -0.155059814453125 +92146 -0.5489501953125 +92147 -0.2667236328125 +92148 -0.7738037109375 +92149 -0.375579833984375 +92150 -0.86383056640625 +92151 -0.455841064453125 +92152 -0.870391845703125 +92153 -0.4913330078125 +92154 -0.86895751953125 +92155 -0.49072265625 +92156 -0.861053466796875 +92157 -0.46044921875 +92158 -0.765869140625 +92159 -0.392059326171875 +92160 -0.5301513671875 +92161 -0.27996826171875 +92162 -0.214691162109375 +92163 -0.127105712890625 +92164 0.137359619140625 +92165 0.045318603515625 +92166 0.474822998046875 +92167 0.211639404296875 +92168 0.76239013671875 +92169 0.354217529296875 +92170 0.867462158203125 +92171 0.459747314453125 +92172 0.870361328125 +92173 0.5289306640625 +92174 0.86480712890625 +92175 0.55609130859375 +92176 0.831817626953125 +92177 0.544158935546875 +92178 0.677581787109375 +92179 0.50579833984375 +92180 0.495880126953125 +92181 0.44384765625 +92182 0.30767822265625 +92183 0.36767578125 +92184 0.116180419921875 +92185 0.278045654296875 +92186 -0.110748291015625 +92187 0.157989501953125 +92188 -0.381805419921875 +92189 0.00335693359375 +92190 -0.6572265625 +92191 -0.164093017578125 +92192 -0.857421875 +92193 -0.313720703125 +92194 -0.870391845703125 +92195 -0.42364501953125 +92196 -0.870391845703125 +92197 -0.490570068359375 +92198 -0.86444091796875 +92199 -0.52880859375 +92200 -0.85723876953125 +92201 -0.55712890625 +92202 -0.790008544921875 +92203 -0.56610107421875 +92204 -0.62847900390625 +92205 -0.52752685546875 +92206 -0.3956298828125 +92207 -0.439605712890625 +92208 -0.126708984375 +92209 -0.3192138671875 +92210 0.150115966796875 +92211 -0.180328369140625 +92212 0.424041748046875 +92213 -0.0286865234375 +92214 0.670623779296875 +92215 0.1220703125 +92216 0.854522705078125 +92217 0.252166748046875 +92218 0.866485595703125 +92219 0.352783203125 +92220 0.86920166015625 +92221 0.41632080078125 +92222 0.8653564453125 +92223 0.4525146484375 +92224 0.857147216796875 +92225 0.468597412109375 +92226 0.766845703125 +92227 0.463287353515625 +92228 0.628509521484375 +92229 0.439361572265625 +92230 0.462127685546875 +92231 0.393341064453125 +92232 0.297210693359375 +92233 0.33856201171875 +92234 0.14862060546875 +92235 0.281341552734375 +92236 -0.00537109375 +92237 0.2095947265625 +92238 -0.15753173828125 +92239 0.126983642578125 +92240 -0.31304931640625 +92241 0.03131103515625 +92242 -0.48876953125 +92243 -0.084991455078125 +92244 -0.6416015625 +92245 -0.1978759765625 +92246 -0.751373291015625 +92247 -0.294769287109375 +92248 -0.84619140625 +92249 -0.387969970703125 +92250 -0.861297607421875 +92251 -0.47003173828125 +92252 -0.863250732421875 +92253 -0.523895263671875 +92254 -0.856597900390625 +92255 -0.533233642578125 +92256 -0.7498779296875 +92257 -0.504425048828125 +92258 -0.624542236328125 +92259 -0.467559814453125 +92260 -0.47808837890625 +92261 -0.411102294921875 +92262 -0.253387451171875 +92263 -0.304534912109375 +92264 0.003692626953125 +92265 -0.17138671875 +92266 0.2257080078125 +92267 -0.0469970703125 +92268 0.427154541015625 +92269 0.075408935546875 +92270 0.643218994140625 +92271 0.212921142578125 +92272 0.855926513671875 +92273 0.360748291015625 +92274 0.870361328125 +92275 0.48895263671875 +92276 0.870361328125 +92277 0.571929931640625 +92278 0.862762451171875 +92279 0.61358642578125 +92280 0.79669189453125 +92281 0.612457275390625 +92282 0.595794677734375 +92283 0.563690185546875 +92284 0.362152099609375 +92285 0.482452392578125 +92286 0.1270751953125 +92287 0.383270263671875 +92288 -0.086944580078125 +92289 0.277069091796875 +92290 -0.2784423828125 +92291 0.164825439453125 +92292 -0.484832763671875 +92293 0.0283203125 +92294 -0.729583740234375 +92295 -0.142547607421875 +92296 -0.86688232421875 +92297 -0.3216552734375 +92298 -0.870391845703125 +92299 -0.47625732421875 +92300 -0.86859130859375 +92301 -0.603912353515625 +92302 -0.86279296875 +92303 -0.70361328125 +92304 -0.817962646484375 +92305 -0.75677490234375 +92306 -0.6116943359375 +92307 -0.7398681640625 +92308 -0.3128662109375 +92309 -0.64923095703125 +92310 0.039398193359375 +92311 -0.502410888671875 +92312 0.422821044921875 +92313 -0.309783935546875 +92314 0.805145263671875 +92315 -0.088623046875 +92316 0.870361328125 +92317 0.125640869140625 +92318 0.870361328125 +92319 0.30340576171875 +92320 0.860015869140625 +92321 0.4385986328125 +92322 0.727935791015625 +92323 0.52728271484375 +92324 0.48114013671875 +92325 0.566558837890625 +92326 0.2059326171875 +92327 0.569000244140625 +92328 -0.06103515625 +92329 0.546356201171875 +92330 -0.29913330078125 +92331 0.503875732421875 +92332 -0.516204833984375 +92333 0.43402099609375 +92334 -0.7252197265625 +92335 0.328857421875 +92336 -0.85980224609375 +92337 0.201385498046875 +92338 -0.870391845703125 +92339 0.069549560546875 +92340 -0.870391845703125 +92341 -0.051116943359375 +92342 -0.858062744140625 +92343 -0.13519287109375 +92344 -0.673004150390625 +92345 -0.1802978515625 +92346 -0.42694091796875 +92347 -0.213531494140625 +92348 -0.2100830078125 +92349 -0.257781982421875 +92350 -0.0362548828125 +92351 -0.311767578125 +92352 0.10943603515625 +92353 -0.360260009765625 +92354 0.23516845703125 +92355 -0.392791748046875 +92356 0.373687744140625 +92357 -0.38775634765625 +92358 0.517791748046875 +92359 -0.34613037109375 +92360 0.602783203125 +92361 -0.30072021484375 +92362 0.635711669921875 +92363 -0.248870849609375 +92364 0.655181884765625 +92365 -0.17340087890625 +92366 0.65948486328125 +92367 -0.07965087890625 +92368 0.651275634765625 +92369 0.027984619140625 +92370 0.61846923828125 +92371 0.136505126953125 +92372 0.53753662109375 +92373 0.226470947265625 +92374 0.404144287109375 +92375 0.288238525390625 +92376 0.22186279296875 +92377 0.316558837890625 +92378 0.003997802734375 +92379 0.3118896484375 +92380 -0.22100830078125 +92381 0.28350830078125 +92382 -0.42449951171875 +92383 0.242034912109375 +92384 -0.579833984375 +92385 0.198516845703125 +92386 -0.641876220703125 +92387 0.1751708984375 +92388 -0.6177978515625 +92389 0.1685791015625 +92390 -0.575531005859375 +92391 0.145263671875 +92392 -0.526336669921875 +92393 0.10260009765625 +92394 -0.42645263671875 +92395 0.067718505859375 +92396 -0.2581787109375 +92397 0.055084228515625 +92398 -0.068695068359375 +92399 0.046051025390625 +92400 0.09222412109375 +92401 0.020782470703125 +92402 0.232147216796875 +92403 -0.010772705078125 +92404 0.3509521484375 +92405 -0.0430908203125 +92406 0.410064697265625 +92407 -0.0914306640625 +92408 0.372955322265625 +92409 -0.1708984375 +92410 0.2554931640625 +92411 -0.270477294921875 +92412 0.10711669921875 +92413 -0.363006591796875 +92414 -0.052886962890625 +92415 -0.43829345703125 +92416 -0.186279296875 +92417 -0.47711181640625 +92418 -0.23291015625 +92419 -0.450042724609375 +92420 -0.209442138671875 +92421 -0.369903564453125 +92422 -0.174163818359375 +92423 -0.27239990234375 +92424 -0.126739501953125 +92425 -0.1614990234375 +92426 -0.048126220703125 +92427 -0.031280517578125 +92428 0.0426025390625 +92429 0.103179931640625 +92430 0.10748291015625 +92431 0.21661376953125 +92432 0.1409912109375 +92433 0.302032470703125 +92434 0.19708251953125 +92435 0.3858642578125 +92436 0.273651123046875 +92437 0.464508056640625 +92438 0.31768798828125 +92439 0.50726318359375 +92440 0.341094970703125 +92441 0.520172119140625 +92442 0.368011474609375 +92443 0.51702880859375 +92444 0.37249755859375 +92445 0.48504638671875 +92446 0.30072021484375 +92447 0.396942138671875 +92448 0.1517333984375 +92449 0.25518798828125 +92450 -0.01470947265625 +92451 0.096221923828125 +92452 -0.1883544921875 +92453 -0.070404052734375 +92454 -0.372711181640625 +92455 -0.242645263671875 +92456 -0.51397705078125 +92457 -0.387115478515625 +92458 -0.57177734375 +92459 -0.47802734375 +92460 -0.53948974609375 +92461 -0.508758544921875 +92462 -0.43511962890625 +92463 -0.48687744140625 +92464 -0.2962646484375 +92465 -0.4315185546875 +92466 -0.161102294921875 +92467 -0.362945556640625 +92468 -0.0435791015625 +92469 -0.2889404296875 +92470 0.060394287109375 +92471 -0.20819091796875 +92472 0.13665771484375 +92473 -0.130157470703125 +92474 0.170135498046875 +92475 -0.065460205078125 +92476 0.16552734375 +92477 -0.01434326171875 +92478 0.15728759765625 +92479 0.038970947265625 +92480 0.150787353515625 +92481 0.09417724609375 +92482 0.12200927734375 +92483 0.13482666015625 +92484 0.080108642578125 +92485 0.1629638671875 +92486 0.05126953125 +92487 0.190338134765625 +92488 0.062896728515625 +92489 0.229888916015625 +92490 0.09271240234375 +92491 0.267852783203125 +92492 0.092987060546875 +92493 0.277130126953125 +92494 0.07855224609375 +92495 0.2657470703125 +92496 0.06427001953125 +92497 0.242431640625 +92498 0.0347900390625 +92499 0.19989013671875 +92500 -0.01171875 +92501 0.13885498046875 +92502 -0.056060791015625 +92503 0.07208251953125 +92504 -0.055511474609375 +92505 0.025604248046875 +92506 -0.010467529296875 +92507 0.001861572265625 +92508 0.02508544921875 +92509 -0.026092529296875 +92510 0.025665283203125 +92511 -0.0697021484375 +92512 0.017333984375 +92513 -0.11236572265625 +92514 0.00189208984375 +92515 -0.15118408203125 +92516 -0.03173828125 +92517 -0.190826416015625 +92518 -0.071502685546875 +92519 -0.223785400390625 +92520 -0.13543701171875 +92521 -0.2596435546875 +92522 -0.219970703125 +92523 -0.29669189453125 +92524 -0.300506591796875 +92525 -0.32220458984375 +92526 -0.376312255859375 +92527 -0.337066650390625 +92528 -0.416107177734375 +92529 -0.325775146484375 +92530 -0.371124267578125 +92531 -0.263519287109375 +92532 -0.242279052734375 +92533 -0.152984619140625 +92534 -0.069732666015625 +92535 -0.0184326171875 +92536 0.125640869140625 +92537 0.126434326171875 +92538 0.31268310546875 +92539 0.26251220703125 +92540 0.45501708984375 +92541 0.368133544921875 +92542 0.554779052734375 +92543 0.443115234375 +92544 0.61065673828125 +92545 0.485870361328125 +92546 0.610931396484375 +92547 0.489532470703125 +92548 0.531463623046875 +92549 0.44085693359375 +92550 0.3883056640625 +92551 0.349212646484375 +92552 0.23468017578125 +92553 0.244781494140625 +92554 0.095245361328125 +92555 0.142425537109375 +92556 -0.00396728515625 +92557 0.05804443359375 +92558 -0.04852294921875 +92559 0.00128173828125 +92560 -0.055145263671875 +92561 -0.035186767578125 +92562 -0.0758056640625 +92563 -0.07818603515625 +92564 -0.138702392578125 +92565 -0.141510009765625 +92566 -0.209197998046875 +92567 -0.204620361328125 +92568 -0.289031982421875 +92569 -0.26727294921875 +92570 -0.37884521484375 +92571 -0.328948974609375 +92572 -0.456329345703125 +92573 -0.37689208984375 +92574 -0.51641845703125 +92575 -0.40826416015625 +92576 -0.519287109375 +92577 -0.40142822265625 +92578 -0.458251953125 +92579 -0.353363037109375 +92580 -0.384796142578125 +92581 -0.293365478515625 +92582 -0.323699951171875 +92583 -0.236236572265625 +92584 -0.269287109375 +92585 -0.18023681640625 +92586 -0.1951904296875 +92587 -0.112396240234375 +92588 -0.100006103515625 +92589 -0.033447265625 +92590 -0.01055908203125 +92591 0.0404052734375 +92592 0.1033935546875 +92593 0.12451171875 +92594 0.24908447265625 +92595 0.22174072265625 +92596 0.373199462890625 +92597 0.301971435546875 +92598 0.45806884765625 +92599 0.35498046875 +92600 0.511474609375 +92601 0.384857177734375 +92602 0.565399169921875 +92603 0.40936279296875 +92604 0.61138916015625 +92605 0.424285888671875 +92606 0.5897216796875 +92607 0.397491455078125 +92608 0.4906005859375 +92609 0.32452392578125 +92610 0.33148193359375 +92611 0.21612548828125 +92612 0.147796630859375 +92613 0.09295654296875 +92614 -0.01873779296875 +92615 -0.020751953125 +92616 -0.140289306640625 +92617 -0.108489990234375 +92618 -0.191986083984375 +92619 -0.155487060546875 +92620 -0.184295654296875 +92621 -0.166534423828125 +92622 -0.161834716796875 +92623 -0.16546630859375 +92624 -0.166595458984375 +92625 -0.17486572265625 +92626 -0.19390869140625 +92627 -0.191925048828125 +92628 -0.22442626953125 +92629 -0.206024169921875 +92630 -0.279754638671875 +92631 -0.229339599609375 +92632 -0.3389892578125 +92633 -0.250885009765625 +92634 -0.3543701171875 +92635 -0.2451171875 +92636 -0.348175048828125 +92637 -0.22515869140625 +92638 -0.32598876953125 +92639 -0.19500732421875 +92640 -0.2581787109375 +92641 -0.139434814453125 +92642 -0.139801025390625 +92643 -0.05670166015625 +92644 0.014617919921875 +92645 0.04425048828125 +92646 0.144378662109375 +92647 0.129180908203125 +92648 0.221038818359375 +92649 0.18182373046875 +92650 0.27069091796875 +92651 0.21600341796875 +92652 0.294036865234375 +92653 0.23187255859375 +92654 0.311767578125 +92655 0.240753173828125 +92656 0.339141845703125 +92657 0.251220703125 +92658 0.360260009765625 +92659 0.2548828125 +92660 0.360504150390625 +92661 0.2442626953125 +92662 0.308380126953125 +92663 0.202606201171875 +92664 0.18170166015625 +92665 0.118408203125 +92666 0.0047607421875 +92667 0.00592041015625 +92668 -0.17559814453125 +92669 -0.108184814453125 +92670 -0.3143310546875 +92671 -0.198272705078125 +92672 -0.36785888671875 +92673 -0.23919677734375 +92674 -0.36248779296875 +92675 -0.245269775390625 +92676 -0.343536376953125 +92677 -0.24169921875 +92678 -0.3018798828125 +92679 -0.222625732421875 +92680 -0.231414794921875 +92681 -0.18408203125 +92682 -0.117645263671875 +92683 -0.117462158203125 +92684 0.007049560546875 +92685 -0.04168701171875 +92686 0.087982177734375 +92687 0.011077880859375 +92688 0.13946533203125 +92689 0.048858642578125 +92690 0.17425537109375 +92691 0.078582763671875 +92692 0.188201904296875 +92693 0.09722900390625 +92694 0.171234130859375 +92695 0.09832763671875 +92696 0.118438720703125 +92697 0.078369140625 +92698 0.05706787109375 +92699 0.05267333984375 +92700 -0.010711669921875 +92701 0.02191162109375 +92702 -0.0914306640625 +92703 -0.0181884765625 +92704 -0.162322998046875 +92705 -0.05462646484375 +92706 -0.194549560546875 +92707 -0.07080078125 +92708 -0.1492919921875 +92709 -0.04412841796875 +92710 -0.02166748046875 +92711 0.02825927734375 +92712 0.124053955078125 +92713 0.109039306640625 +92714 0.211151123046875 +92715 0.1536865234375 +92716 0.240447998046875 +92717 0.163116455078125 +92718 0.242218017578125 +92719 0.155426025390625 +92720 0.2257080078125 +92721 0.13653564453125 +92722 0.194366455078125 +92723 0.1090087890625 +92724 0.115509033203125 +92725 0.054229736328125 +92726 0.0128173828125 +92727 -0.013427734375 +92728 -0.053802490234375 +92729 -0.05865478515625 +92730 -0.110626220703125 +92731 -0.096466064453125 +92732 -0.199493408203125 +92733 -0.151092529296875 +92734 -0.29437255859375 +92735 -0.207275390625 +92736 -0.33221435546875 +92737 -0.228179931640625 +92738 -0.27972412109375 +92739 -0.194488525390625 +92740 -0.185333251953125 +92741 -0.134735107421875 +92742 -0.128204345703125 +92743 -0.095428466796875 +92744 -0.115692138671875 +92745 -0.0811767578125 +92746 -0.116455078125 +92747 -0.074127197265625 +92748 -0.105926513671875 +92749 -0.06036376953125 +92750 -0.053955078125 +92751 -0.022705078125 +92752 0.048797607421875 +92753 0.043914794921875 +92754 0.157318115234375 +92755 0.112884521484375 +92756 0.212005615234375 +92757 0.149139404296875 +92758 0.218475341796875 +92759 0.155731201171875 +92760 0.23724365234375 +92761 0.167877197265625 +92762 0.30535888671875 +92763 0.20721435546875 +92764 0.38128662109375 +92765 0.24951171875 +92766 0.404449462890625 +92767 0.25958251953125 +92768 0.3944091796875 +92769 0.24908447265625 +92770 0.3885498046875 +92771 0.240142822265625 +92772 0.362640380859375 +92773 0.21893310546875 +92774 0.27362060546875 +92775 0.16064453125 +92776 0.11712646484375 +92777 0.063079833984375 +92778 -0.054901123046875 +92779 -0.043060302734375 +92780 -0.19085693359375 +92781 -0.127349853515625 +92782 -0.28570556640625 +92783 -0.186614990234375 +92784 -0.339263916015625 +92785 -0.2205810546875 +92786 -0.3775634765625 +92787 -0.24432373046875 +92788 -0.445709228515625 +92789 -0.284149169921875 +92790 -0.535064697265625 +92791 -0.335052490234375 +92792 -0.629058837890625 +92793 -0.387451171875 +92794 -0.697601318359375 +92795 -0.423919677734375 +92796 -0.70391845703125 +92797 -0.423248291015625 +92798 -0.6424560546875 +92799 -0.3824462890625 +92800 -0.491241455078125 +92801 -0.288970947265625 +92802 -0.265716552734375 +92803 -0.152099609375 +92804 -0.023712158203125 +92805 -0.00592041015625 +92806 0.201751708984375 +92807 0.130035400390625 +92808 0.375823974609375 +92809 0.23516845703125 +92810 0.485076904296875 +92811 0.301513671875 +92812 0.56884765625 +92813 0.351898193359375 +92814 0.634765625 +92815 0.3907470703125 +92816 0.63763427734375 +92817 0.391693115234375 +92818 0.5660400390625 +92819 0.34808349609375 +92820 0.4720458984375 +92821 0.290496826171875 +92822 0.40692138671875 +92823 0.2490234375 +92824 0.3778076171875 +92825 0.228057861328125 +92826 0.376953125 +92827 0.223297119140625 +92828 0.371978759765625 +92829 0.216094970703125 +92830 0.313140869140625 +92831 0.1776123046875 +92832 0.184417724609375 +92833 0.09869384765625 +92834 0.011199951171875 +92835 -0.005584716796875 +92836 -0.171051025390625 +92837 -0.114349365234375 +92838 -0.33740234375 +92839 -0.21295166015625 +92840 -0.47198486328125 +92841 -0.29205322265625 +92842 -0.560394287109375 +92843 -0.34326171875 +92844 -0.58056640625 +92845 -0.353759765625 +92846 -0.54754638671875 +92847 -0.332427978515625 +92848 -0.508575439453125 +92849 -0.3070068359375 +92850 -0.459503173828125 +92851 -0.275238037109375 +92852 -0.394378662109375 +92853 -0.233795166015625 +92854 -0.35260009765625 +92855 -0.205902099609375 +92856 -0.31170654296875 +92857 -0.1785888671875 +92858 -0.197418212890625 +92859 -0.108673095703125 +92860 -0.007965087890625 +92861 0.00469970703125 +92862 0.207489013671875 +92863 0.132659912109375 +92864 0.409210205078125 +92865 0.25189208984375 +92866 0.57208251953125 +92867 0.347686767578125 +92868 0.66595458984375 +92869 0.402435302734375 +92870 0.65875244140625 +92871 0.39739990234375 +92872 0.56744384765625 +92873 0.34259033203125 +92874 0.431396484375 +92875 0.2611083984375 +92876 0.29443359375 +92877 0.17864990234375 +92878 0.182464599609375 +92879 0.1104736328125 +92880 0.06365966796875 +92881 0.038177490234375 +92882 -0.075958251953125 +92883 -0.046234130859375 +92884 -0.189422607421875 +92885 -0.11517333984375 +92886 -0.271942138671875 +92887 -0.165679931640625 +92888 -0.342529296875 +92889 -0.208770751953125 +92890 -0.364166259765625 +92891 -0.222747802734375 +92892 -0.327239990234375 +92893 -0.201934814453125 +92894 -0.2769775390625 +92895 -0.1727294921875 +92896 -0.253692626953125 +92897 -0.15869140625 +92898 -0.24365234375 +92899 -0.15179443359375 +92900 -0.1983642578125 +92901 -0.123809814453125 +92902 -0.116241455078125 +92903 -0.07391357421875 +92904 -0.036834716796875 +92905 -0.025299072265625 +92906 0.034881591796875 +92907 0.018951416015625 +92908 0.09124755859375 +92909 0.05426025390625 +92910 0.10888671875 +92911 0.06683349609375 +92912 0.125518798828125 +92913 0.078582763671875 +92914 0.15771484375 +92915 0.099090576171875 +92916 0.17828369140625 +92917 0.11236572265625 +92918 0.17108154296875 +92919 0.108917236328125 +92920 0.129974365234375 +92921 0.08514404296875 +92922 0.082427978515625 +92923 0.057098388671875 +92924 0.027679443359375 +92925 0.024383544921875 +92926 -0.065643310546875 +92927 -0.03125 +92928 -0.15936279296875 +92929 -0.0870361328125 +92930 -0.21307373046875 +92931 -0.1197509765625 +92932 -0.234649658203125 +92933 -0.134552001953125 +92934 -0.2001953125 +92935 -0.1162109375 +92936 -0.119171142578125 +92937 -0.070037841796875 +92938 -0.024749755859375 +92939 -0.016021728515625 +92940 0.085784912109375 +92941 0.047943115234375 +92942 0.178131103515625 +92943 0.101043701171875 +92944 0.215576171875 +92945 0.1209716796875 +92946 0.211456298828125 +92947 0.116119384765625 +92948 0.17523193359375 +92949 0.09246826171875 +92950 0.128753662109375 +92951 0.06353759765625 +92952 0.1019287109375 +92953 0.0477294921875 +92954 0.0743408203125 +92955 0.032379150390625 +92956 0.04327392578125 +92957 0.01568603515625 +92958 0.038177490234375 +92959 0.015594482421875 +92960 0.076263427734375 +92961 0.042510986328125 +92962 0.14105224609375 +92963 0.086029052734375 +92964 0.186431884765625 +92965 0.1175537109375 +92966 0.188812255859375 +92967 0.122344970703125 +92968 0.1390380859375 +92969 0.094573974609375 +92970 0.041778564453125 +92971 0.0369873046875 +92972 -0.079437255859375 +92973 -0.0360107421875 +92974 -0.219390869140625 +92975 -0.121307373046875 +92976 -0.367828369140625 +92977 -0.21258544921875 +92978 -0.494873046875 +92979 -0.291473388671875 +92980 -0.556243896484375 +92981 -0.330596923828125 +92982 -0.508697509765625 +92983 -0.30322265625 +92984 -0.3756103515625 +92985 -0.223663330078125 +92986 -0.218902587890625 +92987 -0.129913330078125 +92988 -0.063751220703125 +92989 -0.03729248046875 +92990 0.091552734375 +92991 0.055389404296875 +92992 0.23602294921875 +92993 0.14154052734375 +92994 0.342987060546875 +92995 0.204864501953125 +92996 0.39520263671875 +92997 0.234893798828125 +92998 0.389373779296875 +92999 0.229705810546875 +93000 0.324249267578125 +93001 0.1885986328125 +93002 0.224090576171875 +93003 0.126556396484375 +93004 0.124267578125 +93005 0.06536865234375 +93006 0.037078857421875 +93007 0.012542724609375 +93008 -0.010101318359375 +93009 -0.015106201171875 +93010 -0.019439697265625 +93011 -0.019012451171875 +93012 -0.022796630859375 +93013 -0.018890380859375 +93014 -0.001556396484375 +93015 -0.00341796875 +93016 0.056304931640625 +93017 0.03466796875 +93018 0.106719970703125 +93019 0.068115234375 +93020 0.096893310546875 +93021 0.06427001953125 +93022 0.042694091796875 +93023 0.032806396484375 +93024 -0.018035888671875 +93025 -0.00311279296875 +93026 -0.07586669921875 +93027 -0.0377197265625 +93028 -0.11944580078125 +93029 -0.064056396484375 +93030 -0.15972900390625 +93031 -0.088897705078125 +93032 -0.202606201171875 +93033 -0.1158447265625 +93034 -0.24859619140625 +93035 -0.145172119140625 +93036 -0.30517578125 +93037 -0.181365966796875 +93038 -0.36212158203125 +93039 -0.218109130859375 +93040 -0.39141845703125 +93041 -0.238037109375 +93042 -0.35528564453125 +93043 -0.217742919921875 +93044 -0.249969482421875 +93045 -0.15484619140625 +93046 -0.092864990234375 +93047 -0.0599365234375 +93048 0.08905029296875 +93049 0.05047607421875 +93050 0.2352294921875 +93051 0.13916015625 +93052 0.318817138671875 +93053 0.18963623046875 +93054 0.358642578125 +93055 0.21356201171875 +93056 0.347747802734375 +93057 0.2066650390625 +93058 0.28564453125 +93059 0.16864013671875 +93060 0.223175048828125 +93061 0.13079833984375 +93062 0.196746826171875 +93063 0.115478515625 +93064 0.179840087890625 +93065 0.1063232421875 +93066 0.155548095703125 +93067 0.09283447265625 +93068 0.151214599609375 +93069 0.091766357421875 +93070 0.156951904296875 +93071 0.096923828125 +93072 0.13177490234375 +93073 0.08294677734375 +93074 0.100799560546875 +93075 0.06524658203125 +93076 0.087127685546875 +93077 0.058013916015625 +93078 0.05487060546875 +93079 0.039093017578125 +93080 -0.009002685546875 +93081 0.0003662109375 +93082 -0.10400390625 +93083 -0.057861328125 +93084 -0.229400634765625 +93085 -0.135162353515625 +93086 -0.35552978515625 +93087 -0.2132568359375 +93088 -0.441925048828125 +93089 -0.26715087890625 +93090 -0.473846435546875 +93091 -0.287750244140625 +93092 -0.464813232421875 +93093 -0.283294677734375 +93094 -0.419097900390625 +93095 -0.25634765625 +93096 -0.334320068359375 +93097 -0.20538330078125 +93098 -0.227935791015625 +93099 -0.141082763671875 +93100 -0.12347412109375 +93101 -0.077880859375 +93102 -0.02764892578125 +93103 -0.01983642578125 +93104 0.077667236328125 +93105 0.04425048828125 +93106 0.2132568359375 +93107 0.127197265625 +93108 0.38885498046875 +93109 0.23504638671875 +93110 0.582794189453125 +93111 0.35443115234375 +93112 0.734039306640625 +93113 0.447784423828125 +93114 0.800140380859375 +93115 0.4888916015625 +93116 0.7783203125 +93117 0.476043701171875 +93118 0.6651611328125 +93119 0.4071044921875 +93120 0.45965576171875 +93121 0.281402587890625 +93122 0.199188232421875 +93123 0.1219482421875 +93124 -0.050689697265625 +93125 -0.030975341796875 +93126 -0.23297119140625 +93127 -0.14227294921875 +93128 -0.33013916015625 +93129 -0.20123291015625 +93130 -0.368408203125 +93131 -0.224029541015625 +93132 -0.378936767578125 +93133 -0.229888916015625 +93134 -0.376983642578125 +93135 -0.228271484375 +93136 -0.37969970703125 +93137 -0.229766845703125 +93138 -0.391510009765625 +93139 -0.237091064453125 +93140 -0.385345458984375 +93141 -0.23358154296875 +93142 -0.3419189453125 +93143 -0.20733642578125 +93144 -0.28289794921875 +93145 -0.171630859375 +93146 -0.251617431640625 +93147 -0.153106689453125 +93148 -0.266143798828125 +93149 -0.162841796875 +93150 -0.273345947265625 +93151 -0.168121337890625 +93152 -0.216796875 +93153 -0.13409423828125 +93154 -0.128265380859375 +93155 -0.080291748046875 +93156 -0.068145751953125 +93157 -0.04388427734375 +93158 -0.0430908203125 +93159 -0.028900146484375 +93160 -0.024444580078125 +93161 -0.0177001953125 +93162 0.020721435546875 +93163 0.009979248046875 +93164 0.124481201171875 +93165 0.07391357421875 +93166 0.25787353515625 +93167 0.15625 +93168 0.379119873046875 +93169 0.231201171875 +93170 0.47991943359375 +93171 0.293670654296875 +93172 0.5281982421875 +93173 0.3238525390625 +93174 0.511138916015625 +93175 0.313873291015625 +93176 0.456207275390625 +93177 0.280609130859375 +93178 0.407470703125 +93179 0.251190185546875 +93180 0.383758544921875 +93181 0.237152099609375 +93182 0.35687255859375 +93183 0.221099853515625 +93184 0.31182861328125 +93185 0.19427490234375 +93186 0.250885009765625 +93187 0.158355712890625 +93188 0.1654052734375 +93189 0.10736083984375 +93190 0.035247802734375 +93191 0.02777099609375 +93192 -0.142059326171875 +93193 -0.08245849609375 +93194 -0.33563232421875 +93195 -0.203704833984375 +93196 -0.5345458984375 +93197 -0.329193115234375 +93198 -0.72186279296875 +93199 -0.448211669921875 +93200 -0.836669921875 +93201 -0.52142333984375 +93202 -0.8326416015625 +93203 -0.51885986328125 +93204 -0.7296142578125 +93205 -0.453369140625 +93206 -0.582550048828125 +93207 -0.360443115234375 +93208 -0.440093994140625 +93209 -0.27142333984375 +93210 -0.324310302734375 +93211 -0.200439453125 +93212 -0.20147705078125 +93213 -0.125335693359375 +93214 -0.044647216796875 +93215 -0.02838134765625 +93216 0.103973388671875 +93217 0.063323974609375 +93218 0.202392578125 +93219 0.122833251953125 +93220 0.264495849609375 +93221 0.15936279296875 +93222 0.338897705078125 +93223 0.204620361328125 +93224 0.443817138671875 +93225 0.27056884765625 +93226 0.545074462890625 +93227 0.335113525390625 +93228 0.6173095703125 +93229 0.381866455078125 +93230 0.6524658203125 +93231 0.405609130859375 +93232 0.66339111328125 +93233 0.414581298828125 +93234 0.6561279296875 +93235 0.41253662109375 +93236 0.606781005859375 +93237 0.383819580078125 +93238 0.501190185546875 +93239 0.319061279296875 +93240 0.352783203125 +93241 0.22674560546875 +93242 0.176544189453125 +93243 0.11639404296875 +93244 -0.034820556640625 +93245 -0.01690673828125 +93246 -0.258209228515625 +93247 -0.15838623046875 +93248 -0.44244384765625 +93249 -0.275054931640625 +93250 -0.5753173828125 +93251 -0.359130859375 +93252 -0.65203857421875 +93253 -0.4075927734375 +93254 -0.641632080078125 +93255 -0.40045166015625 +93256 -0.562164306640625 +93257 -0.34942626953125 +93258 -0.458038330078125 +93259 -0.283233642578125 +93260 -0.350555419921875 +93261 -0.215545654296875 +93262 -0.260528564453125 +93263 -0.15972900390625 +93264 -0.192108154296875 +93265 -0.118316650390625 +93266 -0.141937255859375 +93267 -0.088958740234375 +93268 -0.1021728515625 +93269 -0.06640625 +93270 -0.062896728515625 +93271 -0.0440673828125 +93272 -0.011932373046875 +93273 -0.01385498046875 +93274 0.062835693359375 +93275 0.032196044921875 +93276 0.148712158203125 +93277 0.08599853515625 +93278 0.241729736328125 +93279 0.14501953125 +93280 0.34912109375 +93281 0.214019775390625 +93282 0.457305908203125 +93283 0.28424072265625 +93284 0.54388427734375 +93285 0.341094970703125 +93286 0.5728759765625 +93287 0.36126708984375 +93288 0.506591796875 +93289 0.3201904296875 +93290 0.351226806640625 +93291 0.221771240234375 +93292 0.146514892578125 +93293 0.091644287109375 +93294 -0.05523681640625 +93295 -0.03643798828125 +93296 -0.21624755859375 +93297 -0.138153076171875 +93298 -0.334930419921875 +93299 -0.21258544921875 +93300 -0.402984619140625 +93301 -0.2545166015625 +93302 -0.4412841796875 +93303 -0.277557373046875 +93304 -0.49578857421875 +93305 -0.31158447265625 +93306 -0.5601806640625 +93307 -0.352569580078125 +93308 -0.600738525390625 +93309 -0.378662109375 +93310 -0.584228515625 +93311 -0.36834716796875 +93312 -0.47930908203125 +93313 -0.301300048828125 +93314 -0.27935791015625 +93315 -0.17315673828125 +93316 -0.0089111328125 +93317 0.000244140625 +93318 0.268798828125 +93319 0.17803955078125 +93320 0.482818603515625 +93321 0.314422607421875 +93322 0.60369873046875 +93323 0.39044189453125 +93324 0.650421142578125 +93325 0.418487548828125 +93326 0.66400146484375 +93327 0.42529296875 +93328 0.6414794921875 +93329 0.409027099609375 +93330 0.572540283203125 +93331 0.36309814453125 +93332 0.498138427734375 +93333 0.3140869140625 +93334 0.439453125 +93335 0.2757568359375 +93336 0.375518798828125 +93337 0.234527587890625 +93338 0.274505615234375 +93339 0.16973876953125 +93340 0.1087646484375 +93341 0.06341552734375 +93342 -0.099395751953125 +93343 -0.070037841796875 +93344 -0.3182373046875 +93345 -0.210113525390625 +93346 -0.5489501953125 +93347 -0.35772705078125 +93348 -0.7738037109375 +93349 -0.50146484375 +93350 -0.86383056640625 +93351 -0.60711669921875 +93352 -0.870391845703125 +93353 -0.65325927734375 +93354 -0.86895751953125 +93355 -0.651458740234375 +93356 -0.861053466796875 +93357 -0.610321044921875 +93358 -0.765869140625 +93359 -0.5186767578125 +93360 -0.5301513671875 +93361 -0.369232177734375 +93362 -0.214691162109375 +93363 -0.1666259765625 +93364 0.137359619140625 +93365 0.061248779296875 +93366 0.474822998046875 +93367 0.281158447265625 +93368 0.76239013671875 +93369 0.47015380859375 +93370 0.867462158203125 +93371 0.610809326171875 +93372 0.870361328125 +93373 0.703460693359375 +93374 0.86480712890625 +93375 0.74072265625 +93376 0.831817626953125 +93377 0.726165771484375 +93378 0.677581787109375 +93379 0.6756591796875 +93380 0.495880126953125 +93381 0.593048095703125 +93382 0.30767822265625 +93383 0.490386962890625 +93384 0.116180419921875 +93385 0.36920166015625 +93386 -0.110748291015625 +93387 0.208953857421875 +93388 -0.381805419921875 +93389 0.005157470703125 +93390 -0.6572265625 +93391 -0.21441650390625 +93392 -0.857421875 +93393 -0.410980224609375 +93394 -0.870391845703125 +93395 -0.556732177734375 +93396 -0.870391845703125 +93397 -0.647064208984375 +93398 -0.86444091796875 +93399 -0.699493408203125 +93400 -0.85723876953125 +93401 -0.737213134765625 +93402 -0.790008544921875 +93403 -0.748382568359375 +93404 -0.62847900390625 +93405 -0.697906494140625 +93406 -0.3956298828125 +93407 -0.583770751953125 +93408 -0.126708984375 +93409 -0.4273681640625 +93410 0.150115966796875 +93411 -0.2464599609375 +93412 0.424041748046875 +93413 -0.0487060546875 +93414 0.670623779296875 +93415 0.14837646484375 +93416 0.854522705078125 +93417 0.319671630859375 +93418 0.866485595703125 +93419 0.453704833984375 +93420 0.86920166015625 +93421 0.54052734375 +93422 0.8653564453125 +93423 0.591888427734375 +93424 0.857147216796875 +93425 0.61651611328125 +93426 0.766845703125 +93427 0.612548828125 +93428 0.628509521484375 +93429 0.5833740234375 +93430 0.462127685546875 +93431 0.524658203125 +93432 0.297210693359375 +93433 0.45318603515625 +93434 0.14862060546875 +93435 0.377044677734375 +93436 -0.00537109375 +93437 0.281494140625 +93438 -0.15753173828125 +93439 0.171478271484375 +93440 -0.31304931640625 +93441 0.04425048828125 +93442 -0.48876953125 +93443 -0.10931396484375 +93444 -0.6416015625 +93445 -0.25750732421875 +93446 -0.751373291015625 +93447 -0.384246826171875 +93448 -0.84619140625 +93449 -0.505889892578125 +93450 -0.861297607421875 +93451 -0.6129150390625 +93452 -0.863250732421875 +93453 -0.683197021484375 +93454 -0.856597900390625 +93455 -0.69549560546875 +93456 -0.7498779296875 +93457 -0.658172607421875 +93458 -0.624542236328125 +93459 -0.61053466796875 +93460 -0.47808837890625 +93461 -0.5374755859375 +93462 -0.253387451171875 +93463 -0.39898681640625 +93464 0.003692626953125 +93465 -0.225799560546875 +93466 0.2257080078125 +93467 -0.064056396484375 +93468 0.427154541015625 +93469 0.09515380859375 +93470 0.643218994140625 +93471 0.27423095703125 +93472 0.855926513671875 +93473 0.467010498046875 +93474 0.870361328125 +93475 0.6343994140625 +93476 0.870361328125 +93477 0.742919921875 +93478 0.862762451171875 +93479 0.797637939453125 +93480 0.79669189453125 +93481 0.796661376953125 +93482 0.595794677734375 +93483 0.733612060546875 +93484 0.362152099609375 +93485 0.6282958984375 +93486 0.1270751953125 +93487 0.499664306640625 +93488 -0.086944580078125 +93489 0.361907958984375 +93490 -0.2784423828125 +93491 0.216278076171875 +93492 -0.484832763671875 +93493 0.038848876953125 +93494 -0.729583740234375 +93495 -0.183685302734375 +93496 -0.86688232421875 +93497 -0.41717529296875 +93498 -0.870391845703125 +93499 -0.618804931640625 +93500 -0.86859130859375 +93501 -0.785430908203125 +93502 -0.86279296875 +93503 -0.8612060546875 +93504 -0.817962646484375 +93505 -0.868804931640625 +93506 -0.6116943359375 +93507 -0.866455078125 +93508 -0.3128662109375 +93509 -0.84600830078125 +93510 0.039398193359375 +93511 -0.65478515625 +93512 0.422821044921875 +93513 -0.403778076171875 +93514 0.805145263671875 +93515 -0.11553955078125 +93516 0.870361328125 +93517 0.1636962890625 +93518 0.870361328125 +93519 0.395294189453125 +93520 0.860015869140625 +93521 0.57135009765625 +93522 0.727935791015625 +93523 0.68670654296875 +93524 0.48114013671875 +93525 0.737579345703125 +93526 0.2059326171875 +93527 0.740478515625 +93528 -0.06103515625 +93529 0.710784912109375 +93530 -0.29913330078125 +93531 0.65533447265625 +93532 -0.516204833984375 +93533 0.56427001953125 +93534 -0.7252197265625 +93535 0.42718505859375 +93536 -0.85980224609375 +93537 0.26104736328125 +93538 -0.870391845703125 +93539 0.08929443359375 +93540 -0.870391845703125 +93541 -0.06781005859375 +93542 -0.858062744140625 +93543 -0.176971435546875 +93544 -0.673004150390625 +93545 -0.23516845703125 +93546 -0.42694091796875 +93547 -0.27789306640625 +93548 -0.2100830078125 +93549 -0.33514404296875 +93550 -0.0362548828125 +93551 -0.405303955078125 +93552 0.10943603515625 +93553 -0.468414306640625 +93554 0.23516845703125 +93555 -0.51080322265625 +93556 0.373687744140625 +93557 -0.504241943359375 +93558 0.517791748046875 +93559 -0.45001220703125 +93560 0.602783203125 +93561 -0.390960693359375 +93562 0.635711669921875 +93563 -0.32366943359375 +93564 0.655181884765625 +93565 -0.2255859375 +93566 0.65948486328125 +93567 -0.103668212890625 +93568 0.651275634765625 +93569 0.036376953125 +93570 0.61846923828125 +93571 0.177642822265625 +93572 0.53753662109375 +93573 0.29473876953125 +93574 0.404144287109375 +93575 0.375091552734375 +93576 0.22186279296875 +93577 0.41180419921875 +93578 0.003997802734375 +93579 0.405487060546875 +93580 -0.22100830078125 +93581 0.368255615234375 +93582 -0.42449951171875 +93583 0.314056396484375 +93584 -0.579833984375 +93585 0.25732421875 +93586 -0.641876220703125 +93587 0.227081298828125 +93588 -0.6177978515625 +93589 0.2188720703125 +93590 -0.575531005859375 +93591 0.188873291015625 +93592 -0.526336669921875 +93593 0.13360595703125 +93594 -0.42645263671875 +93595 0.088531494140625 +93596 -0.2581787109375 +93597 0.07257080078125 +93598 -0.068695068359375 +93599 0.061248779296875 +93600 0.09222412109375 +93601 0.028656005859375 +93602 0.232147216796875 +93603 -0.012237548828125 +93604 0.3509521484375 +93605 -0.05426025390625 +93606 0.410064697265625 +93607 -0.117340087890625 +93608 0.372955322265625 +93609 -0.22125244140625 +93610 0.2554931640625 +93611 -0.35162353515625 +93612 0.10711669921875 +93613 -0.472900390625 +93614 -0.052886962890625 +93615 -0.571746826171875 +93616 -0.186279296875 +93617 -0.62353515625 +93618 -0.23291015625 +93619 -0.590362548828125 +93620 -0.209442138671875 +93621 -0.48785400390625 +93622 -0.174163818359375 +93623 -0.3609619140625 +93624 -0.126739501953125 +93625 -0.215545654296875 +93626 -0.048126220703125 +93627 -0.04510498046875 +93628 0.0426025390625 +93629 0.130889892578125 +93630 0.10748291015625 +93631 0.280487060546875 +93632 0.1409912109375 +93633 0.3944091796875 +93634 0.19708251953125 +93635 0.5047607421875 +93636 0.273651123046875 +93637 0.60675048828125 +93638 0.31768798828125 +93639 0.662261962890625 +93640 0.341094970703125 +93641 0.678680419921875 +93642 0.368011474609375 +93643 0.673126220703125 +93644 0.37249755859375 +93645 0.62994384765625 +93646 0.30072021484375 +93647 0.51568603515625 +93648 0.1517333984375 +93649 0.333831787109375 +93650 -0.01470947265625 +93651 0.12982177734375 +93652 -0.1883544921875 +93653 -0.0841064453125 +93654 -0.372711181640625 +93655 -0.304962158203125 +93656 -0.51397705078125 +93657 -0.490966796875 +93658 -0.57177734375 +93659 -0.609893798828125 +93660 -0.53948974609375 +93661 -0.6531982421875 +93662 -0.43511962890625 +93663 -0.6300048828125 +93664 -0.2962646484375 +93665 -0.56378173828125 +93666 -0.161102294921875 +93667 -0.4794921875 +93668 -0.0435791015625 +93669 -0.38677978515625 +93670 0.060394287109375 +93671 -0.2841796875 +93672 0.13665771484375 +93673 -0.18359375 +93674 0.170135498046875 +93675 -0.098388671875 +93676 0.16552734375 +93677 -0.0291748046875 +93678 0.15728759765625 +93679 0.043182373046875 +93680 0.150787353515625 +93681 0.11798095703125 +93682 0.12200927734375 +93683 0.17449951171875 +93684 0.080108642578125 +93685 0.214935302734375 +93686 0.05126953125 +93687 0.253509521484375 +93688 0.062896728515625 +93689 0.3060302734375 +93690 0.09271240234375 +93691 0.35528564453125 +93692 0.092987060546875 +93693 0.367706298828125 +93694 0.07855224609375 +93695 0.353179931640625 +93696 0.06427001953125 +93697 0.322418212890625 +93698 0.0347900390625 +93699 0.2666015625 +93700 -0.01171875 +93701 0.18695068359375 +93702 -0.056060791015625 +93703 0.099700927734375 +93704 -0.055511474609375 +93705 0.0379638671875 +93706 -0.010467529296875 +93707 0.004974365234375 +93708 0.02508544921875 +93709 -0.033477783203125 +93710 0.025665283203125 +93711 -0.09185791015625 +93712 0.017333984375 +93713 -0.148834228515625 +93714 0.00189208984375 +93715 -0.200592041015625 +93716 -0.03173828125 +93717 -0.252960205078125 +93718 -0.071502685546875 +93719 -0.296295166015625 +93720 -0.13543701171875 +93721 -0.34271240234375 +93722 -0.219970703125 +93723 -0.390045166015625 +93724 -0.300506591796875 +93725 -0.42205810546875 +93726 -0.376312255859375 +93727 -0.43994140625 +93728 -0.416107177734375 +93729 -0.423980712890625 +93730 -0.371124267578125 +93731 -0.342681884765625 +93732 -0.242279052734375 +93733 -0.199554443359375 +93734 -0.069732666015625 +93735 -0.025726318359375 +93736 0.125640869140625 +93737 0.161285400390625 +93738 0.31268310546875 +93739 0.337005615234375 +93740 0.45501708984375 +93741 0.47369384765625 +93742 0.554779052734375 +93743 0.571044921875 +93744 0.61065673828125 +93745 0.626922607421875 +93746 0.610931396484375 +93747 0.632537841796875 +93748 0.531463623046875 +93749 0.571044921875 +93750 0.3883056640625 +93751 0.45428466796875 +93752 0.23468017578125 +93753 0.320709228515625 +93754 0.095245361328125 +93755 0.189300537109375 +93756 -0.00396728515625 +93757 0.080322265625 +93758 -0.04852294921875 +93759 0.00616455078125 +93760 -0.055145263671875 +93761 -0.042388916015625 +93762 -0.0758056640625 +93763 -0.09930419921875 +93764 -0.138702392578125 +93765 -0.182037353515625 +93766 -0.209197998046875 +93767 -0.26434326171875 +93768 -0.289031982421875 +93769 -0.345794677734375 +93770 -0.37884521484375 +93771 -0.4256591796875 +93772 -0.456329345703125 +93773 -0.48760986328125 +93774 -0.51641845703125 +93775 -0.527984619140625 +93776 -0.519287109375 +93777 -0.519256591796875 +93778 -0.458251953125 +93779 -0.45758056640625 +93780 -0.384796142578125 +93781 -0.38031005859375 +93782 -0.323699951171875 +93783 -0.306365966796875 +93784 -0.269287109375 +93785 -0.233642578125 +93786 -0.1951904296875 +93787 -0.14569091796875 +93788 -0.100006103515625 +93789 -0.04351806640625 +93790 -0.01055908203125 +93791 0.052154541015625 +93792 0.1033935546875 +93793 0.1607666015625 +93794 0.24908447265625 +93795 0.28594970703125 +93796 0.373199462890625 +93797 0.3892822265625 +93798 0.45806884765625 +93799 0.45770263671875 +93800 0.511474609375 +93801 0.496337890625 +93802 0.565399169921875 +93803 0.527740478515625 +93804 0.61138916015625 +93805 0.546600341796875 +93806 0.5897216796875 +93807 0.51202392578125 +93808 0.4906005859375 +93809 0.41839599609375 +93810 0.33148193359375 +93811 0.279388427734375 +93812 0.147796630859375 +93813 0.121368408203125 +93814 -0.01873779296875 +93815 -0.0247802734375 +93816 -0.140289306640625 +93817 -0.137939453125 +93818 -0.191986083984375 +93819 -0.19921875 +93820 -0.184295654296875 +93821 -0.214691162109375 +93822 -0.161834716796875 +93823 -0.21453857421875 +93824 -0.166595458984375 +93825 -0.227447509765625 +93826 -0.19390869140625 +93827 -0.24981689453125 +93828 -0.22442626953125 +93829 -0.268096923828125 +93830 -0.279754638671875 +93831 -0.29779052734375 +93832 -0.3389892578125 +93833 -0.32489013671875 +93834 -0.3543701171875 +93835 -0.31695556640625 +93836 -0.348175048828125 +93837 -0.290679931640625 +93838 -0.32598876953125 +93839 -0.25128173828125 +93840 -0.2581787109375 +93841 -0.17938232421875 +93842 -0.139801025390625 +93843 -0.072845458984375 +93844 0.014617919921875 +93845 0.056915283203125 +93846 0.144378662109375 +93847 0.166229248046875 +93848 0.221038818359375 +93849 0.23431396484375 +93850 0.27069091796875 +93851 0.27874755859375 +93852 0.294036865234375 +93853 0.29962158203125 +93854 0.311767578125 +93855 0.31134033203125 +93856 0.339141845703125 +93857 0.324798583984375 +93858 0.360260009765625 +93859 0.329437255859375 +93860 0.360504150390625 +93861 0.315704345703125 +93862 0.308380126953125 +93863 0.261962890625 +93864 0.18170166015625 +93865 0.153350830078125 +93866 0.0047607421875 +93867 0.00823974609375 +93868 -0.17559814453125 +93869 -0.138946533203125 +93870 -0.3143310546875 +93871 -0.25518798828125 +93872 -0.36785888671875 +93873 -0.308563232421875 +93874 -0.36248779296875 +93875 -0.317047119140625 +93876 -0.343536376953125 +93877 -0.31231689453125 +93878 -0.3018798828125 +93879 -0.287506103515625 +93880 -0.231414794921875 +93881 -0.23809814453125 +93882 -0.117645263671875 +93883 -0.153839111328125 +93884 0.007049560546875 +93885 -0.058074951171875 +93886 0.087982177734375 +93887 0.009735107421875 +93888 0.13946533203125 +93889 0.059173583984375 +93890 0.17425537109375 +93891 0.09857177734375 +93892 0.188201904296875 +93893 0.12408447265625 +93894 0.171234130859375 +93895 0.127685546875 +93896 0.118438720703125 +93897 0.105010986328125 +93898 0.05706787109375 +93899 0.074676513671875 +93900 -0.010711669921875 +93901 0.03753662109375 +93902 -0.0914306640625 +93903 -0.0115966796875 +93904 -0.162322998046875 +93905 -0.056884765625 +93906 -0.194549560546875 +93907 -0.0780029296875 +93908 -0.1492919921875 +93909 -0.04730224609375 +93910 -0.02166748046875 +93911 0.038848876953125 +93912 0.124053955078125 +93913 0.13507080078125 +93914 0.211151123046875 +93915 0.18719482421875 +93916 0.240447998046875 +93917 0.196441650390625 +93918 0.242218017578125 +93919 0.18505859375 +93920 0.2257080078125 +93921 0.160369873046875 +93922 0.194366455078125 +93923 0.125518798828125 +93924 0.115509033203125 +93925 0.057891845703125 +93926 0.0128173828125 +93927 -0.024993896484375 +93928 -0.053802490234375 +93929 -0.080047607421875 +93930 -0.110626220703125 +93931 -0.1256103515625 +93932 -0.199493408203125 +93933 -0.1912841796875 +93934 -0.29437255859375 +93935 -0.258453369140625 +93936 -0.33221435546875 +93937 -0.2823486328125 +93938 -0.27972412109375 +93939 -0.239532470703125 +93940 -0.185333251953125 +93941 -0.164825439453125 +93942 -0.128204345703125 +93943 -0.115081787109375 +93944 -0.115692138671875 +93945 -0.096038818359375 +93946 -0.116455078125 +93947 -0.085968017578125 +93948 -0.105926513671875 +93949 -0.0679931640625 +93950 -0.053955078125 +93951 -0.021209716796875 +93952 0.048797607421875 +93953 0.06072998046875 +93954 0.157318115234375 +93955 0.145050048828125 +93956 0.212005615234375 +93957 0.1878662109375 +93958 0.218475341796875 +93959 0.193328857421875 +93960 0.23724365234375 +93961 0.206451416015625 +93962 0.30535888671875 +93963 0.254913330078125 +93964 0.38128662109375 +93965 0.30792236328125 +93966 0.404449462890625 +93967 0.320587158203125 +93968 0.3944091796875 +93969 0.3077392578125 +93970 0.3885498046875 +93971 0.297454833984375 +93972 0.362640380859375 +93973 0.272064208984375 +93974 0.27362060546875 +93975 0.1998291015625 +93976 0.11712646484375 +93977 0.07781982421875 +93978 -0.054901123046875 +93979 -0.0550537109375 +93980 -0.19085693359375 +93981 -0.160125732421875 +93982 -0.28570556640625 +93983 -0.2335205078125 +93984 -0.339263916015625 +93985 -0.274993896484375 +93986 -0.3775634765625 +93987 -0.3038330078125 +93988 -0.445709228515625 +93989 -0.353607177734375 +93990 -0.535064697265625 +93991 -0.417999267578125 +93992 -0.629058837890625 +93993 -0.48480224609375 +93994 -0.697601318359375 +93995 -0.531829833984375 +93996 -0.70391845703125 +93997 -0.531951904296875 +93998 -0.6424560546875 +93999 -0.4813232421875 +94000 -0.491241455078125 +94001 -0.3638916015625 +94002 -0.265716552734375 +94003 -0.19140625 +94004 -0.023712158203125 +94005 -0.007110595703125 +94006 0.201751708984375 +94007 0.1641845703125 +94008 0.375823974609375 +94009 0.296356201171875 +94010 0.485076904296875 +94011 0.37933349609375 +94012 0.56884765625 +94013 0.442291259765625 +94014 0.634765625 +94015 0.49090576171875 +94016 0.63763427734375 +94017 0.491607666015625 +94018 0.5660400390625 +94019 0.436004638671875 +94020 0.4720458984375 +94021 0.36297607421875 +94022 0.40692138671875 +94023 0.31085205078125 +94024 0.3778076171875 +94025 0.285186767578125 +94026 0.376953125 +94027 0.280426025390625 +94028 0.371978759765625 +94029 0.272705078125 +94030 0.313140869140625 +94031 0.225250244140625 +94032 0.184417724609375 +94033 0.1263427734375 +94034 0.011199951171875 +94035 -0.004974365234375 +94036 -0.171051025390625 +94037 -0.1422119140625 +94038 -0.33740234375 +94039 -0.266754150390625 +94040 -0.47198486328125 +94041 -0.36676025390625 +94042 -0.560394287109375 +94043 -0.431549072265625 +94044 -0.58056640625 +94045 -0.444793701171875 +94046 -0.54754638671875 +94047 -0.417816162109375 +94048 -0.508575439453125 +94049 -0.385894775390625 +94050 -0.459503173828125 +94051 -0.34613037109375 +94052 -0.394378662109375 +94053 -0.294281005859375 +94054 -0.35260009765625 +94055 -0.259857177734375 +94056 -0.31170654296875 +94057 -0.226287841796875 +94058 -0.197418212890625 +94059 -0.13848876953125 +94060 -0.007965087890625 +94061 0.004669189453125 +94062 0.207489013671875 +94063 0.16650390625 +94064 0.409210205078125 +94065 0.3173828125 +94066 0.57208251953125 +94067 0.4385986328125 +94068 0.66595458984375 +94069 0.507781982421875 +94070 0.65875244140625 +94071 0.5010986328125 +94072 0.56744384765625 +94073 0.4312744140625 +94074 0.431396484375 +94075 0.327728271484375 +94076 0.29443359375 +94077 0.22320556640625 +94078 0.182464599609375 +94079 0.137115478515625 +94080 0.06365966796875 +94081 0.045928955078125 +94082 -0.075958251953125 +94083 -0.060577392578125 +94084 -0.189422607421875 +94085 -0.147308349609375 +94086 -0.271942138671875 +94087 -0.2105712890625 +94088 -0.342529296875 +94089 -0.264434814453125 +94090 -0.364166259765625 +94091 -0.281341552734375 +94092 -0.327239990234375 +94093 -0.25408935546875 +94094 -0.2769775390625 +94095 -0.21630859375 +94096 -0.253692626953125 +94097 -0.19805908203125 +94098 -0.24365234375 +94099 -0.189178466796875 +94100 -0.1983642578125 +94101 -0.1536865234375 +94102 -0.116241455078125 +94103 -0.09051513671875 +94104 -0.036834716796875 +94105 -0.0291748046875 +94106 0.034881591796875 +94107 0.026458740234375 +94108 0.09124755859375 +94109 0.070587158203125 +94110 0.10888671875 +94111 0.085723876953125 +94112 0.125518798828125 +94113 0.09979248046875 +94114 0.15771484375 +94115 0.125030517578125 +94116 0.17828369140625 +94117 0.141143798828125 +94118 0.17108154296875 +94119 0.1361083984375 +94120 0.129974365234375 +94121 0.105377197265625 +94122 0.082427978515625 +94123 0.069366455078125 +94124 0.027679443359375 +94125 0.027587890625 +94126 -0.065643310546875 +94127 -0.043243408203125 +94128 -0.15936279296875 +94129 -0.114593505859375 +94130 -0.21307373046875 +94131 -0.15631103515625 +94132 -0.234649658203125 +94133 -0.1741943359375 +94134 -0.2001953125 +94135 -0.150360107421875 +94136 -0.119171142578125 +94137 -0.09173583984375 +94138 -0.024749755859375 +94139 -0.02294921875 +94140 0.085784912109375 +94141 0.058135986328125 +94142 0.178131103515625 +94143 0.12603759765625 +94144 0.215576171875 +94145 0.153472900390625 +94146 0.211456298828125 +94147 0.150360107421875 +94148 0.17523193359375 +94149 0.123748779296875 +94150 0.128753662109375 +94151 0.08984375 +94152 0.1019287109375 +94153 0.07086181640625 +94154 0.0743408203125 +94155 0.051605224609375 +94156 0.04327392578125 +94157 0.0299072265625 +94158 0.038177490234375 +94159 0.027618408203125 +94160 0.076263427734375 +94161 0.057464599609375 +94162 0.14105224609375 +94163 0.107086181640625 +94164 0.186431884765625 +94165 0.142120361328125 +94166 0.188812255859375 +94167 0.144927978515625 +94168 0.1390380859375 +94169 0.108642578125 +94170 0.041778564453125 +94171 0.0367431640625 +94172 -0.079437255859375 +94173 -0.05328369140625 +94174 -0.219390869140625 +94175 -0.157562255859375 +94176 -0.367828369140625 +94177 -0.2684326171875 +94178 -0.494873046875 +94179 -0.3636474609375 +94180 -0.556243896484375 +94181 -0.41021728515625 +94182 -0.508697509765625 +94183 -0.37591552734375 +94184 -0.3756103515625 +94185 -0.278045654296875 +94186 -0.218902587890625 +94187 -0.162628173828125 +94188 -0.063751220703125 +94189 -0.04833984375 +94190 0.091552734375 +94191 0.06610107421875 +94192 0.23602294921875 +94193 0.172607421875 +94194 0.342987060546875 +94195 0.25140380859375 +94196 0.39520263671875 +94197 0.289703369140625 +94198 0.389373779296875 +94199 0.28509521484375 +94200 0.324249267578125 +94201 0.23663330078125 +94202 0.224090576171875 +94203 0.162353515625 +94204 0.124267578125 +94205 0.088531494140625 +94206 0.037078857421875 +94207 0.0242919921875 +94208 -0.010101318359375 +94209 -0.00958251953125 +94210 -0.019439697265625 +94211 -0.01495361328125 +94212 -0.022796630859375 +94213 -0.0162353515625 +94214 -0.001556396484375 +94215 0.00115966796875 +94216 0.056304931640625 +94217 0.046661376953125 +94218 0.106719970703125 +94219 0.086181640625 +94220 0.096893310546875 +94221 0.078826904296875 +94222 0.042694091796875 +94223 0.036956787109375 +94224 -0.018035888671875 +94225 -0.01007080078125 +94226 -0.07586669921875 +94227 -0.054931640625 +94228 -0.11944580078125 +94229 -0.088836669921875 +94230 -0.15972900390625 +94231 -0.12030029296875 +94232 -0.202606201171875 +94233 -0.15386962890625 +94234 -0.24859619140625 +94235 -0.18994140625 +94236 -0.30517578125 +94237 -0.234283447265625 +94238 -0.36212158203125 +94239 -0.27899169921875 +94240 -0.39141845703125 +94241 -0.302337646484375 +94242 -0.35528564453125 +94243 -0.274932861328125 +94244 -0.249969482421875 +94245 -0.19384765625 +94246 -0.092864990234375 +94247 -0.07257080078125 +94248 0.08905029296875 +94249 0.0679931640625 +94250 0.2352294921875 +94251 0.180877685546875 +94252 0.318817138671875 +94253 0.24530029296875 +94254 0.358642578125 +94255 0.27587890625 +94256 0.347747802734375 +94257 0.267242431640625 +94258 0.28564453125 +94259 0.219024658203125 +94260 0.223175048828125 +94261 0.170684814453125 +94262 0.196746826171875 +94263 0.150421142578125 +94264 0.179840087890625 +94265 0.137664794921875 +94266 0.155548095703125 +94267 0.119293212890625 +94268 0.151214599609375 +94269 0.116485595703125 +94270 0.156951904296875 +94271 0.121551513671875 +94272 0.13177490234375 +94273 0.10260009765625 +94274 0.100799560546875 +94275 0.0791015625 +94276 0.087127685546875 +94277 0.068939208984375 +94278 0.05487060546875 +94279 0.044281005859375 +94280 -0.009002685546875 +94281 -0.0050048828125 +94282 -0.10400390625 +94283 -0.07855224609375 +94284 -0.229400634765625 +94285 -0.175811767578125 +94286 -0.35552978515625 +94287 -0.27374267578125 +94288 -0.441925048828125 +94289 -0.3409423828125 +94290 -0.473846435546875 +94291 -0.365997314453125 +94292 -0.464813232421875 +94293 -0.359344482421875 +94294 -0.419097900390625 +94295 -0.32427978515625 +94296 -0.334320068359375 +94297 -0.2589111328125 +94298 -0.227935791015625 +94299 -0.1767578125 +94300 -0.12347412109375 +94301 -0.0960693359375 +94302 -0.02764892578125 +94303 -0.022064208984375 +94304 0.077667236328125 +94305 0.059356689453125 +94306 0.2132568359375 +94307 0.164337158203125 +94308 0.38885498046875 +94309 0.3004150390625 +94310 0.582794189453125 +94311 0.4508056640625 +94312 0.734039306640625 +94313 0.568115234375 +94314 0.800140380859375 +94315 0.61944580078125 +94316 0.7783203125 +94317 0.60260009765625 +94318 0.6651611328125 +94319 0.51495361328125 +94320 0.45965576171875 +94321 0.355712890625 +94322 0.199188232421875 +94323 0.15386962890625 +94324 -0.050689697265625 +94325 -0.039703369140625 +94326 -0.23297119140625 +94327 -0.180816650390625 +94328 -0.33013916015625 +94329 -0.255889892578125 +94330 -0.368408203125 +94331 -0.2852783203125 +94332 -0.378936767578125 +94333 -0.293182373046875 +94334 -0.376983642578125 +94335 -0.291473388671875 +94336 -0.37969970703125 +94337 -0.29345703125 +94338 -0.391510009765625 +94339 -0.30255126953125 +94340 -0.385345458984375 +94341 -0.297760009765625 +94342 -0.3419189453125 +94343 -0.264129638671875 +94344 -0.28289794921875 +94345 -0.218475341796875 +94346 -0.251617431640625 +94347 -0.19439697265625 +94348 -0.266143798828125 +94349 -0.205902099609375 +94350 -0.273345947265625 +94351 -0.211761474609375 +94352 -0.216796875 +94353 -0.16815185546875 +94354 -0.128265380859375 +94355 -0.099700927734375 +94356 -0.068145751953125 +94357 -0.053253173828125 +94358 -0.0430908203125 +94359 -0.033966064453125 +94360 -0.024444580078125 +94361 -0.019622802734375 +94362 0.020721435546875 +94363 0.015350341796875 +94364 0.124481201171875 +94365 0.095855712890625 +94366 0.25787353515625 +94367 0.199371337890625 +94368 0.379119873046875 +94369 0.293487548828125 +94370 0.47991943359375 +94371 0.371795654296875 +94372 0.5281982421875 +94373 0.40936279296875 +94374 0.511138916015625 +94375 0.396240234375 +94376 0.456207275390625 +94377 0.353729248046875 +94378 0.407470703125 +94379 0.3160400390625 +94380 0.383758544921875 +94381 0.29779052734375 +94382 0.35687255859375 +94383 0.277069091796875 +94384 0.31182861328125 +94385 0.24224853515625 +94386 0.250885009765625 +94387 0.195037841796875 +94388 0.1654052734375 +94389 0.128753662109375 +94390 0.035247802734375 +94391 0.02777099609375 +94392 -0.142059326171875 +94393 -0.109832763671875 +94394 -0.33563232421875 +94395 -0.26007080078125 +94396 -0.5345458984375 +94397 -0.414459228515625 +94398 -0.72186279296875 +94399 -0.559814453125 +94400 -0.836669921875 +94401 -0.64892578125 +94402 -0.8326416015625 +94403 -0.64581298828125 +94404 -0.7296142578125 +94405 -0.56591796875 +94406 -0.582550048828125 +94407 -0.451873779296875 +94408 -0.440093994140625 +94409 -0.341400146484375 +94410 -0.324310302734375 +94411 -0.251617431640625 +94412 -0.20147705078125 +94413 -0.1563720703125 +94414 -0.044647216796875 +94415 -0.03472900390625 +94416 0.103973388671875 +94417 0.08056640625 +94418 0.202392578125 +94419 0.15692138671875 +94420 0.264495849609375 +94421 0.205078125 +94422 0.338897705078125 +94423 0.2628173828125 +94424 0.443817138671875 +94425 0.34423828125 +94426 0.545074462890625 +94427 0.422821044921875 +94428 0.6173095703125 +94429 0.478851318359375 +94430 0.6524658203125 +94431 0.506103515625 +94432 0.66339111328125 +94433 0.514556884765625 +94434 0.6561279296875 +94435 0.5089111328125 +94436 0.606781005859375 +94437 0.470611572265625 +94438 0.501190185546875 +94439 0.388671875 +94440 0.352783203125 +94441 0.273529052734375 +94442 0.176544189453125 +94443 0.13677978515625 +94444 -0.034820556640625 +94445 -0.027191162109375 +94446 -0.258209228515625 +94447 -0.200439453125 +94448 -0.44244384765625 +94449 -0.343292236328125 +94450 -0.5753173828125 +94451 -0.446258544921875 +94452 -0.65203857421875 +94453 -0.505645751953125 +94454 -0.641632080078125 +94455 -0.4974365234375 +94456 -0.562164306640625 +94457 -0.4356689453125 +94458 -0.458038330078125 +94459 -0.35479736328125 +94460 -0.350555419921875 +94461 -0.271331787109375 +94462 -0.260528564453125 +94463 -0.201446533203125 +94464 -0.192108154296875 +94465 -0.1485595703125 +94466 -0.141937255859375 +94467 -0.110107421875 +94468 -0.1021728515625 +94469 -0.0797119140625 +94470 -0.062896728515625 +94471 -0.049530029296875 +94472 -0.011932373046875 +94473 -0.00982666015625 +94474 0.062835693359375 +94475 0.049102783203125 +94476 0.148712158203125 +94477 0.11700439453125 +94478 0.241729736328125 +94479 0.190704345703125 +94480 0.34912109375 +94481 0.276123046875 +94482 0.457305908203125 +94483 0.362396240234375 +94484 0.54388427734375 +94485 0.431488037109375 +94486 0.5728759765625 +94487 0.45440673828125 +94488 0.506591796875 +94489 0.400726318359375 +94490 0.351226806640625 +94491 0.275482177734375 +94492 0.146514892578125 +94493 0.110748291015625 +94494 -0.05523681640625 +94495 -0.051239013671875 +94496 -0.21624755859375 +94497 -0.17999267578125 +94498 -0.334930419921875 +94499 -0.2742919921875 +94500 -0.402984619140625 +94501 -0.3275146484375 +94502 -0.4412841796875 +94503 -0.35662841796875 +94504 -0.49578857421875 +94505 -0.39886474609375 +94506 -0.5601806640625 +94507 -0.449188232421875 +94508 -0.600738525390625 +94509 -0.480499267578125 +94510 -0.584228515625 +94511 -0.46600341796875 +94512 -0.47930908203125 +94513 -0.380401611328125 +94514 -0.27935791015625 +94515 -0.218414306640625 +94516 -0.0089111328125 +94517 9.1552734375e-05 +94518 0.268798828125 +94519 0.22406005859375 +94520 0.482818603515625 +94521 0.396209716796875 +94522 0.60369873046875 +94523 0.4927978515625 +94524 0.650421142578125 +94525 0.529205322265625 +94526 0.66400146484375 +94527 0.5386962890625 +94528 0.6414794921875 +94529 0.5189208984375 +94530 0.572540283203125 +94531 0.461669921875 +94532 0.498138427734375 +94533 0.40008544921875 +94534 0.439453125 +94535 0.351348876953125 +94536 0.375518798828125 +94537 0.298614501953125 +94538 0.274505615234375 +94539 0.2161865234375 +94540 0.1087646484375 +94541 0.081787109375 +94542 -0.099395751953125 +94543 -0.0865478515625 +94544 -0.3182373046875 +94545 -0.26312255859375 +94546 -0.5489501953125 +94547 -0.448974609375 +94548 -0.7738037109375 +94549 -0.62982177734375 +94550 -0.86383056640625 +94551 -0.762908935546875 +94552 -0.870391845703125 +94553 -0.8214111328125 +94554 -0.86895751953125 +94555 -0.819732666015625 +94556 -0.861053466796875 +94557 -0.7685546875 +94558 -0.765869140625 +94559 -0.65399169921875 +94560 -0.5301513671875 +94561 -0.46697998046875 +94562 -0.214691162109375 +94563 -0.213348388671875 +94564 0.137359619140625 +94565 0.07208251953125 +94566 0.474822998046875 +94567 0.3477783203125 +94568 0.76239013671875 +94569 0.584991455078125 +94570 0.867462158203125 +94571 0.761932373046875 +94572 0.870361328125 +94573 0.857147216796875 +94574 0.86480712890625 +94575 0.86236572265625 +94576 0.831817626953125 +94577 0.860504150390625 +94578 0.677581787109375 +94579 0.847625732421875 +94580 0.495880126953125 +94581 0.745147705078125 +94582 0.30767822265625 +94583 0.61737060546875 +94584 0.116180419921875 +94585 0.466156005859375 +94586 -0.110748291015625 +94587 0.26593017578125 +94588 -0.381805419921875 +94589 0.011138916015625 +94590 -0.6572265625 +94591 -0.263580322265625 +94592 -0.857421875 +94593 -0.509765625 +94594 -0.870391845703125 +94595 -0.692718505859375 +94596 -0.870391845703125 +94597 -0.806640625 +94598 -0.86444091796875 +94599 -0.8565673828125 +94600 -0.85723876953125 +94601 -0.86181640625 +94602 -0.790008544921875 +94603 -0.863433837890625 +94604 -0.62847900390625 +94605 -0.856658935546875 +94606 -0.3956298828125 +94607 -0.732574462890625 +94608 -0.126708984375 +94609 -0.537872314453125 +94610 0.150115966796875 +94611 -0.312347412109375 +94612 0.424041748046875 +94613 -0.0655517578125 +94614 0.670623779296875 +94615 0.1806640625 +94616 0.854522705078125 +94617 0.394927978515625 +94618 0.866485595703125 +94619 0.562896728515625 +94620 0.86920166015625 +94621 0.672088623046875 +94622 0.8653564453125 +94623 0.737152099609375 +94624 0.857147216796875 +94625 0.7689208984375 +94626 0.766845703125 +94627 0.7650146484375 +94628 0.628509521484375 +94629 0.729583740234375 +94630 0.462127685546875 +94631 0.657196044921875 +94632 0.297210693359375 +94633 0.5687255859375 +94634 0.14862060546875 +94635 0.474212646484375 +94636 -0.00537109375 +94637 0.35528564453125 +94638 -0.15753173828125 +94639 0.218048095703125 +94640 -0.31304931640625 +94641 0.059661865234375 +94642 -0.48876953125 +94643 -0.13116455078125 +94644 -0.6416015625 +94645 -0.316436767578125 +94646 -0.751373291015625 +94647 -0.47613525390625 +94648 -0.84619140625 +94649 -0.62884521484375 +94650 -0.861297607421875 +94651 -0.76263427734375 +94652 -0.863250732421875 +94653 -0.850677490234375 +94654 -0.856597900390625 +94655 -0.855926513671875 +94656 -0.7498779296875 +94657 -0.8228759765625 +94658 -0.624542236328125 +94659 -0.76361083984375 +94660 -0.47808837890625 +94661 -0.671966552734375 +94662 -0.253387451171875 +94663 -0.500732421875 +94664 0.003692626953125 +94665 -0.286865234375 +94666 0.2257080078125 +94667 -0.085662841796875 +94668 0.427154541015625 +94669 0.112884521484375 +94670 0.643218994140625 +94671 0.334869384765625 +94672 0.855926513671875 +94673 0.572418212890625 +94674 0.870361328125 +94675 0.778656005859375 +94676 0.870361328125 +94677 0.86090087890625 +94678 0.862762451171875 +94679 0.868438720703125 +94680 0.79669189453125 +94681 0.8685302734375 +94682 0.595794677734375 +94683 0.860321044921875 +94684 0.362152099609375 +94685 0.780853271484375 +94686 0.1270751953125 +94687 0.624053955078125 +94688 -0.086944580078125 +94689 0.45489501953125 +94690 -0.2784423828125 +94691 0.275177001953125 +94692 -0.484832763671875 +94693 0.056854248046875 +94694 -0.729583740234375 +94695 -0.215423583984375 +94696 -0.86688232421875 +94697 -0.500640869140625 +94698 -0.870391845703125 +94699 -0.747528076171875 +94700 -0.86859130859375 +94701 -0.865142822265625 +94702 -0.86279296875 +94703 -0.870391845703125 +94704 -0.817962646484375 +94705 -0.868621826171875 +94706 -0.6116943359375 +94707 -0.8564453125 +94708 -0.3128662109375 +94709 -0.663543701171875 +94710 0.039398193359375 +94711 -0.38836669921875 +94712 0.422821044921875 +94713 -0.064788818359375 +94714 0.805145263671875 +94715 0.279632568359375 +94716 0.870361328125 +94717 0.590606689453125 +94718 0.870361328125 +94719 0.823974609375 +94720 0.860015869140625 +94721 0.867462158203125 +94722 0.727935791015625 +94723 0.870361328125 +94724 0.48114013671875 +94725 0.86407470703125 +94726 0.2059326171875 +94727 0.827606201171875 +94728 -0.06103515625 +94729 0.6807861328125 +94730 -0.29913330078125 +94731 0.516021728515625 +94732 -0.516204833984375 +94733 0.325958251953125 +94734 -0.7252197265625 +94735 0.10137939453125 +94736 -0.85980224609375 +94737 -0.134368896484375 +94738 -0.870391845703125 +94739 -0.351348876953125 +94740 -0.870391845703125 +94741 -0.525054931640625 +94742 -0.858062744140625 +94743 -0.6162109375 +94744 -0.673004150390625 +94745 -0.624114990234375 +94746 -0.42694091796875 +94747 -0.596649169921875 +94748 -0.2100830078125 +94749 -0.575653076171875 +94750 -0.0362548828125 +94751 -0.564422607421875 +94752 0.10943603515625 +94753 -0.54388427734375 +94754 0.23516845703125 +94755 -0.50250244140625 +94756 0.373687744140625 +94757 -0.410369873046875 +94758 0.517791748046875 +94759 -0.273345947265625 +94760 0.602783203125 +94761 -0.147796630859375 +94762 0.635711669921875 +94763 -0.031829833984375 +94764 0.655181884765625 +94765 0.10113525390625 +94766 0.65948486328125 +94767 0.242462158203125 +94768 0.651275634765625 +94769 0.38629150390625 +94770 0.61846923828125 +94771 0.51385498046875 +94772 0.53753662109375 +94773 0.596832275390625 +94774 0.404144287109375 +94775 0.623504638671875 +94776 0.22186279296875 +94777 0.58966064453125 +94778 0.003997802734375 +94779 0.500518798828125 +94780 -0.22100830078125 +94781 0.375579833984375 +94782 -0.42449951171875 +94783 0.23626708984375 +94784 -0.579833984375 +94785 0.104156494140625 +94786 -0.641876220703125 +94787 0.0181884765625 +94788 -0.6177978515625 +94789 -0.024810791015625 +94790 -0.575531005859375 +94791 -0.07763671875 +94792 -0.526336669921875 +94793 -0.14422607421875 +94794 -0.42645263671875 +94795 -0.181396484375 +94796 -0.2581787109375 +94797 -0.167266845703125 +94798 -0.068695068359375 +94799 -0.13433837890625 +94800 0.09222412109375 +94801 -0.1175537109375 +94802 0.232147216796875 +94803 -0.104339599609375 +94804 0.3509521484375 +94805 -0.089508056640625 +94806 0.410064697265625 +94807 -0.101409912109375 +94808 0.372955322265625 +94809 -0.16802978515625 +94810 0.2554931640625 +94811 -0.27484130859375 +94812 0.10711669921875 +94813 -0.380706787109375 +94814 -0.052886962890625 +94815 -0.471221923828125 +94816 -0.186279296875 +94817 -0.517333984375 +94818 -0.23291015625 +94819 -0.4727783203125 +94820 -0.209442138671875 +94821 -0.356658935546875 +94822 -0.174163818359375 +94823 -0.223541259765625 +94824 -0.126739501953125 +94825 -0.0789794921875 +94826 -0.048126220703125 +94827 0.087249755859375 +94828 0.0426025390625 +94829 0.253814697265625 +94830 0.10748291015625 +94831 0.384185791015625 +94832 0.1409912109375 +94833 0.470001220703125 +94834 0.19708251953125 +94835 0.553955078125 +94836 0.273651123046875 +94837 0.63287353515625 +94838 0.31768798828125 +94839 0.66204833984375 +94840 0.341094970703125 +94841 0.652587890625 +94842 0.368011474609375 +94843 0.626953125 +94844 0.37249755859375 +94845 0.5665283203125 +94846 0.30072021484375 +94847 0.4300537109375 +94848 0.1517333984375 +94849 0.221221923828125 +94850 -0.01470947265625 +94851 -0.004974365234375 +94852 -0.1883544921875 +94853 -0.235137939453125 +94854 -0.372711181640625 +94855 -0.467681884765625 +94856 -0.51397705078125 +94857 -0.65338134765625 +94858 -0.57177734375 +94859 -0.75494384765625 +94860 -0.53948974609375 +94861 -0.764312744140625 +94862 -0.43511962890625 +94863 -0.69512939453125 +94864 -0.2962646484375 +94865 -0.5784912109375 +94866 -0.161102294921875 +94867 -0.446990966796875 +94868 -0.0435791015625 +94869 -0.313812255859375 +94870 0.060394287109375 +94871 -0.177886962890625 +94872 0.13665771484375 +94873 -0.054168701171875 +94874 0.170135498046875 +94875 0.041107177734375 +94876 0.16552734375 +94877 0.108062744140625 +94878 0.15728759765625 +94879 0.171600341796875 +94880 0.150787353515625 +94881 0.232421875 +94882 0.12200927734375 +94883 0.266876220703125 +94884 0.080108642578125 +94885 0.2796630859375 +94886 0.05126953125 +94887 0.290435791015625 +94888 0.062896728515625 +94889 0.32073974609375 +94890 0.09271240234375 +94891 0.351104736328125 +94892 0.092987060546875 +94893 0.341644287109375 +94894 0.07855224609375 +94895 0.30572509765625 +94896 0.06427001953125 +94897 0.257537841796875 +94898 0.0347900390625 +94899 0.1865234375 +94900 -0.01171875 +94901 0.093902587890625 +94902 -0.056060791015625 +94903 -0.001007080078125 +94904 -0.055511474609375 +94905 -0.059051513671875 +94906 -0.010467529296875 +94907 -0.077362060546875 +94908 0.02508544921875 +94909 -0.0982666015625 +94910 0.025665283203125 +94911 -0.140533447265625 +94912 0.017333984375 +94913 -0.18017578125 +94914 0.00189208984375 +94915 -0.214202880859375 +94916 -0.03173828125 +94917 -0.251129150390625 +94918 -0.071502685546875 +94919 -0.280731201171875 +94920 -0.13543701171875 +94921 -0.3187255859375 +94922 -0.219970703125 +94923 -0.36328125 +94924 -0.300506591796875 +94925 -0.3955078125 +94926 -0.376312255859375 +94927 -0.416961669921875 +94928 -0.416107177734375 +94929 -0.40386962890625 +94930 -0.371124267578125 +94931 -0.31793212890625 +94932 -0.242279052734375 +94933 -0.162567138671875 +94934 -0.069732666015625 +94935 0.02587890625 +94936 0.125640869140625 +94937 0.22760009765625 +94938 0.31268310546875 +94939 0.41455078125 +94940 0.45501708984375 +94941 0.5548095703125 +94942 0.554779052734375 +94943 0.649322509765625 +94944 0.61065673828125 +94945 0.696685791015625 +94946 0.610931396484375 +94947 0.68731689453125 +94948 0.531463623046875 +94949 0.601776123046875 +94950 0.3883056640625 +94951 0.454803466796875 +94952 0.23468017578125 +94953 0.29278564453125 +94954 0.095245361328125 +94955 0.138458251953125 +94956 -0.00396728515625 +94957 0.015777587890625 +94958 -0.04852294921875 +94959 -0.060882568359375 +94960 -0.055145263671875 +94961 -0.103424072265625 +94962 -0.0758056640625 +94963 -0.15362548828125 +94964 -0.138702392578125 +94965 -0.23345947265625 +94966 -0.209197998046875 +94967 -0.312530517578125 +94968 -0.289031982421875 +94969 -0.391387939453125 +94970 -0.37884521484375 +94971 -0.47021484375 +94972 -0.456329345703125 +94973 -0.5302734375 +94974 -0.51641845703125 +94975 -0.56787109375 +94976 -0.519287109375 +94977 -0.55029296875 +94978 -0.458251953125 +94979 -0.47320556640625 +94980 -0.384796142578125 +94981 -0.381805419921875 +94982 -0.323699951171875 +94983 -0.298797607421875 +94984 -0.269287109375 +94985 -0.221099853515625 +94986 -0.1951904296875 +94987 -0.128021240234375 +94988 -0.100006103515625 +94989 -0.01995849609375 +94990 -0.01055908203125 +94991 0.078857421875 +94992 0.1033935546875 +94993 0.193023681640625 +94994 0.24908447265625 +94995 0.327911376953125 +94996 0.373199462890625 +94997 0.43780517578125 +94998 0.45806884765625 +94999 0.50762939453125 +95000 0.511474609375 +95001 0.5443115234375 +95002 0.565399169921875 +95003 0.575714111328125 +95004 0.61138916015625 +95005 0.59564208984375 +95006 0.5897216796875 +95007 0.554473876953125 +95008 0.4906005859375 +95009 0.4451904296875 +95010 0.33148193359375 +95011 0.28411865234375 +95012 0.147796630859375 +95013 0.102752685546875 +95014 -0.01873779296875 +95015 -0.062042236328125 +95016 -0.140289306640625 +95017 -0.1854248046875 +95018 -0.191986083984375 +95019 -0.2452392578125 +95020 -0.184295654296875 +95021 -0.2496337890625 +95022 -0.161834716796875 +95023 -0.236083984375 +95024 -0.166595458984375 +95025 -0.240142822265625 +95026 -0.19390869140625 +95027 -0.25799560546875 +95028 -0.22442626953125 +95029 -0.273651123046875 +95030 -0.279754638671875 +95031 -0.30615234375 +95032 -0.3389892578125 +95033 -0.338653564453125 +95034 -0.3543701171875 +95035 -0.331634521484375 +95036 -0.348175048828125 +95037 -0.305206298828125 +95038 -0.32598876953125 +95039 -0.2652587890625 +95040 -0.2581787109375 +95041 -0.18780517578125 +95042 -0.139801025390625 +95043 -0.06964111328125 +95044 0.014617919921875 +95045 0.07598876953125 +95046 0.144378662109375 +95047 0.19677734375 +95048 0.221038818359375 +95049 0.268096923828125 +95050 0.27069091796875 +95051 0.3118896484375 +95052 0.294036865234375 +95053 0.328826904296875 +95054 0.311767578125 +95055 0.3367919921875 +95056 0.339141845703125 +95057 0.349334716796875 +95058 0.360260009765625 +95059 0.3538818359375 +95060 0.360504150390625 +95061 0.338775634765625 +95062 0.308380126953125 +95063 0.277313232421875 +95064 0.18170166015625 +95065 0.15093994140625 +95066 0.0047607421875 +95067 -0.01824951171875 +95068 -0.17559814453125 +95069 -0.188720703125 +95070 -0.3143310546875 +95071 -0.320587158203125 +95072 -0.36785888671875 +95073 -0.375335693359375 +95074 -0.36248779296875 +95075 -0.37554931640625 +95076 -0.343536376953125 +95077 -0.360565185546875 +95078 -0.3018798828125 +95079 -0.322479248046875 +95080 -0.231414794921875 +95081 -0.256134033203125 +95082 -0.117645263671875 +95083 -0.149200439453125 +95084 0.007049560546875 +95085 -0.030426025390625 +95086 0.087982177734375 +95087 0.0518798828125 +95088 0.13946533203125 +95089 0.1094970703125 +95090 0.17425537109375 +95091 0.152862548828125 +95092 0.188201904296875 +95093 0.1776123046875 +95094 0.171234130859375 +95095 0.174285888671875 +95096 0.118438720703125 +95097 0.138031005859375 +95098 0.05706787109375 +95099 0.092132568359375 +95100 -0.010711669921875 +95101 0.0380859375 +95102 -0.0914306640625 +95103 -0.02996826171875 +95104 -0.162322998046875 +95105 -0.09222412109375 +95106 -0.194549560546875 +95107 -0.123443603515625 +95108 -0.1492919921875 +95109 -0.08953857421875 +95110 -0.02166748046875 +95111 0.01409912109375 +95112 0.124053955078125 +95113 0.131927490234375 +95114 0.211151123046875 +95115 0.1976318359375 +95116 0.240447998046875 +95117 0.2125244140625 +95118 0.242218017578125 +95119 0.20355224609375 +95120 0.2257080078125 +95121 0.17938232421875 +95122 0.194366455078125 +95123 0.143524169921875 +95124 0.115509033203125 +95125 0.067901611328125 +95126 0.0128173828125 +95127 -0.0264892578125 +95128 -0.053802490234375 +95129 -0.087249755859375 +95130 -0.110626220703125 +95131 -0.137176513671875 +95132 -0.199493408203125 +95133 -0.21282958984375 +95134 -0.29437255859375 +95135 -0.291656494140625 +95136 -0.33221435546875 +95137 -0.31890869140625 +95138 -0.27972412109375 +95139 -0.265960693359375 +95140 -0.185333251953125 +95141 -0.175506591796875 +95142 -0.128204345703125 +95143 -0.11700439453125 +95144 -0.115692138671875 +95145 -0.09735107421875 +95146 -0.116455078125 +95147 -0.0897216796875 +95148 -0.105926513671875 +95149 -0.0731201171875 +95150 -0.053955078125 +95151 -0.021636962890625 +95152 0.048797607421875 +95153 0.07257080078125 +95154 0.157318115234375 +95155 0.1700439453125 +95156 0.212005615234375 +95157 0.21868896484375 +95158 0.218475341796875 +95159 0.223419189453125 +95160 0.23724365234375 +95161 0.23712158203125 +95162 0.30535888671875 +95163 0.29229736328125 +95164 0.38128662109375 +95165 0.35296630859375 +95166 0.404449462890625 +95167 0.36663818359375 +95168 0.3944091796875 +95169 0.35076904296875 +95170 0.3885498046875 +95171 0.338348388671875 +95172 0.362640380859375 +95173 0.308685302734375 +95174 0.27362060546875 +95175 0.224609375 +95176 0.11712646484375 +95177 0.0826416015625 +95178 -0.054901123046875 +95179 -0.071624755859375 +95180 -0.19085693359375 +95181 -0.1929931640625 +95182 -0.28570556640625 +95183 -0.2769775390625 +95184 -0.339263916015625 +95185 -0.32342529296875 +95186 -0.3775634765625 +95187 -0.355072021484375 +95188 -0.445709228515625 +95189 -0.411376953125 +95190 -0.535064697265625 +95191 -0.485015869140625 +95192 -0.629058837890625 +95193 -0.56182861328125 +95194 -0.697601318359375 +95195 -0.615875244140625 +95196 -0.70391845703125 +95197 -0.615386962890625 +95198 -0.6424560546875 +95199 -0.555877685546875 +95200 -0.491241455078125 +95201 -0.41851806640625 +95202 -0.265716552734375 +95203 -0.217010498046875 +95204 -0.023712158203125 +95205 -0.0020751953125 +95206 0.201751708984375 +95207 0.197296142578125 +95208 0.375823974609375 +95209 0.350616455078125 +95210 0.485076904296875 +95211 0.446136474609375 +95212 0.56884765625 +95213 0.518157958984375 +95214 0.634765625 +95215 0.57342529296875 +95216 0.63763427734375 +95217 0.572723388671875 +95218 0.5660400390625 +95219 0.50628662109375 +95220 0.4720458984375 +95221 0.419708251953125 +95222 0.40692138671875 +95223 0.35797119140625 +95224 0.3778076171875 +95225 0.327606201171875 +95226 0.376953125 +95227 0.322113037109375 +95228 0.371978759765625 +95229 0.31353759765625 +95230 0.313140869140625 +95231 0.25872802734375 +95232 0.184417724609375 +95233 0.143646240234375 +95234 0.011199951171875 +95235 -0.009674072265625 +95236 -0.171051025390625 +95237 -0.1700439453125 +95238 -0.33740234375 +95239 -0.31524658203125 +95240 -0.47198486328125 +95241 -0.4312744140625 +95242 -0.560394287109375 +95243 -0.505462646484375 +95244 -0.58056640625 +95245 -0.518218994140625 +95246 -0.54754638671875 +95247 -0.483428955078125 +95248 -0.508575439453125 +95249 -0.444091796875 +95250 -0.459503173828125 +95251 -0.396636962890625 +95252 -0.394378662109375 +95253 -0.3358154296875 +95254 -0.35260009765625 +95255 -0.297332763671875 +95256 -0.31170654296875 +95257 -0.260833740234375 +95258 -0.197418212890625 +95259 -0.159149169921875 +95260 -0.007965087890625 +95261 0.00946044921875 +95262 0.207489013671875 +95263 0.20074462890625 +95264 0.409210205078125 +95265 0.37896728515625 +95266 0.57208251953125 +95267 0.52166748046875 +95268 0.66595458984375 +95269 0.60186767578125 +95270 0.65875244140625 +95271 0.5908203125 +95272 0.56744384765625 +95273 0.504119873046875 +95274 0.431396484375 +95275 0.3775634765625 +95276 0.29443359375 +95277 0.2509765625 +95278 0.182464599609375 +95279 0.14788818359375 +95280 0.06365966796875 +95281 0.03961181640625 +95282 -0.075958251953125 +95283 -0.086456298828125 +95284 -0.189422607421875 +95285 -0.18792724609375 +95286 -0.271942138671875 +95287 -0.26055908203125 +95288 -0.342529296875 +95289 -0.3216552734375 +95290 -0.364166259765625 +95291 -0.337921142578125 +95292 -0.327239990234375 +95293 -0.3009033203125 +95294 -0.2769775390625 +95295 -0.251678466796875 +95296 -0.253692626953125 +95297 -0.22686767578125 +95298 -0.24365234375 +95299 -0.214263916015625 +95300 -0.1983642578125 +95301 -0.17022705078125 +95302 -0.116241455078125 +95303 -0.093505859375 +95304 -0.036834716796875 +95305 -0.019927978515625 +95306 0.034881591796875 +95307 0.0458984375 +95308 0.09124755859375 +95309 0.0970458984375 +95310 0.10888671875 +95311 0.1124267578125 +95312 0.125518798828125 +95313 0.126129150390625 +95314 0.15771484375 +95315 0.15325927734375 +95316 0.17828369140625 +95317 0.1693115234375 +95318 0.17108154296875 +95319 0.15985107421875 +95320 0.129974365234375 +95321 0.11956787109375 +95322 0.082427978515625 +95323 0.073455810546875 +95324 0.027679443359375 +95325 0.02099609375 +95326 -0.065643310546875 +95327 -0.066009521484375 +95328 -0.15936279296875 +95329 -0.15289306640625 +95330 -0.21307373046875 +95331 -0.20306396484375 +95332 -0.234649658203125 +95333 -0.22357177734375 +95334 -0.2001953125 +95335 -0.192779541015625 +95336 -0.119171142578125 +95337 -0.119232177734375 +95338 -0.024749755859375 +95339 -0.032958984375 +95340 0.085784912109375 +95341 0.06842041015625 +95342 0.178131103515625 +95343 0.15380859375 +95344 0.215576171875 +95345 0.189910888671875 +95346 0.211456298828125 +95347 0.188629150390625 +95348 0.17523193359375 +95349 0.15838623046875 +95350 0.128753662109375 +95351 0.118804931640625 +95352 0.1019287109375 +95353 0.0968017578125 +95354 0.0743408203125 +95355 0.07379150390625 +95356 0.04327392578125 +95357 0.047210693359375 +95358 0.038177490234375 +95359 0.043609619140625 +95360 0.076263427734375 +95361 0.078521728515625 +95362 0.14105224609375 +95363 0.137054443359375 +95364 0.186431884765625 +95365 0.177520751953125 +95366 0.188812255859375 +95367 0.17864990234375 +95368 0.1390380859375 +95369 0.1322021484375 +95370 0.041778564453125 +95371 0.04254150390625 +95372 -0.079437255859375 +95373 -0.0689697265625 +95374 -0.219390869140625 +95375 -0.197509765625 +95376 -0.367828369140625 +95377 -0.33367919921875 +95378 -0.494873046875 +95379 -0.450408935546875 +95380 -0.556243896484375 +95381 -0.507537841796875 +95382 -0.508697509765625 +95383 -0.465911865234375 +95384 -0.3756103515625 +95385 -0.3465576171875 +95386 -0.218902587890625 +95387 -0.2054443359375 +95388 -0.063751220703125 +95389 -0.0653076171875 +95390 0.091552734375 +95391 0.07537841796875 +95392 0.23602294921875 +95393 0.2066650390625 +95394 0.342987060546875 +95395 0.30438232421875 +95396 0.39520263671875 +95397 0.352874755859375 +95398 0.389373779296875 +95399 0.34912109375 +95400 0.324249267578125 +95401 0.291900634765625 +95402 0.224090576171875 +95403 0.203033447265625 +95404 0.124267578125 +95405 0.114410400390625 +95406 0.037078857421875 +95407 0.037017822265625 +95408 -0.010101318359375 +95409 -0.00445556640625 +95410 -0.019439697265625 +95411 -0.011993408203125 +95412 -0.022796630859375 +95413 -0.014434814453125 +95414 -0.001556396484375 +95415 0.004974365234375 +95416 0.056304931640625 +95417 0.05712890625 +95418 0.106719970703125 +95419 0.102203369140625 +95420 0.096893310546875 +95421 0.092529296875 +95422 0.042694091796875 +95423 0.04248046875 +95424 -0.018035888671875 +95425 -0.013671875 +95426 -0.07586669921875 +95427 -0.067291259765625 +95428 -0.11944580078125 +95429 -0.108062744140625 +95430 -0.15972900390625 +95431 -0.145843505859375 +95432 -0.202606201171875 +95433 -0.18585205078125 +95434 -0.24859619140625 +95435 -0.228485107421875 +95436 -0.30517578125 +95437 -0.280426025390625 +95438 -0.36212158203125 +95439 -0.332427978515625 +95440 -0.39141845703125 +95441 -0.359130859375 +95442 -0.35528564453125 +95443 -0.32635498046875 +95444 -0.249969482421875 +95445 -0.230743408203125 +95446 -0.092864990234375 +95447 -0.088104248046875 +95448 0.08905029296875 +95449 0.077178955078125 +95450 0.2352294921875 +95451 0.2103271484375 +95452 0.318817138671875 +95453 0.287017822265625 +95454 0.358642578125 +95455 0.32415771484375 +95456 0.347747802734375 +95457 0.3154296875 +95458 0.28564453125 +95459 0.260345458984375 +95460 0.223175048828125 +95461 0.204803466796875 +95462 0.196746826171875 +95463 0.181640625 +95464 0.179840087890625 +95465 0.1668701171875 +95466 0.155548095703125 +95467 0.145172119140625 +95468 0.151214599609375 +95469 0.141265869140625 +95470 0.156951904296875 +95471 0.146209716796875 +95472 0.13177490234375 +95473 0.122955322265625 +95474 0.100799560546875 +95475 0.094268798828125 +95476 0.087127685546875 +95477 0.0810546875 +95478 0.05487060546875 +95479 0.050933837890625 +95480 -0.009002685546875 +95481 -0.007781982421875 +95482 -0.10400390625 +95483 -0.0946044921875 +95484 -0.229400634765625 +95485 -0.2088623046875 +95486 -0.35552978515625 +95487 -0.32366943359375 +95488 -0.441925048828125 +95489 -0.402587890625 +95490 -0.473846435546875 +95491 -0.4326171875 +95492 -0.464813232421875 +95493 -0.426055908203125 +95494 -0.419097900390625 +95495 -0.386260986328125 +95496 -0.334320068359375 +95497 -0.31048583984375 +95498 -0.227935791015625 +95499 -0.214569091796875 +95500 -0.12347412109375 +95501 -0.120208740234375 +95502 -0.02764892578125 +95503 -0.03338623046875 +95504 0.077667236328125 +95505 0.063079833984375 +95506 0.2132568359375 +95507 0.188720703125 +95508 0.38885498046875 +95509 0.352691650390625 +95510 0.582794189453125 +95511 0.53466796875 +95512 0.734039306640625 +95513 0.677398681640625 +95514 0.800140380859375 +95515 0.7410888671875 +95516 0.7783203125 +95517 0.72296142578125 +95518 0.6651611328125 +95519 0.619659423828125 +95520 0.45965576171875 +95521 0.4300537109375 +95522 0.199188232421875 +95523 0.18896484375 +95524 -0.050689697265625 +95525 -0.04241943359375 +95526 -0.23297119140625 +95527 -0.21087646484375 +95528 -0.33013916015625 +95529 -0.300140380859375 +95530 -0.368408203125 +95531 -0.33477783203125 +95532 -0.378936767578125 +95533 -0.344024658203125 +95534 -0.376983642578125 +95535 -0.342193603515625 +95536 -0.37969970703125 +95537 -0.345306396484375 +95538 -0.391510009765625 +95539 -0.357452392578125 +95540 -0.385345458984375 +95541 -0.353271484375 +95542 -0.3419189453125 +95543 -0.314605712890625 +95544 -0.28289794921875 +95545 -0.2615966796875 +95546 -0.251617431640625 +95547 -0.234649658203125 +95548 -0.266143798828125 +95549 -0.25054931640625 +95550 -0.273345947265625 +95551 -0.25946044921875 +95552 -0.216796875 +95553 -0.20843505859375 +95554 -0.128265380859375 +95555 -0.127105712890625 +95556 -0.068145751953125 +95557 -0.07196044921875 +95558 -0.0430908203125 +95559 -0.049163818359375 +95560 -0.024444580078125 +95561 -0.0318603515625 +95562 0.020721435546875 +95563 0.010772705078125 +95564 0.124481201171875 +95565 0.108734130859375 +95566 0.25787353515625 +95567 0.23480224609375 +95568 0.379119873046875 +95569 0.349822998046875 +95570 0.47991943359375 +95571 0.445953369140625 +95572 0.5281982421875 +95573 0.4930419921875 +95574 0.511138916015625 +95575 0.47900390625 +95576 0.456207275390625 +95577 0.429443359375 +95578 0.407470703125 +95579 0.385498046875 +95580 0.383758544921875 +95581 0.36468505859375 +95582 0.35687255859375 +95583 0.340576171875 +95584 0.31182861328125 +95585 0.299102783203125 +95586 0.250885009765625 +95587 0.2423095703125 +95588 0.1654052734375 +95589 0.162139892578125 +95590 0.035247802734375 +95591 0.03973388671875 +95592 -0.142059326171875 +95593 -0.127166748046875 +95594 -0.33563232421875 +95595 -0.3095703125 +95596 -0.5345458984375 +95597 -0.4971923828125 +95598 -0.72186279296875 +95599 -0.674072265625 +95600 -0.836669921875 +95601 -0.783111572265625 +95602 -0.8326416015625 +95603 -0.7808837890625 +95604 -0.7296142578125 +95605 -0.685882568359375 +95606 -0.582550048828125 +95607 -0.549468994140625 +95608 -0.440093994140625 +95609 -0.417083740234375 +95610 -0.324310302734375 +95611 -0.30938720703125 +95612 -0.20147705078125 +95613 -0.194732666015625 +95614 -0.044647216796875 +95615 -0.04791259765625 +95616 0.103973388671875 +95617 0.091583251953125 +95618 0.202392578125 +95619 0.18438720703125 +95620 0.264495849609375 +95621 0.243438720703125 +95622 0.338897705078125 +95623 0.314239501953125 +95624 0.443817138671875 +95625 0.413726806640625 +95626 0.545074462890625 +95627 0.509857177734375 +95628 0.6173095703125 +95629 0.57879638671875 +95630 0.6524658203125 +95631 0.612945556640625 +95632 0.66339111328125 +95633 0.624237060546875 +95634 0.6561279296875 +95635 0.6182861328125 +95636 0.606781005859375 +95637 0.572662353515625 +95638 0.501190185546875 +95639 0.47412109375 +95640 0.352783203125 +95641 0.335174560546875 +95642 0.176544189453125 +95643 0.169921875 +95644 -0.034820556640625 +95645 -0.0284423828125 +95646 -0.258209228515625 +95647 -0.23828125 +95648 -0.44244384765625 +95649 -0.411651611328125 +95650 -0.5753173828125 +95651 -0.53704833984375 +95652 -0.65203857421875 +95653 -0.60992431640625 +95654 -0.641632080078125 +95655 -0.601226806640625 +95656 -0.562164306640625 +95657 -0.52783203125 +95658 -0.458038330078125 +95659 -0.431243896484375 +95660 -0.350555419921875 +95661 -0.331329345703125 +95662 -0.260528564453125 +95663 -0.24755859375 +95664 -0.192108154296875 +95665 -0.183807373046875 +95666 -0.141937255859375 +95667 -0.13690185546875 +95668 -0.1021728515625 +95669 -0.099517822265625 +95670 -0.062896728515625 +95671 -0.0623779296875 +95672 -0.011932373046875 +95673 -0.01409912109375 +95674 0.062835693359375 +95675 0.056610107421875 +95676 0.148712158203125 +95677 0.137847900390625 +95678 0.241729736328125 +95679 0.225799560546875 +95680 0.34912109375 +95681 0.32720947265625 +95682 0.457305908203125 +95683 0.4293212890625 +95684 0.54388427734375 +95685 0.5111083984375 +95686 0.5728759765625 +95687 0.53887939453125 +95688 0.506591796875 +95689 0.477294921875 +95690 0.351226806640625 +95691 0.3321533203125 +95692 0.146514892578125 +95693 0.140625 +95694 -0.05523681640625 +95695 -0.048309326171875 +95696 -0.21624755859375 +95697 -0.19927978515625 +95698 -0.334930419921875 +95699 -0.310760498046875 +95700 -0.402984619140625 +95701 -0.375 +95702 -0.4412841796875 +95703 -0.4114990234375 +95704 -0.49578857421875 +95705 -0.463226318359375 +95706 -0.5601806640625 +95707 -0.52423095703125 +95708 -0.600738525390625 +95709 -0.56292724609375 +95710 -0.584228515625 +95711 -0.548126220703125 +95712 -0.47930908203125 +95713 -0.450469970703125 +95714 -0.27935791015625 +95715 -0.263763427734375 +95716 -0.0089111328125 +95717 -0.01092529296875 +95718 0.268798828125 +95719 0.24884033203125 +95720 0.482818603515625 +95721 0.44915771484375 +95722 0.60369873046875 +95723 0.562469482421875 +95724 0.650421142578125 +95725 0.60650634765625 +95726 0.66400146484375 +95727 0.61962890625 +95728 0.6414794921875 +95729 0.599029541015625 +95730 0.572540283203125 +95731 0.5350341796875 +95732 0.498138427734375 +95733 0.465972900390625 +95734 0.439453125 +95735 0.41162109375 +95736 0.375518798828125 +95737 0.352325439453125 +95738 0.274505615234375 +95739 0.258270263671875 +95740 0.1087646484375 +95741 0.103546142578125 +95742 -0.099395751953125 +95743 -0.09100341796875 +95744 -0.3182373046875 +95745 -0.296142578125 +95746 -0.5489501953125 +95747 -0.51385498046875 +95748 -0.7738037109375 +95749 -0.727325439453125 +95750 -0.86383056640625 +95751 -0.857879638671875 +95752 -0.870391845703125 +95753 -0.8656005859375 +95754 -0.86895751953125 +95755 -0.865631103515625 +95756 -0.861053466796875 +95757 -0.859344482421875 +95758 -0.765869140625 +95759 -0.7667236328125 +95760 -0.5301513671875 +95761 -0.548583984375 +95762 -0.214691162109375 +95763 -0.251129150390625 +95764 0.137359619140625 +95765 0.084320068359375 +95766 0.474822998046875 +95767 0.408416748046875 +95768 0.76239013671875 +95769 0.68707275390625 +95770 0.867462158203125 +95771 0.85882568359375 +95772 0.870361328125 +95773 0.870361328125 +95774 0.86480712890625 +95775 0.870361328125 +95776 0.831817626953125 +95777 0.862701416015625 +95778 0.677581787109375 +95779 0.816070556640625 +95780 0.495880126953125 +95781 0.665863037109375 +95782 0.30767822265625 +95783 0.498504638671875 +95784 0.116180419921875 +95785 0.316619873046875 +95786 -0.110748291015625 +95787 0.089202880859375 +95788 -0.381805419921875 +95789 -0.19140625 +95790 -0.6572265625 +95791 -0.485443115234375 +95792 -0.857421875 +95793 -0.737091064453125 +95794 -0.870391845703125 +95795 -0.860260009765625 +95796 -0.870391845703125 +95797 -0.869537353515625 +95798 -0.86444091796875 +95799 -0.870391845703125 +95800 -0.85723876953125 +95801 -0.86932373046875 +95802 -0.790008544921875 +95803 -0.864837646484375 +95804 -0.62847900390625 +95805 -0.826568603515625 +95806 -0.3956298828125 +95807 -0.622161865234375 +95808 -0.126708984375 +95809 -0.369171142578125 +95810 0.150115966796875 +95811 -0.0948486328125 +95812 0.424041748046875 +95813 0.1895751953125 +95814 0.670623779296875 +95815 0.459014892578125 +95816 0.854522705078125 +95817 0.677703857421875 +95818 0.866485595703125 +95819 0.830902099609375 +95820 0.86920166015625 +95821 0.86016845703125 +95822 0.8653564453125 +95823 0.862213134765625 +95824 0.857147216796875 +95825 0.85986328125 +95826 0.766845703125 +95827 0.84197998046875 +95828 0.628509521484375 +95829 0.748138427734375 +95830 0.462127685546875 +95831 0.61834716796875 +95832 0.297210693359375 +95833 0.479736328125 +95834 0.14862060546875 +95835 0.3458251953125 +95836 -0.00537109375 +95837 0.19537353515625 +95838 -0.15753173828125 +95839 0.0357666015625 +95840 -0.31304931640625 +95841 -0.136993408203125 +95842 -0.48876953125 +95843 -0.337738037109375 +95844 -0.6416015625 +95845 -0.5228271484375 +95846 -0.751373291015625 +95847 -0.67047119140625 +95848 -0.84619140625 +95849 -0.805572509765625 +95850 -0.861297607421875 +95851 -0.86126708984375 +95852 -0.863250732421875 +95853 -0.8675537109375 +95854 -0.856597900390625 +95855 -0.86492919921875 +95856 -0.7498779296875 +95857 -0.854949951171875 +95858 -0.624542236328125 +95859 -0.757598876953125 +95860 -0.47808837890625 +95861 -0.627227783203125 +95862 -0.253387451171875 +95863 -0.41180419921875 +95864 0.003692626953125 +95865 -0.155853271484375 +95866 0.2257080078125 +95867 0.07464599609375 +95868 0.427154541015625 +95869 0.2926025390625 +95870 0.643218994140625 +95871 0.5306396484375 +95872 0.855926513671875 +95873 0.78106689453125 +95874 0.870361328125 +95875 0.869232177734375 +95876 0.870361328125 +95877 0.870361328125 +95878 0.862762451171875 +95879 0.8638916015625 +95880 0.79669189453125 +95881 0.817047119140625 +95882 0.595794677734375 +95883 0.6256103515625 +95884 0.362152099609375 +95885 0.39971923828125 +95886 0.1270751953125 +95887 0.169769287109375 +95888 -0.086944580078125 +95889 -0.042266845703125 +95890 -0.2784423828125 +95891 -0.23468017578125 +95892 -0.484832763671875 +95893 -0.443206787109375 +95894 -0.729583740234375 +95895 -0.6900634765625 +95896 -0.86688232421875 +95897 -0.862884521484375 +95898 -0.870391845703125 +95899 -0.870391845703125 +95900 -0.86859130859375 +95901 -0.870391845703125 +95902 -0.86279296875 +95903 -0.8662109375 +95904 -0.817962646484375 +95905 -0.8553466796875 +95906 -0.6116943359375 +95907 -0.667633056640625 +95908 -0.3128662109375 +95909 -0.379302978515625 +95910 0.039398193359375 +95911 -0.0350341796875 +95912 0.422821044921875 +95913 0.34332275390625 +95914 0.805145263671875 +95915 0.723968505859375 +95916 0.870361328125 +95917 0.870361328125 +95918 0.870361328125 +95919 0.870361328125 +95920 0.860015869140625 +95921 0.86016845703125 +95922 0.727935791015625 +95923 0.7315673828125 +95924 0.48114013671875 +95925 0.48797607421875 +95926 0.2059326171875 +95927 0.215789794921875 +95928 -0.06103515625 +95929 -0.04913330078125 +95930 -0.29913330078125 +95931 -0.2864990234375 +95932 -0.516204833984375 +95933 -0.503509521484375 +95934 -0.7252197265625 +95935 -0.712310791015625 +95936 -0.85980224609375 +95937 -0.8583984375 +95938 -0.870391845703125 +95939 -0.870391845703125 +95940 -0.870391845703125 +95941 -0.870391845703125 +95942 -0.858062744140625 +95943 -0.8582763671875 +95944 -0.673004150390625 +95945 -0.6783447265625 +95946 -0.42694091796875 +95947 -0.435394287109375 +95948 -0.2100830078125 +95949 -0.219696044921875 +95950 -0.0362548828125 +95951 -0.044921875 +95952 0.10943603515625 +95953 0.10296630859375 +95954 0.23516845703125 +95955 0.23150634765625 +95956 0.373687744140625 +95957 0.37200927734375 +95958 0.517791748046875 +95959 0.51715087890625 +95960 0.602783203125 +95961 0.604034423828125 +95962 0.635711669921875 +95963 0.639312744140625 +95964 0.655181884765625 +95965 0.66015625 +95966 0.65948486328125 +95967 0.66485595703125 +95968 0.651275634765625 +95969 0.655975341796875 +95970 0.61846923828125 +95971 0.62188720703125 +95972 0.53753662109375 +95973 0.540008544921875 +95974 0.404144287109375 +95975 0.4063720703125 +95976 0.22186279296875 +95977 0.224700927734375 +95978 0.003997802734375 +95979 0.008209228515625 +95980 -0.22100830078125 +95981 -0.21527099609375 +95982 -0.42449951171875 +95983 -0.417724609375 +95984 -0.579833984375 +95985 -0.57305908203125 +95986 -0.641876220703125 +95987 -0.637298583984375 +95988 -0.6177978515625 +95989 -0.617156982421875 +95990 -0.575531005859375 +95991 -0.578277587890625 +95992 -0.526336669921875 +95993 -0.531463623046875 +95994 -0.42645263671875 +95995 -0.43438720703125 +95996 -0.2581787109375 +95997 -0.2698974609375 +95998 -0.068695068359375 +95999 -0.083831787109375 +96000 0.09222412109375 +96001 0.075958251953125 +96002 0.232147216796875 +96003 0.2171630859375 +96004 0.3509521484375 +96005 0.3388671875 +96006 0.410064697265625 +96007 0.401947021484375 +96008 0.372955322265625 +96009 0.369384765625 +96010 0.2554931640625 +96011 0.256622314453125 +96012 0.10711669921875 +96013 0.11273193359375 +96014 -0.052886962890625 +96015 -0.0433349609375 +96016 -0.186279296875 +96017 -0.173553466796875 +96018 -0.23291015625 +96019 -0.21795654296875 +96020 -0.209442138671875 +96021 -0.19329833984375 +96022 -0.174163818359375 +96023 -0.15789794921875 +96024 -0.126739501953125 +96025 -0.111358642578125 +96026 -0.048126220703125 +96027 -0.0345458984375 +96028 0.0426025390625 +96029 0.0535888671875 +96030 0.10748291015625 +96031 0.11529541015625 +96032 0.1409912109375 +96033 0.145233154296875 +96034 0.19708251953125 +96035 0.197601318359375 +96036 0.273651123046875 +96037 0.270538330078125 +96038 0.31768798828125 +96039 0.311248779296875 +96040 0.341094970703125 +96041 0.331787109375 +96042 0.368011474609375 +96043 0.356414794921875 +96044 0.37249755859375 +96045 0.359283447265625 +96046 0.30072021484375 +96047 0.286651611328125 +96048 0.1517333984375 +96049 0.1375732421875 +96050 -0.01470947265625 +96051 -0.0281982421875 +96052 -0.1883544921875 +96053 -0.200439453125 +96054 -0.372711181640625 +96055 -0.38275146484375 +96056 -0.51397705078125 +96057 -0.521484375 +96058 -0.57177734375 +96059 -0.576416015625 +96060 -0.53948974609375 +96061 -0.541107177734375 +96062 -0.43511962890625 +96063 -0.4337158203125 +96064 -0.2962646484375 +96065 -0.292022705078125 +96066 -0.161102294921875 +96067 -0.154327392578125 +96068 -0.0435791015625 +96069 -0.034698486328125 +96070 0.060394287109375 +96071 0.070831298828125 +96072 0.13665771484375 +96073 0.148040771484375 +96074 0.170135498046875 +96075 0.18182373046875 +96076 0.16552734375 +96077 0.1768798828125 +96078 0.15728759765625 +96079 0.16766357421875 +96080 0.150787353515625 +96081 0.15966796875 +96082 0.12200927734375 +96083 0.12896728515625 +96084 0.080108642578125 +96085 0.084808349609375 +96086 0.05126953125 +96087 0.05352783203125 +96088 0.062896728515625 +96089 0.06268310546875 +96090 0.09271240234375 +96091 0.090118408203125 +96092 0.092987060546875 +96093 0.088226318359375 +96094 0.07855224609375 +96095 0.071929931640625 +96096 0.06427001953125 +96097 0.05621337890625 +96098 0.0347900390625 +96099 0.025787353515625 +96100 -0.01171875 +96101 -0.021148681640625 +96102 -0.056060791015625 +96103 -0.06536865234375 +96104 -0.055511474609375 +96105 -0.064208984375 +96106 -0.010467529296875 +96107 -0.018096923828125 +96108 0.02508544921875 +96109 0.0189208984375 +96110 0.025665283203125 +96111 0.021270751953125 +96112 0.017333984375 +96113 0.014923095703125 +96114 0.00189208984375 +96115 0.00152587890625 +96116 -0.03173828125 +96117 -0.03009033203125 +96118 -0.071502685546875 +96119 -0.0679931640625 +96120 -0.13543701171875 +96121 -0.13031005859375 +96122 -0.219970703125 +96123 -0.21356201171875 +96124 -0.300506591796875 +96125 -0.293182373046875 +96126 -0.376312255859375 +96127 -0.368499755859375 +96128 -0.416107177734375 +96129 -0.408233642578125 +96130 -0.371124267578125 +96131 -0.363616943359375 +96132 -0.242279052734375 +96133 -0.23553466796875 +96134 -0.069732666015625 +96135 -0.0640869140625 +96136 0.125640869140625 +96137 0.129913330078125 +96138 0.31268310546875 +96139 0.31536865234375 +96140 0.45501708984375 +96141 0.456024169921875 +96142 0.554779052734375 +96143 0.554107666015625 +96144 0.61065673828125 +96145 0.6083984375 +96146 0.610931396484375 +96147 0.607269287109375 +96148 0.531463623046875 +96149 0.526641845703125 +96150 0.3883056640625 +96151 0.382598876953125 +96152 0.23468017578125 +96153 0.228424072265625 +96154 0.095245361328125 +96155 0.08880615234375 +96156 -0.00396728515625 +96157 -0.010223388671875 +96158 -0.04852294921875 +96159 -0.05426025390625 +96160 -0.055145263671875 +96161 -0.06005859375 +96162 -0.0758056640625 +96163 -0.07965087890625 +96164 -0.138702392578125 +96165 -0.14129638671875 +96166 -0.209197998046875 +96167 -0.21044921875 +96168 -0.289031982421875 +96169 -0.288909912109375 +96170 -0.37884521484375 +96171 -0.377410888671875 +96172 -0.456329345703125 +96173 -0.45367431640625 +96174 -0.51641845703125 +96175 -0.512725830078125 +96176 -0.519287109375 +96177 -0.514801025390625 +96178 -0.458251953125 +96179 -0.4532470703125 +96180 -0.384796142578125 +96181 -0.379547119140625 +96182 -0.323699951171875 +96183 -0.3184814453125 +96184 -0.269287109375 +96185 -0.264373779296875 +96186 -0.1951904296875 +96187 -0.19085693359375 +96188 -0.100006103515625 +96189 -0.096466064453125 +96190 -0.01055908203125 +96191 -0.007965087890625 +96192 0.1033935546875 +96193 0.10491943359375 +96194 0.24908447265625 +96195 0.249481201171875 +96196 0.373199462890625 +96197 0.372467041015625 +96198 0.45806884765625 +96199 0.456298828125 +96200 0.511474609375 +96201 0.5087890625 +96202 0.565399169921875 +96203 0.561981201171875 +96204 0.61138916015625 +96205 0.607452392578125 +96206 0.5897216796875 +96207 0.58551025390625 +96208 0.4906005859375 +96209 0.486328125 +96210 0.33148193359375 +96211 0.327392578125 +96212 0.147796630859375 +96213 0.14410400390625 +96214 -0.01873779296875 +96215 -0.0218505859375 +96216 -0.140289306640625 +96217 -0.142669677734375 +96218 -0.191986083984375 +96219 -0.193511962890625 +96220 -0.184295654296875 +96221 -0.184906005859375 +96222 -0.161834716796875 +96223 -0.1614990234375 +96224 -0.166595458984375 +96225 -0.16534423828125 +96226 -0.19390869140625 +96227 -0.19183349609375 +96228 -0.22442626953125 +96229 -0.2216796875 +96230 -0.279754638671875 +96231 -0.2764892578125 +96232 -0.3389892578125 +96233 -0.33538818359375 +96234 -0.3543701171875 +96235 -0.35064697265625 +96236 -0.348175048828125 +96237 -0.34454345703125 +96238 -0.32598876953125 +96239 -0.322662353515625 +96240 -0.2581787109375 +96241 -0.255340576171875 +96242 -0.139801025390625 +96243 -0.137603759765625 +96244 0.014617919921875 +96245 0.016082763671875 +96246 0.144378662109375 +96247 0.145050048828125 +96248 0.221038818359375 +96249 0.220916748046875 +96250 0.27069091796875 +96251 0.269805908203125 +96252 0.294036865234375 +96253 0.29248046875 +96254 0.311767578125 +96255 0.309661865234375 +96256 0.33905029296875 +96257 0.33660888671875 +96258 0.359588623046875 +96259 0.357452392578125 +96260 0.35888671875 +96261 0.357574462890625 +96262 0.306671142578125 +96263 0.30548095703125 +96264 0.18170166015625 +96265 0.178985595703125 +96266 0.00775146484375 +96267 0.00238037109375 +96268 -0.16961669921875 +96269 -0.177520751953125 +96270 -0.306640625 +96271 -0.315704345703125 +96272 -0.3609619140625 +96273 -0.368621826171875 +96274 -0.357879638671875 +96275 -0.36260986328125 +96276 -0.341156005859375 +96277 -0.343017578125 +96278 -0.3018798828125 +96279 -0.30078125 +96280 -0.234100341796875 +96281 -0.22979736328125 +96282 -0.123809814453125 +96283 -0.1156005859375 +96284 -0.002349853515625 +96285 0.0093994140625 +96286 0.0772705078125 +96287 0.09051513671875 +96288 0.1287841796875 +96289 0.14202880859375 +96290 0.164459228515625 +96291 0.176727294921875 +96292 0.18011474609375 +96293 0.1904296875 +96294 0.1658935546875 +96295 0.173095703125 +96296 0.116943359375 +96297 0.119842529296875 +96298 0.05950927734375 +96299 0.057952880859375 +96300 -0.004425048828125 +96301 -0.0103759765625 +96302 -0.081298828125 +96303 -0.091644287109375 +96304 -0.149078369140625 +96305 -0.163055419921875 +96306 -0.179901123046875 +96307 -0.19573974609375 +96308 -0.13623046875 +96309 -0.15087890625 +96310 -0.0133056640625 +96311 -0.0235595703125 +96312 0.126739501953125 +96313 0.121978759765625 +96314 0.209686279296875 +96315 0.209014892578125 +96316 0.2364501953125 +96317 0.238372802734375 +96318 0.23638916015625 +96319 0.24029541015625 +96320 0.218597412109375 +96321 0.22406005859375 +96322 0.186492919921875 +96323 0.193084716796875 +96324 0.108551025390625 +96325 0.114654541015625 +96326 0.00775146484375 +96327 0.012420654296875 +96328 -0.057830810546875 +96329 -0.053741455078125 +96330 -0.113555908203125 +96331 -0.110107421875 +96332 -0.199951171875 +96333 -0.198577880859375 +96334 -0.29180908203125 +96335 -0.293121337890625 +96336 -0.32806396484375 +96337 -0.3306884765625 +96338 -0.27655029296875 +96339 -0.27801513671875 +96340 -0.184173583984375 +96341 -0.18353271484375 +96342 -0.12762451171875 +96343 -0.12640380859375 +96344 -0.11407470703125 +96345 -0.113983154296875 +96346 -0.11328125 +96347 -0.11492919921875 +96348 -0.1015625 +96349 -0.104644775390625 +96350 -0.049835205078125 +96351 -0.052978515625 +96352 0.05084228515625 +96353 0.0494384765625 +96354 0.156890869140625 +96355 0.157623291015625 +96356 0.2105712890625 +96357 0.21197509765625 +96358 0.217254638671875 +96359 0.218109130859375 +96360 0.23553466796875 +96361 0.236572265625 +96362 0.30126953125 +96363 0.304443359375 +96364 0.374237060546875 +96365 0.380157470703125 +96366 0.395843505859375 +96367 0.403167724609375 +96368 0.38507080078125 +96369 0.393035888671875 +96370 0.378173828125 +96371 0.38714599609375 +96372 0.351806640625 +96373 0.361297607421875 +96374 0.264373779296875 +96375 0.27239990234375 +96376 0.1116943359375 +96377 0.1160888671875 +96378 -0.055877685546875 +96379 -0.055694580078125 +96380 -0.188323974609375 +96381 -0.19134521484375 +96382 -0.28076171875 +96383 -0.285858154296875 +96384 -0.3330078125 +96385 -0.339080810546875 +96386 -0.370208740234375 +96387 -0.3770751953125 +96388 -0.43603515625 +96389 -0.4449462890625 +96390 -0.52215576171875 +96391 -0.534088134765625 +96392 -0.612548828125 +96393 -0.6279296875 +96394 -0.678131103515625 +96395 -0.696380615234375 +96396 -0.683349609375 +96397 -0.70269775390625 +96398 -0.62286376953125 +96399 -0.64129638671875 +96400 -0.4754638671875 +96401 -0.490203857421875 +96402 -0.25616455078125 +96403 -0.264862060546875 +96404 -0.02099609375 +96405 -0.0230712890625 +96406 0.198028564453125 +96407 0.2021484375 +96408 0.36712646484375 +96409 0.3759765625 +96410 0.473297119140625 +96411 0.4849853515625 +96412 0.554595947265625 +96413 0.568511962890625 +96414 0.618408203125 +96415 0.63421630859375 +96416 0.6209716796875 +96417 0.636932373046875 +96418 0.551239013671875 +96419 0.565216064453125 +96420 0.45965576171875 +96421 0.47113037109375 +96422 0.3958740234375 +96423 0.40594482421875 +96424 0.36688232421875 +96425 0.376800537109375 +96426 0.36517333984375 +96427 0.375946044921875 +96428 0.3594970703125 +96429 0.37103271484375 +96430 0.3017578125 +96431 0.31231689453125 +96432 0.17645263671875 +96433 0.183746337890625 +96434 0.008209228515625 +96435 0.010711669921875 +96436 -0.168609619140625 +96437 -0.17132568359375 +96438 -0.329864501953125 +96439 -0.33746337890625 +96440 -0.460174560546875 +96441 -0.471832275390625 +96442 -0.54559326171875 +96443 -0.560028076171875 +96444 -0.5648193359375 +96445 -0.58001708984375 +96446 -0.53240966796875 +96447 -0.546844482421875 +96448 -0.494140625 +96449 -0.507781982421875 +96450 -0.44598388671875 +96451 -0.458648681640625 +96452 -0.38226318359375 +96453 -0.393524169921875 +96454 -0.34112548828125 +96455 -0.351806640625 +96456 -0.30084228515625 +96457 -0.311004638671875 +96458 -0.1895751953125 +96459 -0.19683837890625 +96460 -0.005645751953125 +96461 -0.007537841796875 +96462 0.203338623046875 +96463 0.207733154296875 +96464 0.398834228515625 +96465 0.409271240234375 +96466 0.556549072265625 +96467 0.57196044921875 +96468 0.647308349609375 +96469 0.6656494140625 +96470 0.64007568359375 +96471 0.65826416015625 +96472 0.551300048828125 +96473 0.566802978515625 +96474 0.41912841796875 +96475 0.430633544921875 +96476 0.2860107421875 +96477 0.2935791015625 +96478 0.17706298828125 +96479 0.18157958984375 +96480 0.061492919921875 +96481 0.062774658203125 +96482 -0.074188232421875 +96483 -0.076812744140625 +96484 -0.18450927734375 +96485 -0.190185546875 +96486 -0.2647705078125 +96487 -0.2725830078125 +96488 -0.3333740234375 +96489 -0.343017578125 +96490 -0.354522705078125 +96491 -0.364501953125 +96492 -0.31890869140625 +96493 -0.327423095703125 +96494 -0.270263671875 +96495 -0.277008056640625 +96496 -0.24761962890625 +96497 -0.253570556640625 +96498 -0.2376708984375 +96499 -0.243377685546875 +96500 -0.19354248046875 +96501 -0.197967529296875 +96502 -0.11370849609375 +96503 -0.115753173828125 +96504 -0.036407470703125 +96505 -0.036285400390625 +96506 0.033477783203125 +96507 0.03546142578125 +96508 0.0885009765625 +96509 0.091827392578125 +96510 0.10601806640625 +96511 0.10943603515625 +96512 0.12213134765625 +96513 0.126007080078125 +96514 0.152740478515625 +96515 0.15814208984375 +96516 0.1719970703125 +96517 0.178619384765625 +96518 0.1649169921875 +96519 0.171295166015625 +96520 0.12591552734375 +96521 0.13006591796875 +96522 0.080780029296875 +96523 0.0823974609375 +96524 0.02886962890625 +96525 0.02752685546875 +96526 -0.059173583984375 +96527 -0.06591796875 +96528 -0.147552490234375 +96529 -0.15972900390625 +96530 -0.198455810546875 +96531 -0.2135009765625 +96532 -0.219207763671875 +96533 -0.235107421875 +96534 -0.18743896484375 +96535 -0.200653076171875 +96536 -0.11199951171875 +96537 -0.119598388671875 +96538 -0.023956298828125 +96539 -0.025115966796875 +96540 0.0792236328125 +96541 0.085479736328125 +96542 0.16546630859375 +96543 0.17791748046875 +96544 0.200408935546875 +96545 0.2154541015625 +96546 0.196533203125 +96547 0.21142578125 +96548 0.16265869140625 +96549 0.17529296875 +96550 0.1192626953125 +96551 0.12890625 +96552 0.094329833984375 +96553 0.1021728515625 +96554 0.068756103515625 +96555 0.074676513671875 +96556 0.03997802734375 +96557 0.043701171875 +96558 0.0355224609375 +96559 0.038665771484375 +96560 0.071502685546875 +96561 0.0767822265625 +96562 0.1324462890625 +96563 0.141571044921875 +96564 0.175201416015625 +96565 0.186920166015625 +96566 0.17767333984375 +96567 0.189239501953125 +96568 0.131256103515625 +96569 0.139373779296875 +96570 0.04034423828125 +96571 0.042022705078125 +96572 -0.07305908203125 +96573 -0.07928466796875 +96574 -0.204071044921875 +96575 -0.219329833984375 +96576 -0.343109130859375 +96577 -0.36785888671875 +96578 -0.462188720703125 +96579 -0.4949951171875 +96580 -0.51983642578125 +96581 -0.55645751953125 +96582 -0.4755859375 +96583 -0.509002685546875 +96584 -0.351287841796875 +96585 -0.3759765625 +96586 -0.20489501953125 +96587 -0.21929931640625 +96588 -0.059967041015625 +96589 -0.06414794921875 +96590 0.085113525390625 +96591 0.091156005859375 +96592 0.2200927734375 +96593 0.23565673828125 +96594 0.32000732421875 +96595 0.3426513671875 +96596 0.368743896484375 +96597 0.3948974609375 +96598 0.36322021484375 +96599 0.38909912109375 +96600 0.302276611328125 +96601 0.324005126953125 +96602 0.208587646484375 +96603 0.223907470703125 +96604 0.115264892578125 +96605 0.1241455078125 +96606 0.0338134765625 +96607 0.037017822265625 +96608 -0.0101318359375 +96609 -0.010101318359375 +96610 -0.018646240234375 +96611 -0.019378662109375 +96612 -0.02154541015625 +96613 -0.022674560546875 +96614 -0.00140380859375 +96615 -0.001373291015625 +96616 0.053009033203125 +96617 0.0565185546875 +96618 0.10040283203125 +96619 0.10693359375 +96620 0.091400146484375 +96621 0.097076416015625 +96622 0.04083251953125 +96623 0.0428466796875 +96624 -0.015899658203125 +96625 -0.017913818359375 +96626 -0.069976806640625 +96627 -0.075775146484375 +96628 -0.11077880859375 +96629 -0.119384765625 +96630 -0.148590087890625 +96631 -0.159698486328125 +96632 -0.188873291015625 +96633 -0.202606201171875 +96634 -0.232086181640625 +96635 -0.248626708984375 +96636 -0.285186767578125 +96637 -0.305206298828125 +96638 -0.338653564453125 +96639 -0.362152099609375 +96640 -0.36627197265625 +96641 -0.391448974609375 +96642 -0.3326416015625 +96643 -0.355316162109375 +96644 -0.234222412109375 +96645 -0.25 +96646 -0.087310791015625 +96647 -0.0928955078125 +96648 0.08282470703125 +96649 0.089019775390625 +96650 0.219573974609375 +96651 0.235198974609375 +96652 0.297760009765625 +96653 0.31878662109375 +96654 0.33502197265625 +96655 0.358612060546875 +96656 0.3248291015625 +96657 0.34771728515625 +96658 0.2667236328125 +96659 0.285614013671875 +96660 0.20831298828125 +96661 0.22314453125 +96662 0.18365478515625 +96663 0.19671630859375 +96664 0.167938232421875 +96665 0.1798095703125 +96666 0.14532470703125 +96667 0.155517578125 +96668 0.141448974609375 +96669 0.15118408203125 +96670 0.147003173828125 +96671 0.15692138671875 +96672 0.12359619140625 +96673 0.131744384765625 +96674 0.0947265625 +96675 0.10076904296875 +96676 0.082000732421875 +96677 0.08709716796875 +96678 0.051849365234375 +96679 0.054840087890625 +96680 -0.007904052734375 +96681 -0.009033203125 +96682 -0.0968017578125 +96683 -0.104034423828125 +96684 -0.214202880859375 +96685 -0.22943115234375 +96686 -0.33233642578125 +96687 -0.355560302734375 +96688 -0.41326904296875 +96689 -0.44195556640625 +96690 -0.4432373046875 +96691 -0.473876953125 +96692 -0.43487548828125 +96693 -0.46484375 +96694 -0.392181396484375 +96695 -0.41912841796875 +96696 -0.31292724609375 +96697 -0.3343505859375 +96698 -0.213409423828125 +96699 -0.22796630859375 +96700 -0.115692138671875 +96701 -0.123504638671875 +96702 -0.026031494140625 +96703 -0.027679443359375 +96704 0.072540283203125 +96705 0.07763671875 +96706 0.199462890625 +96707 0.213226318359375 +96708 0.363861083984375 +96709 0.388824462890625 +96710 0.54541015625 +96711 0.582763671875 +96712 0.68701171875 +96713 0.7340087890625 +96714 0.748931884765625 +96715 0.80010986328125 +96716 0.72857666015625 +96717 0.778289794921875 +96718 0.622711181640625 +96719 0.665130615234375 +96720 0.430419921875 +96721 0.459625244140625 +96722 0.186676025390625 +96723 0.199188232421875 +96724 -0.04718017578125 +96725 -0.0506591796875 +96726 -0.2177734375 +96727 -0.23291015625 +96728 -0.3087158203125 +96729 -0.330078125 +96730 -0.344512939453125 +96731 -0.36834716796875 +96732 -0.3543701171875 +96733 -0.378875732421875 +96734 -0.3525390625 +96735 -0.376922607421875 +96736 -0.355133056640625 +96737 -0.379638671875 +96738 -0.366241455078125 +96739 -0.391448974609375 +96740 -0.36053466796875 +96741 -0.385284423828125 +96742 -0.3199462890625 +96743 -0.34185791015625 +96744 -0.2647705078125 +96745 -0.2828369140625 +96746 -0.235565185546875 +96747 -0.251556396484375 +96748 -0.24920654296875 +96749 -0.266082763671875 +96750 -0.2559814453125 +96751 -0.273284912109375 +96752 -0.20306396484375 +96753 -0.21673583984375 +96754 -0.12017822265625 +96755 -0.128204345703125 +96756 -0.063873291015625 +96757 -0.068084716796875 +96758 -0.040374755859375 +96759 -0.04302978515625 +96760 -0.02288818359375 +96761 -0.024383544921875 +96762 0.019439697265625 +96763 0.020782470703125 +96764 0.116607666015625 +96765 0.124542236328125 +96766 0.24151611328125 +96767 0.2579345703125 +96768 0.3544921875 +96769 0.379150390625 +96770 0.447967529296875 +96771 0.47991943359375 +96772 0.4932861328125 +96773 0.528167724609375 +96774 0.4786376953125 +96775 0.5111083984375 +96776 0.42877197265625 +96777 0.4561767578125 +96778 0.383544921875 +96779 0.407440185546875 +96780 0.36004638671875 +96781 0.38372802734375 +96782 0.332916259765625 +96783 0.356842041015625 +96784 0.288787841796875 +96785 0.311798095703125 +96786 0.229888916015625 +96787 0.2508544921875 +96788 0.148681640625 +96789 0.165374755859375 +96790 0.027191162109375 +96791 0.03521728515625 +96792 -0.1365966796875 +96793 -0.14208984375 +96794 -0.3145751953125 +96795 -0.335662841796875 +96796 -0.4967041015625 +96797 -0.534576416015625 +96798 -0.667572021484375 +96799 -0.721893310546875 +96800 -0.772003173828125 +96801 -0.836669921875 +96802 -0.76812744140625 +96803 -0.8326416015625 +96804 -0.6739501953125 +96805 -0.7296142578125 +96806 -0.5391845703125 +96807 -0.582550048828125 +96808 -0.407958984375 +96809 -0.440093994140625 +96810 -0.30035400390625 +96811 -0.324310302734375 +96812 -0.18609619140625 +96813 -0.20147705078125 +96814 -0.04095458984375 +96815 -0.044647216796875 +96816 0.096710205078125 +96817 0.103973388671875 +96818 0.188751220703125 +96819 0.202392578125 +96820 0.24755859375 +96821 0.264495849609375 +96822 0.31695556640625 +96823 0.338897705078125 +96824 0.41326904296875 +96825 0.443817138671875 +96826 0.505584716796875 +96827 0.545074462890625 +96828 0.5709228515625 +96829 0.6173095703125 +96830 0.60205078125 +96831 0.6524658203125 +96832 0.610626220703125 +96833 0.66339111328125 +96834 0.602203369140625 +96835 0.6561279296875 +96836 0.555267333984375 +96837 0.606781005859375 +96838 0.457183837890625 +96839 0.501190185546875 +96840 0.32025146484375 +96841 0.352783203125 +96842 0.15814208984375 +96843 0.176544189453125 +96844 -0.035552978515625 +96845 -0.034820556640625 +96846 -0.23980712890625 +96847 -0.258209228515625 +96848 -0.40826416015625 +96849 -0.44244384765625 +96850 -0.529754638671875 +96851 -0.5753173828125 +96852 -0.59991455078125 +96853 -0.65203857421875 +96854 -0.590728759765625 +96855 -0.641632080078125 +96856 -0.518524169921875 +96857 -0.562164306640625 +96858 -0.423492431640625 +96859 -0.458038330078125 +96860 -0.32489013671875 +96861 -0.350555419921875 +96862 -0.24163818359375 +96863 -0.260528564453125 +96864 -0.177642822265625 +96865 -0.192108154296875 +96866 -0.1300048828125 +96867 -0.141937255859375 +96868 -0.091766357421875 +96869 -0.1021728515625 +96870 -0.0540771484375 +96871 -0.062896728515625 +96872 -0.006011962890625 +96873 -0.011932373046875 +96874 0.063262939453125 +96875 0.062835693359375 +96876 0.142181396484375 +96877 0.148712158203125 +96878 0.227081298828125 +96879 0.241729736328125 +96880 0.324493408203125 +96881 0.34912109375 +96882 0.422119140625 +96883 0.457305908203125 +96884 0.499725341796875 +96885 0.54388427734375 +96886 0.524871826171875 +96887 0.5728759765625 +96888 0.463531494140625 +96889 0.506591796875 +96890 0.321441650390625 +96891 0.351226806640625 +96892 0.13458251953125 +96893 0.146514892578125 +96894 -0.0496826171875 +96895 -0.05523681640625 +96896 -0.19708251953125 +96897 -0.21624755859375 +96898 -0.3060302734375 +96899 -0.334930419921875 +96900 -0.368988037109375 +96901 -0.402984619140625 +96902 -0.404754638671875 +96903 -0.4412841796875 +96904 -0.454803466796875 +96905 -0.49578857421875 +96906 -0.513397216796875 +96907 -0.5601806640625 +96908 -0.550018310546875 +96909 -0.600738525390625 +96910 -0.53466796875 +96911 -0.584228515625 +96912 -0.43902587890625 +96913 -0.47930908203125 +96914 -0.2572021484375 +96915 -0.27935791015625 +96916 -0.011444091796875 +96917 -0.0089111328125 +96918 0.240997314453125 +96919 0.268798828125 +96920 0.435943603515625 +96921 0.482818603515625 +96922 0.54669189453125 +96923 0.60369873046875 +96924 0.59027099609375 +96925 0.650421142578125 +96926 0.603729248046875 +96927 0.66400146484375 +96928 0.584320068359375 +96929 0.6414794921875 +96930 0.522705078125 +96931 0.572540283203125 +96932 0.455841064453125 +96933 0.498138427734375 +96934 0.402862548828125 +96935 0.439453125 +96936 0.3448486328125 +96937 0.375518798828125 +96938 0.253021240234375 +96939 0.274505615234375 +96940 0.1024169921875 +96941 0.1087646484375 +96942 -0.086761474609375 +96943 -0.099395751953125 +96944 -0.28570556640625 +96945 -0.3182373046875 +96946 -0.495452880859375 +96947 -0.5489501953125 +96948 -0.69989013671875 +96949 -0.7738037109375 +96950 -0.851104736328125 +96951 -0.86383056640625 +96952 -0.861541748046875 +96953 -0.870391845703125 +96954 -0.861602783203125 +96955 -0.86895751953125 +96956 -0.8555908203125 +96957 -0.861053466796875 +96958 -0.738067626953125 +96959 -0.765869140625 +96960 -0.53033447265625 +96961 -0.5301513671875 +96962 -0.247589111328125 +96963 -0.214691162109375 +96964 0.071197509765625 +96965 0.137359619140625 +96966 0.379638671875 +96967 0.474822998046875 +96968 0.64556884765625 +96969 0.76239013671875 +96970 0.844512939453125 +96971 0.867462158203125 +96972 0.867828369140625 +96973 0.870361328125 +96974 0.870361328125 +96975 0.86480712890625 +96976 0.865264892578125 +96977 0.831817626953125 +96978 0.85516357421875 +96979 0.677581787109375 +96980 0.7283935546875 +96981 0.495880126953125 +96982 0.573974609375 +96983 0.30767822265625 +96984 0.4000244140625 +96985 0.116180419921875 +96986 0.177978515625 +96987 -0.110748291015625 +96988 -0.098602294921875 +96989 -0.381805419921875 +96990 -0.39166259765625 +96991 -0.6572265625 +96992 -0.647979736328125 +96993 -0.857421875 +96994 -0.829864501953125 +96995 -0.870391845703125 +96996 -0.86297607421875 +96997 -0.870391845703125 +96998 -0.8682861328125 +96999 -0.86444091796875 +97000 -0.870391845703125 +97001 -0.85723876953125 +97002 -0.86871337890625 +97003 -0.790008544921875 +97004 -0.858123779296875 +97005 -0.62847900390625 +97006 -0.7071533203125 +97007 -0.3956298828125 +97008 -0.474212646484375 +97009 -0.126708984375 +97010 -0.214202880859375 +97011 0.150115966796875 +97012 0.061981201171875 +97013 0.424041748046875 +97014 0.33013916015625 +97015 0.670623779296875 +97016 0.555816650390625 +97017 0.854522705078125 +97018 0.723907470703125 +97019 0.866485595703125 +97020 0.821685791015625 +97021 0.86920166015625 +97022 0.8558349609375 +97023 0.8653564453125 +97024 0.8565673828125 +97025 0.857147216796875 +97026 0.840728759765625 +97027 0.766845703125 +97028 0.77374267578125 +97029 0.628509521484375 +97030 0.66845703125 +97031 0.462127685546875 +97032 0.548797607421875 +97033 0.297210693359375 +97034 0.4268798828125 +97035 0.14862060546875 +97036 0.283782958984375 +97037 -0.00537109375 +97038 0.126739501953125 +97039 -0.15753173828125 +97040 -0.046966552734375 +97041 -0.31304931640625 +97042 -0.249542236328125 +97043 -0.48876953125 +97044 -0.440399169921875 +97045 -0.6416015625 +97046 -0.59857177734375 +97047 -0.751373291015625 +97048 -0.745025634765625 +97049 -0.84619140625 +97050 -0.855987548828125 +97051 -0.861297607421875 +97052 -0.863800048828125 +97053 -0.863250732421875 +97054 -0.863189697265625 +97055 -0.856597900390625 +97056 -0.855438232421875 +97057 -0.7498779296875 +97058 -0.778289794921875 +97059 -0.624542236328125 +97060 -0.661590576171875 +97061 -0.47808837890625 +97062 -0.462982177734375 +97063 -0.253387451171875 +97064 -0.222991943359375 +97065 0.003692626953125 +97066 -0.00164794921875 +97067 0.2257080078125 +97068 0.2117919921875 +97069 0.427154541015625 +97070 0.445648193359375 +97071 0.643218994140625 +97072 0.691864013671875 +97073 0.855926513671875 +97074 0.8594970703125 +97075 0.870361328125 +97076 0.870361328125 +97077 0.870361328125 +97078 0.870361328125 +97079 0.862762451171875 +97080 0.8629150390625 +97081 0.79669189453125 +97082 0.790863037109375 +97083 0.595794677734375 +97084 0.6055908203125 +97085 0.362152099609375 +97086 0.402740478515625 +97087 0.1270751953125 +97088 0.2022705078125 +97089 -0.086944580078125 +97090 0.006622314453125 +97091 -0.2784423828125 +97092 -0.214813232421875 +97093 -0.484832763671875 +97094 -0.4798583984375 +97095 -0.729583740234375 +97096 -0.7462158203125 +97097 -0.86688232421875 +97098 -0.86614990234375 +97099 -0.870391845703125 +97100 -0.870391845703125 +97101 -0.86859130859375 +97102 -0.870147705078125 +97103 -0.86279296875 +97104 -0.863006591796875 +97105 -0.817962646484375 +97106 -0.77215576171875 +97107 -0.6116943359375 +97108 -0.5177001953125 +97109 -0.3128662109375 +97110 -0.203094482421875 +97111 0.039398193359375 +97112 0.15142822265625 +97113 0.422821044921875 +97114 0.5162353515625 +97115 0.805145263671875 +97116 0.83343505859375 +97117 0.870361328125 +97118 0.870361328125 +97119 0.870361328125 +97120 0.870361328125 +97121 0.860015869140625 +97122 0.860992431640625 +97123 0.727935791015625 +97124 0.75042724609375 +97125 0.48114013671875 +97126 0.542449951171875 +97127 0.2059326171875 +97128 0.320953369140625 +97129 -0.06103515625 +97130 0.1038818359375 +97131 -0.29913330078125 +97132 -0.114471435546875 +97133 -0.516204833984375 +97134 -0.343231201171875 +97135 -0.7252197265625 +97136 -0.55914306640625 +97137 -0.85980224609375 +97138 -0.733428955078125 +97139 -0.870391845703125 +97140 -0.844024658203125 +97141 -0.870391845703125 +97142 -0.8544921875 +97143 -0.858062744140625 +97144 -0.769134521484375 +97145 -0.673004150390625 +97146 -0.64306640625 +97147 -0.42694091796875 +97148 -0.52520751953125 +97149 -0.2100830078125 +97150 -0.424163818359375 +97151 -0.0362548828125 +97152 -0.324798583984375 +97153 0.10943603515625 +97154 -0.219085693359375 +97155 0.23516845703125 +97156 -0.078948974609375 +97157 0.373687744140625 +97158 0.087554931640625 +97159 0.517791748046875 +97160 0.221160888671875 +97161 0.602783203125 +97162 0.32427978515625 +97163 0.635711669921875 +97164 0.42608642578125 +97165 0.655181884765625 +97166 0.5201416015625 +97167 0.65948486328125 +97168 0.603668212890625 +97169 0.651275634765625 +97170 0.661163330078125 +97171 0.61846923828125 +97172 0.667572021484375 +97173 0.53753662109375 +97174 0.615203857421875 +97175 0.404144287109375 +97176 0.5040283203125 +97177 0.22186279296875 +97178 0.343505859375 +97179 0.003997802734375 +97180 0.157379150390625 +97181 -0.22100830078125 +97182 -0.02935791015625 +97183 -0.42449951171875 +97184 -0.192413330078125 +97185 -0.579833984375 +97186 -0.2904052734375 +97187 -0.641876220703125 +97188 -0.326690673828125 +97189 -0.6177978515625 +97190 -0.357025146484375 +97191 -0.575531005859375 +97192 -0.387298583984375 +97193 -0.526336669921875 +97194 -0.37518310546875 +97195 -0.42645263671875 +97196 -0.30108642578125 +97197 -0.2581787109375 +97198 -0.202239990234375 +97199 -0.068695068359375 +97200 -0.11859130859375 +97201 0.09222412109375 +97202 -0.040740966796875 +97203 0.232147216796875 +97204 0.033233642578125 +97205 0.3509521484375 +97206 0.07086181640625 +97207 0.410064697265625 +97208 0.040618896484375 +97209 0.372955322265625 +97210 -0.044189453125 +97211 0.2554931640625 +97212 -0.14190673828125 +97213 0.10711669921875 +97214 -0.23785400390625 +97215 -0.052886962890625 +97216 -0.3013916015625 +97217 -0.186279296875 +97218 -0.283233642578125 +97219 -0.23291015625 +97220 -0.20123291015625 +97221 -0.209442138671875 +97222 -0.10968017578125 +97223 -0.174163818359375 +97224 -0.011566162109375 +97225 -0.126739501953125 +97226 0.106658935546875 +97227 -0.048126220703125 +97228 0.225921630859375 +97229 0.0426025390625 +97230 0.311187744140625 +97231 0.10748291015625 +97232 0.35638427734375 +97233 0.1409912109375 +97234 0.4080810546875 +97235 0.19708251953125 +97236 0.464691162109375 +97237 0.273651123046875 +97238 0.48089599609375 +97239 0.31768798828125 +97240 0.4686279296875 +97241 0.341094970703125 +97242 0.4510498046875 +97243 0.368011474609375 +97244 0.407989501953125 +97245 0.37249755859375 +97246 0.29522705078125 +97247 0.30072021484375 +97248 0.11474609375 +97249 0.1517333984375 +97250 -0.07855224609375 +97251 -0.01470947265625 +97252 -0.27313232421875 +97253 -0.1883544921875 +97254 -0.469879150390625 +97255 -0.372711181640625 +97256 -0.620147705078125 +97257 -0.51397705078125 +97258 -0.687469482421875 +97259 -0.57177734375 +97260 -0.66546630859375 +97261 -0.53948974609375 +97262 -0.569793701171875 +97263 -0.43511962890625 +97264 -0.433807373046875 +97265 -0.2962646484375 +97266 -0.2918701171875 +97267 -0.161102294921875 +97268 -0.15771484375 +97269 -0.0435791015625 +97270 -0.029754638671875 +97271 0.060394287109375 +97272 0.07745361328125 +97273 0.13665771484375 +97274 0.148468017578125 +97275 0.170135498046875 +97276 0.185089111328125 +97277 0.16552734375 +97278 0.21514892578125 +97279 0.15728759765625 +97280 0.241607666015625 +97281 0.150787353515625 +97282 0.241943359375 +97283 0.12200927734375 +97284 0.222625732421875 +97285 0.080108642578125 +97286 0.205413818359375 +97287 0.05126953125 +97288 0.213592529296875 +97289 0.062896728515625 +97290 0.2286376953125 +97291 0.09271240234375 +97292 0.2108154296875 +97293 0.092987060546875 +97294 0.1739501953125 +97295 0.07855224609375 +97296 0.132232666015625 +97297 0.06427001953125 +97298 0.0743408203125 +97299 0.0347900390625 +97300 0.000518798828125 +97301 -0.01171875 +97302 -0.070953369140625 +97303 -0.056060791015625 +97304 -0.10198974609375 +97305 -0.055511474609375 +97306 -0.09124755859375 +97307 -0.010467529296875 +97308 -0.083221435546875 +97309 0.02508544921875 +97310 -0.0985107421875 +97311 0.025665283203125 +97312 -0.11431884765625 +97313 0.017333984375 +97314 -0.128875732421875 +97315 0.00189208984375 +97316 -0.151702880859375 +97317 -0.03173828125 +97318 -0.17315673828125 +97319 -0.071502685546875 +97320 -0.209381103515625 +97321 -0.13543701171875 +97322 -0.25848388671875 +97323 -0.219970703125 +97324 -0.30096435546875 +97325 -0.300506591796875 +97326 -0.337677001953125 +97327 -0.376312255859375 +97328 -0.343597412109375 +97329 -0.416107177734375 +97330 -0.278778076171875 +97331 -0.371124267578125 +97332 -0.145416259765625 +97333 -0.242279052734375 +97334 0.021087646484375 +97335 -0.069732666015625 +97336 0.201995849609375 +97337 0.125640869140625 +97338 0.370208740234375 +97339 0.31268310546875 +97340 0.494476318359375 +97341 0.45501708984375 +97342 0.57659912109375 +97343 0.554779052734375 +97344 0.615753173828125 +97345 0.61065673828125 +97346 0.602630615234375 +97347 0.610931396484375 +97348 0.517578125 +97349 0.531463623046875 +97350 0.37530517578125 +97351 0.3883056640625 +97352 0.22222900390625 +97353 0.23468017578125 +97354 0.08062744140625 +97355 0.095245361328125 +97356 -0.026092529296875 +97357 -0.00396728515625 +97358 -0.08447265625 +97359 -0.04852294921875 +97360 -0.107635498046875 +97361 -0.055145263671875 +97362 -0.138916015625 +97363 -0.0758056640625 +97364 -0.20166015625 +97365 -0.138702392578125 +97366 -0.266021728515625 +97367 -0.209197998046875 +97368 -0.3333740234375 +97369 -0.289031982421875 +97370 -0.404449462890625 +97371 -0.37884521484375 +97372 -0.460662841796875 +97373 -0.456329345703125 +97374 -0.4984130859375 +97375 -0.51641845703125 +97376 -0.484649658203125 +97377 -0.519287109375 +97378 -0.4146728515625 +97379 -0.458251953125 +97380 -0.33331298828125 +97381 -0.384796142578125 +97382 -0.26263427734375 +97383 -0.323699951171875 +97384 -0.198822021484375 +97385 -0.269287109375 +97386 -0.12042236328125 +97387 -0.1951904296875 +97388 -0.027008056640625 +97389 -0.100006103515625 +97390 0.0579833984375 +97391 -0.01055908203125 +97392 0.159881591796875 +97393 0.1033935546875 +97394 0.28466796875 +97395 0.24908447265625 +97396 0.387115478515625 +97397 0.373199462890625 +97398 0.452484130859375 +97399 0.45806884765625 +97400 0.48785400390625 +97401 0.511474609375 +97402 0.52105712890625 +97403 0.565399169921875 +97404 0.545684814453125 +97405 0.61138916015625 +97406 0.511810302734375 +97407 0.5897216796875 +97408 0.411956787109375 +97409 0.4906005859375 +97410 0.2618408203125 +97411 0.33148193359375 +97412 0.09234619140625 +97413 0.147796630859375 +97414 -0.06036376953125 +97415 -0.01873779296875 +97416 -0.172088623046875 +97417 -0.140289306640625 +97418 -0.221282958984375 +97419 -0.191986083984375 +97420 -0.2166748046875 +97421 -0.184295654296875 +97422 -0.196197509765625 +97423 -0.161834716796875 +97424 -0.1956787109375 +97425 -0.166595458984375 +97426 -0.21148681640625 +97427 -0.19390869140625 +97428 -0.227691650390625 +97429 -0.22442626953125 +97430 -0.26324462890625 +97431 -0.279754638671875 +97432 -0.301055908203125 +97433 -0.3389892578125 +97434 -0.30126953125 +97435 -0.3543701171875 +97436 -0.28350830078125 +97437 -0.348175048828125 +97438 -0.253173828125 +97439 -0.32598876953125 +97440 -0.185699462890625 +97441 -0.2581787109375 +97442 -0.077362060546875 +97443 -0.139801025390625 +97444 0.05914306640625 +97445 0.014617919921875 +97446 0.171966552734375 +97447 0.144378662109375 +97448 0.236907958984375 +97449 0.221038818359375 +97450 0.276214599609375 +97451 0.27069091796875 +97452 0.290740966796875 +97453 0.294036865234375 +97454 0.298431396484375 +97455 0.311767578125 +97456 0.31268310546875 +97457 0.339141845703125 +97458 0.320404052734375 +97459 0.360260009765625 +97460 0.309783935546875 +97461 0.360504150390625 +97462 0.2550048828125 +97463 0.308380126953125 +97464 0.1380615234375 +97465 0.18170166015625 +97466 -0.019989013671875 +97467 0.0047607421875 +97468 -0.1793212890625 +97469 -0.17559814453125 +97470 -0.301727294921875 +97471 -0.3143310546875 +97472 -0.350311279296875 +97473 -0.36785888671875 +97474 -0.3470458984375 +97475 -0.36248779296875 +97476 -0.329986572265625 +97477 -0.343536376953125 +97478 -0.2916259765625 +97479 -0.3018798828125 +97480 -0.227081298828125 +97481 -0.231414794921875 +97482 -0.12451171875 +97483 -0.117645263671875 +97484 -0.011505126953125 +97485 0.007049560546875 +97486 0.06549072265625 +97487 0.087982177734375 +97488 0.117950439453125 +97489 0.13946533203125 +97490 0.156097412109375 +97491 0.17425537109375 +97492 0.175933837890625 +97493 0.188201904296875 +97494 0.1685791015625 +97495 0.171234130859375 +97496 0.12957763671875 +97497 0.118438720703125 +97498 0.081573486328125 +97499 0.05706787109375 +97500 0.026214599609375 +97501 -0.010711669921875 +97502 -0.041961669921875 +97503 -0.0914306640625 +97504 -0.103759765625 +97505 -0.162322998046875 +97506 -0.134796142578125 +97507 -0.194549560546875 +97508 -0.102203369140625 +97509 -0.1492919921875 +97510 -0.00152587890625 +97511 -0.02166748046875 +97512 0.1136474609375 +97513 0.124053955078125 +97514 0.17926025390625 +97515 0.211151123046875 +97516 0.196441650390625 +97517 0.240447998046875 +97518 0.191009521484375 +97519 0.242218017578125 +97520 0.171112060546875 +97521 0.2257080078125 +97522 0.139923095703125 +97523 0.194366455078125 +97524 0.070220947265625 +97525 0.115509033203125 +97526 -0.017913818359375 +97527 0.0128173828125 +97528 -0.074127197265625 +97529 -0.053802490234375 +97530 -0.12054443359375 +97531 -0.110626220703125 +97532 -0.192413330078125 +97533 -0.199493408203125 +97534 -0.26806640625 +97535 -0.29437255859375 +97536 -0.295135498046875 +97537 -0.33221435546875 +97538 -0.246734619140625 +97539 -0.27972412109375 +97540 -0.162811279296875 +97541 -0.185333251953125 +97542 -0.108062744140625 +97543 -0.128204345703125 +97544 -0.089111328125 +97545 -0.115692138671875 +97546 -0.081298828125 +97547 -0.116455078125 +97548 -0.06536865234375 +97549 -0.105926513671875 +97550 -0.017364501953125 +97551 -0.053955078125 +97552 0.06988525390625 +97553 0.048797607421875 +97554 0.159881591796875 +97555 0.157318115234375 +97556 0.204376220703125 +97557 0.212005615234375 +97558 0.207977294921875 +97559 0.218475341796875 +97560 0.219757080078125 +97561 0.23724365234375 +97562 0.2698974609375 +97563 0.30535888671875 +97564 0.32513427734375 +97565 0.38128662109375 +97566 0.3369140625 +97567 0.404449462890625 +97568 0.32147216796875 +97569 0.3944091796875 +97570 0.3094482421875 +97571 0.3885498046875 +97572 0.281707763671875 +97573 0.362640380859375 +97574 0.203765869140625 +97575 0.27362060546875 +97576 0.072418212890625 +97577 0.11712646484375 +97578 -0.070098876953125 +97579 -0.054901123046875 +97580 -0.181915283203125 +97581 -0.19085693359375 +97582 -0.258941650390625 +97583 -0.28570556640625 +97584 -0.30108642578125 +97585 -0.339263916015625 +97586 -0.329437255859375 +97587 -0.3775634765625 +97588 -0.380645751953125 +97589 -0.445709228515625 +97590 -0.447998046875 +97591 -0.535064697265625 +97592 -0.51837158203125 +97593 -0.629058837890625 +97594 -0.567779541015625 +97595 -0.697601318359375 +97596 -0.56683349609375 +97597 -0.70391845703125 +97598 -0.51141357421875 +97599 -0.6424560546875 +97600 -0.384063720703125 +97601 -0.491241455078125 +97602 -0.197479248046875 +97603 -0.265716552734375 +97604 0.0013427734375 +97605 -0.023712158203125 +97606 0.185577392578125 +97607 0.201751708984375 +97608 0.326995849609375 +97609 0.375823974609375 +97610 0.414764404296875 +97611 0.485076904296875 +97612 0.480712890625 +97613 0.56884765625 +97614 0.5311279296875 +97615 0.634765625 +97616 0.529693603515625 +97617 0.63763427734375 +97618 0.4674072265625 +97619 0.5660400390625 +97620 0.3865966796875 +97621 0.4720458984375 +97622 0.328948974609375 +97623 0.40692138671875 +97624 0.300537109375 +97625 0.3778076171875 +97626 0.29534912109375 +97627 0.376953125 +97628 0.287445068359375 +97629 0.371978759765625 +97630 0.236846923828125 +97631 0.313140869140625 +97632 0.1307373046875 +97633 0.184417724609375 +97634 -0.010223388671875 +97635 0.011199951171875 +97636 -0.157379150390625 +97637 -0.171051025390625 +97638 -0.290618896484375 +97639 -0.33740234375 +97640 -0.397216796875 +97641 -0.47198486328125 +97642 -0.465728759765625 +97643 -0.560394287109375 +97644 -0.478485107421875 +97645 -0.58056640625 +97646 -0.447845458984375 +97647 -0.54754638671875 +97648 -0.412200927734375 +97649 -0.508575439453125 +97650 -0.368438720703125 +97651 -0.459503173828125 +97652 -0.311981201171875 +97653 -0.394378662109375 +97654 -0.27484130859375 +97655 -0.35260009765625 +97656 -0.239044189453125 +97657 -0.31170654296875 +97658 -0.14471435546875 +97659 -0.197418212890625 +97660 0.00946044921875 +97661 -0.007965087890625 +97662 0.1837158203125 +97663 0.207489013671875 +97664 0.345977783203125 +97665 0.409210205078125 +97666 0.47601318359375 +97667 0.57208251953125 +97668 0.549560546875 +97669 0.66595458984375 +97670 0.540863037109375 +97671 0.65875244140625 +97672 0.463836669921875 +97673 0.56744384765625 +97674 0.3504638671875 +97675 0.431396484375 +97676 0.236358642578125 +97677 0.29443359375 +97678 0.14263916015625 +97679 0.182464599609375 +97680 0.04376220703125 +97681 0.06365966796875 +97682 -0.0714111328125 +97683 -0.075958251953125 +97684 -0.16485595703125 +97685 -0.189422607421875 +97686 -0.23260498046875 +97687 -0.271942138671875 +97688 -0.28997802734375 +97689 -0.342529296875 +97690 -0.307098388671875 +97691 -0.364166259765625 +97692 -0.276214599609375 +97693 -0.327239990234375 +97694 -0.233917236328125 +97695 -0.2769775390625 +97696 -0.212921142578125 +97697 -0.253692626953125 +97698 -0.20220947265625 +97699 -0.24365234375 +97700 -0.162811279296875 +97701 -0.1983642578125 +97702 -0.093597412109375 +97703 -0.116241455078125 +97704 -0.026641845703125 +97705 -0.036834716796875 +97706 0.033843994140625 +97707 0.034881591796875 +97708 0.08154296875 +97709 0.09124755859375 +97710 0.09747314453125 +97711 0.10888671875 +97712 0.112030029296875 +97713 0.125518798828125 +97714 0.1385498046875 +97715 0.15771484375 +97716 0.155029296875 +97717 0.17828369140625 +97718 0.148468017578125 +97719 0.17108154296875 +97720 0.113983154296875 +97721 0.129974365234375 +97722 0.073822021484375 +97723 0.082427978515625 +97724 0.02752685546875 +97725 0.027679443359375 +97726 -0.050140380859375 +97727 -0.065643310546875 +97728 -0.128173828125 +97729 -0.15936279296875 +97730 -0.173828125 +97731 -0.21307373046875 +97732 -0.193359375 +97733 -0.234649658203125 +97734 -0.1673583984375 +97735 -0.2001953125 +97736 -0.103363037109375 +97737 -0.119171142578125 +97738 -0.02813720703125 +97739 -0.024749755859375 +97740 0.060577392578125 +97741 0.085784912109375 +97742 0.135101318359375 +97743 0.178131103515625 +97744 0.165771484375 +97745 0.215576171875 +97746 0.163299560546875 +97747 0.211456298828125 +97748 0.13525390625 +97749 0.17523193359375 +97750 0.099212646484375 +97751 0.128753662109375 +97752 0.079254150390625 +97753 0.1019287109375 +97754 0.058807373046875 +97755 0.0743408203125 +97756 0.035552978515625 +97757 0.04327392578125 +97758 0.033203125 +97759 0.038177490234375 +97760 0.065582275390625 +97761 0.076263427734375 +97762 0.119293212890625 +97763 0.14105224609375 +97764 0.157012939453125 +97765 0.186431884765625 +97766 0.15960693359375 +97767 0.188812255859375 +97768 0.11962890625 +97769 0.1390380859375 +97770 0.040863037109375 +97771 0.041778564453125 +97772 -0.0576171875 +97773 -0.079437255859375 +97774 -0.17156982421875 +97775 -0.219390869140625 +97776 -0.29266357421875 +97777 -0.367828369140625 +97778 -0.396697998046875 +97779 -0.494873046875 +97780 -0.447784423828125 +97781 -0.556243896484375 +97782 -0.410919189453125 +97783 -0.508697509765625 +97784 -0.304901123046875 +97785 -0.3756103515625 +97786 -0.179656982421875 +97787 -0.218902587890625 +97788 -0.05548095703125 +97789 -0.063751220703125 +97790 0.06903076171875 +97791 0.091552734375 +97792 0.18499755859375 +97793 0.23602294921875 +97794 0.27093505859375 +97795 0.342987060546875 +97796 0.313232421875 +97797 0.39520263671875 +97798 0.309539794921875 +97799 0.389373779296875 +97800 0.259063720703125 +97801 0.324249267578125 +97802 0.180816650390625 +97803 0.224090576171875 +97804 0.1024169921875 +97805 0.124267578125 +97806 0.033538818359375 +97807 0.037078857421875 +97808 -0.004425048828125 +97809 -0.010101318359375 +97810 -0.013092041015625 +97811 -0.019439697265625 +97812 -0.017059326171875 +97813 -0.022796630859375 +97814 -0.0018310546875 +97815 -0.001556396484375 +97816 0.0419921875 +97817 0.056304931640625 +97818 0.080230712890625 +97819 0.106719970703125 +97820 0.07196044921875 +97821 0.096893310546875 +97822 0.029510498046875 +97823 0.042694091796875 +97824 -0.017791748046875 +97825 -0.018035888671875 +97826 -0.062591552734375 +97827 -0.07586669921875 +97828 -0.096099853515625 +97829 -0.11944580078125 +97830 -0.12689208984375 +97831 -0.15972900390625 +97832 -0.1595458984375 +97833 -0.202606201171875 +97834 -0.194488525390625 +97835 -0.24859619140625 +97836 -0.237548828125 +97837 -0.30517578125 +97838 -0.280853271484375 +97839 -0.36212158203125 +97840 -0.302734375 +97841 -0.39141845703125 +97842 -0.273895263671875 +97843 -0.35528564453125 +97844 -0.191497802734375 +97845 -0.249969482421875 +97846 -0.069091796875 +97847 -0.092864990234375 +97848 0.0723876953125 +97849 0.08905029296875 +97850 0.185943603515625 +97851 0.2352294921875 +97852 0.250732421875 +97853 0.318817138671875 +97854 0.2813720703125 +97855 0.358642578125 +97856 0.272491455078125 +97857 0.347747802734375 +97858 0.2237548828125 +97859 0.28564453125 +97860 0.174652099609375 +97861 0.223175048828125 +97862 0.1534423828125 +97863 0.196746826171875 +97864 0.139617919921875 +97865 0.179840087890625 +97866 0.120086669921875 +97867 0.155548095703125 +97868 0.116119384765625 +97869 0.151214599609375 +97870 0.12005615234375 +97871 0.156951904296875 +97872 0.10009765625 +97873 0.13177490234375 +97874 0.075775146484375 +97875 0.100799560546875 +97876 0.06500244140625 +97877 0.087127685546875 +97878 0.03997802734375 +97879 0.05487060546875 +97880 -0.009429931640625 +97881 -0.009002685546875 +97882 -0.08282470703125 +97883 -0.10400390625 +97884 -0.1796875 +97885 -0.229400634765625 +97886 -0.27703857421875 +97887 -0.35552978515625 +97888 -0.343505859375 +97889 -0.441925048828125 +97890 -0.367706298828125 +97891 -0.473846435546875 +97892 -0.360137939453125 +97893 -0.464813232421875 +97894 -0.324127197265625 +97895 -0.419097900390625 +97896 -0.25787353515625 +97897 -0.334320068359375 +97898 -0.1749267578125 +97899 -0.227935791015625 +97900 -0.093597412109375 +97901 -0.12347412109375 +97902 -0.019073486328125 +97903 -0.02764892578125 +97904 0.06268310546875 +97905 0.077667236328125 +97906 0.167816162109375 +97907 0.2132568359375 +97908 0.303863525390625 +97909 0.38885498046875 +97910 0.45404052734375 +97911 0.582794189453125 +97912 0.57098388671875 +97913 0.734039306640625 +97914 0.621795654296875 +97915 0.800140380859375 +97916 0.604339599609375 +97917 0.7783203125 +97918 0.5159912109375 +97919 0.6651611328125 +97920 0.35601806640625 +97921 0.45965576171875 +97922 0.1534423828125 +97923 0.199188232421875 +97924 -0.040802001953125 +97925 -0.050689697265625 +97926 -0.1824951171875 +97927 -0.23297119140625 +97928 -0.258056640625 +97929 -0.33013916015625 +97930 -0.287811279296875 +97931 -0.368408203125 +97932 -0.295928955078125 +97933 -0.378936767578125 +97934 -0.294281005859375 +97935 -0.376983642578125 +97936 -0.296173095703125 +97937 -0.37969970703125 +97938 -0.305023193359375 +97939 -0.391510009765625 +97940 -0.29986572265625 +97941 -0.385345458984375 +97942 -0.2657470703125 +97943 -0.3419189453125 +97944 -0.219512939453125 +97945 -0.28289794921875 +97946 -0.194793701171875 +97947 -0.251617431640625 +97948 -0.205657958984375 +97949 -0.266143798828125 +97950 -0.210906982421875 +97951 -0.273345947265625 +97952 -0.166748046875 +97953 -0.216796875 +97954 -0.09783935546875 +97955 -0.128265380859375 +97956 -0.051055908203125 +97957 -0.068145751953125 +97958 -0.031585693359375 +97959 -0.0430908203125 +97960 -0.017181396484375 +97961 -0.024444580078125 +97962 0.0177001953125 +97963 0.020721435546875 +97964 0.097991943359375 +97965 0.124481201171875 +97966 0.201202392578125 +97967 0.25787353515625 +97968 0.294921875 +97969 0.379119873046875 +97970 0.37274169921875 +97971 0.47991943359375 +97972 0.4097900390625 +97973 0.5281982421875 +97974 0.396148681640625 +97975 0.511138916015625 +97976 0.3531494140625 +97977 0.456207275390625 +97978 0.31500244140625 +97979 0.407470703125 +97980 0.296356201171875 +97981 0.383758544921875 +97982 0.27532958984375 +97983 0.35687255859375 +97984 0.240325927734375 +97985 0.31182861328125 +97986 0.19305419921875 +97987 0.250885009765625 +97988 0.1268310546875 +97989 0.1654052734375 +97990 0.026031494140625 +97991 0.035247802734375 +97992 -0.111297607421875 +97993 -0.142059326171875 +97994 -0.261199951171875 +97995 -0.33563232421875 +97996 -0.415191650390625 +97997 -0.5345458984375 +97998 -0.56011962890625 +97999 -0.72186279296875 +98000 -0.648773193359375 +98001 -0.836669921875 +98002 -0.645233154296875 +98003 -0.8326416015625 +98004 -0.56494140625 +98005 -0.7296142578125 +98006 -0.4505615234375 +98007 -0.582550048828125 +98008 -0.339813232421875 +98009 -0.440093994140625 +98010 -0.249847412109375 +98011 -0.324310302734375 +98012 -0.154510498046875 +98013 -0.20147705078125 +98014 -0.032867431640625 +98015 -0.044647216796875 +98016 0.08233642578125 +98017 0.103973388671875 +98018 0.15850830078125 +98019 0.202392578125 +98020 0.2064208984375 +98021 0.264495849609375 +98022 0.263824462890625 +98023 0.338897705078125 +98024 0.3448486328125 +98025 0.443817138671875 +98026 0.42303466796875 +98027 0.545074462890625 +98028 0.478668212890625 +98029 0.6173095703125 +98030 0.50555419921875 +98031 0.6524658203125 +98032 0.513702392578125 +98033 0.66339111328125 +98034 0.5078125 +98035 0.6561279296875 +98036 0.469329833984375 +98037 0.606781005859375 +98038 0.38726806640625 +98039 0.501190185546875 +98040 0.272064208984375 +98041 0.352783203125 +98042 0.135345458984375 +98043 0.176544189453125 +98044 -0.028533935546875 +98045 -0.034820556640625 +98046 -0.201629638671875 +98047 -0.258209228515625 +98048 -0.344451904296875 +98049 -0.44244384765625 +98050 -0.4473876953125 +98051 -0.5753173828125 +98052 -0.50689697265625 +98053 -0.65203857421875 +98054 -0.5 +98055 -0.641632080078125 +98056 -0.440277099609375 +98057 -0.562164306640625 +98058 -0.36090087890625 +98059 -0.458038330078125 +98060 -0.277923583984375 +98061 -0.350555419921875 +98062 -0.20709228515625 +98063 -0.260528564453125 +98064 -0.15179443359375 +98065 -0.192108154296875 +98066 -0.109771728515625 +98067 -0.141937255859375 +98068 -0.075469970703125 +98069 -0.1021728515625 +98070 -0.041748046875 +98071 -0.062896728515625 +98072 0.00018310546875 +98073 -0.011932373046875 +98074 0.059173583984375 +98075 0.062835693359375 +98076 0.125640869140625 +98077 0.148712158203125 +98078 0.19647216796875 +98079 0.241729736328125 +98080 0.277008056640625 +98081 0.34912109375 +98082 0.357177734375 +98083 0.457305908203125 +98084 0.42034912109375 +98085 0.54388427734375 +98086 0.439849853515625 +98087 0.5728759765625 +98088 0.387786865234375 +98089 0.506591796875 +98090 0.268951416015625 +98091 0.351226806640625 +98092 0.11309814453125 +98093 0.146514892578125 +98094 -0.040679931640625 +98095 -0.05523681640625 +98096 -0.1640625 +98097 -0.21624755859375 +98098 -0.255645751953125 +98099 -0.334930419921875 +98100 -0.30908203125 +98101 -0.402984619140625 +98102 -0.33978271484375 +98103 -0.4412841796875 +98104 -0.3818359375 +98105 -0.49578857421875 +98106 -0.43048095703125 +98107 -0.5601806640625 +98108 -0.460601806640625 +98109 -0.600738525390625 +98110 -0.447509765625 +98111 -0.584228515625 +98112 -0.367950439453125 +98113 -0.47930908203125 +98114 -0.21710205078125 +98115 -0.27935791015625 +98116 -0.01336669921875 +98117 -0.0089111328125 +98118 0.196044921875 +98119 0.268798828125 +98120 0.35821533203125 +98121 0.482818603515625 +98122 0.451080322265625 +98123 0.60369873046875 +98124 0.488555908203125 +98125 0.650421142578125 +98126 0.50103759765625 +98127 0.66400146484375 +98128 0.486175537109375 +98129 0.6414794921875 +98130 0.436248779296875 +98131 0.572540283203125 +98132 0.38165283203125 +98133 0.498138427734375 +98134 0.338104248046875 +98135 0.439453125 +98136 0.2900390625 +98137 0.375518798828125 +98138 0.21380615234375 +98139 0.274505615234375 +98140 0.08892822265625 +98141 0.1087646484375 +98142 -0.067901611328125 +98143 -0.099395751953125 +98144 -0.232940673828125 +98145 -0.3182373046875 +98146 -0.406982421875 +98147 -0.5489501953125 +98148 -0.57666015625 +98149 -0.7738037109375 +98150 -0.702423095703125 +98151 -0.86383056640625 +98152 -0.759429931640625 +98153 -0.870391845703125 +98154 -0.760772705078125 +98155 -0.86895751953125 +98156 -0.716156005859375 +98157 -0.861053466796875 +98158 -0.612640380859375 +98159 -0.765869140625 +98160 -0.441802978515625 +98161 -0.5301513671875 +98162 -0.208953857421875 +98163 -0.214691162109375 +98164 0.0538330078125 +98165 0.137359619140625 +98166 0.308349609375 +98167 0.474822998046875 +98168 0.528106689453125 +98169 0.76239013671875 +98170 0.692901611328125 +98171 0.867462158203125 +98172 0.802978515625 +98173 0.870361328125 +98174 0.849609375 +98175 0.86480712890625 +98176 0.836669921875 +98177 0.831817626953125 +98178 0.78216552734375 +98179 0.677581787109375 +98180 0.690338134765625 +98181 0.495880126953125 +98182 0.574920654296875 +98183 0.30767822265625 +98184 0.4375 +98185 0.116180419921875 +98186 0.254425048828125 +98187 -0.110748291015625 +98188 0.02056884765625 +98189 -0.381805419921875 +98190 -0.232208251953125 +98191 -0.6572265625 +98192 -0.459320068359375 +98193 -0.857421875 +98194 -0.62872314453125 +98195 -0.870391845703125 +98196 -0.73504638671875 +98197 -0.870391845703125 +98198 -0.7982177734375 +98199 -0.86444091796875 +98200 -0.84466552734375 +98201 -0.85723876953125 +98202 -0.855194091796875 +98203 -0.790008544921875 +98204 -0.80572509765625 +98205 -0.62847900390625 +98206 -0.677398681640625 +98207 -0.3956298828125 +98208 -0.50006103515625 +98209 -0.126708984375 +98210 -0.294036865234375 +98211 0.150115966796875 +98212 -0.068023681640625 +98213 0.424041748046875 +98214 0.15789794921875 +98215 0.670623779296875 +98216 0.354888916015625 +98217 0.854522705078125 +98218 0.509765625 +98219 0.866485595703125 +98220 0.610992431640625 +98221 0.86920166015625 +98222 0.6719970703125 +98223 0.8653564453125 +98224 0.702667236328125 +98225 0.857147216796875 +98226 0.700714111328125 +98227 0.766845703125 +98228 0.669891357421875 +98229 0.628509521484375 +98230 0.605072021484375 +98231 0.462127685546875 +98232 0.525390625 +98233 0.297210693359375 +98234 0.44000244140625 +98235 0.14862060546875 +98236 0.3319091796875 +98237 -0.00537109375 +98238 0.2066650390625 +98239 -0.15753173828125 +98240 0.06158447265625 +98241 -0.31304931640625 +98242 -0.11370849609375 +98243 -0.48876953125 +98244 -0.2843017578125 +98245 -0.6416015625 +98246 -0.431732177734375 +98247 -0.751373291015625 +98248 -0.573089599609375 +98249 -0.84619140625 +98250 -0.69732666015625 +98251 -0.861297607421875 +98252 -0.779693603515625 +98253 -0.863250732421875 +98254 -0.796600341796875 +98255 -0.856597900390625 +98256 -0.75701904296875 +98257 -0.7498779296875 +98258 -0.703948974609375 +98259 -0.624542236328125 +98260 -0.620941162109375 +98261 -0.47808837890625 +98262 -0.464508056640625 +98263 -0.253387451171875 +98264 -0.268585205078125 +98265 0.003692626953125 +98266 -0.08404541015625 +98267 0.2257080078125 +98268 0.098358154296875 +98269 0.427154541015625 +98270 0.30267333984375 +98271 0.643218994140625 +98272 0.5216064453125 +98273 0.855926513671875 +98274 0.71197509765625 +98275 0.870361328125 +98276 0.836761474609375 +98277 0.870361328125 +98278 0.859588623046875 +98279 0.862762451171875 +98280 0.859771728515625 +98281 0.79669189453125 +98282 0.835174560546875 +98283 0.595794677734375 +98284 0.719207763671875 +98285 0.362152099609375 +98286 0.57598876953125 +98287 0.1270751953125 +98288 0.4212646484375 +98289 -0.086944580078125 +98290 0.256622314453125 +98291 -0.2784423828125 +98292 0.056243896484375 +98293 -0.484832763671875 +98294 -0.19403076171875 +98295 -0.729583740234375 +98296 -0.45648193359375 +98297 -0.86688232421875 +98298 -0.68389892578125 +98299 -0.870391845703125 +98300 -0.856475830078125 +98301 -0.86859130859375 +98302 -0.870391845703125 +98303 -0.86279296875 +98304 -0.870391845703125 +98305 -0.817962646484375 +98306 -0.860198974609375 +98307 -0.6116943359375 +98308 -0.718719482421875 +98309 -0.3128662109375 +98310 -0.463897705078125 +98311 0.039398193359375 +98312 -0.159515380859375 +98313 0.422821044921875 +98314 0.1685791015625 +98315 0.805145263671875 +98316 0.470794677734375 +98317 0.870361328125 +98318 0.706451416015625 +98319 0.870361328125 +98320 0.85595703125 +98321 0.860015869140625 +98322 0.8651123046875 +98323 0.727935791015625 +98324 0.8656005859375 +98325 0.48114013671875 +98326 0.859619140625 +98327 0.2059326171875 +98328 0.8074951171875 +98329 -0.06103515625 +98330 0.684539794921875 +98331 -0.29913330078125 +98332 0.526153564453125 +98333 -0.516204833984375 +98334 0.324798583984375 +98335 -0.7252197265625 +98336 0.101287841796875 +98337 -0.85980224609375 +98338 -0.1173095703125 +98339 -0.870391845703125 +98340 -0.3079833984375 +98341 -0.870391845703125 +98342 -0.434814453125 +98343 -0.858062744140625 +98344 -0.494354248046875 +98345 -0.673004150390625 +98346 -0.52423095703125 +98347 -0.42694091796875 +98348 -0.5570068359375 +98349 -0.2100830078125 +98350 -0.592803955078125 +98351 -0.0362548828125 +98352 -0.613128662109375 +98353 0.10943603515625 +98354 -0.60638427734375 +98355 0.23516845703125 +98356 -0.54595947265625 +98357 0.373687744140625 +98358 -0.4361572265625 +98359 0.517791748046875 +98360 -0.324737548828125 +98361 0.602783203125 +98362 -0.210723876953125 +98363 0.635711669921875 +98364 -0.072723388671875 +98365 0.655181884765625 +98366 0.080322265625 +98367 0.65948486328125 +98368 0.241363525390625 +98369 0.651275634765625 +98370 0.3922119140625 +98371 0.61846923828125 +98372 0.50640869140625 +98373 0.53753662109375 +98374 0.571563720703125 +98375 0.404144287109375 +98376 0.581817626953125 +98377 0.22186279296875 +98378 0.53961181640625 +98379 0.003997802734375 +98380 0.459808349609375 +98381 -0.22100830078125 +98382 0.359344482421875 +98383 -0.42449951171875 +98384 0.255828857421875 +98385 -0.579833984375 +98386 0.18206787109375 +98387 -0.641876220703125 +98388 0.1356201171875 +98389 -0.6177978515625 +98390 0.07257080078125 +98391 -0.575531005859375 +98392 -0.0091552734375 +98393 -0.526336669921875 +98394 -0.071380615234375 +98395 -0.42645263671875 +98396 -0.093719482421875 +98397 -0.2581787109375 +98398 -0.101776123046875 +98399 -0.068695068359375 +98400 -0.123138427734375 +98401 0.09222412109375 +98402 -0.145233154296875 +98403 0.232147216796875 +98404 -0.161895751953125 +98405 0.3509521484375 +98406 -0.1956787109375 +98407 0.410064697265625 +98408 -0.2691650390625 +98409 0.372955322265625 +98410 -0.36932373046875 +98411 0.2554931640625 +98412 -0.4609375 +98413 0.10711669921875 +98414 -0.531951904296875 +98415 -0.052886962890625 +98416 -0.55828857421875 +98417 -0.186279296875 +98418 -0.501617431640625 +98419 -0.23291015625 +98420 -0.379302978515625 +98421 -0.209442138671875 +98422 -0.239044189453125 +98423 -0.174163818359375 +98424 -0.087188720703125 +98425 -0.126739501953125 +98426 0.083282470703125 +98427 -0.048126220703125 +98428 0.252685546875 +98429 0.0426025390625 +98430 0.3885498046875 +98431 0.10748291015625 +98432 0.48248291015625 +98433 0.1409912109375 +98434 0.56964111328125 +98435 0.19708251953125 +98436 0.646636962890625 +98437 0.273651123046875 +98438 0.675201416015625 +98439 0.31768798828125 +98440 0.6646728515625 +98441 0.341094970703125 +98442 0.634429931640625 +98443 0.368011474609375 +98444 0.569305419921875 +98445 0.37249755859375 +98446 0.435272216796875 +98447 0.30072021484375 +98448 0.236572265625 +98449 0.1517333984375 +98450 0.02105712890625 +98451 -0.01470947265625 +98452 -0.198486328125 +98453 -0.1883544921875 +98454 -0.41937255859375 +98455 -0.372711181640625 +98456 -0.598602294921875 +98457 -0.51397705078125 +98458 -0.703460693359375 +98459 -0.57177734375 +98460 -0.726165771484375 +98461 -0.53948974609375 +98462 -0.677581787109375 +98463 -0.43511962890625 +98464 -0.583648681640625 +98465 -0.2962646484375 +98466 -0.471893310546875 +98467 -0.161102294921875 +98468 -0.353668212890625 +98469 -0.0435791015625 +98470 -0.228515625 +98471 0.060394287109375 +98472 -0.1097412109375 +98473 0.13665771484375 +98474 -0.011962890625 +98475 0.170135498046875 +98476 0.0638427734375 +98477 0.16552734375 +98478 0.137725830078125 +98479 0.15728759765625 +98480 0.209136962890625 +98481 0.150787353515625 +98482 0.2569580078125 +98483 0.12200927734375 +98484 0.284210205078125 +98485 0.080108642578125 +98486 0.3067626953125 +98487 0.05126953125 +98488 0.3421630859375 +98489 0.062896728515625 +98490 0.37353515625 +98491 0.09271240234375 +98492 0.3668212890625 +98493 0.092987060546875 +98494 0.333465576171875 +98495 0.07855224609375 +98496 0.2857666015625 +98497 0.06427001953125 +98498 0.215240478515625 +98499 0.0347900390625 +98500 0.12359619140625 +98501 -0.01171875 +98502 0.0279541015625 +98503 -0.056060791015625 +98504 -0.037567138671875 +98505 -0.055511474609375 +98506 -0.069580078125 +98507 -0.010467529296875 +98508 -0.10308837890625 +98509 0.02508544921875 +98510 -0.153167724609375 +98511 0.025665283203125 +98512 -0.198760986328125 +98513 0.017333984375 +98514 -0.23675537109375 +98515 0.00189208984375 +98516 -0.27392578125 +98517 -0.03173828125 +98518 -0.3013916015625 +98519 -0.071502685546875 +98520 -0.332427978515625 +98521 -0.13543701171875 +98522 -0.36566162109375 +98523 -0.219970703125 +98524 -0.38543701171875 +98525 -0.300506591796875 +98526 -0.393585205078125 +98527 -0.376312255859375 +98528 -0.370513916015625 +98529 -0.416107177734375 +98530 -0.284515380859375 +98531 -0.371124267578125 +98532 -0.13922119140625 +98533 -0.242279052734375 +98534 0.033843994140625 +98535 -0.069732666015625 +98536 0.2171630859375 +98537 0.125640869140625 +98538 0.38629150390625 +98539 0.31268310546875 +98540 0.513641357421875 +98541 0.45501708984375 +98542 0.599578857421875 +98543 0.554779052734375 +98544 0.6427001953125 +98545 0.61065673828125 +98546 0.634796142578125 +98547 0.610931396484375 +98548 0.559478759765625 +98549 0.531463623046875 +98550 0.42950439453125 +98551 0.3883056640625 +98552 0.2845458984375 +98553 0.23468017578125 +98554 0.144317626953125 +98555 0.095245361328125 +98556 0.02972412109375 +98557 -0.00396728515625 +98558 -0.046478271484375 +98559 -0.04852294921875 +98560 -0.09393310546875 +98561 -0.055145263671875 +98562 -0.14727783203125 +98563 -0.0758056640625 +98564 -0.22430419921875 +98565 -0.138702392578125 +98566 -0.299041748046875 +98567 -0.209197998046875 +98568 -0.37139892578125 +98569 -0.289031982421875 +98570 -0.441131591796875 +98571 -0.37884521484375 +98572 -0.492462158203125 +98573 -0.456329345703125 +98574 -0.52227783203125 +98575 -0.51641845703125 +98576 -0.50360107421875 +98577 -0.519287109375 +98578 -0.43310546875 +98579 -0.458251953125 +98580 -0.348541259765625 +98581 -0.384796142578125 +98582 -0.269195556640625 +98583 -0.323699951171875 +98584 -0.19317626953125 +98585 -0.269287109375 +98586 -0.104156494140625 +98587 -0.1951904296875 +98588 -0.003173828125 +98589 -0.100006103515625 +98590 0.08917236328125 +98591 -0.01055908203125 +98592 0.192535400390625 +98593 0.1033935546875 +98594 0.310882568359375 +98595 0.24908447265625 +98596 0.406219482421875 +98597 0.373199462890625 +98598 0.4659423828125 +98599 0.45806884765625 +98600 0.495697021484375 +98601 0.511474609375 +98602 0.518524169921875 +98603 0.565399169921875 +98604 0.529541015625 +98605 0.61138916015625 +98606 0.48828125 +98607 0.5897216796875 +98608 0.389404296875 +98609 0.4906005859375 +98610 0.24688720703125 +98611 0.33148193359375 +98612 0.087249755859375 +98613 0.147796630859375 +98614 -0.05859375 +98615 -0.01873779296875 +98616 -0.16961669921875 +98617 -0.140289306640625 +98618 -0.227081298828125 +98619 -0.191986083984375 +98620 -0.2373046875 +98621 -0.184295654296875 +98622 -0.2308349609375 +98623 -0.161834716796875 +98624 -0.236724853515625 +98625 -0.166595458984375 +98626 -0.25177001953125 +98627 -0.19390869140625 +98628 -0.262847900390625 +98629 -0.22442626953125 +98630 -0.285797119140625 +98631 -0.279754638671875 +98632 -0.307037353515625 +98633 -0.3389892578125 +98634 -0.29437255859375 +98635 -0.3543701171875 +98636 -0.264739990234375 +98637 -0.348175048828125 +98638 -0.223480224609375 +98639 -0.32598876953125 +98640 -0.151275634765625 +98641 -0.2581787109375 +98642 -0.04595947265625 +98643 -0.139801025390625 +98644 0.081146240234375 +98645 0.014617919921875 +98646 0.186553955078125 +98647 0.144378662109375 +98648 0.249725341796875 +98649 0.221038818359375 +98650 0.288543701171875 +98651 0.27069091796875 +98652 0.303436279296875 +98653 0.294036865234375 +98654 0.30914306640625 +98655 0.311767578125 +98656 0.316802978515625 +98657 0.339141845703125 +98658 0.315765380859375 +98659 0.360260009765625 +98660 0.296875 +98661 0.360504150390625 +98662 0.239898681640625 +98663 0.308380126953125 +98664 0.131072998046875 +98665 0.18170166015625 +98666 -0.011688232421875 +98667 0.0047607421875 +98668 -0.155303955078125 +98669 -0.17559814453125 +98670 -0.268035888671875 +98671 -0.3143310546875 +98672 -0.319305419921875 +98673 -0.36785888671875 +98674 -0.326263427734375 +98675 -0.36248779296875 +98676 -0.319305419921875 +98677 -0.343536376953125 +98678 -0.29205322265625 +98679 -0.3018798828125 +98680 -0.24041748046875 +98681 -0.231414794921875 +98682 -0.154876708984375 +98683 -0.117645263671875 +98684 -0.058013916015625 +98685 0.007049560546875 +98686 0.012176513671875 +98687 0.087982177734375 +98688 0.06451416015625 +98689 0.13946533203125 +98690 0.106658935546875 +98691 0.17425537109375 +98692 0.134735107421875 +98693 0.188201904296875 +98694 0.140869140625 +98695 0.171234130859375 +98696 0.120819091796875 +98697 0.118438720703125 +98698 0.09228515625 +98699 0.05706787109375 +98700 0.056060791015625 +98701 -0.010711669921875 +98702 0.00726318359375 +98703 -0.0914306640625 +98704 -0.038787841796875 +98705 -0.162322998046875 +98706 -0.0625 +98707 -0.194549560546875 +98708 -0.03729248046875 +98709 -0.1492919921875 +98710 0.04058837890625 +98711 -0.02166748046875 +98712 0.128021240234375 +98713 0.124053955078125 +98714 0.173553466796875 +98715 0.211151123046875 +98716 0.17852783203125 +98717 0.240447998046875 +98718 0.16436767578125 +98719 0.242218017578125 +98720 0.13824462890625 +98721 0.2257080078125 +98722 0.103302001953125 +98723 0.194366455078125 +98724 0.03802490234375 +98725 0.115509033203125 +98726 -0.0408935546875 +98727 0.0128173828125 +98728 -0.09228515625 +98729 -0.053802490234375 +98730 -0.1337890625 +98731 -0.110626220703125 +98732 -0.19378662109375 +98733 -0.199493408203125 +98734 -0.254730224609375 +98735 -0.29437255859375 +98736 -0.27398681640625 +98737 -0.33221435546875 +98738 -0.229400634765625 +98739 -0.27972412109375 +98740 -0.154449462890625 +98741 -0.185333251953125 +98742 -0.10357666015625 +98743 -0.128204345703125 +98744 -0.08245849609375 +98745 -0.115692138671875 +98746 -0.07049560546875 +98747 -0.116455078125 +98748 -0.051666259765625 +98749 -0.105926513671875 +98750 -0.006072998046875 +98751 -0.053955078125 +98752 0.07208251953125 +98753 0.048797607421875 +98754 0.15179443359375 +98755 0.157318115234375 +98756 0.192291259765625 +98757 0.212005615234375 +98758 0.197265625 +98759 0.218475341796875 +98760 0.207916259765625 +98761 0.23724365234375 +98762 0.2496337890625 +98763 0.30535888671875 +98764 0.29449462890625 +98765 0.38128662109375 +98766 0.301727294921875 +98767 0.404449462890625 +98768 0.28515625 +98769 0.3944091796875 +98770 0.270782470703125 +98771 0.3885498046875 +98772 0.24273681640625 +98773 0.362640380859375 +98774 0.172271728515625 +98775 0.27362060546875 +98776 0.056976318359375 +98777 0.11712646484375 +98778 -0.0673828125 +98779 -0.054901123046875 +98780 -0.16534423828125 +98781 -0.19085693359375 +98782 -0.233245849609375 +98783 -0.28570556640625 +98784 -0.270843505859375 +98785 -0.339263916015625 +98786 -0.29583740234375 +98787 -0.3775634765625 +98788 -0.339019775390625 +98789 -0.445709228515625 +98790 -0.394775390625 +98791 -0.535064697265625 +98792 -0.452117919921875 +98793 -0.629058837890625 +98794 -0.490997314453125 +98795 -0.697601318359375 +98796 -0.48687744140625 +98797 -0.70391845703125 +98798 -0.43646240234375 +98799 -0.6424560546875 +98800 -0.32525634765625 +98801 -0.491241455078125 +98802 -0.164215087890625 +98803 -0.265716552734375 +98804 0.00689697265625 +98805 -0.023712158203125 +98806 0.165313720703125 +98807 0.201751708984375 +98808 0.287078857421875 +98809 0.375823974609375 +98810 0.362945556640625 +98811 0.485076904296875 +98812 0.419647216796875 +98813 0.56884765625 +98814 0.462432861328125 +98815 0.634765625 +98816 0.461212158203125 +98817 0.63763427734375 +98818 0.409210205078125 +98819 0.5660400390625 +98820 0.341064453125 +98821 0.4720458984375 +98822 0.290252685546875 +98823 0.40692138671875 +98824 0.26177978515625 +98825 0.3778076171875 +98826 0.251068115234375 +98827 0.376953125 +98828 0.237640380859375 +98829 0.371978759765625 +98830 0.18975830078125 +98831 0.313140869140625 +98832 0.0975341796875 +98833 0.184417724609375 +98834 -0.022125244140625 +98835 0.011199951171875 +98836 -0.1458740234375 +98837 -0.171051025390625 +98838 -0.257293701171875 +98839 -0.33740234375 +98840 -0.345977783203125 +98841 -0.47198486328125 +98842 -0.402557373046875 +98843 -0.560394287109375 +98844 -0.412841796875 +98845 -0.58056640625 +98846 -0.38677978515625 +98847 -0.54754638671875 +98848 -0.35528564453125 +98849 -0.508575439453125 +98850 -0.3160400390625 +98851 -0.459503173828125 +98852 -0.265625 +98853 -0.394378662109375 +98854 -0.230010986328125 +98855 -0.35260009765625 +98856 -0.195098876953125 +98857 -0.31170654296875 +98858 -0.113250732421875 +98859 -0.197418212890625 +98860 0.016265869140625 +98861 -0.007965087890625 +98862 0.1612548828125 +98863 0.207489013671875 +98864 0.29571533203125 +98865 0.409210205078125 +98866 0.403228759765625 +98867 0.57208251953125 +98868 0.4642333984375 +98869 0.66595458984375 +98870 0.45794677734375 +98871 0.65875244140625 +98872 0.3955078125 +98873 0.56744384765625 +98874 0.302642822265625 +98875 0.431396484375 +98876 0.208038330078125 +98877 0.29443359375 +98878 0.128875732421875 +98879 0.182464599609375 +98880 0.044891357421875 +98881 0.06365966796875 +98882 -0.05255126953125 +98883 -0.075958251953125 +98884 -0.132659912109375 +98885 -0.189422607421875 +98886 -0.19195556640625 +98887 -0.271942138671875 +98888 -0.242462158203125 +98889 -0.342529296875 +98890 -0.260009765625 +98891 -0.364166259765625 +98892 -0.238189697265625 +98893 -0.327239990234375 +98894 -0.20623779296875 +98895 -0.2769775390625 +98896 -0.1903076171875 +98897 -0.253692626953125 +98898 -0.181549072265625 +98899 -0.24365234375 +98900 -0.14874267578125 +98901 -0.1983642578125 +98902 -0.091064453125 +98903 -0.116241455078125 +98904 -0.034393310546875 +98905 -0.036834716796875 +98906 0.0177001953125 +98907 0.034881591796875 +98908 0.0599365234375 +98909 0.09124755859375 +98910 0.076904296875 +98911 0.10888671875 +98912 0.092681884765625 +98913 0.125518798828125 +98914 0.117767333984375 +98915 0.15771484375 +98916 0.13433837890625 +98917 0.17828369140625 +98918 0.13177490234375 +98919 0.17108154296875 +98920 0.106048583984375 +98921 0.129974365234375 +98922 0.074920654296875 +98923 0.082427978515625 +98924 0.037994384765625 +98925 0.027679443359375 +98926 -0.024932861328125 +98927 -0.065643310546875 +98928 -0.0889892578125 +98929 -0.15936279296875 +98930 -0.127777099609375 +98931 -0.21307373046875 +98932 -0.14617919921875 +98933 -0.234649658203125 +98934 -0.12847900390625 +98935 -0.2001953125 +98936 -0.08050537109375 +98937 -0.119171142578125 +98938 -0.0235595703125 +98939 -0.024749755859375 +98940 0.04437255859375 +98941 0.085784912109375 +98942 0.101226806640625 +98943 0.178131103515625 +98944 0.123382568359375 +98945 0.215576171875 +98946 0.119537353515625 +98947 0.211456298828125 +98948 0.09588623046875 +98949 0.17523193359375 +98950 0.066558837890625 +98951 0.128753662109375 +98952 0.05084228515625 +98953 0.1019287109375 +98954 0.035430908203125 +98955 0.0743408203125 +98956 0.01837158203125 +98957 0.04327392578125 +98958 0.01861572265625 +98959 0.038177490234375 +98960 0.047088623046875 +98961 0.076263427734375 +98962 0.0928955078125 +98963 0.14105224609375 +98964 0.12591552734375 +98965 0.186431884765625 +98966 0.13067626953125 +98967 0.188812255859375 +98968 0.101104736328125 +98969 0.1390380859375 +98970 0.040069580078125 +98971 0.041778564453125 +98972 -0.0372314453125 +98973 -0.079437255859375 +98974 -0.12750244140625 +98975 -0.219390869140625 +98976 -0.224029541015625 +98977 -0.367828369140625 +98978 -0.30743408203125 +98979 -0.494873046875 +98980 -0.348968505859375 +98981 -0.556243896484375 +98982 -0.32049560546875 +98983 -0.508697509765625 +98984 -0.23699951171875 +98985 -0.3756103515625 +98986 -0.13848876953125 +98987 -0.218902587890625 +98988 -0.04107666015625 +98989 -0.063751220703125 +98990 0.056488037109375 +98991 0.091552734375 +98992 0.14727783203125 +98993 0.23602294921875 +98994 0.214141845703125 +98995 0.342987060546875 +98996 0.246063232421875 +98997 0.39520263671875 +98998 0.240997314453125 +98999 0.389373779296875 +99000 0.19818115234375 +99001 0.324249267578125 +99002 0.133331298828125 +99003 0.224090576171875 +99004 0.0693359375 +99005 0.124267578125 +99006 0.01409912109375 +99007 0.037078857421875 +99008 -0.014678955078125 +99009 -0.010101318359375 +99010 -0.0185546875 +99011 -0.019439697265625 +99012 -0.018280029296875 +99013 -0.022796630859375 +99014 -0.001953125 +99015 -0.001556396484375 +99016 0.038055419921875 +99017 0.056304931640625 +99018 0.07305908203125 +99019 0.106719970703125 +99020 0.068756103515625 +99021 0.096893310546875 +99022 0.035308837890625 +99023 0.042694091796875 +99024 -0.002838134765625 +99025 -0.018035888671875 +99026 -0.03961181640625 +99027 -0.07586669921875 +99028 -0.06768798828125 +99029 -0.11944580078125 +99030 -0.094146728515625 +99031 -0.15972900390625 +99032 -0.122772216796875 +99033 -0.202606201171875 +99034 -0.15380859375 +99035 -0.24859619140625 +99036 -0.1920166015625 +99037 -0.30517578125 +99038 -0.230743408203125 +99039 -0.36212158203125 +99040 -0.251708984375 +99041 -0.39141845703125 +99042 -0.23028564453125 +99043 -0.35528564453125 +99044 -0.163970947265625 +99045 -0.249969482421875 +99046 -0.06396484375 +99047 -0.092864990234375 +99048 0.0523681640625 +99049 0.08905029296875 +99050 0.145904541015625 +99051 0.2352294921875 +99052 0.199249267578125 +99053 0.318817138671875 +99054 0.22467041015625 +99055 0.358642578125 +99056 0.2176513671875 +99057 0.347747802734375 +99058 0.1778564453125 +99059 0.28564453125 +99060 0.138214111328125 +99061 0.223175048828125 +99062 0.122222900390625 +99063 0.196746826171875 +99064 0.1126708984375 +99065 0.179840087890625 +99066 0.0985107421875 +99067 0.155548095703125 +99068 0.097381591796875 +99069 0.151214599609375 +99070 0.102783203125 +99071 0.156951904296875 +99072 0.08819580078125 +99073 0.13177490234375 +99074 0.069366455078125 +99075 0.100799560546875 +99076 0.06103515625 +99077 0.087127685546875 +99078 0.040924072265625 +99079 0.05487060546875 +99080 0.000885009765625 +99081 -0.009002685546875 +99082 -0.0587158203125 +99083 -0.10400390625 +99084 -0.137420654296875 +99085 -0.229400634765625 +99086 -0.216888427734375 +99087 -0.35552978515625 +99088 -0.272064208984375 +99089 -0.441925048828125 +99090 -0.293792724609375 +99091 -0.473846435546875 +99092 -0.29022216796875 +99093 -0.464813232421875 +99094 -0.26385498046875 +99095 -0.419097900390625 +99096 -0.213104248046875 +99097 -0.334320068359375 +99098 -0.14862060546875 +99099 -0.227935791015625 +99100 -0.084869384765625 +99101 -0.12347412109375 +99102 -0.02593994140625 +99103 -0.02764892578125 +99104 0.039337158203125 +99105 0.077667236328125 +99106 0.12371826171875 +99107 0.2132568359375 +99108 0.233154296875 +99109 0.38885498046875 +99110 0.354217529296875 +99111 0.582794189453125 +99112 0.44921875 +99113 0.734039306640625 +99114 0.49188232421875 +99115 0.800140380859375 +99116 0.480377197265625 +99117 0.7783203125 +99118 0.412506103515625 +99119 0.6651611328125 +99120 0.287567138671875 +99121 0.45965576171875 +99122 0.128509521484375 +99123 0.199188232421875 +99124 -0.024383544921875 +99125 -0.050689697265625 +99126 -0.13604736328125 +99127 -0.23297119140625 +99128 -0.195709228515625 +99129 -0.33013916015625 +99130 -0.219482421875 +99131 -0.368408203125 +99132 -0.226531982421875 +99133 -0.378936767578125 +99134 -0.22625732421875 +99135 -0.376983642578125 +99136 -0.229156494140625 +99137 -0.37969970703125 +99138 -0.237884521484375 +99139 -0.391510009765625 +99140 -0.235687255859375 +99141 -0.385345458984375 +99142 -0.2105712890625 +99143 -0.3419189453125 +99144 -0.175811767578125 +99145 -0.28289794921875 +99146 -0.15802001953125 +99147 -0.251617431640625 +99148 -0.168212890625 +99149 -0.266143798828125 +99150 -0.17364501953125 +99151 -0.273345947265625 +99152 -0.13946533203125 +99153 -0.216796875 +99154 -0.085205078125 +99155 -0.128265380859375 +99156 -0.048095703125 +99157 -0.068145751953125 +99158 -0.0322265625 +99159 -0.0430908203125 +99160 -0.02001953125 +99161 -0.024444580078125 +99162 0.0087890625 +99163 0.020721435546875 +99164 0.073883056640625 +99165 0.124481201171875 +99166 0.1573486328125 +99167 0.25787353515625 +99168 0.23333740234375 +99169 0.379119873046875 +99170 0.296722412109375 +99171 0.47991943359375 +99172 0.32763671875 +99173 0.5281982421875 +99174 0.318145751953125 +99175 0.511138916015625 +99176 0.285125732421875 +99177 0.456207275390625 +99178 0.255706787109375 +99179 0.407470703125 +99180 0.241424560546875 +99181 0.383758544921875 +99182 0.224884033203125 +99183 0.35687255859375 +99184 0.1968994140625 +99185 0.31182861328125 +99186 0.158843994140625 +99187 0.250885009765625 +99188 0.105438232421875 +99189 0.1654052734375 +99190 0.02435302734375 +99191 0.035247802734375 +99192 -0.085906982421875 +99193 -0.142059326171875 +99194 -0.20623779296875 +99195 -0.33563232421875 +99196 -0.329803466796875 +99197 -0.5345458984375 +99198 -0.446136474609375 +99199 -0.72186279296875 +99200 -0.5177001953125 +99201 -0.836669921875 +99202 -0.515899658203125 +99203 -0.8326416015625 +99204 -0.452911376953125 +99205 -0.7296142578125 +99206 -0.36260986328125 +99207 -0.582550048828125 +99208 -0.274932861328125 +99209 -0.440093994140625 +99210 -0.203460693359375 +99211 -0.324310302734375 +99212 -0.12744140625 +99213 -0.20147705078125 +99214 -0.0302734375 +99215 -0.044647216796875 +99216 0.061981201171875 +99217 0.103973388671875 +99218 0.1234130859375 +99219 0.202392578125 +99220 0.16253662109375 +99221 0.264495849609375 +99222 0.209228515625 +99223 0.338897705078125 +99224 0.274658203125 +99225 0.443817138671875 +99226 0.337738037109375 +99227 0.545074462890625 +99228 0.382781982421875 +99229 0.6173095703125 +99230 0.40484619140625 +99231 0.6524658203125 +99232 0.41180419921875 +99233 0.66339111328125 +99234 0.4073486328125 +99235 0.6561279296875 +99236 0.376800537109375 +99237 0.606781005859375 +99238 0.311431884765625 +99239 0.501190185546875 +99240 0.21954345703125 +99241 0.352783203125 +99242 0.110382080078125 +99243 0.176544189453125 +99244 -0.020477294921875 +99245 -0.034820556640625 +99246 -0.15875244140625 +99247 -0.258209228515625 +99248 -0.27288818359375 +99249 -0.44244384765625 +99250 -0.355316162109375 +99251 -0.5753173828125 +99252 -0.403076171875 +99253 -0.65203857421875 +99254 -0.397064208984375 +99255 -0.641632080078125 +99256 -0.348388671875 +99257 -0.562164306640625 +99258 -0.284393310546875 +99259 -0.458038330078125 +99260 -0.21820068359375 +99261 -0.350555419921875 +99262 -0.162628173828125 +99263 -0.260528564453125 +99264 -0.120269775390625 +99265 -0.192108154296875 +99266 -0.08905029296875 +99267 -0.141937255859375 +99268 -0.06414794921875 +99269 -0.1021728515625 +99270 -0.03948974609375 +99271 -0.062896728515625 +99272 -0.007568359375 +99273 -0.011932373046875 +99274 0.03900146484375 +99275 0.062835693359375 +99276 0.0924072265625 +99277 0.148712158203125 +99278 0.150146484375 +99279 0.241729736328125 +99280 0.2166748046875 +99281 0.34912109375 +99282 0.283599853515625 +99283 0.457305908203125 +99284 0.33709716796875 +99285 0.54388427734375 +99286 0.355010986328125 +99287 0.5728759765625 +99288 0.31414794921875 +99289 0.506591796875 +99290 0.218292236328125 +99291 0.351226806640625 +99292 0.0919189453125 +99293 0.146514892578125 +99294 -0.032684326171875 +99295 -0.05523681640625 +99296 -0.132232666015625 +99297 -0.21624755859375 +99298 -0.205718994140625 +99299 -0.334930419921875 +99300 -0.248016357421875 +99301 -0.402984619140625 +99302 -0.27197265625 +99303 -0.4412841796875 +99304 -0.305908203125 +99305 -0.49578857421875 +99306 -0.345855712890625 +99307 -0.5601806640625 +99308 -0.371063232421875 +99309 -0.600738525390625 +99310 -0.361053466796875 +99311 -0.584228515625 +99312 -0.2965087890625 +99313 -0.47930908203125 +99314 -0.173370361328125 +99315 -0.27935791015625 +99316 -0.006744384765625 +99317 -0.0089111328125 +99318 0.164398193359375 +99319 0.268798828125 +99320 0.29638671875 +99321 0.482818603515625 +99322 0.371063232421875 +99323 0.60369873046875 +99324 0.40008544921875 +99325 0.650421142578125 +99326 0.408721923828125 +99327 0.66400146484375 +99328 0.395355224609375 +99329 0.6414794921875 +99330 0.353546142578125 +99331 0.572540283203125 +99332 0.307373046875 +99333 0.498138427734375 +99334 0.26947021484375 +99335 0.439453125 +99336 0.227874755859375 +99337 0.375518798828125 +99338 0.164276123046875 +99339 0.274505615234375 +99340 0.06280517578125 +99341 0.1087646484375 +99342 -0.063201904296875 +99343 -0.099395751953125 +99344 -0.1949462890625 +99345 -0.3182373046875 +99346 -0.33294677734375 +99347 -0.5489501953125 +99348 -0.4666748046875 +99349 -0.7738037109375 +99350 -0.56512451171875 +99351 -0.86383056640625 +99352 -0.60882568359375 +99353 -0.870391845703125 +99354 -0.608154296875 +99355 -0.86895751953125 +99356 -0.570831298828125 +99357 -0.861053466796875 +99358 -0.486846923828125 +99359 -0.765869140625 +99360 -0.349761962890625 +99361 -0.5301513671875 +99362 -0.163909912109375 +99363 -0.214691162109375 +99364 0.045379638671875 +99365 0.137359619140625 +99366 0.2479248046875 +99367 0.474822998046875 +99368 0.422760009765625 +99369 0.76239013671875 +99370 0.553924560546875 +99371 0.867462158203125 +99372 0.641510009765625 +99373 0.870361328125 +99374 0.678619384765625 +99375 0.86480712890625 +99376 0.668304443359375 +99377 0.831817626953125 +99378 0.624725341796875 +99379 0.677581787109375 +99380 0.55126953125 +99381 0.495880126953125 +99382 0.458831787109375 +99383 0.30767822265625 +99384 0.3487548828125 +99385 0.116180419921875 +99386 0.20263671875 +99387 -0.110748291015625 +99388 0.01654052734375 +99389 -0.381805419921875 +99390 -0.184326171875 +99391 -0.6572265625 +99392 -0.364837646484375 +99393 -0.857421875 +99394 -0.499755859375 +99395 -0.870391845703125 +99396 -0.584747314453125 +99397 -0.870391845703125 +99398 -0.635406494140625 +99399 -0.86444091796875 +99400 -0.67242431640625 +99401 -0.85723876953125 +99402 -0.68499755859375 +99403 -0.790008544921875 +99404 -0.641387939453125 +99405 -0.62847900390625 +99406 -0.539703369140625 +99407 -0.3956298828125 +99408 -0.39910888671875 +99409 -0.126708984375 +99410 -0.23565673828125 +99411 0.150115966796875 +99412 -0.0562744140625 +99413 0.424041748046875 +99414 0.123138427734375 +99415 0.670623779296875 +99416 0.279815673828125 +99417 0.854522705078125 +99418 0.403289794921875 +99419 0.866485595703125 +99420 0.48443603515625 +99421 0.86920166015625 +99422 0.53369140625 +99423 0.8653564453125 +99424 0.558746337890625 +99425 0.857147216796875 +99426 0.55780029296875 +99427 0.766845703125 +99428 0.533721923828125 +99429 0.628509521484375 +99430 0.482513427734375 +99431 0.462127685546875 +99432 0.41925048828125 +99433 0.297210693359375 +99434 0.351165771484375 +99435 0.14862060546875 +99436 0.26495361328125 +99437 -0.00537109375 +99438 0.16510009765625 +99439 -0.15753173828125 +99440 0.049560546875 +99441 -0.31304931640625 +99442 -0.0897216796875 +99443 -0.48876953125 +99444 -0.2252197265625 +99445 -0.6416015625 +99446 -0.34234619140625 +99447 -0.751373291015625 +99448 -0.4544677734375 +99449 -0.84619140625 +99450 -0.5528564453125 +99451 -0.861297607421875 +99452 -0.6180419921875 +99453 -0.863250732421875 +99454 -0.631500244140625 +99455 -0.856597900390625 +99456 -0.60028076171875 +99457 -0.7498779296875 +99458 -0.558135986328125 +99459 -0.624542236328125 +99460 -0.492218017578125 +99461 -0.47808837890625 +99462 -0.368408203125 +99463 -0.253387451171875 +99464 -0.21343994140625 +99465 0.003692626953125 +99466 -0.06732177734375 +99467 0.2257080078125 +99468 0.077178955078125 +99469 0.427154541015625 +99470 0.23883056640625 +99471 0.643218994140625 +99472 0.411865234375 +99473 0.855926513671875 +99474 0.56231689453125 +99475 0.870361328125 +99476 0.66107177734375 +99477 0.870361328125 +99478 0.712188720703125 +99479 0.862762451171875 +99480 0.7138671875 +99481 0.79669189453125 +99482 0.6605224609375 +99483 0.595794677734375 +99484 0.5692138671875 +99485 0.362152099609375 +99486 0.456298828125 +99487 0.1270751953125 +99488 0.33416748046875 +99489 -0.086944580078125 +99490 0.2041015625 +99491 -0.2784423828125 +99492 0.04583740234375 +99493 -0.484832763671875 +99494 -0.15167236328125 +99495 -0.729583740234375 +99496 -0.358734130859375 +99497 -0.86688232421875 +99498 -0.538238525390625 +99499 -0.870391845703125 +99500 -0.687103271484375 +99501 -0.86859130859375 +99502 -0.803955078125 +99503 -0.86279296875 +99504 -0.85595703125 +99505 -0.817962646484375 +99506 -0.851593017578125 +99507 -0.6116943359375 +99508 -0.751495361328125 +99509 -0.3128662109375 +99510 -0.5870361328125 +99511 0.039398193359375 +99512 -0.369903564453125 +99513 0.422821044921875 +99514 -0.119598388671875 +99515 0.805145263671875 +99516 0.1240234375 +99517 0.870361328125 +99518 0.3275146484375 +99519 0.870361328125 +99520 0.48382568359375 +99521 0.860015869140625 +99522 0.588226318359375 +99523 0.727935791015625 +99524 0.637176513671875 +99525 0.48114013671875 +99526 0.644561767578125 +99527 0.2059326171875 +99528 0.62335205078125 +99529 -0.06103515625 +99530 0.579193115234375 +99531 -0.29913330078125 +99532 0.503448486328125 +99533 -0.516204833984375 +99534 0.3870849609375 +99535 -0.7252197265625 +99536 0.24462890625 +99537 -0.85980224609375 +99538 0.096221923828125 +99539 -0.870391845703125 +99540 -0.0406494140625 +99541 -0.870391845703125 +99542 -0.13726806640625 +99543 -0.858062744140625 +99544 -0.190826416015625 +99545 -0.673004150390625 +99546 -0.231597900390625 +99547 -0.42694091796875 +99548 -0.285125732421875 +99549 -0.2100830078125 +99550 -0.3497314453125 +99551 -0.0362548828125 +99552 -0.4080810546875 +99553 0.10943603515625 +99554 -0.448211669921875 +99555 0.23516845703125 +99556 -0.4456787109375 +99557 0.373687744140625 +99558 -0.40142822265625 +99559 0.517791748046875 +99560 -0.352142333984375 +99561 0.602783203125 +99562 -0.294830322265625 +99563 0.635711669921875 +99564 -0.21014404296875 +99565 0.655181884765625 +99566 -0.104095458984375 +99567 0.65948486328125 +99568 0.018341064453125 +99569 0.651275634765625 +99570 0.142486572265625 +99571 0.61846923828125 +99572 0.246307373046875 +99573 0.53753662109375 +99574 0.318817138671875 +99575 0.404144287109375 +99576 0.353912353515625 +99577 0.22186279296875 +99578 0.351959228515625 +99579 0.003997802734375 +99580 0.32318115234375 +99581 -0.22100830078125 +99582 0.279327392578125 +99583 -0.42449951171875 +99584 0.23236083984375 +99585 -0.579833984375 +99586 0.206451416015625 +99587 -0.641876220703125 +99588 0.19830322265625 +99589 -0.6177978515625 +99590 0.17205810546875 +99591 -0.575531005859375 +99592 0.124725341796875 +99593 -0.526336669921875 +99594 0.084991455078125 +99595 -0.42645263671875 +99596 0.068267822265625 +99597 -0.2581787109375 +99598 0.0548095703125 +99599 -0.068695068359375 +99600 0.023773193359375 +99601 0.09222412109375 +99602 -0.014068603515625 +99603 0.232147216796875 +99604 -0.052642822265625 +99605 0.3509521484375 +99606 -0.107879638671875 +99607 0.410064697265625 +99608 -0.19561767578125 +99609 0.372955322265625 +99610 -0.303955078125 +99611 0.2554931640625 +99612 -0.4039306640625 +99613 0.10711669921875 +99614 -0.484588623046875 +99615 -0.052886962890625 +99616 -0.52593994140625 +99617 -0.186279296875 +99618 -0.497314453125 +99619 -0.23291015625 +99620 -0.411468505859375 +99621 -0.209442138671875 +99622 -0.3050537109375 +99623 -0.174163818359375 +99624 -0.183013916015625 +99625 -0.126739501953125 +99626 -0.040313720703125 +99627 -0.048126220703125 +99628 0.106964111328125 +99629 0.0426025390625 +99630 0.232635498046875 +99631 0.10748291015625 +99632 0.32891845703125 +99633 0.1409912109375 +99634 0.4217529296875 +99635 0.19708251953125 +99636 0.507049560546875 +99637 0.273651123046875 +99638 0.553741455078125 +99639 0.31768798828125 +99640 0.567779541015625 +99641 0.341094970703125 +99642 0.56304931640625 +99643 0.368011474609375 +99644 0.526885986328125 +99645 0.37249755859375 +99646 0.432220458984375 +99647 0.30072021484375 +99648 0.282012939453125 +99649 0.1517333984375 +99650 0.113311767578125 +99651 -0.01470947265625 +99652 -0.063751220703125 +99653 -0.1883544921875 +99654 -0.24658203125 +99655 -0.372711181640625 +99656 -0.401092529296875 +99657 -0.51397705078125 +99658 -0.50091552734375 +99659 -0.57177734375 +99660 -0.5389404296875 +99661 -0.53948974609375 +99662 -0.52239990234375 +99663 -0.43511962890625 +99664 -0.470245361328125 +99665 -0.2962646484375 +99666 -0.4027099609375 +99667 -0.161102294921875 +99668 -0.32757568359375 +99669 -0.0435791015625 +99670 -0.24365234375 +99671 0.060394287109375 +99672 -0.16064453125 +99673 0.13665771484375 +99674 -0.089508056640625 +99675 0.170135498046875 +99676 -0.0308837890625 +99677 0.16552734375 +99678 0.0306396484375 +99679 0.15728759765625 +99680 0.09429931640625 +99681 0.150787353515625 +99682 0.14312744140625 +99683 0.12200927734375 +99684 0.1787109375 +99685 0.080108642578125 +99686 0.212493896484375 +99687 0.05126953125 +99688 0.25714111328125 +99689 0.062896728515625 +99690 0.298583984375 +99691 0.09271240234375 +99692 0.309539794921875 +99693 0.092987060546875 +99694 0.2979736328125 +99695 0.07855224609375 +99696 0.272735595703125 +99697 0.06427001953125 +99698 0.2266845703125 +99699 0.0347900390625 +99700 0.1607666015625 +99701 -0.01171875 +99702 0.08807373046875 +99703 -0.056060791015625 +99704 0.0350341796875 +99705 -0.055511474609375 +99706 0.0045166015625 +99707 -0.010467529296875 +99708 -0.030181884765625 +99709 0.02508544921875 +99710 -0.0802001953125 +99711 0.025665283203125 +99712 -0.128509521484375 +99713 0.017333984375 +99714 -0.17193603515625 +99715 0.00189208984375 +99716 -0.214935302734375 +99717 -0.03173828125 +99718 -0.249847412109375 +99719 -0.071502685546875 +99720 -0.2862548828125 +99721 -0.13543701171875 +99722 -0.322479248046875 +99723 -0.219970703125 +99724 -0.3458251953125 +99725 -0.300506591796875 +99726 -0.357330322265625 +99727 -0.376312255859375 +99728 -0.341644287109375 +99729 -0.416107177734375 +99730 -0.27410888671875 +99731 -0.371124267578125 +99732 -0.157745361328125 +99733 -0.242279052734375 +99734 -0.017242431640625 +99735 -0.069732666015625 +99736 0.133392333984375 +99737 0.125640869140625 +99738 0.274688720703125 +99739 0.31268310546875 +99740 0.3846435546875 +99741 0.45501708984375 +99742 0.462921142578125 +99743 0.554779052734375 +99744 0.507781982421875 +99745 0.61065673828125 +99746 0.512237548828125 +99747 0.610931396484375 +99748 0.4630126953125 +99749 0.531463623046875 +99750 0.36956787109375 +99751 0.3883056640625 +99752 0.262298583984375 +99753 0.23468017578125 +99754 0.15631103515625 +99755 0.095245361328125 +99756 0.06768798828125 +99757 -0.00396728515625 +99758 0.006378173828125 +99759 -0.04852294921875 +99760 -0.03472900390625 +99761 -0.055145263671875 +99762 -0.082275390625 +99763 -0.0758056640625 +99764 -0.149871826171875 +99765 -0.138702392578125 +99766 -0.216705322265625 +99767 -0.209197998046875 +99768 -0.2823486328125 +99769 -0.289031982421875 +99770 -0.346160888671875 +99771 -0.37884521484375 +99772 -0.395263671875 +99773 -0.456329345703125 +99774 -0.4267578125 +99775 -0.51641845703125 +99776 -0.418975830078125 +99777 -0.519287109375 +99778 -0.368988037109375 +99779 -0.458251953125 +99780 -0.3062744140625 +99781 -0.384796142578125 +99782 -0.245880126953125 +99783 -0.323699951171875 +99784 -0.186248779296875 +99785 -0.269287109375 +99786 -0.114532470703125 +99787 -0.1951904296875 +99788 -0.03167724609375 +99789 -0.100006103515625 +99790 0.04583740234375 +99791 -0.01055908203125 +99792 0.13323974609375 +99793 0.1033935546875 +99794 0.233306884765625 +99795 0.24908447265625 +99796 0.315673828125 +99797 0.373199462890625 +99798 0.370025634765625 +99799 0.45806884765625 +99800 0.400390625 +99801 0.511474609375 +99802 0.424591064453125 +99803 0.565399169921875 +99804 0.43841552734375 +99805 0.61138916015625 +99806 0.40972900390625 +99807 0.5897216796875 +99808 0.334136962890625 +99809 0.4906005859375 +99810 0.222564697265625 +99811 0.33148193359375 +99812 0.095947265625 +99813 0.147796630859375 +99814 -0.021240234375 +99815 -0.01873779296875 +99816 -0.112274169921875 +99817 -0.140289306640625 +99818 -0.162139892578125 +99819 -0.191986083984375 +99820 -0.175537109375 +99821 -0.184295654296875 +99822 -0.176239013671875 +99823 -0.161834716796875 +99824 -0.18682861328125 +99825 -0.166595458984375 +99826 -0.204437255859375 +99827 -0.19390869140625 +99828 -0.218414306640625 +99829 -0.22442626953125 +99830 -0.240997314453125 +99831 -0.279754638671875 +99832 -0.26123046875 +99833 -0.3389892578125 +99834 -0.253570556640625 +99835 -0.3543701171875 +99836 -0.231292724609375 +99837 -0.348175048828125 +99838 -0.198577880859375 +99839 -0.32598876953125 +99840 -0.1402587890625 +99841 -0.2581787109375 +99842 -0.054779052734375 +99843 -0.139801025390625 +99844 0.04876708984375 +99845 0.014617919921875 +99846 0.135955810546875 +99847 0.144378662109375 +99848 0.1904296875 +99849 0.221038818359375 +99850 0.225921630859375 +99851 0.27069091796875 +99852 0.24249267578125 +99853 0.294036865234375 +99854 0.25146484375 +99855 0.311767578125 +99856 0.261322021484375 +99857 0.339141845703125 +99858 0.263336181640625 +99859 0.360260009765625 +99860 0.250213623046875 +99861 0.360504150390625 +99862 0.20654296875 +99863 0.308380126953125 +99864 0.121856689453125 +99865 0.18170166015625 +99866 0.010009765625 +99867 0.0047607421875 +99868 -0.10345458984375 +99869 -0.17559814453125 +99870 -0.194000244140625 +99871 -0.3143310546875 +99872 -0.238006591796875 +99873 -0.36785888671875 +99874 -0.248321533203125 +99875 -0.36248779296875 +99876 -0.247894287109375 +99877 -0.343536376953125 +99878 -0.2315673828125 +99879 -0.3018798828125 +99880 -0.19598388671875 +99881 -0.231414794921875 +99882 -0.133697509765625 +99883 -0.117645263671875 +99884 -0.06182861328125 +99885 0.007049560546875 +99886 -0.009307861328125 +99887 0.087982177734375 +99888 0.030609130859375 +99889 0.13946533203125 +99890 0.06378173828125 +99891 0.17425537109375 +99892 0.087158203125 +99893 0.188201904296875 +99894 0.094573974609375 +99895 0.171234130859375 +99896 0.08258056640625 +99897 0.118438720703125 +99898 0.064544677734375 +99899 0.05706787109375 +99900 0.040863037109375 +99901 -0.010711669921875 +99902 0.007568359375 +99903 -0.0914306640625 +99904 -0.023834228515625 +99905 -0.162322998046875 +99906 -0.03857421875 +99907 -0.194549560546875 +99908 -0.0164794921875 +99909 -0.1492919921875 +99910 0.045135498046875 +99911 -0.02166748046875 +99912 0.11322021484375 +99913 0.124053955078125 +99914 0.14837646484375 +99915 0.211151123046875 +99916 0.151641845703125 +99917 0.240447998046875 +99918 0.13946533203125 +99919 0.242218017578125 +99920 0.117431640625 +99921 0.2257080078125 +99922 0.08807373046875 +99923 0.194366455078125 +99924 0.03509521484375 +99925 0.115509033203125 +99926 -0.028533935546875 +99927 0.0128173828125 +99928 -0.0711669921875 +99929 -0.053802490234375 +99930 -0.1060791015625 +99931 -0.110626220703125 +99932 -0.15484619140625 +99933 -0.199493408203125 +99934 -0.203887939453125 +99935 -0.29437255859375 +99936 -0.220458984375 +99937 -0.33221435546875 +99938 -0.187530517578125 +99939 -0.27972412109375 +99940 -0.13067626953125 +99941 -0.185333251953125 +99942 -0.091522216796875 +99943 -0.128204345703125 +99944 -0.074462890625 +99945 -0.115692138671875 +99946 -0.0638427734375 +99947 -0.116455078125 +99948 -0.047454833984375 +99949 -0.105926513671875 +99950 -0.01025390625 +99951 -0.053955078125 +99952 0.052093505859375 +99953 0.048797607421875 +99954 0.115753173828125 +99955 0.157318115234375 +99956 0.14935302734375 +99957 0.212005615234375 +99958 0.155609130859375 +99959 0.218475341796875 +99960 0.165863037109375 +99961 0.23724365234375 +99962 0.199432373046875 +99963 0.30535888671875 +99964 0.234893798828125 +99965 0.38128662109375 +99966 0.24102783203125 +99967 0.404449462890625 +99968 0.228363037109375 +99969 0.3944091796875 +99970 0.216827392578125 +99971 0.3885498046875 +99972 0.194305419921875 +99973 0.362640380859375 +99974 0.138916015625 +99975 0.27362060546875 +99976 0.04888916015625 +99977 0.11712646484375 +99978 -0.04827880859375 +99979 -0.054901123046875 +99980 -0.125335693359375 +99981 -0.19085693359375 +99982 -0.17938232421875 +99983 -0.28570556640625 +99984 -0.21014404296875 +99985 -0.339263916015625 +99986 -0.23101806640625 +99987 -0.3775634765625 +99988 -0.2655029296875 +99989 -0.445709228515625 +99990 -0.309173583984375 +99991 -0.535064697265625 +99992 -0.3536376953125 +99993 -0.629058837890625 +99994 -0.383514404296875 +99995 -0.697601318359375 +99996 -0.38006591796875 +99997 -0.70391845703125 +99998 -0.340789794921875 +99999 -0.6424560546875 +100000 -0.254669189453125 +100001 -0.491241455078125 +100002 -0.130157470703125 +100003 -0.265716552734375 +100004 0.00225830078125 +100005 -0.023712158203125 +100006 0.125091552734375 +100007 0.201751708984375 +100008 0.219940185546875 +100009 0.375823974609375 +100010 0.27960205078125 +100011 0.485076904296875 +100012 0.324432373046875 +100013 0.56884765625 +100014 0.3583984375 +100015 0.634765625 +100016 0.3580322265625 +100017 0.63763427734375 +100018 0.317535400390625 +100019 0.5660400390625 +100020 0.26422119140625 +100021 0.4720458984375 +100022 0.225006103515625 +100023 0.40692138671875 +100024 0.203948974609375 +100025 0.3778076171875 +100026 0.197357177734375 +100027 0.376953125 +100028 0.188720703125 +100029 0.371978759765625 +100030 0.15252685546875 +100031 0.313140869140625 +100032 0.0806884765625 +100033 0.184417724609375 +100034 -0.0133056640625 +100035 0.011199951171875 +100036 -0.110809326171875 +100037 -0.171051025390625 +100038 -0.198760986328125 +100039 -0.33740234375 +100040 -0.268829345703125 +100041 -0.47198486328125 +100042 -0.3135986328125 +100043 -0.560394287109375 +100044 -0.321685791015625 +100045 -0.58056640625 +100046 -0.30108642578125 +100047 -0.54754638671875 +100048 -0.276580810546875 +100049 -0.508575439453125 +100050 -0.24627685546875 +100051 -0.459503173828125 +100052 -0.207366943359375 +100053 -0.394378662109375 +100054 -0.18060302734375 +100055 -0.35260009765625 +100056 -0.154571533203125 +100057 -0.31170654296875 +100058 -0.090911865234375 +100059 -0.197418212890625 +100060 0.01104736328125 +100061 -0.007965087890625 +100062 0.125579833984375 +100063 0.207489013671875 +100064 0.23193359375 +100065 0.409210205078125 +100066 0.3170166015625 +100067 0.57208251953125 +100068 0.365142822265625 +100069 0.66595458984375 +100070 0.359710693359375 +100071 0.65875244140625 +100072 0.30963134765625 +100073 0.56744384765625 +100074 0.235565185546875 +100075 0.431396484375 +100076 0.1605224609375 +100077 0.29443359375 +100078 0.098175048828125 +100079 0.182464599609375 +100080 0.0322265625 +100081 0.06365966796875 +100082 -0.044342041015625 +100083 -0.075958251953125 +100084 -0.10693359375 +100085 -0.189422607421875 +100086 -0.152862548828125 +100087 -0.271942138671875 +100088 -0.19183349609375 +100089 -0.342529296875 +100090 -0.204559326171875 +100091 -0.364166259765625 +100092 -0.18597412109375 +100093 -0.327239990234375 +100094 -0.159576416015625 +100095 -0.2769775390625 +100096 -0.146087646484375 +100097 -0.253692626953125 +100098 -0.138702392578125 +100099 -0.24365234375 +100100 -0.1134033203125 +100101 -0.1983642578125 +100102 -0.069488525390625 +100103 -0.116241455078125 +100104 -0.026336669921875 +100105 -0.036834716796875 +100106 0.013427734375 +100107 0.034881591796875 +100108 0.04583740234375 +100109 0.09124755859375 +100110 0.059234619140625 +100111 0.10888671875 +100112 0.071746826171875 +100113 0.125518798828125 +100114 0.09124755859375 +100115 0.15771484375 +100116 0.104248046875 +100117 0.17828369140625 +100118 0.10272216796875 +100119 0.17108154296875 +100120 0.083587646484375 +100121 0.129974365234375 +100122 0.060211181640625 +100123 0.082427978515625 +100124 0.032257080078125 +100125 0.027679443359375 +100126 -0.015472412109375 +100127 -0.065643310546875 +100128 -0.064178466796875 +100129 -0.15936279296875 +100130 -0.093994140625 +100131 -0.21307373046875 +100132 -0.108551025390625 +100133 -0.234649658203125 +100134 -0.095947265625 +100135 -0.2001953125 +100136 -0.060577392578125 +100137 -0.119171142578125 +100138 -0.018402099609375 +100139 -0.024749755859375 +100140 0.032073974609375 +100141 0.085784912109375 +100142 0.074310302734375 +100143 0.178131103515625 +100144 0.09051513671875 +100145 0.215576171875 +100146 0.0872802734375 +100147 0.211456298828125 +100148 0.06927490234375 +100149 0.17523193359375 +100150 0.04718017578125 +100151 0.128753662109375 +100152 0.0355224609375 +100153 0.1019287109375 +100154 0.02423095703125 +100155 0.0743408203125 +100156 0.0118408203125 +100157 0.04327392578125 +100158 0.012542724609375 +100159 0.038177490234375 +100160 0.034576416015625 +100161 0.076263427734375 +100162 0.069671630859375 +100163 0.14105224609375 +100164 0.09515380859375 +100165 0.186431884765625 +100166 0.099334716796875 +100167 0.188812255859375 +100168 0.07757568359375 +100169 0.1390380859375 +100170 0.03204345703125 +100171 0.041778564453125 +100172 -0.025848388671875 +100173 -0.079437255859375 +100174 -0.093597412109375 +100175 -0.219390869140625 +100176 -0.16619873046875 +100177 -0.367828369140625 +100178 -0.229034423828125 +100179 -0.494873046875 +100180 -0.260467529296875 +100181 -0.556243896484375 +100182 -0.239288330078125 +100183 -0.508697509765625 +100184 -0.176788330078125 +100185 -0.3756103515625 +100186 -0.10302734375 +100187 -0.218902587890625 +100188 -0.030120849609375 +100189 -0.063751220703125 +100190 0.042877197265625 +100191 0.091552734375 +100192 0.110748291015625 +100193 0.23602294921875 +100194 0.160614013671875 +100195 0.342987060546875 +100196 0.1842041015625 +100197 0.39520263671875 +100198 0.17999267578125 +100199 0.389373779296875 +100200 0.147430419921875 +100201 0.324249267578125 +100202 0.098388671875 +100203 0.224090576171875 +100204 0.050140380859375 +100205 0.124267578125 +100206 0.00860595703125 +100207 0.037078857421875 +100208 -0.012908935546875 +100209 -0.010101318359375 +100210 -0.01556396484375 +100211 -0.019439697265625 +100212 -0.0150146484375 +100213 -0.022796630859375 +100214 -0.002288818359375 +100215 -0.001556396484375 +100216 0.0283203125 +100217 0.056304931640625 +100218 0.05517578125 +100219 0.106719970703125 +100220 0.05242919921875 +100221 0.096893310546875 +100222 0.027679443359375 +100223 0.042694091796875 +100224 -0.00067138671875 +100225 -0.018035888671875 +100226 -0.028076171875 +100227 -0.07586669921875 +100228 -0.04901123046875 +100229 -0.11944580078125 +100230 -0.06884765625 +100231 -0.15972900390625 +100232 -0.0904541015625 +100233 -0.202606201171875 +100234 -0.113983154296875 +100235 -0.24859619140625 +100236 -0.143035888671875 +100237 -0.30517578125 +100238 -0.17254638671875 +100239 -0.36212158203125 +100240 -0.188720703125 +100241 -0.39141845703125 +100242 -0.173004150390625 +100243 -0.35528564453125 +100244 -0.12347412109375 +100245 -0.249969482421875 +100246 -0.04852294921875 +100247 -0.092864990234375 +100248 0.03875732421875 +100249 0.08905029296875 +100250 0.10888671875 +100251 0.2352294921875 +100252 0.148834228515625 +100253 0.318817138671875 +100254 0.167816162109375 +100255 0.358642578125 +100256 0.162445068359375 +100257 0.347747802734375 +100258 0.132476806640625 +100259 0.28564453125 +100260 0.102691650390625 +100261 0.223175048828125 +100262 0.090789794921875 +100263 0.196746826171875 +100264 0.08380126953125 +100265 0.179840087890625 +100266 0.073394775390625 +100267 0.155548095703125 +100268 0.07281494140625 +100269 0.151214599609375 +100270 0.0771484375 +100271 0.156951904296875 +100272 0.066314697265625 +100273 0.13177490234375 +100274 0.052520751953125 +100275 0.100799560546875 +100276 0.04693603515625 +100277 0.087127685546875 +100278 0.032012939453125 +100279 0.05487060546875 +100280 0.0013427734375 +100281 -0.009002685546875 +100282 -0.044830322265625 +100283 -0.10400390625 +100284 -0.10614013671875 +100285 -0.229400634765625 +100286 -0.1680908203125 +100287 -0.35552978515625 +100288 -0.210906982421875 +100289 -0.441925048828125 +100290 -0.227386474609375 +100291 -0.473846435546875 +100292 -0.22406005859375 +100293 -0.464813232421875 +100294 -0.202911376953125 +100295 -0.419097900390625 +100296 -0.1627197265625 +100297 -0.334320068359375 +100298 -0.111968994140625 +100299 -0.227935791015625 +100300 -0.06207275390625 +100301 -0.12347412109375 +100302 -0.0162353515625 +100303 -0.02764892578125 +100304 0.034423828125 +100305 0.077667236328125 +100306 0.100067138671875 +100307 0.2132568359375 +100308 0.185455322265625 +100309 0.38885498046875 +100310 0.280029296875 +100311 0.582794189453125 +100312 0.35400390625 +100313 0.734039306640625 +100314 0.38665771484375 +100315 0.800140380859375 +100316 0.3765869140625 +100317 0.7783203125 +100318 0.322113037109375 +100319 0.6651611328125 +100320 0.222686767578125 +100321 0.45965576171875 +100322 0.09649658203125 +100323 0.199188232421875 +100324 -0.024505615234375 +100325 -0.050689697265625 +100326 -0.112548828125 +100327 -0.23297119140625 +100328 -0.159149169921875 +100329 -0.33013916015625 +100330 -0.177093505859375 +100331 -0.368408203125 +100332 -0.181640625 +100333 -0.378936767578125 +100334 -0.1802978515625 +100335 -0.376983642578125 +100336 -0.18145751953125 +100337 -0.37969970703125 +100338 -0.187255859375 +100339 -0.391510009765625 +100340 -0.1844482421875 +100341 -0.385345458984375 +100342 -0.16363525390625 +100343 -0.3419189453125 +100344 -0.1353759765625 +100345 -0.28289794921875 +100346 -0.12078857421875 +100347 -0.251617431640625 +100348 -0.12860107421875 +100349 -0.266143798828125 +100350 -0.13287353515625 +100351 -0.273345947265625 +100352 -0.106170654296875 +100353 -0.216796875 +100354 -0.06365966796875 +100355 -0.128265380859375 +100356 -0.0338134765625 +100357 -0.068145751953125 +100358 -0.019805908203125 +100359 -0.0430908203125 +100360 -0.008697509765625 +100361 -0.024444580078125 +100362 0.01434326171875 +100363 0.020721435546875 +100364 0.06378173828125 +100365 0.124481201171875 +100366 0.126312255859375 +100367 0.25787353515625 +100368 0.182769775390625 +100369 0.379119873046875 +100370 0.229339599609375 +100371 0.47991943359375 +100372 0.251373291015625 +100373 0.5281982421875 +100374 0.243011474609375 +100375 0.511138916015625 +100376 0.216827392578125 +100377 0.456207275390625 +100378 0.193023681640625 +100379 0.407470703125 +100380 0.1802978515625 +100381 0.383758544921875 +100382 0.1658935546875 +100383 0.35687255859375 +100384 0.143096923828125 +100385 0.31182861328125 +100386 0.113037109375 +100387 0.250885009765625 +100388 0.071929931640625 +100389 0.1654052734375 +100390 0.010711669921875 +100391 0.035247802734375 +100392 -0.071624755859375 +100393 -0.142059326171875 +100394 -0.160919189453125 +100395 -0.33563232421875 +100396 -0.252166748046875 +100397 -0.5345458984375 +100398 -0.337615966796875 +100399 -0.72186279296875 +100400 -0.389495849609375 +100401 -0.836669921875 +100402 -0.386749267578125 +100403 -0.8326416015625 +100404 -0.3385009765625 +100405 -0.7296142578125 +100406 -0.2698974609375 +100407 -0.582550048828125 +100408 -0.20318603515625 +100409 -0.440093994140625 +100410 -0.1485595703125 +100411 -0.324310302734375 +100412 -0.0906982421875 +100413 -0.20147705078125 +100414 -0.017425537109375 +100415 -0.044647216796875 +100416 0.051910400390625 +100417 0.103973388671875 +100418 0.098052978515625 +100419 0.202392578125 +100420 0.12725830078125 +100421 0.264495849609375 +100422 0.16168212890625 +100423 0.338897705078125 +100424 0.209625244140625 +100425 0.443817138671875 +100426 0.2554931640625 +100427 0.545074462890625 +100428 0.287750244140625 +100429 0.6173095703125 +100430 0.302764892578125 +100431 0.6524658203125 +100432 0.30645751953125 +100433 0.66339111328125 +100434 0.301666259765625 +100435 0.6561279296875 +100436 0.277587890625 +100437 0.606781005859375 +100438 0.22784423828125 +100439 0.501190185546875 +100440 0.158660888671875 +100441 0.352783203125 +100442 0.076934814453125 +100443 0.176544189453125 +100444 -0.020538330078125 +100445 -0.034820556640625 +100446 -0.1231689453125 +100447 -0.258209228515625 +100448 -0.20758056640625 +100449 -0.44244384765625 +100450 -0.268218994140625 +100451 -0.5753173828125 +100452 -0.30291748046875 +100453 -0.65203857421875 +100454 -0.297576904296875 +100455 -0.641632080078125 +100456 -0.260467529296875 +100457 -0.562164306640625 +100458 -0.2119140625 +100459 -0.458038330078125 +100460 -0.16168212890625 +100461 -0.350555419921875 +100462 -0.11932373046875 +100463 -0.260528564453125 +100464 -0.086822509765625 +100465 -0.192108154296875 +100466 -0.062713623046875 +100467 -0.141937255859375 +100468 -0.043487548828125 +100469 -0.1021728515625 +100470 -0.024658203125 +100471 -0.062896728515625 +100472 -0.000701904296875 +100473 -0.011932373046875 +100474 0.033843994140625 +100475 0.062835693359375 +100476 0.07318115234375 +100477 0.148712158203125 +100478 0.115478515625 +100479 0.241729736328125 +100480 0.164031982421875 +100481 0.34912109375 +100482 0.212677001953125 +100483 0.457305908203125 +100484 0.251251220703125 +100485 0.54388427734375 +100486 0.263427734375 +100487 0.5728759765625 +100488 0.232086181640625 +100489 0.506591796875 +100490 0.16009521484375 +100491 0.351226806640625 +100492 0.065643310546875 +100493 0.146514892578125 +100494 -0.02734375 +100495 -0.05523681640625 +100496 -0.101593017578125 +100497 -0.21624755859375 +100498 -0.156341552734375 +100499 -0.334930419921875 +100500 -0.187774658203125 +100501 -0.402984619140625 +100502 -0.20538330078125 +100503 -0.4412841796875 +100504 -0.230133056640625 +100505 -0.49578857421875 +100506 -0.2591552734375 +100507 -0.5601806640625 +100508 -0.277099609375 +100509 -0.600738525390625 +100510 -0.268829345703125 +100511 -0.584228515625 +100512 -0.220123291015625 +100513 -0.47930908203125 +100514 -0.128021240234375 +100515 -0.27935791015625 +100516 -0.003753662109375 +100517 -0.0089111328125 +100518 0.123748779296875 +100519 0.268798828125 +100520 0.222137451171875 +100521 0.482818603515625 +100522 0.277923583984375 +100523 0.60369873046875 +100524 0.299713134765625 +100525 0.650421142578125 +100526 0.30621337890625 +100527 0.66400146484375 +100528 0.296051025390625 +100529 0.6414794921875 +100530 0.2645263671875 +100531 0.572540283203125 +100532 0.230316162109375 +100533 0.498138427734375 +100534 0.203094482421875 +100535 0.439453125 +100536 0.173370361328125 +100537 0.375518798828125 +100538 0.12664794921875 +100539 0.274505615234375 +100540 0.05035400390625 +100541 0.1087646484375 +100542 -0.0452880859375 +100543 -0.099395751953125 +100544 -0.145782470703125 +100545 -0.3182373046875 +100546 -0.251617431640625 +100547 -0.5489501953125 +100548 -0.35467529296875 +100549 -0.7738037109375 +100550 -0.4307861328125 +100551 -0.86383056640625 +100552 -0.464752197265625 +100553 -0.870391845703125 +100554 -0.46466064453125 +100555 -0.86895751953125 +100556 -0.436492919921875 +100557 -0.861053466796875 +100558 -0.37237548828125 +100559 -0.765869140625 +100560 -0.26715087890625 +100561 -0.5301513671875 +100562 -0.124114990234375 +100563 -0.214691162109375 +100564 0.037078857421875 +100565 0.137359619140625 +100566 0.1929931640625 +100567 0.474822998046875 +100568 0.327362060546875 +100569 0.76239013671875 +100570 0.427825927734375 +100571 0.867462158203125 +100572 0.49456787109375 +100573 0.870361328125 +100574 0.522308349609375 +100575 0.86480712890625 +100576 0.513458251953125 +100577 0.831817626953125 +100578 0.4791259765625 +100579 0.677581787109375 +100580 0.42193603515625 +100581 0.495880126953125 +100582 0.35040283203125 +100583 0.30767822265625 +100584 0.2655029296875 +100585 0.116180419921875 +100586 0.152801513671875 +100587 -0.110748291015625 +100588 0.009185791015625 +100589 -0.381805419921875 +100590 -0.14581298828125 +100591 -0.6572265625 +100592 -0.28485107421875 +100593 -0.857421875 +100594 -0.388336181640625 +100595 -0.870391845703125 +100596 -0.4530029296875 +100597 -0.870391845703125 +100598 -0.4910888671875 +100599 -0.86444091796875 +100600 -0.518829345703125 +100601 -0.85723876953125 +100602 -0.52783203125 +100603 -0.790008544921875 +100604 -0.49334716796875 +100605 -0.62847900390625 +100606 -0.413909912109375 +100607 -0.3956298828125 +100608 -0.3045654296875 +100609 -0.126708984375 +100610 -0.17779541015625 +100611 0.150115966796875 +100612 -0.039276123046875 +100613 0.424041748046875 +100614 0.098876953125 +100615 0.670623779296875 +100616 0.21966552734375 +100617 0.854522705078125 +100618 0.315093994140625 +100619 0.866485595703125 +100620 0.37823486328125 +100621 0.86920166015625 +100622 0.41650390625 +100623 0.8653564453125 +100624 0.4354248046875 +100625 0.857147216796875 +100626 0.433685302734375 +100627 0.766845703125 +100628 0.413543701171875 +100629 0.628509521484375 +100630 0.372314453125 +100631 0.462127685546875 +100632 0.3211669921875 +100633 0.297210693359375 +100634 0.265716552734375 +100635 0.14862060546875 +100636 0.1966552734375 +100637 -0.00537109375 +100638 0.11761474609375 +100639 -0.15753173828125 +100640 0.027496337890625 +100641 -0.31304931640625 +100642 -0.079193115234375 +100643 -0.48876953125 +100644 -0.182220458984375 +100645 -0.6416015625 +100646 -0.270751953125 +100647 -0.751373291015625 +100648 -0.35430908203125 +100649 -0.84619140625 +100650 -0.426513671875 +100651 -0.861297607421875 +100652 -0.47320556640625 +100653 -0.863250732421875 +100654 -0.480987548828125 +100655 -0.856597900390625 +100656 -0.455108642578125 +100657 -0.7498779296875 +100658 -0.420318603515625 +100659 -0.624542236328125 +100660 -0.367523193359375 +100661 -0.47808837890625 +100662 -0.27227783203125 +100663 -0.253387451171875 +100664 -0.154266357421875 +100665 0.003692626953125 +100666 -0.042877197265625 +100667 0.2257080078125 +100668 0.066802978515625 +100669 0.427154541015625 +100670 0.188201904296875 +100671 0.643218994140625 +100672 0.31695556640625 +100673 0.855926513671875 +100674 0.42822265625 +100675 0.870361328125 +100676 0.500823974609375 +100677 0.870361328125 +100678 0.537689208984375 +100679 0.862762451171875 +100680 0.53753662109375 +100681 0.79669189453125 +100682 0.496429443359375 +100683 0.595794677734375 +100684 0.4268798828125 +100685 0.362152099609375 +100686 0.340972900390625 +100687 0.1270751953125 +100688 0.2479248046875 +100689 -0.086944580078125 +100690 0.148956298828125 +100691 -0.2784423828125 +100692 0.02960205078125 +100693 -0.484832763671875 +100694 -0.117889404296875 +100695 -0.729583740234375 +100696 -0.27178955078125 +100697 -0.86688232421875 +100698 -0.404937744140625 +100699 -0.870391845703125 +100700 -0.514984130859375 +100701 -0.86859130859375 +100702 -0.600830078125 +100703 -0.86279296875 +100704 -0.6470947265625 +100705 -0.817962646484375 +100706 -0.634490966796875 +100707 -0.6116943359375 +100708 -0.56005859375 +100709 -0.3128662109375 +100710 -0.43817138671875 +100711 0.039398193359375 +100712 -0.2774658203125 +100713 0.422821044921875 +100714 -0.092254638671875 +100715 0.805145263671875 +100716 0.0882568359375 +100717 0.870361328125 +100718 0.239593505859375 +100719 0.870361328125 +100720 0.356475830078125 +100721 0.860015869140625 +100722 0.435302734375 +100723 0.727935791015625 +100724 0.473358154296875 +100725 0.48114013671875 +100726 0.480560302734375 +100727 0.2059326171875 +100728 0.46624755859375 +100729 -0.06103515625 +100730 0.43450927734375 +100731 -0.29913330078125 +100732 0.37908935546875 +100733 -0.516204833984375 +100734 0.29345703125 +100735 -0.7252197265625 +100736 0.188262939453125 +100737 -0.85980224609375 +100738 0.0782470703125 +100739 -0.870391845703125 +100740 -0.023773193359375 +100741 -0.870391845703125 +100742 -0.0968017578125 +100743 -0.858062744140625 +100744 -0.138641357421875 +100745 -0.673004150390625 +100746 -0.171112060546875 +100747 -0.42694091796875 +100748 -0.212615966796875 +100749 -0.2100830078125 +100750 -0.26177978515625 +100751 -0.0362548828125 +100752 -0.305877685546875 +100753 0.10943603515625 +100754 -0.336151123046875 +100755 0.23516845703125 +100756 -0.334808349609375 +100757 0.373687744140625 +100758 -0.302520751953125 +100759 0.517791748046875 +100760 -0.2659912109375 +100761 0.602783203125 +100762 -0.22308349609375 +100763 0.635711669921875 +100764 -0.15985107421875 +100765 0.655181884765625 +100766 -0.080718994140625 +100767 0.65948486328125 +100768 0.010498046875 +100769 0.651275634765625 +100770 0.10302734375 +100771 0.61846923828125 +100772 0.180755615234375 +100773 0.53753662109375 +100774 0.235565185546875 +100775 0.404144287109375 +100776 0.262939453125 +100777 0.22186279296875 +100778 0.263031005859375 +100779 0.003997802734375 +100780 0.243194580078125 +100781 -0.22100830078125 +100782 0.2119140625 +100783 -0.42449951171875 +100784 0.1781005859375 +100785 -0.579833984375 +100786 0.159820556640625 +100787 -0.641876220703125 +100788 0.154266357421875 +100789 -0.6177978515625 +100790 0.134185791015625 +100791 -0.575531005859375 +100792 0.097503662109375 +100793 -0.526336669921875 +100794 0.06646728515625 +100795 -0.42645263671875 +100796 0.053009033203125 +100797 -0.2581787109375 +100798 0.0421142578125 +100799 -0.068695068359375 +100800 0.017852783203125 +100801 0.09222412109375 +100802 -0.011474609375 +100803 0.232147216796875 +100804 -0.041168212890625 +100805 0.3509521484375 +100806 -0.08349609375 +100807 0.410064697265625 +100808 -0.150604248046875 +100809 0.372955322265625 +100810 -0.23345947265625 +100811 0.2554931640625 +100812 -0.309814453125 +100813 0.10711669921875 +100814 -0.371337890625 +100815 -0.052886962890625 +100816 -0.4027099609375 +100817 -0.186279296875 +100818 -0.380340576171875 +100819 -0.23291015625 +100820 -0.3140869140625 +100821 -0.209442138671875 +100822 -0.232147216796875 +100823 -0.174163818359375 +100824 -0.138336181640625 +100825 -0.126739501953125 +100826 -0.02880859375 +100827 -0.048126220703125 +100828 0.084136962890625 +100829 0.0426025390625 +100830 0.180389404296875 +100831 0.10748291015625 +100832 0.2540283203125 +100833 0.1409912109375 +100834 0.32489013671875 +100835 0.19708251953125 +100836 0.389923095703125 +100837 0.273651123046875 +100838 0.42529296875 +100839 0.31768798828125 +100840 0.43560791015625 +100841 0.341094970703125 +100842 0.4315185546875 +100843 0.368011474609375 +100844 0.403350830078125 +100845 0.37249755859375 +100846 0.330322265625 +100847 0.30072021484375 +100848 0.2147216796875 +100849 0.1517333984375 +100850 0.08502197265625 +100851 -0.01470947265625 +100852 -0.05096435546875 +100853 -0.1883544921875 +100854 -0.191253662109375 +100855 -0.372711181640625 +100856 -0.309661865234375 +100857 -0.51397705078125 +100858 -0.385986328125 +100859 -0.57177734375 +100860 -0.414794921875 +100861 -0.53948974609375 +100862 -0.40167236328125 +100863 -0.43511962890625 +100864 -0.3614501953125 +100865 -0.2962646484375 +100866 -0.309814453125 +100867 -0.161102294921875 +100868 -0.252593994140625 +100869 -0.0435791015625 +100870 -0.188812255859375 +100871 0.060394287109375 +100872 -0.125457763671875 +100873 0.13665771484375 +100874 -0.070465087890625 +100875 0.170135498046875 +100876 -0.02435302734375 +100877 0.16552734375 +100878 0.023895263671875 +100879 0.15728759765625 +100880 0.0736083984375 +100881 0.150787353515625 +100882 0.1123046875 +100883 0.12200927734375 +100884 0.1409912109375 +100885 0.080108642578125 +100886 0.16778564453125 +100887 0.05126953125 +100888 0.201751708984375 +100889 0.062896728515625 +100890 0.23260498046875 +100891 0.09271240234375 +100892 0.240509033203125 +100893 0.092987060546875 +100894 0.231292724609375 +100895 0.07855224609375 +100896 0.21136474609375 +100897 0.06427001953125 +100898 0.1756591796875 +100899 0.0347900390625 +100900 0.125 +100901 -0.01171875 +100902 0.069061279296875 +100903 -0.056060791015625 +100904 0.027191162109375 +100905 -0.055511474609375 +100906 0.001617431640625 +100907 -0.010467529296875 +100908 -0.02679443359375 +100909 0.02508544921875 +100910 -0.06591796875 +100911 0.025665283203125 +100912 -0.103302001953125 +100913 0.017333984375 +100914 -0.13653564453125 +100915 0.00189208984375 +100916 -0.16876220703125 +100917 -0.03173828125 +100918 -0.19439697265625 +100919 -0.071502685546875 +100920 -0.220367431640625 +100921 -0.13543701171875 +100922 -0.245513916015625 +100923 -0.219970703125 +100924 -0.26068115234375 +100925 -0.300506591796875 +100926 -0.266754150390625 +100927 -0.376312255859375 +100928 -0.252777099609375 +100929 -0.416107177734375 +100930 -0.2010498046875 +100931 -0.371124267578125 +100932 -0.113861083984375 +100933 -0.242279052734375 +100934 -0.00927734375 +100935 -0.069732666015625 +100936 0.102386474609375 +100937 0.125640869140625 +100938 0.206878662109375 +100939 0.31268310546875 +100940 0.288177490234375 +100941 0.45501708984375 +100942 0.345947265625 +100943 0.554779052734375 +100944 0.37890625 +100945 0.61065673828125 +100946 0.381988525390625 +100947 0.610931396484375 +100948 0.3455810546875 +100949 0.531463623046875 +100950 0.276580810546875 +100951 0.3883056640625 +100952 0.1971435546875 +100953 0.23468017578125 +100954 0.1182861328125 +100955 0.095245361328125 +100956 0.05181884765625 +100957 -0.00396728515625 +100958 0.00506591796875 +100959 -0.04852294921875 +100960 -0.027008056640625 +100961 -0.055145263671875 +100962 -0.063568115234375 +100963 -0.0758056640625 +100964 -0.1143798828125 +100965 -0.138702392578125 +100966 -0.164276123046875 +100967 -0.209197998046875 +100968 -0.212860107421875 +100969 -0.289031982421875 +100970 -0.259674072265625 +100971 -0.37884521484375 +100972 -0.295318603515625 +100973 -0.456329345703125 +100974 -0.31768798828125 +100975 -0.51641845703125 +100976 -0.3111572265625 +100977 -0.519287109375 +100978 -0.27362060546875 +100979 -0.458251953125 +100980 -0.2265625 +100981 -0.384796142578125 +100982 -0.18096923828125 +100983 -0.323699951171875 +100984 -0.13580322265625 +100985 -0.269287109375 +100986 -0.081878662109375 +100987 -0.1951904296875 +100988 -0.019989013671875 +100989 -0.100006103515625 +100990 0.037841796875 +100991 -0.01055908203125 +100992 0.1025390625 +100993 0.1033935546875 +100994 0.176055908203125 +100995 0.24908447265625 +100996 0.236328125 +100997 0.373199462890625 +100998 0.275848388671875 +100999 0.45806884765625 +101000 0.297576904296875 +101001 0.511474609375 +101002 0.314422607421875 +101003 0.565399169921875 +101004 0.32342529296875 +101005 0.61138916015625 +101006 0.30133056640625 +101007 0.5897216796875 +101008 0.24505615234375 +101009 0.4906005859375 +101010 0.16259765625 +101011 0.33148193359375 +101012 0.0692138671875 +101013 0.147796630859375 +101014 -0.01727294921875 +101015 -0.01873779296875 +101016 -0.084625244140625 +101017 -0.140289306640625 +101018 -0.121917724609375 +101019 -0.191986083984375 +101020 -0.13250732421875 +101021 -0.184295654296875 +101022 -0.133575439453125 +101023 -0.161834716796875 +101024 -0.141448974609375 +101025 -0.166595458984375 +101026 -0.154083251953125 +101027 -0.19390869140625 +101028 -0.163726806640625 +101029 -0.22442626953125 +101030 -0.179290771484375 +101031 -0.279754638671875 +101032 -0.192901611328125 +101033 -0.3389892578125 +101034 -0.1861572265625 +101035 -0.3543701171875 +101036 -0.168731689453125 +101037 -0.348175048828125 +101038 -0.143707275390625 +101039 -0.32598876953125 +101040 -0.100189208984375 +101041 -0.2581787109375 +101042 -0.037078857421875 +101043 -0.139801025390625 +101044 0.038970947265625 +101045 0.014617919921875 +101046 0.1029052734375 +101047 0.144378662109375 +101048 0.142822265625 +101049 0.221038818359375 +101050 0.168701171875 +101051 0.27069091796875 +101052 0.18060302734375 +101053 0.294036865234375 +101054 0.186737060546875 +101055 0.311767578125 +101056 0.193328857421875 +101057 0.339141845703125 +101058 0.194305419921875 +101059 0.360260009765625 +101060 0.184295654296875 +101061 0.360504150390625 +101062 0.151611328125 +101063 0.308380126953125 +101064 0.088348388671875 +101065 0.18170166015625 +101066 0.004852294921875 +101067 0.0047607421875 +101068 -0.0797119140625 +101069 -0.17559814453125 +101070 -0.146942138671875 +101071 -0.3143310546875 +101072 -0.179107666015625 +101073 -0.36785888671875 +101074 -0.185943603515625 +101075 -0.36248779296875 +101076 -0.184783935546875 +101077 -0.343536376953125 +101078 -0.17181396484375 +101079 -0.3018798828125 +101080 -0.144500732421875 +101081 -0.231414794921875 +101082 -0.097259521484375 +101083 -0.117645263671875 +101084 -0.042999267578125 +101085 0.007049560546875 +101086 -0.0035400390625 +101087 0.087982177734375 +101088 0.026214599609375 +101089 0.13946533203125 +101090 0.05072021484375 +101091 0.17425537109375 +101092 0.06768798828125 +101093 0.188201904296875 +101094 0.072540283203125 +101095 0.171234130859375 +101096 0.062744140625 +101097 0.118438720703125 +101098 0.04840087890625 +101099 0.05706787109375 +101100 0.02984619140625 +101101 -0.010711669921875 +101102 0.004119873046875 +101103 -0.0914306640625 +101104 -0.02008056640625 +101105 -0.162322998046875 +101106 -0.031585693359375 +101107 -0.194549560546875 +101108 -0.015167236328125 +101109 -0.1492919921875 +101110 0.031219482421875 +101111 -0.02166748046875 +101112 0.0826416015625 +101113 0.124053955078125 +101114 0.109375 +101115 0.211151123046875 +101116 0.112213134765625 +101117 0.240447998046875 +101118 0.103515625 +101119 0.242218017578125 +101120 0.086944580078125 +101121 0.2257080078125 +101122 0.06463623046875 +101123 0.194366455078125 +101124 0.025970458984375 +101125 0.115509033203125 +101126 -0.019927978515625 +101127 0.0128173828125 +101128 -0.05108642578125 +101129 -0.053802490234375 +101130 -0.076629638671875 +101131 -0.110626220703125 +101132 -0.111480712890625 +101133 -0.199493408203125 +101134 -0.146148681640625 +101135 -0.29437255859375 +101136 -0.15802001953125 +101137 -0.33221435546875 +101138 -0.13531494140625 +101139 -0.27972412109375 +101140 -0.095703125 +101141 -0.185333251953125 +101142 -0.06805419921875 +101143 -0.128204345703125 +101144 -0.055450439453125 +101145 -0.115692138671875 +101146 -0.047088623046875 +101147 -0.116455078125 +101148 -0.03460693359375 +101149 -0.105926513671875 +101150 -0.00762939453125 +101151 -0.053955078125 +101152 0.0367431640625 +101153 0.048797607421875 +101154 0.081939697265625 +101155 0.157318115234375 +101156 0.106201171875 +101157 0.212005615234375 +101158 0.111328125 +101159 0.218475341796875 +101160 0.1190185546875 +101161 0.23724365234375 +101162 0.142608642578125 +101163 0.30535888671875 +101164 0.167236328125 +101165 0.38128662109375 +101166 0.1712646484375 +101167 0.404449462890625 +101168 0.16204833984375 +101169 0.3944091796875 +101170 0.153411865234375 +101171 0.3885498046875 +101172 0.13702392578125 +101173 0.362640380859375 +101174 0.0977783203125 +101175 0.27362060546875 +101176 0.034515380859375 +101177 0.11712646484375 +101178 -0.03369140625 +101179 -0.054901123046875 +101180 -0.087921142578125 +101181 -0.19085693359375 +101182 -0.126129150390625 +101183 -0.28570556640625 +101184 -0.148101806640625 +101185 -0.339263916015625 +101186 -0.163055419921875 +101187 -0.3775634765625 +101188 -0.187225341796875 +101189 -0.445709228515625 +101190 -0.217559814453125 +101191 -0.535064697265625 +101192 -0.248260498046875 +101193 -0.629058837890625 +101194 -0.2686767578125 +101195 -0.697601318359375 +101196 -0.26580810546875 +101197 -0.70391845703125 +101198 -0.23797607421875 +101199 -0.6424560546875 +101200 -0.1776123046875 +101201 -0.491241455078125 +101202 -0.090606689453125 +101203 -0.265716552734375 +101204 0.00189208984375 +101205 -0.023712158203125 +101206 0.08770751953125 +101207 0.201751708984375 +101208 0.154052734375 +101209 0.375823974609375 +101210 0.1959228515625 +101211 0.485076904296875 +101212 0.227386474609375 +101213 0.56884765625 +101214 0.25115966796875 +101215 0.634765625 +101216 0.2509765625 +101217 0.63763427734375 +101218 0.22283935546875 +101219 0.5660400390625 +101220 0.185638427734375 +101221 0.4720458984375 +101222 0.158050537109375 +101223 0.40692138671875 +101224 0.1429443359375 +101225 0.3778076171875 +101226 0.137786865234375 +101227 0.376953125 +101228 0.13116455078125 +101229 0.371978759765625 +101230 0.10540771484375 +101231 0.313140869140625 +101232 0.055023193359375 +101233 0.184417724609375 +101234 -0.0106201171875 +101235 0.011199951171875 +101236 -0.078582763671875 +101237 -0.171051025390625 +101238 -0.139801025390625 +101239 -0.33740234375 +101240 -0.18853759765625 +101241 -0.47198486328125 +101242 -0.2196044921875 +101243 -0.560394287109375 +101244 -0.225128173828125 +101245 -0.58056640625 +101246 -0.210662841796875 +101247 -0.54754638671875 +101248 -0.193389892578125 +101249 -0.508575439453125 +101250 -0.1719970703125 +101251 -0.459503173828125 +101252 -0.144561767578125 +101253 -0.394378662109375 +101254 -0.125457763671875 +101255 -0.35260009765625 +101256 -0.106842041015625 +101257 -0.31170654296875 +101258 -0.06219482421875 +101259 -0.197418212890625 +101260 0.0089111328125 +101261 -0.007965087890625 +101262 0.088653564453125 +101263 0.207489013671875 +101264 0.16259765625 +101265 0.409210205078125 +101266 0.2216796875 +101267 0.57208251953125 +101268 0.25506591796875 +101269 0.66595458984375 +101270 0.251251220703125 +101271 0.65875244140625 +101272 0.2164306640625 +101273 0.56744384765625 +101274 0.164886474609375 +101275 0.431396484375 +101276 0.112579345703125 +101277 0.29443359375 +101278 0.069000244140625 +101279 0.182464599609375 +101280 0.02288818359375 +101281 0.06365966796875 +101282 -0.03057861328125 +101283 -0.075958251953125 +101284 -0.0743408203125 +101285 -0.189422607421875 +101286 -0.10650634765625 +101287 -0.271942138671875 +101288 -0.1337890625 +101289 -0.342529296875 +101290 -0.142822265625 +101291 -0.364166259765625 +101292 -0.130096435546875 +101293 -0.327239990234375 +101294 -0.111846923828125 +101295 -0.2769775390625 +101296 -0.1026611328125 +101297 -0.253692626953125 +101298 -0.097625732421875 +101299 -0.24365234375 +101300 -0.079376220703125 +101301 -0.1983642578125 +101302 -0.0474853515625 +101303 -0.116241455078125 +101304 -0.01629638671875 +101305 -0.036834716796875 +101306 0.01220703125 +101307 0.034881591796875 +101308 0.035125732421875 +101309 0.09124755859375 +101310 0.043914794921875 +101311 0.10888671875 +101312 0.052001953125 +101313 0.125518798828125 +101314 0.065277099609375 +101315 0.15771484375 +101316 0.0738525390625 +101317 0.17828369140625 +101318 0.071868896484375 +101319 0.17108154296875 +101320 0.057098388671875 +101321 0.129974365234375 +101322 0.039459228515625 +101323 0.082427978515625 +101324 0.018707275390625 +101325 0.027679443359375 +101326 -0.016357421875 +101327 -0.065643310546875 +101328 -0.0518798828125 +101329 -0.15936279296875 +101330 -0.0732421875 +101331 -0.21307373046875 +101332 -0.0831298828125 +101333 -0.234649658203125 +101334 -0.072845458984375 +101335 -0.2001953125 +101336 -0.045684814453125 +101337 -0.119171142578125 +101338 -0.013458251953125 +101339 -0.024749755859375 +101340 0.024871826171875 +101341 0.085784912109375 +101342 0.0570068359375 +101343 0.178131103515625 +101344 0.06976318359375 +101345 0.215576171875 +101346 0.0679931640625 +101347 0.211456298828125 +101348 0.05511474609375 +101349 0.17523193359375 +101350 0.038970947265625 +101351 0.128753662109375 +101352 0.030303955078125 +101353 0.1019287109375 +101354 0.021697998046875 +101355 0.0743408203125 +101356 0.012054443359375 +101357 0.04327392578125 +101358 0.01190185546875 +101359 0.038177490234375 +101360 0.027374267578125 +101361 0.076263427734375 +101362 0.052398681640625 +101363 0.14105224609375 +101364 0.070281982421875 +101365 0.186431884765625 +101366 0.07244873046875 +101367 0.188812255859375 +101368 0.055572509765625 +101369 0.1390380859375 +101370 0.02130126953125 +101371 0.041778564453125 +101372 -0.021942138671875 +101373 -0.079437255859375 +101374 -0.072296142578125 +101375 -0.219390869140625 +101376 -0.125701904296875 +101377 -0.367828369140625 +101378 -0.170928955078125 +101379 -0.494873046875 +101380 -0.192962646484375 +101381 -0.556243896484375 +101382 -0.1778564453125 +101383 -0.508697509765625 +101384 -0.133514404296875 +101385 -0.3756103515625 +101386 -0.080535888671875 +101387 -0.218902587890625 +101388 -0.027435302734375 +101389 -0.063751220703125 +101390 0.02606201171875 +101391 0.091552734375 +101392 0.07611083984375 +101393 0.23602294921875 +101394 0.113800048828125 +101395 0.342987060546875 +101396 0.13330078125 +101397 0.39520263671875 +101398 0.133392333984375 +101399 0.389373779296875 +101400 0.11358642578125 +101401 0.324249267578125 +101402 0.081787109375 +101403 0.224090576171875 +101404 0.049560546875 +101405 0.124267578125 +101406 0.02093505859375 +101407 0.037078857421875 +101408 0.0048828125 +101409 -0.010101318359375 +101410 0.000732421875 +101411 -0.019439697265625 +101412 -0.0018310546875 +101413 -0.022796630859375 +101414 0.003387451171875 +101415 -0.001556396484375 +101416 0.02044677734375 +101417 0.056304931640625 +101418 0.035003662109375 +101419 0.106719970703125 +101420 0.02984619140625 +101421 0.096893310546875 +101422 0.01031494140625 +101423 0.042694091796875 +101424 -0.011077880859375 +101425 -0.018035888671875 +101426 -0.031158447265625 +101427 -0.07586669921875 +101428 -0.046173095703125 +101429 -0.11944580078125 +101430 -0.0596923828125 +101431 -0.15972900390625 +101432 -0.073638916015625 +101433 -0.202606201171875 +101434 -0.088165283203125 +101435 -0.24859619140625 +101436 -0.10577392578125 +101437 -0.30517578125 +101438 -0.123199462890625 +101439 -0.36212158203125 +101440 -0.131317138671875 +101441 -0.39141845703125 +101442 -0.117828369140625 +101443 -0.35528564453125 +101444 -0.08160400390625 +101445 -0.249969482421875 +101446 -0.028472900390625 +101447 -0.092864990234375 +101448 0.032623291015625 +101449 0.08905029296875 +101450 0.081756591796875 +101451 0.2352294921875 +101452 0.110076904296875 +101453 0.318817138671875 +101454 0.12371826171875 +101455 0.358642578125 +101456 0.120391845703125 +101457 0.347747802734375 +101458 0.09991455078125 +101459 0.28564453125 +101460 0.0789794921875 +101461 0.223175048828125 +101462 0.069549560546875 +101463 0.196746826171875 +101464 0.06298828125 +101465 0.179840087890625 +101466 0.053802490234375 +101467 0.155548095703125 +101468 0.051055908203125 +101469 0.151214599609375 +101470 0.05157470703125 +101471 0.156951904296875 +101472 0.041961669921875 +101473 0.13177490234375 +101474 0.030548095703125 +101475 0.100799560546875 +101476 0.02496337890625 +101477 0.087127685546875 +101478 0.013519287109375 +101479 0.05487060546875 +101480 -0.00799560546875 +101481 -0.009002685546875 +101482 -0.039398193359375 +101483 -0.10400390625 +101484 -0.0804443359375 +101485 -0.229400634765625 +101486 -0.121429443359375 +101487 -0.35552978515625 +101488 -0.14910888671875 +101489 -0.441925048828125 +101490 -0.15869140625 +101491 -0.473846435546875 +101492 -0.1546630859375 +101493 -0.464813232421875 +101494 -0.13848876953125 +101495 -0.419097900390625 +101496 -0.109466552734375 +101497 -0.334320068359375 +101498 -0.0733642578125 +101499 -0.227935791015625 +101500 -0.0379638671875 +101501 -0.12347412109375 +101502 -0.00555419921875 +101503 -0.02764892578125 +101504 0.029754638671875 +101505 0.077667236328125 +101506 0.074737548828125 +101507 0.2132568359375 +101508 0.132568359375 +101509 0.38885498046875 +101510 0.196136474609375 +101511 0.582794189453125 +101512 0.24542236328125 +101513 0.734039306640625 +101514 0.266510009765625 +101515 0.800140380859375 +101516 0.258544921875 +101517 0.7783203125 +101518 0.220458984375 +101519 0.6651611328125 +101520 0.1519775390625 +101521 0.45965576171875 +101522 0.0654296875 +101523 0.199188232421875 +101524 -0.017608642578125 +101525 -0.050689697265625 +101526 -0.078338623046875 +101527 -0.23297119140625 +101528 -0.11102294921875 +101529 -0.33013916015625 +101530 -0.12420654296875 +101531 -0.368408203125 +101532 -0.1280517578125 +101533 -0.378936767578125 +101534 -0.127593994140625 +101535 -0.376983642578125 +101536 -0.128448486328125 +101537 -0.37969970703125 +101538 -0.132080078125 +101539 -0.391510009765625 +101540 -0.129608154296875 +101541 -0.385345458984375 +101542 -0.11474609375 +101543 -0.3419189453125 +101544 -0.094635009765625 +101545 -0.28289794921875 +101546 -0.08349609375 +101547 -0.251617431640625 +101548 -0.087310791015625 +101549 -0.266143798828125 +101550 -0.0887451171875 +101551 -0.273345947265625 +101552 -0.069305419921875 +101553 -0.216796875 +101554 -0.039459228515625 +101555 -0.128265380859375 +101556 -0.01904296875 +101557 -0.068145751953125 +101558 -0.01031494140625 +101559 -0.0430908203125 +101560 -0.003875732421875 +101561 -0.024444580078125 +101562 0.01104736328125 +101563 0.020721435546875 +101564 0.044921875 +101565 0.124481201171875 +101566 0.088287353515625 +101567 0.25787353515625 +101568 0.127471923828125 +101569 0.379119873046875 +101570 0.1597900390625 +101571 0.47991943359375 +101572 0.174774169921875 +101573 0.5281982421875 +101574 0.16827392578125 +101575 0.511138916015625 +101576 0.14935302734375 +101577 0.456207275390625 +101578 0.13250732421875 +101579 0.407470703125 +101580 0.12396240234375 +101581 0.383758544921875 +101582 0.114471435546875 +101583 0.35687255859375 +101584 0.099151611328125 +101585 0.31182861328125 +101586 0.078765869140625 +101587 0.250885009765625 +101588 0.050506591796875 +101589 0.1654052734375 +101590 0.0078125 +101591 0.035247802734375 +101592 -0.05010986328125 +101593 -0.142059326171875 +101594 -0.1131591796875 +101595 -0.33563232421875 +101596 -0.17779541015625 +101597 -0.5345458984375 +101598 -0.23846435546875 +101599 -0.72186279296875 +101600 -0.275238037109375 +101601 -0.836669921875 +101602 -0.272979736328125 +101603 -0.8326416015625 +101604 -0.238250732421875 +101605 -0.7296142578125 +101606 -0.18914794921875 +101607 -0.582550048828125 +101608 -0.14166259765625 +101609 -0.440093994140625 +101610 -0.10308837890625 +101611 -0.324310302734375 +101612 -0.0623779296875 +101613 -0.20147705078125 +101614 -0.01068115234375 +101615 -0.044647216796875 +101616 0.038116455078125 +101617 0.103973388671875 +101618 0.070220947265625 +101619 0.202392578125 +101620 0.090179443359375 +101621 0.264495849609375 +101622 0.113983154296875 +101623 0.338897705078125 +101624 0.14764404296875 +101625 0.443817138671875 +101626 0.17999267578125 +101627 0.545074462890625 +101628 0.202789306640625 +101629 0.6173095703125 +101630 0.21343994140625 +101631 0.6524658203125 +101632 0.2158203125 +101633 0.66339111328125 +101634 0.211822509765625 +101635 0.6561279296875 +101636 0.194244384765625 +101637 0.606781005859375 +101638 0.15911865234375 +101639 0.501190185546875 +101640 0.11065673828125 +101641 0.352783203125 +101642 0.053619384765625 +101643 0.176544189453125 +101644 -0.013824462890625 +101645 -0.034820556640625 +101646 -0.08453369140625 +101647 -0.258209228515625 +101648 -0.14312744140625 +101649 -0.44244384765625 +101650 -0.18572998046875 +101651 -0.5753173828125 +101652 -0.210784912109375 +101653 -0.65203857421875 +101654 -0.209014892578125 +101655 -0.641632080078125 +101656 -0.18572998046875 +101657 -0.562164306640625 +101658 -0.154083251953125 +101659 -0.458038330078125 +101660 -0.12042236328125 +101661 -0.350555419921875 +101662 -0.091064453125 +101663 -0.260528564453125 +101664 -0.067413330078125 +101665 -0.192108154296875 +101666 -0.04864501953125 +101667 -0.141937255859375 +101668 -0.03265380859375 +101669 -0.1021728515625 +101670 -0.016754150390625 +101671 -0.062896728515625 +101672 0.00238037109375 +101673 -0.011932373046875 +101674 0.02813720703125 +101675 0.062835693359375 +101676 0.05657958984375 +101677 0.148712158203125 +101678 0.086334228515625 +101679 0.241729736328125 +101680 0.119476318359375 +101681 0.34912109375 +101682 0.151947021484375 +101683 0.457305908203125 +101684 0.177093505859375 +101685 0.54388427734375 +101686 0.184326171875 +101687 0.5728759765625 +101688 0.16259765625 +101689 0.506591796875 +101690 0.1138916015625 +101691 0.351226806640625 +101692 0.05010986328125 +101693 0.146514892578125 +101694 -0.013031005859375 +101695 -0.05523681640625 +101696 -0.064178466796875 +101697 -0.21624755859375 +101698 -0.102630615234375 +101699 -0.334930419921875 +101700 -0.12579345703125 +101701 -0.402984619140625 +101702 -0.1396484375 +101703 -0.4412841796875 +101704 -0.15771484375 +101705 -0.49578857421875 +101706 -0.17803955078125 +101707 -0.5601806640625 +101708 -0.190582275390625 +101709 -0.600738525390625 +101710 -0.18548583984375 +101711 -0.584228515625 +101712 -0.15350341796875 +101713 -0.47930908203125 +101714 -0.0927734375 +101715 -0.27935791015625 +101716 -0.010650634765625 +101717 -0.0089111328125 +101718 0.073974609375 +101719 0.268798828125 +101720 0.139984130859375 +101721 0.482818603515625 +101722 0.178497314453125 +101723 0.60369873046875 +101724 0.194976806640625 +101725 0.650421142578125 +101726 0.201416015625 +101727 0.66400146484375 +101728 0.19683837890625 +101729 0.6414794921875 +101730 0.178070068359375 +101731 0.572540283203125 +101732 0.15716552734375 +101733 0.498138427734375 +101734 0.140380859375 +101735 0.439453125 +101736 0.1214599609375 +101737 0.375518798828125 +101738 0.09100341796875 +101739 0.274505615234375 +101740 0.0408935546875 +101741 0.1087646484375 +101742 -0.022186279296875 +101743 -0.099395751953125 +101744 -0.0887451171875 +101745 -0.3182373046875 +101746 -0.1590576171875 +101747 -0.5489501953125 +101748 -0.22772216796875 +101749 -0.7738037109375 +101750 -0.2789306640625 +101751 -0.86383056640625 +101752 -0.302764892578125 +101753 -0.870391845703125 +101754 -0.304351806640625 +101755 -0.86895751953125 +101756 -0.287506103515625 +101757 -0.861053466796875 +101758 -0.247039794921875 +101759 -0.765869140625 +101760 -0.179595947265625 +101761 -0.5301513671875 +101762 -0.087249755859375 +101763 -0.214691162109375 +101764 0.017242431640625 +101765 0.137359619140625 +101766 0.118682861328125 +101767 0.474822998046875 +101768 0.206512451171875 +101769 0.76239013671875 +101770 0.27264404296875 +101771 0.867462158203125 +101772 0.317138671875 +101773 0.870361328125 +101774 0.33648681640625 +101775 0.86480712890625 +101776 0.3321533203125 +101777 0.831817626953125 +101778 0.311279296875 +101779 0.677581787109375 +101780 0.2755126953125 +101781 0.495880126953125 +101782 0.23028564453125 +101783 0.30767822265625 +101784 0.17620849609375 +101785 0.116180419921875 +101786 0.103851318359375 +101787 -0.110748291015625 +101788 0.0111083984375 +101789 -0.381805419921875 +101790 -0.08929443359375 +101791 -0.6572265625 +101792 -0.179595947265625 +101793 -0.857421875 +101794 -0.247100830078125 +101795 -0.870391845703125 +101796 -0.289642333984375 +101797 -0.870391845703125 +101798 -0.315155029296875 +101799 -0.86444091796875 +101800 -0.3341064453125 +101801 -0.85723876953125 +101802 -0.34100341796875 +101803 -0.790008544921875 +101804 -0.3197021484375 +101805 -0.62847900390625 +101806 -0.26922607421875 +101807 -0.3956298828125 +101808 -0.199249267578125 +101809 -0.126708984375 +101810 -0.1177978515625 +101811 0.150115966796875 +101812 -0.0283203125 +101813 0.424041748046875 +101814 0.061187744140625 +101815 0.670623779296875 +101816 0.1392822265625 +101817 0.854522705078125 +101818 0.200714111328125 +101819 0.866485595703125 +101820 0.240936279296875 +101821 0.86920166015625 +101822 0.2652587890625 +101823 0.8653564453125 +101824 0.277618408203125 +101825 0.857147216796875 +101826 0.277099609375 +101827 0.766845703125 +101828 0.265167236328125 +101829 0.628509521484375 +101830 0.239776611328125 +101831 0.462127685546875 +101832 0.208526611328125 +101833 0.297210693359375 +101834 0.175018310546875 +101835 0.14862060546875 +101836 0.1324462890625 +101837 -0.00537109375 +101838 0.0830078125 +101839 -0.15753173828125 +101840 0.025634765625 +101841 -0.31304931640625 +101842 -0.0438232421875 +101843 -0.48876953125 +101844 -0.111480712890625 +101845 -0.6416015625 +101846 -0.16998291015625 +101847 -0.751373291015625 +101848 -0.22613525390625 +101849 -0.84619140625 +101850 -0.275543212890625 +101851 -0.861297607421875 +101852 -0.308380126953125 +101853 -0.863250732421875 +101854 -0.31524658203125 +101855 -0.856597900390625 +101856 -0.2996826171875 +101857 -0.7498779296875 +101858 -0.278778076171875 +101859 -0.624542236328125 +101860 -0.246002197265625 +101861 -0.47808837890625 +101862 -0.184051513671875 +101863 -0.253387451171875 +101864 -0.106414794921875 +101865 0.003692626953125 +101866 -0.0333251953125 +101867 0.2257080078125 +101868 0.038909912109375 +101869 0.427154541015625 +101870 0.119873046875 +101871 0.643218994140625 +101872 0.206695556640625 +101873 0.855926513671875 +101874 0.282196044921875 +101875 0.870361328125 +101876 0.3316650390625 +101877 0.870361328125 +101878 0.357208251953125 +101879 0.862762451171875 +101880 0.35791015625 +101881 0.79669189453125 +101882 0.330963134765625 +101883 0.595794677734375 +101884 0.28497314453125 +101885 0.362152099609375 +101886 0.22821044921875 +101887 0.1270751953125 +101888 0.166351318359375 +101889 -0.086944580078125 +101890 0.0997314453125 +101891 -0.2784423828125 +101892 0.01947021484375 +101893 -0.484832763671875 +101894 -0.078582763671875 +101895 -0.729583740234375 +101896 -0.1802978515625 +101897 -0.86688232421875 +101898 -0.268310546875 +101899 -0.870391845703125 +101900 -0.3408203125 +101901 -0.86859130859375 +101902 -0.3968505859375 +101903 -0.86279296875 +101904 -0.426727294921875 +101905 -0.817962646484375 +101906 -0.418426513671875 +101907 -0.6116943359375 +101908 -0.37017822265625 +101909 -0.3128662109375 +101910 -0.291107177734375 +101911 0.039398193359375 +101912 -0.186798095703125 +101913 0.422821044921875 +101914 -0.066497802734375 +101915 0.805145263671875 +101916 0.051300048828125 +101917 0.870361328125 +101918 0.15106201171875 +101919 0.870361328125 +101920 0.2291259765625 +101921 0.860015869140625 +101922 0.282958984375 +101923 0.727935791015625 +101924 0.310638427734375 +101925 0.48114013671875 +101926 0.318145751953125 +101927 0.2059326171875 +101928 0.3111572265625 +101929 -0.06103515625 +101930 0.292083740234375 +101931 -0.29913330078125 +101932 0.257049560546875 +101933 -0.516204833984375 +101934 0.202056884765625 +101935 -0.7252197265625 +101936 0.13385009765625 +101937 -0.85980224609375 +101938 0.061798095703125 +101939 -0.870391845703125 +101940 -0.005889892578125 +101941 -0.870391845703125 +101942 -0.055877685546875 +101943 -0.858062744140625 +101944 -0.0865478515625 +101945 -0.673004150390625 +101946 -0.111236572265625 +101947 -0.42694091796875 +101948 -0.141143798828125 +101949 -0.2100830078125 +101950 -0.17523193359375 +101951 -0.0362548828125 +101952 -0.205413818359375 +101953 0.10943603515625 +101954 -0.226043701171875 +101955 0.23516845703125 +101956 -0.225982666015625 +101957 0.373687744140625 +101958 -0.2056884765625 +101959 0.517791748046875 +101960 -0.181793212890625 +101961 0.602783203125 +101962 -0.153076171875 +101963 0.635711669921875 +101964 -0.1109619140625 +101965 0.655181884765625 +101966 -0.05841064453125 +101967 0.65948486328125 +101968 0.00201416015625 +101969 0.651275634765625 +101970 0.06341552734375 +101971 0.61846923828125 +101972 0.115509033203125 +101973 0.53753662109375 +101974 0.153076171875 +101975 0.404144287109375 +101976 0.173095703125 +101977 0.22186279296875 +101978 0.175537109375 +101979 0.003997802734375 +101980 0.16485595703125 +101981 -0.22100830078125 +101982 0.14630126953125 +101983 -0.42449951171875 +101984 0.125335693359375 +101985 -0.579833984375 +101986 0.113250732421875 +101987 -0.641876220703125 +101988 0.108367919921875 +101989 -0.6177978515625 +101990 0.09381103515625 +101991 -0.575531005859375 +101992 0.06842041015625 +101993 -0.526336669921875 +101994 0.04620361328125 +101995 -0.42645263671875 +101996 0.03472900390625 +101997 -0.2581787109375 +101998 0.02484130859375 +101999 -0.068695068359375 +102000 0.006805419921875 +102001 0.09222412109375 +102002 -0.0140380859375 +102003 0.232147216796875 +102004 -0.034637451171875 +102005 0.3509521484375 +102006 -0.062530517578125 +102007 0.410064697265625 +102008 -0.105224609375 +102009 0.372955322265625 +102010 -0.157073974609375 +102011 0.2554931640625 +102012 -0.2042236328125 +102013 0.10711669921875 +102014 -0.241485595703125 +102015 -0.052886962890625 +102016 -0.2593994140625 +102017 -0.186279296875 +102018 -0.243438720703125 +102019 -0.23291015625 +102020 -0.1998291015625 +102021 -0.209442138671875 +102022 -0.146270751953125 +102023 -0.174163818359375 +102024 -0.085296630859375 +102025 -0.126739501953125 +102026 -0.014617919921875 +102027 -0.048126220703125 +102028 0.05792236328125 +102029 0.0426025390625 +102030 0.11968994140625 +102031 0.10748291015625 +102032 0.166900634765625 +102033 0.1409912109375 +102034 0.211883544921875 +102035 0.19708251953125 +102036 0.252685546875 +102037 0.273651123046875 +102038 0.27447509765625 +102039 0.31768798828125 +102040 0.2801513671875 +102041 0.341094970703125 +102042 0.27642822265625 +102043 0.368011474609375 +102044 0.25732421875 +102045 0.37249755859375 +102046 0.209991455078125 +102047 0.30072021484375 +102048 0.135955810546875 +102049 0.1517333984375 +102050 0.053070068359375 +102051 -0.01470947265625 +102052 -0.03369140625 +102053 -0.1883544921875 +102054 -0.122955322265625 +102055 -0.372711181640625 +102056 -0.198333740234375 +102057 -0.51397705078125 +102058 -0.24713134765625 +102059 -0.57177734375 +102060 -0.26593017578125 +102061 -0.53948974609375 +102062 -0.258148193359375 +102063 -0.43511962890625 +102064 -0.232879638671875 +102065 -0.2962646484375 +102066 -0.199798583984375 +102067 -0.161102294921875 +102068 -0.162689208984375 +102069 -0.0435791015625 +102070 -0.121063232421875 +102071 0.060394287109375 +102072 -0.079681396484375 +102073 0.13665771484375 +102074 -0.04388427734375 +102075 0.170135498046875 +102076 -0.0140380859375 +102077 0.16552734375 +102078 0.017120361328125 +102079 0.15728759765625 +102080 0.049102783203125 +102081 0.150787353515625 +102082 0.07373046875 +102083 0.12200927734375 +102084 0.091705322265625 +102085 0.080108642578125 +102086 0.108428955078125 +102087 0.05126953125 +102088 0.129974365234375 +102089 0.062896728515625 +102090 0.14959716796875 +102091 0.09271240234375 +102092 0.154266357421875 +102093 0.092987060546875 +102094 0.1478271484375 +102095 0.07855224609375 +102096 0.13458251953125 +102097 0.06427001953125 +102098 0.111175537109375 +102099 0.0347900390625 +102100 0.078125 +102101 -0.01171875 +102102 0.041839599609375 +102103 -0.056060791015625 +102104 0.0150146484375 +102105 -0.055511474609375 +102106 -0.000885009765625 +102107 -0.010467529296875 +102108 -0.0185546875 +102109 0.02508544921875 +102110 -0.04327392578125 +102111 0.025665283203125 +102112 -0.066864013671875 +102113 0.017333984375 +102114 -0.087799072265625 +102115 0.00189208984375 +102116 -0.10821533203125 +102117 -0.03173828125 +102118 -0.12445068359375 +102119 -0.071502685546875 +102120 -0.14111328125 +102121 -0.13543701171875 +102122 -0.157470703125 +102123 -0.219970703125 +102124 -0.16748046875 +102125 -0.300506591796875 +102126 -0.171722412109375 +102127 -0.376312255859375 +102128 -0.1629638671875 +102129 -0.416107177734375 +102130 -0.12945556640625 +102131 -0.371124267578125 +102132 -0.072662353515625 +102133 -0.242279052734375 +102134 -0.004486083984375 +102135 -0.069732666015625 +102136 0.06829833984375 +102137 0.125640869140625 +102138 0.136322021484375 +102139 0.31268310546875 +102140 0.189056396484375 +102141 0.45501708984375 +102142 0.226348876953125 +102143 0.554779052734375 +102144 0.247161865234375 +102145 0.61065673828125 +102146 0.24835205078125 +102147 0.610931396484375 +102148 0.224212646484375 +102149 0.531463623046875 +102150 0.179229736328125 +102151 0.3883056640625 +102152 0.12738037109375 +102153 0.23468017578125 +102154 0.07574462890625 +102155 0.095245361328125 +102156 0.0318603515625 +102157 -0.00396728515625 +102158 0.000396728515625 +102159 -0.04852294921875 +102160 -0.021636962890625 +102161 -0.055145263671875 +102162 -0.046112060546875 +102163 -0.0758056640625 +102164 -0.079071044921875 +102165 -0.138702392578125 +102166 -0.1109619140625 +102167 -0.209197998046875 +102168 -0.14154052734375 +102169 -0.289031982421875 +102170 -0.170501708984375 +102171 -0.37884521484375 +102172 -0.1920166015625 +102173 -0.456329345703125 +102174 -0.204864501953125 +102175 -0.51641845703125 +102176 -0.199310302734375 +102177 -0.519287109375 +102178 -0.174163818359375 +102179 -0.458251953125 +102180 -0.142913818359375 +102181 -0.384796142578125 +102182 -0.112548828125 +102183 -0.323699951171875 +102184 -0.082489013671875 +102185 -0.269287109375 +102186 -0.047149658203125 +102187 -0.1951904296875 +102188 -0.007080078125 +102189 -0.100006103515625 +102190 0.030120849609375 +102191 -0.01055908203125 +102192 0.07122802734375 +102193 0.1033935546875 +102194 0.117431640625 +102195 0.24908447265625 +102196 0.15496826171875 +102197 0.373199462890625 +102198 0.17913818359375 +102199 0.45806884765625 +102200 0.191802978515625 +102201 0.511474609375 +102202 0.20111083984375 +102203 0.565399169921875 +102204 0.205291748046875 +102205 0.61138916015625 +102206 0.189910888671875 +102207 0.5897216796875 +102208 0.153106689453125 +102209 0.4906005859375 +102210 0.100006103515625 +102211 0.33148193359375 +102212 0.04022216796875 +102213 0.147796630859375 +102214 -0.015045166015625 +102215 -0.01873779296875 +102216 -0.058074951171875 +102217 -0.140289306640625 +102218 -0.082000732421875 +102219 -0.191986083984375 +102220 -0.088897705078125 +102221 -0.184295654296875 +102222 -0.089508056640625 +102223 -0.161834716796875 +102224 -0.094024658203125 +102225 -0.166595458984375 +102226 -0.1011962890625 +102227 -0.19390869140625 +102228 -0.10626220703125 +102229 -0.22442626953125 +102230 -0.114837646484375 +102231 -0.279754638671875 +102232 -0.1220703125 +102233 -0.3389892578125 +102234 -0.11651611328125 +102235 -0.3543701171875 +102236 -0.10430908203125 +102237 -0.348175048828125 +102238 -0.087432861328125 +102239 -0.32598876953125 +102240 -0.059112548828125 +102241 -0.2581787109375 +102242 -0.01873779296875 +102243 -0.139801025390625 +102244 0.029449462890625 +102245 0.014617919921875 +102246 0.069793701171875 +102247 0.144378662109375 +102248 0.09478759765625 +102249 0.221038818359375 +102250 0.110687255859375 +102251 0.27069091796875 +102252 0.117584228515625 +102253 0.294036865234375 +102254 0.12066650390625 +102255 0.311767578125 +102256 0.123809814453125 +102257 0.339141845703125 +102258 0.123077392578125 +102259 0.360260009765625 +102260 0.115264892578125 +102261 0.360504150390625 +102262 0.093658447265625 +102263 0.308380126953125 +102264 0.0537109375 +102265 0.18170166015625 +102266 0.001739501953125 +102267 0.0047607421875 +102268 -0.05072021484375 +102269 -0.17559814453125 +102270 -0.0926513671875 +102271 -0.3143310546875 +102272 -0.113433837890625 +102273 -0.36785888671875 +102274 -0.118743896484375 +102275 -0.36248779296875 +102276 -0.1187744140625 +102277 -0.343536376953125 +102278 -0.111236572265625 +102279 -0.3018798828125 +102280 -0.09466552734375 +102281 -0.231414794921875 +102282 -0.0657958984375 +102283 -0.117645263671875 +102284 -0.032318115234375 +102285 0.007049560546875 +102286 -0.007232666015625 +102287 0.087982177734375 +102288 0.012359619140625 +102289 0.13946533203125 +102290 0.028961181640625 +102291 0.17425537109375 +102292 0.041107177734375 +102293 0.188201904296875 +102294 0.04595947265625 +102295 0.171234130859375 +102296 0.041900634765625 +102297 0.118438720703125 +102298 0.034881591796875 +102299 0.05706787109375 +102300 0.02496337890625 +102301 -0.010711669921875 +102302 0.0103759765625 +102303 -0.0914306640625 +102304 -0.00372314453125 +102305 -0.162322998046875 +102306 -0.0107421875 +102307 -0.194549560546875 +102308 -0.001678466796875 +102309 -0.1492919921875 +102310 0.02471923828125 +102311 -0.02166748046875 +102312 0.053802490234375 +102313 0.124053955078125 +102314 0.068023681640625 +102315 0.211151123046875 +102316 0.067962646484375 +102317 0.240447998046875 +102318 0.061065673828125 +102319 0.242218017578125 +102320 0.049896240234375 +102321 0.2257080078125 +102322 0.035614013671875 +102323 0.194366455078125 +102324 0.011016845703125 +102325 0.115509033203125 +102326 -0.01800537109375 +102327 0.0128173828125 +102328 -0.037322998046875 +102329 -0.053802490234375 +102330 -0.0528564453125 +102331 -0.110626220703125 +102332 -0.074249267578125 +102333 -0.199493408203125 +102334 -0.095458984375 +102335 -0.29437255859375 +102336 -0.101959228515625 +102337 -0.33221435546875 +102338 -0.086181640625 +102339 -0.27972412109375 +102340 -0.059600830078125 +102341 -0.185333251953125 +102342 -0.0408935546875 +102343 -0.128204345703125 +102344 -0.032073974609375 +102345 -0.115692138671875 +102346 -0.02618408203125 +102347 -0.116455078125 +102348 -0.01788330078125 +102349 -0.105926513671875 +102350 -0.00048828125 +102351 -0.053955078125 +102352 0.02789306640625 +102353 0.048797607421875 +102354 0.05657958984375 +102355 0.157318115234375 +102356 0.071563720703125 +102357 0.212005615234375 +102358 0.074066162109375 +102359 0.218475341796875 +102360 0.078125 +102361 0.23724365234375 +102362 0.092376708984375 +102363 0.30535888671875 +102364 0.1072998046875 +102365 0.38128662109375 +102366 0.1090087890625 +102367 0.404449462890625 +102368 0.102294921875 +102369 0.3944091796875 +102370 0.0960693359375 +102371 0.3885498046875 +102372 0.08502197265625 +102373 0.362640380859375 +102374 0.0594482421875 +102375 0.27362060546875 +102376 0.018585205078125 +102377 0.11712646484375 +102378 -0.0252685546875 +102379 -0.054901123046875 +102380 -0.0599365234375 +102381 -0.19085693359375 +102382 -0.084075927734375 +102383 -0.28570556640625 +102384 -0.097564697265625 +102385 -0.339263916015625 +102386 -0.106414794921875 +102387 -0.3775634765625 +102388 -0.121124267578125 +102389 -0.445709228515625 +102390 -0.139801025390625 +102391 -0.535064697265625 +102392 -0.15875244140625 +102393 -0.629058837890625 +102394 -0.171142578125 +102395 -0.697601318359375 +102396 -0.168670654296875 +102397 -0.70391845703125 +102398 -0.150238037109375 +102399 -0.6424560546875 diff --git a/tests/circuitpython/getenv.py b/tests/circuitpython/getenv.py index 37819dd6f5f..3647b562eed 100644 --- a/tests/circuitpython/getenv.py +++ b/tests/circuitpython/getenv.py @@ -58,7 +58,7 @@ def ioctl(self, op, arg): b'key = """\n', b"key =\n", b'key="', - b"key = strings must be quoted\n", + b"key = this is an unquoted string\n", ] @@ -75,6 +75,7 @@ def run_test(key, content): run_test("key", b"") +# key12 does not exist for i in range(13): run_test(f"key{i}", content_good) @@ -82,11 +83,9 @@ def run_test(key, content): for i in range(13): run_test(f"key{i}", content_good) -run_test(f"K", b"K = 7\r\n") -print(getenv_int("K")) - # Test value without trailing newline run_test(f"noeol", b"noeol=3") +# These return None now for content in content_bad: run_test("key", content) diff --git a/tests/circuitpython/getenv.py.exp b/tests/circuitpython/getenv.py.exp index 67707eb67fd..89d654403dc 100644 --- a/tests/circuitpython/getenv.py.exp +++ b/tests/circuitpython/getenv.py.exp @@ -1,6 +1,6 @@ key None key0 'hello world' -key1 7 +key1 '7' key2 '\n' key3 'Áx' key4 'Áx' @@ -9,11 +9,11 @@ key6 '\t\r\x08' key7 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' key8 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' key9 'hello comment' -key10 127 -key11 0 +key10 '0x7f' +key11 '0' key12 None key0 'hello world' -key1 7 +key1 '7' key2 '\n' key3 'Áx' key4 'Áx' @@ -22,14 +22,12 @@ key6 '\t\r\x08' key7 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' key8 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' key9 'hello comment' -key10 127 -key11 0 +key10 '0x7f' +key11 '0' key12 None -K 7 -7 -noeol 3 -key Invalid byte '\n' -key Invalid byte '"' -key invalid syntax for integer with base 10: '' -key Invalid byte 'EOF' -key invalid syntax for integer with base 10: 'strings must be quoted' +noeol '3' +key None +key None +key None +key None +key 'this is an unquoted string' diff --git a/tests/circuitpython/synth_note_panning.py b/tests/circuitpython/synth_note_panning.py new file mode 100644 index 00000000000..3968f2dfddb --- /dev/null +++ b/tests/circuitpython/synth_note_panning.py @@ -0,0 +1,10 @@ +from synthnotehelper import * + + +@synth_test(channel_count=2) +def gen(synth): + l = LFO(sine, offset=0.0, scale=1.0, rate=2) + yield [l] + n = Note(8, panning=l) + synth.press(n) + yield 2 diff --git a/tests/circuitpython/synth_note_panning.py.exp b/tests/circuitpython/synth_note_panning.py.exp new file mode 100644 index 00000000000..7b6bd871424 --- /dev/null +++ b/tests/circuitpython/synth_note_panning.py.exp @@ -0,0 +1,16128 @@ +0.0 0.0 0.0 0.391339111328125 +0.000125 0.003173828125 0.005218505859375 0.391339111328125 +0.00025 0.003173828125 0.005218505859375 0.391339111328125 +0.000375 0.00634765625 0.01043701171875 0.391339111328125 +0.0005 0.009552001953125 0.01568603515625 0.391339111328125 +0.000625 0.009552001953125 0.01568603515625 0.391339111328125 +0.00075 0.012725830078125 0.020904541015625 0.391339111328125 +0.000875 0.012725830078125 0.020904541015625 0.391339111328125 +0.001 0.015899658203125 0.026123046875 0.391339111328125 +0.0011250000000000002 0.019073486328125 0.0313720703125 0.391339111328125 +0.00125 0.019073486328125 0.0313720703125 0.391339111328125 +0.001375 0.022247314453125 0.036590576171875 0.391339111328125 +0.0015 0.022247314453125 0.036590576171875 0.391339111328125 +0.0016250000000000002 0.02545166015625 0.04180908203125 0.391339111328125 +0.00175 0.02862548828125 0.047027587890625 0.391339111328125 +0.001875 0.02862548828125 0.047027587890625 0.391339111328125 +0.002 0.03179931640625 0.05224609375 0.391339111328125 +0.002125 0.03179931640625 0.05224609375 0.391339111328125 +0.0022500000000000004 0.034942626953125 0.05743408203125 0.391339111328125 +0.002375 0.038116455078125 0.0626220703125 0.391339111328125 +0.0025 0.038116455078125 0.0626220703125 0.391339111328125 +0.002625 0.041259765625 0.06781005859375 0.391339111328125 +0.00275 0.041259765625 0.06781005859375 0.391339111328125 +0.002875 0.04443359375 0.072998046875 0.391339111328125 +0.003 0.047576904296875 0.07818603515625 0.391339111328125 +0.003125 0.047576904296875 0.07818603515625 0.391339111328125 +0.0032500000000000004 0.05072021484375 0.083343505859375 0.391339111328125 +0.003375 0.05072021484375 0.083343505859375 0.391339111328125 +0.0035 0.053863525390625 0.0885009765625 0.391339111328125 +0.003625 0.0570068359375 0.093658447265625 0.391339111328125 +0.00375 0.0570068359375 0.093658447265625 0.391339111328125 +0.003875 0.06011962890625 0.098785400390625 0.391339111328125 +0.004 0.06011962890625 0.098785400390625 0.391339111328125 +0.004125 0.063232421875 0.103912353515625 0.391339111328125 +0.00425 0.06634521484375 0.109039306640625 0.391339111328125 +0.004375 0.06634521484375 0.109039306640625 0.391339111328125 +0.0045000000000000006 0.0694580078125 0.1141357421875 0.391339111328125 +0.004625 0.0694580078125 0.1141357421875 0.391339111328125 +0.00475 0.07257080078125 0.119232177734375 0.391339111328125 +0.004875 0.075653076171875 0.124298095703125 0.391339111328125 +0.005 0.075653076171875 0.124298095703125 0.391339111328125 +0.005125 0.0787353515625 0.129364013671875 0.391339111328125 +0.00525 0.0787353515625 0.129364013671875 0.391339111328125 +0.0053750000000000008 0.081817626953125 0.134429931640625 0.391339111328125 +0.0055 0.084869384765625 0.13946533203125 0.391339111328125 +0.005625 0.084869384765625 0.13946533203125 0.391339111328125 +0.00575 0.087921142578125 0.14447021484375 0.391339111328125 +0.005875 0.087921142578125 0.14447021484375 0.391339111328125 +0.006 0.090972900390625 0.14947509765625 0.391339111328125 +0.006125 0.093994140625 0.15447998046875 0.391339111328125 +0.00625 0.093994140625 0.15447998046875 0.391339111328125 +0.0063750000000000008 0.0970458984375 0.159454345703125 0.391339111328125 +0.006500000000000001 0.0970458984375 0.159454345703125 0.391339111328125 +0.006625 0.10003662109375 0.164398193359375 0.391339111328125 +0.00675 0.103057861328125 0.169342041015625 0.391339111328125 +0.006875 0.103057861328125 0.169342041015625 0.391339111328125 +0.007 0.106048583984375 0.17425537109375 0.391339111328125 +0.007125 0.106048583984375 0.17425537109375 0.391339111328125 +0.00725 0.1090087890625 0.17913818359375 0.391339111328125 +0.00737500000000000064 0.11199951171875 0.18402099609375 0.391339111328125 +0.0075 0.11199951171875 0.18402099609375 0.391339111328125 +0.007625 0.114959716796875 0.188873291015625 0.391339111328125 +0.00775 0.114959716796875 0.188873291015625 0.391339111328125 +0.007875 0.117889404296875 0.1937255859375 0.391339111328125 +0.008 0.120819091796875 0.19854736328125 0.391339111328125 +0.008125 0.120819091796875 0.19854736328125 0.391339111328125 +0.00825 0.123748779296875 0.203338623046875 0.391339111328125 +0.008375 0.123748779296875 0.203338623046875 0.391339111328125 +0.008500000000000001 0.12664794921875 0.208099365234375 0.391339111328125 +0.008625000000000001 0.129547119140625 0.212860107421875 0.391339111328125 +0.008750000000000001 0.129547119140625 0.212860107421875 0.391339111328125 +0.008875000000000001 0.132415771484375 0.21759033203125 0.391339111328125 +0.009000000000000001 0.132415771484375 0.21759033203125 0.391339111328125 +0.009125 0.135284423828125 0.2222900390625 0.391339111328125 +0.00925 0.13812255859375 0.226959228515625 0.391339111328125 +0.009375 0.13812255859375 0.226959228515625 0.391339111328125 +0.0095 0.140960693359375 0.231597900390625 0.391339111328125 +0.009625 0.140960693359375 0.231597900390625 0.391339111328125 +0.00975 0.143768310546875 0.236236572265625 0.391339111328125 +0.009875 0.146575927734375 0.2408447265625 0.391339111328125 +0.01 0.146575927734375 0.2408447265625 0.391339111328125 +0.010125 0.14935302734375 0.24542236328125 0.391339111328125 +0.01025 0.14935302734375 0.24542236328125 0.391339111328125 +0.010375 0.152130126953125 0.249969482421875 0.391339111328125 +0.0105 0.154876708984375 0.25445556640625 0.391339111328125 +0.010625 0.154876708984375 0.25445556640625 0.391339111328125 +0.0107500000000000016 0.157623291015625 0.25897216796875 0.391339111328125 +0.0108750000000000016 0.157623291015625 0.25897216796875 0.391339111328125 +0.011 0.160308837890625 0.263427734375 0.391339111328125 +0.011125 0.16302490234375 0.267852783203125 0.391339111328125 +0.01125 0.16302490234375 0.267852783203125 0.391339111328125 +0.011375 0.16571044921875 0.27227783203125 0.391339111328125 +0.0115 0.16571044921875 0.27227783203125 0.391339111328125 +0.011625 0.168365478515625 0.276641845703125 0.391339111328125 +0.01175 0.1710205078125 0.280975341796875 0.391339111328125 +0.011875 0.1710205078125 0.280975341796875 0.391339111328125 +0.012 0.17364501953125 0.285308837890625 0.391339111328125 +0.012125 0.17364501953125 0.285308837890625 0.391339111328125 +0.01225 0.176239013671875 0.289581298828125 0.391339111328125 +0.012375 0.1788330078125 0.2938232421875 0.391339111328125 +0.0125 0.1788330078125 0.2938232421875 0.391339111328125 +0.012625 0.181396484375 0.298065185546875 0.391339111328125 +0.0127500000000000016 0.181396484375 0.298065185546875 0.391339111328125 +0.0128750000000000016 0.1839599609375 0.30224609375 0.391339111328125 +0.013000000000000002 0.186492919921875 0.306396484375 0.391339111328125 +0.013125 0.186492919921875 0.306396484375 0.391339111328125 +0.01325 0.188995361328125 0.310516357421875 0.391339111328125 +0.013375 0.188995361328125 0.310516357421875 0.391339111328125 +0.0135 0.19146728515625 0.314605712890625 0.391339111328125 +0.013625 0.193939208984375 0.31866455078125 0.391339111328125 +0.01375 0.193939208984375 0.31866455078125 0.391339111328125 +0.013875 0.196380615234375 0.322662353515625 0.391339111328125 +0.014 0.196380615234375 0.322662353515625 0.391339111328125 +0.014125 0.19879150390625 0.32666015625 0.391339111328125 +0.01425 0.201202392578125 0.330596923828125 0.391339111328125 +0.014375 0.201202392578125 0.330596923828125 0.391339111328125 +0.0145 0.203582763671875 0.334503173828125 0.391339111328125 +0.014625 0.203582763671875 0.334503173828125 0.391339111328125 +0.0147500000000000016 0.2059326171875 0.33837890625 0.391339111328125 +0.0148750000000000013 0.208282470703125 0.34222412109375 0.391339111328125 +0.015 0.208282470703125 0.34222412109375 0.391339111328125 +0.015125 0.210601806640625 0.34600830078125 0.391339111328125 +0.01525 0.210601806640625 0.34600830078125 0.391339111328125 +0.015375 0.212860107421875 0.349761962890625 0.391339111328125 +0.0155 0.21514892578125 0.353485107421875 0.391339111328125 +0.015625 0.21514892578125 0.353485107421875 0.391339111328125 +0.01575 0.217376708984375 0.357177734375 0.391339111328125 +0.015875 0.217376708984375 0.357177734375 0.391339111328125 +0.016 0.2196044921875 0.360809326171875 0.391339111328125 +0.016125 0.2218017578125 0.36444091796875 0.391339111328125 +0.01625 0.2218017578125 0.36444091796875 0.391339111328125 +0.016375 0.223968505859375 0.36798095703125 0.391339111328125 +0.0165 0.223968505859375 0.36798095703125 0.391339111328125 +0.016625 0.226104736328125 0.37152099609375 0.391339111328125 +0.01675 0.22821044921875 0.375 0.391339111328125 +0.016875 0.22821044921875 0.375 0.391339111328125 +0.017 0.230316162109375 0.378448486328125 0.391339111328125 +0.017125 0.230316162109375 0.378448486328125 0.391339111328125 +0.01725 0.232391357421875 0.3818359375 0.391339111328125 +0.017375 0.23443603515625 0.38519287109375 0.391339111328125 +0.0175 0.23443603515625 0.38519287109375 0.391339111328125 +0.017625000000000002 0.2364501953125 0.388519287109375 0.391339111328125 +0.017750000000000002 0.2364501953125 0.388519287109375 0.391339111328125 +0.017875000000000002 0.238433837890625 0.39178466796875 0.391339111328125 +0.018000000000000002 0.24041748046875 0.39501953125 0.391339111328125 +0.018125 0.24041748046875 0.39501953125 0.391339111328125 +0.01825 0.242340087890625 0.398193359375 0.391339111328125 +0.018375 0.242340087890625 0.398193359375 0.391339111328125 +0.0185 0.2442626953125 0.401336669921875 0.391339111328125 +0.018625 0.24615478515625 0.404449462890625 0.391339111328125 +0.01875 0.24615478515625 0.404449462890625 0.391339111328125 +0.018875 0.248016357421875 0.407501220703125 0.391339111328125 +0.019 0.248016357421875 0.407501220703125 0.391339111328125 +0.019125 0.249847412109375 0.4105224609375 0.391339111328125 +0.01925 0.25164794921875 0.413482666015625 0.391339111328125 +0.019375 0.25164794921875 0.413482666015625 0.391339111328125 +0.0195 0.25341796875 0.416412353515625 0.391339111328125 +0.019625 0.25341796875 0.416412353515625 0.391339111328125 +0.01975 0.255157470703125 0.419281005859375 0.391339111328125 +0.019875 0.25689697265625 0.422119140625 0.391339111328125 +0.02 0.25689697265625 0.422119140625 0.391339111328125 +0.020125 0.258575439453125 0.424896240234375 0.391339111328125 +0.02025 0.258575439453125 0.424896240234375 0.391339111328125 +0.020375 0.26025390625 0.4276123046875 0.391339111328125 +0.0205 0.261871337890625 0.4302978515625 0.391339111328125 +0.020625 0.261871337890625 0.4302978515625 0.391339111328125 +0.02075 0.26348876953125 0.432952880859375 0.391339111328125 +0.020875 0.26348876953125 0.432952880859375 0.391339111328125 +0.021 0.26507568359375 0.435546875 0.391339111328125 +0.021125 0.266632080078125 0.438079833984375 0.391339111328125 +0.02125 0.266632080078125 0.438079833984375 0.391339111328125 +0.021375 0.268157958984375 0.440582275390625 0.391339111328125 +0.0215000000000000032 0.268157958984375 0.440582275390625 0.391339111328125 +0.0216250000000000032 0.269622802734375 0.44305419921875 0.391339111328125 +0.0217500000000000032 0.271087646484375 0.4454345703125 0.391339111328125 +0.0218750000000000032 0.271087646484375 0.4454345703125 0.391339111328125 +0.022 0.27252197265625 0.447784423828125 0.391339111328125 +0.022125 0.27252197265625 0.447784423828125 0.391339111328125 +0.02225 0.27392578125 0.450103759765625 0.391339111328125 +0.022375 0.275299072265625 0.452362060546875 0.391339111328125 +0.0225 0.275299072265625 0.452362060546875 0.391339111328125 +0.022625 0.276641845703125 0.454559326171875 0.391339111328125 +0.02275 0.276641845703125 0.454559326171875 0.391339111328125 +0.022875 0.2779541015625 0.45672607421875 0.391339111328125 +0.023 0.27923583984375 0.458831787109375 0.391339111328125 +0.023125 0.27923583984375 0.458831787109375 0.391339111328125 +0.02325 0.280487060546875 0.46087646484375 0.391339111328125 +0.023375 0.280487060546875 0.46087646484375 0.391339111328125 +0.0235 0.281707763671875 0.462890625 0.391339111328125 +0.023625 0.28289794921875 0.464813232421875 0.391339111328125 +0.02375 0.28289794921875 0.464813232421875 0.391339111328125 +0.023875 0.2840576171875 0.46673583984375 0.391339111328125 +0.024 0.2840576171875 0.46673583984375 0.391339111328125 +0.024125 0.285186767578125 0.46856689453125 0.391339111328125 +0.02425 0.2862548828125 0.470367431640625 0.391339111328125 +0.024375 0.2862548828125 0.470367431640625 0.391339111328125 +0.0245 0.287322998046875 0.472137451171875 0.391339111328125 +0.024625 0.287322998046875 0.472137451171875 0.391339111328125 +0.02475 0.288360595703125 0.47381591796875 0.391339111328125 +0.024875 0.28936767578125 0.4754638671875 0.391339111328125 +0.025 0.28936767578125 0.4754638671875 0.391339111328125 +0.025125 0.29034423828125 0.47705078125 0.391339111328125 +0.02525 0.29034423828125 0.47705078125 0.391339111328125 +0.025375 0.291259765625 0.478607177734375 0.391339111328125 +0.0255000000000000032 0.29217529296875 0.480072021484375 0.391339111328125 +0.0256250000000000032 0.29217529296875 0.480072021484375 0.391339111328125 +0.0257500000000000032 0.293060302734375 0.48150634765625 0.391339111328125 +0.0258750000000000032 0.293060302734375 0.48150634765625 0.391339111328125 +0.026000000000000004 0.29388427734375 0.48291015625 0.391339111328125 +0.026125 0.294708251953125 0.484222412109375 0.391339111328125 +0.02625 0.294708251953125 0.484222412109375 0.391339111328125 +0.026375 0.29547119140625 0.485504150390625 0.391339111328125 +0.0265 0.29547119140625 0.485504150390625 0.391339111328125 +0.026625 0.296234130859375 0.486724853515625 0.391339111328125 +0.02675 0.29693603515625 0.487884521484375 0.391339111328125 +0.026875 0.29693603515625 0.487884521484375 0.391339111328125 +0.027 0.297607421875 0.489013671875 0.391339111328125 +0.027125 0.297607421875 0.489013671875 0.391339111328125 +0.02725 0.298248291015625 0.490081787109375 0.391339111328125 +0.027375 0.298858642578125 0.4910888671875 0.391339111328125 +0.0275 0.298858642578125 0.4910888671875 0.391339111328125 +0.027625 0.299468994140625 0.492034912109375 0.391339111328125 +0.02775 0.299468994140625 0.492034912109375 0.391339111328125 +0.027875 0.300018310546875 0.492950439453125 0.391339111328125 +0.028 0.300506591796875 0.4937744140625 0.391339111328125 +0.028125 0.300506591796875 0.4937744140625 0.391339111328125 +0.02825 0.300994873046875 0.49456787109375 0.391339111328125 +0.028375 0.300994873046875 0.49456787109375 0.391339111328125 +0.0285 0.30145263671875 0.49530029296875 0.391339111328125 +0.028625 0.301849365234375 0.496002197265625 0.391339111328125 +0.02875 0.301849365234375 0.496002197265625 0.391339111328125 +0.028875 0.30224609375 0.496612548828125 0.391339111328125 +0.029 0.30224609375 0.496612548828125 0.391339111328125 +0.029125 0.302581787109375 0.4971923828125 0.391339111328125 +0.02925 0.30291748046875 0.497711181640625 0.391339111328125 +0.0293750000000000032 0.30291748046875 0.497711181640625 0.391339111328125 +0.0295000000000000032 0.303192138671875 0.498199462890625 0.391339111328125 +0.0296250000000000026 0.303192138671875 0.498199462890625 0.391339111328125 +0.0297500000000000026 0.303436279296875 0.49859619140625 0.391339111328125 +0.0298750000000000026 0.30364990234375 0.49896240234375 0.391339111328125 +0.03 0.30364990234375 0.49896240234375 0.391339111328125 +0.030125 0.303863525390625 0.499267578125 0.391339111328125 +0.03025 0.303863525390625 0.499267578125 0.391339111328125 +0.030375 0.303985595703125 0.49951171875 0.391339111328125 +0.0305 0.304107666015625 0.49969482421875 0.391339111328125 +0.030625 0.304107666015625 0.49969482421875 0.391339111328125 +0.03075 0.30419921875 0.49981689453125 0.391339111328125 +0.030875 0.30419921875 0.49981689453125 0.391339111328125 +0.031 0.30426025390625 0.499908447265625 0.391339111328125 +0.031125 0.30426025390625 0.49993896484375 0.391339111328125 +0.03125 0.30426025390625 0.49993896484375 0.391339111328125 +0.031375 0.30426025390625 0.499908447265625 0.391339111328125 +0.0315 0.30426025390625 0.499908447265625 0.391339111328125 +0.031625 0.30419921875 0.49981689453125 0.391339111328125 +0.03175 0.304107666015625 0.49969482421875 0.391339111328125 +0.031875 0.304107666015625 0.49969482421875 0.391339111328125 +0.032 0.139678955078125 0.49951171875 0.7202575683593749 +0.032125 0.139678955078125 0.49951171875 0.7202575683593749 +0.03225 0.139617919921875 0.499267578125 0.7202575683593749 +0.032375 0.1395263671875 0.49896240234375 0.7202575683593749 +0.0325 0.1395263671875 0.49896240234375 0.7202575683593749 +0.032625 0.139434814453125 0.49859619140625 0.7202575683593749 +0.03275 0.139434814453125 0.49859619140625 0.7202575683593749 +0.032875 0.139312744140625 0.498199462890625 0.7202575683593749 +0.033 0.139190673828125 0.497711181640625 0.7202575683593749 +0.033125 0.139190673828125 0.497711181640625 0.7202575683593749 +0.03325 0.1390380859375 0.4971923828125 0.7202575683593749 +0.033375 0.1390380859375 0.4971923828125 0.7202575683593749 +0.0335 0.138885498046875 0.496612548828125 0.7202575683593749 +0.033625 0.138702392578125 0.496002197265625 0.7202575683593749 +0.03375 0.138702392578125 0.496002197265625 0.7202575683593749 +0.033875 0.138519287109375 0.49530029296875 0.7202575683593749 +0.034 0.138519287109375 0.49530029296875 0.7202575683593749 +0.034125 0.1383056640625 0.49456787109375 0.7202575683593749 +0.03425 0.138092041015625 0.4937744140625 0.7202575683593749 +0.034375 0.138092041015625 0.4937744140625 0.7202575683593749 +0.0345 0.137847900390625 0.492950439453125 0.7202575683593749 +0.034625 0.137847900390625 0.492950439453125 0.7202575683593749 +0.03475 0.137603759765625 0.492034912109375 0.7202575683593749 +0.034875 0.1373291015625 0.4910888671875 0.7202575683593749 +0.035 0.1373291015625 0.4910888671875 0.7202575683593749 +0.035125 0.137054443359375 0.490081787109375 0.7202575683593749 +0.035250000000000004 0.137054443359375 0.490081787109375 0.7202575683593749 +0.035375000000000004 0.136749267578125 0.489013671875 0.7202575683593749 +0.035500000000000004 0.136444091796875 0.487884521484375 0.7202575683593749 +0.035625000000000004 0.136444091796875 0.487884521484375 0.7202575683593749 +0.035750000000000004 0.1361083984375 0.486724853515625 0.7202575683593749 +0.035875000000000004 0.1361083984375 0.486724853515625 0.7202575683593749 +0.036000000000000004 0.135772705078125 0.485504150390625 0.7202575683593749 +0.036125 0.135406494140625 0.484222412109375 0.7202575683593749 +0.03625 0.135406494140625 0.484222412109375 0.7202575683593749 +0.036375 0.135040283203125 0.48291015625 0.7202575683593749 +0.0365 0.135040283203125 0.48291015625 0.7202575683593749 +0.036625 0.1346435546875 0.48150634765625 0.7202575683593749 +0.03675 0.134246826171875 0.480072021484375 0.7202575683593749 +0.036875 0.134246826171875 0.480072021484375 0.7202575683593749 +0.037 0.13385009765625 0.478607177734375 0.7202575683593749 +0.037125 0.13385009765625 0.478607177734375 0.7202575683593749 +0.03725 0.1334228515625 0.47705078125 0.7202575683593749 +0.037375 0.132965087890625 0.4754638671875 0.7202575683593749 +0.0375 0.132965087890625 0.4754638671875 0.7202575683593749 +0.037625 0.13250732421875 0.47381591796875 0.7202575683593749 +0.03775 0.13250732421875 0.47381591796875 0.7202575683593749 +0.037875 0.13201904296875 0.472137451171875 0.7202575683593749 +0.038 0.13153076171875 0.470367431640625 0.7202575683593749 +0.038125 0.13153076171875 0.470367431640625 0.7202575683593749 +0.03825 0.13104248046875 0.46856689453125 0.7202575683593749 +0.038375 0.13104248046875 0.46856689453125 0.7202575683593749 +0.0385 0.130523681640625 0.46673583984375 0.7202575683593749 +0.038625 0.129974365234375 0.464813232421875 0.7202575683593749 +0.03875 0.129974365234375 0.464813232421875 0.7202575683593749 +0.038875 0.12945556640625 0.462890625 0.7202575683593749 +0.039 0.12945556640625 0.462890625 0.7202575683593749 +0.039125 0.128875732421875 0.46087646484375 0.7202575683593749 +0.03925 0.128326416015625 0.458831787109375 0.7202575683593749 +0.039375 0.128326416015625 0.458831787109375 0.7202575683593749 +0.0395 0.127716064453125 0.45672607421875 0.7202575683593749 +0.039625 0.127716064453125 0.45672607421875 0.7202575683593749 +0.03975 0.127105712890625 0.454559326171875 0.7202575683593749 +0.039875 0.126495361328125 0.452362060546875 0.7202575683593749 +0.04 0.126495361328125 0.452362060546875 0.7202575683593749 +0.040125 0.125885009765625 0.450103759765625 0.7202575683593749 +0.04025 0.125885009765625 0.450103759765625 0.7202575683593749 +0.040375 0.125213623046875 0.447784423828125 0.7202575683593749 +0.0405 0.12457275390625 0.4454345703125 0.7202575683593749 +0.040625 0.12457275390625 0.4454345703125 0.7202575683593749 +0.04075 0.1239013671875 0.44305419921875 0.7202575683593749 +0.040875 0.1239013671875 0.44305419921875 0.7202575683593749 +0.041 0.123199462890625 0.440582275390625 0.7202575683593749 +0.041125 0.12249755859375 0.438079833984375 0.7202575683593749 +0.04125 0.12249755859375 0.438079833984375 0.7202575683593749 +0.041375 0.121795654296875 0.435546875 0.7202575683593749 +0.0415 0.121795654296875 0.435546875 0.7202575683593749 +0.041625 0.121063232421875 0.432952880859375 0.7202575683593749 +0.04175 0.120330810546875 0.4302978515625 0.7202575683593749 +0.041875 0.120330810546875 0.4302978515625 0.7202575683593749 +0.042 0.119598388671875 0.4276123046875 0.7202575683593749 +0.042125 0.119598388671875 0.4276123046875 0.7202575683593749 +0.04225 0.11883544921875 0.424896240234375 0.7202575683593749 +0.042375 0.1180419921875 0.422119140625 0.7202575683593749 +0.0425 0.1180419921875 0.422119140625 0.7202575683593749 +0.042625 0.11724853515625 0.419281005859375 0.7202575683593749 +0.04275 0.11724853515625 0.419281005859375 0.7202575683593749 +0.042875 0.116455078125 0.416412353515625 0.7202575683593749 +0.0430000000000000036 0.115631103515625 0.413482666015625 0.7202575683593749 +0.0431250000000000036 0.115631103515625 0.413482666015625 0.7202575683593749 +0.0432500000000000036 0.11480712890625 0.4105224609375 0.7202575683593749 +0.0433750000000000036 0.11480712890625 0.4105224609375 0.7202575683593749 +0.0435000000000000036 0.11395263671875 0.407501220703125 0.7202575683593749 +0.0436250000000000036 0.11309814453125 0.404449462890625 0.7202575683593749 +0.0437500000000000036 0.11309814453125 0.404449462890625 0.7202575683593749 +0.0438750000000000036 0.11224365234375 0.401336669921875 0.7202575683593749 +0.044 0.11224365234375 0.401336669921875 0.7202575683593749 +0.044125 0.111358642578125 0.398193359375 0.7202575683593749 +0.04425 0.1104736328125 0.39501953125 0.7202575683593749 +0.044375 0.1104736328125 0.39501953125 0.7202575683593749 +0.0445 0.10955810546875 0.39178466796875 0.7202575683593749 +0.044625 0.10955810546875 0.39178466796875 0.7202575683593749 +0.04475 0.108642578125 0.388519287109375 0.7202575683593749 +0.044875 0.10772705078125 0.38519287109375 0.7202575683593749 +0.045 0.10772705078125 0.38519287109375 0.7202575683593749 +0.045125 0.106781005859375 0.3818359375 0.7202575683593749 +0.04525 0.106781005859375 0.3818359375 0.7202575683593749 +0.045375 0.1058349609375 0.378448486328125 0.7202575683593749 +0.0455 0.1048583984375 0.375 0.7202575683593749 +0.045625 0.1048583984375 0.375 0.7202575683593749 +0.04575 0.1038818359375 0.37152099609375 0.7202575683593749 +0.045875 0.1038818359375 0.37152099609375 0.7202575683593749 +0.046 0.1029052734375 0.36798095703125 0.7202575683593749 +0.046125 0.1019287109375 0.36444091796875 0.7202575683593749 +0.04625 0.1019287109375 0.36444091796875 0.7202575683593749 +0.046375 0.10089111328125 0.360809326171875 0.7202575683593749 +0.0465 0.10089111328125 0.360809326171875 0.7202575683593749 +0.046625 0.099884033203125 0.357177734375 0.7202575683593749 +0.04675 0.098846435546875 0.353485107421875 0.7202575683593749 +0.046875 0.098846435546875 0.353485107421875 0.7202575683593749 +0.047 0.097808837890625 0.349761962890625 0.7202575683593749 +0.047125 0.097808837890625 0.349761962890625 0.7202575683593749 +0.04725 0.096771240234375 0.34600830078125 0.7202575683593749 +0.047375 0.095703125 0.34222412109375 0.7202575683593749 +0.0475 0.095703125 0.34222412109375 0.7202575683593749 +0.047625 0.094635009765625 0.33837890625 0.7202575683593749 +0.04775 0.094635009765625 0.33837890625 0.7202575683593749 +0.047875 0.093536376953125 0.334503173828125 0.7202575683593749 +0.048 0.09246826171875 0.330596923828125 0.7202575683593749 +0.048125 0.09246826171875 0.330596923828125 0.7202575683593749 +0.04825 0.091339111328125 0.32666015625 0.7202575683593749 +0.048375 0.091339111328125 0.32666015625 0.7202575683593749 +0.0485 0.090240478515625 0.322662353515625 0.7202575683593749 +0.048625 0.089111328125 0.31866455078125 0.7202575683593749 +0.04875 0.089111328125 0.31866455078125 0.7202575683593749 +0.048875 0.087982177734375 0.314605712890625 0.7202575683593749 +0.049 0.087982177734375 0.314605712890625 0.7202575683593749 +0.049125 0.086822509765625 0.310516357421875 0.7202575683593749 +0.04925 0.085693359375 0.306396484375 0.7202575683593749 +0.049375 0.085693359375 0.306396484375 0.7202575683593749 +0.0495 0.08453369140625 0.30224609375 0.7202575683593749 +0.049625 0.08453369140625 0.30224609375 0.7202575683593749 +0.04975 0.083343505859375 0.298065185546875 0.7202575683593749 +0.049875 0.082183837890625 0.2938232421875 0.7202575683593749 +0.05 0.082183837890625 0.2938232421875 0.7202575683593749 +0.050125 0.08099365234375 0.289581298828125 0.7202575683593749 +0.05025 0.08099365234375 0.289581298828125 0.7202575683593749 +0.050375 0.07977294921875 0.285308837890625 0.7202575683593749 +0.0505 0.078582763671875 0.280975341796875 0.7202575683593749 +0.050625 0.078582763671875 0.280975341796875 0.7202575683593749 +0.05075 0.077362060546875 0.276641845703125 0.7202575683593749 +0.0508750000000000064 0.077362060546875 0.276641845703125 0.7202575683593749 +0.0510000000000000064 0.076141357421875 0.27227783203125 0.7202575683593749 +0.0511250000000000064 0.074920654296875 0.267852783203125 0.7202575683593749 +0.0512500000000000064 0.074920654296875 0.267852783203125 0.7202575683593749 +0.0513750000000000064 0.07366943359375 0.263427734375 0.7202575683593749 +0.0515000000000000064 0.07366943359375 0.263427734375 0.7202575683593749 +0.0516250000000000064 0.072418212890625 0.25897216796875 0.7202575683593749 +0.0517500000000000064 0.0711669921875 0.25445556640625 0.7202575683593749 +0.0518750000000000064 0.0711669921875 0.25445556640625 0.7202575683593749 +0.052000000000000008 0.06988525390625 0.249969482421875 0.7202575683593749 +0.052125 0.06988525390625 0.249969482421875 0.7202575683593749 +0.05225 0.068634033203125 0.24542236328125 0.7202575683593749 +0.052375 0.067352294921875 0.2408447265625 0.7202575683593749 +0.0525 0.067352294921875 0.2408447265625 0.7202575683593749 +0.052625 0.066070556640625 0.236236572265625 0.7202575683593749 +0.05275 0.066070556640625 0.236236572265625 0.7202575683593749 +0.052875 0.06475830078125 0.231597900390625 0.7202575683593749 +0.053 0.063446044921875 0.226959228515625 0.7202575683593749 +0.053125 0.063446044921875 0.226959228515625 0.7202575683593749 +0.05325 0.062164306640625 0.2222900390625 0.7202575683593749 +0.053375 0.062164306640625 0.2222900390625 0.7202575683593749 +0.0535 0.06085205078125 0.21759033203125 0.7202575683593749 +0.053625 0.05950927734375 0.212860107421875 0.7202575683593749 +0.05375 0.05950927734375 0.212860107421875 0.7202575683593749 +0.053875 0.058197021484375 0.208099365234375 0.7202575683593749 +0.054 0.058197021484375 0.208099365234375 0.7202575683593749 +0.054125 0.056854248046875 0.203338623046875 0.7202575683593749 +0.05425 0.055511474609375 0.19854736328125 0.7202575683593749 +0.054375 0.055511474609375 0.19854736328125 0.7202575683593749 +0.0545 0.054168701171875 0.1937255859375 0.7202575683593749 +0.054625 0.054168701171875 0.1937255859375 0.7202575683593749 +0.05475 0.052825927734375 0.188873291015625 0.7202575683593749 +0.054875 0.05145263671875 0.18402099609375 0.7202575683593749 +0.055 0.05145263671875 0.18402099609375 0.7202575683593749 +0.055125 0.050079345703125 0.17913818359375 0.7202575683593749 +0.05525 0.050079345703125 0.17913818359375 0.7202575683593749 +0.055375 0.048736572265625 0.17425537109375 0.7202575683593749 +0.0555 0.047332763671875 0.169342041015625 0.7202575683593749 +0.055625 0.047332763671875 0.169342041015625 0.7202575683593749 +0.05575 0.04595947265625 0.164398193359375 0.7202575683593749 +0.055875 0.04595947265625 0.164398193359375 0.7202575683593749 +0.056 0.044586181640625 0.159454345703125 0.7202575683593749 +0.056125 0.043182373046875 0.15447998046875 0.7202575683593749 +0.05625 0.043182373046875 0.15447998046875 0.7202575683593749 +0.056375 0.04180908203125 0.14947509765625 0.7202575683593749 +0.0565 0.04180908203125 0.14947509765625 0.7202575683593749 +0.056625 0.0404052734375 0.14447021484375 0.7202575683593749 +0.05675 0.03900146484375 0.13946533203125 0.7202575683593749 +0.056875 0.03900146484375 0.13946533203125 0.7202575683593749 +0.057 0.03759765625 0.134429931640625 0.7202575683593749 +0.057125 0.03759765625 0.134429931640625 0.7202575683593749 +0.05725 0.036163330078125 0.129364013671875 0.7202575683593749 +0.057375 0.034759521484375 0.124298095703125 0.7202575683593749 +0.0575 0.034759521484375 0.124298095703125 0.7202575683593749 +0.057625 0.0333251953125 0.119232177734375 0.7202575683593749 +0.05775 0.0333251953125 0.119232177734375 0.7202575683593749 +0.057875 0.03192138671875 0.1141357421875 0.7202575683593749 +0.058 0.030487060546875 0.109039306640625 0.7202575683593749 +0.058125 0.030487060546875 0.109039306640625 0.7202575683593749 +0.05825 0.029052734375 0.103912353515625 0.7202575683593749 +0.058375 0.029052734375 0.103912353515625 0.7202575683593749 +0.0585 0.027618408203125 0.098785400390625 0.7202575683593749 +0.0586250000000000064 0.02618408203125 0.093658447265625 0.7202575683593749 +0.0587500000000000064 0.02618408203125 0.093658447265625 0.7202575683593749 +0.0588750000000000064 0.024749755859375 0.0885009765625 0.7202575683593749 +0.0590000000000000064 0.024749755859375 0.0885009765625 0.7202575683593749 +0.0591250000000000064 0.0233154296875 0.083343505859375 0.7202575683593749 +0.0592500000000000052 0.0218505859375 0.07818603515625 0.7202575683593749 +0.0593750000000000052 0.0218505859375 0.07818603515625 0.7202575683593749 +0.0595000000000000052 0.020416259765625 0.072998046875 0.7202575683593749 +0.0596250000000000052 0.020416259765625 0.072998046875 0.7202575683593749 +0.0597500000000000052 0.018951416015625 0.06781005859375 0.7202575683593749 +0.059875000000000008 0.01751708984375 0.0626220703125 0.7202575683593749 +0.06 0.01751708984375 0.0626220703125 0.7202575683593749 +0.060125 0.01605224609375 0.05743408203125 0.7202575683593749 +0.06025 0.01605224609375 0.05743408203125 0.7202575683593749 +0.060375 0.01458740234375 0.05224609375 0.7202575683593749 +0.0605 0.013153076171875 0.047027587890625 0.7202575683593749 +0.060625 0.013153076171875 0.047027587890625 0.7202575683593749 +0.06075 0.011688232421875 0.04180908203125 0.7202575683593749 +0.060875 0.011688232421875 0.04180908203125 0.7202575683593749 +0.061 0.010223388671875 0.036590576171875 0.7202575683593749 +0.061125 0.008758544921875 0.0313720703125 0.7202575683593749 +0.06125 0.008758544921875 0.0313720703125 0.7202575683593749 +0.061375 0.007293701171875 0.026123046875 0.7202575683593749 +0.0615 0.007293701171875 0.026123046875 0.7202575683593749 +0.061625 0.005828857421875 0.020904541015625 0.7202575683593749 +0.06175 0.004364013671875 0.01568603515625 0.7202575683593749 +0.061875 0.004364013671875 0.01568603515625 0.7202575683593749 +0.062 0.002899169921875 0.01043701171875 0.7202575683593749 +0.062125 0.002899169921875 0.01043701171875 0.7202575683593749 +0.06225 0.001434326171875 0.005218505859375 0.7202575683593749 +0.062375 0.0 0.0 0.7202575683593749 +0.0625 0.0 0.0 0.7202575683593749 +0.062625 -0.001434326171875 -0.005218505859375 0.7202575683593749 +0.06275 -0.001434326171875 -0.005218505859375 0.7202575683593749 +0.062875 -0.002899169921875 -0.01043701171875 0.7202575683593749 +0.063 -0.004364013671875 -0.01568603515625 0.7202575683593749 +0.063125 -0.004364013671875 -0.01568603515625 0.7202575683593749 +0.06325 -0.005828857421875 -0.020904541015625 0.7202575683593749 +0.063375 -0.005828857421875 -0.020904541015625 0.7202575683593749 +0.0635 -0.007293701171875 -0.026123046875 0.7202575683593749 +0.063625 -0.008758544921875 -0.0313720703125 0.7202575683593749 +0.06375 -0.008758544921875 -0.0313720703125 0.7202575683593749 +0.063875 -0.010223388671875 -0.036590576171875 0.7202575683593749 +0.064 -0.00238037109375 -0.036590576171875 0.934271240234375 +0.064125 -0.002716064453125 -0.04180908203125 0.934271240234375 +0.06425 -0.003082275390625 -0.047027587890625 0.934271240234375 +0.064375 -0.003082275390625 -0.047027587890625 0.934271240234375 +0.0645 -0.00341796875 -0.05224609375 0.934271240234375 +0.064625 -0.00341796875 -0.05224609375 0.934271240234375 +0.06475 -0.003753662109375 -0.05743408203125 0.934271240234375 +0.064875 -0.00408935546875 -0.0626220703125 0.934271240234375 +0.065 -0.00408935546875 -0.0626220703125 0.934271240234375 +0.065125 -0.004425048828125 -0.06781005859375 0.934271240234375 +0.06525 -0.004425048828125 -0.06781005859375 0.934271240234375 +0.065375 -0.004791259765625 -0.072998046875 0.934271240234375 +0.0655 -0.005126953125 -0.07818603515625 0.934271240234375 +0.065625 -0.005126953125 -0.07818603515625 0.934271240234375 +0.06575 -0.005462646484375 -0.083343505859375 0.934271240234375 +0.065875 -0.005462646484375 -0.083343505859375 0.934271240234375 +0.066 -0.00579833984375 -0.0885009765625 0.934271240234375 +0.066125 -0.006134033203125 -0.093658447265625 0.934271240234375 +0.06625 -0.006134033203125 -0.093658447265625 0.934271240234375 +0.066375 -0.0064697265625 -0.098785400390625 0.934271240234375 +0.0665 -0.0064697265625 -0.098785400390625 0.934271240234375 +0.066625 -0.006805419921875 -0.103912353515625 0.934271240234375 +0.06675 -0.00714111328125 -0.109039306640625 0.934271240234375 +0.066875 -0.00714111328125 -0.109039306640625 0.934271240234375 +0.067 -0.007476806640625 -0.1141357421875 0.934271240234375 +0.067125 -0.007476806640625 -0.1141357421875 0.934271240234375 +0.06725 -0.0078125 -0.119232177734375 0.934271240234375 +0.067375 -0.008148193359375 -0.124298095703125 0.934271240234375 +0.0675 -0.008148193359375 -0.124298095703125 0.934271240234375 +0.067625 -0.00848388671875 -0.129364013671875 0.934271240234375 +0.06775 -0.00848388671875 -0.129364013671875 0.934271240234375 +0.067875 -0.008819580078125 -0.134429931640625 0.934271240234375 +0.068 -0.0091552734375 -0.13946533203125 0.934271240234375 +0.068125 -0.0091552734375 -0.13946533203125 0.934271240234375 +0.06825000000000001 -0.00946044921875 -0.14447021484375 0.934271240234375 +0.06837500000000001 -0.00946044921875 -0.14447021484375 0.934271240234375 +0.06850000000000001 -0.009796142578125 -0.14947509765625 0.934271240234375 +0.06862500000000001 -0.0101318359375 -0.15447998046875 0.934271240234375 +0.06875000000000001 -0.0101318359375 -0.15447998046875 0.934271240234375 +0.06887500000000001 -0.010467529296875 -0.159454345703125 0.934271240234375 +0.06900000000000001 -0.010467529296875 -0.159454345703125 0.934271240234375 +0.06912500000000001 -0.010772705078125 -0.164398193359375 0.934271240234375 +0.06925000000000001 -0.0111083984375 -0.169342041015625 0.934271240234375 +0.06937500000000001 -0.0111083984375 -0.169342041015625 0.934271240234375 +0.06950000000000001 -0.01141357421875 -0.17425537109375 0.934271240234375 +0.06962500000000001 -0.01141357421875 -0.17425537109375 0.934271240234375 +0.06975000000000001 -0.011749267578125 -0.17913818359375 0.934271240234375 +0.06987500000000001 -0.012054443359375 -0.18402099609375 0.934271240234375 +0.07000000000000001 -0.012054443359375 -0.18402099609375 0.934271240234375 +0.07012500000000001 -0.01239013671875 -0.188873291015625 0.934271240234375 +0.07025000000000001 -0.01239013671875 -0.188873291015625 0.934271240234375 +0.07037500000000001 -0.0126953125 -0.1937255859375 0.934271240234375 +0.07050000000000001 -0.013031005859375 -0.19854736328125 0.934271240234375 +0.07062500000000001 -0.013031005859375 -0.19854736328125 0.934271240234375 +0.07075000000000001 -0.013336181640625 -0.203338623046875 0.934271240234375 +0.07087500000000001 -0.013336181640625 -0.203338623046875 0.934271240234375 +0.07100000000000001 -0.013641357421875 -0.208099365234375 0.934271240234375 +0.07112500000000001 -0.013946533203125 -0.212860107421875 0.934271240234375 +0.07125000000000001 -0.013946533203125 -0.212860107421875 0.934271240234375 +0.07137500000000001 -0.0142822265625 -0.21759033203125 0.934271240234375 +0.07150000000000001 -0.0142822265625 -0.21759033203125 0.934271240234375 +0.07162500000000001 -0.01458740234375 -0.2222900390625 0.934271240234375 +0.07175000000000001 -0.014892578125 -0.226959228515625 0.934271240234375 +0.07187500000000001 -0.014892578125 -0.226959228515625 0.934271240234375 +0.07200000000000001 -0.01519775390625 -0.231597900390625 0.934271240234375 +0.072125 -0.01519775390625 -0.231597900390625 0.934271240234375 +0.07225 -0.0155029296875 -0.236236572265625 0.934271240234375 +0.072375 -0.01580810546875 -0.2408447265625 0.934271240234375 +0.0725 -0.01580810546875 -0.2408447265625 0.934271240234375 +0.072625 -0.016082763671875 -0.24542236328125 0.934271240234375 +0.07275 -0.016082763671875 -0.24542236328125 0.934271240234375 +0.072875 -0.016387939453125 -0.249969482421875 0.934271240234375 +0.073 -0.016693115234375 -0.25445556640625 0.934271240234375 +0.073125 -0.016693115234375 -0.25445556640625 0.934271240234375 +0.07325 -0.016998291015625 -0.25897216796875 0.934271240234375 +0.073375 -0.016998291015625 -0.25897216796875 0.934271240234375 +0.0735 -0.01727294921875 -0.263427734375 0.934271240234375 +0.073625 -0.017578125 -0.267852783203125 0.934271240234375 +0.07375 -0.017578125 -0.267852783203125 0.934271240234375 +0.073875 -0.017852783203125 -0.27227783203125 0.934271240234375 +0.074 -0.017852783203125 -0.27227783203125 0.934271240234375 +0.074125 -0.018157958984375 -0.276641845703125 0.934271240234375 +0.07425 -0.0184326171875 -0.280975341796875 0.934271240234375 +0.074375 -0.0184326171875 -0.280975341796875 0.934271240234375 +0.0745 -0.018707275390625 -0.285308837890625 0.934271240234375 +0.074625 -0.018707275390625 -0.285308837890625 0.934271240234375 +0.07475 -0.01898193359375 -0.289581298828125 0.934271240234375 +0.074875 -0.019287109375 -0.2938232421875 0.934271240234375 +0.075 -0.019287109375 -0.2938232421875 0.934271240234375 +0.075125 -0.019561767578125 -0.298065185546875 0.934271240234375 +0.07525 -0.019561767578125 -0.298065185546875 0.934271240234375 +0.075375 -0.01983642578125 -0.30224609375 0.934271240234375 +0.0755 -0.020111083984375 -0.306396484375 0.934271240234375 +0.075625 -0.020111083984375 -0.306396484375 0.934271240234375 +0.07575 -0.0203857421875 -0.310516357421875 0.934271240234375 +0.075875 -0.0203857421875 -0.310516357421875 0.934271240234375 +0.076 -0.0206298828125 -0.314605712890625 0.934271240234375 +0.076125 -0.020904541015625 -0.31866455078125 0.934271240234375 +0.07625 -0.020904541015625 -0.31866455078125 0.934271240234375 +0.076375 -0.02117919921875 -0.322662353515625 0.934271240234375 +0.0765 -0.02117919921875 -0.322662353515625 0.934271240234375 +0.076625 -0.02142333984375 -0.32666015625 0.934271240234375 +0.07675 -0.021697998046875 -0.330596923828125 0.934271240234375 +0.076875 -0.021697998046875 -0.330596923828125 0.934271240234375 +0.077 -0.021942138671875 -0.334503173828125 0.934271240234375 +0.077125 -0.021942138671875 -0.334503173828125 0.934271240234375 +0.07725 -0.022186279296875 -0.33837890625 0.934271240234375 +0.077375 -0.0224609375 -0.34222412109375 0.934271240234375 +0.0775 -0.0224609375 -0.34222412109375 0.934271240234375 +0.077625 -0.022705078125 -0.34600830078125 0.934271240234375 +0.07775 -0.022705078125 -0.34600830078125 0.934271240234375 +0.077875 -0.02294921875 -0.349761962890625 0.934271240234375 +0.078 -0.023193359375 -0.353485107421875 0.934271240234375 +0.078125 -0.023193359375 -0.353485107421875 0.934271240234375 +0.07825 -0.0234375 -0.357177734375 0.934271240234375 +0.078375 -0.0234375 -0.357177734375 0.934271240234375 +0.0785 -0.023681640625 -0.360809326171875 0.934271240234375 +0.078625 -0.023895263671875 -0.36444091796875 0.934271240234375 +0.07875 -0.023895263671875 -0.36444091796875 0.934271240234375 +0.078875 -0.024139404296875 -0.36798095703125 0.934271240234375 +0.079 -0.024139404296875 -0.36798095703125 0.934271240234375 +0.079125 -0.024383544921875 -0.37152099609375 0.934271240234375 +0.07925 -0.02459716796875 -0.375 0.934271240234375 +0.079375 -0.02459716796875 -0.375 0.934271240234375 +0.0795 -0.02484130859375 -0.378448486328125 0.934271240234375 +0.079625 -0.02484130859375 -0.378448486328125 0.934271240234375 +0.07975 -0.025054931640625 -0.3818359375 0.934271240234375 +0.079875 -0.0252685546875 -0.38519287109375 0.934271240234375 +0.08 -0.0252685546875 -0.38519287109375 0.934271240234375 +0.080125 -0.025482177734375 -0.388519287109375 0.934271240234375 +0.08025 -0.025482177734375 -0.388519287109375 0.934271240234375 +0.080375 -0.02569580078125 -0.39178466796875 0.934271240234375 +0.0805 -0.025909423828125 -0.39501953125 0.934271240234375 +0.080625 -0.025909423828125 -0.39501953125 0.934271240234375 +0.08075 -0.026123046875 -0.398193359375 0.934271240234375 +0.080875 -0.026123046875 -0.398193359375 0.934271240234375 +0.081 -0.026336669921875 -0.401336669921875 0.934271240234375 +0.081125 -0.02655029296875 -0.404449462890625 0.934271240234375 +0.08125 -0.02655029296875 -0.404449462890625 0.934271240234375 +0.081375 -0.0267333984375 -0.407501220703125 0.934271240234375 +0.0815 -0.0267333984375 -0.407501220703125 0.934271240234375 +0.081625 -0.026947021484375 -0.4105224609375 0.934271240234375 +0.08175 -0.027130126953125 -0.413482666015625 0.934271240234375 +0.081875 -0.027130126953125 -0.413482666015625 0.934271240234375 +0.082 -0.027313232421875 -0.416412353515625 0.934271240234375 +0.082125 -0.027313232421875 -0.416412353515625 0.934271240234375 +0.08225 -0.027496337890625 -0.419281005859375 0.934271240234375 +0.082375 -0.0277099609375 -0.422119140625 0.934271240234375 +0.0825 -0.0277099609375 -0.422119140625 0.934271240234375 +0.082625 -0.02789306640625 -0.424896240234375 0.934271240234375 +0.08275 -0.02789306640625 -0.424896240234375 0.934271240234375 +0.082875 -0.028045654296875 -0.4276123046875 0.934271240234375 +0.083 -0.028228759765625 -0.4302978515625 0.934271240234375 +0.083125 -0.028228759765625 -0.4302978515625 0.934271240234375 +0.08325 -0.028411865234375 -0.432952880859375 0.934271240234375 +0.083375 -0.028411865234375 -0.432952880859375 0.934271240234375 +0.0835 -0.028564453125 -0.435546875 0.934271240234375 +0.083625 -0.02874755859375 -0.438079833984375 0.934271240234375 +0.08375 -0.02874755859375 -0.438079833984375 0.934271240234375 +0.08387500000000001 -0.028900146484375 -0.440582275390625 0.934271240234375 +0.08400000000000001 -0.028900146484375 -0.440582275390625 0.934271240234375 +0.08412500000000001 -0.029083251953125 -0.44305419921875 0.934271240234375 +0.08425000000000001 -0.02923583984375 -0.4454345703125 0.934271240234375 +0.08437500000000001 -0.02923583984375 -0.4454345703125 0.934271240234375 +0.08450000000000001 -0.029388427734375 -0.447784423828125 0.934271240234375 +0.08462500000000001 -0.029388427734375 -0.447784423828125 0.934271240234375 +0.08475000000000001 -0.029541015625 -0.450103759765625 0.934271240234375 +0.08487500000000001 -0.029693603515625 -0.452362060546875 0.934271240234375 +0.08500000000000001 -0.029693603515625 -0.452362060546875 0.934271240234375 +0.08512500000000001 -0.029815673828125 -0.454559326171875 0.934271240234375 +0.08525000000000001 -0.029815673828125 -0.454559326171875 0.934271240234375 +0.08537500000000001 -0.02996826171875 -0.45672607421875 0.934271240234375 +0.08550000000000001 -0.030120849609375 -0.458831787109375 0.934271240234375 +0.08562500000000001 -0.030120849609375 -0.458831787109375 0.934271240234375 +0.08575000000000001 -0.030242919921875 -0.46087646484375 0.934271240234375 +0.08587500000000001 -0.030242919921875 -0.46087646484375 0.934271240234375 +0.08600000000000001 -0.030364990234375 -0.462890625 0.934271240234375 +0.08612500000000001 -0.030487060546875 -0.464813232421875 0.934271240234375 +0.08625000000000001 -0.030487060546875 -0.464813232421875 0.934271240234375 +0.08637500000000001 -0.0306396484375 -0.46673583984375 0.934271240234375 +0.08650000000000001 -0.0306396484375 -0.46673583984375 0.934271240234375 +0.08662500000000001 -0.030731201171875 -0.46856689453125 0.934271240234375 +0.08675000000000001 -0.030853271484375 -0.470367431640625 0.934271240234375 +0.08687500000000001 -0.030853271484375 -0.470367431640625 0.934271240234375 +0.08700000000000001 -0.030975341796875 -0.472137451171875 0.934271240234375 +0.08712500000000001 -0.030975341796875 -0.472137451171875 0.934271240234375 +0.08725000000000001 -0.031097412109375 -0.47381591796875 0.934271240234375 +0.08737500000000001 -0.03118896484375 -0.4754638671875 0.934271240234375 +0.08750000000000001 -0.03118896484375 -0.4754638671875 0.934271240234375 +0.08762500000000001 -0.03131103515625 -0.47705078125 0.934271240234375 +0.08775000000000001 -0.03131103515625 -0.47705078125 0.934271240234375 +0.08787500000000001 -0.031402587890625 -0.478607177734375 0.934271240234375 +0.088 -0.031494140625 -0.480072021484375 0.934271240234375 +0.088125 -0.031494140625 -0.480072021484375 0.934271240234375 +0.08825 -0.031585693359375 -0.48150634765625 0.934271240234375 +0.088375 -0.031585693359375 -0.48150634765625 0.934271240234375 +0.0885 -0.03167724609375 -0.48291015625 0.934271240234375 +0.088625 -0.031768798828125 -0.484222412109375 0.934271240234375 +0.08875 -0.031768798828125 -0.484222412109375 0.934271240234375 +0.088875 -0.0318603515625 -0.485504150390625 0.934271240234375 +0.089 -0.0318603515625 -0.485504150390625 0.934271240234375 +0.089125 -0.031951904296875 -0.486724853515625 0.934271240234375 +0.08925 -0.032012939453125 -0.487884521484375 0.934271240234375 +0.089375 -0.032012939453125 -0.487884521484375 0.934271240234375 +0.0895 -0.032073974609375 -0.489013671875 0.934271240234375 +0.089625 -0.032073974609375 -0.489013671875 0.934271240234375 +0.08975 -0.03216552734375 -0.490081787109375 0.934271240234375 +0.089875 -0.0322265625 -0.4910888671875 0.934271240234375 +0.09 -0.0322265625 -0.4910888671875 0.934271240234375 +0.090125 -0.03228759765625 -0.492034912109375 0.934271240234375 +0.09025 -0.03228759765625 -0.492034912109375 0.934271240234375 +0.090375 -0.0323486328125 -0.492950439453125 0.934271240234375 +0.0905 -0.03240966796875 -0.4937744140625 0.934271240234375 +0.090625 -0.03240966796875 -0.4937744140625 0.934271240234375 +0.09075 -0.032440185546875 -0.49456787109375 0.934271240234375 +0.090875 -0.032440185546875 -0.49456787109375 0.934271240234375 +0.091 -0.032501220703125 -0.49530029296875 0.934271240234375 +0.091125 -0.03253173828125 -0.496002197265625 0.934271240234375 +0.09125 -0.03253173828125 -0.496002197265625 0.934271240234375 +0.091375 -0.0325927734375 -0.496612548828125 0.934271240234375 +0.0915 -0.0325927734375 -0.496612548828125 0.934271240234375 +0.091625 -0.032623291015625 -0.4971923828125 0.934271240234375 +0.09175 -0.03265380859375 -0.497711181640625 0.934271240234375 +0.091875 -0.03265380859375 -0.497711181640625 0.934271240234375 +0.092 -0.032684326171875 -0.498199462890625 0.934271240234375 +0.092125 -0.032684326171875 -0.498199462890625 0.934271240234375 +0.09225 -0.03271484375 -0.49859619140625 0.934271240234375 +0.092375 -0.032745361328125 -0.49896240234375 0.934271240234375 +0.0925 -0.032745361328125 -0.49896240234375 0.934271240234375 +0.092625 -0.032745361328125 -0.499267578125 0.934271240234375 +0.09275 -0.032745361328125 -0.499267578125 0.934271240234375 +0.092875 -0.03277587890625 -0.49951171875 0.934271240234375 +0.093 -0.03277587890625 -0.49969482421875 0.934271240234375 +0.093125 -0.03277587890625 -0.49969482421875 0.934271240234375 +0.09325 -0.032806396484375 -0.49981689453125 0.934271240234375 +0.093375 -0.032806396484375 -0.49981689453125 0.934271240234375 +0.0935 -0.032806396484375 -0.499908447265625 0.934271240234375 +0.093625 -0.032806396484375 -0.49993896484375 0.934271240234375 +0.09375 -0.032806396484375 -0.49993896484375 0.934271240234375 +0.093875 -0.032806396484375 -0.499908447265625 0.934271240234375 +0.094 -0.032806396484375 -0.499908447265625 0.934271240234375 +0.094125 -0.032806396484375 -0.49981689453125 0.934271240234375 +0.09425 -0.03277587890625 -0.49969482421875 0.934271240234375 +0.094375 -0.03277587890625 -0.49969482421875 0.934271240234375 +0.0945 -0.03277587890625 -0.49951171875 0.934271240234375 +0.094625 -0.03277587890625 -0.49951171875 0.934271240234375 +0.09475 -0.032745361328125 -0.499267578125 0.934271240234375 +0.094875 -0.032745361328125 -0.49896240234375 0.934271240234375 +0.095 -0.032745361328125 -0.49896240234375 0.934271240234375 +0.095125 -0.03271484375 -0.49859619140625 0.934271240234375 +0.09525 -0.03271484375 -0.49859619140625 0.934271240234375 +0.095375 -0.032684326171875 -0.498199462890625 0.934271240234375 +0.0955 -0.03265380859375 -0.497711181640625 0.934271240234375 +0.095625 -0.03265380859375 -0.497711181640625 0.934271240234375 +0.09575 -0.032623291015625 -0.4971923828125 0.934271240234375 +0.095875 -0.032623291015625 -0.4971923828125 0.934271240234375 +0.096 -0.00030517578125 -0.496612548828125 0.99923095703125 +0.096125 -0.00030517578125 -0.496002197265625 0.99923095703125 +0.09625 -0.00030517578125 -0.496002197265625 0.99923095703125 +0.096375 -0.00030517578125 -0.49530029296875 0.99923095703125 +0.0965 -0.00030517578125 -0.49530029296875 0.99923095703125 +0.096625 -0.00030517578125 -0.49456787109375 0.99923095703125 +0.09675 -0.00030517578125 -0.4937744140625 0.99923095703125 +0.096875 -0.00030517578125 -0.4937744140625 0.99923095703125 +0.097 -0.00030517578125 -0.492950439453125 0.99923095703125 +0.097125 -0.00030517578125 -0.492950439453125 0.99923095703125 +0.09725 -0.00030517578125 -0.492034912109375 0.99923095703125 +0.097375 -0.00030517578125 -0.4910888671875 0.99923095703125 +0.0975 -0.00030517578125 -0.4910888671875 0.99923095703125 +0.097625 -0.00030517578125 -0.490081787109375 0.99923095703125 +0.09775 -0.00030517578125 -0.490081787109375 0.99923095703125 +0.097875 -0.00030517578125 -0.489013671875 0.99923095703125 +0.098 -0.00030517578125 -0.487884521484375 0.99923095703125 +0.098125 -0.00030517578125 -0.487884521484375 0.99923095703125 +0.09825 -0.00030517578125 -0.486724853515625 0.99923095703125 +0.098375 -0.00030517578125 -0.486724853515625 0.99923095703125 +0.0985 -0.00030517578125 -0.485504150390625 0.99923095703125 +0.098625 -0.00030517578125 -0.484222412109375 0.99923095703125 +0.09875 -0.00030517578125 -0.484222412109375 0.99923095703125 +0.098875 -0.00030517578125 -0.48291015625 0.99923095703125 +0.099 -0.00030517578125 -0.48291015625 0.99923095703125 +0.099125 -0.00030517578125 -0.48150634765625 0.99923095703125 +0.09925 -0.00030517578125 -0.480072021484375 0.99923095703125 +0.099375 -0.00030517578125 -0.480072021484375 0.99923095703125 +0.0995 -0.00030517578125 -0.478607177734375 0.99923095703125 +0.099625 -0.00030517578125 -0.478607177734375 0.99923095703125 +0.09975 -0.00030517578125 -0.47705078125 0.99923095703125 +0.099875 -0.00030517578125 -0.4754638671875 0.99923095703125 +0.1 -0.00030517578125 -0.4754638671875 0.99923095703125 +0.100125 -0.00030517578125 -0.47381591796875 0.99923095703125 +0.10025 -0.00030517578125 -0.47381591796875 0.99923095703125 +0.100375 -0.00030517578125 -0.472137451171875 0.99923095703125 +0.1005 -0.00030517578125 -0.470367431640625 0.99923095703125 +0.100625 -0.00030517578125 -0.470367431640625 0.99923095703125 +0.10075 -0.00030517578125 -0.46856689453125 0.99923095703125 +0.100875 -0.00030517578125 -0.46856689453125 0.99923095703125 +0.101 -0.00030517578125 -0.46673583984375 0.99923095703125 +0.101125 -0.00030517578125 -0.464813232421875 0.99923095703125 +0.10125 -0.00030517578125 -0.464813232421875 0.99923095703125 +0.101375 -0.00030517578125 -0.462890625 0.99923095703125 +0.1015 -0.00030517578125 -0.462890625 0.99923095703125 +0.1016250000000000128 -0.00030517578125 -0.46087646484375 0.99923095703125 +0.1017500000000000128 -0.00030517578125 -0.458831787109375 0.99923095703125 +0.1018750000000000128 -0.00030517578125 -0.458831787109375 0.99923095703125 +0.1020000000000000128 -0.00030517578125 -0.45672607421875 0.99923095703125 +0.1021250000000000128 -0.00030517578125 -0.45672607421875 0.99923095703125 +0.1022500000000000128 -0.00030517578125 -0.454559326171875 0.99923095703125 +0.1023750000000000128 -0.000274658203125 -0.452362060546875 0.99923095703125 +0.1025000000000000128 -0.000274658203125 -0.452362060546875 0.99923095703125 +0.1026250000000000128 -0.000274658203125 -0.450103759765625 0.99923095703125 +0.1027500000000000128 -0.000274658203125 -0.450103759765625 0.99923095703125 +0.1028750000000000128 -0.000274658203125 -0.447784423828125 0.99923095703125 +0.1030000000000000128 -0.000274658203125 -0.4454345703125 0.99923095703125 +0.1031250000000000128 -0.000274658203125 -0.4454345703125 0.99923095703125 +0.1032500000000000128 -0.000274658203125 -0.44305419921875 0.99923095703125 +0.1033750000000000128 -0.000274658203125 -0.44305419921875 0.99923095703125 +0.1035000000000000128 -0.000274658203125 -0.440582275390625 0.99923095703125 +0.1036250000000000128 -0.000274658203125 -0.438079833984375 0.99923095703125 +0.1037500000000000128 -0.000274658203125 -0.438079833984375 0.99923095703125 +0.1038750000000000128 -0.000274658203125 -0.435546875 0.99923095703125 +0.104000000000000016 -0.000274658203125 -0.435546875 0.99923095703125 +0.104125 -0.000274658203125 -0.432952880859375 0.99923095703125 +0.10425 -0.000274658203125 -0.4302978515625 0.99923095703125 +0.104375 -0.000274658203125 -0.4302978515625 0.99923095703125 +0.1045 -0.000274658203125 -0.4276123046875 0.99923095703125 +0.104625 -0.000274658203125 -0.4276123046875 0.99923095703125 +0.10475 -0.000274658203125 -0.424896240234375 0.99923095703125 +0.104875 -0.000274658203125 -0.422119140625 0.99923095703125 +0.105 -0.000274658203125 -0.422119140625 0.99923095703125 +0.105125 -0.000274658203125 -0.419281005859375 0.99923095703125 +0.10525 -0.000274658203125 -0.419281005859375 0.99923095703125 +0.105375 -0.000274658203125 -0.416412353515625 0.99923095703125 +0.1055 -0.000274658203125 -0.413482666015625 0.99923095703125 +0.105625 -0.000274658203125 -0.413482666015625 0.99923095703125 +0.10575 -0.000274658203125 -0.4105224609375 0.99923095703125 +0.105875 -0.000274658203125 -0.4105224609375 0.99923095703125 +0.106 -0.000244140625 -0.407501220703125 0.99923095703125 +0.106125 -0.000244140625 -0.404449462890625 0.99923095703125 +0.10625 -0.000244140625 -0.404449462890625 0.99923095703125 +0.106375 -0.000244140625 -0.401336669921875 0.99923095703125 +0.1065 -0.000244140625 -0.401336669921875 0.99923095703125 +0.106625 -0.000244140625 -0.398193359375 0.99923095703125 +0.10675 -0.000244140625 -0.39501953125 0.99923095703125 +0.106875 -0.000244140625 -0.39501953125 0.99923095703125 +0.107 -0.000244140625 -0.39178466796875 0.99923095703125 +0.107125 -0.000244140625 -0.39178466796875 0.99923095703125 +0.10725 -0.000244140625 -0.388519287109375 0.99923095703125 +0.107375 -0.000244140625 -0.38519287109375 0.99923095703125 +0.1075 -0.000244140625 -0.38519287109375 0.99923095703125 +0.107625 -0.000244140625 -0.3818359375 0.99923095703125 +0.10775 -0.000244140625 -0.3818359375 0.99923095703125 +0.107875 -0.000244140625 -0.378448486328125 0.99923095703125 +0.108 -0.000244140625 -0.375 0.99923095703125 +0.108125 -0.000244140625 -0.375 0.99923095703125 +0.10825 -0.000244140625 -0.37152099609375 0.99923095703125 +0.108375 -0.000244140625 -0.37152099609375 0.99923095703125 +0.1085 -0.000244140625 -0.36798095703125 0.99923095703125 +0.108625 -0.000244140625 -0.36444091796875 0.99923095703125 +0.10875 -0.000244140625 -0.36444091796875 0.99923095703125 +0.108875 -0.000213623046875 -0.360809326171875 0.99923095703125 +0.109 -0.000213623046875 -0.360809326171875 0.99923095703125 +0.109125 -0.000213623046875 -0.357177734375 0.99923095703125 +0.10925 -0.000213623046875 -0.353485107421875 0.99923095703125 +0.109375 -0.000213623046875 -0.353485107421875 0.99923095703125 +0.1095 -0.000213623046875 -0.349761962890625 0.99923095703125 +0.109625 -0.000213623046875 -0.349761962890625 0.99923095703125 +0.10975 -0.000213623046875 -0.34600830078125 0.99923095703125 +0.109875 -0.000213623046875 -0.34222412109375 0.99923095703125 +0.11 -0.000213623046875 -0.34222412109375 0.99923095703125 +0.110125 -0.000213623046875 -0.33837890625 0.99923095703125 +0.11025 -0.000213623046875 -0.33837890625 0.99923095703125 +0.110375 -0.000213623046875 -0.334503173828125 0.99923095703125 +0.1105 -0.000213623046875 -0.330596923828125 0.99923095703125 +0.110625 -0.000213623046875 -0.330596923828125 0.99923095703125 +0.11075 -0.000213623046875 -0.32666015625 0.99923095703125 +0.110875 -0.000213623046875 -0.32666015625 0.99923095703125 +0.111 -0.000213623046875 -0.322662353515625 0.99923095703125 +0.111125 -0.000213623046875 -0.31866455078125 0.99923095703125 +0.11125 -0.000213623046875 -0.31866455078125 0.99923095703125 +0.111375 -0.00018310546875 -0.314605712890625 0.99923095703125 +0.1115 -0.00018310546875 -0.314605712890625 0.99923095703125 +0.111625 -0.00018310546875 -0.310516357421875 0.99923095703125 +0.11175 -0.00018310546875 -0.306396484375 0.99923095703125 +0.111875 -0.00018310546875 -0.306396484375 0.99923095703125 +0.112 -0.00018310546875 -0.30224609375 0.99923095703125 +0.112125 -0.00018310546875 -0.30224609375 0.99923095703125 +0.11225 -0.00018310546875 -0.298065185546875 0.99923095703125 +0.112375 -0.00018310546875 -0.2938232421875 0.99923095703125 +0.1125 -0.00018310546875 -0.2938232421875 0.99923095703125 +0.112625 -0.00018310546875 -0.289581298828125 0.99923095703125 +0.11275 -0.00018310546875 -0.289581298828125 0.99923095703125 +0.112875 -0.00018310546875 -0.285308837890625 0.99923095703125 +0.113 -0.00018310546875 -0.280975341796875 0.99923095703125 +0.113125 -0.00018310546875 -0.280975341796875 0.99923095703125 +0.11325 -0.00018310546875 -0.276641845703125 0.99923095703125 +0.113375 -0.00018310546875 -0.276641845703125 0.99923095703125 +0.1135 -0.000152587890625 -0.27227783203125 0.99923095703125 +0.113625 -0.000152587890625 -0.267852783203125 0.99923095703125 +0.11375 -0.000152587890625 -0.267852783203125 0.99923095703125 +0.113875 -0.000152587890625 -0.263427734375 0.99923095703125 +0.114 -0.000152587890625 -0.263427734375 0.99923095703125 +0.114125 -0.000152587890625 -0.25897216796875 0.99923095703125 +0.11425 -0.000152587890625 -0.25445556640625 0.99923095703125 +0.114375 -0.000152587890625 -0.25445556640625 0.99923095703125 +0.1145 -0.000152587890625 -0.249969482421875 0.99923095703125 +0.114625 -0.000152587890625 -0.249969482421875 0.99923095703125 +0.11475 -0.000152587890625 -0.24542236328125 0.99923095703125 +0.114875 -0.000152587890625 -0.2408447265625 0.99923095703125 +0.115 -0.000152587890625 -0.2408447265625 0.99923095703125 +0.115125 -0.000152587890625 -0.236236572265625 0.99923095703125 +0.11525 -0.000152587890625 -0.236236572265625 0.99923095703125 +0.115375 -0.000152587890625 -0.231597900390625 0.99923095703125 +0.1155 -0.0001220703125 -0.226959228515625 0.99923095703125 +0.115625 -0.0001220703125 -0.226959228515625 0.99923095703125 +0.11575 -0.0001220703125 -0.2222900390625 0.99923095703125 +0.115875 -0.0001220703125 -0.2222900390625 0.99923095703125 +0.116 -0.0001220703125 -0.21759033203125 0.99923095703125 +0.116125 -0.0001220703125 -0.212860107421875 0.99923095703125 +0.11625 -0.0001220703125 -0.212860107421875 0.99923095703125 +0.116375 -0.0001220703125 -0.208099365234375 0.99923095703125 +0.1165 -0.0001220703125 -0.208099365234375 0.99923095703125 +0.116625 -0.0001220703125 -0.203338623046875 0.99923095703125 +0.11675 -0.0001220703125 -0.19854736328125 0.99923095703125 +0.116875 -0.0001220703125 -0.19854736328125 0.99923095703125 +0.117 -0.0001220703125 -0.1937255859375 0.99923095703125 +0.117125 -0.0001220703125 -0.1937255859375 0.99923095703125 +0.117250000000000013 -0.0001220703125 -0.188873291015625 0.99923095703125 +0.117375000000000013 -0.0001220703125 -0.18402099609375 0.99923095703125 +0.117500000000000013 -0.0001220703125 -0.18402099609375 0.99923095703125 +0.117625000000000013 -9.1552734375e-05 -0.17913818359375 0.99923095703125 +0.117750000000000013 -9.1552734375e-05 -0.17913818359375 0.99923095703125 +0.117875000000000013 -9.1552734375e-05 -0.17425537109375 0.99923095703125 +0.118000000000000013 -9.1552734375e-05 -0.169342041015625 0.99923095703125 +0.118125000000000013 -9.1552734375e-05 -0.169342041015625 0.99923095703125 +0.118250000000000013 -9.1552734375e-05 -0.164398193359375 0.99923095703125 +0.118375000000000013 -9.1552734375e-05 -0.164398193359375 0.99923095703125 +0.118500000000000013 -9.1552734375e-05 -0.159454345703125 0.99923095703125 +0.118625000000000013 -9.1552734375e-05 -0.15447998046875 0.99923095703125 +0.118750000000000013 -9.1552734375e-05 -0.15447998046875 0.99923095703125 +0.118875000000000013 -9.1552734375e-05 -0.14947509765625 0.99923095703125 +0.119000000000000013 -9.1552734375e-05 -0.14947509765625 0.99923095703125 +0.119125000000000013 -9.1552734375e-05 -0.14447021484375 0.99923095703125 +0.119250000000000013 -9.1552734375e-05 -0.13946533203125 0.99923095703125 +0.119375000000000013 -9.1552734375e-05 -0.13946533203125 0.99923095703125 +0.119500000000000013 -6.103515625e-05 -0.134429931640625 0.99923095703125 +0.119625000000000016 -6.103515625e-05 -0.134429931640625 0.99923095703125 +0.119750000000000016 -6.103515625e-05 -0.129364013671875 0.99923095703125 +0.119875000000000016 -6.103515625e-05 -0.124298095703125 0.99923095703125 +0.12 -6.103515625e-05 -0.124298095703125 0.99923095703125 +0.120125 -6.103515625e-05 -0.119232177734375 0.99923095703125 +0.12025 -6.103515625e-05 -0.119232177734375 0.99923095703125 +0.120375 -6.103515625e-05 -0.1141357421875 0.99923095703125 +0.1205 -6.103515625e-05 -0.109039306640625 0.99923095703125 +0.120625 -6.103515625e-05 -0.109039306640625 0.99923095703125 +0.12075 -6.103515625e-05 -0.103912353515625 0.99923095703125 +0.120875 -6.103515625e-05 -0.103912353515625 0.99923095703125 +0.121 -6.103515625e-05 -0.098785400390625 0.99923095703125 +0.121125 -6.103515625e-05 -0.093658447265625 0.99923095703125 +0.12125 -6.103515625e-05 -0.093658447265625 0.99923095703125 +0.121375 -3.0517578125e-05 -0.0885009765625 0.99923095703125 +0.1215 -3.0517578125e-05 -0.0885009765625 0.99923095703125 +0.121625 -3.0517578125e-05 -0.083343505859375 0.99923095703125 +0.12175 -3.0517578125e-05 -0.07818603515625 0.99923095703125 +0.121875 -3.0517578125e-05 -0.07818603515625 0.99923095703125 +0.122 -3.0517578125e-05 -0.072998046875 0.99923095703125 +0.122125 -3.0517578125e-05 -0.072998046875 0.99923095703125 +0.12225 -3.0517578125e-05 -0.06781005859375 0.99923095703125 +0.122375 -3.0517578125e-05 -0.0626220703125 0.99923095703125 +0.1225 -3.0517578125e-05 -0.0626220703125 0.99923095703125 +0.122625 -3.0517578125e-05 -0.05743408203125 0.99923095703125 +0.12275 -3.0517578125e-05 -0.05743408203125 0.99923095703125 +0.122875 -3.0517578125e-05 -0.05224609375 0.99923095703125 +0.123 -3.0517578125e-05 -0.047027587890625 0.99923095703125 +0.123125 -3.0517578125e-05 -0.047027587890625 0.99923095703125 +0.12325 0.0 -0.04180908203125 0.99923095703125 +0.123375 0.0 -0.04180908203125 0.99923095703125 +0.1235 0.0 -0.036590576171875 0.99923095703125 +0.123625 0.0 -0.0313720703125 0.99923095703125 +0.12375 0.0 -0.0313720703125 0.99923095703125 +0.123875 0.0 -0.026123046875 0.99923095703125 +0.124 0.0 -0.026123046875 0.99923095703125 +0.124125 0.0 -0.020904541015625 0.99923095703125 +0.12425 0.0 -0.01568603515625 0.99923095703125 +0.124375 0.0 -0.01568603515625 0.99923095703125 +0.1245 0.0 -0.01043701171875 0.99923095703125 +0.124625 0.0 -0.01043701171875 0.99923095703125 +0.12475 0.0 -0.005218505859375 0.99923095703125 +0.124875 0.0 0.0 0.99923095703125 +0.125 0.0 0.0 0.99923095703125 +0.12512500000000002 0.0 0.005218505859375 0.99923095703125 +0.12525 0.0 0.005218505859375 0.99923095703125 +0.12537500000000002 0.0 0.01043701171875 0.99923095703125 +0.1255 0.0 0.01568603515625 0.99923095703125 +0.12562500000000002 0.0 0.01568603515625 0.99923095703125 +0.12575 0.0 0.020904541015625 0.99923095703125 +0.12587500000000002 0.0 0.020904541015625 0.99923095703125 +0.126 0.0 0.026123046875 0.99923095703125 +0.12612500000000002 0.0 0.0313720703125 0.99923095703125 +0.12625 0.0 0.0313720703125 0.99923095703125 +0.12637500000000002 0.0 0.036590576171875 0.99923095703125 +0.1265 0.0 0.036590576171875 0.99923095703125 +0.12662500000000002 0.0 0.04180908203125 0.99923095703125 +0.12675 3.0517578125e-05 0.047027587890625 0.99923095703125 +0.12687500000000002 3.0517578125e-05 0.047027587890625 0.99923095703125 +0.127 3.0517578125e-05 0.05224609375 0.99923095703125 +0.12712500000000002 3.0517578125e-05 0.05224609375 0.99923095703125 +0.12725 3.0517578125e-05 0.05743408203125 0.99923095703125 +0.12737500000000002 3.0517578125e-05 0.0626220703125 0.99923095703125 +0.1275 3.0517578125e-05 0.0626220703125 0.99923095703125 +0.12762500000000002 3.0517578125e-05 0.06781005859375 0.99923095703125 +0.12775 3.0517578125e-05 0.06781005859375 0.99923095703125 +0.12787500000000002 3.0517578125e-05 0.072998046875 0.99923095703125 +0.128 0.007415771484375 0.07818603515625 0.90478515625 +0.128125 0.007415771484375 0.07818603515625 0.90478515625 +0.12825 0.007904052734375 0.083343505859375 0.90478515625 +0.128375 0.007904052734375 0.083343505859375 0.90478515625 +0.1285 0.008392333984375 0.0885009765625 0.90478515625 +0.128625 0.008880615234375 0.093658447265625 0.90478515625 +0.12875 0.008880615234375 0.093658447265625 0.90478515625 +0.128875 0.0093994140625 0.098785400390625 0.90478515625 +0.129 0.0093994140625 0.098785400390625 0.90478515625 +0.129125 0.009857177734375 0.103912353515625 0.90478515625 +0.12925 0.010345458984375 0.109039306640625 0.90478515625 +0.129375 0.010345458984375 0.109039306640625 0.90478515625 +0.1295 0.010833740234375 0.1141357421875 0.90478515625 +0.129625 0.010833740234375 0.1141357421875 0.90478515625 +0.12975 0.011322021484375 0.119232177734375 0.90478515625 +0.129875 0.011810302734375 0.124298095703125 0.90478515625 +0.13 0.011810302734375 0.124298095703125 0.90478515625 +0.130125 0.012298583984375 0.129364013671875 0.90478515625 +0.13025 0.012298583984375 0.129364013671875 0.90478515625 +0.130375 0.012786865234375 0.134429931640625 0.90478515625 +0.1305 0.01324462890625 0.13946533203125 0.90478515625 +0.130625 0.01324462890625 0.13946533203125 0.90478515625 +0.13075 0.01373291015625 0.14447021484375 0.90478515625 +0.130875 0.01373291015625 0.14447021484375 0.90478515625 +0.131 0.01422119140625 0.14947509765625 0.90478515625 +0.131125 0.014678955078125 0.15447998046875 0.90478515625 +0.13125 0.014678955078125 0.15447998046875 0.90478515625 +0.131375 0.015167236328125 0.159454345703125 0.90478515625 +0.1315 0.015167236328125 0.159454345703125 0.90478515625 +0.131625 0.015625 0.164398193359375 0.90478515625 +0.13175 0.016082763671875 0.169342041015625 0.90478515625 +0.131875 0.016082763671875 0.169342041015625 0.90478515625 +0.132 0.016571044921875 0.17425537109375 0.90478515625 +0.132125 0.016571044921875 0.17425537109375 0.90478515625 +0.13225 0.01702880859375 0.17913818359375 0.90478515625 +0.132375 0.017486572265625 0.18402099609375 0.90478515625 +0.1325 0.017486572265625 0.18402099609375 0.90478515625 +0.132625 0.0179443359375 0.188873291015625 0.90478515625 +0.13275 0.0179443359375 0.188873291015625 0.90478515625 +0.132875 0.018402099609375 0.1937255859375 0.90478515625 +0.133 0.01885986328125 0.19854736328125 0.90478515625 +0.133125 0.01885986328125 0.19854736328125 0.90478515625 +0.13325 0.019317626953125 0.203338623046875 0.90478515625 +0.133375 0.019317626953125 0.203338623046875 0.90478515625 +0.1335 0.019775390625 0.208099365234375 0.90478515625 +0.133625 0.020233154296875 0.212860107421875 0.90478515625 +0.13375 0.020233154296875 0.212860107421875 0.90478515625 +0.133875 0.02069091796875 0.21759033203125 0.90478515625 +0.134 0.02069091796875 0.21759033203125 0.90478515625 +0.134125 0.0211181640625 0.2222900390625 0.90478515625 +0.13425 0.021575927734375 0.226959228515625 0.90478515625 +0.134375 0.021575927734375 0.226959228515625 0.90478515625 +0.1345 0.022003173828125 0.231597900390625 0.90478515625 +0.134625 0.022003173828125 0.231597900390625 0.90478515625 +0.13475 0.0224609375 0.236236572265625 0.90478515625 +0.134875 0.02288818359375 0.2408447265625 0.90478515625 +0.135 0.02288818359375 0.2408447265625 0.90478515625 +0.135125 0.023345947265625 0.24542236328125 0.90478515625 +0.13525 0.023345947265625 0.24542236328125 0.90478515625 +0.135375 0.023773193359375 0.249969482421875 0.90478515625 +0.1355 0.024200439453125 0.25445556640625 0.90478515625 +0.135625 0.024200439453125 0.25445556640625 0.90478515625 +0.13575 0.024627685546875 0.25897216796875 0.90478515625 +0.135875 0.024627685546875 0.25897216796875 0.90478515625 +0.136 0.025054931640625 0.263427734375 0.90478515625 +0.136125 0.025482177734375 0.267852783203125 0.90478515625 +0.13625 0.025482177734375 0.267852783203125 0.90478515625 +0.136375 0.02587890625 0.27227783203125 0.90478515625 +0.1365 0.02587890625 0.27227783203125 0.90478515625 +0.136625 0.02630615234375 0.276641845703125 0.90478515625 +0.13675 0.026702880859375 0.280975341796875 0.90478515625 +0.136875 0.026702880859375 0.280975341796875 0.90478515625 +0.137 0.027130126953125 0.285308837890625 0.90478515625 +0.137125 0.027130126953125 0.285308837890625 0.90478515625 +0.13725 0.02752685546875 0.289581298828125 0.90478515625 +0.137375 0.027923583984375 0.2938232421875 0.90478515625 +0.1375 0.027923583984375 0.2938232421875 0.90478515625 +0.137625 0.028350830078125 0.298065185546875 0.90478515625 +0.13775 0.028350830078125 0.298065185546875 0.90478515625 +0.137875 0.02874755859375 0.30224609375 0.90478515625 +0.138 0.029144287109375 0.306396484375 0.90478515625 +0.138125 0.029144287109375 0.306396484375 0.90478515625 +0.13825 0.029541015625 0.310516357421875 0.90478515625 +0.138375 0.029541015625 0.310516357421875 0.90478515625 +0.1385 0.0299072265625 0.314605712890625 0.90478515625 +0.138625 0.030303955078125 0.31866455078125 0.90478515625 +0.13875 0.030303955078125 0.31866455078125 0.90478515625 +0.138875 0.030670166015625 0.322662353515625 0.90478515625 +0.139 0.030670166015625 0.322662353515625 0.90478515625 +0.139125 0.03106689453125 0.32666015625 0.90478515625 +0.13925 0.03143310546875 0.330596923828125 0.90478515625 +0.139375 0.03143310546875 0.330596923828125 0.90478515625 +0.1395 0.03179931640625 0.334503173828125 0.90478515625 +0.139625 0.03179931640625 0.334503173828125 0.90478515625 +0.13975 0.03216552734375 0.33837890625 0.90478515625 +0.139875 0.03253173828125 0.34222412109375 0.90478515625 +0.14 0.03253173828125 0.34222412109375 0.90478515625 +0.140125 0.03289794921875 0.34600830078125 0.90478515625 +0.14025 0.03289794921875 0.34600830078125 0.90478515625 +0.140375 0.03326416015625 0.349761962890625 0.90478515625 +0.1405 0.033599853515625 0.353485107421875 0.90478515625 +0.140625 0.033599853515625 0.353485107421875 0.90478515625 +0.14075000000000002 0.033966064453125 0.357177734375 0.90478515625 +0.140875 0.033966064453125 0.357177734375 0.90478515625 +0.14100000000000002 0.0343017578125 0.360809326171875 0.90478515625 +0.141125 0.03466796875 0.36444091796875 0.90478515625 +0.14125000000000002 0.03466796875 0.36444091796875 0.90478515625 +0.141375 0.035003662109375 0.36798095703125 0.90478515625 +0.14150000000000002 0.035003662109375 0.36798095703125 0.90478515625 +0.141625 0.03533935546875 0.37152099609375 0.90478515625 +0.14175000000000002 0.03564453125 0.375 0.90478515625 +0.141875 0.03564453125 0.375 0.90478515625 +0.14200000000000002 0.035980224609375 0.378448486328125 0.90478515625 +0.142125 0.035980224609375 0.378448486328125 0.90478515625 +0.14225000000000002 0.03631591796875 0.3818359375 0.90478515625 +0.142375 0.03662109375 0.38519287109375 0.90478515625 +0.14250000000000002 0.03662109375 0.38519287109375 0.90478515625 +0.142625 0.036956787109375 0.388519287109375 0.90478515625 +0.14275000000000002 0.036956787109375 0.388519287109375 0.90478515625 +0.142875 0.037261962890625 0.39178466796875 0.90478515625 +0.14300000000000002 0.037567138671875 0.39501953125 0.90478515625 +0.143125 0.037567138671875 0.39501953125 0.90478515625 +0.14325000000000002 0.037872314453125 0.398193359375 0.90478515625 +0.143375 0.037872314453125 0.398193359375 0.90478515625 +0.14350000000000002 0.038177490234375 0.401336669921875 0.90478515625 +0.143625 0.0384521484375 0.404449462890625 0.90478515625 +0.14375000000000002 0.0384521484375 0.404449462890625 0.90478515625 +0.143875 0.03875732421875 0.407501220703125 0.90478515625 +0.14400000000000002 0.03875732421875 0.407501220703125 0.90478515625 +0.144125 0.039031982421875 0.4105224609375 0.90478515625 +0.14425 0.039306640625 0.413482666015625 0.90478515625 +0.144375 0.039306640625 0.413482666015625 0.90478515625 +0.1445 0.03961181640625 0.416412353515625 0.90478515625 +0.144625 0.03961181640625 0.416412353515625 0.90478515625 +0.14475 0.03985595703125 0.419281005859375 0.90478515625 +0.144875 0.040130615234375 0.422119140625 0.90478515625 +0.145 0.040130615234375 0.422119140625 0.90478515625 +0.145125 0.0404052734375 0.424896240234375 0.90478515625 +0.14525 0.0404052734375 0.424896240234375 0.90478515625 +0.145375 0.040679931640625 0.4276123046875 0.90478515625 +0.1455 0.040924072265625 0.4302978515625 0.90478515625 +0.145625 0.040924072265625 0.4302978515625 0.90478515625 +0.14575 0.041168212890625 0.432952880859375 0.90478515625 +0.145875 0.041168212890625 0.432952880859375 0.90478515625 +0.146 0.041412353515625 0.435546875 0.90478515625 +0.146125 0.041656494140625 0.438079833984375 0.90478515625 +0.14625 0.041656494140625 0.438079833984375 0.90478515625 +0.146375 0.041900634765625 0.440582275390625 0.90478515625 +0.1465 0.041900634765625 0.440582275390625 0.90478515625 +0.146625 0.042144775390625 0.44305419921875 0.90478515625 +0.14675 0.0423583984375 0.4454345703125 0.90478515625 +0.146875 0.0423583984375 0.4454345703125 0.90478515625 +0.147 0.042572021484375 0.447784423828125 0.90478515625 +0.147125 0.042572021484375 0.447784423828125 0.90478515625 +0.14725 0.042816162109375 0.450103759765625 0.90478515625 +0.147375 0.04302978515625 0.452362060546875 0.90478515625 +0.1475 0.04302978515625 0.452362060546875 0.90478515625 +0.147625 0.043212890625 0.454559326171875 0.90478515625 +0.14775 0.043212890625 0.454559326171875 0.90478515625 +0.147875 0.043426513671875 0.45672607421875 0.90478515625 +0.148 0.04364013671875 0.458831787109375 0.90478515625 +0.148125 0.04364013671875 0.458831787109375 0.90478515625 +0.14825 0.0438232421875 0.46087646484375 0.90478515625 +0.148375 0.0438232421875 0.46087646484375 0.90478515625 +0.1485 0.04400634765625 0.462890625 0.90478515625 +0.148625 0.044189453125 0.464813232421875 0.90478515625 +0.14875 0.044189453125 0.464813232421875 0.90478515625 +0.148875 0.04437255859375 0.46673583984375 0.90478515625 +0.149 0.04437255859375 0.46673583984375 0.90478515625 +0.149125 0.0445556640625 0.46856689453125 0.90478515625 +0.14925 0.04473876953125 0.470367431640625 0.90478515625 +0.149375 0.04473876953125 0.470367431640625 0.90478515625 +0.1495 0.044891357421875 0.472137451171875 0.90478515625 +0.149625 0.044891357421875 0.472137451171875 0.90478515625 +0.14975 0.045074462890625 0.47381591796875 0.90478515625 +0.149875 0.04522705078125 0.4754638671875 0.90478515625 +0.15 0.04522705078125 0.4754638671875 0.90478515625 +0.150125 0.045379638671875 0.47705078125 0.90478515625 +0.15025 0.045379638671875 0.47705078125 0.90478515625 +0.150375 0.045501708984375 0.478607177734375 0.90478515625 +0.1505 0.045654296875 0.480072021484375 0.90478515625 +0.150625 0.045654296875 0.480072021484375 0.90478515625 +0.15075 0.0457763671875 0.48150634765625 0.90478515625 +0.150875 0.0457763671875 0.48150634765625 0.90478515625 +0.151 0.045928955078125 0.48291015625 0.90478515625 +0.151125 0.046051025390625 0.484222412109375 0.90478515625 +0.15125 0.046051025390625 0.484222412109375 0.90478515625 +0.151375 0.046173095703125 0.485504150390625 0.90478515625 +0.1515 0.046173095703125 0.485504150390625 0.90478515625 +0.151625 0.046295166015625 0.486724853515625 0.90478515625 +0.15175 0.04638671875 0.487884521484375 0.90478515625 +0.151875 0.04638671875 0.487884521484375 0.90478515625 +0.152 0.0465087890625 0.489013671875 0.90478515625 +0.152125 0.0465087890625 0.489013671875 0.90478515625 +0.15225 0.046600341796875 0.490081787109375 0.90478515625 +0.152375 0.04669189453125 0.4910888671875 0.90478515625 +0.1525 0.04669189453125 0.4910888671875 0.90478515625 +0.152625 0.046783447265625 0.492034912109375 0.90478515625 +0.15275 0.046783447265625 0.492034912109375 0.90478515625 +0.152875 0.046875 0.492950439453125 0.90478515625 +0.153 0.046966552734375 0.4937744140625 0.90478515625 +0.153125 0.046966552734375 0.4937744140625 0.90478515625 +0.15325 0.047027587890625 0.49456787109375 0.90478515625 +0.153375 0.047027587890625 0.49456787109375 0.90478515625 +0.1535 0.047088623046875 0.49530029296875 0.90478515625 +0.153625 0.04718017578125 0.496002197265625 0.90478515625 +0.15375 0.04718017578125 0.496002197265625 0.90478515625 +0.153875 0.0472412109375 0.496612548828125 0.90478515625 +0.154 0.0472412109375 0.496612548828125 0.90478515625 +0.154125 0.047271728515625 0.4971923828125 0.90478515625 +0.15425 0.047332763671875 0.497711181640625 0.90478515625 +0.154375 0.047332763671875 0.497711181640625 0.90478515625 +0.1545 0.04736328125 0.498199462890625 0.90478515625 +0.154625 0.04736328125 0.498199462890625 0.90478515625 +0.15475 0.04742431640625 0.49859619140625 0.90478515625 +0.154875 0.047454833984375 0.49896240234375 0.90478515625 +0.155 0.047454833984375 0.49896240234375 0.90478515625 +0.155125 0.0474853515625 0.499267578125 0.90478515625 +0.15525 0.0474853515625 0.499267578125 0.90478515625 +0.155375 0.047515869140625 0.49951171875 0.90478515625 +0.1555 0.047515869140625 0.49969482421875 0.90478515625 +0.155625 0.047515869140625 0.49969482421875 0.90478515625 +0.15575 0.04754638671875 0.49981689453125 0.90478515625 +0.155875 0.04754638671875 0.49981689453125 0.90478515625 +0.156 0.04754638671875 0.499908447265625 0.90478515625 +0.156125 0.04754638671875 0.49993896484375 0.90478515625 +0.15625 0.04754638671875 0.49993896484375 0.90478515625 +0.15637500000000002 0.04754638671875 0.499908447265625 0.90478515625 +0.1565 0.04754638671875 0.499908447265625 0.90478515625 +0.15662500000000002 0.04754638671875 0.49981689453125 0.90478515625 +0.15675 0.047515869140625 0.49969482421875 0.90478515625 +0.15687500000000002 0.047515869140625 0.49969482421875 0.90478515625 +0.157 0.047515869140625 0.49951171875 0.90478515625 +0.15712500000000002 0.047515869140625 0.49951171875 0.90478515625 +0.15725 0.0474853515625 0.499267578125 0.90478515625 +0.15737500000000002 0.047454833984375 0.49896240234375 0.90478515625 +0.1575 0.047454833984375 0.49896240234375 0.90478515625 +0.15762500000000002 0.04742431640625 0.49859619140625 0.90478515625 +0.15775 0.04742431640625 0.49859619140625 0.90478515625 +0.15787500000000002 0.04736328125 0.498199462890625 0.90478515625 +0.158 0.047332763671875 0.497711181640625 0.90478515625 +0.15812500000000002 0.047332763671875 0.497711181640625 0.90478515625 +0.15825 0.047271728515625 0.4971923828125 0.90478515625 +0.15837500000000002 0.047271728515625 0.4971923828125 0.90478515625 +0.1585 0.0472412109375 0.496612548828125 0.90478515625 +0.15862500000000002 0.04718017578125 0.496002197265625 0.90478515625 +0.15875 0.04718017578125 0.496002197265625 0.90478515625 +0.15887500000000002 0.047088623046875 0.49530029296875 0.90478515625 +0.159 0.047088623046875 0.49530029296875 0.90478515625 +0.15912500000000002 0.047027587890625 0.49456787109375 0.90478515625 +0.15925 0.046966552734375 0.4937744140625 0.90478515625 +0.15937500000000002 0.046966552734375 0.4937744140625 0.90478515625 +0.1595 0.046875 0.492950439453125 0.90478515625 +0.15962500000000002 0.046875 0.492950439453125 0.90478515625 +0.15975 0.046783447265625 0.492034912109375 0.90478515625 +0.15987500000000002 0.04669189453125 0.4910888671875 0.90478515625 +0.16 0.163970947265625 0.4910888671875 0.665972900390625 +0.160125 0.16363525390625 0.490081787109375 0.665972900390625 +0.16025 0.16363525390625 0.490081787109375 0.665972900390625 +0.160375 0.163299560546875 0.489013671875 0.665972900390625 +0.1605 0.16290283203125 0.487884521484375 0.665972900390625 +0.160625 0.16290283203125 0.487884521484375 0.665972900390625 +0.16075 0.16253662109375 0.486724853515625 0.665972900390625 +0.160875 0.16253662109375 0.486724853515625 0.665972900390625 +0.161 0.162109375 0.485504150390625 0.665972900390625 +0.161125 0.16168212890625 0.484222412109375 0.665972900390625 +0.16125 0.16168212890625 0.484222412109375 0.665972900390625 +0.161375 0.1612548828125 0.48291015625 0.665972900390625 +0.1615 0.1612548828125 0.48291015625 0.665972900390625 +0.161625 0.160797119140625 0.48150634765625 0.665972900390625 +0.16175 0.160308837890625 0.480072021484375 0.665972900390625 +0.161875 0.160308837890625 0.480072021484375 0.665972900390625 +0.162 0.159820556640625 0.478607177734375 0.665972900390625 +0.162125 0.159820556640625 0.478607177734375 0.665972900390625 +0.16225 0.1593017578125 0.47705078125 0.665972900390625 +0.162375 0.158782958984375 0.4754638671875 0.665972900390625 +0.1625 0.158782958984375 0.4754638671875 0.665972900390625 +0.162625 0.158203125 0.47381591796875 0.665972900390625 +0.16275 0.158203125 0.47381591796875 0.665972900390625 +0.162875 0.15765380859375 0.472137451171875 0.665972900390625 +0.163 0.157073974609375 0.470367431640625 0.665972900390625 +0.163125 0.157073974609375 0.470367431640625 0.665972900390625 +0.16325 0.156463623046875 0.46856689453125 0.665972900390625 +0.163375 0.156463623046875 0.46856689453125 0.665972900390625 +0.1635 0.155853271484375 0.46673583984375 0.665972900390625 +0.163625 0.15521240234375 0.464813232421875 0.665972900390625 +0.16375 0.15521240234375 0.464813232421875 0.665972900390625 +0.163875 0.154571533203125 0.462890625 0.665972900390625 +0.164 0.154571533203125 0.462890625 0.665972900390625 +0.164125 0.153900146484375 0.46087646484375 0.665972900390625 +0.16425 0.1531982421875 0.458831787109375 0.665972900390625 +0.164375 0.1531982421875 0.458831787109375 0.665972900390625 +0.1645 0.152496337890625 0.45672607421875 0.665972900390625 +0.164625 0.152496337890625 0.45672607421875 0.665972900390625 +0.16475 0.15179443359375 0.454559326171875 0.665972900390625 +0.164875 0.15106201171875 0.452362060546875 0.665972900390625 +0.165 0.15106201171875 0.452362060546875 0.665972900390625 +0.165125 0.150299072265625 0.450103759765625 0.665972900390625 +0.16525 0.150299072265625 0.450103759765625 0.665972900390625 +0.165375 0.1495361328125 0.447784423828125 0.665972900390625 +0.1655 0.14874267578125 0.4454345703125 0.665972900390625 +0.165625 0.14874267578125 0.4454345703125 0.665972900390625 +0.16575 0.14794921875 0.44305419921875 0.665972900390625 +0.165875 0.14794921875 0.44305419921875 0.665972900390625 +0.166 0.147125244140625 0.440582275390625 0.665972900390625 +0.166125 0.146270751953125 0.438079833984375 0.665972900390625 +0.16625 0.146270751953125 0.438079833984375 0.665972900390625 +0.166375 0.14544677734375 0.435546875 0.665972900390625 +0.1665 0.14544677734375 0.435546875 0.665972900390625 +0.166625 0.144561767578125 0.432952880859375 0.665972900390625 +0.16675 0.1436767578125 0.4302978515625 0.665972900390625 +0.166875 0.1436767578125 0.4302978515625 0.665972900390625 +0.167 0.142791748046875 0.4276123046875 0.665972900390625 +0.167125 0.142791748046875 0.4276123046875 0.665972900390625 +0.16725 0.141876220703125 0.424896240234375 0.665972900390625 +0.167375 0.140960693359375 0.422119140625 0.665972900390625 +0.1675 0.140960693359375 0.422119140625 0.665972900390625 +0.167625 0.1400146484375 0.419281005859375 0.665972900390625 +0.16775 0.1400146484375 0.419281005859375 0.665972900390625 +0.167875 0.1390380859375 0.416412353515625 0.665972900390625 +0.168 0.1380615234375 0.413482666015625 0.665972900390625 +0.168125 0.1380615234375 0.413482666015625 0.665972900390625 +0.16825 0.1370849609375 0.4105224609375 0.665972900390625 +0.168375 0.1370849609375 0.4105224609375 0.665972900390625 +0.1685 0.136077880859375 0.407501220703125 0.665972900390625 +0.168625 0.135040283203125 0.404449462890625 0.665972900390625 +0.16875 0.135040283203125 0.404449462890625 0.665972900390625 +0.168875 0.134002685546875 0.401336669921875 0.665972900390625 +0.169 0.134002685546875 0.401336669921875 0.665972900390625 +0.169125 0.132965087890625 0.398193359375 0.665972900390625 +0.16925 0.13189697265625 0.39501953125 0.665972900390625 +0.169375 0.13189697265625 0.39501953125 0.665972900390625 +0.1695 0.130828857421875 0.39178466796875 0.665972900390625 +0.169625 0.130828857421875 0.39178466796875 0.665972900390625 +0.16975 0.129730224609375 0.388519287109375 0.665972900390625 +0.169875 0.128631591796875 0.38519287109375 0.665972900390625 +0.17 0.128631591796875 0.38519287109375 0.665972900390625 +0.170125 0.12750244140625 0.3818359375 0.665972900390625 +0.17025 0.12750244140625 0.3818359375 0.665972900390625 +0.170375 0.126373291015625 0.378448486328125 0.665972900390625 +0.1705 0.125213623046875 0.375 0.665972900390625 +0.170625 0.125213623046875 0.375 0.665972900390625 +0.17075 0.124053955078125 0.37152099609375 0.665972900390625 +0.170875 0.124053955078125 0.37152099609375 0.665972900390625 +0.171 0.12286376953125 0.36798095703125 0.665972900390625 +0.171125 0.1217041015625 0.36444091796875 0.665972900390625 +0.17125 0.1217041015625 0.36444091796875 0.665972900390625 +0.171375 0.1204833984375 0.360809326171875 0.665972900390625 +0.1715 0.1204833984375 0.360809326171875 0.665972900390625 +0.171625 0.1192626953125 0.357177734375 0.665972900390625 +0.17175 0.1180419921875 0.353485107421875 0.665972900390625 +0.171875 0.1180419921875 0.353485107421875 0.665972900390625 +0.17200000000000002 0.116790771484375 0.349761962890625 0.665972900390625 +0.172125 0.116790771484375 0.349761962890625 0.665972900390625 +0.17225000000000002 0.11553955078125 0.34600830078125 0.665972900390625 +0.172375 0.1142578125 0.34222412109375 0.665972900390625 +0.17250000000000002 0.1142578125 0.34222412109375 0.665972900390625 +0.172625 0.113006591796875 0.33837890625 0.665972900390625 +0.17275000000000002 0.113006591796875 0.33837890625 0.665972900390625 +0.172875 0.1116943359375 0.334503173828125 0.665972900390625 +0.17300000000000002 0.110382080078125 0.330596923828125 0.665972900390625 +0.173125 0.110382080078125 0.330596923828125 0.665972900390625 +0.17325000000000002 0.10906982421875 0.32666015625 0.665972900390625 +0.173375 0.10906982421875 0.32666015625 0.665972900390625 +0.17350000000000002 0.107757568359375 0.322662353515625 0.665972900390625 +0.173625 0.106414794921875 0.31866455078125 0.665972900390625 +0.17375000000000002 0.106414794921875 0.31866455078125 0.665972900390625 +0.173875 0.10504150390625 0.314605712890625 0.665972900390625 +0.17400000000000002 0.10504150390625 0.314605712890625 0.665972900390625 +0.174125 0.10369873046875 0.310516357421875 0.665972900390625 +0.17425000000000002 0.102325439453125 0.306396484375 0.665972900390625 +0.174375 0.102325439453125 0.306396484375 0.665972900390625 +0.17450000000000002 0.100921630859375 0.30224609375 0.665972900390625 +0.174625 0.100921630859375 0.30224609375 0.665972900390625 +0.17475000000000002 0.099517822265625 0.298065185546875 0.665972900390625 +0.174875 0.098114013671875 0.2938232421875 0.665972900390625 +0.17500000000000002 0.098114013671875 0.2938232421875 0.665972900390625 +0.175125 0.096710205078125 0.289581298828125 0.665972900390625 +0.17525000000000002 0.096710205078125 0.289581298828125 0.665972900390625 +0.175375 0.09527587890625 0.285308837890625 0.665972900390625 +0.17550000000000002 0.09381103515625 0.280975341796875 0.665972900390625 +0.175625 0.09381103515625 0.280975341796875 0.665972900390625 +0.17575000000000002 0.092376708984375 0.276641845703125 0.665972900390625 +0.175875 0.092376708984375 0.276641845703125 0.665972900390625 +0.176 0.090911865234375 0.27227783203125 0.665972900390625 +0.176125 0.089447021484375 0.267852783203125 0.665972900390625 +0.17625 0.089447021484375 0.267852783203125 0.665972900390625 +0.176375 0.08795166015625 0.263427734375 0.665972900390625 +0.1765 0.08795166015625 0.263427734375 0.665972900390625 +0.176625 0.08648681640625 0.25897216796875 0.665972900390625 +0.17675 0.0849609375 0.25445556640625 0.665972900390625 +0.176875 0.0849609375 0.25445556640625 0.665972900390625 +0.177 0.083465576171875 0.249969482421875 0.665972900390625 +0.177125 0.083465576171875 0.249969482421875 0.665972900390625 +0.17725 0.081939697265625 0.24542236328125 0.665972900390625 +0.177375 0.080413818359375 0.2408447265625 0.665972900390625 +0.1775 0.080413818359375 0.2408447265625 0.665972900390625 +0.177625 0.078887939453125 0.236236572265625 0.665972900390625 +0.17775 0.078887939453125 0.236236572265625 0.665972900390625 +0.177875 0.07733154296875 0.231597900390625 0.665972900390625 +0.178 0.075775146484375 0.226959228515625 0.665972900390625 +0.178125 0.075775146484375 0.226959228515625 0.665972900390625 +0.17825 0.07421875 0.2222900390625 0.665972900390625 +0.178375 0.07421875 0.2222900390625 0.665972900390625 +0.1785 0.072662353515625 0.21759033203125 0.665972900390625 +0.178625 0.071075439453125 0.212860107421875 0.665972900390625 +0.17875 0.071075439453125 0.212860107421875 0.665972900390625 +0.178875 0.069488525390625 0.208099365234375 0.665972900390625 +0.179 0.069488525390625 0.208099365234375 0.665972900390625 +0.179125 0.067901611328125 0.203338623046875 0.665972900390625 +0.17925 0.0662841796875 0.19854736328125 0.665972900390625 +0.179375 0.0662841796875 0.19854736328125 0.665972900390625 +0.1795 0.064666748046875 0.1937255859375 0.665972900390625 +0.179625 0.064666748046875 0.1937255859375 0.665972900390625 +0.17975 0.06304931640625 0.188873291015625 0.665972900390625 +0.179875 0.061431884765625 0.18402099609375 0.665972900390625 +0.18 0.061431884765625 0.18402099609375 0.665972900390625 +0.180125 0.059814453125 0.17913818359375 0.665972900390625 +0.18025 0.059814453125 0.17913818359375 0.665972900390625 +0.180375 0.05816650390625 0.17425537109375 0.665972900390625 +0.1805 0.056549072265625 0.169342041015625 0.665972900390625 +0.180625 0.056549072265625 0.169342041015625 0.665972900390625 +0.18075 0.054901123046875 0.164398193359375 0.665972900390625 +0.180875 0.054901123046875 0.164398193359375 0.665972900390625 +0.181 0.05322265625 0.159454345703125 0.665972900390625 +0.181125 0.05157470703125 0.15447998046875 0.665972900390625 +0.18125 0.05157470703125 0.15447998046875 0.665972900390625 +0.181375 0.049896240234375 0.14947509765625 0.665972900390625 +0.1815 0.049896240234375 0.14947509765625 0.665972900390625 +0.181625 0.048248291015625 0.14447021484375 0.665972900390625 +0.18175 0.04656982421875 0.13946533203125 0.665972900390625 +0.181875 0.04656982421875 0.13946533203125 0.665972900390625 +0.182 0.044891357421875 0.134429931640625 0.665972900390625 +0.182125 0.044891357421875 0.134429931640625 0.665972900390625 +0.18225 0.043182373046875 0.129364013671875 0.665972900390625 +0.182375 0.04150390625 0.124298095703125 0.665972900390625 +0.1825 0.04150390625 0.124298095703125 0.665972900390625 +0.182625 0.039794921875 0.119232177734375 0.665972900390625 +0.18275 0.039794921875 0.119232177734375 0.665972900390625 +0.182875 0.038116455078125 0.1141357421875 0.665972900390625 +0.183 0.036407470703125 0.109039306640625 0.665972900390625 +0.183125 0.036407470703125 0.109039306640625 0.665972900390625 +0.18325 0.034698486328125 0.103912353515625 0.665972900390625 +0.183375 0.034698486328125 0.103912353515625 0.665972900390625 +0.1835 0.032989501953125 0.098785400390625 0.665972900390625 +0.183625 0.03125 0.093658447265625 0.665972900390625 +0.18375 0.03125 0.093658447265625 0.665972900390625 +0.183875 0.029541015625 0.0885009765625 0.665972900390625 +0.184 0.029541015625 0.0885009765625 0.665972900390625 +0.184125 0.02783203125 0.083343505859375 0.665972900390625 +0.18425 0.026092529296875 0.07818603515625 0.665972900390625 +0.184375 0.026092529296875 0.07818603515625 0.665972900390625 +0.1845 0.024383544921875 0.072998046875 0.665972900390625 +0.184625 0.024383544921875 0.072998046875 0.665972900390625 +0.18475 0.02264404296875 0.06781005859375 0.665972900390625 +0.184875 0.020904541015625 0.0626220703125 0.665972900390625 +0.185 0.020904541015625 0.0626220703125 0.665972900390625 +0.185125 0.0191650390625 0.05743408203125 0.665972900390625 +0.18525 0.0191650390625 0.05743408203125 0.665972900390625 +0.185375 0.017425537109375 0.05224609375 0.665972900390625 +0.1855 0.01568603515625 0.047027587890625 0.665972900390625 +0.185625 0.01568603515625 0.047027587890625 0.665972900390625 +0.18575 0.013946533203125 0.04180908203125 0.665972900390625 +0.185875 0.013946533203125 0.04180908203125 0.665972900390625 +0.186 0.01220703125 0.036590576171875 0.665972900390625 +0.186125 0.010467529296875 0.0313720703125 0.665972900390625 +0.18625 0.010467529296875 0.0313720703125 0.665972900390625 +0.186375 0.00872802734375 0.026123046875 0.665972900390625 +0.1865 0.00872802734375 0.026123046875 0.665972900390625 +0.186625 0.006988525390625 0.020904541015625 0.665972900390625 +0.18675 0.005218505859375 0.01568603515625 0.665972900390625 +0.186875 0.005218505859375 0.01568603515625 0.665972900390625 +0.187 0.00347900390625 0.01043701171875 0.665972900390625 +0.187125 0.00347900390625 0.01043701171875 0.665972900390625 +0.18725 0.001739501953125 0.005218505859375 0.665972900390625 +0.187375 0.0 0.0 0.665972900390625 +0.1875 0.0 0.0 0.665972900390625 +0.1876250000000000256 -0.001739501953125 -0.005218505859375 0.665972900390625 +0.18775 -0.001739501953125 -0.005218505859375 0.665972900390625 +0.1878750000000000256 -0.00347900390625 -0.01043701171875 0.665972900390625 +0.188 -0.005218505859375 -0.01568603515625 0.665972900390625 +0.1881250000000000256 -0.005218505859375 -0.01568603515625 0.665972900390625 +0.18825 -0.006988525390625 -0.020904541015625 0.665972900390625 +0.1883750000000000256 -0.006988525390625 -0.020904541015625 0.665972900390625 +0.1885 -0.00872802734375 -0.026123046875 0.665972900390625 +0.1886250000000000256 -0.010467529296875 -0.0313720703125 0.665972900390625 +0.18875 -0.010467529296875 -0.0313720703125 0.665972900390625 +0.1888750000000000256 -0.01220703125 -0.036590576171875 0.665972900390625 +0.189 -0.01220703125 -0.036590576171875 0.665972900390625 +0.1891250000000000256 -0.013946533203125 -0.04180908203125 0.665972900390625 +0.18925 -0.01568603515625 -0.047027587890625 0.665972900390625 +0.1893750000000000256 -0.01568603515625 -0.047027587890625 0.665972900390625 +0.1895 -0.017425537109375 -0.05224609375 0.665972900390625 +0.1896250000000000256 -0.017425537109375 -0.05224609375 0.665972900390625 +0.18975 -0.0191650390625 -0.05743408203125 0.665972900390625 +0.1898750000000000256 -0.020904541015625 -0.0626220703125 0.665972900390625 +0.19 -0.020904541015625 -0.0626220703125 0.665972900390625 +0.1901250000000000256 -0.02264404296875 -0.06781005859375 0.665972900390625 +0.19025 -0.02264404296875 -0.06781005859375 0.665972900390625 +0.1903750000000000256 -0.024383544921875 -0.072998046875 0.665972900390625 +0.1905 -0.026092529296875 -0.07818603515625 0.665972900390625 +0.1906250000000000256 -0.026092529296875 -0.07818603515625 0.665972900390625 +0.19075 -0.02783203125 -0.083343505859375 0.665972900390625 +0.1908750000000000256 -0.02783203125 -0.083343505859375 0.665972900390625 +0.191 -0.029541015625 -0.0885009765625 0.665972900390625 +0.1911250000000000256 -0.03125 -0.093658447265625 0.665972900390625 +0.19125 -0.03125 -0.093658447265625 0.665972900390625 +0.1913750000000000256 -0.032989501953125 -0.098785400390625 0.665972900390625 +0.1915 -0.032989501953125 -0.098785400390625 0.665972900390625 +0.1916250000000000256 -0.034698486328125 -0.103912353515625 0.665972900390625 +0.19175 -0.036407470703125 -0.109039306640625 0.665972900390625 +0.1918750000000000256 -0.036407470703125 -0.109039306640625 0.665972900390625 +0.192 -0.0775146484375 -0.1141357421875 0.3209167480468749 +0.192125 -0.0775146484375 -0.1141357421875 0.3209167480468749 +0.19225 -0.080963134765625 -0.119232177734375 0.3209167480468749 +0.192375 -0.08441162109375 -0.124298095703125 0.3209167480468749 +0.1925 -0.08441162109375 -0.124298095703125 0.3209167480468749 +0.192625 -0.08782958984375 -0.129364013671875 0.3209167480468749 +0.19275 -0.08782958984375 -0.129364013671875 0.3209167480468749 +0.192875 -0.091278076171875 -0.134429931640625 0.3209167480468749 +0.193 -0.094696044921875 -0.13946533203125 0.3209167480468749 +0.193125 -0.094696044921875 -0.13946533203125 0.3209167480468749 +0.19325 -0.09808349609375 -0.14447021484375 0.3209167480468749 +0.193375 -0.09808349609375 -0.14447021484375 0.3209167480468749 +0.1935 -0.10150146484375 -0.14947509765625 0.3209167480468749 +0.193625 -0.104888916015625 -0.15447998046875 0.3209167480468749 +0.19375 -0.104888916015625 -0.15447998046875 0.3209167480468749 +0.193875 -0.1082763671875 -0.159454345703125 0.3209167480468749 +0.194 -0.1082763671875 -0.159454345703125 0.3209167480468749 +0.194125 -0.11163330078125 -0.164398193359375 0.3209167480468749 +0.19425 -0.114990234375 -0.169342041015625 0.3209167480468749 +0.194375 -0.114990234375 -0.169342041015625 0.3209167480468749 +0.1945 -0.118316650390625 -0.17425537109375 0.3209167480468749 +0.194625 -0.118316650390625 -0.17425537109375 0.3209167480468749 +0.19475 -0.12164306640625 -0.17913818359375 0.3209167480468749 +0.194875 -0.12493896484375 -0.18402099609375 0.3209167480468749 +0.195 -0.12493896484375 -0.18402099609375 0.3209167480468749 +0.195125 -0.12823486328125 -0.188873291015625 0.3209167480468749 +0.19525 -0.12823486328125 -0.188873291015625 0.3209167480468749 +0.195375 -0.13153076171875 -0.1937255859375 0.3209167480468749 +0.1955 -0.134796142578125 -0.19854736328125 0.3209167480468749 +0.195625 -0.134796142578125 -0.19854736328125 0.3209167480468749 +0.19575 -0.1380615234375 -0.203338623046875 0.3209167480468749 +0.195875 -0.1380615234375 -0.203338623046875 0.3209167480468749 +0.196 -0.14129638671875 -0.208099365234375 0.3209167480468749 +0.196125 -0.14453125 -0.212860107421875 0.3209167480468749 +0.19625 -0.14453125 -0.212860107421875 0.3209167480468749 +0.196375 -0.147735595703125 -0.21759033203125 0.3209167480468749 +0.1965 -0.147735595703125 -0.21759033203125 0.3209167480468749 +0.196625 -0.15093994140625 -0.2222900390625 0.3209167480468749 +0.19675 -0.154083251953125 -0.226959228515625 0.3209167480468749 +0.196875 -0.154083251953125 -0.226959228515625 0.3209167480468749 +0.197 -0.157257080078125 -0.231597900390625 0.3209167480468749 +0.197125 -0.157257080078125 -0.231597900390625 0.3209167480468749 +0.19725 -0.160400390625 -0.236236572265625 0.3209167480468749 +0.197375 -0.16351318359375 -0.2408447265625 0.3209167480468749 +0.1975 -0.16351318359375 -0.2408447265625 0.3209167480468749 +0.197625 -0.1666259765625 -0.24542236328125 0.3209167480468749 +0.19775 -0.1666259765625 -0.24542236328125 0.3209167480468749 +0.197875 -0.169708251953125 -0.249969482421875 0.3209167480468749 +0.198 -0.17279052734375 -0.25445556640625 0.3209167480468749 +0.198125 -0.17279052734375 -0.25445556640625 0.3209167480468749 +0.19825 -0.17584228515625 -0.25897216796875 0.3209167480468749 +0.198375 -0.17584228515625 -0.25897216796875 0.3209167480468749 +0.1985 -0.178863525390625 -0.263427734375 0.3209167480468749 +0.198625 -0.181884765625 -0.267852783203125 0.3209167480468749 +0.19875 -0.181884765625 -0.267852783203125 0.3209167480468749 +0.198875 -0.18487548828125 -0.27227783203125 0.3209167480468749 +0.199 -0.18487548828125 -0.27227783203125 0.3209167480468749 +0.199125 -0.187835693359375 -0.276641845703125 0.3209167480468749 +0.19925 -0.1907958984375 -0.280975341796875 0.3209167480468749 +0.199375 -0.1907958984375 -0.280975341796875 0.3209167480468749 +0.1995 -0.1937255859375 -0.285308837890625 0.3209167480468749 +0.199625 -0.1937255859375 -0.285308837890625 0.3209167480468749 +0.19975 -0.196624755859375 -0.289581298828125 0.3209167480468749 +0.199875 -0.19952392578125 -0.2938232421875 0.3209167480468749 +0.2 -0.19952392578125 -0.2938232421875 0.3209167480468749 +0.200125 -0.202392578125 -0.298065185546875 0.3209167480468749 +0.20025 -0.202392578125 -0.298065185546875 0.3209167480468749 +0.200375 -0.205230712890625 -0.30224609375 0.3209167480468749 +0.2005 -0.20806884765625 -0.306396484375 0.3209167480468749 +0.200625 -0.20806884765625 -0.306396484375 0.3209167480468749 +0.20075 -0.210845947265625 -0.310516357421875 0.3209167480468749 +0.200875 -0.210845947265625 -0.310516357421875 0.3209167480468749 +0.201 -0.213623046875 -0.314605712890625 0.3209167480468749 +0.201125 -0.21636962890625 -0.31866455078125 0.3209167480468749 +0.20125 -0.21636962890625 -0.31866455078125 0.3209167480468749 +0.201375 -0.219085693359375 -0.322662353515625 0.3209167480468749 +0.2015 -0.219085693359375 -0.322662353515625 0.3209167480468749 +0.201625 -0.2218017578125 -0.32666015625 0.3209167480468749 +0.20175 -0.2244873046875 -0.330596923828125 0.3209167480468749 +0.201875 -0.2244873046875 -0.330596923828125 0.3209167480468749 +0.202 -0.227142333984375 -0.334503173828125 0.3209167480468749 +0.202125 -0.227142333984375 -0.334503173828125 0.3209167480468749 +0.20225 -0.229766845703125 -0.33837890625 0.3209167480468749 +0.202375 -0.23236083984375 -0.34222412109375 0.3209167480468749 +0.2025 -0.23236083984375 -0.34222412109375 0.3209167480468749 +0.202625 -0.234954833984375 -0.34600830078125 0.3209167480468749 +0.20275 -0.234954833984375 -0.34600830078125 0.3209167480468749 +0.202875 -0.23748779296875 -0.349761962890625 0.3209167480468749 +0.203 -0.240020751953125 -0.353485107421875 0.3209167480468749 +0.203125 -0.240020751953125 -0.353485107421875 0.3209167480468749 +0.2032500000000000256 -0.242523193359375 -0.357177734375 0.3209167480468749 +0.203375 -0.242523193359375 -0.357177734375 0.3209167480468749 +0.2035000000000000256 -0.2449951171875 -0.360809326171875 0.3209167480468749 +0.203625 -0.247467041015625 -0.36444091796875 0.3209167480468749 +0.2037500000000000256 -0.247467041015625 -0.36444091796875 0.3209167480468749 +0.203875 -0.2498779296875 -0.36798095703125 0.3209167480468749 +0.2040000000000000256 -0.2498779296875 -0.36798095703125 0.3209167480468749 +0.204125 -0.25225830078125 -0.37152099609375 0.3209167480468749 +0.2042500000000000256 -0.254638671875 -0.375 0.3209167480468749 +0.204375 -0.254638671875 -0.375 0.3209167480468749 +0.2045000000000000256 -0.2569580078125 -0.378448486328125 0.3209167480468749 +0.204625 -0.2569580078125 -0.378448486328125 0.3209167480468749 +0.2047500000000000256 -0.25927734375 -0.3818359375 0.3209167480468749 +0.204875 -0.261566162109375 -0.38519287109375 0.3209167480468749 +0.2050000000000000256 -0.261566162109375 -0.38519287109375 0.3209167480468749 +0.205125 -0.2637939453125 -0.388519287109375 0.3209167480468749 +0.2052500000000000256 -0.2637939453125 -0.388519287109375 0.3209167480468749 +0.205375 -0.266021728515625 -0.39178466796875 0.3209167480468749 +0.2055000000000000256 -0.268218994140625 -0.39501953125 0.3209167480468749 +0.205625 -0.268218994140625 -0.39501953125 0.3209167480468749 +0.2057500000000000256 -0.2703857421875 -0.398193359375 0.3209167480468749 +0.205875 -0.2703857421875 -0.398193359375 0.3209167480468749 +0.2060000000000000256 -0.27252197265625 -0.401336669921875 0.3209167480468749 +0.206125 -0.274627685546875 -0.404449462890625 0.3209167480468749 +0.2062500000000000256 -0.274627685546875 -0.404449462890625 0.3209167480468749 +0.206375 -0.276702880859375 -0.407501220703125 0.3209167480468749 +0.2065000000000000256 -0.276702880859375 -0.407501220703125 0.3209167480468749 +0.206625 -0.27874755859375 -0.4105224609375 0.3209167480468749 +0.2067500000000000256 -0.28076171875 -0.413482666015625 0.3209167480468749 +0.206875 -0.28076171875 -0.413482666015625 0.3209167480468749 +0.2070000000000000256 -0.282745361328125 -0.416412353515625 0.3209167480468749 +0.207125 -0.282745361328125 -0.416412353515625 0.3209167480468749 +0.2072500000000000256 -0.284698486328125 -0.419281005859375 0.3209167480468749 +0.207375 -0.28662109375 -0.422119140625 0.3209167480468749 +0.2075000000000000256 -0.28662109375 -0.422119140625 0.3209167480468749 +0.207625 -0.28851318359375 -0.424896240234375 0.3209167480468749 +0.2077500000000000256 -0.28851318359375 -0.424896240234375 0.3209167480468749 +0.207875 -0.29034423828125 -0.4276123046875 0.3209167480468749 +0.208000000000000032 -0.29217529296875 -0.4302978515625 0.3209167480468749 +0.208125 -0.29217529296875 -0.4302978515625 0.3209167480468749 +0.20825 -0.293975830078125 -0.432952880859375 0.3209167480468749 +0.208375 -0.293975830078125 -0.432952880859375 0.3209167480468749 +0.2085 -0.295745849609375 -0.435546875 0.3209167480468749 +0.208625 -0.297454833984375 -0.438079833984375 0.3209167480468749 +0.20875 -0.297454833984375 -0.438079833984375 0.3209167480468749 +0.208875 -0.299163818359375 -0.440582275390625 0.3209167480468749 +0.209 -0.299163818359375 -0.440582275390625 0.3209167480468749 +0.209125 -0.30084228515625 -0.44305419921875 0.3209167480468749 +0.20925 -0.302459716796875 -0.4454345703125 0.3209167480468749 +0.209375 -0.302459716796875 -0.4454345703125 0.3209167480468749 +0.2095 -0.304046630859375 -0.447784423828125 0.3209167480468749 +0.209625 -0.304046630859375 -0.447784423828125 0.3209167480468749 +0.20975 -0.305633544921875 -0.450103759765625 0.3209167480468749 +0.209875 -0.307159423828125 -0.452362060546875 0.3209167480468749 +0.21 -0.307159423828125 -0.452362060546875 0.3209167480468749 +0.210125 -0.30865478515625 -0.454559326171875 0.3209167480468749 +0.21025 -0.30865478515625 -0.454559326171875 0.3209167480468749 +0.210375 -0.31011962890625 -0.45672607421875 0.3209167480468749 +0.2105 -0.311553955078125 -0.458831787109375 0.3209167480468749 +0.210625 -0.311553955078125 -0.458831787109375 0.3209167480468749 +0.21075 -0.31292724609375 -0.46087646484375 0.3209167480468749 +0.210875 -0.31292724609375 -0.46087646484375 0.3209167480468749 +0.211 -0.314300537109375 -0.462890625 0.3209167480468749 +0.211125 -0.31561279296875 -0.464813232421875 0.3209167480468749 +0.21125 -0.31561279296875 -0.464813232421875 0.3209167480468749 +0.211375 -0.316925048828125 -0.46673583984375 0.3209167480468749 +0.2115 -0.316925048828125 -0.46673583984375 0.3209167480468749 +0.211625 -0.31817626953125 -0.46856689453125 0.3209167480468749 +0.21175 -0.31939697265625 -0.470367431640625 0.3209167480468749 +0.211875 -0.31939697265625 -0.470367431640625 0.3209167480468749 +0.212 -0.320587158203125 -0.472137451171875 0.3209167480468749 +0.212125 -0.320587158203125 -0.472137451171875 0.3209167480468749 +0.21225 -0.32171630859375 -0.47381591796875 0.3209167480468749 +0.212375 -0.322845458984375 -0.4754638671875 0.3209167480468749 +0.2125 -0.322845458984375 -0.4754638671875 0.3209167480468749 +0.212625 -0.32391357421875 -0.47705078125 0.3209167480468749 +0.21275 -0.32391357421875 -0.47705078125 0.3209167480468749 +0.212875 -0.324981689453125 -0.478607177734375 0.3209167480468749 +0.213 -0.32598876953125 -0.480072021484375 0.3209167480468749 +0.213125 -0.32598876953125 -0.480072021484375 0.3209167480468749 +0.21325 -0.32696533203125 -0.48150634765625 0.3209167480468749 +0.213375 -0.32696533203125 -0.48150634765625 0.3209167480468749 +0.2135 -0.327880859375 -0.48291015625 0.3209167480468749 +0.213625 -0.32879638671875 -0.484222412109375 0.3209167480468749 +0.21375 -0.32879638671875 -0.484222412109375 0.3209167480468749 +0.213875 -0.329681396484375 -0.485504150390625 0.3209167480468749 +0.214 -0.329681396484375 -0.485504150390625 0.3209167480468749 +0.214125 -0.33050537109375 -0.486724853515625 0.3209167480468749 +0.21425 -0.331268310546875 -0.487884521484375 0.3209167480468749 +0.214375 -0.331268310546875 -0.487884521484375 0.3209167480468749 +0.2145 -0.33203125 -0.489013671875 0.3209167480468749 +0.214625 -0.33203125 -0.489013671875 0.3209167480468749 +0.21475 -0.332763671875 -0.490081787109375 0.3209167480468749 +0.214875 -0.33343505859375 -0.4910888671875 0.3209167480468749 +0.215 -0.33343505859375 -0.4910888671875 0.3209167480468749 +0.215125 -0.3341064453125 -0.492034912109375 0.3209167480468749 +0.21525 -0.3341064453125 -0.492034912109375 0.3209167480468749 +0.215375 -0.334716796875 -0.492950439453125 0.3209167480468749 +0.2155 -0.335296630859375 -0.4937744140625 0.3209167480468749 +0.215625 -0.335296630859375 -0.4937744140625 0.3209167480468749 +0.21575 -0.3358154296875 -0.49456787109375 0.3209167480468749 +0.215875 -0.3358154296875 -0.49456787109375 0.3209167480468749 +0.216 -0.3363037109375 -0.49530029296875 0.3209167480468749 +0.216125 -0.3367919921875 -0.496002197265625 0.3209167480468749 +0.21625 -0.3367919921875 -0.496002197265625 0.3209167480468749 +0.216375 -0.33721923828125 -0.496612548828125 0.3209167480468749 +0.2165 -0.33721923828125 -0.496612548828125 0.3209167480468749 +0.216625 -0.337615966796875 -0.4971923828125 0.3209167480468749 +0.21675 -0.33795166015625 -0.497711181640625 0.3209167480468749 +0.216875 -0.33795166015625 -0.497711181640625 0.3209167480468749 +0.217 -0.338287353515625 -0.498199462890625 0.3209167480468749 +0.217125 -0.338287353515625 -0.498199462890625 0.3209167480468749 +0.21725 -0.33856201171875 -0.49859619140625 0.3209167480468749 +0.217375 -0.33880615234375 -0.49896240234375 0.3209167480468749 +0.2175 -0.33880615234375 -0.49896240234375 0.3209167480468749 +0.217625 -0.3389892578125 -0.499267578125 0.3209167480468749 +0.21775 -0.3389892578125 -0.499267578125 0.3209167480468749 +0.217875 -0.33917236328125 -0.49951171875 0.3209167480468749 +0.218 -0.33929443359375 -0.49969482421875 0.3209167480468749 +0.218125 -0.33929443359375 -0.49969482421875 0.3209167480468749 +0.21825 -0.339385986328125 -0.49981689453125 0.3209167480468749 +0.218375 -0.339385986328125 -0.49981689453125 0.3209167480468749 +0.2185 -0.339447021484375 -0.499908447265625 0.3209167480468749 +0.218625 -0.3394775390625 -0.49993896484375 0.3209167480468749 +0.21875 -0.3394775390625 -0.49993896484375 0.3209167480468749 +0.2188750000000000256 -0.339447021484375 -0.499908447265625 0.3209167480468749 +0.219 -0.339447021484375 -0.499908447265625 0.3209167480468749 +0.2191250000000000256 -0.339385986328125 -0.49981689453125 0.3209167480468749 +0.21925 -0.33929443359375 -0.49969482421875 0.3209167480468749 +0.2193750000000000256 -0.33929443359375 -0.49969482421875 0.3209167480468749 +0.2195 -0.33917236328125 -0.49951171875 0.3209167480468749 +0.2196250000000000256 -0.33917236328125 -0.49951171875 0.3209167480468749 +0.21975 -0.3389892578125 -0.499267578125 0.3209167480468749 +0.2198750000000000256 -0.33880615234375 -0.49896240234375 0.3209167480468749 +0.22 -0.33880615234375 -0.49896240234375 0.3209167480468749 +0.2201250000000000256 -0.33856201171875 -0.49859619140625 0.3209167480468749 +0.22025 -0.33856201171875 -0.49859619140625 0.3209167480468749 +0.2203750000000000256 -0.338287353515625 -0.498199462890625 0.3209167480468749 +0.2205 -0.33795166015625 -0.497711181640625 0.3209167480468749 +0.2206250000000000256 -0.33795166015625 -0.497711181640625 0.3209167480468749 +0.22075 -0.337615966796875 -0.4971923828125 0.3209167480468749 +0.2208750000000000256 -0.337615966796875 -0.4971923828125 0.3209167480468749 +0.221 -0.33721923828125 -0.496612548828125 0.3209167480468749 +0.2211250000000000256 -0.3367919921875 -0.496002197265625 0.3209167480468749 +0.22125 -0.3367919921875 -0.496002197265625 0.3209167480468749 +0.2213750000000000256 -0.3363037109375 -0.49530029296875 0.3209167480468749 +0.2215 -0.3363037109375 -0.49530029296875 0.3209167480468749 +0.2216250000000000256 -0.3358154296875 -0.49456787109375 0.3209167480468749 +0.22175 -0.335296630859375 -0.4937744140625 0.3209167480468749 +0.2218750000000000256 -0.335296630859375 -0.4937744140625 0.3209167480468749 +0.222 -0.334716796875 -0.492950439453125 0.3209167480468749 +0.2221250000000000256 -0.334716796875 -0.492950439453125 0.3209167480468749 +0.22225 -0.3341064453125 -0.492034912109375 0.3209167480468749 +0.2223750000000000256 -0.33343505859375 -0.4910888671875 0.3209167480468749 +0.2225 -0.33343505859375 -0.4910888671875 0.3209167480468749 +0.2226250000000000256 -0.332763671875 -0.490081787109375 0.3209167480468749 +0.22275 -0.332763671875 -0.490081787109375 0.3209167480468749 +0.2228750000000000256 -0.33203125 -0.489013671875 0.3209167480468749 +0.223 -0.331268310546875 -0.487884521484375 0.3209167480468749 +0.2231250000000000256 -0.331268310546875 -0.487884521484375 0.3209167480468749 +0.22325 -0.33050537109375 -0.486724853515625 0.3209167480468749 +0.2233750000000000256 -0.33050537109375 -0.486724853515625 0.3209167480468749 +0.2235 -0.329681396484375 -0.485504150390625 0.3209167480468749 +0.223625000000000032 -0.32879638671875 -0.484222412109375 0.3209167480468749 +0.22375 -0.32879638671875 -0.484222412109375 0.3209167480468749 +0.223875000000000032 -0.327880859375 -0.48291015625 0.3209167480468749 +0.224 -0.48291015625 -0.446533203125 -0.07529907226562488 +0.224125 -0.48150634765625 -0.44525146484375 -0.07529907226562488 +0.22425 -0.480072021484375 -0.44390869140625 -0.07529907226562488 +0.224375 -0.480072021484375 -0.44390869140625 -0.07529907226562488 +0.2245 -0.478607177734375 -0.442535400390625 -0.07529907226562488 +0.224625 -0.478607177734375 -0.442535400390625 -0.07529907226562488 +0.22475 -0.47705078125 -0.441131591796875 -0.07529907226562488 +0.224875 -0.4754638671875 -0.43963623046875 -0.07529907226562488 +0.225 -0.4754638671875 -0.43963623046875 -0.07529907226562488 +0.225125 -0.47381591796875 -0.438140869140625 -0.07529907226562488 +0.22525 -0.47381591796875 -0.438140869140625 -0.07529907226562488 +0.225375 -0.472137451171875 -0.436553955078125 -0.07529907226562488 +0.2255 -0.470367431640625 -0.4349365234375 -0.07529907226562488 +0.225625 -0.470367431640625 -0.4349365234375 -0.07529907226562488 +0.22575 -0.46856689453125 -0.43328857421875 -0.07529907226562488 +0.225875 -0.46856689453125 -0.43328857421875 -0.07529907226562488 +0.226 -0.46673583984375 -0.43157958984375 -0.07529907226562488 +0.226125 -0.464813232421875 -0.4298095703125 -0.07529907226562488 +0.22625 -0.464813232421875 -0.4298095703125 -0.07529907226562488 +0.226375 -0.462890625 -0.428009033203125 -0.07529907226562488 +0.2265 -0.462890625 -0.428009033203125 -0.07529907226562488 +0.226625 -0.46087646484375 -0.4261474609375 -0.07529907226562488 +0.22675 -0.458831787109375 -0.42425537109375 -0.07529907226562488 +0.226875 -0.458831787109375 -0.42425537109375 -0.07529907226562488 +0.227 -0.45672607421875 -0.42230224609375 -0.07529907226562488 +0.227125 -0.45672607421875 -0.42230224609375 -0.07529907226562488 +0.22725 -0.454559326171875 -0.420318603515625 -0.07529907226562488 +0.227375 -0.452362060546875 -0.41827392578125 -0.07529907226562488 +0.2275 -0.452362060546875 -0.41827392578125 -0.07529907226562488 +0.227625 -0.450103759765625 -0.41619873046875 -0.07529907226562488 +0.22775 -0.450103759765625 -0.41619873046875 -0.07529907226562488 +0.227875 -0.447784423828125 -0.4140625 -0.07529907226562488 +0.228 -0.4454345703125 -0.411895751953125 -0.07529907226562488 +0.228125 -0.4454345703125 -0.411895751953125 -0.07529907226562488 +0.22825 -0.44305419921875 -0.40966796875 -0.07529907226562488 +0.228375 -0.44305419921875 -0.40966796875 -0.07529907226562488 +0.2285 -0.440582275390625 -0.40740966796875 -0.07529907226562488 +0.228625 -0.438079833984375 -0.40509033203125 -0.07529907226562488 +0.22875 -0.438079833984375 -0.40509033203125 -0.07529907226562488 +0.228875 -0.435546875 -0.402740478515625 -0.07529907226562488 +0.229 -0.435546875 -0.402740478515625 -0.07529907226562488 +0.229125 -0.432952880859375 -0.40032958984375 -0.07529907226562488 +0.22925 -0.4302978515625 -0.39788818359375 -0.07529907226562488 +0.229375 -0.4302978515625 -0.39788818359375 -0.07529907226562488 +0.2295 -0.4276123046875 -0.395416259765625 -0.07529907226562488 +0.229625 -0.4276123046875 -0.395416259765625 -0.07529907226562488 +0.22975 -0.424896240234375 -0.39288330078125 -0.07529907226562488 +0.229875 -0.422119140625 -0.39031982421875 -0.07529907226562488 +0.23 -0.422119140625 -0.39031982421875 -0.07529907226562488 +0.230125 -0.419281005859375 -0.3876953125 -0.07529907226562488 +0.23025 -0.419281005859375 -0.3876953125 -0.07529907226562488 +0.230375 -0.416412353515625 -0.385040283203125 -0.07529907226562488 +0.2305 -0.413482666015625 -0.38232421875 -0.07529907226562488 +0.230625 -0.413482666015625 -0.38232421875 -0.07529907226562488 +0.23075 -0.4105224609375 -0.37957763671875 -0.07529907226562488 +0.230875 -0.4105224609375 -0.37957763671875 -0.07529907226562488 +0.231 -0.407501220703125 -0.376800537109375 -0.07529907226562488 +0.231125 -0.404449462890625 -0.373992919921875 -0.07529907226562488 +0.23125 -0.404449462890625 -0.373992919921875 -0.07529907226562488 +0.231375 -0.401336669921875 -0.371124267578125 -0.07529907226562488 +0.2315 -0.401336669921875 -0.371124267578125 -0.07529907226562488 +0.231625 -0.398193359375 -0.368194580078125 -0.07529907226562488 +0.23175 -0.39501953125 -0.365264892578125 -0.07529907226562488 +0.231875 -0.39501953125 -0.365264892578125 -0.07529907226562488 +0.232 -0.39178466796875 -0.362274169921875 -0.07529907226562488 +0.232125 -0.39178466796875 -0.362274169921875 -0.07529907226562488 +0.23225 -0.388519287109375 -0.3592529296875 -0.07529907226562488 +0.232375 -0.38519287109375 -0.356170654296875 -0.07529907226562488 +0.2325 -0.38519287109375 -0.356170654296875 -0.07529907226562488 +0.232625 -0.3818359375 -0.35308837890625 -0.07529907226562488 +0.23275 -0.3818359375 -0.35308837890625 -0.07529907226562488 +0.232875 -0.378448486328125 -0.349945068359375 -0.07529907226562488 +0.233 -0.375 -0.34674072265625 -0.07529907226562488 +0.233125 -0.375 -0.34674072265625 -0.07529907226562488 +0.23325 -0.37152099609375 -0.343536376953125 -0.07529907226562488 +0.233375 -0.37152099609375 -0.343536376953125 -0.07529907226562488 +0.2335 -0.36798095703125 -0.34027099609375 -0.07529907226562488 +0.233625 -0.36444091796875 -0.33697509765625 -0.07529907226562488 +0.23375 -0.36444091796875 -0.33697509765625 -0.07529907226562488 +0.233875 -0.360809326171875 -0.333648681640625 -0.07529907226562488 +0.234 -0.360809326171875 -0.333648681640625 -0.07529907226562488 +0.234125 -0.357177734375 -0.330291748046875 -0.07529907226562488 +0.23425 -0.353485107421875 -0.326873779296875 -0.07529907226562488 +0.234375 -0.353485107421875 -0.326873779296875 -0.07529907226562488 +0.234500000000000026 -0.349761962890625 -0.32342529296875 -0.07529907226562488 +0.234625 -0.349761962890625 -0.32342529296875 -0.07529907226562488 +0.234750000000000026 -0.34600830078125 -0.3199462890625 -0.07529907226562488 +0.234875 -0.34222412109375 -0.316436767578125 -0.07529907226562488 +0.235000000000000026 -0.34222412109375 -0.316436767578125 -0.07529907226562488 +0.235125 -0.33837890625 -0.312896728515625 -0.07529907226562488 +0.235250000000000026 -0.33837890625 -0.312896728515625 -0.07529907226562488 +0.235375 -0.334503173828125 -0.309326171875 -0.07529907226562488 +0.235500000000000026 -0.330596923828125 -0.305694580078125 -0.07529907226562488 +0.235625 -0.330596923828125 -0.305694580078125 -0.07529907226562488 +0.235750000000000026 -0.32666015625 -0.30206298828125 -0.07529907226562488 +0.235875 -0.32666015625 -0.30206298828125 -0.07529907226562488 +0.236000000000000026 -0.322662353515625 -0.298370361328125 -0.07529907226562488 +0.236125 -0.31866455078125 -0.294647216796875 -0.07529907226562488 +0.236250000000000026 -0.31866455078125 -0.294647216796875 -0.07529907226562488 +0.236375 -0.314605712890625 -0.2908935546875 -0.07529907226562488 +0.236500000000000026 -0.314605712890625 -0.2908935546875 -0.07529907226562488 +0.236625 -0.310516357421875 -0.287139892578125 -0.07529907226562488 +0.236750000000000026 -0.306396484375 -0.2833251953125 -0.07529907226562488 +0.236875 -0.306396484375 -0.2833251953125 -0.07529907226562488 +0.237000000000000026 -0.30224609375 -0.27947998046875 -0.07529907226562488 +0.237125 -0.30224609375 -0.27947998046875 -0.07529907226562488 +0.237250000000000026 -0.298065185546875 -0.275604248046875 -0.07529907226562488 +0.237375 -0.2938232421875 -0.271697998046875 -0.07529907226562488 +0.237500000000000026 -0.2938232421875 -0.271697998046875 -0.07529907226562488 +0.237625 -0.289581298828125 -0.267791748046875 -0.07529907226562488 +0.237750000000000026 -0.289581298828125 -0.267791748046875 -0.07529907226562488 +0.237875 -0.285308837890625 -0.263824462890625 -0.07529907226562488 +0.238000000000000026 -0.280975341796875 -0.25982666015625 -0.07529907226562488 +0.238125 -0.280975341796875 -0.25982666015625 -0.07529907226562488 +0.238250000000000026 -0.276641845703125 -0.25579833984375 -0.07529907226562488 +0.238375 -0.276641845703125 -0.25579833984375 -0.07529907226562488 +0.238500000000000026 -0.27227783203125 -0.25177001953125 -0.07529907226562488 +0.238625 -0.267852783203125 -0.2476806640625 -0.07529907226562488 +0.238750000000000026 -0.267852783203125 -0.2476806640625 -0.07529907226562488 +0.238875 -0.263427734375 -0.24359130859375 -0.07529907226562488 +0.239000000000000026 -0.263427734375 -0.24359130859375 -0.07529907226562488 +0.239125 -0.25897216796875 -0.239471435546875 -0.07529907226562488 +0.239250000000000032 -0.25445556640625 -0.23529052734375 -0.07529907226562488 +0.239375 -0.25445556640625 -0.23529052734375 -0.07529907226562488 +0.239500000000000032 -0.249969482421875 -0.23114013671875 -0.07529907226562488 +0.239625 -0.249969482421875 -0.23114013671875 -0.07529907226562488 +0.239750000000000032 -0.24542236328125 -0.2269287109375 -0.07529907226562488 +0.239875 -0.2408447265625 -0.222686767578125 -0.07529907226562488 +0.24 -0.2408447265625 -0.222686767578125 -0.07529907226562488 +0.240125 -0.236236572265625 -0.21844482421875 -0.07529907226562488 +0.24025 -0.236236572265625 -0.21844482421875 -0.07529907226562488 +0.240375 -0.231597900390625 -0.214141845703125 -0.07529907226562488 +0.2405 -0.226959228515625 -0.2098388671875 -0.07529907226562488 +0.240625 -0.226959228515625 -0.2098388671875 -0.07529907226562488 +0.24075 -0.2222900390625 -0.205535888671875 -0.07529907226562488 +0.240875 -0.2222900390625 -0.205535888671875 -0.07529907226562488 +0.241 -0.21759033203125 -0.201202392578125 -0.07529907226562488 +0.241125 -0.212860107421875 -0.196807861328125 -0.07529907226562488 +0.24125 -0.212860107421875 -0.196807861328125 -0.07529907226562488 +0.241375 -0.208099365234375 -0.192413330078125 -0.07529907226562488 +0.2415 -0.208099365234375 -0.192413330078125 -0.07529907226562488 +0.241625 -0.203338623046875 -0.188018798828125 -0.07529907226562488 +0.24175 -0.19854736328125 -0.18359375 -0.07529907226562488 +0.241875 -0.19854736328125 -0.18359375 -0.07529907226562488 +0.242 -0.1937255859375 -0.179107666015625 -0.07529907226562488 +0.242125 -0.1937255859375 -0.179107666015625 -0.07529907226562488 +0.24225 -0.188873291015625 -0.174652099609375 -0.07529907226562488 +0.242375 -0.18402099609375 -0.170166015625 -0.07529907226562488 +0.2425 -0.18402099609375 -0.170166015625 -0.07529907226562488 +0.242625 -0.17913818359375 -0.1656494140625 -0.07529907226562488 +0.24275 -0.17913818359375 -0.1656494140625 -0.07529907226562488 +0.242875 -0.17425537109375 -0.1611328125 -0.07529907226562488 +0.243 -0.169342041015625 -0.156585693359375 -0.07529907226562488 +0.243125 -0.169342041015625 -0.156585693359375 -0.07529907226562488 +0.24325 -0.164398193359375 -0.152008056640625 -0.07529907226562488 +0.243375 -0.164398193359375 -0.152008056640625 -0.07529907226562488 +0.2435 -0.159454345703125 -0.147430419921875 -0.07529907226562488 +0.243625 -0.15447998046875 -0.142822265625 -0.07529907226562488 +0.24375 -0.15447998046875 -0.142822265625 -0.07529907226562488 +0.243875 -0.14947509765625 -0.138214111328125 -0.07529907226562488 +0.244 -0.14947509765625 -0.138214111328125 -0.07529907226562488 +0.244125 -0.14447021484375 -0.13360595703125 -0.07529907226562488 +0.24425 -0.13946533203125 -0.128936767578125 -0.07529907226562488 +0.244375 -0.13946533203125 -0.128936767578125 -0.07529907226562488 +0.2445 -0.134429931640625 -0.124298095703125 -0.07529907226562488 +0.244625 -0.134429931640625 -0.124298095703125 -0.07529907226562488 +0.24475 -0.129364013671875 -0.11962890625 -0.07529907226562488 +0.244875 -0.124298095703125 -0.11492919921875 -0.07529907226562488 +0.245 -0.124298095703125 -0.11492919921875 -0.07529907226562488 +0.245125 -0.119232177734375 -0.110260009765625 -0.07529907226562488 +0.24525 -0.119232177734375 -0.110260009765625 -0.07529907226562488 +0.245375 -0.1141357421875 -0.105560302734375 -0.07529907226562488 +0.2455 -0.109039306640625 -0.100830078125 -0.07529907226562488 +0.245625 -0.109039306640625 -0.100830078125 -0.07529907226562488 +0.24575 -0.103912353515625 -0.096099853515625 -0.07529907226562488 +0.245875 -0.103912353515625 -0.096099853515625 -0.07529907226562488 +0.246 -0.098785400390625 -0.091339111328125 -0.07529907226562488 +0.246125 -0.093658447265625 -0.08660888671875 -0.07529907226562488 +0.24625 -0.093658447265625 -0.08660888671875 -0.07529907226562488 +0.246375 -0.0885009765625 -0.08184814453125 -0.07529907226562488 +0.2465 -0.0885009765625 -0.08184814453125 -0.07529907226562488 +0.246625 -0.083343505859375 -0.07708740234375 -0.07529907226562488 +0.24675 -0.07818603515625 -0.072296142578125 -0.07529907226562488 +0.246875 -0.07818603515625 -0.072296142578125 -0.07529907226562488 +0.247 -0.072998046875 -0.0675048828125 -0.07529907226562488 +0.247125 -0.072998046875 -0.0675048828125 -0.07529907226562488 +0.24725 -0.06781005859375 -0.062713623046875 -0.07529907226562488 +0.247375 -0.0626220703125 -0.05792236328125 -0.07529907226562488 +0.2475 -0.0626220703125 -0.05792236328125 -0.07529907226562488 +0.247625 -0.05743408203125 -0.053131103515625 -0.07529907226562488 +0.24775 -0.05743408203125 -0.053131103515625 -0.07529907226562488 +0.247875 -0.05224609375 -0.048309326171875 -0.07529907226562488 +0.248 -0.047027587890625 -0.043487548828125 -0.07529907226562488 +0.248125 -0.047027587890625 -0.043487548828125 -0.07529907226562488 +0.24825 -0.04180908203125 -0.038665771484375 -0.07529907226562488 +0.248375 -0.04180908203125 -0.038665771484375 -0.07529907226562488 +0.2485 -0.036590576171875 -0.033843994140625 -0.07529907226562488 +0.248625 -0.0313720703125 -0.02899169921875 -0.07529907226562488 +0.24875 -0.0313720703125 -0.02899169921875 -0.07529907226562488 +0.248875 -0.026123046875 -0.024169921875 -0.07529907226562488 +0.249 -0.026123046875 -0.024169921875 -0.07529907226562488 +0.249125 -0.020904541015625 -0.01934814453125 -0.07529907226562488 +0.24925 -0.01568603515625 -0.014495849609375 -0.07529907226562488 +0.249375 -0.01568603515625 -0.014495849609375 -0.07529907226562488 +0.2495 -0.01043701171875 -0.009674072265625 -0.07529907226562488 +0.249625 -0.01043701171875 -0.009674072265625 -0.07529907226562488 +0.24975 -0.005218505859375 -0.00482177734375 -0.07529907226562488 +0.249875 0.0 0.0 -0.07529907226562488 +0.25 0.0 0.0 -0.07529907226562488 +0.250125 0.005218505859375 0.00482177734375 -0.07529907226562488 +0.25025000000000004 0.005218505859375 0.00482177734375 -0.07529907226562488 +0.250375 0.01043701171875 0.009674072265625 -0.07529907226562488 +0.2505 0.01568603515625 0.014495849609375 -0.07529907226562488 +0.250625 0.01568603515625 0.014495849609375 -0.07529907226562488 +0.25075000000000004 0.020904541015625 0.01934814453125 -0.07529907226562488 +0.250875 0.020904541015625 0.01934814453125 -0.07529907226562488 +0.251 0.026123046875 0.024169921875 -0.07529907226562488 +0.251125 0.0313720703125 0.02899169921875 -0.07529907226562488 +0.25125000000000004 0.0313720703125 0.02899169921875 -0.07529907226562488 +0.251375 0.036590576171875 0.033843994140625 -0.07529907226562488 +0.2515 0.036590576171875 0.033843994140625 -0.07529907226562488 +0.251625 0.04180908203125 0.038665771484375 -0.07529907226562488 +0.25175000000000004 0.047027587890625 0.043487548828125 -0.07529907226562488 +0.251875 0.047027587890625 0.043487548828125 -0.07529907226562488 +0.252 0.05224609375 0.048309326171875 -0.07529907226562488 +0.252125 0.05224609375 0.048309326171875 -0.07529907226562488 +0.25225000000000004 0.05743408203125 0.053131103515625 -0.07529907226562488 +0.252375 0.0626220703125 0.05792236328125 -0.07529907226562488 +0.2525 0.0626220703125 0.05792236328125 -0.07529907226562488 +0.252625 0.06781005859375 0.062713623046875 -0.07529907226562488 +0.25275000000000004 0.06781005859375 0.062713623046875 -0.07529907226562488 +0.252875 0.072998046875 0.0675048828125 -0.07529907226562488 +0.253 0.07818603515625 0.072296142578125 -0.07529907226562488 +0.253125 0.07818603515625 0.072296142578125 -0.07529907226562488 +0.25325000000000004 0.083343505859375 0.07708740234375 -0.07529907226562488 +0.253375 0.083343505859375 0.07708740234375 -0.07529907226562488 +0.2535 0.0885009765625 0.08184814453125 -0.07529907226562488 +0.253625 0.093658447265625 0.08660888671875 -0.07529907226562488 +0.25375000000000004 0.093658447265625 0.08660888671875 -0.07529907226562488 +0.253875 0.098785400390625 0.091339111328125 -0.07529907226562488 +0.254 0.098785400390625 0.091339111328125 -0.07529907226562488 +0.254125 0.103912353515625 0.096099853515625 -0.07529907226562488 +0.25425000000000004 0.109039306640625 0.100830078125 -0.07529907226562488 +0.254375 0.109039306640625 0.100830078125 -0.07529907226562488 +0.2545 0.1141357421875 0.105560302734375 -0.07529907226562488 +0.254625 0.1141357421875 0.105560302734375 -0.07529907226562488 +0.25475000000000004 0.119232177734375 0.110260009765625 -0.07529907226562488 +0.254875 0.124298095703125 0.11492919921875 -0.07529907226562488 +0.255 0.124298095703125 0.11492919921875 -0.07529907226562488 +0.255125 0.129364013671875 0.11962890625 -0.07529907226562488 +0.25525000000000004 0.129364013671875 0.11962890625 -0.07529907226562488 +0.255375 0.134429931640625 0.124298095703125 -0.07529907226562488 +0.2555 0.13946533203125 0.128936767578125 -0.07529907226562488 +0.255625 0.13946533203125 0.128936767578125 -0.07529907226562488 +0.25575000000000004 0.14447021484375 0.13360595703125 -0.07529907226562488 +0.255875 0.14447021484375 0.13360595703125 -0.07529907226562488 +0.256 0.14947509765625 0.080780029296875 -0.4595336914062502 +0.256125 0.15447998046875 0.083465576171875 -0.4595336914062502 +0.25625 0.15447998046875 0.083465576171875 -0.4595336914062502 +0.256375 0.159454345703125 0.086151123046875 -0.4595336914062502 +0.2565 0.159454345703125 0.086151123046875 -0.4595336914062502 +0.256625 0.164398193359375 0.088836669921875 -0.4595336914062502 +0.25675 0.169342041015625 0.09149169921875 -0.4595336914062502 +0.256875 0.169342041015625 0.09149169921875 -0.4595336914062502 +0.257 0.17425537109375 0.094146728515625 -0.4595336914062502 +0.257125 0.17425537109375 0.094146728515625 -0.4595336914062502 +0.25725 0.17913818359375 0.0968017578125 -0.4595336914062502 +0.257375 0.18402099609375 0.099456787109375 -0.4595336914062502 +0.2575 0.18402099609375 0.099456787109375 -0.4595336914062502 +0.257625 0.188873291015625 0.10205078125 -0.4595336914062502 +0.25775 0.188873291015625 0.10205078125 -0.4595336914062502 +0.257875 0.1937255859375 0.10467529296875 -0.4595336914062502 +0.258 0.19854736328125 0.107269287109375 -0.4595336914062502 +0.258125 0.19854736328125 0.107269287109375 -0.4595336914062502 +0.25825 0.203338623046875 0.10986328125 -0.4595336914062502 +0.258375 0.203338623046875 0.10986328125 -0.4595336914062502 +0.2585 0.208099365234375 0.112457275390625 -0.4595336914062502 +0.258625 0.212860107421875 0.115020751953125 -0.4595336914062502 +0.25875 0.212860107421875 0.115020751953125 -0.4595336914062502 +0.258875 0.21759033203125 0.117584228515625 -0.4595336914062502 +0.259 0.21759033203125 0.117584228515625 -0.4595336914062502 +0.259125 0.2222900390625 0.1201171875 -0.4595336914062502 +0.25925 0.226959228515625 0.122650146484375 -0.4595336914062502 +0.259375 0.226959228515625 0.122650146484375 -0.4595336914062502 +0.2595 0.231597900390625 0.125152587890625 -0.4595336914062502 +0.259625 0.231597900390625 0.125152587890625 -0.4595336914062502 +0.25975 0.236236572265625 0.127655029296875 -0.4595336914062502 +0.259875 0.2408447265625 0.130126953125 -0.4595336914062502 +0.26 0.2408447265625 0.130126953125 -0.4595336914062502 +0.260125 0.24542236328125 0.132598876953125 -0.4595336914062502 +0.26025 0.24542236328125 0.132598876953125 -0.4595336914062502 +0.260375 0.249969482421875 0.13507080078125 -0.4595336914062502 +0.2605 0.25445556640625 0.13751220703125 -0.4595336914062502 +0.260625 0.25445556640625 0.13751220703125 -0.4595336914062502 +0.26075 0.25897216796875 0.13995361328125 -0.4595336914062502 +0.260875 0.25897216796875 0.13995361328125 -0.4595336914062502 +0.261 0.263427734375 0.142364501953125 -0.4595336914062502 +0.261125 0.267852783203125 0.144744873046875 -0.4595336914062502 +0.26125 0.267852783203125 0.144744873046875 -0.4595336914062502 +0.261375 0.27227783203125 0.147125244140625 -0.4595336914062502 +0.2615 0.27227783203125 0.147125244140625 -0.4595336914062502 +0.261625 0.276641845703125 0.149505615234375 -0.4595336914062502 +0.26175 0.280975341796875 0.15185546875 -0.4595336914062502 +0.261875 0.280975341796875 0.15185546875 -0.4595336914062502 +0.262 0.285308837890625 0.1541748046875 -0.4595336914062502 +0.262125 0.285308837890625 0.1541748046875 -0.4595336914062502 +0.26225 0.289581298828125 0.156494140625 -0.4595336914062502 +0.262375 0.2938232421875 0.158782958984375 -0.4595336914062502 +0.2625 0.2938232421875 0.158782958984375 -0.4595336914062502 +0.262625 0.298065185546875 0.16107177734375 -0.4595336914062502 +0.26275 0.298065185546875 0.16107177734375 -0.4595336914062502 +0.262875 0.30224609375 0.163330078125 -0.4595336914062502 +0.263 0.306396484375 0.16558837890625 -0.4595336914062502 +0.263125 0.306396484375 0.16558837890625 -0.4595336914062502 +0.26325 0.310516357421875 0.167816162109375 -0.4595336914062502 +0.263375 0.310516357421875 0.167816162109375 -0.4595336914062502 +0.2635 0.314605712890625 0.170013427734375 -0.4595336914062502 +0.263625 0.31866455078125 0.172210693359375 -0.4595336914062502 +0.26375 0.31866455078125 0.172210693359375 -0.4595336914062502 +0.263875 0.322662353515625 0.17437744140625 -0.4595336914062502 +0.264 0.322662353515625 0.17437744140625 -0.4595336914062502 +0.264125 0.32666015625 0.176513671875 -0.4595336914062502 +0.26425 0.330596923828125 0.17864990234375 -0.4595336914062502 +0.264375 0.330596923828125 0.17864990234375 -0.4595336914062502 +0.2645 0.334503173828125 0.180755615234375 -0.4595336914062502 +0.264625 0.334503173828125 0.180755615234375 -0.4595336914062502 +0.26475 0.33837890625 0.182861328125 -0.4595336914062502 +0.264875 0.34222412109375 0.1849365234375 -0.4595336914062502 +0.265 0.34222412109375 0.1849365234375 -0.4595336914062502 +0.265125 0.34600830078125 0.186981201171875 -0.4595336914062502 +0.26525 0.34600830078125 0.186981201171875 -0.4595336914062502 +0.265375 0.349761962890625 0.18902587890625 -0.4595336914062502 +0.2655 0.353485107421875 0.191009521484375 -0.4595336914062502 +0.265625 0.353485107421875 0.191009521484375 -0.4595336914062502 +0.26575 0.357177734375 0.193023681640625 -0.4595336914062502 +0.26587500000000004 0.357177734375 0.193023681640625 -0.4595336914062502 +0.266 0.360809326171875 0.194976806640625 -0.4595336914062502 +0.266125 0.36444091796875 0.196929931640625 -0.4595336914062502 +0.26625 0.36444091796875 0.196929931640625 -0.4595336914062502 +0.26637500000000004 0.36798095703125 0.1988525390625 -0.4595336914062502 +0.2665 0.36798095703125 0.1988525390625 -0.4595336914062502 +0.266625 0.37152099609375 0.200775146484375 -0.4595336914062502 +0.26675 0.375 0.20263671875 -0.4595336914062502 +0.26687500000000004 0.375 0.20263671875 -0.4595336914062502 +0.267 0.378448486328125 0.204498291015625 -0.4595336914062502 +0.267125 0.378448486328125 0.204498291015625 -0.4595336914062502 +0.26725 0.3818359375 0.206329345703125 -0.4595336914062502 +0.26737500000000004 0.38519287109375 0.208160400390625 -0.4595336914062502 +0.2675 0.38519287109375 0.208160400390625 -0.4595336914062502 +0.267625 0.388519287109375 0.2099609375 -0.4595336914062502 +0.26775 0.388519287109375 0.2099609375 -0.4595336914062502 +0.26787500000000004 0.39178466796875 0.21173095703125 -0.4595336914062502 +0.268 0.39501953125 0.213470458984375 -0.4595336914062502 +0.268125 0.39501953125 0.213470458984375 -0.4595336914062502 +0.26825 0.398193359375 0.215179443359375 -0.4595336914062502 +0.26837500000000004 0.398193359375 0.215179443359375 -0.4595336914062502 +0.2685 0.401336669921875 0.216888427734375 -0.4595336914062502 +0.268625 0.404449462890625 0.21856689453125 -0.4595336914062502 +0.26875 0.404449462890625 0.21856689453125 -0.4595336914062502 +0.26887500000000004 0.407501220703125 0.22021484375 -0.4595336914062502 +0.269 0.407501220703125 0.22021484375 -0.4595336914062502 +0.269125 0.4105224609375 0.221832275390625 -0.4595336914062502 +0.26925 0.413482666015625 0.22344970703125 -0.4595336914062502 +0.26937500000000004 0.413482666015625 0.22344970703125 -0.4595336914062502 +0.2695 0.416412353515625 0.225006103515625 -0.4595336914062502 +0.269625 0.416412353515625 0.225006103515625 -0.4595336914062502 +0.26975 0.419281005859375 0.2265625 -0.4595336914062502 +0.26987500000000004 0.422119140625 0.228118896484375 -0.4595336914062502 +0.27 0.422119140625 0.228118896484375 -0.4595336914062502 +0.270125 0.424896240234375 0.2296142578125 -0.4595336914062502 +0.27025 0.424896240234375 0.2296142578125 -0.4595336914062502 +0.27037500000000004 0.4276123046875 0.2310791015625 -0.4595336914062502 +0.2705 0.4302978515625 0.2325439453125 -0.4595336914062502 +0.270625 0.4302978515625 0.2325439453125 -0.4595336914062502 +0.27075 0.432952880859375 0.233978271484375 -0.4595336914062502 +0.27087500000000004 0.432952880859375 0.233978271484375 -0.4595336914062502 +0.271 0.435546875 0.235382080078125 -0.4595336914062502 +0.271125 0.438079833984375 0.236724853515625 -0.4595336914062502 +0.27125 0.438079833984375 0.236724853515625 -0.4595336914062502 +0.27137500000000004 0.440582275390625 0.23809814453125 -0.4595336914062502 +0.2715 0.440582275390625 0.23809814453125 -0.4595336914062502 +0.271625 0.44305419921875 0.239410400390625 -0.4595336914062502 +0.27175 0.4454345703125 0.24072265625 -0.4595336914062502 +0.27187500000000004 0.4454345703125 0.24072265625 -0.4595336914062502 +0.272 0.447784423828125 0.241973876953125 -0.4595336914062502 +0.272125 0.447784423828125 0.241973876953125 -0.4595336914062502 +0.27225 0.450103759765625 0.24322509765625 -0.4595336914062502 +0.272375 0.452362060546875 0.24444580078125 -0.4595336914062502 +0.2725 0.452362060546875 0.24444580078125 -0.4595336914062502 +0.272625 0.454559326171875 0.245635986328125 -0.4595336914062502 +0.27275 0.454559326171875 0.245635986328125 -0.4595336914062502 +0.272875 0.45672607421875 0.246795654296875 -0.4595336914062502 +0.273 0.458831787109375 0.247955322265625 -0.4595336914062502 +0.273125 0.458831787109375 0.247955322265625 -0.4595336914062502 +0.27325 0.46087646484375 0.249053955078125 -0.4595336914062502 +0.273375 0.46087646484375 0.249053955078125 -0.4595336914062502 +0.2735 0.462890625 0.2501220703125 -0.4595336914062502 +0.273625 0.464813232421875 0.251190185546875 -0.4595336914062502 +0.27375 0.464813232421875 0.251190185546875 -0.4595336914062502 +0.273875 0.46673583984375 0.252227783203125 -0.4595336914062502 +0.274 0.46673583984375 0.252227783203125 -0.4595336914062502 +0.274125 0.46856689453125 0.253204345703125 -0.4595336914062502 +0.27425 0.470367431640625 0.254180908203125 -0.4595336914062502 +0.274375 0.470367431640625 0.254180908203125 -0.4595336914062502 +0.2745 0.472137451171875 0.255126953125 -0.4595336914062502 +0.274625 0.472137451171875 0.255126953125 -0.4595336914062502 +0.27475 0.47381591796875 0.25604248046875 -0.4595336914062502 +0.274875 0.4754638671875 0.256927490234375 -0.4595336914062502 +0.275 0.4754638671875 0.256927490234375 -0.4595336914062502 +0.275125 0.47705078125 0.257781982421875 -0.4595336914062502 +0.27525 0.47705078125 0.257781982421875 -0.4595336914062502 +0.275375 0.478607177734375 0.258636474609375 -0.4595336914062502 +0.2755 0.480072021484375 0.259429931640625 -0.4595336914062502 +0.275625 0.480072021484375 0.259429931640625 -0.4595336914062502 +0.27575 0.48150634765625 0.26019287109375 -0.4595336914062502 +0.275875 0.48150634765625 0.26019287109375 -0.4595336914062502 +0.276 0.48291015625 0.260955810546875 -0.4595336914062502 +0.276125 0.484222412109375 0.26165771484375 -0.4595336914062502 +0.27625 0.484222412109375 0.26165771484375 -0.4595336914062502 +0.276375 0.485504150390625 0.262359619140625 -0.4595336914062502 +0.2765 0.485504150390625 0.262359619140625 -0.4595336914062502 +0.276625 0.486724853515625 0.263031005859375 -0.4595336914062502 +0.27675 0.487884521484375 0.263641357421875 -0.4595336914062502 +0.276875 0.487884521484375 0.263641357421875 -0.4595336914062502 +0.277 0.489013671875 0.264251708984375 -0.4595336914062502 +0.277125 0.489013671875 0.264251708984375 -0.4595336914062502 +0.27725 0.490081787109375 0.26483154296875 -0.4595336914062502 +0.277375 0.4910888671875 0.265380859375 -0.4595336914062502 +0.2775 0.4910888671875 0.265380859375 -0.4595336914062502 +0.277625 0.492034912109375 0.265899658203125 -0.4595336914062502 +0.27775 0.492034912109375 0.265899658203125 -0.4595336914062502 +0.277875 0.492950439453125 0.266387939453125 -0.4595336914062502 +0.278 0.4937744140625 0.266845703125 -0.4595336914062502 +0.278125 0.4937744140625 0.266845703125 -0.4595336914062502 +0.27825 0.49456787109375 0.26727294921875 -0.4595336914062502 +0.278375 0.49456787109375 0.26727294921875 -0.4595336914062502 +0.2785 0.49530029296875 0.267669677734375 -0.4595336914062502 +0.278625 0.496002197265625 0.268035888671875 -0.4595336914062502 +0.27875 0.496002197265625 0.268035888671875 -0.4595336914062502 +0.278875 0.496612548828125 0.26837158203125 -0.4595336914062502 +0.279 0.496612548828125 0.26837158203125 -0.4595336914062502 +0.279125 0.4971923828125 0.2686767578125 -0.4595336914062502 +0.27925 0.497711181640625 0.268951416015625 -0.4595336914062502 +0.279375 0.497711181640625 0.268951416015625 -0.4595336914062502 +0.2795 0.498199462890625 0.26922607421875 -0.4595336914062502 +0.279625 0.498199462890625 0.26922607421875 -0.4595336914062502 +0.27975 0.49859619140625 0.269439697265625 -0.4595336914062502 +0.279875 0.49896240234375 0.269622802734375 -0.4595336914062502 +0.28 0.49896240234375 0.269622802734375 -0.4595336914062502 +0.280125 0.499267578125 0.269805908203125 -0.4595336914062502 +0.28025 0.499267578125 0.269805908203125 -0.4595336914062502 +0.280375 0.49951171875 0.269927978515625 -0.4595336914062502 +0.2805 0.49969482421875 0.27001953125 -0.4595336914062502 +0.280625 0.49969482421875 0.27001953125 -0.4595336914062502 +0.28075 0.49981689453125 0.270111083984375 -0.4595336914062502 +0.280875 0.49981689453125 0.270111083984375 -0.4595336914062502 +0.281 0.499908447265625 0.2701416015625 -0.4595336914062502 +0.281125 0.49993896484375 0.270172119140625 -0.4595336914062502 +0.28125 0.49993896484375 0.270172119140625 -0.4595336914062502 +0.281375 0.499908447265625 0.2701416015625 -0.4595336914062502 +0.28150000000000004 0.499908447265625 0.2701416015625 -0.4595336914062502 +0.281625 0.49981689453125 0.270111083984375 -0.4595336914062502 +0.28175 0.49969482421875 0.27001953125 -0.4595336914062502 +0.281875 0.49969482421875 0.27001953125 -0.4595336914062502 +0.28200000000000004 0.49951171875 0.269927978515625 -0.4595336914062502 +0.282125 0.49951171875 0.269927978515625 -0.4595336914062502 +0.28225 0.499267578125 0.269805908203125 -0.4595336914062502 +0.282375 0.49896240234375 0.269622802734375 -0.4595336914062502 +0.28250000000000004 0.49896240234375 0.269622802734375 -0.4595336914062502 +0.282625 0.49859619140625 0.269439697265625 -0.4595336914062502 +0.28275 0.49859619140625 0.269439697265625 -0.4595336914062502 +0.282875 0.498199462890625 0.26922607421875 -0.4595336914062502 +0.28300000000000004 0.497711181640625 0.268951416015625 -0.4595336914062502 +0.283125 0.497711181640625 0.268951416015625 -0.4595336914062502 +0.28325 0.4971923828125 0.2686767578125 -0.4595336914062502 +0.283375 0.4971923828125 0.2686767578125 -0.4595336914062502 +0.28350000000000004 0.496612548828125 0.26837158203125 -0.4595336914062502 +0.283625 0.496002197265625 0.268035888671875 -0.4595336914062502 +0.28375 0.496002197265625 0.268035888671875 -0.4595336914062502 +0.283875 0.49530029296875 0.267669677734375 -0.4595336914062502 +0.28400000000000004 0.49530029296875 0.267669677734375 -0.4595336914062502 +0.284125 0.49456787109375 0.26727294921875 -0.4595336914062502 +0.28425 0.4937744140625 0.266845703125 -0.4595336914062502 +0.284375 0.4937744140625 0.266845703125 -0.4595336914062502 +0.28450000000000004 0.492950439453125 0.266387939453125 -0.4595336914062502 +0.284625 0.492950439453125 0.266387939453125 -0.4595336914062502 +0.28475 0.492034912109375 0.265899658203125 -0.4595336914062502 +0.284875 0.4910888671875 0.265380859375 -0.4595336914062502 +0.28500000000000004 0.4910888671875 0.265380859375 -0.4595336914062502 +0.285125 0.490081787109375 0.26483154296875 -0.4595336914062502 +0.28525 0.490081787109375 0.26483154296875 -0.4595336914062502 +0.285375 0.489013671875 0.264251708984375 -0.4595336914062502 +0.28550000000000004 0.487884521484375 0.263641357421875 -0.4595336914062502 +0.285625 0.487884521484375 0.263641357421875 -0.4595336914062502 +0.28575 0.486724853515625 0.263031005859375 -0.4595336914062502 +0.285875 0.486724853515625 0.263031005859375 -0.4595336914062502 +0.28600000000000004 0.485504150390625 0.262359619140625 -0.4595336914062502 +0.286125 0.484222412109375 0.26165771484375 -0.4595336914062502 +0.28625 0.484222412109375 0.26165771484375 -0.4595336914062502 +0.286375 0.48291015625 0.260955810546875 -0.4595336914062502 +0.28650000000000004 0.48291015625 0.260955810546875 -0.4595336914062502 +0.286625 0.48150634765625 0.26019287109375 -0.4595336914062502 +0.28675 0.480072021484375 0.259429931640625 -0.4595336914062502 +0.286875 0.480072021484375 0.259429931640625 -0.4595336914062502 +0.28700000000000004 0.478607177734375 0.258636474609375 -0.4595336914062502 +0.287125 0.478607177734375 0.258636474609375 -0.4595336914062502 +0.28725 0.47705078125 0.257781982421875 -0.4595336914062502 +0.287375 0.4754638671875 0.256927490234375 -0.4595336914062502 +0.28750000000000004 0.4754638671875 0.256927490234375 -0.4595336914062502 +0.287625 0.47381591796875 0.25604248046875 -0.4595336914062502 +0.28775 0.47381591796875 0.25604248046875 -0.4595336914062502 +0.287875 0.472137451171875 0.255126953125 -0.4595336914062502 +0.28800000000000004 0.470367431640625 0.10791015625 -0.7704772949218753 +0.288125 0.470367431640625 0.10791015625 -0.7704772949218753 +0.28825 0.46856689453125 0.107513427734375 -0.7704772949218753 +0.288375 0.46856689453125 0.107513427734375 -0.7704772949218753 +0.2885 0.46673583984375 0.107086181640625 -0.7704772949218753 +0.288625 0.464813232421875 0.10662841796875 -0.7704772949218753 +0.28875 0.464813232421875 0.10662841796875 -0.7704772949218753 +0.288875 0.462890625 0.106201171875 -0.7704772949218753 +0.289 0.462890625 0.106201171875 -0.7704772949218753 +0.289125 0.46087646484375 0.105743408203125 -0.7704772949218753 +0.28925 0.458831787109375 0.105255126953125 -0.7704772949218753 +0.289375 0.458831787109375 0.105255126953125 -0.7704772949218753 +0.2895 0.45672607421875 0.104766845703125 -0.7704772949218753 +0.289625 0.45672607421875 0.104766845703125 -0.7704772949218753 +0.28975 0.454559326171875 0.104278564453125 -0.7704772949218753 +0.289875 0.452362060546875 0.103790283203125 -0.7704772949218753 +0.29 0.452362060546875 0.103790283203125 -0.7704772949218753 +0.290125 0.450103759765625 0.103271484375 -0.7704772949218753 +0.29025 0.450103759765625 0.103271484375 -0.7704772949218753 +0.290375 0.447784423828125 0.10272216796875 -0.7704772949218753 +0.2905 0.4454345703125 0.102203369140625 -0.7704772949218753 +0.290625 0.4454345703125 0.102203369140625 -0.7704772949218753 +0.29075 0.44305419921875 0.101654052734375 -0.7704772949218753 +0.290875 0.44305419921875 0.101654052734375 -0.7704772949218753 +0.291 0.440582275390625 0.10107421875 -0.7704772949218753 +0.291125 0.438079833984375 0.100494384765625 -0.7704772949218753 +0.29125 0.438079833984375 0.100494384765625 -0.7704772949218753 +0.291375 0.435546875 0.09991455078125 -0.7704772949218753 +0.2915 0.435546875 0.09991455078125 -0.7704772949218753 +0.291625 0.432952880859375 0.099334716796875 -0.7704772949218753 +0.29175 0.4302978515625 0.098724365234375 -0.7704772949218753 +0.291875 0.4302978515625 0.098724365234375 -0.7704772949218753 +0.292 0.4276123046875 0.098114013671875 -0.7704772949218753 +0.292125 0.4276123046875 0.098114013671875 -0.7704772949218753 +0.29225 0.424896240234375 0.09747314453125 -0.7704772949218753 +0.292375 0.422119140625 0.096832275390625 -0.7704772949218753 +0.2925 0.422119140625 0.096832275390625 -0.7704772949218753 +0.292625 0.419281005859375 0.09619140625 -0.7704772949218753 +0.29275 0.419281005859375 0.09619140625 -0.7704772949218753 +0.292875 0.416412353515625 0.09552001953125 -0.7704772949218753 +0.293 0.413482666015625 0.0948486328125 -0.7704772949218753 +0.293125 0.413482666015625 0.0948486328125 -0.7704772949218753 +0.29325 0.4105224609375 0.09417724609375 -0.7704772949218753 +0.293375 0.4105224609375 0.09417724609375 -0.7704772949218753 +0.2935 0.407501220703125 0.093475341796875 -0.7704772949218753 +0.293625 0.404449462890625 0.0927734375 -0.7704772949218753 +0.29375 0.404449462890625 0.0927734375 -0.7704772949218753 +0.293875 0.401336669921875 0.092071533203125 -0.7704772949218753 +0.294 0.401336669921875 0.092071533203125 -0.7704772949218753 +0.294125 0.398193359375 0.091339111328125 -0.7704772949218753 +0.29425 0.39501953125 0.09063720703125 -0.7704772949218753 +0.294375 0.39501953125 0.09063720703125 -0.7704772949218753 +0.2945 0.39178466796875 0.089874267578125 -0.7704772949218753 +0.294625 0.39178466796875 0.089874267578125 -0.7704772949218753 +0.29475 0.388519287109375 0.089141845703125 -0.7704772949218753 +0.294875 0.38519287109375 0.08837890625 -0.7704772949218753 +0.295 0.38519287109375 0.08837890625 -0.7704772949218753 +0.295125 0.3818359375 0.08758544921875 -0.7704772949218753 +0.29525 0.3818359375 0.08758544921875 -0.7704772949218753 +0.295375 0.378448486328125 0.086822509765625 -0.7704772949218753 +0.2955 0.375 0.086029052734375 -0.7704772949218753 +0.295625 0.375 0.086029052734375 -0.7704772949218753 +0.29575 0.37152099609375 0.085235595703125 -0.7704772949218753 +0.295875 0.37152099609375 0.085235595703125 -0.7704772949218753 +0.296 0.36798095703125 0.08441162109375 -0.7704772949218753 +0.296125 0.36444091796875 0.0836181640625 -0.7704772949218753 +0.29625 0.36444091796875 0.0836181640625 -0.7704772949218753 +0.296375 0.360809326171875 0.082763671875 -0.7704772949218753 +0.2965 0.360809326171875 0.082763671875 -0.7704772949218753 +0.296625 0.357177734375 0.081939697265625 -0.7704772949218753 +0.29675 0.353485107421875 0.081085205078125 -0.7704772949218753 +0.296875 0.353485107421875 0.081085205078125 -0.7704772949218753 +0.297 0.349761962890625 0.080230712890625 -0.7704772949218753 +0.29712500000000004 0.349761962890625 0.080230712890625 -0.7704772949218753 +0.29725 0.34600830078125 0.079376220703125 -0.7704772949218753 +0.297375 0.34222412109375 0.078521728515625 -0.7704772949218753 +0.2975 0.34222412109375 0.078521728515625 -0.7704772949218753 +0.29762500000000004 0.33837890625 0.07763671875 -0.7704772949218753 +0.29775 0.33837890625 0.07763671875 -0.7704772949218753 +0.297875 0.334503173828125 0.076751708984375 -0.7704772949218753 +0.298 0.330596923828125 0.075836181640625 -0.7704772949218753 +0.29812500000000004 0.330596923828125 0.075836181640625 -0.7704772949218753 +0.29825 0.32666015625 0.074951171875 -0.7704772949218753 +0.298375 0.32666015625 0.074951171875 -0.7704772949218753 +0.2985 0.322662353515625 0.07403564453125 -0.7704772949218753 +0.29862500000000004 0.31866455078125 0.073089599609375 -0.7704772949218753 +0.29875 0.31866455078125 0.073089599609375 -0.7704772949218753 +0.298875 0.314605712890625 0.072174072265625 -0.7704772949218753 +0.299 0.314605712890625 0.072174072265625 -0.7704772949218753 +0.29912500000000004 0.310516357421875 0.07122802734375 -0.7704772949218753 +0.29925 0.306396484375 0.070281982421875 -0.7704772949218753 +0.299375 0.306396484375 0.070281982421875 -0.7704772949218753 +0.2995 0.30224609375 0.0693359375 -0.7704772949218753 +0.29962500000000004 0.30224609375 0.0693359375 -0.7704772949218753 +0.29975 0.298065185546875 0.068389892578125 -0.7704772949218753 +0.299875 0.2938232421875 0.067413330078125 -0.7704772949218753 +0.3 0.2938232421875 0.067413330078125 -0.7704772949218753 +0.30012500000000004 0.289581298828125 0.066436767578125 -0.7704772949218753 +0.30025 0.289581298828125 0.066436767578125 -0.7704772949218753 +0.300375 0.285308837890625 0.065460205078125 -0.7704772949218753 +0.3005 0.280975341796875 0.064453125 -0.7704772949218753 +0.30062500000000004 0.280975341796875 0.064453125 -0.7704772949218753 +0.30075 0.276641845703125 0.0634765625 -0.7704772949218753 +0.300875 0.276641845703125 0.0634765625 -0.7704772949218753 +0.301 0.27227783203125 0.062469482421875 -0.7704772949218753 +0.30112500000000004 0.267852783203125 0.06146240234375 -0.7704772949218753 +0.30125 0.267852783203125 0.06146240234375 -0.7704772949218753 +0.301375 0.263427734375 0.0604248046875 -0.7704772949218753 +0.3015 0.263427734375 0.0604248046875 -0.7704772949218753 +0.30162500000000004 0.25897216796875 0.059417724609375 -0.7704772949218753 +0.30175 0.25445556640625 0.058380126953125 -0.7704772949218753 +0.301875 0.25445556640625 0.058380126953125 -0.7704772949218753 +0.302 0.249969482421875 0.057342529296875 -0.7704772949218753 +0.30212500000000004 0.249969482421875 0.057342529296875 -0.7704772949218753 +0.30225 0.24542236328125 0.056304931640625 -0.7704772949218753 +0.302375 0.2408447265625 0.05523681640625 -0.7704772949218753 +0.3025 0.2408447265625 0.05523681640625 -0.7704772949218753 +0.30262500000000004 0.236236572265625 0.05419921875 -0.7704772949218753 +0.30275 0.236236572265625 0.05419921875 -0.7704772949218753 +0.302875 0.231597900390625 0.053131103515625 -0.7704772949218753 +0.303 0.226959228515625 0.05206298828125 -0.7704772949218753 +0.30312500000000004 0.226959228515625 0.05206298828125 -0.7704772949218753 +0.30325 0.2222900390625 0.050994873046875 -0.7704772949218753 +0.303375 0.2222900390625 0.050994873046875 -0.7704772949218753 +0.3035 0.21759033203125 0.049896240234375 -0.7704772949218753 +0.30362500000000004 0.212860107421875 0.048828125 -0.7704772949218753 +0.30375 0.212860107421875 0.048828125 -0.7704772949218753 +0.303875 0.208099365234375 0.0477294921875 -0.7704772949218753 +0.304 0.208099365234375 0.0477294921875 -0.7704772949218753 +0.304125 0.203338623046875 0.046630859375 -0.7704772949218753 +0.30425 0.19854736328125 0.0455322265625 -0.7704772949218753 +0.304375 0.19854736328125 0.0455322265625 -0.7704772949218753 +0.3045 0.1937255859375 0.04443359375 -0.7704772949218753 +0.304625 0.1937255859375 0.04443359375 -0.7704772949218753 +0.30475 0.188873291015625 0.0433349609375 -0.7704772949218753 +0.304875 0.18402099609375 0.042205810546875 -0.7704772949218753 +0.305 0.18402099609375 0.042205810546875 -0.7704772949218753 +0.305125 0.17913818359375 0.04107666015625 -0.7704772949218753 +0.30525 0.17913818359375 0.04107666015625 -0.7704772949218753 +0.305375 0.17425537109375 0.03997802734375 -0.7704772949218753 +0.3055 0.169342041015625 0.038848876953125 -0.7704772949218753 +0.305625 0.169342041015625 0.038848876953125 -0.7704772949218753 +0.30575 0.164398193359375 0.0377197265625 -0.7704772949218753 +0.305875 0.164398193359375 0.0377197265625 -0.7704772949218753 +0.306 0.159454345703125 0.03656005859375 -0.7704772949218753 +0.306125 0.15447998046875 0.035430908203125 -0.7704772949218753 +0.30625 0.15447998046875 0.035430908203125 -0.7704772949218753 +0.306375 0.14947509765625 0.034271240234375 -0.7704772949218753 +0.3065 0.14947509765625 0.034271240234375 -0.7704772949218753 +0.306625 0.14447021484375 0.03314208984375 -0.7704772949218753 +0.30675 0.13946533203125 0.031982421875 -0.7704772949218753 +0.306875 0.13946533203125 0.031982421875 -0.7704772949218753 +0.307 0.134429931640625 0.03082275390625 -0.7704772949218753 +0.307125 0.134429931640625 0.03082275390625 -0.7704772949218753 +0.30725 0.129364013671875 0.0296630859375 -0.7704772949218753 +0.307375 0.124298095703125 0.02850341796875 -0.7704772949218753 +0.3075 0.124298095703125 0.02850341796875 -0.7704772949218753 +0.307625 0.119232177734375 0.02734375 -0.7704772949218753 +0.30775 0.119232177734375 0.02734375 -0.7704772949218753 +0.307875 0.1141357421875 0.02618408203125 -0.7704772949218753 +0.308 0.109039306640625 0.024993896484375 -0.7704772949218753 +0.308125 0.109039306640625 0.024993896484375 -0.7704772949218753 +0.30825 0.103912353515625 0.023834228515625 -0.7704772949218753 +0.308375 0.103912353515625 0.023834228515625 -0.7704772949218753 +0.3085 0.098785400390625 0.02264404296875 -0.7704772949218753 +0.308625 0.093658447265625 0.021484375 -0.7704772949218753 +0.30875 0.093658447265625 0.021484375 -0.7704772949218753 +0.308875 0.0885009765625 0.020294189453125 -0.7704772949218753 +0.309 0.0885009765625 0.020294189453125 -0.7704772949218753 +0.309125 0.083343505859375 0.01910400390625 -0.7704772949218753 +0.30925 0.07818603515625 0.017913818359375 -0.7704772949218753 +0.309375 0.07818603515625 0.017913818359375 -0.7704772949218753 +0.3095 0.072998046875 0.016754150390625 -0.7704772949218753 +0.309625 0.072998046875 0.016754150390625 -0.7704772949218753 +0.30975 0.06781005859375 0.01556396484375 -0.7704772949218753 +0.309875 0.0626220703125 0.014373779296875 -0.7704772949218753 +0.31 0.0626220703125 0.014373779296875 -0.7704772949218753 +0.310125 0.05743408203125 0.01318359375 -0.7704772949218753 +0.31025 0.05743408203125 0.01318359375 -0.7704772949218753 +0.310375 0.05224609375 0.011962890625 -0.7704772949218753 +0.3105 0.047027587890625 0.010772705078125 -0.7704772949218753 +0.310625 0.047027587890625 0.010772705078125 -0.7704772949218753 +0.31075 0.04180908203125 0.00958251953125 -0.7704772949218753 +0.310875 0.04180908203125 0.00958251953125 -0.7704772949218753 +0.311 0.036590576171875 0.008392333984375 -0.7704772949218753 +0.311125 0.0313720703125 0.007171630859375 -0.7704772949218753 +0.31125 0.0313720703125 0.007171630859375 -0.7704772949218753 +0.311375 0.026123046875 0.0059814453125 -0.7704772949218753 +0.3115 0.026123046875 0.0059814453125 -0.7704772949218753 +0.311625 0.020904541015625 0.004791259765625 -0.7704772949218753 +0.31175 0.01568603515625 0.00360107421875 -0.7704772949218753 +0.311875 0.01568603515625 0.00360107421875 -0.7704772949218753 +0.312 0.01043701171875 0.00238037109375 -0.7704772949218753 +0.312125 0.01043701171875 0.00238037109375 -0.7704772949218753 +0.31225 0.005218505859375 0.001190185546875 -0.7704772949218753 +0.312375 0.0 0.0 -0.7704772949218753 +0.3125 0.0 0.0 -0.7704772949218753 +0.312625 -0.005218505859375 -0.001190185546875 -0.7704772949218753 +0.31275000000000004 -0.005218505859375 -0.001190185546875 -0.7704772949218753 +0.312875 -0.01043701171875 -0.00238037109375 -0.7704772949218753 +0.313 -0.01568603515625 -0.00360107421875 -0.7704772949218753 +0.313125 -0.01568603515625 -0.00360107421875 -0.7704772949218753 +0.31325000000000004 -0.020904541015625 -0.004791259765625 -0.7704772949218753 +0.313375 -0.020904541015625 -0.004791259765625 -0.7704772949218753 +0.3135 -0.026123046875 -0.0059814453125 -0.7704772949218753 +0.313625 -0.0313720703125 -0.007171630859375 -0.7704772949218753 +0.31375000000000004 -0.0313720703125 -0.007171630859375 -0.7704772949218753 +0.313875 -0.036590576171875 -0.008392333984375 -0.7704772949218753 +0.314 -0.036590576171875 -0.008392333984375 -0.7704772949218753 +0.314125 -0.04180908203125 -0.00958251953125 -0.7704772949218753 +0.31425000000000004 -0.047027587890625 -0.010772705078125 -0.7704772949218753 +0.314375 -0.047027587890625 -0.010772705078125 -0.7704772949218753 +0.3145 -0.05224609375 -0.011962890625 -0.7704772949218753 +0.314625 -0.05224609375 -0.011962890625 -0.7704772949218753 +0.31475000000000004 -0.05743408203125 -0.01318359375 -0.7704772949218753 +0.314875 -0.0626220703125 -0.014373779296875 -0.7704772949218753 +0.315 -0.0626220703125 -0.014373779296875 -0.7704772949218753 +0.315125 -0.06781005859375 -0.01556396484375 -0.7704772949218753 +0.31525000000000004 -0.06781005859375 -0.01556396484375 -0.7704772949218753 +0.315375 -0.072998046875 -0.016754150390625 -0.7704772949218753 +0.3155 -0.07818603515625 -0.017913818359375 -0.7704772949218753 +0.315625 -0.07818603515625 -0.017913818359375 -0.7704772949218753 +0.31575000000000004 -0.083343505859375 -0.01910400390625 -0.7704772949218753 +0.315875 -0.083343505859375 -0.01910400390625 -0.7704772949218753 +0.316 -0.0885009765625 -0.020294189453125 -0.7704772949218753 +0.316125 -0.093658447265625 -0.021484375 -0.7704772949218753 +0.31625000000000004 -0.093658447265625 -0.021484375 -0.7704772949218753 +0.316375 -0.098785400390625 -0.02264404296875 -0.7704772949218753 +0.3165 -0.098785400390625 -0.02264404296875 -0.7704772949218753 +0.316625 -0.103912353515625 -0.023834228515625 -0.7704772949218753 +0.31675000000000004 -0.109039306640625 -0.024993896484375 -0.7704772949218753 +0.316875 -0.109039306640625 -0.024993896484375 -0.7704772949218753 +0.317 -0.1141357421875 -0.02618408203125 -0.7704772949218753 +0.317125 -0.1141357421875 -0.02618408203125 -0.7704772949218753 +0.31725000000000004 -0.119232177734375 -0.02734375 -0.7704772949218753 +0.317375 -0.124298095703125 -0.02850341796875 -0.7704772949218753 +0.3175 -0.124298095703125 -0.02850341796875 -0.7704772949218753 +0.317625 -0.129364013671875 -0.0296630859375 -0.7704772949218753 +0.31775000000000004 -0.129364013671875 -0.0296630859375 -0.7704772949218753 +0.317875 -0.134429931640625 -0.03082275390625 -0.7704772949218753 +0.318 -0.13946533203125 -0.031982421875 -0.7704772949218753 +0.318125 -0.13946533203125 -0.031982421875 -0.7704772949218753 +0.31825000000000004 -0.14447021484375 -0.03314208984375 -0.7704772949218753 +0.318375 -0.14447021484375 -0.03314208984375 -0.7704772949218753 +0.3185 -0.14947509765625 -0.034271240234375 -0.7704772949218753 +0.318625 -0.15447998046875 -0.035430908203125 -0.7704772949218753 +0.31875000000000004 -0.15447998046875 -0.035430908203125 -0.7704772949218753 +0.318875 -0.159454345703125 -0.03656005859375 -0.7704772949218753 +0.319 -0.159454345703125 -0.03656005859375 -0.7704772949218753 +0.319125 -0.164398193359375 -0.0377197265625 -0.7704772949218753 +0.31925000000000004 -0.169342041015625 -0.038848876953125 -0.7704772949218753 +0.319375 -0.169342041015625 -0.038848876953125 -0.7704772949218753 +0.3195 -0.17425537109375 -0.03997802734375 -0.7704772949218753 +0.319625 -0.17425537109375 -0.03997802734375 -0.7704772949218753 +0.31975000000000004 -0.17913818359375 -0.04107666015625 -0.7704772949218753 +0.319875 -0.18402099609375 -0.042205810546875 -0.7704772949218753 +0.32 -0.18402099609375 -0.007598876953125 -0.9584594726562502912 +0.320125 -0.188873291015625 -0.0078125 -0.9584594726562502912 +0.32025 -0.188873291015625 -0.0078125 -0.9584594726562502912 +0.320375 -0.1937255859375 -0.008026123046875 -0.9584594726562502912 +0.3205 -0.19854736328125 -0.008209228515625 -0.9584594726562502912 +0.320625 -0.19854736328125 -0.008209228515625 -0.9584594726562502912 +0.32075 -0.203338623046875 -0.0084228515625 -0.9584594726562502912 +0.320875 -0.203338623046875 -0.0084228515625 -0.9584594726562502912 +0.321 -0.208099365234375 -0.00860595703125 -0.9584594726562502912 +0.321125 -0.212860107421875 -0.008819580078125 -0.9584594726562502912 +0.32125 -0.212860107421875 -0.008819580078125 -0.9584594726562502912 +0.321375 -0.21759033203125 -0.009002685546875 -0.9584594726562502912 +0.3215 -0.21759033203125 -0.009002685546875 -0.9584594726562502912 +0.321625 -0.2222900390625 -0.009185791015625 -0.9584594726562502912 +0.32175 -0.226959228515625 -0.0093994140625 -0.9584594726562502912 +0.321875 -0.226959228515625 -0.0093994140625 -0.9584594726562502912 +0.322 -0.231597900390625 -0.00958251953125 -0.9584594726562502912 +0.322125 -0.231597900390625 -0.00958251953125 -0.9584594726562502912 +0.32225 -0.236236572265625 -0.009765625 -0.9584594726562502912 +0.322375 -0.2408447265625 -0.009979248046875 -0.9584594726562502912 +0.3225 -0.2408447265625 -0.009979248046875 -0.9584594726562502912 +0.322625 -0.24542236328125 -0.010162353515625 -0.9584594726562502912 +0.32275 -0.24542236328125 -0.010162353515625 -0.9584594726562502912 +0.322875 -0.249969482421875 -0.010345458984375 -0.9584594726562502912 +0.323 -0.25445556640625 -0.010528564453125 -0.9584594726562502912 +0.323125 -0.25445556640625 -0.010528564453125 -0.9584594726562502912 +0.32325 -0.25897216796875 -0.010711669921875 -0.9584594726562502912 +0.323375 -0.25897216796875 -0.010711669921875 -0.9584594726562502912 +0.3235 -0.263427734375 -0.010894775390625 -0.9584594726562502912 +0.323625 -0.267852783203125 -0.011077880859375 -0.9584594726562502912 +0.32375 -0.267852783203125 -0.011077880859375 -0.9584594726562502912 +0.323875 -0.27227783203125 -0.011260986328125 -0.9584594726562502912 +0.324 -0.27227783203125 -0.011260986328125 -0.9584594726562502912 +0.324125 -0.276641845703125 -0.011444091796875 -0.9584594726562502912 +0.32425 -0.280975341796875 -0.011627197265625 -0.9584594726562502912 +0.324375 -0.280975341796875 -0.011627197265625 -0.9584594726562502912 +0.3245 -0.285308837890625 -0.011810302734375 -0.9584594726562502912 +0.324625 -0.285308837890625 -0.011810302734375 -0.9584594726562502912 +0.32475 -0.289581298828125 -0.011993408203125 -0.9584594726562502912 +0.324875 -0.2938232421875 -0.012176513671875 -0.9584594726562502912 +0.325 -0.2938232421875 -0.012176513671875 -0.9584594726562502912 +0.325125 -0.298065185546875 -0.0123291015625 -0.9584594726562502912 +0.32525 -0.298065185546875 -0.0123291015625 -0.9584594726562502912 +0.325375 -0.30224609375 -0.01251220703125 -0.9584594726562502912 +0.3255 -0.306396484375 -0.0126953125 -0.9584594726562502912 +0.325625 -0.306396484375 -0.0126953125 -0.9584594726562502912 +0.32575 -0.310516357421875 -0.012847900390625 -0.9584594726562502912 +0.325875 -0.310516357421875 -0.012847900390625 -0.9584594726562502912 +0.326 -0.314605712890625 -0.013031005859375 -0.9584594726562502912 +0.326125 -0.31866455078125 -0.01318359375 -0.9584594726562502912 +0.32625 -0.31866455078125 -0.01318359375 -0.9584594726562502912 +0.326375 -0.322662353515625 -0.01336669921875 -0.9584594726562502912 +0.3265 -0.322662353515625 -0.01336669921875 -0.9584594726562502912 +0.326625 -0.32666015625 -0.013519287109375 -0.9584594726562502912 +0.32675 -0.330596923828125 -0.013702392578125 -0.9584594726562502912 +0.326875 -0.330596923828125 -0.013702392578125 -0.9584594726562502912 +0.327 -0.334503173828125 -0.01385498046875 -0.9584594726562502912 +0.327125 -0.334503173828125 -0.01385498046875 -0.9584594726562502912 +0.32725 -0.33837890625 -0.014007568359375 -0.9584594726562502912 +0.327375 -0.34222412109375 -0.01416015625 -0.9584594726562502912 +0.3275 -0.34222412109375 -0.01416015625 -0.9584594726562502912 +0.327625 -0.34600830078125 -0.014312744140625 -0.9584594726562502912 +0.32775 -0.34600830078125 -0.014312744140625 -0.9584594726562502912 +0.327875 -0.349761962890625 -0.014495849609375 -0.9584594726562502912 +0.328 -0.353485107421875 -0.0146484375 -0.9584594726562502912 +0.328125 -0.353485107421875 -0.0146484375 -0.9584594726562502912 +0.32825 -0.357177734375 -0.014801025390625 -0.9584594726562502912 +0.32837500000000004 -0.357177734375 -0.014801025390625 -0.9584594726562502912 +0.3285 -0.360809326171875 -0.01495361328125 -0.9584594726562502912 +0.328625 -0.36444091796875 -0.01507568359375 -0.9584594726562502912 +0.32875 -0.36444091796875 -0.01507568359375 -0.9584594726562502912 +0.32887500000000004 -0.36798095703125 -0.015228271484375 -0.9584594726562502912 +0.329 -0.36798095703125 -0.015228271484375 -0.9584594726562502912 +0.329125 -0.37152099609375 -0.015380859375 -0.9584594726562502912 +0.32925 -0.375 -0.015533447265625 -0.9584594726562502912 +0.32937500000000004 -0.375 -0.015533447265625 -0.9584594726562502912 +0.3295 -0.378448486328125 -0.015655517578125 -0.9584594726562502912 +0.329625 -0.378448486328125 -0.015655517578125 -0.9584594726562502912 +0.32975 -0.3818359375 -0.01580810546875 -0.9584594726562502912 +0.32987500000000004 -0.38519287109375 -0.015960693359375 -0.9584594726562502912 +0.33 -0.38519287109375 -0.015960693359375 -0.9584594726562502912 +0.330125 -0.388519287109375 -0.016082763671875 -0.9584594726562502912 +0.33025 -0.388519287109375 -0.016082763671875 -0.9584594726562502912 +0.33037500000000004 -0.39178466796875 -0.0162353515625 -0.9584594726562502912 +0.3305 -0.39501953125 -0.016357421875 -0.9584594726562502912 +0.330625 -0.39501953125 -0.016357421875 -0.9584594726562502912 +0.33075 -0.398193359375 -0.0164794921875 -0.9584594726562502912 +0.33087500000000004 -0.398193359375 -0.0164794921875 -0.9584594726562502912 +0.331 -0.401336669921875 -0.016632080078125 -0.9584594726562502912 +0.331125 -0.404449462890625 -0.016754150390625 -0.9584594726562502912 +0.33125 -0.404449462890625 -0.016754150390625 -0.9584594726562502912 +0.33137500000000004 -0.407501220703125 -0.016876220703125 -0.9584594726562502912 +0.3315 -0.407501220703125 -0.016876220703125 -0.9584594726562502912 +0.331625 -0.4105224609375 -0.016998291015625 -0.9584594726562502912 +0.33175 -0.413482666015625 -0.017120361328125 -0.9584594726562502912 +0.33187500000000004 -0.413482666015625 -0.017120361328125 -0.9584594726562502912 +0.332 -0.416412353515625 -0.017242431640625 -0.9584594726562502912 +0.332125 -0.416412353515625 -0.017242431640625 -0.9584594726562502912 +0.33225 -0.419281005859375 -0.017364501953125 -0.9584594726562502912 +0.33237500000000004 -0.422119140625 -0.017486572265625 -0.9584594726562502912 +0.3325 -0.422119140625 -0.017486572265625 -0.9584594726562502912 +0.332625 -0.424896240234375 -0.017608642578125 -0.9584594726562502912 +0.33275 -0.424896240234375 -0.017608642578125 -0.9584594726562502912 +0.33287500000000004 -0.4276123046875 -0.0177001953125 -0.9584594726562502912 +0.333 -0.4302978515625 -0.017822265625 -0.9584594726562502912 +0.333125 -0.4302978515625 -0.017822265625 -0.9584594726562502912 +0.33325 -0.432952880859375 -0.0179443359375 -0.9584594726562502912 +0.33337500000000004 -0.432952880859375 -0.0179443359375 -0.9584594726562502912 +0.3335 -0.435546875 -0.018035888671875 -0.9584594726562502912 +0.333625 -0.438079833984375 -0.01812744140625 -0.9584594726562502912 +0.33375 -0.438079833984375 -0.01812744140625 -0.9584594726562502912 +0.33387500000000004 -0.440582275390625 -0.01824951171875 -0.9584594726562502912 +0.334 -0.440582275390625 -0.01824951171875 -0.9584594726562502912 +0.334125 -0.44305419921875 -0.018341064453125 -0.9584594726562502912 +0.33425 -0.4454345703125 -0.0184326171875 -0.9584594726562502912 +0.33437500000000004 -0.4454345703125 -0.0184326171875 -0.9584594726562502912 +0.3345 -0.447784423828125 -0.0185546875 -0.9584594726562502912 +0.334625 -0.447784423828125 -0.0185546875 -0.9584594726562502912 +0.33475 -0.450103759765625 -0.018646240234375 -0.9584594726562502912 +0.33487500000000004 -0.452362060546875 -0.01873779296875 -0.9584594726562502912 +0.335 -0.452362060546875 -0.01873779296875 -0.9584594726562502912 +0.335125 -0.454559326171875 -0.018829345703125 -0.9584594726562502912 +0.33525 -0.454559326171875 -0.018829345703125 -0.9584594726562502912 +0.33537500000000004 -0.45672607421875 -0.0189208984375 -0.9584594726562502912 +0.3355 -0.458831787109375 -0.019012451171875 -0.9584594726562502912 +0.335625 -0.458831787109375 -0.019012451171875 -0.9584594726562502912 +0.33575 -0.46087646484375 -0.019073486328125 -0.9584594726562502912 +0.33587500000000004 -0.46087646484375 -0.019073486328125 -0.9584594726562502912 +0.336 -0.462890625 -0.0191650390625 -0.9584594726562502912 +0.336125 -0.464813232421875 -0.019256591796875 -0.9584594726562502912 +0.33625 -0.464813232421875 -0.019256591796875 -0.9584594726562502912 +0.336375 -0.46673583984375 -0.019317626953125 -0.9584594726562502912 +0.3365 -0.46673583984375 -0.019317626953125 -0.9584594726562502912 +0.336625 -0.46856689453125 -0.0194091796875 -0.9584594726562502912 +0.33675 -0.470367431640625 -0.01947021484375 -0.9584594726562502912 +0.336875 -0.470367431640625 -0.01947021484375 -0.9584594726562502912 +0.337 -0.472137451171875 -0.019561767578125 -0.9584594726562502912 +0.337125 -0.472137451171875 -0.019561767578125 -0.9584594726562502912 +0.33725 -0.47381591796875 -0.019622802734375 -0.9584594726562502912 +0.337375 -0.4754638671875 -0.019683837890625 -0.9584594726562502912 +0.3375 -0.4754638671875 -0.019683837890625 -0.9584594726562502912 +0.337625 -0.47705078125 -0.019744873046875 -0.9584594726562502912 +0.33775 -0.47705078125 -0.019744873046875 -0.9584594726562502912 +0.337875 -0.478607177734375 -0.019805908203125 -0.9584594726562502912 +0.338 -0.480072021484375 -0.019866943359375 -0.9584594726562502912 +0.338125 -0.480072021484375 -0.019866943359375 -0.9584594726562502912 +0.33825 -0.48150634765625 -0.019927978515625 -0.9584594726562502912 +0.338375 -0.48150634765625 -0.019927978515625 -0.9584594726562502912 +0.3385 -0.48291015625 -0.019989013671875 -0.9584594726562502912 +0.338625 -0.484222412109375 -0.020050048828125 -0.9584594726562502912 +0.33875 -0.484222412109375 -0.020050048828125 -0.9584594726562502912 +0.338875 -0.485504150390625 -0.020111083984375 -0.9584594726562502912 +0.339 -0.485504150390625 -0.020111083984375 -0.9584594726562502912 +0.339125 -0.486724853515625 -0.020172119140625 -0.9584594726562502912 +0.33925 -0.487884521484375 -0.02020263671875 -0.9584594726562502912 +0.339375 -0.487884521484375 -0.02020263671875 -0.9584594726562502912 +0.3395 -0.489013671875 -0.020263671875 -0.9584594726562502912 +0.339625 -0.489013671875 -0.020263671875 -0.9584594726562502912 +0.33975 -0.490081787109375 -0.020294189453125 -0.9584594726562502912 +0.339875 -0.4910888671875 -0.02032470703125 -0.9584594726562502912 +0.34 -0.4910888671875 -0.02032470703125 -0.9584594726562502912 +0.340125 -0.492034912109375 -0.0203857421875 -0.9584594726562502912 +0.34025 -0.492034912109375 -0.0203857421875 -0.9584594726562502912 +0.340375 -0.492950439453125 -0.020416259765625 -0.9584594726562502912 +0.3405 -0.4937744140625 -0.02044677734375 -0.9584594726562502912 +0.340625 -0.4937744140625 -0.02044677734375 -0.9584594726562502912 +0.34075 -0.49456787109375 -0.020477294921875 -0.9584594726562502912 +0.340875 -0.49456787109375 -0.020477294921875 -0.9584594726562502912 +0.341 -0.49530029296875 -0.0205078125 -0.9584594726562502912 +0.341125 -0.496002197265625 -0.020538330078125 -0.9584594726562502912 +0.34125 -0.496002197265625 -0.020538330078125 -0.9584594726562502912 +0.341375 -0.496612548828125 -0.02056884765625 -0.9584594726562502912 +0.3415 -0.496612548828125 -0.02056884765625 -0.9584594726562502912 +0.341625 -0.4971923828125 -0.020599365234375 -0.9584594726562502912 +0.34175 -0.497711181640625 -0.020599365234375 -0.9584594726562502912 +0.341875 -0.497711181640625 -0.020599365234375 -0.9584594726562502912 +0.342 -0.498199462890625 -0.0206298828125 -0.9584594726562502912 +0.342125 -0.498199462890625 -0.0206298828125 -0.9584594726562502912 +0.34225 -0.49859619140625 -0.020660400390625 -0.9584594726562502912 +0.342375 -0.49896240234375 -0.020660400390625 -0.9584594726562502912 +0.3425 -0.49896240234375 -0.020660400390625 -0.9584594726562502912 +0.342625 -0.499267578125 -0.02069091796875 -0.9584594726562502912 +0.34275 -0.499267578125 -0.02069091796875 -0.9584594726562502912 +0.342875 -0.49951171875 -0.02069091796875 -0.9584594726562502912 +0.343 -0.49969482421875 -0.02069091796875 -0.9584594726562502912 +0.343125 -0.49969482421875 -0.02069091796875 -0.9584594726562502912 +0.34325 -0.49981689453125 -0.02069091796875 -0.9584594726562502912 +0.343375 -0.49981689453125 -0.02069091796875 -0.9584594726562502912 +0.3435 -0.499908447265625 -0.02069091796875 -0.9584594726562502912 +0.343625 -0.49993896484375 -0.02069091796875 -0.9584594726562502912 +0.34375 -0.49993896484375 -0.02069091796875 -0.9584594726562502912 +0.343875 -0.499908447265625 -0.02069091796875 -0.9584594726562502912 +0.34400000000000004 -0.499908447265625 -0.02069091796875 -0.9584594726562502912 +0.344125 -0.49981689453125 -0.02069091796875 -0.9584594726562502912 +0.34425 -0.49969482421875 -0.02069091796875 -0.9584594726562502912 +0.344375 -0.49969482421875 -0.02069091796875 -0.9584594726562502912 +0.34450000000000004 -0.49951171875 -0.02069091796875 -0.9584594726562502912 +0.344625 -0.49951171875 -0.02069091796875 -0.9584594726562502912 +0.34475 -0.499267578125 -0.02069091796875 -0.9584594726562502912 +0.344875 -0.49896240234375 -0.020660400390625 -0.9584594726562502912 +0.34500000000000004 -0.49896240234375 -0.020660400390625 -0.9584594726562502912 +0.345125 -0.49859619140625 -0.020660400390625 -0.9584594726562502912 +0.34525 -0.49859619140625 -0.020660400390625 -0.9584594726562502912 +0.345375 -0.498199462890625 -0.0206298828125 -0.9584594726562502912 +0.34550000000000004 -0.497711181640625 -0.020599365234375 -0.9584594726562502912 +0.345625 -0.497711181640625 -0.020599365234375 -0.9584594726562502912 +0.34575 -0.4971923828125 -0.020599365234375 -0.9584594726562502912 +0.345875 -0.4971923828125 -0.020599365234375 -0.9584594726562502912 +0.34600000000000004 -0.496612548828125 -0.02056884765625 -0.9584594726562502912 +0.346125 -0.496002197265625 -0.020538330078125 -0.9584594726562502912 +0.34625 -0.496002197265625 -0.020538330078125 -0.9584594726562502912 +0.346375 -0.49530029296875 -0.0205078125 -0.9584594726562502912 +0.34650000000000004 -0.49530029296875 -0.0205078125 -0.9584594726562502912 +0.346625 -0.49456787109375 -0.020477294921875 -0.9584594726562502912 +0.34675 -0.4937744140625 -0.02044677734375 -0.9584594726562502912 +0.346875 -0.4937744140625 -0.02044677734375 -0.9584594726562502912 +0.34700000000000004 -0.492950439453125 -0.020416259765625 -0.9584594726562502912 +0.347125 -0.492950439453125 -0.020416259765625 -0.9584594726562502912 +0.34725 -0.492034912109375 -0.0203857421875 -0.9584594726562502912 +0.347375 -0.4910888671875 -0.02032470703125 -0.9584594726562502912 +0.34750000000000004 -0.4910888671875 -0.02032470703125 -0.9584594726562502912 +0.347625 -0.490081787109375 -0.020294189453125 -0.9584594726562502912 +0.34775 -0.490081787109375 -0.020294189453125 -0.9584594726562502912 +0.347875 -0.489013671875 -0.020263671875 -0.9584594726562502912 +0.34800000000000004 -0.487884521484375 -0.02020263671875 -0.9584594726562502912 +0.348125 -0.487884521484375 -0.02020263671875 -0.9584594726562502912 +0.34825 -0.486724853515625 -0.020172119140625 -0.9584594726562502912 +0.348375 -0.486724853515625 -0.020172119140625 -0.9584594726562502912 +0.34850000000000004 -0.485504150390625 -0.020111083984375 -0.9584594726562502912 +0.348625 -0.484222412109375 -0.020050048828125 -0.9584594726562502912 +0.34875 -0.484222412109375 -0.020050048828125 -0.9584594726562502912 +0.348875 -0.48291015625 -0.019989013671875 -0.9584594726562502912 +0.34900000000000004 -0.48291015625 -0.019989013671875 -0.9584594726562502912 +0.349125 -0.48150634765625 -0.019927978515625 -0.9584594726562502912 +0.34925 -0.480072021484375 -0.019866943359375 -0.9584594726562502912 +0.349375 -0.480072021484375 -0.019866943359375 -0.9584594726562502912 +0.34950000000000004 -0.478607177734375 -0.019805908203125 -0.9584594726562502912 +0.349625 -0.478607177734375 -0.019805908203125 -0.9584594726562502912 +0.34975 -0.47705078125 -0.019744873046875 -0.9584594726562502912 +0.349875 -0.4754638671875 -0.019683837890625 -0.9584594726562502912 +0.35000000000000004 -0.4754638671875 -0.019683837890625 -0.9584594726562502912 +0.350125 -0.47381591796875 -0.019622802734375 -0.9584594726562502912 +0.35025 -0.47381591796875 -0.019622802734375 -0.9584594726562502912 +0.350375 -0.472137451171875 -0.019561767578125 -0.9584594726562502912 +0.35050000000000004 -0.470367431640625 -0.01947021484375 -0.9584594726562502912 +0.350625 -0.470367431640625 -0.01947021484375 -0.9584594726562502912 +0.35075 -0.46856689453125 -0.0194091796875 -0.9584594726562502912 +0.350875 -0.46856689453125 -0.0194091796875 -0.9584594726562502912 +0.35100000000000004 -0.46673583984375 -0.019317626953125 -0.9584594726562502912 +0.351125 -0.464813232421875 -0.019256591796875 -0.9584594726562502912 +0.35125 -0.464813232421875 -0.019256591796875 -0.9584594726562502912 +0.351375 -0.462890625 -0.0191650390625 -0.9584594726562502912 +0.35150000000000004 -0.462890625 -0.0191650390625 -0.9584594726562502912 +0.351625 -0.46087646484375 -0.019073486328125 -0.9584594726562502912 +0.35175 -0.458831787109375 -0.019012451171875 -0.9584594726562502912 +0.351875 -0.458831787109375 -0.019012451171875 -0.9584594726562502912 +0.352 -0.45672607421875 -0.002899169921875 -0.9935485839843748 +0.352125 -0.45672607421875 -0.002899169921875 -0.9935485839843748 +0.35225 -0.454559326171875 -0.00286865234375 -0.9935485839843748 +0.352375 -0.452362060546875 -0.00286865234375 -0.9935485839843748 +0.3525 -0.452362060546875 -0.00286865234375 -0.9935485839843748 +0.352625 -0.450103759765625 -0.002838134765625 -0.9935485839843748 +0.35275 -0.450103759765625 -0.002838134765625 -0.9935485839843748 +0.352875 -0.447784423828125 -0.002838134765625 -0.9935485839843748 +0.353 -0.4454345703125 -0.0028076171875 -0.9935485839843748 +0.353125 -0.4454345703125 -0.0028076171875 -0.9935485839843748 +0.35325 -0.44305419921875 -0.0028076171875 -0.9935485839843748 +0.353375 -0.44305419921875 -0.0028076171875 -0.9935485839843748 +0.3535 -0.440582275390625 -0.002777099609375 -0.9935485839843748 +0.353625 -0.438079833984375 -0.002777099609375 -0.9935485839843748 +0.35375 -0.438079833984375 -0.002777099609375 -0.9935485839843748 +0.353875 -0.435546875 -0.00274658203125 -0.9935485839843748 +0.354 -0.435546875 -0.00274658203125 -0.9935485839843748 +0.354125 -0.432952880859375 -0.00274658203125 -0.9935485839843748 +0.35425 -0.4302978515625 -0.002716064453125 -0.9935485839843748 +0.354375 -0.4302978515625 -0.002716064453125 -0.9935485839843748 +0.3545 -0.4276123046875 -0.002685546875 -0.9935485839843748 +0.354625 -0.4276123046875 -0.002685546875 -0.9935485839843748 +0.35475 -0.424896240234375 -0.002685546875 -0.9935485839843748 +0.354875 -0.422119140625 -0.002655029296875 -0.9935485839843748 +0.355 -0.422119140625 -0.002655029296875 -0.9935485839843748 +0.355125 -0.419281005859375 -0.002655029296875 -0.9935485839843748 +0.35525 -0.419281005859375 -0.002655029296875 -0.9935485839843748 +0.355375 -0.416412353515625 -0.00262451171875 -0.9935485839843748 +0.3555 -0.413482666015625 -0.00262451171875 -0.9935485839843748 +0.355625 -0.413482666015625 -0.00262451171875 -0.9935485839843748 +0.35575 -0.4105224609375 -0.002593994140625 -0.9935485839843748 +0.355875 -0.4105224609375 -0.002593994140625 -0.9935485839843748 +0.356 -0.407501220703125 -0.0025634765625 -0.9935485839843748 +0.356125 -0.404449462890625 -0.0025634765625 -0.9935485839843748 +0.35625 -0.404449462890625 -0.0025634765625 -0.9935485839843748 +0.356375 -0.401336669921875 -0.002532958984375 -0.9935485839843748 +0.3565 -0.401336669921875 -0.002532958984375 -0.9935485839843748 +0.356625 -0.398193359375 -0.00250244140625 -0.9935485839843748 +0.35675 -0.39501953125 -0.00250244140625 -0.9935485839843748 +0.356875 -0.39501953125 -0.00250244140625 -0.9935485839843748 +0.357 -0.39178466796875 -0.002471923828125 -0.9935485839843748 +0.357125 -0.39178466796875 -0.002471923828125 -0.9935485839843748 +0.35725 -0.388519287109375 -0.00244140625 -0.9935485839843748 +0.357375 -0.38519287109375 -0.00244140625 -0.9935485839843748 +0.3575 -0.38519287109375 -0.00244140625 -0.9935485839843748 +0.357625 -0.3818359375 -0.002410888671875 -0.9935485839843748 +0.35775 -0.3818359375 -0.002410888671875 -0.9935485839843748 +0.357875 -0.378448486328125 -0.00238037109375 -0.9935485839843748 +0.358 -0.375 -0.00238037109375 -0.9935485839843748 +0.358125 -0.375 -0.00238037109375 -0.9935485839843748 +0.35825 -0.37152099609375 -0.002349853515625 -0.9935485839843748 +0.358375 -0.37152099609375 -0.002349853515625 -0.9935485839843748 +0.3585 -0.36798095703125 -0.0023193359375 -0.9935485839843748 +0.358625 -0.36444091796875 -0.002288818359375 -0.9935485839843748 +0.35875 -0.36444091796875 -0.002288818359375 -0.9935485839843748 +0.358875 -0.360809326171875 -0.002288818359375 -0.9935485839843748 +0.359 -0.360809326171875 -0.002288818359375 -0.9935485839843748 +0.359125 -0.357177734375 -0.00225830078125 -0.9935485839843748 +0.35925 -0.353485107421875 -0.002227783203125 -0.9935485839843748 +0.359375 -0.353485107421875 -0.002227783203125 -0.9935485839843748 +0.3595 -0.349761962890625 -0.002197265625 -0.9935485839843748 +0.35962500000000004 -0.349761962890625 -0.002197265625 -0.9935485839843748 +0.35975 -0.34600830078125 -0.002166748046875 -0.9935485839843748 +0.359875 -0.34222412109375 -0.002166748046875 -0.9935485839843748 +0.36 -0.34222412109375 -0.002166748046875 -0.9935485839843748 +0.36012500000000004 -0.33837890625 -0.00213623046875 -0.9935485839843748 +0.36025 -0.33837890625 -0.00213623046875 -0.9935485839843748 +0.360375 -0.334503173828125 -0.002105712890625 -0.9935485839843748 +0.3605 -0.330596923828125 -0.0020751953125 -0.9935485839843748 +0.3606250000000000512 -0.330596923828125 -0.0020751953125 -0.9935485839843748 +0.36075 -0.32666015625 -0.002044677734375 -0.9935485839843748 +0.360875 -0.32666015625 -0.002044677734375 -0.9935485839843748 +0.361 -0.322662353515625 -0.002044677734375 -0.9935485839843748 +0.3611250000000000512 -0.31866455078125 -0.00201416015625 -0.9935485839843748 +0.36125 -0.31866455078125 -0.00201416015625 -0.9935485839843748 +0.361375 -0.314605712890625 -0.001983642578125 -0.9935485839843748 +0.3615 -0.314605712890625 -0.001983642578125 -0.9935485839843748 +0.3616250000000000512 -0.310516357421875 -0.001953125 -0.9935485839843748 +0.36175 -0.306396484375 -0.001922607421875 -0.9935485839843748 +0.361875 -0.306396484375 -0.001922607421875 -0.9935485839843748 +0.362 -0.30224609375 -0.00189208984375 -0.9935485839843748 +0.3621250000000000512 -0.30224609375 -0.00189208984375 -0.9935485839843748 +0.36225 -0.298065185546875 -0.00189208984375 -0.9935485839843748 +0.362375 -0.2938232421875 -0.001861572265625 -0.9935485839843748 +0.3625 -0.2938232421875 -0.001861572265625 -0.9935485839843748 +0.3626250000000000512 -0.289581298828125 -0.0018310546875 -0.9935485839843748 +0.36275 -0.289581298828125 -0.0018310546875 -0.9935485839843748 +0.362875 -0.285308837890625 -0.001800537109375 -0.9935485839843748 +0.363 -0.280975341796875 -0.00177001953125 -0.9935485839843748 +0.3631250000000000512 -0.280975341796875 -0.00177001953125 -0.9935485839843748 +0.36325 -0.276641845703125 -0.001739501953125 -0.9935485839843748 +0.363375 -0.276641845703125 -0.001739501953125 -0.9935485839843748 +0.3635 -0.27227783203125 -0.001708984375 -0.9935485839843748 +0.3636250000000000512 -0.267852783203125 -0.001678466796875 -0.9935485839843748 +0.36375 -0.267852783203125 -0.001678466796875 -0.9935485839843748 +0.363875 -0.263427734375 -0.00164794921875 -0.9935485839843748 +0.364 -0.263427734375 -0.00164794921875 -0.9935485839843748 +0.3641250000000000512 -0.25897216796875 -0.001617431640625 -0.9935485839843748 +0.36425 -0.25445556640625 -0.0015869140625 -0.9935485839843748 +0.364375 -0.25445556640625 -0.0015869140625 -0.9935485839843748 +0.3645 -0.249969482421875 -0.001556396484375 -0.9935485839843748 +0.3646250000000000512 -0.249969482421875 -0.001556396484375 -0.9935485839843748 +0.36475 -0.24542236328125 -0.001556396484375 -0.9935485839843748 +0.364875 -0.2408447265625 -0.00152587890625 -0.9935485839843748 +0.365 -0.2408447265625 -0.00152587890625 -0.9935485839843748 +0.3651250000000000512 -0.236236572265625 -0.001495361328125 -0.9935485839843748 +0.36525 -0.236236572265625 -0.001495361328125 -0.9935485839843748 +0.365375 -0.231597900390625 -0.00146484375 -0.9935485839843748 +0.3655 -0.226959228515625 -0.001434326171875 -0.9935485839843748 +0.3656250000000000512 -0.226959228515625 -0.001434326171875 -0.9935485839843748 +0.36575 -0.2222900390625 -0.00140380859375 -0.9935485839843748 +0.365875 -0.2222900390625 -0.00140380859375 -0.9935485839843748 +0.366 -0.21759033203125 -0.001373291015625 -0.9935485839843748 +0.3661250000000000512 -0.212860107421875 -0.0013427734375 -0.9935485839843748 +0.36625 -0.212860107421875 -0.0013427734375 -0.9935485839843748 +0.366375 -0.208099365234375 -0.001312255859375 -0.9935485839843748 +0.3665 -0.208099365234375 -0.001312255859375 -0.9935485839843748 +0.3666250000000000512 -0.203338623046875 -0.00128173828125 -0.9935485839843748 +0.36675 -0.19854736328125 -0.001251220703125 -0.9935485839843748 +0.366875 -0.19854736328125 -0.001251220703125 -0.9935485839843748 +0.367 -0.1937255859375 -0.001220703125 -0.9935485839843748 +0.3671250000000000512 -0.1937255859375 -0.001220703125 -0.9935485839843748 +0.36725 -0.188873291015625 -0.001190185546875 -0.9935485839843748 +0.367375 -0.18402099609375 -0.00115966796875 -0.9935485839843748 +0.3675 -0.18402099609375 -0.00115966796875 -0.9935485839843748 +0.3676250000000000512 -0.17913818359375 -0.001129150390625 -0.9935485839843748 +0.36775 -0.17913818359375 -0.001129150390625 -0.9935485839843748 +0.367875 -0.17425537109375 -0.0010986328125 -0.9935485839843748 +0.368 -0.169342041015625 -0.001068115234375 -0.9935485839843748 +0.368125 -0.169342041015625 -0.001068115234375 -0.9935485839843748 +0.36825 -0.164398193359375 -0.00103759765625 -0.9935485839843748 +0.368375 -0.164398193359375 -0.00103759765625 -0.9935485839843748 +0.3685 -0.159454345703125 -0.001007080078125 -0.9935485839843748 +0.368625 -0.15447998046875 -0.0009765625 -0.9935485839843748 +0.36875 -0.15447998046875 -0.0009765625 -0.9935485839843748 +0.368875 -0.14947509765625 -0.000946044921875 -0.9935485839843748 +0.369 -0.14947509765625 -0.000946044921875 -0.9935485839843748 +0.369125 -0.14447021484375 -0.00091552734375 -0.9935485839843748 +0.36925 -0.13946533203125 -0.000885009765625 -0.9935485839843748 +0.369375 -0.13946533203125 -0.000885009765625 -0.9935485839843748 +0.3695 -0.134429931640625 -0.000823974609375 -0.9935485839843748 +0.369625 -0.134429931640625 -0.000823974609375 -0.9935485839843748 +0.36975 -0.129364013671875 -0.00079345703125 -0.9935485839843748 +0.369875 -0.124298095703125 -0.000762939453125 -0.9935485839843748 +0.37 -0.124298095703125 -0.000762939453125 -0.9935485839843748 +0.370125 -0.119232177734375 -0.000732421875 -0.9935485839843748 +0.37025 -0.119232177734375 -0.000732421875 -0.9935485839843748 +0.370375 -0.1141357421875 -0.000701904296875 -0.9935485839843748 +0.3705 -0.109039306640625 -0.00067138671875 -0.9935485839843748 +0.370625 -0.109039306640625 -0.00067138671875 -0.9935485839843748 +0.37075 -0.103912353515625 -0.000640869140625 -0.9935485839843748 +0.370875 -0.103912353515625 -0.000640869140625 -0.9935485839843748 +0.371 -0.098785400390625 -0.0006103515625 -0.9935485839843748 +0.371125 -0.093658447265625 -0.000579833984375 -0.9935485839843748 +0.37125 -0.093658447265625 -0.000579833984375 -0.9935485839843748 +0.371375 -0.0885009765625 -0.00054931640625 -0.9935485839843748 +0.3715 -0.0885009765625 -0.00054931640625 -0.9935485839843748 +0.371625 -0.083343505859375 -0.000518798828125 -0.9935485839843748 +0.37175 -0.07818603515625 -0.00048828125 -0.9935485839843748 +0.371875 -0.07818603515625 -0.00048828125 -0.9935485839843748 +0.372 -0.072998046875 -0.000457763671875 -0.9935485839843748 +0.372125 -0.072998046875 -0.000457763671875 -0.9935485839843748 +0.37225 -0.06781005859375 -0.00042724609375 -0.9935485839843748 +0.372375 -0.0626220703125 -0.000396728515625 -0.9935485839843748 +0.3725 -0.0626220703125 -0.000396728515625 -0.9935485839843748 +0.372625 -0.05743408203125 -0.000335693359375 -0.9935485839843748 +0.37275 -0.05743408203125 -0.000335693359375 -0.9935485839843748 +0.372875 -0.05224609375 -0.00030517578125 -0.9935485839843748 +0.373 -0.047027587890625 -0.000274658203125 -0.9935485839843748 +0.373125 -0.047027587890625 -0.000274658203125 -0.9935485839843748 +0.37325 -0.04180908203125 -0.000244140625 -0.9935485839843748 +0.373375 -0.04180908203125 -0.000244140625 -0.9935485839843748 +0.3735 -0.036590576171875 -0.000213623046875 -0.9935485839843748 +0.373625 -0.0313720703125 -0.00018310546875 -0.9935485839843748 +0.37375 -0.0313720703125 -0.00018310546875 -0.9935485839843748 +0.373875 -0.026123046875 -0.000152587890625 -0.9935485839843748 +0.374 -0.026123046875 -0.000152587890625 -0.9935485839843748 +0.374125 -0.020904541015625 -0.0001220703125 -0.9935485839843748 +0.37425 -0.01568603515625 -9.1552734375e-05 -0.9935485839843748 +0.374375 -0.01568603515625 -9.1552734375e-05 -0.9935485839843748 +0.3745 -0.01043701171875 -6.103515625e-05 -0.9935485839843748 +0.374625 -0.01043701171875 -6.103515625e-05 -0.9935485839843748 +0.37475 -0.005218505859375 -3.0517578125e-05 -0.9935485839843748 +0.374875 0.0 0.0 -0.9935485839843748 +0.375 0.0 0.0 -0.9935485839843748 +0.375125 0.005218505859375 3.0517578125e-05 -0.9935485839843748 +0.3752500000000000512 0.005218505859375 3.0517578125e-05 -0.9935485839843748 +0.375375 0.01043701171875 6.103515625e-05 -0.9935485839843748 +0.3755 0.01568603515625 9.1552734375e-05 -0.9935485839843748 +0.375625 0.01568603515625 9.1552734375e-05 -0.9935485839843748 +0.3757500000000000512 0.020904541015625 0.0001220703125 -0.9935485839843748 +0.375875 0.020904541015625 0.0001220703125 -0.9935485839843748 +0.376 0.026123046875 0.000152587890625 -0.9935485839843748 +0.376125 0.0313720703125 0.00018310546875 -0.9935485839843748 +0.3762500000000000512 0.0313720703125 0.00018310546875 -0.9935485839843748 +0.376375 0.036590576171875 0.000213623046875 -0.9935485839843748 +0.3765 0.036590576171875 0.000213623046875 -0.9935485839843748 +0.376625 0.04180908203125 0.000244140625 -0.9935485839843748 +0.3767500000000000512 0.047027587890625 0.000274658203125 -0.9935485839843748 +0.376875 0.047027587890625 0.000274658203125 -0.9935485839843748 +0.377 0.05224609375 0.00030517578125 -0.9935485839843748 +0.377125 0.05224609375 0.00030517578125 -0.9935485839843748 +0.3772500000000000512 0.05743408203125 0.000335693359375 -0.9935485839843748 +0.377375 0.0626220703125 0.000396728515625 -0.9935485839843748 +0.3775 0.0626220703125 0.000396728515625 -0.9935485839843748 +0.377625 0.06781005859375 0.00042724609375 -0.9935485839843748 +0.3777500000000000512 0.06781005859375 0.00042724609375 -0.9935485839843748 +0.377875 0.072998046875 0.000457763671875 -0.9935485839843748 +0.378 0.07818603515625 0.00048828125 -0.9935485839843748 +0.378125 0.07818603515625 0.00048828125 -0.9935485839843748 +0.3782500000000000512 0.083343505859375 0.000518798828125 -0.9935485839843748 +0.378375 0.083343505859375 0.000518798828125 -0.9935485839843748 +0.3785 0.0885009765625 0.00054931640625 -0.9935485839843748 +0.378625 0.093658447265625 0.000579833984375 -0.9935485839843748 +0.3787500000000000512 0.093658447265625 0.000579833984375 -0.9935485839843748 +0.378875 0.098785400390625 0.0006103515625 -0.9935485839843748 +0.379 0.098785400390625 0.0006103515625 -0.9935485839843748 +0.379125 0.103912353515625 0.000640869140625 -0.9935485839843748 +0.3792500000000000512 0.109039306640625 0.00067138671875 -0.9935485839843748 +0.379375 0.109039306640625 0.00067138671875 -0.9935485839843748 +0.3795 0.1141357421875 0.000701904296875 -0.9935485839843748 +0.379625 0.1141357421875 0.000701904296875 -0.9935485839843748 +0.3797500000000000512 0.119232177734375 0.000732421875 -0.9935485839843748 +0.379875 0.124298095703125 0.000762939453125 -0.9935485839843748 +0.38 0.124298095703125 0.000762939453125 -0.9935485839843748 +0.380125 0.129364013671875 0.00079345703125 -0.9935485839843748 +0.3802500000000000512 0.129364013671875 0.00079345703125 -0.9935485839843748 +0.380375 0.134429931640625 0.000823974609375 -0.9935485839843748 +0.3805 0.13946533203125 0.000885009765625 -0.9935485839843748 +0.380625 0.13946533203125 0.000885009765625 -0.9935485839843748 +0.3807500000000000512 0.14447021484375 0.00091552734375 -0.9935485839843748 +0.380875 0.14447021484375 0.00091552734375 -0.9935485839843748 +0.381 0.14947509765625 0.000946044921875 -0.9935485839843748 +0.381125 0.15447998046875 0.0009765625 -0.9935485839843748 +0.3812500000000000512 0.15447998046875 0.0009765625 -0.9935485839843748 +0.381375 0.159454345703125 0.001007080078125 -0.9935485839843748 +0.3815 0.159454345703125 0.001007080078125 -0.9935485839843748 +0.381625 0.164398193359375 0.00103759765625 -0.9935485839843748 +0.3817500000000000512 0.169342041015625 0.001068115234375 -0.9935485839843748 +0.381875 0.169342041015625 0.001068115234375 -0.9935485839843748 +0.382 0.17425537109375 0.0010986328125 -0.9935485839843748 +0.382125 0.17425537109375 0.0010986328125 -0.9935485839843748 +0.3822500000000000512 0.17913818359375 0.001129150390625 -0.9935485839843748 +0.382375 0.18402099609375 0.00115966796875 -0.9935485839843748 +0.3825 0.18402099609375 0.00115966796875 -0.9935485839843748 +0.382625 0.188873291015625 0.001190185546875 -0.9935485839843748 +0.3827500000000000512 0.188873291015625 0.001190185546875 -0.9935485839843748 +0.382875 0.1937255859375 0.001220703125 -0.9935485839843748 +0.383 0.19854736328125 0.001251220703125 -0.9935485839843748 +0.383125 0.19854736328125 0.001251220703125 -0.9935485839843748 +0.3832500000000000512 0.203338623046875 0.00128173828125 -0.9935485839843748 +0.383375 0.203338623046875 0.00128173828125 -0.9935485839843748 +0.3835 0.208099365234375 0.001312255859375 -0.9935485839843748 +0.383625 0.212860107421875 0.0013427734375 -0.9935485839843748 +0.3837500000000000512 0.212860107421875 0.0013427734375 -0.9935485839843748 +0.383875 0.21759033203125 0.001373291015625 -0.9935485839843748 +0.384 0.21759033203125 0.028228759765625 -0.8701477050781241 +0.384125 0.2222900390625 0.028839111328125 -0.8701477050781241 +0.38425 0.226959228515625 0.029449462890625 -0.8701477050781241 +0.384375 0.226959228515625 0.029449462890625 -0.8701477050781241 +0.3845 0.231597900390625 0.030029296875 -0.8701477050781241 +0.384625 0.231597900390625 0.030029296875 -0.8701477050781241 +0.38475 0.236236572265625 0.0306396484375 -0.8701477050781241 +0.384875 0.2408447265625 0.03125 -0.8701477050781241 +0.385 0.2408447265625 0.03125 -0.8701477050781241 +0.385125 0.24542236328125 0.031829833984375 -0.8701477050781241 +0.38525 0.24542236328125 0.031829833984375 -0.8701477050781241 +0.385375 0.249969482421875 0.03240966796875 -0.8701477050781241 +0.3855 0.25445556640625 0.03302001953125 -0.8701477050781241 +0.385625 0.25445556640625 0.03302001953125 -0.8701477050781241 +0.38575 0.25897216796875 0.033599853515625 -0.8701477050781241 +0.385875 0.25897216796875 0.033599853515625 -0.8701477050781241 +0.386 0.263427734375 0.0341796875 -0.8701477050781241 +0.386125 0.267852783203125 0.034759521484375 -0.8701477050781241 +0.38625 0.267852783203125 0.034759521484375 -0.8701477050781241 +0.386375 0.27227783203125 0.035308837890625 -0.8701477050781241 +0.3865 0.27227783203125 0.035308837890625 -0.8701477050781241 +0.386625 0.276641845703125 0.035888671875 -0.8701477050781241 +0.38675 0.280975341796875 0.03643798828125 -0.8701477050781241 +0.386875 0.280975341796875 0.03643798828125 -0.8701477050781241 +0.387 0.285308837890625 0.037017822265625 -0.8701477050781241 +0.387125 0.285308837890625 0.037017822265625 -0.8701477050781241 +0.38725 0.289581298828125 0.037567138671875 -0.8701477050781241 +0.387375 0.2938232421875 0.038116455078125 -0.8701477050781241 +0.3875 0.2938232421875 0.038116455078125 -0.8701477050781241 +0.387625 0.298065185546875 0.038665771484375 -0.8701477050781241 +0.38775 0.298065185546875 0.038665771484375 -0.8701477050781241 +0.387875 0.30224609375 0.039215087890625 -0.8701477050781241 +0.388 0.306396484375 0.03973388671875 -0.8701477050781241 +0.388125 0.306396484375 0.03973388671875 -0.8701477050781241 +0.38825 0.310516357421875 0.040283203125 -0.8701477050781241 +0.388375 0.310516357421875 0.040283203125 -0.8701477050781241 +0.3885 0.314605712890625 0.040802001953125 -0.8701477050781241 +0.388625 0.31866455078125 0.041351318359375 -0.8701477050781241 +0.38875 0.31866455078125 0.041351318359375 -0.8701477050781241 +0.388875 0.322662353515625 0.0418701171875 -0.8701477050781241 +0.389 0.322662353515625 0.0418701171875 -0.8701477050781241 +0.389125 0.32666015625 0.042388916015625 -0.8701477050781241 +0.38925 0.330596923828125 0.042877197265625 -0.8701477050781241 +0.389375 0.330596923828125 0.042877197265625 -0.8701477050781241 +0.3895 0.334503173828125 0.04339599609375 -0.8701477050781241 +0.389625 0.334503173828125 0.04339599609375 -0.8701477050781241 +0.38975 0.33837890625 0.04388427734375 -0.8701477050781241 +0.389875 0.34222412109375 0.044403076171875 -0.8701477050781241 +0.39 0.34222412109375 0.044403076171875 -0.8701477050781241 +0.390125 0.34600830078125 0.044891357421875 -0.8701477050781241 +0.39025 0.34600830078125 0.044891357421875 -0.8701477050781241 +0.390375 0.349761962890625 0.045379638671875 -0.8701477050781241 +0.3905 0.353485107421875 0.045867919921875 -0.8701477050781241 +0.390625 0.353485107421875 0.045867919921875 -0.8701477050781241 +0.39075 0.357177734375 0.04632568359375 -0.8701477050781241 +0.3908750000000000512 0.357177734375 0.04632568359375 -0.8701477050781241 +0.391 0.360809326171875 0.04681396484375 -0.8701477050781241 +0.391125 0.36444091796875 0.047271728515625 -0.8701477050781241 +0.39125 0.36444091796875 0.047271728515625 -0.8701477050781241 +0.3913750000000000512 0.36798095703125 0.0477294921875 -0.8701477050781241 +0.3915 0.36798095703125 0.0477294921875 -0.8701477050781241 +0.391625 0.37152099609375 0.048187255859375 -0.8701477050781241 +0.39175 0.375 0.04864501953125 -0.8701477050781241 +0.3918750000000000512 0.375 0.04864501953125 -0.8701477050781241 +0.392 0.378448486328125 0.049102783203125 -0.8701477050781241 +0.392125 0.378448486328125 0.049102783203125 -0.8701477050781241 +0.39225 0.3818359375 0.049530029296875 -0.8701477050781241 +0.3923750000000000512 0.38519287109375 0.04998779296875 -0.8701477050781241 +0.3925 0.38519287109375 0.04998779296875 -0.8701477050781241 +0.392625 0.388519287109375 0.0504150390625 -0.8701477050781241 +0.39275 0.388519287109375 0.0504150390625 -0.8701477050781241 +0.3928750000000000512 0.39178466796875 0.05084228515625 -0.8701477050781241 +0.393 0.39501953125 0.051239013671875 -0.8701477050781241 +0.393125 0.39501953125 0.051239013671875 -0.8701477050781241 +0.39325 0.398193359375 0.051666259765625 -0.8701477050781241 +0.3933750000000000512 0.398193359375 0.051666259765625 -0.8701477050781241 +0.3935 0.401336669921875 0.05206298828125 -0.8701477050781241 +0.393625 0.404449462890625 0.052459716796875 -0.8701477050781241 +0.39375 0.404449462890625 0.052459716796875 -0.8701477050781241 +0.3938750000000000512 0.407501220703125 0.0528564453125 -0.8701477050781241 +0.394 0.407501220703125 0.0528564453125 -0.8701477050781241 +0.394125 0.4105224609375 0.053253173828125 -0.8701477050781241 +0.39425 0.413482666015625 0.05364990234375 -0.8701477050781241 +0.3943750000000000512 0.413482666015625 0.05364990234375 -0.8701477050781241 +0.3945 0.416412353515625 0.05401611328125 -0.8701477050781241 +0.394625 0.416412353515625 0.05401611328125 -0.8701477050781241 +0.39475 0.419281005859375 0.05438232421875 -0.8701477050781241 +0.3948750000000000512 0.422119140625 0.05474853515625 -0.8701477050781241 +0.395 0.422119140625 0.05474853515625 -0.8701477050781241 +0.395125 0.424896240234375 0.05511474609375 -0.8701477050781241 +0.39525 0.424896240234375 0.05511474609375 -0.8701477050781241 +0.3953750000000000512 0.4276123046875 0.05548095703125 -0.8701477050781241 +0.3955 0.4302978515625 0.055816650390625 -0.8701477050781241 +0.395625 0.4302978515625 0.055816650390625 -0.8701477050781241 +0.39575 0.432952880859375 0.056182861328125 -0.8701477050781241 +0.3958750000000000512 0.432952880859375 0.056182861328125 -0.8701477050781241 +0.396 0.435546875 0.0565185546875 -0.8701477050781241 +0.396125 0.438079833984375 0.05682373046875 -0.8701477050781241 +0.39625 0.438079833984375 0.05682373046875 -0.8701477050781241 +0.3963750000000000512 0.440582275390625 0.057159423828125 -0.8701477050781241 +0.3965 0.440582275390625 0.057159423828125 -0.8701477050781241 +0.396625 0.44305419921875 0.057464599609375 -0.8701477050781241 +0.39675 0.4454345703125 0.05780029296875 -0.8701477050781241 +0.3968750000000000512 0.4454345703125 0.05780029296875 -0.8701477050781241 +0.397 0.447784423828125 0.05810546875 -0.8701477050781241 +0.397125 0.447784423828125 0.05810546875 -0.8701477050781241 +0.39725 0.450103759765625 0.058380126953125 -0.8701477050781241 +0.3973750000000000512 0.452362060546875 0.058685302734375 -0.8701477050781241 +0.3975 0.452362060546875 0.058685302734375 -0.8701477050781241 +0.397625 0.454559326171875 0.0589599609375 -0.8701477050781241 +0.39775 0.454559326171875 0.0589599609375 -0.8701477050781241 +0.3978750000000000512 0.45672607421875 0.05926513671875 -0.8701477050781241 +0.398 0.458831787109375 0.059539794921875 -0.8701477050781241 +0.398125 0.458831787109375 0.059539794921875 -0.8701477050781241 +0.39825 0.46087646484375 0.059783935546875 -0.8701477050781241 +0.3983750000000000512 0.46087646484375 0.059783935546875 -0.8701477050781241 +0.3985 0.462890625 0.06005859375 -0.8701477050781241 +0.398625 0.464813232421875 0.060302734375 -0.8701477050781241 +0.39875 0.464813232421875 0.060302734375 -0.8701477050781241 +0.3988750000000000512 0.46673583984375 0.060546875 -0.8701477050781241 +0.399 0.46673583984375 0.060546875 -0.8701477050781241 +0.399125 0.46856689453125 0.060791015625 -0.8701477050781241 +0.39925 0.470367431640625 0.06103515625 -0.8701477050781241 +0.3993750000000000512 0.470367431640625 0.06103515625 -0.8701477050781241 +0.3995 0.472137451171875 0.061248779296875 -0.8701477050781241 +0.399625 0.472137451171875 0.061248779296875 -0.8701477050781241 +0.39975 0.47381591796875 0.06146240234375 -0.8701477050781241 +0.3998750000000000512 0.4754638671875 0.061676025390625 -0.8701477050781241 +0.4 0.4754638671875 0.061676025390625 -0.8701477050781241 +0.400125 0.47705078125 0.0618896484375 -0.8701477050781241 +0.40025 0.47705078125 0.0618896484375 -0.8701477050781241 +0.400375 0.478607177734375 0.062103271484375 -0.8701477050781241 +0.4005 0.480072021484375 0.062286376953125 -0.8701477050781241 +0.400625 0.480072021484375 0.062286376953125 -0.8701477050781241 +0.40075 0.48150634765625 0.062469482421875 -0.8701477050781241 +0.400875 0.48150634765625 0.062469482421875 -0.8701477050781241 +0.401 0.48291015625 0.062652587890625 -0.8701477050781241 +0.401125 0.484222412109375 0.062835693359375 -0.8701477050781241 +0.40125 0.484222412109375 0.062835693359375 -0.8701477050781241 +0.401375 0.485504150390625 0.06298828125 -0.8701477050781241 +0.4015 0.485504150390625 0.06298828125 -0.8701477050781241 +0.401625 0.486724853515625 0.063140869140625 -0.8701477050781241 +0.40175 0.487884521484375 0.06329345703125 -0.8701477050781241 +0.401875 0.487884521484375 0.06329345703125 -0.8701477050781241 +0.402 0.489013671875 0.063446044921875 -0.8701477050781241 +0.402125 0.489013671875 0.063446044921875 -0.8701477050781241 +0.40225 0.490081787109375 0.063568115234375 -0.8701477050781241 +0.402375 0.4910888671875 0.063720703125 -0.8701477050781241 +0.4025 0.4910888671875 0.063720703125 -0.8701477050781241 +0.402625 0.492034912109375 0.0638427734375 -0.8701477050781241 +0.40275 0.492034912109375 0.0638427734375 -0.8701477050781241 +0.402875 0.492950439453125 0.06396484375 -0.8701477050781241 +0.403 0.4937744140625 0.064056396484375 -0.8701477050781241 +0.403125 0.4937744140625 0.064056396484375 -0.8701477050781241 +0.40325 0.49456787109375 0.064178466796875 -0.8701477050781241 +0.403375 0.49456787109375 0.064178466796875 -0.8701477050781241 +0.4035 0.49530029296875 0.06427001953125 -0.8701477050781241 +0.403625 0.496002197265625 0.064361572265625 -0.8701477050781241 +0.40375 0.496002197265625 0.064361572265625 -0.8701477050781241 +0.403875 0.496612548828125 0.064422607421875 -0.8701477050781241 +0.404 0.496612548828125 0.064422607421875 -0.8701477050781241 +0.404125 0.4971923828125 0.06451416015625 -0.8701477050781241 +0.40425 0.497711181640625 0.0645751953125 -0.8701477050781241 +0.404375 0.497711181640625 0.0645751953125 -0.8701477050781241 +0.4045 0.498199462890625 0.06463623046875 -0.8701477050781241 +0.404625 0.498199462890625 0.06463623046875 -0.8701477050781241 +0.40475 0.49859619140625 0.064697265625 -0.8701477050781241 +0.404875 0.49896240234375 0.064727783203125 -0.8701477050781241 +0.405 0.49896240234375 0.064727783203125 -0.8701477050781241 +0.405125 0.499267578125 0.064788818359375 -0.8701477050781241 +0.40525 0.499267578125 0.064788818359375 -0.8701477050781241 +0.405375 0.49951171875 0.0648193359375 -0.8701477050781241 +0.4055 0.49969482421875 0.0648193359375 -0.8701477050781241 +0.405625 0.49969482421875 0.0648193359375 -0.8701477050781241 +0.40575 0.49981689453125 0.064849853515625 -0.8701477050781241 +0.405875 0.49981689453125 0.064849853515625 -0.8701477050781241 +0.406 0.499908447265625 0.064849853515625 -0.8701477050781241 +0.406125 0.49993896484375 0.064849853515625 -0.8701477050781241 +0.40625 0.49993896484375 0.064849853515625 -0.8701477050781241 +0.406375 0.499908447265625 0.064849853515625 -0.8701477050781241 +0.4065000000000000512 0.499908447265625 0.064849853515625 -0.8701477050781241 +0.406625 0.49981689453125 0.064849853515625 -0.8701477050781241 +0.40675 0.49969482421875 0.0648193359375 -0.8701477050781241 +0.406875 0.49969482421875 0.0648193359375 -0.8701477050781241 +0.4070000000000000512 0.49951171875 0.0648193359375 -0.8701477050781241 +0.407125 0.49951171875 0.0648193359375 -0.8701477050781241 +0.40725 0.499267578125 0.064788818359375 -0.8701477050781241 +0.407375 0.49896240234375 0.064727783203125 -0.8701477050781241 +0.4075000000000000512 0.49896240234375 0.064727783203125 -0.8701477050781241 +0.407625 0.49859619140625 0.064697265625 -0.8701477050781241 +0.40775 0.49859619140625 0.064697265625 -0.8701477050781241 +0.407875 0.498199462890625 0.06463623046875 -0.8701477050781241 +0.4080000000000000512 0.497711181640625 0.0645751953125 -0.8701477050781241 +0.408125 0.497711181640625 0.0645751953125 -0.8701477050781241 +0.40825 0.4971923828125 0.06451416015625 -0.8701477050781241 +0.408375 0.4971923828125 0.06451416015625 -0.8701477050781241 +0.4085000000000000512 0.496612548828125 0.064422607421875 -0.8701477050781241 +0.408625 0.496002197265625 0.064361572265625 -0.8701477050781241 +0.40875 0.496002197265625 0.064361572265625 -0.8701477050781241 +0.408875 0.49530029296875 0.06427001953125 -0.8701477050781241 +0.4090000000000000512 0.49530029296875 0.06427001953125 -0.8701477050781241 +0.409125 0.49456787109375 0.064178466796875 -0.8701477050781241 +0.40925 0.4937744140625 0.064056396484375 -0.8701477050781241 +0.409375 0.4937744140625 0.064056396484375 -0.8701477050781241 +0.4095000000000000512 0.492950439453125 0.06396484375 -0.8701477050781241 +0.409625 0.492950439453125 0.06396484375 -0.8701477050781241 +0.40975 0.492034912109375 0.0638427734375 -0.8701477050781241 +0.409875 0.4910888671875 0.063720703125 -0.8701477050781241 +0.4100000000000000512 0.4910888671875 0.063720703125 -0.8701477050781241 +0.410125 0.490081787109375 0.063568115234375 -0.8701477050781241 +0.41025 0.490081787109375 0.063568115234375 -0.8701477050781241 +0.410375 0.489013671875 0.063446044921875 -0.8701477050781241 +0.4105000000000000512 0.487884521484375 0.06329345703125 -0.8701477050781241 +0.410625 0.487884521484375 0.06329345703125 -0.8701477050781241 +0.41075 0.486724853515625 0.063140869140625 -0.8701477050781241 +0.410875 0.486724853515625 0.063140869140625 -0.8701477050781241 +0.4110000000000000512 0.485504150390625 0.06298828125 -0.8701477050781241 +0.411125 0.484222412109375 0.062835693359375 -0.8701477050781241 +0.41125 0.484222412109375 0.062835693359375 -0.8701477050781241 +0.411375 0.48291015625 0.062652587890625 -0.8701477050781241 +0.4115000000000000512 0.48291015625 0.062652587890625 -0.8701477050781241 +0.411625 0.48150634765625 0.062469482421875 -0.8701477050781241 +0.41175 0.480072021484375 0.062286376953125 -0.8701477050781241 +0.411875 0.480072021484375 0.062286376953125 -0.8701477050781241 +0.4120000000000000512 0.478607177734375 0.062103271484375 -0.8701477050781241 +0.412125 0.478607177734375 0.062103271484375 -0.8701477050781241 +0.41225 0.47705078125 0.0618896484375 -0.8701477050781241 +0.412375 0.4754638671875 0.061676025390625 -0.8701477050781241 +0.4125000000000000512 0.4754638671875 0.061676025390625 -0.8701477050781241 +0.412625 0.47381591796875 0.06146240234375 -0.8701477050781241 +0.41275 0.47381591796875 0.06146240234375 -0.8701477050781241 +0.412875 0.472137451171875 0.061248779296875 -0.8701477050781241 +0.4130000000000000512 0.470367431640625 0.06103515625 -0.8701477050781241 +0.413125 0.470367431640625 0.06103515625 -0.8701477050781241 +0.41325 0.46856689453125 0.060791015625 -0.8701477050781241 +0.413375 0.46856689453125 0.060791015625 -0.8701477050781241 +0.4135000000000000512 0.46673583984375 0.060546875 -0.8701477050781241 +0.413625 0.464813232421875 0.060302734375 -0.8701477050781241 +0.41375 0.464813232421875 0.060302734375 -0.8701477050781241 +0.413875 0.462890625 0.06005859375 -0.8701477050781241 +0.4140000000000000512 0.462890625 0.06005859375 -0.8701477050781241 +0.414125 0.46087646484375 0.059783935546875 -0.8701477050781241 +0.41425 0.458831787109375 0.059539794921875 -0.8701477050781241 +0.414375 0.458831787109375 0.059539794921875 -0.8701477050781241 +0.4145000000000000512 0.45672607421875 0.05926513671875 -0.8701477050781241 +0.414625 0.45672607421875 0.05926513671875 -0.8701477050781241 +0.41475 0.454559326171875 0.0589599609375 -0.8701477050781241 +0.414875 0.452362060546875 0.058685302734375 -0.8701477050781241 +0.4150000000000000512 0.452362060546875 0.058685302734375 -0.8701477050781241 +0.415125 0.450103759765625 0.058380126953125 -0.8701477050781241 +0.41525 0.450103759765625 0.058380126953125 -0.8701477050781241 +0.415375 0.447784423828125 0.05810546875 -0.8701477050781241 +0.4155000000000000512 0.4454345703125 0.05780029296875 -0.8701477050781241 +0.415625 0.4454345703125 0.05780029296875 -0.8701477050781241 +0.41575 0.44305419921875 0.057464599609375 -0.8701477050781241 +0.415875 0.44305419921875 0.057464599609375 -0.8701477050781241 +0.416000000000000036 0.440582275390625 0.1727294921875 -0.6078857421874979 +0.416125 0.438079833984375 0.1717529296875 -0.6078857421874979 +0.41625 0.438079833984375 0.1717529296875 -0.6078857421874979 +0.416375 0.435546875 0.170745849609375 -0.6078857421874979 +0.4165 0.435546875 0.170745849609375 -0.6078857421874979 +0.416625 0.432952880859375 0.16973876953125 -0.6078857421874979 +0.41675 0.4302978515625 0.168701171875 -0.6078857421874979 +0.416875 0.4302978515625 0.168701171875 -0.6078857421874979 +0.417 0.4276123046875 0.167633056640625 -0.6078857421874979 +0.417125 0.4276123046875 0.167633056640625 -0.6078857421874979 +0.41725 0.424896240234375 0.16656494140625 -0.6078857421874979 +0.417375 0.422119140625 0.16546630859375 -0.6078857421874979 +0.4175 0.422119140625 0.16546630859375 -0.6078857421874979 +0.417625 0.419281005859375 0.16436767578125 -0.6078857421874979 +0.41775 0.419281005859375 0.16436767578125 -0.6078857421874979 +0.417875 0.416412353515625 0.163238525390625 -0.6078857421874979 +0.418 0.413482666015625 0.162078857421875 -0.6078857421874979 +0.418125 0.413482666015625 0.162078857421875 -0.6078857421874979 +0.41825 0.4105224609375 0.160919189453125 -0.6078857421874979 +0.418375 0.4105224609375 0.160919189453125 -0.6078857421874979 +0.4185 0.407501220703125 0.159759521484375 -0.6078857421874979 +0.418625 0.404449462890625 0.1585693359375 -0.6078857421874979 +0.41875 0.404449462890625 0.1585693359375 -0.6078857421874979 +0.418875 0.401336669921875 0.1573486328125 -0.6078857421874979 +0.419 0.401336669921875 0.1573486328125 -0.6078857421874979 +0.419125 0.398193359375 0.156097412109375 -0.6078857421874979 +0.41925 0.39501953125 0.154876708984375 -0.6078857421874979 +0.419375 0.39501953125 0.154876708984375 -0.6078857421874979 +0.4195 0.39178466796875 0.153594970703125 -0.6078857421874979 +0.419625 0.39178466796875 0.153594970703125 -0.6078857421874979 +0.41975 0.388519287109375 0.152313232421875 -0.6078857421874979 +0.419875 0.38519287109375 0.1510009765625 -0.6078857421874979 +0.42 0.38519287109375 0.1510009765625 -0.6078857421874979 +0.420125 0.3818359375 0.149688720703125 -0.6078857421874979 +0.42025 0.3818359375 0.149688720703125 -0.6078857421874979 +0.420375 0.378448486328125 0.148345947265625 -0.6078857421874979 +0.4205 0.375 0.147003173828125 -0.6078857421874979 +0.420625 0.375 0.147003173828125 -0.6078857421874979 +0.42075 0.37152099609375 0.1456298828125 -0.6078857421874979 +0.420875 0.37152099609375 0.1456298828125 -0.6078857421874979 +0.421 0.36798095703125 0.144256591796875 -0.6078857421874979 +0.421125 0.36444091796875 0.14288330078125 -0.6078857421874979 +0.42125 0.36444091796875 0.14288330078125 -0.6078857421874979 +0.421375 0.360809326171875 0.141448974609375 -0.6078857421874979 +0.4215 0.360809326171875 0.141448974609375 -0.6078857421874979 +0.421625 0.357177734375 0.1400146484375 -0.6078857421874979 +0.42175 0.353485107421875 0.138580322265625 -0.6078857421874979 +0.421875 0.353485107421875 0.138580322265625 -0.6078857421874979 +0.422 0.349761962890625 0.137115478515625 -0.6078857421874979 +0.4221250000000000512 0.349761962890625 0.137115478515625 -0.6078857421874979 +0.42225 0.34600830078125 0.135650634765625 -0.6078857421874979 +0.422375 0.34222412109375 0.1341552734375 -0.6078857421874979 +0.4225 0.34222412109375 0.1341552734375 -0.6078857421874979 +0.4226250000000000512 0.33837890625 0.132659912109375 -0.6078857421874979 +0.42275 0.33837890625 0.132659912109375 -0.6078857421874979 +0.422875 0.334503173828125 0.131134033203125 -0.6078857421874979 +0.423 0.330596923828125 0.129608154296875 -0.6078857421874979 +0.4231250000000000512 0.330596923828125 0.129608154296875 -0.6078857421874979 +0.42325 0.32666015625 0.1280517578125 -0.6078857421874979 +0.423375 0.32666015625 0.1280517578125 -0.6078857421874979 +0.4235 0.322662353515625 0.126495361328125 -0.6078857421874979 +0.4236250000000000512 0.31866455078125 0.124908447265625 -0.6078857421874979 +0.42375 0.31866455078125 0.124908447265625 -0.6078857421874979 +0.423875 0.314605712890625 0.123321533203125 -0.6078857421874979 +0.424 0.314605712890625 0.123321533203125 -0.6078857421874979 +0.4241250000000000512 0.310516357421875 0.121734619140625 -0.6078857421874979 +0.42425 0.306396484375 0.1201171875 -0.6078857421874979 +0.424375 0.306396484375 0.1201171875 -0.6078857421874979 +0.4245 0.30224609375 0.118499755859375 -0.6078857421874979 +0.4246250000000000512 0.30224609375 0.118499755859375 -0.6078857421874979 +0.42475 0.298065185546875 0.116851806640625 -0.6078857421874979 +0.424875 0.2938232421875 0.115203857421875 -0.6078857421874979 +0.425 0.2938232421875 0.115203857421875 -0.6078857421874979 +0.4251250000000000512 0.289581298828125 0.113525390625 -0.6078857421874979 +0.42525 0.289581298828125 0.113525390625 -0.6078857421874979 +0.425375 0.285308837890625 0.111846923828125 -0.6078857421874979 +0.4255 0.280975341796875 0.110137939453125 -0.6078857421874979 +0.4256250000000000512 0.280975341796875 0.110137939453125 -0.6078857421874979 +0.42575 0.276641845703125 0.10845947265625 -0.6078857421874979 +0.425875 0.276641845703125 0.10845947265625 -0.6078857421874979 +0.426 0.27227783203125 0.10675048828125 -0.6078857421874979 +0.4261250000000000512 0.267852783203125 0.105010986328125 -0.6078857421874979 +0.42625 0.267852783203125 0.105010986328125 -0.6078857421874979 +0.426375 0.263427734375 0.103271484375 -0.6078857421874979 +0.4265 0.263427734375 0.103271484375 -0.6078857421874979 +0.4266250000000000512 0.25897216796875 0.101531982421875 -0.6078857421874979 +0.42675 0.25445556640625 0.099761962890625 -0.6078857421874979 +0.426875 0.25445556640625 0.099761962890625 -0.6078857421874979 +0.427 0.249969482421875 0.097991943359375 -0.6078857421874979 +0.4271250000000000512 0.249969482421875 0.097991943359375 -0.6078857421874979 +0.42725 0.24542236328125 0.09619140625 -0.6078857421874979 +0.427375 0.2408447265625 0.09442138671875 -0.6078857421874979 +0.4275 0.2408447265625 0.09442138671875 -0.6078857421874979 +0.4276250000000000512 0.236236572265625 0.092620849609375 -0.6078857421874979 +0.42775 0.236236572265625 0.092620849609375 -0.6078857421874979 +0.427875 0.231597900390625 0.090789794921875 -0.6078857421874979 +0.428 0.226959228515625 0.088958740234375 -0.6078857421874979 +0.4281250000000000512 0.226959228515625 0.088958740234375 -0.6078857421874979 +0.42825 0.2222900390625 0.087127685546875 -0.6078857421874979 +0.428375 0.2222900390625 0.087127685546875 -0.6078857421874979 +0.4285 0.21759033203125 0.085296630859375 -0.6078857421874979 +0.4286250000000000512 0.212860107421875 0.08343505859375 -0.6078857421874979 +0.42875 0.212860107421875 0.08343505859375 -0.6078857421874979 +0.428875 0.208099365234375 0.081573486328125 -0.6078857421874979 +0.429 0.208099365234375 0.081573486328125 -0.6078857421874979 +0.4291250000000000512 0.203338623046875 0.0797119140625 -0.6078857421874979 +0.42925 0.19854736328125 0.07781982421875 -0.6078857421874979 +0.429375 0.19854736328125 0.07781982421875 -0.6078857421874979 +0.4295 0.1937255859375 0.075927734375 -0.6078857421874979 +0.4296250000000000512 0.1937255859375 0.075927734375 -0.6078857421874979 +0.42975 0.188873291015625 0.07403564453125 -0.6078857421874979 +0.429875 0.18402099609375 0.0721435546875 -0.6078857421874979 +0.43 0.18402099609375 0.0721435546875 -0.6078857421874979 +0.4301250000000000512 0.17913818359375 0.070220947265625 -0.6078857421874979 +0.43025 0.17913818359375 0.070220947265625 -0.6078857421874979 +0.430375 0.17425537109375 0.06829833984375 -0.6078857421874979 +0.4305 0.169342041015625 0.066375732421875 -0.6078857421874979 +0.4306250000000000512 0.169342041015625 0.066375732421875 -0.6078857421874979 +0.43075 0.164398193359375 0.064453125 -0.6078857421874979 +0.430875 0.164398193359375 0.064453125 -0.6078857421874979 +0.431 0.159454345703125 0.0625 -0.6078857421874979 +0.4311250000000000512 0.15447998046875 0.060546875 -0.6078857421874979 +0.43125 0.15447998046875 0.060546875 -0.6078857421874979 +0.431375 0.14947509765625 0.05859375 -0.6078857421874979 +0.4315 0.14947509765625 0.05859375 -0.6078857421874979 +0.431625000000000036 0.14447021484375 0.056640625 -0.6078857421874979 +0.43175 0.13946533203125 0.054656982421875 -0.6078857421874979 +0.431875 0.13946533203125 0.054656982421875 -0.6078857421874979 +0.432 0.134429931640625 0.052703857421875 -0.6078857421874979 +0.432125 0.134429931640625 0.052703857421875 -0.6078857421874979 +0.43225 0.129364013671875 0.05072021484375 -0.6078857421874979 +0.432375 0.124298095703125 0.048736572265625 -0.6078857421874979 +0.4325 0.124298095703125 0.048736572265625 -0.6078857421874979 +0.432625 0.119232177734375 0.0467529296875 -0.6078857421874979 +0.43275 0.119232177734375 0.0467529296875 -0.6078857421874979 +0.432875 0.1141357421875 0.04473876953125 -0.6078857421874979 +0.433 0.109039306640625 0.042724609375 -0.6078857421874979 +0.433125 0.109039306640625 0.042724609375 -0.6078857421874979 +0.43325 0.103912353515625 0.040740966796875 -0.6078857421874979 +0.433375 0.103912353515625 0.040740966796875 -0.6078857421874979 +0.4335 0.098785400390625 0.038726806640625 -0.6078857421874979 +0.433625 0.093658447265625 0.036712646484375 -0.6078857421874979 +0.43375 0.093658447265625 0.036712646484375 -0.6078857421874979 +0.433875 0.0885009765625 0.034698486328125 -0.6078857421874979 +0.434 0.0885009765625 0.034698486328125 -0.6078857421874979 +0.434125 0.083343505859375 0.032684326171875 -0.6078857421874979 +0.43425 0.07818603515625 0.0306396484375 -0.6078857421874979 +0.434375 0.07818603515625 0.0306396484375 -0.6078857421874979 +0.4345 0.072998046875 0.02862548828125 -0.6078857421874979 +0.434625 0.072998046875 0.02862548828125 -0.6078857421874979 +0.43475 0.06781005859375 0.026580810546875 -0.6078857421874979 +0.434875 0.0626220703125 0.0245361328125 -0.6078857421874979 +0.435 0.0626220703125 0.0245361328125 -0.6078857421874979 +0.435125 0.05743408203125 0.02252197265625 -0.6078857421874979 +0.43525 0.05743408203125 0.02252197265625 -0.6078857421874979 +0.435375 0.05224609375 0.020477294921875 -0.6078857421874979 +0.4355 0.047027587890625 0.0184326171875 -0.6078857421874979 +0.435625 0.047027587890625 0.0184326171875 -0.6078857421874979 +0.43575 0.04180908203125 0.016387939453125 -0.6078857421874979 +0.435875 0.04180908203125 0.016387939453125 -0.6078857421874979 +0.436 0.036590576171875 0.01434326171875 -0.6078857421874979 +0.436125 0.0313720703125 0.012298583984375 -0.6078857421874979 +0.43625 0.0313720703125 0.012298583984375 -0.6078857421874979 +0.436375 0.026123046875 0.010223388671875 -0.6078857421874979 +0.4365 0.026123046875 0.010223388671875 -0.6078857421874979 +0.436625 0.020904541015625 0.0081787109375 -0.6078857421874979 +0.43675 0.01568603515625 0.006134033203125 -0.6078857421874979 +0.436875 0.01568603515625 0.006134033203125 -0.6078857421874979 +0.437 0.01043701171875 0.00408935546875 -0.6078857421874979 +0.437125 0.01043701171875 0.00408935546875 -0.6078857421874979 +0.43725 0.005218505859375 0.002044677734375 -0.6078857421874979 +0.437375 0.0 0.0 -0.6078857421874979 +0.4375 0.0 0.0 -0.6078857421874979 +0.437625 -0.005218505859375 -0.002044677734375 -0.6078857421874979 +0.4377500000000000512 -0.005218505859375 -0.002044677734375 -0.6078857421874979 +0.437875 -0.01043701171875 -0.00408935546875 -0.6078857421874979 +0.438 -0.01568603515625 -0.006134033203125 -0.6078857421874979 +0.438125 -0.01568603515625 -0.006134033203125 -0.6078857421874979 +0.4382500000000000512 -0.020904541015625 -0.0081787109375 -0.6078857421874979 +0.438375 -0.020904541015625 -0.0081787109375 -0.6078857421874979 +0.4385 -0.026123046875 -0.010223388671875 -0.6078857421874979 +0.438625 -0.0313720703125 -0.012298583984375 -0.6078857421874979 +0.4387500000000000512 -0.0313720703125 -0.012298583984375 -0.6078857421874979 +0.438875 -0.036590576171875 -0.01434326171875 -0.6078857421874979 +0.439 -0.036590576171875 -0.01434326171875 -0.6078857421874979 +0.439125 -0.04180908203125 -0.016387939453125 -0.6078857421874979 +0.4392500000000000512 -0.047027587890625 -0.0184326171875 -0.6078857421874979 +0.439375 -0.047027587890625 -0.0184326171875 -0.6078857421874979 +0.4395 -0.05224609375 -0.020477294921875 -0.6078857421874979 +0.439625 -0.05224609375 -0.020477294921875 -0.6078857421874979 +0.4397500000000000512 -0.05743408203125 -0.02252197265625 -0.6078857421874979 +0.439875 -0.0626220703125 -0.0245361328125 -0.6078857421874979 +0.44 -0.0626220703125 -0.0245361328125 -0.6078857421874979 +0.440125 -0.06781005859375 -0.026580810546875 -0.6078857421874979 +0.4402500000000000512 -0.06781005859375 -0.026580810546875 -0.6078857421874979 +0.440375 -0.072998046875 -0.02862548828125 -0.6078857421874979 +0.4405 -0.07818603515625 -0.0306396484375 -0.6078857421874979 +0.440625 -0.07818603515625 -0.0306396484375 -0.6078857421874979 +0.4407500000000000512 -0.083343505859375 -0.032684326171875 -0.6078857421874979 +0.440875 -0.083343505859375 -0.032684326171875 -0.6078857421874979 +0.441 -0.0885009765625 -0.034698486328125 -0.6078857421874979 +0.441125 -0.093658447265625 -0.036712646484375 -0.6078857421874979 +0.4412500000000000512 -0.093658447265625 -0.036712646484375 -0.6078857421874979 +0.441375 -0.098785400390625 -0.038726806640625 -0.6078857421874979 +0.4415 -0.098785400390625 -0.038726806640625 -0.6078857421874979 +0.441625 -0.103912353515625 -0.040740966796875 -0.6078857421874979 +0.4417500000000000512 -0.109039306640625 -0.042724609375 -0.6078857421874979 +0.441875 -0.109039306640625 -0.042724609375 -0.6078857421874979 +0.442 -0.1141357421875 -0.04473876953125 -0.6078857421874979 +0.442125 -0.1141357421875 -0.04473876953125 -0.6078857421874979 +0.4422500000000000512 -0.119232177734375 -0.0467529296875 -0.6078857421874979 +0.442375 -0.124298095703125 -0.048736572265625 -0.6078857421874979 +0.4425 -0.124298095703125 -0.048736572265625 -0.6078857421874979 +0.442625 -0.129364013671875 -0.05072021484375 -0.6078857421874979 +0.4427500000000000512 -0.129364013671875 -0.05072021484375 -0.6078857421874979 +0.442875 -0.134429931640625 -0.052703857421875 -0.6078857421874979 +0.443 -0.13946533203125 -0.054656982421875 -0.6078857421874979 +0.443125 -0.13946533203125 -0.054656982421875 -0.6078857421874979 +0.4432500000000000512 -0.14447021484375 -0.056640625 -0.6078857421874979 +0.443375 -0.14447021484375 -0.056640625 -0.6078857421874979 +0.4435 -0.14947509765625 -0.05859375 -0.6078857421874979 +0.443625 -0.15447998046875 -0.060546875 -0.6078857421874979 +0.4437500000000000512 -0.15447998046875 -0.060546875 -0.6078857421874979 +0.443875 -0.159454345703125 -0.0625 -0.6078857421874979 +0.444 -0.159454345703125 -0.0625 -0.6078857421874979 +0.444125 -0.164398193359375 -0.064453125 -0.6078857421874979 +0.4442500000000000512 -0.169342041015625 -0.066375732421875 -0.6078857421874979 +0.444375 -0.169342041015625 -0.066375732421875 -0.6078857421874979 +0.4445 -0.17425537109375 -0.06829833984375 -0.6078857421874979 +0.444625 -0.17425537109375 -0.06829833984375 -0.6078857421874979 +0.4447500000000000512 -0.17913818359375 -0.070220947265625 -0.6078857421874979 +0.444875 -0.18402099609375 -0.0721435546875 -0.6078857421874979 +0.445 -0.18402099609375 -0.0721435546875 -0.6078857421874979 +0.445125 -0.188873291015625 -0.07403564453125 -0.6078857421874979 +0.4452500000000000512 -0.188873291015625 -0.07403564453125 -0.6078857421874979 +0.445375 -0.1937255859375 -0.075927734375 -0.6078857421874979 +0.4455 -0.19854736328125 -0.07781982421875 -0.6078857421874979 +0.445625 -0.19854736328125 -0.07781982421875 -0.6078857421874979 +0.4457500000000000512 -0.203338623046875 -0.0797119140625 -0.6078857421874979 +0.445875 -0.203338623046875 -0.0797119140625 -0.6078857421874979 +0.446 -0.208099365234375 -0.081573486328125 -0.6078857421874979 +0.446125 -0.212860107421875 -0.08343505859375 -0.6078857421874979 +0.4462500000000000512 -0.212860107421875 -0.08343505859375 -0.6078857421874979 +0.446375 -0.21759033203125 -0.085296630859375 -0.6078857421874979 +0.4465 -0.21759033203125 -0.085296630859375 -0.6078857421874979 +0.446625 -0.2222900390625 -0.087127685546875 -0.6078857421874979 +0.4467500000000000512 -0.226959228515625 -0.088958740234375 -0.6078857421874979 +0.446875 -0.226959228515625 -0.088958740234375 -0.6078857421874979 +0.447 -0.231597900390625 -0.090789794921875 -0.6078857421874979 +0.447125 -0.231597900390625 -0.090789794921875 -0.6078857421874979 +0.447250000000000036 -0.236236572265625 -0.092620849609375 -0.6078857421874979 +0.447375 -0.2408447265625 -0.09442138671875 -0.6078857421874979 +0.4475 -0.2408447265625 -0.09442138671875 -0.6078857421874979 +0.447625 -0.24542236328125 -0.09619140625 -0.6078857421874979 +0.447750000000000036 -0.24542236328125 -0.09619140625 -0.6078857421874979 +0.447875 -0.249969482421875 -0.097991943359375 -0.6078857421874979 +0.448 -0.25445556640625 -0.191192626953125 -0.2486572265624977 +0.448125 -0.25445556640625 -0.191192626953125 -0.2486572265624977 +0.44825 -0.25897216796875 -0.194549560546875 -0.2486572265624977 +0.448375 -0.25897216796875 -0.194549560546875 -0.2486572265624977 +0.4485 -0.263427734375 -0.197906494140625 -0.2486572265624977 +0.448625 -0.267852783203125 -0.20123291015625 -0.2486572265624977 +0.44875 -0.267852783203125 -0.20123291015625 -0.2486572265624977 +0.448875 -0.27227783203125 -0.204559326171875 -0.2486572265624977 +0.449 -0.27227783203125 -0.204559326171875 -0.2486572265624977 +0.449125 -0.276641845703125 -0.20782470703125 -0.2486572265624977 +0.44925 -0.280975341796875 -0.211090087890625 -0.2486572265624977 +0.449375 -0.280975341796875 -0.211090087890625 -0.2486572265624977 +0.4495 -0.285308837890625 -0.21435546875 -0.2486572265624977 +0.449625 -0.285308837890625 -0.21435546875 -0.2486572265624977 +0.44975 -0.289581298828125 -0.217559814453125 -0.2486572265624977 +0.449875 -0.2938232421875 -0.22076416015625 -0.2486572265624977 +0.45 -0.2938232421875 -0.22076416015625 -0.2486572265624977 +0.450125 -0.298065185546875 -0.22393798828125 -0.2486572265624977 +0.45025 -0.298065185546875 -0.22393798828125 -0.2486572265624977 +0.450375 -0.30224609375 -0.227081298828125 -0.2486572265624977 +0.4505 -0.306396484375 -0.230194091796875 -0.2486572265624977 +0.450625 -0.306396484375 -0.230194091796875 -0.2486572265624977 +0.45075 -0.310516357421875 -0.233306884765625 -0.2486572265624977 +0.450875 -0.310516357421875 -0.233306884765625 -0.2486572265624977 +0.451 -0.314605712890625 -0.236358642578125 -0.2486572265624977 +0.451125 -0.31866455078125 -0.239410400390625 -0.2486572265624977 +0.45125 -0.31866455078125 -0.239410400390625 -0.2486572265624977 +0.451375 -0.322662353515625 -0.242431640625 -0.2486572265624977 +0.4515 -0.322662353515625 -0.242431640625 -0.2486572265624977 +0.451625 -0.32666015625 -0.24542236328125 -0.2486572265624977 +0.45175 -0.330596923828125 -0.248382568359375 -0.2486572265624977 +0.451875 -0.330596923828125 -0.248382568359375 -0.2486572265624977 +0.452 -0.334503173828125 -0.251312255859375 -0.2486572265624977 +0.452125 -0.334503173828125 -0.251312255859375 -0.2486572265624977 +0.45225 -0.33837890625 -0.254241943359375 -0.2486572265624977 +0.452375 -0.34222412109375 -0.257110595703125 -0.2486572265624977 +0.4525 -0.34222412109375 -0.257110595703125 -0.2486572265624977 +0.452625 -0.34600830078125 -0.25994873046875 -0.2486572265624977 +0.45275 -0.34600830078125 -0.25994873046875 -0.2486572265624977 +0.452875 -0.349761962890625 -0.262786865234375 -0.2486572265624977 +0.453 -0.353485107421875 -0.26556396484375 -0.2486572265624977 +0.453125 -0.353485107421875 -0.26556396484375 -0.2486572265624977 +0.45325 -0.357177734375 -0.268341064453125 -0.2486572265624977 +0.4533750000000000512 -0.357177734375 -0.268341064453125 -0.2486572265624977 +0.4535 -0.360809326171875 -0.271087646484375 -0.2486572265624977 +0.453625 -0.36444091796875 -0.2738037109375 -0.2486572265624977 +0.45375 -0.36444091796875 -0.2738037109375 -0.2486572265624977 +0.4538750000000000512 -0.36798095703125 -0.276458740234375 -0.2486572265624977 +0.454 -0.36798095703125 -0.276458740234375 -0.2486572265624977 +0.454125 -0.37152099609375 -0.27911376953125 -0.2486572265624977 +0.45425 -0.375 -0.28173828125 -0.2486572265624977 +0.4543750000000000512 -0.375 -0.28173828125 -0.2486572265624977 +0.4545 -0.378448486328125 -0.284332275390625 -0.2486572265624977 +0.454625 -0.378448486328125 -0.284332275390625 -0.2486572265624977 +0.45475 -0.3818359375 -0.286865234375 -0.2486572265624977 +0.4548750000000000512 -0.38519287109375 -0.289398193359375 -0.2486572265624977 +0.455 -0.38519287109375 -0.289398193359375 -0.2486572265624977 +0.455125 -0.388519287109375 -0.2918701171875 -0.2486572265624977 +0.45525 -0.388519287109375 -0.2918701171875 -0.2486572265624977 +0.4553750000000000512 -0.39178466796875 -0.294342041015625 -0.2486572265624977 +0.4555 -0.39501953125 -0.296783447265625 -0.2486572265624977 +0.455625 -0.39501953125 -0.296783447265625 -0.2486572265624977 +0.45575 -0.398193359375 -0.299163818359375 -0.2486572265624977 +0.4558750000000000512 -0.398193359375 -0.299163818359375 -0.2486572265624977 +0.456 -0.401336669921875 -0.301513671875 -0.2486572265624977 +0.456125 -0.404449462890625 -0.303863525390625 -0.2486572265624977 +0.45625 -0.404449462890625 -0.303863525390625 -0.2486572265624977 +0.4563750000000000512 -0.407501220703125 -0.30615234375 -0.2486572265624977 +0.4565 -0.407501220703125 -0.30615234375 -0.2486572265624977 +0.456625 -0.4105224609375 -0.30841064453125 -0.2486572265624977 +0.45675 -0.413482666015625 -0.310638427734375 -0.2486572265624977 +0.4568750000000000512 -0.413482666015625 -0.310638427734375 -0.2486572265624977 +0.457 -0.416412353515625 -0.312835693359375 -0.2486572265624977 +0.457125 -0.416412353515625 -0.312835693359375 -0.2486572265624977 +0.45725 -0.419281005859375 -0.31500244140625 -0.2486572265624977 +0.4573750000000000512 -0.422119140625 -0.317138671875 -0.2486572265624977 +0.4575 -0.422119140625 -0.317138671875 -0.2486572265624977 +0.457625 -0.424896240234375 -0.3192138671875 -0.2486572265624977 +0.45775 -0.424896240234375 -0.3192138671875 -0.2486572265624977 +0.4578750000000000512 -0.4276123046875 -0.321258544921875 -0.2486572265624977 +0.458 -0.4302978515625 -0.323272705078125 -0.2486572265624977 +0.458125 -0.4302978515625 -0.323272705078125 -0.2486572265624977 +0.45825 -0.432952880859375 -0.325286865234375 -0.2486572265624977 +0.4583750000000000512 -0.432952880859375 -0.325286865234375 -0.2486572265624977 +0.4585 -0.435546875 -0.32720947265625 -0.2486572265624977 +0.458625 -0.438079833984375 -0.329132080078125 -0.2486572265624977 +0.45875 -0.438079833984375 -0.329132080078125 -0.2486572265624977 +0.4588750000000000512 -0.440582275390625 -0.33099365234375 -0.2486572265624977 +0.459 -0.440582275390625 -0.33099365234375 -0.2486572265624977 +0.459125 -0.44305419921875 -0.332855224609375 -0.2486572265624977 +0.45925 -0.4454345703125 -0.33465576171875 -0.2486572265624977 +0.4593750000000000512 -0.4454345703125 -0.33465576171875 -0.2486572265624977 +0.4595 -0.447784423828125 -0.33642578125 -0.2486572265624977 +0.459625 -0.447784423828125 -0.33642578125 -0.2486572265624977 +0.45975 -0.450103759765625 -0.338134765625 -0.2486572265624977 +0.4598750000000000512 -0.452362060546875 -0.33984375 -0.2486572265624977 +0.46 -0.452362060546875 -0.33984375 -0.2486572265624977 +0.460125 -0.454559326171875 -0.34149169921875 -0.2486572265624977 +0.46025 -0.454559326171875 -0.34149169921875 -0.2486572265624977 +0.4603750000000000512 -0.45672607421875 -0.343109130859375 -0.2486572265624977 +0.4605 -0.458831787109375 -0.344696044921875 -0.2486572265624977 +0.460625 -0.458831787109375 -0.344696044921875 -0.2486572265624977 +0.46075 -0.46087646484375 -0.34625244140625 -0.2486572265624977 +0.4608750000000000512 -0.46087646484375 -0.34625244140625 -0.2486572265624977 +0.461 -0.462890625 -0.347747802734375 -0.2486572265624977 +0.461125 -0.464813232421875 -0.349212646484375 -0.2486572265624977 +0.46125 -0.464813232421875 -0.349212646484375 -0.2486572265624977 +0.461375000000000052 -0.46673583984375 -0.35064697265625 -0.2486572265624977 +0.4615 -0.46673583984375 -0.35064697265625 -0.2486572265624977 +0.461625 -0.46856689453125 -0.352020263671875 -0.2486572265624977 +0.46175 -0.470367431640625 -0.3533935546875 -0.2486572265624977 +0.461875000000000052 -0.470367431640625 -0.3533935546875 -0.2486572265624977 +0.462 -0.472137451171875 -0.354705810546875 -0.2486572265624977 +0.462125 -0.472137451171875 -0.354705810546875 -0.2486572265624977 +0.46225 -0.47381591796875 -0.355987548828125 -0.2486572265624977 +0.462375000000000052 -0.4754638671875 -0.357208251953125 -0.2486572265624977 +0.4625 -0.4754638671875 -0.357208251953125 -0.2486572265624977 +0.462625 -0.47705078125 -0.3583984375 -0.2486572265624977 +0.46275 -0.47705078125 -0.3583984375 -0.2486572265624977 +0.462875000000000064 -0.478607177734375 -0.35955810546875 -0.2486572265624977 +0.463 -0.480072021484375 -0.360687255859375 -0.2486572265624977 +0.463125 -0.480072021484375 -0.360687255859375 -0.2486572265624977 +0.46325 -0.48150634765625 -0.36175537109375 -0.2486572265624977 +0.463375000000000064 -0.48150634765625 -0.36175537109375 -0.2486572265624977 +0.4635 -0.48291015625 -0.36279296875 -0.2486572265624977 +0.463625 -0.484222412109375 -0.363800048828125 -0.2486572265624977 +0.46375 -0.484222412109375 -0.363800048828125 -0.2486572265624977 +0.463875000000000064 -0.485504150390625 -0.36474609375 -0.2486572265624977 +0.464 -0.485504150390625 -0.36474609375 -0.2486572265624977 +0.464125 -0.486724853515625 -0.36566162109375 -0.2486572265624977 +0.46425 -0.487884521484375 -0.366546630859375 -0.2486572265624977 +0.464375 -0.487884521484375 -0.366546630859375 -0.2486572265624977 +0.4645 -0.489013671875 -0.36737060546875 -0.2486572265624977 +0.464625 -0.489013671875 -0.36737060546875 -0.2486572265624977 +0.46475 -0.490081787109375 -0.368194580078125 -0.2486572265624977 +0.464875 -0.4910888671875 -0.368927001953125 -0.2486572265624977 +0.465 -0.4910888671875 -0.368927001953125 -0.2486572265624977 +0.465125 -0.492034912109375 -0.369659423828125 -0.2486572265624977 +0.46525 -0.492034912109375 -0.369659423828125 -0.2486572265624977 +0.465375 -0.492950439453125 -0.370330810546875 -0.2486572265624977 +0.4655 -0.4937744140625 -0.3709716796875 -0.2486572265624977 +0.465625 -0.4937744140625 -0.3709716796875 -0.2486572265624977 +0.46575 -0.49456787109375 -0.371551513671875 -0.2486572265624977 +0.465875 -0.49456787109375 -0.371551513671875 -0.2486572265624977 +0.466 -0.49530029296875 -0.372100830078125 -0.2486572265624977 +0.466125 -0.496002197265625 -0.37261962890625 -0.2486572265624977 +0.46625 -0.496002197265625 -0.37261962890625 -0.2486572265624977 +0.466375 -0.496612548828125 -0.37310791015625 -0.2486572265624977 +0.4665 -0.496612548828125 -0.37310791015625 -0.2486572265624977 +0.466625 -0.4971923828125 -0.37353515625 -0.2486572265624977 +0.46675 -0.497711181640625 -0.373931884765625 -0.2486572265624977 +0.466875 -0.497711181640625 -0.373931884765625 -0.2486572265624977 +0.467 -0.498199462890625 -0.374267578125 -0.2486572265624977 +0.467125 -0.498199462890625 -0.374267578125 -0.2486572265624977 +0.46725 -0.49859619140625 -0.374603271484375 -0.2486572265624977 +0.467375 -0.49896240234375 -0.374847412109375 -0.2486572265624977 +0.4675 -0.49896240234375 -0.374847412109375 -0.2486572265624977 +0.467625 -0.499267578125 -0.375091552734375 -0.2486572265624977 +0.46775 -0.499267578125 -0.375091552734375 -0.2486572265624977 +0.467875 -0.49951171875 -0.375274658203125 -0.2486572265624977 +0.468 -0.49969482421875 -0.375396728515625 -0.2486572265624977 +0.468125 -0.49969482421875 -0.375396728515625 -0.2486572265624977 +0.46825 -0.49981689453125 -0.375518798828125 -0.2486572265624977 +0.468375 -0.49981689453125 -0.375518798828125 -0.2486572265624977 +0.4685 -0.499908447265625 -0.375579833984375 -0.2486572265624977 +0.468625 -0.49993896484375 -0.3756103515625 -0.2486572265624977 +0.46875 -0.49993896484375 -0.3756103515625 -0.2486572265624977 +0.468875 -0.499908447265625 -0.375579833984375 -0.2486572265624977 +0.469000000000000052 -0.499908447265625 -0.375579833984375 -0.2486572265624977 +0.469125 -0.49981689453125 -0.375518798828125 -0.2486572265624977 +0.46925 -0.49969482421875 -0.375396728515625 -0.2486572265624977 +0.469375 -0.49969482421875 -0.375396728515625 -0.2486572265624977 +0.469500000000000052 -0.49951171875 -0.375274658203125 -0.2486572265624977 +0.469625 -0.49951171875 -0.375274658203125 -0.2486572265624977 +0.46975 -0.499267578125 -0.375091552734375 -0.2486572265624977 +0.469875 -0.49896240234375 -0.374847412109375 -0.2486572265624977 +0.470000000000000052 -0.49896240234375 -0.374847412109375 -0.2486572265624977 +0.470125 -0.49859619140625 -0.374603271484375 -0.2486572265624977 +0.47025 -0.49859619140625 -0.374603271484375 -0.2486572265624977 +0.470375 -0.498199462890625 -0.374267578125 -0.2486572265624977 +0.470500000000000052 -0.497711181640625 -0.373931884765625 -0.2486572265624977 +0.470625 -0.497711181640625 -0.373931884765625 -0.2486572265624977 +0.47075 -0.4971923828125 -0.37353515625 -0.2486572265624977 +0.470875 -0.4971923828125 -0.37353515625 -0.2486572265624977 +0.471000000000000052 -0.496612548828125 -0.37310791015625 -0.2486572265624977 +0.471125 -0.496002197265625 -0.37261962890625 -0.2486572265624977 +0.47125 -0.496002197265625 -0.37261962890625 -0.2486572265624977 +0.471375 -0.49530029296875 -0.372100830078125 -0.2486572265624977 +0.471500000000000052 -0.49530029296875 -0.372100830078125 -0.2486572265624977 +0.471625 -0.49456787109375 -0.371551513671875 -0.2486572265624977 +0.47175 -0.4937744140625 -0.3709716796875 -0.2486572265624977 +0.471875 -0.4937744140625 -0.3709716796875 -0.2486572265624977 +0.472000000000000052 -0.492950439453125 -0.370330810546875 -0.2486572265624977 +0.472125 -0.492950439453125 -0.370330810546875 -0.2486572265624977 +0.47225 -0.492034912109375 -0.369659423828125 -0.2486572265624977 +0.472375 -0.4910888671875 -0.368927001953125 -0.2486572265624977 +0.472500000000000052 -0.4910888671875 -0.368927001953125 -0.2486572265624977 +0.472625 -0.490081787109375 -0.368194580078125 -0.2486572265624977 +0.47275 -0.490081787109375 -0.368194580078125 -0.2486572265624977 +0.472875 -0.489013671875 -0.36737060546875 -0.2486572265624977 +0.473000000000000052 -0.487884521484375 -0.366546630859375 -0.2486572265624977 +0.473125 -0.487884521484375 -0.366546630859375 -0.2486572265624977 +0.47325 -0.486724853515625 -0.36566162109375 -0.2486572265624977 +0.473375 -0.486724853515625 -0.36566162109375 -0.2486572265624977 +0.473500000000000052 -0.485504150390625 -0.36474609375 -0.2486572265624977 +0.473625 -0.484222412109375 -0.363800048828125 -0.2486572265624977 +0.47375 -0.484222412109375 -0.363800048828125 -0.2486572265624977 +0.473875 -0.48291015625 -0.36279296875 -0.2486572265624977 +0.474000000000000052 -0.48291015625 -0.36279296875 -0.2486572265624977 +0.474125 -0.48150634765625 -0.36175537109375 -0.2486572265624977 +0.47425 -0.480072021484375 -0.360687255859375 -0.2486572265624977 +0.474375 -0.480072021484375 -0.360687255859375 -0.2486572265624977 +0.474500000000000052 -0.478607177734375 -0.35955810546875 -0.2486572265624977 +0.474625 -0.478607177734375 -0.35955810546875 -0.2486572265624977 +0.47475 -0.47705078125 -0.3583984375 -0.2486572265624977 +0.474875 -0.4754638671875 -0.357208251953125 -0.2486572265624977 +0.475000000000000052 -0.4754638671875 -0.357208251953125 -0.2486572265624977 +0.475125 -0.47381591796875 -0.355987548828125 -0.2486572265624977 +0.47525 -0.47381591796875 -0.355987548828125 -0.2486572265624977 +0.475375 -0.472137451171875 -0.354705810546875 -0.2486572265624977 +0.475500000000000052 -0.470367431640625 -0.3533935546875 -0.2486572265624977 +0.475625 -0.470367431640625 -0.3533935546875 -0.2486572265624977 +0.47575 -0.46856689453125 -0.352020263671875 -0.2486572265624977 +0.475875 -0.46856689453125 -0.352020263671875 -0.2486572265624977 +0.476000000000000052 -0.46673583984375 -0.35064697265625 -0.2486572265624977 +0.476125 -0.464813232421875 -0.349212646484375 -0.2486572265624977 +0.47625 -0.464813232421875 -0.349212646484375 -0.2486572265624977 +0.476375 -0.462890625 -0.347747802734375 -0.2486572265624977 +0.476500000000000052 -0.462890625 -0.347747802734375 -0.2486572265624977 +0.476625 -0.46087646484375 -0.34625244140625 -0.2486572265624977 +0.47675 -0.458831787109375 -0.344696044921875 -0.2486572265624977 +0.476875 -0.458831787109375 -0.344696044921875 -0.2486572265624977 +0.477000000000000052 -0.45672607421875 -0.343109130859375 -0.2486572265624977 +0.477125 -0.45672607421875 -0.343109130859375 -0.2486572265624977 +0.47725 -0.454559326171875 -0.34149169921875 -0.2486572265624977 +0.477375 -0.452362060546875 -0.33984375 -0.2486572265624977 +0.477500000000000052 -0.452362060546875 -0.33984375 -0.2486572265624977 +0.477625 -0.450103759765625 -0.338134765625 -0.2486572265624977 +0.47775 -0.450103759765625 -0.338134765625 -0.2486572265624977 +0.477875 -0.447784423828125 -0.33642578125 -0.2486572265624977 +0.478000000000000052 -0.4454345703125 -0.33465576171875 -0.2486572265624977 +0.478125 -0.4454345703125 -0.33465576171875 -0.2486572265624977 +0.47825 -0.44305419921875 -0.332855224609375 -0.2486572265624977 +0.478375 -0.44305419921875 -0.332855224609375 -0.2486572265624977 +0.478500000000000064 -0.440582275390625 -0.33099365234375 -0.2486572265624977 +0.478625 -0.438079833984375 -0.329132080078125 -0.2486572265624977 +0.47875 -0.438079833984375 -0.329132080078125 -0.2486572265624977 +0.478875 -0.435546875 -0.32720947265625 -0.2486572265624977 +0.479000000000000064 -0.435546875 -0.32720947265625 -0.2486572265624977 +0.479125 -0.432952880859375 -0.325286865234375 -0.2486572265624977 +0.47925 -0.4302978515625 -0.323272705078125 -0.2486572265624977 +0.479375 -0.4302978515625 -0.323272705078125 -0.2486572265624977 +0.479500000000000064 -0.4276123046875 -0.321258544921875 -0.2486572265624977 +0.479625 -0.4276123046875 -0.321258544921875 -0.2486572265624977 +0.47975 -0.424896240234375 -0.3192138671875 -0.2486572265624977 +0.479875 -0.422119140625 -0.317138671875 -0.2486572265624977 +0.48 -0.358673095703125 -0.422119140625 0.1501953125000029 +0.480125 -0.35626220703125 -0.419281005859375 0.1501953125000029 +0.48025 -0.35626220703125 -0.419281005859375 0.1501953125000029 +0.480375 -0.353851318359375 -0.416412353515625 0.1501953125000029 +0.4805 -0.351348876953125 -0.413482666015625 0.1501953125000029 +0.480625 -0.351348876953125 -0.413482666015625 0.1501953125000029 +0.48075 -0.348846435546875 -0.4105224609375 0.1501953125000029 +0.480875 -0.348846435546875 -0.4105224609375 0.1501953125000029 +0.481 -0.346282958984375 -0.407501220703125 0.1501953125000029 +0.481125 -0.34368896484375 -0.404449462890625 0.1501953125000029 +0.48125 -0.34368896484375 -0.404449462890625 0.1501953125000029 +0.481375 -0.341033935546875 -0.401336669921875 0.1501953125000029 +0.4815 -0.341033935546875 -0.401336669921875 0.1501953125000029 +0.481625 -0.33837890625 -0.398193359375 0.1501953125000029 +0.48175 -0.335662841796875 -0.39501953125 0.1501953125000029 +0.481875 -0.335662841796875 -0.39501953125 0.1501953125000029 +0.482 -0.332916259765625 -0.39178466796875 0.1501953125000029 +0.482125 -0.332916259765625 -0.39178466796875 0.1501953125000029 +0.48225 -0.33013916015625 -0.388519287109375 0.1501953125000029 +0.482375 -0.32733154296875 -0.38519287109375 0.1501953125000029 +0.4825 -0.32733154296875 -0.38519287109375 0.1501953125000029 +0.482625 -0.324462890625 -0.3818359375 0.1501953125000029 +0.48275 -0.324462890625 -0.3818359375 0.1501953125000029 +0.482875 -0.321563720703125 -0.378448486328125 0.1501953125000029 +0.483 -0.318634033203125 -0.375 0.1501953125000029 +0.483125 -0.318634033203125 -0.375 0.1501953125000029 +0.48325 -0.315704345703125 -0.37152099609375 0.1501953125000029 +0.483375 -0.315704345703125 -0.37152099609375 0.1501953125000029 +0.4835 -0.31268310546875 -0.36798095703125 0.1501953125000029 +0.483625 -0.309661865234375 -0.36444091796875 0.1501953125000029 +0.48375 -0.309661865234375 -0.36444091796875 0.1501953125000029 +0.483875 -0.306610107421875 -0.360809326171875 0.1501953125000029 +0.484 -0.306610107421875 -0.360809326171875 0.1501953125000029 +0.484125 -0.30352783203125 -0.357177734375 0.1501953125000029 +0.48425 -0.300384521484375 -0.353485107421875 0.1501953125000029 +0.484375 -0.300384521484375 -0.353485107421875 0.1501953125000029 +0.4845 -0.297210693359375 -0.349761962890625 0.1501953125000029 +0.484625000000000052 -0.297210693359375 -0.349761962890625 0.1501953125000029 +0.48475 -0.294036865234375 -0.34600830078125 0.1501953125000029 +0.484875 -0.290802001953125 -0.34222412109375 0.1501953125000029 +0.485 -0.290802001953125 -0.34222412109375 0.1501953125000029 +0.485125000000000052 -0.28753662109375 -0.33837890625 0.1501953125000029 +0.48525 -0.28753662109375 -0.33837890625 0.1501953125000029 +0.485375 -0.28424072265625 -0.334503173828125 0.1501953125000029 +0.4855 -0.28094482421875 -0.330596923828125 0.1501953125000029 +0.485625000000000052 -0.28094482421875 -0.330596923828125 0.1501953125000029 +0.48575 -0.277587890625 -0.32666015625 0.1501953125000029 +0.485875 -0.277587890625 -0.32666015625 0.1501953125000029 +0.486 -0.274200439453125 -0.322662353515625 0.1501953125000029 +0.486125000000000052 -0.270782470703125 -0.31866455078125 0.1501953125000029 +0.48625 -0.270782470703125 -0.31866455078125 0.1501953125000029 +0.486375 -0.267333984375 -0.314605712890625 0.1501953125000029 +0.4865 -0.267333984375 -0.314605712890625 0.1501953125000029 +0.486625000000000052 -0.26385498046875 -0.310516357421875 0.1501953125000029 +0.48675 -0.2603759765625 -0.306396484375 0.1501953125000029 +0.486875 -0.2603759765625 -0.306396484375 0.1501953125000029 +0.487 -0.2568359375 -0.30224609375 0.1501953125000029 +0.487125000000000052 -0.2568359375 -0.30224609375 0.1501953125000029 +0.48725 -0.253265380859375 -0.298065185546875 0.1501953125000029 +0.487375 -0.24969482421875 -0.2938232421875 0.1501953125000029 +0.4875 -0.24969482421875 -0.2938232421875 0.1501953125000029 +0.487625000000000052 -0.24609375 -0.289581298828125 0.1501953125000029 +0.48775 -0.24609375 -0.289581298828125 0.1501953125000029 +0.487875 -0.242431640625 -0.285308837890625 0.1501953125000029 +0.488 -0.23876953125 -0.280975341796875 0.1501953125000029 +0.488125000000000052 -0.23876953125 -0.280975341796875 0.1501953125000029 +0.48825 -0.235076904296875 -0.276641845703125 0.1501953125000029 +0.488375 -0.235076904296875 -0.276641845703125 0.1501953125000029 +0.4885 -0.231353759765625 -0.27227783203125 0.1501953125000029 +0.488625000000000052 -0.227630615234375 -0.267852783203125 0.1501953125000029 +0.48875 -0.227630615234375 -0.267852783203125 0.1501953125000029 +0.488875 -0.223846435546875 -0.263427734375 0.1501953125000029 +0.489 -0.223846435546875 -0.263427734375 0.1501953125000029 +0.489125000000000052 -0.220062255859375 -0.25897216796875 0.1501953125000029 +0.48925 -0.21624755859375 -0.25445556640625 0.1501953125000029 +0.489375 -0.21624755859375 -0.25445556640625 0.1501953125000029 +0.4895 -0.21240234375 -0.249969482421875 0.1501953125000029 +0.489625000000000052 -0.21240234375 -0.249969482421875 0.1501953125000029 +0.48975 -0.208526611328125 -0.24542236328125 0.1501953125000029 +0.489875 -0.20465087890625 -0.2408447265625 0.1501953125000029 +0.49 -0.20465087890625 -0.2408447265625 0.1501953125000029 +0.490125000000000052 -0.20074462890625 -0.236236572265625 0.1501953125000029 +0.49025 -0.20074462890625 -0.236236572265625 0.1501953125000029 +0.490375 -0.196807861328125 -0.231597900390625 0.1501953125000029 +0.4905 -0.192840576171875 -0.226959228515625 0.1501953125000029 +0.490625000000000052 -0.192840576171875 -0.226959228515625 0.1501953125000029 +0.49075 -0.188873291015625 -0.2222900390625 0.1501953125000029 +0.490875 -0.188873291015625 -0.2222900390625 0.1501953125000029 +0.491 -0.18487548828125 -0.21759033203125 0.1501953125000029 +0.491125000000000052 -0.180877685546875 -0.212860107421875 0.1501953125000029 +0.49125 -0.180877685546875 -0.212860107421875 0.1501953125000029 +0.491375 -0.17681884765625 -0.208099365234375 0.1501953125000029 +0.4915 -0.17681884765625 -0.208099365234375 0.1501953125000029 +0.491625000000000052 -0.172760009765625 -0.203338623046875 0.1501953125000029 +0.49175 -0.168701171875 -0.19854736328125 0.1501953125000029 +0.491875 -0.168701171875 -0.19854736328125 0.1501953125000029 +0.492 -0.16461181640625 -0.1937255859375 0.1501953125000029 +0.492125000000000052 -0.16461181640625 -0.1937255859375 0.1501953125000029 +0.49225 -0.160491943359375 -0.188873291015625 0.1501953125000029 +0.492375 -0.1563720703125 -0.18402099609375 0.1501953125000029 +0.4925 -0.1563720703125 -0.18402099609375 0.1501953125000029 +0.492625000000000052 -0.1522216796875 -0.17913818359375 0.1501953125000029 +0.49275 -0.1522216796875 -0.17913818359375 0.1501953125000029 +0.492875 -0.1480712890625 -0.17425537109375 0.1501953125000029 +0.493 -0.143890380859375 -0.169342041015625 0.1501953125000029 +0.493125000000000052 -0.143890380859375 -0.169342041015625 0.1501953125000029 +0.49325 -0.139678955078125 -0.164398193359375 0.1501953125000029 +0.493375 -0.139678955078125 -0.164398193359375 0.1501953125000029 +0.4935 -0.135498046875 -0.159454345703125 0.1501953125000029 +0.493625000000000052 -0.131256103515625 -0.15447998046875 0.1501953125000029 +0.49375 -0.131256103515625 -0.15447998046875 0.1501953125000029 +0.493875 -0.12701416015625 -0.14947509765625 0.1501953125000029 +0.494 -0.12701416015625 -0.14947509765625 0.1501953125000029 +0.494125000000000064 -0.122772216796875 -0.14447021484375 0.1501953125000029 +0.49425 -0.118499755859375 -0.13946533203125 0.1501953125000029 +0.494375 -0.118499755859375 -0.13946533203125 0.1501953125000029 +0.4945 -0.114227294921875 -0.134429931640625 0.1501953125000029 +0.494625000000000064 -0.114227294921875 -0.134429931640625 0.1501953125000029 +0.49475 -0.10992431640625 -0.129364013671875 0.1501953125000029 +0.494875 -0.105621337890625 -0.124298095703125 0.1501953125000029 +0.495 -0.105621337890625 -0.124298095703125 0.1501953125000029 +0.495125000000000064 -0.101318359375 -0.119232177734375 0.1501953125000029 +0.49525 -0.101318359375 -0.119232177734375 0.1501953125000029 +0.495375 -0.09698486328125 -0.1141357421875 0.1501953125000029 +0.4955 -0.0926513671875 -0.109039306640625 0.1501953125000029 +0.495625000000000064 -0.0926513671875 -0.109039306640625 0.1501953125000029 +0.49575 -0.08831787109375 -0.103912353515625 0.1501953125000029 +0.495875 -0.08831787109375 -0.103912353515625 0.1501953125000029 +0.496 -0.083953857421875 -0.098785400390625 0.1501953125000029 +0.496125 -0.07958984375 -0.093658447265625 0.1501953125000029 +0.49625 -0.07958984375 -0.093658447265625 0.1501953125000029 +0.496375 -0.0751953125 -0.0885009765625 0.1501953125000029 +0.4965 -0.0751953125 -0.0885009765625 0.1501953125000029 +0.496625 -0.070831298828125 -0.083343505859375 0.1501953125000029 +0.49675 -0.066436767578125 -0.07818603515625 0.1501953125000029 +0.496875 -0.066436767578125 -0.07818603515625 0.1501953125000029 +0.497 -0.062042236328125 -0.072998046875 0.1501953125000029 +0.497125 -0.062042236328125 -0.072998046875 0.1501953125000029 +0.49725 -0.0576171875 -0.06781005859375 0.1501953125000029 +0.497375 -0.05322265625 -0.0626220703125 0.1501953125000029 +0.4975 -0.05322265625 -0.0626220703125 0.1501953125000029 +0.497625 -0.048797607421875 -0.05743408203125 0.1501953125000029 +0.49775 -0.048797607421875 -0.05743408203125 0.1501953125000029 +0.497875 -0.044403076171875 -0.05224609375 0.1501953125000029 +0.498 -0.039947509765625 -0.047027587890625 0.1501953125000029 +0.498125 -0.039947509765625 -0.047027587890625 0.1501953125000029 +0.49825 -0.0355224609375 -0.04180908203125 0.1501953125000029 +0.498375 -0.0355224609375 -0.04180908203125 0.1501953125000029 +0.4985 -0.031097412109375 -0.036590576171875 0.1501953125000029 +0.498625 -0.026641845703125 -0.0313720703125 0.1501953125000029 +0.49875 -0.026641845703125 -0.0313720703125 0.1501953125000029 +0.498875 -0.022216796875 -0.026123046875 0.1501953125000029 +0.499 -0.022216796875 -0.026123046875 0.1501953125000029 +0.499125 -0.01776123046875 -0.020904541015625 0.1501953125000029 +0.49925 -0.013336181640625 -0.01568603515625 0.1501953125000029 +0.499375 -0.013336181640625 -0.01568603515625 0.1501953125000029 +0.4995 -0.008880615234375 -0.01043701171875 0.1501953125000029 +0.499625 -0.008880615234375 -0.01043701171875 0.1501953125000029 +0.49975 -0.004425048828125 -0.005218505859375 0.1501953125000029 +0.499875 0.0 0.0 0.1501953125000029 +0.5 0.0 0.0 0.1501953125000029 +0.500125 0.004425048828125 0.005218505859375 0.1501953125000029 +0.50025 0.004425048828125 0.005218505859375 0.1501953125000029 +0.500375 0.008880615234375 0.01043701171875 0.1501953125000029 +0.5005000000000001 0.013336181640625 0.01568603515625 0.1501953125000029 +0.500625 0.013336181640625 0.01568603515625 0.1501953125000029 +0.50075 0.01776123046875 0.020904541015625 0.1501953125000029 +0.500875 0.01776123046875 0.020904541015625 0.1501953125000029 +0.501 0.022216796875 0.026123046875 0.1501953125000029 +0.501125 0.026641845703125 0.0313720703125 0.1501953125000029 +0.50125 0.026641845703125 0.0313720703125 0.1501953125000029 +0.501375 0.031097412109375 0.036590576171875 0.1501953125000029 +0.5015000000000001 0.031097412109375 0.036590576171875 0.1501953125000029 +0.501625 0.0355224609375 0.04180908203125 0.1501953125000029 +0.50175 0.039947509765625 0.047027587890625 0.1501953125000029 +0.501875 0.039947509765625 0.047027587890625 0.1501953125000029 +0.502 0.044403076171875 0.05224609375 0.1501953125000029 +0.502125 0.044403076171875 0.05224609375 0.1501953125000029 +0.50225 0.048797607421875 0.05743408203125 0.1501953125000029 +0.502375 0.05322265625 0.0626220703125 0.1501953125000029 +0.5025000000000001 0.05322265625 0.0626220703125 0.1501953125000029 +0.502625 0.0576171875 0.06781005859375 0.1501953125000029 +0.50275 0.0576171875 0.06781005859375 0.1501953125000029 +0.502875 0.062042236328125 0.072998046875 0.1501953125000029 +0.503 0.066436767578125 0.07818603515625 0.1501953125000029 +0.503125 0.066436767578125 0.07818603515625 0.1501953125000029 +0.50325 0.070831298828125 0.083343505859375 0.1501953125000029 +0.503375 0.070831298828125 0.083343505859375 0.1501953125000029 +0.5035000000000001 0.0751953125 0.0885009765625 0.1501953125000029 +0.503625 0.07958984375 0.093658447265625 0.1501953125000029 +0.50375 0.07958984375 0.093658447265625 0.1501953125000029 +0.503875 0.083953857421875 0.098785400390625 0.1501953125000029 +0.504 0.083953857421875 0.098785400390625 0.1501953125000029 +0.504125 0.08831787109375 0.103912353515625 0.1501953125000029 +0.50425 0.0926513671875 0.109039306640625 0.1501953125000029 +0.504375 0.0926513671875 0.109039306640625 0.1501953125000029 +0.5045000000000001 0.09698486328125 0.1141357421875 0.1501953125000029 +0.504625 0.09698486328125 0.1141357421875 0.1501953125000029 +0.50475 0.101318359375 0.119232177734375 0.1501953125000029 +0.504875 0.105621337890625 0.124298095703125 0.1501953125000029 +0.505 0.105621337890625 0.124298095703125 0.1501953125000029 +0.505125 0.10992431640625 0.129364013671875 0.1501953125000029 +0.50525 0.10992431640625 0.129364013671875 0.1501953125000029 +0.505375 0.114227294921875 0.134429931640625 0.1501953125000029 +0.5055000000000001 0.118499755859375 0.13946533203125 0.1501953125000029 +0.505625 0.118499755859375 0.13946533203125 0.1501953125000029 +0.50575 0.122772216796875 0.14447021484375 0.1501953125000029 +0.505875 0.122772216796875 0.14447021484375 0.1501953125000029 +0.506 0.12701416015625 0.14947509765625 0.1501953125000029 +0.506125 0.131256103515625 0.15447998046875 0.1501953125000029 +0.50625 0.131256103515625 0.15447998046875 0.1501953125000029 +0.506375 0.135498046875 0.159454345703125 0.1501953125000029 +0.5065000000000001 0.135498046875 0.159454345703125 0.1501953125000029 +0.506625 0.139678955078125 0.164398193359375 0.1501953125000029 +0.50675 0.143890380859375 0.169342041015625 0.1501953125000029 +0.506875 0.143890380859375 0.169342041015625 0.1501953125000029 +0.507 0.1480712890625 0.17425537109375 0.1501953125000029 +0.507125 0.1480712890625 0.17425537109375 0.1501953125000029 +0.50725 0.1522216796875 0.17913818359375 0.1501953125000029 +0.507375 0.1563720703125 0.18402099609375 0.1501953125000029 +0.5075000000000001 0.1563720703125 0.18402099609375 0.1501953125000029 +0.507625 0.160491943359375 0.188873291015625 0.1501953125000029 +0.50775 0.160491943359375 0.188873291015625 0.1501953125000029 +0.507875 0.16461181640625 0.1937255859375 0.1501953125000029 +0.508 0.168701171875 0.19854736328125 0.1501953125000029 +0.508125 0.168701171875 0.19854736328125 0.1501953125000029 +0.50825 0.172760009765625 0.203338623046875 0.1501953125000029 +0.508375 0.172760009765625 0.203338623046875 0.1501953125000029 +0.5085000000000001 0.17681884765625 0.208099365234375 0.1501953125000029 +0.508625 0.180877685546875 0.212860107421875 0.1501953125000029 +0.50875 0.180877685546875 0.212860107421875 0.1501953125000029 +0.508875 0.18487548828125 0.21759033203125 0.1501953125000029 +0.509 0.18487548828125 0.21759033203125 0.1501953125000029 +0.509125 0.188873291015625 0.2222900390625 0.1501953125000029 +0.50925 0.192840576171875 0.226959228515625 0.1501953125000029 +0.509375 0.192840576171875 0.226959228515625 0.1501953125000029 +0.5095000000000001 0.196807861328125 0.231597900390625 0.1501953125000029 +0.509625 0.196807861328125 0.231597900390625 0.1501953125000029 +0.50975 0.20074462890625 0.236236572265625 0.1501953125000029 +0.509875 0.20465087890625 0.2408447265625 0.1501953125000029 +0.51 0.20465087890625 0.2408447265625 0.1501953125000029 +0.5101250000000001 0.208526611328125 0.24542236328125 0.1501953125000029 +0.51025 0.208526611328125 0.24542236328125 0.1501953125000029 +0.510375 0.21240234375 0.249969482421875 0.1501953125000029 +0.5105000000000001 0.21624755859375 0.25445556640625 0.1501953125000029 +0.510625 0.21624755859375 0.25445556640625 0.1501953125000029 +0.51075 0.220062255859375 0.25897216796875 0.1501953125000029 +0.510875 0.220062255859375 0.25897216796875 0.1501953125000029 +0.511 0.223846435546875 0.263427734375 0.1501953125000029 +0.5111250000000001 0.227630615234375 0.267852783203125 0.1501953125000029 +0.51125 0.227630615234375 0.267852783203125 0.1501953125000029 +0.511375 0.231353759765625 0.27227783203125 0.1501953125000029 +0.5115000000000001 0.231353759765625 0.27227783203125 0.1501953125000029 +0.511625 0.235076904296875 0.276641845703125 0.1501953125000029 +0.51175 0.23876953125 0.280975341796875 0.1501953125000029 +0.511875 0.23876953125 0.280975341796875 0.1501953125000029 +0.512 0.135467529296875 0.285308837890625 0.5251342773437525 +0.5121250000000001 0.135467529296875 0.285308837890625 0.5251342773437525 +0.51225 0.137481689453125 0.289581298828125 0.5251342773437525 +0.512375 0.139495849609375 0.2938232421875 0.5251342773437525 +0.5125 0.139495849609375 0.2938232421875 0.5251342773437525 +0.512625 0.141510009765625 0.298065185546875 0.5251342773437525 +0.51275 0.141510009765625 0.298065185546875 0.5251342773437525 +0.512875 0.14349365234375 0.30224609375 0.5251342773437525 +0.513 0.145477294921875 0.306396484375 0.5251342773437525 +0.5131250000000001 0.145477294921875 0.306396484375 0.5251342773437525 +0.51325 0.147430419921875 0.310516357421875 0.5251342773437525 +0.513375 0.147430419921875 0.310516357421875 0.5251342773437525 +0.5135 0.14935302734375 0.314605712890625 0.5251342773437525 +0.513625 0.151275634765625 0.31866455078125 0.5251342773437525 +0.51375 0.151275634765625 0.31866455078125 0.5251342773437525 +0.513875 0.1531982421875 0.322662353515625 0.5251342773437525 +0.514 0.1531982421875 0.322662353515625 0.5251342773437525 +0.5141250000000001 0.15509033203125 0.32666015625 0.5251342773437525 +0.51425 0.156951904296875 0.330596923828125 0.5251342773437525 +0.514375 0.156951904296875 0.330596923828125 0.5251342773437525 +0.5145 0.1588134765625 0.334503173828125 0.5251342773437525 +0.514625 0.1588134765625 0.334503173828125 0.5251342773437525 +0.51475 0.16064453125 0.33837890625 0.5251342773437525 +0.514875 0.1624755859375 0.34222412109375 0.5251342773437525 +0.515 0.1624755859375 0.34222412109375 0.5251342773437525 +0.5151250000000001 0.164276123046875 0.34600830078125 0.5251342773437525 +0.51525 0.164276123046875 0.34600830078125 0.5251342773437525 +0.515375 0.166046142578125 0.349761962890625 0.5251342773437525 +0.5155 0.167816162109375 0.353485107421875 0.5251342773437525 +0.515625 0.167816162109375 0.353485107421875 0.5251342773437525 +0.51575 0.169586181640625 0.357177734375 0.5251342773437525 +0.515875 0.169586181640625 0.357177734375 0.5251342773437525 +0.516 0.171295166015625 0.360809326171875 0.5251342773437525 +0.5161250000000001 0.17303466796875 0.36444091796875 0.5251342773437525 +0.51625 0.17303466796875 0.36444091796875 0.5251342773437525 +0.516375 0.174713134765625 0.36798095703125 0.5251342773437525 +0.5165 0.174713134765625 0.36798095703125 0.5251342773437525 +0.516625 0.1763916015625 0.37152099609375 0.5251342773437525 +0.51675 0.17803955078125 0.375 0.5251342773437525 +0.516875 0.17803955078125 0.375 0.5251342773437525 +0.517 0.179656982421875 0.378448486328125 0.5251342773437525 +0.5171250000000001 0.179656982421875 0.378448486328125 0.5251342773437525 +0.51725 0.1812744140625 0.3818359375 0.5251342773437525 +0.517375 0.182891845703125 0.38519287109375 0.5251342773437525 +0.5175 0.182891845703125 0.38519287109375 0.5251342773437525 +0.517625 0.1844482421875 0.388519287109375 0.5251342773437525 +0.51775 0.1844482421875 0.388519287109375 0.5251342773437525 +0.517875 0.186004638671875 0.39178466796875 0.5251342773437525 +0.518 0.18756103515625 0.39501953125 0.5251342773437525 +0.5181250000000001 0.18756103515625 0.39501953125 0.5251342773437525 +0.51825 0.189056396484375 0.398193359375 0.5251342773437525 +0.518375 0.189056396484375 0.398193359375 0.5251342773437525 +0.5185 0.1905517578125 0.401336669921875 0.5251342773437525 +0.518625 0.1920166015625 0.404449462890625 0.5251342773437525 +0.51875 0.1920166015625 0.404449462890625 0.5251342773437525 +0.518875 0.1934814453125 0.407501220703125 0.5251342773437525 +0.519 0.1934814453125 0.407501220703125 0.5251342773437525 +0.5191250000000001 0.19488525390625 0.4105224609375 0.5251342773437525 +0.51925 0.196319580078125 0.413482666015625 0.5251342773437525 +0.519375 0.196319580078125 0.413482666015625 0.5251342773437525 +0.5195 0.19769287109375 0.416412353515625 0.5251342773437525 +0.519625 0.19769287109375 0.416412353515625 0.5251342773437525 +0.51975 0.199066162109375 0.419281005859375 0.5251342773437525 +0.519875 0.200408935546875 0.422119140625 0.5251342773437525 +0.52 0.200408935546875 0.422119140625 0.5251342773437525 +0.5201250000000001 0.20172119140625 0.424896240234375 0.5251342773437525 +0.52025 0.20172119140625 0.424896240234375 0.5251342773437525 +0.520375 0.203033447265625 0.4276123046875 0.5251342773437525 +0.5205 0.20428466796875 0.4302978515625 0.5251342773437525 +0.520625 0.20428466796875 0.4302978515625 0.5251342773437525 +0.52075 0.20556640625 0.432952880859375 0.5251342773437525 +0.520875 0.20556640625 0.432952880859375 0.5251342773437525 +0.521 0.206787109375 0.435546875 0.5251342773437525 +0.5211250000000001 0.207977294921875 0.438079833984375 0.5251342773437525 +0.52125 0.207977294921875 0.438079833984375 0.5251342773437525 +0.521375 0.20916748046875 0.440582275390625 0.5251342773437525 +0.5215 0.20916748046875 0.440582275390625 0.5251342773437525 +0.521625 0.210357666015625 0.44305419921875 0.5251342773437525 +0.52175 0.21148681640625 0.4454345703125 0.5251342773437525 +0.521875 0.21148681640625 0.4454345703125 0.5251342773437525 +0.522 0.21258544921875 0.447784423828125 0.5251342773437525 +0.5221250000000001 0.21258544921875 0.447784423828125 0.5251342773437525 +0.52225 0.21368408203125 0.450103759765625 0.5251342773437525 +0.522375 0.214752197265625 0.452362060546875 0.5251342773437525 +0.5225 0.214752197265625 0.452362060546875 0.5251342773437525 +0.522625 0.2158203125 0.454559326171875 0.5251342773437525 +0.52275 0.2158203125 0.454559326171875 0.5251342773437525 +0.522875 0.216827392578125 0.45672607421875 0.5251342773437525 +0.523 0.21783447265625 0.458831787109375 0.5251342773437525 +0.5231250000000001 0.21783447265625 0.458831787109375 0.5251342773437525 +0.52325 0.21881103515625 0.46087646484375 0.5251342773437525 +0.523375 0.21881103515625 0.46087646484375 0.5251342773437525 +0.5235 0.219757080078125 0.462890625 0.5251342773437525 +0.523625 0.220672607421875 0.464813232421875 0.5251342773437525 +0.52375 0.220672607421875 0.464813232421875 0.5251342773437525 +0.523875 0.221588134765625 0.46673583984375 0.5251342773437525 +0.524 0.221588134765625 0.46673583984375 0.5251342773437525 +0.5241250000000001 0.22247314453125 0.46856689453125 0.5251342773437525 +0.52425 0.22332763671875 0.470367431640625 0.5251342773437525 +0.524375 0.22332763671875 0.470367431640625 0.5251342773437525 +0.5245 0.224151611328125 0.472137451171875 0.5251342773437525 +0.524625 0.224151611328125 0.472137451171875 0.5251342773437525 +0.52475 0.224945068359375 0.47381591796875 0.5251342773437525 +0.524875 0.225738525390625 0.4754638671875 0.5251342773437525 +0.525 0.225738525390625 0.4754638671875 0.5251342773437525 +0.5251250000000001 0.22650146484375 0.47705078125 0.5251342773437525 +0.52525 0.22650146484375 0.47705078125 0.5251342773437525 +0.525375 0.22723388671875 0.478607177734375 0.5251342773437525 +0.5255 0.227935791015625 0.480072021484375 0.5251342773437525 +0.525625 0.227935791015625 0.480072021484375 0.5251342773437525 +0.5257500000000001 0.228607177734375 0.48150634765625 0.5251342773437525 +0.525875 0.228607177734375 0.48150634765625 0.5251342773437525 +0.526 0.229278564453125 0.48291015625 0.5251342773437525 +0.5261250000000001 0.229888916015625 0.484222412109375 0.5251342773437525 +0.52625 0.229888916015625 0.484222412109375 0.5251342773437525 +0.526375 0.230499267578125 0.485504150390625 0.5251342773437525 +0.5265 0.230499267578125 0.485504150390625 0.5251342773437525 +0.526625 0.2310791015625 0.486724853515625 0.5251342773437525 +0.5267500000000001 0.23162841796875 0.487884521484375 0.5251342773437525 +0.526875 0.23162841796875 0.487884521484375 0.5251342773437525 +0.527 0.232177734375 0.489013671875 0.5251342773437525 +0.5271250000000001 0.232177734375 0.489013671875 0.5251342773437525 +0.52725 0.232666015625 0.490081787109375 0.5251342773437525 +0.527375 0.233154296875 0.4910888671875 0.5251342773437525 +0.5275 0.233154296875 0.4910888671875 0.5251342773437525 +0.527625 0.233612060546875 0.492034912109375 0.5251342773437525 +0.5277500000000001 0.233612060546875 0.492034912109375 0.5251342773437525 +0.527875 0.234039306640625 0.492950439453125 0.5251342773437525 +0.528 0.23443603515625 0.4937744140625 0.5251342773437525 +0.528125 0.23443603515625 0.4937744140625 0.5251342773437525 +0.52825 0.23480224609375 0.49456787109375 0.5251342773437525 +0.528375 0.23480224609375 0.49456787109375 0.5251342773437525 +0.5285 0.23516845703125 0.49530029296875 0.5251342773437525 +0.528625 0.2354736328125 0.496002197265625 0.5251342773437525 +0.5287500000000001 0.2354736328125 0.496002197265625 0.5251342773437525 +0.528875 0.23577880859375 0.496612548828125 0.5251342773437525 +0.529 0.23577880859375 0.496612548828125 0.5251342773437525 +0.529125 0.236053466796875 0.4971923828125 0.5251342773437525 +0.52925 0.236297607421875 0.497711181640625 0.5251342773437525 +0.529375 0.236297607421875 0.497711181640625 0.5251342773437525 +0.5295 0.23651123046875 0.498199462890625 0.5251342773437525 +0.529625 0.23651123046875 0.498199462890625 0.5251342773437525 +0.5297500000000001 0.236724853515625 0.49859619140625 0.5251342773437525 +0.529875 0.23687744140625 0.49896240234375 0.5251342773437525 +0.53 0.23687744140625 0.49896240234375 0.5251342773437525 +0.530125 0.237030029296875 0.499267578125 0.5251342773437525 +0.53025 0.237030029296875 0.499267578125 0.5251342773437525 +0.530375 0.237152099609375 0.49951171875 0.5251342773437525 +0.5305 0.23724365234375 0.49969482421875 0.5251342773437525 +0.530625 0.23724365234375 0.49969482421875 0.5251342773437525 +0.5307500000000001 0.2373046875 0.49981689453125 0.5251342773437525 +0.530875 0.2373046875 0.49981689453125 0.5251342773437525 +0.531 0.237335205078125 0.499908447265625 0.5251342773437525 +0.531125 0.23736572265625 0.49993896484375 0.5251342773437525 +0.53125 0.23736572265625 0.49993896484375 0.5251342773437525 +0.531375 0.237335205078125 0.499908447265625 0.5251342773437525 +0.5315 0.237335205078125 0.499908447265625 0.5251342773437525 +0.531625 0.2373046875 0.49981689453125 0.5251342773437525 +0.5317500000000001 0.23724365234375 0.49969482421875 0.5251342773437525 +0.531875 0.23724365234375 0.49969482421875 0.5251342773437525 +0.532 0.237152099609375 0.49951171875 0.5251342773437525 +0.532125 0.237152099609375 0.49951171875 0.5251342773437525 +0.53225 0.237030029296875 0.499267578125 0.5251342773437525 +0.532375 0.23687744140625 0.49896240234375 0.5251342773437525 +0.5325 0.23687744140625 0.49896240234375 0.5251342773437525 +0.532625 0.236724853515625 0.49859619140625 0.5251342773437525 +0.5327500000000001 0.236724853515625 0.49859619140625 0.5251342773437525 +0.532875 0.23651123046875 0.498199462890625 0.5251342773437525 +0.533 0.236297607421875 0.497711181640625 0.5251342773437525 +0.533125 0.236297607421875 0.497711181640625 0.5251342773437525 +0.53325 0.236053466796875 0.4971923828125 0.5251342773437525 +0.533375 0.236053466796875 0.4971923828125 0.5251342773437525 +0.5335 0.23577880859375 0.496612548828125 0.5251342773437525 +0.533625 0.2354736328125 0.496002197265625 0.5251342773437525 +0.5337500000000001 0.2354736328125 0.496002197265625 0.5251342773437525 +0.533875 0.23516845703125 0.49530029296875 0.5251342773437525 +0.534 0.23516845703125 0.49530029296875 0.5251342773437525 +0.534125 0.23480224609375 0.49456787109375 0.5251342773437525 +0.53425 0.23443603515625 0.4937744140625 0.5251342773437525 +0.534375 0.23443603515625 0.4937744140625 0.5251342773437525 +0.5345 0.234039306640625 0.492950439453125 0.5251342773437525 +0.534625 0.234039306640625 0.492950439453125 0.5251342773437525 +0.5347500000000001 0.233612060546875 0.492034912109375 0.5251342773437525 +0.534875 0.233154296875 0.4910888671875 0.5251342773437525 +0.535 0.233154296875 0.4910888671875 0.5251342773437525 +0.535125 0.232666015625 0.490081787109375 0.5251342773437525 +0.53525 0.232666015625 0.490081787109375 0.5251342773437525 +0.535375 0.232177734375 0.489013671875 0.5251342773437525 +0.5355 0.23162841796875 0.487884521484375 0.5251342773437525 +0.535625 0.23162841796875 0.487884521484375 0.5251342773437525 +0.5357500000000001 0.2310791015625 0.486724853515625 0.5251342773437525 +0.535875 0.2310791015625 0.486724853515625 0.5251342773437525 +0.536 0.230499267578125 0.485504150390625 0.5251342773437525 +0.536125 0.229888916015625 0.484222412109375 0.5251342773437525 +0.53625 0.229888916015625 0.484222412109375 0.5251342773437525 +0.536375 0.229278564453125 0.48291015625 0.5251342773437525 +0.5365 0.229278564453125 0.48291015625 0.5251342773437525 +0.536625 0.228607177734375 0.48150634765625 0.5251342773437525 +0.5367500000000001 0.227935791015625 0.480072021484375 0.5251342773437525 +0.536875 0.227935791015625 0.480072021484375 0.5251342773437525 +0.537 0.22723388671875 0.478607177734375 0.5251342773437525 +0.537125 0.22723388671875 0.478607177734375 0.5251342773437525 +0.53725 0.22650146484375 0.47705078125 0.5251342773437525 +0.537375 0.225738525390625 0.4754638671875 0.5251342773437525 +0.5375 0.225738525390625 0.4754638671875 0.5251342773437525 +0.537625 0.224945068359375 0.47381591796875 0.5251342773437525 +0.5377500000000001 0.224945068359375 0.47381591796875 0.5251342773437525 +0.537875 0.224151611328125 0.472137451171875 0.5251342773437525 +0.538 0.22332763671875 0.470367431640625 0.5251342773437525 +0.538125 0.22332763671875 0.470367431640625 0.5251342773437525 +0.53825 0.22247314453125 0.46856689453125 0.5251342773437525 +0.538375 0.22247314453125 0.46856689453125 0.5251342773437525 +0.5385 0.221588134765625 0.46673583984375 0.5251342773437525 +0.538625 0.220672607421875 0.464813232421875 0.5251342773437525 +0.5387500000000001 0.220672607421875 0.464813232421875 0.5251342773437525 +0.538875 0.219757080078125 0.462890625 0.5251342773437525 +0.539 0.219757080078125 0.462890625 0.5251342773437525 +0.539125 0.21881103515625 0.46087646484375 0.5251342773437525 +0.53925 0.21783447265625 0.458831787109375 0.5251342773437525 +0.539375 0.21783447265625 0.458831787109375 0.5251342773437525 +0.5395 0.216827392578125 0.45672607421875 0.5251342773437525 +0.539625 0.216827392578125 0.45672607421875 0.5251342773437525 +0.5397500000000001 0.2158203125 0.454559326171875 0.5251342773437525 +0.539875 0.214752197265625 0.452362060546875 0.5251342773437525 +0.54 0.214752197265625 0.452362060546875 0.5251342773437525 +0.540125 0.21368408203125 0.450103759765625 0.5251342773437525 +0.54025 0.21368408203125 0.450103759765625 0.5251342773437525 +0.540375 0.21258544921875 0.447784423828125 0.5251342773437525 +0.5405 0.21148681640625 0.4454345703125 0.5251342773437525 +0.540625 0.21148681640625 0.4454345703125 0.5251342773437525 +0.5407500000000001 0.210357666015625 0.44305419921875 0.5251342773437525 +0.540875 0.210357666015625 0.44305419921875 0.5251342773437525 +0.541 0.20916748046875 0.440582275390625 0.5251342773437525 +0.541125 0.207977294921875 0.438079833984375 0.5251342773437525 +0.54125 0.207977294921875 0.438079833984375 0.5251342773437525 +0.5413750000000001 0.206787109375 0.435546875 0.5251342773437525 +0.5415 0.206787109375 0.435546875 0.5251342773437525 +0.541625 0.20556640625 0.432952880859375 0.5251342773437525 +0.5417500000000001 0.20428466796875 0.4302978515625 0.5251342773437525 +0.541875 0.20428466796875 0.4302978515625 0.5251342773437525 +0.542 0.203033447265625 0.4276123046875 0.5251342773437525 +0.542125 0.203033447265625 0.4276123046875 0.5251342773437525 +0.54225 0.20172119140625 0.424896240234375 0.5251342773437525 +0.5423750000000001 0.200408935546875 0.422119140625 0.5251342773437525 +0.5425 0.200408935546875 0.422119140625 0.5251342773437525 +0.542625 0.199066162109375 0.419281005859375 0.5251342773437525 +0.5427500000000001 0.199066162109375 0.419281005859375 0.5251342773437525 +0.542875 0.19769287109375 0.416412353515625 0.5251342773437525 +0.543 0.196319580078125 0.413482666015625 0.5251342773437525 +0.543125 0.196319580078125 0.413482666015625 0.5251342773437525 +0.54325 0.19488525390625 0.4105224609375 0.5251342773437525 +0.5433750000000001 0.19488525390625 0.4105224609375 0.5251342773437525 +0.5435 0.1934814453125 0.407501220703125 0.5251342773437525 +0.543625 0.1920166015625 0.404449462890625 0.5251342773437525 +0.5437500000000001 0.1920166015625 0.404449462890625 0.5251342773437525 +0.543875 0.1905517578125 0.401336669921875 0.5251342773437525 +0.544 0.073699951171875 0.401336669921875 0.8162963867187517 +0.544125 0.0731201171875 0.398193359375 0.8162963867187517 +0.54425 0.072540283203125 0.39501953125 0.8162963867187517 +0.5443750000000001 0.072540283203125 0.39501953125 0.8162963867187517 +0.5445 0.071929931640625 0.39178466796875 0.8162963867187517 +0.544625 0.071929931640625 0.39178466796875 0.8162963867187517 +0.54475 0.071319580078125 0.388519287109375 0.8162963867187517 +0.544875 0.070709228515625 0.38519287109375 0.8162963867187517 +0.545 0.070709228515625 0.38519287109375 0.8162963867187517 +0.545125 0.070098876953125 0.3818359375 0.8162963867187517 +0.54525 0.070098876953125 0.3818359375 0.8162963867187517 +0.5453750000000001 0.069488525390625 0.378448486328125 0.8162963867187517 +0.5455 0.06884765625 0.375 0.8162963867187517 +0.545625 0.06884765625 0.375 0.8162963867187517 +0.54575 0.068206787109375 0.37152099609375 0.8162963867187517 +0.545875 0.068206787109375 0.37152099609375 0.8162963867187517 +0.546 0.06756591796875 0.36798095703125 0.8162963867187517 +0.546125 0.066925048828125 0.36444091796875 0.8162963867187517 +0.54625 0.066925048828125 0.36444091796875 0.8162963867187517 +0.5463750000000001 0.066253662109375 0.360809326171875 0.8162963867187517 +0.5465 0.066253662109375 0.360809326171875 0.8162963867187517 +0.546625 0.065582275390625 0.357177734375 0.8162963867187517 +0.54675 0.064910888671875 0.353485107421875 0.8162963867187517 +0.546875 0.064910888671875 0.353485107421875 0.8162963867187517 +0.547 0.064208984375 0.349761962890625 0.8162963867187517 +0.547125 0.064208984375 0.349761962890625 0.8162963867187517 +0.54725 0.06353759765625 0.34600830078125 0.8162963867187517 +0.5473750000000001 0.062835693359375 0.34222412109375 0.8162963867187517 +0.5475 0.062835693359375 0.34222412109375 0.8162963867187517 +0.547625 0.0621337890625 0.33837890625 0.8162963867187517 +0.54775 0.0621337890625 0.33837890625 0.8162963867187517 +0.547875 0.0614013671875 0.334503173828125 0.8162963867187517 +0.548 0.060699462890625 0.330596923828125 0.8162963867187517 +0.548125 0.060699462890625 0.330596923828125 0.8162963867187517 +0.54825 0.059967041015625 0.32666015625 0.8162963867187517 +0.5483750000000001 0.059967041015625 0.32666015625 0.8162963867187517 +0.5485 0.059234619140625 0.322662353515625 0.8162963867187517 +0.548625 0.058502197265625 0.31866455078125 0.8162963867187517 +0.54875 0.058502197265625 0.31866455078125 0.8162963867187517 +0.548875 0.057769775390625 0.314605712890625 0.8162963867187517 +0.549 0.057769775390625 0.314605712890625 0.8162963867187517 +0.549125 0.0570068359375 0.310516357421875 0.8162963867187517 +0.54925 0.056243896484375 0.306396484375 0.8162963867187517 +0.5493750000000001 0.056243896484375 0.306396484375 0.8162963867187517 +0.5495 0.05548095703125 0.30224609375 0.8162963867187517 +0.549625 0.05548095703125 0.30224609375 0.8162963867187517 +0.54975 0.054718017578125 0.298065185546875 0.8162963867187517 +0.549875 0.053955078125 0.2938232421875 0.8162963867187517 +0.55 0.053955078125 0.2938232421875 0.8162963867187517 +0.550125 0.05316162109375 0.289581298828125 0.8162963867187517 +0.55025 0.05316162109375 0.289581298828125 0.8162963867187517 +0.5503750000000001 0.0523681640625 0.285308837890625 0.8162963867187517 +0.5505 0.05157470703125 0.280975341796875 0.8162963867187517 +0.550625 0.05157470703125 0.280975341796875 0.8162963867187517 +0.55075 0.05078125 0.276641845703125 0.8162963867187517 +0.550875 0.05078125 0.276641845703125 0.8162963867187517 +0.551 0.04998779296875 0.27227783203125 0.8162963867187517 +0.551125 0.049163818359375 0.267852783203125 0.8162963867187517 +0.55125 0.049163818359375 0.267852783203125 0.8162963867187517 +0.5513750000000001 0.048370361328125 0.263427734375 0.8162963867187517 +0.5515 0.048370361328125 0.263427734375 0.8162963867187517 +0.551625 0.04754638671875 0.25897216796875 0.8162963867187517 +0.55175 0.046722412109375 0.25445556640625 0.8162963867187517 +0.551875 0.046722412109375 0.25445556640625 0.8162963867187517 +0.552 0.0458984375 0.249969482421875 0.8162963867187517 +0.552125 0.0458984375 0.249969482421875 0.8162963867187517 +0.55225 0.0450439453125 0.24542236328125 0.8162963867187517 +0.5523750000000001 0.044219970703125 0.2408447265625 0.8162963867187517 +0.5525 0.044219970703125 0.2408447265625 0.8162963867187517 +0.552625 0.043365478515625 0.236236572265625 0.8162963867187517 +0.55275 0.043365478515625 0.236236572265625 0.8162963867187517 +0.552875 0.042510986328125 0.231597900390625 0.8162963867187517 +0.553 0.041656494140625 0.226959228515625 0.8162963867187517 +0.553125 0.041656494140625 0.226959228515625 0.8162963867187517 +0.55325 0.040802001953125 0.2222900390625 0.8162963867187517 +0.5533750000000001 0.040802001953125 0.2222900390625 0.8162963867187517 +0.5535 0.039947509765625 0.21759033203125 0.8162963867187517 +0.553625 0.0390625 0.212860107421875 0.8162963867187517 +0.55375 0.0390625 0.212860107421875 0.8162963867187517 +0.553875 0.0382080078125 0.208099365234375 0.8162963867187517 +0.554 0.0382080078125 0.208099365234375 0.8162963867187517 +0.554125 0.037322998046875 0.203338623046875 0.8162963867187517 +0.55425 0.03643798828125 0.19854736328125 0.8162963867187517 +0.5543750000000001 0.03643798828125 0.19854736328125 0.8162963867187517 +0.5545 0.035552978515625 0.1937255859375 0.8162963867187517 +0.554625 0.035552978515625 0.1937255859375 0.8162963867187517 +0.55475 0.03466796875 0.188873291015625 0.8162963867187517 +0.554875 0.033782958984375 0.18402099609375 0.8162963867187517 +0.555 0.033782958984375 0.18402099609375 0.8162963867187517 +0.555125 0.03289794921875 0.17913818359375 0.8162963867187517 +0.55525 0.03289794921875 0.17913818359375 0.8162963867187517 +0.5553750000000001 0.031982421875 0.17425537109375 0.8162963867187517 +0.5555 0.031097412109375 0.169342041015625 0.8162963867187517 +0.555625 0.031097412109375 0.169342041015625 0.8162963867187517 +0.55575 0.030181884765625 0.164398193359375 0.8162963867187517 +0.555875 0.030181884765625 0.164398193359375 0.8162963867187517 +0.556 0.029266357421875 0.159454345703125 0.8162963867187517 +0.556125 0.028350830078125 0.15447998046875 0.8162963867187517 +0.55625 0.028350830078125 0.15447998046875 0.8162963867187517 +0.5563750000000001 0.027435302734375 0.14947509765625 0.8162963867187517 +0.5565 0.027435302734375 0.14947509765625 0.8162963867187517 +0.556625 0.026519775390625 0.14447021484375 0.8162963867187517 +0.55675 0.025604248046875 0.13946533203125 0.8162963867187517 +0.556875 0.025604248046875 0.13946533203125 0.8162963867187517 +0.5570000000000001 0.024658203125 0.134429931640625 0.8162963867187517 +0.557125 0.024658203125 0.134429931640625 0.8162963867187517 +0.55725 0.02374267578125 0.129364013671875 0.8162963867187517 +0.5573750000000001 0.0228271484375 0.124298095703125 0.8162963867187517 +0.5575 0.0228271484375 0.124298095703125 0.8162963867187517 +0.557625 0.021881103515625 0.119232177734375 0.8162963867187517 +0.55775 0.021881103515625 0.119232177734375 0.8162963867187517 +0.557875 0.02093505859375 0.1141357421875 0.8162963867187517 +0.5580000000000001 0.02001953125 0.109039306640625 0.8162963867187517 +0.558125 0.02001953125 0.109039306640625 0.8162963867187517 +0.55825 0.019073486328125 0.103912353515625 0.8162963867187517 +0.5583750000000001 0.019073486328125 0.103912353515625 0.8162963867187517 +0.5585 0.01812744140625 0.098785400390625 0.8162963867187517 +0.558625 0.017181396484375 0.093658447265625 0.8162963867187517 +0.55875 0.017181396484375 0.093658447265625 0.8162963867187517 +0.558875 0.0162353515625 0.0885009765625 0.8162963867187517 +0.5590000000000001 0.0162353515625 0.0885009765625 0.8162963867187517 +0.559125 0.015289306640625 0.083343505859375 0.8162963867187517 +0.55925 0.01434326171875 0.07818603515625 0.8162963867187517 +0.5593750000000001 0.01434326171875 0.07818603515625 0.8162963867187517 +0.5595 0.013397216796875 0.072998046875 0.8162963867187517 +0.559625 0.013397216796875 0.072998046875 0.8162963867187517 +0.55975 0.012451171875 0.06781005859375 0.8162963867187517 +0.559875 0.011474609375 0.0626220703125 0.8162963867187517 +0.5600000000000001 0.011474609375 0.0626220703125 0.8162963867187517 +0.560125 0.010528564453125 0.05743408203125 0.8162963867187517 +0.56025 0.010528564453125 0.05743408203125 0.8162963867187517 +0.560375 0.00958251953125 0.05224609375 0.8162963867187517 +0.5605 0.008636474609375 0.047027587890625 0.8162963867187517 +0.560625 0.008636474609375 0.047027587890625 0.8162963867187517 +0.56075 0.007659912109375 0.04180908203125 0.8162963867187517 +0.560875 0.007659912109375 0.04180908203125 0.8162963867187517 +0.5610000000000001 0.0067138671875 0.036590576171875 0.8162963867187517 +0.561125 0.0057373046875 0.0313720703125 0.8162963867187517 +0.56125 0.0057373046875 0.0313720703125 0.8162963867187517 +0.561375 0.004791259765625 0.026123046875 0.8162963867187517 +0.5615 0.004791259765625 0.026123046875 0.8162963867187517 +0.561625 0.003814697265625 0.020904541015625 0.8162963867187517 +0.56175 0.00286865234375 0.01568603515625 0.8162963867187517 +0.561875 0.00286865234375 0.01568603515625 0.8162963867187517 +0.5620000000000001 0.00189208984375 0.01043701171875 0.8162963867187517 +0.562125 0.00189208984375 0.01043701171875 0.8162963867187517 +0.56225 0.000946044921875 0.005218505859375 0.8162963867187517 +0.562375 0.0 0.0 0.8162963867187517 +0.5625 0.0 0.0 0.8162963867187517 +0.562625 -0.000946044921875 -0.005218505859375 0.8162963867187517 +0.56275 -0.000946044921875 -0.005218505859375 0.8162963867187517 +0.562875 -0.00189208984375 -0.01043701171875 0.8162963867187517 +0.5630000000000001 -0.00286865234375 -0.01568603515625 0.8162963867187517 +0.563125 -0.00286865234375 -0.01568603515625 0.8162963867187517 +0.56325 -0.003814697265625 -0.020904541015625 0.8162963867187517 +0.563375 -0.003814697265625 -0.020904541015625 0.8162963867187517 +0.5635 -0.004791259765625 -0.026123046875 0.8162963867187517 +0.563625 -0.0057373046875 -0.0313720703125 0.8162963867187517 +0.56375 -0.0057373046875 -0.0313720703125 0.8162963867187517 +0.563875 -0.0067138671875 -0.036590576171875 0.8162963867187517 +0.5640000000000001 -0.0067138671875 -0.036590576171875 0.8162963867187517 +0.564125 -0.007659912109375 -0.04180908203125 0.8162963867187517 +0.56425 -0.008636474609375 -0.047027587890625 0.8162963867187517 +0.564375 -0.008636474609375 -0.047027587890625 0.8162963867187517 +0.5645 -0.00958251953125 -0.05224609375 0.8162963867187517 +0.564625 -0.00958251953125 -0.05224609375 0.8162963867187517 +0.56475 -0.010528564453125 -0.05743408203125 0.8162963867187517 +0.564875 -0.011474609375 -0.0626220703125 0.8162963867187517 +0.5650000000000001 -0.011474609375 -0.0626220703125 0.8162963867187517 +0.565125 -0.012451171875 -0.06781005859375 0.8162963867187517 +0.56525 -0.012451171875 -0.06781005859375 0.8162963867187517 +0.565375 -0.013397216796875 -0.072998046875 0.8162963867187517 +0.5655 -0.01434326171875 -0.07818603515625 0.8162963867187517 +0.565625 -0.01434326171875 -0.07818603515625 0.8162963867187517 +0.56575 -0.015289306640625 -0.083343505859375 0.8162963867187517 +0.565875 -0.015289306640625 -0.083343505859375 0.8162963867187517 +0.5660000000000001 -0.0162353515625 -0.0885009765625 0.8162963867187517 +0.566125 -0.017181396484375 -0.093658447265625 0.8162963867187517 +0.56625 -0.017181396484375 -0.093658447265625 0.8162963867187517 +0.566375 -0.01812744140625 -0.098785400390625 0.8162963867187517 +0.5665 -0.01812744140625 -0.098785400390625 0.8162963867187517 +0.566625 -0.019073486328125 -0.103912353515625 0.8162963867187517 +0.56675 -0.02001953125 -0.109039306640625 0.8162963867187517 +0.566875 -0.02001953125 -0.109039306640625 0.8162963867187517 +0.5670000000000001 -0.02093505859375 -0.1141357421875 0.8162963867187517 +0.567125 -0.02093505859375 -0.1141357421875 0.8162963867187517 +0.56725 -0.021881103515625 -0.119232177734375 0.8162963867187517 +0.567375 -0.0228271484375 -0.124298095703125 0.8162963867187517 +0.5675 -0.0228271484375 -0.124298095703125 0.8162963867187517 +0.567625 -0.02374267578125 -0.129364013671875 0.8162963867187517 +0.56775 -0.02374267578125 -0.129364013671875 0.8162963867187517 +0.567875 -0.024658203125 -0.134429931640625 0.8162963867187517 +0.5680000000000001 -0.025604248046875 -0.13946533203125 0.8162963867187517 +0.568125 -0.025604248046875 -0.13946533203125 0.8162963867187517 +0.56825 -0.026519775390625 -0.14447021484375 0.8162963867187517 +0.568375 -0.026519775390625 -0.14447021484375 0.8162963867187517 +0.5685 -0.027435302734375 -0.14947509765625 0.8162963867187517 +0.568625 -0.028350830078125 -0.15447998046875 0.8162963867187517 +0.56875 -0.028350830078125 -0.15447998046875 0.8162963867187517 +0.568875 -0.029266357421875 -0.159454345703125 0.8162963867187517 +0.5690000000000001 -0.029266357421875 -0.159454345703125 0.8162963867187517 +0.569125 -0.030181884765625 -0.164398193359375 0.8162963867187517 +0.56925 -0.031097412109375 -0.169342041015625 0.8162963867187517 +0.569375 -0.031097412109375 -0.169342041015625 0.8162963867187517 +0.5695 -0.031982421875 -0.17425537109375 0.8162963867187517 +0.569625 -0.031982421875 -0.17425537109375 0.8162963867187517 +0.56975 -0.03289794921875 -0.17913818359375 0.8162963867187517 +0.569875 -0.033782958984375 -0.18402099609375 0.8162963867187517 +0.5700000000000001 -0.033782958984375 -0.18402099609375 0.8162963867187517 +0.570125 -0.03466796875 -0.188873291015625 0.8162963867187517 +0.57025 -0.03466796875 -0.188873291015625 0.8162963867187517 +0.570375 -0.035552978515625 -0.1937255859375 0.8162963867187517 +0.5705 -0.03643798828125 -0.19854736328125 0.8162963867187517 +0.570625 -0.03643798828125 -0.19854736328125 0.8162963867187517 +0.57075 -0.037322998046875 -0.203338623046875 0.8162963867187517 +0.570875 -0.037322998046875 -0.203338623046875 0.8162963867187517 +0.5710000000000001 -0.0382080078125 -0.208099365234375 0.8162963867187517 +0.571125 -0.0390625 -0.212860107421875 0.8162963867187517 +0.57125 -0.0390625 -0.212860107421875 0.8162963867187517 +0.571375 -0.039947509765625 -0.21759033203125 0.8162963867187517 +0.5715 -0.039947509765625 -0.21759033203125 0.8162963867187517 +0.571625 -0.040802001953125 -0.2222900390625 0.8162963867187517 +0.57175 -0.041656494140625 -0.226959228515625 0.8162963867187517 +0.571875 -0.041656494140625 -0.226959228515625 0.8162963867187517 +0.5720000000000001 -0.042510986328125 -0.231597900390625 0.8162963867187517 +0.572125 -0.042510986328125 -0.231597900390625 0.8162963867187517 +0.57225 -0.043365478515625 -0.236236572265625 0.8162963867187517 +0.572375 -0.044219970703125 -0.2408447265625 0.8162963867187517 +0.5725 -0.044219970703125 -0.2408447265625 0.8162963867187517 +0.5726250000000001 -0.0450439453125 -0.24542236328125 0.8162963867187517 +0.57275 -0.0450439453125 -0.24542236328125 0.8162963867187517 +0.572875 -0.0458984375 -0.249969482421875 0.8162963867187517 +0.5730000000000001 -0.046722412109375 -0.25445556640625 0.8162963867187517 +0.573125 -0.046722412109375 -0.25445556640625 0.8162963867187517 +0.57325 -0.04754638671875 -0.25897216796875 0.8162963867187517 +0.573375 -0.04754638671875 -0.25897216796875 0.8162963867187517 +0.5735 -0.048370361328125 -0.263427734375 0.8162963867187517 +0.5736250000000001 -0.049163818359375 -0.267852783203125 0.8162963867187517 +0.57375 -0.049163818359375 -0.267852783203125 0.8162963867187517 +0.573875 -0.04998779296875 -0.27227783203125 0.8162963867187517 +0.5740000000000001 -0.04998779296875 -0.27227783203125 0.8162963867187517 +0.574125 -0.05078125 -0.276641845703125 0.8162963867187517 +0.57425 -0.05157470703125 -0.280975341796875 0.8162963867187517 +0.574375 -0.05157470703125 -0.280975341796875 0.8162963867187517 +0.5745 -0.0523681640625 -0.285308837890625 0.8162963867187517 +0.5746250000000001 -0.0523681640625 -0.285308837890625 0.8162963867187517 +0.57475 -0.05316162109375 -0.289581298828125 0.8162963867187517 +0.574875 -0.053955078125 -0.2938232421875 0.8162963867187517 +0.5750000000000001 -0.053955078125 -0.2938232421875 0.8162963867187517 +0.575125 -0.054718017578125 -0.298065185546875 0.8162963867187517 +0.57525 -0.054718017578125 -0.298065185546875 0.8162963867187517 +0.575375 -0.05548095703125 -0.30224609375 0.8162963867187517 +0.5755 -0.056243896484375 -0.306396484375 0.8162963867187517 +0.5756250000000001 -0.056243896484375 -0.306396484375 0.8162963867187517 +0.57575 -0.0570068359375 -0.310516357421875 0.8162963867187517 +0.575875 -0.0570068359375 -0.310516357421875 0.8162963867187517 +0.5760000000000001 -0.00714111328125 -0.314605712890625 0.9771972656250006 +0.576125 -0.007232666015625 -0.31866455078125 0.9771972656250006 +0.57625 -0.007232666015625 -0.31866455078125 0.9771972656250006 +0.576375 -0.00732421875 -0.322662353515625 0.9771972656250006 +0.5765 -0.00732421875 -0.322662353515625 0.9771972656250006 +0.5766250000000001 -0.007415771484375 -0.32666015625 0.9771972656250006 +0.57675 -0.007476806640625 -0.330596923828125 0.9771972656250006 +0.576875 -0.007476806640625 -0.330596923828125 0.9771972656250006 +0.577 -0.007568359375 -0.334503173828125 0.9771972656250006 +0.577125 -0.007568359375 -0.334503173828125 0.9771972656250006 +0.57725 -0.007659912109375 -0.33837890625 0.9771972656250006 +0.577375 -0.00775146484375 -0.34222412109375 0.9771972656250006 +0.5775 -0.00775146484375 -0.34222412109375 0.9771972656250006 +0.5776250000000001 -0.007843017578125 -0.34600830078125 0.9771972656250006 +0.57775 -0.007843017578125 -0.34600830078125 0.9771972656250006 +0.577875 -0.0079345703125 -0.349761962890625 0.9771972656250006 +0.578 -0.008026123046875 -0.353485107421875 0.9771972656250006 +0.578125 -0.008026123046875 -0.353485107421875 0.9771972656250006 +0.57825 -0.008087158203125 -0.357177734375 0.9771972656250006 +0.578375 -0.008087158203125 -0.357177734375 0.9771972656250006 +0.5785 -0.0081787109375 -0.360809326171875 0.9771972656250006 +0.5786250000000001 -0.008270263671875 -0.36444091796875 0.9771972656250006 +0.57875 -0.008270263671875 -0.36444091796875 0.9771972656250006 +0.578875 -0.008331298828125 -0.36798095703125 0.9771972656250006 +0.579 -0.008331298828125 -0.36798095703125 0.9771972656250006 +0.579125 -0.0084228515625 -0.37152099609375 0.9771972656250006 +0.57925 -0.008514404296875 -0.375 0.9771972656250006 +0.579375 -0.008514404296875 -0.375 0.9771972656250006 +0.5795 -0.008575439453125 -0.378448486328125 0.9771972656250006 +0.5796250000000001 -0.008575439453125 -0.378448486328125 0.9771972656250006 +0.57975 -0.0086669921875 -0.3818359375 0.9771972656250006 +0.579875 -0.00872802734375 -0.38519287109375 0.9771972656250006 +0.58 -0.00872802734375 -0.38519287109375 0.9771972656250006 +0.580125 -0.008819580078125 -0.388519287109375 0.9771972656250006 +0.58025 -0.008819580078125 -0.388519287109375 0.9771972656250006 +0.580375 -0.008880615234375 -0.39178466796875 0.9771972656250006 +0.5805 -0.008941650390625 -0.39501953125 0.9771972656250006 +0.5806250000000001 -0.008941650390625 -0.39501953125 0.9771972656250006 +0.58075 -0.009033203125 -0.398193359375 0.9771972656250006 +0.580875 -0.009033203125 -0.398193359375 0.9771972656250006 +0.581 -0.00909423828125 -0.401336669921875 0.9771972656250006 +0.581125 -0.0091552734375 -0.404449462890625 0.9771972656250006 +0.58125 -0.0091552734375 -0.404449462890625 0.9771972656250006 +0.581375 -0.009246826171875 -0.407501220703125 0.9771972656250006 +0.5815 -0.009246826171875 -0.407501220703125 0.9771972656250006 +0.5816250000000001 -0.009307861328125 -0.4105224609375 0.9771972656250006 +0.58175 -0.009368896484375 -0.413482666015625 0.9771972656250006 +0.581875 -0.009368896484375 -0.413482666015625 0.9771972656250006 +0.582 -0.009429931640625 -0.416412353515625 0.9771972656250006 +0.582125 -0.009429931640625 -0.416412353515625 0.9771972656250006 +0.58225 -0.009490966796875 -0.419281005859375 0.9771972656250006 +0.582375 -0.00958251953125 -0.422119140625 0.9771972656250006 +0.5825 -0.00958251953125 -0.422119140625 0.9771972656250006 +0.5826250000000001 -0.0096435546875 -0.424896240234375 0.9771972656250006 +0.58275 -0.0096435546875 -0.424896240234375 0.9771972656250006 +0.582875 -0.00970458984375 -0.4276123046875 0.9771972656250006 +0.583 -0.009765625 -0.4302978515625 0.9771972656250006 +0.583125 -0.009765625 -0.4302978515625 0.9771972656250006 +0.58325 -0.00982666015625 -0.432952880859375 0.9771972656250006 +0.583375 -0.00982666015625 -0.432952880859375 0.9771972656250006 +0.5835 -0.0098876953125 -0.435546875 0.9771972656250006 +0.5836250000000001 -0.009918212890625 -0.438079833984375 0.9771972656250006 +0.58375 -0.009918212890625 -0.438079833984375 0.9771972656250006 +0.583875 -0.009979248046875 -0.440582275390625 0.9771972656250006 +0.584 -0.009979248046875 -0.440582275390625 0.9771972656250006 +0.584125 -0.010040283203125 -0.44305419921875 0.9771972656250006 +0.58425 -0.010101318359375 -0.4454345703125 0.9771972656250006 +0.584375 -0.010101318359375 -0.4454345703125 0.9771972656250006 +0.5845 -0.010162353515625 -0.447784423828125 0.9771972656250006 +0.5846250000000001 -0.010162353515625 -0.447784423828125 0.9771972656250006 +0.58475 -0.01019287109375 -0.450103759765625 0.9771972656250006 +0.584875 -0.01025390625 -0.452362060546875 0.9771972656250006 +0.585 -0.01025390625 -0.452362060546875 0.9771972656250006 +0.585125 -0.01031494140625 -0.454559326171875 0.9771972656250006 +0.58525 -0.01031494140625 -0.454559326171875 0.9771972656250006 +0.585375 -0.010345458984375 -0.45672607421875 0.9771972656250006 +0.5855 -0.010406494140625 -0.458831787109375 0.9771972656250006 +0.5856250000000001 -0.010406494140625 -0.458831787109375 0.9771972656250006 +0.58575 -0.01043701171875 -0.46087646484375 0.9771972656250006 +0.585875 -0.01043701171875 -0.46087646484375 0.9771972656250006 +0.586 -0.010498046875 -0.462890625 0.9771972656250006 +0.586125 -0.010528564453125 -0.464813232421875 0.9771972656250006 +0.58625 -0.010528564453125 -0.464813232421875 0.9771972656250006 +0.586375 -0.010589599609375 -0.46673583984375 0.9771972656250006 +0.5865 -0.010589599609375 -0.46673583984375 0.9771972656250006 +0.5866250000000001 -0.0106201171875 -0.46856689453125 0.9771972656250006 +0.58675 -0.010650634765625 -0.470367431640625 0.9771972656250006 +0.586875 -0.010650634765625 -0.470367431640625 0.9771972656250006 +0.587 -0.010711669921875 -0.472137451171875 0.9771972656250006 +0.587125 -0.010711669921875 -0.472137451171875 0.9771972656250006 +0.58725 -0.0107421875 -0.47381591796875 0.9771972656250006 +0.587375 -0.010772705078125 -0.4754638671875 0.9771972656250006 +0.5875 -0.010772705078125 -0.4754638671875 0.9771972656250006 +0.5876250000000001 -0.01080322265625 -0.47705078125 0.9771972656250006 +0.58775 -0.01080322265625 -0.47705078125 0.9771972656250006 +0.587875 -0.0108642578125 -0.478607177734375 0.9771972656250006 +0.588 -0.010894775390625 -0.480072021484375 0.9771972656250006 +0.588125 -0.010894775390625 -0.480072021484375 0.9771972656250006 +0.5882500000000001 -0.01092529296875 -0.48150634765625 0.9771972656250006 +0.588375 -0.01092529296875 -0.48150634765625 0.9771972656250006 +0.5885 -0.010955810546875 -0.48291015625 0.9771972656250006 +0.5886250000000001 -0.010986328125 -0.484222412109375 0.9771972656250006 +0.58875 -0.010986328125 -0.484222412109375 0.9771972656250006 +0.588875 -0.011016845703125 -0.485504150390625 0.9771972656250006 +0.589 -0.011016845703125 -0.485504150390625 0.9771972656250006 +0.589125 -0.01104736328125 -0.486724853515625 0.9771972656250006 +0.5892500000000001 -0.011077880859375 -0.487884521484375 0.9771972656250006 +0.589375 -0.011077880859375 -0.487884521484375 0.9771972656250006 +0.5895 -0.011077880859375 -0.489013671875 0.9771972656250006 +0.5896250000000001 -0.011077880859375 -0.489013671875 0.9771972656250006 +0.58975 -0.0111083984375 -0.490081787109375 0.9771972656250006 +0.589875 -0.011138916015625 -0.4910888671875 0.9771972656250006 +0.59 -0.011138916015625 -0.4910888671875 0.9771972656250006 +0.590125 -0.01116943359375 -0.492034912109375 0.9771972656250006 +0.5902500000000001 -0.01116943359375 -0.492034912109375 0.9771972656250006 +0.590375 -0.01116943359375 -0.492950439453125 0.9771972656250006 +0.5905 -0.011199951171875 -0.4937744140625 0.9771972656250006 +0.5906250000000001 -0.011199951171875 -0.4937744140625 0.9771972656250006 +0.59075 -0.011199951171875 -0.49456787109375 0.9771972656250006 +0.590875 -0.011199951171875 -0.49456787109375 0.9771972656250006 +0.591 -0.01123046875 -0.49530029296875 0.9771972656250006 +0.591125 -0.011260986328125 -0.496002197265625 0.9771972656250006 +0.5912500000000001 -0.011260986328125 -0.496002197265625 0.9771972656250006 +0.591375 -0.011260986328125 -0.496612548828125 0.9771972656250006 +0.5915 -0.011260986328125 -0.496612548828125 0.9771972656250006 +0.5916250000000001 -0.011260986328125 -0.4971923828125 0.9771972656250006 +0.59175 -0.01129150390625 -0.497711181640625 0.9771972656250006 +0.591875 -0.01129150390625 -0.497711181640625 0.9771972656250006 +0.592 -0.01129150390625 -0.498199462890625 0.9771972656250006 +0.592125 -0.01129150390625 -0.498199462890625 0.9771972656250006 +0.5922500000000001 -0.01129150390625 -0.49859619140625 0.9771972656250006 +0.592375 -0.011322021484375 -0.49896240234375 0.9771972656250006 +0.5925 -0.011322021484375 -0.49896240234375 0.9771972656250006 +0.592625 -0.011322021484375 -0.499267578125 0.9771972656250006 +0.59275 -0.011322021484375 -0.499267578125 0.9771972656250006 +0.592875 -0.011322021484375 -0.49951171875 0.9771972656250006 +0.593 -0.011322021484375 -0.49969482421875 0.9771972656250006 +0.593125 -0.011322021484375 -0.49969482421875 0.9771972656250006 +0.5932500000000001 -0.011322021484375 -0.49981689453125 0.9771972656250006 +0.593375 -0.011322021484375 -0.49981689453125 0.9771972656250006 +0.5935 -0.011322021484375 -0.499908447265625 0.9771972656250006 +0.593625 -0.011322021484375 -0.49993896484375 0.9771972656250006 +0.59375 -0.011322021484375 -0.49993896484375 0.9771972656250006 +0.593875 -0.011322021484375 -0.499908447265625 0.9771972656250006 +0.594 -0.011322021484375 -0.499908447265625 0.9771972656250006 +0.594125 -0.011322021484375 -0.49981689453125 0.9771972656250006 +0.5942500000000001 -0.011322021484375 -0.49969482421875 0.9771972656250006 +0.594375 -0.011322021484375 -0.49969482421875 0.9771972656250006 +0.5945 -0.011322021484375 -0.49951171875 0.9771972656250006 +0.594625 -0.011322021484375 -0.49951171875 0.9771972656250006 +0.59475 -0.011322021484375 -0.499267578125 0.9771972656250006 +0.594875 -0.011322021484375 -0.49896240234375 0.9771972656250006 +0.595 -0.011322021484375 -0.49896240234375 0.9771972656250006 +0.595125 -0.01129150390625 -0.49859619140625 0.9771972656250006 +0.5952500000000001 -0.01129150390625 -0.49859619140625 0.9771972656250006 +0.595375 -0.01129150390625 -0.498199462890625 0.9771972656250006 +0.5955 -0.01129150390625 -0.497711181640625 0.9771972656250006 +0.595625 -0.01129150390625 -0.497711181640625 0.9771972656250006 +0.59575 -0.011260986328125 -0.4971923828125 0.9771972656250006 +0.595875 -0.011260986328125 -0.4971923828125 0.9771972656250006 +0.596 -0.011260986328125 -0.496612548828125 0.9771972656250006 +0.596125 -0.011260986328125 -0.496002197265625 0.9771972656250006 +0.5962500000000001 -0.011260986328125 -0.496002197265625 0.9771972656250006 +0.596375 -0.01123046875 -0.49530029296875 0.9771972656250006 +0.5965 -0.01123046875 -0.49530029296875 0.9771972656250006 +0.596625 -0.011199951171875 -0.49456787109375 0.9771972656250006 +0.59675 -0.011199951171875 -0.4937744140625 0.9771972656250006 +0.596875 -0.011199951171875 -0.4937744140625 0.9771972656250006 +0.597 -0.01116943359375 -0.492950439453125 0.9771972656250006 +0.597125 -0.01116943359375 -0.492950439453125 0.9771972656250006 +0.5972500000000001 -0.01116943359375 -0.492034912109375 0.9771972656250006 +0.597375 -0.011138916015625 -0.4910888671875 0.9771972656250006 +0.5975 -0.011138916015625 -0.4910888671875 0.9771972656250006 +0.597625 -0.0111083984375 -0.490081787109375 0.9771972656250006 +0.59775 -0.0111083984375 -0.490081787109375 0.9771972656250006 +0.597875 -0.011077880859375 -0.489013671875 0.9771972656250006 +0.598 -0.011077880859375 -0.487884521484375 0.9771972656250006 +0.598125 -0.011077880859375 -0.487884521484375 0.9771972656250006 +0.5982500000000001 -0.01104736328125 -0.486724853515625 0.9771972656250006 +0.598375 -0.01104736328125 -0.486724853515625 0.9771972656250006 +0.5985 -0.011016845703125 -0.485504150390625 0.9771972656250006 +0.598625 -0.010986328125 -0.484222412109375 0.9771972656250006 +0.59875 -0.010986328125 -0.484222412109375 0.9771972656250006 +0.598875 -0.010955810546875 -0.48291015625 0.9771972656250006 +0.599 -0.010955810546875 -0.48291015625 0.9771972656250006 +0.599125 -0.01092529296875 -0.48150634765625 0.9771972656250006 +0.5992500000000001 -0.010894775390625 -0.480072021484375 0.9771972656250006 +0.599375 -0.010894775390625 -0.480072021484375 0.9771972656250006 +0.5995 -0.0108642578125 -0.478607177734375 0.9771972656250006 +0.599625 -0.0108642578125 -0.478607177734375 0.9771972656250006 +0.59975 -0.01080322265625 -0.47705078125 0.9771972656250006 +0.599875 -0.010772705078125 -0.4754638671875 0.9771972656250006 +0.6 -0.010772705078125 -0.4754638671875 0.9771972656250006 +0.600125 -0.0107421875 -0.47381591796875 0.9771972656250006 +0.6002500000000001 -0.0107421875 -0.47381591796875 0.9771972656250006 +0.600375 -0.010711669921875 -0.472137451171875 0.9771972656250006 +0.6005 -0.010650634765625 -0.470367431640625 0.9771972656250006 +0.600625 -0.010650634765625 -0.470367431640625 0.9771972656250006 +0.60075 -0.0106201171875 -0.46856689453125 0.9771972656250006 +0.600875 -0.0106201171875 -0.46856689453125 0.9771972656250006 +0.601 -0.010589599609375 -0.46673583984375 0.9771972656250006 +0.601125 -0.010528564453125 -0.464813232421875 0.9771972656250006 +0.6012500000000001 -0.010528564453125 -0.464813232421875 0.9771972656250006 +0.601375 -0.010498046875 -0.462890625 0.9771972656250006 +0.6015 -0.010498046875 -0.462890625 0.9771972656250006 +0.601625 -0.01043701171875 -0.46087646484375 0.9771972656250006 +0.60175 -0.010406494140625 -0.458831787109375 0.9771972656250006 +0.601875 -0.010406494140625 -0.458831787109375 0.9771972656250006 +0.602 -0.010345458984375 -0.45672607421875 0.9771972656250006 +0.602125 -0.010345458984375 -0.45672607421875 0.9771972656250006 +0.6022500000000001 -0.01031494140625 -0.454559326171875 0.9771972656250006 +0.602375 -0.01025390625 -0.452362060546875 0.9771972656250006 +0.6025 -0.01025390625 -0.452362060546875 0.9771972656250006 +0.602625 -0.01019287109375 -0.450103759765625 0.9771972656250006 +0.60275 -0.01019287109375 -0.450103759765625 0.9771972656250006 +0.602875 -0.010162353515625 -0.447784423828125 0.9771972656250006 +0.603 -0.010101318359375 -0.4454345703125 0.9771972656250006 +0.603125 -0.010101318359375 -0.4454345703125 0.9771972656250006 +0.6032500000000001 -0.010040283203125 -0.44305419921875 0.9771972656250006 +0.603375 -0.010040283203125 -0.44305419921875 0.9771972656250006 +0.6035 -0.009979248046875 -0.440582275390625 0.9771972656250006 +0.603625 -0.009918212890625 -0.438079833984375 0.9771972656250006 +0.60375 -0.009918212890625 -0.438079833984375 0.9771972656250006 +0.6038750000000001 -0.0098876953125 -0.435546875 0.9771972656250006 +0.604 -0.0098876953125 -0.435546875 0.9771972656250006 +0.604125 -0.00982666015625 -0.432952880859375 0.9771972656250006 +0.6042500000000001 -0.009765625 -0.4302978515625 0.9771972656250006 +0.604375 -0.009765625 -0.4302978515625 0.9771972656250006 +0.6045 -0.00970458984375 -0.4276123046875 0.9771972656250006 +0.604625 -0.00970458984375 -0.4276123046875 0.9771972656250006 +0.60475 -0.0096435546875 -0.424896240234375 0.9771972656250006 +0.6048750000000001 -0.00958251953125 -0.422119140625 0.9771972656250006 +0.605 -0.00958251953125 -0.422119140625 0.9771972656250006 +0.605125 -0.009490966796875 -0.419281005859375 0.9771972656250006 +0.6052500000000001 -0.009490966796875 -0.419281005859375 0.9771972656250006 +0.605375 -0.009429931640625 -0.416412353515625 0.9771972656250006 +0.6055 -0.009368896484375 -0.413482666015625 0.9771972656250006 +0.605625 -0.009368896484375 -0.413482666015625 0.9771972656250006 +0.60575 -0.009307861328125 -0.4105224609375 0.9771972656250006 +0.6058750000000001 -0.009307861328125 -0.4105224609375 0.9771972656250006 +0.606 -0.009246826171875 -0.407501220703125 0.9771972656250006 +0.606125 -0.0091552734375 -0.404449462890625 0.9771972656250006 +0.6062500000000001 -0.0091552734375 -0.404449462890625 0.9771972656250006 +0.606375 -0.00909423828125 -0.401336669921875 0.9771972656250006 +0.6065 -0.00909423828125 -0.401336669921875 0.9771972656250006 +0.606625 -0.009033203125 -0.398193359375 0.9771972656250006 +0.60675 -0.008941650390625 -0.39501953125 0.9771972656250006 +0.6068750000000001 -0.008941650390625 -0.39501953125 0.9771972656250006 +0.607 -0.008880615234375 -0.39178466796875 0.9771972656250006 +0.607125 -0.008880615234375 -0.39178466796875 0.9771972656250006 +0.6072500000000001 -0.008819580078125 -0.388519287109375 0.9771972656250006 +0.607375 -0.00872802734375 -0.38519287109375 0.9771972656250006 +0.6075 -0.00872802734375 -0.38519287109375 0.9771972656250006 +0.607625 -0.0086669921875 -0.3818359375 0.9771972656250006 +0.60775 -0.0086669921875 -0.3818359375 0.9771972656250006 +0.6078750000000001 -0.008575439453125 -0.378448486328125 0.9771972656250006 +0.608 -0.006622314453125 -0.375 0.9822387695312494 +0.608125 -0.006622314453125 -0.375 0.9822387695312494 +0.60825 -0.006561279296875 -0.37152099609375 0.9822387695312494 +0.608375 -0.006561279296875 -0.37152099609375 0.9822387695312494 +0.6085 -0.006500244140625 -0.36798095703125 0.9822387695312494 +0.608625 -0.006439208984375 -0.36444091796875 0.9822387695312494 +0.60875 -0.006439208984375 -0.36444091796875 0.9822387695312494 +0.6088750000000001 -0.00634765625 -0.360809326171875 0.9822387695312494 +0.609 -0.00634765625 -0.360809326171875 0.9822387695312494 +0.609125 -0.00628662109375 -0.357177734375 0.9822387695312494 +0.60925 -0.0062255859375 -0.353485107421875 0.9822387695312494 +0.609375 -0.0062255859375 -0.353485107421875 0.9822387695312494 +0.6095 -0.00616455078125 -0.349761962890625 0.9822387695312494 +0.609625 -0.00616455078125 -0.349761962890625 0.9822387695312494 +0.60975 -0.006103515625 -0.34600830078125 0.9822387695312494 +0.6098750000000001 -0.00604248046875 -0.34222412109375 0.9822387695312494 +0.61 -0.00604248046875 -0.34222412109375 0.9822387695312494 +0.610125 -0.005950927734375 -0.33837890625 0.9822387695312494 +0.61025 -0.005950927734375 -0.33837890625 0.9822387695312494 +0.610375 -0.005889892578125 -0.334503173828125 0.9822387695312494 +0.6105 -0.005828857421875 -0.330596923828125 0.9822387695312494 +0.610625 -0.005828857421875 -0.330596923828125 0.9822387695312494 +0.61075 -0.005767822265625 -0.32666015625 0.9822387695312494 +0.6108750000000001 -0.005767822265625 -0.32666015625 0.9822387695312494 +0.611 -0.00567626953125 -0.322662353515625 0.9822387695312494 +0.611125 -0.005615234375 -0.31866455078125 0.9822387695312494 +0.61125 -0.005615234375 -0.31866455078125 0.9822387695312494 +0.611375 -0.00555419921875 -0.314605712890625 0.9822387695312494 +0.6115 -0.00555419921875 -0.314605712890625 0.9822387695312494 +0.611625 -0.005462646484375 -0.310516357421875 0.9822387695312494 +0.61175 -0.005401611328125 -0.306396484375 0.9822387695312494 +0.6118750000000001 -0.005401611328125 -0.306396484375 0.9822387695312494 +0.612 -0.005340576171875 -0.30224609375 0.9822387695312494 +0.612125 -0.005340576171875 -0.30224609375 0.9822387695312494 +0.61225 -0.0052490234375 -0.298065185546875 0.9822387695312494 +0.612375 -0.00518798828125 -0.2938232421875 0.9822387695312494 +0.6125 -0.00518798828125 -0.2938232421875 0.9822387695312494 +0.612625 -0.005096435546875 -0.289581298828125 0.9822387695312494 +0.61275 -0.005096435546875 -0.289581298828125 0.9822387695312494 +0.6128750000000001 -0.005035400390625 -0.285308837890625 0.9822387695312494 +0.613 -0.00494384765625 -0.280975341796875 0.9822387695312494 +0.613125 -0.00494384765625 -0.280975341796875 0.9822387695312494 +0.61325 -0.0048828125 -0.276641845703125 0.9822387695312494 +0.613375 -0.0048828125 -0.276641845703125 0.9822387695312494 +0.6135 -0.004791259765625 -0.27227783203125 0.9822387695312494 +0.613625 -0.004730224609375 -0.267852783203125 0.9822387695312494 +0.61375 -0.004730224609375 -0.267852783203125 0.9822387695312494 +0.6138750000000001 -0.004638671875 -0.263427734375 0.9822387695312494 +0.614 -0.004638671875 -0.263427734375 0.9822387695312494 +0.614125 -0.004547119140625 -0.25897216796875 0.9822387695312494 +0.61425 -0.004486083984375 -0.25445556640625 0.9822387695312494 +0.614375 -0.004486083984375 -0.25445556640625 0.9822387695312494 +0.6145 -0.00439453125 -0.249969482421875 0.9822387695312494 +0.614625 -0.00439453125 -0.249969482421875 0.9822387695312494 +0.61475 -0.00433349609375 -0.24542236328125 0.9822387695312494 +0.6148750000000001 -0.004241943359375 -0.2408447265625 0.9822387695312494 +0.615 -0.004241943359375 -0.2408447265625 0.9822387695312494 +0.615125 -0.004150390625 -0.236236572265625 0.9822387695312494 +0.61525 -0.004150390625 -0.236236572265625 0.9822387695312494 +0.615375 -0.00408935546875 -0.231597900390625 0.9822387695312494 +0.6155 -0.003997802734375 -0.226959228515625 0.9822387695312494 +0.615625 -0.003997802734375 -0.226959228515625 0.9822387695312494 +0.61575 -0.00390625 -0.2222900390625 0.9822387695312494 +0.6158750000000001 -0.00390625 -0.2222900390625 0.9822387695312494 +0.616 -0.003814697265625 -0.21759033203125 0.9822387695312494 +0.616125 -0.003753662109375 -0.212860107421875 0.9822387695312494 +0.61625 -0.003753662109375 -0.212860107421875 0.9822387695312494 +0.616375 -0.003662109375 -0.208099365234375 0.9822387695312494 +0.6165 -0.003662109375 -0.208099365234375 0.9822387695312494 +0.616625 -0.003570556640625 -0.203338623046875 0.9822387695312494 +0.61675 -0.00347900390625 -0.19854736328125 0.9822387695312494 +0.6168750000000001 -0.00347900390625 -0.19854736328125 0.9822387695312494 +0.617 -0.00341796875 -0.1937255859375 0.9822387695312494 +0.617125 -0.00341796875 -0.1937255859375 0.9822387695312494 +0.61725 -0.003326416015625 -0.188873291015625 0.9822387695312494 +0.617375 -0.00323486328125 -0.18402099609375 0.9822387695312494 +0.6175 -0.00323486328125 -0.18402099609375 0.9822387695312494 +0.617625 -0.003143310546875 -0.17913818359375 0.9822387695312494 +0.61775 -0.003143310546875 -0.17913818359375 0.9822387695312494 +0.6178750000000001 -0.0030517578125 -0.17425537109375 0.9822387695312494 +0.618 -0.00299072265625 -0.169342041015625 0.9822387695312494 +0.618125 -0.00299072265625 -0.169342041015625 0.9822387695312494 +0.61825 -0.002899169921875 -0.164398193359375 0.9822387695312494 +0.618375 -0.002899169921875 -0.164398193359375 0.9822387695312494 +0.6185 -0.0028076171875 -0.159454345703125 0.9822387695312494 +0.618625 -0.002716064453125 -0.15447998046875 0.9822387695312494 +0.61875 -0.002716064453125 -0.15447998046875 0.9822387695312494 +0.6188750000000001 -0.00262451171875 -0.14947509765625 0.9822387695312494 +0.619 -0.00262451171875 -0.14947509765625 0.9822387695312494 +0.619125 -0.002532958984375 -0.14447021484375 0.9822387695312494 +0.61925 -0.00244140625 -0.13946533203125 0.9822387695312494 +0.619375 -0.00244140625 -0.13946533203125 0.9822387695312494 +0.6195000000000001 -0.002349853515625 -0.134429931640625 0.9822387695312494 +0.619625 -0.002349853515625 -0.134429931640625 0.9822387695312494 +0.61975 -0.00225830078125 -0.129364013671875 0.9822387695312494 +0.6198750000000001 -0.002166748046875 -0.124298095703125 0.9822387695312494 +0.62 -0.002166748046875 -0.124298095703125 0.9822387695312494 +0.620125 -0.002105712890625 -0.119232177734375 0.9822387695312494 +0.62025 -0.002105712890625 -0.119232177734375 0.9822387695312494 +0.620375 -0.00201416015625 -0.1141357421875 0.9822387695312494 +0.6205000000000001 -0.001922607421875 -0.109039306640625 0.9822387695312494 +0.620625 -0.001922607421875 -0.109039306640625 0.9822387695312494 +0.62075 -0.0018310546875 -0.103912353515625 0.9822387695312494 +0.6208750000000001 -0.0018310546875 -0.103912353515625 0.9822387695312494 +0.621 -0.001739501953125 -0.098785400390625 0.9822387695312494 +0.621125 -0.00164794921875 -0.093658447265625 0.9822387695312494 +0.62125 -0.00164794921875 -0.093658447265625 0.9822387695312494 +0.621375 -0.001556396484375 -0.0885009765625 0.9822387695312494 +0.6215000000000001 -0.001556396484375 -0.0885009765625 0.9822387695312494 +0.621625 -0.00146484375 -0.083343505859375 0.9822387695312494 +0.62175 -0.001373291015625 -0.07818603515625 0.9822387695312494 +0.6218750000000001 -0.001373291015625 -0.07818603515625 0.9822387695312494 +0.622 -0.00128173828125 -0.072998046875 0.9822387695312494 +0.622125 -0.00128173828125 -0.072998046875 0.9822387695312494 +0.62225 -0.001190185546875 -0.06781005859375 0.9822387695312494 +0.622375 -0.0010986328125 -0.0626220703125 0.9822387695312494 +0.6225000000000001 -0.0010986328125 -0.0626220703125 0.9822387695312494 +0.622625 -0.001007080078125 -0.05743408203125 0.9822387695312494 +0.62275 -0.001007080078125 -0.05743408203125 0.9822387695312494 +0.6228750000000001 -0.00091552734375 -0.05224609375 0.9822387695312494 +0.623 -0.000823974609375 -0.047027587890625 0.9822387695312494 +0.623125 -0.000823974609375 -0.047027587890625 0.9822387695312494 +0.62325 -0.000732421875 -0.04180908203125 0.9822387695312494 +0.623375 -0.000732421875 -0.04180908203125 0.9822387695312494 +0.6235000000000001 -0.000640869140625 -0.036590576171875 0.9822387695312494 +0.623625 -0.00054931640625 -0.0313720703125 0.9822387695312494 +0.62375 -0.00054931640625 -0.0313720703125 0.9822387695312494 +0.6238750000000001 -0.000457763671875 -0.026123046875 0.9822387695312494 +0.624 -0.000457763671875 -0.026123046875 0.9822387695312494 +0.624125 -0.0003662109375 -0.020904541015625 0.9822387695312494 +0.62425 -0.000274658203125 -0.01568603515625 0.9822387695312494 +0.624375 -0.000274658203125 -0.01568603515625 0.9822387695312494 +0.6245000000000001 -0.00018310546875 -0.01043701171875 0.9822387695312494 +0.624625 -0.00018310546875 -0.01043701171875 0.9822387695312494 +0.62475 -9.1552734375e-05 -0.005218505859375 0.9822387695312494 +0.624875 0.0 0.0 0.9822387695312494 +0.625 0.0 0.0 0.9822387695312494 +0.625125 9.1552734375e-05 0.005218505859375 0.9822387695312494 +0.62525 9.1552734375e-05 0.005218505859375 0.9822387695312494 +0.625375 0.00018310546875 0.01043701171875 0.9822387695312494 +0.6255000000000001 0.000274658203125 0.01568603515625 0.9822387695312494 +0.625625 0.000274658203125 0.01568603515625 0.9822387695312494 +0.62575 0.0003662109375 0.020904541015625 0.9822387695312494 +0.625875 0.0003662109375 0.020904541015625 0.9822387695312494 +0.626 0.000457763671875 0.026123046875 0.9822387695312494 +0.626125 0.00054931640625 0.0313720703125 0.9822387695312494 +0.62625 0.00054931640625 0.0313720703125 0.9822387695312494 +0.626375 0.000640869140625 0.036590576171875 0.9822387695312494 +0.6265000000000001 0.000640869140625 0.036590576171875 0.9822387695312494 +0.626625 0.000732421875 0.04180908203125 0.9822387695312494 +0.62675 0.000823974609375 0.047027587890625 0.9822387695312494 +0.626875 0.000823974609375 0.047027587890625 0.9822387695312494 +0.627 0.00091552734375 0.05224609375 0.9822387695312494 +0.627125 0.00091552734375 0.05224609375 0.9822387695312494 +0.62725 0.001007080078125 0.05743408203125 0.9822387695312494 +0.627375 0.0010986328125 0.0626220703125 0.9822387695312494 +0.6275000000000001 0.0010986328125 0.0626220703125 0.9822387695312494 +0.627625 0.001190185546875 0.06781005859375 0.9822387695312494 +0.62775 0.001190185546875 0.06781005859375 0.9822387695312494 +0.627875 0.00128173828125 0.072998046875 0.9822387695312494 +0.628 0.001373291015625 0.07818603515625 0.9822387695312494 +0.628125 0.001373291015625 0.07818603515625 0.9822387695312494 +0.62825 0.00146484375 0.083343505859375 0.9822387695312494 +0.628375 0.00146484375 0.083343505859375 0.9822387695312494 +0.6285000000000001 0.001556396484375 0.0885009765625 0.9822387695312494 +0.628625 0.00164794921875 0.093658447265625 0.9822387695312494 +0.62875 0.00164794921875 0.093658447265625 0.9822387695312494 +0.628875 0.001739501953125 0.098785400390625 0.9822387695312494 +0.629 0.001739501953125 0.098785400390625 0.9822387695312494 +0.629125 0.0018310546875 0.103912353515625 0.9822387695312494 +0.62925 0.001922607421875 0.109039306640625 0.9822387695312494 +0.629375 0.001922607421875 0.109039306640625 0.9822387695312494 +0.6295000000000001 0.00201416015625 0.1141357421875 0.9822387695312494 +0.629625 0.00201416015625 0.1141357421875 0.9822387695312494 +0.62975 0.002105712890625 0.119232177734375 0.9822387695312494 +0.629875 0.002166748046875 0.124298095703125 0.9822387695312494 +0.63 0.002166748046875 0.124298095703125 0.9822387695312494 +0.630125 0.00225830078125 0.129364013671875 0.9822387695312494 +0.63025 0.00225830078125 0.129364013671875 0.9822387695312494 +0.630375 0.002349853515625 0.134429931640625 0.9822387695312494 +0.6305000000000001 0.00244140625 0.13946533203125 0.9822387695312494 +0.630625 0.00244140625 0.13946533203125 0.9822387695312494 +0.63075 0.002532958984375 0.14447021484375 0.9822387695312494 +0.630875 0.002532958984375 0.14447021484375 0.9822387695312494 +0.631 0.00262451171875 0.14947509765625 0.9822387695312494 +0.631125 0.002716064453125 0.15447998046875 0.9822387695312494 +0.63125 0.002716064453125 0.15447998046875 0.9822387695312494 +0.631375 0.0028076171875 0.159454345703125 0.9822387695312494 +0.6315000000000001 0.0028076171875 0.159454345703125 0.9822387695312494 +0.631625 0.002899169921875 0.164398193359375 0.9822387695312494 +0.63175 0.00299072265625 0.169342041015625 0.9822387695312494 +0.631875 0.00299072265625 0.169342041015625 0.9822387695312494 +0.632 0.0030517578125 0.17425537109375 0.9822387695312494 +0.632125 0.0030517578125 0.17425537109375 0.9822387695312494 +0.63225 0.003143310546875 0.17913818359375 0.9822387695312494 +0.632375 0.00323486328125 0.18402099609375 0.9822387695312494 +0.6325000000000001 0.00323486328125 0.18402099609375 0.9822387695312494 +0.632625 0.003326416015625 0.188873291015625 0.9822387695312494 +0.63275 0.003326416015625 0.188873291015625 0.9822387695312494 +0.632875 0.00341796875 0.1937255859375 0.9822387695312494 +0.633 0.00347900390625 0.19854736328125 0.9822387695312494 +0.633125 0.00347900390625 0.19854736328125 0.9822387695312494 +0.63325 0.003570556640625 0.203338623046875 0.9822387695312494 +0.633375 0.003570556640625 0.203338623046875 0.9822387695312494 +0.6335000000000001 0.003662109375 0.208099365234375 0.9822387695312494 +0.633625 0.003753662109375 0.212860107421875 0.9822387695312494 +0.63375 0.003753662109375 0.212860107421875 0.9822387695312494 +0.633875 0.003814697265625 0.21759033203125 0.9822387695312494 +0.634 0.003814697265625 0.21759033203125 0.9822387695312494 +0.634125 0.00390625 0.2222900390625 0.9822387695312494 +0.63425 0.003997802734375 0.226959228515625 0.9822387695312494 +0.634375 0.003997802734375 0.226959228515625 0.9822387695312494 +0.6345000000000001 0.00408935546875 0.231597900390625 0.9822387695312494 +0.634625 0.00408935546875 0.231597900390625 0.9822387695312494 +0.63475 0.004150390625 0.236236572265625 0.9822387695312494 +0.634875 0.004241943359375 0.2408447265625 0.9822387695312494 +0.635 0.004241943359375 0.2408447265625 0.9822387695312494 +0.6351250000000001 0.00433349609375 0.24542236328125 0.9822387695312494 +0.63525 0.00433349609375 0.24542236328125 0.9822387695312494 +0.635375 0.00439453125 0.249969482421875 0.9822387695312494 +0.6355000000000001 0.004486083984375 0.25445556640625 0.9822387695312494 +0.635625 0.004486083984375 0.25445556640625 0.9822387695312494 +0.63575 0.004547119140625 0.25897216796875 0.9822387695312494 +0.635875 0.004547119140625 0.25897216796875 0.9822387695312494 +0.636 0.004638671875 0.263427734375 0.9822387695312494 +0.6361250000000001 0.004730224609375 0.267852783203125 0.9822387695312494 +0.63625 0.004730224609375 0.267852783203125 0.9822387695312494 +0.636375 0.004791259765625 0.27227783203125 0.9822387695312494 +0.6365000000000001 0.004791259765625 0.27227783203125 0.9822387695312494 +0.636625 0.0048828125 0.276641845703125 0.9822387695312494 +0.63675 0.00494384765625 0.280975341796875 0.9822387695312494 +0.636875 0.00494384765625 0.280975341796875 0.9822387695312494 +0.637 0.005035400390625 0.285308837890625 0.9822387695312494 +0.6371250000000001 0.005035400390625 0.285308837890625 0.9822387695312494 +0.63725 0.005096435546875 0.289581298828125 0.9822387695312494 +0.637375 0.00518798828125 0.2938232421875 0.9822387695312494 +0.6375000000000001 0.00518798828125 0.2938232421875 0.9822387695312494 +0.637625 0.0052490234375 0.298065185546875 0.9822387695312494 +0.63775 0.0052490234375 0.298065185546875 0.9822387695312494 +0.637875 0.005340576171875 0.30224609375 0.9822387695312494 +0.638 0.005401611328125 0.306396484375 0.9822387695312494 +0.6381250000000001 0.005401611328125 0.306396484375 0.9822387695312494 +0.63825 0.005462646484375 0.310516357421875 0.9822387695312494 +0.638375 0.005462646484375 0.310516357421875 0.9822387695312494 +0.6385000000000001 0.00555419921875 0.314605712890625 0.9822387695312494 +0.638625 0.005615234375 0.31866455078125 0.9822387695312494 +0.63875 0.005615234375 0.31866455078125 0.9822387695312494 +0.638875 0.00567626953125 0.322662353515625 0.9822387695312494 +0.639 0.00567626953125 0.322662353515625 0.9822387695312494 +0.6391250000000001 0.005767822265625 0.32666015625 0.9822387695312494 +0.63925 0.005828857421875 0.330596923828125 0.9822387695312494 +0.639375 0.005828857421875 0.330596923828125 0.9822387695312494 +0.6395000000000001 0.005889892578125 0.334503173828125 0.9822387695312494 +0.639625 0.005889892578125 0.334503173828125 0.9822387695312494 +0.63975 0.005950927734375 0.33837890625 0.9822387695312494 +0.639875 0.00604248046875 0.34222412109375 0.9822387695312494 +0.64 0.057952880859375 0.34222412109375 0.8305419921874982 +0.6401250000000001 0.05859375 0.34600830078125 0.8305419921874982 +0.64025 0.05859375 0.34600830078125 0.8305419921874982 +0.640375 0.059234619140625 0.349761962890625 0.8305419921874982 +0.6405 0.05987548828125 0.353485107421875 0.8305419921874982 +0.640625 0.05987548828125 0.353485107421875 0.8305419921874982 +0.64075 0.06048583984375 0.357177734375 0.8305419921874982 +0.640875 0.06048583984375 0.357177734375 0.8305419921874982 +0.641 0.06109619140625 0.360809326171875 0.8305419921874982 +0.6411250000000001 0.06170654296875 0.36444091796875 0.8305419921874982 +0.64125 0.06170654296875 0.36444091796875 0.8305419921874982 +0.641375 0.06231689453125 0.36798095703125 0.8305419921874982 +0.6415 0.06231689453125 0.36798095703125 0.8305419921874982 +0.641625 0.06292724609375 0.37152099609375 0.8305419921874982 +0.64175 0.063507080078125 0.375 0.8305419921874982 +0.641875 0.063507080078125 0.375 0.8305419921874982 +0.642 0.0640869140625 0.378448486328125 0.8305419921874982 +0.6421250000000001 0.0640869140625 0.378448486328125 0.8305419921874982 +0.64225 0.064666748046875 0.3818359375 0.8305419921874982 +0.642375 0.06524658203125 0.38519287109375 0.8305419921874982 +0.6425 0.06524658203125 0.38519287109375 0.8305419921874982 +0.642625 0.0657958984375 0.388519287109375 0.8305419921874982 +0.64275 0.0657958984375 0.388519287109375 0.8305419921874982 +0.642875 0.06634521484375 0.39178466796875 0.8305419921874982 +0.643 0.06689453125 0.39501953125 0.8305419921874982 +0.6431250000000001 0.06689453125 0.39501953125 0.8305419921874982 +0.64325 0.06744384765625 0.398193359375 0.8305419921874982 +0.643375 0.06744384765625 0.398193359375 0.8305419921874982 +0.6435 0.067962646484375 0.401336669921875 0.8305419921874982 +0.643625 0.0684814453125 0.404449462890625 0.8305419921874982 +0.64375 0.0684814453125 0.404449462890625 0.8305419921874982 +0.643875 0.069000244140625 0.407501220703125 0.8305419921874982 +0.644 0.069000244140625 0.407501220703125 0.8305419921874982 +0.6441250000000001 0.06951904296875 0.4105224609375 0.8305419921874982 +0.64425 0.07000732421875 0.413482666015625 0.8305419921874982 +0.644375 0.07000732421875 0.413482666015625 0.8305419921874982 +0.6445 0.070526123046875 0.416412353515625 0.8305419921874982 +0.644625 0.070526123046875 0.416412353515625 0.8305419921874982 +0.64475 0.071014404296875 0.419281005859375 0.8305419921874982 +0.644875 0.07147216796875 0.422119140625 0.8305419921874982 +0.645 0.07147216796875 0.422119140625 0.8305419921874982 +0.6451250000000001 0.07196044921875 0.424896240234375 0.8305419921874982 +0.64525 0.07196044921875 0.424896240234375 0.8305419921874982 +0.645375 0.072418212890625 0.4276123046875 0.8305419921874982 +0.6455 0.0728759765625 0.4302978515625 0.8305419921874982 +0.645625 0.0728759765625 0.4302978515625 0.8305419921874982 +0.64575 0.073333740234375 0.432952880859375 0.8305419921874982 +0.645875 0.073333740234375 0.432952880859375 0.8305419921874982 +0.646 0.073760986328125 0.435546875 0.8305419921874982 +0.6461250000000001 0.074188232421875 0.438079833984375 0.8305419921874982 +0.64625 0.074188232421875 0.438079833984375 0.8305419921874982 +0.646375 0.074615478515625 0.440582275390625 0.8305419921874982 +0.6465 0.074615478515625 0.440582275390625 0.8305419921874982 +0.646625 0.075042724609375 0.44305419921875 0.8305419921874982 +0.64675 0.075439453125 0.4454345703125 0.8305419921874982 +0.646875 0.075439453125 0.4454345703125 0.8305419921874982 +0.647 0.075836181640625 0.447784423828125 0.8305419921874982 +0.6471250000000001 0.075836181640625 0.447784423828125 0.8305419921874982 +0.64725 0.07623291015625 0.450103759765625 0.8305419921874982 +0.647375 0.07659912109375 0.452362060546875 0.8305419921874982 +0.6475 0.07659912109375 0.452362060546875 0.8305419921874982 +0.647625 0.07696533203125 0.454559326171875 0.8305419921874982 +0.64775 0.07696533203125 0.454559326171875 0.8305419921874982 +0.647875 0.07733154296875 0.45672607421875 0.8305419921874982 +0.648 0.07769775390625 0.458831787109375 0.8305419921874982 +0.6481250000000001 0.07769775390625 0.458831787109375 0.8305419921874982 +0.64825 0.07806396484375 0.46087646484375 0.8305419921874982 +0.648375 0.07806396484375 0.46087646484375 0.8305419921874982 +0.6485 0.078399658203125 0.462890625 0.8305419921874982 +0.648625 0.078704833984375 0.464813232421875 0.8305419921874982 +0.64875 0.078704833984375 0.464813232421875 0.8305419921874982 +0.648875 0.07904052734375 0.46673583984375 0.8305419921874982 +0.649 0.07904052734375 0.46673583984375 0.8305419921874982 +0.6491250000000001 0.079345703125 0.46856689453125 0.8305419921874982 +0.64925 0.07965087890625 0.470367431640625 0.8305419921874982 +0.649375 0.07965087890625 0.470367431640625 0.8305419921874982 +0.6495 0.0799560546875 0.472137451171875 0.8305419921874982 +0.649625 0.0799560546875 0.472137451171875 0.8305419921874982 +0.64975 0.080230712890625 0.47381591796875 0.8305419921874982 +0.649875 0.080535888671875 0.4754638671875 0.8305419921874982 +0.65 0.080535888671875 0.4754638671875 0.8305419921874982 +0.6501250000000001 0.080780029296875 0.47705078125 0.8305419921874982 +0.65025 0.080780029296875 0.47705078125 0.8305419921874982 +0.650375 0.0810546875 0.478607177734375 0.8305419921874982 +0.6505 0.081298828125 0.480072021484375 0.8305419921874982 +0.650625 0.081298828125 0.480072021484375 0.8305419921874982 +0.6507500000000001 0.08154296875 0.48150634765625 0.8305419921874982 +0.650875 0.08154296875 0.48150634765625 0.8305419921874982 +0.651 0.081787109375 0.48291015625 0.8305419921874982 +0.6511250000000001 0.082000732421875 0.484222412109375 0.8305419921874982 +0.65125 0.082000732421875 0.484222412109375 0.8305419921874982 +0.651375 0.08221435546875 0.485504150390625 0.8305419921874982 +0.6515 0.08221435546875 0.485504150390625 0.8305419921874982 +0.651625 0.082427978515625 0.486724853515625 0.8305419921874982 +0.6517500000000001 0.0826416015625 0.487884521484375 0.8305419921874982 +0.651875 0.0826416015625 0.487884521484375 0.8305419921874982 +0.652 0.08282470703125 0.489013671875 0.8305419921874982 +0.6521250000000001 0.08282470703125 0.489013671875 0.8305419921874982 +0.65225 0.0830078125 0.490081787109375 0.8305419921874982 +0.652375 0.083160400390625 0.4910888671875 0.8305419921874982 +0.6525 0.083160400390625 0.4910888671875 0.8305419921874982 +0.652625 0.083343505859375 0.492034912109375 0.8305419921874982 +0.6527500000000001 0.083343505859375 0.492034912109375 0.8305419921874982 +0.652875 0.08349609375 0.492950439453125 0.8305419921874982 +0.653 0.0836181640625 0.4937744140625 0.8305419921874982 +0.6531250000000001 0.0836181640625 0.4937744140625 0.8305419921874982 +0.65325 0.083770751953125 0.49456787109375 0.8305419921874982 +0.653375 0.083770751953125 0.49456787109375 0.8305419921874982 +0.6535 0.083892822265625 0.49530029296875 0.8305419921874982 +0.653625 0.083984375 0.496002197265625 0.8305419921874982 +0.6537500000000001 0.083984375 0.496002197265625 0.8305419921874982 +0.653875 0.0841064453125 0.496612548828125 0.8305419921874982 +0.654 0.0841064453125 0.496612548828125 0.8305419921874982 +0.6541250000000001 0.084197998046875 0.4971923828125 0.8305419921874982 +0.65425 0.08428955078125 0.497711181640625 0.8305419921874982 +0.654375 0.08428955078125 0.497711181640625 0.8305419921874982 +0.6545 0.084381103515625 0.498199462890625 0.8305419921874982 +0.654625 0.084381103515625 0.498199462890625 0.8305419921874982 +0.6547500000000001 0.084442138671875 0.49859619140625 0.8305419921874982 +0.654875 0.084503173828125 0.49896240234375 0.8305419921874982 +0.655 0.084503173828125 0.49896240234375 0.8305419921874982 +0.6551250000000001 0.084564208984375 0.499267578125 0.8305419921874982 +0.65525 0.084564208984375 0.499267578125 0.8305419921874982 +0.655375 0.0845947265625 0.49951171875 0.8305419921874982 +0.6555 0.084625244140625 0.49969482421875 0.8305419921874982 +0.655625 0.084625244140625 0.49969482421875 0.8305419921874982 +0.6557500000000001 0.08465576171875 0.49981689453125 0.8305419921874982 +0.655875 0.08465576171875 0.49981689453125 0.8305419921874982 +0.656 0.08465576171875 0.499908447265625 0.8305419921874982 +0.656125 0.08465576171875 0.49993896484375 0.8305419921874982 +0.65625 0.08465576171875 0.49993896484375 0.8305419921874982 +0.656375 0.08465576171875 0.499908447265625 0.8305419921874982 +0.6565 0.08465576171875 0.499908447265625 0.8305419921874982 +0.656625 0.08465576171875 0.49981689453125 0.8305419921874982 +0.6567500000000001 0.084625244140625 0.49969482421875 0.8305419921874982 +0.656875 0.084625244140625 0.49969482421875 0.8305419921874982 +0.657 0.0845947265625 0.49951171875 0.8305419921874982 +0.657125 0.0845947265625 0.49951171875 0.8305419921874982 +0.65725 0.084564208984375 0.499267578125 0.8305419921874982 +0.657375 0.084503173828125 0.49896240234375 0.8305419921874982 +0.6575 0.084503173828125 0.49896240234375 0.8305419921874982 +0.657625 0.084442138671875 0.49859619140625 0.8305419921874982 +0.6577500000000001 0.084442138671875 0.49859619140625 0.8305419921874982 +0.657875 0.084381103515625 0.498199462890625 0.8305419921874982 +0.658 0.08428955078125 0.497711181640625 0.8305419921874982 +0.658125 0.08428955078125 0.497711181640625 0.8305419921874982 +0.65825 0.084197998046875 0.4971923828125 0.8305419921874982 +0.658375 0.084197998046875 0.4971923828125 0.8305419921874982 +0.6585 0.0841064453125 0.496612548828125 0.8305419921874982 +0.658625 0.083984375 0.496002197265625 0.8305419921874982 +0.6587500000000001 0.083984375 0.496002197265625 0.8305419921874982 +0.658875 0.083892822265625 0.49530029296875 0.8305419921874982 +0.659 0.083892822265625 0.49530029296875 0.8305419921874982 +0.659125 0.083770751953125 0.49456787109375 0.8305419921874982 +0.65925 0.0836181640625 0.4937744140625 0.8305419921874982 +0.659375 0.0836181640625 0.4937744140625 0.8305419921874982 +0.6595 0.08349609375 0.492950439453125 0.8305419921874982 +0.659625 0.08349609375 0.492950439453125 0.8305419921874982 +0.6597500000000001 0.083343505859375 0.492034912109375 0.8305419921874982 +0.659875 0.083160400390625 0.4910888671875 0.8305419921874982 +0.66 0.083160400390625 0.4910888671875 0.8305419921874982 +0.660125 0.0830078125 0.490081787109375 0.8305419921874982 +0.66025 0.0830078125 0.490081787109375 0.8305419921874982 +0.660375 0.08282470703125 0.489013671875 0.8305419921874982 +0.6605 0.0826416015625 0.487884521484375 0.8305419921874982 +0.660625 0.0826416015625 0.487884521484375 0.8305419921874982 +0.6607500000000001 0.082427978515625 0.486724853515625 0.8305419921874982 +0.660875 0.082427978515625 0.486724853515625 0.8305419921874982 +0.661 0.08221435546875 0.485504150390625 0.8305419921874982 +0.661125 0.082000732421875 0.484222412109375 0.8305419921874982 +0.66125 0.082000732421875 0.484222412109375 0.8305419921874982 +0.661375 0.081787109375 0.48291015625 0.8305419921874982 +0.6615 0.081787109375 0.48291015625 0.8305419921874982 +0.661625 0.08154296875 0.48150634765625 0.8305419921874982 +0.6617500000000001 0.081298828125 0.480072021484375 0.8305419921874982 +0.661875 0.081298828125 0.480072021484375 0.8305419921874982 +0.662 0.0810546875 0.478607177734375 0.8305419921874982 +0.662125 0.0810546875 0.478607177734375 0.8305419921874982 +0.66225 0.080780029296875 0.47705078125 0.8305419921874982 +0.662375 0.080535888671875 0.4754638671875 0.8305419921874982 +0.6625 0.080535888671875 0.4754638671875 0.8305419921874982 +0.662625 0.080230712890625 0.47381591796875 0.8305419921874982 +0.6627500000000001 0.080230712890625 0.47381591796875 0.8305419921874982 +0.662875 0.0799560546875 0.472137451171875 0.8305419921874982 +0.663 0.07965087890625 0.470367431640625 0.8305419921874982 +0.663125 0.07965087890625 0.470367431640625 0.8305419921874982 +0.66325 0.079345703125 0.46856689453125 0.8305419921874982 +0.663375 0.079345703125 0.46856689453125 0.8305419921874982 +0.6635 0.07904052734375 0.46673583984375 0.8305419921874982 +0.663625 0.078704833984375 0.464813232421875 0.8305419921874982 +0.6637500000000001 0.078704833984375 0.464813232421875 0.8305419921874982 +0.663875 0.078399658203125 0.462890625 0.8305419921874982 +0.664 0.078399658203125 0.462890625 0.8305419921874982 +0.664125 0.07806396484375 0.46087646484375 0.8305419921874982 +0.66425 0.07769775390625 0.458831787109375 0.8305419921874982 +0.664375 0.07769775390625 0.458831787109375 0.8305419921874982 +0.6645 0.07733154296875 0.45672607421875 0.8305419921874982 +0.664625 0.07733154296875 0.45672607421875 0.8305419921874982 +0.6647500000000001 0.07696533203125 0.454559326171875 0.8305419921874982 +0.664875 0.07659912109375 0.452362060546875 0.8305419921874982 +0.665 0.07659912109375 0.452362060546875 0.8305419921874982 +0.665125 0.07623291015625 0.450103759765625 0.8305419921874982 +0.66525 0.07623291015625 0.450103759765625 0.8305419921874982 +0.665375 0.075836181640625 0.447784423828125 0.8305419921874982 +0.6655 0.075439453125 0.4454345703125 0.8305419921874982 +0.665625 0.075439453125 0.4454345703125 0.8305419921874982 +0.6657500000000001 0.075042724609375 0.44305419921875 0.8305419921874982 +0.665875 0.075042724609375 0.44305419921875 0.8305419921874982 +0.666 0.074615478515625 0.440582275390625 0.8305419921874982 +0.666125 0.074188232421875 0.438079833984375 0.8305419921874982 +0.66625 0.074188232421875 0.438079833984375 0.8305419921874982 +0.6663750000000001 0.073760986328125 0.435546875 0.8305419921874982 +0.6665 0.073760986328125 0.435546875 0.8305419921874982 +0.666625 0.073333740234375 0.432952880859375 0.8305419921874982 +0.6667500000000001 0.0728759765625 0.4302978515625 0.8305419921874982 +0.666875 0.0728759765625 0.4302978515625 0.8305419921874982 +0.667 0.072418212890625 0.4276123046875 0.8305419921874982 +0.667125 0.072418212890625 0.4276123046875 0.8305419921874982 +0.66725 0.07196044921875 0.424896240234375 0.8305419921874982 +0.6673750000000001 0.07147216796875 0.422119140625 0.8305419921874982 +0.6675 0.07147216796875 0.422119140625 0.8305419921874982 +0.667625 0.071014404296875 0.419281005859375 0.8305419921874982 +0.6677500000000001 0.071014404296875 0.419281005859375 0.8305419921874982 +0.667875 0.070526123046875 0.416412353515625 0.8305419921874982 +0.668 0.07000732421875 0.413482666015625 0.8305419921874982 +0.668125 0.07000732421875 0.413482666015625 0.8305419921874982 +0.66825 0.06951904296875 0.4105224609375 0.8305419921874982 +0.6683750000000001 0.06951904296875 0.4105224609375 0.8305419921874982 +0.6685 0.069000244140625 0.407501220703125 0.8305419921874982 +0.668625 0.0684814453125 0.404449462890625 0.8305419921874982 +0.6687500000000001 0.0684814453125 0.404449462890625 0.8305419921874982 +0.668875 0.067962646484375 0.401336669921875 0.8305419921874982 +0.669 0.067962646484375 0.401336669921875 0.8305419921874982 +0.669125 0.06744384765625 0.398193359375 0.8305419921874982 +0.66925 0.06689453125 0.39501953125 0.8305419921874982 +0.6693750000000001 0.06689453125 0.39501953125 0.8305419921874982 +0.6695 0.06634521484375 0.39178466796875 0.8305419921874982 +0.669625 0.06634521484375 0.39178466796875 0.8305419921874982 +0.6697500000000001 0.0657958984375 0.388519287109375 0.8305419921874982 +0.669875 0.06524658203125 0.38519287109375 0.8305419921874982 +0.67 0.06524658203125 0.38519287109375 0.8305419921874982 +0.670125 0.064666748046875 0.3818359375 0.8305419921874982 +0.67025 0.064666748046875 0.3818359375 0.8305419921874982 +0.6703750000000001 0.0640869140625 0.378448486328125 0.8305419921874982 +0.6705 0.063507080078125 0.375 0.8305419921874982 +0.670625 0.063507080078125 0.375 0.8305419921874982 +0.6707500000000001 0.06292724609375 0.37152099609375 0.8305419921874982 +0.670875 0.06292724609375 0.37152099609375 0.8305419921874982 +0.671 0.06231689453125 0.36798095703125 0.8305419921874982 +0.671125 0.06170654296875 0.36444091796875 0.8305419921874982 +0.67125 0.06170654296875 0.36444091796875 0.8305419921874982 +0.6713750000000001 0.06109619140625 0.360809326171875 0.8305419921874982 +0.6715 0.06109619140625 0.360809326171875 0.8305419921874982 +0.671625 0.06048583984375 0.357177734375 0.8305419921874982 +0.6717500000000001 0.05987548828125 0.353485107421875 0.8305419921874982 +0.671875 0.05987548828125 0.353485107421875 0.8305419921874982 +0.672 0.15863037109375 0.349761962890625 0.5463623046874974 +0.672125 0.15863037109375 0.349761962890625 0.5463623046874974 +0.67225 0.156951904296875 0.34600830078125 0.5463623046874974 +0.6723750000000001 0.15521240234375 0.34222412109375 0.5463623046874974 +0.6725 0.15521240234375 0.34222412109375 0.5463623046874974 +0.672625 0.153472900390625 0.33837890625 0.5463623046874974 +0.67275 0.153472900390625 0.33837890625 0.5463623046874974 +0.672875 0.1517333984375 0.334503173828125 0.5463623046874974 +0.673 0.14996337890625 0.330596923828125 0.5463623046874974 +0.673125 0.14996337890625 0.330596923828125 0.5463623046874974 +0.67325 0.148162841796875 0.32666015625 0.5463623046874974 +0.6733750000000001 0.148162841796875 0.32666015625 0.5463623046874974 +0.6735 0.1463623046875 0.322662353515625 0.5463623046874974 +0.673625 0.14453125 0.31866455078125 0.5463623046874974 +0.67375 0.14453125 0.31866455078125 0.5463623046874974 +0.673875 0.1427001953125 0.314605712890625 0.5463623046874974 +0.674 0.1427001953125 0.314605712890625 0.5463623046874974 +0.674125 0.140838623046875 0.310516357421875 0.5463623046874974 +0.67425 0.13897705078125 0.306396484375 0.5463623046874974 +0.6743750000000001 0.13897705078125 0.306396484375 0.5463623046874974 +0.6745 0.1370849609375 0.30224609375 0.5463623046874974 +0.674625 0.1370849609375 0.30224609375 0.5463623046874974 +0.67475 0.13519287109375 0.298065185546875 0.5463623046874974 +0.674875 0.133270263671875 0.2938232421875 0.5463623046874974 +0.675 0.133270263671875 0.2938232421875 0.5463623046874974 +0.675125 0.13134765625 0.289581298828125 0.5463623046874974 +0.67525 0.13134765625 0.289581298828125 0.5463623046874974 +0.6753750000000001 0.12939453125 0.285308837890625 0.5463623046874974 +0.6755 0.12744140625 0.280975341796875 0.5463623046874974 +0.675625 0.12744140625 0.280975341796875 0.5463623046874974 +0.67575 0.125457763671875 0.276641845703125 0.5463623046874974 +0.675875 0.125457763671875 0.276641845703125 0.5463623046874974 +0.676 0.123504638671875 0.27227783203125 0.5463623046874974 +0.676125 0.121490478515625 0.267852783203125 0.5463623046874974 +0.67625 0.121490478515625 0.267852783203125 0.5463623046874974 +0.6763750000000001 0.119476318359375 0.263427734375 0.5463623046874974 +0.6765 0.119476318359375 0.263427734375 0.5463623046874974 +0.676625 0.117462158203125 0.25897216796875 0.5463623046874974 +0.67675 0.11541748046875 0.25445556640625 0.5463623046874974 +0.676875 0.11541748046875 0.25445556640625 0.5463623046874974 +0.677 0.113372802734375 0.249969482421875 0.5463623046874974 +0.677125 0.113372802734375 0.249969482421875 0.5463623046874974 +0.67725 0.111297607421875 0.24542236328125 0.5463623046874974 +0.6773750000000001 0.109222412109375 0.2408447265625 0.5463623046874974 +0.6775 0.109222412109375 0.2408447265625 0.5463623046874974 +0.677625 0.107147216796875 0.236236572265625 0.5463623046874974 +0.67775 0.107147216796875 0.236236572265625 0.5463623046874974 +0.677875 0.10504150390625 0.231597900390625 0.5463623046874974 +0.678 0.102935791015625 0.226959228515625 0.5463623046874974 +0.678125 0.102935791015625 0.226959228515625 0.5463623046874974 +0.67825 0.100799560546875 0.2222900390625 0.5463623046874974 +0.6783750000000001 0.100799560546875 0.2222900390625 0.5463623046874974 +0.6785 0.09869384765625 0.21759033203125 0.5463623046874974 +0.678625 0.096527099609375 0.212860107421875 0.5463623046874974 +0.67875 0.096527099609375 0.212860107421875 0.5463623046874974 +0.678875 0.094390869140625 0.208099365234375 0.5463623046874974 +0.679 0.094390869140625 0.208099365234375 0.5463623046874974 +0.679125 0.09222412109375 0.203338623046875 0.5463623046874974 +0.67925 0.090057373046875 0.19854736328125 0.5463623046874974 +0.6793750000000001 0.090057373046875 0.19854736328125 0.5463623046874974 +0.6795 0.087860107421875 0.1937255859375 0.5463623046874974 +0.679625 0.087860107421875 0.1937255859375 0.5463623046874974 +0.67975 0.085662841796875 0.188873291015625 0.5463623046874974 +0.679875 0.083465576171875 0.18402099609375 0.5463623046874974 +0.68 0.083465576171875 0.18402099609375 0.5463623046874974 +0.680125 0.08123779296875 0.17913818359375 0.5463623046874974 +0.68025 0.08123779296875 0.17913818359375 0.5463623046874974 +0.6803750000000001 0.07904052734375 0.17425537109375 0.5463623046874974 +0.6805 0.0767822265625 0.169342041015625 0.5463623046874974 +0.680625 0.0767822265625 0.169342041015625 0.5463623046874974 +0.68075 0.074554443359375 0.164398193359375 0.5463623046874974 +0.680875 0.074554443359375 0.164398193359375 0.5463623046874974 +0.681 0.07232666015625 0.159454345703125 0.5463623046874974 +0.681125 0.070068359375 0.15447998046875 0.5463623046874974 +0.68125 0.070068359375 0.15447998046875 0.5463623046874974 +0.6813750000000001 0.067779541015625 0.14947509765625 0.5463623046874974 +0.6815 0.067779541015625 0.14947509765625 0.5463623046874974 +0.681625 0.065521240234375 0.14447021484375 0.5463623046874974 +0.68175 0.063232421875 0.13946533203125 0.5463623046874974 +0.681875 0.063232421875 0.13946533203125 0.5463623046874974 +0.6820000000000001 0.06097412109375 0.134429931640625 0.5463623046874974 +0.682125 0.06097412109375 0.134429931640625 0.5463623046874974 +0.68225 0.058685302734375 0.129364013671875 0.5463623046874974 +0.6823750000000001 0.056365966796875 0.124298095703125 0.5463623046874974 +0.6825 0.056365966796875 0.124298095703125 0.5463623046874974 +0.682625 0.0540771484375 0.119232177734375 0.5463623046874974 +0.68275 0.0540771484375 0.119232177734375 0.5463623046874974 +0.682875 0.0517578125 0.1141357421875 0.5463623046874974 +0.6830000000000001 0.0494384765625 0.109039306640625 0.5463623046874974 +0.683125 0.0494384765625 0.109039306640625 0.5463623046874974 +0.68325 0.047119140625 0.103912353515625 0.5463623046874974 +0.6833750000000001 0.047119140625 0.103912353515625 0.5463623046874974 +0.6835 0.0447998046875 0.098785400390625 0.5463623046874974 +0.683625 0.04248046875 0.093658447265625 0.5463623046874974 +0.68375 0.04248046875 0.093658447265625 0.5463623046874974 +0.683875 0.040130615234375 0.0885009765625 0.5463623046874974 +0.6840000000000001 0.040130615234375 0.0885009765625 0.5463623046874974 +0.684125 0.037811279296875 0.083343505859375 0.5463623046874974 +0.68425 0.03546142578125 0.07818603515625 0.5463623046874974 +0.6843750000000001 0.03546142578125 0.07818603515625 0.5463623046874974 +0.6845 0.033111572265625 0.072998046875 0.5463623046874974 +0.684625 0.033111572265625 0.072998046875 0.5463623046874974 +0.68475 0.03076171875 0.06781005859375 0.5463623046874974 +0.684875 0.028411865234375 0.0626220703125 0.5463623046874974 +0.6850000000000001 0.028411865234375 0.0626220703125 0.5463623046874974 +0.685125 0.02606201171875 0.05743408203125 0.5463623046874974 +0.68525 0.02606201171875 0.05743408203125 0.5463623046874974 +0.6853750000000001 0.023681640625 0.05224609375 0.5463623046874974 +0.6855 0.021331787109375 0.047027587890625 0.5463623046874974 +0.685625 0.021331787109375 0.047027587890625 0.5463623046874974 +0.68575 0.018951416015625 0.04180908203125 0.5463623046874974 +0.685875 0.018951416015625 0.04180908203125 0.5463623046874974 +0.6860000000000001 0.0166015625 0.036590576171875 0.5463623046874974 +0.686125 0.01422119140625 0.0313720703125 0.5463623046874974 +0.68625 0.01422119140625 0.0313720703125 0.5463623046874974 +0.6863750000000001 0.0118408203125 0.026123046875 0.5463623046874974 +0.6865 0.0118408203125 0.026123046875 0.5463623046874974 +0.686625 0.009490966796875 0.020904541015625 0.5463623046874974 +0.68675 0.007110595703125 0.01568603515625 0.5463623046874974 +0.686875 0.007110595703125 0.01568603515625 0.5463623046874974 +0.6870000000000001 0.004730224609375 0.01043701171875 0.5463623046874974 +0.687125 0.004730224609375 0.01043701171875 0.5463623046874974 +0.68725 0.002349853515625 0.005218505859375 0.5463623046874974 +0.6873750000000001 0.0 0.0 0.5463623046874974 +0.6875 0.0 0.0 0.5463623046874974 +0.687625 -0.002349853515625 -0.005218505859375 0.5463623046874974 +0.68775 -0.002349853515625 -0.005218505859375 0.5463623046874974 +0.687875 -0.004730224609375 -0.01043701171875 0.5463623046874974 +0.6880000000000001 -0.007110595703125 -0.01568603515625 0.5463623046874974 +0.688125 -0.007110595703125 -0.01568603515625 0.5463623046874974 +0.68825 -0.009490966796875 -0.020904541015625 0.5463623046874974 +0.688375 -0.009490966796875 -0.020904541015625 0.5463623046874974 +0.6885 -0.0118408203125 -0.026123046875 0.5463623046874974 +0.688625 -0.01422119140625 -0.0313720703125 0.5463623046874974 +0.68875 -0.01422119140625 -0.0313720703125 0.5463623046874974 +0.688875 -0.0166015625 -0.036590576171875 0.5463623046874974 +0.6890000000000001 -0.0166015625 -0.036590576171875 0.5463623046874974 +0.689125 -0.018951416015625 -0.04180908203125 0.5463623046874974 +0.68925 -0.021331787109375 -0.047027587890625 0.5463623046874974 +0.689375 -0.021331787109375 -0.047027587890625 0.5463623046874974 +0.6895 -0.023681640625 -0.05224609375 0.5463623046874974 +0.689625 -0.023681640625 -0.05224609375 0.5463623046874974 +0.68975 -0.02606201171875 -0.05743408203125 0.5463623046874974 +0.689875 -0.028411865234375 -0.0626220703125 0.5463623046874974 +0.6900000000000001 -0.028411865234375 -0.0626220703125 0.5463623046874974 +0.690125 -0.03076171875 -0.06781005859375 0.5463623046874974 +0.69025 -0.03076171875 -0.06781005859375 0.5463623046874974 +0.690375 -0.033111572265625 -0.072998046875 0.5463623046874974 +0.6905 -0.03546142578125 -0.07818603515625 0.5463623046874974 +0.690625 -0.03546142578125 -0.07818603515625 0.5463623046874974 +0.69075 -0.037811279296875 -0.083343505859375 0.5463623046874974 +0.690875 -0.037811279296875 -0.083343505859375 0.5463623046874974 +0.6910000000000001 -0.040130615234375 -0.0885009765625 0.5463623046874974 +0.691125 -0.04248046875 -0.093658447265625 0.5463623046874974 +0.69125 -0.04248046875 -0.093658447265625 0.5463623046874974 +0.691375 -0.0447998046875 -0.098785400390625 0.5463623046874974 +0.6915 -0.0447998046875 -0.098785400390625 0.5463623046874974 +0.691625 -0.047119140625 -0.103912353515625 0.5463623046874974 +0.69175 -0.0494384765625 -0.109039306640625 0.5463623046874974 +0.691875 -0.0494384765625 -0.109039306640625 0.5463623046874974 +0.6920000000000001 -0.0517578125 -0.1141357421875 0.5463623046874974 +0.692125 -0.0517578125 -0.1141357421875 0.5463623046874974 +0.69225 -0.0540771484375 -0.119232177734375 0.5463623046874974 +0.692375 -0.056365966796875 -0.124298095703125 0.5463623046874974 +0.6925 -0.056365966796875 -0.124298095703125 0.5463623046874974 +0.692625 -0.058685302734375 -0.129364013671875 0.5463623046874974 +0.69275 -0.058685302734375 -0.129364013671875 0.5463623046874974 +0.692875 -0.06097412109375 -0.134429931640625 0.5463623046874974 +0.6930000000000001 -0.063232421875 -0.13946533203125 0.5463623046874974 +0.693125 -0.063232421875 -0.13946533203125 0.5463623046874974 +0.69325 -0.065521240234375 -0.14447021484375 0.5463623046874974 +0.693375 -0.065521240234375 -0.14447021484375 0.5463623046874974 +0.6935 -0.067779541015625 -0.14947509765625 0.5463623046874974 +0.693625 -0.070068359375 -0.15447998046875 0.5463623046874974 +0.69375 -0.070068359375 -0.15447998046875 0.5463623046874974 +0.693875 -0.07232666015625 -0.159454345703125 0.5463623046874974 +0.6940000000000001 -0.07232666015625 -0.159454345703125 0.5463623046874974 +0.694125 -0.074554443359375 -0.164398193359375 0.5463623046874974 +0.69425 -0.0767822265625 -0.169342041015625 0.5463623046874974 +0.694375 -0.0767822265625 -0.169342041015625 0.5463623046874974 +0.6945 -0.07904052734375 -0.17425537109375 0.5463623046874974 +0.694625 -0.07904052734375 -0.17425537109375 0.5463623046874974 +0.69475 -0.08123779296875 -0.17913818359375 0.5463623046874974 +0.694875 -0.083465576171875 -0.18402099609375 0.5463623046874974 +0.6950000000000001 -0.083465576171875 -0.18402099609375 0.5463623046874974 +0.695125 -0.085662841796875 -0.188873291015625 0.5463623046874974 +0.69525 -0.085662841796875 -0.188873291015625 0.5463623046874974 +0.695375 -0.087860107421875 -0.1937255859375 0.5463623046874974 +0.6955 -0.090057373046875 -0.19854736328125 0.5463623046874974 +0.695625 -0.090057373046875 -0.19854736328125 0.5463623046874974 +0.69575 -0.09222412109375 -0.203338623046875 0.5463623046874974 +0.695875 -0.09222412109375 -0.203338623046875 0.5463623046874974 +0.6960000000000001 -0.094390869140625 -0.208099365234375 0.5463623046874974 +0.696125 -0.096527099609375 -0.212860107421875 0.5463623046874974 +0.69625 -0.096527099609375 -0.212860107421875 0.5463623046874974 +0.696375 -0.09869384765625 -0.21759033203125 0.5463623046874974 +0.6965 -0.09869384765625 -0.21759033203125 0.5463623046874974 +0.696625 -0.100799560546875 -0.2222900390625 0.5463623046874974 +0.69675 -0.102935791015625 -0.226959228515625 0.5463623046874974 +0.696875 -0.102935791015625 -0.226959228515625 0.5463623046874974 +0.6970000000000001 -0.10504150390625 -0.231597900390625 0.5463623046874974 +0.697125 -0.10504150390625 -0.231597900390625 0.5463623046874974 +0.69725 -0.107147216796875 -0.236236572265625 0.5463623046874974 +0.697375 -0.109222412109375 -0.2408447265625 0.5463623046874974 +0.6975 -0.109222412109375 -0.2408447265625 0.5463623046874974 +0.6976250000000001 -0.111297607421875 -0.24542236328125 0.5463623046874974 +0.69775 -0.111297607421875 -0.24542236328125 0.5463623046874974 +0.697875 -0.113372802734375 -0.249969482421875 0.5463623046874974 +0.6980000000000001 -0.11541748046875 -0.25445556640625 0.5463623046874974 +0.698125 -0.11541748046875 -0.25445556640625 0.5463623046874974 +0.69825 -0.117462158203125 -0.25897216796875 0.5463623046874974 +0.698375 -0.117462158203125 -0.25897216796875 0.5463623046874974 +0.6985 -0.119476318359375 -0.263427734375 0.5463623046874974 +0.6986250000000001 -0.121490478515625 -0.267852783203125 0.5463623046874974 +0.69875 -0.121490478515625 -0.267852783203125 0.5463623046874974 +0.698875 -0.123504638671875 -0.27227783203125 0.5463623046874974 +0.6990000000000001 -0.123504638671875 -0.27227783203125 0.5463623046874974 +0.699125 -0.125457763671875 -0.276641845703125 0.5463623046874974 +0.69925 -0.12744140625 -0.280975341796875 0.5463623046874974 +0.699375 -0.12744140625 -0.280975341796875 0.5463623046874974 +0.6995 -0.12939453125 -0.285308837890625 0.5463623046874974 +0.6996250000000001 -0.12939453125 -0.285308837890625 0.5463623046874974 +0.69975 -0.13134765625 -0.289581298828125 0.5463623046874974 +0.699875 -0.133270263671875 -0.2938232421875 0.5463623046874974 +0.7000000000000001 -0.133270263671875 -0.2938232421875 0.5463623046874974 +0.700125 -0.13519287109375 -0.298065185546875 0.5463623046874974 +0.70025 -0.13519287109375 -0.298065185546875 0.5463623046874974 +0.700375 -0.1370849609375 -0.30224609375 0.5463623046874974 +0.7005 -0.13897705078125 -0.306396484375 0.5463623046874974 +0.7006250000000001 -0.13897705078125 -0.306396484375 0.5463623046874974 +0.70075 -0.140838623046875 -0.310516357421875 0.5463623046874974 +0.700875 -0.140838623046875 -0.310516357421875 0.5463623046874974 +0.7010000000000001 -0.1427001953125 -0.314605712890625 0.5463623046874974 +0.701125 -0.14453125 -0.31866455078125 0.5463623046874974 +0.70125 -0.14453125 -0.31866455078125 0.5463623046874974 +0.701375 -0.1463623046875 -0.322662353515625 0.5463623046874974 +0.7015 -0.1463623046875 -0.322662353515625 0.5463623046874974 +0.7016250000000001 -0.148162841796875 -0.32666015625 0.5463623046874974 +0.70175 -0.14996337890625 -0.330596923828125 0.5463623046874974 +0.701875 -0.14996337890625 -0.330596923828125 0.5463623046874974 +0.7020000000000001 -0.1517333984375 -0.334503173828125 0.5463623046874974 +0.702125 -0.1517333984375 -0.334503173828125 0.5463623046874974 +0.70225 -0.153472900390625 -0.33837890625 0.5463623046874974 +0.702375 -0.15521240234375 -0.34222412109375 0.5463623046874974 +0.7025 -0.15521240234375 -0.34222412109375 0.5463623046874974 +0.7026250000000001 -0.156951904296875 -0.34600830078125 0.5463623046874974 +0.70275 -0.156951904296875 -0.34600830078125 0.5463623046874974 +0.702875 -0.15863037109375 -0.349761962890625 0.5463623046874974 +0.7030000000000001 -0.16033935546875 -0.353485107421875 0.5463623046874974 +0.703125 -0.16033935546875 -0.353485107421875 0.5463623046874974 +0.70325 -0.162017822265625 -0.357177734375 0.5463623046874974 +0.703375 -0.162017822265625 -0.357177734375 0.5463623046874974 +0.7035 -0.163665771484375 -0.360809326171875 0.5463623046874974 +0.7036250000000001 -0.165283203125 -0.36444091796875 0.5463623046874974 +0.70375 -0.165283203125 -0.36444091796875 0.5463623046874974 +0.703875 -0.166900634765625 -0.36798095703125 0.5463623046874974 +0.704 -0.3035888671875 -0.36798095703125 0.17499999999999718 +0.704125 -0.306488037109375 -0.37152099609375 0.17499999999999718 +0.70425 -0.309356689453125 -0.375 0.17499999999999718 +0.704375 -0.309356689453125 -0.375 0.17499999999999718 +0.7045 -0.31219482421875 -0.378448486328125 0.17499999999999718 +0.7046250000000001 -0.31219482421875 -0.378448486328125 0.17499999999999718 +0.70475 -0.31500244140625 -0.3818359375 0.17499999999999718 +0.704875 -0.317779541015625 -0.38519287109375 0.17499999999999718 +0.705 -0.317779541015625 -0.38519287109375 0.17499999999999718 +0.705125 -0.32049560546875 -0.388519287109375 0.17499999999999718 +0.70525 -0.32049560546875 -0.388519287109375 0.17499999999999718 +0.705375 -0.323211669921875 -0.39178466796875 0.17499999999999718 +0.7055 -0.325897216796875 -0.39501953125 0.17499999999999718 +0.7056250000000001 -0.325897216796875 -0.39501953125 0.17499999999999718 +0.70575 -0.3284912109375 -0.398193359375 0.17499999999999718 +0.705875 -0.3284912109375 -0.398193359375 0.17499999999999718 +0.706 -0.331085205078125 -0.401336669921875 0.17499999999999718 +0.706125 -0.333648681640625 -0.404449462890625 0.17499999999999718 +0.70625 -0.333648681640625 -0.404449462890625 0.17499999999999718 +0.706375 -0.336181640625 -0.407501220703125 0.17499999999999718 +0.7065 -0.336181640625 -0.407501220703125 0.17499999999999718 +0.7066250000000001 -0.338653564453125 -0.4105224609375 0.17499999999999718 +0.70675 -0.341094970703125 -0.413482666015625 0.17499999999999718 +0.706875 -0.341094970703125 -0.413482666015625 0.17499999999999718 +0.707 -0.343505859375 -0.416412353515625 0.17499999999999718 +0.707125 -0.343505859375 -0.416412353515625 0.17499999999999718 +0.70725 -0.34588623046875 -0.419281005859375 0.17499999999999718 +0.707375 -0.348236083984375 -0.422119140625 0.17499999999999718 +0.7075 -0.348236083984375 -0.422119140625 0.17499999999999718 +0.7076250000000001 -0.35052490234375 -0.424896240234375 0.17499999999999718 +0.70775 -0.35052490234375 -0.424896240234375 0.17499999999999718 +0.707875 -0.352783203125 -0.4276123046875 0.17499999999999718 +0.708 -0.35498046875 -0.4302978515625 0.17499999999999718 +0.708125 -0.35498046875 -0.4302978515625 0.17499999999999718 +0.70825 -0.357177734375 -0.432952880859375 0.17499999999999718 +0.708375 -0.357177734375 -0.432952880859375 0.17499999999999718 +0.7085 -0.35931396484375 -0.435546875 0.17499999999999718 +0.7086250000000001 -0.36138916015625 -0.438079833984375 0.17499999999999718 +0.70875 -0.36138916015625 -0.438079833984375 0.17499999999999718 +0.708875 -0.36346435546875 -0.440582275390625 0.17499999999999718 +0.709 -0.36346435546875 -0.440582275390625 0.17499999999999718 +0.709125 -0.365509033203125 -0.44305419921875 0.17499999999999718 +0.70925 -0.367462158203125 -0.4454345703125 0.17499999999999718 +0.709375 -0.367462158203125 -0.4454345703125 0.17499999999999718 +0.7095 -0.369415283203125 -0.447784423828125 0.17499999999999718 +0.7096250000000001 -0.369415283203125 -0.447784423828125 0.17499999999999718 +0.70975 -0.371307373046875 -0.450103759765625 0.17499999999999718 +0.709875 -0.3731689453125 -0.452362060546875 0.17499999999999718 +0.71 -0.3731689453125 -0.452362060546875 0.17499999999999718 +0.710125 -0.375 -0.454559326171875 0.17499999999999718 +0.71025 -0.375 -0.454559326171875 0.17499999999999718 +0.710375 -0.37677001953125 -0.45672607421875 0.17499999999999718 +0.7105 -0.378509521484375 -0.458831787109375 0.17499999999999718 +0.7106250000000001 -0.378509521484375 -0.458831787109375 0.17499999999999718 +0.71075 -0.38018798828125 -0.46087646484375 0.17499999999999718 +0.710875 -0.38018798828125 -0.46087646484375 0.17499999999999718 +0.711 -0.381866455078125 -0.462890625 0.17499999999999718 +0.711125 -0.383453369140625 -0.464813232421875 0.17499999999999718 +0.71125 -0.383453369140625 -0.464813232421875 0.17499999999999718 +0.711375 -0.385040283203125 -0.46673583984375 0.17499999999999718 +0.7115 -0.385040283203125 -0.46673583984375 0.17499999999999718 +0.7116250000000001 -0.386566162109375 -0.46856689453125 0.17499999999999718 +0.71175 -0.388031005859375 -0.470367431640625 0.17499999999999718 +0.711875 -0.388031005859375 -0.470367431640625 0.17499999999999718 +0.712 -0.389495849609375 -0.472137451171875 0.17499999999999718 +0.712125 -0.389495849609375 -0.472137451171875 0.17499999999999718 +0.71225 -0.390869140625 -0.47381591796875 0.17499999999999718 +0.712375 -0.392242431640625 -0.4754638671875 0.17499999999999718 +0.7125 -0.392242431640625 -0.4754638671875 0.17499999999999718 +0.7126250000000001 -0.3935546875 -0.47705078125 0.17499999999999718 +0.71275 -0.3935546875 -0.47705078125 0.17499999999999718 +0.712875 -0.39483642578125 -0.478607177734375 0.17499999999999718 +0.713 -0.39605712890625 -0.480072021484375 0.17499999999999718 +0.713125 -0.39605712890625 -0.480072021484375 0.17499999999999718 +0.7132500000000001 -0.397216796875 -0.48150634765625 0.17499999999999718 +0.713375 -0.397216796875 -0.48150634765625 0.17499999999999718 +0.7135 -0.39837646484375 -0.48291015625 0.17499999999999718 +0.7136250000000001 -0.39947509765625 -0.484222412109375 0.17499999999999718 +0.71375 -0.39947509765625 -0.484222412109375 0.17499999999999718 +0.713875 -0.4005126953125 -0.485504150390625 0.17499999999999718 +0.714 -0.4005126953125 -0.485504150390625 0.17499999999999718 +0.714125 -0.401519775390625 -0.486724853515625 0.17499999999999718 +0.7142500000000001 -0.402496337890625 -0.487884521484375 0.17499999999999718 +0.714375 -0.402496337890625 -0.487884521484375 0.17499999999999718 +0.7145 -0.403411865234375 -0.489013671875 0.17499999999999718 +0.7146250000000001 -0.403411865234375 -0.489013671875 0.17499999999999718 +0.71475 -0.404296875 -0.490081787109375 0.17499999999999718 +0.714875 -0.405120849609375 -0.4910888671875 0.17499999999999718 +0.715 -0.405120849609375 -0.4910888671875 0.17499999999999718 +0.715125 -0.405914306640625 -0.492034912109375 0.17499999999999718 +0.7152500000000001 -0.405914306640625 -0.492034912109375 0.17499999999999718 +0.715375 -0.406646728515625 -0.492950439453125 0.17499999999999718 +0.7155 -0.4073486328125 -0.4937744140625 0.17499999999999718 +0.7156250000000001 -0.4073486328125 -0.4937744140625 0.17499999999999718 +0.71575 -0.407989501953125 -0.49456787109375 0.17499999999999718 +0.715875 -0.407989501953125 -0.49456787109375 0.17499999999999718 +0.716 -0.408599853515625 -0.49530029296875 0.17499999999999718 +0.716125 -0.4091796875 -0.496002197265625 0.17499999999999718 +0.7162500000000001 -0.4091796875 -0.496002197265625 0.17499999999999718 +0.716375 -0.409698486328125 -0.496612548828125 0.17499999999999718 +0.7165 -0.409698486328125 -0.496612548828125 0.17499999999999718 +0.7166250000000001 -0.41015625 -0.4971923828125 0.17499999999999718 +0.71675 -0.41058349609375 -0.497711181640625 0.17499999999999718 +0.716875 -0.41058349609375 -0.497711181640625 0.17499999999999718 +0.717 -0.410980224609375 -0.498199462890625 0.17499999999999718 +0.717125 -0.410980224609375 -0.498199462890625 0.17499999999999718 +0.7172500000000001 -0.41131591796875 -0.49859619140625 0.17499999999999718 +0.717375 -0.41162109375 -0.49896240234375 0.17499999999999718 +0.7175 -0.41162109375 -0.49896240234375 0.17499999999999718 +0.7176250000000001 -0.411865234375 -0.499267578125 0.17499999999999718 +0.71775 -0.411865234375 -0.499267578125 0.17499999999999718 +0.717875 -0.412078857421875 -0.49951171875 0.17499999999999718 +0.718 -0.4122314453125 -0.49969482421875 0.17499999999999718 +0.718125 -0.4122314453125 -0.49969482421875 0.17499999999999718 +0.7182500000000001 -0.412322998046875 -0.49981689453125 0.17499999999999718 +0.718375 -0.412322998046875 -0.49981689453125 0.17499999999999718 +0.7185 -0.41241455078125 -0.499908447265625 0.17499999999999718 +0.7186250000000001 -0.412445068359375 -0.49993896484375 0.17499999999999718 +0.71875 -0.412445068359375 -0.49993896484375 0.17499999999999718 +0.718875 -0.41241455078125 -0.499908447265625 0.17499999999999718 +0.719 -0.41241455078125 -0.499908447265625 0.17499999999999718 +0.719125 -0.412322998046875 -0.49981689453125 0.17499999999999718 +0.7192500000000001 -0.4122314453125 -0.49969482421875 0.17499999999999718 +0.719375 -0.4122314453125 -0.49969482421875 0.17499999999999718 +0.7195 -0.412078857421875 -0.49951171875 0.17499999999999718 +0.7196250000000001 -0.412078857421875 -0.49951171875 0.17499999999999718 +0.71975 -0.411865234375 -0.499267578125 0.17499999999999718 +0.719875 -0.41162109375 -0.49896240234375 0.17499999999999718 +0.72 -0.41162109375 -0.49896240234375 0.17499999999999718 +0.720125 -0.41131591796875 -0.49859619140625 0.17499999999999718 +0.7202500000000001 -0.41131591796875 -0.49859619140625 0.17499999999999718 +0.720375 -0.410980224609375 -0.498199462890625 0.17499999999999718 +0.7205 -0.41058349609375 -0.497711181640625 0.17499999999999718 +0.720625 -0.41058349609375 -0.497711181640625 0.17499999999999718 +0.72075 -0.41015625 -0.4971923828125 0.17499999999999718 +0.720875 -0.41015625 -0.4971923828125 0.17499999999999718 +0.721 -0.409698486328125 -0.496612548828125 0.17499999999999718 +0.721125 -0.4091796875 -0.496002197265625 0.17499999999999718 +0.7212500000000001 -0.4091796875 -0.496002197265625 0.17499999999999718 +0.721375 -0.408599853515625 -0.49530029296875 0.17499999999999718 +0.7215 -0.408599853515625 -0.49530029296875 0.17499999999999718 +0.721625 -0.407989501953125 -0.49456787109375 0.17499999999999718 +0.72175 -0.4073486328125 -0.4937744140625 0.17499999999999718 +0.721875 -0.4073486328125 -0.4937744140625 0.17499999999999718 +0.722 -0.406646728515625 -0.492950439453125 0.17499999999999718 +0.722125 -0.406646728515625 -0.492950439453125 0.17499999999999718 +0.7222500000000001 -0.405914306640625 -0.492034912109375 0.17499999999999718 +0.722375 -0.405120849609375 -0.4910888671875 0.17499999999999718 +0.7225 -0.405120849609375 -0.4910888671875 0.17499999999999718 +0.722625 -0.404296875 -0.490081787109375 0.17499999999999718 +0.72275 -0.404296875 -0.490081787109375 0.17499999999999718 +0.722875 -0.403411865234375 -0.489013671875 0.17499999999999718 +0.723 -0.402496337890625 -0.487884521484375 0.17499999999999718 +0.723125 -0.402496337890625 -0.487884521484375 0.17499999999999718 +0.7232500000000001 -0.401519775390625 -0.486724853515625 0.17499999999999718 +0.723375 -0.401519775390625 -0.486724853515625 0.17499999999999718 +0.7235 -0.4005126953125 -0.485504150390625 0.17499999999999718 +0.723625 -0.39947509765625 -0.484222412109375 0.17499999999999718 +0.72375 -0.39947509765625 -0.484222412109375 0.17499999999999718 +0.723875 -0.39837646484375 -0.48291015625 0.17499999999999718 +0.724 -0.39837646484375 -0.48291015625 0.17499999999999718 +0.724125 -0.397216796875 -0.48150634765625 0.17499999999999718 +0.7242500000000001 -0.39605712890625 -0.480072021484375 0.17499999999999718 +0.724375 -0.39605712890625 -0.480072021484375 0.17499999999999718 +0.7245 -0.39483642578125 -0.478607177734375 0.17499999999999718 +0.724625 -0.39483642578125 -0.478607177734375 0.17499999999999718 +0.72475 -0.3935546875 -0.47705078125 0.17499999999999718 +0.724875 -0.392242431640625 -0.4754638671875 0.17499999999999718 +0.725 -0.392242431640625 -0.4754638671875 0.17499999999999718 +0.725125 -0.390869140625 -0.47381591796875 0.17499999999999718 +0.7252500000000001 -0.390869140625 -0.47381591796875 0.17499999999999718 +0.725375 -0.389495849609375 -0.472137451171875 0.17499999999999718 +0.7255 -0.388031005859375 -0.470367431640625 0.17499999999999718 +0.725625 -0.388031005859375 -0.470367431640625 0.17499999999999718 +0.72575 -0.386566162109375 -0.46856689453125 0.17499999999999718 +0.725875 -0.386566162109375 -0.46856689453125 0.17499999999999718 +0.726 -0.385040283203125 -0.46673583984375 0.17499999999999718 +0.726125 -0.383453369140625 -0.464813232421875 0.17499999999999718 +0.7262500000000001 -0.383453369140625 -0.464813232421875 0.17499999999999718 +0.726375 -0.381866455078125 -0.462890625 0.17499999999999718 +0.7265 -0.381866455078125 -0.462890625 0.17499999999999718 +0.726625 -0.38018798828125 -0.46087646484375 0.17499999999999718 +0.72675 -0.378509521484375 -0.458831787109375 0.17499999999999718 +0.726875 -0.378509521484375 -0.458831787109375 0.17499999999999718 +0.727 -0.37677001953125 -0.45672607421875 0.17499999999999718 +0.727125 -0.37677001953125 -0.45672607421875 0.17499999999999718 +0.7272500000000001 -0.375 -0.454559326171875 0.17499999999999718 +0.727375 -0.3731689453125 -0.452362060546875 0.17499999999999718 +0.7275 -0.3731689453125 -0.452362060546875 0.17499999999999718 +0.727625 -0.371307373046875 -0.450103759765625 0.17499999999999718 +0.72775 -0.371307373046875 -0.450103759765625 0.17499999999999718 +0.727875 -0.369415283203125 -0.447784423828125 0.17499999999999718 +0.728 -0.367462158203125 -0.4454345703125 0.17499999999999718 +0.728125 -0.367462158203125 -0.4454345703125 0.17499999999999718 +0.7282500000000001 -0.365509033203125 -0.44305419921875 0.17499999999999718 +0.728375 -0.365509033203125 -0.44305419921875 0.17499999999999718 +0.7285 -0.36346435546875 -0.440582275390625 0.17499999999999718 +0.728625 -0.36138916015625 -0.438079833984375 0.17499999999999718 +0.72875 -0.36138916015625 -0.438079833984375 0.17499999999999718 +0.7288750000000001 -0.35931396484375 -0.435546875 0.17499999999999718 +0.729 -0.35931396484375 -0.435546875 0.17499999999999718 +0.729125 -0.357177734375 -0.432952880859375 0.17499999999999718 +0.7292500000000001 -0.35498046875 -0.4302978515625 0.17499999999999718 +0.729375 -0.35498046875 -0.4302978515625 0.17499999999999718 +0.7295 -0.352783203125 -0.4276123046875 0.17499999999999718 +0.729625 -0.352783203125 -0.4276123046875 0.17499999999999718 +0.72975 -0.35052490234375 -0.424896240234375 0.17499999999999718 +0.7298750000000001 -0.348236083984375 -0.422119140625 0.17499999999999718 +0.73 -0.348236083984375 -0.422119140625 0.17499999999999718 +0.730125 -0.34588623046875 -0.419281005859375 0.17499999999999718 +0.7302500000000001 -0.34588623046875 -0.419281005859375 0.17499999999999718 +0.730375 -0.343505859375 -0.416412353515625 0.17499999999999718 +0.7305 -0.341094970703125 -0.413482666015625 0.17499999999999718 +0.730625 -0.341094970703125 -0.413482666015625 0.17499999999999718 +0.73075 -0.338653564453125 -0.4105224609375 0.17499999999999718 +0.7308750000000001 -0.338653564453125 -0.4105224609375 0.17499999999999718 +0.731 -0.336181640625 -0.407501220703125 0.17499999999999718 +0.731125 -0.333648681640625 -0.404449462890625 0.17499999999999718 +0.7312500000000001 -0.333648681640625 -0.404449462890625 0.17499999999999718 +0.731375 -0.331085205078125 -0.401336669921875 0.17499999999999718 +0.7315 -0.331085205078125 -0.401336669921875 0.17499999999999718 +0.731625 -0.3284912109375 -0.398193359375 0.17499999999999718 +0.73175 -0.325897216796875 -0.39501953125 0.17499999999999718 +0.7318750000000001 -0.325897216796875 -0.39501953125 0.17499999999999718 +0.732 -0.323211669921875 -0.39178466796875 0.17499999999999718 +0.732125 -0.323211669921875 -0.39178466796875 0.17499999999999718 +0.7322500000000001 -0.32049560546875 -0.388519287109375 0.17499999999999718 +0.732375 -0.317779541015625 -0.38519287109375 0.17499999999999718 +0.7325 -0.317779541015625 -0.38519287109375 0.17499999999999718 +0.732625 -0.31500244140625 -0.3818359375 0.17499999999999718 +0.73275 -0.31500244140625 -0.3818359375 0.17499999999999718 +0.7328750000000001 -0.31219482421875 -0.378448486328125 0.17499999999999718 +0.733 -0.309356689453125 -0.375 0.17499999999999718 +0.733125 -0.309356689453125 -0.375 0.17499999999999718 +0.7332500000000001 -0.306488037109375 -0.37152099609375 0.17499999999999718 +0.733375 -0.306488037109375 -0.37152099609375 0.17499999999999718 +0.7335 -0.3035888671875 -0.36798095703125 0.17499999999999718 +0.733625 -0.3006591796875 -0.36444091796875 0.17499999999999718 +0.73375 -0.3006591796875 -0.36444091796875 0.17499999999999718 +0.7338750000000001 -0.29766845703125 -0.360809326171875 0.17499999999999718 +0.734 -0.29766845703125 -0.360809326171875 0.17499999999999718 +0.734125 -0.294677734375 -0.357177734375 0.17499999999999718 +0.7342500000000001 -0.2916259765625 -0.353485107421875 0.17499999999999718 +0.734375 -0.2916259765625 -0.353485107421875 0.17499999999999718 +0.7345 -0.288543701171875 -0.349761962890625 0.17499999999999718 +0.734625 -0.288543701171875 -0.349761962890625 0.17499999999999718 +0.73475 -0.28546142578125 -0.34600830078125 0.17499999999999718 +0.7348750000000001 -0.282318115234375 -0.34222412109375 0.17499999999999718 +0.735 -0.282318115234375 -0.34222412109375 0.17499999999999718 +0.735125 -0.279144287109375 -0.33837890625 0.17499999999999718 +0.7352500000000001 -0.279144287109375 -0.33837890625 0.17499999999999718 +0.735375 -0.275970458984375 -0.334503173828125 0.17499999999999718 +0.7355 -0.272735595703125 -0.330596923828125 0.17499999999999718 +0.735625 -0.272735595703125 -0.330596923828125 0.17499999999999718 +0.73575 -0.26947021484375 -0.32666015625 0.17499999999999718 +0.7358750000000001 -0.26947021484375 -0.32666015625 0.17499999999999718 +0.736 -0.322662353515625 -0.25030517578125 -0.224243164062503132 +0.736125 -0.31866455078125 -0.2471923828125 -0.224243164062503132 +0.73625 -0.31866455078125 -0.2471923828125 -0.224243164062503132 +0.736375 -0.314605712890625 -0.244049072265625 -0.224243164062503132 +0.7365 -0.314605712890625 -0.244049072265625 -0.224243164062503132 +0.736625 -0.310516357421875 -0.240875244140625 -0.224243164062503132 +0.73675 -0.306396484375 -0.2376708984375 -0.224243164062503132 +0.7368750000000001 -0.306396484375 -0.2376708984375 -0.224243164062503132 +0.737 -0.30224609375 -0.23443603515625 -0.224243164062503132 +0.737125 -0.30224609375 -0.23443603515625 -0.224243164062503132 +0.73725 -0.298065185546875 -0.231201171875 -0.224243164062503132 +0.737375 -0.2938232421875 -0.227935791015625 -0.224243164062503132 +0.7375 -0.2938232421875 -0.227935791015625 -0.224243164062503132 +0.737625 -0.289581298828125 -0.224639892578125 -0.224243164062503132 +0.73775 -0.289581298828125 -0.224639892578125 -0.224243164062503132 +0.7378750000000001 -0.285308837890625 -0.2213134765625 -0.224243164062503132 +0.738 -0.280975341796875 -0.21795654296875 -0.224243164062503132 +0.738125 -0.280975341796875 -0.21795654296875 -0.224243164062503132 +0.73825 -0.276641845703125 -0.214599609375 -0.224243164062503132 +0.738375 -0.276641845703125 -0.214599609375 -0.224243164062503132 +0.7385 -0.27227783203125 -0.211212158203125 -0.224243164062503132 +0.738625 -0.267852783203125 -0.207794189453125 -0.224243164062503132 +0.73875 -0.267852783203125 -0.207794189453125 -0.224243164062503132 +0.7388750000000001 -0.263427734375 -0.204345703125 -0.224243164062503132 +0.739 -0.263427734375 -0.204345703125 -0.224243164062503132 +0.739125 -0.25897216796875 -0.200897216796875 -0.224243164062503132 +0.73925 -0.25445556640625 -0.1973876953125 -0.224243164062503132 +0.739375 -0.25445556640625 -0.1973876953125 -0.224243164062503132 +0.7395 -0.249969482421875 -0.193878173828125 -0.224243164062503132 +0.739625 -0.249969482421875 -0.193878173828125 -0.224243164062503132 +0.73975 -0.24542236328125 -0.19036865234375 -0.224243164062503132 +0.7398750000000001 -0.2408447265625 -0.186798095703125 -0.224243164062503132 +0.74 -0.2408447265625 -0.186798095703125 -0.224243164062503132 +0.740125 -0.236236572265625 -0.183258056640625 -0.224243164062503132 +0.74025 -0.236236572265625 -0.183258056640625 -0.224243164062503132 +0.740375 -0.231597900390625 -0.179656982421875 -0.224243164062503132 +0.7405 -0.226959228515625 -0.176055908203125 -0.224243164062503132 +0.740625 -0.226959228515625 -0.176055908203125 -0.224243164062503132 +0.74075 -0.2222900390625 -0.17242431640625 -0.224243164062503132 +0.7408750000000001 -0.2222900390625 -0.17242431640625 -0.224243164062503132 +0.741 -0.21759033203125 -0.16876220703125 -0.224243164062503132 +0.741125 -0.212860107421875 -0.16510009765625 -0.224243164062503132 +0.74125 -0.212860107421875 -0.16510009765625 -0.224243164062503132 +0.741375 -0.208099365234375 -0.16143798828125 -0.224243164062503132 +0.7415 -0.208099365234375 -0.16143798828125 -0.224243164062503132 +0.741625 -0.203338623046875 -0.15771484375 -0.224243164062503132 +0.74175 -0.19854736328125 -0.15399169921875 -0.224243164062503132 +0.7418750000000001 -0.19854736328125 -0.15399169921875 -0.224243164062503132 +0.742 -0.1937255859375 -0.1502685546875 -0.224243164062503132 +0.742125 -0.1937255859375 -0.1502685546875 -0.224243164062503132 +0.74225 -0.188873291015625 -0.146514892578125 -0.224243164062503132 +0.742375 -0.18402099609375 -0.14276123046875 -0.224243164062503132 +0.7425 -0.18402099609375 -0.14276123046875 -0.224243164062503132 +0.742625 -0.17913818359375 -0.138946533203125 -0.224243164062503132 +0.74275 -0.17913818359375 -0.138946533203125 -0.224243164062503132 +0.7428750000000001 -0.17425537109375 -0.135162353515625 -0.224243164062503132 +0.743 -0.169342041015625 -0.13134765625 -0.224243164062503132 +0.743125 -0.169342041015625 -0.13134765625 -0.224243164062503132 +0.74325 -0.164398193359375 -0.12750244140625 -0.224243164062503132 +0.743375 -0.164398193359375 -0.12750244140625 -0.224243164062503132 +0.7435 -0.159454345703125 -0.123687744140625 -0.224243164062503132 +0.743625 -0.15447998046875 -0.11981201171875 -0.224243164062503132 +0.74375 -0.15447998046875 -0.11981201171875 -0.224243164062503132 +0.7438750000000001 -0.14947509765625 -0.115936279296875 -0.224243164062503132 +0.744 -0.14947509765625 -0.115936279296875 -0.224243164062503132 +0.744125 -0.14447021484375 -0.112060546875 -0.224243164062503132 +0.74425 -0.13946533203125 -0.108184814453125 -0.224243164062503132 +0.744375 -0.13946533203125 -0.108184814453125 -0.224243164062503132 +0.7445000000000001 -0.134429931640625 -0.104278564453125 -0.224243164062503132 +0.744625 -0.134429931640625 -0.104278564453125 -0.224243164062503132 +0.74475 -0.129364013671875 -0.100341796875 -0.224243164062503132 +0.7448750000000001 -0.124298095703125 -0.096435546875 -0.224243164062503132 +0.745 -0.124298095703125 -0.096435546875 -0.224243164062503132 +0.745125 -0.119232177734375 -0.092498779296875 -0.224243164062503132 +0.74525 -0.119232177734375 -0.092498779296875 -0.224243164062503132 +0.745375 -0.1141357421875 -0.088531494140625 -0.224243164062503132 +0.7455000000000001 -0.109039306640625 -0.084564208984375 -0.224243164062503132 +0.745625 -0.109039306640625 -0.084564208984375 -0.224243164062503132 +0.74575 -0.103912353515625 -0.080596923828125 -0.224243164062503132 +0.7458750000000001 -0.103912353515625 -0.080596923828125 -0.224243164062503132 +0.746 -0.098785400390625 -0.076629638671875 -0.224243164062503132 +0.746125 -0.093658447265625 -0.0726318359375 -0.224243164062503132 +0.74625 -0.093658447265625 -0.0726318359375 -0.224243164062503132 +0.746375 -0.0885009765625 -0.06866455078125 -0.224243164062503132 +0.7465000000000001 -0.0885009765625 -0.06866455078125 -0.224243164062503132 +0.746625 -0.083343505859375 -0.064666748046875 -0.224243164062503132 +0.74675 -0.07818603515625 -0.060638427734375 -0.224243164062503132 +0.7468750000000001 -0.07818603515625 -0.060638427734375 -0.224243164062503132 +0.747 -0.072998046875 -0.056640625 -0.224243164062503132 +0.747125 -0.072998046875 -0.056640625 -0.224243164062503132 +0.74725 -0.06781005859375 -0.0526123046875 -0.224243164062503132 +0.747375 -0.0626220703125 -0.048583984375 -0.224243164062503132 +0.7475000000000001 -0.0626220703125 -0.048583984375 -0.224243164062503132 +0.747625 -0.05743408203125 -0.0445556640625 -0.224243164062503132 +0.74775 -0.05743408203125 -0.0445556640625 -0.224243164062503132 +0.7478750000000001 -0.05224609375 -0.04052734375 -0.224243164062503132 +0.748 -0.047027587890625 -0.036468505859375 -0.224243164062503132 +0.748125 -0.047027587890625 -0.036468505859375 -0.224243164062503132 +0.74825 -0.04180908203125 -0.032440185546875 -0.224243164062503132 +0.748375 -0.04180908203125 -0.032440185546875 -0.224243164062503132 +0.7485000000000001 -0.036590576171875 -0.02838134765625 -0.224243164062503132 +0.748625 -0.0313720703125 -0.024322509765625 -0.224243164062503132 +0.74875 -0.0313720703125 -0.024322509765625 -0.224243164062503132 +0.7488750000000001 -0.026123046875 -0.020263671875 -0.224243164062503132 +0.749 -0.026123046875 -0.020263671875 -0.224243164062503132 +0.749125 -0.020904541015625 -0.0162353515625 -0.224243164062503132 +0.74925 -0.01568603515625 -0.012176513671875 -0.224243164062503132 +0.749375 -0.01568603515625 -0.012176513671875 -0.224243164062503132 +0.7495000000000001 -0.01043701171875 -0.00811767578125 -0.224243164062503132 +0.749625 -0.01043701171875 -0.00811767578125 -0.224243164062503132 +0.74975 -0.005218505859375 -0.004058837890625 -0.224243164062503132 +0.7498750000000001 0.0 0.0 -0.224243164062503132 +0.75 0.0 0.0 -0.224243164062503132 +0.750125 0.005218505859375 0.004058837890625 -0.224243164062503132 +0.75025 0.005218505859375 0.004058837890625 -0.224243164062503132 +0.750375 0.01043701171875 0.00811767578125 -0.224243164062503132 +0.7505000000000001 0.01568603515625 0.012176513671875 -0.224243164062503132 +0.750625 0.01568603515625 0.012176513671875 -0.224243164062503132 +0.75075 0.020904541015625 0.0162353515625 -0.224243164062503132 +0.7508750000000001 0.020904541015625 0.0162353515625 -0.224243164062503132 +0.751 0.026123046875 0.020263671875 -0.224243164062503132 +0.751125 0.0313720703125 0.024322509765625 -0.224243164062503132 +0.75125 0.0313720703125 0.024322509765625 -0.224243164062503132 +0.751375 0.036590576171875 0.02838134765625 -0.224243164062503132 +0.7515000000000001 0.036590576171875 0.02838134765625 -0.224243164062503132 +0.751625 0.04180908203125 0.032440185546875 -0.224243164062503132 +0.75175 0.047027587890625 0.036468505859375 -0.224243164062503132 +0.7518750000000001 0.047027587890625 0.036468505859375 -0.224243164062503132 +0.752 0.05224609375 0.04052734375 -0.224243164062503132 +0.752125 0.05224609375 0.04052734375 -0.224243164062503132 +0.75225 0.05743408203125 0.0445556640625 -0.224243164062503132 +0.752375 0.0626220703125 0.048583984375 -0.224243164062503132 +0.7525000000000001 0.0626220703125 0.048583984375 -0.224243164062503132 +0.752625 0.06781005859375 0.0526123046875 -0.224243164062503132 +0.75275 0.06781005859375 0.0526123046875 -0.224243164062503132 +0.752875 0.072998046875 0.056640625 -0.224243164062503132 +0.753 0.07818603515625 0.060638427734375 -0.224243164062503132 +0.753125 0.07818603515625 0.060638427734375 -0.224243164062503132 +0.75325 0.083343505859375 0.064666748046875 -0.224243164062503132 +0.753375 0.083343505859375 0.064666748046875 -0.224243164062503132 +0.7535000000000001 0.0885009765625 0.06866455078125 -0.224243164062503132 +0.753625 0.093658447265625 0.0726318359375 -0.224243164062503132 +0.75375 0.093658447265625 0.0726318359375 -0.224243164062503132 +0.753875 0.098785400390625 0.076629638671875 -0.224243164062503132 +0.754 0.098785400390625 0.076629638671875 -0.224243164062503132 +0.754125 0.103912353515625 0.080596923828125 -0.224243164062503132 +0.75425 0.109039306640625 0.084564208984375 -0.224243164062503132 +0.754375 0.109039306640625 0.084564208984375 -0.224243164062503132 +0.7545000000000001 0.1141357421875 0.088531494140625 -0.224243164062503132 +0.754625 0.1141357421875 0.088531494140625 -0.224243164062503132 +0.75475 0.119232177734375 0.092498779296875 -0.224243164062503132 +0.754875 0.124298095703125 0.096435546875 -0.224243164062503132 +0.755 0.124298095703125 0.096435546875 -0.224243164062503132 +0.755125 0.129364013671875 0.100341796875 -0.224243164062503132 +0.75525 0.129364013671875 0.100341796875 -0.224243164062503132 +0.755375 0.134429931640625 0.104278564453125 -0.224243164062503132 +0.7555000000000001 0.13946533203125 0.108184814453125 -0.224243164062503132 +0.755625 0.13946533203125 0.108184814453125 -0.224243164062503132 +0.75575 0.14447021484375 0.112060546875 -0.224243164062503132 +0.755875 0.14447021484375 0.112060546875 -0.224243164062503132 +0.756 0.14947509765625 0.115936279296875 -0.224243164062503132 +0.756125 0.15447998046875 0.11981201171875 -0.224243164062503132 +0.75625 0.15447998046875 0.11981201171875 -0.224243164062503132 +0.756375 0.159454345703125 0.123687744140625 -0.224243164062503132 +0.7565000000000001 0.159454345703125 0.123687744140625 -0.224243164062503132 +0.756625 0.164398193359375 0.12750244140625 -0.224243164062503132 +0.75675 0.169342041015625 0.13134765625 -0.224243164062503132 +0.756875 0.169342041015625 0.13134765625 -0.224243164062503132 +0.757 0.17425537109375 0.135162353515625 -0.224243164062503132 +0.757125 0.17425537109375 0.135162353515625 -0.224243164062503132 +0.75725 0.17913818359375 0.138946533203125 -0.224243164062503132 +0.757375 0.18402099609375 0.14276123046875 -0.224243164062503132 +0.7575000000000001 0.18402099609375 0.14276123046875 -0.224243164062503132 +0.757625 0.188873291015625 0.146514892578125 -0.224243164062503132 +0.75775 0.188873291015625 0.146514892578125 -0.224243164062503132 +0.757875 0.1937255859375 0.1502685546875 -0.224243164062503132 +0.758 0.19854736328125 0.15399169921875 -0.224243164062503132 +0.758125 0.19854736328125 0.15399169921875 -0.224243164062503132 +0.75825 0.203338623046875 0.15771484375 -0.224243164062503132 +0.758375 0.203338623046875 0.15771484375 -0.224243164062503132 +0.7585000000000001 0.208099365234375 0.16143798828125 -0.224243164062503132 +0.758625 0.212860107421875 0.16510009765625 -0.224243164062503132 +0.75875 0.212860107421875 0.16510009765625 -0.224243164062503132 +0.758875 0.21759033203125 0.16876220703125 -0.224243164062503132 +0.759 0.21759033203125 0.16876220703125 -0.224243164062503132 +0.759125 0.2222900390625 0.17242431640625 -0.224243164062503132 +0.75925 0.226959228515625 0.176055908203125 -0.224243164062503132 +0.759375 0.226959228515625 0.176055908203125 -0.224243164062503132 +0.7595000000000001 0.231597900390625 0.179656982421875 -0.224243164062503132 +0.759625 0.231597900390625 0.179656982421875 -0.224243164062503132 +0.75975 0.236236572265625 0.183258056640625 -0.224243164062503132 +0.759875 0.2408447265625 0.186798095703125 -0.224243164062503132 +0.76 0.2408447265625 0.186798095703125 -0.224243164062503132 +0.7601250000000001 0.24542236328125 0.19036865234375 -0.224243164062503132 +0.76025 0.24542236328125 0.19036865234375 -0.224243164062503132 +0.760375 0.249969482421875 0.193878173828125 -0.224243164062503132 +0.7605000000000001 0.25445556640625 0.1973876953125 -0.224243164062503132 +0.760625 0.25445556640625 0.1973876953125 -0.224243164062503132 +0.76075 0.25897216796875 0.200897216796875 -0.224243164062503132 +0.760875 0.25897216796875 0.200897216796875 -0.224243164062503132 +0.761 0.263427734375 0.204345703125 -0.224243164062503132 +0.7611250000000001 0.267852783203125 0.207794189453125 -0.224243164062503132 +0.76125 0.267852783203125 0.207794189453125 -0.224243164062503132 +0.761375 0.27227783203125 0.211212158203125 -0.224243164062503132 +0.7615000000000001 0.27227783203125 0.211212158203125 -0.224243164062503132 +0.761625 0.276641845703125 0.214599609375 -0.224243164062503132 +0.76175 0.280975341796875 0.21795654296875 -0.224243164062503132 +0.761875 0.280975341796875 0.21795654296875 -0.224243164062503132 +0.762 0.285308837890625 0.2213134765625 -0.224243164062503132 +0.7621250000000001 0.285308837890625 0.2213134765625 -0.224243164062503132 +0.76225 0.289581298828125 0.224639892578125 -0.224243164062503132 +0.762375 0.2938232421875 0.227935791015625 -0.224243164062503132 +0.7625000000000001 0.2938232421875 0.227935791015625 -0.224243164062503132 +0.762625 0.298065185546875 0.231201171875 -0.224243164062503132 +0.76275 0.298065185546875 0.231201171875 -0.224243164062503132 +0.762875 0.30224609375 0.23443603515625 -0.224243164062503132 +0.763 0.306396484375 0.2376708984375 -0.224243164062503132 +0.7631250000000001 0.306396484375 0.2376708984375 -0.224243164062503132 +0.76325 0.310516357421875 0.240875244140625 -0.224243164062503132 +0.763375 0.310516357421875 0.240875244140625 -0.224243164062503132 +0.7635000000000001 0.314605712890625 0.244049072265625 -0.224243164062503132 +0.763625 0.31866455078125 0.2471923828125 -0.224243164062503132 +0.76375 0.31866455078125 0.2471923828125 -0.224243164062503132 +0.763875 0.322662353515625 0.25030517578125 -0.224243164062503132 +0.764 0.322662353515625 0.25030517578125 -0.224243164062503132 +0.7641250000000001 0.32666015625 0.253387451171875 -0.224243164062503132 +0.76425 0.330596923828125 0.256439208984375 -0.224243164062503132 +0.764375 0.330596923828125 0.256439208984375 -0.224243164062503132 +0.7645000000000001 0.334503173828125 0.259490966796875 -0.224243164062503132 +0.764625 0.334503173828125 0.259490966796875 -0.224243164062503132 +0.76475 0.33837890625 0.262481689453125 -0.224243164062503132 +0.764875 0.34222412109375 0.265472412109375 -0.224243164062503132 +0.765 0.34222412109375 0.265472412109375 -0.224243164062503132 +0.7651250000000001 0.34600830078125 0.268402099609375 -0.224243164062503132 +0.76525 0.34600830078125 0.268402099609375 -0.224243164062503132 +0.765375 0.349761962890625 0.271331787109375 -0.224243164062503132 +0.7655000000000001 0.353485107421875 0.274200439453125 -0.224243164062503132 +0.765625 0.353485107421875 0.274200439453125 -0.224243164062503132 +0.76575 0.357177734375 0.277069091796875 -0.224243164062503132 +0.765875 0.357177734375 0.277069091796875 -0.224243164062503132 +0.766 0.360809326171875 0.279876708984375 -0.224243164062503132 +0.7661250000000001 0.36444091796875 0.282684326171875 -0.224243164062503132 +0.76625 0.36444091796875 0.282684326171875 -0.224243164062503132 +0.766375 0.36798095703125 0.28546142578125 -0.224243164062503132 +0.7665000000000001 0.36798095703125 0.28546142578125 -0.224243164062503132 +0.766625 0.37152099609375 0.288177490234375 -0.224243164062503132 +0.76675 0.375 0.2908935546875 -0.224243164062503132 +0.766875 0.375 0.2908935546875 -0.224243164062503132 +0.767 0.378448486328125 0.293548583984375 -0.224243164062503132 +0.7671250000000001 0.378448486328125 0.293548583984375 -0.224243164062503132 +0.76725 0.3818359375 0.29620361328125 -0.224243164062503132 +0.767375 0.38519287109375 0.298797607421875 -0.224243164062503132 +0.7675000000000001 0.38519287109375 0.298797607421875 -0.224243164062503132 +0.767625 0.388519287109375 0.301361083984375 -0.224243164062503132 +0.76775 0.388519287109375 0.301361083984375 -0.224243164062503132 +0.767875 0.39178466796875 0.303924560546875 -0.224243164062503132 +0.768 0.39501953125 0.162811279296875 -0.5877380371093779 +0.7681250000000001 0.39501953125 0.162811279296875 -0.5877380371093779 +0.76825 0.398193359375 0.16412353515625 -0.5877380371093779 +0.768375 0.398193359375 0.16412353515625 -0.5877380371093779 +0.7685 0.401336669921875 0.165435791015625 -0.5877380371093779 +0.768625 0.404449462890625 0.166717529296875 -0.5877380371093779 +0.76875 0.404449462890625 0.166717529296875 -0.5877380371093779 +0.768875 0.407501220703125 0.16796875 -0.5877380371093779 +0.769 0.407501220703125 0.16796875 -0.5877380371093779 +0.7691250000000001 0.4105224609375 0.169189453125 -0.5877380371093779 +0.76925 0.413482666015625 0.17041015625 -0.5877380371093779 +0.769375 0.413482666015625 0.17041015625 -0.5877380371093779 +0.7695 0.416412353515625 0.171630859375 -0.5877380371093779 +0.769625 0.416412353515625 0.171630859375 -0.5877380371093779 +0.76975 0.419281005859375 0.172821044921875 -0.5877380371093779 +0.769875 0.422119140625 0.173980712890625 -0.5877380371093779 +0.77 0.422119140625 0.173980712890625 -0.5877380371093779 +0.7701250000000001 0.424896240234375 0.175140380859375 -0.5877380371093779 +0.77025 0.424896240234375 0.175140380859375 -0.5877380371093779 +0.770375 0.4276123046875 0.176239013671875 -0.5877380371093779 +0.7705 0.4302978515625 0.1773681640625 -0.5877380371093779 +0.770625 0.4302978515625 0.1773681640625 -0.5877380371093779 +0.77075 0.432952880859375 0.178466796875 -0.5877380371093779 +0.770875 0.432952880859375 0.178466796875 -0.5877380371093779 +0.771 0.435546875 0.179534912109375 -0.5877380371093779 +0.7711250000000001 0.438079833984375 0.180572509765625 -0.5877380371093779 +0.77125 0.438079833984375 0.180572509765625 -0.5877380371093779 +0.771375 0.440582275390625 0.181610107421875 -0.5877380371093779 +0.7715 0.440582275390625 0.181610107421875 -0.5877380371093779 +0.771625 0.44305419921875 0.1826171875 -0.5877380371093779 +0.77175 0.4454345703125 0.18359375 -0.5877380371093779 +0.771875 0.4454345703125 0.18359375 -0.5877380371093779 +0.772 0.447784423828125 0.1845703125 -0.5877380371093779 +0.7721250000000001 0.447784423828125 0.1845703125 -0.5877380371093779 +0.77225 0.450103759765625 0.185516357421875 -0.5877380371093779 +0.772375 0.452362060546875 0.18646240234375 -0.5877380371093779 +0.7725 0.452362060546875 0.18646240234375 -0.5877380371093779 +0.772625 0.454559326171875 0.187347412109375 -0.5877380371093779 +0.77275 0.454559326171875 0.187347412109375 -0.5877380371093779 +0.772875 0.45672607421875 0.188232421875 -0.5877380371093779 +0.773 0.458831787109375 0.189117431640625 -0.5877380371093779 +0.7731250000000001 0.458831787109375 0.189117431640625 -0.5877380371093779 +0.77325 0.46087646484375 0.189971923828125 -0.5877380371093779 +0.773375 0.46087646484375 0.189971923828125 -0.5877380371093779 +0.7735 0.462890625 0.1907958984375 -0.5877380371093779 +0.773625 0.464813232421875 0.19158935546875 -0.5877380371093779 +0.77375 0.464813232421875 0.19158935546875 -0.5877380371093779 +0.773875 0.46673583984375 0.1923828125 -0.5877380371093779 +0.774 0.46673583984375 0.1923828125 -0.5877380371093779 +0.7741250000000001 0.46856689453125 0.193145751953125 -0.5877380371093779 +0.77425 0.470367431640625 0.193878173828125 -0.5877380371093779 +0.774375 0.470367431640625 0.193878173828125 -0.5877380371093779 +0.7745 0.472137451171875 0.194610595703125 -0.5877380371093779 +0.774625 0.472137451171875 0.194610595703125 -0.5877380371093779 +0.77475 0.47381591796875 0.195281982421875 -0.5877380371093779 +0.774875 0.4754638671875 0.19598388671875 -0.5877380371093779 +0.775 0.4754638671875 0.19598388671875 -0.5877380371093779 +0.7751250000000001 0.47705078125 0.196624755859375 -0.5877380371093779 +0.77525 0.47705078125 0.196624755859375 -0.5877380371093779 +0.775375 0.478607177734375 0.197265625 -0.5877380371093779 +0.7755 0.480072021484375 0.1978759765625 -0.5877380371093779 +0.775625 0.480072021484375 0.1978759765625 -0.5877380371093779 +0.7757500000000001 0.48150634765625 0.198455810546875 -0.5877380371093779 +0.775875 0.48150634765625 0.198455810546875 -0.5877380371093779 +0.776 0.48291015625 0.19903564453125 -0.5877380371093779 +0.7761250000000001 0.484222412109375 0.1995849609375 -0.5877380371093779 +0.77625 0.484222412109375 0.1995849609375 -0.5877380371093779 +0.776375 0.485504150390625 0.200103759765625 -0.5877380371093779 +0.7765 0.485504150390625 0.200103759765625 -0.5877380371093779 +0.776625 0.486724853515625 0.20062255859375 -0.5877380371093779 +0.7767500000000001 0.487884521484375 0.201080322265625 -0.5877380371093779 +0.776875 0.487884521484375 0.201080322265625 -0.5877380371093779 +0.777 0.489013671875 0.201568603515625 -0.5877380371093779 +0.7771250000000001 0.489013671875 0.201568603515625 -0.5877380371093779 +0.77725 0.490081787109375 0.201995849609375 -0.5877380371093779 +0.777375 0.4910888671875 0.202423095703125 -0.5877380371093779 +0.7775 0.4910888671875 0.202423095703125 -0.5877380371093779 +0.777625 0.492034912109375 0.20281982421875 -0.5877380371093779 +0.7777500000000001 0.492034912109375 0.20281982421875 -0.5877380371093779 +0.777875 0.492950439453125 0.20318603515625 -0.5877380371093779 +0.778 0.4937744140625 0.203521728515625 -0.5877380371093779 +0.7781250000000001 0.4937744140625 0.203521728515625 -0.5877380371093779 +0.77825 0.49456787109375 0.203857421875 -0.5877380371093779 +0.778375 0.49456787109375 0.203857421875 -0.5877380371093779 +0.7785 0.49530029296875 0.20416259765625 -0.5877380371093779 +0.778625 0.496002197265625 0.204437255859375 -0.5877380371093779 +0.7787500000000001 0.496002197265625 0.204437255859375 -0.5877380371093779 +0.778875 0.496612548828125 0.204681396484375 -0.5877380371093779 +0.779 0.496612548828125 0.204681396484375 -0.5877380371093779 +0.7791250000000001 0.4971923828125 0.204925537109375 -0.5877380371093779 +0.77925 0.497711181640625 0.20513916015625 -0.5877380371093779 +0.779375 0.497711181640625 0.20513916015625 -0.5877380371093779 +0.7795 0.498199462890625 0.205352783203125 -0.5877380371093779 +0.779625 0.498199462890625 0.205352783203125 -0.5877380371093779 +0.7797500000000001 0.49859619140625 0.20550537109375 -0.5877380371093779 +0.779875 0.49896240234375 0.205657958984375 -0.5877380371093779 +0.78 0.49896240234375 0.205657958984375 -0.5877380371093779 +0.7801250000000001 0.499267578125 0.205780029296875 -0.5877380371093779 +0.78025 0.499267578125 0.205780029296875 -0.5877380371093779 +0.780375 0.49951171875 0.20587158203125 -0.5877380371093779 +0.7805 0.49969482421875 0.205963134765625 -0.5877380371093779 +0.780625 0.49969482421875 0.205963134765625 -0.5877380371093779 +0.7807500000000001 0.49981689453125 0.206024169921875 -0.5877380371093779 +0.780875 0.49981689453125 0.206024169921875 -0.5877380371093779 +0.781 0.499908447265625 0.2060546875 -0.5877380371093779 +0.7811250000000001 0.49993896484375 0.2060546875 -0.5877380371093779 +0.78125 0.49993896484375 0.2060546875 -0.5877380371093779 +0.781375 0.499908447265625 0.2060546875 -0.5877380371093779 +0.7815 0.499908447265625 0.2060546875 -0.5877380371093779 +0.781625 0.49981689453125 0.206024169921875 -0.5877380371093779 +0.7817500000000001 0.49969482421875 0.205963134765625 -0.5877380371093779 +0.781875 0.49969482421875 0.205963134765625 -0.5877380371093779 +0.782 0.49951171875 0.20587158203125 -0.5877380371093779 +0.7821250000000001 0.49951171875 0.20587158203125 -0.5877380371093779 +0.78225 0.499267578125 0.205780029296875 -0.5877380371093779 +0.782375 0.49896240234375 0.205657958984375 -0.5877380371093779 +0.7825 0.49896240234375 0.205657958984375 -0.5877380371093779 +0.782625 0.49859619140625 0.20550537109375 -0.5877380371093779 +0.7827500000000001 0.49859619140625 0.20550537109375 -0.5877380371093779 +0.782875 0.498199462890625 0.205352783203125 -0.5877380371093779 +0.783 0.497711181640625 0.20513916015625 -0.5877380371093779 +0.7831250000000001 0.497711181640625 0.20513916015625 -0.5877380371093779 +0.78325 0.4971923828125 0.204925537109375 -0.5877380371093779 +0.783375 0.4971923828125 0.204925537109375 -0.5877380371093779 +0.7835 0.496612548828125 0.204681396484375 -0.5877380371093779 +0.783625 0.496002197265625 0.204437255859375 -0.5877380371093779 +0.7837500000000001 0.496002197265625 0.204437255859375 -0.5877380371093779 +0.783875 0.49530029296875 0.20416259765625 -0.5877380371093779 +0.784 0.49530029296875 0.20416259765625 -0.5877380371093779 +0.784125 0.49456787109375 0.203857421875 -0.5877380371093779 +0.78425 0.4937744140625 0.203521728515625 -0.5877380371093779 +0.784375 0.4937744140625 0.203521728515625 -0.5877380371093779 +0.7845 0.492950439453125 0.20318603515625 -0.5877380371093779 +0.784625 0.492950439453125 0.20318603515625 -0.5877380371093779 +0.7847500000000001 0.492034912109375 0.20281982421875 -0.5877380371093779 +0.784875 0.4910888671875 0.202423095703125 -0.5877380371093779 +0.785 0.4910888671875 0.202423095703125 -0.5877380371093779 +0.785125 0.490081787109375 0.201995849609375 -0.5877380371093779 +0.78525 0.490081787109375 0.201995849609375 -0.5877380371093779 +0.785375 0.489013671875 0.201568603515625 -0.5877380371093779 +0.7855 0.487884521484375 0.201080322265625 -0.5877380371093779 +0.785625 0.487884521484375 0.201080322265625 -0.5877380371093779 +0.7857500000000001 0.486724853515625 0.20062255859375 -0.5877380371093779 +0.785875 0.486724853515625 0.20062255859375 -0.5877380371093779 +0.786 0.485504150390625 0.200103759765625 -0.5877380371093779 +0.786125 0.484222412109375 0.1995849609375 -0.5877380371093779 +0.78625 0.484222412109375 0.1995849609375 -0.5877380371093779 +0.786375 0.48291015625 0.19903564453125 -0.5877380371093779 +0.7865 0.48291015625 0.19903564453125 -0.5877380371093779 +0.786625 0.48150634765625 0.198455810546875 -0.5877380371093779 +0.7867500000000001 0.480072021484375 0.1978759765625 -0.5877380371093779 +0.786875 0.480072021484375 0.1978759765625 -0.5877380371093779 +0.787 0.478607177734375 0.197265625 -0.5877380371093779 +0.787125 0.478607177734375 0.197265625 -0.5877380371093779 +0.78725 0.47705078125 0.196624755859375 -0.5877380371093779 +0.787375 0.4754638671875 0.19598388671875 -0.5877380371093779 +0.7875 0.4754638671875 0.19598388671875 -0.5877380371093779 +0.787625 0.47381591796875 0.195281982421875 -0.5877380371093779 +0.7877500000000001 0.47381591796875 0.195281982421875 -0.5877380371093779 +0.787875 0.472137451171875 0.194610595703125 -0.5877380371093779 +0.788 0.470367431640625 0.193878173828125 -0.5877380371093779 +0.788125 0.470367431640625 0.193878173828125 -0.5877380371093779 +0.78825 0.46856689453125 0.193145751953125 -0.5877380371093779 +0.788375 0.46856689453125 0.193145751953125 -0.5877380371093779 +0.7885 0.46673583984375 0.1923828125 -0.5877380371093779 +0.788625 0.464813232421875 0.19158935546875 -0.5877380371093779 +0.7887500000000001 0.464813232421875 0.19158935546875 -0.5877380371093779 +0.788875 0.462890625 0.1907958984375 -0.5877380371093779 +0.789 0.462890625 0.1907958984375 -0.5877380371093779 +0.789125 0.46087646484375 0.189971923828125 -0.5877380371093779 +0.78925 0.458831787109375 0.189117431640625 -0.5877380371093779 +0.789375 0.458831787109375 0.189117431640625 -0.5877380371093779 +0.7895 0.45672607421875 0.188232421875 -0.5877380371093779 +0.789625 0.45672607421875 0.188232421875 -0.5877380371093779 +0.7897500000000001 0.454559326171875 0.187347412109375 -0.5877380371093779 +0.789875 0.452362060546875 0.18646240234375 -0.5877380371093779 +0.79 0.452362060546875 0.18646240234375 -0.5877380371093779 +0.790125 0.450103759765625 0.185516357421875 -0.5877380371093779 +0.79025 0.450103759765625 0.185516357421875 -0.5877380371093779 +0.790375 0.447784423828125 0.1845703125 -0.5877380371093779 +0.7905 0.4454345703125 0.18359375 -0.5877380371093779 +0.790625 0.4454345703125 0.18359375 -0.5877380371093779 +0.7907500000000001 0.44305419921875 0.1826171875 -0.5877380371093779 +0.790875 0.44305419921875 0.1826171875 -0.5877380371093779 +0.791 0.440582275390625 0.181610107421875 -0.5877380371093779 +0.791125 0.438079833984375 0.180572509765625 -0.5877380371093779 +0.79125 0.438079833984375 0.180572509765625 -0.5877380371093779 +0.7913750000000001 0.435546875 0.179534912109375 -0.5877380371093779 +0.7915 0.435546875 0.179534912109375 -0.5877380371093779 +0.791625 0.432952880859375 0.178466796875 -0.5877380371093779 +0.7917500000000001 0.4302978515625 0.1773681640625 -0.5877380371093779 +0.791875 0.4302978515625 0.1773681640625 -0.5877380371093779 +0.792 0.4276123046875 0.176239013671875 -0.5877380371093779 +0.792125 0.4276123046875 0.176239013671875 -0.5877380371093779 +0.79225 0.424896240234375 0.175140380859375 -0.5877380371093779 +0.7923750000000001 0.422119140625 0.173980712890625 -0.5877380371093779 +0.7925 0.422119140625 0.173980712890625 -0.5877380371093779 +0.792625 0.419281005859375 0.172821044921875 -0.5877380371093779 +0.7927500000000001 0.419281005859375 0.172821044921875 -0.5877380371093779 +0.792875 0.416412353515625 0.171630859375 -0.5877380371093779 +0.793 0.413482666015625 0.17041015625 -0.5877380371093779 +0.793125 0.413482666015625 0.17041015625 -0.5877380371093779 +0.79325 0.4105224609375 0.169189453125 -0.5877380371093779 +0.7933750000000001 0.4105224609375 0.169189453125 -0.5877380371093779 +0.7935 0.407501220703125 0.16796875 -0.5877380371093779 +0.793625 0.404449462890625 0.166717529296875 -0.5877380371093779 +0.7937500000000001 0.404449462890625 0.166717529296875 -0.5877380371093779 +0.793875 0.401336669921875 0.165435791015625 -0.5877380371093779 +0.794 0.401336669921875 0.165435791015625 -0.5877380371093779 +0.794125 0.398193359375 0.16412353515625 -0.5877380371093779 +0.79425 0.39501953125 0.162811279296875 -0.5877380371093779 +0.7943750000000001 0.39501953125 0.162811279296875 -0.5877380371093779 +0.7945 0.39178466796875 0.1614990234375 -0.5877380371093779 +0.794625 0.39178466796875 0.1614990234375 -0.5877380371093779 +0.7947500000000001 0.388519287109375 0.160125732421875 -0.5877380371093779 +0.794875 0.38519287109375 0.158782958984375 -0.5877380371093779 +0.795 0.38519287109375 0.158782958984375 -0.5877380371093779 +0.795125 0.3818359375 0.157379150390625 -0.5877380371093779 +0.79525 0.3818359375 0.157379150390625 -0.5877380371093779 +0.7953750000000001 0.378448486328125 0.155975341796875 -0.5877380371093779 +0.7955 0.375 0.154571533203125 -0.5877380371093779 +0.795625 0.375 0.154571533203125 -0.5877380371093779 +0.7957500000000001 0.37152099609375 0.15313720703125 -0.5877380371093779 +0.795875 0.37152099609375 0.15313720703125 -0.5877380371093779 +0.796 0.36798095703125 0.15167236328125 -0.5877380371093779 +0.796125 0.36444091796875 0.15020751953125 -0.5877380371093779 +0.79625 0.36444091796875 0.15020751953125 -0.5877380371093779 +0.7963750000000001 0.360809326171875 0.148712158203125 -0.5877380371093779 +0.7965 0.360809326171875 0.148712158203125 -0.5877380371093779 +0.796625 0.357177734375 0.147216796875 -0.5877380371093779 +0.7967500000000001 0.353485107421875 0.14569091796875 -0.5877380371093779 +0.796875 0.353485107421875 0.14569091796875 -0.5877380371093779 +0.797 0.349761962890625 0.1441650390625 -0.5877380371093779 +0.797125 0.349761962890625 0.1441650390625 -0.5877380371093779 +0.79725 0.34600830078125 0.142608642578125 -0.5877380371093779 +0.7973750000000001 0.34222412109375 0.14105224609375 -0.5877380371093779 +0.7975 0.34222412109375 0.14105224609375 -0.5877380371093779 +0.797625 0.33837890625 0.13946533203125 -0.5877380371093779 +0.7977500000000001 0.33837890625 0.13946533203125 -0.5877380371093779 +0.797875 0.334503173828125 0.13787841796875 -0.5877380371093779 +0.798 0.330596923828125 0.136260986328125 -0.5877380371093779 +0.798125 0.330596923828125 0.136260986328125 -0.5877380371093779 +0.79825 0.32666015625 0.1346435546875 -0.5877380371093779 +0.7983750000000001 0.32666015625 0.1346435546875 -0.5877380371093779 +0.7985 0.322662353515625 0.13299560546875 -0.5877380371093779 +0.798625 0.31866455078125 0.13134765625 -0.5877380371093779 +0.7987500000000001 0.31866455078125 0.13134765625 -0.5877380371093779 +0.798875 0.314605712890625 0.129669189453125 -0.5877380371093779 +0.799 0.314605712890625 0.129669189453125 -0.5877380371093779 +0.799125 0.310516357421875 0.12799072265625 -0.5877380371093779 +0.79925 0.306396484375 0.12628173828125 -0.5877380371093779 +0.7993750000000001 0.306396484375 0.12628173828125 -0.5877380371093779 +0.7995 0.30224609375 0.12457275390625 -0.5877380371093779 +0.799625 0.30224609375 0.12457275390625 -0.5877380371093779 +0.7997500000000001 0.298065185546875 0.12286376953125 -0.5877380371093779 +0.799875 0.2938232421875 0.12109375 -0.5877380371093779 +0.8 0.2938232421875 0.041839599609375 -0.857464599609377 +0.800125 0.289581298828125 0.041229248046875 -0.857464599609377 +0.80025 0.289581298828125 0.041229248046875 -0.857464599609377 +0.8003750000000001 0.285308837890625 0.040618896484375 -0.857464599609377 +0.8005 0.280975341796875 0.040008544921875 -0.857464599609377 +0.800625 0.280975341796875 0.040008544921875 -0.857464599609377 +0.80075 0.276641845703125 0.039398193359375 -0.857464599609377 +0.800875 0.276641845703125 0.039398193359375 -0.857464599609377 +0.801 0.27227783203125 0.038787841796875 -0.857464599609377 +0.801125 0.267852783203125 0.03814697265625 -0.857464599609377 +0.80125 0.267852783203125 0.03814697265625 -0.857464599609377 +0.8013750000000001 0.263427734375 0.037506103515625 -0.857464599609377 +0.8015 0.263427734375 0.037506103515625 -0.857464599609377 +0.801625 0.25897216796875 0.036895751953125 -0.857464599609377 +0.80175 0.25445556640625 0.0362548828125 -0.857464599609377 +0.801875 0.25445556640625 0.0362548828125 -0.857464599609377 +0.802 0.249969482421875 0.03558349609375 -0.857464599609377 +0.802125 0.249969482421875 0.03558349609375 -0.857464599609377 +0.80225 0.24542236328125 0.034942626953125 -0.857464599609377 +0.8023750000000001 0.2408447265625 0.0343017578125 -0.857464599609377 +0.8025 0.2408447265625 0.0343017578125 -0.857464599609377 +0.802625 0.236236572265625 0.03363037109375 -0.857464599609377 +0.80275 0.236236572265625 0.03363037109375 -0.857464599609377 +0.802875 0.231597900390625 0.032989501953125 -0.857464599609377 +0.803 0.226959228515625 0.032318115234375 -0.857464599609377 +0.803125 0.226959228515625 0.032318115234375 -0.857464599609377 +0.80325 0.2222900390625 0.031646728515625 -0.857464599609377 +0.8033750000000001 0.2222900390625 0.031646728515625 -0.857464599609377 +0.8035 0.21759033203125 0.030975341796875 -0.857464599609377 +0.803625 0.212860107421875 0.030303955078125 -0.857464599609377 +0.80375 0.212860107421875 0.030303955078125 -0.857464599609377 +0.803875 0.208099365234375 0.029632568359375 -0.857464599609377 +0.804 0.208099365234375 0.029632568359375 -0.857464599609377 +0.804125 0.203338623046875 0.028961181640625 -0.857464599609377 +0.80425 0.19854736328125 0.02825927734375 -0.857464599609377 +0.8043750000000001 0.19854736328125 0.02825927734375 -0.857464599609377 +0.8045 0.1937255859375 0.027587890625 -0.857464599609377 +0.804625 0.1937255859375 0.027587890625 -0.857464599609377 +0.80475 0.188873291015625 0.026885986328125 -0.857464599609377 +0.804875 0.18402099609375 0.026214599609375 -0.857464599609377 +0.805 0.18402099609375 0.026214599609375 -0.857464599609377 +0.805125 0.17913818359375 0.0255126953125 -0.857464599609377 +0.80525 0.17913818359375 0.0255126953125 -0.857464599609377 +0.8053750000000001 0.17425537109375 0.024810791015625 -0.857464599609377 +0.8055 0.169342041015625 0.02410888671875 -0.857464599609377 +0.805625 0.169342041015625 0.02410888671875 -0.857464599609377 +0.80575 0.164398193359375 0.023406982421875 -0.857464599609377 +0.805875 0.164398193359375 0.023406982421875 -0.857464599609377 +0.806 0.159454345703125 0.022705078125 -0.857464599609377 +0.806125 0.15447998046875 0.022003173828125 -0.857464599609377 +0.80625 0.15447998046875 0.022003173828125 -0.857464599609377 +0.8063750000000001 0.14947509765625 0.021270751953125 -0.857464599609377 +0.8065 0.14947509765625 0.021270751953125 -0.857464599609377 +0.806625 0.14447021484375 0.02056884765625 -0.857464599609377 +0.80675 0.13946533203125 0.019866943359375 -0.857464599609377 +0.806875 0.13946533203125 0.019866943359375 -0.857464599609377 +0.8070000000000001 0.134429931640625 0.019134521484375 -0.857464599609377 +0.807125 0.134429931640625 0.019134521484375 -0.857464599609377 +0.80725 0.129364013671875 0.0184326171875 -0.857464599609377 +0.8073750000000001 0.124298095703125 0.0177001953125 -0.857464599609377 +0.8075 0.124298095703125 0.0177001953125 -0.857464599609377 +0.807625 0.119232177734375 0.0169677734375 -0.857464599609377 +0.80775 0.119232177734375 0.0169677734375 -0.857464599609377 +0.807875 0.1141357421875 0.0162353515625 -0.857464599609377 +0.8080000000000001 0.109039306640625 0.015533447265625 -0.857464599609377 +0.808125 0.109039306640625 0.015533447265625 -0.857464599609377 +0.80825 0.103912353515625 0.014801025390625 -0.857464599609377 +0.8083750000000001 0.103912353515625 0.014801025390625 -0.857464599609377 +0.8085 0.098785400390625 0.014068603515625 -0.857464599609377 +0.808625 0.093658447265625 0.013336181640625 -0.857464599609377 +0.80875 0.093658447265625 0.013336181640625 -0.857464599609377 +0.808875 0.0885009765625 0.012603759765625 -0.857464599609377 +0.8090000000000001 0.0885009765625 0.012603759765625 -0.857464599609377 +0.809125 0.083343505859375 0.011871337890625 -0.857464599609377 +0.80925 0.07818603515625 0.011138916015625 -0.857464599609377 +0.8093750000000001 0.07818603515625 0.011138916015625 -0.857464599609377 +0.8095 0.072998046875 0.0103759765625 -0.857464599609377 +0.809625 0.072998046875 0.0103759765625 -0.857464599609377 +0.80975 0.06781005859375 0.0096435546875 -0.857464599609377 +0.809875 0.0626220703125 0.0089111328125 -0.857464599609377 +0.8100000000000001 0.0626220703125 0.0089111328125 -0.857464599609377 +0.810125 0.05743408203125 0.0081787109375 -0.857464599609377 +0.81025 0.05743408203125 0.0081787109375 -0.857464599609377 +0.8103750000000001 0.05224609375 0.007415771484375 -0.857464599609377 +0.8105 0.047027587890625 0.006683349609375 -0.857464599609377 +0.810625 0.047027587890625 0.006683349609375 -0.857464599609377 +0.81075 0.04180908203125 0.005950927734375 -0.857464599609377 +0.810875 0.04180908203125 0.005950927734375 -0.857464599609377 +0.8110000000000001 0.036590576171875 0.00518798828125 -0.857464599609377 +0.811125 0.0313720703125 0.00445556640625 -0.857464599609377 +0.81125 0.0313720703125 0.00445556640625 -0.857464599609377 +0.8113750000000001 0.026123046875 0.00372314453125 -0.857464599609377 +0.8115 0.026123046875 0.00372314453125 -0.857464599609377 +0.811625 0.020904541015625 0.002960205078125 -0.857464599609377 +0.81175 0.01568603515625 0.002227783203125 -0.857464599609377 +0.811875 0.01568603515625 0.002227783203125 -0.857464599609377 +0.8120000000000001 0.01043701171875 0.00146484375 -0.857464599609377 +0.812125 0.01043701171875 0.00146484375 -0.857464599609377 +0.81225 0.005218505859375 0.000732421875 -0.857464599609377 +0.8123750000000001 0.0 0.0 -0.857464599609377 +0.8125 0.0 0.0 -0.857464599609377 +0.812625 -0.005218505859375 -0.000732421875 -0.857464599609377 +0.81275 -0.005218505859375 -0.000732421875 -0.857464599609377 +0.812875 -0.01043701171875 -0.00146484375 -0.857464599609377 +0.8130000000000001 -0.01568603515625 -0.002227783203125 -0.857464599609377 +0.813125 -0.01568603515625 -0.002227783203125 -0.857464599609377 +0.81325 -0.020904541015625 -0.002960205078125 -0.857464599609377 +0.8133750000000001 -0.020904541015625 -0.002960205078125 -0.857464599609377 +0.8135 -0.026123046875 -0.00372314453125 -0.857464599609377 +0.813625 -0.0313720703125 -0.00445556640625 -0.857464599609377 +0.81375 -0.0313720703125 -0.00445556640625 -0.857464599609377 +0.813875 -0.036590576171875 -0.00518798828125 -0.857464599609377 +0.8140000000000001 -0.036590576171875 -0.00518798828125 -0.857464599609377 +0.814125 -0.04180908203125 -0.005950927734375 -0.857464599609377 +0.81425 -0.047027587890625 -0.006683349609375 -0.857464599609377 +0.8143750000000001 -0.047027587890625 -0.006683349609375 -0.857464599609377 +0.8145 -0.05224609375 -0.007415771484375 -0.857464599609377 +0.814625 -0.05224609375 -0.007415771484375 -0.857464599609377 +0.81475 -0.05743408203125 -0.0081787109375 -0.857464599609377 +0.814875 -0.0626220703125 -0.0089111328125 -0.857464599609377 +0.8150000000000001 -0.0626220703125 -0.0089111328125 -0.857464599609377 +0.815125 -0.06781005859375 -0.0096435546875 -0.857464599609377 +0.81525 -0.06781005859375 -0.0096435546875 -0.857464599609377 +0.8153750000000001 -0.072998046875 -0.0103759765625 -0.857464599609377 +0.8155 -0.07818603515625 -0.011138916015625 -0.857464599609377 +0.815625 -0.07818603515625 -0.011138916015625 -0.857464599609377 +0.81575 -0.083343505859375 -0.011871337890625 -0.857464599609377 +0.815875 -0.083343505859375 -0.011871337890625 -0.857464599609377 +0.8160000000000001 -0.0885009765625 -0.012603759765625 -0.857464599609377 +0.816125 -0.093658447265625 -0.013336181640625 -0.857464599609377 +0.81625 -0.093658447265625 -0.013336181640625 -0.857464599609377 +0.816375 -0.098785400390625 -0.014068603515625 -0.857464599609377 +0.8165 -0.098785400390625 -0.014068603515625 -0.857464599609377 +0.816625 -0.103912353515625 -0.014801025390625 -0.857464599609377 +0.81675 -0.109039306640625 -0.015533447265625 -0.857464599609377 +0.816875 -0.109039306640625 -0.015533447265625 -0.857464599609377 +0.8170000000000001 -0.1141357421875 -0.0162353515625 -0.857464599609377 +0.817125 -0.1141357421875 -0.0162353515625 -0.857464599609377 +0.81725 -0.119232177734375 -0.0169677734375 -0.857464599609377 +0.817375 -0.124298095703125 -0.0177001953125 -0.857464599609377 +0.8175 -0.124298095703125 -0.0177001953125 -0.857464599609377 +0.817625 -0.129364013671875 -0.0184326171875 -0.857464599609377 +0.81775 -0.129364013671875 -0.0184326171875 -0.857464599609377 +0.817875 -0.134429931640625 -0.019134521484375 -0.857464599609377 +0.8180000000000001 -0.13946533203125 -0.019866943359375 -0.857464599609377 +0.818125 -0.13946533203125 -0.019866943359375 -0.857464599609377 +0.81825 -0.14447021484375 -0.02056884765625 -0.857464599609377 +0.818375 -0.14447021484375 -0.02056884765625 -0.857464599609377 +0.8185 -0.14947509765625 -0.021270751953125 -0.857464599609377 +0.818625 -0.15447998046875 -0.022003173828125 -0.857464599609377 +0.81875 -0.15447998046875 -0.022003173828125 -0.857464599609377 +0.818875 -0.159454345703125 -0.022705078125 -0.857464599609377 +0.8190000000000001 -0.159454345703125 -0.022705078125 -0.857464599609377 +0.819125 -0.164398193359375 -0.023406982421875 -0.857464599609377 +0.81925 -0.169342041015625 -0.02410888671875 -0.857464599609377 +0.819375 -0.169342041015625 -0.02410888671875 -0.857464599609377 +0.8195 -0.17425537109375 -0.024810791015625 -0.857464599609377 +0.819625 -0.17425537109375 -0.024810791015625 -0.857464599609377 +0.81975 -0.17913818359375 -0.0255126953125 -0.857464599609377 +0.819875 -0.18402099609375 -0.026214599609375 -0.857464599609377 +0.8200000000000001 -0.18402099609375 -0.026214599609375 -0.857464599609377 +0.820125 -0.188873291015625 -0.026885986328125 -0.857464599609377 +0.82025 -0.188873291015625 -0.026885986328125 -0.857464599609377 +0.820375 -0.1937255859375 -0.027587890625 -0.857464599609377 +0.8205 -0.19854736328125 -0.02825927734375 -0.857464599609377 +0.820625 -0.19854736328125 -0.02825927734375 -0.857464599609377 +0.82075 -0.203338623046875 -0.028961181640625 -0.857464599609377 +0.820875 -0.203338623046875 -0.028961181640625 -0.857464599609377 +0.8210000000000001 -0.208099365234375 -0.029632568359375 -0.857464599609377 +0.821125 -0.212860107421875 -0.030303955078125 -0.857464599609377 +0.82125 -0.212860107421875 -0.030303955078125 -0.857464599609377 +0.821375 -0.21759033203125 -0.030975341796875 -0.857464599609377 +0.8215 -0.21759033203125 -0.030975341796875 -0.857464599609377 +0.821625 -0.2222900390625 -0.031646728515625 -0.857464599609377 +0.82175 -0.226959228515625 -0.032318115234375 -0.857464599609377 +0.821875 -0.226959228515625 -0.032318115234375 -0.857464599609377 +0.8220000000000001 -0.231597900390625 -0.032989501953125 -0.857464599609377 +0.822125 -0.231597900390625 -0.032989501953125 -0.857464599609377 +0.82225 -0.236236572265625 -0.03363037109375 -0.857464599609377 +0.822375 -0.2408447265625 -0.0343017578125 -0.857464599609377 +0.8225 -0.2408447265625 -0.0343017578125 -0.857464599609377 +0.8226250000000001 -0.24542236328125 -0.034942626953125 -0.857464599609377 +0.82275 -0.24542236328125 -0.034942626953125 -0.857464599609377 +0.822875 -0.249969482421875 -0.03558349609375 -0.857464599609377 +0.8230000000000001 -0.25445556640625 -0.0362548828125 -0.857464599609377 +0.823125 -0.25445556640625 -0.0362548828125 -0.857464599609377 +0.82325 -0.25897216796875 -0.036895751953125 -0.857464599609377 +0.823375 -0.25897216796875 -0.036895751953125 -0.857464599609377 +0.8235 -0.263427734375 -0.037506103515625 -0.857464599609377 +0.8236250000000001 -0.267852783203125 -0.03814697265625 -0.857464599609377 +0.82375 -0.267852783203125 -0.03814697265625 -0.857464599609377 +0.823875 -0.27227783203125 -0.038787841796875 -0.857464599609377 +0.8240000000000001 -0.27227783203125 -0.038787841796875 -0.857464599609377 +0.824125 -0.276641845703125 -0.039398193359375 -0.857464599609377 +0.82425 -0.280975341796875 -0.040008544921875 -0.857464599609377 +0.824375 -0.280975341796875 -0.040008544921875 -0.857464599609377 +0.8245 -0.285308837890625 -0.040618896484375 -0.857464599609377 +0.8246250000000001 -0.285308837890625 -0.040618896484375 -0.857464599609377 +0.82475 -0.289581298828125 -0.041229248046875 -0.857464599609377 +0.824875 -0.2938232421875 -0.041839599609375 -0.857464599609377 +0.8250000000000001 -0.2938232421875 -0.041839599609375 -0.857464599609377 +0.825125 -0.298065185546875 -0.042449951171875 -0.857464599609377 +0.82525 -0.298065185546875 -0.042449951171875 -0.857464599609377 +0.825375 -0.30224609375 -0.043060302734375 -0.857464599609377 +0.8255 -0.306396484375 -0.04364013671875 -0.857464599609377 +0.8256250000000001 -0.306396484375 -0.04364013671875 -0.857464599609377 +0.82575 -0.310516357421875 -0.044219970703125 -0.857464599609377 +0.825875 -0.310516357421875 -0.044219970703125 -0.857464599609377 +0.8260000000000001 -0.314605712890625 -0.0447998046875 -0.857464599609377 +0.826125 -0.31866455078125 -0.045379638671875 -0.857464599609377 +0.82625 -0.31866455078125 -0.045379638671875 -0.857464599609377 +0.826375 -0.322662353515625 -0.04595947265625 -0.857464599609377 +0.8265 -0.322662353515625 -0.04595947265625 -0.857464599609377 +0.8266250000000001 -0.32666015625 -0.0465087890625 -0.857464599609377 +0.82675 -0.330596923828125 -0.047088623046875 -0.857464599609377 +0.826875 -0.330596923828125 -0.047088623046875 -0.857464599609377 +0.8270000000000001 -0.334503173828125 -0.047637939453125 -0.857464599609377 +0.827125 -0.334503173828125 -0.047637939453125 -0.857464599609377 +0.82725 -0.33837890625 -0.048187255859375 -0.857464599609377 +0.827375 -0.34222412109375 -0.048736572265625 -0.857464599609377 +0.8275 -0.34222412109375 -0.048736572265625 -0.857464599609377 +0.8276250000000001 -0.34600830078125 -0.049285888671875 -0.857464599609377 +0.82775 -0.34600830078125 -0.049285888671875 -0.857464599609377 +0.827875 -0.349761962890625 -0.0498046875 -0.857464599609377 +0.8280000000000001 -0.353485107421875 -0.05035400390625 -0.857464599609377 +0.828125 -0.353485107421875 -0.05035400390625 -0.857464599609377 +0.82825 -0.357177734375 -0.050872802734375 -0.857464599609377 +0.828375 -0.357177734375 -0.050872802734375 -0.857464599609377 +0.8285 -0.360809326171875 -0.0513916015625 -0.857464599609377 +0.8286250000000001 -0.36444091796875 -0.051910400390625 -0.857464599609377 +0.82875 -0.36444091796875 -0.051910400390625 -0.857464599609377 +0.828875 -0.36798095703125 -0.052398681640625 -0.857464599609377 +0.8290000000000001 -0.36798095703125 -0.052398681640625 -0.857464599609377 +0.829125 -0.37152099609375 -0.05291748046875 -0.857464599609377 +0.82925 -0.375 -0.05340576171875 -0.857464599609377 +0.829375 -0.375 -0.05340576171875 -0.857464599609377 +0.8295 -0.378448486328125 -0.05389404296875 -0.857464599609377 +0.8296250000000001 -0.378448486328125 -0.05389404296875 -0.857464599609377 +0.82975 -0.3818359375 -0.05438232421875 -0.857464599609377 +0.829875 -0.38519287109375 -0.05487060546875 -0.857464599609377 +0.8300000000000001 -0.38519287109375 -0.05487060546875 -0.857464599609377 +0.830125 -0.388519287109375 -0.055328369140625 -0.857464599609377 +0.83025 -0.388519287109375 -0.055328369140625 -0.857464599609377 +0.830375 -0.39178466796875 -0.055816650390625 -0.857464599609377 +0.8305 -0.39501953125 -0.0562744140625 -0.857464599609377 +0.8306250000000001 -0.39501953125 -0.0562744140625 -0.857464599609377 +0.83075 -0.398193359375 -0.05670166015625 -0.857464599609377 +0.830875 -0.398193359375 -0.05670166015625 -0.857464599609377 +0.8310000000000001 -0.401336669921875 -0.057159423828125 -0.857464599609377 +0.831125 -0.404449462890625 -0.0576171875 -0.857464599609377 +0.83125 -0.404449462890625 -0.0576171875 -0.857464599609377 +0.831375 -0.407501220703125 -0.05804443359375 -0.857464599609377 +0.8315 -0.407501220703125 -0.05804443359375 -0.857464599609377 +0.8316250000000001 -0.4105224609375 -0.0584716796875 -0.857464599609377 +0.83175 -0.413482666015625 -0.05889892578125 -0.857464599609377 +0.831875 -0.413482666015625 -0.05889892578125 -0.857464599609377 +0.8320000000000001 -0.416412353515625 -0.003936767578125 -0.9903991699218756 +0.832125 -0.416412353515625 -0.003936767578125 -0.9903991699218756 +0.83225 -0.419281005859375 -0.00396728515625 -0.9903991699218756 +0.832375 -0.422119140625 -0.003997802734375 -0.9903991699218756 +0.8325 -0.422119140625 -0.003997802734375 -0.9903991699218756 +0.8326250000000001 -0.424896240234375 -0.0040283203125 -0.9903991699218756 +0.83275 -0.424896240234375 -0.0040283203125 -0.9903991699218756 +0.832875 -0.4276123046875 -0.004058837890625 -0.9903991699218756 +0.833 -0.4302978515625 -0.00408935546875 -0.9903991699218756 +0.833125 -0.4302978515625 -0.00408935546875 -0.9903991699218756 +0.83325 -0.432952880859375 -0.004119873046875 -0.9903991699218756 +0.833375 -0.432952880859375 -0.004119873046875 -0.9903991699218756 +0.8335 -0.435546875 -0.004119873046875 -0.9903991699218756 +0.8336250000000001 -0.438079833984375 -0.004150390625 -0.9903991699218756 +0.83375 -0.438079833984375 -0.004150390625 -0.9903991699218756 +0.833875 -0.440582275390625 -0.004180908203125 -0.9903991699218756 +0.834 -0.440582275390625 -0.004180908203125 -0.9903991699218756 +0.834125 -0.44305419921875 -0.00421142578125 -0.9903991699218756 +0.83425 -0.4454345703125 -0.00421142578125 -0.9903991699218756 +0.834375 -0.4454345703125 -0.00421142578125 -0.9903991699218756 +0.8345 -0.447784423828125 -0.004241943359375 -0.9903991699218756 +0.8346250000000001 -0.447784423828125 -0.004241943359375 -0.9903991699218756 +0.83475 -0.450103759765625 -0.0042724609375 -0.9903991699218756 +0.834875 -0.452362060546875 -0.004302978515625 -0.9903991699218756 +0.835 -0.452362060546875 -0.004302978515625 -0.9903991699218756 +0.835125 -0.454559326171875 -0.004302978515625 -0.9903991699218756 +0.83525 -0.454559326171875 -0.004302978515625 -0.9903991699218756 +0.835375 -0.45672607421875 -0.00433349609375 -0.9903991699218756 +0.8355 -0.458831787109375 -0.004364013671875 -0.9903991699218756 +0.8356250000000001 -0.458831787109375 -0.004364013671875 -0.9903991699218756 +0.83575 -0.46087646484375 -0.004364013671875 -0.9903991699218756 +0.835875 -0.46087646484375 -0.004364013671875 -0.9903991699218756 +0.836 -0.462890625 -0.00439453125 -0.9903991699218756 +0.836125 -0.464813232421875 -0.004425048828125 -0.9903991699218756 +0.83625 -0.464813232421875 -0.004425048828125 -0.9903991699218756 +0.836375 -0.46673583984375 -0.004425048828125 -0.9903991699218756 +0.8365 -0.46673583984375 -0.004425048828125 -0.9903991699218756 +0.8366250000000001 -0.46856689453125 -0.00445556640625 -0.9903991699218756 +0.83675 -0.470367431640625 -0.00445556640625 -0.9903991699218756 +0.836875 -0.470367431640625 -0.00445556640625 -0.9903991699218756 +0.837 -0.472137451171875 -0.004486083984375 -0.9903991699218756 +0.837125 -0.472137451171875 -0.004486083984375 -0.9903991699218756 +0.83725 -0.47381591796875 -0.004486083984375 -0.9903991699218756 +0.837375 -0.4754638671875 -0.0045166015625 -0.9903991699218756 +0.8375 -0.4754638671875 -0.0045166015625 -0.9903991699218756 +0.8376250000000001 -0.47705078125 -0.0045166015625 -0.9903991699218756 +0.83775 -0.47705078125 -0.0045166015625 -0.9903991699218756 +0.837875 -0.478607177734375 -0.004547119140625 -0.9903991699218756 +0.838 -0.480072021484375 -0.004547119140625 -0.9903991699218756 +0.838125 -0.480072021484375 -0.004547119140625 -0.9903991699218756 +0.8382500000000001 -0.48150634765625 -0.00457763671875 -0.9903991699218756 +0.838375 -0.48150634765625 -0.00457763671875 -0.9903991699218756 +0.8385 -0.48291015625 -0.00457763671875 -0.9903991699218756 +0.8386250000000001 -0.484222412109375 -0.004608154296875 -0.9903991699218756 +0.83875 -0.484222412109375 -0.004608154296875 -0.9903991699218756 +0.838875 -0.485504150390625 -0.004608154296875 -0.9903991699218756 +0.839 -0.485504150390625 -0.004608154296875 -0.9903991699218756 +0.839125 -0.486724853515625 -0.004608154296875 -0.9903991699218756 +0.8392500000000001 -0.487884521484375 -0.004638671875 -0.9903991699218756 +0.839375 -0.487884521484375 -0.004638671875 -0.9903991699218756 +0.8395 -0.489013671875 -0.004638671875 -0.9903991699218756 +0.8396250000000001 -0.489013671875 -0.004638671875 -0.9903991699218756 +0.83975 -0.490081787109375 -0.004638671875 -0.9903991699218756 +0.839875 -0.4910888671875 -0.004669189453125 -0.9903991699218756 +0.84 -0.4910888671875 -0.004669189453125 -0.9903991699218756 +0.840125 -0.492034912109375 -0.004669189453125 -0.9903991699218756 +0.8402500000000001 -0.492034912109375 -0.004669189453125 -0.9903991699218756 +0.840375 -0.492950439453125 -0.004669189453125 -0.9903991699218756 +0.8405 -0.4937744140625 -0.00469970703125 -0.9903991699218756 +0.8406250000000001 -0.4937744140625 -0.00469970703125 -0.9903991699218756 +0.84075 -0.49456787109375 -0.00469970703125 -0.9903991699218756 +0.840875 -0.49456787109375 -0.00469970703125 -0.9903991699218756 +0.841 -0.49530029296875 -0.00469970703125 -0.9903991699218756 +0.841125 -0.496002197265625 -0.00469970703125 -0.9903991699218756 +0.8412500000000001 -0.496002197265625 -0.00469970703125 -0.9903991699218756 +0.841375 -0.496612548828125 -0.00469970703125 -0.9903991699218756 +0.8415 -0.496612548828125 -0.00469970703125 -0.9903991699218756 +0.8416250000000001 -0.4971923828125 -0.004730224609375 -0.9903991699218756 +0.84175 -0.497711181640625 -0.004730224609375 -0.9903991699218756 +0.841875 -0.497711181640625 -0.004730224609375 -0.9903991699218756 +0.842 -0.498199462890625 -0.004730224609375 -0.9903991699218756 +0.842125 -0.498199462890625 -0.004730224609375 -0.9903991699218756 +0.8422500000000001 -0.49859619140625 -0.004730224609375 -0.9903991699218756 +0.842375 -0.49896240234375 -0.004730224609375 -0.9903991699218756 +0.8425 -0.49896240234375 -0.004730224609375 -0.9903991699218756 +0.8426250000000001 -0.499267578125 -0.004730224609375 -0.9903991699218756 +0.84275 -0.499267578125 -0.004730224609375 -0.9903991699218756 +0.842875 -0.49951171875 -0.004730224609375 -0.9903991699218756 +0.843 -0.49969482421875 -0.004730224609375 -0.9903991699218756 +0.843125 -0.49969482421875 -0.004730224609375 -0.9903991699218756 +0.8432500000000001 -0.49981689453125 -0.004730224609375 -0.9903991699218756 +0.843375 -0.49981689453125 -0.004730224609375 -0.9903991699218756 +0.8435 -0.499908447265625 -0.004730224609375 -0.9903991699218756 +0.8436250000000001 -0.49993896484375 -0.004730224609375 -0.9903991699218756 +0.84375 -0.49993896484375 -0.004730224609375 -0.9903991699218756 +0.843875 -0.499908447265625 -0.004730224609375 -0.9903991699218756 +0.844 -0.499908447265625 -0.004730224609375 -0.9903991699218756 +0.844125 -0.49981689453125 -0.004730224609375 -0.9903991699218756 +0.8442500000000001 -0.49969482421875 -0.004730224609375 -0.9903991699218756 +0.844375 -0.49969482421875 -0.004730224609375 -0.9903991699218756 +0.8445 -0.49951171875 -0.004730224609375 -0.9903991699218756 +0.8446250000000001 -0.49951171875 -0.004730224609375 -0.9903991699218756 +0.84475 -0.499267578125 -0.004730224609375 -0.9903991699218756 +0.844875 -0.49896240234375 -0.004730224609375 -0.9903991699218756 +0.845 -0.49896240234375 -0.004730224609375 -0.9903991699218756 +0.845125 -0.49859619140625 -0.004730224609375 -0.9903991699218756 +0.8452500000000001 -0.49859619140625 -0.004730224609375 -0.9903991699218756 +0.845375 -0.498199462890625 -0.004730224609375 -0.9903991699218756 +0.8455 -0.497711181640625 -0.004730224609375 -0.9903991699218756 +0.8456250000000001 -0.497711181640625 -0.004730224609375 -0.9903991699218756 +0.84575 -0.4971923828125 -0.004730224609375 -0.9903991699218756 +0.845875 -0.4971923828125 -0.004730224609375 -0.9903991699218756 +0.846 -0.496612548828125 -0.00469970703125 -0.9903991699218756 +0.846125 -0.496002197265625 -0.00469970703125 -0.9903991699218756 +0.8462500000000001 -0.496002197265625 -0.00469970703125 -0.9903991699218756 +0.846375 -0.49530029296875 -0.00469970703125 -0.9903991699218756 +0.8465 -0.49530029296875 -0.00469970703125 -0.9903991699218756 +0.8466250000000001 -0.49456787109375 -0.00469970703125 -0.9903991699218756 +0.84675 -0.4937744140625 -0.00469970703125 -0.9903991699218756 +0.846875 -0.4937744140625 -0.00469970703125 -0.9903991699218756 +0.847 -0.492950439453125 -0.004669189453125 -0.9903991699218756 +0.847125 -0.492950439453125 -0.004669189453125 -0.9903991699218756 +0.8472500000000001 -0.492034912109375 -0.004669189453125 -0.9903991699218756 +0.847375 -0.4910888671875 -0.004669189453125 -0.9903991699218756 +0.8475 -0.4910888671875 -0.004669189453125 -0.9903991699218756 +0.8476250000000001 -0.490081787109375 -0.004638671875 -0.9903991699218756 +0.84775 -0.490081787109375 -0.004638671875 -0.9903991699218756 +0.847875 -0.489013671875 -0.004638671875 -0.9903991699218756 +0.848 -0.487884521484375 -0.004638671875 -0.9903991699218756 +0.848125 -0.487884521484375 -0.004638671875 -0.9903991699218756 +0.8482500000000001 -0.486724853515625 -0.004608154296875 -0.9903991699218756 +0.848375 -0.486724853515625 -0.004608154296875 -0.9903991699218756 +0.8485 -0.485504150390625 -0.004608154296875 -0.9903991699218756 +0.848625 -0.484222412109375 -0.004608154296875 -0.9903991699218756 +0.84875 -0.484222412109375 -0.004608154296875 -0.9903991699218756 +0.848875 -0.48291015625 -0.00457763671875 -0.9903991699218756 +0.849 -0.48291015625 -0.00457763671875 -0.9903991699218756 +0.849125 -0.48150634765625 -0.00457763671875 -0.9903991699218756 +0.8492500000000001 -0.480072021484375 -0.004547119140625 -0.9903991699218756 +0.849375 -0.480072021484375 -0.004547119140625 -0.9903991699218756 +0.8495 -0.478607177734375 -0.004547119140625 -0.9903991699218756 +0.849625 -0.478607177734375 -0.004547119140625 -0.9903991699218756 +0.84975 -0.47705078125 -0.0045166015625 -0.9903991699218756 +0.849875 -0.4754638671875 -0.0045166015625 -0.9903991699218756 +0.85 -0.4754638671875 -0.0045166015625 -0.9903991699218756 +0.850125 -0.47381591796875 -0.004486083984375 -0.9903991699218756 +0.8502500000000001 -0.47381591796875 -0.004486083984375 -0.9903991699218756 +0.850375 -0.472137451171875 -0.004486083984375 -0.9903991699218756 +0.8505 -0.470367431640625 -0.00445556640625 -0.9903991699218756 +0.850625 -0.470367431640625 -0.00445556640625 -0.9903991699218756 +0.85075 -0.46856689453125 -0.00445556640625 -0.9903991699218756 +0.850875 -0.46856689453125 -0.00445556640625 -0.9903991699218756 +0.851 -0.46673583984375 -0.004425048828125 -0.9903991699218756 +0.851125 -0.464813232421875 -0.004425048828125 -0.9903991699218756 +0.8512500000000001 -0.464813232421875 -0.004425048828125 -0.9903991699218756 +0.851375 -0.462890625 -0.00439453125 -0.9903991699218756 +0.8515 -0.462890625 -0.00439453125 -0.9903991699218756 +0.851625 -0.46087646484375 -0.004364013671875 -0.9903991699218756 +0.85175 -0.458831787109375 -0.004364013671875 -0.9903991699218756 +0.851875 -0.458831787109375 -0.004364013671875 -0.9903991699218756 +0.852 -0.45672607421875 -0.00433349609375 -0.9903991699218756 +0.852125 -0.45672607421875 -0.00433349609375 -0.9903991699218756 +0.8522500000000001 -0.454559326171875 -0.004302978515625 -0.9903991699218756 +0.852375 -0.452362060546875 -0.004302978515625 -0.9903991699218756 +0.8525 -0.452362060546875 -0.004302978515625 -0.9903991699218756 +0.852625 -0.450103759765625 -0.0042724609375 -0.9903991699218756 +0.85275 -0.450103759765625 -0.0042724609375 -0.9903991699218756 +0.852875 -0.447784423828125 -0.004241943359375 -0.9903991699218756 +0.853 -0.4454345703125 -0.00421142578125 -0.9903991699218756 +0.853125 -0.4454345703125 -0.00421142578125 -0.9903991699218756 +0.8532500000000001 -0.44305419921875 -0.00421142578125 -0.9903991699218756 +0.853375 -0.44305419921875 -0.00421142578125 -0.9903991699218756 +0.8535 -0.440582275390625 -0.004180908203125 -0.9903991699218756 +0.853625 -0.438079833984375 -0.004150390625 -0.9903991699218756 +0.85375 -0.438079833984375 -0.004150390625 -0.9903991699218756 +0.8538750000000001 -0.435546875 -0.004119873046875 -0.9903991699218756 +0.854 -0.435546875 -0.004119873046875 -0.9903991699218756 +0.854125 -0.432952880859375 -0.004119873046875 -0.9903991699218756 +0.8542500000000001 -0.4302978515625 -0.00408935546875 -0.9903991699218756 +0.854375 -0.4302978515625 -0.00408935546875 -0.9903991699218756 +0.8545 -0.4276123046875 -0.004058837890625 -0.9903991699218756 +0.854625 -0.4276123046875 -0.004058837890625 -0.9903991699218756 +0.85475 -0.424896240234375 -0.0040283203125 -0.9903991699218756 +0.8548750000000001 -0.422119140625 -0.003997802734375 -0.9903991699218756 +0.855 -0.422119140625 -0.003997802734375 -0.9903991699218756 +0.855125 -0.419281005859375 -0.00396728515625 -0.9903991699218756 +0.8552500000000001 -0.419281005859375 -0.00396728515625 -0.9903991699218756 +0.855375 -0.416412353515625 -0.003936767578125 -0.9903991699218756 +0.8555 -0.413482666015625 -0.003936767578125 -0.9903991699218756 +0.855625 -0.413482666015625 -0.003936767578125 -0.9903991699218756 +0.85575 -0.4105224609375 -0.00390625 -0.9903991699218756 +0.8558750000000001 -0.4105224609375 -0.00390625 -0.9903991699218756 +0.856 -0.407501220703125 -0.003875732421875 -0.9903991699218756 +0.856125 -0.404449462890625 -0.00384521484375 -0.9903991699218756 +0.8562500000000001 -0.404449462890625 -0.00384521484375 -0.9903991699218756 +0.856375 -0.401336669921875 -0.003814697265625 -0.9903991699218756 +0.8565 -0.401336669921875 -0.003814697265625 -0.9903991699218756 +0.856625 -0.398193359375 -0.0037841796875 -0.9903991699218756 +0.85675 -0.39501953125 -0.003753662109375 -0.9903991699218756 +0.8568750000000001 -0.39501953125 -0.003753662109375 -0.9903991699218756 +0.857 -0.39178466796875 -0.00372314453125 -0.9903991699218756 +0.857125 -0.39178466796875 -0.00372314453125 -0.9903991699218756 +0.8572500000000001 -0.388519287109375 -0.003692626953125 -0.9903991699218756 +0.857375 -0.38519287109375 -0.003662109375 -0.9903991699218756 +0.8575 -0.38519287109375 -0.003662109375 -0.9903991699218756 +0.857625 -0.3818359375 -0.003631591796875 -0.9903991699218756 +0.85775 -0.3818359375 -0.003631591796875 -0.9903991699218756 +0.8578750000000001 -0.378448486328125 -0.00360107421875 -0.9903991699218756 +0.858 -0.375 -0.003570556640625 -0.9903991699218756 +0.858125 -0.375 -0.003570556640625 -0.9903991699218756 +0.8582500000000001 -0.37152099609375 -0.003509521484375 -0.9903991699218756 +0.858375 -0.37152099609375 -0.003509521484375 -0.9903991699218756 +0.8585 -0.36798095703125 -0.00347900390625 -0.9903991699218756 +0.858625 -0.36444091796875 -0.003448486328125 -0.9903991699218756 +0.85875 -0.36444091796875 -0.003448486328125 -0.9903991699218756 +0.8588750000000001 -0.360809326171875 -0.00341796875 -0.9903991699218756 +0.859 -0.360809326171875 -0.00341796875 -0.9903991699218756 +0.859125 -0.357177734375 -0.003387451171875 -0.9903991699218756 +0.8592500000000001 -0.353485107421875 -0.00335693359375 -0.9903991699218756 +0.859375 -0.353485107421875 -0.00335693359375 -0.9903991699218756 +0.8595 -0.349761962890625 -0.003326416015625 -0.9903991699218756 +0.859625 -0.349761962890625 -0.003326416015625 -0.9903991699218756 +0.85975 -0.34600830078125 -0.003265380859375 -0.9903991699218756 +0.8598750000000001 -0.34222412109375 -0.00323486328125 -0.9903991699218756 +0.86 -0.34222412109375 -0.00323486328125 -0.9903991699218756 +0.860125 -0.33837890625 -0.003204345703125 -0.9903991699218756 +0.8602500000000001 -0.33837890625 -0.003204345703125 -0.9903991699218756 +0.860375 -0.334503173828125 -0.003173828125 -0.9903991699218756 +0.8605 -0.330596923828125 -0.003143310546875 -0.9903991699218756 +0.860625 -0.330596923828125 -0.003143310546875 -0.9903991699218756 +0.86075 -0.32666015625 -0.003082275390625 -0.9903991699218756 +0.8608750000000001 -0.32666015625 -0.003082275390625 -0.9903991699218756 +0.861 -0.322662353515625 -0.0030517578125 -0.9903991699218756 +0.861125 -0.31866455078125 -0.003021240234375 -0.9903991699218756 +0.8612500000000001 -0.31866455078125 -0.003021240234375 -0.9903991699218756 +0.861375 -0.314605712890625 -0.00299072265625 -0.9903991699218756 +0.8615 -0.314605712890625 -0.00299072265625 -0.9903991699218756 +0.861625 -0.310516357421875 -0.0029296875 -0.9903991699218756 +0.86175 -0.306396484375 -0.002899169921875 -0.9903991699218756 +0.8618750000000001 -0.306396484375 -0.002899169921875 -0.9903991699218756 +0.862 -0.30224609375 -0.00286865234375 -0.9903991699218756 +0.862125 -0.30224609375 -0.00286865234375 -0.9903991699218756 +0.8622500000000001 -0.298065185546875 -0.002838134765625 -0.9903991699218756 +0.862375 -0.2938232421875 -0.002777099609375 -0.9903991699218756 +0.8625 -0.2938232421875 -0.002777099609375 -0.9903991699218756 +0.862625 -0.289581298828125 -0.00274658203125 -0.9903991699218756 +0.86275 -0.289581298828125 -0.00274658203125 -0.9903991699218756 +0.8628750000000001 -0.285308837890625 -0.002716064453125 -0.9903991699218756 +0.863 -0.280975341796875 -0.002655029296875 -0.9903991699218756 +0.863125 -0.280975341796875 -0.002655029296875 -0.9903991699218756 +0.8632500000000001 -0.276641845703125 -0.00262451171875 -0.9903991699218756 +0.863375 -0.276641845703125 -0.00262451171875 -0.9903991699218756 +0.8635 -0.27227783203125 -0.0025634765625 -0.9903991699218756 +0.863625 -0.267852783203125 -0.002532958984375 -0.9903991699218756 +0.86375 -0.267852783203125 -0.002532958984375 -0.9903991699218756 +0.8638750000000001 -0.263427734375 -0.00250244140625 -0.9903991699218756 +0.864 -0.263427734375 -0.00909423828125 -0.9653259277343738 +0.864125 -0.25897216796875 -0.008941650390625 -0.9653259277343738 +0.86425 -0.25445556640625 -0.0087890625 -0.9653259277343738 +0.864375 -0.25445556640625 -0.0087890625 -0.9653259277343738 +0.8645 -0.249969482421875 -0.008636474609375 -0.9653259277343738 +0.864625 -0.249969482421875 -0.008636474609375 -0.9653259277343738 +0.86475 -0.24542236328125 -0.00848388671875 -0.9653259277343738 +0.8648750000000001 -0.2408447265625 -0.00830078125 -0.9653259277343738 +0.865 -0.2408447265625 -0.00830078125 -0.9653259277343738 +0.865125 -0.236236572265625 -0.008148193359375 -0.9653259277343738 +0.86525 -0.236236572265625 -0.008148193359375 -0.9653259277343738 +0.865375 -0.231597900390625 -0.00799560546875 -0.9653259277343738 +0.8655 -0.226959228515625 -0.007843017578125 -0.9653259277343738 +0.865625 -0.226959228515625 -0.007843017578125 -0.9653259277343738 +0.86575 -0.2222900390625 -0.007659912109375 -0.9653259277343738 +0.8658750000000001 -0.2222900390625 -0.007659912109375 -0.9653259277343738 +0.866 -0.21759033203125 -0.00750732421875 -0.9653259277343738 +0.866125 -0.212860107421875 -0.007354736328125 -0.9653259277343738 +0.86625 -0.212860107421875 -0.007354736328125 -0.9653259277343738 +0.866375 -0.208099365234375 -0.007171630859375 -0.9653259277343738 +0.8665 -0.208099365234375 -0.007171630859375 -0.9653259277343738 +0.866625 -0.203338623046875 -0.00701904296875 -0.9653259277343738 +0.86675 -0.19854736328125 -0.0068359375 -0.9653259277343738 +0.8668750000000001 -0.19854736328125 -0.0068359375 -0.9653259277343738 +0.867 -0.1937255859375 -0.006683349609375 -0.9653259277343738 +0.867125 -0.1937255859375 -0.006683349609375 -0.9653259277343738 +0.86725 -0.188873291015625 -0.00653076171875 -0.9653259277343738 +0.867375 -0.18402099609375 -0.00634765625 -0.9653259277343738 +0.8675 -0.18402099609375 -0.00634765625 -0.9653259277343738 +0.867625 -0.17913818359375 -0.00616455078125 -0.9653259277343738 +0.86775 -0.17913818359375 -0.00616455078125 -0.9653259277343738 +0.8678750000000001 -0.17425537109375 -0.006011962890625 -0.9653259277343738 +0.868 -0.169342041015625 -0.005828857421875 -0.9653259277343738 +0.868125 -0.169342041015625 -0.005828857421875 -0.9653259277343738 +0.86825 -0.164398193359375 -0.00567626953125 -0.9653259277343738 +0.868375 -0.164398193359375 -0.00567626953125 -0.9653259277343738 +0.8685 -0.159454345703125 -0.0054931640625 -0.9653259277343738 +0.868625 -0.15447998046875 -0.005340576171875 -0.9653259277343738 +0.86875 -0.15447998046875 -0.005340576171875 -0.9653259277343738 +0.8688750000000001 -0.14947509765625 -0.005157470703125 -0.9653259277343738 +0.869 -0.14947509765625 -0.005157470703125 -0.9653259277343738 +0.869125 -0.14447021484375 -0.004974365234375 -0.9653259277343738 +0.86925 -0.13946533203125 -0.00482177734375 -0.9653259277343738 +0.869375 -0.13946533203125 -0.00482177734375 -0.9653259277343738 +0.8695000000000001 -0.134429931640625 -0.004638671875 -0.9653259277343738 +0.869625 -0.134429931640625 -0.004638671875 -0.9653259277343738 +0.86975 -0.129364013671875 -0.00445556640625 -0.9653259277343738 +0.8698750000000001 -0.124298095703125 -0.0042724609375 -0.9653259277343738 +0.87 -0.124298095703125 -0.0042724609375 -0.9653259277343738 +0.870125 -0.119232177734375 -0.004119873046875 -0.9653259277343738 +0.87025 -0.119232177734375 -0.004119873046875 -0.9653259277343738 +0.870375 -0.1141357421875 -0.003936767578125 -0.9653259277343738 +0.8705000000000001 -0.109039306640625 -0.003753662109375 -0.9653259277343738 +0.870625 -0.109039306640625 -0.003753662109375 -0.9653259277343738 +0.87075 -0.103912353515625 -0.003570556640625 -0.9653259277343738 +0.8708750000000001 -0.103912353515625 -0.003570556640625 -0.9653259277343738 +0.871 -0.098785400390625 -0.003387451171875 -0.9653259277343738 +0.871125 -0.093658447265625 -0.00323486328125 -0.9653259277343738 +0.87125 -0.093658447265625 -0.00323486328125 -0.9653259277343738 +0.871375 -0.0885009765625 -0.0030517578125 -0.9653259277343738 +0.8715000000000001 -0.0885009765625 -0.0030517578125 -0.9653259277343738 +0.871625 -0.083343505859375 -0.00286865234375 -0.9653259277343738 +0.87175 -0.07818603515625 -0.002685546875 -0.9653259277343738 +0.8718750000000001 -0.07818603515625 -0.002685546875 -0.9653259277343738 +0.872 -0.072998046875 -0.00250244140625 -0.9653259277343738 +0.872125 -0.072998046875 -0.00250244140625 -0.9653259277343738 +0.87225 -0.06781005859375 -0.0023193359375 -0.9653259277343738 +0.872375 -0.0626220703125 -0.00213623046875 -0.9653259277343738 +0.8725000000000001 -0.0626220703125 -0.00213623046875 -0.9653259277343738 +0.872625 -0.05743408203125 -0.001983642578125 -0.9653259277343738 +0.87275 -0.05743408203125 -0.001983642578125 -0.9653259277343738 +0.8728750000000001 -0.05224609375 -0.001800537109375 -0.9653259277343738 +0.873 -0.047027587890625 -0.001617431640625 -0.9653259277343738 +0.873125 -0.047027587890625 -0.001617431640625 -0.9653259277343738 +0.87325 -0.04180908203125 -0.001434326171875 -0.9653259277343738 +0.873375 -0.04180908203125 -0.001434326171875 -0.9653259277343738 +0.8735000000000001 -0.036590576171875 -0.001251220703125 -0.9653259277343738 +0.873625 -0.0313720703125 -0.001068115234375 -0.9653259277343738 +0.87375 -0.0313720703125 -0.001068115234375 -0.9653259277343738 +0.8738750000000001 -0.026123046875 -0.000885009765625 -0.9653259277343738 +0.874 -0.026123046875 -0.000885009765625 -0.9653259277343738 +0.874125 -0.020904541015625 -0.000701904296875 -0.9653259277343738 +0.87425 -0.01568603515625 -0.000518798828125 -0.9653259277343738 +0.874375 -0.01568603515625 -0.000518798828125 -0.9653259277343738 +0.8745000000000001 -0.01043701171875 -0.000335693359375 -0.9653259277343738 +0.874625 -0.01043701171875 -0.000335693359375 -0.9653259277343738 +0.87475 -0.005218505859375 -0.000152587890625 -0.9653259277343738 +0.8748750000000001 0.0 0.0 -0.9653259277343738 +0.875 0.0 0.0 -0.9653259277343738 +0.875125 0.005218505859375 0.000152587890625 -0.9653259277343738 +0.87525 0.005218505859375 0.000152587890625 -0.9653259277343738 +0.875375 0.01043701171875 0.000335693359375 -0.9653259277343738 +0.8755000000000001 0.01568603515625 0.000518798828125 -0.9653259277343738 +0.875625 0.01568603515625 0.000518798828125 -0.9653259277343738 +0.87575 0.020904541015625 0.000701904296875 -0.9653259277343738 +0.8758750000000001 0.020904541015625 0.000701904296875 -0.9653259277343738 +0.876 0.026123046875 0.000885009765625 -0.9653259277343738 +0.876125 0.0313720703125 0.001068115234375 -0.9653259277343738 +0.87625 0.0313720703125 0.001068115234375 -0.9653259277343738 +0.876375 0.036590576171875 0.001251220703125 -0.9653259277343738 +0.8765000000000001 0.036590576171875 0.001251220703125 -0.9653259277343738 +0.876625 0.04180908203125 0.001434326171875 -0.9653259277343738 +0.87675 0.047027587890625 0.001617431640625 -0.9653259277343738 +0.8768750000000001 0.047027587890625 0.001617431640625 -0.9653259277343738 +0.877 0.05224609375 0.001800537109375 -0.9653259277343738 +0.877125 0.05224609375 0.001800537109375 -0.9653259277343738 +0.87725 0.05743408203125 0.001983642578125 -0.9653259277343738 +0.877375 0.0626220703125 0.00213623046875 -0.9653259277343738 +0.8775000000000001 0.0626220703125 0.00213623046875 -0.9653259277343738 +0.877625 0.06781005859375 0.0023193359375 -0.9653259277343738 +0.87775 0.06781005859375 0.0023193359375 -0.9653259277343738 +0.8778750000000001 0.072998046875 0.00250244140625 -0.9653259277343738 +0.878 0.07818603515625 0.002685546875 -0.9653259277343738 +0.878125 0.07818603515625 0.002685546875 -0.9653259277343738 +0.87825 0.083343505859375 0.00286865234375 -0.9653259277343738 +0.878375 0.083343505859375 0.00286865234375 -0.9653259277343738 +0.8785000000000001 0.0885009765625 0.0030517578125 -0.9653259277343738 +0.878625 0.093658447265625 0.00323486328125 -0.9653259277343738 +0.87875 0.093658447265625 0.00323486328125 -0.9653259277343738 +0.8788750000000001 0.098785400390625 0.003387451171875 -0.9653259277343738 +0.879 0.098785400390625 0.003387451171875 -0.9653259277343738 +0.879125 0.103912353515625 0.003570556640625 -0.9653259277343738 +0.87925 0.109039306640625 0.003753662109375 -0.9653259277343738 +0.879375 0.109039306640625 0.003753662109375 -0.9653259277343738 +0.8795000000000001 0.1141357421875 0.003936767578125 -0.9653259277343738 +0.879625 0.1141357421875 0.003936767578125 -0.9653259277343738 +0.87975 0.119232177734375 0.004119873046875 -0.9653259277343738 +0.8798750000000001 0.124298095703125 0.0042724609375 -0.9653259277343738 +0.88 0.124298095703125 0.0042724609375 -0.9653259277343738 +0.880125 0.129364013671875 0.00445556640625 -0.9653259277343738 +0.88025 0.129364013671875 0.00445556640625 -0.9653259277343738 +0.880375 0.134429931640625 0.004638671875 -0.9653259277343738 +0.8805000000000001 0.13946533203125 0.00482177734375 -0.9653259277343738 +0.880625 0.13946533203125 0.00482177734375 -0.9653259277343738 +0.88075 0.14447021484375 0.004974365234375 -0.9653259277343738 +0.880875 0.14447021484375 0.004974365234375 -0.9653259277343738 +0.881 0.14947509765625 0.005157470703125 -0.9653259277343738 +0.881125 0.15447998046875 0.005340576171875 -0.9653259277343738 +0.88125 0.15447998046875 0.005340576171875 -0.9653259277343738 +0.881375 0.159454345703125 0.0054931640625 -0.9653259277343738 +0.8815000000000001 0.159454345703125 0.0054931640625 -0.9653259277343738 +0.881625 0.164398193359375 0.00567626953125 -0.9653259277343738 +0.88175 0.169342041015625 0.005828857421875 -0.9653259277343738 +0.881875 0.169342041015625 0.005828857421875 -0.9653259277343738 +0.882 0.17425537109375 0.006011962890625 -0.9653259277343738 +0.882125 0.17425537109375 0.006011962890625 -0.9653259277343738 +0.88225 0.17913818359375 0.00616455078125 -0.9653259277343738 +0.882375 0.18402099609375 0.00634765625 -0.9653259277343738 +0.8825000000000001 0.18402099609375 0.00634765625 -0.9653259277343738 +0.882625 0.188873291015625 0.00653076171875 -0.9653259277343738 +0.88275 0.188873291015625 0.00653076171875 -0.9653259277343738 +0.882875 0.1937255859375 0.006683349609375 -0.9653259277343738 +0.883 0.19854736328125 0.0068359375 -0.9653259277343738 +0.883125 0.19854736328125 0.0068359375 -0.9653259277343738 +0.88325 0.203338623046875 0.00701904296875 -0.9653259277343738 +0.883375 0.203338623046875 0.00701904296875 -0.9653259277343738 +0.8835000000000001 0.208099365234375 0.007171630859375 -0.9653259277343738 +0.883625 0.212860107421875 0.007354736328125 -0.9653259277343738 +0.88375 0.212860107421875 0.007354736328125 -0.9653259277343738 +0.883875 0.21759033203125 0.00750732421875 -0.9653259277343738 +0.884 0.21759033203125 0.00750732421875 -0.9653259277343738 +0.884125 0.2222900390625 0.007659912109375 -0.9653259277343738 +0.88425 0.226959228515625 0.007843017578125 -0.9653259277343738 +0.884375 0.226959228515625 0.007843017578125 -0.9653259277343738 +0.8845000000000001 0.231597900390625 0.00799560546875 -0.9653259277343738 +0.884625 0.231597900390625 0.00799560546875 -0.9653259277343738 +0.88475 0.236236572265625 0.008148193359375 -0.9653259277343738 +0.884875 0.2408447265625 0.00830078125 -0.9653259277343738 +0.885 0.2408447265625 0.00830078125 -0.9653259277343738 +0.8851250000000001 0.24542236328125 0.00848388671875 -0.9653259277343738 +0.88525 0.24542236328125 0.00848388671875 -0.9653259277343738 +0.885375 0.249969482421875 0.008636474609375 -0.9653259277343738 +0.8855000000000001 0.25445556640625 0.0087890625 -0.9653259277343738 +0.885625 0.25445556640625 0.0087890625 -0.9653259277343738 +0.88575 0.25897216796875 0.008941650390625 -0.9653259277343738 +0.885875 0.25897216796875 0.008941650390625 -0.9653259277343738 +0.886 0.263427734375 0.00909423828125 -0.9653259277343738 +0.8861250000000001 0.267852783203125 0.009246826171875 -0.9653259277343738 +0.88625 0.267852783203125 0.009246826171875 -0.9653259277343738 +0.886375 0.27227783203125 0.0093994140625 -0.9653259277343738 +0.8865000000000001 0.27227783203125 0.0093994140625 -0.9653259277343738 +0.886625 0.276641845703125 0.009552001953125 -0.9653259277343738 +0.88675 0.280975341796875 0.00970458984375 -0.9653259277343738 +0.886875 0.280975341796875 0.00970458984375 -0.9653259277343738 +0.887 0.285308837890625 0.009857177734375 -0.9653259277343738 +0.8871250000000001 0.285308837890625 0.009857177734375 -0.9653259277343738 +0.88725 0.289581298828125 0.010009765625 -0.9653259277343738 +0.887375 0.2938232421875 0.0101318359375 -0.9653259277343738 +0.8875000000000001 0.2938232421875 0.0101318359375 -0.9653259277343738 +0.887625 0.298065185546875 0.010284423828125 -0.9653259277343738 +0.88775 0.298065185546875 0.010284423828125 -0.9653259277343738 +0.887875 0.30224609375 0.01043701171875 -0.9653259277343738 +0.888 0.306396484375 0.010589599609375 -0.9653259277343738 +0.8881250000000001 0.306396484375 0.010589599609375 -0.9653259277343738 +0.88825 0.310516357421875 0.010711669921875 -0.9653259277343738 +0.888375 0.310516357421875 0.010711669921875 -0.9653259277343738 +0.8885000000000001 0.314605712890625 0.0108642578125 -0.9653259277343738 +0.888625 0.31866455078125 0.011016845703125 -0.9653259277343738 +0.88875 0.31866455078125 0.011016845703125 -0.9653259277343738 +0.888875 0.322662353515625 0.011138916015625 -0.9653259277343738 +0.889 0.322662353515625 0.011138916015625 -0.9653259277343738 +0.8891250000000001 0.32666015625 0.01129150390625 -0.9653259277343738 +0.88925 0.330596923828125 0.01141357421875 -0.9653259277343738 +0.889375 0.330596923828125 0.01141357421875 -0.9653259277343738 +0.8895000000000001 0.334503173828125 0.011566162109375 -0.9653259277343738 +0.889625 0.334503173828125 0.011566162109375 -0.9653259277343738 +0.88975 0.33837890625 0.011688232421875 -0.9653259277343738 +0.889875 0.34222412109375 0.011810302734375 -0.9653259277343738 +0.89 0.34222412109375 0.011810302734375 -0.9653259277343738 +0.8901250000000001 0.34600830078125 0.011962890625 -0.9653259277343738 +0.89025 0.34600830078125 0.011962890625 -0.9653259277343738 +0.890375 0.349761962890625 0.0120849609375 -0.9653259277343738 +0.8905000000000001 0.353485107421875 0.01220703125 -0.9653259277343738 +0.890625 0.353485107421875 0.01220703125 -0.9653259277343738 +0.89075 0.357177734375 0.0123291015625 -0.9653259277343738 +0.890875 0.357177734375 0.0123291015625 -0.9653259277343738 +0.891 0.360809326171875 0.012451171875 -0.9653259277343738 +0.8911250000000001 0.36444091796875 0.0125732421875 -0.9653259277343738 +0.89125 0.36444091796875 0.0125732421875 -0.9653259277343738 +0.891375 0.36798095703125 0.0126953125 -0.9653259277343738 +0.8915000000000001 0.36798095703125 0.0126953125 -0.9653259277343738 +0.891625 0.37152099609375 0.0128173828125 -0.9653259277343738 +0.89175 0.375 0.012939453125 -0.9653259277343738 +0.891875 0.375 0.012939453125 -0.9653259277343738 +0.892 0.378448486328125 0.0130615234375 -0.9653259277343738 +0.8921250000000001 0.378448486328125 0.0130615234375 -0.9653259277343738 +0.89225 0.3818359375 0.01318359375 -0.9653259277343738 +0.892375 0.38519287109375 0.0133056640625 -0.9653259277343738 +0.8925000000000001 0.38519287109375 0.0133056640625 -0.9653259277343738 +0.892625 0.388519287109375 0.013427734375 -0.9653259277343738 +0.89275 0.388519287109375 0.013427734375 -0.9653259277343738 +0.892875 0.39178466796875 0.013519287109375 -0.9653259277343738 +0.893 0.39501953125 0.013641357421875 -0.9653259277343738 +0.8931250000000001 0.39501953125 0.013641357421875 -0.9653259277343738 +0.89325 0.398193359375 0.013763427734375 -0.9653259277343738 +0.893375 0.398193359375 0.013763427734375 -0.9653259277343738 +0.8935000000000001 0.401336669921875 0.01385498046875 -0.9653259277343738 +0.893625 0.404449462890625 0.01397705078125 -0.9653259277343738 +0.89375 0.404449462890625 0.01397705078125 -0.9653259277343738 +0.893875 0.407501220703125 0.014068603515625 -0.9653259277343738 +0.894 0.407501220703125 0.014068603515625 -0.9653259277343738 +0.8941250000000001 0.4105224609375 0.014190673828125 -0.9653259277343738 +0.89425 0.413482666015625 0.0142822265625 -0.9653259277343738 +0.894375 0.413482666015625 0.0142822265625 -0.9653259277343738 +0.8945000000000001 0.416412353515625 0.014373779296875 -0.9653259277343738 +0.894625 0.416412353515625 0.014373779296875 -0.9653259277343738 +0.89475 0.419281005859375 0.014495849609375 -0.9653259277343738 +0.894875 0.422119140625 0.01458740234375 -0.9653259277343738 +0.895 0.422119140625 0.01458740234375 -0.9653259277343738 +0.8951250000000001 0.424896240234375 0.014678955078125 -0.9653259277343738 +0.89525 0.424896240234375 0.014678955078125 -0.9653259277343738 +0.895375 0.4276123046875 0.0147705078125 -0.9653259277343738 +0.8955000000000001 0.4302978515625 0.014862060546875 -0.9653259277343738 +0.895625 0.4302978515625 0.014862060546875 -0.9653259277343738 +0.89575 0.432952880859375 0.01495361328125 -0.9653259277343738 +0.895875 0.432952880859375 0.01495361328125 -0.9653259277343738 +0.896 0.435546875 0.093048095703125 -0.7862487792968719 +0.8961250000000001 0.438079833984375 0.093597412109375 -0.7862487792968719 +0.89625 0.438079833984375 0.093597412109375 -0.7862487792968719 +0.896375 0.440582275390625 0.0941162109375 -0.7862487792968719 +0.8965 0.440582275390625 0.0941162109375 -0.7862487792968719 +0.896625 0.44305419921875 0.09466552734375 -0.7862487792968719 +0.89675 0.4454345703125 0.09515380859375 -0.7862487792968719 +0.896875 0.4454345703125 0.09515380859375 -0.7862487792968719 +0.897 0.447784423828125 0.095672607421875 -0.7862487792968719 +0.8971250000000001 0.447784423828125 0.095672607421875 -0.7862487792968719 +0.89725 0.450103759765625 0.096160888671875 -0.7862487792968719 +0.897375 0.452362060546875 0.096649169921875 -0.7862487792968719 +0.8975 0.452362060546875 0.096649169921875 -0.7862487792968719 +0.897625 0.454559326171875 0.09710693359375 -0.7862487792968719 +0.89775 0.454559326171875 0.09710693359375 -0.7862487792968719 +0.897875 0.45672607421875 0.097564697265625 -0.7862487792968719 +0.898 0.458831787109375 0.0980224609375 -0.7862487792968719 +0.8981250000000001 0.458831787109375 0.0980224609375 -0.7862487792968719 +0.89825 0.46087646484375 0.09844970703125 -0.7862487792968719 +0.898375 0.46087646484375 0.09844970703125 -0.7862487792968719 +0.8985 0.462890625 0.098876953125 -0.7862487792968719 +0.898625 0.464813232421875 0.09930419921875 -0.7862487792968719 +0.89875 0.464813232421875 0.09930419921875 -0.7862487792968719 +0.898875 0.46673583984375 0.099700927734375 -0.7862487792968719 +0.899 0.46673583984375 0.099700927734375 -0.7862487792968719 +0.8991250000000001 0.46856689453125 0.10009765625 -0.7862487792968719 +0.89925 0.470367431640625 0.100494384765625 -0.7862487792968719 +0.899375 0.470367431640625 0.100494384765625 -0.7862487792968719 +0.8995 0.472137451171875 0.100860595703125 -0.7862487792968719 +0.899625 0.472137451171875 0.100860595703125 -0.7862487792968719 +0.89975 0.47381591796875 0.101226806640625 -0.7862487792968719 +0.899875 0.4754638671875 0.101593017578125 -0.7862487792968719 +0.9 0.4754638671875 0.101593017578125 -0.7862487792968719 +0.9001250000000001 0.47705078125 0.1019287109375 -0.7862487792968719 +0.90025 0.47705078125 0.1019287109375 -0.7862487792968719 +0.900375 0.478607177734375 0.10223388671875 -0.7862487792968719 +0.9005 0.480072021484375 0.102569580078125 -0.7862487792968719 +0.900625 0.480072021484375 0.102569580078125 -0.7862487792968719 +0.90075 0.48150634765625 0.102874755859375 -0.7862487792968719 +0.900875 0.48150634765625 0.102874755859375 -0.7862487792968719 +0.901 0.48291015625 0.103179931640625 -0.7862487792968719 +0.9011250000000000768 0.484222412109375 0.10345458984375 -0.7862487792968719 +0.90125 0.484222412109375 0.10345458984375 -0.7862487792968719 +0.901375 0.485504150390625 0.103729248046875 -0.7862487792968719 +0.9015 0.485504150390625 0.103729248046875 -0.7862487792968719 +0.901625 0.486724853515625 0.103973388671875 -0.7862487792968719 +0.90175 0.487884521484375 0.104248046875 -0.7862487792968719 +0.901875 0.487884521484375 0.104248046875 -0.7862487792968719 +0.902 0.489013671875 0.104461669921875 -0.7862487792968719 +0.9021250000000000768 0.489013671875 0.104461669921875 -0.7862487792968719 +0.90225 0.490081787109375 0.104705810546875 -0.7862487792968719 +0.902375 0.4910888671875 0.10491943359375 -0.7862487792968719 +0.9025 0.4910888671875 0.10491943359375 -0.7862487792968719 +0.902625 0.492034912109375 0.105133056640625 -0.7862487792968719 +0.90275 0.492034912109375 0.105133056640625 -0.7862487792968719 +0.902875 0.492950439453125 0.105316162109375 -0.7862487792968719 +0.903 0.4937744140625 0.105499267578125 -0.7862487792968719 +0.9031250000000000768 0.4937744140625 0.105499267578125 -0.7862487792968719 +0.90325 0.49456787109375 0.10565185546875 -0.7862487792968719 +0.903375 0.49456787109375 0.10565185546875 -0.7862487792968719 +0.9035 0.49530029296875 0.105804443359375 -0.7862487792968719 +0.903625 0.496002197265625 0.10595703125 -0.7862487792968719 +0.90375 0.496002197265625 0.10595703125 -0.7862487792968719 +0.903875 0.496612548828125 0.106109619140625 -0.7862487792968719 +0.904 0.496612548828125 0.106109619140625 -0.7862487792968719 +0.9041250000000000768 0.4971923828125 0.106231689453125 -0.7862487792968719 +0.90425 0.497711181640625 0.1063232421875 -0.7862487792968719 +0.904375 0.497711181640625 0.1063232421875 -0.7862487792968719 +0.9045 0.498199462890625 0.1064453125 -0.7862487792968719 +0.904625 0.498199462890625 0.1064453125 -0.7862487792968719 +0.90475 0.49859619140625 0.10650634765625 -0.7862487792968719 +0.904875 0.49896240234375 0.106597900390625 -0.7862487792968719 +0.905 0.49896240234375 0.106597900390625 -0.7862487792968719 +0.9051250000000000768 0.499267578125 0.106658935546875 -0.7862487792968719 +0.90525 0.499267578125 0.106658935546875 -0.7862487792968719 +0.905375 0.49951171875 0.106719970703125 -0.7862487792968719 +0.9055 0.49969482421875 0.10675048828125 -0.7862487792968719 +0.905625 0.49969482421875 0.10675048828125 -0.7862487792968719 +0.90575 0.49981689453125 0.106781005859375 -0.7862487792968719 +0.905875 0.49981689453125 0.106781005859375 -0.7862487792968719 +0.906 0.499908447265625 0.1068115234375 -0.7862487792968719 +0.9061250000000000768 0.49993896484375 0.1068115234375 -0.7862487792968719 +0.90625 0.49993896484375 0.1068115234375 -0.7862487792968719 +0.906375 0.499908447265625 0.1068115234375 -0.7862487792968719 +0.9065 0.499908447265625 0.1068115234375 -0.7862487792968719 +0.906625 0.49981689453125 0.106781005859375 -0.7862487792968719 +0.9067500000000000768 0.49969482421875 0.10675048828125 -0.7862487792968719 +0.906875 0.49969482421875 0.10675048828125 -0.7862487792968719 +0.907 0.49951171875 0.106719970703125 -0.7862487792968719 +0.9071250000000000768 0.49951171875 0.106719970703125 -0.7862487792968719 +0.90725 0.499267578125 0.106658935546875 -0.7862487792968719 +0.907375 0.49896240234375 0.106597900390625 -0.7862487792968719 +0.9075 0.49896240234375 0.106597900390625 -0.7862487792968719 +0.907625 0.49859619140625 0.10650634765625 -0.7862487792968719 +0.9077500000000000768 0.49859619140625 0.10650634765625 -0.7862487792968719 +0.907875 0.498199462890625 0.1064453125 -0.7862487792968719 +0.908 0.497711181640625 0.1063232421875 -0.7862487792968719 +0.9081250000000000768 0.497711181640625 0.1063232421875 -0.7862487792968719 +0.90825 0.4971923828125 0.106231689453125 -0.7862487792968719 +0.908375 0.4971923828125 0.106231689453125 -0.7862487792968719 +0.9085 0.496612548828125 0.106109619140625 -0.7862487792968719 +0.908625 0.496002197265625 0.10595703125 -0.7862487792968719 +0.9087500000000000768 0.496002197265625 0.10595703125 -0.7862487792968719 +0.908875 0.49530029296875 0.105804443359375 -0.7862487792968719 +0.909 0.49530029296875 0.105804443359375 -0.7862487792968719 +0.9091250000000000768 0.49456787109375 0.10565185546875 -0.7862487792968719 +0.90925 0.4937744140625 0.105499267578125 -0.7862487792968719 +0.909375 0.4937744140625 0.105499267578125 -0.7862487792968719 +0.9095 0.492950439453125 0.105316162109375 -0.7862487792968719 +0.909625 0.492950439453125 0.105316162109375 -0.7862487792968719 +0.9097500000000000768 0.492034912109375 0.105133056640625 -0.7862487792968719 +0.909875 0.4910888671875 0.10491943359375 -0.7862487792968719 +0.91 0.4910888671875 0.10491943359375 -0.7862487792968719 +0.910125000000000096 0.490081787109375 0.104705810546875 -0.7862487792968719 +0.91025 0.490081787109375 0.104705810546875 -0.7862487792968719 +0.910375 0.489013671875 0.104461669921875 -0.7862487792968719 +0.9105 0.487884521484375 0.104248046875 -0.7862487792968719 +0.910625 0.487884521484375 0.104248046875 -0.7862487792968719 +0.9107500000000000768 0.486724853515625 0.103973388671875 -0.7862487792968719 +0.910875 0.486724853515625 0.103973388671875 -0.7862487792968719 +0.911 0.485504150390625 0.103729248046875 -0.7862487792968719 +0.911125000000000096 0.484222412109375 0.10345458984375 -0.7862487792968719 +0.91125 0.484222412109375 0.10345458984375 -0.7862487792968719 +0.911375 0.48291015625 0.103179931640625 -0.7862487792968719 +0.9115 0.48291015625 0.103179931640625 -0.7862487792968719 +0.911625 0.48150634765625 0.102874755859375 -0.7862487792968719 +0.9117500000000000768 0.480072021484375 0.102569580078125 -0.7862487792968719 +0.911875 0.480072021484375 0.102569580078125 -0.7862487792968719 +0.912 0.478607177734375 0.10223388671875 -0.7862487792968719 +0.912125 0.478607177734375 0.10223388671875 -0.7862487792968719 +0.91225 0.47705078125 0.1019287109375 -0.7862487792968719 +0.912375 0.4754638671875 0.101593017578125 -0.7862487792968719 +0.9125 0.4754638671875 0.101593017578125 -0.7862487792968719 +0.912625 0.47381591796875 0.101226806640625 -0.7862487792968719 +0.9127500000000000768 0.47381591796875 0.101226806640625 -0.7862487792968719 +0.912875 0.472137451171875 0.100860595703125 -0.7862487792968719 +0.913 0.470367431640625 0.100494384765625 -0.7862487792968719 +0.913125 0.470367431640625 0.100494384765625 -0.7862487792968719 +0.91325 0.46856689453125 0.10009765625 -0.7862487792968719 +0.913375 0.46856689453125 0.10009765625 -0.7862487792968719 +0.9135 0.46673583984375 0.099700927734375 -0.7862487792968719 +0.913625 0.464813232421875 0.09930419921875 -0.7862487792968719 +0.9137500000000000768 0.464813232421875 0.09930419921875 -0.7862487792968719 +0.913875 0.462890625 0.098876953125 -0.7862487792968719 +0.914 0.462890625 0.098876953125 -0.7862487792968719 +0.914125 0.46087646484375 0.09844970703125 -0.7862487792968719 +0.91425 0.458831787109375 0.0980224609375 -0.7862487792968719 +0.914375 0.458831787109375 0.0980224609375 -0.7862487792968719 +0.9145 0.45672607421875 0.097564697265625 -0.7862487792968719 +0.914625 0.45672607421875 0.097564697265625 -0.7862487792968719 +0.9147500000000000768 0.454559326171875 0.09710693359375 -0.7862487792968719 +0.914875 0.452362060546875 0.096649169921875 -0.7862487792968719 +0.915 0.452362060546875 0.096649169921875 -0.7862487792968719 +0.915125 0.450103759765625 0.096160888671875 -0.7862487792968719 +0.91525 0.450103759765625 0.096160888671875 -0.7862487792968719 +0.915375 0.447784423828125 0.095672607421875 -0.7862487792968719 +0.9155 0.4454345703125 0.09515380859375 -0.7862487792968719 +0.915625 0.4454345703125 0.09515380859375 -0.7862487792968719 +0.9157500000000000768 0.44305419921875 0.09466552734375 -0.7862487792968719 +0.915875 0.44305419921875 0.09466552734375 -0.7862487792968719 +0.916 0.440582275390625 0.0941162109375 -0.7862487792968719 +0.916125 0.438079833984375 0.093597412109375 -0.7862487792968719 +0.91625 0.438079833984375 0.093597412109375 -0.7862487792968719 +0.916375 0.435546875 0.093048095703125 -0.7862487792968719 +0.9165 0.435546875 0.093048095703125 -0.7862487792968719 +0.916625 0.432952880859375 0.092498779296875 -0.7862487792968719 +0.9167500000000000768 0.4302978515625 0.0919189453125 -0.7862487792968719 +0.916875 0.4302978515625 0.0919189453125 -0.7862487792968719 +0.917 0.4276123046875 0.09136962890625 -0.7862487792968719 +0.917125 0.4276123046875 0.09136962890625 -0.7862487792968719 +0.91725 0.424896240234375 0.09075927734375 -0.7862487792968719 +0.917375 0.422119140625 0.090179443359375 -0.7862487792968719 +0.9175 0.422119140625 0.090179443359375 -0.7862487792968719 +0.917625 0.419281005859375 0.089569091796875 -0.7862487792968719 +0.9177500000000000768 0.419281005859375 0.089569091796875 -0.7862487792968719 +0.917875 0.416412353515625 0.088958740234375 -0.7862487792968719 +0.918 0.413482666015625 0.088348388671875 -0.7862487792968719 +0.918125 0.413482666015625 0.088348388671875 -0.7862487792968719 +0.91825 0.4105224609375 0.08770751953125 -0.7862487792968719 +0.918375 0.4105224609375 0.08770751953125 -0.7862487792968719 +0.9185 0.407501220703125 0.087066650390625 -0.7862487792968719 +0.918625 0.404449462890625 0.086395263671875 -0.7862487792968719 +0.9187500000000000768 0.404449462890625 0.086395263671875 -0.7862487792968719 +0.918875 0.401336669921875 0.08575439453125 -0.7862487792968719 +0.919 0.401336669921875 0.08575439453125 -0.7862487792968719 +0.919125 0.398193359375 0.0850830078125 -0.7862487792968719 +0.91925 0.39501953125 0.084381103515625 -0.7862487792968719 +0.919375 0.39501953125 0.084381103515625 -0.7862487792968719 +0.9195 0.39178466796875 0.083709716796875 -0.7862487792968719 +0.919625 0.39178466796875 0.083709716796875 -0.7862487792968719 +0.9197500000000000768 0.388519287109375 0.0830078125 -0.7862487792968719 +0.919875 0.38519287109375 0.082305908203125 -0.7862487792968719 +0.92 0.38519287109375 0.082305908203125 -0.7862487792968719 +0.920125 0.3818359375 0.081573486328125 -0.7862487792968719 +0.92025 0.3818359375 0.081573486328125 -0.7862487792968719 +0.920375 0.378448486328125 0.080841064453125 -0.7862487792968719 +0.9205 0.375 0.080108642578125 -0.7862487792968719 +0.920625 0.375 0.080108642578125 -0.7862487792968719 +0.9207500000000000768 0.37152099609375 0.079376220703125 -0.7862487792968719 +0.920875 0.37152099609375 0.079376220703125 -0.7862487792968719 +0.921 0.36798095703125 0.07861328125 -0.7862487792968719 +0.921125 0.36444091796875 0.077850341796875 -0.7862487792968719 +0.92125 0.36444091796875 0.077850341796875 -0.7862487792968719 +0.921375 0.360809326171875 0.07708740234375 -0.7862487792968719 +0.9215 0.360809326171875 0.07708740234375 -0.7862487792968719 +0.921625 0.357177734375 0.0762939453125 -0.7862487792968719 +0.9217500000000000768 0.353485107421875 0.075531005859375 -0.7862487792968719 +0.921875 0.353485107421875 0.075531005859375 -0.7862487792968719 +0.922 0.349761962890625 0.074737548828125 -0.7862487792968719 +0.922125 0.349761962890625 0.074737548828125 -0.7862487792968719 +0.92225 0.34600830078125 0.07391357421875 -0.7862487792968719 +0.922375000000000096 0.34222412109375 0.0731201171875 -0.7862487792968719 +0.9225 0.34222412109375 0.0731201171875 -0.7862487792968719 +0.922625 0.33837890625 0.072296142578125 -0.7862487792968719 +0.922750000000000096 0.33837890625 0.072296142578125 -0.7862487792968719 +0.922875 0.334503173828125 0.07147216796875 -0.7862487792968719 +0.923 0.330596923828125 0.07061767578125 -0.7862487792968719 +0.923125 0.330596923828125 0.07061767578125 -0.7862487792968719 +0.92325 0.32666015625 0.069793701171875 -0.7862487792968719 +0.923375000000000096 0.32666015625 0.069793701171875 -0.7862487792968719 +0.9235 0.322662353515625 0.068939208984375 -0.7862487792968719 +0.923625 0.31866455078125 0.068084716796875 -0.7862487792968719 +0.923750000000000096 0.31866455078125 0.068084716796875 -0.7862487792968719 +0.923875 0.314605712890625 0.06719970703125 -0.7862487792968719 +0.924 0.314605712890625 0.06719970703125 -0.7862487792968719 +0.924125 0.310516357421875 0.06634521484375 -0.7862487792968719 +0.92425 0.306396484375 0.065460205078125 -0.7862487792968719 +0.924375000000000096 0.306396484375 0.065460205078125 -0.7862487792968719 +0.9245 0.30224609375 0.0645751953125 -0.7862487792968719 +0.924625 0.30224609375 0.0645751953125 -0.7862487792968719 +0.924750000000000096 0.298065185546875 0.06365966796875 -0.7862487792968719 +0.924875 0.2938232421875 0.062774658203125 -0.7862487792968719 +0.925 0.2938232421875 0.062774658203125 -0.7862487792968719 +0.925125 0.289581298828125 0.061859130859375 -0.7862487792968719 +0.92525 0.289581298828125 0.061859130859375 -0.7862487792968719 +0.925375000000000096 0.285308837890625 0.060943603515625 -0.7862487792968719 +0.9255 0.280975341796875 0.060028076171875 -0.7862487792968719 +0.925625 0.280975341796875 0.060028076171875 -0.7862487792968719 +0.925750000000000096 0.276641845703125 0.05908203125 -0.7862487792968719 +0.925875 0.276641845703125 0.05908203125 -0.7862487792968719 +0.926 0.27227783203125 0.05816650390625 -0.7862487792968719 +0.926125 0.267852783203125 0.057220458984375 -0.7862487792968719 +0.92625 0.267852783203125 0.057220458984375 -0.7862487792968719 +0.926375000000000096 0.263427734375 0.0562744140625 -0.7862487792968719 +0.9265 0.263427734375 0.0562744140625 -0.7862487792968719 +0.926625 0.25897216796875 0.055328369140625 -0.7862487792968719 +0.926750000000000096 0.25445556640625 0.054351806640625 -0.7862487792968719 +0.926875 0.25445556640625 0.054351806640625 -0.7862487792968719 +0.927 0.249969482421875 0.05340576171875 -0.7862487792968719 +0.927125 0.249969482421875 0.05340576171875 -0.7862487792968719 +0.92725 0.24542236328125 0.05242919921875 -0.7862487792968719 +0.927375000000000096 0.2408447265625 0.05145263671875 -0.7862487792968719 +0.9275 0.2408447265625 0.05145263671875 -0.7862487792968719 +0.927625 0.236236572265625 0.05047607421875 -0.7862487792968719 +0.927750000000000096 0.236236572265625 0.05047607421875 -0.7862487792968719 +0.927875 0.231597900390625 0.049468994140625 -0.7862487792968719 +0.928 0.226959228515625 0.11761474609375 -0.481719970703120832 +0.928125 0.226959228515625 0.11761474609375 -0.481719970703120832 +0.92825 0.2222900390625 0.11517333984375 -0.481719970703120832 +0.928375000000000096 0.2222900390625 0.11517333984375 -0.481719970703120832 +0.9285 0.21759033203125 0.11273193359375 -0.481719970703120832 +0.928625 0.212860107421875 0.11029052734375 -0.481719970703120832 +0.92875 0.212860107421875 0.11029052734375 -0.481719970703120832 +0.928875 0.208099365234375 0.10784912109375 -0.481719970703120832 +0.929 0.208099365234375 0.10784912109375 -0.481719970703120832 +0.929125 0.203338623046875 0.1053466796875 -0.481719970703120832 +0.92925 0.19854736328125 0.102874755859375 -0.481719970703120832 +0.929375000000000096 0.19854736328125 0.102874755859375 -0.481719970703120832 +0.9295 0.1937255859375 0.100372314453125 -0.481719970703120832 +0.929625 0.1937255859375 0.100372314453125 -0.481719970703120832 +0.92975 0.188873291015625 0.097869873046875 -0.481719970703120832 +0.929875 0.18402099609375 0.095367431640625 -0.481719970703120832 +0.93 0.18402099609375 0.095367431640625 -0.481719970703120832 +0.930125 0.17913818359375 0.09283447265625 -0.481719970703120832 +0.93025 0.17913818359375 0.09283447265625 -0.481719970703120832 +0.930375000000000096 0.17425537109375 0.090301513671875 -0.481719970703120832 +0.9305 0.169342041015625 0.087738037109375 -0.481719970703120832 +0.930625 0.169342041015625 0.087738037109375 -0.481719970703120832 +0.93075 0.164398193359375 0.085174560546875 -0.481719970703120832 +0.930875 0.164398193359375 0.085174560546875 -0.481719970703120832 +0.931 0.159454345703125 0.082611083984375 -0.481719970703120832 +0.931125 0.15447998046875 0.080047607421875 -0.481719970703120832 +0.93125 0.15447998046875 0.080047607421875 -0.481719970703120832 +0.931375000000000096 0.14947509765625 0.07745361328125 -0.481719970703120832 +0.9315 0.14947509765625 0.07745361328125 -0.481719970703120832 +0.931625 0.14447021484375 0.074859619140625 -0.481719970703120832 +0.93175 0.13946533203125 0.072265625 -0.481719970703120832 +0.931875 0.13946533203125 0.072265625 -0.481719970703120832 +0.932 0.134429931640625 0.06964111328125 -0.481719970703120832 +0.932125 0.134429931640625 0.06964111328125 -0.481719970703120832 +0.93225 0.129364013671875 0.067047119140625 -0.481719970703120832 +0.932375000000000096 0.124298095703125 0.064422607421875 -0.481719970703120832 +0.9325 0.124298095703125 0.064422607421875 -0.481719970703120832 +0.932625 0.119232177734375 0.061798095703125 -0.481719970703120832 +0.93275 0.119232177734375 0.061798095703125 -0.481719970703120832 +0.932875 0.1141357421875 0.05914306640625 -0.481719970703120832 +0.933 0.109039306640625 0.056488037109375 -0.481719970703120832 +0.933125 0.109039306640625 0.056488037109375 -0.481719970703120832 +0.93325 0.103912353515625 0.0538330078125 -0.481719970703120832 +0.933375000000000096 0.103912353515625 0.0538330078125 -0.481719970703120832 +0.9335 0.098785400390625 0.051177978515625 -0.481719970703120832 +0.933625 0.093658447265625 0.04852294921875 -0.481719970703120832 +0.93375 0.093658447265625 0.04852294921875 -0.481719970703120832 +0.933875 0.0885009765625 0.045867919921875 -0.481719970703120832 +0.934 0.0885009765625 0.045867919921875 -0.481719970703120832 +0.934125 0.083343505859375 0.043182373046875 -0.481719970703120832 +0.93425 0.07818603515625 0.040496826171875 -0.481719970703120832 +0.934375000000000096 0.07818603515625 0.040496826171875 -0.481719970703120832 +0.9345 0.072998046875 0.037841796875 -0.481719970703120832 +0.934625 0.072998046875 0.037841796875 -0.481719970703120832 +0.93475 0.06781005859375 0.035125732421875 -0.481719970703120832 +0.934875 0.0626220703125 0.032440185546875 -0.481719970703120832 +0.935 0.0626220703125 0.032440185546875 -0.481719970703120832 +0.935125 0.05743408203125 0.029754638671875 -0.481719970703120832 +0.93525 0.05743408203125 0.029754638671875 -0.481719970703120832 +0.935375000000000096 0.05224609375 0.027069091796875 -0.481719970703120832 +0.9355 0.047027587890625 0.02435302734375 -0.481719970703120832 +0.935625 0.047027587890625 0.02435302734375 -0.481719970703120832 +0.93575 0.04180908203125 0.02166748046875 -0.481719970703120832 +0.935875 0.04180908203125 0.02166748046875 -0.481719970703120832 +0.936 0.036590576171875 0.018951416015625 -0.481719970703120832 +0.936125 0.0313720703125 0.0162353515625 -0.481719970703120832 +0.93625 0.0313720703125 0.0162353515625 -0.481719970703120832 +0.936375000000000096 0.026123046875 0.0135498046875 -0.481719970703120832 +0.9365 0.026123046875 0.0135498046875 -0.481719970703120832 +0.936625 0.020904541015625 0.010833740234375 -0.481719970703120832 +0.93675 0.01568603515625 0.00811767578125 -0.481719970703120832 +0.936875 0.01568603515625 0.00811767578125 -0.481719970703120832 +0.937 0.01043701171875 0.005401611328125 -0.481719970703120832 +0.937125 0.01043701171875 0.005401611328125 -0.481719970703120832 +0.93725 0.005218505859375 0.002685546875 -0.481719970703120832 +0.937375000000000096 0.0 0.0 -0.481719970703120832 +0.9375 0.0 0.0 -0.481719970703120832 +0.937625 -0.005218505859375 -0.002685546875 -0.481719970703120832 +0.93775 -0.005218505859375 -0.002685546875 -0.481719970703120832 +0.937875 -0.01043701171875 -0.005401611328125 -0.481719970703120832 +0.938000000000000096 -0.01568603515625 -0.00811767578125 -0.481719970703120832 +0.938125 -0.01568603515625 -0.00811767578125 -0.481719970703120832 +0.93825 -0.020904541015625 -0.010833740234375 -0.481719970703120832 +0.938375000000000096 -0.020904541015625 -0.010833740234375 -0.481719970703120832 +0.9385 -0.026123046875 -0.0135498046875 -0.481719970703120832 +0.938625 -0.0313720703125 -0.0162353515625 -0.481719970703120832 +0.93875 -0.0313720703125 -0.0162353515625 -0.481719970703120832 +0.938875 -0.036590576171875 -0.018951416015625 -0.481719970703120832 +0.939000000000000096 -0.036590576171875 -0.018951416015625 -0.481719970703120832 +0.939125 -0.04180908203125 -0.02166748046875 -0.481719970703120832 +0.93925 -0.047027587890625 -0.02435302734375 -0.481719970703120832 +0.939375000000000096 -0.047027587890625 -0.02435302734375 -0.481719970703120832 +0.9395 -0.05224609375 -0.027069091796875 -0.481719970703120832 +0.939625 -0.05224609375 -0.027069091796875 -0.481719970703120832 +0.93975 -0.05743408203125 -0.029754638671875 -0.481719970703120832 +0.939875 -0.0626220703125 -0.032440185546875 -0.481719970703120832 +0.940000000000000096 -0.0626220703125 -0.032440185546875 -0.481719970703120832 +0.940125 -0.06781005859375 -0.035125732421875 -0.481719970703120832 +0.94025 -0.06781005859375 -0.035125732421875 -0.481719970703120832 +0.940375000000000096 -0.072998046875 -0.037841796875 -0.481719970703120832 +0.9405 -0.07818603515625 -0.040496826171875 -0.481719970703120832 +0.940625 -0.07818603515625 -0.040496826171875 -0.481719970703120832 +0.94075 -0.083343505859375 -0.043182373046875 -0.481719970703120832 +0.940875 -0.083343505859375 -0.043182373046875 -0.481719970703120832 +0.941000000000000096 -0.0885009765625 -0.045867919921875 -0.481719970703120832 +0.941125 -0.093658447265625 -0.04852294921875 -0.481719970703120832 +0.94125 -0.093658447265625 -0.04852294921875 -0.481719970703120832 +0.941375000000000096 -0.098785400390625 -0.051177978515625 -0.481719970703120832 +0.9415 -0.098785400390625 -0.051177978515625 -0.481719970703120832 +0.941625 -0.103912353515625 -0.0538330078125 -0.481719970703120832 +0.94175 -0.109039306640625 -0.056488037109375 -0.481719970703120832 +0.941875 -0.109039306640625 -0.056488037109375 -0.481719970703120832 +0.942000000000000096 -0.1141357421875 -0.05914306640625 -0.481719970703120832 +0.942125 -0.1141357421875 -0.05914306640625 -0.481719970703120832 +0.94225 -0.119232177734375 -0.061798095703125 -0.481719970703120832 +0.942375000000000096 -0.124298095703125 -0.064422607421875 -0.481719970703120832 +0.9425 -0.124298095703125 -0.064422607421875 -0.481719970703120832 +0.942625 -0.129364013671875 -0.067047119140625 -0.481719970703120832 +0.94275 -0.129364013671875 -0.067047119140625 -0.481719970703120832 +0.942875 -0.134429931640625 -0.06964111328125 -0.481719970703120832 +0.943000000000000096 -0.13946533203125 -0.072265625 -0.481719970703120832 +0.943125 -0.13946533203125 -0.072265625 -0.481719970703120832 +0.94325 -0.14447021484375 -0.074859619140625 -0.481719970703120832 +0.943375000000000096 -0.14447021484375 -0.074859619140625 -0.481719970703120832 +0.9435 -0.14947509765625 -0.07745361328125 -0.481719970703120832 +0.943625 -0.15447998046875 -0.080047607421875 -0.481719970703120832 +0.94375 -0.15447998046875 -0.080047607421875 -0.481719970703120832 +0.943875 -0.159454345703125 -0.082611083984375 -0.481719970703120832 +0.944000000000000096 -0.159454345703125 -0.082611083984375 -0.481719970703120832 +0.944125 -0.164398193359375 -0.085174560546875 -0.481719970703120832 +0.94425 -0.169342041015625 -0.087738037109375 -0.481719970703120832 +0.944375 -0.169342041015625 -0.087738037109375 -0.481719970703120832 +0.9445 -0.17425537109375 -0.090301513671875 -0.481719970703120832 +0.944625 -0.17425537109375 -0.090301513671875 -0.481719970703120832 +0.94475 -0.17913818359375 -0.09283447265625 -0.481719970703120832 +0.944875 -0.18402099609375 -0.095367431640625 -0.481719970703120832 +0.945000000000000096 -0.18402099609375 -0.095367431640625 -0.481719970703120832 +0.945125 -0.188873291015625 -0.097869873046875 -0.481719970703120832 +0.94525 -0.188873291015625 -0.097869873046875 -0.481719970703120832 +0.945375 -0.1937255859375 -0.100372314453125 -0.481719970703120832 +0.9455 -0.19854736328125 -0.102874755859375 -0.481719970703120832 +0.945625 -0.19854736328125 -0.102874755859375 -0.481719970703120832 +0.94575 -0.203338623046875 -0.1053466796875 -0.481719970703120832 +0.945875 -0.203338623046875 -0.1053466796875 -0.481719970703120832 +0.946000000000000096 -0.208099365234375 -0.10784912109375 -0.481719970703120832 +0.946125 -0.212860107421875 -0.11029052734375 -0.481719970703120832 +0.94625 -0.212860107421875 -0.11029052734375 -0.481719970703120832 +0.946375 -0.21759033203125 -0.11273193359375 -0.481719970703120832 +0.9465 -0.21759033203125 -0.11273193359375 -0.481719970703120832 +0.946625 -0.2222900390625 -0.11517333984375 -0.481719970703120832 +0.94675 -0.226959228515625 -0.11761474609375 -0.481719970703120832 +0.946875 -0.226959228515625 -0.11761474609375 -0.481719970703120832 +0.947000000000000096 -0.231597900390625 -0.120025634765625 -0.481719970703120832 +0.947125 -0.231597900390625 -0.120025634765625 -0.481719970703120832 +0.94725 -0.236236572265625 -0.122406005859375 -0.481719970703120832 +0.947375 -0.2408447265625 -0.124786376953125 -0.481719970703120832 +0.9475 -0.2408447265625 -0.124786376953125 -0.481719970703120832 +0.947625 -0.24542236328125 -0.127166748046875 -0.481719970703120832 +0.94775 -0.24542236328125 -0.127166748046875 -0.481719970703120832 +0.947875 -0.249969482421875 -0.1295166015625 -0.481719970703120832 +0.948000000000000096 -0.25445556640625 -0.131866455078125 -0.481719970703120832 +0.948125 -0.25445556640625 -0.131866455078125 -0.481719970703120832 +0.94825 -0.25897216796875 -0.134185791015625 -0.481719970703120832 +0.948375 -0.25897216796875 -0.134185791015625 -0.481719970703120832 +0.9485 -0.263427734375 -0.136505126953125 -0.481719970703120832 +0.948625 -0.267852783203125 -0.1387939453125 -0.481719970703120832 +0.94875 -0.267852783203125 -0.1387939453125 -0.481719970703120832 +0.948875 -0.27227783203125 -0.141082763671875 -0.481719970703120832 +0.949000000000000096 -0.27227783203125 -0.141082763671875 -0.481719970703120832 +0.949125 -0.276641845703125 -0.143341064453125 -0.481719970703120832 +0.94925 -0.280975341796875 -0.145599365234375 -0.481719970703120832 +0.949375 -0.280975341796875 -0.145599365234375 -0.481719970703120832 +0.9495 -0.285308837890625 -0.147857666015625 -0.481719970703120832 +0.949625 -0.285308837890625 -0.147857666015625 -0.481719970703120832 +0.94975 -0.289581298828125 -0.150054931640625 -0.481719970703120832 +0.949875 -0.2938232421875 -0.152252197265625 -0.481719970703120832 +0.950000000000000096 -0.2938232421875 -0.152252197265625 -0.481719970703120832 +0.950125 -0.298065185546875 -0.154449462890625 -0.481719970703120832 +0.95025 -0.298065185546875 -0.154449462890625 -0.481719970703120832 +0.950375 -0.30224609375 -0.1566162109375 -0.481719970703120832 +0.9505 -0.306396484375 -0.158782958984375 -0.481719970703120832 +0.950625 -0.306396484375 -0.158782958984375 -0.481719970703120832 +0.95075 -0.310516357421875 -0.160919189453125 -0.481719970703120832 +0.950875 -0.310516357421875 -0.160919189453125 -0.481719970703120832 +0.951000000000000096 -0.314605712890625 -0.16302490234375 -0.481719970703120832 +0.951125 -0.31866455078125 -0.165130615234375 -0.481719970703120832 +0.95125 -0.31866455078125 -0.165130615234375 -0.481719970703120832 +0.951375 -0.322662353515625 -0.167205810546875 -0.481719970703120832 +0.9515 -0.322662353515625 -0.167205810546875 -0.481719970703120832 +0.951625 -0.32666015625 -0.169281005859375 -0.481719970703120832 +0.95175 -0.330596923828125 -0.17132568359375 -0.481719970703120832 +0.951875 -0.330596923828125 -0.17132568359375 -0.481719970703120832 +0.952000000000000096 -0.334503173828125 -0.17333984375 -0.481719970703120832 +0.952125 -0.334503173828125 -0.17333984375 -0.481719970703120832 +0.95225 -0.33837890625 -0.17535400390625 -0.481719970703120832 +0.952375 -0.34222412109375 -0.177337646484375 -0.481719970703120832 +0.9525 -0.34222412109375 -0.177337646484375 -0.481719970703120832 +0.952625 -0.34600830078125 -0.179290771484375 -0.481719970703120832 +0.95275 -0.34600830078125 -0.179290771484375 -0.481719970703120832 +0.952875 -0.349761962890625 -0.181243896484375 -0.481719970703120832 +0.953000000000000096 -0.353485107421875 -0.18316650390625 -0.481719970703120832 +0.953125 -0.353485107421875 -0.18316650390625 -0.481719970703120832 +0.95325 -0.357177734375 -0.185089111328125 -0.481719970703120832 +0.953375 -0.357177734375 -0.185089111328125 -0.481719970703120832 +0.9535 -0.360809326171875 -0.186981201171875 -0.481719970703120832 +0.953625000000000096 -0.36444091796875 -0.1888427734375 -0.481719970703120832 +0.95375 -0.36444091796875 -0.1888427734375 -0.481719970703120832 +0.953875 -0.36798095703125 -0.190704345703125 -0.481719970703120832 +0.954000000000000096 -0.36798095703125 -0.190704345703125 -0.481719970703120832 +0.954125 -0.37152099609375 -0.1925048828125 -0.481719970703120832 +0.95425 -0.375 -0.1943359375 -0.481719970703120832 +0.954375 -0.375 -0.1943359375 -0.481719970703120832 +0.9545 -0.378448486328125 -0.19610595703125 -0.481719970703120832 +0.954625000000000096 -0.378448486328125 -0.19610595703125 -0.481719970703120832 +0.95475 -0.3818359375 -0.1978759765625 -0.481719970703120832 +0.954875 -0.38519287109375 -0.199615478515625 -0.481719970703120832 +0.955000000000000096 -0.38519287109375 -0.199615478515625 -0.481719970703120832 +0.955125 -0.388519287109375 -0.201324462890625 -0.481719970703120832 +0.95525 -0.388519287109375 -0.201324462890625 -0.481719970703120832 +0.955375 -0.39178466796875 -0.203033447265625 -0.481719970703120832 +0.9555 -0.39501953125 -0.2047119140625 -0.481719970703120832 +0.955625000000000096 -0.39501953125 -0.2047119140625 -0.481719970703120832 +0.95575 -0.398193359375 -0.20635986328125 -0.481719970703120832 +0.955875 -0.398193359375 -0.20635986328125 -0.481719970703120832 +0.956000000000000096 -0.401336669921875 -0.207977294921875 -0.481719970703120832 +0.956125 -0.404449462890625 -0.2095947265625 -0.481719970703120832 +0.95625 -0.404449462890625 -0.2095947265625 -0.481719970703120832 +0.956375 -0.407501220703125 -0.211181640625 -0.481719970703120832 +0.9565 -0.407501220703125 -0.211181640625 -0.481719970703120832 +0.956625000000000096 -0.4105224609375 -0.212738037109375 -0.481719970703120832 +0.95675 -0.413482666015625 -0.214263916015625 -0.481719970703120832 +0.956875 -0.413482666015625 -0.214263916015625 -0.481719970703120832 +0.957000000000000096 -0.416412353515625 -0.215789794921875 -0.481719970703120832 +0.957125 -0.416412353515625 -0.215789794921875 -0.481719970703120832 +0.95725 -0.419281005859375 -0.217254638671875 -0.481719970703120832 +0.957375 -0.422119140625 -0.21875 -0.481719970703120832 +0.9575 -0.422119140625 -0.21875 -0.481719970703120832 +0.957625000000000096 -0.424896240234375 -0.220184326171875 -0.481719970703120832 +0.95775 -0.424896240234375 -0.220184326171875 -0.481719970703120832 +0.957875 -0.4276123046875 -0.221588134765625 -0.481719970703120832 +0.958000000000000096 -0.4302978515625 -0.222991943359375 -0.481719970703120832 +0.958125 -0.4302978515625 -0.222991943359375 -0.481719970703120832 +0.95825 -0.432952880859375 -0.224365234375 -0.481719970703120832 +0.958375 -0.432952880859375 -0.224365234375 -0.481719970703120832 +0.9585 -0.435546875 -0.2257080078125 -0.481719970703120832 +0.958625000000000096 -0.438079833984375 -0.227020263671875 -0.481719970703120832 +0.95875 -0.438079833984375 -0.227020263671875 -0.481719970703120832 +0.958875 -0.440582275390625 -0.228302001953125 -0.481719970703120832 +0.959000000000000096 -0.440582275390625 -0.228302001953125 -0.481719970703120832 +0.959125 -0.44305419921875 -0.229583740234375 -0.481719970703120832 +0.95925 -0.4454345703125 -0.2308349609375 -0.481719970703120832 +0.959375 -0.4454345703125 -0.2308349609375 -0.481719970703120832 +0.9595 -0.447784423828125 -0.2320556640625 -0.481719970703120832 +0.959625000000000096 -0.447784423828125 -0.2320556640625 -0.481719970703120832 +0.95975 -0.450103759765625 -0.233245849609375 -0.481719970703120832 +0.959875 -0.452362060546875 -0.234405517578125 -0.481719970703120832 +0.96 -0.452362060546875 -0.406951904296875 -0.1003479003906193 +0.960125 -0.454559326171875 -0.408905029296875 -0.1003479003906193 +0.96025 -0.454559326171875 -0.408905029296875 -0.1003479003906193 +0.960375 -0.45672607421875 -0.410858154296875 -0.1003479003906193 +0.9605 -0.458831787109375 -0.412750244140625 -0.1003479003906193 +0.960625000000000096 -0.458831787109375 -0.412750244140625 -0.1003479003906193 +0.96075 -0.46087646484375 -0.41461181640625 -0.1003479003906193 +0.960875 -0.46087646484375 -0.41461181640625 -0.1003479003906193 +0.961 -0.462890625 -0.416412353515625 -0.1003479003906193 +0.961125 -0.464813232421875 -0.41815185546875 -0.1003479003906193 +0.96125 -0.464813232421875 -0.41815185546875 -0.1003479003906193 +0.961375 -0.46673583984375 -0.41986083984375 -0.1003479003906193 +0.9615 -0.46673583984375 -0.41986083984375 -0.1003479003906193 +0.961625000000000096 -0.46856689453125 -0.421539306640625 -0.1003479003906193 +0.96175 -0.470367431640625 -0.42315673828125 -0.1003479003906193 +0.961875 -0.470367431640625 -0.42315673828125 -0.1003479003906193 +0.962 -0.472137451171875 -0.42474365234375 -0.1003479003906193 +0.962125 -0.472137451171875 -0.42474365234375 -0.1003479003906193 +0.96225 -0.47381591796875 -0.42626953125 -0.1003479003906193 +0.962375 -0.4754638671875 -0.427734375 -0.1003479003906193 +0.9625 -0.4754638671875 -0.427734375 -0.1003479003906193 +0.962625000000000096 -0.47705078125 -0.429168701171875 -0.1003479003906193 +0.96275 -0.47705078125 -0.429168701171875 -0.1003479003906193 +0.962875 -0.478607177734375 -0.4305419921875 -0.1003479003906193 +0.963 -0.480072021484375 -0.431884765625 -0.1003479003906193 +0.963125 -0.480072021484375 -0.431884765625 -0.1003479003906193 +0.96325 -0.48150634765625 -0.43316650390625 -0.1003479003906193 +0.963375 -0.48150634765625 -0.43316650390625 -0.1003479003906193 +0.9635 -0.48291015625 -0.434417724609375 -0.1003479003906193 +0.963625000000000096 -0.484222412109375 -0.43560791015625 -0.1003479003906193 +0.96375 -0.484222412109375 -0.43560791015625 -0.1003479003906193 +0.963875 -0.485504150390625 -0.436767578125 -0.1003479003906193 +0.964 -0.485504150390625 -0.436767578125 -0.1003479003906193 +0.964125 -0.486724853515625 -0.4378662109375 -0.1003479003906193 +0.96425 -0.487884521484375 -0.43890380859375 -0.1003479003906193 +0.964375 -0.487884521484375 -0.43890380859375 -0.1003479003906193 +0.9645 -0.489013671875 -0.439910888671875 -0.1003479003906193 +0.964625000000000096 -0.489013671875 -0.439910888671875 -0.1003479003906193 +0.96475 -0.490081787109375 -0.440887451171875 -0.1003479003906193 +0.964875 -0.4910888671875 -0.4417724609375 -0.1003479003906193 +0.965 -0.4910888671875 -0.4417724609375 -0.1003479003906193 +0.965125 -0.492034912109375 -0.442657470703125 -0.1003479003906193 +0.96525 -0.492034912109375 -0.442657470703125 -0.1003479003906193 +0.965375 -0.492950439453125 -0.443450927734375 -0.1003479003906193 +0.9655 -0.4937744140625 -0.4442138671875 -0.1003479003906193 +0.965625000000000096 -0.4937744140625 -0.4442138671875 -0.1003479003906193 +0.96575 -0.49456787109375 -0.444915771484375 -0.1003479003906193 +0.965875 -0.49456787109375 -0.444915771484375 -0.1003479003906193 +0.966 -0.49530029296875 -0.445587158203125 -0.1003479003906193 +0.966125 -0.496002197265625 -0.446197509765625 -0.1003479003906193 +0.96625 -0.496002197265625 -0.446197509765625 -0.1003479003906193 +0.966375 -0.496612548828125 -0.446746826171875 -0.1003479003906193 +0.9665 -0.496612548828125 -0.446746826171875 -0.1003479003906193 +0.966625000000000096 -0.4971923828125 -0.447296142578125 -0.1003479003906193 +0.96675 -0.497711181640625 -0.44775390625 -0.1003479003906193 +0.966875 -0.497711181640625 -0.44775390625 -0.1003479003906193 +0.967 -0.498199462890625 -0.44818115234375 -0.1003479003906193 +0.967125 -0.498199462890625 -0.44818115234375 -0.1003479003906193 +0.96725 -0.49859619140625 -0.44854736328125 -0.1003479003906193 +0.967375 -0.49896240234375 -0.4488525390625 -0.1003479003906193 +0.9675 -0.49896240234375 -0.4488525390625 -0.1003479003906193 +0.967625000000000096 -0.499267578125 -0.449127197265625 -0.1003479003906193 +0.96775 -0.499267578125 -0.449127197265625 -0.1003479003906193 +0.967875 -0.49951171875 -0.449371337890625 -0.1003479003906193 +0.968 -0.49969482421875 -0.44952392578125 -0.1003479003906193 +0.968125 -0.49969482421875 -0.44952392578125 -0.1003479003906193 +0.96825 -0.49981689453125 -0.44964599609375 -0.1003479003906193 +0.968375 -0.49981689453125 -0.44964599609375 -0.1003479003906193 +0.9685 -0.499908447265625 -0.449737548828125 -0.1003479003906193 +0.968625000000000096 -0.49993896484375 -0.44976806640625 -0.1003479003906193 +0.96875 -0.49993896484375 -0.44976806640625 -0.1003479003906193 +0.968875 -0.499908447265625 -0.449737548828125 -0.1003479003906193 +0.969 -0.499908447265625 -0.449737548828125 -0.1003479003906193 +0.969125 -0.49981689453125 -0.44964599609375 -0.1003479003906193 +0.969250000000000096 -0.49969482421875 -0.44952392578125 -0.1003479003906193 +0.969375 -0.49969482421875 -0.44952392578125 -0.1003479003906193 +0.9695 -0.49951171875 -0.449371337890625 -0.1003479003906193 +0.969625000000000096 -0.49951171875 -0.449371337890625 -0.1003479003906193 +0.96975 -0.499267578125 -0.449127197265625 -0.1003479003906193 +0.969875 -0.49896240234375 -0.4488525390625 -0.1003479003906193 +0.97 -0.49896240234375 -0.4488525390625 -0.1003479003906193 +0.970125 -0.49859619140625 -0.44854736328125 -0.1003479003906193 +0.970250000000000096 -0.49859619140625 -0.44854736328125 -0.1003479003906193 +0.970375 -0.498199462890625 -0.44818115234375 -0.1003479003906193 +0.9705 -0.497711181640625 -0.44775390625 -0.1003479003906193 +0.970625000000000096 -0.497711181640625 -0.44775390625 -0.1003479003906193 +0.97075 -0.4971923828125 -0.447296142578125 -0.1003479003906193 +0.970875 -0.4971923828125 -0.447296142578125 -0.1003479003906193 +0.971 -0.496612548828125 -0.446746826171875 -0.1003479003906193 +0.971125 -0.496002197265625 -0.446197509765625 -0.1003479003906193 +0.971250000000000096 -0.496002197265625 -0.446197509765625 -0.1003479003906193 +0.971375 -0.49530029296875 -0.445587158203125 -0.1003479003906193 +0.9715 -0.49530029296875 -0.445587158203125 -0.1003479003906193 +0.971625000000000096 -0.49456787109375 -0.444915771484375 -0.1003479003906193 +0.97175 -0.4937744140625 -0.4442138671875 -0.1003479003906193 +0.971875 -0.4937744140625 -0.4442138671875 -0.1003479003906193 +0.972 -0.492950439453125 -0.443450927734375 -0.1003479003906193 +0.972125 -0.492950439453125 -0.443450927734375 -0.1003479003906193 +0.972250000000000096 -0.492034912109375 -0.442657470703125 -0.1003479003906193 +0.972375 -0.4910888671875 -0.4417724609375 -0.1003479003906193 +0.9725 -0.4910888671875 -0.4417724609375 -0.1003479003906193 +0.972625000000000096 -0.490081787109375 -0.440887451171875 -0.1003479003906193 +0.97275 -0.490081787109375 -0.440887451171875 -0.1003479003906193 +0.972875 -0.489013671875 -0.439910888671875 -0.1003479003906193 +0.973 -0.487884521484375 -0.43890380859375 -0.1003479003906193 +0.973125 -0.487884521484375 -0.43890380859375 -0.1003479003906193 +0.973250000000000096 -0.486724853515625 -0.4378662109375 -0.1003479003906193 +0.973375 -0.486724853515625 -0.4378662109375 -0.1003479003906193 +0.9735 -0.485504150390625 -0.436767578125 -0.1003479003906193 +0.973625000000000096 -0.484222412109375 -0.43560791015625 -0.1003479003906193 +0.97375 -0.484222412109375 -0.43560791015625 -0.1003479003906193 +0.973875 -0.48291015625 -0.434417724609375 -0.1003479003906193 +0.974 -0.48291015625 -0.434417724609375 -0.1003479003906193 +0.974125 -0.48150634765625 -0.43316650390625 -0.1003479003906193 +0.974250000000000096 -0.480072021484375 -0.431884765625 -0.1003479003906193 +0.974375 -0.480072021484375 -0.431884765625 -0.1003479003906193 +0.9745 -0.478607177734375 -0.4305419921875 -0.1003479003906193 +0.974625000000000096 -0.478607177734375 -0.4305419921875 -0.1003479003906193 +0.97475 -0.47705078125 -0.429168701171875 -0.1003479003906193 +0.974875 -0.4754638671875 -0.427734375 -0.1003479003906193 +0.975 -0.4754638671875 -0.427734375 -0.1003479003906193 +0.975125 -0.47381591796875 -0.42626953125 -0.1003479003906193 +0.975250000000000096 -0.47381591796875 -0.42626953125 -0.1003479003906193 +0.975375 -0.472137451171875 -0.42474365234375 -0.1003479003906193 +0.9755 -0.470367431640625 -0.42315673828125 -0.1003479003906193 +0.975625000000000096 -0.470367431640625 -0.42315673828125 -0.1003479003906193 +0.97575 -0.46856689453125 -0.421539306640625 -0.1003479003906193 +0.975875 -0.46856689453125 -0.421539306640625 -0.1003479003906193 +0.976 -0.46673583984375 -0.41986083984375 -0.1003479003906193 +0.976125 -0.464813232421875 -0.41815185546875 -0.1003479003906193 +0.976250000000000096 -0.464813232421875 -0.41815185546875 -0.1003479003906193 +0.976375 -0.462890625 -0.416412353515625 -0.1003479003906193 +0.9765 -0.462890625 -0.416412353515625 -0.1003479003906193 +0.976625 -0.46087646484375 -0.41461181640625 -0.1003479003906193 +0.97675 -0.458831787109375 -0.412750244140625 -0.1003479003906193 +0.976875 -0.458831787109375 -0.412750244140625 -0.1003479003906193 +0.977 -0.45672607421875 -0.410858154296875 -0.1003479003906193 +0.977125 -0.45672607421875 -0.410858154296875 -0.1003479003906193 +0.977250000000000096 -0.454559326171875 -0.408905029296875 -0.1003479003906193 +0.977375 -0.452362060546875 -0.406951904296875 -0.1003479003906193 +0.9775 -0.452362060546875 -0.406951904296875 -0.1003479003906193 +0.977625 -0.450103759765625 -0.4049072265625 -0.1003479003906193 +0.97775 -0.450103759765625 -0.4049072265625 -0.1003479003906193 +0.977875 -0.447784423828125 -0.40283203125 -0.1003479003906193 +0.978 -0.4454345703125 -0.400726318359375 -0.1003479003906193 +0.978125 -0.4454345703125 -0.400726318359375 -0.1003479003906193 +0.978250000000000096 -0.44305419921875 -0.3985595703125 -0.1003479003906193 +0.978375 -0.44305419921875 -0.3985595703125 -0.1003479003906193 +0.9785 -0.440582275390625 -0.3963623046875 -0.1003479003906193 +0.978625 -0.438079833984375 -0.39410400390625 -0.1003479003906193 +0.97875 -0.438079833984375 -0.39410400390625 -0.1003479003906193 +0.978875 -0.435546875 -0.391815185546875 -0.1003479003906193 +0.979 -0.435546875 -0.391815185546875 -0.1003479003906193 +0.979125 -0.432952880859375 -0.389495849609375 -0.1003479003906193 +0.979250000000000096 -0.4302978515625 -0.387115478515625 -0.1003479003906193 +0.979375 -0.4302978515625 -0.387115478515625 -0.1003479003906193 +0.9795 -0.4276123046875 -0.38470458984375 -0.1003479003906193 +0.979625 -0.4276123046875 -0.38470458984375 -0.1003479003906193 +0.97975 -0.424896240234375 -0.382232666015625 -0.1003479003906193 +0.979875 -0.422119140625 -0.379730224609375 -0.1003479003906193 +0.98 -0.422119140625 -0.379730224609375 -0.1003479003906193 +0.980125 -0.419281005859375 -0.377197265625 -0.1003479003906193 +0.980250000000000096 -0.419281005859375 -0.377197265625 -0.1003479003906193 +0.980375 -0.416412353515625 -0.374603271484375 -0.1003479003906193 +0.9805 -0.413482666015625 -0.371978759765625 -0.1003479003906193 +0.980625 -0.413482666015625 -0.371978759765625 -0.1003479003906193 +0.98075 -0.4105224609375 -0.369293212890625 -0.1003479003906193 +0.980875 -0.4105224609375 -0.369293212890625 -0.1003479003906193 +0.981 -0.407501220703125 -0.366607666015625 -0.1003479003906193 +0.981125 -0.404449462890625 -0.363861083984375 -0.1003479003906193 +0.981250000000000096 -0.404449462890625 -0.363861083984375 -0.1003479003906193 +0.981375 -0.401336669921875 -0.361053466796875 -0.1003479003906193 +0.9815 -0.401336669921875 -0.361053466796875 -0.1003479003906193 +0.981625 -0.398193359375 -0.35821533203125 -0.1003479003906193 +0.98175 -0.39501953125 -0.355377197265625 -0.1003479003906193 +0.981875 -0.39501953125 -0.355377197265625 -0.1003479003906193 +0.982 -0.39178466796875 -0.352447509765625 -0.1003479003906193 +0.982125 -0.39178466796875 -0.352447509765625 -0.1003479003906193 +0.982250000000000096 -0.388519287109375 -0.349517822265625 -0.1003479003906193 +0.982375 -0.38519287109375 -0.346527099609375 -0.1003479003906193 +0.9825 -0.38519287109375 -0.346527099609375 -0.1003479003906193 +0.982625 -0.3818359375 -0.343505859375 -0.1003479003906193 +0.98275 -0.3818359375 -0.343505859375 -0.1003479003906193 +0.982875 -0.378448486328125 -0.3404541015625 -0.1003479003906193 +0.983 -0.375 -0.33734130859375 -0.1003479003906193 +0.983125 -0.375 -0.33734130859375 -0.1003479003906193 +0.983250000000000096 -0.37152099609375 -0.334228515625 -0.1003479003906193 +0.983375 -0.37152099609375 -0.334228515625 -0.1003479003906193 +0.9835 -0.36798095703125 -0.3310546875 -0.1003479003906193 +0.983625 -0.36444091796875 -0.327850341796875 -0.1003479003906193 +0.98375 -0.36444091796875 -0.327850341796875 -0.1003479003906193 +0.983875 -0.360809326171875 -0.3245849609375 -0.1003479003906193 +0.984 -0.360809326171875 -0.3245849609375 -0.1003479003906193 +0.984125 -0.357177734375 -0.321319580078125 -0.1003479003906193 +0.984250000000000096 -0.353485107421875 -0.318023681640625 -0.1003479003906193 +0.984375 -0.353485107421875 -0.318023681640625 -0.1003479003906193 +0.9845 -0.349761962890625 -0.314666748046875 -0.1003479003906193 +0.984625 -0.349761962890625 -0.314666748046875 -0.1003479003906193 +0.98475 -0.34600830078125 -0.311279296875 -0.1003479003906193 +0.984875000000000096 -0.34222412109375 -0.307861328125 -0.1003479003906193 +0.985 -0.34222412109375 -0.307861328125 -0.1003479003906193 +0.985125 -0.33837890625 -0.304412841796875 -0.1003479003906193 +0.985250000000000096 -0.33837890625 -0.304412841796875 -0.1003479003906193 +0.985375 -0.334503173828125 -0.300933837890625 -0.1003479003906193 +0.9855 -0.330596923828125 -0.29742431640625 -0.1003479003906193 +0.985625 -0.330596923828125 -0.29742431640625 -0.1003479003906193 +0.98575 -0.32666015625 -0.293853759765625 -0.1003479003906193 +0.985875000000000096 -0.32666015625 -0.293853759765625 -0.1003479003906193 +0.986 -0.322662353515625 -0.290283203125 -0.1003479003906193 +0.986125 -0.31866455078125 -0.28668212890625 -0.1003479003906193 +0.986250000000000096 -0.31866455078125 -0.28668212890625 -0.1003479003906193 +0.986375 -0.314605712890625 -0.28302001953125 -0.1003479003906193 +0.9865 -0.314605712890625 -0.28302001953125 -0.1003479003906193 +0.986625 -0.310516357421875 -0.27935791015625 -0.1003479003906193 +0.98675 -0.306396484375 -0.275634765625 -0.1003479003906193 +0.986875000000000096 -0.306396484375 -0.275634765625 -0.1003479003906193 +0.987 -0.30224609375 -0.27191162109375 -0.1003479003906193 +0.987125 -0.30224609375 -0.27191162109375 -0.1003479003906193 +0.987250000000000096 -0.298065185546875 -0.26812744140625 -0.1003479003906193 +0.987375 -0.2938232421875 -0.26434326171875 -0.1003479003906193 +0.9875 -0.2938232421875 -0.26434326171875 -0.1003479003906193 +0.987625 -0.289581298828125 -0.260528564453125 -0.1003479003906193 +0.98775 -0.289581298828125 -0.260528564453125 -0.1003479003906193 +0.987875000000000096 -0.285308837890625 -0.25665283203125 -0.1003479003906193 +0.988 -0.280975341796875 -0.252777099609375 -0.1003479003906193 +0.988125 -0.280975341796875 -0.252777099609375 -0.1003479003906193 +0.988250000000000096 -0.276641845703125 -0.248870849609375 -0.1003479003906193 +0.988375 -0.276641845703125 -0.248870849609375 -0.1003479003906193 +0.9885 -0.27227783203125 -0.24493408203125 -0.1003479003906193 +0.988625 -0.267852783203125 -0.240966796875 -0.1003479003906193 +0.98875 -0.267852783203125 -0.240966796875 -0.1003479003906193 +0.988875000000000096 -0.263427734375 -0.236968994140625 -0.1003479003906193 +0.989 -0.263427734375 -0.236968994140625 -0.1003479003906193 +0.989125 -0.25897216796875 -0.23297119140625 -0.1003479003906193 +0.989250000000000096 -0.25445556640625 -0.228912353515625 -0.1003479003906193 +0.989375 -0.25445556640625 -0.228912353515625 -0.1003479003906193 +0.9895 -0.249969482421875 -0.224853515625 -0.1003479003906193 +0.989625 -0.249969482421875 -0.224853515625 -0.1003479003906193 +0.98975 -0.24542236328125 -0.22076416015625 -0.1003479003906193 +0.989875000000000096 -0.2408447265625 -0.216644287109375 -0.1003479003906193 +0.99 -0.2408447265625 -0.216644287109375 -0.1003479003906193 +0.990125 -0.236236572265625 -0.2125244140625 -0.1003479003906193 +0.990250000000000096 -0.236236572265625 -0.2125244140625 -0.1003479003906193 +0.990375 -0.231597900390625 -0.208343505859375 -0.1003479003906193 +0.9905 -0.226959228515625 -0.20416259765625 -0.1003479003906193 +0.990625 -0.226959228515625 -0.20416259765625 -0.1003479003906193 +0.99075 -0.2222900390625 -0.199951171875 -0.1003479003906193 +0.990875000000000096 -0.2222900390625 -0.199951171875 -0.1003479003906193 +0.991 -0.21759033203125 -0.19573974609375 -0.1003479003906193 +0.991125 -0.212860107421875 -0.19146728515625 -0.1003479003906193 +0.991250000000000096 -0.212860107421875 -0.19146728515625 -0.1003479003906193 +0.991375 -0.208099365234375 -0.187225341796875 -0.1003479003906193 +0.9915 -0.208099365234375 -0.187225341796875 -0.1003479003906193 +0.991625 -0.203338623046875 -0.18292236328125 -0.1003479003906193 +0.99175 -0.19854736328125 -0.178619384765625 -0.1003479003906193 +0.991875000000000096 -0.19854736328125 -0.178619384765625 -0.1003479003906193 +0.992 -0.13616943359375 -0.1937255859375 0.2970092773437556 +0.992125 -0.13616943359375 -0.1937255859375 0.2970092773437556 +0.99225 -0.132781982421875 -0.188873291015625 0.2970092773437556 +0.992375 -0.129364013671875 -0.18402099609375 0.2970092773437556 +0.9925 -0.129364013671875 -0.18402099609375 0.2970092773437556 +0.992625 -0.12591552734375 -0.17913818359375 0.2970092773437556 +0.99275 -0.12591552734375 -0.17913818359375 0.2970092773437556 +0.992875000000000096 -0.122467041015625 -0.17425537109375 0.2970092773437556 +0.993 -0.1190185546875 -0.169342041015625 0.2970092773437556 +0.993125 -0.1190185546875 -0.169342041015625 0.2970092773437556 +0.99325 -0.11553955078125 -0.164398193359375 0.2970092773437556 +0.993375 -0.11553955078125 -0.164398193359375 0.2970092773437556 +0.9935 -0.112091064453125 -0.159454345703125 0.2970092773437556 +0.993625 -0.10858154296875 -0.15447998046875 0.2970092773437556 +0.99375 -0.10858154296875 -0.15447998046875 0.2970092773437556 +0.993875000000000096 -0.105072021484375 -0.14947509765625 0.2970092773437556 +0.994 -0.105072021484375 -0.14947509765625 0.2970092773437556 +0.994125 -0.1015625 -0.14447021484375 0.2970092773437556 +0.99425 -0.0980224609375 -0.13946533203125 0.2970092773437556 +0.994375 -0.0980224609375 -0.13946533203125 0.2970092773437556 +0.9945 -0.094482421875 -0.134429931640625 0.2970092773437556 +0.994625 -0.094482421875 -0.134429931640625 0.2970092773437556 +0.99475 -0.0909423828125 -0.129364013671875 0.2970092773437556 +0.994875000000000096 -0.087371826171875 -0.124298095703125 0.2970092773437556 +0.995 -0.087371826171875 -0.124298095703125 0.2970092773437556 +0.995125 -0.08380126953125 -0.119232177734375 0.2970092773437556 +0.99525 -0.08380126953125 -0.119232177734375 0.2970092773437556 +0.995375 -0.080230712890625 -0.1141357421875 0.2970092773437556 +0.9955 -0.076629638671875 -0.109039306640625 0.2970092773437556 +0.995625 -0.076629638671875 -0.109039306640625 0.2970092773437556 +0.99575 -0.07305908203125 -0.103912353515625 0.2970092773437556 +0.995875000000000096 -0.07305908203125 -0.103912353515625 0.2970092773437556 +0.996 -0.0694580078125 -0.098785400390625 0.2970092773437556 +0.996125 -0.065826416015625 -0.093658447265625 0.2970092773437556 +0.99625 -0.065826416015625 -0.093658447265625 0.2970092773437556 +0.996375 -0.062225341796875 -0.0885009765625 0.2970092773437556 +0.9965 -0.062225341796875 -0.0885009765625 0.2970092773437556 +0.996625 -0.05859375 -0.083343505859375 0.2970092773437556 +0.99675 -0.054962158203125 -0.07818603515625 0.2970092773437556 +0.996875000000000096 -0.054962158203125 -0.07818603515625 0.2970092773437556 +0.997 -0.05133056640625 -0.072998046875 0.2970092773437556 +0.997125 -0.05133056640625 -0.072998046875 0.2970092773437556 +0.99725 -0.04766845703125 -0.06781005859375 0.2970092773437556 +0.997375 -0.044036865234375 -0.0626220703125 0.2970092773437556 +0.9975 -0.044036865234375 -0.0626220703125 0.2970092773437556 +0.997625 -0.040374755859375 -0.05743408203125 0.2970092773437556 +0.99775 -0.040374755859375 -0.05743408203125 0.2970092773437556 +0.997875000000000096 -0.036712646484375 -0.05224609375 0.2970092773437556 +0.998 -0.033050537109375 -0.047027587890625 0.2970092773437556 +0.998125 -0.033050537109375 -0.047027587890625 0.2970092773437556 +0.99825 -0.029388427734375 -0.04180908203125 0.2970092773437556 +0.998375 -0.029388427734375 -0.04180908203125 0.2970092773437556 +0.9985 -0.025726318359375 -0.036590576171875 0.2970092773437556 +0.998625 -0.02203369140625 -0.0313720703125 0.2970092773437556 +0.99875 -0.02203369140625 -0.0313720703125 0.2970092773437556 +0.998875000000000096 -0.01837158203125 -0.026123046875 0.2970092773437556 +0.999 -0.01837158203125 -0.026123046875 0.2970092773437556 +0.999125 -0.01470947265625 -0.020904541015625 0.2970092773437556 +0.99925 -0.011016845703125 -0.01568603515625 0.2970092773437556 +0.999375 -0.011016845703125 -0.01568603515625 0.2970092773437556 +0.9995 -0.007354736328125 -0.01043701171875 0.2970092773437556 +0.999625 -0.007354736328125 -0.01043701171875 0.2970092773437556 +0.99975 -0.003662109375 -0.005218505859375 0.2970092773437556 +0.999875000000000096 0.0 0.0 0.2970092773437556 +1.0 0.0 0.0 0.2970092773437556 +1.000125 0.003662109375 0.005218505859375 0.2970092773437556 +1.00025 0.003662109375 0.005218505859375 0.2970092773437556 +1.000375 0.007354736328125 0.01043701171875 0.2970092773437556 +1.0005 0.011016845703125 0.01568603515625 0.2970092773437556 +1.000625 0.011016845703125 0.01568603515625 0.2970092773437556 +1.00075 0.01470947265625 0.020904541015625 0.2970092773437556 +1.000875 0.01470947265625 0.020904541015625 0.2970092773437556 +1.0010000000000002 0.01837158203125 0.026123046875 0.2970092773437556 +1.001125 0.02203369140625 0.0313720703125 0.2970092773437556 +1.00125 0.02203369140625 0.0313720703125 0.2970092773437556 +1.0013750000000002 0.025726318359375 0.036590576171875 0.2970092773437556 +1.0015 0.025726318359375 0.036590576171875 0.2970092773437556 +1.001625 0.029388427734375 0.04180908203125 0.2970092773437556 +1.00175 0.033050537109375 0.047027587890625 0.2970092773437556 +1.001875 0.033050537109375 0.047027587890625 0.2970092773437556 +1.002 0.036712646484375 0.05224609375 0.2970092773437556 +1.002125 0.036712646484375 0.05224609375 0.2970092773437556 +1.00225 0.040374755859375 0.05743408203125 0.2970092773437556 +1.002375 0.044036865234375 0.0626220703125 0.2970092773437556 +1.0025 0.044036865234375 0.0626220703125 0.2970092773437556 +1.002625 0.04766845703125 0.06781005859375 0.2970092773437556 +1.00275 0.04766845703125 0.06781005859375 0.2970092773437556 +1.002875 0.05133056640625 0.072998046875 0.2970092773437556 +1.0030000000000002 0.054962158203125 0.07818603515625 0.2970092773437556 +1.003125 0.054962158203125 0.07818603515625 0.2970092773437556 +1.00325 0.05859375 0.083343505859375 0.2970092773437556 +1.0033750000000002 0.05859375 0.083343505859375 0.2970092773437556 +1.0035 0.062225341796875 0.0885009765625 0.2970092773437556 +1.003625 0.065826416015625 0.093658447265625 0.2970092773437556 +1.00375 0.065826416015625 0.093658447265625 0.2970092773437556 +1.003875 0.0694580078125 0.098785400390625 0.2970092773437556 +1.004 0.0694580078125 0.098785400390625 0.2970092773437556 +1.004125 0.07305908203125 0.103912353515625 0.2970092773437556 +1.00425 0.076629638671875 0.109039306640625 0.2970092773437556 +1.004375 0.076629638671875 0.109039306640625 0.2970092773437556 +1.0045 0.080230712890625 0.1141357421875 0.2970092773437556 +1.004625 0.080230712890625 0.1141357421875 0.2970092773437556 +1.00475 0.08380126953125 0.119232177734375 0.2970092773437556 +1.004875 0.087371826171875 0.124298095703125 0.2970092773437556 +1.0050000000000002 0.087371826171875 0.124298095703125 0.2970092773437556 +1.005125 0.0909423828125 0.129364013671875 0.2970092773437556 +1.00525 0.0909423828125 0.129364013671875 0.2970092773437556 +1.0053750000000002 0.094482421875 0.134429931640625 0.2970092773437556 +1.0055 0.0980224609375 0.13946533203125 0.2970092773437556 +1.005625 0.0980224609375 0.13946533203125 0.2970092773437556 +1.00575 0.1015625 0.14447021484375 0.2970092773437556 +1.005875 0.1015625 0.14447021484375 0.2970092773437556 +1.006 0.105072021484375 0.14947509765625 0.2970092773437556 +1.006125 0.10858154296875 0.15447998046875 0.2970092773437556 +1.00625 0.10858154296875 0.15447998046875 0.2970092773437556 +1.006375 0.112091064453125 0.159454345703125 0.2970092773437556 +1.0065 0.112091064453125 0.159454345703125 0.2970092773437556 +1.006625 0.11553955078125 0.164398193359375 0.2970092773437556 +1.00675 0.1190185546875 0.169342041015625 0.2970092773437556 +1.006875 0.1190185546875 0.169342041015625 0.2970092773437556 +1.0070000000000002 0.122467041015625 0.17425537109375 0.2970092773437556 +1.007125 0.122467041015625 0.17425537109375 0.2970092773437556 +1.00725 0.12591552734375 0.17913818359375 0.2970092773437556 +1.0073750000000002 0.129364013671875 0.18402099609375 0.2970092773437556 +1.0075 0.129364013671875 0.18402099609375 0.2970092773437556 +1.007625 0.132781982421875 0.188873291015625 0.2970092773437556 +1.00775 0.132781982421875 0.188873291015625 0.2970092773437556 +1.007875 0.13616943359375 0.1937255859375 0.2970092773437556 +1.008 0.139556884765625 0.19854736328125 0.2970092773437556 +1.008125 0.139556884765625 0.19854736328125 0.2970092773437556 +1.00825 0.142913818359375 0.203338623046875 0.2970092773437556 +1.008375 0.142913818359375 0.203338623046875 0.2970092773437556 +1.0085 0.146270751953125 0.208099365234375 0.2970092773437556 +1.008625 0.149627685546875 0.212860107421875 0.2970092773437556 +1.00875 0.149627685546875 0.212860107421875 0.2970092773437556 +1.008875 0.1529541015625 0.21759033203125 0.2970092773437556 +1.0090000000000002 0.1529541015625 0.21759033203125 0.2970092773437556 +1.009125 0.15625 0.2222900390625 0.2970092773437556 +1.00925 0.159515380859375 0.226959228515625 0.2970092773437556 +1.009375 0.159515380859375 0.226959228515625 0.2970092773437556 +1.0095 0.162811279296875 0.231597900390625 0.2970092773437556 +1.009625 0.162811279296875 0.231597900390625 0.2970092773437556 +1.00975 0.166046142578125 0.236236572265625 0.2970092773437556 +1.009875 0.169281005859375 0.2408447265625 0.2970092773437556 +1.01 0.169281005859375 0.2408447265625 0.2970092773437556 +1.010125 0.172515869140625 0.24542236328125 0.2970092773437556 +1.01025 0.172515869140625 0.24542236328125 0.2970092773437556 +1.010375 0.175689697265625 0.249969482421875 0.2970092773437556 +1.0105 0.178863525390625 0.25445556640625 0.2970092773437556 +1.010625 0.178863525390625 0.25445556640625 0.2970092773437556 +1.01075 0.182037353515625 0.25897216796875 0.2970092773437556 +1.010875 0.182037353515625 0.25897216796875 0.2970092773437556 +1.0110000000000002 0.1851806640625 0.263427734375 0.2970092773437556 +1.011125 0.18829345703125 0.267852783203125 0.2970092773437556 +1.01125 0.18829345703125 0.267852783203125 0.2970092773437556 +1.011375 0.19140625 0.27227783203125 0.2970092773437556 +1.0115 0.19140625 0.27227783203125 0.2970092773437556 +1.011625 0.1944580078125 0.276641845703125 0.2970092773437556 +1.01175 0.197509765625 0.280975341796875 0.2970092773437556 +1.011875 0.197509765625 0.280975341796875 0.2970092773437556 +1.012 0.2005615234375 0.285308837890625 0.2970092773437556 +1.012125 0.2005615234375 0.285308837890625 0.2970092773437556 +1.01225 0.20355224609375 0.289581298828125 0.2970092773437556 +1.012375 0.20654296875 0.2938232421875 0.2970092773437556 +1.0125 0.20654296875 0.2938232421875 0.2970092773437556 +1.012625 0.20953369140625 0.298065185546875 0.2970092773437556 +1.01275 0.20953369140625 0.298065185546875 0.2970092773437556 +1.012875 0.21246337890625 0.30224609375 0.2970092773437556 +1.0130000000000002 0.21539306640625 0.306396484375 0.2970092773437556 +1.013125 0.21539306640625 0.306396484375 0.2970092773437556 +1.01325 0.218292236328125 0.310516357421875 0.2970092773437556 +1.013375 0.218292236328125 0.310516357421875 0.2970092773437556 +1.0135 0.221160888671875 0.314605712890625 0.2970092773437556 +1.013625 0.2239990234375 0.31866455078125 0.2970092773437556 +1.01375 0.2239990234375 0.31866455078125 0.2970092773437556 +1.013875 0.226806640625 0.322662353515625 0.2970092773437556 +1.014 0.226806640625 0.322662353515625 0.2970092773437556 +1.014125 0.2296142578125 0.32666015625 0.2970092773437556 +1.01425 0.232391357421875 0.330596923828125 0.2970092773437556 +1.014375 0.232391357421875 0.330596923828125 0.2970092773437556 +1.0145 0.235137939453125 0.334503173828125 0.2970092773437556 +1.014625 0.235137939453125 0.334503173828125 0.2970092773437556 +1.01475 0.23785400390625 0.33837890625 0.2970092773437556 +1.014875 0.240570068359375 0.34222412109375 0.2970092773437556 +1.0150000000000002 0.240570068359375 0.34222412109375 0.2970092773437556 +1.015125 0.24322509765625 0.34600830078125 0.2970092773437556 +1.01525 0.24322509765625 0.34600830078125 0.2970092773437556 +1.015375 0.245880126953125 0.349761962890625 0.2970092773437556 +1.0155 0.24847412109375 0.353485107421875 0.2970092773437556 +1.015625 0.24847412109375 0.353485107421875 0.2970092773437556 +1.01575 0.251068115234375 0.357177734375 0.2970092773437556 +1.015875 0.251068115234375 0.357177734375 0.2970092773437556 +1.016 0.253631591796875 0.360809326171875 0.2970092773437556 +1.016125 0.25616455078125 0.36444091796875 0.2970092773437556 +1.01625 0.25616455078125 0.36444091796875 0.2970092773437556 +1.016375 0.2586669921875 0.36798095703125 0.2970092773437556 +1.0165 0.2586669921875 0.36798095703125 0.2970092773437556 +1.0166250000000002 0.261138916015625 0.37152099609375 0.2970092773437556 +1.01675 0.26361083984375 0.375 0.2970092773437556 +1.016875 0.26361083984375 0.375 0.2970092773437556 +1.0170000000000002 0.266021728515625 0.378448486328125 0.2970092773437556 +1.017125 0.266021728515625 0.378448486328125 0.2970092773437556 +1.01725 0.268402099609375 0.3818359375 0.2970092773437556 +1.017375 0.270782470703125 0.38519287109375 0.2970092773437556 +1.0175 0.270782470703125 0.38519287109375 0.2970092773437556 +1.017625 0.273101806640625 0.388519287109375 0.2970092773437556 +1.01775 0.273101806640625 0.388519287109375 0.2970092773437556 +1.017875 0.275421142578125 0.39178466796875 0.2970092773437556 +1.018 0.277679443359375 0.39501953125 0.2970092773437556 +1.018125 0.277679443359375 0.39501953125 0.2970092773437556 +1.01825 0.2799072265625 0.398193359375 0.2970092773437556 +1.018375 0.2799072265625 0.398193359375 0.2970092773437556 +1.0185 0.282135009765625 0.401336669921875 0.2970092773437556 +1.0186250000000002 0.2843017578125 0.404449462890625 0.2970092773437556 +1.01875 0.2843017578125 0.404449462890625 0.2970092773437556 +1.018875 0.286468505859375 0.407501220703125 0.2970092773437556 +1.0190000000000002 0.286468505859375 0.407501220703125 0.2970092773437556 +1.019125 0.28857421875 0.4105224609375 0.2970092773437556 +1.01925 0.2906494140625 0.413482666015625 0.2970092773437556 +1.019375 0.2906494140625 0.413482666015625 0.2970092773437556 +1.0195 0.292694091796875 0.416412353515625 0.2970092773437556 +1.019625 0.292694091796875 0.416412353515625 0.2970092773437556 +1.01975 0.29473876953125 0.419281005859375 0.2970092773437556 +1.019875 0.296722412109375 0.422119140625 0.2970092773437556 +1.02 0.296722412109375 0.422119140625 0.2970092773437556 +1.020125 0.298675537109375 0.424896240234375 0.2970092773437556 +1.02025 0.298675537109375 0.424896240234375 0.2970092773437556 +1.020375 0.30059814453125 0.4276123046875 0.2970092773437556 +1.0205 0.302490234375 0.4302978515625 0.2970092773437556 +1.0206250000000002 0.302490234375 0.4302978515625 0.2970092773437556 +1.02075 0.304351806640625 0.432952880859375 0.2970092773437556 +1.020875 0.304351806640625 0.432952880859375 0.2970092773437556 +1.0210000000000002 0.306182861328125 0.435546875 0.2970092773437556 +1.021125 0.307952880859375 0.438079833984375 0.2970092773437556 +1.02125 0.307952880859375 0.438079833984375 0.2970092773437556 +1.021375 0.3096923828125 0.440582275390625 0.2970092773437556 +1.0215 0.3096923828125 0.440582275390625 0.2970092773437556 +1.021625 0.311431884765625 0.44305419921875 0.2970092773437556 +1.02175 0.3131103515625 0.4454345703125 0.2970092773437556 +1.021875 0.3131103515625 0.4454345703125 0.2970092773437556 +1.022 0.31475830078125 0.447784423828125 0.2970092773437556 +1.022125 0.31475830078125 0.447784423828125 0.2970092773437556 +1.02225 0.316375732421875 0.450103759765625 0.2970092773437556 +1.022375 0.317962646484375 0.452362060546875 0.2970092773437556 +1.0225 0.317962646484375 0.452362060546875 0.2970092773437556 +1.0226250000000002 0.31951904296875 0.454559326171875 0.2970092773437556 +1.02275 0.31951904296875 0.454559326171875 0.2970092773437556 +1.022875 0.321044921875 0.45672607421875 0.2970092773437556 +1.0230000000000002 0.322509765625 0.458831787109375 0.2970092773437556 +1.023125 0.322509765625 0.458831787109375 0.2970092773437556 +1.02325 0.323974609375 0.46087646484375 0.2970092773437556 +1.023375 0.323974609375 0.46087646484375 0.2970092773437556 +1.0235 0.32537841796875 0.462890625 0.2970092773437556 +1.023625 0.326751708984375 0.464813232421875 0.2970092773437556 +1.02375 0.326751708984375 0.464813232421875 0.2970092773437556 +1.023875 0.328094482421875 0.46673583984375 0.2970092773437556 +1.024 0.164703369140625 0.46673583984375 0.6470092773437545 +1.024125 0.165374755859375 0.46856689453125 0.6470092773437545 +1.02425 0.165985107421875 0.470367431640625 0.6470092773437545 +1.024375 0.165985107421875 0.470367431640625 0.6470092773437545 +1.0245 0.1666259765625 0.472137451171875 0.6470092773437545 +1.0246250000000002 0.1666259765625 0.472137451171875 0.6470092773437545 +1.02475 0.167205810546875 0.47381591796875 0.6470092773437545 +1.024875 0.16778564453125 0.4754638671875 0.6470092773437545 +1.025 0.16778564453125 0.4754638671875 0.6470092773437545 +1.025125 0.168365478515625 0.47705078125 0.6470092773437545 +1.02525 0.168365478515625 0.47705078125 0.6470092773437545 +1.025375 0.16888427734375 0.478607177734375 0.6470092773437545 +1.0255 0.16943359375 0.480072021484375 0.6470092773437545 +1.025625 0.16943359375 0.480072021484375 0.6470092773437545 +1.02575 0.169921875 0.48150634765625 0.6470092773437545 +1.025875 0.169921875 0.48150634765625 0.6470092773437545 +1.026 0.17041015625 0.48291015625 0.6470092773437545 +1.026125 0.1708984375 0.484222412109375 0.6470092773437545 +1.02625 0.1708984375 0.484222412109375 0.6470092773437545 +1.026375 0.17132568359375 0.485504150390625 0.6470092773437545 +1.0265 0.17132568359375 0.485504150390625 0.6470092773437545 +1.0266250000000002 0.171783447265625 0.486724853515625 0.6470092773437545 +1.02675 0.17218017578125 0.487884521484375 0.6470092773437545 +1.026875 0.17218017578125 0.487884521484375 0.6470092773437545 +1.027 0.172576904296875 0.489013671875 0.6470092773437545 +1.027125 0.172576904296875 0.489013671875 0.6470092773437545 +1.02725 0.172943115234375 0.490081787109375 0.6470092773437545 +1.027375 0.173309326171875 0.4910888671875 0.6470092773437545 +1.0275 0.173309326171875 0.4910888671875 0.6470092773437545 +1.027625 0.17364501953125 0.492034912109375 0.6470092773437545 +1.02775 0.17364501953125 0.492034912109375 0.6470092773437545 +1.027875 0.1739501953125 0.492950439453125 0.6470092773437545 +1.028 0.17425537109375 0.4937744140625 0.6470092773437545 +1.028125 0.17425537109375 0.4937744140625 0.6470092773437545 +1.02825 0.174530029296875 0.49456787109375 0.6470092773437545 +1.028375 0.174530029296875 0.49456787109375 0.6470092773437545 +1.0285 0.1748046875 0.49530029296875 0.6470092773437545 +1.0286250000000002 0.175048828125 0.496002197265625 0.6470092773437545 +1.02875 0.175048828125 0.496002197265625 0.6470092773437545 +1.028875 0.175262451171875 0.496612548828125 0.6470092773437545 +1.029 0.175262451171875 0.496612548828125 0.6470092773437545 +1.029125 0.17547607421875 0.4971923828125 0.6470092773437545 +1.02925 0.1756591796875 0.497711181640625 0.6470092773437545 +1.029375 0.1756591796875 0.497711181640625 0.6470092773437545 +1.0295 0.175811767578125 0.498199462890625 0.6470092773437545 +1.029625 0.175811767578125 0.498199462890625 0.6470092773437545 +1.02975 0.17596435546875 0.49859619140625 0.6470092773437545 +1.029875 0.17608642578125 0.49896240234375 0.6470092773437545 +1.03 0.17608642578125 0.49896240234375 0.6470092773437545 +1.030125 0.176177978515625 0.499267578125 0.6470092773437545 +1.03025 0.176177978515625 0.499267578125 0.6470092773437545 +1.030375 0.17626953125 0.49951171875 0.6470092773437545 +1.0305 0.17633056640625 0.49969482421875 0.6470092773437545 +1.0306250000000002 0.17633056640625 0.49969482421875 0.6470092773437545 +1.03075 0.1763916015625 0.49981689453125 0.6470092773437545 +1.030875 0.1763916015625 0.49981689453125 0.6470092773437545 +1.031 0.176422119140625 0.499908447265625 0.6470092773437545 +1.031125 0.176422119140625 0.49993896484375 0.6470092773437545 +1.03125 0.176422119140625 0.49993896484375 0.6470092773437545 +1.031375 0.176422119140625 0.499908447265625 0.6470092773437545 +1.0315 0.176422119140625 0.499908447265625 0.6470092773437545 +1.031625 0.1763916015625 0.49981689453125 0.6470092773437545 +1.03175 0.17633056640625 0.49969482421875 0.6470092773437545 +1.031875 0.17633056640625 0.49969482421875 0.6470092773437545 +1.032 0.17626953125 0.49951171875 0.6470092773437545 +1.032125 0.17626953125 0.49951171875 0.6470092773437545 +1.0322500000000002 0.176177978515625 0.499267578125 0.6470092773437545 +1.032375 0.17608642578125 0.49896240234375 0.6470092773437545 +1.0325 0.17608642578125 0.49896240234375 0.6470092773437545 +1.0326250000000002 0.17596435546875 0.49859619140625 0.6470092773437545 +1.03275 0.17596435546875 0.49859619140625 0.6470092773437545 +1.032875 0.175811767578125 0.498199462890625 0.6470092773437545 +1.033 0.1756591796875 0.497711181640625 0.6470092773437545 +1.033125 0.1756591796875 0.497711181640625 0.6470092773437545 +1.03325 0.17547607421875 0.4971923828125 0.6470092773437545 +1.033375 0.17547607421875 0.4971923828125 0.6470092773437545 +1.0335 0.175262451171875 0.496612548828125 0.6470092773437545 +1.033625 0.175048828125 0.496002197265625 0.6470092773437545 +1.03375 0.175048828125 0.496002197265625 0.6470092773437545 +1.033875 0.1748046875 0.49530029296875 0.6470092773437545 +1.034 0.1748046875 0.49530029296875 0.6470092773437545 +1.034125 0.174530029296875 0.49456787109375 0.6470092773437545 +1.0342500000000002 0.17425537109375 0.4937744140625 0.6470092773437545 +1.034375 0.17425537109375 0.4937744140625 0.6470092773437545 +1.0345 0.1739501953125 0.492950439453125 0.6470092773437545 +1.0346250000000002 0.1739501953125 0.492950439453125 0.6470092773437545 +1.03475 0.17364501953125 0.492034912109375 0.6470092773437545 +1.034875 0.173309326171875 0.4910888671875 0.6470092773437545 +1.035 0.173309326171875 0.4910888671875 0.6470092773437545 +1.035125 0.172943115234375 0.490081787109375 0.6470092773437545 +1.03525 0.172943115234375 0.490081787109375 0.6470092773437545 +1.035375 0.172576904296875 0.489013671875 0.6470092773437545 +1.0355 0.17218017578125 0.487884521484375 0.6470092773437545 +1.035625 0.17218017578125 0.487884521484375 0.6470092773437545 +1.03575 0.171783447265625 0.486724853515625 0.6470092773437545 +1.035875 0.171783447265625 0.486724853515625 0.6470092773437545 +1.036 0.17132568359375 0.485504150390625 0.6470092773437545 +1.036125 0.1708984375 0.484222412109375 0.6470092773437545 +1.0362500000000002 0.1708984375 0.484222412109375 0.6470092773437545 +1.036375 0.17041015625 0.48291015625 0.6470092773437545 +1.0365 0.17041015625 0.48291015625 0.6470092773437545 +1.0366250000000002 0.169921875 0.48150634765625 0.6470092773437545 +1.03675 0.16943359375 0.480072021484375 0.6470092773437545 +1.036875 0.16943359375 0.480072021484375 0.6470092773437545 +1.037 0.16888427734375 0.478607177734375 0.6470092773437545 +1.037125 0.16888427734375 0.478607177734375 0.6470092773437545 +1.03725 0.168365478515625 0.47705078125 0.6470092773437545 +1.037375 0.16778564453125 0.4754638671875 0.6470092773437545 +1.0375 0.16778564453125 0.4754638671875 0.6470092773437545 +1.037625 0.167205810546875 0.47381591796875 0.6470092773437545 +1.03775 0.167205810546875 0.47381591796875 0.6470092773437545 +1.037875 0.1666259765625 0.472137451171875 0.6470092773437545 +1.038 0.165985107421875 0.470367431640625 0.6470092773437545 +1.038125 0.165985107421875 0.470367431640625 0.6470092773437545 +1.0382500000000002 0.165374755859375 0.46856689453125 0.6470092773437545 +1.038375 0.165374755859375 0.46856689453125 0.6470092773437545 +1.0385 0.164703369140625 0.46673583984375 0.6470092773437545 +1.0386250000000002 0.164031982421875 0.464813232421875 0.6470092773437545 +1.03875 0.164031982421875 0.464813232421875 0.6470092773437545 +1.038875 0.163360595703125 0.462890625 0.6470092773437545 +1.039 0.163360595703125 0.462890625 0.6470092773437545 +1.039125 0.162628173828125 0.46087646484375 0.6470092773437545 +1.03925 0.16192626953125 0.458831787109375 0.6470092773437545 +1.039375 0.16192626953125 0.458831787109375 0.6470092773437545 +1.0395 0.161163330078125 0.45672607421875 0.6470092773437545 +1.039625 0.161163330078125 0.45672607421875 0.6470092773437545 +1.03975 0.160400390625 0.454559326171875 0.6470092773437545 +1.039875 0.159637451171875 0.452362060546875 0.6470092773437545 +1.04 0.159637451171875 0.452362060546875 0.6470092773437545 +1.040125 0.158843994140625 0.450103759765625 0.6470092773437545 +1.0402500000000002 0.158843994140625 0.450103759765625 0.6470092773437545 +1.040375 0.15802001953125 0.447784423828125 0.6470092773437545 +1.0405 0.157196044921875 0.4454345703125 0.6470092773437545 +1.040625 0.157196044921875 0.4454345703125 0.6470092773437545 +1.04075 0.156341552734375 0.44305419921875 0.6470092773437545 +1.040875 0.156341552734375 0.44305419921875 0.6470092773437545 +1.041 0.155487060546875 0.440582275390625 0.6470092773437545 +1.041125 0.15460205078125 0.438079833984375 0.6470092773437545 +1.04125 0.15460205078125 0.438079833984375 0.6470092773437545 +1.041375 0.153717041015625 0.435546875 0.6470092773437545 +1.0415 0.153717041015625 0.435546875 0.6470092773437545 +1.041625 0.152801513671875 0.432952880859375 0.6470092773437545 +1.04175 0.15185546875 0.4302978515625 0.6470092773437545 +1.041875 0.15185546875 0.4302978515625 0.6470092773437545 +1.042 0.150909423828125 0.4276123046875 0.6470092773437545 +1.042125 0.150909423828125 0.4276123046875 0.6470092773437545 +1.0422500000000002 0.149932861328125 0.424896240234375 0.6470092773437545 +1.042375 0.148956298828125 0.422119140625 0.6470092773437545 +1.0425 0.148956298828125 0.422119140625 0.6470092773437545 +1.042625 0.14794921875 0.419281005859375 0.6470092773437545 +1.04275 0.14794921875 0.419281005859375 0.6470092773437545 +1.042875 0.146942138671875 0.416412353515625 0.6470092773437545 +1.043 0.145904541015625 0.413482666015625 0.6470092773437545 +1.043125 0.145904541015625 0.413482666015625 0.6470092773437545 +1.04325 0.144866943359375 0.4105224609375 0.6470092773437545 +1.043375 0.144866943359375 0.4105224609375 0.6470092773437545 +1.0435 0.143798828125 0.407501220703125 0.6470092773437545 +1.043625 0.142730712890625 0.404449462890625 0.6470092773437545 +1.04375 0.142730712890625 0.404449462890625 0.6470092773437545 +1.043875 0.141632080078125 0.401336669921875 0.6470092773437545 +1.044 0.141632080078125 0.401336669921875 0.6470092773437545 +1.044125 0.140533447265625 0.398193359375 0.6470092773437545 +1.0442500000000002 0.139404296875 0.39501953125 0.6470092773437545 +1.044375 0.139404296875 0.39501953125 0.6470092773437545 +1.0445 0.138275146484375 0.39178466796875 0.6470092773437545 +1.044625 0.138275146484375 0.39178466796875 0.6470092773437545 +1.04475 0.137115478515625 0.388519287109375 0.6470092773437545 +1.044875 0.13592529296875 0.38519287109375 0.6470092773437545 +1.045 0.13592529296875 0.38519287109375 0.6470092773437545 +1.045125 0.134765625 0.3818359375 0.6470092773437545 +1.04525 0.134765625 0.3818359375 0.6470092773437545 +1.045375 0.133544921875 0.378448486328125 0.6470092773437545 +1.0455 0.13232421875 0.375 0.6470092773437545 +1.045625 0.13232421875 0.375 0.6470092773437545 +1.04575 0.131103515625 0.37152099609375 0.6470092773437545 +1.045875 0.131103515625 0.37152099609375 0.6470092773437545 +1.046 0.129852294921875 0.36798095703125 0.6470092773437545 +1.046125 0.12860107421875 0.36444091796875 0.6470092773437545 +1.0462500000000002 0.12860107421875 0.36444091796875 0.6470092773437545 +1.046375 0.1273193359375 0.360809326171875 0.6470092773437545 +1.0465 0.1273193359375 0.360809326171875 0.6470092773437545 +1.046625 0.12603759765625 0.357177734375 0.6470092773437545 +1.04675 0.124755859375 0.353485107421875 0.6470092773437545 +1.046875 0.124755859375 0.353485107421875 0.6470092773437545 +1.047 0.123443603515625 0.349761962890625 0.6470092773437545 +1.047125 0.123443603515625 0.349761962890625 0.6470092773437545 +1.04725 0.122100830078125 0.34600830078125 0.6470092773437545 +1.047375 0.120758056640625 0.34222412109375 0.6470092773437545 +1.0475 0.120758056640625 0.34222412109375 0.6470092773437545 +1.047625 0.119415283203125 0.33837890625 0.6470092773437545 +1.04775 0.119415283203125 0.33837890625 0.6470092773437545 +1.0478750000000002 0.1180419921875 0.334503173828125 0.6470092773437545 +1.048 0.116668701171875 0.330596923828125 0.6470092773437545 +1.048125 0.116668701171875 0.330596923828125 0.6470092773437545 +1.0482500000000002 0.115264892578125 0.32666015625 0.6470092773437545 +1.048375 0.115264892578125 0.32666015625 0.6470092773437545 +1.0485 0.113861083984375 0.322662353515625 0.6470092773437545 +1.048625 0.112457275390625 0.31866455078125 0.6470092773437545 +1.04875 0.112457275390625 0.31866455078125 0.6470092773437545 +1.048875 0.11102294921875 0.314605712890625 0.6470092773437545 +1.049 0.11102294921875 0.314605712890625 0.6470092773437545 +1.049125 0.109588623046875 0.310516357421875 0.6470092773437545 +1.04925 0.108123779296875 0.306396484375 0.6470092773437545 +1.049375 0.108123779296875 0.306396484375 0.6470092773437545 +1.0495 0.106658935546875 0.30224609375 0.6470092773437545 +1.049625 0.106658935546875 0.30224609375 0.6470092773437545 +1.04975 0.105194091796875 0.298065185546875 0.6470092773437545 +1.0498750000000002 0.10369873046875 0.2938232421875 0.6470092773437545 +1.05 0.10369873046875 0.2938232421875 0.6470092773437545 +1.050125 0.102203369140625 0.289581298828125 0.6470092773437545 +1.0502500000000002 0.102203369140625 0.289581298828125 0.6470092773437545 +1.050375 0.100677490234375 0.285308837890625 0.6470092773437545 +1.0505 0.099151611328125 0.280975341796875 0.6470092773437545 +1.050625 0.099151611328125 0.280975341796875 0.6470092773437545 +1.05075 0.097625732421875 0.276641845703125 0.6470092773437545 +1.050875 0.097625732421875 0.276641845703125 0.6470092773437545 +1.051 0.0960693359375 0.27227783203125 0.6470092773437545 +1.051125 0.094512939453125 0.267852783203125 0.6470092773437545 +1.05125 0.094512939453125 0.267852783203125 0.6470092773437545 +1.051375 0.09295654296875 0.263427734375 0.6470092773437545 +1.0515 0.09295654296875 0.263427734375 0.6470092773437545 +1.051625 0.091400146484375 0.25897216796875 0.6470092773437545 +1.05175 0.089813232421875 0.25445556640625 0.6470092773437545 +1.0518750000000002 0.089813232421875 0.25445556640625 0.6470092773437545 +1.052 0.08819580078125 0.249969482421875 0.6470092773437545 +1.052125 0.08819580078125 0.249969482421875 0.6470092773437545 +1.0522500000000002 0.08660888671875 0.24542236328125 0.6470092773437545 +1.052375 0.084991455078125 0.2408447265625 0.6470092773437545 +1.0525 0.084991455078125 0.2408447265625 0.6470092773437545 +1.052625 0.0833740234375 0.236236572265625 0.6470092773437545 +1.05275 0.0833740234375 0.236236572265625 0.6470092773437545 +1.052875 0.08172607421875 0.231597900390625 0.6470092773437545 +1.053 0.080078125 0.226959228515625 0.6470092773437545 +1.053125 0.080078125 0.226959228515625 0.6470092773437545 +1.05325 0.07843017578125 0.2222900390625 0.6470092773437545 +1.053375 0.07843017578125 0.2222900390625 0.6470092773437545 +1.0535 0.0767822265625 0.21759033203125 0.6470092773437545 +1.053625 0.075103759765625 0.212860107421875 0.6470092773437545 +1.05375 0.075103759765625 0.212860107421875 0.6470092773437545 +1.0538750000000002 0.07342529296875 0.208099365234375 0.6470092773437545 +1.054 0.07342529296875 0.208099365234375 0.6470092773437545 +1.054125 0.071746826171875 0.203338623046875 0.6470092773437545 +1.0542500000000002 0.070068359375 0.19854736328125 0.6470092773437545 +1.054375 0.070068359375 0.19854736328125 0.6470092773437545 +1.0545 0.068359375 0.1937255859375 0.6470092773437545 +1.054625 0.068359375 0.1937255859375 0.6470092773437545 +1.05475 0.066650390625 0.188873291015625 0.6470092773437545 +1.054875 0.06494140625 0.18402099609375 0.6470092773437545 +1.055 0.06494140625 0.18402099609375 0.6470092773437545 +1.055125 0.063201904296875 0.17913818359375 0.6470092773437545 +1.05525 0.063201904296875 0.17913818359375 0.6470092773437545 +1.055375 0.061492919921875 0.17425537109375 0.6470092773437545 +1.0555 0.05975341796875 0.169342041015625 0.6470092773437545 +1.055625 0.05975341796875 0.169342041015625 0.6470092773437545 +1.05575 0.058013916015625 0.164398193359375 0.6470092773437545 +1.0558750000000002 0.058013916015625 0.164398193359375 0.6470092773437545 +1.056 0.01690673828125 0.159454345703125 0.8937805175781277 +1.056125 0.016387939453125 0.15447998046875 0.8937805175781277 +1.05625 0.016387939453125 0.15447998046875 0.8937805175781277 +1.056375 0.015838623046875 0.14947509765625 0.8937805175781277 +1.0565 0.015838623046875 0.14947509765625 0.8937805175781277 +1.056625 0.01531982421875 0.14447021484375 0.8937805175781277 +1.05675 0.014801025390625 0.13946533203125 0.8937805175781277 +1.056875 0.014801025390625 0.13946533203125 0.8937805175781277 +1.057 0.014251708984375 0.134429931640625 0.8937805175781277 +1.057125 0.014251708984375 0.134429931640625 0.8937805175781277 +1.05725 0.01373291015625 0.129364013671875 0.8937805175781277 +1.057375 0.01318359375 0.124298095703125 0.8937805175781277 +1.0575 0.01318359375 0.124298095703125 0.8937805175781277 +1.057625 0.01263427734375 0.119232177734375 0.8937805175781277 +1.05775 0.01263427734375 0.119232177734375 0.8937805175781277 +1.0578750000000002 0.012115478515625 0.1141357421875 0.8937805175781277 +1.058 0.011566162109375 0.109039306640625 0.8937805175781277 +1.058125 0.011566162109375 0.109039306640625 0.8937805175781277 +1.05825 0.011016845703125 0.103912353515625 0.8937805175781277 +1.058375 0.011016845703125 0.103912353515625 0.8937805175781277 +1.0585 0.010467529296875 0.098785400390625 0.8937805175781277 +1.058625 0.009918212890625 0.093658447265625 0.8937805175781277 +1.05875 0.009918212890625 0.093658447265625 0.8937805175781277 +1.058875 0.009368896484375 0.0885009765625 0.8937805175781277 +1.059 0.009368896484375 0.0885009765625 0.8937805175781277 +1.059125 0.008819580078125 0.083343505859375 0.8937805175781277 +1.05925 0.008270263671875 0.07818603515625 0.8937805175781277 +1.059375 0.008270263671875 0.07818603515625 0.8937805175781277 +1.0595 0.007720947265625 0.072998046875 0.8937805175781277 +1.059625 0.007720947265625 0.072998046875 0.8937805175781277 +1.05975 0.007171630859375 0.06781005859375 0.8937805175781277 +1.0598750000000002 0.006622314453125 0.0626220703125 0.8937805175781277 +1.06 0.006622314453125 0.0626220703125 0.8937805175781277 +1.060125 0.006072998046875 0.05743408203125 0.8937805175781277 +1.06025 0.006072998046875 0.05743408203125 0.8937805175781277 +1.060375 0.005523681640625 0.05224609375 0.8937805175781277 +1.0605 0.004974365234375 0.047027587890625 0.8937805175781277 +1.060625 0.004974365234375 0.047027587890625 0.8937805175781277 +1.06075 0.004425048828125 0.04180908203125 0.8937805175781277 +1.060875 0.004425048828125 0.04180908203125 0.8937805175781277 +1.061 0.003875732421875 0.036590576171875 0.8937805175781277 +1.061125 0.003326416015625 0.0313720703125 0.8937805175781277 +1.06125 0.003326416015625 0.0313720703125 0.8937805175781277 +1.061375 0.00274658203125 0.026123046875 0.8937805175781277 +1.0615 0.00274658203125 0.026123046875 0.8937805175781277 +1.061625 0.002197265625 0.020904541015625 0.8937805175781277 +1.06175 0.00164794921875 0.01568603515625 0.8937805175781277 +1.0618750000000002 0.00164794921875 0.01568603515625 0.8937805175781277 +1.062 0.0010986328125 0.01043701171875 0.8937805175781277 +1.062125 0.0010986328125 0.01043701171875 0.8937805175781277 +1.06225 0.00054931640625 0.005218505859375 0.8937805175781277 +1.062375 0.0 0.0 0.8937805175781277 +1.0625 0.0 0.0 0.8937805175781277 +1.062625 -0.00054931640625 -0.005218505859375 0.8937805175781277 +1.06275 -0.00054931640625 -0.005218505859375 0.8937805175781277 +1.062875 -0.0010986328125 -0.01043701171875 0.8937805175781277 +1.063 -0.00164794921875 -0.01568603515625 0.8937805175781277 +1.063125 -0.00164794921875 -0.01568603515625 0.8937805175781277 +1.06325 -0.002197265625 -0.020904541015625 0.8937805175781277 +1.063375 -0.002197265625 -0.020904541015625 0.8937805175781277 +1.0635000000000002 -0.00274658203125 -0.026123046875 0.8937805175781277 +1.063625 -0.003326416015625 -0.0313720703125 0.8937805175781277 +1.06375 -0.003326416015625 -0.0313720703125 0.8937805175781277 +1.0638750000000002 -0.003875732421875 -0.036590576171875 0.8937805175781277 +1.064 -0.003875732421875 -0.036590576171875 0.8937805175781277 +1.064125 -0.004425048828125 -0.04180908203125 0.8937805175781277 +1.06425 -0.004974365234375 -0.047027587890625 0.8937805175781277 +1.064375 -0.004974365234375 -0.047027587890625 0.8937805175781277 +1.0645 -0.005523681640625 -0.05224609375 0.8937805175781277 +1.064625 -0.005523681640625 -0.05224609375 0.8937805175781277 +1.06475 -0.006072998046875 -0.05743408203125 0.8937805175781277 +1.064875 -0.006622314453125 -0.0626220703125 0.8937805175781277 +1.065 -0.006622314453125 -0.0626220703125 0.8937805175781277 +1.065125 -0.007171630859375 -0.06781005859375 0.8937805175781277 +1.06525 -0.007171630859375 -0.06781005859375 0.8937805175781277 +1.065375 -0.007720947265625 -0.072998046875 0.8937805175781277 +1.0655000000000002 -0.008270263671875 -0.07818603515625 0.8937805175781277 +1.065625 -0.008270263671875 -0.07818603515625 0.8937805175781277 +1.06575 -0.008819580078125 -0.083343505859375 0.8937805175781277 +1.0658750000000002 -0.008819580078125 -0.083343505859375 0.8937805175781277 +1.066 -0.009368896484375 -0.0885009765625 0.8937805175781277 +1.066125 -0.009918212890625 -0.093658447265625 0.8937805175781277 +1.06625 -0.009918212890625 -0.093658447265625 0.8937805175781277 +1.066375 -0.010467529296875 -0.098785400390625 0.8937805175781277 +1.0665 -0.010467529296875 -0.098785400390625 0.8937805175781277 +1.066625 -0.011016845703125 -0.103912353515625 0.8937805175781277 +1.06675 -0.011566162109375 -0.109039306640625 0.8937805175781277 +1.066875 -0.011566162109375 -0.109039306640625 0.8937805175781277 +1.067 -0.012115478515625 -0.1141357421875 0.8937805175781277 +1.067125 -0.012115478515625 -0.1141357421875 0.8937805175781277 +1.06725 -0.01263427734375 -0.119232177734375 0.8937805175781277 +1.067375 -0.01318359375 -0.124298095703125 0.8937805175781277 +1.0675000000000002 -0.01318359375 -0.124298095703125 0.8937805175781277 +1.067625 -0.01373291015625 -0.129364013671875 0.8937805175781277 +1.06775 -0.01373291015625 -0.129364013671875 0.8937805175781277 +1.0678750000000002 -0.014251708984375 -0.134429931640625 0.8937805175781277 +1.068 -0.014801025390625 -0.13946533203125 0.8937805175781277 +1.068125 -0.014801025390625 -0.13946533203125 0.8937805175781277 +1.06825 -0.01531982421875 -0.14447021484375 0.8937805175781277 +1.068375 -0.01531982421875 -0.14447021484375 0.8937805175781277 +1.0685 -0.015838623046875 -0.14947509765625 0.8937805175781277 +1.068625 -0.016387939453125 -0.15447998046875 0.8937805175781277 +1.06875 -0.016387939453125 -0.15447998046875 0.8937805175781277 +1.068875 -0.01690673828125 -0.159454345703125 0.8937805175781277 +1.069 -0.01690673828125 -0.159454345703125 0.8937805175781277 +1.069125 -0.017425537109375 -0.164398193359375 0.8937805175781277 +1.06925 -0.017974853515625 -0.169342041015625 0.8937805175781277 +1.069375 -0.017974853515625 -0.169342041015625 0.8937805175781277 +1.0695000000000002 -0.01849365234375 -0.17425537109375 0.8937805175781277 +1.069625 -0.01849365234375 -0.17425537109375 0.8937805175781277 +1.06975 -0.019012451171875 -0.17913818359375 0.8937805175781277 +1.0698750000000002 -0.01953125 -0.18402099609375 0.8937805175781277 +1.07 -0.01953125 -0.18402099609375 0.8937805175781277 +1.070125 -0.020050048828125 -0.188873291015625 0.8937805175781277 +1.07025 -0.020050048828125 -0.188873291015625 0.8937805175781277 +1.070375 -0.020538330078125 -0.1937255859375 0.8937805175781277 +1.0705 -0.02105712890625 -0.19854736328125 0.8937805175781277 +1.070625 -0.02105712890625 -0.19854736328125 0.8937805175781277 +1.07075 -0.021575927734375 -0.203338623046875 0.8937805175781277 +1.070875 -0.021575927734375 -0.203338623046875 0.8937805175781277 +1.071 -0.022064208984375 -0.208099365234375 0.8937805175781277 +1.071125 -0.0225830078125 -0.212860107421875 0.8937805175781277 +1.07125 -0.0225830078125 -0.212860107421875 0.8937805175781277 +1.071375 -0.0230712890625 -0.21759033203125 0.8937805175781277 +1.0715000000000002 -0.0230712890625 -0.21759033203125 0.8937805175781277 +1.071625 -0.023590087890625 -0.2222900390625 0.8937805175781277 +1.07175 -0.024078369140625 -0.226959228515625 0.8937805175781277 +1.0718750000000002 -0.024078369140625 -0.226959228515625 0.8937805175781277 +1.072 -0.024566650390625 -0.231597900390625 0.8937805175781277 +1.072125 -0.024566650390625 -0.231597900390625 0.8937805175781277 +1.07225 -0.025054931640625 -0.236236572265625 0.8937805175781277 +1.072375 -0.025543212890625 -0.2408447265625 0.8937805175781277 +1.0725 -0.025543212890625 -0.2408447265625 0.8937805175781277 +1.072625 -0.026031494140625 -0.24542236328125 0.8937805175781277 +1.07275 -0.026031494140625 -0.24542236328125 0.8937805175781277 +1.072875 -0.026519775390625 -0.249969482421875 0.8937805175781277 +1.073 -0.027008056640625 -0.25445556640625 0.8937805175781277 +1.073125 -0.027008056640625 -0.25445556640625 0.8937805175781277 +1.07325 -0.0274658203125 -0.25897216796875 0.8937805175781277 +1.073375 -0.0274658203125 -0.25897216796875 0.8937805175781277 +1.0735000000000002 -0.0279541015625 -0.263427734375 0.8937805175781277 +1.073625 -0.028411865234375 -0.267852783203125 0.8937805175781277 +1.07375 -0.028411865234375 -0.267852783203125 0.8937805175781277 +1.073875 -0.028900146484375 -0.27227783203125 0.8937805175781277 +1.074 -0.028900146484375 -0.27227783203125 0.8937805175781277 +1.074125 -0.02935791015625 -0.276641845703125 0.8937805175781277 +1.07425 -0.029815673828125 -0.280975341796875 0.8937805175781277 +1.074375 -0.029815673828125 -0.280975341796875 0.8937805175781277 +1.0745 -0.0302734375 -0.285308837890625 0.8937805175781277 +1.074625 -0.0302734375 -0.285308837890625 0.8937805175781277 +1.07475 -0.030731201171875 -0.289581298828125 0.8937805175781277 +1.074875 -0.03118896484375 -0.2938232421875 0.8937805175781277 +1.075 -0.03118896484375 -0.2938232421875 0.8937805175781277 +1.075125 -0.0316162109375 -0.298065185546875 0.8937805175781277 +1.07525 -0.0316162109375 -0.298065185546875 0.8937805175781277 +1.075375 -0.032073974609375 -0.30224609375 0.8937805175781277 +1.0755000000000002 -0.032501220703125 -0.306396484375 0.8937805175781277 +1.075625 -0.032501220703125 -0.306396484375 0.8937805175781277 +1.07575 -0.032958984375 -0.310516357421875 0.8937805175781277 +1.075875 -0.032958984375 -0.310516357421875 0.8937805175781277 +1.076 -0.03338623046875 -0.314605712890625 0.8937805175781277 +1.076125 -0.0338134765625 -0.31866455078125 0.8937805175781277 +1.07625 -0.0338134765625 -0.31866455078125 0.8937805175781277 +1.076375 -0.03424072265625 -0.322662353515625 0.8937805175781277 +1.0765 -0.03424072265625 -0.322662353515625 0.8937805175781277 +1.076625 -0.03466796875 -0.32666015625 0.8937805175781277 +1.07675 -0.035064697265625 -0.330596923828125 0.8937805175781277 +1.076875 -0.035064697265625 -0.330596923828125 0.8937805175781277 +1.077 -0.035491943359375 -0.334503173828125 0.8937805175781277 +1.077125 -0.035491943359375 -0.334503173828125 0.8937805175781277 +1.07725 -0.035919189453125 -0.33837890625 0.8937805175781277 +1.077375 -0.03631591796875 -0.34222412109375 0.8937805175781277 +1.0775000000000002 -0.03631591796875 -0.34222412109375 0.8937805175781277 +1.077625 -0.036712646484375 -0.34600830078125 0.8937805175781277 +1.07775 -0.036712646484375 -0.34600830078125 0.8937805175781277 +1.077875 -0.037109375 -0.349761962890625 0.8937805175781277 +1.078 -0.037506103515625 -0.353485107421875 0.8937805175781277 +1.078125 -0.037506103515625 -0.353485107421875 0.8937805175781277 +1.07825 -0.03790283203125 -0.357177734375 0.8937805175781277 +1.078375 -0.03790283203125 -0.357177734375 0.8937805175781277 +1.0785 -0.038299560546875 -0.360809326171875 0.8937805175781277 +1.078625 -0.038665771484375 -0.36444091796875 0.8937805175781277 +1.07875 -0.038665771484375 -0.36444091796875 0.8937805175781277 +1.078875 -0.039031982421875 -0.36798095703125 0.8937805175781277 +1.079 -0.039031982421875 -0.36798095703125 0.8937805175781277 +1.0791250000000002 -0.0394287109375 -0.37152099609375 0.8937805175781277 +1.07925 -0.039794921875 -0.375 0.8937805175781277 +1.079375 -0.039794921875 -0.375 0.8937805175781277 +1.0795000000000002 -0.0401611328125 -0.378448486328125 0.8937805175781277 +1.079625 -0.0401611328125 -0.378448486328125 0.8937805175781277 +1.07975 -0.04052734375 -0.3818359375 0.8937805175781277 +1.079875 -0.040863037109375 -0.38519287109375 0.8937805175781277 +1.08 -0.040863037109375 -0.38519287109375 0.8937805175781277 +1.080125 -0.041229248046875 -0.388519287109375 0.8937805175781277 +1.08025 -0.041229248046875 -0.388519287109375 0.8937805175781277 +1.080375 -0.04156494140625 -0.39178466796875 0.8937805175781277 +1.0805 -0.04193115234375 -0.39501953125 0.8937805175781277 +1.080625 -0.04193115234375 -0.39501953125 0.8937805175781277 +1.08075 -0.042266845703125 -0.398193359375 0.8937805175781277 +1.080875 -0.042266845703125 -0.398193359375 0.8937805175781277 +1.081 -0.0426025390625 -0.401336669921875 0.8937805175781277 +1.0811250000000002 -0.04290771484375 -0.404449462890625 0.8937805175781277 +1.08125 -0.04290771484375 -0.404449462890625 0.8937805175781277 +1.081375 -0.043243408203125 -0.407501220703125 0.8937805175781277 +1.0815000000000002 -0.043243408203125 -0.407501220703125 0.8937805175781277 +1.081625 -0.043548583984375 -0.4105224609375 0.8937805175781277 +1.08175 -0.04388427734375 -0.413482666015625 0.8937805175781277 +1.081875 -0.04388427734375 -0.413482666015625 0.8937805175781277 +1.082 -0.044189453125 -0.416412353515625 0.8937805175781277 +1.082125 -0.044189453125 -0.416412353515625 0.8937805175781277 +1.08225 -0.04449462890625 -0.419281005859375 0.8937805175781277 +1.082375 -0.0447998046875 -0.422119140625 0.8937805175781277 +1.0825 -0.0447998046875 -0.422119140625 0.8937805175781277 +1.082625 -0.045074462890625 -0.424896240234375 0.8937805175781277 +1.08275 -0.045074462890625 -0.424896240234375 0.8937805175781277 +1.082875 -0.045379638671875 -0.4276123046875 0.8937805175781277 +1.083 -0.045654296875 -0.4302978515625 0.8937805175781277 +1.0831250000000002 -0.045654296875 -0.4302978515625 0.8937805175781277 +1.08325 -0.045928955078125 -0.432952880859375 0.8937805175781277 +1.083375 -0.045928955078125 -0.432952880859375 0.8937805175781277 +1.0835000000000002 -0.04620361328125 -0.435546875 0.8937805175781277 +1.083625 -0.046478271484375 -0.438079833984375 0.8937805175781277 +1.08375 -0.046478271484375 -0.438079833984375 0.8937805175781277 +1.083875 -0.0467529296875 -0.440582275390625 0.8937805175781277 +1.084 -0.0467529296875 -0.440582275390625 0.8937805175781277 +1.084125 -0.047027587890625 -0.44305419921875 0.8937805175781277 +1.08425 -0.047271728515625 -0.4454345703125 0.8937805175781277 +1.084375 -0.047271728515625 -0.4454345703125 0.8937805175781277 +1.0845 -0.047515869140625 -0.447784423828125 0.8937805175781277 +1.084625 -0.047515869140625 -0.447784423828125 0.8937805175781277 +1.08475 -0.047760009765625 -0.450103759765625 0.8937805175781277 +1.084875 -0.048004150390625 -0.452362060546875 0.8937805175781277 +1.085 -0.048004150390625 -0.452362060546875 0.8937805175781277 +1.0851250000000002 -0.048248291015625 -0.454559326171875 0.8937805175781277 +1.08525 -0.048248291015625 -0.454559326171875 0.8937805175781277 +1.085375 -0.0484619140625 -0.45672607421875 0.8937805175781277 +1.0855000000000002 -0.048675537109375 -0.458831787109375 0.8937805175781277 +1.085625 -0.048675537109375 -0.458831787109375 0.8937805175781277 +1.08575 -0.048919677734375 -0.46087646484375 0.8937805175781277 +1.085875 -0.048919677734375 -0.46087646484375 0.8937805175781277 +1.086 -0.04913330078125 -0.462890625 0.8937805175781277 +1.086125 -0.04931640625 -0.464813232421875 0.8937805175781277 +1.08625 -0.04931640625 -0.464813232421875 0.8937805175781277 +1.086375 -0.049530029296875 -0.46673583984375 0.8937805175781277 +1.0865 -0.049530029296875 -0.46673583984375 0.8937805175781277 +1.086625 -0.049713134765625 -0.46856689453125 0.8937805175781277 +1.08675 -0.0499267578125 -0.470367431640625 0.8937805175781277 +1.086875 -0.0499267578125 -0.470367431640625 0.8937805175781277 +1.087 -0.05010986328125 -0.472137451171875 0.8937805175781277 +1.0871250000000002 -0.05010986328125 -0.472137451171875 0.8937805175781277 +1.08725 -0.05029296875 -0.47381591796875 0.8937805175781277 +1.087375 -0.050445556640625 -0.4754638671875 0.8937805175781277 +1.0875000000000002 -0.050445556640625 -0.4754638671875 0.8937805175781277 +1.087625 -0.050628662109375 -0.47705078125 0.8937805175781277 +1.08775 -0.050628662109375 -0.47705078125 0.8937805175781277 +1.087875 -0.05078125 -0.478607177734375 0.8937805175781277 +1.088 -0.00091552734375 -0.480072021484375 0.9979858398437503488 +1.088125 -0.00091552734375 -0.480072021484375 0.9979858398437503488 +1.08825 -0.00091552734375 -0.48150634765625 0.9979858398437503488 +1.088375 -0.00091552734375 -0.48150634765625 0.9979858398437503488 +1.0885 -0.00091552734375 -0.48291015625 0.9979858398437503488 +1.088625 -0.00091552734375 -0.484222412109375 0.9979858398437503488 +1.08875 -0.00091552734375 -0.484222412109375 0.9979858398437503488 +1.088875 -0.00091552734375 -0.485504150390625 0.9979858398437503488 +1.089 -0.00091552734375 -0.485504150390625 0.9979858398437503488 +1.0891250000000002 -0.00091552734375 -0.486724853515625 0.9979858398437503488 +1.08925 -0.00091552734375 -0.487884521484375 0.9979858398437503488 +1.089375 -0.00091552734375 -0.487884521484375 0.9979858398437503488 +1.0895 -0.00091552734375 -0.489013671875 0.9979858398437503488 +1.089625 -0.00091552734375 -0.489013671875 0.9979858398437503488 +1.08975 -0.00091552734375 -0.490081787109375 0.9979858398437503488 +1.089875 -0.00091552734375 -0.4910888671875 0.9979858398437503488 +1.09 -0.00091552734375 -0.4910888671875 0.9979858398437503488 +1.090125 -0.000946044921875 -0.492034912109375 0.9979858398437503488 +1.09025 -0.000946044921875 -0.492034912109375 0.9979858398437503488 +1.090375 -0.000946044921875 -0.492950439453125 0.9979858398437503488 +1.0905 -0.000946044921875 -0.4937744140625 0.9979858398437503488 +1.090625 -0.000946044921875 -0.4937744140625 0.9979858398437503488 +1.09075 -0.000946044921875 -0.49456787109375 0.9979858398437503488 +1.090875 -0.000946044921875 -0.49456787109375 0.9979858398437503488 +1.091 -0.000946044921875 -0.49530029296875 0.9979858398437503488 +1.0911250000000002 -0.000946044921875 -0.496002197265625 0.9979858398437503488 +1.09125 -0.000946044921875 -0.496002197265625 0.9979858398437503488 +1.091375 -0.000946044921875 -0.496612548828125 0.9979858398437503488 +1.0915 -0.000946044921875 -0.496612548828125 0.9979858398437503488 +1.091625 -0.000946044921875 -0.4971923828125 0.9979858398437503488 +1.09175 -0.000946044921875 -0.497711181640625 0.9979858398437503488 +1.091875 -0.000946044921875 -0.497711181640625 0.9979858398437503488 +1.092 -0.000946044921875 -0.498199462890625 0.9979858398437503488 +1.092125 -0.000946044921875 -0.498199462890625 0.9979858398437503488 +1.09225 -0.000946044921875 -0.49859619140625 0.9979858398437503488 +1.092375 -0.000946044921875 -0.49896240234375 0.9979858398437503488 +1.0925 -0.000946044921875 -0.49896240234375 0.9979858398437503488 +1.092625 -0.000946044921875 -0.499267578125 0.9979858398437503488 +1.09275 -0.000946044921875 -0.499267578125 0.9979858398437503488 +1.092875 -0.000946044921875 -0.49951171875 0.9979858398437503488 +1.093 -0.000946044921875 -0.49969482421875 0.9979858398437503488 +1.0931250000000002 -0.000946044921875 -0.49969482421875 0.9979858398437503488 +1.09325 -0.000946044921875 -0.49981689453125 0.9979858398437503488 +1.093375 -0.000946044921875 -0.49981689453125 0.9979858398437503488 +1.0935 -0.000946044921875 -0.499908447265625 0.9979858398437503488 +1.093625 -0.000946044921875 -0.49993896484375 0.9979858398437503488 +1.09375 -0.000946044921875 -0.49993896484375 0.9979858398437503488 +1.093875 -0.000946044921875 -0.499908447265625 0.9979858398437503488 +1.094 -0.000946044921875 -0.499908447265625 0.9979858398437503488 +1.094125 -0.000946044921875 -0.49981689453125 0.9979858398437503488 +1.09425 -0.000946044921875 -0.49969482421875 0.9979858398437503488 +1.094375 -0.000946044921875 -0.49969482421875 0.9979858398437503488 +1.0945 -0.000946044921875 -0.49951171875 0.9979858398437503488 +1.094625 -0.000946044921875 -0.49951171875 0.9979858398437503488 +1.0947500000000002 -0.000946044921875 -0.499267578125 0.9979858398437503488 +1.094875 -0.000946044921875 -0.49896240234375 0.9979858398437503488 +1.095 -0.000946044921875 -0.49896240234375 0.9979858398437503488 +1.0951250000000002 -0.000946044921875 -0.49859619140625 0.9979858398437503488 +1.09525 -0.000946044921875 -0.49859619140625 0.9979858398437503488 +1.095375 -0.000946044921875 -0.498199462890625 0.9979858398437503488 +1.0955 -0.000946044921875 -0.497711181640625 0.9979858398437503488 +1.095625 -0.000946044921875 -0.497711181640625 0.9979858398437503488 +1.09575 -0.000946044921875 -0.4971923828125 0.9979858398437503488 +1.095875 -0.000946044921875 -0.4971923828125 0.9979858398437503488 +1.096 -0.000946044921875 -0.496612548828125 0.9979858398437503488 +1.096125 -0.000946044921875 -0.496002197265625 0.9979858398437503488 +1.09625 -0.000946044921875 -0.496002197265625 0.9979858398437503488 +1.096375 -0.000946044921875 -0.49530029296875 0.9979858398437503488 +1.0965 -0.000946044921875 -0.49530029296875 0.9979858398437503488 +1.096625 -0.000946044921875 -0.49456787109375 0.9979858398437503488 +1.0967500000000002 -0.000946044921875 -0.4937744140625 0.9979858398437503488 +1.096875 -0.000946044921875 -0.4937744140625 0.9979858398437503488 +1.097 -0.000946044921875 -0.492950439453125 0.9979858398437503488 +1.0971250000000002 -0.000946044921875 -0.492950439453125 0.9979858398437503488 +1.09725 -0.000946044921875 -0.492034912109375 0.9979858398437503488 +1.097375 -0.00091552734375 -0.4910888671875 0.9979858398437503488 +1.0975 -0.00091552734375 -0.4910888671875 0.9979858398437503488 +1.097625 -0.00091552734375 -0.490081787109375 0.9979858398437503488 +1.09775 -0.00091552734375 -0.490081787109375 0.9979858398437503488 +1.097875 -0.00091552734375 -0.489013671875 0.9979858398437503488 +1.098 -0.00091552734375 -0.487884521484375 0.9979858398437503488 +1.098125 -0.00091552734375 -0.487884521484375 0.9979858398437503488 +1.09825 -0.00091552734375 -0.486724853515625 0.9979858398437503488 +1.098375 -0.00091552734375 -0.486724853515625 0.9979858398437503488 +1.0985 -0.00091552734375 -0.485504150390625 0.9979858398437503488 +1.098625 -0.00091552734375 -0.484222412109375 0.9979858398437503488 +1.0987500000000002 -0.00091552734375 -0.484222412109375 0.9979858398437503488 +1.098875 -0.00091552734375 -0.48291015625 0.9979858398437503488 +1.099 -0.00091552734375 -0.48291015625 0.9979858398437503488 +1.0991250000000002 -0.00091552734375 -0.48150634765625 0.9979858398437503488 +1.09925 -0.00091552734375 -0.480072021484375 0.9979858398437503488 +1.099375 -0.00091552734375 -0.480072021484375 0.9979858398437503488 +1.0995 -0.00091552734375 -0.478607177734375 0.9979858398437503488 +1.099625 -0.00091552734375 -0.478607177734375 0.9979858398437503488 +1.09975 -0.00091552734375 -0.47705078125 0.9979858398437503488 +1.099875 -0.000885009765625 -0.4754638671875 0.9979858398437503488 +1.1 -0.000885009765625 -0.4754638671875 0.9979858398437503488 +1.100125 -0.000885009765625 -0.47381591796875 0.9979858398437503488 +1.10025 -0.000885009765625 -0.47381591796875 0.9979858398437503488 +1.100375 -0.000885009765625 -0.472137451171875 0.9979858398437503488 +1.1005 -0.000885009765625 -0.470367431640625 0.9979858398437503488 +1.100625 -0.000885009765625 -0.470367431640625 0.9979858398437503488 +1.1007500000000002 -0.000885009765625 -0.46856689453125 0.9979858398437503488 +1.100875 -0.000885009765625 -0.46856689453125 0.9979858398437503488 +1.101 -0.000885009765625 -0.46673583984375 0.9979858398437503488 +1.1011250000000002 -0.000885009765625 -0.464813232421875 0.9979858398437503488 +1.10125 -0.000885009765625 -0.464813232421875 0.9979858398437503488 +1.101375 -0.000885009765625 -0.462890625 0.9979858398437503488 +1.1015 -0.000885009765625 -0.462890625 0.9979858398437503488 +1.101625 -0.000885009765625 -0.46087646484375 0.9979858398437503488 +1.10175 -0.0008544921875 -0.458831787109375 0.9979858398437503488 +1.101875 -0.0008544921875 -0.458831787109375 0.9979858398437503488 +1.102 -0.0008544921875 -0.45672607421875 0.9979858398437503488 +1.102125 -0.0008544921875 -0.45672607421875 0.9979858398437503488 +1.10225 -0.0008544921875 -0.454559326171875 0.9979858398437503488 +1.102375 -0.0008544921875 -0.452362060546875 0.9979858398437503488 +1.1025 -0.0008544921875 -0.452362060546875 0.9979858398437503488 +1.102625 -0.0008544921875 -0.450103759765625 0.9979858398437503488 +1.1027500000000002 -0.0008544921875 -0.450103759765625 0.9979858398437503488 +1.102875 -0.0008544921875 -0.447784423828125 0.9979858398437503488 +1.103 -0.0008544921875 -0.4454345703125 0.9979858398437503488 +1.1031250000000002 -0.0008544921875 -0.4454345703125 0.9979858398437503488 +1.10325 -0.000823974609375 -0.44305419921875 0.9979858398437503488 +1.103375 -0.000823974609375 -0.44305419921875 0.9979858398437503488 +1.1035 -0.000823974609375 -0.440582275390625 0.9979858398437503488 +1.103625 -0.000823974609375 -0.438079833984375 0.9979858398437503488 +1.10375 -0.000823974609375 -0.438079833984375 0.9979858398437503488 +1.103875 -0.000823974609375 -0.435546875 0.9979858398437503488 +1.104 -0.000823974609375 -0.435546875 0.9979858398437503488 +1.104125 -0.000823974609375 -0.432952880859375 0.9979858398437503488 +1.10425 -0.000823974609375 -0.4302978515625 0.9979858398437503488 +1.104375 -0.000823974609375 -0.4302978515625 0.9979858398437503488 +1.1045 -0.00079345703125 -0.4276123046875 0.9979858398437503488 +1.104625 -0.00079345703125 -0.4276123046875 0.9979858398437503488 +1.1047500000000002 -0.00079345703125 -0.424896240234375 0.9979858398437503488 +1.104875 -0.00079345703125 -0.422119140625 0.9979858398437503488 +1.105 -0.00079345703125 -0.422119140625 0.9979858398437503488 +1.105125 -0.00079345703125 -0.419281005859375 0.9979858398437503488 +1.10525 -0.00079345703125 -0.419281005859375 0.9979858398437503488 +1.105375 -0.00079345703125 -0.416412353515625 0.9979858398437503488 +1.1055 -0.00079345703125 -0.413482666015625 0.9979858398437503488 +1.105625 -0.00079345703125 -0.413482666015625 0.9979858398437503488 +1.10575 -0.000762939453125 -0.4105224609375 0.9979858398437503488 +1.105875 -0.000762939453125 -0.4105224609375 0.9979858398437503488 +1.106 -0.000762939453125 -0.407501220703125 0.9979858398437503488 +1.106125 -0.000762939453125 -0.404449462890625 0.9979858398437503488 +1.10625 -0.000762939453125 -0.404449462890625 0.9979858398437503488 +1.106375 -0.000762939453125 -0.401336669921875 0.9979858398437503488 +1.1065 -0.000762939453125 -0.401336669921875 0.9979858398437503488 +1.106625 -0.000762939453125 -0.398193359375 0.9979858398437503488 +1.1067500000000002 -0.000732421875 -0.39501953125 0.9979858398437503488 +1.106875 -0.000732421875 -0.39501953125 0.9979858398437503488 +1.107 -0.000732421875 -0.39178466796875 0.9979858398437503488 +1.107125 -0.000732421875 -0.39178466796875 0.9979858398437503488 +1.10725 -0.000732421875 -0.388519287109375 0.9979858398437503488 +1.107375 -0.000732421875 -0.38519287109375 0.9979858398437503488 +1.1075 -0.000732421875 -0.38519287109375 0.9979858398437503488 +1.107625 -0.000732421875 -0.3818359375 0.9979858398437503488 +1.10775 -0.000732421875 -0.3818359375 0.9979858398437503488 +1.107875 -0.000701904296875 -0.378448486328125 0.9979858398437503488 +1.108 -0.000701904296875 -0.375 0.9979858398437503488 +1.108125 -0.000701904296875 -0.375 0.9979858398437503488 +1.10825 -0.000701904296875 -0.37152099609375 0.9979858398437503488 +1.108375 -0.000701904296875 -0.37152099609375 0.9979858398437503488 +1.1085 -0.000701904296875 -0.36798095703125 0.9979858398437503488 +1.108625 -0.00067138671875 -0.36444091796875 0.9979858398437503488 +1.1087500000000002 -0.00067138671875 -0.36444091796875 0.9979858398437503488 +1.108875 -0.00067138671875 -0.360809326171875 0.9979858398437503488 +1.109 -0.00067138671875 -0.360809326171875 0.9979858398437503488 +1.109125 -0.00067138671875 -0.357177734375 0.9979858398437503488 +1.10925 -0.00067138671875 -0.353485107421875 0.9979858398437503488 +1.109375 -0.00067138671875 -0.353485107421875 0.9979858398437503488 +1.1095 -0.00067138671875 -0.349761962890625 0.9979858398437503488 +1.109625 -0.00067138671875 -0.349761962890625 0.9979858398437503488 +1.10975 -0.000640869140625 -0.34600830078125 0.9979858398437503488 +1.109875 -0.000640869140625 -0.34222412109375 0.9979858398437503488 +1.11 -0.000640869140625 -0.34222412109375 0.9979858398437503488 +1.110125 -0.000640869140625 -0.33837890625 0.9979858398437503488 +1.11025 -0.000640869140625 -0.33837890625 0.9979858398437503488 +1.1103750000000002 -0.000640869140625 -0.334503173828125 0.9979858398437503488 +1.1105 -0.0006103515625 -0.330596923828125 0.9979858398437503488 +1.110625 -0.0006103515625 -0.330596923828125 0.9979858398437503488 +1.1107500000000002 -0.0006103515625 -0.32666015625 0.9979858398437503488 +1.110875 -0.0006103515625 -0.32666015625 0.9979858398437503488 +1.111 -0.0006103515625 -0.322662353515625 0.9979858398437503488 +1.111125 -0.0006103515625 -0.31866455078125 0.9979858398437503488 +1.11125 -0.0006103515625 -0.31866455078125 0.9979858398437503488 +1.111375 -0.000579833984375 -0.314605712890625 0.9979858398437503488 +1.1115 -0.000579833984375 -0.314605712890625 0.9979858398437503488 +1.111625 -0.000579833984375 -0.310516357421875 0.9979858398437503488 +1.11175 -0.000579833984375 -0.306396484375 0.9979858398437503488 +1.111875 -0.000579833984375 -0.306396484375 0.9979858398437503488 +1.112 -0.000579833984375 -0.30224609375 0.9979858398437503488 +1.112125 -0.000579833984375 -0.30224609375 0.9979858398437503488 +1.11225 -0.00054931640625 -0.298065185546875 0.9979858398437503488 +1.1123750000000002 -0.00054931640625 -0.2938232421875 0.9979858398437503488 +1.1125 -0.00054931640625 -0.2938232421875 0.9979858398437503488 +1.112625 -0.00054931640625 -0.289581298828125 0.9979858398437503488 +1.1127500000000002 -0.00054931640625 -0.289581298828125 0.9979858398437503488 +1.112875 -0.000518798828125 -0.285308837890625 0.9979858398437503488 +1.113 -0.000518798828125 -0.280975341796875 0.9979858398437503488 +1.113125 -0.000518798828125 -0.280975341796875 0.9979858398437503488 +1.11325 -0.000518798828125 -0.276641845703125 0.9979858398437503488 +1.113375 -0.000518798828125 -0.276641845703125 0.9979858398437503488 +1.1135 -0.000518798828125 -0.27227783203125 0.9979858398437503488 +1.113625 -0.00048828125 -0.267852783203125 0.9979858398437503488 +1.11375 -0.00048828125 -0.267852783203125 0.9979858398437503488 +1.113875 -0.00048828125 -0.263427734375 0.9979858398437503488 +1.114 -0.00048828125 -0.263427734375 0.9979858398437503488 +1.114125 -0.00048828125 -0.25897216796875 0.9979858398437503488 +1.11425 -0.00048828125 -0.25445556640625 0.9979858398437503488 +1.1143750000000002 -0.00048828125 -0.25445556640625 0.9979858398437503488 +1.1145 -0.000457763671875 -0.249969482421875 0.9979858398437503488 +1.114625 -0.000457763671875 -0.249969482421875 0.9979858398437503488 +1.1147500000000002 -0.000457763671875 -0.24542236328125 0.9979858398437503488 +1.114875 -0.000457763671875 -0.2408447265625 0.9979858398437503488 +1.115 -0.000457763671875 -0.2408447265625 0.9979858398437503488 +1.115125 -0.00042724609375 -0.236236572265625 0.9979858398437503488 +1.11525 -0.00042724609375 -0.236236572265625 0.9979858398437503488 +1.115375 -0.00042724609375 -0.231597900390625 0.9979858398437503488 +1.1155 -0.00042724609375 -0.226959228515625 0.9979858398437503488 +1.115625 -0.00042724609375 -0.226959228515625 0.9979858398437503488 +1.11575 -0.00042724609375 -0.2222900390625 0.9979858398437503488 +1.115875 -0.00042724609375 -0.2222900390625 0.9979858398437503488 +1.116 -0.000396728515625 -0.21759033203125 0.9979858398437503488 +1.116125 -0.000396728515625 -0.212860107421875 0.9979858398437503488 +1.11625 -0.000396728515625 -0.212860107421875 0.9979858398437503488 +1.1163750000000002 -0.000396728515625 -0.208099365234375 0.9979858398437503488 +1.1165 -0.000396728515625 -0.208099365234375 0.9979858398437503488 +1.116625 -0.0003662109375 -0.203338623046875 0.9979858398437503488 +1.1167500000000002 -0.0003662109375 -0.19854736328125 0.9979858398437503488 +1.116875 -0.0003662109375 -0.19854736328125 0.9979858398437503488 +1.117 -0.0003662109375 -0.1937255859375 0.9979858398437503488 +1.117125 -0.0003662109375 -0.1937255859375 0.9979858398437503488 +1.11725 -0.000335693359375 -0.188873291015625 0.9979858398437503488 +1.117375 -0.000335693359375 -0.18402099609375 0.9979858398437503488 +1.1175 -0.000335693359375 -0.18402099609375 0.9979858398437503488 +1.117625 -0.000335693359375 -0.17913818359375 0.9979858398437503488 +1.11775 -0.000335693359375 -0.17913818359375 0.9979858398437503488 +1.117875 -0.00030517578125 -0.17425537109375 0.9979858398437503488 +1.118 -0.00030517578125 -0.169342041015625 0.9979858398437503488 +1.118125 -0.00030517578125 -0.169342041015625 0.9979858398437503488 +1.11825 -0.00030517578125 -0.164398193359375 0.9979858398437503488 +1.1183750000000002 -0.00030517578125 -0.164398193359375 0.9979858398437503488 +1.1185 -0.00030517578125 -0.159454345703125 0.9979858398437503488 +1.118625 -0.000274658203125 -0.15447998046875 0.9979858398437503488 +1.1187500000000002 -0.000274658203125 -0.15447998046875 0.9979858398437503488 +1.118875 -0.000274658203125 -0.14947509765625 0.9979858398437503488 +1.119 -0.000274658203125 -0.14947509765625 0.9979858398437503488 +1.119125 -0.000274658203125 -0.14447021484375 0.9979858398437503488 +1.11925 -0.000244140625 -0.13946533203125 0.9979858398437503488 +1.119375 -0.000244140625 -0.13946533203125 0.9979858398437503488 +1.1195 -0.000244140625 -0.134429931640625 0.9979858398437503488 +1.119625 -0.000244140625 -0.134429931640625 0.9979858398437503488 +1.11975 -0.000244140625 -0.129364013671875 0.9979858398437503488 +1.119875 -0.000213623046875 -0.124298095703125 0.9979858398437503488 +1.12 -0.007080078125 -0.124298095703125 0.942932128906248 +1.120125 -0.00677490234375 -0.119232177734375 0.942932128906248 +1.12025 -0.00677490234375 -0.119232177734375 0.942932128906248 +1.1203750000000002 -0.006500244140625 -0.1141357421875 0.942932128906248 +1.1205 -0.006195068359375 -0.109039306640625 0.942932128906248 +1.120625 -0.006195068359375 -0.109039306640625 0.942932128906248 +1.12075 -0.00592041015625 -0.103912353515625 0.942932128906248 +1.120875 -0.00592041015625 -0.103912353515625 0.942932128906248 +1.121 -0.005615234375 -0.098785400390625 0.942932128906248 +1.121125 -0.00531005859375 -0.093658447265625 0.942932128906248 +1.12125 -0.00531005859375 -0.093658447265625 0.942932128906248 +1.121375 -0.005035400390625 -0.0885009765625 0.942932128906248 +1.1215 -0.005035400390625 -0.0885009765625 0.942932128906248 +1.121625 -0.004730224609375 -0.083343505859375 0.942932128906248 +1.12175 -0.00445556640625 -0.07818603515625 0.942932128906248 +1.121875 -0.00445556640625 -0.07818603515625 0.942932128906248 +1.122 -0.004150390625 -0.072998046875 0.942932128906248 +1.122125 -0.004150390625 -0.072998046875 0.942932128906248 +1.12225 -0.00384521484375 -0.06781005859375 0.942932128906248 +1.1223750000000002 -0.0035400390625 -0.0626220703125 0.942932128906248 +1.1225 -0.0035400390625 -0.0626220703125 0.942932128906248 +1.122625 -0.003265380859375 -0.05743408203125 0.942932128906248 +1.12275 -0.003265380859375 -0.05743408203125 0.942932128906248 +1.122875 -0.002960205078125 -0.05224609375 0.942932128906248 +1.123 -0.002655029296875 -0.047027587890625 0.942932128906248 +1.123125 -0.002655029296875 -0.047027587890625 0.942932128906248 +1.12325 -0.00238037109375 -0.04180908203125 0.942932128906248 +1.123375 -0.00238037109375 -0.04180908203125 0.942932128906248 +1.1235 -0.0020751953125 -0.036590576171875 0.942932128906248 +1.123625 -0.00177001953125 -0.0313720703125 0.942932128906248 +1.12375 -0.00177001953125 -0.0313720703125 0.942932128906248 +1.123875 -0.00146484375 -0.026123046875 0.942932128906248 +1.124 -0.00146484375 -0.026123046875 0.942932128906248 +1.124125 -0.001190185546875 -0.020904541015625 0.942932128906248 +1.12425 -0.000885009765625 -0.01568603515625 0.942932128906248 +1.1243750000000002 -0.000885009765625 -0.01568603515625 0.942932128906248 +1.1245 -0.000579833984375 -0.01043701171875 0.942932128906248 +1.124625 -0.000579833984375 -0.01043701171875 0.942932128906248 +1.12475 -0.000274658203125 -0.005218505859375 0.942932128906248 +1.124875 0.0 0.0 0.942932128906248 +1.125 0.0 0.0 0.942932128906248 +1.125125 0.000274658203125 0.005218505859375 0.942932128906248 +1.12525 0.000274658203125 0.005218505859375 0.942932128906248 +1.125375 0.000579833984375 0.01043701171875 0.942932128906248 +1.1255 0.000885009765625 0.01568603515625 0.942932128906248 +1.125625 0.000885009765625 0.01568603515625 0.942932128906248 +1.12575 0.001190185546875 0.020904541015625 0.942932128906248 +1.125875 0.001190185546875 0.020904541015625 0.942932128906248 +1.1260000000000002 0.00146484375 0.026123046875 0.942932128906248 +1.126125 0.00177001953125 0.0313720703125 0.942932128906248 +1.12625 0.00177001953125 0.0313720703125 0.942932128906248 +1.1263750000000002 0.0020751953125 0.036590576171875 0.942932128906248 +1.1265 0.0020751953125 0.036590576171875 0.942932128906248 +1.126625 0.00238037109375 0.04180908203125 0.942932128906248 +1.12675 0.002655029296875 0.047027587890625 0.942932128906248 +1.126875 0.002655029296875 0.047027587890625 0.942932128906248 +1.127 0.002960205078125 0.05224609375 0.942932128906248 +1.127125 0.002960205078125 0.05224609375 0.942932128906248 +1.12725 0.003265380859375 0.05743408203125 0.942932128906248 +1.127375 0.0035400390625 0.0626220703125 0.942932128906248 +1.1275 0.0035400390625 0.0626220703125 0.942932128906248 +1.127625 0.00384521484375 0.06781005859375 0.942932128906248 +1.12775 0.00384521484375 0.06781005859375 0.942932128906248 +1.127875 0.004150390625 0.072998046875 0.942932128906248 +1.1280000000000002 0.00445556640625 0.07818603515625 0.942932128906248 +1.128125 0.00445556640625 0.07818603515625 0.942932128906248 +1.12825 0.004730224609375 0.083343505859375 0.942932128906248 +1.1283750000000002 0.004730224609375 0.083343505859375 0.942932128906248 +1.1285 0.005035400390625 0.0885009765625 0.942932128906248 +1.128625 0.00531005859375 0.093658447265625 0.942932128906248 +1.12875 0.00531005859375 0.093658447265625 0.942932128906248 +1.128875 0.005615234375 0.098785400390625 0.942932128906248 +1.129 0.005615234375 0.098785400390625 0.942932128906248 +1.129125 0.00592041015625 0.103912353515625 0.942932128906248 +1.12925 0.006195068359375 0.109039306640625 0.942932128906248 +1.129375 0.006195068359375 0.109039306640625 0.942932128906248 +1.1295 0.006500244140625 0.1141357421875 0.942932128906248 +1.129625 0.006500244140625 0.1141357421875 0.942932128906248 +1.12975 0.00677490234375 0.119232177734375 0.942932128906248 +1.129875 0.007080078125 0.124298095703125 0.942932128906248 +1.1300000000000002 0.007080078125 0.124298095703125 0.942932128906248 +1.130125 0.007354736328125 0.129364013671875 0.942932128906248 +1.13025 0.007354736328125 0.129364013671875 0.942932128906248 +1.1303750000000002 0.007659912109375 0.134429931640625 0.942932128906248 +1.1305 0.0079345703125 0.13946533203125 0.942932128906248 +1.130625 0.0079345703125 0.13946533203125 0.942932128906248 +1.13075 0.008209228515625 0.14447021484375 0.942932128906248 +1.130875 0.008209228515625 0.14447021484375 0.942932128906248 +1.131 0.008514404296875 0.14947509765625 0.942932128906248 +1.131125 0.0087890625 0.15447998046875 0.942932128906248 +1.13125 0.0087890625 0.15447998046875 0.942932128906248 +1.131375 0.009063720703125 0.159454345703125 0.942932128906248 +1.1315 0.009063720703125 0.159454345703125 0.942932128906248 +1.131625 0.00933837890625 0.164398193359375 0.942932128906248 +1.13175 0.0096435546875 0.169342041015625 0.942932128906248 +1.131875 0.0096435546875 0.169342041015625 0.942932128906248 +1.1320000000000002 0.009918212890625 0.17425537109375 0.942932128906248 +1.132125 0.009918212890625 0.17425537109375 0.942932128906248 +1.13225 0.01019287109375 0.17913818359375 0.942932128906248 +1.1323750000000002 0.010467529296875 0.18402099609375 0.942932128906248 +1.1325 0.010467529296875 0.18402099609375 0.942932128906248 +1.132625 0.0107421875 0.188873291015625 0.942932128906248 +1.13275 0.0107421875 0.188873291015625 0.942932128906248 +1.132875 0.011016845703125 0.1937255859375 0.942932128906248 +1.133 0.01129150390625 0.19854736328125 0.942932128906248 +1.133125 0.01129150390625 0.19854736328125 0.942932128906248 +1.13325 0.011566162109375 0.203338623046875 0.942932128906248 +1.133375 0.011566162109375 0.203338623046875 0.942932128906248 +1.1335 0.0118408203125 0.208099365234375 0.942932128906248 +1.133625 0.012115478515625 0.212860107421875 0.942932128906248 +1.13375 0.012115478515625 0.212860107421875 0.942932128906248 +1.133875 0.01239013671875 0.21759033203125 0.942932128906248 +1.1340000000000002 0.01239013671875 0.21759033203125 0.942932128906248 +1.134125 0.012664794921875 0.2222900390625 0.942932128906248 +1.13425 0.012908935546875 0.226959228515625 0.942932128906248 +1.1343750000000002 0.012908935546875 0.226959228515625 0.942932128906248 +1.1345 0.01318359375 0.231597900390625 0.942932128906248 +1.134625 0.01318359375 0.231597900390625 0.942932128906248 +1.13475 0.013458251953125 0.236236572265625 0.942932128906248 +1.134875 0.013702392578125 0.2408447265625 0.942932128906248 +1.135 0.013702392578125 0.2408447265625 0.942932128906248 +1.135125 0.01397705078125 0.24542236328125 0.942932128906248 +1.13525 0.01397705078125 0.24542236328125 0.942932128906248 +1.135375 0.01422119140625 0.249969482421875 0.942932128906248 +1.1355 0.014495849609375 0.25445556640625 0.942932128906248 +1.135625 0.014495849609375 0.25445556640625 0.942932128906248 +1.13575 0.014739990234375 0.25897216796875 0.942932128906248 +1.135875 0.014739990234375 0.25897216796875 0.942932128906248 +1.1360000000000002 0.014984130859375 0.263427734375 0.942932128906248 +1.136125 0.0152587890625 0.267852783203125 0.942932128906248 +1.13625 0.0152587890625 0.267852783203125 0.942932128906248 +1.136375 0.0155029296875 0.27227783203125 0.942932128906248 +1.1365 0.0155029296875 0.27227783203125 0.942932128906248 +1.136625 0.0157470703125 0.276641845703125 0.942932128906248 +1.13675 0.0159912109375 0.280975341796875 0.942932128906248 +1.136875 0.0159912109375 0.280975341796875 0.942932128906248 +1.137 0.0162353515625 0.285308837890625 0.942932128906248 +1.137125 0.0162353515625 0.285308837890625 0.942932128906248 +1.13725 0.0164794921875 0.289581298828125 0.942932128906248 +1.137375 0.0167236328125 0.2938232421875 0.942932128906248 +1.1375 0.0167236328125 0.2938232421875 0.942932128906248 +1.137625 0.0169677734375 0.298065185546875 0.942932128906248 +1.13775 0.0169677734375 0.298065185546875 0.942932128906248 +1.137875 0.0172119140625 0.30224609375 0.942932128906248 +1.1380000000000002 0.0174560546875 0.306396484375 0.942932128906248 +1.138125 0.0174560546875 0.306396484375 0.942932128906248 +1.13825 0.017669677734375 0.310516357421875 0.942932128906248 +1.138375 0.017669677734375 0.310516357421875 0.942932128906248 +1.1385 0.017913818359375 0.314605712890625 0.942932128906248 +1.138625 0.018157958984375 0.31866455078125 0.942932128906248 +1.13875 0.018157958984375 0.31866455078125 0.942932128906248 +1.138875 0.01837158203125 0.322662353515625 0.942932128906248 +1.139 0.01837158203125 0.322662353515625 0.942932128906248 +1.139125 0.018585205078125 0.32666015625 0.942932128906248 +1.13925 0.018829345703125 0.330596923828125 0.942932128906248 +1.139375 0.018829345703125 0.330596923828125 0.942932128906248 +1.1395 0.01904296875 0.334503173828125 0.942932128906248 +1.139625 0.01904296875 0.334503173828125 0.942932128906248 +1.13975 0.019256591796875 0.33837890625 0.942932128906248 +1.139875 0.01947021484375 0.34222412109375 0.942932128906248 +1.1400000000000002 0.01947021484375 0.34222412109375 0.942932128906248 +1.140125 0.01971435546875 0.34600830078125 0.942932128906248 +1.14025 0.01971435546875 0.34600830078125 0.942932128906248 +1.140375 0.019927978515625 0.349761962890625 0.942932128906248 +1.1405 0.0201416015625 0.353485107421875 0.942932128906248 +1.140625 0.0201416015625 0.353485107421875 0.942932128906248 +1.14075 0.02032470703125 0.357177734375 0.942932128906248 +1.140875 0.02032470703125 0.357177734375 0.942932128906248 +1.141 0.020538330078125 0.360809326171875 0.942932128906248 +1.141125 0.020751953125 0.36444091796875 0.942932128906248 +1.14125 0.020751953125 0.36444091796875 0.942932128906248 +1.141375 0.020965576171875 0.36798095703125 0.942932128906248 +1.1415 0.020965576171875 0.36798095703125 0.942932128906248 +1.1416250000000002 0.021148681640625 0.37152099609375 0.942932128906248 +1.14175 0.0213623046875 0.375 0.942932128906248 +1.141875 0.0213623046875 0.375 0.942932128906248 +1.1420000000000002 0.02154541015625 0.378448486328125 0.942932128906248 +1.142125 0.02154541015625 0.378448486328125 0.942932128906248 +1.14225 0.021728515625 0.3818359375 0.942932128906248 +1.142375 0.021942138671875 0.38519287109375 0.942932128906248 +1.1425 0.021942138671875 0.38519287109375 0.942932128906248 +1.142625 0.022125244140625 0.388519287109375 0.942932128906248 +1.14275 0.022125244140625 0.388519287109375 0.942932128906248 +1.142875 0.022308349609375 0.39178466796875 0.942932128906248 +1.143 0.022491455078125 0.39501953125 0.942932128906248 +1.143125 0.022491455078125 0.39501953125 0.942932128906248 +1.14325 0.022674560546875 0.398193359375 0.942932128906248 +1.143375 0.022674560546875 0.398193359375 0.942932128906248 +1.1435 0.022857666015625 0.401336669921875 0.942932128906248 +1.1436250000000002 0.023040771484375 0.404449462890625 0.942932128906248 +1.14375 0.023040771484375 0.404449462890625 0.942932128906248 +1.143875 0.023193359375 0.407501220703125 0.942932128906248 +1.1440000000000002 0.023193359375 0.407501220703125 0.942932128906248 +1.144125 0.02337646484375 0.4105224609375 0.942932128906248 +1.14425 0.0235595703125 0.413482666015625 0.942932128906248 +1.144375 0.0235595703125 0.413482666015625 0.942932128906248 +1.1445 0.023712158203125 0.416412353515625 0.942932128906248 +1.144625 0.023712158203125 0.416412353515625 0.942932128906248 +1.14475 0.02386474609375 0.419281005859375 0.942932128906248 +1.144875 0.0240478515625 0.422119140625 0.942932128906248 +1.145 0.0240478515625 0.422119140625 0.942932128906248 +1.145125 0.024200439453125 0.424896240234375 0.942932128906248 +1.14525 0.024200439453125 0.424896240234375 0.942932128906248 +1.145375 0.02435302734375 0.4276123046875 0.942932128906248 +1.1455 0.024505615234375 0.4302978515625 0.942932128906248 +1.1456250000000002 0.024505615234375 0.4302978515625 0.942932128906248 +1.14575 0.024658203125 0.432952880859375 0.942932128906248 +1.145875 0.024658203125 0.432952880859375 0.942932128906248 +1.1460000000000002 0.024810791015625 0.435546875 0.942932128906248 +1.146125 0.024932861328125 0.438079833984375 0.942932128906248 +1.14625 0.024932861328125 0.438079833984375 0.942932128906248 +1.146375 0.02508544921875 0.440582275390625 0.942932128906248 +1.1465 0.02508544921875 0.440582275390625 0.942932128906248 +1.146625 0.025238037109375 0.44305419921875 0.942932128906248 +1.14675 0.025360107421875 0.4454345703125 0.942932128906248 +1.146875 0.025360107421875 0.4454345703125 0.942932128906248 +1.147 0.0255126953125 0.447784423828125 0.942932128906248 +1.147125 0.0255126953125 0.447784423828125 0.942932128906248 +1.14725 0.025634765625 0.450103759765625 0.942932128906248 +1.147375 0.0257568359375 0.452362060546875 0.942932128906248 +1.1475 0.0257568359375 0.452362060546875 0.942932128906248 +1.1476250000000002 0.02587890625 0.454559326171875 0.942932128906248 +1.14775 0.02587890625 0.454559326171875 0.942932128906248 +1.147875 0.0260009765625 0.45672607421875 0.942932128906248 +1.1480000000000002 0.026123046875 0.458831787109375 0.942932128906248 +1.148125 0.026123046875 0.458831787109375 0.942932128906248 +1.14825 0.0262451171875 0.46087646484375 0.942932128906248 +1.148375 0.0262451171875 0.46087646484375 0.942932128906248 +1.1485 0.0263671875 0.462890625 0.942932128906248 +1.148625 0.026458740234375 0.464813232421875 0.942932128906248 +1.14875 0.026458740234375 0.464813232421875 0.942932128906248 +1.148875 0.026580810546875 0.46673583984375 0.942932128906248 +1.149 0.026580810546875 0.46673583984375 0.942932128906248 +1.149125 0.02667236328125 0.46856689453125 0.942932128906248 +1.14925 0.02679443359375 0.470367431640625 0.942932128906248 +1.149375 0.02679443359375 0.470367431640625 0.942932128906248 +1.1495 0.026885986328125 0.472137451171875 0.942932128906248 +1.1496250000000002 0.026885986328125 0.472137451171875 0.942932128906248 +1.14975 0.0269775390625 0.47381591796875 0.942932128906248 +1.149875 0.027069091796875 0.4754638671875 0.942932128906248 +1.1500000000000002 0.027069091796875 0.4754638671875 0.942932128906248 +1.150125 0.02716064453125 0.47705078125 0.942932128906248 +1.15025 0.02716064453125 0.47705078125 0.942932128906248 +1.150375 0.027252197265625 0.478607177734375 0.942932128906248 +1.1505 0.02734375 0.480072021484375 0.942932128906248 +1.150625 0.02734375 0.480072021484375 0.942932128906248 +1.15075 0.027435302734375 0.48150634765625 0.942932128906248 +1.150875 0.027435302734375 0.48150634765625 0.942932128906248 +1.151 0.027496337890625 0.48291015625 0.942932128906248 +1.151125 0.027587890625 0.484222412109375 0.942932128906248 +1.15125 0.027587890625 0.484222412109375 0.942932128906248 +1.151375 0.02764892578125 0.485504150390625 0.942932128906248 +1.1515 0.02764892578125 0.485504150390625 0.942932128906248 +1.1516250000000002 0.0277099609375 0.486724853515625 0.942932128906248 +1.15175 0.02777099609375 0.487884521484375 0.942932128906248 +1.151875 0.02777099609375 0.487884521484375 0.942932128906248 +1.1520000000000002 0.128326416015625 0.489013671875 0.737463378906246 +1.152125 0.128326416015625 0.489013671875 0.737463378906246 +1.15225 0.12860107421875 0.490081787109375 0.737463378906246 +1.152375 0.128875732421875 0.4910888671875 0.737463378906246 +1.1525 0.128875732421875 0.4910888671875 0.737463378906246 +1.152625 0.129119873046875 0.492034912109375 0.737463378906246 +1.15275 0.129119873046875 0.492034912109375 0.737463378906246 +1.152875 0.129364013671875 0.492950439453125 0.737463378906246 +1.153 0.12957763671875 0.4937744140625 0.737463378906246 +1.153125 0.12957763671875 0.4937744140625 0.737463378906246 +1.15325 0.129791259765625 0.49456787109375 0.737463378906246 +1.153375 0.129791259765625 0.49456787109375 0.737463378906246 +1.1535 0.129974365234375 0.49530029296875 0.737463378906246 +1.1536250000000002 0.130157470703125 0.496002197265625 0.737463378906246 +1.15375 0.130157470703125 0.496002197265625 0.737463378906246 +1.153875 0.130340576171875 0.496612548828125 0.737463378906246 +1.154 0.130340576171875 0.496612548828125 0.737463378906246 +1.154125 0.1304931640625 0.4971923828125 0.737463378906246 +1.15425 0.130615234375 0.497711181640625 0.737463378906246 +1.154375 0.130615234375 0.497711181640625 0.737463378906246 +1.1545 0.1307373046875 0.498199462890625 0.737463378906246 +1.154625 0.1307373046875 0.498199462890625 0.737463378906246 +1.15475 0.130859375 0.49859619140625 0.737463378906246 +1.154875 0.130950927734375 0.49896240234375 0.737463378906246 +1.155 0.130950927734375 0.49896240234375 0.737463378906246 +1.155125 0.131011962890625 0.499267578125 0.737463378906246 +1.15525 0.131011962890625 0.499267578125 0.737463378906246 +1.155375 0.131103515625 0.49951171875 0.737463378906246 +1.1555 0.131134033203125 0.49969482421875 0.737463378906246 +1.1556250000000002 0.131134033203125 0.49969482421875 0.737463378906246 +1.15575 0.13116455078125 0.49981689453125 0.737463378906246 +1.155875 0.13116455078125 0.49981689453125 0.737463378906246 +1.156 0.131195068359375 0.499908447265625 0.737463378906246 +1.156125 0.131195068359375 0.49993896484375 0.737463378906246 +1.15625 0.131195068359375 0.49993896484375 0.737463378906246 +1.156375 0.131195068359375 0.499908447265625 0.737463378906246 +1.1565 0.131195068359375 0.499908447265625 0.737463378906246 +1.156625 0.13116455078125 0.49981689453125 0.737463378906246 +1.15675 0.131134033203125 0.49969482421875 0.737463378906246 +1.156875 0.131134033203125 0.49969482421875 0.737463378906246 +1.157 0.131103515625 0.49951171875 0.737463378906246 +1.157125 0.131103515625 0.49951171875 0.737463378906246 +1.1572500000000002 0.131011962890625 0.499267578125 0.737463378906246 +1.157375 0.130950927734375 0.49896240234375 0.737463378906246 +1.1575 0.130950927734375 0.49896240234375 0.737463378906246 +1.1576250000000002 0.130859375 0.49859619140625 0.737463378906246 +1.15775 0.130859375 0.49859619140625 0.737463378906246 +1.157875 0.1307373046875 0.498199462890625 0.737463378906246 +1.158 0.130615234375 0.497711181640625 0.737463378906246 +1.158125 0.130615234375 0.497711181640625 0.737463378906246 +1.15825 0.1304931640625 0.4971923828125 0.737463378906246 +1.158375 0.1304931640625 0.4971923828125 0.737463378906246 +1.1585 0.130340576171875 0.496612548828125 0.737463378906246 +1.158625 0.130157470703125 0.496002197265625 0.737463378906246 +1.15875 0.130157470703125 0.496002197265625 0.737463378906246 +1.158875 0.129974365234375 0.49530029296875 0.737463378906246 +1.159 0.129974365234375 0.49530029296875 0.737463378906246 +1.159125 0.129791259765625 0.49456787109375 0.737463378906246 +1.1592500000000002 0.12957763671875 0.4937744140625 0.737463378906246 +1.159375 0.12957763671875 0.4937744140625 0.737463378906246 +1.1595 0.129364013671875 0.492950439453125 0.737463378906246 +1.1596250000000002 0.129364013671875 0.492950439453125 0.737463378906246 +1.15975 0.129119873046875 0.492034912109375 0.737463378906246 +1.159875 0.128875732421875 0.4910888671875 0.737463378906246 +1.16 0.128875732421875 0.4910888671875 0.737463378906246 +1.160125 0.12860107421875 0.490081787109375 0.737463378906246 +1.16025 0.12860107421875 0.490081787109375 0.737463378906246 +1.160375 0.128326416015625 0.489013671875 0.737463378906246 +1.1605 0.1280517578125 0.487884521484375 0.737463378906246 +1.160625 0.1280517578125 0.487884521484375 0.737463378906246 +1.16075 0.12774658203125 0.486724853515625 0.737463378906246 +1.160875 0.12774658203125 0.486724853515625 0.737463378906246 +1.161 0.127410888671875 0.485504150390625 0.737463378906246 +1.161125 0.1270751953125 0.484222412109375 0.737463378906246 +1.1612500000000002 0.1270751953125 0.484222412109375 0.737463378906246 +1.161375 0.126739501953125 0.48291015625 0.737463378906246 +1.1615 0.126739501953125 0.48291015625 0.737463378906246 +1.1616250000000002 0.126373291015625 0.48150634765625 0.737463378906246 +1.16175 0.126007080078125 0.480072021484375 0.737463378906246 +1.161875 0.126007080078125 0.480072021484375 0.737463378906246 +1.162 0.1256103515625 0.478607177734375 0.737463378906246 +1.162125 0.1256103515625 0.478607177734375 0.737463378906246 +1.16225 0.125213623046875 0.47705078125 0.737463378906246 +1.162375 0.124786376953125 0.4754638671875 0.737463378906246 +1.1625 0.124786376953125 0.4754638671875 0.737463378906246 +1.162625 0.124359130859375 0.47381591796875 0.737463378906246 +1.16275 0.124359130859375 0.47381591796875 0.737463378906246 +1.162875 0.1239013671875 0.472137451171875 0.737463378906246 +1.163 0.123443603515625 0.470367431640625 0.737463378906246 +1.163125 0.123443603515625 0.470367431640625 0.737463378906246 +1.1632500000000002 0.12298583984375 0.46856689453125 0.737463378906246 +1.163375 0.12298583984375 0.46856689453125 0.737463378906246 +1.1635 0.12249755859375 0.46673583984375 0.737463378906246 +1.1636250000000002 0.121978759765625 0.464813232421875 0.737463378906246 +1.16375 0.121978759765625 0.464813232421875 0.737463378906246 +1.163875 0.121490478515625 0.462890625 0.737463378906246 +1.164 0.121490478515625 0.462890625 0.737463378906246 +1.164125 0.120941162109375 0.46087646484375 0.737463378906246 +1.16425 0.12042236328125 0.458831787109375 0.737463378906246 +1.164375 0.12042236328125 0.458831787109375 0.737463378906246 +1.1645 0.119873046875 0.45672607421875 0.737463378906246 +1.164625 0.119873046875 0.45672607421875 0.737463378906246 +1.16475 0.119293212890625 0.454559326171875 0.737463378906246 +1.164875 0.11871337890625 0.452362060546875 0.737463378906246 +1.165 0.11871337890625 0.452362060546875 0.737463378906246 +1.165125 0.118133544921875 0.450103759765625 0.737463378906246 +1.1652500000000002 0.118133544921875 0.450103759765625 0.737463378906246 +1.165375 0.117523193359375 0.447784423828125 0.737463378906246 +1.1655 0.116912841796875 0.4454345703125 0.737463378906246 +1.1656250000000002 0.116912841796875 0.4454345703125 0.737463378906246 +1.16575 0.11627197265625 0.44305419921875 0.737463378906246 +1.165875 0.11627197265625 0.44305419921875 0.737463378906246 +1.166 0.115631103515625 0.440582275390625 0.737463378906246 +1.166125 0.114959716796875 0.438079833984375 0.737463378906246 +1.16625 0.114959716796875 0.438079833984375 0.737463378906246 +1.166375 0.11431884765625 0.435546875 0.737463378906246 +1.1665 0.11431884765625 0.435546875 0.737463378906246 +1.166625 0.113616943359375 0.432952880859375 0.737463378906246 +1.16675 0.1129150390625 0.4302978515625 0.737463378906246 +1.166875 0.1129150390625 0.4302978515625 0.737463378906246 +1.167 0.112213134765625 0.4276123046875 0.737463378906246 +1.167125 0.112213134765625 0.4276123046875 0.737463378906246 +1.1672500000000002 0.11151123046875 0.424896240234375 0.737463378906246 +1.167375 0.11077880859375 0.422119140625 0.737463378906246 +1.1675 0.11077880859375 0.422119140625 0.737463378906246 +1.1676250000000002 0.11004638671875 0.419281005859375 0.737463378906246 +1.16775 0.11004638671875 0.419281005859375 0.737463378906246 +1.167875 0.109283447265625 0.416412353515625 0.737463378906246 +1.168 0.1085205078125 0.413482666015625 0.737463378906246 +1.168125 0.1085205078125 0.413482666015625 0.737463378906246 +1.16825 0.10772705078125 0.4105224609375 0.737463378906246 +1.168375 0.10772705078125 0.4105224609375 0.737463378906246 +1.1685 0.10693359375 0.407501220703125 0.737463378906246 +1.168625 0.10614013671875 0.404449462890625 0.737463378906246 +1.16875 0.10614013671875 0.404449462890625 0.737463378906246 +1.168875 0.105316162109375 0.401336669921875 0.737463378906246 +1.169 0.105316162109375 0.401336669921875 0.737463378906246 +1.169125 0.1044921875 0.398193359375 0.737463378906246 +1.1692500000000002 0.103668212890625 0.39501953125 0.737463378906246 +1.169375 0.103668212890625 0.39501953125 0.737463378906246 +1.1695 0.102813720703125 0.39178466796875 0.737463378906246 +1.169625 0.102813720703125 0.39178466796875 0.737463378906246 +1.16975 0.101959228515625 0.388519287109375 0.737463378906246 +1.169875 0.101104736328125 0.38519287109375 0.737463378906246 +1.17 0.101104736328125 0.38519287109375 0.737463378906246 +1.170125 0.1002197265625 0.3818359375 0.737463378906246 +1.17025 0.1002197265625 0.3818359375 0.737463378906246 +1.170375 0.09930419921875 0.378448486328125 0.737463378906246 +1.1705 0.098419189453125 0.375 0.737463378906246 +1.170625 0.098419189453125 0.375 0.737463378906246 +1.17075 0.097503662109375 0.37152099609375 0.737463378906246 +1.170875 0.097503662109375 0.37152099609375 0.737463378906246 +1.171 0.096588134765625 0.36798095703125 0.737463378906246 +1.171125 0.09564208984375 0.36444091796875 0.737463378906246 +1.1712500000000002 0.09564208984375 0.36444091796875 0.737463378906246 +1.171375 0.094696044921875 0.360809326171875 0.737463378906246 +1.1715 0.094696044921875 0.360809326171875 0.737463378906246 +1.171625 0.09375 0.357177734375 0.737463378906246 +1.17175 0.0927734375 0.353485107421875 0.737463378906246 +1.171875 0.0927734375 0.353485107421875 0.737463378906246 +1.172 0.091796875 0.349761962890625 0.737463378906246 +1.172125 0.091796875 0.349761962890625 0.737463378906246 +1.17225 0.0908203125 0.34600830078125 0.737463378906246 +1.172375 0.089813232421875 0.34222412109375 0.737463378906246 +1.1725 0.089813232421875 0.34222412109375 0.737463378906246 +1.172625 0.08880615234375 0.33837890625 0.737463378906246 +1.17275 0.08880615234375 0.33837890625 0.737463378906246 +1.1728750000000002 0.087799072265625 0.334503173828125 0.737463378906246 +1.173 0.086761474609375 0.330596923828125 0.737463378906246 +1.173125 0.086761474609375 0.330596923828125 0.737463378906246 +1.1732500000000002 0.085723876953125 0.32666015625 0.737463378906246 +1.173375 0.085723876953125 0.32666015625 0.737463378906246 +1.1735 0.084686279296875 0.322662353515625 0.737463378906246 +1.173625 0.0836181640625 0.31866455078125 0.737463378906246 +1.17375 0.0836181640625 0.31866455078125 0.737463378906246 +1.173875 0.082550048828125 0.314605712890625 0.737463378906246 +1.174 0.082550048828125 0.314605712890625 0.737463378906246 +1.174125 0.08148193359375 0.310516357421875 0.737463378906246 +1.17425 0.080413818359375 0.306396484375 0.737463378906246 +1.174375 0.080413818359375 0.306396484375 0.737463378906246 +1.1745 0.079315185546875 0.30224609375 0.737463378906246 +1.174625 0.079315185546875 0.30224609375 0.737463378906246 +1.17475 0.078216552734375 0.298065185546875 0.737463378906246 +1.1748750000000002 0.077117919921875 0.2938232421875 0.737463378906246 +1.175 0.077117919921875 0.2938232421875 0.737463378906246 +1.175125 0.07598876953125 0.289581298828125 0.737463378906246 +1.1752500000000002 0.07598876953125 0.289581298828125 0.737463378906246 +1.175375 0.074859619140625 0.285308837890625 0.737463378906246 +1.1755 0.07373046875 0.280975341796875 0.737463378906246 +1.175625 0.07373046875 0.280975341796875 0.737463378906246 +1.17575 0.072601318359375 0.276641845703125 0.737463378906246 +1.175875 0.072601318359375 0.276641845703125 0.737463378906246 +1.176 0.071441650390625 0.27227783203125 0.737463378906246 +1.176125 0.070281982421875 0.267852783203125 0.737463378906246 +1.17625 0.070281982421875 0.267852783203125 0.737463378906246 +1.176375 0.069122314453125 0.263427734375 0.737463378906246 +1.1765 0.069122314453125 0.263427734375 0.737463378906246 +1.176625 0.067962646484375 0.25897216796875 0.737463378906246 +1.17675 0.0667724609375 0.25445556640625 0.737463378906246 +1.1768750000000002 0.0667724609375 0.25445556640625 0.737463378906246 +1.177 0.065582275390625 0.249969482421875 0.737463378906246 +1.177125 0.065582275390625 0.249969482421875 0.737463378906246 +1.1772500000000002 0.06439208984375 0.24542236328125 0.737463378906246 +1.177375 0.063201904296875 0.2408447265625 0.737463378906246 +1.1775 0.063201904296875 0.2408447265625 0.737463378906246 +1.177625 0.061981201171875 0.236236572265625 0.737463378906246 +1.17775 0.061981201171875 0.236236572265625 0.737463378906246 +1.177875 0.060791015625 0.231597900390625 0.737463378906246 +1.178 0.059539794921875 0.226959228515625 0.737463378906246 +1.178125 0.059539794921875 0.226959228515625 0.737463378906246 +1.17825 0.058319091796875 0.2222900390625 0.737463378906246 +1.178375 0.058319091796875 0.2222900390625 0.737463378906246 +1.1785 0.057098388671875 0.21759033203125 0.737463378906246 +1.178625 0.05584716796875 0.212860107421875 0.737463378906246 +1.17875 0.05584716796875 0.212860107421875 0.737463378906246 +1.1788750000000002 0.054595947265625 0.208099365234375 0.737463378906246 +1.179 0.054595947265625 0.208099365234375 0.737463378906246 +1.179125 0.0533447265625 0.203338623046875 0.737463378906246 +1.1792500000000002 0.052093505859375 0.19854736328125 0.737463378906246 +1.179375 0.052093505859375 0.19854736328125 0.737463378906246 +1.1795 0.05084228515625 0.1937255859375 0.737463378906246 +1.179625 0.05084228515625 0.1937255859375 0.737463378906246 +1.17975 0.049560546875 0.188873291015625 0.737463378906246 +1.179875 0.04827880859375 0.18402099609375 0.737463378906246 +1.18 0.04827880859375 0.18402099609375 0.737463378906246 +1.180125 0.0469970703125 0.17913818359375 0.737463378906246 +1.18025 0.0469970703125 0.17913818359375 0.737463378906246 +1.180375 0.04571533203125 0.17425537109375 0.737463378906246 +1.1805 0.04443359375 0.169342041015625 0.737463378906246 +1.180625 0.04443359375 0.169342041015625 0.737463378906246 +1.18075 0.043121337890625 0.164398193359375 0.737463378906246 +1.1808750000000002 0.043121337890625 0.164398193359375 0.737463378906246 +1.181 0.041839599609375 0.159454345703125 0.737463378906246 +1.181125 0.04052734375 0.15447998046875 0.737463378906246 +1.1812500000000002 0.04052734375 0.15447998046875 0.737463378906246 +1.181375 0.039215087890625 0.14947509765625 0.737463378906246 +1.1815 0.039215087890625 0.14947509765625 0.737463378906246 +1.181625 0.03790283203125 0.14447021484375 0.737463378906246 +1.18175 0.036590576171875 0.13946533203125 0.737463378906246 +1.181875 0.036590576171875 0.13946533203125 0.737463378906246 +1.182 0.0352783203125 0.134429931640625 0.737463378906246 +1.182125 0.0352783203125 0.134429931640625 0.737463378906246 +1.18225 0.033935546875 0.129364013671875 0.737463378906246 +1.182375 0.032623291015625 0.124298095703125 0.737463378906246 +1.1825 0.032623291015625 0.124298095703125 0.737463378906246 +1.182625 0.031280517578125 0.119232177734375 0.737463378906246 +1.18275 0.031280517578125 0.119232177734375 0.737463378906246 +1.1828750000000002 0.029937744140625 0.1141357421875 0.737463378906246 +1.183 0.028594970703125 0.109039306640625 0.737463378906246 +1.183125 0.028594970703125 0.109039306640625 0.737463378906246 +1.1832500000000002 0.027252197265625 0.103912353515625 0.737463378906246 +1.183375 0.027252197265625 0.103912353515625 0.737463378906246 +1.1835 0.025909423828125 0.098785400390625 0.737463378906246 +1.183625 0.024566650390625 0.093658447265625 0.737463378906246 +1.18375 0.024566650390625 0.093658447265625 0.737463378906246 +1.183875 0.023223876953125 0.0885009765625 0.737463378906246 +1.184 0.05181884765625 0.0885009765625 0.41434936523436966 +1.184125 0.048797607421875 0.083343505859375 0.41434936523436966 +1.18425 0.0457763671875 0.07818603515625 0.41434936523436966 +1.184375 0.0457763671875 0.07818603515625 0.41434936523436966 +1.1845 0.042755126953125 0.072998046875 0.41434936523436966 +1.184625 0.042755126953125 0.072998046875 0.41434936523436966 +1.18475 0.039703369140625 0.06781005859375 0.41434936523436966 +1.1848750000000002 0.03668212890625 0.0626220703125 0.41434936523436966 +1.185 0.03668212890625 0.0626220703125 0.41434936523436966 +1.185125 0.03363037109375 0.05743408203125 0.41434936523436966 +1.18525 0.03363037109375 0.05743408203125 0.41434936523436966 +1.185375 0.03057861328125 0.05224609375 0.41434936523436966 +1.1855 0.02752685546875 0.047027587890625 0.41434936523436966 +1.185625 0.02752685546875 0.047027587890625 0.41434936523436966 +1.18575 0.02447509765625 0.04180908203125 0.41434936523436966 +1.185875 0.02447509765625 0.04180908203125 0.41434936523436966 +1.186 0.02142333984375 0.036590576171875 0.41434936523436966 +1.186125 0.01837158203125 0.0313720703125 0.41434936523436966 +1.18625 0.01837158203125 0.0313720703125 0.41434936523436966 +1.186375 0.015289306640625 0.026123046875 0.41434936523436966 +1.1865 0.015289306640625 0.026123046875 0.41434936523436966 +1.186625 0.012237548828125 0.020904541015625 0.41434936523436966 +1.18675 0.009185791015625 0.01568603515625 0.41434936523436966 +1.1868750000000002 0.009185791015625 0.01568603515625 0.41434936523436966 +1.187 0.006103515625 0.01043701171875 0.41434936523436966 +1.187125 0.006103515625 0.01043701171875 0.41434936523436966 +1.18725 0.0030517578125 0.005218505859375 0.41434936523436966 +1.187375 0.0 0.0 0.41434936523436966 +1.1875 0.0 0.0 0.41434936523436966 +1.187625 -0.0030517578125 -0.005218505859375 0.41434936523436966 +1.18775 -0.0030517578125 -0.005218505859375 0.41434936523436966 +1.187875 -0.006103515625 -0.01043701171875 0.41434936523436966 +1.188 -0.009185791015625 -0.01568603515625 0.41434936523436966 +1.188125 -0.009185791015625 -0.01568603515625 0.41434936523436966 +1.18825 -0.012237548828125 -0.020904541015625 0.41434936523436966 +1.188375 -0.012237548828125 -0.020904541015625 0.41434936523436966 +1.1885000000000002 -0.015289306640625 -0.026123046875 0.41434936523436966 +1.188625 -0.01837158203125 -0.0313720703125 0.41434936523436966 +1.18875 -0.01837158203125 -0.0313720703125 0.41434936523436966 +1.1888750000000002 -0.02142333984375 -0.036590576171875 0.41434936523436966 +1.189 -0.02142333984375 -0.036590576171875 0.41434936523436966 +1.189125 -0.02447509765625 -0.04180908203125 0.41434936523436966 +1.18925 -0.02752685546875 -0.047027587890625 0.41434936523436966 +1.189375 -0.02752685546875 -0.047027587890625 0.41434936523436966 +1.1895 -0.03057861328125 -0.05224609375 0.41434936523436966 +1.189625 -0.03057861328125 -0.05224609375 0.41434936523436966 +1.18975 -0.03363037109375 -0.05743408203125 0.41434936523436966 +1.189875 -0.03668212890625 -0.0626220703125 0.41434936523436966 +1.19 -0.03668212890625 -0.0626220703125 0.41434936523436966 +1.190125 -0.039703369140625 -0.06781005859375 0.41434936523436966 +1.19025 -0.039703369140625 -0.06781005859375 0.41434936523436966 +1.190375 -0.042755126953125 -0.072998046875 0.41434936523436966 +1.1905000000000002 -0.0457763671875 -0.07818603515625 0.41434936523436966 +1.190625 -0.0457763671875 -0.07818603515625 0.41434936523436966 +1.19075 -0.048797607421875 -0.083343505859375 0.41434936523436966 +1.1908750000000002 -0.048797607421875 -0.083343505859375 0.41434936523436966 +1.191 -0.05181884765625 -0.0885009765625 0.41434936523436966 +1.191125 -0.054840087890625 -0.093658447265625 0.41434936523436966 +1.19125 -0.054840087890625 -0.093658447265625 0.41434936523436966 +1.191375 -0.057861328125 -0.098785400390625 0.41434936523436966 +1.1915 -0.057861328125 -0.098785400390625 0.41434936523436966 +1.191625 -0.06085205078125 -0.103912353515625 0.41434936523436966 +1.19175 -0.0638427734375 -0.109039306640625 0.41434936523436966 +1.191875 -0.0638427734375 -0.109039306640625 0.41434936523436966 +1.192 -0.06683349609375 -0.1141357421875 0.41434936523436966 +1.192125 -0.06683349609375 -0.1141357421875 0.41434936523436966 +1.19225 -0.06982421875 -0.119232177734375 0.41434936523436966 +1.192375 -0.072784423828125 -0.124298095703125 0.41434936523436966 +1.1925000000000002 -0.072784423828125 -0.124298095703125 0.41434936523436966 +1.192625 -0.07574462890625 -0.129364013671875 0.41434936523436966 +1.19275 -0.07574462890625 -0.129364013671875 0.41434936523436966 +1.1928750000000002 -0.078704833984375 -0.134429931640625 0.41434936523436966 +1.193 -0.0816650390625 -0.13946533203125 0.41434936523436966 +1.193125 -0.0816650390625 -0.13946533203125 0.41434936523436966 +1.19325 -0.0845947265625 -0.14447021484375 0.41434936523436966 +1.193375 -0.0845947265625 -0.14447021484375 0.41434936523436966 +1.1935 -0.0875244140625 -0.14947509765625 0.41434936523436966 +1.193625 -0.0904541015625 -0.15447998046875 0.41434936523436966 +1.19375 -0.0904541015625 -0.15447998046875 0.41434936523436966 +1.193875 -0.093353271484375 -0.159454345703125 0.41434936523436966 +1.194 -0.093353271484375 -0.159454345703125 0.41434936523436966 +1.194125 -0.09625244140625 -0.164398193359375 0.41434936523436966 +1.19425 -0.099151611328125 -0.169342041015625 0.41434936523436966 +1.194375 -0.099151611328125 -0.169342041015625 0.41434936523436966 +1.1945000000000002 -0.102020263671875 -0.17425537109375 0.41434936523436966 +1.194625 -0.102020263671875 -0.17425537109375 0.41434936523436966 +1.19475 -0.104888916015625 -0.17913818359375 0.41434936523436966 +1.1948750000000002 -0.107757568359375 -0.18402099609375 0.41434936523436966 +1.195 -0.107757568359375 -0.18402099609375 0.41434936523436966 +1.195125 -0.110595703125 -0.188873291015625 0.41434936523436966 +1.19525 -0.110595703125 -0.188873291015625 0.41434936523436966 +1.195375 -0.113433837890625 -0.1937255859375 0.41434936523436966 +1.1955 -0.11627197265625 -0.19854736328125 0.41434936523436966 +1.195625 -0.11627197265625 -0.19854736328125 0.41434936523436966 +1.19575 -0.119049072265625 -0.203338623046875 0.41434936523436966 +1.195875 -0.119049072265625 -0.203338623046875 0.41434936523436966 +1.196 -0.121856689453125 -0.208099365234375 0.41434936523436966 +1.196125 -0.1246337890625 -0.212860107421875 0.41434936523436966 +1.19625 -0.1246337890625 -0.212860107421875 0.41434936523436966 +1.196375 -0.127410888671875 -0.21759033203125 0.41434936523436966 +1.1965000000000002 -0.127410888671875 -0.21759033203125 0.41434936523436966 +1.196625 -0.130157470703125 -0.2222900390625 0.41434936523436966 +1.19675 -0.132904052734375 -0.226959228515625 0.41434936523436966 +1.1968750000000002 -0.132904052734375 -0.226959228515625 0.41434936523436966 +1.197 -0.1356201171875 -0.231597900390625 0.41434936523436966 +1.197125 -0.1356201171875 -0.231597900390625 0.41434936523436966 +1.19725 -0.138336181640625 -0.236236572265625 0.41434936523436966 +1.197375 -0.141021728515625 -0.2408447265625 0.41434936523436966 +1.1975 -0.141021728515625 -0.2408447265625 0.41434936523436966 +1.197625 -0.143707275390625 -0.24542236328125 0.41434936523436966 +1.19775 -0.143707275390625 -0.24542236328125 0.41434936523436966 +1.197875 -0.1463623046875 -0.249969482421875 0.41434936523436966 +1.198 -0.149017333984375 -0.25445556640625 0.41434936523436966 +1.198125 -0.149017333984375 -0.25445556640625 0.41434936523436966 +1.19825 -0.151641845703125 -0.25897216796875 0.41434936523436966 +1.198375 -0.151641845703125 -0.25897216796875 0.41434936523436966 +1.1985000000000002 -0.154266357421875 -0.263427734375 0.41434936523436966 +1.198625 -0.1568603515625 -0.267852783203125 0.41434936523436966 +1.19875 -0.1568603515625 -0.267852783203125 0.41434936523436966 +1.1988750000000002 -0.159454345703125 -0.27227783203125 0.41434936523436966 +1.199 -0.159454345703125 -0.27227783203125 0.41434936523436966 +1.199125 -0.1619873046875 -0.276641845703125 0.41434936523436966 +1.19925 -0.16455078125 -0.280975341796875 0.41434936523436966 +1.199375 -0.16455078125 -0.280975341796875 0.41434936523436966 +1.1995 -0.167083740234375 -0.285308837890625 0.41434936523436966 +1.199625 -0.167083740234375 -0.285308837890625 0.41434936523436966 +1.19975 -0.169586181640625 -0.289581298828125 0.41434936523436966 +1.199875 -0.17205810546875 -0.2938232421875 0.41434936523436966 +1.2 -0.17205810546875 -0.2938232421875 0.41434936523436966 +1.200125 -0.174530029296875 -0.298065185546875 0.41434936523436966 +1.20025 -0.174530029296875 -0.298065185546875 0.41434936523436966 +1.200375 -0.177001953125 -0.30224609375 0.41434936523436966 +1.2005000000000002 -0.179443359375 -0.306396484375 0.41434936523436966 +1.200625 -0.179443359375 -0.306396484375 0.41434936523436966 +1.20075 -0.181854248046875 -0.310516357421875 0.41434936523436966 +1.200875 -0.181854248046875 -0.310516357421875 0.41434936523436966 +1.201 -0.184234619140625 -0.314605712890625 0.41434936523436966 +1.201125 -0.186614990234375 -0.31866455078125 0.41434936523436966 +1.20125 -0.186614990234375 -0.31866455078125 0.41434936523436966 +1.201375 -0.18896484375 -0.322662353515625 0.41434936523436966 +1.2015 -0.18896484375 -0.322662353515625 0.41434936523436966 +1.201625 -0.1912841796875 -0.32666015625 0.41434936523436966 +1.20175 -0.193603515625 -0.330596923828125 0.41434936523436966 +1.201875 -0.193603515625 -0.330596923828125 0.41434936523436966 +1.202 -0.195892333984375 -0.334503173828125 0.41434936523436966 +1.202125 -0.195892333984375 -0.334503173828125 0.41434936523436966 +1.20225 -0.198150634765625 -0.33837890625 0.41434936523436966 +1.202375 -0.200408935546875 -0.34222412109375 0.41434936523436966 +1.2025000000000002 -0.200408935546875 -0.34222412109375 0.41434936523436966 +1.202625 -0.20263671875 -0.34600830078125 0.41434936523436966 +1.20275 -0.20263671875 -0.34600830078125 0.41434936523436966 +1.202875 -0.204833984375 -0.349761962890625 0.41434936523436966 +1.203 -0.207000732421875 -0.353485107421875 0.41434936523436966 +1.203125 -0.207000732421875 -0.353485107421875 0.41434936523436966 +1.20325 -0.20916748046875 -0.357177734375 0.41434936523436966 +1.203375 -0.20916748046875 -0.357177734375 0.41434936523436966 +1.2035 -0.2113037109375 -0.360809326171875 0.41434936523436966 +1.203625 -0.213409423828125 -0.36444091796875 0.41434936523436966 +1.20375 -0.213409423828125 -0.36444091796875 0.41434936523436966 +1.203875 -0.215484619140625 -0.36798095703125 0.41434936523436966 +1.204 -0.215484619140625 -0.36798095703125 0.41434936523436966 +1.2041250000000002 -0.217559814453125 -0.37152099609375 0.41434936523436966 +1.20425 -0.2196044921875 -0.375 0.41434936523436966 +1.204375 -0.2196044921875 -0.375 0.41434936523436966 +1.2045000000000002 -0.22161865234375 -0.378448486328125 0.41434936523436966 +1.204625 -0.22161865234375 -0.378448486328125 0.41434936523436966 +1.20475 -0.223602294921875 -0.3818359375 0.41434936523436966 +1.204875 -0.225555419921875 -0.38519287109375 0.41434936523436966 +1.205 -0.225555419921875 -0.38519287109375 0.41434936523436966 +1.205125 -0.227508544921875 -0.388519287109375 0.41434936523436966 +1.20525 -0.227508544921875 -0.388519287109375 0.41434936523436966 +1.205375 -0.22943115234375 -0.39178466796875 0.41434936523436966 +1.2055 -0.2313232421875 -0.39501953125 0.41434936523436966 +1.205625 -0.2313232421875 -0.39501953125 0.41434936523436966 +1.20575 -0.233184814453125 -0.398193359375 0.41434936523436966 +1.205875 -0.233184814453125 -0.398193359375 0.41434936523436966 +1.206 -0.235015869140625 -0.401336669921875 0.41434936523436966 +1.2061250000000002 -0.236846923828125 -0.404449462890625 0.41434936523436966 +1.20625 -0.236846923828125 -0.404449462890625 0.41434936523436966 +1.206375 -0.2386474609375 -0.407501220703125 0.41434936523436966 +1.2065000000000002 -0.2386474609375 -0.407501220703125 0.41434936523436966 +1.206625 -0.240386962890625 -0.4105224609375 0.41434936523436966 +1.20675 -0.24212646484375 -0.413482666015625 0.41434936523436966 +1.206875 -0.24212646484375 -0.413482666015625 0.41434936523436966 +1.207 -0.24383544921875 -0.416412353515625 0.41434936523436966 +1.207125 -0.24383544921875 -0.416412353515625 0.41434936523436966 +1.20725 -0.245513916015625 -0.419281005859375 0.41434936523436966 +1.207375 -0.2471923828125 -0.422119140625 0.41434936523436966 +1.2075 -0.2471923828125 -0.422119140625 0.41434936523436966 +1.207625 -0.248809814453125 -0.424896240234375 0.41434936523436966 +1.20775 -0.248809814453125 -0.424896240234375 0.41434936523436966 +1.207875 -0.250396728515625 -0.4276123046875 0.41434936523436966 +1.208 -0.251983642578125 -0.4302978515625 0.41434936523436966 +1.2081250000000002 -0.251983642578125 -0.4302978515625 0.41434936523436966 +1.20825 -0.2535400390625 -0.432952880859375 0.41434936523436966 +1.208375 -0.2535400390625 -0.432952880859375 0.41434936523436966 +1.2085000000000002 -0.25506591796875 -0.435546875 0.41434936523436966 +1.208625 -0.25653076171875 -0.438079833984375 0.41434936523436966 +1.20875 -0.25653076171875 -0.438079833984375 0.41434936523436966 +1.208875 -0.25799560546875 -0.440582275390625 0.41434936523436966 +1.209 -0.25799560546875 -0.440582275390625 0.41434936523436966 +1.209125 -0.259429931640625 -0.44305419921875 0.41434936523436966 +1.20925 -0.260833740234375 -0.4454345703125 0.41434936523436966 +1.209375 -0.260833740234375 -0.4454345703125 0.41434936523436966 +1.2095 -0.26220703125 -0.447784423828125 0.41434936523436966 +1.209625 -0.26220703125 -0.447784423828125 0.41434936523436966 +1.20975 -0.263580322265625 -0.450103759765625 0.41434936523436966 +1.209875 -0.264892578125 -0.452362060546875 0.41434936523436966 +1.21 -0.264892578125 -0.452362060546875 0.41434936523436966 +1.2101250000000002 -0.26617431640625 -0.454559326171875 0.41434936523436966 +1.21025 -0.26617431640625 -0.454559326171875 0.41434936523436966 +1.210375 -0.2674560546875 -0.45672607421875 0.41434936523436966 +1.2105000000000002 -0.2686767578125 -0.458831787109375 0.41434936523436966 +1.210625 -0.2686767578125 -0.458831787109375 0.41434936523436966 +1.21075 -0.269866943359375 -0.46087646484375 0.41434936523436966 +1.210875 -0.269866943359375 -0.46087646484375 0.41434936523436966 +1.211 -0.27105712890625 -0.462890625 0.41434936523436966 +1.211125 -0.272186279296875 -0.464813232421875 0.41434936523436966 +1.21125 -0.272186279296875 -0.464813232421875 0.41434936523436966 +1.211375 -0.2733154296875 -0.46673583984375 0.41434936523436966 +1.2115 -0.2733154296875 -0.46673583984375 0.41434936523436966 +1.211625 -0.274383544921875 -0.46856689453125 0.41434936523436966 +1.21175 -0.27545166015625 -0.470367431640625 0.41434936523436966 +1.211875 -0.27545166015625 -0.470367431640625 0.41434936523436966 +1.212 -0.276458740234375 -0.472137451171875 0.41434936523436966 +1.2121250000000002 -0.276458740234375 -0.472137451171875 0.41434936523436966 +1.21225 -0.2774658203125 -0.47381591796875 0.41434936523436966 +1.212375 -0.2784423828125 -0.4754638671875 0.41434936523436966 +1.2125000000000002 -0.2784423828125 -0.4754638671875 0.41434936523436966 +1.212625 -0.27935791015625 -0.47705078125 0.41434936523436966 +1.21275 -0.27935791015625 -0.47705078125 0.41434936523436966 +1.212875 -0.2802734375 -0.478607177734375 0.41434936523436966 +1.213 -0.2811279296875 -0.480072021484375 0.41434936523436966 +1.213125 -0.2811279296875 -0.480072021484375 0.41434936523436966 +1.21325 -0.281982421875 -0.48150634765625 0.41434936523436966 +1.213375 -0.281982421875 -0.48150634765625 0.41434936523436966 +1.2135 -0.28277587890625 -0.48291015625 0.41434936523436966 +1.213625 -0.2835693359375 -0.484222412109375 0.41434936523436966 +1.21375 -0.2835693359375 -0.484222412109375 0.41434936523436966 +1.213875 -0.2843017578125 -0.485504150390625 0.41434936523436966 +1.214 -0.2843017578125 -0.485504150390625 0.41434936523436966 +1.2141250000000002 -0.2850341796875 -0.486724853515625 0.41434936523436966 +1.21425 -0.28570556640625 -0.487884521484375 0.41434936523436966 +1.214375 -0.28570556640625 -0.487884521484375 0.41434936523436966 +1.2145000000000002 -0.286346435546875 -0.489013671875 0.41434936523436966 +1.214625 -0.286346435546875 -0.489013671875 0.41434936523436966 +1.21475 -0.2869873046875 -0.490081787109375 0.41434936523436966 +1.214875 -0.287567138671875 -0.4910888671875 0.41434936523436966 +1.215 -0.287567138671875 -0.4910888671875 0.41434936523436966 +1.215125 -0.28814697265625 -0.492034912109375 0.41434936523436966 +1.21525 -0.28814697265625 -0.492034912109375 0.41434936523436966 +1.215375 -0.288665771484375 -0.492950439453125 0.41434936523436966 +1.2155 -0.289154052734375 -0.4937744140625 0.41434936523436966 +1.215625 -0.289154052734375 -0.4937744140625 0.41434936523436966 +1.21575 -0.28961181640625 -0.49456787109375 0.41434936523436966 +1.215875 -0.28961181640625 -0.49456787109375 0.41434936523436966 +1.216 -0.48284912109375 -0.49530029296875 0.025122070312493812 +1.2161250000000002 -0.4835205078125 -0.496002197265625 0.025122070312493812 +1.21625 -0.4835205078125 -0.496002197265625 0.025122070312493812 +1.216375 -0.484130859375 -0.496612548828125 0.025122070312493812 +1.2165 -0.484130859375 -0.496612548828125 0.025122070312493812 +1.216625 -0.48468017578125 -0.4971923828125 0.025122070312493812 +1.21675 -0.485198974609375 -0.497711181640625 0.025122070312493812 +1.216875 -0.485198974609375 -0.497711181640625 0.025122070312493812 +1.217 -0.48565673828125 -0.498199462890625 0.025122070312493812 +1.217125 -0.48565673828125 -0.498199462890625 0.025122070312493812 +1.21725 -0.486053466796875 -0.49859619140625 0.025122070312493812 +1.217375 -0.48638916015625 -0.49896240234375 0.025122070312493812 +1.2175 -0.48638916015625 -0.49896240234375 0.025122070312493812 +1.217625 -0.4866943359375 -0.499267578125 0.025122070312493812 +1.21775 -0.4866943359375 -0.499267578125 0.025122070312493812 +1.217875 -0.4869384765625 -0.49951171875 0.025122070312493812 +1.218 -0.48712158203125 -0.49969482421875 0.025122070312493812 +1.2181250000000002 -0.48712158203125 -0.49969482421875 0.025122070312493812 +1.21825 -0.48724365234375 -0.49981689453125 0.025122070312493812 +1.218375 -0.48724365234375 -0.49981689453125 0.025122070312493812 +1.2185 -0.487335205078125 -0.499908447265625 0.025122070312493812 +1.218625 -0.48736572265625 -0.49993896484375 0.025122070312493812 +1.21875 -0.48736572265625 -0.49993896484375 0.025122070312493812 +1.218875 -0.487335205078125 -0.499908447265625 0.025122070312493812 +1.219 -0.487335205078125 -0.499908447265625 0.025122070312493812 +1.219125 -0.48724365234375 -0.49981689453125 0.025122070312493812 +1.21925 -0.48712158203125 -0.49969482421875 0.025122070312493812 +1.219375 -0.48712158203125 -0.49969482421875 0.025122070312493812 +1.2195 -0.4869384765625 -0.49951171875 0.025122070312493812 +1.219625 -0.4869384765625 -0.49951171875 0.025122070312493812 +1.2197500000000002 -0.4866943359375 -0.499267578125 0.025122070312493812 +1.219875 -0.48638916015625 -0.49896240234375 0.025122070312493812 +1.22 -0.48638916015625 -0.49896240234375 0.025122070312493812 +1.2201250000000002 -0.486053466796875 -0.49859619140625 0.025122070312493812 +1.22025 -0.486053466796875 -0.49859619140625 0.025122070312493812 +1.220375 -0.48565673828125 -0.498199462890625 0.025122070312493812 +1.2205 -0.485198974609375 -0.497711181640625 0.025122070312493812 +1.220625 -0.485198974609375 -0.497711181640625 0.025122070312493812 +1.22075 -0.48468017578125 -0.4971923828125 0.025122070312493812 +1.220875 -0.48468017578125 -0.4971923828125 0.025122070312493812 +1.221 -0.484130859375 -0.496612548828125 0.025122070312493812 +1.221125 -0.4835205078125 -0.496002197265625 0.025122070312493812 +1.22125 -0.4835205078125 -0.496002197265625 0.025122070312493812 +1.221375 -0.48284912109375 -0.49530029296875 0.025122070312493812 +1.2215 -0.48284912109375 -0.49530029296875 0.025122070312493812 +1.221625 -0.48211669921875 -0.49456787109375 0.025122070312493812 +1.2217500000000002 -0.481353759765625 -0.4937744140625 0.025122070312493812 +1.221875 -0.481353759765625 -0.4937744140625 0.025122070312493812 +1.222 -0.48052978515625 -0.492950439453125 0.025122070312493812 +1.2221250000000002 -0.48052978515625 -0.492950439453125 0.025122070312493812 +1.22225 -0.47967529296875 -0.492034912109375 0.025122070312493812 +1.222375 -0.478729248046875 -0.4910888671875 0.025122070312493812 +1.2225 -0.478729248046875 -0.4910888671875 0.025122070312493812 +1.222625 -0.477752685546875 -0.490081787109375 0.025122070312493812 +1.22275 -0.477752685546875 -0.490081787109375 0.025122070312493812 +1.222875 -0.476715087890625 -0.489013671875 0.025122070312493812 +1.223 -0.475616455078125 -0.487884521484375 0.025122070312493812 +1.223125 -0.475616455078125 -0.487884521484375 0.025122070312493812 +1.22325 -0.4744873046875 -0.486724853515625 0.025122070312493812 +1.223375 -0.4744873046875 -0.486724853515625 0.025122070312493812 +1.2235 -0.473297119140625 -0.485504150390625 0.025122070312493812 +1.223625 -0.4720458984375 -0.484222412109375 0.025122070312493812 +1.2237500000000002 -0.4720458984375 -0.484222412109375 0.025122070312493812 +1.223875 -0.47076416015625 -0.48291015625 0.025122070312493812 +1.224 -0.47076416015625 -0.48291015625 0.025122070312493812 +1.2241250000000002 -0.469390869140625 -0.48150634765625 0.025122070312493812 +1.22425 -0.467987060546875 -0.480072021484375 0.025122070312493812 +1.224375 -0.467987060546875 -0.480072021484375 0.025122070312493812 +1.2245 -0.466552734375 -0.478607177734375 0.025122070312493812 +1.224625 -0.466552734375 -0.478607177734375 0.025122070312493812 +1.22475 -0.465057373046875 -0.47705078125 0.025122070312493812 +1.224875 -0.4635009765625 -0.4754638671875 0.025122070312493812 +1.225 -0.4635009765625 -0.4754638671875 0.025122070312493812 +1.225125 -0.4619140625 -0.47381591796875 0.025122070312493812 +1.22525 -0.4619140625 -0.47381591796875 0.025122070312493812 +1.225375 -0.460235595703125 -0.472137451171875 0.025122070312493812 +1.2255 -0.458526611328125 -0.470367431640625 0.025122070312493812 +1.225625 -0.458526611328125 -0.470367431640625 0.025122070312493812 +1.2257500000000002 -0.456787109375 -0.46856689453125 0.025122070312493812 +1.225875 -0.456787109375 -0.46856689453125 0.025122070312493812 +1.226 -0.454986572265625 -0.46673583984375 0.025122070312493812 +1.2261250000000002 -0.453125 -0.464813232421875 0.025122070312493812 +1.22625 -0.453125 -0.464813232421875 0.025122070312493812 +1.226375 -0.45123291015625 -0.462890625 0.025122070312493812 +1.2265 -0.45123291015625 -0.462890625 0.025122070312493812 +1.226625 -0.44927978515625 -0.46087646484375 0.025122070312493812 +1.22675 -0.447265625 -0.458831787109375 0.025122070312493812 +1.226875 -0.447265625 -0.458831787109375 0.025122070312493812 +1.227 -0.445220947265625 -0.45672607421875 0.025122070312493812 +1.227125 -0.445220947265625 -0.45672607421875 0.025122070312493812 +1.22725 -0.443115234375 -0.454559326171875 0.025122070312493812 +1.227375 -0.44097900390625 -0.452362060546875 0.025122070312493812 +1.2275 -0.44097900390625 -0.452362060546875 0.025122070312493812 +1.227625 -0.43878173828125 -0.450103759765625 0.025122070312493812 +1.2277500000000002 -0.43878173828125 -0.450103759765625 0.025122070312493812 +1.227875 -0.4365234375 -0.447784423828125 0.025122070312493812 +1.228 -0.434234619140625 -0.4454345703125 0.025122070312493812 +1.2281250000000002 -0.434234619140625 -0.4454345703125 0.025122070312493812 +1.22825 -0.431915283203125 -0.44305419921875 0.025122070312493812 +1.228375 -0.431915283203125 -0.44305419921875 0.025122070312493812 +1.2285 -0.42950439453125 -0.440582275390625 0.025122070312493812 +1.228625 -0.42706298828125 -0.438079833984375 0.025122070312493812 +1.22875 -0.42706298828125 -0.438079833984375 0.025122070312493812 +1.228875 -0.424591064453125 -0.435546875 0.025122070312493812 +1.229 -0.424591064453125 -0.435546875 0.025122070312493812 +1.229125 -0.42205810546875 -0.432952880859375 0.025122070312493812 +1.22925 -0.41949462890625 -0.4302978515625 0.025122070312493812 +1.229375 -0.41949462890625 -0.4302978515625 0.025122070312493812 +1.2295 -0.4168701171875 -0.4276123046875 0.025122070312493812 +1.229625 -0.4168701171875 -0.4276123046875 0.025122070312493812 +1.2297500000000002 -0.414215087890625 -0.424896240234375 0.025122070312493812 +1.229875 -0.4114990234375 -0.422119140625 0.025122070312493812 +1.23 -0.4114990234375 -0.422119140625 0.025122070312493812 +1.2301250000000002 -0.408721923828125 -0.419281005859375 0.025122070312493812 +1.23025 -0.408721923828125 -0.419281005859375 0.025122070312493812 +1.230375 -0.40594482421875 -0.416412353515625 0.025122070312493812 +1.2305 -0.403076171875 -0.413482666015625 0.025122070312493812 +1.230625 -0.403076171875 -0.413482666015625 0.025122070312493812 +1.23075 -0.400177001953125 -0.4105224609375 0.025122070312493812 +1.230875 -0.400177001953125 -0.4105224609375 0.025122070312493812 +1.231 -0.397247314453125 -0.407501220703125 0.025122070312493812 +1.231125 -0.394287109375 -0.404449462890625 0.025122070312493812 +1.23125 -0.394287109375 -0.404449462890625 0.025122070312493812 +1.231375 -0.3912353515625 -0.401336669921875 0.025122070312493812 +1.2315 -0.3912353515625 -0.401336669921875 0.025122070312493812 +1.231625 -0.38818359375 -0.398193359375 0.025122070312493812 +1.2317500000000002 -0.385101318359375 -0.39501953125 0.025122070312493812 +1.231875 -0.385101318359375 -0.39501953125 0.025122070312493812 +1.232 -0.381927490234375 -0.39178466796875 0.025122070312493812 +1.232125 -0.381927490234375 -0.39178466796875 0.025122070312493812 +1.23225 -0.378753662109375 -0.388519287109375 0.025122070312493812 +1.232375 -0.375518798828125 -0.38519287109375 0.025122070312493812 +1.2325 -0.375518798828125 -0.38519287109375 0.025122070312493812 +1.232625 -0.37225341796875 -0.3818359375 0.025122070312493812 +1.23275 -0.37225341796875 -0.3818359375 0.025122070312493812 +1.232875 -0.368927001953125 -0.378448486328125 0.025122070312493812 +1.233 -0.365570068359375 -0.375 0.025122070312493812 +1.233125 -0.365570068359375 -0.375 0.025122070312493812 +1.23325 -0.3621826171875 -0.37152099609375 0.025122070312493812 +1.233375 -0.3621826171875 -0.37152099609375 0.025122070312493812 +1.2335 -0.358734130859375 -0.36798095703125 0.025122070312493812 +1.233625 -0.355255126953125 -0.36444091796875 0.025122070312493812 +1.2337500000000002 -0.355255126953125 -0.36444091796875 0.025122070312493812 +1.233875 -0.35174560546875 -0.360809326171875 0.025122070312493812 +1.234 -0.35174560546875 -0.360809326171875 0.025122070312493812 +1.234125 -0.34820556640625 -0.357177734375 0.025122070312493812 +1.23425 -0.3446044921875 -0.353485107421875 0.025122070312493812 +1.234375 -0.3446044921875 -0.353485107421875 0.025122070312493812 +1.2345 -0.340972900390625 -0.349761962890625 0.025122070312493812 +1.234625 -0.340972900390625 -0.349761962890625 0.025122070312493812 +1.23475 -0.337310791015625 -0.34600830078125 0.025122070312493812 +1.234875 -0.3336181640625 -0.34222412109375 0.025122070312493812 +1.235 -0.3336181640625 -0.34222412109375 0.025122070312493812 +1.235125 -0.329864501953125 -0.33837890625 0.025122070312493812 +1.23525 -0.329864501953125 -0.33837890625 0.025122070312493812 +1.2353750000000002 -0.32611083984375 -0.334503173828125 0.025122070312493812 +1.2355 -0.322296142578125 -0.330596923828125 0.025122070312493812 +1.235625 -0.322296142578125 -0.330596923828125 0.025122070312493812 +1.2357500000000002 -0.318450927734375 -0.32666015625 0.025122070312493812 +1.235875 -0.318450927734375 -0.32666015625 0.025122070312493812 +1.236 -0.314544677734375 -0.322662353515625 0.025122070312493812 +1.236125 -0.310638427734375 -0.31866455078125 0.025122070312493812 +1.23625 -0.310638427734375 -0.31866455078125 0.025122070312493812 +1.236375 -0.30670166015625 -0.314605712890625 0.025122070312493812 +1.2365 -0.30670166015625 -0.314605712890625 0.025122070312493812 +1.236625 -0.302703857421875 -0.310516357421875 0.025122070312493812 +1.23675 -0.2987060546875 -0.306396484375 0.025122070312493812 +1.236875 -0.2987060546875 -0.306396484375 0.025122070312493812 +1.237 -0.294647216796875 -0.30224609375 0.025122070312493812 +1.237125 -0.294647216796875 -0.30224609375 0.025122070312493812 +1.23725 -0.290557861328125 -0.298065185546875 0.025122070312493812 +1.2373750000000002 -0.28643798828125 -0.2938232421875 0.025122070312493812 +1.2375 -0.28643798828125 -0.2938232421875 0.025122070312493812 +1.237625 -0.282318115234375 -0.289581298828125 0.025122070312493812 +1.2377500000000002 -0.282318115234375 -0.289581298828125 0.025122070312493812 +1.237875 -0.27813720703125 -0.285308837890625 0.025122070312493812 +1.238 -0.27392578125 -0.280975341796875 0.025122070312493812 +1.238125 -0.27392578125 -0.280975341796875 0.025122070312493812 +1.23825 -0.269683837890625 -0.276641845703125 0.025122070312493812 +1.238375 -0.269683837890625 -0.276641845703125 0.025122070312493812 +1.2385 -0.26544189453125 -0.27227783203125 0.025122070312493812 +1.238625 -0.261138916015625 -0.267852783203125 0.025122070312493812 +1.23875 -0.261138916015625 -0.267852783203125 0.025122070312493812 +1.238875 -0.256805419921875 -0.263427734375 0.025122070312493812 +1.239 -0.256805419921875 -0.263427734375 0.025122070312493812 +1.239125 -0.252471923828125 -0.25897216796875 0.025122070312493812 +1.23925 -0.248077392578125 -0.25445556640625 0.025122070312493812 +1.2393750000000002 -0.248077392578125 -0.25445556640625 0.025122070312493812 +1.2395 -0.243682861328125 -0.249969482421875 0.025122070312493812 +1.239625 -0.243682861328125 -0.249969482421875 0.025122070312493812 +1.2397500000000002 -0.239227294921875 -0.24542236328125 0.025122070312493812 +1.239875 -0.234771728515625 -0.2408447265625 0.025122070312493812 +1.24 -0.234771728515625 -0.2408447265625 0.025122070312493812 +1.240125 -0.23028564453125 -0.236236572265625 0.025122070312493812 +1.24025 -0.23028564453125 -0.236236572265625 0.025122070312493812 +1.240375 -0.22576904296875 -0.231597900390625 0.025122070312493812 +1.2405 -0.22125244140625 -0.226959228515625 0.025122070312493812 +1.240625 -0.22125244140625 -0.226959228515625 0.025122070312493812 +1.24075 -0.2166748046875 -0.2222900390625 0.025122070312493812 +1.240875 -0.2166748046875 -0.2222900390625 0.025122070312493812 +1.241 -0.21209716796875 -0.21759033203125 0.025122070312493812 +1.241125 -0.207489013671875 -0.212860107421875 0.025122070312493812 +1.24125 -0.207489013671875 -0.212860107421875 0.025122070312493812 +1.2413750000000002 -0.202880859375 -0.208099365234375 0.025122070312493812 +1.2415 -0.202880859375 -0.208099365234375 0.025122070312493812 +1.241625 -0.198211669921875 -0.203338623046875 0.025122070312493812 +1.2417500000000002 -0.19354248046875 -0.19854736328125 0.025122070312493812 +1.241875 -0.19354248046875 -0.19854736328125 0.025122070312493812 +1.242 -0.1888427734375 -0.1937255859375 0.025122070312493812 +1.242125 -0.1888427734375 -0.1937255859375 0.025122070312493812 +1.24225 -0.184112548828125 -0.188873291015625 0.025122070312493812 +1.242375 -0.17938232421875 -0.18402099609375 0.025122070312493812 +1.2425 -0.17938232421875 -0.18402099609375 0.025122070312493812 +1.242625 -0.174652099609375 -0.17913818359375 0.025122070312493812 +1.24275 -0.174652099609375 -0.17913818359375 0.025122070312493812 +1.242875 -0.16986083984375 -0.17425537109375 0.025122070312493812 +1.243 -0.165069580078125 -0.169342041015625 0.025122070312493812 +1.243125 -0.165069580078125 -0.169342041015625 0.025122070312493812 +1.24325 -0.160247802734375 -0.164398193359375 0.025122070312493812 +1.2433750000000002 -0.160247802734375 -0.164398193359375 0.025122070312493812 +1.2435 -0.155426025390625 -0.159454345703125 0.025122070312493812 +1.243625 -0.15057373046875 -0.15447998046875 0.025122070312493812 +1.2437500000000002 -0.15057373046875 -0.15447998046875 0.025122070312493812 +1.243875 -0.145721435546875 -0.14947509765625 0.025122070312493812 +1.244 -0.145721435546875 -0.14947509765625 0.025122070312493812 +1.244125 -0.140838623046875 -0.14447021484375 0.025122070312493812 +1.24425 -0.135955810546875 -0.13946533203125 0.025122070312493812 +1.244375 -0.135955810546875 -0.13946533203125 0.025122070312493812 +1.2445 -0.13104248046875 -0.134429931640625 0.025122070312493812 +1.244625 -0.13104248046875 -0.134429931640625 0.025122070312493812 +1.24475 -0.126129150390625 -0.129364013671875 0.025122070312493812 +1.244875 -0.121185302734375 -0.124298095703125 0.025122070312493812 +1.245 -0.121185302734375 -0.124298095703125 0.025122070312493812 +1.245125 -0.116241455078125 -0.119232177734375 0.025122070312493812 +1.24525 -0.116241455078125 -0.119232177734375 0.025122070312493812 +1.2453750000000002 -0.11126708984375 -0.1141357421875 0.025122070312493812 +1.2455 -0.106292724609375 -0.109039306640625 0.025122070312493812 +1.245625 -0.106292724609375 -0.109039306640625 0.025122070312493812 +1.2457500000000002 -0.101318359375 -0.103912353515625 0.025122070312493812 +1.245875 -0.101318359375 -0.103912353515625 0.025122070312493812 +1.246 -0.0963134765625 -0.098785400390625 0.025122070312493812 +1.246125 -0.09130859375 -0.093658447265625 0.025122070312493812 +1.24625 -0.09130859375 -0.093658447265625 0.025122070312493812 +1.246375 -0.086273193359375 -0.0885009765625 0.025122070312493812 +1.2465 -0.086273193359375 -0.0885009765625 0.025122070312493812 +1.246625 -0.081268310546875 -0.083343505859375 0.025122070312493812 +1.24675 -0.076202392578125 -0.07818603515625 0.025122070312493812 +1.246875 -0.076202392578125 -0.07818603515625 0.025122070312493812 +1.247 -0.0711669921875 -0.072998046875 0.025122070312493812 +1.247125 -0.0711669921875 -0.072998046875 0.025122070312493812 +1.24725 -0.06610107421875 -0.06781005859375 0.025122070312493812 +1.2473750000000002 -0.061065673828125 -0.0626220703125 0.025122070312493812 +1.2475 -0.061065673828125 -0.0626220703125 0.025122070312493812 +1.247625 -0.055999755859375 -0.05743408203125 0.025122070312493812 +1.2477500000000002 -0.055999755859375 -0.05743408203125 0.025122070312493812 +1.247875 -0.050933837890625 -0.05224609375 0.025122070312493812 +1.248 -0.047027587890625 -0.029693603515625 -0.3681030273437555 +1.248125 -0.047027587890625 -0.029693603515625 -0.3681030273437555 +1.24825 -0.04180908203125 -0.026397705078125 -0.3681030273437555 +1.248375 -0.04180908203125 -0.026397705078125 -0.3681030273437555 +1.2485 -0.036590576171875 -0.023101806640625 -0.3681030273437555 +1.248625 -0.0313720703125 -0.019805908203125 -0.3681030273437555 +1.24875 -0.0313720703125 -0.019805908203125 -0.3681030273437555 +1.248875 -0.026123046875 -0.016510009765625 -0.3681030273437555 +1.249 -0.026123046875 -0.016510009765625 -0.3681030273437555 +1.249125 -0.020904541015625 -0.013214111328125 -0.3681030273437555 +1.24925 -0.01568603515625 -0.009918212890625 -0.3681030273437555 +1.2493750000000002 -0.01568603515625 -0.009918212890625 -0.3681030273437555 +1.2495 -0.01043701171875 -0.006591796875 -0.3681030273437555 +1.249625 -0.01043701171875 -0.006591796875 -0.3681030273437555 +1.24975 -0.005218505859375 -0.0032958984375 -0.3681030273437555 +1.249875 0.0 0.0 -0.3681030273437555 +1.25 0.0 0.0 -0.3681030273437555 +1.250125 0.005218505859375 0.0032958984375 -0.3681030273437555 +1.25025 0.005218505859375 0.0032958984375 -0.3681030273437555 +1.250375 0.01043701171875 0.006591796875 -0.3681030273437555 +1.2505 0.01568603515625 0.009918212890625 -0.3681030273437555 +1.250625 0.01568603515625 0.009918212890625 -0.3681030273437555 +1.25075 0.020904541015625 0.013214111328125 -0.3681030273437555 +1.250875 0.020904541015625 0.013214111328125 -0.3681030273437555 +1.2510000000000002 0.026123046875 0.016510009765625 -0.3681030273437555 +1.251125 0.0313720703125 0.019805908203125 -0.3681030273437555 +1.25125 0.0313720703125 0.019805908203125 -0.3681030273437555 +1.2513750000000002 0.036590576171875 0.023101806640625 -0.3681030273437555 +1.2515 0.036590576171875 0.023101806640625 -0.3681030273437555 +1.251625 0.04180908203125 0.026397705078125 -0.3681030273437555 +1.25175 0.047027587890625 0.029693603515625 -0.3681030273437555 +1.251875 0.047027587890625 0.029693603515625 -0.3681030273437555 +1.252 0.05224609375 0.032989501953125 -0.3681030273437555 +1.252125 0.05224609375 0.032989501953125 -0.3681030273437555 +1.25225 0.05743408203125 0.036285400390625 -0.3681030273437555 +1.252375 0.0626220703125 0.039581298828125 -0.3681030273437555 +1.2525 0.0626220703125 0.039581298828125 -0.3681030273437555 +1.252625 0.06781005859375 0.0428466796875 -0.3681030273437555 +1.25275 0.06781005859375 0.0428466796875 -0.3681030273437555 +1.252875 0.072998046875 0.046112060546875 -0.3681030273437555 +1.2530000000000002 0.07818603515625 0.049407958984375 -0.3681030273437555 +1.253125 0.07818603515625 0.049407958984375 -0.3681030273437555 +1.25325 0.083343505859375 0.05267333984375 -0.3681030273437555 +1.2533750000000002 0.083343505859375 0.05267333984375 -0.3681030273437555 +1.2535 0.0885009765625 0.055908203125 -0.3681030273437555 +1.253625 0.093658447265625 0.059173583984375 -0.3681030273437555 +1.25375 0.093658447265625 0.059173583984375 -0.3681030273437555 +1.253875 0.098785400390625 0.062408447265625 -0.3681030273437555 +1.254 0.098785400390625 0.062408447265625 -0.3681030273437555 +1.254125 0.103912353515625 0.065643310546875 -0.3681030273437555 +1.25425 0.109039306640625 0.068878173828125 -0.3681030273437555 +1.254375 0.109039306640625 0.068878173828125 -0.3681030273437555 +1.2545 0.1141357421875 0.072113037109375 -0.3681030273437555 +1.254625 0.1141357421875 0.072113037109375 -0.3681030273437555 +1.25475 0.119232177734375 0.075347900390625 -0.3681030273437555 +1.254875 0.124298095703125 0.078521728515625 -0.3681030273437555 +1.2550000000000002 0.124298095703125 0.078521728515625 -0.3681030273437555 +1.255125 0.129364013671875 0.08172607421875 -0.3681030273437555 +1.25525 0.129364013671875 0.08172607421875 -0.3681030273437555 +1.2553750000000002 0.134429931640625 0.084930419921875 -0.3681030273437555 +1.2555 0.13946533203125 0.088104248046875 -0.3681030273437555 +1.255625 0.13946533203125 0.088104248046875 -0.3681030273437555 +1.25575 0.14447021484375 0.091278076171875 -0.3681030273437555 +1.255875 0.14447021484375 0.091278076171875 -0.3681030273437555 +1.256 0.14947509765625 0.094451904296875 -0.3681030273437555 +1.256125 0.15447998046875 0.09759521484375 -0.3681030273437555 +1.25625 0.15447998046875 0.09759521484375 -0.3681030273437555 +1.256375 0.159454345703125 0.100738525390625 -0.3681030273437555 +1.2565 0.159454345703125 0.100738525390625 -0.3681030273437555 +1.256625 0.164398193359375 0.103851318359375 -0.3681030273437555 +1.25675 0.169342041015625 0.10699462890625 -0.3681030273437555 +1.256875 0.169342041015625 0.10699462890625 -0.3681030273437555 +1.2570000000000002 0.17425537109375 0.110076904296875 -0.3681030273437555 +1.257125 0.17425537109375 0.110076904296875 -0.3681030273437555 +1.25725 0.17913818359375 0.113189697265625 -0.3681030273437555 +1.2573750000000002 0.18402099609375 0.11627197265625 -0.3681030273437555 +1.2575 0.18402099609375 0.11627197265625 -0.3681030273437555 +1.257625 0.188873291015625 0.11932373046875 -0.3681030273437555 +1.25775 0.188873291015625 0.11932373046875 -0.3681030273437555 +1.257875 0.1937255859375 0.122406005859375 -0.3681030273437555 +1.258 0.19854736328125 0.12542724609375 -0.3681030273437555 +1.258125 0.19854736328125 0.12542724609375 -0.3681030273437555 +1.25825 0.203338623046875 0.12847900390625 -0.3681030273437555 +1.258375 0.203338623046875 0.12847900390625 -0.3681030273437555 +1.2585 0.208099365234375 0.1314697265625 -0.3681030273437555 +1.258625 0.212860107421875 0.134490966796875 -0.3681030273437555 +1.25875 0.212860107421875 0.134490966796875 -0.3681030273437555 +1.258875 0.21759033203125 0.137481689453125 -0.3681030273437555 +1.2590000000000002 0.21759033203125 0.137481689453125 -0.3681030273437555 +1.259125 0.2222900390625 0.14044189453125 -0.3681030273437555 +1.25925 0.226959228515625 0.143402099609375 -0.3681030273437555 +1.2593750000000002 0.226959228515625 0.143402099609375 -0.3681030273437555 +1.2595 0.231597900390625 0.146331787109375 -0.3681030273437555 +1.259625 0.231597900390625 0.146331787109375 -0.3681030273437555 +1.25975 0.236236572265625 0.149261474609375 -0.3681030273437555 +1.259875 0.2408447265625 0.15216064453125 -0.3681030273437555 +1.26 0.2408447265625 0.15216064453125 -0.3681030273437555 +1.260125 0.24542236328125 0.155059814453125 -0.3681030273437555 +1.26025 0.24542236328125 0.155059814453125 -0.3681030273437555 +1.260375 0.249969482421875 0.157928466796875 -0.3681030273437555 +1.2605 0.25445556640625 0.1607666015625 -0.3681030273437555 +1.260625 0.25445556640625 0.1607666015625 -0.3681030273437555 +1.26075 0.25897216796875 0.16363525390625 -0.3681030273437555 +1.260875 0.25897216796875 0.16363525390625 -0.3681030273437555 +1.2610000000000002 0.263427734375 0.16644287109375 -0.3681030273437555 +1.261125 0.267852783203125 0.16925048828125 -0.3681030273437555 +1.26125 0.267852783203125 0.16925048828125 -0.3681030273437555 +1.2613750000000002 0.27227783203125 0.172027587890625 -0.3681030273437555 +1.2615 0.27227783203125 0.172027587890625 -0.3681030273437555 +1.261625 0.276641845703125 0.174774169921875 -0.3681030273437555 +1.26175 0.280975341796875 0.177520751953125 -0.3681030273437555 +1.261875 0.280975341796875 0.177520751953125 -0.3681030273437555 +1.262 0.285308837890625 0.180267333984375 -0.3681030273437555 +1.262125 0.285308837890625 0.180267333984375 -0.3681030273437555 +1.26225 0.289581298828125 0.1829833984375 -0.3681030273437555 +1.262375 0.2938232421875 0.185638427734375 -0.3681030273437555 +1.2625 0.2938232421875 0.185638427734375 -0.3681030273437555 +1.262625 0.298065185546875 0.188323974609375 -0.3681030273437555 +1.26275 0.298065185546875 0.188323974609375 -0.3681030273437555 +1.262875 0.30224609375 0.19097900390625 -0.3681030273437555 +1.2630000000000002 0.306396484375 0.193603515625 -0.3681030273437555 +1.263125 0.306396484375 0.193603515625 -0.3681030273437555 +1.26325 0.310516357421875 0.196197509765625 -0.3681030273437555 +1.2633750000000002 0.310516357421875 0.196197509765625 -0.3681030273437555 +1.2635 0.314605712890625 0.198760986328125 -0.3681030273437555 +1.263625 0.31866455078125 0.201324462890625 -0.3681030273437555 +1.26375 0.31866455078125 0.201324462890625 -0.3681030273437555 +1.263875 0.322662353515625 0.203887939453125 -0.3681030273437555 +1.264 0.322662353515625 0.203887939453125 -0.3681030273437555 +1.264125 0.32666015625 0.206390380859375 -0.3681030273437555 +1.26425 0.330596923828125 0.208892822265625 -0.3681030273437555 +1.264375 0.330596923828125 0.208892822265625 -0.3681030273437555 +1.2645 0.334503173828125 0.21136474609375 -0.3681030273437555 +1.264625 0.334503173828125 0.21136474609375 -0.3681030273437555 +1.26475 0.33837890625 0.21380615234375 -0.3681030273437555 +1.264875 0.34222412109375 0.216217041015625 -0.3681030273437555 +1.2650000000000002 0.34222412109375 0.216217041015625 -0.3681030273437555 +1.265125 0.34600830078125 0.2186279296875 -0.3681030273437555 +1.26525 0.34600830078125 0.2186279296875 -0.3681030273437555 +1.265375 0.349761962890625 0.22100830078125 -0.3681030273437555 +1.2655 0.353485107421875 0.223358154296875 -0.3681030273437555 +1.265625 0.353485107421875 0.223358154296875 -0.3681030273437555 +1.26575 0.357177734375 0.225677490234375 -0.3681030273437555 +1.265875 0.357177734375 0.225677490234375 -0.3681030273437555 +1.266 0.360809326171875 0.22796630859375 -0.3681030273437555 +1.266125 0.36444091796875 0.230255126953125 -0.3681030273437555 +1.26625 0.36444091796875 0.230255126953125 -0.3681030273437555 +1.266375 0.36798095703125 0.232513427734375 -0.3681030273437555 +1.2665 0.36798095703125 0.232513427734375 -0.3681030273437555 +1.2666250000000002 0.37152099609375 0.2347412109375 -0.3681030273437555 +1.26675 0.375 0.2369384765625 -0.3681030273437555 +1.266875 0.375 0.2369384765625 -0.3681030273437555 +1.2670000000000002 0.378448486328125 0.239105224609375 -0.3681030273437555 +1.267125 0.378448486328125 0.239105224609375 -0.3681030273437555 +1.26725 0.3818359375 0.24127197265625 -0.3681030273437555 +1.267375 0.38519287109375 0.243377685546875 -0.3681030273437555 +1.2675 0.38519287109375 0.243377685546875 -0.3681030273437555 +1.267625 0.388519287109375 0.2454833984375 -0.3681030273437555 +1.26775 0.388519287109375 0.2454833984375 -0.3681030273437555 +1.267875 0.39178466796875 0.24755859375 -0.3681030273437555 +1.268 0.39501953125 0.249603271484375 -0.3681030273437555 +1.268125 0.39501953125 0.249603271484375 -0.3681030273437555 +1.26825 0.398193359375 0.2515869140625 -0.3681030273437555 +1.268375 0.398193359375 0.2515869140625 -0.3681030273437555 +1.2685 0.401336669921875 0.253570556640625 -0.3681030273437555 +1.2686250000000002 0.404449462890625 0.25555419921875 -0.3681030273437555 +1.26875 0.404449462890625 0.25555419921875 -0.3681030273437555 +1.268875 0.407501220703125 0.257476806640625 -0.3681030273437555 +1.2690000000000002 0.407501220703125 0.257476806640625 -0.3681030273437555 +1.269125 0.4105224609375 0.259368896484375 -0.3681030273437555 +1.26925 0.413482666015625 0.26123046875 -0.3681030273437555 +1.269375 0.413482666015625 0.26123046875 -0.3681030273437555 +1.2695 0.416412353515625 0.263092041015625 -0.3681030273437555 +1.269625 0.416412353515625 0.263092041015625 -0.3681030273437555 +1.26975 0.419281005859375 0.264923095703125 -0.3681030273437555 +1.269875 0.422119140625 0.266693115234375 -0.3681030273437555 +1.27 0.422119140625 0.266693115234375 -0.3681030273437555 +1.270125 0.424896240234375 0.268463134765625 -0.3681030273437555 +1.27025 0.424896240234375 0.268463134765625 -0.3681030273437555 +1.270375 0.4276123046875 0.270172119140625 -0.3681030273437555 +1.2705 0.4302978515625 0.271881103515625 -0.3681030273437555 +1.2706250000000002 0.4302978515625 0.271881103515625 -0.3681030273437555 +1.27075 0.432952880859375 0.2735595703125 -0.3681030273437555 +1.270875 0.432952880859375 0.2735595703125 -0.3681030273437555 +1.2710000000000002 0.435546875 0.27520751953125 -0.3681030273437555 +1.271125 0.438079833984375 0.27679443359375 -0.3681030273437555 +1.27125 0.438079833984375 0.27679443359375 -0.3681030273437555 +1.271375 0.440582275390625 0.27838134765625 -0.3681030273437555 +1.2715 0.440582275390625 0.27838134765625 -0.3681030273437555 +1.271625 0.44305419921875 0.279937744140625 -0.3681030273437555 +1.27175 0.4454345703125 0.28143310546875 -0.3681030273437555 +1.271875 0.4454345703125 0.28143310546875 -0.3681030273437555 +1.272 0.447784423828125 0.282928466796875 -0.3681030273437555 +1.272125 0.447784423828125 0.282928466796875 -0.3681030273437555 +1.27225 0.450103759765625 0.284393310546875 -0.3681030273437555 +1.272375 0.452362060546875 0.285797119140625 -0.3681030273437555 +1.2725 0.452362060546875 0.285797119140625 -0.3681030273437555 +1.2726250000000002 0.454559326171875 0.287200927734375 -0.3681030273437555 +1.27275 0.454559326171875 0.287200927734375 -0.3681030273437555 +1.272875 0.45672607421875 0.28857421875 -0.3681030273437555 +1.2730000000000002 0.458831787109375 0.289886474609375 -0.3681030273437555 +1.273125 0.458831787109375 0.289886474609375 -0.3681030273437555 +1.27325 0.46087646484375 0.29119873046875 -0.3681030273437555 +1.273375 0.46087646484375 0.29119873046875 -0.3681030273437555 +1.2735 0.462890625 0.292449951171875 -0.3681030273437555 +1.273625 0.464813232421875 0.293670654296875 -0.3681030273437555 +1.27375 0.464813232421875 0.293670654296875 -0.3681030273437555 +1.273875 0.46673583984375 0.294891357421875 -0.3681030273437555 +1.274 0.46673583984375 0.294891357421875 -0.3681030273437555 +1.274125 0.46856689453125 0.296051025390625 -0.3681030273437555 +1.27425 0.470367431640625 0.29718017578125 -0.3681030273437555 +1.274375 0.470367431640625 0.29718017578125 -0.3681030273437555 +1.2745 0.472137451171875 0.298309326171875 -0.3681030273437555 +1.2746250000000002 0.472137451171875 0.298309326171875 -0.3681030273437555 +1.27475 0.47381591796875 0.29937744140625 -0.3681030273437555 +1.274875 0.4754638671875 0.3004150390625 -0.3681030273437555 +1.2750000000000002 0.4754638671875 0.3004150390625 -0.3681030273437555 +1.275125 0.47705078125 0.301422119140625 -0.3681030273437555 +1.27525 0.47705078125 0.301422119140625 -0.3681030273437555 +1.275375 0.478607177734375 0.302398681640625 -0.3681030273437555 +1.2755 0.480072021484375 0.303314208984375 -0.3681030273437555 +1.275625 0.480072021484375 0.303314208984375 -0.3681030273437555 +1.27575 0.48150634765625 0.304229736328125 -0.3681030273437555 +1.275875 0.48150634765625 0.304229736328125 -0.3681030273437555 +1.276 0.48291015625 0.30511474609375 -0.3681030273437555 +1.276125 0.484222412109375 0.305938720703125 -0.3681030273437555 +1.27625 0.484222412109375 0.305938720703125 -0.3681030273437555 +1.276375 0.485504150390625 0.3067626953125 -0.3681030273437555 +1.2765 0.485504150390625 0.3067626953125 -0.3681030273437555 +1.2766250000000002 0.486724853515625 0.307525634765625 -0.3681030273437555 +1.27675 0.487884521484375 0.308258056640625 -0.3681030273437555 +1.276875 0.487884521484375 0.308258056640625 -0.3681030273437555 +1.2770000000000002 0.489013671875 0.3089599609375 -0.3681030273437555 +1.277125 0.489013671875 0.3089599609375 -0.3681030273437555 +1.27725 0.490081787109375 0.30963134765625 -0.3681030273437555 +1.277375 0.4910888671875 0.310272216796875 -0.3681030273437555 +1.2775 0.4910888671875 0.310272216796875 -0.3681030273437555 +1.277625 0.492034912109375 0.310882568359375 -0.3681030273437555 +1.27775 0.492034912109375 0.310882568359375 -0.3681030273437555 +1.277875 0.492950439453125 0.31146240234375 -0.3681030273437555 +1.278 0.4937744140625 0.311981201171875 -0.3681030273437555 +1.278125 0.4937744140625 0.311981201171875 -0.3681030273437555 +1.27825 0.49456787109375 0.312469482421875 -0.3681030273437555 +1.278375 0.49456787109375 0.312469482421875 -0.3681030273437555 +1.2785 0.49530029296875 0.312957763671875 -0.3681030273437555 +1.2786250000000002 0.496002197265625 0.313385009765625 -0.3681030273437555 +1.27875 0.496002197265625 0.313385009765625 -0.3681030273437555 +1.278875 0.496612548828125 0.31378173828125 -0.3681030273437555 +1.2790000000000002 0.496612548828125 0.31378173828125 -0.3681030273437555 +1.279125 0.4971923828125 0.31414794921875 -0.3681030273437555 +1.27925 0.497711181640625 0.314483642578125 -0.3681030273437555 +1.279375 0.497711181640625 0.314483642578125 -0.3681030273437555 +1.2795 0.498199462890625 0.31475830078125 -0.3681030273437555 +1.279625 0.498199462890625 0.31475830078125 -0.3681030273437555 +1.27975 0.49859619140625 0.315032958984375 -0.3681030273437555 +1.279875 0.49896240234375 0.31524658203125 -0.3681030273437555 +1.28 0.49896240234375 0.148345947265625 -0.7025939941406295 +1.280125 0.499267578125 0.1484375 -0.7025939941406295 +1.28025 0.499267578125 0.1484375 -0.7025939941406295 +1.280375 0.49951171875 0.14849853515625 -0.7025939941406295 +1.2805 0.49969482421875 0.1485595703125 -0.7025939941406295 +1.2806250000000002 0.49969482421875 0.1485595703125 -0.7025939941406295 +1.28075 0.49981689453125 0.148590087890625 -0.7025939941406295 +1.280875 0.49981689453125 0.148590087890625 -0.7025939941406295 +1.281 0.499908447265625 0.14862060546875 -0.7025939941406295 +1.281125 0.49993896484375 0.14862060546875 -0.7025939941406295 +1.28125 0.49993896484375 0.14862060546875 -0.7025939941406295 +1.281375 0.499908447265625 0.14862060546875 -0.7025939941406295 +1.2815 0.499908447265625 0.14862060546875 -0.7025939941406295 +1.281625 0.49981689453125 0.148590087890625 -0.7025939941406295 +1.28175 0.49969482421875 0.1485595703125 -0.7025939941406295 +1.281875 0.49969482421875 0.1485595703125 -0.7025939941406295 +1.282 0.49951171875 0.14849853515625 -0.7025939941406295 +1.282125 0.49951171875 0.14849853515625 -0.7025939941406295 +1.2822500000000002 0.499267578125 0.1484375 -0.7025939941406295 +1.282375 0.49896240234375 0.148345947265625 -0.7025939941406295 +1.2825 0.49896240234375 0.148345947265625 -0.7025939941406295 +1.2826250000000002 0.49859619140625 0.148223876953125 -0.7025939941406295 +1.28275 0.49859619140625 0.148223876953125 -0.7025939941406295 +1.282875 0.498199462890625 0.148101806640625 -0.7025939941406295 +1.283 0.497711181640625 0.147979736328125 -0.7025939941406295 +1.283125 0.497711181640625 0.147979736328125 -0.7025939941406295 +1.28325 0.4971923828125 0.1478271484375 -0.7025939941406295 +1.283375 0.4971923828125 0.1478271484375 -0.7025939941406295 +1.2835 0.496612548828125 0.14764404296875 -0.7025939941406295 +1.283625 0.496002197265625 0.1474609375 -0.7025939941406295 +1.28375 0.496002197265625 0.1474609375 -0.7025939941406295 +1.283875 0.49530029296875 0.147247314453125 -0.7025939941406295 +1.284 0.49530029296875 0.147247314453125 -0.7025939941406295 +1.284125 0.49456787109375 0.14703369140625 -0.7025939941406295 +1.2842500000000002 0.4937744140625 0.14678955078125 -0.7025939941406295 +1.284375 0.4937744140625 0.14678955078125 -0.7025939941406295 +1.2845 0.492950439453125 0.14654541015625 -0.7025939941406295 +1.2846250000000002 0.492950439453125 0.14654541015625 -0.7025939941406295 +1.28475 0.492034912109375 0.146270751953125 -0.7025939941406295 +1.284875 0.4910888671875 0.14599609375 -0.7025939941406295 +1.285 0.4910888671875 0.14599609375 -0.7025939941406295 +1.285125 0.490081787109375 0.14569091796875 -0.7025939941406295 +1.28525 0.490081787109375 0.14569091796875 -0.7025939941406295 +1.285375 0.489013671875 0.1453857421875 -0.7025939941406295 +1.2855 0.487884521484375 0.145050048828125 -0.7025939941406295 +1.285625 0.487884521484375 0.145050048828125 -0.7025939941406295 +1.28575 0.486724853515625 0.14471435546875 -0.7025939941406295 +1.285875 0.486724853515625 0.14471435546875 -0.7025939941406295 +1.286 0.485504150390625 0.14434814453125 -0.7025939941406295 +1.286125 0.484222412109375 0.143951416015625 -0.7025939941406295 +1.2862500000000002 0.484222412109375 0.143951416015625 -0.7025939941406295 +1.286375 0.48291015625 0.1435546875 -0.7025939941406295 +1.2865 0.48291015625 0.1435546875 -0.7025939941406295 +1.2866250000000002 0.48150634765625 0.143157958984375 -0.7025939941406295 +1.28675 0.480072021484375 0.142730712890625 -0.7025939941406295 +1.286875 0.480072021484375 0.142730712890625 -0.7025939941406295 +1.287 0.478607177734375 0.14227294921875 -0.7025939941406295 +1.287125 0.478607177734375 0.14227294921875 -0.7025939941406295 +1.28725 0.47705078125 0.141815185546875 -0.7025939941406295 +1.287375 0.4754638671875 0.141357421875 -0.7025939941406295 +1.2875 0.4754638671875 0.141357421875 -0.7025939941406295 +1.287625 0.47381591796875 0.140869140625 -0.7025939941406295 +1.28775 0.47381591796875 0.140869140625 -0.7025939941406295 +1.287875 0.472137451171875 0.140350341796875 -0.7025939941406295 +1.288 0.470367431640625 0.13983154296875 -0.7025939941406295 +1.288125 0.470367431640625 0.13983154296875 -0.7025939941406295 +1.2882500000000002 0.46856689453125 0.139312744140625 -0.7025939941406295 +1.288375 0.46856689453125 0.139312744140625 -0.7025939941406295 +1.2885 0.46673583984375 0.138763427734375 -0.7025939941406295 +1.2886250000000002 0.464813232421875 0.13818359375 -0.7025939941406295 +1.28875 0.464813232421875 0.13818359375 -0.7025939941406295 +1.288875 0.462890625 0.137603759765625 -0.7025939941406295 +1.289 0.462890625 0.137603759765625 -0.7025939941406295 +1.289125 0.46087646484375 0.13702392578125 -0.7025939941406295 +1.28925 0.458831787109375 0.13641357421875 -0.7025939941406295 +1.289375 0.458831787109375 0.13641357421875 -0.7025939941406295 +1.2895 0.45672607421875 0.135772705078125 -0.7025939941406295 +1.289625 0.45672607421875 0.135772705078125 -0.7025939941406295 +1.28975 0.454559326171875 0.1351318359375 -0.7025939941406295 +1.289875 0.452362060546875 0.134490966796875 -0.7025939941406295 +1.29 0.452362060546875 0.134490966796875 -0.7025939941406295 +1.290125 0.450103759765625 0.133819580078125 -0.7025939941406295 +1.2902500000000002 0.450103759765625 0.133819580078125 -0.7025939941406295 +1.290375 0.447784423828125 0.13311767578125 -0.7025939941406295 +1.2905 0.4454345703125 0.132415771484375 -0.7025939941406295 +1.2906250000000002 0.4454345703125 0.132415771484375 -0.7025939941406295 +1.29075 0.44305419921875 0.1317138671875 -0.7025939941406295 +1.290875 0.44305419921875 0.1317138671875 -0.7025939941406295 +1.291 0.440582275390625 0.1309814453125 -0.7025939941406295 +1.291125 0.438079833984375 0.1302490234375 -0.7025939941406295 +1.29125 0.438079833984375 0.1302490234375 -0.7025939941406295 +1.291375 0.435546875 0.129486083984375 -0.7025939941406295 +1.2915 0.435546875 0.129486083984375 -0.7025939941406295 +1.291625 0.432952880859375 0.12872314453125 -0.7025939941406295 +1.29175 0.4302978515625 0.1279296875 -0.7025939941406295 +1.291875 0.4302978515625 0.1279296875 -0.7025939941406295 +1.292 0.4276123046875 0.12713623046875 -0.7025939941406295 +1.292125 0.4276123046875 0.12713623046875 -0.7025939941406295 +1.2922500000000002 0.424896240234375 0.126312255859375 -0.7025939941406295 +1.292375 0.422119140625 0.12548828125 -0.7025939941406295 +1.2925 0.422119140625 0.12548828125 -0.7025939941406295 +1.2926250000000002 0.419281005859375 0.1246337890625 -0.7025939941406295 +1.29275 0.419281005859375 0.1246337890625 -0.7025939941406295 +1.292875 0.416412353515625 0.123779296875 -0.7025939941406295 +1.293 0.413482666015625 0.1229248046875 -0.7025939941406295 +1.293125 0.413482666015625 0.1229248046875 -0.7025939941406295 +1.29325 0.4105224609375 0.122039794921875 -0.7025939941406295 +1.293375 0.4105224609375 0.122039794921875 -0.7025939941406295 +1.2935 0.407501220703125 0.12115478515625 -0.7025939941406295 +1.293625 0.404449462890625 0.1202392578125 -0.7025939941406295 +1.29375 0.404449462890625 0.1202392578125 -0.7025939941406295 +1.293875 0.401336669921875 0.11932373046875 -0.7025939941406295 +1.294 0.401336669921875 0.11932373046875 -0.7025939941406295 +1.294125 0.398193359375 0.118377685546875 -0.7025939941406295 +1.2942500000000002 0.39501953125 0.117431640625 -0.7025939941406295 +1.294375 0.39501953125 0.117431640625 -0.7025939941406295 +1.2945 0.39178466796875 0.116485595703125 -0.7025939941406295 +1.2946250000000002 0.39178466796875 0.116485595703125 -0.7025939941406295 +1.29475 0.388519287109375 0.115509033203125 -0.7025939941406295 +1.294875 0.38519287109375 0.114501953125 -0.7025939941406295 +1.295 0.38519287109375 0.114501953125 -0.7025939941406295 +1.295125 0.3818359375 0.113525390625 -0.7025939941406295 +1.29525 0.3818359375 0.113525390625 -0.7025939941406295 +1.295375 0.378448486328125 0.112518310546875 -0.7025939941406295 +1.2955 0.375 0.111480712890625 -0.7025939941406295 +1.295625 0.375 0.111480712890625 -0.7025939941406295 +1.29575 0.37152099609375 0.110443115234375 -0.7025939941406295 +1.295875 0.37152099609375 0.110443115234375 -0.7025939941406295 +1.296 0.36798095703125 0.109405517578125 -0.7025939941406295 +1.296125 0.36444091796875 0.10833740234375 -0.7025939941406295 +1.2962500000000002 0.36444091796875 0.10833740234375 -0.7025939941406295 +1.296375 0.360809326171875 0.107269287109375 -0.7025939941406295 +1.2965 0.360809326171875 0.107269287109375 -0.7025939941406295 +1.296625 0.357177734375 0.106201171875 -0.7025939941406295 +1.29675 0.353485107421875 0.1051025390625 -0.7025939941406295 +1.296875 0.353485107421875 0.1051025390625 -0.7025939941406295 +1.297 0.349761962890625 0.103973388671875 -0.7025939941406295 +1.297125 0.349761962890625 0.103973388671875 -0.7025939941406295 +1.29725 0.34600830078125 0.102874755859375 -0.7025939941406295 +1.297375 0.34222412109375 0.10174560546875 -0.7025939941406295 +1.2975 0.34222412109375 0.10174560546875 -0.7025939941406295 +1.297625 0.33837890625 0.1005859375 -0.7025939941406295 +1.29775 0.33837890625 0.1005859375 -0.7025939941406295 +1.2978750000000002 0.334503173828125 0.099456787109375 -0.7025939941406295 +1.298 0.330596923828125 0.098297119140625 -0.7025939941406295 +1.298125 0.330596923828125 0.098297119140625 -0.7025939941406295 +1.2982500000000002 0.32666015625 0.09710693359375 -0.7025939941406295 +1.298375 0.32666015625 0.09710693359375 -0.7025939941406295 +1.2985 0.322662353515625 0.095916748046875 -0.7025939941406295 +1.298625 0.31866455078125 0.0947265625 -0.7025939941406295 +1.29875 0.31866455078125 0.0947265625 -0.7025939941406295 +1.298875 0.314605712890625 0.093536376953125 -0.7025939941406295 +1.299 0.314605712890625 0.093536376953125 -0.7025939941406295 +1.299125 0.310516357421875 0.092315673828125 -0.7025939941406295 +1.29925 0.306396484375 0.091094970703125 -0.7025939941406295 +1.299375 0.306396484375 0.091094970703125 -0.7025939941406295 +1.2995 0.30224609375 0.08984375 -0.7025939941406295 +1.299625 0.30224609375 0.08984375 -0.7025939941406295 +1.29975 0.298065185546875 0.088623046875 -0.7025939941406295 +1.2998750000000002 0.2938232421875 0.08734130859375 -0.7025939941406295 +1.3 0.2938232421875 0.08734130859375 -0.7025939941406295 +1.300125 0.289581298828125 0.086090087890625 -0.7025939941406295 +1.3002500000000002 0.289581298828125 0.086090087890625 -0.7025939941406295 +1.300375 0.285308837890625 0.084808349609375 -0.7025939941406295 +1.3005 0.280975341796875 0.083526611328125 -0.7025939941406295 +1.300625 0.280975341796875 0.083526611328125 -0.7025939941406295 +1.30075 0.276641845703125 0.082244873046875 -0.7025939941406295 +1.300875 0.276641845703125 0.082244873046875 -0.7025939941406295 +1.301 0.27227783203125 0.0809326171875 -0.7025939941406295 +1.301125 0.267852783203125 0.079620361328125 -0.7025939941406295 +1.30125 0.267852783203125 0.079620361328125 -0.7025939941406295 +1.301375 0.263427734375 0.07830810546875 -0.7025939941406295 +1.3015 0.263427734375 0.07830810546875 -0.7025939941406295 +1.301625 0.25897216796875 0.076995849609375 -0.7025939941406295 +1.30175 0.25445556640625 0.075653076171875 -0.7025939941406295 +1.3018750000000002 0.25445556640625 0.075653076171875 -0.7025939941406295 +1.302 0.249969482421875 0.074310302734375 -0.7025939941406295 +1.302125 0.249969482421875 0.074310302734375 -0.7025939941406295 +1.3022500000000002 0.24542236328125 0.072967529296875 -0.7025939941406295 +1.302375 0.2408447265625 0.07159423828125 -0.7025939941406295 +1.3025 0.2408447265625 0.07159423828125 -0.7025939941406295 +1.302625 0.236236572265625 0.070220947265625 -0.7025939941406295 +1.30275 0.236236572265625 0.070220947265625 -0.7025939941406295 +1.302875 0.231597900390625 0.06884765625 -0.7025939941406295 +1.303 0.226959228515625 0.067474365234375 -0.7025939941406295 +1.303125 0.226959228515625 0.067474365234375 -0.7025939941406295 +1.30325 0.2222900390625 0.066070556640625 -0.7025939941406295 +1.303375 0.2222900390625 0.066070556640625 -0.7025939941406295 +1.3035 0.21759033203125 0.064666748046875 -0.7025939941406295 +1.303625 0.212860107421875 0.063262939453125 -0.7025939941406295 +1.30375 0.212860107421875 0.063262939453125 -0.7025939941406295 +1.3038750000000002 0.208099365234375 0.061859130859375 -0.7025939941406295 +1.304 0.208099365234375 0.061859130859375 -0.7025939941406295 +1.304125 0.203338623046875 0.060455322265625 -0.7025939941406295 +1.3042500000000002 0.19854736328125 0.05902099609375 -0.7025939941406295 +1.304375 0.19854736328125 0.05902099609375 -0.7025939941406295 +1.3045 0.1937255859375 0.057586669921875 -0.7025939941406295 +1.304625 0.1937255859375 0.057586669921875 -0.7025939941406295 +1.30475 0.188873291015625 0.05615234375 -0.7025939941406295 +1.304875 0.18402099609375 0.054718017578125 -0.7025939941406295 +1.305 0.18402099609375 0.054718017578125 -0.7025939941406295 +1.305125 0.17913818359375 0.053253173828125 -0.7025939941406295 +1.30525 0.17913818359375 0.053253173828125 -0.7025939941406295 +1.305375 0.17425537109375 0.051788330078125 -0.7025939941406295 +1.3055 0.169342041015625 0.050323486328125 -0.7025939941406295 +1.305625 0.169342041015625 0.050323486328125 -0.7025939941406295 +1.30575 0.164398193359375 0.048858642578125 -0.7025939941406295 +1.3058750000000002 0.164398193359375 0.048858642578125 -0.7025939941406295 +1.306 0.159454345703125 0.047393798828125 -0.7025939941406295 +1.306125 0.15447998046875 0.045928955078125 -0.7025939941406295 +1.3062500000000002 0.15447998046875 0.045928955078125 -0.7025939941406295 +1.306375 0.14947509765625 0.04443359375 -0.7025939941406295 +1.3065 0.14947509765625 0.04443359375 -0.7025939941406295 +1.306625 0.14447021484375 0.042938232421875 -0.7025939941406295 +1.30675 0.13946533203125 0.04144287109375 -0.7025939941406295 +1.306875 0.13946533203125 0.04144287109375 -0.7025939941406295 +1.307 0.134429931640625 0.039947509765625 -0.7025939941406295 +1.307125 0.134429931640625 0.039947509765625 -0.7025939941406295 +1.30725 0.129364013671875 0.0384521484375 -0.7025939941406295 +1.307375 0.124298095703125 0.036956787109375 -0.7025939941406295 +1.3075 0.124298095703125 0.036956787109375 -0.7025939941406295 +1.307625 0.119232177734375 0.035430908203125 -0.7025939941406295 +1.30775 0.119232177734375 0.035430908203125 -0.7025939941406295 +1.3078750000000002 0.1141357421875 0.033935546875 -0.7025939941406295 +1.308 0.109039306640625 0.03240966796875 -0.7025939941406295 +1.308125 0.109039306640625 0.03240966796875 -0.7025939941406295 +1.3082500000000002 0.103912353515625 0.0308837890625 -0.7025939941406295 +1.308375 0.103912353515625 0.0308837890625 -0.7025939941406295 +1.3085 0.098785400390625 0.02935791015625 -0.7025939941406295 +1.308625 0.093658447265625 0.02783203125 -0.7025939941406295 +1.30875 0.093658447265625 0.02783203125 -0.7025939941406295 +1.308875 0.0885009765625 0.02630615234375 -0.7025939941406295 +1.309 0.0885009765625 0.02630615234375 -0.7025939941406295 +1.309125 0.083343505859375 0.0247802734375 -0.7025939941406295 +1.30925 0.07818603515625 0.023223876953125 -0.7025939941406295 +1.309375 0.07818603515625 0.023223876953125 -0.7025939941406295 +1.3095 0.072998046875 0.021697998046875 -0.7025939941406295 +1.309625 0.072998046875 0.021697998046875 -0.7025939941406295 +1.30975 0.06781005859375 0.0201416015625 -0.7025939941406295 +1.3098750000000002 0.0626220703125 0.01861572265625 -0.7025939941406295 +1.31 0.0626220703125 0.01861572265625 -0.7025939941406295 +1.310125 0.05743408203125 0.017059326171875 -0.7025939941406295 +1.3102500000000002 0.05743408203125 0.017059326171875 -0.7025939941406295 +1.310375 0.05224609375 0.015533447265625 -0.7025939941406295 +1.3105 0.047027587890625 0.01397705078125 -0.7025939941406295 +1.310625 0.047027587890625 0.01397705078125 -0.7025939941406295 +1.31075 0.04180908203125 0.012420654296875 -0.7025939941406295 +1.310875 0.04180908203125 0.012420654296875 -0.7025939941406295 +1.311 0.036590576171875 0.0108642578125 -0.7025939941406295 +1.311125 0.0313720703125 0.009307861328125 -0.7025939941406295 +1.31125 0.0313720703125 0.009307861328125 -0.7025939941406295 +1.311375 0.026123046875 0.00775146484375 -0.7025939941406295 +1.3115 0.026123046875 0.00775146484375 -0.7025939941406295 +1.311625 0.020904541015625 0.006195068359375 -0.7025939941406295 +1.31175 0.01568603515625 0.004638671875 -0.7025939941406295 +1.3118750000000002 0.01568603515625 0.004638671875 -0.7025939941406295 +1.312 0.01043701171875 0.000762939453125 -0.9250366210937526 +1.312125 0.01043701171875 0.000762939453125 -0.9250366210937526 +1.31225 0.005218505859375 0.0003662109375 -0.9250366210937526 +1.312375 0.0 0.0 -0.9250366210937526 +1.3125 0.0 0.0 -0.9250366210937526 +1.312625 -0.005218505859375 -0.0003662109375 -0.9250366210937526 +1.31275 -0.005218505859375 -0.0003662109375 -0.9250366210937526 +1.312875 -0.01043701171875 -0.000762939453125 -0.9250366210937526 +1.313 -0.01568603515625 -0.00115966796875 -0.9250366210937526 +1.313125 -0.01568603515625 -0.00115966796875 -0.9250366210937526 +1.31325 -0.020904541015625 -0.001556396484375 -0.9250366210937526 +1.313375 -0.020904541015625 -0.001556396484375 -0.9250366210937526 +1.3135000000000002 -0.026123046875 -0.001953125 -0.9250366210937526 +1.313625 -0.0313720703125 -0.0023193359375 -0.9250366210937526 +1.31375 -0.0313720703125 -0.0023193359375 -0.9250366210937526 +1.3138750000000002 -0.036590576171875 -0.002716064453125 -0.9250366210937526 +1.314 -0.036590576171875 -0.002716064453125 -0.9250366210937526 +1.314125 -0.04180908203125 -0.00311279296875 -0.9250366210937526 +1.31425 -0.047027587890625 -0.003509521484375 -0.9250366210937526 +1.314375 -0.047027587890625 -0.003509521484375 -0.9250366210937526 +1.3145 -0.05224609375 -0.00390625 -0.9250366210937526 +1.314625 -0.05224609375 -0.00390625 -0.9250366210937526 +1.31475 -0.05743408203125 -0.0042724609375 -0.9250366210937526 +1.314875 -0.0626220703125 -0.004669189453125 -0.9250366210937526 +1.315 -0.0626220703125 -0.004669189453125 -0.9250366210937526 +1.315125 -0.06781005859375 -0.00506591796875 -0.9250366210937526 +1.31525 -0.06781005859375 -0.00506591796875 -0.9250366210937526 +1.315375 -0.072998046875 -0.005462646484375 -0.9250366210937526 +1.3155000000000002 -0.07818603515625 -0.005828857421875 -0.9250366210937526 +1.315625 -0.07818603515625 -0.005828857421875 -0.9250366210937526 +1.31575 -0.083343505859375 -0.0062255859375 -0.9250366210937526 +1.3158750000000002 -0.083343505859375 -0.0062255859375 -0.9250366210937526 +1.316 -0.0885009765625 -0.006622314453125 -0.9250366210937526 +1.316125 -0.093658447265625 -0.006988525390625 -0.9250366210937526 +1.31625 -0.093658447265625 -0.006988525390625 -0.9250366210937526 +1.316375 -0.098785400390625 -0.00738525390625 -0.9250366210937526 +1.3165 -0.098785400390625 -0.00738525390625 -0.9250366210937526 +1.316625 -0.103912353515625 -0.00775146484375 -0.9250366210937526 +1.31675 -0.109039306640625 -0.008148193359375 -0.9250366210937526 +1.316875 -0.109039306640625 -0.008148193359375 -0.9250366210937526 +1.317 -0.1141357421875 -0.008544921875 -0.9250366210937526 +1.317125 -0.1141357421875 -0.008544921875 -0.9250366210937526 +1.31725 -0.119232177734375 -0.0089111328125 -0.9250366210937526 +1.317375 -0.124298095703125 -0.00927734375 -0.9250366210937526 +1.3175000000000002 -0.124298095703125 -0.00927734375 -0.9250366210937526 +1.317625 -0.129364013671875 -0.009674072265625 -0.9250366210937526 +1.31775 -0.129364013671875 -0.009674072265625 -0.9250366210937526 +1.3178750000000002 -0.134429931640625 -0.010040283203125 -0.9250366210937526 +1.318 -0.13946533203125 -0.01043701171875 -0.9250366210937526 +1.318125 -0.13946533203125 -0.01043701171875 -0.9250366210937526 +1.31825 -0.14447021484375 -0.01080322265625 -0.9250366210937526 +1.318375 -0.14447021484375 -0.01080322265625 -0.9250366210937526 +1.3185 -0.14947509765625 -0.01116943359375 -0.9250366210937526 +1.318625 -0.15447998046875 -0.01153564453125 -0.9250366210937526 +1.31875 -0.15447998046875 -0.01153564453125 -0.9250366210937526 +1.318875 -0.159454345703125 -0.011932373046875 -0.9250366210937526 +1.319 -0.159454345703125 -0.011932373046875 -0.9250366210937526 +1.319125 -0.164398193359375 -0.012298583984375 -0.9250366210937526 +1.31925 -0.169342041015625 -0.012664794921875 -0.9250366210937526 +1.319375 -0.169342041015625 -0.012664794921875 -0.9250366210937526 +1.3195000000000002 -0.17425537109375 -0.013031005859375 -0.9250366210937526 +1.319625 -0.17425537109375 -0.013031005859375 -0.9250366210937526 +1.31975 -0.17913818359375 -0.013397216796875 -0.9250366210937526 +1.3198750000000002 -0.18402099609375 -0.013763427734375 -0.9250366210937526 +1.32 -0.18402099609375 -0.013763427734375 -0.9250366210937526 +1.320125 -0.188873291015625 -0.014129638671875 -0.9250366210937526 +1.32025 -0.188873291015625 -0.014129638671875 -0.9250366210937526 +1.320375 -0.1937255859375 -0.014495849609375 -0.9250366210937526 +1.3205 -0.19854736328125 -0.014862060546875 -0.9250366210937526 +1.320625 -0.19854736328125 -0.014862060546875 -0.9250366210937526 +1.32075 -0.203338623046875 -0.01519775390625 -0.9250366210937526 +1.320875 -0.203338623046875 -0.01519775390625 -0.9250366210937526 +1.321 -0.208099365234375 -0.01556396484375 -0.9250366210937526 +1.321125 -0.212860107421875 -0.01593017578125 -0.9250366210937526 +1.32125 -0.212860107421875 -0.01593017578125 -0.9250366210937526 +1.321375 -0.21759033203125 -0.016265869140625 -0.9250366210937526 +1.3215000000000002 -0.21759033203125 -0.016265869140625 -0.9250366210937526 +1.321625 -0.2222900390625 -0.016632080078125 -0.9250366210937526 +1.32175 -0.226959228515625 -0.0169677734375 -0.9250366210937526 +1.3218750000000002 -0.226959228515625 -0.0169677734375 -0.9250366210937526 +1.322 -0.231597900390625 -0.017333984375 -0.9250366210937526 +1.322125 -0.231597900390625 -0.017333984375 -0.9250366210937526 +1.32225 -0.236236572265625 -0.017669677734375 -0.9250366210937526 +1.322375 -0.2408447265625 -0.01800537109375 -0.9250366210937526 +1.3225 -0.2408447265625 -0.01800537109375 -0.9250366210937526 +1.322625 -0.24542236328125 -0.01837158203125 -0.9250366210937526 +1.32275 -0.24542236328125 -0.01837158203125 -0.9250366210937526 +1.322875 -0.249969482421875 -0.018707275390625 -0.9250366210937526 +1.323 -0.25445556640625 -0.01904296875 -0.9250366210937526 +1.323125 -0.25445556640625 -0.01904296875 -0.9250366210937526 +1.32325 -0.25897216796875 -0.019378662109375 -0.9250366210937526 +1.323375 -0.25897216796875 -0.019378662109375 -0.9250366210937526 +1.3235000000000002 -0.263427734375 -0.01971435546875 -0.9250366210937526 +1.323625 -0.267852783203125 -0.020050048828125 -0.9250366210937526 +1.32375 -0.267852783203125 -0.020050048828125 -0.9250366210937526 +1.3238750000000002 -0.27227783203125 -0.020355224609375 -0.9250366210937526 +1.324 -0.27227783203125 -0.020355224609375 -0.9250366210937526 +1.324125 -0.276641845703125 -0.02069091796875 -0.9250366210937526 +1.32425 -0.280975341796875 -0.021026611328125 -0.9250366210937526 +1.324375 -0.280975341796875 -0.021026611328125 -0.9250366210937526 +1.3245 -0.285308837890625 -0.021331787109375 -0.9250366210937526 +1.324625 -0.285308837890625 -0.021331787109375 -0.9250366210937526 +1.32475 -0.289581298828125 -0.02166748046875 -0.9250366210937526 +1.324875 -0.2938232421875 -0.02197265625 -0.9250366210937526 +1.325 -0.2938232421875 -0.02197265625 -0.9250366210937526 +1.325125 -0.298065185546875 -0.022308349609375 -0.9250366210937526 +1.32525 -0.298065185546875 -0.022308349609375 -0.9250366210937526 +1.325375 -0.30224609375 -0.022613525390625 -0.9250366210937526 +1.3255000000000002 -0.306396484375 -0.022918701171875 -0.9250366210937526 +1.325625 -0.306396484375 -0.022918701171875 -0.9250366210937526 +1.32575 -0.310516357421875 -0.023223876953125 -0.9250366210937526 +1.3258750000000002 -0.310516357421875 -0.023223876953125 -0.9250366210937526 +1.326 -0.314605712890625 -0.023529052734375 -0.9250366210937526 +1.326125 -0.31866455078125 -0.023834228515625 -0.9250366210937526 +1.32625 -0.31866455078125 -0.023834228515625 -0.9250366210937526 +1.326375 -0.322662353515625 -0.024139404296875 -0.9250366210937526 +1.3265 -0.322662353515625 -0.024139404296875 -0.9250366210937526 +1.326625 -0.32666015625 -0.024444580078125 -0.9250366210937526 +1.32675 -0.330596923828125 -0.024749755859375 -0.9250366210937526 +1.326875 -0.330596923828125 -0.024749755859375 -0.9250366210937526 +1.327 -0.334503173828125 -0.0250244140625 -0.9250366210937526 +1.327125 -0.334503173828125 -0.0250244140625 -0.9250366210937526 +1.32725 -0.33837890625 -0.02532958984375 -0.9250366210937526 +1.327375 -0.34222412109375 -0.025604248046875 -0.9250366210937526 +1.3275000000000002 -0.34222412109375 -0.025604248046875 -0.9250366210937526 +1.327625 -0.34600830078125 -0.02587890625 -0.9250366210937526 +1.32775 -0.34600830078125 -0.02587890625 -0.9250366210937526 +1.3278750000000002 -0.349761962890625 -0.02618408203125 -0.9250366210937526 +1.328 -0.353485107421875 -0.026458740234375 -0.9250366210937526 +1.328125 -0.353485107421875 -0.026458740234375 -0.9250366210937526 +1.32825 -0.357177734375 -0.0267333984375 -0.9250366210937526 +1.328375 -0.357177734375 -0.0267333984375 -0.9250366210937526 +1.3285 -0.360809326171875 -0.027008056640625 -0.9250366210937526 +1.328625 -0.36444091796875 -0.02728271484375 -0.9250366210937526 +1.32875 -0.36444091796875 -0.02728271484375 -0.9250366210937526 +1.328875 -0.36798095703125 -0.02752685546875 -0.9250366210937526 +1.329 -0.36798095703125 -0.02752685546875 -0.9250366210937526 +1.3291250000000002 -0.37152099609375 -0.027801513671875 -0.9250366210937526 +1.32925 -0.375 -0.028045654296875 -0.9250366210937526 +1.329375 -0.375 -0.028045654296875 -0.9250366210937526 +1.3295000000000002 -0.378448486328125 -0.0283203125 -0.9250366210937526 +1.329625 -0.378448486328125 -0.0283203125 -0.9250366210937526 +1.32975 -0.3818359375 -0.028564453125 -0.9250366210937526 +1.329875 -0.38519287109375 -0.02880859375 -0.9250366210937526 +1.33 -0.38519287109375 -0.02880859375 -0.9250366210937526 +1.330125 -0.388519287109375 -0.029083251953125 -0.9250366210937526 +1.33025 -0.388519287109375 -0.029083251953125 -0.9250366210937526 +1.330375 -0.39178466796875 -0.029327392578125 -0.9250366210937526 +1.3305 -0.39501953125 -0.029571533203125 -0.9250366210937526 +1.330625 -0.39501953125 -0.029571533203125 -0.9250366210937526 +1.33075 -0.398193359375 -0.02978515625 -0.9250366210937526 +1.330875 -0.398193359375 -0.02978515625 -0.9250366210937526 +1.331 -0.401336669921875 -0.030029296875 -0.9250366210937526 +1.3311250000000002 -0.404449462890625 -0.0302734375 -0.9250366210937526 +1.33125 -0.404449462890625 -0.0302734375 -0.9250366210937526 +1.331375 -0.407501220703125 -0.030487060546875 -0.9250366210937526 +1.3315000000000002 -0.407501220703125 -0.030487060546875 -0.9250366210937526 +1.331625 -0.4105224609375 -0.030731201171875 -0.9250366210937526 +1.33175 -0.413482666015625 -0.03094482421875 -0.9250366210937526 +1.331875 -0.413482666015625 -0.03094482421875 -0.9250366210937526 +1.332 -0.416412353515625 -0.031158447265625 -0.9250366210937526 +1.332125 -0.416412353515625 -0.031158447265625 -0.9250366210937526 +1.33225 -0.419281005859375 -0.0313720703125 -0.9250366210937526 +1.332375 -0.422119140625 -0.031585693359375 -0.9250366210937526 +1.3325 -0.422119140625 -0.031585693359375 -0.9250366210937526 +1.332625 -0.424896240234375 -0.03179931640625 -0.9250366210937526 +1.33275 -0.424896240234375 -0.03179931640625 -0.9250366210937526 +1.332875 -0.4276123046875 -0.032012939453125 -0.9250366210937526 +1.333 -0.4302978515625 -0.032196044921875 -0.9250366210937526 +1.3331250000000002 -0.4302978515625 -0.032196044921875 -0.9250366210937526 +1.33325 -0.432952880859375 -0.03240966796875 -0.9250366210937526 +1.333375 -0.432952880859375 -0.03240966796875 -0.9250366210937526 +1.3335000000000002 -0.435546875 -0.0325927734375 -0.9250366210937526 +1.333625 -0.438079833984375 -0.03277587890625 -0.9250366210937526 +1.33375 -0.438079833984375 -0.03277587890625 -0.9250366210937526 +1.333875 -0.440582275390625 -0.032958984375 -0.9250366210937526 +1.334 -0.440582275390625 -0.032958984375 -0.9250366210937526 +1.334125 -0.44305419921875 -0.03314208984375 -0.9250366210937526 +1.33425 -0.4454345703125 -0.0333251953125 -0.9250366210937526 +1.334375 -0.4454345703125 -0.0333251953125 -0.9250366210937526 +1.3345 -0.447784423828125 -0.03350830078125 -0.9250366210937526 +1.334625 -0.447784423828125 -0.03350830078125 -0.9250366210937526 +1.33475 -0.450103759765625 -0.03369140625 -0.9250366210937526 +1.334875 -0.452362060546875 -0.033843994140625 -0.9250366210937526 +1.335 -0.452362060546875 -0.033843994140625 -0.9250366210937526 +1.3351250000000002 -0.454559326171875 -0.034027099609375 -0.9250366210937526 +1.33525 -0.454559326171875 -0.034027099609375 -0.9250366210937526 +1.335375 -0.45672607421875 -0.0341796875 -0.9250366210937526 +1.3355000000000002 -0.458831787109375 -0.034332275390625 -0.9250366210937526 +1.335625 -0.458831787109375 -0.034332275390625 -0.9250366210937526 +1.33575 -0.46087646484375 -0.03448486328125 -0.9250366210937526 +1.335875 -0.46087646484375 -0.03448486328125 -0.9250366210937526 +1.336 -0.462890625 -0.034637451171875 -0.9250366210937526 +1.336125 -0.464813232421875 -0.0347900390625 -0.9250366210937526 +1.33625 -0.464813232421875 -0.0347900390625 -0.9250366210937526 +1.336375 -0.46673583984375 -0.034912109375 -0.9250366210937526 +1.3365 -0.46673583984375 -0.034912109375 -0.9250366210937526 +1.336625 -0.46856689453125 -0.035064697265625 -0.9250366210937526 +1.33675 -0.470367431640625 -0.035186767578125 -0.9250366210937526 +1.336875 -0.470367431640625 -0.035186767578125 -0.9250366210937526 +1.337 -0.472137451171875 -0.03533935546875 -0.9250366210937526 +1.3371250000000002 -0.472137451171875 -0.03533935546875 -0.9250366210937526 +1.33725 -0.47381591796875 -0.03546142578125 -0.9250366210937526 +1.337375 -0.4754638671875 -0.03558349609375 -0.9250366210937526 +1.3375000000000002 -0.4754638671875 -0.03558349609375 -0.9250366210937526 +1.337625 -0.47705078125 -0.03570556640625 -0.9250366210937526 +1.33775 -0.47705078125 -0.03570556640625 -0.9250366210937526 +1.337875 -0.478607177734375 -0.03582763671875 -0.9250366210937526 +1.338 -0.480072021484375 -0.035919189453125 -0.9250366210937526 +1.338125 -0.480072021484375 -0.035919189453125 -0.9250366210937526 +1.33825 -0.48150634765625 -0.036041259765625 -0.9250366210937526 +1.338375 -0.48150634765625 -0.036041259765625 -0.9250366210937526 +1.3385 -0.48291015625 -0.0361328125 -0.9250366210937526 +1.338625 -0.484222412109375 -0.036224365234375 -0.9250366210937526 +1.33875 -0.484222412109375 -0.036224365234375 -0.9250366210937526 +1.338875 -0.485504150390625 -0.036346435546875 -0.9250366210937526 +1.339 -0.485504150390625 -0.036346435546875 -0.9250366210937526 +1.3391250000000002 -0.486724853515625 -0.03643798828125 -0.9250366210937526 +1.33925 -0.487884521484375 -0.0364990234375 -0.9250366210937526 +1.339375 -0.487884521484375 -0.0364990234375 -0.9250366210937526 +1.3395000000000002 -0.489013671875 -0.036590576171875 -0.9250366210937526 +1.339625 -0.489013671875 -0.036590576171875 -0.9250366210937526 +1.33975 -0.490081787109375 -0.03668212890625 -0.9250366210937526 +1.339875 -0.4910888671875 -0.0367431640625 -0.9250366210937526 +1.34 -0.4910888671875 -0.0367431640625 -0.9250366210937526 +1.340125 -0.492034912109375 -0.036834716796875 -0.9250366210937526 +1.34025 -0.492034912109375 -0.036834716796875 -0.9250366210937526 +1.340375 -0.492950439453125 -0.036895751953125 -0.9250366210937526 +1.3405 -0.4937744140625 -0.036956787109375 -0.9250366210937526 +1.340625 -0.4937744140625 -0.036956787109375 -0.9250366210937526 +1.34075 -0.49456787109375 -0.037017822265625 -0.9250366210937526 +1.340875 -0.49456787109375 -0.037017822265625 -0.9250366210937526 +1.341 -0.49530029296875 -0.037078857421875 -0.9250366210937526 +1.3411250000000002 -0.496002197265625 -0.037109375 -0.9250366210937526 +1.34125 -0.496002197265625 -0.037109375 -0.9250366210937526 +1.341375 -0.496612548828125 -0.03717041015625 -0.9250366210937526 +1.3415000000000002 -0.496612548828125 -0.03717041015625 -0.9250366210937526 +1.341625 -0.4971923828125 -0.037200927734375 -0.9250366210937526 +1.34175 -0.497711181640625 -0.0372314453125 -0.9250366210937526 +1.341875 -0.497711181640625 -0.0372314453125 -0.9250366210937526 +1.342 -0.498199462890625 -0.03729248046875 -0.9250366210937526 +1.342125 -0.498199462890625 -0.03729248046875 -0.9250366210937526 +1.34225 -0.49859619140625 -0.037322998046875 -0.9250366210937526 +1.342375 -0.49896240234375 -0.037353515625 -0.9250366210937526 +1.3425 -0.49896240234375 -0.037353515625 -0.9250366210937526 +1.342625 -0.499267578125 -0.037353515625 -0.9250366210937526 +1.34275 -0.499267578125 -0.037353515625 -0.9250366210937526 +1.342875 -0.49951171875 -0.037384033203125 -0.9250366210937526 +1.343 -0.49969482421875 -0.037384033203125 -0.9250366210937526 +1.3431250000000002 -0.49969482421875 -0.037384033203125 -0.9250366210937526 +1.34325 -0.49981689453125 -0.03741455078125 -0.9250366210937526 +1.343375 -0.49981689453125 -0.03741455078125 -0.9250366210937526 +1.3435000000000002 -0.499908447265625 -0.03741455078125 -0.9250366210937526 +1.343625 -0.49993896484375 -0.03741455078125 -0.9250366210937526 +1.34375 -0.49993896484375 -0.03741455078125 -0.9250366210937526 +1.343875 -0.499908447265625 -0.03741455078125 -0.9250366210937526 +1.344 -0.499908447265625 0.0 -0.99987182617187488 +1.344125 -0.49981689453125 0.0 -0.99987182617187488 +1.34425 -0.49969482421875 0.0 -0.99987182617187488 +1.344375 -0.49969482421875 0.0 -0.99987182617187488 +1.3445 -0.49951171875 0.0 -0.99987182617187488 +1.344625 -0.49951171875 0.0 -0.99987182617187488 +1.3447500000000002 -0.499267578125 0.0 -0.99987182617187488 +1.344875 -0.49896240234375 0.0 -0.99987182617187488 +1.345 -0.49896240234375 0.0 -0.99987182617187488 +1.3451250000000002 -0.49859619140625 0.0 -0.99987182617187488 +1.34525 -0.49859619140625 0.0 -0.99987182617187488 +1.345375 -0.498199462890625 0.0 -0.99987182617187488 +1.3455 -0.497711181640625 0.0 -0.99987182617187488 +1.345625 -0.497711181640625 0.0 -0.99987182617187488 +1.34575 -0.4971923828125 0.0 -0.99987182617187488 +1.345875 -0.4971923828125 0.0 -0.99987182617187488 +1.346 -0.496612548828125 0.0 -0.99987182617187488 +1.346125 -0.496002197265625 0.0 -0.99987182617187488 +1.34625 -0.496002197265625 0.0 -0.99987182617187488 +1.346375 -0.49530029296875 0.0 -0.99987182617187488 +1.3465 -0.49530029296875 0.0 -0.99987182617187488 +1.346625 -0.49456787109375 0.0 -0.99987182617187488 +1.3467500000000002 -0.4937744140625 0.0 -0.99987182617187488 +1.346875 -0.4937744140625 0.0 -0.99987182617187488 +1.347 -0.492950439453125 0.0 -0.99987182617187488 +1.3471250000000002 -0.492950439453125 0.0 -0.99987182617187488 +1.34725 -0.492034912109375 0.0 -0.99987182617187488 +1.347375 -0.4910888671875 0.0 -0.99987182617187488 +1.3475 -0.4910888671875 0.0 -0.99987182617187488 +1.347625 -0.490081787109375 0.0 -0.99987182617187488 +1.34775 -0.490081787109375 0.0 -0.99987182617187488 +1.347875 -0.489013671875 0.0 -0.99987182617187488 +1.348 -0.487884521484375 0.0 -0.99987182617187488 +1.348125 -0.487884521484375 0.0 -0.99987182617187488 +1.34825 -0.486724853515625 0.0 -0.99987182617187488 +1.348375 -0.486724853515625 0.0 -0.99987182617187488 +1.3485 -0.485504150390625 0.0 -0.99987182617187488 +1.348625 -0.484222412109375 0.0 -0.99987182617187488 +1.3487500000000002 -0.484222412109375 0.0 -0.99987182617187488 +1.348875 -0.48291015625 0.0 -0.99987182617187488 +1.349 -0.48291015625 0.0 -0.99987182617187488 +1.3491250000000002 -0.48150634765625 0.0 -0.99987182617187488 +1.34925 -0.480072021484375 0.0 -0.99987182617187488 +1.349375 -0.480072021484375 0.0 -0.99987182617187488 +1.3495 -0.478607177734375 0.0 -0.99987182617187488 +1.349625 -0.478607177734375 0.0 -0.99987182617187488 +1.34975 -0.47705078125 0.0 -0.99987182617187488 +1.349875 -0.4754638671875 0.0 -0.99987182617187488 +1.35 -0.4754638671875 0.0 -0.99987182617187488 +1.350125 -0.47381591796875 0.0 -0.99987182617187488 +1.35025 -0.47381591796875 0.0 -0.99987182617187488 +1.350375 -0.472137451171875 0.0 -0.99987182617187488 +1.3505 -0.470367431640625 0.0 -0.99987182617187488 +1.350625 -0.470367431640625 0.0 -0.99987182617187488 +1.3507500000000002 -0.46856689453125 0.0 -0.99987182617187488 +1.350875 -0.46856689453125 0.0 -0.99987182617187488 +1.351 -0.46673583984375 0.0 -0.99987182617187488 +1.3511250000000002 -0.464813232421875 0.0 -0.99987182617187488 +1.35125 -0.464813232421875 0.0 -0.99987182617187488 +1.351375 -0.462890625 0.0 -0.99987182617187488 +1.3515 -0.462890625 0.0 -0.99987182617187488 +1.351625 -0.46087646484375 0.0 -0.99987182617187488 +1.35175 -0.458831787109375 0.0 -0.99987182617187488 +1.351875 -0.458831787109375 0.0 -0.99987182617187488 +1.352 -0.45672607421875 0.0 -0.99987182617187488 +1.352125 -0.45672607421875 0.0 -0.99987182617187488 +1.35225 -0.454559326171875 0.0 -0.99987182617187488 +1.352375 -0.452362060546875 0.0 -0.99987182617187488 +1.3525 -0.452362060546875 0.0 -0.99987182617187488 +1.352625 -0.450103759765625 0.0 -0.99987182617187488 +1.3527500000000002 -0.450103759765625 0.0 -0.99987182617187488 +1.352875 -0.447784423828125 0.0 -0.99987182617187488 +1.353 -0.4454345703125 0.0 -0.99987182617187488 +1.3531250000000002 -0.4454345703125 0.0 -0.99987182617187488 +1.35325 -0.44305419921875 0.0 -0.99987182617187488 +1.353375 -0.44305419921875 0.0 -0.99987182617187488 +1.3535 -0.440582275390625 0.0 -0.99987182617187488 +1.353625 -0.438079833984375 0.0 -0.99987182617187488 +1.35375 -0.438079833984375 0.0 -0.99987182617187488 +1.353875 -0.435546875 0.0 -0.99987182617187488 +1.354 -0.435546875 0.0 -0.99987182617187488 +1.354125 -0.432952880859375 0.0 -0.99987182617187488 +1.35425 -0.4302978515625 0.0 -0.99987182617187488 +1.354375 -0.4302978515625 0.0 -0.99987182617187488 +1.3545 -0.4276123046875 0.0 -0.99987182617187488 +1.354625 -0.4276123046875 0.0 -0.99987182617187488 +1.3547500000000002 -0.424896240234375 0.0 -0.99987182617187488 +1.354875 -0.422119140625 0.0 -0.99987182617187488 +1.355 -0.422119140625 0.0 -0.99987182617187488 +1.3551250000000002 -0.419281005859375 0.0 -0.99987182617187488 +1.35525 -0.419281005859375 0.0 -0.99987182617187488 +1.355375 -0.416412353515625 0.0 -0.99987182617187488 +1.3555 -0.413482666015625 0.0 -0.99987182617187488 +1.355625 -0.413482666015625 0.0 -0.99987182617187488 +1.35575 -0.4105224609375 0.0 -0.99987182617187488 +1.355875 -0.4105224609375 0.0 -0.99987182617187488 +1.356 -0.407501220703125 0.0 -0.99987182617187488 +1.356125 -0.404449462890625 0.0 -0.99987182617187488 +1.35625 -0.404449462890625 0.0 -0.99987182617187488 +1.356375 -0.401336669921875 0.0 -0.99987182617187488 +1.3565 -0.401336669921875 0.0 -0.99987182617187488 +1.356625 -0.398193359375 0.0 -0.99987182617187488 +1.3567500000000002 -0.39501953125 0.0 -0.99987182617187488 +1.356875 -0.39501953125 0.0 -0.99987182617187488 +1.357 -0.39178466796875 0.0 -0.99987182617187488 +1.3571250000000002 -0.39178466796875 0.0 -0.99987182617187488 +1.35725 -0.388519287109375 0.0 -0.99987182617187488 +1.357375 -0.38519287109375 0.0 -0.99987182617187488 +1.3575 -0.38519287109375 0.0 -0.99987182617187488 +1.357625 -0.3818359375 0.0 -0.99987182617187488 +1.35775 -0.3818359375 0.0 -0.99987182617187488 +1.357875 -0.378448486328125 0.0 -0.99987182617187488 +1.358 -0.375 0.0 -0.99987182617187488 +1.358125 -0.375 0.0 -0.99987182617187488 +1.35825 -0.37152099609375 0.0 -0.99987182617187488 +1.358375 -0.37152099609375 0.0 -0.99987182617187488 +1.3585 -0.36798095703125 0.0 -0.99987182617187488 +1.358625 -0.36444091796875 0.0 -0.99987182617187488 +1.3587500000000002 -0.36444091796875 0.0 -0.99987182617187488 +1.358875 -0.360809326171875 0.0 -0.99987182617187488 +1.359 -0.360809326171875 0.0 -0.99987182617187488 +1.3591250000000002 -0.357177734375 0.0 -0.99987182617187488 +1.35925 -0.353485107421875 0.0 -0.99987182617187488 +1.359375 -0.353485107421875 0.0 -0.99987182617187488 +1.3595 -0.349761962890625 0.0 -0.99987182617187488 +1.359625 -0.349761962890625 0.0 -0.99987182617187488 +1.35975 -0.34600830078125 0.0 -0.99987182617187488 +1.359875 -0.34222412109375 0.0 -0.99987182617187488 +1.36 -0.34222412109375 0.0 -0.99987182617187488 +1.360125 -0.33837890625 0.0 -0.99987182617187488 +1.36025 -0.33837890625 0.0 -0.99987182617187488 +1.3603750000000002 -0.334503173828125 0.0 -0.99987182617187488 +1.3605 -0.330596923828125 0.0 -0.99987182617187488 +1.360625 -0.330596923828125 0.0 -0.99987182617187488 +1.3607500000000002 -0.32666015625 0.0 -0.99987182617187488 +1.360875 -0.32666015625 0.0 -0.99987182617187488 +1.361 -0.322662353515625 0.0 -0.99987182617187488 +1.361125 -0.31866455078125 0.0 -0.99987182617187488 +1.36125 -0.31866455078125 0.0 -0.99987182617187488 +1.361375 -0.314605712890625 0.0 -0.99987182617187488 +1.3615 -0.314605712890625 0.0 -0.99987182617187488 +1.361625 -0.310516357421875 0.0 -0.99987182617187488 +1.36175 -0.306396484375 0.0 -0.99987182617187488 +1.361875 -0.306396484375 0.0 -0.99987182617187488 +1.362 -0.30224609375 0.0 -0.99987182617187488 +1.362125 -0.30224609375 0.0 -0.99987182617187488 +1.36225 -0.298065185546875 0.0 -0.99987182617187488 +1.3623750000000002 -0.2938232421875 0.0 -0.99987182617187488 +1.3625 -0.2938232421875 0.0 -0.99987182617187488 +1.362625 -0.289581298828125 0.0 -0.99987182617187488 +1.3627500000000002 -0.289581298828125 0.0 -0.99987182617187488 +1.362875 -0.285308837890625 0.0 -0.99987182617187488 +1.363 -0.280975341796875 0.0 -0.99987182617187488 +1.363125 -0.280975341796875 0.0 -0.99987182617187488 +1.36325 -0.276641845703125 0.0 -0.99987182617187488 +1.363375 -0.276641845703125 0.0 -0.99987182617187488 +1.3635 -0.27227783203125 0.0 -0.99987182617187488 +1.363625 -0.267852783203125 0.0 -0.99987182617187488 +1.36375 -0.267852783203125 0.0 -0.99987182617187488 +1.363875 -0.263427734375 0.0 -0.99987182617187488 +1.364 -0.263427734375 0.0 -0.99987182617187488 +1.364125 -0.25897216796875 0.0 -0.99987182617187488 +1.36425 -0.25445556640625 0.0 -0.99987182617187488 +1.3643750000000002 -0.25445556640625 0.0 -0.99987182617187488 +1.3645 -0.249969482421875 0.0 -0.99987182617187488 +1.364625 -0.249969482421875 0.0 -0.99987182617187488 +1.3647500000000002 -0.24542236328125 0.0 -0.99987182617187488 +1.364875 -0.2408447265625 0.0 -0.99987182617187488 +1.365 -0.2408447265625 0.0 -0.99987182617187488 +1.365125 -0.236236572265625 0.0 -0.99987182617187488 +1.36525 -0.236236572265625 0.0 -0.99987182617187488 +1.365375 -0.231597900390625 0.0 -0.99987182617187488 +1.3655 -0.226959228515625 0.0 -0.99987182617187488 +1.365625 -0.226959228515625 0.0 -0.99987182617187488 +1.36575 -0.2222900390625 0.0 -0.99987182617187488 +1.365875 -0.2222900390625 0.0 -0.99987182617187488 +1.366 -0.21759033203125 0.0 -0.99987182617187488 +1.366125 -0.212860107421875 0.0 -0.99987182617187488 +1.36625 -0.212860107421875 0.0 -0.99987182617187488 +1.3663750000000002 -0.208099365234375 0.0 -0.99987182617187488 +1.3665 -0.208099365234375 0.0 -0.99987182617187488 +1.366625 -0.203338623046875 0.0 -0.99987182617187488 +1.3667500000000002 -0.19854736328125 0.0 -0.99987182617187488 +1.366875 -0.19854736328125 0.0 -0.99987182617187488 +1.367 -0.1937255859375 0.0 -0.99987182617187488 +1.367125 -0.1937255859375 0.0 -0.99987182617187488 +1.36725 -0.188873291015625 0.0 -0.99987182617187488 +1.367375 -0.18402099609375 0.0 -0.99987182617187488 +1.3675 -0.18402099609375 0.0 -0.99987182617187488 +1.367625 -0.17913818359375 0.0 -0.99987182617187488 +1.36775 -0.17913818359375 0.0 -0.99987182617187488 +1.367875 -0.17425537109375 0.0 -0.99987182617187488 +1.368 -0.169342041015625 0.0 -0.99987182617187488 +1.368125 -0.169342041015625 0.0 -0.99987182617187488 +1.36825 -0.164398193359375 0.0 -0.99987182617187488 +1.3683750000000002 -0.164398193359375 0.0 -0.99987182617187488 +1.3685 -0.159454345703125 0.0 -0.99987182617187488 +1.368625 -0.15447998046875 0.0 -0.99987182617187488 +1.3687500000000002 -0.15447998046875 0.0 -0.99987182617187488 +1.368875 -0.14947509765625 0.0 -0.99987182617187488 +1.369 -0.14947509765625 0.0 -0.99987182617187488 +1.369125 -0.14447021484375 0.0 -0.99987182617187488 +1.36925 -0.13946533203125 0.0 -0.99987182617187488 +1.369375 -0.13946533203125 0.0 -0.99987182617187488 +1.3695 -0.134429931640625 0.0 -0.99987182617187488 +1.369625 -0.134429931640625 0.0 -0.99987182617187488 +1.36975 -0.129364013671875 0.0 -0.99987182617187488 +1.369875 -0.124298095703125 0.0 -0.99987182617187488 +1.37 -0.124298095703125 0.0 -0.99987182617187488 +1.370125 -0.119232177734375 0.0 -0.99987182617187488 +1.37025 -0.119232177734375 0.0 -0.99987182617187488 +1.3703750000000002 -0.1141357421875 0.0 -0.99987182617187488 +1.3705 -0.109039306640625 0.0 -0.99987182617187488 +1.370625 -0.109039306640625 0.0 -0.99987182617187488 +1.3707500000000002 -0.103912353515625 0.0 -0.99987182617187488 +1.370875 -0.103912353515625 0.0 -0.99987182617187488 +1.371 -0.098785400390625 0.0 -0.99987182617187488 +1.371125 -0.093658447265625 0.0 -0.99987182617187488 +1.37125 -0.093658447265625 0.0 -0.99987182617187488 +1.371375 -0.0885009765625 0.0 -0.99987182617187488 +1.3715 -0.0885009765625 0.0 -0.99987182617187488 +1.371625 -0.083343505859375 0.0 -0.99987182617187488 +1.37175 -0.07818603515625 0.0 -0.99987182617187488 +1.371875 -0.07818603515625 0.0 -0.99987182617187488 +1.372 -0.072998046875 0.0 -0.99987182617187488 +1.372125 -0.072998046875 0.0 -0.99987182617187488 +1.37225 -0.06781005859375 0.0 -0.99987182617187488 +1.3723750000000002 -0.0626220703125 0.0 -0.99987182617187488 +1.3725 -0.0626220703125 0.0 -0.99987182617187488 +1.372625 -0.05743408203125 0.0 -0.99987182617187488 +1.3727500000000002 -0.05743408203125 0.0 -0.99987182617187488 +1.372875 -0.05224609375 0.0 -0.99987182617187488 +1.373 -0.047027587890625 0.0 -0.99987182617187488 +1.373125 -0.047027587890625 0.0 -0.99987182617187488 +1.37325 -0.04180908203125 0.0 -0.99987182617187488 +1.373375 -0.04180908203125 0.0 -0.99987182617187488 +1.3735 -0.036590576171875 0.0 -0.99987182617187488 +1.373625 -0.0313720703125 0.0 -0.99987182617187488 +1.37375 -0.0313720703125 0.0 -0.99987182617187488 +1.373875 -0.026123046875 0.0 -0.99987182617187488 +1.374 -0.026123046875 0.0 -0.99987182617187488 +1.374125 -0.020904541015625 0.0 -0.99987182617187488 +1.37425 -0.01568603515625 0.0 -0.99987182617187488 +1.3743750000000002 -0.01568603515625 0.0 -0.99987182617187488 +1.3745 -0.01043701171875 0.0 -0.99987182617187488 +1.374625 -0.01043701171875 0.0 -0.99987182617187488 +1.3747500000000002 -0.005218505859375 0.0 -0.99987182617187488 +1.374875 0.0 0.0 -0.99987182617187488 +1.375 0.0 0.0 -0.99987182617187488 +1.375125 0.005218505859375 0.0 -0.99987182617187488 +1.37525 0.005218505859375 0.0 -0.99987182617187488 +1.375375 0.01043701171875 0.0 -0.99987182617187488 +1.3755 0.01568603515625 0.0 -0.99987182617187488 +1.375625 0.01568603515625 0.0 -0.99987182617187488 +1.37575 0.020904541015625 0.0 -0.99987182617187488 +1.375875 0.020904541015625 0.0 -0.99987182617187488 +1.3760000000000002 0.026123046875 0.002197265625 -0.915197753906247 +1.376125 0.0313720703125 0.002655029296875 -0.915197753906247 +1.37625 0.0313720703125 0.002655029296875 -0.915197753906247 +1.3763750000000002 0.036590576171875 0.003082275390625 -0.915197753906247 +1.3765 0.036590576171875 0.003082275390625 -0.915197753906247 +1.376625 0.04180908203125 0.0035400390625 -0.915197753906247 +1.37675 0.047027587890625 0.00396728515625 -0.915197753906247 +1.376875 0.047027587890625 0.00396728515625 -0.915197753906247 +1.377 0.05224609375 0.004425048828125 -0.915197753906247 +1.377125 0.05224609375 0.004425048828125 -0.915197753906247 +1.37725 0.05743408203125 0.004852294921875 -0.915197753906247 +1.377375 0.0626220703125 0.005279541015625 -0.915197753906247 +1.3775 0.0626220703125 0.005279541015625 -0.915197753906247 +1.377625 0.06781005859375 0.0057373046875 -0.915197753906247 +1.37775 0.06781005859375 0.0057373046875 -0.915197753906247 +1.377875 0.072998046875 0.00616455078125 -0.915197753906247 +1.3780000000000002 0.07818603515625 0.006622314453125 -0.915197753906247 +1.378125 0.07818603515625 0.006622314453125 -0.915197753906247 +1.37825 0.083343505859375 0.007049560546875 -0.915197753906247 +1.3783750000000002 0.083343505859375 0.007049560546875 -0.915197753906247 +1.3785 0.0885009765625 0.007476806640625 -0.915197753906247 +1.378625 0.093658447265625 0.0079345703125 -0.915197753906247 +1.37875 0.093658447265625 0.0079345703125 -0.915197753906247 +1.378875 0.098785400390625 0.00836181640625 -0.915197753906247 +1.379 0.098785400390625 0.00836181640625 -0.915197753906247 +1.379125 0.103912353515625 0.0087890625 -0.915197753906247 +1.37925 0.109039306640625 0.00921630859375 -0.915197753906247 +1.379375 0.109039306640625 0.00921630859375 -0.915197753906247 +1.3795 0.1141357421875 0.0096435546875 -0.915197753906247 +1.379625 0.1141357421875 0.0096435546875 -0.915197753906247 +1.37975 0.119232177734375 0.010101318359375 -0.915197753906247 +1.379875 0.124298095703125 0.010528564453125 -0.915197753906247 +1.3800000000000002 0.124298095703125 0.010528564453125 -0.915197753906247 +1.380125 0.129364013671875 0.010955810546875 -0.915197753906247 +1.38025 0.129364013671875 0.010955810546875 -0.915197753906247 +1.3803750000000002 0.134429931640625 0.011383056640625 -0.915197753906247 +1.3805 0.13946533203125 0.011810302734375 -0.915197753906247 +1.380625 0.13946533203125 0.011810302734375 -0.915197753906247 +1.38075 0.14447021484375 0.012237548828125 -0.915197753906247 +1.380875 0.14447021484375 0.012237548828125 -0.915197753906247 +1.381 0.14947509765625 0.012664794921875 -0.915197753906247 +1.381125 0.15447998046875 0.0130615234375 -0.915197753906247 +1.38125 0.15447998046875 0.0130615234375 -0.915197753906247 +1.381375 0.159454345703125 0.01348876953125 -0.915197753906247 +1.3815 0.159454345703125 0.01348876953125 -0.915197753906247 +1.381625 0.164398193359375 0.013916015625 -0.915197753906247 +1.38175 0.169342041015625 0.01434326171875 -0.915197753906247 +1.381875 0.169342041015625 0.01434326171875 -0.915197753906247 +1.3820000000000002 0.17425537109375 0.014739990234375 -0.915197753906247 +1.382125 0.17425537109375 0.014739990234375 -0.915197753906247 +1.38225 0.17913818359375 0.015167236328125 -0.915197753906247 +1.3823750000000002 0.18402099609375 0.01556396484375 -0.915197753906247 +1.3825 0.18402099609375 0.01556396484375 -0.915197753906247 +1.382625 0.188873291015625 0.0159912109375 -0.915197753906247 +1.38275 0.188873291015625 0.0159912109375 -0.915197753906247 +1.382875 0.1937255859375 0.016387939453125 -0.915197753906247 +1.383 0.19854736328125 0.016815185546875 -0.915197753906247 +1.383125 0.19854736328125 0.016815185546875 -0.915197753906247 +1.38325 0.203338623046875 0.0172119140625 -0.915197753906247 +1.383375 0.203338623046875 0.0172119140625 -0.915197753906247 +1.3835 0.208099365234375 0.017608642578125 -0.915197753906247 +1.383625 0.212860107421875 0.01800537109375 -0.915197753906247 +1.38375 0.212860107421875 0.01800537109375 -0.915197753906247 +1.383875 0.21759033203125 0.0184326171875 -0.915197753906247 +1.3840000000000002 0.21759033203125 0.0184326171875 -0.915197753906247 +1.384125 0.2222900390625 0.018829345703125 -0.915197753906247 +1.38425 0.226959228515625 0.01922607421875 -0.915197753906247 +1.3843750000000002 0.226959228515625 0.01922607421875 -0.915197753906247 +1.3845 0.231597900390625 0.019622802734375 -0.915197753906247 +1.384625 0.231597900390625 0.019622802734375 -0.915197753906247 +1.38475 0.236236572265625 0.019989013671875 -0.915197753906247 +1.384875 0.2408447265625 0.0203857421875 -0.915197753906247 +1.385 0.2408447265625 0.0203857421875 -0.915197753906247 +1.385125 0.24542236328125 0.020782470703125 -0.915197753906247 +1.38525 0.24542236328125 0.020782470703125 -0.915197753906247 +1.385375 0.249969482421875 0.021148681640625 -0.915197753906247 +1.3855 0.25445556640625 0.02154541015625 -0.915197753906247 +1.385625 0.25445556640625 0.02154541015625 -0.915197753906247 +1.38575 0.25897216796875 0.02191162109375 -0.915197753906247 +1.385875 0.25897216796875 0.02191162109375 -0.915197753906247 +1.3860000000000002 0.263427734375 0.022308349609375 -0.915197753906247 +1.386125 0.267852783203125 0.022674560546875 -0.915197753906247 +1.38625 0.267852783203125 0.022674560546875 -0.915197753906247 +1.3863750000000002 0.27227783203125 0.023040771484375 -0.915197753906247 +1.3865 0.27227783203125 0.023040771484375 -0.915197753906247 +1.386625 0.276641845703125 0.0234375 -0.915197753906247 +1.38675 0.280975341796875 0.0238037109375 -0.915197753906247 +1.386875 0.280975341796875 0.0238037109375 -0.915197753906247 +1.387 0.285308837890625 0.024169921875 -0.915197753906247 +1.387125 0.285308837890625 0.024169921875 -0.915197753906247 +1.38725 0.289581298828125 0.0245361328125 -0.915197753906247 +1.387375 0.2938232421875 0.024871826171875 -0.915197753906247 +1.3875 0.2938232421875 0.024871826171875 -0.915197753906247 +1.387625 0.298065185546875 0.025238037109375 -0.915197753906247 +1.38775 0.298065185546875 0.025238037109375 -0.915197753906247 +1.387875 0.30224609375 0.025604248046875 -0.915197753906247 +1.3880000000000002 0.306396484375 0.02593994140625 -0.915197753906247 +1.388125 0.306396484375 0.02593994140625 -0.915197753906247 +1.38825 0.310516357421875 0.02630615234375 -0.915197753906247 +1.3883750000000002 0.310516357421875 0.02630615234375 -0.915197753906247 +1.3885 0.314605712890625 0.026641845703125 -0.915197753906247 +1.388625 0.31866455078125 0.0269775390625 -0.915197753906247 +1.38875 0.31866455078125 0.0269775390625 -0.915197753906247 +1.388875 0.322662353515625 0.027313232421875 -0.915197753906247 +1.389 0.322662353515625 0.027313232421875 -0.915197753906247 +1.389125 0.32666015625 0.02764892578125 -0.915197753906247 +1.38925 0.330596923828125 0.027984619140625 -0.915197753906247 +1.389375 0.330596923828125 0.027984619140625 -0.915197753906247 +1.3895 0.334503173828125 0.0283203125 -0.915197753906247 +1.389625 0.334503173828125 0.0283203125 -0.915197753906247 +1.38975 0.33837890625 0.028656005859375 -0.915197753906247 +1.389875 0.34222412109375 0.02899169921875 -0.915197753906247 +1.3900000000000002 0.34222412109375 0.02899169921875 -0.915197753906247 +1.390125 0.34600830078125 0.029296875 -0.915197753906247 +1.39025 0.34600830078125 0.029296875 -0.915197753906247 +1.3903750000000002 0.349761962890625 0.029632568359375 -0.915197753906247 +1.3905 0.353485107421875 0.029937744140625 -0.915197753906247 +1.390625 0.353485107421875 0.029937744140625 -0.915197753906247 +1.39075 0.357177734375 0.030242919921875 -0.915197753906247 +1.390875 0.357177734375 0.030242919921875 -0.915197753906247 +1.391 0.360809326171875 0.030548095703125 -0.915197753906247 +1.391125 0.36444091796875 0.030853271484375 -0.915197753906247 +1.39125 0.36444091796875 0.030853271484375 -0.915197753906247 +1.391375 0.36798095703125 0.031158447265625 -0.915197753906247 +1.3915 0.36798095703125 0.031158447265625 -0.915197753906247 +1.3916250000000002 0.37152099609375 0.031463623046875 -0.915197753906247 +1.39175 0.375 0.031768798828125 -0.915197753906247 +1.391875 0.375 0.031768798828125 -0.915197753906247 +1.3920000000000002 0.378448486328125 0.03204345703125 -0.915197753906247 +1.392125 0.378448486328125 0.03204345703125 -0.915197753906247 +1.39225 0.3818359375 0.0323486328125 -0.915197753906247 +1.392375 0.38519287109375 0.032623291015625 -0.915197753906247 +1.3925 0.38519287109375 0.032623291015625 -0.915197753906247 +1.392625 0.388519287109375 0.03289794921875 -0.915197753906247 +1.39275 0.388519287109375 0.03289794921875 -0.915197753906247 +1.392875 0.39178466796875 0.033172607421875 -0.915197753906247 +1.393 0.39501953125 0.033447265625 -0.915197753906247 +1.393125 0.39501953125 0.033447265625 -0.915197753906247 +1.39325 0.398193359375 0.033721923828125 -0.915197753906247 +1.393375 0.398193359375 0.033721923828125 -0.915197753906247 +1.3935 0.401336669921875 0.03399658203125 -0.915197753906247 +1.3936250000000002 0.404449462890625 0.03424072265625 -0.915197753906247 +1.39375 0.404449462890625 0.03424072265625 -0.915197753906247 +1.393875 0.407501220703125 0.034515380859375 -0.915197753906247 +1.3940000000000002 0.407501220703125 0.034515380859375 -0.915197753906247 +1.394125 0.4105224609375 0.034759521484375 -0.915197753906247 +1.39425 0.413482666015625 0.035003662109375 -0.915197753906247 +1.394375 0.413482666015625 0.035003662109375 -0.915197753906247 +1.3945 0.416412353515625 0.0352783203125 -0.915197753906247 +1.394625 0.416412353515625 0.0352783203125 -0.915197753906247 +1.39475 0.419281005859375 0.0355224609375 -0.915197753906247 +1.394875 0.422119140625 0.035736083984375 -0.915197753906247 +1.395 0.422119140625 0.035736083984375 -0.915197753906247 +1.395125 0.424896240234375 0.035980224609375 -0.915197753906247 +1.39525 0.424896240234375 0.035980224609375 -0.915197753906247 +1.395375 0.4276123046875 0.036224365234375 -0.915197753906247 +1.3955 0.4302978515625 0.03643798828125 -0.915197753906247 +1.3956250000000002 0.4302978515625 0.03643798828125 -0.915197753906247 +1.39575 0.432952880859375 0.03668212890625 -0.915197753906247 +1.395875 0.432952880859375 0.03668212890625 -0.915197753906247 +1.3960000000000002 0.435546875 0.036895751953125 -0.915197753906247 +1.396125 0.438079833984375 0.037109375 -0.915197753906247 +1.39625 0.438079833984375 0.037109375 -0.915197753906247 +1.396375 0.440582275390625 0.037322998046875 -0.915197753906247 +1.3965 0.440582275390625 0.037322998046875 -0.915197753906247 +1.396625 0.44305419921875 0.03753662109375 -0.915197753906247 +1.39675 0.4454345703125 0.0377197265625 -0.915197753906247 +1.396875 0.4454345703125 0.0377197265625 -0.915197753906247 +1.397 0.447784423828125 0.037933349609375 -0.915197753906247 +1.397125 0.447784423828125 0.037933349609375 -0.915197753906247 +1.39725 0.450103759765625 0.038116455078125 -0.915197753906247 +1.397375 0.452362060546875 0.038299560546875 -0.915197753906247 +1.3975 0.452362060546875 0.038299560546875 -0.915197753906247 +1.3976250000000002 0.454559326171875 0.038482666015625 -0.915197753906247 +1.39775 0.454559326171875 0.038482666015625 -0.915197753906247 +1.397875 0.45672607421875 0.038665771484375 -0.915197753906247 +1.3980000000000002 0.458831787109375 0.038848876953125 -0.915197753906247 +1.398125 0.458831787109375 0.038848876953125 -0.915197753906247 +1.39825 0.46087646484375 0.039031982421875 -0.915197753906247 +1.398375 0.46087646484375 0.039031982421875 -0.915197753906247 +1.3985 0.462890625 0.039215087890625 -0.915197753906247 +1.398625 0.464813232421875 0.03936767578125 -0.915197753906247 +1.39875 0.464813232421875 0.03936767578125 -0.915197753906247 +1.398875 0.46673583984375 0.039520263671875 -0.915197753906247 +1.399 0.46673583984375 0.039520263671875 -0.915197753906247 +1.399125 0.46856689453125 0.0396728515625 -0.915197753906247 +1.39925 0.470367431640625 0.039825439453125 -0.915197753906247 +1.399375 0.470367431640625 0.039825439453125 -0.915197753906247 +1.3995 0.472137451171875 0.03997802734375 -0.915197753906247 +1.3996250000000002 0.472137451171875 0.03997802734375 -0.915197753906247 +1.39975 0.47381591796875 0.040130615234375 -0.915197753906247 +1.399875 0.4754638671875 0.040283203125 -0.915197753906247 +1.4000000000000002 0.4754638671875 0.040283203125 -0.915197753906247 +1.400125 0.47705078125 0.0404052734375 -0.915197753906247 +1.40025 0.47705078125 0.0404052734375 -0.915197753906247 +1.400375 0.478607177734375 0.04052734375 -0.915197753906247 +1.4005 0.480072021484375 0.0406494140625 -0.915197753906247 +1.400625 0.480072021484375 0.0406494140625 -0.915197753906247 +1.40075 0.48150634765625 0.040771484375 -0.915197753906247 +1.400875 0.48150634765625 0.040771484375 -0.915197753906247 +1.401 0.48291015625 0.0408935546875 -0.915197753906247 +1.401125 0.484222412109375 0.041015625 -0.915197753906247 +1.40125 0.484222412109375 0.041015625 -0.915197753906247 +1.401375 0.485504150390625 0.041107177734375 -0.915197753906247 +1.4015 0.485504150390625 0.041107177734375 -0.915197753906247 +1.4016250000000002 0.486724853515625 0.041229248046875 -0.915197753906247 +1.40175 0.487884521484375 0.04132080078125 -0.915197753906247 +1.401875 0.487884521484375 0.04132080078125 -0.915197753906247 +1.4020000000000002 0.489013671875 0.041412353515625 -0.915197753906247 +1.402125 0.489013671875 0.041412353515625 -0.915197753906247 +1.40225 0.490081787109375 0.04150390625 -0.915197753906247 +1.402375 0.4910888671875 0.041595458984375 -0.915197753906247 +1.4025 0.4910888671875 0.041595458984375 -0.915197753906247 +1.402625 0.492034912109375 0.04168701171875 -0.915197753906247 +1.40275 0.492034912109375 0.04168701171875 -0.915197753906247 +1.402875 0.492950439453125 0.041748046875 -0.915197753906247 +1.403 0.4937744140625 0.04180908203125 -0.915197753906247 +1.403125 0.4937744140625 0.04180908203125 -0.915197753906247 +1.40325 0.49456787109375 0.041900634765625 -0.915197753906247 +1.403375 0.49456787109375 0.041900634765625 -0.915197753906247 +1.4035 0.49530029296875 0.041961669921875 -0.915197753906247 +1.4036250000000002 0.496002197265625 0.0419921875 -0.915197753906247 +1.40375 0.496002197265625 0.0419921875 -0.915197753906247 +1.403875 0.496612548828125 0.04205322265625 -0.915197753906247 +1.4040000000000002 0.496612548828125 0.04205322265625 -0.915197753906247 +1.404125 0.4971923828125 0.0421142578125 -0.915197753906247 +1.40425 0.497711181640625 0.042144775390625 -0.915197753906247 +1.404375 0.497711181640625 0.042144775390625 -0.915197753906247 +1.4045 0.498199462890625 0.042205810546875 -0.915197753906247 +1.404625 0.498199462890625 0.042205810546875 -0.915197753906247 +1.40475 0.49859619140625 0.042236328125 -0.915197753906247 +1.404875 0.49896240234375 0.042266845703125 -0.915197753906247 +1.405 0.49896240234375 0.042266845703125 -0.915197753906247 +1.405125 0.499267578125 0.04229736328125 -0.915197753906247 +1.40525 0.499267578125 0.04229736328125 -0.915197753906247 +1.405375 0.49951171875 0.04229736328125 -0.915197753906247 +1.4055 0.49969482421875 0.042327880859375 -0.915197753906247 +1.4056250000000002 0.49969482421875 0.042327880859375 -0.915197753906247 +1.40575 0.49981689453125 0.042327880859375 -0.915197753906247 +1.405875 0.49981689453125 0.042327880859375 -0.915197753906247 +1.4060000000000002 0.499908447265625 0.042327880859375 -0.915197753906247 +1.406125 0.49993896484375 0.042327880859375 -0.915197753906247 +1.40625 0.49993896484375 0.042327880859375 -0.915197753906247 +1.406375 0.499908447265625 0.042327880859375 -0.915197753906247 +1.4065 0.499908447265625 0.042327880859375 -0.915197753906247 +1.406625 0.49981689453125 0.042327880859375 -0.915197753906247 +1.40675 0.49969482421875 0.042327880859375 -0.915197753906247 +1.406875 0.49969482421875 0.042327880859375 -0.915197753906247 +1.407 0.49951171875 0.04229736328125 -0.915197753906247 +1.407125 0.49951171875 0.04229736328125 -0.915197753906247 +1.4072500000000002 0.499267578125 0.04229736328125 -0.915197753906247 +1.407375 0.49896240234375 0.042266845703125 -0.915197753906247 +1.4075 0.49896240234375 0.042266845703125 -0.915197753906247 +1.4076250000000002 0.49859619140625 0.042236328125 -0.915197753906247 +1.40775 0.49859619140625 0.042236328125 -0.915197753906247 +1.407875 0.498199462890625 0.042205810546875 -0.915197753906247 +1.408 0.497711181640625 0.156982421875 -0.6845092773437448 +1.408125 0.497711181640625 0.156982421875 -0.6845092773437448 +1.40825 0.4971923828125 0.15679931640625 -0.6845092773437448 +1.408375 0.4971923828125 0.15679931640625 -0.6845092773437448 +1.4085 0.496612548828125 0.1566162109375 -0.6845092773437448 +1.408625 0.496002197265625 0.15643310546875 -0.6845092773437448 +1.40875 0.496002197265625 0.15643310546875 -0.6845092773437448 +1.408875 0.49530029296875 0.156219482421875 -0.6845092773437448 +1.409 0.49530029296875 0.156219482421875 -0.6845092773437448 +1.409125 0.49456787109375 0.155975341796875 -0.6845092773437448 +1.4092500000000002 0.4937744140625 0.155731201171875 -0.6845092773437448 +1.409375 0.4937744140625 0.155731201171875 -0.6845092773437448 +1.4095 0.492950439453125 0.15545654296875 -0.6845092773437448 +1.4096250000000002 0.492950439453125 0.15545654296875 -0.6845092773437448 +1.40975 0.492034912109375 0.155181884765625 -0.6845092773437448 +1.409875 0.4910888671875 0.154876708984375 -0.6845092773437448 +1.41 0.4910888671875 0.154876708984375 -0.6845092773437448 +1.410125 0.490081787109375 0.154571533203125 -0.6845092773437448 +1.41025 0.490081787109375 0.154571533203125 -0.6845092773437448 +1.410375 0.489013671875 0.15423583984375 -0.6845092773437448 +1.4105 0.487884521484375 0.15386962890625 -0.6845092773437448 +1.410625 0.487884521484375 0.15386962890625 -0.6845092773437448 +1.41075 0.486724853515625 0.15350341796875 -0.6845092773437448 +1.410875 0.486724853515625 0.15350341796875 -0.6845092773437448 +1.411 0.485504150390625 0.15313720703125 -0.6845092773437448 +1.411125 0.484222412109375 0.1527099609375 -0.6845092773437448 +1.4112500000000002 0.484222412109375 0.1527099609375 -0.6845092773437448 +1.411375 0.48291015625 0.152313232421875 -0.6845092773437448 +1.4115 0.48291015625 0.152313232421875 -0.6845092773437448 +1.4116250000000002 0.48150634765625 0.15185546875 -0.6845092773437448 +1.41175 0.480072021484375 0.15142822265625 -0.6845092773437448 +1.411875 0.480072021484375 0.15142822265625 -0.6845092773437448 +1.412 0.478607177734375 0.15093994140625 -0.6845092773437448 +1.412125 0.478607177734375 0.15093994140625 -0.6845092773437448 +1.41225 0.47705078125 0.15045166015625 -0.6845092773437448 +1.412375 0.4754638671875 0.14996337890625 -0.6845092773437448 +1.4125 0.4754638671875 0.14996337890625 -0.6845092773437448 +1.412625 0.47381591796875 0.149444580078125 -0.6845092773437448 +1.41275 0.47381591796875 0.149444580078125 -0.6845092773437448 +1.412875 0.472137451171875 0.148895263671875 -0.6845092773437448 +1.413 0.470367431640625 0.148345947265625 -0.6845092773437448 +1.413125 0.470367431640625 0.148345947265625 -0.6845092773437448 +1.4132500000000002 0.46856689453125 0.147796630859375 -0.6845092773437448 +1.413375 0.46856689453125 0.147796630859375 -0.6845092773437448 +1.4135 0.46673583984375 0.147216796875 -0.6845092773437448 +1.4136250000000002 0.464813232421875 0.1466064453125 -0.6845092773437448 +1.41375 0.464813232421875 0.1466064453125 -0.6845092773437448 +1.413875 0.462890625 0.14599609375 -0.6845092773437448 +1.414 0.462890625 0.14599609375 -0.6845092773437448 +1.414125 0.46087646484375 0.145355224609375 -0.6845092773437448 +1.41425 0.458831787109375 0.14471435546875 -0.6845092773437448 +1.414375 0.458831787109375 0.14471435546875 -0.6845092773437448 +1.4145 0.45672607421875 0.14404296875 -0.6845092773437448 +1.414625 0.45672607421875 0.14404296875 -0.6845092773437448 +1.41475 0.454559326171875 0.14337158203125 -0.6845092773437448 +1.414875 0.452362060546875 0.142669677734375 -0.6845092773437448 +1.415 0.452362060546875 0.142669677734375 -0.6845092773437448 +1.415125 0.450103759765625 0.1419677734375 -0.6845092773437448 +1.4152500000000002 0.450103759765625 0.1419677734375 -0.6845092773437448 +1.415375 0.447784423828125 0.1412353515625 -0.6845092773437448 +1.4155 0.4454345703125 0.1405029296875 -0.6845092773437448 +1.4156250000000002 0.4454345703125 0.1405029296875 -0.6845092773437448 +1.41575 0.44305419921875 0.139739990234375 -0.6845092773437448 +1.415875 0.44305419921875 0.139739990234375 -0.6845092773437448 +1.416 0.440582275390625 0.138946533203125 -0.6845092773437448 +1.416125 0.438079833984375 0.13818359375 -0.6845092773437448 +1.41625 0.438079833984375 0.13818359375 -0.6845092773437448 +1.416375 0.435546875 0.137359619140625 -0.6845092773437448 +1.4165 0.435546875 0.137359619140625 -0.6845092773437448 +1.416625 0.432952880859375 0.136566162109375 -0.6845092773437448 +1.41675 0.4302978515625 0.135711669921875 -0.6845092773437448 +1.416875 0.4302978515625 0.135711669921875 -0.6845092773437448 +1.417 0.4276123046875 0.134857177734375 -0.6845092773437448 +1.417125 0.4276123046875 0.134857177734375 -0.6845092773437448 +1.4172500000000002 0.424896240234375 0.134002685546875 -0.6845092773437448 +1.417375 0.422119140625 0.13311767578125 -0.6845092773437448 +1.4175 0.422119140625 0.13311767578125 -0.6845092773437448 +1.4176250000000002 0.419281005859375 0.132232666015625 -0.6845092773437448 +1.41775 0.419281005859375 0.132232666015625 -0.6845092773437448 +1.417875 0.416412353515625 0.131317138671875 -0.6845092773437448 +1.418 0.413482666015625 0.130401611328125 -0.6845092773437448 +1.418125 0.413482666015625 0.130401611328125 -0.6845092773437448 +1.41825 0.4105224609375 0.129486083984375 -0.6845092773437448 +1.418375 0.4105224609375 0.129486083984375 -0.6845092773437448 +1.4185 0.407501220703125 0.128509521484375 -0.6845092773437448 +1.418625 0.404449462890625 0.1275634765625 -0.6845092773437448 +1.41875 0.404449462890625 0.1275634765625 -0.6845092773437448 +1.418875 0.401336669921875 0.1265869140625 -0.6845092773437448 +1.419 0.401336669921875 0.1265869140625 -0.6845092773437448 +1.419125 0.398193359375 0.125579833984375 -0.6845092773437448 +1.4192500000000002 0.39501953125 0.12457275390625 -0.6845092773437448 +1.419375 0.39501953125 0.12457275390625 -0.6845092773437448 +1.4195 0.39178466796875 0.123565673828125 -0.6845092773437448 +1.4196250000000002 0.39178466796875 0.123565673828125 -0.6845092773437448 +1.41975 0.388519287109375 0.122528076171875 -0.6845092773437448 +1.419875 0.38519287109375 0.121490478515625 -0.6845092773437448 +1.42 0.38519287109375 0.121490478515625 -0.6845092773437448 +1.420125 0.3818359375 0.12042236328125 -0.6845092773437448 +1.42025 0.3818359375 0.12042236328125 -0.6845092773437448 +1.420375 0.378448486328125 0.119354248046875 -0.6845092773437448 +1.4205 0.375 0.118255615234375 -0.6845092773437448 +1.420625 0.375 0.118255615234375 -0.6845092773437448 +1.42075 0.37152099609375 0.117156982421875 -0.6845092773437448 +1.420875 0.37152099609375 0.117156982421875 -0.6845092773437448 +1.421 0.36798095703125 0.116058349609375 -0.6845092773437448 +1.421125 0.36444091796875 0.11492919921875 -0.6845092773437448 +1.4212500000000002 0.36444091796875 0.11492919921875 -0.6845092773437448 +1.421375 0.360809326171875 0.113800048828125 -0.6845092773437448 +1.4215 0.360809326171875 0.113800048828125 -0.6845092773437448 +1.4216250000000002 0.357177734375 0.112640380859375 -0.6845092773437448 +1.42175 0.353485107421875 0.111480712890625 -0.6845092773437448 +1.421875 0.353485107421875 0.111480712890625 -0.6845092773437448 +1.422 0.349761962890625 0.110321044921875 -0.6845092773437448 +1.422125 0.349761962890625 0.110321044921875 -0.6845092773437448 +1.42225 0.34600830078125 0.109130859375 -0.6845092773437448 +1.422375 0.34222412109375 0.107940673828125 -0.6845092773437448 +1.4225 0.34222412109375 0.107940673828125 -0.6845092773437448 +1.422625 0.33837890625 0.106719970703125 -0.6845092773437448 +1.42275 0.33837890625 0.106719970703125 -0.6845092773437448 +1.4228750000000002 0.334503173828125 0.105499267578125 -0.6845092773437448 +1.423 0.330596923828125 0.104278564453125 -0.6845092773437448 +1.423125 0.330596923828125 0.104278564453125 -0.6845092773437448 +1.4232500000000002 0.32666015625 0.10302734375 -0.6845092773437448 +1.423375 0.32666015625 0.10302734375 -0.6845092773437448 +1.4235 0.322662353515625 0.101776123046875 -0.6845092773437448 +1.4236250000000002 0.31866455078125 0.100494384765625 -0.6845092773437448 +1.42375 0.31866455078125 0.100494384765625 -0.6845092773437448 +1.423875 0.314605712890625 0.099212646484375 -0.6845092773437448 +1.424 0.314605712890625 0.099212646484375 -0.6845092773437448 +1.424125 0.310516357421875 0.097930908203125 -0.6845092773437448 +1.42425 0.306396484375 0.096649169921875 -0.6845092773437448 +1.424375 0.306396484375 0.096649169921875 -0.6845092773437448 +1.4245 0.30224609375 0.0953369140625 -0.6845092773437448 +1.424625 0.30224609375 0.0953369140625 -0.6845092773437448 +1.42475 0.298065185546875 0.093994140625 -0.6845092773437448 +1.4248750000000002 0.2938232421875 0.092681884765625 -0.6845092773437448 +1.425 0.2938232421875 0.092681884765625 -0.6845092773437448 +1.425125 0.289581298828125 0.091339111328125 -0.6845092773437448 +1.4252500000000002 0.289581298828125 0.091339111328125 -0.6845092773437448 +1.425375 0.285308837890625 0.0899658203125 -0.6845092773437448 +1.4255 0.280975341796875 0.088623046875 -0.6845092773437448 +1.425625 0.280975341796875 0.088623046875 -0.6845092773437448 +1.42575 0.276641845703125 0.087249755859375 -0.6845092773437448 +1.425875 0.276641845703125 0.087249755859375 -0.6845092773437448 +1.426 0.27227783203125 0.08587646484375 -0.6845092773437448 +1.426125 0.267852783203125 0.08447265625 -0.6845092773437448 +1.42625 0.267852783203125 0.08447265625 -0.6845092773437448 +1.426375 0.263427734375 0.08306884765625 -0.6845092773437448 +1.4265 0.263427734375 0.08306884765625 -0.6845092773437448 +1.426625 0.25897216796875 0.0816650390625 -0.6845092773437448 +1.42675 0.25445556640625 0.08026123046875 -0.6845092773437448 +1.4268750000000002 0.25445556640625 0.08026123046875 -0.6845092773437448 +1.427 0.249969482421875 0.078826904296875 -0.6845092773437448 +1.427125 0.249969482421875 0.078826904296875 -0.6845092773437448 +1.4272500000000002 0.24542236328125 0.077392578125 -0.6845092773437448 +1.427375 0.2408447265625 0.075958251953125 -0.6845092773437448 +1.4275 0.2408447265625 0.075958251953125 -0.6845092773437448 +1.427625 0.236236572265625 0.074493408203125 -0.6845092773437448 +1.42775 0.236236572265625 0.074493408203125 -0.6845092773437448 +1.427875 0.231597900390625 0.073028564453125 -0.6845092773437448 +1.428 0.226959228515625 0.071563720703125 -0.6845092773437448 +1.428125 0.226959228515625 0.071563720703125 -0.6845092773437448 +1.42825 0.2222900390625 0.070098876953125 -0.6845092773437448 +1.428375 0.2222900390625 0.070098876953125 -0.6845092773437448 +1.4285 0.21759033203125 0.068603515625 -0.6845092773437448 +1.428625 0.212860107421875 0.067138671875 -0.6845092773437448 +1.42875 0.212860107421875 0.067138671875 -0.6845092773437448 +1.4288750000000002 0.208099365234375 0.065643310546875 -0.6845092773437448 +1.429 0.208099365234375 0.065643310546875 -0.6845092773437448 +1.429125 0.203338623046875 0.064117431640625 -0.6845092773437448 +1.4292500000000002 0.19854736328125 0.0626220703125 -0.6845092773437448 +1.429375 0.19854736328125 0.0626220703125 -0.6845092773437448 +1.4295 0.1937255859375 0.06109619140625 -0.6845092773437448 +1.429625 0.1937255859375 0.06109619140625 -0.6845092773437448 +1.42975 0.188873291015625 0.0595703125 -0.6845092773437448 +1.429875 0.18402099609375 0.05804443359375 -0.6845092773437448 +1.43 0.18402099609375 0.05804443359375 -0.6845092773437448 +1.430125 0.17913818359375 0.056488037109375 -0.6845092773437448 +1.43025 0.17913818359375 0.056488037109375 -0.6845092773437448 +1.430375 0.17425537109375 0.054962158203125 -0.6845092773437448 +1.4305 0.169342041015625 0.05340576171875 -0.6845092773437448 +1.430625 0.169342041015625 0.05340576171875 -0.6845092773437448 +1.43075 0.164398193359375 0.051849365234375 -0.6845092773437448 +1.4308750000000002 0.164398193359375 0.051849365234375 -0.6845092773437448 +1.431 0.159454345703125 0.05029296875 -0.6845092773437448 +1.431125 0.15447998046875 0.0487060546875 -0.6845092773437448 +1.4312500000000002 0.15447998046875 0.0487060546875 -0.6845092773437448 +1.431375 0.14947509765625 0.047149658203125 -0.6845092773437448 +1.4315 0.14947509765625 0.047149658203125 -0.6845092773437448 +1.431625 0.14447021484375 0.045562744140625 -0.6845092773437448 +1.43175 0.13946533203125 0.043975830078125 -0.6845092773437448 +1.431875 0.13946533203125 0.043975830078125 -0.6845092773437448 +1.432 0.134429931640625 0.042388916015625 -0.6845092773437448 +1.432125 0.134429931640625 0.042388916015625 -0.6845092773437448 +1.43225 0.129364013671875 0.040802001953125 -0.6845092773437448 +1.432375 0.124298095703125 0.0391845703125 -0.6845092773437448 +1.4325 0.124298095703125 0.0391845703125 -0.6845092773437448 +1.432625 0.119232177734375 0.03759765625 -0.6845092773437448 +1.43275 0.119232177734375 0.03759765625 -0.6845092773437448 +1.4328750000000002 0.1141357421875 0.035980224609375 -0.6845092773437448 +1.433 0.109039306640625 0.034393310546875 -0.6845092773437448 +1.433125 0.109039306640625 0.034393310546875 -0.6845092773437448 +1.4332500000000002 0.103912353515625 0.03277587890625 -0.6845092773437448 +1.433375 0.103912353515625 0.03277587890625 -0.6845092773437448 +1.4335 0.098785400390625 0.031158447265625 -0.6845092773437448 +1.433625 0.093658447265625 0.029541015625 -0.6845092773437448 +1.43375 0.093658447265625 0.029541015625 -0.6845092773437448 +1.433875 0.0885009765625 0.02789306640625 -0.6845092773437448 +1.434 0.0885009765625 0.02789306640625 -0.6845092773437448 +1.434125 0.083343505859375 0.026275634765625 -0.6845092773437448 +1.43425 0.07818603515625 0.024658203125 -0.6845092773437448 +1.434375 0.07818603515625 0.024658203125 -0.6845092773437448 +1.4345 0.072998046875 0.02301025390625 -0.6845092773437448 +1.434625 0.072998046875 0.02301025390625 -0.6845092773437448 +1.43475 0.06781005859375 0.021392822265625 -0.6845092773437448 +1.4348750000000002 0.0626220703125 0.019744873046875 -0.6845092773437448 +1.435 0.0626220703125 0.019744873046875 -0.6845092773437448 +1.435125 0.05743408203125 0.018096923828125 -0.6845092773437448 +1.4352500000000002 0.05743408203125 0.018096923828125 -0.6845092773437448 +1.435375 0.05224609375 0.0164794921875 -0.6845092773437448 +1.4355 0.047027587890625 0.01483154296875 -0.6845092773437448 +1.435625 0.047027587890625 0.01483154296875 -0.6845092773437448 +1.43575 0.04180908203125 0.01318359375 -0.6845092773437448 +1.435875 0.04180908203125 0.01318359375 -0.6845092773437448 +1.436 0.036590576171875 0.01153564453125 -0.6845092773437448 +1.436125 0.0313720703125 0.0098876953125 -0.6845092773437448 +1.43625 0.0313720703125 0.0098876953125 -0.6845092773437448 +1.436375 0.026123046875 0.00823974609375 -0.6845092773437448 +1.4365 0.026123046875 0.00823974609375 -0.6845092773437448 +1.436625 0.020904541015625 0.006591796875 -0.6845092773437448 +1.43675 0.01568603515625 0.00494384765625 -0.6845092773437448 +1.4368750000000002 0.01568603515625 0.00494384765625 -0.6845092773437448 +1.437 0.01043701171875 0.0032958984375 -0.6845092773437448 +1.437125 0.01043701171875 0.0032958984375 -0.6845092773437448 +1.4372500000000002 0.005218505859375 0.00164794921875 -0.6845092773437448 +1.437375 0.0 0.0 -0.6845092773437448 +1.4375 0.0 0.0 -0.6845092773437448 +1.437625 -0.005218505859375 -0.00164794921875 -0.6845092773437448 +1.43775 -0.005218505859375 -0.00164794921875 -0.6845092773437448 +1.437875 -0.01043701171875 -0.0032958984375 -0.6845092773437448 +1.438 -0.01568603515625 -0.00494384765625 -0.6845092773437448 +1.438125 -0.01568603515625 -0.00494384765625 -0.6845092773437448 +1.43825 -0.020904541015625 -0.006591796875 -0.6845092773437448 +1.438375 -0.020904541015625 -0.006591796875 -0.6845092773437448 +1.4385000000000002 -0.026123046875 -0.00823974609375 -0.6845092773437448 +1.438625 -0.0313720703125 -0.0098876953125 -0.6845092773437448 +1.43875 -0.0313720703125 -0.0098876953125 -0.6845092773437448 +1.4388750000000002 -0.036590576171875 -0.01153564453125 -0.6845092773437448 +1.439 -0.036590576171875 -0.01153564453125 -0.6845092773437448 +1.439125 -0.04180908203125 -0.01318359375 -0.6845092773437448 +1.4392500000000002 -0.047027587890625 -0.01483154296875 -0.6845092773437448 +1.439375 -0.047027587890625 -0.01483154296875 -0.6845092773437448 +1.4395 -0.05224609375 -0.0164794921875 -0.6845092773437448 +1.439625 -0.05224609375 -0.0164794921875 -0.6845092773437448 +1.43975 -0.05743408203125 -0.018096923828125 -0.6845092773437448 +1.439875 -0.0626220703125 -0.019744873046875 -0.6845092773437448 +1.44 -0.0626220703125 -0.041046142578125 -0.3446105957031174 +1.440125 -0.06781005859375 -0.04443359375 -0.3446105957031174 +1.44025 -0.06781005859375 -0.04443359375 -0.3446105957031174 +1.440375 -0.072998046875 -0.0478515625 -0.3446105957031174 +1.4405000000000002 -0.07818603515625 -0.051239013671875 -0.3446105957031174 +1.440625 -0.07818603515625 -0.051239013671875 -0.3446105957031174 +1.44075 -0.083343505859375 -0.05462646484375 -0.3446105957031174 +1.4408750000000002 -0.083343505859375 -0.05462646484375 -0.3446105957031174 +1.441 -0.0885009765625 -0.058013916015625 -0.3446105957031174 +1.441125 -0.093658447265625 -0.061370849609375 -0.3446105957031174 +1.44125 -0.093658447265625 -0.061370849609375 -0.3446105957031174 +1.441375 -0.098785400390625 -0.064727783203125 -0.3446105957031174 +1.4415 -0.098785400390625 -0.064727783203125 -0.3446105957031174 +1.441625 -0.103912353515625 -0.068084716796875 -0.3446105957031174 +1.44175 -0.109039306640625 -0.071441650390625 -0.3446105957031174 +1.441875 -0.109039306640625 -0.071441650390625 -0.3446105957031174 +1.442 -0.1141357421875 -0.074798583984375 -0.3446105957031174 +1.442125 -0.1141357421875 -0.074798583984375 -0.3446105957031174 +1.44225 -0.119232177734375 -0.078125 -0.3446105957031174 +1.442375 -0.124298095703125 -0.081451416015625 -0.3446105957031174 +1.4425000000000002 -0.124298095703125 -0.081451416015625 -0.3446105957031174 +1.442625 -0.129364013671875 -0.08477783203125 -0.3446105957031174 +1.44275 -0.129364013671875 -0.08477783203125 -0.3446105957031174 +1.4428750000000002 -0.134429931640625 -0.08807373046875 -0.3446105957031174 +1.443 -0.13946533203125 -0.091400146484375 -0.3446105957031174 +1.443125 -0.13946533203125 -0.091400146484375 -0.3446105957031174 +1.44325 -0.14447021484375 -0.09466552734375 -0.3446105957031174 +1.443375 -0.14447021484375 -0.09466552734375 -0.3446105957031174 +1.4435 -0.14947509765625 -0.09796142578125 -0.3446105957031174 +1.443625 -0.15447998046875 -0.101226806640625 -0.3446105957031174 +1.44375 -0.15447998046875 -0.101226806640625 -0.3446105957031174 +1.443875 -0.159454345703125 -0.1044921875 -0.3446105957031174 +1.444 -0.159454345703125 -0.1044921875 -0.3446105957031174 +1.444125 -0.164398193359375 -0.10772705078125 -0.3446105957031174 +1.44425 -0.169342041015625 -0.1109619140625 -0.3446105957031174 +1.444375 -0.169342041015625 -0.1109619140625 -0.3446105957031174 +1.4445000000000002 -0.17425537109375 -0.11419677734375 -0.3446105957031174 +1.444625 -0.17425537109375 -0.11419677734375 -0.3446105957031174 +1.44475 -0.17913818359375 -0.117401123046875 -0.3446105957031174 +1.4448750000000002 -0.18402099609375 -0.12060546875 -0.3446105957031174 +1.445 -0.18402099609375 -0.12060546875 -0.3446105957031174 +1.445125 -0.188873291015625 -0.123779296875 -0.3446105957031174 +1.44525 -0.188873291015625 -0.123779296875 -0.3446105957031174 +1.445375 -0.1937255859375 -0.126953125 -0.3446105957031174 +1.4455 -0.19854736328125 -0.130096435546875 -0.3446105957031174 +1.445625 -0.19854736328125 -0.130096435546875 -0.3446105957031174 +1.44575 -0.203338623046875 -0.13323974609375 -0.3446105957031174 +1.445875 -0.203338623046875 -0.13323974609375 -0.3446105957031174 +1.446 -0.208099365234375 -0.136383056640625 -0.3446105957031174 +1.446125 -0.212860107421875 -0.139495849609375 -0.3446105957031174 +1.44625 -0.212860107421875 -0.139495849609375 -0.3446105957031174 +1.446375 -0.21759033203125 -0.142578125 -0.3446105957031174 +1.4465000000000002 -0.21759033203125 -0.142578125 -0.3446105957031174 +1.446625 -0.2222900390625 -0.145660400390625 -0.3446105957031174 +1.44675 -0.226959228515625 -0.148712158203125 -0.3446105957031174 +1.4468750000000002 -0.226959228515625 -0.148712158203125 -0.3446105957031174 +1.447 -0.231597900390625 -0.151763916015625 -0.3446105957031174 +1.447125 -0.231597900390625 -0.151763916015625 -0.3446105957031174 +1.44725 -0.236236572265625 -0.154815673828125 -0.3446105957031174 +1.447375 -0.2408447265625 -0.157806396484375 -0.3446105957031174 +1.4475 -0.2408447265625 -0.157806396484375 -0.3446105957031174 +1.447625 -0.24542236328125 -0.16082763671875 -0.3446105957031174 +1.44775 -0.24542236328125 -0.16082763671875 -0.3446105957031174 +1.447875 -0.249969482421875 -0.163787841796875 -0.3446105957031174 +1.448 -0.25445556640625 -0.166748046875 -0.3446105957031174 +1.448125 -0.25445556640625 -0.166748046875 -0.3446105957031174 +1.44825 -0.25897216796875 -0.169708251953125 -0.3446105957031174 +1.448375 -0.25897216796875 -0.169708251953125 -0.3446105957031174 +1.4485000000000002 -0.263427734375 -0.172637939453125 -0.3446105957031174 +1.448625 -0.267852783203125 -0.175537109375 -0.3446105957031174 +1.44875 -0.267852783203125 -0.175537109375 -0.3446105957031174 +1.4488750000000002 -0.27227783203125 -0.178436279296875 -0.3446105957031174 +1.449 -0.27227783203125 -0.178436279296875 -0.3446105957031174 +1.449125 -0.276641845703125 -0.1812744140625 -0.3446105957031174 +1.44925 -0.280975341796875 -0.18414306640625 -0.3446105957031174 +1.449375 -0.280975341796875 -0.18414306640625 -0.3446105957031174 +1.4495 -0.285308837890625 -0.186981201171875 -0.3446105957031174 +1.449625 -0.285308837890625 -0.186981201171875 -0.3446105957031174 +1.44975 -0.289581298828125 -0.189788818359375 -0.3446105957031174 +1.449875 -0.2938232421875 -0.19256591796875 -0.3446105957031174 +1.45 -0.2938232421875 -0.19256591796875 -0.3446105957031174 +1.450125 -0.298065185546875 -0.195343017578125 -0.3446105957031174 +1.45025 -0.298065185546875 -0.195343017578125 -0.3446105957031174 +1.450375 -0.30224609375 -0.19805908203125 -0.3446105957031174 +1.4505000000000002 -0.306396484375 -0.2008056640625 -0.3446105957031174 +1.450625 -0.306396484375 -0.2008056640625 -0.3446105957031174 +1.45075 -0.310516357421875 -0.2034912109375 -0.3446105957031174 +1.4508750000000002 -0.310516357421875 -0.2034912109375 -0.3446105957031174 +1.451 -0.314605712890625 -0.2061767578125 -0.3446105957031174 +1.451125 -0.31866455078125 -0.208831787109375 -0.3446105957031174 +1.45125 -0.31866455078125 -0.208831787109375 -0.3446105957031174 +1.451375 -0.322662353515625 -0.211456298828125 -0.3446105957031174 +1.4515 -0.322662353515625 -0.211456298828125 -0.3446105957031174 +1.451625 -0.32666015625 -0.214080810546875 -0.3446105957031174 +1.45175 -0.330596923828125 -0.216644287109375 -0.3446105957031174 +1.451875 -0.330596923828125 -0.216644287109375 -0.3446105957031174 +1.452 -0.334503173828125 -0.219207763671875 -0.3446105957031174 +1.452125 -0.334503173828125 -0.219207763671875 -0.3446105957031174 +1.45225 -0.33837890625 -0.22174072265625 -0.3446105957031174 +1.452375 -0.34222412109375 -0.224273681640625 -0.3446105957031174 +1.4525000000000002 -0.34222412109375 -0.224273681640625 -0.3446105957031174 +1.452625 -0.34600830078125 -0.22674560546875 -0.3446105957031174 +1.45275 -0.34600830078125 -0.22674560546875 -0.3446105957031174 +1.4528750000000002 -0.349761962890625 -0.229217529296875 -0.3446105957031174 +1.453 -0.353485107421875 -0.231658935546875 -0.3446105957031174 +1.453125 -0.353485107421875 -0.231658935546875 -0.3446105957031174 +1.45325 -0.357177734375 -0.23406982421875 -0.3446105957031174 +1.453375 -0.357177734375 -0.23406982421875 -0.3446105957031174 +1.4535 -0.360809326171875 -0.2364501953125 -0.3446105957031174 +1.453625 -0.36444091796875 -0.23883056640625 -0.3446105957031174 +1.45375 -0.36444091796875 -0.23883056640625 -0.3446105957031174 +1.453875 -0.36798095703125 -0.24114990234375 -0.3446105957031174 +1.454 -0.36798095703125 -0.24114990234375 -0.3446105957031174 +1.4541250000000002 -0.37152099609375 -0.24346923828125 -0.3446105957031174 +1.45425 -0.375 -0.245758056640625 -0.3446105957031174 +1.454375 -0.375 -0.245758056640625 -0.3446105957031174 +1.4545000000000002 -0.378448486328125 -0.248016357421875 -0.3446105957031174 +1.454625 -0.378448486328125 -0.248016357421875 -0.3446105957031174 +1.45475 -0.3818359375 -0.250244140625 -0.3446105957031174 +1.4548750000000002 -0.38519287109375 -0.25244140625 -0.3446105957031174 +1.455 -0.38519287109375 -0.25244140625 -0.3446105957031174 +1.455125 -0.388519287109375 -0.254608154296875 -0.3446105957031174 +1.45525 -0.388519287109375 -0.254608154296875 -0.3446105957031174 +1.455375 -0.39178466796875 -0.256744384765625 -0.3446105957031174 +1.4555 -0.39501953125 -0.258880615234375 -0.3446105957031174 +1.455625 -0.39501953125 -0.258880615234375 -0.3446105957031174 +1.45575 -0.398193359375 -0.260955810546875 -0.3446105957031174 +1.455875 -0.398193359375 -0.260955810546875 -0.3446105957031174 +1.456 -0.401336669921875 -0.26300048828125 -0.3446105957031174 +1.4561250000000002 -0.404449462890625 -0.265045166015625 -0.3446105957031174 +1.45625 -0.404449462890625 -0.265045166015625 -0.3446105957031174 +1.456375 -0.407501220703125 -0.267059326171875 -0.3446105957031174 +1.4565000000000002 -0.407501220703125 -0.267059326171875 -0.3446105957031174 +1.456625 -0.4105224609375 -0.269012451171875 -0.3446105957031174 +1.45675 -0.413482666015625 -0.270965576171875 -0.3446105957031174 +1.456875 -0.413482666015625 -0.270965576171875 -0.3446105957031174 +1.457 -0.416412353515625 -0.27288818359375 -0.3446105957031174 +1.457125 -0.416412353515625 -0.27288818359375 -0.3446105957031174 +1.45725 -0.419281005859375 -0.274749755859375 -0.3446105957031174 +1.457375 -0.422119140625 -0.276611328125 -0.3446105957031174 +1.4575 -0.422119140625 -0.276611328125 -0.3446105957031174 +1.457625 -0.424896240234375 -0.2784423828125 -0.3446105957031174 +1.45775 -0.424896240234375 -0.2784423828125 -0.3446105957031174 +1.457875 -0.4276123046875 -0.280242919921875 -0.3446105957031174 +1.458 -0.4302978515625 -0.281982421875 -0.3446105957031174 +1.4581250000000002 -0.4302978515625 -0.281982421875 -0.3446105957031174 +1.45825 -0.432952880859375 -0.283721923828125 -0.3446105957031174 +1.458375 -0.432952880859375 -0.283721923828125 -0.3446105957031174 +1.4585000000000002 -0.435546875 -0.285430908203125 -0.3446105957031174 +1.458625 -0.438079833984375 -0.287078857421875 -0.3446105957031174 +1.45875 -0.438079833984375 -0.287078857421875 -0.3446105957031174 +1.458875 -0.440582275390625 -0.288726806640625 -0.3446105957031174 +1.459 -0.440582275390625 -0.288726806640625 -0.3446105957031174 +1.459125 -0.44305419921875 -0.29034423828125 -0.3446105957031174 +1.45925 -0.4454345703125 -0.291900634765625 -0.3446105957031174 +1.459375 -0.4454345703125 -0.291900634765625 -0.3446105957031174 +1.4595 -0.447784423828125 -0.29345703125 -0.3446105957031174 +1.459625 -0.447784423828125 -0.29345703125 -0.3446105957031174 +1.45975 -0.450103759765625 -0.294952392578125 -0.3446105957031174 +1.459875 -0.452362060546875 -0.29644775390625 -0.3446105957031174 +1.46 -0.452362060546875 -0.29644775390625 -0.3446105957031174 +1.4601250000000002 -0.454559326171875 -0.297882080078125 -0.3446105957031174 +1.46025 -0.454559326171875 -0.297882080078125 -0.3446105957031174 +1.460375 -0.45672607421875 -0.299285888671875 -0.3446105957031174 +1.4605000000000002 -0.458831787109375 -0.300689697265625 -0.3446105957031174 +1.460625 -0.458831787109375 -0.300689697265625 -0.3446105957031174 +1.46075 -0.46087646484375 -0.302032470703125 -0.3446105957031174 +1.460875 -0.46087646484375 -0.302032470703125 -0.3446105957031174 +1.461 -0.462890625 -0.3033447265625 -0.3446105957031174 +1.461125 -0.464813232421875 -0.304595947265625 -0.3446105957031174 +1.46125 -0.464813232421875 -0.304595947265625 -0.3446105957031174 +1.461375 -0.46673583984375 -0.30584716796875 -0.3446105957031174 +1.4615 -0.46673583984375 -0.30584716796875 -0.3446105957031174 +1.461625 -0.46856689453125 -0.30706787109375 -0.3446105957031174 +1.46175 -0.470367431640625 -0.308258056640625 -0.3446105957031174 +1.461875 -0.470367431640625 -0.308258056640625 -0.3446105957031174 +1.462 -0.472137451171875 -0.30938720703125 -0.3446105957031174 +1.4621250000000002 -0.472137451171875 -0.30938720703125 -0.3446105957031174 +1.46225 -0.47381591796875 -0.310516357421875 -0.3446105957031174 +1.462375 -0.4754638671875 -0.31158447265625 -0.3446105957031174 +1.4625000000000002 -0.4754638671875 -0.31158447265625 -0.3446105957031174 +1.462625 -0.47705078125 -0.3126220703125 -0.3446105957031174 +1.46275 -0.47705078125 -0.3126220703125 -0.3446105957031174 +1.462875 -0.478607177734375 -0.313629150390625 -0.3446105957031174 +1.463 -0.480072021484375 -0.314605712890625 -0.3446105957031174 +1.463125 -0.480072021484375 -0.314605712890625 -0.3446105957031174 +1.46325 -0.48150634765625 -0.3155517578125 -0.3446105957031174 +1.463375 -0.48150634765625 -0.3155517578125 -0.3446105957031174 +1.4635 -0.48291015625 -0.31646728515625 -0.3446105957031174 +1.463625 -0.484222412109375 -0.31732177734375 -0.3446105957031174 +1.46375 -0.484222412109375 -0.31732177734375 -0.3446105957031174 +1.463875 -0.485504150390625 -0.31817626953125 -0.3446105957031174 +1.464 -0.485504150390625 -0.31817626953125 -0.3446105957031174 +1.4641250000000002 -0.486724853515625 -0.3189697265625 -0.3446105957031174 +1.46425 -0.487884521484375 -0.319732666015625 -0.3446105957031174 +1.464375 -0.487884521484375 -0.319732666015625 -0.3446105957031174 +1.4645000000000002 -0.489013671875 -0.320465087890625 -0.3446105957031174 +1.464625 -0.489013671875 -0.320465087890625 -0.3446105957031174 +1.46475 -0.490081787109375 -0.3211669921875 -0.3446105957031174 +1.464875 -0.4910888671875 -0.321807861328125 -0.3446105957031174 +1.465 -0.4910888671875 -0.321807861328125 -0.3446105957031174 +1.465125 -0.492034912109375 -0.32244873046875 -0.3446105957031174 +1.46525 -0.492034912109375 -0.32244873046875 -0.3446105957031174 +1.465375 -0.492950439453125 -0.323028564453125 -0.3446105957031174 +1.4655 -0.4937744140625 -0.323577880859375 -0.3446105957031174 +1.465625 -0.4937744140625 -0.323577880859375 -0.3446105957031174 +1.46575 -0.49456787109375 -0.3240966796875 -0.3446105957031174 +1.465875 -0.49456787109375 -0.3240966796875 -0.3446105957031174 +1.466 -0.49530029296875 -0.3245849609375 -0.3446105957031174 +1.4661250000000002 -0.496002197265625 -0.325042724609375 -0.3446105957031174 +1.46625 -0.496002197265625 -0.325042724609375 -0.3446105957031174 +1.466375 -0.496612548828125 -0.325439453125 -0.3446105957031174 +1.4665000000000002 -0.496612548828125 -0.325439453125 -0.3446105957031174 +1.466625 -0.4971923828125 -0.325836181640625 -0.3446105957031174 +1.46675 -0.497711181640625 -0.326171875 -0.3446105957031174 +1.466875 -0.497711181640625 -0.326171875 -0.3446105957031174 +1.467 -0.498199462890625 -0.32647705078125 -0.3446105957031174 +1.467125 -0.498199462890625 -0.32647705078125 -0.3446105957031174 +1.46725 -0.49859619140625 -0.326751708984375 -0.3446105957031174 +1.467375 -0.49896240234375 -0.32696533203125 -0.3446105957031174 +1.4675 -0.49896240234375 -0.32696533203125 -0.3446105957031174 +1.467625 -0.499267578125 -0.327178955078125 -0.3446105957031174 +1.46775 -0.499267578125 -0.327178955078125 -0.3446105957031174 +1.467875 -0.49951171875 -0.32733154296875 -0.3446105957031174 +1.468 -0.49969482421875 -0.32745361328125 -0.3446105957031174 +1.4681250000000002 -0.49969482421875 -0.32745361328125 -0.3446105957031174 +1.46825 -0.49981689453125 -0.327545166015625 -0.3446105957031174 +1.468375 -0.49981689453125 -0.327545166015625 -0.3446105957031174 +1.4685000000000002 -0.499908447265625 -0.327606201171875 -0.3446105957031174 +1.468625 -0.49993896484375 -0.32763671875 -0.3446105957031174 +1.46875 -0.49993896484375 -0.32763671875 -0.3446105957031174 +1.468875 -0.499908447265625 -0.327606201171875 -0.3446105957031174 +1.469 -0.499908447265625 -0.327606201171875 -0.3446105957031174 +1.469125 -0.49981689453125 -0.327545166015625 -0.3446105957031174 +1.46925 -0.49969482421875 -0.32745361328125 -0.3446105957031174 +1.469375 -0.49969482421875 -0.32745361328125 -0.3446105957031174 +1.4695 -0.49951171875 -0.32733154296875 -0.3446105957031174 +1.469625 -0.49951171875 -0.32733154296875 -0.3446105957031174 +1.4697500000000002 -0.499267578125 -0.327178955078125 -0.3446105957031174 +1.469875 -0.49896240234375 -0.32696533203125 -0.3446105957031174 +1.47 -0.49896240234375 -0.32696533203125 -0.3446105957031174 +1.4701250000000002 -0.49859619140625 -0.326751708984375 -0.3446105957031174 +1.47025 -0.49859619140625 -0.326751708984375 -0.3446105957031174 +1.470375 -0.498199462890625 -0.32647705078125 -0.3446105957031174 +1.4705000000000002 -0.497711181640625 -0.326171875 -0.3446105957031174 +1.470625 -0.497711181640625 -0.326171875 -0.3446105957031174 +1.47075 -0.4971923828125 -0.325836181640625 -0.3446105957031174 +1.470875 -0.4971923828125 -0.325836181640625 -0.3446105957031174 +1.471 -0.496612548828125 -0.325439453125 -0.3446105957031174 +1.471125 -0.496002197265625 -0.325042724609375 -0.3446105957031174 +1.47125 -0.496002197265625 -0.325042724609375 -0.3446105957031174 +1.471375 -0.49530029296875 -0.3245849609375 -0.3446105957031174 +1.4715 -0.49530029296875 -0.3245849609375 -0.3446105957031174 +1.471625 -0.49456787109375 -0.3240966796875 -0.3446105957031174 +1.4717500000000002 -0.4937744140625 -0.323577880859375 -0.3446105957031174 +1.471875 -0.4937744140625 -0.323577880859375 -0.3446105957031174 +1.472 -0.468170166015625 -0.492950439453125 0.050219726562508388 +1.4721250000000002 -0.468170166015625 -0.492950439453125 0.050219726562508388 +1.47225 -0.467315673828125 -0.492034912109375 0.050219726562508388 +1.472375 -0.466400146484375 -0.4910888671875 0.050219726562508388 +1.4725 -0.466400146484375 -0.4910888671875 0.050219726562508388 +1.472625 -0.465423583984375 -0.490081787109375 0.050219726562508388 +1.47275 -0.465423583984375 -0.490081787109375 0.050219726562508388 +1.472875 -0.46441650390625 -0.489013671875 0.050219726562508388 +1.473 -0.463348388671875 -0.487884521484375 0.050219726562508388 +1.473125 -0.463348388671875 -0.487884521484375 0.050219726562508388 +1.47325 -0.462249755859375 -0.486724853515625 0.050219726562508388 +1.473375 -0.462249755859375 -0.486724853515625 0.050219726562508388 +1.4735 -0.461090087890625 -0.485504150390625 0.050219726562508388 +1.473625 -0.459869384765625 -0.484222412109375 0.050219726562508388 +1.4737500000000002 -0.459869384765625 -0.484222412109375 0.050219726562508388 +1.473875 -0.4586181640625 -0.48291015625 0.050219726562508388 +1.474 -0.4586181640625 -0.48291015625 0.050219726562508388 +1.4741250000000002 -0.457305908203125 -0.48150634765625 0.050219726562508388 +1.47425 -0.4559326171875 -0.480072021484375 0.050219726562508388 +1.474375 -0.4559326171875 -0.480072021484375 0.050219726562508388 +1.4745 -0.45452880859375 -0.478607177734375 0.050219726562508388 +1.474625 -0.45452880859375 -0.478607177734375 0.050219726562508388 +1.47475 -0.45306396484375 -0.47705078125 0.050219726562508388 +1.474875 -0.451568603515625 -0.4754638671875 0.050219726562508388 +1.475 -0.451568603515625 -0.4754638671875 0.050219726562508388 +1.475125 -0.45001220703125 -0.47381591796875 0.050219726562508388 +1.47525 -0.45001220703125 -0.47381591796875 0.050219726562508388 +1.475375 -0.448394775390625 -0.472137451171875 0.050219726562508388 +1.4755 -0.44671630859375 -0.470367431640625 0.050219726562508388 +1.475625 -0.44671630859375 -0.470367431640625 0.050219726562508388 +1.4757500000000002 -0.44500732421875 -0.46856689453125 0.050219726562508388 +1.475875 -0.44500732421875 -0.46856689453125 0.050219726562508388 +1.476 -0.443267822265625 -0.46673583984375 0.050219726562508388 +1.4761250000000002 -0.441436767578125 -0.464813232421875 0.050219726562508388 +1.47625 -0.441436767578125 -0.464813232421875 0.050219726562508388 +1.476375 -0.439605712890625 -0.462890625 0.050219726562508388 +1.4765 -0.439605712890625 -0.462890625 0.050219726562508388 +1.476625 -0.43768310546875 -0.46087646484375 0.050219726562508388 +1.47675 -0.435760498046875 -0.458831787109375 0.050219726562508388 +1.476875 -0.435760498046875 -0.458831787109375 0.050219726562508388 +1.477 -0.433746337890625 -0.45672607421875 0.050219726562508388 +1.477125 -0.433746337890625 -0.45672607421875 0.050219726562508388 +1.47725 -0.43170166015625 -0.454559326171875 0.050219726562508388 +1.477375 -0.42962646484375 -0.452362060546875 0.050219726562508388 +1.4775 -0.42962646484375 -0.452362060546875 0.050219726562508388 +1.477625 -0.427459716796875 -0.450103759765625 0.050219726562508388 +1.4777500000000002 -0.427459716796875 -0.450103759765625 0.050219726562508388 +1.477875 -0.42529296875 -0.447784423828125 0.050219726562508388 +1.478 -0.42303466796875 -0.4454345703125 0.050219726562508388 +1.4781250000000002 -0.42303466796875 -0.4454345703125 0.050219726562508388 +1.47825 -0.4207763671875 -0.44305419921875 0.050219726562508388 +1.478375 -0.4207763671875 -0.44305419921875 0.050219726562508388 +1.4785 -0.418426513671875 -0.440582275390625 0.050219726562508388 +1.478625 -0.41607666015625 -0.438079833984375 0.050219726562508388 +1.47875 -0.41607666015625 -0.438079833984375 0.050219726562508388 +1.478875 -0.413665771484375 -0.435546875 0.050219726562508388 +1.479 -0.413665771484375 -0.435546875 0.050219726562508388 +1.479125 -0.41119384765625 -0.432952880859375 0.050219726562508388 +1.47925 -0.408660888671875 -0.4302978515625 0.050219726562508388 +1.479375 -0.408660888671875 -0.4302978515625 0.050219726562508388 +1.4795 -0.4061279296875 -0.4276123046875 0.050219726562508388 +1.479625 -0.4061279296875 -0.4276123046875 0.050219726562508388 +1.4797500000000002 -0.403533935546875 -0.424896240234375 0.050219726562508388 +1.479875 -0.40087890625 -0.422119140625 0.050219726562508388 +1.48 -0.40087890625 -0.422119140625 0.050219726562508388 +1.4801250000000002 -0.398193359375 -0.419281005859375 0.050219726562508388 +1.48025 -0.398193359375 -0.419281005859375 0.050219726562508388 +1.480375 -0.395477294921875 -0.416412353515625 0.050219726562508388 +1.4805 -0.3927001953125 -0.413482666015625 0.050219726562508388 +1.480625 -0.3927001953125 -0.413482666015625 0.050219726562508388 +1.48075 -0.389862060546875 -0.4105224609375 0.050219726562508388 +1.480875 -0.389862060546875 -0.4105224609375 0.050219726562508388 +1.481 -0.38702392578125 -0.407501220703125 0.050219726562508388 +1.481125 -0.384124755859375 -0.404449462890625 0.050219726562508388 +1.48125 -0.384124755859375 -0.404449462890625 0.050219726562508388 +1.481375 -0.38116455078125 -0.401336669921875 0.050219726562508388 +1.4815 -0.38116455078125 -0.401336669921875 0.050219726562508388 +1.481625 -0.378173828125 -0.398193359375 0.050219726562508388 +1.4817500000000002 -0.37518310546875 -0.39501953125 0.050219726562508388 +1.481875 -0.37518310546875 -0.39501953125 0.050219726562508388 +1.482 -0.372100830078125 -0.39178466796875 0.050219726562508388 +1.4821250000000002 -0.372100830078125 -0.39178466796875 0.050219726562508388 +1.48225 -0.368988037109375 -0.388519287109375 0.050219726562508388 +1.482375 -0.3658447265625 -0.38519287109375 0.050219726562508388 +1.4825 -0.3658447265625 -0.38519287109375 0.050219726562508388 +1.482625 -0.362640380859375 -0.3818359375 0.050219726562508388 +1.48275 -0.362640380859375 -0.3818359375 0.050219726562508388 +1.482875 -0.359405517578125 -0.378448486328125 0.050219726562508388 +1.483 -0.35614013671875 -0.375 0.050219726562508388 +1.483125 -0.35614013671875 -0.375 0.050219726562508388 +1.48325 -0.35284423828125 -0.37152099609375 0.050219726562508388 +1.483375 -0.35284423828125 -0.37152099609375 0.050219726562508388 +1.4835 -0.3494873046875 -0.36798095703125 0.050219726562508388 +1.483625 -0.346099853515625 -0.36444091796875 0.050219726562508388 +1.4837500000000002 -0.346099853515625 -0.36444091796875 0.050219726562508388 +1.483875 -0.342681884765625 -0.360809326171875 0.050219726562508388 +1.484 -0.342681884765625 -0.360809326171875 0.050219726562508388 +1.4841250000000002 -0.3392333984375 -0.357177734375 0.050219726562508388 +1.48425 -0.335723876953125 -0.353485107421875 0.050219726562508388 +1.484375 -0.335723876953125 -0.353485107421875 0.050219726562508388 +1.4845 -0.332183837890625 -0.349761962890625 0.050219726562508388 +1.484625 -0.332183837890625 -0.349761962890625 0.050219726562508388 +1.48475 -0.32861328125 -0.34600830078125 0.050219726562508388 +1.484875 -0.32501220703125 -0.34222412109375 0.050219726562508388 +1.485 -0.32501220703125 -0.34222412109375 0.050219726562508388 +1.485125 -0.321380615234375 -0.33837890625 0.050219726562508388 +1.48525 -0.321380615234375 -0.33837890625 0.050219726562508388 +1.4853750000000002 -0.31768798828125 -0.334503173828125 0.050219726562508388 +1.4855 -0.313995361328125 -0.330596923828125 0.050219726562508388 +1.485625 -0.313995361328125 -0.330596923828125 0.050219726562508388 +1.4857500000000002 -0.31024169921875 -0.32666015625 0.050219726562508388 +1.485875 -0.31024169921875 -0.32666015625 0.050219726562508388 +1.486 -0.30645751953125 -0.322662353515625 0.050219726562508388 +1.4861250000000002 -0.302642822265625 -0.31866455078125 0.050219726562508388 +1.48625 -0.302642822265625 -0.31866455078125 0.050219726562508388 +1.486375 -0.298797607421875 -0.314605712890625 0.050219726562508388 +1.4865 -0.298797607421875 -0.314605712890625 0.050219726562508388 +1.486625 -0.294921875 -0.310516357421875 0.050219726562508388 +1.48675 -0.291015625 -0.306396484375 0.050219726562508388 +1.486875 -0.291015625 -0.306396484375 0.050219726562508388 +1.487 -0.28704833984375 -0.30224609375 0.050219726562508388 +1.487125 -0.28704833984375 -0.30224609375 0.050219726562508388 +1.48725 -0.2830810546875 -0.298065185546875 0.050219726562508388 +1.4873750000000002 -0.279052734375 -0.2938232421875 0.050219726562508388 +1.4875 -0.279052734375 -0.2938232421875 0.050219726562508388 +1.487625 -0.2750244140625 -0.289581298828125 0.050219726562508388 +1.4877500000000002 -0.2750244140625 -0.289581298828125 0.050219726562508388 +1.487875 -0.270965576171875 -0.285308837890625 0.050219726562508388 +1.488 -0.266876220703125 -0.280975341796875 0.050219726562508388 +1.488125 -0.266876220703125 -0.280975341796875 0.050219726562508388 +1.48825 -0.262725830078125 -0.276641845703125 0.050219726562508388 +1.488375 -0.262725830078125 -0.276641845703125 0.050219726562508388 +1.4885 -0.258575439453125 -0.27227783203125 0.050219726562508388 +1.488625 -0.25439453125 -0.267852783203125 0.050219726562508388 +1.48875 -0.25439453125 -0.267852783203125 0.050219726562508388 +1.488875 -0.25018310546875 -0.263427734375 0.050219726562508388 +1.489 -0.25018310546875 -0.263427734375 0.050219726562508388 +1.489125 -0.245941162109375 -0.25897216796875 0.050219726562508388 +1.48925 -0.241668701171875 -0.25445556640625 0.050219726562508388 +1.4893750000000002 -0.241668701171875 -0.25445556640625 0.050219726562508388 +1.4895 -0.237396240234375 -0.249969482421875 0.050219726562508388 +1.489625 -0.237396240234375 -0.249969482421875 0.050219726562508388 +1.4897500000000002 -0.233062744140625 -0.24542236328125 0.050219726562508388 +1.489875 -0.228729248046875 -0.2408447265625 0.050219726562508388 +1.49 -0.228729248046875 -0.2408447265625 0.050219726562508388 +1.490125 -0.224365234375 -0.236236572265625 0.050219726562508388 +1.49025 -0.224365234375 -0.236236572265625 0.050219726562508388 +1.490375 -0.219970703125 -0.231597900390625 0.050219726562508388 +1.4905 -0.215545654296875 -0.226959228515625 0.050219726562508388 +1.490625 -0.215545654296875 -0.226959228515625 0.050219726562508388 +1.49075 -0.211090087890625 -0.2222900390625 0.050219726562508388 +1.490875 -0.211090087890625 -0.2222900390625 0.050219726562508388 +1.491 -0.206634521484375 -0.21759033203125 0.050219726562508388 +1.491125 -0.2021484375 -0.212860107421875 0.050219726562508388 +1.49125 -0.2021484375 -0.212860107421875 0.050219726562508388 +1.4913750000000002 -0.1976318359375 -0.208099365234375 0.050219726562508388 +1.4915 -0.1976318359375 -0.208099365234375 0.050219726562508388 +1.491625 -0.193115234375 -0.203338623046875 0.050219726562508388 +1.4917500000000002 -0.188568115234375 -0.19854736328125 0.050219726562508388 +1.491875 -0.188568115234375 -0.19854736328125 0.050219726562508388 +1.492 -0.183990478515625 -0.1937255859375 0.050219726562508388 +1.492125 -0.183990478515625 -0.1937255859375 0.050219726562508388 +1.49225 -0.17938232421875 -0.188873291015625 0.050219726562508388 +1.492375 -0.174774169921875 -0.18402099609375 0.050219726562508388 +1.4925 -0.174774169921875 -0.18402099609375 0.050219726562508388 +1.492625 -0.170135498046875 -0.17913818359375 0.050219726562508388 +1.49275 -0.170135498046875 -0.17913818359375 0.050219726562508388 +1.492875 -0.165496826171875 -0.17425537109375 0.050219726562508388 +1.493 -0.16082763671875 -0.169342041015625 0.050219726562508388 +1.493125 -0.16082763671875 -0.169342041015625 0.050219726562508388 +1.49325 -0.1561279296875 -0.164398193359375 0.050219726562508388 +1.4933750000000002 -0.1561279296875 -0.164398193359375 0.050219726562508388 +1.4935 -0.15142822265625 -0.159454345703125 0.050219726562508388 +1.493625 -0.146697998046875 -0.15447998046875 0.050219726562508388 +1.4937500000000002 -0.146697998046875 -0.15447998046875 0.050219726562508388 +1.493875 -0.1419677734375 -0.14947509765625 0.050219726562508388 +1.494 -0.1419677734375 -0.14947509765625 0.050219726562508388 +1.494125 -0.13720703125 -0.14447021484375 0.050219726562508388 +1.49425 -0.1324462890625 -0.13946533203125 0.050219726562508388 +1.494375 -0.1324462890625 -0.13946533203125 0.050219726562508388 +1.4945 -0.127655029296875 -0.134429931640625 0.050219726562508388 +1.494625 -0.127655029296875 -0.134429931640625 0.050219726562508388 +1.49475 -0.12286376953125 -0.129364013671875 0.050219726562508388 +1.494875 -0.1180419921875 -0.124298095703125 0.050219726562508388 +1.495 -0.1180419921875 -0.124298095703125 0.050219726562508388 +1.495125 -0.113250732421875 -0.119232177734375 0.050219726562508388 +1.49525 -0.113250732421875 -0.119232177734375 0.050219726562508388 +1.4953750000000002 -0.1083984375 -0.1141357421875 0.050219726562508388 +1.4955 -0.103546142578125 -0.109039306640625 0.050219726562508388 +1.495625 -0.103546142578125 -0.109039306640625 0.050219726562508388 +1.4957500000000002 -0.09869384765625 -0.103912353515625 0.050219726562508388 +1.495875 -0.09869384765625 -0.103912353515625 0.050219726562508388 +1.496 -0.093841552734375 -0.098785400390625 0.050219726562508388 +1.496125 -0.088958740234375 -0.093658447265625 0.050219726562508388 +1.49625 -0.088958740234375 -0.093658447265625 0.050219726562508388 +1.496375 -0.084075927734375 -0.0885009765625 0.050219726562508388 +1.4965 -0.084075927734375 -0.0885009765625 0.050219726562508388 +1.496625 -0.07916259765625 -0.083343505859375 0.050219726562508388 +1.49675 -0.074249267578125 -0.07818603515625 0.050219726562508388 +1.496875 -0.074249267578125 -0.07818603515625 0.050219726562508388 +1.497 -0.0693359375 -0.072998046875 0.050219726562508388 +1.497125 -0.0693359375 -0.072998046875 0.050219726562508388 +1.49725 -0.064422607421875 -0.06781005859375 0.050219726562508388 +1.4973750000000002 -0.059478759765625 -0.0626220703125 0.050219726562508388 +1.4975 -0.059478759765625 -0.0626220703125 0.050219726562508388 +1.497625 -0.0545654296875 -0.05743408203125 0.050219726562508388 +1.4977500000000002 -0.0545654296875 -0.05743408203125 0.050219726562508388 +1.497875 -0.04962158203125 -0.05224609375 0.050219726562508388 +1.498 -0.044647216796875 -0.047027587890625 0.050219726562508388 +1.498125 -0.044647216796875 -0.047027587890625 0.050219726562508388 +1.49825 -0.039703369140625 -0.04180908203125 0.050219726562508388 +1.498375 -0.039703369140625 -0.04180908203125 0.050219726562508388 +1.4985 -0.034759521484375 -0.036590576171875 0.050219726562508388 +1.498625 -0.02978515625 -0.0313720703125 0.050219726562508388 +1.49875 -0.02978515625 -0.0313720703125 0.050219726562508388 +1.498875 -0.024810791015625 -0.026123046875 0.050219726562508388 +1.499 -0.024810791015625 -0.026123046875 0.050219726562508388 +1.499125 -0.019866943359375 -0.020904541015625 0.050219726562508388 +1.49925 -0.014892578125 -0.01568603515625 0.050219726562508388 +1.4993750000000002 -0.014892578125 -0.01568603515625 0.050219726562508388 +1.4995 -0.009918212890625 -0.01043701171875 0.050219726562508388 +1.499625 -0.009918212890625 -0.01043701171875 0.050219726562508388 +1.4997500000000002 -0.00494384765625 -0.005218505859375 0.050219726562508388 +1.499875 0.0 0.0 0.050219726562508388 +1.5 0.0 0.0 0.050219726562508388 +1.500125 0.00494384765625 0.005218505859375 0.050219726562508388 +1.50025 0.00494384765625 0.005218505859375 0.050219726562508388 +1.500375 0.009918212890625 0.01043701171875 0.050219726562508388 +1.5005 0.014892578125 0.01568603515625 0.050219726562508388 +1.500625 0.014892578125 0.01568603515625 0.050219726562508388 +1.50075 0.019866943359375 0.020904541015625 0.050219726562508388 +1.500875 0.019866943359375 0.020904541015625 0.050219726562508388 +1.5010000000000002 0.024810791015625 0.026123046875 0.050219726562508388 +1.501125 0.02978515625 0.0313720703125 0.050219726562508388 +1.50125 0.02978515625 0.0313720703125 0.050219726562508388 +1.5013750000000002 0.034759521484375 0.036590576171875 0.050219726562508388 +1.5015 0.034759521484375 0.036590576171875 0.050219726562508388 +1.501625 0.039703369140625 0.04180908203125 0.050219726562508388 +1.5017500000000002 0.044647216796875 0.047027587890625 0.050219726562508388 +1.501875 0.044647216796875 0.047027587890625 0.050219726562508388 +1.502 0.04962158203125 0.05224609375 0.050219726562508388 +1.502125 0.04962158203125 0.05224609375 0.050219726562508388 +1.50225 0.0545654296875 0.05743408203125 0.050219726562508388 +1.502375 0.059478759765625 0.0626220703125 0.050219726562508388 +1.5025 0.059478759765625 0.0626220703125 0.050219726562508388 +1.502625 0.064422607421875 0.06781005859375 0.050219726562508388 +1.50275 0.064422607421875 0.06781005859375 0.050219726562508388 +1.502875 0.0693359375 0.072998046875 0.050219726562508388 +1.5030000000000002 0.074249267578125 0.07818603515625 0.050219726562508388 +1.503125 0.074249267578125 0.07818603515625 0.050219726562508388 +1.50325 0.07916259765625 0.083343505859375 0.050219726562508388 +1.5033750000000002 0.07916259765625 0.083343505859375 0.050219726562508388 +1.5035 0.084075927734375 0.0885009765625 0.050219726562508388 +1.503625 0.088958740234375 0.093658447265625 0.050219726562508388 +1.5037500000000002 0.088958740234375 0.093658447265625 0.050219726562508388 +1.503875 0.093841552734375 0.098785400390625 0.050219726562508388 +1.504 0.05560302734375 0.098785400390625 0.43709106445313256 +1.504125 0.0584716796875 0.103912353515625 0.43709106445313256 +1.50425 0.061370849609375 0.109039306640625 0.43709106445313256 +1.504375 0.061370849609375 0.109039306640625 0.43709106445313256 +1.5045 0.064239501953125 0.1141357421875 0.43709106445313256 +1.504625 0.064239501953125 0.1141357421875 0.43709106445313256 +1.50475 0.067108154296875 0.119232177734375 0.43709106445313256 +1.504875 0.0699462890625 0.124298095703125 0.43709106445313256 +1.5050000000000002 0.0699462890625 0.124298095703125 0.43709106445313256 +1.505125 0.07281494140625 0.129364013671875 0.43709106445313256 +1.50525 0.07281494140625 0.129364013671875 0.43709106445313256 +1.5053750000000002 0.075653076171875 0.134429931640625 0.43709106445313256 +1.5055 0.0784912109375 0.13946533203125 0.43709106445313256 +1.505625 0.0784912109375 0.13946533203125 0.43709106445313256 +1.50575 0.081298828125 0.14447021484375 0.43709106445313256 +1.505875 0.081298828125 0.14447021484375 0.43709106445313256 +1.506 0.084136962890625 0.14947509765625 0.43709106445313256 +1.506125 0.086944580078125 0.15447998046875 0.43709106445313256 +1.50625 0.086944580078125 0.15447998046875 0.43709106445313256 +1.506375 0.0897216796875 0.159454345703125 0.43709106445313256 +1.5065 0.0897216796875 0.159454345703125 0.43709106445313256 +1.506625 0.092529296875 0.164398193359375 0.43709106445313256 +1.50675 0.095306396484375 0.169342041015625 0.43709106445313256 +1.506875 0.095306396484375 0.169342041015625 0.43709106445313256 +1.5070000000000002 0.098052978515625 0.17425537109375 0.43709106445313256 +1.507125 0.098052978515625 0.17425537109375 0.43709106445313256 +1.50725 0.100830078125 0.17913818359375 0.43709106445313256 +1.5073750000000002 0.10357666015625 0.18402099609375 0.43709106445313256 +1.5075 0.10357666015625 0.18402099609375 0.43709106445313256 +1.507625 0.106292724609375 0.188873291015625 0.43709106445313256 +1.50775 0.106292724609375 0.188873291015625 0.43709106445313256 +1.507875 0.1090087890625 0.1937255859375 0.43709106445313256 +1.508 0.111724853515625 0.19854736328125 0.43709106445313256 +1.508125 0.111724853515625 0.19854736328125 0.43709106445313256 +1.50825 0.11444091796875 0.203338623046875 0.43709106445313256 +1.508375 0.11444091796875 0.203338623046875 0.43709106445313256 +1.5085 0.11712646484375 0.208099365234375 0.43709106445313256 +1.508625 0.119781494140625 0.212860107421875 0.43709106445313256 +1.50875 0.119781494140625 0.212860107421875 0.43709106445313256 +1.508875 0.122467041015625 0.21759033203125 0.43709106445313256 +1.5090000000000002 0.122467041015625 0.21759033203125 0.43709106445313256 +1.509125 0.125091552734375 0.2222900390625 0.43709106445313256 +1.50925 0.127716064453125 0.226959228515625 0.43709106445313256 +1.5093750000000002 0.127716064453125 0.226959228515625 0.43709106445313256 +1.5095 0.130340576171875 0.231597900390625 0.43709106445313256 +1.509625 0.130340576171875 0.231597900390625 0.43709106445313256 +1.50975 0.132965087890625 0.236236572265625 0.43709106445313256 +1.509875 0.135528564453125 0.2408447265625 0.43709106445313256 +1.51 0.135528564453125 0.2408447265625 0.43709106445313256 +1.510125 0.13812255859375 0.24542236328125 0.43709106445313256 +1.51025 0.13812255859375 0.24542236328125 0.43709106445313256 +1.510375 0.14068603515625 0.249969482421875 0.43709106445313256 +1.5105 0.143218994140625 0.25445556640625 0.43709106445313256 +1.510625 0.143218994140625 0.25445556640625 0.43709106445313256 +1.51075 0.145751953125 0.25897216796875 0.43709106445313256 +1.510875 0.145751953125 0.25897216796875 0.43709106445313256 +1.5110000000000002 0.14825439453125 0.263427734375 0.43709106445313256 +1.511125 0.1507568359375 0.267852783203125 0.43709106445313256 +1.51125 0.1507568359375 0.267852783203125 0.43709106445313256 +1.5113750000000002 0.153228759765625 0.27227783203125 0.43709106445313256 +1.5115 0.153228759765625 0.27227783203125 0.43709106445313256 +1.511625 0.15570068359375 0.276641845703125 0.43709106445313256 +1.51175 0.15814208984375 0.280975341796875 0.43709106445313256 +1.511875 0.15814208984375 0.280975341796875 0.43709106445313256 +1.512 0.16058349609375 0.285308837890625 0.43709106445313256 +1.512125 0.16058349609375 0.285308837890625 0.43709106445313256 +1.51225 0.162994384765625 0.289581298828125 0.43709106445313256 +1.512375 0.165374755859375 0.2938232421875 0.43709106445313256 +1.5125 0.165374755859375 0.2938232421875 0.43709106445313256 +1.512625 0.167755126953125 0.298065185546875 0.43709106445313256 +1.51275 0.167755126953125 0.298065185546875 0.43709106445313256 +1.512875 0.17010498046875 0.30224609375 0.43709106445313256 +1.5130000000000002 0.172454833984375 0.306396484375 0.43709106445313256 +1.513125 0.172454833984375 0.306396484375 0.43709106445313256 +1.51325 0.174774169921875 0.310516357421875 0.43709106445313256 +1.5133750000000002 0.174774169921875 0.310516357421875 0.43709106445313256 +1.5135 0.17706298828125 0.314605712890625 0.43709106445313256 +1.513625 0.179351806640625 0.31866455078125 0.43709106445313256 +1.51375 0.179351806640625 0.31866455078125 0.43709106445313256 +1.513875 0.181610107421875 0.322662353515625 0.43709106445313256 +1.514 0.181610107421875 0.322662353515625 0.43709106445313256 +1.514125 0.183837890625 0.32666015625 0.43709106445313256 +1.51425 0.186065673828125 0.330596923828125 0.43709106445313256 +1.514375 0.186065673828125 0.330596923828125 0.43709106445313256 +1.5145 0.188262939453125 0.334503173828125 0.43709106445313256 +1.514625 0.188262939453125 0.334503173828125 0.43709106445313256 +1.51475 0.190460205078125 0.33837890625 0.43709106445313256 +1.514875 0.192596435546875 0.34222412109375 0.43709106445313256 +1.5150000000000002 0.192596435546875 0.34222412109375 0.43709106445313256 +1.515125 0.194732666015625 0.34600830078125 0.43709106445313256 +1.51525 0.194732666015625 0.34600830078125 0.43709106445313256 +1.5153750000000002 0.196868896484375 0.349761962890625 0.43709106445313256 +1.5155 0.198944091796875 0.353485107421875 0.43709106445313256 +1.515625 0.198944091796875 0.353485107421875 0.43709106445313256 +1.51575 0.201019287109375 0.357177734375 0.43709106445313256 +1.515875 0.201019287109375 0.357177734375 0.43709106445313256 +1.516 0.20306396484375 0.360809326171875 0.43709106445313256 +1.516125 0.205108642578125 0.36444091796875 0.43709106445313256 +1.51625 0.205108642578125 0.36444091796875 0.43709106445313256 +1.516375 0.207122802734375 0.36798095703125 0.43709106445313256 +1.5165 0.207122802734375 0.36798095703125 0.43709106445313256 +1.5166250000000002 0.2091064453125 0.37152099609375 0.43709106445313256 +1.51675 0.2110595703125 0.375 0.43709106445313256 +1.516875 0.2110595703125 0.375 0.43709106445313256 +1.5170000000000002 0.212982177734375 0.378448486328125 0.43709106445313256 +1.517125 0.212982177734375 0.378448486328125 0.43709106445313256 +1.51725 0.21490478515625 0.3818359375 0.43709106445313256 +1.5173750000000002 0.216796875 0.38519287109375 0.43709106445313256 +1.5175 0.216796875 0.38519287109375 0.43709106445313256 +1.517625 0.218658447265625 0.388519287109375 0.43709106445313256 +1.51775 0.218658447265625 0.388519287109375 0.43709106445313256 +1.517875 0.22052001953125 0.39178466796875 0.43709106445313256 +1.518 0.222320556640625 0.39501953125 0.43709106445313256 +1.518125 0.222320556640625 0.39501953125 0.43709106445313256 +1.51825 0.22412109375 0.398193359375 0.43709106445313256 +1.518375 0.22412109375 0.398193359375 0.43709106445313256 +1.5185 0.22589111328125 0.401336669921875 0.43709106445313256 +1.5186250000000002 0.227630615234375 0.404449462890625 0.43709106445313256 +1.51875 0.227630615234375 0.404449462890625 0.43709106445313256 +1.518875 0.229339599609375 0.407501220703125 0.43709106445313256 +1.5190000000000002 0.229339599609375 0.407501220703125 0.43709106445313256 +1.519125 0.231048583984375 0.4105224609375 0.43709106445313256 +1.51925 0.23272705078125 0.413482666015625 0.43709106445313256 +1.5193750000000002 0.23272705078125 0.413482666015625 0.43709106445313256 +1.5195 0.234375 0.416412353515625 0.43709106445313256 +1.519625 0.234375 0.416412353515625 0.43709106445313256 +1.51975 0.2359619140625 0.419281005859375 0.43709106445313256 +1.519875 0.237579345703125 0.422119140625 0.43709106445313256 +1.52 0.237579345703125 0.422119140625 0.43709106445313256 +1.520125 0.2391357421875 0.424896240234375 0.43709106445313256 +1.52025 0.2391357421875 0.424896240234375 0.43709106445313256 +1.520375 0.24066162109375 0.4276123046875 0.43709106445313256 +1.5205 0.2421875 0.4302978515625 0.43709106445313256 +1.5206250000000002 0.2421875 0.4302978515625 0.43709106445313256 +1.52075 0.243682861328125 0.432952880859375 0.43709106445313256 +1.520875 0.243682861328125 0.432952880859375 0.43709106445313256 +1.5210000000000002 0.245147705078125 0.435546875 0.43709106445313256 +1.521125 0.246551513671875 0.438079833984375 0.43709106445313256 +1.52125 0.246551513671875 0.438079833984375 0.43709106445313256 +1.521375 0.24798583984375 0.440582275390625 0.43709106445313256 +1.5215 0.24798583984375 0.440582275390625 0.43709106445313256 +1.521625 0.249359130859375 0.44305419921875 0.43709106445313256 +1.52175 0.250701904296875 0.4454345703125 0.43709106445313256 +1.521875 0.250701904296875 0.4454345703125 0.43709106445313256 +1.522 0.25201416015625 0.447784423828125 0.43709106445313256 +1.522125 0.25201416015625 0.447784423828125 0.43709106445313256 +1.52225 0.253326416015625 0.450103759765625 0.43709106445313256 +1.522375 0.254608154296875 0.452362060546875 0.43709106445313256 +1.5225 0.254608154296875 0.452362060546875 0.43709106445313256 +1.5226250000000002 0.255828857421875 0.454559326171875 0.43709106445313256 +1.52275 0.255828857421875 0.454559326171875 0.43709106445313256 +1.522875 0.257049560546875 0.45672607421875 0.43709106445313256 +1.5230000000000002 0.25823974609375 0.458831787109375 0.43709106445313256 +1.523125 0.25823974609375 0.458831787109375 0.43709106445313256 +1.52325 0.2593994140625 0.46087646484375 0.43709106445313256 +1.523375 0.2593994140625 0.46087646484375 0.43709106445313256 +1.5235 0.260528564453125 0.462890625 0.43709106445313256 +1.523625 0.2615966796875 0.464813232421875 0.43709106445313256 +1.52375 0.2615966796875 0.464813232421875 0.43709106445313256 +1.523875 0.2626953125 0.46673583984375 0.43709106445313256 +1.524 0.2626953125 0.46673583984375 0.43709106445313256 +1.524125 0.26373291015625 0.46856689453125 0.43709106445313256 +1.52425 0.264739990234375 0.470367431640625 0.43709106445313256 +1.524375 0.264739990234375 0.470367431640625 0.43709106445313256 +1.5245 0.265716552734375 0.472137451171875 0.43709106445313256 +1.5246250000000002 0.265716552734375 0.472137451171875 0.43709106445313256 +1.52475 0.26666259765625 0.47381591796875 0.43709106445313256 +1.524875 0.267608642578125 0.4754638671875 0.43709106445313256 +1.5250000000000002 0.267608642578125 0.4754638671875 0.43709106445313256 +1.525125 0.26849365234375 0.47705078125 0.43709106445313256 +1.52525 0.26849365234375 0.47705078125 0.43709106445313256 +1.525375 0.269378662109375 0.478607177734375 0.43709106445313256 +1.5255 0.27020263671875 0.480072021484375 0.43709106445313256 +1.525625 0.27020263671875 0.480072021484375 0.43709106445313256 +1.52575 0.27099609375 0.48150634765625 0.43709106445313256 +1.525875 0.27099609375 0.48150634765625 0.43709106445313256 +1.526 0.27178955078125 0.48291015625 0.43709106445313256 +1.526125 0.27252197265625 0.484222412109375 0.43709106445313256 +1.52625 0.27252197265625 0.484222412109375 0.43709106445313256 +1.526375 0.27325439453125 0.485504150390625 0.43709106445313256 +1.5265 0.27325439453125 0.485504150390625 0.43709106445313256 +1.5266250000000002 0.273956298828125 0.486724853515625 0.43709106445313256 +1.52675 0.27459716796875 0.487884521484375 0.43709106445313256 +1.526875 0.27459716796875 0.487884521484375 0.43709106445313256 +1.5270000000000002 0.27520751953125 0.489013671875 0.43709106445313256 +1.527125 0.27520751953125 0.489013671875 0.43709106445313256 +1.52725 0.27581787109375 0.490081787109375 0.43709106445313256 +1.527375 0.276397705078125 0.4910888671875 0.43709106445313256 +1.5275 0.276397705078125 0.4910888671875 0.43709106445313256 +1.527625 0.27691650390625 0.492034912109375 0.43709106445313256 +1.52775 0.27691650390625 0.492034912109375 0.43709106445313256 +1.527875 0.277435302734375 0.492950439453125 0.43709106445313256 +1.528 0.277923583984375 0.4937744140625 0.43709106445313256 +1.528125 0.277923583984375 0.4937744140625 0.43709106445313256 +1.52825 0.278350830078125 0.49456787109375 0.43709106445313256 +1.528375 0.278350830078125 0.49456787109375 0.43709106445313256 +1.5285 0.278778076171875 0.49530029296875 0.43709106445313256 +1.5286250000000002 0.279144287109375 0.496002197265625 0.43709106445313256 +1.52875 0.279144287109375 0.496002197265625 0.43709106445313256 +1.528875 0.279510498046875 0.496612548828125 0.43709106445313256 +1.5290000000000002 0.279510498046875 0.496612548828125 0.43709106445313256 +1.529125 0.27984619140625 0.4971923828125 0.43709106445313256 +1.52925 0.280120849609375 0.497711181640625 0.43709106445313256 +1.529375 0.280120849609375 0.497711181640625 0.43709106445313256 +1.5295 0.2803955078125 0.498199462890625 0.43709106445313256 +1.529625 0.2803955078125 0.498199462890625 0.43709106445313256 +1.52975 0.280609130859375 0.49859619140625 0.43709106445313256 +1.529875 0.28082275390625 0.49896240234375 0.43709106445313256 +1.53 0.28082275390625 0.49896240234375 0.43709106445313256 +1.530125 0.281005859375 0.499267578125 0.43709106445313256 +1.53025 0.281005859375 0.499267578125 0.43709106445313256 +1.530375 0.2811279296875 0.49951171875 0.43709106445313256 +1.5305 0.281219482421875 0.49969482421875 0.43709106445313256 +1.5306250000000002 0.281219482421875 0.49969482421875 0.43709106445313256 +1.53075 0.28131103515625 0.49981689453125 0.43709106445313256 +1.530875 0.28131103515625 0.49981689453125 0.43709106445313256 +1.5310000000000002 0.2813720703125 0.499908447265625 0.43709106445313256 +1.531125 0.2813720703125 0.49993896484375 0.43709106445313256 +1.53125 0.2813720703125 0.49993896484375 0.43709106445313256 +1.531375 0.2813720703125 0.499908447265625 0.43709106445313256 +1.5315 0.2813720703125 0.499908447265625 0.43709106445313256 +1.531625 0.28131103515625 0.49981689453125 0.43709106445313256 +1.53175 0.281219482421875 0.49969482421875 0.43709106445313256 +1.531875 0.281219482421875 0.49969482421875 0.43709106445313256 +1.532 0.2811279296875 0.49951171875 0.43709106445313256 +1.532125 0.2811279296875 0.49951171875 0.43709106445313256 +1.5322500000000002 0.281005859375 0.499267578125 0.43709106445313256 +1.532375 0.28082275390625 0.49896240234375 0.43709106445313256 +1.5325 0.28082275390625 0.49896240234375 0.43709106445313256 +1.5326250000000002 0.280609130859375 0.49859619140625 0.43709106445313256 +1.53275 0.280609130859375 0.49859619140625 0.43709106445313256 +1.532875 0.2803955078125 0.498199462890625 0.43709106445313256 +1.5330000000000002 0.280120849609375 0.497711181640625 0.43709106445313256 +1.533125 0.280120849609375 0.497711181640625 0.43709106445313256 +1.53325 0.27984619140625 0.4971923828125 0.43709106445313256 +1.533375 0.27984619140625 0.4971923828125 0.43709106445313256 +1.5335 0.279510498046875 0.496612548828125 0.43709106445313256 +1.533625 0.279144287109375 0.496002197265625 0.43709106445313256 +1.53375 0.279144287109375 0.496002197265625 0.43709106445313256 +1.533875 0.278778076171875 0.49530029296875 0.43709106445313256 +1.534 0.278778076171875 0.49530029296875 0.43709106445313256 +1.534125 0.278350830078125 0.49456787109375 0.43709106445313256 +1.5342500000000002 0.277923583984375 0.4937744140625 0.43709106445313256 +1.534375 0.277923583984375 0.4937744140625 0.43709106445313256 +1.5345 0.277435302734375 0.492950439453125 0.43709106445313256 +1.5346250000000002 0.277435302734375 0.492950439453125 0.43709106445313256 +1.53475 0.27691650390625 0.492034912109375 0.43709106445313256 +1.534875 0.276397705078125 0.4910888671875 0.43709106445313256 +1.5350000000000002 0.276397705078125 0.4910888671875 0.43709106445313256 +1.535125 0.27581787109375 0.490081787109375 0.43709106445313256 +1.53525 0.27581787109375 0.490081787109375 0.43709106445313256 +1.535375 0.27520751953125 0.489013671875 0.43709106445313256 +1.5355 0.27459716796875 0.487884521484375 0.43709106445313256 +1.535625 0.27459716796875 0.487884521484375 0.43709106445313256 +1.53575 0.273956298828125 0.486724853515625 0.43709106445313256 +1.535875 0.273956298828125 0.486724853515625 0.43709106445313256 +1.536 0.119293212890625 0.485504150390625 0.7541992187500055 +1.536125 0.11895751953125 0.484222412109375 0.7541992187500055 +1.5362500000000002 0.11895751953125 0.484222412109375 0.7541992187500055 +1.536375 0.11865234375 0.48291015625 0.7541992187500055 +1.5365 0.11865234375 0.48291015625 0.7541992187500055 +1.5366250000000002 0.1182861328125 0.48150634765625 0.7541992187500055 +1.53675 0.117950439453125 0.480072021484375 0.7541992187500055 +1.536875 0.117950439453125 0.480072021484375 0.7541992187500055 +1.537 0.117584228515625 0.478607177734375 0.7541992187500055 +1.537125 0.117584228515625 0.478607177734375 0.7541992187500055 +1.53725 0.117218017578125 0.47705078125 0.7541992187500055 +1.537375 0.1168212890625 0.4754638671875 0.7541992187500055 +1.5375 0.1168212890625 0.4754638671875 0.7541992187500055 +1.537625 0.116424560546875 0.47381591796875 0.7541992187500055 +1.53775 0.116424560546875 0.47381591796875 0.7541992187500055 +1.537875 0.115997314453125 0.472137451171875 0.7541992187500055 +1.538 0.115570068359375 0.470367431640625 0.7541992187500055 +1.538125 0.115570068359375 0.470367431640625 0.7541992187500055 +1.5382500000000002 0.1151123046875 0.46856689453125 0.7541992187500055 +1.538375 0.1151123046875 0.46856689453125 0.7541992187500055 +1.5385 0.114654541015625 0.46673583984375 0.7541992187500055 +1.5386250000000002 0.11419677734375 0.464813232421875 0.7541992187500055 +1.53875 0.11419677734375 0.464813232421875 0.7541992187500055 +1.538875 0.11370849609375 0.462890625 0.7541992187500055 +1.539 0.11370849609375 0.462890625 0.7541992187500055 +1.539125 0.11322021484375 0.46087646484375 0.7541992187500055 +1.53925 0.11273193359375 0.458831787109375 0.7541992187500055 +1.539375 0.11273193359375 0.458831787109375 0.7541992187500055 +1.5395 0.112213134765625 0.45672607421875 0.7541992187500055 +1.539625 0.112213134765625 0.45672607421875 0.7541992187500055 +1.53975 0.111663818359375 0.454559326171875 0.7541992187500055 +1.539875 0.11114501953125 0.452362060546875 0.7541992187500055 +1.54 0.11114501953125 0.452362060546875 0.7541992187500055 +1.540125 0.110595703125 0.450103759765625 0.7541992187500055 +1.5402500000000002 0.110595703125 0.450103759765625 0.7541992187500055 +1.540375 0.110015869140625 0.447784423828125 0.7541992187500055 +1.5405 0.10943603515625 0.4454345703125 0.7541992187500055 +1.5406250000000002 0.10943603515625 0.4454345703125 0.7541992187500055 +1.54075 0.108856201171875 0.44305419921875 0.7541992187500055 +1.540875 0.108856201171875 0.44305419921875 0.7541992187500055 +1.541 0.108245849609375 0.440582275390625 0.7541992187500055 +1.541125 0.107635498046875 0.438079833984375 0.7541992187500055 +1.54125 0.107635498046875 0.438079833984375 0.7541992187500055 +1.541375 0.10699462890625 0.435546875 0.7541992187500055 +1.5415 0.10699462890625 0.435546875 0.7541992187500055 +1.541625 0.10638427734375 0.432952880859375 0.7541992187500055 +1.54175 0.105712890625 0.4302978515625 0.7541992187500055 +1.541875 0.105712890625 0.4302978515625 0.7541992187500055 +1.542 0.105072021484375 0.4276123046875 0.7541992187500055 +1.542125 0.105072021484375 0.4276123046875 0.7541992187500055 +1.5422500000000002 0.104400634765625 0.424896240234375 0.7541992187500055 +1.542375 0.10369873046875 0.422119140625 0.7541992187500055 +1.5425 0.10369873046875 0.422119140625 0.7541992187500055 +1.5426250000000002 0.102996826171875 0.419281005859375 0.7541992187500055 +1.54275 0.102996826171875 0.419281005859375 0.7541992187500055 +1.542875 0.102294921875 0.416412353515625 0.7541992187500055 +1.543 0.101593017578125 0.413482666015625 0.7541992187500055 +1.543125 0.101593017578125 0.413482666015625 0.7541992187500055 +1.54325 0.100860595703125 0.4105224609375 0.7541992187500055 +1.543375 0.100860595703125 0.4105224609375 0.7541992187500055 +1.5435 0.100128173828125 0.407501220703125 0.7541992187500055 +1.543625 0.099365234375 0.404449462890625 0.7541992187500055 +1.54375 0.099365234375 0.404449462890625 0.7541992187500055 +1.543875 0.098602294921875 0.401336669921875 0.7541992187500055 +1.544 0.098602294921875 0.401336669921875 0.7541992187500055 +1.544125 0.09783935546875 0.398193359375 0.7541992187500055 +1.5442500000000002 0.0970458984375 0.39501953125 0.7541992187500055 +1.544375 0.0970458984375 0.39501953125 0.7541992187500055 +1.5445 0.09625244140625 0.39178466796875 0.7541992187500055 +1.5446250000000002 0.09625244140625 0.39178466796875 0.7541992187500055 +1.54475 0.095458984375 0.388519287109375 0.7541992187500055 +1.544875 0.094635009765625 0.38519287109375 0.7541992187500055 +1.545 0.094635009765625 0.38519287109375 0.7541992187500055 +1.545125 0.09381103515625 0.3818359375 0.7541992187500055 +1.54525 0.09381103515625 0.3818359375 0.7541992187500055 +1.545375 0.092987060546875 0.378448486328125 0.7541992187500055 +1.5455 0.092132568359375 0.375 0.7541992187500055 +1.545625 0.092132568359375 0.375 0.7541992187500055 +1.54575 0.091278076171875 0.37152099609375 0.7541992187500055 +1.545875 0.091278076171875 0.37152099609375 0.7541992187500055 +1.546 0.09039306640625 0.36798095703125 0.7541992187500055 +1.546125 0.08953857421875 0.36444091796875 0.7541992187500055 +1.5462500000000002 0.08953857421875 0.36444091796875 0.7541992187500055 +1.546375 0.088653564453125 0.360809326171875 0.7541992187500055 +1.5465 0.088653564453125 0.360809326171875 0.7541992187500055 +1.5466250000000002 0.0877685546875 0.357177734375 0.7541992187500055 +1.54675 0.08685302734375 0.353485107421875 0.7541992187500055 +1.546875 0.08685302734375 0.353485107421875 0.7541992187500055 +1.547 0.0859375 0.349761962890625 0.7541992187500055 +1.547125 0.0859375 0.349761962890625 0.7541992187500055 +1.54725 0.08502197265625 0.34600830078125 0.7541992187500055 +1.547375 0.084075927734375 0.34222412109375 0.7541992187500055 +1.5475 0.084075927734375 0.34222412109375 0.7541992187500055 +1.547625 0.0831298828125 0.33837890625 0.7541992187500055 +1.54775 0.0831298828125 0.33837890625 0.7541992187500055 +1.5478750000000002 0.082183837890625 0.334503173828125 0.7541992187500055 +1.548 0.08123779296875 0.330596923828125 0.7541992187500055 +1.548125 0.08123779296875 0.330596923828125 0.7541992187500055 +1.5482500000000002 0.08026123046875 0.32666015625 0.7541992187500055 +1.548375 0.08026123046875 0.32666015625 0.7541992187500055 +1.5485 0.07928466796875 0.322662353515625 0.7541992187500055 +1.5486250000000002 0.078277587890625 0.31866455078125 0.7541992187500055 +1.54875 0.078277587890625 0.31866455078125 0.7541992187500055 +1.548875 0.077301025390625 0.314605712890625 0.7541992187500055 +1.549 0.077301025390625 0.314605712890625 0.7541992187500055 +1.549125 0.0762939453125 0.310516357421875 0.7541992187500055 +1.54925 0.075286865234375 0.306396484375 0.7541992187500055 +1.549375 0.075286865234375 0.306396484375 0.7541992187500055 +1.5495 0.074249267578125 0.30224609375 0.7541992187500055 +1.549625 0.074249267578125 0.30224609375 0.7541992187500055 +1.54975 0.073211669921875 0.298065185546875 0.7541992187500055 +1.5498750000000002 0.072174072265625 0.2938232421875 0.7541992187500055 +1.55 0.072174072265625 0.2938232421875 0.7541992187500055 +1.550125 0.071136474609375 0.289581298828125 0.7541992187500055 +1.5502500000000002 0.071136474609375 0.289581298828125 0.7541992187500055 +1.550375 0.070098876953125 0.285308837890625 0.7541992187500055 +1.5505 0.06903076171875 0.280975341796875 0.7541992187500055 +1.5506250000000002 0.06903076171875 0.280975341796875 0.7541992187500055 +1.55075 0.067962646484375 0.276641845703125 0.7541992187500055 +1.550875 0.067962646484375 0.276641845703125 0.7541992187500055 +1.551 0.06689453125 0.27227783203125 0.7541992187500055 +1.551125 0.0657958984375 0.267852783203125 0.7541992187500055 +1.55125 0.0657958984375 0.267852783203125 0.7541992187500055 +1.551375 0.064727783203125 0.263427734375 0.7541992187500055 +1.5515 0.064727783203125 0.263427734375 0.7541992187500055 +1.551625 0.063629150390625 0.25897216796875 0.7541992187500055 +1.55175 0.0625 0.25445556640625 0.7541992187500055 +1.5518750000000002 0.0625 0.25445556640625 0.7541992187500055 +1.552 0.0614013671875 0.249969482421875 0.7541992187500055 +1.552125 0.0614013671875 0.249969482421875 0.7541992187500055 +1.5522500000000002 0.060302734375 0.24542236328125 0.7541992187500055 +1.552375 0.059173583984375 0.2408447265625 0.7541992187500055 +1.5525 0.059173583984375 0.2408447265625 0.7541992187500055 +1.552625 0.05804443359375 0.236236572265625 0.7541992187500055 +1.55275 0.05804443359375 0.236236572265625 0.7541992187500055 +1.552875 0.056884765625 0.231597900390625 0.7541992187500055 +1.553 0.055755615234375 0.226959228515625 0.7541992187500055 +1.553125 0.055755615234375 0.226959228515625 0.7541992187500055 +1.55325 0.054595947265625 0.2222900390625 0.7541992187500055 +1.553375 0.054595947265625 0.2222900390625 0.7541992187500055 +1.5535 0.053436279296875 0.21759033203125 0.7541992187500055 +1.553625 0.052276611328125 0.212860107421875 0.7541992187500055 +1.55375 0.052276611328125 0.212860107421875 0.7541992187500055 +1.5538750000000002 0.051116943359375 0.208099365234375 0.7541992187500055 +1.554 0.051116943359375 0.208099365234375 0.7541992187500055 +1.554125 0.049957275390625 0.203338623046875 0.7541992187500055 +1.5542500000000002 0.04876708984375 0.19854736328125 0.7541992187500055 +1.554375 0.04876708984375 0.19854736328125 0.7541992187500055 +1.5545 0.047576904296875 0.1937255859375 0.7541992187500055 +1.554625 0.047576904296875 0.1937255859375 0.7541992187500055 +1.55475 0.04638671875 0.188873291015625 0.7541992187500055 +1.554875 0.045196533203125 0.18402099609375 0.7541992187500055 +1.555 0.045196533203125 0.18402099609375 0.7541992187500055 +1.555125 0.04400634765625 0.17913818359375 0.7541992187500055 +1.55525 0.04400634765625 0.17913818359375 0.7541992187500055 +1.555375 0.042816162109375 0.17425537109375 0.7541992187500055 +1.5555 0.041595458984375 0.169342041015625 0.7541992187500055 +1.555625 0.041595458984375 0.169342041015625 0.7541992187500055 +1.55575 0.040374755859375 0.164398193359375 0.7541992187500055 +1.5558750000000002 0.040374755859375 0.164398193359375 0.7541992187500055 +1.556 0.039154052734375 0.159454345703125 0.7541992187500055 +1.556125 0.037933349609375 0.15447998046875 0.7541992187500055 +1.5562500000000002 0.037933349609375 0.15447998046875 0.7541992187500055 +1.556375 0.036712646484375 0.14947509765625 0.7541992187500055 +1.5565 0.036712646484375 0.14947509765625 0.7541992187500055 +1.556625 0.035491943359375 0.14447021484375 0.7541992187500055 +1.55675 0.03424072265625 0.13946533203125 0.7541992187500055 +1.556875 0.03424072265625 0.13946533203125 0.7541992187500055 +1.557 0.03302001953125 0.134429931640625 0.7541992187500055 +1.557125 0.03302001953125 0.134429931640625 0.7541992187500055 +1.55725 0.031768798828125 0.129364013671875 0.7541992187500055 +1.557375 0.030517578125 0.124298095703125 0.7541992187500055 +1.5575 0.030517578125 0.124298095703125 0.7541992187500055 +1.557625 0.029296875 0.119232177734375 0.7541992187500055 +1.55775 0.029296875 0.119232177734375 0.7541992187500055 +1.5578750000000002 0.028045654296875 0.1141357421875 0.7541992187500055 +1.558 0.026763916015625 0.109039306640625 0.7541992187500055 +1.558125 0.026763916015625 0.109039306640625 0.7541992187500055 +1.5582500000000002 0.0255126953125 0.103912353515625 0.7541992187500055 +1.558375 0.0255126953125 0.103912353515625 0.7541992187500055 +1.5585 0.024261474609375 0.098785400390625 0.7541992187500055 +1.558625 0.02301025390625 0.093658447265625 0.7541992187500055 +1.55875 0.02301025390625 0.093658447265625 0.7541992187500055 +1.558875 0.021728515625 0.0885009765625 0.7541992187500055 +1.559 0.021728515625 0.0885009765625 0.7541992187500055 +1.559125 0.020477294921875 0.083343505859375 0.7541992187500055 +1.55925 0.019195556640625 0.07818603515625 0.7541992187500055 +1.559375 0.019195556640625 0.07818603515625 0.7541992187500055 +1.5595 0.017913818359375 0.072998046875 0.7541992187500055 +1.559625 0.017913818359375 0.072998046875 0.7541992187500055 +1.55975 0.01666259765625 0.06781005859375 0.7541992187500055 +1.5598750000000002 0.015380859375 0.0626220703125 0.7541992187500055 +1.56 0.015380859375 0.0626220703125 0.7541992187500055 +1.560125 0.01409912109375 0.05743408203125 0.7541992187500055 +1.5602500000000002 0.01409912109375 0.05743408203125 0.7541992187500055 +1.560375 0.0128173828125 0.05224609375 0.7541992187500055 +1.5605 0.01153564453125 0.047027587890625 0.7541992187500055 +1.560625 0.01153564453125 0.047027587890625 0.7541992187500055 +1.56075 0.01025390625 0.04180908203125 0.7541992187500055 +1.560875 0.01025390625 0.04180908203125 0.7541992187500055 +1.561 0.00897216796875 0.036590576171875 0.7541992187500055 +1.561125 0.0076904296875 0.0313720703125 0.7541992187500055 +1.56125 0.0076904296875 0.0313720703125 0.7541992187500055 +1.561375 0.00640869140625 0.026123046875 0.7541992187500055 +1.5615 0.00640869140625 0.026123046875 0.7541992187500055 +1.561625 0.005126953125 0.020904541015625 0.7541992187500055 +1.56175 0.00384521484375 0.01568603515625 0.7541992187500055 +1.5618750000000002 0.00384521484375 0.01568603515625 0.7541992187500055 +1.562 0.0025634765625 0.01043701171875 0.7541992187500055 +1.562125 0.0025634765625 0.01043701171875 0.7541992187500055 +1.5622500000000002 0.00128173828125 0.005218505859375 0.7541992187500055 +1.562375 0.0 0.0 0.7541992187500055 +1.5625 0.0 0.0 0.7541992187500055 +1.562625 -0.00128173828125 -0.005218505859375 0.7541992187500055 +1.56275 -0.00128173828125 -0.005218505859375 0.7541992187500055 +1.562875 -0.0025634765625 -0.01043701171875 0.7541992187500055 +1.563 -0.00384521484375 -0.01568603515625 0.7541992187500055 +1.563125 -0.00384521484375 -0.01568603515625 0.7541992187500055 +1.56325 -0.005126953125 -0.020904541015625 0.7541992187500055 +1.563375 -0.005126953125 -0.020904541015625 0.7541992187500055 +1.5635000000000002 -0.00640869140625 -0.026123046875 0.7541992187500055 +1.563625 -0.0076904296875 -0.0313720703125 0.7541992187500055 +1.56375 -0.0076904296875 -0.0313720703125 0.7541992187500055 +1.5638750000000002 -0.00897216796875 -0.036590576171875 0.7541992187500055 +1.564 -0.00897216796875 -0.036590576171875 0.7541992187500055 +1.564125 -0.01025390625 -0.04180908203125 0.7541992187500055 +1.5642500000000002 -0.01153564453125 -0.047027587890625 0.7541992187500055 +1.564375 -0.01153564453125 -0.047027587890625 0.7541992187500055 +1.5645 -0.0128173828125 -0.05224609375 0.7541992187500055 +1.564625 -0.0128173828125 -0.05224609375 0.7541992187500055 +1.56475 -0.01409912109375 -0.05743408203125 0.7541992187500055 +1.564875 -0.015380859375 -0.0626220703125 0.7541992187500055 +1.565 -0.015380859375 -0.0626220703125 0.7541992187500055 +1.565125 -0.01666259765625 -0.06781005859375 0.7541992187500055 +1.56525 -0.01666259765625 -0.06781005859375 0.7541992187500055 +1.565375 -0.017913818359375 -0.072998046875 0.7541992187500055 +1.5655000000000002 -0.019195556640625 -0.07818603515625 0.7541992187500055 +1.565625 -0.019195556640625 -0.07818603515625 0.7541992187500055 +1.56575 -0.020477294921875 -0.083343505859375 0.7541992187500055 +1.5658750000000002 -0.020477294921875 -0.083343505859375 0.7541992187500055 +1.566 -0.021728515625 -0.0885009765625 0.7541992187500055 +1.566125 -0.02301025390625 -0.093658447265625 0.7541992187500055 +1.5662500000000002 -0.02301025390625 -0.093658447265625 0.7541992187500055 +1.566375 -0.024261474609375 -0.098785400390625 0.7541992187500055 +1.5665 -0.024261474609375 -0.098785400390625 0.7541992187500055 +1.566625 -0.0255126953125 -0.103912353515625 0.7541992187500055 +1.56675 -0.026763916015625 -0.109039306640625 0.7541992187500055 +1.566875 -0.026763916015625 -0.109039306640625 0.7541992187500055 +1.567 -0.028045654296875 -0.1141357421875 0.7541992187500055 +1.567125 -0.028045654296875 -0.1141357421875 0.7541992187500055 +1.56725 -0.029296875 -0.119232177734375 0.7541992187500055 +1.567375 -0.030517578125 -0.124298095703125 0.7541992187500055 +1.5675000000000002 -0.030517578125 -0.124298095703125 0.7541992187500055 +1.567625 -0.031768798828125 -0.129364013671875 0.7541992187500055 +1.56775 -0.031768798828125 -0.129364013671875 0.7541992187500055 +1.5678750000000002 -0.03302001953125 -0.134429931640625 0.7541992187500055 +1.568 -0.006805419921875 -0.13946533203125 0.9510192871093776 +1.568125 -0.006805419921875 -0.13946533203125 0.9510192871093776 +1.56825 -0.007049560546875 -0.14447021484375 0.9510192871093776 +1.568375 -0.007049560546875 -0.14447021484375 0.9510192871093776 +1.5685 -0.007293701171875 -0.14947509765625 0.9510192871093776 +1.568625 -0.007537841796875 -0.15447998046875 0.9510192871093776 +1.56875 -0.007537841796875 -0.15447998046875 0.9510192871093776 +1.568875 -0.007781982421875 -0.159454345703125 0.9510192871093776 +1.569 -0.007781982421875 -0.159454345703125 0.9510192871093776 +1.569125 -0.008026123046875 -0.164398193359375 0.9510192871093776 +1.56925 -0.008270263671875 -0.169342041015625 0.9510192871093776 +1.569375 -0.008270263671875 -0.169342041015625 0.9510192871093776 +1.5695000000000002 -0.008514404296875 -0.17425537109375 0.9510192871093776 +1.569625 -0.008514404296875 -0.17425537109375 0.9510192871093776 +1.56975 -0.008758544921875 -0.17913818359375 0.9510192871093776 +1.5698750000000002 -0.00897216796875 -0.18402099609375 0.9510192871093776 +1.57 -0.00897216796875 -0.18402099609375 0.9510192871093776 +1.570125 -0.00921630859375 -0.188873291015625 0.9510192871093776 +1.57025 -0.00921630859375 -0.188873291015625 0.9510192871093776 +1.570375 -0.00946044921875 -0.1937255859375 0.9510192871093776 +1.5705 -0.00970458984375 -0.19854736328125 0.9510192871093776 +1.570625 -0.00970458984375 -0.19854736328125 0.9510192871093776 +1.57075 -0.009918212890625 -0.203338623046875 0.9510192871093776 +1.570875 -0.009918212890625 -0.203338623046875 0.9510192871093776 +1.571 -0.010162353515625 -0.208099365234375 0.9510192871093776 +1.571125 -0.010406494140625 -0.212860107421875 0.9510192871093776 +1.57125 -0.010406494140625 -0.212860107421875 0.9510192871093776 +1.571375 -0.0106201171875 -0.21759033203125 0.9510192871093776 +1.5715000000000002 -0.0106201171875 -0.21759033203125 0.9510192871093776 +1.571625 -0.0108642578125 -0.2222900390625 0.9510192871093776 +1.57175 -0.011077880859375 -0.226959228515625 0.9510192871093776 +1.5718750000000002 -0.011077880859375 -0.226959228515625 0.9510192871093776 +1.572 -0.011322021484375 -0.231597900390625 0.9510192871093776 +1.572125 -0.011322021484375 -0.231597900390625 0.9510192871093776 +1.57225 -0.01153564453125 -0.236236572265625 0.9510192871093776 +1.572375 -0.011749267578125 -0.2408447265625 0.9510192871093776 +1.5725 -0.011749267578125 -0.2408447265625 0.9510192871093776 +1.572625 -0.011993408203125 -0.24542236328125 0.9510192871093776 +1.57275 -0.011993408203125 -0.24542236328125 0.9510192871093776 +1.572875 -0.01220703125 -0.249969482421875 0.9510192871093776 +1.573 -0.012420654296875 -0.25445556640625 0.9510192871093776 +1.573125 -0.012420654296875 -0.25445556640625 0.9510192871093776 +1.57325 -0.01263427734375 -0.25897216796875 0.9510192871093776 +1.573375 -0.01263427734375 -0.25897216796875 0.9510192871093776 +1.5735000000000002 -0.01287841796875 -0.263427734375 0.9510192871093776 +1.573625 -0.013092041015625 -0.267852783203125 0.9510192871093776 +1.57375 -0.013092041015625 -0.267852783203125 0.9510192871093776 +1.5738750000000002 -0.0133056640625 -0.27227783203125 0.9510192871093776 +1.574 -0.0133056640625 -0.27227783203125 0.9510192871093776 +1.574125 -0.013519287109375 -0.276641845703125 0.9510192871093776 +1.57425 -0.01373291015625 -0.280975341796875 0.9510192871093776 +1.574375 -0.01373291015625 -0.280975341796875 0.9510192871093776 +1.5745 -0.013946533203125 -0.285308837890625 0.9510192871093776 +1.574625 -0.013946533203125 -0.285308837890625 0.9510192871093776 +1.57475 -0.014129638671875 -0.289581298828125 0.9510192871093776 +1.574875 -0.01434326171875 -0.2938232421875 0.9510192871093776 +1.575 -0.01434326171875 -0.2938232421875 0.9510192871093776 +1.575125 -0.014556884765625 -0.298065185546875 0.9510192871093776 +1.57525 -0.014556884765625 -0.298065185546875 0.9510192871093776 +1.575375 -0.0147705078125 -0.30224609375 0.9510192871093776 +1.5755000000000002 -0.01495361328125 -0.306396484375 0.9510192871093776 +1.575625 -0.01495361328125 -0.306396484375 0.9510192871093776 +1.57575 -0.015167236328125 -0.310516357421875 0.9510192871093776 +1.5758750000000002 -0.015167236328125 -0.310516357421875 0.9510192871093776 +1.576 -0.015380859375 -0.314605712890625 0.9510192871093776 +1.576125 -0.01556396484375 -0.31866455078125 0.9510192871093776 +1.57625 -0.01556396484375 -0.31866455078125 0.9510192871093776 +1.576375 -0.0157470703125 -0.322662353515625 0.9510192871093776 +1.5765 -0.0157470703125 -0.322662353515625 0.9510192871093776 +1.576625 -0.015960693359375 -0.32666015625 0.9510192871093776 +1.57675 -0.016143798828125 -0.330596923828125 0.9510192871093776 +1.576875 -0.016143798828125 -0.330596923828125 0.9510192871093776 +1.577 -0.016326904296875 -0.334503173828125 0.9510192871093776 +1.577125 -0.016326904296875 -0.334503173828125 0.9510192871093776 +1.57725 -0.01654052734375 -0.33837890625 0.9510192871093776 +1.577375 -0.0167236328125 -0.34222412109375 0.9510192871093776 +1.5775000000000002 -0.0167236328125 -0.34222412109375 0.9510192871093776 +1.577625 -0.01690673828125 -0.34600830078125 0.9510192871093776 +1.57775 -0.01690673828125 -0.34600830078125 0.9510192871093776 +1.5778750000000002 -0.01708984375 -0.349761962890625 0.9510192871093776 +1.578 -0.01727294921875 -0.353485107421875 0.9510192871093776 +1.578125 -0.01727294921875 -0.353485107421875 0.9510192871093776 +1.57825 -0.0174560546875 -0.357177734375 0.9510192871093776 +1.578375 -0.0174560546875 -0.357177734375 0.9510192871093776 +1.5785 -0.01763916015625 -0.360809326171875 0.9510192871093776 +1.578625 -0.017791748046875 -0.36444091796875 0.9510192871093776 +1.57875 -0.017791748046875 -0.36444091796875 0.9510192871093776 +1.578875 -0.017974853515625 -0.36798095703125 0.9510192871093776 +1.579 -0.017974853515625 -0.36798095703125 0.9510192871093776 +1.5791250000000002 -0.018157958984375 -0.37152099609375 0.9510192871093776 +1.57925 -0.018310546875 -0.375 0.9510192871093776 +1.579375 -0.018310546875 -0.375 0.9510192871093776 +1.5795000000000002 -0.01849365234375 -0.378448486328125 0.9510192871093776 +1.579625 -0.01849365234375 -0.378448486328125 0.9510192871093776 +1.57975 -0.018646240234375 -0.3818359375 0.9510192871093776 +1.5798750000000002 -0.018829345703125 -0.38519287109375 0.9510192871093776 +1.58 -0.018829345703125 -0.38519287109375 0.9510192871093776 +1.580125 -0.01898193359375 -0.388519287109375 0.9510192871093776 +1.58025 -0.01898193359375 -0.388519287109375 0.9510192871093776 +1.580375 -0.019134521484375 -0.39178466796875 0.9510192871093776 +1.5805 -0.019287109375 -0.39501953125 0.9510192871093776 +1.580625 -0.019287109375 -0.39501953125 0.9510192871093776 +1.58075 -0.019439697265625 -0.398193359375 0.9510192871093776 +1.580875 -0.019439697265625 -0.398193359375 0.9510192871093776 +1.581 -0.019622802734375 -0.401336669921875 0.9510192871093776 +1.5811250000000002 -0.019775390625 -0.404449462890625 0.9510192871093776 +1.58125 -0.019775390625 -0.404449462890625 0.9510192871093776 +1.581375 -0.0198974609375 -0.407501220703125 0.9510192871093776 +1.5815000000000002 -0.0198974609375 -0.407501220703125 0.9510192871093776 +1.581625 -0.020050048828125 -0.4105224609375 0.9510192871093776 +1.58175 -0.02020263671875 -0.413482666015625 0.9510192871093776 +1.5818750000000002 -0.02020263671875 -0.413482666015625 0.9510192871093776 +1.582 -0.020355224609375 -0.416412353515625 0.9510192871093776 +1.582125 -0.020355224609375 -0.416412353515625 0.9510192871093776 +1.58225 -0.020477294921875 -0.419281005859375 0.9510192871093776 +1.582375 -0.0206298828125 -0.422119140625 0.9510192871093776 +1.5825 -0.0206298828125 -0.422119140625 0.9510192871093776 +1.582625 -0.020751953125 -0.424896240234375 0.9510192871093776 +1.58275 -0.020751953125 -0.424896240234375 0.9510192871093776 +1.582875 -0.020904541015625 -0.4276123046875 0.9510192871093776 +1.583 -0.021026611328125 -0.4302978515625 0.9510192871093776 +1.5831250000000002 -0.021026611328125 -0.4302978515625 0.9510192871093776 +1.58325 -0.021148681640625 -0.432952880859375 0.9510192871093776 +1.583375 -0.021148681640625 -0.432952880859375 0.9510192871093776 +1.5835000000000002 -0.021270751953125 -0.435546875 0.9510192871093776 +1.583625 -0.021392822265625 -0.438079833984375 0.9510192871093776 +1.58375 -0.021392822265625 -0.438079833984375 0.9510192871093776 +1.5838750000000002 -0.021514892578125 -0.440582275390625 0.9510192871093776 +1.584 -0.021514892578125 -0.440582275390625 0.9510192871093776 +1.584125 -0.021636962890625 -0.44305419921875 0.9510192871093776 +1.58425 -0.021759033203125 -0.4454345703125 0.9510192871093776 +1.584375 -0.021759033203125 -0.4454345703125 0.9510192871093776 +1.5845 -0.021881103515625 -0.447784423828125 0.9510192871093776 +1.584625 -0.021881103515625 -0.447784423828125 0.9510192871093776 +1.58475 -0.022003173828125 -0.450103759765625 0.9510192871093776 +1.584875 -0.0220947265625 -0.452362060546875 0.9510192871093776 +1.585 -0.0220947265625 -0.452362060546875 0.9510192871093776 +1.5851250000000002 -0.022216796875 -0.454559326171875 0.9510192871093776 +1.58525 -0.022216796875 -0.454559326171875 0.9510192871093776 +1.585375 -0.022308349609375 -0.45672607421875 0.9510192871093776 +1.5855000000000002 -0.022430419921875 -0.458831787109375 0.9510192871093776 +1.585625 -0.022430419921875 -0.458831787109375 0.9510192871093776 +1.58575 -0.02252197265625 -0.46087646484375 0.9510192871093776 +1.585875 -0.02252197265625 -0.46087646484375 0.9510192871093776 +1.586 -0.022613525390625 -0.462890625 0.9510192871093776 +1.586125 -0.022705078125 -0.464813232421875 0.9510192871093776 +1.58625 -0.022705078125 -0.464813232421875 0.9510192871093776 +1.586375 -0.022796630859375 -0.46673583984375 0.9510192871093776 +1.5865 -0.022796630859375 -0.46673583984375 0.9510192871093776 +1.586625 -0.02288818359375 -0.46856689453125 0.9510192871093776 +1.58675 -0.022979736328125 -0.470367431640625 0.9510192871093776 +1.586875 -0.022979736328125 -0.470367431640625 0.9510192871093776 +1.587 -0.0230712890625 -0.472137451171875 0.9510192871093776 +1.5871250000000002 -0.0230712890625 -0.472137451171875 0.9510192871093776 +1.58725 -0.023162841796875 -0.47381591796875 0.9510192871093776 +1.587375 -0.023223876953125 -0.4754638671875 0.9510192871093776 +1.5875000000000002 -0.023223876953125 -0.4754638671875 0.9510192871093776 +1.587625 -0.0233154296875 -0.47705078125 0.9510192871093776 +1.58775 -0.0233154296875 -0.47705078125 0.9510192871093776 +1.587875 -0.02337646484375 -0.478607177734375 0.9510192871093776 +1.588 -0.023468017578125 -0.480072021484375 0.9510192871093776 +1.588125 -0.023468017578125 -0.480072021484375 0.9510192871093776 +1.58825 -0.023529052734375 -0.48150634765625 0.9510192871093776 +1.588375 -0.023529052734375 -0.48150634765625 0.9510192871093776 +1.5885 -0.023590087890625 -0.48291015625 0.9510192871093776 +1.588625 -0.023651123046875 -0.484222412109375 0.9510192871093776 +1.58875 -0.023651123046875 -0.484222412109375 0.9510192871093776 +1.588875 -0.023712158203125 -0.485504150390625 0.9510192871093776 +1.589 -0.023712158203125 -0.485504150390625 0.9510192871093776 +1.5891250000000002 -0.023773193359375 -0.486724853515625 0.9510192871093776 +1.58925 -0.023834228515625 -0.487884521484375 0.9510192871093776 +1.589375 -0.023834228515625 -0.487884521484375 0.9510192871093776 +1.5895000000000002 -0.023895263671875 -0.489013671875 0.9510192871093776 +1.589625 -0.023895263671875 -0.489013671875 0.9510192871093776 +1.58975 -0.023956298828125 -0.490081787109375 0.9510192871093776 +1.589875 -0.02398681640625 -0.4910888671875 0.9510192871093776 +1.59 -0.02398681640625 -0.4910888671875 0.9510192871093776 +1.590125 -0.0240478515625 -0.492034912109375 0.9510192871093776 +1.59025 -0.0240478515625 -0.492034912109375 0.9510192871093776 +1.590375 -0.024078369140625 -0.492950439453125 0.9510192871093776 +1.5905 -0.024139404296875 -0.4937744140625 0.9510192871093776 +1.590625 -0.024139404296875 -0.4937744140625 0.9510192871093776 +1.59075 -0.024169921875 -0.49456787109375 0.9510192871093776 +1.590875 -0.024169921875 -0.49456787109375 0.9510192871093776 +1.591 -0.024200439453125 -0.49530029296875 0.9510192871093776 +1.5911250000000002 -0.02423095703125 -0.496002197265625 0.9510192871093776 +1.59125 -0.02423095703125 -0.496002197265625 0.9510192871093776 +1.591375 -0.024261474609375 -0.496612548828125 0.9510192871093776 +1.5915000000000002 -0.024261474609375 -0.496612548828125 0.9510192871093776 +1.591625 -0.0242919921875 -0.4971923828125 0.9510192871093776 +1.59175 -0.024322509765625 -0.497711181640625 0.9510192871093776 +1.591875 -0.024322509765625 -0.497711181640625 0.9510192871093776 +1.592 -0.02435302734375 -0.498199462890625 0.9510192871093776 +1.592125 -0.02435302734375 -0.498199462890625 0.9510192871093776 +1.59225 -0.02435302734375 -0.49859619140625 0.9510192871093776 +1.592375 -0.024383544921875 -0.49896240234375 0.9510192871093776 +1.5925 -0.024383544921875 -0.49896240234375 0.9510192871093776 +1.592625 -0.024383544921875 -0.499267578125 0.9510192871093776 +1.59275 -0.024383544921875 -0.499267578125 0.9510192871093776 +1.592875 -0.0244140625 -0.49951171875 0.9510192871093776 +1.593 -0.0244140625 -0.49969482421875 0.9510192871093776 +1.5931250000000002 -0.0244140625 -0.49969482421875 0.9510192871093776 +1.59325 -0.0244140625 -0.49981689453125 0.9510192871093776 +1.593375 -0.0244140625 -0.49981689453125 0.9510192871093776 +1.5935000000000002 -0.0244140625 -0.499908447265625 0.9510192871093776 +1.593625 -0.0244140625 -0.49993896484375 0.9510192871093776 +1.59375 -0.0244140625 -0.49993896484375 0.9510192871093776 +1.593875 -0.0244140625 -0.499908447265625 0.9510192871093776 +1.594 -0.0244140625 -0.499908447265625 0.9510192871093776 +1.594125 -0.0244140625 -0.49981689453125 0.9510192871093776 +1.59425 -0.0244140625 -0.49969482421875 0.9510192871093776 +1.594375 -0.0244140625 -0.49969482421875 0.9510192871093776 +1.5945 -0.0244140625 -0.49951171875 0.9510192871093776 +1.594625 -0.0244140625 -0.49951171875 0.9510192871093776 +1.5947500000000002 -0.024383544921875 -0.499267578125 0.9510192871093776 +1.594875 -0.024383544921875 -0.49896240234375 0.9510192871093776 +1.595 -0.024383544921875 -0.49896240234375 0.9510192871093776 +1.5951250000000002 -0.02435302734375 -0.49859619140625 0.9510192871093776 +1.59525 -0.02435302734375 -0.49859619140625 0.9510192871093776 +1.595375 -0.02435302734375 -0.498199462890625 0.9510192871093776 +1.5955000000000002 -0.024322509765625 -0.497711181640625 0.9510192871093776 +1.595625 -0.024322509765625 -0.497711181640625 0.9510192871093776 +1.59575 -0.0242919921875 -0.4971923828125 0.9510192871093776 +1.595875 -0.0242919921875 -0.4971923828125 0.9510192871093776 +1.596 -0.024261474609375 -0.496612548828125 0.9510192871093776 +1.596125 -0.02423095703125 -0.496002197265625 0.9510192871093776 +1.59625 -0.02423095703125 -0.496002197265625 0.9510192871093776 +1.596375 -0.024200439453125 -0.49530029296875 0.9510192871093776 +1.5965 -0.024200439453125 -0.49530029296875 0.9510192871093776 +1.596625 -0.024169921875 -0.49456787109375 0.9510192871093776 +1.5967500000000002 -0.024139404296875 -0.4937744140625 0.9510192871093776 +1.596875 -0.024139404296875 -0.4937744140625 0.9510192871093776 +1.597 -0.024078369140625 -0.492950439453125 0.9510192871093776 +1.5971250000000002 -0.024078369140625 -0.492950439453125 0.9510192871093776 +1.59725 -0.0240478515625 -0.492034912109375 0.9510192871093776 +1.597375 -0.02398681640625 -0.4910888671875 0.9510192871093776 +1.5975000000000002 -0.02398681640625 -0.4910888671875 0.9510192871093776 +1.597625 -0.023956298828125 -0.490081787109375 0.9510192871093776 +1.59775 -0.023956298828125 -0.490081787109375 0.9510192871093776 +1.597875 -0.023895263671875 -0.489013671875 0.9510192871093776 +1.598 -0.023834228515625 -0.487884521484375 0.9510192871093776 +1.598125 -0.023834228515625 -0.487884521484375 0.9510192871093776 +1.59825 -0.023773193359375 -0.486724853515625 0.9510192871093776 +1.598375 -0.023773193359375 -0.486724853515625 0.9510192871093776 +1.5985 -0.023712158203125 -0.485504150390625 0.9510192871093776 +1.598625 -0.023651123046875 -0.484222412109375 0.9510192871093776 +1.5987500000000002 -0.023651123046875 -0.484222412109375 0.9510192871093776 +1.598875 -0.023590087890625 -0.48291015625 0.9510192871093776 +1.599 -0.023590087890625 -0.48291015625 0.9510192871093776 +1.5991250000000002 -0.023529052734375 -0.48150634765625 0.9510192871093776 +1.59925 -0.023468017578125 -0.480072021484375 0.9510192871093776 +1.599375 -0.023468017578125 -0.480072021484375 0.9510192871093776 +1.5995000000000002 -0.02337646484375 -0.478607177734375 0.9510192871093776 +1.599625 -0.02337646484375 -0.478607177734375 0.9510192871093776 +1.59975 -0.0233154296875 -0.47705078125 0.9510192871093776 +1.599875 -0.023223876953125 -0.4754638671875 0.9510192871093776 +1.6 -0.001800537109375 -0.4754638671875 0.99608154296874928 +1.600125 -0.001800537109375 -0.47381591796875 0.99608154296874928 +1.60025 -0.001800537109375 -0.47381591796875 0.99608154296874928 +1.600375 -0.001800537109375 -0.472137451171875 0.99608154296874928 +1.6005 -0.00177001953125 -0.470367431640625 0.99608154296874928 +1.600625 -0.00177001953125 -0.470367431640625 0.99608154296874928 +1.6007500000000002 -0.00177001953125 -0.46856689453125 0.99608154296874928 +1.600875 -0.00177001953125 -0.46856689453125 0.99608154296874928 +1.601 -0.00177001953125 -0.46673583984375 0.99608154296874928 +1.6011250000000002 -0.00177001953125 -0.464813232421875 0.99608154296874928 +1.60125 -0.00177001953125 -0.464813232421875 0.99608154296874928 +1.601375 -0.001739501953125 -0.462890625 0.99608154296874928 +1.6015 -0.001739501953125 -0.462890625 0.99608154296874928 +1.601625 -0.001739501953125 -0.46087646484375 0.99608154296874928 +1.60175 -0.001739501953125 -0.458831787109375 0.99608154296874928 +1.601875 -0.001739501953125 -0.458831787109375 0.99608154296874928 +1.602 -0.001739501953125 -0.45672607421875 0.99608154296874928 +1.602125 -0.001739501953125 -0.45672607421875 0.99608154296874928 +1.60225 -0.001708984375 -0.454559326171875 0.99608154296874928 +1.602375 -0.001708984375 -0.452362060546875 0.99608154296874928 +1.6025 -0.001708984375 -0.452362060546875 0.99608154296874928 +1.602625 -0.001708984375 -0.450103759765625 0.99608154296874928 +1.6027500000000002 -0.001708984375 -0.450103759765625 0.99608154296874928 +1.602875 -0.001678466796875 -0.447784423828125 0.99608154296874928 +1.603 -0.001678466796875 -0.4454345703125 0.99608154296874928 +1.6031250000000002 -0.001678466796875 -0.4454345703125 0.99608154296874928 +1.60325 -0.001678466796875 -0.44305419921875 0.99608154296874928 +1.603375 -0.001678466796875 -0.44305419921875 0.99608154296874928 +1.6035 -0.001678466796875 -0.440582275390625 0.99608154296874928 +1.603625 -0.00164794921875 -0.438079833984375 0.99608154296874928 +1.60375 -0.00164794921875 -0.438079833984375 0.99608154296874928 +1.603875 -0.00164794921875 -0.435546875 0.99608154296874928 +1.604 -0.00164794921875 -0.435546875 0.99608154296874928 +1.604125 -0.00164794921875 -0.432952880859375 0.99608154296874928 +1.60425 -0.001617431640625 -0.4302978515625 0.99608154296874928 +1.604375 -0.001617431640625 -0.4302978515625 0.99608154296874928 +1.6045 -0.001617431640625 -0.4276123046875 0.99608154296874928 +1.604625 -0.001617431640625 -0.4276123046875 0.99608154296874928 +1.6047500000000002 -0.001617431640625 -0.424896240234375 0.99608154296874928 +1.604875 -0.0015869140625 -0.422119140625 0.99608154296874928 +1.605 -0.0015869140625 -0.422119140625 0.99608154296874928 +1.6051250000000002 -0.0015869140625 -0.419281005859375 0.99608154296874928 +1.60525 -0.0015869140625 -0.419281005859375 0.99608154296874928 +1.605375 -0.0015869140625 -0.416412353515625 0.99608154296874928 +1.6055 -0.001556396484375 -0.413482666015625 0.99608154296874928 +1.605625 -0.001556396484375 -0.413482666015625 0.99608154296874928 +1.60575 -0.001556396484375 -0.4105224609375 0.99608154296874928 +1.605875 -0.001556396484375 -0.4105224609375 0.99608154296874928 +1.606 -0.00152587890625 -0.407501220703125 0.99608154296874928 +1.606125 -0.00152587890625 -0.404449462890625 0.99608154296874928 +1.60625 -0.00152587890625 -0.404449462890625 0.99608154296874928 +1.606375 -0.00152587890625 -0.401336669921875 0.99608154296874928 +1.6065 -0.00152587890625 -0.401336669921875 0.99608154296874928 +1.606625 -0.001495361328125 -0.398193359375 0.99608154296874928 +1.6067500000000002 -0.001495361328125 -0.39501953125 0.99608154296874928 +1.606875 -0.001495361328125 -0.39501953125 0.99608154296874928 +1.607 -0.00146484375 -0.39178466796875 0.99608154296874928 +1.6071250000000002 -0.00146484375 -0.39178466796875 0.99608154296874928 +1.60725 -0.00146484375 -0.388519287109375 0.99608154296874928 +1.607375 -0.00146484375 -0.38519287109375 0.99608154296874928 +1.6075 -0.00146484375 -0.38519287109375 0.99608154296874928 +1.607625 -0.001434326171875 -0.3818359375 0.99608154296874928 +1.60775 -0.001434326171875 -0.3818359375 0.99608154296874928 +1.607875 -0.001434326171875 -0.378448486328125 0.99608154296874928 +1.608 -0.00140380859375 -0.375 0.99608154296874928 +1.608125 -0.00140380859375 -0.375 0.99608154296874928 +1.60825 -0.00140380859375 -0.37152099609375 0.99608154296874928 +1.608375 -0.00140380859375 -0.37152099609375 0.99608154296874928 +1.6085 -0.00140380859375 -0.36798095703125 0.99608154296874928 +1.608625 -0.001373291015625 -0.36444091796875 0.99608154296874928 +1.6087500000000002 -0.001373291015625 -0.36444091796875 0.99608154296874928 +1.608875 -0.001373291015625 -0.360809326171875 0.99608154296874928 +1.609 -0.001373291015625 -0.360809326171875 0.99608154296874928 +1.6091250000000002 -0.0013427734375 -0.357177734375 0.99608154296874928 +1.60925 -0.0013427734375 -0.353485107421875 0.99608154296874928 +1.609375 -0.0013427734375 -0.353485107421875 0.99608154296874928 +1.6095 -0.001312255859375 -0.349761962890625 0.99608154296874928 +1.609625 -0.001312255859375 -0.349761962890625 0.99608154296874928 +1.60975 -0.001312255859375 -0.34600830078125 0.99608154296874928 +1.609875 -0.00128173828125 -0.34222412109375 0.99608154296874928 +1.61 -0.00128173828125 -0.34222412109375 0.99608154296874928 +1.610125 -0.00128173828125 -0.33837890625 0.99608154296874928 +1.61025 -0.00128173828125 -0.33837890625 0.99608154296874928 +1.6103750000000002 -0.001251220703125 -0.334503173828125 0.99608154296874928 +1.6105 -0.001251220703125 -0.330596923828125 0.99608154296874928 +1.610625 -0.001251220703125 -0.330596923828125 0.99608154296874928 +1.6107500000000002 -0.001220703125 -0.32666015625 0.99608154296874928 +1.610875 -0.001220703125 -0.32666015625 0.99608154296874928 +1.611 -0.001220703125 -0.322662353515625 0.99608154296874928 +1.6111250000000002 -0.001190185546875 -0.31866455078125 0.99608154296874928 +1.61125 -0.001190185546875 -0.31866455078125 0.99608154296874928 +1.611375 -0.001190185546875 -0.314605712890625 0.99608154296874928 +1.6115 -0.001190185546875 -0.314605712890625 0.99608154296874928 +1.611625 -0.00115966796875 -0.310516357421875 0.99608154296874928 +1.61175 -0.00115966796875 -0.306396484375 0.99608154296874928 +1.611875 -0.00115966796875 -0.306396484375 0.99608154296874928 +1.612 -0.001129150390625 -0.30224609375 0.99608154296874928 +1.612125 -0.001129150390625 -0.30224609375 0.99608154296874928 +1.61225 -0.001129150390625 -0.298065185546875 0.99608154296874928 +1.6123750000000002 -0.0010986328125 -0.2938232421875 0.99608154296874928 +1.6125 -0.0010986328125 -0.2938232421875 0.99608154296874928 +1.612625 -0.0010986328125 -0.289581298828125 0.99608154296874928 +1.6127500000000002 -0.0010986328125 -0.289581298828125 0.99608154296874928 +1.612875 -0.001068115234375 -0.285308837890625 0.99608154296874928 +1.613 -0.001068115234375 -0.280975341796875 0.99608154296874928 +1.6131250000000002 -0.001068115234375 -0.280975341796875 0.99608154296874928 +1.61325 -0.00103759765625 -0.276641845703125 0.99608154296874928 +1.613375 -0.00103759765625 -0.276641845703125 0.99608154296874928 +1.6135 -0.00103759765625 -0.27227783203125 0.99608154296874928 +1.613625 -0.001007080078125 -0.267852783203125 0.99608154296874928 +1.61375 -0.001007080078125 -0.267852783203125 0.99608154296874928 +1.613875 -0.0009765625 -0.263427734375 0.99608154296874928 +1.614 -0.0009765625 -0.263427734375 0.99608154296874928 +1.614125 -0.0009765625 -0.25897216796875 0.99608154296874928 +1.61425 -0.000946044921875 -0.25445556640625 0.99608154296874928 +1.6143750000000002 -0.000946044921875 -0.25445556640625 0.99608154296874928 +1.6145 -0.000946044921875 -0.249969482421875 0.99608154296874928 +1.614625 -0.000946044921875 -0.249969482421875 0.99608154296874928 +1.6147500000000002 -0.00091552734375 -0.24542236328125 0.99608154296874928 +1.614875 -0.00091552734375 -0.2408447265625 0.99608154296874928 +1.615 -0.00091552734375 -0.2408447265625 0.99608154296874928 +1.6151250000000002 -0.000885009765625 -0.236236572265625 0.99608154296874928 +1.61525 -0.000885009765625 -0.236236572265625 0.99608154296874928 +1.615375 -0.0008544921875 -0.231597900390625 0.99608154296874928 +1.6155 -0.0008544921875 -0.226959228515625 0.99608154296874928 +1.615625 -0.0008544921875 -0.226959228515625 0.99608154296874928 +1.61575 -0.000823974609375 -0.2222900390625 0.99608154296874928 +1.615875 -0.000823974609375 -0.2222900390625 0.99608154296874928 +1.616 -0.000823974609375 -0.21759033203125 0.99608154296874928 +1.616125 -0.00079345703125 -0.212860107421875 0.99608154296874928 +1.61625 -0.00079345703125 -0.212860107421875 0.99608154296874928 +1.6163750000000002 -0.00079345703125 -0.208099365234375 0.99608154296874928 +1.6165 -0.00079345703125 -0.208099365234375 0.99608154296874928 +1.616625 -0.000762939453125 -0.203338623046875 0.99608154296874928 +1.6167500000000002 -0.000732421875 -0.19854736328125 0.99608154296874928 +1.616875 -0.000732421875 -0.19854736328125 0.99608154296874928 +1.617 -0.000732421875 -0.1937255859375 0.99608154296874928 +1.617125 -0.000732421875 -0.1937255859375 0.99608154296874928 +1.61725 -0.000701904296875 -0.188873291015625 0.99608154296874928 +1.617375 -0.000701904296875 -0.18402099609375 0.99608154296874928 +1.6175 -0.000701904296875 -0.18402099609375 0.99608154296874928 +1.617625 -0.00067138671875 -0.17913818359375 0.99608154296874928 +1.61775 -0.00067138671875 -0.17913818359375 0.99608154296874928 +1.617875 -0.000640869140625 -0.17425537109375 0.99608154296874928 +1.618 -0.000640869140625 -0.169342041015625 0.99608154296874928 +1.618125 -0.000640869140625 -0.169342041015625 0.99608154296874928 +1.61825 -0.0006103515625 -0.164398193359375 0.99608154296874928 +1.6183750000000002 -0.0006103515625 -0.164398193359375 0.99608154296874928 +1.6185 -0.000579833984375 -0.159454345703125 0.99608154296874928 +1.618625 -0.000579833984375 -0.15447998046875 0.99608154296874928 +1.6187500000000002 -0.000579833984375 -0.15447998046875 0.99608154296874928 +1.618875 -0.00054931640625 -0.14947509765625 0.99608154296874928 +1.619 -0.00054931640625 -0.14947509765625 0.99608154296874928 +1.619125 -0.00054931640625 -0.14447021484375 0.99608154296874928 +1.61925 -0.000518798828125 -0.13946533203125 0.99608154296874928 +1.619375 -0.000518798828125 -0.13946533203125 0.99608154296874928 +1.6195 -0.00048828125 -0.134429931640625 0.99608154296874928 +1.619625 -0.00048828125 -0.134429931640625 0.99608154296874928 +1.61975 -0.00048828125 -0.129364013671875 0.99608154296874928 +1.619875 -0.000457763671875 -0.124298095703125 0.99608154296874928 +1.62 -0.000457763671875 -0.124298095703125 0.99608154296874928 +1.620125 -0.00042724609375 -0.119232177734375 0.99608154296874928 +1.62025 -0.00042724609375 -0.119232177734375 0.99608154296874928 +1.6203750000000002 -0.00042724609375 -0.1141357421875 0.99608154296874928 +1.6205 -0.000396728515625 -0.109039306640625 0.99608154296874928 +1.620625 -0.000396728515625 -0.109039306640625 0.99608154296874928 +1.6207500000000002 -0.0003662109375 -0.103912353515625 0.99608154296874928 +1.620875 -0.0003662109375 -0.103912353515625 0.99608154296874928 +1.621 -0.0003662109375 -0.098785400390625 0.99608154296874928 +1.621125 -0.000335693359375 -0.093658447265625 0.99608154296874928 +1.62125 -0.000335693359375 -0.093658447265625 0.99608154296874928 +1.621375 -0.000335693359375 -0.0885009765625 0.99608154296874928 +1.6215 -0.000335693359375 -0.0885009765625 0.99608154296874928 +1.621625 -0.00030517578125 -0.083343505859375 0.99608154296874928 +1.62175 -0.000274658203125 -0.07818603515625 0.99608154296874928 +1.621875 -0.000274658203125 -0.07818603515625 0.99608154296874928 +1.622 -0.000274658203125 -0.072998046875 0.99608154296874928 +1.622125 -0.000274658203125 -0.072998046875 0.99608154296874928 +1.62225 -0.000244140625 -0.06781005859375 0.99608154296874928 +1.6223750000000002 -0.000213623046875 -0.0626220703125 0.99608154296874928 +1.6225 -0.000213623046875 -0.0626220703125 0.99608154296874928 +1.622625 -0.000213623046875 -0.05743408203125 0.99608154296874928 +1.6227500000000002 -0.000213623046875 -0.05743408203125 0.99608154296874928 +1.622875 -0.00018310546875 -0.05224609375 0.99608154296874928 +1.623 -0.000152587890625 -0.047027587890625 0.99608154296874928 +1.623125 -0.000152587890625 -0.047027587890625 0.99608154296874928 +1.62325 -0.000152587890625 -0.04180908203125 0.99608154296874928 +1.623375 -0.000152587890625 -0.04180908203125 0.99608154296874928 +1.6235 -0.0001220703125 -0.036590576171875 0.99608154296874928 +1.623625 -9.1552734375e-05 -0.0313720703125 0.99608154296874928 +1.62375 -9.1552734375e-05 -0.0313720703125 0.99608154296874928 +1.623875 -9.1552734375e-05 -0.026123046875 0.99608154296874928 +1.624 -9.1552734375e-05 -0.026123046875 0.99608154296874928 +1.624125 -6.103515625e-05 -0.020904541015625 0.99608154296874928 +1.62425 -3.0517578125e-05 -0.01568603515625 0.99608154296874928 +1.6243750000000002 -3.0517578125e-05 -0.01568603515625 0.99608154296874928 +1.6245 -3.0517578125e-05 -0.01043701171875 0.99608154296874928 +1.624625 -3.0517578125e-05 -0.01043701171875 0.99608154296874928 +1.6247500000000002 0.0 -0.005218505859375 0.99608154296874928 +1.624875 0.0 0.0 0.99608154296874928 +1.625 0.0 0.0 0.99608154296874928 +1.625125 0.0 0.005218505859375 0.99608154296874928 +1.62525 0.0 0.005218505859375 0.99608154296874928 +1.625375 3.0517578125e-05 0.01043701171875 0.99608154296874928 +1.6255 3.0517578125e-05 0.01568603515625 0.99608154296874928 +1.625625 3.0517578125e-05 0.01568603515625 0.99608154296874928 +1.62575 6.103515625e-05 0.020904541015625 0.99608154296874928 +1.625875 6.103515625e-05 0.020904541015625 0.99608154296874928 +1.6260000000000002 9.1552734375e-05 0.026123046875 0.99608154296874928 +1.626125 9.1552734375e-05 0.0313720703125 0.99608154296874928 +1.62625 9.1552734375e-05 0.0313720703125 0.99608154296874928 +1.6263750000000002 0.0001220703125 0.036590576171875 0.99608154296874928 +1.6265 0.0001220703125 0.036590576171875 0.99608154296874928 +1.626625 0.000152587890625 0.04180908203125 0.99608154296874928 +1.6267500000000002 0.000152587890625 0.047027587890625 0.99608154296874928 +1.626875 0.000152587890625 0.047027587890625 0.99608154296874928 +1.627 0.00018310546875 0.05224609375 0.99608154296874928 +1.627125 0.00018310546875 0.05224609375 0.99608154296874928 +1.62725 0.000213623046875 0.05743408203125 0.99608154296874928 +1.627375 0.000213623046875 0.0626220703125 0.99608154296874928 +1.6275 0.000213623046875 0.0626220703125 0.99608154296874928 +1.627625 0.000244140625 0.06781005859375 0.99608154296874928 +1.62775 0.000244140625 0.06781005859375 0.99608154296874928 +1.627875 0.000274658203125 0.072998046875 0.99608154296874928 +1.6280000000000002 0.000274658203125 0.07818603515625 0.99608154296874928 +1.628125 0.000274658203125 0.07818603515625 0.99608154296874928 +1.62825 0.00030517578125 0.083343505859375 0.99608154296874928 +1.6283750000000002 0.00030517578125 0.083343505859375 0.99608154296874928 +1.6285 0.000335693359375 0.0885009765625 0.99608154296874928 +1.628625 0.000335693359375 0.093658447265625 0.99608154296874928 +1.6287500000000002 0.000335693359375 0.093658447265625 0.99608154296874928 +1.628875 0.0003662109375 0.098785400390625 0.99608154296874928 +1.629 0.0003662109375 0.098785400390625 0.99608154296874928 +1.629125 0.0003662109375 0.103912353515625 0.99608154296874928 +1.62925 0.000396728515625 0.109039306640625 0.99608154296874928 +1.629375 0.000396728515625 0.109039306640625 0.99608154296874928 +1.6295 0.00042724609375 0.1141357421875 0.99608154296874928 +1.629625 0.00042724609375 0.1141357421875 0.99608154296874928 +1.62975 0.00042724609375 0.119232177734375 0.99608154296874928 +1.629875 0.000457763671875 0.124298095703125 0.99608154296874928 +1.6300000000000002 0.000457763671875 0.124298095703125 0.99608154296874928 +1.630125 0.00048828125 0.129364013671875 0.99608154296874928 +1.63025 0.00048828125 0.129364013671875 0.99608154296874928 +1.6303750000000002 0.00048828125 0.134429931640625 0.99608154296874928 +1.6305 0.000518798828125 0.13946533203125 0.99608154296874928 +1.630625 0.000518798828125 0.13946533203125 0.99608154296874928 +1.6307500000000002 0.00054931640625 0.14447021484375 0.99608154296874928 +1.630875 0.00054931640625 0.14447021484375 0.99608154296874928 +1.631 0.00054931640625 0.14947509765625 0.99608154296874928 +1.631125 0.000579833984375 0.15447998046875 0.99608154296874928 +1.63125 0.000579833984375 0.15447998046875 0.99608154296874928 +1.631375 0.000579833984375 0.159454345703125 0.99608154296874928 +1.6315 0.000579833984375 0.159454345703125 0.99608154296874928 +1.631625 0.0006103515625 0.164398193359375 0.99608154296874928 +1.63175 0.000640869140625 0.169342041015625 0.99608154296874928 +1.631875 0.000640869140625 0.169342041015625 0.99608154296874928 +1.6320000000000002 0.020477294921875 0.17425537109375 0.882238769531246 +1.632125 0.020477294921875 0.17425537109375 0.882238769531246 +1.63225 0.02105712890625 0.17913818359375 0.882238769531246 +1.6323750000000002 0.021636962890625 0.18402099609375 0.882238769531246 +1.6325 0.021636962890625 0.18402099609375 0.882238769531246 +1.632625 0.022216796875 0.188873291015625 0.882238769531246 +1.63275 0.022216796875 0.188873291015625 0.882238769531246 +1.632875 0.022796630859375 0.1937255859375 0.882238769531246 +1.633 0.023345947265625 0.19854736328125 0.882238769531246 +1.633125 0.023345947265625 0.19854736328125 0.882238769531246 +1.63325 0.02392578125 0.203338623046875 0.882238769531246 +1.633375 0.02392578125 0.203338623046875 0.882238769531246 +1.6335 0.02447509765625 0.208099365234375 0.882238769531246 +1.633625 0.0250244140625 0.212860107421875 0.882238769531246 +1.63375 0.0250244140625 0.212860107421875 0.882238769531246 +1.633875 0.025604248046875 0.21759033203125 0.882238769531246 +1.6340000000000002 0.025604248046875 0.21759033203125 0.882238769531246 +1.634125 0.026153564453125 0.2222900390625 0.882238769531246 +1.63425 0.026702880859375 0.226959228515625 0.882238769531246 +1.6343750000000002 0.026702880859375 0.226959228515625 0.882238769531246 +1.6345 0.027252197265625 0.231597900390625 0.882238769531246 +1.634625 0.027252197265625 0.231597900390625 0.882238769531246 +1.63475 0.027801513671875 0.236236572265625 0.882238769531246 +1.634875 0.0283203125 0.2408447265625 0.882238769531246 +1.635 0.0283203125 0.2408447265625 0.882238769531246 +1.635125 0.02886962890625 0.24542236328125 0.882238769531246 +1.63525 0.02886962890625 0.24542236328125 0.882238769531246 +1.635375 0.029388427734375 0.249969482421875 0.882238769531246 +1.6355 0.029937744140625 0.25445556640625 0.882238769531246 +1.635625 0.029937744140625 0.25445556640625 0.882238769531246 +1.63575 0.03045654296875 0.25897216796875 0.882238769531246 +1.635875 0.03045654296875 0.25897216796875 0.882238769531246 +1.6360000000000002 0.030975341796875 0.263427734375 0.882238769531246 +1.636125 0.031524658203125 0.267852783203125 0.882238769531246 +1.63625 0.031524658203125 0.267852783203125 0.882238769531246 +1.6363750000000002 0.03204345703125 0.27227783203125 0.882238769531246 +1.6365 0.03204345703125 0.27227783203125 0.882238769531246 +1.636625 0.03253173828125 0.276641845703125 0.882238769531246 +1.63675 0.033050537109375 0.280975341796875 0.882238769531246 +1.636875 0.033050537109375 0.280975341796875 0.882238769531246 +1.637 0.0335693359375 0.285308837890625 0.882238769531246 +1.637125 0.0335693359375 0.285308837890625 0.882238769531246 +1.63725 0.0340576171875 0.289581298828125 0.882238769531246 +1.637375 0.034576416015625 0.2938232421875 0.882238769531246 +1.6375 0.034576416015625 0.2938232421875 0.882238769531246 +1.637625 0.035064697265625 0.298065185546875 0.882238769531246 +1.63775 0.035064697265625 0.298065185546875 0.882238769531246 +1.637875 0.035552978515625 0.30224609375 0.882238769531246 +1.6380000000000002 0.036041259765625 0.306396484375 0.882238769531246 +1.638125 0.036041259765625 0.306396484375 0.882238769531246 +1.63825 0.036529541015625 0.310516357421875 0.882238769531246 +1.6383750000000002 0.036529541015625 0.310516357421875 0.882238769531246 +1.6385 0.037017822265625 0.314605712890625 0.882238769531246 +1.638625 0.0374755859375 0.31866455078125 0.882238769531246 +1.63875 0.0374755859375 0.31866455078125 0.882238769531246 +1.638875 0.0379638671875 0.322662353515625 0.882238769531246 +1.639 0.0379638671875 0.322662353515625 0.882238769531246 +1.639125 0.038421630859375 0.32666015625 0.882238769531246 +1.63925 0.03887939453125 0.330596923828125 0.882238769531246 +1.639375 0.03887939453125 0.330596923828125 0.882238769531246 +1.6395 0.03936767578125 0.334503173828125 0.882238769531246 +1.639625 0.03936767578125 0.334503173828125 0.882238769531246 +1.63975 0.039794921875 0.33837890625 0.882238769531246 +1.639875 0.040252685546875 0.34222412109375 0.882238769531246 +1.6400000000000002 0.040252685546875 0.34222412109375 0.882238769531246 +1.640125 0.04071044921875 0.34600830078125 0.882238769531246 +1.64025 0.04071044921875 0.34600830078125 0.882238769531246 +1.6403750000000002 0.0411376953125 0.349761962890625 0.882238769531246 +1.6405 0.041595458984375 0.353485107421875 0.882238769531246 +1.640625 0.041595458984375 0.353485107421875 0.882238769531246 +1.64075 0.042022705078125 0.357177734375 0.882238769531246 +1.640875 0.042022705078125 0.357177734375 0.882238769531246 +1.641 0.042449951171875 0.360809326171875 0.882238769531246 +1.641125 0.042877197265625 0.36444091796875 0.882238769531246 +1.64125 0.042877197265625 0.36444091796875 0.882238769531246 +1.641375 0.043304443359375 0.36798095703125 0.882238769531246 +1.6415 0.043304443359375 0.36798095703125 0.882238769531246 +1.6416250000000002 0.043701171875 0.37152099609375 0.882238769531246 +1.64175 0.04412841796875 0.375 0.882238769531246 +1.641875 0.04412841796875 0.375 0.882238769531246 +1.6420000000000002 0.044525146484375 0.378448486328125 0.882238769531246 +1.642125 0.044525146484375 0.378448486328125 0.882238769531246 +1.64225 0.044921875 0.3818359375 0.882238769531246 +1.6423750000000002 0.045318603515625 0.38519287109375 0.882238769531246 +1.6425 0.045318603515625 0.38519287109375 0.882238769531246 +1.642625 0.04571533203125 0.388519287109375 0.882238769531246 +1.64275 0.04571533203125 0.388519287109375 0.882238769531246 +1.642875 0.04608154296875 0.39178466796875 0.882238769531246 +1.643 0.046478271484375 0.39501953125 0.882238769531246 +1.643125 0.046478271484375 0.39501953125 0.882238769531246 +1.64325 0.046844482421875 0.398193359375 0.882238769531246 +1.643375 0.046844482421875 0.398193359375 0.882238769531246 +1.6435 0.047210693359375 0.401336669921875 0.882238769531246 +1.6436250000000002 0.047576904296875 0.404449462890625 0.882238769531246 +1.64375 0.047576904296875 0.404449462890625 0.882238769531246 +1.643875 0.047943115234375 0.407501220703125 0.882238769531246 +1.6440000000000002 0.047943115234375 0.407501220703125 0.882238769531246 +1.644125 0.048309326171875 0.4105224609375 0.882238769531246 +1.64425 0.04864501953125 0.413482666015625 0.882238769531246 +1.6443750000000002 0.04864501953125 0.413482666015625 0.882238769531246 +1.6445 0.048980712890625 0.416412353515625 0.882238769531246 +1.644625 0.048980712890625 0.416412353515625 0.882238769531246 +1.64475 0.04931640625 0.419281005859375 0.882238769531246 +1.644875 0.049652099609375 0.422119140625 0.882238769531246 +1.645 0.049652099609375 0.422119140625 0.882238769531246 +1.645125 0.04998779296875 0.424896240234375 0.882238769531246 +1.64525 0.04998779296875 0.424896240234375 0.882238769531246 +1.645375 0.050323486328125 0.4276123046875 0.882238769531246 +1.6455 0.050628662109375 0.4302978515625 0.882238769531246 +1.6456250000000002 0.050628662109375 0.4302978515625 0.882238769531246 +1.64575 0.050933837890625 0.432952880859375 0.882238769531246 +1.645875 0.050933837890625 0.432952880859375 0.882238769531246 +1.6460000000000002 0.051239013671875 0.435546875 0.882238769531246 +1.646125 0.051544189453125 0.438079833984375 0.882238769531246 +1.64625 0.051544189453125 0.438079833984375 0.882238769531246 +1.6463750000000002 0.051849365234375 0.440582275390625 0.882238769531246 +1.6465 0.051849365234375 0.440582275390625 0.882238769531246 +1.646625 0.0521240234375 0.44305419921875 0.882238769531246 +1.64675 0.052398681640625 0.4454345703125 0.882238769531246 +1.646875 0.052398681640625 0.4454345703125 0.882238769531246 +1.647 0.05267333984375 0.447784423828125 0.882238769531246 +1.647125 0.05267333984375 0.447784423828125 0.882238769531246 +1.64725 0.052947998046875 0.450103759765625 0.882238769531246 +1.647375 0.05322265625 0.452362060546875 0.882238769531246 +1.6475 0.05322265625 0.452362060546875 0.882238769531246 +1.6476250000000002 0.053466796875 0.454559326171875 0.882238769531246 +1.64775 0.053466796875 0.454559326171875 0.882238769531246 +1.647875 0.053741455078125 0.45672607421875 0.882238769531246 +1.6480000000000002 0.053985595703125 0.458831787109375 0.882238769531246 +1.648125 0.053985595703125 0.458831787109375 0.882238769531246 +1.64825 0.054229736328125 0.46087646484375 0.882238769531246 +1.648375 0.054229736328125 0.46087646484375 0.882238769531246 +1.6485 0.054473876953125 0.462890625 0.882238769531246 +1.648625 0.0546875 0.464813232421875 0.882238769531246 +1.64875 0.0546875 0.464813232421875 0.882238769531246 +1.648875 0.054901123046875 0.46673583984375 0.882238769531246 +1.649 0.054901123046875 0.46673583984375 0.882238769531246 +1.649125 0.05511474609375 0.46856689453125 0.882238769531246 +1.64925 0.055328369140625 0.470367431640625 0.882238769531246 +1.649375 0.055328369140625 0.470367431640625 0.882238769531246 +1.6495 0.0555419921875 0.472137451171875 0.882238769531246 +1.6496250000000002 0.0555419921875 0.472137451171875 0.882238769531246 +1.64975 0.055755615234375 0.47381591796875 0.882238769531246 +1.649875 0.055938720703125 0.4754638671875 0.882238769531246 +1.6500000000000002 0.055938720703125 0.4754638671875 0.882238769531246 +1.650125 0.056121826171875 0.47705078125 0.882238769531246 +1.65025 0.056121826171875 0.47705078125 0.882238769531246 +1.650375 0.056304931640625 0.478607177734375 0.882238769531246 +1.6505 0.056488037109375 0.480072021484375 0.882238769531246 +1.650625 0.056488037109375 0.480072021484375 0.882238769531246 +1.65075 0.056640625 0.48150634765625 0.882238769531246 +1.650875 0.056640625 0.48150634765625 0.882238769531246 +1.651 0.05682373046875 0.48291015625 0.882238769531246 +1.651125 0.056976318359375 0.484222412109375 0.882238769531246 +1.65125 0.056976318359375 0.484222412109375 0.882238769531246 +1.651375 0.05712890625 0.485504150390625 0.882238769531246 +1.6515 0.05712890625 0.485504150390625 0.882238769531246 +1.6516250000000002 0.0572509765625 0.486724853515625 0.882238769531246 +1.65175 0.057403564453125 0.487884521484375 0.882238769531246 +1.651875 0.057403564453125 0.487884521484375 0.882238769531246 +1.6520000000000002 0.057525634765625 0.489013671875 0.882238769531246 +1.652125 0.057525634765625 0.489013671875 0.882238769531246 +1.65225 0.057647705078125 0.490081787109375 0.882238769531246 +1.652375 0.057769775390625 0.4910888671875 0.882238769531246 +1.6525 0.057769775390625 0.4910888671875 0.882238769531246 +1.652625 0.057891845703125 0.492034912109375 0.882238769531246 +1.65275 0.057891845703125 0.492034912109375 0.882238769531246 +1.652875 0.0579833984375 0.492950439453125 0.882238769531246 +1.653 0.05810546875 0.4937744140625 0.882238769531246 +1.653125 0.05810546875 0.4937744140625 0.882238769531246 +1.65325 0.058197021484375 0.49456787109375 0.882238769531246 +1.653375 0.058197021484375 0.49456787109375 0.882238769531246 +1.6535 0.05828857421875 0.49530029296875 0.882238769531246 +1.6536250000000002 0.058349609375 0.496002197265625 0.882238769531246 +1.65375 0.058349609375 0.496002197265625 0.882238769531246 +1.653875 0.058441162109375 0.496612548828125 0.882238769531246 +1.6540000000000002 0.058441162109375 0.496612548828125 0.882238769531246 +1.654125 0.058502197265625 0.4971923828125 0.882238769531246 +1.65425 0.058563232421875 0.497711181640625 0.882238769531246 +1.654375 0.058563232421875 0.497711181640625 0.882238769531246 +1.6545 0.058624267578125 0.498199462890625 0.882238769531246 +1.654625 0.058624267578125 0.498199462890625 0.882238769531246 +1.65475 0.05865478515625 0.49859619140625 0.882238769531246 +1.654875 0.0587158203125 0.49896240234375 0.882238769531246 +1.655 0.0587158203125 0.49896240234375 0.882238769531246 +1.655125 0.058746337890625 0.499267578125 0.882238769531246 +1.65525 0.058746337890625 0.499267578125 0.882238769531246 +1.655375 0.05877685546875 0.49951171875 0.882238769531246 +1.6555 0.05877685546875 0.49969482421875 0.882238769531246 +1.6556250000000002 0.05877685546875 0.49969482421875 0.882238769531246 +1.65575 0.058807373046875 0.49981689453125 0.882238769531246 +1.655875 0.058807373046875 0.49981689453125 0.882238769531246 +1.6560000000000002 0.058807373046875 0.499908447265625 0.882238769531246 +1.656125 0.058807373046875 0.49993896484375 0.882238769531246 +1.65625 0.058807373046875 0.49993896484375 0.882238769531246 +1.656375 0.058807373046875 0.499908447265625 0.882238769531246 +1.6565 0.058807373046875 0.499908447265625 0.882238769531246 +1.656625 0.058807373046875 0.49981689453125 0.882238769531246 +1.65675 0.05877685546875 0.49969482421875 0.882238769531246 +1.656875 0.05877685546875 0.49969482421875 0.882238769531246 +1.657 0.05877685546875 0.49951171875 0.882238769531246 +1.657125 0.05877685546875 0.49951171875 0.882238769531246 +1.6572500000000002 0.058746337890625 0.499267578125 0.882238769531246 +1.657375 0.0587158203125 0.49896240234375 0.882238769531246 +1.6575 0.0587158203125 0.49896240234375 0.882238769531246 +1.6576250000000002 0.05865478515625 0.49859619140625 0.882238769531246 +1.65775 0.05865478515625 0.49859619140625 0.882238769531246 +1.657875 0.058624267578125 0.498199462890625 0.882238769531246 +1.6580000000000002 0.058563232421875 0.497711181640625 0.882238769531246 +1.658125 0.058563232421875 0.497711181640625 0.882238769531246 +1.65825 0.058502197265625 0.4971923828125 0.882238769531246 +1.658375 0.058502197265625 0.4971923828125 0.882238769531246 +1.6585 0.058441162109375 0.496612548828125 0.882238769531246 +1.658625 0.058349609375 0.496002197265625 0.882238769531246 +1.65875 0.058349609375 0.496002197265625 0.882238769531246 +1.658875 0.05828857421875 0.49530029296875 0.882238769531246 +1.659 0.05828857421875 0.49530029296875 0.882238769531246 +1.659125 0.058197021484375 0.49456787109375 0.882238769531246 +1.6592500000000002 0.05810546875 0.4937744140625 0.882238769531246 +1.659375 0.05810546875 0.4937744140625 0.882238769531246 +1.6595 0.0579833984375 0.492950439453125 0.882238769531246 +1.6596250000000002 0.0579833984375 0.492950439453125 0.882238769531246 +1.65975 0.057891845703125 0.492034912109375 0.882238769531246 +1.659875 0.057769775390625 0.4910888671875 0.882238769531246 +1.6600000000000002 0.057769775390625 0.4910888671875 0.882238769531246 +1.660125 0.057647705078125 0.490081787109375 0.882238769531246 +1.66025 0.057647705078125 0.490081787109375 0.882238769531246 +1.660375 0.057525634765625 0.489013671875 0.882238769531246 +1.6605 0.057403564453125 0.487884521484375 0.882238769531246 +1.660625 0.057403564453125 0.487884521484375 0.882238769531246 +1.66075 0.0572509765625 0.486724853515625 0.882238769531246 +1.660875 0.0572509765625 0.486724853515625 0.882238769531246 +1.661 0.05712890625 0.485504150390625 0.882238769531246 +1.661125 0.056976318359375 0.484222412109375 0.882238769531246 +1.6612500000000002 0.056976318359375 0.484222412109375 0.882238769531246 +1.661375 0.05682373046875 0.48291015625 0.882238769531246 +1.6615 0.05682373046875 0.48291015625 0.882238769531246 +1.6616250000000002 0.056640625 0.48150634765625 0.882238769531246 +1.66175 0.056488037109375 0.480072021484375 0.882238769531246 +1.661875 0.056488037109375 0.480072021484375 0.882238769531246 +1.6620000000000002 0.056304931640625 0.478607177734375 0.882238769531246 +1.662125 0.056304931640625 0.478607177734375 0.882238769531246 +1.66225 0.056121826171875 0.47705078125 0.882238769531246 +1.662375 0.055938720703125 0.4754638671875 0.882238769531246 +1.6625 0.055938720703125 0.4754638671875 0.882238769531246 +1.662625 0.055755615234375 0.47381591796875 0.882238769531246 +1.66275 0.055755615234375 0.47381591796875 0.882238769531246 +1.662875 0.0555419921875 0.472137451171875 0.882238769531246 +1.663 0.055328369140625 0.470367431640625 0.882238769531246 +1.663125 0.055328369140625 0.470367431640625 0.882238769531246 +1.6632500000000002 0.05511474609375 0.46856689453125 0.882238769531246 +1.663375 0.05511474609375 0.46856689453125 0.882238769531246 +1.6635 0.054901123046875 0.46673583984375 0.882238769531246 +1.6636250000000002 0.0546875 0.464813232421875 0.882238769531246 +1.66375 0.0546875 0.464813232421875 0.882238769531246 +1.663875 0.054473876953125 0.462890625 0.882238769531246 +1.6640000000000002 0.17230224609375 0.462890625 0.6276428222656184 +1.664125 0.17156982421875 0.46087646484375 0.6276428222656184 +1.66425 0.170806884765625 0.458831787109375 0.6276428222656184 +1.664375 0.170806884765625 0.458831787109375 0.6276428222656184 +1.6645 0.170013427734375 0.45672607421875 0.6276428222656184 +1.664625 0.170013427734375 0.45672607421875 0.6276428222656184 +1.66475 0.169219970703125 0.454559326171875 0.6276428222656184 +1.664875 0.16839599609375 0.452362060546875 0.6276428222656184 +1.665 0.16839599609375 0.452362060546875 0.6276428222656184 +1.665125 0.16754150390625 0.450103759765625 0.6276428222656184 +1.6652500000000002 0.16754150390625 0.450103759765625 0.6276428222656184 +1.665375 0.16668701171875 0.447784423828125 0.6276428222656184 +1.6655 0.165802001953125 0.4454345703125 0.6276428222656184 +1.6656250000000002 0.165802001953125 0.4454345703125 0.6276428222656184 +1.66575 0.1649169921875 0.44305419921875 0.6276428222656184 +1.665875 0.1649169921875 0.44305419921875 0.6276428222656184 +1.666 0.16400146484375 0.440582275390625 0.6276428222656184 +1.666125 0.1630859375 0.438079833984375 0.6276428222656184 +1.66625 0.1630859375 0.438079833984375 0.6276428222656184 +1.666375 0.162139892578125 0.435546875 0.6276428222656184 +1.6665 0.162139892578125 0.435546875 0.6276428222656184 +1.666625 0.161163330078125 0.432952880859375 0.6276428222656184 +1.66675 0.160186767578125 0.4302978515625 0.6276428222656184 +1.666875 0.160186767578125 0.4302978515625 0.6276428222656184 +1.667 0.1591796875 0.4276123046875 0.6276428222656184 +1.667125 0.1591796875 0.4276123046875 0.6276428222656184 +1.6672500000000002 0.158172607421875 0.424896240234375 0.6276428222656184 +1.667375 0.157135009765625 0.422119140625 0.6276428222656184 +1.6675 0.157135009765625 0.422119140625 0.6276428222656184 +1.6676250000000002 0.15606689453125 0.419281005859375 0.6276428222656184 +1.66775 0.15606689453125 0.419281005859375 0.6276428222656184 +1.667875 0.154998779296875 0.416412353515625 0.6276428222656184 +1.668 0.1539306640625 0.413482666015625 0.6276428222656184 +1.668125 0.1539306640625 0.413482666015625 0.6276428222656184 +1.66825 0.152801513671875 0.4105224609375 0.6276428222656184 +1.668375 0.152801513671875 0.4105224609375 0.6276428222656184 +1.6685 0.151702880859375 0.407501220703125 0.6276428222656184 +1.668625 0.15057373046875 0.404449462890625 0.6276428222656184 +1.66875 0.15057373046875 0.404449462890625 0.6276428222656184 +1.668875 0.1494140625 0.401336669921875 0.6276428222656184 +1.669 0.1494140625 0.401336669921875 0.6276428222656184 +1.669125 0.148223876953125 0.398193359375 0.6276428222656184 +1.6692500000000002 0.147064208984375 0.39501953125 0.6276428222656184 +1.669375 0.147064208984375 0.39501953125 0.6276428222656184 +1.6695 0.145843505859375 0.39178466796875 0.6276428222656184 +1.6696250000000002 0.145843505859375 0.39178466796875 0.6276428222656184 +1.66975 0.144622802734375 0.388519287109375 0.6276428222656184 +1.669875 0.143402099609375 0.38519287109375 0.6276428222656184 +1.67 0.143402099609375 0.38519287109375 0.6276428222656184 +1.670125 0.14215087890625 0.3818359375 0.6276428222656184 +1.67025 0.14215087890625 0.3818359375 0.6276428222656184 +1.670375 0.140869140625 0.378448486328125 0.6276428222656184 +1.6705 0.13958740234375 0.375 0.6276428222656184 +1.670625 0.13958740234375 0.375 0.6276428222656184 +1.67075 0.1383056640625 0.37152099609375 0.6276428222656184 +1.670875 0.1383056640625 0.37152099609375 0.6276428222656184 +1.671 0.136993408203125 0.36798095703125 0.6276428222656184 +1.671125 0.135650634765625 0.36444091796875 0.6276428222656184 +1.6712500000000002 0.135650634765625 0.36444091796875 0.6276428222656184 +1.671375 0.134307861328125 0.360809326171875 0.6276428222656184 +1.6715 0.134307861328125 0.360809326171875 0.6276428222656184 +1.6716250000000002 0.132965087890625 0.357177734375 0.6276428222656184 +1.67175 0.131591796875 0.353485107421875 0.6276428222656184 +1.671875 0.131591796875 0.353485107421875 0.6276428222656184 +1.672 0.13018798828125 0.349761962890625 0.6276428222656184 +1.672125 0.13018798828125 0.349761962890625 0.6276428222656184 +1.67225 0.128814697265625 0.34600830078125 0.6276428222656184 +1.672375 0.12738037109375 0.34222412109375 0.6276428222656184 +1.6725 0.12738037109375 0.34222412109375 0.6276428222656184 +1.672625 0.1259765625 0.33837890625 0.6276428222656184 +1.67275 0.1259765625 0.33837890625 0.6276428222656184 +1.6728750000000002 0.12451171875 0.334503173828125 0.6276428222656184 +1.673 0.123077392578125 0.330596923828125 0.6276428222656184 +1.673125 0.123077392578125 0.330596923828125 0.6276428222656184 +1.6732500000000002 0.12158203125 0.32666015625 0.6276428222656184 +1.673375 0.12158203125 0.32666015625 0.6276428222656184 +1.6735 0.1201171875 0.322662353515625 0.6276428222656184 +1.6736250000000002 0.118621826171875 0.31866455078125 0.6276428222656184 +1.67375 0.118621826171875 0.31866455078125 0.6276428222656184 +1.673875 0.117095947265625 0.314605712890625 0.6276428222656184 +1.674 0.117095947265625 0.314605712890625 0.6276428222656184 +1.674125 0.1156005859375 0.310516357421875 0.6276428222656184 +1.67425 0.114044189453125 0.306396484375 0.6276428222656184 +1.674375 0.114044189453125 0.306396484375 0.6276428222656184 +1.6745 0.112518310546875 0.30224609375 0.6276428222656184 +1.674625 0.112518310546875 0.30224609375 0.6276428222656184 +1.67475 0.1109619140625 0.298065185546875 0.6276428222656184 +1.6748750000000002 0.109375 0.2938232421875 0.6276428222656184 +1.675 0.109375 0.2938232421875 0.6276428222656184 +1.675125 0.1077880859375 0.289581298828125 0.6276428222656184 +1.6752500000000002 0.1077880859375 0.289581298828125 0.6276428222656184 +1.675375 0.106201171875 0.285308837890625 0.6276428222656184 +1.6755 0.104583740234375 0.280975341796875 0.6276428222656184 +1.6756250000000002 0.104583740234375 0.280975341796875 0.6276428222656184 +1.67575 0.10296630859375 0.276641845703125 0.6276428222656184 +1.675875 0.10296630859375 0.276641845703125 0.6276428222656184 +1.676 0.101348876953125 0.27227783203125 0.6276428222656184 +1.676125 0.099700927734375 0.267852783203125 0.6276428222656184 +1.67625 0.099700927734375 0.267852783203125 0.6276428222656184 +1.676375 0.098052978515625 0.263427734375 0.6276428222656184 +1.6765 0.098052978515625 0.263427734375 0.6276428222656184 +1.676625 0.096405029296875 0.25897216796875 0.6276428222656184 +1.67675 0.0947265625 0.25445556640625 0.6276428222656184 +1.6768750000000002 0.0947265625 0.25445556640625 0.6276428222656184 +1.677 0.093048095703125 0.249969482421875 0.6276428222656184 +1.677125 0.093048095703125 0.249969482421875 0.6276428222656184 +1.6772500000000002 0.091339111328125 0.24542236328125 0.6276428222656184 +1.677375 0.08966064453125 0.2408447265625 0.6276428222656184 +1.6775 0.08966064453125 0.2408447265625 0.6276428222656184 +1.6776250000000002 0.087921142578125 0.236236572265625 0.6276428222656184 +1.67775 0.087921142578125 0.236236572265625 0.6276428222656184 +1.677875 0.086212158203125 0.231597900390625 0.6276428222656184 +1.678 0.08447265625 0.226959228515625 0.6276428222656184 +1.678125 0.08447265625 0.226959228515625 0.6276428222656184 +1.67825 0.082733154296875 0.2222900390625 0.6276428222656184 +1.678375 0.082733154296875 0.2222900390625 0.6276428222656184 +1.6785 0.08099365234375 0.21759033203125 0.6276428222656184 +1.678625 0.0792236328125 0.212860107421875 0.6276428222656184 +1.67875 0.0792236328125 0.212860107421875 0.6276428222656184 +1.6788750000000002 0.07745361328125 0.208099365234375 0.6276428222656184 +1.679 0.07745361328125 0.208099365234375 0.6276428222656184 +1.679125 0.07568359375 0.203338623046875 0.6276428222656184 +1.6792500000000002 0.07391357421875 0.19854736328125 0.6276428222656184 +1.679375 0.07391357421875 0.19854736328125 0.6276428222656184 +1.6795 0.072113037109375 0.1937255859375 0.6276428222656184 +1.6796250000000002 0.072113037109375 0.1937255859375 0.6276428222656184 +1.67975 0.0703125 0.188873291015625 0.6276428222656184 +1.679875 0.068511962890625 0.18402099609375 0.6276428222656184 +1.68 0.068511962890625 0.18402099609375 0.6276428222656184 +1.680125 0.066680908203125 0.17913818359375 0.6276428222656184 +1.68025 0.066680908203125 0.17913818359375 0.6276428222656184 +1.680375 0.064849853515625 0.17425537109375 0.6276428222656184 +1.6805 0.063018798828125 0.169342041015625 0.6276428222656184 +1.680625 0.063018798828125 0.169342041015625 0.6276428222656184 +1.68075 0.061187744140625 0.164398193359375 0.6276428222656184 +1.6808750000000002 0.061187744140625 0.164398193359375 0.6276428222656184 +1.681 0.059356689453125 0.159454345703125 0.6276428222656184 +1.681125 0.0574951171875 0.15447998046875 0.6276428222656184 +1.6812500000000002 0.0574951171875 0.15447998046875 0.6276428222656184 +1.681375 0.055633544921875 0.14947509765625 0.6276428222656184 +1.6815 0.055633544921875 0.14947509765625 0.6276428222656184 +1.681625 0.05377197265625 0.14447021484375 0.6276428222656184 +1.68175 0.051910400390625 0.13946533203125 0.6276428222656184 +1.681875 0.051910400390625 0.13946533203125 0.6276428222656184 +1.682 0.050018310546875 0.134429931640625 0.6276428222656184 +1.682125 0.050018310546875 0.134429931640625 0.6276428222656184 +1.68225 0.04815673828125 0.129364013671875 0.6276428222656184 +1.682375 0.0462646484375 0.124298095703125 0.6276428222656184 +1.6825 0.0462646484375 0.124298095703125 0.6276428222656184 +1.682625 0.04437255859375 0.119232177734375 0.6276428222656184 +1.68275 0.04437255859375 0.119232177734375 0.6276428222656184 +1.6828750000000002 0.04248046875 0.1141357421875 0.6276428222656184 +1.683 0.04058837890625 0.109039306640625 0.6276428222656184 +1.683125 0.04058837890625 0.109039306640625 0.6276428222656184 +1.6832500000000002 0.038665771484375 0.103912353515625 0.6276428222656184 +1.683375 0.038665771484375 0.103912353515625 0.6276428222656184 +1.6835 0.036773681640625 0.098785400390625 0.6276428222656184 +1.683625 0.03485107421875 0.093658447265625 0.6276428222656184 +1.68375 0.03485107421875 0.093658447265625 0.6276428222656184 +1.683875 0.032928466796875 0.0885009765625 0.6276428222656184 +1.684 0.032928466796875 0.0885009765625 0.6276428222656184 +1.684125 0.031005859375 0.083343505859375 0.6276428222656184 +1.68425 0.029083251953125 0.07818603515625 0.6276428222656184 +1.684375 0.029083251953125 0.07818603515625 0.6276428222656184 +1.6845 0.02716064453125 0.072998046875 0.6276428222656184 +1.684625 0.02716064453125 0.072998046875 0.6276428222656184 +1.68475 0.025238037109375 0.06781005859375 0.6276428222656184 +1.6848750000000002 0.0233154296875 0.0626220703125 0.6276428222656184 +1.685 0.0233154296875 0.0626220703125 0.6276428222656184 +1.685125 0.0213623046875 0.05743408203125 0.6276428222656184 +1.6852500000000002 0.0213623046875 0.05743408203125 0.6276428222656184 +1.685375 0.019439697265625 0.05224609375 0.6276428222656184 +1.6855 0.017486572265625 0.047027587890625 0.6276428222656184 +1.685625 0.017486572265625 0.047027587890625 0.6276428222656184 +1.68575 0.01556396484375 0.04180908203125 0.6276428222656184 +1.685875 0.01556396484375 0.04180908203125 0.6276428222656184 +1.686 0.01361083984375 0.036590576171875 0.6276428222656184 +1.686125 0.01165771484375 0.0313720703125 0.6276428222656184 +1.68625 0.01165771484375 0.0313720703125 0.6276428222656184 +1.686375 0.009735107421875 0.026123046875 0.6276428222656184 +1.6865 0.009735107421875 0.026123046875 0.6276428222656184 +1.686625 0.007781982421875 0.020904541015625 0.6276428222656184 +1.68675 0.005828857421875 0.01568603515625 0.6276428222656184 +1.6868750000000002 0.005828857421875 0.01568603515625 0.6276428222656184 +1.687 0.003875732421875 0.01043701171875 0.6276428222656184 +1.687125 0.003875732421875 0.01043701171875 0.6276428222656184 +1.6872500000000002 0.001922607421875 0.005218505859375 0.6276428222656184 +1.687375 0.0 0.0 0.6276428222656184 +1.6875 0.0 0.0 0.6276428222656184 +1.687625 -0.001922607421875 -0.005218505859375 0.6276428222656184 +1.68775 -0.001922607421875 -0.005218505859375 0.6276428222656184 +1.687875 -0.003875732421875 -0.01043701171875 0.6276428222656184 +1.688 -0.005828857421875 -0.01568603515625 0.6276428222656184 +1.688125 -0.005828857421875 -0.01568603515625 0.6276428222656184 +1.68825 -0.007781982421875 -0.020904541015625 0.6276428222656184 +1.688375 -0.007781982421875 -0.020904541015625 0.6276428222656184 +1.6885000000000002 -0.009735107421875 -0.026123046875 0.6276428222656184 +1.688625 -0.01165771484375 -0.0313720703125 0.6276428222656184 +1.68875 -0.01165771484375 -0.0313720703125 0.6276428222656184 +1.6888750000000002 -0.01361083984375 -0.036590576171875 0.6276428222656184 +1.689 -0.01361083984375 -0.036590576171875 0.6276428222656184 +1.689125 -0.01556396484375 -0.04180908203125 0.6276428222656184 +1.6892500000000002 -0.017486572265625 -0.047027587890625 0.6276428222656184 +1.689375 -0.017486572265625 -0.047027587890625 0.6276428222656184 +1.6895 -0.019439697265625 -0.05224609375 0.6276428222656184 +1.689625 -0.019439697265625 -0.05224609375 0.6276428222656184 +1.68975 -0.0213623046875 -0.05743408203125 0.6276428222656184 +1.689875 -0.0233154296875 -0.0626220703125 0.6276428222656184 +1.69 -0.0233154296875 -0.0626220703125 0.6276428222656184 +1.690125 -0.025238037109375 -0.06781005859375 0.6276428222656184 +1.69025 -0.025238037109375 -0.06781005859375 0.6276428222656184 +1.690375 -0.02716064453125 -0.072998046875 0.6276428222656184 +1.6905000000000002 -0.029083251953125 -0.07818603515625 0.6276428222656184 +1.690625 -0.029083251953125 -0.07818603515625 0.6276428222656184 +1.69075 -0.031005859375 -0.083343505859375 0.6276428222656184 +1.6908750000000002 -0.031005859375 -0.083343505859375 0.6276428222656184 +1.691 -0.032928466796875 -0.0885009765625 0.6276428222656184 +1.691125 -0.03485107421875 -0.093658447265625 0.6276428222656184 +1.6912500000000002 -0.03485107421875 -0.093658447265625 0.6276428222656184 +1.691375 -0.036773681640625 -0.098785400390625 0.6276428222656184 +1.6915 -0.036773681640625 -0.098785400390625 0.6276428222656184 +1.691625 -0.038665771484375 -0.103912353515625 0.6276428222656184 +1.69175 -0.04058837890625 -0.109039306640625 0.6276428222656184 +1.691875 -0.04058837890625 -0.109039306640625 0.6276428222656184 +1.692 -0.04248046875 -0.1141357421875 0.6276428222656184 +1.692125 -0.04248046875 -0.1141357421875 0.6276428222656184 +1.69225 -0.04437255859375 -0.119232177734375 0.6276428222656184 +1.692375 -0.0462646484375 -0.124298095703125 0.6276428222656184 +1.6925000000000002 -0.0462646484375 -0.124298095703125 0.6276428222656184 +1.692625 -0.04815673828125 -0.129364013671875 0.6276428222656184 +1.69275 -0.04815673828125 -0.129364013671875 0.6276428222656184 +1.6928750000000002 -0.050018310546875 -0.134429931640625 0.6276428222656184 +1.693 -0.051910400390625 -0.13946533203125 0.6276428222656184 +1.693125 -0.051910400390625 -0.13946533203125 0.6276428222656184 +1.6932500000000002 -0.05377197265625 -0.14447021484375 0.6276428222656184 +1.693375 -0.05377197265625 -0.14447021484375 0.6276428222656184 +1.6935 -0.055633544921875 -0.14947509765625 0.6276428222656184 +1.693625 -0.0574951171875 -0.15447998046875 0.6276428222656184 +1.69375 -0.0574951171875 -0.15447998046875 0.6276428222656184 +1.693875 -0.059356689453125 -0.159454345703125 0.6276428222656184 +1.694 -0.059356689453125 -0.159454345703125 0.6276428222656184 +1.694125 -0.061187744140625 -0.164398193359375 0.6276428222656184 +1.69425 -0.063018798828125 -0.169342041015625 0.6276428222656184 +1.694375 -0.063018798828125 -0.169342041015625 0.6276428222656184 +1.6945000000000002 -0.064849853515625 -0.17425537109375 0.6276428222656184 +1.694625 -0.064849853515625 -0.17425537109375 0.6276428222656184 +1.69475 -0.066680908203125 -0.17913818359375 0.6276428222656184 +1.6948750000000002 -0.068511962890625 -0.18402099609375 0.6276428222656184 +1.695 -0.068511962890625 -0.18402099609375 0.6276428222656184 +1.695125 -0.0703125 -0.188873291015625 0.6276428222656184 +1.6952500000000002 -0.0703125 -0.188873291015625 0.6276428222656184 +1.695375 -0.072113037109375 -0.1937255859375 0.6276428222656184 +1.6955 -0.07391357421875 -0.19854736328125 0.6276428222656184 +1.695625 -0.07391357421875 -0.19854736328125 0.6276428222656184 +1.69575 -0.07568359375 -0.203338623046875 0.6276428222656184 +1.695875 -0.07568359375 -0.203338623046875 0.6276428222656184 +1.696 -0.15130615234375 -0.208099365234375 0.2729187011718668 +1.696125 -0.154754638671875 -0.212860107421875 0.2729187011718668 +1.69625 -0.154754638671875 -0.212860107421875 0.2729187011718668 +1.696375 -0.158172607421875 -0.21759033203125 0.2729187011718668 +1.6965000000000002 -0.158172607421875 -0.21759033203125 0.2729187011718668 +1.696625 -0.161590576171875 -0.2222900390625 0.2729187011718668 +1.69675 -0.16497802734375 -0.226959228515625 0.2729187011718668 +1.6968750000000002 -0.16497802734375 -0.226959228515625 0.2729187011718668 +1.697 -0.168365478515625 -0.231597900390625 0.2729187011718668 +1.697125 -0.168365478515625 -0.231597900390625 0.2729187011718668 +1.69725 -0.1717529296875 -0.236236572265625 0.2729187011718668 +1.697375 -0.175079345703125 -0.2408447265625 0.2729187011718668 +1.6975 -0.175079345703125 -0.2408447265625 0.2729187011718668 +1.697625 -0.17840576171875 -0.24542236328125 0.2729187011718668 +1.69775 -0.17840576171875 -0.24542236328125 0.2729187011718668 +1.697875 -0.181732177734375 -0.249969482421875 0.2729187011718668 +1.698 -0.18499755859375 -0.25445556640625 0.2729187011718668 +1.698125 -0.18499755859375 -0.25445556640625 0.2729187011718668 +1.69825 -0.188262939453125 -0.25897216796875 0.2729187011718668 +1.698375 -0.188262939453125 -0.25897216796875 0.2729187011718668 +1.6985000000000002 -0.1915283203125 -0.263427734375 0.2729187011718668 +1.698625 -0.194732666015625 -0.267852783203125 0.2729187011718668 +1.69875 -0.194732666015625 -0.267852783203125 0.2729187011718668 +1.6988750000000002 -0.19793701171875 -0.27227783203125 0.2729187011718668 +1.699 -0.19793701171875 -0.27227783203125 0.2729187011718668 +1.699125 -0.20111083984375 -0.276641845703125 0.2729187011718668 +1.69925 -0.20428466796875 -0.280975341796875 0.2729187011718668 +1.699375 -0.20428466796875 -0.280975341796875 0.2729187011718668 +1.6995 -0.207427978515625 -0.285308837890625 0.2729187011718668 +1.699625 -0.207427978515625 -0.285308837890625 0.2729187011718668 +1.69975 -0.210540771484375 -0.289581298828125 0.2729187011718668 +1.699875 -0.213623046875 -0.2938232421875 0.2729187011718668 +1.7 -0.213623046875 -0.2938232421875 0.2729187011718668 +1.700125 -0.216705322265625 -0.298065185546875 0.2729187011718668 +1.70025 -0.216705322265625 -0.298065185546875 0.2729187011718668 +1.700375 -0.2197265625 -0.30224609375 0.2729187011718668 +1.7005000000000002 -0.2227783203125 -0.306396484375 0.2729187011718668 +1.700625 -0.2227783203125 -0.306396484375 0.2729187011718668 +1.70075 -0.22576904296875 -0.310516357421875 0.2729187011718668 +1.7008750000000002 -0.22576904296875 -0.310516357421875 0.2729187011718668 +1.701 -0.228729248046875 -0.314605712890625 0.2729187011718668 +1.701125 -0.231658935546875 -0.31866455078125 0.2729187011718668 +1.70125 -0.231658935546875 -0.31866455078125 0.2729187011718668 +1.701375 -0.234588623046875 -0.322662353515625 0.2729187011718668 +1.7015 -0.234588623046875 -0.322662353515625 0.2729187011718668 +1.701625 -0.23748779296875 -0.32666015625 0.2729187011718668 +1.70175 -0.2403564453125 -0.330596923828125 0.2729187011718668 +1.701875 -0.2403564453125 -0.330596923828125 0.2729187011718668 +1.702 -0.243194580078125 -0.334503173828125 0.2729187011718668 +1.702125 -0.243194580078125 -0.334503173828125 0.2729187011718668 +1.70225 -0.246002197265625 -0.33837890625 0.2729187011718668 +1.702375 -0.248809814453125 -0.34222412109375 0.2729187011718668 +1.7025000000000002 -0.248809814453125 -0.34222412109375 0.2729187011718668 +1.702625 -0.251556396484375 -0.34600830078125 0.2729187011718668 +1.70275 -0.251556396484375 -0.34600830078125 0.2729187011718668 +1.7028750000000002 -0.254302978515625 -0.349761962890625 0.2729187011718668 +1.703 -0.256988525390625 -0.353485107421875 0.2729187011718668 +1.703125 -0.256988525390625 -0.353485107421875 0.2729187011718668 +1.70325 -0.259674072265625 -0.357177734375 0.2729187011718668 +1.703375 -0.259674072265625 -0.357177734375 0.2729187011718668 +1.7035 -0.2623291015625 -0.360809326171875 0.2729187011718668 +1.703625 -0.26495361328125 -0.36444091796875 0.2729187011718668 +1.70375 -0.26495361328125 -0.36444091796875 0.2729187011718668 +1.703875 -0.267547607421875 -0.36798095703125 0.2729187011718668 +1.704 -0.267547607421875 -0.36798095703125 0.2729187011718668 +1.7041250000000002 -0.270111083984375 -0.37152099609375 0.2729187011718668 +1.70425 -0.272613525390625 -0.375 0.2729187011718668 +1.704375 -0.272613525390625 -0.375 0.2729187011718668 +1.7045000000000002 -0.275146484375 -0.378448486328125 0.2729187011718668 +1.704625 -0.275146484375 -0.378448486328125 0.2729187011718668 +1.70475 -0.277618408203125 -0.3818359375 0.2729187011718668 +1.7048750000000002 -0.280059814453125 -0.38519287109375 0.2729187011718668 +1.705 -0.280059814453125 -0.38519287109375 0.2729187011718668 +1.705125 -0.282470703125 -0.388519287109375 0.2729187011718668 +1.70525 -0.282470703125 -0.388519287109375 0.2729187011718668 +1.705375 -0.28485107421875 -0.39178466796875 0.2729187011718668 +1.7055 -0.287200927734375 -0.39501953125 0.2729187011718668 +1.705625 -0.287200927734375 -0.39501953125 0.2729187011718668 +1.70575 -0.28948974609375 -0.398193359375 0.2729187011718668 +1.705875 -0.28948974609375 -0.398193359375 0.2729187011718668 +1.706 -0.291778564453125 -0.401336669921875 0.2729187011718668 +1.7061250000000002 -0.294036865234375 -0.404449462890625 0.2729187011718668 +1.70625 -0.294036865234375 -0.404449462890625 0.2729187011718668 +1.706375 -0.2962646484375 -0.407501220703125 0.2729187011718668 +1.7065000000000002 -0.2962646484375 -0.407501220703125 0.2729187011718668 +1.706625 -0.2984619140625 -0.4105224609375 0.2729187011718668 +1.70675 -0.30059814453125 -0.413482666015625 0.2729187011718668 +1.7068750000000002 -0.30059814453125 -0.413482666015625 0.2729187011718668 +1.707 -0.302734375 -0.416412353515625 0.2729187011718668 +1.707125 -0.302734375 -0.416412353515625 0.2729187011718668 +1.70725 -0.3048095703125 -0.419281005859375 0.2729187011718668 +1.707375 -0.306884765625 -0.422119140625 0.2729187011718668 +1.7075 -0.306884765625 -0.422119140625 0.2729187011718668 +1.707625 -0.30889892578125 -0.424896240234375 0.2729187011718668 +1.70775 -0.30889892578125 -0.424896240234375 0.2729187011718668 +1.707875 -0.310882568359375 -0.4276123046875 0.2729187011718668 +1.708 -0.312835693359375 -0.4302978515625 0.2729187011718668 +1.7081250000000002 -0.312835693359375 -0.4302978515625 0.2729187011718668 +1.70825 -0.31475830078125 -0.432952880859375 0.2729187011718668 +1.708375 -0.31475830078125 -0.432952880859375 0.2729187011718668 +1.7085000000000002 -0.316650390625 -0.435546875 0.2729187011718668 +1.708625 -0.318511962890625 -0.438079833984375 0.2729187011718668 +1.70875 -0.318511962890625 -0.438079833984375 0.2729187011718668 +1.7088750000000002 -0.3203125 -0.440582275390625 0.2729187011718668 +1.709 -0.3203125 -0.440582275390625 0.2729187011718668 +1.709125 -0.322113037109375 -0.44305419921875 0.2729187011718668 +1.70925 -0.3238525390625 -0.4454345703125 0.2729187011718668 +1.709375 -0.3238525390625 -0.4454345703125 0.2729187011718668 +1.7095 -0.3255615234375 -0.447784423828125 0.2729187011718668 +1.709625 -0.3255615234375 -0.447784423828125 0.2729187011718668 +1.70975 -0.327239990234375 -0.450103759765625 0.2729187011718668 +1.709875 -0.328857421875 -0.452362060546875 0.2729187011718668 +1.71 -0.328857421875 -0.452362060546875 0.2729187011718668 +1.7101250000000002 -0.330474853515625 -0.454559326171875 0.2729187011718668 +1.71025 -0.330474853515625 -0.454559326171875 0.2729187011718668 +1.710375 -0.33203125 -0.45672607421875 0.2729187011718668 +1.7105000000000002 -0.333587646484375 -0.458831787109375 0.2729187011718668 +1.710625 -0.333587646484375 -0.458831787109375 0.2729187011718668 +1.71075 -0.335052490234375 -0.46087646484375 0.2729187011718668 +1.7108750000000002 -0.335052490234375 -0.46087646484375 0.2729187011718668 +1.711 -0.336517333984375 -0.462890625 0.2729187011718668 +1.711125 -0.337921142578125 -0.464813232421875 0.2729187011718668 +1.71125 -0.337921142578125 -0.464813232421875 0.2729187011718668 +1.711375 -0.339324951171875 -0.46673583984375 0.2729187011718668 +1.7115 -0.339324951171875 -0.46673583984375 0.2729187011718668 +1.711625 -0.340667724609375 -0.46856689453125 0.2729187011718668 +1.71175 -0.34197998046875 -0.470367431640625 0.2729187011718668 +1.711875 -0.34197998046875 -0.470367431640625 0.2729187011718668 +1.712 -0.343231201171875 -0.472137451171875 0.2729187011718668 +1.7121250000000002 -0.343231201171875 -0.472137451171875 0.2729187011718668 +1.71225 -0.344482421875 -0.47381591796875 0.2729187011718668 +1.712375 -0.345672607421875 -0.4754638671875 0.2729187011718668 +1.7125000000000002 -0.345672607421875 -0.4754638671875 0.2729187011718668 +1.712625 -0.346832275390625 -0.47705078125 0.2729187011718668 +1.71275 -0.346832275390625 -0.47705078125 0.2729187011718668 +1.712875 -0.34796142578125 -0.478607177734375 0.2729187011718668 +1.713 -0.349029541015625 -0.480072021484375 0.2729187011718668 +1.713125 -0.349029541015625 -0.480072021484375 0.2729187011718668 +1.71325 -0.350067138671875 -0.48150634765625 0.2729187011718668 +1.713375 -0.350067138671875 -0.48150634765625 0.2729187011718668 +1.7135 -0.35107421875 -0.48291015625 0.2729187011718668 +1.713625 -0.35205078125 -0.484222412109375 0.2729187011718668 +1.71375 -0.35205078125 -0.484222412109375 0.2729187011718668 +1.713875 -0.35296630859375 -0.485504150390625 0.2729187011718668 +1.714 -0.35296630859375 -0.485504150390625 0.2729187011718668 +1.7141250000000002 -0.353851318359375 -0.486724853515625 0.2729187011718668 +1.71425 -0.354705810546875 -0.487884521484375 0.2729187011718668 +1.714375 -0.354705810546875 -0.487884521484375 0.2729187011718668 +1.7145000000000002 -0.35552978515625 -0.489013671875 0.2729187011718668 +1.714625 -0.35552978515625 -0.489013671875 0.2729187011718668 +1.71475 -0.356292724609375 -0.490081787109375 0.2729187011718668 +1.714875 -0.357025146484375 -0.4910888671875 0.2729187011718668 +1.715 -0.357025146484375 -0.4910888671875 0.2729187011718668 +1.715125 -0.35772705078125 -0.492034912109375 0.2729187011718668 +1.71525 -0.35772705078125 -0.492034912109375 0.2729187011718668 +1.715375 -0.358367919921875 -0.492950439453125 0.2729187011718668 +1.7155 -0.358978271484375 -0.4937744140625 0.2729187011718668 +1.715625 -0.358978271484375 -0.4937744140625 0.2729187011718668 +1.71575 -0.35955810546875 -0.49456787109375 0.2729187011718668 +1.715875 -0.35955810546875 -0.49456787109375 0.2729187011718668 +1.716 -0.360107421875 -0.49530029296875 0.2729187011718668 +1.7161250000000002 -0.360595703125 -0.496002197265625 0.2729187011718668 +1.71625 -0.360595703125 -0.496002197265625 0.2729187011718668 +1.716375 -0.361053466796875 -0.496612548828125 0.2729187011718668 +1.7165000000000002 -0.361053466796875 -0.496612548828125 0.2729187011718668 +1.716625 -0.361480712890625 -0.4971923828125 0.2729187011718668 +1.71675 -0.361846923828125 -0.497711181640625 0.2729187011718668 +1.716875 -0.361846923828125 -0.497711181640625 0.2729187011718668 +1.717 -0.3621826171875 -0.498199462890625 0.2729187011718668 +1.717125 -0.3621826171875 -0.498199462890625 0.2729187011718668 +1.71725 -0.36248779296875 -0.49859619140625 0.2729187011718668 +1.717375 -0.362762451171875 -0.49896240234375 0.2729187011718668 +1.7175 -0.362762451171875 -0.49896240234375 0.2729187011718668 +1.717625 -0.36297607421875 -0.499267578125 0.2729187011718668 +1.71775 -0.36297607421875 -0.499267578125 0.2729187011718668 +1.717875 -0.3631591796875 -0.49951171875 0.2729187011718668 +1.718 -0.36328125 -0.49969482421875 0.2729187011718668 +1.7181250000000002 -0.36328125 -0.49969482421875 0.2729187011718668 +1.71825 -0.363372802734375 -0.49981689453125 0.2729187011718668 +1.718375 -0.363372802734375 -0.49981689453125 0.2729187011718668 +1.7185000000000002 -0.363433837890625 -0.499908447265625 0.2729187011718668 +1.718625 -0.36346435546875 -0.49993896484375 0.2729187011718668 +1.71875 -0.36346435546875 -0.49993896484375 0.2729187011718668 +1.718875 -0.363433837890625 -0.499908447265625 0.2729187011718668 +1.719 -0.363433837890625 -0.499908447265625 0.2729187011718668 +1.719125 -0.363372802734375 -0.49981689453125 0.2729187011718668 +1.71925 -0.36328125 -0.49969482421875 0.2729187011718668 +1.719375 -0.36328125 -0.49969482421875 0.2729187011718668 +1.7195 -0.3631591796875 -0.49951171875 0.2729187011718668 +1.719625 -0.3631591796875 -0.49951171875 0.2729187011718668 +1.7197500000000002 -0.36297607421875 -0.499267578125 0.2729187011718668 +1.719875 -0.362762451171875 -0.49896240234375 0.2729187011718668 +1.72 -0.362762451171875 -0.49896240234375 0.2729187011718668 +1.7201250000000002 -0.36248779296875 -0.49859619140625 0.2729187011718668 +1.72025 -0.36248779296875 -0.49859619140625 0.2729187011718668 +1.720375 -0.3621826171875 -0.498199462890625 0.2729187011718668 +1.7205000000000002 -0.361846923828125 -0.497711181640625 0.2729187011718668 +1.720625 -0.361846923828125 -0.497711181640625 0.2729187011718668 +1.72075 -0.361480712890625 -0.4971923828125 0.2729187011718668 +1.720875 -0.361480712890625 -0.4971923828125 0.2729187011718668 +1.721 -0.361053466796875 -0.496612548828125 0.2729187011718668 +1.721125 -0.360595703125 -0.496002197265625 0.2729187011718668 +1.72125 -0.360595703125 -0.496002197265625 0.2729187011718668 +1.721375 -0.360107421875 -0.49530029296875 0.2729187011718668 +1.7215 -0.360107421875 -0.49530029296875 0.2729187011718668 +1.721625 -0.35955810546875 -0.49456787109375 0.2729187011718668 +1.7217500000000002 -0.358978271484375 -0.4937744140625 0.2729187011718668 +1.721875 -0.358978271484375 -0.4937744140625 0.2729187011718668 +1.722 -0.358367919921875 -0.492950439453125 0.2729187011718668 +1.7221250000000002 -0.358367919921875 -0.492950439453125 0.2729187011718668 +1.72225 -0.35772705078125 -0.492034912109375 0.2729187011718668 +1.722375 -0.357025146484375 -0.4910888671875 0.2729187011718668 +1.7225000000000002 -0.357025146484375 -0.4910888671875 0.2729187011718668 +1.722625 -0.356292724609375 -0.490081787109375 0.2729187011718668 +1.72275 -0.356292724609375 -0.490081787109375 0.2729187011718668 +1.722875 -0.35552978515625 -0.489013671875 0.2729187011718668 +1.723 -0.354705810546875 -0.487884521484375 0.2729187011718668 +1.723125 -0.354705810546875 -0.487884521484375 0.2729187011718668 +1.72325 -0.353851318359375 -0.486724853515625 0.2729187011718668 +1.723375 -0.353851318359375 -0.486724853515625 0.2729187011718668 +1.7235 -0.35296630859375 -0.485504150390625 0.2729187011718668 +1.723625 -0.35205078125 -0.484222412109375 0.2729187011718668 +1.7237500000000002 -0.35205078125 -0.484222412109375 0.2729187011718668 +1.723875 -0.35107421875 -0.48291015625 0.2729187011718668 +1.724 -0.35107421875 -0.48291015625 0.2729187011718668 +1.7241250000000002 -0.350067138671875 -0.48150634765625 0.2729187011718668 +1.72425 -0.349029541015625 -0.480072021484375 0.2729187011718668 +1.724375 -0.349029541015625 -0.480072021484375 0.2729187011718668 +1.7245000000000002 -0.34796142578125 -0.478607177734375 0.2729187011718668 +1.724625 -0.34796142578125 -0.478607177734375 0.2729187011718668 +1.72475 -0.346832275390625 -0.47705078125 0.2729187011718668 +1.724875 -0.345672607421875 -0.4754638671875 0.2729187011718668 +1.725 -0.345672607421875 -0.4754638671875 0.2729187011718668 +1.725125 -0.344482421875 -0.47381591796875 0.2729187011718668 +1.72525 -0.344482421875 -0.47381591796875 0.2729187011718668 +1.725375 -0.343231201171875 -0.472137451171875 0.2729187011718668 +1.7255 -0.34197998046875 -0.470367431640625 0.2729187011718668 +1.725625 -0.34197998046875 -0.470367431640625 0.2729187011718668 +1.7257500000000002 -0.340667724609375 -0.46856689453125 0.2729187011718668 +1.725875 -0.340667724609375 -0.46856689453125 0.2729187011718668 +1.726 -0.339324951171875 -0.46673583984375 0.2729187011718668 +1.7261250000000002 -0.337921142578125 -0.464813232421875 0.2729187011718668 +1.72625 -0.337921142578125 -0.464813232421875 0.2729187011718668 +1.726375 -0.336517333984375 -0.462890625 0.2729187011718668 +1.7265000000000002 -0.336517333984375 -0.462890625 0.2729187011718668 +1.726625 -0.335052490234375 -0.46087646484375 0.2729187011718668 +1.72675 -0.333587646484375 -0.458831787109375 0.2729187011718668 +1.726875 -0.333587646484375 -0.458831787109375 0.2729187011718668 +1.727 -0.33203125 -0.45672607421875 0.2729187011718668 +1.727125 -0.33203125 -0.45672607421875 0.2729187011718668 +1.72725 -0.330474853515625 -0.454559326171875 0.2729187011718668 +1.727375 -0.328857421875 -0.452362060546875 0.2729187011718668 +1.7275 -0.328857421875 -0.452362060546875 0.2729187011718668 +1.727625 -0.327239990234375 -0.450103759765625 0.2729187011718668 +1.7277500000000002 -0.327239990234375 -0.450103759765625 0.2729187011718668 +1.727875 -0.3255615234375 -0.447784423828125 0.2729187011718668 +1.728 -0.4454345703125 -0.389617919921875 -0.12530517578125826 +1.7281250000000002 -0.4454345703125 -0.389617919921875 -0.12530517578125826 +1.72825 -0.44305419921875 -0.38751220703125 -0.12530517578125826 +1.728375 -0.44305419921875 -0.38751220703125 -0.12530517578125826 +1.7285 -0.440582275390625 -0.385345458984375 -0.12530517578125826 +1.728625 -0.438079833984375 -0.3831787109375 -0.12530517578125826 +1.72875 -0.438079833984375 -0.3831787109375 -0.12530517578125826 +1.728875 -0.435546875 -0.380950927734375 -0.12530517578125826 +1.729 -0.435546875 -0.380950927734375 -0.12530517578125826 +1.729125 -0.432952880859375 -0.378692626953125 -0.12530517578125826 +1.72925 -0.4302978515625 -0.376373291015625 -0.12530517578125826 +1.729375 -0.4302978515625 -0.376373291015625 -0.12530517578125826 +1.7295 -0.4276123046875 -0.3740234375 -0.12530517578125826 +1.729625 -0.4276123046875 -0.3740234375 -0.12530517578125826 +1.7297500000000002 -0.424896240234375 -0.371612548828125 -0.12530517578125826 +1.729875 -0.422119140625 -0.36920166015625 -0.12530517578125826 +1.73 -0.422119140625 -0.36920166015625 -0.12530517578125826 +1.7301250000000002 -0.419281005859375 -0.366729736328125 -0.12530517578125826 +1.73025 -0.419281005859375 -0.366729736328125 -0.12530517578125826 +1.730375 -0.416412353515625 -0.36419677734375 -0.12530517578125826 +1.7305 -0.413482666015625 -0.36163330078125 -0.12530517578125826 +1.730625 -0.413482666015625 -0.36163330078125 -0.12530517578125826 +1.73075 -0.4105224609375 -0.35906982421875 -0.12530517578125826 +1.730875 -0.4105224609375 -0.35906982421875 -0.12530517578125826 +1.731 -0.407501220703125 -0.356414794921875 -0.12530517578125826 +1.731125 -0.404449462890625 -0.353759765625 -0.12530517578125826 +1.73125 -0.404449462890625 -0.353759765625 -0.12530517578125826 +1.731375 -0.401336669921875 -0.351043701171875 -0.12530517578125826 +1.7315 -0.401336669921875 -0.351043701171875 -0.12530517578125826 +1.731625 -0.398193359375 -0.348297119140625 -0.12530517578125826 +1.7317500000000002 -0.39501953125 -0.34552001953125 -0.12530517578125826 +1.731875 -0.39501953125 -0.34552001953125 -0.12530517578125826 +1.732 -0.39178466796875 -0.342681884765625 -0.12530517578125826 +1.7321250000000002 -0.39178466796875 -0.342681884765625 -0.12530517578125826 +1.73225 -0.388519287109375 -0.339813232421875 -0.12530517578125826 +1.732375 -0.38519287109375 -0.3369140625 -0.12530517578125826 +1.7325 -0.38519287109375 -0.3369140625 -0.12530517578125826 +1.732625 -0.3818359375 -0.333984375 -0.12530517578125826 +1.73275 -0.3818359375 -0.333984375 -0.12530517578125826 +1.732875 -0.378448486328125 -0.33099365234375 -0.12530517578125826 +1.733 -0.375 -0.327972412109375 -0.12530517578125826 +1.733125 -0.375 -0.327972412109375 -0.12530517578125826 +1.73325 -0.37152099609375 -0.324951171875 -0.12530517578125826 +1.733375 -0.37152099609375 -0.324951171875 -0.12530517578125826 +1.7335 -0.36798095703125 -0.321868896484375 -0.12530517578125826 +1.733625 -0.36444091796875 -0.318756103515625 -0.12530517578125826 +1.7337500000000002 -0.36444091796875 -0.318756103515625 -0.12530517578125826 +1.733875 -0.360809326171875 -0.315582275390625 -0.12530517578125826 +1.734 -0.360809326171875 -0.315582275390625 -0.12530517578125826 +1.7341250000000002 -0.357177734375 -0.312408447265625 -0.12530517578125826 +1.73425 -0.353485107421875 -0.309173583984375 -0.12530517578125826 +1.734375 -0.353485107421875 -0.309173583984375 -0.12530517578125826 +1.7345 -0.349761962890625 -0.305938720703125 -0.12530517578125826 +1.734625 -0.349761962890625 -0.305938720703125 -0.12530517578125826 +1.73475 -0.34600830078125 -0.302642822265625 -0.12530517578125826 +1.734875 -0.34222412109375 -0.29931640625 -0.12530517578125826 +1.735 -0.34222412109375 -0.29931640625 -0.12530517578125826 +1.735125 -0.33837890625 -0.29595947265625 -0.12530517578125826 +1.73525 -0.33837890625 -0.29595947265625 -0.12530517578125826 +1.7353750000000002 -0.334503173828125 -0.292572021484375 -0.12530517578125826 +1.7355 -0.330596923828125 -0.289154052734375 -0.12530517578125826 +1.735625 -0.330596923828125 -0.289154052734375 -0.12530517578125826 +1.7357500000000002 -0.32666015625 -0.28570556640625 -0.12530517578125826 +1.735875 -0.32666015625 -0.28570556640625 -0.12530517578125826 +1.736 -0.322662353515625 -0.2822265625 -0.12530517578125826 +1.7361250000000002 -0.31866455078125 -0.278717041015625 -0.12530517578125826 +1.73625 -0.31866455078125 -0.278717041015625 -0.12530517578125826 +1.736375 -0.314605712890625 -0.275177001953125 -0.12530517578125826 +1.7365 -0.314605712890625 -0.275177001953125 -0.12530517578125826 +1.736625 -0.310516357421875 -0.2716064453125 -0.12530517578125826 +1.73675 -0.306396484375 -0.26800537109375 -0.12530517578125826 +1.736875 -0.306396484375 -0.26800537109375 -0.12530517578125826 +1.737 -0.30224609375 -0.26434326171875 -0.12530517578125826 +1.737125 -0.30224609375 -0.26434326171875 -0.12530517578125826 +1.73725 -0.298065185546875 -0.260711669921875 -0.12530517578125826 +1.7373750000000002 -0.2938232421875 -0.256988525390625 -0.12530517578125826 +1.7375 -0.2938232421875 -0.256988525390625 -0.12530517578125826 +1.737625 -0.289581298828125 -0.2532958984375 -0.12530517578125826 +1.7377500000000002 -0.289581298828125 -0.2532958984375 -0.12530517578125826 +1.737875 -0.285308837890625 -0.249542236328125 -0.12530517578125826 +1.738 -0.280975341796875 -0.245758056640625 -0.12530517578125826 +1.7381250000000002 -0.280975341796875 -0.245758056640625 -0.12530517578125826 +1.73825 -0.276641845703125 -0.241973876953125 -0.12530517578125826 +1.738375 -0.276641845703125 -0.241973876953125 -0.12530517578125826 +1.7385 -0.27227783203125 -0.2381591796875 -0.12530517578125826 +1.738625 -0.267852783203125 -0.234283447265625 -0.12530517578125826 +1.73875 -0.267852783203125 -0.234283447265625 -0.12530517578125826 +1.738875 -0.263427734375 -0.23040771484375 -0.12530517578125826 +1.739 -0.263427734375 -0.23040771484375 -0.12530517578125826 +1.739125 -0.25897216796875 -0.22650146484375 -0.12530517578125826 +1.73925 -0.25445556640625 -0.222564697265625 -0.12530517578125826 +1.7393750000000002 -0.25445556640625 -0.222564697265625 -0.12530517578125826 +1.7395 -0.249969482421875 -0.2186279296875 -0.12530517578125826 +1.739625 -0.249969482421875 -0.2186279296875 -0.12530517578125826 +1.7397500000000002 -0.24542236328125 -0.214630126953125 -0.12530517578125826 +1.739875 -0.2408447265625 -0.21063232421875 -0.12530517578125826 +1.74 -0.2408447265625 -0.21063232421875 -0.12530517578125826 +1.7401250000000002 -0.236236572265625 -0.206634521484375 -0.12530517578125826 +1.74025 -0.236236572265625 -0.206634521484375 -0.12530517578125826 +1.740375 -0.231597900390625 -0.20257568359375 -0.12530517578125826 +1.7405 -0.226959228515625 -0.198486328125 -0.12530517578125826 +1.740625 -0.226959228515625 -0.198486328125 -0.12530517578125826 +1.74075 -0.2222900390625 -0.194427490234375 -0.12530517578125826 +1.740875 -0.2222900390625 -0.194427490234375 -0.12530517578125826 +1.741 -0.21759033203125 -0.1903076171875 -0.12530517578125826 +1.741125 -0.212860107421875 -0.1861572265625 -0.12530517578125826 +1.74125 -0.212860107421875 -0.1861572265625 -0.12530517578125826 +1.7413750000000002 -0.208099365234375 -0.1820068359375 -0.12530517578125826 +1.7415 -0.208099365234375 -0.1820068359375 -0.12530517578125826 +1.741625 -0.203338623046875 -0.177825927734375 -0.12530517578125826 +1.7417500000000002 -0.19854736328125 -0.17364501953125 -0.12530517578125826 +1.741875 -0.19854736328125 -0.17364501953125 -0.12530517578125826 +1.742 -0.1937255859375 -0.16943359375 -0.12530517578125826 +1.7421250000000002 -0.1937255859375 -0.16943359375 -0.12530517578125826 +1.74225 -0.188873291015625 -0.165191650390625 -0.12530517578125826 +1.742375 -0.18402099609375 -0.16094970703125 -0.12530517578125826 +1.7425 -0.18402099609375 -0.16094970703125 -0.12530517578125826 +1.742625 -0.17913818359375 -0.15667724609375 -0.12530517578125826 +1.74275 -0.17913818359375 -0.15667724609375 -0.12530517578125826 +1.742875 -0.17425537109375 -0.15240478515625 -0.12530517578125826 +1.743 -0.169342041015625 -0.148101806640625 -0.12530517578125826 +1.743125 -0.169342041015625 -0.148101806640625 -0.12530517578125826 +1.74325 -0.164398193359375 -0.143768310546875 -0.12530517578125826 +1.7433750000000002 -0.164398193359375 -0.143768310546875 -0.12530517578125826 +1.7435 -0.159454345703125 -0.13946533203125 -0.12530517578125826 +1.743625 -0.15447998046875 -0.135101318359375 -0.12530517578125826 +1.7437500000000002 -0.15447998046875 -0.135101318359375 -0.12530517578125826 +1.743875 -0.14947509765625 -0.1307373046875 -0.12530517578125826 +1.744 -0.14947509765625 -0.1307373046875 -0.12530517578125826 +1.744125 -0.14447021484375 -0.126373291015625 -0.12530517578125826 +1.74425 -0.13946533203125 -0.121978759765625 -0.12530517578125826 +1.744375 -0.13946533203125 -0.121978759765625 -0.12530517578125826 +1.7445 -0.134429931640625 -0.117584228515625 -0.12530517578125826 +1.744625 -0.134429931640625 -0.117584228515625 -0.12530517578125826 +1.74475 -0.129364013671875 -0.1131591796875 -0.12530517578125826 +1.744875 -0.124298095703125 -0.108734130859375 -0.12530517578125826 +1.745 -0.124298095703125 -0.108734130859375 -0.12530517578125826 +1.745125 -0.119232177734375 -0.104278564453125 -0.12530517578125826 +1.74525 -0.119232177734375 -0.104278564453125 -0.12530517578125826 +1.7453750000000002 -0.1141357421875 -0.099822998046875 -0.12530517578125826 +1.7455 -0.109039306640625 -0.095367431640625 -0.12530517578125826 +1.745625 -0.109039306640625 -0.095367431640625 -0.12530517578125826 +1.7457500000000002 -0.103912353515625 -0.09088134765625 -0.12530517578125826 +1.745875 -0.103912353515625 -0.09088134765625 -0.12530517578125826 +1.746 -0.098785400390625 -0.086395263671875 -0.12530517578125826 +1.746125 -0.093658447265625 -0.0819091796875 -0.12530517578125826 +1.74625 -0.093658447265625 -0.0819091796875 -0.12530517578125826 +1.746375 -0.0885009765625 -0.077423095703125 -0.12530517578125826 +1.7465 -0.0885009765625 -0.077423095703125 -0.12530517578125826 +1.746625 -0.083343505859375 -0.072906494140625 -0.12530517578125826 +1.74675 -0.07818603515625 -0.068389892578125 -0.12530517578125826 +1.746875 -0.07818603515625 -0.068389892578125 -0.12530517578125826 +1.747 -0.072998046875 -0.0638427734375 -0.12530517578125826 +1.747125 -0.072998046875 -0.0638427734375 -0.12530517578125826 +1.74725 -0.06781005859375 -0.059326171875 -0.12530517578125826 +1.7473750000000002 -0.0626220703125 -0.054779052734375 -0.12530517578125826 +1.7475 -0.0626220703125 -0.054779052734375 -0.12530517578125826 +1.747625 -0.05743408203125 -0.05023193359375 -0.12530517578125826 +1.7477500000000002 -0.05743408203125 -0.05023193359375 -0.12530517578125826 +1.747875 -0.05224609375 -0.045684814453125 -0.12530517578125826 +1.748 -0.047027587890625 -0.0411376953125 -0.12530517578125826 +1.748125 -0.047027587890625 -0.0411376953125 -0.12530517578125826 +1.74825 -0.04180908203125 -0.03656005859375 -0.12530517578125826 +1.748375 -0.04180908203125 -0.03656005859375 -0.12530517578125826 +1.7485 -0.036590576171875 -0.032012939453125 -0.12530517578125826 +1.748625 -0.0313720703125 -0.027435302734375 -0.12530517578125826 +1.74875 -0.0313720703125 -0.027435302734375 -0.12530517578125826 +1.748875 -0.026123046875 -0.022857666015625 -0.12530517578125826 +1.749 -0.026123046875 -0.022857666015625 -0.12530517578125826 +1.749125 -0.020904541015625 -0.018280029296875 -0.12530517578125826 +1.74925 -0.01568603515625 -0.013702392578125 -0.12530517578125826 +1.7493750000000002 -0.01568603515625 -0.013702392578125 -0.12530517578125826 +1.7495 -0.01043701171875 -0.009124755859375 -0.12530517578125826 +1.749625 -0.01043701171875 -0.009124755859375 -0.12530517578125826 +1.7497500000000002 -0.005218505859375 -0.004547119140625 -0.12530517578125826 +1.749875 0.0 0.0 -0.12530517578125826 +1.75 0.0 0.0 -0.12530517578125826 +1.750125 0.005218505859375 0.004547119140625 -0.12530517578125826 +1.75025 0.005218505859375 0.004547119140625 -0.12530517578125826 +1.750375 0.01043701171875 0.009124755859375 -0.12530517578125826 +1.7505 0.01568603515625 0.013702392578125 -0.12530517578125826 +1.750625 0.01568603515625 0.013702392578125 -0.12530517578125826 +1.75075 0.020904541015625 0.018280029296875 -0.12530517578125826 +1.750875 0.020904541015625 0.018280029296875 -0.12530517578125826 +1.7510000000000002 0.026123046875 0.022857666015625 -0.12530517578125826 +1.751125 0.0313720703125 0.027435302734375 -0.12530517578125826 +1.75125 0.0313720703125 0.027435302734375 -0.12530517578125826 +1.7513750000000002 0.036590576171875 0.032012939453125 -0.12530517578125826 +1.7515 0.036590576171875 0.032012939453125 -0.12530517578125826 +1.751625 0.04180908203125 0.03656005859375 -0.12530517578125826 +1.7517500000000002 0.047027587890625 0.0411376953125 -0.12530517578125826 +1.751875 0.047027587890625 0.0411376953125 -0.12530517578125826 +1.752 0.05224609375 0.045684814453125 -0.12530517578125826 +1.752125 0.05224609375 0.045684814453125 -0.12530517578125826 +1.75225 0.05743408203125 0.05023193359375 -0.12530517578125826 +1.752375 0.0626220703125 0.054779052734375 -0.12530517578125826 +1.7525 0.0626220703125 0.054779052734375 -0.12530517578125826 +1.752625 0.06781005859375 0.059326171875 -0.12530517578125826 +1.75275 0.06781005859375 0.059326171875 -0.12530517578125826 +1.752875 0.072998046875 0.0638427734375 -0.12530517578125826 +1.7530000000000002 0.07818603515625 0.068389892578125 -0.12530517578125826 +1.753125 0.07818603515625 0.068389892578125 -0.12530517578125826 +1.75325 0.083343505859375 0.072906494140625 -0.12530517578125826 +1.7533750000000002 0.083343505859375 0.072906494140625 -0.12530517578125826 +1.7535 0.0885009765625 0.077423095703125 -0.12530517578125826 +1.753625 0.093658447265625 0.0819091796875 -0.12530517578125826 +1.7537500000000002 0.093658447265625 0.0819091796875 -0.12530517578125826 +1.753875 0.098785400390625 0.086395263671875 -0.12530517578125826 +1.754 0.098785400390625 0.086395263671875 -0.12530517578125826 +1.754125 0.103912353515625 0.09088134765625 -0.12530517578125826 +1.75425 0.109039306640625 0.095367431640625 -0.12530517578125826 +1.754375 0.109039306640625 0.095367431640625 -0.12530517578125826 +1.7545 0.1141357421875 0.099822998046875 -0.12530517578125826 +1.754625 0.1141357421875 0.099822998046875 -0.12530517578125826 +1.75475 0.119232177734375 0.104278564453125 -0.12530517578125826 +1.754875 0.124298095703125 0.108734130859375 -0.12530517578125826 +1.7550000000000002 0.124298095703125 0.108734130859375 -0.12530517578125826 +1.755125 0.129364013671875 0.1131591796875 -0.12530517578125826 +1.75525 0.129364013671875 0.1131591796875 -0.12530517578125826 +1.7553750000000002 0.134429931640625 0.117584228515625 -0.12530517578125826 +1.7555 0.13946533203125 0.121978759765625 -0.12530517578125826 +1.755625 0.13946533203125 0.121978759765625 -0.12530517578125826 +1.7557500000000002 0.14447021484375 0.126373291015625 -0.12530517578125826 +1.755875 0.14447021484375 0.126373291015625 -0.12530517578125826 +1.756 0.14947509765625 0.1307373046875 -0.12530517578125826 +1.756125 0.15447998046875 0.135101318359375 -0.12530517578125826 +1.75625 0.15447998046875 0.135101318359375 -0.12530517578125826 +1.756375 0.159454345703125 0.13946533203125 -0.12530517578125826 +1.7565 0.159454345703125 0.13946533203125 -0.12530517578125826 +1.756625 0.164398193359375 0.143768310546875 -0.12530517578125826 +1.75675 0.169342041015625 0.148101806640625 -0.12530517578125826 +1.756875 0.169342041015625 0.148101806640625 -0.12530517578125826 +1.7570000000000002 0.17425537109375 0.15240478515625 -0.12530517578125826 +1.757125 0.17425537109375 0.15240478515625 -0.12530517578125826 +1.75725 0.17913818359375 0.15667724609375 -0.12530517578125826 +1.7573750000000002 0.18402099609375 0.16094970703125 -0.12530517578125826 +1.7575 0.18402099609375 0.16094970703125 -0.12530517578125826 +1.757625 0.188873291015625 0.165191650390625 -0.12530517578125826 +1.7577500000000002 0.188873291015625 0.165191650390625 -0.12530517578125826 +1.757875 0.1937255859375 0.16943359375 -0.12530517578125826 +1.758 0.19854736328125 0.17364501953125 -0.12530517578125826 +1.758125 0.19854736328125 0.17364501953125 -0.12530517578125826 +1.75825 0.203338623046875 0.177825927734375 -0.12530517578125826 +1.758375 0.203338623046875 0.177825927734375 -0.12530517578125826 +1.7585 0.208099365234375 0.1820068359375 -0.12530517578125826 +1.758625 0.212860107421875 0.1861572265625 -0.12530517578125826 +1.75875 0.212860107421875 0.1861572265625 -0.12530517578125826 +1.758875 0.21759033203125 0.1903076171875 -0.12530517578125826 +1.7590000000000002 0.21759033203125 0.1903076171875 -0.12530517578125826 +1.759125 0.2222900390625 0.194427490234375 -0.12530517578125826 +1.75925 0.226959228515625 0.198486328125 -0.12530517578125826 +1.7593750000000002 0.226959228515625 0.198486328125 -0.12530517578125826 +1.7595 0.231597900390625 0.20257568359375 -0.12530517578125826 +1.759625 0.231597900390625 0.20257568359375 -0.12530517578125826 +1.7597500000000002 0.236236572265625 0.206634521484375 -0.12530517578125826 +1.759875 0.2408447265625 0.21063232421875 -0.12530517578125826 +1.76 0.2408447265625 0.119537353515625 -0.5035827636718825 +1.760125 0.24542236328125 0.121795654296875 -0.5035827636718825 +1.76025 0.24542236328125 0.121795654296875 -0.5035827636718825 +1.760375 0.249969482421875 0.124053955078125 -0.5035827636718825 +1.7605 0.25445556640625 0.126312255859375 -0.5035827636718825 +1.760625 0.25445556640625 0.126312255859375 -0.5035827636718825 +1.76075 0.25897216796875 0.1285400390625 -0.5035827636718825 +1.760875 0.25897216796875 0.1285400390625 -0.5035827636718825 +1.7610000000000002 0.263427734375 0.1307373046875 -0.5035827636718825 +1.761125 0.267852783203125 0.132965087890625 -0.5035827636718825 +1.76125 0.267852783203125 0.132965087890625 -0.5035827636718825 +1.7613750000000002 0.27227783203125 0.1351318359375 -0.5035827636718825 +1.7615 0.27227783203125 0.1351318359375 -0.5035827636718825 +1.761625 0.276641845703125 0.137298583984375 -0.5035827636718825 +1.76175 0.280975341796875 0.13946533203125 -0.5035827636718825 +1.761875 0.280975341796875 0.13946533203125 -0.5035827636718825 +1.762 0.285308837890625 0.1416015625 -0.5035827636718825 +1.762125 0.285308837890625 0.1416015625 -0.5035827636718825 +1.76225 0.289581298828125 0.14373779296875 -0.5035827636718825 +1.762375 0.2938232421875 0.145843505859375 -0.5035827636718825 +1.7625 0.2938232421875 0.145843505859375 -0.5035827636718825 +1.762625 0.298065185546875 0.14794921875 -0.5035827636718825 +1.76275 0.298065185546875 0.14794921875 -0.5035827636718825 +1.762875 0.30224609375 0.1500244140625 -0.5035827636718825 +1.7630000000000002 0.306396484375 0.152069091796875 -0.5035827636718825 +1.763125 0.306396484375 0.152069091796875 -0.5035827636718825 +1.76325 0.310516357421875 0.15411376953125 -0.5035827636718825 +1.7633750000000002 0.310516357421875 0.15411376953125 -0.5035827636718825 +1.7635 0.314605712890625 0.156158447265625 -0.5035827636718825 +1.763625 0.31866455078125 0.158172607421875 -0.5035827636718825 +1.76375 0.31866455078125 0.158172607421875 -0.5035827636718825 +1.763875 0.322662353515625 0.16015625 -0.5035827636718825 +1.764 0.322662353515625 0.16015625 -0.5035827636718825 +1.764125 0.32666015625 0.162139892578125 -0.5035827636718825 +1.76425 0.330596923828125 0.164093017578125 -0.5035827636718825 +1.764375 0.330596923828125 0.164093017578125 -0.5035827636718825 +1.7645 0.334503173828125 0.166046142578125 -0.5035827636718825 +1.764625 0.334503173828125 0.166046142578125 -0.5035827636718825 +1.76475 0.33837890625 0.16796875 -0.5035827636718825 +1.764875 0.34222412109375 0.16986083984375 -0.5035827636718825 +1.7650000000000002 0.34222412109375 0.16986083984375 -0.5035827636718825 +1.765125 0.34600830078125 0.1717529296875 -0.5035827636718825 +1.76525 0.34600830078125 0.1717529296875 -0.5035827636718825 +1.7653750000000002 0.349761962890625 0.173614501953125 -0.5035827636718825 +1.7655 0.353485107421875 0.175445556640625 -0.5035827636718825 +1.765625 0.353485107421875 0.175445556640625 -0.5035827636718825 +1.76575 0.357177734375 0.177276611328125 -0.5035827636718825 +1.765875 0.357177734375 0.177276611328125 -0.5035827636718825 +1.766 0.360809326171875 0.1790771484375 -0.5035827636718825 +1.766125 0.36444091796875 0.180877685546875 -0.5035827636718825 +1.76625 0.36444091796875 0.180877685546875 -0.5035827636718825 +1.766375 0.36798095703125 0.182647705078125 -0.5035827636718825 +1.7665 0.36798095703125 0.182647705078125 -0.5035827636718825 +1.7666250000000002 0.37152099609375 0.18438720703125 -0.5035827636718825 +1.76675 0.375 0.186126708984375 -0.5035827636718825 +1.766875 0.375 0.186126708984375 -0.5035827636718825 +1.7670000000000002 0.378448486328125 0.187835693359375 -0.5035827636718825 +1.767125 0.378448486328125 0.187835693359375 -0.5035827636718825 +1.76725 0.3818359375 0.18951416015625 -0.5035827636718825 +1.7673750000000002 0.38519287109375 0.191192626953125 -0.5035827636718825 +1.7675 0.38519287109375 0.191192626953125 -0.5035827636718825 +1.767625 0.388519287109375 0.192840576171875 -0.5035827636718825 +1.76775 0.388519287109375 0.192840576171875 -0.5035827636718825 +1.767875 0.39178466796875 0.1944580078125 -0.5035827636718825 +1.768 0.39501953125 0.196075439453125 -0.5035827636718825 +1.768125 0.39501953125 0.196075439453125 -0.5035827636718825 +1.76825 0.398193359375 0.1976318359375 -0.5035827636718825 +1.768375 0.398193359375 0.1976318359375 -0.5035827636718825 +1.7685 0.401336669921875 0.19921875 -0.5035827636718825 +1.7686250000000002 0.404449462890625 0.20074462890625 -0.5035827636718825 +1.76875 0.404449462890625 0.20074462890625 -0.5035827636718825 +1.768875 0.407501220703125 0.2022705078125 -0.5035827636718825 +1.7690000000000002 0.407501220703125 0.2022705078125 -0.5035827636718825 +1.769125 0.4105224609375 0.203765869140625 -0.5035827636718825 +1.76925 0.413482666015625 0.205230712890625 -0.5035827636718825 +1.7693750000000002 0.413482666015625 0.205230712890625 -0.5035827636718825 +1.7695 0.416412353515625 0.206695556640625 -0.5035827636718825 +1.769625 0.416412353515625 0.206695556640625 -0.5035827636718825 +1.76975 0.419281005859375 0.208099365234375 -0.5035827636718825 +1.769875 0.422119140625 0.209503173828125 -0.5035827636718825 +1.77 0.422119140625 0.209503173828125 -0.5035827636718825 +1.770125 0.424896240234375 0.210906982421875 -0.5035827636718825 +1.77025 0.424896240234375 0.210906982421875 -0.5035827636718825 +1.770375 0.4276123046875 0.212249755859375 -0.5035827636718825 +1.7705 0.4302978515625 0.213592529296875 -0.5035827636718825 +1.7706250000000002 0.4302978515625 0.213592529296875 -0.5035827636718825 +1.77075 0.432952880859375 0.21490478515625 -0.5035827636718825 +1.770875 0.432952880859375 0.21490478515625 -0.5035827636718825 +1.7710000000000002 0.435546875 0.2161865234375 -0.5035827636718825 +1.771125 0.438079833984375 0.217437744140625 -0.5035827636718825 +1.77125 0.438079833984375 0.217437744140625 -0.5035827636718825 +1.7713750000000002 0.440582275390625 0.21868896484375 -0.5035827636718825 +1.7715 0.440582275390625 0.21868896484375 -0.5035827636718825 +1.771625 0.44305419921875 0.21990966796875 -0.5035827636718825 +1.77175 0.4454345703125 0.221099853515625 -0.5035827636718825 +1.771875 0.4454345703125 0.221099853515625 -0.5035827636718825 +1.772 0.447784423828125 0.222259521484375 -0.5035827636718825 +1.772125 0.447784423828125 0.222259521484375 -0.5035827636718825 +1.77225 0.450103759765625 0.223388671875 -0.5035827636718825 +1.772375 0.452362060546875 0.224517822265625 -0.5035827636718825 +1.7725 0.452362060546875 0.224517822265625 -0.5035827636718825 +1.7726250000000002 0.454559326171875 0.225616455078125 -0.5035827636718825 +1.77275 0.454559326171875 0.225616455078125 -0.5035827636718825 +1.772875 0.45672607421875 0.2266845703125 -0.5035827636718825 +1.7730000000000002 0.458831787109375 0.22772216796875 -0.5035827636718825 +1.773125 0.458831787109375 0.22772216796875 -0.5035827636718825 +1.77325 0.46087646484375 0.228759765625 -0.5035827636718825 +1.7733750000000002 0.46087646484375 0.228759765625 -0.5035827636718825 +1.7735 0.462890625 0.229736328125 -0.5035827636718825 +1.773625 0.464813232421875 0.230712890625 -0.5035827636718825 +1.77375 0.464813232421875 0.230712890625 -0.5035827636718825 +1.773875 0.46673583984375 0.231658935546875 -0.5035827636718825 +1.774 0.46673583984375 0.231658935546875 -0.5035827636718825 +1.774125 0.46856689453125 0.232574462890625 -0.5035827636718825 +1.77425 0.470367431640625 0.23345947265625 -0.5035827636718825 +1.774375 0.470367431640625 0.23345947265625 -0.5035827636718825 +1.7745 0.472137451171875 0.234344482421875 -0.5035827636718825 +1.7746250000000002 0.472137451171875 0.234344482421875 -0.5035827636718825 +1.77475 0.47381591796875 0.23516845703125 -0.5035827636718825 +1.774875 0.4754638671875 0.235992431640625 -0.5035827636718825 +1.7750000000000002 0.4754638671875 0.235992431640625 -0.5035827636718825 +1.775125 0.47705078125 0.236785888671875 -0.5035827636718825 +1.77525 0.47705078125 0.236785888671875 -0.5035827636718825 +1.7753750000000002 0.478607177734375 0.237548828125 -0.5035827636718825 +1.7755 0.480072021484375 0.23828125 -0.5035827636718825 +1.775625 0.480072021484375 0.23828125 -0.5035827636718825 +1.77575 0.48150634765625 0.238983154296875 -0.5035827636718825 +1.775875 0.48150634765625 0.238983154296875 -0.5035827636718825 +1.776 0.48291015625 0.23968505859375 -0.5035827636718825 +1.776125 0.484222412109375 0.2403564453125 -0.5035827636718825 +1.77625 0.484222412109375 0.2403564453125 -0.5035827636718825 +1.776375 0.485504150390625 0.240966796875 -0.5035827636718825 +1.7765 0.485504150390625 0.240966796875 -0.5035827636718825 +1.7766250000000002 0.486724853515625 0.2415771484375 -0.5035827636718825 +1.77675 0.487884521484375 0.242156982421875 -0.5035827636718825 +1.776875 0.487884521484375 0.242156982421875 -0.5035827636718825 +1.7770000000000002 0.489013671875 0.242706298828125 -0.5035827636718825 +1.777125 0.489013671875 0.242706298828125 -0.5035827636718825 +1.77725 0.490081787109375 0.243255615234375 -0.5035827636718825 +1.777375 0.4910888671875 0.243743896484375 -0.5035827636718825 +1.7775 0.4910888671875 0.243743896484375 -0.5035827636718825 +1.777625 0.492034912109375 0.244232177734375 -0.5035827636718825 +1.77775 0.492034912109375 0.244232177734375 -0.5035827636718825 +1.777875 0.492950439453125 0.244659423828125 -0.5035827636718825 +1.778 0.4937744140625 0.245086669921875 -0.5035827636718825 +1.778125 0.4937744140625 0.245086669921875 -0.5035827636718825 +1.77825 0.49456787109375 0.2454833984375 -0.5035827636718825 +1.778375 0.49456787109375 0.2454833984375 -0.5035827636718825 +1.7785 0.49530029296875 0.245849609375 -0.5035827636718825 +1.7786250000000002 0.496002197265625 0.246185302734375 -0.5035827636718825 +1.77875 0.496002197265625 0.246185302734375 -0.5035827636718825 +1.778875 0.496612548828125 0.246490478515625 -0.5035827636718825 +1.7790000000000002 0.496612548828125 0.246490478515625 -0.5035827636718825 +1.779125 0.4971923828125 0.246795654296875 -0.5035827636718825 +1.77925 0.497711181640625 0.247039794921875 -0.5035827636718825 +1.779375 0.497711181640625 0.247039794921875 -0.5035827636718825 +1.7795 0.498199462890625 0.247283935546875 -0.5035827636718825 +1.779625 0.498199462890625 0.247283935546875 -0.5035827636718825 +1.77975 0.49859619140625 0.247467041015625 -0.5035827636718825 +1.779875 0.49896240234375 0.247650146484375 -0.5035827636718825 +1.78 0.49896240234375 0.247650146484375 -0.5035827636718825 +1.780125 0.499267578125 0.247802734375 -0.5035827636718825 +1.78025 0.499267578125 0.247802734375 -0.5035827636718825 +1.780375 0.49951171875 0.2479248046875 -0.5035827636718825 +1.7805 0.49969482421875 0.248016357421875 -0.5035827636718825 +1.7806250000000002 0.49969482421875 0.248016357421875 -0.5035827636718825 +1.78075 0.49981689453125 0.248077392578125 -0.5035827636718825 +1.780875 0.49981689453125 0.248077392578125 -0.5035827636718825 +1.7810000000000002 0.499908447265625 0.248138427734375 -0.5035827636718825 +1.781125 0.49993896484375 0.248138427734375 -0.5035827636718825 +1.78125 0.49993896484375 0.248138427734375 -0.5035827636718825 +1.781375 0.499908447265625 0.248138427734375 -0.5035827636718825 +1.7815 0.499908447265625 0.248138427734375 -0.5035827636718825 +1.781625 0.49981689453125 0.248077392578125 -0.5035827636718825 +1.78175 0.49969482421875 0.248016357421875 -0.5035827636718825 +1.781875 0.49969482421875 0.248016357421875 -0.5035827636718825 +1.782 0.49951171875 0.2479248046875 -0.5035827636718825 +1.782125 0.49951171875 0.2479248046875 -0.5035827636718825 +1.7822500000000002 0.499267578125 0.247802734375 -0.5035827636718825 +1.782375 0.49896240234375 0.247650146484375 -0.5035827636718825 +1.7825 0.49896240234375 0.247650146484375 -0.5035827636718825 +1.7826250000000002 0.49859619140625 0.247467041015625 -0.5035827636718825 +1.78275 0.49859619140625 0.247467041015625 -0.5035827636718825 +1.782875 0.498199462890625 0.247283935546875 -0.5035827636718825 +1.7830000000000002 0.497711181640625 0.247039794921875 -0.5035827636718825 +1.783125 0.497711181640625 0.247039794921875 -0.5035827636718825 +1.78325 0.4971923828125 0.246795654296875 -0.5035827636718825 +1.783375 0.4971923828125 0.246795654296875 -0.5035827636718825 +1.7835 0.496612548828125 0.246490478515625 -0.5035827636718825 +1.783625 0.496002197265625 0.246185302734375 -0.5035827636718825 +1.78375 0.496002197265625 0.246185302734375 -0.5035827636718825 +1.783875 0.49530029296875 0.245849609375 -0.5035827636718825 +1.784 0.49530029296875 0.245849609375 -0.5035827636718825 +1.784125 0.49456787109375 0.2454833984375 -0.5035827636718825 +1.7842500000000002 0.4937744140625 0.245086669921875 -0.5035827636718825 +1.784375 0.4937744140625 0.245086669921875 -0.5035827636718825 +1.7845 0.492950439453125 0.244659423828125 -0.5035827636718825 +1.7846250000000002 0.492950439453125 0.244659423828125 -0.5035827636718825 +1.78475 0.492034912109375 0.244232177734375 -0.5035827636718825 +1.784875 0.4910888671875 0.243743896484375 -0.5035827636718825 +1.7850000000000002 0.4910888671875 0.243743896484375 -0.5035827636718825 +1.785125 0.490081787109375 0.243255615234375 -0.5035827636718825 +1.78525 0.490081787109375 0.243255615234375 -0.5035827636718825 +1.785375 0.489013671875 0.242706298828125 -0.5035827636718825 +1.7855 0.487884521484375 0.242156982421875 -0.5035827636718825 +1.785625 0.487884521484375 0.242156982421875 -0.5035827636718825 +1.78575 0.486724853515625 0.2415771484375 -0.5035827636718825 +1.785875 0.486724853515625 0.2415771484375 -0.5035827636718825 +1.786 0.485504150390625 0.240966796875 -0.5035827636718825 +1.786125 0.484222412109375 0.2403564453125 -0.5035827636718825 +1.7862500000000002 0.484222412109375 0.2403564453125 -0.5035827636718825 +1.786375 0.48291015625 0.23968505859375 -0.5035827636718825 +1.7865 0.48291015625 0.23968505859375 -0.5035827636718825 +1.7866250000000002 0.48150634765625 0.238983154296875 -0.5035827636718825 +1.78675 0.480072021484375 0.23828125 -0.5035827636718825 +1.786875 0.480072021484375 0.23828125 -0.5035827636718825 +1.7870000000000002 0.478607177734375 0.237548828125 -0.5035827636718825 +1.787125 0.478607177734375 0.237548828125 -0.5035827636718825 +1.78725 0.47705078125 0.236785888671875 -0.5035827636718825 +1.787375 0.4754638671875 0.235992431640625 -0.5035827636718825 +1.7875 0.4754638671875 0.235992431640625 -0.5035827636718825 +1.787625 0.47381591796875 0.23516845703125 -0.5035827636718825 +1.78775 0.47381591796875 0.23516845703125 -0.5035827636718825 +1.787875 0.472137451171875 0.234344482421875 -0.5035827636718825 +1.788 0.470367431640625 0.23345947265625 -0.5035827636718825 +1.788125 0.470367431640625 0.23345947265625 -0.5035827636718825 +1.7882500000000002 0.46856689453125 0.232574462890625 -0.5035827636718825 +1.788375 0.46856689453125 0.232574462890625 -0.5035827636718825 +1.7885 0.46673583984375 0.231658935546875 -0.5035827636718825 +1.7886250000000002 0.464813232421875 0.230712890625 -0.5035827636718825 +1.78875 0.464813232421875 0.230712890625 -0.5035827636718825 +1.788875 0.462890625 0.229736328125 -0.5035827636718825 +1.7890000000000002 0.462890625 0.229736328125 -0.5035827636718825 +1.789125 0.46087646484375 0.228759765625 -0.5035827636718825 +1.78925 0.458831787109375 0.22772216796875 -0.5035827636718825 +1.789375 0.458831787109375 0.22772216796875 -0.5035827636718825 +1.7895 0.45672607421875 0.2266845703125 -0.5035827636718825 +1.789625 0.45672607421875 0.2266845703125 -0.5035827636718825 +1.78975 0.454559326171875 0.225616455078125 -0.5035827636718825 +1.789875 0.452362060546875 0.224517822265625 -0.5035827636718825 +1.79 0.452362060546875 0.224517822265625 -0.5035827636718825 +1.790125 0.450103759765625 0.223388671875 -0.5035827636718825 +1.7902500000000002 0.450103759765625 0.223388671875 -0.5035827636718825 +1.790375 0.447784423828125 0.222259521484375 -0.5035827636718825 +1.7905 0.4454345703125 0.221099853515625 -0.5035827636718825 +1.7906250000000002 0.4454345703125 0.221099853515625 -0.5035827636718825 +1.79075 0.44305419921875 0.21990966796875 -0.5035827636718825 +1.790875 0.44305419921875 0.21990966796875 -0.5035827636718825 +1.7910000000000002 0.440582275390625 0.21868896484375 -0.5035827636718825 +1.791125 0.438079833984375 0.217437744140625 -0.5035827636718825 +1.79125 0.438079833984375 0.217437744140625 -0.5035827636718825 +1.791375 0.435546875 0.2161865234375 -0.5035827636718825 +1.7915 0.435546875 0.2161865234375 -0.5035827636718825 +1.791625 0.432952880859375 0.21490478515625 -0.5035827636718825 +1.79175 0.4302978515625 0.213592529296875 -0.5035827636718825 +1.791875 0.4302978515625 0.213592529296875 -0.5035827636718825 +1.792 0.4276123046875 0.0848388671875 -0.8015075683593804 +1.792125 0.4276123046875 0.0848388671875 -0.8015075683593804 +1.7922500000000002 0.424896240234375 0.08428955078125 -0.8015075683593804 +1.792375 0.422119140625 0.083740234375 -0.8015075683593804 +1.7925 0.422119140625 0.083740234375 -0.8015075683593804 +1.7926250000000002 0.419281005859375 0.083160400390625 -0.8015075683593804 +1.79275 0.419281005859375 0.083160400390625 -0.8015075683593804 +1.792875 0.416412353515625 0.082611083984375 -0.8015075683593804 +1.793 0.413482666015625 0.08203125 -0.8015075683593804 +1.793125 0.413482666015625 0.08203125 -0.8015075683593804 +1.79325 0.4105224609375 0.081451416015625 -0.8015075683593804 +1.793375 0.4105224609375 0.081451416015625 -0.8015075683593804 +1.7935 0.407501220703125 0.080841064453125 -0.8015075683593804 +1.793625 0.404449462890625 0.080230712890625 -0.8015075683593804 +1.79375 0.404449462890625 0.080230712890625 -0.8015075683593804 +1.793875 0.401336669921875 0.079620361328125 -0.8015075683593804 +1.794 0.401336669921875 0.079620361328125 -0.8015075683593804 +1.794125 0.398193359375 0.0789794921875 -0.8015075683593804 +1.7942500000000002 0.39501953125 0.078369140625 -0.8015075683593804 +1.794375 0.39501953125 0.078369140625 -0.8015075683593804 +1.7945 0.39178466796875 0.077728271484375 -0.8015075683593804 +1.7946250000000002 0.39178466796875 0.077728271484375 -0.8015075683593804 +1.79475 0.388519287109375 0.077056884765625 -0.8015075683593804 +1.794875 0.38519287109375 0.076416015625 -0.8015075683593804 +1.795 0.38519287109375 0.076416015625 -0.8015075683593804 +1.795125 0.3818359375 0.07574462890625 -0.8015075683593804 +1.79525 0.3818359375 0.07574462890625 -0.8015075683593804 +1.795375 0.378448486328125 0.0750732421875 -0.8015075683593804 +1.7955 0.375 0.07440185546875 -0.8015075683593804 +1.795625 0.375 0.07440185546875 -0.8015075683593804 +1.79575 0.37152099609375 0.073699951171875 -0.8015075683593804 +1.795875 0.37152099609375 0.073699951171875 -0.8015075683593804 +1.796 0.36798095703125 0.072998046875 -0.8015075683593804 +1.796125 0.36444091796875 0.072296142578125 -0.8015075683593804 +1.7962500000000002 0.36444091796875 0.072296142578125 -0.8015075683593804 +1.796375 0.360809326171875 0.071563720703125 -0.8015075683593804 +1.7965 0.360809326171875 0.071563720703125 -0.8015075683593804 +1.7966250000000002 0.357177734375 0.07086181640625 -0.8015075683593804 +1.79675 0.353485107421875 0.07012939453125 -0.8015075683593804 +1.796875 0.353485107421875 0.07012939453125 -0.8015075683593804 +1.797 0.349761962890625 0.06939697265625 -0.8015075683593804 +1.797125 0.349761962890625 0.06939697265625 -0.8015075683593804 +1.79725 0.34600830078125 0.068634033203125 -0.8015075683593804 +1.797375 0.34222412109375 0.06787109375 -0.8015075683593804 +1.7975 0.34222412109375 0.06787109375 -0.8015075683593804 +1.797625 0.33837890625 0.067138671875 -0.8015075683593804 +1.79775 0.33837890625 0.067138671875 -0.8015075683593804 +1.7978750000000002 0.334503173828125 0.06634521484375 -0.8015075683593804 +1.798 0.330596923828125 0.065582275390625 -0.8015075683593804 +1.798125 0.330596923828125 0.065582275390625 -0.8015075683593804 +1.7982500000000002 0.32666015625 0.064788818359375 -0.8015075683593804 +1.798375 0.32666015625 0.064788818359375 -0.8015075683593804 +1.7985 0.322662353515625 0.063995361328125 -0.8015075683593804 +1.7986250000000002 0.31866455078125 0.063201904296875 -0.8015075683593804 +1.79875 0.31866455078125 0.063201904296875 -0.8015075683593804 +1.798875 0.314605712890625 0.062408447265625 -0.8015075683593804 +1.799 0.314605712890625 0.062408447265625 -0.8015075683593804 +1.799125 0.310516357421875 0.06158447265625 -0.8015075683593804 +1.79925 0.306396484375 0.060791015625 -0.8015075683593804 +1.799375 0.306396484375 0.060791015625 -0.8015075683593804 +1.7995 0.30224609375 0.059967041015625 -0.8015075683593804 +1.799625 0.30224609375 0.059967041015625 -0.8015075683593804 +1.79975 0.298065185546875 0.059112548828125 -0.8015075683593804 +1.7998750000000002 0.2938232421875 0.05828857421875 -0.8015075683593804 +1.8 0.2938232421875 0.05828857421875 -0.8015075683593804 +1.800125 0.289581298828125 0.05743408203125 -0.8015075683593804 +1.8002500000000002 0.289581298828125 0.05743408203125 -0.8015075683593804 +1.800375 0.285308837890625 0.05657958984375 -0.8015075683593804 +1.8005 0.280975341796875 0.05572509765625 -0.8015075683593804 +1.8006250000000002 0.280975341796875 0.05572509765625 -0.8015075683593804 +1.80075 0.276641845703125 0.05487060546875 -0.8015075683593804 +1.800875 0.276641845703125 0.05487060546875 -0.8015075683593804 +1.801 0.27227783203125 0.05401611328125 -0.8015075683593804 +1.801125 0.267852783203125 0.053131103515625 -0.8015075683593804 +1.80125 0.267852783203125 0.053131103515625 -0.8015075683593804 +1.801375 0.263427734375 0.05224609375 -0.8015075683593804 +1.8015 0.263427734375 0.05224609375 -0.8015075683593804 +1.801625 0.25897216796875 0.051361083984375 -0.8015075683593804 +1.80175 0.25445556640625 0.05047607421875 -0.8015075683593804 +1.80187500000000016 0.25445556640625 0.05047607421875 -0.8015075683593804 +1.802 0.249969482421875 0.049591064453125 -0.8015075683593804 +1.802125 0.249969482421875 0.049591064453125 -0.8015075683593804 +1.80225000000000016 0.24542236328125 0.048675537109375 -0.8015075683593804 +1.802375 0.2408447265625 0.047760009765625 -0.8015075683593804 +1.8025 0.2408447265625 0.047760009765625 -0.8015075683593804 +1.80262500000000016 0.236236572265625 0.046844482421875 -0.8015075683593804 +1.80275 0.236236572265625 0.046844482421875 -0.8015075683593804 +1.802875 0.231597900390625 0.045928955078125 -0.8015075683593804 +1.803 0.226959228515625 0.045013427734375 -0.8015075683593804 +1.803125 0.226959228515625 0.045013427734375 -0.8015075683593804 +1.80325 0.2222900390625 0.044097900390625 -0.8015075683593804 +1.803375 0.2222900390625 0.044097900390625 -0.8015075683593804 +1.8035 0.21759033203125 0.04315185546875 -0.8015075683593804 +1.803625 0.212860107421875 0.042205810546875 -0.8015075683593804 +1.80375 0.212860107421875 0.042205810546875 -0.8015075683593804 +1.80387500000000016 0.208099365234375 0.041290283203125 -0.8015075683593804 +1.804 0.208099365234375 0.041290283203125 -0.8015075683593804 +1.804125 0.203338623046875 0.04034423828125 -0.8015075683593804 +1.80425000000000016 0.19854736328125 0.03936767578125 -0.8015075683593804 +1.804375 0.19854736328125 0.03936767578125 -0.8015075683593804 +1.8045 0.1937255859375 0.038421630859375 -0.8015075683593804 +1.804625000000000256 0.1937255859375 0.038421630859375 -0.8015075683593804 +1.80475 0.188873291015625 0.0374755859375 -0.8015075683593804 +1.804875 0.18402099609375 0.0364990234375 -0.8015075683593804 +1.805 0.18402099609375 0.0364990234375 -0.8015075683593804 +1.805125 0.17913818359375 0.0355224609375 -0.8015075683593804 +1.80525 0.17913818359375 0.0355224609375 -0.8015075683593804 +1.805375 0.17425537109375 0.0345458984375 -0.8015075683593804 +1.8055 0.169342041015625 0.0335693359375 -0.8015075683593804 +1.805625 0.169342041015625 0.0335693359375 -0.8015075683593804 +1.80575 0.164398193359375 0.0325927734375 -0.8015075683593804 +1.80587500000000016 0.164398193359375 0.0325927734375 -0.8015075683593804 +1.806 0.159454345703125 0.0316162109375 -0.8015075683593804 +1.806125 0.15447998046875 0.0306396484375 -0.8015075683593804 +1.80625000000000016 0.15447998046875 0.0306396484375 -0.8015075683593804 +1.806375 0.14947509765625 0.029632568359375 -0.8015075683593804 +1.8065 0.14947509765625 0.029632568359375 -0.8015075683593804 +1.806625000000000256 0.14447021484375 0.028656005859375 -0.8015075683593804 +1.80675 0.13946533203125 0.02764892578125 -0.8015075683593804 +1.806875 0.13946533203125 0.02764892578125 -0.8015075683593804 +1.807 0.134429931640625 0.02667236328125 -0.8015075683593804 +1.807125 0.134429931640625 0.02667236328125 -0.8015075683593804 +1.80725 0.129364013671875 0.025665283203125 -0.8015075683593804 +1.807375 0.124298095703125 0.024658203125 -0.8015075683593804 +1.8075 0.124298095703125 0.024658203125 -0.8015075683593804 +1.807625 0.119232177734375 0.023651123046875 -0.8015075683593804 +1.80775 0.119232177734375 0.023651123046875 -0.8015075683593804 +1.80787500000000016 0.1141357421875 0.02264404296875 -0.8015075683593804 +1.808 0.109039306640625 0.0216064453125 -0.8015075683593804 +1.808125 0.109039306640625 0.0216064453125 -0.8015075683593804 +1.80825000000000016 0.103912353515625 0.020599365234375 -0.8015075683593804 +1.808375 0.103912353515625 0.020599365234375 -0.8015075683593804 +1.8085 0.098785400390625 0.01959228515625 -0.8015075683593804 +1.808625 0.093658447265625 0.0185546875 -0.8015075683593804 +1.80875 0.093658447265625 0.0185546875 -0.8015075683593804 +1.808875 0.0885009765625 0.017547607421875 -0.8015075683593804 +1.809 0.0885009765625 0.017547607421875 -0.8015075683593804 +1.809125 0.083343505859375 0.01654052734375 -0.8015075683593804 +1.80925 0.07818603515625 0.0155029296875 -0.8015075683593804 +1.809375 0.07818603515625 0.0155029296875 -0.8015075683593804 +1.8095 0.072998046875 0.01446533203125 -0.8015075683593804 +1.809625 0.072998046875 0.01446533203125 -0.8015075683593804 +1.80975 0.06781005859375 0.013458251953125 -0.8015075683593804 +1.80987500000000016 0.0626220703125 0.012420654296875 -0.8015075683593804 +1.81 0.0626220703125 0.012420654296875 -0.8015075683593804 +1.810125 0.05743408203125 0.011383056640625 -0.8015075683593804 +1.81025000000000016 0.05743408203125 0.011383056640625 -0.8015075683593804 +1.810375 0.05224609375 0.010345458984375 -0.8015075683593804 +1.8105 0.047027587890625 0.009307861328125 -0.8015075683593804 +1.810625 0.047027587890625 0.009307861328125 -0.8015075683593804 +1.81075 0.04180908203125 0.008270263671875 -0.8015075683593804 +1.810875 0.04180908203125 0.008270263671875 -0.8015075683593804 +1.811 0.036590576171875 0.007232666015625 -0.8015075683593804 +1.811125 0.0313720703125 0.0062255859375 -0.8015075683593804 +1.81125 0.0313720703125 0.0062255859375 -0.8015075683593804 +1.811375 0.026123046875 0.00518798828125 -0.8015075683593804 +1.8115 0.026123046875 0.00518798828125 -0.8015075683593804 +1.811625 0.020904541015625 0.004150390625 -0.8015075683593804 +1.81175 0.01568603515625 0.00311279296875 -0.8015075683593804 +1.81187500000000016 0.01568603515625 0.00311279296875 -0.8015075683593804 +1.812 0.01043701171875 0.0020751953125 -0.8015075683593804 +1.812125 0.01043701171875 0.0020751953125 -0.8015075683593804 +1.81225000000000016 0.005218505859375 0.00103759765625 -0.8015075683593804 +1.812375 0.0 0.0 -0.8015075683593804 +1.8125 0.0 0.0 -0.8015075683593804 +1.812625 -0.005218505859375 -0.00103759765625 -0.8015075683593804 +1.81275 -0.005218505859375 -0.00103759765625 -0.8015075683593804 +1.812875 -0.01043701171875 -0.0020751953125 -0.8015075683593804 +1.813 -0.01568603515625 -0.00311279296875 -0.8015075683593804 +1.813125 -0.01568603515625 -0.00311279296875 -0.8015075683593804 +1.81325 -0.020904541015625 -0.004150390625 -0.8015075683593804 +1.813375 -0.020904541015625 -0.004150390625 -0.8015075683593804 +1.81350000000000016 -0.026123046875 -0.00518798828125 -0.8015075683593804 +1.813625 -0.0313720703125 -0.0062255859375 -0.8015075683593804 +1.81375 -0.0313720703125 -0.0062255859375 -0.8015075683593804 +1.81387500000000016 -0.036590576171875 -0.007232666015625 -0.8015075683593804 +1.814 -0.036590576171875 -0.007232666015625 -0.8015075683593804 +1.814125 -0.04180908203125 -0.008270263671875 -0.8015075683593804 +1.81425000000000016 -0.047027587890625 -0.009307861328125 -0.8015075683593804 +1.814375 -0.047027587890625 -0.009307861328125 -0.8015075683593804 +1.8145 -0.05224609375 -0.010345458984375 -0.8015075683593804 +1.814625 -0.05224609375 -0.010345458984375 -0.8015075683593804 +1.81475 -0.05743408203125 -0.011383056640625 -0.8015075683593804 +1.814875 -0.0626220703125 -0.012420654296875 -0.8015075683593804 +1.815 -0.0626220703125 -0.012420654296875 -0.8015075683593804 +1.815125 -0.06781005859375 -0.013458251953125 -0.8015075683593804 +1.81525 -0.06781005859375 -0.013458251953125 -0.8015075683593804 +1.815375 -0.072998046875 -0.01446533203125 -0.8015075683593804 +1.81550000000000016 -0.07818603515625 -0.0155029296875 -0.8015075683593804 +1.815625 -0.07818603515625 -0.0155029296875 -0.8015075683593804 +1.81575 -0.083343505859375 -0.01654052734375 -0.8015075683593804 +1.81587500000000016 -0.083343505859375 -0.01654052734375 -0.8015075683593804 +1.816 -0.0885009765625 -0.017547607421875 -0.8015075683593804 +1.816125 -0.093658447265625 -0.0185546875 -0.8015075683593804 +1.81625000000000016 -0.093658447265625 -0.0185546875 -0.8015075683593804 +1.816375 -0.098785400390625 -0.01959228515625 -0.8015075683593804 +1.8165 -0.098785400390625 -0.01959228515625 -0.8015075683593804 +1.816625 -0.103912353515625 -0.020599365234375 -0.8015075683593804 +1.81675 -0.109039306640625 -0.0216064453125 -0.8015075683593804 +1.816875 -0.109039306640625 -0.0216064453125 -0.8015075683593804 +1.817 -0.1141357421875 -0.02264404296875 -0.8015075683593804 +1.817125 -0.1141357421875 -0.02264404296875 -0.8015075683593804 +1.81725 -0.119232177734375 -0.023651123046875 -0.8015075683593804 +1.817375 -0.124298095703125 -0.024658203125 -0.8015075683593804 +1.81750000000000016 -0.124298095703125 -0.024658203125 -0.8015075683593804 +1.817625 -0.129364013671875 -0.025665283203125 -0.8015075683593804 +1.81775 -0.129364013671875 -0.025665283203125 -0.8015075683593804 +1.81787500000000016 -0.134429931640625 -0.02667236328125 -0.8015075683593804 +1.818 -0.13946533203125 -0.02764892578125 -0.8015075683593804 +1.818125 -0.13946533203125 -0.02764892578125 -0.8015075683593804 +1.81825000000000016 -0.14447021484375 -0.028656005859375 -0.8015075683593804 +1.818375 -0.14447021484375 -0.028656005859375 -0.8015075683593804 +1.8185 -0.14947509765625 -0.029632568359375 -0.8015075683593804 +1.818625 -0.15447998046875 -0.0306396484375 -0.8015075683593804 +1.81875 -0.15447998046875 -0.0306396484375 -0.8015075683593804 +1.818875 -0.159454345703125 -0.0316162109375 -0.8015075683593804 +1.819 -0.159454345703125 -0.0316162109375 -0.8015075683593804 +1.819125 -0.164398193359375 -0.0325927734375 -0.8015075683593804 +1.81925 -0.169342041015625 -0.0335693359375 -0.8015075683593804 +1.819375 -0.169342041015625 -0.0335693359375 -0.8015075683593804 +1.81950000000000016 -0.17425537109375 -0.0345458984375 -0.8015075683593804 +1.819625 -0.17425537109375 -0.0345458984375 -0.8015075683593804 +1.81975 -0.17913818359375 -0.0355224609375 -0.8015075683593804 +1.81987500000000016 -0.18402099609375 -0.0364990234375 -0.8015075683593804 +1.82 -0.18402099609375 -0.0364990234375 -0.8015075683593804 +1.820125 -0.188873291015625 -0.0374755859375 -0.8015075683593804 +1.820250000000000256 -0.188873291015625 -0.0374755859375 -0.8015075683593804 +1.820375 -0.1937255859375 -0.038421630859375 -0.8015075683593804 +1.8205 -0.19854736328125 -0.03936767578125 -0.8015075683593804 +1.820625 -0.19854736328125 -0.03936767578125 -0.8015075683593804 +1.82075 -0.203338623046875 -0.04034423828125 -0.8015075683593804 +1.820875 -0.203338623046875 -0.04034423828125 -0.8015075683593804 +1.821 -0.208099365234375 -0.041290283203125 -0.8015075683593804 +1.821125 -0.212860107421875 -0.042205810546875 -0.8015075683593804 +1.82125 -0.212860107421875 -0.042205810546875 -0.8015075683593804 +1.821375 -0.21759033203125 -0.04315185546875 -0.8015075683593804 +1.82150000000000016 -0.21759033203125 -0.04315185546875 -0.8015075683593804 +1.821625 -0.2222900390625 -0.044097900390625 -0.8015075683593804 +1.82175 -0.226959228515625 -0.045013427734375 -0.8015075683593804 +1.82187500000000016 -0.226959228515625 -0.045013427734375 -0.8015075683593804 +1.822 -0.231597900390625 -0.045928955078125 -0.8015075683593804 +1.822125 -0.231597900390625 -0.045928955078125 -0.8015075683593804 +1.822250000000000256 -0.236236572265625 -0.046844482421875 -0.8015075683593804 +1.822375 -0.2408447265625 -0.047760009765625 -0.8015075683593804 +1.8225 -0.2408447265625 -0.047760009765625 -0.8015075683593804 +1.822625 -0.24542236328125 -0.048675537109375 -0.8015075683593804 +1.82275 -0.24542236328125 -0.048675537109375 -0.8015075683593804 +1.822875 -0.249969482421875 -0.049591064453125 -0.8015075683593804 +1.823 -0.25445556640625 -0.05047607421875 -0.8015075683593804 +1.823125 -0.25445556640625 -0.05047607421875 -0.8015075683593804 +1.82325 -0.25897216796875 -0.051361083984375 -0.8015075683593804 +1.823375 -0.25897216796875 -0.051361083984375 -0.8015075683593804 +1.82350000000000016 -0.263427734375 -0.05224609375 -0.8015075683593804 +1.823625 -0.267852783203125 -0.053131103515625 -0.8015075683593804 +1.82375 -0.267852783203125 -0.053131103515625 -0.8015075683593804 +1.82387500000000016 -0.27227783203125 -0.05401611328125 -0.8015075683593804 +1.824 -0.27227783203125 -0.0076904296875 -0.9715881347656272 +1.824125 -0.276641845703125 -0.0078125 -0.9715881347656272 +1.82425 -0.280975341796875 -0.0079345703125 -0.9715881347656272 +1.824375 -0.280975341796875 -0.0079345703125 -0.9715881347656272 +1.8245 -0.285308837890625 -0.008056640625 -0.9715881347656272 +1.824625 -0.285308837890625 -0.008056640625 -0.9715881347656272 +1.82475 -0.289581298828125 -0.0081787109375 -0.9715881347656272 +1.824875 -0.2938232421875 -0.00830078125 -0.9715881347656272 +1.825 -0.2938232421875 -0.00830078125 -0.9715881347656272 +1.825125 -0.298065185546875 -0.0084228515625 -0.9715881347656272 +1.82525 -0.298065185546875 -0.0084228515625 -0.9715881347656272 +1.825375 -0.30224609375 -0.008544921875 -0.9715881347656272 +1.82550000000000016 -0.306396484375 -0.0086669921875 -0.9715881347656272 +1.825625 -0.306396484375 -0.0086669921875 -0.9715881347656272 +1.82575 -0.310516357421875 -0.0087890625 -0.9715881347656272 +1.82587500000000016 -0.310516357421875 -0.0087890625 -0.9715881347656272 +1.826 -0.314605712890625 -0.008880615234375 -0.9715881347656272 +1.826125 -0.31866455078125 -0.009002685546875 -0.9715881347656272 +1.82625 -0.31866455078125 -0.009002685546875 -0.9715881347656272 +1.826375 -0.322662353515625 -0.009124755859375 -0.9715881347656272 +1.8265 -0.322662353515625 -0.009124755859375 -0.9715881347656272 +1.826625 -0.32666015625 -0.009246826171875 -0.9715881347656272 +1.82675 -0.330596923828125 -0.00933837890625 -0.9715881347656272 +1.826875 -0.330596923828125 -0.00933837890625 -0.9715881347656272 +1.827 -0.334503173828125 -0.00946044921875 -0.9715881347656272 +1.827125 -0.334503173828125 -0.00946044921875 -0.9715881347656272 +1.82725 -0.33837890625 -0.00958251953125 -0.9715881347656272 +1.827375 -0.34222412109375 -0.009674072265625 -0.9715881347656272 +1.82750000000000016 -0.34222412109375 -0.009674072265625 -0.9715881347656272 +1.827625 -0.34600830078125 -0.009796142578125 -0.9715881347656272 +1.82775 -0.34600830078125 -0.009796142578125 -0.9715881347656272 +1.82787500000000016 -0.349761962890625 -0.0098876953125 -0.9715881347656272 +1.828 -0.353485107421875 -0.010009765625 -0.9715881347656272 +1.828125 -0.353485107421875 -0.010009765625 -0.9715881347656272 +1.82825 -0.357177734375 -0.010101318359375 -0.9715881347656272 +1.828375 -0.357177734375 -0.010101318359375 -0.9715881347656272 +1.8285 -0.360809326171875 -0.01019287109375 -0.9715881347656272 +1.828625 -0.36444091796875 -0.01031494140625 -0.9715881347656272 +1.82875 -0.36444091796875 -0.01031494140625 -0.9715881347656272 +1.828875 -0.36798095703125 -0.010406494140625 -0.9715881347656272 +1.829 -0.36798095703125 -0.010406494140625 -0.9715881347656272 +1.82912500000000016 -0.37152099609375 -0.010498046875 -0.9715881347656272 +1.82925 -0.375 -0.0106201171875 -0.9715881347656272 +1.829375 -0.375 -0.0106201171875 -0.9715881347656272 +1.82950000000000016 -0.378448486328125 -0.010711669921875 -0.9715881347656272 +1.829625 -0.378448486328125 -0.010711669921875 -0.9715881347656272 +1.82975 -0.3818359375 -0.01080322265625 -0.9715881347656272 +1.82987500000000016 -0.38519287109375 -0.010894775390625 -0.9715881347656272 +1.83 -0.38519287109375 -0.010894775390625 -0.9715881347656272 +1.830125 -0.388519287109375 -0.010986328125 -0.9715881347656272 +1.83025 -0.388519287109375 -0.010986328125 -0.9715881347656272 +1.830375 -0.39178466796875 -0.011077880859375 -0.9715881347656272 +1.8305 -0.39501953125 -0.01116943359375 -0.9715881347656272 +1.830625 -0.39501953125 -0.01116943359375 -0.9715881347656272 +1.83075 -0.398193359375 -0.011260986328125 -0.9715881347656272 +1.830875 -0.398193359375 -0.011260986328125 -0.9715881347656272 +1.831 -0.401336669921875 -0.0113525390625 -0.9715881347656272 +1.83112500000000016 -0.404449462890625 -0.011444091796875 -0.9715881347656272 +1.83125 -0.404449462890625 -0.011444091796875 -0.9715881347656272 +1.831375 -0.407501220703125 -0.01153564453125 -0.9715881347656272 +1.83150000000000016 -0.407501220703125 -0.01153564453125 -0.9715881347656272 +1.831625 -0.4105224609375 -0.0115966796875 -0.9715881347656272 +1.83175 -0.413482666015625 -0.011688232421875 -0.9715881347656272 +1.83187500000000016 -0.413482666015625 -0.011688232421875 -0.9715881347656272 +1.832 -0.416412353515625 -0.01177978515625 -0.9715881347656272 +1.832125 -0.416412353515625 -0.01177978515625 -0.9715881347656272 +1.83225 -0.419281005859375 -0.011871337890625 -0.9715881347656272 +1.832375 -0.422119140625 -0.011932373046875 -0.9715881347656272 +1.8325 -0.422119140625 -0.011932373046875 -0.9715881347656272 +1.832625 -0.424896240234375 -0.01202392578125 -0.9715881347656272 +1.83275 -0.424896240234375 -0.01202392578125 -0.9715881347656272 +1.832875 -0.4276123046875 -0.0120849609375 -0.9715881347656272 +1.833 -0.4302978515625 -0.012176513671875 -0.9715881347656272 +1.83312500000000016 -0.4302978515625 -0.012176513671875 -0.9715881347656272 +1.83325 -0.432952880859375 -0.012237548828125 -0.9715881347656272 +1.833375 -0.432952880859375 -0.012237548828125 -0.9715881347656272 +1.83350000000000016 -0.435546875 -0.0123291015625 -0.9715881347656272 +1.833625 -0.438079833984375 -0.01239013671875 -0.9715881347656272 +1.83375 -0.438079833984375 -0.01239013671875 -0.9715881347656272 +1.83387500000000016 -0.440582275390625 -0.012451171875 -0.9715881347656272 +1.834 -0.440582275390625 -0.012451171875 -0.9715881347656272 +1.834125 -0.44305419921875 -0.012542724609375 -0.9715881347656272 +1.83425 -0.4454345703125 -0.012603759765625 -0.9715881347656272 +1.834375 -0.4454345703125 -0.012603759765625 -0.9715881347656272 +1.8345 -0.447784423828125 -0.012664794921875 -0.9715881347656272 +1.834625 -0.447784423828125 -0.012664794921875 -0.9715881347656272 +1.83475 -0.450103759765625 -0.012725830078125 -0.9715881347656272 +1.834875 -0.452362060546875 -0.012786865234375 -0.9715881347656272 +1.835 -0.452362060546875 -0.012786865234375 -0.9715881347656272 +1.83512500000000016 -0.454559326171875 -0.012847900390625 -0.9715881347656272 +1.83525 -0.454559326171875 -0.012847900390625 -0.9715881347656272 +1.835375 -0.45672607421875 -0.012908935546875 -0.9715881347656272 +1.83550000000000016 -0.458831787109375 -0.012969970703125 -0.9715881347656272 +1.835625 -0.458831787109375 -0.012969970703125 -0.9715881347656272 +1.83575 -0.46087646484375 -0.013031005859375 -0.9715881347656272 +1.835875000000000256 -0.46087646484375 -0.013031005859375 -0.9715881347656272 +1.836 -0.462890625 -0.013092041015625 -0.9715881347656272 +1.836125 -0.464813232421875 -0.013153076171875 -0.9715881347656272 +1.83625 -0.464813232421875 -0.013153076171875 -0.9715881347656272 +1.836375 -0.46673583984375 -0.013214111328125 -0.9715881347656272 +1.8365 -0.46673583984375 -0.013214111328125 -0.9715881347656272 +1.836625 -0.46856689453125 -0.01324462890625 -0.9715881347656272 +1.83675 -0.470367431640625 -0.0133056640625 -0.9715881347656272 +1.836875 -0.470367431640625 -0.0133056640625 -0.9715881347656272 +1.837 -0.472137451171875 -0.01336669921875 -0.9715881347656272 +1.83712500000000016 -0.472137451171875 -0.01336669921875 -0.9715881347656272 +1.83725 -0.47381591796875 -0.013397216796875 -0.9715881347656272 +1.837375 -0.4754638671875 -0.013458251953125 -0.9715881347656272 +1.83750000000000016 -0.4754638671875 -0.013458251953125 -0.9715881347656272 +1.837625 -0.47705078125 -0.01348876953125 -0.9715881347656272 +1.83775 -0.47705078125 -0.01348876953125 -0.9715881347656272 +1.837875000000000256 -0.478607177734375 -0.0135498046875 -0.9715881347656272 +1.838 -0.480072021484375 -0.013580322265625 -0.9715881347656272 +1.838125 -0.480072021484375 -0.013580322265625 -0.9715881347656272 +1.83825 -0.48150634765625 -0.01361083984375 -0.9715881347656272 +1.838375 -0.48150634765625 -0.01361083984375 -0.9715881347656272 +1.8385 -0.48291015625 -0.013671875 -0.9715881347656272 +1.838625 -0.484222412109375 -0.013702392578125 -0.9715881347656272 +1.83875 -0.484222412109375 -0.013702392578125 -0.9715881347656272 +1.838875 -0.485504150390625 -0.01373291015625 -0.9715881347656272 +1.839 -0.485504150390625 -0.01373291015625 -0.9715881347656272 +1.83912500000000016 -0.486724853515625 -0.013763427734375 -0.9715881347656272 +1.83925 -0.487884521484375 -0.0137939453125 -0.9715881347656272 +1.839375 -0.487884521484375 -0.0137939453125 -0.9715881347656272 +1.83950000000000016 -0.489013671875 -0.013824462890625 -0.9715881347656272 +1.839625 -0.489013671875 -0.013824462890625 -0.9715881347656272 +1.83975 -0.490081787109375 -0.01385498046875 -0.9715881347656272 +1.839875000000000256 -0.4910888671875 -0.013885498046875 -0.9715881347656272 +1.84 -0.4910888671875 -0.013885498046875 -0.9715881347656272 +1.840125 -0.492034912109375 -0.013916015625 -0.9715881347656272 +1.84025 -0.492034912109375 -0.013916015625 -0.9715881347656272 +1.840375 -0.492950439453125 -0.013946533203125 -0.9715881347656272 +1.8405 -0.4937744140625 -0.01397705078125 -0.9715881347656272 +1.840625 -0.4937744140625 -0.01397705078125 -0.9715881347656272 +1.84075 -0.49456787109375 -0.014007568359375 -0.9715881347656272 +1.840875 -0.49456787109375 -0.014007568359375 -0.9715881347656272 +1.841 -0.49530029296875 -0.014007568359375 -0.9715881347656272 +1.84112500000000016 -0.496002197265625 -0.0140380859375 -0.9715881347656272 +1.84125 -0.496002197265625 -0.0140380859375 -0.9715881347656272 +1.841375 -0.496612548828125 -0.0140380859375 -0.9715881347656272 +1.84150000000000016 -0.496612548828125 -0.0140380859375 -0.9715881347656272 +1.841625 -0.4971923828125 -0.014068603515625 -0.9715881347656272 +1.84175 -0.497711181640625 -0.014068603515625 -0.9715881347656272 +1.841875 -0.497711181640625 -0.014068603515625 -0.9715881347656272 +1.842 -0.498199462890625 -0.01409912109375 -0.9715881347656272 +1.842125 -0.498199462890625 -0.01409912109375 -0.9715881347656272 +1.84225 -0.49859619140625 -0.01409912109375 -0.9715881347656272 +1.842375 -0.49896240234375 -0.014129638671875 -0.9715881347656272 +1.8425 -0.49896240234375 -0.014129638671875 -0.9715881347656272 +1.842625 -0.499267578125 -0.014129638671875 -0.9715881347656272 +1.84275 -0.499267578125 -0.014129638671875 -0.9715881347656272 +1.842875 -0.49951171875 -0.014129638671875 -0.9715881347656272 +1.843 -0.49969482421875 -0.014129638671875 -0.9715881347656272 +1.84312500000000016 -0.49969482421875 -0.014129638671875 -0.9715881347656272 +1.84325 -0.49981689453125 -0.014129638671875 -0.9715881347656272 +1.843375 -0.49981689453125 -0.014129638671875 -0.9715881347656272 +1.84350000000000016 -0.499908447265625 -0.014129638671875 -0.9715881347656272 +1.843625 -0.49993896484375 -0.014129638671875 -0.9715881347656272 +1.84375 -0.49993896484375 -0.014129638671875 -0.9715881347656272 +1.843875 -0.499908447265625 -0.014129638671875 -0.9715881347656272 +1.844 -0.499908447265625 -0.014129638671875 -0.9715881347656272 +1.844125 -0.49981689453125 -0.014129638671875 -0.9715881347656272 +1.84425 -0.49969482421875 -0.014129638671875 -0.9715881347656272 +1.844375 -0.49969482421875 -0.014129638671875 -0.9715881347656272 +1.8445 -0.49951171875 -0.014129638671875 -0.9715881347656272 +1.844625 -0.49951171875 -0.014129638671875 -0.9715881347656272 +1.84475000000000016 -0.499267578125 -0.014129638671875 -0.9715881347656272 +1.844875 -0.49896240234375 -0.014129638671875 -0.9715881347656272 +1.845 -0.49896240234375 -0.014129638671875 -0.9715881347656272 +1.84512500000000016 -0.49859619140625 -0.01409912109375 -0.9715881347656272 +1.84525 -0.49859619140625 -0.01409912109375 -0.9715881347656272 +1.845375 -0.498199462890625 -0.01409912109375 -0.9715881347656272 +1.84550000000000016 -0.497711181640625 -0.014068603515625 -0.9715881347656272 +1.845625 -0.497711181640625 -0.014068603515625 -0.9715881347656272 +1.84575 -0.4971923828125 -0.014068603515625 -0.9715881347656272 +1.845875 -0.4971923828125 -0.014068603515625 -0.9715881347656272 +1.846 -0.496612548828125 -0.0140380859375 -0.9715881347656272 +1.846125 -0.496002197265625 -0.0140380859375 -0.9715881347656272 +1.84625 -0.496002197265625 -0.0140380859375 -0.9715881347656272 +1.846375 -0.49530029296875 -0.014007568359375 -0.9715881347656272 +1.8465 -0.49530029296875 -0.014007568359375 -0.9715881347656272 +1.846625 -0.49456787109375 -0.014007568359375 -0.9715881347656272 +1.84675000000000016 -0.4937744140625 -0.01397705078125 -0.9715881347656272 +1.846875 -0.4937744140625 -0.01397705078125 -0.9715881347656272 +1.847 -0.492950439453125 -0.013946533203125 -0.9715881347656272 +1.84712500000000016 -0.492950439453125 -0.013946533203125 -0.9715881347656272 +1.84725 -0.492034912109375 -0.013916015625 -0.9715881347656272 +1.847375 -0.4910888671875 -0.013885498046875 -0.9715881347656272 +1.84750000000000016 -0.4910888671875 -0.013885498046875 -0.9715881347656272 +1.847625 -0.490081787109375 -0.01385498046875 -0.9715881347656272 +1.84775 -0.490081787109375 -0.01385498046875 -0.9715881347656272 +1.847875 -0.489013671875 -0.013824462890625 -0.9715881347656272 +1.848 -0.487884521484375 -0.0137939453125 -0.9715881347656272 +1.848125 -0.487884521484375 -0.0137939453125 -0.9715881347656272 +1.84825 -0.486724853515625 -0.013763427734375 -0.9715881347656272 +1.848375 -0.486724853515625 -0.013763427734375 -0.9715881347656272 +1.8485 -0.485504150390625 -0.01373291015625 -0.9715881347656272 +1.848625 -0.484222412109375 -0.013702392578125 -0.9715881347656272 +1.84875000000000016 -0.484222412109375 -0.013702392578125 -0.9715881347656272 +1.848875 -0.48291015625 -0.013671875 -0.9715881347656272 +1.849 -0.48291015625 -0.013671875 -0.9715881347656272 +1.84912500000000016 -0.48150634765625 -0.01361083984375 -0.9715881347656272 +1.84925 -0.480072021484375 -0.013580322265625 -0.9715881347656272 +1.849375 -0.480072021484375 -0.013580322265625 -0.9715881347656272 +1.84950000000000016 -0.478607177734375 -0.0135498046875 -0.9715881347656272 +1.849625 -0.478607177734375 -0.0135498046875 -0.9715881347656272 +1.84975 -0.47705078125 -0.01348876953125 -0.9715881347656272 +1.849875 -0.4754638671875 -0.013458251953125 -0.9715881347656272 +1.85 -0.4754638671875 -0.013458251953125 -0.9715881347656272 +1.850125 -0.47381591796875 -0.013397216796875 -0.9715881347656272 +1.85025 -0.47381591796875 -0.013397216796875 -0.9715881347656272 +1.850375 -0.472137451171875 -0.01336669921875 -0.9715881347656272 +1.8505 -0.470367431640625 -0.0133056640625 -0.9715881347656272 +1.850625 -0.470367431640625 -0.0133056640625 -0.9715881347656272 +1.85075000000000016 -0.46856689453125 -0.01324462890625 -0.9715881347656272 +1.850875 -0.46856689453125 -0.01324462890625 -0.9715881347656272 +1.851 -0.46673583984375 -0.013214111328125 -0.9715881347656272 +1.85112500000000016 -0.464813232421875 -0.013153076171875 -0.9715881347656272 +1.85125 -0.464813232421875 -0.013153076171875 -0.9715881347656272 +1.851375 -0.462890625 -0.013092041015625 -0.9715881347656272 +1.851500000000000256 -0.462890625 -0.013092041015625 -0.9715881347656272 +1.851625 -0.46087646484375 -0.013031005859375 -0.9715881347656272 +1.85175 -0.458831787109375 -0.012969970703125 -0.9715881347656272 +1.851875 -0.458831787109375 -0.012969970703125 -0.9715881347656272 +1.852 -0.45672607421875 -0.012908935546875 -0.9715881347656272 +1.852125 -0.45672607421875 -0.012908935546875 -0.9715881347656272 +1.85225 -0.454559326171875 -0.012847900390625 -0.9715881347656272 +1.852375 -0.452362060546875 -0.012786865234375 -0.9715881347656272 +1.8525 -0.452362060546875 -0.012786865234375 -0.9715881347656272 +1.852625 -0.450103759765625 -0.012725830078125 -0.9715881347656272 +1.85275000000000016 -0.450103759765625 -0.012725830078125 -0.9715881347656272 +1.852875 -0.447784423828125 -0.012664794921875 -0.9715881347656272 +1.853 -0.4454345703125 -0.012603759765625 -0.9715881347656272 +1.85312500000000016 -0.4454345703125 -0.012603759765625 -0.9715881347656272 +1.85325 -0.44305419921875 -0.012542724609375 -0.9715881347656272 +1.853375 -0.44305419921875 -0.012542724609375 -0.9715881347656272 +1.853500000000000256 -0.440582275390625 -0.012451171875 -0.9715881347656272 +1.853625 -0.438079833984375 -0.01239013671875 -0.9715881347656272 +1.85375 -0.438079833984375 -0.01239013671875 -0.9715881347656272 +1.853875 -0.435546875 -0.0123291015625 -0.9715881347656272 +1.854 -0.435546875 -0.0123291015625 -0.9715881347656272 +1.854125 -0.432952880859375 -0.012237548828125 -0.9715881347656272 +1.85425 -0.4302978515625 -0.012176513671875 -0.9715881347656272 +1.854375 -0.4302978515625 -0.012176513671875 -0.9715881347656272 +1.8545 -0.4276123046875 -0.0120849609375 -0.9715881347656272 +1.854625 -0.4276123046875 -0.0120849609375 -0.9715881347656272 +1.85475000000000016 -0.424896240234375 -0.01202392578125 -0.9715881347656272 +1.854875 -0.422119140625 -0.011932373046875 -0.9715881347656272 +1.855 -0.422119140625 -0.011932373046875 -0.9715881347656272 +1.85512500000000016 -0.419281005859375 -0.011871337890625 -0.9715881347656272 +1.85525 -0.419281005859375 -0.011871337890625 -0.9715881347656272 +1.855375 -0.416412353515625 -0.01177978515625 -0.9715881347656272 +1.855500000000000256 -0.413482666015625 -0.011688232421875 -0.9715881347656272 +1.855625 -0.413482666015625 -0.011688232421875 -0.9715881347656272 +1.85575 -0.4105224609375 -0.0115966796875 -0.9715881347656272 +1.855875 -0.4105224609375 -0.0115966796875 -0.9715881347656272 +1.856 -0.407501220703125 -0.005401611328125 -0.9866333007812484 +1.856125 -0.404449462890625 -0.005340576171875 -0.9866333007812484 +1.85625 -0.404449462890625 -0.005340576171875 -0.9866333007812484 +1.856375 -0.401336669921875 -0.00531005859375 -0.9866333007812484 +1.8565 -0.401336669921875 -0.00531005859375 -0.9866333007812484 +1.856625 -0.398193359375 -0.005279541015625 -0.9866333007812484 +1.85675000000000016 -0.39501953125 -0.005218505859375 -0.9866333007812484 +1.856875 -0.39501953125 -0.005218505859375 -0.9866333007812484 +1.857 -0.39178466796875 -0.00518798828125 -0.9866333007812484 +1.85712500000000016 -0.39178466796875 -0.00518798828125 -0.9866333007812484 +1.85725 -0.388519287109375 -0.005157470703125 -0.9866333007812484 +1.857375 -0.38519287109375 -0.005096435546875 -0.9866333007812484 +1.8575 -0.38519287109375 -0.005096435546875 -0.9866333007812484 +1.857625 -0.3818359375 -0.00506591796875 -0.9866333007812484 +1.85775 -0.3818359375 -0.00506591796875 -0.9866333007812484 +1.857875 -0.378448486328125 -0.0050048828125 -0.9866333007812484 +1.858 -0.375 -0.004974365234375 -0.9866333007812484 +1.858125 -0.375 -0.004974365234375 -0.9866333007812484 +1.85825 -0.37152099609375 -0.004913330078125 -0.9866333007812484 +1.858375 -0.37152099609375 -0.004913330078125 -0.9866333007812484 +1.8585 -0.36798095703125 -0.0048828125 -0.9866333007812484 +1.858625 -0.36444091796875 -0.00482177734375 -0.9866333007812484 +1.85875000000000016 -0.36444091796875 -0.00482177734375 -0.9866333007812484 +1.858875 -0.360809326171875 -0.0047607421875 -0.9866333007812484 +1.859 -0.360809326171875 -0.0047607421875 -0.9866333007812484 +1.85912500000000016 -0.357177734375 -0.004730224609375 -0.9866333007812484 +1.85925 -0.353485107421875 -0.004669189453125 -0.9866333007812484 +1.859375 -0.353485107421875 -0.004669189453125 -0.9866333007812484 +1.8595 -0.349761962890625 -0.004638671875 -0.9866333007812484 +1.859625 -0.349761962890625 -0.004638671875 -0.9866333007812484 +1.85975 -0.34600830078125 -0.00457763671875 -0.9866333007812484 +1.859875 -0.34222412109375 -0.0045166015625 -0.9866333007812484 +1.86 -0.34222412109375 -0.0045166015625 -0.9866333007812484 +1.860125 -0.33837890625 -0.004486083984375 -0.9866333007812484 +1.86025 -0.33837890625 -0.004486083984375 -0.9866333007812484 +1.86037500000000016 -0.334503173828125 -0.004425048828125 -0.9866333007812484 +1.8605 -0.330596923828125 -0.004364013671875 -0.9866333007812484 +1.860625 -0.330596923828125 -0.004364013671875 -0.9866333007812484 +1.86075000000000016 -0.32666015625 -0.00433349609375 -0.9866333007812484 +1.860875 -0.32666015625 -0.00433349609375 -0.9866333007812484 +1.861 -0.322662353515625 -0.0042724609375 -0.9866333007812484 +1.86112500000000016 -0.31866455078125 -0.00421142578125 -0.9866333007812484 +1.86125 -0.31866455078125 -0.00421142578125 -0.9866333007812484 +1.861375 -0.314605712890625 -0.004150390625 -0.9866333007812484 +1.8615 -0.314605712890625 -0.004150390625 -0.9866333007812484 +1.861625 -0.310516357421875 -0.004119873046875 -0.9866333007812484 +1.86175 -0.306396484375 -0.004058837890625 -0.9866333007812484 +1.861875 -0.306396484375 -0.004058837890625 -0.9866333007812484 +1.862 -0.30224609375 -0.003997802734375 -0.9866333007812484 +1.862125 -0.30224609375 -0.003997802734375 -0.9866333007812484 +1.86225 -0.298065185546875 -0.003936767578125 -0.9866333007812484 +1.86237500000000016 -0.2938232421875 -0.003875732421875 -0.9866333007812484 +1.8625 -0.2938232421875 -0.003875732421875 -0.9866333007812484 +1.862625 -0.289581298828125 -0.003814697265625 -0.9866333007812484 +1.86275000000000016 -0.289581298828125 -0.003814697265625 -0.9866333007812484 +1.862875 -0.285308837890625 -0.0037841796875 -0.9866333007812484 +1.863 -0.280975341796875 -0.00372314453125 -0.9866333007812484 +1.86312500000000016 -0.280975341796875 -0.00372314453125 -0.9866333007812484 +1.86325 -0.276641845703125 -0.003662109375 -0.9866333007812484 +1.863375 -0.276641845703125 -0.003662109375 -0.9866333007812484 +1.8635 -0.27227783203125 -0.00360107421875 -0.9866333007812484 +1.863625 -0.267852783203125 -0.0035400390625 -0.9866333007812484 +1.86375 -0.267852783203125 -0.0035400390625 -0.9866333007812484 +1.863875 -0.263427734375 -0.00347900390625 -0.9866333007812484 +1.864 -0.263427734375 -0.00347900390625 -0.9866333007812484 +1.864125 -0.25897216796875 -0.00341796875 -0.9866333007812484 +1.86425 -0.25445556640625 -0.00335693359375 -0.9866333007812484 +1.86437500000000016 -0.25445556640625 -0.00335693359375 -0.9866333007812484 +1.8645 -0.249969482421875 -0.0032958984375 -0.9866333007812484 +1.864625 -0.249969482421875 -0.0032958984375 -0.9866333007812484 +1.86475000000000016 -0.24542236328125 -0.00323486328125 -0.9866333007812484 +1.864875 -0.2408447265625 -0.003173828125 -0.9866333007812484 +1.865 -0.2408447265625 -0.003173828125 -0.9866333007812484 +1.86512500000000016 -0.236236572265625 -0.00311279296875 -0.9866333007812484 +1.86525 -0.236236572265625 -0.00311279296875 -0.9866333007812484 +1.865375 -0.231597900390625 -0.0030517578125 -0.9866333007812484 +1.8655 -0.226959228515625 -0.00299072265625 -0.9866333007812484 +1.865625 -0.226959228515625 -0.00299072265625 -0.9866333007812484 +1.86575 -0.2222900390625 -0.0029296875 -0.9866333007812484 +1.865875 -0.2222900390625 -0.0029296875 -0.9866333007812484 +1.866 -0.21759033203125 -0.00286865234375 -0.9866333007812484 +1.866125 -0.212860107421875 -0.0028076171875 -0.9866333007812484 +1.86625 -0.212860107421875 -0.0028076171875 -0.9866333007812484 +1.86637500000000016 -0.208099365234375 -0.00274658203125 -0.9866333007812484 +1.8665 -0.208099365234375 -0.00274658203125 -0.9866333007812484 +1.866625 -0.203338623046875 -0.002685546875 -0.9866333007812484 +1.86675000000000016 -0.19854736328125 -0.00262451171875 -0.9866333007812484 +1.866875 -0.19854736328125 -0.00262451171875 -0.9866333007812484 +1.867 -0.1937255859375 -0.0025634765625 -0.9866333007812484 +1.867125000000000256 -0.1937255859375 -0.0025634765625 -0.9866333007812484 +1.86725 -0.188873291015625 -0.00250244140625 -0.9866333007812484 +1.867375 -0.18402099609375 -0.00244140625 -0.9866333007812484 +1.8675 -0.18402099609375 -0.00244140625 -0.9866333007812484 +1.867625 -0.17913818359375 -0.002349853515625 -0.9866333007812484 +1.86775 -0.17913818359375 -0.002349853515625 -0.9866333007812484 +1.867875 -0.17425537109375 -0.002288818359375 -0.9866333007812484 +1.868 -0.169342041015625 -0.002227783203125 -0.9866333007812484 +1.868125 -0.169342041015625 -0.002227783203125 -0.9866333007812484 +1.86825 -0.164398193359375 -0.002166748046875 -0.9866333007812484 +1.86837500000000016 -0.164398193359375 -0.002166748046875 -0.9866333007812484 +1.8685 -0.159454345703125 -0.002105712890625 -0.9866333007812484 +1.868625 -0.15447998046875 -0.002044677734375 -0.9866333007812484 +1.86875000000000016 -0.15447998046875 -0.002044677734375 -0.9866333007812484 +1.868875 -0.14947509765625 -0.001983642578125 -0.9866333007812484 +1.869 -0.14947509765625 -0.001983642578125 -0.9866333007812484 +1.869125000000000256 -0.14447021484375 -0.00189208984375 -0.9866333007812484 +1.86925 -0.13946533203125 -0.0018310546875 -0.9866333007812484 +1.869375 -0.13946533203125 -0.0018310546875 -0.9866333007812484 +1.8695 -0.134429931640625 -0.00177001953125 -0.9866333007812484 +1.869625 -0.134429931640625 -0.00177001953125 -0.9866333007812484 +1.86975 -0.129364013671875 -0.001708984375 -0.9866333007812484 +1.869875 -0.124298095703125 -0.00164794921875 -0.9866333007812484 +1.87 -0.124298095703125 -0.00164794921875 -0.9866333007812484 +1.870125 -0.119232177734375 -0.001556396484375 -0.9866333007812484 +1.87025 -0.119232177734375 -0.001556396484375 -0.9866333007812484 +1.87037500000000016 -0.1141357421875 -0.001495361328125 -0.9866333007812484 +1.8705 -0.109039306640625 -0.001434326171875 -0.9866333007812484 +1.870625 -0.109039306640625 -0.001434326171875 -0.9866333007812484 +1.87075000000000016 -0.103912353515625 -0.001373291015625 -0.9866333007812484 +1.870875 -0.103912353515625 -0.001373291015625 -0.9866333007812484 +1.871 -0.098785400390625 -0.00128173828125 -0.9866333007812484 +1.871125000000000256 -0.093658447265625 -0.001220703125 -0.9866333007812484 +1.87125 -0.093658447265625 -0.001220703125 -0.9866333007812484 +1.871375 -0.0885009765625 -0.00115966796875 -0.9866333007812484 +1.8715 -0.0885009765625 -0.00115966796875 -0.9866333007812484 +1.871625 -0.083343505859375 -0.0010986328125 -0.9866333007812484 +1.87175 -0.07818603515625 -0.00103759765625 -0.9866333007812484 +1.871875 -0.07818603515625 -0.00103759765625 -0.9866333007812484 +1.872 -0.072998046875 -0.000946044921875 -0.9866333007812484 +1.872125 -0.072998046875 -0.000946044921875 -0.9866333007812484 +1.87225 -0.06781005859375 -0.000885009765625 -0.9866333007812484 +1.87237500000000016 -0.0626220703125 -0.000823974609375 -0.9866333007812484 +1.8725 -0.0626220703125 -0.000823974609375 -0.9866333007812484 +1.872625 -0.05743408203125 -0.000732421875 -0.9866333007812484 +1.87275000000000016 -0.05743408203125 -0.000732421875 -0.9866333007812484 +1.872875 -0.05224609375 -0.00067138671875 -0.9866333007812484 +1.873 -0.047027587890625 -0.0006103515625 -0.9866333007812484 +1.873125 -0.047027587890625 -0.0006103515625 -0.9866333007812484 +1.87325 -0.04180908203125 -0.00054931640625 -0.9866333007812484 +1.873375 -0.04180908203125 -0.00054931640625 -0.9866333007812484 +1.8735 -0.036590576171875 -0.000457763671875 -0.9866333007812484 +1.873625 -0.0313720703125 -0.000396728515625 -0.9866333007812484 +1.87375 -0.0313720703125 -0.000396728515625 -0.9866333007812484 +1.873875 -0.026123046875 -0.000335693359375 -0.9866333007812484 +1.874 -0.026123046875 -0.000335693359375 -0.9866333007812484 +1.874125 -0.020904541015625 -0.000274658203125 -0.9866333007812484 +1.87425 -0.01568603515625 -0.00018310546875 -0.9866333007812484 +1.87437500000000016 -0.01568603515625 -0.00018310546875 -0.9866333007812484 +1.8745 -0.01043701171875 -0.0001220703125 -0.9866333007812484 +1.874625 -0.01043701171875 -0.0001220703125 -0.9866333007812484 +1.87475000000000016 -0.005218505859375 -6.103515625e-05 -0.9866333007812484 +1.874875 0.0 0.0 -0.9866333007812484 +1.875 0.0 0.0 -0.9866333007812484 +1.875125 0.005218505859375 6.103515625e-05 -0.9866333007812484 +1.87525 0.005218505859375 6.103515625e-05 -0.9866333007812484 +1.875375 0.01043701171875 0.0001220703125 -0.9866333007812484 +1.8755 0.01568603515625 0.00018310546875 -0.9866333007812484 +1.875625 0.01568603515625 0.00018310546875 -0.9866333007812484 +1.87575 0.020904541015625 0.000274658203125 -0.9866333007812484 +1.875875 0.020904541015625 0.000274658203125 -0.9866333007812484 +1.87600000000000016 0.026123046875 0.000335693359375 -0.9866333007812484 +1.876125 0.0313720703125 0.000396728515625 -0.9866333007812484 +1.87625 0.0313720703125 0.000396728515625 -0.9866333007812484 +1.87637500000000016 0.036590576171875 0.000457763671875 -0.9866333007812484 +1.8765 0.036590576171875 0.000457763671875 -0.9866333007812484 +1.876625 0.04180908203125 0.00054931640625 -0.9866333007812484 +1.87675000000000016 0.047027587890625 0.0006103515625 -0.9866333007812484 +1.876875 0.047027587890625 0.0006103515625 -0.9866333007812484 +1.877 0.05224609375 0.00067138671875 -0.9866333007812484 +1.877125 0.05224609375 0.00067138671875 -0.9866333007812484 +1.87725 0.05743408203125 0.000732421875 -0.9866333007812484 +1.877375 0.0626220703125 0.000823974609375 -0.9866333007812484 +1.8775 0.0626220703125 0.000823974609375 -0.9866333007812484 +1.877625 0.06781005859375 0.000885009765625 -0.9866333007812484 +1.87775 0.06781005859375 0.000885009765625 -0.9866333007812484 +1.877875 0.072998046875 0.000946044921875 -0.9866333007812484 +1.87800000000000016 0.07818603515625 0.00103759765625 -0.9866333007812484 +1.878125 0.07818603515625 0.00103759765625 -0.9866333007812484 +1.87825 0.083343505859375 0.0010986328125 -0.9866333007812484 +1.87837500000000016 0.083343505859375 0.0010986328125 -0.9866333007812484 +1.8785 0.0885009765625 0.00115966796875 -0.9866333007812484 +1.878625 0.093658447265625 0.001220703125 -0.9866333007812484 +1.87875000000000016 0.093658447265625 0.001220703125 -0.9866333007812484 +1.878875 0.098785400390625 0.00128173828125 -0.9866333007812484 +1.879 0.098785400390625 0.00128173828125 -0.9866333007812484 +1.879125 0.103912353515625 0.001373291015625 -0.9866333007812484 +1.87925 0.109039306640625 0.001434326171875 -0.9866333007812484 +1.879375 0.109039306640625 0.001434326171875 -0.9866333007812484 +1.8795 0.1141357421875 0.001495361328125 -0.9866333007812484 +1.879625 0.1141357421875 0.001495361328125 -0.9866333007812484 +1.87975 0.119232177734375 0.001556396484375 -0.9866333007812484 +1.879875 0.124298095703125 0.00164794921875 -0.9866333007812484 +1.88000000000000016 0.124298095703125 0.00164794921875 -0.9866333007812484 +1.880125 0.129364013671875 0.001708984375 -0.9866333007812484 +1.88025 0.129364013671875 0.001708984375 -0.9866333007812484 +1.88037500000000016 0.134429931640625 0.00177001953125 -0.9866333007812484 +1.8805 0.13946533203125 0.0018310546875 -0.9866333007812484 +1.880625 0.13946533203125 0.0018310546875 -0.9866333007812484 +1.88075000000000016 0.14447021484375 0.00189208984375 -0.9866333007812484 +1.880875 0.14447021484375 0.00189208984375 -0.9866333007812484 +1.881 0.14947509765625 0.001983642578125 -0.9866333007812484 +1.881125 0.15447998046875 0.002044677734375 -0.9866333007812484 +1.88125 0.15447998046875 0.002044677734375 -0.9866333007812484 +1.881375 0.159454345703125 0.002105712890625 -0.9866333007812484 +1.8815 0.159454345703125 0.002105712890625 -0.9866333007812484 +1.881625 0.164398193359375 0.002166748046875 -0.9866333007812484 +1.88175 0.169342041015625 0.002227783203125 -0.9866333007812484 +1.881875 0.169342041015625 0.002227783203125 -0.9866333007812484 +1.88200000000000016 0.17425537109375 0.002288818359375 -0.9866333007812484 +1.882125 0.17425537109375 0.002288818359375 -0.9866333007812484 +1.88225 0.17913818359375 0.002349853515625 -0.9866333007812484 +1.88237500000000016 0.18402099609375 0.00244140625 -0.9866333007812484 +1.8825 0.18402099609375 0.00244140625 -0.9866333007812484 +1.882625 0.188873291015625 0.00250244140625 -0.9866333007812484 +1.882750000000000256 0.188873291015625 0.00250244140625 -0.9866333007812484 +1.882875 0.1937255859375 0.0025634765625 -0.9866333007812484 +1.883 0.19854736328125 0.00262451171875 -0.9866333007812484 +1.883125 0.19854736328125 0.00262451171875 -0.9866333007812484 +1.88325 0.203338623046875 0.002685546875 -0.9866333007812484 +1.883375 0.203338623046875 0.002685546875 -0.9866333007812484 +1.8835 0.208099365234375 0.00274658203125 -0.9866333007812484 +1.883625 0.212860107421875 0.0028076171875 -0.9866333007812484 +1.88375 0.212860107421875 0.0028076171875 -0.9866333007812484 +1.883875 0.21759033203125 0.00286865234375 -0.9866333007812484 +1.88400000000000016 0.21759033203125 0.00286865234375 -0.9866333007812484 +1.884125 0.2222900390625 0.0029296875 -0.9866333007812484 +1.88425 0.226959228515625 0.00299072265625 -0.9866333007812484 +1.88437500000000016 0.226959228515625 0.00299072265625 -0.9866333007812484 +1.8845 0.231597900390625 0.0030517578125 -0.9866333007812484 +1.884625 0.231597900390625 0.0030517578125 -0.9866333007812484 +1.884750000000000256 0.236236572265625 0.00311279296875 -0.9866333007812484 +1.884875 0.2408447265625 0.003173828125 -0.9866333007812484 +1.885 0.2408447265625 0.003173828125 -0.9866333007812484 +1.885125 0.24542236328125 0.00323486328125 -0.9866333007812484 +1.88525 0.24542236328125 0.00323486328125 -0.9866333007812484 +1.885375 0.249969482421875 0.0032958984375 -0.9866333007812484 +1.8855 0.25445556640625 0.00335693359375 -0.9866333007812484 +1.885625 0.25445556640625 0.00335693359375 -0.9866333007812484 +1.88575 0.25897216796875 0.00341796875 -0.9866333007812484 +1.885875 0.25897216796875 0.00341796875 -0.9866333007812484 +1.88600000000000016 0.263427734375 0.00347900390625 -0.9866333007812484 +1.886125 0.267852783203125 0.0035400390625 -0.9866333007812484 +1.88625 0.267852783203125 0.0035400390625 -0.9866333007812484 +1.88637500000000016 0.27227783203125 0.00360107421875 -0.9866333007812484 +1.8865 0.27227783203125 0.00360107421875 -0.9866333007812484 +1.886625 0.276641845703125 0.003662109375 -0.9866333007812484 +1.886750000000000256 0.280975341796875 0.00372314453125 -0.9866333007812484 +1.886875 0.280975341796875 0.00372314453125 -0.9866333007812484 +1.887 0.285308837890625 0.0037841796875 -0.9866333007812484 +1.887125 0.285308837890625 0.0037841796875 -0.9866333007812484 +1.88725 0.289581298828125 0.003814697265625 -0.9866333007812484 +1.887375 0.2938232421875 0.003875732421875 -0.9866333007812484 +1.8875 0.2938232421875 0.003875732421875 -0.9866333007812484 +1.887625 0.298065185546875 0.003936767578125 -0.9866333007812484 +1.88775 0.298065185546875 0.003936767578125 -0.9866333007812484 +1.887875 0.30224609375 0.003997802734375 -0.9866333007812484 +1.88800000000000016 0.306396484375 0.04766845703125 -0.8442993164062446 +1.888125 0.306396484375 0.04766845703125 -0.8442993164062446 +1.88825 0.310516357421875 0.048309326171875 -0.8442993164062446 +1.88837500000000016 0.310516357421875 0.048309326171875 -0.8442993164062446 +1.8885 0.314605712890625 0.0489501953125 -0.8442993164062446 +1.888625 0.31866455078125 0.049591064453125 -0.8442993164062446 +1.88875 0.31866455078125 0.049591064453125 -0.8442993164062446 +1.888875 0.322662353515625 0.050201416015625 -0.8442993164062446 +1.889 0.322662353515625 0.050201416015625 -0.8442993164062446 +1.889125 0.32666015625 0.050811767578125 -0.8442993164062446 +1.88925 0.330596923828125 0.051422119140625 -0.8442993164062446 +1.889375 0.330596923828125 0.051422119140625 -0.8442993164062446 +1.8895 0.334503173828125 0.052032470703125 -0.8442993164062446 +1.889625 0.334503173828125 0.052032470703125 -0.8442993164062446 +1.88975 0.33837890625 0.052642822265625 -0.8442993164062446 +1.889875 0.34222412109375 0.053253173828125 -0.8442993164062446 +1.89000000000000016 0.34222412109375 0.053253173828125 -0.8442993164062446 +1.890125 0.34600830078125 0.0538330078125 -0.8442993164062446 +1.89025 0.34600830078125 0.0538330078125 -0.8442993164062446 +1.89037500000000016 0.349761962890625 0.054412841796875 -0.8442993164062446 +1.8905 0.353485107421875 0.05499267578125 -0.8442993164062446 +1.890625 0.353485107421875 0.05499267578125 -0.8442993164062446 +1.89075 0.357177734375 0.055572509765625 -0.8442993164062446 +1.890875 0.357177734375 0.055572509765625 -0.8442993164062446 +1.891 0.360809326171875 0.05615234375 -0.8442993164062446 +1.891125 0.36444091796875 0.05670166015625 -0.8442993164062446 +1.89125 0.36444091796875 0.05670166015625 -0.8442993164062446 +1.891375 0.36798095703125 0.0572509765625 -0.8442993164062446 +1.8915 0.36798095703125 0.0572509765625 -0.8442993164062446 +1.89162500000000016 0.37152099609375 0.05780029296875 -0.8442993164062446 +1.89175 0.375 0.058349609375 -0.8442993164062446 +1.891875 0.375 0.058349609375 -0.8442993164062446 +1.89200000000000016 0.378448486328125 0.058868408203125 -0.8442993164062446 +1.892125 0.378448486328125 0.058868408203125 -0.8442993164062446 +1.89225 0.3818359375 0.059417724609375 -0.8442993164062446 +1.89237500000000016 0.38519287109375 0.0599365234375 -0.8442993164062446 +1.8925 0.38519287109375 0.0599365234375 -0.8442993164062446 +1.892625 0.388519287109375 0.060455322265625 -0.8442993164062446 +1.89275 0.388519287109375 0.060455322265625 -0.8442993164062446 +1.892875 0.39178466796875 0.060943603515625 -0.8442993164062446 +1.893 0.39501953125 0.06146240234375 -0.8442993164062446 +1.893125 0.39501953125 0.06146240234375 -0.8442993164062446 +1.89325 0.398193359375 0.06195068359375 -0.8442993164062446 +1.893375 0.398193359375 0.06195068359375 -0.8442993164062446 +1.8935 0.401336669921875 0.06243896484375 -0.8442993164062446 +1.89362500000000016 0.404449462890625 0.06292724609375 -0.8442993164062446 +1.89375 0.404449462890625 0.06292724609375 -0.8442993164062446 +1.893875 0.407501220703125 0.06341552734375 -0.8442993164062446 +1.89400000000000016 0.407501220703125 0.06341552734375 -0.8442993164062446 +1.894125 0.4105224609375 0.063873291015625 -0.8442993164062446 +1.89425 0.413482666015625 0.0643310546875 -0.8442993164062446 +1.89437500000000016 0.413482666015625 0.0643310546875 -0.8442993164062446 +1.8945 0.416412353515625 0.064788818359375 -0.8442993164062446 +1.894625 0.416412353515625 0.064788818359375 -0.8442993164062446 +1.89475 0.419281005859375 0.06524658203125 -0.8442993164062446 +1.894875 0.422119140625 0.065673828125 -0.8442993164062446 +1.895 0.422119140625 0.065673828125 -0.8442993164062446 +1.895125 0.424896240234375 0.06610107421875 -0.8442993164062446 +1.89525 0.424896240234375 0.06610107421875 -0.8442993164062446 +1.895375 0.4276123046875 0.0665283203125 -0.8442993164062446 +1.8955 0.4302978515625 0.06695556640625 -0.8442993164062446 +1.89562500000000016 0.4302978515625 0.06695556640625 -0.8442993164062446 +1.89575 0.432952880859375 0.067352294921875 -0.8442993164062446 +1.895875 0.432952880859375 0.067352294921875 -0.8442993164062446 +1.89600000000000016 0.435546875 0.067779541015625 -0.8442993164062446 +1.896125 0.438079833984375 0.06817626953125 -0.8442993164062446 +1.89625 0.438079833984375 0.06817626953125 -0.8442993164062446 +1.89637500000000016 0.440582275390625 0.06854248046875 -0.8442993164062446 +1.8965 0.440582275390625 0.06854248046875 -0.8442993164062446 +1.896625 0.44305419921875 0.068939208984375 -0.8442993164062446 +1.89675 0.4454345703125 0.069305419921875 -0.8442993164062446 +1.896875 0.4454345703125 0.069305419921875 -0.8442993164062446 +1.897 0.447784423828125 0.069671630859375 -0.8442993164062446 +1.897125 0.447784423828125 0.069671630859375 -0.8442993164062446 +1.89725 0.450103759765625 0.070037841796875 -0.8442993164062446 +1.897375 0.452362060546875 0.07037353515625 -0.8442993164062446 +1.8975 0.452362060546875 0.07037353515625 -0.8442993164062446 +1.89762500000000016 0.454559326171875 0.070709228515625 -0.8442993164062446 +1.89775 0.454559326171875 0.070709228515625 -0.8442993164062446 +1.897875 0.45672607421875 0.071075439453125 -0.8442993164062446 +1.89800000000000016 0.458831787109375 0.071380615234375 -0.8442993164062446 +1.898125 0.458831787109375 0.071380615234375 -0.8442993164062446 +1.89825 0.46087646484375 0.07171630859375 -0.8442993164062446 +1.898375000000000256 0.46087646484375 0.07171630859375 -0.8442993164062446 +1.8985 0.462890625 0.072021484375 -0.8442993164062446 +1.898625 0.464813232421875 0.07232666015625 -0.8442993164062446 +1.89875 0.464813232421875 0.07232666015625 -0.8442993164062446 +1.898875 0.46673583984375 0.0726318359375 -0.8442993164062446 +1.899 0.46673583984375 0.0726318359375 -0.8442993164062446 +1.899125 0.46856689453125 0.072906494140625 -0.8442993164062446 +1.89925 0.470367431640625 0.07318115234375 -0.8442993164062446 +1.899375 0.470367431640625 0.07318115234375 -0.8442993164062446 +1.8995 0.472137451171875 0.073455810546875 -0.8442993164062446 +1.89962500000000016 0.472137451171875 0.073455810546875 -0.8442993164062446 +1.89975 0.47381591796875 0.07373046875 -0.8442993164062446 +1.899875 0.4754638671875 0.073974609375 -0.8442993164062446 +1.90000000000000016 0.4754638671875 0.073974609375 -0.8442993164062446 +1.900125 0.47705078125 0.07421875 -0.8442993164062446 +1.90025 0.47705078125 0.07421875 -0.8442993164062446 +1.900375000000000256 0.478607177734375 0.074462890625 -0.8442993164062446 +1.9005 0.480072021484375 0.07470703125 -0.8442993164062446 +1.900625 0.480072021484375 0.07470703125 -0.8442993164062446 +1.90075 0.48150634765625 0.074920654296875 -0.8442993164062446 +1.900875 0.48150634765625 0.074920654296875 -0.8442993164062446 +1.901 0.48291015625 0.07513427734375 -0.8442993164062446 +1.901125 0.484222412109375 0.075347900390625 -0.8442993164062446 +1.90125 0.484222412109375 0.075347900390625 -0.8442993164062446 +1.901375 0.485504150390625 0.075531005859375 -0.8442993164062446 +1.9015 0.485504150390625 0.075531005859375 -0.8442993164062446 +1.90162500000000016 0.486724853515625 0.07574462890625 -0.8442993164062446 +1.90175 0.487884521484375 0.075897216796875 -0.8442993164062446 +1.901875 0.487884521484375 0.075897216796875 -0.8442993164062446 +1.90200000000000016 0.489013671875 0.076080322265625 -0.8442993164062446 +1.902125 0.489013671875 0.076080322265625 -0.8442993164062446 +1.90225 0.490081787109375 0.076263427734375 -0.8442993164062446 +1.902375000000000256 0.4910888671875 0.076416015625 -0.8442993164062446 +1.9025 0.4910888671875 0.076416015625 -0.8442993164062446 +1.902625 0.492034912109375 0.076568603515625 -0.8442993164062446 +1.90275 0.492034912109375 0.076568603515625 -0.8442993164062446 +1.902875 0.492950439453125 0.076690673828125 -0.8442993164062446 +1.903 0.4937744140625 0.076812744140625 -0.8442993164062446 +1.903125 0.4937744140625 0.076812744140625 -0.8442993164062446 +1.90325 0.49456787109375 0.07696533203125 -0.8442993164062446 +1.903375 0.49456787109375 0.07696533203125 -0.8442993164062446 +1.9035 0.49530029296875 0.077056884765625 -0.8442993164062446 +1.90362500000000016 0.496002197265625 0.077178955078125 -0.8442993164062446 +1.90375 0.496002197265625 0.077178955078125 -0.8442993164062446 +1.903875 0.496612548828125 0.0772705078125 -0.8442993164062446 +1.90400000000000016 0.496612548828125 0.0772705078125 -0.8442993164062446 +1.904125 0.4971923828125 0.077362060546875 -0.8442993164062446 +1.90425 0.497711181640625 0.07745361328125 -0.8442993164062446 +1.904375 0.497711181640625 0.07745361328125 -0.8442993164062446 +1.9045 0.498199462890625 0.0775146484375 -0.8442993164062446 +1.904625 0.498199462890625 0.0775146484375 -0.8442993164062446 +1.90475 0.49859619140625 0.07757568359375 -0.8442993164062446 +1.904875 0.49896240234375 0.07763671875 -0.8442993164062446 +1.905 0.49896240234375 0.07763671875 -0.8442993164062446 +1.905125 0.499267578125 0.077667236328125 -0.8442993164062446 +1.90525 0.499267578125 0.077667236328125 -0.8442993164062446 +1.905375 0.49951171875 0.077728271484375 -0.8442993164062446 +1.9055 0.49969482421875 0.0777587890625 -0.8442993164062446 +1.90562500000000016 0.49969482421875 0.0777587890625 -0.8442993164062446 +1.90575 0.49981689453125 0.0777587890625 -0.8442993164062446 +1.905875 0.49981689453125 0.0777587890625 -0.8442993164062446 +1.90600000000000016 0.499908447265625 0.077789306640625 -0.8442993164062446 +1.906125 0.49993896484375 0.077789306640625 -0.8442993164062446 +1.90625 0.49993896484375 0.077789306640625 -0.8442993164062446 +1.906375 0.499908447265625 0.077789306640625 -0.8442993164062446 +1.9065 0.499908447265625 0.077789306640625 -0.8442993164062446 +1.906625 0.49981689453125 0.0777587890625 -0.8442993164062446 +1.90675 0.49969482421875 0.0777587890625 -0.8442993164062446 +1.906875 0.49969482421875 0.0777587890625 -0.8442993164062446 +1.907 0.49951171875 0.077728271484375 -0.8442993164062446 +1.907125 0.49951171875 0.077728271484375 -0.8442993164062446 +1.90725000000000016 0.499267578125 0.077667236328125 -0.8442993164062446 +1.907375 0.49896240234375 0.07763671875 -0.8442993164062446 +1.9075 0.49896240234375 0.07763671875 -0.8442993164062446 +1.90762500000000016 0.49859619140625 0.07757568359375 -0.8442993164062446 +1.90775 0.49859619140625 0.07757568359375 -0.8442993164062446 +1.907875 0.498199462890625 0.0775146484375 -0.8442993164062446 +1.90800000000000016 0.497711181640625 0.07745361328125 -0.8442993164062446 +1.908125 0.497711181640625 0.07745361328125 -0.8442993164062446 +1.90825 0.4971923828125 0.077362060546875 -0.8442993164062446 +1.908375 0.4971923828125 0.077362060546875 -0.8442993164062446 +1.9085 0.496612548828125 0.0772705078125 -0.8442993164062446 +1.908625 0.496002197265625 0.077178955078125 -0.8442993164062446 +1.90875 0.496002197265625 0.077178955078125 -0.8442993164062446 +1.908875 0.49530029296875 0.077056884765625 -0.8442993164062446 +1.909 0.49530029296875 0.077056884765625 -0.8442993164062446 +1.909125 0.49456787109375 0.07696533203125 -0.8442993164062446 +1.90925000000000016 0.4937744140625 0.076812744140625 -0.8442993164062446 +1.909375 0.4937744140625 0.076812744140625 -0.8442993164062446 +1.9095 0.492950439453125 0.076690673828125 -0.8442993164062446 +1.90962500000000016 0.492950439453125 0.076690673828125 -0.8442993164062446 +1.90975 0.492034912109375 0.076568603515625 -0.8442993164062446 +1.909875 0.4910888671875 0.076416015625 -0.8442993164062446 +1.91000000000000016 0.4910888671875 0.076416015625 -0.8442993164062446 +1.910125 0.490081787109375 0.076263427734375 -0.8442993164062446 +1.91025 0.490081787109375 0.076263427734375 -0.8442993164062446 +1.910375 0.489013671875 0.076080322265625 -0.8442993164062446 +1.9105 0.487884521484375 0.075897216796875 -0.8442993164062446 +1.910625 0.487884521484375 0.075897216796875 -0.8442993164062446 +1.91075 0.486724853515625 0.07574462890625 -0.8442993164062446 +1.910875 0.486724853515625 0.07574462890625 -0.8442993164062446 +1.911 0.485504150390625 0.075531005859375 -0.8442993164062446 +1.911125 0.484222412109375 0.075347900390625 -0.8442993164062446 +1.91125000000000016 0.484222412109375 0.075347900390625 -0.8442993164062446 +1.911375 0.48291015625 0.07513427734375 -0.8442993164062446 +1.9115 0.48291015625 0.07513427734375 -0.8442993164062446 +1.91162500000000016 0.48150634765625 0.074920654296875 -0.8442993164062446 +1.91175 0.480072021484375 0.07470703125 -0.8442993164062446 +1.911875 0.480072021484375 0.07470703125 -0.8442993164062446 +1.91200000000000016 0.478607177734375 0.074462890625 -0.8442993164062446 +1.912125 0.478607177734375 0.074462890625 -0.8442993164062446 +1.91225 0.47705078125 0.07421875 -0.8442993164062446 +1.912375 0.4754638671875 0.073974609375 -0.8442993164062446 +1.9125 0.4754638671875 0.073974609375 -0.8442993164062446 +1.912625 0.47381591796875 0.07373046875 -0.8442993164062446 +1.91275 0.47381591796875 0.07373046875 -0.8442993164062446 +1.912875 0.472137451171875 0.073455810546875 -0.8442993164062446 +1.913 0.470367431640625 0.07318115234375 -0.8442993164062446 +1.913125 0.470367431640625 0.07318115234375 -0.8442993164062446 +1.91325000000000016 0.46856689453125 0.072906494140625 -0.8442993164062446 +1.913375 0.46856689453125 0.072906494140625 -0.8442993164062446 +1.9135 0.46673583984375 0.0726318359375 -0.8442993164062446 +1.91362500000000016 0.464813232421875 0.07232666015625 -0.8442993164062446 +1.91375 0.464813232421875 0.07232666015625 -0.8442993164062446 +1.913875 0.462890625 0.072021484375 -0.8442993164062446 +1.914000000000000256 0.462890625 0.072021484375 -0.8442993164062446 +1.914125 0.46087646484375 0.07171630859375 -0.8442993164062446 +1.91425 0.458831787109375 0.071380615234375 -0.8442993164062446 +1.914375 0.458831787109375 0.071380615234375 -0.8442993164062446 +1.9145 0.45672607421875 0.071075439453125 -0.8442993164062446 +1.914625 0.45672607421875 0.071075439453125 -0.8442993164062446 +1.91475 0.454559326171875 0.070709228515625 -0.8442993164062446 +1.914875 0.452362060546875 0.07037353515625 -0.8442993164062446 +1.915 0.452362060546875 0.07037353515625 -0.8442993164062446 +1.915125 0.450103759765625 0.070037841796875 -0.8442993164062446 +1.91525000000000016 0.450103759765625 0.070037841796875 -0.8442993164062446 +1.915375 0.447784423828125 0.069671630859375 -0.8442993164062446 +1.9155 0.4454345703125 0.069305419921875 -0.8442993164062446 +1.91562500000000016 0.4454345703125 0.069305419921875 -0.8442993164062446 +1.91575 0.44305419921875 0.068939208984375 -0.8442993164062446 +1.915875 0.44305419921875 0.068939208984375 -0.8442993164062446 +1.916000000000000256 0.440582275390625 0.06854248046875 -0.8442993164062446 +1.916125 0.438079833984375 0.06817626953125 -0.8442993164062446 +1.91625 0.438079833984375 0.06817626953125 -0.8442993164062446 +1.916375 0.435546875 0.067779541015625 -0.8442993164062446 +1.9165 0.435546875 0.067779541015625 -0.8442993164062446 +1.916625 0.432952880859375 0.067352294921875 -0.8442993164062446 +1.91675 0.4302978515625 0.06695556640625 -0.8442993164062446 +1.916875 0.4302978515625 0.06695556640625 -0.8442993164062446 +1.917 0.4276123046875 0.0665283203125 -0.8442993164062446 +1.917125 0.4276123046875 0.0665283203125 -0.8442993164062446 +1.91725000000000016 0.424896240234375 0.06610107421875 -0.8442993164062446 +1.917375 0.422119140625 0.065673828125 -0.8442993164062446 +1.9175 0.422119140625 0.065673828125 -0.8442993164062446 +1.91762500000000016 0.419281005859375 0.06524658203125 -0.8442993164062446 +1.91775 0.419281005859375 0.06524658203125 -0.8442993164062446 +1.917875 0.416412353515625 0.064788818359375 -0.8442993164062446 +1.918000000000000256 0.413482666015625 0.0643310546875 -0.8442993164062446 +1.918125 0.413482666015625 0.0643310546875 -0.8442993164062446 +1.91825 0.4105224609375 0.063873291015625 -0.8442993164062446 +1.918375 0.4105224609375 0.063873291015625 -0.8442993164062446 +1.9185 0.407501220703125 0.06341552734375 -0.8442993164062446 +1.918625 0.404449462890625 0.06292724609375 -0.8442993164062446 +1.91875 0.404449462890625 0.06292724609375 -0.8442993164062446 +1.918875 0.401336669921875 0.06243896484375 -0.8442993164062446 +1.919 0.401336669921875 0.06243896484375 -0.8442993164062446 +1.919125 0.398193359375 0.06195068359375 -0.8442993164062446 +1.91925000000000016 0.39501953125 0.06146240234375 -0.8442993164062446 +1.919375 0.39501953125 0.06146240234375 -0.8442993164062446 +1.9195 0.39178466796875 0.060943603515625 -0.8442993164062446 +1.91962500000000016 0.39178466796875 0.060943603515625 -0.8442993164062446 +1.91975 0.388519287109375 0.060455322265625 -0.8442993164062446 +1.919875 0.38519287109375 0.0599365234375 -0.8442993164062446 +1.92 0.38519287109375 0.166656494140625 -0.5672241210937414 +1.920125 0.3818359375 0.16522216796875 -0.5672241210937414 +1.92025 0.3818359375 0.16522216796875 -0.5672241210937414 +1.920375 0.378448486328125 0.16375732421875 -0.5672241210937414 +1.9205 0.375 0.162261962890625 -0.5672241210937414 +1.920625 0.375 0.162261962890625 -0.5672241210937414 +1.92075 0.37152099609375 0.160736083984375 -0.5672241210937414 +1.920875 0.37152099609375 0.160736083984375 -0.5672241210937414 +1.921 0.36798095703125 0.159210205078125 -0.5672241210937414 +1.921125 0.36444091796875 0.157684326171875 -0.5672241210937414 +1.92125000000000016 0.36444091796875 0.157684326171875 -0.5672241210937414 +1.921375 0.360809326171875 0.1561279296875 -0.5672241210937414 +1.9215 0.360809326171875 0.1561279296875 -0.5672241210937414 +1.92162500000000016 0.357177734375 0.154541015625 -0.5672241210937414 +1.92175 0.353485107421875 0.1529541015625 -0.5672241210937414 +1.921875 0.353485107421875 0.1529541015625 -0.5672241210937414 +1.922 0.349761962890625 0.151336669921875 -0.5672241210937414 +1.922125 0.349761962890625 0.151336669921875 -0.5672241210937414 +1.92225 0.34600830078125 0.14971923828125 -0.5672241210937414 +1.922375 0.34222412109375 0.1480712890625 -0.5672241210937414 +1.9225 0.34222412109375 0.1480712890625 -0.5672241210937414 +1.922625 0.33837890625 0.14642333984375 -0.5672241210937414 +1.92275 0.33837890625 0.14642333984375 -0.5672241210937414 +1.92287500000000016 0.334503173828125 0.144744873046875 -0.5672241210937414 +1.923 0.330596923828125 0.143035888671875 -0.5672241210937414 +1.923125 0.330596923828125 0.143035888671875 -0.5672241210937414 +1.92325000000000016 0.32666015625 0.141326904296875 -0.5672241210937414 +1.923375 0.32666015625 0.141326904296875 -0.5672241210937414 +1.9235 0.322662353515625 0.139617919921875 -0.5672241210937414 +1.92362500000000016 0.31866455078125 0.13787841796875 -0.5672241210937414 +1.92375 0.31866455078125 0.13787841796875 -0.5672241210937414 +1.923875 0.314605712890625 0.1361083984375 -0.5672241210937414 +1.924 0.314605712890625 0.1361083984375 -0.5672241210937414 +1.924125 0.310516357421875 0.134368896484375 -0.5672241210937414 +1.92425 0.306396484375 0.132568359375 -0.5672241210937414 +1.924375 0.306396484375 0.132568359375 -0.5672241210937414 +1.9245 0.30224609375 0.130767822265625 -0.5672241210937414 +1.924625 0.30224609375 0.130767822265625 -0.5672241210937414 +1.92475 0.298065185546875 0.12896728515625 -0.5672241210937414 +1.92487500000000016 0.2938232421875 0.12713623046875 -0.5672241210937414 +1.925 0.2938232421875 0.12713623046875 -0.5672241210937414 +1.925125 0.289581298828125 0.12530517578125 -0.5672241210937414 +1.92525000000000016 0.289581298828125 0.12530517578125 -0.5672241210937414 +1.925375 0.285308837890625 0.123443603515625 -0.5672241210937414 +1.9255 0.280975341796875 0.12158203125 -0.5672241210937414 +1.92562500000000016 0.280975341796875 0.12158203125 -0.5672241210937414 +1.92575 0.276641845703125 0.11968994140625 -0.5672241210937414 +1.925875 0.276641845703125 0.11968994140625 -0.5672241210937414 +1.926 0.27227783203125 0.1177978515625 -0.5672241210937414 +1.926125 0.267852783203125 0.11590576171875 -0.5672241210937414 +1.92625 0.267852783203125 0.11590576171875 -0.5672241210937414 +1.926375 0.263427734375 0.113983154296875 -0.5672241210937414 +1.9265 0.263427734375 0.113983154296875 -0.5672241210937414 +1.926625 0.25897216796875 0.112060546875 -0.5672241210937414 +1.92675 0.25445556640625 0.110107421875 -0.5672241210937414 +1.92687500000000016 0.25445556640625 0.110107421875 -0.5672241210937414 +1.927 0.249969482421875 0.108154296875 -0.5672241210937414 +1.927125 0.249969482421875 0.108154296875 -0.5672241210937414 +1.92725000000000016 0.24542236328125 0.106170654296875 -0.5672241210937414 +1.927375 0.2408447265625 0.10418701171875 -0.5672241210937414 +1.9275 0.2408447265625 0.10418701171875 -0.5672241210937414 +1.92762500000000016 0.236236572265625 0.102203369140625 -0.5672241210937414 +1.92775 0.236236572265625 0.102203369140625 -0.5672241210937414 +1.927875 0.231597900390625 0.1002197265625 -0.5672241210937414 +1.928 0.226959228515625 0.09820556640625 -0.5672241210937414 +1.928125 0.226959228515625 0.09820556640625 -0.5672241210937414 +1.92825 0.2222900390625 0.096160888671875 -0.5672241210937414 +1.928375 0.2222900390625 0.096160888671875 -0.5672241210937414 +1.9285 0.21759033203125 0.094146728515625 -0.5672241210937414 +1.928625 0.212860107421875 0.09210205078125 -0.5672241210937414 +1.92875 0.212860107421875 0.09210205078125 -0.5672241210937414 +1.92887500000000016 0.208099365234375 0.09002685546875 -0.5672241210937414 +1.929 0.208099365234375 0.09002685546875 -0.5672241210937414 +1.929125 0.203338623046875 0.087982177734375 -0.5672241210937414 +1.92925000000000016 0.19854736328125 0.085906982421875 -0.5672241210937414 +1.929375 0.19854736328125 0.085906982421875 -0.5672241210937414 +1.9295 0.1937255859375 0.08380126953125 -0.5672241210937414 +1.929625000000000256 0.1937255859375 0.08380126953125 -0.5672241210937414 +1.92975 0.188873291015625 0.08172607421875 -0.5672241210937414 +1.929875 0.18402099609375 0.079620361328125 -0.5672241210937414 +1.93 0.18402099609375 0.079620361328125 -0.5672241210937414 +1.930125 0.17913818359375 0.0775146484375 -0.5672241210937414 +1.93025 0.17913818359375 0.0775146484375 -0.5672241210937414 +1.930375 0.17425537109375 0.07537841796875 -0.5672241210937414 +1.9305 0.169342041015625 0.073272705078125 -0.5672241210937414 +1.930625 0.169342041015625 0.073272705078125 -0.5672241210937414 +1.93075 0.164398193359375 0.071136474609375 -0.5672241210937414 +1.93087500000000016 0.164398193359375 0.071136474609375 -0.5672241210937414 +1.931 0.159454345703125 0.0689697265625 -0.5672241210937414 +1.931125 0.15447998046875 0.06683349609375 -0.5672241210937414 +1.93125000000000016 0.15447998046875 0.06683349609375 -0.5672241210937414 +1.931375 0.14947509765625 0.064666748046875 -0.5672241210937414 +1.9315 0.14947509765625 0.064666748046875 -0.5672241210937414 +1.931625000000000256 0.14447021484375 0.0625 -0.5672241210937414 +1.93175 0.13946533203125 0.060333251953125 -0.5672241210937414 +1.931875 0.13946533203125 0.060333251953125 -0.5672241210937414 +1.932 0.134429931640625 0.05816650390625 -0.5672241210937414 +1.932125 0.134429931640625 0.05816650390625 -0.5672241210937414 +1.93225 0.129364013671875 0.05596923828125 -0.5672241210937414 +1.932375 0.124298095703125 0.05377197265625 -0.5672241210937414 +1.9325 0.124298095703125 0.05377197265625 -0.5672241210937414 +1.932625 0.119232177734375 0.05157470703125 -0.5672241210937414 +1.93275 0.119232177734375 0.05157470703125 -0.5672241210937414 +1.93287500000000016 0.1141357421875 0.04937744140625 -0.5672241210937414 +1.933 0.109039306640625 0.04718017578125 -0.5672241210937414 +1.933125 0.109039306640625 0.04718017578125 -0.5672241210937414 +1.93325000000000016 0.103912353515625 0.044952392578125 -0.5672241210937414 +1.933375 0.103912353515625 0.044952392578125 -0.5672241210937414 +1.9335 0.098785400390625 0.042755126953125 -0.5672241210937414 +1.933625000000000256 0.093658447265625 0.04052734375 -0.5672241210937414 +1.93375 0.093658447265625 0.04052734375 -0.5672241210937414 +1.933875 0.0885009765625 0.038299560546875 -0.5672241210937414 +1.934 0.0885009765625 0.038299560546875 -0.5672241210937414 +1.934125 0.083343505859375 0.03607177734375 -0.5672241210937414 +1.93425 0.07818603515625 0.0338134765625 -0.5672241210937414 +1.934375 0.07818603515625 0.0338134765625 -0.5672241210937414 +1.9345 0.072998046875 0.031585693359375 -0.5672241210937414 +1.934625 0.072998046875 0.031585693359375 -0.5672241210937414 +1.93475 0.06781005859375 0.029327392578125 -0.5672241210937414 +1.93487500000000016 0.0626220703125 0.027099609375 -0.5672241210937414 +1.935 0.0626220703125 0.027099609375 -0.5672241210937414 +1.935125 0.05743408203125 0.02484130859375 -0.5672241210937414 +1.93525000000000016 0.05743408203125 0.02484130859375 -0.5672241210937414 +1.935375 0.05224609375 0.0225830078125 -0.5672241210937414 +1.9355 0.047027587890625 0.02032470703125 -0.5672241210937414 +1.935625000000000256 0.047027587890625 0.02032470703125 -0.5672241210937414 +1.93575 0.04180908203125 0.01806640625 -0.5672241210937414 +1.935875 0.04180908203125 0.01806640625 -0.5672241210937414 +1.936 0.036590576171875 0.01580810546875 -0.5672241210937414 +1.936125 0.0313720703125 0.013580322265625 -0.5672241210937414 +1.93625 0.0313720703125 0.013580322265625 -0.5672241210937414 +1.936375 0.026123046875 0.01129150390625 -0.5672241210937414 +1.9365 0.026123046875 0.01129150390625 -0.5672241210937414 +1.936625 0.020904541015625 0.009033203125 -0.5672241210937414 +1.93675 0.01568603515625 0.00677490234375 -0.5672241210937414 +1.93687500000000016 0.01568603515625 0.00677490234375 -0.5672241210937414 +1.937 0.01043701171875 0.0045166015625 -0.5672241210937414 +1.937125 0.01043701171875 0.0045166015625 -0.5672241210937414 +1.93725000000000016 0.005218505859375 0.00225830078125 -0.5672241210937414 +1.937375 0.0 0.0 -0.5672241210937414 +1.9375 0.0 0.0 -0.5672241210937414 +1.937625 -0.005218505859375 -0.00225830078125 -0.5672241210937414 +1.93775 -0.005218505859375 -0.00225830078125 -0.5672241210937414 +1.937875 -0.01043701171875 -0.0045166015625 -0.5672241210937414 +1.938 -0.01568603515625 -0.00677490234375 -0.5672241210937414 +1.938125 -0.01568603515625 -0.00677490234375 -0.5672241210937414 +1.93825 -0.020904541015625 -0.009033203125 -0.5672241210937414 +1.938375 -0.020904541015625 -0.009033203125 -0.5672241210937414 +1.93850000000000016 -0.026123046875 -0.01129150390625 -0.5672241210937414 +1.938625 -0.0313720703125 -0.013580322265625 -0.5672241210937414 +1.93875 -0.0313720703125 -0.013580322265625 -0.5672241210937414 +1.93887500000000016 -0.036590576171875 -0.01580810546875 -0.5672241210937414 +1.939 -0.036590576171875 -0.01580810546875 -0.5672241210937414 +1.939125 -0.04180908203125 -0.01806640625 -0.5672241210937414 +1.93925000000000016 -0.047027587890625 -0.02032470703125 -0.5672241210937414 +1.939375 -0.047027587890625 -0.02032470703125 -0.5672241210937414 +1.9395 -0.05224609375 -0.0225830078125 -0.5672241210937414 +1.939625 -0.05224609375 -0.0225830078125 -0.5672241210937414 +1.93975 -0.05743408203125 -0.02484130859375 -0.5672241210937414 +1.939875 -0.0626220703125 -0.027099609375 -0.5672241210937414 +1.94 -0.0626220703125 -0.027099609375 -0.5672241210937414 +1.940125 -0.06781005859375 -0.029327392578125 -0.5672241210937414 +1.94025 -0.06781005859375 -0.029327392578125 -0.5672241210937414 +1.940375 -0.072998046875 -0.031585693359375 -0.5672241210937414 +1.94050000000000016 -0.07818603515625 -0.0338134765625 -0.5672241210937414 +1.940625 -0.07818603515625 -0.0338134765625 -0.5672241210937414 +1.94075 -0.083343505859375 -0.03607177734375 -0.5672241210937414 +1.94087500000000016 -0.083343505859375 -0.03607177734375 -0.5672241210937414 +1.941 -0.0885009765625 -0.038299560546875 -0.5672241210937414 +1.941125 -0.093658447265625 -0.04052734375 -0.5672241210937414 +1.94125000000000016 -0.093658447265625 -0.04052734375 -0.5672241210937414 +1.941375 -0.098785400390625 -0.042755126953125 -0.5672241210937414 +1.9415 -0.098785400390625 -0.042755126953125 -0.5672241210937414 +1.941625 -0.103912353515625 -0.044952392578125 -0.5672241210937414 +1.94175 -0.109039306640625 -0.04718017578125 -0.5672241210937414 +1.941875 -0.109039306640625 -0.04718017578125 -0.5672241210937414 +1.942 -0.1141357421875 -0.04937744140625 -0.5672241210937414 +1.942125 -0.1141357421875 -0.04937744140625 -0.5672241210937414 +1.94225 -0.119232177734375 -0.05157470703125 -0.5672241210937414 +1.942375 -0.124298095703125 -0.05377197265625 -0.5672241210937414 +1.94250000000000016 -0.124298095703125 -0.05377197265625 -0.5672241210937414 +1.942625 -0.129364013671875 -0.05596923828125 -0.5672241210937414 +1.94275 -0.129364013671875 -0.05596923828125 -0.5672241210937414 +1.94287500000000016 -0.134429931640625 -0.05816650390625 -0.5672241210937414 +1.943 -0.13946533203125 -0.060333251953125 -0.5672241210937414 +1.943125 -0.13946533203125 -0.060333251953125 -0.5672241210937414 +1.94325000000000016 -0.14447021484375 -0.0625 -0.5672241210937414 +1.943375 -0.14447021484375 -0.0625 -0.5672241210937414 +1.9435 -0.14947509765625 -0.064666748046875 -0.5672241210937414 +1.943625 -0.15447998046875 -0.06683349609375 -0.5672241210937414 +1.94375 -0.15447998046875 -0.06683349609375 -0.5672241210937414 +1.943875 -0.159454345703125 -0.0689697265625 -0.5672241210937414 +1.944 -0.159454345703125 -0.0689697265625 -0.5672241210937414 +1.944125 -0.164398193359375 -0.071136474609375 -0.5672241210937414 +1.94425 -0.169342041015625 -0.073272705078125 -0.5672241210937414 +1.944375 -0.169342041015625 -0.073272705078125 -0.5672241210937414 +1.94450000000000016 -0.17425537109375 -0.07537841796875 -0.5672241210937414 +1.944625 -0.17425537109375 -0.07537841796875 -0.5672241210937414 +1.94475 -0.17913818359375 -0.0775146484375 -0.5672241210937414 +1.94487500000000016 -0.18402099609375 -0.079620361328125 -0.5672241210937414 +1.945 -0.18402099609375 -0.079620361328125 -0.5672241210937414 +1.945125 -0.188873291015625 -0.08172607421875 -0.5672241210937414 +1.945250000000000256 -0.188873291015625 -0.08172607421875 -0.5672241210937414 +1.945375 -0.1937255859375 -0.08380126953125 -0.5672241210937414 +1.9455 -0.19854736328125 -0.085906982421875 -0.5672241210937414 +1.945625 -0.19854736328125 -0.085906982421875 -0.5672241210937414 +1.94575 -0.203338623046875 -0.087982177734375 -0.5672241210937414 +1.945875 -0.203338623046875 -0.087982177734375 -0.5672241210937414 +1.946 -0.208099365234375 -0.09002685546875 -0.5672241210937414 +1.946125 -0.212860107421875 -0.09210205078125 -0.5672241210937414 +1.94625 -0.212860107421875 -0.09210205078125 -0.5672241210937414 +1.946375 -0.21759033203125 -0.094146728515625 -0.5672241210937414 +1.94650000000000016 -0.21759033203125 -0.094146728515625 -0.5672241210937414 +1.946625 -0.2222900390625 -0.096160888671875 -0.5672241210937414 +1.94675 -0.226959228515625 -0.09820556640625 -0.5672241210937414 +1.94687500000000016 -0.226959228515625 -0.09820556640625 -0.5672241210937414 +1.947 -0.231597900390625 -0.1002197265625 -0.5672241210937414 +1.947125 -0.231597900390625 -0.1002197265625 -0.5672241210937414 +1.947250000000000256 -0.236236572265625 -0.102203369140625 -0.5672241210937414 +1.947375 -0.2408447265625 -0.10418701171875 -0.5672241210937414 +1.9475 -0.2408447265625 -0.10418701171875 -0.5672241210937414 +1.947625 -0.24542236328125 -0.106170654296875 -0.5672241210937414 +1.94775 -0.24542236328125 -0.106170654296875 -0.5672241210937414 +1.947875 -0.249969482421875 -0.108154296875 -0.5672241210937414 +1.948 -0.25445556640625 -0.110107421875 -0.5672241210937414 +1.948125 -0.25445556640625 -0.110107421875 -0.5672241210937414 +1.94825 -0.25897216796875 -0.112060546875 -0.5672241210937414 +1.948375 -0.25897216796875 -0.112060546875 -0.5672241210937414 +1.94850000000000016 -0.263427734375 -0.113983154296875 -0.5672241210937414 +1.948625 -0.267852783203125 -0.11590576171875 -0.5672241210937414 +1.94875 -0.267852783203125 -0.11590576171875 -0.5672241210937414 +1.94887500000000016 -0.27227783203125 -0.1177978515625 -0.5672241210937414 +1.949 -0.27227783203125 -0.1177978515625 -0.5672241210937414 +1.949125 -0.276641845703125 -0.11968994140625 -0.5672241210937414 +1.949250000000000256 -0.280975341796875 -0.12158203125 -0.5672241210937414 +1.949375 -0.280975341796875 -0.12158203125 -0.5672241210937414 +1.9495 -0.285308837890625 -0.123443603515625 -0.5672241210937414 +1.949625 -0.285308837890625 -0.123443603515625 -0.5672241210937414 +1.94975 -0.289581298828125 -0.12530517578125 -0.5672241210937414 +1.949875 -0.2938232421875 -0.12713623046875 -0.5672241210937414 +1.95 -0.2938232421875 -0.12713623046875 -0.5672241210937414 +1.950125 -0.298065185546875 -0.12896728515625 -0.5672241210937414 +1.95025 -0.298065185546875 -0.12896728515625 -0.5672241210937414 +1.950375 -0.30224609375 -0.130767822265625 -0.5672241210937414 +1.95050000000000016 -0.306396484375 -0.132568359375 -0.5672241210937414 +1.950625 -0.306396484375 -0.132568359375 -0.5672241210937414 +1.95075 -0.310516357421875 -0.134368896484375 -0.5672241210937414 +1.95087500000000016 -0.310516357421875 -0.134368896484375 -0.5672241210937414 +1.951 -0.314605712890625 -0.1361083984375 -0.5672241210937414 +1.951125 -0.31866455078125 -0.13787841796875 -0.5672241210937414 +1.951250000000000256 -0.31866455078125 -0.13787841796875 -0.5672241210937414 +1.951375 -0.322662353515625 -0.139617919921875 -0.5672241210937414 +1.9515 -0.322662353515625 -0.139617919921875 -0.5672241210937414 +1.951625 -0.32666015625 -0.141326904296875 -0.5672241210937414 +1.95175 -0.330596923828125 -0.143035888671875 -0.5672241210937414 +1.951875 -0.330596923828125 -0.143035888671875 -0.5672241210937414 +1.952 -0.334503173828125 -0.2677001953125 -0.1996826171874888 +1.952125 -0.334503173828125 -0.2677001953125 -0.1996826171874888 +1.95225 -0.33837890625 -0.27081298828125 -0.1996826171874888 +1.952375 -0.34222412109375 -0.27386474609375 -0.1996826171874888 +1.95250000000000016 -0.34222412109375 -0.27386474609375 -0.1996826171874888 +1.952625 -0.34600830078125 -0.27691650390625 -0.1996826171874888 +1.95275 -0.34600830078125 -0.27691650390625 -0.1996826171874888 +1.95287500000000016 -0.349761962890625 -0.2799072265625 -0.1996826171874888 +1.953 -0.353485107421875 -0.28289794921875 -0.1996826171874888 +1.953125 -0.353485107421875 -0.28289794921875 -0.1996826171874888 +1.95325 -0.357177734375 -0.285858154296875 -0.1996826171874888 +1.953375 -0.357177734375 -0.285858154296875 -0.1996826171874888 +1.9535 -0.360809326171875 -0.28875732421875 -0.1996826171874888 +1.953625 -0.36444091796875 -0.291656494140625 -0.1996826171874888 +1.95375 -0.36444091796875 -0.291656494140625 -0.1996826171874888 +1.953875 -0.36798095703125 -0.29449462890625 -0.1996826171874888 +1.954 -0.36798095703125 -0.29449462890625 -0.1996826171874888 +1.95412500000000016 -0.37152099609375 -0.29730224609375 -0.1996826171874888 +1.95425 -0.375 -0.30010986328125 -0.1996826171874888 +1.954375 -0.375 -0.30010986328125 -0.1996826171874888 +1.95450000000000016 -0.378448486328125 -0.3028564453125 -0.1996826171874888 +1.954625 -0.378448486328125 -0.3028564453125 -0.1996826171874888 +1.95475 -0.3818359375 -0.305572509765625 -0.1996826171874888 +1.95487500000000016 -0.38519287109375 -0.308258056640625 -0.1996826171874888 +1.955 -0.38519287109375 -0.308258056640625 -0.1996826171874888 +1.955125 -0.388519287109375 -0.3109130859375 -0.1996826171874888 +1.95525 -0.388519287109375 -0.3109130859375 -0.1996826171874888 +1.955375 -0.39178466796875 -0.31353759765625 -0.1996826171874888 +1.9555 -0.39501953125 -0.316131591796875 -0.1996826171874888 +1.955625 -0.39501953125 -0.316131591796875 -0.1996826171874888 +1.95575 -0.398193359375 -0.31866455078125 -0.1996826171874888 +1.955875 -0.398193359375 -0.31866455078125 -0.1996826171874888 +1.956 -0.401336669921875 -0.321197509765625 -0.1996826171874888 +1.95612500000000016 -0.404449462890625 -0.32366943359375 -0.1996826171874888 +1.95625 -0.404449462890625 -0.32366943359375 -0.1996826171874888 +1.956375 -0.407501220703125 -0.32611083984375 -0.1996826171874888 +1.95650000000000016 -0.407501220703125 -0.32611083984375 -0.1996826171874888 +1.956625 -0.4105224609375 -0.328521728515625 -0.1996826171874888 +1.95675 -0.413482666015625 -0.330902099609375 -0.1996826171874888 +1.95687500000000016 -0.413482666015625 -0.330902099609375 -0.1996826171874888 +1.957 -0.416412353515625 -0.333221435546875 -0.1996826171874888 +1.957125 -0.416412353515625 -0.333221435546875 -0.1996826171874888 +1.95725 -0.419281005859375 -0.335540771484375 -0.1996826171874888 +1.957375 -0.422119140625 -0.337799072265625 -0.1996826171874888 +1.9575 -0.422119140625 -0.337799072265625 -0.1996826171874888 +1.957625 -0.424896240234375 -0.34002685546875 -0.1996826171874888 +1.95775 -0.424896240234375 -0.34002685546875 -0.1996826171874888 +1.957875 -0.4276123046875 -0.34222412109375 -0.1996826171874888 +1.958 -0.4302978515625 -0.3443603515625 -0.1996826171874888 +1.95812500000000016 -0.4302978515625 -0.3443603515625 -0.1996826171874888 +1.95825 -0.432952880859375 -0.34649658203125 -0.1996826171874888 +1.958375 -0.432952880859375 -0.34649658203125 -0.1996826171874888 +1.95850000000000016 -0.435546875 -0.34857177734375 -0.1996826171874888 +1.958625 -0.438079833984375 -0.3505859375 -0.1996826171874888 +1.95875 -0.438079833984375 -0.3505859375 -0.1996826171874888 +1.95887500000000016 -0.440582275390625 -0.35260009765625 -0.1996826171874888 +1.959 -0.440582275390625 -0.35260009765625 -0.1996826171874888 +1.959125 -0.44305419921875 -0.35455322265625 -0.1996826171874888 +1.95925 -0.4454345703125 -0.356475830078125 -0.1996826171874888 +1.959375 -0.4454345703125 -0.356475830078125 -0.1996826171874888 +1.9595 -0.447784423828125 -0.358367919921875 -0.1996826171874888 +1.959625 -0.447784423828125 -0.358367919921875 -0.1996826171874888 +1.95975 -0.450103759765625 -0.360198974609375 -0.1996826171874888 +1.959875 -0.452362060546875 -0.36199951171875 -0.1996826171874888 +1.96 -0.452362060546875 -0.36199951171875 -0.1996826171874888 +1.96012500000000016 -0.454559326171875 -0.36376953125 -0.1996826171874888 +1.96025 -0.454559326171875 -0.36376953125 -0.1996826171874888 +1.960375 -0.45672607421875 -0.365509033203125 -0.1996826171874888 +1.96050000000000016 -0.458831787109375 -0.3671875 -0.1996826171874888 +1.960625 -0.458831787109375 -0.3671875 -0.1996826171874888 +1.96075 -0.46087646484375 -0.368804931640625 -0.1996826171874888 +1.960875000000000256 -0.46087646484375 -0.368804931640625 -0.1996826171874888 +1.961 -0.462890625 -0.37042236328125 -0.1996826171874888 +1.961125 -0.464813232421875 -0.371978759765625 -0.1996826171874888 +1.96125 -0.464813232421875 -0.371978759765625 -0.1996826171874888 +1.961375 -0.46673583984375 -0.373504638671875 -0.1996826171874888 +1.9615 -0.46673583984375 -0.373504638671875 -0.1996826171874888 +1.961625 -0.46856689453125 -0.374969482421875 -0.1996826171874888 +1.96175 -0.470367431640625 -0.376434326171875 -0.1996826171874888 +1.961875 -0.470367431640625 -0.376434326171875 -0.1996826171874888 +1.962 -0.472137451171875 -0.377838134765625 -0.1996826171874888 +1.96212500000000016 -0.472137451171875 -0.377838134765625 -0.1996826171874888 +1.96225 -0.47381591796875 -0.379180908203125 -0.1996826171874888 +1.962375 -0.4754638671875 -0.3804931640625 -0.1996826171874888 +1.96250000000000016 -0.4754638671875 -0.3804931640625 -0.1996826171874888 +1.962625 -0.47705078125 -0.38177490234375 -0.1996826171874888 +1.96275 -0.47705078125 -0.38177490234375 -0.1996826171874888 +1.962875000000000256 -0.478607177734375 -0.38299560546875 -0.1996826171874888 +1.963 -0.480072021484375 -0.384185791015625 -0.1996826171874888 +1.963125 -0.480072021484375 -0.384185791015625 -0.1996826171874888 +1.96325 -0.48150634765625 -0.385345458984375 -0.1996826171874888 +1.963375 -0.48150634765625 -0.385345458984375 -0.1996826171874888 +1.9635 -0.48291015625 -0.386444091796875 -0.1996826171874888 +1.963625 -0.484222412109375 -0.38751220703125 -0.1996826171874888 +1.96375 -0.484222412109375 -0.38751220703125 -0.1996826171874888 +1.963875 -0.485504150390625 -0.3885498046875 -0.1996826171874888 +1.964 -0.485504150390625 -0.3885498046875 -0.1996826171874888 +1.96412500000000016 -0.486724853515625 -0.3895263671875 -0.1996826171874888 +1.96425 -0.487884521484375 -0.39044189453125 -0.1996826171874888 +1.964375 -0.487884521484375 -0.39044189453125 -0.1996826171874888 +1.96450000000000016 -0.489013671875 -0.391326904296875 -0.1996826171874888 +1.964625 -0.489013671875 -0.391326904296875 -0.1996826171874888 +1.96475 -0.490081787109375 -0.392181396484375 -0.1996826171874888 +1.964875000000000256 -0.4910888671875 -0.39300537109375 -0.1996826171874888 +1.965 -0.4910888671875 -0.39300537109375 -0.1996826171874888 +1.965125 -0.492034912109375 -0.393768310546875 -0.1996826171874888 +1.96525 -0.492034912109375 -0.393768310546875 -0.1996826171874888 +1.965375 -0.492950439453125 -0.39447021484375 -0.1996826171874888 +1.9655 -0.4937744140625 -0.3951416015625 -0.1996826171874888 +1.965625 -0.4937744140625 -0.3951416015625 -0.1996826171874888 +1.96575 -0.49456787109375 -0.395782470703125 -0.1996826171874888 +1.965875 -0.49456787109375 -0.395782470703125 -0.1996826171874888 +1.966 -0.49530029296875 -0.3963623046875 -0.1996826171874888 +1.96612500000000016 -0.496002197265625 -0.39691162109375 -0.1996826171874888 +1.96625 -0.496002197265625 -0.39691162109375 -0.1996826171874888 +1.966375 -0.496612548828125 -0.397430419921875 -0.1996826171874888 +1.96650000000000016 -0.496612548828125 -0.397430419921875 -0.1996826171874888 +1.966625 -0.4971923828125 -0.39788818359375 -0.1996826171874888 +1.96675 -0.497711181640625 -0.3983154296875 -0.1996826171874888 +1.966875000000000256 -0.497711181640625 -0.3983154296875 -0.1996826171874888 +1.967 -0.498199462890625 -0.398681640625 -0.1996826171874888 +1.967125 -0.498199462890625 -0.398681640625 -0.1996826171874888 +1.96725 -0.49859619140625 -0.399017333984375 -0.1996826171874888 +1.967375 -0.49896240234375 -0.3992919921875 -0.1996826171874888 +1.9675 -0.49896240234375 -0.3992919921875 -0.1996826171874888 +1.967625 -0.499267578125 -0.3995361328125 -0.1996826171874888 +1.96775 -0.499267578125 -0.3995361328125 -0.1996826171874888 +1.967875 -0.49951171875 -0.39971923828125 -0.1996826171874888 +1.968 -0.49969482421875 -0.399871826171875 -0.1996826171874888 +1.96812500000000016 -0.49969482421875 -0.399871826171875 -0.1996826171874888 +1.96825 -0.49981689453125 -0.399993896484375 -0.1996826171874888 +1.968375 -0.49981689453125 -0.399993896484375 -0.1996826171874888 +1.96850000000000016 -0.499908447265625 -0.400054931640625 -0.1996826171874888 +1.968625 -0.49993896484375 -0.40008544921875 -0.1996826171874888 +1.96875 -0.49993896484375 -0.40008544921875 -0.1996826171874888 +1.968875 -0.499908447265625 -0.400054931640625 -0.1996826171874888 +1.969 -0.499908447265625 -0.400054931640625 -0.1996826171874888 +1.969125 -0.49981689453125 -0.399993896484375 -0.1996826171874888 +1.96925 -0.49969482421875 -0.399871826171875 -0.1996826171874888 +1.969375 -0.49969482421875 -0.399871826171875 -0.1996826171874888 +1.9695 -0.49951171875 -0.39971923828125 -0.1996826171874888 +1.969625 -0.49951171875 -0.39971923828125 -0.1996826171874888 +1.96975000000000016 -0.499267578125 -0.3995361328125 -0.1996826171874888 +1.969875 -0.49896240234375 -0.3992919921875 -0.1996826171874888 +1.97 -0.49896240234375 -0.3992919921875 -0.1996826171874888 +1.97012500000000016 -0.49859619140625 -0.399017333984375 -0.1996826171874888 +1.97025 -0.49859619140625 -0.399017333984375 -0.1996826171874888 +1.970375 -0.498199462890625 -0.398681640625 -0.1996826171874888 +1.97050000000000016 -0.497711181640625 -0.3983154296875 -0.1996826171874888 +1.970625 -0.497711181640625 -0.3983154296875 -0.1996826171874888 +1.97075 -0.4971923828125 -0.39788818359375 -0.1996826171874888 +1.970875 -0.4971923828125 -0.39788818359375 -0.1996826171874888 +1.971 -0.496612548828125 -0.397430419921875 -0.1996826171874888 +1.971125 -0.496002197265625 -0.39691162109375 -0.1996826171874888 +1.97125 -0.496002197265625 -0.39691162109375 -0.1996826171874888 +1.971375 -0.49530029296875 -0.3963623046875 -0.1996826171874888 +1.9715 -0.49530029296875 -0.3963623046875 -0.1996826171874888 +1.971625 -0.49456787109375 -0.395782470703125 -0.1996826171874888 +1.97175000000000016 -0.4937744140625 -0.3951416015625 -0.1996826171874888 +1.971875 -0.4937744140625 -0.3951416015625 -0.1996826171874888 +1.972 -0.492950439453125 -0.39447021484375 -0.1996826171874888 +1.97212500000000016 -0.492950439453125 -0.39447021484375 -0.1996826171874888 +1.97225 -0.492034912109375 -0.393768310546875 -0.1996826171874888 +1.972375 -0.4910888671875 -0.39300537109375 -0.1996826171874888 +1.97250000000000016 -0.4910888671875 -0.39300537109375 -0.1996826171874888 +1.972625 -0.490081787109375 -0.392181396484375 -0.1996826171874888 +1.97275 -0.490081787109375 -0.392181396484375 -0.1996826171874888 +1.972875 -0.489013671875 -0.391326904296875 -0.1996826171874888 +1.973 -0.487884521484375 -0.39044189453125 -0.1996826171874888 +1.973125 -0.487884521484375 -0.39044189453125 -0.1996826171874888 +1.97325 -0.486724853515625 -0.3895263671875 -0.1996826171874888 +1.973375 -0.486724853515625 -0.3895263671875 -0.1996826171874888 +1.9735 -0.485504150390625 -0.3885498046875 -0.1996826171874888 +1.973625 -0.484222412109375 -0.38751220703125 -0.1996826171874888 +1.97375000000000016 -0.484222412109375 -0.38751220703125 -0.1996826171874888 +1.973875 -0.48291015625 -0.386444091796875 -0.1996826171874888 +1.974 -0.48291015625 -0.386444091796875 -0.1996826171874888 +1.97412500000000016 -0.48150634765625 -0.385345458984375 -0.1996826171874888 +1.97425 -0.480072021484375 -0.384185791015625 -0.1996826171874888 +1.974375 -0.480072021484375 -0.384185791015625 -0.1996826171874888 +1.97450000000000016 -0.478607177734375 -0.38299560546875 -0.1996826171874888 +1.974625 -0.478607177734375 -0.38299560546875 -0.1996826171874888 +1.97475 -0.47705078125 -0.38177490234375 -0.1996826171874888 +1.974875 -0.4754638671875 -0.3804931640625 -0.1996826171874888 +1.975 -0.4754638671875 -0.3804931640625 -0.1996826171874888 +1.975125 -0.47381591796875 -0.379180908203125 -0.1996826171874888 +1.97525 -0.47381591796875 -0.379180908203125 -0.1996826171874888 +1.975375 -0.472137451171875 -0.377838134765625 -0.1996826171874888 +1.9755 -0.470367431640625 -0.376434326171875 -0.1996826171874888 +1.975625 -0.470367431640625 -0.376434326171875 -0.1996826171874888 +1.97575000000000016 -0.46856689453125 -0.374969482421875 -0.1996826171874888 +1.975875 -0.46856689453125 -0.374969482421875 -0.1996826171874888 +1.976 -0.46673583984375 -0.373504638671875 -0.1996826171874888 +1.97612500000000016 -0.464813232421875 -0.371978759765625 -0.1996826171874888 +1.97625 -0.464813232421875 -0.371978759765625 -0.1996826171874888 +1.976375 -0.462890625 -0.37042236328125 -0.1996826171874888 +1.976500000000000256 -0.462890625 -0.37042236328125 -0.1996826171874888 +1.976625 -0.46087646484375 -0.368804931640625 -0.1996826171874888 +1.97675 -0.458831787109375 -0.3671875 -0.1996826171874888 +1.976875 -0.458831787109375 -0.3671875 -0.1996826171874888 +1.977 -0.45672607421875 -0.365509033203125 -0.1996826171874888 +1.977125 -0.45672607421875 -0.365509033203125 -0.1996826171874888 +1.97725 -0.454559326171875 -0.36376953125 -0.1996826171874888 +1.977375 -0.452362060546875 -0.36199951171875 -0.1996826171874888 +1.9775 -0.452362060546875 -0.36199951171875 -0.1996826171874888 +1.977625 -0.450103759765625 -0.360198974609375 -0.1996826171874888 +1.97775000000000016 -0.450103759765625 -0.360198974609375 -0.1996826171874888 +1.977875 -0.447784423828125 -0.358367919921875 -0.1996826171874888 +1.978 -0.4454345703125 -0.356475830078125 -0.1996826171874888 +1.97812500000000016 -0.4454345703125 -0.356475830078125 -0.1996826171874888 +1.97825 -0.44305419921875 -0.35455322265625 -0.1996826171874888 +1.978375 -0.44305419921875 -0.35455322265625 -0.1996826171874888 +1.978500000000000256 -0.440582275390625 -0.35260009765625 -0.1996826171874888 +1.978625 -0.438079833984375 -0.3505859375 -0.1996826171874888 +1.97875 -0.438079833984375 -0.3505859375 -0.1996826171874888 +1.978875 -0.435546875 -0.34857177734375 -0.1996826171874888 +1.979 -0.435546875 -0.34857177734375 -0.1996826171874888 +1.979125 -0.432952880859375 -0.34649658203125 -0.1996826171874888 +1.97925 -0.4302978515625 -0.3443603515625 -0.1996826171874888 +1.979375 -0.4302978515625 -0.3443603515625 -0.1996826171874888 +1.9795 -0.4276123046875 -0.34222412109375 -0.1996826171874888 +1.979625 -0.4276123046875 -0.34222412109375 -0.1996826171874888 +1.97975000000000016 -0.424896240234375 -0.34002685546875 -0.1996826171874888 +1.979875 -0.422119140625 -0.337799072265625 -0.1996826171874888 +1.98 -0.422119140625 -0.337799072265625 -0.1996826171874888 +1.98012500000000016 -0.419281005859375 -0.335540771484375 -0.1996826171874888 +1.98025 -0.419281005859375 -0.335540771484375 -0.1996826171874888 +1.980375 -0.416412353515625 -0.333221435546875 -0.1996826171874888 +1.980500000000000256 -0.413482666015625 -0.330902099609375 -0.1996826171874888 +1.980625 -0.413482666015625 -0.330902099609375 -0.1996826171874888 +1.98075 -0.4105224609375 -0.328521728515625 -0.1996826171874888 +1.980875 -0.4105224609375 -0.328521728515625 -0.1996826171874888 +1.981 -0.407501220703125 -0.32611083984375 -0.1996826171874888 +1.981125 -0.404449462890625 -0.32366943359375 -0.1996826171874888 +1.98125 -0.404449462890625 -0.32366943359375 -0.1996826171874888 +1.981375 -0.401336669921875 -0.321197509765625 -0.1996826171874888 +1.9815 -0.401336669921875 -0.321197509765625 -0.1996826171874888 +1.981625 -0.398193359375 -0.31866455078125 -0.1996826171874888 +1.98175000000000016 -0.39501953125 -0.316131591796875 -0.1996826171874888 +1.981875 -0.39501953125 -0.316131591796875 -0.1996826171874888 +1.982 -0.39178466796875 -0.31353759765625 -0.1996826171874888 +1.98212500000000016 -0.39178466796875 -0.31353759765625 -0.1996826171874888 +1.98225 -0.388519287109375 -0.3109130859375 -0.1996826171874888 +1.982375 -0.38519287109375 -0.308258056640625 -0.1996826171874888 +1.982500000000000256 -0.38519287109375 -0.308258056640625 -0.1996826171874888 +1.982625 -0.3818359375 -0.305572509765625 -0.1996826171874888 +1.98275 -0.3818359375 -0.305572509765625 -0.1996826171874888 +1.982875 -0.378448486328125 -0.3028564453125 -0.1996826171874888 +1.983 -0.375 -0.30010986328125 -0.1996826171874888 +1.983125 -0.375 -0.30010986328125 -0.1996826171874888 +1.98325 -0.37152099609375 -0.29730224609375 -0.1996826171874888 +1.983375 -0.37152099609375 -0.29730224609375 -0.1996826171874888 +1.9835 -0.36798095703125 -0.29449462890625 -0.1996826171874888 +1.983625 -0.36444091796875 -0.291656494140625 -0.1996826171874888 +1.98375000000000016 -0.36444091796875 -0.291656494140625 -0.1996826171874888 +1.983875 -0.360809326171875 -0.28875732421875 -0.1996826171874888 +1.984 -0.28875732421875 -0.360809326171875 0.1996826171875111 +1.98412500000000016 -0.285858154296875 -0.357177734375 0.1996826171875111 +1.98425 -0.28289794921875 -0.353485107421875 0.1996826171875111 +1.984375 -0.28289794921875 -0.353485107421875 0.1996826171875111 +1.9845 -0.2799072265625 -0.349761962890625 0.1996826171875111 +1.984625 -0.2799072265625 -0.349761962890625 0.1996826171875111 +1.98475 -0.27691650390625 -0.34600830078125 0.1996826171875111 +1.984875 -0.27386474609375 -0.34222412109375 0.1996826171875111 +1.985 -0.27386474609375 -0.34222412109375 0.1996826171875111 +1.985125 -0.27081298828125 -0.33837890625 0.1996826171875111 +1.98525 -0.27081298828125 -0.33837890625 0.1996826171875111 +1.98537500000000016 -0.2677001953125 -0.334503173828125 0.1996826171875111 +1.9855 -0.26458740234375 -0.330596923828125 0.1996826171875111 +1.985625 -0.26458740234375 -0.330596923828125 0.1996826171875111 +1.98575000000000016 -0.26141357421875 -0.32666015625 0.1996826171875111 +1.985875 -0.26141357421875 -0.32666015625 0.1996826171875111 +1.986 -0.25823974609375 -0.322662353515625 0.1996826171875111 +1.98612500000000016 -0.2550048828125 -0.31866455078125 0.1996826171875111 +1.98625 -0.2550048828125 -0.31866455078125 0.1996826171875111 +1.986375 -0.25177001953125 -0.314605712890625 0.1996826171875111 +1.9865 -0.25177001953125 -0.314605712890625 0.1996826171875111 +1.986625 -0.248504638671875 -0.310516357421875 0.1996826171875111 +1.98675 -0.245208740234375 -0.306396484375 0.1996826171875111 +1.986875 -0.245208740234375 -0.306396484375 0.1996826171875111 +1.987 -0.24188232421875 -0.30224609375 0.1996826171875111 +1.987125 -0.24188232421875 -0.30224609375 0.1996826171875111 +1.98725 -0.238525390625 -0.298065185546875 0.1996826171875111 +1.98737500000000016 -0.235137939453125 -0.2938232421875 0.1996826171875111 +1.9875 -0.235137939453125 -0.2938232421875 0.1996826171875111 +1.987625 -0.23175048828125 -0.289581298828125 0.1996826171875111 +1.98775000000000016 -0.23175048828125 -0.289581298828125 0.1996826171875111 +1.987875 -0.22833251953125 -0.285308837890625 0.1996826171875111 +1.988 -0.224853515625 -0.280975341796875 0.1996826171875111 +1.98812500000000016 -0.224853515625 -0.280975341796875 0.1996826171875111 +1.98825 -0.22137451171875 -0.276641845703125 0.1996826171875111 +1.988375 -0.22137451171875 -0.276641845703125 0.1996826171875111 +1.9885 -0.2178955078125 -0.27227783203125 0.1996826171875111 +1.988625 -0.21435546875 -0.267852783203125 0.1996826171875111 +1.98875 -0.21435546875 -0.267852783203125 0.1996826171875111 +1.988875 -0.2108154296875 -0.263427734375 0.1996826171875111 +1.989 -0.2108154296875 -0.263427734375 0.1996826171875111 +1.989125 -0.207244873046875 -0.25897216796875 0.1996826171875111 +1.98925 -0.203643798828125 -0.25445556640625 0.1996826171875111 +1.98937500000000016 -0.203643798828125 -0.25445556640625 0.1996826171875111 +1.9895 -0.200042724609375 -0.249969482421875 0.1996826171875111 +1.989625 -0.200042724609375 -0.249969482421875 0.1996826171875111 +1.98975000000000016 -0.196380615234375 -0.24542236328125 0.1996826171875111 +1.989875 -0.192718505859375 -0.2408447265625 0.1996826171875111 +1.99 -0.192718505859375 -0.2408447265625 0.1996826171875111 +1.99012500000000016 -0.189056396484375 -0.236236572265625 0.1996826171875111 +1.99025 -0.189056396484375 -0.236236572265625 0.1996826171875111 +1.990375 -0.185333251953125 -0.231597900390625 0.1996826171875111 +1.9905 -0.181610107421875 -0.226959228515625 0.1996826171875111 +1.990625 -0.181610107421875 -0.226959228515625 0.1996826171875111 +1.99075 -0.177886962890625 -0.2222900390625 0.1996826171875111 +1.990875 -0.177886962890625 -0.2222900390625 0.1996826171875111 +1.991 -0.17413330078125 -0.21759033203125 0.1996826171875111 +1.991125 -0.17034912109375 -0.212860107421875 0.1996826171875111 +1.99125 -0.17034912109375 -0.212860107421875 0.1996826171875111 +1.99137500000000016 -0.166534423828125 -0.208099365234375 0.1996826171875111 +1.9915 -0.166534423828125 -0.208099365234375 0.1996826171875111 +1.991625 -0.1627197265625 -0.203338623046875 0.1996826171875111 +1.99175000000000016 -0.15887451171875 -0.19854736328125 0.1996826171875111 +1.991875 -0.15887451171875 -0.19854736328125 0.1996826171875111 +1.992 -0.155029296875 -0.1937255859375 0.1996826171875111 +1.992125000000000256 -0.155029296875 -0.1937255859375 0.1996826171875111 +1.99225 -0.151153564453125 -0.188873291015625 0.1996826171875111 +1.992375 -0.14727783203125 -0.18402099609375 0.1996826171875111 +1.9925 -0.14727783203125 -0.18402099609375 0.1996826171875111 +1.992625 -0.14337158203125 -0.17913818359375 0.1996826171875111 +1.99275 -0.14337158203125 -0.17913818359375 0.1996826171875111 +1.992875 -0.139434814453125 -0.17425537109375 0.1996826171875111 +1.993 -0.135498046875 -0.169342041015625 0.1996826171875111 +1.993125 -0.135498046875 -0.169342041015625 0.1996826171875111 +1.99325 -0.131561279296875 -0.164398193359375 0.1996826171875111 +1.99337500000000016 -0.131561279296875 -0.164398193359375 0.1996826171875111 +1.9935 -0.127593994140625 -0.159454345703125 0.1996826171875111 +1.993625 -0.123626708984375 -0.15447998046875 0.1996826171875111 +1.99375000000000016 -0.123626708984375 -0.15447998046875 0.1996826171875111 +1.993875 -0.11962890625 -0.14947509765625 0.1996826171875111 +1.994 -0.11962890625 -0.14947509765625 0.1996826171875111 +1.994125000000000256 -0.115631103515625 -0.14447021484375 0.1996826171875111 +1.99425 -0.111602783203125 -0.13946533203125 0.1996826171875111 +1.994375 -0.111602783203125 -0.13946533203125 0.1996826171875111 +1.9945 -0.107574462890625 -0.134429931640625 0.1996826171875111 +1.994625 -0.107574462890625 -0.134429931640625 0.1996826171875111 +1.99475 -0.103515625 -0.129364013671875 0.1996826171875111 +1.994875 -0.0994873046875 -0.124298095703125 0.1996826171875111 +1.995 -0.0994873046875 -0.124298095703125 0.1996826171875111 +1.995125 -0.095428466796875 -0.119232177734375 0.1996826171875111 +1.99525 -0.095428466796875 -0.119232177734375 0.1996826171875111 +1.99537500000000016 -0.091339111328125 -0.1141357421875 0.1996826171875111 +1.9955 -0.087249755859375 -0.109039306640625 0.1996826171875111 +1.995625 -0.087249755859375 -0.109039306640625 0.1996826171875111 +1.99575000000000016 -0.083160400390625 -0.103912353515625 0.1996826171875111 +1.995875 -0.083160400390625 -0.103912353515625 0.1996826171875111 +1.996 -0.079071044921875 -0.098785400390625 0.1996826171875111 +1.996125000000000256 -0.074951171875 -0.093658447265625 0.1996826171875111 +1.99625 -0.074951171875 -0.093658447265625 0.1996826171875111 +1.996375 -0.070831298828125 -0.0885009765625 0.1996826171875111 +1.9965 -0.070831298828125 -0.0885009765625 0.1996826171875111 +1.996625 -0.06671142578125 -0.083343505859375 0.1996826171875111 +1.99675 -0.06256103515625 -0.07818603515625 0.1996826171875111 +1.996875 -0.06256103515625 -0.07818603515625 0.1996826171875111 +1.997 -0.05841064453125 -0.072998046875 0.1996826171875111 +1.997125 -0.05841064453125 -0.072998046875 0.1996826171875111 +1.99725 -0.05426025390625 -0.06781005859375 0.1996826171875111 +1.99737500000000016 -0.05010986328125 -0.0626220703125 0.1996826171875111 +1.9975 -0.05010986328125 -0.0626220703125 0.1996826171875111 +1.997625 -0.04595947265625 -0.05743408203125 0.1996826171875111 +1.99775000000000016 -0.04595947265625 -0.05743408203125 0.1996826171875111 +1.997875 -0.04180908203125 -0.05224609375 0.1996826171875111 +1.998 -0.037628173828125 -0.047027587890625 0.1996826171875111 +1.998125000000000256 -0.037628173828125 -0.047027587890625 0.1996826171875111 +1.99825 -0.033447265625 -0.04180908203125 0.1996826171875111 +1.998375 -0.033447265625 -0.04180908203125 0.1996826171875111 +1.9985 -0.029266357421875 -0.036590576171875 0.1996826171875111 +1.998625 -0.025115966796875 -0.0313720703125 0.1996826171875111 +1.99875 -0.025115966796875 -0.0313720703125 0.1996826171875111 +1.998875 -0.020904541015625 -0.026123046875 0.1996826171875111 +1.999 -0.020904541015625 -0.026123046875 0.1996826171875111 +1.999125 -0.0167236328125 -0.020904541015625 0.1996826171875111 +1.99925 -0.012542724609375 -0.01568603515625 0.1996826171875111 +1.99937500000000016 -0.012542724609375 -0.01568603515625 0.1996826171875111 +1.9995 -0.00836181640625 -0.01043701171875 0.1996826171875111 +1.999625 -0.00836181640625 -0.01043701171875 0.1996826171875111 +1.99975000000000016 -0.004180908203125 -0.005218505859375 0.1996826171875111 +1.999875 0.0 0.0 0.1996826171875111 +2.0 0.0 0.0 0.1996826171875111 +2.000125 0.004180908203125 0.005218505859375 0.1996826171875111 +2.00025 0.004180908203125 0.005218505859375 0.1996826171875111 +2.000375 0.00836181640625 0.01043701171875 0.1996826171875111 +2.0005 0.012542724609375 0.01568603515625 0.1996826171875111 +2.000625 0.012542724609375 0.01568603515625 0.1996826171875111 +2.00075 0.0167236328125 0.020904541015625 0.1996826171875111 +2.000875 0.0167236328125 0.020904541015625 0.1996826171875111 +2.001 0.020904541015625 0.026123046875 0.1996826171875111 +2.001125 0.025115966796875 0.0313720703125 0.1996826171875111 +2.00125 0.025115966796875 0.0313720703125 0.1996826171875111 +2.001375 0.029266357421875 0.036590576171875 0.1996826171875111 +2.0015 0.029266357421875 0.036590576171875 0.1996826171875111 +2.001625 0.033447265625 0.04180908203125 0.1996826171875111 +2.00175 0.037628173828125 0.047027587890625 0.1996826171875111 +2.001875 0.037628173828125 0.047027587890625 0.1996826171875111 +2.0020000000000004 0.04180908203125 0.05224609375 0.1996826171875111 +2.002125 0.04180908203125 0.05224609375 0.1996826171875111 +2.00225 0.04595947265625 0.05743408203125 0.1996826171875111 +2.0023750000000004 0.05010986328125 0.0626220703125 0.1996826171875111 +2.0025 0.05010986328125 0.0626220703125 0.1996826171875111 +2.002625 0.05426025390625 0.06781005859375 0.1996826171875111 +2.0027500000000004 0.05426025390625 0.06781005859375 0.1996826171875111 +2.002875 0.05841064453125 0.072998046875 0.1996826171875111 +2.003 0.06256103515625 0.07818603515625 0.1996826171875111 +2.003125 0.06256103515625 0.07818603515625 0.1996826171875111 +2.00325 0.06671142578125 0.083343505859375 0.1996826171875111 +2.003375 0.06671142578125 0.083343505859375 0.1996826171875111 +2.0035 0.070831298828125 0.0885009765625 0.1996826171875111 +2.003625 0.074951171875 0.093658447265625 0.1996826171875111 +2.00375 0.074951171875 0.093658447265625 0.1996826171875111 +2.003875 0.079071044921875 0.098785400390625 0.1996826171875111 +2.004 0.079071044921875 0.098785400390625 0.1996826171875111 +2.004125 0.083160400390625 0.103912353515625 0.1996826171875111 +2.00425 0.087249755859375 0.109039306640625 0.1996826171875111 +2.004375 0.087249755859375 0.109039306640625 0.1996826171875111 +2.0045 0.091339111328125 0.1141357421875 0.1996826171875111 +2.004625 0.091339111328125 0.1141357421875 0.1996826171875111 +2.00475 0.095428466796875 0.119232177734375 0.1996826171875111 +2.004875 0.0994873046875 0.124298095703125 0.1996826171875111 +2.005 0.0994873046875 0.124298095703125 0.1996826171875111 +2.005125 0.103515625 0.129364013671875 0.1996826171875111 +2.00525 0.103515625 0.129364013671875 0.1996826171875111 +2.005375 0.107574462890625 0.134429931640625 0.1996826171875111 +2.0055 0.111602783203125 0.13946533203125 0.1996826171875111 +2.005625 0.111602783203125 0.13946533203125 0.1996826171875111 +2.00575 0.115631103515625 0.14447021484375 0.1996826171875111 +2.005875 0.115631103515625 0.14447021484375 0.1996826171875111 +2.0060000000000004 0.11962890625 0.14947509765625 0.1996826171875111 +2.006125 0.123626708984375 0.15447998046875 0.1996826171875111 +2.00625 0.123626708984375 0.15447998046875 0.1996826171875111 +2.0063750000000004 0.127593994140625 0.159454345703125 0.1996826171875111 +2.0065 0.127593994140625 0.159454345703125 0.1996826171875111 +2.006625 0.131561279296875 0.164398193359375 0.1996826171875111 +2.0067500000000004 0.135498046875 0.169342041015625 0.1996826171875111 +2.006875 0.135498046875 0.169342041015625 0.1996826171875111 +2.007 0.139434814453125 0.17425537109375 0.1996826171875111 +2.007125 0.139434814453125 0.17425537109375 0.1996826171875111 +2.00725 0.14337158203125 0.17913818359375 0.1996826171875111 +2.007375 0.14727783203125 0.18402099609375 0.1996826171875111 +2.0075 0.14727783203125 0.18402099609375 0.1996826171875111 +2.007625 0.151153564453125 0.188873291015625 0.1996826171875111 +2.00775 0.151153564453125 0.188873291015625 0.1996826171875111 +2.007875 0.155029296875 0.1937255859375 0.1996826171875111 +2.008 0.15887451171875 0.19854736328125 0.1996826171875111 +2.008125 0.15887451171875 0.19854736328125 0.1996826171875111 +2.00825 0.1627197265625 0.203338623046875 0.1996826171875111 +2.008375 0.1627197265625 0.203338623046875 0.1996826171875111 +2.0085 0.166534423828125 0.208099365234375 0.1996826171875111 +2.008625 0.17034912109375 0.212860107421875 0.1996826171875111 +2.00875 0.17034912109375 0.212860107421875 0.1996826171875111 +2.008875 0.17413330078125 0.21759033203125 0.1996826171875111 +2.009 0.17413330078125 0.21759033203125 0.1996826171875111 +2.009125 0.177886962890625 0.2222900390625 0.1996826171875111 +2.00925 0.181610107421875 0.226959228515625 0.1996826171875111 +2.009375 0.181610107421875 0.226959228515625 0.1996826171875111 +2.0095 0.185333251953125 0.231597900390625 0.1996826171875111 +2.009625 0.185333251953125 0.231597900390625 0.1996826171875111 +2.00975 0.189056396484375 0.236236572265625 0.1996826171875111 +2.009875 0.192718505859375 0.2408447265625 0.1996826171875111 +2.0100000000000004 0.192718505859375 0.2408447265625 0.1996826171875111 +2.010125 0.196380615234375 0.24542236328125 0.1996826171875111 +2.01025 0.196380615234375 0.24542236328125 0.1996826171875111 +2.0103750000000004 0.200042724609375 0.249969482421875 0.1996826171875111 +2.0105 0.203643798828125 0.25445556640625 0.1996826171875111 +2.010625 0.203643798828125 0.25445556640625 0.1996826171875111 +2.0107500000000004 0.207244873046875 0.25897216796875 0.1996826171875111 +2.010875 0.207244873046875 0.25897216796875 0.1996826171875111 +2.011 0.2108154296875 0.263427734375 0.1996826171875111 +2.011125 0.21435546875 0.267852783203125 0.1996826171875111 +2.01125 0.21435546875 0.267852783203125 0.1996826171875111 +2.011375 0.2178955078125 0.27227783203125 0.1996826171875111 +2.0115 0.2178955078125 0.27227783203125 0.1996826171875111 +2.011625 0.22137451171875 0.276641845703125 0.1996826171875111 +2.01175 0.224853515625 0.280975341796875 0.1996826171875111 +2.011875 0.224853515625 0.280975341796875 0.1996826171875111 +2.012 0.22833251953125 0.285308837890625 0.1996826171875111 +2.012125 0.22833251953125 0.285308837890625 0.1996826171875111 +2.01225 0.23175048828125 0.289581298828125 0.1996826171875111 +2.012375 0.235137939453125 0.2938232421875 0.1996826171875111 +2.0125 0.235137939453125 0.2938232421875 0.1996826171875111 +2.012625 0.238525390625 0.298065185546875 0.1996826171875111 +2.01275 0.238525390625 0.298065185546875 0.1996826171875111 +2.012875 0.24188232421875 0.30224609375 0.1996826171875111 +2.013 0.245208740234375 0.306396484375 0.1996826171875111 +2.013125 0.245208740234375 0.306396484375 0.1996826171875111 +2.01325 0.248504638671875 0.310516357421875 0.1996826171875111 +2.013375 0.248504638671875 0.310516357421875 0.1996826171875111 +2.0135 0.25177001953125 0.314605712890625 0.1996826171875111 +2.013625 0.2550048828125 0.31866455078125 0.1996826171875111 +2.01375 0.2550048828125 0.31866455078125 0.1996826171875111 +2.013875 0.25823974609375 0.322662353515625 0.1996826171875111 +2.0140000000000004 0.25823974609375 0.322662353515625 0.1996826171875111 +2.014125 0.26141357421875 0.32666015625 0.1996826171875111 +2.01425 0.26458740234375 0.330596923828125 0.1996826171875111 +2.0143750000000004 0.26458740234375 0.330596923828125 0.1996826171875111 +2.0145 0.2677001953125 0.334503173828125 0.1996826171875111 +2.014625 0.2677001953125 0.334503173828125 0.1996826171875111 +2.0147500000000004 0.27081298828125 0.33837890625 0.1996826171875111 +2.014875 0.27386474609375 0.34222412109375 0.1996826171875111 +2.015 0.27386474609375 0.34222412109375 0.1996826171875111 +2.015125 0.27691650390625 0.34600830078125 0.1996826171875111 +2.01525 0.27691650390625 0.34600830078125 0.1996826171875111 +2.015375 0.2799072265625 0.349761962890625 0.1996826171875111 +2.0155 0.28289794921875 0.353485107421875 0.1996826171875111 +2.015625 0.28289794921875 0.353485107421875 0.1996826171875111 +2.01575 0.285858154296875 0.357177734375 0.1996826171875111 +2.015875 0.285858154296875 0.357177734375 0.1996826171875111 diff --git a/tests/circuitpython/synthio_biquad_peaking.py b/tests/circuitpython/synthio_biquad_peaking.py new file mode 100644 index 00000000000..fcdf38a9f4e --- /dev/null +++ b/tests/circuitpython/synthio_biquad_peaking.py @@ -0,0 +1,54 @@ +# A peaking EQ bell should be unity at DC and near Nyquist, and hit its own +# gain at the centre frequency. +import array +import math +from audiocore import get_buffer, RawSample +from audiofilters import Filter +from synthio import Biquad, FilterMode + +RATE = 48000 +FRAMES = 4096 +LEVEL = 2000 +GAIN_DB = 6.0 +CENTRE = 1000.0 + + +def through(values): + source = RawSample(values, sample_rate=RATE, channel_count=1) + bell = Biquad(FilterMode.PEAKING_EQ, CENTRE, Q=1.0, A=10 ** (GAIN_DB / 40)) + effect = Filter( + filter=bell, + sample_rate=RATE, + channel_count=1, + bits_per_sample=16, + samples_signed=True, + buffer_size=FRAMES * 2, + ) + effect.play(source, loop=True) + out = [] + for block in range(3): + data = bytes(get_buffer(effect)[1]) + if block < 2: # let the filter settle + continue + for index in range(0, len(data) - 1, 2): + sample = data[index] | (data[index + 1] << 8) + out.append(sample - 65536 if sample >= 32768 else sample) + return out + + +def tone(hz): + return array.array( + "h", + [int(LEVEL * math.sin(2 * math.pi * hz * frame / RATE)) for frame in range(FRAMES)], + ) + + +def rms_db(values): + total = sum(value * value for value in values) + return 20 * math.log10(math.sqrt(total / len(values)) / (LEVEL / math.sqrt(2))) + + +dc = through(array.array("h", [LEVEL] * FRAMES)) +print("DC %+.1f" % (20 * math.log10(abs(dc[-1]) / LEVEL))) +print("centre %+.1f" % rms_db(through(tone(CENTRE)))) +print("12 kHz %+.1f" % rms_db(through(tone(12000.0)))) diff --git a/tests/circuitpython/synthio_biquad_peaking.py.exp b/tests/circuitpython/synthio_biquad_peaking.py.exp new file mode 100644 index 00000000000..54499ead993 --- /dev/null +++ b/tests/circuitpython/synthio_biquad_peaking.py.exp @@ -0,0 +1,3 @@ +DC -0.1 +centre +5.9 +12 kHz +0.0 diff --git a/tests/circuitpython/synthio_note_repress_after_decay.py b/tests/circuitpython/synthio_note_repress_after_decay.py new file mode 100644 index 00000000000..9fda75b1503 --- /dev/null +++ b/tests/circuitpython/synthio_note_repress_after_decay.py @@ -0,0 +1,24 @@ +# A note whose envelope has decayed to 0 but whose slot hasn't been reaped +# yet should re-press like a fresh note, not silently vanish. +from synthio import Synthesizer, Note, Envelope +from audiocore import get_buffer + +# release_time=0 collapses the envelope to level 0 in a single step, while +# the note object still holds its channel. +quick = Envelope(release_time=0) +synth = Synthesizer() +note = Note(440, envelope=quick) + +synth.press(note) +get_buffer(synth) +synth.release(note) +get_buffer(synth) +print("pressed after decay:", len(synth.pressed)) + +synth.press(note) +print("pressed right after re-press:", len(synth.pressed)) +get_buffer(synth) +print("pressed after one more render:", len(synth.pressed)) +for _ in range(3): + print("{} {:.2f}".format(*synth.note_info(note))) + get_buffer(synth) diff --git a/tests/circuitpython/synthio_note_repress_after_decay.py.exp b/tests/circuitpython/synthio_note_repress_after_decay.py.exp new file mode 100644 index 00000000000..3b79fe6f3ab --- /dev/null +++ b/tests/circuitpython/synthio_note_repress_after_decay.py.exp @@ -0,0 +1,6 @@ +pressed after decay: 0 +pressed right after re-press: 1 +pressed after one more render: 1 +synthio.EnvelopeState.ATTACK 0.46 +synthio.EnvelopeState.ATTACK 0.70 +synthio.EnvelopeState.ATTACK 0.93 diff --git a/tests/circuitpython/synthio_oscillator_loop_end.py b/tests/circuitpython/synthio_oscillator_loop_end.py new file mode 100644 index 00000000000..1c029293c03 --- /dev/null +++ b/tests/circuitpython/synthio_oscillator_loop_end.py @@ -0,0 +1,33 @@ +# A note whose loop end is reached exactly (accum == lim) should wrap back +# to the loop start on that same sample, not read one sample past the loop. +import array +from audiocore import get_buffer +from synthio import Note, Synthesizer + +RATE = 8000 +LOOP = 256 + +# 512 samples: the loop is [0, 256) and is silent; sample 256 is a marker +# the oscillator should never reach. +table = array.array("h", [0] * 512) +table[LOOP] = 30000 + +synth = Synthesizer(sample_rate=RATE, channel_count=1) +note = Note( + frequency=RATE / LOOP, # exactly one table step per output sample + waveform=table, + waveform_loop_start=0, + waveform_loop_end=LOOP, + envelope=None, +) +synth.press(note) + +out = [] +for _ in range(4): + data = bytes(get_buffer(synth)[1]) + for index in range(0, len(data) - 1, 2): + value = data[index] | (data[index + 1] << 8) + out.append(value - 65536 if value >= 32768 else value) + +hits = [i for i, v in enumerate(out) if abs(v) > 1000] +print("marker hits:", hits) diff --git a/tests/circuitpython/synthio_oscillator_loop_end.py.exp b/tests/circuitpython/synthio_oscillator_loop_end.py.exp new file mode 100644 index 00000000000..e8811221896 --- /dev/null +++ b/tests/circuitpython/synthio_oscillator_loop_end.py.exp @@ -0,0 +1 @@ +marker hits: [] diff --git a/tests/circuitpython/traceback_test.py b/tests/circuitpython/traceback_test.py index 17c54c857a9..71888437a22 100644 --- a/tests/circuitpython/traceback_test.py +++ b/tests/circuitpython/traceback_test.py @@ -23,6 +23,22 @@ def fun(): print("\nLimit=-1 Trace:") print("".join(traceback.format_exception(None, exc, exc.__traceback__, limit=-1)), end="") +# value and tb must both be supplied or neither +print() +try: + fun() +except Exception as exc: + try: + traceback.print_exception(None, value=exc) + print("Should have raised ValueError for missing tb arg") + except ValueError: + print("ValueError for missing tb arg, as expected") + try: + traceback.print_exception(None, tb=None) + print("Should have raised ValueError for missing value arg") + except ValueError: + print("ValueError for missing value arg, as expected") + class NonNativeException(Exception): pass diff --git a/tests/circuitpython/wavefile_8bit_padding.py b/tests/circuitpython/wavefile_8bit_padding.py new file mode 100644 index 00000000000..16bc1d868a3 --- /dev/null +++ b/tests/circuitpython/wavefile_8bit_padding.py @@ -0,0 +1,80 @@ +# The last buffer of a WaveFile is padded to a multiple of 4 bytes; for 8-bit +# samples the pad is 0x80 (silence) and never more than 3 bytes. +try: + import os, audiocore + + os.VfsFat +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class RAMFS: + SEC_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.SEC_SIZE) + + def readblocks(self, n, buf): + for i in range(len(buf)): + buf[i] = self.data[n * self.SEC_SIZE + i] + return 0 + + def writeblocks(self, n, buf): + for i in range(len(buf)): + self.data[n * self.SEC_SIZE + i] = buf[i] + return 0 + + def ioctl(self, op, arg): + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT + return len(self.data) // self.SEC_SIZE + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE + return self.SEC_SIZE + + +def le(value, size): + return value.to_bytes(size, "little") + + +def wav_u8_mono(data): + # PCM, mono, 16 kHz, 8 bits per sample + fmt = le(1, 2) + le(1, 2) + le(16000, 4) + le(16000, 4) + le(1, 2) + le(8, 2) + return ( + b"RIFF" + + le(4 + 8 + len(fmt) + 8 + len(data), 4) + + b"WAVEfmt " + + le(len(fmt), 4) + + fmt + + b"data" + + le(len(data), 4) + + data + ) + + +bdev = RAMFS(50) +os.VfsFat.mkfs(bdev) +fs = os.VfsFat(bdev) + +for length in range(4, 9): + name = "u8-%d.wav" % length + with fs.open(name, "wb") as f: + f.write(wav_u8_mono(bytes(range(32, 32 + length)))) + with fs.open(name, "rb") as f: + sample = audiocore.WaveFile(f) + audiocore.reset_buffer(sample) # what an AudioOut does on play() + result, buf = audiocore.get_buffer(sample) + print(length, result, len(buf), list(buf)) + +# A caller-supplied buffer is split in half and each half must be a multiple of +# 4 bytes for the pad to fit, so the whole buffer must be a multiple of 8 bytes. +with fs.open("u8-5.wav", "rb") as f: + try: + audiocore.WaveFile(f, bytearray(12)) + except ValueError as e: + print("ValueError:", e) + sample = audiocore.WaveFile(f, bytearray(8)) + audiocore.reset_buffer(sample) + result = 1 + while result == 1: + result, buf = audiocore.get_buffer(sample) + print(result, len(buf), list(buf)) diff --git a/tests/circuitpython/wavefile_8bit_padding.py.exp b/tests/circuitpython/wavefile_8bit_padding.py.exp new file mode 100644 index 00000000000..b7ec4b5c871 --- /dev/null +++ b/tests/circuitpython/wavefile_8bit_padding.py.exp @@ -0,0 +1,8 @@ +4 0 4 [32, 33, 34, 35] +5 0 8 [32, 33, 34, 35, 36, 128, 128, 128] +6 0 8 [32, 33, 34, 35, 36, 37, 128, 128] +7 0 8 [32, 33, 34, 35, 36, 37, 38, 128] +8 0 8 [32, 33, 34, 35, 36, 37, 38, 39] +ValueError: Buffer must be a multiple of 8 bytes +1 4 [32, 33, 34, 35] +0 4 [36, 128, 128, 128] diff --git a/tests/cmdline/cmd_compile_only.py b/tests/cmdline/cmd_compile_only.py new file mode 100644 index 00000000000..89964c1b5bd --- /dev/null +++ b/tests/cmdline/cmd_compile_only.py @@ -0,0 +1,13 @@ +# cmdline: -X compile-only +# test compile-only functionality +print("This should not be printed") +x = 1 + 2 + + +def hello(): + return "world" + + +class TestClass: + def __init__(self): + self.value = 42 diff --git a/tests/cmdline/cmd_compile_only.py.exp b/tests/cmdline/cmd_compile_only.py.exp new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/cmdline/cmd_compile_only.py.exp @@ -0,0 +1 @@ + diff --git a/tests/cmdline/cmd_compile_only_error.py b/tests/cmdline/cmd_compile_only_error.py new file mode 100644 index 00000000000..326937a5c07 --- /dev/null +++ b/tests/cmdline/cmd_compile_only_error.py @@ -0,0 +1,6 @@ +# cmdline: -X compile-only +# test compile-only with syntax error +print("This should not be printed") +def broken_syntax( + # Missing closing parenthesis + return "error" diff --git a/tests/cmdline/cmd_compile_only_error.py.exp b/tests/cmdline/cmd_compile_only_error.py.exp new file mode 100644 index 00000000000..3911f71d624 --- /dev/null +++ b/tests/cmdline/cmd_compile_only_error.py.exp @@ -0,0 +1 @@ +CRASH \ No newline at end of file diff --git a/tests/cmdline/cmd_file_variable.py b/tests/cmdline/cmd_file_variable.py new file mode 100644 index 00000000000..6cac6744d90 --- /dev/null +++ b/tests/cmdline/cmd_file_variable.py @@ -0,0 +1,5 @@ +# Test that __file__ is set correctly for script execution +try: + print("__file__ =", __file__) +except NameError: + print("__file__ not defined") diff --git a/tests/cmdline/cmd_file_variable.py.exp b/tests/cmdline/cmd_file_variable.py.exp new file mode 100644 index 00000000000..420f789ddf3 --- /dev/null +++ b/tests/cmdline/cmd_file_variable.py.exp @@ -0,0 +1 @@ +__file__ = \.\*cmdline/cmd_file_variable.py diff --git a/tests/cmdline/cmd_module_atexit.py b/tests/cmdline/cmd_module_atexit.py new file mode 100644 index 00000000000..100bc112777 --- /dev/null +++ b/tests/cmdline/cmd_module_atexit.py @@ -0,0 +1,16 @@ +# cmdline: -m cmdline.cmd_module_atexit +# +# Test running as a module and using sys.atexit. + +import sys + +if not hasattr(sys, "atexit"): + print("SKIP") + raise SystemExit + +# Verify we ran as a module. +print(sys.argv) + +sys.atexit(lambda: print("done")) + +print("start") diff --git a/tests/cmdline/cmd_module_atexit.py.exp b/tests/cmdline/cmd_module_atexit.py.exp new file mode 100644 index 00000000000..334bf53bac9 --- /dev/null +++ b/tests/cmdline/cmd_module_atexit.py.exp @@ -0,0 +1,3 @@ +['cmdline.cmd_module_atexit', '\.\*cmdline/cmd_module_atexit.py'] +start +done diff --git a/tests/cmdline/cmd_module_atexit_exc.py b/tests/cmdline/cmd_module_atexit_exc.py new file mode 100644 index 00000000000..88940a7741f --- /dev/null +++ b/tests/cmdline/cmd_module_atexit_exc.py @@ -0,0 +1,19 @@ +# cmdline: -m cmdline.cmd_module_atexit_exc +# +# Test running as a module and using sys.atexit, with script completion via sys.exit. + +import sys + +if not hasattr(sys, "atexit"): + print("SKIP") + raise SystemExit + +# Verify we ran as a module. +print(sys.argv) + +sys.atexit(lambda: print("done")) + +print("start") + +# This will raise SystemExit to finish the script, and atexit should still be run. +sys.exit(0) diff --git a/tests/cmdline/cmd_module_atexit_exc.py.exp b/tests/cmdline/cmd_module_atexit_exc.py.exp new file mode 100644 index 00000000000..210748afdfe --- /dev/null +++ b/tests/cmdline/cmd_module_atexit_exc.py.exp @@ -0,0 +1,3 @@ +['cmdline.cmd_module_atexit_exc', '\.\*cmdline/cmd_module_atexit_exc.py'] +start +done diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index db06de92371..b839de6d1ed 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -1,4 +1,4 @@ -File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 63 bytes) +File \.\*cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 63 bytes) Raw bytecode (code_info_size=18, bytecode_size=45): 10 20 01 60 20 84 7d 64 60 88 07 64 60 69 20 62 64 20 32 00 16 05 32 01 16 05 81 2a 01 53 33 02 @@ -47,7 +47,7 @@ arg names: 42 IMPORT_STAR 43 LOAD_CONST_NONE 44 RETURN_VALUE -File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 46\[68\] bytes) +File \.\*cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 46\[68\] bytes) Raw bytecode (code_info_size=8\[46\], bytecode_size=382): a8 12 9\[bf\] 03 05 60 60 26 22 24 64 22 24 25 25 24 26 23 63 22 22 25 23 23 2f 6c 25 65 25 25 69 68 @@ -185,7 +185,7 @@ arg names: 58 UNARY_OP 1 __neg__ 59 STORE_FAST 9 60 LOAD_FAST 0 -61 UNARY_OP 3 +61 UNARY_OP 3 \$ 62 STORE_FAST 10 63 LOAD_FAST 0 64 LOAD_DEREF 14 @@ -206,7 +206,7 @@ arg names: 84 LOAD_DEREF 14 86 LOAD_FAST 1 87 BINARY_OP 2 __eq__ -88 UNARY_OP 3 +88 UNARY_OP 3 \$ 89 STORE_FAST 10 90 LOAD_DEREF 14 92 LOAD_ATTR c @@ -411,7 +411,7 @@ arg names: 379 RETURN_VALUE 380 LOAD_CONST_NONE 381 RETURN_VALUE -File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 59 bytes) +File \.\*cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 59 bytes) Raw bytecode (code_info_size=8, bytecode_size=51): a8 10 0a 05 80 82 34 38 81 57 c0 57 c1 57 c2 57 c3 57 c4 57 c5 57 c6 57 c7 57 c8 c9 82 57 ca 57 @@ -470,7 +470,7 @@ arg names: 48 POP_TOP 49 LOAD_CONST_NONE 50 RETURN_VALUE -File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 20 bytes) +File \.\*cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 20 bytes) Raw bytecode (code_info_size=9, bytecode_size=11): a1 01 0b 05 06 80 88 40 00 82 2a 01 53 b0 21 00 01 c1 51 63 @@ -489,7 +489,7 @@ arg names: a 08 STORE_FAST 1 09 LOAD_CONST_NONE 10 RETURN_VALUE -File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 21 bytes) +File \.\*cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 21 bytes) Raw bytecode (code_info_size=8, bytecode_size=13): 88 40 0a 05 80 8f 23 23 51 67 59 81 67 59 81 5e 51 68 59 51 63 @@ -513,7 +513,7 @@ arg names: 10 POP_TOP 11 LOAD_CONST_NONE 12 RETURN_VALUE -File cmdline/cmd_showbc.py, code block 'Class' (descriptor: \.\+, bytecode @\.\+ 1\[56\] bytes) +File \.\*cmdline/cmd_showbc.py, code block 'Class' (descriptor: \.\+, bytecode @\.\+ 1\[56\] bytes) Raw bytecode (code_info_size=\[56\], bytecode_size=10): 00 \.\+ 11 0f 16 10 10 02 16 11 51 63 arg names: @@ -528,7 +528,7 @@ arg names: 06 STORE_NAME __qualname__ 08 LOAD_CONST_NONE 09 RETURN_VALUE -File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 18 bytes) +File \.\*cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 18 bytes) Raw bytecode (code_info_size=6, bytecode_size=12): 19 08 05 12 80 9c 12 13 12 14 b0 15 05 36 00 59 51 63 @@ -545,7 +545,7 @@ arg names: self 09 POP_TOP 10 LOAD_CONST_NONE 11 RETURN_VALUE -File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 28 bytes) +File \.\*cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 28 bytes) Raw bytecode (code_info_size=9, bytecode_size=19): c3 40 0c 09 03 03 03 80 3b 53 b2 53 53 4b 0b c3 25 01 44 39 25 00 67 59 42 33 51 63 @@ -568,7 +568,7 @@ arg names: * * * 15 JUMP 4 17 LOAD_CONST_NONE 18 RETURN_VALUE -File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 26 bytes) +File \.\*cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 26 bytes) Raw bytecode (code_info_size=8, bytecode_size=18): 4b 0c 0a 03 03 03 80 3c 2b 00 b2 5f 4b 0b c3 25 01 44 39 25 00 2f 14 42 33 63 @@ -588,7 +588,7 @@ arg names: * * * 13 STORE_COMP 20 15 JUMP 4 17 RETURN_VALUE -File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 28 bytes) +File \.\*cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ 28 bytes) Raw bytecode (code_info_size=8, bytecode_size=20): 53 0c 0b 03 03 03 80 3d 2c 00 b2 5f 4b 0d c3 25 01 44 39 25 00 25 00 2f 19 42 31 63 @@ -609,7 +609,7 @@ arg names: * * * 15 STORE_COMP 25 17 JUMP 4 19 RETURN_VALUE -File cmdline/cmd_showbc.py, code block 'closure' (descriptor: \.\+, bytecode @\.\+ 20 bytes) +File \.\*cmdline/cmd_showbc.py, code block 'closure' (descriptor: \.\+, bytecode @\.\+ 20 bytes) Raw bytecode (code_info_size=8, bytecode_size=12): 19 0c 0c 03 80 6f 25 23 25 00 81 f2 c1 81 27 00 29 00 51 63 @@ -629,7 +629,7 @@ arg names: * 08 DELETE_DEREF 0 10 LOAD_CONST_NONE 11 RETURN_VALUE -File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 13 bytes) +File \.\*cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ 13 bytes) Raw bytecode (code_info_size=8, bytecode_size=5): 9a 01 0a 05 03 08 80 8b b1 25 00 f2 63 arg names: * b diff --git a/tests/cmdline/cmd_showbc_const.py.exp b/tests/cmdline/cmd_showbc_const.py.exp index 6cdc3e9c963..6faeb941d7d 100644 --- a/tests/cmdline/cmd_showbc_const.py.exp +++ b/tests/cmdline/cmd_showbc_const.py.exp @@ -1,4 +1,4 @@ -File cmdline/cmd_showbc_const.py, code block '' (descriptor: \.\+, bytecode @\.\+ 198 bytes) +File \.\*cmdline/cmd_showbc_const.py, code block '' (descriptor: \.\+, bytecode @\.\+ 198 bytes) Raw bytecode (code_info_size=40, bytecode_size=158): 2c 4c 01 60 2c 46 22 65 27 4a 83 0c 20 27 40 20 27 20 27 40 60 20 27 24 40 60 40 24 27 47 24 27 @@ -76,7 +76,7 @@ arg names: 34 RAISE_OBJ 35 DUP_TOP 36 LOAD_NAME AttributeError -38 BINARY_OP 8 +38 BINARY_OP 8 \$ 39 POP_JUMP_IF_FALSE 44 41 POP_TOP 42 POP_EXCEPT_JUMP 45 diff --git a/tests/cmdline/cmd_showbc_opt.py.exp b/tests/cmdline/cmd_showbc_opt.py.exp index 9e4e4fae10c..c3047275a9c 100644 --- a/tests/cmdline/cmd_showbc_opt.py.exp +++ b/tests/cmdline/cmd_showbc_opt.py.exp @@ -1,4 +1,4 @@ -File cmdline/cmd_showbc_opt.py, code block '' (descriptor: \.\+, bytecode @\.\+ 35 bytes) +File \.\*cmdline/cmd_showbc_opt.py, code block '' (descriptor: \.\+, bytecode @\.\+ 35 bytes) Raw bytecode (code_info_size=13, bytecode_size=22): 00 16 01 60 20 64 40 84 07 64 40 84 07 32 00 16 02 32 01 16 03 32 02 16 04 32 03 16 05 32 04 16 @@ -27,7 +27,7 @@ arg names: 18 STORE_NAME f4 20 LOAD_CONST_NONE 21 RETURN_VALUE -File cmdline/cmd_showbc_opt.py, code block 'f0' (descriptor: \.\+, bytecode @\.\+ 8 bytes) +File \.\*cmdline/cmd_showbc_opt.py, code block 'f0' (descriptor: \.\+, bytecode @\.\+ 8 bytes) Raw bytecode (code_info_size=6, bytecode_size=2): 08 08 02 60 40 22 80 63 arg names: @@ -39,7 +39,7 @@ arg names: bc=2 line=7 00 LOAD_CONST_SMALL_INT 0 01 RETURN_VALUE -File cmdline/cmd_showbc_opt.py, code block 'f1' (descriptor: \.\+, bytecode @\.\+ 22 bytes) +File \.\*cmdline/cmd_showbc_opt.py, code block 'f1' (descriptor: \.\+, bytecode @\.\+ 22 bytes) Raw bytecode (code_info_size=9, bytecode_size=13): 11 0e 03 08 80 0a 23 22 20 b0 44 42 51 63 12 07 82 34 01 59 51 63 @@ -61,7 +61,7 @@ arg names: x 10 POP_TOP 11 LOAD_CONST_NONE 12 RETURN_VALUE -File cmdline/cmd_showbc_opt.py, code block 'f2' (descriptor: \.\+, bytecode @\.\+ 10 bytes) +File \.\*cmdline/cmd_showbc_opt.py, code block 'f2' (descriptor: \.\+, bytecode @\.\+ 10 bytes) Raw bytecode (code_info_size=7, bytecode_size=3): 11 0a 04 08 80 11 23 12 09 65 arg names: x @@ -72,7 +72,7 @@ arg names: x bc=3 line=19 00 LOAD_GLOBAL Exception 02 RAISE_OBJ -File cmdline/cmd_showbc_opt.py, code block 'f3' (descriptor: \.\+, bytecode @\.\+ 24 bytes) +File \.\*cmdline/cmd_showbc_opt.py, code block 'f3' (descriptor: \.\+, bytecode @\.\+ 24 bytes) Raw bytecode (code_info_size=9, bytecode_size=15): 11 0e 05 08 80 16 22 22 23 42 42 42 43 b0 43 3b 12 07 82 34 01 59 51 63 @@ -94,7 +94,7 @@ arg names: x 12 POP_TOP 13 LOAD_CONST_NONE 14 RETURN_VALUE -File cmdline/cmd_showbc_opt.py, code block 'f4' (descriptor: \.\+, bytecode @\.\+ 24 bytes) +File \.\*cmdline/cmd_showbc_opt.py, code block 'f4' (descriptor: \.\+, bytecode @\.\+ 24 bytes) Raw bytecode (code_info_size=9, bytecode_size=15): 11 0e 06 08 80 1d 22 22 23 42 42 42 40 b0 43 3b 12 07 82 34 01 59 51 63 diff --git a/tests/cmdline/cmd_sys_exit_0.py b/tests/cmdline/cmd_sys_exit_0.py new file mode 100644 index 00000000000..1294b739e8f --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_0.py @@ -0,0 +1,5 @@ +# cmdline: +# test sys.exit(0) - success exit code +import sys + +sys.exit(0) diff --git a/tests/cmdline/cmd_sys_exit_0.py.exp b/tests/cmdline/cmd_sys_exit_0.py.exp new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_0.py.exp @@ -0,0 +1 @@ + diff --git a/tests/cmdline/cmd_sys_exit_error.py b/tests/cmdline/cmd_sys_exit_error.py new file mode 100644 index 00000000000..ecac15e94f1 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_error.py @@ -0,0 +1,5 @@ +# cmdline: +# test sys.exit() functionality and exit codes +import sys + +sys.exit(123) diff --git a/tests/cmdline/cmd_sys_exit_error.py.exp b/tests/cmdline/cmd_sys_exit_error.py.exp new file mode 100644 index 00000000000..3911f71d624 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_error.py.exp @@ -0,0 +1 @@ +CRASH \ No newline at end of file diff --git a/tests/cmdline/cmd_sys_exit_none.py b/tests/cmdline/cmd_sys_exit_none.py new file mode 100644 index 00000000000..66e19666589 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_none.py @@ -0,0 +1,5 @@ +# cmdline: +# test sys.exit(None) - should exit with code 0 +import sys + +sys.exit(None) diff --git a/tests/cmdline/cmd_sys_exit_none.py.exp b/tests/cmdline/cmd_sys_exit_none.py.exp new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_none.py.exp @@ -0,0 +1 @@ + diff --git a/tests/cmdline/cmd_verbose.py.exp b/tests/cmdline/cmd_verbose.py.exp index ae833dbec8d..1982f313cb7 100644 --- a/tests/cmdline/cmd_verbose.py.exp +++ b/tests/cmdline/cmd_verbose.py.exp @@ -1,4 +1,4 @@ -File cmdline/cmd_verbose.py, code block '' (descriptor: \.\+, bytecode @\.\+ 12 bytes) +File \.\*cmdline/cmd_verbose.py, code block '' (descriptor: \.\+, bytecode @\.\+ 12 bytes) Raw bytecode (code_info_size=4, bytecode_size=8): 08 04 01 40 11 02 81 34 01 59 51 63 arg names: diff --git a/tests/cmdline/repl_autocomplete.py.exp b/tests/cmdline/repl_autocomplete.py.exp index 2e2397bb028..7840e52e8a4 100644 --- a/tests/cmdline/repl_autocomplete.py.exp +++ b/tests/cmdline/repl_autocomplete.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # tests for autocompletion >>> import sys >>> not_exist. @@ -11,4 +11,4 @@ Use \.\+ >>> i.lower('ABC') 'abc' >>> None. ->>> +>>> \$ diff --git a/tests/cmdline/repl_autocomplete_underscore.py b/tests/cmdline/repl_autocomplete_underscore.py new file mode 100644 index 00000000000..a0ad4aadf0f --- /dev/null +++ b/tests/cmdline/repl_autocomplete_underscore.py @@ -0,0 +1,32 @@ +# Test REPL autocompletion filtering of underscore attributes + +# Start paste mode +{\x05} +class TestClass: + def __init__(self): + self.public_attr = 1 + self._private_attr = 2 + self.__very_private = 3 + + def public_method(self): + pass + + def _private_method(self): + pass + + @property + def public_property(self): + return 42 + + @property + def _private_property(self): + return 99 +{\x04} +# Paste executed + +# Create an instance +obj = TestClass() + +# Test tab completion on the instance +# The tab character after `obj.` and 'a' below triggers the completions +obj.{\x09}{\x09}a{\x09} diff --git a/tests/cmdline/repl_autocomplete_underscore.py.exp b/tests/cmdline/repl_autocomplete_underscore.py.exp new file mode 100644 index 00000000000..9c38a6b5900 --- /dev/null +++ b/tests/cmdline/repl_autocomplete_underscore.py.exp @@ -0,0 +1,41 @@ + +Adafruit CircuitPython \.\+ version +>>> # Test REPL autocompletion filtering of underscore attributes +>>> \$ +>>> # Start paste mode +>>> \$ +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== \$ +=== class TestClass: +=== def __init__(self): +=== self.public_attr = 1 +=== self._private_attr = 2 +=== self.__very_private = 3 +=== \$ +=== def public_method(self): +=== pass +=== \$ +=== def _private_method(self): +=== pass +=== \$ +=== @property +=== def public_property(self): +=== return 42 +=== \$ +=== @property +=== def _private_property(self): +=== return 99 +=== \$ +>>> \$ +>>> # Paste executed +>>> \$ +>>> # Create an instance +>>> obj = TestClass() +>>> \$ +>>> # Test tab completion on the instance +>>> # The tab character after `obj.` and 'a' below triggers the completions +>>> obj.public_ +public_attr public_method public_property +>>> obj.public_attr +1 +>>> \$ diff --git a/tests/cmdline/repl_autoindent.py.exp b/tests/cmdline/repl_autoindent.py.exp index 9ff83a92870..04f00686b20 100644 --- a/tests/cmdline/repl_autoindent.py.exp +++ b/tests/cmdline/repl_autoindent.py.exp @@ -1,22 +1,22 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # tests for autoindent >>> if 1: ... print(1) -... -... -... +... \$ +... \$ +... \$ 1 >>> if 0: ...  print(2) ... else: ... print(3) -... +... \$ 3 >>> if 0: ... print(4) ... else: ... print(5) -... +... \$ 5 ->>> +>>> \$ diff --git a/tests/cmdline/repl_basic.py.exp b/tests/cmdline/repl_basic.py.exp index 26442b64455..5bdcc9d6d32 100644 --- a/tests/cmdline/repl_basic.py.exp +++ b/tests/cmdline/repl_basic.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # basic REPL tests >>> print(1) 1 @@ -7,4 +7,4 @@ Use \.\+ 1 >>> 2 2 ->>> +>>> \$ diff --git a/tests/cmdline/repl_cont.py.exp b/tests/cmdline/repl_cont.py.exp index 6eed4a3e02c..41f2436ac18 100644 --- a/tests/cmdline/repl_cont.py.exp +++ b/tests/cmdline/repl_cont.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # check REPL allows to continue input >>> 1 \\\\ ... + 2 @@ -54,4 +54,4 @@ two >>> if1 = 2 >>> print(if1) 2 ->>> +>>> \$ diff --git a/tests/cmdline/repl_ctrl_c_interrupt_execution.py b/tests/cmdline/repl_ctrl_c_interrupt_execution.py new file mode 100644 index 00000000000..b125e2c16b4 --- /dev/null +++ b/tests/cmdline/repl_ctrl_c_interrupt_execution.py @@ -0,0 +1,8 @@ +# sigint: deliver via controlling terminal +# Test that Ctrl-C (SIGINT) interrupts blocking code execution. +# MicroPython restores original terminal mode (ISIG on) during +# execution, so the PTY terminal driver generates SIGINT from \x03. +import time +time.sleep(10) +{\x03} +print('repl still responds') diff --git a/tests/cmdline/repl_ctrl_c_interrupt_execution.py.exp b/tests/cmdline/repl_ctrl_c_interrupt_execution.py.exp new file mode 100644 index 00000000000..89c34b130be --- /dev/null +++ b/tests/cmdline/repl_ctrl_c_interrupt_execution.py.exp @@ -0,0 +1,15 @@ + +Adafruit CircuitPython \.\+ version +>>> # sigint: deliver via controlling terminal +>>> # Test that Ctrl-C (SIGINT) interrupts blocking code execution. +>>> # MicroPython restores original terminal mode (ISIG on) during +>>> # execution, so the PTY terminal driver generates SIGINT from \x03. +>>> import time +>>> time.sleep(10) +######## +\.\*Traceback (most recent call last): + File "", line 1, in +KeyboardInterrupt: \$ +>>> print('repl still responds') +repl still responds +>>> \$ diff --git a/tests/cmdline/repl_emacs_keys.py.exp b/tests/cmdline/repl_emacs_keys.py.exp index 2e8667a8e6c..4979f8bbfc3 100644 --- a/tests/cmdline/repl_emacs_keys.py.exp +++ b/tests/cmdline/repl_emacs_keys.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # REPL tests of GNU-ish readline navigation >>> # history buffer navigation >>> 1 @@ -16,4 +16,4 @@ Use \.\+ >>> t = 121 >>> \.\+ 'foobar' ->>> +>>> \$ diff --git a/tests/cmdline/repl_inspect.py.exp b/tests/cmdline/repl_inspect.py.exp index 8ece5ffc37f..30257f31aab 100644 --- a/tests/cmdline/repl_inspect.py.exp +++ b/tests/cmdline/repl_inspect.py.exp @@ -1,6 +1,6 @@ test -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # cmdline: -i -c print("test") >>> # -c option combined with -i option results in REPL ->>> +>>> \$ diff --git a/tests/cmdline/repl_lock.py b/tests/cmdline/repl_lock.py new file mode 100644 index 00000000000..77e2e932740 --- /dev/null +++ b/tests/cmdline/repl_lock.py @@ -0,0 +1,7 @@ +import micropython +micropython.heap_lock() +1+1 +micropython.heap_lock() +None # Cause the repl's line storage to be enlarged ---------------- +micropython.heap_lock() +raise SystemExit diff --git a/tests/cmdline/repl_lock.py.exp b/tests/cmdline/repl_lock.py.exp new file mode 100644 index 00000000000..e6d63fcf200 --- /dev/null +++ b/tests/cmdline/repl_lock.py.exp @@ -0,0 +1,10 @@ + +Adafruit CircuitPython \.\+ version +>>> import micropython +>>> micropython.heap_lock() +>>> 1+1 +2 +>>> micropython.heap_lock() +>>> None # Cause the repl's line storage to be enlarged ---------------- +>>> micropython.heap_lock() +>>> raise SystemExit diff --git a/tests/cmdline/repl_micropyinspect.py.exp b/tests/cmdline/repl_micropyinspect.py.exp index 3c9cbc030c0..36bef37c62c 100644 --- a/tests/cmdline/repl_micropyinspect.py.exp +++ b/tests/cmdline/repl_micropyinspect.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # cmdline: cmdline/repl_micropyinspect >>> # setting MICROPYINSPECT environment variable before program exit triggers REPL ->>> +>>> \$ diff --git a/tests/cmdline/repl_paste.py b/tests/cmdline/repl_paste.py new file mode 100644 index 00000000000..8c4f341701f --- /dev/null +++ b/tests/cmdline/repl_paste.py @@ -0,0 +1,90 @@ +# Test REPL paste mode functionality + +# Basic paste mode with a simple function +{\x05} +def hello(): + print('Hello from paste mode!') +hello() +{\x04} + +# Paste mode with multiple indentation levels +{\x05} +def calculate(n): + if n > 0: + for i in range(n): + if i % 2 == 0: + print(f'Even: {i}') + else: + print(f'Odd: {i}') + else: + print('n must be positive') + +calculate(5) +{\x04} + +# Paste mode with blank lines +{\x05} +def function_with_blanks(): + print('First line') +{\x20}{\x20}{\x20}{\x20} + print('After blank line') +{\x20}{\x20}{\x20}{\x20} +{\x20}{\x20}{\x20}{\x20} + print('After two blank lines') + +function_with_blanks() +{\x04} + +# Paste mode with class definition and multiple methods +{\x05} +class TestClass: + def __init__(self, value): + self.value = value +{\x20}{\x20}{\x20}{\x20} + def display(self): + print(f'Value is: {self.value}') +{\x20}{\x20}{\x20}{\x20} + def double(self): + self.value *= 2 + return self.value + +obj = TestClass(21) +obj.display() +print(f'Doubled: {obj.double()}') +obj.display() +{\x04} + +# Paste mode with exception handling +{\x05} +try: + x = 1 / 0 +except ZeroDivisionError: + print('Caught division by zero') +finally: + print('Finally block executed') +{\x04} + +# Cancel paste mode with Ctrl-C +{\x05} +print('This should not execute') +{\x03} + +# Normal REPL still works after cancelled paste +print('Back to normal REPL') + +# Paste mode with syntax error +{\x05} +def bad_syntax(: + print('Missing parameter') +{\x04} + +# Paste mode with runtime error +{\x05} +def will_error(): + undefined_variable +{\x20}{\x20}{\x20}{\x20} +will_error() +{\x04} + +# Final test to show REPL is still functioning +1 + 2 + 3 diff --git a/tests/cmdline/repl_paste.py.exp b/tests/cmdline/repl_paste.py.exp new file mode 100644 index 00000000000..c60f07fe8d4 --- /dev/null +++ b/tests/cmdline/repl_paste.py.exp @@ -0,0 +1,140 @@ + +Adafruit CircuitPython \.\+ version +>>> # Test REPL paste mode functionality +>>> \$ +>>> # Basic paste mode with a simple function +>>> \$ +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== \$ +=== def hello(): +=== print('Hello from paste mode!') +=== hello() +=== \$ +Hello from paste mode! +>>> \$ +>>> \$ +>>> # Paste mode with multiple indentation levels +>>> \$ +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== \$ +=== def calculate(n): +=== if n > 0: +=== for i in range(n): +=== if i % 2 == 0: +=== print(f'Even: {i}') +=== else: +=== print(f'Odd: {i}') +=== else: +=== print('n must be positive') +=== \$ +=== calculate(5) +=== \$ +Even: 0 +Odd: 1 +Even: 2 +Odd: 3 +Even: 4 +>>> \$ +>>> \$ +>>> # Paste mode with blank lines +>>> \$ +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== \$ +=== def function_with_blanks(): +=== print('First line') +=== \$ +=== print('After blank line') +=== \$ +=== \$ +=== print('After two blank lines') +=== \$ +=== function_with_blanks() +=== \$ +First line +After blank line +After two blank lines +>>> \$ +>>> \$ +>>> # Paste mode with class definition and multiple methods +>>> \$ +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== \$ +=== class TestClass: +=== def __init__(self, value): +=== self.value = value +=== \$ +=== def display(self): +=== print(f'Value is: {self.value}') +=== \$ +=== def double(self): +=== self.value *= 2 +=== return self.value +=== \$ +=== obj = TestClass(21) +=== obj.display() +=== print(f'Doubled: {obj.double()}') +=== obj.display() +=== \$ +Value is: 21 +Doubled: 42 +Value is: 42 +>>> \$ +>>> \$ +>>> # Paste mode with exception handling +>>> \$ +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== \$ +=== try: +=== x = 1 / 0 +=== except ZeroDivisionError: +=== print('Caught division by zero') +=== finally: +=== print('Finally block executed') +=== \$ +Caught division by zero +Finally block executed +>>> \$ +>>> \$ +>>> # Cancel paste mode with Ctrl-C +>>> \$ +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== \$ +=== print('This should not execute') +=== \$ +>>> \$ +>>> \$ +>>> # Normal REPL still works after cancelled paste +>>> print('Back to normal REPL') +Back to normal REPL +>>> \$ +>>> # Paste mode with syntax error +>>> \$ +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== \$ +=== def bad_syntax(: +=== print('Missing parameter') +=== \$ +Traceback (most recent call last): + File "", line 2 +SyntaxError: invalid syntax +>>> \$ +>>> \$ +>>> # Paste mode with runtime error +>>> \$ +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== \$ +=== def will_error(): +=== undefined_variable +=== \$ +=== will_error() +=== \$ +Traceback (most recent call last): + File "", line 5, in + File "", line 3, in will_error +NameError: name 'undefined_variable' isn't defined +>>> \$ +>>> \$ +>>> # Final test to show REPL is still functioning +>>> 1 + 2 + 3 +6 +>>> \$ diff --git a/tests/cmdline/repl_sys_ps1_ps2.py.exp b/tests/cmdline/repl_sys_ps1_ps2.py.exp index 452a54fe5ae..d4bcf7a44d5 100644 --- a/tests/cmdline/repl_sys_ps1_ps2.py.exp +++ b/tests/cmdline/repl_sys_ps1_ps2.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # test changing ps1/ps2 >>> import sys >>> sys.ps1 = "PS1" diff --git a/tests/cmdline/repl_words_move.py.exp b/tests/cmdline/repl_words_move.py.exp index ba5c3648cff..41ad3d8e733 100644 --- a/tests/cmdline/repl_words_move.py.exp +++ b/tests/cmdline/repl_words_move.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # word movement >>> # backward-word, start in word >>> \.\+ @@ -19,7 +19,7 @@ Use \.\+ >>> # forward-word on eol. if cursor is moved, this will result in a SyntaxError >>> \.\+ 6 ->>> +>>> \$ >>> # kill word >>> # backward-kill-word, start in word >>> \.\+ @@ -33,7 +33,7 @@ Use \.\+ >>> # forward-kill-word, don't start in word >>> \.\+ 3 ->>> +>>> \$ >>> # extra move/kill shortcuts >>> # ctrl-left >>> \.\+ @@ -44,4 +44,4 @@ Use \.\+ >>> # ctrl-w >>> \.\+ 1 ->>> +>>> \$ diff --git a/tests/cpydiff/core_class_dir.py b/tests/cpydiff/core_class_dir.py new file mode 100644 index 00000000000..e2b0e877cdc --- /dev/null +++ b/tests/cpydiff/core_class_dir.py @@ -0,0 +1,14 @@ +""" +categories: Core,Classes +description: dir() does not convert __dir__ return value to a sorted list +cause: MicroPython's dir() returns the value from __dir__ as-is, without iterating it into a list or sorting it. +workaround: Have __dir__ return a sorted list directly. +""" + + +class C: + def __dir__(self): + return "cba" + + +print(dir(C())) diff --git a/tests/cpydiff/core_class_initsubclass.py b/tests/cpydiff/core_class_initsubclass.py new file mode 100644 index 00000000000..8683271dcb0 --- /dev/null +++ b/tests/cpydiff/core_class_initsubclass.py @@ -0,0 +1,21 @@ +""" +categories: Core,Classes +description: ``__init_subclass__`` isn't automatically called. +cause: MicroPython does not currently implement PEP 487. +workaround: Manually call ``__init_subclass__`` after class creation if needed. e.g.:: + + class A(Base): + pass + A.__init_subclass__() + +""" + + +class Base: + @classmethod + def __init_subclass__(cls): + print(f"Base.__init_subclass__({cls.__name__})") + + +class A(Base): + pass diff --git a/tests/cpydiff/core_class_initsubclass_autoclassmethod.py b/tests/cpydiff/core_class_initsubclass_autoclassmethod.py new file mode 100644 index 00000000000..b2f7628976c --- /dev/null +++ b/tests/cpydiff/core_class_initsubclass_autoclassmethod.py @@ -0,0 +1,31 @@ +""" +categories: Core,Classes +description: ``__init_subclass__`` isn't an implicit classmethod. +cause: MicroPython does not currently implement PEP 487. ``__init_subclass__`` is not currently in the list of special-cased class/static methods. +workaround: Decorate declarations of ``__init_subclass__`` with ``@classmethod``. +""" + + +def regularize_spelling(text, prefix="bound_"): + # for regularizing across the CPython "method" vs MicroPython "bound_method" spelling for the type of a bound classmethod + if text.startswith(prefix): + return text[len(prefix) :] + return text + + +class A: + def __init_subclass__(cls): + pass + + @classmethod + def manual_decorated(cls): + pass + + +a = type(A.__init_subclass__).__name__ +b = type(A.manual_decorated).__name__ + +print(regularize_spelling(a)) +print(regularize_spelling(b)) +if a != b: + print("FAIL") diff --git a/tests/cpydiff/core_class_initsubclass_kwargs.py b/tests/cpydiff/core_class_initsubclass_kwargs.py new file mode 100644 index 00000000000..ed5157afeae --- /dev/null +++ b/tests/cpydiff/core_class_initsubclass_kwargs.py @@ -0,0 +1,22 @@ +""" +categories: Core,Classes +description: MicroPython doesn't support parameterized ``__init_subclass__`` class customization. +cause: MicroPython does not currently implement PEP 487. The MicroPython syntax tree does not include a kwargs node after the class inheritance list. +workaround: Use class variables or another mechanism to specify base-class customizations. +""" + + +class Base: + @classmethod + def __init_subclass__(cls, arg=None, **kwargs): + cls.init_subclass_was_called = True + print(f"Base.__init_subclass__({cls.__name__}, {arg=!r}, {kwargs=!r})") + + +class A(Base, arg="arg"): + pass + + +# Regularize across MicroPython not automatically calling __init_subclass__ either. +if not getattr(A, "init_subclass_was_called", False): + A.__init_subclass__() diff --git a/tests/cpydiff/core_class_initsubclass_super.py b/tests/cpydiff/core_class_initsubclass_super.py new file mode 100644 index 00000000000..d18671a74bf --- /dev/null +++ b/tests/cpydiff/core_class_initsubclass_super.py @@ -0,0 +1,22 @@ +""" +categories: Core,Classes +description: ``__init_subclass__`` can't be defined a cooperatively-recursive way. +cause: MicroPython does not currently implement PEP 487. The base object type does not have an ``__init_subclass__`` implementation. +workaround: Omit the recursive ``__init_subclass__`` call unless it's known that the grandparent also defines it. +""" + + +class Base: + @classmethod + def __init_subclass__(cls, **kwargs): + cls.init_subclass_was_called = True + super().__init_subclass__(**kwargs) + + +class A(Base): + pass + + +# Regularize across MicroPython not automatically calling __init_subclass__ either. +if not getattr(A, "init_subclass_was_called", False): + A.__init_subclass__() diff --git a/tests/cpydiff/core_class_strrettype.py b/tests/cpydiff/core_class_strrettype.py new file mode 100644 index 00000000000..398b5bb1a3b --- /dev/null +++ b/tests/cpydiff/core_class_strrettype.py @@ -0,0 +1,14 @@ +""" +categories: Core,Classes +description: ``__str__`` returning non-string type does not raise TypeError +cause: MicroPython's instance_print does not validate that ``__str__`` or ``__repr__`` return a str or its subclass +workaround: Ensure ``__str__`` and ``__repr__`` always return a str instance or its subclass +""" + + +class Foo: + def __str__(self): + return True + + +print(str(Foo())) diff --git a/tests/cpydiff/core_class_subclassret.py b/tests/cpydiff/core_class_subclassret.py new file mode 100644 index 00000000000..681a16e879b --- /dev/null +++ b/tests/cpydiff/core_class_subclassret.py @@ -0,0 +1,19 @@ +""" +categories: Core,Classes +description: str() does not preserve str subclass type from ``__str__`` or ``__repr__`` return value +cause: Implementation discards str subclass type returned by ``__str__`` or ``__repr__`` and always returns a plain str instance from str(). +workaround: Do not rely on str() preserving str subclass types +""" + + +class MyStr(str): + pass + + +class Foo: + def __str__(self): + return MyStr("abc") + + +result = str(Foo()) +print(type(result)) diff --git a/tests/cpydiff/core_exception_construction.py b/tests/cpydiff/core_exception_construction.py new file mode 100644 index 00000000000..56a358f4c45 --- /dev/null +++ b/tests/cpydiff/core_exception_construction.py @@ -0,0 +1,28 @@ +""" +categories: Core,Exceptions +description: Throwing a derived exception class instance in its `__init__` without first calling ``super().__init__`` is a TypeError +cause: In MicroPython, an object is incompletely constructed if it does not call its superclass init function or return normally from its ``__init__``. This prevents its usage in some circumstances. +workaround: Call the superclass `__init__` method before raising the exception. +""" + + +class C(Exception): + def __init__(self): + raise self + + +class C1(Exception): + def __init__(self): + super().__init__() + raise self + + +try: + C() +except Exception as e: + print(type(e).__name__) + +try: + C1() +except Exception as e: + print(type(e).__name__) diff --git a/tests/cpydiff/core_fstring_concat.py b/tests/cpydiff/core_fstring_concat.py index 3daa13d7536..2fbe1b961a1 100644 --- a/tests/cpydiff/core_fstring_concat.py +++ b/tests/cpydiff/core_fstring_concat.py @@ -1,5 +1,5 @@ """ -categories: Core +categories: Core,f-strings description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces cause: MicroPython is optimised for code space. workaround: Use the + operator between literal strings when they are not both f-strings diff --git a/tests/cpydiff/core_fstring_parser.py b/tests/cpydiff/core_fstring_parser.py index 87cf1e63ed8..4964b9707ac 100644 --- a/tests/cpydiff/core_fstring_parser.py +++ b/tests/cpydiff/core_fstring_parser.py @@ -1,5 +1,5 @@ """ -categories: Core +categories: Core,f-strings description: f-strings cannot support expressions that require parsing to resolve unbalanced nested braces and brackets cause: MicroPython is optimised for code space. workaround: Always use balanced braces and brackets in expressions inside f-strings diff --git a/tests/cpydiff/core_fstring_repr.py b/tests/cpydiff/core_fstring_repr.py index d37fb48db75..2589a34b7e3 100644 --- a/tests/cpydiff/core_fstring_repr.py +++ b/tests/cpydiff/core_fstring_repr.py @@ -1,5 +1,5 @@ """ -categories: Core +categories: Core,f-strings description: f-strings don't support !a conversions cause: MicropPython does not implement ascii() workaround: None diff --git a/tests/cpydiff/core_function_star.py b/tests/cpydiff/core_function_star.py new file mode 100644 index 00000000000..26f5effd4e3 --- /dev/null +++ b/tests/cpydiff/core_function_star.py @@ -0,0 +1,16 @@ +""" +categories: Core,Functions +description: ``*args`` cannot follow a keyword argument +cause: MicroPython is optimised for code space. For more information see `this issue `_. +workaround: Re-order the arguments +""" + + +def f(x, y): + return x + y + + +try: + print(f(y=1, *(3,))) +except Exception as e: + print(e) diff --git a/tests/cpydiff/core_import_all.py b/tests/cpydiff/core_import_all.py deleted file mode 100644 index 0fbe9d4d4ec..00000000000 --- a/tests/cpydiff/core_import_all.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -categories: Core,import -description: __all__ is unsupported in __init__.py in MicroPython. -cause: Not implemented. -workaround: Manually import the sub-modules directly in __init__.py using ``from . import foo, bar``. -""" - -from modules3 import * - -foo.hello() diff --git a/tests/cpydiff/modules3/__init__.py b/tests/cpydiff/modules3/__init__.py deleted file mode 100644 index 27a2bf2ad90..00000000000 --- a/tests/cpydiff/modules3/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ["foo"] diff --git a/tests/cpydiff/modules3/foo.py b/tests/cpydiff/modules3/foo.py deleted file mode 100644 index dd9b9d4ddd4..00000000000 --- a/tests/cpydiff/modules3/foo.py +++ /dev/null @@ -1,2 +0,0 @@ -def hello(): - print("hello") diff --git a/tests/cpydiff/modules_errno_enotsup.py b/tests/cpydiff/modules_errno_enotsup.py new file mode 100644 index 00000000000..80e5ad9d032 --- /dev/null +++ b/tests/cpydiff/modules_errno_enotsup.py @@ -0,0 +1,10 @@ +""" +categories: Modules,errno +description: MicroPython does not include ``ENOTSUP`` as a name for errno 95. +cause: MicroPython does not implement the ``ENOTSUP`` canonical alias for ``EOPNOTSUPP`` added in CPython 3.2. +workaround: Use ``errno.EOPNOTSUPP`` in place of ``errno.ENOTSUP``. +""" + +import errno + +print(f"{errno.errorcode[errno.EOPNOTSUPP]=!s}") diff --git a/tests/cpydiff/modules_struct_fewargs.py b/tests/cpydiff/modules_struct_fewargs.py index 49b2a3213c8..f6346a67938 100644 --- a/tests/cpydiff/modules_struct_fewargs.py +++ b/tests/cpydiff/modules_struct_fewargs.py @@ -1,6 +1,6 @@ """ categories: Modules,struct -description: Struct pack with too few args, not checked by uPy +description: Struct pack with too few args, not checked by MicroPython cause: Unknown workaround: Unknown """ diff --git a/tests/cpydiff/modules_struct_manyargs.py b/tests/cpydiff/modules_struct_manyargs.py index e3b78930f21..b2ea93b6c93 100644 --- a/tests/cpydiff/modules_struct_manyargs.py +++ b/tests/cpydiff/modules_struct_manyargs.py @@ -1,6 +1,6 @@ """ categories: Modules,struct -description: Struct pack with too many args, not checked by uPy +description: Struct pack with too many args, not checked by MicroPython cause: Unknown workaround: Unknown """ diff --git a/tests/cpydiff/modules_struct_whitespace_in_format.py b/tests/cpydiff/modules_struct_whitespace_in_format.py index a7a1d2facdf..8b609425eb0 100644 --- a/tests/cpydiff/modules_struct_whitespace_in_format.py +++ b/tests/cpydiff/modules_struct_whitespace_in_format.py @@ -1,6 +1,6 @@ """ categories: Modules,struct -description: Struct pack with whitespace in format, whitespace ignored by CPython, error on uPy +description: Struct pack with whitespace in format, whitespace ignored by CPython, error on MicroPython cause: MicroPython is optimised for code size. workaround: Don't use spaces in format strings. """ diff --git a/tests/cpydiff/syntax_annotation_expression.py b/tests/cpydiff/syntax_annotation_expression.py new file mode 100644 index 00000000000..91814ec9522 --- /dev/null +++ b/tests/cpydiff/syntax_annotation_expression.py @@ -0,0 +1,24 @@ +""" +categories: Syntax,Annotations +description: MicroPython accepts type annotations on expressions where CPython forbids them. +cause: To reduce code size, MicroPython does not check the form of expressions with type annotations applied. +workaround: Always check for valid Python code using a linting tool. + +The expressions themselves are not evaluated. +""" + + +def test(expr): + code = f"def f():\n {expr}: int" + print(code) + try: + exec(code) + print("OK") + except SyntaxError as e: + print("SyntaxError") + print() + + +test("print('test')") +test("[x,y]") +test("x,y") diff --git a/tests/cpydiff/syntax_arg_unpacking.py b/tests/cpydiff/syntax_arg_unpacking.py index e54832ddb91..7133a8a2827 100644 --- a/tests/cpydiff/syntax_arg_unpacking.py +++ b/tests/cpydiff/syntax_arg_unpacking.py @@ -1,5 +1,5 @@ """ -categories: Syntax +categories: Syntax,Unpacking description: Argument unpacking does not work if the argument being unpacked is the nth or greater argument where n is the number of bits in an MP_SMALL_INT. cause: The implementation uses an MP_SMALL_INT to flag args that need to be unpacked. workaround: Use fewer arguments. diff --git a/tests/cpydiff/syntax_literal_underscore.py b/tests/cpydiff/syntax_literal_underscore.py new file mode 100644 index 00000000000..4b1406e9f3f --- /dev/null +++ b/tests/cpydiff/syntax_literal_underscore.py @@ -0,0 +1,19 @@ +""" +categories: Syntax,Literals +description: MicroPython accepts underscores in numeric literals where CPython doesn't +cause: Different parser implementation + +MicroPython's tokenizer ignores underscores in numeric literals, while CPython +rejects multiple consecutive underscores and underscores after the last digit. + +workaround: Remove the underscores not accepted by CPython. +""" + +try: + print(eval("1__1")) +except SyntaxError: + print("Should not work") +try: + print(eval("1_")) +except SyntaxError: + print("Should not work") diff --git a/tests/cpydiff/syntax_spaces.py b/tests/cpydiff/syntax_spaces.py index 03d25d56199..670cefdeac2 100644 --- a/tests/cpydiff/syntax_spaces.py +++ b/tests/cpydiff/syntax_spaces.py @@ -1,8 +1,15 @@ """ -categories: Syntax,Spaces -description: uPy requires spaces between literal numbers and keywords, CPy doesn't -cause: Unknown -workaround: Unknown +categories: Syntax,Literals +description: MicroPython requires spaces between literal numbers and keywords or ".", CPython doesn't +cause: Different parser implementation + +MicroPython's tokenizer treats a sequence like ``1and`` as a single token, while CPython treats it as two tokens. + +Since CPython 3.11, when the literal number is followed by a token, this syntax causes a ``SyntaxWarning`` for an "invalid literal". When a literal number is followed by a "." denoting attribute access, CPython does not warn. + +workaround: Add a space between the integer literal and the intended next token. + +This also fixes the ``SyntaxWarning`` in CPython. """ try: @@ -17,3 +24,7 @@ print(eval("1if 1else 0")) except SyntaxError: print("Should have worked") +try: + print(eval("0x1.to_bytes(1)")) +except SyntaxError: + print("Should have worked") diff --git a/tests/cpydiff/types_bytes_decode_encoding.py b/tests/cpydiff/types_bytes_decode_encoding.py new file mode 100644 index 00000000000..17a129a2af9 --- /dev/null +++ b/tests/cpydiff/types_bytes_decode_encoding.py @@ -0,0 +1,30 @@ +""" +categories: Types,bytes +description: bytes.decode() only supports encoding arguments 'utf8', 'utf-8' and 'ascii'. Other encodings like 'latin-1' are not supported. Other string forms such as 'UTF8' are not supported. +cause: MicroPython is optimised for embedded systems and only includes UTF-8 and ASCII codec support with simple matching to save memory and code size. `The same restriction applies to str constructor `. See also `unicode_support`. +workaround: Convert data to UTF-8 before processing, or implement custom encoding/decoding if needed. Ensure encoding argument is one of the accepted forms. +""" + +# Both CPython and MicroPython support utf8 and ascii encodings +print(b"caf\xc3\xa9".decode("utf8")) # codespell:ignore caf +print(b"cafe".decode("ascii")) + +# MicroPython does not support additional encodings +try: + b"\xe9".decode("latin-1") # 'é' in latin-1 + print("latin-1 supported") +except (ValueError, NotImplementedError, LookupError) as e: + print("latin-1 not supported:", type(e).__name__) + +try: + b"\x80".decode("cp1252") # Euro sign in cp1252 + print("cp1252 supported") +except (ValueError, NotImplementedError, LookupError) as e: + print("cp1252 not supported:", type(e).__name__) + +# Encoding arguments must match exactly in MicroPython +try: + b"hello".decode("ASCII") + print("Capital letters ASCII supported") +except (ValueError, NotImplementedError, LookupError) as e: + print("Capital letters ASCII not supported:", type(e).__name__) diff --git a/tests/cpydiff/types_bytes_decode_kwargs.py b/tests/cpydiff/types_bytes_decode_kwargs.py new file mode 100644 index 00000000000..a1ca2b74c5c --- /dev/null +++ b/tests/cpydiff/types_bytes_decode_kwargs.py @@ -0,0 +1,19 @@ +""" +categories: Types,bytes +description: bytes.decode() does not accept keyword arguments, only positional arguments +cause: MicroPython optimizes for code size and does not implement keyword argument handling for bytes.decode() +workaround: Use positional arguments instead of keyword arguments +""" + +# CPython accepts keyword arguments, MicroPython only accepts positional +b = b"hello\xffworld" + +try: + # Using keyword arguments + result = b.decode(encoding="utf-8", errors="ignore") + print("kwargs supported:", repr(result)) +except TypeError as e: + print("kwargs not supported: TypeError") + # Workaround: use positional arguments + result = b.decode("utf-8", "ignore") + print("positional args work:", repr(result)) diff --git a/tests/cpydiff/types_bytes_encoding.py b/tests/cpydiff/types_bytes_encoding.py new file mode 100644 index 00000000000..0fe3c976589 --- /dev/null +++ b/tests/cpydiff/types_bytes_encoding.py @@ -0,0 +1,21 @@ +""" +categories: Types,bytes +description: bytes() constructor only supports encoding arguments 'utf8', 'utf-8' and 'ascii'. Other encodings like 'latin-1' are not supported. Other string forms such as 'UTF8' are not supported. +cause: MicroPython is optimised for embedded systems and has limited codec support to save code size. `A similar restriction applies to str.encode() `. See also `unicode_support`. +workaround: Implement other encoding conversions manually by parsing the result of str.encode() or bytes() constructor. +""" + +# Both CPython and MicroPython can encode this emoji as UTF-8 bytes +print(bytes("😀", "utf8")) + +# Both CPython and MicroPython will fail to encode this emoji as ASCII bytes +try: + print(bytes("😀", "ascii")) +except UnicodeError: + print("UnicodeError") + +# Other encodings or string formats aren't accepted by MicroPython +try: + print(bytes("😀", "UTF-8")) +except LookupError: + print("LookupError") diff --git a/tests/cpydiff/types_complex_parser.py b/tests/cpydiff/types_complex_parser.py new file mode 100644 index 00000000000..4a012987d9e --- /dev/null +++ b/tests/cpydiff/types_complex_parser.py @@ -0,0 +1,14 @@ +""" +categories: Types,complex +description: MicroPython's complex() accepts certain incorrect values that CPython rejects +cause: MicroPython is highly optimized for memory usage. +workaround: Do not use non-standard complex literals as argument to complex() + +MicroPython's ``complex()`` function accepts literals that contain a space and +no sign between the real and imaginary parts, and interprets it as a plus. +""" + +try: + print(complex("1 1j")) +except ValueError: + print("ValueError") diff --git a/tests/cpydiff/types_float_implicit_conversion.py b/tests/cpydiff/types_float_implicit_conversion.py index 3726839fac6..764c9e4e6ed 100644 --- a/tests/cpydiff/types_float_implicit_conversion.py +++ b/tests/cpydiff/types_float_implicit_conversion.py @@ -1,6 +1,6 @@ """ categories: Types,float -description: uPy allows implicit conversion of objects in maths operations while CPython does not. +description: MicroPython allows implicit conversion of objects in maths operations while CPython does not. cause: Unknown workaround: Objects should be wrapped in ``float(obj)`` for compatibility with CPython. """ diff --git a/tests/cpydiff/types_float_rounding.py b/tests/cpydiff/types_float_rounding.py deleted file mode 100644 index 206e359ed9b..00000000000 --- a/tests/cpydiff/types_float_rounding.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -categories: Types,float -description: uPy and CPython outputs formats may differ -cause: Unknown -workaround: Unknown -""" - -print("%.1g" % -9.9) diff --git a/tests/cpydiff/types_int_to_bytes.py b/tests/cpydiff/types_int_to_bytes.py deleted file mode 100644 index 6530a2a32ec..00000000000 --- a/tests/cpydiff/types_int_to_bytes.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -categories: Types,int -description: ``to_bytes`` method doesn't implement signed parameter. -cause: The ``signed`` keyword-only parameter is not implemented for ``int.to_bytes()``. - -When the integer is negative, MicroPython behaves the same as CPython ``int.to_bytes(..., signed=True)`` - -When the integer is non-negative, MicroPython behaves the same as CPython ``int.to_bytes(..., signed=False)``. - -(The difference is subtle, but in CPython a positive integer converted with ``signed=True`` may require one byte more in the output length, in order to fit the 0 sign bit.) - -workaround: Take care when calling ``to_bytes()`` on an integer value which may be negative. -""" - -x = -1 -print(x.to_bytes(1, "big")) diff --git a/tests/cpydiff/types_oserror_errnomap.py b/tests/cpydiff/types_oserror_errnomap.py new file mode 100644 index 00000000000..6627bd2af4a --- /dev/null +++ b/tests/cpydiff/types_oserror_errnomap.py @@ -0,0 +1,48 @@ +""" +categories: Types,OSError +description: OSError constructor returns a plain OSError for all errno values, rather than a relevant subtype. +cause: MicroPython does not include the CPython-standard OSError subclasses. +workaround: Catch OSError and use its errno attribute to discriminate the cause. +""" + +import errno + +errno_list = [ # i.e. the set implemented by micropython + errno.EPERM, + errno.ENOENT, + errno.EIO, + errno.EBADF, + errno.EAGAIN, + errno.ENOMEM, + errno.EACCES, + errno.EEXIST, + errno.ENODEV, + errno.EISDIR, + errno.EINVAL, + errno.EOPNOTSUPP, + errno.EADDRINUSE, + errno.ECONNABORTED, + errno.ECONNRESET, + errno.ENOBUFS, + errno.ENOTCONN, + errno.ETIMEDOUT, + errno.ECONNREFUSED, + errno.EHOSTUNREACH, + errno.EALREADY, + errno.EINPROGRESS, +] + + +def errno_output_type(n): + try: + raise OSError(n, "") + except OSError as e: + return f"{type(e).__name__}" + except Exception as e: + return f"non-OSError {type(e).__name__}" + else: + return "no error" + + +for n in errno_list: + print(errno.errorcode[n], "=", errno_output_type(n)) diff --git a/tests/cpydiff/types_range_limits.py b/tests/cpydiff/types_range_limits.py new file mode 100644 index 00000000000..dca830d3fbc --- /dev/null +++ b/tests/cpydiff/types_range_limits.py @@ -0,0 +1,32 @@ +""" +categories: Types,range +description: Range arguments must fit in a machine word; large start or stop values misbehave. +cause: Range stores its arguments as the C mp_int_t type, and intermediate calculations also use it. +workaround: Avoid using such ranges +""" + +from sys import maxsize + +# A range including `maxsize-1` cannot be created +try: + print(range(-maxsize - 1, 0)) +except OverflowError: + print("OverflowError") + +# A range with start or stop outside [-maxsize, maxsize] cannot be created, even if the range itself would be small. +try: + print(range(maxsize + 1, maxsize + 2)) +except OverflowError: + print("OverflowError") + +# A range with `stop-start` exceeding sys.maxsize has incorrect len(), while CPython cannot calculate len(). +try: + print(len(range(-maxsize, maxsize))) +except OverflowError: + print("OverflowError") + +# A range with `stop-start` exceeding sys.maxsize has incorrect len() +try: + print(len(range(-maxsize, maxsize, maxsize))) +except OverflowError: + print("OverflowError") diff --git a/tests/cpydiff/types_str_encode_encoding.py b/tests/cpydiff/types_str_encode_encoding.py new file mode 100644 index 00000000000..12f6b947262 --- /dev/null +++ b/tests/cpydiff/types_str_encode_encoding.py @@ -0,0 +1,21 @@ +""" +categories: Types,str +description: str.encode() constructor only supports encoding arguments 'utf8', 'utf-8' and 'ascii'. Other encodings like 'latin-1' are not supported. Other string forms such as 'UTF8' are not supported. +cause: MicroPython is optimised for embedded systems and has limited codec support to save code size. `A similar restriction applies to bytes constructor `. See also `unicode_support`. +workaround: Implement encoding conversions manually by parsing the result of str.encode() or bytes() constructor. +""" + +# Both CPython and MicroPython can encode this emoji as UTF-8 bytes +print("😀".encode("utf8")) + +# Both CPython and MicroPython will fail to encode this emoji as ASCII bytes +try: + print("😀".encode("ascii")) +except UnicodeError: + print("UnicodeError") + +# Other encodings or string formats aren't accepted by MicroPython: +try: + print("😀".encode("UTF-8")) +except LookupError: + print("LookupError") diff --git a/tests/cpydiff/types_str_encode_errors.py b/tests/cpydiff/types_str_encode_errors.py new file mode 100644 index 00000000000..2e2550b0538 --- /dev/null +++ b/tests/cpydiff/types_str_encode_errors.py @@ -0,0 +1,19 @@ +""" +categories: Types,str +description: str.encode() and bytes() constructor ignore any ``errors`` argument specified. If the encoding is specified as ``'ascii'`` and a non-ASCII byte is found in the string then an exception is always raised. +cause: MicroPython is optimised for embedded systems and has limited codec support to save code size. See also `unicode_support`. +workaround: Handle encoding errors manually by parsing the result of str.encode() or bytes() constructor. +""" + +# CPython will replace the emoji with an ASCII '?' but MicroPython will +# raise an exception +try: + print("😀".encode("ascii", "replace")) +except UnicodeError: + print("UnicodeError") + +# CPython will ignore the emoji in the result but MicroPython will raise an exception +try: + print("😀".encode("ascii", "ignore")) +except UnicodeError: + print("UnicodeError") diff --git a/tests/cpydiff/types_str_encoding.py b/tests/cpydiff/types_str_encoding.py new file mode 100644 index 00000000000..b97b984c22e --- /dev/null +++ b/tests/cpydiff/types_str_encoding.py @@ -0,0 +1,30 @@ +""" +categories: Types,str +description: str() constructor only supports encoding arguments 'utf8', 'utf-8' and 'ascii'. Other encodings like 'latin-1' are not supported. Other string forms such as 'UTF8' are not supported. +cause: MicroPython is optimised for embedded systems and only includes UTF-8 and ASCII codec support with simple matching to save memory and code size. `The same restriction applies to bytes.decode() `. See also `unicode_support`. +workaround: Convert data to UTF-8 before processing, or implement custom encoding/decoding if needed. Ensure encoding argument is one of the accepted forms. +""" + +# Both CPython and MicroPython support utf8 and ascii encodings +print(str(b"caf\xc3\xa9", "utf8")) # codespell:ignore caf +print(str(b"cafe", "ascii")) + +# MicroPython does not support additional encodings +try: + str(b"\xe9", "latin-1") # 'é' in latin-1 + print("latin-1 supported") +except (ValueError, NotImplementedError, LookupError) as e: + print("latin-1 not supported:", type(e).__name__) + +try: + str(b"\x80", "cp1252") # Euro sign in cp1252 + print("cp1252 supported") +except (ValueError, NotImplementedError, LookupError) as e: + print("cp1252 not supported:", type(e).__name__) + +# Encoding arguments must match exactly in MicroPython +try: + str(b"hello", "ASCII") + print("Capital letters ASCII supported") +except (ValueError, NotImplementedError, LookupError) as e: + print("Capital letters ASCII not supported:", type(e).__name__) diff --git a/tests/cpydiff/types_str_formatsep.py b/tests/cpydiff/types_str_formatsep.py new file mode 100644 index 00000000000..05d0b8d3d2c --- /dev/null +++ b/tests/cpydiff/types_str_formatsep.py @@ -0,0 +1,19 @@ +""" +categories: Types,str +description: MicroPython accepts the "," grouping option with any radix, unlike CPython +cause: To reduce code size, MicroPython does not issue an error for this combination +workaround: Do not use a format string like ``{:,b}`` if CPython compatibility is required. +""" + +try: + print("{:,b}".format(99)) +except ValueError: + print("ValueError") +try: + print("{:,x}".format(99)) +except ValueError: + print("ValueError") +try: + print("{:,o}".format(99)) +except ValueError: + print("ValueError") diff --git a/tests/cpydiff/types_str_formatsep_float.py b/tests/cpydiff/types_str_formatsep_float.py new file mode 100644 index 00000000000..b487cd3758e --- /dev/null +++ b/tests/cpydiff/types_str_formatsep_float.py @@ -0,0 +1,11 @@ +""" +categories: Types,str +description: MicroPython accepts but does not properly implement the "," or "_" grouping character for float values +cause: To reduce code size, MicroPython does not implement this combination. Grouping characters will not appear in the number's significant digits and will appear at incorrect locations in leading zeros. +workaround: Do not use a format string like ``{:,f}`` if exact CPython compatibility is required. +""" + +print("{:,f}".format(3141.159)) +print("{:_f}".format(3141.159)) +print("{:011,.2f}".format(3141.159)) +print("{:011_.2f}".format(3141.159)) diff --git a/tests/cpydiff/types_str_repr_nonprintable.py b/tests/cpydiff/types_str_repr_nonprintable.py new file mode 100644 index 00000000000..6f9af65d8e1 --- /dev/null +++ b/tests/cpydiff/types_str_repr_nonprintable.py @@ -0,0 +1,11 @@ +""" +categories: Types,str +description: repr() may print some non-printable Unicode characters literally instead of as escape sequences +cause: MicroPython uses a simplified heuristic to determine printable characters, avoiding the need for a full Unicode character database (saves memory). It prints characters >= U+0080 (excluding surrogates) as UTF-8. CPython uses the Unicode database to identify non-printable characters like noncharacters (U+FFFx in each plane). +workaround: Accept the difference for embedded use cases, or use ascii() or manual escaping if exact control is needed. +""" + +# These are noncharacters that CPython escapes but MicroPython prints +# showing as hex to avoid display issues in documentation tables +print("U+FFFF:", repr("\uffff").encode("utf-8").hex()) +print("U+1FFFF:", repr("\U0001ffff").encode("utf-8").hex()) diff --git a/tests/extmod/asyncio_basic.py.exp b/tests/extmod/asyncio_basic.py.exp deleted file mode 100644 index 478e22abc8f..00000000000 --- a/tests/extmod/asyncio_basic.py.exp +++ /dev/null @@ -1,6 +0,0 @@ -start -after sleep -short -long -negative -took 200 400 0 diff --git a/tests/extmod/asyncio_cancel_self.py b/tests/extmod/asyncio_cancel_self.py index a437edb5403..3ed3ee88214 100644 --- a/tests/extmod/asyncio_cancel_self.py +++ b/tests/extmod/asyncio_cancel_self.py @@ -25,4 +25,4 @@ async def main(): try: asyncio.run(main()) except RuntimeError as er: - print(er) + print(str(er) or "can't cancel self") diff --git a/tests/extmod/asyncio_event_queue.py b/tests/extmod/asyncio_event_queue.py new file mode 100644 index 00000000000..e0125b1aefe --- /dev/null +++ b/tests/extmod/asyncio_event_queue.py @@ -0,0 +1,64 @@ +# Ensure that an asyncio task can wait on an Event when the +# _task_queue is empty +# https://github.com/micropython/micropython/issues/16569 + +try: + import asyncio +except ImportError: + print("SKIP") + raise SystemExit + +# This test requires checking that the asyncio scheduler +# remains active "indefinitely" when the task queue is empty. +# +# To check this, we need another independent scheduler that +# can wait for a certain amount of time. So we have to +# create one using micropython.schedule() and time.ticks_ms() +# +# Technically, this code breaks the rules, as it is clearly +# documented that Event.set() should _NOT_ be called from a +# schedule (soft IRQ) because in some cases, a race condition +# can occur, resulting in a crash. However: +# - since the risk of a race condition in that specific +# case has been analysed and excluded +# - given that there is no other simple alternative to +# write this test case, +# an exception to the rule was deemed acceptable. See +# https://github.com/micropython/micropython/pull/16772 + +import micropython, time + +try: + micropython.schedule +except AttributeError: + print("SKIP") + raise SystemExit + + +evt = asyncio.Event() + + +def schedule_watchdog(end_ticks): + if time.ticks_diff(end_ticks, time.ticks_ms()) <= 0: + print("asyncio still pending, unlocking event") + # Caution: about to call Event.set() from a schedule + # (see the note in the comment above) + evt.set() + return + micropython.schedule(schedule_watchdog, end_ticks) + + +async def foo(): + print("foo waiting") + schedule_watchdog(time.ticks_add(time.ticks_ms(), 100)) + await evt.wait() + print("foo done") + + +async def main(): + print("main started") + await foo() + print("main done") + + +asyncio.run(main()) diff --git a/tests/extmod/asyncio_event_queue.py.exp b/tests/extmod/asyncio_event_queue.py.exp new file mode 100644 index 00000000000..ee42c96d83e --- /dev/null +++ b/tests/extmod/asyncio_event_queue.py.exp @@ -0,0 +1,5 @@ +main started +foo waiting +asyncio still pending, unlocking event +foo done +main done diff --git a/tests/extmod/asyncio_heaplock.py b/tests/extmod/asyncio_heaplock.py index 8326443f0e6..9e9908de1cb 100644 --- a/tests/extmod/asyncio_heaplock.py +++ b/tests/extmod/asyncio_heaplock.py @@ -4,7 +4,11 @@ # - StreamWriter.write, stream is blocked and data to write is a bytes object # - StreamWriter.write, when stream is not blocked -import micropython +try: + import asyncio, micropython +except ImportError: + print("SKIP") + raise SystemExit # strict stackless builds can't call functions without allocating a frame on the heap try: @@ -24,12 +28,6 @@ def f(x): print("SKIP") raise SystemExit -try: - import asyncio -except ImportError: - print("SKIP") - raise SystemExit - class TestStream: def __init__(self, blocked): diff --git a/tests/extmod/asyncio_iterator_event.py b/tests/extmod/asyncio_iterator_event.py new file mode 100644 index 00000000000..f61fefcf051 --- /dev/null +++ b/tests/extmod/asyncio_iterator_event.py @@ -0,0 +1,86 @@ +# Ensure that an asyncio task can wait on an Event when the +# _task_queue is empty, in the context of an async iterator +# https://github.com/micropython/micropython/issues/16318 + +try: + import asyncio +except ImportError: + print("SKIP") + raise SystemExit + +# This test requires checking that the asyncio scheduler +# remains active "indefinitely" when the task queue is empty. +# +# To check this, we need another independent scheduler that +# can wait for a certain amount of time. So we have to +# create one using micropython.schedule() and time.ticks_ms() +# +# Technically, this code breaks the rules, as it is clearly +# documented that Event.set() should _NOT_ be called from a +# schedule (soft IRQ) because in some cases, a race condition +# can occur, resulting in a crash. However: +# - since the risk of a race condition in that specific +# case has been analysed and excluded +# - given that there is no other simple alternative to +# write this test case, +# an exception to the rule was deemed acceptable. See +# https://github.com/micropython/micropython/pull/16772 + +import micropython, time + +try: + micropython.schedule +except AttributeError: + print("SKIP") + raise SystemExit + +ai = None + + +def schedule_watchdog(end_ticks): + if time.ticks_diff(end_ticks, time.ticks_ms()) <= 0: + print("good: asyncio iterator is still pending, exiting") + # Caution: ai.fetch_data() will invoke Event.set() + # (see the note in the comment above) + ai.fetch_data(None) + return + micropython.schedule(schedule_watchdog, end_ticks) + + +async def test(ai): + for x in range(3): + await asyncio.sleep(0.1) + ai.fetch_data("bar {}".format(x)) + + +class AsyncIterable: + def __init__(self): + self.message = None + self.evt = asyncio.Event() + + def __aiter__(self): + return self + + async def __anext__(self): + await self.evt.wait() + self.evt.clear() + if self.message is None: + raise StopAsyncIteration + return self.message + + def fetch_data(self, message): + self.message = message + self.evt.set() + + +async def main(): + global ai + ai = AsyncIterable() + asyncio.create_task(test(ai)) + schedule_watchdog(time.ticks_add(time.ticks_ms(), 500)) + async for message in ai: + print(message) + print("end main") + + +asyncio.run(main()) diff --git a/tests/extmod/asyncio_iterator_event.py.exp b/tests/extmod/asyncio_iterator_event.py.exp new file mode 100644 index 00000000000..a1893197d02 --- /dev/null +++ b/tests/extmod/asyncio_iterator_event.py.exp @@ -0,0 +1,5 @@ +bar 0 +bar 1 +bar 2 +good: asyncio iterator is still pending, exiting +end main diff --git a/tests/extmod/asyncio_lock.py.exp b/tests/extmod/asyncio_lock.py.exp deleted file mode 100644 index a37dfcbd2e5..00000000000 --- a/tests/extmod/asyncio_lock.py.exp +++ /dev/null @@ -1,41 +0,0 @@ -False -True -False -have lock ----- -task start 1 -task start 2 -task start 3 -task have 1 0 -task have 2 0 -task have 3 0 -task have 1 1 -task have 2 1 -task have 3 1 -task have 1 2 -task end 1 -task have 2 2 -task end 2 -task have 3 2 -task end 3 ----- -task have True -task release False -task have True -task release False -task have again -task have again ----- -task got 0 -task release 0 -task cancel 1 -task got 2 -task release 2 -False ----- -task got 0 -task cancel 1 -task release 0 -task got 2 -task cancel 2 -False diff --git a/tests/extmod/asyncio_set_exception_handler.py b/tests/extmod/asyncio_set_exception_handler.py index 5935f0f4ebe..0ac4a624224 100644 --- a/tests/extmod/asyncio_set_exception_handler.py +++ b/tests/extmod/asyncio_set_exception_handler.py @@ -12,7 +12,7 @@ def custom_handler(loop, context): async def task(i): - # Raise with 2 args so exception prints the same in uPy and CPython + # Raise with 2 args so exception prints the same in MicroPython and CPython raise ValueError(i, i + 1) diff --git a/tests/extmod/asyncio_wait_for_linked_task.py b/tests/extmod/asyncio_wait_for_linked_task.py new file mode 100644 index 00000000000..4dda62d5476 --- /dev/null +++ b/tests/extmod/asyncio_wait_for_linked_task.py @@ -0,0 +1,66 @@ +# Test asyncio.wait_for, with dependent tasks +# https://github.com/micropython/micropython/issues/16759 + +try: + import asyncio +except ImportError: + print("SKIP") + raise SystemExit + + +# CPython 3.12 deprecated calling get_event_loop() when there is no current event +# loop, so to make this test run on CPython requires setting the event loop. +if hasattr(asyncio, "set_event_loop"): + asyncio.set_event_loop(asyncio.new_event_loop()) + + +class Worker: + def __init__(self): + self._eventLoop = None + self._tasks = [] + + def launchTask(self, asyncJob): + if self._eventLoop is None: + self._eventLoop = asyncio.get_event_loop() + return self._eventLoop.create_task(asyncJob) + + async def job(self, prerequisite, taskName): + if prerequisite: + await prerequisite + await asyncio.sleep(0.1) + print(taskName, "work completed") + + def planTasks(self): + self._tasks.append(self.launchTask(self.job(None, "task0"))) + self._tasks.append(self.launchTask(self.job(self._tasks[0], "task1"))) + self._tasks.append(self.launchTask(self.job(self._tasks[1], "task2"))) + + async def waitForTask(self, taskIdx): + return await self._tasks[taskIdx] + + def syncWaitForTask(self, taskIdx): + return self._eventLoop.run_until_complete(self._tasks[taskIdx]) + + +async def async_test(): + print("--- async test") + worker = Worker() + worker.planTasks() + await worker.waitForTask(0) + print("-> task0 done") + await worker.waitForTask(2) + print("-> task2 done") + + +def sync_test(): + print("--- sync test") + worker = Worker() + worker.planTasks() + worker.syncWaitForTask(0) + print("-> task0 done") + worker.syncWaitForTask(2) + print("-> task2 done") + + +asyncio.get_event_loop().run_until_complete(async_test()) +sync_test() diff --git a/tests/extmod/asyncio_wait_task.py.exp b/tests/extmod/asyncio_wait_task.py.exp deleted file mode 100644 index 514a4342233..00000000000 --- a/tests/extmod/asyncio_wait_task.py.exp +++ /dev/null @@ -1,12 +0,0 @@ -start -task 1 -task 2 ----- -start -hello -world -took 200 200 -task_raise -ValueError -task_raise -ValueError diff --git a/tests/extmod/binascii_hexlify.py b/tests/extmod/binascii_hexlify.py index d06029aabaf..ae90b673365 100644 --- a/tests/extmod/binascii_hexlify.py +++ b/tests/extmod/binascii_hexlify.py @@ -1,5 +1,5 @@ try: - import binascii + from binascii import hexlify except ImportError: print("SKIP") raise SystemExit @@ -10,10 +10,10 @@ b"\x7f\x80\xff", b"1234ABCDabcd", ): - print(binascii.hexlify(x)) + print(hexlify(x)) # Two-argument version (now supported in CPython) -print(binascii.hexlify(b"123", ":")) +print(hexlify(b"123", ":")) # zero length buffer -print(binascii.hexlify(b"", b":")) +print(hexlify(b"", b":")) diff --git a/tests/extmod/binascii_unhexlify.py b/tests/extmod/binascii_unhexlify.py index 731b6a2bd4d..b08704cba65 100644 --- a/tests/extmod/binascii_unhexlify.py +++ b/tests/extmod/binascii_unhexlify.py @@ -1,5 +1,5 @@ try: - import binascii + from binascii import unhexlify except ImportError: print("SKIP") raise SystemExit @@ -10,18 +10,18 @@ b"7f80ff", b"313233344142434461626364", ): - print(binascii.unhexlify(x)) + print(unhexlify(x)) # CIRCUITPY-CHANGE # Unicode strings can be decoded -print(binascii.unhexlify("313233344142434461626364")) +print(unhexlify("313233344142434461626364")) try: - a = binascii.unhexlify(b"0") # odd buffer length + a = unhexlify(b"0") # odd buffer length except ValueError: print("ValueError") try: - a = binascii.unhexlify(b"gg") # digit not hex + a = unhexlify(b"gg") # digit not hex except ValueError: print("ValueError") diff --git a/tests/extmod/framebuf_blit.py b/tests/extmod/framebuf_blit.py new file mode 100644 index 00000000000..b1d98b330a8 --- /dev/null +++ b/tests/extmod/framebuf_blit.py @@ -0,0 +1,68 @@ +# Test FrameBuffer.blit method. + +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print("%02x" % buf[(x + y * w)], end="") + print() + print("-->8--") + + +w = 5 +h = 4 +buf = bytearray(w * h) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS8) + +fbuf2 = framebuf.FrameBuffer(bytearray(4), 2, 2, framebuf.GS8) +fbuf2.fill(0xFF) + +# Blit another FrameBuffer, at various locations. +for x, y in ((-1, -1), (0, 0), (1, 1), (4, 3)): + fbuf.fill(0) + fbuf.blit(fbuf2, x, y) + printbuf() + +# Blit a bytes object. +fbuf.fill(0) +image = (b"\x10\x11\x12\x13", 2, 2, framebuf.GS8) +fbuf.blit(image, 1, 1) +printbuf() + +# Blit a bytes object that has a stride. +fbuf.fill(0) +image = (b"\x20\x21\xff\x22\x23\xff", 2, 2, framebuf.GS8, 3) +fbuf.blit(image, 1, 1) +printbuf() + +# Blit a bytes object with a bytes palette. +fbuf.fill(0) +image = (b"\x00\x01\x01\x00", 2, 2, framebuf.GS8) +palette = (b"\xa1\xa2", 2, 1, framebuf.GS8) +fbuf.blit(image, 1, 1, -1, palette) +printbuf() + +# Not enough elements in the tuple. +try: + fbuf.blit((0, 0, 0), 0, 0) +except ValueError: + print("ValueError") + +# Too many elements in the tuple. +try: + fbuf.blit((0, 0, 0, 0, 0, 0), 0, 0) +except ValueError: + print("ValueError") + +# Bytes too small. +try: + fbuf.blit((b"", 1, 1, framebuf.GS8), 0, 0) +except ValueError: + print("ValueError") diff --git a/tests/extmod/framebuf_blit.py.exp b/tests/extmod/framebuf_blit.py.exp new file mode 100644 index 00000000000..e340f1990c7 --- /dev/null +++ b/tests/extmod/framebuf_blit.py.exp @@ -0,0 +1,45 @@ +--8<-- +ff00000000 +0000000000 +0000000000 +0000000000 +-->8-- +--8<-- +ffff000000 +ffff000000 +0000000000 +0000000000 +-->8-- +--8<-- +0000000000 +00ffff0000 +00ffff0000 +0000000000 +-->8-- +--8<-- +0000000000 +0000000000 +0000000000 +00000000ff +-->8-- +--8<-- +0000000000 +0010110000 +0012130000 +0000000000 +-->8-- +--8<-- +0000000000 +0020210000 +0022230000 +0000000000 +-->8-- +--8<-- +0000000000 +00a1a20000 +00a2a10000 +0000000000 +-->8-- +ValueError +ValueError +ValueError diff --git a/tests/extmod/hashlib_md5.py b/tests/extmod/hashlib_md5.py index 5f925fc97d0..ebbe9155e04 100644 --- a/tests/extmod/hashlib_md5.py +++ b/tests/extmod/hashlib_md5.py @@ -1,8 +1,7 @@ try: import hashlib except ImportError: - # This is neither uPy, nor cPy, so must be uPy with - # hashlib module disabled. + # MicroPython with hashlib module disabled. print("SKIP") raise SystemExit diff --git a/tests/extmod/hashlib_sha1.py b/tests/extmod/hashlib_sha1.py index af23033a591..46ffb73fcbe 100644 --- a/tests/extmod/hashlib_sha1.py +++ b/tests/extmod/hashlib_sha1.py @@ -1,8 +1,7 @@ try: import hashlib except ImportError: - # This is neither uPy, nor cPy, so must be uPy with - # hashlib module disabled. + # MicroPython with hashlib module disabled. print("SKIP") raise SystemExit diff --git a/tests/extmod/hashlib_sha256.py b/tests/extmod/hashlib_sha256.py index 95cd301d160..209fcb39877 100644 --- a/tests/extmod/hashlib_sha256.py +++ b/tests/extmod/hashlib_sha256.py @@ -1,8 +1,7 @@ try: import hashlib except ImportError: - # This is neither uPy, nor cPy, so must be uPy with - # hashlib module disabled. + # MicroPython with hashlib module disabled. print("SKIP") raise SystemExit diff --git a/tests/extmod/json_dump.py b/tests/extmod/json_dump.py index 897d33cc812..0beb4f5f856 100644 --- a/tests/extmod/json_dump.py +++ b/tests/extmod/json_dump.py @@ -16,11 +16,11 @@ # dump to a small-int not allowed try: json.dump(123, 1) -except (AttributeError, OSError): # CPython and uPy have different errors +except (AttributeError, OSError): # CPython and MicroPython have different errors print("Exception") # dump to an object not allowed try: json.dump(123, {}) -except (AttributeError, OSError): # CPython and uPy have different errors +except (AttributeError, OSError): # CPython and MicroPython have different errors print("Exception") diff --git a/tests/extmod/json_dump_iobase.py b/tests/extmod/json_dump_iobase.py index 94d317b8796..81105e36dcc 100644 --- a/tests/extmod/json_dump_iobase.py +++ b/tests/extmod/json_dump_iobase.py @@ -18,7 +18,7 @@ def __init__(self): def write(self, buf): if type(buf) == bytearray: - # uPy passes a bytearray, CPython passes a str + # MicroPython passes a bytearray, CPython passes a str buf = str(buf, "ascii") self.buf += buf return len(buf) diff --git a/tests/extmod/json_dump_separators.py b/tests/extmod/json_dump_separators.py index 4f8e56dceb5..ce39294820f 100644 --- a/tests/extmod/json_dump_separators.py +++ b/tests/extmod/json_dump_separators.py @@ -25,20 +25,20 @@ # dump to a small-int not allowed try: json.dump(123, 1, separators=sep) - except (AttributeError, OSError): # CPython and uPy have different errors + except (AttributeError, OSError): # CPython and MicroPython have different errors print("Exception") # dump to an object not allowed try: json.dump(123, {}, separators=sep) - except (AttributeError, OSError): # CPython and uPy have different errors + except (AttributeError, OSError): # CPython and MicroPython have different errors print("Exception") try: s = StringIO() json.dump(False, s, separators={"a": 1}) -except (TypeError, ValueError): # CPython and uPy have different errors +except (TypeError, ValueError): # CPython and MicroPython have different errors print("Exception") # invalid separator types diff --git a/tests/extmod/json_dumps_extra.py b/tests/extmod/json_dumps_extra.py index a410b0ee0ef..70efc866451 100644 --- a/tests/extmod/json_dumps_extra.py +++ b/tests/extmod/json_dumps_extra.py @@ -1,4 +1,4 @@ -# test uPy json behaviour that's not valid in CPy +# test MicroPython json behaviour that's not valid in CPy # CIRCUITPY-CHANGE: This behavior matches CPython print("SKIP") raise SystemExit diff --git a/tests/extmod/json_dumps_separators.py b/tests/extmod/json_dumps_separators.py index a3a9ec308f0..0a95f489a08 100644 --- a/tests/extmod/json_dumps_separators.py +++ b/tests/extmod/json_dumps_separators.py @@ -39,7 +39,7 @@ try: json.dumps(False, separators={"a": 1}) -except (TypeError, ValueError): # CPython and uPy have different errors +except (TypeError, ValueError): # CPython and MicroPython have different errors print("Exception") # invalid separator types diff --git a/tests/extmod/json_loads.py b/tests/extmod/json_loads.py index f9073c121e2..092402d715d 100644 --- a/tests/extmod/json_loads.py +++ b/tests/extmod/json_loads.py @@ -71,3 +71,27 @@ def my_print(o): my_print(json.loads("[null] a")) except ValueError: print("ValueError") + +# incomplete object declaration +try: + my_print(json.loads('{"a":0,')) +except ValueError: + print("ValueError") + +# incomplete nested array declaration +try: + my_print(json.loads('{"a":0, [')) +except ValueError: + print("ValueError") + +# incomplete array declaration +try: + my_print(json.loads("[0,")) +except ValueError: + print("ValueError") + +# incomplete nested object declaration +try: + my_print(json.loads('[0, {"a":0, ')) +except ValueError: + print("ValueError") diff --git a/tests/extmod/json_loads_bytes.py.exp b/tests/extmod/json_loads_bytes.py.exp deleted file mode 100644 index c2735a99052..00000000000 --- a/tests/extmod/json_loads_bytes.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -[1, 2] -[None] diff --git a/tests/extmod/json_loads_int_64.py b/tests/extmod/json_loads_int_64.py new file mode 100644 index 00000000000..f6236f1904a --- /dev/null +++ b/tests/extmod/json_loads_int_64.py @@ -0,0 +1,16 @@ +# Parse 64-bit integers from JSON payloads. +# +# This also exercises parsing integers from strings +# where the value may not be null terminated (last line) +try: + import json +except ImportError: + print("SKIP") + raise SystemExit + + +print(json.loads("9111222333444555666")) +print(json.loads("-9111222333444555666")) +print(json.loads("9111222333444555666")) +print(json.loads("-9111222333444555666")) +print(json.loads('["9111222333444555666777",9111222333444555666]')) diff --git a/tests/extmod/machine_mem_backup.py b/tests/extmod/machine_mem_backup.py new file mode 100644 index 00000000000..db2ff910a73 --- /dev/null +++ b/tests/extmod/machine_mem_backup.py @@ -0,0 +1,58 @@ +# Test machine.mem_backup() function. + +try: + import machine + + mem = machine.mem_backup() +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +# Discovery: -1 returns a tuple of all regions. +regions = machine.mem_backup(-1) +print("regions is tuple:", isinstance(regions, tuple)) +print("at least one region:", len(regions) >= 1) +print("all memoryviews:", all(isinstance(r, memoryview) for r in regions)) +print("all len > 0:", all(len(r) > 0 for r in regions)) +print("all valid itemsize:", all(r.itemsize in (1, 4) for r in regions)) + +# Default region (index 0). +print("memoryview:", isinstance(mem, memoryview)) +print("len > 0:", len(mem) > 0) +print("itemsize ok:", mem.itemsize in (1, 4)) + +# Small-value write/read. +mem[0] = 42 +print(mem[0] == 42) + +if mem.itemsize == 4: + # Values >= 0x40000000 are big-ints on 32-bit targets; check that + # word-only backup registers receive them as aligned word writes. + for val in (0x40000000, 0x41020304, 0x7FFFFFFF, 0xDEADBEEF): + mem[0] = val + print(mem[0] == val) + mem[0] = -1 + print(mem[0] == 0xFFFFFFFF) +else: + for val in (0x80, 0xA5, 0xFF, 0xC3): + mem[0] = val + print(mem[0] == val) + mem[0] = 0 + print(mem[0] == 0) + +last = len(mem) - 1 +mem[last] = 1 +print(mem[last] == 1) + +# Out-of-range region raises ValueError. +try: + machine.mem_backup(len(regions)) + print("no error") +except ValueError: + print("ValueError") + +try: + machine.mem_backup(-2) + print("no error") +except ValueError: + print("ValueError") diff --git a/tests/extmod/machine_mem_backup.py.exp b/tests/extmod/machine_mem_backup.py.exp new file mode 100644 index 00000000000..c3d858c86d6 --- /dev/null +++ b/tests/extmod/machine_mem_backup.py.exp @@ -0,0 +1,17 @@ +regions is tuple: True +at least one region: True +all memoryviews: True +all len > 0: True +all valid itemsize: True +memoryview: True +len > 0: True +itemsize ok: True +True +True +True +True +True +True +True +ValueError +ValueError diff --git a/tests/extmod/machine_timer.py b/tests/extmod/machine_timer.py new file mode 100644 index 00000000000..cb5f3fa67e2 --- /dev/null +++ b/tests/extmod/machine_timer.py @@ -0,0 +1,149 @@ +try: + from machine import Timer + from time import sleep_ms +except: + print("SKIP") + raise SystemExit + +import sys + +if sys.platform == "nrf": + # Note: The nrf port supports machine.Timer, but is not compatible: It lacks + # the .init() method and freq argument, the period argument is microseconds + # instead milliseconds, and the ONE_SHOT constant is named ONESHOT. + print("SKIP") + raise SystemExit + +import unittest + +# Hardware timers are only supported on the esp32 port +NUM_HARDWARE_TIMERS = 0 +if sys.platform == "esp32": + if "ESP32-C2" in sys.implementation._machine: + # Only one hardware timer on ESP32-C2 + NUM_HARDWARE_TIMERS = 1 + else: + # at least two on other ESP32 SoCs + NUM_HARDWARE_TIMERS = 2 + +# Hard IRQs are not supported on the esp32 port +SUPPORTS_HARD_IRQ = sys.platform != "esp32" + + +class Test(unittest.TestCase): + def test_virtual_create(self): + self._test_create(-1) + self._test_create_multiple(-1, -1) + + @unittest.skipUnless(NUM_HARDWARE_TIMERS > 0, "no hardware timers") + def test_hardware_create(self): + self._test_create(0) + + @unittest.skipUnless(NUM_HARDWARE_TIMERS >= 2, "less than 2 hardware timers") + def test_hardware_create_multiple(self): + self._test_create_multiple(0, 1) + + def test_virtual_softirq(self): + self._test_all_freq_period(-1, Timer.ONE_SHOT, False) + self._test_all_freq_period(-1, Timer.PERIODIC, False) + + @unittest.skipUnless(SUPPORTS_HARD_IRQ, "no hard-irq support") + def test_virtual_hardirq(self): + self._test_all_freq_period(-1, Timer.ONE_SHOT, True) + self._test_all_freq_period(-1, Timer.PERIODIC, True) + + @unittest.skipUnless(NUM_HARDWARE_TIMERS > 0, "no hardware timers") + def test_hardware_softirq(self): + self._test_all_freq_period(0, Timer.ONE_SHOT, False) + self._test_all_freq_period(0, Timer.PERIODIC, False) + + @unittest.skipUnless(NUM_HARDWARE_TIMERS > 0, "no hardware timers") + @unittest.skipUnless(SUPPORTS_HARD_IRQ, "no hard-irq support") + def test_hardware_hardirq(self): + self._test_all_freq_period(0, Timer.ONE_SHOT, True) + self._test_all_freq_period(0, Timer.PERIODIC, True) + + def _test_create(self, id): + # create and deinit + t = Timer(id) + t.init(freq=1) + t.deinit() + + # deinit again + t.deinit() + + # init a large number of times to catch bugs like + # https://github.com/micropython/micropython/issues/19162 + for _ in range(256): + t.init(freq=1) + t.deinit() + + def _test_create_multiple(self, *ids): + # create and deinit + timers = [] + for id in ids: + t = Timer(id) + self.assertFalse(t in timers) + t.init(freq=1) + timers.append(t) + for t in timers: + t.deinit() + + # create and deinit in reverse order + timers = [] + for id in ids: + t = Timer(id) + self.assertFalse(t in timers) + t.init(freq=1) + timers.append(t) + for t in reversed(timers): + t.deinit() + + def _test_all_freq_period(self, id, mode, hard): + # test two different freq and period arguments + for period, freq_period_arg in ( + (1000 // 50, {"freq": 50}), + (1000 // 25, {"freq": 25}), + (20, {"period": 20}), + (40, {"period": 40}), + ): + callback_results = [] + + def _callback(_): + try: + allocate = bytearray(1) + locked = False + except MemoryError: + locked = True + callback_results.append(locked) + + t = Timer(id) + t.init( + mode=mode, + callback=_callback, + hard=hard, + **freq_period_arg, + ) + + # Note: These sleep durations are such that there is always at least + # 10ms between when the callback fires and we perform our checks, + # thus this test also implicitly checks that timers and/or sleep_ms + # do not drift more than 10ms. + total = 0 + for duration in (0, 10, 20, 40, 20): + sleep_ms(duration) + total += duration + + # number of times the callback should have been called + n = total // period + if mode == Timer.ONE_SHOT: + n = min(n, 1) + + # callback reports whether memory was locked, which + # should equal whether the timer uses hard IRQs + self.assertEqual([hard] * n, callback_results) + t.deinit() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod/marshal_fun_nested.py b/tests/extmod/marshal_fun_nested.py new file mode 100644 index 00000000000..fcf8f9a0fa4 --- /dev/null +++ b/tests/extmod/marshal_fun_nested.py @@ -0,0 +1,79 @@ +# Test the marshal module, with functions that have children. + +try: + import marshal + + (lambda: 0).__code__ +except (AttributeError, ImportError): + print("SKIP") + raise SystemExit + + +def f_with_child(): + def child(): + return a + + return child + + +def f_with_child_defargs(): + def child(a="default"): + return a + + return child + + +def f_with_child_closure(): + a = "closure 1" + + def child(): + return a + + a = "closure 2" + return child + + +def f_with_child_closure_defargs(): + a = "closure defargs 1" + + def child(b="defargs default"): + return (a, b) + + a = "closure defargs 1" + return child + + +def f_with_list_comprehension(a): + return [i + a for i in range(4)] + + +ftype = type(lambda: 0) + +# Test function with a child. +f = ftype(marshal.loads(marshal.dumps(f_with_child.__code__)), {"a": "global"}) +print(f()()) + +# Test function with a child that has default arguments. +f = ftype(marshal.loads(marshal.dumps(f_with_child_defargs.__code__)), {}) +print(f()()) +print(f()("non-default")) + +# Test function with a child that is a closure. +f = ftype(marshal.loads(marshal.dumps(f_with_child_closure.__code__)), {}) +print(f()()) + +# Test function with a child that is a closure and has default arguments. +f = ftype(marshal.loads(marshal.dumps(f_with_child_closure_defargs.__code__)), {}) +print(f()()) +print(f()("defargs non-default")) + +# Test function with a list comprehension (which will be an anonymous child). +f = ftype(marshal.loads(marshal.dumps(f_with_list_comprehension.__code__)), {}) +print(f(10)) + +# Test child within a module (the outer scope). +code = compile("def child(a): return a", "", "exec") +f = marshal.loads(marshal.dumps(code)) +ctx = {} +exec(f, ctx) +print(ctx["child"]("arg")) diff --git a/tests/extmod/marshal_micropython.py b/tests/extmod/marshal_micropython.py deleted file mode 100644 index 213b3bf3189..00000000000 --- a/tests/extmod/marshal_micropython.py +++ /dev/null @@ -1,21 +0,0 @@ -# Test the marshal module, MicroPython-specific functionality. - -try: - import marshal -except ImportError: - print("SKIP") - raise SystemExit - -import unittest - - -class Test(unittest.TestCase): - def test_function_with_children(self): - # Can't marshal a function with children (in this case the module has a child function f). - code = compile("def f(): pass", "", "exec") - with self.assertRaises(ValueError): - marshal.dumps(code) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/extmod/os_urandom.py b/tests/extmod/os_urandom.py new file mode 100644 index 00000000000..982d6d04b96 --- /dev/null +++ b/tests/extmod/os_urandom.py @@ -0,0 +1,14 @@ +# Test os.urandom(). + +try: + from os import urandom +except ImportError: + print("SKIP") + raise SystemExit + +for n in range(-2, 5, 1): + try: + r = urandom(n) + print(n, type(r), len(r)) + except ValueError: + print(n, "ValueError") diff --git a/tests/extmod/platform_basic.py b/tests/extmod/platform_basic.py new file mode 100644 index 00000000000..eb6f2be13c1 --- /dev/null +++ b/tests/extmod/platform_basic.py @@ -0,0 +1,8 @@ +try: + import platform +except ImportError: + print("SKIP") + raise SystemExit + +print(type(platform.python_compiler())) +print(type(platform.libc_ver())) diff --git a/tests/extmod/random_extra_float.py b/tests/extmod/random_extra_float.py index 3b37ed8dcef..03973c58349 100644 --- a/tests/extmod/random_extra_float.py +++ b/tests/extmod/random_extra_float.py @@ -1,12 +1,8 @@ try: import random -except ImportError: - print("SKIP") - raise SystemExit -try: - random.randint -except AttributeError: + random.random +except (ImportError, AttributeError): print("SKIP") raise SystemExit diff --git a/tests/extmod/re_error.py b/tests/extmod/re_error.py index f61d0913289..bd678c9d251 100644 --- a/tests/extmod/re_error.py +++ b/tests/extmod/re_error.py @@ -11,7 +11,7 @@ def test_re(r): try: re.compile(r) print("OK") - except: # uPy and CPy use different errors, so just ignore the type + except: # MPy and CPy use different errors, so just ignore the type print("Error") diff --git a/tests/extmod/re_stack_overflow2.py b/tests/extmod/re_stack_overflow2.py new file mode 100644 index 00000000000..c5ddd012b32 --- /dev/null +++ b/tests/extmod/re_stack_overflow2.py @@ -0,0 +1,25 @@ +# Test overflow in re.compile output code. + +try: + import re +except ImportError: + print("SKIP") + raise SystemExit + + +def test_re(r): + try: + re.compile(r) + except: + print("Error") + + +try: + r = "(" * 65536 + ")" * 65536 +except MemoryError: + print("SKIP") + raise SystemExit + +# This happens to trigger RecursionError on current versions of CPython +# (tested with 3.13.5) as well, so no .exp file is needed. +test_re(r) diff --git a/tests/extmod/re_start_end_pos.py b/tests/extmod/re_start_end_pos.py new file mode 100644 index 00000000000..bd16584374b --- /dev/null +++ b/tests/extmod/re_start_end_pos.py @@ -0,0 +1,78 @@ +# test start and end pos specification + +try: + import re +except ImportError: + print("SKIP") + raise SystemExit + + +def print_groups(match): + print("----") + try: + if match is not None: + i = 0 + while True: + print(match.group(i)) + i += 1 + except IndexError: + pass + + +p = re.compile(r"o") +m = p.match("dog") +print_groups(m) + +m = p.match("dog", 1) +print_groups(m) + +m = p.match("dog", 2) +print_groups(m) + +# No match past end of input +m = p.match("dog", 5) +print_groups(m) + +m = p.match("dog", 0, 1) +print_groups(m) + +# Caret only matches the actual beginning +p = re.compile(r"^o") +m = p.match("dog", 1) +print_groups(m) + +# End at beginning means searching empty string +p = re.compile(r"o") +m = p.match("dog", 1, 1) +print_groups(m) + +# End before the beginning doesn't match anything +m = p.match("dog", 2, 1) +print_groups(m) + +# Negative starting values don't crash +m = p.search("dog", -2) +print_groups(m) + +m = p.search("dog", -2, -5) +print_groups(m) + +# Search also works +print("--search") + +p = re.compile(r"o") +m = p.search("dog") +print_groups(m) + +m = p.search("dog", 1) +print_groups(m) + +m = p.search("dog", 2) +print_groups(m) + +# Negative starting values don't crash +m = p.search("dog", -2) +print_groups(m) + +m = p.search("dog", -2, -5) +print_groups(m) diff --git a/tests/extmod/re_sub.py b/tests/extmod/re_sub.py index 3959949724d..bb9aa111287 100644 --- a/tests/extmod/re_sub.py +++ b/tests/extmod/re_sub.py @@ -62,7 +62,7 @@ def A(): except: print("invalid group") -# invalid group with very large number (to test overflow in uPy) +# invalid group with very large number (to test overflow in MicroPython) try: re.sub("(a)", "b\\199999999999999999999999999999999999999", "a") except: diff --git a/tests/extmod/re_sub_unmatched.py.exp b/tests/extmod/re_sub_unmatched.py.exp deleted file mode 100644 index 1e5f0fda055..00000000000 --- a/tests/extmod/re_sub_unmatched.py.exp +++ /dev/null @@ -1 +0,0 @@ -1-a2 diff --git a/tests/extmod/select_poll_eintr.py.exp b/tests/extmod/select_poll_eintr.py.exp new file mode 100644 index 00000000000..2b15f86649c --- /dev/null +++ b/tests/extmod/select_poll_eintr.py.exp @@ -0,0 +1,5 @@ +poll +thread gc start +thread gc end +result: [] +dt in range diff --git a/tests/extmod/socket_badconstructor.py b/tests/extmod/socket_badconstructor.py new file mode 100644 index 00000000000..25d981f70a7 --- /dev/null +++ b/tests/extmod/socket_badconstructor.py @@ -0,0 +1,29 @@ +# Test passing in bad values to socket.socket constructor. + +try: + import socket +except: + print("SKIP") + raise SystemExit + +try: + s = socket.socket(None) +except TypeError: + print("TypeError") + +try: + s = socket.socket(socket.AF_INET, None) +except TypeError: + print("TypeError") + +# This may or may not raise an exception, depending on the socket implementation. +# The test is here for coverage. +try: + s = socket.socket(socket.AF_INET, 123456) +except OSError: + pass + +try: + s = socket.socket(socket.AF_INET, socket.SOCK_RAW, None) +except TypeError: + print("TypeError") diff --git a/tests/extmod/socket_fileno.py b/tests/extmod/socket_fileno.py new file mode 100644 index 00000000000..da15825e3d5 --- /dev/null +++ b/tests/extmod/socket_fileno.py @@ -0,0 +1,17 @@ +# Test socket.fileno() functionality + +try: + import socket +except ImportError: + print("SKIP") + raise SystemExit + +if not hasattr(socket.socket, "fileno"): + print("SKIP") + raise SystemExit + +s = socket.socket() +print(s.fileno() >= 0) + +s.close() +print(s.fileno()) # should print -1 diff --git a/tests/extmod/time_mktime.py b/tests/extmod/time_mktime.py new file mode 100644 index 00000000000..7fc643dc3cb --- /dev/null +++ b/tests/extmod/time_mktime.py @@ -0,0 +1,120 @@ +# test conversion from date tuple to timestamp and back + +try: + import time + + time.localtime +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +# Range of date expected to work on all MicroPython platforms +MIN_YEAR = 1970 +MAX_YEAR = 2099 +# CPython properly supported date range: +# - on Windows: year 1970 to 3000+ +# - on Unix: year 1583 to 3000+ + +# Start test from Jan 1, 2001 13:00 (Feb 2000 might already be broken) +SAFE_DATE = (2001, 1, 1, 13, 0, 0, 0, 0, -1) + + +# mktime function that checks that the result is reversible +def safe_mktime(date_tuple): + try: + res = time.mktime(date_tuple) + chk = time.localtime(res) + except OverflowError: + print("safe_mktime:", date_tuple, "overflow error") + return None + if chk[0:5] != date_tuple[0:5]: + print("safe_mktime:", date_tuple[0:5], " -> ", res, " -> ", chk[0:5]) + return None + return res + + +# localtime function that checks that the result is reversible +def safe_localtime(timestamp): + try: + res = time.localtime(timestamp) + chk = time.mktime(res) + except OverflowError: + print("safe_localtime:", timestamp, "overflow error") + return None + if chk != timestamp: + print("safe_localtime:", timestamp, " -> ", res, " -> ", chk) + return None + return res + + +# look for smallest valid timestamps by iterating backwards on tuple +def test_bwd(date_tuple): + curr_stamp = safe_mktime(date_tuple) + year = date_tuple[0] + month = date_tuple[1] - 1 + if month < 1: + year -= 1 + month = 12 + while year >= MIN_YEAR: + while month >= 1: + next_tuple = (year, month) + date_tuple[2:] + next_stamp = safe_mktime(next_tuple) + # at this stage, only test consistency and monotonicity + if next_stamp is None or next_stamp >= curr_stamp: + return date_tuple + date_tuple = next_tuple + curr_stamp = next_stamp + month -= 1 + year -= 1 + month = 12 + return date_tuple + + +# test day-by-day to ensure that every date is properly converted +def test_fwd(start_date): + DAYS_PER_MONTH = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) + curr_stamp = safe_mktime(start_date) + curr_date = safe_localtime(curr_stamp) + while curr_date[0] <= MAX_YEAR: + if curr_date[2] < 15: + skip_days = 13 + else: + skip_days = 1 + next_stamp = curr_stamp + skip_days * 86400 + next_date = safe_localtime(next_stamp) + if next_date is None: + return curr_date + if next_date[2] != curr_date[2] + skip_days: + # next month + if next_date[2] != 1: + print("wrong day of month:", next_date) + return curr_date + # check the number of days in previous month + month_days = DAYS_PER_MONTH[curr_date[1]] + if month_days == 28 and curr_date[0] % 4 == 0: + if curr_date[0] % 100 != 0 or curr_date[0] % 400 == 0: + month_days += 1 + if curr_date[2] != month_days: + print("wrong day count in prev month:", curr_date[2], "vs", month_days) + return curr_date + if next_date[1] != curr_date[1] + 1: + # next year + if curr_date[1] != 12: + print("wrong month count in prev year:", curr_date[1]) + return curr_date + if next_date[1] != 1: + print("wrong month:", next_date) + return curr_date + if next_date[0] != curr_date[0] + 1: + print("wrong year:", next_date) + return curr_date + curr_stamp = next_stamp + curr_date = next_date + return curr_date + + +small_date = test_bwd(SAFE_DATE) +large_date = test_fwd(small_date) +print("tested from", small_date[0:3], "to", large_date[0:3]) +print(small_date[0:3], "wday is", small_date[6]) +print(large_date[0:3], "wday is", large_date[6]) diff --git a/tests/extmod/time_res.py b/tests/extmod/time_res.py index 548bef1f174..ef20050b914 100644 --- a/tests/extmod/time_res.py +++ b/tests/extmod/time_res.py @@ -37,9 +37,12 @@ def test(): time.sleep_ms(100) for func_name, _ in EXPECTED_MAP: try: - time_func = getattr(time, func_name, None) or globals()[func_name] + if func_name.endswith("_time"): + time_func = globals()[func_name] + else: + time_func = getattr(time, func_name) now = time_func() # may raise AttributeError - except (KeyError, AttributeError): + except AttributeError: continue try: results_map[func_name].add(now) diff --git a/tests/extmod/tls_dtls.py b/tests/extmod/tls_dtls.py index b2d716769d3..753ab2fee4f 100644 --- a/tests/extmod/tls_dtls.py +++ b/tests/extmod/tls_dtls.py @@ -34,9 +34,19 @@ def ioctl(self, req, arg): # Wrap the DTLS Server dtls_server_ctx = SSLContext(PROTOCOL_DTLS_SERVER) dtls_server_ctx.verify_mode = CERT_NONE -dtls_server = dtls_server_ctx.wrap_socket(server_socket, do_handshake_on_connect=False) +dtls_server = dtls_server_ctx.wrap_socket( + server_socket, do_handshake_on_connect=False, client_id=b"dummy_client_id" +) print("Wrapped DTLS Server") +# wrap DTLS server with invalid client_id +try: + dtls_server = dtls_server_ctx.wrap_socket( + server_socket, do_handshake_on_connect=False, client_id=4 + ) +except OSError: + print("Failed to wrap DTLS Server with invalid client_id") + # Wrap the DTLS Client dtls_client_ctx = SSLContext(PROTOCOL_DTLS_CLIENT) dtls_client_ctx.verify_mode = CERT_NONE diff --git a/tests/extmod/tls_dtls.py.exp b/tests/extmod/tls_dtls.py.exp index 78d72bff188..dbd005d0edf 100644 --- a/tests/extmod/tls_dtls.py.exp +++ b/tests/extmod/tls_dtls.py.exp @@ -1,3 +1,4 @@ Wrapped DTLS Server +Failed to wrap DTLS Server with invalid client_id Wrapped DTLS Client OK diff --git a/tests/extmod/ssl_noleak.py b/tests/extmod/tls_noleak.py similarity index 100% rename from tests/extmod/ssl_noleak.py rename to tests/extmod/tls_noleak.py diff --git a/tests/extmod/tls_psk.py b/tests/extmod/tls_psk.py new file mode 100644 index 00000000000..cc49ecfc8ce --- /dev/null +++ b/tests/extmod/tls_psk.py @@ -0,0 +1,42 @@ +# Test the tls.SSLContext PSK attributes (psk_identity, psk_key, +# server_psk_keys) and basic validation, without needing a network connection. + +try: + import tls + + # PSK support is optional; psk_identity only exists when it's enabled. + tls.SSLContext(tls.PROTOCOL_TLS_CLIENT).psk_identity +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +ctx = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + +# The PSK attributes default to None. +print(ctx.psk_identity, ctx.psk_key, ctx.server_psk_keys) + +# They can be set and read back. +ctx.psk_identity = b"micropython" +ctx.psk_key = b"secret-shared-key" +ctx.server_psk_keys = {b"micropython": b"secret-shared-key"} +print(ctx.psk_identity, ctx.psk_key, ctx.server_psk_keys) + +# A PSK key longer than mbedTLS's maximum (MBEDTLS_PSK_MAX_LEN) is rejected +# when it is set on the context (the identity is already set above). +try: + ctx.psk_key = b"x" * 49 + print("no error") +except OSError: + print("OSError") + +# The key/identity are only applied once both are set, in either order. Here +# the over-length key is set first (a no-op while the identity is None), so the +# rejection only surfaces when the identity is set and the pair is applied. +ctx = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) +ctx.psk_key = b"x" * 49 +try: + ctx.psk_identity = b"micropython" + print("no error") +except OSError: + print("OSError") diff --git a/tests/extmod/tls_psk.py.exp b/tests/extmod/tls_psk.py.exp new file mode 100644 index 00000000000..060d5120d85 --- /dev/null +++ b/tests/extmod/tls_psk.py.exp @@ -0,0 +1,4 @@ +None None None +b'micropython' b'secret-shared-key' {b'micropython': b'secret-shared-key'} +OSError +OSError diff --git a/tests/extmod/tls_threads.py b/tests/extmod/tls_threads.py new file mode 100644 index 00000000000..1e0c3d23d2f --- /dev/null +++ b/tests/extmod/tls_threads.py @@ -0,0 +1,58 @@ +# Ensure that SSL sockets can be allocated from multiple +# threads without thread safety issues + +try: + import _thread + import io + import tls + import time +except ImportError: + print("SKIP") + raise SystemExit + +import unittest + + +class TestSocket(io.IOBase): + def write(self, buf): + return len(buf) + + def readinto(self, buf): + return 0 + + def ioctl(self, cmd, arg): + return 0 + + def setblocking(self, value): + pass + + +ITERS = 256 + + +class TLSThreads(unittest.TestCase): + def test_sslsocket_threaded(self): + self.done = False + # only run in two threads: too much RAM demand otherwise, and rp2 only + # supports two anyhow + _thread.start_new_thread(self._alloc_many_sockets, (True,)) + self._alloc_many_sockets(False) + while not self.done: + time.sleep(0.1) + print("done") + + def _alloc_many_sockets(self, set_done_flag): + print("start", _thread.get_ident()) + ctx = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + ctx.verify_mode = tls.CERT_NONE + for n in range(ITERS): + s = TestSocket() + s = ctx.wrap_socket(s, do_handshake_on_connect=False) + s.close() # Free associated resources now from thread, not in a GC pass + print("done", _thread.get_ident()) + if set_done_flag: + self.done = True + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod/uctypes_addressof.py b/tests/extmod/uctypes_addressof.py index c83089d0f72..213fcc05eee 100644 --- a/tests/extmod/uctypes_addressof.py +++ b/tests/extmod/uctypes_addressof.py @@ -12,5 +12,8 @@ print(uctypes.addressof(uctypes.bytearray_at(1 << i, 8))) # Test address that is bigger than the greatest small-int but still within the address range. -large_addr = maxsize + 1 -print(uctypes.addressof(uctypes.bytearray_at(large_addr, 8)) == large_addr) +try: + large_addr = maxsize + 1 + print(uctypes.addressof(uctypes.bytearray_at(large_addr, 8)) == large_addr) +except OverflowError: + print(True) # systems with 64-bit bigints will overflow on the above operation diff --git a/tests/extmod/uctypes_array_load_store.py b/tests/extmod/uctypes_array_load_store.py index 9de07999856..bea1ffc4a74 100644 --- a/tests/extmod/uctypes_array_load_store.py +++ b/tests/extmod/uctypes_array_load_store.py @@ -1,4 +1,5 @@ # Test uctypes array, load and store, with array size > 1 +import sys try: import uctypes @@ -6,18 +7,89 @@ print("SKIP") raise SystemExit +# 'int' needs to be able to represent UINT64 for this test +try: + int("FF" * 8, 16) +except OverflowError: + print("SKIP") + raise SystemExit + +try: + import unittest +except MemoryError: + print("SKIP-TOO-LARGE") # some small boards can't fit unittest in RAM + raise SystemExit + +# MicroPython V2.0 will enforce bounds on bytearray setters, V1.x truncates +# CIRCUITPY-CHANGE: CircuitPython always enforces these bounds (OVERFLOW_CHECKS in py/binary.c). +is_v2 = hasattr(sys.implementation, "_v2") or sys.implementation.name == "circuitpython" + N = 5 +PLACEHOLDER = 99 + + +class Test(unittest.TestCase): + def test_native_endian(self): + self._test_endian("NATIVE") -for endian in ("NATIVE", "LITTLE_ENDIAN", "BIG_ENDIAN"): - for type_ in ("INT8", "UINT8", "INT16", "UINT16", "INT32", "UINT32", "INT64", "UINT64"): - desc = {"arr": (uctypes.ARRAY | 0, getattr(uctypes, type_) | N)} + def test_little_endian(self): + self._test_endian("LITTLE_ENDIAN") + + def test_big_endian(self): + self._test_endian("BIG_ENDIAN") + + def _test_endian(self, endian): + for item_type in ( + "INT8", + "UINT8", + "INT16", + "UINT16", + "INT32", + "UINT32", + "INT64", + "UINT64", + ): + print(endian, item_type) + self._test_endian_type(endian, item_type) + + def _test_endian_type(self, endian, item_type): + print("Testing array of", item_type, "with", endian, "endianness") + desc = {"arr": (uctypes.ARRAY | 0, getattr(uctypes, item_type) | N)} + print(repr(desc)) sz = uctypes.sizeof(desc) data = bytearray(sz) + print(sz, repr((uctypes.addressof(data), desc, getattr(uctypes, endian)))) s = uctypes.struct(uctypes.addressof(data), desc, getattr(uctypes, endian)) + is_unsigned = item_type.startswith("U") + item_sz = uctypes.sizeof({"": getattr(uctypes, item_type)}) + + for i in range(N): + n = i - 2 + print(i, n) + # uctypes returns a bytearray for arrays of type UINT8, MicroPython V2 will + # enforce bounds checks on these so we can't assign a negative value + if is_v2 and isinstance(s.arr, bytearray) and n < 0: + print("placeholder value", n) + with self.assertRaises(OverflowError): + s.arr[i] = n + s.arr[i] = PLACEHOLDER + n = PLACEHOLDER + else: + s.arr[i] = n + + print(endian, item_type, sz, *(s.arr[i] for i in range(N))) + for i in range(N): - # CIRCUITPY-CHANGE: overflow checks - try: - s.arr[i] = i - 2 - except OverflowError: - print("OverflowError") - print(endian, type_, sz, *(s.arr[i] for i in range(N))) + n = i - 2 + if is_v2 and isinstance(s.arr, bytearray) and n < 0: + # The code above has swapped in PLACEHOLDER for this value + n = PLACEHOLDER + elif is_unsigned and n < 0: + # other types of unsigned uctypes arrays will "cast" negative values to unsigned + n = n & ((1 << (item_sz * 8)) - 1) + + self.assertEqual(s.arr[i], n) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod/vfs_basic.py b/tests/extmod/vfs_basic.py index 2c0ce8f5295..e88df1a776d 100644 --- a/tests/extmod/vfs_basic.py +++ b/tests/extmod/vfs_basic.py @@ -19,11 +19,11 @@ def umount(self): print(self.id, "umount") def ilistdir(self, dir): - print(self.id, "ilistdir", dir) + print(self.id, "ilistdir", repr(dir)) return iter([("a%d" % self.id, 0, 0)]) def chdir(self, dir): - print(self.id, "chdir", dir) + print(self.id, "chdir", repr(dir)) if self.fail: raise OSError(self.fail) @@ -32,23 +32,23 @@ def getcwd(self): return "dir%d" % self.id def mkdir(self, path): - print(self.id, "mkdir", path) + print(self.id, "mkdir", repr(path)) def remove(self, path): - print(self.id, "remove", path) + print(self.id, "remove", repr(path)) def rename(self, old_path, new_path): - print(self.id, "rename", old_path, new_path) + print(self.id, "rename", repr(old_path), repr(new_path)) def rmdir(self, path): - print(self.id, "rmdir", path) + print(self.id, "rmdir", repr(path)) def stat(self, path): - print(self.id, "stat", path) - return (self.id,) + print(self.id, "stat", repr(path)) + return (self.id, 0, 0, 0, 0, 0, 0, 0, 0, 0) def statvfs(self, path): - print(self.id, "statvfs", path) + print(self.id, "statvfs", repr(path)) return (self.id,) def open(self, file, mode): @@ -64,7 +64,7 @@ def open(self, file, mode): vfs.umount("/" + path) # stat root dir -print(os.stat("/")) +print(tuple(os.stat("/"))) # statvfs root dir; verify that f_namemax has a sensible size print(os.statvfs("/")[9] >= 32) @@ -131,7 +131,7 @@ def open(self, file, mode): os.remove("test_file") os.rename("test_file", "test_file2") os.rmdir("test_dir") -print(os.stat("test_file")) +print(tuple(os.stat("test_file"))) print(os.statvfs("/test_mnt")) open("test_file") open("test_file", "wb") @@ -148,7 +148,7 @@ def open(self, file, mode): # root dir vfs.mount(Filesystem(3), "/") -print(os.stat("/")) +print(tuple(os.stat("/"))) print(os.statvfs("/")) print(os.listdir()) open("test") diff --git a/tests/extmod/vfs_basic.py.exp b/tests/extmod/vfs_basic.py.exp index 536bb4c805d..39a16c444ee 100644 --- a/tests/extmod/vfs_basic.py.exp +++ b/tests/extmod/vfs_basic.py.exp @@ -18,30 +18,30 @@ stat /x OSError ('test_mnt', 16384, 0) StopIteration StopIteration -1 ilistdir / +1 ilistdir '/' ['a1'] -1 ilistdir / +1 ilistdir '/' ['a1'] 2 mount True False ['test_mnt', 'test_mnt2'] -2 ilistdir / +2 ilistdir '/' ['a2'] 3 mount False False OSError OSError OSError -1 chdir / -1 ilistdir +1 chdir '/' +1 ilistdir '' ['a1'] 1 getcwd /test_mntdir1 -1 mkdir test_dir -1 remove test_file -1 rename test_file test_file2 -1 rmdir test_dir -1 stat test_file -(1,) -1 statvfs / +1 mkdir 'test_dir' +1 remove 'test_file' +1 rename 'test_file' 'test_file2' +1 rmdir 'test_dir' +1 stat 'test_file' +(1, 0, 0, 0, 0, 0, 0, 0, 0, 0) +1 statvfs '/' (1,) 1 open test_file r 1 open test_file wb @@ -50,29 +50,29 @@ OSError OSError 3 mount False False (16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) -3 statvfs / +3 statvfs '/' (3,) -3 ilistdir / +3 ilistdir '/' ['a3'] 3 open test r 4 mount False False -3 ilistdir / +3 ilistdir '/' ['mnt', 'a3'] -4 ilistdir / +4 ilistdir '/' ['a4'] -4 chdir / -4 ilistdir +4 chdir '/' +4 ilistdir '' ['a4'] -3 chdir /subdir -3 ilistdir +3 chdir '/subdir' +3 ilistdir '' ['a3'] -3 chdir / +3 chdir '/' 3 umount ['mnt'] 4 umount OSError / 5 mount False False -5 chdir /subdir +5 chdir '/subdir' OSError / diff --git a/tests/extmod/vfs_blockdev_invalid.py b/tests/extmod/vfs_blockdev_invalid.py index 4d00f4b0027..3cb97ac3144 100644 --- a/tests/extmod/vfs_blockdev_invalid.py +++ b/tests/extmod/vfs_blockdev_invalid.py @@ -46,12 +46,17 @@ def ioctl(self, op, arg): try: bdev = RAMBlockDevice(50) except MemoryError: - print("SKIP") + print("SKIP-TOO-LARGE") raise SystemExit -def test(vfs_class): - print(vfs_class) +ERROR_EIO = (OSError, "[Errno 5] EIO") +ERROR_EINVAL = (OSError, "[Errno 22] EINVAL") +ERROR_TYPE = (TypeError, "can't convert str to int") +ALL_ERROR_TYPES = (OSError, TypeError) + + +def test(vfs_class, test_data): bdev.read_res = 0 # reset function results bdev.write_res = 0 @@ -61,17 +66,15 @@ def test(vfs_class): with fs.open("test", "w") as f: f.write("a" * 64) - for res in (0, -5, 5, 33, "invalid"): - # -5 is a legitimate negative failure (EIO), positive integer - # is not - + for res, error_open, error_read in test_data: # This variant will fail on open bdev.read_res = res try: with fs.open("test", "r") as f: - print("opened") - except OSError as e: - print("OSError", e) + assert error_open is None + except ALL_ERROR_TYPES as e: + assert error_open is not None + assert (type(e), str(e)) == error_open # This variant should succeed on open, may fail on read # unless the filesystem cached the contents already @@ -79,11 +82,52 @@ def test(vfs_class): try: with fs.open("test", "r") as f: bdev.read_res = res - print("read 1", f.read(1)) - print("read rest", f.read()) - except OSError as e: - print("OSError", e) + assert f.read(1) == "a" + assert f.read() == "a" * 63 + assert error_read is None + except ALL_ERROR_TYPES as e: + assert error_read is not None + assert (type(e), str(e)) == error_read + + # Try mounting this block device + # + # Failing mount operation will return EIO rather than EINVAL, but otherwise + # the result should match error_open + error_mount = ERROR_EIO if error_open == ERROR_EINVAL else error_open + try: + vfs.mount(bdev, "/test_ram") + assert error_mount is None + except ALL_ERROR_TYPES as e: + assert error_mount is not None + assert (type(e), str(e)) == error_mount + finally: + try: + vfs.umount("/test_ram") + except OSError: + pass -test(vfs.VfsLfs2) -test(vfs.VfsFat) +try: + test( + vfs.VfsLfs2, + ( + (0, None, None), + (-5, ERROR_EIO, None), + (5, ERROR_EINVAL, None), + (33, ERROR_EINVAL, None), + ("invalid", ERROR_TYPE, None), + ), + ) + test( + vfs.VfsFat, + ( + (0, None, None), + (-5, ERROR_EIO, ERROR_EIO), + (5, ERROR_EIO, ERROR_EIO), + (33, ERROR_EIO, ERROR_EIO), + ("invalid", ERROR_TYPE, ERROR_TYPE), + ), + ) + print("OK") +except MemoryError: + print("SKIP-TOO-LARGE") diff --git a/tests/extmod/vfs_blockdev_invalid.py.exp b/tests/extmod/vfs_blockdev_invalid.py.exp index 13695e0d889..d86bac9de59 100644 --- a/tests/extmod/vfs_blockdev_invalid.py.exp +++ b/tests/extmod/vfs_blockdev_invalid.py.exp @@ -1,28 +1 @@ - -opened -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 5] EIO -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 22] EINVAL -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 22] EINVAL -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 22] EINVAL -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - -opened -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO +OK diff --git a/tests/extmod/vfs_blockdev_invalid2.py b/tests/extmod/vfs_blockdev_invalid2.py new file mode 100644 index 00000000000..8905f833cf7 --- /dev/null +++ b/tests/extmod/vfs_blockdev_invalid2.py @@ -0,0 +1,37 @@ +# Tests where the block device returns invalid values + +try: + import vfs + + vfs.VfsFat + memoryview +except (NameError, ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class BadDev: + SEC_SIZE = 512 + + def __init__(self, blocks): + self.blocks = blocks + + def readblocks(self, n, buf): + assert len(buf) == self.SEC_SIZE + buf[:] = bytearray(self.SEC_SIZE + 1) # Attempts to enlarge passed-in buf + + def writeblocks(self, n, buf): + pass + + def ioctl(self, op, arg): + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT + return self.blocks + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE + return self.SEC_SIZE + + +bdev = BadDev(512) +try: + vfs.VfsFat.mkfs(bdev) +except ValueError as e: + print("ValueError") diff --git a/tests/extmod/vfs_blockdev_invalid2.py.exp b/tests/extmod/vfs_blockdev_invalid2.py.exp new file mode 100644 index 00000000000..94274de1bb3 --- /dev/null +++ b/tests/extmod/vfs_blockdev_invalid2.py.exp @@ -0,0 +1 @@ +ValueError diff --git a/tests/extmod/vfs_fat_ilistdir_del.py b/tests/extmod/vfs_fat_ilistdir_del.py index a6e24ec92f3..964e6b12868 100644 --- a/tests/extmod/vfs_fat_ilistdir_del.py +++ b/tests/extmod/vfs_fat_ilistdir_del.py @@ -1,8 +1,7 @@ # Test ilistdir __del__ for VfsFat using a RAM device. -import gc try: - import os, vfs + import gc, os, vfs vfs.VfsFat except (ImportError, AttributeError): diff --git a/tests/extmod/vfs_lfs.py b/tests/extmod/vfs_lfs.py index 3ad57fd9c38..40d58e9c9f7 100644 --- a/tests/extmod/vfs_lfs.py +++ b/tests/extmod/vfs_lfs.py @@ -136,7 +136,7 @@ def test(bdev, vfs_class): print(fs.getcwd()) fs.chdir("../testdir") print(fs.getcwd()) - fs.chdir("../..") + fs.chdir("..") print(fs.getcwd()) fs.chdir(".//testdir") print(fs.getcwd()) diff --git a/tests/extmod/vfs_lfs_error.py b/tests/extmod/vfs_lfs_error.py index 2ac7629bfa8..73cdf343733 100644 --- a/tests/extmod/vfs_lfs_error.py +++ b/tests/extmod/vfs_lfs_error.py @@ -1,7 +1,7 @@ # Test for VfsLittle using a RAM device, testing error handling try: - import vfs + import errno, vfs vfs.VfsLfs1 vfs.VfsLfs2 @@ -41,14 +41,14 @@ def test(bdev, vfs_class): # mkfs with too-small block device try: vfs_class.mkfs(RAMBlockDevice(1)) - except OSError: - print("mkfs OSError") + except OSError as er: + print("mkfs OSError", er.errno > 0) # mount with invalid filesystem try: vfs_class(bdev) - except OSError: - print("mount OSError") + except OSError as er: + print("mount OSError", er.errno > 0) # set up for following tests vfs_class.mkfs(bdev) @@ -60,60 +60,60 @@ def test(bdev, vfs_class): # ilistdir try: fs.ilistdir("noexist") - except OSError: - print("ilistdir OSError") + except OSError as er: + print("ilistdir OSError", er) # remove try: fs.remove("noexist") - except OSError: - print("remove OSError") + except OSError as er: + print("remove OSError", er) # rmdir try: fs.rmdir("noexist") - except OSError: - print("rmdir OSError") + except OSError as er: + print("rmdir OSError", er) # rename try: fs.rename("noexist", "somethingelse") - except OSError: - print("rename OSError") + except OSError as er: + print("rename OSError", er) # mkdir try: fs.mkdir("testdir") - except OSError: - print("mkdir OSError") + except OSError as er: + print("mkdir OSError", er) # chdir to nonexistent try: fs.chdir("noexist") - except OSError: - print("chdir OSError") + except OSError as er: + print("chdir OSError", er) print(fs.getcwd()) # check still at root # chdir to file try: fs.chdir("testfile") - except OSError: - print("chdir OSError") + except OSError as er: + print("chdir OSError", er) print(fs.getcwd()) # check still at root # stat try: fs.stat("noexist") - except OSError: - print("stat OSError") + except OSError as er: + print("stat OSError", er) # error during seek with fs.open("testfile", "r") as f: f.seek(1 << 30) # SEEK_SET try: f.seek(1 << 30, 1) # SEEK_CUR - except OSError: - print("seek OSError") + except OSError as er: + print("seek OSError", er) bdev = RAMBlockDevice(30) diff --git a/tests/extmod/vfs_lfs_error.py.exp b/tests/extmod/vfs_lfs_error.py.exp index f4327f6962e..440607ed84b 100644 --- a/tests/extmod/vfs_lfs_error.py.exp +++ b/tests/extmod/vfs_lfs_error.py.exp @@ -1,28 +1,28 @@ test -mkfs OSError -mount OSError -ilistdir OSError -remove OSError -rmdir OSError -rename OSError -mkdir OSError -chdir OSError +mkfs OSError True +mount OSError True +ilistdir OSError [Errno 2] ENOENT +remove OSError [Errno 2] ENOENT +rmdir OSError [Errno 2] ENOENT +rename OSError [Errno 2] ENOENT +mkdir OSError [Errno 17] EEXIST +chdir OSError [Errno 2] ENOENT / -chdir OSError +chdir OSError [Errno 2] ENOENT / -stat OSError -seek OSError +stat OSError [Errno 2] ENOENT +seek OSError [Errno 22] EINVAL test -mkfs OSError -mount OSError -ilistdir OSError -remove OSError -rmdir OSError -rename OSError -mkdir OSError -chdir OSError +mkfs OSError True +mount OSError True +ilistdir OSError [Errno 2] ENOENT +remove OSError [Errno 2] ENOENT +rmdir OSError [Errno 2] ENOENT +rename OSError [Errno 2] ENOENT +mkdir OSError [Errno 17] EEXIST +chdir OSError [Errno 2] ENOENT / -chdir OSError +chdir OSError [Errno 2] ENOENT / -stat OSError -seek OSError +stat OSError [Errno 2] ENOENT +seek OSError [Errno 22] EINVAL diff --git a/tests/extmod/vfs_lfs_ilistdir_del.py b/tests/extmod/vfs_lfs_ilistdir_del.py index 7b59bc412d9..828c85a2588 100644 --- a/tests/extmod/vfs_lfs_ilistdir_del.py +++ b/tests/extmod/vfs_lfs_ilistdir_del.py @@ -1,8 +1,7 @@ # Test ilistdir __del__ for VfsLittle using a RAM device. -import gc try: - import vfs + import gc, vfs vfs.VfsLfs2 except (ImportError, AttributeError): @@ -71,5 +70,10 @@ def test(bdev, vfs_class): fs.open("/test", "w").close() -bdev = RAMBlockDevice(30) +try: + bdev = RAMBlockDevice(30) +except MemoryError: + print("SKIP") + raise SystemExit + test(bdev, vfs.VfsLfs2) diff --git a/tests/extmod/vfs_mountinfo.py b/tests/extmod/vfs_mountinfo.py index f674e807634..b31dc60ce76 100644 --- a/tests/extmod/vfs_mountinfo.py +++ b/tests/extmod/vfs_mountinfo.py @@ -5,7 +5,6 @@ except ImportError: print("SKIP") raise SystemExit -import errno class Filesystem: diff --git a/tests/extmod/vfs_posix.py b/tests/extmod/vfs_posix.py index d060c0b9c84..22e6e07d3b6 100644 --- a/tests/extmod/vfs_posix.py +++ b/tests/extmod/vfs_posix.py @@ -29,7 +29,21 @@ print(type(os.stat("/"))) # listdir and ilistdir -print(type(os.listdir("/"))) +target = "/" +try: + import platform + + # On Android non-root users are permitted full filesystem access only to + # selected directories. To let this test pass on bionic, the internal + # user-accessible storage area root is enumerated instead of the + # filesystem root. "/storage/emulated/0" should be there on pretty much + # any recent-ish device; querying the proper location requires a JNI + # round-trip, not really worth it. + if platform.platform().startswith("Android-"): + target = "/storage/emulated/0" +except ImportError: + pass +print(type(os.listdir(target))) # mkdir os.mkdir(temp_dir) @@ -83,6 +97,15 @@ def write_files_without_closing(): os.rename(temp_dir + "/test", temp_dir + "/test2") print(os.listdir(temp_dir)) +# construct new VfsPosix with absolute path +fs = vfs.VfsPosix(os.getcwd() + os.sep + temp_dir) +f = fs.open("/test", "w") +f.close() +print(sorted(os.listdir(temp_dir))) +fs.rename("/test", "/_test") +print(sorted(os.listdir(temp_dir))) +fs.remove("/_test") + # construct new VfsPosix with path argument fs = vfs.VfsPosix(temp_dir) # when VfsPosix is used the intended way via vfs.mount(), it can only be called diff --git a/tests/extmod/vfs_posix.py.exp b/tests/extmod/vfs_posix.py.exp index bd1ec7bad67..28dee4c101a 100644 --- a/tests/extmod/vfs_posix.py.exp +++ b/tests/extmod/vfs_posix.py.exp @@ -6,6 +6,8 @@ True hello next_file_no <= base_file_no True ['test2'] +['test', 'test2'] +['_test', 'test2'] ['test2'] diff --git a/tests/extmod/vfs_posix_ilistdir_del.py b/tests/extmod/vfs_posix_ilistdir_del.py index 78d7c854c54..8b5984cd81c 100644 --- a/tests/extmod/vfs_posix_ilistdir_del.py +++ b/tests/extmod/vfs_posix_ilistdir_del.py @@ -1,8 +1,7 @@ # Test ilistdir __del__ for VfsPosix. -import gc try: - import os, vfs + import gc, os, vfs vfs.VfsPosix except (ImportError, AttributeError): diff --git a/tests/extmod/vfs_posix_paths.py b/tests/extmod/vfs_posix_paths.py index b4fedc6716f..c06318748a3 100644 --- a/tests/extmod/vfs_posix_paths.py +++ b/tests/extmod/vfs_posix_paths.py @@ -31,7 +31,7 @@ fs.mkdir("subdir/one") print('listdir("/"):', sorted(i[0] for i in fs.ilistdir("/"))) print('listdir("."):', sorted(i[0] for i in fs.ilistdir("."))) -print('getcwd() in {"", "/"}:', fs.getcwd() in {"", "/"}) +print('getcwd() in ("", "/"):', fs.getcwd() in ("", "/")) print('chdir("subdir"):', fs.chdir("subdir")) print("getcwd():", fs.getcwd()) print('mkdir("two"):', fs.mkdir("two")) diff --git a/tests/extmod/vfs_posix_paths.py.exp b/tests/extmod/vfs_posix_paths.py.exp index ecc13222aaa..d6a0960efd2 100644 --- a/tests/extmod/vfs_posix_paths.py.exp +++ b/tests/extmod/vfs_posix_paths.py.exp @@ -1,6 +1,6 @@ listdir("/"): ['subdir'] listdir("."): ['subdir'] -getcwd() in {"", "/"}: True +getcwd() in ("", "/"): True chdir("subdir"): None getcwd(): /subdir mkdir("two"): None diff --git a/tests/extmod/vfs_posix_readonly.py b/tests/extmod/vfs_posix_readonly.py new file mode 100644 index 00000000000..e7821381006 --- /dev/null +++ b/tests/extmod/vfs_posix_readonly.py @@ -0,0 +1,99 @@ +# Test for VfsPosix + +try: + import gc, os, vfs, errno + + vfs.VfsPosix +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +# We need a directory for testing that doesn't already exist. +# Skip the test if it does exist. +temp_dir = "vfs_posix_readonly_test_dir" +try: + os.stat(temp_dir) + raise SystemExit("Target directory {} exists".format(temp_dir)) +except OSError: + pass + +# mkdir (skip test if whole filesystem is readonly) +try: + os.mkdir(temp_dir) +except OSError as e: + if e.errno == errno.EROFS: + print("SKIP") + raise SystemExit + +fs_factory = lambda: vfs.VfsPosix(temp_dir) + +# mount +fs = fs_factory() +vfs.mount(fs, "/vfs") + +with open("/vfs/file", "w") as f: + f.write("content") + +# test reading works +with open("/vfs/file") as f: + print("file:", f.read()) + +os.mkdir("/vfs/emptydir") + +# umount +vfs.umount("/vfs") + +# mount read-only +fs = fs_factory() +vfs.mount(fs, "/vfs", readonly=True) + +# test reading works +with open("/vfs/file") as f: + print("file 2:", f.read()) + +# test writing fails +try: + with open("/vfs/test_write", "w"): + pass + print("opened") +except OSError as er: + print(repr(er)) + +# test removing fails +try: + os.unlink("/vfs/file") + print("unlinked") +except OSError as er: + print(repr(er)) + +# test renaming fails +try: + os.rename("/vfs/file2", "/vfs/renamed") + print("renamed") +except OSError as er: + print(repr(er)) + +# test removing directory fails +try: + os.rmdir("/vfs/emptydir") + print("rmdir'd") +except OSError as er: + print(repr(er)) + +# test creating directory fails +try: + os.mkdir("/vfs/emptydir2") + print("mkdir'd") +except OSError as er: + print(repr(er)) + +# umount +vfs.umount("/vfs") + +fs = fs_factory() +vfs.mount(fs, "/vfs") + +os.rmdir("/vfs/emptydir") +os.unlink("/vfs/file") + +os.rmdir(temp_dir) diff --git a/tests/extmod/vfs_posix_readonly.py.exp b/tests/extmod/vfs_posix_readonly.py.exp new file mode 100644 index 00000000000..40e4316775f --- /dev/null +++ b/tests/extmod/vfs_posix_readonly.py.exp @@ -0,0 +1,7 @@ +file: content +file 2: content +OSError(30,) +OSError(30,) +OSError(30,) +OSError(30,) +OSError(30,) diff --git a/tests/extmod/vfs_rom.py b/tests/extmod/vfs_rom.py index 770b6863b9c..18ae1f5cf96 100644 --- a/tests/extmod/vfs_rom.py +++ b/tests/extmod/vfs_rom.py @@ -25,7 +25,7 @@ # An mpy file with four constant objects: str, bytes, long-int, float. test_mpy = ( # header - b"M\x06\x00\x1f" # mpy file header + b"M\x06\x00\x1e" # mpy file header, -msmall-int-bits=30 b"\x06" # n_qstr b"\x05" # n_obj # qstrs @@ -394,6 +394,7 @@ class TestMounted(TestBase): def setUp(self): self.orig_sys_path = list(sys.path) self.orig_cwd = os.getcwd() + sys.path = [] vfs.mount(vfs.VfsRom(self.romfs), "/test_rom") def tearDown(self): diff --git a/tests/extmod/websocket_toobig.py b/tests/extmod/websocket_toobig.py new file mode 100644 index 00000000000..f4c5a74bbce --- /dev/null +++ b/tests/extmod/websocket_toobig.py @@ -0,0 +1,28 @@ +try: + import io + import errno + import websocket +except ImportError: + print("SKIP") + raise SystemExit + +try: + buf = "x" * 65536 +except MemoryError: + print("SKIP") + raise SystemExit + + +# do a websocket write and then return the raw data from the stream +def ws_write(msg, sz): + s = io.BytesIO() + ws = websocket.websocket(s) + ws.write(msg) + s.seek(0) + return s.read(sz) + + +try: + print(ws_write(buf, 1)) +except OSError as e: + print("ioctl: ENOBUFS:", e.errno == errno.ENOBUFS) diff --git a/tests/extmod/websocket_toobig.py.exp b/tests/extmod/websocket_toobig.py.exp new file mode 100644 index 00000000000..3bbd95282fd --- /dev/null +++ b/tests/extmod/websocket_toobig.py.exp @@ -0,0 +1 @@ +ioctl: ENOBUFS: True diff --git a/tests/extmod_hardware/machine_can_instances.py b/tests/extmod_hardware/machine_can_instances.py new file mode 100644 index 00000000000..180f4000c2b --- /dev/null +++ b/tests/extmod_hardware/machine_can_instances.py @@ -0,0 +1,74 @@ +# Test multiple concurrent CAN instances using loopback. +# Initialising in any order shouldn't break TX, RX or filtering. +# +# This test is ported from tests/ports/stm32/pyb_can_instances.py + +try: + from machine import CAN + + CAN(2, 125_000) # skip any board which doesn't have at least 2 CAN peripherals +except (ImportError, ValueError): + print("SKIP") + raise SystemExit + +import time +import unittest + +# Some boards have 3x CAN peripherals, test all three +HAS_CAN3 = True +try: + CAN(3, 125_000) +except ValueError: + HAS_CAN3 = False + + +class Test(unittest.TestCase): + def test_can12(self): + self._test_pairs([(1, 2), (2, 1)]) + + @unittest.skipUnless(HAS_CAN3, "no CAN3") + def test_can3(self): + self._test_pairs([(1, 3), (3, 1), (2, 3), (3, 2)]) + + def _test_pairs(self, seq): + for id_a, id_b in seq: + with self.subTest("Testing CAN pair", id_a=id_a, id_b=id_b): + self._test_controller_pair(id_a, id_b) + + def _test_controller_pair(self, id_a, id_b): + # Setting up each CAN peripheral independently is deliberate here, to catch + # catch cases where initialising CAN2 breaks CAN1 or vice versa + can_a = CAN(id_a, 125_000, mode=CAN.MODE_SILENT_LOOPBACK) + can_a.set_filters([(0x100, 0x700, 0)]) + + can_b = CAN(id_b, 125_000, mode=CAN.MODE_SILENT_LOOPBACK) + can_b.set_filters([(0x000, 0x7F0, 0)]) + + try: + # Drain any old messages in RX FIFOs + for can in (can_a, can_b): + while can.recv(): + pass + + for which, id, can in (("A", id_a, can_a), ("B", id_b, can_b)): + # print("testing config", which, "with controller", can) + # message1 should only receive on can_a, message2 on can_b + can.send(0x123, "message1", 0) + can.send(0x003, "message2", 0) + time.sleep_ms(10) + n_recv = 0 + while res := can.recv(): + n_recv += 1 + # print(res) + if can == can_a: + self.assertEqual(res[1], b"message1", "can_a should receive message1 only") + if can == can_b: + self.assertEqual(res[1], b"message2", "can_b should receive message2 only") + self.assertEqual(n_recv, 1, "Each instance should receive exactly 1 message") + finally: + can_a.deinit() + can_b.deinit() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod_hardware/machine_can_timings.py b/tests/extmod_hardware/machine_can_timings.py new file mode 100644 index 00000000000..441059f5da5 --- /dev/null +++ b/tests/extmod_hardware/machine_can_timings.py @@ -0,0 +1,60 @@ +# Test machine.CAN timings results +# +# Single device test, assumes no connections to the CAN pins + +try: + from machine import CAN +except ImportError: + print("SKIP") + raise SystemExit + +import unittest + +from target_wiring import can_args, can_kwargs + + +class TestTimings(unittest.TestCase): + def test_bitrate(self): + for bitrate in (125_000, 250_000, 500_000, 1_000_000): + can = CAN(*can_args, bitrate=bitrate, **can_kwargs) + print(can) + timings = can.get_timings() + print(timings) + # Actual bitrate may not be exactly equal to requested rate + self.assertAlmostEqual(timings[0], bitrate, delta=1_000) + can.deinit() + + def test_sample_point(self): + # Verify that tseg1 and tseg2 are set correctly from the sample_point argument + for sample_point in (66, 75, 95): + can = CAN(*can_args, bitrate=500_000, sample_point=sample_point, **can_kwargs) + _bitrate, _sjw, tseg1, tseg2, _fd, _port = can.get_timings() + print(f"sample_point={sample_point}, tseg1={tseg1}, tseg2={tseg2}") + self.assertAlmostEqual(sample_point / 100, tseg1 / (tseg1 + tseg2), delta=0.05) + can.deinit() + + def test_tseg_args(self): + # Verify that tseg1 and tseg2 are set correctly and sample_point is ignored if these are provided + for tseg1, tseg2 in ((5, 2), (16, 8), (16, 5), (15, 5)): + print(f"tseg1={tseg1} tseg2={tseg2}") + can = CAN( + *can_args, bitrate=250_000, tseg1=tseg1, tseg2=tseg2, sample_point=99, **can_kwargs + ) + bitrate, _sjw, ret_tseg1, ret_tseg2, _fd, _port = can.get_timings() + self.assertEqual(ret_tseg1, tseg1) + self.assertEqual(ret_tseg2, tseg2) + + def test_invalid_timing_args(self): + # Test various kwargs out of their allowed value ranges + with self.assertRaises(ValueError): + CAN(*can_args, bitrate=250_000, tseg1=55, **can_kwargs) + with self.assertRaises(ValueError): + CAN(*can_args, bitrate=500_000, tseg2=9, **can_kwargs) + with self.assertRaises(ValueError): + CAN(*can_args, bitrate=-1, **can_kwargs) + with self.assertRaises(ValueError): + CAN(*can_args, bitrate=500_000, sample_point=101, **can_kwargs) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod_hardware/machine_counter.py b/tests/extmod_hardware/machine_counter.py new file mode 100644 index 00000000000..a91d262854e --- /dev/null +++ b/tests/extmod_hardware/machine_counter.py @@ -0,0 +1,101 @@ +# Test machine.Counter implementation +# +# IMPORTANT: This test requires hardware connections: the out_pin and in_pin +# must be wired together. + +try: + from machine import Counter +except ImportError: + print("SKIP") + raise SystemExit + +import sys +from machine import Pin + +if "esp32" in sys.platform: + id = 0 + out_pin = 4 + in_pin = 5 +elif sys.platform == "mimxrt": + if "Teensy" in sys.implementation._machine: + id = 0 + out_pin = "D2" + in_pin = "D3" +else: + print("Please add support for this test on this platform.") + raise SystemExit + +import unittest + +out_pin = Pin(out_pin, mode=Pin.OUT) +in_pin = Pin(in_pin, mode=Pin.IN) + + +def toggle(times): + for _ in range(times): + out_pin(1) + out_pin(0) + + +class TestConnections(unittest.TestCase): + def setUp(self): + in_pin.init(Pin.IN) + + def test_connections(self): + # Test the hardware connections are correct. If this test fails, all tests will fail. + out_pin(1) + self.assertEqual(1, in_pin()) + out_pin(0) + self.assertEqual(0, in_pin()) + + +class TestCounter(unittest.TestCase): + def setUp(self): + out_pin(0) + self.counter = Counter(id, in_pin) + + def tearDown(self): + self.counter.deinit() + + def assertCounter(self, value): + self.assertEqual(self.counter.value(), value) + + def test_count_rising(self): + self.assertCounter(0) + toggle(100) + self.assertCounter(100) + out_pin(1) + self.assertEqual(self.counter.value(0), 101) + self.assertCounter(0) # calling value(0) resets + out_pin(0) + self.assertCounter(0) # no rising edge + out_pin(1) + self.assertCounter(1) + + def test_change_directions(self): + self.assertCounter(0) + toggle(100) + self.assertCounter(100) + self.counter.init(in_pin, direction=Counter.DOWN) + self.assertCounter(0) # calling init() zeroes the counter + self.counter.value(100) # need to manually reset the value + self.assertCounter(100) + toggle(25) + self.assertCounter(75) + + @unittest.skipIf(sys.platform == "mimxrt", "FALLING edge not supported") + def test_count_falling(self): + self.counter.init(in_pin, direction=Counter.UP, edge=Counter.FALLING) + toggle(20) + self.assertCounter(20) + out_pin(1) + self.assertCounter(20) # no falling edge + out_pin(0) + self.assertCounter(21) + self.counter.value(-(2**24)) + toggle(20) + self.assertCounter(-(2**24 - 20)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod_hardware/machine_encoder.py b/tests/extmod_hardware/machine_encoder.py new file mode 100644 index 00000000000..67d1b5f443e --- /dev/null +++ b/tests/extmod_hardware/machine_encoder.py @@ -0,0 +1,158 @@ +# Test machine.Encoder implementation +# +# IMPORTANT: This test requires hardware connections: +# - out0_pin and in0_pin must be wired together. +# - out1_pin and in1_pin must be wired together. + +try: + from machine import Encoder +except ImportError: + print("SKIP") + raise SystemExit + +import sys +import unittest +from machine import Pin +from target_wiring import encoder_loopback_id, encoder_loopback_out_pins, encoder_loopback_in_pins + +PRINT = False +PIN_INIT_VALUE = 1 + +id = encoder_loopback_id +out0_pin, out1_pin = encoder_loopback_out_pins +in0_pin, in1_pin = encoder_loopback_in_pins + +out0_pin = Pin(out0_pin, mode=Pin.OUT) +in0_pin = Pin(in0_pin, mode=Pin.IN) +out1_pin = Pin(out1_pin, mode=Pin.OUT) +in1_pin = Pin(in1_pin, mode=Pin.IN) + + +class TestConnections(unittest.TestCase): + def setUp(self): + in0_pin.init(Pin.IN) + in1_pin.init(Pin.IN) + + def test_connections(self): + # Test the hardware connections are correct. If this test fails, all tests will fail. + for ch, outp, inp in ((0, out0_pin, in0_pin), (1, out1_pin, in1_pin)): + print("Testing channel ", ch) + outp(1) + self.assertEqual(1, inp()) + outp(0) + self.assertEqual(0, inp()) + + +class TestEncoder(unittest.TestCase): + def setUp(self): + out0_pin(PIN_INIT_VALUE) + out1_pin(PIN_INIT_VALUE) + self.enc = Encoder(id, in0_pin, in1_pin, phases=1) + self.enc2 = Encoder(id + 1, in0_pin, in1_pin, phases=2) + self.enc4 = Encoder(id + 2, in0_pin, in1_pin, phases=4) + self.pulses = 0 # track the expected encoder position in software + if PRINT: + print( + "\nout0_pin() out1_pin() enc.value() enc2.value() enc4.value() |", + out0_pin(), + out1_pin(), + "|", + self.enc.value(), + self.enc2.value(), + self.enc4.value(), + ) + + def tearDown(self): + self.enc.deinit() + try: + self.enc2.deinit() + except: + pass + try: + self.enc4.deinit() + except: + pass + + def rotate(self, pulses): + for _ in range(abs(pulses)): + self.pulses += 1 if (pulses > 0) else -1 + if pulses > 0: + if self.pulses % 2: + out0_pin(not out0_pin()) + else: + out1_pin(not out1_pin()) + else: + if self.pulses % 2: + out1_pin(not out1_pin()) + else: + out0_pin(not out0_pin()) + if PRINT: + print( + "out0_pin() out1_pin() enc.value() enc2.value() enc4.value() pulses self.pulses |", + out0_pin(), + out1_pin(), + "|", + self.enc.value(), + self.enc2.value(), + self.enc4.value(), + "|", + pulses, + self.pulses, + ) + + def assertPosition(self, value, value2=None, value4=None): + self.assertEqual(self.enc.value(), value) + if not value2 is None: + self.assertEqual(self.enc2.value(), value2) + if not value4 is None: + self.assertEqual(self.enc4.value(), value4) + pass + + def test_basics(self): + self.assertPosition(0) + self.rotate(100) + self.assertPosition(100 // 4, 100 // 2, 100) + self.rotate(-100) + self.assertPosition(0) + + def test_partial(self): + # With phase=1 (default), need 4x pulses to count a rotation + self.assertPosition(0) + self.rotate(1) + self.assertPosition(1, 1, 1) + self.rotate(1) + self.assertPosition(1, 1, 2) + self.rotate(1) + self.assertPosition(1, 2, 3) + self.rotate(1) + self.assertPosition(1, 2, 4) # +4 + self.rotate(1) + self.assertPosition(2, 3, 5) + self.rotate(1) + self.assertPosition(2, 3, 6) + self.rotate(1) + self.assertPosition(2, 4, 7) + self.rotate(1) + self.assertPosition(2, 4, 8) # +4 + self.rotate(-1) + self.assertPosition(2, 4, 7) + self.rotate(-3) + self.assertPosition(1, 2, 4) # -4 + self.rotate(-4) + self.assertPosition(0, 0, 0) # -4 + self.rotate(-1) + self.assertPosition(0, 0, -1) + self.rotate(-1) + self.assertPosition(0, -1, -2) + self.rotate(-1) + self.assertPosition(0, -1, -3) + self.rotate(-1) + self.assertPosition(-1, -2, -4) # -4 + self.rotate(-1) + self.assertPosition(-1, -2, -5) + self.rotate(-3) + self.assertPosition(-2, -4, -8) # -4 + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod_hardware/machine_i2c_target.py b/tests/extmod_hardware/machine_i2c_target.py new file mode 100644 index 00000000000..763e6f4771e --- /dev/null +++ b/tests/extmod_hardware/machine_i2c_target.py @@ -0,0 +1,307 @@ +# Test machine.I2CTarget. +# +# IMPORTANT: This test requires hardware connections: a SoftI2C instance must be +# wired to a hardware I2C target. See pin definitions below. + +import sys + +try: + from machine import Pin, SoftI2C, I2CTarget +except ImportError: + print("SKIP") + raise SystemExit + +import unittest + +ADDR = 67 + +kwargs_target = {} + +# Configure pins based on the target. +if sys.platform == "alif" and sys.implementation._build == "ALIF_ENSEMBLE": + args_controller = {"scl": "P1_1", "sda": "P1_0"} + args_target = (0,) # on pins P0_3/P0_2 +elif sys.platform == "esp32": + args_controller = {"scl": 5, "sda": 6} + args_target = (0,) # on pins 9/8 for C3 and S3, 18/19 for others + kwargs_target = {"scl": 9, "sda": 8} +elif sys.platform == "rp2": + args_controller = {"scl": 5, "sda": 4} + args_target = (1,) +elif sys.platform == "pyboard": + if sys.implementation._build == "NUCLEO_WB55": + args_controller = {"scl": "B8", "sda": "B9"} + args_target = (3,) + else: + args_controller = {"scl": "X1", "sda": "X2"} + args_target = ("X",) +elif "zephyr-nucleo_wb55rg" in sys.implementation._machine: + # PB8=I2C1_SCL, PB9=I2C1_SDA (on Arduino header D15/D14) + # PC0=I2C3_SCL, PC1=I2C3_SDA (on Arduino header A0/A1) + args_controller = {"scl": Pin(("gpiob", 8)), "sda": Pin(("gpiob", 9))} + args_target = ("i2c3",) +elif "zephyr-rpi_pico" in sys.implementation._machine: + args_controller = {"scl": Pin(("gpio0", 5)), "sda": Pin(("gpio0", 4))} + args_target = ("i2c1",) # on gpio7/gpio6 +elif sys.platform == "mimxrt": + if "Teensy" in sys.implementation._machine: + args_controller = {"scl": "A6", "sda": "A3"} # D20/D17 + else: + args_controller = {"scl": "D0", "sda": "D1"} + args_target = (0,) # pins 19/18 On Teensy 4.x +elif sys.platform == "samd": + args_controller = {"scl": "D5", "sda": "D1"} + args_target = () +else: + print("Please add support for this test on this platform.") + raise SystemExit + + +def config_pull_up(): + Pin(args_controller["scl"], Pin.OPEN_DRAIN, Pin.PULL_UP) + Pin(args_controller["sda"], Pin.OPEN_DRAIN, Pin.PULL_UP) + + +class TestMemory(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.mem = bytearray(8) + cls.i2c = SoftI2C(**args_controller) + cls.i2c_target = I2CTarget(*args_target, **kwargs_target, addr=ADDR, mem=cls.mem) + config_pull_up() + + @classmethod + def tearDownClass(cls): + cls.i2c_target.deinit() + + def test_scan(self): + self.assertIn(ADDR, self.i2c.scan()) + + def test_write(self): + self.mem[:] = b"01234567" + self.i2c.writeto_mem(ADDR, 0, b"test") + self.assertEqual(self.mem, bytearray(b"test4567")) + self.i2c.writeto_mem(ADDR, 4, b"TEST") + self.assertEqual(self.mem, bytearray(b"testTEST")) + + def test_write_wrap(self): + self.mem[:] = b"01234567" + self.i2c.writeto_mem(ADDR, 6, b"test") + self.assertEqual(self.mem, bytearray(b"st2345te")) + + @unittest.skipIf(sys.platform == "esp32", "write lengths larger than buffer unsupported") + def test_write_wrap_large(self): + self.mem[:] = b"01234567" + self.i2c.writeto_mem(ADDR, 0, b"testTESTmore") + self.assertEqual(self.mem, bytearray(b"moreTEST")) + + def test_read(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.readfrom_mem(ADDR, 0, 4), b"0123") + self.assertEqual(self.i2c.readfrom_mem(ADDR, 4, 4), b"4567") + + def test_read_wrap(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.readfrom_mem(ADDR, 0, 4), b"0123") + self.assertEqual(self.i2c.readfrom_mem(ADDR, 2, 4), b"2345") + self.assertEqual(self.i2c.readfrom_mem(ADDR, 6, 4), b"6701") + + @unittest.skipIf(sys.platform == "esp32", "read lengths larger than buffer unsupported") + def test_read_wrap_large(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.readfrom_mem(ADDR, 0, 12), b"012345670123") + + def test_write_read(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.writeto(ADDR, b"\x02"), 1) + self.assertEqual(self.i2c.readfrom(ADDR, 4), b"2345") + + @unittest.skipIf(sys.platform == "esp32", "read after read unsupported") + def test_write_read_read(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.writeto(ADDR, b"\x02"), 1) + self.assertEqual(self.i2c.readfrom(ADDR, 4), b"2345") + self.assertEqual(self.i2c.readfrom(ADDR, 4), b"7012") + + +@unittest.skipUnless(hasattr(I2CTarget, "IRQ_END_READ"), "IRQ unsupported") +class TestMemoryIRQ(unittest.TestCase): + @staticmethod + def irq_handler(i2c_target): + flags = i2c_target.irq().flags() + TestMemoryIRQ.events[TestMemoryIRQ.num_events] = flags + TestMemoryIRQ.events[TestMemoryIRQ.num_events + 1] = i2c_target.memaddr + TestMemoryIRQ.num_events += 2 + + @classmethod + def setUpClass(cls): + cls.mem = bytearray(8) + cls.events = [0] * 8 + cls.num_events = 0 + cls.i2c = SoftI2C(**args_controller) + cls.i2c_target = I2CTarget(*args_target, **kwargs_target, addr=ADDR, mem=cls.mem) + cls.i2c_target.irq(TestMemoryIRQ.irq_handler) + config_pull_up() + + @classmethod + def tearDownClass(cls): + cls.i2c_target.deinit() + + @unittest.skipIf(sys.platform == "esp32", "scan doesn't trigger IRQ_END_WRITE") + def test_scan(self): + TestMemoryIRQ.num_events = 0 + self.i2c.scan() + self.assertEqual(self.events[: self.num_events], [I2CTarget.IRQ_END_WRITE, 0]) + + def test_write(self): + TestMemoryIRQ.num_events = 0 + self.mem[:] = b"01234567" + self.i2c.writeto_mem(ADDR, 2, b"test") + self.assertEqual(self.mem, bytearray(b"01test67")) + self.assertEqual(self.events[: self.num_events], [I2CTarget.IRQ_END_WRITE, 2]) + + def test_read(self): + TestMemoryIRQ.num_events = 0 + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.readfrom_mem(ADDR, 2, 4), b"2345") + self.assertEqual(self.events[: self.num_events], [I2CTarget.IRQ_END_READ, 2]) + + +@unittest.skipUnless(hasattr(I2CTarget, "IRQ_WRITE_REQ"), "IRQ unsupported") +@unittest.skipIf(sys.platform == "mimxrt", "not working") +@unittest.skipIf(sys.platform == "pyboard", "can't queue more than one byte") +@unittest.skipIf(sys.platform == "samd", "not working") +@unittest.skipIf(sys.platform == "zephyr", "must call readinto/write in IRQ handler") +class TestPolling(unittest.TestCase): + @staticmethod + def irq_handler(i2c_target, buf=bytearray(1)): + flags = i2c_target.irq().flags() + if flags & I2CTarget.IRQ_READ_REQ: + i2c_target.write(b"0123") + + @classmethod + def setUpClass(cls): + cls.i2c = SoftI2C(**args_controller) + cls.i2c_target = I2CTarget(*args_target, addr=ADDR) + cls.i2c_target.irq( + TestPolling.irq_handler, + I2CTarget.IRQ_WRITE_REQ | I2CTarget.IRQ_READ_REQ, + hard=True, + ) + config_pull_up() + + @classmethod + def tearDownClass(cls): + cls.i2c_target.deinit() + + def test_read(self): + # Can't write data up front, must wait until IRQ_READ_REQ. + # self.assertEqual(self.i2c_target.write(b"abcd"), 4) + self.assertEqual(self.i2c.readfrom(ADDR, 4), b"0123") + + def test_write(self): + # Can do the read outside the IRQ, but requires IRQ_WRITE_REQ trigger to be set. + self.assertEqual(self.i2c.writeto(ADDR, b"0123"), 4) + buf = bytearray(8) + self.assertEqual(self.i2c_target.readinto(buf), 4) + self.assertEqual(buf, b"0123\x00\x00\x00\x00") + + +@unittest.skipUnless(hasattr(I2CTarget, "IRQ_ADDR_MATCH_READ"), "IRQ unsupported") +class TestIRQ(unittest.TestCase): + @staticmethod + def irq_handler(i2c_target, buf=bytearray(1)): + flags = i2c_target.irq().flags() + TestIRQ.events[TestIRQ.num_events] = flags + TestIRQ.num_events += 1 + if flags & I2CTarget.IRQ_READ_REQ: + i2c_target.write(b"Y") + if flags & I2CTarget.IRQ_WRITE_REQ: + i2c_target.readinto(buf) + TestIRQ.events[TestIRQ.num_events] = buf[0] + TestIRQ.num_events += 1 + + @classmethod + def setUpClass(cls): + cls.events = [0] * 8 + cls.num_events = 0 + cls.i2c = SoftI2C(**args_controller) + cls.i2c_target = I2CTarget(*args_target, addr=ADDR) + cls.i2c_target.irq( + TestIRQ.irq_handler, + I2CTarget.IRQ_ADDR_MATCH_READ + | I2CTarget.IRQ_ADDR_MATCH_WRITE + | I2CTarget.IRQ_WRITE_REQ + | I2CTarget.IRQ_READ_REQ + | I2CTarget.IRQ_END_READ + | I2CTarget.IRQ_END_WRITE, + hard=True, + ) + config_pull_up() + + @classmethod + def tearDownClass(cls): + cls.i2c_target.deinit() + + def test_scan(self): + TestIRQ.num_events = 0 + self.i2c.scan() + self.assertEqual( + self.events[: self.num_events], + [ + I2CTarget.IRQ_ADDR_MATCH_WRITE, + I2CTarget.IRQ_END_WRITE, + ], + ) + + def test_write(self): + TestIRQ.num_events = 0 + self.i2c.writeto(ADDR, b"XYZ") + self.assertEqual( + self.events[: self.num_events], + [ + I2CTarget.IRQ_ADDR_MATCH_WRITE, + I2CTarget.IRQ_WRITE_REQ, + ord(b"X"), + I2CTarget.IRQ_WRITE_REQ, + ord(b"Y"), + I2CTarget.IRQ_WRITE_REQ, + ord(b"Z"), + I2CTarget.IRQ_END_WRITE, + ], + ) + + def test_read(self): + TestIRQ.num_events = 0 + self.assertEqual(self.i2c.readfrom(ADDR, 1), b"Y") + self.assertEqual( + self.events[: self.num_events], + [ + I2CTarget.IRQ_ADDR_MATCH_READ, + I2CTarget.IRQ_READ_REQ, + I2CTarget.IRQ_READ_REQ, + I2CTarget.IRQ_END_READ, + ], + ) + + def test_write_read(self): + TestIRQ.num_events = 0 + self.i2c.writeto(ADDR, b"X", False) + self.assertEqual(self.i2c.readfrom(ADDR, 1), b"Y") + self.assertEqual( + self.events[: self.num_events], + [ + I2CTarget.IRQ_ADDR_MATCH_WRITE, + I2CTarget.IRQ_WRITE_REQ, + ord(b"X"), + I2CTarget.IRQ_END_WRITE, + I2CTarget.IRQ_ADDR_MATCH_READ, + I2CTarget.IRQ_READ_REQ, + I2CTarget.IRQ_READ_REQ, + I2CTarget.IRQ_END_READ, + ], + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod_hardware/machine_pwm.py b/tests/extmod_hardware/machine_pwm.py index e27da325486..7d4f82fd2fe 100644 --- a/tests/extmod_hardware/machine_pwm.py +++ b/tests/extmod_hardware/machine_pwm.py @@ -1,10 +1,7 @@ # Test machine.PWM, frequency and duty cycle (using machine.time_pulse_us). # # IMPORTANT: This test requires hardware connections: the PWM-output and pulse-input -# pins must be wired together (see the variable `pwm_pulse_pins`). - -import sys -import time +# pins must be wired together (see the variable `pwm_loopback_pins`). try: from machine import time_pulse_us, Pin, PWM @@ -12,44 +9,34 @@ print("SKIP") raise SystemExit -import unittest +import machine, sys, time, unittest +from target_wiring import pwm_loopback_pins pwm_freq_limit = 1000000 freq_margin_per_thousand = 0 duty_margin_per_thousand = 0 timing_margin_us = 5 -# Configure pins based on the target. +# Slow MCUs cannot capture short pulses using `time_pulse_us` so limit the maximum PWM +# frequency tested on such targets. +if hasattr(machine, "freq"): + f = machine.freq() + if isinstance(f, tuple): + f = f[0] + if f <= 48_000_000: + pwm_freq_limit = 2_000 + elif f <= 64_000_000: + pwm_freq_limit = 5_000 + +# Tune test parameters based on the target. if "esp32" in sys.platform: - pwm_pulse_pins = ((4, 5),) freq_margin_per_thousand = 2 duty_margin_per_thousand = 1 timing_margin_us = 20 elif "esp8266" in sys.platform: - pwm_pulse_pins = ((4, 5),) pwm_freq_limit = 1_000 duty_margin_per_thousand = 3 timing_margin_us = 50 -elif "mimxrt" in sys.platform: - if "Teensy" in sys.implementation._machine: - # Teensy 4.x - pwm_pulse_pins = ( - ("D0", "D1"), # FLEXPWM X and UART 1 - ("D2", "D3"), # FLEXPWM A/B - ("D11", "D12"), # QTMR and MOSI/MISO of SPI 0 - ) - else: - pwm_pulse_pins = (("D0", "D1"),) -elif "rp2" in sys.platform: - pwm_pulse_pins = (("GPIO0", "GPIO1"),) -elif "samd" in sys.platform: - pwm_pulse_pins = (("D0", "D1"),) - if "SAMD21" in sys.implementation._machine: - # MCU is too slow to capture short pulses. - pwm_freq_limit = 2_000 -else: - print("Please add support for this test on this platform.") - raise SystemExit # Test a specific frequency and duty cycle. @@ -66,8 +53,8 @@ def _test_freq_duty(self, pulse_in, pwm, freq, duty_u16): self.assertLessEqual(duty_error, duty_margin_per_thousand) # Calculate expected timing. - expected_total_us = 1_000_000 // freq - expected_high_us = expected_total_us * duty_u16 // 65535 + expected_total_us = (1_000_000 + freq // 2) // freq + expected_high_us = (expected_total_us * duty_u16 + 65535 // 2) // 65535 expected_low_us = expected_total_us - expected_high_us expected_us = (expected_low_us, expected_high_us) timeout = 2 * expected_total_us @@ -156,7 +143,7 @@ def test_freq_10000(self): # Generate test classes, one for each set of pins to test. -for pwm, pulse in pwm_pulse_pins: +for pwm, pulse in pwm_loopback_pins: cls_name = "Test_{}_{}".format(pwm, pulse) globals()[cls_name] = type( cls_name, (TestBase, unittest.TestCase), {"pwm_pin": pwm, "pulse_pin": pulse} diff --git a/tests/extmod_hardware/machine_sdcard_dma_align.py b/tests/extmod_hardware/machine_sdcard_dma_align.py new file mode 100644 index 00000000000..5ab7a501930 --- /dev/null +++ b/tests/extmod_hardware/machine_sdcard_dma_align.py @@ -0,0 +1,225 @@ +# Test DMA read operations when the buffer alignment in RAM varies. +# +# Runs on both pyb.SDCard and machine.SDCard with default arguments, +# although some port-specific info is needed (see below) +# +# Test requirements: +# A mostly empty FAT formatted SDCard installed in SD socket (a card with other +# files may be much slower to start the test.) +import errno +import os +import machine +import micropython +import sys +import vfs +import unittest + +from micropython import const + +# Use pyb classes on stm32, machine class otherwise +try: + from pyb import SDCard, Timer +except ImportError: + try: + from machine import SDCard, Timer + except ImportError: + print("SKIP") + raise SystemExit + +_BLOCK_SZ = const(512) +_OFFS_WIDTH = const(64) # Should be at least the cache line size plus the GC block size +_TEST_BUF_SZ = const(_BLOCK_SZ + _OFFS_WIDTH) + +MOUNT_POINT = "/sd" +FILE_PATH = "/sd/stm32_align.blk" + +# Skip the whole test if there isn't a mountable SDCard +try: + sd = SDCard() + fs = vfs.VfsFat(sd) + vfs.mount(sd, MOUNT_POINT) + vfs.umount(MOUNT_POINT) + del sd +except (OSError, ValueError, AttributeError): + print("SKIP") + raise SystemExit + + +# Set some port-specific parameters for test repeats & interrupt frequency +# (ports which can issue interrupts at a high frequency don't need to run as many +# repeats of the test in order to trigger a failure due to cache bugs.) +if "pyboard" in sys.platform: + + def make_timer(timer_cb): + # Pyboard SF6 can do at least this frequency and still run the test, + # possibly as high as 40kHz depending on the callback details. + return Timer(1, freq=35_000, callback=timer_cb, hard=True) + + REPEATS = 8 +elif "mimxrt" in sys.platform: + + def make_timer(timer_cb): + return Timer(-1, period=1, callback=timer_cb, hard=True) + + # virtual timer limited to 1kHz so run more iterations (slow test!) + REPEATS = 64 + + +def verify_contents(buf, silent=False): + # Verify that each byte in 'buf' has the value of its index in the buffer + bad_pos = [] + for i in range(_BLOCK_SZ): + bi = buf[i] + if bi != i & 0xFF: + if silent: + return False + bad_pos.append((i, bi)) + if not bad_pos: + return True + + assert not silent + + print("{} bad readback values in sector:".format(len(bad_pos)), end="") + for i, v in bad_pos: + print(" {:#x}={:#x}".format(i, v), end="") + print() + return False + + +class TestSDAlign(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.sd = SDCard() + vfs.mount(cls.sd, MOUNT_POINT) + buf = bytearray(_BLOCK_SZ) + try: + with open(FILE_PATH, "rb") as f: + rlen = f.readinto(buf) + if rlen != _BLOCK_SZ: + raise RuntimeError("Unexpected length of temporary file ", FILE_PATH, rlen) + if not verify_contents(buf): + raise RuntimeError("Corrupt test block in temporary file ", FILE_PATH) + except OSError as e: + if e.errno != errno.ENOENT: + raise e + + print("Creating new temp file...") + with open(FILE_PATH, "wb") as f: + f.write(bytes(i & 0xFF for i in range(_BLOCK_SZ))) + + # Now look for the sector which holds the temporary file + # (assume is in the first 20MB of the SD Card) + vfs.umount(MOUNT_POINT) + for b in range(1, 40960): + res = cls.sd.readblocks(b, buf) + if res != 0: + raise RuntimeError("Failed to call readblocks on SDCard:", res, "block:", b) + if verify_contents(buf, True): + print("Temporary file contents found in block {}".format(b)) + cls.block = b + return + + raise RuntimeError( + "Contents of temporary file not found near start of SDCard. Too many files?" + ) + + @classmethod + def tearDownClass(cls): + try: + os.unlink(FILE_PATH) + print("Deleted temp file") + except OSError: + pass + try: + vfs.umount(MOUNT_POINT) + except OSError: + pass + del cls.sd + + def setUp(self): + self.offs = 0 + + @micropython.native + def _test_reads_inner(self, buf, repeats=REPEATS): + for offs in range(_OFFS_WIDTH): + with self.subTest(offs=offs): + self.offs = offs + slice = memoryview(buf)[offs : offs + _BLOCK_SZ] + assert len(slice) == _BLOCK_SZ + for r in range(repeats): + self.assertEqual( + self.sd.readblocks(self.block, slice), + 0, + "Read failed for block {} offs {} repeat {}/{}".format( + self.block, offs, r, repeats + ), + ) + self.assertTrue( + verify_contents(slice), + "Verify failed for block {} offs {} repeat {}/{}".format( + self.block, offs, r, repeats + ), + ) + + def test_reads(self): + # Test reading at all available offsets in a buffer + buf = bytearray(_TEST_BUF_SZ) + # This test is the most random as any failure depends on speculative reads while + # the DMA operation is in progress. We run the test more times to increase the chance + # of hitting one of these cases, but even if the issue is present the test only fails + # once per ~250 iterations. The other tests inject explicit reads and writes so they fail + # more or less immediately. + self._test_reads_inner(buf, repeats=REPEATS * 4) + + def test_interrupted_reads(self): + # Test reading at all available offsets in a buffer, while an interrupt is + # scanning through the whole buffer + buf = bytearray(_TEST_BUF_SZ) + t = None + self.scan = 0 + self.val = None + try: + + @micropython.native + def timer_cb(_): + # Arbitrary read from somewhere in the buffer + self.val = buf[self.scan % _TEST_BUF_SZ] + self.scan += 1 + + t = make_timer(timer_cb) + self._test_reads_inner(buf) + finally: + if t: + t.deinit() + # print("scan count", self.scan, self.val) + + def test_interrupted_read_write(self): + # Test reading at all available offsets in a buffer, while an interrupt is + # writing before & after the DMA buffer + buf = bytearray(_TEST_BUF_SZ) + t = None + try: + + @micropython.native + def timer_cb(t): + # Arbitrary CPU write just before and after the buffer, trying to dirty a DMA cache line + # + # Note: we never write into a word overlapping the DMA buffer, because if the buffer is not 4-byte aligned + # sdcard_read_blocks() will do a trick to align it temporarily, and this will race with that trick and + # corrupt the memory. + offs = self.offs + if offs > 3: + buf[offs - 4] = 0x55 + offs += _BLOCK_SZ + if offs < _TEST_BUF_SZ - 3: + buf[offs] = 0x56 + + t = make_timer(timer_cb) + self._test_reads_inner(buf) + finally: + if t: + t.deinit() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/feature_check/float.py b/tests/feature_check/float.py deleted file mode 100644 index d6d2a99d242..00000000000 --- a/tests/feature_check/float.py +++ /dev/null @@ -1,13 +0,0 @@ -# detect how many bits of precision the floating point implementation has - -try: - float -except NameError: - print(0) -else: - if float("1.0000001") == float("1.0"): - print(30) - elif float("1e300") == float("inf"): - print(32) - else: - print(64) diff --git a/tests/feature_check/float.py.exp b/tests/feature_check/float.py.exp deleted file mode 100644 index 900731ffd51..00000000000 --- a/tests/feature_check/float.py.exp +++ /dev/null @@ -1 +0,0 @@ -64 diff --git a/tests/feature_check/fstring.py.exp b/tests/feature_check/fstring.py.exp deleted file mode 100644 index 73cdb8bcc87..00000000000 --- a/tests/feature_check/fstring.py.exp +++ /dev/null @@ -1 +0,0 @@ -a=1 diff --git a/tests/feature_check/inlineasm.py b/tests/feature_check/inlineasm.py new file mode 100644 index 00000000000..0a2858fa451 --- /dev/null +++ b/tests/feature_check/inlineasm.py @@ -0,0 +1,89 @@ +# check if the inline assembler is enabled and enumerate its capabilities. + +import sys + +fields = [] + +mpy_arch = (getattr(sys.implementation, "_mpy", 0) >> 10) & 0x0F +if 8 >= mpy_arch >= 3: + fields.append("thumb") + if mpy_arch >= 7: + fields.append("vfp") +elif 10 >= mpy_arch >= 9: + fields.append("xtensa") + if mpy_arch == 10: + fields.append("windowed") +elif mpy_arch == 11: + fields.append("rv32") +else: + raise SystemExit + +arch = fields[0] +has_asm = False +if arch == "thumb": + try: + exec(""" +@micropython.asm_thumb +def f(): + add(r0, r0, r0) +""") + has_asm = True + except SyntaxError: + pass +elif arch == "xtensa": + try: + exec(""" +@micropython.asm_xtensa +def f(): + add(a0, a0, a0) +""") + has_asm = True + except SyntaxError: + pass +elif arch == "rv32": + try: + exec(""" +@micropython.asm_rv32 +def f(): + add(a0, a0, a0) +""") + has_asm = True + except SyntaxError: + pass +if not has_asm: + raise SystemExit + +if arch == "thumb": + try: + exec(""" +@micropython.asm_thumb +def f(): + it(eq) + nop() +""") + fields.append("thumb2") + except SyntaxError: + pass +elif arch == "xtensa": + pass +elif arch == "rv32": + try: + exec(""" +@micropython.asm_rv32 +def f(): + sh1add(a0, a0, a0) +""") + fields.append("zba") + except SyntaxError: + pass + try: + exec(""" +@micropython.asm_rv32 +def f(): + cm_mva01s(s0, s1) +""") + fields.append("zcmp") + except SyntaxError: + pass + +print(",".join(fields)) diff --git a/tests/feature_check/inlineasm_rv32.py b/tests/feature_check/inlineasm_rv32.py deleted file mode 100644 index 21dd103b6c3..00000000000 --- a/tests/feature_check/inlineasm_rv32.py +++ /dev/null @@ -1,9 +0,0 @@ -# check if RISC-V 32 inline asm is supported - - -@micropython.asm_rv32 -def f(): - add(a0, a0, a0) - - -print("rv32") diff --git a/tests/feature_check/inlineasm_rv32.py.exp b/tests/feature_check/inlineasm_rv32.py.exp deleted file mode 100644 index 5eecf09c224..00000000000 --- a/tests/feature_check/inlineasm_rv32.py.exp +++ /dev/null @@ -1 +0,0 @@ -rv32 diff --git a/tests/feature_check/inlineasm_thumb.py b/tests/feature_check/inlineasm_thumb.py deleted file mode 100644 index 321eab0e2f8..00000000000 --- a/tests/feature_check/inlineasm_thumb.py +++ /dev/null @@ -1,9 +0,0 @@ -# check if Thumb inline asm is supported - - -@micropython.asm_thumb -def f(): - nop() - - -print("thumb") diff --git a/tests/feature_check/inlineasm_thumb.py.exp b/tests/feature_check/inlineasm_thumb.py.exp deleted file mode 100644 index bb48e1a2f03..00000000000 --- a/tests/feature_check/inlineasm_thumb.py.exp +++ /dev/null @@ -1 +0,0 @@ -thumb diff --git a/tests/feature_check/inlineasm_thumb2.py b/tests/feature_check/inlineasm_thumb2.py deleted file mode 100644 index bc4c128baf5..00000000000 --- a/tests/feature_check/inlineasm_thumb2.py +++ /dev/null @@ -1,10 +0,0 @@ -# check if Thumb2/ARMV7M instructions are supported - - -@micropython.asm_thumb -def f(): - it(eq) - nop() - - -print("thumb2") diff --git a/tests/feature_check/inlineasm_thumb2.py.exp b/tests/feature_check/inlineasm_thumb2.py.exp deleted file mode 100644 index 05d125af9f6..00000000000 --- a/tests/feature_check/inlineasm_thumb2.py.exp +++ /dev/null @@ -1 +0,0 @@ -thumb2 diff --git a/tests/feature_check/inlineasm_xtensa.py b/tests/feature_check/inlineasm_xtensa.py deleted file mode 100644 index 2a24d39973c..00000000000 --- a/tests/feature_check/inlineasm_xtensa.py +++ /dev/null @@ -1,9 +0,0 @@ -# check if Xtensa inline asm is supported - - -@micropython.asm_xtensa -def f(): - ret_n() - - -print("xtensa") diff --git a/tests/feature_check/inlineasm_xtensa.py.exp b/tests/feature_check/inlineasm_xtensa.py.exp deleted file mode 100644 index 036142c5097..00000000000 --- a/tests/feature_check/inlineasm_xtensa.py.exp +++ /dev/null @@ -1 +0,0 @@ -xtensa diff --git a/tests/feature_check/int_64.py b/tests/feature_check/int_64.py new file mode 100644 index 00000000000..4d053782ca8 --- /dev/null +++ b/tests/feature_check/int_64.py @@ -0,0 +1,2 @@ +# Check whether 64-bit long integers are supported +print(1 << 62) diff --git a/tests/feature_check/int_big.py.exp b/tests/feature_check/int_big.py.exp deleted file mode 100644 index 9dfe3354d59..00000000000 --- a/tests/feature_check/int_big.py.exp +++ /dev/null @@ -1 +0,0 @@ -1000000000000000000000000000000000000000000000 diff --git a/tests/feature_check/io_module.py b/tests/feature_check/io_module.py deleted file mode 100644 index 9094e605316..00000000000 --- a/tests/feature_check/io_module.py +++ /dev/null @@ -1,6 +0,0 @@ -try: - import io - - print("io") -except ImportError: - print("no") diff --git a/tests/feature_check/native_check.py.exp b/tests/feature_check/native_check.py.exp deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/feature_check/repl_emacs_check.py.exp b/tests/feature_check/repl_emacs_check.py.exp deleted file mode 100644 index 82a4e28ee4f..00000000000 --- a/tests/feature_check/repl_emacs_check.py.exp +++ /dev/null @@ -1,7 +0,0 @@ -MicroPython \.\+ version -Use \.\+ ->>> # Check for emacs keys in REPL ->>> t = \.\+ ->>> t == 2 -True ->>> diff --git a/tests/feature_check/repl_words_move_check.py.exp b/tests/feature_check/repl_words_move_check.py.exp deleted file mode 100644 index 82a4e28ee4f..00000000000 --- a/tests/feature_check/repl_words_move_check.py.exp +++ /dev/null @@ -1,7 +0,0 @@ -MicroPython \.\+ version -Use \.\+ ->>> # Check for emacs keys in REPL ->>> t = \.\+ ->>> t == 2 -True ->>> diff --git a/tests/feature_check/reverse_ops.py.exp b/tests/feature_check/reverse_ops.py.exp deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/feature_check/set_check.py.exp b/tests/feature_check/set_check.py.exp deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/feature_check/slice.py.exp b/tests/feature_check/slice.py.exp deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/feature_check/target_info.py b/tests/feature_check/target_info.py index f60f3b31919..5c133f17900 100644 --- a/tests/feature_check/target_info.py +++ b/tests/feature_check/target_info.py @@ -19,5 +19,29 @@ "xtensa", "xtensawin", "rv32imc", -][sys_mpy >> 10] -print(platform, arch) + "rv64imc", +][(sys_mpy >> 10) & 0x0F] +arch_flags = sys_mpy >> 16 +build = getattr(sys.implementation, "_build", "unknown") +thread = getattr(sys.implementation, "_thread", None) + +# Detect how many bits of precision the floating point implementation has. +try: + if float("1.0000001") == float("1.0"): + float_prec = 30 + elif float("1e300") == float("inf"): + float_prec = 32 + else: + float_prec = 64 +except NameError: + float_prec = 0 + +# Detect the error reporting level (based on the length of the raised exception message). +try: + (lambda: 0)(0) +except TypeError as er: + # CIRCUITPY-CHANGE: CircuitPython only exposes .value on StopIteration (py/objexcept.c). + message = er.args[0] if er.args else "" + error_reporting = {0: "none", 27: "terse", 54: "normal", 56: "detailed"}[len(message)] + +print(platform, arch, arch_flags, build, thread, float_prec, len("α") == 1, error_reporting) diff --git a/tests/feature_check/target_info.py.exp b/tests/feature_check/target_info.py.exp deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/feature_check/tstring.py b/tests/feature_check/tstring.py new file mode 100644 index 00000000000..05322b2ae61 --- /dev/null +++ b/tests/feature_check/tstring.py @@ -0,0 +1,5 @@ +# check whether t-strings (PEP-750) are supported + +a = 1 +t = t"a={a}" +print("tstring") diff --git a/tests/float/cmath_fun.py b/tests/float/cmath_fun.py index 39011733b02..0037d7c6559 100644 --- a/tests/float/cmath_fun.py +++ b/tests/float/cmath_fun.py @@ -51,6 +51,9 @@ print("%.5g" % ret) elif type(ret) == tuple: print("%.5g %.5g" % ret) + elif f_name == "exp": + # exp amplifies REPR_C inaccuracies, so we need to check one digit less + print("complex(%.4g, %.4g)" % (real, ret.imag)) else: # some test (eg cmath.sqrt(-0.5)) disagree with CPython with tiny real part real = ret.real diff --git a/tests/float/complex1.py b/tests/float/complex1.py index 0a1d98b9af3..4decea2ac6b 100644 --- a/tests/float/complex1.py +++ b/tests/float/complex1.py @@ -20,7 +20,6 @@ print(complex("nanj")) print(complex("nan-infj")) print(complex(1, 2)) -print(complex(1j, 2j)) # unary ops print(bool(1j)) diff --git a/tests/float/complex1_micropython.py b/tests/float/complex1_micropython.py new file mode 100644 index 00000000000..6b92f593ef2 --- /dev/null +++ b/tests/float/complex1_micropython.py @@ -0,0 +1,6 @@ +# test basic complex number functionality + +# CPython 3.14 marks this constructor as deprecated, but it is still currently +# supported by MicroPython. + +print(complex(1j, 2j)) diff --git a/tests/float/complex1_micropython.py.exp b/tests/float/complex1_micropython.py.exp new file mode 100644 index 00000000000..1defdb822cd --- /dev/null +++ b/tests/float/complex1_micropython.py.exp @@ -0,0 +1 @@ +(-2+1j) diff --git a/tests/float/float_array.py b/tests/float/float_array.py index 3d128da8381..cfff3b220c6 100644 --- a/tests/float/float_array.py +++ b/tests/float/float_array.py @@ -19,4 +19,10 @@ def test(a): test(array("f")) test(array("d")) -print("{:.4f}".format(array("f", bytes(array("I", [0x3DCCCCCC])))[0])) +# hand-crafted floats, including non-standard nan +for float_hex in (0x3DCCCCCC, 0x7F800024, 0x7FC00004): + f = array("f", bytes(array("I", [float_hex])))[0] + if type(f) is float: + print("{:.4e}".format(f)) + else: + print(f) diff --git a/tests/float/float_format.py b/tests/float/float_format.py index 98ed0eb096f..0eb8b232b06 100644 --- a/tests/float/float_format.py +++ b/tests/float/float_format.py @@ -2,14 +2,25 @@ # general rounding for val in (116, 1111, 1234, 5010, 11111): - print("%.0f" % val) - print("%.1f" % val) - print("%.3f" % val) + print("Test on %d / 1000:" % val) + for fmt in ("%.5e", "%.3e", "%.1e", "%.0e", "%.3f", "%.1f", "%.0f", "%.3g", "%.1g", "%.0g"): + print(fmt, fmt % (val / 1000)) + +# make sure round-up to the next unit is handled properly +for val in range(4, 9): + divi = 10**val + print("Test on 99994 / (10 ** %d):" % val) + for fmt in ("%.5e", "%.3e", "%.1e", "%.0e", "%.3f", "%.1f", "%.0f", "%.3g", "%.1g", "%.0g"): + print(fmt, fmt % (99994 / divi)) # make sure rounding is done at the correct precision for prec in range(8): print(("%%.%df" % prec) % 6e-5) +# make sure trailing zeroes are added properly +for prec in range(8): + print(("%%.%df" % prec) % 1e19) + # check certain cases that had a digit value of 10 render as a ":" character print("%.2e" % float("9" * 51 + "e-39")) print("%.2e" % float("9" * 40 + "e-21")) diff --git a/tests/float/float_format_accuracy.py b/tests/float/float_format_accuracy.py new file mode 100644 index 00000000000..f9467f9c05d --- /dev/null +++ b/tests/float/float_format_accuracy.py @@ -0,0 +1,73 @@ +# Test accuracy of `repr` conversions. +# This test also increases code coverage for corner cases. + +try: + import array, math, random +except ImportError: + print("SKIP") + raise SystemExit + +# The largest errors come from seldom used very small numbers, near the +# limit of the representation. So we keep them out of this test to keep +# the max relative error display useful. +if float("1e-100") == 0.0: + # single-precision + float_type = "f" + float_size = 4 + # testing range + min_expo = -96 # i.e. not smaller than 1.0e-29 + # Expected results (given >=50'000 samples): + # - MICROPY_FLTCONV_IMPL_EXACT: 100% exact conversions + # - MICROPY_FLTCONV_IMPL_APPROX: >=98.53% exact conversions, max relative error <= 1.01e-7 + min_success = 0.980 # with only 1200 samples, the success rate is lower + max_rel_err = 1.1e-7 + # REPR_C is typically used with FORMAT_IMPL_BASIC, which has a larger error + is_REPR_C = float("1.0000001") == float("1.0") + if is_REPR_C: # REPR_C + min_success = 0.83 + max_rel_err = 5.75e-07 +else: + # double-precision + float_type = "d" + float_size = 8 + # testing range + min_expo = -845 # i.e. not smaller than 1.0e-254 + # Expected results (given >=200'000 samples): + # - MICROPY_FLTCONV_IMPL_EXACT: 100% exact conversions + # - MICROPY_FLTCONV_IMPL_APPROX: >=99.83% exact conversions, max relative error <= 2.7e-16 + min_success = 0.997 # with only 1200 samples, the success rate is lower + max_rel_err = 2.7e-16 + + +# Deterministic pseudorandom generator. Designed to be uniform +# on mantissa values and exponents, not on the represented number +def pseudo_randfloat(): + rnd_buff = bytearray(float_size) + for _ in range(float_size): + rnd_buff[_] = random.getrandbits(8) + return array.array(float_type, rnd_buff)[0] + + +random.seed(42) +stats = 0 +N = 1200 +max_err = 0 +for _ in range(N): + f = pseudo_randfloat() + while type(f) is not float or math.isinf(f) or math.isnan(f) or math.frexp(f)[1] <= min_expo: + f = pseudo_randfloat() + + str_f = repr(f) + f2 = float(str_f) + if f2 == f: + stats += 1 + else: + error = abs((f2 - f) / f) + if max_err < error: + max_err = error + +print(N, "values converted") +if stats / N >= min_success and max_err <= max_rel_err: + print("float format accuracy OK") +else: + print("FAILED: repr rate=%.3f%% max_err=%.3e" % (100 * stats / N, max_err)) diff --git a/tests/float/float_format_ints.py b/tests/float/float_format_ints.py index df4444166c5..1f221bd5e79 100644 --- a/tests/float/float_format_ints.py +++ b/tests/float/float_format_ints.py @@ -12,14 +12,49 @@ print(title, "with format", f_fmt, "gives", f_fmt.format(f)) print(title, "with format", g_fmt, "gives", g_fmt.format(f)) +# The tests below check border cases involving all mantissa bits. +# In case of REPR_C, where the mantissa is missing two bits, the +# the string representation for such numbers might not always be exactly +# the same but nevertheless be correct, so we must allow a few exceptions. +is_REPR_C = float("1.0000001") == float("1.0") + # 16777215 is 2^24 - 1, the largest integer that can be completely held # in a float32. -print("{:f}".format(16777215)) +val_str = "{:f}".format(16777215) + +# When using REPR_C, 16777215.0 is the same as 16777212.0 or 16777214.4 +# (depending on the implementation of pow() function, the result may differ) +if is_REPR_C and (val_str == "16777212.000000" or val_str == "16777214.400000"): + val_str = "16777215.000000" + +print(val_str) + # 4294967040 = 16777215 * 128 is the largest integer that is exactly # represented by a float32 and that will also fit within a (signed) int32. # The upper bound of our integer-handling code is actually double this, # but that constant might cause trouble on systems using 32 bit ints. -print("{:f}".format(2147483520)) +val_str = "{:f}".format(2147483520) + +# When using FLOAT_IMPL_FLOAT, 2147483520.0 == 2147483500.0 +# Both representations are valid, the second being "simpler" +is_float32 = float("1e300") == float("inf") +if is_float32 and val_str == "2147483500.000000": + val_str = "2147483520.000000" + +# When using REPR_C, 2147483520.0 is the same as 2147483200.0 +# Both representations are valid, the second being "simpler" +if is_REPR_C and val_str == "2147483200.000000": + val_str = "2147483520.000000" + +# When using REPR_C, x86 and clang, 2147483520.0 is the same +# as 2147483100.0, the second being "simple" but rounded differently +# due to x87 extra precision on intermediates. +# Both representations are valid. +if is_REPR_C and val_str == "2147483100.000000": + val_str = "2147483520.000000" + +print(val_str) + # Very large positive integers can be a test for precision and resolution. # This is a weird way to represent 1e38 (largest power of 10 for float32). print("{:.6e}".format(float("9" * 30 + "e8"))) diff --git a/tests/float/float_parse_doubleprec.py b/tests/float/float_parse_doubleprec.py index 81fcadcee88..c1b0b4823b0 100644 --- a/tests/float/float_parse_doubleprec.py +++ b/tests/float/float_parse_doubleprec.py @@ -19,3 +19,9 @@ print(float("1.00000000000000000000e-307")) print(float("10.0000000000000000000e-308")) print(float("100.000000000000000000e-309")) + +# ensure repr() adds an extra digit when needed for accurate parsing +print(float(repr(float("2.0") ** 100)) == float("2.0") ** 100) + +# ensure repr does not add meaningless extra digits (1.234999999999) +print(repr(1.2345)) diff --git a/tests/float/float_struct_e.py b/tests/float/float_struct_e.py index 403fbc5db4c..ba4134f3393 100644 --- a/tests/float/float_struct_e.py +++ b/tests/float/float_struct_e.py @@ -32,7 +32,7 @@ for i in (j, -j): x = struct.pack("", "=", "^"): for fill in ("", " ", "0", "@"): for sign in ("", "+", "-", " "): - # An empty precision defaults to 6, but when uPy is + # An empty precision defaults to 6, but when MicroPython is # configured to use a float, we can only use a # precision of 6 with numbers less than 10 and still # get results that compare to CPython (which uses @@ -164,7 +164,7 @@ def test_fmt(conv, fill, alignment, sign, prefix, width, precision, type, arg): for alignment in ("", "<", ">", "=", "^"): for fill in ("", " ", "0", "@"): for sign in ("", "+", "-", " "): - # An empty precision defaults to 6, but when uPy is + # An empty precision defaults to 6, but when MicroPython is # configured to use a float, we can only use a # precision of 6 with numbers less than 10 and still # get results that compare to CPython (which uses diff --git a/tests/float/string_format_fp30.py b/tests/float/string_format_fp30.py deleted file mode 100644 index 5f0b213daa3..00000000000 --- a/tests/float/string_format_fp30.py +++ /dev/null @@ -1,42 +0,0 @@ -def test(fmt, *args): - print("{:8s}".format(fmt) + ">" + fmt.format(*args) + "<") - - -test("{:10.4}", 123.456) -test("{:10.4e}", 123.456) -test("{:10.4e}", -123.456) -# test("{:10.4f}", 123.456) -# test("{:10.4f}", -123.456) -test("{:10.4g}", 123.456) -test("{:10.4g}", -123.456) -test("{:10.4n}", 123.456) -test("{:e}", 100) -test("{:f}", 200) -test("{:g}", 300) - -test("{:10.4E}", 123.456) -test("{:10.4E}", -123.456) -# test("{:10.4F}", 123.456) -# test("{:10.4F}", -123.456) -test("{:10.4G}", 123.456) -test("{:10.4G}", -123.456) - -test("{:06e}", float("inf")) -test("{:06e}", float("-inf")) -test("{:06e}", float("nan")) - -# The following fails right now -# test("{:10.1}", 0.0) - -print("%.0f" % (1.750000 % 0.08333333333)) -# Below isn't compatible with single-precision float -# print("%.1f" % (1.750000 % 0.08333333333)) -# print("%.2f" % (1.750000 % 0.08333333333)) -# print("%.12f" % (1.750000 % 0.08333333333)) - -# tests for errors in format string - -try: - "{:10.1b}".format(0.0) -except ValueError: - print("ValueError") diff --git a/tests/float/string_format_modulo.py b/tests/float/string_format_modulo.py index 3c206b73935..55314643351 100644 --- a/tests/float/string_format_modulo.py +++ b/tests/float/string_format_modulo.py @@ -6,7 +6,7 @@ print("%u" % 1.0) # these 3 have different behaviour in Python 3.x versions -# uPy raises a TypeError, following Python 3.5 (earlier versions don't) +# MicroPython raises a TypeError, following Python 3.5 (earlier versions don't) # print("%x" % 18.0) # print("%o" % 18.0) # print("%X" % 18.0) diff --git a/tests/float/string_format_modulo3.py b/tests/float/string_format_modulo3.py index f9d9c43cdf4..f8aeeda20f2 100644 --- a/tests/float/string_format_modulo3.py +++ b/tests/float/string_format_modulo3.py @@ -1,3 +1,3 @@ -# uPy and CPython outputs differ for the following +# Test corner cases where MicroPython and CPython outputs used to differ in the past print("%.1g" % -9.9) # round up 'g' with '-' sign print("%.2g" % 99.9) # round up diff --git a/tests/float/string_format_modulo3.py.exp b/tests/float/string_format_modulo3.py.exp deleted file mode 100644 index 71432b34045..00000000000 --- a/tests/float/string_format_modulo3.py.exp +++ /dev/null @@ -1,2 +0,0 @@ --10 -100 diff --git a/tests/float/string_fstring.py b/tests/float/string_fstring.py new file mode 100644 index 00000000000..3b4233559e3 --- /dev/null +++ b/tests/float/string_fstring.py @@ -0,0 +1,7 @@ +# Format specifiers with nested replacement fields +space = 5 +prec = 2 +print(f"{3.14:{space}.{prec}}") + +space_prec = "5.2" +print(f"{3.14:{space_prec}}") diff --git a/tests/frozen/README.md b/tests/frozen/README.md deleted file mode 100644 index bd786d5a3c4..00000000000 --- a/tests/frozen/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This is a .mpy built against the current .mpy version that can be used to test -freezing without a dependency on mpy-cross. diff --git a/tests/import/builtin_ext.py b/tests/import/builtin_ext.py index 9d2344d400d..79ee901ea67 100644 --- a/tests/import/builtin_ext.py +++ b/tests/import/builtin_ext.py @@ -1,3 +1,9 @@ +try: + import uos, utime +except ImportError: + print("SKIP") + raise SystemExit + # Verify that sys is a builtin. import sys diff --git a/tests/import/builtin_import.py b/tests/import/builtin_import.py index 734498d1be4..364b0bae912 100644 --- a/tests/import/builtin_import.py +++ b/tests/import/builtin_import.py @@ -20,3 +20,12 @@ __import__("xyz", None, None, None, -1) except ValueError: print("ValueError") + +# globals is not checked for level=0 +__import__("builtins", "globals") + +# globals must be a dict (or None) for level>0 +try: + __import__("builtins", "globals", None, None, 1) +except TypeError: + print("TypeError") diff --git a/tests/import/import_broken.py b/tests/import/import_broken.py index 3c7cf4a4985..440922157ef 100644 --- a/tests/import/import_broken.py +++ b/tests/import/import_broken.py @@ -1,3 +1,9 @@ +try: + Exception.__class__ +except AttributeError: + print("SKIP") + raise SystemExit + import sys, pkg # Modules we import are usually added to sys.modules. diff --git a/tests/import/import_file.py b/tests/import/import_file.py index 90ec4e41e77..4cf307641c6 100644 --- a/tests/import/import_file.py +++ b/tests/import/import_file.py @@ -1,3 +1,7 @@ +if "__file__" not in globals(): + print("SKIP") + raise SystemExit + import import1b print(import1b.__file__) diff --git a/tests/import/import_override.py b/tests/import/import_override.py index 029ebe54c1f..0144e78cb9f 100644 --- a/tests/import/import_override.py +++ b/tests/import/import_override.py @@ -2,6 +2,10 @@ def custom_import(name, globals, locals, fromlist, level): + # CPython always tries to import _io, so just let that through as-is. + if name == "_io": + return orig_import(name, globals, locals, fromlist, level) + print("import", name, fromlist, level) class M: diff --git a/tests/import/import_override.py.exp b/tests/import/import_override.py.exp deleted file mode 100644 index 365248da6d8..00000000000 --- a/tests/import/import_override.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -import import1b None 0 -456 diff --git a/tests/import/import_override2.py b/tests/import/import_override2.py new file mode 100644 index 00000000000..25aac44fe98 --- /dev/null +++ b/tests/import/import_override2.py @@ -0,0 +1,18 @@ +# test overriding __import__ combined with importing from the filesystem + + +def custom_import(name, globals, locals, fromlist, level): + if level > 0: + print("import", name, fromlist, level) + return orig_import(name, globals, locals, fromlist, level) + + +orig_import = __import__ +try: + __import__("builtins").__import__ = custom_import +except AttributeError: + print("SKIP") + raise SystemExit + +# import calls __import__ behind the scenes +import pkg7.subpkg1.subpkg2.mod3 diff --git a/tests/import/import_pkg7.py.exp b/tests/import/import_pkg7.py.exp deleted file mode 100644 index 8f21a615f6a..00000000000 --- a/tests/import/import_pkg7.py.exp +++ /dev/null @@ -1,8 +0,0 @@ -pkg __name__: pkg7 -pkg __name__: pkg7.subpkg1 -pkg __name__: pkg7.subpkg1.subpkg2 -mod1 -mod2 -mod1.foo -mod2.bar -ImportError diff --git a/tests/import/import_pkg9.py b/tests/import/import_pkg9.py index 4de028494f1..c2e0b618b69 100644 --- a/tests/import/import_pkg9.py +++ b/tests/import/import_pkg9.py @@ -13,4 +13,4 @@ import pkg9.mod2 pkg9.mod1() -print(pkg9.mod2.__name__, type(pkg9.mod2).__name__) +print(pkg9.mod2.__name__, type(pkg9.mod2)) diff --git a/tests/import/import_shared_name.py b/tests/import/import_shared_name.py new file mode 100644 index 00000000000..b76695f671e --- /dev/null +++ b/tests/import/import_shared_name.py @@ -0,0 +1,7 @@ +# https://github.com/adafruit/circuitpython/issues/10614 +# When a directory `shared_name/` (no __init__.py) and a module `shared_name.py` +# share a name, `import shared_name` must pick the .py module per PEP 420 +# precedence: regular package > module > namespace package. +import shared_name + +print("done") diff --git a/tests/import/import_star.py b/tests/import/import_star.py new file mode 100644 index 00000000000..dc34577d772 --- /dev/null +++ b/tests/import/import_star.py @@ -0,0 +1,71 @@ +# test `from package import *` conventions, including __all__ support +# +# This test requires MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES + +try: + next(iter([]), 42) +except TypeError: + # 2-argument version of next() not supported + # we are probably not at MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES + print("SKIP") + raise SystemExit + +# 1. test default visibility +from pkgstar_default import * + +print("visibleFun" in globals()) +print("VisibleClass" in globals()) +print("_hiddenFun" in globals()) +print("_HiddenClass" in globals()) +print(visibleFun()) + +# 2. test explicit visibility as defined by __all__ (as an array) +from pkgstar_all_array import * + +print("publicFun" in globals()) +print("PublicClass" in globals()) +print("unlistedFun" in globals()) +print("UnlistedClass" in globals()) +print("_privateFun" in globals()) +print("_PrivateClass" in globals()) +print(publicFun()) +# test dynamic import as used in asyncio +print("dynamicFun" in globals()) +print(dynamicFun()) + +# 3. test explicit visibility as defined by __all__ (as an tuple) +from pkgstar_all_tuple import * + +print("publicFun2" in globals()) +print("PublicClass2" in globals()) +print("unlistedFun2" in globals()) +print("UnlistedClass2" in globals()) +print(publicFun2()) + +# 4. test reporting of missing entries in __all__ +try: + from pkgstar_all_miss import * + + print("missed detection of incorrect __all__ definition") +except AttributeError as er: + print("AttributeError triggered for bad __all__ definition") + +# 5. test reporting of invalid __all__ definition +try: + from pkgstar_all_inval import * + + print("missed detection of incorrect __all__ definition") +except TypeError as er: + print("TypeError triggered for bad __all__ definition") + +# 6. test when package uses __getattr__ and raises AttributeError for __getattr__("__all__") +from pkgstar_getattr_attr_er import * + +print("publicFun3" in globals()) +print(publicFun3()) + +# 7. test when package uses __getattr__ and raises ValueError for __getattr__("__all__") +try: + from pkgstar_getattr_value_er import * +except ValueError as er: + print("ValueError triggered with args", er.args) diff --git a/tests/import/import_star_error.py b/tests/import/import_star_error.py index 9e1757b6ef5..73d9c863d6f 100644 --- a/tests/import/import_star_error.py +++ b/tests/import/import_star_error.py @@ -1,5 +1,10 @@ # test errors with import * +if not hasattr(object, "__init__"): + # target doesn't have MICROPY_CPYTHON_COMPAT enabled, so doesn't check for "import *" + print("SKIP") + raise SystemExit + # 'import *' is not allowed in function scope try: exec("def foo(): from x import *") diff --git a/tests/import/module_getattr.py.exp b/tests/import/module_getattr.py.exp deleted file mode 100644 index bc59c12aa16..00000000000 --- a/tests/import/module_getattr.py.exp +++ /dev/null @@ -1 +0,0 @@ -False diff --git a/tests/import/pkg7/subpkg1/subpkg2/mod3.py b/tests/import/pkg7/subpkg1/subpkg2/mod3.py index b0f4279fcf5..f7f4c1e65f4 100644 --- a/tests/import/pkg7/subpkg1/subpkg2/mod3.py +++ b/tests/import/pkg7/subpkg1/subpkg2/mod3.py @@ -5,7 +5,9 @@ print(bar) # attempted relative import beyond top-level package +# On older versions of CPython (eg 3.8) this is a ValueError, but on +# newer CPython (eg 3.11) and MicroPython it's an ImportError. try: from .... import mod1 -except ImportError: +except (ImportError, ValueError): print("ImportError") diff --git a/tests/import/pkgstar_all_array/__init__.py b/tests/import/pkgstar_all_array/__init__.py new file mode 100644 index 00000000000..03b012123fe --- /dev/null +++ b/tests/import/pkgstar_all_array/__init__.py @@ -0,0 +1,49 @@ +__all__ = ["publicFun", "PublicClass", "dynamicFun"] + + +# Definitions below should always be imported by a star import +def publicFun(): + return 1 + + +class PublicClass: + def __init__(self): + self._val = 1 + + +# If __all__ support is enabled, definitions below +# should not be imported by a star import +def unlistedFun(): + return 0 + + +class UnlistedClass: + def __init__(self): + self._val = 0 + + +# Definitions below should be not be imported by a star import +# (they start with an underscore, and are not listed in __all__) +def _privateFun(): + return -1 + + +class _PrivateClass: + def __init__(self): + self._val = -1 + + +# Test lazy loaded function, as used by extmod/asyncio: +# Works with a star import only if __all__ support is enabled +_attrs = { + "dynamicFun": "funcs", +} + + +def __getattr__(attr): + mod = _attrs.get(attr, None) + if mod is None: + raise AttributeError(attr) + value = getattr(__import__(mod, globals(), locals(), True, 1), attr) + globals()[attr] = value + return value diff --git a/tests/import/pkgstar_all_array/funcs.py b/tests/import/pkgstar_all_array/funcs.py new file mode 100644 index 00000000000..7540d70f66b --- /dev/null +++ b/tests/import/pkgstar_all_array/funcs.py @@ -0,0 +1,2 @@ +def dynamicFun(): + return 777 diff --git a/tests/import/pkgstar_all_inval/__init__.py b/tests/import/pkgstar_all_inval/__init__.py new file mode 100644 index 00000000000..7022476c19b --- /dev/null +++ b/tests/import/pkgstar_all_inval/__init__.py @@ -0,0 +1 @@ +__all__ = 42 diff --git a/tests/import/pkgstar_all_miss/__init__.py b/tests/import/pkgstar_all_miss/__init__.py new file mode 100644 index 00000000000..f9bbb538072 --- /dev/null +++ b/tests/import/pkgstar_all_miss/__init__.py @@ -0,0 +1,8 @@ +__all__ = ("existingFun", "missingFun") + + +def existingFun(): + return None + + +# missingFun is not defined, should raise an error on import diff --git a/tests/import/pkgstar_all_tuple/__init__.py b/tests/import/pkgstar_all_tuple/__init__.py new file mode 100644 index 00000000000..433ddc8e976 --- /dev/null +++ b/tests/import/pkgstar_all_tuple/__init__.py @@ -0,0 +1,22 @@ +__all__ = ("publicFun2", "PublicClass2") + + +# Definitions below should always be imported by a star import +def publicFun2(): + return 2 + + +class PublicClass2: + def __init__(self): + self._val = 2 + + +# If __all__ support is enabled, definitions below +# should not be imported by a star import +def unlistedFun2(): + return 0 + + +class UnlistedClass2: + def __init__(self): + self._val = 0 diff --git a/tests/import/pkgstar_default/__init__.py b/tests/import/pkgstar_default/__init__.py new file mode 100644 index 00000000000..4947e4ce7f1 --- /dev/null +++ b/tests/import/pkgstar_default/__init__.py @@ -0,0 +1,20 @@ +# When __all__ is undefined, star import should only +# show objects that do not start with an underscore + + +def visibleFun(): + return 42 + + +class VisibleClass: + def __init__(self): + self._val = 42 + + +def _hiddenFun(): + return -1 + + +class _HiddenClass: + def __init__(self): + self._val = -1 diff --git a/tests/import/pkgstar_getattr_attr_er/__init__.py b/tests/import/pkgstar_getattr_attr_er/__init__.py new file mode 100644 index 00000000000..123463d3cd6 --- /dev/null +++ b/tests/import/pkgstar_getattr_attr_er/__init__.py @@ -0,0 +1,15 @@ +_print_msg = True + + +def publicFun3(): + return 3 + + +def __getattr__(attr): + global _print_msg + if _print_msg: + # CPython calls __getattr__("__all__") twice, but MicroPython only once. + # To make the output match, only print the message once. + print("__getattr__", attr) + _print_msg = False + raise AttributeError(attr) diff --git a/tests/import/pkgstar_getattr_value_er/__init__.py b/tests/import/pkgstar_getattr_value_er/__init__.py new file mode 100644 index 00000000000..43d6cdf250f --- /dev/null +++ b/tests/import/pkgstar_getattr_value_er/__init__.py @@ -0,0 +1,3 @@ +def __getattr__(attr): + print("__getattr__", attr) + raise ValueError(attr) diff --git a/tests/import/shared_name.py b/tests/import/shared_name.py new file mode 100644 index 00000000000..0ba98242ed9 --- /dev/null +++ b/tests/import/shared_name.py @@ -0,0 +1 @@ +print("hello shared_name.py") diff --git a/tests/feature_check/io_module.py.exp b/tests/import/shared_name/spritesheet.bmp similarity index 100% rename from tests/feature_check/io_module.py.exp rename to tests/import/shared_name/spritesheet.bmp diff --git a/tests/inlineasm/rv32/asm_ext_zba.py b/tests/inlineasm/rv32/asm_ext_zba.py new file mode 100644 index 00000000000..75f3573c864 --- /dev/null +++ b/tests/inlineasm/rv32/asm_ext_zba.py @@ -0,0 +1,18 @@ +@micropython.asm_rv32 +def test_sh1add(a0, a1): + sh1add(a0, a0, a1) + + +@micropython.asm_rv32 +def test_sh2add(a0, a1): + sh2add(a0, a0, a1) + + +@micropython.asm_rv32 +def test_sh3add(a0, a1): + sh3add(a0, a0, a1) + + +print(hex(test_sh1add(10, 20))) +print(hex(test_sh2add(10, 20))) +print(hex(test_sh3add(10, 20))) diff --git a/tests/inlineasm/rv32/asm_ext_zba.py.exp b/tests/inlineasm/rv32/asm_ext_zba.py.exp new file mode 100644 index 00000000000..5f56bd95642 --- /dev/null +++ b/tests/inlineasm/rv32/asm_ext_zba.py.exp @@ -0,0 +1,3 @@ +0x28 +0x3c +0x64 diff --git a/tests/inlineasm/rv32/asm_ext_zcmp.py b/tests/inlineasm/rv32/asm_ext_zcmp.py new file mode 100644 index 00000000000..619478def7f --- /dev/null +++ b/tests/inlineasm/rv32/asm_ext_zcmp.py @@ -0,0 +1,264 @@ +CMMV_TEMPLATE = """ +@micropython.asm_rv32 +def t(): + cm_mv{}({}, {}) +""" + +CMMV_TESTS = ( + ("s0", "s9", False), + ("s0", "s0", False), + ("s1", "s1", False), + ("s9", "s10", False), + ("s0", "s1", True), + ("s1", "s2", True), + ("s2", "s3", True), + ("s3", "s4", True), +) + + +def cmmv_test(op, tests): + passed = True + for lhs, rhs, success in tests: + try: + exec(CMMV_TEMPLATE.format(op, lhs, rhs)) + if success is False: + print("cm.mv{} {} {} syntax fail".format(op, lhs, rhs)) + passed = False + except SyntaxError: + if success is True: + print("cm.mv{} {} {} syntax fail".format(op, lhs, rhs)) + passed = False + if passed: + print("cm.mv{} syntax pass".format(op)) + + +cmmv_test("a01s", CMMV_TESTS) +cmmv_test("sa01", CMMV_TESTS) + + +CMPP_TEMPLATE = """ +@micropython.asm_rv32 +def t(): + cm_push({}, {}) + cm_pop{}({}, {}) +""" + + +CMPP_TESTS = ( + ("", 0, 0, False), + ("ra", 0, 0, False), + ("ra, s0", 0, 0, False), + ("ra, s0-s1", 0, 0, False), + ("ra, s0-s10", 0, 0, False), + ("{}", 0, 0, False), + ("{t0}", 0, 0, False), + ("{s0}", 0, 0, False), + ("{s0-s1}", 0, 0, False), + ("{ra, s1-s0}", 0, 0, False), + ("{ra, s0-s10}", 0, 0, False), + ("{ra}", 16, -16, False), + ("{ra, s0}", -20, 20, False), + ("{ra}", 0, 0, True), + ("{ra, s0}", 0, 0, True), + ("{ra, s0-s1}", 0, 0, True), + ("{ra, s0-s5}", 0, 0, True), + ("{ra, s0-s11}", 0, 0, True), + ("{ra}", -16, 16, True), + ("{ra, s0}", -16, 16, True), + ("{ra, s0-s1}", -16, 16, True), + ("{ra}", -32, 32, True), + ("{ra, s0}", -32, 32, True), + ("{ra, s0-s1}", -32, 32, True), + ("{ra}", -48, 48, True), + ("{ra, s0}", -48, 48, True), + ("{ra, s0-s1}", -48, 48, True), +) + + +def cmpp_test(op, tests): + passed = True + for lhs, rhs_in, rhs_out, success in tests: + try: + exec(CMPP_TEMPLATE.format(lhs, rhs_in, op, lhs, rhs_out)) + if success is False: + print("cm.push/cm.pop{} {} {} {} syntax fail".format(op, lhs, rhs_in, rhs_out)) + passed = False + except SyntaxError: + if success is True: + print("cm.push/cm.pop{} {} {} {} syntax fail".format(op, lhs, rhs_in, rhs_out)) + passed = False + if passed: + print("cm.push/cm.pop{} syntax pass".format(op)) + + +cmpp_test("", CMPP_TESTS) +cmpp_test("ret", CMPP_TESTS) +cmpp_test("retz", CMPP_TESTS) + + +CM_POP_TEMPLATE = """ +@micropython.asm_rv32 +def t(a0): + mv(t0, s0) + mv(a1, a0) + mv(s0, a0) + cm_push({{ra, s0}}, {}) + add(s0, a1, a1) + cm_pop({{ra, s0}}, {}) + bne(s0, a0, fail) + li(a0, 1) + c_j(end) + label(fail) + li(a0, 0) + label(end) + mv(s0, t0) +print("cm.push/cm.pop {}", t(0x1234) == 1) +""" + +for stack_adj in 0, 16, 32, 48: + exec(CM_POP_TEMPLATE.format(-stack_adj, stack_adj, stack_adj)) + + +CM_POPRET_TEMPLATE = """ +@micropython.asm_rv32 +def t(a0): + mv(t0, ra) + mv(a1, s0) + jal(ra, clobber) + mv(ra, t0) + bne(s0, a1, fail) + li(a0, 1) + c_j(end) + label(fail) + li(a0, 0) + label(end) + c_jr(ra) + label(clobber) + cm_push({{ra, s0}}, {}) + mv(s0, a0) + cm_popret({{ra, s0}}, {}) +print("cm.push/cm.popret {}", t(0x1234) == 1) +""" + +for stack_adj in 0, 16, 32, 48: + exec(CM_POPRET_TEMPLATE.format(-stack_adj, stack_adj, stack_adj)) + + +CM_POPRETZ_TEMPLATE = """ +@micropython.asm_rv32 +def t(a0): + mv(t0, ra) + mv(a1, s0) + jal(ra, clobber) + mv(ra, t0) + bne(a0, zero, fail) + bne(s0, a1, fail) + li(a0, 1) + c_j(end) + label(fail) + li(a0, 0) + label(end) + c_jr(ra) + label(clobber) + cm_push({{ra, s0}}, {}) + mv(s0, a0) + cm_popretz({{ra, s0}}, {}) +print("cm.push/cm.popretz {}", t(0x1234) == 1) +""" + + +for stack_adj in 0, 16, 32, 48: + exec(CM_POPRETZ_TEMPLATE.format(-stack_adj, stack_adj, stack_adj)) + + +REGLIST_TEMPLATE = """ +@micropython.asm_rv32 +def t(): + li(t6, 0) +{save} + cm_push({reglist}, 0) +{trash} + cm_pop({reglist}, 0) +{compare} + c_j(restore) + label(fail) + li(t6, 1) + label(restore) +{restore} + mv(a0, t6) +print("reglist {reglist}", t() == 0) +""" + +REG_MAP = [ + ("ra", "a0", "{ra}"), + ("s0", "a1", "{ra,s0}"), + ("s1", "a2", "{ra,s0-s1}"), + ("s2", "a3", "{ra,s0-s2}"), + ("s3", "a4", "{ra,s0-s3}"), + ("s4", "a5", "{ra,s0-s4}"), + ("s5", "a6", "{ra,s0-s5}"), + ("s6", "a7", "{ra,s0-s6}"), + ("s7", "t0", "{ra,s0-s7}"), + ("s8", "t1", "{ra,s0-s8}"), + ("s9", "t2", "{ra,s0-s9}"), + ("s10", "t3", "{ra,s0-s11}"), + ("s11", "t4", "{ra,s0-s11}"), +] + +for i in range(len(REG_MAP)): + save = "" + trash = "" + compare = "" + restore = "" + _, _, reglist = REG_MAP[i] + for j in range(i + 1): + r1, r2, _ = REG_MAP[j] + save += " mv({}, {})\n".format(r2, r1) + trash += " li({}, {})\n".format(r1, (0x1111_1111 * (j + 1)) & 0xFFFF_FFFF) + compare += " bne({}, {}, fail)\n".format(r2, r1) + restore += " mv({}, {})\n".format(r1, r2) + exec( + REGLIST_TEMPLATE.format( + save=save, trash=trash, compare=compare, restore=restore, reglist=reglist + ) + ) + + +@micropython.asm_rv32 +def test_cm_mva01s(a0, a1): + cm_push({ra, s0 - s11}, 0) + mv(s4, a0) + mv(s5, a1) + li(a0, 0) + li(a1, 0) + cm_mva01s(s4, s5) + bne(a0, s4, fail) + bne(a1, s5, fail) + li(a0, 1) + c_j(end) + label(fail) + li(a0, 0) + label(end) + cm_pop({ra, s0 - s11}, 0) + + +print("cm.mva01s", test_cm_mva01s(100, 200) == 1) + + +@micropython.asm_rv32 +def test_cm_mvsa01(a0, a1): + cm_push({ra, s0 - s11}, 0) + li(s6, 0x12345678) + li(s7, 0x87654321) + cm_mvsa01(s6, s7) + bne(a0, s6, fail) + bne(a1, s7, fail) + li(a0, 1) + c_j(end) + label(fail) + li(a0, 0) + label(end) + cm_pop({ra, s0 - s11}, 0) + + +print("cm.mvsa01", test_cm_mvsa01(100, 200) == 1) diff --git a/tests/inlineasm/rv32/asm_ext_zcmp.py.exp b/tests/inlineasm/rv32/asm_ext_zcmp.py.exp new file mode 100644 index 00000000000..62850dfff4a --- /dev/null +++ b/tests/inlineasm/rv32/asm_ext_zcmp.py.exp @@ -0,0 +1,32 @@ +cm.mva01s syntax pass +cm.mvsa01 syntax pass +cm.push/cm.pop syntax pass +cm.push/cm.popret syntax pass +cm.push/cm.popretz syntax pass +cm.push/cm.pop 0 True +cm.push/cm.pop 16 True +cm.push/cm.pop 32 True +cm.push/cm.pop 48 True +cm.push/cm.popret 0 True +cm.push/cm.popret 16 True +cm.push/cm.popret 32 True +cm.push/cm.popret 48 True +cm.push/cm.popretz 0 True +cm.push/cm.popretz 16 True +cm.push/cm.popretz 32 True +cm.push/cm.popretz 48 True +reglist {ra} True +reglist {ra,s0} True +reglist {ra,s0-s1} True +reglist {ra,s0-s2} True +reglist {ra,s0-s3} True +reglist {ra,s0-s4} True +reglist {ra,s0-s5} True +reglist {ra,s0-s6} True +reglist {ra,s0-s7} True +reglist {ra,s0-s8} True +reglist {ra,s0-s9} True +reglist {ra,s0-s11} True +reglist {ra,s0-s11} True +cm.mva01s True +cm.mvsa01 True diff --git a/tests/inlineasm/rv32/asmzba.py b/tests/inlineasm/rv32/asmzba.py new file mode 100644 index 00000000000..75f3573c864 --- /dev/null +++ b/tests/inlineasm/rv32/asmzba.py @@ -0,0 +1,18 @@ +@micropython.asm_rv32 +def test_sh1add(a0, a1): + sh1add(a0, a0, a1) + + +@micropython.asm_rv32 +def test_sh2add(a0, a1): + sh2add(a0, a0, a1) + + +@micropython.asm_rv32 +def test_sh3add(a0, a1): + sh3add(a0, a0, a1) + + +print(hex(test_sh1add(10, 20))) +print(hex(test_sh2add(10, 20))) +print(hex(test_sh3add(10, 20))) diff --git a/tests/inlineasm/rv32/asmzba.py.exp b/tests/inlineasm/rv32/asmzba.py.exp new file mode 100644 index 00000000000..5f56bd95642 --- /dev/null +++ b/tests/inlineasm/rv32/asmzba.py.exp @@ -0,0 +1,3 @@ +0x28 +0x3c +0x64 diff --git a/tests/inlineasm/thumb/asm_thumb2_bcc.py b/tests/inlineasm/thumb/asm_thumb2_bcc.py new file mode 100644 index 00000000000..bf0ee0a48fe --- /dev/null +++ b/tests/inlineasm/thumb/asm_thumb2_bcc.py @@ -0,0 +1,65 @@ +# test bcc instructions, narrow and wide versions + + +RESULT = [] + + +TEMPLATE = """ +@micropython.asm_thumb +def t(r0): + mov(r1, r0) + + mov(r0, 10) + cmp(r1, 1) + b{}(next1) + + b(end) + + label(next1) + + mov(r0, 20) + cmp(r1, 2) + b{}_n(next2) + + b(end) + + label(next2) + mov(r0, 30) + cmp(r1, 3) + b{}_w(next3) + + b(end) + + label(next3) + mov(r0, 0) + + label(end) +""" + +try: + for code in ( + "eq", + "ne", + "cs", + "cc", + "mi", + "pl", + "vs", + "vc", + "hi", + "ls", + "ge", + "lt", + "gt", + "le", + ): + exec(TEMPLATE.format(code, code, code)) + RESULT.append("B" + code.upper()) + for i in range(4): + RESULT.append(t(i)) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + +for line in RESULT: + print(line) diff --git a/tests/inlineasm/thumb/asm_thumb2_bcc.py.exp b/tests/inlineasm/thumb/asm_thumb2_bcc.py.exp new file mode 100644 index 00000000000..06fd057ae52 --- /dev/null +++ b/tests/inlineasm/thumb/asm_thumb2_bcc.py.exp @@ -0,0 +1,70 @@ +BEQ +10 +20 +10 +10 +BNE +0 +10 +20 +30 +BCS +10 +20 +30 +0 +BCC +0 +10 +10 +10 +BMI +0 +10 +10 +10 +BPL +10 +20 +30 +0 +BVS +10 +10 +10 +10 +BVC +0 +0 +0 +0 +BHI +10 +10 +20 +30 +BLS +0 +0 +10 +10 +BGE +10 +20 +30 +0 +BLT +0 +10 +10 +10 +BGT +10 +10 +20 +30 +BLE +0 +0 +10 +10 diff --git a/tests/inlineasm/thumb/asmbitops.py b/tests/inlineasm/thumb/asm_thumb2_bitops.py similarity index 100% rename from tests/inlineasm/thumb/asmbitops.py rename to tests/inlineasm/thumb/asm_thumb2_bitops.py diff --git a/tests/inlineasm/thumb/asmbitops.py.exp b/tests/inlineasm/thumb/asm_thumb2_bitops.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmbitops.py.exp rename to tests/inlineasm/thumb/asm_thumb2_bitops.py.exp diff --git a/tests/inlineasm/thumb/asmconst.py b/tests/inlineasm/thumb/asm_thumb2_const.py similarity index 100% rename from tests/inlineasm/thumb/asmconst.py rename to tests/inlineasm/thumb/asm_thumb2_const.py diff --git a/tests/inlineasm/thumb/asmconst.py.exp b/tests/inlineasm/thumb/asm_thumb2_const.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmconst.py.exp rename to tests/inlineasm/thumb/asm_thumb2_const.py.exp diff --git a/tests/inlineasm/thumb/asmdiv.py b/tests/inlineasm/thumb/asm_thumb2_div.py similarity index 100% rename from tests/inlineasm/thumb/asmdiv.py rename to tests/inlineasm/thumb/asm_thumb2_div.py diff --git a/tests/inlineasm/thumb/asmdiv.py.exp b/tests/inlineasm/thumb/asm_thumb2_div.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmdiv.py.exp rename to tests/inlineasm/thumb/asm_thumb2_div.py.exp diff --git a/tests/inlineasm/thumb/asmit.py b/tests/inlineasm/thumb/asm_thumb2_it.py similarity index 100% rename from tests/inlineasm/thumb/asmit.py rename to tests/inlineasm/thumb/asm_thumb2_it.py diff --git a/tests/inlineasm/thumb/asmit.py.exp b/tests/inlineasm/thumb/asm_thumb2_it.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmit.py.exp rename to tests/inlineasm/thumb/asm_thumb2_it.py.exp diff --git a/tests/inlineasm/thumb/asmspecialregs.py b/tests/inlineasm/thumb/asm_thumb2_specialregs.py similarity index 100% rename from tests/inlineasm/thumb/asmspecialregs.py rename to tests/inlineasm/thumb/asm_thumb2_specialregs.py diff --git a/tests/inlineasm/thumb/asmspecialregs.py.exp b/tests/inlineasm/thumb/asm_thumb2_specialregs.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmspecialregs.py.exp rename to tests/inlineasm/thumb/asm_thumb2_specialregs.py.exp diff --git a/tests/inlineasm/thumb/asmfpaddsub.py b/tests/inlineasm/thumb/asm_vfp_addsub.py similarity index 100% rename from tests/inlineasm/thumb/asmfpaddsub.py rename to tests/inlineasm/thumb/asm_vfp_addsub.py diff --git a/tests/inlineasm/thumb/asmfpaddsub.py.exp b/tests/inlineasm/thumb/asm_vfp_addsub.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmfpaddsub.py.exp rename to tests/inlineasm/thumb/asm_vfp_addsub.py.exp diff --git a/tests/inlineasm/thumb/asmfpcmp.py b/tests/inlineasm/thumb/asm_vfp_cmp.py similarity index 100% rename from tests/inlineasm/thumb/asmfpcmp.py rename to tests/inlineasm/thumb/asm_vfp_cmp.py diff --git a/tests/inlineasm/thumb/asmfpcmp.py.exp b/tests/inlineasm/thumb/asm_vfp_cmp.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmfpcmp.py.exp rename to tests/inlineasm/thumb/asm_vfp_cmp.py.exp diff --git a/tests/inlineasm/thumb/asmfpldrstr.py b/tests/inlineasm/thumb/asm_vfp_ldrstr.py similarity index 100% rename from tests/inlineasm/thumb/asmfpldrstr.py rename to tests/inlineasm/thumb/asm_vfp_ldrstr.py diff --git a/tests/inlineasm/thumb/asmfpldrstr.py.exp b/tests/inlineasm/thumb/asm_vfp_ldrstr.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmfpldrstr.py.exp rename to tests/inlineasm/thumb/asm_vfp_ldrstr.py.exp diff --git a/tests/inlineasm/thumb/asmfpmuldiv.py b/tests/inlineasm/thumb/asm_vfp_muldiv.py similarity index 100% rename from tests/inlineasm/thumb/asmfpmuldiv.py rename to tests/inlineasm/thumb/asm_vfp_muldiv.py diff --git a/tests/inlineasm/thumb/asmfpmuldiv.py.exp b/tests/inlineasm/thumb/asm_vfp_muldiv.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmfpmuldiv.py.exp rename to tests/inlineasm/thumb/asm_vfp_muldiv.py.exp diff --git a/tests/inlineasm/thumb/asmfpsqrt.py b/tests/inlineasm/thumb/asm_vfp_sqrt.py similarity index 100% rename from tests/inlineasm/thumb/asmfpsqrt.py rename to tests/inlineasm/thumb/asm_vfp_sqrt.py diff --git a/tests/inlineasm/thumb/asmfpsqrt.py.exp b/tests/inlineasm/thumb/asm_vfp_sqrt.py.exp similarity index 100% rename from tests/inlineasm/thumb/asmfpsqrt.py.exp rename to tests/inlineasm/thumb/asm_vfp_sqrt.py.exp diff --git a/tests/inlineasm/thumb/asmbcc.py b/tests/inlineasm/thumb/asmbcc.py deleted file mode 100644 index 08967d48c74..00000000000 --- a/tests/inlineasm/thumb/asmbcc.py +++ /dev/null @@ -1,29 +0,0 @@ -# test bcc instructions -# at the moment only tests beq, narrow and wide versions - - -@micropython.asm_thumb -def f(r0): - mov(r1, r0) - - mov(r0, 10) - cmp(r1, 1) - beq(end) - - mov(r0, 20) - cmp(r1, 2) - beq_n(end) - - mov(r0, 30) - cmp(r1, 3) - beq_w(end) - - mov(r0, 0) - - label(end) - - -print(f(0)) -print(f(1)) -print(f(2)) -print(f(3)) diff --git a/tests/inlineasm/thumb/asmbcc.py.exp b/tests/inlineasm/thumb/asmbcc.py.exp deleted file mode 100644 index 39da7d1a99e..00000000000 --- a/tests/inlineasm/thumb/asmbcc.py.exp +++ /dev/null @@ -1,4 +0,0 @@ -0 -10 -20 -30 diff --git a/tests/inlineasm/thumb/asmerrors.py b/tests/inlineasm/thumb/asmerrors.py new file mode 100644 index 00000000000..a26f9322540 --- /dev/null +++ b/tests/inlineasm/thumb/asmerrors.py @@ -0,0 +1,4 @@ +try: + exec("@micropython.asm_thumb\ndef l():\n a = di(a2, a2, -1)") +except SyntaxError as e: + print(e) diff --git a/tests/inlineasm/thumb/asmerrors.py.exp b/tests/inlineasm/thumb/asmerrors.py.exp new file mode 100644 index 00000000000..7590f171e51 --- /dev/null +++ b/tests/inlineasm/thumb/asmerrors.py.exp @@ -0,0 +1 @@ +expecting an assembler instruction diff --git a/tests/inlineasm/xtensa/asmargs.py b/tests/inlineasm/xtensa/asmargs.py new file mode 100644 index 00000000000..2bfccfcc69b --- /dev/null +++ b/tests/inlineasm/xtensa/asmargs.py @@ -0,0 +1,44 @@ +# test passing arguments + + +@micropython.asm_xtensa +def arg0(): + movi(a2, 1) + + +print(arg0()) + + +@micropython.asm_xtensa +def arg1(a2): + addi(a2, a2, 1) + + +print(arg1(1)) + + +@micropython.asm_xtensa +def arg2(a2, a3): + add(a2, a2, a3) + + +print(arg2(1, 2)) + + +@micropython.asm_xtensa +def arg3(a2, a3, a4): + add(a2, a2, a3) + add(a2, a2, a4) + + +print(arg3(1, 2, 3)) + + +@micropython.asm_xtensa +def arg4(a2, a3, a4, a5): + add(a2, a2, a3) + add(a2, a2, a4) + add(a2, a2, a5) + + +print(arg4(1, 2, 3, 4)) diff --git a/tests/inlineasm/xtensa/asmargs.py.exp b/tests/inlineasm/xtensa/asmargs.py.exp new file mode 100644 index 00000000000..e33a6964f46 --- /dev/null +++ b/tests/inlineasm/xtensa/asmargs.py.exp @@ -0,0 +1,5 @@ +1 +2 +3 +6 +10 diff --git a/tests/inlineasm/xtensa/asmarith.py b/tests/inlineasm/xtensa/asmarith.py new file mode 100644 index 00000000000..1c0934eb7a6 --- /dev/null +++ b/tests/inlineasm/xtensa/asmarith.py @@ -0,0 +1,119 @@ +@micropython.asm_xtensa +def f1(a2): + abs_(a2, a2) + + +for value in (10, -10, 0): + print(f1(value)) + + +ADDMI_TEMPLATE = """ +@micropython.asm_xtensa +def f1(a2) -> int: + addmi(a2, a2, {}) +print(f1(0)) +""" + +for value in (-32768, -32767, 32512, 32513, 0): + try: + exec(ADDMI_TEMPLATE.format(value)) + except SyntaxError as error: + print(error) + + +@micropython.asm_xtensa +def a2(a2, a3) -> int: + addx2(a2, a2, a3) + + +@micropython.asm_xtensa +def a4(a2, a3) -> int: + addx4(a2, a2, a3) + + +@micropython.asm_xtensa +def a8(a2, a3) -> int: + addx8(a2, a2, a3) + + +@micropython.asm_xtensa +def s2(a2, a3) -> int: + subx2(a2, a2, a3) + + +@micropython.asm_xtensa +def s4(a2, a3) -> int: + subx4(a2, a2, a3) + + +@micropython.asm_xtensa +def s8(a2, a3) -> int: + subx8(a2, a2, a3) + + +for first, second in ((100, 100), (-100, 100), (-100, -100), (100, -100)): + print("a2", a2(first, second)) + print("a4", a4(first, second)) + print("a8", a8(first, second)) + print("s2", s2(first, second)) + print("s4", s4(first, second)) + print("s8", s8(first, second)) + + +@micropython.asm_xtensa +def f5(a2) -> int: + neg(a2, a2) + + +for value in (0, -100, 100): + print(f5(value)) + + +@micropython.asm_xtensa +def f6(): + movi(a2, 0x100) + movi(a3, 1) + add(a2, a2, a3) + addi(a2, a2, 1) + addi(a2, a2, -2) + sub(a2, a2, a3) + + +print(hex(f6())) + + +@micropython.asm_xtensa +def f7(): + movi(a2, 0x10FF) + movi(a3, 1) + and_(a4, a2, a3) + or_(a4, a4, a3) + movi(a3, 0x200) + xor(a2, a4, a3) + + +print(hex(f7())) + + +@micropython.asm_xtensa +def f8(a2, a3): + add_n(a2, a2, a3) + + +print(f8(100, 200)) + + +@micropython.asm_xtensa +def f9(a2): + addi_n(a2, a2, 1) + + +print(f9(100)) + + +@micropython.asm_xtensa +def f10(a2, a3) -> uint: + mull(a2, a2, a3) + + +print(hex(f10(0xC0000000, 2))) diff --git a/tests/inlineasm/xtensa/asmarith.py.exp b/tests/inlineasm/xtensa/asmarith.py.exp new file mode 100644 index 00000000000..7aba46a27d9 --- /dev/null +++ b/tests/inlineasm/xtensa/asmarith.py.exp @@ -0,0 +1,40 @@ +10 +10 +0 +-32768 +-32767 is not a multiple of 256 +32512 +'addmi' integer 32513 isn't within range -32768..32512 +0 +a2 300 +a4 500 +a8 900 +s2 100 +s4 300 +s8 700 +a2 -100 +a4 -300 +a8 -700 +s2 -300 +s4 -500 +s8 -900 +a2 -300 +a4 -500 +a8 -900 +s2 -100 +s4 -300 +s8 -700 +a2 100 +a4 300 +a8 700 +s2 300 +s4 500 +s8 900 +0 +100 +-100 +0xff +0x201 +300 +101 +0x80000000 diff --git a/tests/inlineasm/xtensa/asmbranch.py b/tests/inlineasm/xtensa/asmbranch.py new file mode 100644 index 00000000000..22bcd5a7c71 --- /dev/null +++ b/tests/inlineasm/xtensa/asmbranch.py @@ -0,0 +1,299 @@ +# test branch instructions + + +@micropython.asm_xtensa +def tball(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + ball(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tball(0xFFFFFFFF, 0xFFFFFFFF)) +print(tball(0xFFFEFFFF, 0xFFFFFFFF)) +print(tball(0x00000000, 0xFFFFFFFF)) +print(tball(0xFFFFFFFF, 0x01010101)) + + +@micropython.asm_xtensa +def tbany(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bany(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbany(0xFFFFFFFF, 0xFFFFFFFF)) +print(tbany(0xFFFEFFFF, 0xFFFFFFFF)) +print(tbany(0x00000000, 0xFFFFFFFF)) +print(tbany(0xFFFFFFFF, 0x01010101)) + + +@micropython.asm_xtensa +def tbbc(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bbc(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbbc(0xFFFFFFFF, 4)) +print(tbbc(0xFFFEFFFF, 16)) +print(tbbc(0x00000000, 1)) + + +BBCI_TEMPLATE = """ +@micropython.asm_xtensa +def tbbci(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bbci(a3, {}, end) + movi(a2, -1) + label(end) + +print(tbbci({})) +""" + + +for value, bit in ((0xFFFFFFFF, 4), (0xFFFEFFFF, 16), (0x00000000, 1)): + try: + exec(BBCI_TEMPLATE.format(bit, value)) + except SyntaxError as error: + print(error) + + +@micropython.asm_xtensa +def tbbs(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bbs(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbbs(0x00000000, 4)) +print(tbbs(0x00010000, 16)) +print(tbbs(0xFFFFFFFF, 1)) + + +BBSI_TEMPLATE = """ +@micropython.asm_xtensa +def tbbsi(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bbsi(a3, {}, end) + movi(a2, -1) + label(end) + +print(tbbsi({})) +""" + + +for value, bit in ((0x00000000, 4), (0x00010000, 16), (0xFFFFFFFF, 1)): + try: + exec(BBSI_TEMPLATE.format(bit, value)) + except SyntaxError as error: + print(error) + + +@micropython.asm_xtensa +def tbeq(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + beq(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbeq(0x00000000, 0x00000000)) +print(tbeq(0x00010000, 0x00000000)) +print(tbeq(0xFFFFFFFF, 0xFFFFFFFF)) + + +@micropython.asm_xtensa +def tbeqz(a2) -> int: + mov(a3, a2) + movi(a2, 0) + beqz(a3, end) + movi(a2, -1) + label(end) + + +print(tbeqz(0)) +print(tbeqz(0x12345678)) +print(tbeqz(-1)) + + +@micropython.asm_xtensa +def tbge(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bge(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbge(0x00000000, 0x00000000)) +print(tbge(0x00010000, 0x00000000)) +print(tbge(0xF0000000, 0xFFFFFFFF)) + + +@micropython.asm_xtensa +def tbgeu(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bgeu(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbgeu(0x00000000, 0x00000000)) +print(tbgeu(0x00010000, 0x00000000)) +print(tbgeu(0xF0000000, 0xFFFFFFFF)) +print(tbgeu(0xFFFFFFFF, 0xF0000000)) + + +@micropython.asm_xtensa +def tbgez(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bgez(a3, end) + movi(a2, -1) + label(end) + + +print(tbgez(0)) +print(tbgez(0x12345678)) +print(tbgez(-1)) + + +@micropython.asm_xtensa +def tblt(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + blt(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tblt(0x00000000, 0x00000000)) +print(tblt(0x00010000, 0x00000000)) +print(tblt(0xF0000000, 0xFFFFFFFF)) + + +@micropython.asm_xtensa +def tbltu(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bltu(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbltu(0x00000000, 0x00000000)) +print(tbltu(0x00010000, 0x00000000)) +print(tbltu(0xF0000000, 0xFFFFFFFF)) +print(tbltu(0xFFFFFFFF, 0xF0000000)) + + +@micropython.asm_xtensa +def tbltz(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bltz(a3, end) + movi(a2, -1) + label(end) + + +print(tbltz(0)) +print(tbltz(0x12345678)) +print(tbltz(-1)) + + +@micropython.asm_xtensa +def tbnall(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bnall(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbnall(0xFFFFFFFF, 0xFFFFFFFF)) +print(tbnall(0xFFFEFFFF, 0xFFFFFFFF)) +print(tbnall(0x00000000, 0xFFFFFFFF)) +print(tbnall(0xFFFFFFFF, 0x01010101)) + + +@micropython.asm_xtensa +def tbne(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bne(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbne(0x00000000, 0x00000000)) +print(tbne(0x00010000, 0x00000000)) +print(tbne(0xFFFFFFFF, 0xFFFFFFFF)) + + +@micropython.asm_xtensa +def tbnez(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bnez(a3, end) + movi(a2, -1) + label(end) + + +print(tbnez(0)) +print(tbnez(0x12345678)) +print(tbnez(-1)) + + +@micropython.asm_xtensa +def tbnone(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bnone(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbnone(0xFFFFFFFF, 0xFFFFFFFF)) +print(tbnone(0xFFFEFFFF, 0xFFFFFFFF)) +print(tbnone(0x00000000, 0xFFFFFFFF)) +print(tbnone(0x10101010, 0x01010101)) + + +@micropython.asm_xtensa +def tbeqz_n(a2) -> int: + mov(a3, a2) + movi(a2, 0) + beqz_n(a3, end) + movi(a2, -1) + label(end) + + +print(tbeqz_n(0)) +print(tbeqz_n(0x12345678)) +print(tbeqz_n(-1)) + + +@micropython.asm_xtensa +def tbnez_n(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bnez(a3, end) + movi(a2, -1) + label(end) + + +print(tbnez_n(0)) +print(tbnez_n(0x12345678)) +print(tbnez_n(-1)) diff --git a/tests/inlineasm/xtensa/asmbranch.py.exp b/tests/inlineasm/xtensa/asmbranch.py.exp new file mode 100644 index 00000000000..319a4b435ef --- /dev/null +++ b/tests/inlineasm/xtensa/asmbranch.py.exp @@ -0,0 +1,66 @@ +0 +-1 +-1 +0 +0 +0 +-1 +0 +-1 +0 +0 +-1 +0 +0 +-1 +0 +0 +-1 +0 +0 +0 +-1 +0 +0 +-1 +-1 +0 +0 +-1 +0 +0 +-1 +0 +0 +0 +-1 +-1 +-1 +0 +-1 +-1 +0 +-1 +-1 +-1 +0 +-1 +0 +0 +-1 +-1 +0 +-1 +-1 +0 +0 +-1 +-1 +0 +0 +0 +-1 +-1 +-1 +0 +0 diff --git a/tests/inlineasm/xtensa/asmjump.py b/tests/inlineasm/xtensa/asmjump.py new file mode 100644 index 00000000000..f41c9482319 --- /dev/null +++ b/tests/inlineasm/xtensa/asmjump.py @@ -0,0 +1,26 @@ +@micropython.asm_xtensa +def jump() -> int: + movi(a2, 0) + j(NEXT) + addi(a2, a2, 1) + j(DONE) + label(NEXT) + addi(a2, a2, 2) + label(DONE) + + +print(jump()) + + +@micropython.asm_xtensa +def jumpx() -> int: + call0(ENTRY) + label(ENTRY) + movi(a2, 0) + addi(a3, a0, 12) + jx(a3) + movi(a2, 1) + movi(a2, 2) + + +print(jumpx()) diff --git a/tests/inlineasm/xtensa/asmjump.py.exp b/tests/inlineasm/xtensa/asmjump.py.exp new file mode 100644 index 00000000000..51993f072d5 --- /dev/null +++ b/tests/inlineasm/xtensa/asmjump.py.exp @@ -0,0 +1,2 @@ +2 +2 diff --git a/tests/inlineasm/xtensa/asmloadstore.py b/tests/inlineasm/xtensa/asmloadstore.py new file mode 100644 index 00000000000..85f1f8a561b --- /dev/null +++ b/tests/inlineasm/xtensa/asmloadstore.py @@ -0,0 +1,101 @@ +import array + +# On the ESP8266 the generated code gets put into the IRAM segment, which is +# only word-addressable. Therefore, to test byte and halfword load/store +# opcodes some memory must be reserved in the DRAM segment. This also happens +# to work on the ESP32 too. + +BYTE_DATA = array.array("B", (0x11, 0x22, 0x33, 0x44)) +WORD_DATA = array.array("h", (100, 200, -100, -200)) +DWORD_DATA = array.array("i", (100_000, -200_000, 300_000, -400_000)) + + +@micropython.asm_xtensa +def tl32r() -> int: + nop() + j(CODE) + align(4) + label(DATA) + data(1, 1, 2, 3, 4, 5, 6, 7) + align(4) + label(CODE) + nop_n() + nop_n() + l32r(a2, DATA) + + +print(hex(tl32r())) + + +@micropython.asm_xtensa +def tl32i() -> uint: + call0(ENTRY) + align(4) + label(ENTRY) + l32i(a2, a0, 0) + nop() + + +print(hex(tl32i())) + + +@micropython.asm_xtensa +def tl8ui(a2) -> uint: + mov(a3, a2) + l8ui(a2, a3, 1) + + +print(hex(tl8ui(BYTE_DATA))) + + +@micropython.asm_xtensa +def tl16ui(a2) -> uint: + mov(a3, a2) + l16ui(a2, a3, 2) + + +print(tl16ui(WORD_DATA)) + + +@micropython.asm_xtensa +def tl16si(a2) -> int: + mov(a3, a2) + l16si(a2, a3, 6) + + +print(tl16si(WORD_DATA)) + + +@micropython.asm_xtensa +def ts8i(a2, a3): + s8i(a3, a2, 1) + + +ts8i(BYTE_DATA, 0xFF) +print(BYTE_DATA) + + +@micropython.asm_xtensa +def ts16i(a2, a3): + s16i(a3, a2, 2) + + +ts16i(WORD_DATA, -123) +print(WORD_DATA) + + +@micropython.asm_xtensa +def ts32i(a2, a3) -> uint: + s32i(a3, a2, 4) + + +ts32i(DWORD_DATA, -123456) +print(DWORD_DATA) + + +@micropython.asm_xtensa +def tl32i_n(a2) -> uint: + l32i_n(a2, a2, 8) + + +print(tl32i_n(DWORD_DATA)) diff --git a/tests/inlineasm/xtensa/asmloadstore.py.exp b/tests/inlineasm/xtensa/asmloadstore.py.exp new file mode 100644 index 00000000000..ec453a1cad6 --- /dev/null +++ b/tests/inlineasm/xtensa/asmloadstore.py.exp @@ -0,0 +1,9 @@ +0x4030201 +0xf0002022 +0x22 +200 +-200 +array('B', [17, 255, 51, 68]) +array('h', [100, -123, -100, -200]) +array('i', [100000, -123456, 300000, -400000]) +300000 diff --git a/tests/inlineasm/xtensa/asmmisc.py b/tests/inlineasm/xtensa/asmmisc.py new file mode 100644 index 00000000000..271ab836625 --- /dev/null +++ b/tests/inlineasm/xtensa/asmmisc.py @@ -0,0 +1,25 @@ +@micropython.asm_xtensa +def tnop(a2, a3, a4, a5): + nop() + + +out2 = tnop(0x100, 0x200, 0x300, 0x400) +print(out2 == 0x100) + + +@micropython.asm_xtensa +def tnop_n(a2, a3, a4, a5): + nop_n() + + +out2 = tnop_n(0x100, 0x200, 0x300, 0x400) +print(out2 == 0x100) + + +@micropython.asm_xtensa +def tmov_n(a2, a3): + mov_n(a4, a3) + add(a2, a4, a3) + + +print(tmov_n(0, 1)) diff --git a/tests/inlineasm/xtensa/asmmisc.py.exp b/tests/inlineasm/xtensa/asmmisc.py.exp new file mode 100644 index 00000000000..eefaa35daf0 --- /dev/null +++ b/tests/inlineasm/xtensa/asmmisc.py.exp @@ -0,0 +1,3 @@ +True +True +2 diff --git a/tests/inlineasm/xtensa/asmshift.py b/tests/inlineasm/xtensa/asmshift.py new file mode 100644 index 00000000000..271ca1ccd49 --- /dev/null +++ b/tests/inlineasm/xtensa/asmshift.py @@ -0,0 +1,137 @@ +@micropython.asm_xtensa +def lsl1(a2): + slli(a2, a2, 1) + + +print(hex(lsl1(0x123))) + + +@micropython.asm_xtensa +def lsl23(a2): + slli(a2, a2, 23) + + +print(hex(lsl23(1))) + + +@micropython.asm_xtensa +def lsr1(a2): + srli(a2, a2, 1) + + +print(hex(lsr1(0x123))) + + +@micropython.asm_xtensa +def lsr15(a2): + srli(a2, a2, 15) + + +print(hex(lsr15(0x80000000))) + + +@micropython.asm_xtensa +def asr1(a2): + srai(a2, a2, 1) + + +print(hex(asr1(0x123))) + + +@micropython.asm_xtensa +def asr31(a2): + srai(a2, a2, 31) + + +print(hex(asr31(0x80000000))) + + +@micropython.asm_xtensa +def lsl1r(a2): + movi(a3, 1) + ssl(a3) + sll(a2, a2) + + +print(hex(lsl1r(0x123))) + + +@micropython.asm_xtensa +def lsr1r(a2): + movi(a3, 1) + ssr(a3) + srl(a2, a2) + + +print(hex(lsr1r(0x123))) + + +@micropython.asm_xtensa +def asr1r(a2): + movi(a3, 1) + ssr(a3) + sra(a2, a2) + + +print(hex(asr1r(0x123))) + + +@micropython.asm_xtensa +def sll9(a2): + ssai(9) + sll(a2, a2) + + +print(hex(sll9(1))) + + +@micropython.asm_xtensa +def srlr(a2, a3): + ssa8l(a3) + srl(a2, a2) + + +print(hex(srlr(0x12340000, 2))) + + +@micropython.asm_xtensa +def sllr(a2, a3): + ssa8b(a3) + sll(a2, a2) + + +print(hex(sllr(0x1234, 2))) + + +@micropython.asm_xtensa +def srcr(a2, a3, a4): + ssr(a4) + src(a2, a2, a3) + + +print(hex(srcr(0x00000001, 0x80000000, 2))) + + +@micropython.asm_xtensa +def srai24(a2): + srai(a2, a2, 24) + + +print(hex(srai24(0x12345678))) + + +@micropython.asm_xtensa +def nsar(a2, a3): + nsa(a2, a3) + + +print(nsar(0x12345678, 0)) +print(nsar(0x12345678, -1)) + + +@micropython.asm_xtensa +def nsaur(a2, a3): + nsau(a2, a3) + + +print(nsaur(0x12345678, 0)) diff --git a/tests/inlineasm/xtensa/asmshift.py.exp b/tests/inlineasm/xtensa/asmshift.py.exp new file mode 100644 index 00000000000..3e2bb3b4aef --- /dev/null +++ b/tests/inlineasm/xtensa/asmshift.py.exp @@ -0,0 +1,17 @@ +0x246 +0x800000 +0x91 +0x10000 +0x91 +-0x1 +0x246 +0x91 +0x91 +0x800000 +0x1234 +0x12340000 +0x60000000 +0x12 +31 +31 +32 diff --git a/tests/internal_bench/class_create-0-empty.py b/tests/internal_bench/class_create-0-empty.py new file mode 100644 index 00000000000..1fd8ccd9257 --- /dev/null +++ b/tests/internal_bench/class_create-0-empty.py @@ -0,0 +1,11 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-1-slots.py b/tests/internal_bench/class_create-1-slots.py new file mode 100644 index 00000000000..9b3e4b9570d --- /dev/null +++ b/tests/internal_bench/class_create-1-slots.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + l = ["x"] + for i in range(num // 40): + + class X: + __slots__ = l + + +bench.run(test) diff --git a/tests/internal_bench/class_create-1.1-slots5.py b/tests/internal_bench/class_create-1.1-slots5.py new file mode 100644 index 00000000000..ccac77dec9d --- /dev/null +++ b/tests/internal_bench/class_create-1.1-slots5.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + l = ["a", "b", "c", "d", "x"] + for i in range(num // 40): + + class X: + __slots__ = l + + +bench.run(test) diff --git a/tests/internal_bench/class_create-2-classattr.py b/tests/internal_bench/class_create-2-classattr.py new file mode 100644 index 00000000000..049a7dab170 --- /dev/null +++ b/tests/internal_bench/class_create-2-classattr.py @@ -0,0 +1,11 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + x = 1 + + +bench.run(test) diff --git a/tests/internal_bench/class_create-2.1-classattr5.py b/tests/internal_bench/class_create-2.1-classattr5.py new file mode 100644 index 00000000000..5051e7dcca7 --- /dev/null +++ b/tests/internal_bench/class_create-2.1-classattr5.py @@ -0,0 +1,15 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + a = 0 + b = 0 + c = 0 + d = 0 + x = 1 + + +bench.run(test) diff --git a/tests/internal_bench/class_create-2.3-classattr5objs.py b/tests/internal_bench/class_create-2.3-classattr5objs.py new file mode 100644 index 00000000000..74540865dcd --- /dev/null +++ b/tests/internal_bench/class_create-2.3-classattr5objs.py @@ -0,0 +1,20 @@ +import bench + + +class Class: + pass + + +def test(num): + instance = Class() + for i in range(num // 40): + + class X: + a = instance + b = instance + c = instance + d = instance + x = instance + + +bench.run(test) diff --git a/tests/internal_bench/class_create-3-instancemethod.py b/tests/internal_bench/class_create-3-instancemethod.py new file mode 100644 index 00000000000..e8c201cb2c3 --- /dev/null +++ b/tests/internal_bench/class_create-3-instancemethod.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + def x(self): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-4-classmethod.py b/tests/internal_bench/class_create-4-classmethod.py new file mode 100644 index 00000000000..f34962bc671 --- /dev/null +++ b/tests/internal_bench/class_create-4-classmethod.py @@ -0,0 +1,13 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + @classmethod + def x(cls): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-4.1-classmethod_implicit.py b/tests/internal_bench/class_create-4.1-classmethod_implicit.py new file mode 100644 index 00000000000..f2d1fcfd188 --- /dev/null +++ b/tests/internal_bench/class_create-4.1-classmethod_implicit.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + def __new__(cls): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-5-staticmethod.py b/tests/internal_bench/class_create-5-staticmethod.py new file mode 100644 index 00000000000..06335566675 --- /dev/null +++ b/tests/internal_bench/class_create-5-staticmethod.py @@ -0,0 +1,13 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + @staticmethod + def x(): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-6-getattribute.py b/tests/internal_bench/class_create-6-getattribute.py new file mode 100644 index 00000000000..10a4fe7ce8d --- /dev/null +++ b/tests/internal_bench/class_create-6-getattribute.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + def __getattribute__(self, name): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-6.1-getattr.py b/tests/internal_bench/class_create-6.1-getattr.py new file mode 100644 index 00000000000..b4b9ba2f552 --- /dev/null +++ b/tests/internal_bench/class_create-6.1-getattr.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + def __getattr__(self, name): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-6.2-property.py b/tests/internal_bench/class_create-6.2-property.py new file mode 100644 index 00000000000..cf847b6dc9c --- /dev/null +++ b/tests/internal_bench/class_create-6.2-property.py @@ -0,0 +1,13 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + @property + def x(self): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-6.3-descriptor.py b/tests/internal_bench/class_create-6.3-descriptor.py new file mode 100644 index 00000000000..7b0a6357263 --- /dev/null +++ b/tests/internal_bench/class_create-6.3-descriptor.py @@ -0,0 +1,17 @@ +import bench + + +class D: + def __get__(self, instance, owner=None): + pass + + +def test(num): + descriptor = D() + for i in range(num // 40): + + class X: + x = descriptor + + +bench.run(test) diff --git a/tests/internal_bench/class_create-7-inherit.py b/tests/internal_bench/class_create-7-inherit.py new file mode 100644 index 00000000000..f48fb215e0a --- /dev/null +++ b/tests/internal_bench/class_create-7-inherit.py @@ -0,0 +1,14 @@ +import bench + + +def test(num): + class B: + pass + + for i in range(num // 40): + + class X(B): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-7.1-inherit_initsubclass.py b/tests/internal_bench/class_create-7.1-inherit_initsubclass.py new file mode 100644 index 00000000000..0660fa86258 --- /dev/null +++ b/tests/internal_bench/class_create-7.1-inherit_initsubclass.py @@ -0,0 +1,16 @@ +import bench + + +def test(num): + class B: + @classmethod + def __init_subclass__(cls): + pass + + for i in range(num // 40): + + class X(B): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-8-metaclass_setname.py b/tests/internal_bench/class_create-8-metaclass_setname.py new file mode 100644 index 00000000000..e4515b54279 --- /dev/null +++ b/tests/internal_bench/class_create-8-metaclass_setname.py @@ -0,0 +1,17 @@ +import bench + + +class D: + def __set_name__(self, owner, name): + pass + + +def test(num): + descriptor = D() + for i in range(num // 40): + + class X: + x = descriptor + + +bench.run(test) diff --git a/tests/internal_bench/class_create-8.1-metaclass_setname5.py b/tests/internal_bench/class_create-8.1-metaclass_setname5.py new file mode 100644 index 00000000000..5daa3f8471b --- /dev/null +++ b/tests/internal_bench/class_create-8.1-metaclass_setname5.py @@ -0,0 +1,21 @@ +import bench + + +class D: + def __set_name__(self, owner, name): + pass + + +def test(num): + descriptor = D() + for i in range(num // 40): + + class X: + a = descriptor + b = descriptor + c = descriptor + d = descriptor + x = descriptor + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-0-object.py b/tests/internal_bench/class_instance-0-object.py new file mode 100644 index 00000000000..401c8ea7e3c --- /dev/null +++ b/tests/internal_bench/class_instance-0-object.py @@ -0,0 +1,11 @@ +import bench + +X = object + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-0.1-object-gc.py b/tests/internal_bench/class_instance-0.1-object-gc.py new file mode 100644 index 00000000000..7c475963a8e --- /dev/null +++ b/tests/internal_bench/class_instance-0.1-object-gc.py @@ -0,0 +1,13 @@ +import bench +import gc + +X = object + + +def test(num): + for i in range(num // 5): + x = X() + gc.collect() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-1-empty.py b/tests/internal_bench/class_instance-1-empty.py new file mode 100644 index 00000000000..617d47a86e9 --- /dev/null +++ b/tests/internal_bench/class_instance-1-empty.py @@ -0,0 +1,13 @@ +import bench + + +class X: + pass + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-1.1-classattr.py b/tests/internal_bench/class_instance-1.1-classattr.py new file mode 100644 index 00000000000..4e667533d4a --- /dev/null +++ b/tests/internal_bench/class_instance-1.1-classattr.py @@ -0,0 +1,13 @@ +import bench + + +class X: + x = 0 + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-1.2-func.py b/tests/internal_bench/class_instance-1.2-func.py new file mode 100644 index 00000000000..21bf7a1ac48 --- /dev/null +++ b/tests/internal_bench/class_instance-1.2-func.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def f(self): + pass + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-1.3-empty-gc.py b/tests/internal_bench/class_instance-1.3-empty-gc.py new file mode 100644 index 00000000000..a5108ef8e81 --- /dev/null +++ b/tests/internal_bench/class_instance-1.3-empty-gc.py @@ -0,0 +1,15 @@ +import bench +import gc + + +class X: + pass + + +def test(num): + for i in range(num // 5): + x = X() + gc.collect() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-2-init.py b/tests/internal_bench/class_instance-2-init.py new file mode 100644 index 00000000000..86619d31548 --- /dev/null +++ b/tests/internal_bench/class_instance-2-init.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def __init__(self): + pass + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-2.1-init_super.py b/tests/internal_bench/class_instance-2.1-init_super.py new file mode 100644 index 00000000000..38bca5fef87 --- /dev/null +++ b/tests/internal_bench/class_instance-2.1-init_super.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def __init__(self): + return super().__init__() + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-2.2-new.py b/tests/internal_bench/class_instance-2.2-new.py new file mode 100644 index 00000000000..dc5e78ea5ef --- /dev/null +++ b/tests/internal_bench/class_instance-2.2-new.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def __new__(cls): + return super().__new__(cls) + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-3-del.py b/tests/internal_bench/class_instance-3-del.py new file mode 100644 index 00000000000..af700f72a94 --- /dev/null +++ b/tests/internal_bench/class_instance-3-del.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def __del__(self): + pass + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-3.1-del-gc.py b/tests/internal_bench/class_instance-3.1-del-gc.py new file mode 100644 index 00000000000..311c71c3571 --- /dev/null +++ b/tests/internal_bench/class_instance-3.1-del-gc.py @@ -0,0 +1,16 @@ +import bench +import gc + + +class X: + def __del__(self): + pass + + +def test(num): + for i in range(num // 5): + x = X() + gc.collect() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-4-slots.py b/tests/internal_bench/class_instance-4-slots.py new file mode 100644 index 00000000000..51b067fedf0 --- /dev/null +++ b/tests/internal_bench/class_instance-4-slots.py @@ -0,0 +1,13 @@ +import bench + + +class X: + __slots__ = ["x"] + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-4.1-slots5.py b/tests/internal_bench/class_instance-4.1-slots5.py new file mode 100644 index 00000000000..8f5c2ecb456 --- /dev/null +++ b/tests/internal_bench/class_instance-4.1-slots5.py @@ -0,0 +1,13 @@ +import bench + + +class X: + __slots__ = ["a", "b", "c", "d", "x"] + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/var-6.2-instance-speciallookup.py b/tests/internal_bench/var-6.2-instance-speciallookup.py new file mode 100644 index 00000000000..fee12b2f930 --- /dev/null +++ b/tests/internal_bench/var-6.2-instance-speciallookup.py @@ -0,0 +1,19 @@ +import bench + + +class Foo: + def __init__(self): + self.num = 20000000 + + def __delattr__(self, name): # just trigger the 'special lookups' flag on the class + pass + + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-6.3-instance-property.py b/tests/internal_bench/var-6.3-instance-property.py new file mode 100644 index 00000000000..b4426ef7928 --- /dev/null +++ b/tests/internal_bench/var-6.3-instance-property.py @@ -0,0 +1,17 @@ +import bench + + +class Foo: + @property + def num(self): + return 20000000 + + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-6.4-instance-descriptor.py b/tests/internal_bench/var-6.4-instance-descriptor.py new file mode 100644 index 00000000000..b4df69f878f --- /dev/null +++ b/tests/internal_bench/var-6.4-instance-descriptor.py @@ -0,0 +1,20 @@ +import bench + + +class Descriptor: + def __get__(self, instance, owner=None): + return 20000000 + + +class Foo: + num = Descriptor() + + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-6.5-instance-getattr.py b/tests/internal_bench/var-6.5-instance-getattr.py new file mode 100644 index 00000000000..3b2ef672110 --- /dev/null +++ b/tests/internal_bench/var-6.5-instance-getattr.py @@ -0,0 +1,16 @@ +import bench + + +class Foo: + def __getattr__(self, name): + return 20000000 + + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-6.6-instance-builtin_ordered.py b/tests/internal_bench/var-6.6-instance-builtin_ordered.py new file mode 100644 index 00000000000..02d75252301 --- /dev/null +++ b/tests/internal_bench/var-6.6-instance-builtin_ordered.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + i = 0 + o = set() # object with largest rom-frozen ordered locals_dict + n = "__contains__" # last element in that dict for longest lookup + while i < num: + i += hasattr(o, n) # True, converts to 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9-getattr.py b/tests/internal_bench/var-9-getattr.py new file mode 100644 index 00000000000..69d2bfed2e0 --- /dev/null +++ b/tests/internal_bench/var-9-getattr.py @@ -0,0 +1,16 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + o.num = num + i = 0 + while i < getattr(o, "num", num): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.1-getattr_default.py b/tests/internal_bench/var-9.1-getattr_default.py new file mode 100644 index 00000000000..e803d39b326 --- /dev/null +++ b/tests/internal_bench/var-9.1-getattr_default.py @@ -0,0 +1,15 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + i = 0 + while i < getattr(o, "num", num): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.2-getattr_default_special.py b/tests/internal_bench/var-9.2-getattr_default_special.py new file mode 100644 index 00000000000..c48ec0742cf --- /dev/null +++ b/tests/internal_bench/var-9.2-getattr_default_special.py @@ -0,0 +1,16 @@ +import bench + + +class Foo: + def __delattr__(self, name): # just trigger the 'special lookups' flag on the class + pass + + +def test(num): + o = Foo() + i = 0 + while i < getattr(o, "num", num): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.3-except_ok.py b/tests/internal_bench/var-9.3-except_ok.py new file mode 100644 index 00000000000..efc1a8f858c --- /dev/null +++ b/tests/internal_bench/var-9.3-except_ok.py @@ -0,0 +1,23 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + o.num = num + + def get(): + try: + return o.num + except AttributeError: + return num + + i = 0 + while i < get(): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.4-except_selfinduced.py b/tests/internal_bench/var-9.4-except_selfinduced.py new file mode 100644 index 00000000000..544609ca4b6 --- /dev/null +++ b/tests/internal_bench/var-9.4-except_selfinduced.py @@ -0,0 +1,22 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + + def get(): + try: + raise AttributeError + except AttributeError: + return num + + i = 0 + while i < get(): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.5-except_error.py b/tests/internal_bench/var-9.5-except_error.py new file mode 100644 index 00000000000..caf83fa46ab --- /dev/null +++ b/tests/internal_bench/var-9.5-except_error.py @@ -0,0 +1,22 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + + def get(): + try: + return o.num + except AttributeError: + return num + + i = 0 + while i < get(): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.6-except_error_special.py b/tests/internal_bench/var-9.6-except_error_special.py new file mode 100644 index 00000000000..8bc395b4d7e --- /dev/null +++ b/tests/internal_bench/var-9.6-except_error_special.py @@ -0,0 +1,23 @@ +import bench + + +class Foo: + def __delattr__(self, name): # just trigger the 'special lookups' flag on the class + pass + + +def test(num): + o = Foo() + + def get(): + try: + return o.num + except AttributeError: + return num + + i = 0 + while i < get(): + i += 1 + + +bench.run(test) diff --git a/tests/io/builtin_print_file.py b/tests/io/builtin_print_file.py index 822356a6cc3..e00f58635a9 100644 --- a/tests/io/builtin_print_file.py +++ b/tests/io/builtin_print_file.py @@ -13,5 +13,5 @@ try: print(file=1) -except (AttributeError, OSError): # CPython and uPy differ in error message +except (AttributeError, OSError): # CPython and MicroPython differ in error message print("Error") diff --git a/tests/io/file_seek.py b/tests/io/file_seek.py index 3990df84090..b9f9593786f 100644 --- a/tests/io/file_seek.py +++ b/tests/io/file_seek.py @@ -30,5 +30,5 @@ try: f.seek(1) except (OSError, ValueError): - # CPy raises ValueError, uPy raises OSError + # CPy raises ValueError, MPy raises OSError print("OSError or ValueError") diff --git a/tests/micropython/builtin_execfile.py b/tests/micropython/builtin_execfile.py index 75a867bb940..4fd4d66d4ee 100644 --- a/tests/micropython/builtin_execfile.py +++ b/tests/micropython/builtin_execfile.py @@ -75,3 +75,24 @@ def open(self, file, mode): # Unmount the VFS object. vfs.umount(fs) + + +class EvilFilesystem: + def mount(self, readonly, mkfs): + print("mount", readonly, mkfs) + + def umount(self): + print("umount") + + def open(self, file, mode): + return None + + +fs = EvilFilesystem() +vfs.mount(fs, "/test_mnt") +try: + execfile("/test_mnt/test.py") + print("ExecFile succeeded") +except OSError: + print("OSError") +vfs.umount(fs) diff --git a/tests/micropython/builtin_execfile.py.exp b/tests/micropython/builtin_execfile.py.exp index 49703d57076..d93dee547b6 100644 --- a/tests/micropython/builtin_execfile.py.exp +++ b/tests/micropython/builtin_execfile.py.exp @@ -5,3 +5,6 @@ open /test.py rb 123 TypeError umount +mount False False +OSError +umount diff --git a/tests/micropython/builtin_tstring.py b/tests/micropython/builtin_tstring.py new file mode 100644 index 00000000000..8de0acfd98b --- /dev/null +++ b/tests/micropython/builtin_tstring.py @@ -0,0 +1,24 @@ +# This tests the built-in __template__ (which is MicroPython specific). + +# Test a varying number of arguments. +print(__template__(())) +print(__template__((), ())) +print(__template__((), None, None)) +print(__template__((), None, None, None)) +print(__template__((), None, None, None, None)) +print(__template__((), None, None, None, None, None)) + +# Test two strings and one interpolation. +print(__template__(("Hello ", "!"), (42, "x", None, ""))) + +# Test not enough arguments. +try: + print(__template__()) +except TypeError as er: + print(repr(er)) + +# Test two arguments with second not being a tuple/list. +try: + print(__template__((), None)) +except TypeError as er: + print(repr(er)) diff --git a/tests/micropython/builtin_tstring.py.exp b/tests/micropython/builtin_tstring.py.exp new file mode 100644 index 00000000000..b6b47306124 --- /dev/null +++ b/tests/micropython/builtin_tstring.py.exp @@ -0,0 +1,9 @@ +Template(strings=(), interpolations=()) +Template(strings=(), interpolations=()) +Template(strings=(), interpolations=()) +Template(strings=(), interpolations=()) +Template(strings=(), interpolations=(Interpolation(None, None, None, None),)) +Template(strings=(), interpolations=(Interpolation(None, None, None, None),)) +Template(strings=('Hello ', '!'), interpolations=(Interpolation(42, 'x', None, ''),)) +TypeError('function missing 1 required positional arguments',) +TypeError("object 'NoneType' isn't a tuple or list",) diff --git a/tests/micropython/const_annotated.py b/tests/micropython/const_annotated.py new file mode 100644 index 00000000000..4d01389e43a --- /dev/null +++ b/tests/micropython/const_annotated.py @@ -0,0 +1,18 @@ +# Test type annotations in combination with const. +# This test will only work when MICROPY_COMP_CONST and MICROPY_COMP_CONST_TUPLE are enabled. + +from micropython import const + +_X0: bool = const(True) +_X1: int = const(123) +_X2: str = const("test") +_X3: tuple = const((1, 2)) +_X4: tuple[bool, int] = const((True, 4)) +_X5: bytes = b"\x01\x02\x03" + +print(_X0) +print(_X1) +print(_X2) +print(_X3) +print(_X4) +print(_X5) diff --git a/tests/micropython/const_annotated.py.exp b/tests/micropython/const_annotated.py.exp new file mode 100644 index 00000000000..65edb58e72e --- /dev/null +++ b/tests/micropython/const_annotated.py.exp @@ -0,0 +1,6 @@ +True +123 +test +(1, 2) +(True, 4) +b'\x01\x02\x03' diff --git a/tests/micropython/const_error.py b/tests/micropython/const_error.py index d35be530a7c..950360e4dc7 100644 --- a/tests/micropython/const_error.py +++ b/tests/micropython/const_error.py @@ -18,8 +18,6 @@ def test_syntax(code): # these operations are not supported within const test_syntax("A = const(1 @ 2)") -test_syntax("A = const(1 / 2)") -test_syntax("A = const(1 ** -2)") test_syntax("A = const(1 << -2)") test_syntax("A = const(1 >> -2)") test_syntax("A = const(1 % 0)") diff --git a/tests/micropython/const_error.py.exp b/tests/micropython/const_error.py.exp index 3edc3efe9c3..bef69eb32ea 100644 --- a/tests/micropython/const_error.py.exp +++ b/tests/micropython/const_error.py.exp @@ -5,5 +5,3 @@ SyntaxError SyntaxError SyntaxError SyntaxError -SyntaxError -SyntaxError diff --git a/tests/micropython/const_float.py b/tests/micropython/const_float.py new file mode 100644 index 00000000000..c3a0df0276b --- /dev/null +++ b/tests/micropython/const_float.py @@ -0,0 +1,23 @@ +# test constant optimisation, with consts that are floats + +from micropython import const + +# check we can make consts from floats +F1 = const(2.5) +F2 = const(-0.3) +print(type(F1), F1) +print(type(F2), F2) + +# check arithmetic with floats +F3 = const(F1 + F2) +F4 = const(F1**2) +print(F3, F4) + +# check int operations with float results +F5 = const(1 / 2) +F6 = const(2**-2) +print(F5, F6) + +# note: we also test float expression folding when +# we're compiling test cases in tests/float, as +# many expressions are resolved at compile time. diff --git a/tests/micropython/const_float.py.exp b/tests/micropython/const_float.py.exp new file mode 100644 index 00000000000..17a86a6d936 --- /dev/null +++ b/tests/micropython/const_float.py.exp @@ -0,0 +1,4 @@ + 2.5 + -0.3 +2.2 6.25 +0.5 0.25 diff --git a/tests/micropython/const_math.py b/tests/micropython/const_math.py new file mode 100644 index 00000000000..7ee5edc6d32 --- /dev/null +++ b/tests/micropython/const_math.py @@ -0,0 +1,18 @@ +# Test expressions based on math module constants +try: + import math +except ImportError: + print("SKIP") + raise SystemExit + +from micropython import const + +# check that we can make consts from math constants +# (skip if the target has MICROPY_COMP_MODULE_CONST disabled) +try: + exec("two_pi = const(2.0 * math.pi)") +except SyntaxError: + print("SKIP") + raise SystemExit + +print(math.cos(two_pi)) diff --git a/tests/micropython/const_math.py.exp b/tests/micropython/const_math.py.exp new file mode 100644 index 00000000000..d3827e75a5c --- /dev/null +++ b/tests/micropython/const_math.py.exp @@ -0,0 +1 @@ +1.0 diff --git a/tests/micropython/decorator_error.py b/tests/micropython/decorator_error.py index 94772ac1e5f..b5eae65b292 100644 --- a/tests/micropython/decorator_error.py +++ b/tests/micropython/decorator_error.py @@ -1,4 +1,4 @@ -# test syntax errors for uPy-specific decorators +# test syntax errors for MicroPython-specific decorators def test_syntax(code): diff --git a/tests/micropython/emg_exc.py b/tests/micropython/emg_exc.py index a74757d028f..cf918b3dc8a 100644 --- a/tests/micropython/emg_exc.py +++ b/tests/micropython/emg_exc.py @@ -1,10 +1,9 @@ # test that emergency exceptions work -import micropython import sys try: - import io + import io, micropython except ImportError: print("SKIP") raise SystemExit diff --git a/tests/micropython/emg_exc.py.native.exp b/tests/micropython/emg_exc.py.native.exp new file mode 100644 index 00000000000..879fa7ef5b9 --- /dev/null +++ b/tests/micropython/emg_exc.py.native.exp @@ -0,0 +1 @@ +ValueError(1,) diff --git a/tests/micropython/extreme_exc.py b/tests/micropython/extreme_exc.py index ad819e408fd..17323b566d3 100644 --- a/tests/micropython/extreme_exc.py +++ b/tests/micropython/extreme_exc.py @@ -1,6 +1,10 @@ # test some extreme cases of allocating exceptions and tracebacks -import micropython +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit # Check for stackless build, which can't call functions without # allocating a frame on the heap. diff --git a/tests/micropython/heap_lock.py b/tests/micropython/heap_lock.py index f2892a6dc58..209a3143461 100644 --- a/tests/micropython/heap_lock.py +++ b/tests/micropython/heap_lock.py @@ -1,6 +1,10 @@ # check that heap_lock/heap_unlock work as expected -import micropython +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit l = [] l2 = list(range(100)) diff --git a/tests/micropython/heap_locked.py b/tests/micropython/heap_locked.py index d9e5b5d4090..d9d99493dd6 100644 --- a/tests/micropython/heap_locked.py +++ b/tests/micropython/heap_locked.py @@ -1,8 +1,10 @@ # test micropython.heap_locked() -import micropython +try: + import micropython -if not hasattr(micropython, "heap_locked"): + micropython.heap_locked +except (AttributeError, ImportError): print("SKIP") raise SystemExit diff --git a/tests/micropython/heapalloc.py b/tests/micropython/heapalloc.py index e19f8d0255d..010bf878a07 100644 --- a/tests/micropython/heapalloc.py +++ b/tests/micropython/heapalloc.py @@ -1,6 +1,10 @@ # check that we can do certain things without allocating heap memory -import micropython +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit # Check for stackless build, which can't call functions without # allocating a frame on heap. diff --git a/tests/micropython/heapalloc_exc_compressed.py b/tests/micropython/heapalloc_exc_compressed.py index aa071d641c2..96fe3ca4f7e 100644 --- a/tests/micropython/heapalloc_exc_compressed.py +++ b/tests/micropython/heapalloc_exc_compressed.py @@ -1,4 +1,10 @@ -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # Tests both code paths for built-in exception raising. # mp_obj_new_exception_msg_varg (exception requires decompression at raise-time to format) diff --git a/tests/micropython/heapalloc_exc_compressed_emg_exc.py b/tests/micropython/heapalloc_exc_compressed_emg_exc.py index 48ce9dd69e6..31d937b8f93 100644 --- a/tests/micropython/heapalloc_exc_compressed_emg_exc.py +++ b/tests/micropython/heapalloc_exc_compressed_emg_exc.py @@ -1,4 +1,10 @@ -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # Does the full test from heapalloc_exc_compressed.py but while the heap is # locked (this can only work when the emergency exception buf is enabled). diff --git a/tests/micropython/heapalloc_exc_raise.py b/tests/micropython/heapalloc_exc_raise.py index 99810e00750..917ccf42f1e 100644 --- a/tests/micropython/heapalloc_exc_raise.py +++ b/tests/micropython/heapalloc_exc_raise.py @@ -1,6 +1,12 @@ # Test that we can raise and catch (preallocated) exception # without memory allocation. -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit e = ValueError("error") diff --git a/tests/micropython/heapalloc_fail_bytearray.py b/tests/micropython/heapalloc_fail_bytearray.py index 1bf7ddd600b..9ee73d1c583 100644 --- a/tests/micropython/heapalloc_fail_bytearray.py +++ b/tests/micropython/heapalloc_fail_bytearray.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with bytearray -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit class GetSlice: diff --git a/tests/micropython/heapalloc_fail_dict.py b/tests/micropython/heapalloc_fail_dict.py index ce2d158bd09..04c79183578 100644 --- a/tests/micropython/heapalloc_fail_dict.py +++ b/tests/micropython/heapalloc_fail_dict.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with dict -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # create dict x = 1 diff --git a/tests/micropython/heapalloc_fail_list.py b/tests/micropython/heapalloc_fail_list.py index 9a2e9a555f3..7afb6dc1019 100644 --- a/tests/micropython/heapalloc_fail_list.py +++ b/tests/micropython/heapalloc_fail_list.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with list -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit class GetSlice: diff --git a/tests/micropython/heapalloc_fail_memoryview.py b/tests/micropython/heapalloc_fail_memoryview.py index da2d1abffa6..17e3e126247 100644 --- a/tests/micropython/heapalloc_fail_memoryview.py +++ b/tests/micropython/heapalloc_fail_memoryview.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with memoryview -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit class GetSlice: diff --git a/tests/micropython/heapalloc_fail_set.py b/tests/micropython/heapalloc_fail_set.py index 3c347660ad7..0c4d85eef62 100644 --- a/tests/micropython/heapalloc_fail_set.py +++ b/tests/micropython/heapalloc_fail_set.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with set -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # create set x = 1 diff --git a/tests/micropython/heapalloc_fail_tstring.py b/tests/micropython/heapalloc_fail_tstring.py new file mode 100644 index 00000000000..94687d57bfb --- /dev/null +++ b/tests/micropython/heapalloc_fail_tstring.py @@ -0,0 +1,475 @@ +# Test template string (t-string) operations with heap allocation failure + +import micropython +from string.templatelib import Template, Interpolation + +i1 = Interpolation(1, "1") +i2 = Interpolation(2, "2") + +micropython.heap_lock() +try: + args = [] + for i in range(9): + args.append("x" * 100) + args.append(Interpolation(i, "x" + str(i))) + args.append("x" * 100) + Template(*args) + print("FAIL: Template creation") +except MemoryError: + print("OK: Template creation") +micropython.heap_unlock() + +# Multiple string concatenation +micropython.heap_lock() +try: + Template("first", "second", "third", "fourth") + print("FAIL: Multi string concat") +except MemoryError: + print("OK: Multi string concat") +micropython.heap_unlock() + +# Mixed constructor +micropython.heap_lock() +try: + Template("a", i1, "b", i2, "c", "d", "e") + print("FAIL: Mixed constructor") +except MemoryError: + print("OK: Mixed constructor") +micropython.heap_unlock() + +# Template.__str__() +t = t"Hello {42} world {99}" +micropython.heap_lock() +try: + str(t) + print("FAIL: Template.__str__()") +except MemoryError: + print("OK: Template.__str__()") +micropython.heap_unlock() + +# Template.values property +vals = list(range(10)) +t_many = t"{vals[0]}{vals[1]}{vals[2]}{vals[3]}{vals[4]}" +micropython.heap_lock() +try: + t_many.values + print("FAIL: Template.values") +except MemoryError: + print("OK: Template.values") +micropython.heap_unlock() + +n = 20 +args_large = [] +for i in range(n): + args_large.append("") + args_large.append(Interpolation(i, "x" + str(i))) +args_large.append("") +t_large = Template(*args_large) +micropython.heap_lock() +try: + t_large.values + print("FAIL: Large values array") +except MemoryError: + print("OK: Large values array") +micropython.heap_unlock() + +# Template concatenation +t1 = t"Hello" +t2 = t"World" +micropython.heap_lock() +try: + t1 + t2 + print("FAIL: Template concatenation") +except MemoryError: + print("OK: Template concatenation") +micropython.heap_unlock() + +# Template iterator +t_iter = t"a{1}b{2}c" +micropython.heap_lock() +try: + iter(t_iter) + print("FAIL: Template iterator") +except MemoryError: + print("OK: Template iterator") +micropython.heap_unlock() + +# Iterator next +t_iter2 = t"a{1}b{2}c{3}d" +it = iter(t_iter2) +micropython.heap_lock() +try: + list(it) + print("FAIL: Iterator next") +except MemoryError: + print("OK: Iterator next") +micropython.heap_unlock() + +# __template__ builtin +strings2 = ("test",) * 5 +interps2 = ((42, "x", None, ""),) * 4 +micropython.heap_lock() +try: + __template__(strings2, interps2) + print("FAIL: __template__ builtin") +except MemoryError: + print("OK: __template__ builtin") +micropython.heap_unlock() + +# Format spec interpolation +width = 10 +t_fmt = t"{42:{width}d}" +micropython.heap_lock() +try: + str(t_fmt) + print("FAIL: Format spec interpolation") +except MemoryError: + print("OK: Format spec interpolation") +micropython.heap_unlock() + +# Debug format +x = 42 +t_debug = t"{x=}" +micropython.heap_lock() +try: + str(t_debug) + print("FAIL: Debug format") +except MemoryError: + print("OK: Debug format") +micropython.heap_unlock() + +# Conversion with format +obj = "test" +t_conv = t"{obj!r:>10}" +micropython.heap_lock() +try: + str(t_conv) + print("FAIL: Conversion + format") +except MemoryError: + print("OK: Conversion + format") +micropython.heap_unlock() + +# String conversion (s) +t_s = t"{'test'!s}" +micropython.heap_lock() +try: + str(t_s) + print("FAIL: s conversion") +except MemoryError: + print("OK: s conversion") +micropython.heap_unlock() + +# ASCII conversion (a) +# t_a = t"{'test'!a}" +# micropython.heap_lock() +# try: +# str(t_a) +# print("FAIL: a conversion") +# except MemoryError: +# print("OK: a conversion") +# micropython.heap_unlock() + +# Complex format spec +fill = "*" +align = ">" +width = 10 +precision = 2 +t_complex = t"{3.14159:{fill}{align}{width}.{precision}f}" +micropython.heap_lock() +try: + str(t_complex) + print("FAIL: Complex format spec") +except MemoryError: + print("OK: Complex format spec") +micropython.heap_unlock() + +# Simple expression +x = 42 +t_simple = t"{x}" +micropython.heap_lock() +try: + str(t_simple) + print("FAIL: Simple expression") +except MemoryError: + print("OK: Simple expression") +micropython.heap_unlock() + +# Interpolation creation +micropython.heap_lock() +try: + Interpolation("value", "expr", "r", ".2f") + print("FAIL: Interpolation creation") +except MemoryError: + print("OK: Interpolation creation") +micropython.heap_unlock() + +# Template repr +t = t"test" +micropython.heap_lock() +try: + repr(t) + print("FAIL: Template repr") +except MemoryError: + print("OK: Template repr") +micropython.heap_unlock() + +# Interpolation repr +i = Interpolation(42, "x") +micropython.heap_lock() +try: + repr(i) + print("FAIL: Interpolation repr") +except MemoryError: + print("OK: Interpolation repr") +micropython.heap_unlock() + +def exhaust_heap(limit): + allocations = [] + try: + for _ in range(limit): + allocations.append("x" * 1024) + except MemoryError: + pass + return allocations + +def test_many_interpolations_heap(): + # Pre-create variables before exhausting heap + x1, x2, x3, x4, x5, x6, x7, x8, x9 = 1, 2, 3, 4, 5, 6, 7, 8, 9 + micropython.heap_lock() + try: + t = t"{x1}{x2}{x3}{x4}{x5}{x6}{x7}{x8}{x9}" + print("FAIL: Many interpolations heap test") + except MemoryError: + print("OK: Many interpolations heap test") + micropython.heap_unlock() + +def test_template_str_heap(): + t = t"x{1}x{2}x{3}x{4}x" + micropython.heap_lock() + try: + s = str(t) + print("FAIL: Template str heap test") + except MemoryError: + print("OK: Template str heap test") + micropython.heap_unlock() + +def test_template_iter_heap(): + t = t"a{1}b{2}c" + micropython.heap_lock() + try: + parts = list(iter(t)) + print("FAIL: Template iter heap test") + except MemoryError: + print("OK: Template iter heap test") + micropython.heap_unlock() + +def test_template_concat_heap(): + t1 = t"first" + t2 = t"second" + micropython.heap_lock() + try: + t3 = t1 + t2 + print("FAIL: Template concat heap test") + except MemoryError: + print("OK: Template concat heap test") + micropython.heap_unlock() + +def test_format_spec_heap(): + width = 10 + t = t"{42:{width}d}" + micropython.heap_lock() + try: + s = str(t) + print("FAIL: Format spec heap test") + except MemoryError: + print("OK: Format spec heap test") + micropython.heap_unlock() + +def test_debug_format_heap(): + value = 42 + t = t"{value}" + micropython.heap_lock() + try: + s = str(t) + print("FAIL: Debug format heap test") + except MemoryError: + print("OK: Debug format heap test") + micropython.heap_unlock() + +print("\n=== Heap allocation failure tests ===") +test_many_interpolations_heap() +test_template_str_heap() +test_template_iter_heap() +test_template_concat_heap() +test_format_spec_heap() +test_debug_format_heap() + +# Additional tests from coverage.c +print("\n=== Coverage.c heap tests ===") + +# Test creating interpolation with heap locked (from coverage.c) +micropython.heap_lock() +try: + i = Interpolation(42, "x", None, None) + print("FAIL: Interpolation with heap locked") +except MemoryError: + print("OK: Interpolation creation with heap locked") +micropython.heap_unlock() + +# Test parsing expression with heap locked (from coverage.c) +micropython.heap_lock() +try: + t = eval('t"{x + 1}"') + print("FAIL: Parse with heap locked") +except Exception as e: + if type(e).__name__ == "MemoryError": + print("OK: Parse with heap locked") + else: + print(f"Parse with heap locked: {type(e).__name__}") +micropython.heap_unlock() + +# Test lexer allocation failure for t-string expression parsing +print("\n=== Lexer/Parser allocation tests ===") + +# Wrap all tests in a try-catch to handle any unexpected errors +try: + # Test 1: Empty expression (tests tstring_expr_parser.c empty check) + try: + micropython.heap_lock() + try: + # This tests the empty expression path + exec("t'{}'") + print("FAIL: Empty expression with heap locked") + except Exception as e: + print(f"OK: Empty expression - {type(e).__name__}") + finally: + micropython.heap_unlock() + except: + pass + + # Test 2: Whitespace-only expression + try: + micropython.heap_lock() + try: + exec("t'{ }'") + print("FAIL: Whitespace expression with heap locked") + except Exception as e: + print(f"OK: Whitespace expression - {type(e).__name__}") + finally: + micropython.heap_unlock() + except: + pass + + # Test 3: Very complex expression to stress parser allocation + # Pre-create variables + x, y, z = 1, 2, 3 + try: + micropython.heap_lock() + try: + # Complex nested expression that requires many parse nodes + result = t'{[x*y for x in range(10) for y in range(10) if x+y > 5]}' + print("FAIL: Complex expression with heap locked") + except MemoryError: + print("OK: Complex expression parser allocation") + except Exception as e: + print(f"Complex expression: {type(e).__name__}") + finally: + micropython.heap_unlock() + except: + pass + + # Test 4: Expression parser lexer failure (simulates NULL lexer) + # This happens when memory is exhausted during lexer creation + try: + micropython.heap_lock() + try: + # Try to create t-string with expression during low memory + long_expr = "x" * 100 # Use a moderately long expression + exec(f"{long_expr} = 42; result = t'{{{long_expr}}}'") + print("FAIL: Lexer creation with heap locked") + except MemoryError: + print("OK: Lexer creation failure") + except Exception as e: + print(f"Lexer creation: {type(e).__name__}") + finally: + micropython.heap_unlock() + except: + pass + + # Test 5: Format spec and conversion parsing under memory pressure + val = 42 + try: + micropython.heap_lock() + try: + # This tests format spec node creation + result = t'{val!r:>10.2f}' + print("FAIL: Format spec with heap locked") + except MemoryError: + print("OK: Format spec allocation") + except Exception as e: + print(f"Format spec: {type(e).__name__}") + finally: + micropython.heap_unlock() + except: + pass + + # Test 6: Debug format with memory pressure + x = 100 + try: + micropython.heap_lock() + try: + result = t'{x=:.2f}' + print("FAIL: Debug format with heap locked") + except MemoryError: + print("OK: Debug format allocation") + except Exception as e: + print(f"Debug format: {type(e).__name__}") + finally: + micropython.heap_unlock() + except: + pass + + # Test 7: Multiple interpolations causing allocation failure + vals = list(range(20)) + try: + micropython.heap_lock() + try: + # Many interpolations to stress allocation + result = t'{vals[0]}{vals[1]}{vals[2]}{vals[3]}{vals[4]}{vals[5]}{vals[6]}{vals[7]}{vals[8]}{vals[9]}' + print("FAIL: Many interpolations with heap locked") + except MemoryError: + print("OK: Many interpolations allocation") + except Exception as e: + print(f"Many interpolations: {type(e).__name__}") + finally: + micropython.heap_unlock() + except: + pass + + # Test 8: Template string size limit (tests overflow check) + # Note: We can't directly test integer overflow, but we can test large templates + print("Template size limit: Tested via exec in coverage tests") + + # Test 9: Compile-time parsing under allocation failure + try: + micropython.heap_lock() + try: + compile("t'{x}'", "", "exec") + print("FAIL: Compile-time parsing under heap lock") + except MemoryError: + print("OK: Compile-time parsing under heap lock") + finally: + micropython.heap_unlock() + except: + pass + +except Exception as e: + # Catch any unexpected errors from the tests + print(f"\nTest error: {type(e).__name__}: {e}") + # Ensure heap is unlocked + try: + micropython.heap_unlock() + except: + pass + +print("\n=== Tests completed ===") diff --git a/tests/micropython/heapalloc_fail_tstring.py.exp b/tests/micropython/heapalloc_fail_tstring.py.exp new file mode 100644 index 00000000000..3bc90ef418a --- /dev/null +++ b/tests/micropython/heapalloc_fail_tstring.py.exp @@ -0,0 +1,42 @@ +OK: Template creation +OK: Multi string concat +OK: Mixed constructor +OK: Template.__str__() +OK: Template.values +OK: Large values array +OK: Template concatenation +OK: Template iterator +OK: Iterator next +OK: __template__ builtin +OK: Format spec interpolation +OK: Debug format +OK: Conversion + format +OK: s conversion +OK: Complex format spec +OK: Simple expression +OK: Interpolation creation +OK: Template repr +OK: Interpolation repr + +=== Heap allocation failure tests === +OK: Many interpolations heap test +OK: Template str heap test +OK: Template iter heap test +OK: Template concat heap test +OK: Format spec heap test +OK: Debug format heap test + +=== Coverage.c heap tests === +OK: Interpolation creation with heap locked +OK: Parse with heap locked + +=== Lexer/Parser allocation tests === +OK: Complex expression parser allocation +OK: Lexer creation failure +OK: Format spec allocation +OK: Debug format allocation +OK: Many interpolations allocation +Template size limit: Tested via exec in coverage tests +OK: Compile-time parsing under heap lock + +=== Tests completed === diff --git a/tests/micropython/heapalloc_fail_tuple.py b/tests/micropython/heapalloc_fail_tuple.py index de79385e3e3..11718a8107b 100644 --- a/tests/micropython/heapalloc_fail_tuple.py +++ b/tests/micropython/heapalloc_fail_tuple.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with tuple -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # create tuple x = 1 diff --git a/tests/micropython/heapalloc_inst_call.py b/tests/micropython/heapalloc_inst_call.py index 14d8826bf06..f78aa3cf877 100644 --- a/tests/micropython/heapalloc_inst_call.py +++ b/tests/micropython/heapalloc_inst_call.py @@ -1,6 +1,13 @@ # Test that calling clazz.__call__() with up to at least 3 arguments # doesn't require heap allocation. -import micropython + +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit class Foo0: diff --git a/tests/micropython/heapalloc_int_from_bytes.py b/tests/micropython/heapalloc_int_from_bytes.py index 5fe50443ae3..3310ea95d14 100644 --- a/tests/micropython/heapalloc_int_from_bytes.py +++ b/tests/micropython/heapalloc_int_from_bytes.py @@ -1,6 +1,13 @@ # Test that int.from_bytes() for small number of bytes generates # small int. -import micropython + +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit micropython.heap_lock() print(int.from_bytes(b"1", "little")) diff --git a/tests/micropython/heapalloc_slice.py b/tests/micropython/heapalloc_slice.py new file mode 100644 index 00000000000..62d96595c71 --- /dev/null +++ b/tests/micropython/heapalloc_slice.py @@ -0,0 +1,18 @@ +# slice operations that don't require allocation +try: + from micropython import heap_lock, heap_unlock +except (ImportError, AttributeError): + heap_lock = heap_unlock = lambda: 0 + +b = bytearray(range(10)) + +m = memoryview(b) + +heap_lock() + +b[3:5] = b"aa" +m[5:7] = b"bb" + +heap_unlock() + +print(b) diff --git a/tests/micropython/heapalloc_str.py b/tests/micropython/heapalloc_str.py index 39aa56ccd78..6372df5d37b 100644 --- a/tests/micropython/heapalloc_str.py +++ b/tests/micropython/heapalloc_str.py @@ -1,5 +1,12 @@ # String operations which don't require allocation -import micropython + +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit micropython.heap_lock() diff --git a/tests/micropython/heapalloc_super.py b/tests/micropython/heapalloc_super.py index 51afae3d83d..6839eee330a 100644 --- a/tests/micropython/heapalloc_super.py +++ b/tests/micropython/heapalloc_super.py @@ -1,5 +1,12 @@ # test super() operations which don't require allocation -import micropython + +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # Check for stackless build, which can't call functions without # allocating a frame on heap. diff --git a/tests/micropython/heapalloc_traceback.py.native.exp b/tests/micropython/heapalloc_traceback.py.native.exp new file mode 100644 index 00000000000..851eb5c7806 --- /dev/null +++ b/tests/micropython/heapalloc_traceback.py.native.exp @@ -0,0 +1,3 @@ +StopIteration +'StopIteration: ' +'' diff --git a/tests/micropython/heapalloc_yield_from.py b/tests/micropython/heapalloc_yield_from.py index 95071718908..9d4f8c6940f 100644 --- a/tests/micropython/heapalloc_yield_from.py +++ b/tests/micropython/heapalloc_yield_from.py @@ -1,6 +1,12 @@ # Check that yield-from can work without heap allocation -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # Yielding from a function generator diff --git a/tests/micropython/import_mpy_native.py b/tests/micropython/import_mpy_native.py index ad63e025db2..84cf198b278 100644 --- a/tests/micropython/import_mpy_native.py +++ b/tests/micropython/import_mpy_native.py @@ -54,12 +54,13 @@ def open(self, path, mode): # these are the test .mpy files # CIRCUITPY-CHANGE -valid_header = bytes([ord("C"), 6, mpy_arch, 31]) +small_int_bits = 31 +valid_header = bytes([77, 6, (mpy_arch & 0x3F), small_int_bits]) # fmt: off user_files = { # bad architecture (mpy_arch needed for sub-version) # CIRCUITPY-CHANGE - '/mod0.mpy': bytes([ord('C'), 6, 0xfc | mpy_arch, 31]), + '/mod0.mpy': bytes([ord('C'), 6, 0xfc | (mpy_arch & 3), small_int_bits]), # test loading of viper and asm '/mod1.mpy': valid_header + ( @@ -123,7 +124,7 @@ def open(self, path, mode): __import__(mod) print(mod, "OK") except ValueError as er: - print(mod, "ValueError", er) + print(mod, "ValueError", str(er) or "incompatible .mpy arch") # unmount and undo path addition vfs.umount("/userfs") diff --git a/tests/micropython/import_mpy_native_gc.py b/tests/micropython/import_mpy_native_gc.py index 0d5b79f0a8d..5159cc9e9f9 100644 --- a/tests/micropython/import_mpy_native_gc.py +++ b/tests/micropython/import_mpy_native_gc.py @@ -57,9 +57,13 @@ def open(self, path, mode): # CIRCUITPY-CHANGE: 'C' instead of 'M' mpy marker. features0_file_contents = { # -march=x64 - 0x806: b'C\x06\n\x1f\x02\x004build/features0.native.mpy\x00\x12factorial\x00\x8a\x02\xe93\x00\x00\x00\xf3\x0f\x1e\xfaSH\x8b\x1d\x7f\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6\xf3\x0f\x1e\xfaATUSH\x8b\x1dI\x00\x00\x00H\x8bG\x08L\x8bc(H\x8bx\x08A\xff\xd4H\x8d5#\x00\x00\x00H\x89\xc5H\x8b\x051\x00\x00\x00\x0f\xb7x\x02\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x11$\r&\xa5 \x01"\xff', + 0x806: b"C\x06\x0b\x1f\x03\x002build/test_x64.native.mpy\x00\x08add1\x00\x0cunused\x00\x91B\xe9I\x00\x00\x00H\x8b\x05\xf4\x00\x00\x00H\x8b\x00\xc3H\x8b\x05\xf9\x00\x00\x00\xbe\x02\x00\x00\x00\x8b8H\x8b\x05\xdb\x00\x00\x00H\x8b@ \xff\xe0H\x8b\x05\xce\x00\x00\x00S\xbe\x02\x00\x00\x00H\x8bX \xffP\x18\xbe\x02\x00\x00\x00H\x8dx\x01H\x89\xd8[\xff\xe0AVAUATUSH\x8b\x1d\xa3\x00\x00\x00H\x8bG\x08L\x8bk(H\x8bx\x08A\xff\xd5L\x8b5\x95\x00\x00\x00L\x8bchH\x8d5r\x00\x00\x00H\x89\xc5H\x8b\x05\x88\x00\x00\x00A\x0f\xb7~\x04\xc7\x00@\xe2\x01\x00A\xff\xd4H\x8d5C\x00\x00\x00\xbfV\x00\x00\x00A\xff\xd4A\x0f\xb7~\x02H\x8d5\x1f\x00\x00\x00A\xff\xd4H\x89\xefA\xff\xd5H\x8b\x03[]A\\A]A^\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x04\x11@\rB\tD\xaf4\x016\xad8\x01:\xaf<\x01>\xff", # -march=armv6m - 0x1006: b"C\x06\x12\x1f\x02\x004build/features0.native.mpy\x00\x12factorial\x00\x88\x02\x18\xe0\x00\x00\x10\xb5\tK\tJ{D\x9cX\x02!\xe3h\x98G\x03\x00\x01 \x00+\x02\xd0XC\x01;\xfa\xe7\x02!#i\x98G\x10\xbd\xc0Fj\x00\x00\x00\x00\x00\x00\x00\xf8\xb5\nN\nK~D\xf4XChgiXh\xb8G\x05\x00\x07K\x08I\xf3XyDX\x88ck\x98G(\x00\xb8G h\xf8\xbd\xc0F:\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x11<\r>\xa58\x01:\xff", + 0x1006: b"C\x06\x13\x1f\x03\x008build/test_armv6m.native.mpy\x00\x08add1\x00\x0cunused\x00\x8eb0\xe0\x00\x00\x00\x00\x00\x00\x02K\x03J{D\x9bX\x18hpG\xd0\x00\x00\x00\x00\x00\x00\x00\x10\xb5\x05K\x05I\x06J{D\x9aX[X\x10h\x02!\x1bi\x98G\x10\xbd\xb8\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x10\xb5\x06K\x06J{D\x9bX\x02!\x1ci\xdbh\x98G\x02!\x010\xa0G\x10\xbd\xc0F\x96\x00\x00\x00\x00\x00\x00\x00\xf7\xb5\x12O\x12K\x7fD\xfdX\x12Lki|D\x00\x93ChXh\x00\x9b\x98G\x0fK\x01\x90\x0fJ\xfbXnk\x1a`\x0eK!\x00\xffX\xb8\x88\xb0G!\x00V \x081\xb0G!\x00x\x88\x101\xb0G\x01\x98\x00\x9b\x98G(h\xfe\xbd\xc0Fr\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x08\x00\x00\x00@\xe2\x01\x00\x04\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x04\x11p\rr\tt\xafd\x01f\xadh\x01j\xafl\x01n\xff", + # -march=xtensawin + 0x2806: b"C\x06+\x1f\x03\x00>build/test_xtensawin.native.mpy\x00\x08add1\x00\x0cunused\x00\x8a\x12\x06\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006A\x00\x81\xf9\xff(\x08\x1d\xf0\x00\x006A\x00\x91\xfb\xff\x81\xf5\xff\xa8\t\x88H\x0c+\xe0\x08\x00-\n\x1d\xf0\x00\x006A\x00\x81\xf0\xff\xad\x02xH\x888\x0c+\xe0\x08\x00\x0c+\x1b\xaa\xe0\x07\x00-\n\x1d\xf06A\x00a\xe9\xff\x88\x122&\x05\xa2(\x01\xe0\x03\x00q\xe6\xff\x81\xea\xff\x92\xa7\x89\xa0\x99\x11H\xd6]\n\xb1\xe3\xff\xa2\x17\x02\x99\x08\xe0\x04\x00\xb1\xe2\xff\\j\xe0\x04\x00\xb1\xe1\xff\xa2\x17\x01\xe0\x04\x00\xad\x05\xe0\x03\x00(\x06\x1d\xf0p\x18\x04\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00(\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x11\x02\r\x04\x07\x06\x03\t\x0c\xaf\x01\x01\x03\xad\x05\x01\x07\xaf\t\x01\x0b\xff", + # -march=rv32imc + 0x2C06: b'C\x06/\x1f\x03\x00:build/test_rv32imc.native.mpy\x00\x08add1\x00\x0cunused\x00\x8fb\x97\x0f\x00\x00g\x80\x0f\x05\x97\x07\x00\x00\x83\xa7\x07\x0e\x88C\x82\x80\x97\x07\x00\x00\x83\xa7G\r\x17\x07\x00\x00\x03\'\xc7\r\x9cK\x08C\x89E\x82\x87A\x11\x97\x07\x00\x00\x83\xa7\xa7\x0b"\xc4\x80K\xdcG\x06\xc6\x89E\x82\x97\xa2\x87"D\xb2@\x89E\x05\x05A\x01\x82\x87\\A\x01\x11"\xcc\x17\x04\x00\x00\x03$$\tN\xc6\xc8C\x83)D\x01\x06\xce&\xcaJ\xc8R\xc4\x82\x99\x17\n\x00\x00\x03*\xca\x07\x03)D\x03\xaa\x84\xf9g\x03UJ\x00\x93\x87\x07$\x17\x07\x00\x00\x03\'\x07\x07\x1c\xc3\x97\x05\x00\x00\x93\x85\xe5\x03\x02\x99\x97\x05\x00\x00\x93\x85\xc5\x03\x13\x05`\x05\x02\x99\x03U*\x00\x97\x05\x00\x00\x93\x85%\x03\x02\x99&\x85\x82\x99\x08@\xf2@bD\xd2DBI\xb2I"J\x05a\x82\x80\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x04\x11t\rv\xafx\xadz\t|\xafh\x01j\xadl\x01n\xafp\x01r\xff', } # Populate armv7m-derived archs based on armv6m. @@ -67,7 +71,7 @@ def open(self, path, mode): features0_file_contents[arch] = features0_file_contents[0x1006] # Check that a .mpy exists for the target (ignore sub-version in lookup). -sys_implementation_mpy = sys.implementation._mpy & ~(3 << 8) +sys_implementation_mpy = (sys.implementation._mpy & ~(3 << 8)) & 0xFFFF if sys_implementation_mpy not in features0_file_contents: print("SKIP") raise SystemExit diff --git a/tests/micropython/incomplete_exc.py b/tests/micropython/incomplete_exc.py new file mode 100644 index 00000000000..2aec9a47b3a --- /dev/null +++ b/tests/micropython/incomplete_exc.py @@ -0,0 +1,40 @@ +# Test raising an incomplete exception. + + +class C(Exception): + def __init__(self): + raise self + + +class C1(C): + pass + + +class B: + pass + + +class C2(B, Exception): + def __init__(self): + raise self + + +class C3(Exception, B): + def __init__(self): + raise self + + +class D(Exception): + pass + + +class C4(D): + def __init__(self): + raise self + + +for cls in C, C1, C2, C3, C4: + try: + cls() + except TypeError as e: + print("TypeError") diff --git a/tests/micropython/incomplete_exc.py.exp b/tests/micropython/incomplete_exc.py.exp new file mode 100644 index 00000000000..f2e9c12f7f9 --- /dev/null +++ b/tests/micropython/incomplete_exc.py.exp @@ -0,0 +1,5 @@ +TypeError +TypeError +TypeError +TypeError +TypeError diff --git a/tests/micropython/io_badlength.py b/tests/micropython/io_badlength.py new file mode 100644 index 00000000000..646a2cd9241 --- /dev/null +++ b/tests/micropython/io_badlength.py @@ -0,0 +1,35 @@ +# Test when a use IOBase class has write/readinto which returns more data than +# requested (https://github.com/micropython/micropython/issues/18845) + +try: + import io, json +except: + print("SKIP") + raise SystemExit + + +class S(io.IOBase): + def write(self, buf): + assert len(buf) >= 0 + return 2 + + def ioctl(self, cmd, arg): + return 0 + + def readinto(self, buf): + assert len(buf) >= 0 + return 3 + + +try: + print("abc", file=S()) + print("write OK") +except OSError as e: + print("write failed, errno", e.errno) + +buf = bytearray(1) +try: + json.load(S()) + print("readinto OK") +except OSError as e: + print("read failed, errno", e.errno) diff --git a/tests/micropython/io_badlength.py.exp b/tests/micropython/io_badlength.py.exp new file mode 100644 index 00000000000..bba660dd3c8 --- /dev/null +++ b/tests/micropython/io_badlength.py.exp @@ -0,0 +1,2 @@ +write failed, errno 5 +read failed, errno 5 diff --git a/tests/micropython/kbd_intr.py b/tests/micropython/kbd_intr.py index 81977aaa52f..e1ed7185ef0 100644 --- a/tests/micropython/kbd_intr.py +++ b/tests/micropython/kbd_intr.py @@ -1,10 +1,10 @@ # test the micropython.kbd_intr() function -import micropython - try: + import micropython + micropython.kbd_intr -except AttributeError: +except (ImportError, AttributeError): print("SKIP") raise SystemExit diff --git a/tests/micropython/meminfo.py b/tests/micropython/meminfo.py index 9df341fbb83..f4dd8fdb604 100644 --- a/tests/micropython/meminfo.py +++ b/tests/micropython/meminfo.py @@ -1,12 +1,14 @@ # tests meminfo functions in micropython module -import micropython +try: + import micropython -# these functions are not always available -if not hasattr(micropython, "mem_info"): + micropython.mem_info +except (ImportError, AttributeError): print("SKIP") -else: - micropython.mem_info() - micropython.mem_info(1) - micropython.qstr_info() - micropython.qstr_info(1) + raise SystemExit + +micropython.mem_info() +micropython.mem_info(1) +micropython.qstr_info() +micropython.qstr_info(1) diff --git a/tests/micropython/memstats.py b/tests/micropython/memstats.py index dee3a4ce2f2..0e2e7b1c0b3 100644 --- a/tests/micropython/memstats.py +++ b/tests/micropython/memstats.py @@ -1,17 +1,19 @@ # tests meminfo functions in micropython module -import micropython +try: + import micropython -# these functions are not always available -if not hasattr(micropython, "mem_total"): + micropython.mem_total +except (ImportError, AttributeError): print("SKIP") -else: - t = micropython.mem_total() - c = micropython.mem_current() - p = micropython.mem_peak() + raise SystemExit - l = list(range(10000)) +t = micropython.mem_total() +c = micropython.mem_current() +p = micropython.mem_peak() - print(micropython.mem_total() > t) - print(micropython.mem_current() > c) - print(micropython.mem_peak() > p) +l = list(range(10000)) + +print(micropython.mem_total() > t) +print(micropython.mem_current() > c) +print(micropython.mem_peak() > p) diff --git a/tests/micropython/native_marshal.py b/tests/micropython/native_marshal.py new file mode 100644 index 00000000000..09a27a374b8 --- /dev/null +++ b/tests/micropython/native_marshal.py @@ -0,0 +1,45 @@ +# Test the marshal module in combination with native/viper functions. + +try: + import marshal + + (lambda: 0).__code__ +except (AttributeError, ImportError): + print("SKIP") + raise SystemExit + +import unittest + + +def f_native(): + @micropython.native + def g(): + pass + + return g + + +def f_viper(): + @micropython.viper + def g(): + pass + + return g + + +class Test(unittest.TestCase): + def test_native_function(self): + # Can't marshal a function with native code. + code = f_native.__code__ + with self.assertRaises(ValueError): + marshal.dumps(code) + + def test_viper_function(self): + # Can't marshal a function with viper code. + code = f_viper.__code__ + with self.assertRaises(ValueError): + marshal.dumps(code) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/micropython/native_with.py b/tests/micropython/native_with.py index 9c0b98af903..37c385a42f9 100644 --- a/tests/micropython/native_with.py +++ b/tests/micropython/native_with.py @@ -9,6 +9,7 @@ def __enter__(self): print("__enter__") def __exit__(self, a, b, c): + b = repr(b)[:10] # shorten exception to "NameError(" prefix for target compatibility print("__exit__", a, b, c) diff --git a/tests/micropython/native_with.py.exp b/tests/micropython/native_with.py.exp index 7e28663f6fc..b8083a4c66b 100644 --- a/tests/micropython/native_with.py.exp +++ b/tests/micropython/native_with.py.exp @@ -5,5 +5,5 @@ __exit__ None None None __init__ __enter__ 1 -__exit__ name 'fail' isn't defined None +__exit__ NameError( None NameError diff --git a/tests/micropython/opt_level.py b/tests/micropython/opt_level.py index dd5493a7a3c..789197d8825 100644 --- a/tests/micropython/opt_level.py +++ b/tests/micropython/opt_level.py @@ -1,4 +1,10 @@ -import micropython as micropython +# test micropython.opt_level() + +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit # check we can get and set the level micropython.opt_level(0) diff --git a/tests/micropython/opt_level_lineno.py b/tests/micropython/opt_level_lineno.py index 40650b68192..4ca76625de4 100644 --- a/tests/micropython/opt_level_lineno.py +++ b/tests/micropython/opt_level_lineno.py @@ -1,7 +1,24 @@ -import micropython as micropython +# test micropython.opt_level() and line numbers + +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit # check that level 3 doesn't store line numbers # the expected output is that any line is printed as "line 1" micropython.opt_level(3) -# CIRCUITPY-CHANGE: use traceback.print_exception() instead of sys.print_exception() -exec("try:\n xyz\nexcept NameError as er:\n import traceback\n traceback.print_exception(er)") + +# force bytecode emitter, because native emitter doesn't store line numbers +exec(""" +@micropython.bytecode +def f(): + try: + xyz + except NameError as er: + # CIRCUITPY-CHANGE: use traceback.print_exception() instead of sys.print_exception() + import traceback + traceback.print_exception(er) +f() +""") diff --git a/tests/micropython/opt_level_lineno.py.exp b/tests/micropython/opt_level_lineno.py.exp index 469b90ba793..b50f0628c81 100644 --- a/tests/micropython/opt_level_lineno.py.exp +++ b/tests/micropython/opt_level_lineno.py.exp @@ -1,3 +1,3 @@ Traceback (most recent call last): - File "", line 1, in + File "", line 1, in f NameError: name 'xyz' isn't defined diff --git a/tests/micropython/ringio_big.py b/tests/micropython/ringio_big.py new file mode 100644 index 00000000000..88d5d2cc165 --- /dev/null +++ b/tests/micropython/ringio_big.py @@ -0,0 +1,40 @@ +# Check that micropython.RingIO works correctly. + +try: + import micropython + + micropython.RingIO +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +results = [] + +try: + # The maximum possible size passed as an integer. + micropython.RingIO(65534) + + try: + # Size may not be too big + micropython.RingIO(65535) + except ValueError as ex: + results.append(type(ex)) + + # Allocate a buffer for use below. + buf_64k = memoryview(bytearray(65536)) + + # The maximum possible size passed as a buffer. + micropython.RingIO(buf_64k[:-1]) + + try: + # Buffer may not be too big + micropython.RingIO(buf_64k) + except ValueError as ex: + results.append(type(ex)) + +except MemoryError: + print("SKIP") + raise SystemExit + +for result in results: + print(result) diff --git a/tests/micropython/ringio_big.py.exp b/tests/micropython/ringio_big.py.exp new file mode 100644 index 00000000000..72af34b3838 --- /dev/null +++ b/tests/micropython/ringio_big.py.exp @@ -0,0 +1,2 @@ + + diff --git a/tests/micropython/schedule.py b/tests/micropython/schedule.py index 6a91459ea3d..e629edb3eb3 100644 --- a/tests/micropython/schedule.py +++ b/tests/micropython/schedule.py @@ -1,10 +1,12 @@ # test micropython.schedule() function - -import micropython +# this test should be manually kept in synch with +# tests/micrpython/schedule_sleep.py. try: + import micropython + micropython.schedule -except AttributeError: +except (ImportError, AttributeError): print("SKIP") raise SystemExit diff --git a/tests/micropython/schedule_kbd_intr.py b/tests/micropython/schedule_kbd_intr.py new file mode 100644 index 00000000000..ec7ef5a5d07 --- /dev/null +++ b/tests/micropython/schedule_kbd_intr.py @@ -0,0 +1,72 @@ +# Test using micropython.schedule() to schedule a KeyboardInterrupt. +# Note: this test cannot use unittest because the unittest overhead +# may trigger the scheduler when we don't want it to. + +try: + from time import sleep + from micropython import schedule, kbd_intr +except ImportError: + print("SKIP") + raise SystemExit + +######################################################################## +# Test basic scheduling. + +try: + schedule(kbd_intr, None) +except ValueError: + # Scheduling `kbd_intr` is not supported on this target. + print("SKIP") + raise SystemExit + +try: + sleep(0) + sleep(0) + print("fail") +except KeyboardInterrupt: + print("KeyboardInterrupt") + +######################################################################## +# Should be able to schedule it many times without error, and that +# should only trigger one KeyboardInterrupt. + +schedule(kbd_intr, None) +schedule(kbd_intr, None) +schedule(kbd_intr, None) +schedule(kbd_intr, None) +schedule(kbd_intr, None) +schedule(kbd_intr, None) +schedule(kbd_intr, None) +schedule(kbd_intr, None) +schedule(kbd_intr, None) +schedule(kbd_intr, None) +try: + sleep(0) + sleep(0) + print("fail") +except KeyboardInterrupt: + print("KeyboardInterrupt") + +# This should not raise. +for _ in range(100): + sleep(0) + +######################################################################## +# Test nested scheduling. + + +def callback(_): + schedule(kbd_intr, None) + # This should not raise because we are in schedule context. + for _ in range(100): + sleep(0) + + +schedule(callback, None) +sleep(0) +try: + sleep(0) + sleep(0) + print("fail") +except KeyboardInterrupt: + print("KeyboardInterrupt") diff --git a/tests/micropython/schedule_kbd_intr.py.exp b/tests/micropython/schedule_kbd_intr.py.exp new file mode 100644 index 00000000000..c4ba7730c52 --- /dev/null +++ b/tests/micropython/schedule_kbd_intr.py.exp @@ -0,0 +1,3 @@ +KeyboardInterrupt +KeyboardInterrupt +KeyboardInterrupt diff --git a/tests/micropython/schedule_sleep.py b/tests/micropython/schedule_sleep.py new file mode 100644 index 00000000000..9aadde7b084 --- /dev/null +++ b/tests/micropython/schedule_sleep.py @@ -0,0 +1,72 @@ +# test micropython.schedule() function +# this is the same as tests/micropython/schedule.py but the busy loops are +# replaced with sleep/sleep_ms which allows the test to succeed when run under +# the native emitter. + +try: + import micropython + import time + + micropython.schedule +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +# Basic test of scheduling a function. + + +def callback(arg): + global done + print(arg) + done = True + + +done = False +micropython.schedule(callback, 1) +while not done: + time.sleep(0) + +# Test that callbacks can be scheduled from within a callback, but +# that they don't execute until the outer callback is finished. + + +def callback_inner(arg): + global done + print("inner") + done += 1 + + +def callback_outer(arg): + global done + micropython.schedule(callback_inner, 0) + # need a loop so that the VM can check for pending events + for i in range(2): + pass + print("outer") + done += 1 + + +done = 0 +micropython.schedule(callback_outer, 0) +while done != 2: + time.sleep(0) + +# Test that scheduling too many callbacks leads to an exception. To do this we +# must schedule from within a callback to guarantee that the scheduler is locked. + + +def callback(arg): + global done + try: + for i in range(100): + micropython.schedule(lambda x: x, None) + except RuntimeError: + print("RuntimeError") + done = True + + +done = False +micropython.schedule(callback, None) +while not done: + time.sleep_ms(0) diff --git a/tests/micropython/schedule_sleep.py.exp b/tests/micropython/schedule_sleep.py.exp new file mode 100644 index 00000000000..c4a3e1227e2 --- /dev/null +++ b/tests/micropython/schedule_sleep.py.exp @@ -0,0 +1,4 @@ +1 +outer +inner +RuntimeError diff --git a/tests/micropython/stack_use.py b/tests/micropython/stack_use.py index 266885d9d18..5d36fdca2fe 100644 --- a/tests/micropython/stack_use.py +++ b/tests/micropython/stack_use.py @@ -1,7 +1,11 @@ # tests stack_use function in micropython module -import micropython -if not hasattr(micropython, "stack_use"): +try: + import micropython + + micropython.stack_use +except (ImportError, AttributeError): print("SKIP") -else: - print(type(micropython.stack_use())) # output varies + raise SystemExit + +print(type(micropython.stack_use())) # output varies diff --git a/tests/micropython/test_normalize_newlines.py b/tests/micropython/test_normalize_newlines.py new file mode 100644 index 00000000000..f19aaa69a3f --- /dev/null +++ b/tests/micropython/test_normalize_newlines.py @@ -0,0 +1,14 @@ +# Test for normalize_newlines functionality +# This test verifies that test framework handles various newline combinations correctly + +# Note: This is more of an integration test since normalize_newlines is in the test framework +# The actual testing happens when this test is run through run-tests.py + +print("Testing newline handling") +print("Line 1\r\nLine 2") # Windows-style line ending - should be normalized +print("Line 3") # Normal line +print("Line 4") # Normal line +print("Line 5\nLine 6") # Unix-style line ending - already normalized + +# Test that literal \r in strings is preserved +print(repr("test\rstring")) # Should show 'test\rstring' not 'test\nstring' diff --git a/tests/micropython/test_normalize_newlines.py.exp b/tests/micropython/test_normalize_newlines.py.exp new file mode 100644 index 00000000000..c4395468cf1 --- /dev/null +++ b/tests/micropython/test_normalize_newlines.py.exp @@ -0,0 +1,8 @@ +Testing newline handling +Line 1 +Line 2 +Line 3 +Line 4 +Line 5 +Line 6 +'test\rstring' diff --git a/tests/micropython/viper_error.py b/tests/micropython/viper_error.py index 6c5c3ba2007..e58a3c59fa0 100644 --- a/tests/micropython/viper_error.py +++ b/tests/micropython/viper_error.py @@ -1,19 +1,19 @@ # test syntax and type errors specific to viper code generation -def test(code): +def test(code, msg): try: exec(code) except (SyntaxError, ViperTypeError, NotImplementedError) as e: - print(repr(e)) + print(type(e), str(e) or msg) # viper: annotations must be identifiers -test("@micropython.viper\ndef f(a:1): pass") -test("@micropython.viper\ndef f() -> 1: pass") +test("@micropython.viper\ndef f(a:1): pass", "annotation must be an identifier") +test("@micropython.viper\ndef f() -> 1: pass", "annotation must be an identifier") # unknown type -test("@micropython.viper\ndef f(x:unknown_type): pass") +test("@micropython.viper\ndef f(x:unknown_type): pass", "unknown type 'unknown_type'") # local used before type known test( @@ -22,7 +22,8 @@ def test(code): def f(): print(x) x = 1 -""" +""", + "local 'x' used before type known", ) # type mismatch storing to local @@ -33,7 +34,8 @@ def f(): x = 1 y = [] x = y -""" +""", + "local 'x' has type 'int' but source is 'object'", ) # can't implicitly convert type to bool @@ -44,47 +46,52 @@ def f(): x = ptr(0) if x: pass -""" +""", + "can't implicitly convert 'ptr' to 'bool'", ) # incorrect return type -test("@micropython.viper\ndef f() -> int: return []") +test("@micropython.viper\ndef f() -> int: return []", "return expected 'int' but got 'object'") # can't do unary op of incompatible type -test("@micropython.viper\ndef f(x:ptr): -x") +test("@micropython.viper\ndef f(x:ptr): -x", "can't do unary op of 'ptr'") # can't do binary op between incompatible types -test("@micropython.viper\ndef f(): 1 + []") -test("@micropython.viper\ndef f(x:int, y:uint): x < y") +test("@micropython.viper\ndef f(): 1 + []", "can't do binary op between 'int' and 'object'") +test("@micropython.viper\ndef f(x:int, y:uint): x < y", "comparison of int and uint") # can't load -test("@micropython.viper\ndef f(): 1[0]") -test("@micropython.viper\ndef f(): 1[x]") +test("@micropython.viper\ndef f(): 1[0]", "can't load from 'int'") +test("@micropython.viper\ndef f(): 1[x]", "can't load from 'int'") # can't store -test("@micropython.viper\ndef f(): 1[0] = 1") -test("@micropython.viper\ndef f(): 1[x] = 1") -test("@micropython.viper\ndef f(x:int): x[0] = x") -test("@micropython.viper\ndef f(x:ptr32): x[0] = None") -test("@micropython.viper\ndef f(x:ptr32): x[x] = None") +test("@micropython.viper\ndef f(): 1[0] = 1", "can't store to 'int'") +test("@micropython.viper\ndef f(): 1[x] = 1", "can't store to 'int'") +test("@micropython.viper\ndef f(x:int): x[0] = x", "can't store to 'int'") +test("@micropython.viper\ndef f(x:ptr32): x[0] = None", "can't store 'None'") +test("@micropython.viper\ndef f(x:ptr32): x[x] = None", "can't store 'None'") # must raise an object -test("@micropython.viper\ndef f(): raise 1") +test("@micropython.viper\ndef f(): raise 1", "must raise an object") # unary ops not implemented -test("@micropython.viper\ndef f(x:int): not x") +test("@micropython.viper\ndef f(x:int): not x", "'not' not implemented") # binary op not implemented -test("@micropython.viper\ndef f(x:uint, y:uint): res = x // y") -test("@micropython.viper\ndef f(x:uint, y:uint): res = x % y") -test("@micropython.viper\ndef f(x:int): res = x in x") +test("@micropython.viper\ndef f(x:uint, y:uint): res = x // y", "div/mod not implemented for uint") +test("@micropython.viper\ndef f(x:uint, y:uint): res = x % y", "div/mod not implemented for uint") +test("@micropython.viper\ndef f(x:int): res = x in x", "binary op not implemented") + +# raise with 0 or 2 args not implemented +test("@micropython.viper\ndef f():\n try:\n x\n except:\n raise\n", "native raise") +test("@micropython.viper\ndef f(): raise Exception from Exception", "native raise") # yield (from) not implemented -test("@micropython.viper\ndef f(): yield") -test("@micropython.viper\ndef f(): yield from f") +test("@micropython.viper\ndef f(): yield", "native yield") +test("@micropython.viper\ndef f(): yield from f", "native yield") # passing a ptr to a Python function not implemented -test("@micropython.viper\ndef f(): print(ptr(1))") +test("@micropython.viper\ndef f(): print(ptr(1))", "conversion to object") # cast of a casting identifier not implemented -test("@micropython.viper\ndef f(): int(int)") +test("@micropython.viper\ndef f(): int(int)", "casting") diff --git a/tests/micropython/viper_error.py.exp b/tests/micropython/viper_error.py.exp index 51cbd6c7097..9b663b8508a 100644 --- a/tests/micropython/viper_error.py.exp +++ b/tests/micropython/viper_error.py.exp @@ -1,26 +1,28 @@ -SyntaxError('annotation must be an identifier',) -SyntaxError('annotation must be an identifier',) -ViperTypeError("unknown type 'unknown_type'",) -ViperTypeError("local 'x' used before type known",) -ViperTypeError("local 'x' has type 'int' but source is 'object'",) -ViperTypeError("can't implicitly convert 'ptr' to 'bool'",) -ViperTypeError("return expected 'int' but got 'object'",) -ViperTypeError("can't do unary op of 'ptr'",) -ViperTypeError("can't do binary op between 'int' and 'object'",) -ViperTypeError('comparison of int and uint',) -ViperTypeError("can't load from 'int'",) -ViperTypeError("can't load from 'int'",) -ViperTypeError("can't store to 'int'",) -ViperTypeError("can't store to 'int'",) -ViperTypeError("can't store to 'int'",) -ViperTypeError("can't store 'None'",) -ViperTypeError("can't store 'None'",) -ViperTypeError('must raise an object',) -ViperTypeError("'not' not implemented",) -ViperTypeError('div/mod not implemented for uint',) -ViperTypeError('div/mod not implemented for uint',) -ViperTypeError('binary op not implemented',) -NotImplementedError('native yield',) -NotImplementedError('native yield',) -NotImplementedError('conversion to object',) -NotImplementedError('casting',) + annotation must be an identifier + annotation must be an identifier + unknown type 'unknown_type' + local 'x' used before type known + local 'x' has type 'int' but source is 'object' + can't implicitly convert 'ptr' to 'bool' + return expected 'int' but got 'object' + can't do unary op of 'ptr' + can't do binary op between 'int' and 'object' + comparison of int and uint + can't load from 'int' + can't load from 'int' + can't store to 'int' + can't store to 'int' + can't store to 'int' + can't store 'None' + can't store 'None' + must raise an object + 'not' not implemented + div/mod not implemented for uint + div/mod not implemented for uint + binary op not implemented + native raise + native raise + native yield + native yield + conversion to object + casting diff --git a/tests/micropython/viper_large_jump.py b/tests/micropython/viper_large_jump.py new file mode 100644 index 00000000000..1c5913dec1e --- /dev/null +++ b/tests/micropython/viper_large_jump.py @@ -0,0 +1,20 @@ +COUNT = 600 + + +try: + code = """ +@micropython.viper +def f() -> int: + x = 0 + while x < 10: +""" + for i in range(COUNT): + code += " x += 1\n" + code += " return x" + exec(code) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + + +print(f()) diff --git a/tests/micropython/viper_large_jump.py.exp b/tests/micropython/viper_large_jump.py.exp new file mode 100644 index 00000000000..e9f960cf4ac --- /dev/null +++ b/tests/micropython/viper_large_jump.py.exp @@ -0,0 +1 @@ +600 diff --git a/tests/micropython/viper_preserve_invariants.py b/tests/micropython/viper_preserve_invariants.py new file mode 100644 index 00000000000..26f6003aba7 --- /dev/null +++ b/tests/micropython/viper_preserve_invariants.py @@ -0,0 +1,39 @@ +RESULTS = [] + +LOAD_TEMPLATE_REG = """ +BUFFER = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) +OFFSET = 1 +@micropython.viper +def test_invariants_load{}_reg(buf: ptr{}, offset: int): + offset_copy1: int = offset + temporary1 = buf[offset] + offset_copy2: int = offset + temporary2 = buf[offset] + RESULTS.append(["LOAD{}", temporary1 == temporary2, offset == offset_copy1 == offset_copy2]) +test_invariants_load{}_reg(BUFFER, OFFSET) +""" + + +STORE_TEMPLATE_REG = """ +BUFFER = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) +OFFSET = 1 +@micropython.viper +def test_invariants_store{}_reg(buf: ptr{}, offset: int): + offset_copy: int = offset + value: uint = {} + buf[offset] = value + temporary = buf[offset] + RESULTS.append(["STORE{}", temporary == value, offset == offset_copy]) +test_invariants_store{}_reg(BUFFER, OFFSET) +""" + +try: + for width, value in ((8, 0x11), (16, 0x1111), (32, 0x11111111)): + exec(LOAD_TEMPLATE_REG.format(width, width, width, width, width)) + exec(STORE_TEMPLATE_REG.format(width, width, value, width, width, width)) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + +for line in RESULTS: + print(" ".join([str(i) for i in line])) diff --git a/tests/micropython/viper_preserve_invariants.py.exp b/tests/micropython/viper_preserve_invariants.py.exp new file mode 100644 index 00000000000..21c66252430 --- /dev/null +++ b/tests/micropython/viper_preserve_invariants.py.exp @@ -0,0 +1,6 @@ +LOAD8 True True +STORE8 True True +LOAD16 True True +STORE16 True True +LOAD32 True True +STORE32 True True diff --git a/tests/micropython/viper_ptr16_load_boundary.py b/tests/micropython/viper_ptr16_load_boundary.py new file mode 100644 index 00000000000..0d4c3105b68 --- /dev/null +++ b/tests/micropython/viper_ptr16_load_boundary.py @@ -0,0 +1,39 @@ +# Test boundary conditions for various architectures + +GET_TEMPLATE = """ +@micropython.viper +def get{off}(src: ptr16) -> uint: + return uint(src[{off}]) +print(hex(get{off}(buffer))) +""" + + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 2 + + +@micropython.viper +def get_index(src: ptr16, i: int) -> int: + return src[i] + + +def data(start, len): + output = bytearray(len) + for idx in range(len): + output[idx] = (start + idx) & 0xFF + return output + + +buffer = bytearray((((1 << max(BIT_THRESHOLDS)) + 1) // 1024) * 1024) +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = ((1 << bit) - (2 * SIZE), (1 << bit) - (1 * SIZE), 1 << bit) + buffer[pre:post] = data(val, 3 * SIZE) + val = val + (3 * SIZE) + + pre, idx, post = pre // SIZE, idx // SIZE, post // SIZE + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) + exec(GET_TEMPLATE.format(off=pre)) + exec(GET_TEMPLATE.format(off=idx)) + exec(GET_TEMPLATE.format(off=post)) diff --git a/tests/micropython/viper_ptr16_load_boundary.py.exp b/tests/micropython/viper_ptr16_load_boundary.py.exp new file mode 100644 index 00000000000..56f1d322904 --- /dev/null +++ b/tests/micropython/viper_ptr16_load_boundary.py.exp @@ -0,0 +1,20 @@ +--- 5 +0x100 0x302 0x504 +0x100 +0x302 +0x504 +--- 8 +0x706 0x908 0xb0a +0x706 +0x908 +0xb0a +--- 11 +0xd0c 0xf0e 0x1110 +0xd0c +0xf0e +0x1110 +--- 12 +0x1312 0x1514 0x1716 +0x1312 +0x1514 +0x1716 diff --git a/tests/micropython/viper_ptr16_store_boundary.py b/tests/micropython/viper_ptr16_store_boundary.py new file mode 100644 index 00000000000..7c774d4d1ca --- /dev/null +++ b/tests/micropython/viper_ptr16_store_boundary.py @@ -0,0 +1,63 @@ +# Test boundary conditions for various architectures + +SET_TEMPLATE = """ +@micropython.viper +def set{off}(dest: ptr16): + saved = dest + dest[{off}] = {val} + assert int(saved) == int(dest) +""" + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 2 +MASK = (1 << (8 * SIZE)) - 1 + +next_int = 1 +test_buffer = bytearray(SIZE) + + +def next_value() -> uint: + global next_int + global test_buffer + for index in range(1, SIZE): + test_buffer[index - 1] = test_buffer[index] + test_buffer[SIZE - 1] = next_int + next_int += 1 + output = 0 + for byte in test_buffer: + output = (output << 8) | byte + return output & MASK + + +def get_index(src, i): + return src[i * SIZE] + (src[(i * SIZE) + 1] << 8) + + +@micropython.viper +def set_index(dest: ptr16, i: int, val: uint): + saved = dest + dest[i] = val + assert int(saved) == int(dest) + + +try: + buffer = bytearray((((1 << max(BIT_THRESHOLDS)) // 1024) + 1) * 1024) + + for bit in BIT_THRESHOLDS: + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + exec(SET_TEMPLATE.format(off=(offset + index) // SIZE, val=next_value())) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + + +for bit in BIT_THRESHOLDS: + print("---", bit) + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + globals()["set{}".format((offset + index) // SIZE)](buffer) + print(hex(get_index(buffer, (offset + index) // SIZE))) + for index in range(0, 3 * SIZE, SIZE): + set_index(buffer, (offset + index) // SIZE, next_value()) + print(hex(get_index(buffer, (offset + index) // SIZE))) diff --git a/tests/micropython/viper_ptr16_store_boundary.py.exp b/tests/micropython/viper_ptr16_store_boundary.py.exp new file mode 100644 index 00000000000..007a50b3eda --- /dev/null +++ b/tests/micropython/viper_ptr16_store_boundary.py.exp @@ -0,0 +1,28 @@ +--- 5 +0x1 +0x102 +0x203 +0xc0d +0xd0e +0xe0f +--- 8 +0x304 +0x405 +0x506 +0xf10 +0x1011 +0x1112 +--- 11 +0x607 +0x708 +0x809 +0x1213 +0x1314 +0x1415 +--- 12 +0x90a +0xa0b +0xb0c +0x1516 +0x1617 +0x1718 diff --git a/tests/micropython/viper_ptr32_load_boundary.py b/tests/micropython/viper_ptr32_load_boundary.py new file mode 100644 index 00000000000..971d1113c49 --- /dev/null +++ b/tests/micropython/viper_ptr32_load_boundary.py @@ -0,0 +1,39 @@ +# Test boundary conditions for various architectures + +GET_TEMPLATE = """ +@micropython.viper +def get{off}(src: ptr32) -> uint: + return uint(src[{off}]) +print(hex(get{off}(buffer))) +""" + + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 4 + + +@micropython.viper +def get_index(src: ptr32, i: int) -> int: + return src[i] + + +def data(start, len): + output = bytearray(len) + for idx in range(len): + output[idx] = (start + idx) & 0xFF + return output + + +buffer = bytearray((((1 << max(BIT_THRESHOLDS)) + 1) // 1024) * 1024) +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = (((1 << bit) - (2 * SIZE)), ((1 << bit) - (1 * SIZE)), (1 << bit)) + buffer[pre:post] = data(val, 3 * SIZE) + val = val + (3 * SIZE) + + pre, idx, post = pre // SIZE, idx // SIZE, post // SIZE + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) + exec(GET_TEMPLATE.format(off=pre)) + exec(GET_TEMPLATE.format(off=idx)) + exec(GET_TEMPLATE.format(off=post)) diff --git a/tests/micropython/viper_ptr32_load_boundary.py.exp b/tests/micropython/viper_ptr32_load_boundary.py.exp new file mode 100644 index 00000000000..1e22a8b3613 --- /dev/null +++ b/tests/micropython/viper_ptr32_load_boundary.py.exp @@ -0,0 +1,20 @@ +--- 5 +0x3020100 0x7060504 0xb0a0908 +0x3020100 +0x7060504 +0xb0a0908 +--- 8 +0xf0e0d0c 0x13121110 0x17161514 +0xf0e0d0c +0x13121110 +0x17161514 +--- 11 +0x1b1a1918 0x1f1e1d1c 0x23222120 +0x1b1a1918 +0x1f1e1d1c +0x23222120 +--- 12 +0x27262524 0x2b2a2928 0x2f2e2d2c +0x27262524 +0x2b2a2928 +0x2f2e2d2c diff --git a/tests/micropython/viper_ptr32_store_boundary.py b/tests/micropython/viper_ptr32_store_boundary.py new file mode 100644 index 00000000000..96ca74ad3ca --- /dev/null +++ b/tests/micropython/viper_ptr32_store_boundary.py @@ -0,0 +1,68 @@ +# Test boundary conditions for various architectures + +SET_TEMPLATE = """ +@micropython.viper +def set{off}(dest: ptr32): + saved = dest + dest[{off}] = {val} + assert int(saved) == int(dest) +""" + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 4 +MASK = (1 << (8 * SIZE)) - 1 + +next_int = 1 +test_buffer = bytearray(SIZE) + + +def next_value() -> uint: + global next_int + global test_buffer + for index in range(1, SIZE): + test_buffer[index - 1] = test_buffer[index] + test_buffer[SIZE - 1] = next_int + next_int += 1 + output = 0 + for byte in test_buffer: + output = (output << 8) | byte + return output & MASK + + +def get_index(src, i): + return ( + src[i * SIZE] + + (src[(i * SIZE) + 1] << 8) + + (src[(i * SIZE) + 2] << 16) + + (src[(i * SIZE) + 3] << 24) + ) + + +@micropython.viper +def set_index(dest: ptr32, i: int, val: uint): + saved = dest + dest[i] = val + assert int(dest) == int(saved) + + +try: + buffer = bytearray((((1 << max(BIT_THRESHOLDS)) // 1024) + 1) * 1024) + + for bit in BIT_THRESHOLDS: + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + exec(SET_TEMPLATE.format(off=(offset + index) // SIZE, val=next_value())) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + + +for bit in BIT_THRESHOLDS: + print("---", bit) + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + globals()["set{}".format((offset + index) // SIZE)](buffer) + print(hex(get_index(buffer, (offset + index) // SIZE))) + for index in range(0, 3 * SIZE, SIZE): + set_index(buffer, (offset + index) // SIZE, next_value()) + print(hex(get_index(buffer, (offset + index) // SIZE))) diff --git a/tests/micropython/viper_ptr32_store_boundary.py.exp b/tests/micropython/viper_ptr32_store_boundary.py.exp new file mode 100644 index 00000000000..7a9a5162474 --- /dev/null +++ b/tests/micropython/viper_ptr32_store_boundary.py.exp @@ -0,0 +1,28 @@ +--- 5 +0x1 +0x102 +0x10203 +0xa0b0c0d +0xb0c0d0e +0xc0d0e0f +--- 8 +0x1020304 +0x2030405 +0x3040506 +0xd0e0f10 +0xe0f1011 +0xf101112 +--- 11 +0x4050607 +0x5060708 +0x6070809 +0x10111213 +0x11121314 +0x12131415 +--- 12 +0x708090a +0x8090a0b +0x90a0b0c +0x13141516 +0x14151617 +0x15161718 diff --git a/tests/micropython/viper_ptr8_load_boundary.py b/tests/micropython/viper_ptr8_load_boundary.py new file mode 100644 index 00000000000..57e06da5709 --- /dev/null +++ b/tests/micropython/viper_ptr8_load_boundary.py @@ -0,0 +1,38 @@ +# Test boundary conditions for various architectures + +GET_TEMPLATE = """ +@micropython.viper +def get{off}(src: ptr8) -> uint: + return uint(src[{off}]) +print(hex(get{off}(buffer))) +""" + + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 1 + + +@micropython.viper +def get_index(src: ptr8, i: int) -> int: + return src[i] + + +def data(start, len): + output = bytearray(len) + for idx in range(len): + output[idx] = (start + idx) & 0xFF + return output + + +buffer = bytearray((((1 << max(BIT_THRESHOLDS)) + 1) // 1024) * 1024) +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = (((1 << bit) - (2 * SIZE)), ((1 << bit) - (1 * SIZE)), (1 << bit)) + buffer[pre:post] = data(val, 3 * SIZE) + val = val + (3 * SIZE) + + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) + exec(GET_TEMPLATE.format(off=pre)) + exec(GET_TEMPLATE.format(off=idx)) + exec(GET_TEMPLATE.format(off=post)) diff --git a/tests/micropython/viper_ptr8_load_boundary.py.exp b/tests/micropython/viper_ptr8_load_boundary.py.exp new file mode 100644 index 00000000000..a0e423686b8 --- /dev/null +++ b/tests/micropython/viper_ptr8_load_boundary.py.exp @@ -0,0 +1,20 @@ +--- 5 +0x0 0x1 0x2 +0x0 +0x1 +0x2 +--- 8 +0x3 0x4 0x5 +0x3 +0x4 +0x5 +--- 11 +0x6 0x7 0x8 +0x6 +0x7 +0x8 +--- 12 +0x9 0xa 0xb +0x9 +0xa +0xb diff --git a/tests/micropython/viper_ptr8_store_boundary.py b/tests/micropython/viper_ptr8_store_boundary.py new file mode 100644 index 00000000000..68b76fd598b --- /dev/null +++ b/tests/micropython/viper_ptr8_store_boundary.py @@ -0,0 +1,63 @@ +# Test boundary conditions for various architectures + +SET_TEMPLATE = """ +@micropython.viper +def set{off}(dest: ptr8): + saved = dest + dest[{off}] = {val} + assert int(saved) == int(dest) +""" + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 1 +MASK = (1 << (8 * SIZE)) - 1 + +next_int = 1 +test_buffer = bytearray(SIZE) + + +def next_value() -> uint: + global next_int + global test_buffer + for index in range(1, SIZE): + test_buffer[index - 1] = test_buffer[index] + test_buffer[SIZE - 1] = next_int + next_int += 1 + output = 0 + for byte in test_buffer: + output = (output << 8) | byte + return output & MASK + + +def get_index(src: ptr8, i: int): + return src[i] + + +@micropython.viper +def set_index(dest: ptr8, i: int, val: uint): + saved = dest + dest[i] = val + assert int(dest) == int(saved) + + +try: + buffer = bytearray((((1 << max(BIT_THRESHOLDS)) // 1024) + 1) * 1024) + + for bit in BIT_THRESHOLDS: + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + exec(SET_TEMPLATE.format(off=(offset + index) // SIZE, val=next_value())) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + + +for bit in BIT_THRESHOLDS: + print("---", bit) + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + globals()["set{}".format((offset + index) // SIZE)](buffer) + print(hex(get_index(buffer, (offset + index) // SIZE))) + for index in range(0, 3 * SIZE, SIZE): + set_index(buffer, (offset + index) // SIZE, next_value()) + print(hex(get_index(buffer, (offset + index) // SIZE))) diff --git a/tests/micropython/viper_ptr8_store_boundary.py.exp b/tests/micropython/viper_ptr8_store_boundary.py.exp new file mode 100644 index 00000000000..621295d81a8 --- /dev/null +++ b/tests/micropython/viper_ptr8_store_boundary.py.exp @@ -0,0 +1,28 @@ +--- 5 +0x1 +0x2 +0x3 +0xd +0xe +0xf +--- 8 +0x4 +0x5 +0x6 +0x10 +0x11 +0x12 +--- 11 +0x7 +0x8 +0x9 +0x13 +0x14 +0x15 +--- 12 +0xa +0xb +0xc +0x16 +0x17 +0x18 diff --git a/tests/micropython/viper_unop.py b/tests/micropython/viper_unop.py index 61cbd5125f1..80c247a581e 100644 --- a/tests/micropython/viper_unop.py +++ b/tests/micropython/viper_unop.py @@ -29,3 +29,36 @@ def inv(x: int) -> int: print(inv(0)) print(inv(1)) print(inv(-2)) + + +@micropython.viper +def posc() -> int: + x = -1 + x1 = +x + assert x == -1 + return x1 + + +print(posc()) + + +@micropython.viper +def negc() -> int: + x = -1 + x1 = -x + assert x == -1 + return x1 + + +print(negc()) + + +@micropython.viper +def invc() -> int: + x = -1 + x1 = ~x + assert x == -1 + return x1 + + +print(invc()) diff --git a/tests/micropython/viper_unop.py.exp b/tests/micropython/viper_unop.py.exp index 6d93312caa1..9e9a5f4715f 100644 --- a/tests/micropython/viper_unop.py.exp +++ b/tests/micropython/viper_unop.py.exp @@ -7,3 +7,6 @@ -1 -2 1 +-1 +1 +0 diff --git a/tests/micropython/viper_with.py b/tests/micropython/viper_with.py index 40fbf6fb315..833a6babe7d 100644 --- a/tests/micropython/viper_with.py +++ b/tests/micropython/viper_with.py @@ -9,6 +9,7 @@ def __enter__(self): print("__enter__") def __exit__(self, a, b, c): + b = repr(b)[:10] # shorten exception to "NameError(" prefix for target compatibility print("__exit__", a, b, c) diff --git a/tests/micropython/viper_with.py.exp b/tests/micropython/viper_with.py.exp index 7e28663f6fc..b8083a4c66b 100644 --- a/tests/micropython/viper_with.py.exp +++ b/tests/micropython/viper_with.py.exp @@ -5,5 +5,5 @@ __exit__ None None None __init__ __enter__ 1 -__exit__ name 'fail' isn't defined None +__exit__ NameError( None NameError diff --git a/tests/misc/cexample_subclass.py b/tests/misc/cexample_subclass.py index 9f52a2c737a..6857788e5dc 100644 --- a/tests/misc/cexample_subclass.py +++ b/tests/misc/cexample_subclass.py @@ -2,6 +2,7 @@ try: from cexample import AdvancedTimer + import time # used to skip this test on minimal unix variant except ImportError: print("SKIP") raise SystemExit diff --git a/tests/misc/features.py b/tests/misc/features.py index 455b44fb1ef..3db88118144 100644 --- a/tests/misc/features.py +++ b/tests/misc/features.py @@ -103,7 +103,7 @@ class c25: x = c25() print(x.x) - raise + raise Exception except: print(26) print(27 + zero) diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index 31c9fa17c3b..8608f2322f8 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -39,7 +39,7 @@ except NotImplementedError: print("NotImplementedError") -# uPy raises TypeError, should be ValueError +# MicroPython raises TypeError, should be ValueError try: "%c" % b"\x01\x02" except (TypeError, ValueError): @@ -100,10 +100,10 @@ print("NotImplementedError") # CIRCUITPY-CHANGE: We do check these. -# struct pack with too many args, not checked by uPy +# struct pack with too many args, not checked by MicroPython # print(struct.pack("bb", 1, 2, 3)) -# struct pack with too few args, not checked by uPy +# struct pack with too few args, not checked by MicroPython # print(struct.pack("bb", 1)) # array slice assignment with unsupported RHS diff --git a/tests/misc/non_compliant_lexer.py b/tests/misc/non_compliant_lexer.py index e1c21f3d713..04c605953e7 100644 --- a/tests/misc/non_compliant_lexer.py +++ b/tests/misc/non_compliant_lexer.py @@ -11,7 +11,7 @@ def test(code): print("NotImplementedError") -# uPy requires spaces between literal numbers and keywords, CPy doesn't +# MPy requires spaces between literal numbers and keywords, CPy doesn't try: eval("1and 0") except SyntaxError: diff --git a/tests/misc/print_exception.py.native.exp b/tests/misc/print_exception.py.native.exp new file mode 100644 index 00000000000..59e856ae3c4 --- /dev/null +++ b/tests/misc/print_exception.py.native.exp @@ -0,0 +1,18 @@ +caught +Exception: msg + +caught +Exception: fail + +finally +caught +Exception: fail + +reraise +Exception: fail + +caught +Exception: fail + +AttributeError: 'function' object has no attribute 'X' + diff --git a/tests/misc/rge_sm.py b/tests/misc/rge_sm.py index 5e071687c49..3c30817952f 100644 --- a/tests/misc/rge_sm.py +++ b/tests/misc/rge_sm.py @@ -39,14 +39,6 @@ def solve(self, finishtime): if not self.iterate(): break - def solveNSteps(self, nSteps): - for i in range(nSteps): - if not self.iterate(): - break - - def series(self): - return zip(*self.Trajectory) - # 1-loop RGES for the main parameters of the SM # couplings are: g1, g2, g3 of U(1), SU(2), SU(3); yt (top Yukawa), lambda (Higgs quartic) @@ -55,85 +47,60 @@ def series(self): lambda *a: 41.0 / 96.0 / math.pi**2 * a[1] ** 3, # g1 lambda *a: -19.0 / 96.0 / math.pi**2 * a[2] ** 3, # g2 lambda *a: -42.0 / 96.0 / math.pi**2 * a[3] ** 3, # g3 - lambda *a: 1.0 - / 16.0 - / math.pi**2 - * ( - 9.0 / 2.0 * a[4] ** 3 - - 8.0 * a[3] ** 2 * a[4] - - 9.0 / 4.0 * a[2] ** 2 * a[4] - - 17.0 / 12.0 * a[1] ** 2 * a[4] + lambda *a: ( + 1.0 + / 16.0 + / math.pi**2 + * ( + 9.0 / 2.0 * a[4] ** 3 + - 8.0 * a[3] ** 2 * a[4] + - 9.0 / 4.0 * a[2] ** 2 * a[4] + - 17.0 / 12.0 * a[1] ** 2 * a[4] + ) ), # yt - lambda *a: 1.0 - / 16.0 - / math.pi**2 - * ( - 24.0 * a[5] ** 2 - + 12.0 * a[4] ** 2 * a[5] - - 9.0 * a[5] * (a[2] ** 2 + 1.0 / 3.0 * a[1] ** 2) - - 6.0 * a[4] ** 4 - + 9.0 / 8.0 * a[2] ** 4 - + 3.0 / 8.0 * a[1] ** 4 - + 3.0 / 4.0 * a[2] ** 2 * a[1] ** 2 + lambda *a: ( + 1.0 + / 16.0 + / math.pi**2 + * ( + 24.0 * a[5] ** 2 + + 12.0 * a[4] ** 2 * a[5] + - 9.0 * a[5] * (a[2] ** 2 + 1.0 / 3.0 * a[1] ** 2) + - 6.0 * a[4] ** 4 + + 9.0 / 8.0 * a[2] ** 4 + + 3.0 / 8.0 * a[1] ** 4 + + 3.0 / 4.0 * a[2] ** 2 * a[1] ** 2 + ) ), # lambda ) -def drange(start, stop, step): - r = start - while r < stop: - yield r - r += step - - -def phaseDiagram(system, trajStart, trajPlot, h=0.1, tend=1.0, range=1.0): - tstart = 0.0 - for i in drange(0, range, 0.1 * range): - for j in drange(0, range, 0.1 * range): - rk = RungeKutta(system, trajStart(i, j), tstart, h) - rk.solve(tend) - # draw the line - for tr in rk.Trajectory: - x, y = trajPlot(tr) - print(x, y) - print() - # draw the arrow - continue - l = (len(rk.Trajectory) - 1) / 3 - if l > 0 and 2 * l < len(rk.Trajectory): - p1 = rk.Trajectory[l] - p2 = rk.Trajectory[2 * l] - x1, y1 = trajPlot(p1) - x2, y2 = trajPlot(p2) - dx = -0.5 * (y2 - y1) # orthogonal to line - dy = 0.5 * (x2 - x1) # orthogonal to line - # l = math.sqrt(dx*dx + dy*dy) - # if abs(l) > 1e-3: - # l = 0.1 / l - # dx *= l - # dy *= l - print(x1 + dx, y1 + dy) - print(x2, y2) - print(x1 - dx, y1 - dy) - print() - - def singleTraj(system, trajStart, h=0.02, tend=1.0): + is_REPR_C = float("1.0000001") == float("1.0") tstart = 0.0 # compute the trajectory rk = RungeKutta(system, trajStart, tstart, h) - rk.solve(tend) + try: + rk.solve(tend) + except MemoryError: + print("SKIP") + raise SystemExit # print out trajectory for i in range(len(rk.Trajectory)): tr = rk.Trajectory[i] - print(" ".join(["{:.4f}".format(t) for t in tr])) - + tr_str = " ".join(["{:.4f}".format(t) for t in tr]) + if is_REPR_C: + # allow two small deviations for REPR_C + if tr_str == "1.0000 0.3559 0.6485 1.1944 0.9271 0.1083": + tr_str = "1.0000 0.3559 0.6485 1.1944 0.9272 0.1083" + if tr_str == "16.0000 0.3894 0.5793 0.7017 0.5686 -0.0168": + tr_str = "16.0000 0.3894 0.5793 0.7017 0.5686 -0.0167" + print(tr_str) -# phaseDiagram(sysSM, (lambda i, j: [0.354, 0.654, 1.278, 0.8 + 0.2 * i, 0.1 + 0.1 * j]), (lambda a: (a[4], a[5])), h=0.1, tend=math.log(10**17)) # initial conditions at M_Z singleTraj(sysSM, [0.354, 0.654, 1.278, 0.983, 0.131], h=0.5, tend=math.log(10**17)) # true values diff --git a/tests/misc/sys_exc_info.py b/tests/misc/sys_exc_info.py index d7e8a2d943b..c076dd572b0 100644 --- a/tests/misc/sys_exc_info.py +++ b/tests/misc/sys_exc_info.py @@ -8,13 +8,14 @@ def f(): - print(sys.exc_info()[0:2]) + e = sys.exc_info() + print(e[0], e[1]) try: raise ValueError("value", 123) except: - print(sys.exc_info()[0:2]) + print(sys.exc_info()[0], sys.exc_info()[1]) f() # Outside except block, sys.exc_info() should be back to None's diff --git a/tests/misc/sys_settrace_cov.py b/tests/misc/sys_settrace_cov.py new file mode 100644 index 00000000000..579c8a4a25e --- /dev/null +++ b/tests/misc/sys_settrace_cov.py @@ -0,0 +1,23 @@ +import sys + +try: + sys.settrace +except AttributeError: + print("SKIP") + raise SystemExit + + +def trace_tick_handler(frame, event, arg): + print("FRAME", frame) + print("LASTI", frame.f_lasti) + return None + + +def f(): + x = 3 + return x + + +sys.settrace(trace_tick_handler) +f() +sys.settrace(None) diff --git a/tests/misc/sys_settrace_cov.py.exp b/tests/misc/sys_settrace_cov.py.exp new file mode 100644 index 00000000000..423d78ec42b --- /dev/null +++ b/tests/misc/sys_settrace_cov.py.exp @@ -0,0 +1,2 @@ +FRAME +LASTI \\d\+ diff --git a/tests/multi_extmod/machine_can_01_rxtx_simple.py b/tests/multi_extmod/machine_can_01_rxtx_simple.py new file mode 100644 index 00000000000..fbc7692926d --- /dev/null +++ b/tests/multi_extmod/machine_can_01_rxtx_simple.py @@ -0,0 +1,35 @@ +from machine import CAN +import time + +ID_0 = 0x50 +ID_1 = 0x50333 +FLAGS_1 = CAN.FLAG_EXT_ID # ID_1 is an extended CAN ID + +can = CAN(1, 500_000) +can.set_filters(None) # receive all + + +def print_rx(can_id, data, flags, errors): + print(hex(can_id), bytes(data), hex(flags), hex(errors)) + + +def instance0(): + multitest.next() + + # receive from instance1 first + while not (rx := can.recv()): + time.sleep(0) + print_rx(*rx) + + # now send one + can.send(ID_0, b"1234") + + +def instance1(): + multitest.next() + + can.send(ID_1, b"ABCD", FLAGS_1) + + while not (rx := can.recv()): + time.sleep(0) + print_rx(*rx) diff --git a/tests/multi_extmod/machine_can_01_rxtx_simple.py.exp b/tests/multi_extmod/machine_can_01_rxtx_simple.py.exp new file mode 100644 index 00000000000..479b6809490 --- /dev/null +++ b/tests/multi_extmod/machine_can_01_rxtx_simple.py.exp @@ -0,0 +1,4 @@ +--- instance0 --- +0x50333 b'ABCD' 0x2 0x0 +--- instance1 --- +0x50 b'1234' 0x0 0x0 diff --git a/tests/multi_extmod/machine_can_02_rx_callback.py b/tests/multi_extmod/machine_can_02_rx_callback.py new file mode 100644 index 00000000000..80b13dcd622 --- /dev/null +++ b/tests/multi_extmod/machine_can_02_rx_callback.py @@ -0,0 +1,122 @@ +from machine import CAN +import time + +# Test the CAN.IRQ_RX irq handler, including overflow + +rx_overflow = False +rx_full = False +received = [] + +# CAN IDs +ID_SPAM = 0x345 # messages spammed into the receive FIFO +ID_ACK_OFLOW = 0x055 # message the receiver sends after it's seen an overflow +ID_AFTER = 0x100 # message the sender sends after the ACK + +can = CAN(1, 500_000) + + +# A very basic "soft" receiver handler that stores received messages into a global list +def receiver_irq_recv(can): + global rx_overflow, rx_full + + assert can.irq().flags() & can.IRQ_RX # the only enabled IRQ + + can_id, data, _flags, errors = can.recv() + + received.append((can_id, None)) + + # The FIFO is expected not to overflow by itself, wait until 40 messages + # have been received and then block the receive handler to induce an overflow + if len(received) == 40: + assert not rx_overflow # shouldn't have already happened, either + time.sleep_ms(500) + + if not rx_overflow and (errors & CAN.RECV_ERR_OVERRUN): + # expected this should happen on the very next message after + # the one where we slept for 500ms + print("irq_recv overrun", len(received)) + received.clear() # check we still get some messages, see rx_spam print line below + rx_overflow = True + + # also expect the FIFO to be FULL again immediately after overrunning and rx_overflow event + if rx_overflow and (errors & CAN.RECV_ERR_OVERRUN | CAN.RECV_ERR_FULL) == CAN.RECV_ERR_FULL: + rx_full = True + + +# Receiver +def instance0(): + can.irq(receiver_irq_recv, trigger=can.IRQ_RX, hard=False) + + can.set_filters(None) # receive all + + multitest.next() + + while not rx_overflow: + pass # Resume ASAP after FIFO0 overflows + + can.send(ID_ACK_OFLOW, b"overflow") + + # at least one ID_SPAM message should have been received + # *after* we overflowed and 'received' was clear in the irq handler + print("rx_spam", any(r[0] == ID_SPAM for r in received)) + + # wait until the "after" message is received + for n in range(100): + if any(r[0] == ID_AFTER for r in received): + break + time.sleep_ms(10) + + can.irq(None) # disable the IRQ + received.clear() + + # at some point while waiting for ID_AFTER the FIFO should have gotten + # full again + print("rx_full", rx_full) + + # now IRQ is disabled, no new messages should be received + time.sleep_ms(250) + print("len", len(received)) + + +received_ack = False + +# reusing the result buffer so sender_irq_recv can be 'hard' +sender_irq_result = [None, memoryview(bytearray(64)), None, None] + + +def sender_irq_recv(can): + global received_ack + + assert can.irq().flags() & can.IRQ_RX # the only enabled IRQ + + can_id, data, _flags, _errors = can.recv(sender_irq_result) + print("sender_irq_recv", can_id, len(data)) # should be ID_ACK_OFLOW and "overflow" payload + received_ack = True + + +# Sender +def instance1(): + can.irq(sender_irq_recv, CAN.IRQ_RX, hard=True) + + can.set_filters(None) + + multitest.next() + + # Spam out messages until the receiver tells us its RX FIFO is full. + # + # The RX FIFO on the receiver can vary from 3 deep (BXCAN) to 25 deep (STM32H7), + # so we keep sending to it until we see a CAN message on ID_ACK_OFLOW indicating + # the receiver's FIFO has overflowed + while not received_ack: + for i in range(255): + while can.send(ID_SPAM, bytes([i] * 8)) is None and not received_ack: + # Don't overflow the TX FIFO + time.sleep_ms(1) + if received_ack: + break + + # give the receiver some time to make space in the FIFO + time.sleep_ms(200) + + # send the final message, the receiver should get this one + can.send(ID_AFTER, b"aaaaa") diff --git a/tests/multi_extmod/machine_can_02_rx_callback.py.exp b/tests/multi_extmod/machine_can_02_rx_callback.py.exp new file mode 100644 index 00000000000..8e4e5dc6475 --- /dev/null +++ b/tests/multi_extmod/machine_can_02_rx_callback.py.exp @@ -0,0 +1,7 @@ +--- instance0 --- +irq_recv overrun 41 +rx_spam True +rx_full True +len 0 +--- instance1 --- +sender_irq_recv 85 8 diff --git a/tests/multi_extmod/machine_can_03_rx_filters.py b/tests/multi_extmod/machine_can_03_rx_filters.py new file mode 100644 index 00000000000..a56acbbe91e --- /dev/null +++ b/tests/multi_extmod/machine_can_03_rx_filters.py @@ -0,0 +1,103 @@ +from machine import CAN +import time + +# Test for filtering capabilities + +can = CAN(1, 500_000) + +# IDs and filter phases used for the 'single id' part of the test +SINGLE_EXT_ID = (0x1234_5678, 0x1FFF_FFFF, CAN.FLAG_EXT_ID) +SINGLE_STD_ID = (0x505, 0x7FF, 0) +SINGLE_ID_PHASES = [ + ("single ext id", [SINGLE_EXT_ID]), + ("single std id", [SINGLE_STD_ID]), + ("ext+std ids", [SINGLE_EXT_ID, SINGLE_STD_ID]), + ("std+ext ids", [SINGLE_STD_ID, SINGLE_EXT_ID]), # these two should be equivalent + ("accept none", []), + ("accept all", None), + ("accept none again", ()), +] + + +# Receiver +def receiver_irq_recv(can): + assert can.irq().flags() & can.IRQ_RX # the only enabled IRQ + can_id, data, _flags, _errors = can.recv() + print("recv", hex(can_id), data.hex()) + + +def instance0(): + can.irq(receiver_irq_recv, trigger=can.IRQ_RX, hard=False) + + multitest.next() + + # Configure to receive standard frames (in a range), and + # extended frames (in a range). + can.set_filters([(0x300, 0x300, 0), (0x3000, 0x3000, CAN.FLAG_EXT_ID)]) + multitest.broadcast("ready id ranges") + + # Run through the phases of filtering for individual IDs + for phase, filters in SINGLE_ID_PHASES: + multitest.wait("configure " + phase) + if filters and len(filters) > CAN.FILTERS_MAX: + # this check really exists to add test coverage for the FILTERS_MAX constant + print("Warning: Too many filters for hardware!") + can.set_filters(filters) + print("receiver configured " + phase) + multitest.broadcast("ready " + phase) + + multitest.wait("Sender done") + + +def send_messages(messages): + for can_id, payload, flags in messages: + r = can.send(can_id, payload, flags) + if r is None: + print("Failed to send:", hex(can_id), payload.hex()) + time.sleep_ms(5) # avoid flooding either our or the receiver's FIFO + + +# Sender +def instance1(): + multitest.next() + multitest.wait("ready id ranges") + + print("Sending ID ranges...") + for i in range(3): + send_messages( + [ + (0x345, bytes([i, 0xFF] * (i + 1)), 0), + (0x3700 + i, bytes([0xEE] * (i + 1)), CAN.FLAG_EXT_ID), + (0x123, b"abcdef", 0), # matches no filter, expect ACKed but not received + ] + ) + + # Now move on to single ID filtering + + single_id_messages = [ + (0x1234_5678, b"\x01\x02\x03\x04\x05", CAN.FLAG_EXT_ID), # matches ext id + (0x0234_5678, b"\x00\x00", CAN.FLAG_EXT_ID), # no match + (0x678, b"\x00\x01", 0), # no match + (0x505, b"\x06\x07\x08\x09\x0a\x0b", 0), # matches standard id + (0x345, b"\x00\x02", 0), # no match (in prev filter) + (0x1234_5679, b"\x00\x03", CAN.FLAG_EXT_ID), # no match + (0x3705, b"\x00\x04", CAN.FLAG_EXT_ID), # no match (in prev filter) + (0x1234_5678, b"\x01\x02\x03", CAN.FLAG_EXT_ID), # matches ext id + (0x505, b"\x04\x05\x06", 0), # matches standard id + (0x505, b"\x00\x05", CAN.FLAG_EXT_ID), # no match (is ext id) + (0x507, b"\x00\x06", 0), # no match + (0x1334_5678, b"\x00\x07", CAN.FLAG_EXT_ID), # no match + (0x1234_5670, b"\x00\x08", CAN.FLAG_EXT_ID), # no match + ] + + # Send the same list of messages for each phase of the test. + # The receiver will have configured different filters, and the .exp + # file is what selects which messages should be received or not. + for phase, _ in SINGLE_ID_PHASES: + multitest.broadcast("configure " + phase) + multitest.wait("ready " + phase) + print("Sending for " + phase + "...") + send_messages(single_id_messages) + + print("Sender done") + multitest.broadcast("Sender done") diff --git a/tests/multi_extmod/machine_can_03_rx_filters.py.exp b/tests/multi_extmod/machine_can_03_rx_filters.py.exp new file mode 100644 index 00000000000..d55c0c97d15 --- /dev/null +++ b/tests/multi_extmod/machine_can_03_rx_filters.py.exp @@ -0,0 +1,49 @@ +--- instance0 --- +recv 0x345 00ff +recv 0x3700 ee +recv 0x345 01ff01ff +recv 0x3701 eeee +recv 0x345 02ff02ff02ff +recv 0x3702 eeeeee +receiver configured single ext id +recv 0x12345678 0102030405 +recv 0x12345678 010203 +receiver configured single std id +recv 0x505 060708090a0b +recv 0x505 040506 +receiver configured ext+std ids +recv 0x12345678 0102030405 +recv 0x505 060708090a0b +recv 0x12345678 010203 +recv 0x505 040506 +receiver configured std+ext ids +recv 0x12345678 0102030405 +recv 0x505 060708090a0b +recv 0x12345678 010203 +recv 0x505 040506 +receiver configured accept none +receiver configured accept all +recv 0x12345678 0102030405 +recv 0x2345678 0000 +recv 0x678 0001 +recv 0x505 060708090a0b +recv 0x345 0002 +recv 0x12345679 0003 +recv 0x3705 0004 +recv 0x12345678 010203 +recv 0x505 040506 +recv 0x505 0005 +recv 0x507 0006 +recv 0x13345678 0007 +recv 0x12345670 0008 +receiver configured accept none again +--- instance1 --- +Sending ID ranges... +Sending for single ext id... +Sending for single std id... +Sending for ext+std ids... +Sending for std+ext ids... +Sending for accept none... +Sending for accept all... +Sending for accept none again... +Sender done diff --git a/tests/multi_extmod/machine_can_04_tx_order.py b/tests/multi_extmod/machine_can_04_tx_order.py new file mode 100644 index 00000000000..9efd9088c94 --- /dev/null +++ b/tests/multi_extmod/machine_can_04_tx_order.py @@ -0,0 +1,183 @@ +from machine import CAN +import time +from random import seed, randrange +import sys + +import micropython + +# The Alif port has an opaque send queue. The Alif CAN controller +# provides no information about the slot number where the message +# is stored, and it does not allow to cancel specific messages. +# This test needs the slot number, which is not available. + +if "alif" in sys.platform: + print("SKIP") + raise SystemExit + +micropython.alloc_emergency_exception_buf(256) +seed(0) + +# Testing that transmit order obeys the priority ordering + +ID_LOW = 0x500 +ID_HIGH = 0x200 + +NUM_MSGS = 255 + +MSG_LEN = 4 + +can = CAN(1, 500_000) + + +def check_sequence(items, label): + # The full range of NUM_MSGS values should have been received or sent, in + # order, without duplicates + if len(items) != NUM_MSGS: + print(label, "wrong count", len(items), "vs", NUM_MSGS) + if items == list(range(NUM_MSGS)): + print(label, "OK") + else: + print(label, "error:") + print(items) + + +# Receiver + +# lists of received messages, one list per ID +received_low = [] +received_high = [] + + +def irq_recv(can): + while can.irq().flags() & can.IRQ_RX: + can_id, data, flags, _errors = can.recv() + + if can_id == ID_LOW and len(data) == MSG_LEN: + received_low.append(data[0]) + elif can_id == ID_HIGH and len(data) == MSG_LEN: + received_high.append(data[0]) + else: + print("unexpected recv", can_id, data, flags) + + +def instance0(): + can.irq(irq_recv, trigger=can.IRQ_RX, hard=False) + can.set_filters(None) # receive all + + multitest.next() + + multitest.wait("sender done") + check_sequence(received_low, "Low prio received") + check_sequence(received_high, "High prio received") + + +# Sender + +## Messages pending to send +pending_low = list(range(NUM_MSGS)) +pending_high = list(range(NUM_MSGS)) + +# List of the messages currently queued to send +tx_queue = [None] * CAN.TX_QUEUE_LEN + +# Messages sent, recorded in order as [high_prio, val] +sent = [] +for _ in range(NUM_MSGS * 2): + sent.append([None, None]) +num_sent = 0 + + +def irq_send(can): + global num_sent + + while flags := can.irq().flags(): + assert flags & can.IRQ_TX # the only enabled IRQ + + idx = (flags >> can.IRQ_TX_IDX_SHIFT) & can.IRQ_TX_IDX_MASK + success = not (flags & can.IRQ_TX_FAILED) + + if not success: + return # We don't worry about failures here + + if not tx_queue[idx]: + print("bad done", idx, success) + return + + was_high, val = tx_queue[idx] + tx_queue[idx] = None + sent[num_sent][0] = was_high + sent[num_sent][1] = val + num_sent += 1 + + +def instance1(): + # note: this test can pass with hard=True, but in a debug build + # the completion IRQ may race ahead of setting tx_queue[idx], below + if "mimxrt" in sys.platform: + can.irq(irq_send, trigger=can.IRQ_TX, hard=True) + else: + can.irq(irq_send, trigger=can.IRQ_TX, hard=False) + data = bytearray(MSG_LEN) + + multitest.next() + + while pending_low or pending_high: + if pending_high: + val = pending_high.pop(0) + data[0] = val + data[1] = 1 + while True: + idx = can.send(ID_HIGH, data) + if idx is None: + continue # keep trying until a queue spot opens up + old = tx_queue[idx] + tx_queue[idx] = (True, val) + if old: + print("error high priority queue race", idx, val, old) + break + + for _ in range(randrange(4)): + # Try and queue many low priority messages (expecting most will fail) + if pending_low: + val = pending_low[0] + data[0] = val + data[1] = 0 + idx = can.send(ID_LOW, data) + if idx is None: + # don't retry indefinitely for low priority messages + continue + + old = tx_queue[idx] + tx_queue[idx] = (False, val) + pending_low.pop(0) + if old is not None: + print("error low priority queue race", idx, val, old) + + print("waiting for tx queue to empty...") + while any(x is not None for x in tx_queue): + pass + + multitest.broadcast("sender done") + + # Check we sent the right number of messages + if num_sent != 2 * NUM_MSGS: + print("Sent %d expected %d" % (num_sent, 2 * NUM_MSGS)) + else: + print("Sent right number of messages") + + # Check the low and high priority messages all arrived in order + sent_low = [val for (prio, val) in sent[:num_sent] if prio == False] + sent_high = [val for (prio, val) in sent[:num_sent] if prio == True] + check_sequence(sent_low, "Low prio sent") + check_sequence(sent_high, "High prio sent") + + # check that high priority message queue items always stayed ahead of the low priority + high_val = -1 + for idx, (prio, val) in enumerate(sent): + if prio: + high_val = val + elif high_val <= val and val < NUM_MSGS - 1: + print( + "Low priority message %d overtook high priority %d at index %d" + % (val, high_val, idx) + ) diff --git a/tests/multi_extmod/machine_can_04_tx_order.py.exp b/tests/multi_extmod/machine_can_04_tx_order.py.exp new file mode 100644 index 00000000000..a2de6ee2706 --- /dev/null +++ b/tests/multi_extmod/machine_can_04_tx_order.py.exp @@ -0,0 +1,8 @@ +--- instance0 --- +Low prio received OK +High prio received OK +--- instance1 --- +waiting for tx queue to empty... +Sent right number of messages +Low prio sent OK +High prio sent OK diff --git a/tests/multi_extmod/machine_can_05_tx_prio_cancel.py b/tests/multi_extmod/machine_can_05_tx_prio_cancel.py new file mode 100644 index 00000000000..c3f67b372df --- /dev/null +++ b/tests/multi_extmod/machine_can_05_tx_prio_cancel.py @@ -0,0 +1,151 @@ +from machine import CAN +import time +import sys + +# The Alif port has an opaque send queue. The Alif CAN controller +# provides no information about the slot number where the message +# is stored, and it does not allow to cancel specific messages. +# This test needs both the slot number, and uses cancel_send() for +# dedicated messages, which both is not available. + +if "alif" in sys.platform: + print("SKIP") + raise SystemExit + +# Check that cancelling a low priority outgoing message and replacing it with a +# high priority message causes it to be transmitted successfully onto a busy bus + +recv = [] + +ITERS = 5 + +can = CAN(1, 500_000) + + +def irq_recv(can): + global recv_std_id + while can.irq().flags() & can.IRQ_RX: + can_id, data, flags, _errors = can.recv() + assert flags & CAN.FLAG_EXT_ID # test uses all extended IDs + if len(recv) < ITERS: + recv.append(can_id) + + +def instance0(): + can.irq(irq_recv, trigger=can.IRQ_RX, hard=False) + can.set_filters(None) # receive all + + multitest.next() + + # don't babble until we know instance1 is ready to receive, or this instance + # may go to Error Passive while instance1 is still initialising CAN (meaning + # the "babble" won't saturate the bus, due to the Suspend Transmission + # requirement) + multitest.wait("instance1 ready") + + bcast_countdown = 5 + + # "Babble" medium priority messages onto the bus to prevent + # instance1() from sending anything lower priority than this + while len(recv) < ITERS: + for id in range(0x5000, 0x6000): + can.send(id, b"BABBLE", CAN.FLAG_EXT_ID) + if len(recv) >= ITERS: + break + if bcast_countdown > 0: + # queue some "babble" messages onto the bus before signalling to + # instance1 that it can start trying to send + bcast_countdown -= 1 + if not bcast_countdown: + multitest.broadcast("instance0 babbling") + + print("received", ITERS, "messages") + for can_id in recv: + print(hex(can_id)) # should be the high priority messages from instance1, only + + multitest.wait("sender done") + print("done") + + +last_idx = 0 +total_cancels = 0 +total_sent = 0 + + +def irq_send(can): + global total_cancels, total_sent + + while flags := can.irq().flags(): + assert flags & can.IRQ_TX # the only enabled IRQ + + idx = (flags >> can.IRQ_TX_IDX_SHIFT) & can.IRQ_TX_IDX_MASK + + if flags & can.IRQ_TX_FAILED: + # we should only see failed transmits due to cancels in buffer 'last_idx' + assert idx == last_idx + total_cancels += 1 + else: + # this includes the messages we explicitly send, plus queued low + # priority messages once the receiver stops 'babbling' on the bus + total_sent += 1 + + +def instance1(): + global last_idx, total_cancels + can.irq(irq_send, trigger=can.IRQ_TX, hard=True) + + multitest.next() + multitest.broadcast("instance1 ready") + + # make sure instance0 can queue outgoing medium-priority + # babble before we start trying to send, so we're trying to + # send onto an already busy bus + multitest.wait("instance0 babbling") + + for i in range(ITERS): + # Fill the transmit queue with low priority messages (all extended IDs) + last_idx = 0 + if i < 3: + # For the first 3 iterations, send unique message IDs + id_range = range(0x7000, 0x7FFF) + flags = CAN.FLAG_EXT_ID + else: + # For the last iterations, repeat the same ID but tell controller to ignore + # ordering (allows it to queue more than one despite hardware limitations) + id_range = [0x50000 + i] * CAN.TX_QUEUE_LEN + flags = CAN.FLAG_EXT_ID | CAN.FLAG_UNORDERED + + for id in id_range: + idx = can.send(id, b"LOWPRIO", flags) + if idx is None: + break # send queue is full, stop trying to send + last_idx = idx + + time.sleep_ms(50) # the send queue shouldn't empty as instance0 is "babbling" + + # try and cancel the last message we queued + res = can.cancel_send(last_idx) + print(i, "cancel result", res) + if ("mimxrt" in sys.platform) and res: + total_cancels += 1 + + # send a high priority message, that we expect to go out + idx = can.send(0x500 + i, b"HIPRIO", CAN.FLAG_EXT_ID) + print(i, "send result", idx is not None) + + # make sure this message is sent onto the bus + time.sleep_ms(1) + + multitest.broadcast("sender done") + + # let the entire transmit queue drain, now instance0 should have gone quiet + time.sleep_ms(50) + + print("total cancels", total_cancels) # should equal ITERS + + if total_sent == CAN.TX_QUEUE_LEN - 1 + ITERS: + # expect we send one message for each of ITERS, plus all low priority + # queued messages once instance0 stops babbling on the bus + print("total sent OK") + else: + print("total sent", total_sent, CAN.TX_QUEUE_LEN - 1 + ITERS) diff --git a/tests/multi_extmod/machine_can_05_tx_prio_cancel.py.exp b/tests/multi_extmod/machine_can_05_tx_prio_cancel.py.exp new file mode 100644 index 00000000000..26bab097c44 --- /dev/null +++ b/tests/multi_extmod/machine_can_05_tx_prio_cancel.py.exp @@ -0,0 +1,21 @@ +--- instance0 --- +received 5 messages +0x500 +0x501 +0x502 +0x503 +0x504 +done +--- instance1 --- +0 cancel result True +0 send result True +1 cancel result True +1 send result True +2 cancel result True +2 send result True +3 cancel result True +3 send result True +4 cancel result True +4 send result True +total cancels 5 +total sent OK diff --git a/tests/multi_extmod/machine_can_06_remote_req.py b/tests/multi_extmod/machine_can_06_remote_req.py new file mode 100644 index 00000000000..4a1414c0946 --- /dev/null +++ b/tests/multi_extmod/machine_can_06_remote_req.py @@ -0,0 +1,70 @@ +from machine import CAN +import time + +# Test CAN remote transmission requests + +ID = 0x750 + +FILTER_ID = 0x101 +FILTER_MASK = 0x7FF + +can = CAN(1, 500_000) + + +def receiver_irq_recv(can): + assert can.irq().flags() & can.IRQ_RX # the only enabled IRQ + can_id, data, flags, _errors = can.recv() + is_rtr = flags == CAN.FLAG_RTR + print( + "recv", + hex(can_id), + is_rtr, + len(data) if is_rtr else bytes(data), + ) + if is_rtr: + # The 'data' response of a remote request should be all zeroes + assert bytes(data) == b"\x00" * len(data) + + +# Receiver +def instance0(): + can.irq(receiver_irq_recv, trigger=can.IRQ_RX, hard=False) + can.set_filters(None) # receive all + + multitest.next() + + multitest.wait("enable filter") + can.set_filters([(FILTER_ID, FILTER_MASK, 0)]) + multitest.broadcast("filter set") + + multitest.wait("done") + + +# Sender +def instance1(): + multitest.next() + + can.send(ID, b"abc", CAN.FLAG_RTR) # length==3 remote request + time.sleep_ms(5) + can.send(ID, b"abc", 0) # regular message using the same ID + time.sleep_ms(5) + can.send(ID, b"abcde", CAN.FLAG_RTR) # length==5 remote request + time.sleep_ms(5) + + multitest.broadcast("enable filter") + multitest.wait("filter set") + + # these two messages should be filtered out + can.send(ID, b"abc", CAN.FLAG_RTR) # length==3 remote request + time.sleep_ms(5) + can.send(ID, b"abc", 0) # regular message using the same ID + time.sleep_ms(5) + + # these messages should be filtered in + can.send(FILTER_ID, b"def", CAN.FLAG_RTR) # length==3 remote request + time.sleep_ms(5) + can.send(FILTER_ID, b"hij", 0) # regular message using the same ID + time.sleep_ms(5) + + multitest.broadcast("done") + print("done") diff --git a/tests/multi_extmod/machine_can_06_remote_req.py.exp b/tests/multi_extmod/machine_can_06_remote_req.py.exp new file mode 100644 index 00000000000..fe94508ba3d --- /dev/null +++ b/tests/multi_extmod/machine_can_06_remote_req.py.exp @@ -0,0 +1,8 @@ +--- instance0 --- +recv 0x750 True 3 +recv 0x750 False b'abc' +recv 0x750 True 5 +recv 0x101 True 3 +recv 0x101 False b'hij' +--- instance1 --- +done diff --git a/tests/multi_extmod/machine_can_07_error_states.py b/tests/multi_extmod/machine_can_07_error_states.py new file mode 100644 index 00000000000..f7071a8bd77 --- /dev/null +++ b/tests/multi_extmod/machine_can_07_error_states.py @@ -0,0 +1,211 @@ +from machine import CAN +from micropython import const +import time + +# Test that without a second CAN node on the network the controller will +# correctly go into the correct error states, and can then recover. +# +# Note this test depends on no other CAN node being active on the network apart +# from the two test instances. (Although it's OK for extra nodes to be in a +# "listen only" mode where they won't ACK messages.) + +rx_overflow = False +rx_full = False +received = [] + +# CAN IDs +_ID = const(0x100) + +# can.state() result list indexes, as constants +_IDX_TEC = const(0) +_IDX_REC = const(1) +_IDX_NUM_WARNING = const(2) +_IDX_NUM_PASSIVE = const(3) +_IDX_NUM_BUS_OFF = const(4) +_IDX_PEND_TX = const(5) + +can = CAN(1, 500_000) + + +def state_name(state): + for name in dir(CAN): + if name.startswith("STATE_") and state == getattr(CAN, name): + return name + return f"UNKNOWN-{state}" + + +def irq_recv(can): + while can.irq().flags() & can.IRQ_RX: + can_id, data, _flags, errors = can.recv() + print("recv", hex(can_id), data.hex()) + + +# Receiver +def instance0(): + can.irq(irq_recv, trigger=can.IRQ_RX, hard=False) + + can.set_filters(None) # receive all + + multitest.next() + + # Receive at least one CAN message before sender asks us to disable the controller + + multitest.wait("disable receiver") + can.deinit() + print("can deinit()") + multitest.broadcast("receiver disabled") + + # Wait for the sender to tell us to re-enable + + multitest.wait("enable receiver") + # note the irq is no longer active after deinit() + can.init(500_000) + print("can init()") + multitest.broadcast("receiver enabled") + + # Receive CAN messages until the sender asks us to switch to an invalid baud rate + + multitest.wait("switch baud") + can.init(125_000) + print("can switch baud") + multitest.broadcast("switched baud") + + time.sleep_ms(1) + + print("sending bad msg") + # trying to send this frame should introduce more bus errors + idx_bad = can.send(_ID, b"BADBAUD") + + multitest.wait("fix baud") + print("sending cancelling") + print("cancelled", can.cancel_send(idx_bad)) + print("re-init") + can.init(500_000) + multitest.broadcast("fixed baud") + + # Should be receiving CAN messages OK again + + print("done") + + +def irq_sender(can): + while flags := can.irq().flags(): + if flags & can.IRQ_STATE: + print("irq state", can.state()) + if flags & can.IRQ_TX: + print("irq sent", not (flags & can.IRQ_TX_FAILED)) + + +# Sender +def instance1(): + can.irq(irq_sender, CAN.IRQ_STATE | CAN.IRQ_TX, hard=False) + + can.set_filters(None) + + multitest.next() + + print("started", state_name(can.state())) # should be ERROR_ACTIVE + + # Send a single message to the receiver, to verify it's working + can.send(_ID, b"PAYLOAD") + time.sleep_ms(50) # irq_sender should fire during this window + + active_counters = can.get_counters() + # print(active_counters) # DEBUG + + multitest.broadcast("disable receiver") + multitest.wait("receiver disabled") + + # Now the receiver shouldn't be ACKing our frames, queue will stay full + # ... we will get the ISR for ERROR_WARNING but it'll go from ERROR_WARNING to ERROR_PASSIVE + # very quickly as all messages are failing + can.send(_ID, b"MORE") + while can.state() in (CAN.STATE_ACTIVE, CAN.STATE_WARNING): + pass + + print(state_name(can.state())) # should be ERROR_PASSIVE now + passive_counters = can.get_counters() + # print(passive_counters) # DEBUG + print("tec increased", passive_counters[_IDX_TEC] > active_counters[_IDX_TEC]) + print("tec over thresh", passive_counters[_IDX_TEC] >= 128) + # we should have counted exactly one ERROR_WARNING and ERROR_PASSIVE transition + print( + "counted warning", + passive_counters[_IDX_NUM_WARNING] == active_counters[_IDX_NUM_WARNING] + 1, + ) + print( + "counted passive", + passive_counters[_IDX_NUM_PASSIVE] == active_counters[_IDX_NUM_PASSIVE] + 1, + ) + print("some pending tx", passive_counters[_IDX_PEND_TX] > 0) + + # Re-enable the receiver which should allow us to go from ERROR_PASSIVE to ERROR_WARNING + multitest.broadcast("enable receiver") + multitest.wait("receiver enabled") + + can.send(_ID, b"MORE") + while can.state() == CAN.STATE_PASSIVE: + pass + + print(state_name(can.state())) # should be ERROR_WARNING now + warning_counters = can.get_counters() + # print(warning_counters) # DEBUG + print("tec decreased", warning_counters[_IDX_TEC] < passive_counters[_IDX_TEC]) + print( + "tec below thresh", warning_counters[_IDX_TEC] < 128 + ) # and should be more than error passive threshold + # error warning count should stay the same, as we went "down" in severity not up + print( + "no new warning", warning_counters[_IDX_NUM_WARNING] == passive_counters[_IDX_NUM_WARNING] + ) + print( + "no new passive", warning_counters[_IDX_NUM_PASSIVE] == passive_counters[_IDX_NUM_PASSIVE] + ) + + # Tell the receiver to change to the wrong baud rate, which should create both RX and TX errorxs + multitest.broadcast("switch baud") + multitest.wait("switched baud") + + # queue another message. This will keep trying to send until we revert back to ERROR_PASSIVE + idx = can.send(_ID, b"YETMORE") + print("queued yetmore", idx is not None) + while can.state() != CAN.STATE_PASSIVE: + pass + + print(state_name(can.state())) # should be ERROR_PASSIVE again + passive_counters = can.get_counters() + # print(passive_counters) # DEBUG + # we can't say for sure which error counter will hit the ERROR_PASSIVE threshold first + print( + "one over thresh", passive_counters[_IDX_TEC] >= 128 or passive_counters[_IDX_REC] >= 128 + ) + print( + "no new warning", passive_counters[_IDX_NUM_WARNING] == warning_counters[_IDX_NUM_WARNING] + ) + print( + "counted passive", + passive_counters[_IDX_NUM_PASSIVE] == warning_counters[_IDX_NUM_PASSIVE] + 1, + ) + + # Note that we can't get all the way to the most severe BUS_OFF error state + # with this test setup, as Bus Off requires more than just "normal" frame + # transmit errors. + + # tell the receiver to go back to a valid baud rate, causing the pending tx + # to be sent. + multitest.broadcast("fix baud") + multitest.wait("fixed baud") + + # Restarting the controller may cause it to leave its error state, or not, depending + # on the implementation - but it shouldn't cause any recovery issues. Also cancels all pending TX. + # If restart() clears the TEC and REC error counters, resetting the error state to ACTIVE, + # and if that is done while instance0 is still trying to send at the wrong baud rate, + # the error state rushes up again pretty fast. Therefore the baud rate is fixed before + # calling restart(). + can.restart() + + idx_more = can.send(_ID, b"MOREMORE") + time.sleep_ms(50) # irq_sender should fire during this window + print("queued moremore", idx_more is not None) + + print("done") diff --git a/tests/multi_extmod/machine_can_07_error_states.py.exp b/tests/multi_extmod/machine_can_07_error_states.py.exp new file mode 100644 index 00000000000..c2731f20905 --- /dev/null +++ b/tests/multi_extmod/machine_can_07_error_states.py.exp @@ -0,0 +1,38 @@ +--- instance0 --- +recv 0x100 5041594c4f4144 +can deinit() +can init() +can switch baud +sending bad msg +sending cancelling +cancelled True +re-init +done +--- instance1 --- +started STATE_ACTIVE +irq sent True +irq state 2 +irq state 3 +STATE_PASSIVE +tec increased True +tec over thresh True +counted warning True +counted passive True +some pending tx True +irq sent True +irq sent True +STATE_WARNING +tec decreased True +tec below thresh True +no new warning True +no new passive True +irq state 3 +queued yetmore True +STATE_PASSIVE +one over thresh True +no new warning True +counted passive True +irq sent True +irq sent True +queued moremore True +done diff --git a/tests/multi_extmod/machine_can_08_init_mode.py b/tests/multi_extmod/machine_can_08_init_mode.py new file mode 100644 index 00000000000..730edfac7e5 --- /dev/null +++ b/tests/multi_extmod/machine_can_08_init_mode.py @@ -0,0 +1,112 @@ +from machine import CAN +from micropython import const +import time +import sys + +# instance0 transitions through various modes, instance1 +# listens for various messages (or not) +# +# Note this test assumes no other CAN nodes are connected apart from the test +# instances (or if they are connected they must be in silent mode.) +# +# TODO: This test needs to eventually support the case where modes aren't supported +# on a controller, maybe by printing fake output if the mode switch fails? + +# MODE_NORMAL, MODE_SLEEP, MODE_LOOPBACK, MODE_SILENT, MODE_SILENT_LOOPBACK +can = CAN(1, 500_000, mode=CAN.MODE_NORMAL) + +# While instance0 is in Silent mode, instance1 sends a message with this ID +# that will be retried for 100ms (as instance0 won't ACK). So don't print every one. +_SILENT_RX_ID = const(0x53) +silent_rx_count = 0 + + +def irq_print(can): + global silent_rx_count + while flags := can.irq().flags(): + if flags & can.IRQ_RX: + can_id, data, _flags, errors = can.recv() + if can_id != _SILENT_RX_ID: + print("recv", hex(can_id), bytes(data)) + else: + silent_rx_count += 1 + elif flags & can.IRQ_TX: # note: only enabled on instance1 to avoid race conditions + print("send", "failed" if flags & can.IRQ_TX_FAILED else "ok") + + +def reinit_with_mode(mode): + can.deinit() + can.init(bitrate=500_000, mode=mode) + can.irq(irq_print, trigger=can.IRQ_RX, hard=False) + can.set_filters(None) # receive all + + +def instance0(): + multitest.next() + multitest.wait("instance1 ready") + + reinit_with_mode(can.MODE_NORMAL) + print("Normal", "MODE_NORMAL" in str(can)) + can.send(0x50, b"Normal") + time.sleep_ms(100) + + # Skipping MODE_SLEEP as means different things on different hardware + + reinit_with_mode(can.MODE_LOOPBACK) + print("Loopback", "MODE_LOOPBACK" in str(can)) + + # This message should go out to the bus, but will also be received by instance0 itself + can.send(0x51, b"Loopback") + time.sleep_ms(100) + + reinit_with_mode(can.MODE_SILENT) + print("Silent", "MODE_SLIENT" in str(can)) + + # This message shouldn't go out onto the bus + idx = can.send(0x52, b"Silent") + multitest.broadcast("silent") + multitest.wait("silent done") + # we should have received the message from instance1 many times, as instance0 won't have ACKed it + # create a dummy "OK" for MIMXRT, since it on receives ACKed messages in SILENT mode. + if ("mimxrt" in sys.platform) or ("alif" in sys.platform): + print("silent_rx_count True") + else: + print("silent_rx_count", silent_rx_count > 5) + # Cancel the sent message only if it was accepted for sending. + if idx is not None: + can.cancel_send(idx) + + reinit_with_mode(can.MODE_SILENT_LOOPBACK) + print("Silent Loopback", "MODE_SILENT_LOOPBACK" in str(can)) + + # This message should be received by instance0 only + idx = can.send(0x54, b"SiLoop") + time.sleep_ms(50) + + reinit_with_mode(can.MODE_NORMAL) + print("Normal again", "MODE_NORMAL" in str(can)) + can.send(0x55, b"Normal2") # should be received by instance1 only, again + multitest.broadcast("normal done") + + +# Receiver +def instance1(): + can.irq(irq_print, trigger=can.IRQ_RX | can.IRQ_TX, hard=False) + can.set_filters(None) # receive all + multitest.next() + + multitest.broadcast("instance1 ready") + + # The IRQ does most of the work on this instance + + multitest.wait("silent") + # Sending this message back, it should fail to send as Silent mode won't ACK it + idx = can.send(0x53, b"Silent2") + time.sleep_ms(20) + can.cancel_send(idx) + # mimxrt does not give TX failed interrupts on cancel_send. + if "mimxrt" in sys.platform: + print("send failed") + multitest.broadcast("silent done") + + multitest.wait("normal done") diff --git a/tests/multi_extmod/machine_can_08_init_mode.py.exp b/tests/multi_extmod/machine_can_08_init_mode.py.exp new file mode 100644 index 00000000000..b9f0f11ae10 --- /dev/null +++ b/tests/multi_extmod/machine_can_08_init_mode.py.exp @@ -0,0 +1,14 @@ +--- instance0 --- +Normal True +Loopback True +recv 0x51 b'Loopback' +Silent False +silent_rx_count True +Silent Loopback True +recv 0x54 b'SiLoop' +Normal again True +--- instance1 --- +recv 0x50 b'Normal' +recv 0x51 b'Loopback' +send failed +recv 0x55 b'Normal2' diff --git a/tests/multi_extmod/machine_i2c_target_irq.py b/tests/multi_extmod/machine_i2c_target_irq.py new file mode 100644 index 00000000000..eafd9dfdca8 --- /dev/null +++ b/tests/multi_extmod/machine_i2c_target_irq.py @@ -0,0 +1,137 @@ +# Test I2CTarget IRQs and clock stretching. +# +# Requires two instances with their SCL and SDA lines connected together. +# Any combination of the below supported boards can be used. +# +# Notes: +# - pull-up resistors may be needed +# - alif use 1.8V signalling + +import sys +import time +from machine import I2C, I2CTarget + +if not hasattr(I2CTarget, "IRQ_ADDR_MATCH_READ"): + print("SKIP") + raise SystemExit + +ADDR = 67 +clock_stretch_us = 200 + +# Configure pins based on the target. +if sys.platform == "alif": + i2c_args = (1,) # pins P3_7/P3_6 + i2c_kwargs = {} +elif sys.platform == "mimxrt": + i2c_args = (0,) # pins 19/18 on Teensy 4.x + i2c_kwargs = {} + clock_stretch_us = 50 # mimxrt cannot delay too long in the IRQ handler +elif sys.platform == "rp2": + i2c_args = (0,) + i2c_kwargs = {"scl": 9, "sda": 8} +elif sys.platform == "pyboard": + i2c_args = ("Y",) + i2c_kwargs = {} +elif sys.platform == "samd": + i2c_args = () # pins SCL/SDA + i2c_kwargs = {} +elif "zephyr-rpi_pico" in sys.implementation._machine: + i2c_args = ("i2c1",) # on gpio7/gpio6 + i2c_kwargs = {} +else: + print("Please add support for this test on this platform.") + raise SystemExit + + +def simple_irq(i2c_target): + flags = i2c_target.irq().flags() + if flags & I2CTarget.IRQ_ADDR_MATCH_READ: + print("IRQ_ADDR_MATCH_READ") + if flags & I2CTarget.IRQ_ADDR_MATCH_WRITE: + print("IRQ_ADDR_MATCH_WRITE") + + # Force clock stretching. + time.sleep_us(clock_stretch_us) + + +class I2CTargetMemory: + def __init__(self, i2c_target, mem): + self.buf1 = bytearray(1) + self.mem = mem + self.memaddr = 0 + self.state = 0 + i2c_target.irq( + self.irq, + I2CTarget.IRQ_ADDR_MATCH_WRITE | I2CTarget.IRQ_READ_REQ | I2CTarget.IRQ_WRITE_REQ, + hard=True, + ) + + def irq(self, i2c_target): + # Force clock stretching. + time.sleep_us(clock_stretch_us) + + flags = i2c_target.irq().flags() + if flags & I2CTarget.IRQ_ADDR_MATCH_WRITE: + self.state = 0 + if flags & I2CTarget.IRQ_READ_REQ: + self.buf1[0] = self.mem[self.memaddr] + self.memaddr += 1 + i2c_target.write(self.buf1) + if flags & I2CTarget.IRQ_WRITE_REQ: + i2c_target.readinto(self.buf1) + if self.state == 0: + self.state = 1 + self.memaddr = self.buf1[0] + else: + self.mem[self.memaddr] = self.buf1[0] + self.memaddr += 1 + self.memaddr %= len(self.mem) + + # Force clock stretching. + time.sleep_us(clock_stretch_us) + + +# I2C controller +def instance0(): + i2c = I2C(*i2c_args, **i2c_kwargs) + multitest.next() + for iteration in range(2): + print("controller iteration", iteration) + multitest.wait("target stage 1") + i2c.writeto_mem(ADDR, 2, "0123") + multitest.broadcast("controller stage 2") + multitest.wait("target stage 3") + print(i2c.readfrom_mem(ADDR, 2, 4)) + multitest.broadcast("controller stage 4") + print("done") + + +# I2C target +def instance1(): + multitest.next() + + for iteration in range(2): + print("target iteration", iteration) + buf = bytearray(b"--------") + if iteration == 0: + # Use built-in memory capability of I2CTarget. + i2c_target = I2CTarget(*i2c_args, **i2c_kwargs, addr=ADDR, mem=buf) + i2c_target.irq( + simple_irq, + I2CTarget.IRQ_ADDR_MATCH_READ | I2CTarget.IRQ_ADDR_MATCH_WRITE, + hard=True, + ) + else: + # Implement a memory device by hand. + i2c_target = I2CTarget(*i2c_args, **i2c_kwargs, addr=ADDR) + I2CTargetMemory(i2c_target, buf) + + multitest.broadcast("target stage 1") + multitest.wait("controller stage 2") + print(buf) + multitest.broadcast("target stage 3") + multitest.wait("controller stage 4") + + i2c_target.deinit() + + print("done") diff --git a/tests/multi_extmod/machine_i2c_target_irq.py.exp b/tests/multi_extmod/machine_i2c_target_irq.py.exp new file mode 100644 index 00000000000..a17c8f43858 --- /dev/null +++ b/tests/multi_extmod/machine_i2c_target_irq.py.exp @@ -0,0 +1,15 @@ +--- instance0 --- +controller iteration 0 +b'0123' +controller iteration 1 +b'0123' +done +--- instance1 --- +target iteration 0 +IRQ_ADDR_MATCH_WRITE +bytearray(b'--0123--') +IRQ_ADDR_MATCH_WRITE +IRQ_ADDR_MATCH_READ +target iteration 1 +bytearray(b'--0123--') +done diff --git a/tests/multi_extmod/machine_i2c_target_memory.py b/tests/multi_extmod/machine_i2c_target_memory.py new file mode 100644 index 00000000000..6b3f0d03eb7 --- /dev/null +++ b/tests/multi_extmod/machine_i2c_target_memory.py @@ -0,0 +1,79 @@ +# Test basic use of I2CTarget and a memory buffer. +# +# Requires two instances with their SCL and SDA lines connected together. +# Any combination of the below supported boards can be used. +# +# Notes: +# - pull-up resistors may be needed +# - alif use 1.8V signalling + +import sys +from machine import I2C, I2CTarget + +ADDR = 67 + +# Configure pins based on the target. +if sys.platform == "alif": + i2c_args = (1,) # pins P3_7/P3_6 + i2c_kwargs = {} +elif sys.platform == "esp32": + i2c_args = (1,) # on pins 9/8 + i2c_kwargs = {} +elif sys.platform == "mimxrt": + i2c_args = (0,) # pins 19/18 on Teensy 4.x + i2c_kwargs = {} +elif sys.platform == "rp2": + i2c_args = (0,) + i2c_kwargs = {"scl": 9, "sda": 8} +elif sys.platform == "pyboard": + i2c_args = ("Y",) + i2c_kwargs = {} +elif sys.platform == "samd": + i2c_args = () # pins SCL/SDA + i2c_kwargs = {} +elif "zephyr-rpi_pico" in sys.implementation._machine: + i2c_args = ("i2c1",) # on gpio7/gpio6 + i2c_kwargs = {} +else: + print("Please add support for this test on this platform.") + raise SystemExit + + +def simple_irq(i2c_target): + flags = i2c_target.irq().flags() + if flags & I2CTarget.IRQ_END_READ: + print("IRQ_END_READ", i2c_target.memaddr) + if flags & I2CTarget.IRQ_END_WRITE: + print("IRQ_END_WRITE", i2c_target.memaddr) + + +# I2C controller +def instance0(): + i2c = I2C(*i2c_args, **i2c_kwargs) + multitest.next() + for iteration in range(2): + print("controller iteration", iteration) + multitest.wait("target stage 1") + i2c.writeto_mem(ADDR, 2 + iteration, "0123") + multitest.broadcast("controller stage 2") + multitest.wait("target stage 3") + print(i2c.readfrom_mem(ADDR, 2 + iteration, 4)) + multitest.broadcast("controller stage 4") + print("done") + + +# I2C target +def instance1(): + buf = bytearray(b"--------") + i2c_target = I2CTarget(*i2c_args, **i2c_kwargs, addr=ADDR, mem=buf) + i2c_target.irq(simple_irq) + multitest.next() + for iteration in range(2): + print("target iteration", iteration) + multitest.broadcast("target stage 1") + multitest.wait("controller stage 2") + print(buf) + multitest.broadcast("target stage 3") + multitest.wait("controller stage 4") + i2c_target.deinit() + print("done") diff --git a/tests/multi_extmod/machine_i2c_target_memory.py.exp b/tests/multi_extmod/machine_i2c_target_memory.py.exp new file mode 100644 index 00000000000..71386cfe769 --- /dev/null +++ b/tests/multi_extmod/machine_i2c_target_memory.py.exp @@ -0,0 +1,16 @@ +--- instance0 --- +controller iteration 0 +b'0123' +controller iteration 1 +b'0123' +done +--- instance1 --- +target iteration 0 +IRQ_END_WRITE 2 +bytearray(b'--0123--') +IRQ_END_READ 2 +target iteration 1 +IRQ_END_WRITE 3 +bytearray(b'--00123-') +IRQ_END_READ 3 +done diff --git a/tests/perf_bench/bm_fft.py b/tests/perf_bench/bm_fft.py index 9a2d03d11b9..e35c1216c13 100644 --- a/tests/perf_bench/bm_fft.py +++ b/tests/perf_bench/bm_fft.py @@ -15,7 +15,7 @@ def reverse(x, bits): # Initialization n = len(vector) - levels = int(math.log(n) / math.log(2)) + levels = int(round(math.log(n) / math.log(2))) coef = (2 if inverse else -2) * cmath.pi / n exptable = [cmath.rect(1, i * coef) for i in range(n // 2)] vector = [vector[reverse(i, levels)] for i in range(n)] # Copy with bit-reversed permutation diff --git a/tests/perf_bench/bm_pidigits.py b/tests/perf_bench/bm_pidigits.py index bdaa73cec7e..c935f103c5b 100644 --- a/tests/perf_bench/bm_pidigits.py +++ b/tests/perf_bench/bm_pidigits.py @@ -5,6 +5,12 @@ # This benchmark stresses big integer arithmetic. # Adapted from code on: http://benchmarksgame.alioth.debian.org/ +try: + int("0x10000000000000000", 16) +except: + print("SKIP") # No support for >64-bit integers + raise SystemExit + def compose(a, b): aq, ar, as_, at = a diff --git a/tests/perf_bench/core_import_mpy_multi.py b/tests/perf_bench/core_import_mpy_multi.py index 8affa157fa0..55aa379e2bf 100644 --- a/tests/perf_bench/core_import_mpy_multi.py +++ b/tests/perf_bench/core_import_mpy_multi.py @@ -1,12 +1,13 @@ # Test performance of importing an .mpy file many times. -import sys, io, vfs - -if not hasattr(io, "IOBase"): +try: + import sys, vfs + from io import IOBase +except ImportError: print("SKIP") raise SystemExit -# This is the test.py file that is compiled to test.mpy below. +# This is the test.py file that is compiled to test.mpy below. mpy-cross must be invoked with `-msmall-int-bits=30`. """ class A: def __init__(self, arg): @@ -23,10 +24,10 @@ def f(): x = ("const tuple", None, False, True, 1, 2, 3) result = 123 """ -file_data = b'M\x06\x00\x1f\x14\x03\x0etest.py\x00\x0f\x02A\x00\x02f\x00\x0cresult\x00/-5#\x82I\x81{\x81w\x82/\x81\x05\x81\x17Iom\x82\x13\x06arg\x00\x05\x1cthis will be a string object\x00\x06\x1bthis will be a bytes object\x00\n\x07\x05\x0bconst tuple\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x81\\\x10\n\x01\x89\x07d`T2\x00\x10\x024\x02\x16\x022\x01\x16\x03"\x80{\x16\x04Qc\x02\x81d\x00\x08\x02(DD\x11\x05\x16\x06\x10\x02\x16\x072\x00\x16\x082\x01\x16\t2\x02\x16\nQc\x03`\x1a\x08\x08\x12\x13@\xb1\xb0\x18\x13Qc@\t\x08\t\x12` Qc@\t\x08\n\x12``Qc\x82@ \x0e\x03\x80\x08+)##\x12\x0b\x12\x0c\x12\r\x12\x0e*\x04Y\x12\x0f\x12\x10\x12\x11*\x03Y#\x00\xc0#\x01\xc0#\x02\xc0Qc' +file_data = b'M\x06\x00\x1e\x14\x03\x0etest.py\x00\x0f\x02A\x00\x02f\x00\x0cresult\x00/-5#\x82I\x81{\x81w\x82/\x81\x05\x81\x17Iom\x82\x13\x06arg\x00\x05\x1cthis will be a string object\x00\x06\x1bthis will be a bytes object\x00\n\x07\x05\x0bconst tuple\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x81\\\x10\n\x01\x89\x07d`T2\x00\x10\x024\x02\x16\x022\x01\x16\x03"\x80{\x16\x04Qc\x02\x81d\x00\x08\x02(DD\x11\x05\x16\x06\x10\x02\x16\x072\x00\x16\x082\x01\x16\t2\x02\x16\nQc\x03`\x1a\x08\x08\x12\x13@\xb1\xb0\x18\x13Qc@\t\x08\t\x12` Qc@\t\x08\n\x12``Qc\x82@ \x0e\x03\x80\x08+)##\x12\x0b\x12\x0c\x12\r\x12\x0e*\x04Y\x12\x0f\x12\x10\x12\x11*\x03Y#\x00\xc0#\x01\xc0#\x02\xc0Qc' -class File(io.IOBase): +class File(IOBase): def __init__(self): self.off = 0 diff --git a/tests/perf_bench/core_import_mpy_single.py b/tests/perf_bench/core_import_mpy_single.py index 4d9aa67bf2f..755e4159487 100644 --- a/tests/perf_bench/core_import_mpy_single.py +++ b/tests/perf_bench/core_import_mpy_single.py @@ -2,13 +2,14 @@ # The first import of a module will intern strings that don't already exist, and # this test should be representative of what happens in a real application. -import sys, io, vfs - -if not hasattr(io, "IOBase"): +try: + import sys, vfs + from io import IOBase +except ImportError: print("SKIP") raise SystemExit -# This is the test.py file that is compiled to test.mpy below. +# This is the test.py file that is compiled to test.mpy below. mpy-cross must be invoked with `-msmall-int-bits=30`. # Many known and unknown names/strings are included to test the linking process. """ class A0: @@ -78,10 +79,10 @@ def f1(): x = ("const tuple 9", None, False, True, 1, 2, 3) result = 123 """ -file_data = b"M\x06\x00\x1f\x81=\x1e\x0etest.py\x00\x0f\x04A0\x00\x04A1\x00\x04f0\x00\x04f1\x00\x0cresult\x00/-5\x04a0\x00\x04a1\x00\x04a2\x00\x04a3\x00\x13\x15\x17\x19\x1b\x1d\x1f!#%')+1379;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}\x7f\x81\x01\x81\x03\x81\x05\x81\x07\x81\t\x81\x0b\x81\r\x81\x0f\x81\x11\x81\x13\x81\x15\x81\x17\x81\x19\x81\x1b\x81\x1d\x81\x1f\x81!\x81#\x81%\x81'\x81)\x81+\x81-\x81/\x811\x813\x815\x817\x819\x81;\x81=\x81?\x81A\x81C\x81E\x81G\x81I\x81K\x81M\x81O\x81Q\x81S\x81U\x81W\x81Y\x81[\x81]\x81_\x81a\x81c\x81e\x81g\x81i\x81k\x81m\x81o\x81q\x81s\x81u\x81w\x81y\x81{\x81}\x81\x7f\x82\x01\x82\x03\x82\x05\x82\x07\x82\t\x82\x0b\x82\r\x82\x0f\x82\x11\x82\x13\x82\x15\x82\x17\x82\x19\x82\x1b\x82\x1d\x82\x1f\x82!\x82#\x82%\x82'\x82)\x82+\x82-\x82/\x821\x823\x825\x827\x829\x82;\x82=\x82?\x82A\x82E\x82G\x82I\x82K\nname0\x00\nname1\x00\nname2\x00\nname3\x00\nname4\x00\nname5\x00\nname6\x00\nname7\x00\nname8\x00\nname9\x00$quite_a_long_name0\x00$quite_a_long_name1\x00$quite_a_long_name2\x00$quite_a_long_name3\x00$quite_a_long_name4\x00$quite_a_long_name5\x00$quite_a_long_name6\x00$quite_a_long_name7\x00$quite_a_long_name8\x00$quite_a_long_name9\x00&quite_a_long_name10\x00&quite_a_long_name11\x00\x05\x1ethis will be a string object 0\x00\x05\x1ethis will be a string object 1\x00\x05\x1ethis will be a string object 2\x00\x05\x1ethis will be a string object 3\x00\x05\x1ethis will be a string object 4\x00\x05\x1ethis will be a string object 5\x00\x05\x1ethis will be a string object 6\x00\x05\x1ethis will be a string object 7\x00\x05\x1ethis will be a string object 8\x00\x05\x1ethis will be a string object 9\x00\x06\x1dthis will be a bytes object 0\x00\x06\x1dthis will be a bytes object 1\x00\x06\x1dthis will be a bytes object 2\x00\x06\x1dthis will be a bytes object 3\x00\x06\x1dthis will be a bytes object 4\x00\x06\x1dthis will be a bytes object 5\x00\x06\x1dthis will be a bytes object 6\x00\x06\x1dthis will be a bytes object 7\x00\x06\x1dthis will be a bytes object 8\x00\x06\x1dthis will be a bytes object 9\x00\n\x07\x05\rconst tuple 0\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 1\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 2\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 3\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 4\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 5\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 6\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 7\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 8\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 9\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x82d\x10\x12\x01i@i@\x84\x18\x84\x1fT2\x00\x10\x024\x02\x16\x02T2\x01\x10\x034\x02\x16\x032\x02\x16\x042\x03\x16\x05\"\x80{\x16\x06Qc\x04\x82\x0c\x00\n\x02($$$\x11\x07\x16\x08\x10\x02\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04@\t\x08\n\x81\x0b Qc@\t\x08\x0b\x81\x0b@Qc@\t\x08\x0c\x81\x0b`QcH\t\n\r\x81\x0b` Qc\x82\x14\x00\x0c\x03h`$$$\x11\x07\x16\x08\x10\x03\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04H\t\n\n\x81\x0b``QcH\t\n\x0b\x81\x0b\x80\x07QcH\t\n\x0c\x81\x0b\x80\x08QcH\t\n\r\x81\x0b\x80\tQc\xa08P:\x04\x80\x0b13///---997799<\x1f%\x1f\"\x1f%)\x1f\"//\x12\x0e\x12\x0f\x12\x10\x12\x11\x12\x12\x12\x13\x12\x14*\x07Y\x12\x15\x12\x16\x12\x17\x12\x18\x12\x19\x12\x1a\x12\x08\x12\x07*\x08Y\x12\x1b\x12\x1c\x12\t\x12\x1d\x12\x1e\x12\x1f*\x06Y\x12 \x12!\x12\"\x12#\x12$\x12%*\x06Y\x12&\x12'\x12(\x12)\x12*\x12+*\x06Y\x12,\x12-\x12.\x12/\x120*\x05Y\x121\x122\x123\x124\x125*\x05Y\x126\x127\x128\x129\x12:*\x05Y\x12;\x12<\x12=\x12>\x12?\x12@\x12A\x12B\x12C\x12D\x12E*\x0bY\x12F\x12G\x12H\x12I\x12J\x12K\x12L\x12M\x12N\x12O\x12P*\x0bY\x12Q\x12R\x12S\x12T\x12U\x12V\x12W\x12X\x12Y\x12Z*\nY\x12[\x12\\\x12]\x12^\x12_\x12`\x12a\x12b\x12c\x12d*\nY\x12e\x12f\x12g\x12h\x12i\x12j\x12k\x12l\x12m\x12n\x12o*\x0bY\x12p\x12q\x12r\x12s\x12t\x12u\x12v\x12w\x12x\x12y\x12z*\x0bY\x12{\x12|\x12}\x12~\x12\x7f\x12\x81\x00\x12\x81\x01\x12\x81\x02\x12\x81\x03\x12\x81\x04*\nY\x12\x81\x05\x12\x81\x06\x12\x81\x07\x12\x81\x08\x12\x81\t\x12\x81\n\x12\x81\x0b\x12\x81\x0c\x12\x81\r\x12\x81\x0e\x12\x81\x0f*\x0bY\x12\x81\x10\x12\x81\x11\x12\x81\x12\x12\x81\x13\x12\x81\x14\x12\x81\x15\x12\x81\x16\x12\x81\x17\x12\x81\x18\x12\x81\x19*\nY\x12\x81\x1a\x12\x81\x1b\x12\x81\x1c\x12\x81\x1d\x12\x81\x1e\x12\x81\x1f\x12\x81 \x12\x81!\x12\x81\"\x12\x81#\x12\x81$*\x0bY\x12\x81%\x12\x81&*\x02Y\x12\x81'\x12\x81(\x12\x81)\x12\x81*\x12\x81+\x12\x81,\x12\x81-\x12\x81.\x12\x81/\x12\x810*\nY\x12\x811\x12\x812\x12\x813\x12\x814*\x04Y\x12\x815\x12\x816\x12\x817\x12\x818*\x04Y\x12\x819\x12\x81:\x12\x81;\x12\x81<*\x04YQc\x87p\x08@\x05\x80###############################\x00\xc0#\x01\xc0#\x02\xc0#\x03\xc0#\x04\xc0#\x05\xc0#\x06\xc0#\x07\xc0#\x08\xc0#\t\xc0#\n\xc0#\x0b\xc0#\x0c\xc0#\r\xc0#\x0e\xc0#\x0f\xc0#\x10\xc0#\x11\xc0#\x12\xc0#\x13\xc0#\x14\xc0#\x15\xc0#\x16\xc0#\x17\xc0#\x18\xc0#\x19\xc0#\x1a\xc0#\x1b\xc0#\x1c\xc0#\x1d\xc0Qc" +file_data = b"M\x06\x00\x1e\x81=\x1e\x0etest.py\x00\x0f\x04A0\x00\x04A1\x00\x04f0\x00\x04f1\x00\x0cresult\x00/-5\x04a0\x00\x04a1\x00\x04a2\x00\x04a3\x00\x13\x15\x17\x19\x1b\x1d\x1f!#%')+1379;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}\x7f\x81\x01\x81\x03\x81\x05\x81\x07\x81\t\x81\x0b\x81\r\x81\x0f\x81\x11\x81\x13\x81\x15\x81\x17\x81\x19\x81\x1b\x81\x1d\x81\x1f\x81!\x81#\x81%\x81'\x81)\x81+\x81-\x81/\x811\x813\x815\x817\x819\x81;\x81=\x81?\x81A\x81C\x81E\x81G\x81I\x81K\x81M\x81O\x81Q\x81S\x81U\x81W\x81Y\x81[\x81]\x81_\x81a\x81c\x81e\x81g\x81i\x81k\x81m\x81o\x81q\x81s\x81u\x81w\x81y\x81{\x81}\x81\x7f\x82\x01\x82\x03\x82\x05\x82\x07\x82\t\x82\x0b\x82\r\x82\x0f\x82\x11\x82\x13\x82\x15\x82\x17\x82\x19\x82\x1b\x82\x1d\x82\x1f\x82!\x82#\x82%\x82'\x82)\x82+\x82-\x82/\x821\x823\x825\x827\x829\x82;\x82=\x82?\x82A\x82E\x82G\x82I\x82K\nname0\x00\nname1\x00\nname2\x00\nname3\x00\nname4\x00\nname5\x00\nname6\x00\nname7\x00\nname8\x00\nname9\x00$quite_a_long_name0\x00$quite_a_long_name1\x00$quite_a_long_name2\x00$quite_a_long_name3\x00$quite_a_long_name4\x00$quite_a_long_name5\x00$quite_a_long_name6\x00$quite_a_long_name7\x00$quite_a_long_name8\x00$quite_a_long_name9\x00&quite_a_long_name10\x00&quite_a_long_name11\x00\x05\x1ethis will be a string object 0\x00\x05\x1ethis will be a string object 1\x00\x05\x1ethis will be a string object 2\x00\x05\x1ethis will be a string object 3\x00\x05\x1ethis will be a string object 4\x00\x05\x1ethis will be a string object 5\x00\x05\x1ethis will be a string object 6\x00\x05\x1ethis will be a string object 7\x00\x05\x1ethis will be a string object 8\x00\x05\x1ethis will be a string object 9\x00\x06\x1dthis will be a bytes object 0\x00\x06\x1dthis will be a bytes object 1\x00\x06\x1dthis will be a bytes object 2\x00\x06\x1dthis will be a bytes object 3\x00\x06\x1dthis will be a bytes object 4\x00\x06\x1dthis will be a bytes object 5\x00\x06\x1dthis will be a bytes object 6\x00\x06\x1dthis will be a bytes object 7\x00\x06\x1dthis will be a bytes object 8\x00\x06\x1dthis will be a bytes object 9\x00\n\x07\x05\rconst tuple 0\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 1\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 2\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 3\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 4\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 5\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 6\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 7\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 8\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 9\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x82d\x10\x12\x01i@i@\x84\x18\x84\x1fT2\x00\x10\x024\x02\x16\x02T2\x01\x10\x034\x02\x16\x032\x02\x16\x042\x03\x16\x05\"\x80{\x16\x06Qc\x04\x82\x0c\x00\n\x02($$$\x11\x07\x16\x08\x10\x02\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04@\t\x08\n\x81\x0b Qc@\t\x08\x0b\x81\x0b@Qc@\t\x08\x0c\x81\x0b`QcH\t\n\r\x81\x0b` Qc\x82\x14\x00\x0c\x03h`$$$\x11\x07\x16\x08\x10\x03\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04H\t\n\n\x81\x0b``QcH\t\n\x0b\x81\x0b\x80\x07QcH\t\n\x0c\x81\x0b\x80\x08QcH\t\n\r\x81\x0b\x80\tQc\xa08P:\x04\x80\x0b13///---997799<\x1f%\x1f\"\x1f%)\x1f\"//\x12\x0e\x12\x0f\x12\x10\x12\x11\x12\x12\x12\x13\x12\x14*\x07Y\x12\x15\x12\x16\x12\x17\x12\x18\x12\x19\x12\x1a\x12\x08\x12\x07*\x08Y\x12\x1b\x12\x1c\x12\t\x12\x1d\x12\x1e\x12\x1f*\x06Y\x12 \x12!\x12\"\x12#\x12$\x12%*\x06Y\x12&\x12'\x12(\x12)\x12*\x12+*\x06Y\x12,\x12-\x12.\x12/\x120*\x05Y\x121\x122\x123\x124\x125*\x05Y\x126\x127\x128\x129\x12:*\x05Y\x12;\x12<\x12=\x12>\x12?\x12@\x12A\x12B\x12C\x12D\x12E*\x0bY\x12F\x12G\x12H\x12I\x12J\x12K\x12L\x12M\x12N\x12O\x12P*\x0bY\x12Q\x12R\x12S\x12T\x12U\x12V\x12W\x12X\x12Y\x12Z*\nY\x12[\x12\\\x12]\x12^\x12_\x12`\x12a\x12b\x12c\x12d*\nY\x12e\x12f\x12g\x12h\x12i\x12j\x12k\x12l\x12m\x12n\x12o*\x0bY\x12p\x12q\x12r\x12s\x12t\x12u\x12v\x12w\x12x\x12y\x12z*\x0bY\x12{\x12|\x12}\x12~\x12\x7f\x12\x81\x00\x12\x81\x01\x12\x81\x02\x12\x81\x03\x12\x81\x04*\nY\x12\x81\x05\x12\x81\x06\x12\x81\x07\x12\x81\x08\x12\x81\t\x12\x81\n\x12\x81\x0b\x12\x81\x0c\x12\x81\r\x12\x81\x0e\x12\x81\x0f*\x0bY\x12\x81\x10\x12\x81\x11\x12\x81\x12\x12\x81\x13\x12\x81\x14\x12\x81\x15\x12\x81\x16\x12\x81\x17\x12\x81\x18\x12\x81\x19*\nY\x12\x81\x1a\x12\x81\x1b\x12\x81\x1c\x12\x81\x1d\x12\x81\x1e\x12\x81\x1f\x12\x81 \x12\x81!\x12\x81\"\x12\x81#\x12\x81$*\x0bY\x12\x81%\x12\x81&*\x02Y\x12\x81'\x12\x81(\x12\x81)\x12\x81*\x12\x81+\x12\x81,\x12\x81-\x12\x81.\x12\x81/\x12\x810*\nY\x12\x811\x12\x812\x12\x813\x12\x814*\x04Y\x12\x815\x12\x816\x12\x817\x12\x818*\x04Y\x12\x819\x12\x81:\x12\x81;\x12\x81<*\x04YQc\x87p\x08@\x05\x80###############################\x00\xc0#\x01\xc0#\x02\xc0#\x03\xc0#\x04\xc0#\x05\xc0#\x06\xc0#\x07\xc0#\x08\xc0#\t\xc0#\n\xc0#\x0b\xc0#\x0c\xc0#\r\xc0#\x0e\xc0#\x0f\xc0#\x10\xc0#\x11\xc0#\x12\xc0#\x13\xc0#\x14\xc0#\x15\xc0#\x16\xc0#\x17\xc0#\x18\xc0#\x19\xc0#\x1a\xc0#\x1b\xc0#\x1c\xc0#\x1d\xc0Qc" -class File(io.IOBase): +class File(IOBase): def __init__(self): self.off = 0 diff --git a/tests/run-internalbench.py b/tests/run-internalbench.py index c9f783e474c..715b0ffc9ed 100755 --- a/tests/run-internalbench.py +++ b/tests/run-internalbench.py @@ -8,48 +8,92 @@ from glob import glob from collections import defaultdict +from test_utils import ( + base_path, + pyboard, + test_instance_description, + test_instance_epilog, + test_directory_description, + get_test_instance, +) + if os.name == "nt": MICROPYTHON = os.getenv( "MICROPY_MICROPYTHON", "../ports/windows/build-standard/micropython.exe" ) + CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3") else: MICROPYTHON = os.getenv("MICROPY_MICROPYTHON", "../ports/unix/build-standard/micropython") + CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3") + +MICROPYTHON_CMD = [MICROPYTHON, "-X", "emit=bytecode"] +CPYTHON3_CMD = [CPYTHON3, "-BS"] + + +injected_bench_code = b""" +import time +class bench_class: + ITERS = 20000000 + + @staticmethod + def run(test): + t = time.ticks_us() + test(bench_class.ITERS) + t = time.ticks_diff(time.ticks_us(), t) + s, us = divmod(t, 1_000_000) + print("{}.{:06}".format(s, us)) + +import sys +sys.modules['bench'] = bench_class +""" -def run_tests(pyb, test_dict): + +def execbench(test_instance, filename, iters): + with open(filename, "rb") as f: + pyfile = f.read() + code = (injected_bench_code + pyfile).replace(b"20000000", str(iters).encode("utf-8")) + return test_instance.exec(code).replace(b"\r\n", b"\n") + + +def run_tests(test_instance, test_dict, iters): test_count = 0 testcase_count = 0 for base_test, tests in sorted(test_dict.items()): print(base_test + ":") + baseline = None for test_file in tests: # run MicroPython - if pyb is None: + if isinstance(test_instance, list): # run on PC try: - output_mupy = subprocess.check_output( - [MICROPYTHON, "-X", "emit=bytecode", test_file[0]] - ) + output_mupy = subprocess.check_output(test_instance + [test_file[0]]) except subprocess.CalledProcessError: output_mupy = b"CRASH" else: # run on pyboard - pyb.enter_raw_repl() + test_instance.enter_raw_repl() try: - output_mupy = pyb.execfile(test_file).replace(b"\r\n", b"\n") + output_mupy = execbench(test_instance, test_file[0], iters) except pyboard.PyboardError: output_mupy = b"CRASH" - output_mupy = float(output_mupy.strip()) + try: + output_mupy = float(output_mupy.strip()) + except ValueError: + output_mupy = -1 test_file[1] = output_mupy testcase_count += 1 - test_count += 1 - baseline = None - for t in tests: if baseline is None: - baseline = t[1] - print(" %.3fs (%+06.2f%%) %s" % (t[1], (t[1] * 100 / baseline) - 100, t[0])) + baseline = test_file[1] + print( + " %.3fs (%+06.2f%%) %s" + % (test_file[1], (test_file[1] * 100 / baseline) - 100, test_file[0]) + ) + + test_count += 1 print("{} tests performed ({} individual testcases)".format(test_count, testcase_count)) @@ -58,27 +102,52 @@ def run_tests(pyb, test_dict): def main(): - cmd_parser = argparse.ArgumentParser(description="Run tests for MicroPython.") - cmd_parser.add_argument("--pyboard", action="store_true", help="run the tests on the pyboard") + cmd_parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description=f"""Run and manage tests for MicroPython. + +{test_instance_description} +{test_directory_description} +""", + epilog=f"""{test_instance_epilog}- cpython - use CPython to run the benchmarks instead\n""", + ) + cmd_parser.add_argument( + "-t", "--test-instance", default="unix", help="the MicroPython instance to test" + ) + cmd_parser.add_argument( + "-b", "--baudrate", default=115200, help="the baud rate of the serial device" + ) + cmd_parser.add_argument("-u", "--user", default="micro", help="the telnet login username") + cmd_parser.add_argument("-p", "--password", default="python", help="the telnet login password") + cmd_parser.add_argument( + "-d", "--test-dirs", nargs="*", help="input test directories (if no files given)" + ) + cmd_parser.add_argument( + "-I", + "--iters", + type=int, + default=200_000, + help="number of test iterations, only for remote instances (default 200,000)", + ) cmd_parser.add_argument("files", nargs="*", help="input test files") args = cmd_parser.parse_args() - # Note pyboard support is copied over from run-tests.py, not tests, and likely needs revamping - if args.pyboard: - import pyboard - - pyb = pyboard.Pyboard("/dev/ttyACM0") - pyb.enter_raw_repl() + if args.test_instance == "cpython": + test_instance = CPYTHON3_CMD else: - pyb = None + # Note pyboard support is copied over from run-tests.py, not tests, and likely needs revamping + test_instance = get_test_instance( + args.test_instance, args.baudrate, args.user, args.password + ) + if test_instance is None: + test_instance = MICROPYTHON_CMD if len(args.files) == 0: - if pyb is None: - # run PC tests - test_dirs = ("internal_bench",) + if args.test_dirs: + test_dirs = tuple(args.test_dirs) else: - # run pyboard tests - test_dirs = ("basics", "float", "pyb") + test_dirs = ("internal_bench",) + tests = sorted( test_file for test_files in (glob("{}/*.py".format(dir)) for dir in test_dirs) @@ -95,7 +164,7 @@ def main(): continue test_dict[m.group(1)].append([t, None]) - if not run_tests(pyb, test_dict): + if not run_tests(test_instance, test_dict, args.iters): sys.exit(1) diff --git a/tests/run-multitests.py b/tests/run-multitests.py index 387eec7018b..de59db2dc38 100755 --- a/tests/run-multitests.py +++ b/tests/run-multitests.py @@ -15,6 +15,14 @@ import subprocess import tempfile +from test_utils import ( + base_path, + pyboard, + test_instance_epilog, + convert_device_shortcut_to_real_device, + create_test_report, +) + test_dir = os.path.abspath(os.path.dirname(__file__)) if os.path.abspath(sys.path[0]) == test_dir: @@ -22,9 +30,6 @@ # accidentally importing tests like micropython/const.py sys.path.pop(0) -sys.path.insert(0, test_dir + "/../tools") -import pyboard - if os.name == "nt": CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3.exe") MICROPYTHON = os.path.abspath( @@ -130,6 +135,11 @@ def get_host_ip(_ip_cache=[]): return _ip_cache[0] +def decode(output): + # Convenience function to convert raw process or serial output to ASCII + return str(output, "ascii", "backslashreplace") + + class PyInstance: def __init__(self): pass @@ -188,7 +198,7 @@ def run_script(self, script): output = p.stdout except subprocess.CalledProcessError as er: err = er - return str(output.strip(), "ascii"), err + return decode(output.strip()), err def start_script(self, script): self.popen = subprocess.Popen( @@ -215,7 +225,7 @@ def readline(self): self.finished = self.popen.poll() is not None return None, None else: - return str(out.rstrip(), "ascii"), None + return decode(out.rstrip()), None def write(self, data): self.popen.stdin.write(data) @@ -227,21 +237,12 @@ def is_finished(self): def wait_finished(self): self.popen.wait() out = self.popen.stdout.read() - return str(out, "ascii"), "" + return decode(out), "" class PyInstancePyboard(PyInstance): - @staticmethod - def map_device_shortcut(device): - if device[0] == "a" and device[1:].isdigit(): - return "/dev/ttyACM" + device[1:] - elif device[0] == "u" and device[1:].isdigit(): - return "/dev/ttyUSB" + device[1:] - else: - return device - def __init__(self, device): - device = self.map_device_shortcut(device) + device = device self.device = device self.pyb = pyboard.Pyboard(device) self.pyb.enter_raw_repl() @@ -262,7 +263,7 @@ def run_script(self, script): output = self.pyb.exec_(script) except pyboard.PyboardError as er: err = er - return str(output.strip(), "ascii"), err + return decode(output.strip()), err def start_script(self, script): self.pyb.enter_raw_repl() @@ -275,19 +276,22 @@ def stop(self): def readline(self): if self.finished: return None, None - if self.pyb.serial.inWaiting() == 0: - return None, None - out = self.pyb.read_until(1, (b"\r\n", b"\x04")) - if out.endswith(b"\x04"): - self.finished = True - out = out[:-1] - err = str(self.pyb.read_until(1, b"\x04"), "ascii") - err = err[:-1] - if not out and not err: + try: + if self.pyb.serial.inWaiting() == 0: return None, None - else: - err = None - return str(out.rstrip(), "ascii"), err + out = self.pyb.read_until(1, (b"\r\n", b"\x04")) + if out.endswith(b"\x04"): + self.finished = True + out = out[:-1] + err = decode(self.pyb.read_until(1, b"\x04")) + err = err[:-1] + if not out and not err: + return None, None + else: + err = None + return decode(out.rstrip()), err + except OSError as e: + return None, "Failed to read from instance: {}".format(e) def write(self, data): self.pyb.serial.write(data) @@ -297,7 +301,7 @@ def is_finished(self): def wait_finished(self): out, err = self.pyb.follow(10, None) - return str(out, "ascii"), str(err, "ascii") + return decode(out), decode(err) def prepare_test_file_list(test_files): @@ -433,7 +437,10 @@ def run_test_on_instances(test_file, num_instances, instances): # Stop all instances for idx in range(num_instances): - instances[idx].stop() + try: + instances[idx].stop() + except OSError as e: + output[idx].append("Runner failed to stop instance: {}".format(e)) output_str = "" for idx, lines in enumerate(output): @@ -488,9 +495,7 @@ def print_diff(a, b): def run_tests(test_files, instances_truth, instances_test): - skipped_tests = [] - passed_tests = [] - failed_tests = [] + test_results = [] for test_file, num_instances in test_files: instances_str = "|".join(str(instances_test[i]) for i in range(num_instances)) @@ -526,13 +531,13 @@ def run_tests(test_files, instances_truth, instances_test): # Print result of test if skip: print("skip") - skipped_tests.append(test_file) + test_results.append((test_file, "skip", "")) elif output_test == output_truth: print("pass") - passed_tests.append(test_file) + test_results.append((test_file, "pass", "")) else: print("FAIL") - failed_tests.append(test_file) + test_results.append((test_file, "fail", "")) if not cmd_args.show_output: print("### TEST ###") print(output_test, end="") @@ -549,15 +554,7 @@ def run_tests(test_files, instances_truth, instances_test): if cmd_args.show_output: print() - print("{} tests performed".format(len(skipped_tests) + len(passed_tests) + len(failed_tests))) - print("{} tests passed".format(len(passed_tests))) - - if skipped_tests: - print("{} tests skipped: {}".format(len(skipped_tests), " ".join(skipped_tests))) - if failed_tests: - print("{} tests failed: {}".format(len(failed_tests), " ".join(failed_tests))) - - return not failed_tests + return test_results def main(): @@ -565,16 +562,24 @@ def main(): cmd_parser = argparse.ArgumentParser( description="Run network tests for MicroPython", + epilog=( + test_instance_epilog + + "Each instance arg can optionally have custom env provided, eg. ,ENV=VAR,ENV=VAR...\n" + ), formatter_class=argparse.RawTextHelpFormatter, ) cmd_parser.add_argument( "-s", "--show-output", action="store_true", help="show test output after running" ) cmd_parser.add_argument( - "-t", "--trace-output", action="store_true", help="trace test output while running" + "-c", "--trace-output", action="store_true", help="trace test output while running" ) cmd_parser.add_argument( - "-i", "--instance", action="append", default=[], help="instance(s) to run the tests on" + "-t", + "--test-instance", + action="append", + default=[], + help="instance(s) to run the tests on", ) cmd_parser.add_argument( "-p", @@ -583,19 +588,17 @@ def main(): default=1, help="repeat the test with this many permutations of the instance order", ) - cmd_parser.epilog = ( - "Supported instance types:\r\n" - " -i pyb: physical device (eg. pyboard) on provided repl port.\n" - " -i micropython unix micropython instance, path customised with MICROPY_MICROPYTHON env.\n" - " -i cpython desktop python3 instance, path customised with MICROPY_CPYTHON3 env.\n" - " -i exec: custom program run on provided path.\n" - "Each instance arg can optionally have custom env provided, eg. ,ENV=VAR,ENV=VAR...\n" + cmd_parser.add_argument( + "-r", + "--result-dir", + default=base_path("results"), + help="directory for test results", ) cmd_parser.add_argument("files", nargs="+", help="input test files") cmd_args = cmd_parser.parse_args() # clear search path to make sure tests use only builtin modules and those in extmod - os.environ["MICROPYPATH"] = os.pathsep.join((".frozen", "../extmod")) + os.environ["MICROPYPATH"] = os.pathsep.join((".frozen", base_path("../extmod"))) test_files = prepare_test_file_list(cmd_args.files) max_instances = max(t[1] for t in test_files) @@ -603,33 +606,36 @@ def main(): instances_truth = [PyInstanceSubProcess([PYTHON_TRUTH]) for _ in range(max_instances)] instances_test = [] - for i in cmd_args.instance: + for i in cmd_args.test_instance: # Each instance arg is ,ENV=VAR,ENV=VAR... i = i.split(",") cmd = i[0] env = i[1:] if cmd.startswith("exec:"): instances_test.append(PyInstanceSubProcess([cmd[len("exec:") :]], env)) - elif cmd == "micropython": + elif cmd == "unix": instances_test.append(PyInstanceSubProcess([MICROPYTHON], env)) elif cmd == "cpython": instances_test.append(PyInstanceSubProcess([CPYTHON3], env)) - elif cmd.startswith("pyb:"): - instances_test.append(PyInstancePyboard(cmd[len("pyb:") :])) + elif cmd == "webassembly" or cmd.startswith("execpty:"): + print("unsupported instance string: {}".format(cmd), file=sys.stderr) + sys.exit(2) else: - print("unknown instance string: {}".format(cmd), file=sys.stderr) - sys.exit(1) + device = convert_device_shortcut_to_real_device(cmd) + instances_test.append(PyInstancePyboard(device)) for _ in range(max_instances - len(instances_test)): instances_test.append(PyInstanceSubProcess([MICROPYTHON])) + os.makedirs(cmd_args.result_dir, exist_ok=True) all_pass = True try: for i, instances_test_permutation in enumerate(itertools.permutations(instances_test)): if i >= cmd_args.permutations: break - all_pass &= run_tests(test_files, instances_truth, instances_test_permutation) + test_results = run_tests(test_files, instances_truth, instances_test_permutation) + all_pass &= create_test_report(cmd_args, test_results) finally: for i in instances_truth: diff --git a/tests/run-natmodtests.py b/tests/run-natmodtests.py index 340a7f004b0..103450f0231 100755 --- a/tests/run-natmodtests.py +++ b/tests/run-natmodtests.py @@ -9,7 +9,15 @@ import sys import argparse -# CIRCUITPY-CHANGE: no pyboard +from test_utils import ( + base_path, + pyboard, + TEST_ENTER_RAW_REPL_TIMEOUT, + TEST_MAXIMUM_RAW_REPL_FAILURES, + test_instance_epilog, + get_test_instance, + create_test_report, +) # Paths for host executables CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3") @@ -38,6 +46,7 @@ "xtensa", "xtensawin", "rv32imc", + "rv64imc", ) ARCH_MAPPINGS = {"armv7em": "armv7m"} @@ -72,6 +81,7 @@ def open(self, path, mode): # CIRCUITPY-CHANGE: no vfs, but still have os os.mount(__FS(), '/__remote') sys.path.insert(0, '/__remote') +{import_prelude} sys.modules['{}'] = __import__('__injected') """ @@ -104,7 +114,7 @@ def close(self): def run_script(self, script): try: - self.pyb.enter_raw_repl() + self.pyb.enter_raw_repl(timeout_overall=TEST_ENTER_RAW_REPL_TIMEOUT) output = self.pyb.exec_(script) output = output.replace(b"\r\n", b"\n") return output, None @@ -131,7 +141,9 @@ def detect_architecture(target): return platform, arch, None -def run_tests(target_truth, target, args, stats, resolved_arch): +def run_tests(target_truth, target, args, resolved_arch): + raw_repl_failure_count = 0 + test_results = [] for test_file in args.files: # Find supported test test_file_basename = os.path.basename(test_file) @@ -154,9 +166,11 @@ def run_tests(target_truth, target, args, stats, resolved_arch): with open(NATMOD_EXAMPLE_DIR + test_mpy, "rb") as f: test_script += b"__buf=" + bytes(repr(f.read()), "ascii") + b"\n" except OSError: - print("---- {} - mpy file not compiled".format(test_file)) + test_results.append((test_file, "skip", "mpy file not compiled")) + print("skip {} - mpy file not compiled".format(test_file)) continue test_script += bytes(injected_import_hook_code.format(test_module), "ascii") + test_script += b"print('START TEST')\n" test_script += test_file_data # Run test under MicroPython @@ -164,11 +178,23 @@ def run_tests(target_truth, target, args, stats, resolved_arch): # Work out result of test extra = "" + result_out = result_out.removeprefix(b"START TEST\n") if error is None and result_out == b"SKIP\n": result = "SKIP" + elif ( + error is not None + and error.args[0] == "exception" + and error.args[1] == b"" + and b"MemoryError" in error.args[2] + ): + # Test had a MemoryError before anything (should be at least "START TEST") + # was printed, so the test is too big for the target. + result = "LRGE" elif error is not None: result = "FAIL" extra = " - " + str(error) + if str(error).startswith("could not enter raw repl"): + raw_repl_failure_count += 1 else: # Check result against truth try: @@ -186,40 +212,73 @@ def run_tests(target_truth, target, args, stats, resolved_arch): result = "pass" # Accumulate statistics - stats["total"] += 1 if result == "pass": - stats["pass"] += 1 + test_results.append((test_file, "pass", "")) elif result == "SKIP": - stats["skip"] += 1 + test_results.append((test_file, "skip", "")) + elif result == "LRGE": + test_results.append((test_file, "skip", "too large")) else: - stats["fail"] += 1 + test_results.append((test_file, "fail", "")) # Print result print("{:4} {}{}".format(result, test_file, extra)) + if raw_repl_failure_count > TEST_MAXIMUM_RAW_REPL_FAILURES: + print("Too many raw REPL failures, aborting test run") + break + + return test_results + def main(): + global injected_import_hook_code + cmd_parser = argparse.ArgumentParser( - description="Run dynamic-native-module tests under MicroPython" + description="Run dynamic-native-module tests under MicroPython", + epilog=test_instance_epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, ) cmd_parser.add_argument( - "-p", "--pyboard", action="store_true", help="run tests via pyboard.py" + "-t", "--test-instance", default="unix", help="the MicroPython instance to test" ) + cmd_parser.add_argument("--baudrate", default=115200, help="baud rate of the serial device") + cmd_parser.add_argument("--user", default="micro", help="telnet login username") + cmd_parser.add_argument("--password", default="python", help="telnet login password") cmd_parser.add_argument( - "-d", "--device", default="/dev/ttyACM0", help="the device for pyboard.py" + "-a", "--arch", choices=AVAILABLE_ARCHS, help="override native architecture of the target" ) cmd_parser.add_argument( - "-a", "--arch", choices=AVAILABLE_ARCHS, help="override native architecture of the target" + "-b", + "--begin", + metavar="PROLOGUE", + default=None, + help="prologue python file to execute before module import", + ) + cmd_parser.add_argument( + "-r", + "--result-dir", + default=base_path("results"), + help="directory for test results", ) cmd_parser.add_argument("files", nargs="*", help="input test files") args = cmd_parser.parse_args() + prologue = "" + if args.begin: + with open(args.begin, "rt") as source: + prologue = source.read() + injected_import_hook_code = injected_import_hook_code.replace("{import_prelude}", prologue) + target_truth = TargetSubprocess([CPYTHON3]) - if args.pyboard: - target = TargetPyboard(pyboard.Pyboard(args.device)) - else: + target = get_test_instance(args.test_instance, args.baudrate, args.user, args.password) + if target is None: + # Use the unix port of MicroPython. target = TargetSubprocess([MICROPYTHON]) + else: + # Use a remote target. + target = TargetPyboard(target) if hasattr(args, "arch") and args.arch is not None: target_arch = args.arch @@ -228,27 +287,21 @@ def main(): target_platform, target_arch, error = detect_architecture(target) if error: print("Cannot run tests: {}".format(error)) - sys.exit(1) + sys.exit(2) target_arch = ARCH_MAPPINGS.get(target_arch, target_arch) if target_platform: print("platform={} ".format(target_platform), end="") print("arch={}".format(target_arch)) - stats = {"total": 0, "pass": 0, "fail": 0, "skip": 0} - run_tests(target_truth, target, args, stats, target_arch) + os.makedirs(args.result_dir, exist_ok=True) + test_results = run_tests(target_truth, target, args, target_arch) + res = create_test_report(args, test_results) target.close() target_truth.close() - print("{} tests performed".format(stats["total"])) - print("{} tests passed".format(stats["pass"])) - if stats["fail"]: - print("{} tests failed".format(stats["fail"])) - if stats["skip"]: - print("{} tests skipped".format(stats["skip"])) - - if stats["fail"]: + if not res: sys.exit(1) diff --git a/tests/run-perfbench.py b/tests/run-perfbench.py index 81d873c4599..2b17655095c 100755 --- a/tests/run-perfbench.py +++ b/tests/run-perfbench.py @@ -8,12 +8,17 @@ import subprocess import sys import argparse +import re from glob import glob -sys.path.append("../tools") -import pyboard - -prepare_script_for_target = __import__("run-tests").prepare_script_for_target +from test_utils import ( + base_path, + pyboard, + set_injected_prologue, + get_test_instance, + prepare_script_for_target, + create_test_report, +) # Paths for host executables if os.name == "nt": @@ -45,7 +50,7 @@ def run_script_on_target(target, script): output = b"" err = None - if isinstance(target, pyboard.Pyboard): + if hasattr(target, "enter_raw_repl"): # Run via pyboard interface try: target.enter_raw_repl() @@ -90,22 +95,22 @@ def run_benchmark_on_target(target, script): def run_benchmarks(args, target, param_n, param_m, n_average, test_list): + test_results = [] skip_complex = run_feature_test(target, "complex") != "complex" skip_native = run_feature_test(target, "native_check") != "native" - target_had_error = False for test_file in sorted(test_list): print(test_file + ": ", end="") # Check if test should be skipped - skip = ( - skip_complex - and test_file.find("bm_fft") != -1 - or skip_native - and test_file.find("viper_") != -1 - ) - if skip: - print("SKIP") + skip_reason = None + if skip_complex and test_file.endswith(("bm_fft.py", "misc_mandel.py")): + skip_reason = "complex not supported" + elif skip_native and test_file.find("viper_") != -1: + skip_reason = "native not supported" + if skip_reason: + test_results.append((test_file, "skip", skip_reason)) + print("SKIP:", skip_reason) continue # Create test script @@ -116,15 +121,29 @@ def run_benchmarks(args, target, param_n, param_m, n_average, test_list): test_script += f.read() test_script += b"bm_run(%u, %u)\n" % (param_n, param_m) + # Search for the bm_params dict, to extract the minimum memory required. + m = re.search(rb"bm_params = {\s+\((\d+), (\d+)\):", test_script) + if not m: + print(f"Test file '{test_file}' doesn't contain valid 'bm_params'") + sys.exit(2) + min_m = int(m.group(2)) + + # Skip the test if the target doesn't have enough memory. + if param_m < min_m: + test_results.append((test_file, "skip", "too large")) + print("SKIP: too large") + continue + # Write full test script if needed if 0: with open("%s.full" % test_file, "wb") as f: f.write(test_script) # Process script through mpy-cross if needed - if isinstance(target, pyboard.Pyboard) or args.via_mpy: - crash, test_script_target = prepare_script_for_target(args, script_text=test_script) + if hasattr(target, "enter_raw_repl") or args.via_mpy: + crash, test_script_target = prepare_script_for_target(args, test_script, test_file) if crash: + test_results.append((test_file, "fail", "preparation")) print("CRASH:", test_script_target) continue else: @@ -162,10 +181,13 @@ def run_benchmarks(args, target, param_n, param_m, n_average, test_list): error = "FAIL truth" if error is not None: - if not error.startswith("SKIP"): - target_had_error = True + if error.startswith("SKIP"): + test_results.append((test_file, "skip", error)) + else: + test_results.append((test_file, "fail", error)) print(error) else: + test_results.append((test_file, "pass", "")) t_avg, t_sd = compute_stats(times) s_avg, s_sd = compute_stats(scores) print( @@ -179,7 +201,7 @@ def run_benchmarks(args, target, param_n, param_m, n_average, test_list): sys.stdout.flush() - return target_had_error + return test_results def parse_output(filename): @@ -190,7 +212,13 @@ def parse_output(filename): m = int(m.split("=")[1]) data = [] for l in f: - if ": " in l and ": SKIP" not in l and "CRASH: " not in l: + if ( + ": " in l + and ": SKIP" not in l + and "CRASH: " not in l + and "skipped: " not in l + and "failed: " not in l + ): name, values = l.strip().split(": ") values = tuple(float(v) for v in values.split()) data.append((name,) + values) @@ -246,17 +274,17 @@ def compute_diff(file1, file2, diff_score): def main(): cmd_parser = argparse.ArgumentParser(description="Run benchmarks for MicroPython") cmd_parser.add_argument( - "-t", "--diff-time", action="store_true", help="diff time outputs from a previous run" + "-m", "--diff-time", action="store_true", help="diff time outputs from a previous run" ) cmd_parser.add_argument( "-s", "--diff-score", action="store_true", help="diff score outputs from a previous run" ) cmd_parser.add_argument( - "-p", "--pyboard", action="store_true", help="run tests via pyboard.py" - ) - cmd_parser.add_argument( - "-d", "--device", default="/dev/ttyACM0", help="the device for pyboard.py" + "-t", "--test-instance", default="unix", help="the MicroPython instance to test" ) + cmd_parser.add_argument("--baudrate", default=115200, help="baud rate of the serial device") + cmd_parser.add_argument("--user", default="micro", help="telnet login username") + cmd_parser.add_argument("--password", default="python", help="telnet login password") cmd_parser.add_argument("-a", "--average", default="8", help="averaging number") cmd_parser.add_argument( "--emit", default="bytecode", help="MicroPython emitter to use (bytecode or native)" @@ -264,6 +292,18 @@ def main(): cmd_parser.add_argument("--heapsize", help="heapsize to use (use default if not specified)") cmd_parser.add_argument("--via-mpy", action="store_true", help="compile code to .mpy first") cmd_parser.add_argument("--mpy-cross-flags", default="", help="flags to pass to mpy-cross") + cmd_parser.add_argument( + "--begin", + metavar="PROLOGUE", + default=None, + help="prologue python file to execute before module import", + ) + cmd_parser.add_argument( + "-r", + "--result-dir", + default=base_path("results"), + help="directory for test results", + ) cmd_parser.add_argument( "N", nargs=1, help="N parameter (approximate target CPU frequency in MHz)" ) @@ -275,6 +315,12 @@ def main(): compute_diff(args.N[0], args.M[0], args.diff_score) sys.exit(0) + prologue = "" + if args.begin: + with open(args.begin, "rt") as source: + prologue = source.read() + set_injected_prologue(prologue) + # N, M = 50, 25 # esp8266 # N, M = 100, 100 # pyboard, esp32 # N, M = 1000, 1000 # PC @@ -282,38 +328,37 @@ def main(): M = int(args.M[0]) n_average = int(args.average) - if args.pyboard: - if not args.mpy_cross_flags: - args.mpy_cross_flags = "-march=armv7m" - target = pyboard.Pyboard(args.device) - target.enter_raw_repl() - else: + target = get_test_instance(args.test_instance, args.baudrate, args.user, args.password) + if target is None: + # Use the unix port of MicroPython. target = [MICROPYTHON, "-X", "emit=" + args.emit] if args.heapsize is not None: target.extend(["-X", "heapsize=" + args.heapsize]) + else: + # Use a remote target. + if not args.mpy_cross_flags: + args.mpy_cross_flags = "-march=armv7m" if len(args.files) == 0: - tests_skip = ("benchrun.py",) - if M <= 25: - # These scripts are too big to be compiled by the target - tests_skip += ("bm_chaos.py", "bm_hexiom.py", "misc_raytrace.py") tests = sorted( BENCH_SCRIPT_DIR + test_file for test_file in os.listdir(BENCH_SCRIPT_DIR) - if test_file.endswith(".py") and test_file not in tests_skip + if test_file.endswith(".py") and test_file != "benchrun.py" ) else: tests = sorted(args.files) print("N={} M={} n_average={}".format(N, M, n_average)) - target_had_error = run_benchmarks(args, target, N, M, n_average, tests) + os.makedirs(args.result_dir, exist_ok=True) + test_results = run_benchmarks(args, target, N, M, n_average, tests) + res = create_test_report(args, test_results) - if isinstance(target, pyboard.Pyboard): + if hasattr(target, "exit_raw_repl"): target.exit_raw_repl() target.close() - if target_had_error: + if not res: sys.exit(1) diff --git a/tests/run-tests.py b/tests/run-tests.py index cb839ae23dc..35eb2eb3aa2 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -6,7 +6,6 @@ import sysconfig import platform import argparse -import inspect import json import re from glob import glob @@ -15,17 +14,29 @@ import threading import tempfile -# Maximum time to run a PC-based test, in seconds. -TEST_TIMEOUT = 30 - -# See stackoverflow.com/questions/2632199: __file__ nor sys.argv[0] -# are guaranteed to always work, this one should though. -BASEPATH = os.path.dirname(os.path.abspath(inspect.getsourcefile(lambda: None))) - - -def base_path(*p): - return os.path.abspath(os.path.join(BASEPATH, *p)).replace("\\", "/") - +from test_utils import ( + base_path, + pyboard, + TEST_TIMEOUT, + TEST_MAXIMUM_RAW_REPL_FAILURES, + MPYCROSS, + test_instance_description, + test_instance_epilog, + test_directory_description, + rm_f, + normalize_newlines, + set_injected_prologue, + get_results_filename, + convert_device_shortcut_to_real_device, + get_test_instance, + create_test_report, + FLAKY_REASON_PREFIX, +) + +RV32_ARCH_FLAGS = { + "zba": 1 << 0, + "zcmp": 1 << 1, +} # Tests require at least CPython 3.3. If your default python3 executable # is of lower version, you can point MICROPY_CPYTHON3 environment var @@ -35,84 +46,88 @@ def base_path(*p): MICROPYTHON = os.getenv( "MICROPY_MICROPYTHON", base_path("../ports/windows/build-standard/micropython.exe") ) - # mpy-cross is only needed if --via-mpy command-line arg is passed - MPYCROSS = os.getenv("MICROPY_MPYCROSS", base_path("../mpy-cross/build/mpy-cross.exe")) else: CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3") MICROPYTHON = os.getenv( "MICROPY_MICROPYTHON", base_path("../ports/unix/build-standard/micropython") ) - # mpy-cross is only needed if --via-mpy command-line arg is passed - MPYCROSS = os.getenv("MICROPY_MPYCROSS", base_path("../mpy-cross/build/mpy-cross")) # Use CPython options to not save .pyc files, to only access the core standard library # (not site packages which may clash with u-module names), and improve start up time. CPYTHON3_CMD = [CPYTHON3, "-BS"] -# File with the test results. -RESULTS_FILE = "_results.json" - # For diff'ing test output DIFF = os.getenv("MICROPY_DIFF", "diff -u") # Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale os.environ["PYTHONIOENCODING"] = "utf-8" -# Code to allow a target MicroPython to import an .mpy from RAM -# Note: the module is named `__injected_test` but it needs to have `__name__` set to -# `__main__` so that the test sees itself as the main module, eg so unittest works. -injected_import_hook_code = """\ -import sys, os, io, vfs -class __File(io.IOBase): - def __init__(self): - module = sys.modules['__injected_test'] - module.__name__ = '__main__' - sys.modules['__main__'] = module - self.off = 0 - def ioctl(self, request, arg): - if request == 4: # MP_STREAM_CLOSE - return 0 - return -1 - def readinto(self, buf): - buf[:] = memoryview(__buf)[self.off:self.off + len(buf)] - self.off += len(buf) - return len(buf) -class __FS: - def mount(self, readonly, mkfs): - pass - def umount(self): - pass - def chdir(self, path): - pass - def getcwd(self): - return "" - def stat(self, path): - if path == '__injected_test.mpy': - return tuple(0 for _ in range(10)) - else: - raise OSError(-2) # ENOENT - def open(self, path, mode): - return __File() -vfs.mount(__FS(), '/__vfstest') -os.chdir('/__vfstest') -__import__('__injected_test') -""" - # Platforms associated with the unix port, values of `sys.platform`. PC_PLATFORMS = ("darwin", "linux", "win32") +# Mapping from `sys.platform` to the port name, for special cases. +# See `platform_to_port()` function. +platform_to_port_map = {"pyboard": "stm32", "WiPy": "cc3200"} +platform_to_port_map.update({p: "unix" for p in PC_PLATFORMS}) + +# Tests to skip for values of the `--via-mpy` argument. +via_mpy_tests_to_skip = { + # Skip the following when mpy is enabled. + True: ( + # These print out the filename and that's expected to match the .py name. + "import/import_file.py", + "io/argv.py", + "misc/sys_settrace_features.py", + "misc/sys_settrace_generator.py", + "misc/sys_settrace_loop.py", + ), +} + +# Tests to skip for specific emitters. +emitter_tests_to_skip = { + # Some tests are known to fail with native emitter. + # Remove them from the below when they work. + "native": ( + # These require raise_varargs. + "basics/try_finally_return2.py", + "basics/try_reraise.py", + "basics/try_reraise2.py", + # CIRCUITPY-CHANGE: our traceback deviation in this test uses a bare + # raise, which is raise_varargs with no argument. + "basics/gen_yield_from_close.py", + # These require checking for unbound local. + "basics/annotate_var.py", + "basics/del_deref.py", + "basics/del_local.py", + "basics/scope_implicit.py", + "basics/unboundlocal.py", + # These require "raise from". + "basics/exception_chain.py", + # These require stack-allocated slice optimisation. + "micropython/heapalloc_slice.py", + # These require implicitly running the scheduler between bytecodes. + "micropython/schedule.py", + # These require sys.exc_info(). + "misc/sys_exc_info.py", + # These require sys.settrace(). + "misc/sys_settrace_cov.py", + "misc/sys_settrace_features.py", + "misc/sys_settrace_generator.py", + "misc/sys_settrace_loop.py", + # These are bytecode-specific tests. + "stress/bytecode_limit.py", + ), +} + # Tests to skip on specific targets. # These are tests that are difficult to detect that they should not be run on the given target. platform_tests_to_skip = { "esp8266": ( - "micropython/viper_args.py", # too large - "micropython/viper_binop_arith.py", # too large - "misc/rge_sm.py", # too large + "stress/list_sort.py", # watchdog kicks in because it takes too long ), "minimal": ( "basics/class_inplace_op.py", # all special methods not supported "basics/subclass_native_init.py", # native subclassing corner cases not support - "misc/rge_sm.py", # too large "micropython/opt_level.py", # don't assume line numbers are stored ), "nrf": ( @@ -140,17 +155,12 @@ def open(self, path, mode): "thread/thread_lock3.py", "thread/thread_shared2.py", ), - "qemu": ( - # Skip tests that require Cortex-M4. - "inlineasm/thumb/asmfpaddsub.py", - "inlineasm/thumb/asmfpcmp.py", - "inlineasm/thumb/asmfpldrstr.py", - "inlineasm/thumb/asmfpmuldiv.py", - "inlineasm/thumb/asmfpsqrt.py", - ), "webassembly": ( "basics/string_format_modulo.py", # can't print nulls to stdout "basics/string_strip.py", # can't print nulls to stdout + "basics/weakref_callback_exception.py", # has different exception printing output + "basics/weakref_ref_collect.py", # requires custom test due to GC behaviour + "basics/weakref_finalize_collect.py", # requires custom test due to GC behaviour "extmod/asyncio_basic2.py", "extmod/asyncio_cancel_self.py", "extmod/asyncio_current_task.py", @@ -162,9 +172,13 @@ def open(self, path, mode): "extmod/asyncio_new_event_loop.py", "extmod/asyncio_threadsafeflag.py", "extmod/asyncio_wait_for_fwd.py", + "extmod/asyncio_event_queue.py", + "extmod/asyncio_iterator_event.py", + "extmod/asyncio_wait_for_linked_task.py", "extmod/binascii_a2b_base64.py", "extmod/deflate_compress_memory_error.py", # tries to allocate unlimited memory "extmod/re_stack_overflow.py", + "extmod/re_stack_overflow2.py", "extmod/time_res.py", "extmod/vfs_posix.py", "extmod/vfs_posix_enoent.py", @@ -184,10 +198,131 @@ def open(self, path, mode): ), } +# Tests to skip when MICROPY_ERROR_REPORTING is at a certain level. +error_reporting_tests_to_skip = { + # Skip at level MICROPY_ERROR_REPORTING_TERSE. + "terse": ( + "cmdline/repl_paste.py", + # This test needs updates before being removed from this list. + "extmod/vfs_blockdev_invalid.py", + "micropython/heapalloc_exc_compressed.py", + "micropython/heapalloc_exc_compressed_emg_exc.py", + "micropython/opt_level_lineno.py", + "misc/print_exception.py", + "misc/sys_settrace_features.py", + ), +} +# Skip at level MICROPY_ERROR_REPORTING_NONE. +error_reporting_tests_to_skip["none"] = error_reporting_tests_to_skip["terse"] + ( + "extmod/asyncio_gather_notimpl.py", +) + +# Tests with known intermittent failures. These tests still run, but failures +# are reclassified as "ignored" instead of "fail" so they don't affect the CI +# exit code. Paths are relative to the tests/ directory (must match test_file +# format used by run_one_test, which normalises backslashes to forward slashes). +# +# Values are (reason, platforms) tuples where platforms is None (all platforms) +# or a tuple of sys.platform strings to restrict ignoring to those platforms. +flaky_tests_to_ignore = { + "thread/thread_gc1.py": ("GC race condition", None), + "thread/stress_schedule.py": ("intermittent crash under QEMU", None), + "thread/stress_recurse.py": ("stack overflow under emulation", None), + "thread/stress_heap.py": ("flaky on macOS", ("darwin",)), + "cmdline/repl_lock.py": ("REPL timing under QEMU", None), + "cmdline/repl_cont.py": ("REPL escaping on macOS", ("darwin",)), + "extmod/time_time_ns.py": ("CI runner clock precision", None), +} -def rm_f(fname): - if os.path.exists(fname): - os.remove(fname) +# These tests don't test float explicitly but rather use it to perform the test. +tests_requiring_float = ( + "extmod/asyncio_basic.py", + "extmod/asyncio_basic2.py", + "extmod/asyncio_cancel_task.py", + "extmod/asyncio_event.py", + "extmod/asyncio_fair.py", + "extmod/asyncio_gather.py", + "extmod/asyncio_gather_notimpl.py", + "extmod/asyncio_get_event_loop.py", + "extmod/asyncio_iterator_event.py", + "extmod/asyncio_lock.py", + "extmod/asyncio_task_done.py", + "extmod/asyncio_wait_for.py", + "extmod/asyncio_wait_for_fwd.py", + "extmod/asyncio_wait_for_linked_task.py", + "extmod/asyncio_wait_task.py", + "extmod/json_dumps_float.py", + "extmod/json_loads_float.py", + "extmod/random_extra_float.py", + "extmod/select_poll_eintr.py", + "extmod/tls_threads.py", + "extmod/uctypes_le_float.py", + "extmod/uctypes_native_float.py", + "extmod/uctypes_sizeof_float.py", + "extmod/vfs_rom.py", + "micropython/const_float.py", + "misc/rge_sm.py", + "ports/unix/ffi_float.py", + "ports/unix/ffi_float2.py", +) + +# These tests don't test slice explicitly but rather use it to perform the test. +tests_requiring_slice = ( + "basics/builtin_range.py", + "basics/bytearray1.py", + "basics/class_super.py", + "basics/containment.py", + "basics/errno1.py", + "basics/fun_str.py", + "basics/generator1.py", + "basics/globals_del.py", + "basics/memoryview1.py", + "basics/memoryview_gc.py", + "basics/object1.py", + "basics/python34.py", + "basics/struct_endian.py", + "extmod/btree1.py", + "extmod/deflate_decompress.py", + "extmod/framebuf16.py", + "extmod/framebuf4.py", + "extmod/machine1.py", + "extmod/time_mktime.py", + "extmod/time_res.py", + "extmod/tls_sslcontext_ciphers.py", + "extmod/vfs_blockdev_invalid2.py", + "extmod/vfs_fat_fileio1.py", + "extmod/vfs_fat_finaliser.py", + "extmod/vfs_fat_more.py", + "extmod/vfs_fat_ramdisk.py", + "extmod/vfs_fat_ramdisklarge.py", + "extmod/vfs_lfs.py", + "extmod/vfs_rom.py", + "float/string_format_modulo.py", + "micropython/builtin_execfile.py", + "micropython/extreme_exc.py", + "micropython/heapalloc_fail_bytearray.py", + "micropython/heapalloc_fail_list.py", + "micropython/heapalloc_fail_memoryview.py", + "micropython/import_mpy_invalid.py", + "micropython/import_mpy_native.py", + "micropython/import_mpy_native_gc.py", + "micropython/ringio_big.py", + "misc/non_compliant.py", + "misc/rge_sm.py", +) + +# Tests that require `import target_wiring` to work. +tests_requiring_target_wiring = ( + "extmod/machine_spi_rate.py", + "extmod/machine_uart_irq_txidle.py", + "extmod/machine_uart_tx.py", + "extmod_hardware/machine_can_timings.py", + "extmod_hardware/machine_encoder.py", + "extmod_hardware/machine_pwm.py", + "extmod_hardware/machine_uart_irq_break.py", + "extmod_hardware/machine_uart_irq_rx.py", + "extmod_hardware/machine_uart_irq_rxidle.py", +) # unescape wanted regex chars and escape unwanted ones @@ -210,39 +345,25 @@ def convert_regex_escapes(line): return bytes("".join(cs), "utf8") -def get_test_instance(test_instance, baudrate, user, password): - if test_instance.startswith("port:"): - _, port = test_instance.split(":", 1) - elif test_instance == "unix": - return None - elif test_instance == "webassembly": - return PyboardNodeRunner() - elif test_instance.startswith("a") and test_instance[1:].isdigit(): - port = "/dev/ttyACM" + test_instance[1:] - elif test_instance.startswith("u") and test_instance[1:].isdigit(): - port = "/dev/ttyUSB" + test_instance[1:] - elif test_instance.startswith("c") and test_instance[1:].isdigit(): - port = "COM" + test_instance[1:] - else: - # Assume it's a device path. - port = test_instance +def platform_to_port(platform): + return platform_to_port_map.get(platform, platform) - global pyboard - sys.path.append(base_path("../tools")) - import pyboard - pyb = pyboard.Pyboard(port, baudrate, user, password) - pyboard.Pyboard.run_script_on_remote_target = run_script_on_remote_target - pyb.enter_raw_repl() - return pyb +def detect_inline_asm_arch(pyb, args): + output = run_feature_check(pyb, args, "inlineasm.py").decode().strip() + arch, *features = output.split(",") + return arch, features -def detect_inline_asm_arch(pyb, args): - for arch in ("rv32", "thumb", "xtensa"): - output = run_feature_check(pyb, args, "inlineasm_{}.py".format(arch)) - if output.strip() == arch.encode(): - return arch - return None +def map_rv32_arch_flags(flags): + mapped_flags = [] + for extension, bit in RV32_ARCH_FLAGS.items(): + if flags & bit: + mapped_flags.append(extension) + flags &= ~bit + if flags: + raise Exception("Unexpected flag bits set in value {}".format(flags)) + return mapped_flags def detect_test_platform(pyb, args): @@ -250,121 +371,128 @@ def detect_test_platform(pyb, args): output = run_feature_check(pyb, args, "target_info.py") if output.endswith(b"CRASH"): raise ValueError("cannot detect platform: {}".format(output)) - platform, arch = str(output, "ascii").strip().split() + # CIRCUITPY-CHANGE: sys.platform is the first field and can contain spaces ("Atmel SAMD21"). + platform, arch, arch_flags, build, thread, float_prec, unicode, error_reporting = ( + str(output, "ascii").strip().rsplit(None, 7) + ) if arch == "None": arch = None - inlineasm_arch = detect_inline_asm_arch(pyb, args) + inlineasm_arch, inlineasm_features = detect_inline_asm_arch(pyb, args) + if thread == "None": + thread = None + float_prec = int(float_prec) + unicode = unicode == "True" + if arch == "rv32imc": + arch_flags = map_rv32_arch_flags(int(arch_flags)) + else: + arch_flags = None args.platform = platform args.arch = arch + args.arch_flags = arch_flags if arch and not args.mpy_cross_flags: args.mpy_cross_flags = "-march=" + arch + if arch_flags: + args.mpy_cross_flags += " -march-flags=" + ",".join(arch_flags) args.inlineasm_arch = inlineasm_arch - + args.inlineasm_features = inlineasm_features + args.build = build + args.thread = thread + args.float_prec = float_prec + args.unicode = unicode + args.error_reporting = error_reporting + + # Print the detected information about the target. print("platform={}".format(platform), end="") if arch: print(" arch={}".format(arch), end="") + if arch_flags: + print(" arch_flags={}".format(",".join(arch_flags)), end="") if inlineasm_arch: print(" inlineasm={}".format(inlineasm_arch), end="") - print() - - -def prepare_script_for_target(args, *, script_filename=None, script_text=None, force_plain=False): - if force_plain or (not args.via_mpy and args.emit == "bytecode"): - if script_filename is not None: - with open(script_filename, "rb") as f: - script_text = f.read() - elif args.via_mpy: - tempname = tempfile.mktemp(dir="") - mpy_filename = tempname + ".mpy" - - if script_filename is None: - script_filename = tempname + ".py" - cleanup_script_filename = True - with open(script_filename, "wb") as f: - f.write(script_text) - else: - cleanup_script_filename = False - - try: - subprocess.check_output( - [MPYCROSS] - + args.mpy_cross_flags.split() - + ["-o", mpy_filename, "-X", "emit=" + args.emit, script_filename], - stderr=subprocess.STDOUT, - ) - except subprocess.CalledProcessError as er: - return True, b"mpy-cross crash\n" + er.output - - with open(mpy_filename, "rb") as f: - script_text = b"__buf=" + bytes(repr(f.read()), "ascii") + b"\n" - - rm_f(mpy_filename) - if cleanup_script_filename: - rm_f(script_filename) - - script_text += bytes(injected_import_hook_code, "ascii") + if thread: + print(" thread={}".format(thread), end="") + if float_prec: + print(" float={}-bit".format(float_prec), end="") + if unicode: + print(" unicode", end="") + + +def detect_target_wiring_script(pyb, args): + tw_data = b"" + tw_source = None + if args.target_wiring: + # A target_wiring path is explicitly provided, so use that. + tw_source = args.target_wiring + with open(tw_source, "rb") as f: + tw_data = f.read() + elif hasattr(pyb, "exec_raw") and pyb.exec_raw("import target_wiring") == (b"", b""): + # The board already has a target_wiring module available, so use that. + tw_source = "on-device" else: - print("error: using emit={} must go via .mpy".format(args.emit)) - sys.exit(1) - - return False, script_text - - -def run_script_on_remote_target(pyb, args, test_file, is_special): - had_crash, script = prepare_script_for_target( - args, script_filename=test_file, force_plain=is_special - ) - if had_crash: - return True, script - - try: - had_crash = False - pyb.enter_raw_repl() - output_mupy = pyb.exec_(script) - except pyboard.PyboardError as e: - had_crash = True - if not is_special and e.args[0] == "exception": - output_mupy = e.args[1] + e.args[2] + b"CRASH" - else: - output_mupy = bytes(e.args[0], "ascii") + b"\nCRASH" - return had_crash, output_mupy - - -special_tests = [ + port = platform_to_port(args.platform) + build = args.build + tw_board_exact = None + tw_board_partial = None + tw_port = None + for file in os.listdir("target_wiring"): + file_base = file.removesuffix(".py") + if file_base == build: + # A file matching the target's board/build name. + tw_board_exact = file + elif file_base.endswith("x") and build.startswith(file_base.removesuffix("x")): + # A file with a partial match to the target's board/build name. + tw_board_partial = file + elif file_base == port: + # A file matching the target's port. + tw_port = file + tw_source = tw_board_exact or tw_board_partial or tw_port + if tw_source: + with open("target_wiring/" + tw_source, "rb") as f: + tw_data = f.read() + if tw_source: + print(" target_wiring={}".format(tw_source), end="") + pyb.target_wiring_script = tw_data + + +tests_with_regex_output = [ base_path(file) for file in ( + # CIRCUITPY-CHANGE: removal and additions "micropython/meminfo.py", "basics/bytes_compare3.py", "basics/builtin_help.py", + "basics/weakref_callback_exception.py", "thread/thread_exc2.py", - # CIRCUITPY-CHANGE: removal and additions - # REMOVE "esp32/partition_ota.py", "circuitpython/traceback_test.py", "circuitpython/traceback_test_chained.py", ) ] -def run_micropython(pyb, args, test_file, test_file_abspath, is_special=False): +def run_micropython( + pyb, args, test_file, test_file_abspath, is_special=False, is_feature_check=False +): had_crash = False if pyb is None: # run on PC - if ( - test_file_abspath.startswith((base_path("cmdline/"), base_path("feature_check/"))) - or test_file_abspath in special_tests - ): + if test_file_abspath.startswith((base_path("cmdline/"), base_path("feature_check/"))): # special handling for tests of the unix cmdline program is_special = True if is_special: # check for any cmdline options needed for this test - args = [MICROPYTHON] + cmdlist = [MICROPYTHON] + send_sigint = False with open(test_file, "rb") as f: - line = f.readline() - if line.startswith(b"# cmdline:"): - # subprocess.check_output on Windows only accepts strings, not bytes - args += [str(c, "utf-8") for c in line[10:].strip().split()] + for line in f: + if line.startswith(b"# cmdline:"): + # subprocess.check_output on Windows only accepts strings, not bytes + cmdlist += [str(c, "utf-8") for c in line[10:].strip().split()] + elif line.startswith(b"# sigint:"): + send_sigint = True + elif not line.startswith(b"#"): + break # run the test, possibly with redirected input try: @@ -392,33 +520,86 @@ def get(required=False): return rv def send_get(what): + # Detect hex {\x00} pattern and convert to ctrl-key codes. + ctrl_code = lambda m: bytes([int(m.group(1), 16)]) + what = re.sub(rb"{\\x(\d\d)}", ctrl_code, what) + os.write(master, what) return get() + def send_ctrl_c(): + # Send \x03 without trailing newline and wait for + # the full response (traceback + new prompt). + os.write(master, b"\x03") + return get(True) + with open(test_file, "rb") as f: - # instead of: output_mupy = subprocess.check_output(args, stdin=f) + # instead of: output_mupy = subprocess.check_output(cmdlist, stdin=f) master, slave = pty.openpty() - p = subprocess.Popen( - args, stdin=slave, stdout=slave, stderr=subprocess.STDOUT, bufsize=0 - ) - banner = get(True) - output_mupy = banner + b"".join(send_get(line) for line in f) - send_get(b"\x04") # exit the REPL, so coverage info is saved - # At this point the process might have exited already, but trying to - # kill it 'again' normally doesn't result in exceptions as Python and/or - # the OS seem to try to handle this nicely. When running Linux on WSL - # though, the situation differs and calling Popen.kill after the process - # terminated results in a ProcessLookupError. Just catch that one here - # since we just want the process to be gone and that's the case. try: - p.kill() - except ProcessLookupError: - pass - os.close(master) - os.close(slave) + preexec_fn = None + use_sigint_kill = False + # Tests with "# sigint:" need Ctrl-C (\x03) to + # generate SIGINT. MicroPython restores original + # terminal mode (ISIG on) during code execution, + # so on Linux we set up the PTY as a controlling + # terminal for proper signal delivery. On macOS, + # setsid/TIOCSCTTY breaks PTY I/O, so we fall + # back to os.kill(). + if send_sigint: + if sys.platform == "darwin": + use_sigint_kill = True + else: + import fcntl + import termios + + def preexec_fn(): + os.setsid() + fcntl.ioctl(0, termios.TIOCSCTTY, 0) + os.tcsetpgrp(0, os.getpid()) + + p = subprocess.Popen( + cmdlist, + stdin=slave, + stdout=slave, + stderr=subprocess.STDOUT, + bufsize=0, + preexec_fn=preexec_fn, + ) + banner = get(True) + if send_sigint: + import signal + + parts = [] + for line in f: + if b"{\\x03}" in line: + if use_sigint_kill: + os.kill(p.pid, signal.SIGINT) + parts.append(get(True)) + else: + parts.append(send_ctrl_c()) + else: + parts.append(send_get(line)) + output_mupy = banner + b"".join(parts) + else: + output_mupy = banner + b"".join(send_get(line) for line in f) + send_get(b"\x04") # exit the REPL, so coverage info is saved + # At this point the process might have exited already, but trying to + # kill it 'again' normally doesn't result in exceptions as Python and/or + # the OS seem to try to handle this nicely. When running Linux on WSL + # though, the situation differs and calling Popen.kill after the process + # terminated results in a ProcessLookupError. Just catch that one here + # since we just want the process to be gone and that's the case. + try: + p.kill() + except ProcessLookupError: + pass + finally: + os.close(master) + os.close(slave) else: output_mupy = subprocess.check_output( - args + [test_file], stderr=subprocess.STDOUT + cmdlist + [test_file], stderr=subprocess.STDOUT ) except subprocess.CalledProcessError: return b"CRASH" @@ -466,24 +647,34 @@ def send_get(what): else: # run via pyboard interface + requires_target_wiring = test_file.endswith(tests_requiring_target_wiring) had_crash, output_mupy = pyb.run_script_on_remote_target( - args, test_file_abspath, is_special + args, test_file_abspath, is_special, requires_target_wiring ) # canonical form for all ports/platforms is to use \n for end-of-line - output_mupy = output_mupy.replace(b"\r\n", b"\n") + output_mupy = normalize_newlines(output_mupy) + + # for feature-check tests, return the output as-is + if is_feature_check: + return output_mupy # don't try to convert the output if we should skip this test - if had_crash or output_mupy in (b"SKIP\n", b"CRASH"): + if had_crash or output_mupy in (b"SKIP\n", b"SKIP-TOO-LARGE\n", b"CRASH"): return output_mupy # skipped special tests will output "SKIP" surrounded by other interpreter debug output if is_special and not had_crash and b"\nSKIP\n" in output_mupy: return b"SKIP\n" - if is_special or test_file_abspath in special_tests: + if is_special or test_file_abspath in tests_with_regex_output: # convert parts of the output that are not stable across runs - with open(test_file + ".exp", "rb") as f: + # Prefer emitter-specific expected output. + exp_file = test_file + "." + args.emit + ".exp" + if not os.path.isfile(exp_file): + # Fall back to generic expected output. + exp_file = test_file + ".exp" + with open(exp_file, "rb") as f: lines_exp = [] for line in f.readlines(): if line == b"########\n": @@ -530,7 +721,9 @@ def run_feature_check(pyb, args, test_file): # REPL feature tests will not run via pyboard because they require prompt interactivity return b"" test_file_path = base_path("feature_check", test_file) - return run_micropython(pyb, args, test_file_path, test_file_path, is_special=True) + return run_micropython( + pyb, args, test_file_path, test_file_path, is_special=True, is_feature_check=True + ) class TestError(Exception): @@ -557,76 +750,28 @@ def value(self): return self._value -class PyboardNodeRunner: - def __init__(self): - mjs = os.getenv("MICROPY_MICROPYTHON_MJS") - if mjs is None: - mjs = base_path("../ports/webassembly/build-standard/micropython.mjs") - else: - mjs = os.path.abspath(mjs) - self.micropython_mjs = mjs - - def close(self): - pass - - def run_script_on_remote_target(self, args, test_file, is_special): - cwd = os.path.dirname(test_file) - - # Create system command list. - cmdlist = ["node"] - if test_file.endswith(".py"): - # Run a Python script indirectly via "node micropython.mjs ". - cmdlist.append(self.micropython_mjs) - if args.heapsize is not None: - cmdlist.extend(["-X", "heapsize=" + args.heapsize]) - cmdlist.append(test_file) - else: - # Run a js/mjs script directly with Node, passing in the path to micropython.mjs. - cmdlist.append(test_file) - cmdlist.append(self.micropython_mjs) - - # Run the script. - try: - had_crash = False - output_mupy = subprocess.check_output( - cmdlist, stderr=subprocess.STDOUT, timeout=TEST_TIMEOUT, cwd=cwd - ) - except subprocess.CalledProcessError as er: - had_crash = True - output_mupy = er.output + b"CRASH" - except subprocess.TimeoutExpired as er: - had_crash = True - output_mupy = (er.output or b"") + b"TIMEOUT" - - # Return the results. - return had_crash, output_mupy - - def run_tests(pyb, tests, args, result_dir, num_threads=1): - test_count = ThreadSafeCounter() testcase_count = ThreadSafeCounter() - passed_count = ThreadSafeCounter() - failed_tests = ThreadSafeCounter([]) - skipped_tests = ThreadSafeCounter([]) + raw_repl_failure_count = ThreadSafeCounter() + test_results = ThreadSafeCounter([]) skip_tests = set() skip_native = False skip_int_big = False + skip_int_64 = False skip_bytearray = False skip_set_type = False skip_slice = False skip_async = False skip_const = False skip_revops = False - skip_io_module = False skip_fstring = False + skip_tstring = False skip_endian = False skip_inlineasm = False has_complex = True has_coverage = False - upy_float_precision = 32 - if True: # Even if we run completely different tests in a different directory, # we need to access feature_checks from the same directory as the @@ -642,6 +787,11 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): if output != b"1000000000000000000000000000000000000000000000\n": skip_int_big = True + # Check if 'long long' precision integers are supported, even if arbitrary precision is not + output = run_feature_check(pyb, args, "int_64.py") + if output != b"4611686018427387904\n": + skip_int_64 = True + # Check if bytearray is supported, and skip such tests if it's not output = run_feature_check(pyb, args, "bytearray.py") if output != b"bytearray\n": @@ -672,31 +822,26 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): if output == b"TypeError\n": skip_revops = True - # Check if io module exists, and skip such tests if it doesn't - output = run_feature_check(pyb, args, "io_module.py") - if output != b"io\n": - skip_io_module = True - # Check if fstring feature is enabled, and skip such tests if it doesn't output = run_feature_check(pyb, args, "fstring.py") if output != b"a=1\n": skip_fstring = True + # Check if tstring feature is enabled, and skip such tests if it doesn't + output = run_feature_check(pyb, args, "tstring.py") + if output != b"tstring\n": + skip_tstring = True + if args.inlineasm_arch == "thumb": - # Check if @micropython.asm_thumb supports Thumb2 instructions, and skip such tests if it doesn't - output = run_feature_check(pyb, args, "inlineasm_thumb2.py") - if output != b"thumb2\n": - skip_tests.add("inlineasm/thumb/asmbcc.py") - skip_tests.add("inlineasm/thumb/asmbitops.py") - skip_tests.add("inlineasm/thumb/asmconst.py") - skip_tests.add("inlineasm/thumb/asmdiv.py") - skip_tests.add("inlineasm/thumb/asmfpaddsub.py") - skip_tests.add("inlineasm/thumb/asmfpcmp.py") - skip_tests.add("inlineasm/thumb/asmfpldrstr.py") - skip_tests.add("inlineasm/thumb/asmfpmuldiv.py") - skip_tests.add("inlineasm/thumb/asmfpsqrt.py") - skip_tests.add("inlineasm/thumb/asmit.py") - skip_tests.add("inlineasm/thumb/asmspecialregs.py") + for feature in ("thumb2", "vfp"): + if feature not in args.inlineasm_features: + for test in glob(f"inlineasm/thumb/asm_{feature}_*.py"): + skip_tests.add(test) + + if args.inlineasm_arch == "rv32": + for extension in RV32_ARCH_FLAGS: + if extension not in args.inlineasm_features: + skip_tests.add(f"inlineasm/rv32/asm_ext_{extension}.py") # Check if emacs repl is supported, and skip such tests if it's not t = run_feature_check(pyb, args, "repl_emacs_check.py") @@ -709,11 +854,6 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_tests.add("cmdline/repl_words_move.py") upy_byteorder = run_feature_check(pyb, args, "byteorder.py") - upy_float_precision = run_feature_check(pyb, args, "float.py") - try: - upy_float_precision = int(upy_float_precision) - except ValueError: - upy_float_precision = 0 has_complex = run_feature_check(pyb, args, "complex.py") == b"complex\n" has_coverage = run_feature_check(pyb, args, "coverage.py") == b"coverage\n" cpy_byteorder = subprocess.check_output( @@ -721,61 +861,48 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): ) skip_endian = upy_byteorder != cpy_byteorder - skip_inlineasm = args.inlineasm_arch is None - - # These tests don't test slice explicitly but rather use it to perform the test - misc_slice_tests = ( - "builtin_range", - "bytearray1", - "class_super", - "containment", - "errno1", - "fun_str", - "generator1", - "globals_del", - "memoryview1", - "memoryview_gc", - "object1", - "python34", - "string_format_modulo", - "struct_endian", - ) + skip_inlineasm = not args.inlineasm_arch # Some tests shouldn't be run on GitHub Actions if os.getenv("GITHUB_ACTIONS") == "true": - skip_tests.add("thread/stress_schedule.py") # has reliability issues - if os.getenv("RUNNER_OS") == "Windows" and os.getenv("CI_BUILD_CONFIGURATION") == "Debug": # fails with stack overflow on Debug builds skip_tests.add("misc/sys_settrace_features.py") - if upy_float_precision == 0: - skip_tests.add("extmod/uctypes_le_float.py") - skip_tests.add("extmod/uctypes_native_float.py") - skip_tests.add("extmod/uctypes_sizeof_float.py") - skip_tests.add("extmod/json_dumps_float.py") - skip_tests.add("extmod/json_loads_float.py") - skip_tests.add("extmod/random_extra_float.py") - skip_tests.add("misc/rge_sm.py") - if upy_float_precision < 32: + if args.float_prec == 0: + skip_tests.update(tests_requiring_float) + if args.float_prec < 32: skip_tests.add( "float/float2int_intbig.py" ) # requires fp32, there's float2int_fp30_intbig.py instead skip_tests.add( - "float/string_format.py" - ) # requires fp32, there's string_format_fp30.py instead + "float/float_struct_e.py" + ) # requires fp32, there's float_struct_e_fp30.py instead skip_tests.add("float/bytes_construct.py") # requires fp32 skip_tests.add("float/bytearray_construct.py") # requires fp32 skip_tests.add("float/float_format_ints_power10.py") # requires fp32 - if upy_float_precision < 64: + if args.float_prec < 64: skip_tests.add("float/float_divmod.py") # tested by float/float_divmod_relaxed.py instead skip_tests.add("float/float2int_doubleprec_intbig.py") + skip_tests.add("float/float_struct_e_doubleprec.py") skip_tests.add("float/float_format_ints_doubleprec.py") skip_tests.add("float/float_parse_doubleprec.py") + if not args.unicode: + if args.via_mpy: + skip_tests.add("basics/string_escape.py") # stores a utf-8 character in the mpy file + skip_tests.add("extmod/json_loads.py") # tests loading a utf-8 character + + # CIRCUITPY-CHANGE: asserts upstream's escaped Unicode repr, see py/objstrunicode.c + skip_tests.add("basics/string_tstring_basic1.py") + + if skip_slice: + skip_tests.update(tests_requiring_slice) + if not has_complex: skip_tests.add("float/complex1.py") skip_tests.add("float/complex1_intbig.py") + skip_tests.add("float/complex1_micropython.py") skip_tests.add("float/complex_reverse_op.py") skip_tests.add("float/complex_special_methods.py") skip_tests.add("float/int_big_float.py") @@ -788,8 +915,8 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_tests.add("cmdline/repl_sys_ps1_ps2.py") skip_tests.add("extmod/ssl_poll.py") - # Skip thread mutation tests on targets that don't have the GIL. - if args.platform in PC_PLATFORMS + ("rp2",): + # Skip thread mutation tests on targets that have unsafe threading behaviour. + if args.thread == "unsafe": for t in tests: if t.startswith("thread/mutate_"): skip_tests.add(t) @@ -798,10 +925,22 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): if args.platform not in PC_PLATFORMS: skip_tests.add("basics/exception_chain.py") # warning is not printed skip_tests.add("micropython/meminfo.py") # output is very different to PC output + skip_tests.add("unicode/file1.py") # requires local file access + skip_tests.add("unicode/file2.py") # requires local file access + skip_tests.add("unicode/file_invalid.py") # requires local file access + + # Skip certain tests when going via a .mpy file. + skip_tests.update(via_mpy_tests_to_skip.get(args.via_mpy, ())) + + # Skip emitter-specific tests. + skip_tests.update(emitter_tests_to_skip.get(args.emit, ())) # Skip platform-specific tests. skip_tests.update(platform_tests_to_skip.get(args.platform, ())) + # Skip error-reporting-specific tests. + skip_tests.update(error_reporting_tests_to_skip.get(args.error_reporting, ())) + # Some tests are known to fail on 64-bit machines if pyb is None and platform.architecture()[0] == "64bit": pass @@ -812,52 +951,23 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): # Works but CPython uses '\' path separator skip_tests.add("import/import_file.py") - # Some tests are known to fail with native emitter - # Remove them from the below when they work - if args.emit == "native": - skip_tests.add("basics/gen_yield_from_close.py") # require raise_varargs - skip_tests.update( - {"basics/%s.py" % t for t in "try_reraise try_reraise2".split()} - ) # require raise_varargs - skip_tests.add("basics/annotate_var.py") # requires checking for unbound local - skip_tests.add("basics/del_deref.py") # requires checking for unbound local - skip_tests.add("basics/del_local.py") # requires checking for unbound local - skip_tests.add("basics/exception_chain.py") # raise from is not supported - skip_tests.add("basics/scope_implicit.py") # requires checking for unbound local - skip_tests.add("basics/sys_tracebacklimit.py") # requires traceback info - skip_tests.add("basics/try_finally_return2.py") # requires raise_varargs - skip_tests.add("basics/unboundlocal.py") # requires checking for unbound local - skip_tests.add("misc/features.py") # requires raise_varargs - # CIRCUITPY-CHANGE - skip_tests.update( - ( - "basics/chained_exception.py", - "circuitpython/traceback_test.py", - "circuitpython/traceback_test_chained.py", - ) - ) # because native doesn't have proper traceback info - skip_tests.add( - "misc/print_exception.py" - ) # because native doesn't have proper traceback info - skip_tests.add("misc/sys_exc_info.py") # sys.exc_info() is not supported for native - skip_tests.add("misc/sys_settrace_features.py") # sys.settrace() not supported - skip_tests.add("misc/sys_settrace_generator.py") # sys.settrace() not supported - skip_tests.add("misc/sys_settrace_loop.py") # sys.settrace() not supported - skip_tests.add( - "micropython/emg_exc.py" - ) # because native doesn't have proper traceback info - skip_tests.add( - "micropython/heapalloc_traceback.py" - ) # because native doesn't have proper traceback info - skip_tests.add( - "micropython/opt_level_lineno.py" - ) # native doesn't have proper traceback info - skip_tests.add("micropython/schedule.py") # native code doesn't check pending events - skip_tests.add("stress/bytecode_limit.py") # bytecode specific test + skip_tests = [os.path.realpath(base_path(skip_test)) for skip_test in skip_tests] def run_one_test(test_file): - test_file = test_file.replace("\\", "/") test_file_abspath = os.path.abspath(test_file).replace("\\", "/") + # If test_file is one of our own tests always make it relative to our tests/ dir and + # otherwise use the absolute path, regardless of actual path passed, + # such that display and result output is always the same. + try: + test_file_relpath = os.path.relpath(test_file, start=base_path()) + if not test_file_relpath.startswith(".."): + test_file = test_file_relpath + else: + test_file = test_file_abspath + except ValueError: + # Path on different drive on Windows. + test_file = test_file_abspath + test_file = test_file.replace("\\", "/") if args.filters: # Default verdict is the opposite of the first action @@ -870,39 +980,45 @@ def run_one_test(test_file): test_basename = test_file.replace("..", "_").replace("./", "").replace("/", "_") test_name = os.path.splitext(os.path.basename(test_file))[0] - is_native = ( - test_name.startswith("native_") - or test_name.startswith("viper_") - or args.emit == "native" - ) + is_native = test_name.startswith("native_") or test_name.startswith("viper_") is_endian = test_name.endswith("_endian") - is_int_big = test_name.startswith("int_big") or test_name.endswith("_intbig") + is_int_big = ( + test_name.startswith("int_big") + or test_name.endswith("_intbig") + or test_name.startswith("ffi_int") # these tests contain large integer literals + ) + is_int_64 = test_name.startswith("int_64") or test_name.endswith("_int64") is_bytearray = test_name.startswith("bytearray") or test_name.endswith("_bytearray") is_set_type = test_name.startswith(("set_", "frozenset")) or test_name.endswith("_set") - is_slice = test_name.find("slice") != -1 or test_name in misc_slice_tests - is_async = test_name.startswith(("async_", "asyncio_")) + is_slice = test_name.find("slice") != -1 + is_async = test_name.startswith(("async_", "asyncio_")) or test_name.endswith("_async") is_const = test_name.startswith("const") - is_io_module = test_name.startswith("io_") - is_fstring = test_name.startswith("string_fstring") + is_fstring = test_name.startswith("string_fstring") or test_name.endswith("_fstring") + is_tstring = test_name.startswith("string_tstring") or test_name.endswith("_tstring") is_inlineasm = test_name.startswith("asm") - skip_it = test_file in skip_tests + skip_it = os.path.realpath(test_file) in skip_tests skip_it |= skip_native and is_native skip_it |= skip_endian and is_endian skip_it |= skip_int_big and is_int_big + skip_it |= skip_int_64 and is_int_64 skip_it |= skip_bytearray and is_bytearray skip_it |= skip_set_type and is_set_type skip_it |= skip_slice and is_slice skip_it |= skip_async and is_async skip_it |= skip_const and is_const skip_it |= skip_revops and "reverse_op" in test_name - skip_it |= skip_io_module and is_io_module skip_it |= skip_fstring and is_fstring + skip_it |= skip_tstring and is_tstring skip_it |= skip_inlineasm and is_inlineasm if skip_it: print("skip ", test_file) - skipped_tests.append(test_name) + test_results.append((test_file, "skip", "")) + return + elif args.dry_run: + print("found", test_file) + test_results.append((test_file, "found", "")) return # Run the test on the MicroPython target. @@ -917,7 +1033,11 @@ def run_one_test(test_file): # start-up code (eg boot.py) when preparing to run the next test. pyb.read_until(1, b"raw REPL; CTRL-B to exit\r\n") print("skip ", test_file) - skipped_tests.append(test_name) + test_results.append((test_file, "skip", "")) + return + elif output_mupy == b"SKIP-TOO-LARGE\n": + print("lrge ", test_file) + test_results.append((test_file, "skip", "too large")) return # Look at the output of the test to see if unittest was used. @@ -954,7 +1074,11 @@ def run_one_test(test_file): # Expected output is result of running unittest. output_expected = None else: - test_file_expected = test_file + ".exp" + # Prefer emitter-specific expected output. + test_file_expected = test_file + "." + args.emit + ".exp" + if not os.path.isfile(test_file_expected): + # Fall back to generic expected output. + test_file_expected = test_file + ".exp" if os.path.isfile(test_file_expected): # Expected output given by a file, so read that in. with open(test_file_expected, "rb") as f: @@ -1012,10 +1136,13 @@ def run_one_test(test_file): # Print test summary, update counters, and save .exp/.out files if needed. if test_passed: print("pass ", test_file, extra_info) - passed_count.increment() + test_results.append((test_file, "pass", "")) rm_f(filename_expected) rm_f(filename_mupy) else: + if output_mupy.startswith(b"could not enter raw repl"): + extra_info = "raw REPL failed" + raw_repl_failure_count.increment() print("FAIL ", test_file, extra_info) if output_expected is not None: with open(filename_expected, "wb") as f: @@ -1024,13 +1151,11 @@ def run_one_test(test_file): rm_f(filename_expected) # in case left over from previous failed run with open(filename_mupy, "wb") as f: f.write(output_mupy) - failed_tests.append((test_name, test_file)) - - test_count.increment() + test_results.append((test_file, "fail", "")) # Print a note if this looks like it might have been a misfired unittest if not uses_unittest and not test_passed: - with open(test_file, "r") as f: + with open(test_file, "r", encoding="utf-8") as f: if any(re.match("^import.+unittest", l) for l in f.readlines()): print( "NOTE: {} may be a unittest that doesn't run unittest.main()".format( @@ -1048,46 +1173,26 @@ def run_one_test(test_file): else: for test in tests: run_one_test(test) + if raw_repl_failure_count.value > TEST_MAXIMUM_RAW_REPL_FAILURES: + print("Too many raw REPL failures, aborting test run") + break except TestError as er: for line in er.args[0]: print(line) - sys.exit(1) + sys.exit(2) - print( - "{} tests performed ({} individual testcases)".format( - test_count.value, testcase_count.value - ) - ) - print("{} tests passed".format(passed_count.value)) - - skipped_tests = sorted(skipped_tests.value) - if len(skipped_tests) > 0: - print("{} tests skipped: {}".format(len(skipped_tests), " ".join(skipped_tests))) - failed_tests = sorted(failed_tests.value) - - # Serialize regex added by append_filter. - def to_json(obj): - if isinstance(obj, re.Pattern): - return obj.pattern - return obj - - with open(os.path.join(result_dir, RESULTS_FILE), "w") as f: - json.dump( - {"args": vars(args), "failed_tests": [test[1] for test in failed_tests]}, - f, - default=to_json, - ) + # Reclassify known-flaky test failures as ignored. + # Safe to mutate: thread pool has joined. + results = test_results.value + for i, r in enumerate(results): + if r[1] == "fail": + reason, platforms = flaky_tests_to_ignore.get(r[0], (None, None)) + if reason is not None: + if platforms is None or sys.platform in platforms: + results[i] = (r[0], "ignored", "{}: {}".format(FLAKY_REASON_PREFIX, reason)) - if len(failed_tests) > 0: - print( - "{} tests failed: {}".format( - len(failed_tests), " ".join(test[0] for test in failed_tests) - ) - ) - return False - - # all tests succeeded - return True + # Return test results. + return test_results.value, testcase_count.value class append_filter(argparse.Action): @@ -1107,40 +1212,20 @@ def __call__(self, parser, args, value, option): def main(): cmd_parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, - description="""Run and manage tests for MicroPython. + description=f"""Run and manage tests for MicroPython. -By default the tests are run against the unix port of MicroPython. To run it -against something else, use the -t option. See below for details. - -Tests are discovered by scanning test directories for .py files or using the -specified test files. If test files nor directories are specified, the script -expects to be ran in the tests directory (where this file is located) and the -builtin tests suitable for the target platform are ran. +{test_instance_description} +{test_directory_description} When running tests, run-tests.py compares the MicroPython output of the test with the output -produced by running the test through CPython unless a .exp file is found, in which -case it is used as comparison. +produced by running the test through CPython unless a .exp file is found (or a +.native.exp file when using the native emitter), in which case it is used as comparison. If a test fails, run-tests.py produces a pair of .out and .exp files in the result directory with the MicroPython output and the expectations, respectively. """, - epilog="""\ -The -t option accepts the following for the test instance: -- unix - use the unix port of MicroPython, specified by the MICROPY_MICROPYTHON - environment variable (which defaults to the standard variant of either the unix - or windows ports, depending on the host platform) -- webassembly - use the webassembly port of MicroPython, specified by the - MICROPY_MICROPYTHON_MJS environment variable (which defaults to the standard - variant of the webassembly port) -- port: - connect to and use the given serial port device -- a - connect to and use /dev/ttyACM -- u - connect to and use /dev/ttyUSB -- c - connect to and use COM -- exec: - execute a command and attach to its stdin/stdout -- execpty: - execute a command and attach to the printed /dev/pts/ device -- ... - connect to the given IPv4 address -- anything else specifies a serial port - + epilog=f"""\ +{test_instance_epilog} Options -i and -e can be multiple and processed in the order given. Regex "search" (vs "match") operation is used. An action (include/exclude) of the last matching regex is used: @@ -1149,6 +1234,9 @@ def main(): run-tests.py -e async -i async_foo - include all, exclude async, yet still include async_foo """, ) + cmd_parser.add_argument( + "-c", "--trace-output", action="store_true", help="trace test output while running" + ) cmd_parser.add_argument( "-t", "--test-instance", default="unix", help="the MicroPython instance to test" ) @@ -1179,6 +1267,11 @@ def main(): dest="filters", help="include test by regex on path/name.py", ) + cmd_parser.add_argument( + "--dry-run", + action="store_true", + help="Show tests which would run (though might still be skipped at runtime)", + ) cmd_parser.add_argument( "--emit", default="bytecode", help="MicroPython emitter to use (bytecode or native)" ) @@ -1214,8 +1307,25 @@ def main(): action="store_true", help="re-run only the failed tests", ) + cmd_parser.add_argument( + "--begin", + metavar="PROLOGUE", + default=None, + help="prologue python file to execute before module import", + ) + cmd_parser.add_argument( + "--target-wiring", + default=None, + help="force the given script to be used as target_wiring.py", + ) args = cmd_parser.parse_args() + prologue = "" + if args.begin: + with open(args.begin, "rt") as source: + prologue = source.read() + set_injected_prologue(prologue) + if args.print_failures: for out in glob(os.path.join(args.result_dir, "*.out")): testbase = out[:-4] @@ -1237,7 +1347,7 @@ def main(): os.path.join(args.result_dir, "*.out") ): os.remove(f) - rm_f(os.path.join(args.result_dir, RESULTS_FILE)) + rm_f(get_results_filename(args)) sys.exit(0) @@ -1253,10 +1363,10 @@ def main(): ) if args.run_failures: - results_file = os.path.join(args.result_dir, RESULTS_FILE) + results_file = get_results_filename(args) if os.path.exists(results_file): with open(results_file, "r") as f: - tests = json.load(f)["failed_tests"] + tests = list(test[0] for test in json.load(f)["results"] if test[1] == "fail") else: tests = [] elif len(args.files) == 0: @@ -1264,57 +1374,54 @@ def main(): if args.platform == "webassembly": test_extensions += ("*.js", "*.mjs") - if args.test_dirs is None: + all_test_dirs = [] + main_tests_dir_in_args = None + if args.test_dirs is not None: + # Run tests from given directories though if user explicitly passes this directory as argument + # still do the normal test discovery to be consistent with running from within this directory. + main_tests_dir = os.path.realpath(base_path()) + for test_dir in args.test_dirs: + if os.path.realpath(test_dir) == main_tests_dir: + main_tests_dir_in_args = test_dir + else: + all_test_dirs.append(test_dir) + + if args.test_dirs is None or main_tests_dir_in_args is not None: test_dirs = ( "basics", - "circuitpython", # CIRCUITPY-CHANGE "micropython", "misc", "extmod", + "stress", ) if args.inlineasm_arch is not None: test_dirs += ("inlineasm/{}".format(args.inlineasm_arch),) - if args.platform == "pyboard": - # run pyboard tests - test_dirs += ("float", "stress", "ports/stm32") - elif args.platform == "mimxrt": - test_dirs += ("float", "stress") - elif args.platform == "renesas-ra": - test_dirs += ("float", "ports/renesas-ra") - elif args.platform == "rp2": - test_dirs += ("float", "stress", "thread", "ports/rp2") - elif args.platform == "esp32": - test_dirs += ("float", "stress", "thread") - elif args.platform in ("esp8266", "minimal", "samd", "nrf"): + if args.thread is not None: + test_dirs += ("thread",) + if args.float_prec > 0: test_dirs += ("float",) - elif args.platform == "WiPy": - # run WiPy tests - test_dirs += ("ports/cc3200",) - elif args.platform in PC_PLATFORMS: + if args.unicode: + test_dirs += ("unicode",) + port_specific_test_dir = "ports/{}".format(platform_to_port(args.platform)) + if os.path.isdir(port_specific_test_dir): + test_dirs += (port_specific_test_dir,) + if args.platform in PC_PLATFORMS: # run PC tests - test_dirs += ( - "float", - "import", - "io", - "stress", - "unicode", - "cmdline", - "ports/unix", - ) - elif args.platform == "qemu": - test_dirs += ( - "float", - "ports/qemu", - ) - elif args.platform == "webassembly": - test_dirs += ("float", "ports/webassembly") - else: - # run tests from these directories - test_dirs = args.test_dirs + test_dirs += ("import",) + if args.build != "minimal": + test_dirs += ("cmdline", "io") + + all_test_dirs.extend( + test_dir + if main_tests_dir_in_args is None + else os.path.join(main_tests_dir_in_args, test_dir) + for test_dir in test_dirs + ) + tests = sorted( test_file for test_files in ( - glob(os.path.join(dir, ext)) for dir in test_dirs for ext in test_extensions + glob(os.path.join(dir, ext)) for dir in all_test_dirs for ext in test_extensions ) for test_file in test_files ) @@ -1322,6 +1429,13 @@ def main(): # tests explicitly given tests = args.files + # If any tests need it, prepare the target_wiring script for the target. + if pyb and any(test.endswith(tests_requiring_target_wiring) for test in tests): + detect_target_wiring_script(pyb, args) + + # End the target information line. + print() + if not args.keep_path: # Clear search path to make sure tests use only builtin modules, those in # extmod, and a path to unittest in case it's needed. @@ -1342,7 +1456,8 @@ def main(): try: os.makedirs(args.result_dir, exist_ok=True) - res = run_tests(pyb, tests, args, args.result_dir, args.jobs) + test_results, testcase_count = run_tests(pyb, tests, args, args.result_dir, args.jobs) + res = create_test_report(args, test_results, testcase_count) finally: if pyb: pyb.close() diff --git a/tests/serial_test.py b/tests/serial_test.py new file mode 100755 index 00000000000..eebea402fa4 --- /dev/null +++ b/tests/serial_test.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python +# +# Performance and reliability test for serial port communication. +# +# Basic usage: +# serial_test.py [-t serial-device] +# +# The `serial-device` will default to /dev/ttyACM0. + +import argparse +import random +import serial +import sys +import time + +from test_utils import test_instance_epilog, convert_device_shortcut_to_real_device + +echo_test_script = """ +import sys +bytes_min=%u +bytes_max=%u +repeat=%u +b=memoryview(bytearray(bytes_max)) +for n in range(bytes_min,bytes_max+1): + for _ in range(repeat): + n2 = sys.stdin.readinto(b[:n]) + sys.stdout.write(b[:n2]) +""" + +read_test_script = """ +bin = True +try: + wr=__import__("pyb").USB_VCP(0).send +except: + import sys + if hasattr(sys.stdout,'buffer'): + wr=sys.stdout.buffer.write + else: + wr=sys.stdout.write + bin = False +b=bytearray(%u) +if bin: + wr('BIN') + for i in range(len(b)): + b[i] = i & 0xff +else: + wr('TXT') + for i in range(len(b)): + b[i] = 0x20 + (i & 0x3f) +for _ in range(%d): + wr(b) +""" + + +write_test_script_verified = """ +import sys +try: + rd=__import__("pyb").USB_VCP(0).recv +except: + rd=sys.stdin.readinto +b=bytearray(%u) +for _ in range(%u): + n = rd(b) + fail = 0 + for i in range(n): + if b[i] != 32 + (i & 0x3f): + fail += 1 + if fail: + sys.stdout.write(b'ER%%05u' %% fail) + else: + sys.stdout.write(b'OK%%05u' %% n) +""" + +write_test_script_unverified = """ +import sys +try: + rd=__import__("pyb").USB_VCP(0).recv +except: + rd=sys.stdin.readinto +b=bytearray(%u) +for _ in range(%u): + n = rd(b) + if n != len(b): + sys.stdout.write(b'ER%%05u' %% n) + else: + sys.stdout.write(b'OK%%05u' %% n) +""" + + +class TestError(Exception): + pass + + +def drain_input(ser): + time.sleep(0.1) + while ser.inWaiting() > 0: + data = ser.read(ser.inWaiting()) + time.sleep(0.1) + + +def send_script(ser, script): + ser.write(b"\x03\x01\x04") # break, raw-repl, soft-reboot + drain_input(ser) + chunk_size = 32 + for i in range(0, len(script), chunk_size): + ser.write(script[i : i + chunk_size]) + time.sleep(0.01) + ser.write(b"\x04") # eof + ser.flush() + response = ser.read(2) + if response != b"OK": + response += ser.read(ser.inWaiting()) + raise TestError("could not send script", response) + + +def echo_test(ser_repl, ser_data): + global test_passed + + # Make the test data deterministic. + random.seed(0) + + # Set parameters for the test. + # Go just a bit above the size of a USB high-speed packet. + bytes_min = 1 + bytes_max = 520 + num_repeat = 1 + + # Load and run the write_test_script. + script = bytes(echo_test_script % (bytes_min, bytes_max, num_repeat), "ascii") + send_script(ser_repl, script) + + # A selection of printable bytes for echo data. + printable_bytes = list(range(48, 58)) + list(range(65, 91)) + list(range(97, 123)) + + # Write data to the device and record the echo'd data. + # Use a different selection of random printable characters for each + # echo, to make it easier to debug when the echo doesn't match. + num_errors = 0 + echo_results = [] + for num_bytes in range(bytes_min, bytes_max + 1): + print(f"DATA ECHO: {num_bytes} / {bytes_max}", end="\r") + for repeat in range(num_repeat): + rand_bytes = list(random.choice(printable_bytes) for _ in range(8)) + buf = bytes(random.choice(rand_bytes) for _ in range(num_bytes)) + ser_data.write(buf) + buf2 = ser_data.read(len(buf)) + match = buf == buf2 + num_errors += not match + echo_results.append((match, buf, buf2)) + if num_errors > 8: + # Stop early if there are too many errors. + break + ser_repl.write(b"\x03") + + # Print results. + if all(match for match, _, _ in echo_results): + print("DATA ECHO: OK for {}-{} bytes at a time".format(bytes_min, bytes_max)) + else: + test_passed = False + print("DATA ECHO: FAIL ") + for match, buf, buf2 in echo_results: + print(" sent", len(buf), buf) + if match: + print(" echo match") + else: + print(" echo", len(buf), buf2) + + +def read_test(ser_repl, ser_data, bufsize, nbuf): + global test_passed + + assert bufsize % 256 == 0 # for verify to work + + # how long to wait for data from device + # (if UART TX is also enabled then it can take 1.4s to send + # out a 16KB butter at 115200bps) + READ_TIMEOUT_S = 2 + + # Load and run the read_test_script. + script = bytes(read_test_script % (bufsize, nbuf), "ascii") + send_script(ser_repl, script) + + # Read from the device the type of data that it will send (BIN or TXT). + data_type = ser_data.read(3) + + # Read data from the device, check it is correct, and measure throughput. + n = 0 + last_byte = None + t_start = time.time() + remain = nbuf * bufsize + total_data = bytearray(remain) + while remain: + t0 = time.monotonic_ns() + while ser_data.inWaiting() == 0: + if time.monotonic_ns() - t0 > READ_TIMEOUT_S * 1e9: + # timeout waiting for data from device + break + time.sleep(0.0001) + if not ser_data.inWaiting(): + test_passed = False + print("ERROR: timeout waiting for data") + print(total_data[:n]) + return 0 + to_read = min(ser_data.inWaiting(), remain) + data = ser_data.read(to_read) + remain -= len(data) + print(f"{n} / {nbuf * bufsize}", end="\r") + total_data[n : n + len(data)] = data + n += len(data) + t_end = time.time() + for i in range(0, len(total_data)): + if data_type == b"BIN": + wanted = i & 0xFF + else: + wanted = 0x20 + (i & 0x3F) + if total_data[i] != wanted: + test_passed = False + print("ERROR: data mismatch:", i, wanted, total_data[i]) + ser_repl.write(b"\x03") # break + t = t_end - t_start + + # Print results. + print( + "DATA IN: bufsize=%u, read %u bytes in %.2f msec = %.2f kibytes/sec = %.2f MBits/sec" + % (bufsize, n, t * 1000, n / 1024 / t, n * 8 / 1000000 / t) + ) + + return n / t + + +def write_test(ser_repl, ser_data, bufsize, nbuf, verified): + global test_passed + + # Load and run the write_test_script. + if verified: + script = write_test_script_verified + else: + script = write_test_script_unverified + script = bytes(script % (bufsize, nbuf), "ascii") + send_script(ser_repl, script) + drain_input(ser_repl) + + # Write data to the device, check it is correct, and measure throughput. + n = 0 + t_start = time.time() + buf = bytearray(bufsize) + for i in range(len(buf)): + buf[i] = 32 + (i & 0x3F) # don't want to send ctrl chars! + for i in range(nbuf): + ser_data.write(buf) + n += len(buf) + print(f"{n} / {nbuf * bufsize}", end="\r") + response = ser_repl.read(7) + if response != b"OK%05u" % bufsize: + test_passed = False + print("ERROR: bad response, expecting OK%05u, got %r" % (bufsize, response)) + t_end = time.time() + ser_repl.write(b"\x03") # break + t = t_end - t_start + + # Print results. + print( + "DATA OUT: verify=%d, bufsize=%u, wrote %u bytes in %.2f msec = %.2f kibytes/sec = %.2f MBits/sec" + % (verified, bufsize, n, t * 1000, n / 1024 / t, n * 8 / 1000000 / t) + ) + + return n / t + + +def do_test(dev_repl, dev_data=None, time_per_subtest=1): + if dev_data is None: + print("REPL and data on", dev_repl) + ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=1) + ser_data = ser_repl + else: + print("REPL on", dev_repl) + print("data on", dev_data) + ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=1) + ser_data = serial.Serial(dev_data, baudrate=115200, timeout=1) + + # Do echo test first, and abort if it doesn't pass. + echo_test(ser_repl, ser_data) + if not test_passed: + return + + # Do read and write throughput test. + for test_func, test_args, bufsize in ( + (read_test, (), 256), + (write_test, (True,), 128), + (write_test, (False,), 128), + ): + nbuf = 128 + while bufsize <= 16384: + rate = test_func(ser_repl, ser_data, bufsize, nbuf, *test_args) + bufsize *= 2 + if rate: + # Adjust the amount of data based on the rate, to keep each subtest + # at around time_per_subtest seconds long. + nbuf = max(min(128, int(rate * time_per_subtest / bufsize)), 1) + + ser_repl.close() + ser_data.close() + + +def main(): + global test_passed + + cmd_parser = argparse.ArgumentParser( + description="Test performance and reliability of serial port communication.", + epilog=test_instance_epilog, + formatter_class=argparse.RawTextHelpFormatter, + ) + cmd_parser.add_argument( + "-t", + "--test-instance", + default="a0", + help="MicroPython instance to test", + ) + cmd_parser.add_argument( + "--time-per-subtest", default="1", help="approximate time to take per subtest (in seconds)" + ) + args = cmd_parser.parse_args() + + dev_repl = convert_device_shortcut_to_real_device(args.test_instance) + + test_passed = True + try: + do_test(dev_repl, None, float(args.time_per_subtest)) + except TestError as er: + test_passed = False + print("ERROR:", er) + + if not test_passed: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/tests/stress/bytecode_limit.py b/tests/stress/bytecode_limit.py index 948d7668da5..7e77cdd5e5a 100644 --- a/tests/stress/bytecode_limit.py +++ b/tests/stress/bytecode_limit.py @@ -1,19 +1,29 @@ # Test the limits of bytecode generation. +import sys + +# Tune the test parameters based on the target's bytecode generator. +if hasattr(sys.implementation, "_mpy"): + # Target can load .mpy files so generated bytecode uses 1 byte per qstr. + number_of_body_copies = (433, 432, 431, 399) +else: + # Target can't load .mpy files so generated bytecode uses 2 bytes per qstr. + number_of_body_copies = (401, 400, 399, 398) + body = " with f()()() as a:\n try:\n f()()()\n except Exception:\n pass\n" # Test overflow of jump offset. # Print results at the end in case an intermediate value of n fails with MemoryError. results = [] -for n in (433, 432, 431, 430): +for n in number_of_body_copies: try: exec("cond = 0\nif cond:\n" + body * n + "else:\n print('cond false')\n") - results.append((n, "ok")) + results.append("ok") except MemoryError: print("SKIP") raise SystemExit - except RuntimeError: - results.append((n, "RuntimeError")) + except RuntimeError as er: + results.append("RuntimeError('{}')".format(str(er) or "bytecode overflow")) print(results) # Test changing size of code info (source line/bytecode mapping) due to changing diff --git a/tests/stress/bytecode_limit.py.exp b/tests/stress/bytecode_limit.py.exp index cda52b1b973..3f1eb0db4c4 100644 --- a/tests/stress/bytecode_limit.py.exp +++ b/tests/stress/bytecode_limit.py.exp @@ -1,4 +1,4 @@ cond false cond false -[(433, 'RuntimeError'), (432, 'RuntimeError'), (431, 'ok'), (430, 'ok')] +["RuntimeError('bytecode overflow')", "RuntimeError('bytecode overflow')", 'ok', 'ok'] [123] diff --git a/tests/stress/dict_copy.py b/tests/stress/dict_copy.py index 73d3a5b51d6..f9b742e20f7 100644 --- a/tests/stress/dict_copy.py +++ b/tests/stress/dict_copy.py @@ -1,6 +1,11 @@ # copying a large dictionary -a = {i: 2 * i for i in range(1000)} +try: + a = {i: 2 * i for i in range(1000)} +except MemoryError: + print("SKIP") + raise SystemExit + b = a.copy() for i in range(1000): print(i, b[i]) diff --git a/tests/stress/dict_create.py b/tests/stress/dict_create.py index e9db40a8e6c..91a83a12f9d 100644 --- a/tests/stress/dict_create.py +++ b/tests/stress/dict_create.py @@ -3,6 +3,10 @@ d = {} x = 1 while x < 1000: - d[x] = x + try: + d[x] = x + except MemoryError: + print("SKIP") + raise SystemExit x += 1 print(d[500]) diff --git a/tests/stress/fun_call_limit.py b/tests/stress/fun_call_limit.py index b802aadd558..69f8aa5aec4 100644 --- a/tests/stress/fun_call_limit.py +++ b/tests/stress/fun_call_limit.py @@ -16,14 +16,16 @@ def test(n): # If the port has at least 32-bits then this test should pass. -print(test(29)) +print(test(28)) # This test should fail on all ports (overflows a small int). print(test(70)) -# Check that there is a correct transition to the limit of too many args before *args. +# 28 is the biggest number that will pass on a 32-bit port using object +# representation B, which has 1<<28 still fitting in a positive small int. reached_limit = False -for i in range(30, 70): +any_test_succeeded = False +for i in range(28, 70): result = test(i) if reached_limit: if result != "SyntaxError": @@ -34,3 +36,5 @@ def test(n): else: if result != i + 4: print("FAIL") + any_test_succeeded = True +assert any_test_succeeded # At least one iteration must have passed diff --git a/tests/stress/fun_call_limit.py.exp b/tests/stress/fun_call_limit.py.exp index 53d2b280430..491abbfa8be 100644 --- a/tests/stress/fun_call_limit.py.exp +++ b/tests/stress/fun_call_limit.py.exp @@ -1,2 +1,2 @@ -33 +32 SyntaxError diff --git a/tests/stress/qstr_limit.py b/tests/stress/qstr_limit.py index 08b10a039f5..55b87075df9 100644 --- a/tests/stress/qstr_limit.py +++ b/tests/stress/qstr_limit.py @@ -12,8 +12,8 @@ def make_id(n, base="a"): var = make_id(l) try: exec(var + "=1", g) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print(str(er) or "name too long", l) continue print(var in g) @@ -26,16 +26,16 @@ def f(**k): for l in range(254, 259): try: exec("f({}=1)".format(make_id(l))) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print(str(er) or "name too long", l) # type construction for l in range(254, 259): id = make_id(l) try: - print(type(id, (), {}).__name__) - except RuntimeError: - print("RuntimeError", l) + print(type(id, (), {})) + except RuntimeError as er: + print(str(er) or "name too long", l) # hasattr, setattr, getattr @@ -48,28 +48,20 @@ class A: a = A() try: setattr(a, id, 123) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print(str(er) or "name too long", l) try: print(hasattr(a, id), getattr(a, id)) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print(str(er) or "name too long", l) # format with keys for l in range(254, 259): id = make_id(l) try: print(("{" + id + "}").format(**{id: l})) - except RuntimeError: - print("RuntimeError", l) - -# modulo format with keys -for l in range(254, 259): - id = make_id(l) - try: - print(("%(" + id + ")d") % {id: l}) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print(str(er) or "name too long", l) # import module # (different OS's have different results so only run those that are consistent) @@ -78,8 +70,8 @@ class A: __import__(make_id(l)) except ImportError: print("ok", l) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print(str(er) or "name too long", l) # import package for l in (100, 101, 102, 128, 129): @@ -87,5 +79,5 @@ class A: exec("import " + make_id(l) + "." + make_id(l, "A")) except ImportError: print("ok", l) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print(str(er) or "name too long", l) diff --git a/tests/stress/qstr_limit.py.exp b/tests/stress/qstr_limit.py.exp index 455761bc71e..5596b54bebd 100644 --- a/tests/stress/qstr_limit.py.exp +++ b/tests/stress/qstr_limit.py.exp @@ -1,43 +1,38 @@ True True -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +name too long 256 +name too long 257 +name too long 258 {'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst': 1} {'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu': 1} -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 -abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst -abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +name too long 256 +name too long 257 +name too long 258 + + +name too long 256 +name too long 257 +name too long 258 True 123 True 123 -RuntimeError 256 -RuntimeError 256 -RuntimeError 257 -RuntimeError 257 -RuntimeError 258 -RuntimeError 258 +name too long 256 +name too long 256 +name too long 257 +name too long 257 +name too long 258 +name too long 258 254 255 -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 -254 -255 -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +name too long 256 +name too long 257 +name too long 258 ok 100 ok 101 -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +name too long 256 +name too long 257 +name too long 258 ok 100 ok 101 ok 102 -RuntimeError 128 -RuntimeError 129 +name too long 128 +name too long 129 diff --git a/tests/stress/qstr_limit_str_modulo.py b/tests/stress/qstr_limit_str_modulo.py new file mode 100644 index 00000000000..c56f23b0a1d --- /dev/null +++ b/tests/stress/qstr_limit_str_modulo.py @@ -0,0 +1,21 @@ +# Test interning qstrs that go over the qstr length limit (255 bytes in default configuration). +# The tests here are specifically for str formatting with %. + +try: + "" % () +except TypeError: + print("SKIP") + raise SystemExit + + +def make_id(n, base="a"): + return "".join(chr(ord(base) + i % 26) for i in range(n)) + + +# modulo format with keys +for l in range(254, 259): + id = make_id(l) + try: + print(("%(" + id + ")d") % {id: l}) + except RuntimeError as er: + print("RuntimeError", str(er) or "name too long", l) diff --git a/tests/stress/qstr_limit_str_modulo.py.exp b/tests/stress/qstr_limit_str_modulo.py.exp new file mode 100644 index 00000000000..3632c85bffe --- /dev/null +++ b/tests/stress/qstr_limit_str_modulo.py.exp @@ -0,0 +1,5 @@ +254 +255 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 diff --git a/tests/stress/recursive_iternext.py b/tests/stress/recursive_iternext.py index bbc389e7262..c737f1e36d7 100644 --- a/tests/stress/recursive_iternext.py +++ b/tests/stress/recursive_iternext.py @@ -1,4 +1,8 @@ # This tests that recursion with iternext doesn't lead to segfault. +# +# This test segfaults CPython, but that's not a bug as CPython doesn't enforce +# limits on C recursion - see +# https://github.com/python/cpython/issues/58218#issuecomment-1093570209 try: enumerate filter @@ -9,49 +13,25 @@ print("SKIP") raise SystemExit -# We need to pick an N that is large enough to hit the recursion -# limit, but not too large that we run out of heap memory. -try: - # large stack/heap, eg unix - [0] * 80000 - N = 5000 -except: - try: - # medium, eg pyboard - [0] * 10000 - N = 1000 - except: - # small, eg esp8266 - N = 100 - -try: - x = (1, 2) - for i in range(N): - x = enumerate(x) - tuple(x) -except RuntimeError: - print("RuntimeError") -try: +# Progressively build a bigger nested iterator structure (10 at a time for speed), +# and then try to evaluate it via tuple(x) which makes deep recursive function calls. +# +# Eventually this should raise a RuntimeError as MicroPython runs out of stack. +# It shouldn't ever raise a MemoryError, if it does then somehow MicroPython has +# run out of heap (for the nested structure) before running out of stack. +def recurse_iternext(nested_fn): x = (1, 2) - for i in range(N): - x = filter(None, x) - tuple(x) -except RuntimeError: - print("RuntimeError") + while True: + for _ in range(10): + x = nested_fn(x) + try: + tuple(x) + except RuntimeError: + print("RuntimeError") + break -try: - x = (1, 2) - for i in range(N): - x = map(max, x, ()) - tuple(x) -except RuntimeError: - print("RuntimeError") -try: - x = (1, 2) - for i in range(N): - x = zip(x) - tuple(x) -except RuntimeError: - print("RuntimeError") +# Test on various nested iterator structures +for nested_fn in [enumerate, lambda x: filter(None, x), lambda x: map(max, x, ()), zip]: + recurse_iternext(nested_fn) diff --git a/tests/target_wiring/EK_RA6M2.py b/tests/target_wiring/EK_RA6M2.py new file mode 100644 index 00000000000..7d4a8cbbd64 --- /dev/null +++ b/tests/target_wiring/EK_RA6M2.py @@ -0,0 +1,8 @@ +# Target wiring for EK_RA6M2. +# +# Connect: +# - P601 to P602 + +# UART(9) is on P602/P601. +uart_loopback_args = (9,) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/KIT_PSE84_AI.py b/tests/target_wiring/KIT_PSE84_AI.py new file mode 100644 index 00000000000..8ef3f08385d --- /dev/null +++ b/tests/target_wiring/KIT_PSE84_AI.py @@ -0,0 +1,5 @@ +# Target wiring for KIT_PSE84_AI. + +# UART(5) is on P17_1/P17_0. +uart_loopback_args = () +uart_loopback_kwargs = {"tx": "P17_1", "rx": "P17_0"} diff --git a/tests/target_wiring/NUCLEO_WB55.py b/tests/target_wiring/NUCLEO_WB55.py new file mode 100644 index 00000000000..e40d35e225b --- /dev/null +++ b/tests/target_wiring/NUCLEO_WB55.py @@ -0,0 +1,12 @@ +# Target wiring for NUCLEO_WB55. +# +# Connect: +# - PA2 to PA3 + +# LPUART(1) is on PA2/PA3. +uart_loopback_args = ("LP1",) +uart_loopback_kwargs = {} + +spi_standalone_args_list = [(1,), (2,)] + +pwm_loopback_pins = [("D1", "D0")] diff --git a/tests/target_wiring/PYBx.py b/tests/target_wiring/PYBx.py new file mode 100644 index 00000000000..b36e342e944 --- /dev/null +++ b/tests/target_wiring/PYBx.py @@ -0,0 +1,16 @@ +# Target wiring for PYBV10, PYBV11, PYBLITEV10, PYBD_SF2, PYBD_SF3, PYBD_SF6. +# +# Connect: +# - X1 to X2 + +# UART("XA") is on X1/X2 (usually UART(4) on PA0/PA1). +uart_loopback_args = ("XA",) +uart_loopback_kwargs = {} + +spi_standalone_args_list = [(1,), (2,)] + +# CAN args assume no connection for single device tests +can_args = (1,) +can_kwargs = {} + +pwm_loopback_pins = [("X1", "X2")] diff --git a/tests/target_wiring/README.md b/tests/target_wiring/README.md new file mode 100644 index 00000000000..c3a7038bb91 --- /dev/null +++ b/tests/target_wiring/README.md @@ -0,0 +1,81 @@ +# Target wiring + +Some tests require hardware configuration and/or external connections, for example +bridging a pair of GPIO pins. Each board that such tests run on needs to be configured +individually. That is achieved by providing a target wiring configuration script that +defines the necessary hardware parameters for each test. + +## Selecting the target wiring + +There are three ways to provide the target wiring configuration: + +1. Specify it explicitly when running the test: `./run-tests.py --target-wiring